From fecfe6320ba71eed6d16849683298f0894aa60de Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 7 May 2009 16:07:41 +0200 Subject: oprofile: remove obselete include headers This became obsolete with this commit: 6dad828 oprofile: port to the new ring_buffer Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 242257b1944..50640cc5eef 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -21,7 +21,6 @@ #include #include -#include #include #include "event_buffer.h" -- cgit v1.2.3-18-g5258 From 51563a0e5650d0d76539625388d72d62b34c726e Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 3 Jun 2009 20:54:56 +0200 Subject: x86/oprofile: introduce oprofile_add_data64() The IBS implemention writes 64 bit register values to the cpu buffer by writing two 32 values using oprofile_add_data(). This patch introduces oprofile_add_data64() to write a single 64 bit value to the buffer. Signed-off-by: Robert Richter --- drivers/oprofile/cpu_buffer.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 50640cc5eef..a7aae24f288 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -406,6 +406,21 @@ int oprofile_add_data(struct op_entry *entry, unsigned long val) return op_cpu_buffer_add_data(entry, val); } +int oprofile_add_data64(struct op_entry *entry, u64 val) +{ + if (!entry->event) + return 0; + if (op_cpu_buffer_get_size(entry) < 2) + /* + * the function returns 0 to indicate a too small + * buffer, even if there is some space left + */ + return 0; + if (!op_cpu_buffer_add_data(entry, (u32)val)) + return 0; + return op_cpu_buffer_add_data(entry, (u32)(val >> 32)); +} + int oprofile_write_commit(struct op_entry *entry) { if (!entry->event) -- cgit v1.2.3-18-g5258 From a635f9dd83f3382577f4544a96df12356e951a40 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 12 Jun 2009 15:20:55 +0200 Subject: HID: use debugfs for report dumping descriptor It is a little bit inconvenient for people who have some non-standard HID hardware (usually violating the HID specification) to have to recompile kernel with CONFIG_HID_DEBUG to be able to see kernel's perspective of the HID report descriptor and observe the parsed events. Plus the messages are then mixed up inconveniently with the rest of the dmesg stuff. This patch implements /sys/kernel/debug/hid//rdesc file, which represents the kernel's view of report descriptor (both the raw report descriptor data and parsed contents). With all the device-specific debug data being available through debugfs, there is no need for keeping CONFIG_HID_DEBUG, as the 'debug' parameter to the hid module will now only output only driver-specific debugging options, which has absolutely minimal memory footprint, just a few error messages and one global flag (hid_debug). We use the current set of output formatting functions. The ones that need to be used both for one-shot rdesc seq_file and also for continuous flow of data (individual reports, as being sent by the device) distinguish according to the passed seq_file parameter, and if it is NULL, it still output to kernel ringbuffer, otherwise the corresponding seq_file is used for output. The format of the output is preserved. Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 15 --- drivers/hid/Makefile | 5 +- drivers/hid/hid-core.c | 13 ++- drivers/hid/hid-debug.c | 227 +++++++++++++++++++++++++++++------------- drivers/hid/hid-input.c | 13 +-- drivers/hid/usbhid/hid-core.c | 8 +- 6 files changed, 172 insertions(+), 109 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 7e67dcb3d4f..05950a78356 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -31,21 +31,6 @@ config HID If unsure, say Y. -config HID_DEBUG - bool "HID debugging support" - default y - depends on HID - ---help--- - This option lets the HID layer output diagnostics about its internal - state, resolve HID usages, dump HID fields, etc. Individual HID drivers - use this debugging facility to output information about individual HID - devices, etc. - - This feature is useful for those who are either debugging the HID parser - or any HID hardware device. - - If unsure, say Y. - config HIDRAW bool "/dev/hidraw raw HID device support" depends on HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 1f7cb0fd450..cf3687d1ed6 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -3,9 +3,12 @@ # hid-objs := hid-core.o hid-input.o +ifdef CONFIG_DEBUG_FS + hid-objs += hid-debug.o +endif + obj-$(CONFIG_HID) += hid.o -hid-$(CONFIG_HID_DEBUG) += hid-debug.o hid-$(CONFIG_HIDRAW) += hidraw.o hid-logitech-objs := hid-lg.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 8551693d645..d4317db85b5 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -44,12 +44,10 @@ #define DRIVER_DESC "HID core driver" #define DRIVER_LICENSE "GPL" -#ifdef CONFIG_HID_DEBUG int hid_debug = 0; module_param_named(debug, hid_debug, int, 0600); MODULE_PARM_DESC(debug, "HID debugging (0=off, 1=probing info, 2=continuous data dumping)"); EXPORT_SYMBOL_GPL(hid_debug); -#endif /* * Register a new report for a device. @@ -987,7 +985,6 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) if (offset >= field->report_count) { dbg_hid("offset (%d) exceeds report_count (%d)\n", offset, field->report_count); - hid_dump_field(field, 8); return -1; } if (field->logical_minimum < 0) { @@ -1721,6 +1718,8 @@ int hid_add_device(struct hid_device *hdev) if (!ret) hdev->status |= HID_STAT_ADDED; + hid_debug_register(hdev, dev_name(&hdev->dev)); + return ret; } EXPORT_SYMBOL_GPL(hid_add_device); @@ -1768,6 +1767,7 @@ static void hid_remove_device(struct hid_device *hdev) { if (hdev->status & HID_STAT_ADDED) { device_del(&hdev->dev); + hid_debug_unregister(hdev); hdev->status &= ~HID_STAT_ADDED; } } @@ -1843,6 +1843,10 @@ static int __init hid_init(void) { int ret; + if (hid_debug) + printk(KERN_WARNING "HID: hid_debug parameter has been deprecated. " + "Debugging data are now provided via debugfs\n"); + ret = bus_register(&hid_bus_type); if (ret) { printk(KERN_ERR "HID: can't register hid bus\n"); @@ -1853,6 +1857,8 @@ static int __init hid_init(void) if (ret) goto err_bus; + hid_debug_init(); + return 0; err_bus: bus_unregister(&hid_bus_type); @@ -1862,6 +1868,7 @@ err: static void __exit hid_exit(void) { + hid_debug_exit(); hidraw_exit(); bus_unregister(&hid_bus_type); } diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 47ac1a7d66e..067e173aa3e 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -1,9 +1,9 @@ /* * (c) 1999 Andreas Gal * (c) 2000-2001 Vojtech Pavlik - * (c) 2007 Jiri Kosina + * (c) 2007-2009 Jiri Kosina * - * Some debug stuff for the HID parser. + * HID debugging support */ /* @@ -26,9 +26,13 @@ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ +#include +#include #include #include +static struct dentry *hid_debug_root; + struct hid_usage_entry { unsigned page; unsigned usage; @@ -331,72 +335,83 @@ static const struct hid_usage_entry hid_usage_table[] = { { 0, 0, NULL } }; -static void resolv_usage_page(unsigned page) { +static void resolv_usage_page(unsigned page, struct seq_file *f) { const struct hid_usage_entry *p; for (p = hid_usage_table; p->description; p++) if (p->page == page) { - printk("%s", p->description); + if (!f) + printk("%s", p->description); + else + seq_printf(f, "%s", p->description); return; } - printk("%04x", page); + if (!f) + printk("%04x", page); + else + seq_printf(f, "%04x", page); } -void hid_resolv_usage(unsigned usage) { +void hid_resolv_usage(unsigned usage, struct seq_file *f) { const struct hid_usage_entry *p; - if (!hid_debug) - return; - - resolv_usage_page(usage >> 16); - printk("."); + resolv_usage_page(usage >> 16, f); + if (!f) + printk("."); + else + seq_printf(f, "."); for (p = hid_usage_table; p->description; p++) if (p->page == (usage >> 16)) { for(++p; p->description && p->usage != 0; p++) if (p->usage == (usage & 0xffff)) { - printk("%s", p->description); + if (!f) + printk("%s", p->description); + else + seq_printf(f, + "%s", + p->description); return; } break; } - printk("%04x", usage & 0xffff); + if (!f) + printk("%04x", usage & 0xffff); + else + seq_printf(f, "%04x", usage & 0xffff); } EXPORT_SYMBOL_GPL(hid_resolv_usage); -static void tab(int n) { - printk(KERN_DEBUG "%*s", n, ""); +static void tab(int n, struct seq_file *f) { + seq_printf(f, "%*s", n, ""); } -void hid_dump_field(struct hid_field *field, int n) { +void hid_dump_field(struct hid_field *field, int n, struct seq_file *f) { int j; - if (!hid_debug) - return; - if (field->physical) { - tab(n); - printk("Physical("); - hid_resolv_usage(field->physical); printk(")\n"); + tab(n, f); + seq_printf(f, "Physical("); + hid_resolv_usage(field->physical, f); seq_printf(f, ")\n"); } if (field->logical) { - tab(n); - printk("Logical("); - hid_resolv_usage(field->logical); printk(")\n"); + tab(n, f); + seq_printf(f, "Logical("); + hid_resolv_usage(field->logical, f); seq_printf(f, ")\n"); } - tab(n); printk("Usage(%d)\n", field->maxusage); + tab(n, f); seq_printf(f, "Usage(%d)\n", field->maxusage); for (j = 0; j < field->maxusage; j++) { - tab(n+2); hid_resolv_usage(field->usage[j].hid); printk("\n"); + tab(n+2, f); hid_resolv_usage(field->usage[j].hid, f); seq_printf(f, "\n"); } if (field->logical_minimum != field->logical_maximum) { - tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum); - tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum); + tab(n, f); seq_printf(f, "Logical Minimum(%d)\n", field->logical_minimum); + tab(n, f); seq_printf(f, "Logical Maximum(%d)\n", field->logical_maximum); } if (field->physical_minimum != field->physical_maximum) { - tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum); - tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum); + tab(n, f); seq_printf(f, "Physical Minimum(%d)\n", field->physical_minimum); + tab(n, f); seq_printf(f, "Physical Maximum(%d)\n", field->physical_maximum); } if (field->unit_exponent) { - tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent); + tab(n, f); seq_printf(f, "Unit Exponent(%d)\n", field->unit_exponent); } if (field->unit) { static const char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" }; @@ -417,77 +432,75 @@ void hid_dump_field(struct hid_field *field, int n) { data >>= 4; if(sys > 4) { - tab(n); printk("Unit(Invalid)\n"); + tab(n, f); seq_printf(f, "Unit(Invalid)\n"); } else { int earlier_unit = 0; - tab(n); printk("Unit(%s : ", systems[sys]); + tab(n, f); seq_printf(f, "Unit(%s : ", systems[sys]); for (i=1 ; i>= 4; if (nibble != 0) { if(earlier_unit++ > 0) - printk("*"); - printk("%s", units[sys][i]); + seq_printf(f, "*"); + seq_printf(f, "%s", units[sys][i]); if(nibble != 1) { /* This is a _signed_ nibble(!) */ int val = nibble & 0x7; if(nibble & 0x08) val = -((0x7 & ~val) +1); - printk("^%d", val); + seq_printf(f, "^%d", val); } } } - printk(")\n"); + seq_printf(f, ")\n"); } } - tab(n); printk("Report Size(%u)\n", field->report_size); - tab(n); printk("Report Count(%u)\n", field->report_count); - tab(n); printk("Report Offset(%u)\n", field->report_offset); + tab(n, f); seq_printf(f, "Report Size(%u)\n", field->report_size); + tab(n, f); seq_printf(f, "Report Count(%u)\n", field->report_count); + tab(n, f); seq_printf(f, "Report Offset(%u)\n", field->report_offset); - tab(n); printk("Flags( "); + tab(n, f); seq_printf(f, "Flags( "); j = field->flags; - printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : ""); - printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array "); - printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute "); - printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : ""); - printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : ""); - printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPreferredState " : ""); - printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : ""); - printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : ""); - printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : ""); - printk(")\n"); + seq_printf(f, "%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : ""); + seq_printf(f, "%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array "); + seq_printf(f, "%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute "); + seq_printf(f, "%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : ""); + seq_printf(f, "%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : ""); + seq_printf(f, "%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPreferredState " : ""); + seq_printf(f, "%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : ""); + seq_printf(f, "%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : ""); + seq_printf(f, "%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : ""); + seq_printf(f, ")\n"); } EXPORT_SYMBOL_GPL(hid_dump_field); -void hid_dump_device(struct hid_device *device) { +void hid_dump_device(struct hid_device *device, struct seq_file *f) +{ struct hid_report_enum *report_enum; struct hid_report *report; struct list_head *list; unsigned i,k; static const char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; - if (!hid_debug) - return; - for (i = 0; i < HID_REPORT_TYPES; i++) { report_enum = device->report_enum + i; list = report_enum->report_list.next; while (list != &report_enum->report_list) { report = (struct hid_report *) list; - tab(2); - printk("%s", table[i]); + tab(2, f); + seq_printf(f, "%s", table[i]); if (report->id) - printk("(%d)", report->id); - printk("[%s]", table[report->type]); - printk("\n"); + seq_printf(f, "(%d)", report->id); + seq_printf(f, "[%s]", table[report->type]); + seq_printf(f, "\n"); for (k = 0; k < report->maxfield; k++) { - tab(4); - printk("Field(%d)\n", k); - hid_dump_field(report->field[k], 6); + tab(4, f); + seq_printf(f, "Field(%d)\n", k); + hid_dump_field(report->field[k], 6, f); } list = list->next; } @@ -500,7 +513,7 @@ void hid_dump_input(struct hid_usage *usage, __s32 value) { return; printk(KERN_DEBUG "hid-debug: input "); - hid_resolv_usage(usage->hid); + hid_resolv_usage(usage->hid, NULL); printk(" = %d\n", value); } EXPORT_SYMBOL_GPL(hid_dump_input); @@ -767,12 +780,84 @@ static const char **names[EV_MAX + 1] = { [EV_SND] = sounds, [EV_REP] = repeats, }; -void hid_resolv_event(__u8 type, __u16 code) { - - if (!hid_debug) - return; +void hid_resolv_event(__u8 type, __u16 code, struct seq_file *f) { - printk("%s.%s", events[type] ? events[type] : "?", + seq_printf(f, "%s.%s", events[type] ? events[type] : "?", names[type] ? (names[type][code] ? names[type][code] : "?") : "?"); } -EXPORT_SYMBOL_GPL(hid_resolv_event); + +void hid_dump_input_mapping(struct hid_device *hid, struct seq_file *f) +{ + int i, j, k; + struct hid_report *report; + struct hid_usage *usage; + + for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) { + list_for_each_entry(report, &hid->report_enum[k].report_list, list) { + for (i = 0; i < report->maxfield; i++) { + for ( j = 0; j < report->field[i]->maxusage; j++) { + usage = report->field[i]->usage + j; + hid_resolv_usage(usage->hid, f); + seq_printf(f, " ---> "); + hid_resolv_event(usage->type, usage->code, f); + seq_printf(f, "\n"); + } + } + } + } + +} + +static int hid_debug_rdesc_show(struct seq_file *f, void *p) +{ + struct hid_device *hdev = f->private; + int i; + + /* dump HID report descriptor */ + for (i = 0; i < hdev->rsize; i++) + seq_printf(f, "%02x ", hdev->rdesc[i]); + seq_printf(f, "\n\n"); + + /* dump parsed data and input mappings */ + hid_dump_device(hdev, f); + seq_printf(f, "\n"); + hid_dump_input_mapping(hdev, f); + + return 0; +} + +static int hid_debug_rdesc_open(struct inode *inode, struct file *file) +{ + return single_open(file, hid_debug_rdesc_show, inode->i_private); +} + +static const struct file_operations hid_debug_rdesc_fops = { + .open = hid_debug_rdesc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +void hid_debug_register(struct hid_device *hdev, const char *name) +{ + hdev->debug_dir = debugfs_create_dir(name, hid_debug_root); + hdev->debug_rdesc = debugfs_create_file("rdesc", 0400, + hdev->debug_dir, hdev, &hid_debug_rdesc_fops); +} + +void hid_debug_unregister(struct hid_device *hdev) +{ + debugfs_remove(hdev->debug_rdesc); + debugfs_remove(hdev->debug_dir); +} + +void hid_debug_init(void) +{ + hid_debug_root = debugfs_create_dir("hid", NULL); +} + +void hid_debug_exit(void) +{ + debugfs_remove_recursive(hid_debug_root); +} + diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 7f183b7147e..5862b0f3b55 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -159,17 +159,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel field->hidinput = hidinput; - dbg_hid("Mapping: "); - hid_resolv_usage(usage->hid); - dbg_hid_line(" ---> "); - if (field->flags & HID_MAIN_ITEM_CONSTANT) goto ignore; /* only LED usages are supported in output fields */ if (field->report_type == HID_OUTPUT_REPORT && (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) { - dbg_hid_line(" [non-LED output field] "); goto ignore; } @@ -561,15 +556,9 @@ mapped: set_bit(MSC_SCAN, input->mscbit); } - hid_resolv_event(usage->type, usage->code); - - dbg_hid_line("\n"); - - return; - ignore: - dbg_hid_line("IGNORED\n"); return; + } void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index ac8049b5f1e..708aa52d075 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -4,8 +4,8 @@ * Copyright (c) 1999 Andreas Gal * Copyright (c) 2000-2005 Vojtech Pavlik * Copyright (c) 2005 Michael Haboustak for Concept2, Inc - * Copyright (c) 2006-2008 Jiri Kosina * Copyright (c) 2007-2008 Oliver Neukum + * Copyright (c) 2006-2009 Jiri Kosina */ /* @@ -886,11 +886,6 @@ static int usbhid_parse(struct hid_device *hid) goto err; } - dbg_hid("report descriptor (size %u, read %d) = ", rsize, n); - for (n = 0; n < rsize; n++) - dbg_hid_line(" %02x", (unsigned char) rdesc[n]); - dbg_hid_line("\n"); - ret = hid_parse_report(hid, rdesc, rsize); kfree(rdesc); if (ret) { @@ -1005,7 +1000,6 @@ static int usbhid_start(struct hid_device *hid) usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); usbhid_init_reports(hid); - hid_dump_device(hid); set_bit(HID_STARTED, &usbhid->iofl); -- cgit v1.2.3-18-g5258 From cd667ce24796700e1a0e6e7528efc61c96ff832e Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 12 Jun 2009 15:20:57 +0200 Subject: HID: use debugfs for events/reports dumping This is a followup patch to the one implemeting rdesc representation in debugfs rather than being dependent on compile-time CONFIG_HID_DEBUG setting. The API of the appropriate formatting functions is slightly modified -- if they are passed seq_file pointer, the one-shot output for 'rdesc' file mode is used, and therefore the message is formatted into the corresponding seq_file immediately. Otherwise the called function allocated a new buffer, formats the text into the buffer and returns the pointer to it, so that it can be queued into the ring-buffer of the processess blocked waiting on input on 'events' file in debugfs. 'debug' parameter to the 'hid' module is now used solely for the prupose of inetrnal driver state debugging (parser, transport, etc). Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 42 +++++++-- drivers/hid/hid-debug.c | 239 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 252 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index d4317db85b5..449bd747d11 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -46,7 +46,7 @@ int hid_debug = 0; module_param_named(debug, hid_debug, int, 0600); -MODULE_PARM_DESC(debug, "HID debugging (0=off, 1=probing info, 2=continuous data dumping)"); +MODULE_PARM_DESC(debug, "toggle HID debugging messages"); EXPORT_SYMBOL_GPL(hid_debug); /* @@ -859,7 +859,7 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_driver *hdrv = hid->driver; int ret; - hid_dump_input(usage, value); + hid_dump_input(hid, usage, value); if (hdrv && hdrv->event && hid_match_usage(hid, usage)) { ret = hdrv->event(hid, field, usage, value); @@ -981,7 +981,7 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) { unsigned size = field->report_size; - hid_dump_input(field->usage + offset, value); + hid_dump_input(field->report->device, field->usage + offset, value); if (offset >= field->report_count) { dbg_hid("offset (%d) exceeds report_count (%d)\n", offset, field->report_count); @@ -1075,6 +1075,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i struct hid_report_enum *report_enum = hid->report_enum + type; struct hid_driver *hdrv = hid->driver; struct hid_report *report; + char *buf; unsigned int i; int ret; @@ -1086,18 +1087,36 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i return -1; } - dbg_hid("report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un"); + buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, + interrupt ? GFP_ATOMIC : GFP_KERNEL); + + if (!buf) { + report = hid_get_report(report_enum, data); + goto nomem; + } + + snprintf(buf, HID_DEBUG_BUFSIZE - 1, + "\nreport (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un"); + hid_debug_event(hid, buf); report = hid_get_report(report_enum, data); if (!report) return -1; /* dump the report */ - dbg_hid("report %d (size %u) = ", report->id, size); - for (i = 0; i < size; i++) - dbg_hid_line(" %02x", data[i]); - dbg_hid_line("\n"); + snprintf(buf, HID_DEBUG_BUFSIZE - 1, + "report %d (size %u) = ", report->id, size); + hid_debug_event(hid, buf); + for (i = 0; i < size; i++) { + snprintf(buf, HID_DEBUG_BUFSIZE - 1, + " %02x", data[i]); + hid_debug_event(hid, buf); + } + hid_debug_event(hid, "\n"); + + kfree(buf); +nomem: if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) { ret = hdrv->raw_event(hid, report, data, size); if (ret != 0) @@ -1756,6 +1775,9 @@ struct hid_device *hid_allocate_device(void) for (i = 0; i < HID_REPORT_TYPES; i++) INIT_LIST_HEAD(&hdev->report_enum[i].report_list); + init_waitqueue_head(&hdev->debug_wait); + INIT_LIST_HEAD(&hdev->debug_list); + return hdev; err: put_device(&hdev->dev); @@ -1844,8 +1866,8 @@ static int __init hid_init(void) int ret; if (hid_debug) - printk(KERN_WARNING "HID: hid_debug parameter has been deprecated. " - "Debugging data are now provided via debugfs\n"); + printk(KERN_WARNING "HID: hid_debug is now used solely for parser and driver debugging.\n" + "HID: debugfs is now used for inspecting the device (report descriptor, reports)\n"); ret = bus_register(&hid_bus_type); if (ret) { diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 067e173aa3e..a331a1821e8 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -28,6 +28,10 @@ #include #include +#include +#include +#include + #include #include @@ -335,49 +339,86 @@ static const struct hid_usage_entry hid_usage_table[] = { { 0, 0, NULL } }; -static void resolv_usage_page(unsigned page, struct seq_file *f) { +/* Either output directly into simple seq_file, or (if f == NULL) + * allocate a separate buffer that will then be passed to the 'events' + * ringbuffer. + * + * This is because these functions can be called both for "one-shot" + * "rdesc" while resolving, or for blocking "events". + * + * This holds both for resolv_usage_page() and hid_resolv_usage(). + */ +static char *resolv_usage_page(unsigned page, struct seq_file *f) { const struct hid_usage_entry *p; + char *buf = NULL; + + if (!f) { + buf = kzalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC); + if (!buf) + return ERR_PTR(-ENOMEM); + } for (p = hid_usage_table; p->description; p++) if (p->page == page) { - if (!f) - printk("%s", p->description); - else + if (!f) { + snprintf(buf, HID_DEBUG_BUFSIZE, "%s", + p->description); + return buf; + } + else { seq_printf(f, "%s", p->description); - return; + return NULL; + } } if (!f) - printk("%04x", page); + snprintf(buf, HID_DEBUG_BUFSIZE, "%04x", page); else seq_printf(f, "%04x", page); + return buf; } -void hid_resolv_usage(unsigned usage, struct seq_file *f) { +char *hid_resolv_usage(unsigned usage, struct seq_file *f) { const struct hid_usage_entry *p; + char *buf = NULL; + int len = 0; - resolv_usage_page(usage >> 16, f); - if (!f) - printk("."); - else + buf = resolv_usage_page(usage >> 16, f); + if (IS_ERR(buf)) { + printk(KERN_ERR "error allocating HID debug buffer\n"); + return NULL; + } + + + if (!f) { + len = strlen(buf); + snprintf(buf+len, max(0, HID_DEBUG_BUFSIZE - len), "."); + len++; + } + else { seq_printf(f, "."); + } for (p = hid_usage_table; p->description; p++) if (p->page == (usage >> 16)) { for(++p; p->description && p->usage != 0; p++) if (p->usage == (usage & 0xffff)) { if (!f) - printk("%s", p->description); + snprintf(buf + len, + max(0,HID_DEBUG_BUFSIZE - len - 1), + "%s", p->description); else seq_printf(f, "%s", p->description); - return; + return buf; } break; } if (!f) - printk("%04x", usage & 0xffff); + snprintf(buf + len, max(0, HID_DEBUG_BUFSIZE - len - 1), + "%04x", usage & 0xffff); else seq_printf(f, "%04x", usage & 0xffff); + return buf; } EXPORT_SYMBOL_GPL(hid_resolv_usage); @@ -508,13 +549,37 @@ void hid_dump_device(struct hid_device *device, struct seq_file *f) } EXPORT_SYMBOL_GPL(hid_dump_device); -void hid_dump_input(struct hid_usage *usage, __s32 value) { - if (hid_debug < 2) +/* enqueue string to 'events' ring buffer */ +void hid_debug_event(struct hid_device *hdev, char *buf) +{ + int i; + struct hid_debug_list *list; + + list_for_each_entry(list, &hdev->debug_list, node) { + for (i = 0; i <= strlen(buf); i++) + list->hid_debug_buf[(list->tail + i) % (HID_DEBUG_BUFSIZE - 1)] = + buf[i]; + list->tail = (list->tail + i) % (HID_DEBUG_BUFSIZE - 1); + } +} +EXPORT_SYMBOL_GPL(hid_debug_event); + +void hid_dump_input(struct hid_device *hdev, struct hid_usage *usage, __s32 value) +{ + char *buf; + int len; + + buf = hid_resolv_usage(usage->hid, NULL); + if (!buf) return; + len = strlen(buf); + snprintf(buf + len, HID_DEBUG_BUFSIZE - len - 1, " = %d\n", value); + + hid_debug_event(hdev, buf); + + kfree(buf); + wake_up_interruptible(&hdev->debug_wait); - printk(KERN_DEBUG "hid-debug: input "); - hid_resolv_usage(usage->hid, NULL); - printk(" = %d\n", value); } EXPORT_SYMBOL_GPL(hid_dump_input); @@ -808,6 +873,7 @@ void hid_dump_input_mapping(struct hid_device *hid, struct seq_file *f) } + static int hid_debug_rdesc_show(struct seq_file *f, void *p) { struct hid_device *hdev = f->private; @@ -831,6 +897,126 @@ static int hid_debug_rdesc_open(struct inode *inode, struct file *file) return single_open(file, hid_debug_rdesc_show, inode->i_private); } +static int hid_debug_events_open(struct inode *inode, struct file *file) +{ + int err = 0; + struct hid_debug_list *list; + + if (!(list = kzalloc(sizeof(struct hid_debug_list), GFP_KERNEL))) { + err = -ENOMEM; + goto out; + } + + if (!(list->hid_debug_buf = kzalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_KERNEL))) { + err = -ENOMEM; + goto out; + } + list->hdev = (struct hid_device *) inode->i_private; + file->private_data = list; + mutex_init(&list->read_mutex); + + list_add_tail(&list->node, &list->hdev->debug_list); + +out: + return err; +} + +static ssize_t hid_debug_events_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct hid_debug_list *list = file->private_data; + int ret = 0, len; + DECLARE_WAITQUEUE(wait, current); + + while (ret == 0) { + mutex_lock(&list->read_mutex); + if (list->head == list->tail) { + add_wait_queue(&list->hdev->debug_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + while (list->head == list->tail) { + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + + if (!list->hdev || !list->hdev->debug) { + ret = -EIO; + break; + } + + /* allow O_NONBLOCK from other threads */ + mutex_unlock(&list->read_mutex); + schedule(); + mutex_lock(&list->read_mutex); + set_current_state(TASK_INTERRUPTIBLE); + } + + set_current_state(TASK_RUNNING); + remove_wait_queue(&list->hdev->debug_wait, &wait); + } + + if (ret) + goto out; + + /* pass the ringbuffer contents to userspace */ +copy_rest: + if (list->tail == list->head) + goto out; + if (list->tail > list->head) { + len = list->tail - list->head; + + if (copy_to_user(buffer + ret, &list->hid_debug_buf[list->head], len)) { + ret = -EFAULT; + goto out; + } + ret += len; + list->head += len; + } else { + len = HID_DEBUG_BUFSIZE - list->head; + + if (copy_to_user(buffer, &list->hid_debug_buf[list->head], len)) { + ret = -EFAULT; + goto out; + } + list->head = 0; + ret += len; + goto copy_rest; + } + + } +out: + mutex_unlock(&list->read_mutex); + return ret; +} + +static unsigned int hid_debug_events_poll(struct file *file, poll_table *wait) +{ + struct hid_debug_list *list = file->private_data; + + poll_wait(file, &list->hdev->debug_wait, wait); + if (list->head != list->tail) + return POLLIN | POLLRDNORM; + if (!list->hdev->debug) + return POLLERR | POLLHUP; + return 0; +} + +static int hid_debug_events_release(struct inode *inode, struct file *file) +{ + struct hid_debug_list *list = file->private_data; + + list_del(&list->node); + kfree(list->hid_debug_buf); + kfree(list); + + return 0; +} + static const struct file_operations hid_debug_rdesc_fops = { .open = hid_debug_rdesc_open, .read = seq_read, @@ -838,16 +1024,31 @@ static const struct file_operations hid_debug_rdesc_fops = { .release = single_release, }; +static const struct file_operations hid_debug_events_fops = { + .owner = THIS_MODULE, + .open = hid_debug_events_open, + .read = hid_debug_events_read, + .poll = hid_debug_events_poll, + .release = hid_debug_events_release, +}; + + void hid_debug_register(struct hid_device *hdev, const char *name) { hdev->debug_dir = debugfs_create_dir(name, hid_debug_root); hdev->debug_rdesc = debugfs_create_file("rdesc", 0400, hdev->debug_dir, hdev, &hid_debug_rdesc_fops); + hdev->debug_events = debugfs_create_file("events", 0400, + hdev->debug_dir, hdev, &hid_debug_events_fops); + hdev->debug = 1; } void hid_debug_unregister(struct hid_device *hdev) { + hdev->debug = 0; + wake_up_interruptible(&hdev->debug_wait); debugfs_remove(hdev->debug_rdesc); + debugfs_remove(hdev->debug_events); debugfs_remove(hdev->debug_dir); } -- cgit v1.2.3-18-g5258 From 1cc4ce6f5f89cdc355013aa43f06a14a015766d1 Mon Sep 17 00:00:00 2001 From: Maynard Johnson Date: Wed, 27 May 2009 10:15:08 -0500 Subject: oprofile: reset bt_lost_no_mapping with other stats The bt_lost_no_mapping is not getting reset at the start of a profiling run, thus the oprofiled.log shows erroneous values for this statistic. The attached patch fixes this problem. Signed-off-by: Maynard Johnson Signed-off-by: Robert Richter --- drivers/oprofile/oprofile_stats.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c index e1f6ce03705..efefae539a5 100644 --- a/drivers/oprofile/oprofile_stats.c +++ b/drivers/oprofile/oprofile_stats.c @@ -33,6 +33,7 @@ void oprofile_reset_stats(void) atomic_set(&oprofile_stats.sample_lost_no_mm, 0); atomic_set(&oprofile_stats.sample_lost_no_mapping, 0); atomic_set(&oprofile_stats.event_lost_overflow, 0); + atomic_set(&oprofile_stats.bt_lost_no_mapping,0); } -- cgit v1.2.3-18-g5258 From 5b739ef8a4e8cf5201d21abff897e292c232477b Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Thu, 18 Jun 2009 19:50:21 +0800 Subject: random: Add optional continuous repetition test to entropy store based rngs FIPS-140 requires that all random number generators implement continuous self tests in which each extracted block of data is compared against the last block for repetition. The ansi_cprng implements such a test, but it would be nice if the hw rng's did the same thing. Obviously its not something thats always needed, but it seems like it would be a nice feature to have on occasion. I've written the below patch which allows individual entropy stores to be flagged as desiring a continuous test to be run on them as is extracted. By default this option is off, but is enabled in the event that fips mode is selected during bootup. Signed-off-by: Neil Horman Acked-by: Matt Mackall Signed-off-by: Herbert Xu --- drivers/char/random.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/char/random.c b/drivers/char/random.c index 8c7444857a4..d8a9255e1a3 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -240,6 +240,7 @@ #include #include #include +#include #ifdef CONFIG_GENERIC_HARDIRQS # include @@ -413,6 +414,7 @@ struct entropy_store { unsigned add_ptr; int entropy_count; int input_rotate; + __u8 *last_data; }; static __u32 input_pool_data[INPUT_POOL_WORDS]; @@ -852,12 +854,21 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, { ssize_t ret = 0, i; __u8 tmp[EXTRACT_SIZE]; + unsigned long flags; xfer_secondary_pool(r, nbytes); nbytes = account(r, nbytes, min, reserved); while (nbytes) { extract_buf(r, tmp); + + if (r->last_data) { + spin_lock_irqsave(&r->lock, flags); + if (!memcmp(tmp, r->last_data, EXTRACT_SIZE)) + panic("Hardware RNG duplicated output!\n"); + memcpy(r->last_data, tmp, EXTRACT_SIZE); + spin_unlock_irqrestore(&r->lock, flags); + } i = min_t(int, nbytes, EXTRACT_SIZE); memcpy(buf, tmp, i); nbytes -= i; @@ -940,6 +951,9 @@ static void init_std_data(struct entropy_store *r) now = ktime_get_real(); mix_pool_bytes(r, &now, sizeof(now)); mix_pool_bytes(r, utsname(), sizeof(*(utsname()))); + /* Enable continuous test in fips mode */ + if (fips_enabled) + r->last_data = kmalloc(EXTRACT_SIZE, GFP_KERNEL); } static int rand_initialize(void) -- cgit v1.2.3-18-g5258 From 409a736336b560798f84d71ad6477c8fad20b523 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 25 Jun 2009 13:50:53 +0800 Subject: hwrng: Use PCI_VDEVICE Signed-off-by: Joe Perches Acked-by: Matt Mackall Signed-off-by: Herbert Xu --- drivers/char/hw_random/amd-rng.c | 4 ++-- drivers/char/hw_random/geode-rng.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c index cd0ba51f7c8..0d8c5788b8e 100644 --- a/drivers/char/hw_random/amd-rng.c +++ b/drivers/char/hw_random/amd-rng.c @@ -44,8 +44,8 @@ * want to register another driver on the same PCI id. */ static const struct pci_device_id pci_tbl[] = { - { 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, - { 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, + { PCI_VDEVICE(AMD, 0x7443), 0, }, + { PCI_VDEVICE(AMD, 0x746b), 0, }, { 0, }, /* terminate list */ }; MODULE_DEVICE_TABLE(pci, pci_tbl); diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c index 64d513f6836..4c4d4e140f9 100644 --- a/drivers/char/hw_random/geode-rng.c +++ b/drivers/char/hw_random/geode-rng.c @@ -46,8 +46,7 @@ * want to register another driver on the same PCI id. */ static const struct pci_device_id pci_tbl[] = { - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_LX_AES), 0, }, { 0, }, /* terminate list */ }; MODULE_DEVICE_TABLE(pci, pci_tbl); -- cgit v1.2.3-18-g5258 From 55dba52458a11126ff4445b5b94ebde03afcf47a Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 26 Jun 2009 10:50:12 +0200 Subject: HID: fix memory leak on error path in debug code If hid_get_report() fails, we forgot to free the already allocated buffer for debugging messages on error path. Fix that up. Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 449bd747d11..86c2ff2429d 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1100,8 +1100,10 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i hid_debug_event(hid, buf); report = hid_get_report(report_enum, data); - if (!report) + if (!report) { + kfree(buf); return -1; + } /* dump the report */ snprintf(buf, HID_DEBUG_BUFSIZE - 1, -- cgit v1.2.3-18-g5258 From 789b23bc40a67d9a19bedc2655c6bcab79bcabd8 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 26 Jun 2009 15:36:58 +0100 Subject: [ARM] 5572/1: at91: Support for at91sam9g45 series: core chip & board support Here are the at91 specific files dedicated to the at91sam9g45 series. They mimic the traditional at91 way of managing chips & boards. The first board that embeds at91sam9g45 chip is the AT91SAM9G45-EKES. In the future, the main board for this 9g45 series will be the AT91SAM9M10G45-EK (I choose this last name for the board file). Simple drivers are enabled in _devices and board- files. Newer peripheral support will be added in future patches. Incuded peripherals support (for now): - USART - SPI - Ethernet - NAND flash - LCD - gpio/joystick/buttons - leds and pwm Signed-off-by: Nicolas Ferre Acked-by: Andrew Victor Signed-off-by: Russell King --- drivers/net/Kconfig | 2 +- drivers/video/Kconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index c155bd3ec9f..f053ba5c37b 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -209,7 +209,7 @@ config MII config MACB tristate "Atmel MACB support" - depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263 || ARCH_AT91SAM9G20 || ARCH_AT91CAP9 + depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263 || ARCH_AT91SAM9G20 || ARCH_AT91SAM9G45 || ARCH_AT91CAP9 select PHYLIB help The Atmel MACB ethernet interface is found on many AT32 and AT91 diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index d6d65ef85f5..36281823fe5 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -933,7 +933,7 @@ config FB_S1D13XXX config FB_ATMEL tristate "AT91/AT32 LCD Controller support" - depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 || AVR32) + depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 || ARCH_AT91CAP9 || AVR32) select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT -- cgit v1.2.3-18-g5258 From 666cbe342622c959ad95515918a1c1f8210c93f2 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sun, 28 Jun 2009 23:50:08 -0700 Subject: Input: dm355evm_keys - use threaded IRQs Convert the dm355evm keys driver to use IRQ threading instead of a private workqueue. IRQ threads were added to Linux after this driver was written, and in this case fit what the driver needs. (Although the non-shared thread costs more runtime memory.) Signed-off-by: David Brownell Signed-off-by: Dmitry Torokhov --- drivers/input/misc/dm355evm_keys.c | 42 ++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c index a63315ce4a6..0918acae584 100644 --- a/drivers/input/misc/dm355evm_keys.c +++ b/drivers/input/misc/dm355evm_keys.c @@ -23,30 +23,16 @@ * pressed, or its autorepeat kicks in, an event is sent. This driver * read those events from the small (32 event) queue and reports them. * - * Because we communicate with the MSP430 using I2C, and all I2C calls - * in Linux sleep, we need to cons up a kind of threaded IRQ handler - * using a work_struct. The IRQ is active low, but we use it through - * the GPIO controller so we can trigger on falling edges. - * * Note that physically there can only be one of these devices. * * This driver was tested with firmware revision A4. */ struct dm355evm_keys { - struct work_struct work; struct input_dev *input; struct device *dev; int irq; }; -static irqreturn_t dm355evm_keys_irq(int irq, void *_keys) -{ - struct dm355evm_keys *keys = _keys; - - schedule_work(&keys->work); - return IRQ_HANDLED; -} - /* These initial keycodes can be remapped by dm355evm_setkeycode(). */ static struct { u16 event; @@ -110,13 +96,12 @@ static struct { { 0x3169, KEY_PAUSE, }, }; -static void dm355evm_keys_work(struct work_struct *work) +/* runs in an IRQ thread -- can (and will!) sleep */ +static irqreturn_t dm355evm_keys_irq(int irq, void *_keys) { - struct dm355evm_keys *keys; + struct dm355evm_keys *keys = _keys; int status; - keys = container_of(work, struct dm355evm_keys, work); - /* For simplicity we ignore INPUT_COUNT and just read * events until we get the "queue empty" indicator. * Reading INPUT_LOW decrements the count. @@ -183,6 +168,19 @@ static void dm355evm_keys_work(struct work_struct *work) input_report_key(keys->input, keycode, 0); input_sync(keys->input); } + return IRQ_HANDLED; +} + +/* + * Because we communicate with the MSP430 using I2C, and all I2C calls + * in Linux sleep, we use a threaded IRQ handler. The IRQ itself is + * active low, but we go through the GPIO controller so we can trigger + * on falling edges and not worry about enabling/disabling the IRQ in + * the keypress handling path. + */ +static irqreturn_t dm355evm_keys_hardirq(int irq, void *_keys) +{ + return IRQ_WAKE_THREAD; } static int dm355evm_setkeycode(struct input_dev *dev, int index, int keycode) @@ -233,7 +231,6 @@ static int __devinit dm355evm_keys_probe(struct platform_device *pdev) keys->dev = &pdev->dev; keys->input = input; - INIT_WORK(&keys->work, dm355evm_keys_work); /* set up "threaded IRQ handler" */ status = platform_get_irq(pdev, 0); @@ -260,9 +257,10 @@ static int __devinit dm355evm_keys_probe(struct platform_device *pdev) /* REVISIT: flush the event queue? */ - status = request_irq(keys->irq, dm355evm_keys_irq, - IRQF_TRIGGER_FALLING, - dev_name(&pdev->dev), keys); + status = request_threaded_irq(keys->irq, + dm355evm_keys_hardirq, dm355evm_keys_irq, + IRQF_TRIGGER_FALLING, + dev_name(&pdev->dev), keys); if (status < 0) goto fail1; -- cgit v1.2.3-18-g5258 From 0e8635a8e1f2d4a9e1bfc6c3b21419a5921e674f Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sat, 20 Jun 2009 00:53:25 +0000 Subject: net: remove NET_RX_BAD and NET_RX_CN* defines almost no users in the tree; and the few that use them treat them like NET_RX_DROP. Signed-off-by: Florian Westphal Signed-off-by: David S. Miller --- drivers/net/rionet.c | 5 ----- drivers/net/wan/farsync.c | 19 ------------------- drivers/staging/otus/wrap_pkt.c | 3 --- 3 files changed, 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index 8702e7acdee..74cdb6f8f84 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -114,11 +114,6 @@ static int rionet_rx_clean(struct net_device *ndev) if (error == NET_RX_DROP) { ndev->stats.rx_dropped++; - } else if (error == NET_RX_BAD) { - if (netif_msg_rx_err(rnet)) - printk(KERN_WARNING "%s: bad rx packet\n", - DRV_NAME); - ndev->stats.rx_errors++; } else { ndev->stats.rx_packets++; ndev->stats.rx_bytes += RIO_MAX_MSG_SIZE; diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 25c9ef6a181..90c0a317d9d 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -792,25 +792,6 @@ fst_process_rx_status(int rx_status, char *name) */ break; } - - case NET_RX_CN_LOW: - { - dbg(DBG_ASS, "%s: Receive Low Congestion\n", name); - break; - } - - case NET_RX_CN_MOD: - { - dbg(DBG_ASS, "%s: Receive Moderate Congestion\n", name); - break; - } - - case NET_RX_CN_HIGH: - { - dbg(DBG_ASS, "%s: Receive High Congestion\n", name); - break; - } - case NET_RX_DROP: { dbg(DBG_ASS, "%s: Received packet dropped\n", name); diff --git a/drivers/staging/otus/wrap_pkt.c b/drivers/staging/otus/wrap_pkt.c index 5db0004c873..89a6b92f597 100644 --- a/drivers/staging/otus/wrap_pkt.c +++ b/drivers/staging/otus/wrap_pkt.c @@ -156,10 +156,7 @@ void zfLnxRecvEth(zdev_t* dev, zbuf_t* buf, u16_t port) switch(netif_rx(buf)) #endif { - case NET_RX_BAD: case NET_RX_DROP: - case NET_RX_CN_MOD: - case NET_RX_CN_HIGH: break; default: macp->drv_stats.net_stats.rx_packets++; -- cgit v1.2.3-18-g5258 From 6ed106549d17474ca17a16057f4c0ed4eba5a7ca Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 23 Jun 2009 06:03:08 +0000 Subject: net: use NETDEV_TX_OK instead of 0 in ndo_start_xmit() functions This patch is the result of an automatic spatch transformation to convert all ndo_start_xmit() return values of 0 to NETDEV_TX_OK. Some occurences are missed by the automatic conversion, those will be handled in a seperate patch. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- drivers/ieee802154/fakehard.c | 2 +- drivers/isdn/i4l/isdn_net.c | 12 ++++++------ drivers/media/dvb/dvb-core/dvb_net.c | 2 +- drivers/message/fusion/mptlan.c | 2 +- drivers/misc/sgi-xp/xpnet.c | 4 ++-- drivers/net/3c505.c | 2 +- drivers/net/3c507.c | 2 +- drivers/net/3c509.c | 2 +- drivers/net/3c515.c | 4 ++-- drivers/net/3c523.c | 2 +- drivers/net/3c527.c | 4 ++-- drivers/net/3c59x.c | 4 ++-- drivers/net/8139cp.c | 2 +- drivers/net/8139too.c | 4 ++-- drivers/net/82596.c | 4 ++-- drivers/net/amd8111e.c | 2 +- drivers/net/appletalk/cops.c | 2 +- drivers/net/appletalk/ipddp.c | 4 ++-- drivers/net/appletalk/ltpc.c | 2 +- drivers/net/ariadne.c | 4 ++-- drivers/net/arm/am79c961a.c | 2 +- drivers/net/arm/at91_ether.c | 2 +- drivers/net/arm/ether1.c | 2 +- drivers/net/arm/ether3.c | 4 ++-- drivers/net/at1700.c | 2 +- drivers/net/atarilance.c | 4 ++-- drivers/net/atp.c | 2 +- drivers/net/au1000_eth.c | 2 +- drivers/net/bfin_mac.c | 2 +- drivers/net/bmac.c | 2 +- drivers/net/can/sja1000/sja1000.c | 2 +- drivers/net/cassini.c | 4 ++-- drivers/net/cris/eth_v10.c | 2 +- drivers/net/cs89x0.c | 2 +- drivers/net/de600.c | 2 +- drivers/net/de620.c | 2 +- drivers/net/declance.c | 4 ++-- drivers/net/dm9000.c | 2 +- drivers/net/dnet.c | 2 +- drivers/net/dummy.c | 2 +- drivers/net/e100.c | 2 +- drivers/net/eepro.c | 4 ++-- drivers/net/eexpress.c | 4 ++-- drivers/net/enc28j60.c | 2 +- drivers/net/epic100.c | 4 ++-- drivers/net/eql.c | 2 +- drivers/net/eth16i.c | 4 ++-- drivers/net/ewrk3.c | 2 +- drivers/net/fealnx.c | 2 +- drivers/net/fec.c | 2 +- drivers/net/hamachi.c | 2 +- drivers/net/hamradio/6pack.c | 2 +- drivers/net/hamradio/baycom_epp.c | 6 +++--- drivers/net/hamradio/bpqether.c | 2 +- drivers/net/hamradio/dmascc.c | 2 +- drivers/net/hamradio/hdlcdrv.c | 4 ++-- drivers/net/hamradio/mkiss.c | 2 +- drivers/net/hamradio/scc.c | 6 +++--- drivers/net/hamradio/yam.c | 2 +- drivers/net/hp100.c | 6 +++--- drivers/net/ibmveth.c | 2 +- drivers/net/ioc3-eth.c | 2 +- drivers/net/irda/ali-ircc.c | 8 ++++---- drivers/net/irda/au1k_ir.c | 4 ++-- drivers/net/irda/donauboe.c | 6 +++--- drivers/net/irda/irda-usb.c | 2 +- drivers/net/irda/nsc-ircc.c | 8 ++++---- drivers/net/irda/pxaficp_ir.c | 4 ++-- drivers/net/irda/sa1100_ir.c | 4 ++-- drivers/net/irda/sir_dev.c | 4 ++-- drivers/net/irda/stir4200.c | 2 +- drivers/net/irda/via-ircc.c | 10 +++++----- drivers/net/irda/vlsi_ir.c | 6 +++--- drivers/net/irda/w83977af_ir.c | 4 ++-- drivers/net/isa-skeleton.c | 2 +- drivers/net/iseries_veth.c | 4 ++-- drivers/net/ixgb/ixgb_main.c | 2 +- drivers/net/ixp2000/ixpdev.c | 4 ++-- drivers/net/lance.c | 2 +- drivers/net/lib82596.c | 4 ++-- drivers/net/ll_temac_main.c | 2 +- drivers/net/loopback.c | 2 +- drivers/net/lp486e.c | 4 ++-- drivers/net/mac89x0.c | 2 +- drivers/net/macb.c | 2 +- drivers/net/mace.c | 2 +- drivers/net/meth.c | 2 +- drivers/net/mipsnet.c | 2 +- drivers/net/myri10ge/myri10ge.c | 6 +++--- drivers/net/myri_sbus.c | 2 +- drivers/net/natsemi.c | 2 +- drivers/net/netx-eth.c | 2 +- drivers/net/ni5010.c | 2 +- drivers/net/ni65.c | 2 +- drivers/net/pci-skeleton.c | 2 +- drivers/net/pcmcia/3c574_cs.c | 2 +- drivers/net/pcmcia/3c589_cs.c | 2 +- drivers/net/pcmcia/axnet_cs.c | 2 +- drivers/net/pcmcia/fmvj18x_cs.c | 4 ++-- drivers/net/pcmcia/nmclan_cs.c | 2 +- drivers/net/pcmcia/smc91c92_cs.c | 6 +++--- drivers/net/pcmcia/xirc2ps_cs.c | 4 ++-- drivers/net/pcnet32.c | 2 +- drivers/net/plip.c | 2 +- drivers/net/ppp_generic.c | 4 ++-- drivers/net/rionet.c | 2 +- drivers/net/rrunner.c | 2 +- drivers/net/s2io.c | 10 +++++----- drivers/net/sb1000.c | 2 +- drivers/net/sb1250-mac.c | 2 +- drivers/net/seeq8005.c | 4 ++-- drivers/net/sgiseeq.c | 4 ++-- drivers/net/sh_eth.c | 2 +- drivers/net/sis900.c | 2 +- drivers/net/skfp/skfddi.c | 2 +- drivers/net/slip.c | 6 +++--- drivers/net/smc911x.c | 6 +++--- drivers/net/smc9194.c | 8 ++++---- drivers/net/smc91x.c | 4 ++-- drivers/net/starfire.c | 2 +- drivers/net/sun3_82586.c | 4 ++-- drivers/net/sun3lance.c | 4 ++-- drivers/net/sunbmac.c | 2 +- drivers/net/sundance.c | 2 +- drivers/net/sunhme.c | 2 +- drivers/net/sunlance.c | 2 +- drivers/net/sunqe.c | 2 +- drivers/net/tc35815.c | 2 +- drivers/net/tlan.c | 6 +++--- drivers/net/tokenring/3c359.c | 2 +- drivers/net/tokenring/ibmtr.c | 2 +- drivers/net/tokenring/lanstreamer.c | 2 +- drivers/net/tokenring/olympic.c | 2 +- drivers/net/tulip/de2104x.c | 2 +- drivers/net/tulip/tulip_core.c | 2 +- drivers/net/tulip/uli526x.c | 4 ++-- drivers/net/tulip/winbond-840.c | 2 +- drivers/net/tulip/xircom_cb.c | 2 +- drivers/net/tun.c | 4 ++-- drivers/net/typhoon.c | 2 +- drivers/net/ucc_geth.c | 2 +- drivers/net/usb/catc.c | 2 +- drivers/net/usb/hso.c | 2 +- drivers/net/usb/kaweth.c | 4 ++-- drivers/net/usb/pegasus.c | 2 +- drivers/net/usb/rtl8150.c | 2 +- drivers/net/veth.c | 6 +++--- drivers/net/via-rhine.c | 6 +++--- drivers/net/via-velocity.c | 2 +- drivers/net/vxge/vxge-main.c | 4 ++-- drivers/net/wan/cycx_x25.c | 2 +- drivers/net/wan/hdlc_fr.c | 6 +++--- drivers/net/wan/sbni.c | 4 ++-- drivers/net/wan/x25_asy.c | 10 +++++----- drivers/net/wireless/airo.c | 14 +++++++------- drivers/net/wireless/arlan-main.c | 2 +- drivers/net/wireless/atmel.c | 6 +++--- drivers/net/wireless/mac80211_hwsim.c | 2 +- drivers/net/wireless/netwave_cs.c | 2 +- drivers/net/wireless/ray_cs.c | 6 +++--- drivers/net/wireless/strip.c | 2 +- drivers/net/wireless/zd1201.c | 4 ++-- drivers/net/xen-netfront.c | 4 ++-- drivers/net/yellowfin.c | 4 ++-- drivers/net/znet.c | 4 ++-- drivers/s390/net/ctcm_main.c | 10 +++++----- drivers/staging/at76_usb/at76_usb.c | 8 ++++---- drivers/staging/epl/VirtualEthernetLinux.c | 2 +- drivers/staging/otus/usbdrv.c | 8 ++++---- drivers/staging/slicoss/slicoss.c | 2 +- drivers/usb/gadget/f_phonet.c | 2 +- drivers/usb/gadget/u_ether.c | 6 +++--- 172 files changed, 289 insertions(+), 289 deletions(-) (limited to 'drivers') diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index 0384144c0b3..14045a7ba38 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c @@ -132,7 +132,7 @@ static int ieee802154_fake_xmit(struct sk_buff *skb, struct net_device *dev) /* FIXME: do hardware work here ... */ - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index de4aad076eb..8209ed6c6d2 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -1202,7 +1202,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) { isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'"); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (lp->phone[1]) { ulong flags; @@ -1215,7 +1215,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) if(time_before(jiffies, lp->dialwait_timer)) { isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached"); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else lp->dialwait_timer = 0; } @@ -1243,7 +1243,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) isdn_net_unreachable(ndev, skb, "No channel"); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* Log packet, which triggered dialing */ if (dev->net_verbose) @@ -1258,7 +1258,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) dev_kfree_skb(skb); isdn_net_unbind_channel(lp); spin_unlock_irqrestore(&dev->lock, flags); - return 0; /* STN (skb to nirvana) ;) */ + return NETDEV_TX_OK; /* STN (skb to nirvana) ;) */ } #ifdef CONFIG_IPPP_FILTER if (isdn_ppp_autodial_filter(skb, lp)) { @@ -1267,7 +1267,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) spin_unlock_irqrestore(&dev->lock, flags); isdn_net_unreachable(ndev, skb, "dial rejected: packet filtered"); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } #endif spin_unlock_irqrestore(&dev->lock, flags); @@ -1285,7 +1285,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) isdn_net_unreachable(ndev, skb, "No phone number"); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } } else { /* Device is connected to an ISDN channel */ diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 8280f8d66a3..8c9ae0a3a27 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -904,7 +904,7 @@ static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len, static int dvb_net_tx(struct sk_buff *skb, struct net_device *dev) { dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static u8 mask_normal[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index a9e48e28b1d..bc2ec2182c0 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -795,7 +795,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) IOC_AND_NETDEV_NAMES_s_s(dev), le32_to_cpu(pSimple->FlagsLength))); - return 0; + return NETDEV_TX_OK; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 8d1c60a3f0d..b681bf8abdc 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -436,7 +436,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->data[0] == 0x33) { dev_kfree_skb(skb); - return 0; /* nothing needed to be done */ + return NETDEV_TX_OK; /* nothing needed to be done */ } /* @@ -503,7 +503,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index f71b3540275..7bba480d722 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -1101,7 +1101,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev) prime_rx(dev); spin_unlock_irqrestore(&adapter->lock, flags); netif_start_queue(dev); - return 0; + return NETDEV_TX_OK; } /****************************************************** diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index 96b86659381..9e93a0b39b6 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -537,7 +537,7 @@ static int el16_send_packet (struct sk_buff *skb, struct net_device *dev) /* You might need to clean up and record Tx statistics here. */ - return 0; + return NETDEV_TX_OK; } /* The typical workload of the driver: diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index d2137efbd45..d2515d840c0 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -892,7 +892,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev) outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ } } - return 0; + return NETDEV_TX_OK; } /* The EL3 interrupt handler. */ diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 3e00fa8ea65..85ffd132bad 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -1054,7 +1054,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb, netif_wake_queue(dev); } dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* Put out the doubleword header... */ outl(skb->len, ioaddr + TX_FIFO); @@ -1117,7 +1117,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb, outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ } } - return 0; + return NETDEV_TX_OK; } /* The interrupt handler does all of the Rx thread work and cleans up diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index cdd955c4014..70c701b80d9 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -1198,7 +1198,7 @@ static int elmc_send_packet(struct sk_buff *skb, struct net_device *dev) netif_wake_queue(dev); dev_kfree_skb(skb); #endif - return 0; + return NETDEV_TX_OK; } /******************************************* diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index aaa8a9f405d..72b9ed7f464 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -1035,7 +1035,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) if (skb_padto(skb, ETH_ZLEN)) { netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } atomic_dec(&lp->tx_count); @@ -1066,7 +1066,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) p->control &= ~CONTROL_EOL; netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index c34aee91250..202048450ee 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -2083,7 +2083,7 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) iowrite8(0x00, ioaddr + TxStatus); /* Pop the status stack. */ } } - return 0; + return NETDEV_TX_OK; } static int @@ -2173,7 +2173,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) iowrite16(DownUnstall, ioaddr + EL3_CMD); spin_unlock_irqrestore(&vp->lock, flags); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* The interrupt handler does all of the Rx thread work and cleans up diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 50efde11ea6..07919d0877e 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -891,7 +891,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) cpw8(TxPoll, NormalTxPoll); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* Set or clear the multicast filter for this adaptor. diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 8ae72ec1445..1a223cd1933 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -1706,7 +1706,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) } else { dev_kfree_skb(skb); dev->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } spin_lock_irqsave(&tp->lock, flags); @@ -1731,7 +1731,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) pr_debug("%s: Queued Tx packet size %u to slot %d.\n", dev->name, len, entry); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 77547545509..996cc910221 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -1068,7 +1068,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->len < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } netif_stop_queue(dev); @@ -1110,7 +1110,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_start_queue(dev); - return 0; + return NETDEV_TX_OK; } static void print_eth(unsigned char *add, char *str) diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 19831bd6401..61ac671f97b 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1346,7 +1346,7 @@ static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev) netif_stop_queue(dev); } spin_unlock_irqrestore(&lp->lock, flags); - return 0; + return NETDEV_TX_OK; } /* This function returns all the memory mapped registers of the device. diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index 7f832541980..29b279f88ef 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -920,7 +920,7 @@ static int cops_send_packet(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += skb->len; dev->trans_start = jiffies; dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index 78cea5e80b1..6cfd961bb8d 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -132,7 +132,7 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) } if(rt == NULL) { spin_unlock(&ipddp_route_lock); - return 0; + return NETDEV_TX_OK; } our_addr = atalk_find_dev_addr(rt->dev); @@ -181,7 +181,7 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock(&ipddp_route_lock); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index b642647170b..c80fb9cf8ff 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -932,7 +932,7 @@ static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += skb->len; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* initialization stuff */ diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 58e8d522e5b..47d976cc3d7 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -610,7 +610,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->len < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; len = ETH_ZLEN; } @@ -685,7 +685,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) } local_irq_restore(flags); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index 627bc75da17..164b37e85ee 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -482,7 +482,7 @@ am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index 2e7419a6119..d46a06e20db 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -834,7 +834,7 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev) we free and return(0) or don't free and return 1 */ } - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c index edf770f639f..e47c0d96285 100644 --- a/drivers/net/arm/ether1.c +++ b/drivers/net/arm/ether1.c @@ -748,7 +748,7 @@ ether1_sendpacket (struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); out: - return 0; + return NETDEV_TX_OK; } static void diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c index 455037134aa..1f7a69c929a 100644 --- a/drivers/net/arm/ether3.c +++ b/drivers/net/arm/ether3.c @@ -511,7 +511,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); priv(dev)->stats.tx_dropped ++; netif_start_queue(dev); - return 0; + return NETDEV_TX_OK; } length = (length + 1) & ~1; @@ -562,7 +562,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); out: - return 0; + return NETDEV_TX_OK; } static irqreturn_t diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index 18b566ad4fd..c2227d79673 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -643,7 +643,7 @@ static int net_send_packet (struct sk_buff *skb, struct net_device *dev) netif_start_queue (dev); dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /* The typical workload of the driver: diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 5425ab0c38c..0c0deceb693 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -796,7 +796,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) if (len > skb->len) { if (skb_padto(skb, len)) - return 0; + return NETDEV_TX_OK; } netif_stop_queue (dev); @@ -846,7 +846,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) lp->tx_full = 1; spin_unlock_irqrestore (&lp->devlock, flags); - return 0; + return NETDEV_TX_OK; } /* The LANCE interrupt handler. */ diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 4317b3edb3d..4beacc9c909 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -587,7 +587,7 @@ static int atp_send_packet(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index d3c734f4d67..2aab1ebc6cd 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -988,7 +988,7 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); aup->tx_head = (aup->tx_head + 1) & (NUM_TX_DMA - 1); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index c15fc281f79..f580b21eabd 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -656,7 +656,7 @@ out: dev->trans_start = jiffies; dev->stats.tx_packets++; dev->stats.tx_bytes += (skb->len); - return 0; + return NETDEV_TX_OK; } static void bfin_mac_rx(struct net_device *dev) diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 9578a3dfac0..41600011cfd 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -1488,7 +1488,7 @@ bmac_output(struct sk_buff *skb, struct net_device *dev) struct bmac_data *bp = netdev_priv(dev); skb_queue_tail(bp->queue, skb); bmac_start(dev); - return 0; + return NETDEV_TX_OK; } static void bmac_tx_timeout(unsigned long data) diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 571f133a8fe..1c30dbec195 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -283,7 +283,7 @@ static int sja1000_start_xmit(struct sk_buff *skb, struct net_device *dev) priv->write_reg(priv, REG_CMR, CMD_TR); - return 0; + return NETDEV_TX_OK; } static void sja1000_rx(struct net_device *dev) diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index eb066673c2a..299a33b914f 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -2928,7 +2928,7 @@ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev) static int ring; if (skb_padto(skb, cp->min_frame_size)) - return 0; + return NETDEV_TX_OK; /* XXX: we need some higher-level QoS hooks to steer packets to * individual queues. @@ -2936,7 +2936,7 @@ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev) if (cas_xmit_tx_ringN(cp, ring++ & N_TX_RINGS_MASK, skb)) return NETDEV_TX_BUSY; dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static void cas_init_tx_dma(struct cas *cp) diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index 7a18dc7e5c7..15c0195ebd3 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -1108,7 +1108,7 @@ e100_send_packet(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&np->lock, flags); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 3eee666a9cd..b5f553a4aa4 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -1571,7 +1571,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) * to restart the netdevice layer */ - return 0; + return NETDEV_TX_OK; } /* The typical workload of the driver: diff --git a/drivers/net/de600.c b/drivers/net/de600.c index e1af089064b..6b13f4fd2e9 100644 --- a/drivers/net/de600.c +++ b/drivers/net/de600.c @@ -226,7 +226,7 @@ static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev) } spin_unlock_irqrestore(&de600_lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/de620.c b/drivers/net/de620.c index 55d2bb67cff..45794f6cb0f 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -542,7 +542,7 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_packets++; spin_unlock_irqrestore(&de620_lock, flags); dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /***************************************************** diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 2b22e580c4d..a31696a3928 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -902,7 +902,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) if (len < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; len = ETH_ZLEN; } @@ -933,7 +933,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void lance_load_multicast(struct net_device *dev) diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index dd771dea6ae..ffd9edceb31 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -788,7 +788,7 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) /* free this SKB */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/dnet.c b/drivers/net/dnet.c index 33fa9eee4ca..2818d5de394 100644 --- a/drivers/net/dnet.c +++ b/drivers/net/dnet.c @@ -596,7 +596,7 @@ static int dnet_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static void dnet_reset_hw(struct dnet *bp) diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 8ebd7d78940..713ce6c532c 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -85,7 +85,7 @@ static int dummy_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += skb->len; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static int dummy_validate(struct nlattr *tb[], struct nlattr *data[]) diff --git a/drivers/net/e100.c b/drivers/net/e100.c index efa680f4b8d..a150d58ec60 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1720,7 +1720,7 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } netdev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static int e100_tx_clean(struct nic *nic) diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index cc2ab6412c7..71605d63708 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -1145,7 +1145,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } netif_stop_queue (dev); @@ -1178,7 +1178,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev) eepro_en_int(ioaddr); spin_unlock_irqrestore(&lp->lock, flags); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 1686dca2874..8c44ef4ba35 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -664,7 +664,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev) if (buf->len < ETH_ZLEN) { if (skb_padto(buf, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } @@ -691,7 +691,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev) spin_unlock_irqrestore(&lp->lock, flags); #endif enable_irq(dev->irq); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index fc6cc038c7b..372d6c6a4e7 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -1299,7 +1299,7 @@ static int enc28j60_send_packet(struct sk_buff *skb, struct net_device *dev) priv->tx_skb = skb; schedule_work(&priv->tx_work); - return 0; + return NETDEV_TX_OK; } static void enc28j60_tx_work_handler(struct work_struct *work) diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index b60e27dfcfa..d6a7aa3142f 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -970,7 +970,7 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags; if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; /* Caution: the write order is important here, set the field with the "ownership" bit last. */ @@ -1014,7 +1014,7 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->name, (int)skb->len, entry, ctrl_word, (int)inl(dev->base_addr + TxSTAT)); - return 0; + return NETDEV_TX_OK; } static void epic_tx_error(struct net_device *dev, struct epic_private *ep, diff --git a/drivers/net/eql.c b/drivers/net/eql.c index 19b7dd98394..c0e69c5cae8 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -348,7 +348,7 @@ static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock(&eql->queue.lock); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index 0d8b6da046f..97d5205edc8 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -1064,7 +1064,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } buf = skb->data; @@ -1126,7 +1126,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev) /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */ status = 0; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void eth16i_rx(struct net_device *dev) diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 1e972328140..9c51bc813ad 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -868,7 +868,7 @@ static int ewrk3_queue_pkt (struct sk_buff *skb, struct net_device *dev) if (inb (EWRK3_FMQC) == 0) netif_stop_queue (dev); - return 0; + return NETDEV_TX_OK; err_out: ENABLE_IRQs; diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index 891be28a7d4..75e5fe5153d 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -1374,7 +1374,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; spin_unlock_irqrestore(&np->lock, flags); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 0f19b743749..08f1edb83f2 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -366,7 +366,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&fep->hw_lock, flags); - return 0; + return NETDEV_TX_OK; } static void diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 9d5b62cb30f..4e8d3728e82 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1369,7 +1369,7 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: Hamachi transmit frame #%d queued in slot %d.\n", dev->name, hmp->cur_tx, entry); } - return 0; + return NETDEV_TX_OK; } /* The interrupt handler does all of the Rx thread work and cleans up diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 155160052c8..e88209fc2a2 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -255,7 +255,7 @@ static int sp_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static int sp_open_dev(struct net_device *dev) diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index 5e4b7afd068..e229edf3261 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -774,18 +774,18 @@ static int baycom_send_packet(struct sk_buff *skb, struct net_device *dev) if (skb->data[0] != 0) { do_kiss_params(bc, skb->data, skb->len); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (bc->skb) return NETDEV_TX_LOCKED; /* strip KISS byte */ if (skb->len >= HDLCDRV_MAXFLEN+1 || skb->len < 3) { dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } netif_stop_queue(dev); bc->skb = skb; - return 0; + return NETDEV_TX_OK; } /* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index abcd19a8bff..4c5f4dfbe05 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -305,7 +305,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev) dev_queue_xmit(skb); netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index 7459b3ac77a..950f3bb21f9 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -959,7 +959,7 @@ static int scc_send_packet(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&priv->ring_lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c index d034f8ca63c..16b060b9211 100644 --- a/drivers/net/hamradio/hdlcdrv.c +++ b/drivers/net/hamradio/hdlcdrv.c @@ -406,13 +406,13 @@ static int hdlcdrv_send_packet(struct sk_buff *skb, struct net_device *dev) if (skb->data[0] != 0) { do_kiss_params(sm, skb->data, skb->len); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (sm->skb) return NETDEV_TX_LOCKED; netif_stop_queue(dev); sm->skb = skb; - return 0; + return NETDEV_TX_OK; } /* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index fda2fc83e9a..ac191ef2119 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -560,7 +560,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev) kfree_skb(skb); } - return 0; + return NETDEV_TX_OK; } static int ax_open_dev(struct net_device *dev) diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index d712e7af780..c5406525c1a 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -1643,7 +1643,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev) if (skb->len > scc->stat.bufsize || skb->len < 2) { scc->dev_stat.tx_dropped++; /* bogus frame */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } scc->dev_stat.tx_packets++; @@ -1656,7 +1656,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev) if (kisscmd) { scc_set_param(scc, kisscmd, *skb->data); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } spin_lock_irqsave(&scc->lock, flags); @@ -1684,7 +1684,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev) __scc_start_tx_timer(scc, t_dwait, 0); } spin_unlock_irqrestore(&scc->lock, flags); - return 0; + return NETDEV_TX_OK; } /* ----> ioctl functions <---- */ diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index b06691937ce..b85aa162314 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -600,7 +600,7 @@ static int yam_send_packet(struct sk_buff *skb, struct net_device *dev) skb_queue_tail(&yp->send_queue, skb); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static void yam_start_tx(struct net_device *dev, struct yam_port *yp) diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 1d3429a415e..d1b63387e9b 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -1499,7 +1499,7 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev) goto drop; if (lp->chip == HP100_CHIPID_SHASTA && skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; /* Get Tx ring tail pointer */ if (lp->txrtail->next == lp->txrhead) { @@ -1585,7 +1585,7 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev) lp->stats.tx_bytes += skb->len; dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; drop: dev_kfree_skb(skb); @@ -1752,7 +1752,7 @@ static int hp100_start_xmit(struct sk_buff *skb, struct net_device *dev) printk("hp100: %s: start_xmit: end\n", dev->name); #endif - return 0; + return NETDEV_TX_OK; drop: dev_kfree_skb(skb); diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 0995c438f28..76b295a1818 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -971,7 +971,7 @@ out: spin_lock_irqsave(&adapter->stats_lock, flags); spin_unlock_irqrestore(&adapter->stats_lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static int ibmveth_poll(struct napi_struct *napi, int budget) diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index e3cfefab670..8ec15ab8c8c 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -1515,7 +1515,7 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&ip->ioc3_lock); - return 0; + return NETDEV_TX_OK; } static void ioc3_timeout(struct net_device *dev) diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index ad179558002..70983578244 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -1466,7 +1466,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else self->new_speed = speed; } @@ -1577,7 +1577,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ ); - return 0; + return NETDEV_TX_OK; } @@ -1991,7 +1991,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else self->new_speed = speed; } @@ -2015,7 +2015,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ ); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c index c4361d46659..22baf65e156 100644 --- a/drivers/net/irda/au1k_ir.c +++ b/drivers/net/irda/au1k_ir.c @@ -502,7 +502,7 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) aup->newspeed = 0; } dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } ptxd = aup->tx_ring[aup->tx_head]; @@ -555,7 +555,7 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); aup->tx_head = (aup->tx_head + 1) & (NUM_IR_DESC - 1); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 9a0346e751a..1484c76becf 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -1021,7 +1021,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) { spin_unlock_irqrestore(&self->spinlock, flags); dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /* True packet, go on, but */ /* do not accept anything before change speed execution */ @@ -1036,7 +1036,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) toshoboe_setbaud (self); spin_unlock_irqrestore(&self->spinlock, flags); dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } } @@ -1143,7 +1143,7 @@ dumpbufs(skb->data,skb->len,'>'); spin_unlock_irqrestore(&self->spinlock, flags); dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /*interrupt handler */ diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 0c0831c03f6..6a1aa7a40fe 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -534,7 +534,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) } spin_unlock_irqrestore(&self->lock, flags); - return 0; + return NETDEV_TX_OK; drop: /* Drop silently the skb and exit */ diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 45fd9c1eb34..05bfc987b34 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -1397,7 +1397,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else self->new_speed = speed; } @@ -1424,7 +1424,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) @@ -1467,7 +1467,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else { /* Change speed after current frame */ self->new_speed = speed; @@ -1554,7 +1554,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c index 3376a4f39e0..e76a083f901 100644 --- a/drivers/net/irda/pxaficp_ir.c +++ b/drivers/net/irda/pxaficp_ir.c @@ -504,7 +504,7 @@ static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) pxa_irda_set_speed(si, speed); } dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } netif_stop_queue(dev); @@ -539,7 +539,7 @@ static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static int pxa_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 2aeb2e6aec1..70e6acc597b 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -667,7 +667,7 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) sa1100_irda_set_speed(si, speed); } dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (!IS_FIR(si)) { @@ -715,7 +715,7 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static int diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index fd0796c3db3..bde004f0a7a 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -621,7 +621,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) */ dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } else dev->new_speed = speed; } @@ -668,7 +668,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) } spin_unlock_irqrestore(&dev->tx_lock, flags); - return 0; + return NETDEV_TX_OK; } /* called from network layer with rtnl hold */ diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 8e5e45caf2f..c475b23091b 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -578,7 +578,7 @@ static int stir_hard_xmit(struct sk_buff *skb, struct net_device *netdev) dev_kfree_skb(skb); } - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 864798502ff..62ba94ba7c9 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -844,7 +844,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb, via_ircc_change_speed(self, speed); dev->trans_start = jiffies; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else self->new_speed = speed; } @@ -892,7 +892,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb, dev->trans_start = jiffies; spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static int via_ircc_hard_xmit_fir(struct sk_buff *skb, @@ -907,7 +907,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb, iobase = self->io.fir_base; if (self->st_fifo.len) - return 0; + return NETDEV_TX_OK; if (self->chip_id == 0x3076) iodelay(1500); else @@ -919,7 +919,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb, via_ircc_change_speed(self, speed); dev->trans_start = jiffies; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else self->new_speed = speed; } @@ -940,7 +940,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb, dev->trans_start = jiffies; dev_kfree_skb(skb); spin_unlock_irqrestore(&self->lock, flags); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index ac0e4b6b6b6..08e26f1297b 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -915,7 +915,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) */ spin_unlock_irqrestore(&idev->lock, flags); dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } /* sanity checks - simply drop the packet */ @@ -1044,7 +1044,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) } spin_unlock_irqrestore(&idev->lock, flags); - return 0; + return NETDEV_TX_OK; drop_unlock: spin_unlock_irqrestore(&idev->lock, flags); @@ -1058,7 +1058,7 @@ drop: * packet for later retry of transmission - which isn't exactly * what we want after we've just called dev_kfree_skb_any ;-) */ - return 0; + return NETDEV_TX_OK; } static void vlsi_tx_interrupt(struct net_device *ndev) diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index d0883835b0c..49ef76320f5 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -516,7 +516,7 @@ static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) w83977af_change_speed(self, speed); dev->trans_start = jiffies; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else self->new_speed = speed; } @@ -576,7 +576,7 @@ static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) /* Restore set register */ outb(set, iobase+SSR); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c index 73585fd8f29..86d2300af37 100644 --- a/drivers/net/isa-skeleton.c +++ b/drivers/net/isa-skeleton.c @@ -467,7 +467,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb (skb); #endif - return 0; + return NETDEV_TX_OK; } #if TX_RING diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index e44215cb188..e36e951cbc6 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -1205,7 +1205,7 @@ static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev) if ( ! ((1 << rlp) & port->lpar_map) ) { dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } lpmask = 1 << rlp; @@ -1217,7 +1217,7 @@ static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* You must hold the connection's lock when you call this function. */ diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 9c897cf86b9..eb917f16027 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1459,7 +1459,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (skb->len <= 0) { dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (unlikely(ixgb_maybe_stop_tx(netdev, &adapter->tx_ring, diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c index 2a0174b62e9..588b44d944c 100644 --- a/drivers/net/ixp2000/ixpdev.c +++ b/drivers/net/ixp2000/ixpdev.c @@ -45,7 +45,7 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(skb->len > PAGE_SIZE)) { /* @@@ Count drops. */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } entry = tx_pointer; @@ -69,7 +69,7 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); local_irq_enable(); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 633808d447b..30fd4f5f1d5 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -1016,7 +1016,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) out: spin_unlock_irqrestore(&lp->devlock, flags); - return 0; + return NETDEV_TX_OK; } /* The LANCE interrupt handler. */ diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c index 070fa450087..51e11c3e53e 100644 --- a/drivers/net/lib82596.c +++ b/drivers/net/lib82596.c @@ -983,7 +983,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } @@ -1028,7 +1028,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_start_queue(dev); - return 0; + return NETDEV_TX_OK; } static void print_eth(unsigned char *add, char *str) diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index 96e7248876c..da8d0a0ca94 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c @@ -591,7 +591,7 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) /* Kick off the transfer */ temac_dma_out32(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */ - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index da472c68748..51bbce72bed 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -89,7 +89,7 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) } else lb_stats->drops++; - return 0; + return NETDEV_TX_OK; } static struct net_device_stats *loopback_get_stats(struct net_device *dev) diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index d44bddbee37..c292bad411e 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -871,7 +871,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) { if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } @@ -906,7 +906,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) { dev->stats.tx_packets++; } - return 0; + return NETDEV_TX_OK; } static void diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index dab45339d3a..149e0ed4a05 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -411,7 +411,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /* The typical workload of the driver: diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 5b5c25368d1..d22952c78f1 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -678,7 +678,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static void macb_free_consistent(struct macb *bp) diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 1427755c224..7d7577b598e 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -581,7 +581,7 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); spin_unlock_irqrestore(&mp->lock, flags); - return 0; + return NETDEV_TX_OK; } static void mace_set_multicast(struct net_device *dev) diff --git a/drivers/net/meth.c b/drivers/net/meth.c index 5d04d94f2a2..abea35de255 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -715,7 +715,7 @@ static int meth_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&priv->meth_lock, flags); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c index b3b9a147d09..8ea98bd89ff 100644 --- a/drivers/net/mipsnet.c +++ b/drivers/net/mipsnet.c @@ -141,7 +141,7 @@ static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); mipsnet_put_todevice(dev, skb); - return 0; + return NETDEV_TX_OK; } static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t len) diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 1f6e36ea669..05cd24d0d0c 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -2748,7 +2748,7 @@ again: /* The packet is gone, so we must * return 0 */ ss->stats.tx_dropped += 1; - return 0; + return NETDEV_TX_OK; } /* adjust the len to account for the zero pad * so that the nic can know how long it is */ @@ -2892,7 +2892,7 @@ again: tx->stop_queue++; netif_tx_stop_queue(netdev_queue); } - return 0; + return NETDEV_TX_OK; abort_linearize: /* Free any DMA resources we've alloced and clear out the skb @@ -2936,7 +2936,7 @@ abort_linearize: drop: dev_kfree_skb_any(skb); ss->stats.tx_dropped += 1; - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 5f0758bda6b..29ebebc6a95 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -692,7 +692,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev) DTX(("tbusy=0, returning 0\n")); netif_start_queue(dev); spin_unlock_irqrestore(&mp->irq_lock, flags); - return 0; + return NETDEV_TX_OK; } /* Create the MyriNet MAC header for an arbitrary protocol layer diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index c9bfe4eea18..481aa2d287a 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -2125,7 +2125,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", dev->name, np->cur_tx, entry); } - return 0; + return NETDEV_TX_OK; } static void netdev_tx_done(struct net_device *dev) diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c index 946366dcc99..9f4235466d5 100644 --- a/drivers/net/netx-eth.c +++ b/drivers/net/netx-eth.c @@ -134,7 +134,7 @@ netx_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) spin_unlock_irq(&priv->lock); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void netx_eth_receive(struct net_device *ndev) diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c index 2a8da476ab3..462d20f2643 100644 --- a/drivers/net/ni5010.c +++ b/drivers/net/ni5010.c @@ -463,7 +463,7 @@ static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev) hardware_send_packet(dev, (unsigned char *)skb->data, skb->len, length-skb->len); dev->trans_start = jiffies; dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index 1f10ed603e2..81a06178589 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -1216,7 +1216,7 @@ static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&p->ring_lock, flags); } - return 0; + return NETDEV_TX_OK; } static void set_multicast_list(struct net_device *dev) diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 8c1f6988f39..e4a93b8ed48 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -1356,7 +1356,7 @@ static int netdrv_start_xmit (struct sk_buff *skb, struct net_device *dev) DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n", dev->name, skb->data, skb->len, entry); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index f35c609ba02..a23aa872404 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -806,7 +806,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) pop_tx_status(dev); spin_unlock_irqrestore(&lp->window_lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* The EL3 interrupt handler. */ diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index ec7cf5ac4f0..a77417c51e4 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -635,7 +635,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&priv->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* The EL3 interrupt handler. */ diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 0e38d80fd25..b5cfac7c517 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -1179,7 +1179,7 @@ static int axnet_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb (skb); dev->stats.tx_bytes += send_length; - return 0; + return NETDEV_TX_OK; } /** diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 479d5b49437..434d9407bfb 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -865,7 +865,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } @@ -924,7 +924,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev) } dev_kfree_skb (skb); - return 0; + return NETDEV_TX_OK; } /* fjn_start_xmit */ /*====================================================================*/ diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 02ef63ed1f9..0f8118a8257 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -990,7 +990,7 @@ static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* mace_start_xmit */ /* ---------------------------------------------------------------------------- diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 37e05d3ab89..2f39244c17f 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -1399,7 +1399,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb (skb); smc->saved_skb = NULL; dev->stats.tx_dropped++; - return 0; /* Do not re-queue this packet. */ + return NETDEV_TX_OK; /* Do not re-queue this packet. */ } /* A packet is now waiting. */ smc->packets_waiting++; @@ -1422,7 +1422,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev) outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT); smc_hardware_send_packet(dev); /* Send the packet now.. */ spin_unlock_irqrestore(&smc->lock, flags); - return 0; + return NETDEV_TX_OK; } } @@ -1431,7 +1431,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev) outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT); spin_unlock_irqrestore(&smc->lock, flags); - return 0; + return NETDEV_TX_OK; } /*====================================================================== diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index ef37d22c7e1..eda7bf6047c 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -1384,7 +1384,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev) if (pktlen < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; pktlen = ETH_ZLEN; } @@ -1414,7 +1414,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; dev->stats.tx_bytes += pktlen; netif_start_queue(dev); - return 0; + return NETDEV_TX_OK; } /**************** diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 1c35e1d637a..955a87ac9af 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -2536,7 +2536,7 @@ static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } spin_unlock_irqrestore(&lp->lock, flags); - return 0; + return NETDEV_TX_OK; } /* The PCNET32 interrupt handler. */ diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 7a62f781fef..ef2e229ebc1 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -987,7 +987,7 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev) schedule_work(&nl->immediate); spin_unlock_irq(&nl->lock); - return 0; + return NETDEV_TX_OK; } static void diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 639d11bc444..d0b965517b4 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -988,12 +988,12 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); skb_queue_tail(&ppp->file.xq, skb); ppp_xmit_process(ppp); - return 0; + return NETDEV_TX_OK; outf: kfree_skb(skb); ++dev->stats.tx_dropped; - return 0; + return NETDEV_TX_OK; } static int diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index 74cdb6f8f84..bc98e7f69ee 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -203,7 +203,7 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) spin_unlock_irqrestore(&rnet->tx_lock, flags); - return 0; + return NETDEV_TX_OK; } static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u16 tid, diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index 81dbcbb910f..d9553465591 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -1466,7 +1466,7 @@ static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&rrpriv->lock, flags); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 458daa06ed4..d4df9330c44 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -4111,14 +4111,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(skb->len <= 0)) { DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name); dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } if (!is_s2io_card_up(sp)) { DBG_PRINT(TX_DBG, "%s: Card going down for reset\n", dev->name); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } queue = 0; @@ -4192,7 +4192,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) s2io_stop_tx_queue(sp, fifo->fifo_no); dev_kfree_skb(skb); spin_unlock_irqrestore(&fifo->tx_lock, flags); - return 0; + return NETDEV_TX_OK; } offload_type = s2io_offload_type(skb); @@ -4304,14 +4304,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) if (sp->config.intr_type == MSI_X) tx_intr_handler(fifo); - return 0; + return NETDEV_TX_OK; pci_map_failed: stats->pci_map_fail_cnt++; s2io_stop_tx_queue(sp, fifo->fifo_no); stats->mem_freed += skb->truesize; dev_kfree_skb(skb); spin_unlock_irqrestore(&fifo->tx_lock, flags); - return 0; + return NETDEV_TX_OK; } static void diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index fc0e38bddee..6a81aec645d 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -1086,7 +1086,7 @@ sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_WARNING "%s: trying to transmit!!!\n", dev->name); /* sb1000 can't xmit datagrams */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* SB1000 interrupt handler. */ diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index d8c9cf1b901..4c2450b6bd0 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2091,7 +2091,7 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&sc->sbm_lock, flags); - return 0; + return NETDEV_TX_OK; } /********************************************************************** diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index ebbbe09725f..7cc8bb81413 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -401,7 +401,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } buf = skb->data; @@ -415,7 +415,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb (skb); /* You might need to clean up and record Tx statistics here. */ - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 5fb88ca6dd7..78f60089b55 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -594,7 +594,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev) len = skb->len; if (len < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; len = ETH_ZLEN; } @@ -642,7 +642,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); spin_unlock_irqrestore(&sp->tx_lock, flags); - return 0; + return NETDEV_TX_OK; } static void timeout(struct net_device *dev) diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index a2d82ddb3b4..4c4dcbf1902 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -1133,7 +1133,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) ndev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* device close function */ diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index a9a897bb42d..61ceeaaf104 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -1628,7 +1628,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) "to slot %d.\n", net_dev->name, skb->data, (int)skb->len, entry); - return 0; + return NETDEV_TX_OK; } /** diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index 088fe26484e..0c31272cf54 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -1091,7 +1091,7 @@ static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } // skfp_send_pkt diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 5c61d5fad90..899c4a2112c 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -484,12 +484,12 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock(&sl->lock); printk(KERN_WARNING "%s: xmit call when iface is down\n", dev->name); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (sl->tty == NULL) { spin_unlock(&sl->lock); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } sl_lock(sl); @@ -498,7 +498,7 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock(&sl->lock); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index bc4976ac871..2a6b6de9533 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -553,7 +553,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_dropped++; spin_unlock_irqrestore(&lp->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } #ifdef SMC_USE_DMA @@ -566,7 +566,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) lp->pending_tx_skb = skb; netif_stop_queue(dev); spin_unlock_irqrestore(&lp->lock, flags); - return 0; + return NETDEV_TX_OK; } else { DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: Activating Tx DMA\n", dev->name); lp->txdma_active = 1; @@ -577,7 +577,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) smc911x_hardware_send_pkt(dev); spin_unlock_irqrestore(&lp->lock, flags); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index e02471b2f2b..0a1b6f40108 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -512,7 +512,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) { netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } length = ETH_ZLEN; } @@ -534,7 +534,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de lp->saved_skb = NULL; /* this IS an error, but, i don't want the skb saved */ netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } /* either way, a packet is waiting now */ lp->packets_waiting++; @@ -571,12 +571,12 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de SMC_ENABLE_INT( IM_ALLOC_INT ); PRINTK2((CARDNAME": memory allocation deferred. \n")); /* it's deferred, but I'll handle it later */ - return 0; + return NETDEV_TX_OK; } /* or YES! I can send the packet now.. */ smc_hardware_send_packet(dev); netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index fdcbaf8dfa7..2968c75ff49 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -655,7 +655,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_errors++; dev->stats.tx_dropped++; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } smc_special_lock(&lp->lock); @@ -692,7 +692,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) smc_hardware_send_pkt((unsigned long)dev); } - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 838cce8b8ff..1018349a29d 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -1311,7 +1311,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index 7bb27426dbd..2f1eaaf7a72 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -1015,7 +1015,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev) if(skb->len > XMIT_BUFF_SIZE) { printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len); - return 0; + return NETDEV_TX_OK; } netif_stop_queue(dev); @@ -1110,7 +1110,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); #endif } - return 0; + return NETDEV_TX_OK; } /******************************************* diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index 534dfe3eef6..0ca4241b4f6 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -562,7 +562,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) netif_start_queue(dev); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } @@ -648,7 +648,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) local_irq_restore(flags); - return 0; + return NETDEV_TX_OK; } /* The LANCE interrupt handler. */ diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 5017d7fcb40..536cf7e06bf 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -984,7 +984,7 @@ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static struct net_device_stats *bigmac_get_stats(struct net_device *dev) diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 545f81b34ad..0df6332ed9c 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -1091,7 +1091,7 @@ start_tx (struct sk_buff *skb, struct net_device *dev) "%s: Transmit frame #%d queued in slot %d.\n", dev->name, np->cur_tx, entry); } - return 0; + return NETDEV_TX_OK; } /* Reset hardware tx and free all of tx buffers */ diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 4ef729198e1..008bd59fc64 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2338,7 +2338,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; tx_add_log(hp, TXLOG_ACTION_TXMIT, 0); - return 0; + return NETDEV_TX_OK; } static struct net_device_stats *happy_meal_get_stats(struct net_device *dev) diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index afc7b351e5e..9d6fd4760ea 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1163,7 +1163,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* taken from the depca driver */ diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index c6ec61e0acc..dcefb608a9f 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -621,7 +621,7 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void qe_set_multicast(struct net_device *dev) diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index d737f6b8f87..1ce2da172ca 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -1509,7 +1509,7 @@ static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev) */ spin_unlock_irqrestore(&lp->lock, flags); - return 0; + return NETDEV_TX_OK; } #define FATAL_ERROR_INT \ diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 384cb5e2839..70c9ec45d8f 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -1095,11 +1095,11 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s PHY is not ready\n", dev->name ); dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } if (skb_padto(skb, TLAN_MIN_FRAME_SIZE)) - return 0; + return NETDEV_TX_OK; txlen = max(skb->len, (unsigned int)TLAN_MIN_FRAME_SIZE); tail_list = priv->txList + priv->txTail; @@ -1150,7 +1150,7 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS ); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* TLan_StartTx */ diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index b40b6de2d08..1787d52941b 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -1240,7 +1240,7 @@ static int xl_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; - return 0; + return NETDEV_TX_OK; } else { spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; return NETDEV_TX_BUSY; diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 9d896116cf7..6472ba5cfc5 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -1041,7 +1041,7 @@ static int tok_send_packet(struct sk_buff *skb, struct net_device *dev) writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); spin_unlock_irqrestore(&(ti->lock), flags); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /*****************************************************************************/ diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index b3715efdce5..d07e61a9499 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -1183,7 +1183,7 @@ static int streamer_xmit(struct sk_buff *skb, struct net_device *dev) streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1); spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags); - return 0; + return NETDEV_TX_OK; } else { netif_stop_queue(dev); spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags); diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 451b54136ed..f73f4e684f3 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -1052,7 +1052,7 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev) writew((((readw(olympic_mmio+TXENQ_1)) & 0x8000) ^ 0x8000) | 1,olympic_mmio+TXENQ_1); netif_wake_queue(dev); spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); - return 0; + return NETDEV_TX_OK; } else { spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); return NETDEV_TX_BUSY; diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 81f054dbb88..769af558a34 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -651,7 +651,7 @@ static int de_start_xmit (struct sk_buff *skb, struct net_device *dev) dw32(TxPoll, NormalTxPoll); dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* Set or clear the multicast filter for this adaptor. diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 2abb5d3becc..9d46638d250 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -690,7 +690,7 @@ tulip_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static void tulip_clean_tx_ring(struct tulip_private *tp) diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index 9277ce8febe..9074a34eb81 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -582,7 +582,7 @@ static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->len > MAX_PACKET_SIZE) { printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } spin_lock_irqsave(&db->lock, flags); @@ -624,7 +624,7 @@ static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev) /* free this SKB */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 842b1a2c40d..6bc7540b216 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -1058,7 +1058,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", dev->name, np->cur_tx, entry); } - return 0; + return NETDEV_TX_OK; } static void netdev_tx_done(struct net_device *dev) diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index c2ca9f40e40..22b6a239fb3 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -434,7 +434,7 @@ static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev) card->transmit_used = nextdescriptor; leave("xircom-start_xmit - sent"); spin_unlock_irqrestore(&card->lock,flags); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/tun.c b/drivers/net/tun.c index b393536012f..c3927b42374 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -398,12 +398,12 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev) if (tun->flags & TUN_FASYNC) kill_fasync(&tun->fasync, SIGIO, POLL_IN); wake_up_interruptible(&tun->socket.wait); - return 0; + return NETDEV_TX_OK; drop: dev->stats.tx_dropped++; kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void tun_net_mclist(struct net_device *dev) diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index cf25eb41b1c..2c26b4577e8 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -909,7 +909,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev) netif_wake_queue(dev); } - return 0; + return NETDEV_TX_OK; } static void diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 40c6eba775c..5ba95867a2b 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3173,7 +3173,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) #endif spin_unlock_irq(&ugeth->lock); - return 0; + return NETDEV_TX_OK; } static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit) diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index b9dd4257428..7abdc4abbe0 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -448,7 +448,7 @@ static int catc_start_xmit(struct sk_buff *skb, struct net_device *netdev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void catc_tx_timeout(struct net_device *netdev) diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index f8c6d7ea726..ffe41063573 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -780,7 +780,7 @@ static int hso_net_start_xmit(struct sk_buff *skb, struct net_device *net) netif_stop_queue(net); if (hso_get_activity(odev->parent) == -EAGAIN) { odev->skb_tx_buf = skb; - return 0; + return NETDEV_TX_OK; } /* log if asked */ diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index e0131478971..09a5bd38156 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -829,7 +829,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) kaweth->stats.tx_errors++; netif_start_queue(net); spin_unlock_irq(&kaweth->device_lock); - return 0; + return NETDEV_TX_OK; } } @@ -864,7 +864,7 @@ skip: spin_unlock_irq(&kaweth->device_lock); - return 0; + return NETDEV_TX_OK; } /**************************************************************** diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 73acbd244aa..632d1aeda57 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -914,7 +914,7 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net) } dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev) diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index fcc6fa0905d..bac8b77fb25 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -753,7 +753,7 @@ static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev) netdev->trans_start = jiffies; } - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 1097c72e44d..f1d753daa5b 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -189,17 +189,17 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev) rcv_stats->rx_packets++; netif_rx(skb); - return 0; + return NETDEV_TX_OK; tx_drop: kfree_skb(skb); stats->tx_dropped++; - return 0; + return NETDEV_TX_OK; rx_drop: kfree_skb(skb); rcv_stats->rx_dropped++; - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index d3489a3c4c0..71522015831 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -1225,7 +1225,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) entry = rp->cur_tx % TX_RING_SIZE; if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; rp->tx_skbuff[entry] = skb; @@ -1237,7 +1237,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); rp->tx_skbuff[entry] = NULL; dev->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } /* Padding is not copied and so must be redone. */ @@ -1285,7 +1285,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", dev->name, rp->cur_tx-1, entry); } - return 0; + return NETDEV_TX_OK; } /* The interrupt handler does all of the Rx thread work and cleans up diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 3ba35956327..42365e5f931 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -2098,7 +2098,7 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) #ifdef VELOCITY_ZERO_COPY_SUPPORT if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) { kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } #endif diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 6034497536a..fd0ebf78bea 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -1000,7 +1000,7 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev) VXGE_COMPLETE_VPATH_TX(fifo); vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...", dev->name, __func__, __LINE__); - return 0; + return NETDEV_TX_OK; _exit0: vxge_debug_tx(VXGE_TRACE, "%s: pci_map_page failed", dev->name); @@ -1024,7 +1024,7 @@ _exit2: spin_unlock_irqrestore(&fifo->tx_lock, flags); VXGE_COMPLETE_VPATH_TX(fifo); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index f525f9fe74d..4ae9bd297cc 100644 --- a/drivers/net/wan/cycx_x25.c +++ b/drivers/net/wan/cycx_x25.c @@ -663,7 +663,7 @@ static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb, free_packet: dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* Get Ethernet-style interface statistics. diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index bfa0161a02d..52438c76bf8 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -421,7 +421,7 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) GFP_ATOMIC)) { dev->stats.tx_dropped++; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } skb_put(skb, pad); memset(skb->data + len, 0, pad); @@ -435,13 +435,13 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_compressed++; skb->dev = pvc->frad; dev_queue_xmit(skb); - return 0; + return NETDEV_TX_OK; } } dev->stats.tx_dropped++; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static inline void fr_log_dlci_active(pvc_device *pvc) diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 3fb9dbc88a1..545178e6765 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -465,7 +465,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) prepare_to_send( skb, p ); spin_unlock( &nl->lock ); netif_start_queue( dev ); - return 0; + return NETDEV_TX_OK; } } @@ -485,7 +485,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) prepare_to_send( skb, dev ); spin_unlock( &nl->lock ); - return 0; + return NETDEV_TX_OK; } #endif /* CONFIG_SBNI_MULTILINE */ diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index d67e208ab37..1047920e742 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -308,7 +308,7 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_ERR "%s: xmit call when iface is down\n", dev->name); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } switch (skb->data[0]) { @@ -319,14 +319,14 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) if (err != LAPB_OK) printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; case 0x02: /* Disconnect request .. do nothing - hang up ?? */ err = lapb_disconnect_request(dev); if (err != LAPB_OK) printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err); default: kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } skb_pull(skb, 1); /* Remove control byte */ /* @@ -344,9 +344,9 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) if (err != LAPB_OK) { printk(KERN_ERR "x25_asy: lapb_data_request error - %d\n", err); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index c70604f0329..49f3139a3fe 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -1927,7 +1927,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { if (!skb) { airo_print_err(dev->name, "%s: skb == NULL!",__func__); - return 0; + return NETDEV_TX_OK; } npacks = skb_queue_len (&ai->txq); @@ -1938,7 +1938,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { return NETDEV_TX_BUSY; } skb_queue_tail (&ai->txq, skb); - return 0; + return NETDEV_TX_OK; } spin_lock_irqsave(&ai->aux_lock, flags); @@ -1951,7 +1951,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { set_bit(FLAG_PENDING_XMIT, &ai->flags); mpi_send_packet (dev); } - return 0; + return NETDEV_TX_OK; } /* @@ -2127,7 +2127,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { if ( skb == NULL ) { airo_print_err(dev->name, "%s: skb == NULL!", __func__); - return 0; + return NETDEV_TX_OK; } /* Find a vacant FID */ @@ -2155,7 +2155,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { wake_up_interruptible(&priv->thr_wait); } else airo_end_xmit(dev); - return 0; + return NETDEV_TX_OK; } static void airo_end_xmit11(struct net_device *dev) { @@ -2199,7 +2199,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { if ( skb == NULL ) { airo_print_err(dev->name, "%s: skb == NULL!", __func__); - return 0; + return NETDEV_TX_OK; } /* Find a vacant FID */ @@ -2227,7 +2227,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { wake_up_interruptible(&priv->thr_wait); } else airo_end_xmit11(dev); - return 0; + return NETDEV_TX_OK; } static void airo_read_stats(struct net_device *dev) diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index d84caf198a2..d479f4735aa 100644 --- a/drivers/net/wireless/arlan-main.c +++ b/drivers/net/wireless/arlan-main.c @@ -1193,7 +1193,7 @@ static int arlan_tx(struct sk_buff *skb, struct net_device *dev) arlan_process_interrupt(dev); ARLAN_DEBUG_EXIT("arlan_tx"); - return 0; + return NETDEV_TX_OK; bad_end: arlan_process_interrupt(dev); diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 291a94bd46f..05813bc3e30 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -793,13 +793,13 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) !(*priv->present_callback)(priv->card)) { dev->stats.tx_errors++; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (priv->station_state != STATION_STATE_READY) { dev->stats.tx_errors++; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* first ensure the timer func cannot run */ @@ -856,7 +856,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_bh(&priv->timerlock); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void atmel_transmit_management_frame(struct atmel_private *priv, diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index e789c6e9938..55f77ad8530 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -314,7 +314,7 @@ static int hwsim_mon_xmit(struct sk_buff *skb, struct net_device *dev) { /* TODO: allow packet injection */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index d63c8992f22..712f26eef35 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -1047,7 +1047,7 @@ static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) { } dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* netwave_start_xmit */ /* diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index b10b0383dfa..64e574c3655 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -937,7 +937,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } switch (ray_hw_xmit(skb->data, length, dev, DATA_TYPE)) { @@ -951,9 +951,9 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) default: dev->trans_start = jiffies; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } - return 0; + return NETDEV_TX_OK; } /* ray_dev_start_xmit */ /*===========================================================================*/ diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 38366a56b71..73300c226f6 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -1582,7 +1582,7 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev) if (skb) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index 4430b8d92e2..dae1bfb7655 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -789,7 +789,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!zd->mac_enabled || zd->monitor) { dev->stats.tx_dropped++; kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } netif_stop_queue(dev); @@ -826,7 +826,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static void zd1201_tx_timeout(struct net_device *dev) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 8d88daeed0c..3700c49d76c 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -558,12 +558,12 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&np->tx_lock); - return 0; + return NETDEV_TX_OK; drop: dev->stats.tx_dropped++; dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } static int xennet_close(struct net_device *dev) diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 3c7a5053f1d..c3722b40a65 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -827,7 +827,7 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb_padto(skb, len)) { yp->tx_skbuff[entry] = NULL; netif_wake_queue(dev); - return 0; + return NETDEV_TX_OK; } } } @@ -881,7 +881,7 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: Yellowfin transmit frame #%d queued in slot %d.\n", dev->name, yp->cur_tx, entry); } - return 0; + return NETDEV_TX_OK; } /* The interrupt handler does all of the Rx thread work and cleans up diff --git a/drivers/net/znet.c b/drivers/net/znet.c index 0a6992d8611..7f9e14131a5 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -546,7 +546,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } @@ -600,7 +600,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length); } dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* The ZNET interrupt handler. */ diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 222e4739443..38b5079f159 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -880,7 +880,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev) "%s(%s): NULL sk_buff passed", CTCM_FUNTAIL, dev->name); priv->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } if (skb_headroom(skb) < (LL_HEADER_LENGTH + 2)) { CTCM_DBF_TEXT_(ERROR, CTC_DBF_ERROR, @@ -888,7 +888,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev) CTCM_FUNTAIL, dev->name, LL_HEADER_LENGTH + 2); dev_kfree_skb(skb); priv->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } /* @@ -901,7 +901,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev) priv->stats.tx_dropped++; priv->stats.tx_errors++; priv->stats.tx_carrier_errors++; - return 0; + return NETDEV_TX_OK; } if (ctcm_test_and_set_busy(dev)) @@ -910,7 +910,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; if (ctcm_transmit_skb(priv->channel[WRITE], skb) != 0) return NETDEV_TX_BUSY; - return 0; + return NETDEV_TX_OK; } /* unmerged MPC variant of ctcm_tx */ @@ -1008,7 +1008,7 @@ done: if (do_debug) MPC_DBF_DEV_NAME(TRACE, dev, "exit"); - return 0; /* handle freeing of skb here */ + return NETDEV_TX_OK; /* handle freeing of skb here */ } diff --git a/drivers/staging/at76_usb/at76_usb.c b/drivers/staging/at76_usb/at76_usb.c index 3f303ae97b4..7b8aa5edf42 100644 --- a/drivers/staging/at76_usb/at76_usb.c +++ b/drivers/staging/at76_usb/at76_usb.c @@ -3134,7 +3134,7 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev) netdev->name, __func__); /* skip this packet */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (priv->tx_urb->status == -EINPROGRESS) { @@ -3142,14 +3142,14 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev) netdev->name, __func__); /* skip this packet */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (skb->len < ETH_HLEN) { printk(KERN_ERR "%s: %s: skb too short (%d)\n", netdev->name, __func__, skb->len); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } at76_ledtrig_tx_activity(); /* tell ledtrigger we send a packet */ @@ -3173,7 +3173,7 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev) skb->data[ETH_HLEN + 1], skb->data[ETH_HLEN + 2]); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } } else { /* add RFC 1042 header in front */ diff --git a/drivers/staging/epl/VirtualEthernetLinux.c b/drivers/staging/epl/VirtualEthernetLinux.c index 077724a556c..7b7cce1b36e 100644 --- a/drivers/staging/epl/VirtualEthernetLinux.c +++ b/drivers/staging/epl/VirtualEthernetLinux.c @@ -223,7 +223,7 @@ static int VEthXmit(struct sk_buff *pSkb_p, struct net_device *pNetDevice_p) } Exit: - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/staging/otus/usbdrv.c b/drivers/staging/otus/usbdrv.c index 540cbbb826f..7cd87caa681 100644 --- a/drivers/staging/otus/usbdrv.c +++ b/drivers/staging/otus/usbdrv.c @@ -659,7 +659,7 @@ int usbdrv_xmit_frame(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } - return 0; + return NETDEV_TX_OK; } @@ -796,13 +796,13 @@ int zfLnxVapXmitFrame(struct sk_buff *skb, struct net_device *dev) if (vapId >= ZM_VAP_PORT_NUMBER) { dev_kfree_skb_irq(skb); - return 0; + return NETDEV_TX_OK; } #if 1 if (vap[vapId].openFlag == 0) { dev_kfree_skb_irq(skb); - return 0; + return NETDEV_TX_OK; } #endif @@ -819,7 +819,7 @@ int zfLnxVapXmitFrame(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } - return 0; + return NETDEV_TX_OK; } static const struct net_device_ops vap_netdev_ops = { diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c index ed47db5ce5f..b01a2822a8e 100644 --- a/drivers/staging/slicoss/slicoss.c +++ b/drivers/staging/slicoss/slicoss.c @@ -845,7 +845,7 @@ static int slic_xmit_start(struct sk_buff *skb, struct net_device *dev) hcmd->paddrh, DONT_FLUSH); } xmit_done: - return 0; + return NETDEV_TX_OK; xmit_fail: slic_xmit_fail(adapter, skb, offloadcmd, skbtype, status); goto xmit_done; diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index 96fb118355b..d17f1082df9 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -256,7 +256,7 @@ out: dev_kfree_skb(skb); dev->stats.tx_dropped++; } - return 0; + return NETDEV_TX_OK; } static int pn_net_mtu(struct net_device *dev, int new_mtu) diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 016f63b3902..aac69b591ae 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -487,7 +487,7 @@ static int eth_start_xmit(struct sk_buff *skb, struct net_device *net) if (!in) { dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } /* apply outgoing CDC or RNDIS filters */ @@ -506,7 +506,7 @@ static int eth_start_xmit(struct sk_buff *skb, struct net_device *net) type = USB_CDC_PACKET_TYPE_ALL_MULTICAST; if (!(cdc_filter & type)) { dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } } /* ignores USB_CDC_PACKET_TYPE_DIRECTED */ @@ -586,7 +586,7 @@ drop: list_add(&req->list, &dev->tx_reqs); spin_unlock_irqrestore(&dev->req_lock, flags); } - return 0; + return NETDEV_TX_OK; } /*-------------------------------------------------------------------------*/ -- cgit v1.2.3-18-g5258 From 6f5bec195839dba3ca0ab8a7a53861e679109c0b Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Wed, 24 Jun 2009 21:05:09 +0000 Subject: Minor code cleanup in drivers/net/r6040.c Replaced '0' by 'bar' in the probe function. The 'bar' variable was already set to '0' and is already used in pci_iomap(). This is cleaner and improves code consistency. Signed-off-by: Michael Opdenacker Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/r6040.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index ed63d23a645..b3197e96f32 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -1112,13 +1112,13 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, } /* IO Size check */ - if (pci_resource_len(pdev, 0) < io_size) { + if (pci_resource_len(pdev, bar) < io_size) { printk(KERN_ERR DRV_NAME ": Insufficient PCI resources, aborting\n"); err = -EIO; goto err_out; } - pioaddr = pci_resource_start(pdev, 0); /* IO map base address */ + pioaddr = pci_resource_start(pdev, bar); /* IO map base address */ pci_set_master(pdev); dev = alloc_etherdev(sizeof(struct r6040_private)); -- cgit v1.2.3-18-g5258 From 7975d1eed732c9d50b41f5847453e324f544bd30 Mon Sep 17 00:00:00 2001 From: Sreenivasa Honnur Date: Wed, 1 Jul 2009 21:12:23 +0000 Subject: vxge: Removed ioremap of unused bar addresses and their references - Removed ioremap of bar1 address Driver needs only bar0 address for register access - Removed references to bar1 and bar2 addresses Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-config.c | 10 ---------- drivers/net/vxge/vxge-config.h | 10 +--------- drivers/net/vxge/vxge-main.c | 34 +++++++++------------------------- drivers/net/vxge/vxge-main.h | 1 - 4 files changed, 10 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index 58d2551c78e..9e94c4b0fb1 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -313,14 +313,6 @@ __vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev) hldev->kdfc = (u8 __iomem *)(hldev->bar0 + VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64)); break; - case 2: - hldev->kdfc = (u8 __iomem *)(hldev->bar1 + - VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64)); - break; - case 4: - hldev->kdfc = (u8 __iomem *)(hldev->bar2 + - VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64)); - break; default: break; } @@ -831,8 +823,6 @@ vxge_hw_device_initialize( sizeof(struct vxge_hw_device_config)); hldev->bar0 = attr->bar0; - hldev->bar1 = attr->bar1; - hldev->bar2 = attr->bar2; hldev->pdev = attr->pdev; hldev->uld_callbacks.link_up = attr->uld_callbacks.link_up; diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h index afbdf6f4d22..224acea771e 100644 --- a/drivers/net/vxge/vxge-config.h +++ b/drivers/net/vxge/vxge-config.h @@ -682,8 +682,6 @@ struct __vxge_hw_vpath_handle{ * @major_revision: PCI Device major revision * @minor_revision: PCI Device minor revision * @bar0: BAR0 virtual address. - * @bar1: BAR1 virtual address. - * @bar2: BAR2 virtual address. * @pdev: Physical device handle * @config: Confguration passed by the LL driver at initialization * @link_state: Link state @@ -698,8 +696,6 @@ struct __vxge_hw_device { u8 major_revision; u8 minor_revision; void __iomem *bar0; - void __iomem *bar1; - void __iomem *bar2; struct pci_dev *pdev; struct net_device *ndev; struct vxge_hw_device_config config; @@ -788,17 +784,13 @@ struct vxge_hw_device_hw_info { /** * struct vxge_hw_device_attr - Device memory spaces. * @bar0: BAR0 virtual address. - * @bar1: BAR1 virtual address. - * @bar2: BAR2 virtual address. * @pdev: PCI device object. * - * Device memory spaces. Includes configuration, BAR0, BAR1, etc. per device + * Device memory spaces. Includes configuration, BAR0 etc. per device * mapped memories. Also, includes a pointer to OS-specific PCI device object. */ struct vxge_hw_device_attr { void __iomem *bar0; - void __iomem *bar1; - void __iomem *bar2; struct pci_dev *pdev; struct vxge_hw_uld_cbs uld_callbacks; }; diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index fd0ebf78bea..8a3c7b327cf 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -4152,18 +4152,6 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) attr.bar0, (unsigned long long)pci_resource_start(pdev, 0)); - attr.bar1 = pci_ioremap_bar(pdev, 2); - if (!attr.bar1) { - vxge_debug_init(VXGE_ERR, - "%s : cannot remap io memory bar2", __func__); - ret = -ENODEV; - goto _exit3; - } - vxge_debug_ll_config(VXGE_TRACE, - "pci ioremap bar1: %p:0x%llx", - attr.bar1, - (unsigned long long)pci_resource_start(pdev, 2)); - status = vxge_hw_device_hw_info_get(attr.bar0, &ll_config.device_hw_info); if (status != VXGE_HW_OK) { @@ -4171,7 +4159,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) "%s: Reading of hardware info failed." "Please try upgrading the firmware.", VXGE_DRIVER_NAME); ret = -EINVAL; - goto _exit4; + goto _exit3; } if (ll_config.device_hw_info.fw_version.major != @@ -4181,7 +4169,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) ll_config.device_hw_info.fw_version.major, VXGE_DRIVER_VERSION_MAJOR); ret = -EINVAL; - goto _exit4; + goto _exit3; } vpath_mask = ll_config.device_hw_info.vpath_mask; @@ -4189,7 +4177,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) vxge_debug_ll_config(VXGE_TRACE, "%s: No vpaths available in device", VXGE_DRIVER_NAME); ret = -EINVAL; - goto _exit4; + goto _exit3; } vxge_debug_ll_config(VXGE_TRACE, @@ -4222,7 +4210,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) vxge_debug_ll_config(VXGE_ERR, "%s: No more vpaths to configure", VXGE_DRIVER_NAME); ret = 0; - goto _exit4; + goto _exit3; } /* Setting driver callbacks */ @@ -4235,7 +4223,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) vxge_debug_init(VXGE_ERR, "Failed to initialize device (%d)", status); ret = -EINVAL; - goto _exit4; + goto _exit3; } vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_LL); @@ -4260,7 +4248,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) if (vxge_device_register(hldev, &ll_config, high_dma, no_of_vpath, &vdev)) { ret = -EINVAL; - goto _exit5; + goto _exit4; } vxge_hw_device_debug_set(hldev, VXGE_TRACE, VXGE_COMPONENT_LL); @@ -4271,7 +4259,6 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) hldev->ndev = vdev->ndev; vdev->mtu = VXGE_HW_DEFAULT_MTU; vdev->bar0 = attr.bar0; - vdev->bar1 = attr.bar1; vdev->max_vpath_supported = max_vpath_supported; vdev->no_of_vpath = no_of_vpath; @@ -4353,7 +4340,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) "%s: mac_addr_list : memory allocation failed", vdev->ndev->name); ret = -EPERM; - goto _exit6; + goto _exit5; } macaddr = (u8 *)&entry->macaddr; memcpy(macaddr, vdev->ndev->dev_addr, ETH_ALEN); @@ -4370,16 +4357,14 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) return 0; -_exit6: +_exit5: for (i = 0; i < vdev->no_of_vpath; i++) vxge_free_mac_add_list(&vdev->vpaths[i]); vxge_device_unregister(hldev); -_exit5: +_exit4: pci_disable_sriov(pdev); vxge_hw_device_terminate(hldev); -_exit4: - iounmap(attr.bar1); _exit3: iounmap(attr.bar0); _exit2: @@ -4438,7 +4423,6 @@ vxge_remove(struct pci_dev *pdev) kfree(vdev->vpaths); iounmap(vdev->bar0); - iounmap(vdev->bar1); pci_disable_sriov(pdev); diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index 9704b2bd432..3386970b7ef 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -363,7 +363,6 @@ struct vxgedev { struct __vxge_hw_vpath_handle *vp_handles[VXGE_HW_MAX_VIRTUAL_PATHS]; void __iomem *bar0; - void __iomem *bar1; struct vxge_sw_stats stats; int mtu; /* Below variables are used for vpath selection to transmit a packet */ -- cgit v1.2.3-18-g5258 From 914d0d714fa472d7f99ef899a8180628ecdcd23c Mon Sep 17 00:00:00 2001 From: Sreenivasa Honnur Date: Wed, 1 Jul 2009 21:13:12 +0000 Subject: vxge: Fixed memory leak by freeing memory allocated for device_config - Fixed memory leak by freeing memory allocated for device_config. Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 8a3c7b327cf..fa4dbc89e27 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -4348,6 +4348,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) vdev->vpaths[i].mac_addr_cnt = 1; } + kfree(device_config); vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...", vdev->ndev->name, __func__, __LINE__); -- cgit v1.2.3-18-g5258 From bd9ee6808b6c9106fd8046693c544d081746184b Mon Sep 17 00:00:00 2001 From: Sreenivasa Honnur Date: Wed, 1 Jul 2009 21:14:03 +0000 Subject: vxge: check for card status before continuing in device close - Fixed the crash in rmmod after vpath open failed when trying to change mtu. We should check for card status before continuing in device close. Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index fa4dbc89e27..dd2add1d756 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -2890,6 +2890,9 @@ int do_vxge_close(struct net_device *dev, int do_io) vdev = (struct vxgedev *)netdev_priv(dev); hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev); + if (unlikely(!is_vxge_card_up(vdev))) + return 0; + /* If vxge_handle_crit_err task is executing, * wait till it completes. */ while (test_and_set_bit(__VXGE_STATE_RESET_CARD, &vdev->state)) -- cgit v1.2.3-18-g5258 From 3255da416de6da8b3bac6d30b8eed61b54953480 Mon Sep 17 00:00:00 2001 From: Sreenivasa Honnur Date: Wed, 1 Jul 2009 21:14:57 +0000 Subject: vxge: Corrected Register map entry for xmac_link registers - Corrected Register map entry for xmac_link registers. Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-reg.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-reg.h b/drivers/net/vxge/vxge-reg.h index 10f4da32929..9a3b823e08d 100644 --- a/drivers/net/vxge/vxge-reg.h +++ b/drivers/net/vxge/vxge-reg.h @@ -1784,7 +1784,7 @@ struct vxge_hw_mrpcim_reg { #define VXGE_HW_XMAC_GEN_ERR_REG_XMACJ_XMAC_FSM_ERR vxge_mBIT(63) /*0x01e18*/ u64 xmac_gen_err_mask; /*0x01e20*/ u64 xmac_gen_err_alarm; -/*0x01e28*/ u64 xmac_link_err_port_reg[2]; +/*0x01e28*/ u64 xmac_link_err_port0_reg; #define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_DOWN vxge_mBIT(3) #define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_UP vxge_mBIT(7) #define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_WENT_DOWN vxge_mBIT(11) @@ -1798,8 +1798,11 @@ struct vxge_hw_mrpcim_reg { #define VXGE_HW_XMAC_LINK_ERR_PORT_REG_RATEMGMT_LASI_INV vxge_mBIT(39) #define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMDIO_MDIO_MGR_ACCESS_COMPLETE \ vxge_mBIT(47) -/*0x01e30*/ u64 xmac_link_err_port_mask[2]; -/*0x01e38*/ u64 xmac_link_err_port_alarm[2]; +/*0x01e30*/ u64 xmac_link_err_port0_mask; +/*0x01e38*/ u64 xmac_link_err_port0_alarm; +/*0x01e40*/ u64 xmac_link_err_port1_reg; +/*0x01e48*/ u64 xmac_link_err_port1_mask; +/*0x01e50*/ u64 xmac_link_err_port1_alarm; /*0x01e58*/ u64 xgxs_gen_err_reg; #define VXGE_HW_XGXS_GEN_ERR_REG_XGXS_XGXS_FSM_ERR vxge_mBIT(63) /*0x01e60*/ u64 xgxs_gen_err_mask; -- cgit v1.2.3-18-g5258 From 6052ae1676b705c67133542e663ec3380f032e2c Mon Sep 17 00:00:00 2001 From: Sreenivasa Honnur Date: Wed, 1 Jul 2009 21:15:41 +0000 Subject: vxge: Removed the code to bounds check the mss value - Removed the code to bounds check the mss value. The hardware does bounds checking and will not allow an oversized mss to lockup the transmit path. Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-main.c | 5 ----- drivers/net/vxge/vxge-traffic.h | 2 -- 2 files changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index dd2add1d756..cda18f815c3 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -817,7 +817,6 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev) u64 dma_pointer; struct vxge_tx_priv *txdl_priv = NULL; struct __vxge_hw_fifo *fifo_hw; - u32 max_mss = 0x0; int offload_type; unsigned long flags = 0; int vpath_no = 0; @@ -969,10 +968,6 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev) int mss = vxge_tcp_mss(skb); if (mss) { - max_mss = dev->mtu + ETH_HLEN - - VXGE_HW_TCPIP_HEADER_MAX_SIZE; - if (mss > max_mss) - mss = max_mss; vxge_debug_tx(VXGE_TRACE, "%s: %s:%d mss = %d", dev->name, __func__, __LINE__, mss); diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h index 7567a1140d0..8260b91fd79 100644 --- a/drivers/net/vxge/vxge-traffic.h +++ b/drivers/net/vxge/vxge-traffic.h @@ -35,8 +35,6 @@ VXGE_HW_HEADER_VLAN_SIZE + \ VXGE_HW_HEADER_SNAP_SIZE) -#define VXGE_HW_TCPIP_HEADER_MAX_SIZE (64 + 64) - /* 32bit alignments */ #define VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN 2 #define VXGE_HW_HEADER_802_2_SNAP_ALIGN 2 -- cgit v1.2.3-18-g5258 From a5d165b571fcf347e82af6292074d2f0c07de3a6 Mon Sep 17 00:00:00 2001 From: Sreenivasa Honnur Date: Wed, 1 Jul 2009 21:16:37 +0000 Subject: vxge: Fixes in isr routine - Fixes in isr routine Fixed crash with INTA mode during driver unload. Pass hldev to request_irq instead of vdev. Fixed Traffic failure with GRO in INTA mode. Pass the correct napi context to gro functions. Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-main.c | 22 ++++++++++++---------- drivers/net/vxge/vxge-main.h | 1 + 2 files changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index cda18f815c3..060549a7558 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -374,10 +374,10 @@ vxge_rx_complete(struct vxge_ring *ring, struct sk_buff *skb, u16 vlan, if (ring->vlgrp && ext_info->vlan && (ring->vlan_tag_strip == VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE)) - vlan_gro_receive(&ring->napi, ring->vlgrp, + vlan_gro_receive(ring->napi_p, ring->vlgrp, ext_info->vlan, skb); else - napi_gro_receive(&ring->napi, skb); + napi_gro_receive(ring->napi_p, skb); } else { if (ring->vlgrp && vlan && (ring->vlan_tag_strip == @@ -2132,16 +2132,16 @@ int vxge_open_vpaths(struct vxgedev *vdev) */ static irqreturn_t vxge_isr_napi(int irq, void *dev_id) { - struct __vxge_hw_device *hldev = (struct __vxge_hw_device *)dev_id; - struct vxgedev *vdev; struct net_device *dev; + struct __vxge_hw_device *hldev; u64 reason; enum vxge_hw_status status; + struct vxgedev *vdev = (struct vxgedev *) dev_id;; vxge_debug_intr(VXGE_TRACE, "%s:%d", __func__, __LINE__); - dev = hldev->ndev; - vdev = netdev_priv(dev); + dev = vdev->ndev; + hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev); if (pci_channel_offline(vdev->pdev)) return IRQ_NONE; @@ -2412,15 +2412,13 @@ static void vxge_rem_isr(struct vxgedev *vdev) #endif if (vdev->config.intr_type == INTA) { synchronize_irq(vdev->pdev->irq); - free_irq(vdev->pdev->irq, hldev); + free_irq(vdev->pdev->irq, vdev); } } static int vxge_add_isr(struct vxgedev *vdev) { int ret = 0; - struct __vxge_hw_device *hldev = - (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev); #ifdef CONFIG_PCI_MSI int vp_idx = 0, intr_idx = 0, intr_cnt = 0, msix_idx = 0, irq_req = 0; u64 function_mode = vdev->config.device_hw_info.function_mode; @@ -2574,7 +2572,7 @@ INTA_MODE: if (vdev->config.intr_type == INTA) { ret = request_irq((int) vdev->pdev->irq, vxge_isr_napi, - IRQF_SHARED, vdev->desc[0], hldev); + IRQF_SHARED, vdev->desc[0], vdev); if (ret) { vxge_debug_init(VXGE_ERR, "%s %s-%d: ISR registration failed", @@ -2707,11 +2705,15 @@ vxge_open(struct net_device *dev) netif_napi_add(dev, &vdev->napi, vxge_poll_inta, vdev->config.napi_weight); napi_enable(&vdev->napi); + for (i = 0; i < vdev->no_of_vpath; i++) + vdev->vpaths[i].ring.napi_p = &vdev->napi; } else { for (i = 0; i < vdev->no_of_vpath; i++) { netif_napi_add(dev, &vdev->vpaths[i].ring.napi, vxge_poll_msix, vdev->config.napi_weight); napi_enable(&vdev->vpaths[i].ring.napi); + vdev->vpaths[i].ring.napi_p = + &vdev->vpaths[i].ring.napi; } } diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index 3386970b7ef..a46f7fe938d 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -260,6 +260,7 @@ struct vxge_ring { int gro_enable; struct napi_struct napi; + struct napi_struct *napi_p; #define VXGE_MAX_MAC_ADDR_COUNT 30 -- cgit v1.2.3-18-g5258 From 22fa125ee24f8db497fa447c145a4a1293fab098 Mon Sep 17 00:00:00 2001 From: Sreenivasa Honnur Date: Wed, 1 Jul 2009 21:17:24 +0000 Subject: vxge: Disable fcs stripping. - Disable fcs stripping. The minimum frame size that can be received by the hardware is 57 Bytes. A 64 Byte Ethernet frame with the vlan tag and fcs stripped will result in a 56 Byte frame which will lock up the receive engine. The work around is to disable fcs stripping in the hardware which is done with a firmware upgrade. The fixes are - 1. Ensure that the correct firmware version is used. 2. Decrement the indicated packet length of the receive packet by 4 bytes (FCS length). Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-main.c | 10 ++++++---- drivers/net/vxge/vxge-main.h | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 060549a7558..eaf916b90ab 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -454,6 +454,8 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, vxge_hw_ring_rxd_1b_get(ringh, dtr, &dma_sizes); pkt_length = dma_sizes; + pkt_length -= ETH_FCS_LEN; + vxge_debug_rx(VXGE_TRACE, "%s: %s:%d Packet Length = %d", ring->ndev->name, __func__, __LINE__, pkt_length); @@ -4163,11 +4165,11 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) } if (ll_config.device_hw_info.fw_version.major != - VXGE_DRIVER_VERSION_MAJOR) { + VXGE_DRIVER_FW_VERSION_MAJOR) { vxge_debug_init(VXGE_ERR, - "FW Ver.(maj): %d not driver's expected version: %d", - ll_config.device_hw_info.fw_version.major, - VXGE_DRIVER_VERSION_MAJOR); + "%s: Incorrect firmware version." + "Please upgrade the firmware to version 1.x.x", + VXGE_DRIVER_NAME); ret = -EINVAL; goto _exit3; } diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index a46f7fe938d..18d824c3ab9 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -21,7 +21,7 @@ #define VXGE_DRIVER_NAME "vxge" #define VXGE_DRIVER_VENDOR "Neterion, Inc" -#define VXGE_DRIVER_VERSION_MAJOR 0 +#define VXGE_DRIVER_FW_VERSION_MAJOR 1 #define DRV_VERSION VXGE_VERSION_MAJOR"."VXGE_VERSION_MINOR"."\ VXGE_VERSION_FIX"."VXGE_VERSION_BUILD"-"\ -- cgit v1.2.3-18-g5258 From 0a25bdc69634fb343c4b23e3422a37e5819448f1 Mon Sep 17 00:00:00 2001 From: Sreenivasa Honnur Date: Wed, 1 Jul 2009 21:18:06 +0000 Subject: vxge: Printing the function's configured mode of operation - Printing the function's configured mode of operation. Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-main.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index eaf916b90ab..7b5402b50d0 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -4325,6 +4325,27 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) ll_config.device_hw_info.fw_version.version, ll_config.device_hw_info.fw_date.date); + if (new_device) { + switch (ll_config.device_hw_info.function_mode) { + case VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION: + vxge_debug_init(VXGE_TRACE, + "%s: Single Function Mode Enabled", vdev->ndev->name); + break; + case VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION: + vxge_debug_init(VXGE_TRACE, + "%s: Multi Function Mode Enabled", vdev->ndev->name); + break; + case VXGE_HW_FUNCTION_MODE_SRIOV: + vxge_debug_init(VXGE_TRACE, + "%s: Single Root IOV Mode Enabled", vdev->ndev->name); + break; + case VXGE_HW_FUNCTION_MODE_MRIOV: + vxge_debug_init(VXGE_TRACE, + "%s: Multi Root IOV Mode Enabled", vdev->ndev->name); + break; + } + } + vxge_print_parm(vdev, vpath_mask); /* Store the fw version for ethttool option */ -- cgit v1.2.3-18-g5258 From a73e76e23c20c05cb8c0b7ba8bc9daa04b05c80f Mon Sep 17 00:00:00 2001 From: Sreenivasa Honnur Date: Wed, 1 Jul 2009 21:18:43 +0000 Subject: vxge: Version update - Version update Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h index 82786ffb7dd..580c6eb077b 100644 --- a/drivers/net/vxge/vxge-version.h +++ b/drivers/net/vxge/vxge-version.h @@ -18,6 +18,6 @@ #define VXGE_VERSION_MAJOR "2" #define VXGE_VERSION_MINOR "0" #define VXGE_VERSION_FIX "4" -#define VXGE_VERSION_BUILD "17795" +#define VXGE_VERSION_BUILD "17899" #define VXGE_VERSION_FOR "k" #endif -- cgit v1.2.3-18-g5258 From ec634fe328182a1a098585bfc7b69e5042bdb08d Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sun, 5 Jul 2009 19:23:38 -0700 Subject: net: convert remaining non-symbolic return values in ndo_start_xmit() functions This patch converts the remaining occurences of raw return values to their symbolic counterparts in ndo_start_xmit() functions that were missed by the previous automatic conversion. Additionally code that assumed the symbolic value of NETDEV_TX_OK to be zero is changed to explicitly use NETDEV_TX_OK. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- drivers/isdn/hysdn/hysdn_net.c | 2 +- drivers/isdn/i4l/isdn_net.c | 4 +-- drivers/isdn/i4l/isdn_ppp.c | 6 ++-- drivers/net/3c501.c | 2 +- drivers/net/7990.c | 2 +- drivers/net/a2065.c | 4 +-- drivers/net/bonding/bond_3ad.c | 2 +- drivers/net/bonding/bond_alb.c | 2 +- drivers/net/bonding/bond_main.c | 8 ++--- drivers/net/defxx.c | 6 ++-- drivers/net/depca.c | 2 +- drivers/net/ibm_newemac/core.c | 2 +- drivers/net/ifb.c | 2 +- drivers/net/irda/ali-ircc.c | 4 +-- drivers/net/irda/donauboe.c | 2 +- drivers/net/irda/nsc-ircc.c | 2 +- drivers/net/irda/sir_dev.c | 2 +- drivers/net/irda/smsc-ircc2.c | 16 ++++----- drivers/net/irda/via-ircc.c | 2 +- drivers/net/lib8390.c | 2 +- drivers/net/mlx4/en_tx.c | 2 +- drivers/net/myri10ge/myri10ge.c | 4 +-- drivers/net/ni52.c | 4 +-- drivers/net/skfp/skfddi.c | 2 +- drivers/net/sonic.c | 4 +-- drivers/net/tokenring/smctr.c | 2 +- drivers/net/tokenring/tms380tr.c | 2 +- drivers/net/tulip/dmfe.c | 4 +-- drivers/net/wan/dlci.c | 4 +-- drivers/net/wan/dscc4.c | 2 +- drivers/net/wan/farsync.c | 8 ++--- drivers/net/wan/lmc/lmc_main.c | 2 +- drivers/net/wan/wanxl.c | 2 +- drivers/net/wireless/hostap/hostap_80211_tx.c | 42 +++++++++++----------- drivers/net/wireless/ipw2x00/libipw_tx.c | 4 +-- drivers/net/wireless/prism54/islpci_eth.c | 2 +- drivers/net/wireless/wavelan.c | 2 +- drivers/net/wireless/wavelan_cs.c | 4 +-- drivers/net/wireless/wl3501_cs.c | 3 +- drivers/s390/net/claw.c | 2 ++ drivers/s390/net/lcs.c | 8 ++--- drivers/s390/net/netiucv.c | 6 ++-- drivers/s390/net/qeth_l2_main.c | 1 + drivers/s390/net/qeth_l3_main.c | 1 + drivers/staging/rt2860/rt_main_dev.c | 6 ++-- drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c | 4 +-- drivers/staging/rtl8187se/r8180_core.c | 4 +-- drivers/staging/wlan-ng/p80211netdev.c | 2 +- 48 files changed, 105 insertions(+), 102 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c index 579974cf4c9..c73004b3b2a 100644 --- a/drivers/isdn/hysdn/hysdn_net.c +++ b/drivers/isdn/hysdn/hysdn_net.c @@ -148,7 +148,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev) if (lp->sk_count <= 3) { schedule_work(&((hysdn_card *) dev->ml_priv)->irq_queue); } - return (0); /* success */ + return NETDEV_TX_OK; /* success */ } /* net_send_packet */ diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 8209ed6c6d2..57bf4bf5027 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -1051,12 +1051,12 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) isdn_net_dev *nd; isdn_net_local *slp; isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev); - int retv = 0; + int retv = NETDEV_TX_OK; if (((isdn_net_local *) netdev_priv(ndev))->master) { printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* For the other encaps the header has already been built */ diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index aa30b5cb351..2d14b64202a 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -1223,7 +1223,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) isdn_net_dev *nd; unsigned int proto = PPP_IP; /* 0x21 */ struct ippp_struct *ipt,*ipts; - int slot, retval = 0; + int slot, retval = NETDEV_TX_OK; mlp = (isdn_net_local *) netdev_priv(netdev); nd = mlp->netdev; /* get master lp */ @@ -1240,7 +1240,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ if (ipts->debug & 0x1) printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name); - retval = 1; + retval = NETDEV_TX_BUSY; goto out; } @@ -1261,7 +1261,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) lp = isdn_net_get_locked_lp(nd); if (!lp) { printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name); - retval = 1; + retval = NETDEV_TX_BUSY; goto out; } /* we have our lp locked from now on */ diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 367bec63620..e29fb1a4a61 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -485,7 +485,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) if (el_debug > 2) pr_debug(" queued xmit.\n"); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* A receive upset our load, despite our best efforts */ if (el_debug > 2) diff --git a/drivers/net/7990.c b/drivers/net/7990.c index 69f5b7d298a..b1e5764628c 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -585,7 +585,7 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) lp->tx_full = 1; spin_unlock_irqrestore (&lp->devlock, flags); - return 0; + return NETDEV_TX_OK; } EXPORT_SYMBOL_GPL(lance_start_xmit); diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 85a18175730..7302e4385bc 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -553,11 +553,11 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) volatile struct lance_regs *ll = lp->ll; volatile struct lance_init_block *ib = lp->init_block; int entry, skblen; - int status = 0; + int status = NETDEV_TX_OK; unsigned long flags; if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; skblen = max_t(unsigned, skb->len, ETH_ZLEN); local_irq_save(flags); diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index d4b570886c6..0e7dfe0981d 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -2431,7 +2431,7 @@ out: dev_kfree_skb(skb); } read_unlock(&bond->lock); - return 0; + return NETDEV_TX_OK; } int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev) diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 46d312bedfb..bf45d200292 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -1413,7 +1413,7 @@ out: } read_unlock(&bond->curr_slave_lock); read_unlock(&bond->lock); - return 0; + return NETDEV_TX_OK; } void bond_alb_monitor(struct work_struct *work) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index d927f71af8a..66596d80b50 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4277,7 +4277,7 @@ out: dev_kfree_skb(skb); } read_unlock(&bond->lock); - return 0; + return NETDEV_TX_OK; } @@ -4308,7 +4308,7 @@ out: read_unlock(&bond->curr_slave_lock); read_unlock(&bond->lock); - return 0; + return NETDEV_TX_OK; } /* @@ -4354,7 +4354,7 @@ out: dev_kfree_skb(skb); } read_unlock(&bond->lock); - return 0; + return NETDEV_TX_OK; } /* @@ -4414,7 +4414,7 @@ out: /* frame sent to all suitable interfaces */ read_unlock(&bond->lock); - return 0; + return NETDEV_TX_OK; } /*------------------------- Device initialization ---------------------------*/ diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index 102b8d43971..b2e0a8fc21d 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -3218,7 +3218,7 @@ static int dfx_xmt_queue_pkt( bp->xmt_length_errors++; /* bump error counter */ netif_wake_queue(dev); dev_kfree_skb(skb); - return(0); /* return "success" */ + return NETDEV_TX_OK; /* return "success" */ } /* * See if adapter link is available, if not, free buffer @@ -3241,7 +3241,7 @@ static int dfx_xmt_queue_pkt( bp->xmt_discards++; /* bump error counter */ dev_kfree_skb(skb); /* free sk_buff now */ netif_wake_queue(dev); - return(0); /* return "success" */ + return NETDEV_TX_OK; /* return "success" */ } } @@ -3345,7 +3345,7 @@ static int dfx_xmt_queue_pkt( dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); spin_unlock_irqrestore(&bp->lock, flags); netif_wake_queue(dev); - return(0); /* packet queued to adapter */ + return NETDEV_TX_OK; /* packet queued to adapter */ } diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 97ea2d6d3fe..adb997c5bb5 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -1793,7 +1793,7 @@ static int __init get_hw_addr(struct net_device *dev) static int load_packet(struct net_device *dev, struct sk_buff *skb) { struct depca_private *lp = netdev_priv(dev); - int i, entry, end, len, status = 0; + int i, entry, end, len, status = NETDEV_TX_OK; entry = lp->tx_new; /* Ring around buffer number. */ end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask; diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index beb84213b67..5443558c439 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -1342,7 +1342,7 @@ static inline int emac_xmit_finish(struct emac_instance *dev, int len) ++dev->stats.tx_packets; dev->stats.tx_bytes += len; - return 0; + return NETDEV_TX_OK; } /* Tx lock BH */ diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 96713ef0629..0a79b451780 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -164,7 +164,7 @@ static int ifb_xmit(struct sk_buff *skb, struct net_device *dev) { struct ifb_private *dp = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; - int ret = 0; + int ret = NETDEV_TX_OK; u32 from = G_TC_FROM(skb->tc_verd); stats->rx_packets++; diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index 70983578244..f0d0cea6e32 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -1966,10 +1966,10 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ ); - IRDA_ASSERT(dev != NULL, return 0;); + IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;); self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return 0;); + IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); iobase = self->io.sir_base; diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 1484c76becf..e4e905698dc 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -981,7 +981,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) self = netdev_priv(dev); - IRDA_ASSERT (self != NULL, return 0; ); + IRDA_ASSERT (self != NULL, return NETDEV_TX_OK; ); IRDA_DEBUG (1, "%s.tx:%x(%x)%x\n", __func__ ,skb->len,self->txpending,INB (OBOE_ENABLEH)); diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 05bfc987b34..51ca89c9a0b 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -1365,7 +1365,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return 0;); + IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); iobase = self->io.fir_base; diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index bde004f0a7a..71dce20e62b 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -590,7 +590,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) int err; s32 speed; - IRDA_ASSERT(dev != NULL, return 0;); + IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;); netif_stop_queue(ndev); diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index d0797adb5f8..15f8a7f8160 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -886,10 +886,10 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) IRDA_DEBUG(1, "%s\n", __func__); - IRDA_ASSERT(dev != NULL, return 0;); + IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;); self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return 0;); + IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); netif_stop_queue(dev); @@ -914,7 +914,7 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) smsc_ircc_change_speed(self, speed); spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } self->new_speed = speed; } @@ -935,7 +935,7 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* @@ -1190,9 +1190,9 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) s32 speed; int mtt; - IRDA_ASSERT(dev != NULL, return 0;); + IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;); self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return 0;); + IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); netif_stop_queue(dev); @@ -1210,7 +1210,7 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) smsc_ircc_change_speed(self, speed); spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } self->new_speed = speed; @@ -1242,7 +1242,7 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 62ba94ba7c9..36a60748447 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -832,7 +832,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb, __u32 speed; self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return 0;); + IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); iobase = self->io.fir_base; netif_stop_queue(dev); diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c index f28c2334300..d6be36000c5 100644 --- a/drivers/net/lib8390.c +++ b/drivers/net/lib8390.c @@ -414,7 +414,7 @@ static int __ei_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb (skb); dev->stats.tx_bytes += send_length; - return 0; + return NETDEV_TX_OK; } /** diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index 08c43f2ae72..d5c18c67425 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c @@ -764,7 +764,7 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) /* Poll CQ here */ mlx4_en_xmit_poll(priv, tx_ind); - return 0; + return NETDEV_TX_OK; tx_drop: dev_kfree_skb_any(skb); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 05cd24d0d0c..1a34f7e11d9 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -2968,13 +2968,13 @@ static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev) } } dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; drop: ss = &mgp->ss[skb_get_queue_mapping(skb)]; dev_kfree_skb_any(skb); ss->stats.tx_dropped += 1; - return 0; + return NETDEV_TX_OK; } static struct net_device_stats *myri10ge_get_stats(struct net_device *dev) diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index 77d44a06170..a0ac5d4f27d 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -1183,7 +1183,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev) if (skb->len > XMIT_BUFF_SIZE) { printk(KERN_ERR "%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n", dev->name, XMIT_BUFF_SIZE, skb->len); - return 0; + return NETDEV_TX_OK; } netif_stop_queue(dev); @@ -1267,7 +1267,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev) } dev_kfree_skb(skb); #endif - return 0; + return NETDEV_TX_OK; } /******************************************* diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index 0c31272cf54..888a14a045e 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -1077,7 +1077,7 @@ static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev) // dequeue packets from xmt queue and send them netif_start_queue(dev); dev_kfree_skb(skb); - return (0); /* return "success" */ + return NETDEV_TX_OK; /* return "success" */ } if (bp->QueueSkb == 0) { // return with tbusy set: queue full diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c index 753a1fba460..9599ce77ef8 100644 --- a/drivers/net/sonic.c +++ b/drivers/net/sonic.c @@ -211,7 +211,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) length = skb->len; if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; length = ETH_ZLEN; } @@ -265,7 +265,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index 54ad4ed0337..6515894c83f 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -4609,7 +4609,7 @@ static int smctr_send_packet(struct sk_buff *skb, struct net_device *dev) if(tp->QueueSkb > 0) netif_wake_queue(dev); - return (0); + return NETDEV_TX_OK; } static int smctr_send_lobe_media_test(struct net_device *dev) diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index a2eab72b507..07f6dfd3ba0 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -682,7 +682,7 @@ static int tms380tr_hardware_send_packet(struct sk_buff *skb, struct net_device tms380tr_exec_sifcmd(dev, CMD_TX_VALID); spin_unlock_irqrestore(&tp->lock, flags); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index 8e78f003f08..5e15fab58c1 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -676,7 +676,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) if (skb->len > MAX_PACKET_SIZE) { printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } spin_lock_irqsave(&db->lock, flags); @@ -722,7 +722,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) /* free this SKB */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 2fa275a58f9..8526b6d1ee4 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -194,7 +194,7 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev) ret = 0; if (!skb || !dev) - return(0); + return NETDEV_TX_OK; dlp = netdev_priv(dev); @@ -219,7 +219,7 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev) /* Alan Cox recommends always returning 0, and always freeing the packet */ /* experience suggest a slightly more conservative approach */ - if (!ret) + if (ret == NETDEV_TX_OK) { dev_kfree_skb(skb); netif_wake_queue(dev); diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 8face5db8f3..e81946d9854 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -1182,7 +1182,7 @@ static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev) if (dscc4_tx_quiescent(dpriv, dev)) dscc4_do_tx(dpriv, dev); - return 0; + return NETDEV_TX_OK; } static int dscc4_close(struct net_device *dev) diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 90c0a317d9d..20a1237a3d7 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -2294,7 +2294,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev) dbg(DBG_ASS, "Tried to transmit but no carrier on card %d port %d\n", card->card_no, port->index); - return 0; + return NETDEV_TX_OK; } /* Drop it if it's too big! MTU failure ? */ @@ -2303,7 +2303,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev) LEN_TX_BUFFER); dev_kfree_skb(skb); dev->stats.tx_errors++; - return 0; + return NETDEV_TX_OK; } /* @@ -2337,7 +2337,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_errors++; dbg(DBG_ASS, "Tx queue overflow card %d port %d\n", card->card_no, port->index); - return 0; + return NETDEV_TX_OK; } /* @@ -2354,7 +2354,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev) fst_q_work_item(&fst_work_txq, card->card_no); tasklet_schedule(&fst_tx_task); - return 0; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index 45b1822c962..d1492ae5d30 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -1428,7 +1428,7 @@ static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev) lmc_softc_t *sc = dev_to_sc(dev); u32 flag; int entry; - int ret = 0; + int ret = NETDEV_TX_OK; unsigned long flags; lmc_trace(dev, "lmc_start_xmit in"); diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c index e4ad7b6b52e..03b76adbe5f 100644 --- a/drivers/net/wan/wanxl.c +++ b/drivers/net/wan/wanxl.c @@ -310,7 +310,7 @@ static int wanxl_xmit(struct sk_buff *skb, struct net_device *dev) } spin_unlock(&port->lock); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index d313b005114..1fe1bbabb90 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -75,7 +75,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb " "(len=%d)\n", dev->name, skb->len); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } if (local->ddev != dev) { @@ -89,14 +89,14 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: prism2_tx: trying to use " "AP device with Ethernet net dev\n", dev->name); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } } else { if (local->iw_mode == IW_MODE_REPEAT) { printk(KERN_DEBUG "%s: prism2_tx: trying to use " "non-WDS link in Repeater mode\n", dev->name); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } else if (local->iw_mode == IW_MODE_INFRA && (local->wds_type & HOSTAP_WDS_AP_CLIENT) && memcmp(skb->data + ETH_ALEN, dev->dev_addr, @@ -210,13 +210,13 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) skb = skb_unshare(skb, GFP_ATOMIC); if (skb == NULL) { iface->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } if (pskb_expand_head(skb, need_headroom, need_tailroom, GFP_ATOMIC)) { kfree_skb(skb); iface->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } } else if (skb_headroom(skb) < need_headroom) { struct sk_buff *tmp = skb; @@ -224,13 +224,13 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) kfree_skb(tmp); if (skb == NULL) { iface->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } } else { skb = skb_unshare(skb, GFP_ATOMIC); if (skb == NULL) { iface->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } } @@ -256,7 +256,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Send IEEE 802.11 encapsulated frame using the master radio device */ skb->dev = local->dev; dev_queue_xmit(skb); - return 0; + return NETDEV_TX_OK; } @@ -276,7 +276,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb " "(len=%d)\n", dev->name, skb->len); kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } iface->stats.tx_packets++; @@ -301,7 +301,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Send IEEE 802.11 encapsulated frame using the master radio device */ skb->dev = local->dev; dev_queue_xmit(skb); - return 0; + return NETDEV_TX_OK; } @@ -396,7 +396,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, " "expected 0x%08x)\n", dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC); - ret = 0; + ret = NETDEV_TX_OK; iface->stats.tx_dropped++; goto fail; } @@ -414,7 +414,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->len < 24) { printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb " "(len=%d)\n", dev->name, skb->len); - ret = 0; + ret = NETDEV_TX_OK; iface->stats.tx_dropped++; goto fail; } @@ -441,13 +441,13 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->name, meta->ethertype); hostap_dump_tx_80211(dev->name, skb); - ret = 0; /* drop packet */ + ret = NETDEV_TX_OK; /* drop packet */ iface->stats.tx_dropped++; goto fail; } break; case AP_TX_DROP: - ret = 0; /* drop packet */ + ret = NETDEV_TX_OK; /* drop packet */ iface->stats.tx_dropped++; goto fail; case AP_TX_RETRY: @@ -455,7 +455,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) case AP_TX_BUFFERED: /* do not free skb here, it will be freed when the * buffered frame is sent/timed out */ - ret = 0; + ret = NETDEV_TX_OK; goto tx_exit; } @@ -501,7 +501,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) "frame (drop_unencrypted=1)\n", dev->name); } iface->stats.tx_dropped++; - ret = 0; + ret = NETDEV_TX_OK; goto fail; } @@ -510,7 +510,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb == NULL) { printk(KERN_DEBUG "%s: TX - encryption failed\n", dev->name); - ret = 0; + ret = NETDEV_TX_OK; goto fail; } meta = (struct hostap_skb_tx_data *) skb->cb; @@ -519,23 +519,23 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) "expected 0x%08x) after hostap_tx_encrypt\n", dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC); - ret = 0; + ret = NETDEV_TX_OK; iface->stats.tx_dropped++; goto fail; } } if (local->func->tx == NULL || local->func->tx(skb, dev)) { - ret = 0; + ret = NETDEV_TX_OK; iface->stats.tx_dropped++; } else { - ret = 0; + ret = NETDEV_TX_OK; iface->stats.tx_packets++; iface->stats.tx_bytes += skb->len; } fail: - if (!ret && skb) + if (ret == NETDEV_TX_OK && skb) dev_kfree_skb(skb); tx_exit: if (tx.sta_ptr) diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c index da2ad5437ce..2e8f84fb29f 100644 --- a/drivers/net/wireless/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/ipw2x00/libipw_tx.c @@ -527,13 +527,13 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) if (ret == 0) { dev->stats.tx_packets++; dev->stats.tx_bytes += txb->payload_size; - return 0; + return NETDEV_TX_OK; } ieee80211_txb_free(txb); } - return 0; + return NETDEV_TX_OK; failed: spin_unlock_irqrestore(&ieee->lock, flags); diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index 8f621099344..c255d9c6a5f 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -234,7 +234,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) /* unlock the driver code */ spin_unlock_irqrestore(&priv->slock, flags); - return 0; + return NETDEV_TX_OK; drop_free: ndev->stats.tx_dropped++; diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index ab7fc5c0c8b..5cb5329a20d 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -2891,7 +2891,7 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) #ifdef DEBUG_TX_TRACE printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); #endif - return 0; + return NETDEV_TX_OK; } /*********************** HARDWARE CONFIGURATION ***********************/ diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 6af706408ac..9dd241adc37 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -3113,7 +3113,7 @@ wavelan_packet_xmit(struct sk_buff * skb, * able to detect collisions, therefore in theory we don't really * need to pad. Jean II */ if (skb_padto(skb, ETH_ZLEN)) - return 0; + return NETDEV_TX_OK; wv_packet_write(dev, skb->data, skb->len); @@ -3122,7 +3122,7 @@ wavelan_packet_xmit(struct sk_buff * skb, #ifdef DEBUG_TX_TRACE printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); #endif - return(0); + return NETDEV_TX_OK; } /********************** HARDWARE CONFIGURATION **********************/ diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index e3e96bb2c24..a83a5621ec4 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1348,7 +1348,6 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (rc) { ++dev->stats.tx_dropped; netif_stop_queue(dev); - rc = NETDEV_TX_OK; } else { ++dev->stats.tx_packets; dev->stats.tx_bytes += skb->len; @@ -1358,7 +1357,7 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } spin_unlock_irqrestore(&this->lock, flags); - return rc; + return NETDEV_TX_OK; } static int wl3501_open(struct net_device *dev) diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index f370f8d460a..c63babefb69 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -350,6 +350,8 @@ claw_tx(struct sk_buff *skb, struct net_device *dev) CLAW_DBF_TEXT_(4, trace, "clawtx%d", rc); if (rc) rc = NETDEV_TX_BUSY; + else + rc = NETDEV_TX_OK; return rc; } /* end of claw_tx */ diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 8c675905448..a70de9b4bf2 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -1553,24 +1553,24 @@ __lcs_start_xmit(struct lcs_card *card, struct sk_buff *skb, struct net_device *dev) { struct lcs_header *header; - int rc = 0; + int rc = NETDEV_TX_OK; LCS_DBF_TEXT(5, trace, "hardxmit"); if (skb == NULL) { card->stats.tx_dropped++; card->stats.tx_errors++; - return 0; + return NETDEV_TX_OK; } if (card->state != DEV_STATE_UP) { dev_kfree_skb(skb); card->stats.tx_dropped++; card->stats.tx_errors++; card->stats.tx_carrier_errors++; - return 0; + return NETDEV_TX_OK; } if (skb->protocol == htons(ETH_P_IPV6)) { dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } netif_stop_queue(card->dev); spin_lock(&card->lock); diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 8c36eafcfbf..bb1183a2ed6 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1376,14 +1376,14 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) if (skb == NULL) { IUCV_DBF_TEXT(data, 2, "netiucv_tx: skb is NULL\n"); privptr->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } if (skb_headroom(skb) < NETIUCV_HDRLEN) { IUCV_DBF_TEXT(data, 2, "netiucv_tx: skb_headroom < NETIUCV_HDRLEN\n"); dev_kfree_skb(skb); privptr->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } /** @@ -1395,7 +1395,7 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) privptr->stats.tx_dropped++; privptr->stats.tx_errors++; privptr->stats.tx_carrier_errors++; - return 0; + return NETDEV_TX_OK; } if (netiucv_test_and_set_busy(dev)) { diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 691cecd03b8..2cfc338c462 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -744,6 +744,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) card->stats.tx_bytes += tx_bytes; if (new_skb != skb) dev_kfree_skb_any(skb); + rc = NETDEV_TX_OK; } else { if (data_offset >= 0) kmem_cache_free(qeth_core_header_cache, hdr); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 54872406864..048defaea81 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2793,6 +2793,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) card->perf_stats.sg_frags_sent += nr_frags + 1; } } + rc = NETDEV_TX_OK; } else { if (data_offset >= 0) kmem_cache_free(qeth_core_header_cache, hdr); diff --git a/drivers/staging/rt2860/rt_main_dev.c b/drivers/staging/rt2860/rt_main_dev.c index f298b9bcec3..35c59d5aa99 100644 --- a/drivers/staging/rt2860/rt_main_dev.c +++ b/drivers/staging/rt2860/rt_main_dev.c @@ -862,7 +862,7 @@ int rt28xx_packet_xmit(struct sk_buff *skb) { struct net_device *net_dev = skb->dev; PRTMP_ADAPTER pAd = net_dev->ml_priv; - int status = 0; + int status = NETDEV_TX_OK; PNDIS_PACKET pPacket = (PNDIS_PACKET) skb; { @@ -892,7 +892,7 @@ int rt28xx_packet_xmit(struct sk_buff *skb) STASendPackets((NDIS_HANDLE)pAd, (PPNDIS_PACKET) &pPacket, 1); - status = 0; + status = NETDEV_TX_OK; done: return status; @@ -923,7 +923,7 @@ INT rt28xx_send_packets( if (!(net_dev->flags & IFF_UP)) { RELEASE_NDIS_PACKET(pAd, (PNDIS_PACKET)skb_p, NDIS_STATUS_FAILURE); - return 0; + return NETDEV_TX_OK; } NdisZeroMemory((PUCHAR)&skb_p->cb[CB_OFF], 15); diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c index 1294e05fcf1..1b774601b4a 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c @@ -802,13 +802,13 @@ int ieee80211_xmit(struct sk_buff *skb, if ((*ieee->hard_start_xmit)(txb, dev) == 0) { stats->tx_packets++; stats->tx_bytes += txb->payload_size; - return 0; + return NETDEV_TX_OK; } ieee80211_txb_free(txb); } } - return 0; + return NETDEV_TX_OK; failed: spin_unlock_irqrestore(&ieee->lock, flags); diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c index 7e2fecae813..26a59118d34 100644 --- a/drivers/staging/rtl8187se/r8180_core.c +++ b/drivers/staging/rtl8187se/r8180_core.c @@ -3040,7 +3040,7 @@ int rtl8180_hard_start_xmit(struct sk_buff *skb,struct net_device *dev) spin_unlock_irqrestore(&priv->tx_lock,flags); dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } rtl8180_tx(dev, skb->data, skb->len, priority, @@ -3051,7 +3051,7 @@ int rtl8180_hard_start_xmit(struct sk_buff *skb,struct net_device *dev) spin_unlock_irqrestore(&priv->tx_lock,flags); dev_kfree_skb_any(skb); - return 0; + return NETDEV_TX_OK; } // longpre 144+48 shortpre 72+24 diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c index 90f499e00dc..c273c034a83 100644 --- a/drivers/staging/wlan-ng/p80211netdev.c +++ b/drivers/staging/wlan-ng/p80211netdev.c @@ -354,7 +354,7 @@ static int p80211knetdev_hard_start_xmit(struct sk_buff *skb, p80211_metawep_t p80211_wep; if (skb == NULL) - return 0; + return NETDEV_TX_OK; if (wlandev->state != WLAN_DEVICE_OPEN) { result = 1; -- cgit v1.2.3-18-g5258 From eacf69a156dd068b3dfaa0aeb4874cda8633de87 Mon Sep 17 00:00:00 2001 From: Guo-Fu Tseng Date: Mon, 6 Jul 2009 04:36:30 +0000 Subject: jme: Some minor coding style consistency modifications Making coding style more consistent. Signed-off-by: Guo-Fu Tseng Signed-off-by: Guo-Fu Tseng Signed-off-by: David S. Miller --- drivers/net/jme.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 1e3c63d67b9..abf82cd2d7c 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -554,7 +554,7 @@ jme_free_tx_resources(struct jme_adapter *jme) { int i; struct jme_ring *txring = &(jme->txring[0]); - struct jme_buffer_info *txbi = txring->bufinf; + struct jme_buffer_info *txbi; if (txring->alloc) { for (i = 0 ; i < jme->tx_ring_size ; ++i) { @@ -653,7 +653,7 @@ jme_disable_tx_engine(struct jme_adapter *jme) static void jme_set_clean_rxdesc(struct jme_adapter *jme, int i) { - struct jme_ring *rxring = jme->rxring; + struct jme_ring *rxring = &(jme->rxring[0]); register struct rxdesc *rxdesc = rxring->desc; struct jme_buffer_info *rxbi = rxring->bufinf; rxdesc += i; @@ -790,9 +790,9 @@ jme_enable_rx_engine(struct jme_adapter *jme) /* * Setup RX DMA Bass Address */ - jwrite32(jme, JME_RXDBA_LO, (__u64)jme->rxring[0].dma & 0xFFFFFFFFUL); + jwrite32(jme, JME_RXDBA_LO, (__u64)(jme->rxring[0].dma) & 0xFFFFFFFFUL); jwrite32(jme, JME_RXDBA_HI, (__u64)(jme->rxring[0].dma) >> 32); - jwrite32(jme, JME_RXNDA, (__u64)jme->rxring[0].dma & 0xFFFFFFFFUL); + jwrite32(jme, JME_RXNDA, (__u64)(jme->rxring[0].dma) & 0xFFFFFFFFUL); /* * Setup RX Descriptor Count @@ -1296,7 +1296,7 @@ jme_rx_empty_tasklet(unsigned long arg) static void jme_wake_queue_if_stopped(struct jme_adapter *jme) { - struct jme_ring *txring = jme->txring; + struct jme_ring *txring = &(jme->txring[0]); smp_wmb(); if (unlikely(netif_queue_stopped(jme->dev) && @@ -1668,7 +1668,7 @@ static int jme_alloc_txdesc(struct jme_adapter *jme, struct sk_buff *skb) { - struct jme_ring *txring = jme->txring; + struct jme_ring *txring = &(jme->txring[0]); int idx, nr_alloc, mask = jme->tx_ring_mask; idx = txring->next_to_use; @@ -1722,7 +1722,7 @@ jme_fill_tx_map(struct pci_dev *pdev, static void jme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx) { - struct jme_ring *txring = jme->txring; + struct jme_ring *txring = &(jme->txring[0]); struct txdesc *txdesc = txring->desc, *ctxdesc; struct jme_buffer_info *txbi = txring->bufinf, *ctxbi; u8 hidma = jme->dev->features & NETIF_F_HIGHDMA; @@ -1835,7 +1835,7 @@ jme_tx_vlan(struct sk_buff *skb, __le16 *vlan, u8 *flags) static int jme_fill_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx) { - struct jme_ring *txring = jme->txring; + struct jme_ring *txring = &(jme->txring[0]); struct txdesc *txdesc; struct jme_buffer_info *txbi; u8 flags; @@ -1883,7 +1883,7 @@ jme_fill_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx) static void jme_stop_queue_if_full(struct jme_adapter *jme) { - struct jme_ring *txring = jme->txring; + struct jme_ring *txring = &(jme->txring[0]); struct jme_buffer_info *txbi = txring->bufinf; int idx = atomic_read(&txring->next_to_clean); -- cgit v1.2.3-18-g5258 From 38ed0c2107dea55347504042ed4e1d0cbc3e9100 Mon Sep 17 00:00:00 2001 From: Guo-Fu Tseng Date: Mon, 6 Jul 2009 04:37:52 +0000 Subject: jme: Fix unmatched tasklet_{enable|disable} pair Fix faulty tasklet function usage. Signed-off-by: Guo-Fu Tseng Signed-off-by: David S. Miller --- drivers/net/jme.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/jme.c b/drivers/net/jme.c index abf82cd2d7c..8de394021a5 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -1566,6 +1566,7 @@ jme_open(struct net_device *netdev) jme_clear_pm(jme); JME_NAPI_ENABLE(jme); + tasklet_enable(&jme->linkch_task); tasklet_enable(&jme->txclean_task); tasklet_hi_enable(&jme->rxclean_task); tasklet_hi_enable(&jme->rxempty_task); @@ -1647,10 +1648,10 @@ jme_close(struct net_device *netdev) JME_NAPI_DISABLE(jme); - tasklet_kill(&jme->linkch_task); - tasklet_kill(&jme->txclean_task); - tasklet_kill(&jme->rxclean_task); - tasklet_kill(&jme->rxempty_task); + tasklet_disable(&jme->linkch_task); + tasklet_disable(&jme->txclean_task); + tasklet_disable(&jme->rxclean_task); + tasklet_disable(&jme->rxempty_task); jme_reset_ghc_speed(jme); jme_disable_rx_engine(jme); @@ -2768,6 +2769,7 @@ jme_init_one(struct pci_dev *pdev, tasklet_init(&jme->rxempty_task, &jme_rx_empty_tasklet, (unsigned long) jme); + tasklet_disable_nosync(&jme->linkch_task); tasklet_disable_nosync(&jme->txclean_task); tasklet_disable_nosync(&jme->rxclean_task); tasklet_disable_nosync(&jme->rxempty_task); -- cgit v1.2.3-18-g5258 From 44d8d2e9f0dfa52bb1aebdbaa510669bff61c9dc Mon Sep 17 00:00:00 2001 From: Guo-Fu Tseng Date: Mon, 6 Jul 2009 04:38:35 +0000 Subject: jme: Fix typo Fix enum typo in jme.h Signed-off-by: Guo-Fu Tseng Signed-off-by: David S. Miller --- drivers/net/jme.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/jme.h b/drivers/net/jme.h index 0996a069ac7..0025e68aeb5 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -247,7 +247,7 @@ enum jme_txdesc_flags_bits { }; #define TXDESC_MSS_SHIFT 2 -enum jme_rxdescwb_flags_bits { +enum jme_txwbdesc_flags_bits { TXWBFLAG_OWN = 0x80, TXWBFLAG_INT = 0x40, TXWBFLAG_TMOUT = 0x20, -- cgit v1.2.3-18-g5258 From 47bd10d14b3341004266395014007c120a359c9d Mon Sep 17 00:00:00 2001 From: Guo-Fu Tseng Date: Mon, 6 Jul 2009 04:39:46 +0000 Subject: jme: Change bufinf memory location Instead of using a large chunk of memory space preserved for for modules, using kmalloc to obtain the needed memory. Signed-off-by: Guo-Fu Tseng Signed-off-by: David S. Miller --- drivers/net/jme.c | 86 +++++++++++++++++++++++++++++++++++++++---------------- drivers/net/jme.h | 3 +- 2 files changed, 63 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 8de394021a5..4a55b055bcb 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -522,12 +522,8 @@ jme_setup_tx_resources(struct jme_adapter *jme) &(txring->dmaalloc), GFP_ATOMIC); - if (!txring->alloc) { - txring->desc = NULL; - txring->dmaalloc = 0; - txring->dma = 0; - return -ENOMEM; - } + if (!txring->alloc) + goto err_set_null; /* * 16 Bytes align @@ -539,6 +535,11 @@ jme_setup_tx_resources(struct jme_adapter *jme) atomic_set(&txring->next_to_clean, 0); atomic_set(&txring->nr_free, jme->tx_ring_size); + txring->bufinf = kmalloc(sizeof(struct jme_buffer_info) * + jme->tx_ring_size, GFP_ATOMIC); + if (unlikely(!(txring->bufinf))) + goto err_free_txring; + /* * Initialize Transmit Descriptors */ @@ -547,6 +548,20 @@ jme_setup_tx_resources(struct jme_adapter *jme) sizeof(struct jme_buffer_info) * jme->tx_ring_size); return 0; + +err_free_txring: + dma_free_coherent(&(jme->pdev->dev), + TX_RING_ALLOC_SIZE(jme->tx_ring_size), + txring->alloc, + txring->dmaalloc); + +err_set_null: + txring->desc = NULL; + txring->dmaalloc = 0; + txring->dma = 0; + txring->bufinf = NULL; + + return -ENOMEM; } static void @@ -557,16 +572,19 @@ jme_free_tx_resources(struct jme_adapter *jme) struct jme_buffer_info *txbi; if (txring->alloc) { - for (i = 0 ; i < jme->tx_ring_size ; ++i) { - txbi = txring->bufinf + i; - if (txbi->skb) { - dev_kfree_skb(txbi->skb); - txbi->skb = NULL; + if (txring->bufinf) { + for (i = 0 ; i < jme->tx_ring_size ; ++i) { + txbi = txring->bufinf + i; + if (txbi->skb) { + dev_kfree_skb(txbi->skb); + txbi->skb = NULL; + } + txbi->mapping = 0; + txbi->len = 0; + txbi->nr_desc = 0; + txbi->start_xmit = 0; } - txbi->mapping = 0; - txbi->len = 0; - txbi->nr_desc = 0; - txbi->start_xmit = 0; + kfree(txring->bufinf); } dma_free_coherent(&(jme->pdev->dev), @@ -578,11 +596,11 @@ jme_free_tx_resources(struct jme_adapter *jme) txring->desc = NULL; txring->dmaalloc = 0; txring->dma = 0; + txring->bufinf = NULL; } txring->next_to_use = 0; atomic_set(&txring->next_to_clean, 0); atomic_set(&txring->nr_free, 0); - } static inline void @@ -720,8 +738,11 @@ jme_free_rx_resources(struct jme_adapter *jme) struct jme_ring *rxring = &(jme->rxring[0]); if (rxring->alloc) { - for (i = 0 ; i < jme->rx_ring_size ; ++i) - jme_free_rx_buf(jme, i); + if (rxring->bufinf) { + for (i = 0 ; i < jme->rx_ring_size ; ++i) + jme_free_rx_buf(jme, i); + kfree(rxring->bufinf); + } dma_free_coherent(&(jme->pdev->dev), RX_RING_ALLOC_SIZE(jme->rx_ring_size), @@ -731,6 +752,7 @@ jme_free_rx_resources(struct jme_adapter *jme) rxring->desc = NULL; rxring->dmaalloc = 0; rxring->dma = 0; + rxring->bufinf = NULL; } rxring->next_to_use = 0; atomic_set(&rxring->next_to_clean, 0); @@ -746,12 +768,8 @@ jme_setup_rx_resources(struct jme_adapter *jme) RX_RING_ALLOC_SIZE(jme->rx_ring_size), &(rxring->dmaalloc), GFP_ATOMIC); - if (!rxring->alloc) { - rxring->desc = NULL; - rxring->dmaalloc = 0; - rxring->dma = 0; - return -ENOMEM; - } + if (!rxring->alloc) + goto err_set_null; /* * 16 Bytes align @@ -762,9 +780,16 @@ jme_setup_rx_resources(struct jme_adapter *jme) rxring->next_to_use = 0; atomic_set(&rxring->next_to_clean, 0); + rxring->bufinf = kmalloc(sizeof(struct jme_buffer_info) * + jme->rx_ring_size, GFP_ATOMIC); + if (unlikely(!(rxring->bufinf))) + goto err_free_rxring; + /* * Initiallize Receive Descriptors */ + memset(rxring->bufinf, 0, + sizeof(struct jme_buffer_info) * jme->rx_ring_size); for (i = 0 ; i < jme->rx_ring_size ; ++i) { if (unlikely(jme_make_new_rx_buf(jme, i))) { jme_free_rx_resources(jme); @@ -775,6 +800,19 @@ jme_setup_rx_resources(struct jme_adapter *jme) } return 0; + +err_free_rxring: + dma_free_coherent(&(jme->pdev->dev), + RX_RING_ALLOC_SIZE(jme->rx_ring_size), + rxring->alloc, + rxring->dmaalloc); +err_set_null: + rxring->desc = NULL; + rxring->dmaalloc = 0; + rxring->dma = 0; + rxring->bufinf = NULL; + + return -ENOMEM; } static inline void diff --git a/drivers/net/jme.h b/drivers/net/jme.h index 0025e68aeb5..9d3cedd394a 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -372,7 +372,6 @@ struct jme_buffer_info { /* * The structure holding buffer information and ring descriptors all together. */ -#define MAX_RING_DESC_NR 1024 struct jme_ring { void *alloc; /* pointer to allocated memory */ void *desc; /* pointer to ring memory */ @@ -380,7 +379,7 @@ struct jme_ring { dma_addr_t dma; /* phys address for ring dma */ /* Buffer information corresponding to each descriptor */ - struct jme_buffer_info bufinf[MAX_RING_DESC_NR]; + struct jme_buffer_info *bufinf; int next_to_use; atomic_t next_to_clean; -- cgit v1.2.3-18-g5258 From d1dfa1d1de855e8db58ec4e403af5939d273f8fe Mon Sep 17 00:00:00 2001 From: Guo-Fu Tseng Date: Mon, 6 Jul 2009 04:40:38 +0000 Subject: jme: Remove shadow register support The hardware failed to update the shadow register in several cases. It's known to be failed at 64bit box with more than 4G RAM. In order to make the device working stable, give up using the shadow register feature. Signed-off-by: Guo-Fu Tseng Signed-off-by: David S. Miller --- drivers/net/jme.c | 49 ++++--------------------------------------------- drivers/net/jme.h | 14 -------------- 2 files changed, 4 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 4a55b055bcb..29cd5f43eea 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -322,20 +322,6 @@ jme_stop_irq(struct jme_adapter *jme) jwrite32f(jme, JME_IENC, INTR_ENABLE); } -static inline void -jme_enable_shadow(struct jme_adapter *jme) -{ - jwrite32(jme, - JME_SHBA_LO, - ((u32)jme->shadow_dma & ~((u32)0x1F)) | SHBA_POSTEN); -} - -static inline void -jme_disable_shadow(struct jme_adapter *jme) -{ - jwrite32(jme, JME_SHBA_LO, 0x0); -} - static u32 jme_linkstat_from_phy(struct jme_adapter *jme) { @@ -1521,12 +1507,7 @@ jme_msi(int irq, void *dev_id) struct jme_adapter *jme = netdev_priv(netdev); u32 intrstat; - pci_dma_sync_single_for_cpu(jme->pdev, - jme->shadow_dma, - sizeof(u32) * SHADOW_REG_NR, - PCI_DMA_FROMDEVICE); - intrstat = jme->shadow_regs[SHADOW_IEVE]; - jme->shadow_regs[SHADOW_IEVE] = 0; + intrstat = jread32(jme, JME_IEVE); jme_intr_msi(jme, intrstat); @@ -1613,7 +1594,6 @@ jme_open(struct net_device *netdev) if (rc) goto err_out; - jme_enable_shadow(jme); jme_start_irq(jme); if (test_bit(JME_FLAG_SSET, &jme->flags)) @@ -1681,7 +1661,6 @@ jme_close(struct net_device *netdev) netif_carrier_off(netdev); jme_stop_irq(jme); - jme_disable_shadow(jme); jme_free_irq(jme); JME_NAPI_DISABLE(jme); @@ -2764,14 +2743,6 @@ jme_init_one(struct pci_dev *pdev, rc = -ENOMEM; goto err_out_free_netdev; } - jme->shadow_regs = pci_alloc_consistent(pdev, - sizeof(u32) * SHADOW_REG_NR, - &(jme->shadow_dma)); - if (!(jme->shadow_regs)) { - jeprintk(pdev, "Allocating shadow register mapping error.\n"); - rc = -ENOMEM; - goto err_out_unmap; - } if (no_pseudohp) { apmc = jread32(jme, JME_APMC) & ~JME_APMC_PSEUDO_HP_EN; @@ -2857,7 +2828,7 @@ jme_init_one(struct pci_dev *pdev, if (!jme->mii_if.phy_id) { rc = -EIO; jeprintk(pdev, "Can not find phy_id.\n"); - goto err_out_free_shadow; + goto err_out_unmap; } jme->reg_ghc |= GHC_LINK_POLL; @@ -2886,7 +2857,7 @@ jme_init_one(struct pci_dev *pdev, if (rc) { jeprintk(pdev, "Reload eeprom for reading MAC Address error.\n"); - goto err_out_free_shadow; + goto err_out_unmap; } jme_load_macaddr(netdev); @@ -2902,7 +2873,7 @@ jme_init_one(struct pci_dev *pdev, rc = register_netdev(netdev); if (rc) { jeprintk(pdev, "Cannot register net device.\n"); - goto err_out_free_shadow; + goto err_out_unmap; } msg_probe(jme, "%s%s ver:%x rev:%x macaddr:%pM\n", @@ -2916,11 +2887,6 @@ jme_init_one(struct pci_dev *pdev, return 0; -err_out_free_shadow: - pci_free_consistent(pdev, - sizeof(u32) * SHADOW_REG_NR, - jme->shadow_regs, - jme->shadow_dma); err_out_unmap: iounmap(jme->regs); err_out_free_netdev: @@ -2941,10 +2907,6 @@ jme_remove_one(struct pci_dev *pdev) struct jme_adapter *jme = netdev_priv(netdev); unregister_netdev(netdev); - pci_free_consistent(pdev, - sizeof(u32) * SHADOW_REG_NR, - jme->shadow_regs, - jme->shadow_dma); iounmap(jme->regs); pci_set_drvdata(pdev, NULL); free_netdev(netdev); @@ -2970,8 +2932,6 @@ jme_suspend(struct pci_dev *pdev, pm_message_t state) tasklet_disable(&jme->rxclean_task); tasklet_disable(&jme->rxempty_task); - jme_disable_shadow(jme); - if (netif_carrier_ok(netdev)) { if (test_bit(JME_FLAG_POLL, &jme->flags)) jme_polling_mode(jme); @@ -3023,7 +2983,6 @@ jme_resume(struct pci_dev *pdev) else jme_reset_phy_processor(jme); - jme_enable_shadow(jme); jme_start_irq(jme); netif_device_attach(netdev); diff --git a/drivers/net/jme.h b/drivers/net/jme.h index 9d3cedd394a..db912f6b37a 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -410,13 +410,10 @@ struct jme_ring { /* * Jmac Adapter Private data */ -#define SHADOW_REG_NR 8 struct jme_adapter { struct pci_dev *pdev; struct net_device *dev; void __iomem *regs; - dma_addr_t shadow_dma; - u32 *shadow_regs; struct mii_if_info mii_if; struct jme_ring rxring[RX_RING_NR]; struct jme_ring txring[TX_RING_NR]; @@ -463,10 +460,6 @@ struct jme_adapter { DECLARE_NET_DEVICE_STATS }; -enum shadow_reg_val { - SHADOW_IEVE = 0, -}; - enum jme_flags_bits { JME_FLAG_MSI = 1, JME_FLAG_SSET = 2, @@ -1102,13 +1095,6 @@ enum jme_chipmode_shifts { CM_CHIPREV_SHIFT = 8, }; -/* - * Shadow base address register bits - */ -enum jme_shadow_base_address_bits { - SHBA_POSTEN = 0x1, -}; - /* * Aggressive Power Mode Control */ -- cgit v1.2.3-18-g5258 From ce7d70af2c8b9c74e8afb2c0d69e304d141ce4aa Mon Sep 17 00:00:00 2001 From: Guo-Fu Tseng Date: Mon, 6 Jul 2009 04:41:22 +0000 Subject: jme: Tuning rxsum function 1. Use more efficient way to determine flag status. 2. Hardware dose not mark fragment bit against IPv6 packets, print TCP/UDP checksum warning message for IPv4 packets only. Signed-off-by: Guo-Fu Tseng Signed-off-by: David S. Miller --- drivers/net/jme.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 29cd5f43eea..e7068c7cd62 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -880,27 +880,27 @@ jme_rxsum_ok(struct jme_adapter *jme, u16 flags) if (!(flags & (RXWBFLAG_TCPON | RXWBFLAG_UDPON | RXWBFLAG_IPV4))) return false; - if (unlikely(!(flags & RXWBFLAG_MF) && - (flags & RXWBFLAG_TCPON) && !(flags & RXWBFLAG_TCPCS))) { - msg_rx_err(jme, "TCP Checksum error.\n"); - goto out_sumerr; + if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_TCPON | RXWBFLAG_TCPCS)) + == RXWBFLAG_TCPON)) { + if (flags & RXWBFLAG_IPV4) + msg_rx_err(jme, "TCP Checksum error\n"); + return false; } - if (unlikely(!(flags & RXWBFLAG_MF) && - (flags & RXWBFLAG_UDPON) && !(flags & RXWBFLAG_UDPCS))) { - msg_rx_err(jme, "UDP Checksum error.\n"); - goto out_sumerr; + if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_UDPON | RXWBFLAG_UDPCS)) + == RXWBFLAG_UDPON)) { + if (flags & RXWBFLAG_IPV4) + msg_rx_err(jme, "UDP Checksum error.\n"); + return false; } - if (unlikely((flags & RXWBFLAG_IPV4) && !(flags & RXWBFLAG_IPCS))) { + if (unlikely((flags & (RXWBFLAG_IPV4 | RXWBFLAG_IPCS)) + == RXWBFLAG_IPV4)) { msg_rx_err(jme, "IPv4 Checksum error.\n"); - goto out_sumerr; + return false; } return true; - -out_sumerr: - return false; } static void -- cgit v1.2.3-18-g5258 From f77139c07a0e1dd164e039320ada50111f899223 Mon Sep 17 00:00:00 2001 From: Guo-Fu Tseng Date: Mon, 6 Jul 2009 04:45:58 +0000 Subject: jme: Advance driver version number Advance driver version number after modifications. Signed-off-by: Guo-Fu Tseng Signed-off-by: David S. Miller --- drivers/net/jme.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/jme.h b/drivers/net/jme.h index db912f6b37a..251abed3817 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -25,7 +25,7 @@ #define __JME_H_INCLUDED__ #define DRV_NAME "jme" -#define DRV_VERSION "1.0.4" +#define DRV_VERSION "1.0.5" #define PFX DRV_NAME ": " #define PCI_DEVICE_ID_JMICRON_JMC250 0x0250 -- cgit v1.2.3-18-g5258 From 94c9e5a89349a1f1ebabe0876c059dc387b8b2a0 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Mon, 6 Jul 2009 10:44:20 +0000 Subject: e1000: allow ethtool coalesece to adjust interrupts per second This patch allows on-the-fly adjustment of the interrupts per second generated by e1000 devices 82545/82546 (hardware support of ITR register is a requirement) adjust using this command: ethtool -C eth0 rx-usecs 10 where 10 is 10 microseconds per interrupt interval, so 10 = 100,000 interrupts per second, and 125 = 8000 interrupts per second. changes should be immediate. 1,3 are special values and indicate the automatic tuning mode to the driver, where 1 is 4000-90000 interrupts per second and 3 is 4000-20000 interrupts per second and is the driver default. Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000/e1000.h | 3 +++ drivers/net/e1000/e1000_ethtool.c | 51 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index e9a416f4016..c87f2cbdbae 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -111,6 +111,9 @@ do { \ #define E1000_MIN_RXD 80 #define E1000_MAX_82544_RXD 4096 +#define E1000_MIN_ITR_USECS 10 /* 100000 irq/sec */ +#define E1000_MAX_ITR_USECS 10000 /* 100 irq/sec */ + /* this is the size past which hardware will drop packets when setting LPE=0 */ #define MAXIMUM_ETHERNET_VLAN_SIZE 1522 diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index c854c96f5ab..27f996a2010 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1904,6 +1904,53 @@ static int e1000_phys_id(struct net_device *netdev, u32 data) return 0; } +static int e1000_get_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + if (adapter->hw.mac_type < e1000_82545) + return -EOPNOTSUPP; + + if (adapter->itr_setting <= 3) + ec->rx_coalesce_usecs = adapter->itr_setting; + else + ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting; + + return 0; +} + +static int e1000_set_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + if (hw->mac_type < e1000_82545) + return -EOPNOTSUPP; + + if ((ec->rx_coalesce_usecs > E1000_MAX_ITR_USECS) || + ((ec->rx_coalesce_usecs > 3) && + (ec->rx_coalesce_usecs < E1000_MIN_ITR_USECS)) || + (ec->rx_coalesce_usecs == 2)) + return -EINVAL; + + if (ec->rx_coalesce_usecs <= 3) { + adapter->itr = 20000; + adapter->itr_setting = ec->rx_coalesce_usecs; + } else { + adapter->itr = (1000000 / ec->rx_coalesce_usecs); + adapter->itr_setting = adapter->itr & ~3; + } + + if (adapter->itr_setting != 0) + ew32(ITR, 1000000000 / (adapter->itr * 256)); + else + ew32(ITR, 0); + + return 0; +} + static int e1000_nway_reset(struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); @@ -1978,7 +2025,9 @@ static const struct ethtool_ops e1000_ethtool_ops = { .get_strings = e1000_get_strings, .phys_id = e1000_phys_id, .get_ethtool_stats = e1000_get_ethtool_stats, - .get_sset_count = e1000_get_sset_count, + .get_sset_count = e1000_get_sset_count, + .get_coalesce = e1000_get_coalesce, + .set_coalesce = e1000_set_coalesce, }; void e1000_set_ethtool_ops(struct net_device *netdev) -- cgit v1.2.3-18-g5258 From edbbb3ca107715067b27a71e6ea7f58750912aa2 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Mon, 6 Jul 2009 10:44:39 +0000 Subject: e1000: implement jumbo receive with partial descriptors This is code extremely similar to what is committed in e1000e already. e1000 will no longer request 32kB slab buffers to support jumbo frames on PCI/PCI-X adapters. This will significantly reduce the likelyhood of order:3 allocation failures. This new code adds support for using pages as receive buffers, and the driver will chain multiple pages together to build a jumbo frame for OS consumption. The hardware takes a power of two buffer size and will dump as much data as it can receive into 1 or more buffers. The benefits of applying this are 1) stop akpm's dissing :-) of this lame e1000 behavior [1] 2) more efficient memory allocation (half) when using jumbo frames, which will also allow for much better socket utilization with jumbos since the socket is charged for the full allocation of each receive buffer, regardless of how much is used. 3) this was a feature request by a customer 4) copybreak for small packets < 256 bytes still applies [1] http://lkml.org/lkml/2008/7/10/68 http://article.gmane.org/gmane.linux.network/130986 Signed-off-by: Jesse Brandeburg CC: Andrew Morton Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000/e1000.h | 4 +- drivers/net/e1000/e1000_main.c | 425 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 391 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index c87f2cbdbae..1a4f89c66a2 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -140,7 +140,7 @@ do { \ #define E1000_FC_HIGH_DIFF 0x1638 /* High: 5688 bytes below Rx FIFO size */ #define E1000_FC_LOW_DIFF 0x1640 /* Low: 5696 bytes below Rx FIFO size */ -#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */ +#define E1000_FC_PAUSE_TIME 0xFFFF /* pause for the max or until send xon */ /* How many Tx Descriptors do we need to call netif_wake_queue ? */ #define E1000_TX_QUEUE_WAKE 16 @@ -164,6 +164,7 @@ do { \ struct e1000_buffer { struct sk_buff *skb; dma_addr_t dma; + struct page *page; unsigned long time_stamp; u16 length; u16 next_to_watch; @@ -205,6 +206,7 @@ struct e1000_rx_ring { unsigned int next_to_clean; /* array of buffer information structs */ struct e1000_buffer *buffer_info; + struct sk_buff *rx_skb_top; /* cpu for rx queue */ int cpu; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 5b8cbdb4b52..f2db9e2069e 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -137,9 +137,15 @@ static int e1000_clean(struct napi_struct *napi, int budget); static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring, int *work_done, int work_to_do); +static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, + int *work_done, int work_to_do); static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring, + struct e1000_rx_ring *rx_ring, int cleaned_count); +static void e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, + int cleaned_count); static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); @@ -761,10 +767,7 @@ void e1000_reset(struct e1000_adapter *adapter) hw->fc_high_water = fc_high_water_mark; hw->fc_low_water = fc_high_water_mark - 8; - if (hw->mac_type == e1000_80003es2lan) - hw->fc_pause_time = 0xFFFF; - else - hw->fc_pause_time = E1000_FC_PAUSE_TIME; + hw->fc_pause_time = E1000_FC_PAUSE_TIME; hw->fc_send_xon = 1; hw->fc = hw->original_fc; @@ -1862,6 +1865,7 @@ setup_rx_desc_die: rxdr->next_to_clean = 0; rxdr->next_to_use = 0; + rxdr->rx_skb_top = NULL; return 0; } @@ -1968,10 +1972,17 @@ static void e1000_configure_rx(struct e1000_adapter *adapter) struct e1000_hw *hw = &adapter->hw; u32 rdlen, rctl, rxcsum, ctrl_ext; - rdlen = adapter->rx_ring[0].count * - sizeof(struct e1000_rx_desc); - adapter->clean_rx = e1000_clean_rx_irq; - adapter->alloc_rx_buf = e1000_alloc_rx_buffers; + if (adapter->netdev->mtu > ETH_DATA_LEN) { + rdlen = adapter->rx_ring[0].count * + sizeof(struct e1000_rx_desc); + adapter->clean_rx = e1000_clean_jumbo_rx_irq; + adapter->alloc_rx_buf = e1000_alloc_jumbo_rx_buffers; + } else { + rdlen = adapter->rx_ring[0].count * + sizeof(struct e1000_rx_desc); + adapter->clean_rx = e1000_clean_rx_irq; + adapter->alloc_rx_buf = e1000_alloc_rx_buffers; + } /* disable receives while setting up the descriptors */ rctl = er32(RCTL); @@ -2185,26 +2196,39 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter, /* Free all the Rx ring sk_buffs */ for (i = 0; i < rx_ring->count; i++) { buffer_info = &rx_ring->buffer_info[i]; - if (buffer_info->dma) { - pci_unmap_single(pdev, - buffer_info->dma, - buffer_info->length, - PCI_DMA_FROMDEVICE); + if (buffer_info->dma && + adapter->clean_rx == e1000_clean_rx_irq) { + pci_unmap_single(pdev, buffer_info->dma, + buffer_info->length, + PCI_DMA_FROMDEVICE); + } else if (buffer_info->dma && + adapter->clean_rx == e1000_clean_jumbo_rx_irq) { + pci_unmap_page(pdev, buffer_info->dma, + buffer_info->length, + PCI_DMA_FROMDEVICE); } buffer_info->dma = 0; - + if (buffer_info->page) { + put_page(buffer_info->page); + buffer_info->page = NULL; + } if (buffer_info->skb) { dev_kfree_skb(buffer_info->skb); buffer_info->skb = NULL; } } + /* there also may be some cached data from a chained receive */ + if (rx_ring->rx_skb_top) { + dev_kfree_skb(rx_ring->rx_skb_top); + rx_ring->rx_skb_top = NULL; + } + size = sizeof(struct e1000_buffer) * rx_ring->count; memset(rx_ring->buffer_info, 0, size); /* Zero out the descriptor ring */ - memset(rx_ring->desc, 0, rx_ring->size); rx_ring->next_to_clean = 0; @@ -3489,8 +3513,10 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) /* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN * means we reserve 2 more, this pushes us to allocate from the next - * larger slab size - * i.e. RXBUFFER_2048 --> size-4096 slab */ + * larger slab size. + * i.e. RXBUFFER_2048 --> size-4096 slab + * however with the new *_jumbo_rx* routines, jumbo receives will use + * fragmented skbs */ if (max_frame <= E1000_RXBUFFER_256) adapter->rx_buffer_len = E1000_RXBUFFER_256; @@ -3500,12 +3526,12 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) adapter->rx_buffer_len = E1000_RXBUFFER_1024; else if (max_frame <= E1000_RXBUFFER_2048) adapter->rx_buffer_len = E1000_RXBUFFER_2048; - else if (max_frame <= E1000_RXBUFFER_4096) - adapter->rx_buffer_len = E1000_RXBUFFER_4096; - else if (max_frame <= E1000_RXBUFFER_8192) - adapter->rx_buffer_len = E1000_RXBUFFER_8192; - else if (max_frame <= E1000_RXBUFFER_16384) + else +#if (PAGE_SIZE >= E1000_RXBUFFER_16384) adapter->rx_buffer_len = E1000_RXBUFFER_16384; +#elif (PAGE_SIZE >= E1000_RXBUFFER_4096) + adapter->rx_buffer_len = PAGE_SIZE; +#endif /* adjust allocation if LPE protects us, and we aren't using SBP */ if (!hw->tbi_compatibility_on && @@ -3986,10 +4012,228 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err, adapter->hw_csum_good++; } +/** + * e1000_consume_page - helper function + **/ +static void e1000_consume_page(struct e1000_buffer *bi, struct sk_buff *skb, + u16 length) +{ + bi->page = NULL; + skb->len += length; + skb->data_len += length; + skb->truesize += length; +} + +/** + * e1000_receive_skb - helper function to handle rx indications + * @adapter: board private structure + * @status: descriptor status field as written by hardware + * @vlan: descriptor vlan field as written by hardware (no le/be conversion) + * @skb: pointer to sk_buff to be indicated to stack + */ +static void e1000_receive_skb(struct e1000_adapter *adapter, u8 status, + __le16 vlan, struct sk_buff *skb) +{ + if (unlikely(adapter->vlgrp && (status & E1000_RXD_STAT_VP))) { + vlan_hwaccel_receive_skb(skb, adapter->vlgrp, + le16_to_cpu(vlan) & + E1000_RXD_SPC_VLAN_MASK); + } else { + netif_receive_skb(skb); + } +} + +/** + * e1000_clean_jumbo_rx_irq - Send received data up the network stack; legacy + * @adapter: board private structure + * @rx_ring: ring to clean + * @work_done: amount of napi work completed this call + * @work_to_do: max amount of work allowed for this call to do + * + * the return value indicates whether actual cleaning was done, there + * is no guarantee that everything was cleaned + */ +static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, + int *work_done, int work_to_do) +{ + struct e1000_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_rx_desc *rx_desc, *next_rxd; + struct e1000_buffer *buffer_info, *next_buffer; + unsigned long irq_flags; + u32 length; + unsigned int i; + int cleaned_count = 0; + bool cleaned = false; + unsigned int total_rx_bytes=0, total_rx_packets=0; + + i = rx_ring->next_to_clean; + rx_desc = E1000_RX_DESC(*rx_ring, i); + buffer_info = &rx_ring->buffer_info[i]; + + while (rx_desc->status & E1000_RXD_STAT_DD) { + struct sk_buff *skb; + u8 status; + + if (*work_done >= work_to_do) + break; + (*work_done)++; + + status = rx_desc->status; + skb = buffer_info->skb; + buffer_info->skb = NULL; + + if (++i == rx_ring->count) i = 0; + next_rxd = E1000_RX_DESC(*rx_ring, i); + prefetch(next_rxd); + + next_buffer = &rx_ring->buffer_info[i]; + + cleaned = true; + cleaned_count++; + pci_unmap_page(pdev, buffer_info->dma, buffer_info->length, + PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; + + length = le16_to_cpu(rx_desc->length); + + /* errors is only valid for DD + EOP descriptors */ + if (unlikely((status & E1000_RXD_STAT_EOP) && + (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK))) { + u8 last_byte = *(skb->data + length - 1); + if (TBI_ACCEPT(hw, status, rx_desc->errors, length, + last_byte)) { + spin_lock_irqsave(&adapter->stats_lock, + irq_flags); + e1000_tbi_adjust_stats(hw, &adapter->stats, + length, skb->data); + spin_unlock_irqrestore(&adapter->stats_lock, + irq_flags); + length--; + } else { + /* recycle both page and skb */ + buffer_info->skb = skb; + /* an error means any chain goes out the window + * too */ + if (rx_ring->rx_skb_top) + dev_kfree_skb(rx_ring->rx_skb_top); + rx_ring->rx_skb_top = NULL; + goto next_desc; + } + } + +#define rxtop rx_ring->rx_skb_top + if (!(status & E1000_RXD_STAT_EOP)) { + /* this descriptor is only the beginning (or middle) */ + if (!rxtop) { + /* this is the beginning of a chain */ + rxtop = skb; + skb_fill_page_desc(rxtop, 0, buffer_info->page, + 0, length); + } else { + /* this is the middle of a chain */ + skb_fill_page_desc(rxtop, + skb_shinfo(rxtop)->nr_frags, + buffer_info->page, 0, length); + /* re-use the skb, only consumed the page */ + buffer_info->skb = skb; + } + e1000_consume_page(buffer_info, rxtop, length); + goto next_desc; + } else { + if (rxtop) { + /* end of the chain */ + skb_fill_page_desc(rxtop, + skb_shinfo(rxtop)->nr_frags, + buffer_info->page, 0, length); + /* re-use the current skb, we only consumed the + * page */ + buffer_info->skb = skb; + skb = rxtop; + rxtop = NULL; + e1000_consume_page(buffer_info, skb, length); + } else { + /* no chain, got EOP, this buf is the packet + * copybreak to save the put_page/alloc_page */ + if (length <= copybreak && + skb_tailroom(skb) >= length) { + u8 *vaddr; + vaddr = kmap_atomic(buffer_info->page, + KM_SKB_DATA_SOFTIRQ); + memcpy(skb_tail_pointer(skb), vaddr, length); + kunmap_atomic(vaddr, + KM_SKB_DATA_SOFTIRQ); + /* re-use the page, so don't erase + * buffer_info->page */ + skb_put(skb, length); + } else { + skb_fill_page_desc(skb, 0, + buffer_info->page, 0, + length); + e1000_consume_page(buffer_info, skb, + length); + } + } + } + + /* Receive Checksum Offload XXX recompute due to CRC strip? */ + e1000_rx_checksum(adapter, + (u32)(status) | + ((u32)(rx_desc->errors) << 24), + le16_to_cpu(rx_desc->csum), skb); + + pskb_trim(skb, skb->len - 4); + + /* probably a little skewed due to removing CRC */ + total_rx_bytes += skb->len; + total_rx_packets++; + + /* eth type trans needs skb->data to point to something */ + if (!pskb_may_pull(skb, ETH_HLEN)) { + DPRINTK(DRV, ERR, "pskb_may_pull failed.\n"); + dev_kfree_skb(skb); + goto next_desc; + } + + skb->protocol = eth_type_trans(skb, netdev); + + e1000_receive_skb(adapter, status, rx_desc->special, skb); + +next_desc: + rx_desc->status = 0; + + /* return some buffers to hardware, one at a time is too slow */ + if (unlikely(cleaned_count >= E1000_RX_BUFFER_WRITE)) { + adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count); + cleaned_count = 0; + } + + /* use prefetched values */ + rx_desc = next_rxd; + buffer_info = next_buffer; + } + rx_ring->next_to_clean = i; + + cleaned_count = E1000_DESC_UNUSED(rx_ring); + if (cleaned_count) + adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count); + + adapter->total_rx_packets += total_rx_packets; + adapter->total_rx_bytes += total_rx_bytes; + adapter->net_stats.rx_bytes += total_rx_bytes; + adapter->net_stats.rx_packets += total_rx_packets; + return cleaned; +} + /** * e1000_clean_rx_irq - Send received data up the network stack; legacy * @adapter: board private structure - **/ + * @rx_ring: ring to clean + * @work_done: amount of napi work completed this call + * @work_to_do: max amount of work allowed for this call to do + */ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring, int *work_done, int work_to_do) @@ -4001,7 +4245,6 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, struct e1000_buffer *buffer_info, *next_buffer; unsigned long flags; u32 length; - u8 last_byte; unsigned int i; int cleaned_count = 0; bool cleaned = false; @@ -4033,9 +4276,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, cleaned = true; cleaned_count++; - pci_unmap_single(pdev, - buffer_info->dma, - buffer_info->length, + pci_unmap_single(pdev, buffer_info->dma, buffer_info->length, PCI_DMA_FROMDEVICE); buffer_info->dma = 0; @@ -4052,7 +4293,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, } if (unlikely(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK)) { - last_byte = *(skb->data + length - 1); + u8 last_byte = *(skb->data + length - 1); if (TBI_ACCEPT(hw, status, rx_desc->errors, length, last_byte)) { spin_lock_irqsave(&adapter->stats_lock, flags); @@ -4107,13 +4348,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, skb->protocol = eth_type_trans(skb, netdev); - if (unlikely(adapter->vlgrp && - (status & E1000_RXD_STAT_VP))) { - vlan_hwaccel_receive_skb(skb, adapter->vlgrp, - le16_to_cpu(rx_desc->special)); - } else { - netif_receive_skb(skb); - } + e1000_receive_skb(adapter, status, rx_desc->special, skb); next_desc: rx_desc->status = 0; @@ -4141,6 +4376,114 @@ next_desc: return cleaned; } +/** + * e1000_alloc_jumbo_rx_buffers - Replace used jumbo receive buffers + * @adapter: address of board private structure + * @rx_ring: pointer to receive ring structure + * @cleaned_count: number of buffers to allocate this pass + **/ + +static void +e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring, int cleaned_count) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_rx_desc *rx_desc; + struct e1000_buffer *buffer_info; + struct sk_buff *skb; + unsigned int i; + unsigned int bufsz = 256 - + 16 /*for skb_reserve */ - + NET_IP_ALIGN; + + i = rx_ring->next_to_use; + buffer_info = &rx_ring->buffer_info[i]; + + while (cleaned_count--) { + skb = buffer_info->skb; + if (skb) { + skb_trim(skb, 0); + goto check_page; + } + + skb = netdev_alloc_skb(netdev, bufsz); + if (unlikely(!skb)) { + /* Better luck next round */ + adapter->alloc_rx_buff_failed++; + break; + } + + /* Fix for errata 23, can't cross 64kB boundary */ + if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) { + struct sk_buff *oldskb = skb; + DPRINTK(PROBE, ERR, "skb align check failed: %u bytes " + "at %p\n", bufsz, skb->data); + /* Try again, without freeing the previous */ + skb = netdev_alloc_skb(netdev, bufsz); + /* Failed allocation, critical failure */ + if (!skb) { + dev_kfree_skb(oldskb); + adapter->alloc_rx_buff_failed++; + break; + } + + if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) { + /* give up */ + dev_kfree_skb(skb); + dev_kfree_skb(oldskb); + break; /* while (cleaned_count--) */ + } + + /* Use new allocation */ + dev_kfree_skb(oldskb); + } + /* Make buffer alignment 2 beyond a 16 byte boundary + * this will result in a 16 byte aligned IP header after + * the 14 byte MAC header is removed + */ + skb_reserve(skb, NET_IP_ALIGN); + + buffer_info->skb = skb; + buffer_info->length = adapter->rx_buffer_len; +check_page: + /* allocate a new page if necessary */ + if (!buffer_info->page) { + buffer_info->page = alloc_page(GFP_ATOMIC); + if (unlikely(!buffer_info->page)) { + adapter->alloc_rx_buff_failed++; + break; + } + } + + if (!buffer_info->dma) + buffer_info->dma = pci_map_page(pdev, + buffer_info->page, 0, + buffer_info->length, + PCI_DMA_FROMDEVICE); + + rx_desc = E1000_RX_DESC(*rx_ring, i); + rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); + + if (unlikely(++i == rx_ring->count)) + i = 0; + buffer_info = &rx_ring->buffer_info[i]; + } + + if (likely(rx_ring->next_to_use != i)) { + rx_ring->next_to_use = i; + if (unlikely(i-- == 0)) + i = (rx_ring->count - 1); + + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). */ + wmb(); + writel(i, adapter->hw.hw_addr + rx_ring->rdt); + } +} + /** * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended * @adapter: address of board private structure @@ -4186,6 +4529,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, /* Failed allocation, critical failure */ if (!skb) { dev_kfree_skb(oldskb); + adapter->alloc_rx_buff_failed++; break; } @@ -4193,6 +4537,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, /* give up */ dev_kfree_skb(skb); dev_kfree_skb(oldskb); + adapter->alloc_rx_buff_failed++; break; /* while !buffer_info->skb */ } @@ -4210,9 +4555,14 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, map_skb: buffer_info->dma = pci_map_single(pdev, skb->data, - adapter->rx_buffer_len, + buffer_info->length, PCI_DMA_FROMDEVICE); + /* + * XXX if it was allocated cleanly it will never map to a + * boundary crossing + */ + /* Fix for errata 23, can't cross 64kB boundary */ if (!e1000_check_64k_bound(adapter, (void *)(unsigned long)buffer_info->dma, @@ -4229,6 +4579,7 @@ map_skb: PCI_DMA_FROMDEVICE); buffer_info->dma = 0; + adapter->alloc_rx_buff_failed++; break; /* while !buffer_info->skb */ } rx_desc = E1000_RX_DESC(*rx_ring, i); -- cgit v1.2.3-18-g5258 From b7cb8c2c8275ab081b97610b13a83c80904571a6 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Mon, 6 Jul 2009 10:45:01 +0000 Subject: e1000: fix flow control thresholds when testing the jumbo frames with pages patch, the stats would show rx_missed errors (dropped packets) even when connected to a link partner with flow control enabled. this indicates that for this MTU (9000) the flow control thresholds are not adjusting correctly. In fact, before this change, the FCRTH (xoff threshold) is 36864 when the fifo size is only 40000, with 9000 byte MTU. fix it so that we at least have room for one frame after we send the xoff. Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000/e1000_hw.c | 2 +- drivers/net/e1000/e1000_hw.h | 3 --- drivers/net/e1000/e1000_main.c | 58 +++++++++++++++++++++++------------------- 3 files changed, 33 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index e1a3fc1303e..1e5ae112d57 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -1955,7 +1955,7 @@ static s32 e1000_setup_copper_link(struct e1000_hw *hw) s32 ret_val; u16 i; u16 phy_data; - u16 reg_data; + u16 reg_data = 0; DEBUGFUNC("e1000_setup_copper_link"); diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 99fce2c5dd2..a8866bdbb67 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -523,11 +523,8 @@ s32 e1000_check_phy_reset_block(struct e1000_hw *hw); /* The sizes (in bytes) of a ethernet packet */ #define ENET_HEADER_SIZE 14 -#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* With FCS */ #define MINIMUM_ETHERNET_FRAME_SIZE 64 /* With FCS */ #define ETHERNET_FCS_SIZE 4 -#define MAXIMUM_ETHERNET_PACKET_SIZE \ - (MAXIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE) #define MINIMUM_ETHERNET_PACKET_SIZE \ (MINIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE) #define CRC_LENGTH ETHERNET_FCS_SIZE diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index f2db9e2069e..d7df00c2dbd 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -641,8 +641,8 @@ void e1000_reset(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; u32 pba = 0, tx_space, min_tx_space, min_rx_space; - u16 fc_high_water_mark = E1000_FC_HIGH_DIFF; bool legacy_pba_adjust = false; + u16 hwm; /* Repartition Pba for greater than 9k mtu * To take effect CTRL.RST is required. @@ -686,7 +686,7 @@ void e1000_reset(struct e1000_adapter *adapter) } if (legacy_pba_adjust) { - if (adapter->netdev->mtu > E1000_RXBUFFER_8192) + if (hw->max_frame_size > E1000_RXBUFFER_8192) pba -= 8; /* allocate more FIFO for Tx */ if (hw->mac_type == e1000_82547) { @@ -696,14 +696,14 @@ void e1000_reset(struct e1000_adapter *adapter) (E1000_PBA_40K - pba) << E1000_PBA_BYTES_SHIFT; atomic_set(&adapter->tx_fifo_stall, 0); } - } else if (hw->max_frame_size > MAXIMUM_ETHERNET_FRAME_SIZE) { + } else if (hw->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN) { /* adjust PBA for jumbo frames */ ew32(PBA, pba); /* To maintain wire speed transmits, the Tx FIFO should be - * large enough to accomodate two full transmit packets, + * large enough to accommodate two full transmit packets, * rounded up to the next 1KB and expressed in KB. Likewise, - * the Rx FIFO should be large enough to accomodate at least + * the Rx FIFO should be large enough to accommodate at least * one full receive packet and is similarly rounded up and * expressed in KB. */ pba = er32(PBA); @@ -711,13 +711,17 @@ void e1000_reset(struct e1000_adapter *adapter) tx_space = pba >> 16; /* lower 16 bits has Rx packet buffer allocation size in KB */ pba &= 0xffff; - /* don't include ethernet FCS because hardware appends/strips */ - min_rx_space = adapter->netdev->mtu + ENET_HEADER_SIZE + - VLAN_TAG_SIZE; - min_tx_space = min_rx_space; - min_tx_space *= 2; + /* + * the tx fifo also stores 16 bytes of information about the tx + * but don't include ethernet FCS because hardware appends it + */ + min_tx_space = (hw->max_frame_size + + sizeof(struct e1000_tx_desc) - + ETH_FCS_LEN) * 2; min_tx_space = ALIGN(min_tx_space, 1024); min_tx_space >>= 10; + /* software strips receive CRC, so leave room for it */ + min_rx_space = hw->max_frame_size; min_rx_space = ALIGN(min_rx_space, 1024); min_rx_space >>= 10; @@ -754,19 +758,21 @@ void e1000_reset(struct e1000_adapter *adapter) ew32(PBA, pba); - /* flow control settings */ - /* Set the FC high water mark to 90% of the FIFO size. - * Required to clear last 3 LSB */ - fc_high_water_mark = ((pba * 9216)/10) & 0xFFF8; - /* We can't use 90% on small FIFOs because the remainder - * would be less than 1 full frame. In this case, we size - * it to allow at least a full frame above the high water - * mark. */ - if (pba < E1000_PBA_16K) - fc_high_water_mark = (pba * 1024) - 1600; - - hw->fc_high_water = fc_high_water_mark; - hw->fc_low_water = fc_high_water_mark - 8; + /* + * flow control settings: + * The high water mark must be low enough to fit one full frame + * (or the size used for early receive) above it in the Rx FIFO. + * Set it to the lower of: + * - 90% of the Rx FIFO size, and + * - the full Rx FIFO size minus the early receive size (for parts + * with ERT support assuming ERT set to E1000_ERT_2048), or + * - the full Rx FIFO size minus one full frame + */ + hwm = min(((pba << 10) * 9 / 10), + ((pba << 10) - hw->max_frame_size)); + + hw->fc_high_water = hwm & 0xFFF8; /* 8-byte granularity */ + hw->fc_low_water = hw->fc_high_water - 8; hw->fc_pause_time = E1000_FC_PAUSE_TIME; hw->fc_send_xon = 1; hw->fc = hw->original_fc; @@ -3474,7 +3480,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) switch (hw->mac_type) { case e1000_undefined ... e1000_82542_rev2_1: case e1000_ich8lan: - if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) { + if (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)) { DPRINTK(PROBE, ERR, "Jumbo Frames not supported.\n"); return -EINVAL; } @@ -3487,7 +3493,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) &eeprom_data); if ((hw->device_id != E1000_DEV_ID_82573L) || (eeprom_data & EEPROM_WORD1A_ASPM_MASK)) { - if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) { + if (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)) { DPRINTK(PROBE, ERR, "Jumbo Frames not supported.\n"); return -EINVAL; @@ -3535,7 +3541,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) /* adjust allocation if LPE protects us, and we aren't using SBP */ if (!hw->tbi_compatibility_on && - ((max_frame == MAXIMUM_ETHERNET_FRAME_SIZE) || + ((max_frame == (ETH_FRAME_LEN + ETH_FCS_LEN)) || (max_frame == MAXIMUM_ETHERNET_VLAN_SIZE))) adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE; -- cgit v1.2.3-18-g5258 From 5dcc60b71886795965fd5029b5d9a9ba7b5a2c17 Mon Sep 17 00:00:00 2001 From: Yeasah Pell Date: Mon, 6 Jul 2009 18:12:33 -0700 Subject: dm9000: add checksum offload support Add checksum offload support for DM9000A and DM9000B chips. v2 changes: added a local copy of ip_summed to save IO cycles in dm9000_send_packet v3 changes: trans_start updating is removed. Signed-off-by: Yeasah Pell Signed-off-by: Mike Rapoport Signed-off-by: David S. Miller --- drivers/net/dm9000.c | 107 +++++++++++++++++++++++++++++++++++++++++++-------- drivers/net/dm9000.h | 18 +++++++++ 2 files changed, 108 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index ffd9edceb31..8603806be89 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -92,6 +92,7 @@ typedef struct board_info { u16 tx_pkt_cnt; u16 queue_pkt_len; u16 queue_start_addr; + u16 queue_ip_summed; u16 dbug_cnt; u8 io_mode; /* 0:word, 2:byte */ u8 phy_addr; @@ -124,6 +125,10 @@ typedef struct board_info { struct mii_if_info mii; u32 msg_enable; + + int rx_csum; + int can_csum; + int ip_summed; } board_info_t; /* debug code */ @@ -460,6 +465,40 @@ static int dm9000_nway_reset(struct net_device *dev) return mii_nway_restart(&dm->mii); } +static uint32_t dm9000_get_rx_csum(struct net_device *dev) +{ + board_info_t *dm = to_dm9000_board(dev); + return dm->rx_csum; +} + +static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data) +{ + board_info_t *dm = to_dm9000_board(dev); + unsigned long flags; + + if (dm->can_csum) { + dm->rx_csum = data; + + spin_lock_irqsave(&dm->lock, flags); + iow(dm, DM9000_RCSR, dm->rx_csum ? RCSR_CSUM : 0); + spin_unlock_irqrestore(&dm->lock, flags); + + return 0; + } + + return -EOPNOTSUPP; +} + +static int dm9000_set_tx_csum(struct net_device *dev, uint32_t data) +{ + board_info_t *dm = to_dm9000_board(dev); + int ret = -EOPNOTSUPP; + + if (dm->can_csum) + ret = ethtool_op_set_tx_csum(dev, data); + return ret; +} + static u32 dm9000_get_link(struct net_device *dev) { board_info_t *dm = to_dm9000_board(dev); @@ -540,6 +579,10 @@ static const struct ethtool_ops dm9000_ethtool_ops = { .get_eeprom_len = dm9000_get_eeprom_len, .get_eeprom = dm9000_get_eeprom, .set_eeprom = dm9000_set_eeprom, + .get_rx_csum = dm9000_get_rx_csum, + .set_rx_csum = dm9000_set_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = dm9000_set_tx_csum, }; static void dm9000_show_carrier(board_info_t *db, @@ -685,6 +728,9 @@ dm9000_init_dm9000(struct net_device *dev) /* I/O mode */ db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */ + /* Checksum mode */ + dm9000_set_rx_csum(dev, db->rx_csum); + /* GPIO0 on pre-activate PHY */ iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */ iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */ @@ -743,6 +789,29 @@ static void dm9000_timeout(struct net_device *dev) spin_unlock_irqrestore(&db->lock, flags); } +static void dm9000_send_packet(struct net_device *dev, + int ip_summed, + u16 pkt_len) +{ + board_info_t *dm = to_dm9000_board(dev); + + /* The DM9000 is not smart enough to leave fragmented packets alone. */ + if (dm->ip_summed != ip_summed) { + if (ip_summed == CHECKSUM_NONE) + iow(dm, DM9000_TCCR, 0); + else + iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP); + dm->ip_summed = ip_summed; + } + + /* Set TX length to DM9000 */ + iow(dm, DM9000_TXPLL, pkt_len); + iow(dm, DM9000_TXPLH, pkt_len >> 8); + + /* Issue TX polling command */ + iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ +} + /* * Hardware start transmission. * Send a packet to media from the upper layer. @@ -769,17 +838,11 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) db->tx_pkt_cnt++; /* TX control: First packet immediately send, second packet queue */ if (db->tx_pkt_cnt == 1) { - /* Set TX length to DM9000 */ - iow(db, DM9000_TXPLL, skb->len); - iow(db, DM9000_TXPLH, skb->len >> 8); - - /* Issue TX polling command */ - iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ - - dev->trans_start = jiffies; /* save the time stamp */ + dm9000_send_packet(dev, skb->ip_summed, skb->len); } else { /* Second packet */ db->queue_pkt_len = skb->len; + db->queue_ip_summed = skb->ip_summed; netif_stop_queue(dev); } @@ -809,12 +872,9 @@ static void dm9000_tx_done(struct net_device *dev, board_info_t *db) dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status); /* Queue packet check & send */ - if (db->tx_pkt_cnt > 0) { - iow(db, DM9000_TXPLL, db->queue_pkt_len); - iow(db, DM9000_TXPLH, db->queue_pkt_len >> 8); - iow(db, DM9000_TCR, TCR_TXREQ); - dev->trans_start = jiffies; - } + if (db->tx_pkt_cnt > 0) + dm9000_send_packet(dev, db->queue_ip_summed, + db->queue_pkt_len); netif_wake_queue(dev); } } @@ -846,14 +906,14 @@ dm9000_rx(struct net_device *dev) rxbyte = readb(db->io_data); /* Status check: this byte must be 0 or 1 */ - if (rxbyte > DM9000_PKT_RDY) { + if (rxbyte & DM9000_PKT_ERR) { dev_warn(db->dev, "status check fail: %d\n", rxbyte); iow(db, DM9000_RCR, 0x00); /* Stop Device */ iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */ return; } - if (rxbyte != DM9000_PKT_RDY) + if (!(rxbyte & DM9000_PKT_RDY)) return; /* A packet ready now & Get status/length */ @@ -914,6 +974,12 @@ dm9000_rx(struct net_device *dev) /* Pass to upper layer */ skb->protocol = eth_type_trans(skb, dev); + if (db->rx_csum) { + if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; + } netif_rx(skb); dev->stats.rx_packets++; @@ -922,7 +988,7 @@ dm9000_rx(struct net_device *dev) (db->dumpblk)(db->io_data, RxLen); } - } while (rxbyte == DM9000_PKT_RDY); + } while (rxbyte & DM9000_PKT_RDY); } static irqreturn_t dm9000_interrupt(int irq, void *dev_id) @@ -1349,6 +1415,13 @@ dm9000_probe(struct platform_device *pdev) db->type = TYPE_DM9000E; } + /* dm9000a/b are capable of hardware checksum offload */ + if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) { + db->can_csum = 1; + db->rx_csum = 1; + ndev->features |= NETIF_F_IP_CSUM; + } + /* from this point we assume that we have found a DM9000 */ /* driver system function */ diff --git a/drivers/net/dm9000.h b/drivers/net/dm9000.h index ba25cf54142..80817c2edfb 100644 --- a/drivers/net/dm9000.h +++ b/drivers/net/dm9000.h @@ -45,6 +45,10 @@ #define DM9000_CHIPR 0x2C #define DM9000_SMCR 0x2F +#define DM9000_ETXCSR 0x30 +#define DM9000_TCCR 0x31 +#define DM9000_RCSR 0x32 + #define CHIPR_DM9000A 0x19 #define CHIPR_DM9000B 0x1B @@ -131,7 +135,21 @@ #define GPCR_GEP_CNTL (1<<0) +#define TCCR_IP (1<<0) +#define TCCR_TCP (1<<1) +#define TCCR_UDP (1<<2) + +#define RCSR_UDP_BAD (1<<7) +#define RCSR_TCP_BAD (1<<6) +#define RCSR_IP_BAD (1<<5) +#define RCSR_UDP (1<<4) +#define RCSR_TCP (1<<3) +#define RCSR_IP (1<<2) +#define RCSR_CSUM (1<<1) +#define RCSR_DISCARD (1<<0) + #define DM9000_PKT_RDY 0x01 /* Packet ready to receive */ +#define DM9000_PKT_ERR 0x02 #define DM9000_PKT_MAX 1536 /* Received packet max size */ /* DM9000A / DM9000B definitions */ -- cgit v1.2.3-18-g5258 From ef0657c49e0f93dcebc9b4719e4fe0b478411f60 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 6 Jul 2009 19:09:50 -0700 Subject: drivers/net/cs89x0.c: Avoid using magic number in set_dma_mode The constant DMA_RX_MODE is defined to be 0x14 in the local include file cs89x0.h. Since a constant with the same name is used elsewhere with set_dma_mode, it seems likely that this constant could be used here. The semantic match that finds this problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @@ expression E1; identifier I; constant int C; @@ ( set_dma_mode(E1,I,...) | *set_dma_mode(E1,C,...) ) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/cs89x0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index b5f553a4aa4..e5948970a42 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -1367,7 +1367,7 @@ net_open(struct net_device *dev) spin_lock_irqsave(&lp->lock, flags); disable_dma(dev->dma); clear_dma_ff(dev->dma); - set_dma_mode(dev->dma, 0x14); /* auto_init as well */ + set_dma_mode(dev->dma, DMA_RX_MODE); /* auto_init as well */ set_dma_addr(dev->dma, isa_virt_to_bus(lp->dma_buff)); set_dma_count(dev->dma, lp->dmasize*1024); enable_dma(dev->dma); -- cgit v1.2.3-18-g5258 From 50f238fdf38e37f0350be17c36e3ec0fd298cc40 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 7 Jul 2009 08:38:42 +0000 Subject: ucc_geth: Add support for skb recycling We can reclaim transmitted skbs to use in the receive path, so-called skb recycling support. Also reorder ucc_geth_poll() steps, so that we'll clean tx ring firstly, thus maybe reclaim some skbs for rx. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/ucc_geth.c | 40 ++++++++++++++++++++++++++++------------ drivers/net/ucc_geth.h | 2 ++ 2 files changed, 30 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 5ba95867a2b..ca476a58087 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -209,9 +209,10 @@ static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, { struct sk_buff *skb = NULL; - skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length + - UCC_GETH_RX_DATA_BUF_ALIGNMENT); - + skb = __skb_dequeue(&ugeth->rx_recycle); + if (!skb) + skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length + + UCC_GETH_RX_DATA_BUF_ALIGNMENT); if (skb == NULL) return NULL; @@ -1986,6 +1987,8 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth) iounmap(ugeth->ug_regs); ugeth->ug_regs = NULL; } + + skb_queue_purge(&ugeth->rx_recycle); } static void ucc_geth_set_multi(struct net_device *dev) @@ -2202,6 +2205,8 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth) return -ENOMEM; } + skb_queue_head_init(&ugeth->rx_recycle); + return 0; } @@ -3208,8 +3213,10 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit if (netif_msg_rx_err(ugeth)) ugeth_err("%s, %d: ERROR!!! skb - 0x%08x", __func__, __LINE__, (u32) skb); - if (skb) - dev_kfree_skb_any(skb); + if (skb) { + skb->data = skb->head + NET_SKB_PAD; + __skb_queue_head(&ugeth->rx_recycle, skb); + } ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = NULL; dev->stats.rx_dropped++; @@ -3267,6 +3274,8 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) /* Normal processing. */ while ((bd_status & T_R) == 0) { + struct sk_buff *skb; + /* BD contains already transmitted buffer. */ /* Handle the transmitted buffer and release */ /* the BD to be used with the current frame */ @@ -3276,9 +3285,16 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) dev->stats.tx_packets++; - /* Free the sk buffer associated with this TxBD */ - dev_kfree_skb(ugeth-> - tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]); + skb = ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]; + + if (skb_queue_len(&ugeth->rx_recycle) < RX_BD_RING_LEN && + skb_recycle_check(skb, + ugeth->ug_info->uf_info.max_rx_buf_length + + UCC_GETH_RX_DATA_BUF_ALIGNMENT)) + __skb_queue_head(&ugeth->rx_recycle, skb); + else + dev_kfree_skb(skb); + ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL; ugeth->skb_dirtytx[txQ] = (ugeth->skb_dirtytx[txQ] + @@ -3307,16 +3323,16 @@ static int ucc_geth_poll(struct napi_struct *napi, int budget) ug_info = ugeth->ug_info; - howmany = 0; - for (i = 0; i < ug_info->numQueuesRx; i++) - howmany += ucc_geth_rx(ugeth, i, budget - howmany); - /* Tx event processing */ spin_lock(&ugeth->lock); for (i = 0; i < ug_info->numQueuesTx; i++) ucc_geth_tx(ugeth->ndev, i); spin_unlock(&ugeth->lock); + howmany = 0; + for (i = 0; i < ug_info->numQueuesRx; i++) + howmany += ucc_geth_rx(ugeth, i, budget - howmany); + if (howmany < budget) { napi_complete(napi); setbits32(ugeth->uccf->p_uccm, UCCE_RX_EVENTS | UCCE_TX_EVENTS); diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index 195ab267ead..cfb31afc08a 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -1212,6 +1212,8 @@ struct ucc_geth_private { /* index of the first skb which hasn't been transmitted yet. */ u16 skb_dirtytx[NUM_TX_QUEUES]; + struct sk_buff_head rx_recycle; + struct ugeth_mii_info *mii_info; struct phy_device *phydev; phy_interface_t phy_interface; -- cgit v1.2.3-18-g5258 From 460deefae62db4472e8bd16b21c7d70f3c7fd785 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Tue, 7 Jul 2009 08:11:33 +0000 Subject: tun: Remove a dead line of code Remove an unnecessary assignment. Signed-off-by: Paul Moore Signed-off-by: David S. Miller --- drivers/net/tun.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index c3927b42374..92ffd11a719 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -995,7 +995,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) goto err_free_sk; } - err = -EINVAL; err = register_netdevice(tun->dev); if (err < 0) goto err_free_sk; -- cgit v1.2.3-18-g5258 From 09bb9aa0ed22bea814b0f137390f911af33ddd1b Mon Sep 17 00:00:00 2001 From: Maxime Bizon Date: Wed, 1 Jul 2009 01:29:36 +0000 Subject: MIPS: BCM63XX: Add integrated ethernet PHY support for phylib. Signed-off-by: Maxime Bizon Signed-off-by: Ralf Baechle drivers/net/phy/Kconfig | 6 ++ drivers/net/phy/Makefile | 1 drivers/net/phy/bcm63xx.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 drivers/net/phy/bcm63xx.c Signed-off-by: David S. Miller --- drivers/net/phy/Kconfig | 6 +++ drivers/net/phy/Makefile | 1 + drivers/net/phy/bcm63xx.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 drivers/net/phy/bcm63xx.c (limited to 'drivers') diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index de9cf5136fd..d5d8e1c5bc9 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -56,6 +56,12 @@ config BROADCOM_PHY Currently supports the BCM5411, BCM5421, BCM5461, BCM5464, BCM5481 and BCM5482 PHYs. +config BCM63XX_PHY + tristate "Drivers for Broadcom 63xx SOCs internal PHY" + depends on BCM63XX + ---help--- + Currently supports the 6348 and 6358 PHYs. + config ICPLUS_PHY tristate "Drivers for ICPlus PHYs" ---help--- diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 3a1bfefefbc..edfaac48cbd 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_QSEMI_PHY) += qsemi.o obj-$(CONFIG_SMSC_PHY) += smsc.o obj-$(CONFIG_VITESSE_PHY) += vitesse.o obj-$(CONFIG_BROADCOM_PHY) += broadcom.o +obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o obj-$(CONFIG_ICPLUS_PHY) += icplus.o obj-$(CONFIG_REALTEK_PHY) += realtek.o obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c new file mode 100644 index 00000000000..4fed95e8350 --- /dev/null +++ b/drivers/net/phy/bcm63xx.c @@ -0,0 +1,132 @@ +/* + * Driver for Broadcom 63xx SOCs integrated PHYs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include + +#define MII_BCM63XX_IR 0x1a /* interrupt register */ +#define MII_BCM63XX_IR_EN 0x4000 /* global interrupt enable */ +#define MII_BCM63XX_IR_DUPLEX 0x0800 /* duplex changed */ +#define MII_BCM63XX_IR_SPEED 0x0400 /* speed changed */ +#define MII_BCM63XX_IR_LINK 0x0200 /* link changed */ +#define MII_BCM63XX_IR_GMASK 0x0100 /* global interrupt mask */ + +MODULE_DESCRIPTION("Broadcom 63xx internal PHY driver"); +MODULE_AUTHOR("Maxime Bizon "); +MODULE_LICENSE("GPL"); + +static int bcm63xx_config_init(struct phy_device *phydev) +{ + int reg, err; + + reg = phy_read(phydev, MII_BCM63XX_IR); + if (reg < 0) + return reg; + + /* Mask interrupts globally. */ + reg |= MII_BCM63XX_IR_GMASK; + err = phy_write(phydev, MII_BCM63XX_IR, reg); + if (err < 0) + return err; + + /* Unmask events we are interested in */ + reg = ~(MII_BCM63XX_IR_DUPLEX | + MII_BCM63XX_IR_SPEED | + MII_BCM63XX_IR_LINK) | + MII_BCM63XX_IR_EN; + err = phy_write(phydev, MII_BCM63XX_IR, reg); + if (err < 0) + return err; + return 0; +} + +static int bcm63xx_ack_interrupt(struct phy_device *phydev) +{ + int reg; + + /* Clear pending interrupts. */ + reg = phy_read(phydev, MII_BCM63XX_IR); + if (reg < 0) + return reg; + + return 0; +} + +static int bcm63xx_config_intr(struct phy_device *phydev) +{ + int reg, err; + + reg = phy_read(phydev, MII_BCM63XX_IR); + if (reg < 0) + return reg; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + reg &= ~MII_BCM63XX_IR_GMASK; + else + reg |= MII_BCM63XX_IR_GMASK; + + err = phy_write(phydev, MII_BCM63XX_IR, reg); + return err; +} + +static struct phy_driver bcm63xx_1_driver = { + .phy_id = 0x00406000, + .phy_id_mask = 0xfffffc00, + .name = "Broadcom BCM63XX (1)", + /* ASYM_PAUSE bit is marked RO in datasheet, so don't cheat */ + .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), + .flags = PHY_HAS_INTERRUPT, + .config_init = bcm63xx_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = bcm63xx_ack_interrupt, + .config_intr = bcm63xx_config_intr, + .driver = { .owner = THIS_MODULE }, +}; + +/* same phy as above, with just a different OUI */ +static struct phy_driver bcm63xx_2_driver = { + .phy_id = 0x002bdc00, + .phy_id_mask = 0xfffffc00, + .name = "Broadcom BCM63XX (2)", + .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), + .flags = PHY_HAS_INTERRUPT, + .config_init = bcm63xx_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = bcm63xx_ack_interrupt, + .config_intr = bcm63xx_config_intr, + .driver = { .owner = THIS_MODULE }, +}; + +static int __init bcm63xx_phy_init(void) +{ + int ret; + + ret = phy_driver_register(&bcm63xx_1_driver); + if (ret) + goto out_63xx_1; + ret = phy_driver_register(&bcm63xx_2_driver); + if (ret) + goto out_63xx_2; + return ret; + +out_63xx_2: + phy_driver_unregister(&bcm63xx_1_driver); +out_63xx_1: + return ret; +} + +static void __exit bcm63xx_phy_exit(void) +{ + phy_driver_unregister(&bcm63xx_1_driver); + phy_driver_unregister(&bcm63xx_2_driver); +} + +module_init(bcm63xx_phy_init); +module_exit(bcm63xx_phy_exit); -- cgit v1.2.3-18-g5258 From 72398e4b1a4cf55d3698a4f265b638093a470b04 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 7 Jul 2009 22:04:55 -0700 Subject: Input: use resource_size when allocating resources Use the function resource_size, which reduces the chance of introducing off-by-one errors in calculating the resource size. The semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @@ struct resource *res; @@ - (res->end - res->start) + 1 + resource_size(res) // Signed-off-by: Julia Lawall Signed-off-by: Dmitry Torokhov --- drivers/input/misc/cobalt_btns.c | 2 +- drivers/input/serio/at32psif.c | 2 +- drivers/input/touchscreen/atmel_tsadcc.c | 8 ++++---- drivers/input/touchscreen/w90p910_ts.c | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/cobalt_btns.c b/drivers/input/misc/cobalt_btns.c index 2adf9cb265d..d01da9bd5da 100644 --- a/drivers/input/misc/cobalt_btns.c +++ b/drivers/input/misc/cobalt_btns.c @@ -116,7 +116,7 @@ static int __devinit cobalt_buttons_probe(struct platform_device *pdev) } bdev->poll_dev = poll_dev; - bdev->reg = ioremap(res->start, res->end - res->start + 1); + bdev->reg = ioremap(res->start, resource_size(res)); dev_set_drvdata(&pdev->dev, bdev); error = input_register_polled_device(poll_dev); diff --git a/drivers/input/serio/at32psif.c b/drivers/input/serio/at32psif.c index 41fda8c67b1..a6fb7a3dcc4 100644 --- a/drivers/input/serio/at32psif.c +++ b/drivers/input/serio/at32psif.c @@ -231,7 +231,7 @@ static int __init psif_probe(struct platform_device *pdev) goto out_free_io; } - psif->regs = ioremap(regs->start, regs->end - regs->start + 1); + psif->regs = ioremap(regs->start, resource_size(regs)); if (!psif->regs) { ret = -ENOMEM; dev_dbg(&pdev->dev, "could not map I/O memory\n"); diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c index 055969e8be1..9c7fce4d74d 100644 --- a/drivers/input/touchscreen/atmel_tsadcc.c +++ b/drivers/input/touchscreen/atmel_tsadcc.c @@ -204,14 +204,14 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) goto err_free_dev; } - if (!request_mem_region(res->start, res->end - res->start + 1, + if (!request_mem_region(res->start, resource_size(res), "atmel tsadcc regs")) { dev_err(&pdev->dev, "resources is unavailable.\n"); err = -EBUSY; goto err_free_dev; } - tsc_base = ioremap(res->start, res->end - res->start + 1); + tsc_base = ioremap(res->start, resource_size(res)); if (!tsc_base) { dev_err(&pdev->dev, "failed to map registers.\n"); err = -ENOMEM; @@ -286,7 +286,7 @@ err_free_irq: err_unmap_regs: iounmap(tsc_base); err_release_mem: - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); err_free_dev: input_free_device(ts_dev->input); err_free_mem: @@ -305,7 +305,7 @@ static int __devexit atmel_tsadcc_remove(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); iounmap(tsc_base); - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); clk_disable(ts_dev->clk); clk_put(ts_dev->clk); diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c index 6071f588257..b3e782fdd2b 100644 --- a/drivers/input/touchscreen/w90p910_ts.c +++ b/drivers/input/touchscreen/w90p910_ts.c @@ -241,13 +241,13 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev) goto fail1; } - if (!request_mem_region(res->start, res->end - res->start + 1, + if (!request_mem_region(res->start, resource_size(res), pdev->name)) { err = -EBUSY; goto fail1; } - w90p910_ts->ts_reg = ioremap(res->start, res->end - res->start + 1); + w90p910_ts->ts_reg = ioremap(res->start, resource_size(res)); if (!w90p910_ts->ts_reg) { err = -ENOMEM; goto fail2; @@ -296,7 +296,7 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev) fail4: free_irq(w90p910_ts->irq_num, w90p910_ts); fail3: iounmap(w90p910_ts->ts_reg); -fail2: release_mem_region(res->start, res->end - res->start + 1); +fail2: release_mem_region(res->start, resource_size(res)); fail1: input_free_device(input_dev); kfree(w90p910_ts); return err; @@ -312,7 +312,7 @@ static int __devexit w90x900ts_remove(struct platform_device *pdev) iounmap(w90p910_ts->ts_reg); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); input_unregister_device(w90p910_ts->input); kfree(w90p910_ts); -- cgit v1.2.3-18-g5258 From f7370699fbbb18f97442d6f47cc2d478a911ad6f Mon Sep 17 00:00:00 2001 From: Jim Persson Date: Tue, 7 Jul 2009 22:07:59 -0700 Subject: Input: usbtouchscreen - support for JASTEC/DigiTech DTR-02U USB touch controllers Add support for the JASTEC/DigiTech DTR-02U USB touch screen controllers. Signed-off-by: Jim Persson Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 6 ++++++ drivers/input/touchscreen/usbtouchscreen.c | 32 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) (limited to 'drivers') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 72e2712c7e2..a66e50aeba1 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -406,6 +406,7 @@ config TOUCHSCREEN_USB_COMPOSITE - IRTOUCHSYSTEMS/UNITOP - IdealTEK URTC1000 - GoTop Super_Q2/GogoPen/PenPower tablets + - JASTEC USB Touch Controller/DigiTech DTR-02U Have a look at for a usage description and the required user-space stuff. @@ -468,6 +469,11 @@ config TOUCHSCREEN_USB_GOTOP bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EMBEDDED depends on TOUCHSCREEN_USB_COMPOSITE +config TOUCHSCREEN_USB_JASTEC + default y + bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EMBEDDED + depends on TOUCHSCREEN_USB_COMPOSITE + config TOUCHSCREEN_TOUCHIT213 tristate "Sahara TouchIT-213 touchscreen" select SERIO diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index fb7cb9bdfbd..c07be07a69b 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -13,6 +13,7 @@ * - IdealTEK URTC1000 * - General Touch * - GoTop Super_Q2/GogoPen/PenPower tablets + * - JASTEC USB touch controller/DigiTech DTR-02U * * Copyright (C) 2004-2007 by Daniel Ritz * Copyright (C) by Todd E. Johnson (mtouchusb.c) @@ -118,6 +119,7 @@ enum { DEVTYPE_IDEALTEK, DEVTYPE_GENERAL_TOUCH, DEVTYPE_GOTOP, + DEVTYPE_JASTEC, }; #define USB_DEVICE_HID_CLASS(vend, prod) \ @@ -191,6 +193,10 @@ static struct usb_device_id usbtouch_devices[] = { {USB_DEVICE(0x08f2, 0x00f4), .driver_info = DEVTYPE_GOTOP}, #endif +#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC + {USB_DEVICE(0x0f92, 0x0001), .driver_info = DEVTYPE_JASTEC}, +#endif + {} }; @@ -559,6 +565,21 @@ static int gotop_read_data(struct usbtouch_usb *dev, unsigned char *pkt) dev->x = ((pkt[1] & 0x38) << 4) | pkt[2]; dev->y = ((pkt[1] & 0x07) << 7) | pkt[3]; dev->touch = pkt[0] & 0x01; + + return 1; +} +#endif + +/***************************************************************************** + * JASTEC Part + */ +#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC +static int jastec_read_data(struct usbtouch_usb *dev, unsigned char *pkt) +{ + dev->x = ((pkt[0] & 0x3f) << 6) | (pkt[2] & 0x3f); + dev->y = ((pkt[1] & 0x3f) << 6) | (pkt[3] & 0x3f); + dev->touch = (pkt[0] & 0x40) >> 6; + return 1; } #endif @@ -702,6 +723,17 @@ static struct usbtouch_device_info usbtouch_dev_info[] = { .read_data = gotop_read_data, }, #endif + +#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC + [DEVTYPE_JASTEC] = { + .min_xc = 0x0, + .max_xc = 0x0fff, + .min_yc = 0x0, + .max_yc = 0x0fff, + .rept_size = 4, + .read_data = jastec_read_data, + }, +#endif }; -- cgit v1.2.3-18-g5258 From 2c3d50f7db6c4aa85b099613aba8660da6de75d4 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 7 Jul 2009 19:48:48 +0000 Subject: cxgb3: AQ100X phy support update Add missing SUPPORTED_TP flag. Update FW version checking. Do the full initialization even if the FW version is unknown, it might help catching further issues. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller --- drivers/net/cxgb3/aq100x.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/aq100x.c b/drivers/net/cxgb3/aq100x.c index b1fd5bf836e..341b7ef1508 100644 --- a/drivers/net/cxgb3/aq100x.c +++ b/drivers/net/cxgb3/aq100x.c @@ -271,7 +271,8 @@ int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, cphy_init(phy, adapter, phy_addr, &aq100x_ops, mdio_ops, SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full | - SUPPORTED_Autoneg | SUPPORTED_AUI, "1000/10GBASE-T"); + SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_AUI, + "1000/10GBASE-T"); /* * The PHY has been out of reset ever since the system powered up. So @@ -316,11 +317,9 @@ int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, /* Firmware version check. */ t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_FW_VERSION, &v); - if (v != 30) { + if (v != 101) CH_WARN(adapter, "PHY%d: unsupported firmware %d\n", phy_addr, v); - return 0; /* allow t3_prep_adapter to succeed */ - } /* * The PHY should start in really-low-power mode. Prepare it for normal -- cgit v1.2.3-18-g5258 From 619f05cf690149bef1f15cd0cec6a31b40d96951 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 7 Jul 2009 19:48:53 +0000 Subject: cxgb3: fix phy power down 2 phys are were not getting the Global Tx disable bit set when powered down, leading to an inconsistent link state on peer. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller --- drivers/net/cxgb3/ael1002.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c index 9fe008ec9ba..949d248b746 100644 --- a/drivers/net/cxgb3/ael1002.c +++ b/drivers/net/cxgb3/ael1002.c @@ -224,12 +224,6 @@ static int ael1006_reset(struct cphy *phy, int wait) return t3_phy_reset(phy, MDIO_MMD_PMAPMD, wait); } -static int ael1006_power_down(struct cphy *phy, int enable) -{ - return mdio_set_flag(&phy->mdio, phy->mdio.prtad, MDIO_MMD_PMAPMD, - MDIO_CTRL1, MDIO_CTRL1_LPOWER, enable); -} - static struct cphy_ops ael1006_ops = { .reset = ael1006_reset, .intr_enable = t3_phy_lasi_intr_enable, @@ -237,7 +231,7 @@ static struct cphy_ops ael1006_ops = { .intr_clear = t3_phy_lasi_intr_clear, .intr_handler = t3_phy_lasi_intr_handler, .get_link_status = get_link_status_r, - .power_down = ael1006_power_down, + .power_down = ael1002_power_down, .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, }; @@ -1840,7 +1834,7 @@ static struct cphy_ops qt2045_ops = { .intr_clear = t3_phy_lasi_intr_clear, .intr_handler = t3_phy_lasi_intr_handler, .get_link_status = get_link_status_x, - .power_down = ael1006_power_down, + .power_down = ael1002_power_down, .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, }; -- cgit v1.2.3-18-g5258 From cfe2462c6af309ee70e4aeefa55cae976071b9e2 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 7 Jul 2009 19:48:38 +0000 Subject: cxgb3: Fix T3C MAC max packet size access Max packet size is not the only field in T3C's High Water Mark register. Mask the register to access this field. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller --- drivers/net/cxgb3/xgmac.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c index f87f9435049..0109ee4f2f9 100644 --- a/drivers/net/cxgb3/xgmac.c +++ b/drivers/net/cxgb3/xgmac.c @@ -447,11 +447,12 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); - if (fc & PAUSE_TX) - val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm( - t3_read_reg(adap, - A_XGM_RX_MAX_PKT_SIZE - + oft)) / 8); + if (fc & PAUSE_TX) { + u32 rx_max_pkt_size = + G_RXMAXPKTSIZE(t3_read_reg(adap, + A_XGM_RX_MAX_PKT_SIZE + oft)); + val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8); + } t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, -- cgit v1.2.3-18-g5258 From 5e659515569220701bfe3c8936dcab67554cc286 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 7 Jul 2009 19:48:43 +0000 Subject: cxgb3: AEL2020 phy support update We don't always see the link status update interrupt when we come out of reset and the peer is up. Check and report the link status right before enabling interrupts. Also fix LED settings, to get a consistent link status. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller --- drivers/net/cxgb3/adapter.h | 8 ++++ drivers/net/cxgb3/ael1002.c | 102 ++++++++++++++++++++++++++++++++------------ 2 files changed, 83 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index 1694fad3872..bfa312d43d8 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -276,6 +276,14 @@ static inline struct port_info *adap2pinfo(struct adapter *adap, int idx) return netdev_priv(adap->port[idx]); } +static inline int phy2portid(struct cphy *phy) +{ + struct adapter *adap = phy->adapter; + struct port_info *port0 = adap2pinfo(adap, 0); + + return &port0->phy == phy ? 0 : 1; +} + #define OFFLOAD_DEVMAP_BIT 15 #define tdev2adap(d) container_of(d, struct adapter, tdev) diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c index 949d248b746..66e47f76f32 100644 --- a/drivers/net/cxgb3/ael1002.c +++ b/drivers/net/cxgb3/ael1002.c @@ -1643,9 +1643,39 @@ static int ael2020_get_module_type(struct cphy *phy, int delay_ms) */ static int ael2020_intr_enable(struct cphy *phy) { - int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, - 0x2 << (AEL2020_GPIO_MODDET*4)); - return err ? err : t3_phy_lasi_intr_enable(phy); + struct reg_val regs[] = { + /* output Module's Loss Of Signal (LOS) to LED */ + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT, + 0xffff, 0x4 }, + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) }, + + /* enable module detect status change interrupts */ + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0xffff, 0x2 << (AEL2020_GPIO_MODDET*4) }, + + /* end */ + { 0, 0, 0, 0 } + }; + int err, link_ok = 0; + + /* set up "link status" LED and enable module change interrupts */ + err = set_phy_regs(phy, regs); + if (err) + return err; + + err = get_link_status_r(phy, &link_ok, NULL, NULL, NULL); + if (err) + return err; + if (link_ok) + t3_link_changed(phy->adapter, + phy2portid(phy)); + + err = t3_phy_lasi_intr_enable(phy); + if (err) + return err; + + return 0; } /* @@ -1653,9 +1683,26 @@ static int ael2020_intr_enable(struct cphy *phy) */ static int ael2020_intr_disable(struct cphy *phy) { - int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, - 0x1 << (AEL2020_GPIO_MODDET*4)); - return err ? err : t3_phy_lasi_intr_disable(phy); + struct reg_val regs[] = { + /* reset "link status" LED to "off" */ + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0xffff, 0xb << (AEL2020_GPIO_LSTAT*4) }, + + /* disable module detect status change interrupts */ + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0xffff, 0x1 << (AEL2020_GPIO_MODDET*4) }, + + /* end */ + { 0, 0, 0, 0 } + }; + int err; + + /* turn off "link status" LED and disable module change interrupts */ + err = set_phy_regs(phy, regs); + if (err) + return err; + + return t3_phy_lasi_intr_disable(phy); } /* @@ -1673,31 +1720,26 @@ static int ael2020_intr_clear(struct cphy *phy) return err ? err : t3_phy_lasi_intr_clear(phy); } +static struct reg_val ael2020_reset_regs[] = { + /* Erratum #2: CDRLOL asserted, causing PMA link down status */ + { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 }, + + /* force XAUI to send LF when RX_LOS is asserted */ + { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 }, + + /* allow writes to transceiver module EEPROM on i2c bus */ + { MDIO_MMD_PMAPMD, 0xff02, 0xffff, 0x0023 }, + { MDIO_MMD_PMAPMD, 0xff03, 0xffff, 0x0000 }, + { MDIO_MMD_PMAPMD, 0xff04, 0xffff, 0x0000 }, + + /* end */ + { 0, 0, 0, 0 } +}; /* * Reset the PHY and put it into a canonical operating state. */ static int ael2020_reset(struct cphy *phy, int wait) { - static struct reg_val regs0[] = { - /* Erratum #2: CDRLOL asserted, causing PMA link down status */ - { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 }, - - /* force XAUI to send LF when RX_LOS is asserted */ - { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 }, - - /* RX_LOS pin is active high */ - { MDIO_MMD_PMAPMD, AEL_OPT_SETTINGS, - 0x0020, 0x0020 }, - - /* output Module's Loss Of Signal (LOS) to LED */ - { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT, - 0xffff, 0x0004 }, - { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, - 0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) }, - - /* end */ - { 0, 0, 0, 0 } - }; int err; unsigned int lasi_ctrl; @@ -1714,7 +1756,7 @@ static int ael2020_reset(struct cphy *phy, int wait) /* basic initialization for all module types */ phy->priv = edc_none; - err = set_phy_regs(phy, regs0); + err = set_phy_regs(phy, ael2020_reset_regs); if (err) return err; @@ -1792,10 +1834,16 @@ static struct cphy_ops ael2020_ops = { int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, const struct mdio_ops *mdio_ops) { + int err; + cphy_init(phy, adapter, phy_addr, &ael2020_ops, mdio_ops, SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE | SUPPORTED_IRQ, "10GBASE-R"); msleep(125); + + err = set_phy_regs(phy, ael2020_reset_regs); + if (err) + return err; return 0; } -- cgit v1.2.3-18-g5258 From 2e8c07c35b3ffee7689406be61fd1448ee45d3cd Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 7 Jul 2009 19:49:09 +0000 Subject: cxgb3: use request_firmware() for the EDC registers setup use request_firmware() to load the phy's EDC programmation Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller --- drivers/net/cxgb3/adapter.h | 2 + drivers/net/cxgb3/ael1002.c | 1081 ++-------------------------------------- drivers/net/cxgb3/common.h | 10 + drivers/net/cxgb3/cxgb3_main.c | 69 +++ 4 files changed, 112 insertions(+), 1050 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index bfa312d43d8..74723f2e743 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -320,4 +320,6 @@ int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx, unsigned char *data); irqreturn_t t3_sge_intr_msix(int irq, void *cookie); +int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size); + #endif /* __T3_ADAPTER_H__ */ diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c index 66e47f76f32..5248f9e0b2f 100644 --- a/drivers/net/cxgb3/ael1002.c +++ b/drivers/net/cxgb3/ael1002.c @@ -298,279 +298,7 @@ static int ael2005_setup_sr_edc(struct cphy *phy) { MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5200 }, { 0, 0, 0, 0 } }; - static u16 sr_edc[] = { - 0xcc00, 0x2ff4, - 0xcc01, 0x3cd4, - 0xcc02, 0x2015, - 0xcc03, 0x3105, - 0xcc04, 0x6524, - 0xcc05, 0x27ff, - 0xcc06, 0x300f, - 0xcc07, 0x2c8b, - 0xcc08, 0x300b, - 0xcc09, 0x4009, - 0xcc0a, 0x400e, - 0xcc0b, 0x2f72, - 0xcc0c, 0x3002, - 0xcc0d, 0x1002, - 0xcc0e, 0x2172, - 0xcc0f, 0x3012, - 0xcc10, 0x1002, - 0xcc11, 0x25d2, - 0xcc12, 0x3012, - 0xcc13, 0x1002, - 0xcc14, 0xd01e, - 0xcc15, 0x27d2, - 0xcc16, 0x3012, - 0xcc17, 0x1002, - 0xcc18, 0x2004, - 0xcc19, 0x3c84, - 0xcc1a, 0x6436, - 0xcc1b, 0x2007, - 0xcc1c, 0x3f87, - 0xcc1d, 0x8676, - 0xcc1e, 0x40b7, - 0xcc1f, 0xa746, - 0xcc20, 0x4047, - 0xcc21, 0x5673, - 0xcc22, 0x2982, - 0xcc23, 0x3002, - 0xcc24, 0x13d2, - 0xcc25, 0x8bbd, - 0xcc26, 0x2862, - 0xcc27, 0x3012, - 0xcc28, 0x1002, - 0xcc29, 0x2092, - 0xcc2a, 0x3012, - 0xcc2b, 0x1002, - 0xcc2c, 0x5cc3, - 0xcc2d, 0x314, - 0xcc2e, 0x2942, - 0xcc2f, 0x3002, - 0xcc30, 0x1002, - 0xcc31, 0xd019, - 0xcc32, 0x2032, - 0xcc33, 0x3012, - 0xcc34, 0x1002, - 0xcc35, 0x2a04, - 0xcc36, 0x3c74, - 0xcc37, 0x6435, - 0xcc38, 0x2fa4, - 0xcc39, 0x3cd4, - 0xcc3a, 0x6624, - 0xcc3b, 0x5563, - 0xcc3c, 0x2d42, - 0xcc3d, 0x3002, - 0xcc3e, 0x13d2, - 0xcc3f, 0x464d, - 0xcc40, 0x2862, - 0xcc41, 0x3012, - 0xcc42, 0x1002, - 0xcc43, 0x2032, - 0xcc44, 0x3012, - 0xcc45, 0x1002, - 0xcc46, 0x2fb4, - 0xcc47, 0x3cd4, - 0xcc48, 0x6624, - 0xcc49, 0x5563, - 0xcc4a, 0x2d42, - 0xcc4b, 0x3002, - 0xcc4c, 0x13d2, - 0xcc4d, 0x2ed2, - 0xcc4e, 0x3002, - 0xcc4f, 0x1002, - 0xcc50, 0x2fd2, - 0xcc51, 0x3002, - 0xcc52, 0x1002, - 0xcc53, 0x004, - 0xcc54, 0x2942, - 0xcc55, 0x3002, - 0xcc56, 0x1002, - 0xcc57, 0x2092, - 0xcc58, 0x3012, - 0xcc59, 0x1002, - 0xcc5a, 0x5cc3, - 0xcc5b, 0x317, - 0xcc5c, 0x2f72, - 0xcc5d, 0x3002, - 0xcc5e, 0x1002, - 0xcc5f, 0x2942, - 0xcc60, 0x3002, - 0xcc61, 0x1002, - 0xcc62, 0x22cd, - 0xcc63, 0x301d, - 0xcc64, 0x2862, - 0xcc65, 0x3012, - 0xcc66, 0x1002, - 0xcc67, 0x2ed2, - 0xcc68, 0x3002, - 0xcc69, 0x1002, - 0xcc6a, 0x2d72, - 0xcc6b, 0x3002, - 0xcc6c, 0x1002, - 0xcc6d, 0x628f, - 0xcc6e, 0x2112, - 0xcc6f, 0x3012, - 0xcc70, 0x1002, - 0xcc71, 0x5aa3, - 0xcc72, 0x2dc2, - 0xcc73, 0x3002, - 0xcc74, 0x1312, - 0xcc75, 0x6f72, - 0xcc76, 0x1002, - 0xcc77, 0x2807, - 0xcc78, 0x31a7, - 0xcc79, 0x20c4, - 0xcc7a, 0x3c24, - 0xcc7b, 0x6724, - 0xcc7c, 0x1002, - 0xcc7d, 0x2807, - 0xcc7e, 0x3187, - 0xcc7f, 0x20c4, - 0xcc80, 0x3c24, - 0xcc81, 0x6724, - 0xcc82, 0x1002, - 0xcc83, 0x2514, - 0xcc84, 0x3c64, - 0xcc85, 0x6436, - 0xcc86, 0xdff4, - 0xcc87, 0x6436, - 0xcc88, 0x1002, - 0xcc89, 0x40a4, - 0xcc8a, 0x643c, - 0xcc8b, 0x4016, - 0xcc8c, 0x8c6c, - 0xcc8d, 0x2b24, - 0xcc8e, 0x3c24, - 0xcc8f, 0x6435, - 0xcc90, 0x1002, - 0xcc91, 0x2b24, - 0xcc92, 0x3c24, - 0xcc93, 0x643a, - 0xcc94, 0x4025, - 0xcc95, 0x8a5a, - 0xcc96, 0x1002, - 0xcc97, 0x2731, - 0xcc98, 0x3011, - 0xcc99, 0x1001, - 0xcc9a, 0xc7a0, - 0xcc9b, 0x100, - 0xcc9c, 0xc502, - 0xcc9d, 0x53ac, - 0xcc9e, 0xc503, - 0xcc9f, 0xd5d5, - 0xcca0, 0xc600, - 0xcca1, 0x2a6d, - 0xcca2, 0xc601, - 0xcca3, 0x2a4c, - 0xcca4, 0xc602, - 0xcca5, 0x111, - 0xcca6, 0xc60c, - 0xcca7, 0x5900, - 0xcca8, 0xc710, - 0xcca9, 0x700, - 0xccaa, 0xc718, - 0xccab, 0x700, - 0xccac, 0xc720, - 0xccad, 0x4700, - 0xccae, 0xc801, - 0xccaf, 0x7f50, - 0xccb0, 0xc802, - 0xccb1, 0x7760, - 0xccb2, 0xc803, - 0xccb3, 0x7fce, - 0xccb4, 0xc804, - 0xccb5, 0x5700, - 0xccb6, 0xc805, - 0xccb7, 0x5f11, - 0xccb8, 0xc806, - 0xccb9, 0x4751, - 0xccba, 0xc807, - 0xccbb, 0x57e1, - 0xccbc, 0xc808, - 0xccbd, 0x2700, - 0xccbe, 0xc809, - 0xccbf, 0x000, - 0xccc0, 0xc821, - 0xccc1, 0x002, - 0xccc2, 0xc822, - 0xccc3, 0x014, - 0xccc4, 0xc832, - 0xccc5, 0x1186, - 0xccc6, 0xc847, - 0xccc7, 0x1e02, - 0xccc8, 0xc013, - 0xccc9, 0xf341, - 0xccca, 0xc01a, - 0xcccb, 0x446, - 0xcccc, 0xc024, - 0xcccd, 0x1000, - 0xccce, 0xc025, - 0xcccf, 0xa00, - 0xccd0, 0xc026, - 0xccd1, 0xc0c, - 0xccd2, 0xc027, - 0xccd3, 0xc0c, - 0xccd4, 0xc029, - 0xccd5, 0x0a0, - 0xccd6, 0xc030, - 0xccd7, 0xa00, - 0xccd8, 0xc03c, - 0xccd9, 0x01c, - 0xccda, 0xc005, - 0xccdb, 0x7a06, - 0xccdc, 0x000, - 0xccdd, 0x2731, - 0xccde, 0x3011, - 0xccdf, 0x1001, - 0xcce0, 0xc620, - 0xcce1, 0x000, - 0xcce2, 0xc621, - 0xcce3, 0x03f, - 0xcce4, 0xc622, - 0xcce5, 0x000, - 0xcce6, 0xc623, - 0xcce7, 0x000, - 0xcce8, 0xc624, - 0xcce9, 0x000, - 0xccea, 0xc625, - 0xcceb, 0x000, - 0xccec, 0xc627, - 0xcced, 0x000, - 0xccee, 0xc628, - 0xccef, 0x000, - 0xccf0, 0xc62c, - 0xccf1, 0x000, - 0xccf2, 0x000, - 0xccf3, 0x2806, - 0xccf4, 0x3cb6, - 0xccf5, 0xc161, - 0xccf6, 0x6134, - 0xccf7, 0x6135, - 0xccf8, 0x5443, - 0xccf9, 0x303, - 0xccfa, 0x6524, - 0xccfb, 0x00b, - 0xccfc, 0x1002, - 0xccfd, 0x2104, - 0xccfe, 0x3c24, - 0xccff, 0x2105, - 0xcd00, 0x3805, - 0xcd01, 0x6524, - 0xcd02, 0xdff4, - 0xcd03, 0x4005, - 0xcd04, 0x6524, - 0xcd05, 0x1002, - 0xcd06, 0x5dd3, - 0xcd07, 0x306, - 0xcd08, 0x2ff7, - 0xcd09, 0x38f7, - 0xcd0a, 0x60b7, - 0xcd0b, 0xdffd, - 0xcd0c, 0x00a, - 0xcd0d, 0x1002, - 0xcd0e, 0 - }; + int i, err; err = set_phy_regs(phy, regs); @@ -579,9 +307,16 @@ static int ael2005_setup_sr_edc(struct cphy *phy) msleep(50); - for (i = 0; i < ARRAY_SIZE(sr_edc) && !err; i += 2) - err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, sr_edc[i], - sr_edc[i + 1]); + if (phy->priv != edc_sr) + err = t3_get_edc_fw(phy, EDC_OPT_AEL2005, + EDC_OPT_AEL2005_SIZE); + if (err) + return err; + + for (i = 0; i < EDC_OPT_AEL2005_SIZE / sizeof(u16) && !err; i += 2) + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, + phy->phy_cache[i], + phy->phy_cache[i + 1]); if (!err) phy->priv = edc_sr; return err; @@ -598,374 +333,6 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype) { MDIO_MMD_PMAPMD, 0xc015, 0xffff, 0xa000 }, { 0, 0, 0, 0 } }; - static u16 twinax_edc[] = { - 0xcc00, 0x4009, - 0xcc01, 0x27ff, - 0xcc02, 0x300f, - 0xcc03, 0x40aa, - 0xcc04, 0x401c, - 0xcc05, 0x401e, - 0xcc06, 0x2ff4, - 0xcc07, 0x3cd4, - 0xcc08, 0x2035, - 0xcc09, 0x3145, - 0xcc0a, 0x6524, - 0xcc0b, 0x26a2, - 0xcc0c, 0x3012, - 0xcc0d, 0x1002, - 0xcc0e, 0x29c2, - 0xcc0f, 0x3002, - 0xcc10, 0x1002, - 0xcc11, 0x2072, - 0xcc12, 0x3012, - 0xcc13, 0x1002, - 0xcc14, 0x22cd, - 0xcc15, 0x301d, - 0xcc16, 0x2e52, - 0xcc17, 0x3012, - 0xcc18, 0x1002, - 0xcc19, 0x28e2, - 0xcc1a, 0x3002, - 0xcc1b, 0x1002, - 0xcc1c, 0x628f, - 0xcc1d, 0x2ac2, - 0xcc1e, 0x3012, - 0xcc1f, 0x1002, - 0xcc20, 0x5553, - 0xcc21, 0x2ae2, - 0xcc22, 0x3002, - 0xcc23, 0x1302, - 0xcc24, 0x401e, - 0xcc25, 0x2be2, - 0xcc26, 0x3012, - 0xcc27, 0x1002, - 0xcc28, 0x2da2, - 0xcc29, 0x3012, - 0xcc2a, 0x1002, - 0xcc2b, 0x2ba2, - 0xcc2c, 0x3002, - 0xcc2d, 0x1002, - 0xcc2e, 0x5ee3, - 0xcc2f, 0x305, - 0xcc30, 0x400e, - 0xcc31, 0x2bc2, - 0xcc32, 0x3002, - 0xcc33, 0x1002, - 0xcc34, 0x2b82, - 0xcc35, 0x3012, - 0xcc36, 0x1002, - 0xcc37, 0x5663, - 0xcc38, 0x302, - 0xcc39, 0x401e, - 0xcc3a, 0x6f72, - 0xcc3b, 0x1002, - 0xcc3c, 0x628f, - 0xcc3d, 0x2be2, - 0xcc3e, 0x3012, - 0xcc3f, 0x1002, - 0xcc40, 0x22cd, - 0xcc41, 0x301d, - 0xcc42, 0x2e52, - 0xcc43, 0x3012, - 0xcc44, 0x1002, - 0xcc45, 0x2522, - 0xcc46, 0x3012, - 0xcc47, 0x1002, - 0xcc48, 0x2da2, - 0xcc49, 0x3012, - 0xcc4a, 0x1002, - 0xcc4b, 0x2ca2, - 0xcc4c, 0x3012, - 0xcc4d, 0x1002, - 0xcc4e, 0x2fa4, - 0xcc4f, 0x3cd4, - 0xcc50, 0x6624, - 0xcc51, 0x410b, - 0xcc52, 0x56b3, - 0xcc53, 0x3c4, - 0xcc54, 0x2fb2, - 0xcc55, 0x3002, - 0xcc56, 0x1002, - 0xcc57, 0x220b, - 0xcc58, 0x303b, - 0xcc59, 0x56b3, - 0xcc5a, 0x3c3, - 0xcc5b, 0x866b, - 0xcc5c, 0x400c, - 0xcc5d, 0x23a2, - 0xcc5e, 0x3012, - 0xcc5f, 0x1002, - 0xcc60, 0x2da2, - 0xcc61, 0x3012, - 0xcc62, 0x1002, - 0xcc63, 0x2ca2, - 0xcc64, 0x3012, - 0xcc65, 0x1002, - 0xcc66, 0x2fb4, - 0xcc67, 0x3cd4, - 0xcc68, 0x6624, - 0xcc69, 0x56b3, - 0xcc6a, 0x3c3, - 0xcc6b, 0x866b, - 0xcc6c, 0x401c, - 0xcc6d, 0x2205, - 0xcc6e, 0x3035, - 0xcc6f, 0x5b53, - 0xcc70, 0x2c52, - 0xcc71, 0x3002, - 0xcc72, 0x13c2, - 0xcc73, 0x5cc3, - 0xcc74, 0x317, - 0xcc75, 0x2522, - 0xcc76, 0x3012, - 0xcc77, 0x1002, - 0xcc78, 0x2da2, - 0xcc79, 0x3012, - 0xcc7a, 0x1002, - 0xcc7b, 0x2b82, - 0xcc7c, 0x3012, - 0xcc7d, 0x1002, - 0xcc7e, 0x5663, - 0xcc7f, 0x303, - 0xcc80, 0x401e, - 0xcc81, 0x004, - 0xcc82, 0x2c42, - 0xcc83, 0x3012, - 0xcc84, 0x1002, - 0xcc85, 0x6f72, - 0xcc86, 0x1002, - 0xcc87, 0x628f, - 0xcc88, 0x2304, - 0xcc89, 0x3c84, - 0xcc8a, 0x6436, - 0xcc8b, 0xdff4, - 0xcc8c, 0x6436, - 0xcc8d, 0x2ff5, - 0xcc8e, 0x3005, - 0xcc8f, 0x8656, - 0xcc90, 0xdfba, - 0xcc91, 0x56a3, - 0xcc92, 0xd05a, - 0xcc93, 0x21c2, - 0xcc94, 0x3012, - 0xcc95, 0x1392, - 0xcc96, 0xd05a, - 0xcc97, 0x56a3, - 0xcc98, 0xdfba, - 0xcc99, 0x383, - 0xcc9a, 0x6f72, - 0xcc9b, 0x1002, - 0xcc9c, 0x28c5, - 0xcc9d, 0x3005, - 0xcc9e, 0x4178, - 0xcc9f, 0x5653, - 0xcca0, 0x384, - 0xcca1, 0x22b2, - 0xcca2, 0x3012, - 0xcca3, 0x1002, - 0xcca4, 0x2be5, - 0xcca5, 0x3005, - 0xcca6, 0x41e8, - 0xcca7, 0x5653, - 0xcca8, 0x382, - 0xcca9, 0x002, - 0xccaa, 0x4258, - 0xccab, 0x2474, - 0xccac, 0x3c84, - 0xccad, 0x6437, - 0xccae, 0xdff4, - 0xccaf, 0x6437, - 0xccb0, 0x2ff5, - 0xccb1, 0x3c05, - 0xccb2, 0x8757, - 0xccb3, 0xb888, - 0xccb4, 0x9787, - 0xccb5, 0xdff4, - 0xccb6, 0x6724, - 0xccb7, 0x866a, - 0xccb8, 0x6f72, - 0xccb9, 0x1002, - 0xccba, 0x2d01, - 0xccbb, 0x3011, - 0xccbc, 0x1001, - 0xccbd, 0xc620, - 0xccbe, 0x14e5, - 0xccbf, 0xc621, - 0xccc0, 0xc53d, - 0xccc1, 0xc622, - 0xccc2, 0x3cbe, - 0xccc3, 0xc623, - 0xccc4, 0x4452, - 0xccc5, 0xc624, - 0xccc6, 0xc5c5, - 0xccc7, 0xc625, - 0xccc8, 0xe01e, - 0xccc9, 0xc627, - 0xccca, 0x000, - 0xcccb, 0xc628, - 0xcccc, 0x000, - 0xcccd, 0xc62b, - 0xccce, 0x000, - 0xcccf, 0xc62c, - 0xccd0, 0x000, - 0xccd1, 0x000, - 0xccd2, 0x2d01, - 0xccd3, 0x3011, - 0xccd4, 0x1001, - 0xccd5, 0xc620, - 0xccd6, 0x000, - 0xccd7, 0xc621, - 0xccd8, 0x000, - 0xccd9, 0xc622, - 0xccda, 0x0ce, - 0xccdb, 0xc623, - 0xccdc, 0x07f, - 0xccdd, 0xc624, - 0xccde, 0x032, - 0xccdf, 0xc625, - 0xcce0, 0x000, - 0xcce1, 0xc627, - 0xcce2, 0x000, - 0xcce3, 0xc628, - 0xcce4, 0x000, - 0xcce5, 0xc62b, - 0xcce6, 0x000, - 0xcce7, 0xc62c, - 0xcce8, 0x000, - 0xcce9, 0x000, - 0xccea, 0x2d01, - 0xcceb, 0x3011, - 0xccec, 0x1001, - 0xcced, 0xc502, - 0xccee, 0x609f, - 0xccef, 0xc600, - 0xccf0, 0x2a6e, - 0xccf1, 0xc601, - 0xccf2, 0x2a2c, - 0xccf3, 0xc60c, - 0xccf4, 0x5400, - 0xccf5, 0xc710, - 0xccf6, 0x700, - 0xccf7, 0xc718, - 0xccf8, 0x700, - 0xccf9, 0xc720, - 0xccfa, 0x4700, - 0xccfb, 0xc728, - 0xccfc, 0x700, - 0xccfd, 0xc729, - 0xccfe, 0x1207, - 0xccff, 0xc801, - 0xcd00, 0x7f50, - 0xcd01, 0xc802, - 0xcd02, 0x7760, - 0xcd03, 0xc803, - 0xcd04, 0x7fce, - 0xcd05, 0xc804, - 0xcd06, 0x520e, - 0xcd07, 0xc805, - 0xcd08, 0x5c11, - 0xcd09, 0xc806, - 0xcd0a, 0x3c51, - 0xcd0b, 0xc807, - 0xcd0c, 0x4061, - 0xcd0d, 0xc808, - 0xcd0e, 0x49c1, - 0xcd0f, 0xc809, - 0xcd10, 0x3840, - 0xcd11, 0xc80a, - 0xcd12, 0x000, - 0xcd13, 0xc821, - 0xcd14, 0x002, - 0xcd15, 0xc822, - 0xcd16, 0x046, - 0xcd17, 0xc844, - 0xcd18, 0x182f, - 0xcd19, 0xc013, - 0xcd1a, 0xf341, - 0xcd1b, 0xc01a, - 0xcd1c, 0x446, - 0xcd1d, 0xc024, - 0xcd1e, 0x1000, - 0xcd1f, 0xc025, - 0xcd20, 0xa00, - 0xcd21, 0xc026, - 0xcd22, 0xc0c, - 0xcd23, 0xc027, - 0xcd24, 0xc0c, - 0xcd25, 0xc029, - 0xcd26, 0x0a0, - 0xcd27, 0xc030, - 0xcd28, 0xa00, - 0xcd29, 0xc03c, - 0xcd2a, 0x01c, - 0xcd2b, 0x000, - 0xcd2c, 0x2b84, - 0xcd2d, 0x3c74, - 0xcd2e, 0x6435, - 0xcd2f, 0xdff4, - 0xcd30, 0x6435, - 0xcd31, 0x2806, - 0xcd32, 0x3006, - 0xcd33, 0x8565, - 0xcd34, 0x2b24, - 0xcd35, 0x3c24, - 0xcd36, 0x6436, - 0xcd37, 0x1002, - 0xcd38, 0x2b24, - 0xcd39, 0x3c24, - 0xcd3a, 0x6436, - 0xcd3b, 0x4045, - 0xcd3c, 0x8656, - 0xcd3d, 0x1002, - 0xcd3e, 0x2807, - 0xcd3f, 0x31a7, - 0xcd40, 0x20c4, - 0xcd41, 0x3c24, - 0xcd42, 0x6724, - 0xcd43, 0x1002, - 0xcd44, 0x2807, - 0xcd45, 0x3187, - 0xcd46, 0x20c4, - 0xcd47, 0x3c24, - 0xcd48, 0x6724, - 0xcd49, 0x1002, - 0xcd4a, 0x2514, - 0xcd4b, 0x3c64, - 0xcd4c, 0x6436, - 0xcd4d, 0xdff4, - 0xcd4e, 0x6436, - 0xcd4f, 0x1002, - 0xcd50, 0x2806, - 0xcd51, 0x3cb6, - 0xcd52, 0xc161, - 0xcd53, 0x6134, - 0xcd54, 0x6135, - 0xcd55, 0x5443, - 0xcd56, 0x303, - 0xcd57, 0x6524, - 0xcd58, 0x00b, - 0xcd59, 0x1002, - 0xcd5a, 0xd019, - 0xcd5b, 0x2104, - 0xcd5c, 0x3c24, - 0xcd5d, 0x2105, - 0xcd5e, 0x3805, - 0xcd5f, 0x6524, - 0xcd60, 0xdff4, - 0xcd61, 0x4005, - 0xcd62, 0x6524, - 0xcd63, 0x2e8d, - 0xcd64, 0x303d, - 0xcd65, 0x5dd3, - 0xcd66, 0x306, - 0xcd67, 0x2ff7, - 0xcd68, 0x38f7, - 0xcd69, 0x60b7, - 0xcd6a, 0xdffd, - 0xcd6b, 0x00a, - 0xcd6c, 0x1002, - 0xcd6d, 0 - }; int i, err; err = set_phy_regs(phy, regs); @@ -976,9 +343,16 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype) msleep(50); - for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2) - err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i], - twinax_edc[i + 1]); + if (phy->priv != edc_twinax) + err = t3_get_edc_fw(phy, EDC_TWX_AEL2005, + EDC_TWX_AEL2005_SIZE); + if (err) + return err; + + for (i = 0; i < EDC_TWX_AEL2005_SIZE / sizeof(u16) && !err; i += 2) + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, + phy->phy_cache[i], + phy->phy_cache[i + 1]); if (!err) phy->priv = edc_twinax; return err; @@ -1195,405 +569,6 @@ static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype) { MDIO_MMD_PMAPMD, 0xd092, 0xffff, 0x0000 }, { 0, 0, 0, 0 } }; - - /* TWINAX EDC firmware */ - static u16 twinax_edc[] = { - 0xd800, 0x4009, - 0xd801, 0x2fff, - 0xd802, 0x300f, - 0xd803, 0x40aa, - 0xd804, 0x401c, - 0xd805, 0x401e, - 0xd806, 0x2ff4, - 0xd807, 0x3dc4, - 0xd808, 0x2035, - 0xd809, 0x3035, - 0xd80a, 0x6524, - 0xd80b, 0x2cb2, - 0xd80c, 0x3012, - 0xd80d, 0x1002, - 0xd80e, 0x26e2, - 0xd80f, 0x3022, - 0xd810, 0x1002, - 0xd811, 0x27d2, - 0xd812, 0x3022, - 0xd813, 0x1002, - 0xd814, 0x2822, - 0xd815, 0x3012, - 0xd816, 0x1002, - 0xd817, 0x2492, - 0xd818, 0x3022, - 0xd819, 0x1002, - 0xd81a, 0x2772, - 0xd81b, 0x3012, - 0xd81c, 0x1002, - 0xd81d, 0x23d2, - 0xd81e, 0x3022, - 0xd81f, 0x1002, - 0xd820, 0x22cd, - 0xd821, 0x301d, - 0xd822, 0x27f2, - 0xd823, 0x3022, - 0xd824, 0x1002, - 0xd825, 0x5553, - 0xd826, 0x0307, - 0xd827, 0x2522, - 0xd828, 0x3022, - 0xd829, 0x1002, - 0xd82a, 0x2142, - 0xd82b, 0x3012, - 0xd82c, 0x1002, - 0xd82d, 0x4016, - 0xd82e, 0x5e63, - 0xd82f, 0x0344, - 0xd830, 0x2142, - 0xd831, 0x3012, - 0xd832, 0x1002, - 0xd833, 0x400e, - 0xd834, 0x2522, - 0xd835, 0x3022, - 0xd836, 0x1002, - 0xd837, 0x2b52, - 0xd838, 0x3012, - 0xd839, 0x1002, - 0xd83a, 0x2742, - 0xd83b, 0x3022, - 0xd83c, 0x1002, - 0xd83d, 0x25e2, - 0xd83e, 0x3022, - 0xd83f, 0x1002, - 0xd840, 0x2fa4, - 0xd841, 0x3dc4, - 0xd842, 0x6624, - 0xd843, 0x414b, - 0xd844, 0x56b3, - 0xd845, 0x03c6, - 0xd846, 0x866b, - 0xd847, 0x400c, - 0xd848, 0x2712, - 0xd849, 0x3012, - 0xd84a, 0x1002, - 0xd84b, 0x2c4b, - 0xd84c, 0x309b, - 0xd84d, 0x56b3, - 0xd84e, 0x03c3, - 0xd84f, 0x866b, - 0xd850, 0x400c, - 0xd851, 0x2272, - 0xd852, 0x3022, - 0xd853, 0x1002, - 0xd854, 0x2742, - 0xd855, 0x3022, - 0xd856, 0x1002, - 0xd857, 0x25e2, - 0xd858, 0x3022, - 0xd859, 0x1002, - 0xd85a, 0x2fb4, - 0xd85b, 0x3dc4, - 0xd85c, 0x6624, - 0xd85d, 0x56b3, - 0xd85e, 0x03c3, - 0xd85f, 0x866b, - 0xd860, 0x401c, - 0xd861, 0x2c45, - 0xd862, 0x3095, - 0xd863, 0x5b53, - 0xd864, 0x2372, - 0xd865, 0x3012, - 0xd866, 0x13c2, - 0xd867, 0x5cc3, - 0xd868, 0x2712, - 0xd869, 0x3012, - 0xd86a, 0x1312, - 0xd86b, 0x2b52, - 0xd86c, 0x3012, - 0xd86d, 0x1002, - 0xd86e, 0x2742, - 0xd86f, 0x3022, - 0xd870, 0x1002, - 0xd871, 0x2582, - 0xd872, 0x3022, - 0xd873, 0x1002, - 0xd874, 0x2142, - 0xd875, 0x3012, - 0xd876, 0x1002, - 0xd877, 0x628f, - 0xd878, 0x2985, - 0xd879, 0x33a5, - 0xd87a, 0x25e2, - 0xd87b, 0x3022, - 0xd87c, 0x1002, - 0xd87d, 0x5653, - 0xd87e, 0x03d2, - 0xd87f, 0x401e, - 0xd880, 0x6f72, - 0xd881, 0x1002, - 0xd882, 0x628f, - 0xd883, 0x2304, - 0xd884, 0x3c84, - 0xd885, 0x6436, - 0xd886, 0xdff4, - 0xd887, 0x6436, - 0xd888, 0x2ff5, - 0xd889, 0x3005, - 0xd88a, 0x8656, - 0xd88b, 0xdfba, - 0xd88c, 0x56a3, - 0xd88d, 0xd05a, - 0xd88e, 0x2972, - 0xd88f, 0x3012, - 0xd890, 0x1392, - 0xd891, 0xd05a, - 0xd892, 0x56a3, - 0xd893, 0xdfba, - 0xd894, 0x0383, - 0xd895, 0x6f72, - 0xd896, 0x1002, - 0xd897, 0x2b45, - 0xd898, 0x3005, - 0xd899, 0x4178, - 0xd89a, 0x5653, - 0xd89b, 0x0384, - 0xd89c, 0x2a62, - 0xd89d, 0x3012, - 0xd89e, 0x1002, - 0xd89f, 0x2f05, - 0xd8a0, 0x3005, - 0xd8a1, 0x41c8, - 0xd8a2, 0x5653, - 0xd8a3, 0x0382, - 0xd8a4, 0x0002, - 0xd8a5, 0x4218, - 0xd8a6, 0x2474, - 0xd8a7, 0x3c84, - 0xd8a8, 0x6437, - 0xd8a9, 0xdff4, - 0xd8aa, 0x6437, - 0xd8ab, 0x2ff5, - 0xd8ac, 0x3c05, - 0xd8ad, 0x8757, - 0xd8ae, 0xb888, - 0xd8af, 0x9787, - 0xd8b0, 0xdff4, - 0xd8b1, 0x6724, - 0xd8b2, 0x866a, - 0xd8b3, 0x6f72, - 0xd8b4, 0x1002, - 0xd8b5, 0x2641, - 0xd8b6, 0x3021, - 0xd8b7, 0x1001, - 0xd8b8, 0xc620, - 0xd8b9, 0x0000, - 0xd8ba, 0xc621, - 0xd8bb, 0x0000, - 0xd8bc, 0xc622, - 0xd8bd, 0x00ce, - 0xd8be, 0xc623, - 0xd8bf, 0x007f, - 0xd8c0, 0xc624, - 0xd8c1, 0x0032, - 0xd8c2, 0xc625, - 0xd8c3, 0x0000, - 0xd8c4, 0xc627, - 0xd8c5, 0x0000, - 0xd8c6, 0xc628, - 0xd8c7, 0x0000, - 0xd8c8, 0xc62c, - 0xd8c9, 0x0000, - 0xd8ca, 0x0000, - 0xd8cb, 0x2641, - 0xd8cc, 0x3021, - 0xd8cd, 0x1001, - 0xd8ce, 0xc502, - 0xd8cf, 0x53ac, - 0xd8d0, 0xc503, - 0xd8d1, 0x2cd3, - 0xd8d2, 0xc600, - 0xd8d3, 0x2a6e, - 0xd8d4, 0xc601, - 0xd8d5, 0x2a2c, - 0xd8d6, 0xc605, - 0xd8d7, 0x5557, - 0xd8d8, 0xc60c, - 0xd8d9, 0x5400, - 0xd8da, 0xc710, - 0xd8db, 0x0700, - 0xd8dc, 0xc711, - 0xd8dd, 0x0f06, - 0xd8de, 0xc718, - 0xd8df, 0x0700, - 0xd8e0, 0xc719, - 0xd8e1, 0x0f06, - 0xd8e2, 0xc720, - 0xd8e3, 0x4700, - 0xd8e4, 0xc721, - 0xd8e5, 0x0f06, - 0xd8e6, 0xc728, - 0xd8e7, 0x0700, - 0xd8e8, 0xc729, - 0xd8e9, 0x1207, - 0xd8ea, 0xc801, - 0xd8eb, 0x7f50, - 0xd8ec, 0xc802, - 0xd8ed, 0x7760, - 0xd8ee, 0xc803, - 0xd8ef, 0x7fce, - 0xd8f0, 0xc804, - 0xd8f1, 0x520e, - 0xd8f2, 0xc805, - 0xd8f3, 0x5c11, - 0xd8f4, 0xc806, - 0xd8f5, 0x3c51, - 0xd8f6, 0xc807, - 0xd8f7, 0x4061, - 0xd8f8, 0xc808, - 0xd8f9, 0x49c1, - 0xd8fa, 0xc809, - 0xd8fb, 0x3840, - 0xd8fc, 0xc80a, - 0xd8fd, 0x0000, - 0xd8fe, 0xc821, - 0xd8ff, 0x0002, - 0xd900, 0xc822, - 0xd901, 0x0046, - 0xd902, 0xc844, - 0xd903, 0x182f, - 0xd904, 0xc013, - 0xd905, 0xf341, - 0xd906, 0xc084, - 0xd907, 0x0030, - 0xd908, 0xc904, - 0xd909, 0x1401, - 0xd90a, 0xcb0c, - 0xd90b, 0x0004, - 0xd90c, 0xcb0e, - 0xd90d, 0xa00a, - 0xd90e, 0xcb0f, - 0xd90f, 0xc0c0, - 0xd910, 0xcb10, - 0xd911, 0xc0c0, - 0xd912, 0xcb11, - 0xd913, 0x00a0, - 0xd914, 0xcb12, - 0xd915, 0x0007, - 0xd916, 0xc241, - 0xd917, 0xa000, - 0xd918, 0xc243, - 0xd919, 0x7fe0, - 0xd91a, 0xc604, - 0xd91b, 0x000e, - 0xd91c, 0xc609, - 0xd91d, 0x00f5, - 0xd91e, 0xc611, - 0xd91f, 0x000e, - 0xd920, 0xc660, - 0xd921, 0x9600, - 0xd922, 0xc687, - 0xd923, 0x0004, - 0xd924, 0xc60a, - 0xd925, 0x04f5, - 0xd926, 0x0000, - 0xd927, 0x2641, - 0xd928, 0x3021, - 0xd929, 0x1001, - 0xd92a, 0xc620, - 0xd92b, 0x14e5, - 0xd92c, 0xc621, - 0xd92d, 0xc53d, - 0xd92e, 0xc622, - 0xd92f, 0x3cbe, - 0xd930, 0xc623, - 0xd931, 0x4452, - 0xd932, 0xc624, - 0xd933, 0xc5c5, - 0xd934, 0xc625, - 0xd935, 0xe01e, - 0xd936, 0xc627, - 0xd937, 0x0000, - 0xd938, 0xc628, - 0xd939, 0x0000, - 0xd93a, 0xc62c, - 0xd93b, 0x0000, - 0xd93c, 0x0000, - 0xd93d, 0x2b84, - 0xd93e, 0x3c74, - 0xd93f, 0x6435, - 0xd940, 0xdff4, - 0xd941, 0x6435, - 0xd942, 0x2806, - 0xd943, 0x3006, - 0xd944, 0x8565, - 0xd945, 0x2b24, - 0xd946, 0x3c24, - 0xd947, 0x6436, - 0xd948, 0x1002, - 0xd949, 0x2b24, - 0xd94a, 0x3c24, - 0xd94b, 0x6436, - 0xd94c, 0x4045, - 0xd94d, 0x8656, - 0xd94e, 0x5663, - 0xd94f, 0x0302, - 0xd950, 0x401e, - 0xd951, 0x1002, - 0xd952, 0x2807, - 0xd953, 0x31a7, - 0xd954, 0x20c4, - 0xd955, 0x3c24, - 0xd956, 0x6724, - 0xd957, 0x1002, - 0xd958, 0x2807, - 0xd959, 0x3187, - 0xd95a, 0x20c4, - 0xd95b, 0x3c24, - 0xd95c, 0x6724, - 0xd95d, 0x1002, - 0xd95e, 0x24f4, - 0xd95f, 0x3c64, - 0xd960, 0x6436, - 0xd961, 0xdff4, - 0xd962, 0x6436, - 0xd963, 0x1002, - 0xd964, 0x2006, - 0xd965, 0x3d76, - 0xd966, 0xc161, - 0xd967, 0x6134, - 0xd968, 0x6135, - 0xd969, 0x5443, - 0xd96a, 0x0303, - 0xd96b, 0x6524, - 0xd96c, 0x00fb, - 0xd96d, 0x1002, - 0xd96e, 0x20d4, - 0xd96f, 0x3c24, - 0xd970, 0x2025, - 0xd971, 0x3005, - 0xd972, 0x6524, - 0xd973, 0x1002, - 0xd974, 0xd019, - 0xd975, 0x2104, - 0xd976, 0x3c24, - 0xd977, 0x2105, - 0xd978, 0x3805, - 0xd979, 0x6524, - 0xd97a, 0xdff4, - 0xd97b, 0x4005, - 0xd97c, 0x6524, - 0xd97d, 0x2e8d, - 0xd97e, 0x303d, - 0xd97f, 0x2408, - 0xd980, 0x35d8, - 0xd981, 0x5dd3, - 0xd982, 0x0307, - 0xd983, 0x8887, - 0xd984, 0x63a7, - 0xd985, 0x8887, - 0xd986, 0x63a7, - 0xd987, 0xdffd, - 0xd988, 0x00f9, - 0xd989, 0x1002, - 0xd98a, 0x0000, - }; int i, err; /* set uC clock and activate it */ @@ -1606,10 +581,16 @@ static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype) if (err) return err; - /* write TWINAX EDC firmware into PHY */ - for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2) - err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i], - twinax_edc[i + 1]); + if (phy->priv != edc_twinax) + err = t3_get_edc_fw(phy, EDC_TWX_AEL2020, + EDC_TWX_AEL2020_SIZE); + if (err) + return err; + + for (i = 0; i < EDC_TWX_AEL2020_SIZE / sizeof(u16) && !err; i += 2) + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, + phy->phy_cache[i], + phy->phy_cache[i + 1]); /* activate uC */ err = set_phy_regs(phy, uCactivate); if (!err) diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index d21b705501a..1b2c305fb82 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -566,6 +566,15 @@ struct cphy_ops { u32 mmds; }; +enum { + EDC_OPT_AEL2005 = 0, + EDC_OPT_AEL2005_SIZE = 1084, + EDC_TWX_AEL2005 = 1, + EDC_TWX_AEL2005_SIZE = 1464, + EDC_TWX_AEL2020 = 2, + EDC_TWX_AEL2020_SIZE = 1628, + EDC_MAX_SIZE = EDC_TWX_AEL2020_SIZE, /* Max cache size */ +}; /* A PHY instance */ struct cphy { @@ -577,6 +586,7 @@ struct cphy { unsigned long fifo_errors; /* FIFO over/under-flows */ const struct cphy_ops *ops; /* PHY operations */ struct mdio_if_info mdio; + u16 phy_cache[EDC_MAX_SIZE]; /* EDC cache */ }; /* Convenience MDIO read/write wrappers */ diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 538dda4422d..27e7ef592b5 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -964,6 +964,75 @@ static int bind_qsets(struct adapter *adap) #define FW_FNAME "cxgb3/t3fw-%d.%d.%d.bin" #define TPSRAM_NAME "cxgb3/t3%c_psram-%d.%d.%d.bin" +#define AEL2005_OPT_EDC_NAME "cxgb3/ael2005_opt_edc.bin" +#define AEL2005_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin" +#define AEL2020_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin" + +static inline const char *get_edc_fw_name(int edc_idx) +{ + const char *fw_name = NULL; + + switch (edc_idx) { + case EDC_OPT_AEL2005: + fw_name = AEL2005_OPT_EDC_NAME; + break; + case EDC_TWX_AEL2005: + fw_name = AEL2005_TWX_EDC_NAME; + break; + case EDC_TWX_AEL2020: + fw_name = AEL2020_TWX_EDC_NAME; + break; + } + return fw_name; +} + +int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size) +{ + struct adapter *adapter = phy->adapter; + const struct firmware *fw; + char buf[64]; + u32 csum; + const __be32 *p; + u16 *cache = phy->phy_cache; + int i, ret; + + snprintf(buf, sizeof(buf), get_edc_fw_name(edc_idx)); + + ret = request_firmware(&fw, buf, &adapter->pdev->dev); + if (ret < 0) { + dev_err(&adapter->pdev->dev, + "could not upgrade firmware: unable to load %s\n", + buf); + return ret; + } + + /* check size, take checksum in account */ + if (fw->size > size + 4) { + CH_ERR(adapter, "firmware image too large %u, expected %d\n", + (unsigned int)fw->size, size + 4); + ret = -EINVAL; + } + + /* compute checksum */ + p = (const __be32 *)fw->data; + for (csum = 0, i = 0; i < fw->size / sizeof(csum); i++) + csum += ntohl(p[i]); + + if (csum != 0xffffffff) { + CH_ERR(adapter, "corrupted firmware image, checksum %u\n", + csum); + ret = -EINVAL; + } + + for (i = 0; i < size / 4 ; i++) { + *cache++ = (be32_to_cpu(p[i]) & 0xffff0000) >> 16; + *cache++ = be32_to_cpu(p[i]) & 0xffff; + } + + release_firmware(fw); + + return ret; +} static int upgrade_fw(struct adapter *adap) { -- cgit v1.2.3-18-g5258 From dce7d1d031aeaa8c65bd37ff2480dc450a68185e Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 7 Jul 2009 19:48:59 +0000 Subject: cxgb3: Fix mss table initialization Fix the HW SMT table initialization to avoid random mss miscomputations for offload connections. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller --- drivers/net/cxgb3/cxgb3_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 27e7ef592b5..d4c4076cf08 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -443,6 +443,7 @@ static int init_tp_parity(struct adapter *adap) memset(req, 0, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i)); + req->mtu_idx = NMTUS - 1; req->iff = i; t3_mgmt_tx(adap, skb); if (skb == adap->nofail_skb) { -- cgit v1.2.3-18-g5258 From 88045b3cf0f8981129cb489c7b6bc36c21dd33a7 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 7 Jul 2009 19:49:04 +0000 Subject: cxgb3: fix mac index mapping Override the mac index computation for the gen2 adapter, as each port is expected to use index 0. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller --- drivers/net/cxgb3/t3_hw.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 870d44992c7..e78d341cbd6 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -3682,6 +3682,8 @@ static void mc7_prep(struct adapter *adapter, struct mc7 *mc7, void mac_prep(struct cmac *mac, struct adapter *adapter, int index) { mac->adapter = adapter; + if (!adapter->params.vpd.xauicfg[1]) + index = 0; mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index; mac->nucast = 1; -- cgit v1.2.3-18-g5258 From 34701fde8f4bf207ca96d10b8700a8667157854c Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 7 Jul 2009 19:48:32 +0000 Subject: cxgb3: Drain Mac Tx fifo when the port goes down. Drain the MAC TX fifos when a port goes down. Back pressure might otherwise occur, leading to both ports of the same adapter to hang. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller --- drivers/net/cxgb3/cxgb3_main.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index d4c4076cf08..8c381c696a3 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -172,6 +172,23 @@ static void link_report(struct net_device *dev) } } +static void enable_tx_fifo_drain(struct adapter *adapter, + struct port_info *pi) +{ + t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, 0, + F_ENDROPPKT); + t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, 0); + t3_write_reg(adapter, A_XGM_TX_CTRL + pi->mac.offset, F_TXEN); + t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, F_RXEN); +} + +static void disable_tx_fifo_drain(struct adapter *adapter, + struct port_info *pi) +{ + t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, + F_ENDROPPKT, 0); +} + void t3_os_link_fault(struct adapter *adap, int port_id, int state) { struct net_device *dev = adap->port[port_id]; @@ -185,6 +202,8 @@ void t3_os_link_fault(struct adapter *adap, int port_id, int state) netif_carrier_on(dev); + disable_tx_fifo_drain(adap, pi); + /* Clear local faults */ t3_xgm_intr_disable(adap, pi->port_id); t3_read_reg(adap, A_XGM_INT_STATUS + @@ -200,9 +219,12 @@ void t3_os_link_fault(struct adapter *adap, int port_id, int state) t3_xgm_intr_enable(adap, pi->port_id); t3_mac_enable(mac, MAC_DIRECTION_TX); - } else + } else { netif_carrier_off(dev); + /* Flush TX FIFO */ + enable_tx_fifo_drain(adap, pi); + } link_report(dev); } @@ -232,6 +254,8 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat, if (link_stat != netif_carrier_ok(dev)) { if (link_stat) { + disable_tx_fifo_drain(adapter, pi); + t3_mac_enable(mac, MAC_DIRECTION_RX); /* Clear local faults */ @@ -263,6 +287,9 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat, t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset); t3_mac_disable(mac, MAC_DIRECTION_RX); t3_link_start(&pi->phy, mac, &pi->link_config); + + /* Flush TX FIFO */ + enable_tx_fifo_drain(adapter, pi); } link_report(dev); -- cgit v1.2.3-18-g5258 From 012b7d339ce8c42d41e35b35c4acc3dd29501d52 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 9 Jul 2009 15:13:56 +0100 Subject: MMC: MMCI: use AMBA bus accessors Rather than open coding the accessors for decoding peripheral IDs, use the macros already provided. Signed-off-by: Russell King Acked-by: Linus Walleij --- drivers/mmc/host/mmci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index e1aa8471ab1..ac43f395eec 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -515,12 +515,12 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) host = mmc_priv(mmc); host->mmc = mmc; - /* Bits 12 thru 19 is the designer */ - host->hw_designer = (dev->periphid >> 12) & 0xff; - /* Bits 20 thru 23 is the revison */ - host->hw_revision = (dev->periphid >> 20) & 0xf; + + host->hw_designer = amba_manf(dev); + host->hw_revision = amba_rev(dev); DBG(host, "designer ID = 0x%02x\n", host->hw_designer); DBG(host, "revision = 0x%01x\n", host->hw_revision); + host->clk = clk_get(&dev->dev, NULL); if (IS_ERR(host->clk)) { ret = PTR_ERR(host->clk); -- cgit v1.2.3-18-g5258 From 89001446925d6da8785c3265a71316e34c6d15de Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 9 Jul 2009 15:16:07 +0100 Subject: MMC: MMCI: use gpiolib for card detect/write protect Use gpiolib where available (and when valid GPIOs are provided) for write protect/card detect status reporting. We fall back to the old 'status' method where gpiolib support is not available. Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++-- drivers/mmc/host/mmci.h | 2 ++ 2 files changed, 63 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index ac43f395eec..5eb86a8c943 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -472,17 +473,41 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } } +static int mmci_get_ro(struct mmc_host *mmc) +{ + struct mmci_host *host = mmc_priv(mmc); + + if (host->gpio_wp == -ENOSYS) + return -ENOSYS; + + return gpio_get_value(host->gpio_wp); +} + +static int mmci_get_cd(struct mmc_host *mmc) +{ + struct mmci_host *host = mmc_priv(mmc); + unsigned int status; + + if (host->gpio_cd == -ENOSYS) + status = host->plat->status(mmc_dev(host->mmc)); + else + status = gpio_get_value(host->gpio_cd); + + return !status; +} + static const struct mmc_host_ops mmci_ops = { .request = mmci_request, .set_ios = mmci_set_ios, + .get_ro = mmci_get_ro, + .get_cd = mmci_get_cd, }; static void mmci_check_status(unsigned long data) { struct mmci_host *host = (struct mmci_host *)data; - unsigned int status; + unsigned int status = mmci_get_cd(host->mmc); - status = host->plat->status(mmc_dev(host->mmc)); if (status ^ host->oldstat) mmc_detect_change(host->mmc, 0); @@ -516,6 +541,9 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) host = mmc_priv(mmc); host->mmc = mmc; + host->gpio_wp = -ENOSYS; + host->gpio_cd = -ENOSYS; + host->hw_designer = amba_manf(dev); host->hw_revision = amba_rev(dev); DBG(host, "designer ID = 0x%02x\n", host->hw_designer); @@ -591,6 +619,25 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) writel(0, host->base + MMCIMASK1); writel(0xfff, host->base + MMCICLEAR); + if (gpio_is_valid(plat->gpio_cd)) { + ret = gpio_request(plat->gpio_cd, DRIVER_NAME " (cd)"); + if (ret == 0) + ret = gpio_direction_input(plat->gpio_cd); + if (ret == 0) + host->gpio_cd = plat->gpio_cd; + else if (ret != -ENOSYS) + goto err_gpio_cd; + } + if (gpio_is_valid(plat->gpio_wp)) { + ret = gpio_request(plat->gpio_wp, DRIVER_NAME " (wp)"); + if (ret == 0) + ret = gpio_direction_input(plat->gpio_wp); + if (ret == 0) + host->gpio_wp = plat->gpio_wp; + else if (ret != -ENOSYS) + goto err_gpio_wp; + } + ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); if (ret) goto unmap; @@ -602,6 +649,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) writel(MCI_IRQENABLE, host->base + MMCIMASK0); amba_set_drvdata(dev, mmc); + host->oldstat = mmci_get_cd(host->mmc); mmc_add_host(mmc); @@ -620,6 +668,12 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) irq0_free: free_irq(dev->irq[0], host); unmap: + if (host->gpio_wp != -ENOSYS) + gpio_free(host->gpio_wp); + err_gpio_wp: + if (host->gpio_cd != -ENOSYS) + gpio_free(host->gpio_cd); + err_gpio_cd: iounmap(host->base); clk_disable: clk_disable(host->clk); @@ -655,6 +709,11 @@ static int __devexit mmci_remove(struct amba_device *dev) free_irq(dev->irq[0], host); free_irq(dev->irq[1], host); + if (host->gpio_wp != -ENOSYS) + gpio_free(host->gpio_wp); + if (host->gpio_cd != -ENOSYS) + gpio_free(host->gpio_cd); + iounmap(host->base); clk_disable(host->clk); clk_put(host->clk); diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 0441bac1c0e..839f264c972 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -151,6 +151,8 @@ struct mmci_host { struct mmc_data *data; struct mmc_host *mmc; struct clk *clk; + int gpio_cd; + int gpio_wp; unsigned int data_xfered; -- cgit v1.2.3-18-g5258 From 583ddafe1787528d08b0026bb3273490a499b730 Mon Sep 17 00:00:00 2001 From: Hartley Sweeten Date: Mon, 6 Jul 2009 17:39:50 +0100 Subject: [ARM] 5592/1: ep93xx: cleanup platform header includes arch/arm/mach-ep93xx/include/mach/hardware.h 1. Properly name the include files so that they are loaded from the directory and not the local directory. 2. Remove including the ts72xx.h header. This header is not generic to the ep93xx platform. It should only be included by the ts72xx specific files that require it. The only two users in the tree are arch/arm/mach-ep93xx/ts72xx.c and drivers/mtd/nand/ts7250.c. arch/arm/mach-ep93xx/include/mach/ts72xx.h 1. should already be included by any user of this header. Doing the include here hides it from being needed by the calling source file. arch/arm/mach-ep93xx/core.c 1. Remove unnecessary headers. They were probably included originally due to cut-and-paste from other files. 2. should be included not arch/arm/mach-ep93xx/adsphere.c arch/arm/mach-ep93xx/edb93xx.c arch/arm/mach-ep93xx/gesbc9312.c arch/arm/mach-ep93xx/micro9.c arch/arm/mach-ep93xx/ts72xx.c 1. Remove unnecessary headers. arch/arm/mach-ep93xx/ts72xx.c 1. Remove unnecessary headers. 2. Add platform specific header . drivers/mtd/nand/ts7250.c 1. should be included not . 2. Add platform specific header . Cc: Ryan Mallon Signed-off-by: H Hartley Sweeten Signed-off-by: Russell King --- drivers/mtd/nand/ts7250.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/ts7250.c b/drivers/mtd/nand/ts7250.c index 2c410a01131..0f5562aeedc 100644 --- a/drivers/mtd/nand/ts7250.c +++ b/drivers/mtd/nand/ts7250.c @@ -24,8 +24,11 @@ #include #include #include -#include +#include + #include +#include + #include #include -- cgit v1.2.3-18-g5258 From e36d56b64808aec54b68b4e9976180c1da0933b2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 9 Jun 2009 21:04:43 +0200 Subject: cfg80211: pass netdev to change_virtual_intf If there was a reason I'm passing the ifidx I cannot remember it any more and don't see one now, so let's just pass the pointer itself. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 9 ++------- drivers/net/wireless/rndis_wlan.c | 15 +++++---------- 2 files changed, 7 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 96f714e6e12..bc89b1ef0ca 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -167,20 +167,15 @@ int iwm_cfg80211_inform_bss(struct iwm_priv *iwm) return 0; } -static int iwm_cfg80211_change_iface(struct wiphy *wiphy, int ifindex, +static int iwm_cfg80211_change_iface(struct wiphy *wiphy, + struct net_device *ndev, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { - struct net_device *ndev; struct wireless_dev *wdev; struct iwm_priv *iwm; u32 old_mode; - /* we're under RTNL */ - ndev = __dev_get_by_index(&init_net, ifindex); - if (!ndev) - return -ENODEV; - wdev = ndev->ieee80211_ptr; iwm = ndev_to_iwm(ndev); old_mode = iwm->conf.mode; diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 3bec3dbd345..e8b0793b030 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -420,7 +420,8 @@ struct rndis_wlan_private { /* * cfg80211 ops */ -static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex, +static int rndis_change_virtual_intf(struct wiphy *wiphy, + struct net_device *dev, enum nl80211_iftype type, u32 *flags, struct vif_params *params); @@ -1222,20 +1223,14 @@ static void set_multicast_list(struct usbnet *usbdev) /* * cfg80211 ops */ -static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex, +static int rndis_change_virtual_intf(struct wiphy *wiphy, + struct net_device *dev, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { - struct net_device *dev; - struct usbnet *usbdev; + struct usbnet *usbdev = netdev_priv(dev); int mode; - /* we're under RTNL */ - dev = __dev_get_by_index(&init_net, ifindex); - if (!dev) - return -ENODEV; - usbdev = netdev_priv(dev); - switch (type) { case NL80211_IFTYPE_ADHOC: mode = NDIS_80211_INFRA_ADHOC; -- cgit v1.2.3-18-g5258 From 089e698d235162324142063c96780aeacd546d36 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 10 Jun 2009 17:50:07 +0530 Subject: ath9k: Nuke unneccesary helper function to see if aggr is active IEEE80211_TX_CTL_AMPDU in tx control flags should be enough to confirm BA is negotiated for that tid. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 4ccf48e396d..aca3526b6c6 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -73,18 +73,6 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, /* Aggregation logic */ /*********************/ -static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno) -{ - struct ath_atx_tid *tid; - tid = ATH_AN_2_TID(an, tidno); - - if (tid->state & AGGR_ADDBA_COMPLETE || - tid->state & AGGR_ADDBA_PROGRESS) - return 1; - else - return 0; -} - static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid) { struct ath_atx_ac *ac = tid->ac; @@ -1636,7 +1624,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, goto tx_done; } - if (ath_aggr_query(sc, an, bf->bf_tidno)) { + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { /* * Try aggregation if it's a unicast data frame * and the destination is HT capable. -- cgit v1.2.3-18-g5258 From c3d8f02ed9699252d69a9a14276980d9df7c5fe1 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 10 Jun 2009 17:50:08 +0530 Subject: ath9k: Remove unnecessary count for addba attempt mac80211 already has one to keep track of number of failure addba attempts. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/xmit.c | 13 +------------ 2 files changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 5efc9345ca0..747e046b03b 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -272,7 +272,6 @@ struct ath_atx_tid { int sched; int paused; u8 state; - int addba_exchangeattempts; }; struct ath_atx_ac { diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index aca3526b6c6..e08c8174d65 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -402,7 +402,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, if (tid->state & AGGR_CLEANUP) { if (tid->baw_head == tid->baw_tail) { tid->state &= ~AGGR_ADDBA_COMPLETE; - tid->addba_exchangeattempts = 0; tid->state &= ~AGGR_CLEANUP; /* send buffered frames as singles */ @@ -707,7 +706,6 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { txtid->state &= ~AGGR_ADDBA_PROGRESS; - txtid->addba_exchangeattempts = 0; return 0; } @@ -735,7 +733,6 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) txtid->state |= AGGR_CLEANUP; } else { txtid->state &= ~AGGR_ADDBA_COMPLETE; - txtid->addba_exchangeattempts = 0; ath_tx_flush_tid(sc, txtid); } @@ -768,14 +765,8 @@ bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno) txtid = ATH_AN_2_TID(an, tidno); - if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { - if (!(txtid->state & AGGR_ADDBA_PROGRESS) && - (txtid->addba_exchangeattempts < ADDBA_EXCHANGE_ATTEMPTS)) { - txtid->addba_exchangeattempts++; + if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS))) return true; - } - } - return false; } @@ -2110,7 +2101,6 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) tid->ac = &an->ac[acno]; tid->state &= ~AGGR_ADDBA_COMPLETE; tid->state &= ~AGGR_ADDBA_PROGRESS; - tid->addba_exchangeattempts = 0; } for (acno = 0, ac = &an->ac[acno]; @@ -2167,7 +2157,6 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) tid->sched = false; ath_tid_drain(sc, txq, tid); tid->state &= ~AGGR_ADDBA_COMPLETE; - tid->addba_exchangeattempts = 0; tid->state &= ~AGGR_CLEANUP; } } -- cgit v1.2.3-18-g5258 From 8a46097a6c60dc9d2f09bf01734f3308142614b3 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 10 Jun 2009 17:50:09 +0530 Subject: ath9k: downgrade ASSERT() in ath_clone_txbuf() We can easily run out of tx buf if there is any stuck in transmission, so downgrade it to WARN_ON(). Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index e08c8174d65..5de9878d2c1 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -238,6 +238,10 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) struct ath_buf *tbf; spin_lock_bh(&sc->tx.txbuflock); + if (WARN_ON(list_empty(&sc->tx.txbuf))) { + spin_unlock_bh(&sc->tx.txbuflock); + return NULL; + } ASSERT(!list_empty((&sc->tx.txbuf))); tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); list_del(&tbf->list); @@ -379,6 +383,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *tbf; tbf = ath_clone_txbuf(sc, bf_last); + if (!tbf) + break; ath9k_hw_cleartxdesc(sc->sc_ah, tbf->bf_desc); list_add_tail(&tbf->list, &bf_head); } else { -- cgit v1.2.3-18-g5258 From 46026e8f487c075f9ec4d671348e351eb5e46d3e Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 10 Jun 2009 22:22:20 -0400 Subject: ath5k: cleanup ath5k_hw struct ah_gpios array isn't used, and ah_current_channel can be a pointer instead of an embedded struct. Removing these and some other write-only variables, and moving some things around for better packing and cache utilization saves 116 bytes. text data bss dec hex filename 121762 472 64 122298 1ddba ath5k_before.ko 121646 472 64 122182 1dd46 ath5k.ko Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 21 +++++++-------------- drivers/net/wireless/ath/ath5k/phy.c | 7 +++---- drivers/net/wireless/ath/ath5k/reset.c | 1 - 3 files changed, 10 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 6358233bac9..91375113916 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -713,8 +713,8 @@ struct ath5k_gain { * Used internaly for reset_tx_queue). * Also see struct struct ieee80211_channel. */ -#define IS_CHAN_XR(_c) ((_c.hw_value & CHANNEL_XR) != 0) -#define IS_CHAN_B(_c) ((_c.hw_value & CHANNEL_B) != 0) +#define IS_CHAN_XR(_c) ((_c->hw_value & CHANNEL_XR) != 0) +#define IS_CHAN_B(_c) ((_c->hw_value & CHANNEL_B) != 0) /* * The following structure is used to map 2GHz channels to @@ -1029,14 +1029,15 @@ struct ath5k_hw { enum ath5k_int ah_imr; enum nl80211_iftype ah_op_mode; - enum ath5k_power_mode ah_power_mode; - struct ieee80211_channel ah_current_channel; + struct ieee80211_channel *ah_current_channel; bool ah_turbo; bool ah_calibration; - bool ah_running; bool ah_single_chip; bool ah_combined_mic; + enum ath5k_version ah_version; + enum ath5k_radio ah_radio; + u32 ah_phy; u32 ah_mac_srev; u16 ah_mac_version; u16 ah_mac_revision; @@ -1044,13 +1045,6 @@ struct ath5k_hw { u16 ah_radio_5ghz_revision; u16 ah_radio_2ghz_revision; - enum ath5k_version ah_version; - enum ath5k_radio ah_radio; - u32 ah_phy; - - bool ah_5ghz; - bool ah_2ghz; - #define ah_modes ah_capabilities.cap_mode #define ah_ee_version ah_capabilities.cap_eeprom.ee_version @@ -1058,7 +1052,6 @@ struct ath5k_hw { u32 ah_aifs; u32 ah_cw_min; u32 ah_cw_max; - bool ah_software_retry; u32 ah_limit_tx_retries; /* Antenna Control */ @@ -1066,6 +1059,7 @@ struct ath5k_hw { u8 ah_ant_mode; u8 ah_tx_ant; u8 ah_def_ant; + bool ah_software_retry; u8 ah_sta_id[ETH_ALEN]; @@ -1075,7 +1069,6 @@ struct ath5k_hw { u8 ah_bssid[ETH_ALEN]; u8 ah_bssid_mask[ETH_ALEN]; - u32 ah_gpio[AR5K_MAX_GPIO]; int ah_gpio_npins; struct ath_regulatory ah_regulatory; diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index a876ca8d69e..2075ba99396 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1085,8 +1085,7 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) AR5K_PHY_CCKTXCTL_WORLD); } - ah->ah_current_channel.center_freq = channel->center_freq; - ah->ah_current_channel.hw_value = channel->hw_value; + ah->ah_current_channel = channel; ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false; return 0; @@ -1731,7 +1730,7 @@ ath5k_hw_set_fast_div(struct ath5k_hw *ah, u8 ee_mode, bool enable) void ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode) { - struct ieee80211_channel *channel = &ah->ah_current_channel; + struct ieee80211_channel *channel = ah->ah_current_channel; bool use_def_for_tx, update_def_on_tx, use_def_for_rts, fast_div; bool use_def_for_sg; u8 def_ant, tx_ant, ee_mode; @@ -3011,7 +3010,7 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower) { /*Just a try M.F.*/ - struct ieee80211_channel *channel = &ah->ah_current_channel; + struct ieee80211_channel *channel = ah->ah_current_channel; u8 ee_mode; ATH5K_TRACE(ah->ah_sc); diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index bd0a97a38d3..86733fdb477 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -290,7 +290,6 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, } commit: - ah->ah_power_mode = mode; ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1); return 0; -- cgit v1.2.3-18-g5258 From f0f3d388baabdbc613548d6ad8e5da7616b1cbd1 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 10 Jun 2009 22:22:21 -0400 Subject: ath5k: enable hardware LEDs Cardbus and some PCI cards use hardware LEDs rather than software GPIOs. Program them with the proper blink patterns when idle, scanning or associated. Fixes http://bugzilla.kernel.org/show_bug.cgi?id=13288. Tested-by: Frans Pop Tested-by: Mark Hindley Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/attach.c | 3 +++ drivers/net/wireless/ath/ath5k/base.c | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index c41ef58393e..9a84d9410b2 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -319,6 +319,9 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) ath5k_hw_rfgain_opt_init(ah); + /* turn on HW LEDs */ + ath5k_hw_set_ledstate(ah, AR5K_LED_INIT); + return ah; err_free: kfree(ah); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index ea045151f95..f26a6896062 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -248,6 +248,8 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changes); +static void ath5k_sw_scan_start(struct ieee80211_hw *hw); +static void ath5k_sw_scan_complete(struct ieee80211_hw *hw); static const struct ieee80211_ops ath5k_hw_ops = { .tx = ath5k_tx, @@ -265,6 +267,8 @@ static const struct ieee80211_ops ath5k_hw_ops = { .set_tsf = ath5k_set_tsf, .reset_tsf = ath5k_reset_tsf, .bss_info_changed = ath5k_bss_info_changed, + .sw_scan_start = ath5k_sw_scan_start, + .sw_scan_complete = ath5k_sw_scan_complete, }; /* @@ -3167,6 +3171,8 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, sc->assoc = bss_conf->assoc; if (sc->opmode == NL80211_IFTYPE_STATION) set_beacon_filter(hw, sc->assoc); + ath5k_hw_set_ledstate(sc->ah, sc->assoc ? + AR5K_LED_ASSOC : AR5K_LED_INIT); } if (changes & BSS_CHANGED_BEACON && @@ -3179,3 +3185,17 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, unlock: mutex_unlock(&sc->lock); } + +static void ath5k_sw_scan_start(struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + if (!sc->assoc) + ath5k_hw_set_ledstate(sc->ah, AR5K_LED_SCAN); +} + +static void ath5k_sw_scan_complete(struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + ath5k_hw_set_ledstate(sc->ah, sc->assoc ? + AR5K_LED_ASSOC : AR5K_LED_INIT); +} -- cgit v1.2.3-18-g5258 From e0d6133cba88759bc760b254c27975330fff6519 Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Tue, 16 Jun 2009 13:20:01 -0700 Subject: libertas: remove ps_supported flag, use fwcapinfo Power save support depends on the firmware capabilities rather than the card's hardware interface. Use the FW_CAPINFO_PS bit in the firmware capabilities mask throughout the driver in place of the redundant ps_supported flag and don't make decisions about PS support in the interface drivers (with the exception of a special case in the USB driver). V2: put the USB special case in the right place. Signed-off-by: Andrey Yurovsky Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/if_cs.c | 3 --- drivers/net/wireless/libertas/if_sdio.c | 3 --- drivers/net/wireless/libertas/if_spi.c | 1 - drivers/net/wireless/libertas/if_usb.c | 3 ++- drivers/net/wireless/libertas/wext.c | 2 +- 6 files changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index f9ec69e0473..578c6978358 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -260,7 +260,6 @@ struct lbs_private { u16 psmode; /* Wlan802_11PowermodeCAM=disable Wlan802_11PowermodeMAX_PSP=enable */ u32 psstate; - char ps_supported; u8 needtowakeup; struct assoc_request * pending_assoc_req; diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 2a5b083bf9b..f658fd6a2c0 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -933,9 +933,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev) goto out3; } - /* The firmware for the CF card supports powersave */ - priv->ps_supported = 1; - ret = 0; goto out; diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 8cdb88c6ca2..89396a78862 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -1039,9 +1039,6 @@ static int if_sdio_probe(struct sdio_func *func, if (ret) goto err_activate_card; - if (priv->fwcapinfo & FW_CAPINFO_PS) - priv->ps_supported = 1; - out: lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 6564282ce47..b213de437ae 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -1118,7 +1118,6 @@ static int __devinit if_spi_probe(struct spi_device *spi) priv->card = card; priv->hw_host_to_card = if_spi_host_to_card; priv->fw_ready = 1; - priv->ps_supported = 1; /* Initialize interrupt handling stuff. */ card->run_thread = 1; diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 1844c5adf6e..92bc8c5f1ca 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -181,13 +181,14 @@ static void if_usb_setup_firmware(struct lbs_private *priv) wake_method.action = cpu_to_le16(CMD_ACT_GET); if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) { lbs_pr_info("Firmware does not seem to support PS mode\n"); + priv->fwcapinfo &= ~FW_CAPINFO_PS; } else { if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) { lbs_deb_usb("Firmware seems to support PS with wake-via-command\n"); - priv->ps_supported = 1; } else { /* The versions which boot up this way don't seem to work even if we set it to the command interrupt */ + priv->fwcapinfo &= ~FW_CAPINFO_PS; lbs_pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n"); } } diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 8bc1907458b..e96451ce470 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -712,7 +712,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (!priv->ps_supported) { + if (!(priv->fwcapinfo & FW_CAPINFO_PS)) { if (vwrq->disabled) return 0; else -- cgit v1.2.3-18-g5258 From c4f9f16b309b65f9f578ec4ba78b3efa106cf65d Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 12 Jun 2009 10:55:55 +0530 Subject: ath9k: Make sure we configure a non-zero beacon interval This patch moves the sanity check on beacon interval which was done only for mesh mode to all operating modes just to be safe. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/beacon.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 3639a2e6987..45c4ea57616 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -674,13 +674,6 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; - /* - * It looks like mac80211 may end up using beacon interval of zero in - * some cases (at least for mesh point). Avoid getting into an - * infinite loop by using a bit safer value instead.. - */ - if (intval == 0) - intval = 100; /* Pull nexttbtt forward to reflect the current TSF */ @@ -745,6 +738,14 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) iftype = sc->sc_ah->opmode; } + /* + * It looks like mac80211 may end up using beacon interval of zero in + * some cases (at least for mesh point). Avoid getting into an + * infinite loop by using a bit safer value instead. To be safe, + * do sanity check on beacon interval for all operating modes. + */ + if (cur_conf->beacon_interval == 0) + cur_conf->beacon_interval = 100; switch (iftype) { case NL80211_IFTYPE_AP: -- cgit v1.2.3-18-g5258 From ff25839bf0c99e828c26864a24417a36a6b6a31e Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:14:19 +0300 Subject: wl12xx: cmd and acx interface rework Rework cmd and acx interfaces, it was just too confusing earlier. Now all commands need to contain all the needed headers, either just cmd headers or both cmd and acx headers. This accomplish to remove the extra copy done for each command. The interfaces are now properly documented as well. Also try to make all commands safe for DMA transfers. I might have missed some, but most of them should be fixed now. And this is not all! As a free bonus you will also get some cosmetic cleanups and code reorganisation. Order today! Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/acx.c | 690 +++++++++++++++++++++-------------- drivers/net/wireless/wl12xx/acx.h | 126 +------ drivers/net/wireless/wl12xx/cmd.c | 311 ++++++++++------ drivers/net/wireless/wl12xx/cmd.h | 168 ++++++++- drivers/net/wireless/wl12xx/main.c | 87 +++-- drivers/net/wireless/wl12xx/ps.c | 2 +- drivers/net/wireless/wl12xx/ps.h | 2 +- drivers/net/wireless/wl12xx/rx.c | 27 +- drivers/net/wireless/wl12xx/wl1251.c | 74 ++-- 9 files changed, 896 insertions(+), 591 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index 1cfd458ad5a..d0daf69558f 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -13,126 +13,160 @@ int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, u8 mgt_rate, u8 mgt_mod) { + struct acx_fw_gen_frame_rates *rates; int ret; - struct acx_fw_gen_frame_rates rates; wl12xx_debug(DEBUG_ACX, "acx frame rates"); - rates.header.id = ACX_FW_GEN_FRAME_RATES; - rates.header.len = sizeof(struct acx_fw_gen_frame_rates) - - sizeof(struct acx_header); + rates = kzalloc(sizeof(*rates), GFP_KERNEL); + if (!rates) { + ret = -ENOMEM; + goto out; + } - rates.tx_ctrl_frame_rate = ctrl_rate; - rates.tx_ctrl_frame_mod = ctrl_mod; - rates.tx_mgt_frame_rate = mgt_rate; - rates.tx_mgt_frame_mod = mgt_mod; + rates->tx_ctrl_frame_rate = ctrl_rate; + rates->tx_ctrl_frame_mod = ctrl_mod; + rates->tx_mgt_frame_rate = mgt_rate; + rates->tx_mgt_frame_mod = mgt_mod; - ret = wl12xx_cmd_configure(wl, &rates, sizeof(rates)); + ret = wl12xx_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES, + rates, sizeof(*rates)); if (ret < 0) { wl12xx_error("Failed to set FW rates and modulation"); - return ret; + goto out; } - return 0; +out: + kfree(rates); + return ret; } int wl12xx_acx_station_id(struct wl12xx *wl) { + struct acx_dot11_station_id *mac; int ret, i; - struct dot11_station_id mac; wl12xx_debug(DEBUG_ACX, "acx dot11_station_id"); - mac.header.id = DOT11_STATION_ID; - mac.header.len = sizeof(mac) - sizeof(struct acx_header); + mac = kzalloc(sizeof(*mac), GFP_KERNEL); + if (!mac) { + ret = -ENOMEM; + goto out; + } for (i = 0; i < ETH_ALEN; i++) - mac.mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; + mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; - ret = wl12xx_cmd_configure(wl, &mac, sizeof(mac)); + ret = wl12xx_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac)); if (ret < 0) - return ret; + goto out; - return 0; +out: + kfree(mac); + return ret; } int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id) { - struct acx_dot11_default_key default_key; + struct acx_dot11_default_key *default_key; int ret; wl12xx_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id); - default_key.header.id = DOT11_DEFAULT_KEY; - default_key.header.len = sizeof(default_key) - - sizeof(struct acx_header); + default_key = kzalloc(sizeof(*default_key), GFP_KERNEL); + if (!default_key) { + ret = -ENOMEM; + goto out; + } - default_key.id = key_id; + default_key->id = key_id; - ret = wl12xx_cmd_configure(wl, &default_key, sizeof(default_key)); + ret = wl12xx_cmd_configure(wl, DOT11_DEFAULT_KEY, + default_key, sizeof(*default_key)); if (ret < 0) { wl12xx_error("Couldnt set default key"); - return ret; + goto out; } wl->default_key = key_id; - return 0; +out: + kfree(default_key); + return ret; } int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval) { - struct acx_wake_up_condition wake_up; + struct acx_wake_up_condition *wake_up; + int ret; wl12xx_debug(DEBUG_ACX, "acx wake up conditions"); - wake_up.header.id = ACX_WAKE_UP_CONDITIONS; - wake_up.header.len = sizeof(wake_up) - sizeof(struct acx_header); + wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); + if (!wake_up) { + ret = -ENOMEM; + goto out; + } - wake_up.wake_up_event = WAKE_UP_EVENT_DTIM_BITMAP; - wake_up.listen_interval = listen_interval; + wake_up->wake_up_event = WAKE_UP_EVENT_DTIM_BITMAP; + wake_up->listen_interval = listen_interval; - return wl12xx_cmd_configure(wl, &wake_up, sizeof(wake_up)); + ret = wl12xx_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, + wake_up, sizeof(*wake_up)); + if (ret < 0) { + wl12xx_warning("could not set wake up conditions: %d", ret); + goto out; + } + +out: + kfree(wake_up); + return ret; } int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth) { + struct acx_sleep_auth *auth; int ret; - struct acx_sleep_auth auth; wl12xx_debug(DEBUG_ACX, "acx sleep auth"); - auth.header.id = ACX_SLEEP_AUTH; - auth.header.len = sizeof(auth) - sizeof(struct acx_header); + auth = kzalloc(sizeof(*auth), GFP_KERNEL); + if (!auth) { + ret = -ENOMEM; + goto out; + } - auth.sleep_auth = sleep_auth; + auth->sleep_auth = sleep_auth; - ret = wl12xx_cmd_configure(wl, &auth, sizeof(auth)); + ret = wl12xx_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); if (ret < 0) return ret; - return 0; +out: + kfree(auth); + return ret; } int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len) { - struct wl12xx_command cmd; struct acx_revision *rev; int ret; wl12xx_debug(DEBUG_ACX, "acx fw rev"); - memset(&cmd, 0, sizeof(cmd)); + rev = kzalloc(sizeof(*rev), GFP_KERNEL); + if (!rev) { + ret = -ENOMEM; + goto out; + } - ret = wl12xx_cmd_interrogate(wl, ACX_FW_REV, sizeof(*rev), &cmd); + ret = wl12xx_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); if (ret < 0) { wl12xx_warning("ACX_FW_REV interrogate failed"); - return ret; + goto out; } - rev = (struct acx_revision *) &cmd.parameters; - /* be careful with the buffer sizes */ strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); @@ -143,12 +177,14 @@ int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len) */ buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; - return 0; +out: + kfree(rev); + return ret; } int wl12xx_acx_tx_power(struct wl12xx *wl, int power) { - struct acx_current_tx_power ie; + struct acx_current_tx_power *acx; int ret; wl12xx_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); @@ -156,534 +192,648 @@ int wl12xx_acx_tx_power(struct wl12xx *wl, int power) if (power < 0 || power > 25) return -EINVAL; - memset(&ie, 0, sizeof(ie)); + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } - ie.header.id = DOT11_CUR_TX_PWR; - ie.header.len = sizeof(ie) - sizeof(struct acx_header); - ie.current_tx_power = power * 10; + acx->current_tx_power = power * 10; - ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie)); + ret = wl12xx_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); if (ret < 0) { wl12xx_warning("configure of tx power failed: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(acx); + return ret; } int wl12xx_acx_feature_cfg(struct wl12xx *wl) { - struct acx_feature_config feature; + struct acx_feature_config *feature; int ret; wl12xx_debug(DEBUG_ACX, "acx feature cfg"); - memset(&feature, 0, sizeof(feature)); - - feature.header.id = ACX_FEATURE_CFG; - feature.header.len = sizeof(feature) - sizeof(struct acx_header); + feature = kzalloc(sizeof(*feature), GFP_KERNEL); + if (!feature) { + ret = -ENOMEM; + goto out; + } /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ - feature.data_flow_options = 0; - feature.options = 0; + feature->data_flow_options = 0; + feature->options = 0; - ret = wl12xx_cmd_configure(wl, &feature, sizeof(feature)); - if (ret < 0) + ret = wl12xx_cmd_configure(wl, ACX_FEATURE_CFG, + feature, sizeof(*feature)); + if (ret < 0) { wl12xx_error("Couldnt set HW encryption"); + goto out; + } +out: + kfree(feature); return ret; } -int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len) +int wl12xx_acx_mem_map(struct wl12xx *wl, struct acx_header *mem_map, + size_t len) { - struct wl12xx_command cmd; int ret; wl12xx_debug(DEBUG_ACX, "acx mem map"); - ret = wl12xx_cmd_interrogate(wl, ACX_MEM_MAP, len, &cmd); + ret = wl12xx_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); if (ret < 0) return ret; - else if (cmd.status != CMD_STATUS_SUCCESS) - return -EIO; - - memcpy(mem_map, &cmd.parameters, len); return 0; } int wl12xx_acx_data_path_params(struct wl12xx *wl, - struct acx_data_path_params_resp *data_path) + struct acx_data_path_params_resp *resp) { - struct acx_data_path_params params; - struct wl12xx_command cmd; + struct acx_data_path_params *params; int ret; wl12xx_debug(DEBUG_ACX, "acx data path params"); - params.rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE; - params.tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE; + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) { + ret = -ENOMEM; + goto out; + } - params.rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM; - params.tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM; + params->rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE; + params->tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE; - params.tx_complete_threshold = 1; + params->rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM; + params->tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM; - params.tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE; + params->tx_complete_threshold = 1; - params.tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT; + params->tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE; - params.header.id = ACX_DATA_PATH_PARAMS; - params.header.len = sizeof(params) - sizeof(struct acx_header); + params->tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT; - ret = wl12xx_cmd_configure(wl, ¶ms, sizeof(params)); + ret = wl12xx_cmd_configure(wl, ACX_DATA_PATH_PARAMS, + params, sizeof(*params)); if (ret < 0) - return ret; - + goto out; + /* FIXME: shouldn't this be ACX_DATA_PATH_RESP_PARAMS? */ ret = wl12xx_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS, - sizeof(struct acx_data_path_params_resp), - &cmd); + resp, sizeof(*resp)); if (ret < 0) { wl12xx_warning("failed to read data path parameters: %d", ret); - return ret; - } else if (cmd.status != CMD_STATUS_SUCCESS) { + goto out; + } else if (resp->header.cmd.status != CMD_STATUS_SUCCESS) { wl12xx_warning("data path parameter acx status failed"); - return -EIO; + ret = -EIO; + goto out; } - memcpy(data_path, &cmd.parameters, sizeof(*data_path)); - - return 0; +out: + kfree(params); + return ret; } int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time) { - struct rx_msdu_lifetime msdu_lifetime; + struct acx_rx_msdu_lifetime *acx; int ret; wl12xx_debug(DEBUG_ACX, "acx rx msdu life time"); - msdu_lifetime.header.id = DOT11_RX_MSDU_LIFE_TIME; - msdu_lifetime.header.len = sizeof(msdu_lifetime) - - sizeof(struct acx_header); - msdu_lifetime.lifetime = life_time; + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } - ret = wl12xx_cmd_configure(wl, &msdu_lifetime, sizeof(msdu_lifetime)); + ret = wl12xx_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, + acx, sizeof(*acx)); if (ret < 0) { wl12xx_warning("failed to set rx msdu life time: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(acx); + return ret; } int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter) { - struct acx_rx_config rx_config; + struct acx_rx_config *rx_config; int ret; wl12xx_debug(DEBUG_ACX, "acx rx config"); - rx_config.header.id = ACX_RX_CFG; - rx_config.header.len = sizeof(rx_config) - sizeof(struct acx_header); - rx_config.config_options = config; - rx_config.filter_options = filter; + rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); + if (!rx_config) { + ret = -ENOMEM; + goto out; + } + + rx_config->config_options = config; + rx_config->filter_options = filter; - ret = wl12xx_cmd_configure(wl, &rx_config, sizeof(rx_config)); + ret = wl12xx_cmd_configure(wl, ACX_RX_CFG, + rx_config, sizeof(*rx_config)); if (ret < 0) { wl12xx_warning("failed to set rx config: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(rx_config); + return ret; } int wl12xx_acx_pd_threshold(struct wl12xx *wl) { - struct acx_packet_detection packet_detection; + struct acx_packet_detection *pd; int ret; wl12xx_debug(DEBUG_ACX, "acx data pd threshold"); + pd = kzalloc(sizeof(*pd), GFP_KERNEL); + if (!pd) { + ret = -ENOMEM; + goto out; + } + /* FIXME: threshold value not set */ - packet_detection.header.id = ACX_PD_THRESHOLD; - packet_detection.header.len = sizeof(packet_detection) - - sizeof(struct acx_header); - ret = wl12xx_cmd_configure(wl, &packet_detection, - sizeof(packet_detection)); + ret = wl12xx_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); if (ret < 0) { wl12xx_warning("failed to set pd threshold: %d", ret); - return ret; + goto out; } +out: + kfree(pd); return 0; } int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time) { - struct acx_slot slot; + struct acx_slot *slot; int ret; wl12xx_debug(DEBUG_ACX, "acx slot"); - slot.header.id = ACX_SLOT; - slot.header.len = sizeof(slot) - sizeof(struct acx_header); + slot = kzalloc(sizeof(*slot), GFP_KERNEL); + if (!slot) { + ret = -ENOMEM; + goto out; + } - slot.wone_index = STATION_WONE_INDEX; - slot.slot_time = slot_time; + slot->wone_index = STATION_WONE_INDEX; + slot->slot_time = slot_time; - ret = wl12xx_cmd_configure(wl, &slot, sizeof(slot)); + ret = wl12xx_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); if (ret < 0) { wl12xx_warning("failed to set slot time: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(slot); + return ret; } int wl12xx_acx_group_address_tbl(struct wl12xx *wl) { - struct multicast_grp_addr_start multicast; + struct acx_dot11_grp_addr_tbl *acx; int ret; wl12xx_debug(DEBUG_ACX, "acx group address tbl"); - /* MAC filtering */ - multicast.header.id = DOT11_GROUP_ADDRESS_TBL; - multicast.header.len = sizeof(multicast) - sizeof(struct acx_header); + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } - multicast.enabled = 0; - multicast.num_groups = 0; - memset(multicast.mac_table, 0, ADDRESS_GROUP_MAX_LEN); + /* MAC filtering */ + acx->enabled = 0; + acx->num_groups = 0; + memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); - ret = wl12xx_cmd_configure(wl, &multicast, sizeof(multicast)); + ret = wl12xx_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, + acx, sizeof(*acx)); if (ret < 0) { wl12xx_warning("failed to set group addr table: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(acx); + return ret; } int wl12xx_acx_service_period_timeout(struct wl12xx *wl) { - struct acx_rx_timeout rx_timeout; + struct acx_rx_timeout *rx_timeout; int ret; - wl12xx_debug(DEBUG_ACX, "acx service period timeout"); + rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); + if (!rx_timeout) { + ret = -ENOMEM; + goto out; + } - /* RX timeout */ - rx_timeout.header.id = ACX_SERVICE_PERIOD_TIMEOUT; - rx_timeout.header.len = sizeof(rx_timeout) - sizeof(struct acx_header); + wl12xx_debug(DEBUG_ACX, "acx service period timeout"); - rx_timeout.ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; - rx_timeout.upsd_timeout = RX_TIMEOUT_UPSD_DEF; + rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; + rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF; - ret = wl12xx_cmd_configure(wl, &rx_timeout, sizeof(rx_timeout)); + ret = wl12xx_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, + rx_timeout, sizeof(*rx_timeout)); if (ret < 0) { wl12xx_warning("failed to set service period timeout: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(rx_timeout); + return ret; } int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold) { - struct acx_rts_threshold rts; + struct acx_rts_threshold *rts; int ret; wl12xx_debug(DEBUG_ACX, "acx rts threshold"); - rts.header.id = DOT11_RTS_THRESHOLD; - rts.header.len = sizeof(rts) - sizeof(struct acx_header); + rts = kzalloc(sizeof(*rts), GFP_KERNEL); + if (!rts) { + ret = -ENOMEM; + goto out; + } - rts.threshold = rts_threshold; + rts->threshold = rts_threshold; - ret = wl12xx_cmd_configure(wl, &rts, sizeof(rts)); + ret = wl12xx_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); if (ret < 0) { wl12xx_warning("failed to set rts threshold: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(rts); + return ret; } int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl) { - struct acx_beacon_filter_option beacon_filter; + struct acx_beacon_filter_option *beacon_filter; int ret; wl12xx_debug(DEBUG_ACX, "acx beacon filter opt"); - beacon_filter.header.id = ACX_BEACON_FILTER_OPT; - beacon_filter.header.len = sizeof(beacon_filter) - - sizeof(struct acx_header); + beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); + if (!beacon_filter) { + ret = -ENOMEM; + goto out; + } - beacon_filter.enable = 0; - beacon_filter.max_num_beacons = 0; + beacon_filter->enable = 0; + beacon_filter->max_num_beacons = 0; - ret = wl12xx_cmd_configure(wl, &beacon_filter, sizeof(beacon_filter)); + ret = wl12xx_cmd_configure(wl, ACX_BEACON_FILTER_OPT, + beacon_filter, sizeof(*beacon_filter)); if (ret < 0) { wl12xx_warning("failed to set beacon filter opt: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(beacon_filter); + return ret; } int wl12xx_acx_beacon_filter_table(struct wl12xx *wl) { - struct acx_beacon_filter_ie_table ie_table; + struct acx_beacon_filter_ie_table *ie_table; int ret; wl12xx_debug(DEBUG_ACX, "acx beacon filter table"); - ie_table.header.id = ACX_BEACON_FILTER_TABLE; - ie_table.header.len = sizeof(ie_table) - sizeof(struct acx_header); + ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); + if (!ie_table) { + ret = -ENOMEM; + goto out; + } - ie_table.num_ie = 0; - memset(ie_table.table, 0, BEACON_FILTER_TABLE_MAX_SIZE); + ie_table->num_ie = 0; + memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE); - ret = wl12xx_cmd_configure(wl, &ie_table, sizeof(ie_table)); + ret = wl12xx_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, + ie_table, sizeof(*ie_table)); if (ret < 0) { wl12xx_warning("failed to set beacon filter table: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(ie_table); + return ret; } int wl12xx_acx_sg_enable(struct wl12xx *wl) { - struct acx_bt_wlan_coex pta; + struct acx_bt_wlan_coex *pta; int ret; wl12xx_debug(DEBUG_ACX, "acx sg enable"); - pta.header.id = ACX_SG_ENABLE; - pta.header.len = sizeof(pta) - sizeof(struct acx_header); + pta = kzalloc(sizeof(*pta), GFP_KERNEL); + if (!pta) { + ret = -ENOMEM; + goto out; + } - pta.enable = SG_ENABLE; + pta->enable = SG_ENABLE; - ret = wl12xx_cmd_configure(wl, &pta, sizeof(pta)); + ret = wl12xx_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); if (ret < 0) { wl12xx_warning("failed to set softgemini enable: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(pta); + return ret; } int wl12xx_acx_sg_cfg(struct wl12xx *wl) { - struct acx_bt_wlan_coex_param param; + struct acx_bt_wlan_coex_param *param; int ret; wl12xx_debug(DEBUG_ACX, "acx sg cfg"); + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) { + ret = -ENOMEM; + goto out; + } + /* BT-WLAN coext parameters */ - param.header.id = ACX_SG_CFG; - param.header.len = sizeof(param) - sizeof(struct acx_header); - - param.min_rate = RATE_INDEX_24MBPS; - param.bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; - param.wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; - param.sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; - param.rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; - param.tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; - param.rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; - param.tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; - param.wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; - param.bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; - param.next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; - param.wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; - param.hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; - param.next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; - param.antenna_type = PTA_ANTENNA_TYPE_DEF; - param.signal_type = PTA_SIGNALING_TYPE_DEF; - param.afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; - param.quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; - param.max_cts = PTA_MAX_NUM_CTS_DEF; - param.wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; - param.bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; - param.missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; - param.wlan_elp_hp = PTA_ELP_HP_DEF; - param.bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; - param.ack_mode_dual_ant = PTA_ACK_MODE_DEF; - param.pa_sd_enable = PTA_ALLOW_PA_SD_DEF; - param.pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; - param.bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; - - ret = wl12xx_cmd_configure(wl, ¶m, sizeof(param)); + param->min_rate = RATE_INDEX_24MBPS; + param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; + param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; + param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; + param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; + param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; + param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; + param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; + param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; + param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; + param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; + param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; + param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; + param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; + param->antenna_type = PTA_ANTENNA_TYPE_DEF; + param->signal_type = PTA_SIGNALING_TYPE_DEF; + param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; + param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; + param->max_cts = PTA_MAX_NUM_CTS_DEF; + param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; + param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; + param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; + param->wlan_elp_hp = PTA_ELP_HP_DEF; + param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; + param->ack_mode_dual_ant = PTA_ACK_MODE_DEF; + param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF; + param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; + param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; + + ret = wl12xx_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); if (ret < 0) { wl12xx_warning("failed to set sg config: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(param); + return ret; } int wl12xx_acx_cca_threshold(struct wl12xx *wl) { - struct acx_energy_detection detection; + struct acx_energy_detection *detection; int ret; wl12xx_debug(DEBUG_ACX, "acx cca threshold"); - detection.header.id = ACX_CCA_THRESHOLD; - detection.header.len = sizeof(detection) - sizeof(struct acx_header); + detection = kzalloc(sizeof(*detection), GFP_KERNEL); + if (!detection) { + ret = -ENOMEM; + goto out; + } - detection.rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; - detection.tx_energy_detection = 0; + detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; + detection->tx_energy_detection = 0; - ret = wl12xx_cmd_configure(wl, &detection, sizeof(detection)); + ret = wl12xx_cmd_configure(wl, ACX_CCA_THRESHOLD, + detection, sizeof(*detection)); if (ret < 0) { wl12xx_warning("failed to set cca threshold: %d", ret); return ret; } - return 0; +out: + kfree(detection); + return ret; } int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl) { - struct acx_beacon_broadcast bb; + struct acx_beacon_broadcast *bb; int ret; wl12xx_debug(DEBUG_ACX, "acx bcn dtim options"); - bb.header.id = ACX_BCN_DTIM_OPTIONS; - bb.header.len = sizeof(bb) - sizeof(struct acx_header); + bb = kzalloc(sizeof(*bb), GFP_KERNEL); + if (!bb) { + ret = -ENOMEM; + goto out; + } - bb.beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; - bb.broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; - bb.rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; - bb.ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; + bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; + bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; + bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; + bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; - ret = wl12xx_cmd_configure(wl, &bb, sizeof(bb)); + ret = wl12xx_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); if (ret < 0) { wl12xx_warning("failed to set rx config: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(bb); + return ret; } int wl12xx_acx_aid(struct wl12xx *wl, u16 aid) { - struct acx_aid acx_aid; + struct acx_aid *acx_aid; int ret; wl12xx_debug(DEBUG_ACX, "acx aid"); - acx_aid.header.id = ACX_AID; - acx_aid.header.len = sizeof(acx_aid) - sizeof(struct acx_header); + acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); + if (!acx_aid) { + ret = -ENOMEM; + goto out; + } - acx_aid.aid = aid; + acx_aid->aid = aid; - ret = wl12xx_cmd_configure(wl, &acx_aid, sizeof(acx_aid)); + ret = wl12xx_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); if (ret < 0) { wl12xx_warning("failed to set aid: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(acx_aid); + return ret; } int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask) { - struct acx_event_mask mask; + struct acx_event_mask *mask; int ret; wl12xx_debug(DEBUG_ACX, "acx event mbox mask"); - mask.header.id = ACX_EVENT_MBOX_MASK; - mask.header.len = sizeof(mask) - sizeof(struct acx_header); + mask = kzalloc(sizeof(*mask), GFP_KERNEL); + if (!mask) { + ret = -ENOMEM; + goto out; + } /* high event mask is unused */ - mask.high_event_mask = 0xffffffff; + mask->high_event_mask = 0xffffffff; - mask.event_mask = event_mask; + mask->event_mask = event_mask; - ret = wl12xx_cmd_configure(wl, &mask, sizeof(mask)); + ret = wl12xx_cmd_configure(wl, ACX_EVENT_MBOX_MASK, + mask, sizeof(*mask)); if (ret < 0) { wl12xx_warning("failed to set aid: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(mask); + return ret; } int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble) { - struct acx_preamble ie; + struct acx_preamble *acx; int ret; wl12xx_debug(DEBUG_ACX, "acx_set_preamble"); - memset(&ie, 0, sizeof(ie)); + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } - ie.header.id = ACX_PREAMBLE_TYPE; - ie.header.len = sizeof(ie) - sizeof(struct acx_header); - ie.preamble = preamble; - ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie)); + acx->preamble = preamble; + + ret = wl12xx_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); if (ret < 0) { wl12xx_warning("Setting of preamble failed: %d", ret); - return ret; + goto out; } - return 0; + +out: + kfree(acx); + return ret; } int wl12xx_acx_cts_protect(struct wl12xx *wl, enum acx_ctsprotect_type ctsprotect) { - struct acx_ctsprotect ie; + struct acx_ctsprotect *acx; int ret; wl12xx_debug(DEBUG_ACX, "acx_set_ctsprotect"); - memset(&ie, 0, sizeof(ie)); + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->ctsprotect = ctsprotect; - ie.header.id = ACX_CTS_PROTECTION; - ie.header.len = sizeof(ie) - sizeof(struct acx_header); - ie.ctsprotect = ctsprotect; - ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie)); + ret = wl12xx_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); if (ret < 0) { wl12xx_warning("Setting of ctsprotect failed: %d", ret); - return ret; + goto out; } - return 0; + +out: + kfree(acx); + return ret; } -int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats) +int wl12xx_acx_tsf_info(struct wl12xx *wl, u64 *mactime) { - struct wl12xx_command *answer; + struct acx_tsf_info *tsf_info; int ret; - wl12xx_debug(DEBUG_ACX, "acx statistics"); - - answer = kmalloc(sizeof(*answer), GFP_KERNEL); - if (!answer) { - wl12xx_warning("could not allocate memory for acx statistics"); + tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); + if (!tsf_info) { ret = -ENOMEM; goto out; } - ret = wl12xx_cmd_interrogate(wl, ACX_STATISTICS, sizeof(*answer), - answer); + ret = wl12xx_cmd_interrogate(wl, ACX_TSF_INFO, + tsf_info, sizeof(*tsf_info)); if (ret < 0) { - wl12xx_warning("acx statistics failed: %d", ret); + wl12xx_warning("ACX_FW_REV interrogate failed"); goto out; } - memcpy(stats, answer->parameters, sizeof(*stats)); + *mactime = tsf_info->current_tsf_lsb | + (tsf_info->current_tsf_msb << 31); out: - kfree(answer); + kfree(tsf_info); return ret; } + +int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats) +{ + int ret; + + wl12xx_debug(DEBUG_ACX, "acx statistics"); + + ret = wl12xx_cmd_interrogate(wl, ACX_STATISTICS, stats, + sizeof(*stats)); + if (ret < 0) { + wl12xx_warning("acx statistics failed: %d", ret); + return -ENOMEM; + } + + return 0; +} diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index fb2d2340993..549e537d2e6 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -26,10 +26,16 @@ #define __WL12XX_ACX_H__ #include "wl12xx.h" +#include "cmd.h" /* Target's information element */ struct acx_header { + struct wl12xx_cmd_header cmd; + + /* acx (or information element) header */ u16 id; + + /* payload length (not including headers */ u16 len; }; @@ -107,25 +113,6 @@ struct acx_sleep_auth { u8 padding[3]; } __attribute__ ((packed)); -#define TIM_ELE_ID 5 -#define PARTIAL_VBM_MAX 251 - -struct tim { - u8 identity; - u8 length; - u8 dtim_count; - u8 dtim_period; - u8 bitmap_ctrl; - u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ -} __attribute__ ((packed)); - -/* Virtual Bit Map update */ -struct vbm_update_request { - __le16 len; - u8 padding[2]; - struct tim tim; -} __attribute__ ((packed)); - enum { HOSTIF_PCI_MASTER_HOST_INDIRECT, HOSTIF_PCI_MASTER_HOST_DIRECT, @@ -202,7 +189,7 @@ struct acx_data_path_params_resp { #define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF #define RX_MSDU_LIFETIME_DEF 512000 -struct rx_msdu_lifetime { +struct acx_rx_msdu_lifetime { struct acx_header header; /* @@ -368,7 +355,7 @@ struct acx_slot { #define ADDRESS_GROUP_MAX (8) #define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) -struct multicast_grp_addr_start { +struct acx_dot11_grp_addr_tbl { struct acx_header header; u8 enabled; @@ -730,22 +717,13 @@ struct acx_fw_gen_frame_rates { } __attribute__ ((packed)); /* STA MAC */ -struct dot11_station_id { +struct acx_dot11_station_id { struct acx_header header; u8 mac[ETH_ALEN]; u8 pad[2]; } __attribute__ ((packed)); -/* HW encryption keys */ -#define NUM_ACCESS_CATEGORIES_COPY 4 -#define MAX_KEY_SIZE 32 - -/* When set, disable HW encryption */ -#define DF_ENCRYPTION_DISABLE 0x01 -/* When set, disable HW decryption */ -#define DF_SNIFF_MODE_ENABLE 0x80 - struct acx_feature_config { struct acx_header header; @@ -753,67 +731,6 @@ struct acx_feature_config { u32 data_flow_options; } __attribute__ ((packed)); -enum acx_key_action { - KEY_ADD_OR_REPLACE = 1, - KEY_REMOVE = 2, - KEY_SET_ID = 3, - MAX_KEY_ACTION = 0xffff, -}; - -enum acx_key_type { - KEY_WEP_DEFAULT = 0, - KEY_WEP_ADDR = 1, - KEY_AES_GROUP = 4, - KEY_AES_PAIRWISE = 5, - KEY_WEP_GROUP = 6, - KEY_TKIP_MIC_GROUP = 10, - KEY_TKIP_MIC_PAIRWISE = 11, -}; - -/* - * - * key_type_e key size key format - * ---------- --------- ---------- - * 0x00 5, 13, 29 Key data - * 0x01 5, 13, 29 Key data - * 0x04 16 16 bytes of key data - * 0x05 16 16 bytes of key data - * 0x0a 32 16 bytes of TKIP key data - * 8 bytes of RX MIC key data - * 8 bytes of TX MIC key data - * 0x0b 32 16 bytes of TKIP key data - * 8 bytes of RX MIC key data - * 8 bytes of TX MIC key data - * - */ - -struct acx_set_key { - /* Ignored for default WEP key */ - u8 addr[ETH_ALEN]; - - /* key_action_e */ - u16 key_action; - - u16 reserved_1; - - /* key size in bytes */ - u8 key_size; - - /* key_type_e */ - u8 key_type; - u8 ssid_profile; - - /* - * TKIP, AES: frame's key id field. - * For WEP default key: key id; - */ - u8 id; - u8 reserved_2[6]; - u8 key[MAX_KEY_SIZE]; - u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; - u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; -} __attribute__ ((packed)); - struct acx_current_tx_power { struct acx_header header; @@ -839,26 +756,6 @@ struct acx_tsf_info { u8 pad[3]; } __attribute__ ((packed)); -/* 802.11 PS */ -enum acx_ps_mode { - STATION_ACTIVE_MODE, - STATION_POWER_SAVE_MODE -}; - -struct acx_ps_params { - u8 ps_mode; /* STATION_* */ - u8 send_null_data; /* Do we have to send NULL data packet ? */ - u8 retries; /* Number of retires for the initial NULL data packet */ - - /* - * TUs during which the target stays awake after switching - * to power save mode. - */ - u8 hang_over_period; - u16 null_data_rate; - u8 pad[2]; -} __attribute__ ((packed)); - enum acx_wake_up_event { WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/ WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/ @@ -892,6 +789,7 @@ enum acx_preamble_type { struct acx_preamble { struct acx_header header; + /* * When set, the WiLink transmits the frames with a short preamble and * when cleared, the WiLink transmits the frames with a long preamble. @@ -1219,7 +1117,8 @@ int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth); int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len); int wl12xx_acx_tx_power(struct wl12xx *wl, int power); int wl12xx_acx_feature_cfg(struct wl12xx *wl); -int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len); +int wl12xx_acx_mem_map(struct wl12xx *wl, + struct acx_header *mem_map, size_t len); int wl12xx_acx_data_path_params(struct wl12xx *wl, struct acx_data_path_params_resp *data_path); int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time); @@ -1241,5 +1140,6 @@ int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble); int wl12xx_acx_cts_protect(struct wl12xx *wl, enum acx_ctsprotect_type ctsprotect); int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats); +int wl12xx_acx_tsf_info(struct wl12xx *wl, u64 *mactime); #endif /* __WL12XX_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index f73ab602b7a..0a02cdde935 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -9,24 +9,32 @@ #include "reg.h" #include "spi.h" #include "ps.h" - -int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len) +#include "acx.h" + +/** + * send command to firmware + * + * @wl: wl struct + * @id: command id + * @buf: buffer containing the command, must work with dma + * @len: length of the buffer + */ +int wl12xx_cmd_send(struct wl12xx *wl, u16 id, void *buf, size_t len) { - struct wl12xx_command cmd; + struct wl12xx_cmd_header *cmd; unsigned long timeout; - size_t cmd_len; u32 intr; int ret = 0; - memset(&cmd, 0, sizeof(cmd)); - cmd.id = type; - cmd.status = 0; - memcpy(cmd.parameters, buf, buf_len); - cmd_len = ALIGN(buf_len, 4) + CMDMBOX_HEADER_LEN; + cmd = buf; + cmd->id = id; + cmd->status = 0; + + WARN_ON(len % 4 != 0); wl12xx_ps_elp_wakeup(wl); - wl12xx_spi_mem_write(wl, wl->cmd_box_addr, &cmd, cmd_len); + wl12xx_spi_mem_write(wl, wl->cmd_box_addr, buf, len); wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); @@ -54,21 +62,42 @@ out: return ret; } +/** + * send test command to firmware + * + * @wl: wl struct + * @buf: buffer containing the command, without headers, no dma requirements + * @len: length of the buffer + * @answer: is answer needed + * + * FIXME: cmd_test users need to be converted to the new interface + */ int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) { + struct wl12xx_command *cmd; + size_t cmd_len; int ret; wl12xx_debug(DEBUG_CMD, "cmd test"); - ret = wl12xx_cmd_send(wl, CMD_TEST, buf, buf_len); + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + memcpy(cmd->parameters, buf, buf_len); + + /* FIXME: ugly */ + cmd_len = sizeof(struct wl12xx_cmd_header) + buf_len; + + ret = wl12xx_cmd_send(wl, CMD_TEST, cmd, cmd_len); if (ret < 0) { wl12xx_warning("TEST command failed"); - return ret; + goto out; } if (answer) { - struct wl12xx_command *cmd_answer; - /* * The test command got in, we can read the answer. * The answer would be a wl12xx_command, where the @@ -77,109 +106,146 @@ int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) wl12xx_ps_elp_wakeup(wl); - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, cmd, cmd_len); wl12xx_ps_elp_sleep(wl); - cmd_answer = buf; - if (cmd_answer->status != CMD_STATUS_SUCCESS) + if (cmd->header.status != CMD_STATUS_SUCCESS) wl12xx_error("TEST command answer error: %d", - cmd_answer->status); + cmd->header.status); + memcpy(buf, cmd->parameters, buf_len); } - return 0; +out: + kfree(cmd); + return ret; } - -int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len, - void *answer) +/** + * read acx from firmware + * + * @wl: wl struct + * @id: acx id + * @buf: buffer for the response, including all headers, must work with dma + * @len: lenght of buf + */ +int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 id, void *buf, size_t len) { - struct wl12xx_command *cmd; - struct acx_header header; + struct acx_header *acx = buf; int ret; wl12xx_debug(DEBUG_CMD, "cmd interrogate"); - header.id = ie_id; - header.len = ie_len - sizeof(header); + acx->id = id; - ret = wl12xx_cmd_send(wl, CMD_INTERROGATE, &header, sizeof(header)); + /* payload length, does not include any headers */ + acx->len = len - sizeof(*acx); + + ret = wl12xx_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); if (ret < 0) { wl12xx_error("INTERROGATE command failed"); - return ret; + goto out; } wl12xx_ps_elp_wakeup(wl); /* the interrogate command got in, we can read the answer */ - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, answer, - CMDMBOX_HEADER_LEN + ie_len); + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, len); wl12xx_ps_elp_sleep(wl); - cmd = answer; - if (cmd->status != CMD_STATUS_SUCCESS) + acx = buf; + if (acx->cmd.status != CMD_STATUS_SUCCESS) wl12xx_error("INTERROGATE command error: %d", - cmd->status); - - return 0; + acx->cmd.status); +out: + return ret; } -int wl12xx_cmd_configure(struct wl12xx *wl, void *ie, int ie_len) +/** + * write acx value to firmware + * + * @wl: wl struct + * @id: acx id + * @buf: buffer containing acx, including all headers, must work with dma + * @len: length of buf + */ +int wl12xx_cmd_configure(struct wl12xx *wl, u16 id, void *buf, size_t len) { + struct acx_header *acx = buf; int ret; wl12xx_debug(DEBUG_CMD, "cmd configure"); - ret = wl12xx_cmd_send(wl, CMD_CONFIGURE, ie, - ie_len); + acx->id = id; + + /* payload length, does not include any headers */ + acx->len = len - sizeof(*acx); + + ret = wl12xx_cmd_send(wl, CMD_CONFIGURE, acx, len); if (ret < 0) { wl12xx_warning("CONFIGURE command NOK"); return ret; } return 0; - } int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, void *bitmap, u16 bitmap_len, u8 bitmap_control) { - struct vbm_update_request vbm; + struct wl12xx_cmd_vbm_update *vbm; int ret; wl12xx_debug(DEBUG_CMD, "cmd vbm"); + vbm = kzalloc(sizeof(*vbm), GFP_KERNEL); + if (!vbm) { + ret = -ENOMEM; + goto out; + } + /* Count and period will be filled by the target */ - vbm.tim.bitmap_ctrl = bitmap_control; + vbm->tim.bitmap_ctrl = bitmap_control; if (bitmap_len > PARTIAL_VBM_MAX) { wl12xx_warning("cmd vbm len is %d B, truncating to %d", bitmap_len, PARTIAL_VBM_MAX); bitmap_len = PARTIAL_VBM_MAX; } - memcpy(vbm.tim.pvb_field, bitmap, bitmap_len); - vbm.tim.identity = identity; - vbm.tim.length = bitmap_len + 3; + memcpy(vbm->tim.pvb_field, bitmap, bitmap_len); + vbm->tim.identity = identity; + vbm->tim.length = bitmap_len + 3; - vbm.len = cpu_to_le16(bitmap_len + 5); + vbm->len = cpu_to_le16(bitmap_len + 5); - ret = wl12xx_cmd_send(wl, CMD_VBM, &vbm, sizeof(vbm)); + ret = wl12xx_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm)); if (ret < 0) { wl12xx_error("VBM command failed"); - return ret; + goto out; } +out: + kfree(vbm); return 0; } -int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable) +int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable) { + struct cmd_enabledisable_path *cmd; int ret; u16 cmd_rx, cmd_tx; wl12xx_debug(DEBUG_CMD, "cmd data path"); + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->channel = channel; + if (enable) { cmd_rx = CMD_ENABLE_RX; cmd_tx = CMD_ENABLE_TX; @@ -188,17 +254,17 @@ int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable) cmd_tx = CMD_DISABLE_TX; } - ret = wl12xx_cmd_send(wl, cmd_rx, &channel, sizeof(channel)); + ret = wl12xx_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); if (ret < 0) { wl12xx_error("rx %s cmd for channel %d failed", enable ? "start" : "stop", channel); - return ret; + goto out; } wl12xx_debug(DEBUG_BOOT, "rx %s cmd channel %d", enable ? "start" : "stop", channel); - ret = wl12xx_cmd_send(wl, cmd_tx, &channel, sizeof(channel)); + ret = wl12xx_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); if (ret < 0) { wl12xx_error("tx %s cmd for channel %d failed", enable ? "start" : "stop", channel); @@ -208,48 +274,56 @@ int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable) wl12xx_debug(DEBUG_BOOT, "tx %s cmd channel %d", enable ? "start" : "stop", channel); - return 0; +out: + kfree(cmd); + return ret; } int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, u16 beacon_interval, u8 wait) { unsigned long timeout; - struct cmd_join join = {}; + struct cmd_join *join; int ret, i; u8 *bssid; + join = kzalloc(sizeof(*join), GFP_KERNEL); + if (!join) { + ret = -ENOMEM; + goto out; + } + /* FIXME: this should be in main.c */ ret = wl12xx_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, DEFAULT_HW_GEN_MODULATION_TYPE, wl->tx_mgmt_frm_rate, wl->tx_mgmt_frm_mod); if (ret < 0) - return ret; + goto out; wl12xx_debug(DEBUG_CMD, "cmd join"); /* Reverse order BSSID */ - bssid = (u8 *)&join.bssid_lsb; + bssid = (u8 *) &join->bssid_lsb; for (i = 0; i < ETH_ALEN; i++) bssid[i] = wl->bssid[ETH_ALEN - i - 1]; - join.rx_config_options = wl->rx_config; - join.rx_filter_options = wl->rx_filter; + join->rx_config_options = wl->rx_config; + join->rx_filter_options = wl->rx_filter; - join.basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | + join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; - join.beacon_interval = beacon_interval; - join.dtim_interval = dtim_interval; - join.bss_type = bss_type; - join.channel = wl->channel; - join.ctrl = JOIN_CMD_CTRL_TX_FLUSH; + join->beacon_interval = beacon_interval; + join->dtim_interval = dtim_interval; + join->bss_type = bss_type; + join->channel = wl->channel; + join->ctrl = JOIN_CMD_CTRL_TX_FLUSH; - ret = wl12xx_cmd_send(wl, CMD_START_JOIN, &join, sizeof(join)); + ret = wl12xx_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); if (ret < 0) { wl12xx_error("failed to initiate cmd join"); - return ret; + goto out; } timeout = msecs_to_jiffies(JOIN_TIMEOUT); @@ -261,93 +335,120 @@ int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, if (wait) msleep(10); - return 0; +out: + kfree(join); + return ret; } int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode) { - int ret; - struct acx_ps_params ps_params; + struct wl12xx_cmd_ps_params *ps_params = NULL; + int ret = 0; /* FIXME: this should be in ps.c */ ret = wl12xx_acx_wake_up_conditions(wl, wl->listen_int); if (ret < 0) { - wl12xx_error("Couldnt set wake up conditions"); - return ret; + wl12xx_error("couldn't set wake up conditions"); + goto out; } wl12xx_debug(DEBUG_CMD, "cmd set ps mode"); - ps_params.ps_mode = ps_mode; - ps_params.send_null_data = 1; - ps_params.retries = 5; - ps_params.hang_over_period = 128; - ps_params.null_data_rate = 1; /* 1 Mbps */ + ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); + if (!ps_params) { + ret = -ENOMEM; + goto out; + } + + ps_params->ps_mode = ps_mode; + ps_params->send_null_data = 1; + ps_params->retries = 5; + ps_params->hang_over_period = 128; + ps_params->null_data_rate = 1; /* 1 Mbps */ - ret = wl12xx_cmd_send(wl, CMD_SET_PS_MODE, &ps_params, - sizeof(ps_params)); + ret = wl12xx_cmd_send(wl, CMD_SET_PS_MODE, ps_params, + sizeof(*ps_params)); if (ret < 0) { wl12xx_error("cmd set_ps_mode failed"); - return ret; + goto out; } - return 0; +out: + kfree(ps_params); + return ret; } -int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer) +int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer, + size_t len) { - struct cmd_read_write_memory mem_cmd, *mem_answer; - struct wl12xx_command cmd; - int ret; + struct cmd_read_write_memory *cmd; + int ret = 0; wl12xx_debug(DEBUG_CMD, "cmd read memory"); - memset(&mem_cmd, 0, sizeof(mem_cmd)); - mem_cmd.addr = addr; - mem_cmd.size = len; + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + WARN_ON(len > MAX_READ_SIZE); + len = min_t(size_t, len, MAX_READ_SIZE); + + cmd->addr = addr; + cmd->size = len; - ret = wl12xx_cmd_send(wl, CMD_READ_MEMORY, &mem_cmd, sizeof(mem_cmd)); + ret = wl12xx_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); if (ret < 0) { wl12xx_error("read memory command failed: %d", ret); - return ret; + goto out; } /* the read command got in, we can now read the answer */ - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, &cmd, - CMDMBOX_HEADER_LEN + sizeof(mem_cmd)); + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); - if (cmd.status != CMD_STATUS_SUCCESS) - wl12xx_error("error in read command result: %d", cmd.status); + if (cmd->header.status != CMD_STATUS_SUCCESS) + wl12xx_error("error in read command result: %d", + cmd->header.status); - mem_answer = (struct cmd_read_write_memory *) cmd.parameters; - memcpy(answer, mem_answer->value, len); + memcpy(answer, cmd->value, len); - return 0; +out: + kfree(cmd); + return ret; } int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, void *buf, size_t buf_len) { - struct wl12xx_cmd_packet_template template; - int ret; + struct wl12xx_cmd_packet_template *cmd; + size_t cmd_len; + int ret = 0; wl12xx_debug(DEBUG_CMD, "cmd template %d", cmd_id); - memset(&template, 0, sizeof(template)); - WARN_ON(buf_len > WL12XX_MAX_TEMPLATE_SIZE); buf_len = min_t(size_t, buf_len, WL12XX_MAX_TEMPLATE_SIZE); - template.size = cpu_to_le16(buf_len); + cmd_len = ALIGN(sizeof(*cmd) + buf_len, 4); + + cmd = kzalloc(cmd_len, GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->size = cpu_to_le16(buf_len); if (buf) - memcpy(template.template, buf, buf_len); + memcpy(cmd->data, buf, buf_len); - ret = wl12xx_cmd_send(wl, cmd_id, &template, - sizeof(template.size) + buf_len); + ret = wl12xx_cmd_send(wl, cmd_id, cmd, cmd_len); if (ret < 0) { wl12xx_warning("cmd set_template failed: %d", ret); - return ret; + goto out; } - return 0; +out: + kfree(cmd); + return ret; } diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index aa307dcd081..7aef1f24352 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -27,31 +27,26 @@ #include "wl12xx.h" +struct acx_header; + int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len); int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer); -int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len, - void *answer); -int wl12xx_cmd_configure(struct wl12xx *wl, void *ie, int ie_len); +int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 id, void *buf, size_t len); +int wl12xx_cmd_configure(struct wl12xx *wl, u16 id, void *buf, size_t len); int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, void *bitmap, u16 bitmap_len, u8 bitmap_control); -int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable); +int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable); int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, u16 beacon_interval, u8 wait); int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode); -int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer); +int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer, + size_t len); int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, void *buf, size_t buf_len); /* unit ms */ #define WL12XX_COMMAND_TIMEOUT 2000 -#define WL12XX_MAX_TEMPLATE_SIZE 300 - -struct wl12xx_cmd_packet_template { - __le16 size; - u8 template[WL12XX_MAX_TEMPLATE_SIZE]; -} __attribute__ ((packed)); - enum wl12xx_commands { CMD_RESET = 0, CMD_INTERROGATE = 1, /*use this to read information elements*/ @@ -100,9 +95,15 @@ enum wl12xx_commands { #define MAX_CMD_PARAMS 572 -struct wl12xx_command { +struct wl12xx_cmd_header { u16 id; u16 status; + /* payload */ + u8 data[0]; +} __attribute__ ((packed)); + +struct wl12xx_command { + struct wl12xx_cmd_header header; u8 parameters[MAX_CMD_PARAMS]; }; @@ -144,6 +145,8 @@ enum { #define MAX_READ_SIZE 256 struct cmd_read_write_memory { + struct wl12xx_cmd_header header; + /* The address of the memory to read from or write to.*/ u32 addr; @@ -211,6 +214,8 @@ struct basic_scan_channel_parameters { #define SCAN_MAX_NUM_OF_CHANNELS 16 struct cmd_scan { + struct wl12xx_cmd_header header; + struct basic_scan_parameters params; struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; } __attribute__ ((packed)); @@ -227,6 +232,8 @@ enum { struct cmd_join { + struct wl12xx_cmd_header header; + u32 bssid_lsb; u16 bssid_msb; u16 beacon_interval; /* in TBTTs */ @@ -261,5 +268,140 @@ struct cmd_join { u8 reserved; } __attribute__ ((packed)); +struct cmd_enabledisable_path { + struct wl12xx_cmd_header header; + + u8 channel; + u8 padding[3]; +} __attribute__ ((packed)); + +#define WL12XX_MAX_TEMPLATE_SIZE 300 + +struct wl12xx_cmd_packet_template { + struct wl12xx_cmd_header header; + + __le16 size; + u8 data[0]; +} __attribute__ ((packed)); + +#define TIM_ELE_ID 5 +#define PARTIAL_VBM_MAX 251 + +struct wl12xx_tim { + u8 identity; + u8 length; + u8 dtim_count; + u8 dtim_period; + u8 bitmap_ctrl; + u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ +} __attribute__ ((packed)); + +/* Virtual Bit Map update */ +struct wl12xx_cmd_vbm_update { + struct wl12xx_cmd_header header; + __le16 len; + u8 padding[2]; + struct wl12xx_tim tim; +} __attribute__ ((packed)); + +enum wl12xx_cmd_ps_mode { + STATION_ACTIVE_MODE, + STATION_POWER_SAVE_MODE +}; + +struct wl12xx_cmd_ps_params { + struct wl12xx_cmd_header header; + + u8 ps_mode; /* STATION_* */ + u8 send_null_data; /* Do we have to send NULL data packet ? */ + u8 retries; /* Number of retires for the initial NULL data packet */ + + /* + * TUs during which the target stays awake after switching + * to power save mode. + */ + u8 hang_over_period; + u16 null_data_rate; + u8 pad[2]; +} __attribute__ ((packed)); + +struct wl12xx_cmd_trigger_scan_to { + struct wl12xx_cmd_header header; + + u32 timeout; +}; + +/* HW encryption keys */ +#define NUM_ACCESS_CATEGORIES_COPY 4 +#define MAX_KEY_SIZE 32 + +/* When set, disable HW encryption */ +#define DF_ENCRYPTION_DISABLE 0x01 +/* When set, disable HW decryption */ +#define DF_SNIFF_MODE_ENABLE 0x80 + +enum wl12xx_cmd_key_action { + KEY_ADD_OR_REPLACE = 1, + KEY_REMOVE = 2, + KEY_SET_ID = 3, + MAX_KEY_ACTION = 0xffff, +}; + +enum wl12xx_cmd_key_type { + KEY_WEP_DEFAULT = 0, + KEY_WEP_ADDR = 1, + KEY_AES_GROUP = 4, + KEY_AES_PAIRWISE = 5, + KEY_WEP_GROUP = 6, + KEY_TKIP_MIC_GROUP = 10, + KEY_TKIP_MIC_PAIRWISE = 11, +}; + +/* + * + * key_type_e key size key format + * ---------- --------- ---------- + * 0x00 5, 13, 29 Key data + * 0x01 5, 13, 29 Key data + * 0x04 16 16 bytes of key data + * 0x05 16 16 bytes of key data + * 0x0a 32 16 bytes of TKIP key data + * 8 bytes of RX MIC key data + * 8 bytes of TX MIC key data + * 0x0b 32 16 bytes of TKIP key data + * 8 bytes of RX MIC key data + * 8 bytes of TX MIC key data + * + */ + +struct wl12xx_cmd_set_keys { + struct wl12xx_cmd_header header; + + /* Ignored for default WEP key */ + u8 addr[ETH_ALEN]; + + /* key_action_e */ + u16 key_action; + + u16 reserved_1; + + /* key size in bytes */ + u8 key_size; + + /* key_type_e */ + u8 key_type; + u8 ssid_profile; + + /* + * TKIP, AES: frame's key id field. + * For WEP default key: key id; + */ + u8 id; + u8 reserved_2[6]; + u8 key[MAX_KEY_SIZE]; + u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; + u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; +} __attribute__ ((packed)); + #endif /* __WL12XX_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 603d6114882..c6a45443971 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -618,7 +618,8 @@ static void wl12xx_op_configure_filter(struct ieee80211_hw *hw, } /* HW encryption */ -static int wl12xx_set_key_type(struct wl12xx *wl, struct acx_set_key *key, +static int wl12xx_set_key_type(struct wl12xx *wl, + struct wl12xx_cmd_set_keys *key, enum set_key_cmd cmd, struct ieee80211_key_conf *mac80211_key, const u8 *addr) @@ -661,7 +662,7 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_key_conf *key) { struct wl12xx *wl = hw->priv; - struct acx_set_key wl_key; + struct wl12xx_cmd_set_keys *wl_cmd; const u8 *addr; int ret; @@ -670,7 +671,11 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, wl12xx_debug(DEBUG_MAC80211, "mac80211 set key"); - memset(&wl_key, 0, sizeof(wl_key)); + wl_cmd = kzalloc(sizeof(*wl_cmd), GFP_KERNEL); + if (!wl_cmd) { + ret = -ENOMEM; + goto out; + } addr = sta ? sta->addr : bcast_addr; @@ -680,59 +685,69 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, key->alg, key->keyidx, key->keylen, key->flags); wl12xx_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen); + if (is_zero_ether_addr(addr)) { + /* We dont support TX only encryption */ + ret = -EOPNOTSUPP; + goto out; + } + mutex_lock(&wl->mutex); switch (cmd) { case SET_KEY: - wl_key.key_action = KEY_ADD_OR_REPLACE; + wl_cmd->key_action = KEY_ADD_OR_REPLACE; break; case DISABLE_KEY: - wl_key.key_action = KEY_REMOVE; + wl_cmd->key_action = KEY_REMOVE; break; default: wl12xx_error("Unsupported key cmd 0x%x", cmd); break; } - ret = wl12xx_set_key_type(wl, &wl_key, cmd, key, addr); + ret = wl12xx_set_key_type(wl, wl_cmd, cmd, key, addr); if (ret < 0) { wl12xx_error("Set KEY type failed"); - goto out; + goto out_unlock; } - if (wl_key.key_type != KEY_WEP_DEFAULT) - memcpy(wl_key.addr, addr, ETH_ALEN); + if (wl_cmd->key_type != KEY_WEP_DEFAULT) + memcpy(wl_cmd->addr, addr, ETH_ALEN); - if ((wl_key.key_type == KEY_TKIP_MIC_GROUP) || - (wl_key.key_type == KEY_TKIP_MIC_PAIRWISE)) { + if ((wl_cmd->key_type == KEY_TKIP_MIC_GROUP) || + (wl_cmd->key_type == KEY_TKIP_MIC_PAIRWISE)) { /* * We get the key in the following form: * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) * but the target is expecting: * TKIP - RX MIC - TX MIC */ - memcpy(wl_key.key, key->key, 16); - memcpy(wl_key.key + 16, key->key + 24, 8); - memcpy(wl_key.key + 24, key->key + 16, 8); + memcpy(wl_cmd->key, key->key, 16); + memcpy(wl_cmd->key + 16, key->key + 24, 8); + memcpy(wl_cmd->key + 24, key->key + 16, 8); } else { - memcpy(wl_key.key, key->key, key->keylen); + memcpy(wl_cmd->key, key->key, key->keylen); } - wl_key.key_size = key->keylen; + wl_cmd->key_size = key->keylen; - wl_key.id = key->keyidx; - wl_key.ssid_profile = 0; + wl_cmd->id = key->keyidx; + wl_cmd->ssid_profile = 0; - wl12xx_dump(DEBUG_CRYPT, "TARGET KEY: ", &wl_key, sizeof(wl_key)); + wl12xx_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd)); - if (wl12xx_cmd_send(wl, CMD_SET_KEYS, &wl_key, sizeof(wl_key)) < 0) { - wl12xx_error("Set KEY failed"); - ret = -EOPNOTSUPP; - goto out; + ret = wl12xx_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd)); + if (ret < 0) { + wl12xx_warning("could not set keys"); + goto out_unlock; } -out: +out_unlock: mutex_unlock(&wl->mutex); + +out: + kfree(wl_cmd); + return ret; } @@ -812,11 +827,10 @@ static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len, u8 active_scan, u8 high_prio, u8 num_channels, u8 probe_requests) { + struct wl12xx_cmd_trigger_scan_to *trigger = NULL; + struct cmd_scan *params = NULL; int i, ret; - u32 split_scan = 0; u16 scan_options = 0; - struct cmd_scan *params; - struct wl12xx_command *cmd_answer; if (wl->scanning) return -EINVAL; @@ -870,10 +884,16 @@ static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len, goto out; } - ret = wl12xx_cmd_send(wl, CMD_TRIGGER_SCAN_TO, &split_scan, - sizeof(u32)); + trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); + if (!trigger) + goto out; + + trigger->timeout = 0; + + ret = wl12xx_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, + sizeof(*trigger)); if (ret < 0) { - wl12xx_error("Split SCAN failed"); + wl12xx_error("trigger scan to failed for hw scan"); goto out; } @@ -887,10 +907,9 @@ static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len, wl12xx_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); - cmd_answer = (struct wl12xx_command *) params; - if (cmd_answer->status != CMD_STATUS_SUCCESS) { + if (params->header.status != CMD_STATUS_SUCCESS) { wl12xx_error("TEST command answer error: %d", - cmd_answer->status); + params->header.status); wl->scanning = false; ret = -EIO; goto out; @@ -942,7 +961,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, u32 changed) { - enum acx_ps_mode mode; + enum wl12xx_cmd_ps_mode mode; struct wl12xx *wl = hw->priv; struct sk_buff *beacon; int ret; diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index 83a10117330..fe5e2d13acf 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -114,7 +114,7 @@ static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable) return 0; } -int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode) +int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode) { int ret; diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/ps.h index 5d7c5255383..ad61b4a0b5e 100644 --- a/drivers/net/wireless/wl12xx/ps.h +++ b/drivers/net/wireless/wl12xx/ps.h @@ -28,7 +28,7 @@ #include "wl12xx.h" #include "acx.h" -int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode); +int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode); void wl12xx_ps_elp_sleep(struct wl12xx *wl); int wl12xx_ps_elp_wakeup(struct wl12xx *wl); diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 981ea259eb8..5fd916a0b25 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -48,6 +48,9 @@ static void wl12xx_rx_status(struct wl12xx *wl, struct ieee80211_rx_status *status, u8 beacon) { + u64 mactime; + int ret; + memset(status, 0, sizeof(struct ieee80211_rx_status)); status->band = IEEE80211_BAND_2GHZ; @@ -62,27 +65,9 @@ static void wl12xx_rx_status(struct wl12xx *wl, * this one must be atomic, while our SPI routines can sleep. */ if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) { - u64 mactime; - int ret; - struct wl12xx_command cmd; - struct acx_tsf_info *tsf_info; - - memset(&cmd, 0, sizeof(cmd)); - - ret = wl12xx_cmd_interrogate(wl, ACX_TSF_INFO, - sizeof(struct acx_tsf_info), - &cmd); - if (ret < 0) { - wl12xx_warning("ACX_FW_REV interrogate failed"); - return; - } - - tsf_info = (struct acx_tsf_info *)&(cmd.parameters); - - mactime = tsf_info->current_tsf_lsb | - (tsf_info->current_tsf_msb << 31); - - status->mactime = mactime; + ret = wl12xx_acx_tsf_info(wl, &mactime); + if (ret == 0) + status->mactime = mactime; } status->signal = desc->rssi; diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251.c index ce1561a41fa..1a352cf8c3e 100644 --- a/drivers/net/wireless/wl12xx/wl1251.c +++ b/drivers/net/wireless/wl12xx/wl1251.c @@ -297,45 +297,48 @@ out: static int wl1251_mem_cfg(struct wl12xx *wl) { - struct wl1251_acx_config_memory mem_conf; + struct wl1251_acx_config_memory *mem_conf; int ret, i; wl12xx_debug(DEBUG_ACX, "wl1251 mem cfg"); + mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); + if (!mem_conf) { + ret = -ENOMEM; + goto out; + } + /* memory config */ - mem_conf.mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); - mem_conf.mem_config.rx_mem_block_num = 35; - mem_conf.mem_config.tx_min_mem_block_num = 64; - mem_conf.mem_config.num_tx_queues = MAX_TX_QUEUES; - mem_conf.mem_config.host_if_options = HOSTIF_PKT_RING; - mem_conf.mem_config.num_ssid_profiles = 1; - mem_conf.mem_config.debug_buffer_size = + mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); + mem_conf->mem_config.rx_mem_block_num = 35; + mem_conf->mem_config.tx_min_mem_block_num = 64; + mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; + mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; + mem_conf->mem_config.num_ssid_profiles = 1; + mem_conf->mem_config.debug_buffer_size = cpu_to_le16(TRACE_BUFFER_MAX_SIZE); /* RX queue config */ - mem_conf.rx_queue_config.dma_address = 0; - mem_conf.rx_queue_config.num_descs = ACX_RX_DESC_DEF; - mem_conf.rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; - mem_conf.rx_queue_config.type = DEFAULT_RXQ_TYPE; + mem_conf->rx_queue_config.dma_address = 0; + mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; + mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; + mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; /* TX queue config */ for (i = 0; i < MAX_TX_QUEUES; i++) { - mem_conf.tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; - mem_conf.tx_queue_config[i].attributes = i; + mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; + mem_conf->tx_queue_config[i].attributes = i; } - mem_conf.header.id = ACX_MEM_CFG; - mem_conf.header.len = sizeof(struct wl1251_acx_config_memory) - - sizeof(struct acx_header); - mem_conf.header.len -= - (MAX_TX_QUEUE_CONFIGS - mem_conf.mem_config.num_tx_queues) * - sizeof(struct wl1251_acx_tx_queue_config); - - ret = wl12xx_cmd_configure(wl, &mem_conf, - sizeof(struct wl1251_acx_config_memory)); - if (ret < 0) + ret = wl12xx_cmd_configure(wl, ACX_MEM_CFG, mem_conf, + sizeof(*mem_conf)); + if (ret < 0) { wl12xx_warning("wl1251 mem config failed: %d", ret); + goto out; + } +out: + kfree(mem_conf); return ret; } @@ -529,28 +532,33 @@ static int wl1251_hw_init_txq_fill(u8 qid, static int wl1251_hw_init_tx_queue_config(struct wl12xx *wl) { - struct acx_tx_queue_qos_config config; + struct acx_tx_queue_qos_config *config; struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; int ret, i; wl12xx_debug(DEBUG_ACX, "acx tx queue config"); - config.header.id = ACX_TX_QUEUE_CFG; - config.header.len = sizeof(struct acx_tx_queue_qos_config) - - sizeof(struct acx_header); + config = kzalloc(sizeof(*config), GFP_KERNEL); + if (!config) { + ret = -ENOMEM; + goto out; + } for (i = 0; i < MAX_NUM_OF_AC; i++) { - ret = wl1251_hw_init_txq_fill(i, &config, + ret = wl1251_hw_init_txq_fill(i, config, wl_mem_map->num_tx_mem_blocks); if (ret < 0) - return ret; + goto out; - ret = wl12xx_cmd_configure(wl, &config, sizeof(config)); + ret = wl12xx_cmd_configure(wl, ACX_TX_QUEUE_CFG, + config, sizeof(*config)); if (ret < 0) - return ret; + goto out; } - return 0; +out: + kfree(config); + return ret; } static int wl1251_hw_init_data_path_config(struct wl12xx *wl) -- cgit v1.2.3-18-g5258 From 1d3b8130611bbe50168ad0a12841735c9c235410 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:14:28 +0300 Subject: wl12xx: reserver buffer for read32()/write32() in struct wl12xx The buffer is needed for DMA safe transfers. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/spi.h | 9 ++++----- drivers/net/wireless/wl12xx/wl12xx.h | 2 ++ 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/spi.h index fd3227e904a..f3f18958657 100644 --- a/drivers/net/wireless/wl12xx/spi.h +++ b/drivers/net/wireless/wl12xx/spi.h @@ -94,16 +94,15 @@ void wl12xx_set_partition(struct wl12xx *wl, static inline u32 wl12xx_read32(struct wl12xx *wl, int addr) { - u32 response; + wl12xx_spi_read(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32)); - wl12xx_spi_read(wl, addr, &response, sizeof(u32)); - - return response; + return wl->buffer_32; } static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val) { - wl12xx_spi_write(wl, addr, &val, sizeof(u32)); + wl->buffer_32 = val; + wl12xx_spi_write(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32)); } #endif /* __WL12XX_SPI_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 48641437414..f252a118925 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -382,6 +382,8 @@ struct wl12xx { struct wl12xx_stats stats; struct wl12xx_debugfs debugfs; + + u32 buffer_32; }; int wl12xx_plt_start(struct wl12xx *wl); -- cgit v1.2.3-18-g5258 From c4f5c8521868789caaf704c9c2d523b40ccfcb02 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:14:34 +0300 Subject: wl12xx: fix error handling in wl12xx_probe() Resources were not freed properly in some cases. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index c6a45443971..6d27cd68767 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1274,13 +1274,15 @@ static int __devinit wl12xx_probe(struct spi_device *spi) wl->set_power = pdata->set_power; if (!wl->set_power) { wl12xx_error("set power function missing in platform data"); - return -ENODEV; + ret = -ENODEV; + goto out_free; } wl->irq = spi->irq; if (wl->irq < 0) { wl12xx_error("irq missing in platform data"); - return -ENODEV; + ret = -ENODEV; + goto out_free; } ret = request_irq(wl->irq, wl12xx_irq, 0, DRIVER_NAME, wl); -- cgit v1.2.3-18-g5258 From 8d47cdb617e0e76e05ea0f92fc164e53bf874b30 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:14:41 +0300 Subject: wl12xx: reserve buffer for partition command in struct wl12xx This is now DMA safe. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/spi.c | 22 ++++++++++++++-------- drivers/net/wireless/wl12xx/spi.h | 6 +++--- 2 files changed, 17 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index abdf171a47e..fb7c52c4d9c 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -167,24 +167,26 @@ void wl12xx_spi_init(struct wl12xx *wl) * | | * */ -void wl12xx_set_partition(struct wl12xx *wl, +int wl12xx_set_partition(struct wl12xx *wl, u32 mem_start, u32 mem_size, u32 reg_start, u32 reg_size) { - u8 tx_buf[sizeof(u32) + 2 * sizeof(struct wl12xx_partition)]; struct wl12xx_partition *partition; struct spi_transfer t; struct spi_message m; + size_t len, cmd_len; u32 *cmd; - size_t len; int addr; + cmd_len = sizeof(u32) + 2 * sizeof(struct wl12xx_partition); + cmd = kzalloc(cmd_len, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + spi_message_init(&m); memset(&t, 0, sizeof(t)); - memset(tx_buf, 0, sizeof(tx_buf)); - cmd = (u32 *) tx_buf; - partition = (struct wl12xx_partition *) (tx_buf + sizeof(u32)); + partition = (struct wl12xx_partition *) (cmd + 1); addr = HW_ACCESS_PART0_SIZE_ADDR; len = 2 * sizeof(struct wl12xx_partition); @@ -244,11 +246,15 @@ void wl12xx_set_partition(struct wl12xx *wl, wl->virtual_mem_addr = 0; wl->virtual_reg_addr = mem_size; - t.tx_buf = tx_buf; - t.len = sizeof(tx_buf); + t.tx_buf = cmd; + t.len = cmd_len; spi_message_add_tail(&t, &m); spi_sync(wl->spi, &m); + + kfree(cmd); + + return 0; } void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/spi.h index f3f18958657..7edb218ee76 100644 --- a/drivers/net/wireless/wl12xx/spi.h +++ b/drivers/net/wireless/wl12xx/spi.h @@ -88,9 +88,9 @@ void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val); /* INIT and RESET words */ void wl12xx_spi_reset(struct wl12xx *wl); void wl12xx_spi_init(struct wl12xx *wl); -void wl12xx_set_partition(struct wl12xx *wl, - u32 part_start, u32 part_size, - u32 reg_start, u32 reg_size); +int wl12xx_set_partition(struct wl12xx *wl, + u32 part_start, u32 part_size, + u32 reg_start, u32 reg_size); static inline u32 wl12xx_read32(struct wl12xx *wl, int addr) { -- cgit v1.2.3-18-g5258 From 56343a3cfdea4d341c7c13d26013024037eae602 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:14:47 +0300 Subject: wl12xx: allocate buffer spi read/write command buffer kzalloc() Needed for DMA safe transfers. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/spi.c | 34 +++++++++++++++++++--------------- drivers/net/wireless/wl12xx/wl12xx.h | 1 + 2 files changed, 20 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index fb7c52c4d9c..939274291a0 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -263,17 +263,19 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, struct spi_transfer t[3]; struct spi_message m; char busy_buf[TNETWIF_READ_OFFSET_BYTES]; - u32 cmd; + u32 *cmd; - cmd = 0; - cmd |= WSPI_CMD_READ; - cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - cmd |= addr & WSPI_CMD_BYTE_ADDR; + cmd = &wl->buffer_cmd; + + *cmd = 0; + *cmd |= WSPI_CMD_READ; + *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; spi_message_init(&m); memset(t, 0, sizeof(t)); - t[0].tx_buf = &cmd; + t[0].tx_buf = cmd; t[0].len = 4; spi_message_add_tail(&t[0], &m); @@ -290,7 +292,7 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, /* FIXME: check busy words */ - wl12xx_dump(DEBUG_SPI, "spi_read cmd -> ", &cmd, sizeof(cmd)); + wl12xx_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); wl12xx_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); } @@ -299,18 +301,20 @@ void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, { struct spi_transfer t[2]; struct spi_message m; - u32 cmd; + u32 *cmd; - cmd = 0; - cmd |= WSPI_CMD_WRITE; - cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - cmd |= addr & WSPI_CMD_BYTE_ADDR; + cmd = &wl->buffer_cmd; + + *cmd = 0; + *cmd |= WSPI_CMD_WRITE; + *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; spi_message_init(&m); memset(t, 0, sizeof(t)); - t[0].tx_buf = &cmd; - t[0].len = sizeof(cmd); + t[0].tx_buf = cmd; + t[0].len = sizeof(*cmd); spi_message_add_tail(&t[0], &m); t[1].tx_buf = buf; @@ -319,7 +323,7 @@ void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, spi_sync(wl->spi, &m); - wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", &cmd, sizeof(cmd)); + wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); wl12xx_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); } diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index f252a118925..58659356351 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -384,6 +384,7 @@ struct wl12xx { struct wl12xx_debugfs debugfs; u32 buffer_32; + u32 buffer_cmd; }; int wl12xx_plt_start(struct wl12xx *wl); -- cgit v1.2.3-18-g5258 From 5262c12d16334a37354c93d606bdb96499f7e5fc Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:14:55 +0300 Subject: wl12xx: allocate buffer the spi busy word from struct wl12xx Needed for DMA transfers. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/spi.c | 5 +++-- drivers/net/wireless/wl12xx/spi.h | 3 +-- drivers/net/wireless/wl12xx/wl12xx.h | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index 939274291a0..bcdcfbca77b 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -262,10 +262,11 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, { struct spi_transfer t[3]; struct spi_message m; - char busy_buf[TNETWIF_READ_OFFSET_BYTES]; + u8 *busy_buf; u32 *cmd; cmd = &wl->buffer_cmd; + busy_buf = wl->buffer_busyword; *cmd = 0; *cmd |= WSPI_CMD_READ; @@ -281,7 +282,7 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, /* Busy and non busy words read */ t[1].rx_buf = busy_buf; - t[1].len = TNETWIF_READ_OFFSET_BYTES; + t[1].len = WL12XX_BUSY_WORD_LEN; spi_message_add_tail(&t[1], &m); t[2].rx_buf = buf; diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/spi.h index 7edb218ee76..1a19557b0b4 100644 --- a/drivers/net/wireless/wl12xx/spi.h +++ b/drivers/net/wireless/wl12xx/spi.h @@ -65,9 +65,8 @@ #define WSPI_INIT_CMD_LEN 8 -#define TNETWIF_READ_OFFSET_BYTES 8 #define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ - ((TNETWIF_READ_OFFSET_BYTES - 4) / sizeof(u32)) + ((WL12XX_BUSY_WORD_LEN - 4) / sizeof(u32)) #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 58659356351..b81102098c7 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -105,6 +105,7 @@ enum { CFG_RX_AUTH_EN | \ CFG_RX_ASSOC_EN) +#define WL12XX_BUSY_WORD_LEN 8 struct boot_attr { u32 radio_type; @@ -385,6 +386,7 @@ struct wl12xx { u32 buffer_32; u32 buffer_cmd; + u8 buffer_busyword[WL12XX_BUSY_WORD_LEN]; }; int wl12xx_plt_start(struct wl12xx *wl); -- cgit v1.2.3-18-g5258 From 53d65423ba1bc3c38d53b27656395c632b073590 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:15:00 +0300 Subject: wl12xx: use wl12xx_mem_read32() to read the rx counter As a side effect the transfer is now DMA safe. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251.c index 1a352cf8c3e..e484a231e6e 100644 --- a/drivers/net/wireless/wl12xx/wl1251.c +++ b/drivers/net/wireless/wl12xx/wl1251.c @@ -415,8 +415,8 @@ static void wl1251_irq_work(struct work_struct *work) wl12xx_debug(DEBUG_IRQ, "intr: 0x%x", intr); if (wl->data_path) { - wl12xx_spi_mem_read(wl, wl->data_path->rx_control_addr, - &wl->rx_counter, sizeof(u32)); + wl->rx_counter = + wl12xx_mem_read32(wl, wl->data_path->rx_control_addr); /* We handle a frmware bug here */ switch ((wl->rx_counter - wl->rx_handled) & 0xf) { -- cgit v1.2.3-18-g5258 From 4721213fdde4456a36a5e63f02e5c2556a4df398 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:15:08 +0300 Subject: wl12xx: fix rx descriptor use Rx descriptor was incorrectly allocated from stack, use struct wl12xx instead. Needed for DMA transfers. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/main.c | 14 ++++++++++++++ drivers/net/wireless/wl12xx/rx.c | 11 ++++++----- drivers/net/wireless/wl12xx/wl12xx.h | 1 + 3 files changed, 21 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 6d27cd68767..3c6cd774192 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1261,6 +1261,13 @@ static int __devinit wl12xx_probe(struct spi_device *spi) wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE; wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE; + wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); + if (!wl->rx_descriptor) { + wl12xx_error("could not allocate memory for rx descriptor"); + ret = -ENOMEM; + goto out_free; + } + /* This is the only SPI value that we need to set here, the rest * comes from the board-peripherals file */ spi->bits_per_word = 32; @@ -1313,6 +1320,9 @@ static int __devinit wl12xx_probe(struct spi_device *spi) free_irq(wl->irq, wl); out_free: + kfree(wl->rx_descriptor); + wl->rx_descriptor = NULL; + ieee80211_free_hw(hw); return ret; @@ -1333,6 +1343,10 @@ static int __devexit wl12xx_remove(struct spi_device *spi) wl->fw = NULL; kfree(wl->nvs); wl->nvs = NULL; + + kfree(wl->rx_descriptor); + wl->rx_descriptor = NULL; + ieee80211_free_hw(wl->hw); return 0; diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 5fd916a0b25..7ac26ef209b 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -39,8 +39,7 @@ static void wl12xx_rx_header(struct wl12xx *wl, if (wl->rx_current_buffer) rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; - wl12xx_spi_mem_read(wl, rx_packet_ring_addr, desc, - sizeof(struct wl12xx_rx_descriptor)); + wl12xx_spi_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); } static void wl12xx_rx_status(struct wl12xx *wl, @@ -175,16 +174,18 @@ static void wl12xx_rx_ack(struct wl12xx *wl) void wl12xx_rx(struct wl12xx *wl) { - struct wl12xx_rx_descriptor rx_desc; + struct wl12xx_rx_descriptor *rx_desc; if (wl->state != WL12XX_STATE_ON) return; + rx_desc = wl->rx_descriptor; + /* We first read the frame's header */ - wl12xx_rx_header(wl, &rx_desc); + wl12xx_rx_header(wl, rx_desc); /* Now we can read the body */ - wl12xx_rx_body(wl, &rx_desc); + wl12xx_rx_body(wl, rx_desc); /* Finally, we need to ACK the RX */ wl12xx_rx_ack(wl); diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index b81102098c7..b87421461a7 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -387,6 +387,7 @@ struct wl12xx { u32 buffer_32; u32 buffer_cmd; u8 buffer_busyword[WL12XX_BUSY_WORD_LEN]; + struct wl12xx_rx_descriptor *rx_descriptor; }; int wl12xx_plt_start(struct wl12xx *wl); -- cgit v1.2.3-18-g5258 From 0628817accc305201fc0e1b7f020dec618c868cc Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 12 Jun 2009 14:15:13 +0300 Subject: wl12xx: removed chipset interrupt source configuration from fw wakeup The chipset source interrupt source configuration during fw wakeup was blocking interrupts on the wl1271. The configuration is effectively unused here as it is used to trigger an interrupt for the chipset wake-up event, which is not handled, or waited for, in the fw wakeup anyway on either wl1251 or wl1271. Signed-off-by: Juuso Oikarinen Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/main.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 3c6cd774192..950c4257f42 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -157,8 +157,6 @@ static void wl12xx_fw_wakeup(struct wl12xx *wl) if (!(elp_reg & ELPCTRL_WLAN_READY)) { wl12xx_warning("WLAN not ready"); - elp_reg = ELPCTRL_WAKE_UP_WLAN_READY; - wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); } } -- cgit v1.2.3-18-g5258 From a336e266640cd9f7be96b14ff09bbb37dfa646de Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 12 Jun 2009 14:15:22 +0300 Subject: wl12xx: add wl12xx_spi_reg_read() and wl12xx_spi_reg_write() functions In some cases we need to read more than 32 bits from the register area. These functions were added to support that, like the existing wl12xx_spi_mem_read() and wl12xx_spi_mem_write() already do for large blocks in the memory area. Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/spi.c | 18 ++++++++++++++++++ drivers/net/wireless/wl12xx/spi.h | 2 ++ 2 files changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index bcdcfbca77b..0d2b13a550e 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -348,6 +348,24 @@ void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, wl12xx_spi_write(wl, physical, buf, len); } +void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len) +{ + int physical; + + physical = wl12xx_translate_reg_addr(wl, addr); + + wl12xx_spi_read(wl, physical, buf, len); +} + +void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len) +{ + int physical; + + physical = wl12xx_translate_reg_addr(wl, addr); + + wl12xx_spi_write(wl, physical, buf, len); +} + u32 wl12xx_mem_read32(struct wl12xx *wl, int addr) { return wl12xx_read32(wl, wl12xx_translate_mem_addr(wl, addr)); diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/spi.h index 1a19557b0b4..0996e48af9f 100644 --- a/drivers/net/wireless/wl12xx/spi.h +++ b/drivers/net/wireless/wl12xx/spi.h @@ -81,6 +81,8 @@ u32 wl12xx_mem_read32(struct wl12xx *wl, int addr); void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val); /* Registers IO */ +void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len); +void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf,size_t len); u32 wl12xx_reg_read32(struct wl12xx *wl, int addr); void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val); -- cgit v1.2.3-18-g5258 From 0d1c38398fa8cd478a229b4428fb511f813376e8 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 12 Jun 2009 14:15:27 +0300 Subject: wl12xx: moved firmware version reading routine to chip-specific functions With WL1271, the firmware version can only be read right after booting the chip. To keep WL1251 aligned with this procedure, the code that reads the firmware version initially has been moved to a common place where it can be read from both chipsets. Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/boot.c | 2 ++ drivers/net/wireless/wl12xx/wl1251.c | 9 ++++++--- drivers/net/wireless/wl12xx/wl12xx.h | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 48ac08c429b..a6a26497dc1 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -269,6 +269,8 @@ int wl12xx_boot_run_firmware(struct wl12xx *wl) wl12xx_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", wl->cmd_box_addr, wl->event_box_addr); + wl->chip.op_fw_version(wl); + /* * in case of full asynchronous mode the firmware event must be * ready to receive event from the command mailbox diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251.c index e484a231e6e..b793325d619 100644 --- a/drivers/net/wireless/wl12xx/wl1251.c +++ b/drivers/net/wireless/wl12xx/wl1251.c @@ -288,9 +288,6 @@ static int wl1251_boot(struct wl12xx *wl) if (ret < 0) goto out; - /* Get and save the firmware version */ - wl12xx_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver)); - out: return ret; } @@ -394,6 +391,11 @@ static void wl1251_target_enable_interrupts(struct wl12xx *wl) wl12xx_boot_target_enable_interrupts(wl); } +static void wl1251_fw_version(struct wl12xx *wl) +{ + wl12xx_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver)); +} + static void wl1251_irq_work(struct work_struct *work) { u32 intr; @@ -709,6 +711,7 @@ void wl1251_setup(struct wl12xx *wl) wl->chip.op_target_enable_interrupts = wl1251_target_enable_interrupts; wl->chip.op_hw_init = wl1251_hw_init; wl->chip.op_plt_init = wl1251_plt_init; + wl->chip.op_fw_version = wl1251_fw_version; wl->chip.p_table = wl1251_part_table; wl->chip.acx_reg_table = wl1251_acx_reg_table; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index b87421461a7..32f62a699b2 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -163,6 +163,7 @@ struct wl12xx_chip { void (*op_target_enable_interrupts)(struct wl12xx *wl); int (*op_hw_init)(struct wl12xx *wl); int (*op_plt_init)(struct wl12xx *wl); + void (*op_fw_version)(struct wl12xx *wl); struct wl12xx_partition_set *p_table; enum wl12xx_acx_int_reg *acx_reg_table; -- cgit v1.2.3-18-g5258 From 27797d68f70b28e77e6d183910dc7b3d7505105d Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 12 Jun 2009 14:15:33 +0300 Subject: wl12xx: add support for new WL1271 chip revision This patch adds the code that recognizes the new WL1271 chip revision (PG 2.0). Full support for this chip is not yet implemented and support for WL1271 PG 1.0 is not guaranteed anymore. Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/main.c | 7 +++++++ drivers/net/wireless/wl12xx/wl12xx.h | 1 + 2 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 950c4257f42..73232db2b46 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -196,6 +196,13 @@ static int wl12xx_chip_wakeup(struct wl12xx *wl) break; case CHIP_ID_1271_PG10: + wl12xx_warning("chip id 0x%x (1271 PG10) support is obsolete", + wl->chip.id); + break; + case CHIP_ID_1271_PG20: + wl12xx_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", + wl->chip.id); + break; case CHIP_ID_1251_PG10: case CHIP_ID_1251_PG11: default: diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 32f62a699b2..c1d00c01f7d 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -412,5 +412,6 @@ int wl12xx_plt_stop(struct wl12xx *wl); #define CHIP_ID_1251_PG11 (0x7020101) #define CHIP_ID_1251_PG12 (0x7030101) #define CHIP_ID_1271_PG10 (0x4030101) +#define CHIP_ID_1271_PG20 (0x4030111) #endif -- cgit v1.2.3-18-g5258 From 052a625a859ceba68022862eeee70511f56483a5 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 12 Jun 2009 14:15:41 +0300 Subject: wl12xx: add support for fixed address in wl12xx_spi_read In the wl1271 implementation, we need to read memory from the register partition using fixed addresses. This change adds the possibility to request fixed address when calling wl12xx_spi_read() or wl12xx_spi_reg_read(). Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/spi.c | 12 ++++++++---- drivers/net/wireless/wl12xx/spi.h | 9 ++++++--- 2 files changed, 14 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index 0d2b13a550e..c3d5b737861 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -258,7 +258,7 @@ int wl12xx_set_partition(struct wl12xx *wl, } void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, - size_t len) + size_t len, bool fixed) { struct spi_transfer t[3]; struct spi_message m; @@ -273,6 +273,9 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; *cmd |= addr & WSPI_CMD_BYTE_ADDR; + if (fixed) + *cmd |= WSPI_CMD_FIXED; + spi_message_init(&m); memset(t, 0, sizeof(t)); @@ -335,7 +338,7 @@ void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, physical = wl12xx_translate_mem_addr(wl, addr); - wl12xx_spi_read(wl, physical, buf, len); + wl12xx_spi_read(wl, physical, buf, len, false); } void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, @@ -348,13 +351,14 @@ void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, wl12xx_spi_write(wl, physical, buf, len); } -void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len) +void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, + bool fixed) { int physical; physical = wl12xx_translate_reg_addr(wl, addr); - wl12xx_spi_read(wl, physical, buf, len); + wl12xx_spi_read(wl, physical, buf, len, fixed); } void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len) diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/spi.h index 0996e48af9f..30f9098925f 100644 --- a/drivers/net/wireless/wl12xx/spi.h +++ b/drivers/net/wireless/wl12xx/spi.h @@ -71,8 +71,9 @@ /* Raw target IO, address is not translated */ -void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, size_t len); void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, size_t len); +void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, + size_t len, bool fixed); /* Memory target IO, address is tranlated to partition 0 */ void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, size_t len); @@ -81,7 +82,8 @@ u32 wl12xx_mem_read32(struct wl12xx *wl, int addr); void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val); /* Registers IO */ -void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len); +void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, + bool fixed); void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf,size_t len); u32 wl12xx_reg_read32(struct wl12xx *wl, int addr); void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val); @@ -95,7 +97,8 @@ int wl12xx_set_partition(struct wl12xx *wl, static inline u32 wl12xx_read32(struct wl12xx *wl, int addr) { - wl12xx_spi_read(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32)); + wl12xx_spi_read(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); return wl->buffer_32; } -- cgit v1.2.3-18-g5258 From 9f483dc3d1b0b1695c8177c1dea2e721954b10fb Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 12 Jun 2009 14:15:46 +0300 Subject: wl12xx: pass the wake up condition when configuring the wake up event Changed the function wl12xx_acx_wake_up_conditions() so that it receives an argument with the actual wake up condition, instead of having WAKE_UP_EVENT_DTIM_BITMAP hardcoded. This is needed because we have to use different conditions in 1271. Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/acx.c | 5 +++-- drivers/net/wireless/wl12xx/acx.h | 3 ++- drivers/net/wireless/wl12xx/cmd.c | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index d0daf69558f..a6b894573f0 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -96,7 +96,8 @@ out: return ret; } -int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval) +int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 wake_up_event, + u8 listen_interval) { struct acx_wake_up_condition *wake_up; int ret; @@ -109,7 +110,7 @@ int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval) goto out; } - wake_up->wake_up_event = WAKE_UP_EVENT_DTIM_BITMAP; + wake_up->wake_up_event = wake_up_event; wake_up->listen_interval = listen_interval; ret = wl12xx_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 549e537d2e6..92e724875ad 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -1112,7 +1112,8 @@ int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, u8 mgt_rate, u8 mgt_mod); int wl12xx_acx_station_id(struct wl12xx *wl); int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id); -int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval); +int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 wake_up_event, + u8 listen_interval); int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth); int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len); int wl12xx_acx_tx_power(struct wl12xx *wl, int power); diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 0a02cdde935..d98941a1089 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -346,7 +346,8 @@ int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode) int ret = 0; /* FIXME: this should be in ps.c */ - ret = wl12xx_acx_wake_up_conditions(wl, wl->listen_int); + ret = wl12xx_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, + wl->listen_int); if (ret < 0) { wl12xx_error("couldn't set wake up conditions"); goto out; -- cgit v1.2.3-18-g5258 From 9f2ad4fb52916e58a1b75e9a30f42638655932d3 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 12 Jun 2009 14:15:54 +0300 Subject: wl12xx: Moved wl1251 TX path implementation into chip specific files Moved wl1251 TX path implementation into chip specific files to enable parallel implementation for the wl1271 TX path. Signed-off-by: Juuso Oikarinen Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/Makefile | 4 +- drivers/net/wireless/wl12xx/main.c | 13 +- drivers/net/wireless/wl12xx/tx.c | 557 -------------------------------- drivers/net/wireless/wl12xx/tx.h | 215 ------------ drivers/net/wireless/wl12xx/wl1251.c | 7 +- drivers/net/wireless/wl12xx/wl1251_tx.c | 557 ++++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1251_tx.h | 216 +++++++++++++ drivers/net/wireless/wl12xx/wl12xx.h | 1 + 8 files changed, 789 insertions(+), 781 deletions(-) delete mode 100644 drivers/net/wireless/wl12xx/tx.c delete mode 100644 drivers/net/wireless/wl12xx/tx.h create mode 100644 drivers/net/wireless/wl12xx/wl1251_tx.c create mode 100644 drivers/net/wireless/wl12xx/wl1251_tx.h (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index d43de27dc54..7e05ea37997 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,4 +1,4 @@ -wl12xx-objs = main.o spi.o event.o tx.o rx.o \ - ps.o cmd.o acx.o boot.o init.o wl1251.o \ +wl12xx-objs = main.o spi.o event.o wl1251_tx.o rx.o \ + ps.o cmd.o acx.o boot.o init.o wl1251.o \ debugfs.o obj-$(CONFIG_WL12XX) += wl12xx.o diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 73232db2b46..8feba36ff48 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -37,7 +37,7 @@ #include "wl1251.h" #include "spi.h" #include "event.h" -#include "tx.h" +#include "wl1251_tx.h" #include "rx.h" #include "ps.h" #include "init.h" @@ -303,6 +303,11 @@ static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) skb_queue_tail(&wl->tx_queue, skb); + /* + * The chip specific setup must run before the first TX packet - + * before that, the tx_work will not be initialized! + */ + schedule_work(&wl->tx_work); /* @@ -400,8 +405,7 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw) mutex_lock(&wl->mutex); /* let's notify MAC80211 about the remaining pending TX frames */ - wl12xx_tx_flush(wl); - + wl->chip.op_tx_flush(wl); wl12xx_power_off(wl); memset(wl->bssid, 0, ETH_ALEN); @@ -1176,7 +1180,7 @@ static int wl12xx_init_ieee80211(struct wl12xx *wl) { /* The tx descriptor buffer and the TKIP space */ wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) - + WL12XX_TKIP_IV_SPACE; + + WL1251_TKIP_IV_SPACE; /* unit us */ /* FIXME: find a proper value */ @@ -1226,7 +1230,6 @@ static int __devinit wl12xx_probe(struct spi_device *spi) skb_queue_head_init(&wl->tx_queue); - INIT_WORK(&wl->tx_work, wl12xx_tx_work); INIT_WORK(&wl->filter_work, wl12xx_filter_work); wl->channel = WL12XX_DEFAULT_CHANNEL; wl->scanning = false; diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c deleted file mode 100644 index 62145e205a8..00000000000 --- a/drivers/net/wireless/wl12xx/tx.c +++ /dev/null @@ -1,557 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include - -#include "wl12xx.h" -#include "reg.h" -#include "spi.h" -#include "tx.h" -#include "ps.h" - -static bool wl12xx_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count) -{ - int used, data_in_count; - - data_in_count = wl->data_in_count; - - if (data_in_count < data_out_count) - /* data_in_count has wrapped */ - data_in_count += TX_STATUS_DATA_OUT_COUNT_MASK + 1; - - used = data_in_count - data_out_count; - - WARN_ON(used < 0); - WARN_ON(used > DP_TX_PACKET_RING_CHUNK_NUM); - - if (used >= DP_TX_PACKET_RING_CHUNK_NUM) - return true; - else - return false; -} - -static int wl12xx_tx_path_status(struct wl12xx *wl) -{ - u32 status, addr, data_out_count; - bool busy; - - addr = wl->data_path->tx_control_addr; - status = wl12xx_mem_read32(wl, addr); - data_out_count = status & TX_STATUS_DATA_OUT_COUNT_MASK; - busy = wl12xx_tx_double_buffer_busy(wl, data_out_count); - - if (busy) - return -EBUSY; - - return 0; -} - -static int wl12xx_tx_id(struct wl12xx *wl, struct sk_buff *skb) -{ - int i; - - for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) - if (wl->tx_frames[i] == NULL) { - wl->tx_frames[i] = skb; - return i; - } - - return -EBUSY; -} - -static void wl12xx_tx_control(struct tx_double_buffer_desc *tx_hdr, - struct ieee80211_tx_info *control, u16 fc) -{ - *(u16 *)&tx_hdr->control = 0; - - tx_hdr->control.rate_policy = 0; - - /* 802.11 packets */ - tx_hdr->control.packet_type = 0; - - if (control->flags & IEEE80211_TX_CTL_NO_ACK) - tx_hdr->control.ack_policy = 1; - - tx_hdr->control.tx_complete = 1; - - if ((fc & IEEE80211_FTYPE_DATA) && - ((fc & IEEE80211_STYPE_QOS_DATA) || - (fc & IEEE80211_STYPE_QOS_NULLFUNC))) - tx_hdr->control.qos = 1; -} - -/* RSN + MIC = 8 + 8 = 16 bytes (worst case - AES). */ -#define MAX_MSDU_SECURITY_LENGTH 16 -#define MAX_MPDU_SECURITY_LENGTH 16 -#define WLAN_QOS_HDR_LEN 26 -#define MAX_MPDU_HEADER_AND_SECURITY (MAX_MPDU_SECURITY_LENGTH + \ - WLAN_QOS_HDR_LEN) -#define HW_BLOCK_SIZE 252 -static void wl12xx_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr) -{ - u16 payload_len, frag_threshold, mem_blocks; - u16 num_mpdus, mem_blocks_per_frag; - - frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; - tx_hdr->frag_threshold = cpu_to_le16(frag_threshold); - - payload_len = tx_hdr->length + MAX_MSDU_SECURITY_LENGTH; - - if (payload_len > frag_threshold) { - mem_blocks_per_frag = - ((frag_threshold + MAX_MPDU_HEADER_AND_SECURITY) / - HW_BLOCK_SIZE) + 1; - num_mpdus = payload_len / frag_threshold; - mem_blocks = num_mpdus * mem_blocks_per_frag; - payload_len -= num_mpdus * frag_threshold; - num_mpdus++; - - } else { - mem_blocks_per_frag = 0; - mem_blocks = 0; - num_mpdus = 1; - } - - mem_blocks += (payload_len / HW_BLOCK_SIZE) + 1; - - if (num_mpdus > 1) - mem_blocks += min(num_mpdus, mem_blocks_per_frag); - - tx_hdr->num_mem_blocks = mem_blocks; -} - -static int wl12xx_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb, - struct ieee80211_tx_info *control) -{ - struct tx_double_buffer_desc *tx_hdr; - struct ieee80211_rate *rate; - int id; - u16 fc; - - if (!skb) - return -EINVAL; - - id = wl12xx_tx_id(wl, skb); - if (id < 0) - return id; - - fc = *(u16 *)skb->data; - tx_hdr = (struct tx_double_buffer_desc *) skb_push(skb, - sizeof(*tx_hdr)); - - tx_hdr->length = cpu_to_le16(skb->len - sizeof(*tx_hdr)); - rate = ieee80211_get_tx_rate(wl->hw, control); - tx_hdr->rate = cpu_to_le16(rate->hw_value); - tx_hdr->expiry_time = cpu_to_le32(1 << 16); - tx_hdr->id = id; - - /* FIXME: how to get the correct queue id? */ - tx_hdr->xmit_queue = 0; - - wl12xx_tx_control(tx_hdr, control, fc); - wl12xx_tx_frag_block_num(tx_hdr); - - return 0; -} - -/* We copy the packet to the target */ -static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb, - struct ieee80211_tx_info *control) -{ - struct tx_double_buffer_desc *tx_hdr; - int len; - u32 addr; - - if (!skb) - return -EINVAL; - - tx_hdr = (struct tx_double_buffer_desc *) skb->data; - - if (control->control.hw_key && - control->control.hw_key->alg == ALG_TKIP) { - int hdrlen; - u16 fc; - u8 *pos; - - fc = *(u16 *)(skb->data + sizeof(*tx_hdr)); - tx_hdr->length += WL12XX_TKIP_IV_SPACE; - - hdrlen = ieee80211_hdrlen(fc); - - pos = skb_push(skb, WL12XX_TKIP_IV_SPACE); - memmove(pos, pos + WL12XX_TKIP_IV_SPACE, - sizeof(*tx_hdr) + hdrlen); - } - - /* Revisit. This is a workaround for getting non-aligned packets. - This happens at least with EAPOL packets from the user space. - Our DMA requires packets to be aligned on a 4-byte boundary. - */ - if (unlikely((long)skb->data & 0x03)) { - int offset = (4 - (long)skb->data) & 0x03; - wl12xx_debug(DEBUG_TX, "skb offset %d", offset); - - /* check whether the current skb can be used */ - if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { - unsigned char *src = skb->data; - - /* align the buffer on a 4-byte boundary */ - skb_reserve(skb, offset); - memmove(skb->data, src, skb->len); - } else { - wl12xx_info("No handler, fixme!"); - return -EINVAL; - } - } - - /* Our skb->data at this point includes the HW header */ - len = WL12XX_TX_ALIGN(skb->len); - - if (wl->data_in_count & 0x1) - addr = wl->data_path->tx_packet_ring_addr + - wl->data_path->tx_packet_ring_chunk_size; - else - addr = wl->data_path->tx_packet_ring_addr; - - wl12xx_spi_mem_write(wl, addr, skb->data, len); - - wl12xx_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x", - tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate); - - return 0; -} - -static void wl12xx_tx_trigger(struct wl12xx *wl) -{ - u32 data, addr; - - if (wl->data_in_count & 0x1) { - addr = ACX_REG_INTERRUPT_TRIG_H; - data = INTR_TRIG_TX_PROC1; - } else { - addr = ACX_REG_INTERRUPT_TRIG; - data = INTR_TRIG_TX_PROC0; - } - - wl12xx_reg_write32(wl, addr, data); - - /* Bumping data in */ - wl->data_in_count = (wl->data_in_count + 1) & - TX_STATUS_DATA_OUT_COUNT_MASK; -} - -/* caller must hold wl->mutex */ -static int wl12xx_tx_frame(struct wl12xx *wl, struct sk_buff *skb) -{ - struct ieee80211_tx_info *info; - int ret = 0; - u8 idx; - - info = IEEE80211_SKB_CB(skb); - - if (info->control.hw_key) { - idx = info->control.hw_key->hw_key_idx; - if (unlikely(wl->default_key != idx)) { - ret = wl12xx_acx_default_key(wl, idx); - if (ret < 0) - return ret; - } - } - - ret = wl12xx_tx_path_status(wl); - if (ret < 0) - return ret; - - ret = wl12xx_tx_fill_hdr(wl, skb, info); - if (ret < 0) - return ret; - - ret = wl12xx_tx_send_packet(wl, skb, info); - if (ret < 0) - return ret; - - wl12xx_tx_trigger(wl); - - return ret; -} - -void wl12xx_tx_work(struct work_struct *work) -{ - struct wl12xx *wl = container_of(work, struct wl12xx, tx_work); - struct sk_buff *skb; - bool woken_up = false; - int ret; - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL12XX_STATE_OFF)) - goto out; - - while ((skb = skb_dequeue(&wl->tx_queue))) { - if (!woken_up) { - wl12xx_ps_elp_wakeup(wl); - woken_up = true; - } - - ret = wl12xx_tx_frame(wl, skb); - if (ret == -EBUSY) { - /* firmware buffer is full, stop queues */ - wl12xx_debug(DEBUG_TX, "tx_work: fw buffer full, " - "stop queues"); - ieee80211_stop_queues(wl->hw); - wl->tx_queue_stopped = true; - skb_queue_head(&wl->tx_queue, skb); - goto out; - } else if (ret < 0) { - dev_kfree_skb(skb); - goto out; - } - } - -out: - if (woken_up) - wl12xx_ps_elp_sleep(wl); - - mutex_unlock(&wl->mutex); -} - -static const char *wl12xx_tx_parse_status(u8 status) -{ - /* 8 bit status field, one character per bit plus null */ - static char buf[9]; - int i = 0; - - memset(buf, 0, sizeof(buf)); - - if (status & TX_DMA_ERROR) - buf[i++] = 'm'; - if (status & TX_DISABLED) - buf[i++] = 'd'; - if (status & TX_RETRY_EXCEEDED) - buf[i++] = 'r'; - if (status & TX_TIMEOUT) - buf[i++] = 't'; - if (status & TX_KEY_NOT_FOUND) - buf[i++] = 'k'; - if (status & TX_ENCRYPT_FAIL) - buf[i++] = 'e'; - if (status & TX_UNAVAILABLE_PRIORITY) - buf[i++] = 'p'; - - /* bit 0 is unused apparently */ - - return buf; -} - -static void wl12xx_tx_packet_cb(struct wl12xx *wl, - struct tx_result *result) -{ - struct ieee80211_tx_info *info; - struct sk_buff *skb; - int hdrlen, ret; - u8 *frame; - - skb = wl->tx_frames[result->id]; - if (skb == NULL) { - wl12xx_error("SKB for packet %d is NULL", result->id); - return; - } - - info = IEEE80211_SKB_CB(skb); - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && - (result->status == TX_SUCCESS)) - info->flags |= IEEE80211_TX_STAT_ACK; - - info->status.rates[0].count = result->ack_failures + 1; - wl->stats.retry_count += result->ack_failures; - - /* - * We have to remove our private TX header before pushing - * the skb back to mac80211. - */ - frame = skb_pull(skb, sizeof(struct tx_double_buffer_desc)); - if (info->control.hw_key && - info->control.hw_key->alg == ALG_TKIP) { - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - memmove(frame + WL12XX_TKIP_IV_SPACE, frame, hdrlen); - skb_pull(skb, WL12XX_TKIP_IV_SPACE); - } - - wl12xx_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" - " status 0x%x (%s)", - result->id, skb, result->ack_failures, result->rate, - result->status, wl12xx_tx_parse_status(result->status)); - - - ieee80211_tx_status(wl->hw, skb); - - wl->tx_frames[result->id] = NULL; - - if (wl->tx_queue_stopped) { - wl12xx_debug(DEBUG_TX, "cb: queue was stopped"); - - skb = skb_dequeue(&wl->tx_queue); - - /* The skb can be NULL because tx_work might have been - scheduled before the queue was stopped making the - queue empty */ - - if (skb) { - ret = wl12xx_tx_frame(wl, skb); - if (ret == -EBUSY) { - /* firmware buffer is still full */ - wl12xx_debug(DEBUG_TX, "cb: fw buffer " - "still full"); - skb_queue_head(&wl->tx_queue, skb); - return; - } else if (ret < 0) { - dev_kfree_skb(skb); - return; - } - } - - wl12xx_debug(DEBUG_TX, "cb: waking queues"); - ieee80211_wake_queues(wl->hw); - wl->tx_queue_stopped = false; - } -} - -/* Called upon reception of a TX complete interrupt */ -void wl12xx_tx_complete(struct wl12xx *wl) -{ - int i, result_index, num_complete = 0; - struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr; - - if (unlikely(wl->state != WL12XX_STATE_ON)) - return; - - /* First we read the result */ - wl12xx_spi_mem_read(wl, wl->data_path->tx_complete_addr, - result, sizeof(result)); - - result_index = wl->next_tx_complete; - - for (i = 0; i < ARRAY_SIZE(result); i++) { - result_ptr = &result[result_index]; - - if (result_ptr->done_1 == 1 && - result_ptr->done_2 == 1) { - wl12xx_tx_packet_cb(wl, result_ptr); - - result_ptr->done_1 = 0; - result_ptr->done_2 = 0; - - result_index = (result_index + 1) & - (FW_TX_CMPLT_BLOCK_SIZE - 1); - num_complete++; - } else { - break; - } - } - - /* Every completed frame needs to be acknowledged */ - if (num_complete) { - /* - * If we've wrapped, we have to clear - * the results in 2 steps. - */ - if (result_index > wl->next_tx_complete) { - /* Only 1 write is needed */ - wl12xx_spi_mem_write(wl, - wl->data_path->tx_complete_addr + - (wl->next_tx_complete * - sizeof(struct tx_result)), - &result[wl->next_tx_complete], - num_complete * - sizeof(struct tx_result)); - - - } else if (result_index < wl->next_tx_complete) { - /* 2 writes are needed */ - wl12xx_spi_mem_write(wl, - wl->data_path->tx_complete_addr + - (wl->next_tx_complete * - sizeof(struct tx_result)), - &result[wl->next_tx_complete], - (FW_TX_CMPLT_BLOCK_SIZE - - wl->next_tx_complete) * - sizeof(struct tx_result)); - - wl12xx_spi_mem_write(wl, - wl->data_path->tx_complete_addr, - result, - (num_complete - - FW_TX_CMPLT_BLOCK_SIZE + - wl->next_tx_complete) * - sizeof(struct tx_result)); - - } else { - /* We have to write the whole array */ - wl12xx_spi_mem_write(wl, - wl->data_path->tx_complete_addr, - result, - FW_TX_CMPLT_BLOCK_SIZE * - sizeof(struct tx_result)); - } - - } - - wl->next_tx_complete = result_index; -} - -/* caller must hold wl->mutex */ -void wl12xx_tx_flush(struct wl12xx *wl) -{ - int i; - struct sk_buff *skb; - struct ieee80211_tx_info *info; - - /* TX failure */ -/* control->flags = 0; FIXME */ - - while ((skb = skb_dequeue(&wl->tx_queue))) { - info = IEEE80211_SKB_CB(skb); - - wl12xx_debug(DEBUG_TX, "flushing skb 0x%p", skb); - - if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) - continue; - - ieee80211_tx_status(wl->hw, skb); - } - - for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) - if (wl->tx_frames[i] != NULL) { - skb = wl->tx_frames[i]; - info = IEEE80211_SKB_CB(skb); - - if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) - continue; - - ieee80211_tx_status(wl->hw, skb); - wl->tx_frames[i] = NULL; - } -} diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h deleted file mode 100644 index dc82691f4c1..00000000000 --- a/drivers/net/wireless/wl12xx/tx.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL12XX_TX_H__ -#define __WL12XX_TX_H__ - -#include - -/* - * - * TX PATH - * - * The Tx path uses a double buffer and a tx_control structure, each located - * at a fixed address in the device's memory. On startup, the host retrieves - * the pointers to these addresses. A double buffer allows for continuous data - * flow towards the device. The host keeps track of which buffer is available - * and alternates between these two buffers on a per packet basis. - * - * The size of each of the two buffers is large enough to hold the longest - * 802.3 packet - maximum size Ethernet packet + header + descriptor. - * TX complete indication will be received a-synchronously in a TX done cyclic - * buffer which is composed of 16 tx_result descriptors structures and is used - * in a cyclic manner. - * - * The TX (HOST) procedure is as follows: - * 1. Read the Tx path status, that will give the data_out_count. - * 2. goto 1, if not possible. - * i.e. if data_in_count - data_out_count >= HwBuffer size (2 for double - * buffer). - * 3. Copy the packet (preceded by double_buffer_desc), if possible. - * i.e. if data_in_count - data_out_count < HwBuffer size (2 for double - * buffer). - * 4. increment data_in_count. - * 5. Inform the firmware by generating a firmware internal interrupt. - * 6. FW will increment data_out_count after it reads the buffer. - * - * The TX Complete procedure: - * 1. To get a TX complete indication the host enables the tx_complete flag in - * the TX descriptor Structure. - * 2. For each packet with a Tx Complete field set, the firmware adds the - * transmit results to the cyclic buffer (txDoneRing) and sets both done_1 - * and done_2 to 1 to indicate driver ownership. - * 3. The firmware sends a Tx Complete interrupt to the host to trigger the - * host to process the new data. Note: interrupt will be send per packet if - * TX complete indication was requested in tx_control or per crossing - * aggregation threshold. - * 4. After receiving the Tx Complete interrupt, the host reads the - * TxDescriptorDone information in a cyclic manner and clears both done_1 - * and done_2 fields. - * - */ - -#define TX_COMPLETE_REQUIRED_BIT 0x80 -#define TX_STATUS_DATA_OUT_COUNT_MASK 0xf -#define WL12XX_TX_ALIGN_TO 4 -#define WL12XX_TX_ALIGN(len) (((len) + WL12XX_TX_ALIGN_TO - 1) & \ - ~(WL12XX_TX_ALIGN_TO - 1)) -#define WL12XX_TKIP_IV_SPACE 4 - -struct tx_control { - /* Rate Policy (class) index */ - unsigned rate_policy:3; - - /* When set, no ack policy is expected */ - unsigned ack_policy:1; - - /* - * Packet type: - * 0 -> 802.11 - * 1 -> 802.3 - * 2 -> IP - * 3 -> raw codec - */ - unsigned packet_type:2; - - /* If set, this is a QoS-Null or QoS-Data frame */ - unsigned qos:1; - - /* - * If set, the target triggers the tx complete INT - * upon frame sending completion. - */ - unsigned tx_complete:1; - - /* 2 bytes padding before packet header */ - unsigned xfer_pad:1; - - unsigned reserved:7; -} __attribute__ ((packed)); - - -struct tx_double_buffer_desc { - /* Length of payload, including headers. */ - u16 length; - - /* - * A bit mask that specifies the initial rate to be used - * Possible values are: - * 0x0001 - 1Mbits - * 0x0002 - 2Mbits - * 0x0004 - 5.5Mbits - * 0x0008 - 6Mbits - * 0x0010 - 9Mbits - * 0x0020 - 11Mbits - * 0x0040 - 12Mbits - * 0x0080 - 18Mbits - * 0x0100 - 22Mbits - * 0x0200 - 24Mbits - * 0x0400 - 36Mbits - * 0x0800 - 48Mbits - * 0x1000 - 54Mbits - */ - u16 rate; - - /* Time in us that a packet can spend in the target */ - u32 expiry_time; - - /* index of the TX queue used for this packet */ - u8 xmit_queue; - - /* Used to identify a packet */ - u8 id; - - struct tx_control control; - - /* - * The FW should cut the packet into fragments - * of this size. - */ - u16 frag_threshold; - - /* Numbers of HW queue blocks to be allocated */ - u8 num_mem_blocks; - - u8 reserved; -} __attribute__ ((packed)); - -enum { - TX_SUCCESS = 0, - TX_DMA_ERROR = BIT(7), - TX_DISABLED = BIT(6), - TX_RETRY_EXCEEDED = BIT(5), - TX_TIMEOUT = BIT(4), - TX_KEY_NOT_FOUND = BIT(3), - TX_ENCRYPT_FAIL = BIT(2), - TX_UNAVAILABLE_PRIORITY = BIT(1), -}; - -struct tx_result { - /* - * Ownership synchronization between the host and - * the firmware. If done_1 and done_2 are cleared, - * owned by the FW (no info ready). - */ - u8 done_1; - - /* same as double_buffer_desc->id */ - u8 id; - - /* - * Total air access duration consumed by this - * packet, including all retries and overheads. - */ - u16 medium_usage; - - /* Total media delay (from 1st EDCA AIFS counter until TX Complete). */ - u32 medium_delay; - - /* Time between host xfer and tx complete */ - u32 fw_hnadling_time; - - /* The LS-byte of the last TKIP sequence number. */ - u8 lsb_seq_num; - - /* Retry count */ - u8 ack_failures; - - /* At which rate we got a ACK */ - u16 rate; - - u16 reserved; - - /* TX_* */ - u8 status; - - /* See done_1 */ - u8 done_2; -} __attribute__ ((packed)); - -void wl12xx_tx_work(struct work_struct *work); -void wl12xx_tx_complete(struct wl12xx *wl); -void wl12xx_tx_flush(struct wl12xx *wl); - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251.c index b793325d619..903624a540a 100644 --- a/drivers/net/wireless/wl12xx/wl1251.c +++ b/drivers/net/wireless/wl12xx/wl1251.c @@ -30,7 +30,7 @@ #include "boot.h" #include "event.h" #include "acx.h" -#include "tx.h" +#include "wl1251_tx.h" #include "rx.h" #include "ps.h" #include "init.h" @@ -471,7 +471,7 @@ static void wl1251_irq_work(struct work_struct *work) if (intr & WL1251_ACX_INTR_TX_RESULT) { wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); - wl12xx_tx_complete(wl); + wl1251_tx_complete(wl); } if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { @@ -712,9 +712,12 @@ void wl1251_setup(struct wl12xx *wl) wl->chip.op_hw_init = wl1251_hw_init; wl->chip.op_plt_init = wl1251_plt_init; wl->chip.op_fw_version = wl1251_fw_version; + wl->chip.op_tx_flush = wl1251_tx_flush; wl->chip.p_table = wl1251_part_table; wl->chip.acx_reg_table = wl1251_acx_reg_table; INIT_WORK(&wl->irq_work, wl1251_irq_work); + INIT_WORK(&wl->tx_work, wl1251_tx_work); + } diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c new file mode 100644 index 00000000000..c42c43de657 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c @@ -0,0 +1,557 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "wl12xx.h" +#include "reg.h" +#include "spi.h" +#include "wl1251_tx.h" +#include "ps.h" + +static bool wl1251_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count) +{ + int used, data_in_count; + + data_in_count = wl->data_in_count; + + if (data_in_count < data_out_count) + /* data_in_count has wrapped */ + data_in_count += TX_STATUS_DATA_OUT_COUNT_MASK + 1; + + used = data_in_count - data_out_count; + + WARN_ON(used < 0); + WARN_ON(used > DP_TX_PACKET_RING_CHUNK_NUM); + + if (used >= DP_TX_PACKET_RING_CHUNK_NUM) + return true; + else + return false; +} + +static int wl1251_tx_path_status(struct wl12xx *wl) +{ + u32 status, addr, data_out_count; + bool busy; + + addr = wl->data_path->tx_control_addr; + status = wl12xx_mem_read32(wl, addr); + data_out_count = status & TX_STATUS_DATA_OUT_COUNT_MASK; + busy = wl1251_tx_double_buffer_busy(wl, data_out_count); + + if (busy) + return -EBUSY; + + return 0; +} + +static int wl1251_tx_id(struct wl12xx *wl, struct sk_buff *skb) +{ + int i; + + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + if (wl->tx_frames[i] == NULL) { + wl->tx_frames[i] = skb; + return i; + } + + return -EBUSY; +} + +static void wl1251_tx_control(struct tx_double_buffer_desc *tx_hdr, + struct ieee80211_tx_info *control, u16 fc) +{ + *(u16 *)&tx_hdr->control = 0; + + tx_hdr->control.rate_policy = 0; + + /* 802.11 packets */ + tx_hdr->control.packet_type = 0; + + if (control->flags & IEEE80211_TX_CTL_NO_ACK) + tx_hdr->control.ack_policy = 1; + + tx_hdr->control.tx_complete = 1; + + if ((fc & IEEE80211_FTYPE_DATA) && + ((fc & IEEE80211_STYPE_QOS_DATA) || + (fc & IEEE80211_STYPE_QOS_NULLFUNC))) + tx_hdr->control.qos = 1; +} + +/* RSN + MIC = 8 + 8 = 16 bytes (worst case - AES). */ +#define MAX_MSDU_SECURITY_LENGTH 16 +#define MAX_MPDU_SECURITY_LENGTH 16 +#define WLAN_QOS_HDR_LEN 26 +#define MAX_MPDU_HEADER_AND_SECURITY (MAX_MPDU_SECURITY_LENGTH + \ + WLAN_QOS_HDR_LEN) +#define HW_BLOCK_SIZE 252 +static void wl1251_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr) +{ + u16 payload_len, frag_threshold, mem_blocks; + u16 num_mpdus, mem_blocks_per_frag; + + frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; + tx_hdr->frag_threshold = cpu_to_le16(frag_threshold); + + payload_len = tx_hdr->length + MAX_MSDU_SECURITY_LENGTH; + + if (payload_len > frag_threshold) { + mem_blocks_per_frag = + ((frag_threshold + MAX_MPDU_HEADER_AND_SECURITY) / + HW_BLOCK_SIZE) + 1; + num_mpdus = payload_len / frag_threshold; + mem_blocks = num_mpdus * mem_blocks_per_frag; + payload_len -= num_mpdus * frag_threshold; + num_mpdus++; + + } else { + mem_blocks_per_frag = 0; + mem_blocks = 0; + num_mpdus = 1; + } + + mem_blocks += (payload_len / HW_BLOCK_SIZE) + 1; + + if (num_mpdus > 1) + mem_blocks += min(num_mpdus, mem_blocks_per_frag); + + tx_hdr->num_mem_blocks = mem_blocks; +} + +static int wl1251_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb, + struct ieee80211_tx_info *control) +{ + struct tx_double_buffer_desc *tx_hdr; + struct ieee80211_rate *rate; + int id; + u16 fc; + + if (!skb) + return -EINVAL; + + id = wl1251_tx_id(wl, skb); + if (id < 0) + return id; + + fc = *(u16 *)skb->data; + tx_hdr = (struct tx_double_buffer_desc *) skb_push(skb, + sizeof(*tx_hdr)); + + tx_hdr->length = cpu_to_le16(skb->len - sizeof(*tx_hdr)); + rate = ieee80211_get_tx_rate(wl->hw, control); + tx_hdr->rate = cpu_to_le16(rate->hw_value); + tx_hdr->expiry_time = cpu_to_le32(1 << 16); + tx_hdr->id = id; + + /* FIXME: how to get the correct queue id? */ + tx_hdr->xmit_queue = 0; + + wl1251_tx_control(tx_hdr, control, fc); + wl1251_tx_frag_block_num(tx_hdr); + + return 0; +} + +/* We copy the packet to the target */ +static int wl1251_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb, + struct ieee80211_tx_info *control) +{ + struct tx_double_buffer_desc *tx_hdr; + int len; + u32 addr; + + if (!skb) + return -EINVAL; + + tx_hdr = (struct tx_double_buffer_desc *) skb->data; + + if (control->control.hw_key && + control->control.hw_key->alg == ALG_TKIP) { + int hdrlen; + u16 fc; + u8 *pos; + + fc = *(u16 *)(skb->data + sizeof(*tx_hdr)); + tx_hdr->length += WL1251_TKIP_IV_SPACE; + + hdrlen = ieee80211_hdrlen(fc); + + pos = skb_push(skb, WL1251_TKIP_IV_SPACE); + memmove(pos, pos + WL1251_TKIP_IV_SPACE, + sizeof(*tx_hdr) + hdrlen); + } + + /* Revisit. This is a workaround for getting non-aligned packets. + This happens at least with EAPOL packets from the user space. + Our DMA requires packets to be aligned on a 4-byte boundary. + */ + if (unlikely((long)skb->data & 0x03)) { + int offset = (4 - (long)skb->data) & 0x03; + wl12xx_debug(DEBUG_TX, "skb offset %d", offset); + + /* check whether the current skb can be used */ + if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { + unsigned char *src = skb->data; + + /* align the buffer on a 4-byte boundary */ + skb_reserve(skb, offset); + memmove(skb->data, src, skb->len); + } else { + wl12xx_info("No handler, fixme!"); + return -EINVAL; + } + } + + /* Our skb->data at this point includes the HW header */ + len = WL1251_TX_ALIGN(skb->len); + + if (wl->data_in_count & 0x1) + addr = wl->data_path->tx_packet_ring_addr + + wl->data_path->tx_packet_ring_chunk_size; + else + addr = wl->data_path->tx_packet_ring_addr; + + wl12xx_spi_mem_write(wl, addr, skb->data, len); + + wl12xx_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x", + tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate); + + return 0; +} + +static void wl1251_tx_trigger(struct wl12xx *wl) +{ + u32 data, addr; + + if (wl->data_in_count & 0x1) { + addr = ACX_REG_INTERRUPT_TRIG_H; + data = INTR_TRIG_TX_PROC1; + } else { + addr = ACX_REG_INTERRUPT_TRIG; + data = INTR_TRIG_TX_PROC0; + } + + wl12xx_reg_write32(wl, addr, data); + + /* Bumping data in */ + wl->data_in_count = (wl->data_in_count + 1) & + TX_STATUS_DATA_OUT_COUNT_MASK; +} + +/* caller must hold wl->mutex */ +static int wl1251_tx_frame(struct wl12xx *wl, struct sk_buff *skb) +{ + struct ieee80211_tx_info *info; + int ret = 0; + u8 idx; + + info = IEEE80211_SKB_CB(skb); + + if (info->control.hw_key) { + idx = info->control.hw_key->hw_key_idx; + if (unlikely(wl->default_key != idx)) { + ret = wl12xx_acx_default_key(wl, idx); + if (ret < 0) + return ret; + } + } + + ret = wl1251_tx_path_status(wl); + if (ret < 0) + return ret; + + ret = wl1251_tx_fill_hdr(wl, skb, info); + if (ret < 0) + return ret; + + ret = wl1251_tx_send_packet(wl, skb, info); + if (ret < 0) + return ret; + + wl1251_tx_trigger(wl); + + return ret; +} + +void wl1251_tx_work(struct work_struct *work) +{ + struct wl12xx *wl = container_of(work, struct wl12xx, tx_work); + struct sk_buff *skb; + bool woken_up = false; + int ret; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL12XX_STATE_OFF)) + goto out; + + while ((skb = skb_dequeue(&wl->tx_queue))) { + if (!woken_up) { + wl12xx_ps_elp_wakeup(wl); + woken_up = true; + } + + ret = wl1251_tx_frame(wl, skb); + if (ret == -EBUSY) { + /* firmware buffer is full, stop queues */ + wl12xx_debug(DEBUG_TX, "tx_work: fw buffer full, " + "stop queues"); + ieee80211_stop_queues(wl->hw); + wl->tx_queue_stopped = true; + skb_queue_head(&wl->tx_queue, skb); + goto out; + } else if (ret < 0) { + dev_kfree_skb(skb); + goto out; + } + } + +out: + if (woken_up) + wl12xx_ps_elp_sleep(wl); + + mutex_unlock(&wl->mutex); +} + +static const char *wl1251_tx_parse_status(u8 status) +{ + /* 8 bit status field, one character per bit plus null */ + static char buf[9]; + int i = 0; + + memset(buf, 0, sizeof(buf)); + + if (status & TX_DMA_ERROR) + buf[i++] = 'm'; + if (status & TX_DISABLED) + buf[i++] = 'd'; + if (status & TX_RETRY_EXCEEDED) + buf[i++] = 'r'; + if (status & TX_TIMEOUT) + buf[i++] = 't'; + if (status & TX_KEY_NOT_FOUND) + buf[i++] = 'k'; + if (status & TX_ENCRYPT_FAIL) + buf[i++] = 'e'; + if (status & TX_UNAVAILABLE_PRIORITY) + buf[i++] = 'p'; + + /* bit 0 is unused apparently */ + + return buf; +} + +static void wl1251_tx_packet_cb(struct wl12xx *wl, + struct tx_result *result) +{ + struct ieee80211_tx_info *info; + struct sk_buff *skb; + int hdrlen, ret; + u8 *frame; + + skb = wl->tx_frames[result->id]; + if (skb == NULL) { + wl12xx_error("SKB for packet %d is NULL", result->id); + return; + } + + info = IEEE80211_SKB_CB(skb); + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (result->status == TX_SUCCESS)) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.rates[0].count = result->ack_failures + 1; + wl->stats.retry_count += result->ack_failures; + + /* + * We have to remove our private TX header before pushing + * the skb back to mac80211. + */ + frame = skb_pull(skb, sizeof(struct tx_double_buffer_desc)); + if (info->control.hw_key && + info->control.hw_key->alg == ALG_TKIP) { + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + memmove(frame + WL1251_TKIP_IV_SPACE, frame, hdrlen); + skb_pull(skb, WL1251_TKIP_IV_SPACE); + } + + wl12xx_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" + " status 0x%x (%s)", + result->id, skb, result->ack_failures, result->rate, + result->status, wl1251_tx_parse_status(result->status)); + + + ieee80211_tx_status(wl->hw, skb); + + wl->tx_frames[result->id] = NULL; + + if (wl->tx_queue_stopped) { + wl12xx_debug(DEBUG_TX, "cb: queue was stopped"); + + skb = skb_dequeue(&wl->tx_queue); + + /* The skb can be NULL because tx_work might have been + scheduled before the queue was stopped making the + queue empty */ + + if (skb) { + ret = wl1251_tx_frame(wl, skb); + if (ret == -EBUSY) { + /* firmware buffer is still full */ + wl12xx_debug(DEBUG_TX, "cb: fw buffer " + "still full"); + skb_queue_head(&wl->tx_queue, skb); + return; + } else if (ret < 0) { + dev_kfree_skb(skb); + return; + } + } + + wl12xx_debug(DEBUG_TX, "cb: waking queues"); + ieee80211_wake_queues(wl->hw); + wl->tx_queue_stopped = false; + } +} + +/* Called upon reception of a TX complete interrupt */ +void wl1251_tx_complete(struct wl12xx *wl) +{ + int i, result_index, num_complete = 0; + struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr; + + if (unlikely(wl->state != WL12XX_STATE_ON)) + return; + + /* First we read the result */ + wl12xx_spi_mem_read(wl, wl->data_path->tx_complete_addr, + result, sizeof(result)); + + result_index = wl->next_tx_complete; + + for (i = 0; i < ARRAY_SIZE(result); i++) { + result_ptr = &result[result_index]; + + if (result_ptr->done_1 == 1 && + result_ptr->done_2 == 1) { + wl1251_tx_packet_cb(wl, result_ptr); + + result_ptr->done_1 = 0; + result_ptr->done_2 = 0; + + result_index = (result_index + 1) & + (FW_TX_CMPLT_BLOCK_SIZE - 1); + num_complete++; + } else { + break; + } + } + + /* Every completed frame needs to be acknowledged */ + if (num_complete) { + /* + * If we've wrapped, we have to clear + * the results in 2 steps. + */ + if (result_index > wl->next_tx_complete) { + /* Only 1 write is needed */ + wl12xx_spi_mem_write(wl, + wl->data_path->tx_complete_addr + + (wl->next_tx_complete * + sizeof(struct tx_result)), + &result[wl->next_tx_complete], + num_complete * + sizeof(struct tx_result)); + + + } else if (result_index < wl->next_tx_complete) { + /* 2 writes are needed */ + wl12xx_spi_mem_write(wl, + wl->data_path->tx_complete_addr + + (wl->next_tx_complete * + sizeof(struct tx_result)), + &result[wl->next_tx_complete], + (FW_TX_CMPLT_BLOCK_SIZE - + wl->next_tx_complete) * + sizeof(struct tx_result)); + + wl12xx_spi_mem_write(wl, + wl->data_path->tx_complete_addr, + result, + (num_complete - + FW_TX_CMPLT_BLOCK_SIZE + + wl->next_tx_complete) * + sizeof(struct tx_result)); + + } else { + /* We have to write the whole array */ + wl12xx_spi_mem_write(wl, + wl->data_path->tx_complete_addr, + result, + FW_TX_CMPLT_BLOCK_SIZE * + sizeof(struct tx_result)); + } + + } + + wl->next_tx_complete = result_index; +} + +/* caller must hold wl->mutex */ +void wl1251_tx_flush(struct wl12xx *wl) +{ + int i; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + + /* TX failure */ +/* control->flags = 0; FIXME */ + + while ((skb = skb_dequeue(&wl->tx_queue))) { + info = IEEE80211_SKB_CB(skb); + + wl12xx_debug(DEBUG_TX, "flushing skb 0x%p", skb); + + if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) + continue; + + ieee80211_tx_status(wl->hw, skb); + } + + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + if (wl->tx_frames[i] != NULL) { + skb = wl->tx_frames[i]; + info = IEEE80211_SKB_CB(skb); + + if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) + continue; + + ieee80211_tx_status(wl->hw, skb); + wl->tx_frames[i] = NULL; + } +} diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.h b/drivers/net/wireless/wl12xx/wl1251_tx.h new file mode 100644 index 00000000000..a5d4c825905 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_tx.h @@ -0,0 +1,216 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1251_TX_H__ +#define __WL1251_TX_H__ + +#include + +/* + * + * TX PATH + * + * The Tx path uses a double buffer and a tx_control structure, each located + * at a fixed address in the device's memory. On startup, the host retrieves + * the pointers to these addresses. A double buffer allows for continuous data + * flow towards the device. The host keeps track of which buffer is available + * and alternates between these two buffers on a per packet basis. + * + * The size of each of the two buffers is large enough to hold the longest + * 802.3 packet - maximum size Ethernet packet + header + descriptor. + * TX complete indication will be received a-synchronously in a TX done cyclic + * buffer which is composed of 16 tx_result descriptors structures and is used + * in a cyclic manner. + * + * The TX (HOST) procedure is as follows: + * 1. Read the Tx path status, that will give the data_out_count. + * 2. goto 1, if not possible. + * i.e. if data_in_count - data_out_count >= HwBuffer size (2 for double + * buffer). + * 3. Copy the packet (preceded by double_buffer_desc), if possible. + * i.e. if data_in_count - data_out_count < HwBuffer size (2 for double + * buffer). + * 4. increment data_in_count. + * 5. Inform the firmware by generating a firmware internal interrupt. + * 6. FW will increment data_out_count after it reads the buffer. + * + * The TX Complete procedure: + * 1. To get a TX complete indication the host enables the tx_complete flag in + * the TX descriptor Structure. + * 2. For each packet with a Tx Complete field set, the firmware adds the + * transmit results to the cyclic buffer (txDoneRing) and sets both done_1 + * and done_2 to 1 to indicate driver ownership. + * 3. The firmware sends a Tx Complete interrupt to the host to trigger the + * host to process the new data. Note: interrupt will be send per packet if + * TX complete indication was requested in tx_control or per crossing + * aggregation threshold. + * 4. After receiving the Tx Complete interrupt, the host reads the + * TxDescriptorDone information in a cyclic manner and clears both done_1 + * and done_2 fields. + * + */ + +#define TX_COMPLETE_REQUIRED_BIT 0x80 +#define TX_STATUS_DATA_OUT_COUNT_MASK 0xf + +#define WL1251_TX_ALIGN_TO 4 +#define WL1251_TX_ALIGN(len) (((len) + WL1251_TX_ALIGN_TO - 1) & \ + ~(WL1251_TX_ALIGN_TO - 1)) +#define WL1251_TKIP_IV_SPACE 4 + +struct tx_control { + /* Rate Policy (class) index */ + unsigned rate_policy:3; + + /* When set, no ack policy is expected */ + unsigned ack_policy:1; + + /* + * Packet type: + * 0 -> 802.11 + * 1 -> 802.3 + * 2 -> IP + * 3 -> raw codec + */ + unsigned packet_type:2; + + /* If set, this is a QoS-Null or QoS-Data frame */ + unsigned qos:1; + + /* + * If set, the target triggers the tx complete INT + * upon frame sending completion. + */ + unsigned tx_complete:1; + + /* 2 bytes padding before packet header */ + unsigned xfer_pad:1; + + unsigned reserved:7; +} __attribute__ ((packed)); + + +struct tx_double_buffer_desc { + /* Length of payload, including headers. */ + u16 length; + + /* + * A bit mask that specifies the initial rate to be used + * Possible values are: + * 0x0001 - 1Mbits + * 0x0002 - 2Mbits + * 0x0004 - 5.5Mbits + * 0x0008 - 6Mbits + * 0x0010 - 9Mbits + * 0x0020 - 11Mbits + * 0x0040 - 12Mbits + * 0x0080 - 18Mbits + * 0x0100 - 22Mbits + * 0x0200 - 24Mbits + * 0x0400 - 36Mbits + * 0x0800 - 48Mbits + * 0x1000 - 54Mbits + */ + u16 rate; + + /* Time in us that a packet can spend in the target */ + u32 expiry_time; + + /* index of the TX queue used for this packet */ + u8 xmit_queue; + + /* Used to identify a packet */ + u8 id; + + struct tx_control control; + + /* + * The FW should cut the packet into fragments + * of this size. + */ + u16 frag_threshold; + + /* Numbers of HW queue blocks to be allocated */ + u8 num_mem_blocks; + + u8 reserved; +} __attribute__ ((packed)); + +enum { + TX_SUCCESS = 0, + TX_DMA_ERROR = BIT(7), + TX_DISABLED = BIT(6), + TX_RETRY_EXCEEDED = BIT(5), + TX_TIMEOUT = BIT(4), + TX_KEY_NOT_FOUND = BIT(3), + TX_ENCRYPT_FAIL = BIT(2), + TX_UNAVAILABLE_PRIORITY = BIT(1), +}; + +struct tx_result { + /* + * Ownership synchronization between the host and + * the firmware. If done_1 and done_2 are cleared, + * owned by the FW (no info ready). + */ + u8 done_1; + + /* same as double_buffer_desc->id */ + u8 id; + + /* + * Total air access duration consumed by this + * packet, including all retries and overheads. + */ + u16 medium_usage; + + /* Total media delay (from 1st EDCA AIFS counter until TX Complete). */ + u32 medium_delay; + + /* Time between host xfer and tx complete */ + u32 fw_hnadling_time; + + /* The LS-byte of the last TKIP sequence number. */ + u8 lsb_seq_num; + + /* Retry count */ + u8 ack_failures; + + /* At which rate we got a ACK */ + u16 rate; + + u16 reserved; + + /* TX_* */ + u8 status; + + /* See done_1 */ + u8 done_2; +} __attribute__ ((packed)); + +void wl1251_tx_work(struct work_struct *work); +void wl1251_tx_complete(struct wl12xx *wl); +void wl1251_tx_flush(struct wl12xx *wl); + +#endif diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index c1d00c01f7d..c38aa5497eb 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -163,6 +163,7 @@ struct wl12xx_chip { void (*op_target_enable_interrupts)(struct wl12xx *wl); int (*op_hw_init)(struct wl12xx *wl); int (*op_plt_init)(struct wl12xx *wl); + void (*op_tx_flush)(struct wl12xx *wl); void (*op_fw_version)(struct wl12xx *wl); struct wl12xx_partition_set *p_table; -- cgit v1.2.3-18-g5258 From 8ec8beb28361864c82153fec5ddb82c9d636430f Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 12 Jun 2009 14:16:00 +0300 Subject: wl12xx: Add support for block reading from a fixed register address Add support for block reading (multiple bytes) from a fixed chipset register address. This is required for the wl1271 TX data path. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/spi.c | 12 ++++++++---- drivers/net/wireless/wl12xx/spi.h | 9 ++++++--- 2 files changed, 14 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index c3d5b737861..9c9943f9867 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -301,7 +301,7 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, } void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, - size_t len) + size_t len, bool fixed) { struct spi_transfer t[2]; struct spi_message m; @@ -314,6 +314,9 @@ void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; *cmd |= addr & WSPI_CMD_BYTE_ADDR; + if (fixed) + *cmd |= WSPI_CMD_FIXED; + spi_message_init(&m); memset(t, 0, sizeof(t)); @@ -348,7 +351,7 @@ void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, physical = wl12xx_translate_mem_addr(wl, addr); - wl12xx_spi_write(wl, physical, buf, len); + wl12xx_spi_write(wl, physical, buf, len, false); } void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, @@ -361,13 +364,14 @@ void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, wl12xx_spi_read(wl, physical, buf, len, fixed); } -void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len) +void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len, + bool fixed) { int physical; physical = wl12xx_translate_reg_addr(wl, addr); - wl12xx_spi_write(wl, physical, buf, len); + wl12xx_spi_write(wl, physical, buf, len, fixed); } u32 wl12xx_mem_read32(struct wl12xx *wl, int addr) diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/spi.h index 30f9098925f..e48a552b2ea 100644 --- a/drivers/net/wireless/wl12xx/spi.h +++ b/drivers/net/wireless/wl12xx/spi.h @@ -71,7 +71,8 @@ /* Raw target IO, address is not translated */ -void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, size_t len); +void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, + size_t len, bool fixed); void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, size_t len, bool fixed); @@ -84,7 +85,8 @@ void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val); /* Registers IO */ void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, bool fixed); -void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf,size_t len); +void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len, + bool fixed); u32 wl12xx_reg_read32(struct wl12xx *wl, int addr); void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val); @@ -106,7 +108,8 @@ static inline u32 wl12xx_read32(struct wl12xx *wl, int addr) static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val) { wl->buffer_32 = val; - wl12xx_spi_write(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32)); + wl12xx_spi_write(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); } #endif /* __WL12XX_SPI_H__ */ -- cgit v1.2.3-18-g5258 From c518a73e537a2c7b83e490335ddedb6465fa5f73 Mon Sep 17 00:00:00 2001 From: Ari Kauppi Date: Fri, 12 Jun 2009 14:16:07 +0300 Subject: wl12xx: Fix incorrect warning message. A warning message in wl12xx_acx_event_mbox_mask has a copy/paste error. Fix it to print the correct acx command. Signed-off-by: Ari Kauppi Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/acx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index a6b894573f0..8227d6db08c 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -735,7 +735,7 @@ int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask) ret = wl12xx_cmd_configure(wl, ACX_EVENT_MBOX_MASK, mask, sizeof(*mask)); if (ret < 0) { - wl12xx_warning("failed to set aid: %d", ret); + wl12xx_warning("failed to set acx_event_mbox_mask: %d", ret); goto out; } -- cgit v1.2.3-18-g5258 From 6021b2895891b161f73ede9938c101234c63218e Mon Sep 17 00:00:00 2001 From: Ari Kauppi Date: Fri, 12 Jun 2009 14:16:13 +0300 Subject: wl12xx: Fix CMD_TEST regression via netlink. CMD_TEST via netlink API has been broken since e29c3f59cfbc38c3b481a2694b08962da19c4664: cmd and acx interface rework. The user of the interface sends the request in a buffer without the wl12xx_command header but expects the response to have the wl12xx_command header (with id and status). This patch reverts the e29c3f5 commit for cmd.c:wl12xx_cmd_test and implements the needed wrapper functionality in netlink.c. Now the API of wl12xx_cmd_test and rest of wl12xx_cmd_* commands in cmd.c are similar. Signed-off-by: Ari Kauppi Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/cmd.c | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index d98941a1089..04e8401fcbe 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -66,38 +66,26 @@ out: * send test command to firmware * * @wl: wl struct - * @buf: buffer containing the command, without headers, no dma requirements + * @buf: buffer containing the command, with all headers, must work with dma * @len: length of the buffer * @answer: is answer needed - * - * FIXME: cmd_test users need to be converted to the new interface */ int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) { - struct wl12xx_command *cmd; - size_t cmd_len; int ret; wl12xx_debug(DEBUG_CMD, "cmd test"); - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - memcpy(cmd->parameters, buf, buf_len); - - /* FIXME: ugly */ - cmd_len = sizeof(struct wl12xx_cmd_header) + buf_len; + ret = wl12xx_cmd_send(wl, CMD_TEST, buf, buf_len); - ret = wl12xx_cmd_send(wl, CMD_TEST, cmd, cmd_len); if (ret < 0) { wl12xx_warning("TEST command failed"); - goto out; + return ret; } if (answer) { + struct wl12xx_command *cmd_answer; + /* * The test command got in, we can read the answer. * The answer would be a wl12xx_command, where the @@ -106,19 +94,18 @@ int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) wl12xx_ps_elp_wakeup(wl); - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, cmd, cmd_len); + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); wl12xx_ps_elp_sleep(wl); - if (cmd->header.status != CMD_STATUS_SUCCESS) + cmd_answer = buf; + + if (cmd_answer->header.status != CMD_STATUS_SUCCESS) wl12xx_error("TEST command answer error: %d", - cmd->header.status); - memcpy(buf, cmd->parameters, buf_len); + cmd_answer->header.status); } -out: - kfree(cmd); - return ret; + return 0; } /** -- cgit v1.2.3-18-g5258 From cee4fd2712a3db21f432bdff14e59aed160453b2 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:16:20 +0300 Subject: wl12xx: protect wl12xx_op_set_rts_threshold() The function doesn't lock the mutex before sending the acx. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/main.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 8feba36ff48..7ec17499278 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -957,11 +957,15 @@ static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) struct wl12xx *wl = hw->priv; int ret; + mutex_lock(&wl->mutex); + ret = wl12xx_acx_rts_threshold(wl, (u16) value); if (ret < 0) wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret); + mutex_unlock(&wl->mutex); + return ret; } -- cgit v1.2.3-18-g5258 From 01d9cfbdaadc64a46b57437c989bbad241074135 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:16:26 +0300 Subject: wl12xx: optimise elp wakeup and sleep calls The wakeup call was done too deep in code path, it's better to wakeup chip from higher levels. This will also reduce wakeup calls significantly. Signed-off-by: Kalle Valo Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/cmd.c | 13 ------------- drivers/net/wireless/wl12xx/debugfs.c | 5 +++++ drivers/net/wireless/wl12xx/main.c | 20 ++++++++++++++++++++ 3 files changed, 25 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 04e8401fcbe..fb4e9962d2c 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -32,8 +32,6 @@ int wl12xx_cmd_send(struct wl12xx *wl, u16 id, void *buf, size_t len) WARN_ON(len % 4 != 0); - wl12xx_ps_elp_wakeup(wl); - wl12xx_spi_mem_write(wl, wl->cmd_box_addr, buf, len); wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); @@ -57,8 +55,6 @@ int wl12xx_cmd_send(struct wl12xx *wl, u16 id, void *buf, size_t len) wl->chip.intr_cmd_complete); out: - wl12xx_ps_elp_sleep(wl); - return ret; } @@ -91,13 +87,8 @@ int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) * The answer would be a wl12xx_command, where the * parameter array contains the actual answer. */ - - wl12xx_ps_elp_wakeup(wl); - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); - wl12xx_ps_elp_sleep(wl); - cmd_answer = buf; if (cmd_answer->header.status != CMD_STATUS_SUCCESS) @@ -134,13 +125,9 @@ int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 id, void *buf, size_t len) goto out; } - wl12xx_ps_elp_wakeup(wl); - /* the interrogate command got in, we can read the answer */ wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, len); - wl12xx_ps_elp_sleep(wl); - acx = buf; if (acx->cmd.status != CMD_STATUS_SUCCESS) wl12xx_error("INTERROGATE command error: %d", diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index cdb368ce4da..3cc5460c11f 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -27,6 +27,7 @@ #include "wl12xx.h" #include "acx.h" +#include "ps.h" /* ms */ #define WL12XX_DEBUGFS_STATS_LIFETIME 1000 @@ -96,6 +97,8 @@ static void wl12xx_debugfs_update_stats(struct wl12xx *wl) { mutex_lock(&wl->mutex); + wl12xx_ps_elp_wakeup(wl); + if (wl->state == WL12XX_STATE_ON && time_after(jiffies, wl->stats.fw_stats_update + msecs_to_jiffies(WL12XX_DEBUGFS_STATS_LIFETIME))) { @@ -103,6 +106,8 @@ static void wl12xx_debugfs_update_stats(struct wl12xx *wl) wl->stats.fw_stats_update = jiffies; } + wl12xx_ps_elp_sleep(wl); + mutex_unlock(&wl->mutex); } diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 7ec17499278..894d5cc43d2 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -239,11 +239,14 @@ static void wl12xx_filter_work(struct work_struct *work) if (wl->state == WL12XX_STATE_OFF) goto out; + wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); if (ret < 0) goto out; out: + wl12xx_ps_elp_sleep(wl); mutex_unlock(&wl->mutex); } @@ -521,6 +524,8 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&wl->mutex); + wl12xx_ps_elp_wakeup(wl); + if (channel != wl->channel) { /* FIXME: use beacon interval provided by mac80211 */ ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); @@ -564,6 +569,7 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) } out: + wl12xx_ps_elp_sleep(wl); mutex_unlock(&wl->mutex); return ret; } @@ -702,6 +708,8 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mutex_lock(&wl->mutex); + wl12xx_ps_elp_wakeup(wl); + switch (cmd) { case SET_KEY: wl_cmd->key_action = KEY_ADD_OR_REPLACE; @@ -752,6 +760,7 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } out_unlock: + wl12xx_ps_elp_sleep(wl); mutex_unlock(&wl->mutex); out: @@ -946,7 +955,11 @@ static int wl12xx_op_hw_scan(struct ieee80211_hw *hw, } mutex_lock(&wl->mutex); + wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); + + wl12xx_ps_elp_sleep(wl); mutex_unlock(&wl->mutex); return ret; @@ -959,11 +972,15 @@ static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) mutex_lock(&wl->mutex); + wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_acx_rts_threshold(wl, (u16) value); if (ret < 0) wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret); + wl12xx_ps_elp_sleep(wl); + mutex_unlock(&wl->mutex); return ret; @@ -983,6 +1000,8 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); + wl12xx_ps_elp_wakeup(wl); + if (changed & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { wl->aid = bss_conf->aid; @@ -1072,6 +1091,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, } out: + wl12xx_ps_elp_sleep(wl); mutex_unlock(&wl->mutex); } -- cgit v1.2.3-18-g5258 From c5483b71936333ba9474f57d0f3a7a7abf9b87a0 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:16:32 +0300 Subject: wl12xx: check if elp wakeup failed Check the return call from wl12xx_ps_elp_wakeup() and bail out if it fails. This shouldn't happen, but if does there's a fundamental low level issue. Signed-off-by: Kalle Valo Reviewed-by: Luciano Coelho Reviewed-by: Vidhya Govindan Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/debugfs.c | 7 +++- drivers/net/wireless/wl12xx/main.c | 66 ++++++++++++++++++++++----------- drivers/net/wireless/wl12xx/wl1251.c | 6 ++- drivers/net/wireless/wl12xx/wl1251_tx.c | 4 +- 4 files changed, 59 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index 3cc5460c11f..94ad9948565 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -95,9 +95,13 @@ static const struct file_operations sub## _ ##name## _ops = { \ static void wl12xx_debugfs_update_stats(struct wl12xx *wl) { + int ret; + mutex_lock(&wl->mutex); - wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; if (wl->state == WL12XX_STATE_ON && time_after(jiffies, wl->stats.fw_stats_update + @@ -108,6 +112,7 @@ static void wl12xx_debugfs_update_stats(struct wl12xx *wl) wl12xx_ps_elp_sleep(wl); +out: mutex_unlock(&wl->mutex); } diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 894d5cc43d2..245544e6434 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -239,14 +239,18 @@ static void wl12xx_filter_work(struct work_struct *work) if (wl->state == WL12XX_STATE_OFF) goto out; - wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); if (ret < 0) - goto out; + goto out_sleep; -out: +out_sleep: wl12xx_ps_elp_sleep(wl); + +out: mutex_unlock(&wl->mutex); } @@ -524,20 +528,22 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&wl->mutex); - wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; if (channel != wl->channel) { /* FIXME: use beacon interval provided by mac80211 */ ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); if (ret < 0) - goto out; + goto out_sleep; wl->channel = channel; } ret = wl12xx_build_null_data(wl); if (ret < 0) - goto out; + goto out_sleep; if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { wl12xx_info("psm enabled"); @@ -568,9 +574,12 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) wl->power_level = conf->power_level; } -out: +out_sleep: wl12xx_ps_elp_sleep(wl); + +out: mutex_unlock(&wl->mutex); + return ret; } @@ -708,7 +717,9 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mutex_lock(&wl->mutex); - wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out_unlock; switch (cmd) { case SET_KEY: @@ -725,7 +736,7 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ret = wl12xx_set_key_type(wl, wl_cmd, cmd, key, addr); if (ret < 0) { wl12xx_error("Set KEY type failed"); - goto out_unlock; + goto out_sleep; } if (wl_cmd->key_type != KEY_WEP_DEFAULT) @@ -756,11 +767,13 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ret = wl12xx_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd)); if (ret < 0) { wl12xx_warning("could not set keys"); - goto out_unlock; + goto out_sleep; } -out_unlock: +out_sleep: wl12xx_ps_elp_sleep(wl); + +out_unlock: mutex_unlock(&wl->mutex); out: @@ -955,11 +968,16 @@ static int wl12xx_op_hw_scan(struct ieee80211_hw *hw, } mutex_lock(&wl->mutex); - wl12xx_ps_elp_wakeup(wl); + + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; ret = wl12xx_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); wl12xx_ps_elp_sleep(wl); + +out: mutex_unlock(&wl->mutex); return ret; @@ -972,15 +990,17 @@ static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) mutex_lock(&wl->mutex); - wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; ret = wl12xx_acx_rts_threshold(wl, (u16) value); - if (ret < 0) wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret); wl12xx_ps_elp_sleep(wl); +out: mutex_unlock(&wl->mutex); return ret; @@ -1000,7 +1020,9 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); - wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; if (changed & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { @@ -1008,18 +1030,18 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, ret = wl12xx_build_ps_poll(wl, wl->aid); if (ret < 0) - goto out; + goto out_sleep; ret = wl12xx_acx_aid(wl, wl->aid); if (ret < 0) - goto out; + goto out_sleep; /* If we want to go in PSM but we're not there yet */ if (wl->psm_requested && !wl->psm) { mode = STATION_POWER_SAVE_MODE; ret = wl12xx_ps_set_mode(wl, mode); if (ret < 0) - goto out; + goto out_sleep; } } } @@ -1030,7 +1052,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, ret = wl12xx_acx_slot(wl, SLOT_TIME_LONG); if (ret < 0) { wl12xx_warning("Set slot time failed %d", ret); - goto out; + goto out_sleep; } } @@ -1048,7 +1070,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_DISABLE); if (ret < 0) { wl12xx_warning("Set ctsprotect failed %d", ret); - goto out; + goto out_sleep; } } @@ -1090,8 +1112,10 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, goto out; } -out: +out_sleep: wl12xx_ps_elp_sleep(wl); + +out: mutex_unlock(&wl->mutex); } diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251.c index 903624a540a..5f6e75c6112 100644 --- a/drivers/net/wireless/wl12xx/wl1251.c +++ b/drivers/net/wireless/wl12xx/wl1251.c @@ -401,6 +401,7 @@ static void wl1251_irq_work(struct work_struct *work) u32 intr; struct wl12xx *wl = container_of(work, struct wl12xx, irq_work); + int ret; mutex_lock(&wl->mutex); @@ -409,7 +410,9 @@ static void wl1251_irq_work(struct work_struct *work) if (wl->state == WL12XX_STATE_OFF) goto out; - wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); @@ -489,6 +492,7 @@ static void wl1251_irq_work(struct work_struct *work) out_sleep: wl12xx_ps_elp_sleep(wl); + out: mutex_unlock(&wl->mutex); } diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c index c42c43de657..10023fce103 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c @@ -311,7 +311,9 @@ void wl1251_tx_work(struct work_struct *work) while ((skb = skb_dequeue(&wl->tx_queue))) { if (!woken_up) { - wl12xx_ps_elp_wakeup(wl); + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; woken_up = true; } -- cgit v1.2.3-18-g5258 From 0182f8d56c1836629f8331a19bd71e3833b81769 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:16:39 +0300 Subject: wl12xx: enable ELP mode ELP mode is working now, let's enable it so that the firmware can sleep and reduce power consumption. Signed-off-by: Kalle Valo Reviewed-by: Luciano Coelho Reviewed-by: Vidhya Govindan Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/ps.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index fe5e2d13acf..f28f194ca6f 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -85,11 +85,7 @@ static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable) if (enable) { wl12xx_debug(DEBUG_PSM, "sleep auth psm/elp"); - /* - * FIXME: we should PSM_ELP, but because of firmware wakeup - * problems let's use only PSM_PS - */ - ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_PS); + ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_ELP); if (ret < 0) return ret; -- cgit v1.2.3-18-g5258 From ce650b5cde686a282aed860bb5cd7368e00eac07 Mon Sep 17 00:00:00 2001 From: Vidhya Govindan Date: Fri, 12 Jun 2009 14:16:45 +0300 Subject: wl12xx: Assign value to rx msdu lifetime variable The patch "wl12xx: cmd and acx interface rework" failed to assign MSDU lifetime value in wl12xx_acx_rx_msdu_life_time() and breaks the functionality. This patch fixes the regression by assigning the correct value. Signed-off-by: Vidhya Govindan Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/acx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index 8227d6db08c..328f88a6756 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -317,6 +317,7 @@ int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time) goto out; } + acx->lifetime = life_time; ret = wl12xx_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, acx, sizeof(*acx)); if (ret < 0) { -- cgit v1.2.3-18-g5258 From 77cc9e43cee58303893f3a4fb8eaa2a3288c9c17 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 12 Jun 2009 14:16:52 +0300 Subject: wl12xx: Use chipset specific join commands Add implementation to use chipset specific join commands. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/cmd.c | 2 +- drivers/net/wireless/wl12xx/cmd.h | 2 +- drivers/net/wireless/wl12xx/main.c | 9 +++++---- drivers/net/wireless/wl12xx/wl1251.c | 1 + drivers/net/wireless/wl12xx/wl12xx.h | 2 ++ 5 files changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index fb4e9962d2c..cad258de9b3 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -253,7 +253,7 @@ out: return ret; } -int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, +int wl1251_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, u16 beacon_interval, u8 wait) { unsigned long timeout; diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index 7aef1f24352..a2eae54a241 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -36,7 +36,7 @@ int wl12xx_cmd_configure(struct wl12xx *wl, u16 id, void *buf, size_t len); int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, void *bitmap, u16 bitmap_len, u8 bitmap_control); int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable); -int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, +int wl1251_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, u16 beacon_interval, u8 wait); int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode); int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer, diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 245544e6434..a2aebac9fb8 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -243,7 +243,8 @@ static void wl12xx_filter_work(struct work_struct *work) if (ret < 0) goto out; - ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); + /* FIXME: replace the magic numbers with proper definitions */ + ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); if (ret < 0) goto out_sleep; @@ -534,7 +535,7 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) if (channel != wl->channel) { /* FIXME: use beacon interval provided by mac80211 */ - ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); + ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); if (ret < 0) goto out_sleep; @@ -1082,7 +1083,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, goto out; if (wl->bss_type != BSS_TYPE_IBSS) { - ret = wl12xx_cmd_join(wl, wl->bss_type, 5, 100, 1); + ret = wl->chip.op_cmd_join(wl, wl->bss_type, 5, 100, 1); if (ret < 0) goto out; } @@ -1106,7 +1107,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out; - ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); + ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); if (ret < 0) goto out; diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251.c index 5f6e75c6112..77494a9046e 100644 --- a/drivers/net/wireless/wl12xx/wl1251.c +++ b/drivers/net/wireless/wl12xx/wl1251.c @@ -717,6 +717,7 @@ void wl1251_setup(struct wl12xx *wl) wl->chip.op_plt_init = wl1251_plt_init; wl->chip.op_fw_version = wl1251_fw_version; wl->chip.op_tx_flush = wl1251_tx_flush; + wl->chip.op_cmd_join = wl1251_cmd_join; wl->chip.p_table = wl1251_part_table; wl->chip.acx_reg_table = wl1251_acx_reg_table; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index c38aa5497eb..c673cdb42d6 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -165,6 +165,8 @@ struct wl12xx_chip { int (*op_plt_init)(struct wl12xx *wl); void (*op_tx_flush)(struct wl12xx *wl); void (*op_fw_version)(struct wl12xx *wl); + int (*op_cmd_join)(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, + u16 beacon_interval, u8 wait); struct wl12xx_partition_set *p_table; enum wl12xx_acx_int_reg *acx_reg_table; -- cgit v1.2.3-18-g5258 From e6f0b5c2993609c576a0c45e86f7e5b6dd0ae421 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:16:58 +0300 Subject: wl12xx: rename wl1251.c wl1251_ops.c In preparation to split wl12xx to wl1251 and wl1271. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Reviewed-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/Makefile | 2 +- drivers/net/wireless/wl12xx/main.c | 2 +- drivers/net/wireless/wl12xx/wl1251.c | 728 ------------------------------- drivers/net/wireless/wl12xx/wl1251.h | 165 ------- drivers/net/wireless/wl12xx/wl1251_ops.c | 728 +++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1251_ops.h | 165 +++++++ 6 files changed, 895 insertions(+), 895 deletions(-) delete mode 100644 drivers/net/wireless/wl12xx/wl1251.c delete mode 100644 drivers/net/wireless/wl12xx/wl1251.h create mode 100644 drivers/net/wireless/wl12xx/wl1251_ops.c create mode 100644 drivers/net/wireless/wl12xx/wl1251_ops.h (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index 7e05ea37997..bb2f2524a0b 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,4 +1,4 @@ wl12xx-objs = main.o spi.o event.o wl1251_tx.o rx.o \ - ps.o cmd.o acx.o boot.o init.o wl1251.o \ + ps.o cmd.o acx.o boot.o init.o wl1251_ops.o \ debugfs.o obj-$(CONFIG_WL12XX) += wl12xx.o diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index a2aebac9fb8..3fc48c7c28c 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -34,7 +34,7 @@ #include "wl12xx.h" #include "wl12xx_80211.h" #include "reg.h" -#include "wl1251.h" +#include "wl1251_ops.h" #include "spi.h" #include "event.h" #include "wl1251_tx.h" diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251.c deleted file mode 100644 index 77494a9046e..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251.c +++ /dev/null @@ -1,728 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include - -#include "wl1251.h" -#include "reg.h" -#include "spi.h" -#include "boot.h" -#include "event.h" -#include "acx.h" -#include "wl1251_tx.h" -#include "rx.h" -#include "ps.h" -#include "init.h" - -static struct wl12xx_partition_set wl1251_part_table[PART_TABLE_LEN] = { - [PART_DOWN] = { - .mem = { - .start = 0x00000000, - .size = 0x00016800 - }, - .reg = { - .start = REGISTERS_BASE, - .size = REGISTERS_DOWN_SIZE - }, - }, - - [PART_WORK] = { - .mem = { - .start = 0x00028000, - .size = 0x00014000 - }, - .reg = { - .start = REGISTERS_BASE, - .size = REGISTERS_WORK_SIZE - }, - }, - - /* WL1251 doesn't use the DRPW partition, so we don't set it here */ -}; - -static enum wl12xx_acx_int_reg wl1251_acx_reg_table[ACX_REG_TABLE_LEN] = { - [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), - [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), - [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), - [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), - [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), - [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), - [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), - [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), - [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), - [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), - [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) -}; - -static int wl1251_upload_firmware(struct wl12xx *wl) -{ - struct wl12xx_partition_set *p_table = wl->chip.p_table; - int addr, chunk_num, partition_limit; - size_t fw_data_len; - u8 *p; - - /* whal_FwCtrl_LoadFwImageSm() */ - - wl12xx_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", - wl12xx_reg_read32(wl, CHIP_ID_B)); - - /* 10.0 check firmware length and set partition */ - fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | - (wl->fw[6] << 8) | (wl->fw[7]); - - wl12xx_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, - CHUNK_SIZE); - - if ((fw_data_len % 4) != 0) { - wl12xx_error("firmware length not multiple of four"); - return -EIO; - } - - wl12xx_set_partition(wl, - p_table[PART_DOWN].mem.start, - p_table[PART_DOWN].mem.size, - p_table[PART_DOWN].reg.start, - p_table[PART_DOWN].reg.size); - - /* 10.1 set partition limit and chunk num */ - chunk_num = 0; - partition_limit = p_table[PART_DOWN].mem.size; - - while (chunk_num < fw_data_len / CHUNK_SIZE) { - /* 10.2 update partition, if needed */ - addr = p_table[PART_DOWN].mem.start + - (chunk_num + 2) * CHUNK_SIZE; - if (addr > partition_limit) { - addr = p_table[PART_DOWN].mem.start + - chunk_num * CHUNK_SIZE; - partition_limit = chunk_num * CHUNK_SIZE + - p_table[PART_DOWN].mem.size; - wl12xx_set_partition(wl, - addr, - p_table[PART_DOWN].mem.size, - p_table[PART_DOWN].reg.start, - p_table[PART_DOWN].reg.size); - } - - /* 10.3 upload the chunk */ - addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; - p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; - wl12xx_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", - p, addr); - wl12xx_spi_mem_write(wl, addr, p, CHUNK_SIZE); - - chunk_num++; - } - - /* 10.4 upload the last chunk */ - addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; - p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; - wl12xx_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", - fw_data_len % CHUNK_SIZE, p, addr); - wl12xx_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); - - return 0; -} - -static int wl1251_upload_nvs(struct wl12xx *wl) -{ - size_t nvs_len, nvs_bytes_written, burst_len; - int nvs_start, i; - u32 dest_addr, val; - u8 *nvs_ptr, *nvs; - - nvs = wl->nvs; - if (nvs == NULL) - return -ENODEV; - - nvs_ptr = nvs; - - nvs_len = wl->nvs_len; - nvs_start = wl->fw_len; - - /* - * Layout before the actual NVS tables: - * 1 byte : burst length. - * 2 bytes: destination address. - * n bytes: data to burst copy. - * - * This is ended by a 0 length, then the NVS tables. - */ - - while (nvs_ptr[0]) { - burst_len = nvs_ptr[0]; - dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); - - /* We move our pointer to the data */ - nvs_ptr += 3; - - for (i = 0; i < burst_len; i++) { - val = (nvs_ptr[0] | (nvs_ptr[1] << 8) - | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); - - wl12xx_debug(DEBUG_BOOT, - "nvs burst write 0x%x: 0x%x", - dest_addr, val); - wl12xx_mem_write32(wl, dest_addr, val); - - nvs_ptr += 4; - dest_addr += 4; - } - } - - /* - * We've reached the first zero length, the first NVS table - * is 7 bytes further. - */ - nvs_ptr += 7; - nvs_len -= nvs_ptr - nvs; - nvs_len = ALIGN(nvs_len, 4); - - /* Now we must set the partition correctly */ - wl12xx_set_partition(wl, nvs_start, - wl->chip.p_table[PART_DOWN].mem.size, - wl->chip.p_table[PART_DOWN].reg.start, - wl->chip.p_table[PART_DOWN].reg.size); - - /* And finally we upload the NVS tables */ - nvs_bytes_written = 0; - while (nvs_bytes_written < nvs_len) { - val = (nvs_ptr[0] | (nvs_ptr[1] << 8) - | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); - - val = cpu_to_le32(val); - - wl12xx_debug(DEBUG_BOOT, - "nvs write table 0x%x: 0x%x", - nvs_start, val); - wl12xx_mem_write32(wl, nvs_start, val); - - nvs_ptr += 4; - nvs_bytes_written += 4; - nvs_start += 4; - } - - return 0; -} - -static int wl1251_boot(struct wl12xx *wl) -{ - int ret = 0, minor_minor_e2_ver; - u32 tmp, boot_data; - - ret = wl12xx_boot_soft_reset(wl); - if (ret < 0) - goto out; - - /* 2. start processing NVS file */ - ret = wl->chip.op_upload_nvs(wl); - if (ret < 0) - goto out; - - /* write firmware's last address (ie. it's length) to - * ACX_EEPROMLESS_IND_REG */ - wl12xx_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); - - /* 6. read the EEPROM parameters */ - tmp = wl12xx_reg_read32(wl, SCR_PAD2); - - /* 7. read bootdata */ - wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; - wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; - tmp = wl12xx_reg_read32(wl, SCR_PAD3); - - /* 8. check bootdata and call restart sequence */ - wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; - minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; - - wl12xx_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " - "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", - wl->boot_attr.radio_type, wl->boot_attr.major, - wl->boot_attr.minor, minor_minor_e2_ver); - - ret = wl12xx_boot_init_seq(wl); - if (ret < 0) - goto out; - - /* 9. NVS processing done */ - boot_data = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL); - - wl12xx_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); - - /* 10. check that ECPU_CONTROL_HALT bits are set in - * pWhalBus->uBootData and start uploading firmware - */ - if ((boot_data & ECPU_CONTROL_HALT) == 0) { - wl12xx_error("boot failed, ECPU_CONTROL_HALT not set"); - ret = -EIO; - goto out; - } - - ret = wl->chip.op_upload_fw(wl); - if (ret < 0) - goto out; - - /* 10.5 start firmware */ - ret = wl12xx_boot_run_firmware(wl); - if (ret < 0) - goto out; - -out: - return ret; -} - -static int wl1251_mem_cfg(struct wl12xx *wl) -{ - struct wl1251_acx_config_memory *mem_conf; - int ret, i; - - wl12xx_debug(DEBUG_ACX, "wl1251 mem cfg"); - - mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); - if (!mem_conf) { - ret = -ENOMEM; - goto out; - } - - /* memory config */ - mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); - mem_conf->mem_config.rx_mem_block_num = 35; - mem_conf->mem_config.tx_min_mem_block_num = 64; - mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; - mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; - mem_conf->mem_config.num_ssid_profiles = 1; - mem_conf->mem_config.debug_buffer_size = - cpu_to_le16(TRACE_BUFFER_MAX_SIZE); - - /* RX queue config */ - mem_conf->rx_queue_config.dma_address = 0; - mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; - mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; - mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; - - /* TX queue config */ - for (i = 0; i < MAX_TX_QUEUES; i++) { - mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; - mem_conf->tx_queue_config[i].attributes = i; - } - - ret = wl12xx_cmd_configure(wl, ACX_MEM_CFG, mem_conf, - sizeof(*mem_conf)); - if (ret < 0) { - wl12xx_warning("wl1251 mem config failed: %d", ret); - goto out; - } - -out: - kfree(mem_conf); - return ret; -} - -static int wl1251_hw_init_mem_config(struct wl12xx *wl) -{ - int ret; - - ret = wl1251_mem_cfg(wl); - if (ret < 0) - return ret; - - wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), - GFP_KERNEL); - if (!wl->target_mem_map) { - wl12xx_error("couldn't allocate target memory map"); - return -ENOMEM; - } - - /* we now ask for the firmware built memory map */ - ret = wl12xx_acx_mem_map(wl, wl->target_mem_map, - sizeof(struct wl1251_acx_mem_map)); - if (ret < 0) { - wl12xx_error("couldn't retrieve firmware memory map"); - kfree(wl->target_mem_map); - wl->target_mem_map = NULL; - return ret; - } - - return 0; -} - -static void wl1251_set_ecpu_ctrl(struct wl12xx *wl, u32 flag) -{ - u32 cpu_ctrl; - - /* 10.5.0 run the firmware (I) */ - cpu_ctrl = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL); - - /* 10.5.1 run the firmware (II) */ - cpu_ctrl &= ~flag; - wl12xx_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); -} - -static void wl1251_target_enable_interrupts(struct wl12xx *wl) -{ - /* Enable target's interrupts */ - wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | - WL1251_ACX_INTR_RX1_DATA | - WL1251_ACX_INTR_TX_RESULT | - WL1251_ACX_INTR_EVENT_A | - WL1251_ACX_INTR_EVENT_B | - WL1251_ACX_INTR_INIT_COMPLETE; - wl12xx_boot_target_enable_interrupts(wl); -} - -static void wl1251_fw_version(struct wl12xx *wl) -{ - wl12xx_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver)); -} - -static void wl1251_irq_work(struct work_struct *work) -{ - u32 intr; - struct wl12xx *wl = - container_of(work, struct wl12xx, irq_work); - int ret; - - mutex_lock(&wl->mutex); - - wl12xx_debug(DEBUG_IRQ, "IRQ work"); - - if (wl->state == WL12XX_STATE_OFF) - goto out; - - ret = wl12xx_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); - - intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); - wl12xx_debug(DEBUG_IRQ, "intr: 0x%x", intr); - - if (wl->data_path) { - wl->rx_counter = - wl12xx_mem_read32(wl, wl->data_path->rx_control_addr); - - /* We handle a frmware bug here */ - switch ((wl->rx_counter - wl->rx_handled) & 0xf) { - case 0: - wl12xx_debug(DEBUG_IRQ, "RX: FW and host in sync"); - intr &= ~WL1251_ACX_INTR_RX0_DATA; - intr &= ~WL1251_ACX_INTR_RX1_DATA; - break; - case 1: - wl12xx_debug(DEBUG_IRQ, "RX: FW +1"); - intr |= WL1251_ACX_INTR_RX0_DATA; - intr &= ~WL1251_ACX_INTR_RX1_DATA; - break; - case 2: - wl12xx_debug(DEBUG_IRQ, "RX: FW +2"); - intr |= WL1251_ACX_INTR_RX0_DATA; - intr |= WL1251_ACX_INTR_RX1_DATA; - break; - default: - wl12xx_warning("RX: FW and host out of sync: %d", - wl->rx_counter - wl->rx_handled); - break; - } - - wl->rx_handled = wl->rx_counter; - - - wl12xx_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); - } - - intr &= wl->intr_mask; - - if (intr == 0) { - wl12xx_debug(DEBUG_IRQ, "INTR is 0"); - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, - ~(wl->intr_mask)); - - goto out_sleep; - } - - if (intr & WL1251_ACX_INTR_RX0_DATA) { - wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); - wl12xx_rx(wl); - } - - if (intr & WL1251_ACX_INTR_RX1_DATA) { - wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); - wl12xx_rx(wl); - } - - if (intr & WL1251_ACX_INTR_TX_RESULT) { - wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); - wl1251_tx_complete(wl); - } - - if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { - wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); - if (intr & WL1251_ACX_INTR_EVENT_A) - wl12xx_event_handle(wl, 0); - else - wl12xx_event_handle(wl, 1); - } - - if (intr & WL1251_ACX_INTR_INIT_COMPLETE) - wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); - - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); - -out_sleep: - wl12xx_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - -static int wl1251_hw_init_txq_fill(u8 qid, - struct acx_tx_queue_qos_config *config, - u32 num_blocks) -{ - config->qid = qid; - - switch (qid) { - case QOS_AC_BE: - config->high_threshold = - (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_BE_DEF * num_blocks) / 100; - break; - case QOS_AC_BK: - config->high_threshold = - (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_BK_DEF * num_blocks) / 100; - break; - case QOS_AC_VI: - config->high_threshold = - (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_VI_DEF * num_blocks) / 100; - break; - case QOS_AC_VO: - config->high_threshold = - (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_VO_DEF * num_blocks) / 100; - break; - default: - wl12xx_error("Invalid TX queue id: %d", qid); - return -EINVAL; - } - - return 0; -} - -static int wl1251_hw_init_tx_queue_config(struct wl12xx *wl) -{ - struct acx_tx_queue_qos_config *config; - struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; - int ret, i; - - wl12xx_debug(DEBUG_ACX, "acx tx queue config"); - - config = kzalloc(sizeof(*config), GFP_KERNEL); - if (!config) { - ret = -ENOMEM; - goto out; - } - - for (i = 0; i < MAX_NUM_OF_AC; i++) { - ret = wl1251_hw_init_txq_fill(i, config, - wl_mem_map->num_tx_mem_blocks); - if (ret < 0) - goto out; - - ret = wl12xx_cmd_configure(wl, ACX_TX_QUEUE_CFG, - config, sizeof(*config)); - if (ret < 0) - goto out; - } - -out: - kfree(config); - return ret; -} - -static int wl1251_hw_init_data_path_config(struct wl12xx *wl) -{ - int ret; - - /* asking for the data path parameters */ - wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), - GFP_KERNEL); - if (!wl->data_path) { - wl12xx_error("Couldnt allocate data path parameters"); - return -ENOMEM; - } - - ret = wl12xx_acx_data_path_params(wl, wl->data_path); - if (ret < 0) { - kfree(wl->data_path); - wl->data_path = NULL; - return ret; - } - - return 0; -} - -static int wl1251_hw_init(struct wl12xx *wl) -{ - struct wl1251_acx_mem_map *wl_mem_map; - int ret; - - ret = wl12xx_hw_init_hwenc_config(wl); - if (ret < 0) - return ret; - - /* Template settings */ - ret = wl12xx_hw_init_templates_config(wl); - if (ret < 0) - return ret; - - /* Default memory configuration */ - ret = wl1251_hw_init_mem_config(wl); - if (ret < 0) - return ret; - - /* Default data path configuration */ - ret = wl1251_hw_init_data_path_config(wl); - if (ret < 0) - goto out_free_memmap; - - /* RX config */ - ret = wl12xx_hw_init_rx_config(wl, - RX_CFG_PROMISCUOUS | RX_CFG_TSF, - RX_FILTER_OPTION_DEF); - /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, - RX_FILTER_OPTION_FILTER_ALL); */ - if (ret < 0) - goto out_free_data_path; - - /* TX queues config */ - ret = wl1251_hw_init_tx_queue_config(wl); - if (ret < 0) - goto out_free_data_path; - - /* PHY layer config */ - ret = wl12xx_hw_init_phy_config(wl); - if (ret < 0) - goto out_free_data_path; - - /* Beacon filtering */ - ret = wl12xx_hw_init_beacon_filter(wl); - if (ret < 0) - goto out_free_data_path; - - /* Bluetooth WLAN coexistence */ - ret = wl12xx_hw_init_pta(wl); - if (ret < 0) - goto out_free_data_path; - - /* Energy detection */ - ret = wl12xx_hw_init_energy_detection(wl); - if (ret < 0) - goto out_free_data_path; - - /* Beacons and boradcast settings */ - ret = wl12xx_hw_init_beacon_broadcast(wl); - if (ret < 0) - goto out_free_data_path; - - /* Enable data path */ - ret = wl12xx_cmd_data_path(wl, wl->channel, 1); - if (ret < 0) - goto out_free_data_path; - - /* Default power state */ - ret = wl12xx_hw_init_power_auth(wl); - if (ret < 0) - goto out_free_data_path; - - wl_mem_map = wl->target_mem_map; - wl12xx_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", - wl_mem_map->num_tx_mem_blocks, - wl->data_path->tx_control_addr, - wl_mem_map->num_rx_mem_blocks, - wl->data_path->rx_control_addr); - - return 0; - - out_free_data_path: - kfree(wl->data_path); - - out_free_memmap: - kfree(wl->target_mem_map); - - return ret; -} - -static int wl1251_plt_init(struct wl12xx *wl) -{ - int ret; - - ret = wl1251_hw_init_mem_config(wl); - if (ret < 0) - return ret; - - ret = wl12xx_cmd_data_path(wl, wl->channel, 1); - if (ret < 0) - return ret; - - return 0; -} - -void wl1251_setup(struct wl12xx *wl) -{ - /* FIXME: Is it better to use strncpy here or is this ok? */ - wl->chip.fw_filename = WL1251_FW_NAME; - wl->chip.nvs_filename = WL1251_NVS_NAME; - - /* Now we know what chip we're using, so adjust the power on sleep - * time accordingly */ - wl->chip.power_on_sleep = WL1251_POWER_ON_SLEEP; - - wl->chip.intr_cmd_complete = WL1251_ACX_INTR_CMD_COMPLETE; - wl->chip.intr_init_complete = WL1251_ACX_INTR_INIT_COMPLETE; - - wl->chip.op_upload_nvs = wl1251_upload_nvs; - wl->chip.op_upload_fw = wl1251_upload_firmware; - wl->chip.op_boot = wl1251_boot; - wl->chip.op_set_ecpu_ctrl = wl1251_set_ecpu_ctrl; - wl->chip.op_target_enable_interrupts = wl1251_target_enable_interrupts; - wl->chip.op_hw_init = wl1251_hw_init; - wl->chip.op_plt_init = wl1251_plt_init; - wl->chip.op_fw_version = wl1251_fw_version; - wl->chip.op_tx_flush = wl1251_tx_flush; - wl->chip.op_cmd_join = wl1251_cmd_join; - - wl->chip.p_table = wl1251_part_table; - wl->chip.acx_reg_table = wl1251_acx_reg_table; - - INIT_WORK(&wl->irq_work, wl1251_irq_work); - INIT_WORK(&wl->tx_work, wl1251_tx_work); - -} diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h deleted file mode 100644 index 1f4a4433039..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_H__ -#define __WL1251_H__ - -#include - -#include "wl12xx.h" -#include "acx.h" - -#define WL1251_FW_NAME "wl1251-fw.bin" -#define WL1251_NVS_NAME "wl1251-nvs.bin" - -#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ - -void wl1251_setup(struct wl12xx *wl); - - -struct wl1251_acx_memory { - __le16 num_stations; /* number of STAs to be supported. */ - u16 reserved_1; - - /* - * Nmber of memory buffers for the RX mem pool. - * The actual number may be less if there are - * not enough blocks left for the minimum num - * of TX ones. - */ - u8 rx_mem_block_num; - u8 reserved_2; - u8 num_tx_queues; /* From 1 to 16 */ - u8 host_if_options; /* HOST_IF* */ - u8 tx_min_mem_block_num; - u8 num_ssid_profiles; - __le16 debug_buffer_size; -} __attribute__ ((packed)); - - -#define ACX_RX_DESC_MIN 1 -#define ACX_RX_DESC_MAX 127 -#define ACX_RX_DESC_DEF 32 -struct wl1251_acx_rx_queue_config { - u8 num_descs; - u8 pad; - u8 type; - u8 priority; - __le32 dma_address; -} __attribute__ ((packed)); - -#define ACX_TX_DESC_MIN 1 -#define ACX_TX_DESC_MAX 127 -#define ACX_TX_DESC_DEF 16 -struct wl1251_acx_tx_queue_config { - u8 num_descs; - u8 pad[2]; - u8 attributes; -} __attribute__ ((packed)); - -#define MAX_TX_QUEUE_CONFIGS 5 -#define MAX_TX_QUEUES 4 -struct wl1251_acx_config_memory { - struct acx_header header; - - struct wl1251_acx_memory mem_config; - struct wl1251_acx_rx_queue_config rx_queue_config; - struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS]; -} __attribute__ ((packed)); - -struct wl1251_acx_mem_map { - struct acx_header header; - - void *code_start; - void *code_end; - - void *wep_defkey_start; - void *wep_defkey_end; - - void *sta_table_start; - void *sta_table_end; - - void *packet_template_start; - void *packet_template_end; - - void *queue_memory_start; - void *queue_memory_end; - - void *packet_memory_pool_start; - void *packet_memory_pool_end; - - void *debug_buffer1_start; - void *debug_buffer1_end; - - void *debug_buffer2_start; - void *debug_buffer2_end; - - /* Number of blocks FW allocated for TX packets */ - u32 num_tx_mem_blocks; - - /* Number of blocks FW allocated for RX packets */ - u32 num_rx_mem_blocks; -} __attribute__ ((packed)); - -/************************************************************************* - - Host Interrupt Register (WiLink -> Host) - -**************************************************************************/ - -/* RX packet is ready in Xfer buffer #0 */ -#define WL1251_ACX_INTR_RX0_DATA BIT(0) - -/* TX result(s) are in the TX complete buffer */ -#define WL1251_ACX_INTR_TX_RESULT BIT(1) - -/* OBSOLETE */ -#define WL1251_ACX_INTR_TX_XFR BIT(2) - -/* RX packet is ready in Xfer buffer #1 */ -#define WL1251_ACX_INTR_RX1_DATA BIT(3) - -/* Event was entered to Event MBOX #A */ -#define WL1251_ACX_INTR_EVENT_A BIT(4) - -/* Event was entered to Event MBOX #B */ -#define WL1251_ACX_INTR_EVENT_B BIT(5) - -/* OBSOLETE */ -#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) - -/* Trace meassge on MBOX #A */ -#define WL1251_ACX_INTR_TRACE_A BIT(7) - -/* Trace meassge on MBOX #B */ -#define WL1251_ACX_INTR_TRACE_B BIT(8) - -/* Command processing completion */ -#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9) - -/* Init sequence is done */ -#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14) - -#define WL1251_ACX_INTR_ALL 0xFFFFFFFF - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.c b/drivers/net/wireless/wl12xx/wl1251_ops.c new file mode 100644 index 00000000000..126537f784b --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_ops.c @@ -0,0 +1,728 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "wl1251_ops.h" +#include "reg.h" +#include "spi.h" +#include "boot.h" +#include "event.h" +#include "acx.h" +#include "wl1251_tx.h" +#include "rx.h" +#include "ps.h" +#include "init.h" + +static struct wl12xx_partition_set wl1251_part_table[PART_TABLE_LEN] = { + [PART_DOWN] = { + .mem = { + .start = 0x00000000, + .size = 0x00016800 + }, + .reg = { + .start = REGISTERS_BASE, + .size = REGISTERS_DOWN_SIZE + }, + }, + + [PART_WORK] = { + .mem = { + .start = 0x00028000, + .size = 0x00014000 + }, + .reg = { + .start = REGISTERS_BASE, + .size = REGISTERS_WORK_SIZE + }, + }, + + /* WL1251 doesn't use the DRPW partition, so we don't set it here */ +}; + +static enum wl12xx_acx_int_reg wl1251_acx_reg_table[ACX_REG_TABLE_LEN] = { + [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), + [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), + [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), + [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), + [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), + [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), + [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), + [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), + [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), + [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), + [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) +}; + +static int wl1251_upload_firmware(struct wl12xx *wl) +{ + struct wl12xx_partition_set *p_table = wl->chip.p_table; + int addr, chunk_num, partition_limit; + size_t fw_data_len; + u8 *p; + + /* whal_FwCtrl_LoadFwImageSm() */ + + wl12xx_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", + wl12xx_reg_read32(wl, CHIP_ID_B)); + + /* 10.0 check firmware length and set partition */ + fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | + (wl->fw[6] << 8) | (wl->fw[7]); + + wl12xx_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, + CHUNK_SIZE); + + if ((fw_data_len % 4) != 0) { + wl12xx_error("firmware length not multiple of four"); + return -EIO; + } + + wl12xx_set_partition(wl, + p_table[PART_DOWN].mem.start, + p_table[PART_DOWN].mem.size, + p_table[PART_DOWN].reg.start, + p_table[PART_DOWN].reg.size); + + /* 10.1 set partition limit and chunk num */ + chunk_num = 0; + partition_limit = p_table[PART_DOWN].mem.size; + + while (chunk_num < fw_data_len / CHUNK_SIZE) { + /* 10.2 update partition, if needed */ + addr = p_table[PART_DOWN].mem.start + + (chunk_num + 2) * CHUNK_SIZE; + if (addr > partition_limit) { + addr = p_table[PART_DOWN].mem.start + + chunk_num * CHUNK_SIZE; + partition_limit = chunk_num * CHUNK_SIZE + + p_table[PART_DOWN].mem.size; + wl12xx_set_partition(wl, + addr, + p_table[PART_DOWN].mem.size, + p_table[PART_DOWN].reg.start, + p_table[PART_DOWN].reg.size); + } + + /* 10.3 upload the chunk */ + addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; + p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; + wl12xx_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", + p, addr); + wl12xx_spi_mem_write(wl, addr, p, CHUNK_SIZE); + + chunk_num++; + } + + /* 10.4 upload the last chunk */ + addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; + p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; + wl12xx_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", + fw_data_len % CHUNK_SIZE, p, addr); + wl12xx_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); + + return 0; +} + +static int wl1251_upload_nvs(struct wl12xx *wl) +{ + size_t nvs_len, nvs_bytes_written, burst_len; + int nvs_start, i; + u32 dest_addr, val; + u8 *nvs_ptr, *nvs; + + nvs = wl->nvs; + if (nvs == NULL) + return -ENODEV; + + nvs_ptr = nvs; + + nvs_len = wl->nvs_len; + nvs_start = wl->fw_len; + + /* + * Layout before the actual NVS tables: + * 1 byte : burst length. + * 2 bytes: destination address. + * n bytes: data to burst copy. + * + * This is ended by a 0 length, then the NVS tables. + */ + + while (nvs_ptr[0]) { + burst_len = nvs_ptr[0]; + dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); + + /* We move our pointer to the data */ + nvs_ptr += 3; + + for (i = 0; i < burst_len; i++) { + val = (nvs_ptr[0] | (nvs_ptr[1] << 8) + | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); + + wl12xx_debug(DEBUG_BOOT, + "nvs burst write 0x%x: 0x%x", + dest_addr, val); + wl12xx_mem_write32(wl, dest_addr, val); + + nvs_ptr += 4; + dest_addr += 4; + } + } + + /* + * We've reached the first zero length, the first NVS table + * is 7 bytes further. + */ + nvs_ptr += 7; + nvs_len -= nvs_ptr - nvs; + nvs_len = ALIGN(nvs_len, 4); + + /* Now we must set the partition correctly */ + wl12xx_set_partition(wl, nvs_start, + wl->chip.p_table[PART_DOWN].mem.size, + wl->chip.p_table[PART_DOWN].reg.start, + wl->chip.p_table[PART_DOWN].reg.size); + + /* And finally we upload the NVS tables */ + nvs_bytes_written = 0; + while (nvs_bytes_written < nvs_len) { + val = (nvs_ptr[0] | (nvs_ptr[1] << 8) + | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); + + val = cpu_to_le32(val); + + wl12xx_debug(DEBUG_BOOT, + "nvs write table 0x%x: 0x%x", + nvs_start, val); + wl12xx_mem_write32(wl, nvs_start, val); + + nvs_ptr += 4; + nvs_bytes_written += 4; + nvs_start += 4; + } + + return 0; +} + +static int wl1251_boot(struct wl12xx *wl) +{ + int ret = 0, minor_minor_e2_ver; + u32 tmp, boot_data; + + ret = wl12xx_boot_soft_reset(wl); + if (ret < 0) + goto out; + + /* 2. start processing NVS file */ + ret = wl->chip.op_upload_nvs(wl); + if (ret < 0) + goto out; + + /* write firmware's last address (ie. it's length) to + * ACX_EEPROMLESS_IND_REG */ + wl12xx_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); + + /* 6. read the EEPROM parameters */ + tmp = wl12xx_reg_read32(wl, SCR_PAD2); + + /* 7. read bootdata */ + wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; + wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; + tmp = wl12xx_reg_read32(wl, SCR_PAD3); + + /* 8. check bootdata and call restart sequence */ + wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; + minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; + + wl12xx_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " + "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", + wl->boot_attr.radio_type, wl->boot_attr.major, + wl->boot_attr.minor, minor_minor_e2_ver); + + ret = wl12xx_boot_init_seq(wl); + if (ret < 0) + goto out; + + /* 9. NVS processing done */ + boot_data = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL); + + wl12xx_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); + + /* 10. check that ECPU_CONTROL_HALT bits are set in + * pWhalBus->uBootData and start uploading firmware + */ + if ((boot_data & ECPU_CONTROL_HALT) == 0) { + wl12xx_error("boot failed, ECPU_CONTROL_HALT not set"); + ret = -EIO; + goto out; + } + + ret = wl->chip.op_upload_fw(wl); + if (ret < 0) + goto out; + + /* 10.5 start firmware */ + ret = wl12xx_boot_run_firmware(wl); + if (ret < 0) + goto out; + +out: + return ret; +} + +static int wl1251_mem_cfg(struct wl12xx *wl) +{ + struct wl1251_acx_config_memory *mem_conf; + int ret, i; + + wl12xx_debug(DEBUG_ACX, "wl1251 mem cfg"); + + mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); + if (!mem_conf) { + ret = -ENOMEM; + goto out; + } + + /* memory config */ + mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); + mem_conf->mem_config.rx_mem_block_num = 35; + mem_conf->mem_config.tx_min_mem_block_num = 64; + mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; + mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; + mem_conf->mem_config.num_ssid_profiles = 1; + mem_conf->mem_config.debug_buffer_size = + cpu_to_le16(TRACE_BUFFER_MAX_SIZE); + + /* RX queue config */ + mem_conf->rx_queue_config.dma_address = 0; + mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; + mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; + mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; + + /* TX queue config */ + for (i = 0; i < MAX_TX_QUEUES; i++) { + mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; + mem_conf->tx_queue_config[i].attributes = i; + } + + ret = wl12xx_cmd_configure(wl, ACX_MEM_CFG, mem_conf, + sizeof(*mem_conf)); + if (ret < 0) { + wl12xx_warning("wl1251 mem config failed: %d", ret); + goto out; + } + +out: + kfree(mem_conf); + return ret; +} + +static int wl1251_hw_init_mem_config(struct wl12xx *wl) +{ + int ret; + + ret = wl1251_mem_cfg(wl); + if (ret < 0) + return ret; + + wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), + GFP_KERNEL); + if (!wl->target_mem_map) { + wl12xx_error("couldn't allocate target memory map"); + return -ENOMEM; + } + + /* we now ask for the firmware built memory map */ + ret = wl12xx_acx_mem_map(wl, wl->target_mem_map, + sizeof(struct wl1251_acx_mem_map)); + if (ret < 0) { + wl12xx_error("couldn't retrieve firmware memory map"); + kfree(wl->target_mem_map); + wl->target_mem_map = NULL; + return ret; + } + + return 0; +} + +static void wl1251_set_ecpu_ctrl(struct wl12xx *wl, u32 flag) +{ + u32 cpu_ctrl; + + /* 10.5.0 run the firmware (I) */ + cpu_ctrl = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL); + + /* 10.5.1 run the firmware (II) */ + cpu_ctrl &= ~flag; + wl12xx_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); +} + +static void wl1251_target_enable_interrupts(struct wl12xx *wl) +{ + /* Enable target's interrupts */ + wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | + WL1251_ACX_INTR_RX1_DATA | + WL1251_ACX_INTR_TX_RESULT | + WL1251_ACX_INTR_EVENT_A | + WL1251_ACX_INTR_EVENT_B | + WL1251_ACX_INTR_INIT_COMPLETE; + wl12xx_boot_target_enable_interrupts(wl); +} + +static void wl1251_fw_version(struct wl12xx *wl) +{ + wl12xx_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver)); +} + +static void wl1251_irq_work(struct work_struct *work) +{ + u32 intr; + struct wl12xx *wl = + container_of(work, struct wl12xx, irq_work); + int ret; + + mutex_lock(&wl->mutex); + + wl12xx_debug(DEBUG_IRQ, "IRQ work"); + + if (wl->state == WL12XX_STATE_OFF) + goto out; + + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); + + intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); + wl12xx_debug(DEBUG_IRQ, "intr: 0x%x", intr); + + if (wl->data_path) { + wl->rx_counter = + wl12xx_mem_read32(wl, wl->data_path->rx_control_addr); + + /* We handle a frmware bug here */ + switch ((wl->rx_counter - wl->rx_handled) & 0xf) { + case 0: + wl12xx_debug(DEBUG_IRQ, "RX: FW and host in sync"); + intr &= ~WL1251_ACX_INTR_RX0_DATA; + intr &= ~WL1251_ACX_INTR_RX1_DATA; + break; + case 1: + wl12xx_debug(DEBUG_IRQ, "RX: FW +1"); + intr |= WL1251_ACX_INTR_RX0_DATA; + intr &= ~WL1251_ACX_INTR_RX1_DATA; + break; + case 2: + wl12xx_debug(DEBUG_IRQ, "RX: FW +2"); + intr |= WL1251_ACX_INTR_RX0_DATA; + intr |= WL1251_ACX_INTR_RX1_DATA; + break; + default: + wl12xx_warning("RX: FW and host out of sync: %d", + wl->rx_counter - wl->rx_handled); + break; + } + + wl->rx_handled = wl->rx_counter; + + + wl12xx_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); + } + + intr &= wl->intr_mask; + + if (intr == 0) { + wl12xx_debug(DEBUG_IRQ, "INTR is 0"); + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, + ~(wl->intr_mask)); + + goto out_sleep; + } + + if (intr & WL1251_ACX_INTR_RX0_DATA) { + wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); + wl12xx_rx(wl); + } + + if (intr & WL1251_ACX_INTR_RX1_DATA) { + wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); + wl12xx_rx(wl); + } + + if (intr & WL1251_ACX_INTR_TX_RESULT) { + wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); + wl1251_tx_complete(wl); + } + + if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { + wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); + if (intr & WL1251_ACX_INTR_EVENT_A) + wl12xx_event_handle(wl, 0); + else + wl12xx_event_handle(wl, 1); + } + + if (intr & WL1251_ACX_INTR_INIT_COMPLETE) + wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); + + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); + +out_sleep: + wl12xx_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +static int wl1251_hw_init_txq_fill(u8 qid, + struct acx_tx_queue_qos_config *config, + u32 num_blocks) +{ + config->qid = qid; + + switch (qid) { + case QOS_AC_BE: + config->high_threshold = + (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_BE_DEF * num_blocks) / 100; + break; + case QOS_AC_BK: + config->high_threshold = + (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_BK_DEF * num_blocks) / 100; + break; + case QOS_AC_VI: + config->high_threshold = + (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_VI_DEF * num_blocks) / 100; + break; + case QOS_AC_VO: + config->high_threshold = + (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_VO_DEF * num_blocks) / 100; + break; + default: + wl12xx_error("Invalid TX queue id: %d", qid); + return -EINVAL; + } + + return 0; +} + +static int wl1251_hw_init_tx_queue_config(struct wl12xx *wl) +{ + struct acx_tx_queue_qos_config *config; + struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; + int ret, i; + + wl12xx_debug(DEBUG_ACX, "acx tx queue config"); + + config = kzalloc(sizeof(*config), GFP_KERNEL); + if (!config) { + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < MAX_NUM_OF_AC; i++) { + ret = wl1251_hw_init_txq_fill(i, config, + wl_mem_map->num_tx_mem_blocks); + if (ret < 0) + goto out; + + ret = wl12xx_cmd_configure(wl, ACX_TX_QUEUE_CFG, + config, sizeof(*config)); + if (ret < 0) + goto out; + } + +out: + kfree(config); + return ret; +} + +static int wl1251_hw_init_data_path_config(struct wl12xx *wl) +{ + int ret; + + /* asking for the data path parameters */ + wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), + GFP_KERNEL); + if (!wl->data_path) { + wl12xx_error("Couldnt allocate data path parameters"); + return -ENOMEM; + } + + ret = wl12xx_acx_data_path_params(wl, wl->data_path); + if (ret < 0) { + kfree(wl->data_path); + wl->data_path = NULL; + return ret; + } + + return 0; +} + +static int wl1251_hw_init(struct wl12xx *wl) +{ + struct wl1251_acx_mem_map *wl_mem_map; + int ret; + + ret = wl12xx_hw_init_hwenc_config(wl); + if (ret < 0) + return ret; + + /* Template settings */ + ret = wl12xx_hw_init_templates_config(wl); + if (ret < 0) + return ret; + + /* Default memory configuration */ + ret = wl1251_hw_init_mem_config(wl); + if (ret < 0) + return ret; + + /* Default data path configuration */ + ret = wl1251_hw_init_data_path_config(wl); + if (ret < 0) + goto out_free_memmap; + + /* RX config */ + ret = wl12xx_hw_init_rx_config(wl, + RX_CFG_PROMISCUOUS | RX_CFG_TSF, + RX_FILTER_OPTION_DEF); + /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, + RX_FILTER_OPTION_FILTER_ALL); */ + if (ret < 0) + goto out_free_data_path; + + /* TX queues config */ + ret = wl1251_hw_init_tx_queue_config(wl); + if (ret < 0) + goto out_free_data_path; + + /* PHY layer config */ + ret = wl12xx_hw_init_phy_config(wl); + if (ret < 0) + goto out_free_data_path; + + /* Beacon filtering */ + ret = wl12xx_hw_init_beacon_filter(wl); + if (ret < 0) + goto out_free_data_path; + + /* Bluetooth WLAN coexistence */ + ret = wl12xx_hw_init_pta(wl); + if (ret < 0) + goto out_free_data_path; + + /* Energy detection */ + ret = wl12xx_hw_init_energy_detection(wl); + if (ret < 0) + goto out_free_data_path; + + /* Beacons and boradcast settings */ + ret = wl12xx_hw_init_beacon_broadcast(wl); + if (ret < 0) + goto out_free_data_path; + + /* Enable data path */ + ret = wl12xx_cmd_data_path(wl, wl->channel, 1); + if (ret < 0) + goto out_free_data_path; + + /* Default power state */ + ret = wl12xx_hw_init_power_auth(wl); + if (ret < 0) + goto out_free_data_path; + + wl_mem_map = wl->target_mem_map; + wl12xx_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", + wl_mem_map->num_tx_mem_blocks, + wl->data_path->tx_control_addr, + wl_mem_map->num_rx_mem_blocks, + wl->data_path->rx_control_addr); + + return 0; + + out_free_data_path: + kfree(wl->data_path); + + out_free_memmap: + kfree(wl->target_mem_map); + + return ret; +} + +static int wl1251_plt_init(struct wl12xx *wl) +{ + int ret; + + ret = wl1251_hw_init_mem_config(wl); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_data_path(wl, wl->channel, 1); + if (ret < 0) + return ret; + + return 0; +} + +void wl1251_setup(struct wl12xx *wl) +{ + /* FIXME: Is it better to use strncpy here or is this ok? */ + wl->chip.fw_filename = WL1251_FW_NAME; + wl->chip.nvs_filename = WL1251_NVS_NAME; + + /* Now we know what chip we're using, so adjust the power on sleep + * time accordingly */ + wl->chip.power_on_sleep = WL1251_POWER_ON_SLEEP; + + wl->chip.intr_cmd_complete = WL1251_ACX_INTR_CMD_COMPLETE; + wl->chip.intr_init_complete = WL1251_ACX_INTR_INIT_COMPLETE; + + wl->chip.op_upload_nvs = wl1251_upload_nvs; + wl->chip.op_upload_fw = wl1251_upload_firmware; + wl->chip.op_boot = wl1251_boot; + wl->chip.op_set_ecpu_ctrl = wl1251_set_ecpu_ctrl; + wl->chip.op_target_enable_interrupts = wl1251_target_enable_interrupts; + wl->chip.op_hw_init = wl1251_hw_init; + wl->chip.op_plt_init = wl1251_plt_init; + wl->chip.op_fw_version = wl1251_fw_version; + wl->chip.op_tx_flush = wl1251_tx_flush; + wl->chip.op_cmd_join = wl1251_cmd_join; + + wl->chip.p_table = wl1251_part_table; + wl->chip.acx_reg_table = wl1251_acx_reg_table; + + INIT_WORK(&wl->irq_work, wl1251_irq_work); + INIT_WORK(&wl->tx_work, wl1251_tx_work); + +} diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.h b/drivers/net/wireless/wl12xx/wl1251_ops.h new file mode 100644 index 00000000000..74acf8e3df9 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_ops.h @@ -0,0 +1,165 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1251_OPS_H__ +#define __WL1251_OPS_H__ + +#include + +#include "wl12xx.h" +#include "acx.h" + +#define WL1251_FW_NAME "wl1251-fw.bin" +#define WL1251_NVS_NAME "wl1251-nvs.bin" + +#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ + +void wl1251_setup(struct wl12xx *wl); + + +struct wl1251_acx_memory { + __le16 num_stations; /* number of STAs to be supported. */ + u16 reserved_1; + + /* + * Nmber of memory buffers for the RX mem pool. + * The actual number may be less if there are + * not enough blocks left for the minimum num + * of TX ones. + */ + u8 rx_mem_block_num; + u8 reserved_2; + u8 num_tx_queues; /* From 1 to 16 */ + u8 host_if_options; /* HOST_IF* */ + u8 tx_min_mem_block_num; + u8 num_ssid_profiles; + __le16 debug_buffer_size; +} __attribute__ ((packed)); + + +#define ACX_RX_DESC_MIN 1 +#define ACX_RX_DESC_MAX 127 +#define ACX_RX_DESC_DEF 32 +struct wl1251_acx_rx_queue_config { + u8 num_descs; + u8 pad; + u8 type; + u8 priority; + __le32 dma_address; +} __attribute__ ((packed)); + +#define ACX_TX_DESC_MIN 1 +#define ACX_TX_DESC_MAX 127 +#define ACX_TX_DESC_DEF 16 +struct wl1251_acx_tx_queue_config { + u8 num_descs; + u8 pad[2]; + u8 attributes; +} __attribute__ ((packed)); + +#define MAX_TX_QUEUE_CONFIGS 5 +#define MAX_TX_QUEUES 4 +struct wl1251_acx_config_memory { + struct acx_header header; + + struct wl1251_acx_memory mem_config; + struct wl1251_acx_rx_queue_config rx_queue_config; + struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS]; +} __attribute__ ((packed)); + +struct wl1251_acx_mem_map { + struct acx_header header; + + void *code_start; + void *code_end; + + void *wep_defkey_start; + void *wep_defkey_end; + + void *sta_table_start; + void *sta_table_end; + + void *packet_template_start; + void *packet_template_end; + + void *queue_memory_start; + void *queue_memory_end; + + void *packet_memory_pool_start; + void *packet_memory_pool_end; + + void *debug_buffer1_start; + void *debug_buffer1_end; + + void *debug_buffer2_start; + void *debug_buffer2_end; + + /* Number of blocks FW allocated for TX packets */ + u32 num_tx_mem_blocks; + + /* Number of blocks FW allocated for RX packets */ + u32 num_rx_mem_blocks; +} __attribute__ ((packed)); + +/************************************************************************* + + Host Interrupt Register (WiLink -> Host) + +**************************************************************************/ + +/* RX packet is ready in Xfer buffer #0 */ +#define WL1251_ACX_INTR_RX0_DATA BIT(0) + +/* TX result(s) are in the TX complete buffer */ +#define WL1251_ACX_INTR_TX_RESULT BIT(1) + +/* OBSOLETE */ +#define WL1251_ACX_INTR_TX_XFR BIT(2) + +/* RX packet is ready in Xfer buffer #1 */ +#define WL1251_ACX_INTR_RX1_DATA BIT(3) + +/* Event was entered to Event MBOX #A */ +#define WL1251_ACX_INTR_EVENT_A BIT(4) + +/* Event was entered to Event MBOX #B */ +#define WL1251_ACX_INTR_EVENT_B BIT(5) + +/* OBSOLETE */ +#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) + +/* Trace meassge on MBOX #A */ +#define WL1251_ACX_INTR_TRACE_A BIT(7) + +/* Trace meassge on MBOX #B */ +#define WL1251_ACX_INTR_TRACE_B BIT(8) + +/* Command processing completion */ +#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9) + +/* Init sequence is done */ +#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14) + +#define WL1251_ACX_INTR_ALL 0xFFFFFFFF + +#endif -- cgit v1.2.3-18-g5258 From c5ce901b3fdb2312f896f138ac864a7ef363c02d Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:17:06 +0300 Subject: wl12xx: rename driver to wl1251 Rename driver to wl1251.ko in preparation for wl1271 driver. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Reviewed-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/Kconfig | 17 ++++++++++++----- drivers/net/wireless/wl12xx/Makefile | 4 ++-- 2 files changed, 14 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index a82c4cd436d..82a0f97975d 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -1,11 +1,18 @@ -config WL12XX - tristate "TI wl1251/wl1271 support" - depends on MAC80211 && WLAN_80211 && SPI_MASTER && GENERIC_HARDIRQS && EXPERIMENTAL +menuconfig WL12XX + boolean "TI wl12xx driver support" + depends on MAC80211 && WLAN_80211 && EXPERIMENTAL + ---help--- + This will enable TI wl12xx driver support. The drivers make + use of the mac80211 stack. + +config WL1251 + tristate "TI wl1251 support" + depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS select FW_LOADER select CRC7 ---help--- This module adds support for wireless adapters based on - TI wl1251/wl1271 chipsets. + TI wl1251 chipset. - If you choose to build a module, it'll be called wl12xx. Say N if + If you choose to build a module, it'll be called wl1251. Say N if unsure. diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index bb2f2524a0b..f94970c1d80 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,4 +1,4 @@ -wl12xx-objs = main.o spi.o event.o wl1251_tx.o rx.o \ +wl1251-objs = main.o spi.o event.o wl1251_tx.o rx.o \ ps.o cmd.o acx.o boot.o init.o wl1251_ops.o \ debugfs.o -obj-$(CONFIG_WL12XX) += wl12xx.o +obj-$(CONFIG_WL1251) += wl1251.o -- cgit v1.2.3-18-g5258 From c731837855a9dcc2ec0c5367b0e16ad975aaed16 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:17:12 +0300 Subject: wl1251: remove wl1271_setup() We don't want to have any 1271 code in wl1251. Signed-off-by: Kalle Valo Reviewed-by: Luciano Coelho Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/main.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 3fc48c7c28c..dd75d3d2efa 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -195,14 +195,6 @@ static int wl12xx_chip_wakeup(struct wl12xx *wl) wl1251_setup(wl); break; - case CHIP_ID_1271_PG10: - wl12xx_warning("chip id 0x%x (1271 PG10) support is obsolete", - wl->chip.id); - break; - case CHIP_ID_1271_PG20: - wl12xx_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", - wl->chip.id); - break; case CHIP_ID_1251_PG10: case CHIP_ID_1251_PG11: default: -- cgit v1.2.3-18-g5258 From ef2f8d45771490de5b8373c25e983ee1e3aee9ea Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:17:19 +0300 Subject: wl1251: add wl1251 prefix to all 1251 files Now that all 1271 files are split, we can add wl1251_ prefix to the files. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Reviewed-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/Makefile | 7 +- drivers/net/wireless/wl12xx/acx.c | 841 --------------- drivers/net/wireless/wl12xx/acx.h | 1146 -------------------- drivers/net/wireless/wl12xx/boot.c | 297 ------ drivers/net/wireless/wl12xx/boot.h | 40 - drivers/net/wireless/wl12xx/cmd.c | 429 -------- drivers/net/wireless/wl12xx/cmd.h | 407 -------- drivers/net/wireless/wl12xx/debugfs.c | 518 --------- drivers/net/wireless/wl12xx/debugfs.h | 33 - drivers/net/wireless/wl12xx/event.c | 127 --- drivers/net/wireless/wl12xx/event.h | 121 --- drivers/net/wireless/wl12xx/init.c | 200 ---- drivers/net/wireless/wl12xx/init.h | 40 - drivers/net/wireless/wl12xx/main.c | 1442 -------------------------- drivers/net/wireless/wl12xx/ps.c | 147 --- drivers/net/wireless/wl12xx/ps.h | 36 - drivers/net/wireless/wl12xx/rx.c | 194 ---- drivers/net/wireless/wl12xx/rx.h | 122 --- drivers/net/wireless/wl12xx/spi.c | 395 ------- drivers/net/wireless/wl12xx/spi.h | 115 -- drivers/net/wireless/wl12xx/wl1251_acx.c | 841 +++++++++++++++ drivers/net/wireless/wl12xx/wl1251_acx.h | 1146 ++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1251_boot.c | 297 ++++++ drivers/net/wireless/wl12xx/wl1251_boot.h | 40 + drivers/net/wireless/wl12xx/wl1251_cmd.c | 429 ++++++++ drivers/net/wireless/wl12xx/wl1251_cmd.h | 407 ++++++++ drivers/net/wireless/wl12xx/wl1251_debugfs.c | 518 +++++++++ drivers/net/wireless/wl12xx/wl1251_debugfs.h | 33 + drivers/net/wireless/wl12xx/wl1251_event.c | 127 +++ drivers/net/wireless/wl12xx/wl1251_event.h | 121 +++ drivers/net/wireless/wl12xx/wl1251_init.c | 200 ++++ drivers/net/wireless/wl12xx/wl1251_init.h | 40 + drivers/net/wireless/wl12xx/wl1251_main.c | 1442 ++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1251_netlink.c | 679 ++++++++++++ drivers/net/wireless/wl12xx/wl1251_netlink.h | 30 + drivers/net/wireless/wl12xx/wl1251_ops.c | 14 +- drivers/net/wireless/wl12xx/wl1251_ops.h | 2 +- drivers/net/wireless/wl12xx/wl1251_ps.c | 147 +++ drivers/net/wireless/wl12xx/wl1251_ps.h | 36 + drivers/net/wireless/wl12xx/wl1251_rx.c | 195 ++++ drivers/net/wireless/wl12xx/wl1251_rx.h | 122 +++ drivers/net/wireless/wl12xx/wl1251_spi.c | 394 +++++++ drivers/net/wireless/wl12xx/wl1251_spi.h | 115 ++ drivers/net/wireless/wl12xx/wl1251_tx.c | 4 +- 44 files changed, 7373 insertions(+), 6663 deletions(-) delete mode 100644 drivers/net/wireless/wl12xx/acx.c delete mode 100644 drivers/net/wireless/wl12xx/acx.h delete mode 100644 drivers/net/wireless/wl12xx/boot.c delete mode 100644 drivers/net/wireless/wl12xx/boot.h delete mode 100644 drivers/net/wireless/wl12xx/cmd.c delete mode 100644 drivers/net/wireless/wl12xx/cmd.h delete mode 100644 drivers/net/wireless/wl12xx/debugfs.c delete mode 100644 drivers/net/wireless/wl12xx/debugfs.h delete mode 100644 drivers/net/wireless/wl12xx/event.c delete mode 100644 drivers/net/wireless/wl12xx/event.h delete mode 100644 drivers/net/wireless/wl12xx/init.c delete mode 100644 drivers/net/wireless/wl12xx/init.h delete mode 100644 drivers/net/wireless/wl12xx/main.c delete mode 100644 drivers/net/wireless/wl12xx/ps.c delete mode 100644 drivers/net/wireless/wl12xx/ps.h delete mode 100644 drivers/net/wireless/wl12xx/rx.c delete mode 100644 drivers/net/wireless/wl12xx/rx.h delete mode 100644 drivers/net/wireless/wl12xx/spi.c delete mode 100644 drivers/net/wireless/wl12xx/spi.h create mode 100644 drivers/net/wireless/wl12xx/wl1251_acx.c create mode 100644 drivers/net/wireless/wl12xx/wl1251_acx.h create mode 100644 drivers/net/wireless/wl12xx/wl1251_boot.c create mode 100644 drivers/net/wireless/wl12xx/wl1251_boot.h create mode 100644 drivers/net/wireless/wl12xx/wl1251_cmd.c create mode 100644 drivers/net/wireless/wl12xx/wl1251_cmd.h create mode 100644 drivers/net/wireless/wl12xx/wl1251_debugfs.c create mode 100644 drivers/net/wireless/wl12xx/wl1251_debugfs.h create mode 100644 drivers/net/wireless/wl12xx/wl1251_event.c create mode 100644 drivers/net/wireless/wl12xx/wl1251_event.h create mode 100644 drivers/net/wireless/wl12xx/wl1251_init.c create mode 100644 drivers/net/wireless/wl12xx/wl1251_init.h create mode 100644 drivers/net/wireless/wl12xx/wl1251_main.c create mode 100644 drivers/net/wireless/wl12xx/wl1251_netlink.c create mode 100644 drivers/net/wireless/wl12xx/wl1251_netlink.h create mode 100644 drivers/net/wireless/wl12xx/wl1251_ps.c create mode 100644 drivers/net/wireless/wl12xx/wl1251_ps.h create mode 100644 drivers/net/wireless/wl12xx/wl1251_rx.c create mode 100644 drivers/net/wireless/wl12xx/wl1251_rx.h create mode 100644 drivers/net/wireless/wl12xx/wl1251_spi.c create mode 100644 drivers/net/wireless/wl12xx/wl1251_spi.h (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index f94970c1d80..d5595a841f5 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,4 +1,5 @@ -wl1251-objs = main.o spi.o event.o wl1251_tx.o rx.o \ - ps.o cmd.o acx.o boot.o init.o wl1251_ops.o \ - debugfs.o +wl1251-objs = wl1251_main.o wl1251_spi.o wl1251_event.o \ + wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \ + wl1251_acx.o wl1251_boot.o wl1251_init.o \ + wl1251_ops.o wl1251_debugfs.o obj-$(CONFIG_WL1251) += wl1251.o diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c deleted file mode 100644 index 328f88a6756..00000000000 --- a/drivers/net/wireless/wl12xx/acx.c +++ /dev/null @@ -1,841 +0,0 @@ -#include "acx.h" - -#include -#include -#include - -#include "wl12xx.h" -#include "wl12xx_80211.h" -#include "reg.h" -#include "spi.h" -#include "ps.h" - -int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, - u8 mgt_rate, u8 mgt_mod) -{ - struct acx_fw_gen_frame_rates *rates; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx frame rates"); - - rates = kzalloc(sizeof(*rates), GFP_KERNEL); - if (!rates) { - ret = -ENOMEM; - goto out; - } - - rates->tx_ctrl_frame_rate = ctrl_rate; - rates->tx_ctrl_frame_mod = ctrl_mod; - rates->tx_mgt_frame_rate = mgt_rate; - rates->tx_mgt_frame_mod = mgt_mod; - - ret = wl12xx_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES, - rates, sizeof(*rates)); - if (ret < 0) { - wl12xx_error("Failed to set FW rates and modulation"); - goto out; - } - -out: - kfree(rates); - return ret; -} - - -int wl12xx_acx_station_id(struct wl12xx *wl) -{ - struct acx_dot11_station_id *mac; - int ret, i; - - wl12xx_debug(DEBUG_ACX, "acx dot11_station_id"); - - mac = kzalloc(sizeof(*mac), GFP_KERNEL); - if (!mac) { - ret = -ENOMEM; - goto out; - } - - for (i = 0; i < ETH_ALEN; i++) - mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; - - ret = wl12xx_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac)); - if (ret < 0) - goto out; - -out: - kfree(mac); - return ret; -} - -int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id) -{ - struct acx_dot11_default_key *default_key; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id); - - default_key = kzalloc(sizeof(*default_key), GFP_KERNEL); - if (!default_key) { - ret = -ENOMEM; - goto out; - } - - default_key->id = key_id; - - ret = wl12xx_cmd_configure(wl, DOT11_DEFAULT_KEY, - default_key, sizeof(*default_key)); - if (ret < 0) { - wl12xx_error("Couldnt set default key"); - goto out; - } - - wl->default_key = key_id; - -out: - kfree(default_key); - return ret; -} - -int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 wake_up_event, - u8 listen_interval) -{ - struct acx_wake_up_condition *wake_up; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx wake up conditions"); - - wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); - if (!wake_up) { - ret = -ENOMEM; - goto out; - } - - wake_up->wake_up_event = wake_up_event; - wake_up->listen_interval = listen_interval; - - ret = wl12xx_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, - wake_up, sizeof(*wake_up)); - if (ret < 0) { - wl12xx_warning("could not set wake up conditions: %d", ret); - goto out; - } - -out: - kfree(wake_up); - return ret; -} - -int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth) -{ - struct acx_sleep_auth *auth; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx sleep auth"); - - auth = kzalloc(sizeof(*auth), GFP_KERNEL); - if (!auth) { - ret = -ENOMEM; - goto out; - } - - auth->sleep_auth = sleep_auth; - - ret = wl12xx_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); - if (ret < 0) - return ret; - -out: - kfree(auth); - return ret; -} - -int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len) -{ - struct acx_revision *rev; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx fw rev"); - - rev = kzalloc(sizeof(*rev), GFP_KERNEL); - if (!rev) { - ret = -ENOMEM; - goto out; - } - - ret = wl12xx_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); - if (ret < 0) { - wl12xx_warning("ACX_FW_REV interrogate failed"); - goto out; - } - - /* be careful with the buffer sizes */ - strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); - - /* - * if the firmware version string is exactly - * sizeof(rev->fw_version) long or fw_len is less than - * sizeof(rev->fw_version) it won't be null terminated - */ - buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; - -out: - kfree(rev); - return ret; -} - -int wl12xx_acx_tx_power(struct wl12xx *wl, int power) -{ - struct acx_current_tx_power *acx; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); - - if (power < 0 || power > 25) - return -EINVAL; - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->current_tx_power = power * 10; - - ret = wl12xx_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); - if (ret < 0) { - wl12xx_warning("configure of tx power failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl12xx_acx_feature_cfg(struct wl12xx *wl) -{ - struct acx_feature_config *feature; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx feature cfg"); - - feature = kzalloc(sizeof(*feature), GFP_KERNEL); - if (!feature) { - ret = -ENOMEM; - goto out; - } - - /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ - feature->data_flow_options = 0; - feature->options = 0; - - ret = wl12xx_cmd_configure(wl, ACX_FEATURE_CFG, - feature, sizeof(*feature)); - if (ret < 0) { - wl12xx_error("Couldnt set HW encryption"); - goto out; - } - -out: - kfree(feature); - return ret; -} - -int wl12xx_acx_mem_map(struct wl12xx *wl, struct acx_header *mem_map, - size_t len) -{ - int ret; - - wl12xx_debug(DEBUG_ACX, "acx mem map"); - - ret = wl12xx_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); - if (ret < 0) - return ret; - - return 0; -} - -int wl12xx_acx_data_path_params(struct wl12xx *wl, - struct acx_data_path_params_resp *resp) -{ - struct acx_data_path_params *params; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx data path params"); - - params = kzalloc(sizeof(*params), GFP_KERNEL); - if (!params) { - ret = -ENOMEM; - goto out; - } - - params->rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE; - params->tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE; - - params->rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM; - params->tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM; - - params->tx_complete_threshold = 1; - - params->tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE; - - params->tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT; - - ret = wl12xx_cmd_configure(wl, ACX_DATA_PATH_PARAMS, - params, sizeof(*params)); - if (ret < 0) - goto out; - - /* FIXME: shouldn't this be ACX_DATA_PATH_RESP_PARAMS? */ - ret = wl12xx_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS, - resp, sizeof(*resp)); - - if (ret < 0) { - wl12xx_warning("failed to read data path parameters: %d", ret); - goto out; - } else if (resp->header.cmd.status != CMD_STATUS_SUCCESS) { - wl12xx_warning("data path parameter acx status failed"); - ret = -EIO; - goto out; - } - -out: - kfree(params); - return ret; -} - -int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time) -{ - struct acx_rx_msdu_lifetime *acx; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx rx msdu life time"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->lifetime = life_time; - ret = wl12xx_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, - acx, sizeof(*acx)); - if (ret < 0) { - wl12xx_warning("failed to set rx msdu life time: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter) -{ - struct acx_rx_config *rx_config; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx rx config"); - - rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); - if (!rx_config) { - ret = -ENOMEM; - goto out; - } - - rx_config->config_options = config; - rx_config->filter_options = filter; - - ret = wl12xx_cmd_configure(wl, ACX_RX_CFG, - rx_config, sizeof(*rx_config)); - if (ret < 0) { - wl12xx_warning("failed to set rx config: %d", ret); - goto out; - } - -out: - kfree(rx_config); - return ret; -} - -int wl12xx_acx_pd_threshold(struct wl12xx *wl) -{ - struct acx_packet_detection *pd; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx data pd threshold"); - - pd = kzalloc(sizeof(*pd), GFP_KERNEL); - if (!pd) { - ret = -ENOMEM; - goto out; - } - - /* FIXME: threshold value not set */ - - ret = wl12xx_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); - if (ret < 0) { - wl12xx_warning("failed to set pd threshold: %d", ret); - goto out; - } - -out: - kfree(pd); - return 0; -} - -int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time) -{ - struct acx_slot *slot; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx slot"); - - slot = kzalloc(sizeof(*slot), GFP_KERNEL); - if (!slot) { - ret = -ENOMEM; - goto out; - } - - slot->wone_index = STATION_WONE_INDEX; - slot->slot_time = slot_time; - - ret = wl12xx_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); - if (ret < 0) { - wl12xx_warning("failed to set slot time: %d", ret); - goto out; - } - -out: - kfree(slot); - return ret; -} - -int wl12xx_acx_group_address_tbl(struct wl12xx *wl) -{ - struct acx_dot11_grp_addr_tbl *acx; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx group address tbl"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - /* MAC filtering */ - acx->enabled = 0; - acx->num_groups = 0; - memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); - - ret = wl12xx_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, - acx, sizeof(*acx)); - if (ret < 0) { - wl12xx_warning("failed to set group addr table: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl12xx_acx_service_period_timeout(struct wl12xx *wl) -{ - struct acx_rx_timeout *rx_timeout; - int ret; - - rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); - if (!rx_timeout) { - ret = -ENOMEM; - goto out; - } - - wl12xx_debug(DEBUG_ACX, "acx service period timeout"); - - rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; - rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF; - - ret = wl12xx_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, - rx_timeout, sizeof(*rx_timeout)); - if (ret < 0) { - wl12xx_warning("failed to set service period timeout: %d", - ret); - goto out; - } - -out: - kfree(rx_timeout); - return ret; -} - -int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold) -{ - struct acx_rts_threshold *rts; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx rts threshold"); - - rts = kzalloc(sizeof(*rts), GFP_KERNEL); - if (!rts) { - ret = -ENOMEM; - goto out; - } - - rts->threshold = rts_threshold; - - ret = wl12xx_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); - if (ret < 0) { - wl12xx_warning("failed to set rts threshold: %d", ret); - goto out; - } - -out: - kfree(rts); - return ret; -} - -int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl) -{ - struct acx_beacon_filter_option *beacon_filter; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx beacon filter opt"); - - beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); - if (!beacon_filter) { - ret = -ENOMEM; - goto out; - } - - beacon_filter->enable = 0; - beacon_filter->max_num_beacons = 0; - - ret = wl12xx_cmd_configure(wl, ACX_BEACON_FILTER_OPT, - beacon_filter, sizeof(*beacon_filter)); - if (ret < 0) { - wl12xx_warning("failed to set beacon filter opt: %d", ret); - goto out; - } - -out: - kfree(beacon_filter); - return ret; -} - -int wl12xx_acx_beacon_filter_table(struct wl12xx *wl) -{ - struct acx_beacon_filter_ie_table *ie_table; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx beacon filter table"); - - ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); - if (!ie_table) { - ret = -ENOMEM; - goto out; - } - - ie_table->num_ie = 0; - memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE); - - ret = wl12xx_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, - ie_table, sizeof(*ie_table)); - if (ret < 0) { - wl12xx_warning("failed to set beacon filter table: %d", ret); - goto out; - } - -out: - kfree(ie_table); - return ret; -} - -int wl12xx_acx_sg_enable(struct wl12xx *wl) -{ - struct acx_bt_wlan_coex *pta; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx sg enable"); - - pta = kzalloc(sizeof(*pta), GFP_KERNEL); - if (!pta) { - ret = -ENOMEM; - goto out; - } - - pta->enable = SG_ENABLE; - - ret = wl12xx_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); - if (ret < 0) { - wl12xx_warning("failed to set softgemini enable: %d", ret); - goto out; - } - -out: - kfree(pta); - return ret; -} - -int wl12xx_acx_sg_cfg(struct wl12xx *wl) -{ - struct acx_bt_wlan_coex_param *param; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx sg cfg"); - - param = kzalloc(sizeof(*param), GFP_KERNEL); - if (!param) { - ret = -ENOMEM; - goto out; - } - - /* BT-WLAN coext parameters */ - param->min_rate = RATE_INDEX_24MBPS; - param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; - param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; - param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; - param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; - param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; - param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; - param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; - param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; - param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; - param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; - param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; - param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; - param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; - param->antenna_type = PTA_ANTENNA_TYPE_DEF; - param->signal_type = PTA_SIGNALING_TYPE_DEF; - param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; - param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; - param->max_cts = PTA_MAX_NUM_CTS_DEF; - param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; - param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; - param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; - param->wlan_elp_hp = PTA_ELP_HP_DEF; - param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; - param->ack_mode_dual_ant = PTA_ACK_MODE_DEF; - param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF; - param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; - param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; - - ret = wl12xx_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); - if (ret < 0) { - wl12xx_warning("failed to set sg config: %d", ret); - goto out; - } - -out: - kfree(param); - return ret; -} - -int wl12xx_acx_cca_threshold(struct wl12xx *wl) -{ - struct acx_energy_detection *detection; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx cca threshold"); - - detection = kzalloc(sizeof(*detection), GFP_KERNEL); - if (!detection) { - ret = -ENOMEM; - goto out; - } - - detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; - detection->tx_energy_detection = 0; - - ret = wl12xx_cmd_configure(wl, ACX_CCA_THRESHOLD, - detection, sizeof(*detection)); - if (ret < 0) { - wl12xx_warning("failed to set cca threshold: %d", ret); - return ret; - } - -out: - kfree(detection); - return ret; -} - -int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl) -{ - struct acx_beacon_broadcast *bb; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx bcn dtim options"); - - bb = kzalloc(sizeof(*bb), GFP_KERNEL); - if (!bb) { - ret = -ENOMEM; - goto out; - } - - bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; - bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; - bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; - bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; - - ret = wl12xx_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); - if (ret < 0) { - wl12xx_warning("failed to set rx config: %d", ret); - goto out; - } - -out: - kfree(bb); - return ret; -} - -int wl12xx_acx_aid(struct wl12xx *wl, u16 aid) -{ - struct acx_aid *acx_aid; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx aid"); - - acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); - if (!acx_aid) { - ret = -ENOMEM; - goto out; - } - - acx_aid->aid = aid; - - ret = wl12xx_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); - if (ret < 0) { - wl12xx_warning("failed to set aid: %d", ret); - goto out; - } - -out: - kfree(acx_aid); - return ret; -} - -int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask) -{ - struct acx_event_mask *mask; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx event mbox mask"); - - mask = kzalloc(sizeof(*mask), GFP_KERNEL); - if (!mask) { - ret = -ENOMEM; - goto out; - } - - /* high event mask is unused */ - mask->high_event_mask = 0xffffffff; - - mask->event_mask = event_mask; - - ret = wl12xx_cmd_configure(wl, ACX_EVENT_MBOX_MASK, - mask, sizeof(*mask)); - if (ret < 0) { - wl12xx_warning("failed to set acx_event_mbox_mask: %d", ret); - goto out; - } - -out: - kfree(mask); - return ret; -} - -int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble) -{ - struct acx_preamble *acx; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx_set_preamble"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->preamble = preamble; - - ret = wl12xx_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); - if (ret < 0) { - wl12xx_warning("Setting of preamble failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl12xx_acx_cts_protect(struct wl12xx *wl, - enum acx_ctsprotect_type ctsprotect) -{ - struct acx_ctsprotect *acx; - int ret; - - wl12xx_debug(DEBUG_ACX, "acx_set_ctsprotect"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->ctsprotect = ctsprotect; - - ret = wl12xx_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); - if (ret < 0) { - wl12xx_warning("Setting of ctsprotect failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl12xx_acx_tsf_info(struct wl12xx *wl, u64 *mactime) -{ - struct acx_tsf_info *tsf_info; - int ret; - - tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); - if (!tsf_info) { - ret = -ENOMEM; - goto out; - } - - ret = wl12xx_cmd_interrogate(wl, ACX_TSF_INFO, - tsf_info, sizeof(*tsf_info)); - if (ret < 0) { - wl12xx_warning("ACX_FW_REV interrogate failed"); - goto out; - } - - *mactime = tsf_info->current_tsf_lsb | - (tsf_info->current_tsf_msb << 31); - -out: - kfree(tsf_info); - return ret; -} - -int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats) -{ - int ret; - - wl12xx_debug(DEBUG_ACX, "acx statistics"); - - ret = wl12xx_cmd_interrogate(wl, ACX_STATISTICS, stats, - sizeof(*stats)); - if (ret < 0) { - wl12xx_warning("acx statistics failed: %d", ret); - return -ENOMEM; - } - - return 0; -} diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h deleted file mode 100644 index 92e724875ad..00000000000 --- a/drivers/net/wireless/wl12xx/acx.h +++ /dev/null @@ -1,1146 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL12XX_ACX_H__ -#define __WL12XX_ACX_H__ - -#include "wl12xx.h" -#include "cmd.h" - -/* Target's information element */ -struct acx_header { - struct wl12xx_cmd_header cmd; - - /* acx (or information element) header */ - u16 id; - - /* payload length (not including headers */ - u16 len; -}; - -struct acx_error_counter { - struct acx_header header; - - /* The number of PLCP errors since the last time this */ - /* information element was interrogated. This field is */ - /* automatically cleared when it is interrogated.*/ - u32 PLCP_error; - - /* The number of FCS errors since the last time this */ - /* information element was interrogated. This field is */ - /* automatically cleared when it is interrogated.*/ - u32 FCS_error; - - /* The number of MPDUs without PLCP header errors received*/ - /* since the last time this information element was interrogated. */ - /* This field is automatically cleared when it is interrogated.*/ - u32 valid_frame; - - /* the number of missed sequence numbers in the squentially */ - /* values of frames seq numbers */ - u32 seq_num_miss; -} __attribute__ ((packed)); - -struct acx_revision { - struct acx_header header; - - /* - * The WiLink firmware version, an ASCII string x.x.x.x, - * that uniquely identifies the current firmware. - * The left most digit is incremented each time a - * significant change is made to the firmware, such as - * code redesign or new platform support. - * The second digit is incremented when major enhancements - * are added or major fixes are made. - * The third digit is incremented for each GA release. - * The fourth digit is incremented for each build. - * The first two digits identify a firmware release version, - * in other words, a unique set of features. - * The first three digits identify a GA release. - */ - char fw_version[20]; - - /* - * This 4 byte field specifies the WiLink hardware version. - * bits 0 - 15: Reserved. - * bits 16 - 23: Version ID - The WiLink version ID - * (1 = first spin, 2 = second spin, and so on). - * bits 24 - 31: Chip ID - The WiLink chip ID. - */ - u32 hw_version; -} __attribute__ ((packed)); - -enum wl12xx_psm_mode { - /* Active mode */ - WL12XX_PSM_CAM = 0, - - /* Power save mode */ - WL12XX_PSM_PS = 1, - - /* Extreme low power */ - WL12XX_PSM_ELP = 2, -}; - -struct acx_sleep_auth { - struct acx_header header; - - /* The sleep level authorization of the device. */ - /* 0 - Always active*/ - /* 1 - Power down mode: light / fast sleep*/ - /* 2 - ELP mode: Deep / Max sleep*/ - u8 sleep_auth; - u8 padding[3]; -} __attribute__ ((packed)); - -enum { - HOSTIF_PCI_MASTER_HOST_INDIRECT, - HOSTIF_PCI_MASTER_HOST_DIRECT, - HOSTIF_SLAVE, - HOSTIF_PKT_RING, - HOSTIF_DONTCARE = 0xFF -}; - -#define DEFAULT_UCAST_PRIORITY 0 -#define DEFAULT_RX_Q_PRIORITY 0 -#define DEFAULT_NUM_STATIONS 1 -#define DEFAULT_RXQ_PRIORITY 0 /* low 0 .. 15 high */ -#define DEFAULT_RXQ_TYPE 0x07 /* All frames, Data/Ctrl/Mgmt */ -#define TRACE_BUFFER_MAX_SIZE 256 - -#define DP_RX_PACKET_RING_CHUNK_SIZE 1600 -#define DP_TX_PACKET_RING_CHUNK_SIZE 1600 -#define DP_RX_PACKET_RING_CHUNK_NUM 2 -#define DP_TX_PACKET_RING_CHUNK_NUM 2 -#define DP_TX_COMPLETE_TIME_OUT 20 -#define FW_TX_CMPLT_BLOCK_SIZE 16 - -struct acx_data_path_params { - struct acx_header header; - - u16 rx_packet_ring_chunk_size; - u16 tx_packet_ring_chunk_size; - - u8 rx_packet_ring_chunk_num; - u8 tx_packet_ring_chunk_num; - - /* - * Maximum number of packets that can be gathered - * in the TX complete ring before an interrupt - * is generated. - */ - u8 tx_complete_threshold; - - /* Number of pending TX complete entries in cyclic ring.*/ - u8 tx_complete_ring_depth; - - /* - * Max num microseconds since a packet enters the TX - * complete ring until an interrupt is generated. - */ - u32 tx_complete_timeout; -} __attribute__ ((packed)); - - -struct acx_data_path_params_resp { - struct acx_header header; - - u16 rx_packet_ring_chunk_size; - u16 tx_packet_ring_chunk_size; - - u8 rx_packet_ring_chunk_num; - u8 tx_packet_ring_chunk_num; - - u8 pad[2]; - - u32 rx_packet_ring_addr; - u32 tx_packet_ring_addr; - - u32 rx_control_addr; - u32 tx_control_addr; - - u32 tx_complete_addr; -} __attribute__ ((packed)); - -#define TX_MSDU_LIFETIME_MIN 0 -#define TX_MSDU_LIFETIME_MAX 3000 -#define TX_MSDU_LIFETIME_DEF 512 -#define RX_MSDU_LIFETIME_MIN 0 -#define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF -#define RX_MSDU_LIFETIME_DEF 512000 - -struct acx_rx_msdu_lifetime { - struct acx_header header; - - /* - * The maximum amount of time, in TU, before the - * firmware discards the MSDU. - */ - u32 lifetime; -} __attribute__ ((packed)); - -/* - * RX Config Options Table - * Bit Definition - * === ========== - * 31:14 Reserved - * 13 Copy RX Status - when set, write three receive status words - * to top of rx'd MPDUs. - * When cleared, do not write three status words (added rev 1.5) - * 12 Reserved - * 11 RX Complete upon FCS error - when set, give rx complete - * interrupt for FCS errors, after the rx filtering, e.g. unicast - * frames not to us with FCS error will not generate an interrupt. - * 10 SSID Filter Enable - When set, the WiLink discards all beacon, - * probe request, and probe response frames with an SSID that does - * not match the SSID specified by the host in the START/JOIN - * command. - * When clear, the WiLink receives frames with any SSID. - * 9 Broadcast Filter Enable - When set, the WiLink discards all - * broadcast frames. When clear, the WiLink receives all received - * broadcast frames. - * 8:6 Reserved - * 5 BSSID Filter Enable - When set, the WiLink discards any frames - * with a BSSID that does not match the BSSID specified by the - * host. - * When clear, the WiLink receives frames from any BSSID. - * 4 MAC Addr Filter - When set, the WiLink discards any frames - * with a destination address that does not match the MAC address - * of the adaptor. - * When clear, the WiLink receives frames destined to any MAC - * address. - * 3 Promiscuous - When set, the WiLink receives all valid frames - * (i.e., all frames that pass the FCS check). - * When clear, only frames that pass the other filters specified - * are received. - * 2 FCS - When set, the WiLink includes the FCS with the received - * frame. - * When cleared, the FCS is discarded. - * 1 PLCP header - When set, write all data from baseband to frame - * buffer including PHY header. - * 0 Reserved - Always equal to 0. - * - * RX Filter Options Table - * Bit Definition - * === ========== - * 31:12 Reserved - Always equal to 0. - * 11 Association - When set, the WiLink receives all association - * related frames (association request/response, reassocation - * request/response, and disassociation). When clear, these frames - * are discarded. - * 10 Auth/De auth - When set, the WiLink receives all authentication - * and de-authentication frames. When clear, these frames are - * discarded. - * 9 Beacon - When set, the WiLink receives all beacon frames. - * When clear, these frames are discarded. - * 8 Contention Free - When set, the WiLink receives all contention - * free frames. - * When clear, these frames are discarded. - * 7 Control - When set, the WiLink receives all control frames. - * When clear, these frames are discarded. - * 6 Data - When set, the WiLink receives all data frames. - * When clear, these frames are discarded. - * 5 FCS Error - When set, the WiLink receives frames that have FCS - * errors. - * When clear, these frames are discarded. - * 4 Management - When set, the WiLink receives all management - * frames. - * When clear, these frames are discarded. - * 3 Probe Request - When set, the WiLink receives all probe request - * frames. - * When clear, these frames are discarded. - * 2 Probe Response - When set, the WiLink receives all probe - * response frames. - * When clear, these frames are discarded. - * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK - * frames. - * When clear, these frames are discarded. - * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames - * that have reserved frame types and sub types as defined by the - * 802.11 specification. - * When clear, these frames are discarded. - */ -struct acx_rx_config { - struct acx_header header; - - u32 config_options; - u32 filter_options; -} __attribute__ ((packed)); - -enum { - QOS_AC_BE = 0, - QOS_AC_BK, - QOS_AC_VI, - QOS_AC_VO, - QOS_HIGHEST_AC_INDEX = QOS_AC_VO, -}; - -#define MAX_NUM_OF_AC (QOS_HIGHEST_AC_INDEX+1) -#define FIRST_AC_INDEX QOS_AC_BE -#define MAX_NUM_OF_802_1d_TAGS 8 -#define AC_PARAMS_MAX_TSID 15 -#define MAX_APSD_CONF 0xffff - -#define QOS_TX_HIGH_MIN (0) -#define QOS_TX_HIGH_MAX (100) - -#define QOS_TX_HIGH_BK_DEF (25) -#define QOS_TX_HIGH_BE_DEF (35) -#define QOS_TX_HIGH_VI_DEF (35) -#define QOS_TX_HIGH_VO_DEF (35) - -#define QOS_TX_LOW_BK_DEF (15) -#define QOS_TX_LOW_BE_DEF (25) -#define QOS_TX_LOW_VI_DEF (25) -#define QOS_TX_LOW_VO_DEF (25) - -struct acx_tx_queue_qos_config { - struct acx_header header; - - u8 qid; - u8 pad[3]; - - /* Max number of blocks allowd in the queue */ - u16 high_threshold; - - /* Lowest memory blocks guaranteed for this queue */ - u16 low_threshold; -} __attribute__ ((packed)); - -struct acx_packet_detection { - struct acx_header header; - - u32 threshold; -} __attribute__ ((packed)); - - -enum acx_slot_type { - SLOT_TIME_LONG = 0, - SLOT_TIME_SHORT = 1, - DEFAULT_SLOT_TIME = SLOT_TIME_SHORT, - MAX_SLOT_TIMES = 0xFF -}; - -#define STATION_WONE_INDEX 0 - -struct acx_slot { - struct acx_header header; - - u8 wone_index; /* Reserved */ - u8 slot_time; - u8 reserved[6]; -} __attribute__ ((packed)); - - -#define ADDRESS_GROUP_MAX (8) -#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) - -struct acx_dot11_grp_addr_tbl { - struct acx_header header; - - u8 enabled; - u8 num_groups; - u8 pad[2]; - u8 mac_table[ADDRESS_GROUP_MAX_LEN]; -} __attribute__ ((packed)); - - -#define RX_TIMEOUT_PS_POLL_MIN 0 -#define RX_TIMEOUT_PS_POLL_MAX (200000) -#define RX_TIMEOUT_PS_POLL_DEF (15) -#define RX_TIMEOUT_UPSD_MIN 0 -#define RX_TIMEOUT_UPSD_MAX (200000) -#define RX_TIMEOUT_UPSD_DEF (15) - -struct acx_rx_timeout { - struct acx_header header; - - /* - * The longest time the STA will wait to receive - * traffic from the AP after a PS-poll has been - * transmitted. - */ - u16 ps_poll_timeout; - - /* - * The longest time the STA will wait to receive - * traffic from the AP after a frame has been sent - * from an UPSD enabled queue. - */ - u16 upsd_timeout; -} __attribute__ ((packed)); - -#define RTS_THRESHOLD_MIN 0 -#define RTS_THRESHOLD_MAX 4096 -#define RTS_THRESHOLD_DEF 2347 - -struct acx_rts_threshold { - struct acx_header header; - - u16 threshold; - u8 pad[2]; -} __attribute__ ((packed)); - -struct acx_beacon_filter_option { - struct acx_header header; - - u8 enable; - - /* - * The number of beacons without the unicast TIM - * bit set that the firmware buffers before - * signaling the host about ready frames. - * When set to 0 and the filter is enabled, beacons - * without the unicast TIM bit set are dropped. - */ - u8 max_num_beacons; - u8 pad[2]; -} __attribute__ ((packed)); - -/* - * ACXBeaconFilterEntry (not 221) - * Byte Offset Size (Bytes) Definition - * =========== ============ ========== - * 0 1 IE identifier - * 1 1 Treatment bit mask - * - * ACXBeaconFilterEntry (221) - * Byte Offset Size (Bytes) Definition - * =========== ============ ========== - * 0 1 IE identifier - * 1 1 Treatment bit mask - * 2 3 OUI - * 5 1 Type - * 6 2 Version - * - * - * Treatment bit mask - The information element handling: - * bit 0 - The information element is compared and transferred - * in case of change. - * bit 1 - The information element is transferred to the host - * with each appearance or disappearance. - * Note that both bits can be set at the same time. - */ -#define BEACON_FILTER_TABLE_MAX_IE_NUM (32) -#define BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM (6) -#define BEACON_FILTER_TABLE_IE_ENTRY_SIZE (2) -#define BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE (6) -#define BEACON_FILTER_TABLE_MAX_SIZE ((BEACON_FILTER_TABLE_MAX_IE_NUM * \ - BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \ - (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ - BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) - -struct acx_beacon_filter_ie_table { - struct acx_header header; - - u8 num_ie; - u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; - u8 pad[3]; -} __attribute__ ((packed)); - -enum { - SG_ENABLE = 0, - SG_DISABLE, - SG_SENSE_NO_ACTIVITY, - SG_SENSE_ACTIVE -}; - -struct acx_bt_wlan_coex { - struct acx_header header; - - /* - * 0 -> PTA enabled - * 1 -> PTA disabled - * 2 -> sense no active mode, i.e. - * an interrupt is sent upon - * BT activity. - * 3 -> PTA is switched on in response - * to the interrupt sending. - */ - u8 enable; - u8 pad[3]; -} __attribute__ ((packed)); - -#define PTA_ANTENNA_TYPE_DEF (0) -#define PTA_BT_HP_MAXTIME_DEF (2000) -#define PTA_WLAN_HP_MAX_TIME_DEF (5000) -#define PTA_SENSE_DISABLE_TIMER_DEF (1350) -#define PTA_PROTECTIVE_RX_TIME_DEF (1500) -#define PTA_PROTECTIVE_TX_TIME_DEF (1500) -#define PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF (3000) -#define PTA_SIGNALING_TYPE_DEF (1) -#define PTA_AFH_LEVERAGE_ON_DEF (0) -#define PTA_NUMBER_QUIET_CYCLE_DEF (0) -#define PTA_MAX_NUM_CTS_DEF (3) -#define PTA_NUMBER_OF_WLAN_PACKETS_DEF (2) -#define PTA_NUMBER_OF_BT_PACKETS_DEF (2) -#define PTA_PROTECTIVE_RX_TIME_FAST_DEF (1500) -#define PTA_PROTECTIVE_TX_TIME_FAST_DEF (3000) -#define PTA_CYCLE_TIME_FAST_DEF (8700) -#define PTA_RX_FOR_AVALANCHE_DEF (5) -#define PTA_ELP_HP_DEF (0) -#define PTA_ANTI_STARVE_PERIOD_DEF (500) -#define PTA_ANTI_STARVE_NUM_CYCLE_DEF (4) -#define PTA_ALLOW_PA_SD_DEF (1) -#define PTA_TIME_BEFORE_BEACON_DEF (6300) -#define PTA_HPDM_MAX_TIME_DEF (1600) -#define PTA_TIME_OUT_NEXT_WLAN_DEF (2550) -#define PTA_AUTO_MODE_NO_CTS_DEF (0) -#define PTA_BT_HP_RESPECTED_DEF (3) -#define PTA_WLAN_RX_MIN_RATE_DEF (24) -#define PTA_ACK_MODE_DEF (1) - -struct acx_bt_wlan_coex_param { - struct acx_header header; - - /* - * The minimum rate of a received WLAN packet in the STA, - * during protective mode, of which a new BT-HP request - * during this Rx will always be respected and gain the antenna. - */ - u32 min_rate; - - /* Max time the BT HP will be respected. */ - u16 bt_hp_max_time; - - /* Max time the WLAN HP will be respected. */ - u16 wlan_hp_max_time; - - /* - * The time between the last BT activity - * and the moment when the sense mode returns - * to SENSE_INACTIVE. - */ - u16 sense_disable_timer; - - /* Time before the next BT HP instance */ - u16 rx_time_bt_hp; - u16 tx_time_bt_hp; - - /* range: 10-20000 default: 1500 */ - u16 rx_time_bt_hp_fast; - u16 tx_time_bt_hp_fast; - - /* range: 2000-65535 default: 8700 */ - u16 wlan_cycle_fast; - - /* range: 0 - 15000 (Msec) default: 1000 */ - u16 bt_anti_starvation_period; - - /* range 400-10000(Usec) default: 3000 */ - u16 next_bt_lp_packet; - - /* Deafult: worst case for BT DH5 traffic */ - u16 wake_up_beacon; - - /* range: 0-50000(Usec) default: 1050 */ - u16 hp_dm_max_guard_time; - - /* - * This is to prevent both BT & WLAN antenna - * starvation. - * Range: 100-50000(Usec) default:2550 - */ - u16 next_wlan_packet; - - /* 0 -> shared antenna */ - u8 antenna_type; - - /* - * 0 -> TI legacy - * 1 -> Palau - */ - u8 signal_type; - - /* - * BT AFH status - * 0 -> no AFH - * 1 -> from dedicated GPIO - * 2 -> AFH on (from host) - */ - u8 afh_leverage_on; - - /* - * The number of cycles during which no - * TX will be sent after 1 cycle of RX - * transaction in protective mode - */ - u8 quiet_cycle_num; - - /* - * The maximum number of CTSs that will - * be sent for receiving RX packet in - * protective mode - */ - u8 max_cts; - - /* - * The number of WLAN packets - * transferred in common mode before - * switching to BT. - */ - u8 wlan_packets_num; - - /* - * The number of BT packets - * transferred in common mode before - * switching to WLAN. - */ - u8 bt_packets_num; - - /* range: 1-255 default: 5 */ - u8 missed_rx_avalanche; - - /* range: 0-1 default: 1 */ - u8 wlan_elp_hp; - - /* range: 0 - 15 default: 4 */ - u8 bt_anti_starvation_cycles; - - u8 ack_mode_dual_ant; - - /* - * Allow PA_SD assertion/de-assertion - * during enabled BT activity. - */ - u8 pa_sd_enable; - - /* - * Enable/Disable PTA in auto mode: - * Support Both Active & P.S modes - */ - u8 pta_auto_mode_enable; - - /* range: 0 - 20 default: 1 */ - u8 bt_hp_respected_num; -} __attribute__ ((packed)); - -#define CCA_THRSH_ENABLE_ENERGY_D 0x140A -#define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF - -struct acx_energy_detection { - struct acx_header header; - - /* The RX Clear Channel Assessment threshold in the PHY */ - u16 rx_cca_threshold; - u8 tx_energy_detection; - u8 pad; -} __attribute__ ((packed)); - -#define BCN_RX_TIMEOUT_DEF_VALUE 10000 -#define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000 -#define RX_BROADCAST_IN_PS_DEF_VALUE 1 -#define CONSECUTIVE_PS_POLL_FAILURE_DEF 4 - -struct acx_beacon_broadcast { - struct acx_header header; - - u16 beacon_rx_timeout; - u16 broadcast_timeout; - - /* Enables receiving of broadcast packets in PS mode */ - u8 rx_broadcast_in_ps; - - /* Consecutive PS Poll failures before updating the host */ - u8 ps_poll_threshold; - u8 pad[2]; -} __attribute__ ((packed)); - -struct acx_event_mask { - struct acx_header header; - - u32 event_mask; - u32 high_event_mask; /* Unused */ -} __attribute__ ((packed)); - -#define CFG_RX_FCS BIT(2) -#define CFG_RX_ALL_GOOD BIT(3) -#define CFG_UNI_FILTER_EN BIT(4) -#define CFG_BSSID_FILTER_EN BIT(5) -#define CFG_MC_FILTER_EN BIT(6) -#define CFG_MC_ADDR0_EN BIT(7) -#define CFG_MC_ADDR1_EN BIT(8) -#define CFG_BC_REJECT_EN BIT(9) -#define CFG_SSID_FILTER_EN BIT(10) -#define CFG_RX_INT_FCS_ERROR BIT(11) -#define CFG_RX_INT_ENCRYPTED BIT(12) -#define CFG_RX_WR_RX_STATUS BIT(13) -#define CFG_RX_FILTER_NULTI BIT(14) -#define CFG_RX_RESERVE BIT(15) -#define CFG_RX_TIMESTAMP_TSF BIT(16) - -#define CFG_RX_RSV_EN BIT(0) -#define CFG_RX_RCTS_ACK BIT(1) -#define CFG_RX_PRSP_EN BIT(2) -#define CFG_RX_PREQ_EN BIT(3) -#define CFG_RX_MGMT_EN BIT(4) -#define CFG_RX_FCS_ERROR BIT(5) -#define CFG_RX_DATA_EN BIT(6) -#define CFG_RX_CTL_EN BIT(7) -#define CFG_RX_CF_EN BIT(8) -#define CFG_RX_BCN_EN BIT(9) -#define CFG_RX_AUTH_EN BIT(10) -#define CFG_RX_ASSOC_EN BIT(11) - -#define SCAN_PASSIVE BIT(0) -#define SCAN_5GHZ_BAND BIT(1) -#define SCAN_TRIGGERED BIT(2) -#define SCAN_PRIORITY_HIGH BIT(3) - -struct acx_fw_gen_frame_rates { - struct acx_header header; - - u8 tx_ctrl_frame_rate; /* RATE_* */ - u8 tx_ctrl_frame_mod; /* CCK_* or PBCC_* */ - u8 tx_mgt_frame_rate; - u8 tx_mgt_frame_mod; -} __attribute__ ((packed)); - -/* STA MAC */ -struct acx_dot11_station_id { - struct acx_header header; - - u8 mac[ETH_ALEN]; - u8 pad[2]; -} __attribute__ ((packed)); - -struct acx_feature_config { - struct acx_header header; - - u32 options; - u32 data_flow_options; -} __attribute__ ((packed)); - -struct acx_current_tx_power { - struct acx_header header; - - u8 current_tx_power; - u8 padding[3]; -} __attribute__ ((packed)); - -struct acx_dot11_default_key { - struct acx_header header; - - u8 id; - u8 pad[3]; -} __attribute__ ((packed)); - -struct acx_tsf_info { - struct acx_header header; - - u32 current_tsf_msb; - u32 current_tsf_lsb; - u32 last_TBTT_msb; - u32 last_TBTT_lsb; - u8 last_dtim_count; - u8 pad[3]; -} __attribute__ ((packed)); - -enum acx_wake_up_event { - WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/ - WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/ - WAKE_UP_EVENT_N_DTIM_BITMAP = 0x04, /* Wake on every Nth DTIM */ - WAKE_UP_EVENT_N_BEACONS_BITMAP = 0x08, /* Wake on every Nth Beacon */ - WAKE_UP_EVENT_BITS_MASK = 0x0F -}; - -struct acx_wake_up_condition { - struct acx_header header; - - u8 wake_up_event; /* Only one bit can be set */ - u8 listen_interval; - u8 pad[2]; -} __attribute__ ((packed)); - -struct acx_aid { - struct acx_header header; - - /* - * To be set when associated with an AP. - */ - u16 aid; - u8 pad[2]; -} __attribute__ ((packed)); - -enum acx_preamble_type { - ACX_PREAMBLE_LONG = 0, - ACX_PREAMBLE_SHORT = 1 -}; - -struct acx_preamble { - struct acx_header header; - - /* - * When set, the WiLink transmits the frames with a short preamble and - * when cleared, the WiLink transmits the frames with a long preamble. - */ - u8 preamble; - u8 padding[3]; -} __attribute__ ((packed)); - -enum acx_ctsprotect_type { - CTSPROTECT_DISABLE = 0, - CTSPROTECT_ENABLE = 1 -}; - -struct acx_ctsprotect { - struct acx_header header; - u8 ctsprotect; - u8 padding[3]; -} __attribute__ ((packed)); - -struct acx_tx_statistics { - u32 internal_desc_overflow; -} __attribute__ ((packed)); - -struct acx_rx_statistics { - u32 out_of_mem; - u32 hdr_overflow; - u32 hw_stuck; - u32 dropped; - u32 fcs_err; - u32 xfr_hint_trig; - u32 path_reset; - u32 reset_counter; -} __attribute__ ((packed)); - -struct acx_dma_statistics { - u32 rx_requested; - u32 rx_errors; - u32 tx_requested; - u32 tx_errors; -} __attribute__ ((packed)); - -struct acx_isr_statistics { - /* host command complete */ - u32 cmd_cmplt; - - /* fiqisr() */ - u32 fiqs; - - /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ - u32 rx_headers; - - /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ - u32 rx_completes; - - /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ - u32 rx_mem_overflow; - - /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ - u32 rx_rdys; - - /* irqisr() */ - u32 irqs; - - /* (INT_STS_ND & INT_TRIG_TX_PROC) */ - u32 tx_procs; - - /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ - u32 decrypt_done; - - /* (INT_STS_ND & INT_TRIG_DMA0) */ - u32 dma0_done; - - /* (INT_STS_ND & INT_TRIG_DMA1) */ - u32 dma1_done; - - /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ - u32 tx_exch_complete; - - /* (INT_STS_ND & INT_TRIG_COMMAND) */ - u32 commands; - - /* (INT_STS_ND & INT_TRIG_RX_PROC) */ - u32 rx_procs; - - /* (INT_STS_ND & INT_TRIG_PM_802) */ - u32 hw_pm_mode_changes; - - /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ - u32 host_acknowledges; - - /* (INT_STS_ND & INT_TRIG_PM_PCI) */ - u32 pci_pm; - - /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ - u32 wakeups; - - /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ - u32 low_rssi; -} __attribute__ ((packed)); - -struct acx_wep_statistics { - /* WEP address keys configured */ - u32 addr_key_count; - - /* default keys configured */ - u32 default_key_count; - - u32 reserved; - - /* number of times that WEP key not found on lookup */ - u32 key_not_found; - - /* number of times that WEP key decryption failed */ - u32 decrypt_fail; - - /* WEP packets decrypted */ - u32 packets; - - /* WEP decrypt interrupts */ - u32 interrupt; -} __attribute__ ((packed)); - -#define ACX_MISSED_BEACONS_SPREAD 10 - -struct acx_pwr_statistics { - /* the amount of enters into power save mode (both PD & ELP) */ - u32 ps_enter; - - /* the amount of enters into ELP mode */ - u32 elp_enter; - - /* the amount of missing beacon interrupts to the host */ - u32 missing_bcns; - - /* the amount of wake on host-access times */ - u32 wake_on_host; - - /* the amount of wake on timer-expire */ - u32 wake_on_timer_exp; - - /* the number of packets that were transmitted with PS bit set */ - u32 tx_with_ps; - - /* the number of packets that were transmitted with PS bit clear */ - u32 tx_without_ps; - - /* the number of received beacons */ - u32 rcvd_beacons; - - /* the number of entering into PowerOn (power save off) */ - u32 power_save_off; - - /* the number of entries into power save mode */ - u16 enable_ps; - - /* - * the number of exits from power save, not including failed PS - * transitions - */ - u16 disable_ps; - - /* - * the number of times the TSF counter was adjusted because - * of drift - */ - u32 fix_tsf_ps; - - /* Gives statistics about the spread continuous missed beacons. - * The 16 LSB are dedicated for the PS mode. - * The 16 MSB are dedicated for the PS mode. - * cont_miss_bcns_spread[0] - single missed beacon. - * cont_miss_bcns_spread[1] - two continuous missed beacons. - * cont_miss_bcns_spread[2] - three continuous missed beacons. - * ... - * cont_miss_bcns_spread[9] - ten and more continuous missed beacons. - */ - u32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; - - /* the number of beacons in awake mode */ - u32 rcvd_awake_beacons; -} __attribute__ ((packed)); - -struct acx_mic_statistics { - u32 rx_pkts; - u32 calc_failure; -} __attribute__ ((packed)); - -struct acx_aes_statistics { - u32 encrypt_fail; - u32 decrypt_fail; - u32 encrypt_packets; - u32 decrypt_packets; - u32 encrypt_interrupt; - u32 decrypt_interrupt; -} __attribute__ ((packed)); - -struct acx_event_statistics { - u32 heart_beat; - u32 calibration; - u32 rx_mismatch; - u32 rx_mem_empty; - u32 rx_pool; - u32 oom_late; - u32 phy_transmit_error; - u32 tx_stuck; -} __attribute__ ((packed)); - -struct acx_ps_statistics { - u32 pspoll_timeouts; - u32 upsd_timeouts; - u32 upsd_max_sptime; - u32 upsd_max_apturn; - u32 pspoll_max_apturn; - u32 pspoll_utilization; - u32 upsd_utilization; -} __attribute__ ((packed)); - -struct acx_rxpipe_statistics { - u32 rx_prep_beacon_drop; - u32 descr_host_int_trig_rx_data; - u32 beacon_buffer_thres_host_int_trig_rx_data; - u32 missed_beacon_host_int_trig_rx_data; - u32 tx_xfr_host_int_trig_rx_data; -} __attribute__ ((packed)); - -struct acx_statistics { - struct acx_header header; - - struct acx_tx_statistics tx; - struct acx_rx_statistics rx; - struct acx_dma_statistics dma; - struct acx_isr_statistics isr; - struct acx_wep_statistics wep; - struct acx_pwr_statistics pwr; - struct acx_aes_statistics aes; - struct acx_mic_statistics mic; - struct acx_event_statistics event; - struct acx_ps_statistics ps; - struct acx_rxpipe_statistics rxpipe; -} __attribute__ ((packed)); - -enum { - ACX_WAKE_UP_CONDITIONS = 0x0002, - ACX_MEM_CFG = 0x0003, - ACX_SLOT = 0x0004, - ACX_QUEUE_HEAD = 0x0005, /* for MASTER mode only */ - ACX_AC_CFG = 0x0007, - ACX_MEM_MAP = 0x0008, - ACX_AID = 0x000A, - ACX_RADIO_PARAM = 0x000B, /* Not used */ - ACX_CFG = 0x000C, /* Not used */ - ACX_FW_REV = 0x000D, - ACX_MEDIUM_USAGE = 0x000F, - ACX_RX_CFG = 0x0010, - ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */ - ACX_BSS_IN_PS = 0x0012, /* for AP only */ - ACX_STATISTICS = 0x0013, /* Debug API */ - ACX_FEATURE_CFG = 0x0015, - ACX_MISC_CFG = 0x0017, /* Not used */ - ACX_TID_CFG = 0x001A, - ACX_BEACON_FILTER_OPT = 0x001F, - ACX_LOW_RSSI = 0x0020, - ACX_NOISE_HIST = 0x0021, - ACX_HDK_VERSION = 0x0022, /* ??? */ - ACX_PD_THRESHOLD = 0x0023, - ACX_DATA_PATH_PARAMS = 0x0024, /* WO */ - ACX_DATA_PATH_RESP_PARAMS = 0x0024, /* RO */ - ACX_CCA_THRESHOLD = 0x0025, - ACX_EVENT_MBOX_MASK = 0x0026, -#ifdef FW_RUNNING_AS_AP - ACX_DTIM_PERIOD = 0x0027, /* for AP only */ -#else - ACX_WR_TBTT_AND_DTIM = 0x0027, /* STA only */ -#endif - ACX_ACI_OPTION_CFG = 0x0029, /* OBSOLETE (for 1251)*/ - ACX_GPIO_CFG = 0x002A, /* Not used */ - ACX_GPIO_SET = 0x002B, /* Not used */ - ACX_PM_CFG = 0x002C, /* To Be Documented */ - ACX_CONN_MONIT_PARAMS = 0x002D, - ACX_AVERAGE_RSSI = 0x002E, /* Not used */ - ACX_CONS_TX_FAILURE = 0x002F, - ACX_BCN_DTIM_OPTIONS = 0x0031, - ACX_SG_ENABLE = 0x0032, - ACX_SG_CFG = 0x0033, - ACX_ANTENNA_DIVERSITY_CFG = 0x0035, /* To Be Documented */ - ACX_LOW_SNR = 0x0037, /* To Be Documented */ - ACX_BEACON_FILTER_TABLE = 0x0038, - ACX_ARP_IP_FILTER = 0x0039, - ACX_ROAMING_STATISTICS_TBL = 0x003B, - ACX_RATE_POLICY = 0x003D, - ACX_CTS_PROTECTION = 0x003E, - ACX_SLEEP_AUTH = 0x003F, - ACX_PREAMBLE_TYPE = 0x0040, - ACX_ERROR_CNT = 0x0041, - ACX_FW_GEN_FRAME_RATES = 0x0042, - ACX_IBSS_FILTER = 0x0044, - ACX_SERVICE_PERIOD_TIMEOUT = 0x0045, - ACX_TSF_INFO = 0x0046, - ACX_CONFIG_PS_WMM = 0x0049, - ACX_ENABLE_RX_DATA_FILTER = 0x004A, - ACX_SET_RX_DATA_FILTER = 0x004B, - ACX_GET_DATA_FILTER_STATISTICS = 0x004C, - ACX_POWER_LEVEL_TABLE = 0x004D, - ACX_BET_ENABLE = 0x0050, - DOT11_STATION_ID = 0x1001, - DOT11_RX_MSDU_LIFE_TIME = 0x1004, - DOT11_CUR_TX_PWR = 0x100D, - DOT11_DEFAULT_KEY = 0x1010, - DOT11_RX_DOT11_MODE = 0x1012, - DOT11_RTS_THRESHOLD = 0x1013, - DOT11_GROUP_ADDRESS_TBL = 0x1014, - - MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, - - MAX_IE = 0xFFFF -}; - - -int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, - u8 mgt_rate, u8 mgt_mod); -int wl12xx_acx_station_id(struct wl12xx *wl); -int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id); -int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 wake_up_event, - u8 listen_interval); -int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth); -int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len); -int wl12xx_acx_tx_power(struct wl12xx *wl, int power); -int wl12xx_acx_feature_cfg(struct wl12xx *wl); -int wl12xx_acx_mem_map(struct wl12xx *wl, - struct acx_header *mem_map, size_t len); -int wl12xx_acx_data_path_params(struct wl12xx *wl, - struct acx_data_path_params_resp *data_path); -int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time); -int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter); -int wl12xx_acx_pd_threshold(struct wl12xx *wl); -int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time); -int wl12xx_acx_group_address_tbl(struct wl12xx *wl); -int wl12xx_acx_service_period_timeout(struct wl12xx *wl); -int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold); -int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl); -int wl12xx_acx_beacon_filter_table(struct wl12xx *wl); -int wl12xx_acx_sg_enable(struct wl12xx *wl); -int wl12xx_acx_sg_cfg(struct wl12xx *wl); -int wl12xx_acx_cca_threshold(struct wl12xx *wl); -int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl); -int wl12xx_acx_aid(struct wl12xx *wl, u16 aid); -int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask); -int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble); -int wl12xx_acx_cts_protect(struct wl12xx *wl, - enum acx_ctsprotect_type ctsprotect); -int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats); -int wl12xx_acx_tsf_info(struct wl12xx *wl, u64 *mactime); - -#endif /* __WL12XX_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c deleted file mode 100644 index a6a26497dc1..00000000000 --- a/drivers/net/wireless/wl12xx/boot.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include - -#include "reg.h" -#include "boot.h" -#include "spi.h" -#include "event.h" - -static void wl12xx_boot_enable_interrupts(struct wl12xx *wl) -{ - enable_irq(wl->irq); -} - -void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl) -{ - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); - wl12xx_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); -} - -int wl12xx_boot_soft_reset(struct wl12xx *wl) -{ - unsigned long timeout; - u32 boot_data; - - /* perform soft reset */ - wl12xx_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); - - /* SOFT_RESET is self clearing */ - timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); - while (1) { - boot_data = wl12xx_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); - wl12xx_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); - if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) - break; - - if (time_after(jiffies, timeout)) { - /* 1.2 check pWhalBus->uSelfClearTime if the - * timeout was reached */ - wl12xx_error("soft reset timeout"); - return -1; - } - - udelay(SOFT_RESET_STALL_TIME); - } - - /* disable Rx/Tx */ - wl12xx_reg_write32(wl, ENABLE, 0x0); - - /* disable auto calibration on start*/ - wl12xx_reg_write32(wl, SPARE_A2, 0xffff); - - return 0; -} - -int wl12xx_boot_init_seq(struct wl12xx *wl) -{ - u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq; - - /* - * col #1: INTEGER_DIVIDER - * col #2: FRACTIONAL_DIVIDER - * col #3: ATTN_BB - * col #4: ALPHA_BB - * col #5: STOP_TIME_BB - * col #6: BB_PLL_LOOP_FILTER - */ - static const u32 LUT[REF_FREQ_NUM][LUT_PARAM_NUM] = { - - { 83, 87381, 0xB, 5, 0xF00, 3}, /* REF_FREQ_19_2*/ - { 61, 141154, 0xB, 5, 0x1450, 2}, /* REF_FREQ_26_0*/ - { 41, 174763, 0xC, 6, 0x2D00, 1}, /* REF_FREQ_38_4*/ - { 40, 0, 0xC, 6, 0x2EE0, 1}, /* REF_FREQ_40_0*/ - { 47, 162280, 0xC, 6, 0x2760, 1} /* REF_FREQ_33_6 */ - }; - - /* read NVS params */ - scr_pad6 = wl12xx_reg_read32(wl, SCR_PAD6); - wl12xx_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6); - - /* read ELP_CMD */ - elp_cmd = wl12xx_reg_read32(wl, ELP_CMD); - wl12xx_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd); - - /* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */ - ref_freq = scr_pad6 & 0x000000FF; - wl12xx_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq); - - wl12xx_reg_write32(wl, PLL_CAL_TIME, 0x9); - - /* - * PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME) - */ - wl12xx_reg_write32(wl, CLK_BUF_TIME, 0x6); - - /* - * set the clock detect feature to work in the restart wu procedure - * (ELP_CFG_MODE[14]) and Select the clock source type - * (ELP_CFG_MODE[13:12]) - */ - tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000; - wl12xx_reg_write32(wl, ELP_CFG_MODE, tmp); - - /* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */ - elp_cmd |= 0x00000040; - wl12xx_reg_write32(wl, ELP_CMD, elp_cmd); - - /* PG 1.2: Set the BB PLL stable time to be 1000usec - * (PLL_STABLE_TIME) */ - wl12xx_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20); - - /* PG 1.2: read clock request time */ - init_data = wl12xx_reg_read32(wl, CLK_REQ_TIME); - - /* - * PG 1.2: set the clock request time to be ref_clk_settling_time - - * 1ms = 4ms - */ - if (init_data > 0x21) - tmp = init_data - 0x21; - else - tmp = 0; - wl12xx_reg_write32(wl, CLK_REQ_TIME, tmp); - - /* set BB PLL configurations in RF AFE */ - wl12xx_reg_write32(wl, 0x003058cc, 0x4B5); - - /* set RF_AFE_REG_5 */ - wl12xx_reg_write32(wl, 0x003058d4, 0x50); - - /* set RF_AFE_CTRL_REG_2 */ - wl12xx_reg_write32(wl, 0x00305948, 0x11c001); - - /* - * change RF PLL and BB PLL divider for VCO clock and adjust VCO - * bais current(RF_AFE_REG_13) - */ - wl12xx_reg_write32(wl, 0x003058f4, 0x1e); - - /* set BB PLL configurations */ - tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000; - wl12xx_reg_write32(wl, 0x00305840, tmp); - - /* set fractional divider according to Appendix C-BB PLL - * Calculations - */ - tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER]; - wl12xx_reg_write32(wl, 0x00305844, tmp); - - /* set the initial data for the sigma delta */ - wl12xx_reg_write32(wl, 0x00305848, 0x3039); - - /* - * set the accumulator attenuation value, calibration loop1 - * (alpha), calibration loop2 (beta), calibration loop3 (gamma) and - * the VCO gain - */ - tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) | - (LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1; - wl12xx_reg_write32(wl, 0x00305854, tmp); - - /* - * set the calibration stop time after holdoff time expires and set - * settling time HOLD_OFF_TIME_BB - */ - tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000; - wl12xx_reg_write32(wl, 0x00305858, tmp); - - /* - * set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL - * constant leakage current to linearize PFD to 0uA - - * BB_ILOOPF[7:3] - */ - tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030; - wl12xx_reg_write32(wl, 0x003058f8, tmp); - - /* - * set regulator output voltage for n divider to - * 1.35-BB_REFDIV[1:0], set charge pump current- BB_CPGAIN[4:2], - * set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB - * PLL auto-call to normal mode- BB_CALGAIN_3DB[8] - */ - wl12xx_reg_write32(wl, 0x003058f0, 0x29); - - /* enable restart wakeup sequence (ELP_CMD[0]) */ - wl12xx_reg_write32(wl, ELP_CMD, elp_cmd | 0x1); - - /* restart sequence completed */ - udelay(2000); - - return 0; -} - -int wl12xx_boot_run_firmware(struct wl12xx *wl) -{ - int loop, ret; - u32 chip_id, interrupt; - - wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); - - chip_id = wl12xx_reg_read32(wl, CHIP_ID_B); - - wl12xx_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); - - if (chip_id != wl->chip.id) { - wl12xx_error("chip id doesn't match after firmware boot"); - return -EIO; - } - - /* wait for init to complete */ - loop = 0; - while (loop++ < INIT_LOOP) { - udelay(INIT_LOOP_DELAY); - interrupt = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); - - if (interrupt == 0xffffffff) { - wl12xx_error("error reading hardware complete " - "init indication"); - return -EIO; - } - /* check that ACX_INTR_INIT_COMPLETE is enabled */ - else if (interrupt & wl->chip.intr_init_complete) { - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK, - wl->chip.intr_init_complete); - break; - } - } - - if (loop >= INIT_LOOP) { - wl12xx_error("timeout waiting for the hardware to " - "complete initialization"); - return -EIO; - } - - /* get hardware config command mail box */ - wl->cmd_box_addr = wl12xx_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); - - /* get hardware config event mail box */ - wl->event_box_addr = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR); - - /* set the working partition to its "running" mode offset */ - wl12xx_set_partition(wl, - wl->chip.p_table[PART_WORK].mem.start, - wl->chip.p_table[PART_WORK].mem.size, - wl->chip.p_table[PART_WORK].reg.start, - wl->chip.p_table[PART_WORK].reg.size); - - wl12xx_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", - wl->cmd_box_addr, wl->event_box_addr); - - wl->chip.op_fw_version(wl); - - /* - * in case of full asynchronous mode the firmware event must be - * ready to receive event from the command mailbox - */ - - /* enable gpio interrupts */ - wl12xx_boot_enable_interrupts(wl); - - wl->chip.op_target_enable_interrupts(wl); - - /* unmask all mbox events */ - wl->event_mask = 0xffffffff; - - ret = wl12xx_event_unmask(wl); - if (ret < 0) { - wl12xx_error("EVENT mask setting failed"); - return ret; - } - - wl12xx_event_mbox_config(wl); - - /* firmware startup completed */ - return 0; -} diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h deleted file mode 100644 index 4fa73132baa..00000000000 --- a/drivers/net/wireless/wl12xx/boot.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __BOOT_H__ -#define __BOOT_H__ - -#include "wl12xx.h" - -int wl12xx_boot_soft_reset(struct wl12xx *wl); -int wl12xx_boot_init_seq(struct wl12xx *wl); -int wl12xx_boot_run_firmware(struct wl12xx *wl); -void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl); - -/* number of times we try to read the INIT interrupt */ -#define INIT_LOOP 20000 - -/* delay between retries */ -#define INIT_LOOP_DELAY 50 - -#endif diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c deleted file mode 100644 index cad258de9b3..00000000000 --- a/drivers/net/wireless/wl12xx/cmd.c +++ /dev/null @@ -1,429 +0,0 @@ -#include "cmd.h" - -#include -#include -#include - -#include "wl12xx.h" -#include "wl12xx_80211.h" -#include "reg.h" -#include "spi.h" -#include "ps.h" -#include "acx.h" - -/** - * send command to firmware - * - * @wl: wl struct - * @id: command id - * @buf: buffer containing the command, must work with dma - * @len: length of the buffer - */ -int wl12xx_cmd_send(struct wl12xx *wl, u16 id, void *buf, size_t len) -{ - struct wl12xx_cmd_header *cmd; - unsigned long timeout; - u32 intr; - int ret = 0; - - cmd = buf; - cmd->id = id; - cmd->status = 0; - - WARN_ON(len % 4 != 0); - - wl12xx_spi_mem_write(wl, wl->cmd_box_addr, buf, len); - - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); - - timeout = jiffies + msecs_to_jiffies(WL12XX_COMMAND_TIMEOUT); - - intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); - while (!(intr & wl->chip.intr_cmd_complete)) { - if (time_after(jiffies, timeout)) { - wl12xx_error("command complete timeout"); - ret = -ETIMEDOUT; - goto out; - } - - msleep(1); - - intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); - } - - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK, - wl->chip.intr_cmd_complete); - -out: - return ret; -} - -/** - * send test command to firmware - * - * @wl: wl struct - * @buf: buffer containing the command, with all headers, must work with dma - * @len: length of the buffer - * @answer: is answer needed - */ -int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) -{ - int ret; - - wl12xx_debug(DEBUG_CMD, "cmd test"); - - ret = wl12xx_cmd_send(wl, CMD_TEST, buf, buf_len); - - if (ret < 0) { - wl12xx_warning("TEST command failed"); - return ret; - } - - if (answer) { - struct wl12xx_command *cmd_answer; - - /* - * The test command got in, we can read the answer. - * The answer would be a wl12xx_command, where the - * parameter array contains the actual answer. - */ - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); - - cmd_answer = buf; - - if (cmd_answer->header.status != CMD_STATUS_SUCCESS) - wl12xx_error("TEST command answer error: %d", - cmd_answer->header.status); - } - - return 0; -} - -/** - * read acx from firmware - * - * @wl: wl struct - * @id: acx id - * @buf: buffer for the response, including all headers, must work with dma - * @len: lenght of buf - */ -int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 id, void *buf, size_t len) -{ - struct acx_header *acx = buf; - int ret; - - wl12xx_debug(DEBUG_CMD, "cmd interrogate"); - - acx->id = id; - - /* payload length, does not include any headers */ - acx->len = len - sizeof(*acx); - - ret = wl12xx_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); - if (ret < 0) { - wl12xx_error("INTERROGATE command failed"); - goto out; - } - - /* the interrogate command got in, we can read the answer */ - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, len); - - acx = buf; - if (acx->cmd.status != CMD_STATUS_SUCCESS) - wl12xx_error("INTERROGATE command error: %d", - acx->cmd.status); - -out: - return ret; -} - -/** - * write acx value to firmware - * - * @wl: wl struct - * @id: acx id - * @buf: buffer containing acx, including all headers, must work with dma - * @len: length of buf - */ -int wl12xx_cmd_configure(struct wl12xx *wl, u16 id, void *buf, size_t len) -{ - struct acx_header *acx = buf; - int ret; - - wl12xx_debug(DEBUG_CMD, "cmd configure"); - - acx->id = id; - - /* payload length, does not include any headers */ - acx->len = len - sizeof(*acx); - - ret = wl12xx_cmd_send(wl, CMD_CONFIGURE, acx, len); - if (ret < 0) { - wl12xx_warning("CONFIGURE command NOK"); - return ret; - } - - return 0; -} - -int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, - void *bitmap, u16 bitmap_len, u8 bitmap_control) -{ - struct wl12xx_cmd_vbm_update *vbm; - int ret; - - wl12xx_debug(DEBUG_CMD, "cmd vbm"); - - vbm = kzalloc(sizeof(*vbm), GFP_KERNEL); - if (!vbm) { - ret = -ENOMEM; - goto out; - } - - /* Count and period will be filled by the target */ - vbm->tim.bitmap_ctrl = bitmap_control; - if (bitmap_len > PARTIAL_VBM_MAX) { - wl12xx_warning("cmd vbm len is %d B, truncating to %d", - bitmap_len, PARTIAL_VBM_MAX); - bitmap_len = PARTIAL_VBM_MAX; - } - memcpy(vbm->tim.pvb_field, bitmap, bitmap_len); - vbm->tim.identity = identity; - vbm->tim.length = bitmap_len + 3; - - vbm->len = cpu_to_le16(bitmap_len + 5); - - ret = wl12xx_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm)); - if (ret < 0) { - wl12xx_error("VBM command failed"); - goto out; - } - -out: - kfree(vbm); - return 0; -} - -int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable) -{ - struct cmd_enabledisable_path *cmd; - int ret; - u16 cmd_rx, cmd_tx; - - wl12xx_debug(DEBUG_CMD, "cmd data path"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->channel = channel; - - if (enable) { - cmd_rx = CMD_ENABLE_RX; - cmd_tx = CMD_ENABLE_TX; - } else { - cmd_rx = CMD_DISABLE_RX; - cmd_tx = CMD_DISABLE_TX; - } - - ret = wl12xx_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); - if (ret < 0) { - wl12xx_error("rx %s cmd for channel %d failed", - enable ? "start" : "stop", channel); - goto out; - } - - wl12xx_debug(DEBUG_BOOT, "rx %s cmd channel %d", - enable ? "start" : "stop", channel); - - ret = wl12xx_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); - if (ret < 0) { - wl12xx_error("tx %s cmd for channel %d failed", - enable ? "start" : "stop", channel); - return ret; - } - - wl12xx_debug(DEBUG_BOOT, "tx %s cmd channel %d", - enable ? "start" : "stop", channel); - -out: - kfree(cmd); - return ret; -} - -int wl1251_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, - u16 beacon_interval, u8 wait) -{ - unsigned long timeout; - struct cmd_join *join; - int ret, i; - u8 *bssid; - - join = kzalloc(sizeof(*join), GFP_KERNEL); - if (!join) { - ret = -ENOMEM; - goto out; - } - - /* FIXME: this should be in main.c */ - ret = wl12xx_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, - DEFAULT_HW_GEN_MODULATION_TYPE, - wl->tx_mgmt_frm_rate, - wl->tx_mgmt_frm_mod); - if (ret < 0) - goto out; - - wl12xx_debug(DEBUG_CMD, "cmd join"); - - /* Reverse order BSSID */ - bssid = (u8 *) &join->bssid_lsb; - for (i = 0; i < ETH_ALEN; i++) - bssid[i] = wl->bssid[ETH_ALEN - i - 1]; - - join->rx_config_options = wl->rx_config; - join->rx_filter_options = wl->rx_filter; - - join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | - RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; - - join->beacon_interval = beacon_interval; - join->dtim_interval = dtim_interval; - join->bss_type = bss_type; - join->channel = wl->channel; - join->ctrl = JOIN_CMD_CTRL_TX_FLUSH; - - ret = wl12xx_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); - if (ret < 0) { - wl12xx_error("failed to initiate cmd join"); - goto out; - } - - timeout = msecs_to_jiffies(JOIN_TIMEOUT); - - /* - * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to - * simplify locking we just sleep instead, for now - */ - if (wait) - msleep(10); - -out: - kfree(join); - return ret; -} - -int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode) -{ - struct wl12xx_cmd_ps_params *ps_params = NULL; - int ret = 0; - - /* FIXME: this should be in ps.c */ - ret = wl12xx_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, - wl->listen_int); - if (ret < 0) { - wl12xx_error("couldn't set wake up conditions"); - goto out; - } - - wl12xx_debug(DEBUG_CMD, "cmd set ps mode"); - - ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); - if (!ps_params) { - ret = -ENOMEM; - goto out; - } - - ps_params->ps_mode = ps_mode; - ps_params->send_null_data = 1; - ps_params->retries = 5; - ps_params->hang_over_period = 128; - ps_params->null_data_rate = 1; /* 1 Mbps */ - - ret = wl12xx_cmd_send(wl, CMD_SET_PS_MODE, ps_params, - sizeof(*ps_params)); - if (ret < 0) { - wl12xx_error("cmd set_ps_mode failed"); - goto out; - } - -out: - kfree(ps_params); - return ret; -} - -int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer, - size_t len) -{ - struct cmd_read_write_memory *cmd; - int ret = 0; - - wl12xx_debug(DEBUG_CMD, "cmd read memory"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - WARN_ON(len > MAX_READ_SIZE); - len = min_t(size_t, len, MAX_READ_SIZE); - - cmd->addr = addr; - cmd->size = len; - - ret = wl12xx_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); - if (ret < 0) { - wl12xx_error("read memory command failed: %d", ret); - goto out; - } - - /* the read command got in, we can now read the answer */ - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); - - if (cmd->header.status != CMD_STATUS_SUCCESS) - wl12xx_error("error in read command result: %d", - cmd->header.status); - - memcpy(answer, cmd->value, len); - -out: - kfree(cmd); - return ret; -} - -int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, - void *buf, size_t buf_len) -{ - struct wl12xx_cmd_packet_template *cmd; - size_t cmd_len; - int ret = 0; - - wl12xx_debug(DEBUG_CMD, "cmd template %d", cmd_id); - - WARN_ON(buf_len > WL12XX_MAX_TEMPLATE_SIZE); - buf_len = min_t(size_t, buf_len, WL12XX_MAX_TEMPLATE_SIZE); - cmd_len = ALIGN(sizeof(*cmd) + buf_len, 4); - - cmd = kzalloc(cmd_len, GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->size = cpu_to_le16(buf_len); - - if (buf) - memcpy(cmd->data, buf, buf_len); - - ret = wl12xx_cmd_send(wl, cmd_id, cmd, cmd_len); - if (ret < 0) { - wl12xx_warning("cmd set_template failed: %d", ret); - goto out; - } - -out: - kfree(cmd); - return ret; -} diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h deleted file mode 100644 index a2eae54a241..00000000000 --- a/drivers/net/wireless/wl12xx/cmd.h +++ /dev/null @@ -1,407 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL12XX_CMD_H__ -#define __WL12XX_CMD_H__ - -#include "wl12xx.h" - -struct acx_header; - -int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len); -int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer); -int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 id, void *buf, size_t len); -int wl12xx_cmd_configure(struct wl12xx *wl, u16 id, void *buf, size_t len); -int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, - void *bitmap, u16 bitmap_len, u8 bitmap_control); -int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable); -int wl1251_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, - u16 beacon_interval, u8 wait); -int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode); -int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer, - size_t len); -int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, - void *buf, size_t buf_len); - -/* unit ms */ -#define WL12XX_COMMAND_TIMEOUT 2000 - -enum wl12xx_commands { - CMD_RESET = 0, - CMD_INTERROGATE = 1, /*use this to read information elements*/ - CMD_CONFIGURE = 2, /*use this to write information elements*/ - CMD_ENABLE_RX = 3, - CMD_ENABLE_TX = 4, - CMD_DISABLE_RX = 5, - CMD_DISABLE_TX = 6, - CMD_SCAN = 8, - CMD_STOP_SCAN = 9, - CMD_VBM = 10, - CMD_START_JOIN = 11, - CMD_SET_KEYS = 12, - CMD_READ_MEMORY = 13, - CMD_WRITE_MEMORY = 14, - CMD_BEACON = 19, - CMD_PROBE_RESP = 20, - CMD_NULL_DATA = 21, - CMD_PROBE_REQ = 22, - CMD_TEST = 23, - CMD_RADIO_CALIBRATE = 25, /* OBSOLETE */ - CMD_ENABLE_RX_PATH = 27, /* OBSOLETE */ - CMD_NOISE_HIST = 28, - CMD_RX_RESET = 29, - CMD_PS_POLL = 30, - CMD_QOS_NULL_DATA = 31, - CMD_LNA_CONTROL = 32, - CMD_SET_BCN_MODE = 33, - CMD_MEASUREMENT = 34, - CMD_STOP_MEASUREMENT = 35, - CMD_DISCONNECT = 36, - CMD_SET_PS_MODE = 37, - CMD_CHANNEL_SWITCH = 38, - CMD_STOP_CHANNEL_SWICTH = 39, - CMD_AP_DISCOVERY = 40, - CMD_STOP_AP_DISCOVERY = 41, - CMD_SPS_SCAN = 42, - CMD_STOP_SPS_SCAN = 43, - CMD_HEALTH_CHECK = 45, - CMD_DEBUG = 46, - CMD_TRIGGER_SCAN_TO = 47, - - NUM_COMMANDS, - MAX_COMMAND_ID = 0xFFFF, -}; - -#define MAX_CMD_PARAMS 572 - -struct wl12xx_cmd_header { - u16 id; - u16 status; - /* payload */ - u8 data[0]; -} __attribute__ ((packed)); - -struct wl12xx_command { - struct wl12xx_cmd_header header; - u8 parameters[MAX_CMD_PARAMS]; -}; - -enum { - CMD_MAILBOX_IDLE = 0, - CMD_STATUS_SUCCESS = 1, - CMD_STATUS_UNKNOWN_CMD = 2, - CMD_STATUS_UNKNOWN_IE = 3, - CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11, - CMD_STATUS_RX_BUSY = 13, - CMD_STATUS_INVALID_PARAM = 14, - CMD_STATUS_TEMPLATE_TOO_LARGE = 15, - CMD_STATUS_OUT_OF_MEMORY = 16, - CMD_STATUS_STA_TABLE_FULL = 17, - CMD_STATUS_RADIO_ERROR = 18, - CMD_STATUS_WRONG_NESTING = 19, - CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ - CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ - MAX_COMMAND_STATUS = 0xff -}; - - -/* - * CMD_READ_MEMORY - * - * The host issues this command to read the WiLink device memory/registers. - * - * Note: The Base Band address has special handling (16 bits registers and - * addresses). For more information, see the hardware specification. - */ -/* - * CMD_WRITE_MEMORY - * - * The host issues this command to write the WiLink device memory/registers. - * - * The Base Band address has special handling (16 bits registers and - * addresses). For more information, see the hardware specification. - */ -#define MAX_READ_SIZE 256 - -struct cmd_read_write_memory { - struct wl12xx_cmd_header header; - - /* The address of the memory to read from or write to.*/ - u32 addr; - - /* The amount of data in bytes to read from or write to the WiLink - * device.*/ - u32 size; - - /* The actual value read from or written to the Wilink. The source - of this field is the Host in WRITE command or the Wilink in READ - command. */ - u8 value[MAX_READ_SIZE]; -}; - -#define CMDMBOX_HEADER_LEN 4 -#define CMDMBOX_INFO_ELEM_HEADER_LEN 4 - - -struct basic_scan_parameters { - u32 rx_config_options; - u32 rx_filter_options; - - /* - * Scan options: - * bit 0: When this bit is set, passive scan. - * bit 1: Band, when this bit is set we scan - * in the 5Ghz band. - * bit 2: voice mode, 0 for normal scan. - * bit 3: scan priority, 1 for high priority. - */ - u16 scan_options; - - /* Number of channels to scan */ - u8 num_channels; - - /* Number opf probe requests to send, per channel */ - u8 num_probe_requests; - - /* Rate and modulation for probe requests */ - u16 tx_rate; - - u8 tid_trigger; - u8 ssid_len; - u32 ssid[8]; - -} __attribute__ ((packed)); - -struct basic_scan_channel_parameters { - u32 min_duration; /* in TU */ - u32 max_duration; /* in TU */ - u32 bssid_lsb; - u16 bssid_msb; - - /* - * bits 0-3: Early termination count. - * bits 4-5: Early termination condition. - */ - u8 early_termination; - - u8 tx_power_att; - u8 channel; - u8 pad[3]; -} __attribute__ ((packed)); - -/* SCAN parameters */ -#define SCAN_MAX_NUM_OF_CHANNELS 16 - -struct cmd_scan { - struct wl12xx_cmd_header header; - - struct basic_scan_parameters params; - struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; -} __attribute__ ((packed)); - -enum { - BSS_TYPE_IBSS = 0, - BSS_TYPE_STA_BSS = 2, - BSS_TYPE_AP_BSS = 3, - MAX_BSS_TYPE = 0xFF -}; - -#define JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ -#define JOIN_CMD_CTRL_EARLY_WAKEUP_ENABLE 0x01 /* Early wakeup time */ - - -struct cmd_join { - struct wl12xx_cmd_header header; - - u32 bssid_lsb; - u16 bssid_msb; - u16 beacon_interval; /* in TBTTs */ - u32 rx_config_options; - u32 rx_filter_options; - - /* - * The target uses this field to determine the rate at - * which to transmit control frame responses (such as - * ACK or CTS frames). - */ - u16 basic_rate_set; - u8 dtim_interval; - u8 tx_ctrl_frame_rate; /* OBSOLETE */ - u8 tx_ctrl_frame_mod; /* OBSOLETE */ - /* - * bits 0-2: This bitwise field specifies the type - * of BSS to start or join (BSS_TYPE_*). - * bit 4: Band - The radio band in which to join - * or start. - * 0 - 2.4GHz band - * 1 - 5GHz band - * bits 3, 5-7: Reserved - */ - u8 bss_type; - u8 channel; - u8 ssid_len; - u8 ssid[IW_ESSID_MAX_SIZE]; - u8 ctrl; /* JOIN_CMD_CTRL_* */ - u8 tx_mgt_frame_rate; /* OBSOLETE */ - u8 tx_mgt_frame_mod; /* OBSOLETE */ - u8 reserved; -} __attribute__ ((packed)); - -struct cmd_enabledisable_path { - struct wl12xx_cmd_header header; - - u8 channel; - u8 padding[3]; -} __attribute__ ((packed)); - -#define WL12XX_MAX_TEMPLATE_SIZE 300 - -struct wl12xx_cmd_packet_template { - struct wl12xx_cmd_header header; - - __le16 size; - u8 data[0]; -} __attribute__ ((packed)); - -#define TIM_ELE_ID 5 -#define PARTIAL_VBM_MAX 251 - -struct wl12xx_tim { - u8 identity; - u8 length; - u8 dtim_count; - u8 dtim_period; - u8 bitmap_ctrl; - u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ -} __attribute__ ((packed)); - -/* Virtual Bit Map update */ -struct wl12xx_cmd_vbm_update { - struct wl12xx_cmd_header header; - __le16 len; - u8 padding[2]; - struct wl12xx_tim tim; -} __attribute__ ((packed)); - -enum wl12xx_cmd_ps_mode { - STATION_ACTIVE_MODE, - STATION_POWER_SAVE_MODE -}; - -struct wl12xx_cmd_ps_params { - struct wl12xx_cmd_header header; - - u8 ps_mode; /* STATION_* */ - u8 send_null_data; /* Do we have to send NULL data packet ? */ - u8 retries; /* Number of retires for the initial NULL data packet */ - - /* - * TUs during which the target stays awake after switching - * to power save mode. - */ - u8 hang_over_period; - u16 null_data_rate; - u8 pad[2]; -} __attribute__ ((packed)); - -struct wl12xx_cmd_trigger_scan_to { - struct wl12xx_cmd_header header; - - u32 timeout; -}; - -/* HW encryption keys */ -#define NUM_ACCESS_CATEGORIES_COPY 4 -#define MAX_KEY_SIZE 32 - -/* When set, disable HW encryption */ -#define DF_ENCRYPTION_DISABLE 0x01 -/* When set, disable HW decryption */ -#define DF_SNIFF_MODE_ENABLE 0x80 - -enum wl12xx_cmd_key_action { - KEY_ADD_OR_REPLACE = 1, - KEY_REMOVE = 2, - KEY_SET_ID = 3, - MAX_KEY_ACTION = 0xffff, -}; - -enum wl12xx_cmd_key_type { - KEY_WEP_DEFAULT = 0, - KEY_WEP_ADDR = 1, - KEY_AES_GROUP = 4, - KEY_AES_PAIRWISE = 5, - KEY_WEP_GROUP = 6, - KEY_TKIP_MIC_GROUP = 10, - KEY_TKIP_MIC_PAIRWISE = 11, -}; - -/* - * - * key_type_e key size key format - * ---------- --------- ---------- - * 0x00 5, 13, 29 Key data - * 0x01 5, 13, 29 Key data - * 0x04 16 16 bytes of key data - * 0x05 16 16 bytes of key data - * 0x0a 32 16 bytes of TKIP key data - * 8 bytes of RX MIC key data - * 8 bytes of TX MIC key data - * 0x0b 32 16 bytes of TKIP key data - * 8 bytes of RX MIC key data - * 8 bytes of TX MIC key data - * - */ - -struct wl12xx_cmd_set_keys { - struct wl12xx_cmd_header header; - - /* Ignored for default WEP key */ - u8 addr[ETH_ALEN]; - - /* key_action_e */ - u16 key_action; - - u16 reserved_1; - - /* key size in bytes */ - u8 key_size; - - /* key_type_e */ - u8 key_type; - u8 ssid_profile; - - /* - * TKIP, AES: frame's key id field. - * For WEP default key: key id; - */ - u8 id; - u8 reserved_2[6]; - u8 key[MAX_KEY_SIZE]; - u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; - u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; -} __attribute__ ((packed)); - - -#endif /* __WL12XX_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c deleted file mode 100644 index 94ad9948565..00000000000 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ /dev/null @@ -1,518 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "debugfs.h" - -#include - -#include "wl12xx.h" -#include "acx.h" -#include "ps.h" - -/* ms */ -#define WL12XX_DEBUGFS_STATS_LIFETIME 1000 - -/* debugfs macros idea from mac80211 */ - -#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ -static ssize_t name## _read(struct file *file, char __user *userbuf, \ - size_t count, loff_t *ppos) \ -{ \ - struct wl12xx *wl = file->private_data; \ - char buf[buflen]; \ - int res; \ - \ - res = scnprintf(buf, buflen, fmt "\n", ##value); \ - return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ -} \ - \ -static const struct file_operations name## _ops = { \ - .read = name## _read, \ - .open = wl12xx_open_file_generic, \ -}; - -#define DEBUGFS_ADD(name, parent) \ - wl->debugfs.name = debugfs_create_file(#name, 0400, parent, \ - wl, &name## _ops); \ - if (IS_ERR(wl->debugfs.name)) { \ - ret = PTR_ERR(wl->debugfs.name); \ - wl->debugfs.name = NULL; \ - goto out; \ - } - -#define DEBUGFS_DEL(name) \ - do { \ - debugfs_remove(wl->debugfs.name); \ - wl->debugfs.name = NULL; \ - } while (0) - -#define DEBUGFS_FWSTATS_FILE(sub, name, buflen, fmt) \ -static ssize_t sub## _ ##name## _read(struct file *file, \ - char __user *userbuf, \ - size_t count, loff_t *ppos) \ -{ \ - struct wl12xx *wl = file->private_data; \ - char buf[buflen]; \ - int res; \ - \ - wl12xx_debugfs_update_stats(wl); \ - \ - res = scnprintf(buf, buflen, fmt "\n", \ - wl->stats.fw_stats->sub.name); \ - return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ -} \ - \ -static const struct file_operations sub## _ ##name## _ops = { \ - .read = sub## _ ##name## _read, \ - .open = wl12xx_open_file_generic, \ -}; - -#define DEBUGFS_FWSTATS_ADD(sub, name) \ - DEBUGFS_ADD(sub## _ ##name, wl->debugfs.fw_statistics) - -#define DEBUGFS_FWSTATS_DEL(sub, name) \ - DEBUGFS_DEL(sub## _ ##name) - -static void wl12xx_debugfs_update_stats(struct wl12xx *wl) -{ - int ret; - - mutex_lock(&wl->mutex); - - ret = wl12xx_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - if (wl->state == WL12XX_STATE_ON && - time_after(jiffies, wl->stats.fw_stats_update + - msecs_to_jiffies(WL12XX_DEBUGFS_STATS_LIFETIME))) { - wl12xx_acx_statistics(wl, wl->stats.fw_stats); - wl->stats.fw_stats_update = jiffies; - } - - wl12xx_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - -static int wl12xx_open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, hw_stuck, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, dropped, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, fcs_err, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, path_reset, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, reset_counter, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(dma, rx_requested, 20, "%u"); -DEBUGFS_FWSTATS_FILE(dma, rx_errors, 20, "%u"); -DEBUGFS_FWSTATS_FILE(dma, tx_requested, 20, "%u"); -DEBUGFS_FWSTATS_FILE(dma, tx_errors, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, fiqs, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_headers, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_rdys, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, irqs, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, tx_procs, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, decrypt_done, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, dma0_done, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, dma1_done, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, commands, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_procs, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, pci_pm, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, wakeups, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, low_rssi, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(wep, addr_key_count, 20, "%u"); -DEBUGFS_FWSTATS_FILE(wep, default_key_count, 20, "%u"); -/* skipping wep.reserved */ -DEBUGFS_FWSTATS_FILE(wep, key_not_found, 20, "%u"); -DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, 20, "%u"); -DEBUGFS_FWSTATS_FILE(wep, packets, 20, "%u"); -DEBUGFS_FWSTATS_FILE(wep, interrupt, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(pwr, ps_enter, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, elp_enter, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, power_save_off, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, enable_ps, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, disable_ps, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, 20, "%u"); -/* skipping cont_miss_bcns_spread for now */ -DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(mic, rx_pkts, 20, "%u"); -DEBUGFS_FWSTATS_FILE(mic, calc_failure, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(event, heart_beat, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, calibration, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, rx_mismatch, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, rx_pool, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, oom_late, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, tx_stuck, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, - 20, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, 20, "%u"); - -DEBUGFS_READONLY_FILE(retry_count, 20, "%u", wl->stats.retry_count); -DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u", - wl->stats.excessive_retries); - -static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct wl12xx *wl = file->private_data; - u32 queue_len; - char buf[20]; - int res; - - queue_len = skb_queue_len(&wl->tx_queue); - - res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); - return simple_read_from_buffer(userbuf, count, ppos, buf, res); -} - -static const struct file_operations tx_queue_len_ops = { - .read = tx_queue_len_read, - .open = wl12xx_open_file_generic, -}; - -static void wl12xx_debugfs_delete_files(struct wl12xx *wl) -{ - DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); - - DEBUGFS_FWSTATS_DEL(rx, out_of_mem); - DEBUGFS_FWSTATS_DEL(rx, hdr_overflow); - DEBUGFS_FWSTATS_DEL(rx, hw_stuck); - DEBUGFS_FWSTATS_DEL(rx, dropped); - DEBUGFS_FWSTATS_DEL(rx, fcs_err); - DEBUGFS_FWSTATS_DEL(rx, xfr_hint_trig); - DEBUGFS_FWSTATS_DEL(rx, path_reset); - DEBUGFS_FWSTATS_DEL(rx, reset_counter); - - DEBUGFS_FWSTATS_DEL(dma, rx_requested); - DEBUGFS_FWSTATS_DEL(dma, rx_errors); - DEBUGFS_FWSTATS_DEL(dma, tx_requested); - DEBUGFS_FWSTATS_DEL(dma, tx_errors); - - DEBUGFS_FWSTATS_DEL(isr, cmd_cmplt); - DEBUGFS_FWSTATS_DEL(isr, fiqs); - DEBUGFS_FWSTATS_DEL(isr, rx_headers); - DEBUGFS_FWSTATS_DEL(isr, rx_mem_overflow); - DEBUGFS_FWSTATS_DEL(isr, rx_rdys); - DEBUGFS_FWSTATS_DEL(isr, irqs); - DEBUGFS_FWSTATS_DEL(isr, tx_procs); - DEBUGFS_FWSTATS_DEL(isr, decrypt_done); - DEBUGFS_FWSTATS_DEL(isr, dma0_done); - DEBUGFS_FWSTATS_DEL(isr, dma1_done); - DEBUGFS_FWSTATS_DEL(isr, tx_exch_complete); - DEBUGFS_FWSTATS_DEL(isr, commands); - DEBUGFS_FWSTATS_DEL(isr, rx_procs); - DEBUGFS_FWSTATS_DEL(isr, hw_pm_mode_changes); - DEBUGFS_FWSTATS_DEL(isr, host_acknowledges); - DEBUGFS_FWSTATS_DEL(isr, pci_pm); - DEBUGFS_FWSTATS_DEL(isr, wakeups); - DEBUGFS_FWSTATS_DEL(isr, low_rssi); - - DEBUGFS_FWSTATS_DEL(wep, addr_key_count); - DEBUGFS_FWSTATS_DEL(wep, default_key_count); - /* skipping wep.reserved */ - DEBUGFS_FWSTATS_DEL(wep, key_not_found); - DEBUGFS_FWSTATS_DEL(wep, decrypt_fail); - DEBUGFS_FWSTATS_DEL(wep, packets); - DEBUGFS_FWSTATS_DEL(wep, interrupt); - - DEBUGFS_FWSTATS_DEL(pwr, ps_enter); - DEBUGFS_FWSTATS_DEL(pwr, elp_enter); - DEBUGFS_FWSTATS_DEL(pwr, missing_bcns); - DEBUGFS_FWSTATS_DEL(pwr, wake_on_host); - DEBUGFS_FWSTATS_DEL(pwr, wake_on_timer_exp); - DEBUGFS_FWSTATS_DEL(pwr, tx_with_ps); - DEBUGFS_FWSTATS_DEL(pwr, tx_without_ps); - DEBUGFS_FWSTATS_DEL(pwr, rcvd_beacons); - DEBUGFS_FWSTATS_DEL(pwr, power_save_off); - DEBUGFS_FWSTATS_DEL(pwr, enable_ps); - DEBUGFS_FWSTATS_DEL(pwr, disable_ps); - DEBUGFS_FWSTATS_DEL(pwr, fix_tsf_ps); - /* skipping cont_miss_bcns_spread for now */ - DEBUGFS_FWSTATS_DEL(pwr, rcvd_awake_beacons); - - DEBUGFS_FWSTATS_DEL(mic, rx_pkts); - DEBUGFS_FWSTATS_DEL(mic, calc_failure); - - DEBUGFS_FWSTATS_DEL(aes, encrypt_fail); - DEBUGFS_FWSTATS_DEL(aes, decrypt_fail); - DEBUGFS_FWSTATS_DEL(aes, encrypt_packets); - DEBUGFS_FWSTATS_DEL(aes, decrypt_packets); - DEBUGFS_FWSTATS_DEL(aes, encrypt_interrupt); - DEBUGFS_FWSTATS_DEL(aes, decrypt_interrupt); - - DEBUGFS_FWSTATS_DEL(event, heart_beat); - DEBUGFS_FWSTATS_DEL(event, calibration); - DEBUGFS_FWSTATS_DEL(event, rx_mismatch); - DEBUGFS_FWSTATS_DEL(event, rx_mem_empty); - DEBUGFS_FWSTATS_DEL(event, rx_pool); - DEBUGFS_FWSTATS_DEL(event, oom_late); - DEBUGFS_FWSTATS_DEL(event, phy_transmit_error); - DEBUGFS_FWSTATS_DEL(event, tx_stuck); - - DEBUGFS_FWSTATS_DEL(ps, pspoll_timeouts); - DEBUGFS_FWSTATS_DEL(ps, upsd_timeouts); - DEBUGFS_FWSTATS_DEL(ps, upsd_max_sptime); - DEBUGFS_FWSTATS_DEL(ps, upsd_max_apturn); - DEBUGFS_FWSTATS_DEL(ps, pspoll_max_apturn); - DEBUGFS_FWSTATS_DEL(ps, pspoll_utilization); - DEBUGFS_FWSTATS_DEL(ps, upsd_utilization); - - DEBUGFS_FWSTATS_DEL(rxpipe, rx_prep_beacon_drop); - DEBUGFS_FWSTATS_DEL(rxpipe, descr_host_int_trig_rx_data); - DEBUGFS_FWSTATS_DEL(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); - DEBUGFS_FWSTATS_DEL(rxpipe, missed_beacon_host_int_trig_rx_data); - DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data); - - DEBUGFS_DEL(tx_queue_len); - DEBUGFS_DEL(retry_count); - DEBUGFS_DEL(excessive_retries); -} - -static int wl12xx_debugfs_add_files(struct wl12xx *wl) -{ - int ret = 0; - - DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow); - - DEBUGFS_FWSTATS_ADD(rx, out_of_mem); - DEBUGFS_FWSTATS_ADD(rx, hdr_overflow); - DEBUGFS_FWSTATS_ADD(rx, hw_stuck); - DEBUGFS_FWSTATS_ADD(rx, dropped); - DEBUGFS_FWSTATS_ADD(rx, fcs_err); - DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig); - DEBUGFS_FWSTATS_ADD(rx, path_reset); - DEBUGFS_FWSTATS_ADD(rx, reset_counter); - - DEBUGFS_FWSTATS_ADD(dma, rx_requested); - DEBUGFS_FWSTATS_ADD(dma, rx_errors); - DEBUGFS_FWSTATS_ADD(dma, tx_requested); - DEBUGFS_FWSTATS_ADD(dma, tx_errors); - - DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt); - DEBUGFS_FWSTATS_ADD(isr, fiqs); - DEBUGFS_FWSTATS_ADD(isr, rx_headers); - DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow); - DEBUGFS_FWSTATS_ADD(isr, rx_rdys); - DEBUGFS_FWSTATS_ADD(isr, irqs); - DEBUGFS_FWSTATS_ADD(isr, tx_procs); - DEBUGFS_FWSTATS_ADD(isr, decrypt_done); - DEBUGFS_FWSTATS_ADD(isr, dma0_done); - DEBUGFS_FWSTATS_ADD(isr, dma1_done); - DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete); - DEBUGFS_FWSTATS_ADD(isr, commands); - DEBUGFS_FWSTATS_ADD(isr, rx_procs); - DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes); - DEBUGFS_FWSTATS_ADD(isr, host_acknowledges); - DEBUGFS_FWSTATS_ADD(isr, pci_pm); - DEBUGFS_FWSTATS_ADD(isr, wakeups); - DEBUGFS_FWSTATS_ADD(isr, low_rssi); - - DEBUGFS_FWSTATS_ADD(wep, addr_key_count); - DEBUGFS_FWSTATS_ADD(wep, default_key_count); - /* skipping wep.reserved */ - DEBUGFS_FWSTATS_ADD(wep, key_not_found); - DEBUGFS_FWSTATS_ADD(wep, decrypt_fail); - DEBUGFS_FWSTATS_ADD(wep, packets); - DEBUGFS_FWSTATS_ADD(wep, interrupt); - - DEBUGFS_FWSTATS_ADD(pwr, ps_enter); - DEBUGFS_FWSTATS_ADD(pwr, elp_enter); - DEBUGFS_FWSTATS_ADD(pwr, missing_bcns); - DEBUGFS_FWSTATS_ADD(pwr, wake_on_host); - DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp); - DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps); - DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps); - DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons); - DEBUGFS_FWSTATS_ADD(pwr, power_save_off); - DEBUGFS_FWSTATS_ADD(pwr, enable_ps); - DEBUGFS_FWSTATS_ADD(pwr, disable_ps); - DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps); - /* skipping cont_miss_bcns_spread for now */ - DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons); - - DEBUGFS_FWSTATS_ADD(mic, rx_pkts); - DEBUGFS_FWSTATS_ADD(mic, calc_failure); - - DEBUGFS_FWSTATS_ADD(aes, encrypt_fail); - DEBUGFS_FWSTATS_ADD(aes, decrypt_fail); - DEBUGFS_FWSTATS_ADD(aes, encrypt_packets); - DEBUGFS_FWSTATS_ADD(aes, decrypt_packets); - DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt); - DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt); - - DEBUGFS_FWSTATS_ADD(event, heart_beat); - DEBUGFS_FWSTATS_ADD(event, calibration); - DEBUGFS_FWSTATS_ADD(event, rx_mismatch); - DEBUGFS_FWSTATS_ADD(event, rx_mem_empty); - DEBUGFS_FWSTATS_ADD(event, rx_pool); - DEBUGFS_FWSTATS_ADD(event, oom_late); - DEBUGFS_FWSTATS_ADD(event, phy_transmit_error); - DEBUGFS_FWSTATS_ADD(event, tx_stuck); - - DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts); - DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts); - DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime); - DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn); - DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn); - DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization); - DEBUGFS_FWSTATS_ADD(ps, upsd_utilization); - - DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop); - DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data); - DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); - DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); - DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); - - DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir); - DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); - DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); - -out: - if (ret < 0) - wl12xx_debugfs_delete_files(wl); - - return ret; -} - -void wl12xx_debugfs_reset(struct wl12xx *wl) -{ - memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); - wl->stats.retry_count = 0; - wl->stats.excessive_retries = 0; -} - -int wl12xx_debugfs_init(struct wl12xx *wl) -{ - int ret; - - wl->debugfs.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); - - if (IS_ERR(wl->debugfs.rootdir)) { - ret = PTR_ERR(wl->debugfs.rootdir); - wl->debugfs.rootdir = NULL; - goto err; - } - - wl->debugfs.fw_statistics = debugfs_create_dir("fw-statistics", - wl->debugfs.rootdir); - - if (IS_ERR(wl->debugfs.fw_statistics)) { - ret = PTR_ERR(wl->debugfs.fw_statistics); - wl->debugfs.fw_statistics = NULL; - goto err_root; - } - - wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats), - GFP_KERNEL); - - if (!wl->stats.fw_stats) { - ret = -ENOMEM; - goto err_fw; - } - - wl->stats.fw_stats_update = jiffies; - - ret = wl12xx_debugfs_add_files(wl); - - if (ret < 0) - goto err_file; - - return 0; - -err_file: - kfree(wl->stats.fw_stats); - wl->stats.fw_stats = NULL; - -err_fw: - debugfs_remove(wl->debugfs.fw_statistics); - wl->debugfs.fw_statistics = NULL; - -err_root: - debugfs_remove(wl->debugfs.rootdir); - wl->debugfs.rootdir = NULL; - -err: - return ret; -} - -void wl12xx_debugfs_exit(struct wl12xx *wl) -{ - wl12xx_debugfs_delete_files(wl); - - kfree(wl->stats.fw_stats); - wl->stats.fw_stats = NULL; - - debugfs_remove(wl->debugfs.fw_statistics); - wl->debugfs.fw_statistics = NULL; - - debugfs_remove(wl->debugfs.rootdir); - wl->debugfs.rootdir = NULL; - -} diff --git a/drivers/net/wireless/wl12xx/debugfs.h b/drivers/net/wireless/wl12xx/debugfs.h deleted file mode 100644 index 562cdcbcc87..00000000000 --- a/drivers/net/wireless/wl12xx/debugfs.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef WL12XX_DEBUGFS_H -#define WL12XX_DEBUGFS_H - -#include "wl12xx.h" - -int wl12xx_debugfs_init(struct wl12xx *wl); -void wl12xx_debugfs_exit(struct wl12xx *wl); -void wl12xx_debugfs_reset(struct wl12xx *wl); - -#endif /* WL12XX_DEBUGFS_H */ diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c deleted file mode 100644 index 99529ca89a7..00000000000 --- a/drivers/net/wireless/wl12xx/event.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "wl12xx.h" -#include "reg.h" -#include "spi.h" -#include "event.h" -#include "ps.h" - -static int wl12xx_event_scan_complete(struct wl12xx *wl, - struct event_mailbox *mbox) -{ - wl12xx_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", - mbox->scheduled_scan_status, - mbox->scheduled_scan_channels); - - if (wl->scanning) { - mutex_unlock(&wl->mutex); - ieee80211_scan_completed(wl->hw, false); - mutex_lock(&wl->mutex); - wl->scanning = false; - } - - return 0; -} - -static void wl12xx_event_mbox_dump(struct event_mailbox *mbox) -{ - wl12xx_debug(DEBUG_EVENT, "MBOX DUMP:"); - wl12xx_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); - wl12xx_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); -} - -static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox) -{ - int ret; - u32 vector; - - wl12xx_event_mbox_dump(mbox); - - vector = mbox->events_vector & ~(mbox->events_mask); - wl12xx_debug(DEBUG_EVENT, "vector: 0x%x", vector); - - if (vector & SCAN_COMPLETE_EVENT_ID) { - ret = wl12xx_event_scan_complete(wl, mbox); - if (ret < 0) - return ret; - } - - if (vector & BSS_LOSE_EVENT_ID) { - wl12xx_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); - - if (wl->psm_requested && wl->psm) { - ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE); - if (ret < 0) - return ret; - } - } - - return 0; -} - -int wl12xx_event_unmask(struct wl12xx *wl) -{ - int ret; - - ret = wl12xx_acx_event_mbox_mask(wl, ~(wl->event_mask)); - if (ret < 0) - return ret; - - return 0; -} - -void wl12xx_event_mbox_config(struct wl12xx *wl) -{ - wl->mbox_ptr[0] = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR); - wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); - - wl12xx_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", - wl->mbox_ptr[0], wl->mbox_ptr[1]); -} - -int wl12xx_event_handle(struct wl12xx *wl, u8 mbox_num) -{ - struct event_mailbox mbox; - int ret; - - wl12xx_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); - - if (mbox_num > 1) - return -EINVAL; - - /* first we read the mbox descriptor */ - wl12xx_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, - sizeof(struct event_mailbox)); - - /* process the descriptor */ - ret = wl12xx_event_process(wl, &mbox); - if (ret < 0) - return ret; - - /* then we let the firmware know it can go on...*/ - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); - - return 0; -} diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h deleted file mode 100644 index 1f4c2f7438a..00000000000 --- a/drivers/net/wireless/wl12xx/event.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL12XX_EVENT_H__ -#define __WL12XX_EVENT_H__ - -/* - * Mbox events - * - * The event mechanism is based on a pair of event buffers (buffers A and - * B) at fixed locations in the target's memory. The host processes one - * buffer while the other buffer continues to collect events. If the host - * is not processing events, an interrupt is issued to signal that a buffer - * is ready. Once the host is done with processing events from one buffer, - * it signals the target (with an ACK interrupt) that the event buffer is - * free. - */ - -enum { - RESERVED1_EVENT_ID = BIT(0), - RESERVED2_EVENT_ID = BIT(1), - MEASUREMENT_START_EVENT_ID = BIT(2), - SCAN_COMPLETE_EVENT_ID = BIT(3), - CALIBRATION_COMPLETE_EVENT_ID = BIT(4), - ROAMING_TRIGGER_LOW_RSSI_EVENT_ID = BIT(5), - PS_REPORT_EVENT_ID = BIT(6), - SYNCHRONIZATION_TIMEOUT_EVENT_ID = BIT(7), - HEALTH_REPORT_EVENT_ID = BIT(8), - ACI_DETECTION_EVENT_ID = BIT(9), - DEBUG_REPORT_EVENT_ID = BIT(10), - MAC_STATUS_EVENT_ID = BIT(11), - DISCONNECT_EVENT_COMPLETE_ID = BIT(12), - JOIN_EVENT_COMPLETE_ID = BIT(13), - CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(14), - BSS_LOSE_EVENT_ID = BIT(15), - ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(16), - MEASUREMENT_COMPLETE_EVENT_ID = BIT(17), - AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(18), - SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(19), - PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(20), - RESET_BSS_EVENT_ID = BIT(21), - REGAINED_BSS_EVENT_ID = BIT(22), - ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID = BIT(23), - ROAMING_TRIGGER_LOW_SNR_EVENT_ID = BIT(24), - ROAMING_TRIGGER_REGAINED_SNR_EVENT_ID = BIT(25), - - DBG_EVENT_ID = BIT(26), - BT_PTA_SENSE_EVENT_ID = BIT(27), - BT_PTA_PREDICTION_EVENT_ID = BIT(28), - BT_PTA_AVALANCHE_EVENT_ID = BIT(29), - - PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(30), - - EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, -}; - -struct event_debug_report { - u8 debug_event_id; - u8 num_params; - u16 pad; - u32 report_1; - u32 report_2; - u32 report_3; -} __attribute__ ((packed)); - -struct event_mailbox { - u32 events_vector; - u32 events_mask; - u32 reserved_1; - u32 reserved_2; - - char average_rssi_level; - u8 ps_status; - u8 channel_switch_status; - u8 scheduled_scan_status; - - /* Channels scanned by the scheduled scan */ - u16 scheduled_scan_channels; - - /* If bit 0 is set -> target's fatal error */ - u16 health_report; - u16 bad_fft_counter; - u8 bt_pta_sense_info; - u8 bt_pta_protective_info; - u32 reserved; - u32 debug_report[2]; - - /* Number of FCS errors since last event */ - u32 fcs_err_counter; - - struct event_debug_report report; - u8 average_snr_level; - u8 padding[19]; -} __attribute__ ((packed)); - -int wl12xx_event_unmask(struct wl12xx *wl); -void wl12xx_event_mbox_config(struct wl12xx *wl); -int wl12xx_event_handle(struct wl12xx *wl, u8 mbox); - -#endif diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c deleted file mode 100644 index 2a573a6010b..00000000000 --- a/drivers/net/wireless/wl12xx/init.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include - -#include "init.h" -#include "wl12xx_80211.h" -#include "acx.h" -#include "cmd.h" - -int wl12xx_hw_init_hwenc_config(struct wl12xx *wl) -{ - int ret; - - ret = wl12xx_acx_feature_cfg(wl); - if (ret < 0) { - wl12xx_warning("couldn't set feature config"); - return ret; - } - - ret = wl12xx_acx_default_key(wl, wl->default_key); - if (ret < 0) { - wl12xx_warning("couldn't set default key"); - return ret; - } - - return 0; -} - -int wl12xx_hw_init_templates_config(struct wl12xx *wl) -{ - int ret; - u8 partial_vbm[PARTIAL_VBM_MAX]; - - /* send empty templates for fw memory reservation */ - ret = wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, NULL, - sizeof(struct wl12xx_probe_req_template)); - if (ret < 0) - return ret; - - ret = wl12xx_cmd_template_set(wl, CMD_NULL_DATA, NULL, - sizeof(struct wl12xx_null_data_template)); - if (ret < 0) - return ret; - - ret = wl12xx_cmd_template_set(wl, CMD_PS_POLL, NULL, - sizeof(struct wl12xx_ps_poll_template)); - if (ret < 0) - return ret; - - ret = wl12xx_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL, - sizeof - (struct wl12xx_qos_null_data_template)); - if (ret < 0) - return ret; - - ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, NULL, - sizeof - (struct wl12xx_probe_resp_template)); - if (ret < 0) - return ret; - - ret = wl12xx_cmd_template_set(wl, CMD_BEACON, NULL, - sizeof - (struct wl12xx_beacon_template)); - if (ret < 0) - return ret; - - /* tim templates, first reserve space then allocate an empty one */ - memset(partial_vbm, 0, PARTIAL_VBM_MAX); - ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0); - if (ret < 0) - return ret; - - ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0); - if (ret < 0) - return ret; - - return 0; -} - -int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter) -{ - int ret; - - ret = wl12xx_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); - if (ret < 0) - return ret; - - ret = wl12xx_acx_rx_config(wl, config, filter); - if (ret < 0) - return ret; - - return 0; -} - -int wl12xx_hw_init_phy_config(struct wl12xx *wl) -{ - int ret; - - ret = wl12xx_acx_pd_threshold(wl); - if (ret < 0) - return ret; - - ret = wl12xx_acx_slot(wl, DEFAULT_SLOT_TIME); - if (ret < 0) - return ret; - - ret = wl12xx_acx_group_address_tbl(wl); - if (ret < 0) - return ret; - - ret = wl12xx_acx_service_period_timeout(wl); - if (ret < 0) - return ret; - - ret = wl12xx_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); - if (ret < 0) - return ret; - - return 0; -} - -int wl12xx_hw_init_beacon_filter(struct wl12xx *wl) -{ - int ret; - - ret = wl12xx_acx_beacon_filter_opt(wl); - if (ret < 0) - return ret; - - ret = wl12xx_acx_beacon_filter_table(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl12xx_hw_init_pta(struct wl12xx *wl) -{ - int ret; - - ret = wl12xx_acx_sg_enable(wl); - if (ret < 0) - return ret; - - ret = wl12xx_acx_sg_cfg(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl12xx_hw_init_energy_detection(struct wl12xx *wl) -{ - int ret; - - ret = wl12xx_acx_cca_threshold(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl) -{ - int ret; - - ret = wl12xx_acx_bcn_dtim_options(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl12xx_hw_init_power_auth(struct wl12xx *wl) -{ - return wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM); -} diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/init.h deleted file mode 100644 index c8b6cd0b7c3..00000000000 --- a/drivers/net/wireless/wl12xx/init.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL12XX_INIT_H__ -#define __WL12XX_INIT_H__ - -#include "wl12xx.h" - -int wl12xx_hw_init_hwenc_config(struct wl12xx *wl); -int wl12xx_hw_init_templates_config(struct wl12xx *wl); -int wl12xx_hw_init_mem_config(struct wl12xx *wl); -int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter); -int wl12xx_hw_init_phy_config(struct wl12xx *wl); -int wl12xx_hw_init_beacon_filter(struct wl12xx *wl); -int wl12xx_hw_init_pta(struct wl12xx *wl); -int wl12xx_hw_init_energy_detection(struct wl12xx *wl); -int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl); -int wl12xx_hw_init_power_auth(struct wl12xx *wl); - -#endif diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c deleted file mode 100644 index dd75d3d2efa..00000000000 --- a/drivers/net/wireless/wl12xx/main.c +++ /dev/null @@ -1,1442 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "wl12xx.h" -#include "wl12xx_80211.h" -#include "reg.h" -#include "wl1251_ops.h" -#include "spi.h" -#include "event.h" -#include "wl1251_tx.h" -#include "rx.h" -#include "ps.h" -#include "init.h" -#include "debugfs.h" - -static void wl12xx_disable_interrupts(struct wl12xx *wl) -{ - disable_irq(wl->irq); -} - -static void wl12xx_power_off(struct wl12xx *wl) -{ - wl->set_power(false); -} - -static void wl12xx_power_on(struct wl12xx *wl) -{ - wl->set_power(true); -} - -static irqreturn_t wl12xx_irq(int irq, void *cookie) -{ - struct wl12xx *wl; - - wl12xx_debug(DEBUG_IRQ, "IRQ"); - - wl = cookie; - - schedule_work(&wl->irq_work); - - return IRQ_HANDLED; -} - -static int wl12xx_fetch_firmware(struct wl12xx *wl) -{ - const struct firmware *fw; - int ret; - - ret = request_firmware(&fw, wl->chip.fw_filename, &wl->spi->dev); - - if (ret < 0) { - wl12xx_error("could not get firmware: %d", ret); - return ret; - } - - if (fw->size % 4) { - wl12xx_error("firmware size is not multiple of 32 bits: %zu", - fw->size); - ret = -EILSEQ; - goto out; - } - - wl->fw_len = fw->size; - wl->fw = kmalloc(wl->fw_len, GFP_KERNEL); - - if (!wl->fw) { - wl12xx_error("could not allocate memory for the firmware"); - ret = -ENOMEM; - goto out; - } - - memcpy(wl->fw, fw->data, wl->fw_len); - - ret = 0; - -out: - release_firmware(fw); - - return ret; -} - -static int wl12xx_fetch_nvs(struct wl12xx *wl) -{ - const struct firmware *fw; - int ret; - - ret = request_firmware(&fw, wl->chip.nvs_filename, &wl->spi->dev); - - if (ret < 0) { - wl12xx_error("could not get nvs file: %d", ret); - return ret; - } - - if (fw->size % 4) { - wl12xx_error("nvs size is not multiple of 32 bits: %zu", - fw->size); - ret = -EILSEQ; - goto out; - } - - wl->nvs_len = fw->size; - wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL); - - if (!wl->nvs) { - wl12xx_error("could not allocate memory for the nvs file"); - ret = -ENOMEM; - goto out; - } - - memcpy(wl->nvs, fw->data, wl->nvs_len); - - ret = 0; - -out: - release_firmware(fw); - - return ret; -} - -static void wl12xx_fw_wakeup(struct wl12xx *wl) -{ - u32 elp_reg; - - elp_reg = ELPCTRL_WAKE_UP; - wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); - elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); - - if (!(elp_reg & ELPCTRL_WLAN_READY)) { - wl12xx_warning("WLAN not ready"); - } -} - -static int wl12xx_chip_wakeup(struct wl12xx *wl) -{ - int ret = 0; - - wl12xx_power_on(wl); - msleep(wl->chip.power_on_sleep); - wl12xx_spi_reset(wl); - wl12xx_spi_init(wl); - - /* We don't need a real memory partition here, because we only want - * to use the registers at this point. */ - wl12xx_set_partition(wl, - 0x00000000, - 0x00000000, - REGISTERS_BASE, - REGISTERS_DOWN_SIZE); - - /* ELP module wake up */ - wl12xx_fw_wakeup(wl); - - /* whal_FwCtrl_BootSm() */ - - /* 0. read chip id from CHIP_ID */ - wl->chip.id = wl12xx_reg_read32(wl, CHIP_ID_B); - - /* 1. check if chip id is valid */ - - switch (wl->chip.id) { - case CHIP_ID_1251_PG12: - wl12xx_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", - wl->chip.id); - - wl1251_setup(wl); - - break; - case CHIP_ID_1251_PG10: - case CHIP_ID_1251_PG11: - default: - wl12xx_error("unsupported chip id: 0x%x", wl->chip.id); - ret = -ENODEV; - goto out; - } - - if (wl->fw == NULL) { - ret = wl12xx_fetch_firmware(wl); - if (ret < 0) - goto out; - } - - /* No NVS from netlink, try to get it from the filesystem */ - if (wl->nvs == NULL) { - ret = wl12xx_fetch_nvs(wl); - if (ret < 0) - goto out; - } - -out: - return ret; -} - -static void wl12xx_filter_work(struct work_struct *work) -{ - struct wl12xx *wl = - container_of(work, struct wl12xx, filter_work); - int ret; - - mutex_lock(&wl->mutex); - - if (wl->state == WL12XX_STATE_OFF) - goto out; - - ret = wl12xx_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - /* FIXME: replace the magic numbers with proper definitions */ - ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); - if (ret < 0) - goto out_sleep; - -out_sleep: - wl12xx_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - -int wl12xx_plt_start(struct wl12xx *wl) -{ - int ret; - - wl12xx_notice("power up"); - - if (wl->state != WL12XX_STATE_OFF) { - wl12xx_error("cannot go into PLT state because not " - "in off state: %d", wl->state); - return -EBUSY; - } - - wl->state = WL12XX_STATE_PLT; - - ret = wl12xx_chip_wakeup(wl); - if (ret < 0) - return ret; - - ret = wl->chip.op_boot(wl); - if (ret < 0) - return ret; - - wl12xx_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); - - ret = wl->chip.op_plt_init(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl12xx_plt_stop(struct wl12xx *wl) -{ - wl12xx_notice("power down"); - - if (wl->state != WL12XX_STATE_PLT) { - wl12xx_error("cannot power down because not in PLT " - "state: %d", wl->state); - return -EBUSY; - } - - wl12xx_disable_interrupts(wl); - wl12xx_power_off(wl); - - wl->state = WL12XX_STATE_OFF; - - return 0; -} - - -static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct wl12xx *wl = hw->priv; - - skb_queue_tail(&wl->tx_queue, skb); - - /* - * The chip specific setup must run before the first TX packet - - * before that, the tx_work will not be initialized! - */ - - schedule_work(&wl->tx_work); - - /* - * The workqueue is slow to process the tx_queue and we need stop - * the queue here, otherwise the queue will get too long. - */ - if (skb_queue_len(&wl->tx_queue) >= WL12XX_TX_QUEUE_MAX_LENGTH) { - ieee80211_stop_queues(wl->hw); - - /* - * FIXME: this is racy, the variable is not properly - * protected. Maybe fix this by removing the stupid - * variable altogether and checking the real queue state? - */ - wl->tx_queue_stopped = true; - } - - return NETDEV_TX_OK; -} - -static int wl12xx_op_start(struct ieee80211_hw *hw) -{ - struct wl12xx *wl = hw->priv; - int ret = 0; - - wl12xx_debug(DEBUG_MAC80211, "mac80211 start"); - - mutex_lock(&wl->mutex); - - if (wl->state != WL12XX_STATE_OFF) { - wl12xx_error("cannot start because not in off state: %d", - wl->state); - ret = -EBUSY; - goto out; - } - - ret = wl12xx_chip_wakeup(wl); - if (ret < 0) - return ret; - - ret = wl->chip.op_boot(wl); - if (ret < 0) - goto out; - - ret = wl->chip.op_hw_init(wl); - if (ret < 0) - goto out; - - ret = wl12xx_acx_station_id(wl); - if (ret < 0) - goto out; - - wl->state = WL12XX_STATE_ON; - - wl12xx_info("firmware booted (%s)", wl->chip.fw_ver); - -out: - if (ret < 0) - wl12xx_power_off(wl); - - mutex_unlock(&wl->mutex); - - return ret; -} - -static void wl12xx_op_stop(struct ieee80211_hw *hw) -{ - struct wl12xx *wl = hw->priv; - - wl12xx_info("down"); - - wl12xx_debug(DEBUG_MAC80211, "mac80211 stop"); - - mutex_lock(&wl->mutex); - - WARN_ON(wl->state != WL12XX_STATE_ON); - - if (wl->scanning) { - mutex_unlock(&wl->mutex); - ieee80211_scan_completed(wl->hw, true); - mutex_lock(&wl->mutex); - wl->scanning = false; - } - - wl->state = WL12XX_STATE_OFF; - - wl12xx_disable_interrupts(wl); - - mutex_unlock(&wl->mutex); - - cancel_work_sync(&wl->irq_work); - cancel_work_sync(&wl->tx_work); - cancel_work_sync(&wl->filter_work); - - mutex_lock(&wl->mutex); - - /* let's notify MAC80211 about the remaining pending TX frames */ - wl->chip.op_tx_flush(wl); - wl12xx_power_off(wl); - - memset(wl->bssid, 0, ETH_ALEN); - wl->listen_int = 1; - wl->bss_type = MAX_BSS_TYPE; - - wl->data_in_count = 0; - wl->rx_counter = 0; - wl->rx_handled = 0; - wl->rx_current_buffer = 0; - wl->rx_last_id = 0; - wl->next_tx_complete = 0; - wl->elp = false; - wl->psm = 0; - wl->tx_queue_stopped = false; - wl->power_level = WL12XX_DEFAULT_POWER_LEVEL; - - wl12xx_debugfs_reset(wl); - - mutex_unlock(&wl->mutex); -} - -static int wl12xx_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) -{ - struct wl12xx *wl = hw->priv; - DECLARE_MAC_BUF(mac); - int ret = 0; - - wl12xx_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", - conf->type, print_mac(mac, conf->mac_addr)); - - mutex_lock(&wl->mutex); - - switch (conf->type) { - case NL80211_IFTYPE_STATION: - wl->bss_type = BSS_TYPE_STA_BSS; - break; - case NL80211_IFTYPE_ADHOC: - wl->bss_type = BSS_TYPE_IBSS; - break; - default: - ret = -EOPNOTSUPP; - goto out; - } - - if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) { - memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); - SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); - ret = wl12xx_acx_station_id(wl); - if (ret < 0) - goto out; - } - -out: - mutex_unlock(&wl->mutex); - return ret; -} - -static void wl12xx_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) -{ - wl12xx_debug(DEBUG_MAC80211, "mac80211 remove interface"); -} - -static int wl12xx_build_null_data(struct wl12xx *wl) -{ - struct wl12xx_null_data_template template; - - if (!is_zero_ether_addr(wl->bssid)) { - memcpy(template.header.da, wl->bssid, ETH_ALEN); - memcpy(template.header.bssid, wl->bssid, ETH_ALEN); - } else { - memset(template.header.da, 0xff, ETH_ALEN); - memset(template.header.bssid, 0xff, ETH_ALEN); - } - - memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); - template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | - IEEE80211_STYPE_NULLFUNC); - - return wl12xx_cmd_template_set(wl, CMD_NULL_DATA, &template, - sizeof(template)); - -} - -static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid) -{ - struct wl12xx_ps_poll_template template; - - memcpy(template.bssid, wl->bssid, ETH_ALEN); - memcpy(template.ta, wl->mac_addr, ETH_ALEN); - template.aid = aid; - template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); - - return wl12xx_cmd_template_set(wl, CMD_PS_POLL, &template, - sizeof(template)); - -} - -static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) -{ - struct wl12xx *wl = hw->priv; - struct ieee80211_conf *conf = &hw->conf; - int channel, ret = 0; - - channel = ieee80211_frequency_to_channel(conf->channel->center_freq); - - wl12xx_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", - channel, - conf->flags & IEEE80211_CONF_PS ? "on" : "off", - conf->power_level); - - mutex_lock(&wl->mutex); - - ret = wl12xx_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - if (channel != wl->channel) { - /* FIXME: use beacon interval provided by mac80211 */ - ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); - if (ret < 0) - goto out_sleep; - - wl->channel = channel; - } - - ret = wl12xx_build_null_data(wl); - if (ret < 0) - goto out_sleep; - - if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { - wl12xx_info("psm enabled"); - - wl->psm_requested = true; - - /* - * We enter PSM only if we're already associated. - * If we're not, we'll enter it when joining an SSID, - * through the bss_info_changed() hook. - */ - ret = wl12xx_ps_set_mode(wl, STATION_POWER_SAVE_MODE); - } else if (!(conf->flags & IEEE80211_CONF_PS) && - wl->psm_requested) { - wl12xx_info("psm disabled"); - - wl->psm_requested = false; - - if (wl->psm) - ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE); - } - - if (conf->power_level != wl->power_level) { - ret = wl12xx_acx_tx_power(wl, conf->power_level); - if (ret < 0) - goto out; - - wl->power_level = conf->power_level; - } - -out_sleep: - wl12xx_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -#define WL12XX_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ - FIF_ALLMULTI | \ - FIF_FCSFAIL | \ - FIF_BCN_PRBRESP_PROMISC | \ - FIF_CONTROL | \ - FIF_OTHER_BSS) - -static void wl12xx_op_configure_filter(struct ieee80211_hw *hw, - unsigned int changed, - unsigned int *total, - int mc_count, - struct dev_addr_list *mc_list) -{ - struct wl12xx *wl = hw->priv; - - wl12xx_debug(DEBUG_MAC80211, "mac80211 configure filter"); - - *total &= WL12XX_SUPPORTED_FILTERS; - changed &= WL12XX_SUPPORTED_FILTERS; - - if (changed == 0) - /* no filters which we support changed */ - return; - - /* FIXME: wl->rx_config and wl->rx_filter are not protected */ - - wl->rx_config = WL12XX_DEFAULT_RX_CONFIG; - wl->rx_filter = WL12XX_DEFAULT_RX_FILTER; - - if (*total & FIF_PROMISC_IN_BSS) { - wl->rx_config |= CFG_BSSID_FILTER_EN; - wl->rx_config |= CFG_RX_ALL_GOOD; - } - if (*total & FIF_ALLMULTI) - /* - * CFG_MC_FILTER_EN in rx_config needs to be 0 to receive - * all multicast frames - */ - wl->rx_config &= ~CFG_MC_FILTER_EN; - if (*total & FIF_FCSFAIL) - wl->rx_filter |= CFG_RX_FCS_ERROR; - if (*total & FIF_BCN_PRBRESP_PROMISC) { - wl->rx_config &= ~CFG_BSSID_FILTER_EN; - wl->rx_config &= ~CFG_SSID_FILTER_EN; - } - if (*total & FIF_CONTROL) - wl->rx_filter |= CFG_RX_CTL_EN; - if (*total & FIF_OTHER_BSS) - wl->rx_filter &= ~CFG_BSSID_FILTER_EN; - - /* - * FIXME: workqueues need to be properly cancelled on stop(), for - * now let's just disable changing the filter settings. They will - * be updated any on config(). - */ - /* schedule_work(&wl->filter_work); */ -} - -/* HW encryption */ -static int wl12xx_set_key_type(struct wl12xx *wl, - struct wl12xx_cmd_set_keys *key, - enum set_key_cmd cmd, - struct ieee80211_key_conf *mac80211_key, - const u8 *addr) -{ - switch (mac80211_key->alg) { - case ALG_WEP: - if (is_broadcast_ether_addr(addr)) - key->key_type = KEY_WEP_DEFAULT; - else - key->key_type = KEY_WEP_ADDR; - - mac80211_key->hw_key_idx = mac80211_key->keyidx; - break; - case ALG_TKIP: - if (is_broadcast_ether_addr(addr)) - key->key_type = KEY_TKIP_MIC_GROUP; - else - key->key_type = KEY_TKIP_MIC_PAIRWISE; - - mac80211_key->hw_key_idx = mac80211_key->keyidx; - break; - case ALG_CCMP: - if (is_broadcast_ether_addr(addr)) - key->key_type = KEY_AES_GROUP; - else - key->key_type = KEY_AES_PAIRWISE; - mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - break; - default: - wl12xx_error("Unknown key algo 0x%x", mac80211_key->alg); - return -EOPNOTSUPP; - } - - return 0; -} - -static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - struct wl12xx *wl = hw->priv; - struct wl12xx_cmd_set_keys *wl_cmd; - const u8 *addr; - int ret; - - static const u8 bcast_addr[ETH_ALEN] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - - wl12xx_debug(DEBUG_MAC80211, "mac80211 set key"); - - wl_cmd = kzalloc(sizeof(*wl_cmd), GFP_KERNEL); - if (!wl_cmd) { - ret = -ENOMEM; - goto out; - } - - addr = sta ? sta->addr : bcast_addr; - - wl12xx_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); - wl12xx_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); - wl12xx_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", - key->alg, key->keyidx, key->keylen, key->flags); - wl12xx_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen); - - if (is_zero_ether_addr(addr)) { - /* We dont support TX only encryption */ - ret = -EOPNOTSUPP; - goto out; - } - - mutex_lock(&wl->mutex); - - ret = wl12xx_ps_elp_wakeup(wl); - if (ret < 0) - goto out_unlock; - - switch (cmd) { - case SET_KEY: - wl_cmd->key_action = KEY_ADD_OR_REPLACE; - break; - case DISABLE_KEY: - wl_cmd->key_action = KEY_REMOVE; - break; - default: - wl12xx_error("Unsupported key cmd 0x%x", cmd); - break; - } - - ret = wl12xx_set_key_type(wl, wl_cmd, cmd, key, addr); - if (ret < 0) { - wl12xx_error("Set KEY type failed"); - goto out_sleep; - } - - if (wl_cmd->key_type != KEY_WEP_DEFAULT) - memcpy(wl_cmd->addr, addr, ETH_ALEN); - - if ((wl_cmd->key_type == KEY_TKIP_MIC_GROUP) || - (wl_cmd->key_type == KEY_TKIP_MIC_PAIRWISE)) { - /* - * We get the key in the following form: - * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) - * but the target is expecting: - * TKIP - RX MIC - TX MIC - */ - memcpy(wl_cmd->key, key->key, 16); - memcpy(wl_cmd->key + 16, key->key + 24, 8); - memcpy(wl_cmd->key + 24, key->key + 16, 8); - - } else { - memcpy(wl_cmd->key, key->key, key->keylen); - } - wl_cmd->key_size = key->keylen; - - wl_cmd->id = key->keyidx; - wl_cmd->ssid_profile = 0; - - wl12xx_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd)); - - ret = wl12xx_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd)); - if (ret < 0) { - wl12xx_warning("could not set keys"); - goto out_sleep; - } - -out_sleep: - wl12xx_ps_elp_sleep(wl); - -out_unlock: - mutex_unlock(&wl->mutex); - -out: - kfree(wl_cmd); - - return ret; -} - -static int wl12xx_build_basic_rates(char *rates) -{ - u8 index = 0; - - rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; - rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; - rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; - rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; - - return index; -} - -static int wl12xx_build_extended_rates(char *rates) -{ - u8 index = 0; - - rates[index++] = IEEE80211_OFDM_RATE_6MB; - rates[index++] = IEEE80211_OFDM_RATE_9MB; - rates[index++] = IEEE80211_OFDM_RATE_12MB; - rates[index++] = IEEE80211_OFDM_RATE_18MB; - rates[index++] = IEEE80211_OFDM_RATE_24MB; - rates[index++] = IEEE80211_OFDM_RATE_36MB; - rates[index++] = IEEE80211_OFDM_RATE_48MB; - rates[index++] = IEEE80211_OFDM_RATE_54MB; - - return index; -} - - -static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len) -{ - struct wl12xx_probe_req_template template; - struct wl12xx_ie_rates *rates; - char *ptr; - u16 size; - - ptr = (char *)&template; - size = sizeof(struct ieee80211_header); - - memset(template.header.da, 0xff, ETH_ALEN); - memset(template.header.bssid, 0xff, ETH_ALEN); - memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); - template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); - - /* IEs */ - /* SSID */ - template.ssid.header.id = WLAN_EID_SSID; - template.ssid.header.len = ssid_len; - if (ssid_len && ssid) - memcpy(template.ssid.ssid, ssid, ssid_len); - size += sizeof(struct wl12xx_ie_header) + ssid_len; - ptr += size; - - /* Basic Rates */ - rates = (struct wl12xx_ie_rates *)ptr; - rates->header.id = WLAN_EID_SUPP_RATES; - rates->header.len = wl12xx_build_basic_rates(rates->rates); - size += sizeof(struct wl12xx_ie_header) + rates->header.len; - ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; - - /* Extended rates */ - rates = (struct wl12xx_ie_rates *)ptr; - rates->header.id = WLAN_EID_EXT_SUPP_RATES; - rates->header.len = wl12xx_build_extended_rates(rates->rates); - size += sizeof(struct wl12xx_ie_header) + rates->header.len; - - wl12xx_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); - - return wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, &template, - size); -} - -static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len, - u8 active_scan, u8 high_prio, u8 num_channels, - u8 probe_requests) -{ - struct wl12xx_cmd_trigger_scan_to *trigger = NULL; - struct cmd_scan *params = NULL; - int i, ret; - u16 scan_options = 0; - - if (wl->scanning) - return -EINVAL; - - params = kzalloc(sizeof(*params), GFP_KERNEL); - if (!params) - return -ENOMEM; - - params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); - params->params.rx_filter_options = - cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); - - /* High priority scan */ - if (!active_scan) - scan_options |= SCAN_PASSIVE; - if (high_prio) - scan_options |= SCAN_PRIORITY_HIGH; - params->params.scan_options = scan_options; - - params->params.num_channels = num_channels; - params->params.num_probe_requests = probe_requests; - params->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ - params->params.tid_trigger = 0; - - for (i = 0; i < num_channels; i++) { - params->channels[i].min_duration = cpu_to_le32(30000); - params->channels[i].max_duration = cpu_to_le32(60000); - memset(¶ms->channels[i].bssid_lsb, 0xff, 4); - memset(¶ms->channels[i].bssid_msb, 0xff, 2); - params->channels[i].early_termination = 0; - params->channels[i].tx_power_att = 0; - params->channels[i].channel = i + 1; - memset(params->channels[i].pad, 0, 3); - } - - for (i = num_channels; i < SCAN_MAX_NUM_OF_CHANNELS; i++) - memset(¶ms->channels[i], 0, - sizeof(struct basic_scan_channel_parameters)); - - if (len && ssid) { - params->params.ssid_len = len; - memcpy(params->params.ssid, ssid, len); - } else { - params->params.ssid_len = 0; - memset(params->params.ssid, 0, 32); - } - - ret = wl12xx_build_probe_req(wl, ssid, len); - if (ret < 0) { - wl12xx_error("PROBE request template failed"); - goto out; - } - - trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); - if (!trigger) - goto out; - - trigger->timeout = 0; - - ret = wl12xx_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, - sizeof(*trigger)); - if (ret < 0) { - wl12xx_error("trigger scan to failed for hw scan"); - goto out; - } - - wl12xx_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); - - wl->scanning = true; - - ret = wl12xx_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); - if (ret < 0) - wl12xx_error("SCAN failed"); - - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); - - if (params->header.status != CMD_STATUS_SUCCESS) { - wl12xx_error("TEST command answer error: %d", - params->header.status); - wl->scanning = false; - ret = -EIO; - goto out; - } - -out: - kfree(params); - return ret; - -} - -static int wl12xx_op_hw_scan(struct ieee80211_hw *hw, - struct cfg80211_scan_request *req) -{ - struct wl12xx *wl = hw->priv; - int ret; - u8 *ssid = NULL; - size_t ssid_len = 0; - - wl12xx_debug(DEBUG_MAC80211, "mac80211 hw scan"); - - if (req->n_ssids) { - ssid = req->ssids[0].ssid; - ssid_len = req->ssids[0].ssid_len; - } - - mutex_lock(&wl->mutex); - - ret = wl12xx_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl12xx_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); - - wl12xx_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) -{ - struct wl12xx *wl = hw->priv; - int ret; - - mutex_lock(&wl->mutex); - - ret = wl12xx_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl12xx_acx_rts_threshold(wl, (u16) value); - if (ret < 0) - wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret); - - wl12xx_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changed) -{ - enum wl12xx_cmd_ps_mode mode; - struct wl12xx *wl = hw->priv; - struct sk_buff *beacon; - int ret; - - wl12xx_debug(DEBUG_MAC80211, "mac80211 bss info changed"); - - mutex_lock(&wl->mutex); - - ret = wl12xx_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - if (changed & BSS_CHANGED_ASSOC) { - if (bss_conf->assoc) { - wl->aid = bss_conf->aid; - - ret = wl12xx_build_ps_poll(wl, wl->aid); - if (ret < 0) - goto out_sleep; - - ret = wl12xx_acx_aid(wl, wl->aid); - if (ret < 0) - goto out_sleep; - - /* If we want to go in PSM but we're not there yet */ - if (wl->psm_requested && !wl->psm) { - mode = STATION_POWER_SAVE_MODE; - ret = wl12xx_ps_set_mode(wl, mode); - if (ret < 0) - goto out_sleep; - } - } - } - if (changed & BSS_CHANGED_ERP_SLOT) { - if (bss_conf->use_short_slot) - ret = wl12xx_acx_slot(wl, SLOT_TIME_SHORT); - else - ret = wl12xx_acx_slot(wl, SLOT_TIME_LONG); - if (ret < 0) { - wl12xx_warning("Set slot time failed %d", ret); - goto out_sleep; - } - } - - if (changed & BSS_CHANGED_ERP_PREAMBLE) { - if (bss_conf->use_short_preamble) - wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); - else - wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_LONG); - } - - if (changed & BSS_CHANGED_ERP_CTS_PROT) { - if (bss_conf->use_cts_prot) - ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_ENABLE); - else - ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_DISABLE); - if (ret < 0) { - wl12xx_warning("Set ctsprotect failed %d", ret); - goto out_sleep; - } - } - - if (changed & BSS_CHANGED_BSSID) { - memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); - - ret = wl12xx_build_null_data(wl); - if (ret < 0) - goto out; - - if (wl->bss_type != BSS_TYPE_IBSS) { - ret = wl->chip.op_cmd_join(wl, wl->bss_type, 5, 100, 1); - if (ret < 0) - goto out; - } - } - - if (changed & BSS_CHANGED_BEACON) { - beacon = ieee80211_beacon_get(hw, vif); - ret = wl12xx_cmd_template_set(wl, CMD_BEACON, beacon->data, - beacon->len); - - if (ret < 0) { - dev_kfree_skb(beacon); - goto out; - } - - ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, - beacon->len); - - dev_kfree_skb(beacon); - - if (ret < 0) - goto out; - - ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); - - if (ret < 0) - goto out; - } - -out_sleep: - wl12xx_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - - -/* can't be const, mac80211 writes to this */ -static struct ieee80211_rate wl12xx_rates[] = { - { .bitrate = 10, - .hw_value = 0x1, - .hw_value_short = 0x1, }, - { .bitrate = 20, - .hw_value = 0x2, - .hw_value_short = 0x2, - .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 55, - .hw_value = 0x4, - .hw_value_short = 0x4, - .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 110, - .hw_value = 0x20, - .hw_value_short = 0x20, - .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 60, - .hw_value = 0x8, - .hw_value_short = 0x8, }, - { .bitrate = 90, - .hw_value = 0x10, - .hw_value_short = 0x10, }, - { .bitrate = 120, - .hw_value = 0x40, - .hw_value_short = 0x40, }, - { .bitrate = 180, - .hw_value = 0x80, - .hw_value_short = 0x80, }, - { .bitrate = 240, - .hw_value = 0x200, - .hw_value_short = 0x200, }, - { .bitrate = 360, - .hw_value = 0x400, - .hw_value_short = 0x400, }, - { .bitrate = 480, - .hw_value = 0x800, - .hw_value_short = 0x800, }, - { .bitrate = 540, - .hw_value = 0x1000, - .hw_value_short = 0x1000, }, -}; - -/* can't be const, mac80211 writes to this */ -static struct ieee80211_channel wl12xx_channels[] = { - { .hw_value = 1, .center_freq = 2412}, - { .hw_value = 2, .center_freq = 2417}, - { .hw_value = 3, .center_freq = 2422}, - { .hw_value = 4, .center_freq = 2427}, - { .hw_value = 5, .center_freq = 2432}, - { .hw_value = 6, .center_freq = 2437}, - { .hw_value = 7, .center_freq = 2442}, - { .hw_value = 8, .center_freq = 2447}, - { .hw_value = 9, .center_freq = 2452}, - { .hw_value = 10, .center_freq = 2457}, - { .hw_value = 11, .center_freq = 2462}, - { .hw_value = 12, .center_freq = 2467}, - { .hw_value = 13, .center_freq = 2472}, -}; - -/* can't be const, mac80211 writes to this */ -static struct ieee80211_supported_band wl12xx_band_2ghz = { - .channels = wl12xx_channels, - .n_channels = ARRAY_SIZE(wl12xx_channels), - .bitrates = wl12xx_rates, - .n_bitrates = ARRAY_SIZE(wl12xx_rates), -}; - -static const struct ieee80211_ops wl12xx_ops = { - .start = wl12xx_op_start, - .stop = wl12xx_op_stop, - .add_interface = wl12xx_op_add_interface, - .remove_interface = wl12xx_op_remove_interface, - .config = wl12xx_op_config, - .configure_filter = wl12xx_op_configure_filter, - .tx = wl12xx_op_tx, - .set_key = wl12xx_op_set_key, - .hw_scan = wl12xx_op_hw_scan, - .bss_info_changed = wl12xx_op_bss_info_changed, - .set_rts_threshold = wl12xx_op_set_rts_threshold, -}; - -static int wl12xx_register_hw(struct wl12xx *wl) -{ - int ret; - - if (wl->mac80211_registered) - return 0; - - SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); - - ret = ieee80211_register_hw(wl->hw); - if (ret < 0) { - wl12xx_error("unable to register mac80211 hw: %d", ret); - return ret; - } - - wl->mac80211_registered = true; - - wl12xx_notice("loaded"); - - return 0; -} - -static int wl12xx_init_ieee80211(struct wl12xx *wl) -{ - /* The tx descriptor buffer and the TKIP space */ - wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) - + WL1251_TKIP_IV_SPACE; - - /* unit us */ - /* FIXME: find a proper value */ - wl->hw->channel_change_time = 10000; - - wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM; - - wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); - wl->hw->wiphy->max_scan_ssids = 1; - wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl12xx_band_2ghz; - - SET_IEEE80211_DEV(wl->hw, &wl->spi->dev); - - return 0; -} - -#define WL12XX_DEFAULT_CHANNEL 1 -static int __devinit wl12xx_probe(struct spi_device *spi) -{ - struct wl12xx_platform_data *pdata; - struct ieee80211_hw *hw; - struct wl12xx *wl; - int ret, i; - static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; - - pdata = spi->dev.platform_data; - if (!pdata) { - wl12xx_error("no platform data"); - return -ENODEV; - } - - hw = ieee80211_alloc_hw(sizeof(*wl), &wl12xx_ops); - if (!hw) { - wl12xx_error("could not alloc ieee80211_hw"); - return -ENOMEM; - } - - wl = hw->priv; - memset(wl, 0, sizeof(*wl)); - - wl->hw = hw; - dev_set_drvdata(&spi->dev, wl); - wl->spi = spi; - - wl->data_in_count = 0; - - skb_queue_head_init(&wl->tx_queue); - - INIT_WORK(&wl->filter_work, wl12xx_filter_work); - wl->channel = WL12XX_DEFAULT_CHANNEL; - wl->scanning = false; - wl->default_key = 0; - wl->listen_int = 1; - wl->rx_counter = 0; - wl->rx_handled = 0; - wl->rx_current_buffer = 0; - wl->rx_last_id = 0; - wl->rx_config = WL12XX_DEFAULT_RX_CONFIG; - wl->rx_filter = WL12XX_DEFAULT_RX_FILTER; - wl->elp = false; - wl->psm = 0; - wl->psm_requested = false; - wl->tx_queue_stopped = false; - wl->power_level = WL12XX_DEFAULT_POWER_LEVEL; - - /* We use the default power on sleep time until we know which chip - * we're using */ - wl->chip.power_on_sleep = WL12XX_DEFAULT_POWER_ON_SLEEP; - - for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) - wl->tx_frames[i] = NULL; - - wl->next_tx_complete = 0; - - /* - * In case our MAC address is not correctly set, - * we use a random but Nokia MAC. - */ - memcpy(wl->mac_addr, nokia_oui, 3); - get_random_bytes(wl->mac_addr + 3, 3); - - wl->state = WL12XX_STATE_OFF; - mutex_init(&wl->mutex); - - wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE; - wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE; - - wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); - if (!wl->rx_descriptor) { - wl12xx_error("could not allocate memory for rx descriptor"); - ret = -ENOMEM; - goto out_free; - } - - /* This is the only SPI value that we need to set here, the rest - * comes from the board-peripherals file */ - spi->bits_per_word = 32; - - ret = spi_setup(spi); - if (ret < 0) { - wl12xx_error("spi_setup failed"); - goto out_free; - } - - wl->set_power = pdata->set_power; - if (!wl->set_power) { - wl12xx_error("set power function missing in platform data"); - ret = -ENODEV; - goto out_free; - } - - wl->irq = spi->irq; - if (wl->irq < 0) { - wl12xx_error("irq missing in platform data"); - ret = -ENODEV; - goto out_free; - } - - ret = request_irq(wl->irq, wl12xx_irq, 0, DRIVER_NAME, wl); - if (ret < 0) { - wl12xx_error("request_irq() failed: %d", ret); - goto out_free; - } - - set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); - - disable_irq(wl->irq); - - ret = wl12xx_init_ieee80211(wl); - if (ret) - goto out_irq; - - ret = wl12xx_register_hw(wl); - if (ret) - goto out_irq; - - wl12xx_debugfs_init(wl); - - wl12xx_notice("initialized"); - - return 0; - - out_irq: - free_irq(wl->irq, wl); - - out_free: - kfree(wl->rx_descriptor); - wl->rx_descriptor = NULL; - - ieee80211_free_hw(hw); - - return ret; -} - -static int __devexit wl12xx_remove(struct spi_device *spi) -{ - struct wl12xx *wl = dev_get_drvdata(&spi->dev); - - ieee80211_unregister_hw(wl->hw); - - wl12xx_debugfs_exit(wl); - - free_irq(wl->irq, wl); - kfree(wl->target_mem_map); - kfree(wl->data_path); - kfree(wl->fw); - wl->fw = NULL; - kfree(wl->nvs); - wl->nvs = NULL; - - kfree(wl->rx_descriptor); - wl->rx_descriptor = NULL; - - ieee80211_free_hw(wl->hw); - - return 0; -} - - -static struct spi_driver wl12xx_spi_driver = { - .driver = { - .name = "wl12xx", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - }, - - .probe = wl12xx_probe, - .remove = __devexit_p(wl12xx_remove), -}; - -static int __init wl12xx_init(void) -{ - int ret; - - ret = spi_register_driver(&wl12xx_spi_driver); - if (ret < 0) { - wl12xx_error("failed to register spi driver: %d", ret); - goto out; - } - -out: - return ret; -} - -static void __exit wl12xx_exit(void) -{ - spi_unregister_driver(&wl12xx_spi_driver); - - wl12xx_notice("unloaded"); -} - -module_init(wl12xx_init); -module_exit(wl12xx_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kalle Valo , " - "Luciano Coelho "); diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c deleted file mode 100644 index f28f194ca6f..00000000000 --- a/drivers/net/wireless/wl12xx/ps.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "reg.h" -#include "ps.h" -#include "spi.h" - -#define WL12XX_WAKEUP_TIMEOUT 2000 - -/* Routines to toggle sleep mode while in ELP */ -void wl12xx_ps_elp_sleep(struct wl12xx *wl) -{ - if (wl->elp || !wl->psm) - return; - - wl12xx_debug(DEBUG_PSM, "chip to elp"); - - wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); - - wl->elp = true; -} - -int wl12xx_ps_elp_wakeup(struct wl12xx *wl) -{ - unsigned long timeout; - u32 elp_reg; - - if (!wl->elp) - return 0; - - wl12xx_debug(DEBUG_PSM, "waking up chip from elp"); - - timeout = jiffies + msecs_to_jiffies(WL12XX_WAKEUP_TIMEOUT); - - wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); - - elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); - - /* - * FIXME: we should wait for irq from chip but, as a temporary - * solution to simplify locking, let's poll instead - */ - while (!(elp_reg & ELPCTRL_WLAN_READY)) { - if (time_after(jiffies, timeout)) { - wl12xx_error("elp wakeup timeout"); - return -ETIMEDOUT; - } - msleep(1); - elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); - } - - wl12xx_debug(DEBUG_PSM, "wakeup time: %u ms", - jiffies_to_msecs(jiffies) - - (jiffies_to_msecs(timeout) - WL12XX_WAKEUP_TIMEOUT)); - - wl->elp = false; - - return 0; -} - -static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable) -{ - int ret; - - if (enable) { - wl12xx_debug(DEBUG_PSM, "sleep auth psm/elp"); - - ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_ELP); - if (ret < 0) - return ret; - - wl12xx_ps_elp_sleep(wl); - } else { - wl12xx_debug(DEBUG_PSM, "sleep auth cam"); - - /* - * When the target is in ELP, we can only - * access the ELP control register. Thus, - * we have to wake the target up before - * changing the power authorization. - */ - - wl12xx_ps_elp_wakeup(wl); - - ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM); - if (ret < 0) - return ret; - } - - return 0; -} - -int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode) -{ - int ret; - - switch (mode) { - case STATION_POWER_SAVE_MODE: - wl12xx_debug(DEBUG_PSM, "entering psm"); - ret = wl12xx_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); - if (ret < 0) - return ret; - - ret = wl12xx_ps_set_elp(wl, true); - if (ret < 0) - return ret; - - wl->psm = 1; - break; - case STATION_ACTIVE_MODE: - default: - wl12xx_debug(DEBUG_PSM, "leaving psm"); - ret = wl12xx_ps_set_elp(wl, false); - if (ret < 0) - return ret; - - ret = wl12xx_cmd_ps_mode(wl, STATION_ACTIVE_MODE); - if (ret < 0) - return ret; - - wl->psm = 0; - break; - } - - return ret; -} - diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/ps.h deleted file mode 100644 index ad61b4a0b5e..00000000000 --- a/drivers/net/wireless/wl12xx/ps.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef __WL12XX_PS_H__ -#define __WL12XX_PS_H__ - -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "wl12xx.h" -#include "acx.h" - -int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode); -void wl12xx_ps_elp_sleep(struct wl12xx *wl); -int wl12xx_ps_elp_wakeup(struct wl12xx *wl); - - -#endif /* __WL12XX_PS_H__ */ diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c deleted file mode 100644 index 7ac26ef209b..00000000000 --- a/drivers/net/wireless/wl12xx/rx.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include - -#include "wl12xx.h" -#include "reg.h" -#include "spi.h" -#include "rx.h" - -static void wl12xx_rx_header(struct wl12xx *wl, - struct wl12xx_rx_descriptor *desc) -{ - u32 rx_packet_ring_addr; - - rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr; - if (wl->rx_current_buffer) - rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; - - wl12xx_spi_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); -} - -static void wl12xx_rx_status(struct wl12xx *wl, - struct wl12xx_rx_descriptor *desc, - struct ieee80211_rx_status *status, - u8 beacon) -{ - u64 mactime; - int ret; - - memset(status, 0, sizeof(struct ieee80211_rx_status)); - - status->band = IEEE80211_BAND_2GHZ; - status->mactime = desc->timestamp; - - /* - * The rx status timestamp is a 32 bits value while the TSF is a - * 64 bits one. - * For IBSS merging, TSF is mandatory, so we have to get it - * somehow, so we ask for ACX_TSF_INFO. - * That could be moved to the get_tsf() hook, but unfortunately, - * this one must be atomic, while our SPI routines can sleep. - */ - if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) { - ret = wl12xx_acx_tsf_info(wl, &mactime); - if (ret == 0) - status->mactime = mactime; - } - - status->signal = desc->rssi; - status->qual = (desc->rssi - WL12XX_RX_MIN_RSSI) * 100 / - (WL12XX_RX_MAX_RSSI - WL12XX_RX_MIN_RSSI); - status->qual = min(status->qual, 100); - status->qual = max(status->qual, 0); - - /* - * FIXME: guessing that snr needs to be divided by two, otherwise - * the values don't make any sense - */ - status->noise = desc->rssi - desc->snr / 2; - - status->freq = ieee80211_channel_to_frequency(desc->channel); - - status->flag |= RX_FLAG_TSFT; - - if (desc->flags & RX_DESC_ENCRYPTION_MASK) { - status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; - - if (likely(!(desc->flags & RX_DESC_DECRYPT_FAIL))) - status->flag |= RX_FLAG_DECRYPTED; - - if (unlikely(desc->flags & RX_DESC_MIC_FAIL)) - status->flag |= RX_FLAG_MMIC_ERROR; - } - - if (unlikely(!(desc->flags & RX_DESC_VALID_FCS))) - status->flag |= RX_FLAG_FAILED_FCS_CRC; - - - /* FIXME: set status->rate_idx */ -} - -static void wl12xx_rx_body(struct wl12xx *wl, - struct wl12xx_rx_descriptor *desc) -{ - struct sk_buff *skb; - struct ieee80211_rx_status status; - u8 *rx_buffer, beacon = 0; - u16 length, *fc; - u32 curr_id, last_id_inc, rx_packet_ring_addr; - - length = WL12XX_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH); - curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT; - last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1); - - if (last_id_inc != curr_id) { - wl12xx_warning("curr ID:%d, last ID inc:%d", - curr_id, last_id_inc); - wl->rx_last_id = curr_id; - } else { - wl->rx_last_id = last_id_inc; - } - - rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr + - sizeof(struct wl12xx_rx_descriptor) + 20; - if (wl->rx_current_buffer) - rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; - - skb = dev_alloc_skb(length); - if (!skb) { - wl12xx_error("Couldn't allocate RX frame"); - return; - } - - rx_buffer = skb_put(skb, length); - wl12xx_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); - - /* The actual lenght doesn't include the target's alignment */ - skb->len = desc->length - PLCP_HEADER_LENGTH; - - fc = (u16 *)skb->data; - - if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) - beacon = 1; - - wl12xx_rx_status(wl, desc, &status, beacon); - - wl12xx_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, - beacon ? "beacon" : ""); - - ieee80211_rx(wl->hw, skb, &status); -} - -static void wl12xx_rx_ack(struct wl12xx *wl) -{ - u32 data, addr; - - if (wl->rx_current_buffer) { - addr = ACX_REG_INTERRUPT_TRIG_H; - data = INTR_TRIG_RX_PROC1; - } else { - addr = ACX_REG_INTERRUPT_TRIG; - data = INTR_TRIG_RX_PROC0; - } - - wl12xx_reg_write32(wl, addr, data); - - /* Toggle buffer ring */ - wl->rx_current_buffer = !wl->rx_current_buffer; -} - - -void wl12xx_rx(struct wl12xx *wl) -{ - struct wl12xx_rx_descriptor *rx_desc; - - if (wl->state != WL12XX_STATE_ON) - return; - - rx_desc = wl->rx_descriptor; - - /* We first read the frame's header */ - wl12xx_rx_header(wl, rx_desc); - - /* Now we can read the body */ - wl12xx_rx_body(wl, rx_desc); - - /* Finally, we need to ACK the RX */ - wl12xx_rx_ack(wl); - - return; -} diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h deleted file mode 100644 index 8a23fdea501..00000000000 --- a/drivers/net/wireless/wl12xx/rx.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL12XX_RX_H__ -#define __WL12XX_RX_H__ - -#include - -/* - * RX PATH - * - * The Rx path uses a double buffer and an rx_contro structure, each located - * at a fixed address in the device memory. The host keeps track of which - * buffer is available and alternates between them on a per packet basis. - * The size of each of the two buffers is large enough to hold the longest - * 802.3 packet. - * The RX path goes like that: - * 1) The target generates an interrupt each time a new packet is received. - * There are 2 RX interrupts, one for each buffer. - * 2) The host reads the received packet from one of the double buffers. - * 3) The host triggers a target interrupt. - * 4) The target prepares the next RX packet. - */ - -#define WL12XX_RX_MAX_RSSI -30 -#define WL12XX_RX_MIN_RSSI -95 - -#define WL12XX_RX_ALIGN_TO 4 -#define WL12XX_RX_ALIGN(len) (((len) + WL12XX_RX_ALIGN_TO - 1) & \ - ~(WL12XX_RX_ALIGN_TO - 1)) - -#define SHORT_PREAMBLE_BIT BIT(0) -#define OFDM_RATE_BIT BIT(6) -#define PBCC_RATE_BIT BIT(7) - -#define PLCP_HEADER_LENGTH 8 -#define RX_DESC_PACKETID_SHIFT 11 -#define RX_MAX_PACKET_ID 3 - -#define RX_DESC_VALID_FCS 0x0001 -#define RX_DESC_MATCH_RXADDR1 0x0002 -#define RX_DESC_MCAST 0x0004 -#define RX_DESC_STAINTIM 0x0008 -#define RX_DESC_VIRTUAL_BM 0x0010 -#define RX_DESC_BCAST 0x0020 -#define RX_DESC_MATCH_SSID 0x0040 -#define RX_DESC_MATCH_BSSID 0x0080 -#define RX_DESC_ENCRYPTION_MASK 0x0300 -#define RX_DESC_MEASURMENT 0x0400 -#define RX_DESC_SEQNUM_MASK 0x1800 -#define RX_DESC_MIC_FAIL 0x2000 -#define RX_DESC_DECRYPT_FAIL 0x4000 - -struct wl12xx_rx_descriptor { - u32 timestamp; /* In microseconds */ - u16 length; /* Paylod length, including headers */ - u16 flags; - - /* - * 0 - 802.11 - * 1 - 802.3 - * 2 - IP - * 3 - Raw Codec - */ - u8 type; - - /* - * Recevied Rate: - * 0x0A - 1MBPS - * 0x14 - 2MBPS - * 0x37 - 5_5MBPS - * 0x0B - 6MBPS - * 0x0F - 9MBPS - * 0x6E - 11MBPS - * 0x0A - 12MBPS - * 0x0E - 18MBPS - * 0xDC - 22MBPS - * 0x09 - 24MBPS - * 0x0D - 36MBPS - * 0x08 - 48MBPS - * 0x0C - 54MBPS - */ - u8 rate; - - u8 mod_pre; /* Modulation and preamble */ - u8 channel; - - /* - * 0 - 2.4 Ghz - * 1 - 5 Ghz - */ - u8 band; - - s8 rssi; /* in dB */ - u8 rcpi; /* in dB */ - u8 snr; /* in dB */ -} __attribute__ ((packed)); - -void wl12xx_rx(struct wl12xx *wl); - -#endif diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c deleted file mode 100644 index 9c9943f9867..00000000000 --- a/drivers/net/wireless/wl12xx/spi.c +++ /dev/null @@ -1,395 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include - -#include "wl12xx.h" -#include "wl12xx_80211.h" -#include "reg.h" -#include "spi.h" -#include "ps.h" - -static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr) -{ - /* If the address is lower than REGISTERS_BASE, it means that this is - * a chip-specific register address, so look it up in the registers - * table */ - if (addr < REGISTERS_BASE) { - /* Make sure we don't go over the table */ - if (addr >= ACX_REG_TABLE_LEN) { - wl12xx_error("address out of range (%d)", addr); - return -EINVAL; - } - addr = wl->chip.acx_reg_table[addr]; - } - - return addr - wl->physical_reg_addr + wl->virtual_reg_addr; -} - -static int wl12xx_translate_mem_addr(struct wl12xx *wl, int addr) -{ - return addr - wl->physical_mem_addr + wl->virtual_mem_addr; -} - - -void wl12xx_spi_reset(struct wl12xx *wl) -{ - u8 *cmd; - struct spi_transfer t; - struct spi_message m; - - cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); - if (!cmd) { - wl12xx_error("could not allocate cmd for spi reset"); - return; - } - - memset(&t, 0, sizeof(t)); - spi_message_init(&m); - - memset(cmd, 0xff, WSPI_INIT_CMD_LEN); - - t.tx_buf = cmd; - t.len = WSPI_INIT_CMD_LEN; - spi_message_add_tail(&t, &m); - - spi_sync(wl->spi, &m); - - wl12xx_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); -} - -void wl12xx_spi_init(struct wl12xx *wl) -{ - u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; - struct spi_transfer t; - struct spi_message m; - - cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); - if (!cmd) { - wl12xx_error("could not allocate cmd for spi init"); - return; - } - - memset(crc, 0, sizeof(crc)); - memset(&t, 0, sizeof(t)); - spi_message_init(&m); - - /* - * Set WSPI_INIT_COMMAND - * the data is being send from the MSB to LSB - */ - cmd[2] = 0xff; - cmd[3] = 0xff; - cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; - cmd[0] = 0; - cmd[7] = 0; - cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3; - cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; - - if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) - cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY; - else - cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY; - - cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS - | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; - - crc[0] = cmd[1]; - crc[1] = cmd[0]; - crc[2] = cmd[7]; - crc[3] = cmd[6]; - crc[4] = cmd[5]; - - cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; - cmd[4] |= WSPI_INIT_CMD_END; - - t.tx_buf = cmd; - t.len = WSPI_INIT_CMD_LEN; - spi_message_add_tail(&t, &m); - - spi_sync(wl->spi, &m); - - wl12xx_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); -} - -/* Set the SPI partitions to access the chip addresses - * - * There are two VIRTUAL (SPI) partitions (the memory partition and the - * registers partition), which are mapped to two different areas of the - * PHYSICAL (hardware) memory. This function also makes other checks to - * ensure that the partitions are not overlapping. In the diagram below, the - * memory partition comes before the register partition, but the opposite is - * also supported. - * - * PHYSICAL address - * space - * - * | | - * ...+----+--> mem_start - * VIRTUAL address ... | | - * space ... | | [PART_0] - * ... | | - * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size - * | | ... | | - * |MEM | ... | | - * | | ... | | - * part_size <--+----+... | | {unused area) - * | | ... | | - * |REG | ... | | - * part_size | | ... | | - * + <--+----+... ...+----+--> reg_start - * reg_size ... | | - * ... | | [PART_1] - * ... | | - * ...+----+--> reg_start + reg_size - * | | - * - */ -int wl12xx_set_partition(struct wl12xx *wl, - u32 mem_start, u32 mem_size, - u32 reg_start, u32 reg_size) -{ - struct wl12xx_partition *partition; - struct spi_transfer t; - struct spi_message m; - size_t len, cmd_len; - u32 *cmd; - int addr; - - cmd_len = sizeof(u32) + 2 * sizeof(struct wl12xx_partition); - cmd = kzalloc(cmd_len, GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - spi_message_init(&m); - memset(&t, 0, sizeof(t)); - - partition = (struct wl12xx_partition *) (cmd + 1); - addr = HW_ACCESS_PART0_SIZE_ADDR; - len = 2 * sizeof(struct wl12xx_partition); - - *cmd |= WSPI_CMD_WRITE; - *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - *cmd |= addr & WSPI_CMD_BYTE_ADDR; - - wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - - /* Make sure that the two partitions together don't exceed the - * address range */ - if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { - wl12xx_debug(DEBUG_SPI, "Total size exceeds maximum virtual" - " address range. Truncating partition[0]."); - mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; - wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } - - if ((mem_start < reg_start) && - ((mem_start + mem_size) > reg_start)) { - /* Guarantee that the memory partition doesn't overlap the - * registers partition */ - wl12xx_debug(DEBUG_SPI, "End of partition[0] is " - "overlapping partition[1]. Adjusted."); - mem_size = reg_start - mem_start; - wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } else if ((reg_start < mem_start) && - ((reg_start + reg_size) > mem_start)) { - /* Guarantee that the register partition doesn't overlap the - * memory partition */ - wl12xx_debug(DEBUG_SPI, "End of partition[1] is" - " overlapping partition[0]. Adjusted."); - reg_size = mem_start - reg_start; - wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } - - partition[0].start = mem_start; - partition[0].size = mem_size; - partition[1].start = reg_start; - partition[1].size = reg_size; - - wl->physical_mem_addr = mem_start; - wl->physical_reg_addr = reg_start; - - wl->virtual_mem_addr = 0; - wl->virtual_reg_addr = mem_size; - - t.tx_buf = cmd; - t.len = cmd_len; - spi_message_add_tail(&t, &m); - - spi_sync(wl->spi, &m); - - kfree(cmd); - - return 0; -} - -void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, - size_t len, bool fixed) -{ - struct spi_transfer t[3]; - struct spi_message m; - u8 *busy_buf; - u32 *cmd; - - cmd = &wl->buffer_cmd; - busy_buf = wl->buffer_busyword; - - *cmd = 0; - *cmd |= WSPI_CMD_READ; - *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - *cmd |= addr & WSPI_CMD_BYTE_ADDR; - - if (fixed) - *cmd |= WSPI_CMD_FIXED; - - spi_message_init(&m); - memset(t, 0, sizeof(t)); - - t[0].tx_buf = cmd; - t[0].len = 4; - spi_message_add_tail(&t[0], &m); - - /* Busy and non busy words read */ - t[1].rx_buf = busy_buf; - t[1].len = WL12XX_BUSY_WORD_LEN; - spi_message_add_tail(&t[1], &m); - - t[2].rx_buf = buf; - t[2].len = len; - spi_message_add_tail(&t[2], &m); - - spi_sync(wl->spi, &m); - - /* FIXME: check busy words */ - - wl12xx_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); - wl12xx_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); -} - -void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, - size_t len, bool fixed) -{ - struct spi_transfer t[2]; - struct spi_message m; - u32 *cmd; - - cmd = &wl->buffer_cmd; - - *cmd = 0; - *cmd |= WSPI_CMD_WRITE; - *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - *cmd |= addr & WSPI_CMD_BYTE_ADDR; - - if (fixed) - *cmd |= WSPI_CMD_FIXED; - - spi_message_init(&m); - memset(t, 0, sizeof(t)); - - t[0].tx_buf = cmd; - t[0].len = sizeof(*cmd); - spi_message_add_tail(&t[0], &m); - - t[1].tx_buf = buf; - t[1].len = len; - spi_message_add_tail(&t[1], &m); - - spi_sync(wl->spi, &m); - - wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); - wl12xx_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); -} - -void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, - size_t len) -{ - int physical; - - physical = wl12xx_translate_mem_addr(wl, addr); - - wl12xx_spi_read(wl, physical, buf, len, false); -} - -void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, - size_t len) -{ - int physical; - - physical = wl12xx_translate_mem_addr(wl, addr); - - wl12xx_spi_write(wl, physical, buf, len, false); -} - -void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, - bool fixed) -{ - int physical; - - physical = wl12xx_translate_reg_addr(wl, addr); - - wl12xx_spi_read(wl, physical, buf, len, fixed); -} - -void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len, - bool fixed) -{ - int physical; - - physical = wl12xx_translate_reg_addr(wl, addr); - - wl12xx_spi_write(wl, physical, buf, len, fixed); -} - -u32 wl12xx_mem_read32(struct wl12xx *wl, int addr) -{ - return wl12xx_read32(wl, wl12xx_translate_mem_addr(wl, addr)); -} - -void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val) -{ - wl12xx_write32(wl, wl12xx_translate_mem_addr(wl, addr), val); -} - -u32 wl12xx_reg_read32(struct wl12xx *wl, int addr) -{ - return wl12xx_read32(wl, wl12xx_translate_reg_addr(wl, addr)); -} - -void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val) -{ - wl12xx_write32(wl, wl12xx_translate_reg_addr(wl, addr), val); -} diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/spi.h deleted file mode 100644 index e48a552b2ea..00000000000 --- a/drivers/net/wireless/wl12xx/spi.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL12XX_SPI_H__ -#define __WL12XX_SPI_H__ - -#include "cmd.h" -#include "acx.h" -#include "reg.h" - -#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 - -#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 -#define HW_ACCESS_PART0_START_ADDR 0x1FFC4 -#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 -#define HW_ACCESS_PART1_START_ADDR 0x1FFCC - -#define HW_ACCESS_REGISTER_SIZE 4 - -#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 - -#define WSPI_CMD_READ 0x40000000 -#define WSPI_CMD_WRITE 0x00000000 -#define WSPI_CMD_FIXED 0x20000000 -#define WSPI_CMD_BYTE_LENGTH 0x1FFE0000 -#define WSPI_CMD_BYTE_LENGTH_OFFSET 17 -#define WSPI_CMD_BYTE_ADDR 0x0001FFFF - -#define WSPI_INIT_CMD_CRC_LEN 5 - -#define WSPI_INIT_CMD_START 0x00 -#define WSPI_INIT_CMD_TX 0x40 -/* the extra bypass bit is sampled by the TNET as '1' */ -#define WSPI_INIT_CMD_BYPASS_BIT 0x80 -#define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07 -#define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80 -#define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00 -#define WSPI_INIT_CMD_IOD 0x40 -#define WSPI_INIT_CMD_IP 0x20 -#define WSPI_INIT_CMD_CS 0x10 -#define WSPI_INIT_CMD_WS 0x08 -#define WSPI_INIT_CMD_WSPI 0x01 -#define WSPI_INIT_CMD_END 0x01 - -#define WSPI_INIT_CMD_LEN 8 - -#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ - ((WL12XX_BUSY_WORD_LEN - 4) / sizeof(u32)) -#define HW_ACCESS_WSPI_INIT_CMD_MASK 0 - - -/* Raw target IO, address is not translated */ -void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, - size_t len, bool fixed); -void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, - size_t len, bool fixed); - -/* Memory target IO, address is tranlated to partition 0 */ -void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, size_t len); -void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, size_t len); -u32 wl12xx_mem_read32(struct wl12xx *wl, int addr); -void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val); - -/* Registers IO */ -void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, - bool fixed); -void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len, - bool fixed); -u32 wl12xx_reg_read32(struct wl12xx *wl, int addr); -void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val); - -/* INIT and RESET words */ -void wl12xx_spi_reset(struct wl12xx *wl); -void wl12xx_spi_init(struct wl12xx *wl); -int wl12xx_set_partition(struct wl12xx *wl, - u32 part_start, u32 part_size, - u32 reg_start, u32 reg_size); - -static inline u32 wl12xx_read32(struct wl12xx *wl, int addr) -{ - wl12xx_spi_read(wl, addr, &wl->buffer_32, - sizeof(wl->buffer_32), false); - - return wl->buffer_32; -} - -static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val) -{ - wl->buffer_32 = val; - wl12xx_spi_write(wl, addr, &wl->buffer_32, - sizeof(wl->buffer_32), false); -} - -#endif /* __WL12XX_SPI_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c new file mode 100644 index 00000000000..cecc1fade3d --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -0,0 +1,841 @@ +#include "wl1251_acx.h" + +#include +#include +#include + +#include "wl12xx.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "wl1251_spi.h" +#include "wl1251_ps.h" + +int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, + u8 mgt_rate, u8 mgt_mod) +{ + struct acx_fw_gen_frame_rates *rates; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx frame rates"); + + rates = kzalloc(sizeof(*rates), GFP_KERNEL); + if (!rates) { + ret = -ENOMEM; + goto out; + } + + rates->tx_ctrl_frame_rate = ctrl_rate; + rates->tx_ctrl_frame_mod = ctrl_mod; + rates->tx_mgt_frame_rate = mgt_rate; + rates->tx_mgt_frame_mod = mgt_mod; + + ret = wl12xx_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES, + rates, sizeof(*rates)); + if (ret < 0) { + wl12xx_error("Failed to set FW rates and modulation"); + goto out; + } + +out: + kfree(rates); + return ret; +} + + +int wl12xx_acx_station_id(struct wl12xx *wl) +{ + struct acx_dot11_station_id *mac; + int ret, i; + + wl12xx_debug(DEBUG_ACX, "acx dot11_station_id"); + + mac = kzalloc(sizeof(*mac), GFP_KERNEL); + if (!mac) { + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < ETH_ALEN; i++) + mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; + + ret = wl12xx_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac)); + if (ret < 0) + goto out; + +out: + kfree(mac); + return ret; +} + +int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id) +{ + struct acx_dot11_default_key *default_key; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id); + + default_key = kzalloc(sizeof(*default_key), GFP_KERNEL); + if (!default_key) { + ret = -ENOMEM; + goto out; + } + + default_key->id = key_id; + + ret = wl12xx_cmd_configure(wl, DOT11_DEFAULT_KEY, + default_key, sizeof(*default_key)); + if (ret < 0) { + wl12xx_error("Couldnt set default key"); + goto out; + } + + wl->default_key = key_id; + +out: + kfree(default_key); + return ret; +} + +int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 wake_up_event, + u8 listen_interval) +{ + struct acx_wake_up_condition *wake_up; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx wake up conditions"); + + wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); + if (!wake_up) { + ret = -ENOMEM; + goto out; + } + + wake_up->wake_up_event = wake_up_event; + wake_up->listen_interval = listen_interval; + + ret = wl12xx_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, + wake_up, sizeof(*wake_up)); + if (ret < 0) { + wl12xx_warning("could not set wake up conditions: %d", ret); + goto out; + } + +out: + kfree(wake_up); + return ret; +} + +int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth) +{ + struct acx_sleep_auth *auth; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx sleep auth"); + + auth = kzalloc(sizeof(*auth), GFP_KERNEL); + if (!auth) { + ret = -ENOMEM; + goto out; + } + + auth->sleep_auth = sleep_auth; + + ret = wl12xx_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); + if (ret < 0) + return ret; + +out: + kfree(auth); + return ret; +} + +int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len) +{ + struct acx_revision *rev; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx fw rev"); + + rev = kzalloc(sizeof(*rev), GFP_KERNEL); + if (!rev) { + ret = -ENOMEM; + goto out; + } + + ret = wl12xx_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); + if (ret < 0) { + wl12xx_warning("ACX_FW_REV interrogate failed"); + goto out; + } + + /* be careful with the buffer sizes */ + strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); + + /* + * if the firmware version string is exactly + * sizeof(rev->fw_version) long or fw_len is less than + * sizeof(rev->fw_version) it won't be null terminated + */ + buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; + +out: + kfree(rev); + return ret; +} + +int wl12xx_acx_tx_power(struct wl12xx *wl, int power) +{ + struct acx_current_tx_power *acx; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); + + if (power < 0 || power > 25) + return -EINVAL; + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->current_tx_power = power * 10; + + ret = wl12xx_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); + if (ret < 0) { + wl12xx_warning("configure of tx power failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl12xx_acx_feature_cfg(struct wl12xx *wl) +{ + struct acx_feature_config *feature; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx feature cfg"); + + feature = kzalloc(sizeof(*feature), GFP_KERNEL); + if (!feature) { + ret = -ENOMEM; + goto out; + } + + /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ + feature->data_flow_options = 0; + feature->options = 0; + + ret = wl12xx_cmd_configure(wl, ACX_FEATURE_CFG, + feature, sizeof(*feature)); + if (ret < 0) { + wl12xx_error("Couldnt set HW encryption"); + goto out; + } + +out: + kfree(feature); + return ret; +} + +int wl12xx_acx_mem_map(struct wl12xx *wl, struct acx_header *mem_map, + size_t len) +{ + int ret; + + wl12xx_debug(DEBUG_ACX, "acx mem map"); + + ret = wl12xx_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_acx_data_path_params(struct wl12xx *wl, + struct acx_data_path_params_resp *resp) +{ + struct acx_data_path_params *params; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx data path params"); + + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) { + ret = -ENOMEM; + goto out; + } + + params->rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE; + params->tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE; + + params->rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM; + params->tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM; + + params->tx_complete_threshold = 1; + + params->tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE; + + params->tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT; + + ret = wl12xx_cmd_configure(wl, ACX_DATA_PATH_PARAMS, + params, sizeof(*params)); + if (ret < 0) + goto out; + + /* FIXME: shouldn't this be ACX_DATA_PATH_RESP_PARAMS? */ + ret = wl12xx_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS, + resp, sizeof(*resp)); + + if (ret < 0) { + wl12xx_warning("failed to read data path parameters: %d", ret); + goto out; + } else if (resp->header.cmd.status != CMD_STATUS_SUCCESS) { + wl12xx_warning("data path parameter acx status failed"); + ret = -EIO; + goto out; + } + +out: + kfree(params); + return ret; +} + +int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time) +{ + struct acx_rx_msdu_lifetime *acx; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx rx msdu life time"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->lifetime = life_time; + ret = wl12xx_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, + acx, sizeof(*acx)); + if (ret < 0) { + wl12xx_warning("failed to set rx msdu life time: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter) +{ + struct acx_rx_config *rx_config; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx rx config"); + + rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); + if (!rx_config) { + ret = -ENOMEM; + goto out; + } + + rx_config->config_options = config; + rx_config->filter_options = filter; + + ret = wl12xx_cmd_configure(wl, ACX_RX_CFG, + rx_config, sizeof(*rx_config)); + if (ret < 0) { + wl12xx_warning("failed to set rx config: %d", ret); + goto out; + } + +out: + kfree(rx_config); + return ret; +} + +int wl12xx_acx_pd_threshold(struct wl12xx *wl) +{ + struct acx_packet_detection *pd; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx data pd threshold"); + + pd = kzalloc(sizeof(*pd), GFP_KERNEL); + if (!pd) { + ret = -ENOMEM; + goto out; + } + + /* FIXME: threshold value not set */ + + ret = wl12xx_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); + if (ret < 0) { + wl12xx_warning("failed to set pd threshold: %d", ret); + goto out; + } + +out: + kfree(pd); + return 0; +} + +int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time) +{ + struct acx_slot *slot; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx slot"); + + slot = kzalloc(sizeof(*slot), GFP_KERNEL); + if (!slot) { + ret = -ENOMEM; + goto out; + } + + slot->wone_index = STATION_WONE_INDEX; + slot->slot_time = slot_time; + + ret = wl12xx_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); + if (ret < 0) { + wl12xx_warning("failed to set slot time: %d", ret); + goto out; + } + +out: + kfree(slot); + return ret; +} + +int wl12xx_acx_group_address_tbl(struct wl12xx *wl) +{ + struct acx_dot11_grp_addr_tbl *acx; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx group address tbl"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* MAC filtering */ + acx->enabled = 0; + acx->num_groups = 0; + memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); + + ret = wl12xx_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, + acx, sizeof(*acx)); + if (ret < 0) { + wl12xx_warning("failed to set group addr table: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl12xx_acx_service_period_timeout(struct wl12xx *wl) +{ + struct acx_rx_timeout *rx_timeout; + int ret; + + rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); + if (!rx_timeout) { + ret = -ENOMEM; + goto out; + } + + wl12xx_debug(DEBUG_ACX, "acx service period timeout"); + + rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; + rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF; + + ret = wl12xx_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, + rx_timeout, sizeof(*rx_timeout)); + if (ret < 0) { + wl12xx_warning("failed to set service period timeout: %d", + ret); + goto out; + } + +out: + kfree(rx_timeout); + return ret; +} + +int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold) +{ + struct acx_rts_threshold *rts; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx rts threshold"); + + rts = kzalloc(sizeof(*rts), GFP_KERNEL); + if (!rts) { + ret = -ENOMEM; + goto out; + } + + rts->threshold = rts_threshold; + + ret = wl12xx_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); + if (ret < 0) { + wl12xx_warning("failed to set rts threshold: %d", ret); + goto out; + } + +out: + kfree(rts); + return ret; +} + +int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl) +{ + struct acx_beacon_filter_option *beacon_filter; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx beacon filter opt"); + + beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); + if (!beacon_filter) { + ret = -ENOMEM; + goto out; + } + + beacon_filter->enable = 0; + beacon_filter->max_num_beacons = 0; + + ret = wl12xx_cmd_configure(wl, ACX_BEACON_FILTER_OPT, + beacon_filter, sizeof(*beacon_filter)); + if (ret < 0) { + wl12xx_warning("failed to set beacon filter opt: %d", ret); + goto out; + } + +out: + kfree(beacon_filter); + return ret; +} + +int wl12xx_acx_beacon_filter_table(struct wl12xx *wl) +{ + struct acx_beacon_filter_ie_table *ie_table; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx beacon filter table"); + + ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); + if (!ie_table) { + ret = -ENOMEM; + goto out; + } + + ie_table->num_ie = 0; + memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE); + + ret = wl12xx_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, + ie_table, sizeof(*ie_table)); + if (ret < 0) { + wl12xx_warning("failed to set beacon filter table: %d", ret); + goto out; + } + +out: + kfree(ie_table); + return ret; +} + +int wl12xx_acx_sg_enable(struct wl12xx *wl) +{ + struct acx_bt_wlan_coex *pta; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx sg enable"); + + pta = kzalloc(sizeof(*pta), GFP_KERNEL); + if (!pta) { + ret = -ENOMEM; + goto out; + } + + pta->enable = SG_ENABLE; + + ret = wl12xx_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); + if (ret < 0) { + wl12xx_warning("failed to set softgemini enable: %d", ret); + goto out; + } + +out: + kfree(pta); + return ret; +} + +int wl12xx_acx_sg_cfg(struct wl12xx *wl) +{ + struct acx_bt_wlan_coex_param *param; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx sg cfg"); + + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) { + ret = -ENOMEM; + goto out; + } + + /* BT-WLAN coext parameters */ + param->min_rate = RATE_INDEX_24MBPS; + param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; + param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; + param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; + param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; + param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; + param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; + param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; + param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; + param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; + param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; + param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; + param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; + param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; + param->antenna_type = PTA_ANTENNA_TYPE_DEF; + param->signal_type = PTA_SIGNALING_TYPE_DEF; + param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; + param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; + param->max_cts = PTA_MAX_NUM_CTS_DEF; + param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; + param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; + param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; + param->wlan_elp_hp = PTA_ELP_HP_DEF; + param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; + param->ack_mode_dual_ant = PTA_ACK_MODE_DEF; + param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF; + param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; + param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; + + ret = wl12xx_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); + if (ret < 0) { + wl12xx_warning("failed to set sg config: %d", ret); + goto out; + } + +out: + kfree(param); + return ret; +} + +int wl12xx_acx_cca_threshold(struct wl12xx *wl) +{ + struct acx_energy_detection *detection; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx cca threshold"); + + detection = kzalloc(sizeof(*detection), GFP_KERNEL); + if (!detection) { + ret = -ENOMEM; + goto out; + } + + detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; + detection->tx_energy_detection = 0; + + ret = wl12xx_cmd_configure(wl, ACX_CCA_THRESHOLD, + detection, sizeof(*detection)); + if (ret < 0) { + wl12xx_warning("failed to set cca threshold: %d", ret); + return ret; + } + +out: + kfree(detection); + return ret; +} + +int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl) +{ + struct acx_beacon_broadcast *bb; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx bcn dtim options"); + + bb = kzalloc(sizeof(*bb), GFP_KERNEL); + if (!bb) { + ret = -ENOMEM; + goto out; + } + + bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; + bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; + bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; + bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; + + ret = wl12xx_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); + if (ret < 0) { + wl12xx_warning("failed to set rx config: %d", ret); + goto out; + } + +out: + kfree(bb); + return ret; +} + +int wl12xx_acx_aid(struct wl12xx *wl, u16 aid) +{ + struct acx_aid *acx_aid; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx aid"); + + acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); + if (!acx_aid) { + ret = -ENOMEM; + goto out; + } + + acx_aid->aid = aid; + + ret = wl12xx_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); + if (ret < 0) { + wl12xx_warning("failed to set aid: %d", ret); + goto out; + } + +out: + kfree(acx_aid); + return ret; +} + +int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask) +{ + struct acx_event_mask *mask; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx event mbox mask"); + + mask = kzalloc(sizeof(*mask), GFP_KERNEL); + if (!mask) { + ret = -ENOMEM; + goto out; + } + + /* high event mask is unused */ + mask->high_event_mask = 0xffffffff; + + mask->event_mask = event_mask; + + ret = wl12xx_cmd_configure(wl, ACX_EVENT_MBOX_MASK, + mask, sizeof(*mask)); + if (ret < 0) { + wl12xx_warning("failed to set acx_event_mbox_mask: %d", ret); + goto out; + } + +out: + kfree(mask); + return ret; +} + +int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble) +{ + struct acx_preamble *acx; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx_set_preamble"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->preamble = preamble; + + ret = wl12xx_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); + if (ret < 0) { + wl12xx_warning("Setting of preamble failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl12xx_acx_cts_protect(struct wl12xx *wl, + enum acx_ctsprotect_type ctsprotect) +{ + struct acx_ctsprotect *acx; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx_set_ctsprotect"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->ctsprotect = ctsprotect; + + ret = wl12xx_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); + if (ret < 0) { + wl12xx_warning("Setting of ctsprotect failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl12xx_acx_tsf_info(struct wl12xx *wl, u64 *mactime) +{ + struct acx_tsf_info *tsf_info; + int ret; + + tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); + if (!tsf_info) { + ret = -ENOMEM; + goto out; + } + + ret = wl12xx_cmd_interrogate(wl, ACX_TSF_INFO, + tsf_info, sizeof(*tsf_info)); + if (ret < 0) { + wl12xx_warning("ACX_FW_REV interrogate failed"); + goto out; + } + + *mactime = tsf_info->current_tsf_lsb | + (tsf_info->current_tsf_msb << 31); + +out: + kfree(tsf_info); + return ret; +} + +int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats) +{ + int ret; + + wl12xx_debug(DEBUG_ACX, "acx statistics"); + + ret = wl12xx_cmd_interrogate(wl, ACX_STATISTICS, stats, + sizeof(*stats)); + if (ret < 0) { + wl12xx_warning("acx statistics failed: %d", ret); + return -ENOMEM; + } + + return 0; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h new file mode 100644 index 00000000000..203f11fd6c2 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_acx.h @@ -0,0 +1,1146 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_ACX_H__ +#define __WL12XX_ACX_H__ + +#include "wl12xx.h" +#include "wl1251_cmd.h" + +/* Target's information element */ +struct acx_header { + struct wl12xx_cmd_header cmd; + + /* acx (or information element) header */ + u16 id; + + /* payload length (not including headers */ + u16 len; +}; + +struct acx_error_counter { + struct acx_header header; + + /* The number of PLCP errors since the last time this */ + /* information element was interrogated. This field is */ + /* automatically cleared when it is interrogated.*/ + u32 PLCP_error; + + /* The number of FCS errors since the last time this */ + /* information element was interrogated. This field is */ + /* automatically cleared when it is interrogated.*/ + u32 FCS_error; + + /* The number of MPDUs without PLCP header errors received*/ + /* since the last time this information element was interrogated. */ + /* This field is automatically cleared when it is interrogated.*/ + u32 valid_frame; + + /* the number of missed sequence numbers in the squentially */ + /* values of frames seq numbers */ + u32 seq_num_miss; +} __attribute__ ((packed)); + +struct acx_revision { + struct acx_header header; + + /* + * The WiLink firmware version, an ASCII string x.x.x.x, + * that uniquely identifies the current firmware. + * The left most digit is incremented each time a + * significant change is made to the firmware, such as + * code redesign or new platform support. + * The second digit is incremented when major enhancements + * are added or major fixes are made. + * The third digit is incremented for each GA release. + * The fourth digit is incremented for each build. + * The first two digits identify a firmware release version, + * in other words, a unique set of features. + * The first three digits identify a GA release. + */ + char fw_version[20]; + + /* + * This 4 byte field specifies the WiLink hardware version. + * bits 0 - 15: Reserved. + * bits 16 - 23: Version ID - The WiLink version ID + * (1 = first spin, 2 = second spin, and so on). + * bits 24 - 31: Chip ID - The WiLink chip ID. + */ + u32 hw_version; +} __attribute__ ((packed)); + +enum wl12xx_psm_mode { + /* Active mode */ + WL12XX_PSM_CAM = 0, + + /* Power save mode */ + WL12XX_PSM_PS = 1, + + /* Extreme low power */ + WL12XX_PSM_ELP = 2, +}; + +struct acx_sleep_auth { + struct acx_header header; + + /* The sleep level authorization of the device. */ + /* 0 - Always active*/ + /* 1 - Power down mode: light / fast sleep*/ + /* 2 - ELP mode: Deep / Max sleep*/ + u8 sleep_auth; + u8 padding[3]; +} __attribute__ ((packed)); + +enum { + HOSTIF_PCI_MASTER_HOST_INDIRECT, + HOSTIF_PCI_MASTER_HOST_DIRECT, + HOSTIF_SLAVE, + HOSTIF_PKT_RING, + HOSTIF_DONTCARE = 0xFF +}; + +#define DEFAULT_UCAST_PRIORITY 0 +#define DEFAULT_RX_Q_PRIORITY 0 +#define DEFAULT_NUM_STATIONS 1 +#define DEFAULT_RXQ_PRIORITY 0 /* low 0 .. 15 high */ +#define DEFAULT_RXQ_TYPE 0x07 /* All frames, Data/Ctrl/Mgmt */ +#define TRACE_BUFFER_MAX_SIZE 256 + +#define DP_RX_PACKET_RING_CHUNK_SIZE 1600 +#define DP_TX_PACKET_RING_CHUNK_SIZE 1600 +#define DP_RX_PACKET_RING_CHUNK_NUM 2 +#define DP_TX_PACKET_RING_CHUNK_NUM 2 +#define DP_TX_COMPLETE_TIME_OUT 20 +#define FW_TX_CMPLT_BLOCK_SIZE 16 + +struct acx_data_path_params { + struct acx_header header; + + u16 rx_packet_ring_chunk_size; + u16 tx_packet_ring_chunk_size; + + u8 rx_packet_ring_chunk_num; + u8 tx_packet_ring_chunk_num; + + /* + * Maximum number of packets that can be gathered + * in the TX complete ring before an interrupt + * is generated. + */ + u8 tx_complete_threshold; + + /* Number of pending TX complete entries in cyclic ring.*/ + u8 tx_complete_ring_depth; + + /* + * Max num microseconds since a packet enters the TX + * complete ring until an interrupt is generated. + */ + u32 tx_complete_timeout; +} __attribute__ ((packed)); + + +struct acx_data_path_params_resp { + struct acx_header header; + + u16 rx_packet_ring_chunk_size; + u16 tx_packet_ring_chunk_size; + + u8 rx_packet_ring_chunk_num; + u8 tx_packet_ring_chunk_num; + + u8 pad[2]; + + u32 rx_packet_ring_addr; + u32 tx_packet_ring_addr; + + u32 rx_control_addr; + u32 tx_control_addr; + + u32 tx_complete_addr; +} __attribute__ ((packed)); + +#define TX_MSDU_LIFETIME_MIN 0 +#define TX_MSDU_LIFETIME_MAX 3000 +#define TX_MSDU_LIFETIME_DEF 512 +#define RX_MSDU_LIFETIME_MIN 0 +#define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF +#define RX_MSDU_LIFETIME_DEF 512000 + +struct acx_rx_msdu_lifetime { + struct acx_header header; + + /* + * The maximum amount of time, in TU, before the + * firmware discards the MSDU. + */ + u32 lifetime; +} __attribute__ ((packed)); + +/* + * RX Config Options Table + * Bit Definition + * === ========== + * 31:14 Reserved + * 13 Copy RX Status - when set, write three receive status words + * to top of rx'd MPDUs. + * When cleared, do not write three status words (added rev 1.5) + * 12 Reserved + * 11 RX Complete upon FCS error - when set, give rx complete + * interrupt for FCS errors, after the rx filtering, e.g. unicast + * frames not to us with FCS error will not generate an interrupt. + * 10 SSID Filter Enable - When set, the WiLink discards all beacon, + * probe request, and probe response frames with an SSID that does + * not match the SSID specified by the host in the START/JOIN + * command. + * When clear, the WiLink receives frames with any SSID. + * 9 Broadcast Filter Enable - When set, the WiLink discards all + * broadcast frames. When clear, the WiLink receives all received + * broadcast frames. + * 8:6 Reserved + * 5 BSSID Filter Enable - When set, the WiLink discards any frames + * with a BSSID that does not match the BSSID specified by the + * host. + * When clear, the WiLink receives frames from any BSSID. + * 4 MAC Addr Filter - When set, the WiLink discards any frames + * with a destination address that does not match the MAC address + * of the adaptor. + * When clear, the WiLink receives frames destined to any MAC + * address. + * 3 Promiscuous - When set, the WiLink receives all valid frames + * (i.e., all frames that pass the FCS check). + * When clear, only frames that pass the other filters specified + * are received. + * 2 FCS - When set, the WiLink includes the FCS with the received + * frame. + * When cleared, the FCS is discarded. + * 1 PLCP header - When set, write all data from baseband to frame + * buffer including PHY header. + * 0 Reserved - Always equal to 0. + * + * RX Filter Options Table + * Bit Definition + * === ========== + * 31:12 Reserved - Always equal to 0. + * 11 Association - When set, the WiLink receives all association + * related frames (association request/response, reassocation + * request/response, and disassociation). When clear, these frames + * are discarded. + * 10 Auth/De auth - When set, the WiLink receives all authentication + * and de-authentication frames. When clear, these frames are + * discarded. + * 9 Beacon - When set, the WiLink receives all beacon frames. + * When clear, these frames are discarded. + * 8 Contention Free - When set, the WiLink receives all contention + * free frames. + * When clear, these frames are discarded. + * 7 Control - When set, the WiLink receives all control frames. + * When clear, these frames are discarded. + * 6 Data - When set, the WiLink receives all data frames. + * When clear, these frames are discarded. + * 5 FCS Error - When set, the WiLink receives frames that have FCS + * errors. + * When clear, these frames are discarded. + * 4 Management - When set, the WiLink receives all management + * frames. + * When clear, these frames are discarded. + * 3 Probe Request - When set, the WiLink receives all probe request + * frames. + * When clear, these frames are discarded. + * 2 Probe Response - When set, the WiLink receives all probe + * response frames. + * When clear, these frames are discarded. + * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK + * frames. + * When clear, these frames are discarded. + * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames + * that have reserved frame types and sub types as defined by the + * 802.11 specification. + * When clear, these frames are discarded. + */ +struct acx_rx_config { + struct acx_header header; + + u32 config_options; + u32 filter_options; +} __attribute__ ((packed)); + +enum { + QOS_AC_BE = 0, + QOS_AC_BK, + QOS_AC_VI, + QOS_AC_VO, + QOS_HIGHEST_AC_INDEX = QOS_AC_VO, +}; + +#define MAX_NUM_OF_AC (QOS_HIGHEST_AC_INDEX+1) +#define FIRST_AC_INDEX QOS_AC_BE +#define MAX_NUM_OF_802_1d_TAGS 8 +#define AC_PARAMS_MAX_TSID 15 +#define MAX_APSD_CONF 0xffff + +#define QOS_TX_HIGH_MIN (0) +#define QOS_TX_HIGH_MAX (100) + +#define QOS_TX_HIGH_BK_DEF (25) +#define QOS_TX_HIGH_BE_DEF (35) +#define QOS_TX_HIGH_VI_DEF (35) +#define QOS_TX_HIGH_VO_DEF (35) + +#define QOS_TX_LOW_BK_DEF (15) +#define QOS_TX_LOW_BE_DEF (25) +#define QOS_TX_LOW_VI_DEF (25) +#define QOS_TX_LOW_VO_DEF (25) + +struct acx_tx_queue_qos_config { + struct acx_header header; + + u8 qid; + u8 pad[3]; + + /* Max number of blocks allowd in the queue */ + u16 high_threshold; + + /* Lowest memory blocks guaranteed for this queue */ + u16 low_threshold; +} __attribute__ ((packed)); + +struct acx_packet_detection { + struct acx_header header; + + u32 threshold; +} __attribute__ ((packed)); + + +enum acx_slot_type { + SLOT_TIME_LONG = 0, + SLOT_TIME_SHORT = 1, + DEFAULT_SLOT_TIME = SLOT_TIME_SHORT, + MAX_SLOT_TIMES = 0xFF +}; + +#define STATION_WONE_INDEX 0 + +struct acx_slot { + struct acx_header header; + + u8 wone_index; /* Reserved */ + u8 slot_time; + u8 reserved[6]; +} __attribute__ ((packed)); + + +#define ADDRESS_GROUP_MAX (8) +#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) + +struct acx_dot11_grp_addr_tbl { + struct acx_header header; + + u8 enabled; + u8 num_groups; + u8 pad[2]; + u8 mac_table[ADDRESS_GROUP_MAX_LEN]; +} __attribute__ ((packed)); + + +#define RX_TIMEOUT_PS_POLL_MIN 0 +#define RX_TIMEOUT_PS_POLL_MAX (200000) +#define RX_TIMEOUT_PS_POLL_DEF (15) +#define RX_TIMEOUT_UPSD_MIN 0 +#define RX_TIMEOUT_UPSD_MAX (200000) +#define RX_TIMEOUT_UPSD_DEF (15) + +struct acx_rx_timeout { + struct acx_header header; + + /* + * The longest time the STA will wait to receive + * traffic from the AP after a PS-poll has been + * transmitted. + */ + u16 ps_poll_timeout; + + /* + * The longest time the STA will wait to receive + * traffic from the AP after a frame has been sent + * from an UPSD enabled queue. + */ + u16 upsd_timeout; +} __attribute__ ((packed)); + +#define RTS_THRESHOLD_MIN 0 +#define RTS_THRESHOLD_MAX 4096 +#define RTS_THRESHOLD_DEF 2347 + +struct acx_rts_threshold { + struct acx_header header; + + u16 threshold; + u8 pad[2]; +} __attribute__ ((packed)); + +struct acx_beacon_filter_option { + struct acx_header header; + + u8 enable; + + /* + * The number of beacons without the unicast TIM + * bit set that the firmware buffers before + * signaling the host about ready frames. + * When set to 0 and the filter is enabled, beacons + * without the unicast TIM bit set are dropped. + */ + u8 max_num_beacons; + u8 pad[2]; +} __attribute__ ((packed)); + +/* + * ACXBeaconFilterEntry (not 221) + * Byte Offset Size (Bytes) Definition + * =========== ============ ========== + * 0 1 IE identifier + * 1 1 Treatment bit mask + * + * ACXBeaconFilterEntry (221) + * Byte Offset Size (Bytes) Definition + * =========== ============ ========== + * 0 1 IE identifier + * 1 1 Treatment bit mask + * 2 3 OUI + * 5 1 Type + * 6 2 Version + * + * + * Treatment bit mask - The information element handling: + * bit 0 - The information element is compared and transferred + * in case of change. + * bit 1 - The information element is transferred to the host + * with each appearance or disappearance. + * Note that both bits can be set at the same time. + */ +#define BEACON_FILTER_TABLE_MAX_IE_NUM (32) +#define BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM (6) +#define BEACON_FILTER_TABLE_IE_ENTRY_SIZE (2) +#define BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE (6) +#define BEACON_FILTER_TABLE_MAX_SIZE ((BEACON_FILTER_TABLE_MAX_IE_NUM * \ + BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \ + (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ + BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) + +struct acx_beacon_filter_ie_table { + struct acx_header header; + + u8 num_ie; + u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; + u8 pad[3]; +} __attribute__ ((packed)); + +enum { + SG_ENABLE = 0, + SG_DISABLE, + SG_SENSE_NO_ACTIVITY, + SG_SENSE_ACTIVE +}; + +struct acx_bt_wlan_coex { + struct acx_header header; + + /* + * 0 -> PTA enabled + * 1 -> PTA disabled + * 2 -> sense no active mode, i.e. + * an interrupt is sent upon + * BT activity. + * 3 -> PTA is switched on in response + * to the interrupt sending. + */ + u8 enable; + u8 pad[3]; +} __attribute__ ((packed)); + +#define PTA_ANTENNA_TYPE_DEF (0) +#define PTA_BT_HP_MAXTIME_DEF (2000) +#define PTA_WLAN_HP_MAX_TIME_DEF (5000) +#define PTA_SENSE_DISABLE_TIMER_DEF (1350) +#define PTA_PROTECTIVE_RX_TIME_DEF (1500) +#define PTA_PROTECTIVE_TX_TIME_DEF (1500) +#define PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF (3000) +#define PTA_SIGNALING_TYPE_DEF (1) +#define PTA_AFH_LEVERAGE_ON_DEF (0) +#define PTA_NUMBER_QUIET_CYCLE_DEF (0) +#define PTA_MAX_NUM_CTS_DEF (3) +#define PTA_NUMBER_OF_WLAN_PACKETS_DEF (2) +#define PTA_NUMBER_OF_BT_PACKETS_DEF (2) +#define PTA_PROTECTIVE_RX_TIME_FAST_DEF (1500) +#define PTA_PROTECTIVE_TX_TIME_FAST_DEF (3000) +#define PTA_CYCLE_TIME_FAST_DEF (8700) +#define PTA_RX_FOR_AVALANCHE_DEF (5) +#define PTA_ELP_HP_DEF (0) +#define PTA_ANTI_STARVE_PERIOD_DEF (500) +#define PTA_ANTI_STARVE_NUM_CYCLE_DEF (4) +#define PTA_ALLOW_PA_SD_DEF (1) +#define PTA_TIME_BEFORE_BEACON_DEF (6300) +#define PTA_HPDM_MAX_TIME_DEF (1600) +#define PTA_TIME_OUT_NEXT_WLAN_DEF (2550) +#define PTA_AUTO_MODE_NO_CTS_DEF (0) +#define PTA_BT_HP_RESPECTED_DEF (3) +#define PTA_WLAN_RX_MIN_RATE_DEF (24) +#define PTA_ACK_MODE_DEF (1) + +struct acx_bt_wlan_coex_param { + struct acx_header header; + + /* + * The minimum rate of a received WLAN packet in the STA, + * during protective mode, of which a new BT-HP request + * during this Rx will always be respected and gain the antenna. + */ + u32 min_rate; + + /* Max time the BT HP will be respected. */ + u16 bt_hp_max_time; + + /* Max time the WLAN HP will be respected. */ + u16 wlan_hp_max_time; + + /* + * The time between the last BT activity + * and the moment when the sense mode returns + * to SENSE_INACTIVE. + */ + u16 sense_disable_timer; + + /* Time before the next BT HP instance */ + u16 rx_time_bt_hp; + u16 tx_time_bt_hp; + + /* range: 10-20000 default: 1500 */ + u16 rx_time_bt_hp_fast; + u16 tx_time_bt_hp_fast; + + /* range: 2000-65535 default: 8700 */ + u16 wlan_cycle_fast; + + /* range: 0 - 15000 (Msec) default: 1000 */ + u16 bt_anti_starvation_period; + + /* range 400-10000(Usec) default: 3000 */ + u16 next_bt_lp_packet; + + /* Deafult: worst case for BT DH5 traffic */ + u16 wake_up_beacon; + + /* range: 0-50000(Usec) default: 1050 */ + u16 hp_dm_max_guard_time; + + /* + * This is to prevent both BT & WLAN antenna + * starvation. + * Range: 100-50000(Usec) default:2550 + */ + u16 next_wlan_packet; + + /* 0 -> shared antenna */ + u8 antenna_type; + + /* + * 0 -> TI legacy + * 1 -> Palau + */ + u8 signal_type; + + /* + * BT AFH status + * 0 -> no AFH + * 1 -> from dedicated GPIO + * 2 -> AFH on (from host) + */ + u8 afh_leverage_on; + + /* + * The number of cycles during which no + * TX will be sent after 1 cycle of RX + * transaction in protective mode + */ + u8 quiet_cycle_num; + + /* + * The maximum number of CTSs that will + * be sent for receiving RX packet in + * protective mode + */ + u8 max_cts; + + /* + * The number of WLAN packets + * transferred in common mode before + * switching to BT. + */ + u8 wlan_packets_num; + + /* + * The number of BT packets + * transferred in common mode before + * switching to WLAN. + */ + u8 bt_packets_num; + + /* range: 1-255 default: 5 */ + u8 missed_rx_avalanche; + + /* range: 0-1 default: 1 */ + u8 wlan_elp_hp; + + /* range: 0 - 15 default: 4 */ + u8 bt_anti_starvation_cycles; + + u8 ack_mode_dual_ant; + + /* + * Allow PA_SD assertion/de-assertion + * during enabled BT activity. + */ + u8 pa_sd_enable; + + /* + * Enable/Disable PTA in auto mode: + * Support Both Active & P.S modes + */ + u8 pta_auto_mode_enable; + + /* range: 0 - 20 default: 1 */ + u8 bt_hp_respected_num; +} __attribute__ ((packed)); + +#define CCA_THRSH_ENABLE_ENERGY_D 0x140A +#define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF + +struct acx_energy_detection { + struct acx_header header; + + /* The RX Clear Channel Assessment threshold in the PHY */ + u16 rx_cca_threshold; + u8 tx_energy_detection; + u8 pad; +} __attribute__ ((packed)); + +#define BCN_RX_TIMEOUT_DEF_VALUE 10000 +#define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000 +#define RX_BROADCAST_IN_PS_DEF_VALUE 1 +#define CONSECUTIVE_PS_POLL_FAILURE_DEF 4 + +struct acx_beacon_broadcast { + struct acx_header header; + + u16 beacon_rx_timeout; + u16 broadcast_timeout; + + /* Enables receiving of broadcast packets in PS mode */ + u8 rx_broadcast_in_ps; + + /* Consecutive PS Poll failures before updating the host */ + u8 ps_poll_threshold; + u8 pad[2]; +} __attribute__ ((packed)); + +struct acx_event_mask { + struct acx_header header; + + u32 event_mask; + u32 high_event_mask; /* Unused */ +} __attribute__ ((packed)); + +#define CFG_RX_FCS BIT(2) +#define CFG_RX_ALL_GOOD BIT(3) +#define CFG_UNI_FILTER_EN BIT(4) +#define CFG_BSSID_FILTER_EN BIT(5) +#define CFG_MC_FILTER_EN BIT(6) +#define CFG_MC_ADDR0_EN BIT(7) +#define CFG_MC_ADDR1_EN BIT(8) +#define CFG_BC_REJECT_EN BIT(9) +#define CFG_SSID_FILTER_EN BIT(10) +#define CFG_RX_INT_FCS_ERROR BIT(11) +#define CFG_RX_INT_ENCRYPTED BIT(12) +#define CFG_RX_WR_RX_STATUS BIT(13) +#define CFG_RX_FILTER_NULTI BIT(14) +#define CFG_RX_RESERVE BIT(15) +#define CFG_RX_TIMESTAMP_TSF BIT(16) + +#define CFG_RX_RSV_EN BIT(0) +#define CFG_RX_RCTS_ACK BIT(1) +#define CFG_RX_PRSP_EN BIT(2) +#define CFG_RX_PREQ_EN BIT(3) +#define CFG_RX_MGMT_EN BIT(4) +#define CFG_RX_FCS_ERROR BIT(5) +#define CFG_RX_DATA_EN BIT(6) +#define CFG_RX_CTL_EN BIT(7) +#define CFG_RX_CF_EN BIT(8) +#define CFG_RX_BCN_EN BIT(9) +#define CFG_RX_AUTH_EN BIT(10) +#define CFG_RX_ASSOC_EN BIT(11) + +#define SCAN_PASSIVE BIT(0) +#define SCAN_5GHZ_BAND BIT(1) +#define SCAN_TRIGGERED BIT(2) +#define SCAN_PRIORITY_HIGH BIT(3) + +struct acx_fw_gen_frame_rates { + struct acx_header header; + + u8 tx_ctrl_frame_rate; /* RATE_* */ + u8 tx_ctrl_frame_mod; /* CCK_* or PBCC_* */ + u8 tx_mgt_frame_rate; + u8 tx_mgt_frame_mod; +} __attribute__ ((packed)); + +/* STA MAC */ +struct acx_dot11_station_id { + struct acx_header header; + + u8 mac[ETH_ALEN]; + u8 pad[2]; +} __attribute__ ((packed)); + +struct acx_feature_config { + struct acx_header header; + + u32 options; + u32 data_flow_options; +} __attribute__ ((packed)); + +struct acx_current_tx_power { + struct acx_header header; + + u8 current_tx_power; + u8 padding[3]; +} __attribute__ ((packed)); + +struct acx_dot11_default_key { + struct acx_header header; + + u8 id; + u8 pad[3]; +} __attribute__ ((packed)); + +struct acx_tsf_info { + struct acx_header header; + + u32 current_tsf_msb; + u32 current_tsf_lsb; + u32 last_TBTT_msb; + u32 last_TBTT_lsb; + u8 last_dtim_count; + u8 pad[3]; +} __attribute__ ((packed)); + +enum acx_wake_up_event { + WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/ + WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/ + WAKE_UP_EVENT_N_DTIM_BITMAP = 0x04, /* Wake on every Nth DTIM */ + WAKE_UP_EVENT_N_BEACONS_BITMAP = 0x08, /* Wake on every Nth Beacon */ + WAKE_UP_EVENT_BITS_MASK = 0x0F +}; + +struct acx_wake_up_condition { + struct acx_header header; + + u8 wake_up_event; /* Only one bit can be set */ + u8 listen_interval; + u8 pad[2]; +} __attribute__ ((packed)); + +struct acx_aid { + struct acx_header header; + + /* + * To be set when associated with an AP. + */ + u16 aid; + u8 pad[2]; +} __attribute__ ((packed)); + +enum acx_preamble_type { + ACX_PREAMBLE_LONG = 0, + ACX_PREAMBLE_SHORT = 1 +}; + +struct acx_preamble { + struct acx_header header; + + /* + * When set, the WiLink transmits the frames with a short preamble and + * when cleared, the WiLink transmits the frames with a long preamble. + */ + u8 preamble; + u8 padding[3]; +} __attribute__ ((packed)); + +enum acx_ctsprotect_type { + CTSPROTECT_DISABLE = 0, + CTSPROTECT_ENABLE = 1 +}; + +struct acx_ctsprotect { + struct acx_header header; + u8 ctsprotect; + u8 padding[3]; +} __attribute__ ((packed)); + +struct acx_tx_statistics { + u32 internal_desc_overflow; +} __attribute__ ((packed)); + +struct acx_rx_statistics { + u32 out_of_mem; + u32 hdr_overflow; + u32 hw_stuck; + u32 dropped; + u32 fcs_err; + u32 xfr_hint_trig; + u32 path_reset; + u32 reset_counter; +} __attribute__ ((packed)); + +struct acx_dma_statistics { + u32 rx_requested; + u32 rx_errors; + u32 tx_requested; + u32 tx_errors; +} __attribute__ ((packed)); + +struct acx_isr_statistics { + /* host command complete */ + u32 cmd_cmplt; + + /* fiqisr() */ + u32 fiqs; + + /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ + u32 rx_headers; + + /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ + u32 rx_completes; + + /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ + u32 rx_mem_overflow; + + /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ + u32 rx_rdys; + + /* irqisr() */ + u32 irqs; + + /* (INT_STS_ND & INT_TRIG_TX_PROC) */ + u32 tx_procs; + + /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ + u32 decrypt_done; + + /* (INT_STS_ND & INT_TRIG_DMA0) */ + u32 dma0_done; + + /* (INT_STS_ND & INT_TRIG_DMA1) */ + u32 dma1_done; + + /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ + u32 tx_exch_complete; + + /* (INT_STS_ND & INT_TRIG_COMMAND) */ + u32 commands; + + /* (INT_STS_ND & INT_TRIG_RX_PROC) */ + u32 rx_procs; + + /* (INT_STS_ND & INT_TRIG_PM_802) */ + u32 hw_pm_mode_changes; + + /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ + u32 host_acknowledges; + + /* (INT_STS_ND & INT_TRIG_PM_PCI) */ + u32 pci_pm; + + /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ + u32 wakeups; + + /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ + u32 low_rssi; +} __attribute__ ((packed)); + +struct acx_wep_statistics { + /* WEP address keys configured */ + u32 addr_key_count; + + /* default keys configured */ + u32 default_key_count; + + u32 reserved; + + /* number of times that WEP key not found on lookup */ + u32 key_not_found; + + /* number of times that WEP key decryption failed */ + u32 decrypt_fail; + + /* WEP packets decrypted */ + u32 packets; + + /* WEP decrypt interrupts */ + u32 interrupt; +} __attribute__ ((packed)); + +#define ACX_MISSED_BEACONS_SPREAD 10 + +struct acx_pwr_statistics { + /* the amount of enters into power save mode (both PD & ELP) */ + u32 ps_enter; + + /* the amount of enters into ELP mode */ + u32 elp_enter; + + /* the amount of missing beacon interrupts to the host */ + u32 missing_bcns; + + /* the amount of wake on host-access times */ + u32 wake_on_host; + + /* the amount of wake on timer-expire */ + u32 wake_on_timer_exp; + + /* the number of packets that were transmitted with PS bit set */ + u32 tx_with_ps; + + /* the number of packets that were transmitted with PS bit clear */ + u32 tx_without_ps; + + /* the number of received beacons */ + u32 rcvd_beacons; + + /* the number of entering into PowerOn (power save off) */ + u32 power_save_off; + + /* the number of entries into power save mode */ + u16 enable_ps; + + /* + * the number of exits from power save, not including failed PS + * transitions + */ + u16 disable_ps; + + /* + * the number of times the TSF counter was adjusted because + * of drift + */ + u32 fix_tsf_ps; + + /* Gives statistics about the spread continuous missed beacons. + * The 16 LSB are dedicated for the PS mode. + * The 16 MSB are dedicated for the PS mode. + * cont_miss_bcns_spread[0] - single missed beacon. + * cont_miss_bcns_spread[1] - two continuous missed beacons. + * cont_miss_bcns_spread[2] - three continuous missed beacons. + * ... + * cont_miss_bcns_spread[9] - ten and more continuous missed beacons. + */ + u32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; + + /* the number of beacons in awake mode */ + u32 rcvd_awake_beacons; +} __attribute__ ((packed)); + +struct acx_mic_statistics { + u32 rx_pkts; + u32 calc_failure; +} __attribute__ ((packed)); + +struct acx_aes_statistics { + u32 encrypt_fail; + u32 decrypt_fail; + u32 encrypt_packets; + u32 decrypt_packets; + u32 encrypt_interrupt; + u32 decrypt_interrupt; +} __attribute__ ((packed)); + +struct acx_event_statistics { + u32 heart_beat; + u32 calibration; + u32 rx_mismatch; + u32 rx_mem_empty; + u32 rx_pool; + u32 oom_late; + u32 phy_transmit_error; + u32 tx_stuck; +} __attribute__ ((packed)); + +struct acx_ps_statistics { + u32 pspoll_timeouts; + u32 upsd_timeouts; + u32 upsd_max_sptime; + u32 upsd_max_apturn; + u32 pspoll_max_apturn; + u32 pspoll_utilization; + u32 upsd_utilization; +} __attribute__ ((packed)); + +struct acx_rxpipe_statistics { + u32 rx_prep_beacon_drop; + u32 descr_host_int_trig_rx_data; + u32 beacon_buffer_thres_host_int_trig_rx_data; + u32 missed_beacon_host_int_trig_rx_data; + u32 tx_xfr_host_int_trig_rx_data; +} __attribute__ ((packed)); + +struct acx_statistics { + struct acx_header header; + + struct acx_tx_statistics tx; + struct acx_rx_statistics rx; + struct acx_dma_statistics dma; + struct acx_isr_statistics isr; + struct acx_wep_statistics wep; + struct acx_pwr_statistics pwr; + struct acx_aes_statistics aes; + struct acx_mic_statistics mic; + struct acx_event_statistics event; + struct acx_ps_statistics ps; + struct acx_rxpipe_statistics rxpipe; +} __attribute__ ((packed)); + +enum { + ACX_WAKE_UP_CONDITIONS = 0x0002, + ACX_MEM_CFG = 0x0003, + ACX_SLOT = 0x0004, + ACX_QUEUE_HEAD = 0x0005, /* for MASTER mode only */ + ACX_AC_CFG = 0x0007, + ACX_MEM_MAP = 0x0008, + ACX_AID = 0x000A, + ACX_RADIO_PARAM = 0x000B, /* Not used */ + ACX_CFG = 0x000C, /* Not used */ + ACX_FW_REV = 0x000D, + ACX_MEDIUM_USAGE = 0x000F, + ACX_RX_CFG = 0x0010, + ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */ + ACX_BSS_IN_PS = 0x0012, /* for AP only */ + ACX_STATISTICS = 0x0013, /* Debug API */ + ACX_FEATURE_CFG = 0x0015, + ACX_MISC_CFG = 0x0017, /* Not used */ + ACX_TID_CFG = 0x001A, + ACX_BEACON_FILTER_OPT = 0x001F, + ACX_LOW_RSSI = 0x0020, + ACX_NOISE_HIST = 0x0021, + ACX_HDK_VERSION = 0x0022, /* ??? */ + ACX_PD_THRESHOLD = 0x0023, + ACX_DATA_PATH_PARAMS = 0x0024, /* WO */ + ACX_DATA_PATH_RESP_PARAMS = 0x0024, /* RO */ + ACX_CCA_THRESHOLD = 0x0025, + ACX_EVENT_MBOX_MASK = 0x0026, +#ifdef FW_RUNNING_AS_AP + ACX_DTIM_PERIOD = 0x0027, /* for AP only */ +#else + ACX_WR_TBTT_AND_DTIM = 0x0027, /* STA only */ +#endif + ACX_ACI_OPTION_CFG = 0x0029, /* OBSOLETE (for 1251)*/ + ACX_GPIO_CFG = 0x002A, /* Not used */ + ACX_GPIO_SET = 0x002B, /* Not used */ + ACX_PM_CFG = 0x002C, /* To Be Documented */ + ACX_CONN_MONIT_PARAMS = 0x002D, + ACX_AVERAGE_RSSI = 0x002E, /* Not used */ + ACX_CONS_TX_FAILURE = 0x002F, + ACX_BCN_DTIM_OPTIONS = 0x0031, + ACX_SG_ENABLE = 0x0032, + ACX_SG_CFG = 0x0033, + ACX_ANTENNA_DIVERSITY_CFG = 0x0035, /* To Be Documented */ + ACX_LOW_SNR = 0x0037, /* To Be Documented */ + ACX_BEACON_FILTER_TABLE = 0x0038, + ACX_ARP_IP_FILTER = 0x0039, + ACX_ROAMING_STATISTICS_TBL = 0x003B, + ACX_RATE_POLICY = 0x003D, + ACX_CTS_PROTECTION = 0x003E, + ACX_SLEEP_AUTH = 0x003F, + ACX_PREAMBLE_TYPE = 0x0040, + ACX_ERROR_CNT = 0x0041, + ACX_FW_GEN_FRAME_RATES = 0x0042, + ACX_IBSS_FILTER = 0x0044, + ACX_SERVICE_PERIOD_TIMEOUT = 0x0045, + ACX_TSF_INFO = 0x0046, + ACX_CONFIG_PS_WMM = 0x0049, + ACX_ENABLE_RX_DATA_FILTER = 0x004A, + ACX_SET_RX_DATA_FILTER = 0x004B, + ACX_GET_DATA_FILTER_STATISTICS = 0x004C, + ACX_POWER_LEVEL_TABLE = 0x004D, + ACX_BET_ENABLE = 0x0050, + DOT11_STATION_ID = 0x1001, + DOT11_RX_MSDU_LIFE_TIME = 0x1004, + DOT11_CUR_TX_PWR = 0x100D, + DOT11_DEFAULT_KEY = 0x1010, + DOT11_RX_DOT11_MODE = 0x1012, + DOT11_RTS_THRESHOLD = 0x1013, + DOT11_GROUP_ADDRESS_TBL = 0x1014, + + MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, + + MAX_IE = 0xFFFF +}; + + +int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, + u8 mgt_rate, u8 mgt_mod); +int wl12xx_acx_station_id(struct wl12xx *wl); +int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id); +int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 wake_up_event, + u8 listen_interval); +int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth); +int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len); +int wl12xx_acx_tx_power(struct wl12xx *wl, int power); +int wl12xx_acx_feature_cfg(struct wl12xx *wl); +int wl12xx_acx_mem_map(struct wl12xx *wl, + struct acx_header *mem_map, size_t len); +int wl12xx_acx_data_path_params(struct wl12xx *wl, + struct acx_data_path_params_resp *data_path); +int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time); +int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter); +int wl12xx_acx_pd_threshold(struct wl12xx *wl); +int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time); +int wl12xx_acx_group_address_tbl(struct wl12xx *wl); +int wl12xx_acx_service_period_timeout(struct wl12xx *wl); +int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold); +int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl); +int wl12xx_acx_beacon_filter_table(struct wl12xx *wl); +int wl12xx_acx_sg_enable(struct wl12xx *wl); +int wl12xx_acx_sg_cfg(struct wl12xx *wl); +int wl12xx_acx_cca_threshold(struct wl12xx *wl); +int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl); +int wl12xx_acx_aid(struct wl12xx *wl, u16 aid); +int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask); +int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble); +int wl12xx_acx_cts_protect(struct wl12xx *wl, + enum acx_ctsprotect_type ctsprotect); +int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats); +int wl12xx_acx_tsf_info(struct wl12xx *wl, u64 *mactime); + +#endif /* __WL12XX_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c new file mode 100644 index 00000000000..c52a2085671 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -0,0 +1,297 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include + +#include "reg.h" +#include "wl1251_boot.h" +#include "wl1251_spi.h" +#include "wl1251_event.h" + +static void wl12xx_boot_enable_interrupts(struct wl12xx *wl) +{ + enable_irq(wl->irq); +} + +void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl) +{ + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); + wl12xx_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); +} + +int wl12xx_boot_soft_reset(struct wl12xx *wl) +{ + unsigned long timeout; + u32 boot_data; + + /* perform soft reset */ + wl12xx_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); + + /* SOFT_RESET is self clearing */ + timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); + while (1) { + boot_data = wl12xx_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); + wl12xx_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); + if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) + break; + + if (time_after(jiffies, timeout)) { + /* 1.2 check pWhalBus->uSelfClearTime if the + * timeout was reached */ + wl12xx_error("soft reset timeout"); + return -1; + } + + udelay(SOFT_RESET_STALL_TIME); + } + + /* disable Rx/Tx */ + wl12xx_reg_write32(wl, ENABLE, 0x0); + + /* disable auto calibration on start*/ + wl12xx_reg_write32(wl, SPARE_A2, 0xffff); + + return 0; +} + +int wl12xx_boot_init_seq(struct wl12xx *wl) +{ + u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq; + + /* + * col #1: INTEGER_DIVIDER + * col #2: FRACTIONAL_DIVIDER + * col #3: ATTN_BB + * col #4: ALPHA_BB + * col #5: STOP_TIME_BB + * col #6: BB_PLL_LOOP_FILTER + */ + static const u32 LUT[REF_FREQ_NUM][LUT_PARAM_NUM] = { + + { 83, 87381, 0xB, 5, 0xF00, 3}, /* REF_FREQ_19_2*/ + { 61, 141154, 0xB, 5, 0x1450, 2}, /* REF_FREQ_26_0*/ + { 41, 174763, 0xC, 6, 0x2D00, 1}, /* REF_FREQ_38_4*/ + { 40, 0, 0xC, 6, 0x2EE0, 1}, /* REF_FREQ_40_0*/ + { 47, 162280, 0xC, 6, 0x2760, 1} /* REF_FREQ_33_6 */ + }; + + /* read NVS params */ + scr_pad6 = wl12xx_reg_read32(wl, SCR_PAD6); + wl12xx_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6); + + /* read ELP_CMD */ + elp_cmd = wl12xx_reg_read32(wl, ELP_CMD); + wl12xx_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd); + + /* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */ + ref_freq = scr_pad6 & 0x000000FF; + wl12xx_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq); + + wl12xx_reg_write32(wl, PLL_CAL_TIME, 0x9); + + /* + * PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME) + */ + wl12xx_reg_write32(wl, CLK_BUF_TIME, 0x6); + + /* + * set the clock detect feature to work in the restart wu procedure + * (ELP_CFG_MODE[14]) and Select the clock source type + * (ELP_CFG_MODE[13:12]) + */ + tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000; + wl12xx_reg_write32(wl, ELP_CFG_MODE, tmp); + + /* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */ + elp_cmd |= 0x00000040; + wl12xx_reg_write32(wl, ELP_CMD, elp_cmd); + + /* PG 1.2: Set the BB PLL stable time to be 1000usec + * (PLL_STABLE_TIME) */ + wl12xx_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20); + + /* PG 1.2: read clock request time */ + init_data = wl12xx_reg_read32(wl, CLK_REQ_TIME); + + /* + * PG 1.2: set the clock request time to be ref_clk_settling_time - + * 1ms = 4ms + */ + if (init_data > 0x21) + tmp = init_data - 0x21; + else + tmp = 0; + wl12xx_reg_write32(wl, CLK_REQ_TIME, tmp); + + /* set BB PLL configurations in RF AFE */ + wl12xx_reg_write32(wl, 0x003058cc, 0x4B5); + + /* set RF_AFE_REG_5 */ + wl12xx_reg_write32(wl, 0x003058d4, 0x50); + + /* set RF_AFE_CTRL_REG_2 */ + wl12xx_reg_write32(wl, 0x00305948, 0x11c001); + + /* + * change RF PLL and BB PLL divider for VCO clock and adjust VCO + * bais current(RF_AFE_REG_13) + */ + wl12xx_reg_write32(wl, 0x003058f4, 0x1e); + + /* set BB PLL configurations */ + tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000; + wl12xx_reg_write32(wl, 0x00305840, tmp); + + /* set fractional divider according to Appendix C-BB PLL + * Calculations + */ + tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER]; + wl12xx_reg_write32(wl, 0x00305844, tmp); + + /* set the initial data for the sigma delta */ + wl12xx_reg_write32(wl, 0x00305848, 0x3039); + + /* + * set the accumulator attenuation value, calibration loop1 + * (alpha), calibration loop2 (beta), calibration loop3 (gamma) and + * the VCO gain + */ + tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) | + (LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1; + wl12xx_reg_write32(wl, 0x00305854, tmp); + + /* + * set the calibration stop time after holdoff time expires and set + * settling time HOLD_OFF_TIME_BB + */ + tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000; + wl12xx_reg_write32(wl, 0x00305858, tmp); + + /* + * set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL + * constant leakage current to linearize PFD to 0uA - + * BB_ILOOPF[7:3] + */ + tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030; + wl12xx_reg_write32(wl, 0x003058f8, tmp); + + /* + * set regulator output voltage for n divider to + * 1.35-BB_REFDIV[1:0], set charge pump current- BB_CPGAIN[4:2], + * set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB + * PLL auto-call to normal mode- BB_CALGAIN_3DB[8] + */ + wl12xx_reg_write32(wl, 0x003058f0, 0x29); + + /* enable restart wakeup sequence (ELP_CMD[0]) */ + wl12xx_reg_write32(wl, ELP_CMD, elp_cmd | 0x1); + + /* restart sequence completed */ + udelay(2000); + + return 0; +} + +int wl12xx_boot_run_firmware(struct wl12xx *wl) +{ + int loop, ret; + u32 chip_id, interrupt; + + wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); + + chip_id = wl12xx_reg_read32(wl, CHIP_ID_B); + + wl12xx_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); + + if (chip_id != wl->chip.id) { + wl12xx_error("chip id doesn't match after firmware boot"); + return -EIO; + } + + /* wait for init to complete */ + loop = 0; + while (loop++ < INIT_LOOP) { + udelay(INIT_LOOP_DELAY); + interrupt = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + + if (interrupt == 0xffffffff) { + wl12xx_error("error reading hardware complete " + "init indication"); + return -EIO; + } + /* check that ACX_INTR_INIT_COMPLETE is enabled */ + else if (interrupt & wl->chip.intr_init_complete) { + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK, + wl->chip.intr_init_complete); + break; + } + } + + if (loop >= INIT_LOOP) { + wl12xx_error("timeout waiting for the hardware to " + "complete initialization"); + return -EIO; + } + + /* get hardware config command mail box */ + wl->cmd_box_addr = wl12xx_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); + + /* get hardware config event mail box */ + wl->event_box_addr = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR); + + /* set the working partition to its "running" mode offset */ + wl12xx_set_partition(wl, + wl->chip.p_table[PART_WORK].mem.start, + wl->chip.p_table[PART_WORK].mem.size, + wl->chip.p_table[PART_WORK].reg.start, + wl->chip.p_table[PART_WORK].reg.size); + + wl12xx_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", + wl->cmd_box_addr, wl->event_box_addr); + + wl->chip.op_fw_version(wl); + + /* + * in case of full asynchronous mode the firmware event must be + * ready to receive event from the command mailbox + */ + + /* enable gpio interrupts */ + wl12xx_boot_enable_interrupts(wl); + + wl->chip.op_target_enable_interrupts(wl); + + /* unmask all mbox events */ + wl->event_mask = 0xffffffff; + + ret = wl12xx_event_unmask(wl); + if (ret < 0) { + wl12xx_error("EVENT mask setting failed"); + return ret; + } + + wl12xx_event_mbox_config(wl); + + /* firmware startup completed */ + return 0; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.h b/drivers/net/wireless/wl12xx/wl1251_boot.h new file mode 100644 index 00000000000..4fa73132baa --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_boot.h @@ -0,0 +1,40 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __BOOT_H__ +#define __BOOT_H__ + +#include "wl12xx.h" + +int wl12xx_boot_soft_reset(struct wl12xx *wl); +int wl12xx_boot_init_seq(struct wl12xx *wl); +int wl12xx_boot_run_firmware(struct wl12xx *wl); +void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl); + +/* number of times we try to read the INIT interrupt */ +#define INIT_LOOP 20000 + +/* delay between retries */ +#define INIT_LOOP_DELAY 50 + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c new file mode 100644 index 00000000000..d0c2df6b519 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -0,0 +1,429 @@ +#include "wl1251_cmd.h" + +#include +#include +#include + +#include "wl12xx.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "wl1251_spi.h" +#include "wl1251_ps.h" +#include "wl1251_acx.h" + +/** + * send command to firmware + * + * @wl: wl struct + * @id: command id + * @buf: buffer containing the command, must work with dma + * @len: length of the buffer + */ +int wl12xx_cmd_send(struct wl12xx *wl, u16 id, void *buf, size_t len) +{ + struct wl12xx_cmd_header *cmd; + unsigned long timeout; + u32 intr; + int ret = 0; + + cmd = buf; + cmd->id = id; + cmd->status = 0; + + WARN_ON(len % 4 != 0); + + wl12xx_spi_mem_write(wl, wl->cmd_box_addr, buf, len); + + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); + + timeout = jiffies + msecs_to_jiffies(WL12XX_COMMAND_TIMEOUT); + + intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + while (!(intr & wl->chip.intr_cmd_complete)) { + if (time_after(jiffies, timeout)) { + wl12xx_error("command complete timeout"); + ret = -ETIMEDOUT; + goto out; + } + + msleep(1); + + intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + } + + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK, + wl->chip.intr_cmd_complete); + +out: + return ret; +} + +/** + * send test command to firmware + * + * @wl: wl struct + * @buf: buffer containing the command, with all headers, must work with dma + * @len: length of the buffer + * @answer: is answer needed + */ +int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) +{ + int ret; + + wl12xx_debug(DEBUG_CMD, "cmd test"); + + ret = wl12xx_cmd_send(wl, CMD_TEST, buf, buf_len); + + if (ret < 0) { + wl12xx_warning("TEST command failed"); + return ret; + } + + if (answer) { + struct wl12xx_command *cmd_answer; + + /* + * The test command got in, we can read the answer. + * The answer would be a wl12xx_command, where the + * parameter array contains the actual answer. + */ + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); + + cmd_answer = buf; + + if (cmd_answer->header.status != CMD_STATUS_SUCCESS) + wl12xx_error("TEST command answer error: %d", + cmd_answer->header.status); + } + + return 0; +} + +/** + * read acx from firmware + * + * @wl: wl struct + * @id: acx id + * @buf: buffer for the response, including all headers, must work with dma + * @len: lenght of buf + */ +int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 id, void *buf, size_t len) +{ + struct acx_header *acx = buf; + int ret; + + wl12xx_debug(DEBUG_CMD, "cmd interrogate"); + + acx->id = id; + + /* payload length, does not include any headers */ + acx->len = len - sizeof(*acx); + + ret = wl12xx_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); + if (ret < 0) { + wl12xx_error("INTERROGATE command failed"); + goto out; + } + + /* the interrogate command got in, we can read the answer */ + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, len); + + acx = buf; + if (acx->cmd.status != CMD_STATUS_SUCCESS) + wl12xx_error("INTERROGATE command error: %d", + acx->cmd.status); + +out: + return ret; +} + +/** + * write acx value to firmware + * + * @wl: wl struct + * @id: acx id + * @buf: buffer containing acx, including all headers, must work with dma + * @len: length of buf + */ +int wl12xx_cmd_configure(struct wl12xx *wl, u16 id, void *buf, size_t len) +{ + struct acx_header *acx = buf; + int ret; + + wl12xx_debug(DEBUG_CMD, "cmd configure"); + + acx->id = id; + + /* payload length, does not include any headers */ + acx->len = len - sizeof(*acx); + + ret = wl12xx_cmd_send(wl, CMD_CONFIGURE, acx, len); + if (ret < 0) { + wl12xx_warning("CONFIGURE command NOK"); + return ret; + } + + return 0; +} + +int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, + void *bitmap, u16 bitmap_len, u8 bitmap_control) +{ + struct wl12xx_cmd_vbm_update *vbm; + int ret; + + wl12xx_debug(DEBUG_CMD, "cmd vbm"); + + vbm = kzalloc(sizeof(*vbm), GFP_KERNEL); + if (!vbm) { + ret = -ENOMEM; + goto out; + } + + /* Count and period will be filled by the target */ + vbm->tim.bitmap_ctrl = bitmap_control; + if (bitmap_len > PARTIAL_VBM_MAX) { + wl12xx_warning("cmd vbm len is %d B, truncating to %d", + bitmap_len, PARTIAL_VBM_MAX); + bitmap_len = PARTIAL_VBM_MAX; + } + memcpy(vbm->tim.pvb_field, bitmap, bitmap_len); + vbm->tim.identity = identity; + vbm->tim.length = bitmap_len + 3; + + vbm->len = cpu_to_le16(bitmap_len + 5); + + ret = wl12xx_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm)); + if (ret < 0) { + wl12xx_error("VBM command failed"); + goto out; + } + +out: + kfree(vbm); + return 0; +} + +int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable) +{ + struct cmd_enabledisable_path *cmd; + int ret; + u16 cmd_rx, cmd_tx; + + wl12xx_debug(DEBUG_CMD, "cmd data path"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->channel = channel; + + if (enable) { + cmd_rx = CMD_ENABLE_RX; + cmd_tx = CMD_ENABLE_TX; + } else { + cmd_rx = CMD_DISABLE_RX; + cmd_tx = CMD_DISABLE_TX; + } + + ret = wl12xx_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); + if (ret < 0) { + wl12xx_error("rx %s cmd for channel %d failed", + enable ? "start" : "stop", channel); + goto out; + } + + wl12xx_debug(DEBUG_BOOT, "rx %s cmd channel %d", + enable ? "start" : "stop", channel); + + ret = wl12xx_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); + if (ret < 0) { + wl12xx_error("tx %s cmd for channel %d failed", + enable ? "start" : "stop", channel); + return ret; + } + + wl12xx_debug(DEBUG_BOOT, "tx %s cmd channel %d", + enable ? "start" : "stop", channel); + +out: + kfree(cmd); + return ret; +} + +int wl1251_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, + u16 beacon_interval, u8 wait) +{ + unsigned long timeout; + struct cmd_join *join; + int ret, i; + u8 *bssid; + + join = kzalloc(sizeof(*join), GFP_KERNEL); + if (!join) { + ret = -ENOMEM; + goto out; + } + + /* FIXME: this should be in main.c */ + ret = wl12xx_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, + DEFAULT_HW_GEN_MODULATION_TYPE, + wl->tx_mgmt_frm_rate, + wl->tx_mgmt_frm_mod); + if (ret < 0) + goto out; + + wl12xx_debug(DEBUG_CMD, "cmd join"); + + /* Reverse order BSSID */ + bssid = (u8 *) &join->bssid_lsb; + for (i = 0; i < ETH_ALEN; i++) + bssid[i] = wl->bssid[ETH_ALEN - i - 1]; + + join->rx_config_options = wl->rx_config; + join->rx_filter_options = wl->rx_filter; + + join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | + RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; + + join->beacon_interval = beacon_interval; + join->dtim_interval = dtim_interval; + join->bss_type = bss_type; + join->channel = wl->channel; + join->ctrl = JOIN_CMD_CTRL_TX_FLUSH; + + ret = wl12xx_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); + if (ret < 0) { + wl12xx_error("failed to initiate cmd join"); + goto out; + } + + timeout = msecs_to_jiffies(JOIN_TIMEOUT); + + /* + * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to + * simplify locking we just sleep instead, for now + */ + if (wait) + msleep(10); + +out: + kfree(join); + return ret; +} + +int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode) +{ + struct wl12xx_cmd_ps_params *ps_params = NULL; + int ret = 0; + + /* FIXME: this should be in ps.c */ + ret = wl12xx_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, + wl->listen_int); + if (ret < 0) { + wl12xx_error("couldn't set wake up conditions"); + goto out; + } + + wl12xx_debug(DEBUG_CMD, "cmd set ps mode"); + + ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); + if (!ps_params) { + ret = -ENOMEM; + goto out; + } + + ps_params->ps_mode = ps_mode; + ps_params->send_null_data = 1; + ps_params->retries = 5; + ps_params->hang_over_period = 128; + ps_params->null_data_rate = 1; /* 1 Mbps */ + + ret = wl12xx_cmd_send(wl, CMD_SET_PS_MODE, ps_params, + sizeof(*ps_params)); + if (ret < 0) { + wl12xx_error("cmd set_ps_mode failed"); + goto out; + } + +out: + kfree(ps_params); + return ret; +} + +int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer, + size_t len) +{ + struct cmd_read_write_memory *cmd; + int ret = 0; + + wl12xx_debug(DEBUG_CMD, "cmd read memory"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + WARN_ON(len > MAX_READ_SIZE); + len = min_t(size_t, len, MAX_READ_SIZE); + + cmd->addr = addr; + cmd->size = len; + + ret = wl12xx_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); + if (ret < 0) { + wl12xx_error("read memory command failed: %d", ret); + goto out; + } + + /* the read command got in, we can now read the answer */ + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); + + if (cmd->header.status != CMD_STATUS_SUCCESS) + wl12xx_error("error in read command result: %d", + cmd->header.status); + + memcpy(answer, cmd->value, len); + +out: + kfree(cmd); + return ret; +} + +int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, + void *buf, size_t buf_len) +{ + struct wl12xx_cmd_packet_template *cmd; + size_t cmd_len; + int ret = 0; + + wl12xx_debug(DEBUG_CMD, "cmd template %d", cmd_id); + + WARN_ON(buf_len > WL12XX_MAX_TEMPLATE_SIZE); + buf_len = min_t(size_t, buf_len, WL12XX_MAX_TEMPLATE_SIZE); + cmd_len = ALIGN(sizeof(*cmd) + buf_len, 4); + + cmd = kzalloc(cmd_len, GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->size = cpu_to_le16(buf_len); + + if (buf) + memcpy(cmd->data, buf, buf_len); + + ret = wl12xx_cmd_send(wl, cmd_id, cmd, cmd_len); + if (ret < 0) { + wl12xx_warning("cmd set_template failed: %d", ret); + goto out; + } + +out: + kfree(cmd); + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h new file mode 100644 index 00000000000..a2eae54a241 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h @@ -0,0 +1,407 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_CMD_H__ +#define __WL12XX_CMD_H__ + +#include "wl12xx.h" + +struct acx_header; + +int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len); +int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer); +int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 id, void *buf, size_t len); +int wl12xx_cmd_configure(struct wl12xx *wl, u16 id, void *buf, size_t len); +int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, + void *bitmap, u16 bitmap_len, u8 bitmap_control); +int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable); +int wl1251_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, + u16 beacon_interval, u8 wait); +int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode); +int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer, + size_t len); +int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, + void *buf, size_t buf_len); + +/* unit ms */ +#define WL12XX_COMMAND_TIMEOUT 2000 + +enum wl12xx_commands { + CMD_RESET = 0, + CMD_INTERROGATE = 1, /*use this to read information elements*/ + CMD_CONFIGURE = 2, /*use this to write information elements*/ + CMD_ENABLE_RX = 3, + CMD_ENABLE_TX = 4, + CMD_DISABLE_RX = 5, + CMD_DISABLE_TX = 6, + CMD_SCAN = 8, + CMD_STOP_SCAN = 9, + CMD_VBM = 10, + CMD_START_JOIN = 11, + CMD_SET_KEYS = 12, + CMD_READ_MEMORY = 13, + CMD_WRITE_MEMORY = 14, + CMD_BEACON = 19, + CMD_PROBE_RESP = 20, + CMD_NULL_DATA = 21, + CMD_PROBE_REQ = 22, + CMD_TEST = 23, + CMD_RADIO_CALIBRATE = 25, /* OBSOLETE */ + CMD_ENABLE_RX_PATH = 27, /* OBSOLETE */ + CMD_NOISE_HIST = 28, + CMD_RX_RESET = 29, + CMD_PS_POLL = 30, + CMD_QOS_NULL_DATA = 31, + CMD_LNA_CONTROL = 32, + CMD_SET_BCN_MODE = 33, + CMD_MEASUREMENT = 34, + CMD_STOP_MEASUREMENT = 35, + CMD_DISCONNECT = 36, + CMD_SET_PS_MODE = 37, + CMD_CHANNEL_SWITCH = 38, + CMD_STOP_CHANNEL_SWICTH = 39, + CMD_AP_DISCOVERY = 40, + CMD_STOP_AP_DISCOVERY = 41, + CMD_SPS_SCAN = 42, + CMD_STOP_SPS_SCAN = 43, + CMD_HEALTH_CHECK = 45, + CMD_DEBUG = 46, + CMD_TRIGGER_SCAN_TO = 47, + + NUM_COMMANDS, + MAX_COMMAND_ID = 0xFFFF, +}; + +#define MAX_CMD_PARAMS 572 + +struct wl12xx_cmd_header { + u16 id; + u16 status; + /* payload */ + u8 data[0]; +} __attribute__ ((packed)); + +struct wl12xx_command { + struct wl12xx_cmd_header header; + u8 parameters[MAX_CMD_PARAMS]; +}; + +enum { + CMD_MAILBOX_IDLE = 0, + CMD_STATUS_SUCCESS = 1, + CMD_STATUS_UNKNOWN_CMD = 2, + CMD_STATUS_UNKNOWN_IE = 3, + CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11, + CMD_STATUS_RX_BUSY = 13, + CMD_STATUS_INVALID_PARAM = 14, + CMD_STATUS_TEMPLATE_TOO_LARGE = 15, + CMD_STATUS_OUT_OF_MEMORY = 16, + CMD_STATUS_STA_TABLE_FULL = 17, + CMD_STATUS_RADIO_ERROR = 18, + CMD_STATUS_WRONG_NESTING = 19, + CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ + CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ + MAX_COMMAND_STATUS = 0xff +}; + + +/* + * CMD_READ_MEMORY + * + * The host issues this command to read the WiLink device memory/registers. + * + * Note: The Base Band address has special handling (16 bits registers and + * addresses). For more information, see the hardware specification. + */ +/* + * CMD_WRITE_MEMORY + * + * The host issues this command to write the WiLink device memory/registers. + * + * The Base Band address has special handling (16 bits registers and + * addresses). For more information, see the hardware specification. + */ +#define MAX_READ_SIZE 256 + +struct cmd_read_write_memory { + struct wl12xx_cmd_header header; + + /* The address of the memory to read from or write to.*/ + u32 addr; + + /* The amount of data in bytes to read from or write to the WiLink + * device.*/ + u32 size; + + /* The actual value read from or written to the Wilink. The source + of this field is the Host in WRITE command or the Wilink in READ + command. */ + u8 value[MAX_READ_SIZE]; +}; + +#define CMDMBOX_HEADER_LEN 4 +#define CMDMBOX_INFO_ELEM_HEADER_LEN 4 + + +struct basic_scan_parameters { + u32 rx_config_options; + u32 rx_filter_options; + + /* + * Scan options: + * bit 0: When this bit is set, passive scan. + * bit 1: Band, when this bit is set we scan + * in the 5Ghz band. + * bit 2: voice mode, 0 for normal scan. + * bit 3: scan priority, 1 for high priority. + */ + u16 scan_options; + + /* Number of channels to scan */ + u8 num_channels; + + /* Number opf probe requests to send, per channel */ + u8 num_probe_requests; + + /* Rate and modulation for probe requests */ + u16 tx_rate; + + u8 tid_trigger; + u8 ssid_len; + u32 ssid[8]; + +} __attribute__ ((packed)); + +struct basic_scan_channel_parameters { + u32 min_duration; /* in TU */ + u32 max_duration; /* in TU */ + u32 bssid_lsb; + u16 bssid_msb; + + /* + * bits 0-3: Early termination count. + * bits 4-5: Early termination condition. + */ + u8 early_termination; + + u8 tx_power_att; + u8 channel; + u8 pad[3]; +} __attribute__ ((packed)); + +/* SCAN parameters */ +#define SCAN_MAX_NUM_OF_CHANNELS 16 + +struct cmd_scan { + struct wl12xx_cmd_header header; + + struct basic_scan_parameters params; + struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; +} __attribute__ ((packed)); + +enum { + BSS_TYPE_IBSS = 0, + BSS_TYPE_STA_BSS = 2, + BSS_TYPE_AP_BSS = 3, + MAX_BSS_TYPE = 0xFF +}; + +#define JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ +#define JOIN_CMD_CTRL_EARLY_WAKEUP_ENABLE 0x01 /* Early wakeup time */ + + +struct cmd_join { + struct wl12xx_cmd_header header; + + u32 bssid_lsb; + u16 bssid_msb; + u16 beacon_interval; /* in TBTTs */ + u32 rx_config_options; + u32 rx_filter_options; + + /* + * The target uses this field to determine the rate at + * which to transmit control frame responses (such as + * ACK or CTS frames). + */ + u16 basic_rate_set; + u8 dtim_interval; + u8 tx_ctrl_frame_rate; /* OBSOLETE */ + u8 tx_ctrl_frame_mod; /* OBSOLETE */ + /* + * bits 0-2: This bitwise field specifies the type + * of BSS to start or join (BSS_TYPE_*). + * bit 4: Band - The radio band in which to join + * or start. + * 0 - 2.4GHz band + * 1 - 5GHz band + * bits 3, 5-7: Reserved + */ + u8 bss_type; + u8 channel; + u8 ssid_len; + u8 ssid[IW_ESSID_MAX_SIZE]; + u8 ctrl; /* JOIN_CMD_CTRL_* */ + u8 tx_mgt_frame_rate; /* OBSOLETE */ + u8 tx_mgt_frame_mod; /* OBSOLETE */ + u8 reserved; +} __attribute__ ((packed)); + +struct cmd_enabledisable_path { + struct wl12xx_cmd_header header; + + u8 channel; + u8 padding[3]; +} __attribute__ ((packed)); + +#define WL12XX_MAX_TEMPLATE_SIZE 300 + +struct wl12xx_cmd_packet_template { + struct wl12xx_cmd_header header; + + __le16 size; + u8 data[0]; +} __attribute__ ((packed)); + +#define TIM_ELE_ID 5 +#define PARTIAL_VBM_MAX 251 + +struct wl12xx_tim { + u8 identity; + u8 length; + u8 dtim_count; + u8 dtim_period; + u8 bitmap_ctrl; + u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ +} __attribute__ ((packed)); + +/* Virtual Bit Map update */ +struct wl12xx_cmd_vbm_update { + struct wl12xx_cmd_header header; + __le16 len; + u8 padding[2]; + struct wl12xx_tim tim; +} __attribute__ ((packed)); + +enum wl12xx_cmd_ps_mode { + STATION_ACTIVE_MODE, + STATION_POWER_SAVE_MODE +}; + +struct wl12xx_cmd_ps_params { + struct wl12xx_cmd_header header; + + u8 ps_mode; /* STATION_* */ + u8 send_null_data; /* Do we have to send NULL data packet ? */ + u8 retries; /* Number of retires for the initial NULL data packet */ + + /* + * TUs during which the target stays awake after switching + * to power save mode. + */ + u8 hang_over_period; + u16 null_data_rate; + u8 pad[2]; +} __attribute__ ((packed)); + +struct wl12xx_cmd_trigger_scan_to { + struct wl12xx_cmd_header header; + + u32 timeout; +}; + +/* HW encryption keys */ +#define NUM_ACCESS_CATEGORIES_COPY 4 +#define MAX_KEY_SIZE 32 + +/* When set, disable HW encryption */ +#define DF_ENCRYPTION_DISABLE 0x01 +/* When set, disable HW decryption */ +#define DF_SNIFF_MODE_ENABLE 0x80 + +enum wl12xx_cmd_key_action { + KEY_ADD_OR_REPLACE = 1, + KEY_REMOVE = 2, + KEY_SET_ID = 3, + MAX_KEY_ACTION = 0xffff, +}; + +enum wl12xx_cmd_key_type { + KEY_WEP_DEFAULT = 0, + KEY_WEP_ADDR = 1, + KEY_AES_GROUP = 4, + KEY_AES_PAIRWISE = 5, + KEY_WEP_GROUP = 6, + KEY_TKIP_MIC_GROUP = 10, + KEY_TKIP_MIC_PAIRWISE = 11, +}; + +/* + * + * key_type_e key size key format + * ---------- --------- ---------- + * 0x00 5, 13, 29 Key data + * 0x01 5, 13, 29 Key data + * 0x04 16 16 bytes of key data + * 0x05 16 16 bytes of key data + * 0x0a 32 16 bytes of TKIP key data + * 8 bytes of RX MIC key data + * 8 bytes of TX MIC key data + * 0x0b 32 16 bytes of TKIP key data + * 8 bytes of RX MIC key data + * 8 bytes of TX MIC key data + * + */ + +struct wl12xx_cmd_set_keys { + struct wl12xx_cmd_header header; + + /* Ignored for default WEP key */ + u8 addr[ETH_ALEN]; + + /* key_action_e */ + u16 key_action; + + u16 reserved_1; + + /* key size in bytes */ + u8 key_size; + + /* key_type_e */ + u8 key_type; + u8 ssid_profile; + + /* + * TKIP, AES: frame's key id field. + * For WEP default key: key id; + */ + u8 id; + u8 reserved_2[6]; + u8 key[MAX_KEY_SIZE]; + u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; + u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; +} __attribute__ ((packed)); + + +#endif /* __WL12XX_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.c b/drivers/net/wireless/wl12xx/wl1251_debugfs.c new file mode 100644 index 00000000000..a63bc78bfbc --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.c @@ -0,0 +1,518 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl1251_debugfs.h" + +#include + +#include "wl12xx.h" +#include "wl1251_acx.h" +#include "wl1251_ps.h" + +/* ms */ +#define WL12XX_DEBUGFS_STATS_LIFETIME 1000 + +/* debugfs macros idea from mac80211 */ + +#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ +static ssize_t name## _read(struct file *file, char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + struct wl12xx *wl = file->private_data; \ + char buf[buflen]; \ + int res; \ + \ + res = scnprintf(buf, buflen, fmt "\n", ##value); \ + return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ +} \ + \ +static const struct file_operations name## _ops = { \ + .read = name## _read, \ + .open = wl12xx_open_file_generic, \ +}; + +#define DEBUGFS_ADD(name, parent) \ + wl->debugfs.name = debugfs_create_file(#name, 0400, parent, \ + wl, &name## _ops); \ + if (IS_ERR(wl->debugfs.name)) { \ + ret = PTR_ERR(wl->debugfs.name); \ + wl->debugfs.name = NULL; \ + goto out; \ + } + +#define DEBUGFS_DEL(name) \ + do { \ + debugfs_remove(wl->debugfs.name); \ + wl->debugfs.name = NULL; \ + } while (0) + +#define DEBUGFS_FWSTATS_FILE(sub, name, buflen, fmt) \ +static ssize_t sub## _ ##name## _read(struct file *file, \ + char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + struct wl12xx *wl = file->private_data; \ + char buf[buflen]; \ + int res; \ + \ + wl12xx_debugfs_update_stats(wl); \ + \ + res = scnprintf(buf, buflen, fmt "\n", \ + wl->stats.fw_stats->sub.name); \ + return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ +} \ + \ +static const struct file_operations sub## _ ##name## _ops = { \ + .read = sub## _ ##name## _read, \ + .open = wl12xx_open_file_generic, \ +}; + +#define DEBUGFS_FWSTATS_ADD(sub, name) \ + DEBUGFS_ADD(sub## _ ##name, wl->debugfs.fw_statistics) + +#define DEBUGFS_FWSTATS_DEL(sub, name) \ + DEBUGFS_DEL(sub## _ ##name) + +static void wl12xx_debugfs_update_stats(struct wl12xx *wl) +{ + int ret; + + mutex_lock(&wl->mutex); + + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + if (wl->state == WL12XX_STATE_ON && + time_after(jiffies, wl->stats.fw_stats_update + + msecs_to_jiffies(WL12XX_DEBUGFS_STATS_LIFETIME))) { + wl12xx_acx_statistics(wl, wl->stats.fw_stats); + wl->stats.fw_stats_update = jiffies; + } + + wl12xx_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +static int wl12xx_open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, hw_stuck, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, dropped, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, fcs_err, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, path_reset, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, reset_counter, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(dma, rx_requested, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, rx_errors, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, tx_requested, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, tx_errors, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, fiqs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_headers, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_rdys, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, irqs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, tx_procs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, decrypt_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, dma0_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, dma1_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, commands, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_procs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, pci_pm, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, wakeups, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, low_rssi, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(wep, addr_key_count, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, default_key_count, 20, "%u"); +/* skipping wep.reserved */ +DEBUGFS_FWSTATS_FILE(wep, key_not_found, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, interrupt, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(pwr, ps_enter, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, elp_enter, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, power_save_off, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, enable_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, disable_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, 20, "%u"); +/* skipping cont_miss_bcns_spread for now */ +DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(mic, rx_pkts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(mic, calc_failure, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(event, heart_beat, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, calibration, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_mismatch, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_pool, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, oom_late, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, tx_stuck, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, + 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, 20, "%u"); + +DEBUGFS_READONLY_FILE(retry_count, 20, "%u", wl->stats.retry_count); +DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u", + wl->stats.excessive_retries); + +static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct wl12xx *wl = file->private_data; + u32 queue_len; + char buf[20]; + int res; + + queue_len = skb_queue_len(&wl->tx_queue); + + res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); + return simple_read_from_buffer(userbuf, count, ppos, buf, res); +} + +static const struct file_operations tx_queue_len_ops = { + .read = tx_queue_len_read, + .open = wl12xx_open_file_generic, +}; + +static void wl12xx_debugfs_delete_files(struct wl12xx *wl) +{ + DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); + + DEBUGFS_FWSTATS_DEL(rx, out_of_mem); + DEBUGFS_FWSTATS_DEL(rx, hdr_overflow); + DEBUGFS_FWSTATS_DEL(rx, hw_stuck); + DEBUGFS_FWSTATS_DEL(rx, dropped); + DEBUGFS_FWSTATS_DEL(rx, fcs_err); + DEBUGFS_FWSTATS_DEL(rx, xfr_hint_trig); + DEBUGFS_FWSTATS_DEL(rx, path_reset); + DEBUGFS_FWSTATS_DEL(rx, reset_counter); + + DEBUGFS_FWSTATS_DEL(dma, rx_requested); + DEBUGFS_FWSTATS_DEL(dma, rx_errors); + DEBUGFS_FWSTATS_DEL(dma, tx_requested); + DEBUGFS_FWSTATS_DEL(dma, tx_errors); + + DEBUGFS_FWSTATS_DEL(isr, cmd_cmplt); + DEBUGFS_FWSTATS_DEL(isr, fiqs); + DEBUGFS_FWSTATS_DEL(isr, rx_headers); + DEBUGFS_FWSTATS_DEL(isr, rx_mem_overflow); + DEBUGFS_FWSTATS_DEL(isr, rx_rdys); + DEBUGFS_FWSTATS_DEL(isr, irqs); + DEBUGFS_FWSTATS_DEL(isr, tx_procs); + DEBUGFS_FWSTATS_DEL(isr, decrypt_done); + DEBUGFS_FWSTATS_DEL(isr, dma0_done); + DEBUGFS_FWSTATS_DEL(isr, dma1_done); + DEBUGFS_FWSTATS_DEL(isr, tx_exch_complete); + DEBUGFS_FWSTATS_DEL(isr, commands); + DEBUGFS_FWSTATS_DEL(isr, rx_procs); + DEBUGFS_FWSTATS_DEL(isr, hw_pm_mode_changes); + DEBUGFS_FWSTATS_DEL(isr, host_acknowledges); + DEBUGFS_FWSTATS_DEL(isr, pci_pm); + DEBUGFS_FWSTATS_DEL(isr, wakeups); + DEBUGFS_FWSTATS_DEL(isr, low_rssi); + + DEBUGFS_FWSTATS_DEL(wep, addr_key_count); + DEBUGFS_FWSTATS_DEL(wep, default_key_count); + /* skipping wep.reserved */ + DEBUGFS_FWSTATS_DEL(wep, key_not_found); + DEBUGFS_FWSTATS_DEL(wep, decrypt_fail); + DEBUGFS_FWSTATS_DEL(wep, packets); + DEBUGFS_FWSTATS_DEL(wep, interrupt); + + DEBUGFS_FWSTATS_DEL(pwr, ps_enter); + DEBUGFS_FWSTATS_DEL(pwr, elp_enter); + DEBUGFS_FWSTATS_DEL(pwr, missing_bcns); + DEBUGFS_FWSTATS_DEL(pwr, wake_on_host); + DEBUGFS_FWSTATS_DEL(pwr, wake_on_timer_exp); + DEBUGFS_FWSTATS_DEL(pwr, tx_with_ps); + DEBUGFS_FWSTATS_DEL(pwr, tx_without_ps); + DEBUGFS_FWSTATS_DEL(pwr, rcvd_beacons); + DEBUGFS_FWSTATS_DEL(pwr, power_save_off); + DEBUGFS_FWSTATS_DEL(pwr, enable_ps); + DEBUGFS_FWSTATS_DEL(pwr, disable_ps); + DEBUGFS_FWSTATS_DEL(pwr, fix_tsf_ps); + /* skipping cont_miss_bcns_spread for now */ + DEBUGFS_FWSTATS_DEL(pwr, rcvd_awake_beacons); + + DEBUGFS_FWSTATS_DEL(mic, rx_pkts); + DEBUGFS_FWSTATS_DEL(mic, calc_failure); + + DEBUGFS_FWSTATS_DEL(aes, encrypt_fail); + DEBUGFS_FWSTATS_DEL(aes, decrypt_fail); + DEBUGFS_FWSTATS_DEL(aes, encrypt_packets); + DEBUGFS_FWSTATS_DEL(aes, decrypt_packets); + DEBUGFS_FWSTATS_DEL(aes, encrypt_interrupt); + DEBUGFS_FWSTATS_DEL(aes, decrypt_interrupt); + + DEBUGFS_FWSTATS_DEL(event, heart_beat); + DEBUGFS_FWSTATS_DEL(event, calibration); + DEBUGFS_FWSTATS_DEL(event, rx_mismatch); + DEBUGFS_FWSTATS_DEL(event, rx_mem_empty); + DEBUGFS_FWSTATS_DEL(event, rx_pool); + DEBUGFS_FWSTATS_DEL(event, oom_late); + DEBUGFS_FWSTATS_DEL(event, phy_transmit_error); + DEBUGFS_FWSTATS_DEL(event, tx_stuck); + + DEBUGFS_FWSTATS_DEL(ps, pspoll_timeouts); + DEBUGFS_FWSTATS_DEL(ps, upsd_timeouts); + DEBUGFS_FWSTATS_DEL(ps, upsd_max_sptime); + DEBUGFS_FWSTATS_DEL(ps, upsd_max_apturn); + DEBUGFS_FWSTATS_DEL(ps, pspoll_max_apturn); + DEBUGFS_FWSTATS_DEL(ps, pspoll_utilization); + DEBUGFS_FWSTATS_DEL(ps, upsd_utilization); + + DEBUGFS_FWSTATS_DEL(rxpipe, rx_prep_beacon_drop); + DEBUGFS_FWSTATS_DEL(rxpipe, descr_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, missed_beacon_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data); + + DEBUGFS_DEL(tx_queue_len); + DEBUGFS_DEL(retry_count); + DEBUGFS_DEL(excessive_retries); +} + +static int wl12xx_debugfs_add_files(struct wl12xx *wl) +{ + int ret = 0; + + DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow); + + DEBUGFS_FWSTATS_ADD(rx, out_of_mem); + DEBUGFS_FWSTATS_ADD(rx, hdr_overflow); + DEBUGFS_FWSTATS_ADD(rx, hw_stuck); + DEBUGFS_FWSTATS_ADD(rx, dropped); + DEBUGFS_FWSTATS_ADD(rx, fcs_err); + DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig); + DEBUGFS_FWSTATS_ADD(rx, path_reset); + DEBUGFS_FWSTATS_ADD(rx, reset_counter); + + DEBUGFS_FWSTATS_ADD(dma, rx_requested); + DEBUGFS_FWSTATS_ADD(dma, rx_errors); + DEBUGFS_FWSTATS_ADD(dma, tx_requested); + DEBUGFS_FWSTATS_ADD(dma, tx_errors); + + DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt); + DEBUGFS_FWSTATS_ADD(isr, fiqs); + DEBUGFS_FWSTATS_ADD(isr, rx_headers); + DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow); + DEBUGFS_FWSTATS_ADD(isr, rx_rdys); + DEBUGFS_FWSTATS_ADD(isr, irqs); + DEBUGFS_FWSTATS_ADD(isr, tx_procs); + DEBUGFS_FWSTATS_ADD(isr, decrypt_done); + DEBUGFS_FWSTATS_ADD(isr, dma0_done); + DEBUGFS_FWSTATS_ADD(isr, dma1_done); + DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete); + DEBUGFS_FWSTATS_ADD(isr, commands); + DEBUGFS_FWSTATS_ADD(isr, rx_procs); + DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes); + DEBUGFS_FWSTATS_ADD(isr, host_acknowledges); + DEBUGFS_FWSTATS_ADD(isr, pci_pm); + DEBUGFS_FWSTATS_ADD(isr, wakeups); + DEBUGFS_FWSTATS_ADD(isr, low_rssi); + + DEBUGFS_FWSTATS_ADD(wep, addr_key_count); + DEBUGFS_FWSTATS_ADD(wep, default_key_count); + /* skipping wep.reserved */ + DEBUGFS_FWSTATS_ADD(wep, key_not_found); + DEBUGFS_FWSTATS_ADD(wep, decrypt_fail); + DEBUGFS_FWSTATS_ADD(wep, packets); + DEBUGFS_FWSTATS_ADD(wep, interrupt); + + DEBUGFS_FWSTATS_ADD(pwr, ps_enter); + DEBUGFS_FWSTATS_ADD(pwr, elp_enter); + DEBUGFS_FWSTATS_ADD(pwr, missing_bcns); + DEBUGFS_FWSTATS_ADD(pwr, wake_on_host); + DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp); + DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps); + DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps); + DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons); + DEBUGFS_FWSTATS_ADD(pwr, power_save_off); + DEBUGFS_FWSTATS_ADD(pwr, enable_ps); + DEBUGFS_FWSTATS_ADD(pwr, disable_ps); + DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps); + /* skipping cont_miss_bcns_spread for now */ + DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons); + + DEBUGFS_FWSTATS_ADD(mic, rx_pkts); + DEBUGFS_FWSTATS_ADD(mic, calc_failure); + + DEBUGFS_FWSTATS_ADD(aes, encrypt_fail); + DEBUGFS_FWSTATS_ADD(aes, decrypt_fail); + DEBUGFS_FWSTATS_ADD(aes, encrypt_packets); + DEBUGFS_FWSTATS_ADD(aes, decrypt_packets); + DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt); + DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt); + + DEBUGFS_FWSTATS_ADD(event, heart_beat); + DEBUGFS_FWSTATS_ADD(event, calibration); + DEBUGFS_FWSTATS_ADD(event, rx_mismatch); + DEBUGFS_FWSTATS_ADD(event, rx_mem_empty); + DEBUGFS_FWSTATS_ADD(event, rx_pool); + DEBUGFS_FWSTATS_ADD(event, oom_late); + DEBUGFS_FWSTATS_ADD(event, phy_transmit_error); + DEBUGFS_FWSTATS_ADD(event, tx_stuck); + + DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts); + DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts); + DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime); + DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn); + DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn); + DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization); + DEBUGFS_FWSTATS_ADD(ps, upsd_utilization); + + DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop); + DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); + + DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir); + DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); + DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); + +out: + if (ret < 0) + wl12xx_debugfs_delete_files(wl); + + return ret; +} + +void wl12xx_debugfs_reset(struct wl12xx *wl) +{ + memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); + wl->stats.retry_count = 0; + wl->stats.excessive_retries = 0; +} + +int wl12xx_debugfs_init(struct wl12xx *wl) +{ + int ret; + + wl->debugfs.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); + + if (IS_ERR(wl->debugfs.rootdir)) { + ret = PTR_ERR(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + goto err; + } + + wl->debugfs.fw_statistics = debugfs_create_dir("fw-statistics", + wl->debugfs.rootdir); + + if (IS_ERR(wl->debugfs.fw_statistics)) { + ret = PTR_ERR(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + goto err_root; + } + + wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats), + GFP_KERNEL); + + if (!wl->stats.fw_stats) { + ret = -ENOMEM; + goto err_fw; + } + + wl->stats.fw_stats_update = jiffies; + + ret = wl12xx_debugfs_add_files(wl); + + if (ret < 0) + goto err_file; + + return 0; + +err_file: + kfree(wl->stats.fw_stats); + wl->stats.fw_stats = NULL; + +err_fw: + debugfs_remove(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + +err_root: + debugfs_remove(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + +err: + return ret; +} + +void wl12xx_debugfs_exit(struct wl12xx *wl) +{ + wl12xx_debugfs_delete_files(wl); + + kfree(wl->stats.fw_stats); + wl->stats.fw_stats = NULL; + + debugfs_remove(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + + debugfs_remove(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + +} diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.h b/drivers/net/wireless/wl12xx/wl1251_debugfs.h new file mode 100644 index 00000000000..562cdcbcc87 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.h @@ -0,0 +1,33 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef WL12XX_DEBUGFS_H +#define WL12XX_DEBUGFS_H + +#include "wl12xx.h" + +int wl12xx_debugfs_init(struct wl12xx *wl); +void wl12xx_debugfs_exit(struct wl12xx *wl); +void wl12xx_debugfs_reset(struct wl12xx *wl); + +#endif /* WL12XX_DEBUGFS_H */ diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl12xx/wl1251_event.c new file mode 100644 index 00000000000..50b5e43d8f3 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_event.c @@ -0,0 +1,127 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl12xx.h" +#include "reg.h" +#include "wl1251_spi.h" +#include "wl1251_event.h" +#include "wl1251_ps.h" + +static int wl12xx_event_scan_complete(struct wl12xx *wl, + struct event_mailbox *mbox) +{ + wl12xx_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", + mbox->scheduled_scan_status, + mbox->scheduled_scan_channels); + + if (wl->scanning) { + mutex_unlock(&wl->mutex); + ieee80211_scan_completed(wl->hw, false); + mutex_lock(&wl->mutex); + wl->scanning = false; + } + + return 0; +} + +static void wl12xx_event_mbox_dump(struct event_mailbox *mbox) +{ + wl12xx_debug(DEBUG_EVENT, "MBOX DUMP:"); + wl12xx_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); + wl12xx_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); +} + +static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox) +{ + int ret; + u32 vector; + + wl12xx_event_mbox_dump(mbox); + + vector = mbox->events_vector & ~(mbox->events_mask); + wl12xx_debug(DEBUG_EVENT, "vector: 0x%x", vector); + + if (vector & SCAN_COMPLETE_EVENT_ID) { + ret = wl12xx_event_scan_complete(wl, mbox); + if (ret < 0) + return ret; + } + + if (vector & BSS_LOSE_EVENT_ID) { + wl12xx_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); + + if (wl->psm_requested && wl->psm) { + ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + return ret; + } + } + + return 0; +} + +int wl12xx_event_unmask(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_event_mbox_mask(wl, ~(wl->event_mask)); + if (ret < 0) + return ret; + + return 0; +} + +void wl12xx_event_mbox_config(struct wl12xx *wl) +{ + wl->mbox_ptr[0] = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR); + wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); + + wl12xx_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", + wl->mbox_ptr[0], wl->mbox_ptr[1]); +} + +int wl12xx_event_handle(struct wl12xx *wl, u8 mbox_num) +{ + struct event_mailbox mbox; + int ret; + + wl12xx_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); + + if (mbox_num > 1) + return -EINVAL; + + /* first we read the mbox descriptor */ + wl12xx_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, + sizeof(struct event_mailbox)); + + /* process the descriptor */ + ret = wl12xx_event_process(wl, &mbox); + if (ret < 0) + return ret; + + /* then we let the firmware know it can go on...*/ + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); + + return 0; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_event.h b/drivers/net/wireless/wl12xx/wl1251_event.h new file mode 100644 index 00000000000..1f4c2f7438a --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_event.h @@ -0,0 +1,121 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_EVENT_H__ +#define __WL12XX_EVENT_H__ + +/* + * Mbox events + * + * The event mechanism is based on a pair of event buffers (buffers A and + * B) at fixed locations in the target's memory. The host processes one + * buffer while the other buffer continues to collect events. If the host + * is not processing events, an interrupt is issued to signal that a buffer + * is ready. Once the host is done with processing events from one buffer, + * it signals the target (with an ACK interrupt) that the event buffer is + * free. + */ + +enum { + RESERVED1_EVENT_ID = BIT(0), + RESERVED2_EVENT_ID = BIT(1), + MEASUREMENT_START_EVENT_ID = BIT(2), + SCAN_COMPLETE_EVENT_ID = BIT(3), + CALIBRATION_COMPLETE_EVENT_ID = BIT(4), + ROAMING_TRIGGER_LOW_RSSI_EVENT_ID = BIT(5), + PS_REPORT_EVENT_ID = BIT(6), + SYNCHRONIZATION_TIMEOUT_EVENT_ID = BIT(7), + HEALTH_REPORT_EVENT_ID = BIT(8), + ACI_DETECTION_EVENT_ID = BIT(9), + DEBUG_REPORT_EVENT_ID = BIT(10), + MAC_STATUS_EVENT_ID = BIT(11), + DISCONNECT_EVENT_COMPLETE_ID = BIT(12), + JOIN_EVENT_COMPLETE_ID = BIT(13), + CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(14), + BSS_LOSE_EVENT_ID = BIT(15), + ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(16), + MEASUREMENT_COMPLETE_EVENT_ID = BIT(17), + AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(18), + SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(19), + PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(20), + RESET_BSS_EVENT_ID = BIT(21), + REGAINED_BSS_EVENT_ID = BIT(22), + ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID = BIT(23), + ROAMING_TRIGGER_LOW_SNR_EVENT_ID = BIT(24), + ROAMING_TRIGGER_REGAINED_SNR_EVENT_ID = BIT(25), + + DBG_EVENT_ID = BIT(26), + BT_PTA_SENSE_EVENT_ID = BIT(27), + BT_PTA_PREDICTION_EVENT_ID = BIT(28), + BT_PTA_AVALANCHE_EVENT_ID = BIT(29), + + PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(30), + + EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, +}; + +struct event_debug_report { + u8 debug_event_id; + u8 num_params; + u16 pad; + u32 report_1; + u32 report_2; + u32 report_3; +} __attribute__ ((packed)); + +struct event_mailbox { + u32 events_vector; + u32 events_mask; + u32 reserved_1; + u32 reserved_2; + + char average_rssi_level; + u8 ps_status; + u8 channel_switch_status; + u8 scheduled_scan_status; + + /* Channels scanned by the scheduled scan */ + u16 scheduled_scan_channels; + + /* If bit 0 is set -> target's fatal error */ + u16 health_report; + u16 bad_fft_counter; + u8 bt_pta_sense_info; + u8 bt_pta_protective_info; + u32 reserved; + u32 debug_report[2]; + + /* Number of FCS errors since last event */ + u32 fcs_err_counter; + + struct event_debug_report report; + u8 average_snr_level; + u8 padding[19]; +} __attribute__ ((packed)); + +int wl12xx_event_unmask(struct wl12xx *wl); +void wl12xx_event_mbox_config(struct wl12xx *wl); +int wl12xx_event_handle(struct wl12xx *wl, u8 mbox); + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c new file mode 100644 index 00000000000..0929461a6d3 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_init.c @@ -0,0 +1,200 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "wl1251_init.h" +#include "wl12xx_80211.h" +#include "wl1251_acx.h" +#include "wl1251_cmd.h" + +int wl12xx_hw_init_hwenc_config(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_feature_cfg(wl); + if (ret < 0) { + wl12xx_warning("couldn't set feature config"); + return ret; + } + + ret = wl12xx_acx_default_key(wl, wl->default_key); + if (ret < 0) { + wl12xx_warning("couldn't set default key"); + return ret; + } + + return 0; +} + +int wl12xx_hw_init_templates_config(struct wl12xx *wl) +{ + int ret; + u8 partial_vbm[PARTIAL_VBM_MAX]; + + /* send empty templates for fw memory reservation */ + ret = wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, NULL, + sizeof(struct wl12xx_probe_req_template)); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_template_set(wl, CMD_NULL_DATA, NULL, + sizeof(struct wl12xx_null_data_template)); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_template_set(wl, CMD_PS_POLL, NULL, + sizeof(struct wl12xx_ps_poll_template)); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL, + sizeof + (struct wl12xx_qos_null_data_template)); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, NULL, + sizeof + (struct wl12xx_probe_resp_template)); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_template_set(wl, CMD_BEACON, NULL, + sizeof + (struct wl12xx_beacon_template)); + if (ret < 0) + return ret; + + /* tim templates, first reserve space then allocate an empty one */ + memset(partial_vbm, 0, PARTIAL_VBM_MAX); + ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter) +{ + int ret; + + ret = wl12xx_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); + if (ret < 0) + return ret; + + ret = wl12xx_acx_rx_config(wl, config, filter); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_phy_config(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_pd_threshold(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_slot(wl, DEFAULT_SLOT_TIME); + if (ret < 0) + return ret; + + ret = wl12xx_acx_group_address_tbl(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_service_period_timeout(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_beacon_filter(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_beacon_filter_opt(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_beacon_filter_table(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_pta(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_sg_enable(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_sg_cfg(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_energy_detection(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_cca_threshold(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_bcn_dtim_options(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_power_auth(struct wl12xx *wl) +{ + return wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM); +} diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl12xx/wl1251_init.h new file mode 100644 index 00000000000..c8b6cd0b7c3 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_init.h @@ -0,0 +1,40 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_INIT_H__ +#define __WL12XX_INIT_H__ + +#include "wl12xx.h" + +int wl12xx_hw_init_hwenc_config(struct wl12xx *wl); +int wl12xx_hw_init_templates_config(struct wl12xx *wl); +int wl12xx_hw_init_mem_config(struct wl12xx *wl); +int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter); +int wl12xx_hw_init_phy_config(struct wl12xx *wl); +int wl12xx_hw_init_beacon_filter(struct wl12xx *wl); +int wl12xx_hw_init_pta(struct wl12xx *wl); +int wl12xx_hw_init_energy_detection(struct wl12xx *wl); +int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl); +int wl12xx_hw_init_power_auth(struct wl12xx *wl); + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c new file mode 100644 index 00000000000..16cd46c7164 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -0,0 +1,1442 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wl12xx.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "wl1251_ops.h" +#include "wl1251_spi.h" +#include "wl1251_event.h" +#include "wl1251_tx.h" +#include "wl1251_rx.h" +#include "wl1251_ps.h" +#include "wl1251_init.h" +#include "wl1251_debugfs.h" + +static void wl12xx_disable_interrupts(struct wl12xx *wl) +{ + disable_irq(wl->irq); +} + +static void wl12xx_power_off(struct wl12xx *wl) +{ + wl->set_power(false); +} + +static void wl12xx_power_on(struct wl12xx *wl) +{ + wl->set_power(true); +} + +static irqreturn_t wl12xx_irq(int irq, void *cookie) +{ + struct wl12xx *wl; + + wl12xx_debug(DEBUG_IRQ, "IRQ"); + + wl = cookie; + + schedule_work(&wl->irq_work); + + return IRQ_HANDLED; +} + +static int wl12xx_fetch_firmware(struct wl12xx *wl) +{ + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, wl->chip.fw_filename, &wl->spi->dev); + + if (ret < 0) { + wl12xx_error("could not get firmware: %d", ret); + return ret; + } + + if (fw->size % 4) { + wl12xx_error("firmware size is not multiple of 32 bits: %zu", + fw->size); + ret = -EILSEQ; + goto out; + } + + wl->fw_len = fw->size; + wl->fw = kmalloc(wl->fw_len, GFP_KERNEL); + + if (!wl->fw) { + wl12xx_error("could not allocate memory for the firmware"); + ret = -ENOMEM; + goto out; + } + + memcpy(wl->fw, fw->data, wl->fw_len); + + ret = 0; + +out: + release_firmware(fw); + + return ret; +} + +static int wl12xx_fetch_nvs(struct wl12xx *wl) +{ + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, wl->chip.nvs_filename, &wl->spi->dev); + + if (ret < 0) { + wl12xx_error("could not get nvs file: %d", ret); + return ret; + } + + if (fw->size % 4) { + wl12xx_error("nvs size is not multiple of 32 bits: %zu", + fw->size); + ret = -EILSEQ; + goto out; + } + + wl->nvs_len = fw->size; + wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL); + + if (!wl->nvs) { + wl12xx_error("could not allocate memory for the nvs file"); + ret = -ENOMEM; + goto out; + } + + memcpy(wl->nvs, fw->data, wl->nvs_len); + + ret = 0; + +out: + release_firmware(fw); + + return ret; +} + +static void wl12xx_fw_wakeup(struct wl12xx *wl) +{ + u32 elp_reg; + + elp_reg = ELPCTRL_WAKE_UP; + wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); + elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + + if (!(elp_reg & ELPCTRL_WLAN_READY)) { + wl12xx_warning("WLAN not ready"); + } +} + +static int wl12xx_chip_wakeup(struct wl12xx *wl) +{ + int ret = 0; + + wl12xx_power_on(wl); + msleep(wl->chip.power_on_sleep); + wl12xx_spi_reset(wl); + wl12xx_spi_init(wl); + + /* We don't need a real memory partition here, because we only want + * to use the registers at this point. */ + wl12xx_set_partition(wl, + 0x00000000, + 0x00000000, + REGISTERS_BASE, + REGISTERS_DOWN_SIZE); + + /* ELP module wake up */ + wl12xx_fw_wakeup(wl); + + /* whal_FwCtrl_BootSm() */ + + /* 0. read chip id from CHIP_ID */ + wl->chip.id = wl12xx_reg_read32(wl, CHIP_ID_B); + + /* 1. check if chip id is valid */ + + switch (wl->chip.id) { + case CHIP_ID_1251_PG12: + wl12xx_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", + wl->chip.id); + + wl1251_setup(wl); + + break; + case CHIP_ID_1251_PG10: + case CHIP_ID_1251_PG11: + default: + wl12xx_error("unsupported chip id: 0x%x", wl->chip.id); + ret = -ENODEV; + goto out; + } + + if (wl->fw == NULL) { + ret = wl12xx_fetch_firmware(wl); + if (ret < 0) + goto out; + } + + /* No NVS from netlink, try to get it from the filesystem */ + if (wl->nvs == NULL) { + ret = wl12xx_fetch_nvs(wl); + if (ret < 0) + goto out; + } + +out: + return ret; +} + +static void wl12xx_filter_work(struct work_struct *work) +{ + struct wl12xx *wl = + container_of(work, struct wl12xx, filter_work); + int ret; + + mutex_lock(&wl->mutex); + + if (wl->state == WL12XX_STATE_OFF) + goto out; + + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + /* FIXME: replace the magic numbers with proper definitions */ + ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); + if (ret < 0) + goto out_sleep; + +out_sleep: + wl12xx_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +int wl12xx_plt_start(struct wl12xx *wl) +{ + int ret; + + wl12xx_notice("power up"); + + if (wl->state != WL12XX_STATE_OFF) { + wl12xx_error("cannot go into PLT state because not " + "in off state: %d", wl->state); + return -EBUSY; + } + + wl->state = WL12XX_STATE_PLT; + + ret = wl12xx_chip_wakeup(wl); + if (ret < 0) + return ret; + + ret = wl->chip.op_boot(wl); + if (ret < 0) + return ret; + + wl12xx_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); + + ret = wl->chip.op_plt_init(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_plt_stop(struct wl12xx *wl) +{ + wl12xx_notice("power down"); + + if (wl->state != WL12XX_STATE_PLT) { + wl12xx_error("cannot power down because not in PLT " + "state: %d", wl->state); + return -EBUSY; + } + + wl12xx_disable_interrupts(wl); + wl12xx_power_off(wl); + + wl->state = WL12XX_STATE_OFF; + + return 0; +} + + +static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct wl12xx *wl = hw->priv; + + skb_queue_tail(&wl->tx_queue, skb); + + /* + * The chip specific setup must run before the first TX packet - + * before that, the tx_work will not be initialized! + */ + + schedule_work(&wl->tx_work); + + /* + * The workqueue is slow to process the tx_queue and we need stop + * the queue here, otherwise the queue will get too long. + */ + if (skb_queue_len(&wl->tx_queue) >= WL12XX_TX_QUEUE_MAX_LENGTH) { + ieee80211_stop_queues(wl->hw); + + /* + * FIXME: this is racy, the variable is not properly + * protected. Maybe fix this by removing the stupid + * variable altogether and checking the real queue state? + */ + wl->tx_queue_stopped = true; + } + + return NETDEV_TX_OK; +} + +static int wl12xx_op_start(struct ieee80211_hw *hw) +{ + struct wl12xx *wl = hw->priv; + int ret = 0; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 start"); + + mutex_lock(&wl->mutex); + + if (wl->state != WL12XX_STATE_OFF) { + wl12xx_error("cannot start because not in off state: %d", + wl->state); + ret = -EBUSY; + goto out; + } + + ret = wl12xx_chip_wakeup(wl); + if (ret < 0) + return ret; + + ret = wl->chip.op_boot(wl); + if (ret < 0) + goto out; + + ret = wl->chip.op_hw_init(wl); + if (ret < 0) + goto out; + + ret = wl12xx_acx_station_id(wl); + if (ret < 0) + goto out; + + wl->state = WL12XX_STATE_ON; + + wl12xx_info("firmware booted (%s)", wl->chip.fw_ver); + +out: + if (ret < 0) + wl12xx_power_off(wl); + + mutex_unlock(&wl->mutex); + + return ret; +} + +static void wl12xx_op_stop(struct ieee80211_hw *hw) +{ + struct wl12xx *wl = hw->priv; + + wl12xx_info("down"); + + wl12xx_debug(DEBUG_MAC80211, "mac80211 stop"); + + mutex_lock(&wl->mutex); + + WARN_ON(wl->state != WL12XX_STATE_ON); + + if (wl->scanning) { + mutex_unlock(&wl->mutex); + ieee80211_scan_completed(wl->hw, true); + mutex_lock(&wl->mutex); + wl->scanning = false; + } + + wl->state = WL12XX_STATE_OFF; + + wl12xx_disable_interrupts(wl); + + mutex_unlock(&wl->mutex); + + cancel_work_sync(&wl->irq_work); + cancel_work_sync(&wl->tx_work); + cancel_work_sync(&wl->filter_work); + + mutex_lock(&wl->mutex); + + /* let's notify MAC80211 about the remaining pending TX frames */ + wl->chip.op_tx_flush(wl); + wl12xx_power_off(wl); + + memset(wl->bssid, 0, ETH_ALEN); + wl->listen_int = 1; + wl->bss_type = MAX_BSS_TYPE; + + wl->data_in_count = 0; + wl->rx_counter = 0; + wl->rx_handled = 0; + wl->rx_current_buffer = 0; + wl->rx_last_id = 0; + wl->next_tx_complete = 0; + wl->elp = false; + wl->psm = 0; + wl->tx_queue_stopped = false; + wl->power_level = WL12XX_DEFAULT_POWER_LEVEL; + + wl12xx_debugfs_reset(wl); + + mutex_unlock(&wl->mutex); +} + +static int wl12xx_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct wl12xx *wl = hw->priv; + DECLARE_MAC_BUF(mac); + int ret = 0; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", + conf->type, print_mac(mac, conf->mac_addr)); + + mutex_lock(&wl->mutex); + + switch (conf->type) { + case NL80211_IFTYPE_STATION: + wl->bss_type = BSS_TYPE_STA_BSS; + break; + case NL80211_IFTYPE_ADHOC: + wl->bss_type = BSS_TYPE_IBSS; + break; + default: + ret = -EOPNOTSUPP; + goto out; + } + + if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) { + memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); + SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); + ret = wl12xx_acx_station_id(wl); + if (ret < 0) + goto out; + } + +out: + mutex_unlock(&wl->mutex); + return ret; +} + +static void wl12xx_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + wl12xx_debug(DEBUG_MAC80211, "mac80211 remove interface"); +} + +static int wl12xx_build_null_data(struct wl12xx *wl) +{ + struct wl12xx_null_data_template template; + + if (!is_zero_ether_addr(wl->bssid)) { + memcpy(template.header.da, wl->bssid, ETH_ALEN); + memcpy(template.header.bssid, wl->bssid, ETH_ALEN); + } else { + memset(template.header.da, 0xff, ETH_ALEN); + memset(template.header.bssid, 0xff, ETH_ALEN); + } + + memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); + template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_NULLFUNC); + + return wl12xx_cmd_template_set(wl, CMD_NULL_DATA, &template, + sizeof(template)); + +} + +static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid) +{ + struct wl12xx_ps_poll_template template; + + memcpy(template.bssid, wl->bssid, ETH_ALEN); + memcpy(template.ta, wl->mac_addr, ETH_ALEN); + template.aid = aid; + template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); + + return wl12xx_cmd_template_set(wl, CMD_PS_POLL, &template, + sizeof(template)); + +} + +static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) +{ + struct wl12xx *wl = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + int channel, ret = 0; + + channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + + wl12xx_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", + channel, + conf->flags & IEEE80211_CONF_PS ? "on" : "off", + conf->power_level); + + mutex_lock(&wl->mutex); + + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + if (channel != wl->channel) { + /* FIXME: use beacon interval provided by mac80211 */ + ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); + if (ret < 0) + goto out_sleep; + + wl->channel = channel; + } + + ret = wl12xx_build_null_data(wl); + if (ret < 0) + goto out_sleep; + + if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { + wl12xx_info("psm enabled"); + + wl->psm_requested = true; + + /* + * We enter PSM only if we're already associated. + * If we're not, we'll enter it when joining an SSID, + * through the bss_info_changed() hook. + */ + ret = wl12xx_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + } else if (!(conf->flags & IEEE80211_CONF_PS) && + wl->psm_requested) { + wl12xx_info("psm disabled"); + + wl->psm_requested = false; + + if (wl->psm) + ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE); + } + + if (conf->power_level != wl->power_level) { + ret = wl12xx_acx_tx_power(wl, conf->power_level); + if (ret < 0) + goto out; + + wl->power_level = conf->power_level; + } + +out_sleep: + wl12xx_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +#define WL12XX_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ + FIF_ALLMULTI | \ + FIF_FCSFAIL | \ + FIF_BCN_PRBRESP_PROMISC | \ + FIF_CONTROL | \ + FIF_OTHER_BSS) + +static void wl12xx_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, + unsigned int *total, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct wl12xx *wl = hw->priv; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 configure filter"); + + *total &= WL12XX_SUPPORTED_FILTERS; + changed &= WL12XX_SUPPORTED_FILTERS; + + if (changed == 0) + /* no filters which we support changed */ + return; + + /* FIXME: wl->rx_config and wl->rx_filter are not protected */ + + wl->rx_config = WL12XX_DEFAULT_RX_CONFIG; + wl->rx_filter = WL12XX_DEFAULT_RX_FILTER; + + if (*total & FIF_PROMISC_IN_BSS) { + wl->rx_config |= CFG_BSSID_FILTER_EN; + wl->rx_config |= CFG_RX_ALL_GOOD; + } + if (*total & FIF_ALLMULTI) + /* + * CFG_MC_FILTER_EN in rx_config needs to be 0 to receive + * all multicast frames + */ + wl->rx_config &= ~CFG_MC_FILTER_EN; + if (*total & FIF_FCSFAIL) + wl->rx_filter |= CFG_RX_FCS_ERROR; + if (*total & FIF_BCN_PRBRESP_PROMISC) { + wl->rx_config &= ~CFG_BSSID_FILTER_EN; + wl->rx_config &= ~CFG_SSID_FILTER_EN; + } + if (*total & FIF_CONTROL) + wl->rx_filter |= CFG_RX_CTL_EN; + if (*total & FIF_OTHER_BSS) + wl->rx_filter &= ~CFG_BSSID_FILTER_EN; + + /* + * FIXME: workqueues need to be properly cancelled on stop(), for + * now let's just disable changing the filter settings. They will + * be updated any on config(). + */ + /* schedule_work(&wl->filter_work); */ +} + +/* HW encryption */ +static int wl12xx_set_key_type(struct wl12xx *wl, + struct wl12xx_cmd_set_keys *key, + enum set_key_cmd cmd, + struct ieee80211_key_conf *mac80211_key, + const u8 *addr) +{ + switch (mac80211_key->alg) { + case ALG_WEP: + if (is_broadcast_ether_addr(addr)) + key->key_type = KEY_WEP_DEFAULT; + else + key->key_type = KEY_WEP_ADDR; + + mac80211_key->hw_key_idx = mac80211_key->keyidx; + break; + case ALG_TKIP: + if (is_broadcast_ether_addr(addr)) + key->key_type = KEY_TKIP_MIC_GROUP; + else + key->key_type = KEY_TKIP_MIC_PAIRWISE; + + mac80211_key->hw_key_idx = mac80211_key->keyidx; + break; + case ALG_CCMP: + if (is_broadcast_ether_addr(addr)) + key->key_type = KEY_AES_GROUP; + else + key->key_type = KEY_AES_PAIRWISE; + mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + break; + default: + wl12xx_error("Unknown key algo 0x%x", mac80211_key->alg); + return -EOPNOTSUPP; + } + + return 0; +} + +static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct wl12xx *wl = hw->priv; + struct wl12xx_cmd_set_keys *wl_cmd; + const u8 *addr; + int ret; + + static const u8 bcast_addr[ETH_ALEN] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 set key"); + + wl_cmd = kzalloc(sizeof(*wl_cmd), GFP_KERNEL); + if (!wl_cmd) { + ret = -ENOMEM; + goto out; + } + + addr = sta ? sta->addr : bcast_addr; + + wl12xx_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); + wl12xx_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); + wl12xx_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", + key->alg, key->keyidx, key->keylen, key->flags); + wl12xx_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen); + + if (is_zero_ether_addr(addr)) { + /* We dont support TX only encryption */ + ret = -EOPNOTSUPP; + goto out; + } + + mutex_lock(&wl->mutex); + + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out_unlock; + + switch (cmd) { + case SET_KEY: + wl_cmd->key_action = KEY_ADD_OR_REPLACE; + break; + case DISABLE_KEY: + wl_cmd->key_action = KEY_REMOVE; + break; + default: + wl12xx_error("Unsupported key cmd 0x%x", cmd); + break; + } + + ret = wl12xx_set_key_type(wl, wl_cmd, cmd, key, addr); + if (ret < 0) { + wl12xx_error("Set KEY type failed"); + goto out_sleep; + } + + if (wl_cmd->key_type != KEY_WEP_DEFAULT) + memcpy(wl_cmd->addr, addr, ETH_ALEN); + + if ((wl_cmd->key_type == KEY_TKIP_MIC_GROUP) || + (wl_cmd->key_type == KEY_TKIP_MIC_PAIRWISE)) { + /* + * We get the key in the following form: + * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) + * but the target is expecting: + * TKIP - RX MIC - TX MIC + */ + memcpy(wl_cmd->key, key->key, 16); + memcpy(wl_cmd->key + 16, key->key + 24, 8); + memcpy(wl_cmd->key + 24, key->key + 16, 8); + + } else { + memcpy(wl_cmd->key, key->key, key->keylen); + } + wl_cmd->key_size = key->keylen; + + wl_cmd->id = key->keyidx; + wl_cmd->ssid_profile = 0; + + wl12xx_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd)); + + ret = wl12xx_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd)); + if (ret < 0) { + wl12xx_warning("could not set keys"); + goto out_sleep; + } + +out_sleep: + wl12xx_ps_elp_sleep(wl); + +out_unlock: + mutex_unlock(&wl->mutex); + +out: + kfree(wl_cmd); + + return ret; +} + +static int wl12xx_build_basic_rates(char *rates) +{ + u8 index = 0; + + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; + + return index; +} + +static int wl12xx_build_extended_rates(char *rates) +{ + u8 index = 0; + + rates[index++] = IEEE80211_OFDM_RATE_6MB; + rates[index++] = IEEE80211_OFDM_RATE_9MB; + rates[index++] = IEEE80211_OFDM_RATE_12MB; + rates[index++] = IEEE80211_OFDM_RATE_18MB; + rates[index++] = IEEE80211_OFDM_RATE_24MB; + rates[index++] = IEEE80211_OFDM_RATE_36MB; + rates[index++] = IEEE80211_OFDM_RATE_48MB; + rates[index++] = IEEE80211_OFDM_RATE_54MB; + + return index; +} + + +static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len) +{ + struct wl12xx_probe_req_template template; + struct wl12xx_ie_rates *rates; + char *ptr; + u16 size; + + ptr = (char *)&template; + size = sizeof(struct ieee80211_header); + + memset(template.header.da, 0xff, ETH_ALEN); + memset(template.header.bssid, 0xff, ETH_ALEN); + memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); + template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); + + /* IEs */ + /* SSID */ + template.ssid.header.id = WLAN_EID_SSID; + template.ssid.header.len = ssid_len; + if (ssid_len && ssid) + memcpy(template.ssid.ssid, ssid, ssid_len); + size += sizeof(struct wl12xx_ie_header) + ssid_len; + ptr += size; + + /* Basic Rates */ + rates = (struct wl12xx_ie_rates *)ptr; + rates->header.id = WLAN_EID_SUPP_RATES; + rates->header.len = wl12xx_build_basic_rates(rates->rates); + size += sizeof(struct wl12xx_ie_header) + rates->header.len; + ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; + + /* Extended rates */ + rates = (struct wl12xx_ie_rates *)ptr; + rates->header.id = WLAN_EID_EXT_SUPP_RATES; + rates->header.len = wl12xx_build_extended_rates(rates->rates); + size += sizeof(struct wl12xx_ie_header) + rates->header.len; + + wl12xx_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); + + return wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, &template, + size); +} + +static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len, + u8 active_scan, u8 high_prio, u8 num_channels, + u8 probe_requests) +{ + struct wl12xx_cmd_trigger_scan_to *trigger = NULL; + struct cmd_scan *params = NULL; + int i, ret; + u16 scan_options = 0; + + if (wl->scanning) + return -EINVAL; + + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; + + params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); + params->params.rx_filter_options = + cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); + + /* High priority scan */ + if (!active_scan) + scan_options |= SCAN_PASSIVE; + if (high_prio) + scan_options |= SCAN_PRIORITY_HIGH; + params->params.scan_options = scan_options; + + params->params.num_channels = num_channels; + params->params.num_probe_requests = probe_requests; + params->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ + params->params.tid_trigger = 0; + + for (i = 0; i < num_channels; i++) { + params->channels[i].min_duration = cpu_to_le32(30000); + params->channels[i].max_duration = cpu_to_le32(60000); + memset(¶ms->channels[i].bssid_lsb, 0xff, 4); + memset(¶ms->channels[i].bssid_msb, 0xff, 2); + params->channels[i].early_termination = 0; + params->channels[i].tx_power_att = 0; + params->channels[i].channel = i + 1; + memset(params->channels[i].pad, 0, 3); + } + + for (i = num_channels; i < SCAN_MAX_NUM_OF_CHANNELS; i++) + memset(¶ms->channels[i], 0, + sizeof(struct basic_scan_channel_parameters)); + + if (len && ssid) { + params->params.ssid_len = len; + memcpy(params->params.ssid, ssid, len); + } else { + params->params.ssid_len = 0; + memset(params->params.ssid, 0, 32); + } + + ret = wl12xx_build_probe_req(wl, ssid, len); + if (ret < 0) { + wl12xx_error("PROBE request template failed"); + goto out; + } + + trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); + if (!trigger) + goto out; + + trigger->timeout = 0; + + ret = wl12xx_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, + sizeof(*trigger)); + if (ret < 0) { + wl12xx_error("trigger scan to failed for hw scan"); + goto out; + } + + wl12xx_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); + + wl->scanning = true; + + ret = wl12xx_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); + if (ret < 0) + wl12xx_error("SCAN failed"); + + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); + + if (params->header.status != CMD_STATUS_SUCCESS) { + wl12xx_error("TEST command answer error: %d", + params->header.status); + wl->scanning = false; + ret = -EIO; + goto out; + } + +out: + kfree(params); + return ret; + +} + +static int wl12xx_op_hw_scan(struct ieee80211_hw *hw, + struct cfg80211_scan_request *req) +{ + struct wl12xx *wl = hw->priv; + int ret; + u8 *ssid = NULL; + size_t ssid_len = 0; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 hw scan"); + + if (req->n_ssids) { + ssid = req->ssids[0].ssid; + ssid_len = req->ssids[0].ssid_len; + } + + mutex_lock(&wl->mutex); + + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl12xx_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); + + wl12xx_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct wl12xx *wl = hw->priv; + int ret; + + mutex_lock(&wl->mutex); + + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl12xx_acx_rts_threshold(wl, (u16) value); + if (ret < 0) + wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret); + + wl12xx_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + enum wl12xx_cmd_ps_mode mode; + struct wl12xx *wl = hw->priv; + struct sk_buff *beacon; + int ret; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 bss info changed"); + + mutex_lock(&wl->mutex); + + ret = wl12xx_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + if (changed & BSS_CHANGED_ASSOC) { + if (bss_conf->assoc) { + wl->aid = bss_conf->aid; + + ret = wl12xx_build_ps_poll(wl, wl->aid); + if (ret < 0) + goto out_sleep; + + ret = wl12xx_acx_aid(wl, wl->aid); + if (ret < 0) + goto out_sleep; + + /* If we want to go in PSM but we're not there yet */ + if (wl->psm_requested && !wl->psm) { + mode = STATION_POWER_SAVE_MODE; + ret = wl12xx_ps_set_mode(wl, mode); + if (ret < 0) + goto out_sleep; + } + } + } + if (changed & BSS_CHANGED_ERP_SLOT) { + if (bss_conf->use_short_slot) + ret = wl12xx_acx_slot(wl, SLOT_TIME_SHORT); + else + ret = wl12xx_acx_slot(wl, SLOT_TIME_LONG); + if (ret < 0) { + wl12xx_warning("Set slot time failed %d", ret); + goto out_sleep; + } + } + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + if (bss_conf->use_short_preamble) + wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); + else + wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_LONG); + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + if (bss_conf->use_cts_prot) + ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_ENABLE); + else + ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_DISABLE); + if (ret < 0) { + wl12xx_warning("Set ctsprotect failed %d", ret); + goto out_sleep; + } + } + + if (changed & BSS_CHANGED_BSSID) { + memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); + + ret = wl12xx_build_null_data(wl); + if (ret < 0) + goto out; + + if (wl->bss_type != BSS_TYPE_IBSS) { + ret = wl->chip.op_cmd_join(wl, wl->bss_type, 5, 100, 1); + if (ret < 0) + goto out; + } + } + + if (changed & BSS_CHANGED_BEACON) { + beacon = ieee80211_beacon_get(hw, vif); + ret = wl12xx_cmd_template_set(wl, CMD_BEACON, beacon->data, + beacon->len); + + if (ret < 0) { + dev_kfree_skb(beacon); + goto out; + } + + ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, + beacon->len); + + dev_kfree_skb(beacon); + + if (ret < 0) + goto out; + + ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); + + if (ret < 0) + goto out; + } + +out_sleep: + wl12xx_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_rate wl12xx_rates[] = { + { .bitrate = 10, + .hw_value = 0x1, + .hw_value_short = 0x1, }, + { .bitrate = 20, + .hw_value = 0x2, + .hw_value_short = 0x2, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, + .hw_value = 0x4, + .hw_value_short = 0x4, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, + .hw_value = 0x20, + .hw_value_short = 0x20, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, + .hw_value = 0x8, + .hw_value_short = 0x8, }, + { .bitrate = 90, + .hw_value = 0x10, + .hw_value_short = 0x10, }, + { .bitrate = 120, + .hw_value = 0x40, + .hw_value_short = 0x40, }, + { .bitrate = 180, + .hw_value = 0x80, + .hw_value_short = 0x80, }, + { .bitrate = 240, + .hw_value = 0x200, + .hw_value_short = 0x200, }, + { .bitrate = 360, + .hw_value = 0x400, + .hw_value_short = 0x400, }, + { .bitrate = 480, + .hw_value = 0x800, + .hw_value_short = 0x800, }, + { .bitrate = 540, + .hw_value = 0x1000, + .hw_value_short = 0x1000, }, +}; + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_channel wl12xx_channels[] = { + { .hw_value = 1, .center_freq = 2412}, + { .hw_value = 2, .center_freq = 2417}, + { .hw_value = 3, .center_freq = 2422}, + { .hw_value = 4, .center_freq = 2427}, + { .hw_value = 5, .center_freq = 2432}, + { .hw_value = 6, .center_freq = 2437}, + { .hw_value = 7, .center_freq = 2442}, + { .hw_value = 8, .center_freq = 2447}, + { .hw_value = 9, .center_freq = 2452}, + { .hw_value = 10, .center_freq = 2457}, + { .hw_value = 11, .center_freq = 2462}, + { .hw_value = 12, .center_freq = 2467}, + { .hw_value = 13, .center_freq = 2472}, +}; + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_supported_band wl12xx_band_2ghz = { + .channels = wl12xx_channels, + .n_channels = ARRAY_SIZE(wl12xx_channels), + .bitrates = wl12xx_rates, + .n_bitrates = ARRAY_SIZE(wl12xx_rates), +}; + +static const struct ieee80211_ops wl12xx_ops = { + .start = wl12xx_op_start, + .stop = wl12xx_op_stop, + .add_interface = wl12xx_op_add_interface, + .remove_interface = wl12xx_op_remove_interface, + .config = wl12xx_op_config, + .configure_filter = wl12xx_op_configure_filter, + .tx = wl12xx_op_tx, + .set_key = wl12xx_op_set_key, + .hw_scan = wl12xx_op_hw_scan, + .bss_info_changed = wl12xx_op_bss_info_changed, + .set_rts_threshold = wl12xx_op_set_rts_threshold, +}; + +static int wl12xx_register_hw(struct wl12xx *wl) +{ + int ret; + + if (wl->mac80211_registered) + return 0; + + SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); + + ret = ieee80211_register_hw(wl->hw); + if (ret < 0) { + wl12xx_error("unable to register mac80211 hw: %d", ret); + return ret; + } + + wl->mac80211_registered = true; + + wl12xx_notice("loaded"); + + return 0; +} + +static int wl12xx_init_ieee80211(struct wl12xx *wl) +{ + /* The tx descriptor buffer and the TKIP space */ + wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) + + WL1251_TKIP_IV_SPACE; + + /* unit us */ + /* FIXME: find a proper value */ + wl->hw->channel_change_time = 10000; + + wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; + + wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + wl->hw->wiphy->max_scan_ssids = 1; + wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl12xx_band_2ghz; + + SET_IEEE80211_DEV(wl->hw, &wl->spi->dev); + + return 0; +} + +#define WL12XX_DEFAULT_CHANNEL 1 +static int __devinit wl12xx_probe(struct spi_device *spi) +{ + struct wl12xx_platform_data *pdata; + struct ieee80211_hw *hw; + struct wl12xx *wl; + int ret, i; + static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; + + pdata = spi->dev.platform_data; + if (!pdata) { + wl12xx_error("no platform data"); + return -ENODEV; + } + + hw = ieee80211_alloc_hw(sizeof(*wl), &wl12xx_ops); + if (!hw) { + wl12xx_error("could not alloc ieee80211_hw"); + return -ENOMEM; + } + + wl = hw->priv; + memset(wl, 0, sizeof(*wl)); + + wl->hw = hw; + dev_set_drvdata(&spi->dev, wl); + wl->spi = spi; + + wl->data_in_count = 0; + + skb_queue_head_init(&wl->tx_queue); + + INIT_WORK(&wl->filter_work, wl12xx_filter_work); + wl->channel = WL12XX_DEFAULT_CHANNEL; + wl->scanning = false; + wl->default_key = 0; + wl->listen_int = 1; + wl->rx_counter = 0; + wl->rx_handled = 0; + wl->rx_current_buffer = 0; + wl->rx_last_id = 0; + wl->rx_config = WL12XX_DEFAULT_RX_CONFIG; + wl->rx_filter = WL12XX_DEFAULT_RX_FILTER; + wl->elp = false; + wl->psm = 0; + wl->psm_requested = false; + wl->tx_queue_stopped = false; + wl->power_level = WL12XX_DEFAULT_POWER_LEVEL; + + /* We use the default power on sleep time until we know which chip + * we're using */ + wl->chip.power_on_sleep = WL12XX_DEFAULT_POWER_ON_SLEEP; + + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + wl->tx_frames[i] = NULL; + + wl->next_tx_complete = 0; + + /* + * In case our MAC address is not correctly set, + * we use a random but Nokia MAC. + */ + memcpy(wl->mac_addr, nokia_oui, 3); + get_random_bytes(wl->mac_addr + 3, 3); + + wl->state = WL12XX_STATE_OFF; + mutex_init(&wl->mutex); + + wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE; + wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE; + + wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); + if (!wl->rx_descriptor) { + wl12xx_error("could not allocate memory for rx descriptor"); + ret = -ENOMEM; + goto out_free; + } + + /* This is the only SPI value that we need to set here, the rest + * comes from the board-peripherals file */ + spi->bits_per_word = 32; + + ret = spi_setup(spi); + if (ret < 0) { + wl12xx_error("spi_setup failed"); + goto out_free; + } + + wl->set_power = pdata->set_power; + if (!wl->set_power) { + wl12xx_error("set power function missing in platform data"); + ret = -ENODEV; + goto out_free; + } + + wl->irq = spi->irq; + if (wl->irq < 0) { + wl12xx_error("irq missing in platform data"); + ret = -ENODEV; + goto out_free; + } + + ret = request_irq(wl->irq, wl12xx_irq, 0, DRIVER_NAME, wl); + if (ret < 0) { + wl12xx_error("request_irq() failed: %d", ret); + goto out_free; + } + + set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); + + disable_irq(wl->irq); + + ret = wl12xx_init_ieee80211(wl); + if (ret) + goto out_irq; + + ret = wl12xx_register_hw(wl); + if (ret) + goto out_irq; + + wl12xx_debugfs_init(wl); + + wl12xx_notice("initialized"); + + return 0; + + out_irq: + free_irq(wl->irq, wl); + + out_free: + kfree(wl->rx_descriptor); + wl->rx_descriptor = NULL; + + ieee80211_free_hw(hw); + + return ret; +} + +static int __devexit wl12xx_remove(struct spi_device *spi) +{ + struct wl12xx *wl = dev_get_drvdata(&spi->dev); + + ieee80211_unregister_hw(wl->hw); + + wl12xx_debugfs_exit(wl); + + free_irq(wl->irq, wl); + kfree(wl->target_mem_map); + kfree(wl->data_path); + kfree(wl->fw); + wl->fw = NULL; + kfree(wl->nvs); + wl->nvs = NULL; + + kfree(wl->rx_descriptor); + wl->rx_descriptor = NULL; + + ieee80211_free_hw(wl->hw); + + return 0; +} + + +static struct spi_driver wl12xx_spi_driver = { + .driver = { + .name = "wl12xx", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = wl12xx_probe, + .remove = __devexit_p(wl12xx_remove), +}; + +static int __init wl12xx_init(void) +{ + int ret; + + ret = spi_register_driver(&wl12xx_spi_driver); + if (ret < 0) { + wl12xx_error("failed to register spi driver: %d", ret); + goto out; + } + +out: + return ret; +} + +static void __exit wl12xx_exit(void) +{ + spi_unregister_driver(&wl12xx_spi_driver); + + wl12xx_notice("unloaded"); +} + +module_init(wl12xx_init); +module_exit(wl12xx_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kalle Valo , " + "Luciano Coelho "); diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.c b/drivers/net/wireless/wl12xx/wl1251_netlink.c new file mode 100644 index 00000000000..1bc049fa2ba --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_netlink.c @@ -0,0 +1,679 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ +#include "wl1251_netlink.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "wl12xx.h" +#include "wl1251_spi.h" +#include "wl1251_acx.h" + +/* FIXME: this should be changed as soon as user space catches up */ +#define WL12XX_NL_NAME "wl1251" +#define WL12XX_NL_VERSION 1 + +#define WL12XX_MAX_TEST_LENGTH 1024 +#define WL12XX_MAX_NVS_LENGTH 1024 + +enum wl12xx_nl_commands { + WL12XX_NL_CMD_UNSPEC, + WL12XX_NL_CMD_TEST, + WL12XX_NL_CMD_INTERROGATE, + WL12XX_NL_CMD_CONFIGURE, + WL12XX_NL_CMD_PHY_REG_READ, + WL12XX_NL_CMD_NVS_PUSH, + WL12XX_NL_CMD_REG_WRITE, + WL12XX_NL_CMD_REG_READ, + WL12XX_NL_CMD_SET_PLT_MODE, + + __WL12XX_NL_CMD_AFTER_LAST +}; +#define WL12XX_NL_CMD_MAX (__WL12XX_NL_CMD_AFTER_LAST - 1) + +enum wl12xx_nl_attrs { + WL12XX_NL_ATTR_UNSPEC, + WL12XX_NL_ATTR_IFNAME, + WL12XX_NL_ATTR_CMD_TEST_PARAM, + WL12XX_NL_ATTR_CMD_TEST_ANSWER, + WL12XX_NL_ATTR_CMD_IE, + WL12XX_NL_ATTR_CMD_IE_LEN, + WL12XX_NL_ATTR_CMD_IE_BUFFER, + WL12XX_NL_ATTR_CMD_IE_ANSWER, + WL12XX_NL_ATTR_REG_ADDR, + WL12XX_NL_ATTR_REG_VAL, + WL12XX_NL_ATTR_NVS_BUFFER, + WL12XX_NL_ATTR_NVS_LEN, + WL12XX_NL_ATTR_PLT_MODE, + + __WL12XX_NL_ATTR_AFTER_LAST +}; +#define WL12XX_NL_ATTR_MAX (__WL12XX_NL_ATTR_AFTER_LAST - 1) + +static struct genl_family wl12xx_nl_family = { + .id = GENL_ID_GENERATE, + .name = WL12XX_NL_NAME, + .hdrsize = 0, + .version = WL12XX_NL_VERSION, + .maxattr = WL12XX_NL_ATTR_MAX, +}; + +static struct net_device *ifname_to_netdev(struct net *net, + struct genl_info *info) +{ + char *ifname; + + if (!info->attrs[WL12XX_NL_ATTR_IFNAME]) + return NULL; + + ifname = nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME]); + + wl12xx_debug(DEBUG_NETLINK, "Looking for %s", ifname); + + return dev_get_by_name(net, ifname); +} + +static struct wl12xx *ifname_to_wl12xx(struct net *net, struct genl_info *info) +{ + struct net_device *netdev; + struct wireless_dev *wdev; + struct wiphy *wiphy; + struct ieee80211_hw *hw; + + netdev = ifname_to_netdev(net, info); + if (netdev == NULL) { + wl12xx_error("Wrong interface"); + return NULL; + } + + wdev = netdev->ieee80211_ptr; + if (wdev == NULL) { + wl12xx_error("ieee80211_ptr is NULL"); + return NULL; + } + + wiphy = wdev->wiphy; + if (wiphy == NULL) { + wl12xx_error("wiphy is NULL"); + return NULL; + } + + hw = wiphy_priv(wiphy); + if (hw == NULL) { + wl12xx_error("hw is NULL"); + return NULL; + } + + dev_put(netdev); + + return hw->priv; +} + +static int wl12xx_nl_test_cmd(struct sk_buff *skb, struct genl_info *info) +{ + struct wl12xx *wl; + struct wl12xx_command *cmd; + char *buf; + int buf_len, ret, cmd_len; + u8 answer; + + if (!info->attrs[WL12XX_NL_ATTR_CMD_TEST_PARAM]) + return -EINVAL; + + wl = ifname_to_wl12xx(&init_net, info); + if (wl == NULL) { + wl12xx_error("wl12xx not found"); + return -EINVAL; + } + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + buf = nla_data(info->attrs[WL12XX_NL_ATTR_CMD_TEST_PARAM]); + buf_len = nla_len(info->attrs[WL12XX_NL_ATTR_CMD_TEST_PARAM]); + answer = nla_get_u8(info->attrs[WL12XX_NL_ATTR_CMD_TEST_ANSWER]); + + cmd->header.id = CMD_TEST; + memcpy(cmd->parameters, buf, buf_len); + cmd_len = sizeof(struct wl12xx_cmd_header) + buf_len; + + mutex_lock(&wl->mutex); + ret = wl12xx_cmd_test(wl, cmd, cmd_len, answer); + mutex_unlock(&wl->mutex); + + if (ret < 0) { + wl12xx_error("%s() failed", __func__); + goto out; + } + + if (answer) { + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) { + ret = -ENOMEM; + goto out; + } + + hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, + &wl12xx_nl_family, 0, WL12XX_NL_CMD_TEST); + if (IS_ERR(hdr)) { + ret = PTR_ERR(hdr); + goto nla_put_failure; + } + + NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME, + nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME])); + NLA_PUT(msg, WL12XX_NL_ATTR_CMD_TEST_ANSWER, + sizeof(*cmd), cmd); + + ret = genlmsg_end(msg, hdr); + if (ret < 0) { + wl12xx_error("%s() failed", __func__); + goto nla_put_failure; + } + + wl12xx_debug(DEBUG_NETLINK, "TEST cmd sent, answer"); + ret = genlmsg_reply(msg, info); + goto out; + + nla_put_failure: + nlmsg_free(msg); + } else + wl12xx_debug(DEBUG_NETLINK, "TEST cmd sent"); + +out: + kfree(cmd); + return ret; +} + +static int wl12xx_nl_interrogate(struct sk_buff *skb, struct genl_info *info) +{ + struct wl12xx *wl; + struct sk_buff *msg; + int ret = -ENOBUFS, cmd_ie, cmd_ie_len; + struct wl12xx_command *cmd; + void *hdr; + + if (!info->attrs[WL12XX_NL_ATTR_CMD_IE]) + return -EINVAL; + + if (!info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN]) + return -EINVAL; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + wl = ifname_to_wl12xx(&init_net, info); + if (wl == NULL) { + wl12xx_error("wl12xx not found"); + ret = -EINVAL; + goto nla_put_failure; + } + + /* acx id */ + cmd_ie = nla_get_u32(info->attrs[WL12XX_NL_ATTR_CMD_IE]); + + /* maximum length of acx, including all headers */ + cmd_ie_len = nla_get_u32(info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN]); + + wl12xx_debug(DEBUG_NETLINK, "Getting IE 0x%x (len %d)", + cmd_ie, cmd_ie_len); + + mutex_lock(&wl->mutex); + ret = wl12xx_cmd_interrogate(wl, cmd_ie, cmd, cmd_ie_len); + mutex_unlock(&wl->mutex); + + if (ret < 0) { + wl12xx_error("%s() failed", __func__); + goto nla_put_failure; + } + + hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, + &wl12xx_nl_family, 0, WL12XX_NL_CMD_INTERROGATE); + if (IS_ERR(hdr)) { + ret = PTR_ERR(hdr); + goto nla_put_failure; + } + + NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME, + nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME])); + NLA_PUT(msg, WL12XX_NL_ATTR_CMD_IE_ANSWER, cmd_ie_len, cmd); + + ret = genlmsg_end(msg, hdr); + if (ret < 0) { + wl12xx_error("%s() failed", __func__); + goto nla_put_failure; + } + + kfree(cmd); + return genlmsg_reply(msg, info); + + nla_put_failure: + kfree(cmd); + nlmsg_free(msg); + + return ret; +} + +static int wl12xx_nl_configure(struct sk_buff *skb, struct genl_info *info) +{ + int ret = 0, cmd_ie_len, acx_len; + struct acx_header *acx = NULL; + struct sk_buff *msg; + struct wl12xx *wl; + void *cmd_ie; + u16 *id; + + if (!info->attrs[WL12XX_NL_ATTR_CMD_IE_BUFFER]) + return -EINVAL; + + if (!info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN]) + return -EINVAL; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + wl = ifname_to_wl12xx(&init_net, info); + if (wl == NULL) { + wl12xx_error("wl12xx not found"); + ret = -EINVAL; + goto nla_put_failure; + } + + /* contains the acx header but not the cmd header */ + cmd_ie = nla_data(info->attrs[WL12XX_NL_ATTR_CMD_IE_BUFFER]); + + cmd_ie_len = nla_get_u32(info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN]); + + /* acx id is in the first two bytes */ + id = cmd_ie; + + /* need to add acx_header before cmd_ie, so create a new command */ + acx_len = sizeof(struct acx_header) + cmd_ie_len; + acx = kzalloc(acx_len, GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto nla_put_failure; + } + + /* copy the acx header and the payload */ + memcpy(&acx->id, cmd_ie, cmd_ie_len); + + mutex_lock(&wl->mutex); + ret = wl12xx_cmd_configure(wl, *id, acx, acx_len); + mutex_unlock(&wl->mutex); + + if (ret < 0) { + wl12xx_error("%s() failed", __func__); + goto nla_put_failure; + } + + wl12xx_debug(DEBUG_NETLINK, "CONFIGURE cmd sent"); + + nla_put_failure: + kfree(acx); + nlmsg_free(msg); + + return ret; +} + +static int wl12xx_nl_phy_reg_read(struct sk_buff *skb, struct genl_info *info) +{ + struct wl12xx *wl; + struct sk_buff *msg; + u32 reg_addr, *reg_value = NULL; + int ret = 0; + void *hdr; + + if (!info->attrs[WL12XX_NL_ATTR_REG_ADDR]) + return -EINVAL; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + wl = ifname_to_wl12xx(&init_net, info); + if (wl == NULL) { + wl12xx_error("wl12xx not found"); + ret = -EINVAL; + goto nla_put_failure; + } + + reg_value = kmalloc(sizeof(*reg_value), GFP_KERNEL); + if (!reg_value) { + ret = -ENOMEM; + goto nla_put_failure; + } + + reg_addr = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_ADDR]); + + wl12xx_debug(DEBUG_NETLINK, "Reading PHY reg 0x%x", reg_addr); + + mutex_lock(&wl->mutex); + ret = wl12xx_cmd_read_memory(wl, reg_addr, reg_value, + sizeof(*reg_value)); + mutex_unlock(&wl->mutex); + + if (ret < 0) { + wl12xx_error("%s() failed", __func__); + goto nla_put_failure; + } + + + hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, + &wl12xx_nl_family, 0, WL12XX_NL_CMD_PHY_REG_READ); + if (IS_ERR(hdr)) { + ret = PTR_ERR(hdr); + goto nla_put_failure; + } + + NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME, + nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME])); + + NLA_PUT_U32(msg, WL12XX_NL_ATTR_REG_VAL, *reg_value); + + ret = genlmsg_end(msg, hdr); + if (ret < 0) { + wl12xx_error("%s() failed", __func__); + goto nla_put_failure; + } + + kfree(reg_value); + + return genlmsg_reply(msg, info); + + nla_put_failure: + nlmsg_free(msg); + kfree(reg_value); + + return ret; +} + +static int wl12xx_nl_nvs_push(struct sk_buff *skb, struct genl_info *info) +{ + struct wl12xx *wl; + int ret = 0; + + if (!info->attrs[WL12XX_NL_ATTR_NVS_BUFFER]) + return -EINVAL; + + if (!info->attrs[WL12XX_NL_ATTR_NVS_LEN]) + return -EINVAL; + + wl = ifname_to_wl12xx(&init_net, info); + if (wl == NULL) { + wl12xx_error("wl12xx not found"); + return -EINVAL; + } + + mutex_lock(&wl->mutex); + wl->nvs_len = nla_get_u32(info->attrs[WL12XX_NL_ATTR_NVS_LEN]); + if (wl->nvs_len % 4) { + wl12xx_error("NVS size is not multiple of 32: %d", wl->nvs_len); + ret = -EILSEQ; + goto out; + } + + /* If we already have an NVS, we should free it */ + kfree(wl->nvs); + + wl->nvs = kzalloc(wl->nvs_len, GFP_KERNEL); + if (wl->nvs == NULL) { + wl12xx_error("Can't allocate NVS"); + ret = -ENOMEM; + goto out; + } + + memcpy(wl->nvs, + nla_data(info->attrs[WL12XX_NL_ATTR_NVS_BUFFER]), + wl->nvs_len); + + wl12xx_debug(DEBUG_NETLINK, "got NVS from userspace, %d bytes", + wl->nvs_len); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static int wl12xx_nl_reg_read(struct sk_buff *skb, struct genl_info *info) +{ + struct wl12xx *wl; + u32 addr, val; + int ret = 0; + struct sk_buff *msg; + void *hdr; + + if (!info->attrs[WL12XX_NL_ATTR_REG_ADDR]) + return -EINVAL; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + wl = ifname_to_wl12xx(&init_net, info); + if (wl == NULL) { + wl12xx_error("wl12xx not found"); + return -EINVAL; + } + + addr = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_ADDR]); + + mutex_lock(&wl->mutex); + val = wl12xx_reg_read32(wl, addr); + mutex_unlock(&wl->mutex); + + hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, + &wl12xx_nl_family, 0, WL12XX_NL_CMD_PHY_REG_READ); + if (IS_ERR(hdr)) { + ret = PTR_ERR(hdr); + goto nla_put_failure; + } + + NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME, + nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME])); + + NLA_PUT_U32(msg, WL12XX_NL_ATTR_REG_VAL, val); + + ret = genlmsg_end(msg, hdr); + if (ret < 0) { + wl12xx_error("%s() failed", __func__); + goto nla_put_failure; + } + + return genlmsg_reply(msg, info); + + nla_put_failure: + nlmsg_free(msg); + + return ret; +} + +static int wl12xx_nl_reg_write(struct sk_buff *skb, struct genl_info *info) +{ + struct wl12xx *wl; + u32 addr, val; + + if (!info->attrs[WL12XX_NL_ATTR_REG_ADDR]) + return -EINVAL; + + if (!info->attrs[WL12XX_NL_ATTR_REG_VAL]) + return -EINVAL; + + wl = ifname_to_wl12xx(&init_net, info); + if (wl == NULL) { + wl12xx_error("wl12xx not found"); + return -EINVAL; + } + + addr = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_ADDR]); + val = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_VAL]); + + mutex_lock(&wl->mutex); + wl12xx_reg_write32(wl, addr, val); + mutex_unlock(&wl->mutex); + + return 0; +} + +static int wl12xx_nl_set_plt_mode(struct sk_buff *skb, struct genl_info *info) +{ + struct wl12xx *wl; + u32 val; + int ret; + + if (!info->attrs[WL12XX_NL_ATTR_PLT_MODE]) + return -EINVAL; + + wl = ifname_to_wl12xx(&init_net, info); + if (wl == NULL) { + wl12xx_error("wl12xx not found"); + return -EINVAL; + } + + val = nla_get_u32(info->attrs[WL12XX_NL_ATTR_PLT_MODE]); + + switch (val) { + case 0: + ret = wl12xx_plt_stop(wl); + break; + case 1: + ret = wl12xx_plt_start(wl); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static struct nla_policy wl12xx_nl_policy[WL12XX_NL_ATTR_MAX + 1] = { + [WL12XX_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING, + .len = IFNAMSIZ-1 }, + [WL12XX_NL_ATTR_CMD_TEST_PARAM] = { .type = NLA_BINARY, + .len = WL12XX_MAX_TEST_LENGTH }, + [WL12XX_NL_ATTR_CMD_TEST_ANSWER] = { .type = NLA_U8 }, + [WL12XX_NL_ATTR_CMD_IE] = { .type = NLA_U32 }, + [WL12XX_NL_ATTR_CMD_IE_LEN] = { .type = NLA_U32 }, + [WL12XX_NL_ATTR_CMD_IE_BUFFER] = { .type = NLA_BINARY, + .len = WL12XX_MAX_TEST_LENGTH }, + [WL12XX_NL_ATTR_CMD_IE_ANSWER] = { .type = NLA_BINARY, + .len = WL12XX_MAX_TEST_LENGTH }, + [WL12XX_NL_ATTR_REG_ADDR] = { .type = NLA_U32 }, + [WL12XX_NL_ATTR_REG_VAL] = { .type = NLA_U32 }, + [WL12XX_NL_ATTR_NVS_BUFFER] = { .type = NLA_BINARY, + .len = WL12XX_MAX_NVS_LENGTH }, + [WL12XX_NL_ATTR_NVS_LEN] = { .type = NLA_U32 }, + [WL12XX_NL_ATTR_PLT_MODE] = { .type = NLA_U32 }, +}; + +static struct genl_ops wl12xx_nl_ops[] = { + { + .cmd = WL12XX_NL_CMD_TEST, + .doit = wl12xx_nl_test_cmd, + .policy = wl12xx_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = WL12XX_NL_CMD_INTERROGATE, + .doit = wl12xx_nl_interrogate, + .policy = wl12xx_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = WL12XX_NL_CMD_CONFIGURE, + .doit = wl12xx_nl_configure, + .policy = wl12xx_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = WL12XX_NL_CMD_PHY_REG_READ, + .doit = wl12xx_nl_phy_reg_read, + .policy = wl12xx_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = WL12XX_NL_CMD_NVS_PUSH, + .doit = wl12xx_nl_nvs_push, + .policy = wl12xx_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = WL12XX_NL_CMD_REG_WRITE, + .doit = wl12xx_nl_reg_write, + .policy = wl12xx_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = WL12XX_NL_CMD_REG_READ, + .doit = wl12xx_nl_reg_read, + .policy = wl12xx_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = WL12XX_NL_CMD_SET_PLT_MODE, + .doit = wl12xx_nl_set_plt_mode, + .policy = wl12xx_nl_policy, + .flags = GENL_ADMIN_PERM, + }, +}; + +int wl12xx_nl_register(void) +{ + int err, i; + + err = genl_register_family(&wl12xx_nl_family); + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE(wl12xx_nl_ops); i++) { + err = genl_register_ops(&wl12xx_nl_family, &wl12xx_nl_ops[i]); + if (err) + goto err_out; + } + return 0; + err_out: + genl_unregister_family(&wl12xx_nl_family); + return err; +} + +void wl12xx_nl_unregister(void) +{ + genl_unregister_family(&wl12xx_nl_family); +} diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.h b/drivers/net/wireless/wl12xx/wl1251_netlink.h new file mode 100644 index 00000000000..acfbd0241b8 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_netlink.h @@ -0,0 +1,30 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_NETLINK_H__ +#define __WL12XX_NETLINK_H__ + +int wl12xx_nl_register(void); +void wl12xx_nl_unregister(void); + +#endif /* __WL12XX_NETLINK_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.c b/drivers/net/wireless/wl12xx/wl1251_ops.c index 126537f784b..cdfd2c21899 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ops.c +++ b/drivers/net/wireless/wl12xx/wl1251_ops.c @@ -26,14 +26,14 @@ #include "wl1251_ops.h" #include "reg.h" -#include "spi.h" -#include "boot.h" -#include "event.h" -#include "acx.h" +#include "wl1251_spi.h" +#include "wl1251_boot.h" +#include "wl1251_event.h" +#include "wl1251_acx.h" #include "wl1251_tx.h" -#include "rx.h" -#include "ps.h" -#include "init.h" +#include "wl1251_rx.h" +#include "wl1251_ps.h" +#include "wl1251_init.h" static struct wl12xx_partition_set wl1251_part_table[PART_TABLE_LEN] = { [PART_DOWN] = { diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.h b/drivers/net/wireless/wl12xx/wl1251_ops.h index 74acf8e3df9..7a78cc9e699 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ops.h +++ b/drivers/net/wireless/wl12xx/wl1251_ops.h @@ -27,7 +27,7 @@ #include #include "wl12xx.h" -#include "acx.h" +#include "wl1251_acx.h" #define WL1251_FW_NAME "wl1251-fw.bin" #define WL1251_NVS_NAME "wl1251-nvs.bin" diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c new file mode 100644 index 00000000000..83baaa2eb19 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_ps.c @@ -0,0 +1,147 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "reg.h" +#include "wl1251_ps.h" +#include "wl1251_spi.h" + +#define WL12XX_WAKEUP_TIMEOUT 2000 + +/* Routines to toggle sleep mode while in ELP */ +void wl12xx_ps_elp_sleep(struct wl12xx *wl) +{ + if (wl->elp || !wl->psm) + return; + + wl12xx_debug(DEBUG_PSM, "chip to elp"); + + wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); + + wl->elp = true; +} + +int wl12xx_ps_elp_wakeup(struct wl12xx *wl) +{ + unsigned long timeout; + u32 elp_reg; + + if (!wl->elp) + return 0; + + wl12xx_debug(DEBUG_PSM, "waking up chip from elp"); + + timeout = jiffies + msecs_to_jiffies(WL12XX_WAKEUP_TIMEOUT); + + wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); + + elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + + /* + * FIXME: we should wait for irq from chip but, as a temporary + * solution to simplify locking, let's poll instead + */ + while (!(elp_reg & ELPCTRL_WLAN_READY)) { + if (time_after(jiffies, timeout)) { + wl12xx_error("elp wakeup timeout"); + return -ETIMEDOUT; + } + msleep(1); + elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + } + + wl12xx_debug(DEBUG_PSM, "wakeup time: %u ms", + jiffies_to_msecs(jiffies) - + (jiffies_to_msecs(timeout) - WL12XX_WAKEUP_TIMEOUT)); + + wl->elp = false; + + return 0; +} + +static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable) +{ + int ret; + + if (enable) { + wl12xx_debug(DEBUG_PSM, "sleep auth psm/elp"); + + ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_ELP); + if (ret < 0) + return ret; + + wl12xx_ps_elp_sleep(wl); + } else { + wl12xx_debug(DEBUG_PSM, "sleep auth cam"); + + /* + * When the target is in ELP, we can only + * access the ELP control register. Thus, + * we have to wake the target up before + * changing the power authorization. + */ + + wl12xx_ps_elp_wakeup(wl); + + ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM); + if (ret < 0) + return ret; + } + + return 0; +} + +int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode) +{ + int ret; + + switch (mode) { + case STATION_POWER_SAVE_MODE: + wl12xx_debug(DEBUG_PSM, "entering psm"); + ret = wl12xx_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); + if (ret < 0) + return ret; + + ret = wl12xx_ps_set_elp(wl, true); + if (ret < 0) + return ret; + + wl->psm = 1; + break; + case STATION_ACTIVE_MODE: + default: + wl12xx_debug(DEBUG_PSM, "leaving psm"); + ret = wl12xx_ps_set_elp(wl, false); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_ps_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + return ret; + + wl->psm = 0; + break; + } + + return ret; +} + diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.h b/drivers/net/wireless/wl12xx/wl1251_ps.h new file mode 100644 index 00000000000..db9f7ed9dd1 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_ps.h @@ -0,0 +1,36 @@ +#ifndef __WL12XX_PS_H__ +#define __WL12XX_PS_H__ + +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl12xx.h" +#include "wl1251_acx.h" + +int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode); +void wl12xx_ps_elp_sleep(struct wl12xx *wl); +int wl12xx_ps_elp_wakeup(struct wl12xx *wl); + + +#endif /* __WL12XX_PS_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c new file mode 100644 index 00000000000..d73e014d611 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_rx.c @@ -0,0 +1,195 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "wl12xx.h" +#include "reg.h" +#include "wl1251_spi.h" +#include "wl1251_rx.h" +#include "wl1251_acx.h" + +static void wl12xx_rx_header(struct wl12xx *wl, + struct wl12xx_rx_descriptor *desc) +{ + u32 rx_packet_ring_addr; + + rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr; + if (wl->rx_current_buffer) + rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; + + wl12xx_spi_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); +} + +static void wl12xx_rx_status(struct wl12xx *wl, + struct wl12xx_rx_descriptor *desc, + struct ieee80211_rx_status *status, + u8 beacon) +{ + u64 mactime; + int ret; + + memset(status, 0, sizeof(struct ieee80211_rx_status)); + + status->band = IEEE80211_BAND_2GHZ; + status->mactime = desc->timestamp; + + /* + * The rx status timestamp is a 32 bits value while the TSF is a + * 64 bits one. + * For IBSS merging, TSF is mandatory, so we have to get it + * somehow, so we ask for ACX_TSF_INFO. + * That could be moved to the get_tsf() hook, but unfortunately, + * this one must be atomic, while our SPI routines can sleep. + */ + if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) { + ret = wl12xx_acx_tsf_info(wl, &mactime); + if (ret == 0) + status->mactime = mactime; + } + + status->signal = desc->rssi; + status->qual = (desc->rssi - WL12XX_RX_MIN_RSSI) * 100 / + (WL12XX_RX_MAX_RSSI - WL12XX_RX_MIN_RSSI); + status->qual = min(status->qual, 100); + status->qual = max(status->qual, 0); + + /* + * FIXME: guessing that snr needs to be divided by two, otherwise + * the values don't make any sense + */ + status->noise = desc->rssi - desc->snr / 2; + + status->freq = ieee80211_channel_to_frequency(desc->channel); + + status->flag |= RX_FLAG_TSFT; + + if (desc->flags & RX_DESC_ENCRYPTION_MASK) { + status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; + + if (likely(!(desc->flags & RX_DESC_DECRYPT_FAIL))) + status->flag |= RX_FLAG_DECRYPTED; + + if (unlikely(desc->flags & RX_DESC_MIC_FAIL)) + status->flag |= RX_FLAG_MMIC_ERROR; + } + + if (unlikely(!(desc->flags & RX_DESC_VALID_FCS))) + status->flag |= RX_FLAG_FAILED_FCS_CRC; + + + /* FIXME: set status->rate_idx */ +} + +static void wl12xx_rx_body(struct wl12xx *wl, + struct wl12xx_rx_descriptor *desc) +{ + struct sk_buff *skb; + struct ieee80211_rx_status status; + u8 *rx_buffer, beacon = 0; + u16 length, *fc; + u32 curr_id, last_id_inc, rx_packet_ring_addr; + + length = WL12XX_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH); + curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT; + last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1); + + if (last_id_inc != curr_id) { + wl12xx_warning("curr ID:%d, last ID inc:%d", + curr_id, last_id_inc); + wl->rx_last_id = curr_id; + } else { + wl->rx_last_id = last_id_inc; + } + + rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr + + sizeof(struct wl12xx_rx_descriptor) + 20; + if (wl->rx_current_buffer) + rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; + + skb = dev_alloc_skb(length); + if (!skb) { + wl12xx_error("Couldn't allocate RX frame"); + return; + } + + rx_buffer = skb_put(skb, length); + wl12xx_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); + + /* The actual lenght doesn't include the target's alignment */ + skb->len = desc->length - PLCP_HEADER_LENGTH; + + fc = (u16 *)skb->data; + + if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) + beacon = 1; + + wl12xx_rx_status(wl, desc, &status, beacon); + + wl12xx_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, + beacon ? "beacon" : ""); + + ieee80211_rx(wl->hw, skb, &status); +} + +static void wl12xx_rx_ack(struct wl12xx *wl) +{ + u32 data, addr; + + if (wl->rx_current_buffer) { + addr = ACX_REG_INTERRUPT_TRIG_H; + data = INTR_TRIG_RX_PROC1; + } else { + addr = ACX_REG_INTERRUPT_TRIG; + data = INTR_TRIG_RX_PROC0; + } + + wl12xx_reg_write32(wl, addr, data); + + /* Toggle buffer ring */ + wl->rx_current_buffer = !wl->rx_current_buffer; +} + + +void wl12xx_rx(struct wl12xx *wl) +{ + struct wl12xx_rx_descriptor *rx_desc; + + if (wl->state != WL12XX_STATE_ON) + return; + + rx_desc = wl->rx_descriptor; + + /* We first read the frame's header */ + wl12xx_rx_header(wl, rx_desc); + + /* Now we can read the body */ + wl12xx_rx_body(wl, rx_desc); + + /* Finally, we need to ACK the RX */ + wl12xx_rx_ack(wl); + + return; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.h b/drivers/net/wireless/wl12xx/wl1251_rx.h new file mode 100644 index 00000000000..8a23fdea501 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_rx.h @@ -0,0 +1,122 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_RX_H__ +#define __WL12XX_RX_H__ + +#include + +/* + * RX PATH + * + * The Rx path uses a double buffer and an rx_contro structure, each located + * at a fixed address in the device memory. The host keeps track of which + * buffer is available and alternates between them on a per packet basis. + * The size of each of the two buffers is large enough to hold the longest + * 802.3 packet. + * The RX path goes like that: + * 1) The target generates an interrupt each time a new packet is received. + * There are 2 RX interrupts, one for each buffer. + * 2) The host reads the received packet from one of the double buffers. + * 3) The host triggers a target interrupt. + * 4) The target prepares the next RX packet. + */ + +#define WL12XX_RX_MAX_RSSI -30 +#define WL12XX_RX_MIN_RSSI -95 + +#define WL12XX_RX_ALIGN_TO 4 +#define WL12XX_RX_ALIGN(len) (((len) + WL12XX_RX_ALIGN_TO - 1) & \ + ~(WL12XX_RX_ALIGN_TO - 1)) + +#define SHORT_PREAMBLE_BIT BIT(0) +#define OFDM_RATE_BIT BIT(6) +#define PBCC_RATE_BIT BIT(7) + +#define PLCP_HEADER_LENGTH 8 +#define RX_DESC_PACKETID_SHIFT 11 +#define RX_MAX_PACKET_ID 3 + +#define RX_DESC_VALID_FCS 0x0001 +#define RX_DESC_MATCH_RXADDR1 0x0002 +#define RX_DESC_MCAST 0x0004 +#define RX_DESC_STAINTIM 0x0008 +#define RX_DESC_VIRTUAL_BM 0x0010 +#define RX_DESC_BCAST 0x0020 +#define RX_DESC_MATCH_SSID 0x0040 +#define RX_DESC_MATCH_BSSID 0x0080 +#define RX_DESC_ENCRYPTION_MASK 0x0300 +#define RX_DESC_MEASURMENT 0x0400 +#define RX_DESC_SEQNUM_MASK 0x1800 +#define RX_DESC_MIC_FAIL 0x2000 +#define RX_DESC_DECRYPT_FAIL 0x4000 + +struct wl12xx_rx_descriptor { + u32 timestamp; /* In microseconds */ + u16 length; /* Paylod length, including headers */ + u16 flags; + + /* + * 0 - 802.11 + * 1 - 802.3 + * 2 - IP + * 3 - Raw Codec + */ + u8 type; + + /* + * Recevied Rate: + * 0x0A - 1MBPS + * 0x14 - 2MBPS + * 0x37 - 5_5MBPS + * 0x0B - 6MBPS + * 0x0F - 9MBPS + * 0x6E - 11MBPS + * 0x0A - 12MBPS + * 0x0E - 18MBPS + * 0xDC - 22MBPS + * 0x09 - 24MBPS + * 0x0D - 36MBPS + * 0x08 - 48MBPS + * 0x0C - 54MBPS + */ + u8 rate; + + u8 mod_pre; /* Modulation and preamble */ + u8 channel; + + /* + * 0 - 2.4 Ghz + * 1 - 5 Ghz + */ + u8 band; + + s8 rssi; /* in dB */ + u8 rcpi; /* in dB */ + u8 snr; /* in dB */ +} __attribute__ ((packed)); + +void wl12xx_rx(struct wl12xx *wl); + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c new file mode 100644 index 00000000000..d7eee8ce7ef --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -0,0 +1,394 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include + +#include "wl12xx.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "wl1251_spi.h" + +static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr) +{ + /* If the address is lower than REGISTERS_BASE, it means that this is + * a chip-specific register address, so look it up in the registers + * table */ + if (addr < REGISTERS_BASE) { + /* Make sure we don't go over the table */ + if (addr >= ACX_REG_TABLE_LEN) { + wl12xx_error("address out of range (%d)", addr); + return -EINVAL; + } + addr = wl->chip.acx_reg_table[addr]; + } + + return addr - wl->physical_reg_addr + wl->virtual_reg_addr; +} + +static int wl12xx_translate_mem_addr(struct wl12xx *wl, int addr) +{ + return addr - wl->physical_mem_addr + wl->virtual_mem_addr; +} + + +void wl12xx_spi_reset(struct wl12xx *wl) +{ + u8 *cmd; + struct spi_transfer t; + struct spi_message m; + + cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); + if (!cmd) { + wl12xx_error("could not allocate cmd for spi reset"); + return; + } + + memset(&t, 0, sizeof(t)); + spi_message_init(&m); + + memset(cmd, 0xff, WSPI_INIT_CMD_LEN); + + t.tx_buf = cmd; + t.len = WSPI_INIT_CMD_LEN; + spi_message_add_tail(&t, &m); + + spi_sync(wl->spi, &m); + + wl12xx_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); +} + +void wl12xx_spi_init(struct wl12xx *wl) +{ + u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; + struct spi_transfer t; + struct spi_message m; + + cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); + if (!cmd) { + wl12xx_error("could not allocate cmd for spi init"); + return; + } + + memset(crc, 0, sizeof(crc)); + memset(&t, 0, sizeof(t)); + spi_message_init(&m); + + /* + * Set WSPI_INIT_COMMAND + * the data is being send from the MSB to LSB + */ + cmd[2] = 0xff; + cmd[3] = 0xff; + cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; + cmd[0] = 0; + cmd[7] = 0; + cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3; + cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; + + if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) + cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY; + else + cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY; + + cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS + | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; + + crc[0] = cmd[1]; + crc[1] = cmd[0]; + crc[2] = cmd[7]; + crc[3] = cmd[6]; + crc[4] = cmd[5]; + + cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; + cmd[4] |= WSPI_INIT_CMD_END; + + t.tx_buf = cmd; + t.len = WSPI_INIT_CMD_LEN; + spi_message_add_tail(&t, &m); + + spi_sync(wl->spi, &m); + + wl12xx_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); +} + +/* Set the SPI partitions to access the chip addresses + * + * There are two VIRTUAL (SPI) partitions (the memory partition and the + * registers partition), which are mapped to two different areas of the + * PHYSICAL (hardware) memory. This function also makes other checks to + * ensure that the partitions are not overlapping. In the diagram below, the + * memory partition comes before the register partition, but the opposite is + * also supported. + * + * PHYSICAL address + * space + * + * | | + * ...+----+--> mem_start + * VIRTUAL address ... | | + * space ... | | [PART_0] + * ... | | + * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size + * | | ... | | + * |MEM | ... | | + * | | ... | | + * part_size <--+----+... | | {unused area) + * | | ... | | + * |REG | ... | | + * part_size | | ... | | + * + <--+----+... ...+----+--> reg_start + * reg_size ... | | + * ... | | [PART_1] + * ... | | + * ...+----+--> reg_start + reg_size + * | | + * + */ +int wl12xx_set_partition(struct wl12xx *wl, + u32 mem_start, u32 mem_size, + u32 reg_start, u32 reg_size) +{ + struct wl12xx_partition *partition; + struct spi_transfer t; + struct spi_message m; + size_t len, cmd_len; + u32 *cmd; + int addr; + + cmd_len = sizeof(u32) + 2 * sizeof(struct wl12xx_partition); + cmd = kzalloc(cmd_len, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + spi_message_init(&m); + memset(&t, 0, sizeof(t)); + + partition = (struct wl12xx_partition *) (cmd + 1); + addr = HW_ACCESS_PART0_SIZE_ADDR; + len = 2 * sizeof(struct wl12xx_partition); + + *cmd |= WSPI_CMD_WRITE; + *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; + + wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + + /* Make sure that the two partitions together don't exceed the + * address range */ + if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { + wl12xx_debug(DEBUG_SPI, "Total size exceeds maximum virtual" + " address range. Truncating partition[0]."); + mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; + wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } + + if ((mem_start < reg_start) && + ((mem_start + mem_size) > reg_start)) { + /* Guarantee that the memory partition doesn't overlap the + * registers partition */ + wl12xx_debug(DEBUG_SPI, "End of partition[0] is " + "overlapping partition[1]. Adjusted."); + mem_size = reg_start - mem_start; + wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } else if ((reg_start < mem_start) && + ((reg_start + reg_size) > mem_start)) { + /* Guarantee that the register partition doesn't overlap the + * memory partition */ + wl12xx_debug(DEBUG_SPI, "End of partition[1] is" + " overlapping partition[0]. Adjusted."); + reg_size = mem_start - reg_start; + wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } + + partition[0].start = mem_start; + partition[0].size = mem_size; + partition[1].start = reg_start; + partition[1].size = reg_size; + + wl->physical_mem_addr = mem_start; + wl->physical_reg_addr = reg_start; + + wl->virtual_mem_addr = 0; + wl->virtual_reg_addr = mem_size; + + t.tx_buf = cmd; + t.len = cmd_len; + spi_message_add_tail(&t, &m); + + spi_sync(wl->spi, &m); + + kfree(cmd); + + return 0; +} + +void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, + size_t len, bool fixed) +{ + struct spi_transfer t[3]; + struct spi_message m; + u8 *busy_buf; + u32 *cmd; + + cmd = &wl->buffer_cmd; + busy_buf = wl->buffer_busyword; + + *cmd = 0; + *cmd |= WSPI_CMD_READ; + *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; + + if (fixed) + *cmd |= WSPI_CMD_FIXED; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = cmd; + t[0].len = 4; + spi_message_add_tail(&t[0], &m); + + /* Busy and non busy words read */ + t[1].rx_buf = busy_buf; + t[1].len = WL12XX_BUSY_WORD_LEN; + spi_message_add_tail(&t[1], &m); + + t[2].rx_buf = buf; + t[2].len = len; + spi_message_add_tail(&t[2], &m); + + spi_sync(wl->spi, &m); + + /* FIXME: check busy words */ + + wl12xx_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); + wl12xx_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); +} + +void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, + size_t len, bool fixed) +{ + struct spi_transfer t[2]; + struct spi_message m; + u32 *cmd; + + cmd = &wl->buffer_cmd; + + *cmd = 0; + *cmd |= WSPI_CMD_WRITE; + *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; + + if (fixed) + *cmd |= WSPI_CMD_FIXED; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = cmd; + t[0].len = sizeof(*cmd); + spi_message_add_tail(&t[0], &m); + + t[1].tx_buf = buf; + t[1].len = len; + spi_message_add_tail(&t[1], &m); + + spi_sync(wl->spi, &m); + + wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); + wl12xx_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); +} + +void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, + size_t len) +{ + int physical; + + physical = wl12xx_translate_mem_addr(wl, addr); + + wl12xx_spi_read(wl, physical, buf, len, false); +} + +void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, + size_t len) +{ + int physical; + + physical = wl12xx_translate_mem_addr(wl, addr); + + wl12xx_spi_write(wl, physical, buf, len, false); +} + +void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, + bool fixed) +{ + int physical; + + physical = wl12xx_translate_reg_addr(wl, addr); + + wl12xx_spi_read(wl, physical, buf, len, fixed); +} + +void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len, + bool fixed) +{ + int physical; + + physical = wl12xx_translate_reg_addr(wl, addr); + + wl12xx_spi_write(wl, physical, buf, len, fixed); +} + +u32 wl12xx_mem_read32(struct wl12xx *wl, int addr) +{ + return wl12xx_read32(wl, wl12xx_translate_mem_addr(wl, addr)); +} + +void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val) +{ + wl12xx_write32(wl, wl12xx_translate_mem_addr(wl, addr), val); +} + +u32 wl12xx_reg_read32(struct wl12xx *wl, int addr) +{ + return wl12xx_read32(wl, wl12xx_translate_reg_addr(wl, addr)); +} + +void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val) +{ + wl12xx_write32(wl, wl12xx_translate_reg_addr(wl, addr), val); +} diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h new file mode 100644 index 00000000000..82b009c3e9e --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_spi.h @@ -0,0 +1,115 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_SPI_H__ +#define __WL12XX_SPI_H__ + +#include "wl1251_cmd.h" +#include "wl1251_acx.h" +#include "reg.h" + +#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 + +#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 +#define HW_ACCESS_PART0_START_ADDR 0x1FFC4 +#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 +#define HW_ACCESS_PART1_START_ADDR 0x1FFCC + +#define HW_ACCESS_REGISTER_SIZE 4 + +#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 + +#define WSPI_CMD_READ 0x40000000 +#define WSPI_CMD_WRITE 0x00000000 +#define WSPI_CMD_FIXED 0x20000000 +#define WSPI_CMD_BYTE_LENGTH 0x1FFE0000 +#define WSPI_CMD_BYTE_LENGTH_OFFSET 17 +#define WSPI_CMD_BYTE_ADDR 0x0001FFFF + +#define WSPI_INIT_CMD_CRC_LEN 5 + +#define WSPI_INIT_CMD_START 0x00 +#define WSPI_INIT_CMD_TX 0x40 +/* the extra bypass bit is sampled by the TNET as '1' */ +#define WSPI_INIT_CMD_BYPASS_BIT 0x80 +#define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07 +#define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80 +#define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00 +#define WSPI_INIT_CMD_IOD 0x40 +#define WSPI_INIT_CMD_IP 0x20 +#define WSPI_INIT_CMD_CS 0x10 +#define WSPI_INIT_CMD_WS 0x08 +#define WSPI_INIT_CMD_WSPI 0x01 +#define WSPI_INIT_CMD_END 0x01 + +#define WSPI_INIT_CMD_LEN 8 + +#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ + ((WL12XX_BUSY_WORD_LEN - 4) / sizeof(u32)) +#define HW_ACCESS_WSPI_INIT_CMD_MASK 0 + + +/* Raw target IO, address is not translated */ +void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, + size_t len, bool fixed); +void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, + size_t len, bool fixed); + +/* Memory target IO, address is tranlated to partition 0 */ +void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, size_t len); +void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, size_t len); +u32 wl12xx_mem_read32(struct wl12xx *wl, int addr); +void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val); + +/* Registers IO */ +void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, + bool fixed); +void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len, + bool fixed); +u32 wl12xx_reg_read32(struct wl12xx *wl, int addr); +void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val); + +/* INIT and RESET words */ +void wl12xx_spi_reset(struct wl12xx *wl); +void wl12xx_spi_init(struct wl12xx *wl); +int wl12xx_set_partition(struct wl12xx *wl, + u32 part_start, u32 part_size, + u32 reg_start, u32 reg_size); + +static inline u32 wl12xx_read32(struct wl12xx *wl, int addr) +{ + wl12xx_spi_read(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); + + return wl->buffer_32; +} + +static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val) +{ + wl->buffer_32 = val; + wl12xx_spi_write(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); +} + +#endif /* __WL12XX_SPI_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c index 10023fce103..c57330e36df 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c @@ -27,9 +27,9 @@ #include "wl12xx.h" #include "reg.h" -#include "spi.h" +#include "wl1251_spi.h" #include "wl1251_tx.h" -#include "ps.h" +#include "wl1251_ps.h" static bool wl1251_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count) { -- cgit v1.2.3-18-g5258 From 1367411858d5fc60b632a3f488f2b4adc73d12d7 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:17:25 +0300 Subject: wl1251: rename wl12xx.h to wl1251.h wl12xx.h is now only used by 1251 code, so we can rename it. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Reviewed-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/reg.h | 1 - drivers/net/wireless/wl12xx/wl1251.h | 420 +++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1251_acx.c | 2 +- drivers/net/wireless/wl12xx/wl1251_acx.h | 2 +- drivers/net/wireless/wl12xx/wl1251_boot.h | 2 +- drivers/net/wireless/wl12xx/wl1251_cmd.c | 2 +- drivers/net/wireless/wl12xx/wl1251_cmd.h | 2 +- drivers/net/wireless/wl12xx/wl1251_debugfs.c | 2 +- drivers/net/wireless/wl12xx/wl1251_debugfs.h | 2 +- drivers/net/wireless/wl12xx/wl1251_event.c | 2 +- drivers/net/wireless/wl12xx/wl1251_init.h | 2 +- drivers/net/wireless/wl12xx/wl1251_main.c | 2 +- drivers/net/wireless/wl12xx/wl1251_netlink.c | 2 +- drivers/net/wireless/wl12xx/wl1251_ops.h | 2 +- drivers/net/wireless/wl12xx/wl1251_ps.h | 2 +- drivers/net/wireless/wl12xx/wl1251_rx.c | 2 +- drivers/net/wireless/wl12xx/wl1251_rx.h | 2 + drivers/net/wireless/wl12xx/wl1251_spi.c | 2 +- drivers/net/wireless/wl12xx/wl1251_tx.c | 2 +- drivers/net/wireless/wl12xx/wl12xx.h | 420 --------------------------- 20 files changed, 438 insertions(+), 437 deletions(-) create mode 100644 drivers/net/wireless/wl12xx/wl1251.h delete mode 100644 drivers/net/wireless/wl12xx/wl12xx.h (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h index e421643215c..2de47cc32b8 100644 --- a/drivers/net/wireless/wl12xx/reg.h +++ b/drivers/net/wireless/wl12xx/reg.h @@ -26,7 +26,6 @@ #define __REG_H__ #include -#include "wl12xx.h" #define REGISTERS_BASE 0x00300000 #define DRPW_BASE 0x00310000 diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h new file mode 100644 index 00000000000..c673cdb42d6 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -0,0 +1,420 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_H__ +#define __WL12XX_H__ + +#include +#include +#include +#include + +#define DRIVER_NAME "wl12xx" +#define DRIVER_PREFIX DRIVER_NAME ": " + +enum { + DEBUG_NONE = 0, + DEBUG_IRQ = BIT(0), + DEBUG_SPI = BIT(1), + DEBUG_BOOT = BIT(2), + DEBUG_MAILBOX = BIT(3), + DEBUG_NETLINK = BIT(4), + DEBUG_EVENT = BIT(5), + DEBUG_TX = BIT(6), + DEBUG_RX = BIT(7), + DEBUG_SCAN = BIT(8), + DEBUG_CRYPT = BIT(9), + DEBUG_PSM = BIT(10), + DEBUG_MAC80211 = BIT(11), + DEBUG_CMD = BIT(12), + DEBUG_ACX = BIT(13), + DEBUG_ALL = ~0, +}; + +#define DEBUG_LEVEL (DEBUG_NONE) + +#define DEBUG_DUMP_LIMIT 1024 + +#define wl12xx_error(fmt, arg...) \ + printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) + +#define wl12xx_warning(fmt, arg...) \ + printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) + +#define wl12xx_notice(fmt, arg...) \ + printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) + +#define wl12xx_info(fmt, arg...) \ + printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) + +#define wl12xx_debug(level, fmt, arg...) \ + do { \ + if (level & DEBUG_LEVEL) \ + printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ + } while (0) + +#define wl12xx_dump(level, prefix, buf, len) \ + do { \ + if (level & DEBUG_LEVEL) \ + print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, \ + min_t(size_t, len, DEBUG_DUMP_LIMIT), \ + 0); \ + } while (0) + +#define wl12xx_dump_ascii(level, prefix, buf, len) \ + do { \ + if (level & DEBUG_LEVEL) \ + print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, \ + min_t(size_t, len, DEBUG_DUMP_LIMIT), \ + true); \ + } while (0) + +#define WL12XX_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ + CFG_BSSID_FILTER_EN) + +#define WL12XX_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \ + CFG_RX_MGMT_EN | \ + CFG_RX_DATA_EN | \ + CFG_RX_CTL_EN | \ + CFG_RX_BCN_EN | \ + CFG_RX_AUTH_EN | \ + CFG_RX_ASSOC_EN) + +#define WL12XX_BUSY_WORD_LEN 8 + +struct boot_attr { + u32 radio_type; + u8 mac_clock; + u8 arm_clock; + int firmware_debug; + u32 minor; + u32 major; + u32 bugfix; +}; + +enum wl12xx_state { + WL12XX_STATE_OFF, + WL12XX_STATE_ON, + WL12XX_STATE_PLT, +}; + +enum wl12xx_partition_type { + PART_DOWN, + PART_WORK, + PART_DRPW, + + PART_TABLE_LEN +}; + +struct wl12xx_partition { + u32 size; + u32 start; +}; + +struct wl12xx_partition_set { + struct wl12xx_partition mem; + struct wl12xx_partition reg; +}; + +struct wl12xx; + +/* FIXME: I'm not sure about this structure name */ +struct wl12xx_chip { + u32 id; + + const char *fw_filename; + const char *nvs_filename; + + char fw_ver[21]; + + unsigned int power_on_sleep; + int intr_cmd_complete; + int intr_init_complete; + + int (*op_upload_fw)(struct wl12xx *wl); + int (*op_upload_nvs)(struct wl12xx *wl); + int (*op_boot)(struct wl12xx *wl); + void (*op_set_ecpu_ctrl)(struct wl12xx *wl, u32 flag); + void (*op_target_enable_interrupts)(struct wl12xx *wl); + int (*op_hw_init)(struct wl12xx *wl); + int (*op_plt_init)(struct wl12xx *wl); + void (*op_tx_flush)(struct wl12xx *wl); + void (*op_fw_version)(struct wl12xx *wl); + int (*op_cmd_join)(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, + u16 beacon_interval, u8 wait); + + struct wl12xx_partition_set *p_table; + enum wl12xx_acx_int_reg *acx_reg_table; +}; + +struct wl12xx_stats { + struct acx_statistics *fw_stats; + unsigned long fw_stats_update; + + unsigned int retry_count; + unsigned int excessive_retries; +}; + +struct wl12xx_debugfs { + struct dentry *rootdir; + struct dentry *fw_statistics; + + struct dentry *tx_internal_desc_overflow; + + struct dentry *rx_out_of_mem; + struct dentry *rx_hdr_overflow; + struct dentry *rx_hw_stuck; + struct dentry *rx_dropped; + struct dentry *rx_fcs_err; + struct dentry *rx_xfr_hint_trig; + struct dentry *rx_path_reset; + struct dentry *rx_reset_counter; + + struct dentry *dma_rx_requested; + struct dentry *dma_rx_errors; + struct dentry *dma_tx_requested; + struct dentry *dma_tx_errors; + + struct dentry *isr_cmd_cmplt; + struct dentry *isr_fiqs; + struct dentry *isr_rx_headers; + struct dentry *isr_rx_mem_overflow; + struct dentry *isr_rx_rdys; + struct dentry *isr_irqs; + struct dentry *isr_tx_procs; + struct dentry *isr_decrypt_done; + struct dentry *isr_dma0_done; + struct dentry *isr_dma1_done; + struct dentry *isr_tx_exch_complete; + struct dentry *isr_commands; + struct dentry *isr_rx_procs; + struct dentry *isr_hw_pm_mode_changes; + struct dentry *isr_host_acknowledges; + struct dentry *isr_pci_pm; + struct dentry *isr_wakeups; + struct dentry *isr_low_rssi; + + struct dentry *wep_addr_key_count; + struct dentry *wep_default_key_count; + /* skipping wep.reserved */ + struct dentry *wep_key_not_found; + struct dentry *wep_decrypt_fail; + struct dentry *wep_packets; + struct dentry *wep_interrupt; + + struct dentry *pwr_ps_enter; + struct dentry *pwr_elp_enter; + struct dentry *pwr_missing_bcns; + struct dentry *pwr_wake_on_host; + struct dentry *pwr_wake_on_timer_exp; + struct dentry *pwr_tx_with_ps; + struct dentry *pwr_tx_without_ps; + struct dentry *pwr_rcvd_beacons; + struct dentry *pwr_power_save_off; + struct dentry *pwr_enable_ps; + struct dentry *pwr_disable_ps; + struct dentry *pwr_fix_tsf_ps; + /* skipping cont_miss_bcns_spread for now */ + struct dentry *pwr_rcvd_awake_beacons; + + struct dentry *mic_rx_pkts; + struct dentry *mic_calc_failure; + + struct dentry *aes_encrypt_fail; + struct dentry *aes_decrypt_fail; + struct dentry *aes_encrypt_packets; + struct dentry *aes_decrypt_packets; + struct dentry *aes_encrypt_interrupt; + struct dentry *aes_decrypt_interrupt; + + struct dentry *event_heart_beat; + struct dentry *event_calibration; + struct dentry *event_rx_mismatch; + struct dentry *event_rx_mem_empty; + struct dentry *event_rx_pool; + struct dentry *event_oom_late; + struct dentry *event_phy_transmit_error; + struct dentry *event_tx_stuck; + + struct dentry *ps_pspoll_timeouts; + struct dentry *ps_upsd_timeouts; + struct dentry *ps_upsd_max_sptime; + struct dentry *ps_upsd_max_apturn; + struct dentry *ps_pspoll_max_apturn; + struct dentry *ps_pspoll_utilization; + struct dentry *ps_upsd_utilization; + + struct dentry *rxpipe_rx_prep_beacon_drop; + struct dentry *rxpipe_descr_host_int_trig_rx_data; + struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data; + struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data; + struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data; + + struct dentry *tx_queue_len; + + struct dentry *retry_count; + struct dentry *excessive_retries; +}; + +struct wl12xx { + struct ieee80211_hw *hw; + bool mac80211_registered; + + struct spi_device *spi; + + void (*set_power)(bool enable); + int irq; + + enum wl12xx_state state; + struct mutex mutex; + + int physical_mem_addr; + int physical_reg_addr; + int virtual_mem_addr; + int virtual_reg_addr; + + struct wl12xx_chip chip; + + int cmd_box_addr; + int event_box_addr; + struct boot_attr boot_attr; + + u8 *fw; + size_t fw_len; + u8 *nvs; + size_t nvs_len; + + u8 bssid[ETH_ALEN]; + u8 mac_addr[ETH_ALEN]; + u8 bss_type; + u8 listen_int; + int channel; + + void *target_mem_map; + struct acx_data_path_params_resp *data_path; + + /* Number of TX packets transferred to the FW, modulo 16 */ + u32 data_in_count; + + /* Frames scheduled for transmission, not handled yet */ + struct sk_buff_head tx_queue; + bool tx_queue_stopped; + + struct work_struct tx_work; + struct work_struct filter_work; + + /* Pending TX frames */ + struct sk_buff *tx_frames[16]; + + /* + * Index pointing to the next TX complete entry + * in the cyclic XT complete array we get from + * the FW. + */ + u32 next_tx_complete; + + /* FW Rx counter */ + u32 rx_counter; + + /* Rx frames handled */ + u32 rx_handled; + + /* Current double buffer */ + u32 rx_current_buffer; + u32 rx_last_id; + + /* The target interrupt mask */ + u32 intr_mask; + struct work_struct irq_work; + + /* The mbox event mask */ + u32 event_mask; + + /* Mailbox pointers */ + u32 mbox_ptr[2]; + + /* Are we currently scanning */ + bool scanning; + + /* Our association ID */ + u16 aid; + + /* Default key (for WEP) */ + u32 default_key; + + unsigned int tx_mgmt_frm_rate; + unsigned int tx_mgmt_frm_mod; + + unsigned int rx_config; + unsigned int rx_filter; + + /* is firmware in elp mode */ + bool elp; + + /* we can be in psm, but not in elp, we have to differentiate */ + bool psm; + + /* PSM mode requested */ + bool psm_requested; + + /* in dBm */ + int power_level; + + struct wl12xx_stats stats; + struct wl12xx_debugfs debugfs; + + u32 buffer_32; + u32 buffer_cmd; + u8 buffer_busyword[WL12XX_BUSY_WORD_LEN]; + struct wl12xx_rx_descriptor *rx_descriptor; +}; + +int wl12xx_plt_start(struct wl12xx *wl); +int wl12xx_plt_stop(struct wl12xx *wl); + +#define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ +#define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS +#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ + +#define WL12XX_DEFAULT_POWER_LEVEL 20 + +#define WL12XX_TX_QUEUE_MAX_LENGTH 20 + +/* Different chips need different sleep times after power on. WL1271 needs + * 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we + * know the chip ID, we change the sleep value in the wl12xx chip structure, + * so in subsequent power ons, we don't waste more time then needed. */ +#define WL12XX_DEFAULT_POWER_ON_SLEEP 200 + +#define CHIP_ID_1251_PG10 (0x7010101) +#define CHIP_ID_1251_PG11 (0x7020101) +#define CHIP_ID_1251_PG12 (0x7030101) +#define CHIP_ID_1271_PG10 (0x4030101) +#define CHIP_ID_1271_PG20 (0x4030111) + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index cecc1fade3d..1a840fa16db 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -4,7 +4,7 @@ #include #include -#include "wl12xx.h" +#include "wl1251.h" #include "wl12xx_80211.h" #include "reg.h" #include "wl1251_spi.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h index 203f11fd6c2..a23912014b9 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.h +++ b/drivers/net/wireless/wl12xx/wl1251_acx.h @@ -25,7 +25,7 @@ #ifndef __WL12XX_ACX_H__ #define __WL12XX_ACX_H__ -#include "wl12xx.h" +#include "wl1251.h" #include "wl1251_cmd.h" /* Target's information element */ diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.h b/drivers/net/wireless/wl12xx/wl1251_boot.h index 4fa73132baa..3e2b7668878 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.h +++ b/drivers/net/wireless/wl12xx/wl1251_boot.h @@ -24,7 +24,7 @@ #ifndef __BOOT_H__ #define __BOOT_H__ -#include "wl12xx.h" +#include "wl1251.h" int wl12xx_boot_soft_reset(struct wl12xx *wl); int wl12xx_boot_init_seq(struct wl12xx *wl); diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index d0c2df6b519..92c7fb6853e 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -4,7 +4,7 @@ #include #include -#include "wl12xx.h" +#include "wl1251.h" #include "wl12xx_80211.h" #include "reg.h" #include "wl1251_spi.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h index a2eae54a241..b252ad25ee2 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h @@ -25,7 +25,7 @@ #ifndef __WL12XX_CMD_H__ #define __WL12XX_CMD_H__ -#include "wl12xx.h" +#include "wl1251.h" struct acx_header; diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.c b/drivers/net/wireless/wl12xx/wl1251_debugfs.c index a63bc78bfbc..866303dd687 100644 --- a/drivers/net/wireless/wl12xx/wl1251_debugfs.c +++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.c @@ -25,7 +25,7 @@ #include -#include "wl12xx.h" +#include "wl1251.h" #include "wl1251_acx.h" #include "wl1251_ps.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.h b/drivers/net/wireless/wl12xx/wl1251_debugfs.h index 562cdcbcc87..37653eb0cd0 100644 --- a/drivers/net/wireless/wl12xx/wl1251_debugfs.h +++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.h @@ -24,7 +24,7 @@ #ifndef WL12XX_DEBUGFS_H #define WL12XX_DEBUGFS_H -#include "wl12xx.h" +#include "wl1251.h" int wl12xx_debugfs_init(struct wl12xx *wl); void wl12xx_debugfs_exit(struct wl12xx *wl); diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl12xx/wl1251_event.c index 50b5e43d8f3..a6d92349add 100644 --- a/drivers/net/wireless/wl12xx/wl1251_event.c +++ b/drivers/net/wireless/wl12xx/wl1251_event.c @@ -22,7 +22,7 @@ * */ -#include "wl12xx.h" +#include "wl1251.h" #include "reg.h" #include "wl1251_spi.h" #include "wl1251_event.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl12xx/wl1251_init.h index c8b6cd0b7c3..5b3301ae009 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.h +++ b/drivers/net/wireless/wl12xx/wl1251_init.h @@ -24,7 +24,7 @@ #ifndef __WL12XX_INIT_H__ #define __WL12XX_INIT_H__ -#include "wl12xx.h" +#include "wl1251.h" int wl12xx_hw_init_hwenc_config(struct wl12xx *wl); int wl12xx_hw_init_templates_config(struct wl12xx *wl); diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 16cd46c7164..41b9c616ee8 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -31,7 +31,7 @@ #include #include -#include "wl12xx.h" +#include "wl1251.h" #include "wl12xx_80211.h" #include "reg.h" #include "wl1251_ops.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.c b/drivers/net/wireless/wl12xx/wl1251_netlink.c index 1bc049fa2ba..ca9a8567d58 100644 --- a/drivers/net/wireless/wl12xx/wl1251_netlink.c +++ b/drivers/net/wireless/wl12xx/wl1251_netlink.c @@ -30,7 +30,7 @@ #include #include -#include "wl12xx.h" +#include "wl1251.h" #include "wl1251_spi.h" #include "wl1251_acx.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.h b/drivers/net/wireless/wl12xx/wl1251_ops.h index 7a78cc9e699..c5c997bb64d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ops.h +++ b/drivers/net/wireless/wl12xx/wl1251_ops.h @@ -26,7 +26,7 @@ #include -#include "wl12xx.h" +#include "wl1251.h" #include "wl1251_acx.h" #define WL1251_FW_NAME "wl1251-fw.bin" diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.h b/drivers/net/wireless/wl12xx/wl1251_ps.h index db9f7ed9dd1..8877842baf1 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.h +++ b/drivers/net/wireless/wl12xx/wl1251_ps.h @@ -25,7 +25,7 @@ * */ -#include "wl12xx.h" +#include "wl1251.h" #include "wl1251_acx.h" int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode); diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c index d73e014d611..280fc1843f8 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.c +++ b/drivers/net/wireless/wl12xx/wl1251_rx.c @@ -25,7 +25,7 @@ #include #include -#include "wl12xx.h" +#include "wl1251.h" #include "reg.h" #include "wl1251_spi.h" #include "wl1251_rx.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.h b/drivers/net/wireless/wl12xx/wl1251_rx.h index 8a23fdea501..4379c539538 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.h +++ b/drivers/net/wireless/wl12xx/wl1251_rx.h @@ -27,6 +27,8 @@ #include +#include "wl1251.h" + /* * RX PATH * diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index d7eee8ce7ef..5b4889e351d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -25,7 +25,7 @@ #include #include -#include "wl12xx.h" +#include "wl1251.h" #include "wl12xx_80211.h" #include "reg.h" #include "wl1251_spi.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c index c57330e36df..00c5649d909 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c @@ -25,7 +25,7 @@ #include #include -#include "wl12xx.h" +#include "wl1251.h" #include "reg.h" #include "wl1251_spi.h" #include "wl1251_tx.h" diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h deleted file mode 100644 index c673cdb42d6..00000000000 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ /dev/null @@ -1,420 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL12XX_H__ -#define __WL12XX_H__ - -#include -#include -#include -#include - -#define DRIVER_NAME "wl12xx" -#define DRIVER_PREFIX DRIVER_NAME ": " - -enum { - DEBUG_NONE = 0, - DEBUG_IRQ = BIT(0), - DEBUG_SPI = BIT(1), - DEBUG_BOOT = BIT(2), - DEBUG_MAILBOX = BIT(3), - DEBUG_NETLINK = BIT(4), - DEBUG_EVENT = BIT(5), - DEBUG_TX = BIT(6), - DEBUG_RX = BIT(7), - DEBUG_SCAN = BIT(8), - DEBUG_CRYPT = BIT(9), - DEBUG_PSM = BIT(10), - DEBUG_MAC80211 = BIT(11), - DEBUG_CMD = BIT(12), - DEBUG_ACX = BIT(13), - DEBUG_ALL = ~0, -}; - -#define DEBUG_LEVEL (DEBUG_NONE) - -#define DEBUG_DUMP_LIMIT 1024 - -#define wl12xx_error(fmt, arg...) \ - printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) - -#define wl12xx_warning(fmt, arg...) \ - printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) - -#define wl12xx_notice(fmt, arg...) \ - printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) - -#define wl12xx_info(fmt, arg...) \ - printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) - -#define wl12xx_debug(level, fmt, arg...) \ - do { \ - if (level & DEBUG_LEVEL) \ - printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ - } while (0) - -#define wl12xx_dump(level, prefix, buf, len) \ - do { \ - if (level & DEBUG_LEVEL) \ - print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ - DUMP_PREFIX_OFFSET, 16, 1, \ - buf, \ - min_t(size_t, len, DEBUG_DUMP_LIMIT), \ - 0); \ - } while (0) - -#define wl12xx_dump_ascii(level, prefix, buf, len) \ - do { \ - if (level & DEBUG_LEVEL) \ - print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ - DUMP_PREFIX_OFFSET, 16, 1, \ - buf, \ - min_t(size_t, len, DEBUG_DUMP_LIMIT), \ - true); \ - } while (0) - -#define WL12XX_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ - CFG_BSSID_FILTER_EN) - -#define WL12XX_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \ - CFG_RX_MGMT_EN | \ - CFG_RX_DATA_EN | \ - CFG_RX_CTL_EN | \ - CFG_RX_BCN_EN | \ - CFG_RX_AUTH_EN | \ - CFG_RX_ASSOC_EN) - -#define WL12XX_BUSY_WORD_LEN 8 - -struct boot_attr { - u32 radio_type; - u8 mac_clock; - u8 arm_clock; - int firmware_debug; - u32 minor; - u32 major; - u32 bugfix; -}; - -enum wl12xx_state { - WL12XX_STATE_OFF, - WL12XX_STATE_ON, - WL12XX_STATE_PLT, -}; - -enum wl12xx_partition_type { - PART_DOWN, - PART_WORK, - PART_DRPW, - - PART_TABLE_LEN -}; - -struct wl12xx_partition { - u32 size; - u32 start; -}; - -struct wl12xx_partition_set { - struct wl12xx_partition mem; - struct wl12xx_partition reg; -}; - -struct wl12xx; - -/* FIXME: I'm not sure about this structure name */ -struct wl12xx_chip { - u32 id; - - const char *fw_filename; - const char *nvs_filename; - - char fw_ver[21]; - - unsigned int power_on_sleep; - int intr_cmd_complete; - int intr_init_complete; - - int (*op_upload_fw)(struct wl12xx *wl); - int (*op_upload_nvs)(struct wl12xx *wl); - int (*op_boot)(struct wl12xx *wl); - void (*op_set_ecpu_ctrl)(struct wl12xx *wl, u32 flag); - void (*op_target_enable_interrupts)(struct wl12xx *wl); - int (*op_hw_init)(struct wl12xx *wl); - int (*op_plt_init)(struct wl12xx *wl); - void (*op_tx_flush)(struct wl12xx *wl); - void (*op_fw_version)(struct wl12xx *wl); - int (*op_cmd_join)(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, - u16 beacon_interval, u8 wait); - - struct wl12xx_partition_set *p_table; - enum wl12xx_acx_int_reg *acx_reg_table; -}; - -struct wl12xx_stats { - struct acx_statistics *fw_stats; - unsigned long fw_stats_update; - - unsigned int retry_count; - unsigned int excessive_retries; -}; - -struct wl12xx_debugfs { - struct dentry *rootdir; - struct dentry *fw_statistics; - - struct dentry *tx_internal_desc_overflow; - - struct dentry *rx_out_of_mem; - struct dentry *rx_hdr_overflow; - struct dentry *rx_hw_stuck; - struct dentry *rx_dropped; - struct dentry *rx_fcs_err; - struct dentry *rx_xfr_hint_trig; - struct dentry *rx_path_reset; - struct dentry *rx_reset_counter; - - struct dentry *dma_rx_requested; - struct dentry *dma_rx_errors; - struct dentry *dma_tx_requested; - struct dentry *dma_tx_errors; - - struct dentry *isr_cmd_cmplt; - struct dentry *isr_fiqs; - struct dentry *isr_rx_headers; - struct dentry *isr_rx_mem_overflow; - struct dentry *isr_rx_rdys; - struct dentry *isr_irqs; - struct dentry *isr_tx_procs; - struct dentry *isr_decrypt_done; - struct dentry *isr_dma0_done; - struct dentry *isr_dma1_done; - struct dentry *isr_tx_exch_complete; - struct dentry *isr_commands; - struct dentry *isr_rx_procs; - struct dentry *isr_hw_pm_mode_changes; - struct dentry *isr_host_acknowledges; - struct dentry *isr_pci_pm; - struct dentry *isr_wakeups; - struct dentry *isr_low_rssi; - - struct dentry *wep_addr_key_count; - struct dentry *wep_default_key_count; - /* skipping wep.reserved */ - struct dentry *wep_key_not_found; - struct dentry *wep_decrypt_fail; - struct dentry *wep_packets; - struct dentry *wep_interrupt; - - struct dentry *pwr_ps_enter; - struct dentry *pwr_elp_enter; - struct dentry *pwr_missing_bcns; - struct dentry *pwr_wake_on_host; - struct dentry *pwr_wake_on_timer_exp; - struct dentry *pwr_tx_with_ps; - struct dentry *pwr_tx_without_ps; - struct dentry *pwr_rcvd_beacons; - struct dentry *pwr_power_save_off; - struct dentry *pwr_enable_ps; - struct dentry *pwr_disable_ps; - struct dentry *pwr_fix_tsf_ps; - /* skipping cont_miss_bcns_spread for now */ - struct dentry *pwr_rcvd_awake_beacons; - - struct dentry *mic_rx_pkts; - struct dentry *mic_calc_failure; - - struct dentry *aes_encrypt_fail; - struct dentry *aes_decrypt_fail; - struct dentry *aes_encrypt_packets; - struct dentry *aes_decrypt_packets; - struct dentry *aes_encrypt_interrupt; - struct dentry *aes_decrypt_interrupt; - - struct dentry *event_heart_beat; - struct dentry *event_calibration; - struct dentry *event_rx_mismatch; - struct dentry *event_rx_mem_empty; - struct dentry *event_rx_pool; - struct dentry *event_oom_late; - struct dentry *event_phy_transmit_error; - struct dentry *event_tx_stuck; - - struct dentry *ps_pspoll_timeouts; - struct dentry *ps_upsd_timeouts; - struct dentry *ps_upsd_max_sptime; - struct dentry *ps_upsd_max_apturn; - struct dentry *ps_pspoll_max_apturn; - struct dentry *ps_pspoll_utilization; - struct dentry *ps_upsd_utilization; - - struct dentry *rxpipe_rx_prep_beacon_drop; - struct dentry *rxpipe_descr_host_int_trig_rx_data; - struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data; - struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data; - struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data; - - struct dentry *tx_queue_len; - - struct dentry *retry_count; - struct dentry *excessive_retries; -}; - -struct wl12xx { - struct ieee80211_hw *hw; - bool mac80211_registered; - - struct spi_device *spi; - - void (*set_power)(bool enable); - int irq; - - enum wl12xx_state state; - struct mutex mutex; - - int physical_mem_addr; - int physical_reg_addr; - int virtual_mem_addr; - int virtual_reg_addr; - - struct wl12xx_chip chip; - - int cmd_box_addr; - int event_box_addr; - struct boot_attr boot_attr; - - u8 *fw; - size_t fw_len; - u8 *nvs; - size_t nvs_len; - - u8 bssid[ETH_ALEN]; - u8 mac_addr[ETH_ALEN]; - u8 bss_type; - u8 listen_int; - int channel; - - void *target_mem_map; - struct acx_data_path_params_resp *data_path; - - /* Number of TX packets transferred to the FW, modulo 16 */ - u32 data_in_count; - - /* Frames scheduled for transmission, not handled yet */ - struct sk_buff_head tx_queue; - bool tx_queue_stopped; - - struct work_struct tx_work; - struct work_struct filter_work; - - /* Pending TX frames */ - struct sk_buff *tx_frames[16]; - - /* - * Index pointing to the next TX complete entry - * in the cyclic XT complete array we get from - * the FW. - */ - u32 next_tx_complete; - - /* FW Rx counter */ - u32 rx_counter; - - /* Rx frames handled */ - u32 rx_handled; - - /* Current double buffer */ - u32 rx_current_buffer; - u32 rx_last_id; - - /* The target interrupt mask */ - u32 intr_mask; - struct work_struct irq_work; - - /* The mbox event mask */ - u32 event_mask; - - /* Mailbox pointers */ - u32 mbox_ptr[2]; - - /* Are we currently scanning */ - bool scanning; - - /* Our association ID */ - u16 aid; - - /* Default key (for WEP) */ - u32 default_key; - - unsigned int tx_mgmt_frm_rate; - unsigned int tx_mgmt_frm_mod; - - unsigned int rx_config; - unsigned int rx_filter; - - /* is firmware in elp mode */ - bool elp; - - /* we can be in psm, but not in elp, we have to differentiate */ - bool psm; - - /* PSM mode requested */ - bool psm_requested; - - /* in dBm */ - int power_level; - - struct wl12xx_stats stats; - struct wl12xx_debugfs debugfs; - - u32 buffer_32; - u32 buffer_cmd; - u8 buffer_busyword[WL12XX_BUSY_WORD_LEN]; - struct wl12xx_rx_descriptor *rx_descriptor; -}; - -int wl12xx_plt_start(struct wl12xx *wl); -int wl12xx_plt_stop(struct wl12xx *wl); - -#define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ -#define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS -#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ - -#define WL12XX_DEFAULT_POWER_LEVEL 20 - -#define WL12XX_TX_QUEUE_MAX_LENGTH 20 - -/* Different chips need different sleep times after power on. WL1271 needs - * 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we - * know the chip ID, we change the sleep value in the wl12xx chip structure, - * so in subsequent power ons, we don't waste more time then needed. */ -#define WL12XX_DEFAULT_POWER_ON_SLEEP 200 - -#define CHIP_ID_1251_PG10 (0x7010101) -#define CHIP_ID_1251_PG11 (0x7020101) -#define CHIP_ID_1251_PG12 (0x7030101) -#define CHIP_ID_1271_PG10 (0x4030101) -#define CHIP_ID_1271_PG20 (0x4030111) - -#endif -- cgit v1.2.3-18-g5258 From 1e6f172fccbf1194bad4b2aeae437ec3189a3f08 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:17:33 +0300 Subject: wl12xx: remove unused wl12xx_hw_init_mem_config() The function declaration is a leftover from some earlier, already removed, code. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Reviewed-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_init.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl12xx/wl1251_init.h index 5b3301ae009..2b6268e1855 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.h +++ b/drivers/net/wireless/wl12xx/wl1251_init.h @@ -28,7 +28,6 @@ int wl12xx_hw_init_hwenc_config(struct wl12xx *wl); int wl12xx_hw_init_templates_config(struct wl12xx *wl); -int wl12xx_hw_init_mem_config(struct wl12xx *wl); int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter); int wl12xx_hw_init_phy_config(struct wl12xx *wl); int wl12xx_hw_init_beacon_filter(struct wl12xx *wl); -- cgit v1.2.3-18-g5258 From 80301cdcfe44e3533175be23d7d52a9fc8c3fdb0 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:17:39 +0300 Subject: wl1251: use wl1251 prefix everywhere Last we can change all code prefixes from wl12xx/WL12XX to wl1251/WL1251. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Reviewed-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251.h | 102 +++--- drivers/net/wireless/wl12xx/wl1251_acx.c | 229 +++++++------ drivers/net/wireless/wl12xx/wl1251_acx.h | 76 ++--- drivers/net/wireless/wl12xx/wl1251_boot.c | 106 +++--- drivers/net/wireless/wl12xx/wl1251_boot.h | 10 +- drivers/net/wireless/wl12xx/wl1251_cmd.c | 133 ++++---- drivers/net/wireless/wl12xx/wl1251_cmd.h | 78 ++--- drivers/net/wireless/wl12xx/wl1251_debugfs.c | 48 +-- drivers/net/wireless/wl12xx/wl1251_debugfs.h | 14 +- drivers/net/wireless/wl12xx/wl1251_event.c | 46 +-- drivers/net/wireless/wl12xx/wl1251_event.h | 12 +- drivers/net/wireless/wl12xx/wl1251_init.c | 72 ++-- drivers/net/wireless/wl12xx/wl1251_init.h | 24 +- drivers/net/wireless/wl12xx/wl1251_main.c | 477 ++++++++++++++------------- drivers/net/wireless/wl12xx/wl1251_netlink.c | 400 +++++++++++----------- drivers/net/wireless/wl12xx/wl1251_netlink.h | 12 +- drivers/net/wireless/wl12xx/wl1251_ops.c | 190 +++++------ drivers/net/wireless/wl12xx/wl1251_ops.h | 4 +- drivers/net/wireless/wl12xx/wl1251_ps.c | 56 ++-- drivers/net/wireless/wl12xx/wl1251_ps.h | 14 +- drivers/net/wireless/wl12xx/wl1251_rx.c | 52 +-- drivers/net/wireless/wl12xx/wl1251_rx.h | 20 +- drivers/net/wireless/wl12xx/wl1251_spi.c | 107 +++--- drivers/net/wireless/wl12xx/wl1251_spi.h | 44 +-- drivers/net/wireless/wl12xx/wl1251_tx.c | 70 ++-- drivers/net/wireless/wl12xx/wl1251_tx.h | 6 +- 26 files changed, 1203 insertions(+), 1199 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index c673cdb42d6..665aca02bea 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008-2009 Nokia Corporation @@ -22,15 +22,15 @@ * */ -#ifndef __WL12XX_H__ -#define __WL12XX_H__ +#ifndef __WL1251_H__ +#define __WL1251_H__ #include #include #include #include -#define DRIVER_NAME "wl12xx" +#define DRIVER_NAME "wl1251" #define DRIVER_PREFIX DRIVER_NAME ": " enum { @@ -56,25 +56,25 @@ enum { #define DEBUG_DUMP_LIMIT 1024 -#define wl12xx_error(fmt, arg...) \ +#define wl1251_error(fmt, arg...) \ printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) -#define wl12xx_warning(fmt, arg...) \ +#define wl1251_warning(fmt, arg...) \ printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) -#define wl12xx_notice(fmt, arg...) \ +#define wl1251_notice(fmt, arg...) \ printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) -#define wl12xx_info(fmt, arg...) \ +#define wl1251_info(fmt, arg...) \ printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) -#define wl12xx_debug(level, fmt, arg...) \ +#define wl1251_debug(level, fmt, arg...) \ do { \ if (level & DEBUG_LEVEL) \ printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ } while (0) -#define wl12xx_dump(level, prefix, buf, len) \ +#define wl1251_dump(level, prefix, buf, len) \ do { \ if (level & DEBUG_LEVEL) \ print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ @@ -84,7 +84,7 @@ enum { 0); \ } while (0) -#define wl12xx_dump_ascii(level, prefix, buf, len) \ +#define wl1251_dump_ascii(level, prefix, buf, len) \ do { \ if (level & DEBUG_LEVEL) \ print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ @@ -94,10 +94,10 @@ enum { true); \ } while (0) -#define WL12XX_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ +#define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ CFG_BSSID_FILTER_EN) -#define WL12XX_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \ +#define WL1251_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \ CFG_RX_MGMT_EN | \ CFG_RX_DATA_EN | \ CFG_RX_CTL_EN | \ @@ -105,7 +105,7 @@ enum { CFG_RX_AUTH_EN | \ CFG_RX_ASSOC_EN) -#define WL12XX_BUSY_WORD_LEN 8 +#define WL1251_BUSY_WORD_LEN 8 struct boot_attr { u32 radio_type; @@ -117,13 +117,13 @@ struct boot_attr { u32 bugfix; }; -enum wl12xx_state { - WL12XX_STATE_OFF, - WL12XX_STATE_ON, - WL12XX_STATE_PLT, +enum wl1251_state { + WL1251_STATE_OFF, + WL1251_STATE_ON, + WL1251_STATE_PLT, }; -enum wl12xx_partition_type { +enum wl1251_partition_type { PART_DOWN, PART_WORK, PART_DRPW, @@ -131,20 +131,20 @@ enum wl12xx_partition_type { PART_TABLE_LEN }; -struct wl12xx_partition { +struct wl1251_partition { u32 size; u32 start; }; -struct wl12xx_partition_set { - struct wl12xx_partition mem; - struct wl12xx_partition reg; +struct wl1251_partition_set { + struct wl1251_partition mem; + struct wl1251_partition reg; }; -struct wl12xx; +struct wl1251; /* FIXME: I'm not sure about this structure name */ -struct wl12xx_chip { +struct wl1251_chip { u32 id; const char *fw_filename; @@ -156,23 +156,23 @@ struct wl12xx_chip { int intr_cmd_complete; int intr_init_complete; - int (*op_upload_fw)(struct wl12xx *wl); - int (*op_upload_nvs)(struct wl12xx *wl); - int (*op_boot)(struct wl12xx *wl); - void (*op_set_ecpu_ctrl)(struct wl12xx *wl, u32 flag); - void (*op_target_enable_interrupts)(struct wl12xx *wl); - int (*op_hw_init)(struct wl12xx *wl); - int (*op_plt_init)(struct wl12xx *wl); - void (*op_tx_flush)(struct wl12xx *wl); - void (*op_fw_version)(struct wl12xx *wl); - int (*op_cmd_join)(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, + int (*op_upload_fw)(struct wl1251 *wl); + int (*op_upload_nvs)(struct wl1251 *wl); + int (*op_boot)(struct wl1251 *wl); + void (*op_set_ecpu_ctrl)(struct wl1251 *wl, u32 flag); + void (*op_target_enable_interrupts)(struct wl1251 *wl); + int (*op_hw_init)(struct wl1251 *wl); + int (*op_plt_init)(struct wl1251 *wl); + void (*op_tx_flush)(struct wl1251 *wl); + void (*op_fw_version)(struct wl1251 *wl); + int (*op_cmd_join)(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, u16 beacon_interval, u8 wait); - struct wl12xx_partition_set *p_table; + struct wl1251_partition_set *p_table; enum wl12xx_acx_int_reg *acx_reg_table; }; -struct wl12xx_stats { +struct wl1251_stats { struct acx_statistics *fw_stats; unsigned long fw_stats_update; @@ -180,7 +180,7 @@ struct wl12xx_stats { unsigned int excessive_retries; }; -struct wl12xx_debugfs { +struct wl1251_debugfs { struct dentry *rootdir; struct dentry *fw_statistics; @@ -281,7 +281,7 @@ struct wl12xx_debugfs { struct dentry *excessive_retries; }; -struct wl12xx { +struct wl1251 { struct ieee80211_hw *hw; bool mac80211_registered; @@ -290,7 +290,7 @@ struct wl12xx { void (*set_power)(bool enable); int irq; - enum wl12xx_state state; + enum wl1251_state state; struct mutex mutex; int physical_mem_addr; @@ -298,7 +298,7 @@ struct wl12xx { int virtual_mem_addr; int virtual_reg_addr; - struct wl12xx_chip chip; + struct wl1251_chip chip; int cmd_box_addr; int event_box_addr; @@ -385,31 +385,31 @@ struct wl12xx { /* in dBm */ int power_level; - struct wl12xx_stats stats; - struct wl12xx_debugfs debugfs; + struct wl1251_stats stats; + struct wl1251_debugfs debugfs; u32 buffer_32; u32 buffer_cmd; - u8 buffer_busyword[WL12XX_BUSY_WORD_LEN]; - struct wl12xx_rx_descriptor *rx_descriptor; + u8 buffer_busyword[WL1251_BUSY_WORD_LEN]; + struct wl1251_rx_descriptor *rx_descriptor; }; -int wl12xx_plt_start(struct wl12xx *wl); -int wl12xx_plt_stop(struct wl12xx *wl); +int wl1251_plt_start(struct wl1251 *wl); +int wl1251_plt_stop(struct wl1251 *wl); #define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ #define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ -#define WL12XX_DEFAULT_POWER_LEVEL 20 +#define WL1251_DEFAULT_POWER_LEVEL 20 -#define WL12XX_TX_QUEUE_MAX_LENGTH 20 +#define WL1251_TX_QUEUE_MAX_LENGTH 20 /* Different chips need different sleep times after power on. WL1271 needs * 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we - * know the chip ID, we change the sleep value in the wl12xx chip structure, + * know the chip ID, we change the sleep value in the wl1251 chip structure, * so in subsequent power ons, we don't waste more time then needed. */ -#define WL12XX_DEFAULT_POWER_ON_SLEEP 200 +#define WL1251_DEFAULT_POWER_ON_SLEEP 200 #define CHIP_ID_1251_PG10 (0x7010101) #define CHIP_ID_1251_PG11 (0x7020101) diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index 1a840fa16db..5a8d21c3192 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -5,18 +5,17 @@ #include #include "wl1251.h" -#include "wl12xx_80211.h" #include "reg.h" #include "wl1251_spi.h" #include "wl1251_ps.h" -int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, +int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, u8 mgt_rate, u8 mgt_mod) { struct acx_fw_gen_frame_rates *rates; int ret; - wl12xx_debug(DEBUG_ACX, "acx frame rates"); + wl1251_debug(DEBUG_ACX, "acx frame rates"); rates = kzalloc(sizeof(*rates), GFP_KERNEL); if (!rates) { @@ -29,10 +28,10 @@ int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, rates->tx_mgt_frame_rate = mgt_rate; rates->tx_mgt_frame_mod = mgt_mod; - ret = wl12xx_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES, + ret = wl1251_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES, rates, sizeof(*rates)); if (ret < 0) { - wl12xx_error("Failed to set FW rates and modulation"); + wl1251_error("Failed to set FW rates and modulation"); goto out; } @@ -42,12 +41,12 @@ out: } -int wl12xx_acx_station_id(struct wl12xx *wl) +int wl1251_acx_station_id(struct wl1251 *wl) { struct acx_dot11_station_id *mac; int ret, i; - wl12xx_debug(DEBUG_ACX, "acx dot11_station_id"); + wl1251_debug(DEBUG_ACX, "acx dot11_station_id"); mac = kzalloc(sizeof(*mac), GFP_KERNEL); if (!mac) { @@ -58,7 +57,7 @@ int wl12xx_acx_station_id(struct wl12xx *wl) for (i = 0; i < ETH_ALEN; i++) mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; - ret = wl12xx_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac)); + ret = wl1251_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac)); if (ret < 0) goto out; @@ -67,12 +66,12 @@ out: return ret; } -int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id) +int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id) { struct acx_dot11_default_key *default_key; int ret; - wl12xx_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id); + wl1251_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id); default_key = kzalloc(sizeof(*default_key), GFP_KERNEL); if (!default_key) { @@ -82,10 +81,10 @@ int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id) default_key->id = key_id; - ret = wl12xx_cmd_configure(wl, DOT11_DEFAULT_KEY, + ret = wl1251_cmd_configure(wl, DOT11_DEFAULT_KEY, default_key, sizeof(*default_key)); if (ret < 0) { - wl12xx_error("Couldnt set default key"); + wl1251_error("Couldnt set default key"); goto out; } @@ -96,13 +95,13 @@ out: return ret; } -int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 wake_up_event, +int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event, u8 listen_interval) { struct acx_wake_up_condition *wake_up; int ret; - wl12xx_debug(DEBUG_ACX, "acx wake up conditions"); + wl1251_debug(DEBUG_ACX, "acx wake up conditions"); wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); if (!wake_up) { @@ -113,10 +112,10 @@ int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 wake_up_event, wake_up->wake_up_event = wake_up_event; wake_up->listen_interval = listen_interval; - ret = wl12xx_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, + ret = wl1251_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, wake_up, sizeof(*wake_up)); if (ret < 0) { - wl12xx_warning("could not set wake up conditions: %d", ret); + wl1251_warning("could not set wake up conditions: %d", ret); goto out; } @@ -125,12 +124,12 @@ out: return ret; } -int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth) +int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth) { struct acx_sleep_auth *auth; int ret; - wl12xx_debug(DEBUG_ACX, "acx sleep auth"); + wl1251_debug(DEBUG_ACX, "acx sleep auth"); auth = kzalloc(sizeof(*auth), GFP_KERNEL); if (!auth) { @@ -140,7 +139,7 @@ int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth) auth->sleep_auth = sleep_auth; - ret = wl12xx_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); + ret = wl1251_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); if (ret < 0) return ret; @@ -149,12 +148,12 @@ out: return ret; } -int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len) +int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len) { struct acx_revision *rev; int ret; - wl12xx_debug(DEBUG_ACX, "acx fw rev"); + wl1251_debug(DEBUG_ACX, "acx fw rev"); rev = kzalloc(sizeof(*rev), GFP_KERNEL); if (!rev) { @@ -162,9 +161,9 @@ int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len) goto out; } - ret = wl12xx_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); + ret = wl1251_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); if (ret < 0) { - wl12xx_warning("ACX_FW_REV interrogate failed"); + wl1251_warning("ACX_FW_REV interrogate failed"); goto out; } @@ -183,12 +182,12 @@ out: return ret; } -int wl12xx_acx_tx_power(struct wl12xx *wl, int power) +int wl1251_acx_tx_power(struct wl1251 *wl, int power) { struct acx_current_tx_power *acx; int ret; - wl12xx_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); + wl1251_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); if (power < 0 || power > 25) return -EINVAL; @@ -201,9 +200,9 @@ int wl12xx_acx_tx_power(struct wl12xx *wl, int power) acx->current_tx_power = power * 10; - ret = wl12xx_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); + ret = wl1251_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); if (ret < 0) { - wl12xx_warning("configure of tx power failed: %d", ret); + wl1251_warning("configure of tx power failed: %d", ret); goto out; } @@ -212,12 +211,12 @@ out: return ret; } -int wl12xx_acx_feature_cfg(struct wl12xx *wl) +int wl1251_acx_feature_cfg(struct wl1251 *wl) { struct acx_feature_config *feature; int ret; - wl12xx_debug(DEBUG_ACX, "acx feature cfg"); + wl1251_debug(DEBUG_ACX, "acx feature cfg"); feature = kzalloc(sizeof(*feature), GFP_KERNEL); if (!feature) { @@ -229,10 +228,10 @@ int wl12xx_acx_feature_cfg(struct wl12xx *wl) feature->data_flow_options = 0; feature->options = 0; - ret = wl12xx_cmd_configure(wl, ACX_FEATURE_CFG, + ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG, feature, sizeof(*feature)); if (ret < 0) { - wl12xx_error("Couldnt set HW encryption"); + wl1251_error("Couldnt set HW encryption"); goto out; } @@ -241,27 +240,27 @@ out: return ret; } -int wl12xx_acx_mem_map(struct wl12xx *wl, struct acx_header *mem_map, +int wl1251_acx_mem_map(struct wl1251 *wl, struct acx_header *mem_map, size_t len) { int ret; - wl12xx_debug(DEBUG_ACX, "acx mem map"); + wl1251_debug(DEBUG_ACX, "acx mem map"); - ret = wl12xx_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); + ret = wl1251_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); if (ret < 0) return ret; return 0; } -int wl12xx_acx_data_path_params(struct wl12xx *wl, +int wl1251_acx_data_path_params(struct wl1251 *wl, struct acx_data_path_params_resp *resp) { struct acx_data_path_params *params; int ret; - wl12xx_debug(DEBUG_ACX, "acx data path params"); + wl1251_debug(DEBUG_ACX, "acx data path params"); params = kzalloc(sizeof(*params), GFP_KERNEL); if (!params) { @@ -281,20 +280,20 @@ int wl12xx_acx_data_path_params(struct wl12xx *wl, params->tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT; - ret = wl12xx_cmd_configure(wl, ACX_DATA_PATH_PARAMS, + ret = wl1251_cmd_configure(wl, ACX_DATA_PATH_PARAMS, params, sizeof(*params)); if (ret < 0) goto out; /* FIXME: shouldn't this be ACX_DATA_PATH_RESP_PARAMS? */ - ret = wl12xx_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS, + ret = wl1251_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS, resp, sizeof(*resp)); if (ret < 0) { - wl12xx_warning("failed to read data path parameters: %d", ret); + wl1251_warning("failed to read data path parameters: %d", ret); goto out; } else if (resp->header.cmd.status != CMD_STATUS_SUCCESS) { - wl12xx_warning("data path parameter acx status failed"); + wl1251_warning("data path parameter acx status failed"); ret = -EIO; goto out; } @@ -304,12 +303,12 @@ out: return ret; } -int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time) +int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time) { struct acx_rx_msdu_lifetime *acx; int ret; - wl12xx_debug(DEBUG_ACX, "acx rx msdu life time"); + wl1251_debug(DEBUG_ACX, "acx rx msdu life time"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { @@ -318,10 +317,10 @@ int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time) } acx->lifetime = life_time; - ret = wl12xx_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, + ret = wl1251_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, acx, sizeof(*acx)); if (ret < 0) { - wl12xx_warning("failed to set rx msdu life time: %d", ret); + wl1251_warning("failed to set rx msdu life time: %d", ret); goto out; } @@ -330,12 +329,12 @@ out: return ret; } -int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter) +int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter) { struct acx_rx_config *rx_config; int ret; - wl12xx_debug(DEBUG_ACX, "acx rx config"); + wl1251_debug(DEBUG_ACX, "acx rx config"); rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); if (!rx_config) { @@ -346,10 +345,10 @@ int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter) rx_config->config_options = config; rx_config->filter_options = filter; - ret = wl12xx_cmd_configure(wl, ACX_RX_CFG, + ret = wl1251_cmd_configure(wl, ACX_RX_CFG, rx_config, sizeof(*rx_config)); if (ret < 0) { - wl12xx_warning("failed to set rx config: %d", ret); + wl1251_warning("failed to set rx config: %d", ret); goto out; } @@ -358,12 +357,12 @@ out: return ret; } -int wl12xx_acx_pd_threshold(struct wl12xx *wl) +int wl1251_acx_pd_threshold(struct wl1251 *wl) { struct acx_packet_detection *pd; int ret; - wl12xx_debug(DEBUG_ACX, "acx data pd threshold"); + wl1251_debug(DEBUG_ACX, "acx data pd threshold"); pd = kzalloc(sizeof(*pd), GFP_KERNEL); if (!pd) { @@ -373,9 +372,9 @@ int wl12xx_acx_pd_threshold(struct wl12xx *wl) /* FIXME: threshold value not set */ - ret = wl12xx_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); + ret = wl1251_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); if (ret < 0) { - wl12xx_warning("failed to set pd threshold: %d", ret); + wl1251_warning("failed to set pd threshold: %d", ret); goto out; } @@ -384,12 +383,12 @@ out: return 0; } -int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time) +int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time) { struct acx_slot *slot; int ret; - wl12xx_debug(DEBUG_ACX, "acx slot"); + wl1251_debug(DEBUG_ACX, "acx slot"); slot = kzalloc(sizeof(*slot), GFP_KERNEL); if (!slot) { @@ -400,9 +399,9 @@ int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time) slot->wone_index = STATION_WONE_INDEX; slot->slot_time = slot_time; - ret = wl12xx_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); + ret = wl1251_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); if (ret < 0) { - wl12xx_warning("failed to set slot time: %d", ret); + wl1251_warning("failed to set slot time: %d", ret); goto out; } @@ -411,12 +410,12 @@ out: return ret; } -int wl12xx_acx_group_address_tbl(struct wl12xx *wl) +int wl1251_acx_group_address_tbl(struct wl1251 *wl) { struct acx_dot11_grp_addr_tbl *acx; int ret; - wl12xx_debug(DEBUG_ACX, "acx group address tbl"); + wl1251_debug(DEBUG_ACX, "acx group address tbl"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { @@ -429,10 +428,10 @@ int wl12xx_acx_group_address_tbl(struct wl12xx *wl) acx->num_groups = 0; memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); - ret = wl12xx_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, + ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, acx, sizeof(*acx)); if (ret < 0) { - wl12xx_warning("failed to set group addr table: %d", ret); + wl1251_warning("failed to set group addr table: %d", ret); goto out; } @@ -441,7 +440,7 @@ out: return ret; } -int wl12xx_acx_service_period_timeout(struct wl12xx *wl) +int wl1251_acx_service_period_timeout(struct wl1251 *wl) { struct acx_rx_timeout *rx_timeout; int ret; @@ -452,15 +451,15 @@ int wl12xx_acx_service_period_timeout(struct wl12xx *wl) goto out; } - wl12xx_debug(DEBUG_ACX, "acx service period timeout"); + wl1251_debug(DEBUG_ACX, "acx service period timeout"); rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF; - ret = wl12xx_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, + ret = wl1251_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, rx_timeout, sizeof(*rx_timeout)); if (ret < 0) { - wl12xx_warning("failed to set service period timeout: %d", + wl1251_warning("failed to set service period timeout: %d", ret); goto out; } @@ -470,12 +469,12 @@ out: return ret; } -int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold) +int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold) { struct acx_rts_threshold *rts; int ret; - wl12xx_debug(DEBUG_ACX, "acx rts threshold"); + wl1251_debug(DEBUG_ACX, "acx rts threshold"); rts = kzalloc(sizeof(*rts), GFP_KERNEL); if (!rts) { @@ -485,9 +484,9 @@ int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold) rts->threshold = rts_threshold; - ret = wl12xx_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); + ret = wl1251_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); if (ret < 0) { - wl12xx_warning("failed to set rts threshold: %d", ret); + wl1251_warning("failed to set rts threshold: %d", ret); goto out; } @@ -496,12 +495,12 @@ out: return ret; } -int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl) +int wl1251_acx_beacon_filter_opt(struct wl1251 *wl) { struct acx_beacon_filter_option *beacon_filter; int ret; - wl12xx_debug(DEBUG_ACX, "acx beacon filter opt"); + wl1251_debug(DEBUG_ACX, "acx beacon filter opt"); beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); if (!beacon_filter) { @@ -512,10 +511,10 @@ int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl) beacon_filter->enable = 0; beacon_filter->max_num_beacons = 0; - ret = wl12xx_cmd_configure(wl, ACX_BEACON_FILTER_OPT, + ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_OPT, beacon_filter, sizeof(*beacon_filter)); if (ret < 0) { - wl12xx_warning("failed to set beacon filter opt: %d", ret); + wl1251_warning("failed to set beacon filter opt: %d", ret); goto out; } @@ -524,12 +523,12 @@ out: return ret; } -int wl12xx_acx_beacon_filter_table(struct wl12xx *wl) +int wl1251_acx_beacon_filter_table(struct wl1251 *wl) { struct acx_beacon_filter_ie_table *ie_table; int ret; - wl12xx_debug(DEBUG_ACX, "acx beacon filter table"); + wl1251_debug(DEBUG_ACX, "acx beacon filter table"); ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); if (!ie_table) { @@ -540,10 +539,10 @@ int wl12xx_acx_beacon_filter_table(struct wl12xx *wl) ie_table->num_ie = 0; memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE); - ret = wl12xx_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, + ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, ie_table, sizeof(*ie_table)); if (ret < 0) { - wl12xx_warning("failed to set beacon filter table: %d", ret); + wl1251_warning("failed to set beacon filter table: %d", ret); goto out; } @@ -552,12 +551,12 @@ out: return ret; } -int wl12xx_acx_sg_enable(struct wl12xx *wl) +int wl1251_acx_sg_enable(struct wl1251 *wl) { struct acx_bt_wlan_coex *pta; int ret; - wl12xx_debug(DEBUG_ACX, "acx sg enable"); + wl1251_debug(DEBUG_ACX, "acx sg enable"); pta = kzalloc(sizeof(*pta), GFP_KERNEL); if (!pta) { @@ -567,9 +566,9 @@ int wl12xx_acx_sg_enable(struct wl12xx *wl) pta->enable = SG_ENABLE; - ret = wl12xx_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); + ret = wl1251_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); if (ret < 0) { - wl12xx_warning("failed to set softgemini enable: %d", ret); + wl1251_warning("failed to set softgemini enable: %d", ret); goto out; } @@ -578,12 +577,12 @@ out: return ret; } -int wl12xx_acx_sg_cfg(struct wl12xx *wl) +int wl1251_acx_sg_cfg(struct wl1251 *wl) { struct acx_bt_wlan_coex_param *param; int ret; - wl12xx_debug(DEBUG_ACX, "acx sg cfg"); + wl1251_debug(DEBUG_ACX, "acx sg cfg"); param = kzalloc(sizeof(*param), GFP_KERNEL); if (!param) { @@ -621,9 +620,9 @@ int wl12xx_acx_sg_cfg(struct wl12xx *wl) param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; - ret = wl12xx_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); + ret = wl1251_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); if (ret < 0) { - wl12xx_warning("failed to set sg config: %d", ret); + wl1251_warning("failed to set sg config: %d", ret); goto out; } @@ -632,12 +631,12 @@ out: return ret; } -int wl12xx_acx_cca_threshold(struct wl12xx *wl) +int wl1251_acx_cca_threshold(struct wl1251 *wl) { struct acx_energy_detection *detection; int ret; - wl12xx_debug(DEBUG_ACX, "acx cca threshold"); + wl1251_debug(DEBUG_ACX, "acx cca threshold"); detection = kzalloc(sizeof(*detection), GFP_KERNEL); if (!detection) { @@ -648,10 +647,10 @@ int wl12xx_acx_cca_threshold(struct wl12xx *wl) detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; detection->tx_energy_detection = 0; - ret = wl12xx_cmd_configure(wl, ACX_CCA_THRESHOLD, + ret = wl1251_cmd_configure(wl, ACX_CCA_THRESHOLD, detection, sizeof(*detection)); if (ret < 0) { - wl12xx_warning("failed to set cca threshold: %d", ret); + wl1251_warning("failed to set cca threshold: %d", ret); return ret; } @@ -660,12 +659,12 @@ out: return ret; } -int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl) +int wl1251_acx_bcn_dtim_options(struct wl1251 *wl) { struct acx_beacon_broadcast *bb; int ret; - wl12xx_debug(DEBUG_ACX, "acx bcn dtim options"); + wl1251_debug(DEBUG_ACX, "acx bcn dtim options"); bb = kzalloc(sizeof(*bb), GFP_KERNEL); if (!bb) { @@ -678,9 +677,9 @@ int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl) bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; - ret = wl12xx_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); + ret = wl1251_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); if (ret < 0) { - wl12xx_warning("failed to set rx config: %d", ret); + wl1251_warning("failed to set rx config: %d", ret); goto out; } @@ -689,12 +688,12 @@ out: return ret; } -int wl12xx_acx_aid(struct wl12xx *wl, u16 aid) +int wl1251_acx_aid(struct wl1251 *wl, u16 aid) { struct acx_aid *acx_aid; int ret; - wl12xx_debug(DEBUG_ACX, "acx aid"); + wl1251_debug(DEBUG_ACX, "acx aid"); acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); if (!acx_aid) { @@ -704,9 +703,9 @@ int wl12xx_acx_aid(struct wl12xx *wl, u16 aid) acx_aid->aid = aid; - ret = wl12xx_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); + ret = wl1251_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); if (ret < 0) { - wl12xx_warning("failed to set aid: %d", ret); + wl1251_warning("failed to set aid: %d", ret); goto out; } @@ -715,12 +714,12 @@ out: return ret; } -int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask) +int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask) { struct acx_event_mask *mask; int ret; - wl12xx_debug(DEBUG_ACX, "acx event mbox mask"); + wl1251_debug(DEBUG_ACX, "acx event mbox mask"); mask = kzalloc(sizeof(*mask), GFP_KERNEL); if (!mask) { @@ -733,10 +732,10 @@ int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask) mask->event_mask = event_mask; - ret = wl12xx_cmd_configure(wl, ACX_EVENT_MBOX_MASK, + ret = wl1251_cmd_configure(wl, ACX_EVENT_MBOX_MASK, mask, sizeof(*mask)); if (ret < 0) { - wl12xx_warning("failed to set acx_event_mbox_mask: %d", ret); + wl1251_warning("failed to set acx_event_mbox_mask: %d", ret); goto out; } @@ -745,12 +744,12 @@ out: return ret; } -int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble) +int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble) { struct acx_preamble *acx; int ret; - wl12xx_debug(DEBUG_ACX, "acx_set_preamble"); + wl1251_debug(DEBUG_ACX, "acx_set_preamble"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { @@ -760,9 +759,9 @@ int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble) acx->preamble = preamble; - ret = wl12xx_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); + ret = wl1251_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); if (ret < 0) { - wl12xx_warning("Setting of preamble failed: %d", ret); + wl1251_warning("Setting of preamble failed: %d", ret); goto out; } @@ -771,13 +770,13 @@ out: return ret; } -int wl12xx_acx_cts_protect(struct wl12xx *wl, +int wl1251_acx_cts_protect(struct wl1251 *wl, enum acx_ctsprotect_type ctsprotect) { struct acx_ctsprotect *acx; int ret; - wl12xx_debug(DEBUG_ACX, "acx_set_ctsprotect"); + wl1251_debug(DEBUG_ACX, "acx_set_ctsprotect"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { @@ -787,9 +786,9 @@ int wl12xx_acx_cts_protect(struct wl12xx *wl, acx->ctsprotect = ctsprotect; - ret = wl12xx_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); + ret = wl1251_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); if (ret < 0) { - wl12xx_warning("Setting of ctsprotect failed: %d", ret); + wl1251_warning("Setting of ctsprotect failed: %d", ret); goto out; } @@ -798,7 +797,7 @@ out: return ret; } -int wl12xx_acx_tsf_info(struct wl12xx *wl, u64 *mactime) +int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime) { struct acx_tsf_info *tsf_info; int ret; @@ -809,10 +808,10 @@ int wl12xx_acx_tsf_info(struct wl12xx *wl, u64 *mactime) goto out; } - ret = wl12xx_cmd_interrogate(wl, ACX_TSF_INFO, + ret = wl1251_cmd_interrogate(wl, ACX_TSF_INFO, tsf_info, sizeof(*tsf_info)); if (ret < 0) { - wl12xx_warning("ACX_FW_REV interrogate failed"); + wl1251_warning("ACX_FW_REV interrogate failed"); goto out; } @@ -824,16 +823,16 @@ out: return ret; } -int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats) +int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats) { int ret; - wl12xx_debug(DEBUG_ACX, "acx statistics"); + wl1251_debug(DEBUG_ACX, "acx statistics"); - ret = wl12xx_cmd_interrogate(wl, ACX_STATISTICS, stats, + ret = wl1251_cmd_interrogate(wl, ACX_STATISTICS, stats, sizeof(*stats)); if (ret < 0) { - wl12xx_warning("acx statistics failed: %d", ret); + wl1251_warning("acx statistics failed: %d", ret); return -ENOMEM; } diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h index a23912014b9..2e7b1933a8f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.h +++ b/drivers/net/wireless/wl12xx/wl1251_acx.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008 Nokia Corporation @@ -22,15 +22,15 @@ * */ -#ifndef __WL12XX_ACX_H__ -#define __WL12XX_ACX_H__ +#ifndef __WL1251_ACX_H__ +#define __WL1251_ACX_H__ #include "wl1251.h" #include "wl1251_cmd.h" /* Target's information element */ struct acx_header { - struct wl12xx_cmd_header cmd; + struct wl1251_cmd_header cmd; /* acx (or information element) header */ u16 id; @@ -91,15 +91,15 @@ struct acx_revision { u32 hw_version; } __attribute__ ((packed)); -enum wl12xx_psm_mode { +enum wl1251_psm_mode { /* Active mode */ - WL12XX_PSM_CAM = 0, + WL1251_PSM_CAM = 0, /* Power save mode */ - WL12XX_PSM_PS = 1, + WL1251_PSM_PS = 1, /* Extreme low power */ - WL12XX_PSM_ELP = 2, + WL1251_PSM_ELP = 2, }; struct acx_sleep_auth { @@ -1108,39 +1108,39 @@ enum { }; -int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, +int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, u8 mgt_rate, u8 mgt_mod); -int wl12xx_acx_station_id(struct wl12xx *wl); -int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id); -int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 wake_up_event, +int wl1251_acx_station_id(struct wl1251 *wl); +int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id); +int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event, u8 listen_interval); -int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth); -int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len); -int wl12xx_acx_tx_power(struct wl12xx *wl, int power); -int wl12xx_acx_feature_cfg(struct wl12xx *wl); -int wl12xx_acx_mem_map(struct wl12xx *wl, +int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth); +int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len); +int wl1251_acx_tx_power(struct wl1251 *wl, int power); +int wl1251_acx_feature_cfg(struct wl1251 *wl); +int wl1251_acx_mem_map(struct wl1251 *wl, struct acx_header *mem_map, size_t len); -int wl12xx_acx_data_path_params(struct wl12xx *wl, +int wl1251_acx_data_path_params(struct wl1251 *wl, struct acx_data_path_params_resp *data_path); -int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time); -int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter); -int wl12xx_acx_pd_threshold(struct wl12xx *wl); -int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time); -int wl12xx_acx_group_address_tbl(struct wl12xx *wl); -int wl12xx_acx_service_period_timeout(struct wl12xx *wl); -int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold); -int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl); -int wl12xx_acx_beacon_filter_table(struct wl12xx *wl); -int wl12xx_acx_sg_enable(struct wl12xx *wl); -int wl12xx_acx_sg_cfg(struct wl12xx *wl); -int wl12xx_acx_cca_threshold(struct wl12xx *wl); -int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl); -int wl12xx_acx_aid(struct wl12xx *wl, u16 aid); -int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask); -int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble); -int wl12xx_acx_cts_protect(struct wl12xx *wl, +int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time); +int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter); +int wl1251_acx_pd_threshold(struct wl1251 *wl); +int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time); +int wl1251_acx_group_address_tbl(struct wl1251 *wl); +int wl1251_acx_service_period_timeout(struct wl1251 *wl); +int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold); +int wl1251_acx_beacon_filter_opt(struct wl1251 *wl); +int wl1251_acx_beacon_filter_table(struct wl1251 *wl); +int wl1251_acx_sg_enable(struct wl1251 *wl); +int wl1251_acx_sg_cfg(struct wl1251 *wl); +int wl1251_acx_cca_threshold(struct wl1251 *wl); +int wl1251_acx_bcn_dtim_options(struct wl1251 *wl); +int wl1251_acx_aid(struct wl1251 *wl, u16 aid); +int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask); +int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble); +int wl1251_acx_cts_protect(struct wl1251 *wl, enum acx_ctsprotect_type ctsprotect); -int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats); -int wl12xx_acx_tsf_info(struct wl12xx *wl, u64 *mactime); +int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats); +int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime); -#endif /* __WL12XX_ACX_H__ */ +#endif /* __WL1251_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index c52a2085671..d8a155dc2fa 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2008 Nokia Corporation * @@ -28,37 +28,37 @@ #include "wl1251_spi.h" #include "wl1251_event.h" -static void wl12xx_boot_enable_interrupts(struct wl12xx *wl) +static void wl1251_boot_enable_interrupts(struct wl1251 *wl) { enable_irq(wl->irq); } -void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl) +void wl1251_boot_target_enable_interrupts(struct wl1251 *wl) { - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); - wl12xx_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); + wl1251_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); } -int wl12xx_boot_soft_reset(struct wl12xx *wl) +int wl1251_boot_soft_reset(struct wl1251 *wl) { unsigned long timeout; u32 boot_data; /* perform soft reset */ - wl12xx_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); + wl1251_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); /* SOFT_RESET is self clearing */ timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); while (1) { - boot_data = wl12xx_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); - wl12xx_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); + boot_data = wl1251_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); + wl1251_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) break; if (time_after(jiffies, timeout)) { /* 1.2 check pWhalBus->uSelfClearTime if the * timeout was reached */ - wl12xx_error("soft reset timeout"); + wl1251_error("soft reset timeout"); return -1; } @@ -66,15 +66,15 @@ int wl12xx_boot_soft_reset(struct wl12xx *wl) } /* disable Rx/Tx */ - wl12xx_reg_write32(wl, ENABLE, 0x0); + wl1251_reg_write32(wl, ENABLE, 0x0); /* disable auto calibration on start*/ - wl12xx_reg_write32(wl, SPARE_A2, 0xffff); + wl1251_reg_write32(wl, SPARE_A2, 0xffff); return 0; } -int wl12xx_boot_init_seq(struct wl12xx *wl) +int wl1251_boot_init_seq(struct wl1251 *wl) { u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq; @@ -96,23 +96,23 @@ int wl12xx_boot_init_seq(struct wl12xx *wl) }; /* read NVS params */ - scr_pad6 = wl12xx_reg_read32(wl, SCR_PAD6); - wl12xx_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6); + scr_pad6 = wl1251_reg_read32(wl, SCR_PAD6); + wl1251_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6); /* read ELP_CMD */ - elp_cmd = wl12xx_reg_read32(wl, ELP_CMD); - wl12xx_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd); + elp_cmd = wl1251_reg_read32(wl, ELP_CMD); + wl1251_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd); /* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */ ref_freq = scr_pad6 & 0x000000FF; - wl12xx_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq); + wl1251_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq); - wl12xx_reg_write32(wl, PLL_CAL_TIME, 0x9); + wl1251_reg_write32(wl, PLL_CAL_TIME, 0x9); /* * PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME) */ - wl12xx_reg_write32(wl, CLK_BUF_TIME, 0x6); + wl1251_reg_write32(wl, CLK_BUF_TIME, 0x6); /* * set the clock detect feature to work in the restart wu procedure @@ -120,18 +120,18 @@ int wl12xx_boot_init_seq(struct wl12xx *wl) * (ELP_CFG_MODE[13:12]) */ tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000; - wl12xx_reg_write32(wl, ELP_CFG_MODE, tmp); + wl1251_reg_write32(wl, ELP_CFG_MODE, tmp); /* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */ elp_cmd |= 0x00000040; - wl12xx_reg_write32(wl, ELP_CMD, elp_cmd); + wl1251_reg_write32(wl, ELP_CMD, elp_cmd); /* PG 1.2: Set the BB PLL stable time to be 1000usec * (PLL_STABLE_TIME) */ - wl12xx_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20); + wl1251_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20); /* PG 1.2: read clock request time */ - init_data = wl12xx_reg_read32(wl, CLK_REQ_TIME); + init_data = wl1251_reg_read32(wl, CLK_REQ_TIME); /* * PG 1.2: set the clock request time to be ref_clk_settling_time - @@ -141,35 +141,35 @@ int wl12xx_boot_init_seq(struct wl12xx *wl) tmp = init_data - 0x21; else tmp = 0; - wl12xx_reg_write32(wl, CLK_REQ_TIME, tmp); + wl1251_reg_write32(wl, CLK_REQ_TIME, tmp); /* set BB PLL configurations in RF AFE */ - wl12xx_reg_write32(wl, 0x003058cc, 0x4B5); + wl1251_reg_write32(wl, 0x003058cc, 0x4B5); /* set RF_AFE_REG_5 */ - wl12xx_reg_write32(wl, 0x003058d4, 0x50); + wl1251_reg_write32(wl, 0x003058d4, 0x50); /* set RF_AFE_CTRL_REG_2 */ - wl12xx_reg_write32(wl, 0x00305948, 0x11c001); + wl1251_reg_write32(wl, 0x00305948, 0x11c001); /* * change RF PLL and BB PLL divider for VCO clock and adjust VCO * bais current(RF_AFE_REG_13) */ - wl12xx_reg_write32(wl, 0x003058f4, 0x1e); + wl1251_reg_write32(wl, 0x003058f4, 0x1e); /* set BB PLL configurations */ tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000; - wl12xx_reg_write32(wl, 0x00305840, tmp); + wl1251_reg_write32(wl, 0x00305840, tmp); /* set fractional divider according to Appendix C-BB PLL * Calculations */ tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER]; - wl12xx_reg_write32(wl, 0x00305844, tmp); + wl1251_reg_write32(wl, 0x00305844, tmp); /* set the initial data for the sigma delta */ - wl12xx_reg_write32(wl, 0x00305848, 0x3039); + wl1251_reg_write32(wl, 0x00305848, 0x3039); /* * set the accumulator attenuation value, calibration loop1 @@ -178,14 +178,14 @@ int wl12xx_boot_init_seq(struct wl12xx *wl) */ tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) | (LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1; - wl12xx_reg_write32(wl, 0x00305854, tmp); + wl1251_reg_write32(wl, 0x00305854, tmp); /* * set the calibration stop time after holdoff time expires and set * settling time HOLD_OFF_TIME_BB */ tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000; - wl12xx_reg_write32(wl, 0x00305858, tmp); + wl1251_reg_write32(wl, 0x00305858, tmp); /* * set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL @@ -193,7 +193,7 @@ int wl12xx_boot_init_seq(struct wl12xx *wl) * BB_ILOOPF[7:3] */ tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030; - wl12xx_reg_write32(wl, 0x003058f8, tmp); + wl1251_reg_write32(wl, 0x003058f8, tmp); /* * set regulator output voltage for n divider to @@ -201,10 +201,10 @@ int wl12xx_boot_init_seq(struct wl12xx *wl) * set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB * PLL auto-call to normal mode- BB_CALGAIN_3DB[8] */ - wl12xx_reg_write32(wl, 0x003058f0, 0x29); + wl1251_reg_write32(wl, 0x003058f0, 0x29); /* enable restart wakeup sequence (ELP_CMD[0]) */ - wl12xx_reg_write32(wl, ELP_CMD, elp_cmd | 0x1); + wl1251_reg_write32(wl, ELP_CMD, elp_cmd | 0x1); /* restart sequence completed */ udelay(2000); @@ -212,19 +212,19 @@ int wl12xx_boot_init_seq(struct wl12xx *wl) return 0; } -int wl12xx_boot_run_firmware(struct wl12xx *wl) +int wl1251_boot_run_firmware(struct wl1251 *wl) { int loop, ret; u32 chip_id, interrupt; wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); - chip_id = wl12xx_reg_read32(wl, CHIP_ID_B); + chip_id = wl1251_reg_read32(wl, CHIP_ID_B); - wl12xx_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); + wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); if (chip_id != wl->chip.id) { - wl12xx_error("chip id doesn't match after firmware boot"); + wl1251_error("chip id doesn't match after firmware boot"); return -EIO; } @@ -232,41 +232,41 @@ int wl12xx_boot_run_firmware(struct wl12xx *wl) loop = 0; while (loop++ < INIT_LOOP) { udelay(INIT_LOOP_DELAY); - interrupt = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + interrupt = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); if (interrupt == 0xffffffff) { - wl12xx_error("error reading hardware complete " + wl1251_error("error reading hardware complete " "init indication"); return -EIO; } /* check that ACX_INTR_INIT_COMPLETE is enabled */ else if (interrupt & wl->chip.intr_init_complete) { - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK, + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, wl->chip.intr_init_complete); break; } } if (loop >= INIT_LOOP) { - wl12xx_error("timeout waiting for the hardware to " + wl1251_error("timeout waiting for the hardware to " "complete initialization"); return -EIO; } /* get hardware config command mail box */ - wl->cmd_box_addr = wl12xx_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); + wl->cmd_box_addr = wl1251_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); /* get hardware config event mail box */ - wl->event_box_addr = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR); + wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); /* set the working partition to its "running" mode offset */ - wl12xx_set_partition(wl, + wl1251_set_partition(wl, wl->chip.p_table[PART_WORK].mem.start, wl->chip.p_table[PART_WORK].mem.size, wl->chip.p_table[PART_WORK].reg.start, wl->chip.p_table[PART_WORK].reg.size); - wl12xx_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", + wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", wl->cmd_box_addr, wl->event_box_addr); wl->chip.op_fw_version(wl); @@ -277,20 +277,20 @@ int wl12xx_boot_run_firmware(struct wl12xx *wl) */ /* enable gpio interrupts */ - wl12xx_boot_enable_interrupts(wl); + wl1251_boot_enable_interrupts(wl); wl->chip.op_target_enable_interrupts(wl); /* unmask all mbox events */ wl->event_mask = 0xffffffff; - ret = wl12xx_event_unmask(wl); + ret = wl1251_event_unmask(wl); if (ret < 0) { - wl12xx_error("EVENT mask setting failed"); + wl1251_error("EVENT mask setting failed"); return ret; } - wl12xx_event_mbox_config(wl); + wl1251_event_mbox_config(wl); /* firmware startup completed */ return 0; diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.h b/drivers/net/wireless/wl12xx/wl1251_boot.h index 3e2b7668878..798362d71e3 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.h +++ b/drivers/net/wireless/wl12xx/wl1251_boot.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2008 Nokia Corporation * @@ -26,10 +26,10 @@ #include "wl1251.h" -int wl12xx_boot_soft_reset(struct wl12xx *wl); -int wl12xx_boot_init_seq(struct wl12xx *wl); -int wl12xx_boot_run_firmware(struct wl12xx *wl); -void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl); +int wl1251_boot_soft_reset(struct wl1251 *wl); +int wl1251_boot_init_seq(struct wl1251 *wl); +int wl1251_boot_run_firmware(struct wl1251 *wl); +void wl1251_boot_target_enable_interrupts(struct wl1251 *wl); /* number of times we try to read the INIT interrupt */ #define INIT_LOOP 20000 diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index 92c7fb6853e..dc04d1fc2ee 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -5,7 +5,6 @@ #include #include "wl1251.h" -#include "wl12xx_80211.h" #include "reg.h" #include "wl1251_spi.h" #include "wl1251_ps.h" @@ -19,9 +18,9 @@ * @buf: buffer containing the command, must work with dma * @len: length of the buffer */ -int wl12xx_cmd_send(struct wl12xx *wl, u16 id, void *buf, size_t len) +int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len) { - struct wl12xx_cmd_header *cmd; + struct wl1251_cmd_header *cmd; unsigned long timeout; u32 intr; int ret = 0; @@ -32,26 +31,26 @@ int wl12xx_cmd_send(struct wl12xx *wl, u16 id, void *buf, size_t len) WARN_ON(len % 4 != 0); - wl12xx_spi_mem_write(wl, wl->cmd_box_addr, buf, len); + wl1251_spi_mem_write(wl, wl->cmd_box_addr, buf, len); - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); - timeout = jiffies + msecs_to_jiffies(WL12XX_COMMAND_TIMEOUT); + timeout = jiffies + msecs_to_jiffies(WL1251_COMMAND_TIMEOUT); - intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); while (!(intr & wl->chip.intr_cmd_complete)) { if (time_after(jiffies, timeout)) { - wl12xx_error("command complete timeout"); + wl1251_error("command complete timeout"); ret = -ETIMEDOUT; goto out; } msleep(1); - intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); } - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK, + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, wl->chip.intr_cmd_complete); out: @@ -66,33 +65,33 @@ out: * @len: length of the buffer * @answer: is answer needed */ -int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) +int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer) { int ret; - wl12xx_debug(DEBUG_CMD, "cmd test"); + wl1251_debug(DEBUG_CMD, "cmd test"); - ret = wl12xx_cmd_send(wl, CMD_TEST, buf, buf_len); + ret = wl1251_cmd_send(wl, CMD_TEST, buf, buf_len); if (ret < 0) { - wl12xx_warning("TEST command failed"); + wl1251_warning("TEST command failed"); return ret; } if (answer) { - struct wl12xx_command *cmd_answer; + struct wl1251_command *cmd_answer; /* * The test command got in, we can read the answer. - * The answer would be a wl12xx_command, where the + * The answer would be a wl1251_command, where the * parameter array contains the actual answer. */ - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); + wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); cmd_answer = buf; if (cmd_answer->header.status != CMD_STATUS_SUCCESS) - wl12xx_error("TEST command answer error: %d", + wl1251_error("TEST command answer error: %d", cmd_answer->header.status); } @@ -107,30 +106,30 @@ int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) * @buf: buffer for the response, including all headers, must work with dma * @len: lenght of buf */ -int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 id, void *buf, size_t len) +int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len) { struct acx_header *acx = buf; int ret; - wl12xx_debug(DEBUG_CMD, "cmd interrogate"); + wl1251_debug(DEBUG_CMD, "cmd interrogate"); acx->id = id; /* payload length, does not include any headers */ acx->len = len - sizeof(*acx); - ret = wl12xx_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); + ret = wl1251_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); if (ret < 0) { - wl12xx_error("INTERROGATE command failed"); + wl1251_error("INTERROGATE command failed"); goto out; } /* the interrogate command got in, we can read the answer */ - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, len); + wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, len); acx = buf; if (acx->cmd.status != CMD_STATUS_SUCCESS) - wl12xx_error("INTERROGATE command error: %d", + wl1251_error("INTERROGATE command error: %d", acx->cmd.status); out: @@ -145,34 +144,34 @@ out: * @buf: buffer containing acx, including all headers, must work with dma * @len: length of buf */ -int wl12xx_cmd_configure(struct wl12xx *wl, u16 id, void *buf, size_t len) +int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len) { struct acx_header *acx = buf; int ret; - wl12xx_debug(DEBUG_CMD, "cmd configure"); + wl1251_debug(DEBUG_CMD, "cmd configure"); acx->id = id; /* payload length, does not include any headers */ acx->len = len - sizeof(*acx); - ret = wl12xx_cmd_send(wl, CMD_CONFIGURE, acx, len); + ret = wl1251_cmd_send(wl, CMD_CONFIGURE, acx, len); if (ret < 0) { - wl12xx_warning("CONFIGURE command NOK"); + wl1251_warning("CONFIGURE command NOK"); return ret; } return 0; } -int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, +int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, void *bitmap, u16 bitmap_len, u8 bitmap_control) { - struct wl12xx_cmd_vbm_update *vbm; + struct wl1251_cmd_vbm_update *vbm; int ret; - wl12xx_debug(DEBUG_CMD, "cmd vbm"); + wl1251_debug(DEBUG_CMD, "cmd vbm"); vbm = kzalloc(sizeof(*vbm), GFP_KERNEL); if (!vbm) { @@ -183,7 +182,7 @@ int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, /* Count and period will be filled by the target */ vbm->tim.bitmap_ctrl = bitmap_control; if (bitmap_len > PARTIAL_VBM_MAX) { - wl12xx_warning("cmd vbm len is %d B, truncating to %d", + wl1251_warning("cmd vbm len is %d B, truncating to %d", bitmap_len, PARTIAL_VBM_MAX); bitmap_len = PARTIAL_VBM_MAX; } @@ -193,9 +192,9 @@ int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, vbm->len = cpu_to_le16(bitmap_len + 5); - ret = wl12xx_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm)); + ret = wl1251_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm)); if (ret < 0) { - wl12xx_error("VBM command failed"); + wl1251_error("VBM command failed"); goto out; } @@ -204,13 +203,13 @@ out: return 0; } -int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable) +int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable) { struct cmd_enabledisable_path *cmd; int ret; u16 cmd_rx, cmd_tx; - wl12xx_debug(DEBUG_CMD, "cmd data path"); + wl1251_debug(DEBUG_CMD, "cmd data path"); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { @@ -228,24 +227,24 @@ int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable) cmd_tx = CMD_DISABLE_TX; } - ret = wl12xx_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); + ret = wl1251_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); if (ret < 0) { - wl12xx_error("rx %s cmd for channel %d failed", + wl1251_error("rx %s cmd for channel %d failed", enable ? "start" : "stop", channel); goto out; } - wl12xx_debug(DEBUG_BOOT, "rx %s cmd channel %d", + wl1251_debug(DEBUG_BOOT, "rx %s cmd channel %d", enable ? "start" : "stop", channel); - ret = wl12xx_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); + ret = wl1251_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); if (ret < 0) { - wl12xx_error("tx %s cmd for channel %d failed", + wl1251_error("tx %s cmd for channel %d failed", enable ? "start" : "stop", channel); return ret; } - wl12xx_debug(DEBUG_BOOT, "tx %s cmd channel %d", + wl1251_debug(DEBUG_BOOT, "tx %s cmd channel %d", enable ? "start" : "stop", channel); out: @@ -253,7 +252,7 @@ out: return ret; } -int wl1251_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, +int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, u16 beacon_interval, u8 wait) { unsigned long timeout; @@ -268,14 +267,14 @@ int wl1251_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, } /* FIXME: this should be in main.c */ - ret = wl12xx_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, + ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, DEFAULT_HW_GEN_MODULATION_TYPE, wl->tx_mgmt_frm_rate, wl->tx_mgmt_frm_mod); if (ret < 0) goto out; - wl12xx_debug(DEBUG_CMD, "cmd join"); + wl1251_debug(DEBUG_CMD, "cmd join"); /* Reverse order BSSID */ bssid = (u8 *) &join->bssid_lsb; @@ -294,9 +293,9 @@ int wl1251_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, join->channel = wl->channel; join->ctrl = JOIN_CMD_CTRL_TX_FLUSH; - ret = wl12xx_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); + ret = wl1251_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); if (ret < 0) { - wl12xx_error("failed to initiate cmd join"); + wl1251_error("failed to initiate cmd join"); goto out; } @@ -314,20 +313,20 @@ out: return ret; } -int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode) +int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode) { - struct wl12xx_cmd_ps_params *ps_params = NULL; + struct wl1251_cmd_ps_params *ps_params = NULL; int ret = 0; /* FIXME: this should be in ps.c */ - ret = wl12xx_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, + ret = wl1251_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, wl->listen_int); if (ret < 0) { - wl12xx_error("couldn't set wake up conditions"); + wl1251_error("couldn't set wake up conditions"); goto out; } - wl12xx_debug(DEBUG_CMD, "cmd set ps mode"); + wl1251_debug(DEBUG_CMD, "cmd set ps mode"); ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); if (!ps_params) { @@ -341,10 +340,10 @@ int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode) ps_params->hang_over_period = 128; ps_params->null_data_rate = 1; /* 1 Mbps */ - ret = wl12xx_cmd_send(wl, CMD_SET_PS_MODE, ps_params, + ret = wl1251_cmd_send(wl, CMD_SET_PS_MODE, ps_params, sizeof(*ps_params)); if (ret < 0) { - wl12xx_error("cmd set_ps_mode failed"); + wl1251_error("cmd set_ps_mode failed"); goto out; } @@ -353,13 +352,13 @@ out: return ret; } -int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer, +int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, size_t len) { struct cmd_read_write_memory *cmd; int ret = 0; - wl12xx_debug(DEBUG_CMD, "cmd read memory"); + wl1251_debug(DEBUG_CMD, "cmd read memory"); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { @@ -373,17 +372,17 @@ int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer, cmd->addr = addr; cmd->size = len; - ret = wl12xx_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); + ret = wl1251_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); if (ret < 0) { - wl12xx_error("read memory command failed: %d", ret); + wl1251_error("read memory command failed: %d", ret); goto out; } /* the read command got in, we can now read the answer */ - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); + wl1251_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); if (cmd->header.status != CMD_STATUS_SUCCESS) - wl12xx_error("error in read command result: %d", + wl1251_error("error in read command result: %d", cmd->header.status); memcpy(answer, cmd->value, len); @@ -393,17 +392,17 @@ out: return ret; } -int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, +int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, void *buf, size_t buf_len) { - struct wl12xx_cmd_packet_template *cmd; + struct wl1251_cmd_packet_template *cmd; size_t cmd_len; int ret = 0; - wl12xx_debug(DEBUG_CMD, "cmd template %d", cmd_id); + wl1251_debug(DEBUG_CMD, "cmd template %d", cmd_id); - WARN_ON(buf_len > WL12XX_MAX_TEMPLATE_SIZE); - buf_len = min_t(size_t, buf_len, WL12XX_MAX_TEMPLATE_SIZE); + WARN_ON(buf_len > WL1251_MAX_TEMPLATE_SIZE); + buf_len = min_t(size_t, buf_len, WL1251_MAX_TEMPLATE_SIZE); cmd_len = ALIGN(sizeof(*cmd) + buf_len, 4); cmd = kzalloc(cmd_len, GFP_KERNEL); @@ -417,9 +416,9 @@ int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, if (buf) memcpy(cmd->data, buf, buf_len); - ret = wl12xx_cmd_send(wl, cmd_id, cmd, cmd_len); + ret = wl1251_cmd_send(wl, cmd_id, cmd, cmd_len); if (ret < 0) { - wl12xx_warning("cmd set_template failed: %d", ret); + wl1251_warning("cmd set_template failed: %d", ret); goto out; } diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h index b252ad25ee2..64f228dd9a9 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008 Nokia Corporation @@ -22,32 +22,32 @@ * */ -#ifndef __WL12XX_CMD_H__ -#define __WL12XX_CMD_H__ +#ifndef __WL1251_CMD_H__ +#define __WL1251_CMD_H__ #include "wl1251.h" struct acx_header; -int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len); -int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer); -int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 id, void *buf, size_t len); -int wl12xx_cmd_configure(struct wl12xx *wl, u16 id, void *buf, size_t len); -int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, +int wl1251_cmd_send(struct wl1251 *wl, u16 type, void *buf, size_t buf_len); +int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer); +int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len); +int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len); +int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, void *bitmap, u16 bitmap_len, u8 bitmap_control); -int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable); -int wl1251_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, +int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable); +int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, u16 beacon_interval, u8 wait); -int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode); -int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer, +int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode); +int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, size_t len); -int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, +int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, void *buf, size_t buf_len); /* unit ms */ -#define WL12XX_COMMAND_TIMEOUT 2000 +#define WL1251_COMMAND_TIMEOUT 2000 -enum wl12xx_commands { +enum wl1251_commands { CMD_RESET = 0, CMD_INTERROGATE = 1, /*use this to read information elements*/ CMD_CONFIGURE = 2, /*use this to write information elements*/ @@ -95,15 +95,15 @@ enum wl12xx_commands { #define MAX_CMD_PARAMS 572 -struct wl12xx_cmd_header { +struct wl1251_cmd_header { u16 id; u16 status; /* payload */ u8 data[0]; } __attribute__ ((packed)); -struct wl12xx_command { - struct wl12xx_cmd_header header; +struct wl1251_command { + struct wl1251_cmd_header header; u8 parameters[MAX_CMD_PARAMS]; }; @@ -145,7 +145,7 @@ enum { #define MAX_READ_SIZE 256 struct cmd_read_write_memory { - struct wl12xx_cmd_header header; + struct wl1251_cmd_header header; /* The address of the memory to read from or write to.*/ u32 addr; @@ -214,7 +214,7 @@ struct basic_scan_channel_parameters { #define SCAN_MAX_NUM_OF_CHANNELS 16 struct cmd_scan { - struct wl12xx_cmd_header header; + struct wl1251_cmd_header header; struct basic_scan_parameters params; struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; @@ -232,7 +232,7 @@ enum { struct cmd_join { - struct wl12xx_cmd_header header; + struct wl1251_cmd_header header; u32 bssid_lsb; u16 bssid_msb; @@ -269,16 +269,16 @@ struct cmd_join { } __attribute__ ((packed)); struct cmd_enabledisable_path { - struct wl12xx_cmd_header header; + struct wl1251_cmd_header header; u8 channel; u8 padding[3]; } __attribute__ ((packed)); -#define WL12XX_MAX_TEMPLATE_SIZE 300 +#define WL1251_MAX_TEMPLATE_SIZE 300 -struct wl12xx_cmd_packet_template { - struct wl12xx_cmd_header header; +struct wl1251_cmd_packet_template { + struct wl1251_cmd_header header; __le16 size; u8 data[0]; @@ -287,7 +287,7 @@ struct wl12xx_cmd_packet_template { #define TIM_ELE_ID 5 #define PARTIAL_VBM_MAX 251 -struct wl12xx_tim { +struct wl1251_tim { u8 identity; u8 length; u8 dtim_count; @@ -297,20 +297,20 @@ struct wl12xx_tim { } __attribute__ ((packed)); /* Virtual Bit Map update */ -struct wl12xx_cmd_vbm_update { - struct wl12xx_cmd_header header; +struct wl1251_cmd_vbm_update { + struct wl1251_cmd_header header; __le16 len; u8 padding[2]; - struct wl12xx_tim tim; + struct wl1251_tim tim; } __attribute__ ((packed)); -enum wl12xx_cmd_ps_mode { +enum wl1251_cmd_ps_mode { STATION_ACTIVE_MODE, STATION_POWER_SAVE_MODE }; -struct wl12xx_cmd_ps_params { - struct wl12xx_cmd_header header; +struct wl1251_cmd_ps_params { + struct wl1251_cmd_header header; u8 ps_mode; /* STATION_* */ u8 send_null_data; /* Do we have to send NULL data packet ? */ @@ -325,8 +325,8 @@ struct wl12xx_cmd_ps_params { u8 pad[2]; } __attribute__ ((packed)); -struct wl12xx_cmd_trigger_scan_to { - struct wl12xx_cmd_header header; +struct wl1251_cmd_trigger_scan_to { + struct wl1251_cmd_header header; u32 timeout; }; @@ -340,14 +340,14 @@ struct wl12xx_cmd_trigger_scan_to { /* When set, disable HW decryption */ #define DF_SNIFF_MODE_ENABLE 0x80 -enum wl12xx_cmd_key_action { +enum wl1251_cmd_key_action { KEY_ADD_OR_REPLACE = 1, KEY_REMOVE = 2, KEY_SET_ID = 3, MAX_KEY_ACTION = 0xffff, }; -enum wl12xx_cmd_key_type { +enum wl1251_cmd_key_type { KEY_WEP_DEFAULT = 0, KEY_WEP_ADDR = 1, KEY_AES_GROUP = 4, @@ -374,8 +374,8 @@ enum wl12xx_cmd_key_type { * */ -struct wl12xx_cmd_set_keys { - struct wl12xx_cmd_header header; +struct wl1251_cmd_set_keys { + struct wl1251_cmd_header header; /* Ignored for default WEP key */ u8 addr[ETH_ALEN]; @@ -404,4 +404,4 @@ struct wl12xx_cmd_set_keys { } __attribute__ ((packed)); -#endif /* __WL12XX_CMD_H__ */ +#endif /* __WL1251_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.c b/drivers/net/wireless/wl12xx/wl1251_debugfs.c index 866303dd687..a00723059f8 100644 --- a/drivers/net/wireless/wl12xx/wl1251_debugfs.c +++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2009 Nokia Corporation * @@ -30,7 +30,7 @@ #include "wl1251_ps.h" /* ms */ -#define WL12XX_DEBUGFS_STATS_LIFETIME 1000 +#define WL1251_DEBUGFS_STATS_LIFETIME 1000 /* debugfs macros idea from mac80211 */ @@ -38,7 +38,7 @@ static ssize_t name## _read(struct file *file, char __user *userbuf, \ size_t count, loff_t *ppos) \ { \ - struct wl12xx *wl = file->private_data; \ + struct wl1251 *wl = file->private_data; \ char buf[buflen]; \ int res; \ \ @@ -48,7 +48,7 @@ static ssize_t name## _read(struct file *file, char __user *userbuf, \ \ static const struct file_operations name## _ops = { \ .read = name## _read, \ - .open = wl12xx_open_file_generic, \ + .open = wl1251_open_file_generic, \ }; #define DEBUGFS_ADD(name, parent) \ @@ -71,11 +71,11 @@ static ssize_t sub## _ ##name## _read(struct file *file, \ char __user *userbuf, \ size_t count, loff_t *ppos) \ { \ - struct wl12xx *wl = file->private_data; \ + struct wl1251 *wl = file->private_data; \ char buf[buflen]; \ int res; \ \ - wl12xx_debugfs_update_stats(wl); \ + wl1251_debugfs_update_stats(wl); \ \ res = scnprintf(buf, buflen, fmt "\n", \ wl->stats.fw_stats->sub.name); \ @@ -84,7 +84,7 @@ static ssize_t sub## _ ##name## _read(struct file *file, \ \ static const struct file_operations sub## _ ##name## _ops = { \ .read = sub## _ ##name## _read, \ - .open = wl12xx_open_file_generic, \ + .open = wl1251_open_file_generic, \ }; #define DEBUGFS_FWSTATS_ADD(sub, name) \ @@ -93,30 +93,30 @@ static const struct file_operations sub## _ ##name## _ops = { \ #define DEBUGFS_FWSTATS_DEL(sub, name) \ DEBUGFS_DEL(sub## _ ##name) -static void wl12xx_debugfs_update_stats(struct wl12xx *wl) +static void wl1251_debugfs_update_stats(struct wl1251 *wl) { int ret; mutex_lock(&wl->mutex); - ret = wl12xx_ps_elp_wakeup(wl); + ret = wl1251_ps_elp_wakeup(wl); if (ret < 0) goto out; - if (wl->state == WL12XX_STATE_ON && + if (wl->state == WL1251_STATE_ON && time_after(jiffies, wl->stats.fw_stats_update + - msecs_to_jiffies(WL12XX_DEBUGFS_STATS_LIFETIME))) { - wl12xx_acx_statistics(wl, wl->stats.fw_stats); + msecs_to_jiffies(WL1251_DEBUGFS_STATS_LIFETIME))) { + wl1251_acx_statistics(wl, wl->stats.fw_stats); wl->stats.fw_stats_update = jiffies; } - wl12xx_ps_elp_sleep(wl); + wl1251_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); } -static int wl12xx_open_file_generic(struct inode *inode, struct file *file) +static int wl1251_open_file_generic(struct inode *inode, struct file *file) { file->private_data = inode->i_private; return 0; @@ -221,7 +221,7 @@ DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u", static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { - struct wl12xx *wl = file->private_data; + struct wl1251 *wl = file->private_data; u32 queue_len; char buf[20]; int res; @@ -234,10 +234,10 @@ static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, static const struct file_operations tx_queue_len_ops = { .read = tx_queue_len_read, - .open = wl12xx_open_file_generic, + .open = wl1251_open_file_generic, }; -static void wl12xx_debugfs_delete_files(struct wl12xx *wl) +static void wl1251_debugfs_delete_files(struct wl1251 *wl) { DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); @@ -335,7 +335,7 @@ static void wl12xx_debugfs_delete_files(struct wl12xx *wl) DEBUGFS_DEL(excessive_retries); } -static int wl12xx_debugfs_add_files(struct wl12xx *wl) +static int wl1251_debugfs_add_files(struct wl1251 *wl) { int ret = 0; @@ -436,19 +436,19 @@ static int wl12xx_debugfs_add_files(struct wl12xx *wl) out: if (ret < 0) - wl12xx_debugfs_delete_files(wl); + wl1251_debugfs_delete_files(wl); return ret; } -void wl12xx_debugfs_reset(struct wl12xx *wl) +void wl1251_debugfs_reset(struct wl1251 *wl) { memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); wl->stats.retry_count = 0; wl->stats.excessive_retries = 0; } -int wl12xx_debugfs_init(struct wl12xx *wl) +int wl1251_debugfs_init(struct wl1251 *wl) { int ret; @@ -479,7 +479,7 @@ int wl12xx_debugfs_init(struct wl12xx *wl) wl->stats.fw_stats_update = jiffies; - ret = wl12xx_debugfs_add_files(wl); + ret = wl1251_debugfs_add_files(wl); if (ret < 0) goto err_file; @@ -502,9 +502,9 @@ err: return ret; } -void wl12xx_debugfs_exit(struct wl12xx *wl) +void wl1251_debugfs_exit(struct wl1251 *wl) { - wl12xx_debugfs_delete_files(wl); + wl1251_debugfs_delete_files(wl); kfree(wl->stats.fw_stats); wl->stats.fw_stats = NULL; diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.h b/drivers/net/wireless/wl12xx/wl1251_debugfs.h index 37653eb0cd0..6dc3d080853 100644 --- a/drivers/net/wireless/wl12xx/wl1251_debugfs.h +++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2009 Nokia Corporation * @@ -21,13 +21,13 @@ * */ -#ifndef WL12XX_DEBUGFS_H -#define WL12XX_DEBUGFS_H +#ifndef WL1251_DEBUGFS_H +#define WL1251_DEBUGFS_H #include "wl1251.h" -int wl12xx_debugfs_init(struct wl12xx *wl); -void wl12xx_debugfs_exit(struct wl12xx *wl); -void wl12xx_debugfs_reset(struct wl12xx *wl); +int wl1251_debugfs_init(struct wl1251 *wl); +void wl1251_debugfs_exit(struct wl1251 *wl); +void wl1251_debugfs_reset(struct wl1251 *wl); -#endif /* WL12XX_DEBUGFS_H */ +#endif /* WL1251_DEBUGFS_H */ diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl12xx/wl1251_event.c index a6d92349add..1a0a0bc1a31 100644 --- a/drivers/net/wireless/wl12xx/wl1251_event.c +++ b/drivers/net/wireless/wl12xx/wl1251_event.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008 Nokia Corporation @@ -28,10 +28,10 @@ #include "wl1251_event.h" #include "wl1251_ps.h" -static int wl12xx_event_scan_complete(struct wl12xx *wl, +static int wl1251_event_scan_complete(struct wl1251 *wl, struct event_mailbox *mbox) { - wl12xx_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", + wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", mbox->scheduled_scan_status, mbox->scheduled_scan_channels); @@ -45,34 +45,34 @@ static int wl12xx_event_scan_complete(struct wl12xx *wl, return 0; } -static void wl12xx_event_mbox_dump(struct event_mailbox *mbox) +static void wl1251_event_mbox_dump(struct event_mailbox *mbox) { - wl12xx_debug(DEBUG_EVENT, "MBOX DUMP:"); - wl12xx_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); - wl12xx_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); + wl1251_debug(DEBUG_EVENT, "MBOX DUMP:"); + wl1251_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); + wl1251_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); } -static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox) +static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox) { int ret; u32 vector; - wl12xx_event_mbox_dump(mbox); + wl1251_event_mbox_dump(mbox); vector = mbox->events_vector & ~(mbox->events_mask); - wl12xx_debug(DEBUG_EVENT, "vector: 0x%x", vector); + wl1251_debug(DEBUG_EVENT, "vector: 0x%x", vector); if (vector & SCAN_COMPLETE_EVENT_ID) { - ret = wl12xx_event_scan_complete(wl, mbox); + ret = wl1251_event_scan_complete(wl, mbox); if (ret < 0) return ret; } if (vector & BSS_LOSE_EVENT_ID) { - wl12xx_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); + wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); if (wl->psm_requested && wl->psm) { - ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE); + ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); if (ret < 0) return ret; } @@ -81,47 +81,47 @@ static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox) return 0; } -int wl12xx_event_unmask(struct wl12xx *wl) +int wl1251_event_unmask(struct wl1251 *wl) { int ret; - ret = wl12xx_acx_event_mbox_mask(wl, ~(wl->event_mask)); + ret = wl1251_acx_event_mbox_mask(wl, ~(wl->event_mask)); if (ret < 0) return ret; return 0; } -void wl12xx_event_mbox_config(struct wl12xx *wl) +void wl1251_event_mbox_config(struct wl1251 *wl) { - wl->mbox_ptr[0] = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR); + wl->mbox_ptr[0] = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); - wl12xx_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", + wl1251_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", wl->mbox_ptr[0], wl->mbox_ptr[1]); } -int wl12xx_event_handle(struct wl12xx *wl, u8 mbox_num) +int wl1251_event_handle(struct wl1251 *wl, u8 mbox_num) { struct event_mailbox mbox; int ret; - wl12xx_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); + wl1251_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); if (mbox_num > 1) return -EINVAL; /* first we read the mbox descriptor */ - wl12xx_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, + wl1251_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, sizeof(struct event_mailbox)); /* process the descriptor */ - ret = wl12xx_event_process(wl, &mbox); + ret = wl1251_event_process(wl, &mbox); if (ret < 0) return ret; /* then we let the firmware know it can go on...*/ - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); return 0; } diff --git a/drivers/net/wireless/wl12xx/wl1251_event.h b/drivers/net/wireless/wl12xx/wl1251_event.h index 1f4c2f7438a..be0ac54d624 100644 --- a/drivers/net/wireless/wl12xx/wl1251_event.h +++ b/drivers/net/wireless/wl12xx/wl1251_event.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008 Nokia Corporation @@ -22,8 +22,8 @@ * */ -#ifndef __WL12XX_EVENT_H__ -#define __WL12XX_EVENT_H__ +#ifndef __WL1251_EVENT_H__ +#define __WL1251_EVENT_H__ /* * Mbox events @@ -114,8 +114,8 @@ struct event_mailbox { u8 padding[19]; } __attribute__ ((packed)); -int wl12xx_event_unmask(struct wl12xx *wl); -void wl12xx_event_mbox_config(struct wl12xx *wl); -int wl12xx_event_handle(struct wl12xx *wl, u8 mbox); +int wl1251_event_unmask(struct wl1251 *wl); +void wl1251_event_mbox_config(struct wl1251 *wl); +int wl1251_event_handle(struct wl1251 *wl, u8 mbox); #endif diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c index 0929461a6d3..df6c60f0fd6 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.c +++ b/drivers/net/wireless/wl12xx/wl1251_init.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2009 Nokia Corporation * @@ -29,59 +29,59 @@ #include "wl1251_acx.h" #include "wl1251_cmd.h" -int wl12xx_hw_init_hwenc_config(struct wl12xx *wl) +int wl1251_hw_init_hwenc_config(struct wl1251 *wl) { int ret; - ret = wl12xx_acx_feature_cfg(wl); + ret = wl1251_acx_feature_cfg(wl); if (ret < 0) { - wl12xx_warning("couldn't set feature config"); + wl1251_warning("couldn't set feature config"); return ret; } - ret = wl12xx_acx_default_key(wl, wl->default_key); + ret = wl1251_acx_default_key(wl, wl->default_key); if (ret < 0) { - wl12xx_warning("couldn't set default key"); + wl1251_warning("couldn't set default key"); return ret; } return 0; } -int wl12xx_hw_init_templates_config(struct wl12xx *wl) +int wl1251_hw_init_templates_config(struct wl1251 *wl) { int ret; u8 partial_vbm[PARTIAL_VBM_MAX]; /* send empty templates for fw memory reservation */ - ret = wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, NULL, + ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, NULL, sizeof(struct wl12xx_probe_req_template)); if (ret < 0) return ret; - ret = wl12xx_cmd_template_set(wl, CMD_NULL_DATA, NULL, + ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, NULL, sizeof(struct wl12xx_null_data_template)); if (ret < 0) return ret; - ret = wl12xx_cmd_template_set(wl, CMD_PS_POLL, NULL, + ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, NULL, sizeof(struct wl12xx_ps_poll_template)); if (ret < 0) return ret; - ret = wl12xx_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL, + ret = wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL, sizeof (struct wl12xx_qos_null_data_template)); if (ret < 0) return ret; - ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, NULL, + ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, NULL, sizeof (struct wl12xx_probe_resp_template)); if (ret < 0) return ret; - ret = wl12xx_cmd_template_set(wl, CMD_BEACON, NULL, + ret = wl1251_cmd_template_set(wl, CMD_BEACON, NULL, sizeof (struct wl12xx_beacon_template)); if (ret < 0) @@ -89,112 +89,112 @@ int wl12xx_hw_init_templates_config(struct wl12xx *wl) /* tim templates, first reserve space then allocate an empty one */ memset(partial_vbm, 0, PARTIAL_VBM_MAX); - ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0); + ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0); if (ret < 0) return ret; - ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0); + ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0); if (ret < 0) return ret; return 0; } -int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter) +int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter) { int ret; - ret = wl12xx_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); + ret = wl1251_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); if (ret < 0) return ret; - ret = wl12xx_acx_rx_config(wl, config, filter); + ret = wl1251_acx_rx_config(wl, config, filter); if (ret < 0) return ret; return 0; } -int wl12xx_hw_init_phy_config(struct wl12xx *wl) +int wl1251_hw_init_phy_config(struct wl1251 *wl) { int ret; - ret = wl12xx_acx_pd_threshold(wl); + ret = wl1251_acx_pd_threshold(wl); if (ret < 0) return ret; - ret = wl12xx_acx_slot(wl, DEFAULT_SLOT_TIME); + ret = wl1251_acx_slot(wl, DEFAULT_SLOT_TIME); if (ret < 0) return ret; - ret = wl12xx_acx_group_address_tbl(wl); + ret = wl1251_acx_group_address_tbl(wl); if (ret < 0) return ret; - ret = wl12xx_acx_service_period_timeout(wl); + ret = wl1251_acx_service_period_timeout(wl); if (ret < 0) return ret; - ret = wl12xx_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); + ret = wl1251_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); if (ret < 0) return ret; return 0; } -int wl12xx_hw_init_beacon_filter(struct wl12xx *wl) +int wl1251_hw_init_beacon_filter(struct wl1251 *wl) { int ret; - ret = wl12xx_acx_beacon_filter_opt(wl); + ret = wl1251_acx_beacon_filter_opt(wl); if (ret < 0) return ret; - ret = wl12xx_acx_beacon_filter_table(wl); + ret = wl1251_acx_beacon_filter_table(wl); if (ret < 0) return ret; return 0; } -int wl12xx_hw_init_pta(struct wl12xx *wl) +int wl1251_hw_init_pta(struct wl1251 *wl) { int ret; - ret = wl12xx_acx_sg_enable(wl); + ret = wl1251_acx_sg_enable(wl); if (ret < 0) return ret; - ret = wl12xx_acx_sg_cfg(wl); + ret = wl1251_acx_sg_cfg(wl); if (ret < 0) return ret; return 0; } -int wl12xx_hw_init_energy_detection(struct wl12xx *wl) +int wl1251_hw_init_energy_detection(struct wl1251 *wl) { int ret; - ret = wl12xx_acx_cca_threshold(wl); + ret = wl1251_acx_cca_threshold(wl); if (ret < 0) return ret; return 0; } -int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl) +int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl) { int ret; - ret = wl12xx_acx_bcn_dtim_options(wl); + ret = wl1251_acx_bcn_dtim_options(wl); if (ret < 0) return ret; return 0; } -int wl12xx_hw_init_power_auth(struct wl12xx *wl) +int wl1251_hw_init_power_auth(struct wl1251 *wl) { - return wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM); + return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); } diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl12xx/wl1251_init.h index 2b6268e1855..8596188e834 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.h +++ b/drivers/net/wireless/wl12xx/wl1251_init.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2009 Nokia Corporation * @@ -21,19 +21,19 @@ * */ -#ifndef __WL12XX_INIT_H__ -#define __WL12XX_INIT_H__ +#ifndef __WL1251_INIT_H__ +#define __WL1251_INIT_H__ #include "wl1251.h" -int wl12xx_hw_init_hwenc_config(struct wl12xx *wl); -int wl12xx_hw_init_templates_config(struct wl12xx *wl); -int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter); -int wl12xx_hw_init_phy_config(struct wl12xx *wl); -int wl12xx_hw_init_beacon_filter(struct wl12xx *wl); -int wl12xx_hw_init_pta(struct wl12xx *wl); -int wl12xx_hw_init_energy_detection(struct wl12xx *wl); -int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl); -int wl12xx_hw_init_power_auth(struct wl12xx *wl); +int wl1251_hw_init_hwenc_config(struct wl1251 *wl); +int wl1251_hw_init_templates_config(struct wl1251 *wl); +int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter); +int wl1251_hw_init_phy_config(struct wl1251 *wl); +int wl1251_hw_init_beacon_filter(struct wl1251 *wl); +int wl1251_hw_init_pta(struct wl1251 *wl); +int wl1251_hw_init_energy_detection(struct wl1251 *wl); +int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl); +int wl1251_hw_init_power_auth(struct wl1251 *wl); #endif diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 41b9c616ee8..f4bc5796c24 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2008-2009 Nokia Corporation * @@ -43,26 +43,26 @@ #include "wl1251_init.h" #include "wl1251_debugfs.h" -static void wl12xx_disable_interrupts(struct wl12xx *wl) +static void wl1251_disable_interrupts(struct wl1251 *wl) { disable_irq(wl->irq); } -static void wl12xx_power_off(struct wl12xx *wl) +static void wl1251_power_off(struct wl1251 *wl) { wl->set_power(false); } -static void wl12xx_power_on(struct wl12xx *wl) +static void wl1251_power_on(struct wl1251 *wl) { wl->set_power(true); } -static irqreturn_t wl12xx_irq(int irq, void *cookie) +static irqreturn_t wl1251_irq(int irq, void *cookie) { - struct wl12xx *wl; + struct wl1251 *wl; - wl12xx_debug(DEBUG_IRQ, "IRQ"); + wl1251_debug(DEBUG_IRQ, "IRQ"); wl = cookie; @@ -71,7 +71,7 @@ static irqreturn_t wl12xx_irq(int irq, void *cookie) return IRQ_HANDLED; } -static int wl12xx_fetch_firmware(struct wl12xx *wl) +static int wl1251_fetch_firmware(struct wl1251 *wl) { const struct firmware *fw; int ret; @@ -79,12 +79,12 @@ static int wl12xx_fetch_firmware(struct wl12xx *wl) ret = request_firmware(&fw, wl->chip.fw_filename, &wl->spi->dev); if (ret < 0) { - wl12xx_error("could not get firmware: %d", ret); + wl1251_error("could not get firmware: %d", ret); return ret; } if (fw->size % 4) { - wl12xx_error("firmware size is not multiple of 32 bits: %zu", + wl1251_error("firmware size is not multiple of 32 bits: %zu", fw->size); ret = -EILSEQ; goto out; @@ -94,7 +94,7 @@ static int wl12xx_fetch_firmware(struct wl12xx *wl) wl->fw = kmalloc(wl->fw_len, GFP_KERNEL); if (!wl->fw) { - wl12xx_error("could not allocate memory for the firmware"); + wl1251_error("could not allocate memory for the firmware"); ret = -ENOMEM; goto out; } @@ -109,7 +109,7 @@ out: return ret; } -static int wl12xx_fetch_nvs(struct wl12xx *wl) +static int wl1251_fetch_nvs(struct wl1251 *wl) { const struct firmware *fw; int ret; @@ -117,12 +117,12 @@ static int wl12xx_fetch_nvs(struct wl12xx *wl) ret = request_firmware(&fw, wl->chip.nvs_filename, &wl->spi->dev); if (ret < 0) { - wl12xx_error("could not get nvs file: %d", ret); + wl1251_error("could not get nvs file: %d", ret); return ret; } if (fw->size % 4) { - wl12xx_error("nvs size is not multiple of 32 bits: %zu", + wl1251_error("nvs size is not multiple of 32 bits: %zu", fw->size); ret = -EILSEQ; goto out; @@ -132,7 +132,7 @@ static int wl12xx_fetch_nvs(struct wl12xx *wl) wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL); if (!wl->nvs) { - wl12xx_error("could not allocate memory for the nvs file"); + wl1251_error("could not allocate memory for the nvs file"); ret = -ENOMEM; goto out; } @@ -147,49 +147,49 @@ out: return ret; } -static void wl12xx_fw_wakeup(struct wl12xx *wl) +static void wl1251_fw_wakeup(struct wl1251 *wl) { u32 elp_reg; elp_reg = ELPCTRL_WAKE_UP; - wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); - elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); + elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); if (!(elp_reg & ELPCTRL_WLAN_READY)) { - wl12xx_warning("WLAN not ready"); + wl1251_warning("WLAN not ready"); } } -static int wl12xx_chip_wakeup(struct wl12xx *wl) +static int wl1251_chip_wakeup(struct wl1251 *wl) { int ret = 0; - wl12xx_power_on(wl); + wl1251_power_on(wl); msleep(wl->chip.power_on_sleep); - wl12xx_spi_reset(wl); - wl12xx_spi_init(wl); + wl1251_spi_reset(wl); + wl1251_spi_init(wl); /* We don't need a real memory partition here, because we only want * to use the registers at this point. */ - wl12xx_set_partition(wl, + wl1251_set_partition(wl, 0x00000000, 0x00000000, REGISTERS_BASE, REGISTERS_DOWN_SIZE); /* ELP module wake up */ - wl12xx_fw_wakeup(wl); + wl1251_fw_wakeup(wl); /* whal_FwCtrl_BootSm() */ /* 0. read chip id from CHIP_ID */ - wl->chip.id = wl12xx_reg_read32(wl, CHIP_ID_B); + wl->chip.id = wl1251_reg_read32(wl, CHIP_ID_B); /* 1. check if chip id is valid */ switch (wl->chip.id) { case CHIP_ID_1251_PG12: - wl12xx_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", + wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", wl->chip.id); wl1251_setup(wl); @@ -198,20 +198,20 @@ static int wl12xx_chip_wakeup(struct wl12xx *wl) case CHIP_ID_1251_PG10: case CHIP_ID_1251_PG11: default: - wl12xx_error("unsupported chip id: 0x%x", wl->chip.id); + wl1251_error("unsupported chip id: 0x%x", wl->chip.id); ret = -ENODEV; goto out; } if (wl->fw == NULL) { - ret = wl12xx_fetch_firmware(wl); + ret = wl1251_fetch_firmware(wl); if (ret < 0) goto out; } /* No NVS from netlink, try to get it from the filesystem */ if (wl->nvs == NULL) { - ret = wl12xx_fetch_nvs(wl); + ret = wl1251_fetch_nvs(wl); if (ret < 0) goto out; } @@ -220,18 +220,18 @@ out: return ret; } -static void wl12xx_filter_work(struct work_struct *work) +static void wl1251_filter_work(struct work_struct *work) { - struct wl12xx *wl = - container_of(work, struct wl12xx, filter_work); + struct wl1251 *wl = + container_of(work, struct wl1251, filter_work); int ret; mutex_lock(&wl->mutex); - if (wl->state == WL12XX_STATE_OFF) + if (wl->state == WL1251_STATE_OFF) goto out; - ret = wl12xx_ps_elp_wakeup(wl); + ret = wl1251_ps_elp_wakeup(wl); if (ret < 0) goto out; @@ -241,27 +241,29 @@ static void wl12xx_filter_work(struct work_struct *work) goto out_sleep; out_sleep: - wl12xx_ps_elp_sleep(wl); + wl1251_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); } -int wl12xx_plt_start(struct wl12xx *wl) +int wl1251_plt_start(struct wl1251 *wl) { int ret; - wl12xx_notice("power up"); + mutex_lock(&wl->mutex); + + wl1251_notice("power up"); - if (wl->state != WL12XX_STATE_OFF) { - wl12xx_error("cannot go into PLT state because not " + if (wl->state != WL1251_STATE_OFF) { + wl1251_error("cannot go into PLT state because not " "in off state: %d", wl->state); return -EBUSY; } - wl->state = WL12XX_STATE_PLT; + wl->state = WL1251_STATE_PLT; - ret = wl12xx_chip_wakeup(wl); + ret = wl1251_chip_wakeup(wl); if (ret < 0) return ret; @@ -269,7 +271,7 @@ int wl12xx_plt_start(struct wl12xx *wl) if (ret < 0) return ret; - wl12xx_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); + wl1251_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); ret = wl->chip.op_plt_init(wl); if (ret < 0) @@ -278,28 +280,30 @@ int wl12xx_plt_start(struct wl12xx *wl) return 0; } -int wl12xx_plt_stop(struct wl12xx *wl) +int wl1251_plt_stop(struct wl1251 *wl) { - wl12xx_notice("power down"); + mutex_lock(&wl->mutex); + + wl1251_notice("power down"); - if (wl->state != WL12XX_STATE_PLT) { - wl12xx_error("cannot power down because not in PLT " + if (wl->state != WL1251_STATE_PLT) { + wl1251_error("cannot power down because not in PLT " "state: %d", wl->state); return -EBUSY; } - wl12xx_disable_interrupts(wl); - wl12xx_power_off(wl); + wl1251_disable_interrupts(wl); + wl1251_power_off(wl); - wl->state = WL12XX_STATE_OFF; + wl->state = WL1251_STATE_OFF; return 0; } -static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { - struct wl12xx *wl = hw->priv; + struct wl1251 *wl = hw->priv; skb_queue_tail(&wl->tx_queue, skb); @@ -314,7 +318,7 @@ static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * The workqueue is slow to process the tx_queue and we need stop * the queue here, otherwise the queue will get too long. */ - if (skb_queue_len(&wl->tx_queue) >= WL12XX_TX_QUEUE_MAX_LENGTH) { + if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_MAX_LENGTH) { ieee80211_stop_queues(wl->hw); /* @@ -328,23 +332,23 @@ static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return NETDEV_TX_OK; } -static int wl12xx_op_start(struct ieee80211_hw *hw) +static int wl1251_op_start(struct ieee80211_hw *hw) { - struct wl12xx *wl = hw->priv; + struct wl1251 *wl = hw->priv; int ret = 0; - wl12xx_debug(DEBUG_MAC80211, "mac80211 start"); + wl1251_debug(DEBUG_MAC80211, "mac80211 start"); mutex_lock(&wl->mutex); - if (wl->state != WL12XX_STATE_OFF) { - wl12xx_error("cannot start because not in off state: %d", + if (wl->state != WL1251_STATE_OFF) { + wl1251_error("cannot start because not in off state: %d", wl->state); ret = -EBUSY; goto out; } - ret = wl12xx_chip_wakeup(wl); + ret = wl1251_chip_wakeup(wl); if (ret < 0) return ret; @@ -356,34 +360,34 @@ static int wl12xx_op_start(struct ieee80211_hw *hw) if (ret < 0) goto out; - ret = wl12xx_acx_station_id(wl); + ret = wl1251_acx_station_id(wl); if (ret < 0) goto out; - wl->state = WL12XX_STATE_ON; + wl->state = WL1251_STATE_ON; - wl12xx_info("firmware booted (%s)", wl->chip.fw_ver); + wl1251_info("firmware booted (%s)", wl->chip.fw_ver); out: if (ret < 0) - wl12xx_power_off(wl); + wl1251_power_off(wl); mutex_unlock(&wl->mutex); return ret; } -static void wl12xx_op_stop(struct ieee80211_hw *hw) +static void wl1251_op_stop(struct ieee80211_hw *hw) { - struct wl12xx *wl = hw->priv; + struct wl1251 *wl = hw->priv; - wl12xx_info("down"); + wl1251_info("down"); - wl12xx_debug(DEBUG_MAC80211, "mac80211 stop"); + wl1251_debug(DEBUG_MAC80211, "mac80211 stop"); mutex_lock(&wl->mutex); - WARN_ON(wl->state != WL12XX_STATE_ON); + WARN_ON(wl->state != WL1251_STATE_ON); if (wl->scanning) { mutex_unlock(&wl->mutex); @@ -392,9 +396,9 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw) wl->scanning = false; } - wl->state = WL12XX_STATE_OFF; + wl->state = WL1251_STATE_OFF; - wl12xx_disable_interrupts(wl); + wl1251_disable_interrupts(wl); mutex_unlock(&wl->mutex); @@ -406,7 +410,7 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw) /* let's notify MAC80211 about the remaining pending TX frames */ wl->chip.op_tx_flush(wl); - wl12xx_power_off(wl); + wl1251_power_off(wl); memset(wl->bssid, 0, ETH_ALEN); wl->listen_int = 1; @@ -421,21 +425,21 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw) wl->elp = false; wl->psm = 0; wl->tx_queue_stopped = false; - wl->power_level = WL12XX_DEFAULT_POWER_LEVEL; + wl->power_level = WL1251_DEFAULT_POWER_LEVEL; - wl12xx_debugfs_reset(wl); + wl1251_debugfs_reset(wl); mutex_unlock(&wl->mutex); } -static int wl12xx_op_add_interface(struct ieee80211_hw *hw, +static int wl1251_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { - struct wl12xx *wl = hw->priv; + struct wl1251 *wl = hw->priv; DECLARE_MAC_BUF(mac); int ret = 0; - wl12xx_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", + wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", conf->type, print_mac(mac, conf->mac_addr)); mutex_lock(&wl->mutex); @@ -455,7 +459,7 @@ static int wl12xx_op_add_interface(struct ieee80211_hw *hw, if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) { memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); - ret = wl12xx_acx_station_id(wl); + ret = wl1251_acx_station_id(wl); if (ret < 0) goto out; } @@ -465,13 +469,13 @@ out: return ret; } -static void wl12xx_op_remove_interface(struct ieee80211_hw *hw, +static void wl1251_op_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { - wl12xx_debug(DEBUG_MAC80211, "mac80211 remove interface"); + wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface"); } -static int wl12xx_build_null_data(struct wl12xx *wl) +static int wl1251_build_null_data(struct wl1251 *wl) { struct wl12xx_null_data_template template; @@ -487,12 +491,12 @@ static int wl12xx_build_null_data(struct wl12xx *wl) template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC); - return wl12xx_cmd_template_set(wl, CMD_NULL_DATA, &template, + return wl1251_cmd_template_set(wl, CMD_NULL_DATA, &template, sizeof(template)); } -static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid) +static int wl1251_build_ps_poll(struct wl1251 *wl, u16 aid) { struct wl12xx_ps_poll_template template; @@ -501,27 +505,27 @@ static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid) template.aid = aid; template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); - return wl12xx_cmd_template_set(wl, CMD_PS_POLL, &template, + return wl1251_cmd_template_set(wl, CMD_PS_POLL, &template, sizeof(template)); } -static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) +static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) { - struct wl12xx *wl = hw->priv; + struct wl1251 *wl = hw->priv; struct ieee80211_conf *conf = &hw->conf; int channel, ret = 0; channel = ieee80211_frequency_to_channel(conf->channel->center_freq); - wl12xx_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", + wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", channel, conf->flags & IEEE80211_CONF_PS ? "on" : "off", conf->power_level); mutex_lock(&wl->mutex); - ret = wl12xx_ps_elp_wakeup(wl); + ret = wl1251_ps_elp_wakeup(wl); if (ret < 0) goto out; @@ -534,12 +538,12 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) wl->channel = channel; } - ret = wl12xx_build_null_data(wl); + ret = wl1251_build_null_data(wl); if (ret < 0) goto out_sleep; if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { - wl12xx_info("psm enabled"); + wl1251_info("psm enabled"); wl->psm_requested = true; @@ -548,19 +552,19 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) * If we're not, we'll enter it when joining an SSID, * through the bss_info_changed() hook. */ - ret = wl12xx_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); } else if (!(conf->flags & IEEE80211_CONF_PS) && wl->psm_requested) { - wl12xx_info("psm disabled"); + wl1251_info("psm disabled"); wl->psm_requested = false; if (wl->psm) - ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE); + ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); } if (conf->power_level != wl->power_level) { - ret = wl12xx_acx_tx_power(wl, conf->power_level); + ret = wl1251_acx_tx_power(wl, conf->power_level); if (ret < 0) goto out; @@ -568,7 +572,7 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) } out_sleep: - wl12xx_ps_elp_sleep(wl); + wl1251_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); @@ -576,25 +580,25 @@ out: return ret; } -#define WL12XX_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ +#define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ FIF_ALLMULTI | \ FIF_FCSFAIL | \ FIF_BCN_PRBRESP_PROMISC | \ FIF_CONTROL | \ FIF_OTHER_BSS) -static void wl12xx_op_configure_filter(struct ieee80211_hw *hw, +static void wl1251_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, unsigned int *total, int mc_count, struct dev_addr_list *mc_list) { - struct wl12xx *wl = hw->priv; + struct wl1251 *wl = hw->priv; - wl12xx_debug(DEBUG_MAC80211, "mac80211 configure filter"); + wl1251_debug(DEBUG_MAC80211, "mac80211 configure filter"); - *total &= WL12XX_SUPPORTED_FILTERS; - changed &= WL12XX_SUPPORTED_FILTERS; + *total &= WL1251_SUPPORTED_FILTERS; + changed &= WL1251_SUPPORTED_FILTERS; if (changed == 0) /* no filters which we support changed */ @@ -602,8 +606,8 @@ static void wl12xx_op_configure_filter(struct ieee80211_hw *hw, /* FIXME: wl->rx_config and wl->rx_filter are not protected */ - wl->rx_config = WL12XX_DEFAULT_RX_CONFIG; - wl->rx_filter = WL12XX_DEFAULT_RX_FILTER; + wl->rx_config = WL1251_DEFAULT_RX_CONFIG; + wl->rx_filter = WL1251_DEFAULT_RX_FILTER; if (*total & FIF_PROMISC_IN_BSS) { wl->rx_config |= CFG_BSSID_FILTER_EN; @@ -635,8 +639,8 @@ static void wl12xx_op_configure_filter(struct ieee80211_hw *hw, } /* HW encryption */ -static int wl12xx_set_key_type(struct wl12xx *wl, - struct wl12xx_cmd_set_keys *key, +static int wl1251_set_key_type(struct wl1251 *wl, + struct wl1251_cmd_set_keys *key, enum set_key_cmd cmd, struct ieee80211_key_conf *mac80211_key, const u8 *addr) @@ -666,27 +670,27 @@ static int wl12xx_set_key_type(struct wl12xx *wl, mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; break; default: - wl12xx_error("Unknown key algo 0x%x", mac80211_key->alg); + wl1251_error("Unknown key algo 0x%x", mac80211_key->alg); return -EOPNOTSUPP; } return 0; } -static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, +static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { - struct wl12xx *wl = hw->priv; - struct wl12xx_cmd_set_keys *wl_cmd; + struct wl1251 *wl = hw->priv; + struct wl1251_cmd_set_keys *wl_cmd; const u8 *addr; int ret; static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - wl12xx_debug(DEBUG_MAC80211, "mac80211 set key"); + wl1251_debug(DEBUG_MAC80211, "mac80211 set key"); wl_cmd = kzalloc(sizeof(*wl_cmd), GFP_KERNEL); if (!wl_cmd) { @@ -696,11 +700,11 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, addr = sta ? sta->addr : bcast_addr; - wl12xx_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); - wl12xx_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); - wl12xx_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", + wl1251_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); + wl1251_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); + wl1251_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", key->alg, key->keyidx, key->keylen, key->flags); - wl12xx_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen); + wl1251_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen); if (is_zero_ether_addr(addr)) { /* We dont support TX only encryption */ @@ -710,7 +714,7 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mutex_lock(&wl->mutex); - ret = wl12xx_ps_elp_wakeup(wl); + ret = wl1251_ps_elp_wakeup(wl); if (ret < 0) goto out_unlock; @@ -722,13 +726,13 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, wl_cmd->key_action = KEY_REMOVE; break; default: - wl12xx_error("Unsupported key cmd 0x%x", cmd); + wl1251_error("Unsupported key cmd 0x%x", cmd); break; } - ret = wl12xx_set_key_type(wl, wl_cmd, cmd, key, addr); + ret = wl1251_set_key_type(wl, wl_cmd, cmd, key, addr); if (ret < 0) { - wl12xx_error("Set KEY type failed"); + wl1251_error("Set KEY type failed"); goto out_sleep; } @@ -755,16 +759,16 @@ static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, wl_cmd->id = key->keyidx; wl_cmd->ssid_profile = 0; - wl12xx_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd)); + wl1251_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd)); - ret = wl12xx_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd)); + ret = wl1251_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd)); if (ret < 0) { - wl12xx_warning("could not set keys"); + wl1251_warning("could not set keys"); goto out_sleep; } out_sleep: - wl12xx_ps_elp_sleep(wl); + wl1251_ps_elp_sleep(wl); out_unlock: mutex_unlock(&wl->mutex); @@ -775,7 +779,7 @@ out: return ret; } -static int wl12xx_build_basic_rates(char *rates) +static int wl1251_build_basic_rates(char *rates) { u8 index = 0; @@ -787,7 +791,7 @@ static int wl12xx_build_basic_rates(char *rates) return index; } -static int wl12xx_build_extended_rates(char *rates) +static int wl1251_build_extended_rates(char *rates) { u8 index = 0; @@ -804,7 +808,7 @@ static int wl12xx_build_extended_rates(char *rates) } -static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len) +static int wl1251_build_probe_req(struct wl1251 *wl, u8 *ssid, size_t ssid_len) { struct wl12xx_probe_req_template template; struct wl12xx_ie_rates *rates; @@ -831,27 +835,27 @@ static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len) /* Basic Rates */ rates = (struct wl12xx_ie_rates *)ptr; rates->header.id = WLAN_EID_SUPP_RATES; - rates->header.len = wl12xx_build_basic_rates(rates->rates); + rates->header.len = wl1251_build_basic_rates(rates->rates); size += sizeof(struct wl12xx_ie_header) + rates->header.len; ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; /* Extended rates */ rates = (struct wl12xx_ie_rates *)ptr; rates->header.id = WLAN_EID_EXT_SUPP_RATES; - rates->header.len = wl12xx_build_extended_rates(rates->rates); + rates->header.len = wl1251_build_extended_rates(rates->rates); size += sizeof(struct wl12xx_ie_header) + rates->header.len; - wl12xx_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); + wl1251_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); - return wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, &template, + return wl1251_cmd_template_set(wl, CMD_PROBE_REQ, &template, size); } -static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len, +static int wl1251_hw_scan(struct wl1251 *wl, u8 *ssid, size_t len, u8 active_scan, u8 high_prio, u8 num_channels, u8 probe_requests) { - struct wl12xx_cmd_trigger_scan_to *trigger = NULL; + struct wl1251_cmd_trigger_scan_to *trigger = NULL; struct cmd_scan *params = NULL; int i, ret; u16 scan_options = 0; @@ -902,9 +906,9 @@ static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len, memset(params->params.ssid, 0, 32); } - ret = wl12xx_build_probe_req(wl, ssid, len); + ret = wl1251_build_probe_req(wl, ssid, len); if (ret < 0) { - wl12xx_error("PROBE request template failed"); + wl1251_error("PROBE request template failed"); goto out; } @@ -914,25 +918,25 @@ static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len, trigger->timeout = 0; - ret = wl12xx_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, + ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, sizeof(*trigger)); if (ret < 0) { - wl12xx_error("trigger scan to failed for hw scan"); + wl1251_error("trigger scan to failed for hw scan"); goto out; } - wl12xx_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); + wl1251_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); wl->scanning = true; - ret = wl12xx_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); + ret = wl1251_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); if (ret < 0) - wl12xx_error("SCAN failed"); + wl1251_error("SCAN failed"); - wl12xx_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); + wl1251_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); if (params->header.status != CMD_STATUS_SUCCESS) { - wl12xx_error("TEST command answer error: %d", + wl1251_error("TEST command answer error: %d", params->header.status); wl->scanning = false; ret = -EIO; @@ -945,15 +949,15 @@ out: } -static int wl12xx_op_hw_scan(struct ieee80211_hw *hw, +static int wl1251_op_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req) { - struct wl12xx *wl = hw->priv; + struct wl1251 *wl = hw->priv; int ret; u8 *ssid = NULL; size_t ssid_len = 0; - wl12xx_debug(DEBUG_MAC80211, "mac80211 hw scan"); + wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan"); if (req->n_ssids) { ssid = req->ssids[0].ssid; @@ -962,13 +966,13 @@ static int wl12xx_op_hw_scan(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); - ret = wl12xx_ps_elp_wakeup(wl); + ret = wl1251_ps_elp_wakeup(wl); if (ret < 0) goto out; - ret = wl12xx_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); + ret = wl1251_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); - wl12xx_ps_elp_sleep(wl); + wl1251_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); @@ -976,22 +980,22 @@ out: return ret; } -static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +static int wl1251_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { - struct wl12xx *wl = hw->priv; + struct wl1251 *wl = hw->priv; int ret; mutex_lock(&wl->mutex); - ret = wl12xx_ps_elp_wakeup(wl); + ret = wl1251_ps_elp_wakeup(wl); if (ret < 0) goto out; - ret = wl12xx_acx_rts_threshold(wl, (u16) value); + ret = wl1251_acx_rts_threshold(wl, (u16) value); if (ret < 0) - wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret); + wl1251_warning("wl1251_op_set_rts_threshold failed: %d", ret); - wl12xx_ps_elp_sleep(wl); + wl1251_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); @@ -999,21 +1003,21 @@ out: return ret; } -static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, +static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changed) { - enum wl12xx_cmd_ps_mode mode; - struct wl12xx *wl = hw->priv; + enum wl1251_cmd_ps_mode mode; + struct wl1251 *wl = hw->priv; struct sk_buff *beacon; int ret; - wl12xx_debug(DEBUG_MAC80211, "mac80211 bss info changed"); + wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed"); mutex_lock(&wl->mutex); - ret = wl12xx_ps_elp_wakeup(wl); + ret = wl1251_ps_elp_wakeup(wl); if (ret < 0) goto out; @@ -1021,18 +1025,18 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, if (bss_conf->assoc) { wl->aid = bss_conf->aid; - ret = wl12xx_build_ps_poll(wl, wl->aid); + ret = wl1251_build_ps_poll(wl, wl->aid); if (ret < 0) goto out_sleep; - ret = wl12xx_acx_aid(wl, wl->aid); + ret = wl1251_acx_aid(wl, wl->aid); if (ret < 0) goto out_sleep; /* If we want to go in PSM but we're not there yet */ if (wl->psm_requested && !wl->psm) { mode = STATION_POWER_SAVE_MODE; - ret = wl12xx_ps_set_mode(wl, mode); + ret = wl1251_ps_set_mode(wl, mode); if (ret < 0) goto out_sleep; } @@ -1040,50 +1044,52 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ERP_SLOT) { if (bss_conf->use_short_slot) - ret = wl12xx_acx_slot(wl, SLOT_TIME_SHORT); + ret = wl1251_acx_slot(wl, SLOT_TIME_SHORT); else - ret = wl12xx_acx_slot(wl, SLOT_TIME_LONG); + ret = wl1251_acx_slot(wl, SLOT_TIME_LONG); if (ret < 0) { - wl12xx_warning("Set slot time failed %d", ret); + wl1251_warning("Set slot time failed %d", ret); goto out_sleep; } } if (changed & BSS_CHANGED_ERP_PREAMBLE) { if (bss_conf->use_short_preamble) - wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); + wl1251_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); else - wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_LONG); + wl1251_acx_set_preamble(wl, ACX_PREAMBLE_LONG); } if (changed & BSS_CHANGED_ERP_CTS_PROT) { if (bss_conf->use_cts_prot) - ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_ENABLE); + ret = wl1251_acx_cts_protect(wl, CTSPROTECT_ENABLE); else - ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_DISABLE); + ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE); if (ret < 0) { - wl12xx_warning("Set ctsprotect failed %d", ret); - goto out_sleep; + wl1251_warning("Set ctsprotect failed %d", ret); + goto out; } } if (changed & BSS_CHANGED_BSSID) { memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); - ret = wl12xx_build_null_data(wl); + ret = wl1251_build_null_data(wl); if (ret < 0) goto out; if (wl->bss_type != BSS_TYPE_IBSS) { - ret = wl->chip.op_cmd_join(wl, wl->bss_type, 5, 100, 1); + ret = wl1251_cmd_join(wl, wl->bss_type, 5, 100, 1); if (ret < 0) - goto out; + goto out_sleep; + wl1251_warning("Set ctsprotect failed %d", ret); + goto out_sleep; } } if (changed & BSS_CHANGED_BEACON) { beacon = ieee80211_beacon_get(hw, vif); - ret = wl12xx_cmd_template_set(wl, CMD_BEACON, beacon->data, + ret = wl1251_cmd_template_set(wl, CMD_BEACON, beacon->data, beacon->len); if (ret < 0) { @@ -1091,7 +1097,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, goto out; } - ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, + ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, beacon->len); dev_kfree_skb(beacon); @@ -1106,7 +1112,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, } out_sleep: - wl12xx_ps_elp_sleep(wl); + wl1251_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); @@ -1114,7 +1120,7 @@ out: /* can't be const, mac80211 writes to this */ -static struct ieee80211_rate wl12xx_rates[] = { +static struct ieee80211_rate wl1251_rates[] = { { .bitrate = 10, .hw_value = 0x1, .hw_value_short = 0x1, }, @@ -1157,7 +1163,7 @@ static struct ieee80211_rate wl12xx_rates[] = { }; /* can't be const, mac80211 writes to this */ -static struct ieee80211_channel wl12xx_channels[] = { +static struct ieee80211_channel wl1251_channels[] = { { .hw_value = 1, .center_freq = 2412}, { .hw_value = 2, .center_freq = 2417}, { .hw_value = 3, .center_freq = 2422}, @@ -1174,28 +1180,28 @@ static struct ieee80211_channel wl12xx_channels[] = { }; /* can't be const, mac80211 writes to this */ -static struct ieee80211_supported_band wl12xx_band_2ghz = { - .channels = wl12xx_channels, - .n_channels = ARRAY_SIZE(wl12xx_channels), - .bitrates = wl12xx_rates, - .n_bitrates = ARRAY_SIZE(wl12xx_rates), +static struct ieee80211_supported_band wl1251_band_2ghz = { + .channels = wl1251_channels, + .n_channels = ARRAY_SIZE(wl1251_channels), + .bitrates = wl1251_rates, + .n_bitrates = ARRAY_SIZE(wl1251_rates), }; -static const struct ieee80211_ops wl12xx_ops = { - .start = wl12xx_op_start, - .stop = wl12xx_op_stop, - .add_interface = wl12xx_op_add_interface, - .remove_interface = wl12xx_op_remove_interface, - .config = wl12xx_op_config, - .configure_filter = wl12xx_op_configure_filter, - .tx = wl12xx_op_tx, - .set_key = wl12xx_op_set_key, - .hw_scan = wl12xx_op_hw_scan, - .bss_info_changed = wl12xx_op_bss_info_changed, - .set_rts_threshold = wl12xx_op_set_rts_threshold, +static const struct ieee80211_ops wl1251_ops = { + .start = wl1251_op_start, + .stop = wl1251_op_stop, + .add_interface = wl1251_op_add_interface, + .remove_interface = wl1251_op_remove_interface, + .config = wl1251_op_config, + .configure_filter = wl1251_op_configure_filter, + .tx = wl1251_op_tx, + .set_key = wl1251_op_set_key, + .hw_scan = wl1251_op_hw_scan, + .bss_info_changed = wl1251_op_bss_info_changed, + .set_rts_threshold = wl1251_op_set_rts_threshold, }; -static int wl12xx_register_hw(struct wl12xx *wl) +static int wl1251_register_hw(struct wl1251 *wl) { int ret; @@ -1206,18 +1212,18 @@ static int wl12xx_register_hw(struct wl12xx *wl) ret = ieee80211_register_hw(wl->hw); if (ret < 0) { - wl12xx_error("unable to register mac80211 hw: %d", ret); + wl1251_error("unable to register mac80211 hw: %d", ret); return ret; } wl->mac80211_registered = true; - wl12xx_notice("loaded"); + wl1251_notice("loaded"); return 0; } -static int wl12xx_init_ieee80211(struct wl12xx *wl) +static int wl1251_init_ieee80211(struct wl1251 *wl) { /* The tx descriptor buffer and the TKIP space */ wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) @@ -1232,31 +1238,31 @@ static int wl12xx_init_ieee80211(struct wl12xx *wl) wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); wl->hw->wiphy->max_scan_ssids = 1; - wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl12xx_band_2ghz; + wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; SET_IEEE80211_DEV(wl->hw, &wl->spi->dev); return 0; } -#define WL12XX_DEFAULT_CHANNEL 1 -static int __devinit wl12xx_probe(struct spi_device *spi) +#define WL1251_DEFAULT_CHANNEL 1 +static int __devinit wl1251_probe(struct spi_device *spi) { struct wl12xx_platform_data *pdata; struct ieee80211_hw *hw; - struct wl12xx *wl; + struct wl1251 *wl; int ret, i; static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; pdata = spi->dev.platform_data; if (!pdata) { - wl12xx_error("no platform data"); + wl1251_error("no platform data"); return -ENODEV; } - hw = ieee80211_alloc_hw(sizeof(*wl), &wl12xx_ops); + hw = ieee80211_alloc_hw(sizeof(*wl), &wl1251_ops); if (!hw) { - wl12xx_error("could not alloc ieee80211_hw"); + wl1251_error("could not alloc ieee80211_hw"); return -ENOMEM; } @@ -1271,8 +1277,8 @@ static int __devinit wl12xx_probe(struct spi_device *spi) skb_queue_head_init(&wl->tx_queue); - INIT_WORK(&wl->filter_work, wl12xx_filter_work); - wl->channel = WL12XX_DEFAULT_CHANNEL; + INIT_WORK(&wl->filter_work, wl1251_filter_work); + wl->channel = WL1251_DEFAULT_CHANNEL; wl->scanning = false; wl->default_key = 0; wl->listen_int = 1; @@ -1280,17 +1286,17 @@ static int __devinit wl12xx_probe(struct spi_device *spi) wl->rx_handled = 0; wl->rx_current_buffer = 0; wl->rx_last_id = 0; - wl->rx_config = WL12XX_DEFAULT_RX_CONFIG; - wl->rx_filter = WL12XX_DEFAULT_RX_FILTER; + wl->rx_config = WL1251_DEFAULT_RX_CONFIG; + wl->rx_filter = WL1251_DEFAULT_RX_FILTER; wl->elp = false; wl->psm = 0; wl->psm_requested = false; wl->tx_queue_stopped = false; - wl->power_level = WL12XX_DEFAULT_POWER_LEVEL; + wl->power_level = WL1251_DEFAULT_POWER_LEVEL; /* We use the default power on sleep time until we know which chip * we're using */ - wl->chip.power_on_sleep = WL12XX_DEFAULT_POWER_ON_SLEEP; + wl->chip.power_on_sleep = WL1251_DEFAULT_POWER_ON_SLEEP; for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) wl->tx_frames[i] = NULL; @@ -1304,7 +1310,7 @@ static int __devinit wl12xx_probe(struct spi_device *spi) memcpy(wl->mac_addr, nokia_oui, 3); get_random_bytes(wl->mac_addr + 3, 3); - wl->state = WL12XX_STATE_OFF; + wl->state = WL1251_STATE_OFF; mutex_init(&wl->mutex); wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE; @@ -1312,7 +1318,7 @@ static int __devinit wl12xx_probe(struct spi_device *spi) wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); if (!wl->rx_descriptor) { - wl12xx_error("could not allocate memory for rx descriptor"); + wl1251_error("could not allocate memory for rx descriptor"); ret = -ENOMEM; goto out_free; } @@ -1323,27 +1329,27 @@ static int __devinit wl12xx_probe(struct spi_device *spi) ret = spi_setup(spi); if (ret < 0) { - wl12xx_error("spi_setup failed"); + wl1251_error("spi_setup failed"); goto out_free; } wl->set_power = pdata->set_power; if (!wl->set_power) { - wl12xx_error("set power function missing in platform data"); + wl1251_error("set power function missing in platform data"); ret = -ENODEV; goto out_free; } wl->irq = spi->irq; if (wl->irq < 0) { - wl12xx_error("irq missing in platform data"); + wl1251_error("irq missing in platform data"); ret = -ENODEV; goto out_free; } - ret = request_irq(wl->irq, wl12xx_irq, 0, DRIVER_NAME, wl); + ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); if (ret < 0) { - wl12xx_error("request_irq() failed: %d", ret); + wl1251_error("request_irq() failed: %d", ret); goto out_free; } @@ -1351,17 +1357,17 @@ static int __devinit wl12xx_probe(struct spi_device *spi) disable_irq(wl->irq); - ret = wl12xx_init_ieee80211(wl); + ret = wl1251_init_ieee80211(wl); if (ret) goto out_irq; - ret = wl12xx_register_hw(wl); + ret = wl1251_register_hw(wl); if (ret) goto out_irq; - wl12xx_debugfs_init(wl); + wl1251_debugfs_init(wl); - wl12xx_notice("initialized"); + wl1251_notice("initialized"); return 0; @@ -1377,13 +1383,13 @@ static int __devinit wl12xx_probe(struct spi_device *spi) return ret; } -static int __devexit wl12xx_remove(struct spi_device *spi) +static int __devexit wl1251_remove(struct spi_device *spi) { - struct wl12xx *wl = dev_get_drvdata(&spi->dev); + struct wl1251 *wl = dev_get_drvdata(&spi->dev); ieee80211_unregister_hw(wl->hw); - wl12xx_debugfs_exit(wl); + wl1251_debugfs_exit(wl); free_irq(wl->irq, wl); kfree(wl->target_mem_map); @@ -1402,24 +1408,25 @@ static int __devexit wl12xx_remove(struct spi_device *spi) } -static struct spi_driver wl12xx_spi_driver = { +static struct spi_driver wl1251_spi_driver = { .driver = { + /* FIXME: use wl12xx name to not break the user space */ .name = "wl12xx", .bus = &spi_bus_type, .owner = THIS_MODULE, }, - .probe = wl12xx_probe, - .remove = __devexit_p(wl12xx_remove), + .probe = wl1251_probe, + .remove = __devexit_p(wl1251_remove), }; -static int __init wl12xx_init(void) +static int __init wl1251_init(void) { int ret; - ret = spi_register_driver(&wl12xx_spi_driver); + ret = spi_register_driver(&wl1251_spi_driver); if (ret < 0) { - wl12xx_error("failed to register spi driver: %d", ret); + wl1251_error("failed to register spi driver: %d", ret); goto out; } @@ -1427,15 +1434,15 @@ out: return ret; } -static void __exit wl12xx_exit(void) +static void __exit wl1251_exit(void) { - spi_unregister_driver(&wl12xx_spi_driver); + spi_unregister_driver(&wl1251_spi_driver); - wl12xx_notice("unloaded"); + wl1251_notice("unloaded"); } -module_init(wl12xx_init); -module_exit(wl12xx_exit); +module_init(wl1251_init); +module_exit(wl1251_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kalle Valo , " diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.c b/drivers/net/wireless/wl12xx/wl1251_netlink.c index ca9a8567d58..67d3d5a3b51 100644 --- a/drivers/net/wireless/wl12xx/wl1251_netlink.c +++ b/drivers/net/wireless/wl12xx/wl1251_netlink.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2008 Nokia Corporation * @@ -35,52 +35,52 @@ #include "wl1251_acx.h" /* FIXME: this should be changed as soon as user space catches up */ -#define WL12XX_NL_NAME "wl1251" -#define WL12XX_NL_VERSION 1 - -#define WL12XX_MAX_TEST_LENGTH 1024 -#define WL12XX_MAX_NVS_LENGTH 1024 - -enum wl12xx_nl_commands { - WL12XX_NL_CMD_UNSPEC, - WL12XX_NL_CMD_TEST, - WL12XX_NL_CMD_INTERROGATE, - WL12XX_NL_CMD_CONFIGURE, - WL12XX_NL_CMD_PHY_REG_READ, - WL12XX_NL_CMD_NVS_PUSH, - WL12XX_NL_CMD_REG_WRITE, - WL12XX_NL_CMD_REG_READ, - WL12XX_NL_CMD_SET_PLT_MODE, - - __WL12XX_NL_CMD_AFTER_LAST +#define WL1251_NL_NAME "wl1251" +#define WL1251_NL_VERSION 1 + +#define WL1251_MAX_TEST_LENGTH 1024 +#define WL1251_MAX_NVS_LENGTH 1024 + +enum wl1251_nl_commands { + WL1251_NL_CMD_UNSPEC, + WL1251_NL_CMD_TEST, + WL1251_NL_CMD_INTERROGATE, + WL1251_NL_CMD_CONFIGURE, + WL1251_NL_CMD_PHY_REG_READ, + WL1251_NL_CMD_NVS_PUSH, + WL1251_NL_CMD_REG_WRITE, + WL1251_NL_CMD_REG_READ, + WL1251_NL_CMD_SET_PLT_MODE, + + __WL1251_NL_CMD_AFTER_LAST }; -#define WL12XX_NL_CMD_MAX (__WL12XX_NL_CMD_AFTER_LAST - 1) - -enum wl12xx_nl_attrs { - WL12XX_NL_ATTR_UNSPEC, - WL12XX_NL_ATTR_IFNAME, - WL12XX_NL_ATTR_CMD_TEST_PARAM, - WL12XX_NL_ATTR_CMD_TEST_ANSWER, - WL12XX_NL_ATTR_CMD_IE, - WL12XX_NL_ATTR_CMD_IE_LEN, - WL12XX_NL_ATTR_CMD_IE_BUFFER, - WL12XX_NL_ATTR_CMD_IE_ANSWER, - WL12XX_NL_ATTR_REG_ADDR, - WL12XX_NL_ATTR_REG_VAL, - WL12XX_NL_ATTR_NVS_BUFFER, - WL12XX_NL_ATTR_NVS_LEN, - WL12XX_NL_ATTR_PLT_MODE, - - __WL12XX_NL_ATTR_AFTER_LAST +#define WL1251_NL_CMD_MAX (__WL1251_NL_CMD_AFTER_LAST - 1) + +enum wl1251_nl_attrs { + WL1251_NL_ATTR_UNSPEC, + WL1251_NL_ATTR_IFNAME, + WL1251_NL_ATTR_CMD_TEST_PARAM, + WL1251_NL_ATTR_CMD_TEST_ANSWER, + WL1251_NL_ATTR_CMD_IE, + WL1251_NL_ATTR_CMD_IE_LEN, + WL1251_NL_ATTR_CMD_IE_BUFFER, + WL1251_NL_ATTR_CMD_IE_ANSWER, + WL1251_NL_ATTR_REG_ADDR, + WL1251_NL_ATTR_REG_VAL, + WL1251_NL_ATTR_NVS_BUFFER, + WL1251_NL_ATTR_NVS_LEN, + WL1251_NL_ATTR_PLT_MODE, + + __WL1251_NL_ATTR_AFTER_LAST }; -#define WL12XX_NL_ATTR_MAX (__WL12XX_NL_ATTR_AFTER_LAST - 1) +#define WL1251_NL_ATTR_MAX (__WL1251_NL_ATTR_AFTER_LAST - 1) -static struct genl_family wl12xx_nl_family = { +static struct genl_family wl1251_nl_family = { .id = GENL_ID_GENERATE, - .name = WL12XX_NL_NAME, + .name = WL1251_NL_NAME, .hdrsize = 0, - .version = WL12XX_NL_VERSION, - .maxattr = WL12XX_NL_ATTR_MAX, + .version = WL1251_NL_VERSION, + .maxattr = WL1251_NL_ATTR_MAX, }; static struct net_device *ifname_to_netdev(struct net *net, @@ -88,17 +88,17 @@ static struct net_device *ifname_to_netdev(struct net *net, { char *ifname; - if (!info->attrs[WL12XX_NL_ATTR_IFNAME]) + if (!info->attrs[WL1251_NL_ATTR_IFNAME]) return NULL; - ifname = nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME]); + ifname = nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]); - wl12xx_debug(DEBUG_NETLINK, "Looking for %s", ifname); + wl1251_debug(DEBUG_NETLINK, "Looking for %s", ifname); return dev_get_by_name(net, ifname); } -static struct wl12xx *ifname_to_wl12xx(struct net *net, struct genl_info *info) +static struct wl1251 *ifname_to_wl1251(struct net *net, struct genl_info *info) { struct net_device *netdev; struct wireless_dev *wdev; @@ -107,25 +107,25 @@ static struct wl12xx *ifname_to_wl12xx(struct net *net, struct genl_info *info) netdev = ifname_to_netdev(net, info); if (netdev == NULL) { - wl12xx_error("Wrong interface"); + wl1251_error("Wrong interface"); return NULL; } wdev = netdev->ieee80211_ptr; if (wdev == NULL) { - wl12xx_error("ieee80211_ptr is NULL"); + wl1251_error("ieee80211_ptr is NULL"); return NULL; } wiphy = wdev->wiphy; if (wiphy == NULL) { - wl12xx_error("wiphy is NULL"); + wl1251_error("wiphy is NULL"); return NULL; } hw = wiphy_priv(wiphy); if (hw == NULL) { - wl12xx_error("hw is NULL"); + wl1251_error("hw is NULL"); return NULL; } @@ -134,20 +134,20 @@ static struct wl12xx *ifname_to_wl12xx(struct net *net, struct genl_info *info) return hw->priv; } -static int wl12xx_nl_test_cmd(struct sk_buff *skb, struct genl_info *info) +static int wl1251_nl_test_cmd(struct sk_buff *skb, struct genl_info *info) { - struct wl12xx *wl; - struct wl12xx_command *cmd; + struct wl1251 *wl; + struct wl1251_command *cmd; char *buf; int buf_len, ret, cmd_len; u8 answer; - if (!info->attrs[WL12XX_NL_ATTR_CMD_TEST_PARAM]) + if (!info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]) return -EINVAL; - wl = ifname_to_wl12xx(&init_net, info); + wl = ifname_to_wl1251(&init_net, info); if (wl == NULL) { - wl12xx_error("wl12xx not found"); + wl1251_error("wl1251 not found"); return -EINVAL; } @@ -155,20 +155,20 @@ static int wl12xx_nl_test_cmd(struct sk_buff *skb, struct genl_info *info) if (!cmd) return -ENOMEM; - buf = nla_data(info->attrs[WL12XX_NL_ATTR_CMD_TEST_PARAM]); - buf_len = nla_len(info->attrs[WL12XX_NL_ATTR_CMD_TEST_PARAM]); - answer = nla_get_u8(info->attrs[WL12XX_NL_ATTR_CMD_TEST_ANSWER]); + buf = nla_data(info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]); + buf_len = nla_len(info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]); + answer = nla_get_u8(info->attrs[WL1251_NL_ATTR_CMD_TEST_ANSWER]); cmd->header.id = CMD_TEST; memcpy(cmd->parameters, buf, buf_len); - cmd_len = sizeof(struct wl12xx_cmd_header) + buf_len; + cmd_len = sizeof(struct wl1251_cmd_header) + buf_len; mutex_lock(&wl->mutex); - ret = wl12xx_cmd_test(wl, cmd, cmd_len, answer); + ret = wl1251_cmd_test(wl, cmd, cmd_len, answer); mutex_unlock(&wl->mutex); if (ret < 0) { - wl12xx_error("%s() failed", __func__); + wl1251_error("%s() failed", __func__); goto out; } @@ -183,49 +183,49 @@ static int wl12xx_nl_test_cmd(struct sk_buff *skb, struct genl_info *info) } hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, - &wl12xx_nl_family, 0, WL12XX_NL_CMD_TEST); + &wl1251_nl_family, 0, WL1251_NL_CMD_TEST); if (IS_ERR(hdr)) { ret = PTR_ERR(hdr); goto nla_put_failure; } - NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME, - nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME])); - NLA_PUT(msg, WL12XX_NL_ATTR_CMD_TEST_ANSWER, + NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME, + nla_data(info->attrs[WL1251_NL_ATTR_IFNAME])); + NLA_PUT(msg, WL1251_NL_ATTR_CMD_TEST_ANSWER, sizeof(*cmd), cmd); ret = genlmsg_end(msg, hdr); if (ret < 0) { - wl12xx_error("%s() failed", __func__); + wl1251_error("%s() failed", __func__); goto nla_put_failure; } - wl12xx_debug(DEBUG_NETLINK, "TEST cmd sent, answer"); + wl1251_debug(DEBUG_NETLINK, "TEST cmd sent, answer"); ret = genlmsg_reply(msg, info); goto out; nla_put_failure: nlmsg_free(msg); } else - wl12xx_debug(DEBUG_NETLINK, "TEST cmd sent"); + wl1251_debug(DEBUG_NETLINK, "TEST cmd sent"); out: kfree(cmd); return ret; } -static int wl12xx_nl_interrogate(struct sk_buff *skb, struct genl_info *info) +static int wl1251_nl_interrogate(struct sk_buff *skb, struct genl_info *info) { - struct wl12xx *wl; + struct wl1251 *wl; struct sk_buff *msg; int ret = -ENOBUFS, cmd_ie, cmd_ie_len; - struct wl12xx_command *cmd; + struct wl1251_command *cmd; void *hdr; - if (!info->attrs[WL12XX_NL_ATTR_CMD_IE]) + if (!info->attrs[WL1251_NL_ATTR_CMD_IE]) return -EINVAL; - if (!info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN]) + if (!info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]) return -EINVAL; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -236,45 +236,45 @@ static int wl12xx_nl_interrogate(struct sk_buff *skb, struct genl_info *info) if (!msg) return -ENOMEM; - wl = ifname_to_wl12xx(&init_net, info); + wl = ifname_to_wl1251(&init_net, info); if (wl == NULL) { - wl12xx_error("wl12xx not found"); + wl1251_error("wl1251 not found"); ret = -EINVAL; goto nla_put_failure; } /* acx id */ - cmd_ie = nla_get_u32(info->attrs[WL12XX_NL_ATTR_CMD_IE]); + cmd_ie = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE]); /* maximum length of acx, including all headers */ - cmd_ie_len = nla_get_u32(info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN]); + cmd_ie_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]); - wl12xx_debug(DEBUG_NETLINK, "Getting IE 0x%x (len %d)", + wl1251_debug(DEBUG_NETLINK, "Getting IE 0x%x (len %d)", cmd_ie, cmd_ie_len); mutex_lock(&wl->mutex); - ret = wl12xx_cmd_interrogate(wl, cmd_ie, cmd, cmd_ie_len); + ret = wl1251_cmd_interrogate(wl, cmd_ie, cmd, cmd_ie_len); mutex_unlock(&wl->mutex); if (ret < 0) { - wl12xx_error("%s() failed", __func__); + wl1251_error("%s() failed", __func__); goto nla_put_failure; } hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, - &wl12xx_nl_family, 0, WL12XX_NL_CMD_INTERROGATE); + &wl1251_nl_family, 0, WL1251_NL_CMD_INTERROGATE); if (IS_ERR(hdr)) { ret = PTR_ERR(hdr); goto nla_put_failure; } - NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME, - nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME])); - NLA_PUT(msg, WL12XX_NL_ATTR_CMD_IE_ANSWER, cmd_ie_len, cmd); + NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME, + nla_data(info->attrs[WL1251_NL_ATTR_IFNAME])); + NLA_PUT(msg, WL1251_NL_ATTR_CMD_IE_ANSWER, cmd_ie_len, cmd); ret = genlmsg_end(msg, hdr); if (ret < 0) { - wl12xx_error("%s() failed", __func__); + wl1251_error("%s() failed", __func__); goto nla_put_failure; } @@ -288,36 +288,36 @@ static int wl12xx_nl_interrogate(struct sk_buff *skb, struct genl_info *info) return ret; } -static int wl12xx_nl_configure(struct sk_buff *skb, struct genl_info *info) +static int wl1251_nl_configure(struct sk_buff *skb, struct genl_info *info) { int ret = 0, cmd_ie_len, acx_len; struct acx_header *acx = NULL; struct sk_buff *msg; - struct wl12xx *wl; + struct wl1251 *wl; void *cmd_ie; u16 *id; - if (!info->attrs[WL12XX_NL_ATTR_CMD_IE_BUFFER]) + if (!info->attrs[WL1251_NL_ATTR_CMD_IE_BUFFER]) return -EINVAL; - if (!info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN]) + if (!info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]) return -EINVAL; msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); if (!msg) return -ENOMEM; - wl = ifname_to_wl12xx(&init_net, info); + wl = ifname_to_wl1251(&init_net, info); if (wl == NULL) { - wl12xx_error("wl12xx not found"); + wl1251_error("wl1251 not found"); ret = -EINVAL; goto nla_put_failure; } /* contains the acx header but not the cmd header */ - cmd_ie = nla_data(info->attrs[WL12XX_NL_ATTR_CMD_IE_BUFFER]); + cmd_ie = nla_data(info->attrs[WL1251_NL_ATTR_CMD_IE_BUFFER]); - cmd_ie_len = nla_get_u32(info->attrs[WL12XX_NL_ATTR_CMD_IE_LEN]); + cmd_ie_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]); /* acx id is in the first two bytes */ id = cmd_ie; @@ -334,15 +334,15 @@ static int wl12xx_nl_configure(struct sk_buff *skb, struct genl_info *info) memcpy(&acx->id, cmd_ie, cmd_ie_len); mutex_lock(&wl->mutex); - ret = wl12xx_cmd_configure(wl, *id, acx, acx_len); + ret = wl1251_cmd_configure(wl, *id, acx, acx_len); mutex_unlock(&wl->mutex); if (ret < 0) { - wl12xx_error("%s() failed", __func__); + wl1251_error("%s() failed", __func__); goto nla_put_failure; } - wl12xx_debug(DEBUG_NETLINK, "CONFIGURE cmd sent"); + wl1251_debug(DEBUG_NETLINK, "CONFIGURE cmd sent"); nla_put_failure: kfree(acx); @@ -351,24 +351,24 @@ static int wl12xx_nl_configure(struct sk_buff *skb, struct genl_info *info) return ret; } -static int wl12xx_nl_phy_reg_read(struct sk_buff *skb, struct genl_info *info) +static int wl1251_nl_phy_reg_read(struct sk_buff *skb, struct genl_info *info) { - struct wl12xx *wl; + struct wl1251 *wl; struct sk_buff *msg; u32 reg_addr, *reg_value = NULL; int ret = 0; void *hdr; - if (!info->attrs[WL12XX_NL_ATTR_REG_ADDR]) + if (!info->attrs[WL1251_NL_ATTR_REG_ADDR]) return -EINVAL; msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); if (!msg) return -ENOMEM; - wl = ifname_to_wl12xx(&init_net, info); + wl = ifname_to_wl1251(&init_net, info); if (wl == NULL) { - wl12xx_error("wl12xx not found"); + wl1251_error("wl1251 not found"); ret = -EINVAL; goto nla_put_failure; } @@ -379,36 +379,36 @@ static int wl12xx_nl_phy_reg_read(struct sk_buff *skb, struct genl_info *info) goto nla_put_failure; } - reg_addr = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_ADDR]); + reg_addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]); - wl12xx_debug(DEBUG_NETLINK, "Reading PHY reg 0x%x", reg_addr); + wl1251_debug(DEBUG_NETLINK, "Reading PHY reg 0x%x", reg_addr); mutex_lock(&wl->mutex); - ret = wl12xx_cmd_read_memory(wl, reg_addr, reg_value, + ret = wl1251_cmd_read_memory(wl, reg_addr, reg_value, sizeof(*reg_value)); mutex_unlock(&wl->mutex); if (ret < 0) { - wl12xx_error("%s() failed", __func__); + wl1251_error("%s() failed", __func__); goto nla_put_failure; } hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, - &wl12xx_nl_family, 0, WL12XX_NL_CMD_PHY_REG_READ); + &wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ); if (IS_ERR(hdr)) { ret = PTR_ERR(hdr); goto nla_put_failure; } - NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME, - nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME])); + NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME, + nla_data(info->attrs[WL1251_NL_ATTR_IFNAME])); - NLA_PUT_U32(msg, WL12XX_NL_ATTR_REG_VAL, *reg_value); + NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, *reg_value); ret = genlmsg_end(msg, hdr); if (ret < 0) { - wl12xx_error("%s() failed", __func__); + wl1251_error("%s() failed", __func__); goto nla_put_failure; } @@ -423,27 +423,27 @@ static int wl12xx_nl_phy_reg_read(struct sk_buff *skb, struct genl_info *info) return ret; } -static int wl12xx_nl_nvs_push(struct sk_buff *skb, struct genl_info *info) +static int wl1251_nl_nvs_push(struct sk_buff *skb, struct genl_info *info) { - struct wl12xx *wl; + struct wl1251 *wl; int ret = 0; - if (!info->attrs[WL12XX_NL_ATTR_NVS_BUFFER]) + if (!info->attrs[WL1251_NL_ATTR_NVS_BUFFER]) return -EINVAL; - if (!info->attrs[WL12XX_NL_ATTR_NVS_LEN]) + if (!info->attrs[WL1251_NL_ATTR_NVS_LEN]) return -EINVAL; - wl = ifname_to_wl12xx(&init_net, info); + wl = ifname_to_wl1251(&init_net, info); if (wl == NULL) { - wl12xx_error("wl12xx not found"); + wl1251_error("wl1251 not found"); return -EINVAL; } mutex_lock(&wl->mutex); - wl->nvs_len = nla_get_u32(info->attrs[WL12XX_NL_ATTR_NVS_LEN]); + wl->nvs_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_NVS_LEN]); if (wl->nvs_len % 4) { - wl12xx_error("NVS size is not multiple of 32: %d", wl->nvs_len); + wl1251_error("NVS size is not multiple of 32: %d", wl->nvs_len); ret = -EILSEQ; goto out; } @@ -453,16 +453,16 @@ static int wl12xx_nl_nvs_push(struct sk_buff *skb, struct genl_info *info) wl->nvs = kzalloc(wl->nvs_len, GFP_KERNEL); if (wl->nvs == NULL) { - wl12xx_error("Can't allocate NVS"); + wl1251_error("Can't allocate NVS"); ret = -ENOMEM; goto out; } memcpy(wl->nvs, - nla_data(info->attrs[WL12XX_NL_ATTR_NVS_BUFFER]), + nla_data(info->attrs[WL1251_NL_ATTR_NVS_BUFFER]), wl->nvs_len); - wl12xx_debug(DEBUG_NETLINK, "got NVS from userspace, %d bytes", + wl1251_debug(DEBUG_NETLINK, "got NVS from userspace, %d bytes", wl->nvs_len); out: @@ -471,48 +471,48 @@ out: return ret; } -static int wl12xx_nl_reg_read(struct sk_buff *skb, struct genl_info *info) +static int wl1251_nl_reg_read(struct sk_buff *skb, struct genl_info *info) { - struct wl12xx *wl; + struct wl1251 *wl; u32 addr, val; int ret = 0; struct sk_buff *msg; void *hdr; - if (!info->attrs[WL12XX_NL_ATTR_REG_ADDR]) + if (!info->attrs[WL1251_NL_ATTR_REG_ADDR]) return -EINVAL; msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); if (!msg) return -ENOMEM; - wl = ifname_to_wl12xx(&init_net, info); + wl = ifname_to_wl1251(&init_net, info); if (wl == NULL) { - wl12xx_error("wl12xx not found"); + wl1251_error("wl1251 not found"); return -EINVAL; } - addr = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_ADDR]); + addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]); mutex_lock(&wl->mutex); - val = wl12xx_reg_read32(wl, addr); + val = wl1251_reg_read32(wl, addr); mutex_unlock(&wl->mutex); hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, - &wl12xx_nl_family, 0, WL12XX_NL_CMD_PHY_REG_READ); + &wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ); if (IS_ERR(hdr)) { ret = PTR_ERR(hdr); goto nla_put_failure; } - NLA_PUT_STRING(msg, WL12XX_NL_ATTR_IFNAME, - nla_data(info->attrs[WL12XX_NL_ATTR_IFNAME])); + NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME, + nla_data(info->attrs[WL1251_NL_ATTR_IFNAME])); - NLA_PUT_U32(msg, WL12XX_NL_ATTR_REG_VAL, val); + NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, val); ret = genlmsg_end(msg, hdr); if (ret < 0) { - wl12xx_error("%s() failed", __func__); + wl1251_error("%s() failed", __func__); goto nla_put_failure; } @@ -524,56 +524,56 @@ static int wl12xx_nl_reg_read(struct sk_buff *skb, struct genl_info *info) return ret; } -static int wl12xx_nl_reg_write(struct sk_buff *skb, struct genl_info *info) +static int wl1251_nl_reg_write(struct sk_buff *skb, struct genl_info *info) { - struct wl12xx *wl; + struct wl1251 *wl; u32 addr, val; - if (!info->attrs[WL12XX_NL_ATTR_REG_ADDR]) + if (!info->attrs[WL1251_NL_ATTR_REG_ADDR]) return -EINVAL; - if (!info->attrs[WL12XX_NL_ATTR_REG_VAL]) + if (!info->attrs[WL1251_NL_ATTR_REG_VAL]) return -EINVAL; - wl = ifname_to_wl12xx(&init_net, info); + wl = ifname_to_wl1251(&init_net, info); if (wl == NULL) { - wl12xx_error("wl12xx not found"); + wl1251_error("wl1251 not found"); return -EINVAL; } - addr = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_ADDR]); - val = nla_get_u32(info->attrs[WL12XX_NL_ATTR_REG_VAL]); + addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]); + val = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_VAL]); mutex_lock(&wl->mutex); - wl12xx_reg_write32(wl, addr, val); + wl1251_reg_write32(wl, addr, val); mutex_unlock(&wl->mutex); return 0; } -static int wl12xx_nl_set_plt_mode(struct sk_buff *skb, struct genl_info *info) +static int wl1251_nl_set_plt_mode(struct sk_buff *skb, struct genl_info *info) { - struct wl12xx *wl; + struct wl1251 *wl; u32 val; int ret; - if (!info->attrs[WL12XX_NL_ATTR_PLT_MODE]) + if (!info->attrs[WL1251_NL_ATTR_PLT_MODE]) return -EINVAL; - wl = ifname_to_wl12xx(&init_net, info); + wl = ifname_to_wl1251(&init_net, info); if (wl == NULL) { - wl12xx_error("wl12xx not found"); + wl1251_error("wl1251 not found"); return -EINVAL; } - val = nla_get_u32(info->attrs[WL12XX_NL_ATTR_PLT_MODE]); + val = nla_get_u32(info->attrs[WL1251_NL_ATTR_PLT_MODE]); switch (val) { case 0: - ret = wl12xx_plt_stop(wl); + ret = wl1251_plt_stop(wl); break; case 1: - ret = wl12xx_plt_start(wl); + ret = wl1251_plt_start(wl); break; default: ret = -EINVAL; @@ -583,97 +583,97 @@ static int wl12xx_nl_set_plt_mode(struct sk_buff *skb, struct genl_info *info) return ret; } -static struct nla_policy wl12xx_nl_policy[WL12XX_NL_ATTR_MAX + 1] = { - [WL12XX_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING, +static struct nla_policy wl1251_nl_policy[WL1251_NL_ATTR_MAX + 1] = { + [WL1251_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, - [WL12XX_NL_ATTR_CMD_TEST_PARAM] = { .type = NLA_BINARY, - .len = WL12XX_MAX_TEST_LENGTH }, - [WL12XX_NL_ATTR_CMD_TEST_ANSWER] = { .type = NLA_U8 }, - [WL12XX_NL_ATTR_CMD_IE] = { .type = NLA_U32 }, - [WL12XX_NL_ATTR_CMD_IE_LEN] = { .type = NLA_U32 }, - [WL12XX_NL_ATTR_CMD_IE_BUFFER] = { .type = NLA_BINARY, - .len = WL12XX_MAX_TEST_LENGTH }, - [WL12XX_NL_ATTR_CMD_IE_ANSWER] = { .type = NLA_BINARY, - .len = WL12XX_MAX_TEST_LENGTH }, - [WL12XX_NL_ATTR_REG_ADDR] = { .type = NLA_U32 }, - [WL12XX_NL_ATTR_REG_VAL] = { .type = NLA_U32 }, - [WL12XX_NL_ATTR_NVS_BUFFER] = { .type = NLA_BINARY, - .len = WL12XX_MAX_NVS_LENGTH }, - [WL12XX_NL_ATTR_NVS_LEN] = { .type = NLA_U32 }, - [WL12XX_NL_ATTR_PLT_MODE] = { .type = NLA_U32 }, + [WL1251_NL_ATTR_CMD_TEST_PARAM] = { .type = NLA_BINARY, + .len = WL1251_MAX_TEST_LENGTH }, + [WL1251_NL_ATTR_CMD_TEST_ANSWER] = { .type = NLA_U8 }, + [WL1251_NL_ATTR_CMD_IE] = { .type = NLA_U32 }, + [WL1251_NL_ATTR_CMD_IE_LEN] = { .type = NLA_U32 }, + [WL1251_NL_ATTR_CMD_IE_BUFFER] = { .type = NLA_BINARY, + .len = WL1251_MAX_TEST_LENGTH }, + [WL1251_NL_ATTR_CMD_IE_ANSWER] = { .type = NLA_BINARY, + .len = WL1251_MAX_TEST_LENGTH }, + [WL1251_NL_ATTR_REG_ADDR] = { .type = NLA_U32 }, + [WL1251_NL_ATTR_REG_VAL] = { .type = NLA_U32 }, + [WL1251_NL_ATTR_NVS_BUFFER] = { .type = NLA_BINARY, + .len = WL1251_MAX_NVS_LENGTH }, + [WL1251_NL_ATTR_NVS_LEN] = { .type = NLA_U32 }, + [WL1251_NL_ATTR_PLT_MODE] = { .type = NLA_U32 }, }; -static struct genl_ops wl12xx_nl_ops[] = { +static struct genl_ops wl1251_nl_ops[] = { { - .cmd = WL12XX_NL_CMD_TEST, - .doit = wl12xx_nl_test_cmd, - .policy = wl12xx_nl_policy, + .cmd = WL1251_NL_CMD_TEST, + .doit = wl1251_nl_test_cmd, + .policy = wl1251_nl_policy, .flags = GENL_ADMIN_PERM, }, { - .cmd = WL12XX_NL_CMD_INTERROGATE, - .doit = wl12xx_nl_interrogate, - .policy = wl12xx_nl_policy, + .cmd = WL1251_NL_CMD_INTERROGATE, + .doit = wl1251_nl_interrogate, + .policy = wl1251_nl_policy, .flags = GENL_ADMIN_PERM, }, { - .cmd = WL12XX_NL_CMD_CONFIGURE, - .doit = wl12xx_nl_configure, - .policy = wl12xx_nl_policy, + .cmd = WL1251_NL_CMD_CONFIGURE, + .doit = wl1251_nl_configure, + .policy = wl1251_nl_policy, .flags = GENL_ADMIN_PERM, }, { - .cmd = WL12XX_NL_CMD_PHY_REG_READ, - .doit = wl12xx_nl_phy_reg_read, - .policy = wl12xx_nl_policy, + .cmd = WL1251_NL_CMD_PHY_REG_READ, + .doit = wl1251_nl_phy_reg_read, + .policy = wl1251_nl_policy, .flags = GENL_ADMIN_PERM, }, { - .cmd = WL12XX_NL_CMD_NVS_PUSH, - .doit = wl12xx_nl_nvs_push, - .policy = wl12xx_nl_policy, + .cmd = WL1251_NL_CMD_NVS_PUSH, + .doit = wl1251_nl_nvs_push, + .policy = wl1251_nl_policy, .flags = GENL_ADMIN_PERM, }, { - .cmd = WL12XX_NL_CMD_REG_WRITE, - .doit = wl12xx_nl_reg_write, - .policy = wl12xx_nl_policy, + .cmd = WL1251_NL_CMD_REG_WRITE, + .doit = wl1251_nl_reg_write, + .policy = wl1251_nl_policy, .flags = GENL_ADMIN_PERM, }, { - .cmd = WL12XX_NL_CMD_REG_READ, - .doit = wl12xx_nl_reg_read, - .policy = wl12xx_nl_policy, + .cmd = WL1251_NL_CMD_REG_READ, + .doit = wl1251_nl_reg_read, + .policy = wl1251_nl_policy, .flags = GENL_ADMIN_PERM, }, { - .cmd = WL12XX_NL_CMD_SET_PLT_MODE, - .doit = wl12xx_nl_set_plt_mode, - .policy = wl12xx_nl_policy, + .cmd = WL1251_NL_CMD_SET_PLT_MODE, + .doit = wl1251_nl_set_plt_mode, + .policy = wl1251_nl_policy, .flags = GENL_ADMIN_PERM, }, }; -int wl12xx_nl_register(void) +int wl1251_nl_register(void) { int err, i; - err = genl_register_family(&wl12xx_nl_family); + err = genl_register_family(&wl1251_nl_family); if (err) return err; - for (i = 0; i < ARRAY_SIZE(wl12xx_nl_ops); i++) { - err = genl_register_ops(&wl12xx_nl_family, &wl12xx_nl_ops[i]); + for (i = 0; i < ARRAY_SIZE(wl1251_nl_ops); i++) { + err = genl_register_ops(&wl1251_nl_family, &wl1251_nl_ops[i]); if (err) goto err_out; } return 0; err_out: - genl_unregister_family(&wl12xx_nl_family); + genl_unregister_family(&wl1251_nl_family); return err; } -void wl12xx_nl_unregister(void) +void wl1251_nl_unregister(void) { - genl_unregister_family(&wl12xx_nl_family); + genl_unregister_family(&wl1251_nl_family); } diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.h b/drivers/net/wireless/wl12xx/wl1251_netlink.h index acfbd0241b8..ee36695e134 100644 --- a/drivers/net/wireless/wl12xx/wl1251_netlink.h +++ b/drivers/net/wireless/wl12xx/wl1251_netlink.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2009 Nokia Corporation * @@ -21,10 +21,10 @@ * */ -#ifndef __WL12XX_NETLINK_H__ -#define __WL12XX_NETLINK_H__ +#ifndef __WL1251_NETLINK_H__ +#define __WL1251_NETLINK_H__ -int wl12xx_nl_register(void); -void wl12xx_nl_unregister(void); +int wl1251_nl_register(void); +void wl1251_nl_unregister(void); -#endif /* __WL12XX_NETLINK_H__ */ +#endif /* __WL1251_NETLINK_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.c b/drivers/net/wireless/wl12xx/wl1251_ops.c index cdfd2c21899..96a45f59529 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ops.c +++ b/drivers/net/wireless/wl12xx/wl1251_ops.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2008-2009 Nokia Corporation * @@ -35,7 +35,7 @@ #include "wl1251_ps.h" #include "wl1251_init.h" -static struct wl12xx_partition_set wl1251_part_table[PART_TABLE_LEN] = { +static struct wl1251_partition_set wl1251_part_table[PART_TABLE_LEN] = { [PART_DOWN] = { .mem = { .start = 0x00000000, @@ -75,31 +75,31 @@ static enum wl12xx_acx_int_reg wl1251_acx_reg_table[ACX_REG_TABLE_LEN] = { [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) }; -static int wl1251_upload_firmware(struct wl12xx *wl) +static int wl1251_upload_firmware(struct wl1251 *wl) { - struct wl12xx_partition_set *p_table = wl->chip.p_table; + struct wl1251_partition_set *p_table = wl->chip.p_table; int addr, chunk_num, partition_limit; size_t fw_data_len; u8 *p; /* whal_FwCtrl_LoadFwImageSm() */ - wl12xx_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", - wl12xx_reg_read32(wl, CHIP_ID_B)); + wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", + wl1251_reg_read32(wl, CHIP_ID_B)); /* 10.0 check firmware length and set partition */ fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | (wl->fw[6] << 8) | (wl->fw[7]); - wl12xx_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, + wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, CHUNK_SIZE); if ((fw_data_len % 4) != 0) { - wl12xx_error("firmware length not multiple of four"); + wl1251_error("firmware length not multiple of four"); return -EIO; } - wl12xx_set_partition(wl, + wl1251_set_partition(wl, p_table[PART_DOWN].mem.start, p_table[PART_DOWN].mem.size, p_table[PART_DOWN].reg.start, @@ -118,7 +118,7 @@ static int wl1251_upload_firmware(struct wl12xx *wl) chunk_num * CHUNK_SIZE; partition_limit = chunk_num * CHUNK_SIZE + p_table[PART_DOWN].mem.size; - wl12xx_set_partition(wl, + wl1251_set_partition(wl, addr, p_table[PART_DOWN].mem.size, p_table[PART_DOWN].reg.start, @@ -128,9 +128,9 @@ static int wl1251_upload_firmware(struct wl12xx *wl) /* 10.3 upload the chunk */ addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; - wl12xx_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", + wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", p, addr); - wl12xx_spi_mem_write(wl, addr, p, CHUNK_SIZE); + wl1251_spi_mem_write(wl, addr, p, CHUNK_SIZE); chunk_num++; } @@ -138,14 +138,14 @@ static int wl1251_upload_firmware(struct wl12xx *wl) /* 10.4 upload the last chunk */ addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; - wl12xx_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", + wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", fw_data_len % CHUNK_SIZE, p, addr); - wl12xx_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); + wl1251_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); return 0; } -static int wl1251_upload_nvs(struct wl12xx *wl) +static int wl1251_upload_nvs(struct wl1251 *wl) { size_t nvs_len, nvs_bytes_written, burst_len; int nvs_start, i; @@ -181,10 +181,10 @@ static int wl1251_upload_nvs(struct wl12xx *wl) val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); - wl12xx_debug(DEBUG_BOOT, + wl1251_debug(DEBUG_BOOT, "nvs burst write 0x%x: 0x%x", dest_addr, val); - wl12xx_mem_write32(wl, dest_addr, val); + wl1251_mem_write32(wl, dest_addr, val); nvs_ptr += 4; dest_addr += 4; @@ -200,7 +200,7 @@ static int wl1251_upload_nvs(struct wl12xx *wl) nvs_len = ALIGN(nvs_len, 4); /* Now we must set the partition correctly */ - wl12xx_set_partition(wl, nvs_start, + wl1251_set_partition(wl, nvs_start, wl->chip.p_table[PART_DOWN].mem.size, wl->chip.p_table[PART_DOWN].reg.start, wl->chip.p_table[PART_DOWN].reg.size); @@ -213,10 +213,10 @@ static int wl1251_upload_nvs(struct wl12xx *wl) val = cpu_to_le32(val); - wl12xx_debug(DEBUG_BOOT, + wl1251_debug(DEBUG_BOOT, "nvs write table 0x%x: 0x%x", nvs_start, val); - wl12xx_mem_write32(wl, nvs_start, val); + wl1251_mem_write32(wl, nvs_start, val); nvs_ptr += 4; nvs_bytes_written += 4; @@ -226,12 +226,12 @@ static int wl1251_upload_nvs(struct wl12xx *wl) return 0; } -static int wl1251_boot(struct wl12xx *wl) +static int wl1251_boot(struct wl1251 *wl) { int ret = 0, minor_minor_e2_ver; u32 tmp, boot_data; - ret = wl12xx_boot_soft_reset(wl); + ret = wl1251_boot_soft_reset(wl); if (ret < 0) goto out; @@ -242,39 +242,39 @@ static int wl1251_boot(struct wl12xx *wl) /* write firmware's last address (ie. it's length) to * ACX_EEPROMLESS_IND_REG */ - wl12xx_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); + wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); /* 6. read the EEPROM parameters */ - tmp = wl12xx_reg_read32(wl, SCR_PAD2); + tmp = wl1251_reg_read32(wl, SCR_PAD2); /* 7. read bootdata */ wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; - tmp = wl12xx_reg_read32(wl, SCR_PAD3); + tmp = wl1251_reg_read32(wl, SCR_PAD3); /* 8. check bootdata and call restart sequence */ wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; - wl12xx_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " + wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", wl->boot_attr.radio_type, wl->boot_attr.major, wl->boot_attr.minor, minor_minor_e2_ver); - ret = wl12xx_boot_init_seq(wl); + ret = wl1251_boot_init_seq(wl); if (ret < 0) goto out; /* 9. NVS processing done */ - boot_data = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL); + boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); - wl12xx_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); + wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); /* 10. check that ECPU_CONTROL_HALT bits are set in * pWhalBus->uBootData and start uploading firmware */ if ((boot_data & ECPU_CONTROL_HALT) == 0) { - wl12xx_error("boot failed, ECPU_CONTROL_HALT not set"); + wl1251_error("boot failed, ECPU_CONTROL_HALT not set"); ret = -EIO; goto out; } @@ -284,7 +284,7 @@ static int wl1251_boot(struct wl12xx *wl) goto out; /* 10.5 start firmware */ - ret = wl12xx_boot_run_firmware(wl); + ret = wl1251_boot_run_firmware(wl); if (ret < 0) goto out; @@ -292,12 +292,12 @@ out: return ret; } -static int wl1251_mem_cfg(struct wl12xx *wl) +static int wl1251_mem_cfg(struct wl1251 *wl) { struct wl1251_acx_config_memory *mem_conf; int ret, i; - wl12xx_debug(DEBUG_ACX, "wl1251 mem cfg"); + wl1251_debug(DEBUG_ACX, "wl1251 mem cfg"); mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); if (!mem_conf) { @@ -327,10 +327,10 @@ static int wl1251_mem_cfg(struct wl12xx *wl) mem_conf->tx_queue_config[i].attributes = i; } - ret = wl12xx_cmd_configure(wl, ACX_MEM_CFG, mem_conf, + ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf, sizeof(*mem_conf)); if (ret < 0) { - wl12xx_warning("wl1251 mem config failed: %d", ret); + wl1251_warning("wl1251 mem config failed: %d", ret); goto out; } @@ -339,7 +339,7 @@ out: return ret; } -static int wl1251_hw_init_mem_config(struct wl12xx *wl) +static int wl1251_hw_init_mem_config(struct wl1251 *wl) { int ret; @@ -350,15 +350,15 @@ static int wl1251_hw_init_mem_config(struct wl12xx *wl) wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), GFP_KERNEL); if (!wl->target_mem_map) { - wl12xx_error("couldn't allocate target memory map"); + wl1251_error("couldn't allocate target memory map"); return -ENOMEM; } /* we now ask for the firmware built memory map */ - ret = wl12xx_acx_mem_map(wl, wl->target_mem_map, + ret = wl1251_acx_mem_map(wl, wl->target_mem_map, sizeof(struct wl1251_acx_mem_map)); if (ret < 0) { - wl12xx_error("couldn't retrieve firmware memory map"); + wl1251_error("couldn't retrieve firmware memory map"); kfree(wl->target_mem_map); wl->target_mem_map = NULL; return ret; @@ -367,19 +367,19 @@ static int wl1251_hw_init_mem_config(struct wl12xx *wl) return 0; } -static void wl1251_set_ecpu_ctrl(struct wl12xx *wl, u32 flag) +static void wl1251_set_ecpu_ctrl(struct wl1251 *wl, u32 flag) { u32 cpu_ctrl; /* 10.5.0 run the firmware (I) */ - cpu_ctrl = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL); + cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); /* 10.5.1 run the firmware (II) */ cpu_ctrl &= ~flag; - wl12xx_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); + wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); } -static void wl1251_target_enable_interrupts(struct wl12xx *wl) +static void wl1251_target_enable_interrupts(struct wl1251 *wl) { /* Enable target's interrupts */ wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | @@ -388,60 +388,60 @@ static void wl1251_target_enable_interrupts(struct wl12xx *wl) WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B | WL1251_ACX_INTR_INIT_COMPLETE; - wl12xx_boot_target_enable_interrupts(wl); + wl1251_boot_target_enable_interrupts(wl); } -static void wl1251_fw_version(struct wl12xx *wl) +static void wl1251_fw_version(struct wl1251 *wl) { - wl12xx_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver)); + wl1251_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver)); } static void wl1251_irq_work(struct work_struct *work) { u32 intr; - struct wl12xx *wl = - container_of(work, struct wl12xx, irq_work); + struct wl1251 *wl = + container_of(work, struct wl1251, irq_work); int ret; mutex_lock(&wl->mutex); - wl12xx_debug(DEBUG_IRQ, "IRQ work"); + wl1251_debug(DEBUG_IRQ, "IRQ work"); - if (wl->state == WL12XX_STATE_OFF) + if (wl->state == WL1251_STATE_OFF) goto out; - ret = wl12xx_ps_elp_wakeup(wl); + ret = wl1251_ps_elp_wakeup(wl); if (ret < 0) goto out; - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); - intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); - wl12xx_debug(DEBUG_IRQ, "intr: 0x%x", intr); + intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); + wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); if (wl->data_path) { wl->rx_counter = - wl12xx_mem_read32(wl, wl->data_path->rx_control_addr); + wl1251_mem_read32(wl, wl->data_path->rx_control_addr); /* We handle a frmware bug here */ switch ((wl->rx_counter - wl->rx_handled) & 0xf) { case 0: - wl12xx_debug(DEBUG_IRQ, "RX: FW and host in sync"); + wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync"); intr &= ~WL1251_ACX_INTR_RX0_DATA; intr &= ~WL1251_ACX_INTR_RX1_DATA; break; case 1: - wl12xx_debug(DEBUG_IRQ, "RX: FW +1"); + wl1251_debug(DEBUG_IRQ, "RX: FW +1"); intr |= WL1251_ACX_INTR_RX0_DATA; intr &= ~WL1251_ACX_INTR_RX1_DATA; break; case 2: - wl12xx_debug(DEBUG_IRQ, "RX: FW +2"); + wl1251_debug(DEBUG_IRQ, "RX: FW +2"); intr |= WL1251_ACX_INTR_RX0_DATA; intr |= WL1251_ACX_INTR_RX1_DATA; break; default: - wl12xx_warning("RX: FW and host out of sync: %d", + wl1251_warning("RX: FW and host out of sync: %d", wl->rx_counter - wl->rx_handled); break; } @@ -449,49 +449,49 @@ static void wl1251_irq_work(struct work_struct *work) wl->rx_handled = wl->rx_counter; - wl12xx_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); + wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); } intr &= wl->intr_mask; if (intr == 0) { - wl12xx_debug(DEBUG_IRQ, "INTR is 0"); - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, + wl1251_debug(DEBUG_IRQ, "INTR is 0"); + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); goto out_sleep; } if (intr & WL1251_ACX_INTR_RX0_DATA) { - wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); - wl12xx_rx(wl); + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); + wl1251_rx(wl); } if (intr & WL1251_ACX_INTR_RX1_DATA) { - wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); - wl12xx_rx(wl); + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); + wl1251_rx(wl); } if (intr & WL1251_ACX_INTR_TX_RESULT) { - wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); wl1251_tx_complete(wl); } if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { - wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); if (intr & WL1251_ACX_INTR_EVENT_A) - wl12xx_event_handle(wl, 0); + wl1251_event_handle(wl, 0); else - wl12xx_event_handle(wl, 1); + wl1251_event_handle(wl, 1); } if (intr & WL1251_ACX_INTR_INIT_COMPLETE) - wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); - wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); out_sleep: - wl12xx_ps_elp_sleep(wl); + wl1251_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); @@ -529,20 +529,20 @@ static int wl1251_hw_init_txq_fill(u8 qid, (QOS_TX_LOW_VO_DEF * num_blocks) / 100; break; default: - wl12xx_error("Invalid TX queue id: %d", qid); + wl1251_error("Invalid TX queue id: %d", qid); return -EINVAL; } return 0; } -static int wl1251_hw_init_tx_queue_config(struct wl12xx *wl) +static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl) { struct acx_tx_queue_qos_config *config; struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; int ret, i; - wl12xx_debug(DEBUG_ACX, "acx tx queue config"); + wl1251_debug(DEBUG_ACX, "acx tx queue config"); config = kzalloc(sizeof(*config), GFP_KERNEL); if (!config) { @@ -556,7 +556,7 @@ static int wl1251_hw_init_tx_queue_config(struct wl12xx *wl) if (ret < 0) goto out; - ret = wl12xx_cmd_configure(wl, ACX_TX_QUEUE_CFG, + ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG, config, sizeof(*config)); if (ret < 0) goto out; @@ -567,7 +567,7 @@ out: return ret; } -static int wl1251_hw_init_data_path_config(struct wl12xx *wl) +static int wl1251_hw_init_data_path_config(struct wl1251 *wl) { int ret; @@ -575,11 +575,11 @@ static int wl1251_hw_init_data_path_config(struct wl12xx *wl) wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), GFP_KERNEL); if (!wl->data_path) { - wl12xx_error("Couldnt allocate data path parameters"); + wl1251_error("Couldnt allocate data path parameters"); return -ENOMEM; } - ret = wl12xx_acx_data_path_params(wl, wl->data_path); + ret = wl1251_acx_data_path_params(wl, wl->data_path); if (ret < 0) { kfree(wl->data_path); wl->data_path = NULL; @@ -589,17 +589,17 @@ static int wl1251_hw_init_data_path_config(struct wl12xx *wl) return 0; } -static int wl1251_hw_init(struct wl12xx *wl) +static int wl1251_hw_init(struct wl1251 *wl) { struct wl1251_acx_mem_map *wl_mem_map; int ret; - ret = wl12xx_hw_init_hwenc_config(wl); + ret = wl1251_hw_init_hwenc_config(wl); if (ret < 0) return ret; /* Template settings */ - ret = wl12xx_hw_init_templates_config(wl); + ret = wl1251_hw_init_templates_config(wl); if (ret < 0) return ret; @@ -614,7 +614,7 @@ static int wl1251_hw_init(struct wl12xx *wl) goto out_free_memmap; /* RX config */ - ret = wl12xx_hw_init_rx_config(wl, + ret = wl1251_hw_init_rx_config(wl, RX_CFG_PROMISCUOUS | RX_CFG_TSF, RX_FILTER_OPTION_DEF); /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, @@ -628,42 +628,42 @@ static int wl1251_hw_init(struct wl12xx *wl) goto out_free_data_path; /* PHY layer config */ - ret = wl12xx_hw_init_phy_config(wl); + ret = wl1251_hw_init_phy_config(wl); if (ret < 0) goto out_free_data_path; /* Beacon filtering */ - ret = wl12xx_hw_init_beacon_filter(wl); + ret = wl1251_hw_init_beacon_filter(wl); if (ret < 0) goto out_free_data_path; /* Bluetooth WLAN coexistence */ - ret = wl12xx_hw_init_pta(wl); + ret = wl1251_hw_init_pta(wl); if (ret < 0) goto out_free_data_path; /* Energy detection */ - ret = wl12xx_hw_init_energy_detection(wl); + ret = wl1251_hw_init_energy_detection(wl); if (ret < 0) goto out_free_data_path; /* Beacons and boradcast settings */ - ret = wl12xx_hw_init_beacon_broadcast(wl); + ret = wl1251_hw_init_beacon_broadcast(wl); if (ret < 0) goto out_free_data_path; /* Enable data path */ - ret = wl12xx_cmd_data_path(wl, wl->channel, 1); + ret = wl1251_cmd_data_path(wl, wl->channel, 1); if (ret < 0) goto out_free_data_path; /* Default power state */ - ret = wl12xx_hw_init_power_auth(wl); + ret = wl1251_hw_init_power_auth(wl); if (ret < 0) goto out_free_data_path; wl_mem_map = wl->target_mem_map; - wl12xx_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", + wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", wl_mem_map->num_tx_mem_blocks, wl->data_path->tx_control_addr, wl_mem_map->num_rx_mem_blocks, @@ -680,7 +680,7 @@ static int wl1251_hw_init(struct wl12xx *wl) return ret; } -static int wl1251_plt_init(struct wl12xx *wl) +static int wl1251_plt_init(struct wl1251 *wl) { int ret; @@ -688,14 +688,14 @@ static int wl1251_plt_init(struct wl12xx *wl) if (ret < 0) return ret; - ret = wl12xx_cmd_data_path(wl, wl->channel, 1); + ret = wl1251_cmd_data_path(wl, wl->channel, 1); if (ret < 0) return ret; return 0; } -void wl1251_setup(struct wl12xx *wl) +void wl1251_setup(struct wl1251 *wl) { /* FIXME: Is it better to use strncpy here or is this ok? */ wl->chip.fw_filename = WL1251_FW_NAME; diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.h b/drivers/net/wireless/wl12xx/wl1251_ops.h index c5c997bb64d..68183c472e4 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ops.h +++ b/drivers/net/wireless/wl12xx/wl1251_ops.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2008 Nokia Corporation * @@ -34,7 +34,7 @@ #define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ -void wl1251_setup(struct wl12xx *wl); +void wl1251_setup(struct wl1251 *wl); struct wl1251_acx_memory { diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c index 83baaa2eb19..68ff7f1900e 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.c +++ b/drivers/net/wireless/wl12xx/wl1251_ps.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2008 Nokia Corporation * @@ -25,22 +25,22 @@ #include "wl1251_ps.h" #include "wl1251_spi.h" -#define WL12XX_WAKEUP_TIMEOUT 2000 +#define WL1251_WAKEUP_TIMEOUT 2000 /* Routines to toggle sleep mode while in ELP */ -void wl12xx_ps_elp_sleep(struct wl12xx *wl) +void wl1251_ps_elp_sleep(struct wl1251 *wl) { if (wl->elp || !wl->psm) return; - wl12xx_debug(DEBUG_PSM, "chip to elp"); + wl1251_debug(DEBUG_PSM, "chip to elp"); - wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); + wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); wl->elp = true; } -int wl12xx_ps_elp_wakeup(struct wl12xx *wl) +int wl1251_ps_elp_wakeup(struct wl1251 *wl) { unsigned long timeout; u32 elp_reg; @@ -48,13 +48,13 @@ int wl12xx_ps_elp_wakeup(struct wl12xx *wl) if (!wl->elp) return 0; - wl12xx_debug(DEBUG_PSM, "waking up chip from elp"); + wl1251_debug(DEBUG_PSM, "waking up chip from elp"); - timeout = jiffies + msecs_to_jiffies(WL12XX_WAKEUP_TIMEOUT); + timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT); - wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); + wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); - elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); /* * FIXME: we should wait for irq from chip but, as a temporary @@ -62,36 +62,36 @@ int wl12xx_ps_elp_wakeup(struct wl12xx *wl) */ while (!(elp_reg & ELPCTRL_WLAN_READY)) { if (time_after(jiffies, timeout)) { - wl12xx_error("elp wakeup timeout"); + wl1251_error("elp wakeup timeout"); return -ETIMEDOUT; } msleep(1); - elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); } - wl12xx_debug(DEBUG_PSM, "wakeup time: %u ms", + wl1251_debug(DEBUG_PSM, "wakeup time: %u ms", jiffies_to_msecs(jiffies) - - (jiffies_to_msecs(timeout) - WL12XX_WAKEUP_TIMEOUT)); + (jiffies_to_msecs(timeout) - WL1251_WAKEUP_TIMEOUT)); wl->elp = false; return 0; } -static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable) +static int wl1251_ps_set_elp(struct wl1251 *wl, bool enable) { int ret; if (enable) { - wl12xx_debug(DEBUG_PSM, "sleep auth psm/elp"); + wl1251_debug(DEBUG_PSM, "sleep auth psm/elp"); - ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_ELP); + ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); if (ret < 0) return ret; - wl12xx_ps_elp_sleep(wl); + wl1251_ps_elp_sleep(wl); } else { - wl12xx_debug(DEBUG_PSM, "sleep auth cam"); + wl1251_debug(DEBUG_PSM, "sleep auth cam"); /* * When the target is in ELP, we can only @@ -100,9 +100,9 @@ static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable) * changing the power authorization. */ - wl12xx_ps_elp_wakeup(wl); + wl1251_ps_elp_wakeup(wl); - ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM); + ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); if (ret < 0) return ret; } @@ -110,18 +110,18 @@ static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable) return 0; } -int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode) +int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) { int ret; switch (mode) { case STATION_POWER_SAVE_MODE: - wl12xx_debug(DEBUG_PSM, "entering psm"); - ret = wl12xx_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); + wl1251_debug(DEBUG_PSM, "entering psm"); + ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); if (ret < 0) return ret; - ret = wl12xx_ps_set_elp(wl, true); + ret = wl1251_ps_set_elp(wl, true); if (ret < 0) return ret; @@ -129,12 +129,12 @@ int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode) break; case STATION_ACTIVE_MODE: default: - wl12xx_debug(DEBUG_PSM, "leaving psm"); - ret = wl12xx_ps_set_elp(wl, false); + wl1251_debug(DEBUG_PSM, "leaving psm"); + ret = wl1251_ps_set_elp(wl, false); if (ret < 0) return ret; - ret = wl12xx_cmd_ps_mode(wl, STATION_ACTIVE_MODE); + ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE); if (ret < 0) return ret; diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.h b/drivers/net/wireless/wl12xx/wl1251_ps.h index 8877842baf1..db036fe12f2 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.h +++ b/drivers/net/wireless/wl12xx/wl1251_ps.h @@ -1,8 +1,8 @@ -#ifndef __WL12XX_PS_H__ -#define __WL12XX_PS_H__ +#ifndef __WL1251_PS_H__ +#define __WL1251_PS_H__ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008 Nokia Corporation @@ -28,9 +28,9 @@ #include "wl1251.h" #include "wl1251_acx.h" -int wl12xx_ps_set_mode(struct wl12xx *wl, enum wl12xx_cmd_ps_mode mode); -void wl12xx_ps_elp_sleep(struct wl12xx *wl); -int wl12xx_ps_elp_wakeup(struct wl12xx *wl); +int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode); +void wl1251_ps_elp_sleep(struct wl1251 *wl); +int wl1251_ps_elp_wakeup(struct wl1251 *wl); -#endif /* __WL12XX_PS_H__ */ +#endif /* __WL1251_PS_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c index 280fc1843f8..48fa39ea17e 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.c +++ b/drivers/net/wireless/wl12xx/wl1251_rx.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008 Nokia Corporation @@ -31,8 +31,8 @@ #include "wl1251_rx.h" #include "wl1251_acx.h" -static void wl12xx_rx_header(struct wl12xx *wl, - struct wl12xx_rx_descriptor *desc) +static void wl1251_rx_header(struct wl1251 *wl, + struct wl1251_rx_descriptor *desc) { u32 rx_packet_ring_addr; @@ -40,11 +40,11 @@ static void wl12xx_rx_header(struct wl12xx *wl, if (wl->rx_current_buffer) rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; - wl12xx_spi_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); + wl1251_spi_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); } -static void wl12xx_rx_status(struct wl12xx *wl, - struct wl12xx_rx_descriptor *desc, +static void wl1251_rx_status(struct wl1251 *wl, + struct wl1251_rx_descriptor *desc, struct ieee80211_rx_status *status, u8 beacon) { @@ -65,14 +65,14 @@ static void wl12xx_rx_status(struct wl12xx *wl, * this one must be atomic, while our SPI routines can sleep. */ if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) { - ret = wl12xx_acx_tsf_info(wl, &mactime); + ret = wl1251_acx_tsf_info(wl, &mactime); if (ret == 0) status->mactime = mactime; } status->signal = desc->rssi; - status->qual = (desc->rssi - WL12XX_RX_MIN_RSSI) * 100 / - (WL12XX_RX_MAX_RSSI - WL12XX_RX_MIN_RSSI); + status->qual = (desc->rssi - WL1251_RX_MIN_RSSI) * 100 / + (WL1251_RX_MAX_RSSI - WL1251_RX_MIN_RSSI); status->qual = min(status->qual, 100); status->qual = max(status->qual, 0); @@ -103,8 +103,8 @@ static void wl12xx_rx_status(struct wl12xx *wl, /* FIXME: set status->rate_idx */ } -static void wl12xx_rx_body(struct wl12xx *wl, - struct wl12xx_rx_descriptor *desc) +static void wl1251_rx_body(struct wl1251 *wl, + struct wl1251_rx_descriptor *desc) { struct sk_buff *skb; struct ieee80211_rx_status status; @@ -112,12 +112,12 @@ static void wl12xx_rx_body(struct wl12xx *wl, u16 length, *fc; u32 curr_id, last_id_inc, rx_packet_ring_addr; - length = WL12XX_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH); + length = WL1251_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH); curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT; last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1); if (last_id_inc != curr_id) { - wl12xx_warning("curr ID:%d, last ID inc:%d", + wl1251_warning("curr ID:%d, last ID inc:%d", curr_id, last_id_inc); wl->rx_last_id = curr_id; } else { @@ -125,18 +125,18 @@ static void wl12xx_rx_body(struct wl12xx *wl, } rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr + - sizeof(struct wl12xx_rx_descriptor) + 20; + sizeof(struct wl1251_rx_descriptor) + 20; if (wl->rx_current_buffer) rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; skb = dev_alloc_skb(length); if (!skb) { - wl12xx_error("Couldn't allocate RX frame"); + wl1251_error("Couldn't allocate RX frame"); return; } rx_buffer = skb_put(skb, length); - wl12xx_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); + wl1251_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); /* The actual lenght doesn't include the target's alignment */ skb->len = desc->length - PLCP_HEADER_LENGTH; @@ -146,15 +146,15 @@ static void wl12xx_rx_body(struct wl12xx *wl, if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) beacon = 1; - wl12xx_rx_status(wl, desc, &status, beacon); + wl1251_rx_status(wl, desc, &status, beacon); - wl12xx_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, + wl1251_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, beacon ? "beacon" : ""); ieee80211_rx(wl->hw, skb, &status); } -static void wl12xx_rx_ack(struct wl12xx *wl) +static void wl1251_rx_ack(struct wl1251 *wl) { u32 data, addr; @@ -166,30 +166,30 @@ static void wl12xx_rx_ack(struct wl12xx *wl) data = INTR_TRIG_RX_PROC0; } - wl12xx_reg_write32(wl, addr, data); + wl1251_reg_write32(wl, addr, data); /* Toggle buffer ring */ wl->rx_current_buffer = !wl->rx_current_buffer; } -void wl12xx_rx(struct wl12xx *wl) +void wl1251_rx(struct wl1251 *wl) { - struct wl12xx_rx_descriptor *rx_desc; + struct wl1251_rx_descriptor *rx_desc; - if (wl->state != WL12XX_STATE_ON) + if (wl->state != WL1251_STATE_ON) return; rx_desc = wl->rx_descriptor; /* We first read the frame's header */ - wl12xx_rx_header(wl, rx_desc); + wl1251_rx_header(wl, rx_desc); /* Now we can read the body */ - wl12xx_rx_body(wl, rx_desc); + wl1251_rx_body(wl, rx_desc); /* Finally, we need to ACK the RX */ - wl12xx_rx_ack(wl); + wl1251_rx_ack(wl); return; } diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.h b/drivers/net/wireless/wl12xx/wl1251_rx.h index 4379c539538..81156b9c475 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.h +++ b/drivers/net/wireless/wl12xx/wl1251_rx.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008 Nokia Corporation @@ -22,8 +22,8 @@ * */ -#ifndef __WL12XX_RX_H__ -#define __WL12XX_RX_H__ +#ifndef __WL1251_RX_H__ +#define __WL1251_RX_H__ #include @@ -45,12 +45,12 @@ * 4) The target prepares the next RX packet. */ -#define WL12XX_RX_MAX_RSSI -30 -#define WL12XX_RX_MIN_RSSI -95 +#define WL1251_RX_MAX_RSSI -30 +#define WL1251_RX_MIN_RSSI -95 -#define WL12XX_RX_ALIGN_TO 4 -#define WL12XX_RX_ALIGN(len) (((len) + WL12XX_RX_ALIGN_TO - 1) & \ - ~(WL12XX_RX_ALIGN_TO - 1)) +#define WL1251_RX_ALIGN_TO 4 +#define WL1251_RX_ALIGN(len) (((len) + WL1251_RX_ALIGN_TO - 1) & \ + ~(WL1251_RX_ALIGN_TO - 1)) #define SHORT_PREAMBLE_BIT BIT(0) #define OFDM_RATE_BIT BIT(6) @@ -74,7 +74,7 @@ #define RX_DESC_MIC_FAIL 0x2000 #define RX_DESC_DECRYPT_FAIL 0x4000 -struct wl12xx_rx_descriptor { +struct wl1251_rx_descriptor { u32 timestamp; /* In microseconds */ u16 length; /* Paylod length, including headers */ u16 flags; @@ -119,6 +119,6 @@ struct wl12xx_rx_descriptor { u8 snr; /* in dB */ } __attribute__ ((packed)); -void wl12xx_rx(struct wl12xx *wl); +void wl1251_rx(struct wl1251 *wl); #endif diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index 5b4889e351d..c5da79dbc49 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (C) 2008 Nokia Corporation * @@ -26,11 +26,10 @@ #include #include "wl1251.h" -#include "wl12xx_80211.h" #include "reg.h" #include "wl1251_spi.h" -static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr) +static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) { /* If the address is lower than REGISTERS_BASE, it means that this is * a chip-specific register address, so look it up in the registers @@ -38,7 +37,7 @@ static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr) if (addr < REGISTERS_BASE) { /* Make sure we don't go over the table */ if (addr >= ACX_REG_TABLE_LEN) { - wl12xx_error("address out of range (%d)", addr); + wl1251_error("address out of range (%d)", addr); return -EINVAL; } addr = wl->chip.acx_reg_table[addr]; @@ -47,13 +46,13 @@ static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr) return addr - wl->physical_reg_addr + wl->virtual_reg_addr; } -static int wl12xx_translate_mem_addr(struct wl12xx *wl, int addr) +static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr) { return addr - wl->physical_mem_addr + wl->virtual_mem_addr; } -void wl12xx_spi_reset(struct wl12xx *wl) +void wl1251_spi_reset(struct wl1251 *wl) { u8 *cmd; struct spi_transfer t; @@ -61,7 +60,7 @@ void wl12xx_spi_reset(struct wl12xx *wl) cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); if (!cmd) { - wl12xx_error("could not allocate cmd for spi reset"); + wl1251_error("could not allocate cmd for spi reset"); return; } @@ -76,10 +75,10 @@ void wl12xx_spi_reset(struct wl12xx *wl) spi_sync(wl->spi, &m); - wl12xx_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); + wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); } -void wl12xx_spi_init(struct wl12xx *wl) +void wl1251_spi_init(struct wl1251 *wl) { u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; struct spi_transfer t; @@ -87,7 +86,7 @@ void wl12xx_spi_init(struct wl12xx *wl) cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); if (!cmd) { - wl12xx_error("could not allocate cmd for spi init"); + wl1251_error("could not allocate cmd for spi init"); return; } @@ -130,7 +129,7 @@ void wl12xx_spi_init(struct wl12xx *wl) spi_sync(wl->spi, &m); - wl12xx_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); + wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); } /* Set the SPI partitions to access the chip addresses @@ -166,18 +165,18 @@ void wl12xx_spi_init(struct wl12xx *wl) * | | * */ -int wl12xx_set_partition(struct wl12xx *wl, +int wl1251_set_partition(struct wl1251 *wl, u32 mem_start, u32 mem_size, u32 reg_start, u32 reg_size) { - struct wl12xx_partition *partition; + struct wl1251_partition *partition; struct spi_transfer t; struct spi_message m; size_t len, cmd_len; u32 *cmd; int addr; - cmd_len = sizeof(u32) + 2 * sizeof(struct wl12xx_partition); + cmd_len = sizeof(u32) + 2 * sizeof(struct wl1251_partition); cmd = kzalloc(cmd_len, GFP_KERNEL); if (!cmd) return -ENOMEM; @@ -185,28 +184,28 @@ int wl12xx_set_partition(struct wl12xx *wl, spi_message_init(&m); memset(&t, 0, sizeof(t)); - partition = (struct wl12xx_partition *) (cmd + 1); + partition = (struct wl1251_partition *) (cmd + 1); addr = HW_ACCESS_PART0_SIZE_ADDR; - len = 2 * sizeof(struct wl12xx_partition); + len = 2 * sizeof(struct wl1251_partition); *cmd |= WSPI_CMD_WRITE; *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; *cmd |= addr & WSPI_CMD_BYTE_ADDR; - wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", mem_start, mem_size); - wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", reg_start, reg_size); /* Make sure that the two partitions together don't exceed the * address range */ if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { - wl12xx_debug(DEBUG_SPI, "Total size exceeds maximum virtual" + wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual" " address range. Truncating partition[0]."); mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; - wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", mem_start, mem_size); - wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", reg_start, reg_size); } @@ -214,23 +213,23 @@ int wl12xx_set_partition(struct wl12xx *wl, ((mem_start + mem_size) > reg_start)) { /* Guarantee that the memory partition doesn't overlap the * registers partition */ - wl12xx_debug(DEBUG_SPI, "End of partition[0] is " + wl1251_debug(DEBUG_SPI, "End of partition[0] is " "overlapping partition[1]. Adjusted."); mem_size = reg_start - mem_start; - wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", mem_start, mem_size); - wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", reg_start, reg_size); } else if ((reg_start < mem_start) && ((reg_start + reg_size) > mem_start)) { /* Guarantee that the register partition doesn't overlap the * memory partition */ - wl12xx_debug(DEBUG_SPI, "End of partition[1] is" + wl1251_debug(DEBUG_SPI, "End of partition[1] is" " overlapping partition[0]. Adjusted."); reg_size = mem_start - reg_start; - wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", mem_start, mem_size); - wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", reg_start, reg_size); } @@ -256,7 +255,7 @@ int wl12xx_set_partition(struct wl12xx *wl, return 0; } -void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, +void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, size_t len, bool fixed) { struct spi_transfer t[3]; @@ -284,7 +283,7 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, /* Busy and non busy words read */ t[1].rx_buf = busy_buf; - t[1].len = WL12XX_BUSY_WORD_LEN; + t[1].len = WL1251_BUSY_WORD_LEN; spi_message_add_tail(&t[1], &m); t[2].rx_buf = buf; @@ -295,11 +294,11 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, /* FIXME: check busy words */ - wl12xx_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); - wl12xx_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); + wl1251_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); + wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); } -void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, +void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, size_t len, bool fixed) { struct spi_transfer t[2]; @@ -329,66 +328,66 @@ void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, spi_sync(wl->spi, &m); - wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); - wl12xx_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); + wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); + wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); } -void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, +void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len) { int physical; - physical = wl12xx_translate_mem_addr(wl, addr); + physical = wl1251_translate_mem_addr(wl, addr); - wl12xx_spi_read(wl, physical, buf, len, false); + wl1251_spi_read(wl, physical, buf, len, false); } -void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, +void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len) { int physical; - physical = wl12xx_translate_mem_addr(wl, addr); + physical = wl1251_translate_mem_addr(wl, addr); - wl12xx_spi_write(wl, physical, buf, len, false); + wl1251_spi_write(wl, physical, buf, len, false); } -void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, +void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len, bool fixed) { int physical; - physical = wl12xx_translate_reg_addr(wl, addr); + physical = wl1251_translate_reg_addr(wl, addr); - wl12xx_spi_read(wl, physical, buf, len, fixed); + wl1251_spi_read(wl, physical, buf, len, fixed); } -void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len, +void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len, bool fixed) { int physical; - physical = wl12xx_translate_reg_addr(wl, addr); + physical = wl1251_translate_reg_addr(wl, addr); - wl12xx_spi_write(wl, physical, buf, len, fixed); + wl1251_spi_write(wl, physical, buf, len, fixed); } -u32 wl12xx_mem_read32(struct wl12xx *wl, int addr) +u32 wl1251_mem_read32(struct wl1251 *wl, int addr) { - return wl12xx_read32(wl, wl12xx_translate_mem_addr(wl, addr)); + return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr)); } -void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val) +void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val) { - wl12xx_write32(wl, wl12xx_translate_mem_addr(wl, addr), val); + wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val); } -u32 wl12xx_reg_read32(struct wl12xx *wl, int addr) +u32 wl1251_reg_read32(struct wl1251 *wl, int addr) { - return wl12xx_read32(wl, wl12xx_translate_reg_addr(wl, addr)); + return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr)); } -void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val) +void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val) { - wl12xx_write32(wl, wl12xx_translate_reg_addr(wl, addr), val); + wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val); } diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h index 82b009c3e9e..6e8daf4e108 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.h +++ b/drivers/net/wireless/wl12xx/wl1251_spi.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008 Nokia Corporation @@ -22,8 +22,8 @@ * */ -#ifndef __WL12XX_SPI_H__ -#define __WL12XX_SPI_H__ +#ifndef __WL1251_SPI_H__ +#define __WL1251_SPI_H__ #include "wl1251_cmd.h" #include "wl1251_acx.h" @@ -66,50 +66,50 @@ #define WSPI_INIT_CMD_LEN 8 #define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ - ((WL12XX_BUSY_WORD_LEN - 4) / sizeof(u32)) + ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32)) #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 /* Raw target IO, address is not translated */ -void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, +void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, size_t len, bool fixed); -void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, +void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, size_t len, bool fixed); /* Memory target IO, address is tranlated to partition 0 */ -void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, size_t len); -void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, size_t len); -u32 wl12xx_mem_read32(struct wl12xx *wl, int addr); -void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val); +void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len); +void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len); +u32 wl1251_mem_read32(struct wl1251 *wl, int addr); +void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val); /* Registers IO */ -void wl12xx_spi_reg_read(struct wl12xx *wl, int addr, void *buf, size_t len, +void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len, bool fixed); -void wl12xx_spi_reg_write(struct wl12xx *wl, int addr, void *buf, size_t len, +void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len, bool fixed); -u32 wl12xx_reg_read32(struct wl12xx *wl, int addr); -void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val); +u32 wl1251_reg_read32(struct wl1251 *wl, int addr); +void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val); /* INIT and RESET words */ -void wl12xx_spi_reset(struct wl12xx *wl); -void wl12xx_spi_init(struct wl12xx *wl); -int wl12xx_set_partition(struct wl12xx *wl, +void wl1251_spi_reset(struct wl1251 *wl); +void wl1251_spi_init(struct wl1251 *wl); +int wl1251_set_partition(struct wl1251 *wl, u32 part_start, u32 part_size, u32 reg_start, u32 reg_size); -static inline u32 wl12xx_read32(struct wl12xx *wl, int addr) +static inline u32 wl1251_read32(struct wl1251 *wl, int addr) { - wl12xx_spi_read(wl, addr, &wl->buffer_32, + wl1251_spi_read(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32), false); return wl->buffer_32; } -static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val) +static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) { wl->buffer_32 = val; - wl12xx_spi_write(wl, addr, &wl->buffer_32, + wl1251_spi_write(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32), false); } -#endif /* __WL12XX_SPI_H__ */ +#endif /* __WL1251_SPI_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c index 00c5649d909..2652a222383 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008 Nokia Corporation @@ -31,7 +31,7 @@ #include "wl1251_tx.h" #include "wl1251_ps.h" -static bool wl1251_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count) +static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count) { int used, data_in_count; @@ -52,13 +52,13 @@ static bool wl1251_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count) return false; } -static int wl1251_tx_path_status(struct wl12xx *wl) +static int wl1251_tx_path_status(struct wl1251 *wl) { u32 status, addr, data_out_count; bool busy; addr = wl->data_path->tx_control_addr; - status = wl12xx_mem_read32(wl, addr); + status = wl1251_mem_read32(wl, addr); data_out_count = status & TX_STATUS_DATA_OUT_COUNT_MASK; busy = wl1251_tx_double_buffer_busy(wl, data_out_count); @@ -68,7 +68,7 @@ static int wl1251_tx_path_status(struct wl12xx *wl) return 0; } -static int wl1251_tx_id(struct wl12xx *wl, struct sk_buff *skb) +static int wl1251_tx_id(struct wl1251 *wl, struct sk_buff *skb) { int i; @@ -142,7 +142,7 @@ static void wl1251_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr) tx_hdr->num_mem_blocks = mem_blocks; } -static int wl1251_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb, +static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb, struct ieee80211_tx_info *control) { struct tx_double_buffer_desc *tx_hdr; @@ -177,7 +177,7 @@ static int wl1251_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb, } /* We copy the packet to the target */ -static int wl1251_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb, +static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb, struct ieee80211_tx_info *control) { struct tx_double_buffer_desc *tx_hdr; @@ -211,7 +211,7 @@ static int wl1251_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb, */ if (unlikely((long)skb->data & 0x03)) { int offset = (4 - (long)skb->data) & 0x03; - wl12xx_debug(DEBUG_TX, "skb offset %d", offset); + wl1251_debug(DEBUG_TX, "skb offset %d", offset); /* check whether the current skb can be used */ if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { @@ -221,7 +221,7 @@ static int wl1251_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb, skb_reserve(skb, offset); memmove(skb->data, src, skb->len); } else { - wl12xx_info("No handler, fixme!"); + wl1251_info("No handler, fixme!"); return -EINVAL; } } @@ -235,15 +235,15 @@ static int wl1251_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb, else addr = wl->data_path->tx_packet_ring_addr; - wl12xx_spi_mem_write(wl, addr, skb->data, len); + wl1251_spi_mem_write(wl, addr, skb->data, len); - wl12xx_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x", + wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x", tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate); return 0; } -static void wl1251_tx_trigger(struct wl12xx *wl) +static void wl1251_tx_trigger(struct wl1251 *wl) { u32 data, addr; @@ -255,7 +255,7 @@ static void wl1251_tx_trigger(struct wl12xx *wl) data = INTR_TRIG_TX_PROC0; } - wl12xx_reg_write32(wl, addr, data); + wl1251_reg_write32(wl, addr, data); /* Bumping data in */ wl->data_in_count = (wl->data_in_count + 1) & @@ -263,7 +263,7 @@ static void wl1251_tx_trigger(struct wl12xx *wl) } /* caller must hold wl->mutex */ -static int wl1251_tx_frame(struct wl12xx *wl, struct sk_buff *skb) +static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb) { struct ieee80211_tx_info *info; int ret = 0; @@ -274,7 +274,7 @@ static int wl1251_tx_frame(struct wl12xx *wl, struct sk_buff *skb) if (info->control.hw_key) { idx = info->control.hw_key->hw_key_idx; if (unlikely(wl->default_key != idx)) { - ret = wl12xx_acx_default_key(wl, idx); + ret = wl1251_acx_default_key(wl, idx); if (ret < 0) return ret; } @@ -299,19 +299,19 @@ static int wl1251_tx_frame(struct wl12xx *wl, struct sk_buff *skb) void wl1251_tx_work(struct work_struct *work) { - struct wl12xx *wl = container_of(work, struct wl12xx, tx_work); + struct wl1251 *wl = container_of(work, struct wl1251, tx_work); struct sk_buff *skb; bool woken_up = false; int ret; mutex_lock(&wl->mutex); - if (unlikely(wl->state == WL12XX_STATE_OFF)) + if (unlikely(wl->state == WL1251_STATE_OFF)) goto out; while ((skb = skb_dequeue(&wl->tx_queue))) { if (!woken_up) { - ret = wl12xx_ps_elp_wakeup(wl); + ret = wl1251_ps_elp_wakeup(wl); if (ret < 0) goto out; woken_up = true; @@ -320,7 +320,7 @@ void wl1251_tx_work(struct work_struct *work) ret = wl1251_tx_frame(wl, skb); if (ret == -EBUSY) { /* firmware buffer is full, stop queues */ - wl12xx_debug(DEBUG_TX, "tx_work: fw buffer full, " + wl1251_debug(DEBUG_TX, "tx_work: fw buffer full, " "stop queues"); ieee80211_stop_queues(wl->hw); wl->tx_queue_stopped = true; @@ -334,7 +334,7 @@ void wl1251_tx_work(struct work_struct *work) out: if (woken_up) - wl12xx_ps_elp_sleep(wl); + wl1251_ps_elp_sleep(wl); mutex_unlock(&wl->mutex); } @@ -367,7 +367,7 @@ static const char *wl1251_tx_parse_status(u8 status) return buf; } -static void wl1251_tx_packet_cb(struct wl12xx *wl, +static void wl1251_tx_packet_cb(struct wl1251 *wl, struct tx_result *result) { struct ieee80211_tx_info *info; @@ -377,7 +377,7 @@ static void wl1251_tx_packet_cb(struct wl12xx *wl, skb = wl->tx_frames[result->id]; if (skb == NULL) { - wl12xx_error("SKB for packet %d is NULL", result->id); + wl1251_error("SKB for packet %d is NULL", result->id); return; } @@ -402,7 +402,7 @@ static void wl1251_tx_packet_cb(struct wl12xx *wl, skb_pull(skb, WL1251_TKIP_IV_SPACE); } - wl12xx_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" + wl1251_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" " status 0x%x (%s)", result->id, skb, result->ack_failures, result->rate, result->status, wl1251_tx_parse_status(result->status)); @@ -413,7 +413,7 @@ static void wl1251_tx_packet_cb(struct wl12xx *wl, wl->tx_frames[result->id] = NULL; if (wl->tx_queue_stopped) { - wl12xx_debug(DEBUG_TX, "cb: queue was stopped"); + wl1251_debug(DEBUG_TX, "cb: queue was stopped"); skb = skb_dequeue(&wl->tx_queue); @@ -425,7 +425,7 @@ static void wl1251_tx_packet_cb(struct wl12xx *wl, ret = wl1251_tx_frame(wl, skb); if (ret == -EBUSY) { /* firmware buffer is still full */ - wl12xx_debug(DEBUG_TX, "cb: fw buffer " + wl1251_debug(DEBUG_TX, "cb: fw buffer " "still full"); skb_queue_head(&wl->tx_queue, skb); return; @@ -435,23 +435,23 @@ static void wl1251_tx_packet_cb(struct wl12xx *wl, } } - wl12xx_debug(DEBUG_TX, "cb: waking queues"); + wl1251_debug(DEBUG_TX, "cb: waking queues"); ieee80211_wake_queues(wl->hw); wl->tx_queue_stopped = false; } } /* Called upon reception of a TX complete interrupt */ -void wl1251_tx_complete(struct wl12xx *wl) +void wl1251_tx_complete(struct wl1251 *wl) { int i, result_index, num_complete = 0; struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr; - if (unlikely(wl->state != WL12XX_STATE_ON)) + if (unlikely(wl->state != WL1251_STATE_ON)) return; /* First we read the result */ - wl12xx_spi_mem_read(wl, wl->data_path->tx_complete_addr, + wl1251_spi_mem_read(wl, wl->data_path->tx_complete_addr, result, sizeof(result)); result_index = wl->next_tx_complete; @@ -482,7 +482,7 @@ void wl1251_tx_complete(struct wl12xx *wl) */ if (result_index > wl->next_tx_complete) { /* Only 1 write is needed */ - wl12xx_spi_mem_write(wl, + wl1251_spi_mem_write(wl, wl->data_path->tx_complete_addr + (wl->next_tx_complete * sizeof(struct tx_result)), @@ -493,7 +493,7 @@ void wl1251_tx_complete(struct wl12xx *wl) } else if (result_index < wl->next_tx_complete) { /* 2 writes are needed */ - wl12xx_spi_mem_write(wl, + wl1251_spi_mem_write(wl, wl->data_path->tx_complete_addr + (wl->next_tx_complete * sizeof(struct tx_result)), @@ -502,7 +502,7 @@ void wl1251_tx_complete(struct wl12xx *wl) wl->next_tx_complete) * sizeof(struct tx_result)); - wl12xx_spi_mem_write(wl, + wl1251_spi_mem_write(wl, wl->data_path->tx_complete_addr, result, (num_complete - @@ -512,7 +512,7 @@ void wl1251_tx_complete(struct wl12xx *wl) } else { /* We have to write the whole array */ - wl12xx_spi_mem_write(wl, + wl1251_spi_mem_write(wl, wl->data_path->tx_complete_addr, result, FW_TX_CMPLT_BLOCK_SIZE * @@ -525,7 +525,7 @@ void wl1251_tx_complete(struct wl12xx *wl) } /* caller must hold wl->mutex */ -void wl1251_tx_flush(struct wl12xx *wl) +void wl1251_tx_flush(struct wl1251 *wl) { int i; struct sk_buff *skb; @@ -537,7 +537,7 @@ void wl1251_tx_flush(struct wl12xx *wl) while ((skb = skb_dequeue(&wl->tx_queue))) { info = IEEE80211_SKB_CB(skb); - wl12xx_debug(DEBUG_TX, "flushing skb 0x%p", skb); + wl1251_debug(DEBUG_TX, "flushing skb 0x%p", skb); if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) continue; diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.h b/drivers/net/wireless/wl12xx/wl1251_tx.h index a5d4c825905..7c1c1665c81 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.h +++ b/drivers/net/wireless/wl12xx/wl1251_tx.h @@ -1,5 +1,5 @@ /* - * This file is part of wl12xx + * This file is part of wl1251 * * Copyright (c) 1998-2007 Texas Instruments Incorporated * Copyright (C) 2008 Nokia Corporation @@ -210,7 +210,7 @@ struct tx_result { } __attribute__ ((packed)); void wl1251_tx_work(struct work_struct *work); -void wl1251_tx_complete(struct wl12xx *wl); -void wl1251_tx_flush(struct wl12xx *wl); +void wl1251_tx_complete(struct wl1251 *wl); +void wl1251_tx_flush(struct wl1251 *wl); #endif -- cgit v1.2.3-18-g5258 From 05fac682c2ca0c572d1bd8e6a38025838ddf0e68 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 12 Jun 2009 14:17:47 +0300 Subject: wl1251: fix a checkpatch warning drivers/net/wireless/wl12xx/wl1251_main.c:158: WARNING: braces {} are not necessary for single statement blocks Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index f4bc5796c24..11e1903aee6 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -155,9 +155,8 @@ static void wl1251_fw_wakeup(struct wl1251 *wl) wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); - if (!(elp_reg & ELPCTRL_WLAN_READY)) { + if (!(elp_reg & ELPCTRL_WLAN_READY)) wl1251_warning("WLAN not ready"); - } } static int wl1251_chip_wakeup(struct wl1251 *wl) -- cgit v1.2.3-18-g5258 From 47af3fe36dc478f7eddc8bec104ff1876d71f37c Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 12 Jun 2009 14:17:53 +0300 Subject: wl1251: change psm enabled/disabled info to debug With shorter CAM timeouts, the logs get flooded with "psm enabled" and "psm disabled traces. This patch changes it from wl1251_info to wl1251_debug, so they are only shown if DEBUF_PSM is enabled. Signed-off-by: Luciano Coelho Reviewed-by: Janne Ylalehto Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 11e1903aee6..cf5e0549fa1 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -542,7 +542,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) goto out_sleep; if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { - wl1251_info("psm enabled"); + wl1251_debug(DEBUG_PSM, "psm enabled"); wl->psm_requested = true; @@ -554,7 +554,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); } else if (!(conf->flags & IEEE80211_CONF_PS) && wl->psm_requested) { - wl1251_info("psm disabled"); + wl1251_debug(DEBUG_PSM, "psm disabled"); wl->psm_requested = false; -- cgit v1.2.3-18-g5258 From 9d67187dbd93df98011f7229f76de25d142b57cc Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 12 Jun 2009 13:22:53 -0700 Subject: iwlwifi: modify sensitivity value for 5150 In 5150 there is a long delay between the AGC(Automatic Gain Control) command till the RF is stabilized causing us to miss detections when there was adjacent channel noise, so we need to adjusted the Sensitivity calibration for 5150 differently. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index b3c648ce8c7..0e445a9c692 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -407,6 +407,28 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = { .nrg_th_ofdm = 95, }; +static struct iwl_sensitivity_ranges iwl5150_sensitivity = { + .min_nrg_cck = 95, + .max_nrg_cck = 0, /* not used, set to 0 */ + .auto_corr_min_ofdm = 90, + .auto_corr_min_ofdm_mrc = 170, + .auto_corr_min_ofdm_x1 = 105, + .auto_corr_min_ofdm_mrc_x1 = 220, + + .auto_corr_max_ofdm = 120, + .auto_corr_max_ofdm_mrc = 210, + /* max = min for performance bug in 5150 DSP */ + .auto_corr_max_ofdm_x1 = 105, + .auto_corr_max_ofdm_mrc_x1 = 220, + + .auto_corr_min_cck = 125, + .auto_corr_max_cck = 200, + .auto_corr_min_cck_mrc = 170, + .auto_corr_max_cck_mrc = 400, + .nrg_th_cck = 95, + .nrg_th_ofdm = 95, +}; + static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) { @@ -826,8 +848,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; - priv->hw_params.sens = &iwl5000_sensitivity; - priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; @@ -836,9 +856,11 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) if (priv->cfg->ops->lib->temp_ops.set_ct_kill) priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); + /* Set initial sensitivity parameters */ /* Set initial calibration set */ switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_5150: + priv->hw_params.sens = &iwl5150_sensitivity; priv->hw_params.calib_init_cfg = BIT(IWL_CALIB_DC) | BIT(IWL_CALIB_LO) | @@ -847,6 +869,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) break; default: + priv->hw_params.sens = &iwl5000_sensitivity; priv->hw_params.calib_init_cfg = BIT(IWL_CALIB_XTAL) | BIT(IWL_CALIB_LO) | -- cgit v1.2.3-18-g5258 From fe6efb4b423c923fb491a9ca4fa419e843548740 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 12 Jun 2009 13:22:54 -0700 Subject: iwlwifi: no need to refer to max_nrg_cck range value max_nrg_cck value inside the sensitivity range structure is not needed for sensitivity calibration. Keep the parameter in sensitivity structure but set the value to "0" in case needed in the future implementation. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- drivers/net/wireless/iwlwifi/iwl-5000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-calib.c | 7 +------ 3 files changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 8f3d4bc6a03..edbb0bfd8cb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -728,7 +728,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) static struct iwl_sensitivity_ranges iwl4965_sensitivity = { .min_nrg_cck = 97, - .max_nrg_cck = 0, + .max_nrg_cck = 0, /* not used, set to 0 */ .auto_corr_min_ofdm = 85, .auto_corr_min_ofdm_mrc = 170, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 0e445a9c692..85e8bac499a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -388,7 +388,7 @@ void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info, static struct iwl_sensitivity_ranges iwl5000_sensitivity = { .min_nrg_cck = 95, - .max_nrg_cck = 0, + .max_nrg_cck = 0, /* not used, set to 0 */ .auto_corr_min_ofdm = 90, .auto_corr_min_ofdm_mrc = 170, .auto_corr_min_ofdm_x1 = 120, diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index a5d63672ad3..f8bf592e939 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -251,12 +251,7 @@ static int iwl_sens_energy_cck(struct iwl_priv *priv, /* increase energy threshold (reduce nrg value) * to decrease sensitivity */ - if (data->nrg_th_cck > - (ranges->max_nrg_cck + NRG_STEP_CCK)) - data->nrg_th_cck = data->nrg_th_cck - - NRG_STEP_CCK; - else - data->nrg_th_cck = ranges->max_nrg_cck; + data->nrg_th_cck = data->nrg_th_cck - NRG_STEP_CCK; /* Else if we got fewer than desired, increase sensitivity */ } else if (false_alarms < min_false_alarms) { data->nrg_curr_state = IWL_FA_TOO_FEW; -- cgit v1.2.3-18-g5258 From 030b865520c3e26f4a316852aa022a22c4948907 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 12 Jun 2009 13:22:55 -0700 Subject: iwlwifi: remove disable_tx_power for device > 4965 After 4965, tx_power_calibration moved from driver to uCode. remove "disable_tx_power" from debugfs to minimize the confusion. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 11e08c06891..f32ac74b69a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -615,7 +615,10 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); - DEBUGFS_ADD_BOOL(disable_tx_power, rf, &priv->disable_tx_power_cal); + if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) || + ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945)) + DEBUGFS_ADD_BOOL(disable_tx_power, rf, + &priv->disable_tx_power_cal); return 0; err: @@ -646,7 +649,9 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dir_data); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power); + if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) || + ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945)) + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power); DEBUGFS_REMOVE(priv->dbgfs->dir_rf); DEBUGFS_REMOVE(priv->dbgfs->dir_drv); kfree(priv->dbgfs); -- cgit v1.2.3-18-g5258 From 0c5553b1392dea5ba5ad678790367c1275ed1172 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 15 Jun 2009 21:59:50 +0200 Subject: iwmc3200wifi: invalidate keys when changing the BSSID While associated, we have to invalidate our key cache if we clear our BSSID through siwap. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/wext.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c index 584c94d0f39..889194931b4 100644 --- a/drivers/net/wireless/iwmc3200wifi/wext.c +++ b/drivers/net/wireless/iwmc3200wifi/wext.c @@ -82,6 +82,7 @@ static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { struct iwm_priv *iwm = ndev_to_iwm(dev); + int ret; if (iwm->conf.mode == UMAC_MODE_IBSS) return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); @@ -104,10 +105,26 @@ static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info, } if (iwm->umac_profile_active) { + int i; + if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN)) return 0; - iwm_invalidate_mlme_profile(iwm); + /* + * If we're clearing the BSSID, and we're associated, + * we have to clear the keys as they're no longer valid. + */ + if (is_zero_ether_addr(ap_addr->sa_data)) { + for (i = 0; i < IWM_NUM_KEYS; i++) + iwm->keys[i].in_use = 0; + + } + + ret = iwm_invalidate_mlme_profile(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't invalidate profile\n"); + return ret; + } } if (iwm->umac_profile->ssid.ssid_len) -- cgit v1.2.3-18-g5258 From a70742f167424bab794ca74b9e99b598b358bb7d Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 15 Jun 2009 21:59:51 +0200 Subject: iwmc3200wifi: handling wifi_if_ntfy responses When we're calling iwm_send_wifi_if_cmd() with the resp flag set, we're currently waiting on the mlme queue, waiting for some flags here and there to show up. This patch adds a wifi_ntfy bitmap, and when we're sending a wifi_if command expecting an answers, we wait synchronously for it to show up, on a dedicated queue. The wifi_ntfy bit is set when we receive the corresponding answer. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 31 ++++++++++++++++------------ drivers/net/wireless/iwmc3200wifi/iwm.h | 3 +++ drivers/net/wireless/iwmc3200wifi/main.c | 1 + drivers/net/wireless/iwmc3200wifi/rx.c | 9 ++++++-- drivers/net/wireless/iwmc3200wifi/umac.h | 2 ++ 5 files changed, 31 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 834a7f544e5..337a884f52d 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -70,14 +70,28 @@ static int iwm_send_lmac_ptrough_cmd(struct iwm_priv *iwm, int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, bool resp) { + struct iwm_umac_wifi_if *hdr = (struct iwm_umac_wifi_if *)payload; struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; struct iwm_umac_cmd umac_cmd; + int ret; + u8 oid = hdr->oid; umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER; umac_cmd.resp = resp; - return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, - payload, payload_size); + ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, + payload, payload_size); + + if (resp) { + ret = wait_event_interruptible_timeout(iwm->wifi_ntfy_queue, + test_and_clear_bit(oid, &iwm->wifi_ntfy[0]), + 3 * HZ); + + if (!ret) + ret = -EBUSY; + } + + return ret; } static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] = @@ -746,14 +760,6 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm) return ret; } - /* Wait for the profile to be active */ - ret = wait_event_interruptible_timeout(iwm->mlme_queue, - iwm->umac_profile_active == 1, - 3 * HZ); - if (!ret) - return -EBUSY; - - for (i = 0; i < IWM_NUM_KEYS; i++) if (iwm->keys[i].in_use) { int default_key = 0; @@ -778,8 +784,8 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm) int iwm_invalidate_mlme_profile(struct iwm_priv *iwm) { - int ret; struct iwm_umac_invalidate_profile invalid; + int ret; invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE; invalid.hdr.buf_size = @@ -793,8 +799,7 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm) return ret; ret = wait_event_interruptible_timeout(iwm->mlme_queue, - (iwm->umac_profile_active == 0), - 2 * HZ); + (iwm->umac_profile_active == 0), 2 * HZ); if (!ret) return -EBUSY; diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 77c339f8516..d8d4ae2d91b 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -278,6 +278,9 @@ struct iwm_priv { struct iwm_key keys[IWM_NUM_KEYS]; struct iwm_key *default_key; + DECLARE_BITMAP(wifi_ntfy, WIFI_IF_NTFY_MAX); + wait_queue_head_t wifi_ntfy_queue; + wait_queue_head_t mlme_queue; struct iw_statistics wstats; diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 8be206d5822..844872213a1 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -191,6 +191,7 @@ int iwm_priv_init(struct iwm_priv *iwm) INIT_LIST_HEAD(&iwm->pending_notif); init_waitqueue_head(&iwm->notif_queue); init_waitqueue_head(&iwm->nonwifi_queue); + init_waitqueue_head(&iwm->wifi_ntfy_queue); init_waitqueue_head(&iwm->mlme_queue); memcpy(&iwm->conf, &def_iwm_conf, sizeof(struct iwm_conf)); spin_lock_init(&iwm->tx_credit.lock); diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index d73cf96c6dc..49a8be7c539 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -993,12 +993,17 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, (struct iwm_umac_wifi_if *)cmd->buf.payload; IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: " - "oid is %d\n", hdr->oid); + "oid is 0x%x\n", hdr->oid); + + if (hdr->oid <= WIFI_IF_NTFY_MAX) { + set_bit(hdr->oid, &iwm->wifi_ntfy[0]); + wake_up_interruptible(&iwm->wifi_ntfy_queue); + } else + return -EINVAL; switch (hdr->oid) { case UMAC_WIFI_IF_CMD_SET_PROFILE: iwm->umac_profile_active = 1; - wake_up_interruptible(&iwm->mlme_queue); break; default: break; diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h index 4a95cce1f0a..0af2a3c7628 100644 --- a/drivers/net/wireless/iwmc3200wifi/umac.h +++ b/drivers/net/wireless/iwmc3200wifi/umac.h @@ -495,6 +495,8 @@ struct iwm_fw_alive_hdr { #define WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP 0xE8 #define WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP 0xE9 +#define WIFI_IF_NTFY_MAX 0xff + /* Notification structures */ struct iwm_umac_notif_wifi_if { struct iwm_umac_wifi_in_hdr hdr; -- cgit v1.2.3-18-g5258 From 13e0fe70960e95cdea89b71aa3d046ec71efac8c Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 15 Jun 2009 21:59:52 +0200 Subject: iwmc3200wifi: cfg80211 key hooks implemetation This patch implements the new cfg80211 privacy related hooks: add/get/set_key and the set_default_key one. With this implementation we can now call the wext-compat *encode* routines and reduce our own wext code. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 172 ++++++++++++++++ drivers/net/wireless/iwmc3200wifi/commands.c | 72 +++---- drivers/net/wireless/iwmc3200wifi/commands.h | 3 +- drivers/net/wireless/iwmc3200wifi/iwm.h | 14 +- drivers/net/wireless/iwmc3200wifi/main.c | 4 +- drivers/net/wireless/iwmc3200wifi/wext.c | 286 ++------------------------- 6 files changed, 219 insertions(+), 332 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index bc89b1ef0ca..739bd9b0dde 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -130,6 +131,173 @@ static struct ieee80211_supported_band iwm_band_5ghz = { .n_bitrates = iwm_a_rates_size, }; +static int iwm_key_init(struct iwm_key *key, u8 key_index, + const u8 *mac_addr, struct key_params *params) +{ + key->hdr.key_idx = key_index; + if (!mac_addr || is_broadcast_ether_addr(mac_addr)) { + key->hdr.multicast = 1; + memset(key->hdr.mac, 0xff, ETH_ALEN); + } else { + key->hdr.multicast = 0; + memcpy(key->hdr.mac, mac_addr, ETH_ALEN); + } + + if (params) { + if (params->key_len > WLAN_MAX_KEY_LEN || + params->seq_len > IW_ENCODE_SEQ_MAX_SIZE) + return -EINVAL; + + key->cipher = params->cipher; + key->key_len = params->key_len; + key->seq_len = params->seq_len; + memcpy(key->key, params->key, key->key_len); + memcpy(key->seq, params->seq, key->seq_len); + } + + return 0; +} + +static int iwm_reset_profile(struct iwm_priv *iwm) +{ + int ret; + + if (!iwm->umac_profile_active) + return 0; + + /* + * If there is a current active profile, but no + * default key, it's not worth trying to associate again. + */ + if (iwm->default_key < 0) + return 0; + + /* + * Here we have an active profile, but a key setting changed. + * We thus have to invalidate the current profile, and push the + * new one. Keys will be pushed when association takes place. + */ + ret = iwm_invalidate_mlme_profile(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't invalidate profile\n"); + return ret; + } + + return iwm_send_mlme_profile(iwm); +} + +static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, + u8 key_index, const u8 *mac_addr, + struct key_params *params) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + struct iwm_key *key = &iwm->keys[key_index]; + int ret; + + IWM_DBG_WEXT(iwm, DBG, "Adding key for %pM\n", mac_addr); + + memset(key, 0, sizeof(struct iwm_key)); + ret = iwm_key_init(key, key_index, mac_addr, params); + if (ret < 0) { + IWM_ERR(iwm, "Invalid key_params\n"); + return ret; + } + + /* + * The WEP keys can be set before or after setting the essid. + * We need to handle both cases by simply pushing the keys after + * we send the profile. + * If the profile is not set yet (i.e. we're pushing keys before + * the essid), we set the cipher appropriately. + * If the profile is set, we havent associated yet because our + * cipher was incorrectly set. So we invalidate and send the + * profile again. + */ + if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || + key->cipher == WLAN_CIPHER_SUITE_WEP104) { + u8 *ucast_cipher = &iwm->umac_profile->sec.ucast_cipher; + u8 *mcast_cipher = &iwm->umac_profile->sec.mcast_cipher; + + IWM_DBG_WEXT(iwm, DBG, "WEP key\n"); + + if (key->cipher == WLAN_CIPHER_SUITE_WEP40) + *ucast_cipher = *mcast_cipher = UMAC_CIPHER_TYPE_WEP_40; + if (key->cipher == WLAN_CIPHER_SUITE_WEP104) + *ucast_cipher = *mcast_cipher = + UMAC_CIPHER_TYPE_WEP_104; + + return iwm_reset_profile(iwm); + } + + return iwm_set_key(iwm, 0, key); +} + +static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, + u8 key_index, const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, + struct key_params*)) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + struct iwm_key *key = &iwm->keys[key_index]; + struct key_params params; + + IWM_DBG_WEXT(iwm, DBG, "Getting key %d\n", key_index); + + memset(¶ms, 0, sizeof(params)); + + params.cipher = key->cipher; + params.key_len = key->key_len; + params.seq_len = key->seq_len; + params.seq = key->seq; + params.key = key->key; + + callback(cookie, ¶ms); + + return key->key_len ? 0 : -ENOENT; +} + + +static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, + u8 key_index, const u8 *mac_addr) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + struct iwm_key *key = &iwm->keys[key_index]; + + if (!iwm->keys[key_index].key_len) { + IWM_DBG_WEXT(iwm, DBG, "Key %d not used\n", key_index); + return 0; + } + + if (key_index == iwm->default_key) + iwm->default_key = -1; + + return iwm_set_key(iwm, 1, key); +} + +static int iwm_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + int ret; + + IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index); + + if (!iwm->keys[key_index].key_len) { + IWM_ERR(iwm, "Key %d not used\n", key_index); + return -EINVAL; + } + + ret = iwm_set_tx_key(iwm, key_index); + if (ret < 0) + return ret; + + iwm->default_key = key_index; + + return iwm_reset_profile(iwm); +} + + int iwm_cfg80211_inform_bss(struct iwm_priv *iwm) { struct wiphy *wiphy = iwm_to_wiphy(iwm); @@ -326,6 +494,10 @@ static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) static struct cfg80211_ops iwm_cfg80211_ops = { .change_virtual_intf = iwm_cfg80211_change_iface, + .add_key = iwm_cfg80211_add_key, + .get_key = iwm_cfg80211_get_key, + .del_key = iwm_cfg80211_del_key, + .set_default_key = iwm_cfg80211_set_default_key, .scan = iwm_cfg80211_scan, .set_wiphy_params = iwm_cfg80211_set_wiphy_params, .join_ibss = iwm_cfg80211_join_ibss, diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 337a884f52d..145f6f5ae74 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -524,9 +524,6 @@ int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx) { struct iwm_umac_tx_key_id tx_key_id; - if (!iwm->default_key || !iwm->default_key->in_use) - return -EINVAL; - tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID; tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) - sizeof(struct iwm_umac_wifi_if)); @@ -569,10 +566,9 @@ static int iwm_check_profile(struct iwm_priv *iwm) return 0; } -int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, - struct iwm_key *key) +int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) { - int ret; + int ret = 0; u8 cmd[64], *sta_addr, *key_data, key_len; s8 key_idx; u16 cmd_size = 0; @@ -582,9 +578,6 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd; struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd; - if (set_tx_key) - iwm->default_key = key; - /* * We check if our current profile is valid. * If not, we dont push the key, we just cache them, @@ -603,8 +596,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, key_idx = key->hdr.key_idx; if (!remove) { - IWM_DBG_WEXT(iwm, DBG, "key_idx:%d set tx key:%d\n", - key_idx, set_tx_key); + IWM_DBG_WEXT(iwm, DBG, "key_idx:%d\n", key_idx); IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len); IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n", key_hdr->mac, key_hdr->key_idx, key_hdr->multicast); @@ -616,8 +608,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, iwm->umac_profile->sec.auth_type, iwm->umac_profile->sec.flags); - switch (key->alg) { - case UMAC_CIPHER_TYPE_WEP_40: + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY; wep40->hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_key_wep40) - @@ -631,7 +623,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, cmd_size = sizeof(struct iwm_umac_key_wep40); break; - case UMAC_CIPHER_TYPE_WEP_104: + case WLAN_CIPHER_SUITE_WEP104: wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY; wep104->hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_key_wep104) - @@ -645,7 +637,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, cmd_size = sizeof(struct iwm_umac_key_wep104); break; - case UMAC_CIPHER_TYPE_CCMP: + case WLAN_CIPHER_SUITE_CCMP: key_hdr->key_idx++; ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY; ccmp->hdr.buf_size = @@ -657,13 +649,13 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, memcpy(ccmp->key, key_data, key_len); - if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID) - memcpy(ccmp->iv_count, key->rx_seq, 6); + if (key->seq_len) + memcpy(ccmp->iv_count, key->seq, key->seq_len); cmd_size = sizeof(struct iwm_umac_key_ccmp); break; - case UMAC_CIPHER_TYPE_TKIP: + case WLAN_CIPHER_SUITE_TKIP: key_hdr->key_idx++; tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY; tkip->hdr.buf_size = @@ -680,8 +672,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE, IWM_TKIP_MIC_SIZE); - if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID) - memcpy(ccmp->iv_count, key->rx_seq, 6); + if (key->seq_len) + memcpy(ccmp->iv_count, key->seq, key->seq_len); cmd_size = sizeof(struct iwm_umac_key_tkip); break; @@ -690,8 +682,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, return -ENOTSUPP; } - if ((key->alg == UMAC_CIPHER_TYPE_CCMP) || - (key->alg == UMAC_CIPHER_TYPE_TKIP)) + if ((key->cipher == WLAN_CIPHER_SUITE_TKIP) || + (key->cipher == WLAN_CIPHER_SUITE_CCMP)) /* * UGLY_UGLY_UGLY * Copied HACK from the MWG driver. @@ -702,23 +694,11 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, schedule_timeout_interruptible(usecs_to_jiffies(300)); ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1); - if (ret < 0) - goto err; - - /* - * We need a default key only if it is set and - * if we're doing WEP. - */ - if (iwm->default_key == key && - ((key->alg == UMAC_CIPHER_TYPE_WEP_40) || - (key->alg == UMAC_CIPHER_TYPE_WEP_104))) { - ret = iwm_set_tx_key(iwm, key_idx); - if (ret < 0) - goto err; - } } else { struct iwm_umac_key_remove key_remove; + IWM_DBG_WEXT(iwm, ERR, "Removing key_idx:%d\n", key_idx); + key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY; key_remove.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_key_remove) - @@ -732,13 +712,9 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, if (ret < 0) return ret; - iwm->keys[key_idx].in_use = 0; + iwm->keys[key_idx].key_len = 0; } - return 0; - - err: - kfree(key); return ret; } @@ -761,22 +737,24 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm) } for (i = 0; i < IWM_NUM_KEYS; i++) - if (iwm->keys[i].in_use) { - int default_key = 0; + if (iwm->keys[i].key_len) { struct iwm_key *key = &iwm->keys[i]; - if (key == iwm->default_key) - default_key = 1; - /* Wait for the profile before sending the keys */ wait_event_interruptible_timeout(iwm->mlme_queue, (test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) || test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)), 3 * HZ); - ret = iwm_set_key(iwm, 0, default_key, key); + ret = iwm_set_key(iwm, 0, key); if (ret < 0) return ret; + + if (iwm->default_key == i) { + ret = iwm_set_tx_key(iwm, i); + if (ret < 0) + return ret; + } } return 0; diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h index 36b13a13059..3510df8ff39 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.h +++ b/drivers/net/wireless/iwmc3200wifi/commands.h @@ -406,8 +406,7 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm); int iwm_invalidate_mlme_profile(struct iwm_priv *iwm); int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id); int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx); -int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, - struct iwm_key *key); +int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key); int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags); int iwm_send_umac_channel_list(struct iwm_priv *iwm); int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index d8d4ae2d91b..90b05d99963 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -162,13 +162,11 @@ struct iwm_umac_key_hdr { struct iwm_key { struct iwm_umac_key_hdr hdr; - u8 in_use; - u8 alg; - u32 flags; - u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; - u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; - u8 key_len; - u8 key[32]; + u32 cipher; + u8 key[WLAN_MAX_KEY_LEN]; + u8 seq[IW_ENCODE_SEQ_MAX_SIZE]; + int key_len; + int seq_len; }; #define IWM_RX_ID_HASH 0xff @@ -276,7 +274,7 @@ struct iwm_priv { struct iwm_tx_queue txq[IWM_TX_QUEUES]; struct iwm_key keys[IWM_NUM_KEYS]; - struct iwm_key *default_key; + s8 default_key; DECLARE_BITMAP(wifi_ntfy, WIFI_IF_NTFY_MAX); wait_queue_head_t wifi_ntfy_queue; diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 844872213a1..7f56c06a53d 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -230,7 +230,7 @@ int iwm_priv_init(struct iwm_priv *iwm) for (i = 0; i < IWM_NUM_KEYS; i++) memset(&iwm->keys[i], 0, sizeof(struct iwm_key)); - iwm->default_key = NULL; + iwm->default_key = -1; init_timer(&iwm->watchdog); iwm->watchdog.function = iwm_watchdog; @@ -709,7 +709,7 @@ int __iwm_down(struct iwm_priv *iwm) iwm->umac_profile = NULL; iwm_bss_list_clean(iwm); - iwm->default_key = NULL; + iwm->default_key = -1; iwm->core_enabled = 0; ret = iwm_bus_disable(iwm); diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c index 889194931b4..3062f37bbe9 100644 --- a/drivers/net/wireless/iwmc3200wifi/wext.c +++ b/drivers/net/wireless/iwmc3200wifi/wext.c @@ -84,6 +84,8 @@ static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info, struct iwm_priv *iwm = ndev_to_iwm(dev); int ret; + IWM_DBG_WEXT(iwm, DBG, "Set BSSID: %pM\n", ap_addr->sa_data); + if (iwm->conf.mode == UMAC_MODE_IBSS) return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); @@ -116,8 +118,7 @@ static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info, */ if (is_zero_ether_addr(ap_addr->sa_data)) { for (i = 0; i < IWM_NUM_KEYS; i++) - iwm->keys[i].in_use = 0; - + iwm->keys[i].key_len = 0; } ret = iwm_invalidate_mlme_profile(iwm); @@ -163,6 +164,8 @@ static int iwm_wext_siwessid(struct net_device *dev, size_t len = data->length; int ret; + IWM_DBG_WEXT(iwm, DBG, "Set ESSID: >%s<\n", ssid); + if (iwm->conf.mode == UMAC_MODE_IBSS) return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); @@ -212,27 +215,6 @@ static int iwm_wext_giwessid(struct net_device *dev, return 0; } -static struct iwm_key * -iwm_key_init(struct iwm_priv *iwm, u8 key_idx, bool in_use, - struct iw_encode_ext *ext, u8 alg) -{ - struct iwm_key *key = &iwm->keys[key_idx]; - - memset(key, 0, sizeof(struct iwm_key)); - memcpy(key->hdr.mac, ext->addr.sa_data, ETH_ALEN); - key->hdr.key_idx = key_idx; - if (is_broadcast_ether_addr(ext->addr.sa_data)) - key->hdr.multicast = 1; - - key->in_use = in_use; - key->flags = ext->ext_flags; - key->alg = alg; - key->key_len = ext->key_len; - memcpy(key->key, ext->key, ext->key_len); - - return key; -} - static int iwm_wext_giwrate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rate, char *extra) @@ -244,184 +226,6 @@ static int iwm_wext_giwrate(struct net_device *dev, return 0; } -static int iwm_wext_siwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *key_buf) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - struct iwm_key *uninitialized_var(key); - int idx, i, uninitialized_var(alg), remove = 0, ret; - - IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", erq->length); - IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags); - - if (!iwm->umac_profile) { - IWM_ERR(iwm, "UMAC profile not allocated yet\n"); - return -ENODEV; - } - - if (erq->length == WLAN_KEY_LEN_WEP40) { - alg = UMAC_CIPHER_TYPE_WEP_40; - iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_40; - iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_40; - } else if (erq->length == WLAN_KEY_LEN_WEP104) { - alg = UMAC_CIPHER_TYPE_WEP_104; - iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_104; - iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_104; - } - - if (erq->flags & IW_ENCODE_RESTRICTED) - iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; - else - iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN; - - idx = erq->flags & IW_ENCODE_INDEX; - if (idx == 0) { - if (iwm->default_key) - for (i = 0; i < IWM_NUM_KEYS; i++) { - if (iwm->default_key == &iwm->keys[i]) { - idx = i; - break; - } - } - else - iwm->default_key = &iwm->keys[idx]; - } else if (idx < 1 || idx > 4) { - return -EINVAL; - } else - idx--; - - if (erq->flags & IW_ENCODE_DISABLED) - remove = 1; - else if (erq->length == 0) { - if (!iwm->keys[idx].in_use) - return -EINVAL; - iwm->default_key = &iwm->keys[idx]; - } - - if (erq->length) { - key = &iwm->keys[idx]; - memset(key, 0, sizeof(struct iwm_key)); - memset(key->hdr.mac, 0xff, ETH_ALEN); - key->hdr.key_idx = idx; - key->hdr.multicast = 1; - key->in_use = !remove; - key->alg = alg; - key->key_len = erq->length; - memcpy(key->key, key_buf, erq->length); - - IWM_DBG_WEXT(iwm, DBG, "Setting key %d, default: %d\n", - idx, !!iwm->default_key); - } - - if (remove) { - if ((erq->flags & IW_ENCODE_NOKEY) || (erq->length == 0)) { - int j; - for (j = 0; j < IWM_NUM_KEYS; j++) - if (iwm->keys[j].in_use) { - struct iwm_key *k = &iwm->keys[j]; - - k->in_use = 0; - ret = iwm_set_key(iwm, remove, 0, k); - if (ret < 0) - return ret; - } - - iwm->umac_profile->sec.ucast_cipher = - UMAC_CIPHER_TYPE_NONE; - iwm->umac_profile->sec.mcast_cipher = - UMAC_CIPHER_TYPE_NONE; - iwm->umac_profile->sec.auth_type = - UMAC_AUTH_TYPE_OPEN; - - return 0; - } else { - key->in_use = 0; - return iwm_set_key(iwm, remove, 0, key); - } - } - - /* - * If we havent set a profile yet, we cant set keys. - * Keys will be pushed after we're associated. - */ - if (!iwm->umac_profile_active) - return 0; - - /* - * If there is a current active profile, but no - * default key, it's not worth trying to associate again. - */ - if (!iwm->default_key) - return 0; - - /* - * Here we have an active profile, but a key setting changed. - * We thus have to invalidate the current profile, and push the - * new one. Keys will be pushed when association takes place. - */ - ret = iwm_invalidate_mlme_profile(iwm); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't invalidate profile\n"); - return ret; - } - - return iwm_send_mlme_profile(iwm); -} - -static int iwm_wext_giwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *key) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - int idx, i; - - idx = erq->flags & IW_ENCODE_INDEX; - if (idx < 1 || idx > 4) { - idx = -1; - if (!iwm->default_key) { - erq->length = 0; - erq->flags |= IW_ENCODE_NOKEY; - return 0; - } else - for (i = 0; i < IWM_NUM_KEYS; i++) { - if (iwm->default_key == &iwm->keys[i]) { - idx = i; - break; - } - } - if (idx < 0) - return -EINVAL; - } else - idx--; - - erq->flags = idx + 1; - - if (!iwm->keys[idx].in_use) { - erq->length = 0; - erq->flags |= IW_ENCODE_DISABLED; - return 0; - } - - memcpy(key, iwm->keys[idx].key, - min_t(int, erq->length, iwm->keys[idx].key_len)); - erq->length = iwm->keys[idx].key_len; - erq->flags |= IW_ENCODE_ENABLED; - - if (iwm->umac_profile->mode == UMAC_MODE_BSS) { - switch (iwm->umac_profile->sec.auth_type) { - case UMAC_AUTH_TYPE_OPEN: - erq->flags |= IW_ENCODE_OPEN; - break; - default: - erq->flags |= IW_ENCODE_RESTRICTED; - break; - } - } - - return 0; -} - static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version) { if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) @@ -481,6 +285,8 @@ static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt) { u8 *auth_type = &iwm->umac_profile->sec.auth_type; + IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt); + if (key_mgt == IW_AUTH_KEY_MGMT_802_1X) *auth_type = UMAC_AUTH_TYPE_8021X; else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) { @@ -530,6 +336,8 @@ static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg) { u8 *auth_type = &iwm->umac_profile->sec.auth_type; + IWM_DBG_WEXT(iwm, DBG, "auth_alg: 0x%x\n", auth_alg); + switch (auth_alg) { case IW_AUTH_ALG_OPEN_SYSTEM: *auth_type = UMAC_AUTH_TYPE_OPEN; @@ -541,6 +349,7 @@ static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg) return -EINVAL; *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; } else { + IWM_DBG_WEXT(iwm, DBG, "WEP shared key\n"); *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; } break; @@ -603,75 +412,6 @@ static int iwm_wext_giwauth(struct net_device *dev, return 0; } -static int iwm_wext_siwencodeext(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - struct iwm_key *key; - struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; - int uninitialized_var(alg), idx, i, remove = 0; - - IWM_DBG_WEXT(iwm, DBG, "alg: 0x%x\n", ext->alg); - IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", ext->key_len); - IWM_DBG_WEXT(iwm, DBG, "ext_flags: 0x%x\n", ext->ext_flags); - IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags); - IWM_DBG_WEXT(iwm, DBG, "length: 0x%x\n", erq->length); - - switch (ext->alg) { - case IW_ENCODE_ALG_NONE: - remove = 1; - break; - case IW_ENCODE_ALG_WEP: - if (ext->key_len == WLAN_KEY_LEN_WEP40) - alg = UMAC_CIPHER_TYPE_WEP_40; - else if (ext->key_len == WLAN_KEY_LEN_WEP104) - alg = UMAC_CIPHER_TYPE_WEP_104; - else { - IWM_ERR(iwm, "Invalid key length: %d\n", ext->key_len); - return -EINVAL; - } - - break; - case IW_ENCODE_ALG_TKIP: - alg = UMAC_CIPHER_TYPE_TKIP; - break; - case IW_ENCODE_ALG_CCMP: - alg = UMAC_CIPHER_TYPE_CCMP; - break; - default: - return -EOPNOTSUPP; - } - - idx = erq->flags & IW_ENCODE_INDEX; - - if (idx == 0) { - if (iwm->default_key) - for (i = 0; i < IWM_NUM_KEYS; i++) { - if (iwm->default_key == &iwm->keys[i]) { - idx = i; - break; - } - } - } else if (idx < 1 || idx > 4) { - return -EINVAL; - } else - idx--; - - if (erq->flags & IW_ENCODE_DISABLED) - remove = 1; - else if ((erq->length == 0) || - (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) { - iwm->default_key = &iwm->keys[idx]; - if (iwm->umac_profile_active && ext->alg == IW_ENCODE_ALG_WEP) - return iwm_set_tx_key(iwm, idx); - } - - key = iwm_key_init(iwm, idx, !remove, ext, alg); - - return iwm_set_key(iwm, remove, !iwm->default_key, key); -} - static const iw_handler iwm_handlers[] = { (iw_handler) NULL, /* SIOCSIWCOMMIT */ @@ -716,8 +456,8 @@ static const iw_handler iwm_handlers[] = (iw_handler) NULL, /* SIOCGIWTXPOW */ (iw_handler) NULL, /* SIOCSIWRETRY */ (iw_handler) NULL, /* SIOCGIWRETRY */ - (iw_handler) iwm_wext_siwencode, /* SIOCSIWENCODE */ - (iw_handler) iwm_wext_giwencode, /* SIOCGIWENCODE */ + (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ + (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */ (iw_handler) iwm_wext_siwpower, /* SIOCSIWPOWER */ (iw_handler) iwm_wext_giwpower, /* SIOCGIWPOWER */ (iw_handler) NULL, /* -- hole -- */ @@ -726,7 +466,7 @@ static const iw_handler iwm_handlers[] = (iw_handler) NULL, /* SIOCGIWGENIE */ (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */ (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */ - (iw_handler) iwm_wext_siwencodeext, /* SIOCSIWENCODEEXT */ + (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */ (iw_handler) NULL, /* SIOCGIWENCODEEXT */ (iw_handler) NULL, /* SIOCSIWPMKSA */ (iw_handler) NULL, /* -- hole -- */ -- cgit v1.2.3-18-g5258 From 191506ecbce03f09f6afa76f1af069574bf99bec Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 15 Jun 2009 21:59:53 +0200 Subject: iwmc3200wifi: change coexist periodic calibration flag The patch changes coexist periodic calibration priority flag. It also set wireless mode to UMAC and set PM control flag to 0x1. Signed-off-by: Zhu Yi Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 13 +++++++++---- drivers/net/wireless/iwmc3200wifi/commands.h | 4 ++-- 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 145f6f5ae74..0d35afefb61 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -120,7 +120,7 @@ static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] = {4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, {3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, {5, 5, 0, COEX_CALIBRATION_FLAGS}, - {4, 4, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, + {3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, {5, 4, 0, COEX_CONNECTION_ESTAB_FLAGS}, {4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS}, {4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, @@ -345,8 +345,7 @@ int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key, return ret; } -int iwm_send_umac_config(struct iwm_priv *iwm, - __le32 reset_flags) +int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags) { int ret; @@ -373,6 +372,12 @@ int iwm_send_umac_config(struct iwm_priv *iwm, if (ret < 0) return ret; + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_WIRELESS_MODE, + iwm->conf.wireless_mode); + if (ret < 0) + return ret; + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, CFG_COEX_MODE, iwm->conf.coexist_mode); if (ret < 0) @@ -415,7 +420,7 @@ int iwm_send_umac_config(struct iwm_priv *iwm, return ret; ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_PM_CTRL_FLAGS, 0x30001); + CFG_PM_CTRL_FLAGS, 0x1); if (ret < 0) return ret; diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h index 3510df8ff39..e24d5b63399 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.h +++ b/drivers/net/wireless/iwmc3200wifi/commands.h @@ -106,8 +106,7 @@ enum { CFG_TLC_SPATIAL_STREAM_SUPPORTED, CFG_TLC_RETRY_PER_RATE, CFG_TLC_RETRY_PER_HT_RATE, - CFG_TLC_FIXED_RATE, - CFG_TLC_FIXED_RATE_FLAGS, + CFG_TLC_FIXED_MCS, CFG_TLC_CONTROL_FLAGS, CFG_TLC_SR_MIN_FAIL, CFG_TLC_SR_MIN_PASS, @@ -232,6 +231,7 @@ struct iwm_umac_cmd_get_channel_list { /* Wireless mode */ #define WIRELESS_MODE_11A 0x1 #define WIRELESS_MODE_11G 0x2 +#define WIRELESS_MODE_11N 0x4 #define UMAC_PROFILE_EX_IE_REQUIRED 0x1 #define UMAC_PROFILE_QOS_ALLOWED 0x2 -- cgit v1.2.3-18-g5258 From 3549716484a95fd16f7fcf8b68699bd4c803b382 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 15 Jun 2009 21:59:54 +0200 Subject: iwmc3200wifi: cache keys when interface is down When the interface is down and one sets a WEP key from userspace, we should be able to simply cache it. Since that implies setting part of the profile's security settings, we now alloc/free the umac_profile at probe/remove time, and no longer at interface bring up/down time. Simply resetting it during the latter is enough. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 12 ++++++++++-- drivers/net/wireless/iwmc3200wifi/main.c | 20 +++----------------- drivers/net/wireless/iwmc3200wifi/netdev.c | 15 +++++++++++++++ 3 files changed, 28 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 739bd9b0dde..0cdd7ef68b7 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -271,6 +271,10 @@ static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, if (key_index == iwm->default_key) iwm->default_key = -1; + /* If the interface is down, we just cache this */ + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return 0; + return iwm_set_key(iwm, 1, key); } @@ -288,12 +292,16 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy, return -EINVAL; } + iwm->default_key = key_index; + + /* If the interface is down, we just cache this */ + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return 0; + ret = iwm_set_tx_key(iwm, key_index); if (ret < 0) return ret; - iwm->default_key = key_index; - return iwm_reset_profile(iwm); } diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 7f56c06a53d..930056b013f 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -643,19 +643,10 @@ int __iwm_up(struct iwm_priv *iwm) } } - iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile), - GFP_KERNEL); - if (!iwm->umac_profile) { - IWM_ERR(iwm, "Couldn't alloc memory for profile\n"); - goto err_fw; - } - - iwm_init_default_profile(iwm, iwm->umac_profile); - ret = iwm_channels_init(iwm); if (ret < 0) { IWM_ERR(iwm, "Couldn't init channels\n"); - goto err_profile; + goto err_fw; } /* Set the READY bit to indicate interface is brought up successfully */ @@ -663,10 +654,6 @@ int __iwm_up(struct iwm_priv *iwm) return 0; - err_profile: - kfree(iwm->umac_profile); - iwm->umac_profile = NULL; - err_fw: iwm_eeprom_exit(iwm); @@ -705,10 +692,9 @@ int __iwm_down(struct iwm_priv *iwm) clear_bit(IWM_STATUS_READY, &iwm->status); iwm_eeprom_exit(iwm); - kfree(iwm->umac_profile); - iwm->umac_profile = NULL; iwm_bss_list_clean(iwm); - + iwm_init_default_profile(iwm, iwm->umac_profile); + iwm->umac_profile_active = false; iwm->default_key = -1; iwm->core_enabled = 0; diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c index aaa20c6885c..d4deb4b471e 100644 --- a/drivers/net/wireless/iwmc3200wifi/netdev.c +++ b/drivers/net/wireless/iwmc3200wifi/netdev.c @@ -48,6 +48,7 @@ #include #include "iwm.h" +#include "commands.h" #include "cfg80211.h" #include "debug.h" @@ -135,8 +136,20 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev, SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); wdev->netdev = ndev; + iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile), + GFP_KERNEL); + if (!iwm->umac_profile) { + dev_err(dev, "Couldn't alloc memory for profile\n"); + goto out_profile; + } + + iwm_init_default_profile(iwm, iwm->umac_profile); + return iwm; + out_profile: + free_netdev(ndev); + out_priv: iwm_priv_deinit(iwm); @@ -153,6 +166,8 @@ void iwm_if_free(struct iwm_priv *iwm) free_netdev(iwm_to_ndev(iwm)); iwm_wdev_free(iwm); iwm_priv_deinit(iwm); + kfree(iwm->umac_profile); + iwm->umac_profile = NULL; } int iwm_if_add(struct iwm_priv *iwm) -- cgit v1.2.3-18-g5258 From 257862f3faef397f1a677ae6a5a1828fa00a97b1 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 15 Jun 2009 21:59:56 +0200 Subject: iwmc3200wifi: rfkill cleanup The patch cleans up the unused rfkill related structures and flags. It also adds wext and cfg80211 handlers for txpower auto and off so that software rfkill could be issued by user space. Signed-off-by: Zhu Yi Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 24 ++++++++++++++++++++++++ drivers/net/wireless/iwmc3200wifi/iwm.h | 7 +------ drivers/net/wireless/iwmc3200wifi/netdev.c | 12 ++---------- drivers/net/wireless/iwmc3200wifi/rx.c | 18 +++++++++--------- drivers/net/wireless/iwmc3200wifi/sdio.c | 6 +----- drivers/net/wireless/iwmc3200wifi/wext.c | 4 ++-- 6 files changed, 39 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 0cdd7ef68b7..d0629d4757d 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -500,6 +500,28 @@ static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) return 0; } +static int iwm_cfg80211_set_txpower(struct wiphy *wiphy, + enum tx_power_setting type, int dbm) +{ + switch (type) { + case TX_POWER_AUTOMATIC: + return 0; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + + *dbm = iwm->txpower; + + return 0; +} + static struct cfg80211_ops iwm_cfg80211_ops = { .change_virtual_intf = iwm_cfg80211_change_iface, .add_key = iwm_cfg80211_add_key, @@ -510,6 +532,8 @@ static struct cfg80211_ops iwm_cfg80211_ops = { .set_wiphy_params = iwm_cfg80211_set_wiphy_params, .join_ibss = iwm_cfg80211_join_ibss, .leave_ibss = iwm_cfg80211_leave_ibss, + .set_tx_power = iwm_cfg80211_set_txpower, + .get_tx_power = iwm_cfg80211_get_txpower, }; struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev) diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 90b05d99963..4da57f737f2 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -184,10 +184,6 @@ struct iwm_key { #define IWM_STATUS_ASSOCIATING 3 #define IWM_STATUS_ASSOCIATED 4 -#define IWM_RADIO_RFKILL_OFF 0 -#define IWM_RADIO_RFKILL_HW 1 -#define IWM_RADIO_RFKILL_SW 2 - struct iwm_tx_queue { int id; struct sk_buff_head queue; @@ -221,7 +217,6 @@ struct iwm_priv { struct iwm_conf conf; unsigned long status; - unsigned long radio; struct list_head pending_notif; wait_queue_head_t notif_queue; @@ -240,6 +235,7 @@ struct iwm_priv { u8 bssid[ETH_ALEN]; u8 channel; u16 rate; + u32 txpower; struct iwm_sta_info sta_table[IWM_STA_TABLE_NUM]; struct list_head bss_list; @@ -290,7 +286,6 @@ struct iwm_priv { struct timer_list watchdog; struct work_struct reset_worker; struct mutex mutex; - struct rfkill *rfkill; char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); }; diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c index d4deb4b471e..e94e96955b9 100644 --- a/drivers/net/wireless/iwmc3200wifi/netdev.c +++ b/drivers/net/wireless/iwmc3200wifi/netdev.c @@ -55,23 +55,15 @@ static int iwm_open(struct net_device *ndev) { struct iwm_priv *iwm = ndev_to_iwm(ndev); - int ret = 0; - - if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) - ret = iwm_up(iwm); - return ret; + return iwm_up(iwm); } static int iwm_stop(struct net_device *ndev) { struct iwm_priv *iwm = ndev_to_iwm(ndev); - int ret = 0; - - if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) - ret = iwm_down(iwm); - return ret; + return iwm_down(iwm); } /* diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 49a8be7c539..55871da695a 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -143,17 +143,18 @@ static int iwm_ntf_init_complete(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, struct iwm_wifi_cmd *cmd) { + struct wiphy *wiphy = iwm_to_wiphy(iwm); struct iwm_umac_notif_init_complete *init_complete = (struct iwm_umac_notif_init_complete *)(buf); u16 status = le16_to_cpu(init_complete->status); + bool blocked = (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR); - if (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR) { + if (blocked) IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is on (radio off)\n"); - set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); - } else { + else IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is off (radio on)\n"); - clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); - } + + wiphy_rfkill_set_hw_state(wiphy, blocked); return 0; } @@ -875,6 +876,7 @@ static int iwm_ntf_statistics(struct iwm_priv *iwm, u8 *buf, /* UMAC passes rate info multiplies by 2 */ iwm->rate = max_rate >> 1; } + iwm->txpower = le32_to_cpu(stats->tx_power); wstats->status = 0; @@ -1015,6 +1017,7 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, struct iwm_wifi_cmd *cmd) { + struct wiphy *wiphy = iwm_to_wiphy(iwm); struct iwm_lmac_card_state *state = (struct iwm_lmac_card_state *) (buf + sizeof(struct iwm_umac_wifi_in_hdr)); u32 flags = le32_to_cpu(state->flags); @@ -1023,10 +1026,7 @@ static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf, flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF", flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF"); - if (flags & IWM_CARD_STATE_HW_DISABLED) - set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); - else - clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); + wiphy_rfkill_set_hw_state(wiphy, flags & IWM_CARD_STATE_HW_DISABLED); return 0; } diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c index 916681837fd..b93f620ee4f 100644 --- a/drivers/net/wireless/iwmc3200wifi/sdio.c +++ b/drivers/net/wireless/iwmc3200wifi/sdio.c @@ -506,11 +506,7 @@ static struct sdio_driver iwm_sdio_driver = { static int __init iwm_sdio_init_module(void) { - int ret; - - ret = sdio_register_driver(&iwm_sdio_driver); - - return ret; + return sdio_register_driver(&iwm_sdio_driver); } static void __exit iwm_sdio_exit_module(void) diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c index 3062f37bbe9..973457383c1 100644 --- a/drivers/net/wireless/iwmc3200wifi/wext.c +++ b/drivers/net/wireless/iwmc3200wifi/wext.c @@ -452,8 +452,8 @@ static const iw_handler iwm_handlers[] = (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */ - (iw_handler) NULL, /* SIOCSIWTXPOW */ - (iw_handler) NULL, /* SIOCGIWTXPOW */ + (iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */ + (iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */ (iw_handler) NULL, /* SIOCSIWRETRY */ (iw_handler) NULL, /* SIOCGIWRETRY */ (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ -- cgit v1.2.3-18-g5258 From d75ec2b7ec27fd6cdba78492fbd63bee4d091a87 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 16 Jun 2009 17:17:21 +0300 Subject: rndis_wlan: convert get/set frag/rts to cfg80211 Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 135 ++++++++++++++++++-------------------- 1 file changed, 63 insertions(+), 72 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index e8b0793b030..edd4aad68be 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -428,9 +428,12 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request); +static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed); + static struct cfg80211_ops rndis_config_ops = { .change_virtual_intf = rndis_change_virtual_intf, .scan = rndis_scan, + .set_wiphy_params = rndis_set_wiphy_params, }; static void *rndis_wiphy_privid = &rndis_wiphy_privid; @@ -969,6 +972,36 @@ static int set_infra_mode(struct usbnet *usbdev, int mode) } +static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold) +{ + __le32 tmp; + + devdbg(usbdev, "set_rts_threshold %i", rts_threshold); + + if (rts_threshold < 0 || rts_threshold > 2347) + rts_threshold = 2347; + + tmp = cpu_to_le32(rts_threshold); + return rndis_set_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp, + sizeof(tmp)); +} + + +static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold) +{ + __le32 tmp; + + devdbg(usbdev, "set_frag_threshold %i", frag_threshold); + + if (frag_threshold < 256 || frag_threshold > 2346) + frag_threshold = 2346; + + tmp = cpu_to_le32(frag_threshold); + return rndis_set_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp, + sizeof(tmp)); +} + + static void set_default_iw_params(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -1246,6 +1279,28 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, } +static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + int err; + + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { + err = set_frag_threshold(usbdev, wiphy->frag_threshold); + if (err < 0) + return err; + } + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + err = set_rts_threshold(usbdev, wiphy->rts_threshold); + if (err < 0) + return err; + } + + return 0; +} + + #define SCAN_DELAY_JIFFIES (HZ) static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request) @@ -1761,74 +1816,6 @@ static int rndis_iw_get_genie(struct net_device *dev, } -static int rndis_iw_set_rts(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - __le32 tmp; - devdbg(usbdev, "SIOCSIWRTS"); - - tmp = cpu_to_le32(wrqu->rts.value); - return rndis_set_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp, - sizeof(tmp)); -} - - -static int rndis_iw_get_rts(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - __le32 tmp; - int len, ret; - - len = sizeof(tmp); - ret = rndis_query_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp, &len); - if (ret == 0) { - wrqu->rts.value = le32_to_cpu(tmp); - wrqu->rts.flags = 1; - wrqu->rts.disabled = 0; - } - - devdbg(usbdev, "SIOCGIWRTS: %d", wrqu->rts.value); - - return ret; -} - - -static int rndis_iw_set_frag(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - __le32 tmp; - - devdbg(usbdev, "SIOCSIWFRAG"); - - tmp = cpu_to_le32(wrqu->frag.value); - return rndis_set_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp, - sizeof(tmp)); -} - - -static int rndis_iw_get_frag(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - __le32 tmp; - int len, ret; - - len = sizeof(tmp); - ret = rndis_query_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp, - &len); - if (ret == 0) { - wrqu->frag.value = le32_to_cpu(tmp); - wrqu->frag.flags = 1; - wrqu->frag.disabled = 0; - } - devdbg(usbdev, "SIOCGIWFRAG: %d", wrqu->frag.value); - return ret; -} - - static int rndis_iw_set_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { @@ -2017,10 +2004,10 @@ static const iw_handler rndis_iw_handler[] = IW_IOCTL(SIOCSIWESSID) = rndis_iw_set_essid, IW_IOCTL(SIOCGIWESSID) = rndis_iw_get_essid, IW_IOCTL(SIOCGIWRATE) = rndis_iw_get_rate, - IW_IOCTL(SIOCSIWRTS) = rndis_iw_set_rts, - IW_IOCTL(SIOCGIWRTS) = rndis_iw_get_rts, - IW_IOCTL(SIOCSIWFRAG) = rndis_iw_set_frag, - IW_IOCTL(SIOCGIWFRAG) = rndis_iw_get_frag, + IW_IOCTL(SIOCSIWRTS) = (iw_handler) cfg80211_wext_siwrts, + IW_IOCTL(SIOCGIWRTS) = (iw_handler) cfg80211_wext_giwrts, + IW_IOCTL(SIOCSIWFRAG) = (iw_handler) cfg80211_wext_siwfrag, + IW_IOCTL(SIOCGIWFRAG) = (iw_handler) cfg80211_wext_giwfrag, IW_IOCTL(SIOCSIWTXPOW) = rndis_iw_set_txpower, IW_IOCTL(SIOCGIWTXPOW) = rndis_iw_get_txpower, IW_IOCTL(SIOCSIWENCODE) = rndis_iw_set_encode, @@ -2470,6 +2457,10 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) set_default_iw_params(usbdev); + /* set default rts/frag */ + rndis_set_wiphy_params(wiphy, + WIPHY_PARAM_FRAG_THRESHOLD | WIPHY_PARAM_RTS_THRESHOLD); + /* turn radio on */ priv->radio_on = 1; disassociate(usbdev, 1); -- cgit v1.2.3-18-g5258 From a33e9e7f35ef6dcab528e0327f29188475f60691 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 16 Jun 2009 17:17:27 +0300 Subject: usbnet: Add stop function pointer to 'struct rndis_data'. Allow minidriver to know that netdev has stopped. This is to let wireless turn off radio when usbnet dev is stopped. Signed-off-by: Jussi Kivilinna Acked-by: David Brownell Acked-by: David S. Miller Signed-off-by: John W. Linville --- drivers/net/usb/usbnet.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index edfd9e10ceb..25e435c4904 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -575,7 +575,9 @@ EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs); int usbnet_stop (struct net_device *net) { struct usbnet *dev = netdev_priv(net); + struct driver_info *info = dev->driver_info; int temp; + int retval; DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup); DECLARE_WAITQUEUE (wait, current); @@ -587,6 +589,18 @@ int usbnet_stop (struct net_device *net) net->stats.rx_errors, net->stats.tx_errors ); + /* allow minidriver to stop correctly (wireless devices to turn off + * radio etc) */ + if (info->stop) { + retval = info->stop(dev); + if (retval < 0 && netif_msg_ifdown(dev)) + devinfo(dev, + "stop fail (%d) usbnet usb-%s-%s, %s", + retval, + dev->udev->bus->bus_name, dev->udev->devpath, + info->description); + } + // ensure there are no more active urbs add_wait_queue (&unlink_wakeup, &wait); dev->wait = &unlink_wakeup; -- cgit v1.2.3-18-g5258 From 222ec50a0a5d20e75522aacf4c767df6585e8548 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 16 Jun 2009 17:17:32 +0300 Subject: rndis_wlan: convert set/get txpower to cfg80211 Convert set/get txpower to cfg80211 and add stop netdev handler to turn off radio for rfkill. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 148 +++++++++++++++++++------------------- 1 file changed, 75 insertions(+), 73 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index edd4aad68be..09c0702ae64 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -139,9 +139,15 @@ MODULE_PARM_DESC(workaround_interval, /* Assume that Broadcom 4320 (only chipset at time of writing known to be * based on wireless rndis) has default txpower of 13dBm. * This value is from Linksys WUSB54GSC User Guide, Appendix F: Specifications. - * 13dBm == 19.9mW + * 100% : 20 mW ~ 13dBm + * 75% : 15 mW ~ 12dBm + * 50% : 10 mW ~ 10dBm + * 25% : 5 mW ~ 7dBm */ -#define BCM4320_DEFAULT_TXPOWER 20 +#define BCM4320_DEFAULT_TXPOWER_DBM_100 13 +#define BCM4320_DEFAULT_TXPOWER_DBM_75 12 +#define BCM4320_DEFAULT_TXPOWER_DBM_50 10 +#define BCM4320_DEFAULT_TXPOWER_DBM_25 7 /* codes for "status" field of completion messages */ @@ -430,15 +436,20 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed); +static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, + int dbm); +static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm); + static struct cfg80211_ops rndis_config_ops = { .change_virtual_intf = rndis_change_virtual_intf, .scan = rndis_scan, .set_wiphy_params = rndis_set_wiphy_params, + .set_tx_power = rndis_set_tx_power, + .get_tx_power = rndis_get_tx_power, }; static void *rndis_wiphy_privid = &rndis_wiphy_privid; -static const int bcm4320_power_output[4] = { 25, 50, 75, 100 }; static const unsigned char zero_bssid[ETH_ALEN] = {0,}; static const unsigned char ffff_bssid[ETH_ALEN] = { 0xff, 0xff, 0xff, @@ -451,10 +462,19 @@ static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev) } -static u32 get_bcm4320_power(struct rndis_wlan_private *priv) +static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv) { - return BCM4320_DEFAULT_TXPOWER * - bcm4320_power_output[priv->param_power_output] / 100; + switch (priv->param_power_output) { + default: + case 3: + return BCM4320_DEFAULT_TXPOWER_DBM_100; + case 2: + return BCM4320_DEFAULT_TXPOWER_DBM_75; + case 1: + return BCM4320_DEFAULT_TXPOWER_DBM_50; + case 0: + return BCM4320_DEFAULT_TXPOWER_DBM_25; + } } @@ -1301,6 +1321,42 @@ static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed) } +static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, + int dbm) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + + devdbg(usbdev, "rndis_set_tx_power type:0x%x dbm:%i", type, dbm); + + /* Device doesn't support changing txpower after initialization, only + * turn off/on radio. Support 'auto' mode and setting same dBm that is + * currently used. + */ + if (type == TX_POWER_AUTOMATIC || dbm == get_bcm4320_power_dbm(priv)) { + if (!priv->radio_on) + disassociate(usbdev, 1); /* turn on radio */ + + return 0; + } + + return -ENOTSUPP; +} + + +static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + + *dbm = get_bcm4320_power_dbm(priv); + + devdbg(usbdev, "rndis_get_tx_power dbm:%i", *dbm); + + return 0; +} + + #define SCAN_DELAY_JIFFIES (HZ) static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request) @@ -1864,71 +1920,6 @@ static int rndis_iw_get_freq(struct net_device *dev, } -static int rndis_iw_get_txpower(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - __le32 tx_power; - - if (priv->radio_on) { - /* fake since changing tx_power (by userlevel) not supported */ - tx_power = cpu_to_le32(get_bcm4320_power(priv)); - - wrqu->txpower.flags = IW_TXPOW_MWATT; - wrqu->txpower.value = le32_to_cpu(tx_power); - wrqu->txpower.disabled = 0; - } else { - wrqu->txpower.flags = IW_TXPOW_MWATT; - wrqu->txpower.value = 0; - wrqu->txpower.disabled = 1; - } - - devdbg(usbdev, "SIOCGIWTXPOW: %d", wrqu->txpower.value); - - return 0; -} - - -static int rndis_iw_set_txpower(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - __le32 tx_power = 0; - - if (!wrqu->txpower.disabled) { - if (wrqu->txpower.flags == IW_TXPOW_MWATT) - tx_power = cpu_to_le32(wrqu->txpower.value); - else { /* wrqu->txpower.flags == IW_TXPOW_DBM */ - if (wrqu->txpower.value > 20) - tx_power = cpu_to_le32(128); - else if (wrqu->txpower.value < -43) - tx_power = cpu_to_le32(127); - else { - signed char tmp; - tmp = wrqu->txpower.value; - tmp = -12 - tmp; - tmp <<= 2; - tx_power = cpu_to_le32((unsigned char)tmp); - } - } - } - - devdbg(usbdev, "SIOCSIWTXPOW: %d", le32_to_cpu(tx_power)); - - if (le32_to_cpu(tx_power) != 0) { - /* txpower unsupported, just turn radio on */ - if (!priv->radio_on) - return disassociate(usbdev, 1); - return 0; /* all ready on */ - } - - /* tx_power == 0, turn off radio */ - return disassociate(usbdev, 0); -} - - static int rndis_iw_get_rate(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { @@ -2008,8 +1999,8 @@ static const iw_handler rndis_iw_handler[] = IW_IOCTL(SIOCGIWRTS) = (iw_handler) cfg80211_wext_giwrts, IW_IOCTL(SIOCSIWFRAG) = (iw_handler) cfg80211_wext_siwfrag, IW_IOCTL(SIOCGIWFRAG) = (iw_handler) cfg80211_wext_giwfrag, - IW_IOCTL(SIOCSIWTXPOW) = rndis_iw_set_txpower, - IW_IOCTL(SIOCGIWTXPOW) = rndis_iw_get_txpower, + IW_IOCTL(SIOCSIWTXPOW) = (iw_handler) cfg80211_wext_siwtxpower, + IW_IOCTL(SIOCGIWTXPOW) = (iw_handler) cfg80211_wext_giwtxpower, IW_IOCTL(SIOCSIWENCODE) = rndis_iw_set_encode, IW_IOCTL(SIOCSIWENCODEEXT) = rndis_iw_set_encode_ext, IW_IOCTL(SIOCSIWAUTH) = rndis_iw_set_auth, @@ -2508,10 +2499,18 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) static int rndis_wlan_reset(struct usbnet *usbdev) { + devdbg(usbdev, "rndis_wlan_reset"); return deauthenticate(usbdev); } +static int rndis_wlan_stop(struct usbnet *usbdev) +{ + devdbg(usbdev, "rndis_wlan_stop"); + return disassociate(usbdev, 0); +} + + static const struct driver_info bcm4320b_info = { .description = "Wireless RNDIS device, BCM4320b based", .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, @@ -2521,6 +2520,7 @@ static const struct driver_info bcm4320b_info = { .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, .reset = rndis_wlan_reset, + .stop = rndis_wlan_stop, .early_init = bcm4320b_early_init, .link_change = rndis_wlan_link_change, }; @@ -2534,6 +2534,7 @@ static const struct driver_info bcm4320a_info = { .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, .reset = rndis_wlan_reset, + .stop = rndis_wlan_stop, .early_init = bcm4320a_early_init, .link_change = rndis_wlan_link_change, }; @@ -2547,6 +2548,7 @@ static const struct driver_info rndis_wlan_info = { .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, .reset = rndis_wlan_reset, + .stop = rndis_wlan_stop, .early_init = bcm4320a_early_init, .link_change = rndis_wlan_link_change, }; -- cgit v1.2.3-18-g5258 From 18ad01c43918751cc22f8ee28f6b38b8954a55b2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 Jun 2009 20:46:45 +0200 Subject: rt2x00: remove skb->do_not_encrypt usage Johannes is trying to get rid of the master netdev and in the process will remove skb->do_not_encrypt field. This removes the do_not_encrypt usage from rt2x00 to make the change easier. Signed-off-by: Johannes Berg Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00crypto.c | 6 ++---- drivers/net/wireless/rt2x00/rt2x00mac.c | 3 ++- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index bc4e81e2184..c54eda3c2db 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -53,8 +53,7 @@ void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; - if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || - !hw_key || entry->skb->do_not_encrypt) + if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !hw_key) return; __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags); @@ -82,8 +81,7 @@ unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev, struct ieee80211_key_conf *key = tx_info->control.hw_key; unsigned int overhead = 0; - if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || - !key || skb->do_not_encrypt) + if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !key) return overhead; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index c4c06b4e1f0..475a3ed7646 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -73,7 +73,8 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, else rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK; - skb->do_not_encrypt = 1; + /* Disable hardware encryption */ + rts_info->control.hw_key = NULL; /* * RTS/CTS frame should use the length of the frame plus any -- cgit v1.2.3-18-g5258 From f1d58c2521eb160178b2151d6326d8dc5d7c8560 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 17 Jun 2009 13:13:00 +0200 Subject: mac80211: push rx status into skb->cb Within mac80211, we often need to copy the rx status into skb->cb. This is wasteful, as drivers could be building it in there to start with. This patch changes the API so that drivers are expected to pass the RX status in skb->cb, now accessible as IEEE80211_SKB_RXCB(skb). It also updates all drivers to pass the rx status in there, but only by making them memcpy() it into place before the call to the receive function (ieee80211_rx(_irqsafe)). Each driver can now be optimised on its own schedule. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 3 ++- drivers/net/wireless/at76c50x-usb.c | 3 ++- drivers/net/wireless/ath/ar9170/main.c | 6 ++++-- drivers/net/wireless/ath/ath5k/base.c | 3 ++- drivers/net/wireless/ath/ath9k/recv.c | 13 +++++++++---- drivers/net/wireless/b43/xmit.c | 3 ++- drivers/net/wireless/b43legacy/xmit.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-3945.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-rx.c | 3 ++- drivers/net/wireless/libertas_tf/main.c | 3 ++- drivers/net/wireless/mac80211_hwsim.c | 3 ++- drivers/net/wireless/mwl8k.c | 3 ++- drivers/net/wireless/p54/p54common.c | 3 ++- drivers/net/wireless/rt2x00/rt2x00dev.c | 3 ++- drivers/net/wireless/rtl818x/rtl8180_dev.c | 3 ++- drivers/net/wireless/rtl818x/rtl8187_dev.c | 3 ++- drivers/net/wireless/wl12xx/wl1251_rx.c | 3 ++- drivers/net/wireless/zd1211rw/zd_mac.c | 3 ++- drivers/staging/agnx/xmit.c | 3 ++- drivers/staging/stlc45xx/stlc45xx.c | 3 ++- drivers/staging/winbond/wb35rx.c | 3 ++- 21 files changed, 51 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 2b9e379994a..ecc93834533 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -452,7 +452,8 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev) rx_status.freq = adm8211_channels[priv->channel - 1].center_freq; rx_status.band = IEEE80211_BAND_2GHZ; - ieee80211_rx_irqsafe(dev, skb, &rx_status); + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); + ieee80211_rx_irqsafe(dev, skb); } entry = (++priv->cur_rx) % priv->rx_ring_size; diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 4efbdbe6d6b..13303fa3473 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1568,7 +1568,8 @@ static void at76_rx_tasklet(unsigned long param) at76_dbg(DBG_MAC80211, "calling ieee80211_rx_irqsafe(): %d/%d", priv->rx_skb->len, priv->rx_skb->data_len); - ieee80211_rx_irqsafe(priv->hw, priv->rx_skb, &rx_status); + memcpy(IEEE80211_SKB_RXCB(priv->rx_skb), &rx_status, sizeof(rx_status)); + ieee80211_rx_irqsafe(priv->hw, priv->rx_skb); /* Use a new skb for the next receive */ priv->rx_skb = NULL; diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 9d38cf60a0d..51753ed1b8b 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -917,8 +917,10 @@ static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) ar9170_rx_phy_status(ar, phy, &status); skb = ar9170_rx_copy_data(buf, mpdu_len); - if (likely(skb)) - ieee80211_rx_irqsafe(ar->hw, skb, &status); + if (likely(skb)) { + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + ieee80211_rx_irqsafe(ar->hw, skb); + } } void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index f26a6896062..c6e70919435 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1905,7 +1905,8 @@ accept: if (sc->opmode == NL80211_IFTYPE_ADHOC) ath5k_check_ibss_tsf(sc, skb, &rxs); - __ieee80211_rx(sc->hw, skb, &rxs); + memcpy(IEEE80211_SKB_RXCB(skb), &rxs, sizeof(rxs)); + ieee80211_rx(sc->hw, skb); bf->skb = next_skb; bf->skbaddr = next_skb_addr; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index cece1c4c6bd..c00b9051bb5 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -619,13 +619,18 @@ static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb, if (aphy == NULL) continue; nskb = skb_copy(skb, GFP_ATOMIC); - if (nskb) - __ieee80211_rx(aphy->hw, nskb, rx_status); + if (nskb) { + memcpy(IEEE80211_SKB_RXCB(nskb), rx_status, + sizeof(*rx_status)); + ieee80211_rx(aphy->hw, nskb); + } } - __ieee80211_rx(sc->hw, skb, rx_status); + memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); + ieee80211_rx(sc->hw, skb); } else { /* Deliver unicast frames based on receiver address */ - __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, rx_status); + memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); + ieee80211_rx(ath_get_virt_hw(sc, hdr), skb); } } diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 55f36a7254d..5b85e7d7359 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -670,7 +670,8 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) goto drop; } - ieee80211_rx_irqsafe(dev->wl->hw, skb, &status); + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + ieee80211_rx_irqsafe(dev->wl->hw, skb); return; drop: diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index b8e39dd06e9..f79cee82601 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -591,7 +591,8 @@ void b43legacy_rx(struct b43legacy_wldev *dev, } dev->stats.last_rx = jiffies; - ieee80211_rx_irqsafe(dev->wl->hw, skb, &status); + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + ieee80211_rx_irqsafe(dev->wl->hw, skb); return; drop: diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 46288e72488..777c09534ce 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -577,7 +577,8 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, if (ieee80211_is_data(hdr->frame_control)) priv->rxtxpackets += len; #endif - ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); + memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); + ieee80211_rx_irqsafe(priv->hw, rxb->skb); rxb->skb = NULL; } diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 2b8d40b37a1..2160795ed01 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -932,7 +932,8 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, return; iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len); - ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); + memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); + ieee80211_rx_irqsafe(priv->hw, rxb->skb); priv->alloc_rxb_skb--; rxb->skb = NULL; } diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index 10a99e26d39..4872345a2f6 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -503,7 +503,8 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb) skb_reserve(skb, 2); } - ieee80211_rx_irqsafe(priv->hw, skb, &stats); + memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats)); + ieee80211_rx_irqsafe(priv->hw, skb); return 0; } EXPORT_SYMBOL_GPL(lbtf_rx); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index c47ef48f31c..b1e4baec29f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -430,7 +430,8 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr, ETH_ALEN) == 0) ack = true; - ieee80211_rx_irqsafe(data2->hw, nskb, &rx_status); + memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status)); + ieee80211_rx_irqsafe(data2->hw, nskb); } spin_unlock(&hwsim_radio_lock); diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index a263d5c84c0..b9eded88c32 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1047,7 +1047,8 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) status.flag = 0; status.band = IEEE80211_BAND_2GHZ; status.freq = ieee80211_channel_to_frequency(rx_desc->channel); - ieee80211_rx_irqsafe(hw, skb, &status); + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + ieee80211_rx_irqsafe(hw, skb); processed++; } diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 22ca122bd79..1b15f9e0b86 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -794,7 +794,8 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) skb_pull(skb, header_len); skb_trim(skb, le16_to_cpu(hdr->len)); - ieee80211_rx_irqsafe(dev, skb, &rx_status); + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); + ieee80211_rx_irqsafe(dev, skb); queue_delayed_work(dev->workqueue, &priv->work, msecs_to_jiffies(P54_STATISTICS_UPDATE)); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 57813e72c80..41e33798adb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -449,7 +449,8 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, * mac80211 will clean up the skb structure. */ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb); - ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status); + memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status)); + ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb); /* * Replace the skb with the freshly allocated one. diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index 7e65d7c3180..47521c5b6f9 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -143,7 +143,8 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; - ieee80211_rx_irqsafe(dev, skb, &rx_status); + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); + ieee80211_rx_irqsafe(dev, skb); skb = new_skb; priv->rx_buf[priv->rx_idx] = skb; diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 294250e294d..c9b9dbe584c 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -380,7 +380,8 @@ static void rtl8187_rx_cb(struct urb *urb) rx_status.flag |= RX_FLAG_TSFT; if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; - ieee80211_rx_irqsafe(dev, skb, &rx_status); + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); + ieee80211_rx_irqsafe(dev, skb); skb = dev_alloc_skb(RTL8187_MAX_RX); if (unlikely(!skb)) { diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c index 48fa39ea17e..0dbb483a097 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.c +++ b/drivers/net/wireless/wl12xx/wl1251_rx.c @@ -151,7 +151,8 @@ static void wl1251_rx_body(struct wl1251 *wl, wl1251_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, beacon ? "beacon" : ""); - ieee80211_rx(wl->hw, skb, &status); + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + ieee80211_rx(wl->hw, skb); } static void wl1251_rx_ack(struct wl1251 *wl) diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 40b07b98822..9600b72495d 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -711,7 +711,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) memcpy(skb_put(skb, length), buffer, length); - ieee80211_rx_irqsafe(hw, skb, &stats); + memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats)); + ieee80211_rx_irqsafe(hw, skb); return 0; } diff --git a/drivers/staging/agnx/xmit.c b/drivers/staging/agnx/xmit.c index 0e034081f3a..42db41070cf 100644 --- a/drivers/staging/agnx/xmit.c +++ b/drivers/staging/agnx/xmit.c @@ -384,7 +384,8 @@ void handle_rx_irq(struct agnx_priv *priv) /* dump_ieee80211_hdr((struct ieee80211_hdr *)skb->data, "RX G"); */ } else agnx_bug("Unknown packets type"); - ieee80211_rx_irqsafe(priv->hw, skb, &status); + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + ieee80211_rx_irqsafe(priv->hw, skb); rx_desc_reinit(priv, i); } while (priv->rx.idx++); diff --git a/drivers/staging/stlc45xx/stlc45xx.c b/drivers/staging/stlc45xx/stlc45xx.c index cfdaac9b747..52744faedbf 100644 --- a/drivers/staging/stlc45xx/stlc45xx.c +++ b/drivers/staging/stlc45xx/stlc45xx.c @@ -1429,7 +1429,8 @@ static int stlc45xx_rx_data(struct stlc45xx *stlc, struct sk_buff *skb) stlc45xx_debug(DEBUG_RX, "rx data 0x%p %d B", skb->data, skb->len); stlc45xx_dump(DEBUG_RX_CONTENT, skb->data, skb->len); - ieee80211_rx(stlc->hw, skb, &status); + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + ieee80211_rx(stlc->hw, skb); return 0; } diff --git a/drivers/staging/winbond/wb35rx.c b/drivers/staging/winbond/wb35rx.c index 3e8cf08b87e..b905e7b43a1 100644 --- a/drivers/staging/winbond/wb35rx.c +++ b/drivers/staging/winbond/wb35rx.c @@ -40,7 +40,8 @@ static void packet_came(struct ieee80211_hw *hw, char *pRxBufferAddress, int Pac rx_status.phymode = MODE_IEEE80211B; */ - ieee80211_rx_irqsafe(hw, skb, &rx_status); + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); + ieee80211_rx_irqsafe(hw, skb); } static void Wb35Rx_adjust(PDESCRIPTOR pRxDes) -- cgit v1.2.3-18-g5258 From 3bfbe80e4462c22e5dc42a00b2b394e347f4aa09 Mon Sep 17 00:00:00 2001 From: Hin-Tak Leung Date: Thu, 18 Jun 2009 03:53:26 +0100 Subject: zd1211rw: sort vid/pid pairs by numerical value In the past ids were inserted in no particular order and it has become hard to see what ids are already included or not. This patch sorts the ids by numerical value and has no functional effect. Signed-off-by: Hin-Tak Leung Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_usb.c | 73 +++++++++++++++++----------------- 1 file changed, 37 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 0e6e44689cc..07d7ab674a0 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -36,58 +36,59 @@ static struct usb_device_id usb_ids[] = { /* ZD1211 */ + { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0586, 0x3409), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x0ace, 0x1211), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x0ace, 0xa211), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x0df6, 0x9075), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x1435, 0x0711), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x0586, 0x3409), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 }, /* ZD1211B */ + { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x054c, 0x0257), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0ace, 0xb215), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x083a, 0xe503), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0ace, 0xb215), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0b05, 0x171b), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0cde, 0x001a), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0df6, 0x0036), .driver_info = DEVICE_ZD1211B }, - { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B }, /* "Driverless" devices that need ejecting */ { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, { USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER }, -- cgit v1.2.3-18-g5258 From 90e3012e94be0755a516f60f5339a2a08f4a7d0a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 18 Jun 2009 14:51:12 +0200 Subject: mac80211_hwsim: clean up the skb before passing it back We need to clean up the skb before we can copy it, this is required for proper operation since the socket it is still attached to could potentially live in a different network namespace or so. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index b1e4baec29f..1b59edc916c 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -15,6 +15,8 @@ #include #include +#include +#include #include #include #include @@ -409,6 +411,14 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, if (data->ps != PS_DISABLED) hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); + /* release the skb's source info */ + skb_orphan(skb); + dst_release(skb->dst); + skb->dst = NULL; + skb->mark = 0; + secpath_reset(skb); + nf_reset(skb); + /* Copy skb to all enabled radios that are on the current frequency */ spin_lock(&hwsim_radio_lock); list_for_each_entry(data2, &hwsim_radios, list) { -- cgit v1.2.3-18-g5258 From a2d1a42a4b44c97fb83c5bf53af8cd6ab4c6c110 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:18 +0100 Subject: orinoco: Move firmware capability determination into hw.c This is part of refactorring the initialisation code so that we can load the firmware before registerring with netdev. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/hw.c | 216 +++++++++++++++++++++++++++++++++++ drivers/net/wireless/orinoco/hw.h | 1 + drivers/net/wireless/orinoco/main.c | 218 +----------------------------------- 3 files changed, 219 insertions(+), 216 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 632fac86a30..209c6bef0cd 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -13,6 +13,8 @@ #include "hw.h" +#define SYMBOL_MAX_VER_LEN (14) + /********************************************************************/ /* Data tables */ /********************************************************************/ @@ -36,6 +38,220 @@ static const struct { }; #define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table) +/* Firmware version encoding */ +struct comp_id { + u16 id, variant, major, minor; +} __attribute__ ((packed)); + +static inline fwtype_t determine_firmware_type(struct comp_id *nic_id) +{ + if (nic_id->id < 0x8000) + return FIRMWARE_TYPE_AGERE; + else if (nic_id->id == 0x8000 && nic_id->major == 0) + return FIRMWARE_TYPE_SYMBOL; + else + return FIRMWARE_TYPE_INTERSIL; +} + +/* Set priv->firmware type, determine firmware properties */ +int determine_fw_capabilities(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + hermes_t *hw = &priv->hw; + int err; + struct comp_id nic_id, sta_id; + unsigned int firmver; + char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2))); + + /* Get the hardware version */ + err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id); + if (err) { + printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n", + dev->name, err); + return err; + } + + le16_to_cpus(&nic_id.id); + le16_to_cpus(&nic_id.variant); + le16_to_cpus(&nic_id.major); + le16_to_cpus(&nic_id.minor); + printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n", + dev->name, nic_id.id, nic_id.variant, + nic_id.major, nic_id.minor); + + priv->firmware_type = determine_firmware_type(&nic_id); + + /* Get the firmware version */ + err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id); + if (err) { + printk(KERN_ERR "%s: Cannot read station identity: error %d\n", + dev->name, err); + return err; + } + + le16_to_cpus(&sta_id.id); + le16_to_cpus(&sta_id.variant); + le16_to_cpus(&sta_id.major); + le16_to_cpus(&sta_id.minor); + printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n", + dev->name, sta_id.id, sta_id.variant, + sta_id.major, sta_id.minor); + + switch (sta_id.id) { + case 0x15: + printk(KERN_ERR "%s: Primary firmware is active\n", + dev->name); + return -ENODEV; + case 0x14b: + printk(KERN_ERR "%s: Tertiary firmware is active\n", + dev->name); + return -ENODEV; + case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */ + case 0x21: /* Symbol Spectrum24 Trilogy */ + break; + default: + printk(KERN_NOTICE "%s: Unknown station ID, please report\n", + dev->name); + break; + } + + /* Default capabilities */ + priv->has_sensitivity = 1; + priv->has_mwo = 0; + priv->has_preamble = 0; + priv->has_port3 = 1; + priv->has_ibss = 1; + priv->has_wep = 0; + priv->has_big_wep = 0; + priv->has_alt_txcntl = 0; + priv->has_ext_scan = 0; + priv->has_wpa = 0; + priv->do_fw_download = 0; + + /* Determine capabilities from the firmware version */ + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: + /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, + ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */ + snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, + "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor); + + firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor; + + priv->has_ibss = (firmver >= 0x60006); + priv->has_wep = (firmver >= 0x40020); + priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell + Gold cards from the others? */ + priv->has_mwo = (firmver >= 0x60000); + priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ + priv->ibss_port = 1; + priv->has_hostscan = (firmver >= 0x8000a); + priv->do_fw_download = 1; + priv->broken_monitor = (firmver >= 0x80000); + priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */ + priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */ + priv->has_wpa = (firmver >= 0x9002a); + /* Tested with Agere firmware : + * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II + * Tested CableTron firmware : 4.32 => Anton */ + break; + case FIRMWARE_TYPE_SYMBOL: + /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ + /* Intel MAC : 00:02:B3:* */ + /* 3Com MAC : 00:50:DA:* */ + memset(tmp, 0, sizeof(tmp)); + /* Get the Symbol firmware version */ + err = hermes_read_ltv(hw, USER_BAP, + HERMES_RID_SECONDARYVERSION_SYMBOL, + SYMBOL_MAX_VER_LEN, NULL, &tmp); + if (err) { + printk(KERN_WARNING + "%s: Error %d reading Symbol firmware info. " + "Wildly guessing capabilities...\n", + dev->name, err); + firmver = 0; + tmp[0] = '\0'; + } else { + /* The firmware revision is a string, the format is + * something like : "V2.20-01". + * Quick and dirty parsing... - Jean II + */ + firmver = ((tmp[1] - '0') << 16) + | ((tmp[3] - '0') << 12) + | ((tmp[4] - '0') << 8) + | ((tmp[6] - '0') << 4) + | (tmp[7] - '0'); + + tmp[SYMBOL_MAX_VER_LEN] = '\0'; + } + + snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, + "Symbol %s", tmp); + + priv->has_ibss = (firmver >= 0x20000); + priv->has_wep = (firmver >= 0x15012); + priv->has_big_wep = (firmver >= 0x20000); + priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) || + (firmver >= 0x29000 && firmver < 0x30000) || + firmver >= 0x31000; + priv->has_preamble = (firmver >= 0x20000); + priv->ibss_port = 4; + + /* Symbol firmware is found on various cards, but + * there has been no attempt to check firmware + * download on non-spectrum_cs based cards. + * + * Given that the Agere firmware download works + * differently, we should avoid doing a firmware + * download with the Symbol algorithm on non-spectrum + * cards. + * + * For now we can identify a spectrum_cs based card + * because it has a firmware reset function. + */ + priv->do_fw_download = (priv->stop_fw != NULL); + + priv->broken_disableport = (firmver == 0x25013) || + (firmver >= 0x30000 && firmver <= 0x31000); + priv->has_hostscan = (firmver >= 0x31001) || + (firmver >= 0x29057 && firmver < 0x30000); + /* Tested with Intel firmware : 0x20015 => Jean II */ + /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */ + break; + case FIRMWARE_TYPE_INTERSIL: + /* D-Link, Linksys, Adtron, ZoomAir, and many others... + * Samsung, Compaq 100/200 and Proxim are slightly + * different and less well tested */ + /* D-Link MAC : 00:40:05:* */ + /* Addtron MAC : 00:90:D1:* */ + snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, + "Intersil %d.%d.%d", sta_id.major, sta_id.minor, + sta_id.variant); + + firmver = ((unsigned long)sta_id.major << 16) | + ((unsigned long)sta_id.minor << 8) | sta_id.variant; + + priv->has_ibss = (firmver >= 0x000700); /* FIXME */ + priv->has_big_wep = priv->has_wep = (firmver >= 0x000800); + priv->has_pm = (firmver >= 0x000700); + priv->has_hostscan = (firmver >= 0x010301); + + if (firmver >= 0x000800) + priv->ibss_port = 0; + else { + printk(KERN_NOTICE "%s: Intersil firmware earlier " + "than v0.8.x - several features not supported\n", + dev->name); + priv->ibss_port = 1; + } + break; + } + printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name, + priv->fw_name); + + return 0; +} + int orinoco_get_bitratemode(int bitrate, int automatic) { int ratemode = -1; diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index dc3f23a9c1c..f7845b855f7 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h @@ -23,6 +23,7 @@ struct orinoco_private; struct dev_addr_list; +int determine_fw_capabilities(struct orinoco_private *priv); int orinoco_get_bitratemode(int bitrate, int automatic); void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic); diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 345593c4acc..33326d6ef81 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -142,7 +142,6 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; #define ORINOCO_MIN_MTU 256 #define ORINOCO_MAX_MTU (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD) -#define SYMBOL_MAX_VER_LEN (14) #define MAX_IRQLOOPS_PER_IRQ 10 #define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of * how many events the @@ -2096,219 +2095,6 @@ static void orinoco_unregister_pm_notifier(struct orinoco_private *priv) /* Initialization */ /********************************************************************/ -struct comp_id { - u16 id, variant, major, minor; -} __attribute__ ((packed)); - -static inline fwtype_t determine_firmware_type(struct comp_id *nic_id) -{ - if (nic_id->id < 0x8000) - return FIRMWARE_TYPE_AGERE; - else if (nic_id->id == 0x8000 && nic_id->major == 0) - return FIRMWARE_TYPE_SYMBOL; - else - return FIRMWARE_TYPE_INTERSIL; -} - -/* Set priv->firmware type, determine firmware properties */ -static int determine_firmware(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - hermes_t *hw = &priv->hw; - int err; - struct comp_id nic_id, sta_id; - unsigned int firmver; - char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2))); - - /* Get the hardware version */ - err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id); - if (err) { - printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n", - dev->name, err); - return err; - } - - le16_to_cpus(&nic_id.id); - le16_to_cpus(&nic_id.variant); - le16_to_cpus(&nic_id.major); - le16_to_cpus(&nic_id.minor); - printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n", - dev->name, nic_id.id, nic_id.variant, - nic_id.major, nic_id.minor); - - priv->firmware_type = determine_firmware_type(&nic_id); - - /* Get the firmware version */ - err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id); - if (err) { - printk(KERN_ERR "%s: Cannot read station identity: error %d\n", - dev->name, err); - return err; - } - - le16_to_cpus(&sta_id.id); - le16_to_cpus(&sta_id.variant); - le16_to_cpus(&sta_id.major); - le16_to_cpus(&sta_id.minor); - printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n", - dev->name, sta_id.id, sta_id.variant, - sta_id.major, sta_id.minor); - - switch (sta_id.id) { - case 0x15: - printk(KERN_ERR "%s: Primary firmware is active\n", - dev->name); - return -ENODEV; - case 0x14b: - printk(KERN_ERR "%s: Tertiary firmware is active\n", - dev->name); - return -ENODEV; - case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */ - case 0x21: /* Symbol Spectrum24 Trilogy */ - break; - default: - printk(KERN_NOTICE "%s: Unknown station ID, please report\n", - dev->name); - break; - } - - /* Default capabilities */ - priv->has_sensitivity = 1; - priv->has_mwo = 0; - priv->has_preamble = 0; - priv->has_port3 = 1; - priv->has_ibss = 1; - priv->has_wep = 0; - priv->has_big_wep = 0; - priv->has_alt_txcntl = 0; - priv->has_ext_scan = 0; - priv->has_wpa = 0; - priv->do_fw_download = 0; - - /* Determine capabilities from the firmware version */ - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, - ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */ - snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, - "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor); - - firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor; - - priv->has_ibss = (firmver >= 0x60006); - priv->has_wep = (firmver >= 0x40020); - priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell - Gold cards from the others? */ - priv->has_mwo = (firmver >= 0x60000); - priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ - priv->ibss_port = 1; - priv->has_hostscan = (firmver >= 0x8000a); - priv->do_fw_download = 1; - priv->broken_monitor = (firmver >= 0x80000); - priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */ - priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */ - priv->has_wpa = (firmver >= 0x9002a); - /* Tested with Agere firmware : - * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II - * Tested CableTron firmware : 4.32 => Anton */ - break; - case FIRMWARE_TYPE_SYMBOL: - /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ - /* Intel MAC : 00:02:B3:* */ - /* 3Com MAC : 00:50:DA:* */ - memset(tmp, 0, sizeof(tmp)); - /* Get the Symbol firmware version */ - err = hermes_read_ltv(hw, USER_BAP, - HERMES_RID_SECONDARYVERSION_SYMBOL, - SYMBOL_MAX_VER_LEN, NULL, &tmp); - if (err) { - printk(KERN_WARNING - "%s: Error %d reading Symbol firmware info. " - "Wildly guessing capabilities...\n", - dev->name, err); - firmver = 0; - tmp[0] = '\0'; - } else { - /* The firmware revision is a string, the format is - * something like : "V2.20-01". - * Quick and dirty parsing... - Jean II - */ - firmver = ((tmp[1] - '0') << 16) - | ((tmp[3] - '0') << 12) - | ((tmp[4] - '0') << 8) - | ((tmp[6] - '0') << 4) - | (tmp[7] - '0'); - - tmp[SYMBOL_MAX_VER_LEN] = '\0'; - } - - snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, - "Symbol %s", tmp); - - priv->has_ibss = (firmver >= 0x20000); - priv->has_wep = (firmver >= 0x15012); - priv->has_big_wep = (firmver >= 0x20000); - priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) || - (firmver >= 0x29000 && firmver < 0x30000) || - firmver >= 0x31000; - priv->has_preamble = (firmver >= 0x20000); - priv->ibss_port = 4; - - /* Symbol firmware is found on various cards, but - * there has been no attempt to check firmware - * download on non-spectrum_cs based cards. - * - * Given that the Agere firmware download works - * differently, we should avoid doing a firmware - * download with the Symbol algorithm on non-spectrum - * cards. - * - * For now we can identify a spectrum_cs based card - * because it has a firmware reset function. - */ - priv->do_fw_download = (priv->stop_fw != NULL); - - priv->broken_disableport = (firmver == 0x25013) || - (firmver >= 0x30000 && firmver <= 0x31000); - priv->has_hostscan = (firmver >= 0x31001) || - (firmver >= 0x29057 && firmver < 0x30000); - /* Tested with Intel firmware : 0x20015 => Jean II */ - /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */ - break; - case FIRMWARE_TYPE_INTERSIL: - /* D-Link, Linksys, Adtron, ZoomAir, and many others... - * Samsung, Compaq 100/200 and Proxim are slightly - * different and less well tested */ - /* D-Link MAC : 00:40:05:* */ - /* Addtron MAC : 00:90:D1:* */ - snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, - "Intersil %d.%d.%d", sta_id.major, sta_id.minor, - sta_id.variant); - - firmver = ((unsigned long)sta_id.major << 16) | - ((unsigned long)sta_id.minor << 8) | sta_id.variant; - - priv->has_ibss = (firmver >= 0x000700); /* FIXME */ - priv->has_big_wep = priv->has_wep = (firmver >= 0x000800); - priv->has_pm = (firmver >= 0x000700); - priv->has_hostscan = (firmver >= 0x010301); - - if (firmver >= 0x000800) - priv->ibss_port = 0; - else { - printk(KERN_NOTICE "%s: Intersil firmware earlier " - "than v0.8.x - several features not supported\n", - dev->name); - priv->ibss_port = 1; - } - break; - } - printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name, - priv->fw_name); - - return 0; -} - static int orinoco_init(struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); @@ -2330,7 +2116,7 @@ static int orinoco_init(struct net_device *dev) goto out; } - err = determine_firmware(dev); + err = determine_fw_capabilities(priv); if (err != 0) { printk(KERN_ERR "%s: Incompatible firmware, aborting\n", dev->name); @@ -2347,7 +2133,7 @@ static int orinoco_init(struct net_device *dev) priv->do_fw_download = 0; /* Check firmware version again */ - err = determine_firmware(dev); + err = determine_fw_capabilities(priv); if (err != 0) { printk(KERN_ERR "%s: Incompatible firmware, aborting\n", dev->name); -- cgit v1.2.3-18-g5258 From e9e3d0100eae5f254024bd59229ef1be2b719b84 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:19 +0100 Subject: orinoco: Move card reading code into hw.c This is part of refactorring the initialisation code so that we can load the firmware before registerring with netdev. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/hw.c | 112 ++++++++++++++++++++++++++++++++++++ drivers/net/wireless/orinoco/hw.h | 1 + drivers/net/wireless/orinoco/main.c | 102 +------------------------------- 3 files changed, 115 insertions(+), 100 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 209c6bef0cd..40dc25c7d0e 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -252,6 +252,118 @@ int determine_fw_capabilities(struct orinoco_private *priv) return 0; } +/* Read settings from EEPROM into our private structure. + * MAC address gets dropped into callers buffer */ +int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) +{ + struct net_device *dev = priv->ndev; + struct hermes_idstring nickbuf; + hermes_t *hw = &priv->hw; + int len; + int err; + u16 reclen; + + /* Get the MAC address */ + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, + ETH_ALEN, NULL, dev_addr); + if (err) { + printk(KERN_WARNING "%s: failed to read MAC address!\n", + dev->name); + goto out; + } + + printk(KERN_DEBUG "%s: MAC address %pM\n", + dev->name, dev_addr); + + /* Get the station name */ + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, + sizeof(nickbuf), &reclen, &nickbuf); + if (err) { + printk(KERN_ERR "%s: failed to read station name\n", + dev->name); + goto out; + } + if (nickbuf.len) + len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len)); + else + len = min(IW_ESSID_MAX_SIZE, 2 * reclen); + memcpy(priv->nick, &nickbuf.val, len); + priv->nick[len] = '\0'; + + printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick); + + /* Get allowed channels */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST, + &priv->channel_mask); + if (err) { + printk(KERN_ERR "%s: failed to read channel list!\n", + dev->name); + goto out; + } + + /* Get initial AP density */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, + &priv->ap_density); + if (err || priv->ap_density < 1 || priv->ap_density > 3) + priv->has_sensitivity = 0; + + /* Get initial RTS threshold */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, + &priv->rts_thresh); + if (err) { + printk(KERN_ERR "%s: failed to read RTS threshold!\n", + dev->name); + goto out; + } + + /* Get initial fragmentation settings */ + if (priv->has_mwo) + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFMWOROBUST_AGERE, + &priv->mwo_robust); + else + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, + &priv->frag_thresh); + if (err) { + printk(KERN_ERR "%s: failed to read fragmentation settings!\n", + dev->name); + goto out; + } + + /* Power management setup */ + if (priv->has_pm) { + priv->pm_on = 0; + priv->pm_mcast = 1; + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFMAXSLEEPDURATION, + &priv->pm_period); + if (err) { + printk(KERN_ERR "%s: failed to read power management " + "period!\n", dev->name); + goto out; + } + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFPMHOLDOVERDURATION, + &priv->pm_timeout); + if (err) { + printk(KERN_ERR "%s: failed to read power management " + "timeout!\n", dev->name); + goto out; + } + } + + /* Preamble setup */ + if (priv->has_preamble) { + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFPREAMBLE_SYMBOL, + &priv->preamble); + } + +out: + return err; +} + int orinoco_get_bitratemode(int bitrate, int automatic) { int ratemode = -1; diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index f7845b855f7..6186e44f54e 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h @@ -24,6 +24,7 @@ struct orinoco_private; struct dev_addr_list; int determine_fw_capabilities(struct orinoco_private *priv); +int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr); int orinoco_get_bitratemode(int bitrate, int automatic); void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic); diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 33326d6ef81..0fe9420c490 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -2100,9 +2100,6 @@ static int orinoco_init(struct net_device *dev) struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; - struct hermes_idstring nickbuf; - u16 reclen; - int len; /* No need to lock, the hw_unavailable flag is already set in * alloc_orinocodev() */ @@ -2166,34 +2163,9 @@ static int orinoco_init(struct net_device *dev) goto out; orinoco_bss_data_init(priv); - /* Get the MAC address */ - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, - ETH_ALEN, NULL, dev->dev_addr); - if (err) { - printk(KERN_WARNING "%s: failed to read MAC address!\n", - dev->name); - goto out; - } - - printk(KERN_DEBUG "%s: MAC address %pM\n", - dev->name, dev->dev_addr); - - /* Get the station name */ - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, - sizeof(nickbuf), &reclen, &nickbuf); - if (err) { - printk(KERN_ERR "%s: failed to read station name\n", - dev->name); + err = orinoco_hw_read_card_settings(priv, dev->dev_addr); + if (err) goto out; - } - if (nickbuf.len) - len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len)); - else - len = min(IW_ESSID_MAX_SIZE, 2 * reclen); - memcpy(priv->nick, &nickbuf.val, len); - priv->nick[len] = '\0'; - - printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick); err = orinoco_allocate_fid(dev); if (err) { @@ -2202,76 +2174,6 @@ static int orinoco_init(struct net_device *dev) goto out; } - /* Get allowed channels */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST, - &priv->channel_mask); - if (err) { - printk(KERN_ERR "%s: failed to read channel list!\n", - dev->name); - goto out; - } - - /* Get initial AP density */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, - &priv->ap_density); - if (err || priv->ap_density < 1 || priv->ap_density > 3) - priv->has_sensitivity = 0; - - /* Get initial RTS threshold */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, - &priv->rts_thresh); - if (err) { - printk(KERN_ERR "%s: failed to read RTS threshold!\n", - dev->name); - goto out; - } - - /* Get initial fragmentation settings */ - if (priv->has_mwo) - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFMWOROBUST_AGERE, - &priv->mwo_robust); - else - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, - &priv->frag_thresh); - if (err) { - printk(KERN_ERR "%s: failed to read fragmentation settings!\n", - dev->name); - goto out; - } - - /* Power management setup */ - if (priv->has_pm) { - priv->pm_on = 0; - priv->pm_mcast = 1; - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFMAXSLEEPDURATION, - &priv->pm_period); - if (err) { - printk(KERN_ERR "%s: failed to read power management period!\n", - dev->name); - goto out; - } - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMHOLDOVERDURATION, - &priv->pm_timeout); - if (err) { - printk(KERN_ERR "%s: failed to read power management timeout!\n", - dev->name); - goto out; - } - } - - /* Preamble setup */ - if (priv->has_preamble) { - err = hermes_read_wordrec(hw, USER_BAP, - HERMES_RID_CNFPREAMBLE_SYMBOL, - &priv->preamble); - if (err) - goto out; - } - /* Set up the default configuration */ priv->iw_mode = IW_MODE_INFRA; /* By default use IEEE/IBSS ad-hoc mode if we have it */ -- cgit v1.2.3-18-g5258 From 42a51b933034bbed93fa54009c96a482044e5b43 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:20 +0100 Subject: orinoco: Move FID allocation to hw.c This is part of refactorring the initialisation code so that we can load the firmware before registerring with netdev. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/hw.c | 23 +++++++++++++++++++++++ drivers/net/wireless/orinoco/hw.h | 1 + drivers/net/wireless/orinoco/main.c | 25 ++----------------------- 3 files changed, 26 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 40dc25c7d0e..0f6426d54f2 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -15,6 +15,9 @@ #define SYMBOL_MAX_VER_LEN (14) +/* Symbol firmware has a bug allocating buffers larger than this */ +#define TX_NICBUF_SIZE_BUG 1585 + /********************************************************************/ /* Data tables */ /********************************************************************/ @@ -364,6 +367,26 @@ out: return err; } +int orinoco_hw_allocate_fid(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + struct hermes *hw = &priv->hw; + int err; + + err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); + if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) { + /* Try workaround for old Symbol firmware bug */ + priv->nicbuf_size = TX_NICBUF_SIZE_BUG; + err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); + + printk(KERN_WARNING "%s: firmware ALLOC bug detected " + "(old Symbol firmware?). Work around %s\n", + dev->name, err ? "failed!" : "ok."); + } + + return err; +} + int orinoco_get_bitratemode(int bitrate, int automatic) { int ratemode = -1; diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index 6186e44f54e..89277de9087 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h @@ -25,6 +25,7 @@ struct dev_addr_list; int determine_fw_capabilities(struct orinoco_private *priv); int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr); +int orinoco_hw_allocate_fid(struct orinoco_private *priv); int orinoco_get_bitratemode(int bitrate, int automatic); void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic); diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 0fe9420c490..58a48db692e 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -147,7 +147,6 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; * how many events the * device could * legitimately generate */ -#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */ #define DUMMY_FID 0xFFFF @@ -1574,26 +1573,6 @@ int __orinoco_down(struct net_device *dev) } EXPORT_SYMBOL(__orinoco_down); -static int orinoco_allocate_fid(struct net_device *dev) -{ - struct orinoco_private *priv = netdev_priv(dev); - struct hermes *hw = &priv->hw; - int err; - - err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); - if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) { - /* Try workaround for old Symbol firmware bug */ - priv->nicbuf_size = TX_NICBUF_SIZE_BUG; - err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); - - printk(KERN_WARNING "%s: firmware ALLOC bug detected " - "(old Symbol firmware?). Work around %s\n", - dev->name, err ? "failed!" : "ok."); - } - - return err; -} - int orinoco_reinit_firmware(struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); @@ -1607,7 +1586,7 @@ int orinoco_reinit_firmware(struct net_device *dev) priv->do_fw_download = 0; } if (!err) - err = orinoco_allocate_fid(dev); + err = orinoco_hw_allocate_fid(priv); return err; } @@ -2167,7 +2146,7 @@ static int orinoco_init(struct net_device *dev) if (err) goto out; - err = orinoco_allocate_fid(dev); + err = orinoco_hw_allocate_fid(priv); if (err) { printk(KERN_ERR "%s: failed to allocate NIC buffer!\n", dev->name); -- cgit v1.2.3-18-g5258 From a3f47b9c2ada45ffacc8f2b54507221a1ba8eb10 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:21 +0100 Subject: orinoco: use dev_err in early initialisation routines This allows us to use determine_fw_capabilities, orinoco_hw_read_card_setting and orinoco_hw_allocate_fid prior to netdev registration. Since dev_dbg only prints if DEBUG is defined (or dynamic debug is enabled), move a couple of the more useful prints up to info. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/hw.c | 92 ++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 0f6426d54f2..4a26d68083f 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -3,6 +3,7 @@ * See copyright notice in main.c */ #include +#include #include #include #include @@ -56,10 +57,13 @@ static inline fwtype_t determine_firmware_type(struct comp_id *nic_id) return FIRMWARE_TYPE_INTERSIL; } -/* Set priv->firmware type, determine firmware properties */ +/* Set priv->firmware type, determine firmware properties + * This function can be called before we have registerred with netdev, + * so all errors go out with dev_* rather than printk + */ int determine_fw_capabilities(struct orinoco_private *priv) { - struct net_device *dev = priv->ndev; + struct device *dev = priv->dev; hermes_t *hw = &priv->hw; int err; struct comp_id nic_id, sta_id; @@ -69,8 +73,8 @@ int determine_fw_capabilities(struct orinoco_private *priv) /* Get the hardware version */ err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id); if (err) { - printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n", - dev->name, err); + dev_err(dev, "Cannot read hardware identity: error %d\n", + err); return err; } @@ -78,17 +82,16 @@ int determine_fw_capabilities(struct orinoco_private *priv) le16_to_cpus(&nic_id.variant); le16_to_cpus(&nic_id.major); le16_to_cpus(&nic_id.minor); - printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n", - dev->name, nic_id.id, nic_id.variant, - nic_id.major, nic_id.minor); + dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n", + nic_id.id, nic_id.variant, nic_id.major, nic_id.minor); priv->firmware_type = determine_firmware_type(&nic_id); /* Get the firmware version */ err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id); if (err) { - printk(KERN_ERR "%s: Cannot read station identity: error %d\n", - dev->name, err); + dev_err(dev, "Cannot read station identity: error %d\n", + err); return err; } @@ -96,25 +99,21 @@ int determine_fw_capabilities(struct orinoco_private *priv) le16_to_cpus(&sta_id.variant); le16_to_cpus(&sta_id.major); le16_to_cpus(&sta_id.minor); - printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n", - dev->name, sta_id.id, sta_id.variant, - sta_id.major, sta_id.minor); + dev_info(dev, "Station identity %04x:%04x:%04x:%04x\n", + sta_id.id, sta_id.variant, sta_id.major, sta_id.minor); switch (sta_id.id) { case 0x15: - printk(KERN_ERR "%s: Primary firmware is active\n", - dev->name); + dev_err(dev, "Primary firmware is active\n"); return -ENODEV; case 0x14b: - printk(KERN_ERR "%s: Tertiary firmware is active\n", - dev->name); + dev_err(dev, "Tertiary firmware is active\n"); return -ENODEV; case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */ case 0x21: /* Symbol Spectrum24 Trilogy */ break; default: - printk(KERN_NOTICE "%s: Unknown station ID, please report\n", - dev->name); + dev_notice(dev, "Unknown station ID, please report\n"); break; } @@ -168,10 +167,8 @@ int determine_fw_capabilities(struct orinoco_private *priv) HERMES_RID_SECONDARYVERSION_SYMBOL, SYMBOL_MAX_VER_LEN, NULL, &tmp); if (err) { - printk(KERN_WARNING - "%s: Error %d reading Symbol firmware info. " - "Wildly guessing capabilities...\n", - dev->name, err); + dev_warn(dev, "Error %d reading Symbol firmware info. " + "Wildly guessing capabilities...\n", err); firmver = 0; tmp[0] = '\0'; } else { @@ -242,24 +239,24 @@ int determine_fw_capabilities(struct orinoco_private *priv) if (firmver >= 0x000800) priv->ibss_port = 0; else { - printk(KERN_NOTICE "%s: Intersil firmware earlier " - "than v0.8.x - several features not supported\n", - dev->name); + dev_notice(dev, "Intersil firmware earlier than v0.8.x" + " - several features not supported\n"); priv->ibss_port = 1; } break; } - printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name, - priv->fw_name); + dev_info(dev, "Firmware determined as %s\n", priv->fw_name); return 0; } /* Read settings from EEPROM into our private structure. - * MAC address gets dropped into callers buffer */ + * MAC address gets dropped into callers buffer + * Can be called before netdev registration. + */ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) { - struct net_device *dev = priv->ndev; + struct device *dev = priv->dev; struct hermes_idstring nickbuf; hermes_t *hw = &priv->hw; int len; @@ -270,20 +267,17 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, ETH_ALEN, NULL, dev_addr); if (err) { - printk(KERN_WARNING "%s: failed to read MAC address!\n", - dev->name); + dev_warn(dev, "Failed to read MAC address!\n"); goto out; } - printk(KERN_DEBUG "%s: MAC address %pM\n", - dev->name, dev_addr); + dev_dbg(dev, "MAC address %pM\n", dev_addr); /* Get the station name */ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, sizeof(nickbuf), &reclen, &nickbuf); if (err) { - printk(KERN_ERR "%s: failed to read station name\n", - dev->name); + dev_err(dev, "failed to read station name\n"); goto out; } if (nickbuf.len) @@ -293,14 +287,13 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) memcpy(priv->nick, &nickbuf.val, len); priv->nick[len] = '\0'; - printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick); + dev_dbg(dev, "Station name \"%s\"\n", priv->nick); /* Get allowed channels */ err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST, &priv->channel_mask); if (err) { - printk(KERN_ERR "%s: failed to read channel list!\n", - dev->name); + dev_err(dev, "Failed to read channel list!\n"); goto out; } @@ -314,8 +307,7 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, &priv->rts_thresh); if (err) { - printk(KERN_ERR "%s: failed to read RTS threshold!\n", - dev->name); + dev_err(dev, "Failed to read RTS threshold!\n"); goto out; } @@ -329,8 +321,7 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, &priv->frag_thresh); if (err) { - printk(KERN_ERR "%s: failed to read fragmentation settings!\n", - dev->name); + dev_err(dev, "Failed to read fragmentation settings!\n"); goto out; } @@ -342,16 +333,16 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr) HERMES_RID_CNFMAXSLEEPDURATION, &priv->pm_period); if (err) { - printk(KERN_ERR "%s: failed to read power management " - "period!\n", dev->name); + dev_err(dev, "Failed to read power management " + "period!\n"); goto out; } err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMHOLDOVERDURATION, &priv->pm_timeout); if (err) { - printk(KERN_ERR "%s: failed to read power management " - "timeout!\n", dev->name); + dev_err(dev, "Failed to read power management " + "timeout!\n"); goto out; } } @@ -367,9 +358,10 @@ out: return err; } +/* Can be called before netdev registration */ int orinoco_hw_allocate_fid(struct orinoco_private *priv) { - struct net_device *dev = priv->ndev; + struct device *dev = priv->dev; struct hermes *hw = &priv->hw; int err; @@ -379,9 +371,9 @@ int orinoco_hw_allocate_fid(struct orinoco_private *priv) priv->nicbuf_size = TX_NICBUF_SIZE_BUG; err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); - printk(KERN_WARNING "%s: firmware ALLOC bug detected " - "(old Symbol firmware?). Work around %s\n", - dev->name, err ? "failed!" : "ok."); + dev_warn(dev, "Firmware ALLOC bug detected " + "(old Symbol firmware?). Work around %s\n", + err ? "failed!" : "ok."); } return err; -- cgit v1.2.3-18-g5258 From 44d8dade8f12ffe5c9b7eddd0512c1548c027a4c Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:22 +0100 Subject: orinoco: firmware helpers should use dev_err and friends We should be able to call these routines before we register with netdev, so avoid printks using the netdev name. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/fw.c | 41 ++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c index 1084b43e04b..1257250a1e2 100644 --- a/drivers/net/wireless/orinoco/fw.c +++ b/drivers/net/wireless/orinoco/fw.c @@ -4,6 +4,7 @@ */ #include #include +#include #include "hermes.h" #include "hermes_dld.h" @@ -99,7 +100,7 @@ orinoco_dl_firmware(struct orinoco_private *priv, const void *end; const char *firmware; const char *fw_err; - struct net_device *dev = priv->ndev; + struct device *dev = priv->dev; int err = 0; pda = kzalloc(fw->pda_size, GFP_KERNEL); @@ -111,12 +112,11 @@ orinoco_dl_firmware(struct orinoco_private *priv, else firmware = fw->sta_fw; - printk(KERN_DEBUG "%s: Attempting to download firmware %s\n", - dev->name, firmware); + dev_dbg(dev, "Attempting to download firmware %s\n", firmware); /* Read current plug data */ err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0); - printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err); + dev_dbg(dev, "Read PDA returned %d\n", err); if (err) goto free; @@ -124,8 +124,7 @@ orinoco_dl_firmware(struct orinoco_private *priv, err = request_firmware(&fw_entry, firmware, priv->dev); if (err) { - printk(KERN_ERR "%s: Cannot find firmware %s\n", - dev->name, firmware); + dev_err(dev, "Cannot find firmware %s\n", firmware); err = -ENOENT; goto free; } @@ -136,16 +135,15 @@ orinoco_dl_firmware(struct orinoco_private *priv, fw_err = validate_fw(hdr, fw_entry->size); if (fw_err) { - printk(KERN_WARNING "%s: Invalid firmware image detected (%s). " - "Aborting download\n", - dev->name, fw_err); + dev_warn(dev, "Invalid firmware image detected (%s). " + "Aborting download\n", fw_err); err = -EINVAL; goto abort; } /* Enable aux port to allow programming */ err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point)); - printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err); + dev_dbg(dev, "Program init returned %d\n", err); if (err != 0) goto abort; @@ -156,7 +154,7 @@ orinoco_dl_firmware(struct orinoco_private *priv, end = fw_entry->data + fw_entry->size; err = hermes_program(hw, first_block, end); - printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err); + dev_dbg(dev, "Program returned %d\n", err); if (err != 0) goto abort; @@ -167,19 +165,18 @@ orinoco_dl_firmware(struct orinoco_private *priv, err = hermes_apply_pda_with_defaults(hw, first_block, end, pda, &pda[fw->pda_size / sizeof(*pda)]); - printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err); + dev_dbg(dev, "Apply PDA returned %d\n", err); if (err) goto abort; /* Tell card we've finished */ err = hermesi_program_end(hw); - printk(KERN_DEBUG "%s: Program end returned %d\n", dev->name, err); + dev_dbg(dev, "Program end returned %d\n", err); if (err != 0) goto abort; /* Check if we're running */ - printk(KERN_DEBUG "%s: hermes_present returned %d\n", - dev->name, hermes_present(hw)); + dev_dbg(dev, "hermes_present returned %d\n", hermes_present(hw)); abort: /* If we requested the firmware, release it. */ @@ -282,14 +279,13 @@ static int symbol_dl_firmware(struct orinoco_private *priv, const struct fw_info *fw) { - struct net_device *dev = priv->ndev; + struct device *dev = priv->dev; int ret; const struct firmware *fw_entry; if (!orinoco_cached_fw_get(priv, true)) { if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) { - printk(KERN_ERR "%s: Cannot find firmware: %s\n", - dev->name, fw->pri_fw); + dev_err(dev, "Cannot find firmware: %s\n", fw->pri_fw); return -ENOENT; } } else @@ -302,15 +298,13 @@ symbol_dl_firmware(struct orinoco_private *priv, if (!orinoco_cached_fw_get(priv, true)) release_firmware(fw_entry); if (ret) { - printk(KERN_ERR "%s: Primary firmware download failed\n", - dev->name); + dev_err(dev, "Primary firmware download failed\n"); return ret; } if (!orinoco_cached_fw_get(priv, false)) { if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) { - printk(KERN_ERR "%s: Cannot find firmware: %s\n", - dev->name, fw->sta_fw); + dev_err(dev, "Cannot find firmware: %s\n", fw->sta_fw); return -ENOENT; } } else @@ -322,8 +316,7 @@ symbol_dl_firmware(struct orinoco_private *priv, if (!orinoco_cached_fw_get(priv, false)) release_firmware(fw_entry); if (ret) { - printk(KERN_ERR "%s: Secondary firmware download failed\n", - dev->name); + dev_err(dev, "Secondary firmware download failed\n"); } return ret; -- cgit v1.2.3-18-g5258 From a2608362b22ade22ef5472a8c9b82687d86f976f Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:23 +0100 Subject: orinoco: Replace net_device with orinoco_private in driver interfaces Move away from using net_device as the main structure in orinoco function calls. Use orinoco_private instead. This makes more sense when we move to cfg80211, and we get wiphys as well. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/airport.c | 36 +++++++++++------------ drivers/net/wireless/orinoco/main.c | 31 ++++++++++---------- drivers/net/wireless/orinoco/orinoco.h | 10 +++---- drivers/net/wireless/orinoco/orinoco_cs.c | 39 ++++++++++++------------- drivers/net/wireless/orinoco/orinoco_nortel.c | 24 ++++++++-------- drivers/net/wireless/orinoco/orinoco_pci.c | 24 ++++++++-------- drivers/net/wireless/orinoco/orinoco_pci.h | 18 ++++++------ drivers/net/wireless/orinoco/orinoco_plx.c | 24 ++++++++-------- drivers/net/wireless/orinoco/orinoco_tmd.c | 24 ++++++++-------- drivers/net/wireless/orinoco/spectrum_cs.c | 41 +++++++++++++-------------- 10 files changed, 132 insertions(+), 139 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c index 8c4065f1b0d..6559aee09e3 100644 --- a/drivers/net/wireless/orinoco/airport.c +++ b/drivers/net/wireless/orinoco/airport.c @@ -34,8 +34,8 @@ struct airport { static int airport_suspend(struct macio_dev *mdev, pm_message_t state) { - struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); + struct net_device *dev = priv->ndev; unsigned long flags; int err; @@ -48,7 +48,7 @@ airport_suspend(struct macio_dev *mdev, pm_message_t state) return 0; } - err = __orinoco_down(dev); + err = __orinoco_down(priv); if (err) printk(KERN_WARNING "%s: PBOOK_SLEEP_NOW: Error %d downing interface\n", dev->name, err); @@ -69,8 +69,8 @@ airport_suspend(struct macio_dev *mdev, pm_message_t state) static int airport_resume(struct macio_dev *mdev) { - struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); + struct net_device *dev = priv->ndev; unsigned long flags; int err; @@ -82,7 +82,7 @@ airport_resume(struct macio_dev *mdev) enable_irq(dev->irq); - err = orinoco_reinit_firmware(dev); + err = orinoco_reinit_firmware(priv); if (err) { printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n", dev->name, err); @@ -96,7 +96,7 @@ airport_resume(struct macio_dev *mdev) priv->hw_unavailable--; if (priv->open && (!priv->hw_unavailable)) { - err = __orinoco_up(dev); + err = __orinoco_up(priv); if (err) printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n", dev->name, err); @@ -111,8 +111,8 @@ airport_resume(struct macio_dev *mdev) static int airport_detach(struct macio_dev *mdev) { - struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); + struct net_device *dev = priv->ndev; struct airport *card = priv->card; if (card->ndev_registered) @@ -120,7 +120,7 @@ airport_detach(struct macio_dev *mdev) card->ndev_registered = 0; if (card->irq_requested) - free_irq(dev->irq, dev); + free_irq(dev->irq, priv); card->irq_requested = 0; if (card->vaddr) @@ -134,7 +134,7 @@ airport_detach(struct macio_dev *mdev) ssleep(1); macio_set_drvdata(mdev, NULL); - free_orinocodev(dev); + free_orinocodev(priv); return 0; } @@ -185,13 +185,13 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) } /* Allocate space for private device-specific data */ - dev = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev, - airport_hard_reset, NULL); - if (!dev) { + priv = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev, + airport_hard_reset, NULL); + if (!priv) { printk(KERN_ERR PFX "Cannot allocate network device\n"); return -ENODEV; } - priv = netdev_priv(dev); + dev = priv->ndev; card = priv->card; hw = &priv->hw; @@ -199,13 +199,13 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) if (macio_request_resource(mdev, 0, "airport")) { printk(KERN_ERR PFX "can't request IO resource !\n"); - free_orinocodev(dev); + free_orinocodev(priv); return -EBUSY; } SET_NETDEV_DEV(dev, &mdev->ofdev.dev); - macio_set_drvdata(mdev, dev); + macio_set_drvdata(mdev, priv); /* Setup interrupts & base address */ dev->irq = macio_irq(mdev, 0); @@ -228,7 +228,7 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) /* Reset it before we get the interrupt */ hermes_init(hw); - if (request_irq(dev->irq, orinoco_interrupt, 0, dev->name, dev)) { + if (request_irq(dev->irq, orinoco_interrupt, 0, dev->name, priv)) { printk(KERN_ERR PFX "Couldn't get IRQ %d\n", dev->irq); goto failed; } diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 58a48db692e..4fa8264a400 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -252,7 +252,7 @@ static int orinoco_open(struct net_device *dev) if (orinoco_lock(priv, &flags) != 0) return -EBUSY; - err = __orinoco_up(dev); + err = __orinoco_up(priv); if (!err) priv->open = 1; @@ -274,7 +274,7 @@ static int orinoco_stop(struct net_device *dev) priv->open = 0; - err = __orinoco_down(dev); + err = __orinoco_down(priv); spin_unlock_irq(&priv->lock); @@ -1511,9 +1511,9 @@ static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) /* Internal hardware control routines */ /********************************************************************/ -int __orinoco_up(struct net_device *dev) +int __orinoco_up(struct orinoco_private *priv) { - struct orinoco_private *priv = netdev_priv(dev); + struct net_device *dev = priv->ndev; struct hermes *hw = &priv->hw; int err; @@ -1541,9 +1541,9 @@ int __orinoco_up(struct net_device *dev) } EXPORT_SYMBOL(__orinoco_up); -int __orinoco_down(struct net_device *dev) +int __orinoco_down(struct orinoco_private *priv) { - struct orinoco_private *priv = netdev_priv(dev); + struct net_device *dev = priv->ndev; struct hermes *hw = &priv->hw; int err; @@ -1573,9 +1573,8 @@ int __orinoco_down(struct net_device *dev) } EXPORT_SYMBOL(__orinoco_down); -int orinoco_reinit_firmware(struct net_device *dev) +int orinoco_reinit_firmware(struct orinoco_private *priv) { - struct orinoco_private *priv = netdev_priv(dev); struct hermes *hw = &priv->hw; int err; @@ -1887,7 +1886,7 @@ void orinoco_reset(struct work_struct *work) } } - err = orinoco_reinit_firmware(dev); + err = orinoco_reinit_firmware(priv); if (err) { printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n", dev->name, err); @@ -1902,7 +1901,7 @@ void orinoco_reset(struct work_struct *work) /* priv->open or priv->hw_unavailable might have changed while * we dropped the lock */ if (priv->open && (!priv->hw_unavailable)) { - err = __orinoco_up(dev); + err = __orinoco_up(priv); if (err) { printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n", dev->name, err); @@ -1938,8 +1937,8 @@ static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw) irqreturn_t orinoco_interrupt(int irq, void *dev_id) { - struct net_device *dev = dev_id; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = dev_id; + struct net_device *dev = priv->ndev; hermes_t *hw = &priv->hw; int count = MAX_IRQLOOPS_PER_IRQ; u16 evstat, events; @@ -2192,7 +2191,7 @@ static const struct net_device_ops orinoco_netdev_ops = { .ndo_get_stats = orinoco_get_stats, }; -struct net_device +struct orinoco_private *alloc_orinocodev(int sizeof_card, struct device *device, int (*hard_reset)(struct orinoco_private *), @@ -2255,13 +2254,13 @@ struct net_device /* Register PM notifiers */ orinoco_register_pm_notifier(priv); - return dev; + return priv; } EXPORT_SYMBOL(alloc_orinocodev); -void free_orinocodev(struct net_device *dev) +void free_orinocodev(struct orinoco_private *priv) { - struct orinoco_private *priv = netdev_priv(dev); + struct net_device *dev = priv->ndev; struct orinoco_rx_data *rx_data, *temp; /* If the tasklet is scheduled when we call tasklet_kill it diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index 8e5a72cc297..b93e86cf004 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -182,14 +182,14 @@ extern int orinoco_debug; /* Exported prototypes */ /********************************************************************/ -extern struct net_device *alloc_orinocodev( +extern struct orinoco_private *alloc_orinocodev( int sizeof_card, struct device *device, int (*hard_reset)(struct orinoco_private *), int (*stop_fw)(struct orinoco_private *, int)); -extern void free_orinocodev(struct net_device *dev); -extern int __orinoco_up(struct net_device *dev); -extern int __orinoco_down(struct net_device *dev); -extern int orinoco_reinit_firmware(struct net_device *dev); +extern void free_orinocodev(struct orinoco_private *priv); +extern int __orinoco_up(struct orinoco_private *priv); +extern int __orinoco_down(struct orinoco_private *priv); +extern int orinoco_reinit_firmware(struct orinoco_private *priv); extern irqreturn_t orinoco_interrupt(int irq, void *dev_id); /********************************************************************/ diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index b381aed24d7..fa8fe5be58c 100644 --- a/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -106,26 +106,24 @@ orinoco_cs_hard_reset(struct orinoco_private *priv) static int orinoco_cs_probe(struct pcmcia_device *link) { - struct net_device *dev; struct orinoco_private *priv; struct orinoco_pccard *card; - dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link), - orinoco_cs_hard_reset, NULL); - if (!dev) + priv = alloc_orinocodev(sizeof(*card), &handle_to_dev(link), + orinoco_cs_hard_reset, NULL); + if (!priv) return -ENOMEM; - priv = netdev_priv(dev); card = priv->card; /* Link both structures together */ card->p_dev = link; - link->priv = dev; + link->priv = priv; /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = orinoco_interrupt; - link->irq.Instance = dev; + link->irq.Instance = priv; /* General socket configuration defaults can go here. In this * client, we assume very little, and rely on the CIS for @@ -146,14 +144,14 @@ orinoco_cs_probe(struct pcmcia_device *link) */ static void orinoco_cs_detach(struct pcmcia_device *link) { - struct net_device *dev = link->priv; + struct orinoco_private *priv = link->priv; if (link->dev_node) - unregister_netdev(dev); + unregister_netdev(priv->ndev); orinoco_cs_release(link); - free_orinocodev(dev); + free_orinocodev(priv); } /* orinoco_cs_detach */ /* @@ -239,9 +237,9 @@ next_entry: static int orinoco_cs_config(struct pcmcia_device *link) { - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = link->priv; struct orinoco_pccard *card = priv->card; + struct net_device *dev = priv->ndev; hermes_t *hw = &priv->hw; int last_fn, last_ret; void __iomem *mem; @@ -336,8 +334,7 @@ orinoco_cs_config(struct pcmcia_device *link) static void orinoco_cs_release(struct pcmcia_device *link) { - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = link->priv; unsigned long flags; /* We're committed to taking the device away now, so mark the @@ -353,9 +350,9 @@ orinoco_cs_release(struct pcmcia_device *link) static int orinoco_cs_suspend(struct pcmcia_device *link) { - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = link->priv; struct orinoco_pccard *card = priv->card; + struct net_device *dev = priv->ndev; int err = 0; unsigned long flags; @@ -365,7 +362,7 @@ static int orinoco_cs_suspend(struct pcmcia_device *link) if (!test_bit(0, &card->hard_reset_in_progress)) { spin_lock_irqsave(&priv->lock, flags); - err = __orinoco_down(dev); + err = __orinoco_down(priv); if (err) printk(KERN_WARNING "%s: Error %d downing interface\n", dev->name, err); @@ -381,14 +378,14 @@ static int orinoco_cs_suspend(struct pcmcia_device *link) static int orinoco_cs_resume(struct pcmcia_device *link) { - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = link->priv; struct orinoco_pccard *card = priv->card; + struct net_device *dev = priv->ndev; int err = 0; unsigned long flags; if (!test_bit(0, &card->hard_reset_in_progress)) { - err = orinoco_reinit_firmware(dev); + err = orinoco_reinit_firmware(priv); if (err) { printk(KERN_ERR "%s: Error %d re-initializing firmware\n", dev->name, err); @@ -401,7 +398,7 @@ static int orinoco_cs_resume(struct pcmcia_device *link) priv->hw_unavailable--; if (priv->open && !priv->hw_unavailable) { - err = __orinoco_up(dev); + err = __orinoco_up(priv); if (err) printk(KERN_ERR "%s: Error %d restarting card\n", dev->name, err); diff --git a/drivers/net/wireless/orinoco/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c index b01726255c6..4efd5a0d33b 100644 --- a/drivers/net/wireless/orinoco/orinoco_nortel.c +++ b/drivers/net/wireless/orinoco/orinoco_nortel.c @@ -181,15 +181,15 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, } /* Allocate network device */ - dev = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_nortel_cor_reset, NULL); - if (!dev) { + priv = alloc_orinocodev(sizeof(*card), &pdev->dev, + orinoco_nortel_cor_reset, NULL); + if (!priv) { printk(KERN_ERR PFX "Cannot allocate network device\n"); err = -ENOMEM; goto fail_alloc; } - priv = netdev_priv(dev); + dev = priv->ndev; card = priv->card; card->bridge_io = bridge_io; card->attr_io = attr_io; @@ -198,7 +198,7 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, dev); + dev->name, priv); if (err) { printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); err = -EBUSY; @@ -223,18 +223,18 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, goto fail; } - pci_set_drvdata(pdev, dev); + pci_set_drvdata(pdev, priv); printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, pci_name(pdev)); return 0; fail: - free_irq(pdev->irq, dev); + free_irq(pdev->irq, priv); fail_irq: pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); + free_orinocodev(priv); fail_alloc: pci_iounmap(pdev, hermes_io); @@ -256,17 +256,17 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, static void __devexit orinoco_nortel_remove_one(struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = pci_get_drvdata(pdev); + struct net_device *dev = priv->ndev; struct orinoco_pci_card *card = priv->card; /* Clear LEDs */ iowrite16(0, card->bridge_io + 10); unregister_netdev(dev); - free_irq(pdev->irq, dev); + free_irq(pdev->irq, priv); pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); + free_orinocodev(priv); pci_iounmap(pdev, priv->hw.iobase); pci_iounmap(pdev, card->attr_io); pci_iounmap(pdev, card->bridge_io); diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c index 78cafff1fb2..12b9c6a1bbe 100644 --- a/drivers/net/wireless/orinoco/orinoco_pci.c +++ b/drivers/net/wireless/orinoco/orinoco_pci.c @@ -139,22 +139,22 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, } /* Allocate network device */ - dev = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_pci_cor_reset, NULL); - if (!dev) { + priv = alloc_orinocodev(sizeof(*card), &pdev->dev, + orinoco_pci_cor_reset, NULL); + if (!priv) { printk(KERN_ERR PFX "Cannot allocate network device\n"); err = -ENOMEM; goto fail_alloc; } - priv = netdev_priv(dev); + dev = priv->ndev; card = priv->card; SET_NETDEV_DEV(dev, &pdev->dev); hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING); err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, dev); + dev->name, priv); if (err) { printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); err = -EBUSY; @@ -173,18 +173,18 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, goto fail; } - pci_set_drvdata(pdev, dev); + pci_set_drvdata(pdev, priv); printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, pci_name(pdev)); return 0; fail: - free_irq(pdev->irq, dev); + free_irq(pdev->irq, priv); fail_irq: pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); + free_orinocodev(priv); fail_alloc: pci_iounmap(pdev, hermes_io); @@ -200,13 +200,13 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = pci_get_drvdata(pdev); + struct net_device *dev = priv->ndev; unregister_netdev(dev); - free_irq(pdev->irq, dev); + free_irq(pdev->irq, priv); pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); + free_orinocodev(priv); pci_iounmap(pdev, priv->hw.iobase); pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/net/wireless/orinoco/orinoco_pci.h b/drivers/net/wireless/orinoco/orinoco_pci.h index c655b4a3de1..22aa630027e 100644 --- a/drivers/net/wireless/orinoco/orinoco_pci.h +++ b/drivers/net/wireless/orinoco/orinoco_pci.h @@ -21,8 +21,8 @@ struct orinoco_pci_card { #ifdef CONFIG_PM static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state) { - struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = pci_get_drvdata(pdev); + struct net_device *dev = priv->ndev; unsigned long flags; int err; @@ -33,7 +33,7 @@ static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state) return err; } - err = __orinoco_down(dev); + err = __orinoco_down(priv); if (err) printk(KERN_WARNING "%s: error %d bringing interface down " "for suspend\n", dev->name, err); @@ -44,7 +44,7 @@ static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state) orinoco_unlock(priv, &flags); - free_irq(pdev->irq, dev); + free_irq(pdev->irq, priv); pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); @@ -54,8 +54,8 @@ static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state) static int orinoco_pci_resume(struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = pci_get_drvdata(pdev); + struct net_device *dev = priv->ndev; unsigned long flags; int err; @@ -69,7 +69,7 @@ static int orinoco_pci_resume(struct pci_dev *pdev) pci_restore_state(pdev); err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, dev); + dev->name, priv); if (err) { printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n", dev->name); @@ -77,7 +77,7 @@ static int orinoco_pci_resume(struct pci_dev *pdev) return -EBUSY; } - err = orinoco_reinit_firmware(dev); + err = orinoco_reinit_firmware(priv); if (err) { printk(KERN_ERR "%s: error %d re-initializing firmware " "on resume\n", dev->name, err); @@ -91,7 +91,7 @@ static int orinoco_pci_resume(struct pci_dev *pdev) priv->hw_unavailable--; if (priv->open && (!priv->hw_unavailable)) { - err = __orinoco_up(dev); + err = __orinoco_up(priv); if (err) printk(KERN_ERR "%s: Error %d restarting card on resume\n", dev->name, err); diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c index a2a4471c033..77d5668a9e4 100644 --- a/drivers/net/wireless/orinoco/orinoco_plx.c +++ b/drivers/net/wireless/orinoco/orinoco_plx.c @@ -220,15 +220,15 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, } /* Allocate network device */ - dev = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_plx_cor_reset, NULL); - if (!dev) { + priv = alloc_orinocodev(sizeof(*card), &pdev->dev, + orinoco_plx_cor_reset, NULL); + if (!priv) { printk(KERN_ERR PFX "Cannot allocate network device\n"); err = -ENOMEM; goto fail_alloc; } - priv = netdev_priv(dev); + dev = priv->ndev; card = priv->card; card->bridge_io = bridge_io; card->attr_io = attr_io; @@ -237,7 +237,7 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, dev); + dev->name, priv); if (err) { printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); err = -EBUSY; @@ -262,18 +262,18 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, goto fail; } - pci_set_drvdata(pdev, dev); + pci_set_drvdata(pdev, priv); printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, pci_name(pdev)); return 0; fail: - free_irq(pdev->irq, dev); + free_irq(pdev->irq, priv); fail_irq: pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); + free_orinocodev(priv); fail_alloc: pci_iounmap(pdev, hermes_io); @@ -295,14 +295,14 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = pci_get_drvdata(pdev); + struct net_device *dev = priv->ndev; struct orinoco_pci_card *card = priv->card; unregister_netdev(dev); - free_irq(pdev->irq, dev); + free_irq(pdev->irq, priv); pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); + free_orinocodev(priv); pci_iounmap(pdev, priv->hw.iobase); pci_iounmap(pdev, card->attr_io); pci_iounmap(pdev, card->bridge_io); diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c index cda0e6e4d7a..5f24c0332de 100644 --- a/drivers/net/wireless/orinoco/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco/orinoco_tmd.c @@ -124,15 +124,15 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, } /* Allocate network device */ - dev = alloc_orinocodev(sizeof(*card), &pdev->dev, - orinoco_tmd_cor_reset, NULL); - if (!dev) { + priv = alloc_orinocodev(sizeof(*card), &pdev->dev, + orinoco_tmd_cor_reset, NULL); + if (!priv) { printk(KERN_ERR PFX "Cannot allocate network device\n"); err = -ENOMEM; goto fail_alloc; } - priv = netdev_priv(dev); + dev = priv->ndev; card = priv->card; card->bridge_io = bridge_io; SET_NETDEV_DEV(dev, &pdev->dev); @@ -140,7 +140,7 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, dev); + dev->name, priv); if (err) { printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); err = -EBUSY; @@ -159,18 +159,18 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, goto fail; } - pci_set_drvdata(pdev, dev); + pci_set_drvdata(pdev, priv); printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, pci_name(pdev)); return 0; fail: - free_irq(pdev->irq, dev); + free_irq(pdev->irq, priv); fail_irq: pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); + free_orinocodev(priv); fail_alloc: pci_iounmap(pdev, hermes_io); @@ -189,14 +189,14 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = pci_get_drvdata(pdev); + struct net_device *dev = priv->ndev; struct orinoco_pci_card *card = priv->card; unregister_netdev(dev); - free_irq(pdev->irq, dev); + free_irq(pdev->irq, priv); pci_set_drvdata(pdev, NULL); - free_orinocodev(dev); + free_orinocodev(priv); pci_iounmap(pdev, priv->hw.iobase); pci_iounmap(pdev, card->bridge_io); pci_release_regions(pdev); diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index 38e5198e44c..ce909e40329 100644 --- a/drivers/net/wireless/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -178,27 +178,25 @@ spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle) static int spectrum_cs_probe(struct pcmcia_device *link) { - struct net_device *dev; struct orinoco_private *priv; struct orinoco_pccard *card; - dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link), - spectrum_cs_hard_reset, - spectrum_cs_stop_firmware); - if (!dev) + priv = alloc_orinocodev(sizeof(*card), &handle_to_dev(link), + spectrum_cs_hard_reset, + spectrum_cs_stop_firmware); + if (!priv) return -ENOMEM; - priv = netdev_priv(dev); card = priv->card; /* Link both structures together */ card->p_dev = link; - link->priv = dev; + link->priv = priv; /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = orinoco_interrupt; - link->irq.Instance = dev; + link->irq.Instance = priv; /* General socket configuration defaults can go here. In this * client, we assume very little, and rely on the CIS for @@ -219,14 +217,14 @@ spectrum_cs_probe(struct pcmcia_device *link) */ static void spectrum_cs_detach(struct pcmcia_device *link) { - struct net_device *dev = link->priv; + struct orinoco_private *priv = link->priv; if (link->dev_node) - unregister_netdev(dev); + unregister_netdev(priv->ndev); spectrum_cs_release(link); - free_orinocodev(dev); + free_orinocodev(priv); } /* spectrum_cs_detach */ /* @@ -306,9 +304,9 @@ next_entry: static int spectrum_cs_config(struct pcmcia_device *link) { - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = link->priv; struct orinoco_pccard *card = priv->card; + struct net_device *dev = priv->ndev; hermes_t *hw = &priv->hw; int last_fn, last_ret; void __iomem *mem; @@ -408,8 +406,7 @@ spectrum_cs_config(struct pcmcia_device *link) static void spectrum_cs_release(struct pcmcia_device *link) { - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = link->priv; unsigned long flags; /* We're committed to taking the device away now, so mark the @@ -427,15 +424,15 @@ spectrum_cs_release(struct pcmcia_device *link) static int spectrum_cs_suspend(struct pcmcia_device *link) { - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = link->priv; + struct net_device *dev = priv->ndev; unsigned long flags; int err = 0; /* Mark the device as stopped, to block IO until later */ spin_lock_irqsave(&priv->lock, flags); - err = __orinoco_down(dev); + err = __orinoco_down(priv); if (err) printk(KERN_WARNING "%s: Error %d downing interface\n", dev->name, err); @@ -451,12 +448,12 @@ spectrum_cs_suspend(struct pcmcia_device *link) static int spectrum_cs_resume(struct pcmcia_device *link) { - struct net_device *dev = link->priv; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = link->priv; + struct net_device *dev = priv->ndev; unsigned long flags; int err; - err = orinoco_reinit_firmware(dev); + err = orinoco_reinit_firmware(priv); if (err) { printk(KERN_ERR "%s: Error %d re-initializing firmware\n", dev->name, err); @@ -469,7 +466,7 @@ spectrum_cs_resume(struct pcmcia_device *link) priv->hw_unavailable--; if (priv->open && !priv->hw_unavailable) { - err = __orinoco_up(dev); + err = __orinoco_up(priv); if (err) printk(KERN_ERR "%s: Error %d restarting card\n", dev->name, err); -- cgit v1.2.3-18-g5258 From 8e638267a896e171e49fb9013f5baf96a4ede754 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:24 +0100 Subject: orinoco: initialise independently of netdev Initialise the orinoco driver before registerring with netdev, which will help when we get to cfg80211... Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/airport.c | 6 ++++ drivers/net/wireless/orinoco/main.c | 44 ++++++++++++--------------- drivers/net/wireless/orinoco/orinoco.h | 1 + drivers/net/wireless/orinoco/orinoco_cs.c | 6 ++++ drivers/net/wireless/orinoco/orinoco_nortel.c | 6 ++++ drivers/net/wireless/orinoco/orinoco_pci.c | 6 ++++ drivers/net/wireless/orinoco/orinoco_plx.c | 6 ++++ drivers/net/wireless/orinoco/orinoco_tmd.c | 6 ++++ drivers/net/wireless/orinoco/spectrum_cs.c | 6 ++++ 9 files changed, 63 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c index 6559aee09e3..9f90337344f 100644 --- a/drivers/net/wireless/orinoco/airport.c +++ b/drivers/net/wireless/orinoco/airport.c @@ -234,6 +234,12 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) } card->irq_requested = 1; + /* Initialise the main driver */ + if (orinoco_init(priv) != 0) { + printk(KERN_ERR PFX "orinoco_init() failed\n"); + goto failed; + } + /* Tell the stack we exist */ if (register_netdev(dev) != 0) { printk(KERN_ERR PFX "register_netdev() failed\n"); diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 4fa8264a400..ff869a25024 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -80,6 +80,7 @@ #include #include #include +#include #include #include #include @@ -2073,9 +2074,9 @@ static void orinoco_unregister_pm_notifier(struct orinoco_private *priv) /* Initialization */ /********************************************************************/ -static int orinoco_init(struct net_device *dev) +int orinoco_init(struct orinoco_private *priv) { - struct orinoco_private *priv = netdev_priv(dev); + struct device *dev = priv->dev; hermes_t *hw = &priv->hw; int err = 0; @@ -2086,15 +2087,14 @@ static int orinoco_init(struct net_device *dev) /* Initialize the firmware */ err = hermes_init(hw); if (err != 0) { - printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n", - dev->name, err); + dev_err(dev, "Failed to initialize firmware (err = %d)\n", + err); goto out; } err = determine_fw_capabilities(priv); if (err != 0) { - printk(KERN_ERR "%s: Incompatible firmware, aborting\n", - dev->name); + dev_err(dev, "Incompatible firmware, aborting\n"); goto out; } @@ -2110,27 +2110,23 @@ static int orinoco_init(struct net_device *dev) /* Check firmware version again */ err = determine_fw_capabilities(priv); if (err != 0) { - printk(KERN_ERR "%s: Incompatible firmware, aborting\n", - dev->name); + dev_err(dev, "Incompatible firmware, aborting\n"); goto out; } } if (priv->has_port3) - printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", - dev->name); + dev_info(dev, "Ad-hoc demo mode supported\n"); if (priv->has_ibss) - printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported\n", - dev->name); - if (priv->has_wep) { - printk(KERN_DEBUG "%s: WEP supported, %s-bit key\n", dev->name, - priv->has_big_wep ? "104" : "40"); - } + dev_info(dev, "IEEE standard IBSS ad-hoc mode supported\n"); + if (priv->has_wep) + dev_info(dev, "WEP supported, %s-bit key\n", + priv->has_big_wep ? "104" : "40"); if (priv->has_wpa) { - printk(KERN_DEBUG "%s: WPA-PSK supported\n", dev->name); + dev_info(dev, "WPA-PSK supported\n"); if (orinoco_mic_init(priv)) { - printk(KERN_ERR "%s: Failed to setup MIC crypto " - "algorithm. Disabling WPA support\n", dev->name); + dev_err(dev, "Failed to setup MIC crypto algorithm. " + "Disabling WPA support\n"); priv->has_wpa = 0; } } @@ -2141,14 +2137,14 @@ static int orinoco_init(struct net_device *dev) goto out; orinoco_bss_data_init(priv); - err = orinoco_hw_read_card_settings(priv, dev->dev_addr); + /* Netdev has not initialised, but we have allocated the buffer. */ + err = orinoco_hw_read_card_settings(priv, priv->ndev->dev_addr); if (err) goto out; err = orinoco_hw_allocate_fid(priv); if (err) { - printk(KERN_ERR "%s: failed to allocate NIC buffer!\n", - dev->name); + dev_err(dev, "Failed to allocate NIC buffer!\n"); goto out; } @@ -2174,14 +2170,14 @@ static int orinoco_init(struct net_device *dev) priv->hw_unavailable--; spin_unlock_irq(&priv->lock); - printk(KERN_DEBUG "%s: ready\n", dev->name); + dev_dbg(dev, "Ready\n"); out: return err; } +EXPORT_SYMBOL(orinoco_init); static const struct net_device_ops orinoco_netdev_ops = { - .ndo_init = orinoco_init, .ndo_open = orinoco_open, .ndo_stop = orinoco_stop, .ndo_start_xmit = orinoco_xmit, diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index b93e86cf004..2e9d33fc6b1 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -187,6 +187,7 @@ extern struct orinoco_private *alloc_orinocodev( int (*hard_reset)(struct orinoco_private *), int (*stop_fw)(struct orinoco_private *, int)); extern void free_orinocodev(struct orinoco_private *priv); +extern int orinoco_init(struct orinoco_private *priv); extern int __orinoco_up(struct orinoco_private *priv); extern int __orinoco_down(struct orinoco_private *priv); extern int orinoco_reinit_firmware(struct orinoco_private *priv); diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index fa8fe5be58c..20abf021c06 100644 --- a/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -297,6 +297,12 @@ orinoco_cs_config(struct pcmcia_device *link) dev->irq = link->irq.AssignedIRQ; card->node.major = card->node.minor = 0; + /* Initialise the main driver */ + if (orinoco_init(priv) != 0) { + printk(KERN_ERR PFX "orinoco_init() failed\n"); + goto failed; + } + SET_NETDEV_DEV(dev, &handle_to_dev(link)); /* Tell the stack we exist */ if (register_netdev(dev) != 0) { diff --git a/drivers/net/wireless/orinoco/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c index 4efd5a0d33b..45cef818b29 100644 --- a/drivers/net/wireless/orinoco/orinoco_nortel.c +++ b/drivers/net/wireless/orinoco/orinoco_nortel.c @@ -217,6 +217,12 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, goto fail; } + err = orinoco_init(priv); + if (err) { + printk(KERN_ERR PFX "orinoco_init() failed\n"); + goto fail; + } + err = register_netdev(dev); if (err) { printk(KERN_ERR PFX "Cannot register network device\n"); diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c index 12b9c6a1bbe..d0eb4ae9bd1 100644 --- a/drivers/net/wireless/orinoco/orinoco_pci.c +++ b/drivers/net/wireless/orinoco/orinoco_pci.c @@ -167,6 +167,12 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, goto fail; } + err = orinoco_init(priv); + if (err) { + printk(KERN_ERR PFX "orinoco_init() failed\n"); + goto fail; + } + err = register_netdev(dev); if (err) { printk(KERN_ERR PFX "Cannot register network device\n"); diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c index 77d5668a9e4..8f225d064a7 100644 --- a/drivers/net/wireless/orinoco/orinoco_plx.c +++ b/drivers/net/wireless/orinoco/orinoco_plx.c @@ -256,6 +256,12 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, goto fail; } + err = orinoco_init(priv); + if (err) { + printk(KERN_ERR PFX "orinoco_init() failed\n"); + goto fail; + } + err = register_netdev(dev); if (err) { printk(KERN_ERR PFX "Cannot register network device\n"); diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c index 5f24c0332de..3c04faee7ae 100644 --- a/drivers/net/wireless/orinoco/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco/orinoco_tmd.c @@ -153,6 +153,12 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, goto fail; } + err = orinoco_init(priv); + if (err) { + printk(KERN_ERR PFX "orinoco_init() failed\n"); + goto fail; + } + err = register_netdev(dev); if (err) { printk(KERN_ERR PFX "Cannot register network device\n"); diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index ce909e40329..43e1aed4e4b 100644 --- a/drivers/net/wireless/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -368,6 +368,12 @@ spectrum_cs_config(struct pcmcia_device *link) if (spectrum_cs_hard_reset(priv) != 0) goto failed; + /* Initialise the main driver */ + if (orinoco_init(priv) != 0) { + printk(KERN_ERR PFX "orinoco_init() failed\n"); + goto failed; + } + SET_NETDEV_DEV(dev, &handle_to_dev(link)); /* Tell the stack we exist */ if (register_netdev(dev) != 0) { -- cgit v1.2.3-18-g5258 From 98e5f404485d5d11b15e8351535a0e064a37647c Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:25 +0100 Subject: orinoco: Change set_tkip to use orinoco_private instead of hermes_t hw.h does not include hermes.h, and none of the other functions requires types from that file. Also hermes_t is a (discouraged) typedef so we can't add a forward declaration. Therefore change this function to use orinoco_private. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/hw.c | 5 +++-- drivers/net/wireless/orinoco/hw.h | 4 ++-- drivers/net/wireless/orinoco/wext.c | 3 +-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 4a26d68083f..eaa89d3866c 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -677,8 +677,8 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) * rsc must be 8 bytes * tsc must be 8 bytes or NULL */ -int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx, - u8 *key, u8 *rsc, u8 *tsc) +int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, + int set_tx, u8 *key, u8 *rsc, u8 *tsc) { struct { __le16 idx; @@ -688,6 +688,7 @@ int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx, u8 rx_mic[MIC_KEYLEN]; u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; } __attribute__ ((packed)) buf; + hermes_t *hw = &priv->hw; int ret; int err; int k; diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index 89277de9087..84c108cc0f5 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h @@ -35,8 +35,8 @@ int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate); int __orinoco_hw_set_wap(struct orinoco_private *priv); int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv); int __orinoco_hw_setup_enc(struct orinoco_private *priv); -int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx, - u8 *key, u8 *rsc, u8 *tsc); +int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, + int set_tx, u8 *key, u8 *rsc, u8 *tsc); int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx); int __orinoco_hw_set_multicast_list(struct orinoco_private *priv, struct dev_addr_list *mc_list, diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 3f081423439..74fdfcec9b2 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -1079,7 +1079,6 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, case IW_ENCODE_ALG_TKIP: { - hermes_t *hw = &priv->hw; u8 *tkip_iv = NULL; if (!priv->has_wpa || @@ -1094,7 +1093,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) tkip_iv = &ext->rx_seq[0]; - err = __orinoco_hw_set_tkip_key(hw, idx, + err = __orinoco_hw_set_tkip_key(priv, idx, ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, (u8 *) &priv->tkip_key[idx], tkip_iv, NULL); -- cgit v1.2.3-18-g5258 From ea60a6aaf55984a13a7150568cc103d006e86ab2 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:26 +0100 Subject: orinoco: initiate cfg80211 conversion Initialise and register a wiphy. Store the orinoco_private structure in the new wiphy, and use the net_device private area to store the wireless_dev. This results in a change to the way we navigate from a net_device to the driver private orinoco_private, which we encapsulate in the inline function ndev_priv. Most of the remaining calls to netdev_priv are thus replaced by ndev_priv. We can immediately rely on cfg80211 to handle SIOCGIWNAME, so orinoco_ioctl_getname is removed. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/Kconfig | 1 + drivers/net/wireless/orinoco/Makefile | 2 +- drivers/net/wireless/orinoco/cfg.c | 98 +++++++++++++++++++++++++++++ drivers/net/wireless/orinoco/cfg.h | 15 +++++ drivers/net/wireless/orinoco/main.c | 108 +++++++++++++++++++++++++------- drivers/net/wireless/orinoco/orinoco.h | 11 ++++ drivers/net/wireless/orinoco/wext.c | 110 ++++++++++++++------------------- 7 files changed, 256 insertions(+), 89 deletions(-) create mode 100644 drivers/net/wireless/orinoco/cfg.c create mode 100644 drivers/net/wireless/orinoco/cfg.h (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig index 44411eb4e91..83b635fd778 100644 --- a/drivers/net/wireless/orinoco/Kconfig +++ b/drivers/net/wireless/orinoco/Kconfig @@ -1,6 +1,7 @@ config HERMES tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)" depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211 + depends on CFG80211 select WIRELESS_EXT select FW_LOADER select CRYPTO diff --git a/drivers/net/wireless/orinoco/Makefile b/drivers/net/wireless/orinoco/Makefile index 1fc7409d669..9abd6329bcb 100644 --- a/drivers/net/wireless/orinoco/Makefile +++ b/drivers/net/wireless/orinoco/Makefile @@ -1,7 +1,7 @@ # # Makefile for the orinoco wireless device drivers. # -orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o +orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o cfg.o obj-$(CONFIG_HERMES) += orinoco.o obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c new file mode 100644 index 00000000000..9a616ddac09 --- /dev/null +++ b/drivers/net/wireless/orinoco/cfg.c @@ -0,0 +1,98 @@ +/* cfg80211 support + * + * See copyright notice in main.c + */ +#include +#include +#include "hw.h" +#include "main.h" +#include "orinoco.h" + +#include "cfg.h" + +/* Supported bitrates. Must agree with hw.c */ +static struct ieee80211_rate orinoco_rates[] = { + { .bitrate = 10 }, + { .bitrate = 20 }, + { .bitrate = 55 }, + { .bitrate = 110 }, +}; + +static const void * const orinoco_wiphy_privid = &orinoco_wiphy_privid; + +/* Called after orinoco_private is allocated. */ +void orinoco_wiphy_init(struct wiphy *wiphy) +{ + struct orinoco_private *priv = wiphy_priv(wiphy); + + wiphy->privid = orinoco_wiphy_privid; + + set_wiphy_dev(wiphy, priv->dev); +} + +/* Called after firmware is initialised */ +int orinoco_wiphy_register(struct wiphy *wiphy) +{ + struct orinoco_private *priv = wiphy_priv(wiphy); + int i, channels = 0; + + if (priv->firmware_type == FIRMWARE_TYPE_AGERE) + wiphy->max_scan_ssids = 1; + else + wiphy->max_scan_ssids = 0; + + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + + /* TODO: should we set if we only have demo ad-hoc? + * (priv->has_port3) + */ + if (priv->has_ibss) + wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); + + if (!priv->broken_monitor || force_monitor) + wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); + + priv->band.bitrates = orinoco_rates; + priv->band.n_bitrates = ARRAY_SIZE(orinoco_rates); + + /* Only support channels allowed by the card EEPROM */ + for (i = 0; i < NUM_CHANNELS; i++) { + if (priv->channel_mask & (1 << i)) { + priv->channels[i].center_freq = + ieee80211_dsss_chan_to_freq(i+1); + channels++; + } + } + priv->band.channels = priv->channels; + priv->band.n_channels = channels; + + wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + + i = 0; + if (priv->has_wep) { + priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP40; + i++; + + if (priv->has_big_wep) { + priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP104; + i++; + } + } + if (priv->has_wpa) { + priv->cipher_suites[i] = WLAN_CIPHER_SUITE_TKIP; + i++; + } + wiphy->cipher_suites = priv->cipher_suites; + wiphy->n_cipher_suites = i; + + wiphy->rts_threshold = priv->rts_thresh; + if (!priv->has_mwo) + wiphy->frag_threshold = priv->frag_thresh; + + return wiphy_register(wiphy); +} + +const struct cfg80211_ops orinoco_cfg_ops = { + +}; diff --git a/drivers/net/wireless/orinoco/cfg.h b/drivers/net/wireless/orinoco/cfg.h new file mode 100644 index 00000000000..3ddc96a06cd --- /dev/null +++ b/drivers/net/wireless/orinoco/cfg.h @@ -0,0 +1,15 @@ +/* cfg80211 support. + * + * See copyright notice in main.c + */ +#ifndef ORINOCO_CFG_H +#define ORINOCO_CFG_H + +#include + +extern const struct cfg80211_ops orinoco_cfg_ops; + +void orinoco_wiphy_init(struct wiphy *wiphy); +int orinoco_wiphy_register(struct wiphy *wiphy); + +#endif /* ORINOCO_CFG_H */ diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index ff869a25024..5c1cf648002 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -89,6 +89,7 @@ #include #include #include +#include #include "hermes_rid.h" #include "hermes_dld.h" @@ -97,6 +98,7 @@ #include "mic.h" #include "fw.h" #include "wext.h" +#include "cfg.h" #include "main.h" #include "orinoco.h" @@ -246,7 +248,7 @@ void set_port_type(struct orinoco_private *priv) static int orinoco_open(struct net_device *dev) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); unsigned long flags; int err; @@ -265,7 +267,7 @@ static int orinoco_open(struct net_device *dev) static int orinoco_stop(struct net_device *dev) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int err = 0; /* We mustn't use orinoco_lock() here, because we need to be @@ -284,14 +286,14 @@ static int orinoco_stop(struct net_device *dev) static struct net_device_stats *orinoco_get_stats(struct net_device *dev) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); return &priv->stats; } static void orinoco_set_multicast_list(struct net_device *dev) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); unsigned long flags; if (orinoco_lock(priv, &flags) != 0) { @@ -306,7 +308,7 @@ static void orinoco_set_multicast_list(struct net_device *dev) static int orinoco_change_mtu(struct net_device *dev, int new_mtu) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); if ((new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU)) return -EINVAL; @@ -327,7 +329,7 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu) static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct net_device_stats *stats = &priv->stats; hermes_t *hw = &priv->hw; int err = 0; @@ -517,7 +519,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); u16 fid = hermes_read_regn(hw, ALLOCFID); if (fid != priv->txfid) { @@ -532,7 +534,7 @@ static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw) static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct net_device_stats *stats = &priv->stats; stats->tx_packets++; @@ -544,7 +546,7 @@ static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw) static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct net_device_stats *stats = &priv->stats; u16 fid = hermes_read_regn(hw, TXCOMPLFID); u16 status; @@ -600,7 +602,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) static void orinoco_tx_timeout(struct net_device *dev) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct net_device_stats *stats = &priv->stats; struct hermes *hw = &priv->hw; @@ -649,7 +651,7 @@ static void orinoco_stat_gather(struct net_device *dev, struct sk_buff *skb, struct hermes_rx_descriptor *desc) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); /* Using spy support with lots of Rx packets, like in an * infrastructure (AP), will really slow down everything, because @@ -686,7 +688,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, int err; int len; struct sk_buff *skb; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct net_device_stats *stats = &priv->stats; hermes_t *hw = &priv->hw; @@ -777,7 +779,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct net_device_stats *stats = &priv->stats; struct iw_statistics *wstats = &priv->wstats; struct sk_buff *skb = NULL; @@ -901,7 +903,7 @@ static void orinoco_rx(struct net_device *dev, struct hermes_rx_descriptor *desc, struct sk_buff *skb) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct net_device_stats *stats = &priv->stats; u16 status, fc; int length; @@ -1016,7 +1018,7 @@ static void orinoco_rx(struct net_device *dev, static void orinoco_rx_isr_tasklet(unsigned long data) { struct net_device *dev = (struct net_device *) data; - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct orinoco_rx_data *rx_data, *temp; struct hermes_rx_descriptor *desc; struct sk_buff *skb; @@ -1261,7 +1263,7 @@ static void orinoco_send_wevents(struct work_struct *work) static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); u16 infofid; struct { __le16 len; @@ -1594,7 +1596,7 @@ EXPORT_SYMBOL(orinoco_reinit_firmware); int __orinoco_program_rids(struct net_device *dev) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; int err; struct hermes_idstring idbuf; @@ -1825,7 +1827,7 @@ int __orinoco_program_rids(struct net_device *dev) static void __orinoco_set_multicast_list(struct net_device *dev) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int err = 0; int promisc, mc_count; @@ -2077,6 +2079,7 @@ static void orinoco_unregister_pm_notifier(struct orinoco_private *priv) int orinoco_init(struct orinoco_private *priv) { struct device *dev = priv->dev; + struct wiphy *wiphy = priv_to_wiphy(priv); hermes_t *hw = &priv->hw; int err = 0; @@ -2137,10 +2140,10 @@ int orinoco_init(struct orinoco_private *priv) goto out; orinoco_bss_data_init(priv); - /* Netdev has not initialised, but we have allocated the buffer. */ - err = orinoco_hw_read_card_settings(priv, priv->ndev->dev_addr); + err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr); if (err) goto out; + memcpy(priv->ndev->dev_addr, wiphy->perm_addr, ETH_ALEN); err = orinoco_hw_allocate_fid(priv); if (err) { @@ -2164,6 +2167,11 @@ int orinoco_init(struct orinoco_private *priv) priv->wpa_ie_len = 0; priv->wpa_ie = NULL; + if (orinoco_wiphy_register(wiphy)) { + err = -ENODEV; + goto out; + } + /* Make the hardware available, as long as it hasn't been * removed elsewhere (e.g. by PCMCIA hot unplug) */ spin_lock_irq(&priv->lock); @@ -2187,6 +2195,31 @@ static const struct net_device_ops orinoco_netdev_ops = { .ndo_get_stats = orinoco_get_stats, }; +/* Allocate private data. + * + * This driver has a number of structures associated with it + * netdev - Net device structure for each network interface + * wiphy - structure associated with wireless phy + * wireless_dev (wdev) - structure for each wireless interface + * hw - structure for hermes chip info + * card - card specific structure for use by the card driver + * (airport, orinoco_cs) + * priv - orinoco private data + * device - generic linux device structure + * + * +---------+ +---------+ + * | wiphy | | netdev | + * | +-------+ | +-------+ + * | | priv | | | wdev | + * | | +-----+ +-+-------+ + * | | | hw | + * | +-+-----+ + * | | card | + * +-+-------+ + * + * priv has a link to netdev and device + * wdev has a link to wiphy + */ struct orinoco_private *alloc_orinocodev(int sizeof_card, struct device *device, @@ -2195,12 +2228,27 @@ struct orinoco_private { struct net_device *dev; struct orinoco_private *priv; + struct wireless_dev *wdev; + struct wiphy *wiphy; + + /* allocate wiphy + * NOTE: We only support a single virtual interface + * but this may change when monitor mode is added + */ + wiphy = wiphy_new(&orinoco_cfg_ops, + sizeof(struct orinoco_private) + sizeof_card); + if (!wiphy) + return NULL; - dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card); - if (!dev) + dev = alloc_etherdev(sizeof(struct wireless_dev)); + if (!dev) { + wiphy_free(wiphy); return NULL; - priv = netdev_priv(dev); + } + + priv = wiphy_priv(wiphy); priv->ndev = dev; + if (sizeof_card) priv->card = (void *)((unsigned long)priv + sizeof(struct orinoco_private)); @@ -2208,7 +2256,15 @@ struct orinoco_private priv->card = NULL; priv->dev = device; + orinoco_wiphy_init(wiphy); + + /* Initialise wireless_dev */ + wdev = netdev_priv(dev); + wdev->wiphy = wiphy; + wdev->iftype = NL80211_IFTYPE_STATION; + /* Setup / override net_device fields */ + dev->ieee80211_ptr = wdev; dev->netdev_ops = &orinoco_netdev_ops; dev->watchdog_timeo = HZ; /* 1 second timeout */ dev->ethtool_ops = &orinoco_ethtool_ops; @@ -2257,8 +2313,11 @@ EXPORT_SYMBOL(alloc_orinocodev); void free_orinocodev(struct orinoco_private *priv) { struct net_device *dev = priv->ndev; + struct wiphy *wiphy = priv_to_wiphy(priv); struct orinoco_rx_data *rx_data, *temp; + wiphy_unregister(wiphy); + /* If the tasklet is scheduled when we call tasklet_kill it * will run one final time. However the tasklet will only * drain priv->rx_list if the hw is still available. */ @@ -2281,13 +2340,14 @@ void free_orinocodev(struct orinoco_private *priv) orinoco_mic_free(priv); orinoco_bss_data_free(priv); free_netdev(dev); + wiphy_free(wiphy); } EXPORT_SYMBOL(free_orinocodev); static void orinoco_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1); strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1); diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index 2e9d33fc6b1..608cc5e1bd9 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -14,6 +14,7 @@ #include #include #include +#include #include "hermes.h" @@ -67,6 +68,10 @@ struct orinoco_private { int (*hard_reset)(struct orinoco_private *); int (*stop_fw)(struct orinoco_private *, int); + struct ieee80211_supported_band band; + struct ieee80211_channel channels[14]; + u32 cipher_suites[3]; + /* Synchronisation stuff */ spinlock_t lock; int hw_unavailable; @@ -216,4 +221,10 @@ static inline void orinoco_unlock(struct orinoco_private *priv, spin_unlock_irqrestore(&priv->lock, *flags); } +/*** Navigate from net_device to orinoco_private ***/ +static inline struct orinoco_private *ndev_priv(struct net_device *dev) +{ + struct wireless_dev *wdev = netdev_priv(dev); + return wdev_priv(wdev); +} #endif /* _ORINOCO_H */ diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 74fdfcec9b2..74892e1d34a 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "hermes.h" #include "hermes_rid.h" @@ -23,7 +24,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; struct iw_statistics *wstats = &priv->wstats; int err; @@ -87,31 +88,12 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) /* Wireless extensions */ /********************************************************************/ -static int orinoco_ioctl_getname(struct net_device *dev, - struct iw_request_info *info, - char *name, - char *extra) -{ - struct orinoco_private *priv = netdev_priv(dev); - int numrates; - int err; - - err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0); - - if (!err && (numrates > 2)) - strcpy(name, "IEEE 802.11b"); - else - strcpy(name, "IEEE 802.11-DS"); - - return 0; -} - static int orinoco_ioctl_setwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int err = -EINPROGRESS; /* Call commit handler */ unsigned long flags; static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -172,7 +154,7 @@ static int orinoco_ioctl_getwap(struct net_device *dev, struct sockaddr *ap_addr, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; @@ -195,7 +177,7 @@ static int orinoco_ioctl_setmode(struct net_device *dev, u32 *mode, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int err = -EINPROGRESS; /* Call commit handler */ unsigned long flags; @@ -243,7 +225,7 @@ static int orinoco_ioctl_getmode(struct net_device *dev, u32 *mode, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); *mode = priv->iw_mode; return 0; @@ -254,7 +236,7 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int err = 0; struct iw_range *range = (struct iw_range *) extra; int numrates; @@ -367,7 +349,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq, char *keybuf) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int index = (erq->flags & IW_ENCODE_INDEX) - 1; int setindex = priv->tx_key; int encode_alg = priv->encode_alg; @@ -469,7 +451,7 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq, char *keybuf) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int index = (erq->flags & IW_ENCODE_INDEX) - 1; u16 xlen = 0; unsigned long flags; @@ -508,7 +490,7 @@ static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq, char *essidbuf) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); unsigned long flags; /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it @@ -539,7 +521,7 @@ static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq, char *essidbuf) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int active; int err = 0; unsigned long flags; @@ -567,7 +549,7 @@ static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq, char *nickbuf) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); unsigned long flags; if (nrq->length > IW_ESSID_MAX_SIZE) @@ -589,7 +571,7 @@ static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq, char *nickbuf) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); unsigned long flags; if (orinoco_lock(priv, &flags) != 0) @@ -608,7 +590,7 @@ static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int chan = -1; unsigned long flags; int err = -EINPROGRESS; /* Call commit handler */ @@ -657,7 +639,7 @@ static int orinoco_ioctl_getfreq(struct net_device *dev, struct iw_freq *frq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int tmp; /* Locking done in there */ @@ -676,7 +658,7 @@ static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; u16 val; int err; @@ -705,7 +687,7 @@ static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int val = srq->value; unsigned long flags; @@ -728,7 +710,7 @@ static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int val = rrq->value; unsigned long flags; @@ -752,7 +734,7 @@ static int orinoco_ioctl_getrts(struct net_device *dev, struct iw_param *rrq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); rrq->value = priv->rts_thresh; rrq->disabled = (rrq->value == 2347); @@ -766,7 +748,7 @@ static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int err = -EINPROGRESS; /* Call commit handler */ unsigned long flags; @@ -806,7 +788,7 @@ static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; int err; u16 val; @@ -847,7 +829,7 @@ static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int ratemode; int bitrate; /* 100s of kilobits */ unsigned long flags; @@ -881,7 +863,7 @@ static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int err = 0; int bitrate, automatic; unsigned long flags; @@ -910,7 +892,7 @@ static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int err = -EINPROGRESS; /* Call commit handler */ unsigned long flags; @@ -964,7 +946,7 @@ static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; u16 enable, period, timeout, mcast; @@ -1018,7 +1000,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct iw_point *encoding = &wrqu->encoding; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; int idx, alg = ext->alg, set_key = 1; @@ -1119,7 +1101,7 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct iw_point *encoding = &wrqu->encoding; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; int idx, max_key_len; @@ -1176,7 +1158,7 @@ static int orinoco_ioctl_set_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; struct iw_param *param = &wrqu->param; unsigned long flags; @@ -1254,7 +1236,7 @@ static int orinoco_ioctl_get_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct iw_param *param = &wrqu->param; unsigned long flags; int ret = 0; @@ -1294,7 +1276,7 @@ static int orinoco_ioctl_set_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); u8 *buf; unsigned long flags; @@ -1337,7 +1319,7 @@ static int orinoco_ioctl_get_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); unsigned long flags; int err = 0; @@ -1366,7 +1348,7 @@ static int orinoco_ioctl_set_mlme(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; struct iw_mlme *mlme = (struct iw_mlme *)extra; unsigned long flags; @@ -1407,7 +1389,7 @@ static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; u16 short_limit, long_limit, lifetime; @@ -1461,7 +1443,7 @@ static int orinoco_ioctl_reset(struct net_device *dev, void *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -1486,7 +1468,7 @@ static int orinoco_ioctl_setibssport(struct net_device *dev, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int val = *((int *) extra); unsigned long flags; @@ -1507,7 +1489,7 @@ static int orinoco_ioctl_getibssport(struct net_device *dev, void *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int *val = (int *) extra; *val = priv->ibss_port; @@ -1519,7 +1501,7 @@ static int orinoco_ioctl_setport3(struct net_device *dev, void *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int val = *((int *) extra); int err = 0; unsigned long flags; @@ -1565,7 +1547,7 @@ static int orinoco_ioctl_getport3(struct net_device *dev, void *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int *val = (int *) extra; *val = priv->prefer_port3; @@ -1577,7 +1559,7 @@ static int orinoco_ioctl_setpreamble(struct net_device *dev, void *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); unsigned long flags; int val; @@ -1609,7 +1591,7 @@ static int orinoco_ioctl_getpreamble(struct net_device *dev, void *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int *val = (int *) extra; if (!priv->has_preamble) @@ -1629,7 +1611,7 @@ static int orinoco_ioctl_getrid(struct net_device *dev, struct iw_point *data, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; int rid = data->flags; u16 length; @@ -1666,7 +1648,7 @@ static int orinoco_ioctl_setscan(struct net_device *dev, struct iw_point *srq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; struct iw_scan_req *si = (struct iw_scan_req *) extra; int err = 0; @@ -1791,7 +1773,7 @@ static inline char *orinoco_translate_scan(struct net_device *dev, union hermes_scan_info *bss, unsigned long last_scanned) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); u16 capabilities; u16 channel; struct iw_event iwe; /* Temporary buffer */ @@ -2102,7 +2084,7 @@ static int orinoco_ioctl_getscan(struct net_device *dev, struct iw_point *srq, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); int err = 0; unsigned long flags; char *current_ev = extra; @@ -2180,7 +2162,7 @@ static int orinoco_ioctl_commit(struct net_device *dev, void *wrqu, char *extra) { - struct orinoco_private *priv = netdev_priv(dev); + struct orinoco_private *priv = ndev_priv(dev); struct hermes *hw = &priv->hw; unsigned long flags; int err = 0; @@ -2257,7 +2239,7 @@ static const struct iw_priv_args orinoco_privtab[] = { [IW_IOCTL_IDX(id)] = (iw_handler) func static const iw_handler orinoco_handler[] = { STD_IW_HANDLER(SIOCSIWCOMMIT, orinoco_ioctl_commit), - STD_IW_HANDLER(SIOCGIWNAME, orinoco_ioctl_getname), + STD_IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname), STD_IW_HANDLER(SIOCSIWFREQ, orinoco_ioctl_setfreq), STD_IW_HANDLER(SIOCGIWFREQ, orinoco_ioctl_getfreq), STD_IW_HANDLER(SIOCSIWMODE, orinoco_ioctl_setmode), -- cgit v1.2.3-18-g5258 From 35832c50d1d1552618f55aa5457a251df9e63b26 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:27 +0100 Subject: orinoco: make firmware download less verbose The firmware download code has been in a couple of releases, without any significant issues reported in this code. Convert to use pr_debug, so the messages can be recoverred by defining DEBUG. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/hermes_dld.c | 50 ++++++++++++++----------------- 1 file changed, 23 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c index a9ba195cdad..a3eefe109df 100644 --- a/drivers/net/wireless/orinoco/hermes_dld.c +++ b/drivers/net/wireless/orinoco/hermes_dld.c @@ -309,7 +309,7 @@ int hermes_read_pda(hermes_t *hw, /* Open auxiliary port */ ret = hermes_aux_control(hw, 1); - printk(KERN_DEBUG PFX "AUX enable returned %d\n", ret); + pr_debug(PFX "AUX enable returned %d\n", ret); if (ret) return ret; @@ -319,12 +319,12 @@ int hermes_read_pda(hermes_t *hw, /* Close aux port */ ret = hermes_aux_control(hw, 0); - printk(KERN_DEBUG PFX "AUX disable returned %d\n", ret); + pr_debug(PFX "AUX disable returned %d\n", ret); /* Check PDA length */ pda_size = le16_to_cpu(pda[0]); - printk(KERN_DEBUG PFX "Actual PDA length %d, Max allowed %d\n", - pda_size, pda_len); + pr_debug(PFX "Actual PDA length %d, Max allowed %d\n", + pda_size, pda_len); if (pda_size > pda_len) return -EINVAL; @@ -422,20 +422,19 @@ int hermesi_program_init(hermes_t *hw, u32 offset) return err; err = hermes_aux_control(hw, 1); - printk(KERN_DEBUG PFX "AUX enable returned %d\n", err); + pr_debug(PFX "AUX enable returned %d\n", err); if (err) return err; - printk(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset); + pr_debug(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset); err = hermes_doicmd_wait(hw, HERMES_PROGRAM_ENABLE_VOLATILE, offset & 0xFFFFu, offset >> 16, 0, NULL); - printk(KERN_DEBUG PFX "PROGRAM_ENABLE returned %d\n", - err); + pr_debug(PFX "PROGRAM_ENABLE returned %d\n", err); return err; } @@ -454,16 +453,16 @@ int hermesi_program_end(hermes_t *hw) rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp); - printk(KERN_DEBUG PFX "PROGRAM_DISABLE returned %d, " - "r0 0x%04x, r1 0x%04x, r2 0x%04x\n", - rc, resp.resp0, resp.resp1, resp.resp2); + pr_debug(PFX "PROGRAM_DISABLE returned %d, " + "r0 0x%04x, r1 0x%04x, r2 0x%04x\n", + rc, resp.resp0, resp.resp1, resp.resp2); if ((rc == 0) && ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD)) rc = -EIO; err = hermes_aux_control(hw, 0); - printk(KERN_DEBUG PFX "AUX disable returned %d\n", err); + pr_debug(PFX "AUX disable returned %d\n", err); /* Acknowledge any outstanding command */ hermes_write_regn(hw, EVACK, 0xFFFF); @@ -496,9 +495,8 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end) while ((blkaddr != BLOCK_END) && (((void *) blk + blklen) <= end)) { - printk(KERN_DEBUG PFX - "Programming block of length %d to address 0x%08x\n", - blklen, blkaddr); + pr_debug(PFX "Programming block of length %d " + "to address 0x%08x\n", blklen, blkaddr); #if !LIMIT_PROGRAM_SIZE /* wl_lkm driver splits this into writes of 2000 bytes */ @@ -510,10 +508,9 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end) addr = blkaddr; while (addr < (blkaddr + blklen)) { - printk(KERN_DEBUG PFX - "Programming subblock of length %d " - "to address 0x%08x. Data @ %p\n", - len, addr, &blk->data[addr - blkaddr]); + pr_debug(PFX "Programming subblock of length %d " + "to address 0x%08x. Data @ %p\n", + len, addr, &blk->data[addr - blkaddr]); hermes_aux_setaddr(hw, addr); hermes_write_bytes(hw, HERMES_AUXDATA, @@ -643,8 +640,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw, pdi = hermes_find_pdi(first_pdi, record_id, pda_end); if (pdi) - printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n", - record_id, pdi); + pr_debug(PFX "Found record 0x%04x at %p\n", + record_id, pdi); switch (record_id) { case 0x110: /* Modem REFDAC values */ @@ -654,9 +651,9 @@ int hermes_apply_pda_with_defaults(hermes_t *hw, default_pdi = NULL; if (outdoor_pdi) { pdi = outdoor_pdi; - printk(KERN_DEBUG PFX - "Using outdoor record 0x%04x at %p\n", - record_id + 1, pdi); + pr_debug(PFX + "Using outdoor record 0x%04x at %p\n", + record_id + 1, pdi); } break; case 0x5: /* HWIF Compatiblity */ @@ -684,9 +681,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw, if (!pdi && default_pdi) { /* Use default */ pdi = default_pdi; - printk(KERN_DEBUG PFX - "Using default record 0x%04x at %p\n", - record_id, pdi); + pr_debug(PFX "Using default record 0x%04x at %p\n", + record_id, pdi); } if (pdi) { -- cgit v1.2.3-18-g5258 From 5381956b780e82805247c2ec8e32c4c665309394 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:28 +0100 Subject: orinoco: move netdev interface creation to main driver With the move to cfg80211 it's nice to keep the hardware operations distinct from the interface, even though we can only support a single interface. This also means the driver resembles other cfg80211 drivers. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/airport.c | 23 +++--- drivers/net/wireless/orinoco/main.c | 111 ++++++++++++++++++-------- drivers/net/wireless/orinoco/orinoco.h | 4 + drivers/net/wireless/orinoco/orinoco_cs.c | 21 ++--- drivers/net/wireless/orinoco/orinoco_nortel.c | 14 +--- drivers/net/wireless/orinoco/orinoco_pci.c | 14 +--- drivers/net/wireless/orinoco/orinoco_plx.c | 14 +--- drivers/net/wireless/orinoco/orinoco_tmd.c | 14 +--- drivers/net/wireless/orinoco/spectrum_cs.c | 22 ++--- 9 files changed, 119 insertions(+), 118 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c index 9f90337344f..e46e0d7c36f 100644 --- a/drivers/net/wireless/orinoco/airport.c +++ b/drivers/net/wireless/orinoco/airport.c @@ -116,7 +116,7 @@ airport_detach(struct macio_dev *mdev) struct airport *card = priv->card; if (card->ndev_registered) - unregister_netdev(dev); + orinoco_if_del(priv); card->ndev_registered = 0; if (card->irq_requested) @@ -174,9 +174,9 @@ static int airport_attach(struct macio_dev *mdev, const struct of_device_id *match) { struct orinoco_private *priv; - struct net_device *dev; struct airport *card; unsigned long phys_addr; + unsigned int irq; hermes_t *hw; if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) { @@ -191,27 +191,23 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) printk(KERN_ERR PFX "Cannot allocate network device\n"); return -ENODEV; } - dev = priv->ndev; card = priv->card; hw = &priv->hw; card->mdev = mdev; - if (macio_request_resource(mdev, 0, "airport")) { + if (macio_request_resource(mdev, 0, DRIVER_NAME)) { printk(KERN_ERR PFX "can't request IO resource !\n"); free_orinocodev(priv); return -EBUSY; } - SET_NETDEV_DEV(dev, &mdev->ofdev.dev); - macio_set_drvdata(mdev, priv); /* Setup interrupts & base address */ - dev->irq = macio_irq(mdev, 0); + irq = macio_irq(mdev, 0); phys_addr = macio_resource_start(mdev, 0); /* Physical address */ printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr); - dev->base_addr = phys_addr; card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN); if (!card->vaddr) { printk(KERN_ERR PFX "ioremap() failed\n"); @@ -228,8 +224,8 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) /* Reset it before we get the interrupt */ hermes_init(hw); - if (request_irq(dev->irq, orinoco_interrupt, 0, dev->name, priv)) { - printk(KERN_ERR PFX "Couldn't get IRQ %d\n", dev->irq); + if (request_irq(irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) { + printk(KERN_ERR PFX "Couldn't get IRQ %d\n", irq); goto failed; } card->irq_requested = 1; @@ -240,12 +236,11 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) goto failed; } - /* Tell the stack we exist */ - if (register_netdev(dev) != 0) { - printk(KERN_ERR PFX "register_netdev() failed\n"); + /* Register an interface with the stack */ + if (orinoco_if_add(priv, phys_addr, irq) != 0) { + printk(KERN_ERR PFX "orinoco_if_add() failed\n"); goto failed; } - printk(KERN_DEBUG PFX "Card registered for interface %s\n", dev->name); card->ndev_registered = 1; return 0; failed: diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 5c1cf648002..361cf09d6b7 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -1017,8 +1017,8 @@ static void orinoco_rx(struct net_device *dev, static void orinoco_rx_isr_tasklet(unsigned long data) { - struct net_device *dev = (struct net_device *) data; - struct orinoco_private *priv = ndev_priv(dev); + struct orinoco_private *priv = (struct orinoco_private *) data; + struct net_device *dev = priv->ndev; struct orinoco_rx_data *rx_data, *temp; struct hermes_rx_descriptor *desc; struct sk_buff *skb; @@ -2143,7 +2143,6 @@ int orinoco_init(struct orinoco_private *priv) err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr); if (err) goto out; - memcpy(priv->ndev->dev_addr, wiphy->perm_addr, ETH_ALEN); err = orinoco_hw_allocate_fid(priv); if (err) { @@ -2226,9 +2225,7 @@ struct orinoco_private int (*hard_reset)(struct orinoco_private *), int (*stop_fw)(struct orinoco_private *, int)) { - struct net_device *dev; struct orinoco_private *priv; - struct wireless_dev *wdev; struct wiphy *wiphy; /* allocate wiphy @@ -2240,43 +2237,20 @@ struct orinoco_private if (!wiphy) return NULL; - dev = alloc_etherdev(sizeof(struct wireless_dev)); - if (!dev) { - wiphy_free(wiphy); - return NULL; - } - priv = wiphy_priv(wiphy); - priv->ndev = dev; + priv->dev = device; if (sizeof_card) priv->card = (void *)((unsigned long)priv + sizeof(struct orinoco_private)); else priv->card = NULL; - priv->dev = device; orinoco_wiphy_init(wiphy); - /* Initialise wireless_dev */ - wdev = netdev_priv(dev); - wdev->wiphy = wiphy; - wdev->iftype = NL80211_IFTYPE_STATION; - - /* Setup / override net_device fields */ - dev->ieee80211_ptr = wdev; - dev->netdev_ops = &orinoco_netdev_ops; - dev->watchdog_timeo = HZ; /* 1 second timeout */ - dev->ethtool_ops = &orinoco_ethtool_ops; - dev->wireless_handlers = &orinoco_handler_def; #ifdef WIRELESS_SPY priv->wireless_data.spy_data = &priv->spy_data; - dev->wireless_data = &priv->wireless_data; #endif - /* we use the default eth_mac_addr for setting the MAC addr */ - - /* Reserve space in skb for the SNAP header */ - dev->hard_header_len += ENCAPS_OVERHEAD; /* Set up default callbacks */ priv->hard_reset = hard_reset; @@ -2293,9 +2267,8 @@ struct orinoco_private INIT_LIST_HEAD(&priv->rx_list); tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet, - (unsigned long) dev); + (unsigned long) priv); - netif_carrier_off(dev); priv->last_linkstatus = 0xffff; #if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) @@ -2310,9 +2283,82 @@ struct orinoco_private } EXPORT_SYMBOL(alloc_orinocodev); -void free_orinocodev(struct orinoco_private *priv) +/* We can only support a single interface. We provide a separate + * function to set it up to distinguish between hardware + * initialisation and interface setup. + * + * The base_addr and irq parameters are passed on to netdev for use + * with SIOCGIFMAP. + */ +int orinoco_if_add(struct orinoco_private *priv, + unsigned long base_addr, + unsigned int irq) +{ + struct wiphy *wiphy = priv_to_wiphy(priv); + struct wireless_dev *wdev; + struct net_device *dev; + int ret; + + dev = alloc_etherdev(sizeof(struct wireless_dev)); + + if (!dev) + return -ENOMEM; + + /* Initialise wireless_dev */ + wdev = netdev_priv(dev); + wdev->wiphy = wiphy; + wdev->iftype = NL80211_IFTYPE_STATION; + + /* Setup / override net_device fields */ + dev->ieee80211_ptr = wdev; + dev->netdev_ops = &orinoco_netdev_ops; + dev->watchdog_timeo = HZ; /* 1 second timeout */ + dev->ethtool_ops = &orinoco_ethtool_ops; + dev->wireless_handlers = &orinoco_handler_def; +#ifdef WIRELESS_SPY + dev->wireless_data = &priv->wireless_data; +#endif + /* we use the default eth_mac_addr for setting the MAC addr */ + + /* Reserve space in skb for the SNAP header */ + dev->hard_header_len += ENCAPS_OVERHEAD; + + netif_carrier_off(dev); + + memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN); + + dev->base_addr = base_addr; + dev->irq = irq; + + SET_NETDEV_DEV(dev, priv->dev); + ret = register_netdev(dev); + if (ret) + goto fail; + + priv->ndev = dev; + + /* Report what we've done */ + dev_dbg(priv->dev, "Registerred interface %s.\n", dev->name); + + return 0; + + fail: + free_netdev(dev); + return ret; +} +EXPORT_SYMBOL(orinoco_if_add); + +void orinoco_if_del(struct orinoco_private *priv) { struct net_device *dev = priv->ndev; + + unregister_netdev(dev); + free_netdev(dev); +} +EXPORT_SYMBOL(orinoco_if_del); + +void free_orinocodev(struct orinoco_private *priv) +{ struct wiphy *wiphy = priv_to_wiphy(priv); struct orinoco_rx_data *rx_data, *temp; @@ -2339,7 +2385,6 @@ void free_orinocodev(struct orinoco_private *priv) kfree(priv->wpa_ie); orinoco_mic_free(priv); orinoco_bss_data_free(priv); - free_netdev(dev); wiphy_free(wiphy); } EXPORT_SYMBOL(free_orinocodev); diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index 608cc5e1bd9..45aa616eb66 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -193,6 +193,10 @@ extern struct orinoco_private *alloc_orinocodev( int (*stop_fw)(struct orinoco_private *, int)); extern void free_orinocodev(struct orinoco_private *priv); extern int orinoco_init(struct orinoco_private *priv); +extern int orinoco_if_add(struct orinoco_private *priv, + unsigned long base_addr, + unsigned int irq); +extern void orinoco_if_del(struct orinoco_private *priv); extern int __orinoco_up(struct orinoco_private *priv); extern int __orinoco_down(struct orinoco_private *priv); extern int orinoco_reinit_firmware(struct orinoco_private *priv); diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index 20abf021c06..4c29d368925 100644 --- a/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -147,7 +147,7 @@ static void orinoco_cs_detach(struct pcmcia_device *link) struct orinoco_private *priv = link->priv; if (link->dev_node) - unregister_netdev(priv->ndev); + orinoco_if_del(priv); orinoco_cs_release(link); @@ -239,7 +239,6 @@ orinoco_cs_config(struct pcmcia_device *link) { struct orinoco_private *priv = link->priv; struct orinoco_pccard *card = priv->card; - struct net_device *dev = priv->ndev; hermes_t *hw = &priv->hw; int last_fn, last_ret; void __iomem *mem; @@ -293,8 +292,6 @@ orinoco_cs_config(struct pcmcia_device *link) pcmcia_request_configuration(link, &link->conf)); /* Ok, we have the configuration, prepare to register the netdev */ - dev->base_addr = link->io.BasePort1; - dev->irq = link->irq.AssignedIRQ; card->node.major = card->node.minor = 0; /* Initialise the main driver */ @@ -303,25 +300,19 @@ orinoco_cs_config(struct pcmcia_device *link) goto failed; } - SET_NETDEV_DEV(dev, &handle_to_dev(link)); - /* Tell the stack we exist */ - if (register_netdev(dev) != 0) { - printk(KERN_ERR PFX "register_netdev() failed\n"); + /* Register an interface with the stack */ + if (orinoco_if_add(priv, link->io.BasePort1, + link->irq.AssignedIRQ) != 0) { + printk(KERN_ERR PFX "orinoco_if_add() failed\n"); goto failed; } /* At this point, the dev_node_t structure(s) needs to be * initialized and arranged in a linked list at link->dev_node. */ - strcpy(card->node.dev_name, dev->name); + strcpy(card->node.dev_name, priv->ndev->name); link->dev_node = &card->node; /* link->dev_node being non-NULL is also * used to indicate that the * net_device has been registered */ - - /* Finally, report what we've done */ - printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io " - "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent), - link->irq.AssignedIRQ, link->io.BasePort1, - link->io.BasePort1 + link->io.NumPorts1 - 1); return 0; cs_failed: diff --git a/drivers/net/wireless/orinoco/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c index 45cef818b29..c13a4c38341 100644 --- a/drivers/net/wireless/orinoco/orinoco_nortel.c +++ b/drivers/net/wireless/orinoco/orinoco_nortel.c @@ -144,7 +144,6 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, int err; struct orinoco_private *priv; struct orinoco_pci_card *card; - struct net_device *dev; void __iomem *hermes_io, *bridge_io, *attr_io; err = pci_enable_device(pdev); @@ -189,16 +188,14 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, goto fail_alloc; } - dev = priv->ndev; card = priv->card; card->bridge_io = bridge_io; card->attr_io = attr_io; - SET_NETDEV_DEV(dev, &pdev->dev); hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, priv); + DRIVER_NAME, priv); if (err) { printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); err = -EBUSY; @@ -223,15 +220,13 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, goto fail; } - err = register_netdev(dev); + err = orinoco_if_add(priv, 0, 0); if (err) { - printk(KERN_ERR PFX "Cannot register network device\n"); + printk(KERN_ERR PFX "orinoco_if_add() failed\n"); goto fail; } pci_set_drvdata(pdev, priv); - printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, - pci_name(pdev)); return 0; @@ -263,13 +258,12 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, static void __devexit orinoco_nortel_remove_one(struct pci_dev *pdev) { struct orinoco_private *priv = pci_get_drvdata(pdev); - struct net_device *dev = priv->ndev; struct orinoco_pci_card *card = priv->card; /* Clear LEDs */ iowrite16(0, card->bridge_io + 10); - unregister_netdev(dev); + orinoco_if_del(priv); free_irq(pdev->irq, priv); pci_set_drvdata(pdev, NULL); free_orinocodev(priv); diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c index d0eb4ae9bd1..fea7781948e 100644 --- a/drivers/net/wireless/orinoco/orinoco_pci.c +++ b/drivers/net/wireless/orinoco/orinoco_pci.c @@ -116,7 +116,6 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, int err; struct orinoco_private *priv; struct orinoco_pci_card *card; - struct net_device *dev; void __iomem *hermes_io; err = pci_enable_device(pdev); @@ -147,14 +146,12 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, goto fail_alloc; } - dev = priv->ndev; card = priv->card; - SET_NETDEV_DEV(dev, &pdev->dev); hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING); err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, priv); + DRIVER_NAME, priv); if (err) { printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); err = -EBUSY; @@ -173,15 +170,13 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, goto fail; } - err = register_netdev(dev); + err = orinoco_if_add(priv, 0, 0); if (err) { - printk(KERN_ERR PFX "Cannot register network device\n"); + printk(KERN_ERR PFX "orinoco_if_add() failed\n"); goto fail; } pci_set_drvdata(pdev, priv); - printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, - pci_name(pdev)); return 0; @@ -207,9 +202,8 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev) { struct orinoco_private *priv = pci_get_drvdata(pdev); - struct net_device *dev = priv->ndev; - unregister_netdev(dev); + orinoco_if_del(priv); free_irq(pdev->irq, priv); pci_set_drvdata(pdev, NULL); free_orinocodev(priv); diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c index 8f225d064a7..3f2942a1e4f 100644 --- a/drivers/net/wireless/orinoco/orinoco_plx.c +++ b/drivers/net/wireless/orinoco/orinoco_plx.c @@ -183,7 +183,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, int err; struct orinoco_private *priv; struct orinoco_pci_card *card; - struct net_device *dev; void __iomem *hermes_io, *attr_io, *bridge_io; err = pci_enable_device(pdev); @@ -228,16 +227,14 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, goto fail_alloc; } - dev = priv->ndev; card = priv->card; card->bridge_io = bridge_io; card->attr_io = attr_io; - SET_NETDEV_DEV(dev, &pdev->dev); hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, priv); + DRIVER_NAME, priv); if (err) { printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); err = -EBUSY; @@ -262,15 +259,13 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, goto fail; } - err = register_netdev(dev); + err = orinoco_if_add(priv, 0, 0); if (err) { - printk(KERN_ERR PFX "Cannot register network device\n"); + printk(KERN_ERR PFX "orinoco_if_add() failed\n"); goto fail; } pci_set_drvdata(pdev, priv); - printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, - pci_name(pdev)); return 0; @@ -302,10 +297,9 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev) { struct orinoco_private *priv = pci_get_drvdata(pdev); - struct net_device *dev = priv->ndev; struct orinoco_pci_card *card = priv->card; - unregister_netdev(dev); + orinoco_if_del(priv); free_irq(pdev->irq, priv); pci_set_drvdata(pdev, NULL); free_orinocodev(priv); diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c index 3c04faee7ae..d3452548cc7 100644 --- a/drivers/net/wireless/orinoco/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco/orinoco_tmd.c @@ -94,7 +94,6 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, int err; struct orinoco_private *priv; struct orinoco_pci_card *card; - struct net_device *dev; void __iomem *hermes_io, *bridge_io; err = pci_enable_device(pdev); @@ -132,15 +131,13 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, goto fail_alloc; } - dev = priv->ndev; card = priv->card; card->bridge_io = bridge_io; - SET_NETDEV_DEV(dev, &pdev->dev); hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, - dev->name, priv); + DRIVER_NAME, priv); if (err) { printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); err = -EBUSY; @@ -159,15 +156,13 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, goto fail; } - err = register_netdev(dev); + err = orinoco_if_add(priv, 0, 0); if (err) { - printk(KERN_ERR PFX "Cannot register network device\n"); + printk(KERN_ERR PFX "orinoco_if_add() failed\n"); goto fail; } pci_set_drvdata(pdev, priv); - printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, - pci_name(pdev)); return 0; @@ -196,10 +191,9 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev) { struct orinoco_private *priv = pci_get_drvdata(pdev); - struct net_device *dev = priv->ndev; struct orinoco_pci_card *card = priv->card; - unregister_netdev(dev); + orinoco_if_del(priv); free_irq(pdev->irq, priv); pci_set_drvdata(pdev, NULL); free_orinocodev(priv); diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index 43e1aed4e4b..7b4a7e42835 100644 --- a/drivers/net/wireless/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -220,7 +220,7 @@ static void spectrum_cs_detach(struct pcmcia_device *link) struct orinoco_private *priv = link->priv; if (link->dev_node) - unregister_netdev(priv->ndev); + orinoco_if_del(priv); spectrum_cs_release(link); @@ -306,7 +306,6 @@ spectrum_cs_config(struct pcmcia_device *link) { struct orinoco_private *priv = link->priv; struct orinoco_pccard *card = priv->card; - struct net_device *dev = priv->ndev; hermes_t *hw = &priv->hw; int last_fn, last_ret; void __iomem *mem; @@ -360,8 +359,6 @@ spectrum_cs_config(struct pcmcia_device *link) pcmcia_request_configuration(link, &link->conf)); /* Ok, we have the configuration, prepare to register the netdev */ - dev->base_addr = link->io.BasePort1; - dev->irq = link->irq.AssignedIRQ; card->node.major = card->node.minor = 0; /* Reset card */ @@ -374,26 +371,19 @@ spectrum_cs_config(struct pcmcia_device *link) goto failed; } - SET_NETDEV_DEV(dev, &handle_to_dev(link)); - /* Tell the stack we exist */ - if (register_netdev(dev) != 0) { - printk(KERN_ERR PFX "register_netdev() failed\n"); + /* Register an interface with the stack */ + if (orinoco_if_add(priv, link->io.BasePort1, + link->irq.AssignedIRQ) != 0) { + printk(KERN_ERR PFX "orinoco_if_add() failed\n"); goto failed; } /* At this point, the dev_node_t structure(s) needs to be * initialized and arranged in a linked list at link->dev_node. */ - strcpy(card->node.dev_name, dev->name); + strcpy(card->node.dev_name, priv->ndev->name); link->dev_node = &card->node; /* link->dev_node being non-NULL is also * used to indicate that the * net_device has been registered */ - - /* Finally, report what we've done */ - printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io " - "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent), - link->irq.AssignedIRQ, link->io.BasePort1, - link->io.BasePort1 + link->io.NumPorts1 - 1); - return 0; cs_failed: -- cgit v1.2.3-18-g5258 From ef96b5c9ed6ba4b45fd4cf45810c34978bb8d8bb Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:29 +0100 Subject: airport: store irq in card private structure ... instead of relying on the net_device fields. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/airport.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c index e46e0d7c36f..70f1331512b 100644 --- a/drivers/net/wireless/orinoco/airport.c +++ b/drivers/net/wireless/orinoco/airport.c @@ -27,6 +27,7 @@ struct airport { struct macio_dev *mdev; void __iomem *vaddr; + unsigned int irq; int irq_requested; int ndev_registered; }; @@ -36,6 +37,7 @@ airport_suspend(struct macio_dev *mdev, pm_message_t state) { struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); struct net_device *dev = priv->ndev; + struct airport *card = priv->card; unsigned long flags; int err; @@ -59,7 +61,7 @@ airport_suspend(struct macio_dev *mdev, pm_message_t state) orinoco_unlock(priv, &flags); - disable_irq(dev->irq); + disable_irq(card->irq); pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0); @@ -71,6 +73,7 @@ airport_resume(struct macio_dev *mdev) { struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); struct net_device *dev = priv->ndev; + struct airport *card = priv->card; unsigned long flags; int err; @@ -80,7 +83,7 @@ airport_resume(struct macio_dev *mdev) macio_get_of_node(mdev), 0, 1); msleep(200); - enable_irq(dev->irq); + enable_irq(card->irq); err = orinoco_reinit_firmware(priv); if (err) { @@ -112,7 +115,6 @@ static int airport_detach(struct macio_dev *mdev) { struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev); - struct net_device *dev = priv->ndev; struct airport *card = priv->card; if (card->ndev_registered) @@ -120,7 +122,7 @@ airport_detach(struct macio_dev *mdev) card->ndev_registered = 0; if (card->irq_requested) - free_irq(dev->irq, priv); + free_irq(card->irq, priv); card->irq_requested = 0; if (card->vaddr) @@ -146,7 +148,6 @@ static int airport_hard_reset(struct orinoco_private *priv) * re-initialize properly, it falls in a screaming heap * shortly afterwards. */ #if 0 - struct net_device *dev = priv->ndev; struct airport *card = priv->card; /* Vitally important. If we don't do this it seems we get an @@ -154,7 +155,7 @@ static int airport_hard_reset(struct orinoco_private *priv) * hw_unavailable is already set it doesn't get ACKed, we get * into an interrupt loop and the PMU decides to turn us * off. */ - disable_irq(dev->irq); + disable_irq(card->irq); pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 0); @@ -163,7 +164,7 @@ static int airport_hard_reset(struct orinoco_private *priv) macio_get_of_node(card->mdev), 0, 1); ssleep(1); - enable_irq(dev->irq); + enable_irq(card->irq); ssleep(1); #endif @@ -176,7 +177,6 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) struct orinoco_private *priv; struct airport *card; unsigned long phys_addr; - unsigned int irq; hermes_t *hw; if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) { @@ -205,7 +205,7 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) macio_set_drvdata(mdev, priv); /* Setup interrupts & base address */ - irq = macio_irq(mdev, 0); + card->irq = macio_irq(mdev, 0); phys_addr = macio_resource_start(mdev, 0); /* Physical address */ printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr); card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN); @@ -224,8 +224,8 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) /* Reset it before we get the interrupt */ hermes_init(hw); - if (request_irq(irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) { - printk(KERN_ERR PFX "Couldn't get IRQ %d\n", irq); + if (request_irq(card->irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) { + printk(KERN_ERR PFX "Couldn't get IRQ %d\n", card->irq); goto failed; } card->irq_requested = 1; @@ -237,7 +237,7 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) } /* Register an interface with the stack */ - if (orinoco_if_add(priv, phys_addr, irq) != 0) { + if (orinoco_if_add(priv, phys_addr, card->irq) != 0) { printk(KERN_ERR PFX "orinoco_if_add() failed\n"); goto failed; } -- cgit v1.2.3-18-g5258 From 6415f7df10573bf1ec42644f42bef565127114a1 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:30 +0100 Subject: orinoco: Handle suspend/restore in core driver Each device does almost exactly the same things on suspend and resume when upping and downing the interface. So move this logic into a common routine. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/airport.c | 33 ++-------------- drivers/net/wireless/orinoco/main.c | 61 +++++++++++++++++++++++++++--- drivers/net/wireless/orinoco/orinoco.h | 5 +-- drivers/net/wireless/orinoco/orinoco_cs.c | 44 ++------------------- drivers/net/wireless/orinoco/orinoco_pci.h | 47 ++--------------------- drivers/net/wireless/orinoco/spectrum_cs.c | 41 ++------------------ 6 files changed, 70 insertions(+), 161 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c index 70f1331512b..c60df2c1aca 100644 --- a/drivers/net/wireless/orinoco/airport.c +++ b/drivers/net/wireless/orinoco/airport.c @@ -50,15 +50,7 @@ airport_suspend(struct macio_dev *mdev, pm_message_t state) return 0; } - err = __orinoco_down(priv); - if (err) - printk(KERN_WARNING "%s: PBOOK_SLEEP_NOW: Error %d downing interface\n", - dev->name, err); - - netif_device_detach(dev); - - priv->hw_unavailable++; - + orinoco_down(priv); orinoco_unlock(priv, &flags); disable_irq(card->irq); @@ -85,30 +77,11 @@ airport_resume(struct macio_dev *mdev) enable_irq(card->irq); - err = orinoco_reinit_firmware(priv); - if (err) { - printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n", - dev->name, err); - return 0; - } - spin_lock_irqsave(&priv->lock, flags); - - netif_device_attach(dev); - - priv->hw_unavailable--; - - if (priv->open && (!priv->hw_unavailable)) { - err = __orinoco_up(priv); - if (err) - printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n", - dev->name, err); - } - - + err = orinoco_up(priv); spin_unlock_irqrestore(&priv->lock, flags); - return 0; + return err; } static int diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 361cf09d6b7..0727b41a397 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -211,6 +211,8 @@ struct orinoco_rx_data { /********************************************************************/ static void __orinoco_set_multicast_list(struct net_device *dev); +static int __orinoco_up(struct orinoco_private *priv); +static int __orinoco_down(struct orinoco_private *priv); /********************************************************************/ /* Internal helper functions */ @@ -1514,7 +1516,7 @@ static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) /* Internal hardware control routines */ /********************************************************************/ -int __orinoco_up(struct orinoco_private *priv) +static int __orinoco_up(struct orinoco_private *priv) { struct net_device *dev = priv->ndev; struct hermes *hw = &priv->hw; @@ -1542,9 +1544,8 @@ int __orinoco_up(struct orinoco_private *priv) return 0; } -EXPORT_SYMBOL(__orinoco_up); -int __orinoco_down(struct orinoco_private *priv) +static int __orinoco_down(struct orinoco_private *priv) { struct net_device *dev = priv->ndev; struct hermes *hw = &priv->hw; @@ -1574,9 +1575,8 @@ int __orinoco_down(struct orinoco_private *priv) return 0; } -EXPORT_SYMBOL(__orinoco_down); -int orinoco_reinit_firmware(struct orinoco_private *priv) +static int orinoco_reinit_firmware(struct orinoco_private *priv) { struct hermes *hw = &priv->hw; int err; @@ -1592,7 +1592,6 @@ int orinoco_reinit_firmware(struct orinoco_private *priv) return err; } -EXPORT_SYMBOL(orinoco_reinit_firmware); int __orinoco_program_rids(struct net_device *dev) { @@ -2389,6 +2388,56 @@ void free_orinocodev(struct orinoco_private *priv) } EXPORT_SYMBOL(free_orinocodev); +int orinoco_up(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + unsigned long flags; + int err; + + spin_lock_irqsave(&priv->lock, flags); + + err = orinoco_reinit_firmware(priv); + if (err) { + printk(KERN_ERR "%s: Error %d re-initializing firmware\n", + dev->name, err); + goto exit; + } + + netif_device_attach(dev); + priv->hw_unavailable--; + + if (priv->open && !priv->hw_unavailable) { + err = __orinoco_up(priv); + if (err) + printk(KERN_ERR "%s: Error %d restarting card\n", + dev->name, err); + } + +exit: + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} +EXPORT_SYMBOL(orinoco_up); + +void orinoco_down(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + unsigned long flags; + int err; + + spin_lock_irqsave(&priv->lock, flags); + err = __orinoco_down(priv); + if (err) + printk(KERN_WARNING "%s: Error %d downing interface\n", + dev->name, err); + + netif_device_detach(dev); + priv->hw_unavailable++; + spin_unlock_irqrestore(&priv->lock, flags); +} +EXPORT_SYMBOL(orinoco_down); + static void orinoco_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index 45aa616eb66..4ee85f8f6bc 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -197,9 +197,8 @@ extern int orinoco_if_add(struct orinoco_private *priv, unsigned long base_addr, unsigned int irq); extern void orinoco_if_del(struct orinoco_private *priv); -extern int __orinoco_up(struct orinoco_private *priv); -extern int __orinoco_down(struct orinoco_private *priv); -extern int orinoco_reinit_firmware(struct orinoco_private *priv); +extern int orinoco_up(struct orinoco_private *priv); +extern void orinoco_down(struct orinoco_private *priv); extern irqreturn_t orinoco_interrupt(int irq, void *dev_id); /********************************************************************/ diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index 4c29d368925..38c1c9d2abb 100644 --- a/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -349,26 +349,12 @@ static int orinoco_cs_suspend(struct pcmcia_device *link) { struct orinoco_private *priv = link->priv; struct orinoco_pccard *card = priv->card; - struct net_device *dev = priv->ndev; - int err = 0; - unsigned long flags; /* This is probably racy, but I can't think of a better way, short of rewriting the PCMCIA layer to not suck :-( */ - if (!test_bit(0, &card->hard_reset_in_progress)) { - spin_lock_irqsave(&priv->lock, flags); - - err = __orinoco_down(priv); - if (err) - printk(KERN_WARNING "%s: Error %d downing interface\n", - dev->name, err); - - netif_device_detach(dev); - priv->hw_unavailable++; - - spin_unlock_irqrestore(&priv->lock, flags); - } + if (!test_bit(0, &card->hard_reset_in_progress)) + orinoco_down(priv); return 0; } @@ -377,32 +363,10 @@ static int orinoco_cs_resume(struct pcmcia_device *link) { struct orinoco_private *priv = link->priv; struct orinoco_pccard *card = priv->card; - struct net_device *dev = priv->ndev; int err = 0; - unsigned long flags; - if (!test_bit(0, &card->hard_reset_in_progress)) { - err = orinoco_reinit_firmware(priv); - if (err) { - printk(KERN_ERR "%s: Error %d re-initializing firmware\n", - dev->name, err); - return -EIO; - } - - spin_lock_irqsave(&priv->lock, flags); - - netif_device_attach(dev); - priv->hw_unavailable--; - - if (priv->open && !priv->hw_unavailable) { - err = __orinoco_up(priv); - if (err) - printk(KERN_ERR "%s: Error %d restarting card\n", - dev->name, err); - } - - spin_unlock_irqrestore(&priv->lock, flags); - } + if (!test_bit(0, &card->hard_reset_in_progress)) + err = orinoco_up(priv); return err; } diff --git a/drivers/net/wireless/orinoco/orinoco_pci.h b/drivers/net/wireless/orinoco/orinoco_pci.h index 22aa630027e..ea7231af40a 100644 --- a/drivers/net/wireless/orinoco/orinoco_pci.h +++ b/drivers/net/wireless/orinoco/orinoco_pci.h @@ -22,28 +22,8 @@ struct orinoco_pci_card { static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state) { struct orinoco_private *priv = pci_get_drvdata(pdev); - struct net_device *dev = priv->ndev; - unsigned long flags; - int err; - - err = orinoco_lock(priv, &flags); - if (err) { - printk(KERN_ERR "%s: cannot lock hardware for suspend\n", - dev->name); - return err; - } - - err = __orinoco_down(priv); - if (err) - printk(KERN_WARNING "%s: error %d bringing interface down " - "for suspend\n", dev->name, err); - - netif_device_detach(dev); - - priv->hw_unavailable++; - - orinoco_unlock(priv, &flags); + orinoco_down(priv); free_irq(pdev->irq, priv); pci_save_state(pdev); pci_disable_device(pdev); @@ -56,7 +36,6 @@ static int orinoco_pci_resume(struct pci_dev *pdev) { struct orinoco_private *priv = pci_get_drvdata(pdev); struct net_device *dev = priv->ndev; - unsigned long flags; int err; pci_set_power_state(pdev, 0); @@ -77,29 +56,9 @@ static int orinoco_pci_resume(struct pci_dev *pdev) return -EBUSY; } - err = orinoco_reinit_firmware(priv); - if (err) { - printk(KERN_ERR "%s: error %d re-initializing firmware " - "on resume\n", dev->name, err); - return err; - } - - spin_lock_irqsave(&priv->lock, flags); - - netif_device_attach(dev); + err = orinoco_up(priv); - priv->hw_unavailable--; - - if (priv->open && (!priv->hw_unavailable)) { - err = __orinoco_up(priv); - if (err) - printk(KERN_ERR "%s: Error %d restarting card on resume\n", - dev->name, err); - } - - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; + return err; } #else #define orinoco_pci_suspend NULL diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index 7b4a7e42835..c361310b885 100644 --- a/drivers/net/wireless/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -421,22 +421,10 @@ static int spectrum_cs_suspend(struct pcmcia_device *link) { struct orinoco_private *priv = link->priv; - struct net_device *dev = priv->ndev; - unsigned long flags; int err = 0; /* Mark the device as stopped, to block IO until later */ - spin_lock_irqsave(&priv->lock, flags); - - err = __orinoco_down(priv); - if (err) - printk(KERN_WARNING "%s: Error %d downing interface\n", - dev->name, err); - - netif_device_detach(dev); - priv->hw_unavailable++; - - spin_unlock_irqrestore(&priv->lock, flags); + orinoco_down(priv); return err; } @@ -445,32 +433,9 @@ static int spectrum_cs_resume(struct pcmcia_device *link) { struct orinoco_private *priv = link->priv; - struct net_device *dev = priv->ndev; - unsigned long flags; - int err; - - err = orinoco_reinit_firmware(priv); - if (err) { - printk(KERN_ERR "%s: Error %d re-initializing firmware\n", - dev->name, err); - return -EIO; - } + int err = orinoco_up(priv); - spin_lock_irqsave(&priv->lock, flags); - - netif_device_attach(dev); - priv->hw_unavailable--; - - if (priv->open && !priv->hw_unavailable) { - err = __orinoco_up(priv); - if (err) - printk(KERN_ERR "%s: Error %d restarting card\n", - dev->name, err); - } - - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; + return err; } -- cgit v1.2.3-18-g5258 From 721aa2f75b00399074eb443fdf16d797b4504a36 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:31 +0100 Subject: orinoco: provide generic commit function This allows changes to be commited from cfg80211 functions. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/hw.c | 227 +++++++++++++++++++++++++++ drivers/net/wireless/orinoco/hw.h | 1 + drivers/net/wireless/orinoco/main.c | 297 ++++++++---------------------------- drivers/net/wireless/orinoco/main.h | 3 +- drivers/net/wireless/orinoco/wext.c | 35 +---- 5 files changed, 294 insertions(+), 269 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index eaa89d3866c..56627d91aa7 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -406,6 +406,233 @@ void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic) *automatic = bitrate_table[ratemode].automatic; } +int orinoco_hw_program_rids(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + hermes_t *hw = &priv->hw; + int err; + struct hermes_idstring idbuf; + + /* Set the MAC address */ + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, + HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr); + if (err) { + printk(KERN_ERR "%s: Error %d setting MAC address\n", + dev->name, err); + return err; + } + + /* Set up the link mode */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, + priv->port_type); + if (err) { + printk(KERN_ERR "%s: Error %d setting port type\n", + dev->name, err); + return err; + } + /* Set the channel/frequency */ + if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFOWNCHANNEL, + priv->channel); + if (err) { + printk(KERN_ERR "%s: Error %d setting channel %d\n", + dev->name, err, priv->channel); + return err; + } + } + + if (priv->has_ibss) { + u16 createibss; + + if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) { + printk(KERN_WARNING "%s: This firmware requires an " + "ESSID in IBSS-Ad-Hoc mode.\n", dev->name); + /* With wvlan_cs, in this case, we would crash. + * hopefully, this driver will behave better... + * Jean II */ + createibss = 0; + } else { + createibss = priv->createibss; + } + + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFCREATEIBSS, + createibss); + if (err) { + printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", + dev->name, err); + return err; + } + } + + /* Set the desired BSSID */ + err = __orinoco_hw_set_wap(priv); + if (err) { + printk(KERN_ERR "%s: Error %d setting AP address\n", + dev->name, err); + return err; + } + + /* Set the desired ESSID */ + idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); + memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); + /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */ + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID, + HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), + &idbuf); + if (err) { + printk(KERN_ERR "%s: Error %d setting OWNSSID\n", + dev->name, err); + return err; + } + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID, + HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), + &idbuf); + if (err) { + printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n", + dev->name, err); + return err; + } + + /* Set the station name */ + idbuf.len = cpu_to_le16(strlen(priv->nick)); + memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, + HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), + &idbuf); + if (err) { + printk(KERN_ERR "%s: Error %d setting nickname\n", + dev->name, err); + return err; + } + + /* Set AP density */ + if (priv->has_sensitivity) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFSYSTEMSCALE, + priv->ap_density); + if (err) { + printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. " + "Disabling sensitivity control\n", + dev->name, err); + + priv->has_sensitivity = 0; + } + } + + /* Set RTS threshold */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, + priv->rts_thresh); + if (err) { + printk(KERN_ERR "%s: Error %d setting RTS threshold\n", + dev->name, err); + return err; + } + + /* Set fragmentation threshold or MWO robustness */ + if (priv->has_mwo) + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFMWOROBUST_AGERE, + priv->mwo_robust); + else + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, + priv->frag_thresh); + if (err) { + printk(KERN_ERR "%s: Error %d setting fragmentation\n", + dev->name, err); + return err; + } + + /* Set bitrate */ + err = __orinoco_hw_set_bitrate(priv); + if (err) { + printk(KERN_ERR "%s: Error %d setting bitrate\n", + dev->name, err); + return err; + } + + /* Set power management */ + if (priv->has_pm) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPMENABLED, + priv->pm_on); + if (err) { + printk(KERN_ERR "%s: Error %d setting up PM\n", + dev->name, err); + return err; + } + + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFMULTICASTRECEIVE, + priv->pm_mcast); + if (err) { + printk(KERN_ERR "%s: Error %d setting up PM\n", + dev->name, err); + return err; + } + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFMAXSLEEPDURATION, + priv->pm_period); + if (err) { + printk(KERN_ERR "%s: Error %d setting up PM\n", + dev->name, err); + return err; + } + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPMHOLDOVERDURATION, + priv->pm_timeout); + if (err) { + printk(KERN_ERR "%s: Error %d setting up PM\n", + dev->name, err); + return err; + } + } + + /* Set preamble - only for Symbol so far... */ + if (priv->has_preamble) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPREAMBLE_SYMBOL, + priv->preamble); + if (err) { + printk(KERN_ERR "%s: Error %d setting preamble\n", + dev->name, err); + return err; + } + } + + /* Set up encryption */ + if (priv->has_wep || priv->has_wpa) { + err = __orinoco_hw_setup_enc(priv); + if (err) { + printk(KERN_ERR "%s: Error %d activating encryption\n", + dev->name, err); + return err; + } + } + + if (priv->iw_mode == IW_MODE_MONITOR) { + /* Enable monitor mode */ + dev->type = ARPHRD_IEEE80211; + err = hermes_docmd_wait(hw, HERMES_CMD_TEST | + HERMES_TEST_MONITOR, 0, NULL); + } else { + /* Disable monitor mode */ + dev->type = ARPHRD_ETHER; + err = hermes_docmd_wait(hw, HERMES_CMD_TEST | + HERMES_TEST_STOP, 0, NULL); + } + if (err) + return err; + + /* Reset promiscuity / multicast*/ + priv->promiscuous = 0; + priv->mc_count = 0; + + return 0; +} + /* Get tsc from the firmware */ int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc) { diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index 84c108cc0f5..210c2b1b7f9 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h @@ -29,6 +29,7 @@ int orinoco_hw_allocate_fid(struct orinoco_private *priv); int orinoco_get_bitratemode(int bitrate, int automatic); void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic); +int orinoco_hw_program_rids(struct orinoco_private *priv); int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc); int __orinoco_hw_set_bitrate(struct orinoco_private *priv); int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate); diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 0727b41a397..dab6649ad0c 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -210,9 +210,10 @@ struct orinoco_rx_data { /* Function prototypes */ /********************************************************************/ -static void __orinoco_set_multicast_list(struct net_device *dev); +static int __orinoco_set_multicast_list(struct net_device *dev); static int __orinoco_up(struct orinoco_private *priv); static int __orinoco_down(struct orinoco_private *priv); +static int __orinoco_commit(struct orinoco_private *priv); /********************************************************************/ /* Internal helper functions */ @@ -1524,7 +1525,7 @@ static int __orinoco_up(struct orinoco_private *priv) netif_carrier_off(dev); /* just to make sure */ - err = __orinoco_program_rids(dev); + err = __orinoco_commit(priv); if (err) { printk(KERN_ERR "%s: Error %d configuring card\n", dev->name, err); @@ -1593,237 +1594,7 @@ static int orinoco_reinit_firmware(struct orinoco_private *priv) return err; } -int __orinoco_program_rids(struct net_device *dev) -{ - struct orinoco_private *priv = ndev_priv(dev); - hermes_t *hw = &priv->hw; - int err; - struct hermes_idstring idbuf; - - /* Set the MAC address */ - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, - HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr); - if (err) { - printk(KERN_ERR "%s: Error %d setting MAC address\n", - dev->name, err); - return err; - } - - /* Set up the link mode */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, - priv->port_type); - if (err) { - printk(KERN_ERR "%s: Error %d setting port type\n", - dev->name, err); - return err; - } - /* Set the channel/frequency */ - if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFOWNCHANNEL, - priv->channel); - if (err) { - printk(KERN_ERR "%s: Error %d setting channel %d\n", - dev->name, err, priv->channel); - return err; - } - } - - if (priv->has_ibss) { - u16 createibss; - - if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) { - printk(KERN_WARNING "%s: This firmware requires an " - "ESSID in IBSS-Ad-Hoc mode.\n", dev->name); - /* With wvlan_cs, in this case, we would crash. - * hopefully, this driver will behave better... - * Jean II */ - createibss = 0; - } else { - createibss = priv->createibss; - } - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFCREATEIBSS, - createibss); - if (err) { - printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", - dev->name, err); - return err; - } - } - - /* Set the desired BSSID */ - err = __orinoco_hw_set_wap(priv); - if (err) { - printk(KERN_ERR "%s: Error %d setting AP address\n", - dev->name, err); - return err; - } - /* Set the desired ESSID */ - idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); - memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); - /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */ - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID, - HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting OWNSSID\n", - dev->name, err); - return err; - } - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID, - HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n", - dev->name, err); - return err; - } - - /* Set the station name */ - idbuf.len = cpu_to_le16(strlen(priv->nick)); - memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, - HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), - &idbuf); - if (err) { - printk(KERN_ERR "%s: Error %d setting nickname\n", - dev->name, err); - return err; - } - - /* Set AP density */ - if (priv->has_sensitivity) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSYSTEMSCALE, - priv->ap_density); - if (err) { - printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. " - "Disabling sensitivity control\n", - dev->name, err); - - priv->has_sensitivity = 0; - } - } - - /* Set RTS threshold */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, - priv->rts_thresh); - if (err) { - printk(KERN_ERR "%s: Error %d setting RTS threshold\n", - dev->name, err); - return err; - } - - /* Set fragmentation threshold or MWO robustness */ - if (priv->has_mwo) - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMWOROBUST_AGERE, - priv->mwo_robust); - else - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, - priv->frag_thresh); - if (err) { - printk(KERN_ERR "%s: Error %d setting fragmentation\n", - dev->name, err); - return err; - } - - /* Set bitrate */ - err = __orinoco_hw_set_bitrate(priv); - if (err) { - printk(KERN_ERR "%s: Error %d setting bitrate\n", - dev->name, err); - return err; - } - - /* Set power management */ - if (priv->has_pm) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMENABLED, - priv->pm_on); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMULTICASTRECEIVE, - priv->pm_mcast); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFMAXSLEEPDURATION, - priv->pm_period); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPMHOLDOVERDURATION, - priv->pm_timeout); - if (err) { - printk(KERN_ERR "%s: Error %d setting up PM\n", - dev->name, err); - return err; - } - } - - /* Set preamble - only for Symbol so far... */ - if (priv->has_preamble) { - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFPREAMBLE_SYMBOL, - priv->preamble); - if (err) { - printk(KERN_ERR "%s: Error %d setting preamble\n", - dev->name, err); - return err; - } - } - - /* Set up encryption */ - if (priv->has_wep || priv->has_wpa) { - err = __orinoco_hw_setup_enc(priv); - if (err) { - printk(KERN_ERR "%s: Error %d activating encryption\n", - dev->name, err); - return err; - } - } - - if (priv->iw_mode == IW_MODE_MONITOR) { - /* Enable monitor mode */ - dev->type = ARPHRD_IEEE80211; - err = hermes_docmd_wait(hw, HERMES_CMD_TEST | - HERMES_TEST_MONITOR, 0, NULL); - } else { - /* Disable monitor mode */ - dev->type = ARPHRD_ETHER; - err = hermes_docmd_wait(hw, HERMES_CMD_TEST | - HERMES_TEST_STOP, 0, NULL); - } - if (err) - return err; - - /* Set promiscuity / multicast*/ - priv->promiscuous = 0; - priv->mc_count = 0; - - /* FIXME: what about netif_tx_lock */ - __orinoco_set_multicast_list(dev); - - return 0; -} - -/* FIXME: return int? */ -static void +static int __orinoco_set_multicast_list(struct net_device *dev) { struct orinoco_private *priv = ndev_priv(dev); @@ -1843,6 +1614,8 @@ __orinoco_set_multicast_list(struct net_device *dev) err = __orinoco_hw_set_multicast_list(priv, dev->mc_list, mc_count, promisc); + + return err; } /* This must be called from user context, without locks held - use @@ -1920,6 +1693,64 @@ void orinoco_reset(struct work_struct *work) printk(KERN_ERR "%s: Device has been disabled!\n", dev->name); } +static int __orinoco_commit(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + int err = 0; + + err = orinoco_hw_program_rids(priv); + + /* FIXME: what about netif_tx_lock */ + (void) __orinoco_set_multicast_list(dev); + + return err; +} + +/* Ensures configuration changes are applied. May result in a reset. + * The caller should hold priv->lock + */ +int orinoco_commit(struct orinoco_private *priv) +{ + struct net_device *dev = priv->ndev; + hermes_t *hw = &priv->hw; + int err; + + if (priv->broken_disableport) { + schedule_work(&priv->reset_work); + return 0; + } + + err = hermes_disable_port(hw, 0); + if (err) { + printk(KERN_WARNING "%s: Unable to disable port " + "while reconfiguring card\n", dev->name); + priv->broken_disableport = 1; + goto out; + } + + err = __orinoco_commit(priv); + if (err) { + printk(KERN_WARNING "%s: Unable to reconfigure card\n", + dev->name); + goto out; + } + + err = hermes_enable_port(hw, 0); + if (err) { + printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", + dev->name); + goto out; + } + + out: + if (err) { + printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); + schedule_work(&priv->reset_work); + err = 0; + } + return err; +} + /********************************************************************/ /* Interrupt handler */ /********************************************************************/ diff --git a/drivers/net/wireless/orinoco/main.h b/drivers/net/wireless/orinoco/main.h index af2bae4fe39..21ab36cd76c 100644 --- a/drivers/net/wireless/orinoco/main.h +++ b/drivers/net/wireless/orinoco/main.h @@ -29,10 +29,9 @@ struct net_device; struct work_struct; void set_port_type(struct orinoco_private *priv); -int __orinoco_program_rids(struct net_device *dev); +int orinoco_commit(struct orinoco_private *priv); void orinoco_reset(struct work_struct *work); - /* Information element helpers - find a home for these... */ static inline u8 *orinoco_get_ie(u8 *data, size_t len, enum ieee80211_eid eid) diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 74892e1d34a..4c20b1d5c2a 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -2163,49 +2163,16 @@ static int orinoco_ioctl_commit(struct net_device *dev, char *extra) { struct orinoco_private *priv = ndev_priv(dev); - struct hermes *hw = &priv->hw; unsigned long flags; int err = 0; if (!priv->open) return 0; - if (priv->broken_disableport) { - orinoco_reset(&priv->reset_work); - return 0; - } - if (orinoco_lock(priv, &flags) != 0) return err; - err = hermes_disable_port(hw, 0); - if (err) { - printk(KERN_WARNING "%s: Unable to disable port " - "while reconfiguring card\n", dev->name); - priv->broken_disableport = 1; - goto out; - } - - err = __orinoco_program_rids(dev); - if (err) { - printk(KERN_WARNING "%s: Unable to reconfigure card\n", - dev->name); - goto out; - } - - err = hermes_enable_port(hw, 0); - if (err) { - printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", - dev->name); - goto out; - } - - out: - if (err) { - printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); - schedule_work(&priv->reset_work); - err = 0; - } + err = orinoco_commit(priv); orinoco_unlock(priv, &flags); return err; -- cgit v1.2.3-18-g5258 From 5217c571c898371c540e49671600d54346b2e123 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:32 +0100 Subject: orinoco: convert mode setting to cfg80211 Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/cfg.c | 46 ++++++++++++++++++++- drivers/net/wireless/orinoco/hw.c | 12 ++++-- drivers/net/wireless/orinoco/main.c | 15 +++---- drivers/net/wireless/orinoco/orinoco.h | 2 +- drivers/net/wireless/orinoco/wext.c | 75 ++++------------------------------ 5 files changed, 70 insertions(+), 80 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c index 9a616ddac09..9e59d90b32e 100644 --- a/drivers/net/wireless/orinoco/cfg.c +++ b/drivers/net/wireless/orinoco/cfg.c @@ -93,6 +93,50 @@ int orinoco_wiphy_register(struct wiphy *wiphy) return wiphy_register(wiphy); } -const struct cfg80211_ops orinoco_cfg_ops = { +static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + struct orinoco_private *priv = wiphy_priv(wiphy); + int err = 0; + unsigned long lock; + + if (orinoco_lock(priv, &lock) != 0) + return -EBUSY; + + switch (type) { + case NL80211_IFTYPE_ADHOC: + if (!priv->has_ibss && !priv->has_port3) + err = -EINVAL; + break; + + case NL80211_IFTYPE_STATION: + break; + + case NL80211_IFTYPE_MONITOR: + if (priv->broken_monitor && !force_monitor) { + printk(KERN_WARNING "%s: Monitor mode support is " + "buggy in this firmware, not enabling\n", + wiphy_name(wiphy)); + err = -EINVAL; + } + break; + + default: + err = -EINVAL; + } + if (!err) { + priv->iw_mode = type; + set_port_type(priv); + err = orinoco_commit(priv); + } + + orinoco_unlock(priv, &lock); + + return err; +} + +const struct cfg80211_ops orinoco_cfg_ops = { + .change_virtual_intf = orinoco_change_vif, }; diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 56627d91aa7..4600fe4a7e1 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -7,7 +7,7 @@ #include #include #include - +#include #include "hermes.h" #include "hermes_rid.h" #include "orinoco.h" @@ -409,6 +409,7 @@ void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic) int orinoco_hw_program_rids(struct orinoco_private *priv) { struct net_device *dev = priv->ndev; + struct wireless_dev *wdev = netdev_priv(dev); hermes_t *hw = &priv->hw; int err; struct hermes_idstring idbuf; @@ -431,7 +432,7 @@ int orinoco_hw_program_rids(struct orinoco_private *priv) return err; } /* Set the channel/frequency */ - if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) { + if (priv->channel != 0 && priv->iw_mode != NL80211_IFTYPE_STATION) { err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFOWNCHANNEL, priv->channel); @@ -612,7 +613,7 @@ int orinoco_hw_program_rids(struct orinoco_private *priv) } } - if (priv->iw_mode == IW_MODE_MONITOR) { + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { /* Enable monitor mode */ dev->type = ARPHRD_IEEE80211; err = hermes_docmd_wait(hw, HERMES_CMD_TEST | @@ -630,6 +631,9 @@ int orinoco_hw_program_rids(struct orinoco_private *priv) priv->promiscuous = 0; priv->mc_count = 0; + /* Record mode change */ + wdev->iftype = priv->iw_mode; + return 0; } @@ -884,7 +888,7 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) } else master_wep_flag = 0; - if (priv->iw_mode == IW_MODE_MONITOR) + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) master_wep_flag |= HERMES_WEP_HOST_DECRYPT; /* Master WEP setting : on/off */ diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index dab6649ad0c..ebf92ae6e36 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -222,11 +222,11 @@ static int __orinoco_commit(struct orinoco_private *priv); void set_port_type(struct orinoco_private *priv) { switch (priv->iw_mode) { - case IW_MODE_INFRA: + case NL80211_IFTYPE_STATION: priv->port_type = 1; priv->createibss = 0; break; - case IW_MODE_ADHOC: + case NL80211_IFTYPE_ADHOC: if (priv->prefer_port3) { priv->port_type = 3; priv->createibss = 0; @@ -235,7 +235,7 @@ void set_port_type(struct orinoco_private *priv) priv->createibss = 1; } break; - case IW_MODE_MONITOR: + case NL80211_IFTYPE_MONITOR: priv->port_type = 3; priv->createibss = 0; break; @@ -359,7 +359,8 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; } - if (!netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) { + if (!netif_carrier_ok(dev) || + (priv->iw_mode == NL80211_IFTYPE_MONITOR)) { /* Oops, the firmware hasn't established a connection, silently drop the packet (this seems to be the safest approach). */ @@ -820,7 +821,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) } /* Handle frames in monitor mode */ - if (priv->iw_mode == IW_MODE_MONITOR) { + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { orinoco_rx_monitor(dev, rxfid, desc); goto out; } @@ -1331,7 +1332,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) u16 newstatus; int connected; - if (priv->iw_mode == IW_MODE_MONITOR) + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) break; if (len != sizeof(linkstatus)) { @@ -1981,7 +1982,7 @@ int orinoco_init(struct orinoco_private *priv) } /* Set up the default configuration */ - priv->iw_mode = IW_MODE_INFRA; + priv->iw_mode = NL80211_IFTYPE_STATION; /* By default use IEEE/IBSS ad-hoc mode if we have it */ priv->prefer_port3 = priv->has_port3 && (!priv->has_ibss); set_port_type(priv); diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index 4ee85f8f6bc..0c89c281e3e 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -121,7 +121,7 @@ struct orinoco_private { unsigned int broken_monitor:1; /* Configuration paramaters */ - u32 iw_mode; + enum nl80211_iftype iw_mode; int prefer_port3; u16 encode_alg, wep_restrict, tx_key; struct orinoco_key keys[ORINOCO_MAX_KEYS]; diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 4c20b1d5c2a..9cd991a41ad 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -52,7 +52,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) * here so we're not safe to sleep here. */ hermes_inquire(hw, HERMES_INQ_TALLIES); - if (priv->iw_mode == IW_MODE_ADHOC) { + if (priv->iw_mode == NL80211_IFTYPE_ADHOC) { memset(&wstats->qual, 0, sizeof(wstats->qual)); /* If a spy address is defined, we report stats of the * first spy address - Jean II */ @@ -124,7 +124,7 @@ static int orinoco_ioctl_setwap(struct net_device *dev, goto out; } - if (priv->iw_mode != IW_MODE_INFRA) { + if (priv->iw_mode != NL80211_IFTYPE_STATION) { printk(KERN_WARNING "%s: Manual roaming supported only in " "managed mode\n", dev->name); err = -EOPNOTSUPP; @@ -172,65 +172,6 @@ static int orinoco_ioctl_getwap(struct net_device *dev, return err; } -static int orinoco_ioctl_setmode(struct net_device *dev, - struct iw_request_info *info, - u32 *mode, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - int err = -EINPROGRESS; /* Call commit handler */ - unsigned long flags; - - if (priv->iw_mode == *mode) - return 0; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - switch (*mode) { - case IW_MODE_ADHOC: - if (!priv->has_ibss && !priv->has_port3) - err = -EOPNOTSUPP; - break; - - case IW_MODE_INFRA: - break; - - case IW_MODE_MONITOR: - if (priv->broken_monitor && !force_monitor) { - printk(KERN_WARNING "%s: Monitor mode support is " - "buggy in this firmware, not enabling\n", - dev->name); - err = -EOPNOTSUPP; - } - break; - - default: - err = -EOPNOTSUPP; - break; - } - - if (err == -EINPROGRESS) { - priv->iw_mode = *mode; - set_port_type(priv); - } - - orinoco_unlock(priv, &flags); - - return err; -} - -static int orinoco_ioctl_getmode(struct net_device *dev, - struct iw_request_info *info, - u32 *mode, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - - *mode = priv->iw_mode; - return 0; -} - static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_request_info *info, struct iw_point *rrq, @@ -280,7 +221,7 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, if (priv->has_wpa) range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP; - if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))) { + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && (!SPY_NUMBER(priv))) { /* Quality stats meaningless in ad-hoc mode */ } else { range->max_qual.qual = 0x8b - 0x2f; @@ -596,7 +537,7 @@ static int orinoco_ioctl_setfreq(struct net_device *dev, int err = -EINPROGRESS; /* Call commit handler */ /* In infrastructure mode the AP sets the channel */ - if (priv->iw_mode == IW_MODE_INFRA) + if (priv->iw_mode == NL80211_IFTYPE_STATION) return -EBUSY; if ((frq->e == 0) && (frq->m <= 1000)) { @@ -622,7 +563,7 @@ static int orinoco_ioctl_setfreq(struct net_device *dev, return -EBUSY; priv->channel = chan; - if (priv->iw_mode == IW_MODE_MONITOR) { + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { /* Fast channel change - no commit if successful */ hermes_t *hw = &priv->hw; err = hermes_docmd_wait(hw, HERMES_CMD_TEST | @@ -1673,7 +1614,7 @@ static int orinoco_ioctl_setscan(struct net_device *dev, /* In monitor mode, the scan results are always empty. * Probe responses are passed to the driver as received * frames and could be processed in software. */ - if (priv->iw_mode == IW_MODE_MONITOR) { + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { err = -EOPNOTSUPP; goto out; } @@ -2209,8 +2150,8 @@ static const iw_handler orinoco_handler[] = { STD_IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname), STD_IW_HANDLER(SIOCSIWFREQ, orinoco_ioctl_setfreq), STD_IW_HANDLER(SIOCGIWFREQ, orinoco_ioctl_getfreq), - STD_IW_HANDLER(SIOCSIWMODE, orinoco_ioctl_setmode), - STD_IW_HANDLER(SIOCGIWMODE, orinoco_ioctl_getmode), + STD_IW_HANDLER(SIOCSIWMODE, cfg80211_wext_siwmode), + STD_IW_HANDLER(SIOCGIWMODE, cfg80211_wext_giwmode), STD_IW_HANDLER(SIOCSIWSENS, orinoco_ioctl_setsens), STD_IW_HANDLER(SIOCGIWSENS, orinoco_ioctl_getsens), STD_IW_HANDLER(SIOCGIWRANGE, orinoco_ioctl_getiwrange), -- cgit v1.2.3-18-g5258 From c63cdbe8f80487c372fe0dfe460ed30467029f01 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:33 +0100 Subject: orinoco: convert scanning to cfg80211 This removes the custom scan cache used by orinoco. We also have to avoid calling cfg80211_scan_done from the hard interrupt, so we offload the entirety of scan processing to a workqueue. This may behave strangely if you start scanning just prior to suspending... Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/cfg.c | 20 ++ drivers/net/wireless/orinoco/hermes.h | 2 +- drivers/net/wireless/orinoco/hw.c | 85 ++++++ drivers/net/wireless/orinoco/hw.h | 3 + drivers/net/wireless/orinoco/main.c | 167 +++++++---- drivers/net/wireless/orinoco/orinoco.h | 22 +- drivers/net/wireless/orinoco/scan.c | 285 +++++++++--------- drivers/net/wireless/orinoco/scan.h | 21 +- drivers/net/wireless/orinoco/wext.c | 517 +-------------------------------- 9 files changed, 378 insertions(+), 744 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c index 9e59d90b32e..1a87d3a0967 100644 --- a/drivers/net/wireless/orinoco/cfg.c +++ b/drivers/net/wireless/orinoco/cfg.c @@ -137,6 +137,26 @@ static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev, return err; } +static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_scan_request *request) +{ + struct orinoco_private *priv = wiphy_priv(wiphy); + int err; + + if (!request) + return -EINVAL; + + if (priv->scan_request && priv->scan_request != request) + return -EBUSY; + + priv->scan_request = request; + + err = orinoco_hw_trigger_scan(priv, request->ssids); + + return err; +} + const struct cfg80211_ops orinoco_cfg_ops = { .change_virtual_intf = orinoco_change_vif, + .scan = orinoco_scan, }; diff --git a/drivers/net/wireless/orinoco/hermes.h b/drivers/net/wireless/orinoco/hermes.h index c78c442a02c..2dddbb597c4 100644 --- a/drivers/net/wireless/orinoco/hermes.h +++ b/drivers/net/wireless/orinoco/hermes.h @@ -342,7 +342,7 @@ struct agere_ext_scan_info { __le64 timestamp; __le16 beacon_interval; __le16 capabilities; - u8 data[316]; + u8 data[0]; } __attribute__ ((packed)); #define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000) diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 4600fe4a7e1..fa508af1a35 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -1157,3 +1157,88 @@ int orinoco_hw_get_bitratelist(struct orinoco_private *priv, return 0; } + +int orinoco_hw_trigger_scan(struct orinoco_private *priv, + const struct cfg80211_ssid *ssid) +{ + struct net_device *dev = priv->ndev; + hermes_t *hw = &priv->hw; + unsigned long flags; + int err = 0; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + /* Scanning with port 0 disabled would fail */ + if (!netif_running(dev)) { + err = -ENETDOWN; + goto out; + } + + /* In monitor mode, the scan results are always empty. + * Probe responses are passed to the driver as received + * frames and could be processed in software. */ + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { + err = -EOPNOTSUPP; + goto out; + } + + if (priv->has_hostscan) { + switch (priv->firmware_type) { + case FIRMWARE_TYPE_SYMBOL: + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFHOSTSCAN_SYMBOL, + HERMES_HOSTSCAN_SYMBOL_ONCE | + HERMES_HOSTSCAN_SYMBOL_BCAST); + break; + case FIRMWARE_TYPE_INTERSIL: { + __le16 req[3]; + + req[0] = cpu_to_le16(0x3fff); /* All channels */ + req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */ + req[2] = 0; /* Any ESSID */ + err = HERMES_WRITE_RECORD(hw, USER_BAP, + HERMES_RID_CNFHOSTSCAN, &req); + break; + } + case FIRMWARE_TYPE_AGERE: + if (ssid->ssid_len > 0) { + struct hermes_idstring idbuf; + size_t len = ssid->ssid_len; + + idbuf.len = cpu_to_le16(len); + memcpy(idbuf.val, ssid->ssid, len); + + err = hermes_write_ltv(hw, USER_BAP, + HERMES_RID_CNFSCANSSID_AGERE, + HERMES_BYTES_TO_RECLEN(len + 2), + &idbuf); + } else + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFSCANSSID_AGERE, + 0); /* Any ESSID */ + if (err) + break; + + if (priv->has_ext_scan) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFSCANCHANNELS2GHZ, + 0x7FFF); + if (err) + goto out; + + err = hermes_inquire(hw, + HERMES_INQ_CHANNELINFO); + } else + err = hermes_inquire(hw, HERMES_INQ_SCAN); + + break; + } + } else + err = hermes_inquire(hw, HERMES_INQ_SCAN); + + out: + orinoco_unlock(priv, &flags); + + return err; +} diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index 210c2b1b7f9..27b427649d1 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h @@ -7,6 +7,7 @@ #include #include +#include /* Hardware BAPs */ #define USER_BAP 0 @@ -47,5 +48,7 @@ int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, int orinoco_hw_get_freq(struct orinoco_private *priv); int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates, s32 *rates, int max); +int orinoco_hw_trigger_scan(struct orinoco_private *priv, + const struct cfg80211_ssid *ssid); #endif /* _ORINOCO_HW_H_ */ diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index ebf92ae6e36..cd1c04d42b6 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -206,6 +206,13 @@ struct orinoco_rx_data { struct list_head list; }; +struct orinoco_scan_data { + void *buf; + size_t len; + int type; + struct list_head list; +}; + /********************************************************************/ /* Function prototypes */ /********************************************************************/ @@ -1265,6 +1272,78 @@ static void orinoco_send_wevents(struct work_struct *work) orinoco_unlock(priv, &flags); } +static void qbuf_scan(struct orinoco_private *priv, void *buf, + int len, int type) +{ + struct orinoco_scan_data *sd; + unsigned long flags; + + sd = kmalloc(sizeof(*sd), GFP_ATOMIC); + sd->buf = buf; + sd->len = len; + sd->type = type; + + spin_lock_irqsave(&priv->scan_lock, flags); + list_add_tail(&sd->list, &priv->scan_list); + spin_unlock_irqrestore(&priv->scan_lock, flags); + + schedule_work(&priv->process_scan); +} + +static void qabort_scan(struct orinoco_private *priv) +{ + struct orinoco_scan_data *sd; + unsigned long flags; + + sd = kmalloc(sizeof(*sd), GFP_ATOMIC); + sd->len = -1; /* Abort */ + + spin_lock_irqsave(&priv->scan_lock, flags); + list_add_tail(&sd->list, &priv->scan_list); + spin_unlock_irqrestore(&priv->scan_lock, flags); + + schedule_work(&priv->process_scan); +} + +static void orinoco_process_scan_results(struct work_struct *work) +{ + struct orinoco_private *priv = + container_of(work, struct orinoco_private, process_scan); + struct orinoco_scan_data *sd, *temp; + unsigned long flags; + void *buf; + int len; + int type; + + spin_lock_irqsave(&priv->scan_lock, flags); + list_for_each_entry_safe(sd, temp, &priv->scan_list, list) { + spin_unlock_irqrestore(&priv->scan_lock, flags); + + buf = sd->buf; + len = sd->len; + type = sd->type; + + list_del(&sd->list); + kfree(sd); + + if (len > 0) { + if (type == HERMES_INQ_CHANNELINFO) + orinoco_add_extscan_result(priv, buf, len); + else + orinoco_add_hostscan_results(priv, buf, len); + + kfree(buf); + } else if (priv->scan_request) { + /* Either abort or complete the scan */ + cfg80211_scan_done(priv->scan_request, (len < 0)); + priv->scan_request = NULL; + } + + spin_lock_irqsave(&priv->scan_lock, flags); + } + spin_unlock_irqrestore(&priv->scan_lock, flags); +} + static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) { struct orinoco_private *priv = ndev_priv(dev); @@ -1351,7 +1430,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) * the hostscan frame can be requested. */ if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE && priv->firmware_type == FIRMWARE_TYPE_SYMBOL && - priv->has_hostscan && priv->scan_inprogress) { + priv->has_hostscan && priv->scan_request) { hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL); break; } @@ -1377,7 +1456,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) } break; case HERMES_INQ_SCAN: - if (!priv->scan_inprogress && priv->bssid_fixed && + if (!priv->scan_request && priv->bssid_fixed && priv->firmware_type == FIRMWARE_TYPE_INTERSIL) { schedule_work(&priv->join_work); break; @@ -1387,30 +1466,30 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) case HERMES_INQ_HOSTSCAN_SYMBOL: { /* Result of a scanning. Contains information about * cells in the vicinity - Jean II */ - union iwreq_data wrqu; unsigned char *buf; - /* Scan is no longer in progress */ - priv->scan_inprogress = 0; - /* Sanity check */ if (len > 4096) { printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n", dev->name, len); + qabort_scan(priv); break; } /* Allocate buffer for results */ buf = kmalloc(len, GFP_ATOMIC); - if (buf == NULL) + if (buf == NULL) { /* No memory, so can't printk()... */ + qabort_scan(priv); break; + } /* Read scan data */ err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len, infofid, sizeof(info)); if (err) { kfree(buf); + qabort_scan(priv); break; } @@ -1424,24 +1503,14 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) } #endif /* ORINOCO_DEBUG */ - if (orinoco_process_scan_results(priv, buf, len) == 0) { - /* Send an empty event to user space. - * We don't send the received data on the event because - * it would require us to do complex transcoding, and - * we want to minimise the work done in the irq handler - * Use a request to extract the data - Jean II */ - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); - } - kfree(buf); + qbuf_scan(priv, buf, len, type); } break; case HERMES_INQ_CHANNELINFO: { struct agere_ext_scan_info *bss; - if (!priv->scan_inprogress) { + if (!priv->scan_request) { printk(KERN_DEBUG "%s: Got chaninfo without scan, " "len=%d\n", dev->name, len); break; @@ -1449,25 +1518,12 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) /* An empty result indicates that the scan is complete */ if (len == 0) { - union iwreq_data wrqu; - - /* Scan is no longer in progress */ - priv->scan_inprogress = 0; - - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); + qbuf_scan(priv, NULL, len, type); break; } /* Sanity check */ - else if (len > sizeof(*bss)) { - printk(KERN_WARNING - "%s: Ext scan results too large (%d bytes). " - "Truncating results to %zd bytes.\n", - dev->name, len, sizeof(*bss)); - len = sizeof(*bss); - } else if (len < (offsetof(struct agere_ext_scan_info, + else if (len < (offsetof(struct agere_ext_scan_info, data) + 2)) { /* Drop this result now so we don't have to * keep checking later */ @@ -1477,21 +1533,18 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) break; } - bss = kmalloc(sizeof(*bss), GFP_ATOMIC); + bss = kmalloc(len, GFP_ATOMIC); if (bss == NULL) break; /* Read scan data */ err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len, infofid, sizeof(info)); - if (err) { + if (err) kfree(bss); - break; - } - - orinoco_add_ext_scan_result(priv, bss); + else + qbuf_scan(priv, bss, len, type); - kfree(bss); break; } case HERMES_INQ_SEC_STAT_AGERE: @@ -1506,6 +1559,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) /* We don't actually do anything about it */ break; } + + return; } static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) @@ -1649,9 +1704,11 @@ void orinoco_reset(struct work_struct *work) orinoco_unlock(priv, &flags); - /* Scanning support: Cleanup of driver struct */ - orinoco_clear_scan_results(priv, 0); - priv->scan_inprogress = 0; + /* Scanning support: Notify scan cancellation */ + if (priv->scan_request) { + cfg80211_scan_done(priv->scan_request, 1); + priv->scan_request = NULL; + } if (priv->hard_reset) { err = (*priv->hard_reset)(priv); @@ -1965,12 +2022,6 @@ int orinoco_init(struct orinoco_private *priv) } } - /* Now we have the firmware capabilities, allocate appropiate - * sized scan buffers */ - if (orinoco_bss_data_allocate(priv)) - goto out; - orinoco_bss_data_init(priv); - err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr); if (err) goto out; @@ -2100,6 +2151,10 @@ struct orinoco_private tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet, (unsigned long) priv); + spin_lock_init(&priv->scan_lock); + INIT_LIST_HEAD(&priv->scan_list); + INIT_WORK(&priv->process_scan, orinoco_process_scan_results); + priv->last_linkstatus = 0xffff; #if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) @@ -2192,6 +2247,7 @@ void free_orinocodev(struct orinoco_private *priv) { struct wiphy *wiphy = priv_to_wiphy(priv); struct orinoco_rx_data *rx_data, *temp; + struct orinoco_scan_data *sd, *sdtemp; wiphy_unregister(wiphy); @@ -2209,13 +2265,22 @@ void free_orinocodev(struct orinoco_private *priv) kfree(rx_data); } + cancel_work_sync(&priv->process_scan); + /* Explicitly drain priv->scan_list */ + list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) { + list_del(&sd->list); + + if ((sd->len > 0) && sd->buf) + kfree(sd->buf); + kfree(sd); + } + orinoco_unregister_pm_notifier(priv); orinoco_uncache_fw(priv); priv->wpa_ie_len = 0; kfree(priv->wpa_ie); orinoco_mic_free(priv); - orinoco_bss_data_free(priv); wiphy_free(wiphy); } EXPORT_SYMBOL(free_orinocodev); diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index 0c89c281e3e..5f4f5c9eef7 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -48,18 +48,6 @@ typedef enum { FIRMWARE_TYPE_SYMBOL } fwtype_t; -struct bss_element { - union hermes_scan_info bss; - unsigned long last_scanned; - struct list_head list; -}; - -struct xbss_element { - struct agere_ext_scan_info bss; - unsigned long last_scanned; - struct list_head list; -}; - struct firmware; struct orinoco_private { @@ -145,12 +133,10 @@ struct orinoco_private { int promiscuous, mc_count; /* Scanning support */ - struct list_head bss_list; - struct list_head bss_free_list; - void *bss_xbss_data; - - int scan_inprogress; /* Scan pending... */ - u32 scan_mode; /* Type of scan done */ + struct cfg80211_scan_request *scan_request; + struct work_struct process_scan; + struct list_head scan_list; + spinlock_t scan_lock; /* protects the scan list */ /* WPA support */ u8 *wpa_ie; diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c index 89d699d4dfe..522eb98ec6f 100644 --- a/drivers/net/wireless/orinoco/scan.c +++ b/drivers/net/wireless/orinoco/scan.c @@ -5,147 +5,166 @@ #include #include -#include +#include +#include #include "hermes.h" #include "orinoco.h" +#include "main.h" #include "scan.h" -#define ORINOCO_MAX_BSS_COUNT 64 +#define ZERO_DBM_OFFSET 0x95 +#define MAX_SIGNAL_LEVEL 0x8A +#define MIN_SIGNAL_LEVEL 0x2F -#define PRIV_BSS ((struct bss_element *)priv->bss_xbss_data) -#define PRIV_XBSS ((struct xbss_element *)priv->bss_xbss_data) +#define SIGNAL_TO_DBM(x) \ + (clamp_t(s32, (x), MIN_SIGNAL_LEVEL, MAX_SIGNAL_LEVEL) \ + - ZERO_DBM_OFFSET) +#define SIGNAL_TO_MBM(x) (SIGNAL_TO_DBM(x) * 100) -int orinoco_bss_data_allocate(struct orinoco_private *priv) +static int symbol_build_supp_rates(u8 *buf, const __le16 *rates) { - if (priv->bss_xbss_data) - return 0; - - if (priv->has_ext_scan) - priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT * - sizeof(struct xbss_element), - GFP_KERNEL); - else - priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT * - sizeof(struct bss_element), - GFP_KERNEL); - - if (!priv->bss_xbss_data) { - printk(KERN_WARNING "Out of memory allocating beacons"); - return -ENOMEM; + int i; + u8 rate; + + buf[0] = WLAN_EID_SUPP_RATES; + for (i = 0; i < 5; i++) { + rate = le16_to_cpu(rates[i]); + /* NULL terminated */ + if (rate == 0x0) + break; + buf[i + 2] = rate; } - return 0; -} + buf[1] = i; -void orinoco_bss_data_free(struct orinoco_private *priv) -{ - kfree(priv->bss_xbss_data); - priv->bss_xbss_data = NULL; + return i + 2; } -void orinoco_bss_data_init(struct orinoco_private *priv) +static int prism_build_supp_rates(u8 *buf, const u8 *rates) { int i; - INIT_LIST_HEAD(&priv->bss_free_list); - INIT_LIST_HEAD(&priv->bss_list); - if (priv->has_ext_scan) - for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++) - list_add_tail(&(PRIV_XBSS[i].list), - &priv->bss_free_list); - else - for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++) - list_add_tail(&(PRIV_BSS[i].list), - &priv->bss_free_list); - -} - -void orinoco_clear_scan_results(struct orinoco_private *priv, - unsigned long scan_age) -{ - if (priv->has_ext_scan) { - struct xbss_element *bss; - struct xbss_element *tmp_bss; - - /* Blow away current list of scan results */ - list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) { - if (!scan_age || - time_after(jiffies, bss->last_scanned + scan_age)) { - list_move_tail(&bss->list, - &priv->bss_free_list); - /* Don't blow away ->list, just BSS data */ - memset(&bss->bss, 0, sizeof(bss->bss)); - bss->last_scanned = 0; - } - } - } else { - struct bss_element *bss; - struct bss_element *tmp_bss; - - /* Blow away current list of scan results */ - list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) { - if (!scan_age || - time_after(jiffies, bss->last_scanned + scan_age)) { - list_move_tail(&bss->list, - &priv->bss_free_list); - /* Don't blow away ->list, just BSS data */ - memset(&bss->bss, 0, sizeof(bss->bss)); - bss->last_scanned = 0; - } + buf[0] = WLAN_EID_SUPP_RATES; + for (i = 0; i < 8; i++) { + /* NULL terminated */ + if (rates[i] == 0x0) + break; + buf[i + 2] = rates[i]; + } + buf[1] = i; + + /* We might still have another 2 rates, which need to go in + * extended supported rates */ + if (i == 8 && rates[i] > 0) { + buf[10] = WLAN_EID_EXT_SUPP_RATES; + for (; i < 10; i++) { + /* NULL terminated */ + if (rates[i] == 0x0) + break; + buf[i + 2] = rates[i]; } + buf[11] = i - 8; } + + return (i < 8) ? i + 2 : i + 4; } -void orinoco_add_ext_scan_result(struct orinoco_private *priv, - struct agere_ext_scan_info *atom) +static void orinoco_add_hostscan_result(struct orinoco_private *priv, + const union hermes_scan_info *bss) { - struct xbss_element *bss = NULL; - int found = 0; - - /* Try to update an existing bss first */ - list_for_each_entry(bss, &priv->bss_list, list) { - if (compare_ether_addr(bss->bss.bssid, atom->bssid)) - continue; - /* ESSID lengths */ - if (bss->bss.data[1] != atom->data[1]) - continue; - if (memcmp(&bss->bss.data[2], &atom->data[2], - atom->data[1])) - continue; - found = 1; + struct wiphy *wiphy = priv_to_wiphy(priv); + struct ieee80211_channel *channel; + u8 *ie; + u8 ie_buf[46]; + u64 timestamp; + s32 signal; + u16 capability; + u16 beacon_interval; + int ie_len; + int freq; + int len; + + len = le16_to_cpu(bss->a.essid_len); + + /* Reconstruct SSID and bitrate IEs to pass up */ + ie_buf[0] = WLAN_EID_SSID; + ie_buf[1] = len; + memcpy(&ie_buf[2], bss->a.essid, len); + + ie = ie_buf + len + 2; + ie_len = ie_buf[1] + 2; + switch (priv->firmware_type) { + case FIRMWARE_TYPE_SYMBOL: + ie_len += symbol_build_supp_rates(ie, bss->s.rates); break; - } - /* Grab a bss off the free list */ - if (!found && !list_empty(&priv->bss_free_list)) { - bss = list_entry(priv->bss_free_list.next, - struct xbss_element, list); - list_del(priv->bss_free_list.next); + case FIRMWARE_TYPE_INTERSIL: + ie_len += prism_build_supp_rates(ie, bss->p.rates); + break; - list_add_tail(&bss->list, &priv->bss_list); + case FIRMWARE_TYPE_AGERE: + default: + break; } - if (bss) { - /* Always update the BSS to get latest beacon info */ - memcpy(&bss->bss, atom, sizeof(bss->bss)); - bss->last_scanned = jiffies; - } + freq = ieee80211_dsss_chan_to_freq(le16_to_cpu(bss->a.channel)); + channel = ieee80211_get_channel(wiphy, freq); + timestamp = 0; + capability = le16_to_cpu(bss->a.capabilities); + beacon_interval = le16_to_cpu(bss->a.beacon_interv); + signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level)); + + cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp, + capability, beacon_interval, ie_buf, ie_len, + signal, GFP_KERNEL); } -int orinoco_process_scan_results(struct orinoco_private *priv, - unsigned char *buf, - int len) +void orinoco_add_extscan_result(struct orinoco_private *priv, + struct agere_ext_scan_info *bss, + size_t len) { - int offset; /* In the scan data */ - union hermes_scan_info *atom; - int atom_len; + struct wiphy *wiphy = priv_to_wiphy(priv); + struct ieee80211_channel *channel; + u8 *ie; + u64 timestamp; + s32 signal; + u16 capability; + u16 beacon_interval; + size_t ie_len; + int chan, freq; + + ie_len = len - sizeof(*bss); + ie = orinoco_get_ie(bss->data, ie_len, WLAN_EID_DS_PARAMS); + chan = ie ? ie[2] : 0; + freq = ieee80211_dsss_chan_to_freq(chan); + channel = ieee80211_get_channel(wiphy, freq); + + timestamp = le64_to_cpu(bss->timestamp); + capability = le16_to_cpu(bss->capabilities); + beacon_interval = le16_to_cpu(bss->beacon_interval); + ie = bss->data; + signal = SIGNAL_TO_MBM(bss->level); + + cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp, + capability, beacon_interval, ie, ie_len, + signal, GFP_KERNEL); +} + +void orinoco_add_hostscan_results(struct orinoco_private *priv, + unsigned char *buf, + size_t len) +{ + int offset; /* In the scan data */ + size_t atom_len; + bool abort = false; switch (priv->firmware_type) { case FIRMWARE_TYPE_AGERE: atom_len = sizeof(struct agere_scan_apinfo); offset = 0; break; + case FIRMWARE_TYPE_SYMBOL: /* Lack of documentation necessitates this hack. * Different firmwares have 68 or 76 byte long atoms. @@ -163,6 +182,7 @@ int orinoco_process_scan_results(struct orinoco_private *priv, atom_len = 68; offset = 0; break; + case FIRMWARE_TYPE_INTERSIL: offset = 4; if (priv->has_hostscan) { @@ -172,13 +192,16 @@ int orinoco_process_scan_results(struct orinoco_private *priv, printk(KERN_ERR "%s: Invalid atom_len in scan " "data: %d\n", priv->ndev->name, atom_len); - return -EIO; + abort = true; + goto scan_abort; } } else atom_len = offsetof(struct prism2_scan_apinfo, atim); break; + default: - return -EOPNOTSUPP; + abort = true; + goto scan_abort; } /* Check that we got an whole number of atoms */ @@ -186,48 +209,22 @@ int orinoco_process_scan_results(struct orinoco_private *priv, printk(KERN_ERR "%s: Unexpected scan data length %d, " "atom_len %d, offset %d\n", priv->ndev->name, len, atom_len, offset); - return -EIO; + abort = true; + goto scan_abort; } - orinoco_clear_scan_results(priv, msecs_to_jiffies(15000)); - - /* Read the entries one by one */ + /* Process the entries one by one */ for (; offset + atom_len <= len; offset += atom_len) { - int found = 0; - struct bss_element *bss = NULL; + union hermes_scan_info *atom; - /* Get next atom */ atom = (union hermes_scan_info *) (buf + offset); - /* Try to update an existing bss first */ - list_for_each_entry(bss, &priv->bss_list, list) { - if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid)) - continue; - if (le16_to_cpu(bss->bss.a.essid_len) != - le16_to_cpu(atom->a.essid_len)) - continue; - if (memcmp(bss->bss.a.essid, atom->a.essid, - le16_to_cpu(atom->a.essid_len))) - continue; - found = 1; - break; - } - - /* Grab a bss off the free list */ - if (!found && !list_empty(&priv->bss_free_list)) { - bss = list_entry(priv->bss_free_list.next, - struct bss_element, list); - list_del(priv->bss_free_list.next); - - list_add_tail(&bss->list, &priv->bss_list); - } - - if (bss) { - /* Always update the BSS to get latest beacon info */ - memcpy(&bss->bss, atom, sizeof(bss->bss)); - bss->last_scanned = jiffies; - } + orinoco_add_hostscan_result(priv, atom); } - return 0; + scan_abort: + if (priv->scan_request) { + cfg80211_scan_done(priv->scan_request, abort); + priv->scan_request = NULL; + } } diff --git a/drivers/net/wireless/orinoco/scan.h b/drivers/net/wireless/orinoco/scan.h index f319f7466af..2dc4e046dbd 100644 --- a/drivers/net/wireless/orinoco/scan.h +++ b/drivers/net/wireless/orinoco/scan.h @@ -9,21 +9,12 @@ struct orinoco_private; struct agere_ext_scan_info; -/* Setup and free memory for scan results */ -int orinoco_bss_data_allocate(struct orinoco_private *priv); -void orinoco_bss_data_free(struct orinoco_private *priv); -void orinoco_bss_data_init(struct orinoco_private *priv); - /* Add scan results */ -void orinoco_add_ext_scan_result(struct orinoco_private *priv, - struct agere_ext_scan_info *atom); -int orinoco_process_scan_results(struct orinoco_private *dev, - unsigned char *buf, - int len); - -/* Clear scan results */ -void orinoco_clear_scan_results(struct orinoco_private *priv, - unsigned long scan_age); - +void orinoco_add_extscan_result(struct orinoco_private *priv, + struct agere_ext_scan_info *atom, + size_t len); +void orinoco_add_hostscan_results(struct orinoco_private *dev, + unsigned char *buf, + size_t len); #endif /* _ORINOCO_SCAN_H_ */ diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 9cd991a41ad..082ea0a0cc9 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -1583,519 +1583,6 @@ static int orinoco_ioctl_getrid(struct net_device *dev, return err; } -/* Trigger a scan (look for other cells in the vicinity) */ -static int orinoco_ioctl_setscan(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *srq, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - hermes_t *hw = &priv->hw; - struct iw_scan_req *si = (struct iw_scan_req *) extra; - int err = 0; - unsigned long flags; - - /* Note : you may have realised that, as this is a SET operation, - * this is privileged and therefore a normal user can't - * perform scanning. - * This is not an error, while the device perform scanning, - * traffic doesn't flow, so it's a perfect DoS... - * Jean II */ - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - /* Scanning with port 0 disabled would fail */ - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } - - /* In monitor mode, the scan results are always empty. - * Probe responses are passed to the driver as received - * frames and could be processed in software. */ - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { - err = -EOPNOTSUPP; - goto out; - } - - /* Note : because we don't lock out the irq handler, the way - * we access scan variables in priv is critical. - * o scan_inprogress : not touched by irq handler - * o scan_mode : not touched by irq handler - * Before modifying anything on those variables, please think hard ! - * Jean II */ - - /* Save flags */ - priv->scan_mode = srq->flags; - - /* Always trigger scanning, even if it's in progress. - * This way, if the info frame get lost, we will recover somewhat - * gracefully - Jean II */ - - if (priv->has_hostscan) { - switch (priv->firmware_type) { - case FIRMWARE_TYPE_SYMBOL: - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFHOSTSCAN_SYMBOL, - HERMES_HOSTSCAN_SYMBOL_ONCE | - HERMES_HOSTSCAN_SYMBOL_BCAST); - break; - case FIRMWARE_TYPE_INTERSIL: { - __le16 req[3]; - - req[0] = cpu_to_le16(0x3fff); /* All channels */ - req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */ - req[2] = 0; /* Any ESSID */ - err = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFHOSTSCAN, &req); - } - break; - case FIRMWARE_TYPE_AGERE: - if (priv->scan_mode & IW_SCAN_THIS_ESSID) { - struct hermes_idstring idbuf; - size_t len = min(sizeof(idbuf.val), - (size_t) si->essid_len); - idbuf.len = cpu_to_le16(len); - memcpy(idbuf.val, si->essid, len); - - err = hermes_write_ltv(hw, USER_BAP, - HERMES_RID_CNFSCANSSID_AGERE, - HERMES_BYTES_TO_RECLEN(len + 2), - &idbuf); - } else - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSCANSSID_AGERE, - 0); /* Any ESSID */ - if (err) - break; - - if (priv->has_ext_scan) { - /* Clear scan results at the start of - * an extended scan */ - orinoco_clear_scan_results(priv, - msecs_to_jiffies(15000)); - - /* TODO: Is this available on older firmware? - * Can we use it to scan specific channels - * for IW_SCAN_THIS_FREQ? */ - err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNFSCANCHANNELS2GHZ, - 0x7FFF); - if (err) - goto out; - - err = hermes_inquire(hw, - HERMES_INQ_CHANNELINFO); - } else - err = hermes_inquire(hw, HERMES_INQ_SCAN); - break; - } - } else - err = hermes_inquire(hw, HERMES_INQ_SCAN); - - /* One more client */ - if (!err) - priv->scan_inprogress = 1; - - out: - orinoco_unlock(priv, &flags); - return err; -} - -#define MAX_CUSTOM_LEN 64 - -/* Translate scan data returned from the card to a card independant - * format that the Wireless Tools will understand - Jean II */ -static inline char *orinoco_translate_scan(struct net_device *dev, - struct iw_request_info *info, - char *current_ev, - char *end_buf, - union hermes_scan_info *bss, - unsigned long last_scanned) -{ - struct orinoco_private *priv = ndev_priv(dev); - u16 capabilities; - u16 channel; - struct iw_event iwe; /* Temporary buffer */ - char custom[MAX_CUSTOM_LEN]; - - memset(&iwe, 0, sizeof(iwe)); - - /* First entry *MUST* be the AP MAC address */ - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_ADDR_LEN); - - /* Other entries will be displayed in the order we give them */ - - /* Add the ESSID */ - iwe.u.data.length = le16_to_cpu(bss->a.essid_len); - if (iwe.u.data.length > 32) - iwe.u.data.length = 32; - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->a.essid); - - /* Add mode */ - iwe.cmd = SIOCGIWMODE; - capabilities = le16_to_cpu(bss->a.capabilities); - if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { - if (capabilities & WLAN_CAPABILITY_ESS) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_ADHOC; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_UINT_LEN); - } - - channel = bss->s.channel; - if ((channel >= 1) && (channel <= NUM_CHANNELS)) { - /* Add channel and frequency */ - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = channel; - iwe.u.freq.e = 0; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_FREQ_LEN); - - iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000; - iwe.u.freq.e = 1; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_FREQ_LEN); - } - - /* Add quality statistics. level and noise in dB. No link quality */ - iwe.cmd = IWEVQUAL; - iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID; - iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95; - iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95; - /* Wireless tools prior to 27.pre22 will show link quality - * anyway, so we provide a reasonable value. */ - if (iwe.u.qual.level > iwe.u.qual.noise) - iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; - else - iwe.u.qual.qual = 0; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_QUAL_LEN); - - /* Add encryption capability */ - iwe.cmd = SIOCGIWENCODE; - if (capabilities & WLAN_CAPABILITY_PRIVACY) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, NULL); - - /* Bit rate is not available in Lucent/Agere firmwares */ - if (priv->firmware_type != FIRMWARE_TYPE_AGERE) { - char *current_val = current_ev + iwe_stream_lcp_len(info); - int i; - int step; - - if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) - step = 2; - else - step = 1; - - iwe.cmd = SIOCGIWRATE; - /* Those two flags are ignored... */ - iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; - /* Max 10 values */ - for (i = 0; i < 10; i += step) { - /* NULL terminated */ - if (bss->p.rates[i] == 0x0) - break; - /* Bit rate given in 500 kb/s units (+ 0x80) */ - iwe.u.bitrate.value = - ((bss->p.rates[i] & 0x7f) * 500000); - current_val = iwe_stream_add_value(info, current_ev, - current_val, - end_buf, &iwe, - IW_EV_PARAM_LEN); - } - /* Check if we added any event */ - if ((current_val - current_ev) > iwe_stream_lcp_len(info)) - current_ev = current_val; - } - - /* Beacon interval */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, - "bcn_int=%d", - le16_to_cpu(bss->a.beacon_interv)); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - /* Capabilites */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, - "capab=0x%04x", - capabilities); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - /* Add EXTRA: Age to display seconds since last beacon/probe response - * for given network. */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, - " Last beacon: %dms ago", - jiffies_to_msecs(jiffies - last_scanned)); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - return current_ev; -} - -static inline char *orinoco_translate_ext_scan(struct net_device *dev, - struct iw_request_info *info, - char *current_ev, - char *end_buf, - struct agere_ext_scan_info *bss, - unsigned long last_scanned) -{ - u16 capabilities; - u16 channel; - struct iw_event iwe; /* Temporary buffer */ - char custom[MAX_CUSTOM_LEN]; - u8 *ie; - - memset(&iwe, 0, sizeof(iwe)); - - /* First entry *MUST* be the AP MAC address */ - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_ADDR_LEN); - - /* Other entries will be displayed in the order we give them */ - - /* Add the ESSID */ - ie = bss->data; - iwe.u.data.length = ie[1]; - if (iwe.u.data.length) { - if (iwe.u.data.length > 32) - iwe.u.data.length = 32; - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, &ie[2]); - } - - /* Add mode */ - capabilities = le16_to_cpu(bss->capabilities); - if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { - iwe.cmd = SIOCGIWMODE; - if (capabilities & WLAN_CAPABILITY_ESS) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_ADHOC; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_UINT_LEN); - } - - ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_DS_PARAMS); - channel = ie ? ie[2] : 0; - if ((channel >= 1) && (channel <= NUM_CHANNELS)) { - /* Add channel and frequency */ - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = channel; - iwe.u.freq.e = 0; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_FREQ_LEN); - - iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000; - iwe.u.freq.e = 1; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_FREQ_LEN); - } - - /* Add quality statistics. level and noise in dB. No link quality */ - iwe.cmd = IWEVQUAL; - iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID; - iwe.u.qual.level = bss->level - 0x95; - iwe.u.qual.noise = bss->noise - 0x95; - /* Wireless tools prior to 27.pre22 will show link quality - * anyway, so we provide a reasonable value. */ - if (iwe.u.qual.level > iwe.u.qual.noise) - iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; - else - iwe.u.qual.qual = 0; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_QUAL_LEN); - - /* Add encryption capability */ - iwe.cmd = SIOCGIWENCODE; - if (capabilities & WLAN_CAPABILITY_PRIVACY) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, NULL); - - /* WPA IE */ - ie = orinoco_get_wpa_ie(bss->data, sizeof(bss->data)); - if (ie) { - iwe.cmd = IWEVGENIE; - iwe.u.data.length = ie[1] + 2; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, ie); - } - - /* RSN IE */ - ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_RSN); - if (ie) { - iwe.cmd = IWEVGENIE; - iwe.u.data.length = ie[1] + 2; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, ie); - } - - ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_SUPP_RATES); - if (ie) { - char *p = current_ev + iwe_stream_lcp_len(info); - int i; - - iwe.cmd = SIOCGIWRATE; - /* Those two flags are ignored... */ - iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; - - for (i = 2; i < (ie[1] + 2); i++) { - iwe.u.bitrate.value = ((ie[i] & 0x7F) * 500000); - p = iwe_stream_add_value(info, current_ev, p, end_buf, - &iwe, IW_EV_PARAM_LEN); - } - /* Check if we added any event */ - if (p > (current_ev + iwe_stream_lcp_len(info))) - current_ev = p; - } - - /* Timestamp */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = - snprintf(custom, MAX_CUSTOM_LEN, "tsf=%016llx", - (unsigned long long) le64_to_cpu(bss->timestamp)); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - /* Beacon interval */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, - "bcn_int=%d", - le16_to_cpu(bss->beacon_interval)); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - /* Capabilites */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, - "capab=0x%04x", - capabilities); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - /* Add EXTRA: Age to display seconds since last beacon/probe response - * for given network. */ - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, - " Last beacon: %dms ago", - jiffies_to_msecs(jiffies - last_scanned)); - if (iwe.u.data.length) - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, custom); - - return current_ev; -} - -/* Return results of a scan */ -static int orinoco_ioctl_getscan(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *srq, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - int err = 0; - unsigned long flags; - char *current_ev = extra; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - if (priv->scan_inprogress) { - /* Important note : we don't want to block the caller - * until results are ready for various reasons. - * First, managing wait queues is complex and racy. - * Second, we grab some rtnetlink lock before comming - * here (in dev_ioctl()). - * Third, we generate an Wireless Event, so the - * caller can wait itself on that - Jean II */ - err = -EAGAIN; - goto out; - } - - if (priv->has_ext_scan) { - struct xbss_element *bss; - - list_for_each_entry(bss, &priv->bss_list, list) { - /* Translate this entry to WE format */ - current_ev = - orinoco_translate_ext_scan(dev, info, - current_ev, - extra + srq->length, - &bss->bss, - bss->last_scanned); - - /* Check if there is space for one more entry */ - if ((extra + srq->length - current_ev) - <= IW_EV_ADDR_LEN) { - /* Ask user space to try again with a - * bigger buffer */ - err = -E2BIG; - goto out; - } - } - - } else { - struct bss_element *bss; - - list_for_each_entry(bss, &priv->bss_list, list) { - /* Translate this entry to WE format */ - current_ev = orinoco_translate_scan(dev, info, - current_ev, - extra + srq->length, - &bss->bss, - bss->last_scanned); - - /* Check if there is space for one more entry */ - if ((extra + srq->length - current_ev) - <= IW_EV_ADDR_LEN) { - /* Ask user space to try again with a - * bigger buffer */ - err = -E2BIG; - goto out; - } - } - } - - srq->length = (current_ev - extra); - srq->flags = (__u16) priv->scan_mode; - -out: - orinoco_unlock(priv, &flags); - return err; -} /* Commit handler, called after set operations */ static int orinoco_ioctl_commit(struct net_device *dev, @@ -2161,8 +1648,8 @@ static const iw_handler orinoco_handler[] = { STD_IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), STD_IW_HANDLER(SIOCSIWAP, orinoco_ioctl_setwap), STD_IW_HANDLER(SIOCGIWAP, orinoco_ioctl_getwap), - STD_IW_HANDLER(SIOCSIWSCAN, orinoco_ioctl_setscan), - STD_IW_HANDLER(SIOCGIWSCAN, orinoco_ioctl_getscan), + STD_IW_HANDLER(SIOCSIWSCAN, cfg80211_wext_siwscan), + STD_IW_HANDLER(SIOCGIWSCAN, cfg80211_wext_giwscan), STD_IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid), STD_IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid), STD_IW_HANDLER(SIOCSIWNICKN, orinoco_ioctl_setnick), -- cgit v1.2.3-18-g5258 From 934fd51a94572bcdeea5150ba6a0148971ea9980 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:34 +0100 Subject: orinoco: convert giwrange to cfg80211 Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/wext.c | 115 +----------------------------------- 1 file changed, 1 insertion(+), 114 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 082ea0a0cc9..21db57815dd 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -172,119 +172,6 @@ static int orinoco_ioctl_getwap(struct net_device *dev, return err; } -static int orinoco_ioctl_getiwrange(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *rrq, - char *extra) -{ - struct orinoco_private *priv = ndev_priv(dev); - int err = 0; - struct iw_range *range = (struct iw_range *) extra; - int numrates; - int i, k; - - rrq->length = sizeof(struct iw_range); - memset(range, 0, sizeof(struct iw_range)); - - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 22; - - /* Set available channels/frequencies */ - range->num_channels = NUM_CHANNELS; - k = 0; - for (i = 0; i < NUM_CHANNELS; i++) { - if (priv->channel_mask & (1 << i)) { - range->freq[k].i = i + 1; - range->freq[k].m = (ieee80211_dsss_chan_to_freq(i + 1) * - 100000); - range->freq[k].e = 1; - k++; - } - - if (k >= IW_MAX_FREQUENCIES) - break; - } - range->num_frequency = k; - range->sensitivity = 3; - - if (priv->has_wep) { - range->max_encoding_tokens = ORINOCO_MAX_KEYS; - range->encoding_size[0] = SMALL_KEY_SIZE; - range->num_encoding_sizes = 1; - - if (priv->has_big_wep) { - range->encoding_size[1] = LARGE_KEY_SIZE; - range->num_encoding_sizes = 2; - } - } - - if (priv->has_wpa) - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP; - - if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && (!SPY_NUMBER(priv))) { - /* Quality stats meaningless in ad-hoc mode */ - } else { - range->max_qual.qual = 0x8b - 0x2f; - range->max_qual.level = 0x2f - 0x95 - 1; - range->max_qual.noise = 0x2f - 0x95 - 1; - /* Need to get better values */ - range->avg_qual.qual = 0x24; - range->avg_qual.level = 0xC2; - range->avg_qual.noise = 0x9E; - } - - err = orinoco_hw_get_bitratelist(priv, &numrates, - range->bitrate, IW_MAX_BITRATES); - if (err) - return err; - range->num_bitrates = numrates; - - /* Set an indication of the max TCP throughput in bit/s that we can - * expect using this interface. May be use for QoS stuff... - * Jean II */ - if (numrates > 2) - range->throughput = 5 * 1000 * 1000; /* ~5 Mb/s */ - else - range->throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */ - - range->min_rts = 0; - range->max_rts = 2347; - range->min_frag = 256; - range->max_frag = 2346; - - range->min_pmp = 0; - range->max_pmp = 65535000; - range->min_pmt = 0; - range->max_pmt = 65535 * 1000; /* ??? */ - range->pmp_flags = IW_POWER_PERIOD; - range->pmt_flags = IW_POWER_TIMEOUT; - range->pm_capa = (IW_POWER_PERIOD | IW_POWER_TIMEOUT | - IW_POWER_UNICAST_R); - - range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; - range->retry_flags = IW_RETRY_LIMIT; - range->r_time_flags = IW_RETRY_LIFETIME; - range->min_retry = 0; - range->max_retry = 65535; /* ??? */ - range->min_r_time = 0; - range->max_r_time = 65535 * 1000; /* ??? */ - - if (priv->firmware_type == FIRMWARE_TYPE_AGERE) - range->scan_capa = IW_SCAN_CAPA_ESSID; - else - range->scan_capa = IW_SCAN_CAPA_NONE; - - /* Event capability (kernel) */ - IW_EVENT_CAPA_SET_KERNEL(range->event_capa); - /* Event capability (driver) */ - IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY); - IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); - IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); - IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP); - - return 0; -} - static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, @@ -1641,7 +1528,7 @@ static const iw_handler orinoco_handler[] = { STD_IW_HANDLER(SIOCGIWMODE, cfg80211_wext_giwmode), STD_IW_HANDLER(SIOCSIWSENS, orinoco_ioctl_setsens), STD_IW_HANDLER(SIOCGIWSENS, orinoco_ioctl_getsens), - STD_IW_HANDLER(SIOCGIWRANGE, orinoco_ioctl_getiwrange), + STD_IW_HANDLER(SIOCGIWRANGE, cfg80211_wext_giwrange), STD_IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), STD_IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), STD_IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), -- cgit v1.2.3-18-g5258 From b5c469108935bacfe6f45005867256801832fdce Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 18 Jun 2009 23:21:35 +0100 Subject: orinoco: remove WE nickname support Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/wext.c | 43 ------------------------------------- 1 file changed, 43 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 21db57815dd..b6ff3dbb7dd 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -372,47 +372,6 @@ static int orinoco_ioctl_getessid(struct net_device *dev, return 0; } -static int orinoco_ioctl_setnick(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *nrq, - char *nickbuf) -{ - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - - if (nrq->length > IW_ESSID_MAX_SIZE) - return -E2BIG; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - memset(priv->nick, 0, sizeof(priv->nick)); - memcpy(priv->nick, nickbuf, nrq->length); - - orinoco_unlock(priv, &flags); - - return -EINPROGRESS; /* Call commit handler */ -} - -static int orinoco_ioctl_getnick(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *nrq, - char *nickbuf) -{ - struct orinoco_private *priv = ndev_priv(dev); - unsigned long flags; - - if (orinoco_lock(priv, &flags) != 0) - return -EBUSY; - - memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE); - orinoco_unlock(priv, &flags); - - nrq->length = strlen(priv->nick); - - return 0; -} - static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *frq, @@ -1539,8 +1498,6 @@ static const iw_handler orinoco_handler[] = { STD_IW_HANDLER(SIOCGIWSCAN, cfg80211_wext_giwscan), STD_IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid), STD_IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid), - STD_IW_HANDLER(SIOCSIWNICKN, orinoco_ioctl_setnick), - STD_IW_HANDLER(SIOCGIWNICKN, orinoco_ioctl_getnick), STD_IW_HANDLER(SIOCSIWRATE, orinoco_ioctl_setrate), STD_IW_HANDLER(SIOCGIWRATE, orinoco_ioctl_getrate), STD_IW_HANDLER(SIOCSIWRTS, orinoco_ioctl_setrts), -- cgit v1.2.3-18-g5258 From b7351a003ca29ac4372393040ffb06dc04309e2e Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 19 Jun 2009 12:17:47 +0200 Subject: ath9k: remove unnecessary clearing of SC_OP_WAIT_{BEACON,CAB} flags All SC_OP_WAIT_* flags will be cleared in 'ath9k_conf' when PS mode is disabled, so we don't have to clear it here. Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index c00b9051bb5..385bd4cd550 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -528,14 +528,6 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) ath_beacon_config(sc, NULL); } - if (!(sc->hw->conf.flags & IEEE80211_CONF_PS)) { - /* We are not in PS mode anymore; remain awake */ - DPRINTF(sc, ATH_DBG_PS, "Not in PS mode anymore, remain " - "awake\n"); - sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB); - return; - } - if (ath_beacon_dtim_pending_cab(skb)) { /* * Remain awake waiting for buffered broadcast/multicast -- cgit v1.2.3-18-g5258 From 293dc5dfdbcc16cde06e40a688394cc8ab083e48 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 19 Jun 2009 12:17:48 +0200 Subject: ath9k: remove ath_rx_ps_back_to_sleep helper This helper only clears the SC_OP_WAIT_FOR_{BEACON,CAB} flags. Remove it and clear these flags directly in the approptiate places instead. Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 385bd4cd550..2b2872baaa3 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -505,11 +505,6 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) return false; } -static void ath_rx_ps_back_to_sleep(struct ath_softc *sc) -{ - sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB); -} - static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) { struct ieee80211_mgmt *mgmt; @@ -521,6 +516,8 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) if (memcmp(sc->curbssid, mgmt->bssid, ETH_ALEN) != 0) return; /* not from our current AP */ + sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; + if (sc->sc_flags & SC_OP_BEACON_SYNC) { sc->sc_flags &= ~SC_OP_BEACON_SYNC; DPRINTF(sc, ATH_DBG_PS, "Reconfigure Beacon timers based on " @@ -548,11 +545,9 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) * fails to send a frame indicating that all CAB frames have * been delivered. */ + sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB; DPRINTF(sc, ATH_DBG_PS, "PS wait for CAB frames timed out\n"); } - - /* No more broadcast/multicast frames to be received at this point. */ - ath_rx_ps_back_to_sleep(sc); } static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) @@ -570,13 +565,13 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) ieee80211_is_action(hdr->frame_control)) && is_multicast_ether_addr(hdr->addr1) && !ieee80211_has_moredata(hdr->frame_control)) { - DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to " - "sleep\n"); /* * No more broadcast/multicast frames to be received at this * point. */ - ath_rx_ps_back_to_sleep(sc); + sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB; + DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to " + "sleep\n"); } else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) && !is_multicast_ether_addr(hdr->addr1) && !ieee80211_has_morefrags(hdr->frame_control)) { -- cgit v1.2.3-18-g5258 From c0acf38e0ba42f93d8d56a6db2e2116ea1b23961 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 30 Jun 2009 16:55:52 -0400 Subject: mac80211_hwsim: fix-up build damage from removal of skb->dst Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 1b59edc916c..93c1c4a73e6 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -413,8 +413,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, /* release the skb's source info */ skb_orphan(skb); - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); skb->mark = 0; secpath_reset(skb); nf_reset(skb); -- cgit v1.2.3-18-g5258 From aff89a9b9084931e51b89d8f3ee3c547bea6c422 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:51 +0200 Subject: cfg80211: introduce nl80211 testmode command This introduces a new NL80211_CMD_TESTMODE for testing and calibration use with nl80211. There's no multiplexing like like iwpriv had, and the command is not available by default, it needs to be explicitly enabled in Kconfig and shouldn't be enabled in most kernels. The command requires a wiphy index or interface index to identify the device to operate on, and the new TESTDATA attribute. There also is API for sending replies to the command, and testmode multicast messages (on a testmode multicast group). I've also updated mac80211 to be able to pass through the command to the driver, since it itself doesn't implement the testmode command. Additionally, to give people an idea of how to use the command, I've added a little code to hwsim that makes use of the new command to set the powersave mode, this is currently done via debugfs and should remain there, and the testmode command only serves as an example of how to use this best -- with nested netlink attributes in the TESTDATA attribute. A hwsim testmode tool can be found at http://git.sipsolutions.net/hwsim.git/. This tool is BSD licensed so people can easily use it as a basis for their own internal fabrication and validation tools. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 68 +++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 93c1c4a73e6..6ac8565072e 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -700,6 +700,73 @@ static int mac80211_hwsim_conf_tx( return 0; } +#ifdef CONFIG_NL80211_TESTMODE +/* + * This section contains example code for using netlink + * attributes with the testmode command in nl80211. + */ + +/* These enums need to be kept in sync with userspace */ +enum hwsim_testmode_attr { + __HWSIM_TM_ATTR_INVALID = 0, + HWSIM_TM_ATTR_CMD = 1, + HWSIM_TM_ATTR_PS = 2, + + /* keep last */ + __HWSIM_TM_ATTR_AFTER_LAST, + HWSIM_TM_ATTR_MAX = __HWSIM_TM_ATTR_AFTER_LAST - 1 +}; + +enum hwsim_testmode_cmd { + HWSIM_TM_CMD_SET_PS = 0, + HWSIM_TM_CMD_GET_PS = 1, +}; + +static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = { + [HWSIM_TM_ATTR_CMD] = { .type = NLA_U32 }, + [HWSIM_TM_ATTR_PS] = { .type = NLA_U32 }, +}; + +static int hwsim_fops_ps_write(void *dat, u64 val); + +int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) +{ + struct mac80211_hwsim_data *hwsim = hw->priv; + struct nlattr *tb[HWSIM_TM_ATTR_MAX + 1]; + struct sk_buff *skb; + int err, ps; + + err = nla_parse(tb, HWSIM_TM_ATTR_MAX, data, len, + hwsim_testmode_policy); + if (err) + return err; + + if (!tb[HWSIM_TM_ATTR_CMD]) + return -EINVAL; + + switch (nla_get_u32(tb[HWSIM_TM_ATTR_CMD])) { + case HWSIM_TM_CMD_SET_PS: + if (!tb[HWSIM_TM_ATTR_PS]) + return -EINVAL; + ps = nla_get_u32(tb[HWSIM_TM_ATTR_PS]); + return hwsim_fops_ps_write(hwsim, ps); + case HWSIM_TM_CMD_GET_PS: + skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, + nla_total_size(sizeof(u32))); + if (!skb) + return -ENOMEM; + NLA_PUT_U32(skb, HWSIM_TM_ATTR_PS, hwsim->ps); + return cfg80211_testmode_reply(skb); + default: + return -EOPNOTSUPP; + } + + nla_put_failure: + kfree_skb(skb); + return -ENOBUFS; +} +#endif + static const struct ieee80211_ops mac80211_hwsim_ops = { .tx = mac80211_hwsim_tx, @@ -713,6 +780,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops = .sta_notify = mac80211_hwsim_sta_notify, .set_tim = mac80211_hwsim_set_tim, .conf_tx = mac80211_hwsim_conf_tx, + CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd) }; -- cgit v1.2.3-18-g5258 From bc92afd92088ab41223383cc6863ab4792533c54 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:57 +0200 Subject: cfg80211: implement iwpower Just on/off and timeout, and with a hacky cfg80211 method until we figure out what we want, though this is probably sufficient as we want to use pm_qos for wifi everywhere. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 22 +++++++++++++ drivers/net/wireless/iwmc3200wifi/wext.c | 47 ++-------------------------- 2 files changed, 24 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index d0629d4757d..54bebba8e27 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -522,6 +522,27 @@ static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm) return 0; } +static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, + bool enabled, int timeout) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + u32 power_index; + + if (enabled) + power_index = IWM_POWER_INDEX_DEFAULT; + else + power_index = IWM_POWER_INDEX_MIN; + + if (power_index == iwm->conf.power_index) + return 0; + + iwm->conf.power_index = power_index; + + return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_POWER_INDEX, iwm->conf.power_index); +} + static struct cfg80211_ops iwm_cfg80211_ops = { .change_virtual_intf = iwm_cfg80211_change_iface, .add_key = iwm_cfg80211_add_key, @@ -534,6 +555,7 @@ static struct cfg80211_ops iwm_cfg80211_ops = { .leave_ibss = iwm_cfg80211_leave_ibss, .set_tx_power = iwm_cfg80211_set_txpower, .get_tx_power = iwm_cfg80211_get_txpower, + .set_power_mgmt = iwm_cfg80211_set_power_mgmt, }; struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev) diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c index 973457383c1..2e7eaf96cf9 100644 --- a/drivers/net/wireless/iwmc3200wifi/wext.c +++ b/drivers/net/wireless/iwmc3200wifi/wext.c @@ -238,49 +238,6 @@ static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version) return 0; } -static int iwm_wext_siwpower(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *wrq, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - u32 power_index; - - if (wrq->disabled) { - power_index = IWM_POWER_INDEX_MIN; - goto set; - } else - power_index = IWM_POWER_INDEX_DEFAULT; - - switch (wrq->flags & IW_POWER_MODE) { - case IW_POWER_ON: - case IW_POWER_MODE: - case IW_POWER_ALL_R: - break; - default: - return -EINVAL; - } - - set: - if (power_index == iwm->conf.power_index) - return 0; - - iwm->conf.power_index = power_index; - - return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_POWER_INDEX, iwm->conf.power_index); -} - -static int iwm_wext_giwpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - wrqu->power.disabled = (iwm->conf.power_index == IWM_POWER_INDEX_MIN); - - return 0; -} - static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt) { u8 *auth_type = &iwm->umac_profile->sec.auth_type; @@ -458,8 +415,8 @@ static const iw_handler iwm_handlers[] = (iw_handler) NULL, /* SIOCGIWRETRY */ (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */ - (iw_handler) iwm_wext_siwpower, /* SIOCSIWPOWER */ - (iw_handler) iwm_wext_giwpower, /* SIOCGIWPOWER */ + (iw_handler) cfg80211_wext_siwpower, /* SIOCSIWPOWER */ + (iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* SIOCSIWGENIE */ -- cgit v1.2.3-18-g5258 From 4244f41a040288e07d050ea64f60997c584cce9e Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Thu, 2 Jul 2009 20:26:45 +0100 Subject: orinoco: fix printk format specifier for size_t arguments This addresses the following compile warnings on 64-bit platforms. drivers/net/wireless/orinoco/scan.c: In function 'orinoco_add_hostscan_results': drivers/net/wireless/orinoco/scan.c:194: warning: format '%d' expects type 'int', but argument 3 has type 'size_t' drivers/net/wireless/orinoco/scan.c:211: warning: format '%d' expects type 'int', but argument 3 has type 'size_t' drivers/net/wireless/orinoco/scan.c:211: warning: format '%d' expects type 'int', but argument 4 has type 'size_t' Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/scan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c index 522eb98ec6f..d2f10e9c216 100644 --- a/drivers/net/wireless/orinoco/scan.c +++ b/drivers/net/wireless/orinoco/scan.c @@ -190,7 +190,7 @@ void orinoco_add_hostscan_results(struct orinoco_private *priv, /* Sanity check for atom_len */ if (atom_len < sizeof(struct prism2_scan_apinfo)) { printk(KERN_ERR "%s: Invalid atom_len in scan " - "data: %d\n", priv->ndev->name, + "data: %zu\n", priv->ndev->name, atom_len); abort = true; goto scan_abort; @@ -206,8 +206,8 @@ void orinoco_add_hostscan_results(struct orinoco_private *priv, /* Check that we got an whole number of atoms */ if ((len - offset) % atom_len) { - printk(KERN_ERR "%s: Unexpected scan data length %d, " - "atom_len %d, offset %d\n", priv->ndev->name, len, + printk(KERN_ERR "%s: Unexpected scan data length %zu, " + "atom_len %zu, offset %d\n", priv->ndev->name, len, atom_len, offset); abort = true; goto scan_abort; -- cgit v1.2.3-18-g5258 From ce8d096dac70e92a506d2f686ae4f724f42052cf Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Wed, 17 Jun 2009 18:45:34 -0700 Subject: libertas: copy WPA keys to priv when associating Libertas currently maintains a copy of the WPA unicast and group keys when using WPA or WPA2. This copy is checked when deciding whether or not to return to sleep in IEEE PS mode but the actual copying back to priv was omitted, which breaks IEEE PS mode with WPA/WPA2 when one issues commands that require temporarily keeping the device awake. This patch introduces the omitted copy-back of the keys so that IEEE PS functions correctly in WPA/WPA2 mode. Thanks to Dan Williams for clearing up the issue. V2: fix typo. Also, this has been tested on GSPI and SDIO with V9 firmware. Signed-off-by: Andrey Yurovsky Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index b9b37411903..fbf26499c9a 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -1368,11 +1368,17 @@ static int assoc_helper_wpa_keys(struct lbs_private *priv, if (ret) goto out; + memcpy(&priv->wpa_unicast_key, &assoc_req->wpa_unicast_key, + sizeof(struct enc_key)); + if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req); assoc_req->flags = flags; + + memcpy(&priv->wpa_mcast_key, &assoc_req->wpa_mcast_key, + sizeof(struct enc_key)); } out: -- cgit v1.2.3-18-g5258 From efcfd1f28f6a5c377a0e630ca2c96c54eb3f1e8f Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Thu, 18 Jun 2009 09:51:57 -0700 Subject: libertas: correct card cleanup order in SPI driver The SPI driver does a couple of card cleanup steps in the wrong order on module removal. If IEEE PS is enabled, this results in the card being left in IEEE PS mode and subsequent failures to reload the module. The problem is that the surpriseremoved flag is set before calling lbs_remove_card, but that function needs to issue a command to exit IEEE PS mode (the flag blocks the command path). In addition, lbs_stop_card should be called first because it clears out any pending commands. Tested on a GSPI device with V9 firmware by confirming that we can reload the module with or without IEEE PS enabled. Also fix a warning from the wrong uint format in a printk. V2: use z modifier, thanks Sebastian. Signed-off-by: Andrey Yurovsky Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_spi.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index b213de437ae..963c20125fc 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -737,7 +737,7 @@ static int if_spi_c2h_data(struct if_spi_card *card) goto out; } else if (len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { lbs_pr_err("%s: error: card has %d bytes of data, but " - "our maximum skb size is %lu\n", + "our maximum skb size is %zu\n", __func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE); err = -EINVAL; goto out; @@ -1170,12 +1170,13 @@ static int __devexit libertas_spi_remove(struct spi_device *spi) lbs_deb_spi("libertas_spi_remove\n"); lbs_deb_enter(LBS_DEB_SPI); - priv->surpriseremoved = 1; lbs_stop_card(priv); + lbs_remove_card(priv); /* will call free_netdev */ + + priv->surpriseremoved = 1; free_irq(spi->irq, card); if_spi_terminate_spi_thread(card); - lbs_remove_card(priv); /* will call free_netdev */ if (card->pdata->teardown) card->pdata->teardown(spi); free_if_spi_card(card); -- cgit v1.2.3-18-g5258 From 23b149c1890f9a55f065c6b7842e9383d22e0c04 Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Wed, 17 Jun 2009 19:15:19 -0700 Subject: libertas: fix card cleanup order in SDIO driver The SDIO driver sets the surpriseremoved flag before calling lbs_remove_card. With IEEE PS enabled, lbs_remove_card must issue a command to exit IEEE PS mode, however with that flag set the command path is blocked and the card is never taken out of IEEE PS mode. This step is required to ensure that the driver can be reloaded. This patch moves the setting of surpriseremoved after lbs_remove_card is called. Tested with V9 firmware by ensuring that IEEE PS is disabled when the driver is removed. Reloading the driver is not fully tested due to a separate issue with module reload in the SDIO driver, however this patch at least leaves the card in a better state when we bring the driver down. Signed-off-by: Andrey Yurovsky Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_sdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 89396a78862..485a8d40652 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -1093,11 +1093,11 @@ static void if_sdio_remove(struct sdio_func *func) lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n"); } - card->priv->surpriseremoved = 1; lbs_deb_sdio("call remove card\n"); lbs_stop_card(card->priv); lbs_remove_card(card->priv); + card->priv->surpriseremoved = 1; flush_workqueue(card->workqueue); destroy_workqueue(card->workqueue); -- cgit v1.2.3-18-g5258 From 7d5ca3b8b2b38ab676d0adc268a3c6a82e7a7588 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 19 Jun 2009 11:57:59 -0700 Subject: ath9k: differentiate quality reporting between legacy and HT configurations We were not differentiating quality between legacy and HT configurations. We change this to consider the differences. New theory for reporting quality: At a hardware RSSI of 45 you will be able to use MCS 7 reliably. At a hardware RSSI of 45 you will be able to use MCS 15 reliably. At a hardware RSSI of 35 you should be able use 54 Mbps reliably. MCS 7 is the highets MCS index usable by a 1-stream device. MCS 15 is the highest MCS index usable by a 2-stream device. All ath9k devices are either 1-stream or 2-stream. How many bars you see is derived from the qual reporting. A more elaborate scheme can be used here but it requires tables of SNR/throughput for each possible mode used. For the MCS table you can refer to the wireless wiki: http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n This should fix this bug report: http://bugzilla.kernel.org/show_bug.cgi?id=13537 Cc: Janath.Peiris@atheros.com Cc: Matt.Smith@atheros.com Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 2b2872baaa3..b3da81db453 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -236,10 +236,31 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi; rx_status->antenna = ds->ds_rxstat.rs_antenna; - /* at 45 you will be able to use MCS 15 reliably. A more elaborate - * scheme can be used here but it requires tables of SNR/throughput for - * each possible mode used. */ - rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45; + /* + * Theory for reporting quality: + * + * At a hardware RSSI of 45 you will be able to use MCS 7 reliably. + * At a hardware RSSI of 45 you will be able to use MCS 15 reliably. + * At a hardware RSSI of 35 you should be able use 54 Mbps reliably. + * + * MCS 7 is the highets MCS index usable by a 1-stream device. + * MCS 15 is the highest MCS index usable by a 2-stream device. + * + * All ath9k devices are either 1-stream or 2-stream. + * + * How many bars you see is derived from the qual reporting. + * + * A more elaborate scheme can be used here but it requires tables + * of SNR/throughput for each possible mode used. For the MCS table + * you can refer to the wireless wiki: + * + * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n + * + */ + if (conf_is_ht(&hw->conf)) + rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45; + else + rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 35; /* rssi can be more than 45 though, anything above that * should be considered at 100% */ -- cgit v1.2.3-18-g5258 From 3354a0f6a3ced6957dfb9f689ad075cfa8fd272f Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Fri, 19 Jun 2009 13:52:41 -0700 Subject: iwlwifi: Check HW ready before prepare card. Hardware may be ready for us to manage it without us trying to prepare it first. Check if this is the case. Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6d1519e1f01..63cba8c0ad4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1812,6 +1812,11 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter \n"); + ret = iwl_set_hw_ready(priv); + if (priv->hw_ready) + return ret; + + /* If HW is not ready, prepare the conditions to check again */ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_PREPARE); @@ -1819,6 +1824,7 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv) ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000); + /* HW should be ready by now, check again. */ if (ret != -ETIMEDOUT) iwl_set_hw_ready(priv); -- cgit v1.2.3-18-g5258 From 90e8e424d9c071f2db22100de81af6c8f7df34ee Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 19 Jun 2009 13:52:42 -0700 Subject: iwlwifi: drop sw_crypto from hw_params. Each HW supported by iwlwifi is capable of hardware crypto so drop this flag from hw_params structure. Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-core.c | 1 - drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - drivers/net/wireless/iwlwifi/iwl-rx.c | 2 +- 5 files changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 777c09534ce..8cfc83055aa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1987,7 +1987,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) staging_rxon->reserved4 = 0; staging_rxon->reserved5 = 0; - iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); + iwl_set_rxon_hwcrypto(priv, !iwl3945_mod_params.sw_crypto); /* Apply the new configuration */ rc = iwl_send_cmd_pdu(priv, REPLY_RXON, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 63cba8c0ad4..d9285615c67 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -171,7 +171,7 @@ int iwl_commit_rxon(struct iwl_priv *priv) le16_to_cpu(priv->staging_rxon.channel), priv->staging_rxon.bssid_addr); - iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); + iwl_set_rxon_hwcrypto(priv, !priv->cfg->mod_params->sw_crypto); /* Apply the new configuration * RXON unassoc clears the station table in uCode, send it before @@ -2337,7 +2337,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, IWL_DEBUG_MAC80211(priv, "enter\n"); - if (priv->hw_params.sw_crypto) { + if (priv->cfg->mod_params->sw_crypto) { IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n"); return -EOPNOTSUPP; } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 6ab07165ea2..11a19692f33 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1361,7 +1361,6 @@ EXPORT_SYMBOL(iwl_setup_mac); int iwl_set_hw_params(struct iwl_priv *priv) { - priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto; priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; if (priv->cfg->mod_params->amsdu_size_8K) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index e2d620f0b6e..5da60e402f7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -608,7 +608,6 @@ struct iwl_hw_params { u8 max_stations; u8 bcast_sta_id; u8 fat_channel; - u8 sw_crypto; u32 max_inst_size; u32 max_data_size; u32 max_bsm_size; diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 2160795ed01..66fe365dd08 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -927,7 +927,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, hdr = (struct ieee80211_hdr *)rxb->skb->data; /* in case of HW accelerated crypto and bad decryption, drop */ - if (!priv->hw_params.sw_crypto && + if (!priv->cfg->mod_params->sw_crypto && iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; -- cgit v1.2.3-18-g5258 From 45af81956e990440fe78d6d41f847664cb620609 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 19 Jun 2009 13:52:43 -0700 Subject: iwlwifi: make software queue assignment more efficient There really is no reason to be assigning txq->swq_id all the time, once at aggregation setup is sufficient. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 85ae7a62109..b35c1fd2cb2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -348,6 +348,10 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, txq->need_update = 0; + /* aggregation TX queues will get their ID when aggregation begins */ + if (txq_id <= IWL_TX_FIFO_AC3) + txq->swq_id = txq_id; + /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); @@ -734,8 +738,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); - swq_id = skb_get_queue_mapping(skb); - txq_id = swq_id; + txq_id = skb_get_queue_mapping(skb); if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; @@ -746,16 +749,14 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr->seq_ctrl |= cpu_to_le16(seq_number); seq_number += 0x10; /* aggregation is on for this */ - if (info->flags & IEEE80211_TX_CTL_AMPDU) { + if (info->flags & IEEE80211_TX_CTL_AMPDU) txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; - swq_id = iwl_virtual_agg_queue_num(swq_id, txq_id); - } priv->stations[sta_id].tid[tid].tfds_in_queue++; } txq = &priv->txq[txq_id]; + swq_id = txq->swq_id; q = &txq->q; - txq->swq_id = swq_id; spin_lock_irqsave(&priv->lock, flags); @@ -1186,6 +1187,7 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn) tid_data = &priv->stations[sta_id].tid[tid]; *ssn = SEQ_TO_SN(tid_data->seq_number); tid_data->agg.txq_id = txq_id; + priv->txq[txq_id].swq_id = iwl_virtual_agg_queue_num(tx_fifo, txq_id); spin_unlock_irqrestore(&priv->sta_lock, flags); ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo, -- cgit v1.2.3-18-g5258 From 4e05c2347a50f1d0892ff3475d7609eec428f781 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 19 Jun 2009 13:52:44 -0700 Subject: iwlwifi: scan requested channels only When userspace requests only certain channels to be scanned, we currently ignore that request entirely. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.h | 2 -- drivers/net/wireless/iwlwifi/iwl-scan.c | 31 +++++++++++++---------------- drivers/net/wireless/iwlwifi/iwl3945-base.c | 14 ++++++------- 3 files changed, 21 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index dabf663e36e..356d4e3aec7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -384,7 +384,6 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) void iwl_init_scan_params(struct iwl_priv *priv); int iwl_scan_cancel(struct iwl_priv *priv); int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); -int iwl_scan_initiate(struct iwl_priv *priv); int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req); u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, const u8 *ie, int ie_len, int left); @@ -398,7 +397,6 @@ void iwl_bg_scan_check(struct work_struct *data); void iwl_bg_abort_scan(struct work_struct *work); void iwl_bg_scan_completed(struct work_struct *work); void iwl_setup_scan_deferred_work(struct iwl_priv *priv); -int iwl_send_scan_abort(struct iwl_priv *priv); /* For faster active scanning, scan will move to the next channel if fewer than * PLCP_QUIET_THRESH packets are heard on this channel within diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index e26875dbe85..00398d973a0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -109,7 +109,7 @@ int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) } EXPORT_SYMBOL(iwl_scan_cancel_timeout); -int iwl_send_scan_abort(struct iwl_priv *priv) +static int iwl_send_scan_abort(struct iwl_priv *priv) { int ret = 0; struct iwl_rx_packet *res; @@ -150,7 +150,6 @@ int iwl_send_scan_abort(struct iwl_priv *priv) return ret; } -EXPORT_SYMBOL(iwl_send_scan_abort); /* Service response to REPLY_SCAN_CMD (0x80) */ static void iwl_rx_reply_scan(struct iwl_priv *priv, @@ -322,7 +321,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, u8 is_active, u8 n_probes, struct iwl_scan_channel *scan_ch) { - const struct ieee80211_channel *channels = NULL; + struct ieee80211_channel *chan; const struct ieee80211_supported_band *sband; const struct iwl_channel_info *ch_info; u16 passive_dwell = 0; @@ -334,20 +333,19 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, if (!sband) return 0; - channels = sband->channels; - active_dwell = iwl_get_active_dwell_time(priv, band, n_probes); passive_dwell = iwl_get_passive_dwell_time(priv, band); if (passive_dwell <= active_dwell) passive_dwell = active_dwell + 1; - for (i = 0, added = 0; i < sband->n_channels; i++) { - if (channels[i].flags & IEEE80211_CHAN_DISABLED) + for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) { + chan = priv->scan_request->channels[i]; + + if (chan->band != band) continue; - channel = - ieee80211_frequency_to_channel(channels[i].center_freq); + channel = ieee80211_frequency_to_channel(chan->center_freq); scan_ch->channel = cpu_to_le16(channel); ch_info = iwl_get_channel_info(priv, band, channel); @@ -358,7 +356,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, } if (!is_active || is_channel_passive(ch_info) || - (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) + (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; else scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE; @@ -405,7 +403,7 @@ void iwl_init_scan_params(struct iwl_priv *priv) priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx; } -int iwl_scan_initiate(struct iwl_priv *priv) +static int iwl_scan_initiate(struct iwl_priv *priv) { if (!iwl_is_ready_rf(priv)) { IWL_DEBUG_SCAN(priv, "Aborting scan due to not ready.\n"); @@ -423,10 +421,6 @@ int iwl_scan_initiate(struct iwl_priv *priv) } IWL_DEBUG_INFO(priv, "Starting scan...\n"); - if (priv->cfg->sku & IWL_SKU_G) - priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ); - if (priv->cfg->sku & IWL_SKU_A) - priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ); set_bit(STATUS_SCANNING, &priv->status); priv->scan_start = jiffies; priv->scan_pass_start = priv->scan_start; @@ -435,7 +429,6 @@ int iwl_scan_initiate(struct iwl_priv *priv) return 0; } -EXPORT_SYMBOL(iwl_scan_initiate); #define IWL_DELAY_NEXT_SCAN (HZ*2) @@ -444,7 +437,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, { unsigned long flags; struct iwl_priv *priv = hw->priv; - int ret; + int ret, i; IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -478,6 +471,10 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, goto out_unlock; } + priv->scan_bands = 0; + for (i = 0; i < req->n_channels; i++) + priv->scan_bands |= BIT(req->channels[i]->band); + priv->scan_request = req; ret = iwl_scan_initiate(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index cb9bd4c8f25..016567f3e88 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1844,7 +1844,7 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv, u8 is_active, u8 n_probes, struct iwl3945_scan_channel *scan_ch) { - const struct ieee80211_channel *channels = NULL; + struct ieee80211_channel *chan; const struct ieee80211_supported_band *sband; const struct iwl_channel_info *ch_info; u16 passive_dwell = 0; @@ -1855,19 +1855,19 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv, if (!sband) return 0; - channels = sband->channels; - active_dwell = iwl_get_active_dwell_time(priv, band, n_probes); passive_dwell = iwl_get_passive_dwell_time(priv, band); if (passive_dwell <= active_dwell) passive_dwell = active_dwell + 1; - for (i = 0, added = 0; i < sband->n_channels; i++) { - if (channels[i].flags & IEEE80211_CHAN_DISABLED) + for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) { + chan = priv->scan_request->channels[i]; + + if (chan->band != band) continue; - scan_ch->channel = channels[i].hw_value; + scan_ch->channel = chan->hw_value; ch_info = iwl_get_channel_info(priv, band, scan_ch->channel); if (!is_channel_valid(ch_info)) { @@ -1882,7 +1882,7 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv, * and use long active_dwell time. */ if (!is_active || is_channel_passive(ch_info) || - (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) { + (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) { scan_ch->type = 0; /* passive */ if (IWL_UCODE_API(priv->ucode_ver) == 1) scan_ch->active_dwell = cpu_to_le16(passive_dwell - 1); -- cgit v1.2.3-18-g5258 From 2c2f3b33888419fb9e7d015b9dc67b9db4437efa Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 19 Jun 2009 13:52:45 -0700 Subject: iwlwifi: unify iwl_setup_rxon_timing This patch unifies setup_rxon_timing funcions of AGN and 3945. HWs differ only in supported maximal beacon interval. This is reflected in hw_paras.max_beacon_itrvl Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 1 + drivers/net/wireless/iwlwifi/iwl-agn.c | 64 ------------------------- drivers/net/wireless/iwlwifi/iwl-commands.h | 2 + drivers/net/wireless/iwlwifi/iwl-core.c | 59 +++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 1 + drivers/net/wireless/iwlwifi/iwl-dev.h | 1 + drivers/net/wireless/iwlwifi/iwl3945-base.c | 74 +---------------------------- 7 files changed, 66 insertions(+), 136 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 8cfc83055aa..b0246dbda99 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2563,6 +2563,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.bcast_sta_id = IWL3945_BROADCAST_ID; priv->hw_params.rx_wrt_ptr_reg = FH39_RSCSR_CHNL0_WPTR; + priv->hw_params.max_beacon_itrvl = IWL39_MAX_UCODE_BEACON_INTERVAL; return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index d9285615c67..1d4e9cadb08 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -512,70 +512,6 @@ int iwl_hw_tx_queue_init(struct iwl_priv *priv, return 0; } - -/****************************************************************************** - * - * Misc. internal state and helper functions - * - ******************************************************************************/ - -#define MAX_UCODE_BEACON_INTERVAL 4096 - -static u16 iwl_adjust_beacon_interval(u16 beacon_val) -{ - u16 new_val = 0; - u16 beacon_factor = 0; - - beacon_factor = (beacon_val + MAX_UCODE_BEACON_INTERVAL) - / MAX_UCODE_BEACON_INTERVAL; - new_val = beacon_val / beacon_factor; - - if (!new_val) - new_val = MAX_UCODE_BEACON_INTERVAL; - - return new_val; -} - -static void iwl_setup_rxon_timing(struct iwl_priv *priv) -{ - u64 tsf; - s32 interval_tm, rem; - unsigned long flags; - struct ieee80211_conf *conf = NULL; - u16 beacon_int = 0; - - conf = ieee80211_get_hw_conf(priv->hw); - - spin_lock_irqsave(&priv->lock, flags); - priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp); - priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval); - - if (priv->iw_mode == NL80211_IFTYPE_STATION) { - beacon_int = iwl_adjust_beacon_interval(priv->beacon_int); - priv->rxon_timing.atim_window = 0; - } else { - beacon_int = iwl_adjust_beacon_interval( - priv->vif->bss_conf.beacon_int); - - /* TODO: we need to get atim_window from upper stack - * for now we set to 0 */ - priv->rxon_timing.atim_window = 0; - } - - priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int); - - tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */ - interval_tm = beacon_int * 1024; - rem = do_div(tsf, interval_tm); - priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem); - - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_ASSOC(priv, "beacon interval %d beacon timer %d beacon tim %d\n", - le16_to_cpu(priv->rxon_timing.beacon_interval), - le32_to_cpu(priv->rxon_timing.beacon_init_val), - le16_to_cpu(priv->rxon_timing.atim_window)); -} - /****************************************************************************** * * Generic RX handler implementations diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index c87033bf3ad..6e9b8a8356e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -765,6 +765,8 @@ struct iwl5000_rxon_assoc_cmd { } __attribute__ ((packed)); #define IWL_CONN_MAX_LISTEN_INTERVAL 10 +#define IWL_MAX_UCODE_BEACON_INTERVAL 4 /* 4096 */ +#define IWL39_MAX_UCODE_BEACON_INTERVAL 1 /* 1024 */ /* * REPLY_RXON_TIMING = 0x14 (command, has simple generic response) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 11a19692f33..7e528a0a15e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -635,6 +635,63 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_is_fat_tx_allowed); +static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val) +{ + u16 new_val = 0; + u16 beacon_factor = 0; + + beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val; + new_val = beacon_val / beacon_factor; + + if (!new_val) + new_val = max_beacon_val; + + return new_val; +} + +void iwl_setup_rxon_timing(struct iwl_priv *priv) +{ + u64 tsf; + s32 interval_tm, rem; + unsigned long flags; + struct ieee80211_conf *conf = NULL; + u16 beacon_int; + + conf = ieee80211_get_hw_conf(priv->hw); + + spin_lock_irqsave(&priv->lock, flags); + priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp); + priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval); + + if (priv->iw_mode == NL80211_IFTYPE_STATION) { + beacon_int = priv->beacon_int; + priv->rxon_timing.atim_window = 0; + } else { + beacon_int = priv->vif->bss_conf.beacon_int; + + /* TODO: we need to get atim_window from upper stack + * for now we set to 0 */ + priv->rxon_timing.atim_window = 0; + } + + beacon_int = iwl_adjust_beacon_interval(beacon_int, + priv->hw_params.max_beacon_itrvl * 1024); + priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int); + + tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */ + interval_tm = beacon_int * 1024; + rem = do_div(tsf, interval_tm); + priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem); + + spin_unlock_irqrestore(&priv->lock, flags); + IWL_DEBUG_ASSOC(priv, + "beacon interval %d beacon timer %d beacon tim %d\n", + le16_to_cpu(priv->rxon_timing.beacon_interval), + le32_to_cpu(priv->rxon_timing.beacon_init_val), + le16_to_cpu(priv->rxon_timing.atim_window)); +} +EXPORT_SYMBOL(iwl_setup_rxon_timing); + void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; @@ -1369,6 +1426,8 @@ int iwl_set_hw_params(struct iwl_priv *priv) priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K; priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256; + priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL; + if (priv->cfg->mod_params->disable_11n) priv->cfg->sku &= ~IWL_SKU_N; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 356d4e3aec7..a658410e66a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -554,6 +554,7 @@ extern void iwl_rx_reply_rx_phy(struct iwl_priv *priv, void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); +void iwl_setup_rxon_timing(struct iwl_priv *priv); static inline int iwl_send_rxon_assoc(struct iwl_priv *priv) { return priv->cfg->ops->hcmd->rxon_assoc(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 5da60e402f7..1a2fe37d473 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -608,6 +608,7 @@ struct iwl_hw_params { u8 max_stations; u8 bcast_sta_id; u8 fat_channel; + u8 max_beacon_itrvl; /* in 1024 ms */ u32 max_inst_size; u32 max_data_size; u32 max_bsm_size; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 016567f3e88..303c4b483f5 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -361,76 +361,6 @@ static void iwl3945_unset_hw_params(struct iwl_priv *priv) priv->shared_phys); } -#define MAX_UCODE_BEACON_INTERVAL 1024 -#define INTEL_CONN_LISTEN_INTERVAL cpu_to_le16(0xA) - -static __le16 iwl3945_adjust_beacon_interval(u16 beacon_val) -{ - u16 new_val = 0; - u16 beacon_factor = 0; - - beacon_factor = - (beacon_val + MAX_UCODE_BEACON_INTERVAL) - / MAX_UCODE_BEACON_INTERVAL; - new_val = beacon_val / beacon_factor; - - return cpu_to_le16(new_val); -} - -static void iwl3945_setup_rxon_timing(struct iwl_priv *priv) -{ - u64 interval_tm_unit; - u64 tsf, result; - unsigned long flags; - struct ieee80211_conf *conf = NULL; - u16 beacon_int = 0; - - conf = ieee80211_get_hw_conf(priv->hw); - - spin_lock_irqsave(&priv->lock, flags); - priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp); - priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL; - - tsf = priv->timestamp; - - beacon_int = priv->beacon_int; - spin_unlock_irqrestore(&priv->lock, flags); - - if (priv->iw_mode == NL80211_IFTYPE_STATION) { - if (beacon_int == 0) { - priv->rxon_timing.beacon_interval = cpu_to_le16(100); - priv->rxon_timing.beacon_init_val = cpu_to_le32(102400); - } else { - priv->rxon_timing.beacon_interval = - cpu_to_le16(beacon_int); - priv->rxon_timing.beacon_interval = - iwl3945_adjust_beacon_interval( - le16_to_cpu(priv->rxon_timing.beacon_interval)); - } - - priv->rxon_timing.atim_window = 0; - } else { - priv->rxon_timing.beacon_interval = - iwl3945_adjust_beacon_interval( - priv->vif->bss_conf.beacon_int); - /* TODO: we need to get atim_window from upper stack - * for now we set to 0 */ - priv->rxon_timing.atim_window = 0; - } - - interval_tm_unit = - (le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024); - result = do_div(tsf, interval_tm_unit); - priv->rxon_timing.beacon_init_val = - cpu_to_le32((u32) ((u64) interval_tm_unit - result)); - - IWL_DEBUG_ASSOC(priv, - "beacon interval %d beacon timer %d beacon tim %d\n", - le16_to_cpu(priv->rxon_timing.beacon_interval), - le32_to_cpu(priv->rxon_timing.beacon_init_val), - le16_to_cpu(priv->rxon_timing.atim_window)); -} - static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, struct ieee80211_tx_info *info, struct iwl_cmd *cmd, @@ -3066,7 +2996,7 @@ void iwl3945_post_associate(struct iwl_priv *priv) iwlcore_commit_rxon(priv); memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); - iwl3945_setup_rxon_timing(priv); + iwl_setup_rxon_timing(priv); rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, sizeof(priv->rxon_timing), &priv->rxon_timing); if (rc) @@ -3261,7 +3191,7 @@ void iwl3945_config_ap(struct iwl_priv *priv) /* RXON Timing */ memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); - iwl3945_setup_rxon_timing(priv); + iwl_setup_rxon_timing(priv); rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, sizeof(priv->rxon_timing), &priv->rxon_timing); -- cgit v1.2.3-18-g5258 From 92179986ba5221a21e0f8a1e9b7b82a2883fef79 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 20 Jun 2009 05:10:24 +0200 Subject: ar9170usb: module link in sysfs Andrey Yurovsky reported that the driver forwarded erroneously the parent device structure instead of the real thing, which of course led to some dodgy sysfs links (at least?). Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index 754b1f8d8da..1aec7afdffa 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -779,7 +779,7 @@ static int ar9170_usb_probe(struct usb_interface *intf, aru->req_one_stage_fw = ar9170_requires_one_stage(id); usb_set_intfdata(intf, aru); - SET_IEEE80211_DEV(ar->hw, &udev->dev); + SET_IEEE80211_DEV(ar->hw, &intf->dev); init_usb_anchor(&aru->rx_submitted); init_usb_anchor(&aru->tx_pending); -- cgit v1.2.3-18-g5258 From 1795378ee8d162084c6f98fc62ec309e418dfbe9 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 20 Jun 2009 21:13:46 +0200 Subject: p54: redo rx_status into skb->cb This patch slightly optimizes p54_rx_data's stack and code size. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54common.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 1b15f9e0b86..d1ea609a690 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -743,7 +743,7 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_common *priv = dev->priv; struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data; - struct ieee80211_rx_status rx_status = {0}; + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); u16 freq = le16_to_cpu(hdr->freq); size_t header_len = sizeof(*hdr); u32 tsf32; @@ -762,39 +762,37 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) } if (hdr->decrypt_status == P54_DECRYPT_OK) - rx_status.flag |= RX_FLAG_DECRYPTED; + rx_status->flag |= RX_FLAG_DECRYPTED; if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) || (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP)) - rx_status.flag |= RX_FLAG_MMIC_ERROR; + rx_status->flag |= RX_FLAG_MMIC_ERROR; - rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi); - rx_status.noise = priv->noise; + rx_status->signal = p54_rssi_to_dbm(dev, hdr->rssi); + rx_status->noise = priv->noise; if (hdr->rate & 0x10) - rx_status.flag |= RX_FLAG_SHORTPRE; + rx_status->flag |= RX_FLAG_SHORTPRE; if (dev->conf.channel->band == IEEE80211_BAND_5GHZ) - rx_status.rate_idx = (rate < 4) ? 0 : rate - 4; + rx_status->rate_idx = (rate < 4) ? 0 : rate - 4; else - rx_status.rate_idx = rate; + rx_status->rate_idx = rate; - rx_status.freq = freq; - rx_status.band = dev->conf.channel->band; - rx_status.antenna = hdr->antenna; + rx_status->freq = freq; + rx_status->band = dev->conf.channel->band; + rx_status->antenna = hdr->antenna; tsf32 = le32_to_cpu(hdr->tsf32); if (tsf32 < priv->tsf_low32) priv->tsf_high32++; - rx_status.mactime = ((u64)priv->tsf_high32) << 32 | tsf32; + rx_status->mactime = ((u64)priv->tsf_high32) << 32 | tsf32; priv->tsf_low32 = tsf32; - rx_status.flag |= RX_FLAG_TSFT; + rx_status->flag |= RX_FLAG_TSFT; if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) header_len += hdr->align[0]; skb_pull(skb, header_len); skb_trim(skb, le16_to_cpu(hdr->len)); - - memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); ieee80211_rx_irqsafe(dev, skb); queue_delayed_work(dev->workqueue, &priv->work, -- cgit v1.2.3-18-g5258 From 35a0ace7739b50331c919a3255639f123b78eaff Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Mon, 22 Jun 2009 17:42:21 +0200 Subject: wireless: remove redundant tests on unsigned bufsize and remainder are unsigned. When negative they are wrapped and caught by the other test. Signed-off-by: Roel Kluin Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/hermes.c | 2 +- drivers/net/wireless/rtl818x/rtl8180_dev.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/hermes.c b/drivers/net/wireless/orinoco/hermes.c index f2c918c2572..1a2fca76fd3 100644 --- a/drivers/net/wireless/orinoco/hermes.c +++ b/drivers/net/wireless/orinoco/hermes.c @@ -469,7 +469,7 @@ int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize, u16 rlength, rtype; unsigned nwords; - if ((bufsize < 0) || (bufsize % 2)) + if (bufsize % 2) return -EINVAL; err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL); diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index 47521c5b6f9..09f46abc730 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -281,7 +281,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) (ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10); remainder = (16 * (skb->len + 4)) % ((ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10); - if (remainder > 0 && remainder <= 6) + if (remainder <= 6) plcp_len |= 1 << 15; } -- cgit v1.2.3-18-g5258 From 4c8a32f57105a78c49e01f083717cdb531d3c2b9 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 23 Jun 2009 10:36:26 -0500 Subject: p54: Move eeprom code Copy the eeprom code from p54common.c into a new file eeprom.c Signed-off-by: Christian Lamparter Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/p54/eeprom.c | 564 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 564 insertions(+) create mode 100644 drivers/net/wireless/p54/eeprom.c (limited to 'drivers') diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c new file mode 100644 index 00000000000..a2a044ef101 --- /dev/null +++ b/drivers/net/wireless/p54/eeprom.c @@ -0,0 +1,564 @@ +/* + * EEPROM parser code for mac80211 Prism54 drivers + * + * Copyright (c) 2006, Michael Wu + * Copyright (c) 2007-2009, Christian Lamparter + * Copyright 2008, Johannes Berg + * + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * - stlc45xx driver + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include + +#include "p54.h" +#include "eeprom.h" +#include "lmac.h" + +static struct ieee80211_rate p54_bgrates[] = { + { .bitrate = 10, .hw_value = 0, }, + { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, .hw_value = 4, }, + { .bitrate = 90, .hw_value = 5, }, + { .bitrate = 120, .hw_value = 6, }, + { .bitrate = 180, .hw_value = 7, }, + { .bitrate = 240, .hw_value = 8, }, + { .bitrate = 360, .hw_value = 9, }, + { .bitrate = 480, .hw_value = 10, }, + { .bitrate = 540, .hw_value = 11, }, +}; + +static struct ieee80211_channel p54_bgchannels[] = { + { .center_freq = 2412, .hw_value = 1, }, + { .center_freq = 2417, .hw_value = 2, }, + { .center_freq = 2422, .hw_value = 3, }, + { .center_freq = 2427, .hw_value = 4, }, + { .center_freq = 2432, .hw_value = 5, }, + { .center_freq = 2437, .hw_value = 6, }, + { .center_freq = 2442, .hw_value = 7, }, + { .center_freq = 2447, .hw_value = 8, }, + { .center_freq = 2452, .hw_value = 9, }, + { .center_freq = 2457, .hw_value = 10, }, + { .center_freq = 2462, .hw_value = 11, }, + { .center_freq = 2467, .hw_value = 12, }, + { .center_freq = 2472, .hw_value = 13, }, + { .center_freq = 2484, .hw_value = 14, }, +}; + +static struct ieee80211_supported_band band_2GHz = { + .channels = p54_bgchannels, + .n_channels = ARRAY_SIZE(p54_bgchannels), + .bitrates = p54_bgrates, + .n_bitrates = ARRAY_SIZE(p54_bgrates), +}; + +static struct ieee80211_rate p54_arates[] = { + { .bitrate = 60, .hw_value = 4, }, + { .bitrate = 90, .hw_value = 5, }, + { .bitrate = 120, .hw_value = 6, }, + { .bitrate = 180, .hw_value = 7, }, + { .bitrate = 240, .hw_value = 8, }, + { .bitrate = 360, .hw_value = 9, }, + { .bitrate = 480, .hw_value = 10, }, + { .bitrate = 540, .hw_value = 11, }, +}; + +static struct ieee80211_channel p54_achannels[] = { + { .center_freq = 4920 }, + { .center_freq = 4940 }, + { .center_freq = 4960 }, + { .center_freq = 4980 }, + { .center_freq = 5040 }, + { .center_freq = 5060 }, + { .center_freq = 5080 }, + { .center_freq = 5170 }, + { .center_freq = 5180 }, + { .center_freq = 5190 }, + { .center_freq = 5200 }, + { .center_freq = 5210 }, + { .center_freq = 5220 }, + { .center_freq = 5230 }, + { .center_freq = 5240 }, + { .center_freq = 5260 }, + { .center_freq = 5280 }, + { .center_freq = 5300 }, + { .center_freq = 5320 }, + { .center_freq = 5500 }, + { .center_freq = 5520 }, + { .center_freq = 5540 }, + { .center_freq = 5560 }, + { .center_freq = 5580 }, + { .center_freq = 5600 }, + { .center_freq = 5620 }, + { .center_freq = 5640 }, + { .center_freq = 5660 }, + { .center_freq = 5680 }, + { .center_freq = 5700 }, + { .center_freq = 5745 }, + { .center_freq = 5765 }, + { .center_freq = 5785 }, + { .center_freq = 5805 }, + { .center_freq = 5825 }, +}; + +static struct ieee80211_supported_band band_5GHz = { + .channels = p54_achannels, + .n_channels = ARRAY_SIZE(p54_achannels), + .bitrates = p54_arates, + .n_bitrates = ARRAY_SIZE(p54_arates), +}; + +static int p54_convert_rev0(struct ieee80211_hw *dev, + struct pda_pa_curve_data *curve_data) +{ + struct p54_common *priv = dev->priv; + struct p54_pa_curve_data_sample *dst; + struct pda_pa_curve_data_sample_rev0 *src; + size_t cd_len = sizeof(*curve_data) + + (curve_data->points_per_channel*sizeof(*dst) + 2) * + curve_data->channels; + unsigned int i, j; + void *source, *target; + + priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len, + GFP_KERNEL); + if (!priv->curve_data) + return -ENOMEM; + + priv->curve_data->entries = curve_data->channels; + priv->curve_data->entry_size = sizeof(__le16) + + sizeof(*dst) * curve_data->points_per_channel; + priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data); + priv->curve_data->len = cd_len; + memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data)); + source = curve_data->data; + target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data; + for (i = 0; i < curve_data->channels; i++) { + __le16 *freq = source; + source += sizeof(__le16); + *((__le16 *)target) = *freq; + target += sizeof(__le16); + for (j = 0; j < curve_data->points_per_channel; j++) { + dst = target; + src = source; + + dst->rf_power = src->rf_power; + dst->pa_detector = src->pa_detector; + dst->data_64qam = src->pcv; + /* "invent" the points for the other modulations */ +#define SUB(x, y) (u8)(((x) - (y)) > (x) ? 0 : (x) - (y)) + dst->data_16qam = SUB(src->pcv, 12); + dst->data_qpsk = SUB(dst->data_16qam, 12); + dst->data_bpsk = SUB(dst->data_qpsk, 12); + dst->data_barker = SUB(dst->data_bpsk, 14); +#undef SUB + target += sizeof(*dst); + source += sizeof(*src); + } + } + + return 0; +} + +static int p54_convert_rev1(struct ieee80211_hw *dev, + struct pda_pa_curve_data *curve_data) +{ + struct p54_common *priv = dev->priv; + struct p54_pa_curve_data_sample *dst; + struct pda_pa_curve_data_sample_rev1 *src; + size_t cd_len = sizeof(*curve_data) + + (curve_data->points_per_channel*sizeof(*dst) + 2) * + curve_data->channels; + unsigned int i, j; + void *source, *target; + + priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data), + GFP_KERNEL); + if (!priv->curve_data) + return -ENOMEM; + + priv->curve_data->entries = curve_data->channels; + priv->curve_data->entry_size = sizeof(__le16) + + sizeof(*dst) * curve_data->points_per_channel; + priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data); + priv->curve_data->len = cd_len; + memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data)); + source = curve_data->data; + target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data; + for (i = 0; i < curve_data->channels; i++) { + __le16 *freq = source; + source += sizeof(__le16); + *((__le16 *)target) = *freq; + target += sizeof(__le16); + for (j = 0; j < curve_data->points_per_channel; j++) { + memcpy(target, source, sizeof(*src)); + + target += sizeof(*dst); + source += sizeof(*src); + } + source++; + } + + return 0; +} + +static const char *p54_rf_chips[] = { "INVALID-0", "Duette3", "Duette2", + "Frisbee", "Xbow", "Longbow", "INVALID-6", "INVALID-7" }; + +static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len, + u16 type) +{ + struct p54_common *priv = dev->priv; + int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0; + int entry_size = sizeof(struct pda_rssi_cal_entry) + offset; + int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2; + int i; + + if (len != (entry_size * num_entries)) { + printk(KERN_ERR "%s: unknown rssi calibration data packing " + " type:(%x) len:%d.\n", + wiphy_name(dev->wiphy), type, len); + + print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE, + data, len); + + printk(KERN_ERR "%s: please report this issue.\n", + wiphy_name(dev->wiphy)); + return; + } + + for (i = 0; i < num_entries; i++) { + struct pda_rssi_cal_entry *cal = data + + (offset + i * entry_size); + priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul); + priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add); + } +} + +static void p54_parse_default_country(struct ieee80211_hw *dev, + void *data, int len) +{ + struct pda_country *country; + + if (len != sizeof(*country)) { + printk(KERN_ERR "%s: found possible invalid default country " + "eeprom entry. (entry size: %d)\n", + wiphy_name(dev->wiphy), len); + + print_hex_dump_bytes("country:", DUMP_PREFIX_NONE, + data, len); + + printk(KERN_ERR "%s: please report this issue.\n", + wiphy_name(dev->wiphy)); + return; + } + + country = (struct pda_country *) data; + if (country->flags == PDR_COUNTRY_CERT_CODE_PSEUDO) + regulatory_hint(dev->wiphy, country->alpha2); + else { + /* TODO: + * write a shared/common function that converts + * "Regulatory domain codes" (802.11-2007 14.8.2.2) + * into ISO/IEC 3166-1 alpha2 for regulatory_hint. + */ + } +} + +static int p54_convert_output_limits(struct ieee80211_hw *dev, + u8 *data, size_t len) +{ + struct p54_common *priv = dev->priv; + + if (len < 2) + return -EINVAL; + + if (data[0] != 0) { + printk(KERN_ERR "%s: unknown output power db revision:%x\n", + wiphy_name(dev->wiphy), data[0]); + return -EINVAL; + } + + if (2 + data[1] * sizeof(struct pda_channel_output_limit) > len) + return -EINVAL; + + priv->output_limit = kmalloc(data[1] * + sizeof(struct pda_channel_output_limit) + + sizeof(*priv->output_limit), GFP_KERNEL); + + if (!priv->output_limit) + return -ENOMEM; + + priv->output_limit->offset = 0; + priv->output_limit->entries = data[1]; + priv->output_limit->entry_size = + sizeof(struct pda_channel_output_limit); + priv->output_limit->len = priv->output_limit->entry_size * + priv->output_limit->entries + + priv->output_limit->offset; + + memcpy(priv->output_limit->data, &data[2], + data[1] * sizeof(struct pda_channel_output_limit)); + + return 0; +} + +static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src, + size_t total_len) +{ + struct p54_cal_database *dst; + size_t payload_len, entries, entry_size, offset; + + payload_len = le16_to_cpu(src->len); + entries = le16_to_cpu(src->entries); + entry_size = le16_to_cpu(src->entry_size); + offset = le16_to_cpu(src->offset); + if (((entries * entry_size + offset) != payload_len) || + (payload_len + sizeof(*src) != total_len)) + return NULL; + + dst = kmalloc(sizeof(*dst) + payload_len, GFP_KERNEL); + if (!dst) + return NULL; + + dst->entries = entries; + dst->entry_size = entry_size; + dst->offset = offset; + dst->len = payload_len; + + memcpy(dst->data, src->data, payload_len); + return dst; +} + +int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) +{ + struct p54_common *priv = dev->priv; + struct eeprom_pda_wrap *wrap = NULL; + struct pda_entry *entry; + unsigned int data_len, entry_len; + void *tmp; + int err; + u8 *end = (u8 *)eeprom + len; + u16 synth = 0; + + wrap = (struct eeprom_pda_wrap *) eeprom; + entry = (void *)wrap->data + le16_to_cpu(wrap->len); + + /* verify that at least the entry length/code fits */ + while ((u8 *)entry <= end - sizeof(*entry)) { + entry_len = le16_to_cpu(entry->len); + data_len = ((entry_len - 1) << 1); + + /* abort if entry exceeds whole structure */ + if ((u8 *)entry + sizeof(*entry) + data_len > end) + break; + + switch (le16_to_cpu(entry->code)) { + case PDR_MAC_ADDRESS: + if (data_len != ETH_ALEN) + break; + SET_IEEE80211_PERM_ADDR(dev, entry->data); + break; + case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS: + if (priv->output_limit) + break; + err = p54_convert_output_limits(dev, entry->data, + data_len); + if (err) + goto err; + break; + case PDR_PRISM_PA_CAL_CURVE_DATA: { + struct pda_pa_curve_data *curve_data = + (struct pda_pa_curve_data *)entry->data; + if (data_len < sizeof(*curve_data)) { + err = -EINVAL; + goto err; + } + + switch (curve_data->cal_method_rev) { + case 0: + err = p54_convert_rev0(dev, curve_data); + break; + case 1: + err = p54_convert_rev1(dev, curve_data); + break; + default: + printk(KERN_ERR "%s: unknown curve data " + "revision %d\n", + wiphy_name(dev->wiphy), + curve_data->cal_method_rev); + err = -ENODEV; + break; + } + if (err) + goto err; + } + break; + case PDR_PRISM_ZIF_TX_IQ_CALIBRATION: + priv->iq_autocal = kmalloc(data_len, GFP_KERNEL); + if (!priv->iq_autocal) { + err = -ENOMEM; + goto err; + } + + memcpy(priv->iq_autocal, entry->data, data_len); + priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry); + break; + case PDR_DEFAULT_COUNTRY: + p54_parse_default_country(dev, entry->data, data_len); + break; + case PDR_INTERFACE_LIST: + tmp = entry->data; + while ((u8 *)tmp < entry->data + data_len) { + struct exp_if *exp_if = tmp; + if (exp_if->if_id == cpu_to_le16(IF_ID_ISL39000)) + synth = le16_to_cpu(exp_if->variant); + tmp += sizeof(*exp_if); + } + break; + case PDR_HARDWARE_PLATFORM_COMPONENT_ID: + if (data_len < 2) + break; + priv->version = *(u8 *)(entry->data + 1); + break; + case PDR_RSSI_LINEAR_APPROXIMATION: + case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND: + case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED: + p54_parse_rssical(dev, entry->data, data_len, + le16_to_cpu(entry->code)); + break; + case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM: { + __le16 *src = (void *) entry->data; + s16 *dst = (void *) &priv->rssical_db; + int i; + + if (data_len != sizeof(priv->rssical_db)) { + err = -EINVAL; + goto err; + } + for (i = 0; i < sizeof(priv->rssical_db) / + sizeof(*src); i++) + *(dst++) = (s16) le16_to_cpu(*(src++)); + } + break; + case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: { + struct pda_custom_wrapper *pda = (void *) entry->data; + if (priv->output_limit || data_len < sizeof(*pda)) + break; + priv->output_limit = p54_convert_db(pda, data_len); + } + break; + case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: { + struct pda_custom_wrapper *pda = (void *) entry->data; + if (priv->curve_data || data_len < sizeof(*pda)) + break; + priv->curve_data = p54_convert_db(pda, data_len); + } + break; + case PDR_END: + /* make it overrun */ + entry_len = len; + break; + default: + break; + } + + entry = (void *)entry + (entry_len + 1)*2; + } + + if (!synth || !priv->iq_autocal || !priv->output_limit || + !priv->curve_data) { + printk(KERN_ERR "%s: not all required entries found in eeprom!\n", + wiphy_name(dev->wiphy)); + err = -EINVAL; + goto err; + } + + priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK; + if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW) + p54_init_xbow_synth(priv); + if (!(synth & PDR_SYNTH_24_GHZ_DISABLED)) + dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; + if (!(synth & PDR_SYNTH_5_GHZ_DISABLED)) + dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz; + if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED) + priv->rx_diversity_mask = 3; + if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED) + priv->tx_diversity_mask = 3; + + if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { + u8 perm_addr[ETH_ALEN]; + + printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n", + wiphy_name(dev->wiphy)); + random_ether_addr(perm_addr); + SET_IEEE80211_PERM_ADDR(dev, perm_addr); + } + + printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n", + wiphy_name(dev->wiphy), dev->wiphy->perm_addr, priv->version, + p54_rf_chips[priv->rxhw]); + + return 0; + +err: + kfree(priv->iq_autocal); + kfree(priv->output_limit); + kfree(priv->curve_data); + priv->iq_autocal = NULL; + priv->output_limit = NULL; + priv->curve_data = NULL; + + printk(KERN_ERR "%s: eeprom parse failed!\n", + wiphy_name(dev->wiphy)); + return err; +} +EXPORT_SYMBOL_GPL(p54_parse_eeprom); + +int p54_read_eeprom(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize; + int ret = -ENOMEM; + void *eeprom = NULL; + + maxblocksize = EEPROM_READBACK_LEN; + if (priv->fw_var >= 0x509) + maxblocksize -= 0xc; + else + maxblocksize -= 0x4; + + eeprom = kzalloc(eeprom_size, GFP_KERNEL); + if (unlikely(!eeprom)) + goto free; + + while (eeprom_size) { + blocksize = min(eeprom_size, maxblocksize); + ret = p54_download_eeprom(priv, (void *) (eeprom + offset), + offset, blocksize); + if (unlikely(ret)) + goto free; + + offset += blocksize; + eeprom_size -= blocksize; + } + + ret = p54_parse_eeprom(dev, eeprom, offset); +free: + kfree(eeprom); + return ret; +} +EXPORT_SYMBOL_GPL(p54_read_eeprom); -- cgit v1.2.3-18-g5258 From 289b098c2754d04f768b34ac5a9d08b59c38b725 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 23 Jun 2009 10:37:13 -0500 Subject: p54: Move eeprom header Copy the eeprom code from p54common.h into a new file eeprom.h Signed-off-by: Christian Lamparter Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/p54/eeprom.h | 226 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 drivers/net/wireless/p54/eeprom.h (limited to 'drivers') diff --git a/drivers/net/wireless/p54/eeprom.h b/drivers/net/wireless/p54/eeprom.h new file mode 100644 index 00000000000..9051aef1124 --- /dev/null +++ b/drivers/net/wireless/p54/eeprom.h @@ -0,0 +1,226 @@ +/* + * eeprom specific definitions for mac80211 Prism54 drivers + * + * Copyright (c) 2006, Michael Wu + * Copyright (c) 2007-2009, Christian Lamparter + * + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * + * - LMAC API interface header file for STLC4560 (lmac_longbow.h) + * Copyright (C) 2007 Conexant Systems, Inc. + * + * - islmvc driver + * Copyright (C) 2001 Intersil Americas Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef EEPROM_H +#define EEPROM_H + +/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */ + +struct pda_entry { + __le16 len; /* includes both code and data */ + __le16 code; + u8 data[0]; +} __packed; + +struct eeprom_pda_wrap { + __le32 magic; + __le16 pad; + __le16 len; + __le32 arm_opcode; + u8 data[0]; +} __packed; + +struct p54_iq_autocal_entry { + __le16 iq_param[4]; +} __packed; + +struct pda_iq_autocal_entry { + __le16 freq; + struct p54_iq_autocal_entry params; +} __packed; + +struct pda_channel_output_limit { + __le16 freq; + u8 val_bpsk; + u8 val_qpsk; + u8 val_16qam; + u8 val_64qam; + u8 rate_set_mask; + u8 rate_set_size; +} __packed; + +struct pda_pa_curve_data_sample_rev0 { + u8 rf_power; + u8 pa_detector; + u8 pcv; +} __packed; + +struct pda_pa_curve_data_sample_rev1 { + u8 rf_power; + u8 pa_detector; + u8 data_barker; + u8 data_bpsk; + u8 data_qpsk; + u8 data_16qam; + u8 data_64qam; +} __packed; + +struct pda_pa_curve_data { + u8 cal_method_rev; + u8 channels; + u8 points_per_channel; + u8 padding; + u8 data[0]; +} __packed; + +struct pda_rssi_cal_entry { + __le16 mul; + __le16 add; +} __packed; + +struct pda_country { + u8 regdomain; + u8 alpha2[2]; + u8 flags; +} __packed; + +struct pda_antenna_gain { + struct { + u8 gain_5GHz; /* 0.25 dBi units */ + u8 gain_2GHz; /* 0.25 dBi units */ + } __packed antenna[0]; +} __packed; + +struct pda_custom_wrapper { + __le16 entries; + __le16 entry_size; + __le16 offset; + __le16 len; + u8 data[0]; +} __packed; + +/* + * this defines the PDR codes used to build PDAs as defined in document + * number 553155. The current implementation mirrors version 1.1 of the + * document and lists only PDRs supported by the ARM platform. + */ + +/* common and choice range (0x0000 - 0x0fff) */ +#define PDR_END 0x0000 +#define PDR_MANUFACTURING_PART_NUMBER 0x0001 +#define PDR_PDA_VERSION 0x0002 +#define PDR_NIC_SERIAL_NUMBER 0x0003 +#define PDR_NIC_RAM_SIZE 0x0005 +#define PDR_RFMODEM_SUP_RANGE 0x0006 +#define PDR_PRISM_MAC_SUP_RANGE 0x0007 +#define PDR_NIC_ID 0x0008 + +#define PDR_MAC_ADDRESS 0x0101 +#define PDR_REGULATORY_DOMAIN_LIST 0x0103 /* obsolete */ +#define PDR_ALLOWED_CHAN_SET 0x0104 +#define PDR_DEFAULT_CHAN 0x0105 +#define PDR_TEMPERATURE_TYPE 0x0107 + +#define PDR_IFR_SETTING 0x0200 +#define PDR_RFR_SETTING 0x0201 +#define PDR_3861_BASELINE_REG_SETTINGS 0x0202 +#define PDR_3861_SHADOW_REG_SETTINGS 0x0203 +#define PDR_3861_IFRF_REG_SETTINGS 0x0204 + +#define PDR_3861_CHAN_CALIB_SET_POINTS 0x0300 +#define PDR_3861_CHAN_CALIB_INTEGRATOR 0x0301 + +#define PDR_3842_PRISM_II_NIC_CONFIG 0x0400 +#define PDR_PRISM_USB_ID 0x0401 +#define PDR_PRISM_PCI_ID 0x0402 +#define PDR_PRISM_PCI_IF_CONFIG 0x0403 +#define PDR_PRISM_PCI_PM_CONFIG 0x0404 + +#define PDR_3861_MF_TEST_CHAN_SET_POINTS 0x0900 +#define PDR_3861_MF_TEST_CHAN_INTEGRATORS 0x0901 + +/* ARM range (0x1000 - 0x1fff) */ +#define PDR_COUNTRY_INFORMATION 0x1000 /* obsolete */ +#define PDR_INTERFACE_LIST 0x1001 +#define PDR_HARDWARE_PLATFORM_COMPONENT_ID 0x1002 +#define PDR_OEM_NAME 0x1003 +#define PDR_PRODUCT_NAME 0x1004 +#define PDR_UTF8_OEM_NAME 0x1005 +#define PDR_UTF8_PRODUCT_NAME 0x1006 +#define PDR_COUNTRY_LIST 0x1007 +#define PDR_DEFAULT_COUNTRY 0x1008 + +#define PDR_ANTENNA_GAIN 0x1100 + +#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA 0x1901 +#define PDR_RSSI_LINEAR_APPROXIMATION 0x1902 +#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS 0x1903 +#define PDR_PRISM_PA_CAL_CURVE_DATA 0x1904 +#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND 0x1905 +#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION 0x1906 +#define PDR_REGULATORY_POWER_LIMITS 0x1907 +#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED 0x1908 +#define PDR_RADIATED_TRANSMISSION_CORRECTION 0x1909 +#define PDR_PRISM_TX_IQ_CALIBRATION 0x190a + +/* reserved range (0x2000 - 0x7fff) */ + +/* customer range (0x8000 - 0xffff) */ +#define PDR_BASEBAND_REGISTERS 0x8000 +#define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001 + +/* used by our modificated eeprom image */ +#define PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM 0xDEAD +#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM 0xBEEF +#define PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM 0xB05D + +/* Interface Definitions */ +#define PDR_INTERFACE_ROLE_SERVER 0x0000 +#define PDR_INTERFACE_ROLE_CLIENT 0x0001 + +/* PDR definitions for default country & country list */ +#define PDR_COUNTRY_CERT_CODE 0x80 +#define PDR_COUNTRY_CERT_CODE_REAL 0x00 +#define PDR_COUNTRY_CERT_CODE_PSEUDO 0x80 +#define PDR_COUNTRY_CERT_BAND 0x40 +#define PDR_COUNTRY_CERT_BAND_2GHZ 0x00 +#define PDR_COUNTRY_CERT_BAND_5GHZ 0x40 +#define PDR_COUNTRY_CERT_IODOOR 0x30 +#define PDR_COUNTRY_CERT_IODOOR_BOTH 0x00 +#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20 +#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR 0x30 +#define PDR_COUNTRY_CERT_INDEX 0x0f + +/* Specific LMAC FW/HW variant definitions */ +#define PDR_SYNTH_FRONTEND_MASK 0x0007 +#define PDR_SYNTH_FRONTEND_DUETTE3 0x0001 +#define PDR_SYNTH_FRONTEND_DUETTE2 0x0002 +#define PDR_SYNTH_FRONTEND_FRISBEE 0x0003 +#define PDR_SYNTH_FRONTEND_XBOW 0x0004 +#define PDR_SYNTH_FRONTEND_LONGBOW 0x0005 +#define PDR_SYNTH_IQ_CAL_MASK 0x0018 +#define PDR_SYNTH_IQ_CAL_PA_DETECTOR 0x0000 +#define PDR_SYNTH_IQ_CAL_DISABLED 0x0008 +#define PDR_SYNTH_IQ_CAL_ZIF 0x0010 +#define PDR_SYNTH_FAA_SWITCH_MASK 0x0020 +#define PDR_SYNTH_FAA_SWITCH_ENABLED 0x0020 +#define PDR_SYNTH_24_GHZ_MASK 0x0040 +#define PDR_SYNTH_24_GHZ_DISABLED 0x0040 +#define PDR_SYNTH_5_GHZ_MASK 0x0080 +#define PDR_SYNTH_5_GHZ_DISABLED 0x0080 +#define PDR_SYNTH_RX_DIV_MASK 0x0100 +#define PDR_SYNTH_RX_DIV_SUPPORTED 0x0100 +#define PDR_SYNTH_TX_DIV_MASK 0x0200 +#define PDR_SYNTH_TX_DIV_SUPPORTED 0x0200 +#define PDR_SYNTH_ASM_MASK 0x0400 +#define PDR_SYNTH_ASM_XSWON 0x0400 + +#endif /* EEPROM_H */ -- cgit v1.2.3-18-g5258 From 76074e1670b197385ce93242e3ba3ccc7a6be377 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 23 Jun 2009 10:37:40 -0500 Subject: p54: Move firmware code Copy the firmware i/o code from p54common.c into a new file fwio.c Signed-off-by: Christian Lamparter Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/p54/fwio.c | 697 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 697 insertions(+) create mode 100644 drivers/net/wireless/p54/fwio.c (limited to 'drivers') diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c new file mode 100644 index 00000000000..178efbce461 --- /dev/null +++ b/drivers/net/wireless/p54/fwio.c @@ -0,0 +1,697 @@ +/* + * Firmware I/O code for mac80211 Prism54 drivers + * + * Copyright (c) 2006, Michael Wu + * Copyright (c) 2007-2009, Christian Lamparter + * Copyright 2008, Johannes Berg + * + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * - stlc45xx driver + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include + +#include "p54.h" +#include "eeprom.h" +#include "lmac.h" + +int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) +{ + struct p54_common *priv = dev->priv; + struct exp_if *exp_if; + struct bootrec *bootrec; + u32 *data = (u32 *)fw->data; + u32 *end_data = (u32 *)fw->data + (fw->size >> 2); + u8 *fw_version = NULL; + size_t len; + int i; + int maxlen; + + if (priv->rx_start) + return 0; + + while (data < end_data && *data) + data++; + + while (data < end_data && !*data) + data++; + + bootrec = (struct bootrec *) data; + + while (bootrec->data <= end_data && (bootrec->data + + (len = le32_to_cpu(bootrec->len))) <= end_data) { + u32 code = le32_to_cpu(bootrec->code); + switch (code) { + case BR_CODE_COMPONENT_ID: + priv->fw_interface = be32_to_cpup((__be32 *) + bootrec->data); + switch (priv->fw_interface) { + case FW_LM86: + case FW_LM20: + case FW_LM87: { + char *iftype = (char *)bootrec->data; + printk(KERN_INFO "%s: p54 detected a LM%c%c " + "firmware\n", + wiphy_name(priv->hw->wiphy), + iftype[2], iftype[3]); + break; + } + case FW_FMAC: + default: + printk(KERN_ERR "%s: unsupported firmware\n", + wiphy_name(priv->hw->wiphy)); + return -ENODEV; + } + break; + case BR_CODE_COMPONENT_VERSION: + /* 24 bytes should be enough for all firmwares */ + if (strnlen((unsigned char *) bootrec->data, 24) < 24) + fw_version = (unsigned char *) bootrec->data; + break; + case BR_CODE_DESCR: { + struct bootrec_desc *desc = + (struct bootrec_desc *)bootrec->data; + priv->rx_start = le32_to_cpu(desc->rx_start); + /* FIXME add sanity checking */ + priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500; + priv->headroom = desc->headroom; + priv->tailroom = desc->tailroom; + priv->privacy_caps = desc->privacy_caps; + priv->rx_keycache_size = desc->rx_keycache_size; + if (le32_to_cpu(bootrec->len) == 11) + priv->rx_mtu = le16_to_cpu(desc->rx_mtu); + else + priv->rx_mtu = (size_t) + 0x620 - priv->tx_hdr_len; + maxlen = priv->tx_hdr_len + /* USB devices */ + sizeof(struct p54_rx_data) + + 4 + /* rx alignment */ + IEEE80211_MAX_FRAG_THRESHOLD; + if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) { + printk(KERN_INFO "p54: rx_mtu reduced from %d " + "to %d\n", priv->rx_mtu, maxlen); + priv->rx_mtu = maxlen; + } + break; + } + case BR_CODE_EXPOSED_IF: + exp_if = (struct exp_if *) bootrec->data; + for (i = 0; i < (len * sizeof(*exp_if) / 4); i++) + if (exp_if[i].if_id == cpu_to_le16(IF_ID_LMAC)) + priv->fw_var = le16_to_cpu(exp_if[i].variant); + break; + case BR_CODE_DEPENDENT_IF: + break; + case BR_CODE_END_OF_BRA: + case LEGACY_BR_CODE_END_OF_BRA: + end_data = NULL; + break; + default: + break; + } + bootrec = (struct bootrec *)&bootrec->data[len]; + } + + if (fw_version) + printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n", + wiphy_name(priv->hw->wiphy), fw_version, + priv->fw_var >> 8, priv->fw_var & 0xff); + + if (priv->fw_var < 0x500) + printk(KERN_INFO "%s: you are using an obsolete firmware. " + "visit http://wireless.kernel.org/en/users/Drivers/p54 " + "and grab one for \"kernel >= 2.6.28\"!\n", + wiphy_name(priv->hw->wiphy)); + + if (priv->fw_var >= 0x300) { + /* Firmware supports QoS, use it! */ + + if (priv->fw_var >= 0x500) { + priv->tx_stats[P54_QUEUE_AC_VO].limit = 16; + priv->tx_stats[P54_QUEUE_AC_VI].limit = 16; + priv->tx_stats[P54_QUEUE_AC_BE].limit = 16; + priv->tx_stats[P54_QUEUE_AC_BK].limit = 16; + } else { + priv->tx_stats[P54_QUEUE_AC_VO].limit = 3; + priv->tx_stats[P54_QUEUE_AC_VI].limit = 4; + priv->tx_stats[P54_QUEUE_AC_BE].limit = 3; + priv->tx_stats[P54_QUEUE_AC_BK].limit = 2; + } + priv->hw->queues = P54_QUEUE_AC_NUM; + } + + printk(KERN_INFO "%s: cryptographic accelerator " + "WEP:%s, TKIP:%s, CCMP:%s\n", wiphy_name(priv->hw->wiphy), + (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" : + "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP | + BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no", + (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ? + "YES" : "no"); + + if (priv->rx_keycache_size) { + /* + * NOTE: + * + * The firmware provides at most 255 (0 - 254) slots + * for keys which are then used to offload decryption. + * As a result the 255 entry (aka 0xff) can be used + * safely by the driver to mark keys that didn't fit + * into the full cache. This trick saves us from + * keeping a extra list for uploaded keys. + */ + + priv->used_rxkeys = kzalloc(BITS_TO_LONGS( + priv->rx_keycache_size), GFP_KERNEL); + + if (!priv->used_rxkeys) + return -ENOMEM; + } + + return 0; +} +EXPORT_SYMBOL_GPL(p54_parse_firmware); + +static struct sk_buff *p54_alloc_skb(struct p54_common *priv, u16 hdr_flags, + u16 payload_len, u16 type, gfp_t memflags) +{ + struct p54_hdr *hdr; + struct sk_buff *skb; + size_t frame_len = sizeof(*hdr) + payload_len; + + if (frame_len > P54_MAX_CTRL_FRAME_LEN) + return NULL; + + if (unlikely(skb_queue_len(&priv->tx_pending) > 64)) + return NULL; + + skb = __dev_alloc_skb(priv->tx_hdr_len + frame_len, memflags); + if (!skb) + return NULL; + skb_reserve(skb, priv->tx_hdr_len); + + hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr)); + hdr->flags = cpu_to_le16(hdr_flags); + hdr->len = cpu_to_le16(payload_len); + hdr->type = cpu_to_le16(type); + hdr->tries = hdr->rts_tries = 0; + return skb; +} + +int p54_download_eeprom(struct p54_common *priv, void *buf, + u16 offset, u16 len) +{ + struct p54_eeprom_lm86 *eeprom_hdr; + struct sk_buff *skb; + size_t eeprom_hdr_size; + int ret = 0; + + if (priv->fw_var >= 0x509) + eeprom_hdr_size = sizeof(*eeprom_hdr); + else + eeprom_hdr_size = 0x4; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL, eeprom_hdr_size + + len, P54_CONTROL_TYPE_EEPROM_READBACK, + GFP_KERNEL); + if (unlikely(!skb)) + return -ENOMEM; + + mutex_lock(&priv->eeprom_mutex); + priv->eeprom = buf; + eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb, + eeprom_hdr_size + len); + + if (priv->fw_var < 0x509) { + eeprom_hdr->v1.offset = cpu_to_le16(offset); + eeprom_hdr->v1.len = cpu_to_le16(len); + } else { + eeprom_hdr->v2.offset = cpu_to_le32(offset); + eeprom_hdr->v2.len = cpu_to_le16(len); + eeprom_hdr->v2.magic2 = 0xf; + memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4); + } + + p54_tx(priv, skb); + + if (!wait_for_completion_interruptible_timeout( + &priv->eeprom_comp, HZ)) { + printk(KERN_ERR "%s: device does not respond!\n", + wiphy_name(priv->hw->wiphy)); + ret = -EBUSY; + } + priv->eeprom = NULL; + mutex_unlock(&priv->eeprom_mutex); + return ret; +} + +int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set) +{ + struct sk_buff *skb; + struct p54_tim *tim; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*tim), + P54_CONTROL_TYPE_TIM, GFP_ATOMIC); + if (unlikely(!skb)) + return -ENOMEM; + + tim = (struct p54_tim *) skb_put(skb, sizeof(*tim)); + tim->count = 1; + tim->entry[0] = cpu_to_le16(set ? (aid | 0x8000) : aid); + p54_tx(priv, skb); + return 0; +} + +int p54_sta_unlock(struct p54_common *priv, u8 *addr) +{ + struct sk_buff *skb; + struct p54_sta_unlock *sta; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*sta), + P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC); + if (unlikely(!skb)) + return -ENOMEM; + + sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta)); + memcpy(sta->addr, addr, ETH_ALEN); + p54_tx(priv, skb); + return 0; +} + +int p54_tx_cancel(struct p54_common *priv, __le32 req_id) +{ + struct sk_buff *skb; + struct p54_txcancel *cancel; + + if (unlikely(req_id < priv->rx_start || req_id > priv->rx_end)) + return -EINVAL; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel), + P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC); + if (unlikely(!skb)) + return -ENOMEM; + + cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel)); + cancel->req_id = req_id; + p54_tx(priv, skb); + return 0; +} + +int p54_setup_mac(struct p54_common *priv) +{ + struct sk_buff *skb; + struct p54_setup_mac *setup; + u16 mode; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup), + P54_CONTROL_TYPE_SETUP, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup)); + if (priv->hw->conf.radio_enabled) { + switch (priv->mode) { + case NL80211_IFTYPE_STATION: + mode = P54_FILTER_TYPE_STATION; + break; + case NL80211_IFTYPE_AP: + mode = P54_FILTER_TYPE_AP; + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + mode = P54_FILTER_TYPE_IBSS; + break; + case NL80211_IFTYPE_MONITOR: + mode = P54_FILTER_TYPE_PROMISCUOUS; + break; + default: + mode = P54_FILTER_TYPE_HIBERNATE; + break; + } + + /* + * "TRANSPARENT and PROMISCUOUS are mutually exclusive" + * STSW45X0C LMAC API - page 12 + */ + if (((priv->filter_flags & FIF_PROMISC_IN_BSS) || + (priv->filter_flags & FIF_OTHER_BSS)) && + (mode != P54_FILTER_TYPE_PROMISCUOUS)) + mode |= P54_FILTER_TYPE_TRANSPARENT; + } else + mode = P54_FILTER_TYPE_HIBERNATE; + + setup->mac_mode = cpu_to_le16(mode); + memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN); + memcpy(setup->bssid, priv->bssid, ETH_ALEN); + setup->rx_antenna = 2 & priv->rx_diversity_mask; /* automatic */ + setup->rx_align = 0; + if (priv->fw_var < 0x500) { + setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); + memset(setup->v1.rts_rates, 0, 8); + setup->v1.rx_addr = cpu_to_le32(priv->rx_end); + setup->v1.max_rx = cpu_to_le16(priv->rx_mtu); + setup->v1.rxhw = cpu_to_le16(priv->rxhw); + setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer); + setup->v1.unalloc0 = cpu_to_le16(0); + } else { + setup->v2.rx_addr = cpu_to_le32(priv->rx_end); + setup->v2.max_rx = cpu_to_le16(priv->rx_mtu); + setup->v2.rxhw = cpu_to_le16(priv->rxhw); + setup->v2.timer = cpu_to_le16(priv->wakeup_timer); + setup->v2.truncate = cpu_to_le16(48896); + setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); + setup->v2.sbss_offset = 0; + setup->v2.mcast_window = 0; + setup->v2.rx_rssi_threshold = 0; + setup->v2.rx_ed_threshold = 0; + setup->v2.ref_clock = cpu_to_le32(644245094); + setup->v2.lpf_bandwidth = cpu_to_le16(65535); + setup->v2.osc_start_delay = cpu_to_le16(65535); + } + p54_tx(priv, skb); + return 0; +} + +int p54_scan(struct p54_common *priv, u16 mode, u16 dwell) +{ + struct sk_buff *skb; + struct p54_hdr *hdr; + struct p54_scan_head *head; + struct p54_iq_autocal_entry *iq_autocal; + union p54_scan_body_union *body; + struct p54_scan_tail_rate *rate; + struct pda_rssi_cal_entry *rssi; + unsigned int i; + void *entry; + int band = priv->hw->conf.channel->band; + __le16 freq = cpu_to_le16(priv->hw->conf.channel->center_freq); + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) + + 2 + sizeof(*iq_autocal) + sizeof(*body) + + sizeof(*rate) + 2 * sizeof(*rssi), + P54_CONTROL_TYPE_SCAN, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + head = (struct p54_scan_head *) skb_put(skb, sizeof(*head)); + memset(head->scan_params, 0, sizeof(head->scan_params)); + head->mode = cpu_to_le16(mode); + head->dwell = cpu_to_le16(dwell); + head->freq = freq; + + if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { + __le16 *pa_power_points = (__le16 *) skb_put(skb, 2); + *pa_power_points = cpu_to_le16(0x0c); + } + + iq_autocal = (void *) skb_put(skb, sizeof(*iq_autocal)); + for (i = 0; i < priv->iq_autocal_len; i++) { + if (priv->iq_autocal[i].freq != freq) + continue; + + memcpy(iq_autocal, &priv->iq_autocal[i].params, + sizeof(struct p54_iq_autocal_entry)); + break; + } + if (i == priv->iq_autocal_len) + goto err; + + if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) + body = (void *) skb_put(skb, sizeof(body->longbow)); + else + body = (void *) skb_put(skb, sizeof(body->normal)); + + for (i = 0; i < priv->output_limit->entries; i++) { + __le16 *entry_freq = (void *) (priv->output_limit->data + + priv->output_limit->entry_size * i); + + if (*entry_freq != freq) + continue; + + if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { + memcpy(&body->longbow.power_limits, + (void *) entry_freq + sizeof(__le16), + priv->output_limit->entry_size); + } else { + struct pda_channel_output_limit *limits = + (void *) entry_freq; + + body->normal.val_barker = 0x38; + body->normal.val_bpsk = body->normal.dup_bpsk = + limits->val_bpsk; + body->normal.val_qpsk = body->normal.dup_qpsk = + limits->val_qpsk; + body->normal.val_16qam = body->normal.dup_16qam = + limits->val_16qam; + body->normal.val_64qam = body->normal.dup_64qam = + limits->val_64qam; + } + break; + } + if (i == priv->output_limit->entries) + goto err; + + entry = (void *)(priv->curve_data->data + priv->curve_data->offset); + for (i = 0; i < priv->curve_data->entries; i++) { + if (*((__le16 *)entry) != freq) { + entry += priv->curve_data->entry_size; + continue; + } + + if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { + memcpy(&body->longbow.curve_data, + (void *) entry + sizeof(__le16), + priv->curve_data->entry_size); + } else { + struct p54_scan_body *chan = &body->normal; + struct pda_pa_curve_data *curve_data = + (void *) priv->curve_data->data; + + entry += sizeof(__le16); + chan->pa_points_per_curve = 8; + memset(chan->curve_data, 0, sizeof(*chan->curve_data)); + memcpy(chan->curve_data, entry, + sizeof(struct p54_pa_curve_data_sample) * + min((u8)8, curve_data->points_per_channel)); + } + break; + } + if (i == priv->curve_data->entries) + goto err; + + if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) { + rate = (void *) skb_put(skb, sizeof(*rate)); + rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); + for (i = 0; i < sizeof(rate->rts_rates); i++) + rate->rts_rates[i] = i; + } + + rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi)); + rssi->mul = cpu_to_le16(priv->rssical_db[band].mul); + rssi->add = cpu_to_le16(priv->rssical_db[band].add); + if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { + /* Longbow frontend needs ever more */ + rssi = (void *) skb_put(skb, sizeof(*rssi)); + rssi->mul = cpu_to_le16(priv->rssical_db[band].longbow_unkn); + rssi->add = cpu_to_le16(priv->rssical_db[band].longbow_unk2); + } + + if (priv->fw_var >= 0x509) { + rate = (void *) skb_put(skb, sizeof(*rate)); + rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); + for (i = 0; i < sizeof(rate->rts_rates); i++) + rate->rts_rates[i] = i; + } + + hdr = (struct p54_hdr *) skb->data; + hdr->len = cpu_to_le16(skb->len - sizeof(*hdr)); + + p54_tx(priv, skb); + return 0; + +err: + printk(KERN_ERR "%s: frequency change to channel %d failed.\n", + wiphy_name(priv->hw->wiphy), ieee80211_frequency_to_channel( + priv->hw->conf.channel->center_freq)); + + dev_kfree_skb_any(skb); + return -EINVAL; +} + +int p54_set_leds(struct p54_common *priv) +{ + struct sk_buff *skb; + struct p54_led *led; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led), + P54_CONTROL_TYPE_LED, GFP_ATOMIC); + if (unlikely(!skb)) + return -ENOMEM; + + led = (struct p54_led *) skb_put(skb, sizeof(*led)); + led->flags = cpu_to_le16(0x0003); + led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state); + led->delay[0] = cpu_to_le16(1); + led->delay[1] = cpu_to_le16(0); + p54_tx(priv, skb); + return 0; +} + +int p54_set_edcf(struct p54_common *priv) +{ + struct sk_buff *skb; + struct p54_edcf *edcf; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf), + P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC); + if (unlikely(!skb)) + return -ENOMEM; + + edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf)); + if (priv->use_short_slot) { + edcf->slottime = 9; + edcf->sifs = 0x10; + edcf->eofpad = 0x00; + } else { + edcf->slottime = 20; + edcf->sifs = 0x0a; + edcf->eofpad = 0x06; + } + /* (see prism54/isl_oid.h for further details) */ + edcf->frameburst = cpu_to_le16(0); + edcf->round_trip_delay = cpu_to_le16(0); + edcf->flags = 0; + memset(edcf->mapping, 0, sizeof(edcf->mapping)); + memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue)); + p54_tx(priv, skb); + return 0; +} + +int p54_set_ps(struct p54_common *priv) +{ + struct sk_buff *skb; + struct p54_psm *psm; + unsigned int i; + u16 mode; + + if (priv->hw->conf.flags & IEEE80211_CONF_PS) + mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM | + P54_PSM_CHECKSUM | P54_PSM_MCBC; + else + mode = P54_PSM_CAM; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*psm), + P54_CONTROL_TYPE_PSM, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + psm = (struct p54_psm *)skb_put(skb, sizeof(*psm)); + psm->mode = cpu_to_le16(mode); + psm->aid = cpu_to_le16(priv->aid); + for (i = 0; i < ARRAY_SIZE(psm->intervals); i++) { + psm->intervals[i].interval = + cpu_to_le16(priv->hw->conf.listen_interval); + psm->intervals[i].periods = cpu_to_le16(1); + } + + psm->beacon_rssi_skip_max = 200; + psm->rssi_delta_threshold = 0; + psm->nr = 10; + psm->exclude[0] = 0; + + p54_tx(priv, skb); + return 0; +} + +int p54_init_xbow_synth(struct p54_common *priv) +{ + struct sk_buff *skb; + struct p54_xbow_synth *xbow; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow), + P54_CONTROL_TYPE_XBOW_SYNTH_CFG, GFP_KERNEL); + if (unlikely(!skb)) + return -ENOMEM; + + xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow)); + xbow->magic1 = cpu_to_le16(0x1); + xbow->magic2 = cpu_to_le16(0x2); + xbow->freq = cpu_to_le16(5390); + memset(xbow->padding, 0, sizeof(xbow->padding)); + p54_tx(priv, skb); + return 0; +} + +int p54_upload_key(struct p54_common *priv, u8 algo, int slot, u8 idx, u8 len, + u8 *addr, u8* key) +{ + struct sk_buff *skb; + struct p54_keycache *rxkey; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey), + P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL); + if (unlikely(!skb)) + return -ENOMEM; + + rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey)); + rxkey->entry = slot; + rxkey->key_id = idx; + rxkey->key_type = algo; + if (addr) + memcpy(rxkey->mac, addr, ETH_ALEN); + else + memset(rxkey->mac, ~0, ETH_ALEN); + + switch (algo) { + case P54_CRYPTO_WEP: + case P54_CRYPTO_AESCCMP: + rxkey->key_len = min_t(u8, 16, len); + memcpy(rxkey->key, key, rxkey->key_len); + break; + + case P54_CRYPTO_TKIPMICHAEL: + rxkey->key_len = 24; + memcpy(rxkey->key, key, 16); + memcpy(&(rxkey->key[16]), &(key + [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8); + break; + + case P54_CRYPTO_NONE: + rxkey->key_len = 0; + memset(rxkey->key, 0, sizeof(rxkey->key)); + break; + + default: + printk(KERN_ERR "%s: invalid cryptographic algorithm: %d\n", + wiphy_name(priv->hw->wiphy), algo); + dev_kfree_skb(skb); + return -EINVAL; + } + + p54_tx(priv, skb); + return 0; +} + +int p54_fetch_statistics(struct p54_common *priv) +{ + struct sk_buff *skb; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL, + sizeof(struct p54_statistics), + P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + p54_tx(priv, skb); + return 0; +} -- cgit v1.2.3-18-g5258 From 0597c0141cf011ccf76419cb4f96f99b0d4b6171 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 23 Jun 2009 10:37:59 -0500 Subject: p54: Move LED code Copy the LED code from p54common.c into a new file led.c Signed-off-by: Christian Lamparter Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/p54/led.c | 163 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 drivers/net/wireless/p54/led.c (limited to 'drivers') diff --git a/drivers/net/wireless/p54/led.c b/drivers/net/wireless/p54/led.c new file mode 100644 index 00000000000..c00115b206d --- /dev/null +++ b/drivers/net/wireless/p54/led.c @@ -0,0 +1,163 @@ +/* + * Common code for mac80211 Prism54 drivers + * + * Copyright (c) 2006, Michael Wu + * Copyright (c) 2007-2009, Christian Lamparter + * Copyright 2008, Johannes Berg + * + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * - stlc45xx driver + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include +#ifdef CONFIG_P54_LEDS +#include +#endif /* CONFIG_P54_LEDS */ + +#include "p54.h" +#include "lmac.h" + +static void p54_update_leds(struct work_struct *work) +{ + struct p54_common *priv = container_of(work, struct p54_common, + led_work.work); + int err, i, tmp, blink_delay = 400; + bool rerun = false; + + /* Don't toggle the LED, when the device is down. */ + if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) + return ; + + for (i = 0; i < ARRAY_SIZE(priv->leds); i++) + if (priv->leds[i].toggled) { + priv->softled_state |= BIT(i); + + tmp = 70 + 200 / (priv->leds[i].toggled); + if (tmp < blink_delay) + blink_delay = tmp; + + if (priv->leds[i].led_dev.brightness == LED_OFF) + rerun = true; + + priv->leds[i].toggled = + !!priv->leds[i].led_dev.brightness; + } else + priv->softled_state &= ~BIT(i); + + err = p54_set_leds(priv); + if (err && net_ratelimit()) + printk(KERN_ERR "%s: failed to update LEDs (%d).\n", + wiphy_name(priv->hw->wiphy), err); + + if (rerun) + queue_delayed_work(priv->hw->workqueue, &priv->led_work, + msecs_to_jiffies(blink_delay)); +} + +static void p54_led_brightness_set(struct led_classdev *led_dev, + enum led_brightness brightness) +{ + struct p54_led_dev *led = container_of(led_dev, struct p54_led_dev, + led_dev); + struct ieee80211_hw *dev = led->hw_dev; + struct p54_common *priv = dev->priv; + + if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) + return ; + + if ((brightness) && (led->registered)) { + led->toggled++; + queue_delayed_work(priv->hw->workqueue, &priv->led_work, + HZ/10); + } +} + +static int p54_register_led(struct p54_common *priv, + unsigned int led_index, + char *name, char *trigger) +{ + struct p54_led_dev *led = &priv->leds[led_index]; + int err; + + if (led->registered) + return -EEXIST; + + snprintf(led->name, sizeof(led->name), "p54-%s::%s", + wiphy_name(priv->hw->wiphy), name); + led->hw_dev = priv->hw; + led->index = led_index; + led->led_dev.name = led->name; + led->led_dev.default_trigger = trigger; + led->led_dev.brightness_set = p54_led_brightness_set; + + err = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_dev); + if (err) + printk(KERN_ERR "%s: Failed to register %s LED.\n", + wiphy_name(priv->hw->wiphy), name); + else + led->registered = 1; + + return err; +} + +int p54_init_leds(struct p54_common *priv) +{ + int err; + + /* + * TODO: + * Figure out if the EEPROM contains some hints about the number + * of available/programmable LEDs of the device. + */ + + INIT_DELAYED_WORK(&priv->led_work, p54_update_leds); + + err = p54_register_led(priv, 0, "assoc", + ieee80211_get_assoc_led_name(priv->hw)); + if (err) + return err; + + err = p54_register_led(priv, 1, "tx", + ieee80211_get_tx_led_name(priv->hw)); + if (err) + return err; + + err = p54_register_led(priv, 2, "rx", + ieee80211_get_rx_led_name(priv->hw)); + if (err) + return err; + + err = p54_register_led(priv, 3, "radio", + ieee80211_get_radio_led_name(priv->hw)); + if (err) + return err; + + err = p54_set_leds(priv); + return err; +} + +void p54_unregister_leds(struct p54_common *priv) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(priv->leds); i++) { + if (priv->leds[i].registered) { + priv->leds[i].registered = false; + priv->leds[i].toggled = 0; + led_classdev_unregister(&priv->leds[i].led_dev); + } + } + + cancel_delayed_work_sync(&priv->led_work); +} -- cgit v1.2.3-18-g5258 From 0533f796993f7e8ccd682005bfbbe4135b24587e Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 23 Jun 2009 10:38:24 -0500 Subject: p54: Move LMAC interface definitions Copy the LMAC Interface specific definitions from p54common.h into a new file lmac.h Signed-off-by: Christian Lamparter Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/p54/lmac.h | 551 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 551 insertions(+) create mode 100644 drivers/net/wireless/p54/lmac.h (limited to 'drivers') diff --git a/drivers/net/wireless/p54/lmac.h b/drivers/net/wireless/p54/lmac.h new file mode 100644 index 00000000000..0496cff26b3 --- /dev/null +++ b/drivers/net/wireless/p54/lmac.h @@ -0,0 +1,551 @@ +/* + * LMAC Interface specific definitions for mac80211 Prism54 drivers + * + * Copyright (c) 2006, Michael Wu + * Copyright (c) 2007 - 2009, Christian Lamparter + * + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * + * - LMAC API interface header file for STLC4560 (lmac_longbow.h) + * Copyright (C) 2007 Conexant Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef LMAC_H +#define LMAC_H + +enum p54_control_frame_types { + P54_CONTROL_TYPE_SETUP = 0, + P54_CONTROL_TYPE_SCAN, + P54_CONTROL_TYPE_TRAP, + P54_CONTROL_TYPE_DCFINIT, + P54_CONTROL_TYPE_RX_KEYCACHE, + P54_CONTROL_TYPE_TIM, + P54_CONTROL_TYPE_PSM, + P54_CONTROL_TYPE_TXCANCEL, + P54_CONTROL_TYPE_TXDONE, + P54_CONTROL_TYPE_BURST, + P54_CONTROL_TYPE_STAT_READBACK, + P54_CONTROL_TYPE_BBP, + P54_CONTROL_TYPE_EEPROM_READBACK, + P54_CONTROL_TYPE_LED, + P54_CONTROL_TYPE_GPIO, + P54_CONTROL_TYPE_TIMER, + P54_CONTROL_TYPE_MODULATION, + P54_CONTROL_TYPE_SYNTH_CONFIG, + P54_CONTROL_TYPE_DETECTOR_VALUE, + P54_CONTROL_TYPE_XBOW_SYNTH_CFG, + P54_CONTROL_TYPE_CCE_QUIET, + P54_CONTROL_TYPE_PSM_STA_UNLOCK, + P54_CONTROL_TYPE_PCS, + P54_CONTROL_TYPE_BT_BALANCER = 28, + P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30, + P54_CONTROL_TYPE_ARPTABLE = 31, + P54_CONTROL_TYPE_BT_OPTIONS = 35, +}; + +#define P54_HDR_FLAG_CONTROL BIT(15) +#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0)) +#define P54_HDR_FLAG_DATA_ALIGN BIT(14) + +#define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0) +#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1) +#define P54_HDR_FLAG_DATA_OUT_SEQNR BIT(2) +#define P54_HDR_FLAG_DATA_OUT_BIT3 BIT(3) +#define P54_HDR_FLAG_DATA_OUT_BURST BIT(4) +#define P54_HDR_FLAG_DATA_OUT_NOCANCEL BIT(5) +#define P54_HDR_FLAG_DATA_OUT_CLEARTIM BIT(6) +#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE BIT(7) +#define P54_HDR_FLAG_DATA_OUT_COMPRESS BIT(8) +#define P54_HDR_FLAG_DATA_OUT_CONCAT BIT(9) +#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT BIT(10) +#define P54_HDR_FLAG_DATA_OUT_WAITEOSP BIT(11) + +#define P54_HDR_FLAG_DATA_IN_FCS_GOOD BIT(0) +#define P54_HDR_FLAG_DATA_IN_MATCH_MAC BIT(1) +#define P54_HDR_FLAG_DATA_IN_MCBC BIT(2) +#define P54_HDR_FLAG_DATA_IN_BEACON BIT(3) +#define P54_HDR_FLAG_DATA_IN_MATCH_BSS BIT(4) +#define P54_HDR_FLAG_DATA_IN_BCAST_BSS BIT(5) +#define P54_HDR_FLAG_DATA_IN_DATA BIT(6) +#define P54_HDR_FLAG_DATA_IN_TRUNCATED BIT(7) +#define P54_HDR_FLAG_DATA_IN_BIT8 BIT(8) +#define P54_HDR_FLAG_DATA_IN_TRANSPARENT BIT(9) + +struct p54_hdr { + __le16 flags; + __le16 len; + __le32 req_id; + __le16 type; /* enum p54_control_frame_types */ + u8 rts_tries; + u8 tries; + u8 data[0]; +} __packed; + +#define GET_REQ_ID(skb) \ + (((struct p54_hdr *) ((struct sk_buff *) skb)->data)->req_id) \ + +#define FREE_AFTER_TX(skb) \ + ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \ + flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET)) + +#define IS_DATA_FRAME(skb) \ + (!((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \ + flags) & cpu_to_le16(P54_HDR_FLAG_CONTROL))) + +/* + * shared interface ID definitions + * The interface ID is a unique identification of a specific interface. + * The following values are reserved: 0x0000, 0x0002, 0x0012, 0x0014, 0x0015 + */ +#define IF_ID_ISL36356A 0x0001 /* ISL36356A <-> Firmware */ +#define IF_ID_MVC 0x0003 /* MAC Virtual Coprocessor */ +#define IF_ID_DEBUG 0x0008 /* PolDebug Interface */ +#define IF_ID_PRODUCT 0x0009 +#define IF_ID_OEM 0x000a +#define IF_ID_PCI3877 0x000b /* 3877 <-> Host PCI */ +#define IF_ID_ISL37704C 0x000c /* ISL37704C <-> Fw */ +#define IF_ID_ISL39000 0x000f /* ISL39000 <-> Fw */ +#define IF_ID_ISL39300A 0x0010 /* ISL39300A <-> Fw */ +#define IF_ID_ISL37700_UAP 0x0016 /* ISL37700 uAP Fw <-> Fw */ +#define IF_ID_ISL39000_UAP 0x0017 /* ISL39000 uAP Fw <-> Fw */ +#define IF_ID_LMAC 0x001a /* Interface exposed by LMAC */ + +struct exp_if { + __le16 role; + __le16 if_id; + __le16 variant; + __le16 btm_compat; + __le16 top_compat; +} __packed; + +struct dep_if { + __le16 role; + __le16 if_id; + __le16 variant; +} __packed; + +/* driver <-> lmac definitions */ +struct p54_eeprom_lm86 { + union { + struct { + __le16 offset; + __le16 len; + u8 data[0]; + } __packed v1; + struct { + __le32 offset; + __le16 len; + u8 magic2; + u8 pad; + u8 magic[4]; + u8 data[0]; + } __packed v2; + } __packed; +} __packed; + +enum p54_rx_decrypt_status { + P54_DECRYPT_NONE = 0, + P54_DECRYPT_OK, + P54_DECRYPT_NOKEY, + P54_DECRYPT_NOMICHAEL, + P54_DECRYPT_NOCKIPMIC, + P54_DECRYPT_FAIL_WEP, + P54_DECRYPT_FAIL_TKIP, + P54_DECRYPT_FAIL_MICHAEL, + P54_DECRYPT_FAIL_CKIPKP, + P54_DECRYPT_FAIL_CKIPMIC, + P54_DECRYPT_FAIL_AESCCMP +}; + +struct p54_rx_data { + __le16 flags; + __le16 len; + __le16 freq; + u8 antenna; + u8 rate; + u8 rssi; + u8 quality; + u8 decrypt_status; + u8 rssi_raw; + __le32 tsf32; + __le32 unalloc0; + u8 align[0]; +} __packed; + +enum p54_trap_type { + P54_TRAP_SCAN = 0, + P54_TRAP_TIMER, + P54_TRAP_BEACON_TX, + P54_TRAP_FAA_RADIO_ON, + P54_TRAP_FAA_RADIO_OFF, + P54_TRAP_RADAR, + P54_TRAP_NO_BEACON, + P54_TRAP_TBTT, + P54_TRAP_SCO_ENTER, + P54_TRAP_SCO_EXIT +}; + +struct p54_trap { + __le16 event; + __le16 frequency; +} __packed; + +enum p54_frame_sent_status { + P54_TX_OK = 0, + P54_TX_FAILED, + P54_TX_PSM, + P54_TX_PSM_CANCELLED = 4 +}; + +struct p54_frame_sent { + u8 status; + u8 tries; + u8 ack_rssi; + u8 quality; + __le16 seq; + u8 antenna; + u8 padding; +} __packed; + +enum p54_tx_data_crypt { + P54_CRYPTO_NONE = 0, + P54_CRYPTO_WEP, + P54_CRYPTO_TKIP, + P54_CRYPTO_TKIPMICHAEL, + P54_CRYPTO_CCX_WEPMIC, + P54_CRYPTO_CCX_KPMIC, + P54_CRYPTO_CCX_KP, + P54_CRYPTO_AESCCMP +}; + +enum p54_tx_data_queue { + P54_QUEUE_BEACON = 0, + P54_QUEUE_FWSCAN = 1, + P54_QUEUE_MGMT = 2, + P54_QUEUE_CAB = 3, + P54_QUEUE_DATA = 4, + + P54_QUEUE_AC_NUM = 4, + P54_QUEUE_AC_VO = 4, + P54_QUEUE_AC_VI = 5, + P54_QUEUE_AC_BE = 6, + P54_QUEUE_AC_BK = 7, + + /* keep last */ + P54_QUEUE_NUM = 8, +}; + +#define IS_QOS_QUEUE(n) (n >= P54_QUEUE_DATA) + +struct p54_tx_data { + u8 rateset[8]; + u8 rts_rate_idx; + u8 crypt_offset; + u8 key_type; + u8 key_len; + u8 key[16]; + u8 hw_queue; + u8 backlog; + __le16 durations[4]; + u8 tx_antenna; + union { + struct { + u8 cts_rate; + __le16 output_power; + } __packed longbow; + struct { + u8 output_power; + u8 cts_rate; + u8 unalloc; + } __packed normal; + } __packed; + u8 unalloc2[2]; + u8 align[0]; +} __packed; + +/* unit is ms */ +#define P54_TX_FRAME_LIFETIME 2000 +#define P54_TX_TIMEOUT 4000 +#define P54_STATISTICS_UPDATE 5000 + +#define P54_FILTER_TYPE_NONE 0 +#define P54_FILTER_TYPE_STATION BIT(0) +#define P54_FILTER_TYPE_IBSS BIT(1) +#define P54_FILTER_TYPE_AP BIT(2) +#define P54_FILTER_TYPE_TRANSPARENT BIT(3) +#define P54_FILTER_TYPE_PROMISCUOUS BIT(4) +#define P54_FILTER_TYPE_HIBERNATE BIT(5) +#define P54_FILTER_TYPE_NOACK BIT(6) +#define P54_FILTER_TYPE_RX_DISABLED BIT(7) + +struct p54_setup_mac { + __le16 mac_mode; + u8 mac_addr[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + u8 rx_antenna; + u8 rx_align; + union { + struct { + __le32 basic_rate_mask; + u8 rts_rates[8]; + __le32 rx_addr; + __le16 max_rx; + __le16 rxhw; + __le16 wakeup_timer; + __le16 unalloc0; + } __packed v1; + struct { + __le32 rx_addr; + __le16 max_rx; + __le16 rxhw; + __le16 timer; + __le16 truncate; + __le32 basic_rate_mask; + u8 sbss_offset; + u8 mcast_window; + u8 rx_rssi_threshold; + u8 rx_ed_threshold; + __le32 ref_clock; + __le16 lpf_bandwidth; + __le16 osc_start_delay; + } __packed v2; + } __packed; +} __packed; + +#define P54_SETUP_V1_LEN 40 +#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac)) + +#define P54_SCAN_EXIT BIT(0) +#define P54_SCAN_TRAP BIT(1) +#define P54_SCAN_ACTIVE BIT(2) +#define P54_SCAN_FILTER BIT(3) + +struct p54_scan_head { + __le16 mode; + __le16 dwell; + u8 scan_params[20]; + __le16 freq; +} __packed; + +struct p54_pa_curve_data_sample { + u8 rf_power; + u8 pa_detector; + u8 data_barker; + u8 data_bpsk; + u8 data_qpsk; + u8 data_16qam; + u8 data_64qam; + u8 padding; +} __packed; + +struct p54_scan_body { + u8 pa_points_per_curve; + u8 val_barker; + u8 val_bpsk; + u8 val_qpsk; + u8 val_16qam; + u8 val_64qam; + struct p54_pa_curve_data_sample curve_data[8]; + u8 dup_bpsk; + u8 dup_qpsk; + u8 dup_16qam; + u8 dup_64qam; +} __packed; + +/* + * Warning: Longbow's structures are bogus. + */ +struct p54_channel_output_limit_longbow { + __le16 rf_power_points[12]; +} __packed; + +struct p54_pa_curve_data_sample_longbow { + __le16 rf_power; + __le16 pa_detector; + struct { + __le16 data[4]; + } points[3] __packed; +} __packed; + +struct p54_scan_body_longbow { + struct p54_channel_output_limit_longbow power_limits; + struct p54_pa_curve_data_sample_longbow curve_data[8]; + __le16 unkn[6]; /* maybe more power_limits or rate_mask */ +} __packed; + +union p54_scan_body_union { + struct p54_scan_body normal; + struct p54_scan_body_longbow longbow; +} __packed; + +struct p54_scan_tail_rate { + __le32 basic_rate_mask; + u8 rts_rates[8]; +} __packed; + +struct p54_led { + __le16 flags; + __le16 mask[2]; + __le16 delay[2]; +} __packed; + +struct p54_edcf { + u8 flags; + u8 slottime; + u8 sifs; + u8 eofpad; + struct p54_edcf_queue_param queue[8]; + u8 mapping[4]; + __le16 frameburst; + __le16 round_trip_delay; +} __packed; + +struct p54_statistics { + __le32 rx_success; + __le32 rx_bad_fcs; + __le32 rx_abort; + __le32 rx_abort_phy; + __le32 rts_success; + __le32 rts_fail; + __le32 tsf32; + __le32 airtime; + __le32 noise; + __le32 sample_noise[8]; + __le32 sample_cca; + __le32 sample_tx; +} __packed; + +struct p54_xbow_synth { + __le16 magic1; + __le16 magic2; + __le16 freq; + u32 padding[5]; +} __packed; + +struct p54_timer { + __le32 interval; +} __packed; + +struct p54_keycache { + u8 entry; + u8 key_id; + u8 mac[ETH_ALEN]; + u8 padding[2]; + u8 key_type; + u8 key_len; + u8 key[24]; +} __packed; + +struct p54_burst { + u8 flags; + u8 queue; + u8 backlog; + u8 pad; + __le16 durations[32]; +} __packed; + +struct p54_psm_interval { + __le16 interval; + __le16 periods; +} __packed; + +#define P54_PSM_CAM 0 +#define P54_PSM BIT(0) +#define P54_PSM_DTIM BIT(1) +#define P54_PSM_MCBC BIT(2) +#define P54_PSM_CHECKSUM BIT(3) +#define P54_PSM_SKIP_MORE_DATA BIT(4) +#define P54_PSM_BEACON_TIMEOUT BIT(5) +#define P54_PSM_HFOSLEEP BIT(6) +#define P54_PSM_AUTOSWITCH_SLEEP BIT(7) +#define P54_PSM_LPIT BIT(8) +#define P54_PSM_BF_UCAST_SKIP BIT(9) +#define P54_PSM_BF_MCAST_SKIP BIT(10) + +struct p54_psm { + __le16 mode; + __le16 aid; + struct p54_psm_interval intervals[4]; + u8 beacon_rssi_skip_max; + u8 rssi_delta_threshold; + u8 nr; + u8 exclude[1]; +} __packed; + +#define MC_FILTER_ADDRESS_NUM 4 + +struct p54_group_address_table { + __le16 filter_enable; + __le16 num_address; + u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN]; +} __packed; + +struct p54_txcancel { + __le32 req_id; +} __packed; + +struct p54_sta_unlock { + u8 addr[ETH_ALEN]; + u16 padding; +} __packed; + +#define P54_TIM_CLEAR BIT(15) +struct p54_tim { + u8 count; + u8 padding[3]; + __le16 entry[8]; +} __packed; + +struct p54_cce_quiet { + __le32 period; +} __packed; + +struct p54_bt_balancer { + __le16 prio_thresh; + __le16 acl_thresh; +} __packed; + +struct p54_arp_table { + __le16 filter_enable; + u8 ipv4_addr[4]; +} __packed; + +/* LED control */ +int p54_set_leds(struct p54_common *priv); +int p54_init_leds(struct p54_common *priv); +void p54_unregister_leds(struct p54_common *priv); + +/* xmit functions */ +int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb); +int p54_tx_cancel(struct p54_common *priv, __le32 req_id); +void p54_tx(struct p54_common *priv, struct sk_buff *skb); + +/* synth/phy configuration */ +int p54_init_xbow_synth(struct p54_common *priv); +int p54_scan(struct p54_common *priv, u16 mode, u16 dwell); + +/* MAC */ +int p54_sta_unlock(struct p54_common *priv, u8 *addr); +int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set); +int p54_setup_mac(struct p54_common *priv); +int p54_set_ps(struct p54_common *priv); +int p54_fetch_statistics(struct p54_common *priv); + +/* e/v DCF setup */ +int p54_set_edcf(struct p54_common *priv); + +/* cryptographic engine */ +int p54_upload_key(struct p54_common *priv, u8 algo, int slot, + u8 idx, u8 len, u8 *addr, u8* key); + +/* eeprom */ +int p54_download_eeprom(struct p54_common *priv, void *buf, + u16 offset, u16 len); + +#endif /* LMAC_H */ -- cgit v1.2.3-18-g5258 From 0ac0d6cedf6110381501c236339a9fbe13c3441d Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 23 Jun 2009 10:38:49 -0500 Subject: p54: Move mac80211 glue code Copy the mac80211 glue code from p54common.c into a new file main.c Signed-off-by: Christian Lamparter Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/p54/main.c | 607 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 607 insertions(+) create mode 100644 drivers/net/wireless/p54/main.c (limited to 'drivers') diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c new file mode 100644 index 00000000000..f9b4f6a238e --- /dev/null +++ b/drivers/net/wireless/p54/main.c @@ -0,0 +1,607 @@ +/* + * mac80211 glue code for mac80211 Prism54 drivers + * + * Copyright (c) 2006, Michael Wu + * Copyright (c) 2007-2009, Christian Lamparter + * Copyright 2008, Johannes Berg + * + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * - stlc45xx driver + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include + +#include "p54.h" +#include "lmac.h" + +static int modparam_nohwcrypt; +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); +MODULE_AUTHOR("Michael Wu "); +MODULE_DESCRIPTION("Softmac Prism54 common code"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("prism54common"); + +static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, + enum sta_notify_cmd notify_cmd, + struct ieee80211_sta *sta) +{ + struct p54_common *priv = dev->priv; + switch (notify_cmd) { + case STA_NOTIFY_ADD: + case STA_NOTIFY_REMOVE: + /* + * Notify the firmware that we don't want or we don't + * need to buffer frames for this station anymore. + */ + + p54_sta_unlock(priv, sta->addr); + break; + case STA_NOTIFY_AWAKE: + /* update the firmware's filter table */ + p54_sta_unlock(priv, sta->addr); + break; + default: + break; + } +} + +static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, + bool set) +{ + struct p54_common *priv = dev->priv; + + return p54_update_beacon_tim(priv, sta->aid, set); +} + +static int p54_beacon_format_ie_tim(struct sk_buff *skb) +{ + /* + * the good excuse for this mess is ... the firmware. + * The dummy TIM MUST be at the end of the beacon frame, + * because it'll be overwritten! + */ + + struct ieee80211_mgmt *mgmt = (void *)skb->data; + u8 *pos, *end; + + if (skb->len <= sizeof(mgmt)) + return -EINVAL; + + pos = (u8 *)mgmt->u.beacon.variable; + end = skb->data + skb->len; + while (pos < end) { + if (pos + 2 + pos[1] > end) + return -EINVAL; + + if (pos[0] == WLAN_EID_TIM) { + u8 dtim_len = pos[1]; + u8 dtim_period = pos[3]; + u8 *next = pos + 2 + dtim_len; + + if (dtim_len < 3) + return -EINVAL; + + memmove(pos, next, end - next); + + if (dtim_len > 3) + skb_trim(skb, skb->len - (dtim_len - 3)); + + pos = end - (dtim_len + 2); + + /* add the dummy at the end */ + pos[0] = WLAN_EID_TIM; + pos[1] = 3; + pos[2] = 0; + pos[3] = dtim_period; + pos[4] = 0; + return 0; + } + pos += 2 + pos[1]; + } + return 0; +} + +static int p54_beacon_update(struct p54_common *priv, + struct ieee80211_vif *vif) +{ + struct sk_buff *beacon; + __le32 old_beacon_req_id; + int ret; + + beacon = ieee80211_beacon_get(priv->hw, vif); + if (!beacon) + return -ENOMEM; + ret = p54_beacon_format_ie_tim(beacon); + if (ret) + return ret; + + old_beacon_req_id = priv->beacon_req_id; + priv->beacon_req_id = GET_REQ_ID(beacon); + + ret = p54_tx_80211(priv->hw, beacon); + if (ret) { + priv->beacon_req_id = old_beacon_req_id; + return -ENOSPC; + } + + priv->tsf_high32 = 0; + priv->tsf_low32 = 0; + + return 0; +} + +static int p54_start(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + int err; + + mutex_lock(&priv->conf_mutex); + err = priv->open(dev); + if (err) + goto out; + P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47); + P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94); + P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0); + P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0); + err = p54_set_edcf(priv); + if (err) + goto out; + + memset(priv->bssid, ~0, ETH_ALEN); + priv->mode = NL80211_IFTYPE_MONITOR; + err = p54_setup_mac(priv); + if (err) { + priv->mode = NL80211_IFTYPE_UNSPECIFIED; + goto out; + } + + queue_delayed_work(dev->workqueue, &priv->work, 0); + + priv->softled_state = 0; + err = p54_set_leds(priv); + +out: + mutex_unlock(&priv->conf_mutex); + return err; +} + +static void p54_stop(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + int i; + + mutex_lock(&priv->conf_mutex); + priv->mode = NL80211_IFTYPE_UNSPECIFIED; + priv->softled_state = 0; + p54_set_leds(priv); + + cancel_delayed_work_sync(&priv->work); + + priv->stop(dev); + skb_queue_purge(&priv->tx_pending); + skb_queue_purge(&priv->tx_queue); + for (i = 0; i < P54_QUEUE_NUM; i++) { + priv->tx_stats[i].count = 0; + priv->tx_stats[i].len = 0; + } + + priv->beacon_req_id = cpu_to_le32(0); + priv->tsf_high32 = priv->tsf_low32 = 0; + mutex_unlock(&priv->conf_mutex); +} + +static int p54_add_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct p54_common *priv = dev->priv; + + mutex_lock(&priv->conf_mutex); + if (priv->mode != NL80211_IFTYPE_MONITOR) { + mutex_unlock(&priv->conf_mutex); + return -EOPNOTSUPP; + } + + priv->vif = conf->vif; + + switch (conf->type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: + priv->mode = conf->type; + break; + default: + mutex_unlock(&priv->conf_mutex); + return -EOPNOTSUPP; + } + + memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); + p54_setup_mac(priv); + mutex_unlock(&priv->conf_mutex); + return 0; +} + +static void p54_remove_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct p54_common *priv = dev->priv; + + mutex_lock(&priv->conf_mutex); + priv->vif = NULL; + if (priv->beacon_req_id) { + p54_tx_cancel(priv, priv->beacon_req_id); + priv->beacon_req_id = cpu_to_le32(0); + } + priv->mode = NL80211_IFTYPE_MONITOR; + memset(priv->mac_addr, 0, ETH_ALEN); + memset(priv->bssid, 0, ETH_ALEN); + p54_setup_mac(priv); + mutex_unlock(&priv->conf_mutex); +} + +static int p54_config(struct ieee80211_hw *dev, u32 changed) +{ + int ret = 0; + struct p54_common *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; + + mutex_lock(&priv->conf_mutex); + if (changed & IEEE80211_CONF_CHANGE_POWER) + priv->output_power = conf->power_level << 2; + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + ret = p54_scan(priv, P54_SCAN_EXIT, 0); + if (ret) + goto out; + } + if (changed & IEEE80211_CONF_CHANGE_PS) { + ret = p54_set_ps(priv); + if (ret) + goto out; + } + +out: + mutex_unlock(&priv->conf_mutex); + return ret; +} + +static void p54_configure_filter(struct ieee80211_hw *dev, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_mc_list *mclist) +{ + struct p54_common *priv = dev->priv; + + *total_flags &= FIF_PROMISC_IN_BSS | + FIF_OTHER_BSS; + + priv->filter_flags = *total_flags; + + if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) + p54_setup_mac(priv); +} + +static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct p54_common *priv = dev->priv; + int ret; + + mutex_lock(&priv->conf_mutex); + if ((params) && !(queue > 4)) { + P54_SET_QUEUE(priv->qos_params[queue], params->aifs, + params->cw_min, params->cw_max, params->txop); + ret = p54_set_edcf(priv); + } else + ret = -EINVAL; + mutex_unlock(&priv->conf_mutex); + return ret; +} + +static void p54_work(struct work_struct *work) +{ + struct p54_common *priv = container_of(work, struct p54_common, + work.work); + + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return ; + + /* + * TODO: walk through tx_queue and do the following tasks + * 1. initiate bursts. + * 2. cancel stuck frames / reset the device if necessary. + */ + + p54_fetch_statistics(priv); +} + +static int p54_get_stats(struct ieee80211_hw *dev, + struct ieee80211_low_level_stats *stats) +{ + struct p54_common *priv = dev->priv; + + memcpy(stats, &priv->stats, sizeof(*stats)); + return 0; +} + +static int p54_get_tx_stats(struct ieee80211_hw *dev, + struct ieee80211_tx_queue_stats *stats) +{ + struct p54_common *priv = dev->priv; + + memcpy(stats, &priv->tx_stats[P54_QUEUE_DATA], + sizeof(stats[0]) * dev->queues); + return 0; +} + +static void p54_bss_info_changed(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + struct p54_common *priv = dev->priv; + + mutex_lock(&priv->conf_mutex); + if (changed & BSS_CHANGED_BSSID) { + memcpy(priv->bssid, info->bssid, ETH_ALEN); + p54_setup_mac(priv); + } + + if (changed & BSS_CHANGED_BEACON) { + p54_scan(priv, P54_SCAN_EXIT, 0); + p54_setup_mac(priv); + p54_beacon_update(priv, vif); + p54_set_edcf(priv); + } + + if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BEACON)) { + priv->use_short_slot = info->use_short_slot; + p54_set_edcf(priv); + } + if (changed & BSS_CHANGED_BASIC_RATES) { + if (dev->conf.channel->band == IEEE80211_BAND_5GHZ) + priv->basic_rate_mask = (info->basic_rates << 4); + else + priv->basic_rate_mask = info->basic_rates; + p54_setup_mac(priv); + if (priv->fw_var >= 0x500) + p54_scan(priv, P54_SCAN_EXIT, 0); + } + if (changed & BSS_CHANGED_ASSOC) { + if (info->assoc) { + priv->aid = info->aid; + priv->wakeup_timer = info->beacon_int * + info->dtim_period * 5; + p54_setup_mac(priv); + } + } + + mutex_unlock(&priv->conf_mutex); +} + +static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct p54_common *priv = dev->priv; + int slot, ret = 0; + u8 algo = 0; + u8 *addr = NULL; + + if (modparam_nohwcrypt) + return -EOPNOTSUPP; + + mutex_lock(&priv->conf_mutex); + if (cmd == SET_KEY) { + switch (key->alg) { + case ALG_TKIP: + if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL | + BR_DESC_PRIV_CAP_TKIP))) { + ret = -EOPNOTSUPP; + goto out_unlock; + } + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + algo = P54_CRYPTO_TKIPMICHAEL; + break; + case ALG_WEP: + if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) { + ret = -EOPNOTSUPP; + goto out_unlock; + } + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + algo = P54_CRYPTO_WEP; + break; + case ALG_CCMP: + if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) { + ret = -EOPNOTSUPP; + goto out_unlock; + } + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + algo = P54_CRYPTO_AESCCMP; + break; + default: + ret = -EOPNOTSUPP; + goto out_unlock; + } + slot = bitmap_find_free_region(priv->used_rxkeys, + priv->rx_keycache_size, 0); + + if (slot < 0) { + /* + * The device supports the choosen algorithm, but the + * firmware does not provide enough key slots to store + * all of them. + * But encryption offload for outgoing frames is always + * possible, so we just pretend that the upload was + * successful and do the decryption in software. + */ + + /* mark the key as invalid. */ + key->hw_key_idx = 0xff; + goto out_unlock; + } + } else { + slot = key->hw_key_idx; + + if (slot == 0xff) { + /* This key was not uploaded into the rx key cache. */ + + goto out_unlock; + } + + bitmap_release_region(priv->used_rxkeys, slot, 0); + algo = 0; + } + + if (sta) + addr = sta->addr; + + ret = p54_upload_key(priv, algo, slot, key->keyidx, + key->keylen, addr, key->key); + if (ret) { + bitmap_release_region(priv->used_rxkeys, slot, 0); + ret = -EOPNOTSUPP; + goto out_unlock; + } + + key->hw_key_idx = slot; + +out_unlock: + mutex_unlock(&priv->conf_mutex); + return ret; +} + +static const struct ieee80211_ops p54_ops = { + .tx = p54_tx_80211, + .start = p54_start, + .stop = p54_stop, + .add_interface = p54_add_interface, + .remove_interface = p54_remove_interface, + .set_tim = p54_set_tim, + .sta_notify = p54_sta_notify, + .set_key = p54_set_key, + .config = p54_config, + .bss_info_changed = p54_bss_info_changed, + .configure_filter = p54_configure_filter, + .conf_tx = p54_conf_tx, + .get_stats = p54_get_stats, + .get_tx_stats = p54_get_tx_stats +}; + +struct ieee80211_hw *p54_init_common(size_t priv_data_len) +{ + struct ieee80211_hw *dev; + struct p54_common *priv; + + dev = ieee80211_alloc_hw(priv_data_len, &p54_ops); + if (!dev) + return NULL; + + priv = dev->priv; + priv->hw = dev; + priv->mode = NL80211_IFTYPE_UNSPECIFIED; + priv->basic_rate_mask = 0x15f; + spin_lock_init(&priv->tx_stats_lock); + skb_queue_head_init(&priv->tx_queue); + skb_queue_head_init(&priv->tx_pending); + dev->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; + + dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT); + + dev->channel_change_time = 1000; /* TODO: find actual value */ + priv->tx_stats[P54_QUEUE_BEACON].limit = 1; + priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1; + priv->tx_stats[P54_QUEUE_MGMT].limit = 3; + priv->tx_stats[P54_QUEUE_CAB].limit = 3; + priv->tx_stats[P54_QUEUE_DATA].limit = 5; + dev->queues = 1; + priv->noise = -94; + /* + * We support at most 8 tries no matter which rate they're at, + * we cannot support max_rates * max_rate_tries as we set it + * here, but setting it correctly to 4/2 or so would limit us + * artificially if the RC algorithm wants just two rates, so + * let's say 4/7, we'll redistribute it at TX time, see the + * comments there. + */ + dev->max_rates = 4; + dev->max_rate_tries = 7; + dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 + + sizeof(struct p54_tx_data); + + mutex_init(&priv->conf_mutex); + mutex_init(&priv->eeprom_mutex); + init_completion(&priv->eeprom_comp); + INIT_DELAYED_WORK(&priv->work, p54_work); + + return dev; +} +EXPORT_SYMBOL_GPL(p54_init_common); + +int p54_register_common(struct ieee80211_hw *dev, struct device *pdev) +{ + struct p54_common *priv = dev->priv; + int err; + + err = ieee80211_register_hw(dev); + if (err) { + dev_err(pdev, "Cannot register device (%d).\n", err); + return err; + } + +#ifdef CONFIG_P54_LEDS + err = p54_init_leds(priv); + if (err) + return err; +#endif /* CONFIG_P54_LEDS */ + + dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy)); + return 0; +} +EXPORT_SYMBOL_GPL(p54_register_common); + +void p54_free_common(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + + kfree(priv->iq_autocal); + kfree(priv->output_limit); + kfree(priv->curve_data); + kfree(priv->used_rxkeys); + priv->iq_autocal = NULL; + priv->output_limit = NULL; + priv->curve_data = NULL; + priv->used_rxkeys = NULL; + ieee80211_free_hw(dev); +} +EXPORT_SYMBOL_GPL(p54_free_common); + +void p54_unregister_common(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + +#ifdef CONFIG_P54_LEDS + p54_unregister_leds(priv); +#endif /* CONFIG_P54_LEDS */ + + ieee80211_unregister_hw(dev); + mutex_destroy(&priv->conf_mutex); + mutex_destroy(&priv->eeprom_mutex); +} +EXPORT_SYMBOL_GPL(p54_unregister_common); -- cgit v1.2.3-18-g5258 From 0a5fb84f6b62bca8352f0aad045118e47340b096 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 23 Jun 2009 10:39:12 -0500 Subject: p54: Move TX/RX code Copy the TX/RX code from p54common.c into a new file txrx.c Signed-off-by: Christian Lamparter Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/p54/txrx.c | 825 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 825 insertions(+) create mode 100644 drivers/net/wireless/p54/txrx.c (limited to 'drivers') diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c new file mode 100644 index 00000000000..31fda17bec4 --- /dev/null +++ b/drivers/net/wireless/p54/txrx.c @@ -0,0 +1,825 @@ +/* + * Common code for mac80211 Prism54 drivers + * + * Copyright (c) 2006, Michael Wu + * Copyright (c) 2007-2009, Christian Lamparter + * Copyright 2008, Johannes Berg + * + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * - stlc45xx driver + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include + +#include "p54.h" +#include "lmac.h" + +#ifdef P54_MM_DEBUG +static void p54_dump_tx_queue(struct p54_common *priv) +{ + unsigned long flags; + struct ieee80211_tx_info *info; + struct p54_tx_info *range; + struct sk_buff *skb; + struct p54_hdr *hdr; + unsigned int i = 0; + u32 prev_addr; + u32 largest_hole = 0, free; + + spin_lock_irqsave(&priv->tx_queue.lock, flags); + printk(KERN_DEBUG "%s: / --- tx queue dump (%d entries) --- \n", + wiphy_name(priv->hw->wiphy), skb_queue_len(&priv->tx_queue)); + + prev_addr = priv->rx_start; + skb_queue_walk(&priv->tx_queue, skb) { + info = IEEE80211_SKB_CB(skb); + range = (void *) info->rate_driver_data; + hdr = (void *) skb->data; + + free = range->start_addr - prev_addr; + printk(KERN_DEBUG "%s: | [%02d] => [skb:%p skb_len:0x%04x " + "hdr:{flags:%02x len:%04x req_id:%04x type:%02x} " + "mem:{start:%04x end:%04x, free:%d}]\n", + wiphy_name(priv->hw->wiphy), i++, skb, skb->len, + le16_to_cpu(hdr->flags), le16_to_cpu(hdr->len), + le32_to_cpu(hdr->req_id), le16_to_cpu(hdr->type), + range->start_addr, range->end_addr, free); + + prev_addr = range->end_addr; + largest_hole = max(largest_hole, free); + } + free = priv->rx_end - prev_addr; + largest_hole = max(largest_hole, free); + printk(KERN_DEBUG "%s: \\ --- [free: %d], largest free block: %d ---\n", + wiphy_name(priv->hw->wiphy), free, largest_hole); + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); +} +#endif /* P54_MM_DEBUG */ + +/* + * So, the firmware is somewhat stupid and doesn't know what places in its + * memory incoming data should go to. By poking around in the firmware, we + * can find some unused memory to upload our packets to. However, data that we + * want the card to TX needs to stay intact until the card has told us that + * it is done with it. This function finds empty places we can upload to and + * marks allocated areas as reserved if necessary. p54_find_and_unlink_skb or + * p54_free_skb frees allocated areas. + */ +static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb) +{ + struct sk_buff *entry, *target_skb = NULL; + struct ieee80211_tx_info *info; + struct p54_tx_info *range; + struct p54_hdr *data = (void *) skb->data; + unsigned long flags; + u32 last_addr = priv->rx_start; + u32 target_addr = priv->rx_start; + u16 len = priv->headroom + skb->len + priv->tailroom + 3; + + if (unlikely(WARN_ON(!skb || !priv))) + return -EINVAL; + + info = IEEE80211_SKB_CB(skb); + range = (void *) info->rate_driver_data; + len = (range->extra_len + len) & ~0x3; + + spin_lock_irqsave(&priv->tx_queue.lock, flags); + if (unlikely(skb_queue_len(&priv->tx_queue) == 32)) { + /* + * The tx_queue is now really full. + * + * TODO: check if the device has crashed and reset it. + */ + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + return -EBUSY; + } + + skb_queue_walk(&priv->tx_queue, entry) { + u32 hole_size; + info = IEEE80211_SKB_CB(entry); + range = (void *) info->rate_driver_data; + hole_size = range->start_addr - last_addr; + + if (!entry->next) { + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + return -ENOSPC; + } + + if (!target_skb && hole_size >= len) { + target_skb = entry->prev; + hole_size -= len; + target_addr = last_addr; + break; + } + last_addr = range->end_addr; + } + if (unlikely(!target_skb)) { + if (priv->rx_end - last_addr >= len) { + target_skb = priv->tx_queue.prev; + if (!skb_queue_empty(&priv->tx_queue)) { + info = IEEE80211_SKB_CB(target_skb); + range = (void *)info->rate_driver_data; + target_addr = range->end_addr; + } + } else { + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + return -ENOSPC; + } + } + + info = IEEE80211_SKB_CB(skb); + range = (void *) info->rate_driver_data; + range->start_addr = target_addr; + range->end_addr = target_addr + len; + __skb_queue_after(&priv->tx_queue, target_skb, skb); + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + data->req_id = cpu_to_le32(target_addr + priv->headroom); + return 0; +} + +static void p54_tx_pending(struct p54_common *priv) +{ + struct sk_buff *skb; + int ret; + + if (unlikely(WARN_ON(!priv))) + return ; + + skb = skb_dequeue(&priv->tx_pending); + if (unlikely(!skb)) + return ; + + ret = p54_assign_address(priv, skb); + if (unlikely(ret)) + skb_queue_head(&priv->tx_pending, skb); + else + priv->tx(priv->hw, skb); +} + +static void p54_wake_queues(struct p54_common *priv) +{ + unsigned long flags; + unsigned int i; + + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return ; + + p54_tx_pending(priv); + + spin_lock_irqsave(&priv->tx_stats_lock, flags); + for (i = 0; i < priv->hw->queues; i++) { + if (priv->tx_stats[i + P54_QUEUE_DATA].len < + priv->tx_stats[i + P54_QUEUE_DATA].limit) + ieee80211_wake_queue(priv->hw, i); + } + spin_unlock_irqrestore(&priv->tx_stats_lock, flags); +} + +static int p54_tx_qos_accounting_alloc(struct p54_common *priv, + struct sk_buff *skb, + const u16 p54_queue) +{ + struct ieee80211_tx_queue_stats *queue; + unsigned long flags; + + if (WARN_ON(p54_queue > P54_QUEUE_NUM)) + return -EINVAL; + + queue = &priv->tx_stats[p54_queue]; + + spin_lock_irqsave(&priv->tx_stats_lock, flags); + if (unlikely(queue->len > queue->limit && IS_QOS_QUEUE(p54_queue))) { + spin_unlock_irqrestore(&priv->tx_stats_lock, flags); + return -ENOSPC; + } + + queue->len++; + queue->count++; + + if (unlikely(queue->len == queue->limit && IS_QOS_QUEUE(p54_queue))) { + u16 ac_queue = p54_queue - P54_QUEUE_DATA; + ieee80211_stop_queue(priv->hw, ac_queue); + } + + spin_unlock_irqrestore(&priv->tx_stats_lock, flags); + return 0; +} + +static void p54_tx_qos_accounting_free(struct p54_common *priv, + struct sk_buff *skb) +{ + if (skb && IS_DATA_FRAME(skb)) { + struct p54_hdr *hdr = (void *) skb->data; + struct p54_tx_data *data = (void *) hdr->data; + + priv->tx_stats[data->hw_queue].len--; + } + p54_wake_queues(priv); +} + +void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_common *priv = dev->priv; + if (unlikely(!skb)) + return ; + + skb_unlink(skb, &priv->tx_queue); + p54_tx_qos_accounting_free(priv, skb); + dev_kfree_skb_any(skb); +} +EXPORT_SYMBOL_GPL(p54_free_skb); + +static struct sk_buff *p54_find_and_unlink_skb(struct p54_common *priv, + const __le32 req_id) +{ + struct sk_buff *entry; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_queue.lock, flags); + skb_queue_walk(&priv->tx_queue, entry) { + struct p54_hdr *hdr = (struct p54_hdr *) entry->data; + + if (hdr->req_id == req_id) { + __skb_unlink(entry, &priv->tx_queue); + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + p54_tx_qos_accounting_free(priv, entry); + return entry; + } + } + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + return NULL; +} + +void p54_tx(struct p54_common *priv, struct sk_buff *skb) +{ + if (unlikely(WARN_ON(!priv))) + return ; + + skb_queue_tail(&priv->tx_pending, skb); + p54_tx_pending(priv); +} + +static int p54_rssi_to_dbm(struct p54_common *priv, int rssi) +{ + int band = priv->hw->conf.channel->band; + + if (priv->rxhw != 5) + return ((rssi * priv->rssical_db[band].mul) / 64 + + priv->rssical_db[band].add) / 4; + else + /* + * TODO: find the correct formula + */ + return ((rssi * priv->rssical_db[band].mul) / 64 + + priv->rssical_db[band].add) / 4; +} + +static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb) +{ + struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data; + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + u16 freq = le16_to_cpu(hdr->freq); + size_t header_len = sizeof(*hdr); + u32 tsf32; + u8 rate = hdr->rate & 0xf; + + /* + * If the device is in a unspecified state we have to + * ignore all data frames. Else we could end up with a + * nasty crash. + */ + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return 0; + + if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD))) + return 0; + + if (hdr->decrypt_status == P54_DECRYPT_OK) + rx_status->flag |= RX_FLAG_DECRYPTED; + if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) || + (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP)) + rx_status->flag |= RX_FLAG_MMIC_ERROR; + + rx_status->signal = p54_rssi_to_dbm(priv, hdr->rssi); + rx_status->noise = priv->noise; + if (hdr->rate & 0x10) + rx_status->flag |= RX_FLAG_SHORTPRE; + if (priv->hw->conf.channel->band == IEEE80211_BAND_5GHZ) + rx_status->rate_idx = (rate < 4) ? 0 : rate - 4; + else + rx_status->rate_idx = rate; + + rx_status->freq = freq; + rx_status->band = priv->hw->conf.channel->band; + rx_status->antenna = hdr->antenna; + + tsf32 = le32_to_cpu(hdr->tsf32); + if (tsf32 < priv->tsf_low32) + priv->tsf_high32++; + rx_status->mactime = ((u64)priv->tsf_high32) << 32 | tsf32; + priv->tsf_low32 = tsf32; + + rx_status->flag |= RX_FLAG_TSFT; + + if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) + header_len += hdr->align[0]; + + skb_pull(skb, header_len); + skb_trim(skb, le16_to_cpu(hdr->len)); + ieee80211_rx_irqsafe(priv->hw, skb); + + queue_delayed_work(priv->hw->workqueue, &priv->work, + msecs_to_jiffies(P54_STATISTICS_UPDATE)); + + return -1; +} + +static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb) +{ + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; + struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data; + struct ieee80211_tx_info *info; + struct p54_hdr *entry_hdr; + struct p54_tx_data *entry_data; + struct sk_buff *entry; + unsigned int pad = 0, frame_len; + int count, idx; + + entry = p54_find_and_unlink_skb(priv, hdr->req_id); + if (unlikely(!entry)) + return ; + + frame_len = entry->len; + info = IEEE80211_SKB_CB(entry); + entry_hdr = (struct p54_hdr *) entry->data; + entry_data = (struct p54_tx_data *) entry_hdr->data; + priv->stats.dot11ACKFailureCount += payload->tries - 1; + + /* + * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are + * generated by the driver. Therefore tx_status is bogus + * and we don't want to confuse the mac80211 stack. + */ + if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) { + if (entry_data->hw_queue == P54_QUEUE_BEACON && + hdr->req_id == priv->beacon_req_id) + priv->beacon_req_id = cpu_to_le32(0); + + dev_kfree_skb_any(entry); + return ; + } + + /* + * Clear manually, ieee80211_tx_info_clear_status would + * clear the counts too and we need them. + */ + memset(&info->status.ampdu_ack_len, 0, + sizeof(struct ieee80211_tx_info) - + offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, + status.ampdu_ack_len) != 23); + + if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) + pad = entry_data->align[0]; + + /* walk through the rates array and adjust the counts */ + count = payload->tries; + for (idx = 0; idx < 4; idx++) { + if (count >= info->status.rates[idx].count) { + count -= info->status.rates[idx].count; + } else if (count > 0) { + info->status.rates[idx].count = count; + count = 0; + } else { + info->status.rates[idx].idx = -1; + info->status.rates[idx].count = 0; + } + } + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (!payload->status)) + info->flags |= IEEE80211_TX_STAT_ACK; + if (payload->status & P54_TX_PSM_CANCELLED) + info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + info->status.ack_signal = p54_rssi_to_dbm(priv, + (int)payload->ack_rssi); + + /* Undo all changes to the frame. */ + switch (entry_data->key_type) { + case P54_CRYPTO_TKIPMICHAEL: { + u8 *iv = (u8 *)(entry_data->align + pad + + entry_data->crypt_offset); + + /* Restore the original TKIP IV. */ + iv[2] = iv[0]; + iv[0] = iv[1]; + iv[1] = (iv[0] | 0x20) & 0x7f; /* WEPSeed - 8.3.2.2 */ + + frame_len -= 12; /* remove TKIP_MMIC + TKIP_ICV */ + break; + } + case P54_CRYPTO_AESCCMP: + frame_len -= 8; /* remove CCMP_MIC */ + break; + case P54_CRYPTO_WEP: + frame_len -= 4; /* remove WEP_ICV */ + break; + } + + skb_trim(entry, frame_len); + skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); + ieee80211_tx_status_irqsafe(priv->hw, entry); +} + +static void p54_rx_eeprom_readback(struct p54_common *priv, + struct sk_buff *skb) +{ + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; + struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data; + struct sk_buff *tmp; + + if (!priv->eeprom) + return ; + + if (priv->fw_var >= 0x509) { + memcpy(priv->eeprom, eeprom->v2.data, + le16_to_cpu(eeprom->v2.len)); + } else { + memcpy(priv->eeprom, eeprom->v1.data, + le16_to_cpu(eeprom->v1.len)); + } + + priv->eeprom = NULL; + tmp = p54_find_and_unlink_skb(priv, hdr->req_id); + p54_tx_qos_accounting_free(priv, tmp); + dev_kfree_skb_any(tmp); + complete(&priv->eeprom_comp); +} + +static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb) +{ + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; + struct p54_statistics *stats = (struct p54_statistics *) hdr->data; + struct sk_buff *tmp; + u32 tsf32; + + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return ; + + tsf32 = le32_to_cpu(stats->tsf32); + if (tsf32 < priv->tsf_low32) + priv->tsf_high32++; + priv->tsf_low32 = tsf32; + + priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail); + priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success); + priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs); + + priv->noise = p54_rssi_to_dbm(priv, le32_to_cpu(stats->noise)); + + tmp = p54_find_and_unlink_skb(priv, hdr->req_id); + p54_tx_qos_accounting_free(priv, tmp); + dev_kfree_skb_any(tmp); +} + +static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb) +{ + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; + struct p54_trap *trap = (struct p54_trap *) hdr->data; + u16 event = le16_to_cpu(trap->event); + u16 freq = le16_to_cpu(trap->frequency); + + switch (event) { + case P54_TRAP_BEACON_TX: + break; + case P54_TRAP_RADAR: + printk(KERN_INFO "%s: radar (freq:%d MHz)\n", + wiphy_name(priv->hw->wiphy), freq); + break; + case P54_TRAP_NO_BEACON: + if (priv->vif) + ieee80211_beacon_loss(priv->vif); + break; + case P54_TRAP_SCAN: + break; + case P54_TRAP_TBTT: + break; + case P54_TRAP_TIMER: + break; + default: + printk(KERN_INFO "%s: received event:%x freq:%d\n", + wiphy_name(priv->hw->wiphy), event, freq); + break; + } +} + +static int p54_rx_control(struct p54_common *priv, struct sk_buff *skb) +{ + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; + + switch (le16_to_cpu(hdr->type)) { + case P54_CONTROL_TYPE_TXDONE: + p54_rx_frame_sent(priv, skb); + break; + case P54_CONTROL_TYPE_TRAP: + p54_rx_trap(priv, skb); + break; + case P54_CONTROL_TYPE_BBP: + break; + case P54_CONTROL_TYPE_STAT_READBACK: + p54_rx_stats(priv, skb); + break; + case P54_CONTROL_TYPE_EEPROM_READBACK: + p54_rx_eeprom_readback(priv, skb); + break; + default: + printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n", + wiphy_name(priv->hw->wiphy), le16_to_cpu(hdr->type)); + break; + } + return 0; +} + +/* returns zero if skb can be reused */ +int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_common *priv = dev->priv; + u16 type = le16_to_cpu(*((__le16 *)skb->data)); + + if (type & P54_HDR_FLAG_CONTROL) + return p54_rx_control(priv, skb); + else + return p54_rx_data(priv, skb); +} +EXPORT_SYMBOL_GPL(p54_rx); + +static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb, + struct ieee80211_tx_info *info, u8 *queue, + u32 *extra_len, u16 *flags, u16 *aid, + bool *burst_possible) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (ieee80211_is_data_qos(hdr->frame_control)) + *burst_possible = true; + else + *burst_possible = false; + + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) + *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR; + + if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) + *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; + + *queue = skb_get_queue_mapping(skb) + P54_QUEUE_DATA; + + switch (priv->mode) { + case NL80211_IFTYPE_MONITOR: + /* + * We have to set P54_HDR_FLAG_DATA_OUT_PROMISC for + * every frame in promiscuous/monitor mode. + * see STSW45x0C LMAC API - page 12. + */ + *aid = 0; + *flags |= P54_HDR_FLAG_DATA_OUT_PROMISC; + break; + case NL80211_IFTYPE_STATION: + *aid = 1; + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { + *aid = 0; + *queue = P54_QUEUE_CAB; + return; + } + + if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) { + if (ieee80211_is_probe_resp(hdr->frame_control)) { + *aid = 0; + *flags |= P54_HDR_FLAG_DATA_OUT_TIMESTAMP | + P54_HDR_FLAG_DATA_OUT_NOCANCEL; + return; + } else if (ieee80211_is_beacon(hdr->frame_control)) { + *aid = 0; + + if (info->flags & IEEE80211_TX_CTL_INJECTED) { + /* + * Injecting beacons on top of a AP is + * not a good idea... nevertheless, + * it should be doable. + */ + + return; + } + + *flags |= P54_HDR_FLAG_DATA_OUT_TIMESTAMP; + *queue = P54_QUEUE_BEACON; + *extra_len = IEEE80211_MAX_TIM_LEN; + return; + } + } + + if (info->control.sta) + *aid = info->control.sta->aid; + break; + } +} + +static u8 p54_convert_algo(enum ieee80211_key_alg alg) +{ + switch (alg) { + case ALG_WEP: + return P54_CRYPTO_WEP; + case ALG_TKIP: + return P54_CRYPTO_TKIPMICHAEL; + case ALG_CCMP: + return P54_CRYPTO_AESCCMP; + default: + return 0; + } +} + +int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_common *priv = dev->priv; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct p54_tx_info *p54info; + struct p54_hdr *hdr; + struct p54_tx_data *txhdr; + unsigned int padding, len, extra_len; + int i, j, ridx; + u16 hdr_flags = 0, aid = 0; + u8 rate, queue = 0, crypt_offset = 0; + u8 cts_rate = 0x20; + u8 rc_flags; + u8 calculated_tries[4]; + u8 nrates = 0, nremaining = 8; + bool burst_allowed = false; + + p54_tx_80211_header(priv, skb, info, &queue, &extra_len, + &hdr_flags, &aid, &burst_allowed); + + if (p54_tx_qos_accounting_alloc(priv, skb, queue)) { + if (!IS_QOS_QUEUE(queue)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } else { + return NETDEV_TX_BUSY; + } + } + + padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; + len = skb->len; + + if (info->control.hw_key) { + crypt_offset = ieee80211_get_hdrlen_from_skb(skb); + if (info->control.hw_key->alg == ALG_TKIP) { + u8 *iv = (u8 *)(skb->data + crypt_offset); + /* + * The firmware excepts that the IV has to have + * this special format + */ + iv[1] = iv[0]; + iv[0] = iv[2]; + iv[2] = 0; + } + } + + txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding); + hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); + + if (padding) + hdr_flags |= P54_HDR_FLAG_DATA_ALIGN; + hdr->type = cpu_to_le16(aid); + hdr->rts_tries = info->control.rates[0].count; + + /* + * we register the rates in perfect order, and + * RTS/CTS won't happen on 5 GHz + */ + cts_rate = info->control.rts_cts_rate_idx; + + memset(&txhdr->rateset, 0, sizeof(txhdr->rateset)); + + /* see how many rates got used */ + for (i = 0; i < dev->max_rates; i++) { + if (info->control.rates[i].idx < 0) + break; + nrates++; + } + + /* limit tries to 8/nrates per rate */ + for (i = 0; i < nrates; i++) { + /* + * The magic expression here is equivalent to 8/nrates for + * all values that matter, but avoids division and jumps. + * Note that nrates can only take the values 1 through 4. + */ + calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1, + info->control.rates[i].count); + nremaining -= calculated_tries[i]; + } + + /* if there are tries left, distribute from back to front */ + for (i = nrates - 1; nremaining > 0 && i >= 0; i--) { + int tmp = info->control.rates[i].count - calculated_tries[i]; + + if (tmp <= 0) + continue; + /* RC requested more tries at this rate */ + + tmp = min_t(int, tmp, nremaining); + calculated_tries[i] += tmp; + nremaining -= tmp; + } + + ridx = 0; + for (i = 0; i < nrates && ridx < 8; i++) { + /* we register the rates in perfect order */ + rate = info->control.rates[i].idx; + if (info->band == IEEE80211_BAND_5GHZ) + rate += 4; + + /* store the count we actually calculated for TX status */ + info->control.rates[i].count = calculated_tries[i]; + + rc_flags = info->control.rates[i].flags; + if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) { + rate |= 0x10; + cts_rate |= 0x10; + } + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { + burst_allowed = false; + rate |= 0x40; + } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { + rate |= 0x20; + burst_allowed = false; + } + for (j = 0; j < calculated_tries[i] && ridx < 8; j++) { + txhdr->rateset[ridx] = rate; + ridx++; + } + } + + if (burst_allowed) + hdr_flags |= P54_HDR_FLAG_DATA_OUT_BURST; + + /* TODO: enable bursting */ + hdr->flags = cpu_to_le16(hdr_flags); + hdr->tries = ridx; + txhdr->rts_rate_idx = 0; + if (info->control.hw_key) { + txhdr->key_type = p54_convert_algo(info->control.hw_key->alg); + txhdr->key_len = min((u8)16, info->control.hw_key->keylen); + memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len); + if (info->control.hw_key->alg == ALG_TKIP) { + /* reserve space for the MIC key */ + len += 8; + memcpy(skb_put(skb, 8), &(info->control.hw_key->key + [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8); + } + /* reserve some space for ICV */ + len += info->control.hw_key->icv_len; + memset(skb_put(skb, info->control.hw_key->icv_len), 0, + info->control.hw_key->icv_len); + } else { + txhdr->key_type = 0; + txhdr->key_len = 0; + } + txhdr->crypt_offset = crypt_offset; + txhdr->hw_queue = queue; + txhdr->backlog = priv->tx_stats[queue].len - 1; + memset(txhdr->durations, 0, sizeof(txhdr->durations)); + txhdr->tx_antenna = ((info->antenna_sel_tx == 0) ? + 2 : info->antenna_sel_tx - 1) & priv->tx_diversity_mask; + if (priv->rxhw == 5) { + txhdr->longbow.cts_rate = cts_rate; + txhdr->longbow.output_power = cpu_to_le16(priv->output_power); + } else { + txhdr->normal.output_power = priv->output_power; + txhdr->normal.cts_rate = cts_rate; + } + if (padding) + txhdr->align[0] = padding; + + hdr->len = cpu_to_le16(len); + /* modifies skb->cb and with it info, so must be last! */ + p54info = (void *) info->rate_driver_data; + p54info->extra_len = extra_len; + + p54_tx(priv, skb); + return NETDEV_TX_OK; +} -- cgit v1.2.3-18-g5258 From d8c9210757605c5191d2d9f4e09be5e59ceac824 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 23 Jun 2009 10:39:45 -0500 Subject: p54: Modify p54 files for new organization Modify the remaining p54 files to account for the new file organization. Signed-off-by: Christian Lamparter Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/p54/Makefile | 3 + drivers/net/wireless/p54/p54.h | 148 +- drivers/net/wireless/p54/p54common.c | 2687 ---------------------------------- drivers/net/wireless/p54/p54common.h | 644 -------- drivers/net/wireless/p54/p54pci.c | 9 +- drivers/net/wireless/p54/p54spi.c | 5 +- drivers/net/wireless/p54/p54usb.c | 6 +- 7 files changed, 102 insertions(+), 3400 deletions(-) delete mode 100644 drivers/net/wireless/p54/p54common.c delete mode 100644 drivers/net/wireless/p54/p54common.h (limited to 'drivers') diff --git a/drivers/net/wireless/p54/Makefile b/drivers/net/wireless/p54/Makefile index c2050dee629..b542e68f178 100644 --- a/drivers/net/wireless/p54/Makefile +++ b/drivers/net/wireless/p54/Makefile @@ -1,3 +1,6 @@ +p54common-objs := eeprom.o fwio.o txrx.o main.o +p54common-$(CONFIG_P54_LEDS) += led.o + obj-$(CONFIG_P54_COMMON) += p54common.o obj-$(CONFIG_P54_USB) += p54usb.o obj-$(CONFIG_P54_PCI) += p54pci.o diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index db3df947d8e..19d085c73d7 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -1,6 +1,3 @@ -#ifndef P54_H -#define P54_H - /* * Shared defines for all mac80211 Prism54 code * @@ -14,39 +11,78 @@ * published by the Free Software Foundation. */ +#ifndef P54_H +#define P54_H + #ifdef CONFIG_P54_LEDS #include #endif /* CONFIG_P54_LEDS */ -enum p54_control_frame_types { - P54_CONTROL_TYPE_SETUP = 0, - P54_CONTROL_TYPE_SCAN, - P54_CONTROL_TYPE_TRAP, - P54_CONTROL_TYPE_DCFINIT, - P54_CONTROL_TYPE_RX_KEYCACHE, - P54_CONTROL_TYPE_TIM, - P54_CONTROL_TYPE_PSM, - P54_CONTROL_TYPE_TXCANCEL, - P54_CONTROL_TYPE_TXDONE, - P54_CONTROL_TYPE_BURST, - P54_CONTROL_TYPE_STAT_READBACK, - P54_CONTROL_TYPE_BBP, - P54_CONTROL_TYPE_EEPROM_READBACK, - P54_CONTROL_TYPE_LED, - P54_CONTROL_TYPE_GPIO, - P54_CONTROL_TYPE_TIMER, - P54_CONTROL_TYPE_MODULATION, - P54_CONTROL_TYPE_SYNTH_CONFIG, - P54_CONTROL_TYPE_DETECTOR_VALUE, - P54_CONTROL_TYPE_XBOW_SYNTH_CFG, - P54_CONTROL_TYPE_CCE_QUIET, - P54_CONTROL_TYPE_PSM_STA_UNLOCK, - P54_CONTROL_TYPE_PCS, - P54_CONTROL_TYPE_BT_BALANCER = 28, - P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30, - P54_CONTROL_TYPE_ARPTABLE = 31, - P54_CONTROL_TYPE_BT_OPTIONS = 35 -}; +#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000 + +#define BR_CODE_MIN 0x80000000 +#define BR_CODE_COMPONENT_ID 0x80000001 +#define BR_CODE_COMPONENT_VERSION 0x80000002 +#define BR_CODE_DEPENDENT_IF 0x80000003 +#define BR_CODE_EXPOSED_IF 0x80000004 +#define BR_CODE_DESCR 0x80000101 +#define BR_CODE_MAX 0x8FFFFFFF +#define BR_CODE_END_OF_BRA 0xFF0000FF +#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF + +struct bootrec { + __le32 code; + __le32 len; + u32 data[10]; +} __packed; + +/* Interface role definitions */ +#define BR_INTERFACE_ROLE_SERVER 0x0000 +#define BR_INTERFACE_ROLE_CLIENT 0x8000 + +#define BR_DESC_PRIV_CAP_WEP BIT(0) +#define BR_DESC_PRIV_CAP_TKIP BIT(1) +#define BR_DESC_PRIV_CAP_MICHAEL BIT(2) +#define BR_DESC_PRIV_CAP_CCX_CP BIT(3) +#define BR_DESC_PRIV_CAP_CCX_MIC BIT(4) +#define BR_DESC_PRIV_CAP_AESCCMP BIT(5) + +struct bootrec_desc { + __le16 modes; + __le16 flags; + __le32 rx_start; + __le32 rx_end; + u8 headroom; + u8 tailroom; + u8 tx_queues; + u8 tx_depth; + u8 privacy_caps; + u8 rx_keycache_size; + u8 time_size; + u8 padding; + u8 rates[16]; + u8 padding2[4]; + __le16 rx_mtu; +} __packed; + +#define FW_FMAC 0x464d4143 +#define FW_LM86 0x4c4d3836 +#define FW_LM87 0x4c4d3837 +#define FW_LM20 0x4c4d3230 + +struct bootrec_comp_id { + __le32 fw_variant; +} __packed; + +struct bootrec_comp_ver { + char fw_version[24]; +} __packed; + +struct bootrec_end { + __le16 crc; + u8 padding[2]; + u8 md5[16]; +} __packed; /* provide 16 bytes for the transport back-end */ #define P54_TX_INFO_DATA_SIZE 16 @@ -55,34 +91,30 @@ enum p54_control_frame_types { struct p54_tx_info { u32 start_addr; u32 end_addr; - void *data[P54_TX_INFO_DATA_SIZE / sizeof(void *)]; + union { + void *data[P54_TX_INFO_DATA_SIZE / sizeof(void *)]; + struct { + u32 extra_len; + }; + }; }; #define P54_MAX_CTRL_FRAME_LEN 0x1000 -#define P54_HDR_FLAG_CONTROL BIT(15) -#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0)) - -struct p54_hdr { - __le16 flags; - __le16 len; - __le32 req_id; - __le16 type; /* enum p54_control_frame_types */ - u8 rts_tries; - u8 tries; - u8 data[0]; -} __attribute__ ((packed)); - -#define FREE_AFTER_TX(skb) \ - ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \ - flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET)) +#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, _txop) \ +do { \ + queue.aifs = cpu_to_le16(ai_fs); \ + queue.cwmin = cpu_to_le16(cw_min); \ + queue.cwmax = cpu_to_le16(cw_max); \ + queue.txop = cpu_to_le16(_txop); \ +} while (0) struct p54_edcf_queue_param { __le16 aifs; __le16 cwmin; __le16 cwmax; __le16 txop; -} __attribute__ ((packed)); +} __packed; struct p54_rssi_linear_approximation { s16 mul; @@ -101,13 +133,6 @@ struct p54_cal_database { #define EEPROM_READBACK_LEN 0x3fc -#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000 - -#define FW_FMAC 0x464d4143 -#define FW_LM86 0x4c4d3836 -#define FW_LM87 0x4c4d3837 -#define FW_LM20 0x4c4d3230 - enum fw_state { FW_STATE_OFF, FW_STATE_BOOTING, @@ -138,6 +163,7 @@ struct p54_common { void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb); int (*open)(struct ieee80211_hw *dev); void (*stop)(struct ieee80211_hw *dev); + struct sk_buff_head tx_pending; struct sk_buff_head tx_queue; struct mutex conf_mutex; @@ -156,6 +182,7 @@ struct p54_common { /* (e)DCF / QOS state */ bool use_short_slot; + spinlock_t tx_stats_lock; struct ieee80211_tx_queue_stats tx_stats[8]; struct p54_edcf_queue_param qos_params[8]; @@ -181,7 +208,7 @@ struct p54_common { u32 tsf_low32, tsf_high32; u32 basic_rate_mask; u16 aid; - struct sk_buff *cached_beacon; + __le32 beacon_req_id; /* cryptographic engine information */ u8 privacy_caps; @@ -202,15 +229,20 @@ struct p54_common { /* eeprom handling */ void *eeprom; struct completion eeprom_comp; + struct mutex eeprom_mutex; }; +/* interfaces for the drivers */ int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb); int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw); int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len); int p54_read_eeprom(struct ieee80211_hw *dev); + struct ieee80211_hw *p54_init_common(size_t priv_data_len); int p54_register_common(struct ieee80211_hw *dev, struct device *pdev); void p54_free_common(struct ieee80211_hw *dev); +void p54_unregister_common(struct ieee80211_hw *dev); + #endif /* P54_H */ diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c deleted file mode 100644 index d1ea609a690..00000000000 --- a/drivers/net/wireless/p54/p54common.c +++ /dev/null @@ -1,2687 +0,0 @@ -/* - * Common code for mac80211 Prism54 drivers - * - * Copyright (c) 2006, Michael Wu - * Copyright (c) 2007, Christian Lamparter - * Copyright 2008, Johannes Berg - * - * Based on: - * - the islsm (softmac prism54) driver, which is: - * Copyright 2004-2006 Jean-Baptiste Note , et al. - * - stlc45xx driver - * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include - -#include -#ifdef CONFIG_P54_LEDS -#include -#endif /* CONFIG_P54_LEDS */ - -#include "p54.h" -#include "p54common.h" - -static int modparam_nohwcrypt; -module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); -MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); -MODULE_AUTHOR("Michael Wu "); -MODULE_DESCRIPTION("Softmac Prism54 common code"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("prism54common"); - -static struct ieee80211_rate p54_bgrates[] = { - { .bitrate = 10, .hw_value = 0, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 60, .hw_value = 4, }, - { .bitrate = 90, .hw_value = 5, }, - { .bitrate = 120, .hw_value = 6, }, - { .bitrate = 180, .hw_value = 7, }, - { .bitrate = 240, .hw_value = 8, }, - { .bitrate = 360, .hw_value = 9, }, - { .bitrate = 480, .hw_value = 10, }, - { .bitrate = 540, .hw_value = 11, }, -}; - -static struct ieee80211_channel p54_bgchannels[] = { - { .center_freq = 2412, .hw_value = 1, }, - { .center_freq = 2417, .hw_value = 2, }, - { .center_freq = 2422, .hw_value = 3, }, - { .center_freq = 2427, .hw_value = 4, }, - { .center_freq = 2432, .hw_value = 5, }, - { .center_freq = 2437, .hw_value = 6, }, - { .center_freq = 2442, .hw_value = 7, }, - { .center_freq = 2447, .hw_value = 8, }, - { .center_freq = 2452, .hw_value = 9, }, - { .center_freq = 2457, .hw_value = 10, }, - { .center_freq = 2462, .hw_value = 11, }, - { .center_freq = 2467, .hw_value = 12, }, - { .center_freq = 2472, .hw_value = 13, }, - { .center_freq = 2484, .hw_value = 14, }, -}; - -static struct ieee80211_supported_band band_2GHz = { - .channels = p54_bgchannels, - .n_channels = ARRAY_SIZE(p54_bgchannels), - .bitrates = p54_bgrates, - .n_bitrates = ARRAY_SIZE(p54_bgrates), -}; - -static struct ieee80211_rate p54_arates[] = { - { .bitrate = 60, .hw_value = 4, }, - { .bitrate = 90, .hw_value = 5, }, - { .bitrate = 120, .hw_value = 6, }, - { .bitrate = 180, .hw_value = 7, }, - { .bitrate = 240, .hw_value = 8, }, - { .bitrate = 360, .hw_value = 9, }, - { .bitrate = 480, .hw_value = 10, }, - { .bitrate = 540, .hw_value = 11, }, -}; - -static struct ieee80211_channel p54_achannels[] = { - { .center_freq = 4920 }, - { .center_freq = 4940 }, - { .center_freq = 4960 }, - { .center_freq = 4980 }, - { .center_freq = 5040 }, - { .center_freq = 5060 }, - { .center_freq = 5080 }, - { .center_freq = 5170 }, - { .center_freq = 5180 }, - { .center_freq = 5190 }, - { .center_freq = 5200 }, - { .center_freq = 5210 }, - { .center_freq = 5220 }, - { .center_freq = 5230 }, - { .center_freq = 5240 }, - { .center_freq = 5260 }, - { .center_freq = 5280 }, - { .center_freq = 5300 }, - { .center_freq = 5320 }, - { .center_freq = 5500 }, - { .center_freq = 5520 }, - { .center_freq = 5540 }, - { .center_freq = 5560 }, - { .center_freq = 5580 }, - { .center_freq = 5600 }, - { .center_freq = 5620 }, - { .center_freq = 5640 }, - { .center_freq = 5660 }, - { .center_freq = 5680 }, - { .center_freq = 5700 }, - { .center_freq = 5745 }, - { .center_freq = 5765 }, - { .center_freq = 5785 }, - { .center_freq = 5805 }, - { .center_freq = 5825 }, -}; - -static struct ieee80211_supported_band band_5GHz = { - .channels = p54_achannels, - .n_channels = ARRAY_SIZE(p54_achannels), - .bitrates = p54_arates, - .n_bitrates = ARRAY_SIZE(p54_arates), -}; - -int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) -{ - struct p54_common *priv = dev->priv; - struct bootrec_exp_if *exp_if; - struct bootrec *bootrec; - u32 *data = (u32 *)fw->data; - u32 *end_data = (u32 *)fw->data + (fw->size >> 2); - u8 *fw_version = NULL; - size_t len; - int i; - int maxlen; - - if (priv->rx_start) - return 0; - - while (data < end_data && *data) - data++; - - while (data < end_data && !*data) - data++; - - bootrec = (struct bootrec *) data; - - while (bootrec->data <= end_data && - (bootrec->data + (len = le32_to_cpu(bootrec->len))) <= end_data) { - u32 code = le32_to_cpu(bootrec->code); - switch (code) { - case BR_CODE_COMPONENT_ID: - priv->fw_interface = be32_to_cpup((__be32 *) - bootrec->data); - switch (priv->fw_interface) { - case FW_LM86: - case FW_LM20: - case FW_LM87: { - char *iftype = (char *)bootrec->data; - printk(KERN_INFO "%s: p54 detected a LM%c%c " - "firmware\n", - wiphy_name(dev->wiphy), - iftype[2], iftype[3]); - break; - } - case FW_FMAC: - default: - printk(KERN_ERR "%s: unsupported firmware\n", - wiphy_name(dev->wiphy)); - return -ENODEV; - } - break; - case BR_CODE_COMPONENT_VERSION: - /* 24 bytes should be enough for all firmwares */ - if (strnlen((unsigned char*)bootrec->data, 24) < 24) - fw_version = (unsigned char*)bootrec->data; - break; - case BR_CODE_DESCR: { - struct bootrec_desc *desc = - (struct bootrec_desc *)bootrec->data; - priv->rx_start = le32_to_cpu(desc->rx_start); - /* FIXME add sanity checking */ - priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500; - priv->headroom = desc->headroom; - priv->tailroom = desc->tailroom; - priv->privacy_caps = desc->privacy_caps; - priv->rx_keycache_size = desc->rx_keycache_size; - if (le32_to_cpu(bootrec->len) == 11) - priv->rx_mtu = le16_to_cpu(desc->rx_mtu); - else - priv->rx_mtu = (size_t) - 0x620 - priv->tx_hdr_len; - maxlen = priv->tx_hdr_len + /* USB devices */ - sizeof(struct p54_rx_data) + - 4 + /* rx alignment */ - IEEE80211_MAX_FRAG_THRESHOLD; - if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) { - printk(KERN_INFO "p54: rx_mtu reduced from %d " - "to %d\n", priv->rx_mtu, - maxlen); - priv->rx_mtu = maxlen; - } - break; - } - case BR_CODE_EXPOSED_IF: - exp_if = (struct bootrec_exp_if *) bootrec->data; - for (i = 0; i < (len * sizeof(*exp_if) / 4); i++) - if (exp_if[i].if_id == cpu_to_le16(0x1a)) - priv->fw_var = le16_to_cpu(exp_if[i].variant); - break; - case BR_CODE_DEPENDENT_IF: - break; - case BR_CODE_END_OF_BRA: - case LEGACY_BR_CODE_END_OF_BRA: - end_data = NULL; - break; - default: - break; - } - bootrec = (struct bootrec *)&bootrec->data[len]; - } - - if (fw_version) - printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n", - wiphy_name(dev->wiphy), fw_version, - priv->fw_var >> 8, priv->fw_var & 0xff); - - if (priv->fw_var < 0x500) - printk(KERN_INFO "%s: you are using an obsolete firmware. " - "visit http://wireless.kernel.org/en/users/Drivers/p54 " - "and grab one for \"kernel >= 2.6.28\"!\n", - wiphy_name(dev->wiphy)); - - if (priv->fw_var >= 0x300) { - /* Firmware supports QoS, use it! */ - priv->tx_stats[P54_QUEUE_AC_VO].limit = 3; - priv->tx_stats[P54_QUEUE_AC_VI].limit = 4; - priv->tx_stats[P54_QUEUE_AC_BE].limit = 3; - priv->tx_stats[P54_QUEUE_AC_BK].limit = 2; - dev->queues = P54_QUEUE_AC_NUM; - } - - if (!modparam_nohwcrypt) { - printk(KERN_INFO "%s: cryptographic accelerator " - "WEP:%s, TKIP:%s, CCMP:%s\n", - wiphy_name(dev->wiphy), - (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" : - "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP | - BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no", - (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ? - "YES" : "no"); - - if (priv->rx_keycache_size) { - /* - * NOTE: - * - * The firmware provides at most 255 (0 - 254) slots - * for keys which are then used to offload decryption. - * As a result the 255 entry (aka 0xff) can be used - * safely by the driver to mark keys that didn't fit - * into the full cache. This trick saves us from - * keeping a extra list for uploaded keys. - */ - - priv->used_rxkeys = kzalloc(BITS_TO_LONGS( - priv->rx_keycache_size), GFP_KERNEL); - - if (!priv->used_rxkeys) - return -ENOMEM; - } - } - - return 0; -} -EXPORT_SYMBOL_GPL(p54_parse_firmware); - -static int p54_convert_rev0(struct ieee80211_hw *dev, - struct pda_pa_curve_data *curve_data) -{ - struct p54_common *priv = dev->priv; - struct p54_pa_curve_data_sample *dst; - struct pda_pa_curve_data_sample_rev0 *src; - size_t cd_len = sizeof(*curve_data) + - (curve_data->points_per_channel*sizeof(*dst) + 2) * - curve_data->channels; - unsigned int i, j; - void *source, *target; - - priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len, - GFP_KERNEL); - if (!priv->curve_data) - return -ENOMEM; - - priv->curve_data->entries = curve_data->channels; - priv->curve_data->entry_size = sizeof(__le16) + - sizeof(*dst) * curve_data->points_per_channel; - priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data); - priv->curve_data->len = cd_len; - memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data)); - source = curve_data->data; - target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data; - for (i = 0; i < curve_data->channels; i++) { - __le16 *freq = source; - source += sizeof(__le16); - *((__le16 *)target) = *freq; - target += sizeof(__le16); - for (j = 0; j < curve_data->points_per_channel; j++) { - dst = target; - src = source; - - dst->rf_power = src->rf_power; - dst->pa_detector = src->pa_detector; - dst->data_64qam = src->pcv; - /* "invent" the points for the other modulations */ -#define SUB(x,y) (u8)((x) - (y)) > (x) ? 0 : (x) - (y) - dst->data_16qam = SUB(src->pcv, 12); - dst->data_qpsk = SUB(dst->data_16qam, 12); - dst->data_bpsk = SUB(dst->data_qpsk, 12); - dst->data_barker = SUB(dst->data_bpsk, 14); -#undef SUB - target += sizeof(*dst); - source += sizeof(*src); - } - } - - return 0; -} - -static int p54_convert_rev1(struct ieee80211_hw *dev, - struct pda_pa_curve_data *curve_data) -{ - struct p54_common *priv = dev->priv; - struct p54_pa_curve_data_sample *dst; - struct pda_pa_curve_data_sample_rev1 *src; - size_t cd_len = sizeof(*curve_data) + - (curve_data->points_per_channel*sizeof(*dst) + 2) * - curve_data->channels; - unsigned int i, j; - void *source, *target; - - priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data), - GFP_KERNEL); - if (!priv->curve_data) - return -ENOMEM; - - priv->curve_data->entries = curve_data->channels; - priv->curve_data->entry_size = sizeof(__le16) + - sizeof(*dst) * curve_data->points_per_channel; - priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data); - priv->curve_data->len = cd_len; - memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data)); - source = curve_data->data; - target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data; - for (i = 0; i < curve_data->channels; i++) { - __le16 *freq = source; - source += sizeof(__le16); - *((__le16 *)target) = *freq; - target += sizeof(__le16); - for (j = 0; j < curve_data->points_per_channel; j++) { - memcpy(target, source, sizeof(*src)); - - target += sizeof(*dst); - source += sizeof(*src); - } - source++; - } - - return 0; -} - -static const char *p54_rf_chips[] = { "NULL", "Duette3", "Duette2", - "Frisbee", "Xbow", "Longbow", "NULL", "NULL" }; -static int p54_init_xbow_synth(struct ieee80211_hw *dev); - -static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len, - u16 type) -{ - struct p54_common *priv = dev->priv; - int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0; - int entry_size = sizeof(struct pda_rssi_cal_entry) + offset; - int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2; - int i; - - if (len != (entry_size * num_entries)) { - printk(KERN_ERR "%s: unknown rssi calibration data packing " - " type:(%x) len:%d.\n", - wiphy_name(dev->wiphy), type, len); - - print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE, - data, len); - - printk(KERN_ERR "%s: please report this issue.\n", - wiphy_name(dev->wiphy)); - return; - } - - for (i = 0; i < num_entries; i++) { - struct pda_rssi_cal_entry *cal = data + - (offset + i * entry_size); - priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul); - priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add); - } -} - -static void p54_parse_default_country(struct ieee80211_hw *dev, - void *data, int len) -{ - struct pda_country *country; - - if (len != sizeof(*country)) { - printk(KERN_ERR "%s: found possible invalid default country " - "eeprom entry. (entry size: %d)\n", - wiphy_name(dev->wiphy), len); - - print_hex_dump_bytes("country:", DUMP_PREFIX_NONE, - data, len); - - printk(KERN_ERR "%s: please report this issue.\n", - wiphy_name(dev->wiphy)); - return; - } - - country = (struct pda_country *) data; - if (country->flags == PDR_COUNTRY_CERT_CODE_PSEUDO) - regulatory_hint(dev->wiphy, country->alpha2); - else { - /* TODO: - * write a shared/common function that converts - * "Regulatory domain codes" (802.11-2007 14.8.2.2) - * into ISO/IEC 3166-1 alpha2 for regulatory_hint. - */ - } -} - -static int p54_convert_output_limits(struct ieee80211_hw *dev, - u8 *data, size_t len) -{ - struct p54_common *priv = dev->priv; - - if (len < 2) - return -EINVAL; - - if (data[0] != 0) { - printk(KERN_ERR "%s: unknown output power db revision:%x\n", - wiphy_name(dev->wiphy), data[0]); - return -EINVAL; - } - - if (2 + data[1] * sizeof(struct pda_channel_output_limit) > len) - return -EINVAL; - - priv->output_limit = kmalloc(data[1] * - sizeof(struct pda_channel_output_limit) + - sizeof(*priv->output_limit), GFP_KERNEL); - - if (!priv->output_limit) - return -ENOMEM; - - priv->output_limit->offset = 0; - priv->output_limit->entries = data[1]; - priv->output_limit->entry_size = - sizeof(struct pda_channel_output_limit); - priv->output_limit->len = priv->output_limit->entry_size * - priv->output_limit->entries + - priv->output_limit->offset; - - memcpy(priv->output_limit->data, &data[2], - data[1] * sizeof(struct pda_channel_output_limit)); - - return 0; -} - -static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src, - size_t total_len) -{ - struct p54_cal_database *dst; - size_t payload_len, entries, entry_size, offset; - - payload_len = le16_to_cpu(src->len); - entries = le16_to_cpu(src->entries); - entry_size = le16_to_cpu(src->entry_size); - offset = le16_to_cpu(src->offset); - if (((entries * entry_size + offset) != payload_len) || - (payload_len + sizeof(*src) != total_len)) - return NULL; - - dst = kmalloc(sizeof(*dst) + payload_len, GFP_KERNEL); - if (!dst) - return NULL; - - dst->entries = entries; - dst->entry_size = entry_size; - dst->offset = offset; - dst->len = payload_len; - - memcpy(dst->data, src->data, payload_len); - return dst; -} - -int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) -{ - struct p54_common *priv = dev->priv; - struct eeprom_pda_wrap *wrap = NULL; - struct pda_entry *entry; - unsigned int data_len, entry_len; - void *tmp; - int err; - u8 *end = (u8 *)eeprom + len; - u16 synth = 0; - - wrap = (struct eeprom_pda_wrap *) eeprom; - entry = (void *)wrap->data + le16_to_cpu(wrap->len); - - /* verify that at least the entry length/code fits */ - while ((u8 *)entry <= end - sizeof(*entry)) { - entry_len = le16_to_cpu(entry->len); - data_len = ((entry_len - 1) << 1); - - /* abort if entry exceeds whole structure */ - if ((u8 *)entry + sizeof(*entry) + data_len > end) - break; - - switch (le16_to_cpu(entry->code)) { - case PDR_MAC_ADDRESS: - if (data_len != ETH_ALEN) - break; - SET_IEEE80211_PERM_ADDR(dev, entry->data); - break; - case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS: - if (priv->output_limit) - break; - err = p54_convert_output_limits(dev, entry->data, - data_len); - if (err) - goto err; - break; - case PDR_PRISM_PA_CAL_CURVE_DATA: { - struct pda_pa_curve_data *curve_data = - (struct pda_pa_curve_data *)entry->data; - if (data_len < sizeof(*curve_data)) { - err = -EINVAL; - goto err; - } - - switch (curve_data->cal_method_rev) { - case 0: - err = p54_convert_rev0(dev, curve_data); - break; - case 1: - err = p54_convert_rev1(dev, curve_data); - break; - default: - printk(KERN_ERR "%s: unknown curve data " - "revision %d\n", - wiphy_name(dev->wiphy), - curve_data->cal_method_rev); - err = -ENODEV; - break; - } - if (err) - goto err; - } - break; - case PDR_PRISM_ZIF_TX_IQ_CALIBRATION: - priv->iq_autocal = kmalloc(data_len, GFP_KERNEL); - if (!priv->iq_autocal) { - err = -ENOMEM; - goto err; - } - - memcpy(priv->iq_autocal, entry->data, data_len); - priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry); - break; - case PDR_DEFAULT_COUNTRY: - p54_parse_default_country(dev, entry->data, data_len); - break; - case PDR_INTERFACE_LIST: - tmp = entry->data; - while ((u8 *)tmp < entry->data + data_len) { - struct bootrec_exp_if *exp_if = tmp; - if (le16_to_cpu(exp_if->if_id) == 0xf) - synth = le16_to_cpu(exp_if->variant); - tmp += sizeof(struct bootrec_exp_if); - } - break; - case PDR_HARDWARE_PLATFORM_COMPONENT_ID: - if (data_len < 2) - break; - priv->version = *(u8 *)(entry->data + 1); - break; - case PDR_RSSI_LINEAR_APPROXIMATION: - case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND: - case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED: - p54_parse_rssical(dev, entry->data, data_len, - le16_to_cpu(entry->code)); - break; - case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM: { - __le16 *src = (void *) entry->data; - s16 *dst = (void *) &priv->rssical_db; - int i; - - if (data_len != sizeof(priv->rssical_db)) { - err = -EINVAL; - goto err; - } - for (i = 0; i < sizeof(priv->rssical_db) / - sizeof(*src); i++) - *(dst++) = (s16) le16_to_cpu(*(src++)); - } - break; - case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: { - struct pda_custom_wrapper *pda = (void *) entry->data; - if (priv->output_limit || data_len < sizeof(*pda)) - break; - priv->output_limit = p54_convert_db(pda, data_len); - } - break; - case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: { - struct pda_custom_wrapper *pda = (void *) entry->data; - if (priv->curve_data || data_len < sizeof(*pda)) - break; - priv->curve_data = p54_convert_db(pda, data_len); - } - break; - case PDR_END: - /* make it overrun */ - entry_len = len; - break; - case PDR_MANUFACTURING_PART_NUMBER: - case PDR_PDA_VERSION: - case PDR_NIC_SERIAL_NUMBER: - case PDR_REGULATORY_DOMAIN_LIST: - case PDR_TEMPERATURE_TYPE: - case PDR_PRISM_PCI_IDENTIFIER: - case PDR_COUNTRY_INFORMATION: - case PDR_OEM_NAME: - case PDR_PRODUCT_NAME: - case PDR_UTF8_OEM_NAME: - case PDR_UTF8_PRODUCT_NAME: - case PDR_COUNTRY_LIST: - case PDR_ANTENNA_GAIN: - case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA: - case PDR_REGULATORY_POWER_LIMITS: - case PDR_RADIATED_TRANSMISSION_CORRECTION: - case PDR_PRISM_TX_IQ_CALIBRATION: - case PDR_BASEBAND_REGISTERS: - case PDR_PER_CHANNEL_BASEBAND_REGISTERS: - break; - default: - printk(KERN_INFO "%s: unknown eeprom code : 0x%x\n", - wiphy_name(dev->wiphy), - le16_to_cpu(entry->code)); - break; - } - - entry = (void *)entry + (entry_len + 1)*2; - } - - if (!synth || !priv->iq_autocal || !priv->output_limit || - !priv->curve_data) { - printk(KERN_ERR "%s: not all required entries found in eeprom!\n", - wiphy_name(dev->wiphy)); - err = -EINVAL; - goto err; - } - - priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK; - if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW) - p54_init_xbow_synth(dev); - if (!(synth & PDR_SYNTH_24_GHZ_DISABLED)) - dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; - if (!(synth & PDR_SYNTH_5_GHZ_DISABLED)) - dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz; - if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED) - priv->rx_diversity_mask = 3; - if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED) - priv->tx_diversity_mask = 3; - - if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { - u8 perm_addr[ETH_ALEN]; - - printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n", - wiphy_name(dev->wiphy)); - random_ether_addr(perm_addr); - SET_IEEE80211_PERM_ADDR(dev, perm_addr); - } - - printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n", - wiphy_name(dev->wiphy), - dev->wiphy->perm_addr, - priv->version, p54_rf_chips[priv->rxhw]); - - return 0; - - err: - if (priv->iq_autocal) { - kfree(priv->iq_autocal); - priv->iq_autocal = NULL; - } - - if (priv->output_limit) { - kfree(priv->output_limit); - priv->output_limit = NULL; - } - - if (priv->curve_data) { - kfree(priv->curve_data); - priv->curve_data = NULL; - } - - printk(KERN_ERR "%s: eeprom parse failed!\n", - wiphy_name(dev->wiphy)); - return err; -} -EXPORT_SYMBOL_GPL(p54_parse_eeprom); - -static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi) -{ - struct p54_common *priv = dev->priv; - int band = dev->conf.channel->band; - - if (priv->rxhw != PDR_SYNTH_FRONTEND_LONGBOW) - return ((rssi * priv->rssical_db[band].mul) / 64 + - priv->rssical_db[band].add) / 4; - else - /* - * TODO: find the correct formula - */ - return ((rssi * priv->rssical_db[band].mul) / 64 + - priv->rssical_db[band].add) / 4; -} - -static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - struct p54_common *priv = dev->priv; - struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data; - struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); - u16 freq = le16_to_cpu(hdr->freq); - size_t header_len = sizeof(*hdr); - u32 tsf32; - u8 rate = hdr->rate & 0xf; - - /* - * If the device is in a unspecified state we have to - * ignore all data frames. Else we could end up with a - * nasty crash. - */ - if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) - return 0; - - if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD))) { - return 0; - } - - if (hdr->decrypt_status == P54_DECRYPT_OK) - rx_status->flag |= RX_FLAG_DECRYPTED; - if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) || - (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP)) - rx_status->flag |= RX_FLAG_MMIC_ERROR; - - rx_status->signal = p54_rssi_to_dbm(dev, hdr->rssi); - rx_status->noise = priv->noise; - if (hdr->rate & 0x10) - rx_status->flag |= RX_FLAG_SHORTPRE; - if (dev->conf.channel->band == IEEE80211_BAND_5GHZ) - rx_status->rate_idx = (rate < 4) ? 0 : rate - 4; - else - rx_status->rate_idx = rate; - - rx_status->freq = freq; - rx_status->band = dev->conf.channel->band; - rx_status->antenna = hdr->antenna; - - tsf32 = le32_to_cpu(hdr->tsf32); - if (tsf32 < priv->tsf_low32) - priv->tsf_high32++; - rx_status->mactime = ((u64)priv->tsf_high32) << 32 | tsf32; - priv->tsf_low32 = tsf32; - - rx_status->flag |= RX_FLAG_TSFT; - - if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) - header_len += hdr->align[0]; - - skb_pull(skb, header_len); - skb_trim(skb, le16_to_cpu(hdr->len)); - ieee80211_rx_irqsafe(dev, skb); - - queue_delayed_work(dev->workqueue, &priv->work, - msecs_to_jiffies(P54_STATISTICS_UPDATE)); - - return -1; -} - -static void inline p54_wake_free_queues(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - int i; - - if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) - return ; - - for (i = 0; i < dev->queues; i++) - if (priv->tx_stats[i + P54_QUEUE_DATA].len < - priv->tx_stats[i + P54_QUEUE_DATA].limit) - ieee80211_wake_queue(dev, i); -} - -void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - struct p54_common *priv = dev->priv; - struct ieee80211_tx_info *info; - struct p54_tx_info *range; - unsigned long flags; - - if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue))) - return; - - /* - * don't try to free an already unlinked skb - */ - if (unlikely((!skb->next) || (!skb->prev))) - return; - - spin_lock_irqsave(&priv->tx_queue.lock, flags); - info = IEEE80211_SKB_CB(skb); - range = (void *)info->rate_driver_data; - if (skb->prev != (struct sk_buff *)&priv->tx_queue) { - struct ieee80211_tx_info *ni; - struct p54_tx_info *mr; - - ni = IEEE80211_SKB_CB(skb->prev); - mr = (struct p54_tx_info *)ni->rate_driver_data; - } - if (skb->next != (struct sk_buff *)&priv->tx_queue) { - struct ieee80211_tx_info *ni; - struct p54_tx_info *mr; - - ni = IEEE80211_SKB_CB(skb->next); - mr = (struct p54_tx_info *)ni->rate_driver_data; - } - __skb_unlink(skb, &priv->tx_queue); - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - dev_kfree_skb_any(skb); - p54_wake_free_queues(dev); -} -EXPORT_SYMBOL_GPL(p54_free_skb); - -static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev, - __le32 req_id) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *entry; - unsigned long flags; - - spin_lock_irqsave(&priv->tx_queue.lock, flags); - entry = priv->tx_queue.next; - while (entry != (struct sk_buff *)&priv->tx_queue) { - struct p54_hdr *hdr = (struct p54_hdr *) entry->data; - - if (hdr->req_id == req_id) { - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - return entry; - } - entry = entry->next; - } - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - return NULL; -} - -static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - struct p54_common *priv = dev->priv; - struct p54_hdr *hdr = (struct p54_hdr *) skb->data; - struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data; - struct sk_buff *entry; - u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom; - struct p54_tx_info *range = NULL; - unsigned long flags; - int count, idx; - - spin_lock_irqsave(&priv->tx_queue.lock, flags); - entry = (struct sk_buff *) priv->tx_queue.next; - while (entry != (struct sk_buff *)&priv->tx_queue) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); - struct p54_hdr *entry_hdr; - struct p54_tx_data *entry_data; - unsigned int pad = 0, frame_len; - - range = (void *)info->rate_driver_data; - if (range->start_addr != addr) { - entry = entry->next; - continue; - } - - if (entry->next != (struct sk_buff *)&priv->tx_queue) { - struct ieee80211_tx_info *ni; - struct p54_tx_info *mr; - - ni = IEEE80211_SKB_CB(entry->next); - mr = (struct p54_tx_info *)ni->rate_driver_data; - } - - __skb_unlink(entry, &priv->tx_queue); - - frame_len = entry->len; - entry_hdr = (struct p54_hdr *) entry->data; - entry_data = (struct p54_tx_data *) entry_hdr->data; - if (priv->tx_stats[entry_data->hw_queue].len) - priv->tx_stats[entry_data->hw_queue].len--; - priv->stats.dot11ACKFailureCount += payload->tries - 1; - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - - /* - * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are - * generated by the driver. Therefore tx_status is bogus - * and we don't want to confuse the mac80211 stack. - */ - if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) { - if (entry_data->hw_queue == P54_QUEUE_BEACON) - priv->cached_beacon = NULL; - - kfree_skb(entry); - goto out; - } - - /* - * Clear manually, ieee80211_tx_info_clear_status would - * clear the counts too and we need them. - */ - memset(&info->status.ampdu_ack_len, 0, - sizeof(struct ieee80211_tx_info) - - offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); - BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, - status.ampdu_ack_len) != 23); - - if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) - pad = entry_data->align[0]; - - /* walk through the rates array and adjust the counts */ - count = payload->tries; - for (idx = 0; idx < 4; idx++) { - if (count >= info->status.rates[idx].count) { - count -= info->status.rates[idx].count; - } else if (count > 0) { - info->status.rates[idx].count = count; - count = 0; - } else { - info->status.rates[idx].idx = -1; - info->status.rates[idx].count = 0; - } - } - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && - (!payload->status)) - info->flags |= IEEE80211_TX_STAT_ACK; - if (payload->status & P54_TX_PSM_CANCELLED) - info->flags |= IEEE80211_TX_STAT_TX_FILTERED; - info->status.ack_signal = p54_rssi_to_dbm(dev, - (int)payload->ack_rssi); - - /* Undo all changes to the frame. */ - switch (entry_data->key_type) { - case P54_CRYPTO_TKIPMICHAEL: { - u8 *iv = (u8 *)(entry_data->align + pad + - entry_data->crypt_offset); - - /* Restore the original TKIP IV. */ - iv[2] = iv[0]; - iv[0] = iv[1]; - iv[1] = (iv[0] | 0x20) & 0x7f; /* WEPSeed - 8.3.2.2 */ - - frame_len -= 12; /* remove TKIP_MMIC + TKIP_ICV */ - break; - } - case P54_CRYPTO_AESCCMP: - frame_len -= 8; /* remove CCMP_MIC */ - break; - case P54_CRYPTO_WEP: - frame_len -= 4; /* remove WEP_ICV */ - break; - } - skb_trim(entry, frame_len); - skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); - ieee80211_tx_status_irqsafe(dev, entry); - goto out; - } - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - -out: - p54_wake_free_queues(dev); -} - -static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, - struct sk_buff *skb) -{ - struct p54_hdr *hdr = (struct p54_hdr *) skb->data; - struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data; - struct p54_common *priv = dev->priv; - - if (!priv->eeprom) - return ; - - if (priv->fw_var >= 0x509) { - memcpy(priv->eeprom, eeprom->v2.data, - le16_to_cpu(eeprom->v2.len)); - } else { - memcpy(priv->eeprom, eeprom->v1.data, - le16_to_cpu(eeprom->v1.len)); - } - - complete(&priv->eeprom_comp); -} - -static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - struct p54_common *priv = dev->priv; - struct p54_hdr *hdr = (struct p54_hdr *) skb->data; - struct p54_statistics *stats = (struct p54_statistics *) hdr->data; - u32 tsf32; - - if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) - return ; - - tsf32 = le32_to_cpu(stats->tsf32); - if (tsf32 < priv->tsf_low32) - priv->tsf_high32++; - priv->tsf_low32 = tsf32; - - priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail); - priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success); - priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs); - - priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise)); - - p54_free_skb(dev, p54_find_tx_entry(dev, hdr->req_id)); -} - -static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - struct p54_common *priv = dev->priv; - struct p54_hdr *hdr = (struct p54_hdr *) skb->data; - struct p54_trap *trap = (struct p54_trap *) hdr->data; - u16 event = le16_to_cpu(trap->event); - u16 freq = le16_to_cpu(trap->frequency); - - switch (event) { - case P54_TRAP_BEACON_TX: - break; - case P54_TRAP_RADAR: - printk(KERN_INFO "%s: radar (freq:%d MHz)\n", - wiphy_name(dev->wiphy), freq); - break; - case P54_TRAP_NO_BEACON: - if (priv->vif) - ieee80211_beacon_loss(priv->vif); - break; - case P54_TRAP_SCAN: - break; - case P54_TRAP_TBTT: - break; - case P54_TRAP_TIMER: - break; - default: - printk(KERN_INFO "%s: received event:%x freq:%d\n", - wiphy_name(dev->wiphy), event, freq); - break; - } -} - -static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - struct p54_hdr *hdr = (struct p54_hdr *) skb->data; - - switch (le16_to_cpu(hdr->type)) { - case P54_CONTROL_TYPE_TXDONE: - p54_rx_frame_sent(dev, skb); - break; - case P54_CONTROL_TYPE_TRAP: - p54_rx_trap(dev, skb); - break; - case P54_CONTROL_TYPE_BBP: - break; - case P54_CONTROL_TYPE_STAT_READBACK: - p54_rx_stats(dev, skb); - break; - case P54_CONTROL_TYPE_EEPROM_READBACK: - p54_rx_eeprom_readback(dev, skb); - break; - default: - printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n", - wiphy_name(dev->wiphy), le16_to_cpu(hdr->type)); - break; - } - - return 0; -} - -/* returns zero if skb can be reused */ -int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - u16 type = le16_to_cpu(*((__le16 *)skb->data)); - - if (type & P54_HDR_FLAG_CONTROL) - return p54_rx_control(dev, skb); - else - return p54_rx_data(dev, skb); -} -EXPORT_SYMBOL_GPL(p54_rx); - -/* - * So, the firmware is somewhat stupid and doesn't know what places in its - * memory incoming data should go to. By poking around in the firmware, we - * can find some unused memory to upload our packets to. However, data that we - * want the card to TX needs to stay intact until the card has told us that - * it is done with it. This function finds empty places we can upload to and - * marks allocated areas as reserved if necessary. p54_rx_frame_sent or - * p54_free_skb frees allocated areas. - */ -static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, - struct p54_hdr *data, u32 len) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *entry; - struct sk_buff *target_skb = NULL; - struct ieee80211_tx_info *info; - struct p54_tx_info *range; - u32 last_addr = priv->rx_start; - u32 largest_hole = 0; - u32 target_addr = priv->rx_start; - unsigned long flags; - unsigned int left; - len = (len + priv->headroom + priv->tailroom + 3) & ~0x3; - - if (!skb) - return -EINVAL; - - spin_lock_irqsave(&priv->tx_queue.lock, flags); - - left = skb_queue_len(&priv->tx_queue); - if (unlikely(left >= 28)) { - /* - * The tx_queue is nearly full! - * We have throttle normal data traffic, because we must - * have a few spare slots for control frames left. - */ - ieee80211_stop_queues(dev); - queue_delayed_work(dev->workqueue, &priv->work, - msecs_to_jiffies(P54_TX_TIMEOUT)); - - if (unlikely(left == 32)) { - /* - * The tx_queue is now really full. - * - * TODO: check if the device has crashed and reset it. - */ - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - return -ENOSPC; - } - } - - entry = priv->tx_queue.next; - while (left--) { - u32 hole_size; - info = IEEE80211_SKB_CB(entry); - range = (void *)info->rate_driver_data; - hole_size = range->start_addr - last_addr; - if (!target_skb && hole_size >= len) { - target_skb = entry->prev; - hole_size -= len; - target_addr = last_addr; - } - largest_hole = max(largest_hole, hole_size); - last_addr = range->end_addr; - entry = entry->next; - } - if (!target_skb && priv->rx_end - last_addr >= len) { - target_skb = priv->tx_queue.prev; - largest_hole = max(largest_hole, priv->rx_end - last_addr - len); - if (!skb_queue_empty(&priv->tx_queue)) { - info = IEEE80211_SKB_CB(target_skb); - range = (void *)info->rate_driver_data; - target_addr = range->end_addr; - } - } else - largest_hole = max(largest_hole, priv->rx_end - last_addr); - - if (!target_skb) { - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - ieee80211_stop_queues(dev); - return -ENOSPC; - } - - info = IEEE80211_SKB_CB(skb); - range = (void *)info->rate_driver_data; - range->start_addr = target_addr; - range->end_addr = target_addr + len; - __skb_queue_after(&priv->tx_queue, target_skb, skb); - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - - if (largest_hole < priv->headroom + sizeof(struct p54_hdr) + - 48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) - ieee80211_stop_queues(dev); - - data->req_id = cpu_to_le32(target_addr + priv->headroom); - return 0; -} - -static struct sk_buff *p54_alloc_skb(struct ieee80211_hw *dev, u16 hdr_flags, - u16 payload_len, u16 type, gfp_t memflags) -{ - struct p54_common *priv = dev->priv; - struct p54_hdr *hdr; - struct sk_buff *skb; - size_t frame_len = sizeof(*hdr) + payload_len; - - if (frame_len > P54_MAX_CTRL_FRAME_LEN) - return NULL; - - skb = __dev_alloc_skb(priv->tx_hdr_len + frame_len, memflags); - if (!skb) - return NULL; - skb_reserve(skb, priv->tx_hdr_len); - - hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr)); - hdr->flags = cpu_to_le16(hdr_flags); - hdr->len = cpu_to_le16(payload_len); - hdr->type = cpu_to_le16(type); - hdr->tries = hdr->rts_tries = 0; - - if (p54_assign_address(dev, skb, hdr, frame_len)) { - kfree_skb(skb); - return NULL; - } - return skb; -} - -int p54_read_eeprom(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - struct p54_eeprom_lm86 *eeprom_hdr; - struct sk_buff *skb; - size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize; - int ret = -ENOMEM; - void *eeprom = NULL; - - maxblocksize = EEPROM_READBACK_LEN; - if (priv->fw_var >= 0x509) - maxblocksize -= 0xc; - else - maxblocksize -= 0x4; - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(*eeprom_hdr) + - maxblocksize, P54_CONTROL_TYPE_EEPROM_READBACK, - GFP_KERNEL); - if (!skb) - goto free; - priv->eeprom = kzalloc(EEPROM_READBACK_LEN, GFP_KERNEL); - if (!priv->eeprom) - goto free; - eeprom = kzalloc(eeprom_size, GFP_KERNEL); - if (!eeprom) - goto free; - - eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb, - sizeof(*eeprom_hdr) + maxblocksize); - - while (eeprom_size) { - blocksize = min(eeprom_size, maxblocksize); - if (priv->fw_var < 0x509) { - eeprom_hdr->v1.offset = cpu_to_le16(offset); - eeprom_hdr->v1.len = cpu_to_le16(blocksize); - } else { - eeprom_hdr->v2.offset = cpu_to_le32(offset); - eeprom_hdr->v2.len = cpu_to_le16(blocksize); - eeprom_hdr->v2.magic2 = 0xf; - memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4); - } - priv->tx(dev, skb); - - if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) { - printk(KERN_ERR "%s: device does not respond!\n", - wiphy_name(dev->wiphy)); - ret = -EBUSY; - goto free; - } - - memcpy(eeprom + offset, priv->eeprom, blocksize); - offset += blocksize; - eeprom_size -= blocksize; - } - - ret = p54_parse_eeprom(dev, eeprom, offset); -free: - kfree(priv->eeprom); - priv->eeprom = NULL; - p54_free_skb(dev, skb); - kfree(eeprom); - - return ret; -} -EXPORT_SYMBOL_GPL(p54_read_eeprom); - -static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, - bool set) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - struct p54_tim *tim; - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*tim), - P54_CONTROL_TYPE_TIM, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - tim = (struct p54_tim *) skb_put(skb, sizeof(*tim)); - tim->count = 1; - tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid); - priv->tx(dev, skb); - return 0; -} - -static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - struct p54_sta_unlock *sta; - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*sta), - P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta)); - memcpy(sta->addr, addr, ETH_ALEN); - priv->tx(dev, skb); - return 0; -} - -static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, - enum sta_notify_cmd notify_cmd, - struct ieee80211_sta *sta) -{ - switch (notify_cmd) { - case STA_NOTIFY_ADD: - case STA_NOTIFY_REMOVE: - /* - * Notify the firmware that we don't want or we don't - * need to buffer frames for this station anymore. - */ - - p54_sta_unlock(dev, sta->addr); - break; - case STA_NOTIFY_AWAKE: - /* update the firmware's filter table */ - p54_sta_unlock(dev, sta->addr); - break; - default: - break; - } -} - -static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - struct p54_hdr *hdr; - struct p54_txcancel *cancel; - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel), - P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - hdr = (void *)entry->data; - cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel)); - cancel->req_id = hdr->req_id; - priv->tx(dev, skb); - return 0; -} - -static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb, - struct ieee80211_tx_info *info, u8 *queue, size_t *extra_len, - u16 *flags, u16 *aid) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct p54_common *priv = dev->priv; - int ret = 1; - - switch (priv->mode) { - case NL80211_IFTYPE_MONITOR: - /* - * We have to set P54_HDR_FLAG_DATA_OUT_PROMISC for - * every frame in promiscuous/monitor mode. - * see STSW45x0C LMAC API - page 12. - */ - *aid = 0; - *flags = P54_HDR_FLAG_DATA_OUT_PROMISC; - *queue += P54_QUEUE_DATA; - break; - case NL80211_IFTYPE_STATION: - *aid = 1; - if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) { - *queue = P54_QUEUE_MGMT; - ret = 0; - } else - *queue += P54_QUEUE_DATA; - break; - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { - *aid = 0; - *queue = P54_QUEUE_CAB; - return 0; - } - - if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) { - if (ieee80211_is_probe_resp(hdr->frame_control)) { - *aid = 0; - *queue = P54_QUEUE_MGMT; - *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP | - P54_HDR_FLAG_DATA_OUT_NOCANCEL; - return 0; - } else if (ieee80211_is_beacon(hdr->frame_control)) { - *aid = 0; - - if (info->flags & IEEE80211_TX_CTL_INJECTED) { - /* - * Injecting beacons on top of a AP is - * not a good idea... nevertheless, - * it should be doable. - */ - - *queue += P54_QUEUE_DATA; - return 1; - } - - *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP; - *queue = P54_QUEUE_BEACON; - *extra_len = IEEE80211_MAX_TIM_LEN; - return 0; - } else { - *queue = P54_QUEUE_MGMT; - ret = 0; - } - } else - *queue += P54_QUEUE_DATA; - - if (info->control.sta) - *aid = info->control.sta->aid; - - if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) - *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; - break; - } - return ret; -} - -static u8 p54_convert_algo(enum ieee80211_key_alg alg) -{ - switch (alg) { - case ALG_WEP: - return P54_CRYPTO_WEP; - case ALG_TKIP: - return P54_CRYPTO_TKIPMICHAEL; - case ALG_CCMP: - return P54_CRYPTO_AESCCMP; - default: - return 0; - } -} - -static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_queue_stats *current_queue; - struct p54_common *priv = dev->priv; - struct p54_hdr *hdr; - struct p54_tx_data *txhdr; - size_t padding, len, tim_len = 0; - int i, j, ridx, ret; - u16 hdr_flags = 0, aid = 0; - u8 rate, queue, crypt_offset = 0; - u8 cts_rate = 0x20; - u8 rc_flags; - u8 calculated_tries[4]; - u8 nrates = 0, nremaining = 8; - - queue = skb_get_queue_mapping(skb); - - ret = p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid); - current_queue = &priv->tx_stats[queue]; - if (unlikely((current_queue->len > current_queue->limit) && ret)) - return NETDEV_TX_BUSY; - current_queue->len++; - current_queue->count++; - if ((current_queue->len == current_queue->limit) && ret) - ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); - - padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; - len = skb->len; - - if (info->control.hw_key) { - crypt_offset = ieee80211_get_hdrlen_from_skb(skb); - if (info->control.hw_key->alg == ALG_TKIP) { - u8 *iv = (u8 *)(skb->data + crypt_offset); - /* - * The firmware excepts that the IV has to have - * this special format - */ - iv[1] = iv[0]; - iv[0] = iv[2]; - iv[2] = 0; - } - } - - txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding); - hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); - - if (padding) - hdr_flags |= P54_HDR_FLAG_DATA_ALIGN; - hdr->type = cpu_to_le16(aid); - hdr->rts_tries = info->control.rates[0].count; - - /* - * we register the rates in perfect order, and - * RTS/CTS won't happen on 5 GHz - */ - cts_rate = info->control.rts_cts_rate_idx; - - memset(&txhdr->rateset, 0, sizeof(txhdr->rateset)); - - /* see how many rates got used */ - for (i = 0; i < 4; i++) { - if (info->control.rates[i].idx < 0) - break; - nrates++; - } - - /* limit tries to 8/nrates per rate */ - for (i = 0; i < nrates; i++) { - /* - * The magic expression here is equivalent to 8/nrates for - * all values that matter, but avoids division and jumps. - * Note that nrates can only take the values 1 through 4. - */ - calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1, - info->control.rates[i].count); - nremaining -= calculated_tries[i]; - } - - /* if there are tries left, distribute from back to front */ - for (i = nrates - 1; nremaining > 0 && i >= 0; i--) { - int tmp = info->control.rates[i].count - calculated_tries[i]; - - if (tmp <= 0) - continue; - /* RC requested more tries at this rate */ - - tmp = min_t(int, tmp, nremaining); - calculated_tries[i] += tmp; - nremaining -= tmp; - } - - ridx = 0; - for (i = 0; i < nrates && ridx < 8; i++) { - /* we register the rates in perfect order */ - rate = info->control.rates[i].idx; - if (info->band == IEEE80211_BAND_5GHZ) - rate += 4; - - /* store the count we actually calculated for TX status */ - info->control.rates[i].count = calculated_tries[i]; - - rc_flags = info->control.rates[i].flags; - if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) { - rate |= 0x10; - cts_rate |= 0x10; - } - if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) - rate |= 0x40; - else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) - rate |= 0x20; - for (j = 0; j < calculated_tries[i] && ridx < 8; j++) { - txhdr->rateset[ridx] = rate; - ridx++; - } - } - - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) - hdr_flags |= P54_HDR_FLAG_DATA_OUT_SEQNR; - - /* TODO: enable bursting */ - hdr->flags = cpu_to_le16(hdr_flags); - hdr->tries = ridx; - txhdr->rts_rate_idx = 0; - if (info->control.hw_key) { - txhdr->key_type = p54_convert_algo(info->control.hw_key->alg); - txhdr->key_len = min((u8)16, info->control.hw_key->keylen); - memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len); - if (info->control.hw_key->alg == ALG_TKIP) { - if (unlikely(skb_tailroom(skb) < 12)) - goto err; - /* reserve space for the MIC key */ - len += 8; - memcpy(skb_put(skb, 8), &(info->control.hw_key->key - [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8); - } - /* reserve some space for ICV */ - len += info->control.hw_key->icv_len; - memset(skb_put(skb, info->control.hw_key->icv_len), 0, - info->control.hw_key->icv_len); - } else { - txhdr->key_type = 0; - txhdr->key_len = 0; - } - txhdr->crypt_offset = crypt_offset; - txhdr->hw_queue = queue; - txhdr->backlog = current_queue->len; - memset(txhdr->durations, 0, sizeof(txhdr->durations)); - txhdr->tx_antenna = ((info->antenna_sel_tx == 0) ? - 2 : info->antenna_sel_tx - 1) & priv->tx_diversity_mask; - if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { - txhdr->longbow.cts_rate = cts_rate; - txhdr->longbow.output_power = cpu_to_le16(priv->output_power); - } else { - txhdr->normal.output_power = priv->output_power; - txhdr->normal.cts_rate = cts_rate; - } - if (padding) - txhdr->align[0] = padding; - - hdr->len = cpu_to_le16(len); - /* modifies skb->cb and with it info, so must be last! */ - if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) - goto err; - priv->tx(dev, skb); - - queue_delayed_work(dev->workqueue, &priv->work, - msecs_to_jiffies(P54_TX_FRAME_LIFETIME)); - - return NETDEV_TX_OK; - - err: - skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding); - current_queue->len--; - current_queue->count--; - return NETDEV_TX_BUSY; -} - -static int p54_setup_mac(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - struct p54_setup_mac *setup; - u16 mode; - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup), - P54_CONTROL_TYPE_SETUP, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup)); - if (dev->conf.radio_enabled) { - switch (priv->mode) { - case NL80211_IFTYPE_STATION: - mode = P54_FILTER_TYPE_STATION; - break; - case NL80211_IFTYPE_AP: - mode = P54_FILTER_TYPE_AP; - break; - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - mode = P54_FILTER_TYPE_IBSS; - break; - case NL80211_IFTYPE_MONITOR: - mode = P54_FILTER_TYPE_PROMISCUOUS; - break; - default: - mode = P54_FILTER_TYPE_HIBERNATE; - break; - } - - /* - * "TRANSPARENT and PROMISCUOUS are mutually exclusive" - * STSW45X0C LMAC API - page 12 - */ - if (((priv->filter_flags & FIF_PROMISC_IN_BSS) || - (priv->filter_flags & FIF_OTHER_BSS)) && - (mode != P54_FILTER_TYPE_PROMISCUOUS)) - mode |= P54_FILTER_TYPE_TRANSPARENT; - } else - mode = P54_FILTER_TYPE_HIBERNATE; - - setup->mac_mode = cpu_to_le16(mode); - memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN); - memcpy(setup->bssid, priv->bssid, ETH_ALEN); - setup->rx_antenna = 2 & priv->rx_diversity_mask; /* automatic */ - setup->rx_align = 0; - if (priv->fw_var < 0x500) { - setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); - memset(setup->v1.rts_rates, 0, 8); - setup->v1.rx_addr = cpu_to_le32(priv->rx_end); - setup->v1.max_rx = cpu_to_le16(priv->rx_mtu); - setup->v1.rxhw = cpu_to_le16(priv->rxhw); - setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer); - setup->v1.unalloc0 = cpu_to_le16(0); - } else { - setup->v2.rx_addr = cpu_to_le32(priv->rx_end); - setup->v2.max_rx = cpu_to_le16(priv->rx_mtu); - setup->v2.rxhw = cpu_to_le16(priv->rxhw); - setup->v2.timer = cpu_to_le16(priv->wakeup_timer); - setup->v2.truncate = cpu_to_le16(48896); - setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); - setup->v2.sbss_offset = 0; - setup->v2.mcast_window = 0; - setup->v2.rx_rssi_threshold = 0; - setup->v2.rx_ed_threshold = 0; - setup->v2.ref_clock = cpu_to_le32(644245094); - setup->v2.lpf_bandwidth = cpu_to_le16(65535); - setup->v2.osc_start_delay = cpu_to_le16(65535); - } - priv->tx(dev, skb); - return 0; -} - -static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - struct p54_hdr *hdr; - struct p54_scan_head *head; - struct p54_iq_autocal_entry *iq_autocal; - union p54_scan_body_union *body; - struct p54_scan_tail_rate *rate; - struct pda_rssi_cal_entry *rssi; - unsigned int i; - void *entry; - int band = dev->conf.channel->band; - __le16 freq = cpu_to_le16(dev->conf.channel->center_freq); - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) + - 2 + sizeof(*iq_autocal) + sizeof(*body) + - sizeof(*rate) + 2 * sizeof(*rssi), - P54_CONTROL_TYPE_SCAN, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - head = (struct p54_scan_head *) skb_put(skb, sizeof(*head)); - memset(head->scan_params, 0, sizeof(head->scan_params)); - head->mode = cpu_to_le16(mode); - head->dwell = cpu_to_le16(dwell); - head->freq = freq; - - if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { - __le16 *pa_power_points = (__le16 *) skb_put(skb, 2); - *pa_power_points = cpu_to_le16(0x0c); - } - - iq_autocal = (void *) skb_put(skb, sizeof(*iq_autocal)); - for (i = 0; i < priv->iq_autocal_len; i++) { - if (priv->iq_autocal[i].freq != freq) - continue; - - memcpy(iq_autocal, &priv->iq_autocal[i].params, - sizeof(struct p54_iq_autocal_entry)); - break; - } - if (i == priv->iq_autocal_len) - goto err; - - if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) - body = (void *) skb_put(skb, sizeof(body->longbow)); - else - body = (void *) skb_put(skb, sizeof(body->normal)); - - for (i = 0; i < priv->output_limit->entries; i++) { - __le16 *entry_freq = (void *) (priv->output_limit->data + - priv->output_limit->entry_size * i); - - if (*entry_freq != freq) - continue; - - if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { - memcpy(&body->longbow.power_limits, - (void *) entry_freq + sizeof(__le16), - priv->output_limit->entry_size); - } else { - struct pda_channel_output_limit *limits = - (void *) entry_freq; - - body->normal.val_barker = 0x38; - body->normal.val_bpsk = body->normal.dup_bpsk = - limits->val_bpsk; - body->normal.val_qpsk = body->normal.dup_qpsk = - limits->val_qpsk; - body->normal.val_16qam = body->normal.dup_16qam = - limits->val_16qam; - body->normal.val_64qam = body->normal.dup_64qam = - limits->val_64qam; - } - break; - } - if (i == priv->output_limit->entries) - goto err; - - entry = (void *)(priv->curve_data->data + priv->curve_data->offset); - for (i = 0; i < priv->curve_data->entries; i++) { - if (*((__le16 *)entry) != freq) { - entry += priv->curve_data->entry_size; - continue; - } - - if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { - memcpy(&body->longbow.curve_data, - (void *) entry + sizeof(__le16), - priv->curve_data->entry_size); - } else { - struct p54_scan_body *chan = &body->normal; - struct pda_pa_curve_data *curve_data = - (void *) priv->curve_data->data; - - entry += sizeof(__le16); - chan->pa_points_per_curve = 8; - memset(chan->curve_data, 0, sizeof(*chan->curve_data)); - memcpy(chan->curve_data, entry, - sizeof(struct p54_pa_curve_data_sample) * - min((u8)8, curve_data->points_per_channel)); - } - break; - } - if (i == priv->curve_data->entries) - goto err; - - if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) { - rate = (void *) skb_put(skb, sizeof(*rate)); - rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); - for (i = 0; i < sizeof(rate->rts_rates); i++) - rate->rts_rates[i] = i; - } - - rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi)); - rssi->mul = cpu_to_le16(priv->rssical_db[band].mul); - rssi->add = cpu_to_le16(priv->rssical_db[band].add); - if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { - /* Longbow frontend needs ever more */ - rssi = (void *) skb_put(skb, sizeof(*rssi)); - rssi->mul = cpu_to_le16(priv->rssical_db[band].longbow_unkn); - rssi->add = cpu_to_le16(priv->rssical_db[band].longbow_unk2); - } - - if (priv->fw_var >= 0x509) { - rate = (void *) skb_put(skb, sizeof(*rate)); - rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); - for (i = 0; i < sizeof(rate->rts_rates); i++) - rate->rts_rates[i] = i; - } - - hdr = (struct p54_hdr *) skb->data; - hdr->len = cpu_to_le16(skb->len - sizeof(*hdr)); - - priv->tx(dev, skb); - return 0; - - err: - printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy)); - p54_free_skb(dev, skb); - return -EINVAL; -} - -static int p54_set_leds(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - struct p54_led *led; - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led), - P54_CONTROL_TYPE_LED, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - led = (struct p54_led *) skb_put(skb, sizeof(*led)); - led->flags = cpu_to_le16(0x0003); - led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state); - led->delay[0] = cpu_to_le16(1); - led->delay[1] = cpu_to_le16(0); - priv->tx(dev, skb); - return 0; -} - -#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, _txop) \ -do { \ - queue.aifs = cpu_to_le16(ai_fs); \ - queue.cwmin = cpu_to_le16(cw_min); \ - queue.cwmax = cpu_to_le16(cw_max); \ - queue.txop = cpu_to_le16(_txop); \ -} while(0) - -static int p54_set_edcf(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - struct p54_edcf *edcf; - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf), - P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf)); - if (priv->use_short_slot) { - edcf->slottime = 9; - edcf->sifs = 0x10; - edcf->eofpad = 0x00; - } else { - edcf->slottime = 20; - edcf->sifs = 0x0a; - edcf->eofpad = 0x06; - } - /* (see prism54/isl_oid.h for further details) */ - edcf->frameburst = cpu_to_le16(0); - edcf->round_trip_delay = cpu_to_le16(0); - edcf->flags = 0; - memset(edcf->mapping, 0, sizeof(edcf->mapping)); - memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue)); - priv->tx(dev, skb); - return 0; -} - -static int p54_set_ps(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - struct p54_psm *psm; - u16 mode; - int i; - - if (dev->conf.flags & IEEE80211_CONF_PS) - mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM | - P54_PSM_CHECKSUM | P54_PSM_MCBC; - else - mode = P54_PSM_CAM; - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*psm), - P54_CONTROL_TYPE_PSM, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - psm = (struct p54_psm *)skb_put(skb, sizeof(*psm)); - psm->mode = cpu_to_le16(mode); - psm->aid = cpu_to_le16(priv->aid); - for (i = 0; i < ARRAY_SIZE(psm->intervals); i++) { - psm->intervals[i].interval = - cpu_to_le16(dev->conf.listen_interval); - psm->intervals[i].periods = cpu_to_le16(1); - } - - psm->beacon_rssi_skip_max = 200; - psm->rssi_delta_threshold = 0; - psm->nr = 10; - psm->exclude[0] = 0; - - priv->tx(dev, skb); - - return 0; -} - -static int p54_beacon_tim(struct sk_buff *skb) -{ - /* - * the good excuse for this mess is ... the firmware. - * The dummy TIM MUST be at the end of the beacon frame, - * because it'll be overwritten! - */ - - struct ieee80211_mgmt *mgmt = (void *)skb->data; - u8 *pos, *end; - - if (skb->len <= sizeof(mgmt)) - return -EINVAL; - - pos = (u8 *)mgmt->u.beacon.variable; - end = skb->data + skb->len; - while (pos < end) { - if (pos + 2 + pos[1] > end) - return -EINVAL; - - if (pos[0] == WLAN_EID_TIM) { - u8 dtim_len = pos[1]; - u8 dtim_period = pos[3]; - u8 *next = pos + 2 + dtim_len; - - if (dtim_len < 3) - return -EINVAL; - - memmove(pos, next, end - next); - - if (dtim_len > 3) - skb_trim(skb, skb->len - (dtim_len - 3)); - - pos = end - (dtim_len + 2); - - /* add the dummy at the end */ - pos[0] = WLAN_EID_TIM; - pos[1] = 3; - pos[2] = 0; - pos[3] = dtim_period; - pos[4] = 0; - return 0; - } - pos += 2 + pos[1]; - } - return 0; -} - -static int p54_beacon_update(struct ieee80211_hw *dev, - struct ieee80211_vif *vif) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *beacon; - int ret; - - if (priv->cached_beacon) { - p54_tx_cancel(dev, priv->cached_beacon); - /* wait for the last beacon the be freed */ - msleep(10); - } - - beacon = ieee80211_beacon_get(dev, vif); - if (!beacon) - return -ENOMEM; - ret = p54_beacon_tim(beacon); - if (ret) - return ret; - ret = p54_tx(dev, beacon); - if (ret) - return ret; - priv->cached_beacon = beacon; - priv->tsf_high32 = 0; - priv->tsf_low32 = 0; - - return 0; -} - -static int p54_start(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - int err; - - mutex_lock(&priv->conf_mutex); - err = priv->open(dev); - if (err) - goto out; - P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47); - P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94); - P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0); - P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0); - err = p54_set_edcf(dev); - if (err) - goto out; - - memset(priv->bssid, ~0, ETH_ALEN); - priv->mode = NL80211_IFTYPE_MONITOR; - err = p54_setup_mac(dev); - if (err) { - priv->mode = NL80211_IFTYPE_UNSPECIFIED; - goto out; - } - - queue_delayed_work(dev->workqueue, &priv->work, 0); - - priv->softled_state = 0; - err = p54_set_leds(dev); - -out: - mutex_unlock(&priv->conf_mutex); - return err; -} - -static void p54_stop(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - - mutex_lock(&priv->conf_mutex); - priv->mode = NL80211_IFTYPE_UNSPECIFIED; - priv->softled_state = 0; - p54_set_leds(dev); - -#ifdef CONFIG_P54_LEDS - cancel_delayed_work_sync(&priv->led_work); -#endif /* CONFIG_P54_LEDS */ - cancel_delayed_work_sync(&priv->work); - if (priv->cached_beacon) - p54_tx_cancel(dev, priv->cached_beacon); - - priv->stop(dev); - while ((skb = skb_dequeue(&priv->tx_queue))) - kfree_skb(skb); - priv->cached_beacon = NULL; - priv->tsf_high32 = priv->tsf_low32 = 0; - mutex_unlock(&priv->conf_mutex); -} - -static int p54_add_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) -{ - struct p54_common *priv = dev->priv; - - mutex_lock(&priv->conf_mutex); - if (priv->mode != NL80211_IFTYPE_MONITOR) { - mutex_unlock(&priv->conf_mutex); - return -EOPNOTSUPP; - } - - priv->vif = conf->vif; - - switch (conf->type) { - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_MESH_POINT: - priv->mode = conf->type; - break; - default: - mutex_unlock(&priv->conf_mutex); - return -EOPNOTSUPP; - } - - memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); - p54_setup_mac(dev); - mutex_unlock(&priv->conf_mutex); - return 0; -} - -static void p54_remove_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) -{ - struct p54_common *priv = dev->priv; - - mutex_lock(&priv->conf_mutex); - priv->vif = NULL; - if (priv->cached_beacon) - p54_tx_cancel(dev, priv->cached_beacon); - priv->mode = NL80211_IFTYPE_MONITOR; - memset(priv->mac_addr, 0, ETH_ALEN); - memset(priv->bssid, 0, ETH_ALEN); - p54_setup_mac(dev); - mutex_unlock(&priv->conf_mutex); -} - -static int p54_config(struct ieee80211_hw *dev, u32 changed) -{ - int ret = 0; - struct p54_common *priv = dev->priv; - struct ieee80211_conf *conf = &dev->conf; - - mutex_lock(&priv->conf_mutex); - if (changed & IEEE80211_CONF_CHANGE_POWER) - priv->output_power = conf->power_level << 2; - if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { - ret = p54_setup_mac(dev); - if (ret) - goto out; - } - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - ret = p54_scan(dev, P54_SCAN_EXIT, 0); - if (ret) - goto out; - } - if (changed & IEEE80211_CONF_CHANGE_PS) { - ret = p54_set_ps(dev); - if (ret) - goto out; - } - -out: - mutex_unlock(&priv->conf_mutex); - return ret; -} - -static void p54_configure_filter(struct ieee80211_hw *dev, - unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, struct dev_mc_list *mclist) -{ - struct p54_common *priv = dev->priv; - - *total_flags &= FIF_PROMISC_IN_BSS | - FIF_OTHER_BSS; - - priv->filter_flags = *total_flags; - - if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) - p54_setup_mac(dev); -} - -static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, - const struct ieee80211_tx_queue_params *params) -{ - struct p54_common *priv = dev->priv; - int ret; - - mutex_lock(&priv->conf_mutex); - if ((params) && !(queue > 4)) { - P54_SET_QUEUE(priv->qos_params[queue], params->aifs, - params->cw_min, params->cw_max, params->txop); - ret = p54_set_edcf(dev); - } else - ret = -EINVAL; - mutex_unlock(&priv->conf_mutex); - return ret; -} - -static int p54_init_xbow_synth(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - struct p54_xbow_synth *xbow; - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow), - P54_CONTROL_TYPE_XBOW_SYNTH_CFG, GFP_KERNEL); - if (!skb) - return -ENOMEM; - - xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow)); - xbow->magic1 = cpu_to_le16(0x1); - xbow->magic2 = cpu_to_le16(0x2); - xbow->freq = cpu_to_le16(5390); - memset(xbow->padding, 0, sizeof(xbow->padding)); - priv->tx(dev, skb); - return 0; -} - -static void p54_work(struct work_struct *work) -{ - struct p54_common *priv = container_of(work, struct p54_common, - work.work); - struct ieee80211_hw *dev = priv->hw; - struct sk_buff *skb; - - if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) - return ; - - /* - * TODO: walk through tx_queue and do the following tasks - * 1. initiate bursts. - * 2. cancel stuck frames / reset the device if necessary. - */ - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, - sizeof(struct p54_statistics), - P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL); - if (!skb) - return ; - - priv->tx(dev, skb); -} - -static int p54_get_stats(struct ieee80211_hw *dev, - struct ieee80211_low_level_stats *stats) -{ - struct p54_common *priv = dev->priv; - - memcpy(stats, &priv->stats, sizeof(*stats)); - return 0; -} - -static int p54_get_tx_stats(struct ieee80211_hw *dev, - struct ieee80211_tx_queue_stats *stats) -{ - struct p54_common *priv = dev->priv; - - memcpy(stats, &priv->tx_stats[P54_QUEUE_DATA], - sizeof(stats[0]) * dev->queues); - return 0; -} - -static void p54_bss_info_changed(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, - u32 changed) -{ - struct p54_common *priv = dev->priv; - int ret; - - mutex_lock(&priv->conf_mutex); - if (changed & BSS_CHANGED_BSSID) { - memcpy(priv->bssid, info->bssid, ETH_ALEN); - ret = p54_setup_mac(dev); - if (ret) - goto out; - } - - if (changed & BSS_CHANGED_BEACON) { - ret = p54_scan(dev, P54_SCAN_EXIT, 0); - if (ret) - goto out; - ret = p54_setup_mac(dev); - if (ret) - goto out; - ret = p54_beacon_update(dev, vif); - if (ret) - goto out; - } - /* XXX: this mimics having two callbacks... clean up */ - out: - mutex_unlock(&priv->conf_mutex); - - if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BEACON)) { - priv->use_short_slot = info->use_short_slot; - p54_set_edcf(dev); - } - if (changed & BSS_CHANGED_BASIC_RATES) { - if (dev->conf.channel->band == IEEE80211_BAND_5GHZ) - priv->basic_rate_mask = (info->basic_rates << 4); - else - priv->basic_rate_mask = info->basic_rates; - p54_setup_mac(dev); - if (priv->fw_var >= 0x500) - p54_scan(dev, P54_SCAN_EXIT, 0); - } - if (changed & BSS_CHANGED_ASSOC) { - if (info->assoc) { - priv->aid = info->aid; - priv->wakeup_timer = info->beacon_int * - info->dtim_period * 5; - p54_setup_mac(dev); - } - } -} - -static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - struct p54_common *priv = dev->priv; - struct sk_buff *skb; - struct p54_keycache *rxkey; - int slot, ret = 0; - u8 algo = 0; - - if (modparam_nohwcrypt) - return -EOPNOTSUPP; - - mutex_lock(&priv->conf_mutex); - if (cmd == SET_KEY) { - switch (key->alg) { - case ALG_TKIP: - if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL | - BR_DESC_PRIV_CAP_TKIP))) { - ret = -EOPNOTSUPP; - goto out_unlock; - } - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - algo = P54_CRYPTO_TKIPMICHAEL; - break; - case ALG_WEP: - if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) { - ret = -EOPNOTSUPP; - goto out_unlock; - } - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - algo = P54_CRYPTO_WEP; - break; - case ALG_CCMP: - if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) { - ret = -EOPNOTSUPP; - goto out_unlock; - } - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - algo = P54_CRYPTO_AESCCMP; - break; - default: - ret = -EOPNOTSUPP; - goto out_unlock; - } - slot = bitmap_find_free_region(priv->used_rxkeys, - priv->rx_keycache_size, 0); - - if (slot < 0) { - /* - * The device supports the choosen algorithm, but the - * firmware does not provide enough key slots to store - * all of them. - * But encryption offload for outgoing frames is always - * possible, so we just pretend that the upload was - * successful and do the decryption in software. - */ - - /* mark the key as invalid. */ - key->hw_key_idx = 0xff; - goto out_unlock; - } - } else { - slot = key->hw_key_idx; - - if (slot == 0xff) { - /* This key was not uploaded into the rx key cache. */ - - goto out_unlock; - } - - bitmap_release_region(priv->used_rxkeys, slot, 0); - algo = 0; - } - - skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey), - P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL); - if (!skb) { - bitmap_release_region(priv->used_rxkeys, slot, 0); - ret = -ENOSPC; - goto out_unlock; - } - - rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey)); - rxkey->entry = slot; - rxkey->key_id = key->keyidx; - rxkey->key_type = algo; - if (sta) - memcpy(rxkey->mac, sta->addr, ETH_ALEN); - else - memset(rxkey->mac, ~0, ETH_ALEN); - if (key->alg != ALG_TKIP) { - rxkey->key_len = min((u8)16, key->keylen); - memcpy(rxkey->key, key->key, rxkey->key_len); - } else { - rxkey->key_len = 24; - memcpy(rxkey->key, key->key, 16); - memcpy(&(rxkey->key[16]), &(key->key - [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8); - } - - priv->tx(dev, skb); - key->hw_key_idx = slot; - -out_unlock: - mutex_unlock(&priv->conf_mutex); - return ret; -} - -#ifdef CONFIG_P54_LEDS -static void p54_update_leds(struct work_struct *work) -{ - struct p54_common *priv = container_of(work, struct p54_common, - led_work.work); - int err, i, tmp, blink_delay = 400; - bool rerun = false; - - /* Don't toggle the LED, when the device is down. */ - if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) - return ; - - for (i = 0; i < ARRAY_SIZE(priv->leds); i++) - if (priv->leds[i].toggled) { - priv->softled_state |= BIT(i); - - tmp = 70 + 200 / (priv->leds[i].toggled); - if (tmp < blink_delay) - blink_delay = tmp; - - if (priv->leds[i].led_dev.brightness == LED_OFF) - rerun = true; - - priv->leds[i].toggled = - !!priv->leds[i].led_dev.brightness; - } else - priv->softled_state &= ~BIT(i); - - err = p54_set_leds(priv->hw); - if (err && net_ratelimit()) - printk(KERN_ERR "%s: failed to update LEDs.\n", - wiphy_name(priv->hw->wiphy)); - - if (rerun) - queue_delayed_work(priv->hw->workqueue, &priv->led_work, - msecs_to_jiffies(blink_delay)); -} - -static void p54_led_brightness_set(struct led_classdev *led_dev, - enum led_brightness brightness) -{ - struct p54_led_dev *led = container_of(led_dev, struct p54_led_dev, - led_dev); - struct ieee80211_hw *dev = led->hw_dev; - struct p54_common *priv = dev->priv; - - if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) - return ; - - if (brightness) { - led->toggled++; - queue_delayed_work(priv->hw->workqueue, &priv->led_work, - HZ/10); - } -} - -static int p54_register_led(struct ieee80211_hw *dev, - unsigned int led_index, - char *name, char *trigger) -{ - struct p54_common *priv = dev->priv; - struct p54_led_dev *led = &priv->leds[led_index]; - int err; - - if (led->registered) - return -EEXIST; - - snprintf(led->name, sizeof(led->name), "p54-%s::%s", - wiphy_name(dev->wiphy), name); - led->hw_dev = dev; - led->index = led_index; - led->led_dev.name = led->name; - led->led_dev.default_trigger = trigger; - led->led_dev.brightness_set = p54_led_brightness_set; - - err = led_classdev_register(wiphy_dev(dev->wiphy), &led->led_dev); - if (err) - printk(KERN_ERR "%s: Failed to register %s LED.\n", - wiphy_name(dev->wiphy), name); - else - led->registered = 1; - - return err; -} - -static int p54_init_leds(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - int err; - - /* - * TODO: - * Figure out if the EEPROM contains some hints about the number - * of available/programmable LEDs of the device. - */ - - INIT_DELAYED_WORK(&priv->led_work, p54_update_leds); - - err = p54_register_led(dev, 0, "assoc", - ieee80211_get_assoc_led_name(dev)); - if (err) - return err; - - err = p54_register_led(dev, 1, "tx", - ieee80211_get_tx_led_name(dev)); - if (err) - return err; - - err = p54_register_led(dev, 2, "rx", - ieee80211_get_rx_led_name(dev)); - if (err) - return err; - - err = p54_register_led(dev, 3, "radio", - ieee80211_get_radio_led_name(dev)); - if (err) - return err; - - err = p54_set_leds(dev); - return err; -} - -static void p54_unregister_leds(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - int i; - - for (i = 0; i < ARRAY_SIZE(priv->leds); i++) - if (priv->leds[i].registered) - led_classdev_unregister(&priv->leds[i].led_dev); -} -#endif /* CONFIG_P54_LEDS */ - -static const struct ieee80211_ops p54_ops = { - .tx = p54_tx, - .start = p54_start, - .stop = p54_stop, - .add_interface = p54_add_interface, - .remove_interface = p54_remove_interface, - .set_tim = p54_set_tim, - .sta_notify = p54_sta_notify, - .set_key = p54_set_key, - .config = p54_config, - .bss_info_changed = p54_bss_info_changed, - .configure_filter = p54_configure_filter, - .conf_tx = p54_conf_tx, - .get_stats = p54_get_stats, - .get_tx_stats = p54_get_tx_stats -}; - -struct ieee80211_hw *p54_init_common(size_t priv_data_len) -{ - struct ieee80211_hw *dev; - struct p54_common *priv; - - dev = ieee80211_alloc_hw(priv_data_len, &p54_ops); - if (!dev) - return NULL; - - priv = dev->priv; - priv->hw = dev; - priv->mode = NL80211_IFTYPE_UNSPECIFIED; - priv->basic_rate_mask = 0x15f; - skb_queue_head_init(&priv->tx_queue); - dev->flags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM; - - dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_MESH_POINT); - - dev->channel_change_time = 1000; /* TODO: find actual value */ - priv->tx_stats[P54_QUEUE_BEACON].limit = 1; - priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1; - priv->tx_stats[P54_QUEUE_MGMT].limit = 3; - priv->tx_stats[P54_QUEUE_CAB].limit = 3; - priv->tx_stats[P54_QUEUE_DATA].limit = 5; - dev->queues = 1; - priv->noise = -94; - /* - * We support at most 8 tries no matter which rate they're at, - * we cannot support max_rates * max_rate_tries as we set it - * here, but setting it correctly to 4/2 or so would limit us - * artificially if the RC algorithm wants just two rates, so - * let's say 4/7, we'll redistribute it at TX time, see the - * comments there. - */ - dev->max_rates = 4; - dev->max_rate_tries = 7; - dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 + - sizeof(struct p54_tx_data); - - mutex_init(&priv->conf_mutex); - init_completion(&priv->eeprom_comp); - INIT_DELAYED_WORK(&priv->work, p54_work); - - return dev; -} -EXPORT_SYMBOL_GPL(p54_init_common); - -int p54_register_common(struct ieee80211_hw *dev, struct device *pdev) -{ - int err; - - err = ieee80211_register_hw(dev); - if (err) { - dev_err(pdev, "Cannot register device (%d).\n", err); - return err; - } - -#ifdef CONFIG_P54_LEDS - err = p54_init_leds(dev); - if (err) - return err; -#endif /* CONFIG_P54_LEDS */ - - dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy)); - return 0; -} -EXPORT_SYMBOL_GPL(p54_register_common); - -void p54_free_common(struct ieee80211_hw *dev) -{ - struct p54_common *priv = dev->priv; - kfree(priv->iq_autocal); - kfree(priv->output_limit); - kfree(priv->curve_data); - kfree(priv->used_rxkeys); - -#ifdef CONFIG_P54_LEDS - p54_unregister_leds(dev); -#endif /* CONFIG_P54_LEDS */ -} -EXPORT_SYMBOL_GPL(p54_free_common); diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h deleted file mode 100644 index 75ead7a150f..00000000000 --- a/drivers/net/wireless/p54/p54common.h +++ /dev/null @@ -1,644 +0,0 @@ -#ifndef P54COMMON_H -#define P54COMMON_H - -/* - * Common code specific definitions for mac80211 Prism54 drivers - * - * Copyright (c) 2006, Michael Wu - * Copyright (c) 2007, Christian Lamparter - * - * Based on: - * - the islsm (softmac prism54) driver, which is: - * Copyright 2004-2006 Jean-Baptiste Note , et al. - * - * - LMAC API interface header file for STLC4560 (lmac_longbow.h) - * Copyright (C) 2007 Conexant Systems, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -struct bootrec { - __le32 code; - __le32 len; - u32 data[10]; -} __attribute__((packed)); - -#define PDR_SYNTH_FRONTEND_MASK 0x0007 -#define PDR_SYNTH_FRONTEND_DUETTE3 0x0001 -#define PDR_SYNTH_FRONTEND_DUETTE2 0x0002 -#define PDR_SYNTH_FRONTEND_FRISBEE 0x0003 -#define PDR_SYNTH_FRONTEND_XBOW 0x0004 -#define PDR_SYNTH_FRONTEND_LONGBOW 0x0005 -#define PDR_SYNTH_IQ_CAL_MASK 0x0018 -#define PDR_SYNTH_IQ_CAL_PA_DETECTOR 0x0000 -#define PDR_SYNTH_IQ_CAL_DISABLED 0x0008 -#define PDR_SYNTH_IQ_CAL_ZIF 0x0010 -#define PDR_SYNTH_FAA_SWITCH_MASK 0x0020 -#define PDR_SYNTH_FAA_SWITCH_ENABLED 0x0020 -#define PDR_SYNTH_24_GHZ_MASK 0x0040 -#define PDR_SYNTH_24_GHZ_DISABLED 0x0040 -#define PDR_SYNTH_5_GHZ_MASK 0x0080 -#define PDR_SYNTH_5_GHZ_DISABLED 0x0080 -#define PDR_SYNTH_RX_DIV_MASK 0x0100 -#define PDR_SYNTH_RX_DIV_SUPPORTED 0x0100 -#define PDR_SYNTH_TX_DIV_MASK 0x0200 -#define PDR_SYNTH_TX_DIV_SUPPORTED 0x0200 - -struct bootrec_exp_if { - __le16 role; - __le16 if_id; - __le16 variant; - __le16 btm_compat; - __le16 top_compat; -} __attribute__((packed)); - -#define BR_DESC_PRIV_CAP_WEP BIT(0) -#define BR_DESC_PRIV_CAP_TKIP BIT(1) -#define BR_DESC_PRIV_CAP_MICHAEL BIT(2) -#define BR_DESC_PRIV_CAP_CCX_CP BIT(3) -#define BR_DESC_PRIV_CAP_CCX_MIC BIT(4) -#define BR_DESC_PRIV_CAP_AESCCMP BIT(5) - -struct bootrec_desc { - __le16 modes; - __le16 flags; - __le32 rx_start; - __le32 rx_end; - u8 headroom; - u8 tailroom; - u8 tx_queues; - u8 tx_depth; - u8 privacy_caps; - u8 rx_keycache_size; - u8 time_size; - u8 padding; - u8 rates[16]; - u8 padding2[4]; - __le16 rx_mtu; -} __attribute__((packed)); - -#define BR_CODE_MIN 0x80000000 -#define BR_CODE_COMPONENT_ID 0x80000001 -#define BR_CODE_COMPONENT_VERSION 0x80000002 -#define BR_CODE_DEPENDENT_IF 0x80000003 -#define BR_CODE_EXPOSED_IF 0x80000004 -#define BR_CODE_DESCR 0x80000101 -#define BR_CODE_MAX 0x8FFFFFFF -#define BR_CODE_END_OF_BRA 0xFF0000FF -#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF - -#define P54_HDR_FLAG_DATA_ALIGN BIT(14) -#define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0) -#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1) -#define P54_HDR_FLAG_DATA_OUT_SEQNR BIT(2) -#define P54_HDR_FLAG_DATA_OUT_BIT3 BIT(3) -#define P54_HDR_FLAG_DATA_OUT_BURST BIT(4) -#define P54_HDR_FLAG_DATA_OUT_NOCANCEL BIT(5) -#define P54_HDR_FLAG_DATA_OUT_CLEARTIM BIT(6) -#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE BIT(7) -#define P54_HDR_FLAG_DATA_OUT_COMPRESS BIT(8) -#define P54_HDR_FLAG_DATA_OUT_CONCAT BIT(9) -#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT BIT(10) -#define P54_HDR_FLAG_DATA_OUT_WAITEOSP BIT(11) - -#define P54_HDR_FLAG_DATA_IN_FCS_GOOD BIT(0) -#define P54_HDR_FLAG_DATA_IN_MATCH_MAC BIT(1) -#define P54_HDR_FLAG_DATA_IN_MCBC BIT(2) -#define P54_HDR_FLAG_DATA_IN_BEACON BIT(3) -#define P54_HDR_FLAG_DATA_IN_MATCH_BSS BIT(4) -#define P54_HDR_FLAG_DATA_IN_BCAST_BSS BIT(5) -#define P54_HDR_FLAG_DATA_IN_DATA BIT(6) -#define P54_HDR_FLAG_DATA_IN_TRUNCATED BIT(7) -#define P54_HDR_FLAG_DATA_IN_BIT8 BIT(8) -#define P54_HDR_FLAG_DATA_IN_TRANSPARENT BIT(9) - -/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */ - -struct pda_entry { - __le16 len; /* includes both code and data */ - __le16 code; - u8 data[0]; -} __attribute__ ((packed)); - -struct eeprom_pda_wrap { - __le32 magic; - __le16 pad; - __le16 len; - __le32 arm_opcode; - u8 data[0]; -} __attribute__ ((packed)); - -struct p54_iq_autocal_entry { - __le16 iq_param[4]; -} __attribute__ ((packed)); - -struct pda_iq_autocal_entry { - __le16 freq; - struct p54_iq_autocal_entry params; -} __attribute__ ((packed)); - -struct pda_channel_output_limit { - __le16 freq; - u8 val_bpsk; - u8 val_qpsk; - u8 val_16qam; - u8 val_64qam; - u8 rate_set_mask; - u8 rate_set_size; -} __attribute__ ((packed)); - -struct pda_pa_curve_data_sample_rev0 { - u8 rf_power; - u8 pa_detector; - u8 pcv; -} __attribute__ ((packed)); - -struct pda_pa_curve_data_sample_rev1 { - u8 rf_power; - u8 pa_detector; - u8 data_barker; - u8 data_bpsk; - u8 data_qpsk; - u8 data_16qam; - u8 data_64qam; -} __attribute__ ((packed)); - -struct p54_pa_curve_data_sample { - u8 rf_power; - u8 pa_detector; - u8 data_barker; - u8 data_bpsk; - u8 data_qpsk; - u8 data_16qam; - u8 data_64qam; - u8 padding; -} __attribute__ ((packed)); - -struct pda_pa_curve_data { - u8 cal_method_rev; - u8 channels; - u8 points_per_channel; - u8 padding; - u8 data[0]; -} __attribute__ ((packed)); - -struct pda_rssi_cal_entry { - __le16 mul; - __le16 add; -} __attribute__ ((packed)); - -struct pda_country { - u8 regdomain; - u8 alpha2[2]; - u8 flags; -} __attribute__ ((packed)); - -/* - * Warning: Longbow's structures are bogus. - */ -struct p54_channel_output_limit_longbow { - __le16 rf_power_points[12]; -} __attribute__ ((packed)); - -struct p54_pa_curve_data_sample_longbow { - __le16 rf_power; - __le16 pa_detector; - struct { - __le16 data[4]; - } points[3] __attribute__ ((packed)); -} __attribute__ ((packed)); - -struct pda_custom_wrapper { - __le16 entries; - __le16 entry_size; - __le16 offset; - __le16 len; - u8 data[0]; -} __attribute__ ((packed)); - -/* - * this defines the PDR codes used to build PDAs as defined in document - * number 553155. The current implementation mirrors version 1.1 of the - * document and lists only PDRs supported by the ARM platform. - */ - -/* common and choice range (0x0000 - 0x0fff) */ -#define PDR_END 0x0000 -#define PDR_MANUFACTURING_PART_NUMBER 0x0001 -#define PDR_PDA_VERSION 0x0002 -#define PDR_NIC_SERIAL_NUMBER 0x0003 - -#define PDR_MAC_ADDRESS 0x0101 -#define PDR_REGULATORY_DOMAIN_LIST 0x0103 -#define PDR_TEMPERATURE_TYPE 0x0107 - -#define PDR_PRISM_PCI_IDENTIFIER 0x0402 - -/* ARM range (0x1000 - 0x1fff) */ -#define PDR_COUNTRY_INFORMATION 0x1000 -#define PDR_INTERFACE_LIST 0x1001 -#define PDR_HARDWARE_PLATFORM_COMPONENT_ID 0x1002 -#define PDR_OEM_NAME 0x1003 -#define PDR_PRODUCT_NAME 0x1004 -#define PDR_UTF8_OEM_NAME 0x1005 -#define PDR_UTF8_PRODUCT_NAME 0x1006 -#define PDR_COUNTRY_LIST 0x1007 -#define PDR_DEFAULT_COUNTRY 0x1008 - -#define PDR_ANTENNA_GAIN 0x1100 - -#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA 0x1901 -#define PDR_RSSI_LINEAR_APPROXIMATION 0x1902 -#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS 0x1903 -#define PDR_PRISM_PA_CAL_CURVE_DATA 0x1904 -#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND 0x1905 -#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION 0x1906 -#define PDR_REGULATORY_POWER_LIMITS 0x1907 -#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED 0x1908 -#define PDR_RADIATED_TRANSMISSION_CORRECTION 0x1909 -#define PDR_PRISM_TX_IQ_CALIBRATION 0x190a - -/* reserved range (0x2000 - 0x7fff) */ - -/* customer range (0x8000 - 0xffff) */ -#define PDR_BASEBAND_REGISTERS 0x8000 -#define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001 - -/* used by our modificated eeprom image */ -#define PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM 0xDEAD -#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM 0xBEEF -#define PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM 0xB05D - -/* PDR definitions for default country & country list */ -#define PDR_COUNTRY_CERT_CODE 0x80 -#define PDR_COUNTRY_CERT_CODE_REAL 0x00 -#define PDR_COUNTRY_CERT_CODE_PSEUDO 0x80 -#define PDR_COUNTRY_CERT_BAND 0x40 -#define PDR_COUNTRY_CERT_BAND_2GHZ 0x00 -#define PDR_COUNTRY_CERT_BAND_5GHZ 0x40 -#define PDR_COUNTRY_CERT_IODOOR 0x30 -#define PDR_COUNTRY_CERT_IODOOR_BOTH 0x00 -#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20 -#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR 0x30 -#define PDR_COUNTRY_CERT_INDEX 0x0F - -struct p54_eeprom_lm86 { - union { - struct { - __le16 offset; - __le16 len; - u8 data[0]; - } v1; - struct { - __le32 offset; - __le16 len; - u8 magic2; - u8 pad; - u8 magic[4]; - u8 data[0]; - } v2; - } __attribute__ ((packed)); -} __attribute__ ((packed)); - -enum p54_rx_decrypt_status { - P54_DECRYPT_NONE = 0, - P54_DECRYPT_OK, - P54_DECRYPT_NOKEY, - P54_DECRYPT_NOMICHAEL, - P54_DECRYPT_NOCKIPMIC, - P54_DECRYPT_FAIL_WEP, - P54_DECRYPT_FAIL_TKIP, - P54_DECRYPT_FAIL_MICHAEL, - P54_DECRYPT_FAIL_CKIPKP, - P54_DECRYPT_FAIL_CKIPMIC, - P54_DECRYPT_FAIL_AESCCMP -}; - -struct p54_rx_data { - __le16 flags; - __le16 len; - __le16 freq; - u8 antenna; - u8 rate; - u8 rssi; - u8 quality; - u8 decrypt_status; - u8 rssi_raw; - __le32 tsf32; - __le32 unalloc0; - u8 align[0]; -} __attribute__ ((packed)); - -enum p54_trap_type { - P54_TRAP_SCAN = 0, - P54_TRAP_TIMER, - P54_TRAP_BEACON_TX, - P54_TRAP_FAA_RADIO_ON, - P54_TRAP_FAA_RADIO_OFF, - P54_TRAP_RADAR, - P54_TRAP_NO_BEACON, - P54_TRAP_TBTT, - P54_TRAP_SCO_ENTER, - P54_TRAP_SCO_EXIT -}; - -struct p54_trap { - __le16 event; - __le16 frequency; -} __attribute__ ((packed)); - -enum p54_frame_sent_status { - P54_TX_OK = 0, - P54_TX_FAILED, - P54_TX_PSM, - P54_TX_PSM_CANCELLED = 4 -}; - -struct p54_frame_sent { - u8 status; - u8 tries; - u8 ack_rssi; - u8 quality; - __le16 seq; - u8 antenna; - u8 padding; -} __attribute__ ((packed)); - -enum p54_tx_data_crypt { - P54_CRYPTO_NONE = 0, - P54_CRYPTO_WEP, - P54_CRYPTO_TKIP, - P54_CRYPTO_TKIPMICHAEL, - P54_CRYPTO_CCX_WEPMIC, - P54_CRYPTO_CCX_KPMIC, - P54_CRYPTO_CCX_KP, - P54_CRYPTO_AESCCMP -}; - -enum p54_tx_data_queue { - P54_QUEUE_BEACON = 0, - P54_QUEUE_FWSCAN = 1, - P54_QUEUE_MGMT = 2, - P54_QUEUE_CAB = 3, - P54_QUEUE_DATA = 4, - - P54_QUEUE_AC_NUM = 4, - P54_QUEUE_AC_VO = 4, - P54_QUEUE_AC_VI = 5, - P54_QUEUE_AC_BE = 6, - P54_QUEUE_AC_BK = 7, - - /* keep last */ - P54_QUEUE_NUM = 8, -}; - -struct p54_tx_data { - u8 rateset[8]; - u8 rts_rate_idx; - u8 crypt_offset; - u8 key_type; - u8 key_len; - u8 key[16]; - u8 hw_queue; - u8 backlog; - __le16 durations[4]; - u8 tx_antenna; - union { - struct { - u8 cts_rate; - __le16 output_power; - } __attribute__((packed)) longbow; - struct { - u8 output_power; - u8 cts_rate; - u8 unalloc; - } __attribute__ ((packed)) normal; - } __attribute__ ((packed)); - u8 unalloc2[2]; - u8 align[0]; -} __attribute__ ((packed)); - -/* unit is ms */ -#define P54_TX_FRAME_LIFETIME 2000 -#define P54_TX_TIMEOUT 4000 -#define P54_STATISTICS_UPDATE 5000 - -#define P54_FILTER_TYPE_NONE 0 -#define P54_FILTER_TYPE_STATION BIT(0) -#define P54_FILTER_TYPE_IBSS BIT(1) -#define P54_FILTER_TYPE_AP BIT(2) -#define P54_FILTER_TYPE_TRANSPARENT BIT(3) -#define P54_FILTER_TYPE_PROMISCUOUS BIT(4) -#define P54_FILTER_TYPE_HIBERNATE BIT(5) -#define P54_FILTER_TYPE_NOACK BIT(6) -#define P54_FILTER_TYPE_RX_DISABLED BIT(7) - -struct p54_setup_mac { - __le16 mac_mode; - u8 mac_addr[ETH_ALEN]; - u8 bssid[ETH_ALEN]; - u8 rx_antenna; - u8 rx_align; - union { - struct { - __le32 basic_rate_mask; - u8 rts_rates[8]; - __le32 rx_addr; - __le16 max_rx; - __le16 rxhw; - __le16 wakeup_timer; - __le16 unalloc0; - } v1 __attribute__ ((packed)); - struct { - __le32 rx_addr; - __le16 max_rx; - __le16 rxhw; - __le16 timer; - __le16 truncate; - __le32 basic_rate_mask; - u8 sbss_offset; - u8 mcast_window; - u8 rx_rssi_threshold; - u8 rx_ed_threshold; - __le32 ref_clock; - __le16 lpf_bandwidth; - __le16 osc_start_delay; - } v2 __attribute__ ((packed)); - } __attribute__ ((packed)); -} __attribute__ ((packed)); - -#define P54_SETUP_V1_LEN 40 -#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac)) - -#define P54_SCAN_EXIT BIT(0) -#define P54_SCAN_TRAP BIT(1) -#define P54_SCAN_ACTIVE BIT(2) -#define P54_SCAN_FILTER BIT(3) - -struct p54_scan_head { - __le16 mode; - __le16 dwell; - u8 scan_params[20]; - __le16 freq; -} __attribute__ ((packed)); - -struct p54_scan_body { - u8 pa_points_per_curve; - u8 val_barker; - u8 val_bpsk; - u8 val_qpsk; - u8 val_16qam; - u8 val_64qam; - struct p54_pa_curve_data_sample curve_data[8]; - u8 dup_bpsk; - u8 dup_qpsk; - u8 dup_16qam; - u8 dup_64qam; -} __attribute__ ((packed)); - -struct p54_scan_body_longbow { - struct p54_channel_output_limit_longbow power_limits; - struct p54_pa_curve_data_sample_longbow curve_data[8]; - __le16 unkn[6]; /* maybe more power_limits or rate_mask */ -} __attribute__ ((packed)); - -union p54_scan_body_union { - struct p54_scan_body normal; - struct p54_scan_body_longbow longbow; -} __attribute__ ((packed)); - -struct p54_scan_tail_rate { - __le32 basic_rate_mask; - u8 rts_rates[8]; -} __attribute__ ((packed)); - -struct p54_led { - __le16 flags; - __le16 mask[2]; - __le16 delay[2]; -} __attribute__ ((packed)); - -struct p54_edcf { - u8 flags; - u8 slottime; - u8 sifs; - u8 eofpad; - struct p54_edcf_queue_param queue[8]; - u8 mapping[4]; - __le16 frameburst; - __le16 round_trip_delay; -} __attribute__ ((packed)); - -struct p54_statistics { - __le32 rx_success; - __le32 rx_bad_fcs; - __le32 rx_abort; - __le32 rx_abort_phy; - __le32 rts_success; - __le32 rts_fail; - __le32 tsf32; - __le32 airtime; - __le32 noise; - __le32 sample_noise[8]; - __le32 sample_cca; - __le32 sample_tx; -} __attribute__ ((packed)); - -struct p54_xbow_synth { - __le16 magic1; - __le16 magic2; - __le16 freq; - u32 padding[5]; -} __attribute__ ((packed)); - -struct p54_timer { - __le32 interval; -} __attribute__ ((packed)); - -struct p54_keycache { - u8 entry; - u8 key_id; - u8 mac[ETH_ALEN]; - u8 padding[2]; - u8 key_type; - u8 key_len; - u8 key[24]; -} __attribute__ ((packed)); - -struct p54_burst { - u8 flags; - u8 queue; - u8 backlog; - u8 pad; - __le16 durations[32]; -} __attribute__ ((packed)); - -struct p54_psm_interval { - __le16 interval; - __le16 periods; -} __attribute__ ((packed)); - -#define P54_PSM_CAM 0 -#define P54_PSM BIT(0) -#define P54_PSM_DTIM BIT(1) -#define P54_PSM_MCBC BIT(2) -#define P54_PSM_CHECKSUM BIT(3) -#define P54_PSM_SKIP_MORE_DATA BIT(4) -#define P54_PSM_BEACON_TIMEOUT BIT(5) -#define P54_PSM_HFOSLEEP BIT(6) -#define P54_PSM_AUTOSWITCH_SLEEP BIT(7) -#define P54_PSM_LPIT BIT(8) -#define P54_PSM_BF_UCAST_SKIP BIT(9) -#define P54_PSM_BF_MCAST_SKIP BIT(10) - -struct p54_psm { - __le16 mode; - __le16 aid; - struct p54_psm_interval intervals[4]; - u8 beacon_rssi_skip_max; - u8 rssi_delta_threshold; - u8 nr; - u8 exclude[1]; -} __attribute__ ((packed)); - -#define MC_FILTER_ADDRESS_NUM 4 - -struct p54_group_address_table { - __le16 filter_enable; - __le16 num_address; - u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN]; -} __attribute__ ((packed)); - -struct p54_txcancel { - __le32 req_id; -} __attribute__ ((packed)); - -struct p54_sta_unlock { - u8 addr[ETH_ALEN]; - u16 padding; -} __attribute__ ((packed)); - -#define P54_TIM_CLEAR BIT(15) -struct p54_tim { - u8 count; - u8 padding[3]; - __le16 entry[8]; -} __attribute__ ((packed)); - -struct p54_cce_quiet { - __le32 period; -} __attribute__ ((packed)); - -struct p54_bt_balancer { - __le16 prio_thresh; - __le16 acl_thresh; -} __attribute__ ((packed)); - -struct p54_arp_table { - __le16 filter_enable; - u8 ipv4_addr[4]; -} __attribute__ ((packed)); - -#endif /* P54COMMON_H */ diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index b1610ea4bb3..d348c265e86 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -22,6 +22,7 @@ #include #include "p54.h" +#include "lmac.h" #include "p54pci.h" MODULE_AUTHOR("Michael Wu "); @@ -564,7 +565,6 @@ static int __devinit p54p_probe(struct pci_dev *pdev, err_free_common: release_firmware(priv->firmware); - p54_free_common(dev); pci_free_consistent(pdev, sizeof(*priv->ring_control), priv->ring_control, priv->ring_control_dma); @@ -573,7 +573,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, err_free_dev: pci_set_drvdata(pdev, NULL); - ieee80211_free_hw(dev); + p54_free_common(dev); err_free_reg: pci_release_regions(pdev); @@ -590,16 +590,15 @@ static void __devexit p54p_remove(struct pci_dev *pdev) if (!dev) return; - ieee80211_unregister_hw(dev); + p54_unregister_common(dev); priv = dev->priv; release_firmware(priv->firmware); pci_free_consistent(pdev, sizeof(*priv->ring_control), priv->ring_control, priv->ring_control_dma); - p54_free_common(dev); iounmap(priv->map); pci_release_regions(pdev); pci_disable_device(pdev); - ieee80211_free_hw(dev); + p54_free_common(dev); } #ifdef CONFIG_PM diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 83116baeb11..7ef191a9d79 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -34,7 +34,7 @@ #include "p54spi_eeprom.h" #include "p54.h" -#include "p54common.h" +#include "lmac.h" MODULE_FIRMWARE("3826.arm"); MODULE_ALIAS("stlc45xx"); @@ -713,7 +713,7 @@ static int __devexit p54spi_remove(struct spi_device *spi) { struct p54s_priv *priv = dev_get_drvdata(&spi->dev); - ieee80211_unregister_hw(priv->hw); + p54_unregister_common(priv->hw); free_irq(gpio_to_irq(p54spi_gpio_irq), spi); @@ -724,7 +724,6 @@ static int __devexit p54spi_remove(struct spi_device *spi) mutex_destroy(&priv->mutex); p54_free_common(priv->hw); - ieee80211_free_hw(priv->hw); return 0; } diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 0e877a104a8..461d88f5ceb 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -22,6 +22,7 @@ #include #include "p54.h" +#include "lmac.h" #include "p54usb.h" MODULE_AUTHOR("Michael Wu "); @@ -961,7 +962,7 @@ err_free_fw: release_firmware(priv->fw); err_free_dev: - ieee80211_free_hw(dev); + p54_free_common(dev); usb_set_intfdata(intf, NULL); usb_put_dev(udev); return err; @@ -975,13 +976,12 @@ static void __devexit p54u_disconnect(struct usb_interface *intf) if (!dev) return; - ieee80211_unregister_hw(dev); + p54_unregister_common(dev); priv = dev->priv; usb_put_dev(interface_to_usbdev(intf)); release_firmware(priv->fw); p54_free_common(dev); - ieee80211_free_hw(dev); } static int p54u_pre_reset(struct usb_interface *intf) -- cgit v1.2.3-18-g5258 From 2664f201ef162224c775ecf7e33aee9c4cac62b0 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Wed, 24 Jun 2009 18:56:39 +0530 Subject: ath9k: remove unnecessary STATION mode check. Remove unncessary STATION mode check in ath9k_bss_assoc_info() as it is called only for STATION mode. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 66a6c1f5022..48cb5534bd1 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -920,24 +920,21 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf) { - struct ath_vif *avp = (void *)vif->drv_priv; if (bss_conf->assoc) { DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n", bss_conf->aid, sc->curbssid); /* New association, store aid */ - if (avp->av_opmode == NL80211_IFTYPE_STATION) { - sc->curaid = bss_conf->aid; - ath9k_hw_write_associd(sc); + sc->curaid = bss_conf->aid; + ath9k_hw_write_associd(sc); - /* - * Request a re-configuration of Beacon related timers - * on the receipt of the first Beacon frame (i.e., - * after time sync with the AP). - */ - sc->sc_flags |= SC_OP_BEACON_SYNC; - } + /* + * Request a re-configuration of Beacon related timers + * on the receipt of the first Beacon frame (i.e., + * after time sync with the AP). + */ + sc->sc_flags |= SC_OP_BEACON_SYNC; /* Configure the beacon */ ath_beacon_config(sc, vif); -- cgit v1.2.3-18-g5258 From f38faa31e0da07390d72fb67d3151e56c54871f4 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Wed, 24 Jun 2009 18:56:40 +0530 Subject: ath9k: stop ani when the STA gets disconnected. ANI is not required when the STA is disconnected. So stop it and enable ANI for adhoc and monitor mode. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 48cb5534bd1..6d63126a81f 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -949,6 +949,8 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, } else { DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); sc->curaid = 0; + /* Stop ANI */ + del_timer_sync(&sc->ani.timer); } } @@ -2193,7 +2195,9 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); - if (conf->type == NL80211_IFTYPE_AP) + if (conf->type == NL80211_IFTYPE_AP || + conf->type == NL80211_IFTYPE_ADHOC || + conf->type == NL80211_IFTYPE_MONITOR) ath_start_ani(sc); out: -- cgit v1.2.3-18-g5258 From e5f0921a9593365b506f69daa3cfd19c0ed1340b Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Wed, 24 Jun 2009 18:56:41 +0530 Subject: ath9k: race condition in SCANNING state check during ANI calibration ANI calibration shouldn't be done when we are not on our home channel. This is already verified. However, it is racy. Fix this by proper spin locks. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/main.c | 11 +++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 747e046b03b..eb9d5228cb6 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -540,6 +540,7 @@ struct ath_softc { int irq; spinlock_t sc_resetlock; spinlock_t sc_serial_rw; + spinlock_t ani_lock; struct mutex mutex; u8 curbssid[ETH_ALEN]; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 6d63126a81f..52dfa43bc52 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -342,6 +342,7 @@ static void ath_ani_calibrate(unsigned long data) * don't calibrate when we're scanning. * we are most likely not on our home channel. */ + spin_lock(&sc->ani_lock); if (sc->sc_flags & SC_OP_SCANNING) goto set_timer; @@ -405,6 +406,7 @@ static void ath_ani_calibrate(unsigned long data) ath9k_ps_restore(sc); set_timer: + spin_unlock(&sc->ani_lock); /* * Set timer interval based on previous results. * The interval must be the shortest necessary to satisfy ANI, @@ -1310,6 +1312,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) spin_lock_init(&sc->wiphy_lock); spin_lock_init(&sc->sc_resetlock); spin_lock_init(&sc->sc_serial_rw); + spin_lock_init(&sc->ani_lock); mutex_init(&sc->mutex); tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, @@ -2682,9 +2685,9 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw) aphy->state = ATH_WIPHY_SCAN; ath9k_wiphy_pause_all_forced(sc, aphy); - mutex_lock(&sc->mutex); + spin_lock_bh(&sc->ani_lock); sc->sc_flags |= SC_OP_SCANNING; - mutex_unlock(&sc->mutex); + spin_unlock_bh(&sc->ani_lock); } static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) @@ -2692,11 +2695,11 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - mutex_lock(&sc->mutex); + spin_lock_bh(&sc->ani_lock); aphy->state = ATH_WIPHY_ACTIVE; sc->sc_flags &= ~SC_OP_SCANNING; sc->sc_flags |= SC_OP_FULL_RESET; - mutex_unlock(&sc->mutex); + spin_unlock_bh(&sc->ani_lock); } struct ieee80211_ops ath9k_ops = { -- cgit v1.2.3-18-g5258 From 140add21356528fc76ad276fd32b2e7abb945325 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Wed, 24 Jun 2009 18:56:42 +0530 Subject: ath9k: Handle different TX and RX streams properly. This patch fixes an issue when the TX and RX streams are different. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 52dfa43bc52..961b0ce6ef3 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -889,6 +889,7 @@ static void setup_ht_cap(struct ath_softc *sc, { #define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */ #define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */ + u8 tx_streams, rx_streams; ht_info->ht_supported = true; ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | @@ -901,21 +902,22 @@ static void setup_ht_cap(struct ath_softc *sc, /* set up supported mcs set */ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + tx_streams = !(sc->tx_chainmask & (sc->tx_chainmask - 1)) ? 1 : 2; + rx_streams = !(sc->rx_chainmask & (sc->rx_chainmask - 1)) ? 1 : 2; - switch(sc->rx_chainmask) { - case 1: - ht_info->mcs.rx_mask[0] = 0xff; - break; - case 3: - case 5: - case 7: - default: - ht_info->mcs.rx_mask[0] = 0xff; - ht_info->mcs.rx_mask[1] = 0xff; - break; + if (tx_streams != rx_streams) { + DPRINTF(sc, ATH_DBG_CONFIG, "TX streams %d, RX streams: %d\n", + tx_streams, rx_streams); + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; + ht_info->mcs.tx_params |= ((tx_streams - 1) << + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); } - ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + ht_info->mcs.rx_mask[0] = 0xff; + if (rx_streams >= 2) + ht_info->mcs.rx_mask[1] = 0xff; + + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; } static void ath9k_bss_assoc_info(struct ath_softc *sc, -- cgit v1.2.3-18-g5258 From 8ab0ea77273ecf97d26cf8ca026ef383098577fb Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 24 Jun 2009 22:13:27 -0700 Subject: drivers/net/wireless: Use PCI_VDEVICE Signed-off-by: Joe Perches Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2200.c | 10 +++++----- drivers/net/wireless/prism54/islpci_hotplug.c | 4 +--- 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 44c29b3f672..d726b3c6077 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -11436,11 +11436,11 @@ static struct pci_device_id card_ids[] = { {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2754, 0, 0, 0}, {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2761, 0, 0, 0}, {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x104f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, 0x4220, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */ - {PCI_VENDOR_ID_INTEL, 0x4221, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */ - {PCI_VENDOR_ID_INTEL, 0x4223, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */ - {PCI_VENDOR_ID_INTEL, 0x4224, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */ + {PCI_VDEVICE(INTEL, 0x104f), 0}, + {PCI_VDEVICE(INTEL, 0x4220), 0}, /* BG */ + {PCI_VDEVICE(INTEL, 0x4221), 0}, /* BG */ + {PCI_VDEVICE(INTEL, 0x4223), 0}, /* ABG */ + {PCI_VDEVICE(INTEL, 0x4224), 0}, /* ABG */ /* required last entry */ {0,} diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c index 30876728d7e..83d366258c8 100644 --- a/drivers/net/wireless/prism54/islpci_hotplug.c +++ b/drivers/net/wireless/prism54/islpci_hotplug.c @@ -49,9 +49,7 @@ static const struct pci_device_id prism54_id_tbl[] = { /* 3COM 3CRWE154G72 Wireless LAN adapter */ { - 0x10b7, 0x6001, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, 0 + PCI_VDEVICE(3COM, 0x6001), 0 }, /* Intersil PRISM Indigo Wireless LAN adapter */ -- cgit v1.2.3-18-g5258 From dd13fd649879b6230be5d855e00c286c5e60f354 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 25 Jun 2009 18:28:30 +0800 Subject: iwmc3200wifi: replace netif_rx with netif_rx_ni The patch uses netif_rx_ni() over netif_rx() to post buffers to upper network code because it is always scheduled in a workqueue. The problem was first observed from a dynamic ticks warning: "NOHZ: local_softirq_pending ..." Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 55871da695a..5d2239f59bc 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -1373,7 +1373,7 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm, ndev->stats.rx_packets++; ndev->stats.rx_bytes += skb->len; - if (netif_rx(skb) == NET_RX_DROP) { + if (netif_rx_ni(skb) == NET_RX_DROP) { IWM_ERR(iwm, "Packet dropped\n"); ndev->stats.rx_dropped++; } -- cgit v1.2.3-18-g5258 From fd2c7fe0b4dedc34ea0a2a72e00648bd2b8c7c3a Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 25 Jun 2009 18:28:31 +0800 Subject: iwmc3200wifi: simplify calibration map The patch simplifies calibration map by combining the init_calib_map and periodic_calib_map into one calib_map in struct iwm_conf. Now the initial calibration map is stored in the lower 16 bits of calib_map and the periodic calibration map is stored in the higher 16 bits. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/fw.c | 19 +++++++++++-------- drivers/net/wireless/iwmc3200wifi/iwm.h | 3 +-- drivers/net/wireless/iwmc3200wifi/lmac.h | 4 ++++ drivers/net/wireless/iwmc3200wifi/main.c | 6 +----- 4 files changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c index ec1a15a5a0e..c58f614ce6d 100644 --- a/drivers/net/wireless/iwmc3200wifi/fw.c +++ b/drivers/net/wireless/iwmc3200wifi/fw.c @@ -275,6 +275,7 @@ static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name) */ int iwm_load_fw(struct iwm_priv *iwm) { + unsigned long init_calib_map, periodic_calib_map; int ret; /* We first start downloading the UMAC */ @@ -315,23 +316,25 @@ int iwm_load_fw(struct iwm_priv *iwm) return ret; } + init_calib_map = iwm->conf.calib_map & IWM_CALIB_MAP_INIT_MSK; + periodic_calib_map = IWM_CALIB_MAP_PER_LMAC(iwm->conf.calib_map); + #ifdef CONFIG_IWM_B0_HW_SUPPORT if (iwm->conf.hw_b0) { - clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map); - clear_bit(PHY_CALIBRATE_RX_IQ_CMD, - &iwm->conf.periodic_calib_map); + clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &init_calib_map); + clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &periodic_calib_map); } #endif /* Read RX IQ calibration result from EEPROM */ - if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map)) { + if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &init_calib_map)) { iwm_store_rxiq_calib_result(iwm); set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map); } iwm_send_prio_table(iwm); - iwm_send_init_calib_cfg(iwm, iwm->conf.init_calib_map); + iwm_send_init_calib_cfg(iwm, init_calib_map); - while (iwm->calib_done_map != iwm->conf.init_calib_map) { + while (iwm->calib_done_map != init_calib_map) { ret = iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION, IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT); if (ret) { @@ -340,7 +343,7 @@ int iwm_load_fw(struct iwm_priv *iwm) } IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: " "0x%lx, requested calibrations: 0x%lx\n", - iwm->calib_done_map, iwm->conf.init_calib_map); + iwm->calib_done_map, init_calib_map); } /* Handle LMAC CALIBRATION_COMPLETE notification */ @@ -378,7 +381,7 @@ int iwm_load_fw(struct iwm_priv *iwm) iwm_send_prio_table(iwm); iwm_send_calib_results(iwm); - iwm_send_periodic_calib_cfg(iwm, iwm->conf.periodic_calib_map); + iwm_send_periodic_calib_cfg(iwm, periodic_calib_map); return 0; diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 4da57f737f2..1bad78f8135 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -65,8 +65,7 @@ struct iwm_conf { u32 sdio_ior_timeout; - unsigned long init_calib_map; - unsigned long periodic_calib_map; + unsigned long calib_map; bool reset_on_fatal_err; bool auto_connect; bool wimax_not_present; diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h index db2e5eea189..19213e165f5 100644 --- a/drivers/net/wireless/iwmc3200wifi/lmac.h +++ b/drivers/net/wireless/iwmc3200wifi/lmac.h @@ -396,6 +396,10 @@ enum { CALIBRATION_CMD_NUM, }; +#define IWM_CALIB_MAP_INIT_MSK 0xFFFF +#define IWM_CALIB_MAP_PER_LMAC(m) ((m & 0xFF0000) >> 16) +#define IWM_CALIB_MAP_PER_UMAC(m) ((m & 0xFF000000) >> 24) + struct iwm_lmac_calib_hdr { u8 opcode; u8 first_grp; diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 930056b013f..4fedb45d62b 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -53,11 +53,7 @@ static struct iwm_conf def_iwm_conf = { .sdio_ior_timeout = 5000, - .init_calib_map = BIT(PHY_CALIBRATE_DC_CMD) | - BIT(PHY_CALIBRATE_LO_CMD) | - BIT(PHY_CALIBRATE_TX_IQ_CMD) | - BIT(PHY_CALIBRATE_RX_IQ_CMD), - .periodic_calib_map = BIT(PHY_CALIBRATE_DC_CMD) | + .calib_map = BIT(PHY_CALIBRATE_DC_CMD) | BIT(PHY_CALIBRATE_LO_CMD) | BIT(PHY_CALIBRATE_TX_IQ_CMD) | BIT(PHY_CALIBRATE_RX_IQ_CMD) | -- cgit v1.2.3-18-g5258 From 19a42803f310ff60ce5a6c02992762068a01394a Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 25 Jun 2009 18:28:32 +0800 Subject: iwmc3200wifi: remove B0 hardware support The patch removes B0 hardware support. Nobody is using it anyway. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/eeprom.c | 4 ---- drivers/net/wireless/iwmc3200wifi/fw.c | 6 ------ drivers/net/wireless/iwmc3200wifi/iwm.h | 5 ----- drivers/net/wireless/iwmc3200wifi/main.c | 7 ------- drivers/net/wireless/iwmc3200wifi/rx.c | 7 ------- 5 files changed, 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.c b/drivers/net/wireless/iwmc3200wifi/eeprom.c index 0f34b84fd2e..365910fbe01 100644 --- a/drivers/net/wireless/iwmc3200wifi/eeprom.c +++ b/drivers/net/wireless/iwmc3200wifi/eeprom.c @@ -156,10 +156,6 @@ int iwm_eeprom_init(struct iwm_priv *iwm) return -ENOMEM; for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) { -#ifdef CONFIG_IWM_B0_HW_SUPPORT - if (iwm->conf.hw_b0 && (i >= IWM_EEPROM_INDIRECT_OFFSET)) - break; -#endif ret = iwm_eeprom_read(iwm, i); if (ret < 0) { IWM_ERR(iwm, "Couldn't read eeprom entry #%d: %s\n", diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c index c58f614ce6d..0f32cab9ced 100644 --- a/drivers/net/wireless/iwmc3200wifi/fw.c +++ b/drivers/net/wireless/iwmc3200wifi/fw.c @@ -319,12 +319,6 @@ int iwm_load_fw(struct iwm_priv *iwm) init_calib_map = iwm->conf.calib_map & IWM_CALIB_MAP_INIT_MSK; periodic_calib_map = IWM_CALIB_MAP_PER_LMAC(iwm->conf.calib_map); -#ifdef CONFIG_IWM_B0_HW_SUPPORT - if (iwm->conf.hw_b0) { - clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &init_calib_map); - clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &periodic_calib_map); - } -#endif /* Read RX IQ calibration result from EEPROM */ if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &init_calib_map)) { iwm_store_rxiq_calib_result(iwm); diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 1bad78f8135..79d9d89d47a 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -52,8 +52,6 @@ #define IWM_COPYRIGHT "Copyright(c) 2009 Intel Corporation" #define IWM_AUTHOR "" -#define CONFIG_IWM_B0_HW_SUPPORT 1 - #define IWM_SRC_LMAC UMAC_HDI_IN_SOURCE_FHRX #define IWM_SRC_UDMA UMAC_HDI_IN_SOURCE_UDMA #define IWM_SRC_UMAC UMAC_HDI_IN_SOURCE_FW @@ -86,9 +84,6 @@ struct iwm_conf { u8 ibss_channel; u8 mac_addr[ETH_ALEN]; -#ifdef CONFIG_IWM_B0_HW_SUPPORT - bool hw_b0; -#endif }; enum { diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 4fedb45d62b..484f110151b 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -515,13 +515,6 @@ static int iwm_channels_init(struct iwm_priv *iwm) { int ret; -#ifdef CONFIG_IWM_B0_HW_SUPPORT - if (iwm->conf.hw_b0) { - IWM_INFO(iwm, "Workaround EEPROM channels for B0 hardware\n"); - return 0; - } -#endif - ret = iwm_send_umac_channel_list(iwm); if (ret) { IWM_ERR(iwm, "Send channel list failed\n"); diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 5d2239f59bc..3909477fb3b 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -924,13 +924,6 @@ static int iwm_ntf_eeprom_proxy(struct iwm_priv *iwm, u8 *buf, if ((hdr_offset + hdr_len) > IWM_EEPROM_LEN) return -EINVAL; -#ifdef CONFIG_IWM_B0_HW_SUPPORT - if (hdr_offset == IWM_EEPROM_SKU_CAP_OFF) { - if (eeprom_proxy->buf[0] == 0xff) - iwm->conf.hw_b0 = 1; - } -#endif - switch (hdr_type) { case IWM_UMAC_CMD_EEPROM_TYPE_READ: memcpy(iwm->eeprom + hdr_offset, eeprom_proxy->buf, hdr_len); -- cgit v1.2.3-18-g5258 From f55e668f902e40a5299deb8cc5940d1d24b19ea0 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 26 Jun 2009 11:00:53 -0700 Subject: iwlagn: re-enable PS support for iwlagn The register locking rework addressed the problem where nic access was obtained incorrectly when PS is enabled. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 7e528a0a15e..d5cd9a20edc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1382,7 +1382,8 @@ int iwl_setup_mac(struct iwl_priv *priv) hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM | IEEE80211_HW_AMPDU_AGGREGATION | - IEEE80211_HW_SPECTRUM_MGMT; + IEEE80211_HW_SPECTRUM_MGMT | + IEEE80211_HW_SUPPORTS_PS; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); -- cgit v1.2.3-18-g5258 From 68021b966b3cb363596251bac0370c12e084e7da Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 26 Jun 2009 11:00:54 -0700 Subject: iwlwifi: add utility to print buffer when error occurs Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debug.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 2cf014f523b..65bbce0f171 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -36,6 +36,12 @@ struct iwl_priv; #define IWL_INFO(p, f, a...) dev_info(&((p)->pci_dev->dev), f, ## a) #define IWL_CRIT(p, f, a...) dev_crit(&((p)->pci_dev->dev), f, ## a) +#define iwl_print_hex_error(priv, p, len) \ +do { \ + print_hex_dump(KERN_ERR, "iwl data: ", \ + DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ +} while (0) + #ifdef CONFIG_IWLWIFI_DEBUG #define IWL_DEBUG(__priv, level, fmt, args...) \ do { \ -- cgit v1.2.3-18-g5258 From 7ac487260e087f1660e856d4afae2dd49774f66b Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 26 Jun 2009 11:00:55 -0700 Subject: iwlwifi: always print buffer when error condition occurs We want to see the buffer contents when the error occurs without needing to set any debug flags. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index b35c1fd2cb2..753fca32d9d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1109,7 +1109,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) txq_id, sequence, priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr, priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) { - iwl_print_hex_dump(priv, IWL_DL_INFO , rxb, 32); + iwl_print_hex_error(priv, rxb, 32); return; } -- cgit v1.2.3-18-g5258 From 6badaaf7729e5d1c02934b1739303ce79014ab67 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 28 Jun 2009 09:26:32 -0700 Subject: drivers/net/wireless/ath/ath9k: Remove unnecessary semicolons Signed-off-by: Joe Perches Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom.c | 2 -- drivers/net/wireless/ath/ath9k/hw.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index a2fda702b62..d82a0f97e6f 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -2516,10 +2516,8 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, targetPowerCck.tPow2x[1]; ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; - ; ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3]; - ; } if (IS_CHAN_HT40(chan)) { for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 34935a8ee59..cffb0789f66 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2345,7 +2345,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_init_bb(ah, chan); if (!ath9k_hw_init_cal(ah, chan)) - return -EIO;; + return -EIO; rx_chainmask = ah->rxchainmask; if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) { -- cgit v1.2.3-18-g5258 From 31670070ffe18f8e8743109b19297a0efac0a72c Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Sun, 28 Jun 2009 23:25:27 +0200 Subject: ath5k: remove permissions from debugfs files Don't allow users to open debugfs files, because it can cause oopses. When a user opens some file, driver unlinks it and frees the corresponding structure, we will dereference freed memory. Signed-off-by: Jiri Slaby Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/debug.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index 4904a07e4b5..747508c15d3 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -380,13 +380,15 @@ ath5k_debug_init_device(struct ath5k_softc *sc) sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy), ath5k_global_debugfs); - sc->debug.debugfs_debug = debugfs_create_file("debug", S_IWUSR | S_IRUGO, + sc->debug.debugfs_debug = debugfs_create_file("debug", + S_IWUSR | S_IRUSR, sc->debug.debugfs_phydir, sc, &fops_debug); - sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUGO, + sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUSR, sc->debug.debugfs_phydir, sc, &fops_registers); - sc->debug.debugfs_beacon = debugfs_create_file("beacon", S_IWUSR | S_IRUGO, + sc->debug.debugfs_beacon = debugfs_create_file("beacon", + S_IWUSR | S_IRUSR, sc->debug.debugfs_phydir, sc, &fops_beacon); sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR, -- cgit v1.2.3-18-g5258 From 9d49e861a5e31fb7f575f348743886189045e102 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Sun, 28 Jun 2009 23:25:28 +0200 Subject: ath9k: remove permissions from debugfs files Don't allow users to open debugfs files, because it can cause oopses. When a user opens some file, driver unlinks it and frees the corresponding structure, we will dereference freed memory. Signed-off-by: Jiri Slaby Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 6d20725d645..9f99f00c144 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -500,31 +500,31 @@ int ath9k_init_debug(struct ath_softc *sc) goto err; sc->debug.debugfs_debug = debugfs_create_file("debug", - S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug); + S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug); if (!sc->debug.debugfs_debug) goto err; - sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO, + sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_dma); if (!sc->debug.debugfs_dma) goto err; sc->debug.debugfs_interrupt = debugfs_create_file("interrupt", - S_IRUGO, + S_IRUSR, sc->debug.debugfs_phy, sc, &fops_interrupt); if (!sc->debug.debugfs_interrupt) goto err; sc->debug.debugfs_rcstat = debugfs_create_file("rcstat", - S_IRUGO, + S_IRUSR, sc->debug.debugfs_phy, sc, &fops_rcstat); if (!sc->debug.debugfs_rcstat) goto err; sc->debug.debugfs_wiphy = debugfs_create_file( - "wiphy", S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, + "wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_wiphy); if (!sc->debug.debugfs_wiphy) goto err; -- cgit v1.2.3-18-g5258 From b623a9f7c488e51dbe4320d8b5cdd0ba242d0067 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 14:57:59 +0200 Subject: iwlwifi: fix aggregation limit According to the documentation, the limit is 0x3f == 63, not 64. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 6e9b8a8356e..ebb2fbce536 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1924,7 +1924,7 @@ struct iwl_link_qual_general_params { #define LINK_QUAL_AGG_DISABLE_START_MIN (0) #define LINK_QUAL_AGG_FRAME_LIMIT_DEF (31) -#define LINK_QUAL_AGG_FRAME_LIMIT_MAX (64) +#define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63) #define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) /** -- cgit v1.2.3-18-g5258 From e47a5cddf893815e7da16e3226b959af785d8aaf Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 1 Jul 2009 15:17:35 +0200 Subject: rt2x00: use wiphy rfkill interface Remove the input_polldev from rt2x00 and replace it with the rfkill interface offered by the wiphy structure. This simplifies the entire rfkill handling in rt2x00 and allows us to remove the CONFIG_RT2X00_LIB_RFKILL option and always enables rfkill capabilities. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/Kconfig | 8 -- drivers/net/wireless/rt2x00/Makefile | 1 - drivers/net/wireless/rt2x00/rt2400pci.c | 7 +- drivers/net/wireless/rt2x00/rt2500pci.c | 7 +- drivers/net/wireless/rt2x00/rt2500usb.c | 7 +- drivers/net/wireless/rt2x00/rt2800usb.c | 7 +- drivers/net/wireless/rt2x00/rt2x00.h | 13 +-- drivers/net/wireless/rt2x00/rt2x00dev.c | 2 - drivers/net/wireless/rt2x00/rt2x00lib.h | 21 +---- drivers/net/wireless/rt2x00/rt2x00mac.c | 9 ++ drivers/net/wireless/rt2x00/rt2x00rfkill.c | 127 ----------------------------- drivers/net/wireless/rt2x00/rt61pci.c | 7 +- drivers/net/wireless/rt2x00/rt73usb.c | 7 +- 13 files changed, 20 insertions(+), 203 deletions(-) delete mode 100644 drivers/net/wireless/rt2x00/rt2x00rfkill.c (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 8aab3e6754b..f970aa25326 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -112,14 +112,6 @@ config RT2X00_LIB_FIRMWARE config RT2X00_LIB_CRYPTO boolean -config RT2X00_LIB_RFKILL - boolean - default y if (RT2X00_LIB=y && INPUT=y) || (RT2X00_LIB=m && INPUT!=n) - select INPUT_POLLDEV - -comment "rt2x00 rfkill support disabled due to modularized INPUT and built-in rt2x00" - depends on RT2X00_LIB=y && INPUT=m - config RT2X00_LIB_LEDS boolean default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n) diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile index bfc7226f0af..13043ea9766 100644 --- a/drivers/net/wireless/rt2x00/Makefile +++ b/drivers/net/wireless/rt2x00/Makefile @@ -5,7 +5,6 @@ rt2x00lib-y += rt2x00queue.o rt2x00lib-y += rt2x00link.o rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS) += rt2x00debug.o rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o -rt2x00lib-$(CONFIG_RT2X00_LIB_RFKILL) += rt2x00rfkill.o rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o rt2x00lib-$(CONFIG_RT2X00_LIB_HT) += rt2x00ht.o diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 435f945fe64..d8035e3575e 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -199,7 +199,6 @@ static const struct rt2x00debug rt2400pci_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT2X00_LIB_RFKILL static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -207,9 +206,6 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_read(rt2x00dev, GPIOCSR, ®); return rt2x00_get_field32(reg, GPIOCSR_BIT0); } -#else -#define rt2400pci_rfkill_poll NULL -#endif /* CONFIG_RT2X00_LIB_RFKILL */ #ifdef CONFIG_RT2X00_LIB_LEDS static void rt2400pci_brightness_set(struct led_classdev *led_cdev, @@ -1391,10 +1387,8 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ -#ifdef CONFIG_RT2X00_LIB_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); -#endif /* CONFIG_RT2X00_LIB_RFKILL */ /* * Check if the BBP tuning should be enabled. @@ -1573,6 +1567,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt2400pci_get_tsf, .tx_last_beacon = rt2400pci_tx_last_beacon, + .rfkill_poll = rt2x00mac_rfkill_poll, }; static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 08b30d01e67..c123e28396d 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -199,7 +199,6 @@ static const struct rt2x00debug rt2500pci_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT2X00_LIB_RFKILL static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -207,9 +206,6 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_read(rt2x00dev, GPIOCSR, ®); return rt2x00_get_field32(reg, GPIOCSR_BIT0); } -#else -#define rt2500pci_rfkill_poll NULL -#endif /* CONFIG_RT2X00_LIB_RFKILL */ #ifdef CONFIG_RT2X00_LIB_LEDS static void rt2500pci_brightness_set(struct led_classdev *led_cdev, @@ -1548,10 +1544,8 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ -#ifdef CONFIG_RT2X00_LIB_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); -#endif /* CONFIG_RT2X00_LIB_RFKILL */ /* * Check if the BBP tuning should be enabled. @@ -1872,6 +1866,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt2500pci_get_tsf, .tx_last_beacon = rt2500pci_tx_last_beacon, + .rfkill_poll = rt2x00mac_rfkill_poll, }; static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 66daf68ff0e..795706d63b9 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -277,7 +277,6 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT2X00_LIB_RFKILL static int rt2500usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u16 reg; @@ -285,9 +284,6 @@ static int rt2500usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) rt2500usb_register_read(rt2x00dev, MAC_CSR19, ®); return rt2x00_get_field32(reg, MAC_CSR19_BIT7); } -#else -#define rt2500usb_rfkill_poll NULL -#endif /* CONFIG_RT2X00_LIB_RFKILL */ #ifdef CONFIG_RT2X00_LIB_LEDS static void rt2500usb_brightness_set(struct led_classdev *led_cdev, @@ -1601,10 +1597,8 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ -#ifdef CONFIG_RT2X00_LIB_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); -#endif /* CONFIG_RT2X00_LIB_RFKILL */ /* * Check if the BBP tuning should be disabled. @@ -1905,6 +1899,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, + .rfkill_poll = rt2x00mac_rfkill_poll, }; static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 37561667925..a204e66753c 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -264,7 +264,6 @@ static const struct rt2x00debug rt2800usb_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT2X00_LIB_RFKILL static int rt2800usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -272,9 +271,6 @@ static int rt2800usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) rt2x00usb_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2); } -#else -#define rt2800usb_rfkill_poll NULL -#endif /* CONFIG_RT2X00_LIB_RFKILL */ #ifdef CONFIG_RT2X00_LIB_LEDS static void rt2800usb_brightness_set(struct led_classdev *led_cdev, @@ -2385,10 +2381,8 @@ static int rt2800usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ -#ifdef CONFIG_RT2X00_LIB_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); -#endif /* CONFIG_RT2X00_LIB_RFKILL */ /* * Store led settings, for correct led behaviour. @@ -2800,6 +2794,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = { .conf_tx = rt2800usb_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt2800usb_get_tsf, + .rfkill_poll = rt2x00mac_rfkill_poll, }; static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index a498dde024e..71f37cb476b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -650,18 +650,6 @@ struct rt2x00_dev { struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; enum ieee80211_band curr_band; - /* - * rfkill structure for RF state switching support. - * This will only be compiled in when required. - */ -#ifdef CONFIG_RT2X00_LIB_RFKILL - unsigned long rfkill_state; -#define RFKILL_STATE_ALLOCATED 1 -#define RFKILL_STATE_REGISTERED 2 -#define RFKILL_STATE_BLOCKED 3 - struct input_polled_dev *rfkill_poll_dev; -#endif /* CONFIG_RT2X00_LIB_RFKILL */ - /* * If enabled, the debugfs interface structures * required for deregistration of debugfs. @@ -992,6 +980,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, u32 changes); int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); +void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw); /* * Driver allocation handlers. diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 41e33798adb..4fff3a83f7d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -871,7 +871,6 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) */ rt2x00link_register(rt2x00dev); rt2x00leds_register(rt2x00dev); - rt2x00rfkill_allocate(rt2x00dev); rt2x00debug_register(rt2x00dev); set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); @@ -903,7 +902,6 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) * Free extra components */ rt2x00debug_deregister(rt2x00dev); - rt2x00rfkill_free(rt2x00dev); rt2x00leds_unregister(rt2x00dev); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 0bf2715fa93..512fa2bc3a1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -30,10 +30,8 @@ /* * Interval defines - * Both the link tuner as the rfkill will be called once per second. */ #define LINK_TUNE_INTERVAL round_jiffies_relative(HZ) -#define RFKILL_POLL_INTERVAL 1000 /* * rt2x00_rate: Per rate device information @@ -386,29 +384,18 @@ static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, /* * RFkill handlers. */ -#ifdef CONFIG_RT2X00_LIB_RFKILL -void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev); -void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev); -void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev); -void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev); -#else static inline void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) { + if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + wiphy_rfkill_start_polling(rt2x00dev->hw->wiphy); } static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) { + if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + wiphy_rfkill_stop_polling(rt2x00dev->hw->wiphy); } -static inline void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) -{ -} - -static inline void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) -{ -} -#endif /* CONFIG_RT2X00_LIB_RFKILL */ - /* * LED handlers */ diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 475a3ed7646..b7e0ddda38f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -688,3 +688,12 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, return 0; } EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx); + +void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + bool blocked = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev); + + wiphy_rfkill_set_hw_state(hw->wiphy, blocked); +} +EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll); diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c deleted file mode 100644 index b6d4c6700bf..00000000000 --- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project - - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - Module: rt2x00rfkill - Abstract: rt2x00 rfkill routines. - */ - -#include -#include - -#include "rt2x00.h" -#include "rt2x00lib.h" - -static void rt2x00rfkill_poll(struct input_polled_dev *poll_dev) -{ - struct rt2x00_dev *rt2x00dev = poll_dev->private; - int state, old_state; - - if (!test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state) || - !test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) - return; - - /* - * Poll latest state, if the state is different then the previous state, - * we should generate an input event. - */ - state = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev); - old_state = !!test_bit(RFKILL_STATE_BLOCKED, &rt2x00dev->rfkill_state); - - if (old_state != state) { - input_report_switch(poll_dev->input, SW_RFKILL_ALL, state); - change_bit(RFKILL_STATE_BLOCKED, &rt2x00dev->rfkill_state); - } -} - -void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) -{ - if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) || - test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) - return; - - if (input_register_polled_device(rt2x00dev->rfkill_poll_dev)) { - ERROR(rt2x00dev, "Failed to register polled device.\n"); - return; - } - - __set_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state); - - /* - * Force initial poll which will detect the initial device state, - * and correctly sends the signal to the input layer about this - * state. - */ - rt2x00rfkill_poll(rt2x00dev->rfkill_poll_dev); -} - -void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) -{ - if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) || - !test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) - return; - - input_unregister_polled_device(rt2x00dev->rfkill_poll_dev); - - __clear_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state); -} - -void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) -{ - struct input_polled_dev *poll_dev; - - if (test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) || - !test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) - return; - - poll_dev = input_allocate_polled_device(); - if (!poll_dev) { - ERROR(rt2x00dev, "Failed to allocate polled device.\n"); - return; - } - - poll_dev->private = rt2x00dev; - poll_dev->poll = rt2x00rfkill_poll; - poll_dev->poll_interval = RFKILL_POLL_INTERVAL; - - poll_dev->input->name = rt2x00dev->ops->name; - poll_dev->input->phys = wiphy_name(rt2x00dev->hw->wiphy); - poll_dev->input->id.bustype = BUS_HOST; - poll_dev->input->id.vendor = 0x1814; - poll_dev->input->id.product = rt2x00dev->chip.rt; - poll_dev->input->id.version = rt2x00dev->chip.rev; - poll_dev->input->dev.parent = wiphy_dev(rt2x00dev->hw->wiphy); - poll_dev->input->evbit[0] = BIT(EV_SW); - poll_dev->input->swbit[0] = BIT(SW_RFKILL_ALL); - - rt2x00dev->rfkill_poll_dev = poll_dev; - - __set_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state); -} - -void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) -{ - if (!__test_and_clear_bit(RFKILL_STATE_ALLOCATED, - &rt2x00dev->rfkill_state)) - return; - - input_free_polled_device(rt2x00dev->rfkill_poll_dev); - rt2x00dev->rfkill_poll_dev = NULL; -} diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 49b29ff90c4..8a49d99df68 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -237,7 +237,6 @@ static const struct rt2x00debug rt61pci_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT2X00_LIB_RFKILL static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -245,9 +244,6 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_read(rt2x00dev, MAC_CSR13, ®); return rt2x00_get_field32(reg, MAC_CSR13_BIT5); } -#else -#define rt61pci_rfkill_poll NULL -#endif /* CONFIG_RT2X00_LIB_RFKILL */ #ifdef CONFIG_RT2X00_LIB_LEDS static void rt61pci_brightness_set(struct led_classdev *led_cdev, @@ -2338,10 +2334,8 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ -#ifdef CONFIG_RT2X00_LIB_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); -#endif /* CONFIG_RT2X00_LIB_RFKILL */ /* * Read frequency offset and RF programming sequence. @@ -2728,6 +2722,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .conf_tx = rt61pci_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt61pci_get_tsf, + .rfkill_poll = rt2x00mac_rfkill_poll, }; static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index c18848836f2..ad2898ca867 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -183,7 +183,6 @@ static const struct rt2x00debug rt73usb_rt2x00debug = { }; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -#ifdef CONFIG_RT2X00_LIB_RFKILL static int rt73usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -191,9 +190,6 @@ static int rt73usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) rt2x00usb_register_read(rt2x00dev, MAC_CSR13, ®); return rt2x00_get_field32(reg, MAC_CSR13_BIT7); } -#else -#define rt73usb_rfkill_poll NULL -#endif /* CONFIG_RT2X00_LIB_RFKILL */ #ifdef CONFIG_RT2X00_LIB_LEDS static void rt73usb_brightness_set(struct led_classdev *led_cdev, @@ -1863,10 +1859,8 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ -#ifdef CONFIG_RT2X00_LIB_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); -#endif /* CONFIG_RT2X00_LIB_RFKILL */ /* * Read frequency offset. @@ -2253,6 +2247,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .conf_tx = rt73usb_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt73usb_get_tsf, + .rfkill_poll = rt2x00mac_rfkill_poll, }; static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { -- cgit v1.2.3-18-g5258 From a7eee06b874a02e2de75727ab21a8747ca6309ff Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 3 Jul 2009 21:01:15 +0200 Subject: p54: two endian fixes This patch fixes all CHECK_ENDIAN complains: 1. p54/fwio.c:296:6: warning: restricted __le32 degrades to integer p54/fwio.c:296:6: warning: restricted __le32 degrades to integer 2. p54/p54spi.c:172:32: warning: incorrect type in initializer p54spi.c:172:32: expected restricted __le32 [usertype] buffer p54/p54spi.c:172:32: got unsigned int Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/fwio.c | 3 ++- drivers/net/wireless/p54/p54spi.c | 11 +++++------ 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index 178efbce461..dc4f3f5ee0c 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c @@ -292,8 +292,9 @@ int p54_tx_cancel(struct p54_common *priv, __le32 req_id) { struct sk_buff *skb; struct p54_txcancel *cancel; + u32 _req_id = le32_to_cpu(req_id); - if (unlikely(req_id < priv->rx_start || req_id > priv->rx_end)) + if (unlikely(_req_id < priv->rx_start || _req_id > priv->rx_end)) return -EINVAL; skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel), diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 7ef191a9d79..9b347cea985 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -164,12 +164,12 @@ static const struct p54spi_spi_reg p54spi_registers_array[] = { SPI_ADRS_DMA_WRITE_BASE, 32, "DMA_RD_BASE " } }; -static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits) +static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, u32 bits) { int i; for (i = 0; i < 2000; i++) { - __le32 buffer = p54spi_read32(priv, reg); + u32 buffer = p54spi_read32(priv, reg); if ((buffer & bits) == bits) return 1; } @@ -179,8 +179,7 @@ static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits) static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base, const void *buf, size_t len) { - if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, - cpu_to_le32(HOST_ALLOWED))) { + if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, HOST_ALLOWED)) { dev_err(&priv->spi->dev, "spi_write_dma not allowed " "to DMA write.\n"); return -EAGAIN; @@ -333,7 +332,7 @@ static int p54spi_wakeup(struct p54s_priv *priv) /* And wait for the READY interrupt */ if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS, - cpu_to_le32(SPI_HOST_INT_READY))) { + SPI_HOST_INT_READY)) { dev_err(&priv->spi->dev, "INT_READY timeout\n"); return -EBUSY; } @@ -444,7 +443,7 @@ static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb) goto out; if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS, - cpu_to_le32(SPI_HOST_INT_WR_READY))) { + SPI_HOST_INT_WR_READY)) { dev_err(&priv->spi->dev, "WR_READY timeout\n"); ret = -EAGAIN; goto out; -- cgit v1.2.3-18-g5258 From 0859339b5c2902a7a4ba1d4c9cf35d882f421e7f Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 4 Jul 2009 17:49:59 +0200 Subject: p54spi: remove dead code and definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch removes some dead code: p54spi.c:115: warning: ‘p54spi_read16’ defined but not used and while we're at it, p54spi_registers_array is purged as well. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54spi.c | 34 ---------------------------------- 1 file changed, 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 9b347cea985..d5f181ad37f 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -111,15 +111,6 @@ static void p54spi_spi_write(struct p54s_priv *priv, u8 address, spi_sync(priv->spi, &m); } -static u16 p54spi_read16(struct p54s_priv *priv, u8 addr) -{ - __le16 val; - - p54spi_spi_read(priv, addr, &val, sizeof(val)); - - return le16_to_cpu(val); -} - static u32 p54spi_read32(struct p54s_priv *priv, u8 addr) { __le32 val; @@ -139,31 +130,6 @@ static inline void p54spi_write32(struct p54s_priv *priv, u8 addr, __le32 val) p54spi_spi_write(priv, addr, &val, sizeof(val)); } -struct p54spi_spi_reg { - u16 address; /* __le16 ? */ - u16 length; - char *name; -}; - -static const struct p54spi_spi_reg p54spi_registers_array[] = -{ - { SPI_ADRS_ARM_INTERRUPTS, 32, "ARM_INT " }, - { SPI_ADRS_ARM_INT_EN, 32, "ARM_INT_ENA " }, - { SPI_ADRS_HOST_INTERRUPTS, 32, "HOST_INT " }, - { SPI_ADRS_HOST_INT_EN, 32, "HOST_INT_ENA" }, - { SPI_ADRS_HOST_INT_ACK, 32, "HOST_INT_ACK" }, - { SPI_ADRS_GEN_PURP_1, 32, "GP1_COMM " }, - { SPI_ADRS_GEN_PURP_2, 32, "GP2_COMM " }, - { SPI_ADRS_DEV_CTRL_STAT, 32, "DEV_CTRL_STA" }, - { SPI_ADRS_DMA_DATA, 16, "DMA_DATA " }, - { SPI_ADRS_DMA_WRITE_CTRL, 16, "DMA_WR_CTRL " }, - { SPI_ADRS_DMA_WRITE_LEN, 16, "DMA_WR_LEN " }, - { SPI_ADRS_DMA_WRITE_BASE, 32, "DMA_WR_BASE " }, - { SPI_ADRS_DMA_READ_CTRL, 16, "DMA_RD_CTRL " }, - { SPI_ADRS_DMA_READ_LEN, 16, "DMA_RD_LEN " }, - { SPI_ADRS_DMA_WRITE_BASE, 32, "DMA_RD_BASE " } -}; - static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, u32 bits) { int i; -- cgit v1.2.3-18-g5258 From cec8db23011d2a0a5ec101a0263d79678adf21ba Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Sat, 4 Jul 2009 12:59:51 -0400 Subject: ath5k: send buffered frames after the beacon Enable the "Content" After Beacon queue and utilize it to send any buffered frames for power-saving clients. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 35 ++++++++++++++++++++++++++++++----- drivers/net/wireless/ath/ath5k/base.h | 9 ++++----- drivers/net/wireless/ath/ath5k/qcu.c | 1 - 3 files changed, 34 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index c6e70919435..87ebc461d74 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -218,6 +218,8 @@ static struct pci_driver ath5k_pci_driver = { * Prototypes - MAC 802.11 stack related functions */ static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb); +static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ath5k_txq *txq); static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan); static int ath5k_reset_wake(struct ath5k_softc *sc); static int ath5k_start(struct ieee80211_hw *hw); @@ -301,7 +303,8 @@ static void ath5k_desc_free(struct ath5k_softc *sc, static int ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf); static int ath5k_txbuf_setup(struct ath5k_softc *sc, - struct ath5k_buf *bf); + struct ath5k_buf *bf, + struct ath5k_txq *txq); static inline void ath5k_txbuf_free(struct ath5k_softc *sc, struct ath5k_buf *bf) { @@ -516,6 +519,7 @@ ath5k_pci_probe(struct pci_dev *pdev, /* Initialize driver private data */ SET_IEEE80211_DEV(hw, &pdev->dev); hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; @@ -789,12 +793,18 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) goto err_desc; } sc->bhalq = ret; + sc->cabq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_CAB, 0); + if (IS_ERR(sc->cabq)) { + ATH5K_ERR(sc, "can't setup cab queue\n"); + ret = PTR_ERR(sc->cabq); + goto err_bhal; + } sc->txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK); if (IS_ERR(sc->txq)) { ATH5K_ERR(sc, "can't setup xmit queue\n"); ret = PTR_ERR(sc->txq); - goto err_bhal; + goto err_queues; } tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc); @@ -1232,10 +1242,10 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) } static int -ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) +ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, + struct ath5k_txq *txq) { struct ath5k_hw *ah = sc->ah; - struct ath5k_txq *txq = sc->txq; struct ath5k_desc *ds = bf->desc; struct sk_buff *skb = bf->skb; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -2103,6 +2113,7 @@ ath5k_beacon_send(struct ath5k_softc *sc) { struct ath5k_buf *bf = sc->bbuf; struct ath5k_hw *ah = sc->ah; + struct sk_buff *skb; ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n"); @@ -2156,6 +2167,12 @@ ath5k_beacon_send(struct ath5k_softc *sc) ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n", sc->bhalq, (unsigned long long)bf->daddr, bf->desc); + skb = ieee80211_get_buffered_bc(sc->hw, sc->vif); + while (skb) { + ath5k_tx_queue(sc->hw, skb, sc->cabq); + skb = ieee80211_get_buffered_bc(sc->hw, sc->vif); + } + sc->bsent++; } @@ -2601,6 +2618,14 @@ ath5k_calibrate(unsigned long data) static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct ath5k_softc *sc = hw->priv; + + return ath5k_tx_queue(hw, skb, sc->txq); +} + +static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ath5k_txq *txq) { struct ath5k_softc *sc = hw->priv; struct ath5k_buf *bf; @@ -2646,7 +2671,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) bf->skb = skb; - if (ath5k_txbuf_setup(sc, bf)) { + if (ath5k_txbuf_setup(sc, bf, txq)) { bf->skb = NULL; spin_lock_irqsave(&sc->txbuflock, flags); list_add_tail(&bf->list, &sc->txbuf); diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index f9b7f2f819b..65e75fb5448 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -114,8 +114,7 @@ struct ath5k_softc { struct pci_dev *pdev; /* for dma mapping */ void __iomem *iobase; /* address of the device */ struct mutex lock; /* dev-level lock */ - /* FIXME: how many does it really need? */ - struct ieee80211_tx_queue_stats tx_stats[16]; + struct ieee80211_tx_queue_stats tx_stats[AR5K_NUM_TX_QUEUES]; struct ieee80211_low_level_stats ll_stats; struct ieee80211_hw *hw; /* IEEE 802.11 common */ struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; @@ -171,9 +170,8 @@ struct ath5k_softc { struct list_head txbuf; /* transmit buffer */ spinlock_t txbuflock; unsigned int txbuf_len; /* buf count in txbuf list */ - struct ath5k_txq txqs[2]; /* beacon and tx */ - - struct ath5k_txq *txq; /* beacon and tx*/ + struct ath5k_txq txqs[AR5K_NUM_TX_QUEUES]; /* tx queues */ + struct ath5k_txq *txq; /* main tx queue */ struct tasklet_struct txtq; /* tx intr tasklet */ struct ath5k_led tx_led; /* tx led */ @@ -187,6 +185,7 @@ struct ath5k_softc { bintval, /* beacon interval in TU */ bsent; unsigned int nexttbtt; /* next beacon time in TU */ + struct ath5k_txq *cabq; /* content after beacon */ struct timer_list calib_tim; /* calibration timer */ int power_level; /* Requested tx power in dbm */ diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 73407b3f53e..6d5aaf00d8b 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -411,7 +411,6 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), AR5K_QCU_MISC_FRSHED_BCN_SENT_GT | AR5K_QCU_MISC_CBREXP_DIS | - AR5K_QCU_MISC_RDY_VEOL_POLICY | AR5K_QCU_MISC_CBREXP_BCN_DIS); ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL - -- cgit v1.2.3-18-g5258 From 21800491cc5c48e9f1084a6f524a0da7c2525cc6 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Sat, 4 Jul 2009 12:59:52 -0400 Subject: ath5k: rework beacon configuration Using the enable_beacon flag allows some simplifications and fixes some corner cases in beacon handling. This change adds a state variable for beaconing in ath5k_beacon_config and handles both enabling and disabling, thus eliminating the need for ath5k_beacon_disable. We also now configure the beacon when any of the beacon parameters change, so ath5k_beacon_reconfig is no longer needed (its mmiowb gets moved to ath5k_beacon_config). Finally, by locking around the whole config function, we don't need to worry about clearing the interrupt mask register before installing the new mask. The upshot is this correctly disables beaconing when the interfaces are taken down, it fixes a potential restarting of beaconing when ath5k_reset() is called, and ensures that updates to the beacon interval take effect immediately. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 59 +++++++++++------------------------ drivers/net/wireless/ath/ath5k/base.h | 1 + 2 files changed, 20 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 87ebc461d74..482932979c9 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2093,13 +2093,6 @@ err_unmap: return ret; } -static void ath5k_beacon_disable(struct ath5k_softc *sc) -{ - sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA); - ath5k_hw_set_imr(sc->ah, sc->imask); - ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq); -} - /* * Transmit a beacon frame at SWBA. Dynamic updates to the * frame contents are done as needed and the slot time is @@ -2293,13 +2286,11 @@ ath5k_beacon_config(struct ath5k_softc *sc) struct ath5k_hw *ah = sc->ah; unsigned long flags; - ath5k_hw_set_imr(ah, 0); + spin_lock_irqsave(&sc->block, flags); sc->bmisscount = 0; sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA); - if (sc->opmode == NL80211_IFTYPE_ADHOC || - sc->opmode == NL80211_IFTYPE_MESH_POINT || - sc->opmode == NL80211_IFTYPE_AP) { + if (sc->enable_beacon) { /* * In IBSS mode we use a self-linked tx descriptor and let the * hardware send the beacons automatically. We have to load it @@ -2312,16 +2303,17 @@ ath5k_beacon_config(struct ath5k_softc *sc) sc->imask |= AR5K_INT_SWBA; if (sc->opmode == NL80211_IFTYPE_ADHOC) { - if (ath5k_hw_hasveol(ah)) { - spin_lock_irqsave(&sc->block, flags); + if (ath5k_hw_hasveol(ah)) ath5k_beacon_send(sc); - spin_unlock_irqrestore(&sc->block, flags); - } } else ath5k_beacon_update_timers(sc, -1); + } else { + ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq); } ath5k_hw_set_imr(ah, sc->imask); + mmiowb(); + spin_unlock_irqrestore(&sc->block, flags); } static void ath5k_tasklet_beacon(unsigned long data) @@ -2806,7 +2798,6 @@ ath5k_remove_interface(struct ieee80211_hw *hw, goto end; ath5k_hw_set_lladdr(sc->ah, mac); - ath5k_beacon_disable(sc); sc->vif = NULL; end: mutex_unlock(&sc->lock); @@ -3135,25 +3126,6 @@ out: return ret; } -/* - * Update the beacon and reconfigure the beacon queues. - */ -static void -ath5k_beacon_reconfig(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - int ret; - unsigned long flags; - struct ath5k_softc *sc = hw->priv; - - spin_lock_irqsave(&sc->block, flags); - ret = ath5k_beacon_update(hw, vif); - spin_unlock_irqrestore(&sc->block, flags); - if (ret == 0) { - ath5k_beacon_config(sc); - mmiowb(); - } -} - static void set_beacon_filter(struct ieee80211_hw *hw, bool enable) { @@ -3176,6 +3148,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, { struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; + unsigned long flags; mutex_lock(&sc->lock); if (WARN_ON(sc->vif != vif)) @@ -3201,13 +3174,19 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, AR5K_LED_ASSOC : AR5K_LED_INIT); } - if (changes & BSS_CHANGED_BEACON && - (vif->type == NL80211_IFTYPE_ADHOC || - vif->type == NL80211_IFTYPE_MESH_POINT || - vif->type == NL80211_IFTYPE_AP)) { - ath5k_beacon_reconfig(hw, vif); + if (changes & BSS_CHANGED_BEACON) { + spin_lock_irqsave(&sc->block, flags); + ath5k_beacon_update(hw, vif); + spin_unlock_irqrestore(&sc->block, flags); } + if (changes & BSS_CHANGED_BEACON_ENABLED) + sc->enable_beacon = bss_conf->enable_beacon; + + if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED | + BSS_CHANGED_BEACON_INT)) + ath5k_beacon_config(sc); + unlock: mutex_unlock(&sc->lock); } diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 65e75fb5448..778e422946a 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -190,6 +190,7 @@ struct ath5k_softc { struct timer_list calib_tim; /* calibration timer */ int power_level; /* Requested tx power in dbm */ bool assoc; /* assocate state */ + bool enable_beacon; /* true if beacons are on */ }; #define ath5k_hw_hasbssidmask(_ah) \ -- cgit v1.2.3-18-g5258 From 88f6bfe1829d67bea37b060d53131b2b96ebc8ac Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Sat, 4 Jul 2009 12:59:53 -0400 Subject: ath: remove unnecessary return in ath_regd_get_band_ctl 'default' case already returns NO_CTL Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/regd.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index eef370bd121..f37c8327579 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -569,7 +569,5 @@ u32 ath_regd_get_band_ctl(struct ath_regulatory *reg, default: return NO_CTL; } - - return NO_CTL; } EXPORT_SYMBOL(ath_regd_get_band_ctl); -- cgit v1.2.3-18-g5258 From 0d0cd72fa1e6bfd419c99478ec70b4877ed0ef86 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Sat, 4 Jul 2009 12:59:54 -0400 Subject: ath5k: do not release irq across suspend/resume Paraphrasing Rafael J. Wysocki: "drivers should not release PCI IRQs in suspend." Doing so causes a warning during suspend/resume on some platforms. Cc: Rafael J. Wysocki Reported-by: Alan Jenkins Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 482932979c9..3f55e90c43f 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -674,7 +674,6 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state) ath5k_led_off(sc); - free_irq(pdev->irq, sc); pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); @@ -702,18 +701,8 @@ ath5k_pci_resume(struct pci_dev *pdev) */ pci_write_config_byte(pdev, 0x41, 0); - err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); - if (err) { - ATH5K_ERR(sc, "request_irq failed\n"); - goto err_no_irq; - } - ath5k_led_enable(sc); return 0; - -err_no_irq: - pci_disable_device(pdev); - return err; } #endif /* CONFIG_PM */ -- cgit v1.2.3-18-g5258 From 3355443ad7601991affa5992b0d53870335af765 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Sat, 4 Jul 2009 21:03:13 -0400 Subject: ath5k: write PCU registers on initial reset "Ath5k: unify resets" introduced a regression into 2.6.28 where the PCU registers are never initialized, due to ath5k_reset() always passing true for change_channel. We subsequently program a lot of these registers but several may start in an unknown state. Cc: stable@kernel.org Reported-by: Forrest Zhang Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 3f55e90c43f..20ba6fa5f1f 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2687,7 +2687,7 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan) sc->curchan = chan; sc->curband = &sc->sbands[chan->band]; } - ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true); + ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL); if (ret) { ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret); goto err; -- cgit v1.2.3-18-g5258 From 6d541a684d7eb72c71eaba82b09a360c96609134 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 6 Jul 2009 15:17:56 +0200 Subject: p54usb: fix stalls caused by urb allocation failures This patch squashes a few old bugs, which have been around since the initial version of p54usb in one form or another. we never freed a orphaned frame, when were denied the resources, which are necessary to pass the data into the usb subsystem. As a result we could end up with a full queue that wasn't emptied, until the device was brought down. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54usb.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 461d88f5ceb..e44460ff149 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -246,8 +246,10 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb) struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr); data_urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!data_urb) + if (!data_urb) { + p54_free_skb(dev, skb); return; + } hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len); hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id; @@ -269,27 +271,22 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb) static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54u_priv *priv = dev->priv; - struct urb *int_urb, *data_urb; + struct urb *int_urb = NULL, *data_urb = NULL; struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr); - struct net2280_reg_write *reg; - int err = 0; + struct net2280_reg_write *reg = NULL; + int err = -ENOMEM; reg = kmalloc(sizeof(*reg), GFP_ATOMIC); if (!reg) - return; + goto out; int_urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!int_urb) { - kfree(reg); - return; - } + if (!int_urb) + goto out; data_urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!data_urb) { - kfree(reg); - usb_free_urb(int_urb); - return; - } + if (!data_urb) + goto out; reg->port = cpu_to_le16(NET2280_DEV_U32); reg->addr = cpu_to_le32(P54U_DEV_BASE); @@ -304,11 +301,12 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) p54u_tx_dummy_cb, dev); /* - * This flag triggers a code path in the USB subsystem that will - * free what's inside the transfer_buffer after the callback routine - * has completed. + * URB_FREE_BUFFER triggers a code path in the USB subsystem that will + * free what is inside the transfer_buffer after the last reference to + * the int_urb is dropped. */ int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET; + reg = NULL; usb_fill_bulk_urb(data_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), @@ -329,12 +327,12 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) usb_unanchor_urb(data_urb); goto out; } - out: +out: usb_free_urb(int_urb); usb_free_urb(data_urb); if (err) { - skb_pull(skb, sizeof(*hdr)); + kfree(reg); p54_free_skb(dev, skb); } } -- cgit v1.2.3-18-g5258 From 2ffa5fede379091bf62a732462b829e4b51af054 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 6 Jul 2009 15:18:13 +0200 Subject: p54: fix queue stall due to underrun Larry Finger discovered a weird behavior under load. In essence, the queue's length count under runs, which in turn renders the associated ac queue unusable. Reported-by: Larry Finger Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/txrx.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 31fda17bec4..6426d2cae6d 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -199,7 +199,7 @@ static int p54_tx_qos_accounting_alloc(struct p54_common *priv, queue = &priv->tx_stats[p54_queue]; spin_lock_irqsave(&priv->tx_stats_lock, flags); - if (unlikely(queue->len > queue->limit && IS_QOS_QUEUE(p54_queue))) { + if (unlikely(queue->len >= queue->limit && IS_QOS_QUEUE(p54_queue))) { spin_unlock_irqrestore(&priv->tx_stats_lock, flags); return -ENOSPC; } @@ -222,8 +222,11 @@ static void p54_tx_qos_accounting_free(struct p54_common *priv, if (skb && IS_DATA_FRAME(skb)) { struct p54_hdr *hdr = (void *) skb->data; struct p54_tx_data *data = (void *) hdr->data; + unsigned long flags; + spin_lock_irqsave(&priv->tx_stats_lock, flags); priv->tx_stats[data->hw_queue].len--; + spin_unlock_irqrestore(&priv->tx_stats_lock, flags); } p54_wake_queues(priv); } @@ -462,7 +465,6 @@ static void p54_rx_eeprom_readback(struct p54_common *priv, priv->eeprom = NULL; tmp = p54_find_and_unlink_skb(priv, hdr->req_id); - p54_tx_qos_accounting_free(priv, tmp); dev_kfree_skb_any(tmp); complete(&priv->eeprom_comp); } @@ -489,7 +491,6 @@ static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb) priv->noise = p54_rssi_to_dbm(priv, le32_to_cpu(stats->noise)); tmp = p54_find_and_unlink_skb(priv, hdr->req_id); - p54_tx_qos_accounting_free(priv, tmp); dev_kfree_skb_any(tmp); } -- cgit v1.2.3-18-g5258 From 5bc38193c1793e240a7e0b93f129606931e35fdb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 11:00:55 +0200 Subject: hwsim: make testmode_cmd static sparse correctly complains about this, no reason for it not to be static. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 6ac8565072e..4befa48dbc3 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -729,7 +729,8 @@ static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = { static int hwsim_fops_ps_write(void *dat, u64 val); -int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) +static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, + void *data, int len) { struct mac80211_hwsim_data *hwsim = hw->priv; struct nlattr *tb[HWSIM_TM_ATTR_MAX + 1]; -- cgit v1.2.3-18-g5258 From 7d024608265eb815ae4ce1e5da097ec9d800dda4 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 10 Jul 2009 17:26:44 +0800 Subject: crypto: padlock - Use shash fallback for sha This patch changes padlock sha fallback to shash instead of hash. Signed-off-by: Herbert Xu --- drivers/crypto/padlock-sha.c | 82 ++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c index a2c8e8514b6..868da54b185 100644 --- a/drivers/crypto/padlock-sha.c +++ b/drivers/crypto/padlock-sha.c @@ -12,28 +12,24 @@ * */ -#include +#include #include #include #include #include #include -#include #include #include #include #include #include "padlock.h" -#define SHA1_DEFAULT_FALLBACK "sha1-generic" -#define SHA256_DEFAULT_FALLBACK "sha256-generic" - struct padlock_sha_ctx { char *data; size_t used; int bypass; void (*f_sha_padlock)(const char *in, char *out, int count); - struct hash_desc fallback; + struct shash_desc *fallback; }; static inline struct padlock_sha_ctx *ctx(struct crypto_tfm *tfm) @@ -47,21 +43,26 @@ static inline struct padlock_sha_ctx *ctx(struct crypto_tfm *tfm) static struct crypto_alg sha1_alg, sha256_alg; -static void padlock_sha_bypass(struct crypto_tfm *tfm) +static int padlock_sha_bypass(struct crypto_tfm *tfm) { + int err = 0; + if (ctx(tfm)->bypass) - return; + goto out; - crypto_hash_init(&ctx(tfm)->fallback); - if (ctx(tfm)->data && ctx(tfm)->used) { - struct scatterlist sg; + err = crypto_shash_init(ctx(tfm)->fallback); + if (err) + goto out; - sg_init_one(&sg, ctx(tfm)->data, ctx(tfm)->used); - crypto_hash_update(&ctx(tfm)->fallback, &sg, sg.length); - } + if (ctx(tfm)->data && ctx(tfm)->used) + err = crypto_shash_update(ctx(tfm)->fallback, ctx(tfm)->data, + ctx(tfm)->used); ctx(tfm)->used = 0; ctx(tfm)->bypass = 1; + +out: + return err; } static void padlock_sha_init(struct crypto_tfm *tfm) @@ -73,15 +74,18 @@ static void padlock_sha_init(struct crypto_tfm *tfm) static void padlock_sha_update(struct crypto_tfm *tfm, const uint8_t *data, unsigned int length) { + int err; + /* Our buffer is always one page. */ if (unlikely(!ctx(tfm)->bypass && - (ctx(tfm)->used + length > PAGE_SIZE))) - padlock_sha_bypass(tfm); + (ctx(tfm)->used + length > PAGE_SIZE))) { + err = padlock_sha_bypass(tfm); + BUG_ON(err); + } if (unlikely(ctx(tfm)->bypass)) { - struct scatterlist sg; - sg_init_one(&sg, (uint8_t *)data, length); - crypto_hash_update(&ctx(tfm)->fallback, &sg, length); + err = crypto_shash_update(ctx(tfm)->fallback, data, length); + BUG_ON(err); return; } @@ -151,8 +155,11 @@ static void padlock_do_sha256(const char *in, char *out, int count) static void padlock_sha_final(struct crypto_tfm *tfm, uint8_t *out) { + int err; + if (unlikely(ctx(tfm)->bypass)) { - crypto_hash_final(&ctx(tfm)->fallback, out); + err = crypto_shash_final(ctx(tfm)->fallback, out); + BUG_ON(err); ctx(tfm)->bypass = 0; return; } @@ -166,27 +173,41 @@ static void padlock_sha_final(struct crypto_tfm *tfm, uint8_t *out) static int padlock_cra_init(struct crypto_tfm *tfm) { const char *fallback_driver_name = tfm->__crt_alg->cra_name; - struct crypto_hash *fallback_tfm; + struct crypto_shash *fallback_tfm; + int err = -ENOMEM; /* For now we'll allocate one page. This * could eventually be configurable one day. */ ctx(tfm)->data = (char *)__get_free_page(GFP_KERNEL); if (!ctx(tfm)->data) - return -ENOMEM; + goto out; /* Allocate a fallback and abort if it failed. */ - fallback_tfm = crypto_alloc_hash(fallback_driver_name, 0, - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK); + fallback_tfm = crypto_alloc_shash(fallback_driver_name, 0, + CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(fallback_tfm)) { printk(KERN_WARNING PFX "Fallback driver '%s' could not be loaded!\n", fallback_driver_name); - free_page((unsigned long)(ctx(tfm)->data)); - return PTR_ERR(fallback_tfm); + err = PTR_ERR(fallback_tfm); + goto out_free_page; } - ctx(tfm)->fallback.tfm = fallback_tfm; + ctx(tfm)->fallback = kmalloc(sizeof(struct shash_desc) + + crypto_shash_descsize(fallback_tfm), + GFP_KERNEL); + if (!ctx(tfm)->fallback) + goto out_free_tfm; + + ctx(tfm)->fallback->tfm = fallback_tfm; + ctx(tfm)->fallback->flags = 0; return 0; + +out_free_tfm: + crypto_free_shash(fallback_tfm); +out_free_page: + free_page((unsigned long)(ctx(tfm)->data)); +out: + return err; } static int padlock_sha1_cra_init(struct crypto_tfm *tfm) @@ -210,8 +231,9 @@ static void padlock_cra_exit(struct crypto_tfm *tfm) ctx(tfm)->data = NULL; } - crypto_free_hash(ctx(tfm)->fallback.tfm); - ctx(tfm)->fallback.tfm = NULL; + crypto_free_shash(ctx(tfm)->fallback->tfm); + + kzfree(ctx(tfm)->fallback); } static struct crypto_alg sha1_alg = { -- cgit v1.2.3-18-g5258 From 0724915a69433716704bc5de6f729d3751981be6 Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Sat, 11 Jul 2009 09:33:21 +0800 Subject: [ARM] remove duplicated #include Remove duplicated #include('s) in drivers/spi/amba-pl022.c Signed-off-by: Huang Weiyi Signed-off-by: Russell King --- drivers/spi/amba-pl022.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c index da76797ce8b..c0f950a7cbe 100644 --- a/drivers/spi/amba-pl022.c +++ b/drivers/spi/amba-pl022.c @@ -38,14 +38,12 @@ #include #include #include -#include #include #include #include #include #include #include -#include /* * This macro is used to define some register default values. -- cgit v1.2.3-18-g5258 From 8e321c4f72e2fb580a091317ba0fb2941f637ce1 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 11 Jul 2009 10:03:55 +0000 Subject: drivers/net/bonding: Adjust constant name AD_SHORT_TIMEOUT and AD_STATE_LACP_ACTIVITY have the same value, but AD_STATE_LACP_ACTIVITY better reflects the intended semantics. [ J adds: AD_STATE_LACP_ACTIVITY is a value defined by the standard, and should be set here in accordance with 802.3ad 43.4.12; AD_SHORT_TIMEOUT is a constant specific to the Linux 802.3ad implementation that happens to have the same value ] The semantic match that finds this problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @@ struct port_params p; @@ * p.port_state |= AD_SHORT_TIMEOUT // Signed-off-by: Julia Lawall Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_3ad.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 0e7dfe0981d..be799d2a8a8 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -1109,7 +1109,8 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) //mux machine in case of EXPIRED even if LINK_DOWN didn't arrive for the port. port->partner_oper.port_state &= ~AD_STATE_SYNCHRONIZATION; port->sm_vars &= ~AD_PORT_MATCHED; - port->partner_oper.port_state |= AD_SHORT_TIMEOUT; + port->partner_oper.port_state |= + AD_STATE_LACP_ACTIVITY; port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(AD_SHORT_TIMEOUT)); port->actor_oper_port_state |= AD_STATE_EXPIRED; break; -- cgit v1.2.3-18-g5258 From f9c22736940cdc8f5e2db0109fc9493e0cbd895d Mon Sep 17 00:00:00 2001 From: "Hans J. Koch" Date: Sun, 12 Jul 2009 20:51:25 -0700 Subject: Input: ucb1400_ts - fix a misleading function name The driver for UCB1400 touchscreen controllers contains a function named ucb1400_ts_pen_down(), but it returns 0 if the pen is down and 1 if it's up. This causes confusion, especially since it's used as a boolean truth value later in the code. This patch renames it. Signed-off-by: Hans J. Koch Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ucb1400_ts.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 6954f550010..e85483578bd 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -128,9 +128,10 @@ static inline unsigned int ucb1400_ts_read_yres(struct ucb1400_ts *ucb) return ucb1400_adc_read(ucb->ac97, 0, adcsync); } -static inline int ucb1400_ts_pen_down(struct snd_ac97 *ac97) +static inline int ucb1400_ts_pen_up(struct snd_ac97 *ac97) { unsigned short val = ucb1400_reg_read(ac97, UCB_TS_CR); + return val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW); } @@ -209,7 +210,7 @@ static int ucb1400_ts_thread(void *_ucb) msleep(10); - if (ucb1400_ts_pen_down(ucb->ac97)) { + if (ucb1400_ts_pen_up(ucb->ac97)) { ucb1400_ts_irq_enable(ucb->ac97); /* -- cgit v1.2.3-18-g5258 From b7788c5ff9e7676dc98ca6dce437ae16b79c6726 Mon Sep 17 00:00:00 2001 From: Wan ZongShun Date: Sun, 12 Jul 2009 20:52:19 -0700 Subject: Input: w90p910_ts - use clk API Now that clk API is available on ARM we can use it in the driver. Signed-off-by: Wan ZongShun Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 1 + drivers/input/touchscreen/w90p910_ts.c | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index a66e50aeba1..1c05b3286d6 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -498,6 +498,7 @@ config TOUCHSCREEN_TSC2007 config TOUCHSCREEN_W90X900 tristate "W90P910 touchscreen driver" + depends on HAVE_CLK help Say Y here if you have a W90P910 based touchscreen. diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c index b3e782fdd2b..dc4c9d6b67c 100644 --- a/drivers/input/touchscreen/w90p910_ts.c +++ b/drivers/input/touchscreen/w90p910_ts.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -47,8 +48,8 @@ enum ts_state { struct w90p910_ts { struct input_dev *input; struct timer_list timer; + struct clk *clk; int irq_num; - void __iomem *clocken; void __iomem *ts_reg; spinlock_t lock; enum ts_state state; @@ -166,8 +167,7 @@ static int w90p910_open(struct input_dev *dev) unsigned long val; /* enable the ADC clock */ - val = __raw_readl(w90p910_ts->clocken); - __raw_writel(val | ADC_CLK_EN, w90p910_ts->clocken); + clk_enable(w90p910_ts->clk); __raw_writel(ADC_RST1, w90p910_ts->ts_reg); msleep(1); @@ -211,8 +211,7 @@ static void w90p910_close(struct input_dev *dev) del_timer_sync(&w90p910_ts->timer); /* stop the ADC clock */ - val = __raw_readl(w90p910_ts->clocken); - __raw_writel(val & ~ADC_CLK_EN, w90p910_ts->clocken); + clk_disable(w90p910_ts->clk); } static int __devinit w90x900ts_probe(struct platform_device *pdev) @@ -253,14 +252,12 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev) goto fail2; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res) { - err = -ENXIO; + w90p910_ts->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(w90p910_ts->clk)) { + err = PTR_ERR(w90p910_ts->clk); goto fail3; } - w90p910_ts->clocken = (void __iomem *)res->start; - input_dev->name = "W90P910 TouchScreen"; input_dev->phys = "w90p910ts/event0"; input_dev->id.bustype = BUS_HOST; @@ -283,18 +280,19 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev) if (request_irq(w90p910_ts->irq_num, w90p910_ts_interrupt, IRQF_DISABLED, "w90p910ts", w90p910_ts)) { err = -EBUSY; - goto fail3; + goto fail4; } err = input_register_device(w90p910_ts->input); if (err) - goto fail4; + goto fail5; platform_set_drvdata(pdev, w90p910_ts); return 0; -fail4: free_irq(w90p910_ts->irq_num, w90p910_ts); +fail5: free_irq(w90p910_ts->irq_num, w90p910_ts); +fail4: clk_put(w90p910_ts->clk); fail3: iounmap(w90p910_ts->ts_reg); fail2: release_mem_region(res->start, resource_size(res)); fail1: input_free_device(input_dev); @@ -311,6 +309,8 @@ static int __devexit w90x900ts_remove(struct platform_device *pdev) del_timer_sync(&w90p910_ts->timer); iounmap(w90p910_ts->ts_reg); + clk_put(w90p910_ts->clk); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); -- cgit v1.2.3-18-g5258 From bbbee4679afd7c29a58087f133ffe241597f3144 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 11 Jul 2009 18:16:16 +0800 Subject: crypto: padlock - Switch sha to shash This patch converts the padlock-sha implementation to shash. In doing so the existing mechanism of storing the data until final is no longer viable as we do not have a way of allocating data in crypto_shash_init and then reliably freeing it. This is just as well because a better way of handling the problem is to hash everything but the last chunk using normal sha code and then provide the intermediate result to the padlock device. This is good enough because the primary application of padlock-sha is IPsec and there the data is laid out in the form of an hmac header followed by the rest of the packet. In essence we can provide all the data to the padlock as the hmac header only needs to be hashed once. Signed-off-by: Herbert Xu --- drivers/crypto/Kconfig | 2 +- drivers/crypto/padlock-sha.c | 333 ++++++++++++++++++++----------------------- 2 files changed, 156 insertions(+), 179 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 5b27692372b..1bb4b7fe458 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -13,7 +13,6 @@ if CRYPTO_HW config CRYPTO_DEV_PADLOCK tristate "Support for VIA PadLock ACE" depends on X86 && !UML - select CRYPTO_ALGAPI help Some VIA processors come with an integrated crypto engine (so called VIA PadLock ACE, Advanced Cryptography Engine) @@ -39,6 +38,7 @@ config CRYPTO_DEV_PADLOCK_AES config CRYPTO_DEV_PADLOCK_SHA tristate "PadLock driver for SHA1 and SHA256 algorithms" depends on CRYPTO_DEV_PADLOCK + select CRYPTO_HASH select CRYPTO_SHA1 select CRYPTO_SHA256 help diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c index 868da54b185..fb6e6c34314 100644 --- a/drivers/crypto/padlock-sha.c +++ b/drivers/crypto/padlock-sha.c @@ -24,73 +24,31 @@ #include #include "padlock.h" -struct padlock_sha_ctx { - char *data; - size_t used; - int bypass; - void (*f_sha_padlock)(const char *in, char *out, int count); - struct shash_desc *fallback; +struct padlock_sha_desc { + struct shash_desc fallback; }; -static inline struct padlock_sha_ctx *ctx(struct crypto_tfm *tfm) -{ - return crypto_tfm_ctx(tfm); -} - -/* We'll need aligned address on the stack */ -#define NEAREST_ALIGNED(ptr) \ - ((void *)ALIGN((size_t)(ptr), PADLOCK_ALIGNMENT)) - -static struct crypto_alg sha1_alg, sha256_alg; +struct padlock_sha_ctx { + struct crypto_shash *fallback; +}; -static int padlock_sha_bypass(struct crypto_tfm *tfm) +static int padlock_sha_init(struct shash_desc *desc) { - int err = 0; - - if (ctx(tfm)->bypass) - goto out; + struct padlock_sha_desc *dctx = shash_desc_ctx(desc); + struct padlock_sha_ctx *ctx = crypto_shash_ctx(desc->tfm); - err = crypto_shash_init(ctx(tfm)->fallback); - if (err) - goto out; - - if (ctx(tfm)->data && ctx(tfm)->used) - err = crypto_shash_update(ctx(tfm)->fallback, ctx(tfm)->data, - ctx(tfm)->used); - - ctx(tfm)->used = 0; - ctx(tfm)->bypass = 1; - -out: - return err; + dctx->fallback.tfm = ctx->fallback; + dctx->fallback.flags = desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; + return crypto_shash_init(&dctx->fallback); } -static void padlock_sha_init(struct crypto_tfm *tfm) +static int padlock_sha_update(struct shash_desc *desc, + const u8 *data, unsigned int length) { - ctx(tfm)->used = 0; - ctx(tfm)->bypass = 0; -} + struct padlock_sha_desc *dctx = shash_desc_ctx(desc); -static void padlock_sha_update(struct crypto_tfm *tfm, - const uint8_t *data, unsigned int length) -{ - int err; - - /* Our buffer is always one page. */ - if (unlikely(!ctx(tfm)->bypass && - (ctx(tfm)->used + length > PAGE_SIZE))) { - err = padlock_sha_bypass(tfm); - BUG_ON(err); - } - - if (unlikely(ctx(tfm)->bypass)) { - err = crypto_shash_update(ctx(tfm)->fallback, data, length); - BUG_ON(err); - return; - } - - memcpy(ctx(tfm)->data + ctx(tfm)->used, data, length); - ctx(tfm)->used += length; + dctx->fallback.flags = desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; + return crypto_shash_update(&dctx->fallback, data, length); } static inline void padlock_output_block(uint32_t *src, @@ -100,88 +58,138 @@ static inline void padlock_output_block(uint32_t *src, *dst++ = swab32(*src++); } -static void padlock_do_sha1(const char *in, char *out, int count) +static int padlock_sha1_finup(struct shash_desc *desc, const u8 *in, + unsigned int count, u8 *out) { /* We can't store directly to *out as it may be unaligned. */ /* BTW Don't reduce the buffer size below 128 Bytes! * PadLock microcode needs it that big. */ - char buf[128+16]; - char *result = NEAREST_ALIGNED(buf); + char result[128] __attribute__ ((aligned(PADLOCK_ALIGNMENT))); + struct padlock_sha_desc *dctx = shash_desc_ctx(desc); + struct sha1_state state; + unsigned int space; + unsigned int leftover; int ts_state; + int err; + + dctx->fallback.flags = desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; + err = crypto_shash_export(&dctx->fallback, &state); + if (err) + goto out; + + if (state.count + count > ULONG_MAX) + return crypto_shash_finup(&dctx->fallback, in, count, out); + + leftover = ((state.count - 1) & (SHA1_BLOCK_SIZE - 1)) + 1; + space = SHA1_BLOCK_SIZE - leftover; + if (space) { + if (count > space) { + err = crypto_shash_update(&dctx->fallback, in, space) ?: + crypto_shash_export(&dctx->fallback, &state); + if (err) + goto out; + count -= space; + in += space; + } else { + memcpy(state.buffer + leftover, in, count); + in = state.buffer; + count += leftover; + } + } + + memcpy(result, &state.state, SHA1_DIGEST_SIZE); - ((uint32_t *)result)[0] = SHA1_H0; - ((uint32_t *)result)[1] = SHA1_H1; - ((uint32_t *)result)[2] = SHA1_H2; - ((uint32_t *)result)[3] = SHA1_H3; - ((uint32_t *)result)[4] = SHA1_H4; - /* prevent taking the spurious DNA fault with padlock. */ ts_state = irq_ts_save(); asm volatile (".byte 0xf3,0x0f,0xa6,0xc8" /* rep xsha1 */ - : "+S"(in), "+D"(result) - : "c"(count), "a"(0)); + : \ + : "c"(state.count + count), "a"(state.count), \ + "S"(in), "D"(result)); irq_ts_restore(ts_state); padlock_output_block((uint32_t *)result, (uint32_t *)out, 5); + +out: + return err; } -static void padlock_do_sha256(const char *in, char *out, int count) +static int padlock_sha1_final(struct shash_desc *desc, u8 *out) +{ + u8 buf[4]; + + return padlock_sha1_finup(desc, buf, 0, out); +} + +static int padlock_sha256_finup(struct shash_desc *desc, const u8 *in, + unsigned int count, u8 *out) { /* We can't store directly to *out as it may be unaligned. */ /* BTW Don't reduce the buffer size below 128 Bytes! * PadLock microcode needs it that big. */ - char buf[128+16]; - char *result = NEAREST_ALIGNED(buf); + char result[128] __attribute__ ((aligned(PADLOCK_ALIGNMENT))); + struct padlock_sha_desc *dctx = shash_desc_ctx(desc); + struct sha256_state state; + unsigned int space; + unsigned int leftover; int ts_state; + int err; - ((uint32_t *)result)[0] = SHA256_H0; - ((uint32_t *)result)[1] = SHA256_H1; - ((uint32_t *)result)[2] = SHA256_H2; - ((uint32_t *)result)[3] = SHA256_H3; - ((uint32_t *)result)[4] = SHA256_H4; - ((uint32_t *)result)[5] = SHA256_H5; - ((uint32_t *)result)[6] = SHA256_H6; - ((uint32_t *)result)[7] = SHA256_H7; + dctx->fallback.flags = desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; + err = crypto_shash_export(&dctx->fallback, &state); + if (err) + goto out; + + if (state.count + count > ULONG_MAX) + return crypto_shash_finup(&dctx->fallback, in, count, out); + + leftover = ((state.count - 1) & (SHA256_BLOCK_SIZE - 1)) + 1; + space = SHA256_BLOCK_SIZE - leftover; + if (space) { + if (count > space) { + err = crypto_shash_update(&dctx->fallback, in, space) ?: + crypto_shash_export(&dctx->fallback, &state); + if (err) + goto out; + count -= space; + in += space; + } else { + memcpy(state.buf + leftover, in, count); + in = state.buf; + count += leftover; + } + } + + memcpy(result, &state.state, SHA256_DIGEST_SIZE); /* prevent taking the spurious DNA fault with padlock. */ ts_state = irq_ts_save(); asm volatile (".byte 0xf3,0x0f,0xa6,0xd0" /* rep xsha256 */ - : "+S"(in), "+D"(result) - : "c"(count), "a"(0)); + : \ + : "c"(state.count + count), "a"(state.count), \ + "S"(in), "D"(result)); irq_ts_restore(ts_state); padlock_output_block((uint32_t *)result, (uint32_t *)out, 8); + +out: + return err; } -static void padlock_sha_final(struct crypto_tfm *tfm, uint8_t *out) +static int padlock_sha256_final(struct shash_desc *desc, u8 *out) { - int err; - - if (unlikely(ctx(tfm)->bypass)) { - err = crypto_shash_final(ctx(tfm)->fallback, out); - BUG_ON(err); - ctx(tfm)->bypass = 0; - return; - } + u8 buf[4]; - /* Pass the input buffer to PadLock microcode... */ - ctx(tfm)->f_sha_padlock(ctx(tfm)->data, out, ctx(tfm)->used); - - ctx(tfm)->used = 0; + return padlock_sha256_finup(desc, buf, 0, out); } static int padlock_cra_init(struct crypto_tfm *tfm) { + struct crypto_shash *hash = __crypto_shash_cast(tfm); const char *fallback_driver_name = tfm->__crt_alg->cra_name; + struct padlock_sha_ctx *ctx = crypto_tfm_ctx(tfm); struct crypto_shash *fallback_tfm; int err = -ENOMEM; - /* For now we'll allocate one page. This - * could eventually be configurable one day. */ - ctx(tfm)->data = (char *)__get_free_page(GFP_KERNEL); - if (!ctx(tfm)->data) - goto out; - /* Allocate a fallback and abort if it failed. */ fallback_tfm = crypto_alloc_shash(fallback_driver_name, 0, CRYPTO_ALG_NEED_FALLBACK); @@ -189,94 +197,63 @@ static int padlock_cra_init(struct crypto_tfm *tfm) printk(KERN_WARNING PFX "Fallback driver '%s' could not be loaded!\n", fallback_driver_name); err = PTR_ERR(fallback_tfm); - goto out_free_page; + goto out; } - ctx(tfm)->fallback = kmalloc(sizeof(struct shash_desc) + - crypto_shash_descsize(fallback_tfm), - GFP_KERNEL); - if (!ctx(tfm)->fallback) - goto out_free_tfm; - - ctx(tfm)->fallback->tfm = fallback_tfm; - ctx(tfm)->fallback->flags = 0; + ctx->fallback = fallback_tfm; + hash->descsize += crypto_shash_descsize(fallback_tfm); return 0; -out_free_tfm: - crypto_free_shash(fallback_tfm); -out_free_page: - free_page((unsigned long)(ctx(tfm)->data)); out: return err; } -static int padlock_sha1_cra_init(struct crypto_tfm *tfm) -{ - ctx(tfm)->f_sha_padlock = padlock_do_sha1; - - return padlock_cra_init(tfm); -} - -static int padlock_sha256_cra_init(struct crypto_tfm *tfm) -{ - ctx(tfm)->f_sha_padlock = padlock_do_sha256; - - return padlock_cra_init(tfm); -} - static void padlock_cra_exit(struct crypto_tfm *tfm) { - if (ctx(tfm)->data) { - free_page((unsigned long)(ctx(tfm)->data)); - ctx(tfm)->data = NULL; - } - - crypto_free_shash(ctx(tfm)->fallback->tfm); + struct padlock_sha_ctx *ctx = crypto_tfm_ctx(tfm); - kzfree(ctx(tfm)->fallback); + crypto_free_shash(ctx->fallback); } -static struct crypto_alg sha1_alg = { - .cra_name = "sha1", - .cra_driver_name = "sha1-padlock", - .cra_priority = PADLOCK_CRA_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_DIGEST | - CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = SHA1_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct padlock_sha_ctx), - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(sha1_alg.cra_list), - .cra_init = padlock_sha1_cra_init, - .cra_exit = padlock_cra_exit, - .cra_u = { - .digest = { - .dia_digestsize = SHA1_DIGEST_SIZE, - .dia_init = padlock_sha_init, - .dia_update = padlock_sha_update, - .dia_final = padlock_sha_final, - } +static struct shash_alg sha1_alg = { + .digestsize = SHA1_DIGEST_SIZE, + .init = padlock_sha_init, + .update = padlock_sha_update, + .finup = padlock_sha1_finup, + .final = padlock_sha1_final, + .descsize = sizeof(struct padlock_sha_desc), + .base = { + .cra_name = "sha1", + .cra_driver_name = "sha1-padlock", + .cra_priority = PADLOCK_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SHASH | + CRYPTO_ALG_NEED_FALLBACK, + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct padlock_sha_ctx), + .cra_module = THIS_MODULE, + .cra_init = padlock_cra_init, + .cra_exit = padlock_cra_exit, } }; -static struct crypto_alg sha256_alg = { - .cra_name = "sha256", - .cra_driver_name = "sha256-padlock", - .cra_priority = PADLOCK_CRA_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_DIGEST | - CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = SHA256_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct padlock_sha_ctx), - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(sha256_alg.cra_list), - .cra_init = padlock_sha256_cra_init, - .cra_exit = padlock_cra_exit, - .cra_u = { - .digest = { - .dia_digestsize = SHA256_DIGEST_SIZE, - .dia_init = padlock_sha_init, - .dia_update = padlock_sha_update, - .dia_final = padlock_sha_final, - } +static struct shash_alg sha256_alg = { + .digestsize = SHA256_DIGEST_SIZE, + .init = padlock_sha_init, + .update = padlock_sha_update, + .finup = padlock_sha256_finup, + .final = padlock_sha256_final, + .descsize = sizeof(struct padlock_sha_desc), + .base = { + .cra_name = "sha256", + .cra_driver_name = "sha256-padlock", + .cra_priority = PADLOCK_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SHASH | + CRYPTO_ALG_NEED_FALLBACK, + .cra_blocksize = SHA256_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct padlock_sha_ctx), + .cra_module = THIS_MODULE, + .cra_init = padlock_cra_init, + .cra_exit = padlock_cra_exit, } }; @@ -294,11 +271,11 @@ static int __init padlock_init(void) return -ENODEV; } - rc = crypto_register_alg(&sha1_alg); + rc = crypto_register_shash(&sha1_alg); if (rc) goto out; - rc = crypto_register_alg(&sha256_alg); + rc = crypto_register_shash(&sha256_alg); if (rc) goto out_unreg1; @@ -307,7 +284,7 @@ static int __init padlock_init(void) return 0; out_unreg1: - crypto_unregister_alg(&sha1_alg); + crypto_unregister_shash(&sha1_alg); out: printk(KERN_ERR PFX "VIA PadLock SHA1/SHA256 initialization failed.\n"); return rc; @@ -315,8 +292,8 @@ out: static void __exit padlock_fini(void) { - crypto_unregister_alg(&sha1_alg); - crypto_unregister_alg(&sha256_alg); + crypto_unregister_shash(&sha1_alg); + crypto_unregister_shash(&sha256_alg); } module_init(padlock_init); -- cgit v1.2.3-18-g5258 From 6b1679f4a006acb5d76f8df686aa44c63d2555b4 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 12 Jul 2009 23:08:28 +0800 Subject: crypto: crypto4xx - Use crypto_ahash_set_reqsize This patch makes crypto4xx use crypto_ahash_set_reqsize to avoid accessing crypto_ahash directly. Signed-off-by: Herbert Xu --- drivers/crypto/amcc/crypto4xx_alg.c | 3 ++- drivers/crypto/amcc/crypto4xx_core.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c index 61b6e1bec8c..a33243c17b0 100644 --- a/drivers/crypto/amcc/crypto4xx_alg.c +++ b/drivers/crypto/amcc/crypto4xx_alg.c @@ -208,7 +208,8 @@ static int crypto4xx_hash_alg_init(struct crypto_tfm *tfm, } } - tfm->crt_ahash.reqsize = sizeof(struct crypto4xx_ctx); + crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), + sizeof(struct crypto4xx_ctx)); sa = (struct dynamic_sa_ctl *) ctx->sa_in; set_dynamic_sa_command_0(sa, SA_SAVE_HASH, SA_NOT_SAVE_IV, SA_NOT_LOAD_HASH, SA_LOAD_IV_FROM_SA, diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 4c0dfb2b872..cb7be4283aa 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -1001,7 +1001,8 @@ static int crypto4xx_alg_init(struct crypto_tfm *tfm) if (alg->cra_type == &crypto_ablkcipher_type) tfm->crt_ablkcipher.reqsize = sizeof(struct crypto4xx_ctx); else if (alg->cra_type == &crypto_ahash_type) - tfm->crt_ahash.reqsize = sizeof(struct crypto4xx_ctx); + crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), + sizeof(struct crypto4xx_ctx)); return 0; } -- cgit v1.2.3-18-g5258 From 4dc10c0142ce0af8c20ec44dc6928ae63ad4f73a Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 14 Jul 2009 20:21:46 +0800 Subject: crypto: crypto4xx - Switch to new style ahash This patch changes crypto4xx to use the new style ahash type. In particular, we now use ahash_alg to define ahash algorithms instead of crypto_alg. This is achieved by introducing a union that encapsulates the new type and the existing crypto_alg structure. They're told apart through a u32 field containing the type value. Signed-off-by: Herbert Xu --- drivers/crypto/amcc/crypto4xx_core.c | 85 +++++++++++++++++++++--------------- drivers/crypto/amcc/crypto4xx_core.h | 25 +++++++++-- 2 files changed, 71 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index cb7be4283aa..857e35efeda 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -31,8 +31,6 @@ #include #include #include -#include -#include #include #include #include "crypto4xx_reg_def.h" @@ -998,11 +996,15 @@ static int crypto4xx_alg_init(struct crypto_tfm *tfm) ctx->sa_out_dma_addr = 0; ctx->sa_len = 0; - if (alg->cra_type == &crypto_ablkcipher_type) + switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) { + default: tfm->crt_ablkcipher.reqsize = sizeof(struct crypto4xx_ctx); - else if (alg->cra_type == &crypto_ahash_type) + break; + case CRYPTO_ALG_TYPE_AHASH: crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), sizeof(struct crypto4xx_ctx)); + break; + } return 0; } @@ -1016,7 +1018,8 @@ static void crypto4xx_alg_exit(struct crypto_tfm *tfm) } int crypto4xx_register_alg(struct crypto4xx_device *sec_dev, - struct crypto_alg *crypto_alg, int array_size) + struct crypto4xx_alg_common *crypto_alg, + int array_size) { struct crypto4xx_alg *alg; int i; @@ -1028,13 +1031,18 @@ int crypto4xx_register_alg(struct crypto4xx_device *sec_dev, return -ENOMEM; alg->alg = crypto_alg[i]; - INIT_LIST_HEAD(&alg->alg.cra_list); - if (alg->alg.cra_init == NULL) - alg->alg.cra_init = crypto4xx_alg_init; - if (alg->alg.cra_exit == NULL) - alg->alg.cra_exit = crypto4xx_alg_exit; alg->dev = sec_dev; - rc = crypto_register_alg(&alg->alg); + + switch (alg->alg.type) { + case CRYPTO_ALG_TYPE_AHASH: + rc = crypto_register_ahash(&alg->alg.u.hash); + break; + + default: + rc = crypto_register_alg(&alg->alg.u.cipher); + break; + } + if (rc) { list_del(&alg->entry); kfree(alg); @@ -1052,7 +1060,14 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev) list_for_each_entry_safe(alg, tmp, &sec_dev->alg_list, entry) { list_del(&alg->entry); - crypto_unregister_alg(&alg->alg); + switch (alg->alg.type) { + case CRYPTO_ALG_TYPE_AHASH: + crypto_unregister_ahash(&alg->alg.u.hash); + break; + + default: + crypto_unregister_alg(&alg->alg.u.cipher); + } kfree(alg); } } @@ -1105,17 +1120,18 @@ static irqreturn_t crypto4xx_ce_interrupt_handler(int irq, void *data) /** * Supported Crypto Algorithms */ -struct crypto_alg crypto4xx_alg[] = { +struct crypto4xx_alg_common crypto4xx_alg[] = { /* Crypto AES modes */ - { + { .type = CRYPTO_ALG_TYPE_ABLKCIPHER, .u.cipher = { .cra_name = "cbc(aes)", .cra_driver_name = "cbc-aes-ppc4xx", .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct crypto4xx_ctx), - .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, + .cra_init = crypto4xx_alg_init, + .cra_exit = crypto4xx_alg_exit, .cra_module = THIS_MODULE, .cra_u = { .ablkcipher = { @@ -1127,29 +1143,26 @@ struct crypto_alg crypto4xx_alg[] = { .decrypt = crypto4xx_decrypt, } } - }, + }}, /* Hash SHA1 */ - { - .cra_name = "sha1", - .cra_driver_name = "sha1-ppc4xx", - .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC, - .cra_blocksize = SHA1_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypto4xx_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_ahash_type, - .cra_init = crypto4xx_sha1_alg_init, - .cra_module = THIS_MODULE, - .cra_u = { - .ahash = { - .digestsize = SHA1_DIGEST_SIZE, - .init = crypto4xx_hash_init, - .update = crypto4xx_hash_update, - .final = crypto4xx_hash_final, - .digest = crypto4xx_hash_digest, - } + { .type = CRYPTO_ALG_TYPE_AHASH, .u.hash = { + .init = crypto4xx_hash_init, + .update = crypto4xx_hash_update, + .final = crypto4xx_hash_final, + .digest = crypto4xx_hash_digest, + .halg.digestsize = SHA1_DIGEST_SIZE, + .halg.base = { + .cra_name = "sha1", + .cra_driver_name = "sha1-ppc4xx", + .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, + .cra_flags = CRYPTO_ALG_ASYNC, + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypto4xx_ctx), + .cra_init = crypto4xx_sha1_alg_init, + .cra_exit = crypto4xx_alg_exit, + .cra_module = THIS_MODULE, } - }, + }}, }; /** diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h index 1ef10344936..da9cbe3b9fc 100644 --- a/drivers/crypto/amcc/crypto4xx_core.h +++ b/drivers/crypto/amcc/crypto4xx_core.h @@ -22,6 +22,8 @@ #ifndef __CRYPTO4XX_CORE_H__ #define __CRYPTO4XX_CORE_H__ +#include + #define PPC460SX_SDR0_SRST 0x201 #define PPC405EX_SDR0_SRST 0x200 #define PPC460EX_SDR0_SRST 0x201 @@ -138,14 +140,31 @@ struct crypto4xx_req_ctx { u16 sa_len; }; +struct crypto4xx_alg_common { + u32 type; + union { + struct crypto_alg cipher; + struct ahash_alg hash; + } u; +}; + struct crypto4xx_alg { struct list_head entry; - struct crypto_alg alg; + struct crypto4xx_alg_common alg; struct crypto4xx_device *dev; }; -#define crypto_alg_to_crypto4xx_alg(x) \ - container_of(x, struct crypto4xx_alg, alg) +static inline struct crypto4xx_alg *crypto_alg_to_crypto4xx_alg( + struct crypto_alg *x) +{ + switch (x->cra_flags & CRYPTO_ALG_TYPE_MASK) { + case CRYPTO_ALG_TYPE_AHASH: + return container_of(__crypto_ahash_alg(x), + struct crypto4xx_alg, alg.u.hash); + } + + return container_of(x, struct crypto4xx_alg, alg.u.cipher); +} extern int crypto4xx_alloc_sa(struct crypto4xx_ctx *ctx, u32 size); extern void crypto4xx_free_sa(struct crypto4xx_ctx *ctx); -- cgit v1.2.3-18-g5258 From 305f9db22d62da10c43c7fd7554ec923c2b8727e Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 15 Jul 2009 15:11:08 +0800 Subject: crypto: crypto4xx - Disable SHA implementation The crypto4xx SHA implementation keeps the hash state in the tfm data structure. This breaks a fundamental requirement of ahash implementations that they must be reentrant. This patch disables the broken implementation. Signed-off-by: Herbert Xu --- drivers/crypto/amcc/crypto4xx_core.c | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 857e35efeda..46e899ac924 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -1144,25 +1144,6 @@ struct crypto4xx_alg_common crypto4xx_alg[] = { } } }}, - /* Hash SHA1 */ - { .type = CRYPTO_ALG_TYPE_AHASH, .u.hash = { - .init = crypto4xx_hash_init, - .update = crypto4xx_hash_update, - .final = crypto4xx_hash_final, - .digest = crypto4xx_hash_digest, - .halg.digestsize = SHA1_DIGEST_SIZE, - .halg.base = { - .cra_name = "sha1", - .cra_driver_name = "sha1-ppc4xx", - .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, - .cra_flags = CRYPTO_ALG_ASYNC, - .cra_blocksize = SHA1_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypto4xx_ctx), - .cra_init = crypto4xx_sha1_alg_init, - .cra_exit = crypto4xx_alg_exit, - .cra_module = THIS_MODULE, - } - }}, }; /** -- cgit v1.2.3-18-g5258 From faae890883624e14a328863eafabf54a36698774 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 15 Jul 2009 18:37:48 +0800 Subject: crypto: padlock - Fix compile error on i386 The previous change to allow hashing from states other than the initial broke compilation on i386 because the inline assembly tried to squeeze a u64 into a 32-bit register. As we've already checked for 32-bit overflows we can simply truncate it to u32, or unsigned long so that we don't truncate at all on x86-64. Signed-off-by: Herbert Xu --- drivers/crypto/padlock-sha.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c index fb6e6c34314..a936ba49b39 100644 --- a/drivers/crypto/padlock-sha.c +++ b/drivers/crypto/padlock-sha.c @@ -103,7 +103,8 @@ static int padlock_sha1_finup(struct shash_desc *desc, const u8 *in, ts_state = irq_ts_save(); asm volatile (".byte 0xf3,0x0f,0xa6,0xc8" /* rep xsha1 */ : \ - : "c"(state.count + count), "a"(state.count), \ + : "c"((unsigned long)state.count + count), \ + "a"((unsigned long)state.count), \ "S"(in), "D"(result)); irq_ts_restore(ts_state); @@ -165,7 +166,8 @@ static int padlock_sha256_finup(struct shash_desc *desc, const u8 *in, ts_state = irq_ts_save(); asm volatile (".byte 0xf3,0x0f,0xa6,0xd0" /* rep xsha256 */ : \ - : "c"(state.count + count), "a"(state.count), \ + : "c"((unsigned long)state.count + count), \ + "a"((unsigned long)state.count), \ "S"(in), "D"(result)); irq_ts_restore(ts_state); -- cgit v1.2.3-18-g5258 From c86ae82605ef92594a0de809a8c588ae955fed63 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Jul 2009 11:31:10 -0700 Subject: gianfar: remove unused DECLARE_MAC_BUF The use of it was converted to %pM, but the variable stuck -- remove it now to not cause spurious warnings. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 4ae1d259fce..21f5b0af78c 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -304,7 +304,6 @@ static int gfar_probe(struct of_device *ofdev, u32 tempval; struct net_device *dev = NULL; struct gfar_private *priv = NULL; - DECLARE_MAC_BUF(mac); int err = 0; int len_devname; -- cgit v1.2.3-18-g5258 From e9b25f16cda88b33fe15b30c009912e6c471edda Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 16 Jul 2009 10:33:27 +0800 Subject: crypto: padlock - Fix hashing of partial blocks When we encounter partial blocks in finup, we'll invoke the xsha instruction with a bogus count that is not a multiple of the block size. This patch fixes it. Signed-off-by: Herbert Xu --- drivers/crypto/padlock-sha.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c index a936ba49b39..76cb6b345e7 100644 --- a/drivers/crypto/padlock-sha.c +++ b/drivers/crypto/padlock-sha.c @@ -94,6 +94,7 @@ static int padlock_sha1_finup(struct shash_desc *desc, const u8 *in, memcpy(state.buffer + leftover, in, count); in = state.buffer; count += leftover; + state.count &= ~(SHA1_BLOCK_SIZE - 1); } } @@ -157,6 +158,7 @@ static int padlock_sha256_finup(struct shash_desc *desc, const u8 *in, memcpy(state.buf + leftover, in, count); in = state.buf; count += leftover; + state.count &= ~(SHA1_BLOCK_SIZE - 1); } } -- cgit v1.2.3-18-g5258 From 652f6787c082a174f0bbfa7f895b65b03d8d46c9 Mon Sep 17 00:00:00 2001 From: Wolfgang Denk Date: Fri, 17 Jul 2009 02:27:07 +0000 Subject: fs_enet/mii-fec.c: fix MII speed calculation The MII speed calculation was based on the CPU clock (ppc_proc_freq), but for MPC512x we must use the bus clock instead. This patch makes it use the correct clock and makes sure we don't clobber reserved bits in the MII_SPEED register. Signed-off-by: Wolfgang Denk Cc: Grant Likely Cc: Kumar Gala Cc: Acked-by: Grant Likely Signed-off-by: David S. Miller --- drivers/net/fs_enet/mii-fec.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index 75a09994d66..a2d69c1cd07 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "fs_enet.h" #include "fec.h" @@ -103,11 +104,11 @@ static int fs_enet_fec_mii_reset(struct mii_bus *bus) static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, const struct of_device_id *match) { - struct device_node *np = NULL; struct resource res; struct mii_bus *new_bus; struct fec_info *fec; - int ret = -ENOMEM, i; + int (*get_bus_freq)(struct device_node *) = match->data; + int ret = -ENOMEM, clock, speed; new_bus = mdiobus_alloc(); if (!new_bus) @@ -133,13 +134,35 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, if (!fec->fecp) goto out_fec; - fec->mii_speed = ((ppc_proc_freq + 4999999) / 5000000) << 1; + if (get_bus_freq) { + clock = get_bus_freq(ofdev->node); + if (!clock) { + /* Use maximum divider if clock is unknown */ + dev_warn(&ofdev->dev, "could not determine IPS clock\n"); + clock = 0x3F * 5000000; + } + } else + clock = ppc_proc_freq; + + /* + * Scale for a MII clock <= 2.5 MHz + * Note that only 6 bits (25:30) are available for MII speed. + */ + speed = (clock + 4999999) / 5000000; + if (speed > 0x3F) { + speed = 0x3F; + dev_err(&ofdev->dev, + "MII clock (%d Hz) exceeds max (2.5 MHz)\n", + clock / speed); + } + + fec->mii_speed = speed << 1; setbits32(&fec->fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE); setbits32(&fec->fecp->fec_ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); out_be32(&fec->fecp->fec_ievent, FEC_ENET_MII); - out_be32(&fec->fecp->fec_mii_speed, fec->mii_speed); + clrsetbits_be32(&fec->fecp->fec_mii_speed, 0x7E, fec->mii_speed); new_bus->phy_mask = ~0; new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); @@ -188,6 +211,12 @@ static struct of_device_id fs_enet_mdio_fec_match[] = { { .compatible = "fsl,pq1-fec-mdio", }, +#if defined(CONFIG_PPC_MPC512x) + { + .compatible = "fsl,mpc5121-fec-mdio", + .data = mpc5xxx_get_bus_frequency, + }, +#endif {}, }; -- cgit v1.2.3-18-g5258 From f4ec443b2b27ecb401eee35a7bea330438556c7e Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Thu, 16 Jul 2009 15:50:12 +0000 Subject: ixgbe: Remove legacy descriptor support The ethtool offline test is the only consumer of the legacy descriptors. Update that path to only use advanced descriptors, and remove all support for legacy descriptors. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe.h | 4 ---- drivers/net/ixgbe/ixgbe_ethtool.c | 33 +++++++++++++++++++-------------- drivers/net/ixgbe/ixgbe_type.h | 31 ------------------------------- 3 files changed, 19 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index cd22323cfd2..2a93e116f5a 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -229,10 +229,6 @@ struct ixgbe_q_vector { #define IXGBE_TX_CTXTDESC_ADV(R, i) \ (&(((struct ixgbe_adv_tx_context_desc *)((R).desc))[i])) -#define IXGBE_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i])) -#define IXGBE_TX_DESC(R, i) IXGBE_GET_DESC(R, i, ixgbe_legacy_tx_desc) -#define IXGBE_RX_DESC(R, i) IXGBE_GET_DESC(R, i, ixgbe_legacy_rx_desc) - #define IXGBE_MAX_JUMBO_FRAME_SIZE 16128 #ifdef IXGBE_FCOE /* Use 3K as the baby jumbo frame size for FCoE */ diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 2a978008fd6..1464b33f1b8 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -1440,7 +1440,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter) goto err_nomem; } - tx_ring->size = tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc); + tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc); tx_ring->size = ALIGN(tx_ring->size, 4096); if (!(tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size, &tx_ring->dma))) { @@ -1454,7 +1454,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDBAH(0), ((u64) tx_ring->dma >> 32)); IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDLEN(0), - tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc)); + tx_ring->count * sizeof(union ixgbe_adv_tx_desc)); IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDH(0), 0); IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(0), 0); @@ -1472,7 +1472,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(&adapter->hw, IXGBE_TXDCTL(0), reg_data); for (i = 0; i < tx_ring->count; i++) { - struct ixgbe_legacy_tx_desc *desc = IXGBE_TX_DESC(*tx_ring, i); + union ixgbe_adv_tx_desc *desc = IXGBE_TX_DESC_ADV(*tx_ring, i); struct sk_buff *skb; unsigned int size = 1024; @@ -1486,13 +1486,18 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter) tx_ring->tx_buffer_info[i].length = skb->len; tx_ring->tx_buffer_info[i].dma = pci_map_single(pdev, skb->data, skb->len, - PCI_DMA_TODEVICE); - desc->buffer_addr = cpu_to_le64(tx_ring->tx_buffer_info[i].dma); - desc->lower.data = cpu_to_le32(skb->len); - desc->lower.data |= cpu_to_le32(IXGBE_TXD_CMD_EOP | - IXGBE_TXD_CMD_IFCS | - IXGBE_TXD_CMD_RS); - desc->upper.data = 0; + PCI_DMA_TODEVICE); + desc->read.buffer_addr = + cpu_to_le64(tx_ring->tx_buffer_info[i].dma); + desc->read.cmd_type_len = cpu_to_le32(skb->len); + desc->read.cmd_type_len |= cpu_to_le32(IXGBE_TXD_CMD_EOP | + IXGBE_TXD_CMD_IFCS | + IXGBE_TXD_CMD_RS); + desc->read.olinfo_status = 0; + if (adapter->hw.mac.type == ixgbe_mac_82599EB) + desc->read.olinfo_status |= + (skb->len << IXGBE_ADVTXD_PAYLEN_SHIFT); + } /* Setup Rx Descriptor ring and Rx buffers */ @@ -1508,7 +1513,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter) goto err_nomem; } - rx_ring->size = rx_ring->count * sizeof(struct ixgbe_legacy_rx_desc); + rx_ring->size = rx_ring->count * sizeof(union ixgbe_adv_rx_desc); rx_ring->size = ALIGN(rx_ring->size, 4096); if (!(rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size, &rx_ring->dma))) { @@ -1566,8 +1571,8 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rctl); for (i = 0; i < rx_ring->count; i++) { - struct ixgbe_legacy_rx_desc *rx_desc = - IXGBE_RX_DESC(*rx_ring, i); + union ixgbe_adv_rx_desc *rx_desc = + IXGBE_RX_DESC_ADV(*rx_ring, i); struct sk_buff *skb; skb = alloc_skb(IXGBE_RXBUFFER_2048 + NET_IP_ALIGN, GFP_KERNEL); @@ -1580,7 +1585,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter) rx_ring->rx_buffer_info[i].dma = pci_map_single(pdev, skb->data, IXGBE_RXBUFFER_2048, PCI_DMA_FROMDEVICE); - rx_desc->buffer_addr = + rx_desc->read.pkt_addr = cpu_to_le64(rx_ring->rx_buffer_info[i].dma); memset(skb->data, 0x00, skb->len); } diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index fa87309dc08..8fb6ade0c62 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1893,27 +1893,6 @@ enum ixgbe_fdir_pballoc_type { #define IXGBE_FDIR_INIT_DONE_POLL 10 #define IXGBE_FDIRCMD_CMD_POLL 10 -/* Transmit Descriptor - Legacy */ -struct ixgbe_legacy_tx_desc { - u64 buffer_addr; /* Address of the descriptor's data buffer */ - union { - __le32 data; - struct { - __le16 length; /* Data buffer length */ - u8 cso; /* Checksum offset */ - u8 cmd; /* Descriptor control */ - } flags; - } lower; - union { - __le32 data; - struct { - u8 status; /* Descriptor status */ - u8 css; /* Checksum start */ - __le16 vlan; - } fields; - } upper; -}; - /* Transmit Descriptor - Advanced */ union ixgbe_adv_tx_desc { struct { @@ -1928,16 +1907,6 @@ union ixgbe_adv_tx_desc { } wb; }; -/* Receive Descriptor - Legacy */ -struct ixgbe_legacy_rx_desc { - __le64 buffer_addr; /* Address of the descriptor's data buffer */ - __le16 length; /* Length of data DMAed into data buffer */ - __le16 csum; /* Packet checksum */ - u8 status; /* Descriptor status */ - u8 errors; /* Descriptor Errors */ - __le16 vlan; -}; - /* Receive Descriptor - Advanced */ union ixgbe_adv_rx_desc { struct { -- cgit v1.2.3-18-g5258 From 078788b6a68828c1caf395b48110535e051cd623 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Thu, 16 Jul 2009 15:50:32 +0000 Subject: ixgbe: Make sure boolean assignments from bitwise operations done correctly When the link comes up, the driver detects which flow control settings are active. This is done using bitwise operations directly from the hardware registers, and assumes the proper boolean assignment. Make this an explicit boolean value before assignment to the bool. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index e3442f47f93..09394c14ee5 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -4643,13 +4643,13 @@ static void ixgbe_watchdog_task(struct work_struct *work) if (hw->mac.type == ixgbe_mac_82599EB) { u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN); u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG); - flow_rx = (mflcn & IXGBE_MFLCN_RFCE); - flow_tx = (fccfg & IXGBE_FCCFG_TFCE_802_3X); + flow_rx = !!(mflcn & IXGBE_MFLCN_RFCE); + flow_tx = !!(fccfg & IXGBE_FCCFG_TFCE_802_3X); } else { u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL); u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS); - flow_rx = (frctl & IXGBE_FCTRL_RFCE); - flow_tx = (rmcs & IXGBE_RMCS_TFCE_802_3X); + flow_rx = !!(frctl & IXGBE_FCTRL_RFCE); + flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X); } printk(KERN_INFO "ixgbe: %s NIC Link is Up %s, " -- cgit v1.2.3-18-g5258 From 3845bec0f33f7c2604ba985f6f80983d0c139d46 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Thu, 16 Jul 2009 15:50:52 +0000 Subject: ixgbe: Add device support for a new copper 82598 device This adds support for a new copper device for 82598, device id 0x150b. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_82598.c | 1 + drivers/net/ixgbe/ixgbe_main.c | 2 ++ drivers/net/ixgbe/ixgbe_type.h | 1 + 3 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index b9923047ce1..ed0bb3b2025 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -269,6 +269,7 @@ static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw) media_type = ixgbe_media_type_fiber; break; case IXGBE_DEV_ID_82598AT: + case IXGBE_DEV_ID_82598AT2: media_type = ixgbe_media_type_copper; break; default: diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 09394c14ee5..a3bbcfd8471 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -74,6 +74,8 @@ static struct pci_device_id ixgbe_pci_tbl[] = { board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT), board_82598 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT2), + board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4), board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT), diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 8fb6ade0c62..17ee3890a0a 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -42,6 +42,7 @@ #define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7 #define IXGBE_DEV_ID_82598EB_SFP_LOM 0x10DB #define IXGBE_DEV_ID_82598AT 0x10C8 +#define IXGBE_DEV_ID_82598AT2 0x150B #define IXGBE_DEV_ID_82598EB_CX4 0x10DD #define IXGBE_DEV_ID_82598_CX4_DUAL_PORT 0x10EC #define IXGBE_DEV_ID_82598_DA_DUAL_PORT 0x10F1 -- cgit v1.2.3-18-g5258 From bbf50e4df11ea5b9d2f625be2a1cea3ec0352890 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Thu, 16 Jul 2009 15:51:11 +0000 Subject: ixgbe: Bump version number Keep the version number marching along as updates come in. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index a3bbcfd8471..79f60e86973 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -48,7 +48,7 @@ char ixgbe_driver_name[] = "ixgbe"; static const char ixgbe_driver_string[] = "Intel(R) 10 Gigabit PCI Express Network Driver"; -#define DRV_VERSION "2.0.34-k2" +#define DRV_VERSION "2.0.37-k2" const char ixgbe_driver_version[] = DRV_VERSION; static char ixgbe_copyright[] = "Copyright (c) 1999-2009 Intel Corporation."; -- cgit v1.2.3-18-g5258 From 5c5167515d80f78f6bb538492c423adcae31ad65 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Tue, 14 Jul 2009 14:21:02 +0000 Subject: virtio-net: Allow UFO feature to be set and advertised. - Allow setting UFO on virtio-net and advertise to host. Signed-off-by: Sridhar Samudrala Acked-by: Rusty Russell Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 2a6e81d5b57..a6f903f0092 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -774,6 +774,7 @@ static struct ethtool_ops virtnet_ethtool_ops = { .set_tx_csum = virtnet_set_tx_csum, .set_sg = ethtool_op_set_sg, .set_tso = ethtool_op_set_tso, + .set_ufo = ethtool_op_set_ufo, .get_link = ethtool_op_get_link, }; @@ -1005,7 +1006,7 @@ static unsigned int features[] = { VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC, VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, - VIRTIO_NET_F_GUEST_ECN, /* We don't yet handle UFO input. */ + VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO, VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, VIRTIO_F_NOTIFY_ON_EMPTY, -- cgit v1.2.3-18-g5258 From e36aa25a533962b08402530e8443ac804a454e27 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Tue, 14 Jul 2009 14:21:04 +0000 Subject: tun: Allow tap device to send/receive UFO packets. - Allow setting UFO on tap device and handle UFO packets. Signed-off-by: Sridhar Samudrala --------------------------------------------------------- Signed-off-by: David S. Miller --- drivers/net/tun.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index dfc1054e4cb..a998b6a9c24 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -641,6 +641,9 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, case VIRTIO_NET_HDR_GSO_TCPV6: skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; break; + case VIRTIO_NET_HDR_GSO_UDP: + skb_shinfo(skb)->gso_type = SKB_GSO_UDP; + break; default: tun->dev->stats.rx_frame_errors++; kfree_skb(skb); @@ -726,6 +729,8 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV4; else if (sinfo->gso_type & SKB_GSO_TCPV6) gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6; + else if (sinfo->gso_type & SKB_GSO_UDP) + gso.gso_type = VIRTIO_NET_HDR_GSO_UDP; else BUG(); if (sinfo->gso_type & SKB_GSO_TCP_ECN) @@ -1073,7 +1078,8 @@ static int set_offload(struct net_device *dev, unsigned long arg) old_features = dev->features; /* Unset features, set them as we chew on the arg. */ features = (old_features & ~(NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST - |NETIF_F_TSO_ECN|NETIF_F_TSO|NETIF_F_TSO6)); + |NETIF_F_TSO_ECN|NETIF_F_TSO|NETIF_F_TSO6 + |NETIF_F_UFO)); if (arg & TUN_F_CSUM) { features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; @@ -1090,6 +1096,11 @@ static int set_offload(struct net_device *dev, unsigned long arg) features |= NETIF_F_TSO6; arg &= ~(TUN_F_TSO4|TUN_F_TSO6); } + + if (arg & TUN_F_UFO) { + features |= NETIF_F_UFO; + arg &= ~TUN_F_UFO; + } } /* This gives the user a way to test for new features in future by -- cgit v1.2.3-18-g5258 From 0741241c6b80bfd58417e95de984d60c9e9ef2a0 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 17 Jul 2009 10:13:21 -0700 Subject: connector: make callback argument type explicit The connector documentation states that the argument to the callback function is always a pointer to a struct cn_msg, but rather than encode it in the API itself, it uses a void pointer everywhere. This doesn't make much sense to encode the pointer in documentation as it prevents proper C type checking from occurring and can easily allow people to use the wrong pointer type. So convert the argument type to an explicit struct cn_msg pointer. Signed-off-by: Mike Frysinger Signed-off-by: David S. Miller --- drivers/connector/cn_proc.c | 3 +-- drivers/connector/cn_queue.c | 7 +++++-- drivers/connector/connector.c | 6 +++--- drivers/staging/dst/dcore.c | 3 +-- drivers/video/uvesafb.c | 3 +-- drivers/w1/w1_netlink.c | 3 +-- 6 files changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c index c5afc98e267..85e5dc0431f 100644 --- a/drivers/connector/cn_proc.c +++ b/drivers/connector/cn_proc.c @@ -202,9 +202,8 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack) * cn_proc_mcast_ctl * @data: message sent from userspace via the connector */ -static void cn_proc_mcast_ctl(void *data) +static void cn_proc_mcast_ctl(struct cn_msg *msg) { - struct cn_msg *msg = data; enum proc_cn_mcast_op *mc_op = NULL; int err = 0; diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c index c769ef269fb..d478aefcd3b 100644 --- a/drivers/connector/cn_queue.c +++ b/drivers/connector/cn_queue.c @@ -87,7 +87,9 @@ void cn_queue_wrapper(struct work_struct *work) kfree(d->free); } -static struct cn_callback_entry *cn_queue_alloc_callback_entry(char *name, struct cb_id *id, void (*callback)(void *)) +static struct cn_callback_entry * +cn_queue_alloc_callback_entry(char *name, struct cb_id *id, + void (*callback)(struct cn_msg *)) { struct cn_callback_entry *cbq; @@ -120,7 +122,8 @@ int cn_cb_equal(struct cb_id *i1, struct cb_id *i2) return ((i1->idx == i2->idx) && (i1->val == i2->val)); } -int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(void *)) +int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, + void (*callback)(struct cn_msg *)) { struct cn_callback_entry *cbq, *__cbq; int found = 0; diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index fd336c5a905..3f45669f5d7 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -269,7 +269,8 @@ static void cn_notify(struct cb_id *id, u32 notify_event) * * May sleep. */ -int cn_add_callback(struct cb_id *id, char *name, void (*callback)(void *)) +int cn_add_callback(struct cb_id *id, char *name, + void (*callback)(struct cn_msg *)) { int err; struct cn_dev *dev = &cdev; @@ -351,9 +352,8 @@ static int cn_ctl_msg_equals(struct cn_ctl_msg *m1, struct cn_ctl_msg *m2) * * Used for notification of a request's processing. */ -static void cn_callback(void *data) +static void cn_callback(struct cn_msg *msg) { - struct cn_msg *msg = data; struct cn_ctl_msg *ctl; struct cn_ctl_entry *ent; u32 size; diff --git a/drivers/staging/dst/dcore.c b/drivers/staging/dst/dcore.c index fad25b75304..84724187ec3 100644 --- a/drivers/staging/dst/dcore.c +++ b/drivers/staging/dst/dcore.c @@ -846,10 +846,9 @@ static dst_command_func dst_commands[] = { /* * Configuration parser. */ -static void cn_dst_callback(void *data) +static void cn_dst_callback(struct cn_msg *msg) { struct dst_ctl *ctl; - struct cn_msg *msg = data; int err; struct dst_ctl_ack ack; struct dst_node *n = NULL, *tmp; diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index ca5b4643a40..e98baf6916b 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -67,9 +67,8 @@ static DEFINE_MUTEX(uvfb_lock); * find the kernel part of the task struct, copy the registers and * the buffer contents and then complete the task. */ -static void uvesafb_cn_callback(void *data) +static void uvesafb_cn_callback(struct cn_msg *msg) { - struct cn_msg *msg = data; struct uvesafb_task *utask; struct uvesafb_ktask *task; diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index fdf72851c57..52ccb3d3a96 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c @@ -306,9 +306,8 @@ static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rm return error; } -static void w1_cn_callback(void *data) +static void w1_cn_callback(struct cn_msg *msg) { - struct cn_msg *msg = data; struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1); struct w1_netlink_cmd *cmd; struct w1_slave *sl; -- cgit v1.2.3-18-g5258 From bff78650a2b0ed42b8fb134b6a9b387e00027d67 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sat, 18 Jul 2009 10:12:28 +0100 Subject: ARM: HWMON: S3C24XX series ADC driver Add support for the ADC controller on the S3C series of processors to drivers/hwmon for use with hardware monitoring systems. Signed-off-by: Ben Dooks Acked-by: Jean Delvare Signed-off-by: Ben Dooks --- drivers/hwmon/Kconfig | 17 ++ drivers/hwmon/Makefile | 1 + drivers/hwmon/s3c-hwmon.c | 405 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 423 insertions(+) create mode 100644 drivers/hwmon/s3c-hwmon.c (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 2d5016691d4..2e25b7a827d 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -702,6 +702,23 @@ config SENSORS_SHT15 This driver can also be built as a module. If so, the module will be called sht15. +config SENSORS_S3C + tristate "S3C24XX/S3C64XX Inbuilt ADC" + depends on ARCH_S3C2410 || ARCH_S3C64XX + help + If you say yes here you get support for the on-board ADCs of + the Samsung S3C24XX or S3C64XX series of SoC + + This driver can also be built as a module. If so, the module + will be called s3c-hwmo. + +config SENSORS_S3C_RAW + bool "Include raw channel attributes in sysfs" + depends on SENSORS_S3C + help + Say Y here if you want to include raw copies of all the ADC + channels in sysfs. + config SENSORS_SIS5595 tristate "Silicon Integrated Systems Corp. SiS5595" depends on PCI diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index b793dce6bed..7f239a247c3 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -76,6 +76,7 @@ obj-$(CONFIG_SENSORS_MAX6650) += max6650.o obj-$(CONFIG_SENSORS_PC87360) += pc87360.o obj-$(CONFIG_SENSORS_PC87427) += pc87427.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o +obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o obj-$(CONFIG_SENSORS_SHT15) += sht15.o obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c new file mode 100644 index 00000000000..3a524f2fe49 --- /dev/null +++ b/drivers/hwmon/s3c-hwmon.c @@ -0,0 +1,405 @@ +/* linux/drivers/hwmon/s3c-hwmon.c + * + * Copyright (C) 2005, 2008, 2009 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks + * + * S3C24XX/S3C64XX ADC hwmon support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +struct s3c_hwmon_attr { + struct sensor_device_attribute in; + struct sensor_device_attribute label; + char in_name[12]; + char label_name[12]; +}; + +/** + * struct s3c_hwmon - ADC hwmon client information + * @lock: Access lock to serialise the conversions. + * @client: The client we registered with the S3C ADC core. + * @hwmon_dev: The hwmon device we created. + * @attr: The holders for the channel attributes. +*/ +struct s3c_hwmon { + struct semaphore lock; + struct s3c_adc_client *client; + struct device *hwmon_dev; + + struct s3c_hwmon_attr attrs[8]; +}; + +/** + * s3c_hwmon_read_ch - read a value from a given adc channel. + * @dev: The device. + * @hwmon: Our state. + * @channel: The channel we're reading from. + * + * Read a value from the @channel with the proper locking and sleep until + * either the read completes or we timeout awaiting the ADC core to get + * back to us. + */ +static int s3c_hwmon_read_ch(struct device *dev, + struct s3c_hwmon *hwmon, int channel) +{ + int ret; + + ret = down_interruptible(&hwmon->lock); + if (ret < 0) + return ret; + + dev_dbg(dev, "reading channel %d\n", channel); + + ret = s3c_adc_read(hwmon->client, channel); + up(&hwmon->lock); + + return ret; +} + +#ifdef CONFIG_SENSORS_S3C_RAW +/** + * s3c_hwmon_show_raw - show a conversion from the raw channel number. + * @dev: The device that the attribute belongs to. + * @attr: The attribute being read. + * @buf: The result buffer. + * + * This show deals with the raw attribute, registered for each possible + * ADC channel. This does a conversion and returns the raw (un-scaled) + * value returned from the hardware. + */ +static ssize_t s3c_hwmon_show_raw(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct s3c_hwmon *adc = platform_get_drvdata(to_platform_device(dev)); + struct sensor_device_attribute *sa = to_sensor_dev_attr(attr); + int ret; + + ret = s3c_hwmon_read_ch(dev, adc, sa->index); + + return (ret < 0) ? ret : snprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +#define DEF_ADC_ATTR(x) \ + static SENSOR_DEVICE_ATTR(adc##x##_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, x) + +DEF_ADC_ATTR(0); +DEF_ADC_ATTR(1); +DEF_ADC_ATTR(2); +DEF_ADC_ATTR(3); +DEF_ADC_ATTR(4); +DEF_ADC_ATTR(5); +DEF_ADC_ATTR(6); +DEF_ADC_ATTR(7); + +static struct attribute *s3c_hwmon_attrs[9] = { + &sensor_dev_attr_adc0_raw.dev_attr.attr, + &sensor_dev_attr_adc1_raw.dev_attr.attr, + &sensor_dev_attr_adc2_raw.dev_attr.attr, + &sensor_dev_attr_adc3_raw.dev_attr.attr, + &sensor_dev_attr_adc4_raw.dev_attr.attr, + &sensor_dev_attr_adc5_raw.dev_attr.attr, + &sensor_dev_attr_adc6_raw.dev_attr.attr, + &sensor_dev_attr_adc7_raw.dev_attr.attr, + NULL, +}; + +static struct attribute_group s3c_hwmon_attrgroup = { + .attrs = s3c_hwmon_attrs, +}; + +static inline int s3c_hwmon_add_raw(struct device *dev) +{ + return sysfs_create_group(&dev->kobj, &s3c_hwmon_attrgroup); +} + +static inline void s3c_hwmon_remove_raw(struct device *dev) +{ + sysfs_remove_group(&dev->kobj, &s3c_hwmon_attrgroup); +} + +#else + +static inline int s3c_hwmon_add_raw(struct device *dev) { return 0; } +static inline void s3c_hwmon_remove_raw(struct device *dev) { } + +#endif /* CONFIG_SENSORS_S3C_RAW */ + +/** + * s3c_hwmon_ch_show - show value of a given channel + * @dev: The device that the attribute belongs to. + * @attr: The attribute being read. + * @buf: The result buffer. + * + * Read a value from the ADC and scale it before returning it to the + * caller. The scale factor is gained from the channel configuration + * passed via the platform data when the device was registered. + */ +static ssize_t s3c_hwmon_ch_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr); + struct s3c_hwmon *hwmon = platform_get_drvdata(to_platform_device(dev)); + struct s3c_hwmon_pdata *pdata = dev->platform_data; + struct s3c_hwmon_chcfg *cfg; + int ret; + + cfg = pdata->in[sen_attr->index]; + + ret = s3c_hwmon_read_ch(dev, hwmon, sen_attr->index); + if (ret < 0) + return ret; + + ret *= cfg->mult; + ret = DIV_ROUND_CLOSEST(ret, cfg->div); + + return snprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +/** + * s3c_hwmon_label_show - show label name of the given channel. + * @dev: The device that the attribute belongs to. + * @attr: The attribute being read. + * @buf: The result buffer. + * + * Return the label name of a given channel + */ +static ssize_t s3c_hwmon_label_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr); + struct s3c_hwmon_pdata *pdata = dev->platform_data; + struct s3c_hwmon_chcfg *cfg; + + cfg = pdata->in[sen_attr->index]; + + return snprintf(buf, PAGE_SIZE, "%s\n", cfg->name); +} + +/** + * s3c_hwmon_create_attr - create hwmon attribute for given channel. + * @dev: The device to create the attribute on. + * @cfg: The channel configuration passed from the platform data. + * @channel: The ADC channel number to process. + * + * Create the scaled attribute for use with hwmon from the specified + * platform data in @pdata. The sysfs entry is handled by the routine + * s3c_hwmon_ch_show(). + * + * The attribute name is taken from the configuration data if present + * otherwise the name is taken by concatenating in_ with the channel + * number. + */ +static int s3c_hwmon_create_attr(struct device *dev, + struct s3c_hwmon_chcfg *cfg, + struct s3c_hwmon_attr *attrs, + int channel) +{ + struct sensor_device_attribute *attr; + int ret; + + snprintf(attrs->in_name, sizeof(attrs->in_name), "in%d_input", channel); + + attr = &attrs->in; + attr->index = channel; + attr->dev_attr.attr.name = attrs->in_name; + attr->dev_attr.attr.mode = S_IRUGO; + attr->dev_attr.attr.owner = THIS_MODULE; + attr->dev_attr.show = s3c_hwmon_ch_show; + + ret = device_create_file(dev, &attr->dev_attr); + if (ret < 0) { + dev_err(dev, "failed to create input attribute\n"); + return ret; + } + + /* if this has a name, add a label */ + if (cfg->name) { + snprintf(attrs->label_name, sizeof(attrs->label_name), + "in%d_label", channel); + + attr = &attrs->label; + attr->index = channel; + attr->dev_attr.attr.name = attrs->label_name; + attr->dev_attr.attr.mode = S_IRUGO; + attr->dev_attr.attr.owner = THIS_MODULE; + attr->dev_attr.show = s3c_hwmon_label_show; + + ret = device_create_file(dev, &attr->dev_attr); + if (ret < 0) { + device_remove_file(dev, &attrs->in.dev_attr); + dev_err(dev, "failed to create label attribute\n"); + } + } + + return ret; +} + +static void s3c_hwmon_remove_attr(struct device *dev, + struct s3c_hwmon_attr *attrs) +{ + device_remove_file(dev, &attrs->in.dev_attr); + device_remove_file(dev, &attrs->label.dev_attr); +} + +/** + * s3c_hwmon_probe - device probe entry. + * @dev: The device being probed. +*/ +static int __devinit s3c_hwmon_probe(struct platform_device *dev) +{ + struct s3c_hwmon_pdata *pdata = dev->dev.platform_data; + struct s3c_hwmon *hwmon; + int ret = 0; + int i; + + if (!pdata) { + dev_err(&dev->dev, "no platform data supplied\n"); + return -EINVAL; + } + + hwmon = kzalloc(sizeof(struct s3c_hwmon), GFP_KERNEL); + if (hwmon == NULL) { + dev_err(&dev->dev, "no memory\n"); + return -ENOMEM; + } + + platform_set_drvdata(dev, hwmon); + + init_MUTEX(&hwmon->lock); + + /* Register with the core ADC driver. */ + + hwmon->client = s3c_adc_register(dev, NULL, NULL, 0); + if (IS_ERR(hwmon->client)) { + dev_err(&dev->dev, "cannot register adc\n"); + ret = PTR_ERR(hwmon->client); + goto err_mem; + } + + /* add attributes for our adc devices. */ + + ret = s3c_hwmon_add_raw(&dev->dev); + if (ret) + goto err_registered; + + /* register with the hwmon core */ + + hwmon->hwmon_dev = hwmon_device_register(&dev->dev); + if (IS_ERR(hwmon->hwmon_dev)) { + dev_err(&dev->dev, "error registering with hwmon\n"); + ret = PTR_ERR(hwmon->hwmon_dev); + goto err_raw_attribute; + } + + for (i = 0; i < ARRAY_SIZE(pdata->in); i++) { + if (!pdata->in[i]) + continue; + + if (pdata->in[i]->mult >= 0x10000) + dev_warn(&dev->dev, + "channel %d multiplier too large\n", + i); + + ret = s3c_hwmon_create_attr(&dev->dev, pdata->in[i], + &hwmon->attrs[i], i); + if (ret) { + dev_err(&dev->dev, + "error creating channel %d\n", i); + + for (i--; i >= 0; i--) + s3c_hwmon_remove_attr(&dev->dev, + &hwmon->attrs[i]); + + goto err_hwmon_register; + } + } + + return 0; + + err_hwmon_register: + hwmon_device_unregister(hwmon->hwmon_dev); + + err_raw_attribute: + s3c_hwmon_remove_raw(&dev->dev); + + err_registered: + s3c_adc_release(hwmon->client); + + err_mem: + kfree(hwmon); + return ret; +} + +static int __devexit s3c_hwmon_remove(struct platform_device *dev) +{ + struct s3c_hwmon *hwmon = platform_get_drvdata(dev); + int i; + + s3c_hwmon_remove_raw(&dev->dev); + + for (i = 0; i < ARRAY_SIZE(hwmon->attrs); i++) + s3c_hwmon_remove_attr(&dev->dev, &hwmon->attrs[i]); + + hwmon_device_unregister(hwmon->hwmon_dev); + s3c_adc_release(hwmon->client); + + return 0; +} + +static struct platform_driver s3c_hwmon_driver = { + .driver = { + .name = "s3c-hwmon", + .owner = THIS_MODULE, + }, + .probe = s3c_hwmon_probe, + .remove = __devexit_p(s3c_hwmon_remove), +}; + +static int __init s3c_hwmon_init(void) +{ + return platform_driver_register(&s3c_hwmon_driver); +} + +static void __exit s3c_hwmon_exit(void) +{ + platform_driver_unregister(&s3c_hwmon_driver); +} + +module_init(s3c_hwmon_init); +module_exit(s3c_hwmon_exit); + +MODULE_AUTHOR("Ben Dooks "); +MODULE_DESCRIPTION("S3C ADC HWMon driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:s3c-hwmon"); -- cgit v1.2.3-18-g5258 From 57594742a2b545f8f114cda34f15650be8ae976d Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 19 Jul 2009 00:11:06 +0900 Subject: x86: Introduce set_desc_base() and set_desc_limit() Rename set_base()/set_limit to set_desc_base()/set_desc_limit() and rewrite them in C. These are naturally introduced by the idea of get_desc_base()/get_desc_limit(). The conversion actually found the bug in apm_32.c: bad_bios_desc is written at run-time, but it is defined const variable. Signed-off-by: Akinobu Mita LKML-Reference: <20090718151105.GC11294@localhost.localdomain> Signed-off-by: Ingo Molnar --- drivers/pnp/pnpbios/bioscalls.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c index 7e6b5a3b328..45ad3e9cc36 100644 --- a/drivers/pnp/pnpbios/bioscalls.c +++ b/drivers/pnp/pnpbios/bioscalls.c @@ -55,9 +55,9 @@ __asm__(".text \n" #define Q2_SET_SEL(cpu, selname, address, size) \ do { \ -struct desc_struct *gdt = get_cpu_gdt_table((cpu)); \ -set_base(gdt[(selname) >> 3], (u32)(address)); \ -set_limit(gdt[(selname) >> 3], size); \ + struct desc_struct *gdt = get_cpu_gdt_table((cpu)); \ + set_desc_base(&gdt[(selname) >> 3], (u32)(address)); \ + set_desc_limit(&gdt[(selname) >> 3], (size) - 1); \ } while(0) static struct desc_struct bad_bios_desc; @@ -479,16 +479,17 @@ void pnpbios_calls_init(union pnp_bios_install_struct *header) bad_bios_desc.a = 0; bad_bios_desc.b = 0x00409200; - set_base(bad_bios_desc, __va((unsigned long)0x40 << 4)); - _set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4)); + set_desc_base(&bad_bios_desc, (unsigned long)__va(0x40UL << 4)); + set_desc_limit(&bad_bios_desc, 4095 - (0x40 << 4)); for_each_possible_cpu(i) { struct desc_struct *gdt = get_cpu_gdt_table(i); if (!gdt) continue; - set_base(gdt[GDT_ENTRY_PNPBIOS_CS32], &pnp_bios_callfunc); - set_base(gdt[GDT_ENTRY_PNPBIOS_CS16], - __va(header->fields.pm16cseg)); - set_base(gdt[GDT_ENTRY_PNPBIOS_DS], - __va(header->fields.pm16dseg)); + set_desc_base(&gdt[GDT_ENTRY_PNPBIOS_CS32], + (unsigned long)&pnp_bios_callfunc); + set_desc_base(&gdt[GDT_ENTRY_PNPBIOS_CS16], + (unsigned long)__va(header->fields.pm16cseg)); + set_desc_base(&gdt[GDT_ENTRY_PNPBIOS_DS], + (unsigned long)__va(header->fields.pm16dseg)); } } -- cgit v1.2.3-18-g5258 From 4d4036e0e7299c6cbb2d2421b4b30b7a409ce61a Mon Sep 17 00:00:00 2001 From: Jason Yeh Date: Wed, 8 Jul 2009 13:49:38 +0200 Subject: oprofile: Implement performance counter multiplexing The number of hardware counters is limited. The multiplexing feature enables OProfile to gather more events than counters are provided by the hardware. This is realized by switching between events at an user specified time interval. A new file (/dev/oprofile/time_slice) is added for the user to specify the timer interval in ms. If the number of events to profile is higher than the number of hardware counters available, the patch will schedule a work queue that switches the event counter and re-writes the different sets of values into it. The switching mechanism needs to be implemented for each architecture to support multiplexing. This patch only implements AMD CPU support, but multiplexing can be easily extended for other models and architectures. There are follow-on patches that rework parts of this patch. Signed-off-by: Jason Yeh Signed-off-by: Robert Richter --- drivers/oprofile/oprof.c | 78 +++++++++++++++++++++++++++++++++++++++ drivers/oprofile/oprof.h | 2 + drivers/oprofile/oprofile_files.c | 43 +++++++++++++++++++++ drivers/oprofile/oprofile_stats.c | 10 +++++ 4 files changed, 133 insertions(+) (limited to 'drivers') diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index 3cffce90f82..7bc64af7cf9 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include "oprof.h" @@ -27,6 +29,15 @@ unsigned long oprofile_backtrace_depth; static unsigned long is_setup; static DEFINE_MUTEX(start_mutex); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static void switch_worker(struct work_struct *work); +static DECLARE_DELAYED_WORK(switch_work, switch_worker); +unsigned long timeout_jiffies; +#define MULTIPLEXING_TIMER_DEFAULT 1 + +#endif + /* timer 0 - use performance monitoring hardware if available 1 - use the timer int mechanism regardless @@ -87,6 +98,20 @@ out: return err; } +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static void start_switch_worker(void) +{ + schedule_delayed_work(&switch_work, timeout_jiffies); +} + +static void switch_worker(struct work_struct *work) +{ + if (!oprofile_ops.switch_events()) + start_switch_worker(); +} + +#endif /* Actually start profiling (echo 1>/dev/oprofile/enable) */ int oprofile_start(void) @@ -108,6 +133,11 @@ int oprofile_start(void) if ((err = oprofile_ops.start())) goto out; +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + if (oprofile_ops.switch_events) + start_switch_worker(); +#endif + oprofile_started = 1; out: mutex_unlock(&start_mutex); @@ -123,6 +153,11 @@ void oprofile_stop(void) goto out; oprofile_ops.stop(); oprofile_started = 0; + +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + cancel_delayed_work_sync(&switch_work); +#endif + /* wake up the daemon to read what remains */ wake_up_buffer_waiter(); out: @@ -155,6 +190,36 @@ post_sync: mutex_unlock(&start_mutex); } +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +/* User inputs in ms, converts to jiffies */ +int oprofile_set_timeout(unsigned long val_msec) +{ + int err = 0; + + mutex_lock(&start_mutex); + + if (oprofile_started) { + err = -EBUSY; + goto out; + } + + if (!oprofile_ops.switch_events) { + err = -EINVAL; + goto out; + } + + timeout_jiffies = msecs_to_jiffies(val_msec); + if (timeout_jiffies == MAX_JIFFY_OFFSET) + timeout_jiffies = msecs_to_jiffies(MULTIPLEXING_TIMER_DEFAULT); + +out: + mutex_unlock(&start_mutex); + return err; + +} + +#endif int oprofile_set_backtrace(unsigned long val) { @@ -179,10 +244,23 @@ out: return err; } +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static void __init oprofile_multiplexing_init(void) +{ + timeout_jiffies = msecs_to_jiffies(MULTIPLEXING_TIMER_DEFAULT); +} + +#endif + static int __init oprofile_init(void) { int err; +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + oprofile_multiplexing_init(); +#endif + err = oprofile_arch_init(&oprofile_ops); if (err < 0 || timer) { diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h index c288d3c24b5..ee38abcc74f 100644 --- a/drivers/oprofile/oprof.h +++ b/drivers/oprofile/oprof.h @@ -27,6 +27,7 @@ extern unsigned long oprofile_buffer_watershed; extern struct oprofile_operations oprofile_ops; extern unsigned long oprofile_started; extern unsigned long oprofile_backtrace_depth; +extern unsigned long timeout_jiffies; struct super_block; struct dentry; @@ -35,5 +36,6 @@ void oprofile_create_files(struct super_block *sb, struct dentry *root); void oprofile_timer_init(struct oprofile_operations *ops); int oprofile_set_backtrace(unsigned long depth); +int oprofile_set_timeout(unsigned long time); #endif /* OPROF_H */ diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index 5d36ffc30dd..468ec3e4f85 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -9,6 +9,7 @@ #include #include +#include #include "event_buffer.h" #include "oprofile_stats.h" @@ -22,6 +23,45 @@ unsigned long oprofile_buffer_size; unsigned long oprofile_cpu_buffer_size; unsigned long oprofile_buffer_watershed; +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + +static ssize_t timeout_read(struct file *file, char __user *buf, + size_t count, loff_t *offset) +{ + return oprofilefs_ulong_to_user(jiffies_to_msecs(timeout_jiffies), + buf, count, offset); +} + + +static ssize_t timeout_write(struct file *file, char const __user *buf, + size_t count, loff_t *offset) +{ + unsigned long val; + int retval; + + if (*offset) + return -EINVAL; + + retval = oprofilefs_ulong_from_user(&val, buf, count); + if (retval) + return retval; + + retval = oprofile_set_timeout(val); + + if (retval) + return retval; + return count; +} + + +static const struct file_operations timeout_fops = { + .read = timeout_read, + .write = timeout_write, +}; + +#endif + + static ssize_t depth_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { return oprofilefs_ulong_to_user(oprofile_backtrace_depth, buf, count, @@ -139,6 +179,9 @@ void oprofile_create_files(struct super_block *sb, struct dentry *root) oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops); oprofilefs_create_file(sb, root, "backtrace_depth", &depth_fops); oprofilefs_create_file(sb, root, "pointer_size", &pointer_size_fops); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + oprofilefs_create_file(sb, root, "time_slice", &timeout_fops); +#endif oprofile_create_stats_files(sb, root); if (oprofile_ops.create_files) oprofile_ops.create_files(sb, root); diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c index 3c2270a8300..77a57a6792f 100644 --- a/drivers/oprofile/oprofile_stats.c +++ b/drivers/oprofile/oprofile_stats.c @@ -16,6 +16,9 @@ #include "cpu_buffer.h" struct oprofile_stat_struct oprofile_stats; +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX +atomic_t multiplex_counter; +#endif void oprofile_reset_stats(void) { @@ -34,6 +37,9 @@ void oprofile_reset_stats(void) atomic_set(&oprofile_stats.sample_lost_no_mapping, 0); atomic_set(&oprofile_stats.event_lost_overflow, 0); atomic_set(&oprofile_stats.bt_lost_no_mapping, 0); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + atomic_set(&multiplex_counter, 0); +#endif } @@ -76,4 +82,8 @@ void oprofile_create_stats_files(struct super_block *sb, struct dentry *root) &oprofile_stats.event_lost_overflow); oprofilefs_create_ro_atomic(sb, dir, "bt_lost_no_mapping", &oprofile_stats.bt_lost_no_mapping); +#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX + oprofilefs_create_ro_atomic(sb, dir, "multiplex_counter", + &multiplex_counter); +#endif } -- cgit v1.2.3-18-g5258 From 2051cade7ccbe45a8bf8b7809d56b23d6d75ad03 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 15 Jul 2009 15:44:18 +0200 Subject: oprofile: oprofile_set_timeout(), return with error for invalid args Return with -EINVAL for invalid parameters instead of setting the default value in oprofile_set_timeout(). Signed-off-by: Robert Richter --- drivers/oprofile/oprof.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index 7bc64af7cf9..42c9c765f9f 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -196,6 +196,7 @@ post_sync: int oprofile_set_timeout(unsigned long val_msec) { int err = 0; + unsigned long time_slice; mutex_lock(&start_mutex); @@ -209,9 +210,13 @@ int oprofile_set_timeout(unsigned long val_msec) goto out; } - timeout_jiffies = msecs_to_jiffies(val_msec); - if (timeout_jiffies == MAX_JIFFY_OFFSET) - timeout_jiffies = msecs_to_jiffies(MULTIPLEXING_TIMER_DEFAULT); + time_slice = msecs_to_jiffies(val_msec); + if (time_slice == MAX_JIFFY_OFFSET) { + err = -EINVAL; + goto out; + } + + timeout_jiffies = time_slice; out: mutex_unlock(&start_mutex); -- cgit v1.2.3-18-g5258 From afe1b50fe6aa56093e9234bdc08779e9fe20b5bf Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 15 Jul 2009 15:19:29 +0200 Subject: oprofile: Rename variable timeout_jiffies and move to oprofile_files.c This patch renames timeout_jiffies into an oprofile specific name. The macro MULTIPLEXING_TIMER_DEFAULT is changed too. Also, since this variable is controlled using oprofilefs, its definition is moved to oprofile_files.c. Signed-off-by: Robert Richter --- drivers/oprofile/oprof.c | 9 ++++----- drivers/oprofile/oprof.h | 3 ++- drivers/oprofile/oprofile_files.c | 5 +++-- 3 files changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index 42c9c765f9f..2b33de71641 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -33,8 +33,7 @@ static DEFINE_MUTEX(start_mutex); static void switch_worker(struct work_struct *work); static DECLARE_DELAYED_WORK(switch_work, switch_worker); -unsigned long timeout_jiffies; -#define MULTIPLEXING_TIMER_DEFAULT 1 +#define TIME_SLICE_DEFAULT 1 #endif @@ -102,7 +101,7 @@ out: static void start_switch_worker(void) { - schedule_delayed_work(&switch_work, timeout_jiffies); + schedule_delayed_work(&switch_work, oprofile_time_slice); } static void switch_worker(struct work_struct *work) @@ -216,7 +215,7 @@ int oprofile_set_timeout(unsigned long val_msec) goto out; } - timeout_jiffies = time_slice; + oprofile_time_slice = time_slice; out: mutex_unlock(&start_mutex); @@ -253,7 +252,7 @@ out: static void __init oprofile_multiplexing_init(void) { - timeout_jiffies = msecs_to_jiffies(MULTIPLEXING_TIMER_DEFAULT); + oprofile_time_slice = msecs_to_jiffies(TIME_SLICE_DEFAULT); } #endif diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h index ee38abcc74f..cb92f5c98c1 100644 --- a/drivers/oprofile/oprof.h +++ b/drivers/oprofile/oprof.h @@ -24,10 +24,11 @@ struct oprofile_operations; extern unsigned long oprofile_buffer_size; extern unsigned long oprofile_cpu_buffer_size; extern unsigned long oprofile_buffer_watershed; +extern unsigned long oprofile_time_slice; + extern struct oprofile_operations oprofile_ops; extern unsigned long oprofile_started; extern unsigned long oprofile_backtrace_depth; -extern unsigned long timeout_jiffies; struct super_block; struct dentry; diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index 468ec3e4f85..4c5b9477584 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -22,14 +22,15 @@ unsigned long oprofile_buffer_size; unsigned long oprofile_cpu_buffer_size; unsigned long oprofile_buffer_watershed; +unsigned long oprofile_time_slice; #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX static ssize_t timeout_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { - return oprofilefs_ulong_to_user(jiffies_to_msecs(timeout_jiffies), - buf, count, offset); + return oprofilefs_ulong_to_user(jiffies_to_msecs(oprofile_time_slice), + buf, count, offset); } -- cgit v1.2.3-18-g5258 From 16422a6e2d16a39861ae5b0b11d9b411a245ab83 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 15 Jul 2009 15:44:18 +0200 Subject: oprofile: Remove oprofile_multiplexing_init() oprofile_multiplexing_init() can be removed when moving the initialization of oprofile_time_slice to oprofile_create_files(). Signed-off-by: Robert Richter --- drivers/oprofile/oprof.c | 14 -------------- drivers/oprofile/oprofile_files.c | 2 ++ 2 files changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index 2b33de71641..fa6cccd87cf 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -33,7 +33,6 @@ static DEFINE_MUTEX(start_mutex); static void switch_worker(struct work_struct *work); static DECLARE_DELAYED_WORK(switch_work, switch_worker); -#define TIME_SLICE_DEFAULT 1 #endif @@ -248,23 +247,10 @@ out: return err; } -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - -static void __init oprofile_multiplexing_init(void) -{ - oprofile_time_slice = msecs_to_jiffies(TIME_SLICE_DEFAULT); -} - -#endif - static int __init oprofile_init(void) { int err; -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - oprofile_multiplexing_init(); -#endif - err = oprofile_arch_init(&oprofile_ops); if (err < 0 || timer) { diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index 4c5b9477584..bbd7516e086 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -18,6 +18,7 @@ #define BUFFER_SIZE_DEFAULT 131072 #define CPU_BUFFER_SIZE_DEFAULT 8192 #define BUFFER_WATERSHED_DEFAULT 32768 /* FIXME: tune */ +#define TIME_SLICE_DEFAULT 1 unsigned long oprofile_buffer_size; unsigned long oprofile_cpu_buffer_size; @@ -170,6 +171,7 @@ void oprofile_create_files(struct super_block *sb, struct dentry *root) oprofile_buffer_size = BUFFER_SIZE_DEFAULT; oprofile_cpu_buffer_size = CPU_BUFFER_SIZE_DEFAULT; oprofile_buffer_watershed = BUFFER_WATERSHED_DEFAULT; + oprofile_time_slice = msecs_to_jiffies(TIME_SLICE_DEFAULT); oprofilefs_create_file(sb, root, "enable", &enable_fops); oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666); -- cgit v1.2.3-18-g5258 From a5659d17adb815fb35e11745e2f39c3f0bfd579f Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 19 Jun 2009 16:45:34 +0200 Subject: oprofile: Grouping multiplexing code in oprof.c This patch moves multiplexing code to a single section of code. This reduces the use of #ifdefs especially within functions. Signed-off-by: Robert Richter --- drivers/oprofile/oprof.c | 100 +++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index fa6cccd87cf..a48294a8ebe 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -29,13 +29,6 @@ unsigned long oprofile_backtrace_depth; static unsigned long is_setup; static DEFINE_MUTEX(start_mutex); -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - -static void switch_worker(struct work_struct *work); -static DECLARE_DELAYED_WORK(switch_work, switch_worker); - -#endif - /* timer 0 - use performance monitoring hardware if available 1 - use the timer int mechanism regardless @@ -98,9 +91,18 @@ out: #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX +static void switch_worker(struct work_struct *work); +static DECLARE_DELAYED_WORK(switch_work, switch_worker); + static void start_switch_worker(void) { - schedule_delayed_work(&switch_work, oprofile_time_slice); + if (oprofile_ops.switch_events) + schedule_delayed_work(&switch_work, oprofile_time_slice); +} + +static void stop_switch_worker(void) +{ + cancel_delayed_work_sync(&switch_work); } static void switch_worker(struct work_struct *work) @@ -109,6 +111,43 @@ static void switch_worker(struct work_struct *work) start_switch_worker(); } +/* User inputs in ms, converts to jiffies */ +int oprofile_set_timeout(unsigned long val_msec) +{ + int err = 0; + unsigned long time_slice; + + mutex_lock(&start_mutex); + + if (oprofile_started) { + err = -EBUSY; + goto out; + } + + if (!oprofile_ops.switch_events) { + err = -EINVAL; + goto out; + } + + time_slice = msecs_to_jiffies(val_msec); + if (time_slice == MAX_JIFFY_OFFSET) { + err = -EINVAL; + goto out; + } + + oprofile_time_slice = time_slice; + +out: + mutex_unlock(&start_mutex); + return err; + +} + +#else + +static inline void start_switch_worker(void) { } +static inline void stop_switch_worker(void) { } + #endif /* Actually start profiling (echo 1>/dev/oprofile/enable) */ @@ -131,10 +170,7 @@ int oprofile_start(void) if ((err = oprofile_ops.start())) goto out; -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - if (oprofile_ops.switch_events) - start_switch_worker(); -#endif + start_switch_worker(); oprofile_started = 1; out: @@ -152,9 +188,7 @@ void oprofile_stop(void) oprofile_ops.stop(); oprofile_started = 0; -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - cancel_delayed_work_sync(&switch_work); -#endif + stop_switch_worker(); /* wake up the daemon to read what remains */ wake_up_buffer_waiter(); @@ -188,42 +222,6 @@ post_sync: mutex_unlock(&start_mutex); } -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - -/* User inputs in ms, converts to jiffies */ -int oprofile_set_timeout(unsigned long val_msec) -{ - int err = 0; - unsigned long time_slice; - - mutex_lock(&start_mutex); - - if (oprofile_started) { - err = -EBUSY; - goto out; - } - - if (!oprofile_ops.switch_events) { - err = -EINVAL; - goto out; - } - - time_slice = msecs_to_jiffies(val_msec); - if (time_slice == MAX_JIFFY_OFFSET) { - err = -EINVAL; - goto out; - } - - oprofile_time_slice = time_slice; - -out: - mutex_unlock(&start_mutex); - return err; - -} - -#endif - int oprofile_set_backtrace(unsigned long val) { int err = 0; -- cgit v1.2.3-18-g5258 From 1b294f5960cd89e49eeb3e797860c552b03f2272 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 9 Jul 2009 14:56:25 +0200 Subject: oprofile: Adding switch counter to oprofile statistic variables This patch moves the multiplexing switch counter from x86 code to common oprofile statistic variables. Now the value will be available and usable for all architectures. The initialization and incrementation also moved to common code. Signed-off-by: Robert Richter --- drivers/oprofile/oprof.c | 7 +++++-- drivers/oprofile/oprofile_stats.c | 9 ++------- drivers/oprofile/oprofile_stats.h | 1 + 3 files changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index a48294a8ebe..dc8a0428260 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -107,8 +107,11 @@ static void stop_switch_worker(void) static void switch_worker(struct work_struct *work) { - if (!oprofile_ops.switch_events()) - start_switch_worker(); + if (oprofile_ops.switch_events()) + return; + + atomic_inc(&oprofile_stats.multiplex_counter); + start_switch_worker(); } /* User inputs in ms, converts to jiffies */ diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c index 77a57a6792f..61689e814d4 100644 --- a/drivers/oprofile/oprofile_stats.c +++ b/drivers/oprofile/oprofile_stats.c @@ -16,9 +16,6 @@ #include "cpu_buffer.h" struct oprofile_stat_struct oprofile_stats; -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX -atomic_t multiplex_counter; -#endif void oprofile_reset_stats(void) { @@ -37,9 +34,7 @@ void oprofile_reset_stats(void) atomic_set(&oprofile_stats.sample_lost_no_mapping, 0); atomic_set(&oprofile_stats.event_lost_overflow, 0); atomic_set(&oprofile_stats.bt_lost_no_mapping, 0); -#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - atomic_set(&multiplex_counter, 0); -#endif + atomic_set(&oprofile_stats.multiplex_counter, 0); } @@ -84,6 +79,6 @@ void oprofile_create_stats_files(struct super_block *sb, struct dentry *root) &oprofile_stats.bt_lost_no_mapping); #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX oprofilefs_create_ro_atomic(sb, dir, "multiplex_counter", - &multiplex_counter); + &oprofile_stats.multiplex_counter); #endif } diff --git a/drivers/oprofile/oprofile_stats.h b/drivers/oprofile/oprofile_stats.h index 3da0d08dc1f..0b54e46c3c1 100644 --- a/drivers/oprofile/oprofile_stats.h +++ b/drivers/oprofile/oprofile_stats.h @@ -17,6 +17,7 @@ struct oprofile_stat_struct { atomic_t sample_lost_no_mapping; atomic_t bt_lost_no_mapping; atomic_t event_lost_overflow; + atomic_t multiplex_counter; }; extern struct oprofile_stat_struct oprofile_stats; -- cgit v1.2.3-18-g5258 From 27e0955184a70c4bd4542ee2da18c749b4f43345 Mon Sep 17 00:00:00 2001 From: roel kluin Date: Fri, 17 Jul 2009 08:01:54 +0000 Subject: b44: strncpy does not null terminate string strlcpy() will always null terminate the string. Also use the sizeof(version) to strlcopy() the version string. Signed-off-by: Roel Kluin Signed-off-by: David S. Miller --- drivers/net/b44.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 36d4d377ec2..1f7f015442d 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1756,15 +1756,15 @@ static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *inf struct b44 *bp = netdev_priv(dev); struct ssb_bus *bus = bp->sdev->bus; - strncpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); - strncpy(info->version, DRV_MODULE_VERSION, sizeof(info->driver)); + strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); + strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version)); switch (bus->bustype) { case SSB_BUSTYPE_PCI: - strncpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info)); + strlcpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info)); break; case SSB_BUSTYPE_PCMCIA: case SSB_BUSTYPE_SSB: - strncpy(info->bus_info, "SSB", sizeof(info->bus_info)); + strlcpy(info->bus_info, "SSB", sizeof(info->bus_info)); break; } } -- cgit v1.2.3-18-g5258 From b833306febc7d9b805a89aff29f1e410a64981c4 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 20 Jul 2009 22:26:37 -0700 Subject: Input: wm97xx - add Palm support to Mainstone accelerated touch This patch refactors the Mainstone accelerated touch code a little and adds support for interrupt driven touchscreen on Palm LifeDrive, TX and Tungsten T5. Signed-off-by: Marek Vasut Acked-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 4 +-- drivers/input/touchscreen/mainstone-wm97xx.c | 50 ++++++++++++++++++---------- 2 files changed, 35 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 1c05b3286d6..07703bcb64c 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -366,11 +366,11 @@ config TOUCHSCREEN_WM97XX_ATMEL be called atmel-wm97xx. config TOUCHSCREEN_WM97XX_MAINSTONE - tristate "WM97xx Mainstone accelerated touch" + tristate "WM97xx Mainstone/Palm accelerated touch" depends on TOUCHSCREEN_WM97XX && ARCH_PXA help Say Y here for support for streaming mode with WM97xx touchscreens - on Mainstone systems. + on Mainstone, Palm Tungsten T5, TX and LifeDrive systems. If unsure, say N. diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c index 4cc047a5116..c797bc04ee8 100644 --- a/drivers/input/touchscreen/mainstone-wm97xx.c +++ b/drivers/input/touchscreen/mainstone-wm97xx.c @@ -31,9 +31,11 @@ #include #include #include +#include + #include -#define VERSION "0.13" +#include struct continuous { u16 id; /* codec id */ @@ -62,6 +64,7 @@ static const struct continuous cinfo[] = { /* continuous speed index */ static int sp_idx; static u16 last, tries; +static int irq; /* * Pen sampling frequency (Hz) in continuous mode. @@ -171,7 +174,7 @@ up: static int wm97xx_acc_startup(struct wm97xx *wm) { - int idx = 0; + int idx = 0, ret = 0; /* check we have a codec */ if (wm->ac97 == NULL) @@ -191,18 +194,37 @@ static int wm97xx_acc_startup(struct wm97xx *wm) "mainstone accelerated touchscreen driver, %d samples/sec\n", cinfo[sp_idx].speed); + /* IRQ driven touchscreen is used on Palm hardware */ + if (machine_is_palmt5() || machine_is_palmtx() || machine_is_palmld()) { + pen_int = 1; + irq = 27; + } else if (machine_is_mainstone() && pen_int) + irq = 4; + + if (irq) { + ret = gpio_request(irq, "Touchscreen IRQ"); + if (ret) + goto out; + + ret = gpio_direction_input(irq); + if (ret) { + gpio_free(irq); + goto out; + } + + wm->pen_irq = gpio_to_irq(irq); + set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH); + } else /* pen irq not supported */ + pen_int = 0; + /* codec specific irq config */ if (pen_int) { switch (wm->id) { case WM9705_ID2: - wm->pen_irq = IRQ_GPIO(4); - set_irq_type(IRQ_GPIO(4), IRQ_TYPE_EDGE_BOTH); break; case WM9712_ID2: case WM9713_ID2: - /* enable pen down interrupt */ /* use PEN_DOWN GPIO 13 to assert IRQ on GPIO line 2 */ - wm->pen_irq = MAINSTONE_AC97_IRQ; wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN, WM97XX_GPIO_POL_HIGH, WM97XX_GPIO_STICKY, @@ -220,23 +242,17 @@ static int wm97xx_acc_startup(struct wm97xx *wm) } } - return 0; +out: + return ret; } static void wm97xx_acc_shutdown(struct wm97xx *wm) { /* codec specific deconfig */ if (pen_int) { - switch (wm->id & 0xffff) { - case WM9705_ID2: - wm->pen_irq = 0; - break; - case WM9712_ID2: - case WM9713_ID2: - /* disable interrupt */ - wm->pen_irq = 0; - break; - } + if (irq) + gpio_free(irq); + wm->pen_irq = 0; } } -- cgit v1.2.3-18-g5258 From 99fde513f57db2c8e1b202ade4be7d47033ff09b Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 20 Jul 2009 22:28:50 -0700 Subject: Input: wm97xx - add possibility to control the GPIO_STATUS shift This patch allows tweaking the behaviour of GPIO_STATUS register shift quirk that's in wm97xx-core. The problem with GPIO_STATUS register being shifted by one doesn't appear on all hardware it seems and causes problems with accelerated touchscreen drivers on Palm hardware. Therefore an accelerated touchscreen driver can select if the shift is/isn't happening on the hardware. Signed-off-by: Marek Vasut Acked-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/mainstone-wm97xx.c | 3 +++ drivers/input/touchscreen/wm97xx-core.c | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c index c797bc04ee8..8fc3b08deb3 100644 --- a/drivers/input/touchscreen/mainstone-wm97xx.c +++ b/drivers/input/touchscreen/mainstone-wm97xx.c @@ -198,6 +198,9 @@ static int wm97xx_acc_startup(struct wm97xx *wm) if (machine_is_palmt5() || machine_is_palmtx() || machine_is_palmld()) { pen_int = 1; irq = 27; + /* There is some obscure mutant of WM9712 interbred with WM9713 + * used on Palm HW */ + wm->variant = WM97xx_WM1613; } else if (machine_is_mainstone() && pen_int) irq = 4; diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index 2957d48e004..252eb11fe9d 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -204,7 +204,7 @@ void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio, else reg &= ~gpio; - if (wm->id == WM9712_ID2) + if (wm->id == WM9712_ID2 && wm->variant != WM97xx_WM1613) wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg << 1); else wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg); @@ -307,7 +307,7 @@ static void wm97xx_pen_irq_worker(struct work_struct *work) WM97XX_GPIO_13); } - if (wm->id == WM9712_ID2) + if (wm->id == WM9712_ID2 && wm->variant != WM97xx_WM1613) wm97xx_reg_write(wm, AC97_GPIO_STATUS, (status & ~WM97XX_GPIO_13) << 1); else @@ -582,6 +582,8 @@ static int wm97xx_probe(struct device *dev) wm->id = wm97xx_reg_read(wm, AC97_VENDOR_ID2); + wm->variant = WM97xx_GENERIC; + dev_info(wm->dev, "detected a wm97%02x codec\n", wm->id & 0xff); switch (wm->id & 0xff) { -- cgit v1.2.3-18-g5258 From 24d01c0681bfbc10a99304c48a89ad213d2d7a4b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 21 Jul 2009 01:12:12 -0700 Subject: Input: sh_keysc - allow modifying keymap from userspace Adjust the driver so EVIOCGKEYCODE/EVIOCSKEYCODE work. Acked-by: Magnus Damm Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/sh_keysc.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index cea70e6a103..0714bf2c28f 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -128,7 +128,7 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev) struct resource *res; struct input_dev *input; char clk_name[8]; - int i, k; + int i; int irq, error; if (!pdev->dev.platform_data) { @@ -195,17 +195,19 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev) input->id.product = 0x0001; input->id.version = 0x0100; + input->keycode = pdata->keycodes; + input->keycodesize = sizeof(pdata->keycodes[0]); + input->keycodemax = ARRAY_SIZE(pdata->keycodes); + error = request_irq(irq, sh_keysc_isr, 0, pdev->name, pdev); if (error) { dev_err(&pdev->dev, "failed to request IRQ\n"); goto err4; } - for (i = 0; i < SH_KEYSC_MAXKEYS; i++) { - k = pdata->keycodes[i]; - if (k) - input_set_capability(input, EV_KEY, k); - } + for (i = 0; i < SH_KEYSC_MAXKEYS; i++) + __set_bit(pdata->keycodes[i], input->keybit); + __clear_bit(KEY_RESERVED, input->keybit); error = input_register_device(input); if (error) { @@ -221,7 +223,9 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev) iowrite16(KYCR2_IRQ_LEVEL, priv->iomem_base + KYCR2_OFFS); device_init_wakeup(&pdev->dev, 1); + return 0; + err5: free_irq(irq, pdev); err4: @@ -252,6 +256,7 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); kfree(priv); + return 0; } @@ -267,11 +272,12 @@ static int sh_keysc_suspend(struct device *dev) if (device_may_wakeup(dev)) { value |= 0x80; enable_irq_wake(irq); - } - else + } else { value &= ~0x80; + } iowrite16(value, priv->iomem_base + KYCR1_OFFS); + return 0; } -- cgit v1.2.3-18-g5258 From 279abdf59c766a06db89b50c6d3615b4f2b19ed3 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Tue, 21 Jul 2009 05:47:22 +0000 Subject: bnx2x: Stop management traffic in loopback test Since management traffic cannot go on the wire while configured to loopback, simply stop it to avoid race condition when the MAC is set to loopback in the middle of a packet Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 11 +++++++++++ drivers/net/bnx2x_reg.h | 2 ++ 2 files changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 6c67be67976..177cb467ba9 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -9691,8 +9691,15 @@ static void bnx2x_self_test(struct net_device *dev, etest->flags &= ~ETH_TEST_FL_OFFLINE; if (etest->flags & ETH_TEST_FL_OFFLINE) { + int port = BP_PORT(bp); + u32 val; u8 link_up; + /* save current value of input enable for TX port IF */ + val = REG_RD(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4); + /* disable input for TX port IF */ + REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, 0); + link_up = bp->link_vars.link_up; bnx2x_nic_unload(bp, UNLOAD_NORMAL); bnx2x_nic_load(bp, LOAD_DIAG); @@ -9712,6 +9719,10 @@ static void bnx2x_self_test(struct net_device *dev, etest->flags |= ETH_TEST_FL_FAILED; bnx2x_nic_unload(bp, UNLOAD_NORMAL); + + /* restore input for TX port IF */ + REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, val); + bnx2x_nic_load(bp, LOAD_NORMAL); /* wait until link state is restored */ bnx2x_wait_for_link(bp, link_up); diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h index b8ce6fc927a..6d77730b6b4 100644 --- a/drivers/net/bnx2x_reg.h +++ b/drivers/net/bnx2x_reg.h @@ -1660,6 +1660,8 @@ #define NIG_REG_EGRESS_PBF0_IN_EN 0x100cc /* [RW 1] Input enable for TX PBF user packet port1 IF */ #define NIG_REG_EGRESS_PBF1_IN_EN 0x100d0 +/* [RW 1] Input enable for TX UMP management packet port0 IF */ +#define NIG_REG_EGRESS_UMP0_IN_EN 0x100d4 /* [RW 1] Input enable for RX_EMAC0 IF */ #define NIG_REG_EMAC0_IN_EN 0x100a4 /* [RW 1] output enable for TX EMAC pause port 0 IF */ -- cgit v1.2.3-18-g5258 From fd4ef40d5977e1c226e9cd9659398e82cc4a1e85 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Tue, 21 Jul 2009 05:47:27 +0000 Subject: bnx2x: Fan failure Setup fan failure for different PHY types or according to nvram settings Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_hsi.h | 15 +++++++ drivers/net/bnx2x_main.c | 112 +++++++++++++++++++++++++++++++---------------- 2 files changed, 90 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x_hsi.h index 03c62421d99..41c6dcb9618 100644 --- a/drivers/net/bnx2x_hsi.h +++ b/drivers/net/bnx2x_hsi.h @@ -91,6 +91,21 @@ struct shared_hw_cfg { /* NVRAM Offset */ #define SHARED_HW_CFG_HIDE_PORT1 0x00002000 + /* The fan failure mechanism is usually related to the PHY type + since the power consumption of the board is determined by the PHY. + Currently, fan is required for most designs with SFX7101, BCM8727 + and BCM8481. If a fan is not required for a board which uses one + of those PHYs, this field should be set to "Disabled". If a fan is + required for a different PHY type, this option should be set to + "Enabled". + The fan failure indication is expected on + SPIO5 */ +#define SHARED_HW_CFG_FAN_FAILURE_MASK 0x00180000 +#define SHARED_HW_CFG_FAN_FAILURE_SHIFT 19 +#define SHARED_HW_CFG_FAN_FAILURE_PHY_TYPE 0x00000000 +#define SHARED_HW_CFG_FAN_FAILURE_DISABLED 0x00080000 +#define SHARED_HW_CFG_FAN_FAILURE_ENABLED 0x00100000 + u32 power_dissipated; /* 0x11c */ #define SHARED_HW_CFG_POWER_DIS_CMN_MASK 0xff000000 #define SHARED_HW_CFG_POWER_DIS_CMN_SHIFT 24 diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 177cb467ba9..ae8b7b517ea 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -2598,6 +2598,22 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted) } } +static inline void bnx2x_fan_failure(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + + /* mark the failure */ + bp->link_params.ext_phy_config &= ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK; + bp->link_params.ext_phy_config |= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE; + SHMEM_WR(bp, dev_info.port_hw_config[port].external_phy_config, + bp->link_params.ext_phy_config); + + /* log the failure */ + printk(KERN_ERR PFX "Fan Failure on Network Controller %s has caused" + " the driver to shutdown the card to prevent permanent" + " damage. Please contact Dell Support for assistance\n", + bp->dev->name); +} static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) { int port = BP_PORT(bp); @@ -2615,36 +2631,21 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) BNX2X_ERR("SPIO5 hw attention\n"); + /* Fan failure attention */ switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) { case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: - /* Fan failure attention */ - - /* The PHY reset is controlled by GPIO 1 */ - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_OUTPUT_LOW, port); /* Low power mode is controlled by GPIO 2 */ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, MISC_REGISTERS_GPIO_OUTPUT_LOW, port); - /* mark the failure */ - bp->link_params.ext_phy_config &= - ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK; - bp->link_params.ext_phy_config |= - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE; - SHMEM_WR(bp, - dev_info.port_hw_config[port]. - external_phy_config, - bp->link_params.ext_phy_config); - /* log the failure */ - printk(KERN_ERR PFX "Fan Failure on Network" - " Controller %s has caused the driver to" - " shutdown the card to prevent permanent" - " damage. Please contact Dell Support for" - " assistance\n", bp->dev->name); + /* The PHY reset is controlled by GPIO 1 */ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, + MISC_REGISTERS_GPIO_OUTPUT_LOW, port); break; default: break; } + bnx2x_fan_failure(bp); } if (attn & (AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 | @@ -5509,6 +5510,58 @@ static void bnx2x_reset_common(struct bnx2x *bp) REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, 0x1403); } + +static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp) +{ + u32 val; + u8 port; + u8 is_required = 0; + + val = SHMEM_RD(bp, dev_info.shared_hw_config.config2) & + SHARED_HW_CFG_FAN_FAILURE_MASK; + + if (val == SHARED_HW_CFG_FAN_FAILURE_ENABLED) + is_required = 1; + + /* + * The fan failure mechanism is usually related to the PHY type since + * the power consumption of the board is affected by the PHY. Currently, + * fan is required for most designs with SFX7101, BCM8727 and BCM8481. + */ + else if (val == SHARED_HW_CFG_FAN_FAILURE_PHY_TYPE) + for (port = PORT_0; port < PORT_MAX; port++) { + u32 phy_type = + SHMEM_RD(bp, dev_info.port_hw_config[port]. + external_phy_config) & + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK; + is_required |= + ((phy_type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) || + (phy_type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481)); + } + + DP(NETIF_MSG_HW, "fan detection setting: %d\n", is_required); + + if (is_required == 0) + return; + + /* Fan failure is indicated by SPIO 5 */ + bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5, + MISC_REGISTERS_SPIO_INPUT_HI_Z); + + /* set to active low mode */ + val = REG_RD(bp, MISC_REG_SPIO_INT); + val |= ((1 << MISC_REGISTERS_SPIO_5) << + MISC_REGISTERS_SPIO_INT_OLD_SET_POS); + REG_WR(bp, MISC_REG_SPIO_INT, val); + + /* enable interrupt to signal the IGU */ + val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN); + val |= (1 << MISC_REGISTERS_SPIO_5); + REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val); +} + static int bnx2x_init_common(struct bnx2x *bp) { u32 val, i; @@ -5738,27 +5791,12 @@ static int bnx2x_init_common(struct bnx2x *bp) bp->port.need_hw_lock = 1; break; - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: - /* Fan failure is indicated by SPIO 5 */ - bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5, - MISC_REGISTERS_SPIO_INPUT_HI_Z); - - /* set to active low mode */ - val = REG_RD(bp, MISC_REG_SPIO_INT); - val |= ((1 << MISC_REGISTERS_SPIO_5) << - MISC_REGISTERS_SPIO_INT_OLD_SET_POS); - REG_WR(bp, MISC_REG_SPIO_INT, val); - - /* enable interrupt to signal the IGU */ - val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN); - val |= (1 << MISC_REGISTERS_SPIO_5); - REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val); - break; - default: break; } + bnx2x_setup_fan_failure_detection(bp); + /* clear PXP2 attentions */ REG_RD(bp, PXP2_REG_PXP2_INT_STS_CLR_0); -- cgit v1.2.3-18-g5258 From eb8da205a6cac953a46a247b8dd19505eba944e2 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Tue, 21 Jul 2009 05:47:30 +0000 Subject: bnx2x: Fan failure early detection Check if fan failure happened before the driver was loaded and notify the user Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index ae8b7b517ea..d946c9ea3f2 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -5185,6 +5185,11 @@ static void bnx2x_nic_init(struct bnx2x *bp, u32 load_code) mmiowb(); bnx2x_int_enable(bp); + + /* Check for SPIO5 */ + bnx2x_attn_int_deasserted0(bp, + REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + BP_PORT(bp)*4) & + AEU_INPUTS_ATTN_BITS_SPIO5); } /* end of nic init */ -- cgit v1.2.3-18-g5258 From 37dbbf32a0d45f0ed88f92cb6d0c35f4809e3a8e Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Tue, 21 Jul 2009 05:47:33 +0000 Subject: bnx2x: Adding some mmiowb Signed-off-by: Vlad Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index d946c9ea3f2..f20df6d7dcb 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -652,6 +652,11 @@ static void bnx2x_int_enable(struct bnx2x *bp) val, port, addr, (msix ? "MSI-X" : (msi ? "MSI" : "INTx"))); REG_WR(bp, addr, val); + /* + * Ensure that HC_CONFIG is written before leading/trailing edge config + */ + mmiowb(); + barrier(); if (CHIP_IS_E1H(bp)) { /* init leading/trailing edge */ @@ -666,6 +671,9 @@ static void bnx2x_int_enable(struct bnx2x *bp) REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val); REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val); } + + /* Make sure that interrupts are indeed enabled from here on */ + mmiowb(); } static void bnx2x_int_disable(struct bnx2x *bp) @@ -739,6 +747,10 @@ static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 sb_id, DP(BNX2X_MSG_OFF, "write 0x%08x to HC addr 0x%x\n", (*(u32 *)&igu_ack), hc_addr); REG_WR(bp, hc_addr, (*(u32 *)&igu_ack)); + + /* Make sure that ACK is written */ + mmiowb(); + barrier(); } static inline u16 bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp) @@ -2429,9 +2441,14 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid, bp->spq_prod_idx++; } + /* Make sure that BD data is updated before writing the producer */ + wmb(); + REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(func), bp->spq_prod_idx); + mmiowb(); + spin_unlock_bh(&bp->spq_lock); return 0; } -- cgit v1.2.3-18-g5258 From e15107065d073714dc47cf6b80c8bf5eea1bf18b Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Tue, 21 Jul 2009 05:47:41 +0000 Subject: bnx2x: SMP-safe inter_sem Signed-off-by: Vlad Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index f20df6d7dcb..18c380330be 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -706,6 +706,8 @@ static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw) /* disable interrupt handling */ atomic_inc(&bp->intr_sem); + smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */ + if (disable_hw) /* prevent the HW from sending interrupts */ bnx2x_int_disable(bp); @@ -6642,7 +6644,12 @@ static void bnx2x_napi_disable(struct bnx2x *bp) static void bnx2x_netif_start(struct bnx2x *bp) { - if (atomic_dec_and_test(&bp->intr_sem)) { + int intr_sem; + + intr_sem = atomic_dec_and_test(&bp->intr_sem); + smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */ + + if (intr_sem) { if (netif_running(bp->dev)) { bnx2x_napi_enable(bp); bnx2x_int_enable(bp); @@ -8229,6 +8236,7 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp) /* Disable interrupt handling until HW is initialized */ atomic_set(&bp->intr_sem, 1); + smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */ mutex_init(&bp->port.phy_mutex); -- cgit v1.2.3-18-g5258 From 5316bc0b9adbefe24f149b12caeddc30df6f04e1 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Tue, 21 Jul 2009 05:47:43 +0000 Subject: bnx2x: Update vlan_features As noted by Or Gerlitz , the vlan_features was not updated Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 18c380330be..b404a9b66d5 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -9310,9 +9310,17 @@ static int bnx2x_set_tso(struct net_device *dev, u32 data) if (data) { dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); dev->features |= NETIF_F_TSO6; +#ifdef BCM_VLAN + dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); + dev->vlan_features |= NETIF_F_TSO6; +#endif } else { dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN); dev->features &= ~NETIF_F_TSO6; +#ifdef BCM_VLAN + dev->vlan_features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN); + dev->vlan_features &= ~NETIF_F_TSO6; +#endif } return 0; @@ -11143,12 +11151,19 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev, dev->features |= NETIF_F_HW_CSUM; if (bp->flags & USING_DAC_FLAG) dev->features |= NETIF_F_HIGHDMA; + dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); + dev->features |= NETIF_F_TSO6; #ifdef BCM_VLAN dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); bp->flags |= (HW_VLAN_RX_FLAG | HW_VLAN_TX_FLAG); + + dev->vlan_features |= NETIF_F_SG; + dev->vlan_features |= NETIF_F_HW_CSUM; + if (bp->flags & USING_DAC_FLAG) + dev->vlan_features |= NETIF_F_HIGHDMA; + dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); + dev->vlan_features |= NETIF_F_TSO6; #endif - dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); - dev->features |= NETIF_F_TSO6; return 0; -- cgit v1.2.3-18-g5258 From 4d295db0efd2ccf06edb7a45ad885b40c56b7161 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Tue, 21 Jul 2009 05:47:47 +0000 Subject: bnx2x: Supporting BCM8727 PHY Adding support for BCM8727 - a dual port SFP+ PHY. That includes verification of the optic module vendor and part number - the list of approved modules resides on the nvram and the module is verified by the FW. Since not all users would like to use this verification feature, it can be disabled. The default behavior is to issue a warning if the module is not approved, but still allow using it - but it is also possible to disable the link if the module is not approved. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x.h | 1 + drivers/net/bnx2x_hsi.h | 25 +- drivers/net/bnx2x_link.c | 1133 +++++++++++++++++++++++++++++++++++++++------- drivers/net/bnx2x_link.h | 14 +- drivers/net/bnx2x_main.c | 67 ++- drivers/net/bnx2x_reg.h | 26 +- 6 files changed, 1068 insertions(+), 198 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 85a737c5c23..8b6e83d03f9 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -1006,6 +1006,7 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr, int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port); int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port); int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port); +u32 bnx2x_fw_command(struct bnx2x *bp, u32 command); static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, int wait) diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x_hsi.h index 41c6dcb9618..7de83c4a557 100644 --- a/drivers/net/bnx2x_hsi.h +++ b/drivers/net/bnx2x_hsi.h @@ -248,6 +248,8 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */ #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726 0x00000600 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481 0x00000700 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101 0x00000800 +#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727 0x00000900 +#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC 0x00000a00 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE 0x0000fd00 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN 0x0000ff00 @@ -358,10 +360,16 @@ struct port_feat_cfg { /* port 0: 0x454 port 1: 0x4c8 */ #define PORT_FEATURE_MBA_ENABLED 0x02000000 #define PORT_FEATURE_MFW_ENABLED 0x04000000 - /* Check the optic vendor via i2c before allowing it to be used by - SW */ -#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLED 0x00000000 -#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_ENABLED 0x08000000 + /* Reserved bits: 28-29 */ + /* Check the optic vendor via i2c against a list of approved modules + in a separate nvram image */ +#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK 0xE0000000 +#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_SHIFT 29 +#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT 0x00000000 +#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER 0x20000000 +#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_WARNING_MSG 0x40000000 +#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN 0x60000000 + u32 wol_config; /* Default is used when driver sets to "auto" mode */ @@ -657,6 +665,12 @@ struct drv_func_mb { #define DRV_MSG_CODE_GET_UPGRADE_KEY 0x81000000 #define DRV_MSG_CODE_GET_MANUF_KEY 0x82000000 #define DRV_MSG_CODE_LOAD_L2B_PRAM 0x90000000 + /* + * The optic module verification commands requris bootcode + * v5.0.6 or later + */ +#define DRV_MSG_CODE_VRFY_OPT_MDL 0xa0000000 +#define REQ_BC_VER_4_VRFY_OPT_MDL 0x00050006 #define BIOS_MSG_CODE_LIC_CHALLENGE 0xff010000 #define BIOS_MSG_CODE_LIC_RESPONSE 0xff020000 @@ -691,6 +705,9 @@ struct drv_func_mb { #define FW_MSG_CODE_L2B_PRAM_C_LOAD_FAILURE 0x90220000 #define FW_MSG_CODE_L2B_PRAM_X_LOAD_FAILURE 0x90230000 #define FW_MSG_CODE_L2B_PRAM_U_LOAD_FAILURE 0x90240000 +#define FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS 0xa0100000 +#define FW_MSG_CODE_VRFY_OPT_MDL_INVLD_IMG 0xa0200000 +#define FW_MSG_CODE_VRFY_OPT_MDL_UNAPPROVED 0xa0300000 #define FW_MSG_CODE_LIC_CHALLENGE 0xff010000 #define FW_MSG_CODE_LIC_RESPONSE 0xff020000 diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index ed648acef7c..b9c85a21457 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -139,21 +139,26 @@ #define SFP_EEPROM_CON_TYPE_VAL_LC 0x7 #define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21 + +#define SFP_EEPROM_COMP_CODE_ADDR 0x3 + #define SFP_EEPROM_COMP_CODE_SR_MASK (1<<4) + #define SFP_EEPROM_COMP_CODE_LR_MASK (1<<5) + #define SFP_EEPROM_COMP_CODE_LRM_MASK (1<<6) + #define SFP_EEPROM_FC_TX_TECH_ADDR 0x8 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8 -#define SFP_EEPROM_VENDOR_NAME_ADDR 0x14 -#define SFP_EEPROM_VENDOR_NAME_SIZE 16 + #define SFP_EEPROM_OPTIONS_ADDR 0x40 #define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1 #define SFP_EEPROM_OPTIONS_SIZE 2 -#define SFP_MODULE_TYPE_UNKNOWN 0x0 -#define SFP_MODULE_TYPE_LC 0x1 -#define SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE 0x2 -#define SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE 0x3 +#define EDC_MODE_LINEAR 0x0022 +#define EDC_MODE_LIMITING 0x0044 +#define EDC_MODE_PASSIVE_DAC 0x0055 + + -#define SFP_LIMITING_MODE_VALUE 0x0044 /**********************************************************/ /* INTERFACE */ /**********************************************************/ @@ -793,6 +798,7 @@ static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port) switch (ext_phy_type) { case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: /* All MDC/MDIO is directed through single EMAC */ if (REG_RD(bp, NIG_REG_PORT_SWAP)) emac_base = GRCBASE_EMAC0; @@ -1887,6 +1893,10 @@ static void bnx2x_ext_phy_reset(struct link_params *params, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040); break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: /* Restore normal power mode*/ @@ -2171,13 +2181,15 @@ static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params) } -static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port, - u8 ext_phy_addr, u32 shmem_base) +static void bnx2x_bcm8073_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port, + u8 ext_phy_addr, + u32 ext_phy_type, + u32 shmem_base) { /* Boot port from external ROM */ /* EDC grst */ bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, @@ -2185,21 +2197,21 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port, /* ucode reboot and rst */ bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x008c); bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL1, 0x0001); /* Reset internal microprocessor */ bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, @@ -2207,7 +2219,7 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port, /* Release srst bit */ bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, @@ -2218,17 +2230,36 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port, /* Clear ser_boot_ctl bit */ bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL1, 0x0000); bnx2x_save_bcm_spirom_ver(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + ext_phy_type, ext_phy_addr, shmem_base); } +static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port, + u8 ext_phy_addr, + u32 shmem_base) +{ + bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + shmem_base); +} + +static void bnx2x_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port, + u8 ext_phy_addr, + u32 shmem_base) +{ + bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + shmem_base); + +} + static void bnx2x_bcm8726_external_rom_boot(struct link_params *params) { struct bnx2x *bp = params->bp; @@ -2258,9 +2289,10 @@ static void bnx2x_bcm8726_external_rom_boot(struct link_params *params) MDIO_PMA_REG_GEN_CTRL, MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET); + /* Set PLL register value to be same like in P13 ver */ bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, - MDIO_PMA_REG_GEN_CTRL2, + MDIO_PMA_REG_PLL_CTRL, 0x73A0); /* Clear soft reset. @@ -2285,15 +2317,16 @@ static void bnx2x_bcm8726_external_rom_boot(struct link_params *params) params->shmem_base); } -static void bnx2x_bcm8726_set_transmitter(struct bnx2x *bp, u8 port, - u8 ext_phy_addr, u8 tx_en) +static void bnx2x_sfp_set_transmitter(struct bnx2x *bp, u8 port, + u32 ext_phy_type, u8 ext_phy_addr, + u8 tx_en) { u16 val; DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n", tx_en, port); /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/ bnx2x_cl45_read(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, + ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, @@ -2305,18 +2338,19 @@ static void bnx2x_bcm8726_set_transmitter(struct bnx2x *bp, u8 port, val |= (1<<15); bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, + ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, val); } - -static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr, - u8 byte_cnt, u8 *o_buf) { +static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params, + u16 addr, u8 byte_cnt, u8 *o_buf) +{ struct bnx2x *bp = params->bp; - u16 val, i; + u16 val = 0; + u16 i; u8 port = params->port; u8 ext_phy_addr = ((params->ext_phy_config & PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> @@ -2332,7 +2366,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT, + MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT, (byte_cnt | 0xa000)); /* Set the read command address */ @@ -2340,7 +2374,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR, + MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR, addr); /* Activate read command */ @@ -2348,7 +2382,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8726_TWO_WIRE_CTRL, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, 0x2c0f); /* Wait up to 500us for command complete status */ @@ -2357,18 +2391,18 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val); - if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) == - MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE) + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); + if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) == + MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) break; udelay(5); } - if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) != - MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE) { + if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) != + MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) { DP(NETIF_MSG_LINK, "Got bad status 0x%x when reading from SFP+ EEPROM\n", - (val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK)); + (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK)); return -EINVAL; } @@ -2387,29 +2421,147 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val); - if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) == - MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE) + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); + if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) == + MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE) + return 0;; + msleep(1); + } + return -EINVAL; +} + +static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params, + u16 addr, u8 byte_cnt, u8 *o_buf) +{ + struct bnx2x *bp = params->bp; + u16 val, i; + u8 port = params->port; + u8 ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + + if (byte_cnt > 16) { + DP(NETIF_MSG_LINK, "Reading from eeprom is" + " is limited to 0xf\n"); + return -EINVAL; + } + + /* Need to read from 1.8000 to clear it */ + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, + &val); + + /* Set the read command byte count */ + bnx2x_cl45_write(bp, port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT, + ((byte_cnt < 2) ? 2 : byte_cnt)); + + /* Set the read command address */ + bnx2x_cl45_write(bp, port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR, + addr); + /* Set the destination address */ + bnx2x_cl45_write(bp, port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0x8004, + MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF); + + /* Activate read command */ + bnx2x_cl45_write(bp, port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, + 0x8002); + /* Wait appropriate time for two-wire command to finish before + polling the status register */ + msleep(1); + + /* Wait up to 500us for command complete status */ + for (i = 0; i < 100; i++) { + bnx2x_cl45_read(bp, port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); + if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) == + MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) + break; + udelay(5); + } + + if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) != + MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) { + DP(NETIF_MSG_LINK, + "Got bad status 0x%x when reading from SFP+ EEPROM\n", + (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK)); + return -EINVAL; + } + + /* Read the buffer */ + for (i = 0; i < byte_cnt; i++) { + bnx2x_cl45_read(bp, port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val); + o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK); + } + + for (i = 0; i < 100; i++) { + bnx2x_cl45_read(bp, port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); + if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) == + MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE) return 0;; msleep(1); } + return -EINVAL; } +u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr, + u8 byte_cnt, u8 *o_buf) +{ + u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + + if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) + return bnx2x_8726_read_sfp_module_eeprom(params, addr, + byte_cnt, o_buf); + else if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) + return bnx2x_8727_read_sfp_module_eeprom(params, addr, + byte_cnt, o_buf); + return -EINVAL; +} -static u8 bnx2x_get_sfp_module_type(struct link_params *params, - u8 *module_type) +static u8 bnx2x_get_edc_mode(struct link_params *params, + u16 *edc_mode) { struct bnx2x *bp = params->bp; - u8 val; - *module_type = SFP_MODULE_TYPE_UNKNOWN; + u8 val, check_limiting_mode = 0; + *edc_mode = EDC_MODE_LIMITING; /* First check for copper cable */ if (bnx2x_read_sfp_module_eeprom(params, SFP_EEPROM_CON_TYPE_ADDR, 1, &val) != 0) { - DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM"); + DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n"); return -EINVAL; } @@ -2433,13 +2585,13 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params, if (copper_module_type & SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) { DP(NETIF_MSG_LINK, "Active Copper cable detected\n"); - *module_type = SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE; + check_limiting_mode = 1; } else if (copper_module_type & SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) { DP(NETIF_MSG_LINK, "Passive Copper" " cable detected\n"); - *module_type = - SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE; + *edc_mode = + EDC_MODE_PASSIVE_DAC; } else { DP(NETIF_MSG_LINK, "Unknown copper-cable-" "type 0x%x !!!\n", copper_module_type); @@ -2449,7 +2601,7 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params, } case SFP_EEPROM_CON_TYPE_VAL_LC: DP(NETIF_MSG_LINK, "Optic module detected\n"); - *module_type = SFP_MODULE_TYPE_LC; + check_limiting_mode = 1; break; default: @@ -2457,89 +2609,92 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params, val); return -EINVAL; } + + if (check_limiting_mode) { + u8 options[SFP_EEPROM_OPTIONS_SIZE]; + if (bnx2x_read_sfp_module_eeprom(params, + SFP_EEPROM_OPTIONS_ADDR, + SFP_EEPROM_OPTIONS_SIZE, + options) != 0) { + DP(NETIF_MSG_LINK, "Failed to read Option" + " field from module EEPROM\n"); + return -EINVAL; + } + if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK)) + *edc_mode = EDC_MODE_LINEAR; + else + *edc_mode = EDC_MODE_LIMITING; + } + DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode); return 0; } - /* This function read the relevant field from the module ( SFP+ ), and verify it is compliant with this board */ -static u8 bnx2x_verify_sfp_module(struct link_params *params, - u8 module_type) +static u8 bnx2x_verify_sfp_module(struct link_params *params) { struct bnx2x *bp = params->bp; - u8 *str_p, *tmp_buf; - u16 i; - -#define COMPLIANCE_STR_CNT 6 - u8 *compliance_str[] = {"Broadcom", "JDSU", "Molex Inc", "PICOLIGHT", - "FINISAR CORP. ", "Amphenol"}; - u8 buf[SFP_EEPROM_VENDOR_NAME_SIZE]; - /* Passive Copper cables are allowed to participate, - since the module is hardwired to the copper cable */ - - if (!(params->feature_config_flags & - FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) { + u32 val; + u32 fw_resp; + char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1]; + char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1]; + + val = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, dev_info. + port_feature_config[params->port].config)); + if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) { DP(NETIF_MSG_LINK, "NOT enforcing module verification\n"); return 0; } - if (module_type != SFP_MODULE_TYPE_LC) { - DP(NETIF_MSG_LINK, "No need to verify copper cable\n"); + /* Ask the FW to validate the module */ + if (!(params->feature_config_flags & + FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY)) { + DP(NETIF_MSG_LINK, "FW does not support OPT MDL " + "verification\n"); + return -EINVAL; + } + + fw_resp = bnx2x_fw_command(bp, DRV_MSG_CODE_VRFY_OPT_MDL); + if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) { + DP(NETIF_MSG_LINK, "Approved module\n"); return 0; } - /* In case of non copper cable or Active copper cable, - verify that the SFP+ module is compliant with this board*/ + /* format the warning message */ if (bnx2x_read_sfp_module_eeprom(params, SFP_EEPROM_VENDOR_NAME_ADDR, SFP_EEPROM_VENDOR_NAME_SIZE, - buf) != 0) { - DP(NETIF_MSG_LINK, "Failed to read Vendor-Name from" - " module EEPROM\n"); - return -EINVAL; - } - for (i = 0; i < COMPLIANCE_STR_CNT; i++) { - str_p = compliance_str[i]; - tmp_buf = buf; - while (*str_p) { - if ((u8)(*tmp_buf) != (u8)(*str_p)) - break; - str_p++; - tmp_buf++; - } + (u8 *)vendor_name)) + vendor_name[0] = '\0'; + else + vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0'; + if (bnx2x_read_sfp_module_eeprom(params, + SFP_EEPROM_PART_NO_ADDR, + SFP_EEPROM_PART_NO_SIZE, + (u8 *)vendor_pn)) + vendor_pn[0] = '\0'; + else + vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0'; - if (!(*str_p)) { - DP(NETIF_MSG_LINK, "SFP+ Module verified, " - "index=%x\n", i); - return 0; - } - } - DP(NETIF_MSG_LINK, "Incompliant SFP+ module. Disable module !!!\n"); + printk(KERN_INFO PFX "Warning: " + "Unqualified SFP+ module " + "detected on %s, Port %d from %s part number %s\n" + , bp->dev->name, params->port, + vendor_name, vendor_pn); return -EINVAL; } - static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params, - u8 module_type) + u16 edc_mode) { struct bnx2x *bp = params->bp; u8 port = params->port; - u8 options[SFP_EEPROM_OPTIONS_SIZE]; - u8 limiting_mode; u8 ext_phy_addr = ((params->ext_phy_config & PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); u16 cur_limiting_mode; - if (bnx2x_read_sfp_module_eeprom(params, - SFP_EEPROM_OPTIONS_ADDR, - SFP_EEPROM_OPTIONS_SIZE, - options) != 0) { - DP(NETIF_MSG_LINK, "Failed to read Option field from" - " module EEPROM\n"); - return -EINVAL; - } - limiting_mode = !(options[0] & - SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK); bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, @@ -2550,26 +2705,23 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params, DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n", cur_limiting_mode); - if (limiting_mode && - (module_type != SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE)) { + if (edc_mode == EDC_MODE_LIMITING) { DP(NETIF_MSG_LINK, - "Module options = 0x%x.Setting LIMITING MODE\n", - options[0]); + "Setting LIMITING MODE\n"); bnx2x_cl45_write(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER2, - SFP_LIMITING_MODE_VALUE); + EDC_MODE_LIMITING); } else { /* LRM mode ( default )*/ - DP(NETIF_MSG_LINK, "Module options = 0x%x.Setting LRM MODE\n", - options[0]); + DP(NETIF_MSG_LINK, "Setting LRM MODE\n"); /* Changing to LRM mode takes quite few seconds. So do it only if current mode is limiting ( default is LRM )*/ - if (cur_limiting_mode != SFP_LIMITING_MODE_VALUE) + if (cur_limiting_mode != EDC_MODE_LIMITING) return 0; bnx2x_cl45_write(bp, port, @@ -2600,6 +2752,56 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params, return 0; } +static u8 bnx2x_bcm8727_set_limiting_mode(struct link_params *params, + u16 edc_mode) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + u16 phy_identifier; + u16 rom_ver2_val; + u8 ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + &phy_identifier); + + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + (phy_identifier & ~(1<<9))); + + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, + &rom_ver2_val); + /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, + (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff)); + + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + (phy_identifier | (1<<9))); + + return 0; +} + + static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params) { u8 val; @@ -2619,61 +2821,114 @@ static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params) return -EINVAL; } +static void bnx2x_8727_power_module(struct bnx2x *bp, + struct link_params *params, + u8 ext_phy_addr, u8 is_power_up) { + /* Make sure GPIOs are not using for LED mode */ + u16 val; + u8 port = params->port; + /* + * In the GPIO register, bit 4 is use to detemine if the GPIOs are + * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for + * output + * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0 + * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1 + * where the 1st bit is the over-current(only input), and 2nd bit is + * for power( only output ) + */ + + /* + * In case of NOC feature is disabled and power is up, set GPIO control + * as input to enable listening of over-current indication + */ + + if (!(params->feature_config_flags & + FEATURE_CONFIG_BCM8727_NOC) && is_power_up) + val = (1<<4); + else + /* + * Set GPIO control to OUTPUT, and set the power bit + * to according to the is_power_up + */ + val = ((!(is_power_up)) << 1); + + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_GPIO_CTRL, + val); +} + static u8 bnx2x_sfp_module_detection(struct link_params *params) { struct bnx2x *bp = params->bp; - u8 module_type; + u16 edc_mode; + u8 rc = 0; u8 ext_phy_addr = ((params->ext_phy_config & PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); - - if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) { - DP(NETIF_MSG_LINK, "Module detection is not required " - "for this phy\n"); - return 0; - } + u32 val = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, dev_info. + port_feature_config[params->port].config)); DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n", params->port); - if (bnx2x_get_sfp_module_type(params, - &module_type) != 0) { + if (bnx2x_get_edc_mode(params, &edc_mode) != 0) { DP(NETIF_MSG_LINK, "Failed to get valid module type\n"); - if (!(params->feature_config_flags & - FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) { - /* In case module detection is disabled, it trys to - link up. The issue that can happen here is LRM / - LIMITING mode which set according to the module-type*/ - DP(NETIF_MSG_LINK, "Unable to read module-type." - "Probably due to Bit Stretching." - " Proceeding...\n"); - } else { - return -EINVAL; - } - } else if (bnx2x_verify_sfp_module(params, module_type) != + return -EINVAL; + } else if (bnx2x_verify_sfp_module(params) != 0) { /* check SFP+ module compatibility */ DP(NETIF_MSG_LINK, "Module verification failed!!\n"); + rc = -EINVAL; /* Turn on fault module-detected led */ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, MISC_REGISTERS_GPIO_HIGH, params->port); - return -EINVAL; + if ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) && + ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) { + /* Shutdown SFP+ module */ + DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n"); + bnx2x_8727_power_module(bp, params, + ext_phy_addr, 0); + return rc; + } + } else { + /* Turn off fault module-detected led */ + DP(NETIF_MSG_LINK, "Turn off fault module-detected led\n"); + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, + MISC_REGISTERS_GPIO_LOW, + params->port); } - /* Turn off fault module-detected led */ - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, - MISC_REGISTERS_GPIO_LOW, - params->port); + /* power up the SFP module */ + if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) + bnx2x_8727_power_module(bp, params, ext_phy_addr, 1); - /* Check and set limiting mode / LRM mode */ - bnx2x_bcm8726_set_limiting_mode(params, module_type); + /* Check and set limiting mode / LRM mode on 8726. + On 8727 it is done automatically */ + if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) + bnx2x_bcm8726_set_limiting_mode(params, edc_mode); + else + bnx2x_bcm8727_set_limiting_mode(params, edc_mode); + /* + * Enable transmit for this module if the module is approved, or + * if unapproved modules should also enable the Tx laser + */ + if (rc == 0 || + (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) != + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) + bnx2x_sfp_set_transmitter(bp, params->port, + ext_phy_type, ext_phy_addr, 1); + else + bnx2x_sfp_set_transmitter(bp, params->port, + ext_phy_type, ext_phy_addr, 0); - /* Enable transmit for this module */ - bnx2x_bcm8726_set_transmitter(bp, params->port, - ext_phy_addr, 1); - return 0; + return rc; } void bnx2x_handle_module_detect_int(struct link_params *params) @@ -2696,8 +2951,8 @@ void bnx2x_handle_module_detect_int(struct link_params *params) MISC_REGISTERS_GPIO_INT_OUTPUT_CLR, port); - if (bnx2x_wait_for_sfp_module_initialized(params) - == 0) + if (bnx2x_wait_for_sfp_module_initialized(params) == + 0) bnx2x_sfp_module_detection(params); else DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n"); @@ -2705,13 +2960,22 @@ void bnx2x_handle_module_detect_int(struct link_params *params) u8 ext_phy_addr = ((params->ext_phy_config & PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u32 ext_phy_type = + XGXS_EXT_PHY_TYPE(params->ext_phy_config); + u32 val = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, dev_info. + port_feature_config[params->port]. + config)); + bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3, MISC_REGISTERS_GPIO_INT_OUTPUT_SET, port); /* Module was plugged out. */ /* Disable transmit for this module */ - bnx2x_bcm8726_set_transmitter(bp, params->port, - ext_phy_addr, 0); + if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) + bnx2x_sfp_set_transmitter(bp, params->port, + ext_phy_type, ext_phy_addr, 0); } } @@ -3160,6 +3424,9 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) driver is loaded, it reset all registers, including the transmitter */ bnx2x_sfp_module_detection(params); + + /* Set Flow control */ + bnx2x_ext_phy_set_pause(params, vars); if (params->req_line_speed == SPEED_1000) { DP(NETIF_MSG_LINK, "Setting 1G force\n"); bnx2x_cl45_write(bp, params->port, ext_phy_type, @@ -3450,43 +3717,224 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) ((val & (1<<7)) > 0)); break; } - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: { - u16 fw_ver1, fw_ver2; - DP(NETIF_MSG_LINK, - "Setting the SFX7101 LASI indication\n"); + u16 tmp1; + u16 rx_alarm_ctrl_val; + u16 lasi_ctrl_val; + /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */ + + u16 mod_abs; + rx_alarm_ctrl_val = (1<<2) | (1<<5) ; + lasi_ctrl_val = 0x0004; + + DP(NETIF_MSG_LINK, "Initializing BCM8727\n"); + /* enable LASI */ bnx2x_cl45_write(bp, params->port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, - MDIO_PMA_REG_LASI_CTRL, 0x1); - DP(NETIF_MSG_LINK, - "Setting the SFX7101 LED to blink on traffic\n"); + MDIO_PMA_REG_RX_ALARM_CTRL, + rx_alarm_ctrl_val); + bnx2x_cl45_write(bp, params->port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, - MDIO_PMA_REG_7107_LED_CNTL, (1<<3)); + MDIO_PMA_REG_LASI_CTRL, + lasi_ctrl_val); - bnx2x_ext_phy_set_pause(params, vars); - /* Restart autoneg */ + /* Initially configure MOD_ABS to interrupt when + module is presence( bit 8) */ bnx2x_cl45_read(bp, params->port, ext_phy_type, ext_phy_addr, - MDIO_AN_DEVAD, - MDIO_AN_REG_CTRL, &val); - val |= 0x200; + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs); + /* Set EDC off by setting OPTXLOS signal input to low + (bit 9). + When the EDC is off it locks onto a reference clock and + avoids becoming 'lost'.*/ + mod_abs &= ~((1<<8) | (1<<9)); bnx2x_cl45_write(bp, params->port, ext_phy_type, ext_phy_addr, - MDIO_AN_DEVAD, - MDIO_AN_REG_CTRL, val); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs); - /* Save spirom version */ - bnx2x_cl45_read(bp, params->port, ext_phy_type, - ext_phy_addr, MDIO_PMA_DEVAD, - MDIO_PMA_REG_7101_VER1, &fw_ver1); + /* Make MOD_ABS give interrupt on change */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_PCS_OPT_CTRL, + &val); + val |= (1<<12); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_PCS_OPT_CTRL, + val); + + /* Set 8727 GPIOs to input to allow reading from the + 8727 GPIO0 status which reflect SFP+ module + over-current */ + + bnx2x_cl45_read(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_PCS_OPT_CTRL, + &val); + val &= 0xff8f; /* Reset bits 4-6 */ + bnx2x_cl45_write(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_PCS_OPT_CTRL, + val); + + bnx2x_8727_power_module(bp, params, ext_phy_addr, 1); + bnx2x_bcm8073_set_xaui_low_power_mode(params); + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_M8051_MSGOUT_REG, + &tmp1); + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM, &tmp1); + + /* Set option 1G speed */ + if (params->req_line_speed == SPEED_1000) { + + DP(NETIF_MSG_LINK, "Setting 1G force\n"); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, 0x40); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_10G_CTRL2, 0xD); + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_10G_CTRL2, &tmp1); + DP(NETIF_MSG_LINK, "1.7 = 0x%x \n", tmp1); + + } else if ((params->req_line_speed == + SPEED_AUTO_NEG) && + ((params->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) { + + DP(NETIF_MSG_LINK, "Setting 1G clause37 \n"); + bnx2x_cl45_write(bp, params->port, ext_phy_type, + ext_phy_addr, MDIO_AN_DEVAD, + MDIO_PMA_REG_8727_MISC_CTRL, 0); + bnx2x_cl45_write(bp, params->port, ext_phy_type, + ext_phy_addr, MDIO_AN_DEVAD, + MDIO_AN_REG_CL37_AN, 0x1300); + } else { + /* Since the 8727 has only single reset pin, + need to set the 10G registers although it is + default */ + bnx2x_cl45_write(bp, params->port, ext_phy_type, + ext_phy_addr, MDIO_AN_DEVAD, + MDIO_AN_REG_CTRL, 0x0020); + bnx2x_cl45_write(bp, params->port, ext_phy_type, + ext_phy_addr, MDIO_AN_DEVAD, + 0x7, 0x0100); + bnx2x_cl45_write(bp, params->port, ext_phy_type, + ext_phy_addr, MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, 0x2040); + bnx2x_cl45_write(bp, params->port, ext_phy_type, + ext_phy_addr, MDIO_PMA_DEVAD, + MDIO_PMA_REG_10G_CTRL2, 0x0008); + } + + /* Set 2-wire transfer rate to 400Khz since 100Khz + is not operational */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR, + 0xa101); + + /* Set TX PreEmphasis if needed */ + if ((params->feature_config_flags & + FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) { + DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x," + "TX_CTRL2 0x%x\n", + params->xgxs_config_tx[0], + params->xgxs_config_tx[1]); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_TX_CTRL1, + params->xgxs_config_tx[0]); + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_TX_CTRL2, + params->xgxs_config_tx[1]); + } + + break; + } + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: + { + u16 fw_ver1, fw_ver2; + DP(NETIF_MSG_LINK, + "Setting the SFX7101 LASI indication\n"); + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_LASI_CTRL, 0x1); + DP(NETIF_MSG_LINK, + "Setting the SFX7101 LED to blink on traffic\n"); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_7107_LED_CNTL, (1<<3)); + + bnx2x_ext_phy_set_pause(params, vars); + /* Restart autoneg */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_CTRL, &val); + val |= 0x200; + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_CTRL, val); + + /* Save spirom version */ + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, MDIO_PMA_DEVAD, + MDIO_PMA_REG_7101_VER1, &fw_ver1); bnx2x_cl45_read(bp, params->port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, @@ -3561,6 +4009,99 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) return rc; } +static void bnx2x_8727_handle_mod_abs(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u16 mod_abs, rx_alarm_status; + u8 ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u32 val = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, dev_info. + port_feature_config[params->port]. + config)); + bnx2x_cl45_read(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs); + if (mod_abs & (1<<8)) { + + /* Module is absent */ + DP(NETIF_MSG_LINK, "MOD_ABS indication " + "show module is absent\n"); + + /* 1. Set mod_abs to detect next module + presence event + 2. Set EDC off by setting OPTXLOS signal input to low + (bit 9). + When the EDC is off it locks onto a reference clock and + avoids becoming 'lost'.*/ + mod_abs &= ~((1<<8)|(1<<9)); + bnx2x_cl45_write(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs); + + /* Clear RX alarm since it stays up as long as + the mod_abs wasn't changed */ + bnx2x_cl45_read(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM, &rx_alarm_status); + + } else { + /* Module is present */ + DP(NETIF_MSG_LINK, "MOD_ABS indication " + "show module is present\n"); + /* First thing, disable transmitter, + and if the module is ok, the + module_detection will enable it*/ + + /* 1. Set mod_abs to detect next module + absent event ( bit 8) + 2. Restore the default polarity of the OPRXLOS signal and + this signal will then correctly indicate the presence or + absence of the Rx signal. (bit 9) */ + mod_abs |= ((1<<8)|(1<<9)); + bnx2x_cl45_write(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs); + + /* Clear RX alarm since it stays up as long as + the mod_abs wasn't changed. This is need to be done + before calling the module detection, otherwise it will clear + the link update alarm */ + bnx2x_cl45_read(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM, &rx_alarm_status); + + + if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) + bnx2x_sfp_set_transmitter(bp, params->port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, 0); + + if (bnx2x_wait_for_sfp_module_initialized(params) + == 0) + bnx2x_sfp_module_detection(params); + else + DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n"); + } + + DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", + rx_alarm_status); + /* No need to check link status in case of + module plugged in/out */ +} + static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, struct link_vars *vars) @@ -3602,8 +4143,19 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd); - DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd); - ext_phy_link_up = (rx_sd & 0x1); + + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + 1, + 0xc809, &val1); + bnx2x_cl45_read(bp, params->port, ext_phy_type, + ext_phy_addr, + 1, + 0xc809, &val1); + + DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1); + ext_phy_link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) + && ((val1 & (1<<8)) == 0)); if (ext_phy_link_up) vars->line_speed = SPEED_10000; break; @@ -3678,8 +4230,160 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, else vars->line_speed = SPEED_10000; } + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + { + u16 link_status = 0; + u16 rx_alarm_status; + /* Check the LASI */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM, &rx_alarm_status); + + DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", + rx_alarm_status); + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_LASI_STATUS, &val1); + + DP(NETIF_MSG_LINK, + "8727 LASI status 0x%x\n", + val1); + + /* Clear MSG-OUT */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_M8051_MSGOUT_REG, + &val1); + + /* + * If a module is present and there is need to check + * for over current + */ + if (!(params->feature_config_flags & + FEATURE_CONFIG_BCM8727_NOC) && + !(rx_alarm_status & (1<<5))) { + /* Check over-current using 8727 GPIO0 input*/ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_GPIO_CTRL, + &val1); + + if ((val1 & (1<<8)) == 0) { + DP(NETIF_MSG_LINK, "8727 Power fault" + " has been detected on port" + " %d\n", params->port); + printk(KERN_ERR PFX "Error: Power" + " fault on %s Port %d has" + " been detected and the" + " power to that SFP+ module" + " has been removed to prevent" + " failure of the card. Please" + " remove the SFP+ module and" + " restart the system to clear" + " this error.\n" + , bp->dev->name, params->port); + /* + * Disable all RX_ALARMs except for + * mod_abs + */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM_CTRL, + (1<<5)); + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + &val1); + /* Wait for module_absent_event */ + val1 |= (1<<8); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + val1); + /* Clear RX alarm */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM, + &rx_alarm_status); + break; + } + } /* Over current check */ + + /* When module absent bit is set, check module */ + if (rx_alarm_status & (1<<5)) { + bnx2x_8727_handle_mod_abs(params); + /* Enable all mod_abs and link detection bits */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM_CTRL, + ((1<<5) | (1<<2))); + } + + /* If transmitter is disabled, + ignore false link up indication */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + &val1); + if (val1 & (1<<15)) { + DP(NETIF_MSG_LINK, "Tx is disabled\n"); + ext_phy_link_up = 0; + break; + } + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8073_SPEED_LINK_STATUS, + &link_status); + /* Bits 0..2 --> speed detected, + bits 13..15--> link is down */ + if ((link_status & (1<<2)) && + (!(link_status & (1<<15)))) { + ext_phy_link_up = 1; + vars->line_speed = SPEED_10000; + } else if ((link_status & (1<<0)) && + (!(link_status & (1<<13)))) { + ext_phy_link_up = 1; + vars->line_speed = SPEED_1000; + DP(NETIF_MSG_LINK, + "port %x: External link" + " up in 1G\n", params->port); + } else { + ext_phy_link_up = 0; + DP(NETIF_MSG_LINK, + "port %x: External link" + " is down\n", params->port); + } break; + } + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: { @@ -4241,6 +4945,7 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: @@ -4842,10 +5547,6 @@ static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr) PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x0001); - - /* Disable Transmitter */ - bnx2x_bcm8726_set_transmitter(bp, port, ext_phy_addr, 0); - } u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, @@ -4858,6 +5559,11 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, u32 chip_id = params->chip_id; u8 port = params->port; u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config); + u32 val = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, dev_info. + port_feature_config[params->port]. + config)); + /* disable attentions */ vars->link_status = 0; @@ -4892,6 +5598,21 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + { + + /* Disable Transmitter */ + u8 ext_phy_addr = ((params->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) + bnx2x_sfp_set_transmitter(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr, 0); + break; + } case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: DP(NETIF_MSG_LINK, "Setting 8073 port %d into " "low power mode\n", @@ -5216,6 +5937,74 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base) } +static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) +{ + u8 ext_phy_addr[PORT_MAX]; + s8 port; + u32 swap_val, swap_override; + DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n"); + swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); + swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); + + bnx2x_hw_reset(bp, 1 ^ (swap_val && swap_override)); + msleep(5); + + /* PART1 - Reset both phys */ + for (port = PORT_MAX - 1; port >= PORT_0; port--) { + /* Extract the ext phy address for the port */ + u32 ext_phy_config = REG_RD(bp, shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].external_phy_config)); + + /* disable attentions */ + bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, + (NIG_MASK_XGXS0_LINK_STATUS | + NIG_MASK_XGXS0_LINK10G | + NIG_MASK_SERDES0_LINK_STATUS | + NIG_MASK_MI_INT)); + + ext_phy_addr[port] = ((ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + + /* Reset the phy */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr[port], + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, + 1<<15); + } + + /* Add delay of 150ms after reset */ + msleep(150); + + /* PART2 - Download firmware to both phys */ + for (port = PORT_MAX - 1; port >= PORT_0; port--) { + u16 fw_ver1; + + bnx2x_bcm8727_external_rom_boot(bp, port, + ext_phy_addr[port], shmem_base); + + bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + ext_phy_addr[port], + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER1, &fw_ver1); + if (fw_ver1 == 0 || fw_ver1 == 0x4321) { + DP(NETIF_MSG_LINK, + "bnx2x_8073_common_init_phy port %x:" + "Download failed. fw version = 0x%x\n", + port, fw_ver1); + return -EINVAL; + } + + } + + + + return 0; +} + static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base) { @@ -5274,6 +6063,12 @@ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base) rc = bnx2x_8073_common_init_phy(bp, shmem_base); break; } + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC: + rc = bnx2x_8727_common_init_phy(bp, shmem_base); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: /* GPIO1 affects both ports, so there's need to pull it for single port alone */ diff --git a/drivers/net/bnx2x_link.h b/drivers/net/bnx2x_link.h index 19a866dc10e..d25ef45d793 100644 --- a/drivers/net/bnx2x_link.h +++ b/drivers/net/bnx2x_link.h @@ -39,7 +39,13 @@ #define SPEED_15000 15000 #define SPEED_16000 16000 - +#define SFP_EEPROM_VENDOR_NAME_ADDR 0x14 +#define SFP_EEPROM_VENDOR_NAME_SIZE 16 +#define SFP_EEPROM_VENDOR_OUI_ADDR 0x25 +#define SFP_EEPROM_VENDOR_OUI_SIZE 3 +#define SFP_EEPROM_PART_NO_ADDR 0x28 +#define SFP_EEPROM_PART_NO_SIZE 16 +#define PWR_FLT_ERR_MSG_LEN 250 /***********************************************************/ /* Structs */ /***********************************************************/ @@ -91,7 +97,8 @@ struct link_params { u16 xgxs_config_tx[4]; /* preemphasis values for the tx side */ u32 feature_config_flags; #define FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED (1<<0) -#define FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED (2<<0) +#define FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY (1<<2) +#define FEATURE_CONFIG_BCM8727_NOC (1<<3) /* Device pointer passed to all callback functions */ struct bnx2x *bp; }; @@ -181,4 +188,7 @@ u8 bnx2x_test_link(struct link_params *input, struct link_vars *vars); u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base); +u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr, + u8 byte_cnt, u8 *o_buf); + #endif /* BNX2X_LINK_H */ diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index b404a9b66d5..197dbe4dad2 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -2637,7 +2637,7 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) { int port = BP_PORT(bp); int reg_offset; - u32 val; + u32 val, swap_val, swap_override; reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 : MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); @@ -2661,6 +2661,17 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) MISC_REGISTERS_GPIO_OUTPUT_LOW, port); break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + /* The PHY reset is controlled by GPIO 1 */ + /* fake the port number to cancel the swap done in + set_gpio() */ + swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); + swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); + port = (swap_val && swap_override) ^ 1; + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, + MISC_REGISTERS_GPIO_OUTPUT_LOW, port); + break; + default: break; } @@ -5561,6 +5572,8 @@ static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp) is_required |= ((phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) || + (phy_type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) || (phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481)); } @@ -5812,6 +5825,7 @@ static int bnx2x_init_common(struct bnx2x *bp) case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: bp->port.need_hw_lock = 1; break; @@ -6050,10 +6064,15 @@ static int bnx2x_init_port(struct bnx2x *bp) break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: /* add SPIO 5 to group 0 */ - val = REG_RD(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); + { + u32 reg_addr = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 : + MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); + val = REG_RD(bp, reg_addr); val |= AEU_INPUTS_ATTN_BITS_SPIO5; - REG_WR(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0, val); + REG_WR(bp, reg_addr, val); + } break; default: @@ -6203,7 +6222,7 @@ init_hw_err: } /* send the MCP a request, block until there is a reply */ -static u32 bnx2x_fw_command(struct bnx2x *bp, u32 command) +u32 bnx2x_fw_command(struct bnx2x *bp, u32 command) { int func = BP_FUNC(bp); u32 seq = ++bp->fw_seq; @@ -7676,6 +7695,9 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp) BNX2X_ERR("This driver needs bc_ver %X but found %X," " please upgrade BC\n", BNX2X_BC_VER, val); } + bp->link_params.feature_config_flags |= + (val >= REQ_BC_VER_4_VRFY_OPT_MDL) ? + FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY : 0; if (BP_E1HVN(bp) == 0) { pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_PMC, &pmc); @@ -7836,6 +7858,18 @@ static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp, SUPPORTED_Asym_Pause); break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + BNX2X_DEV_INFO("ext_phy_type 0x%x (8727)\n", + ext_phy_type); + + bp->port.supported |= (SUPPORTED_10000baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg | + SUPPORTED_FIBRE | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: BNX2X_DEV_INFO("ext_phy_type 0x%x (SFX7101)\n", ext_phy_type); @@ -8099,6 +8133,17 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) bp->link_params.ext_phy_config = SHMEM_RD(bp, dev_info.port_hw_config[port].external_phy_config); + /* BCM8727_NOC => BCM8727 no over current */ + if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC) { + bp->link_params.ext_phy_config &= + ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK; + bp->link_params.ext_phy_config |= + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727; + bp->link_params.feature_config_flags |= + FEATURE_CONFIG_BCM8727_NOC; + } + bp->link_params.speed_cap_mask = SHMEM_RD(bp, dev_info.port_hw_config[port].speed_capability_mask); @@ -8119,17 +8164,10 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) bp->link_params.xgxs_config_tx[(i << 1) + 1] = (val & 0xffff); } - config = SHMEM_RD(bp, dev_info.port_feature_config[port].config); - if (config & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_ENABLED) - bp->link_params.feature_config_flags |= - FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED; - else - bp->link_params.feature_config_flags &= - ~FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED; - /* If the device is capable of WoL, set the default state according * to the HW */ + config = SHMEM_RD(bp, dev_info.port_feature_config[port].config); bp->wol = (!(bp->flags & NO_WOL_FLAG) && (config & PORT_FEATURE_WOL_ENABLED)); @@ -8139,8 +8177,8 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) bp->link_params.ext_phy_config, bp->link_params.speed_cap_mask, bp->port.link_config); - bp->link_params.switch_cfg = (bp->port.link_config & - PORT_FEATURE_CONNECTED_SWITCH_MASK); + bp->link_params.switch_cfg |= (bp->port.link_config & + PORT_FEATURE_CONNECTED_SWITCH_MASK); bnx2x_link_settings_supported(bp, bp->link_params.switch_cfg); bnx2x_link_settings_requested(bp); @@ -8336,6 +8374,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: cmd->port = PORT_FIBRE; break; diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h index 6d77730b6b4..d771168ec20 100644 --- a/drivers/net/bnx2x_reg.h +++ b/drivers/net/bnx2x_reg.h @@ -5845,25 +5845,33 @@ Theotherbitsarereservedandshouldbezero*/ #define MDIO_PMA_REG_ROM_VER2 0xca1a #define MDIO_PMA_REG_EDC_FFE_MAIN 0xca1b #define MDIO_PMA_REG_PLL_BANDWIDTH 0xca1d -#define MDIO_PMA_REG_GEN_CTRL2 0xca1e +#define MDIO_PMA_REG_PLL_CTRL 0xca1e #define MDIO_PMA_REG_MISC_CTRL0 0xca23 #define MDIO_PMA_REG_LRM_MODE 0xca3f #define MDIO_PMA_REG_CDR_BANDWIDTH 0xca46 #define MDIO_PMA_REG_MISC_CTRL1 0xca85 -#define MDIO_PMA_REG_8726_TWO_WIRE_CTRL 0x8000 -#define MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK 0x000c -#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE 0x0000 -#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE 0x0004 -#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IN_PROGRESS 0x0008 -#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_FAILED 0x000c -#define MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT 0x8002 -#define MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR 0x8003 +#define MDIO_PMA_REG_SFP_TWO_WIRE_CTRL 0x8000 +#define MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK 0x000c +#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE 0x0000 +#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE 0x0004 +#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IN_PROGRESS 0x0008 +#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_FAILED 0x000c +#define MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT 0x8002 +#define MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR 0x8003 #define MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF 0xc820 #define MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK 0xff #define MDIO_PMA_REG_8726_TX_CTRL1 0xca01 #define MDIO_PMA_REG_8726_TX_CTRL2 0xca05 +#define MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR 0x8005 +#define MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF 0x8007 +#define MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK 0xff +#define MDIO_PMA_REG_8727_MISC_CTRL 0x8309 +#define MDIO_PMA_REG_8727_TX_CTRL1 0xca02 +#define MDIO_PMA_REG_8727_TX_CTRL2 0xca05 +#define MDIO_PMA_REG_8727_PCS_OPT_CTRL 0xc808 +#define MDIO_PMA_REG_8727_GPIO_CTRL 0xc80e #define MDIO_PMA_REG_8073_CHIP_REV 0xc801 #define MDIO_PMA_REG_8073_SPEED_LINK_STATUS 0xc820 -- cgit v1.2.3-18-g5258 From ba71d3134176b9791aab7cb78242b6ba1428aac8 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Tue, 21 Jul 2009 05:47:49 +0000 Subject: bnx2x: Set LED in loopback test Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_link.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index b9c85a21457..a24bc51c985 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -5494,6 +5494,11 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) } REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); + + bnx2x_set_led(bp, params->port, LED_MODE_OPER, + vars->line_speed, params->hw_led_mode, + params->chip_id); + } else /* No loopback */ { -- cgit v1.2.3-18-g5258 From 5b6402d10328beb8a9b351ac65a31326ed5fe847 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Tue, 21 Jul 2009 05:47:51 +0000 Subject: bnx2x: Missing parenthesis might result with wrong casting Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 8b6e83d03f9..8bd80fca978 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -160,7 +160,7 @@ struct sw_rx_page { #define PAGES_PER_SGE (1 << PAGES_PER_SGE_SHIFT) #define SGE_PAGE_SIZE PAGE_SIZE #define SGE_PAGE_SHIFT PAGE_SHIFT -#define SGE_PAGE_ALIGN(addr) PAGE_ALIGN((typeof(PAGE_SIZE))addr) +#define SGE_PAGE_ALIGN(addr) PAGE_ALIGN((typeof(PAGE_SIZE))(addr)) /* SGE ring related macros */ #define NUM_RX_SGE_PAGES 2 -- cgit v1.2.3-18-g5258 From e8834a63bddf87f7b85955d1ba60d28343d88469 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Tue, 21 Jul 2009 05:47:55 +0000 Subject: bnx2x: Version 1.48.113-1 Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 197dbe4dad2..c4c42b38bbb 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -56,8 +56,8 @@ #include "bnx2x_init_ops.h" #include "bnx2x_dump.h" -#define DRV_MODULE_VERSION "1.48.105-1" -#define DRV_MODULE_RELDATE "2009/04/22" +#define DRV_MODULE_VERSION "1.48.113-1" +#define DRV_MODULE_RELDATE "2009/07/21" #define BNX2X_BC_VER 0x040200 #include -- cgit v1.2.3-18-g5258 From 4a256b5fc028e6dad0fd1b59745f743ee528c944 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 8 Jul 2009 13:22:18 +0200 Subject: DMA: Rework dw_dmac suspend_late()/resume_early() This patch reworks platform driver power management code for dw_dmac from legacy late/early callbacks to dev_pm_ops. The callbacks are converted for CONFIG_SUSPEND like this: suspend_late() -> suspend_noirq() resume_early() -> resume_noirq() Signed-off-by: Magnus Damm Acked-by: Greg Kroah-Hartman Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki --- drivers/dma/dw_dmac.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 98c9a847bf5..933c143b6a7 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -1399,8 +1399,9 @@ static void dw_shutdown(struct platform_device *pdev) clk_disable(dw->clk); } -static int dw_suspend_late(struct platform_device *pdev, pm_message_t mesg) +static int dw_suspend_noirq(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct dw_dma *dw = platform_get_drvdata(pdev); dw_dma_off(platform_get_drvdata(pdev)); @@ -1408,23 +1409,27 @@ static int dw_suspend_late(struct platform_device *pdev, pm_message_t mesg) return 0; } -static int dw_resume_early(struct platform_device *pdev) +static int dw_resume_noirq(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct dw_dma *dw = platform_get_drvdata(pdev); clk_enable(dw->clk); dma_writel(dw, CFG, DW_CFG_DMA_EN); return 0; - } +static struct dev_pm_ops dw_dev_pm_ops = { + .suspend_noirq = dw_suspend_noirq, + .resume_noirq = dw_resume_noirq, +}; + static struct platform_driver dw_driver = { .remove = __exit_p(dw_remove), .shutdown = dw_shutdown, - .suspend_late = dw_suspend_late, - .resume_early = dw_resume_early, .driver = { .name = "dw_dmac", + .pm = &dw_dev_pm_ops, }, }; -- cgit v1.2.3-18-g5258 From 4aebac2fb9645e897864e12cdb8d1e4aadf5b2a4 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 8 Jul 2009 13:22:27 +0200 Subject: DMA: Rework txx9dmac suspend_late()/resume_early() This patch reworks platform driver power management code for txx9dmac from legacy late/early callbacks to dev_pm_ops. The callbacks are converted for CONFIG_SUSPEND like this: suspend_late() -> suspend_noirq() resume_early() -> resume_noirq() Signed-off-by: Magnus Damm Acked-by: Greg Kroah-Hartman Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki --- drivers/dma/txx9dmac.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/txx9dmac.c b/drivers/dma/txx9dmac.c index 88dab52926f..7837930146a 100644 --- a/drivers/dma/txx9dmac.c +++ b/drivers/dma/txx9dmac.c @@ -1291,17 +1291,18 @@ static void txx9dmac_shutdown(struct platform_device *pdev) txx9dmac_off(ddev); } -static int txx9dmac_suspend_late(struct platform_device *pdev, - pm_message_t mesg) +static int txx9dmac_suspend_noirq(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct txx9dmac_dev *ddev = platform_get_drvdata(pdev); txx9dmac_off(ddev); return 0; } -static int txx9dmac_resume_early(struct platform_device *pdev) +static int txx9dmac_resume_noirq(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct txx9dmac_dev *ddev = platform_get_drvdata(pdev); struct txx9dmac_platform_data *pdata = pdev->dev.platform_data; u32 mcr; @@ -1314,6 +1315,11 @@ static int txx9dmac_resume_early(struct platform_device *pdev) } +static struct dev_pm_ops txx9dmac_dev_pm_ops = { + .suspend_noirq = txx9dmac_suspend_noirq, + .resume_noirq = txx9dmac_resume_noirq, +}; + static struct platform_driver txx9dmac_chan_driver = { .remove = __exit_p(txx9dmac_chan_remove), .driver = { @@ -1324,10 +1330,9 @@ static struct platform_driver txx9dmac_chan_driver = { static struct platform_driver txx9dmac_driver = { .remove = __exit_p(txx9dmac_remove), .shutdown = txx9dmac_shutdown, - .suspend_late = txx9dmac_suspend_late, - .resume_early = txx9dmac_resume_early, .driver = { .name = "txx9dmac", + .pm = &txx9dmac_dev_pm_ops, }, }; -- cgit v1.2.3-18-g5258 From 57f4d4f1b72983f8c76e2f232e064730aeffe599 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 8 Jul 2009 13:22:39 +0200 Subject: I2C: Rework i2c-pxa suspend_late()/resume_early() This patch reworks platform driver power management code for i2c-pxa from legacy late/early callbacks to dev_pm_ops. The callbacks are converted for CONFIG_SUSPEND like this: suspend_late() -> suspend_noirq() resume_early() -> resume_noirq() Signed-off-by: Magnus Damm Acked-by: Greg Kroah-Hartman Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki --- drivers/i2c/busses/i2c-pxa.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 762e1e53088..049555777f6 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1134,35 +1134,44 @@ static int __exit i2c_pxa_remove(struct platform_device *dev) } #ifdef CONFIG_PM -static int i2c_pxa_suspend_late(struct platform_device *dev, pm_message_t state) +static int i2c_pxa_suspend_noirq(struct device *dev) { - struct pxa_i2c *i2c = platform_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct pxa_i2c *i2c = platform_get_drvdata(pdev); + clk_disable(i2c->clk); + return 0; } -static int i2c_pxa_resume_early(struct platform_device *dev) +static int i2c_pxa_resume_noirq(struct device *dev) { - struct pxa_i2c *i2c = platform_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct pxa_i2c *i2c = platform_get_drvdata(pdev); clk_enable(i2c->clk); i2c_pxa_reset(i2c); return 0; } + +static struct dev_pm_ops i2c_pxa_dev_pm_ops = { + .suspend_noirq = i2c_pxa_suspend_noirq, + .resume_noirq = i2c_pxa_resume_noirq, +}; + +#define I2C_PXA_DEV_PM_OPS (&i2c_pxa_dev_pm_ops) #else -#define i2c_pxa_suspend_late NULL -#define i2c_pxa_resume_early NULL +#define I2C_PXA_DEV_PM_OPS NULL #endif static struct platform_driver i2c_pxa_driver = { .probe = i2c_pxa_probe, .remove = __exit_p(i2c_pxa_remove), - .suspend_late = i2c_pxa_suspend_late, - .resume_early = i2c_pxa_resume_early, .driver = { .name = "pxa2xx-i2c", .owner = THIS_MODULE, + .pm = I2C_PXA_DEV_PM_OPS, }, .id_table = i2c_pxa_id_table, }; -- cgit v1.2.3-18-g5258 From 6a6c6189b1fef97de9b8b936131fe2085ac42a5a Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 8 Jul 2009 13:22:47 +0200 Subject: I2C: Rework i2c-s3c2410 suspend_late()/resume() V2 This is V2 of the i2c-s3c2410 dev_pm_ops patch. The callbacks are converted for CONFIG_SUSPEND like this: suspend_late() -> suspend_noirq() resume() -> resume() Signed-off-by: Magnus Damm Acked-by: Greg Kroah-Hartman Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki --- drivers/i2c/busses/i2c-s3c2410.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 8f42a4536cd..3be0d6a4d63 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -951,17 +951,20 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) } #ifdef CONFIG_PM -static int s3c24xx_i2c_suspend_late(struct platform_device *dev, - pm_message_t msg) +static int s3c24xx_i2c_suspend_noirq(struct device *dev) { - struct s3c24xx_i2c *i2c = platform_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); + i2c->suspended = 1; + return 0; } -static int s3c24xx_i2c_resume(struct platform_device *dev) +static int s3c24xx_i2c_resume(struct device *dev) { - struct s3c24xx_i2c *i2c = platform_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); i2c->suspended = 0; s3c24xx_i2c_init(i2c); @@ -969,9 +972,14 @@ static int s3c24xx_i2c_resume(struct platform_device *dev) return 0; } +static struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = { + .suspend_noirq = s3c24xx_i2c_suspend_noirq, + .resume = s3c24xx_i2c_resume, +}; + +#define S3C24XX_DEV_PM_OPS (&s3c24xx_i2c_dev_pm_ops) #else -#define s3c24xx_i2c_suspend_late NULL -#define s3c24xx_i2c_resume NULL +#define S3C24XX_DEV_PM_OPS NULL #endif /* device driver for platform bus bits */ @@ -990,12 +998,11 @@ MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); static struct platform_driver s3c24xx_i2c_driver = { .probe = s3c24xx_i2c_probe, .remove = s3c24xx_i2c_remove, - .suspend_late = s3c24xx_i2c_suspend_late, - .resume = s3c24xx_i2c_resume, .id_table = s3c24xx_driver_ids, .driver = { .owner = THIS_MODULE, .name = "s3c-i2c", + .pm = S3C24XX_DEV_PM_OPS, }, }; -- cgit v1.2.3-18-g5258 From 48fea9659ec1a35641db3832adaf3860ecabb6ba Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 8 Jul 2009 13:22:56 +0200 Subject: USB: Rework musb suspend()/resume_early() This patch reworks platform driver power management code for musb from legacy callbacks to dev_pm_ops. The callbacks are converted for CONFIG_SUSPEND like this: suspend() -> suspend() resume_early() -> resume_noirq() Signed-off-by: Magnus Damm Acked-by: Greg Kroah-Hartman Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki --- drivers/usb/musb/musb_core.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 554a414f65d..1191928902f 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2168,8 +2168,9 @@ static int __devexit musb_remove(struct platform_device *pdev) #ifdef CONFIG_PM -static int musb_suspend(struct platform_device *pdev, pm_message_t message) +static int musb_suspend(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); unsigned long flags; struct musb *musb = dev_to_musb(&pdev->dev); @@ -2196,8 +2197,9 @@ static int musb_suspend(struct platform_device *pdev, pm_message_t message) return 0; } -static int musb_resume_early(struct platform_device *pdev) +static int musb_resume_noirq(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct musb *musb = dev_to_musb(&pdev->dev); if (!musb->clock) @@ -2215,9 +2217,14 @@ static int musb_resume_early(struct platform_device *pdev) return 0; } +static struct dev_pm_ops musb_dev_pm_ops = { + .suspend = musb_suspend, + .resume_noirq = musb_resume_noirq, +}; + +#define MUSB_DEV_PM_OPS (&musb_dev_pm_ops) #else -#define musb_suspend NULL -#define musb_resume_early NULL +#define MUSB_DEV_PM_OPS NULL #endif static struct platform_driver musb_driver = { @@ -2225,11 +2232,10 @@ static struct platform_driver musb_driver = { .name = (char *)musb_driver_name, .bus = &platform_bus_type, .owner = THIS_MODULE, + .pm = MUSB_DEV_PM_OPS, }, .remove = __devexit_p(musb_remove), .shutdown = musb_shutdown, - .suspend = musb_suspend, - .resume_early = musb_resume_early, }; /*-------------------------------------------------------------------------*/ -- cgit v1.2.3-18-g5258 From 511647ff58fd0f1c1f415d2c757d841650edac91 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 8 Jul 2009 13:23:07 +0200 Subject: PM: Remove platform device suspend_late()/resume_early() V2 This is V2 of the platform driver power management late/early callback removal patch. The callbacks ->suspend_late() and ->resume_early() are removed since all in-tree users now have been migrated to dev_pm_ops. Signed-off-by: Magnus Damm Acked-by: Greg Kroah-Hartman Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki --- drivers/base/platform.c | 36 ------------------------------------ 1 file changed, 36 deletions(-) (limited to 'drivers') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 81cb01bfc35..455e55971d0 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -628,30 +628,6 @@ static int platform_legacy_suspend(struct device *dev, pm_message_t mesg) return ret; } -static int platform_legacy_suspend_late(struct device *dev, pm_message_t mesg) -{ - struct platform_driver *pdrv = to_platform_driver(dev->driver); - struct platform_device *pdev = to_platform_device(dev); - int ret = 0; - - if (dev->driver && pdrv->suspend_late) - ret = pdrv->suspend_late(pdev, mesg); - - return ret; -} - -static int platform_legacy_resume_early(struct device *dev) -{ - struct platform_driver *pdrv = to_platform_driver(dev->driver); - struct platform_device *pdev = to_platform_device(dev); - int ret = 0; - - if (dev->driver && pdrv->resume_early) - ret = pdrv->resume_early(pdev); - - return ret; -} - static int platform_legacy_resume(struct device *dev) { struct platform_driver *pdrv = to_platform_driver(dev->driver); @@ -714,8 +690,6 @@ static int platform_pm_suspend_noirq(struct device *dev) if (drv->pm) { if (drv->pm->suspend_noirq) ret = drv->pm->suspend_noirq(dev); - } else { - ret = platform_legacy_suspend_late(dev, PMSG_SUSPEND); } return ret; @@ -750,8 +724,6 @@ static int platform_pm_resume_noirq(struct device *dev) if (drv->pm) { if (drv->pm->resume_noirq) ret = drv->pm->resume_noirq(dev); - } else { - ret = platform_legacy_resume_early(dev); } return ret; @@ -797,8 +769,6 @@ static int platform_pm_freeze_noirq(struct device *dev) if (drv->pm) { if (drv->pm->freeze_noirq) ret = drv->pm->freeze_noirq(dev); - } else { - ret = platform_legacy_suspend_late(dev, PMSG_FREEZE); } return ret; @@ -833,8 +803,6 @@ static int platform_pm_thaw_noirq(struct device *dev) if (drv->pm) { if (drv->pm->thaw_noirq) ret = drv->pm->thaw_noirq(dev); - } else { - ret = platform_legacy_resume_early(dev); } return ret; @@ -869,8 +837,6 @@ static int platform_pm_poweroff_noirq(struct device *dev) if (drv->pm) { if (drv->pm->poweroff_noirq) ret = drv->pm->poweroff_noirq(dev); - } else { - ret = platform_legacy_suspend_late(dev, PMSG_HIBERNATE); } return ret; @@ -905,8 +871,6 @@ static int platform_pm_restore_noirq(struct device *dev) if (drv->pm) { if (drv->pm->restore_noirq) ret = drv->pm->restore_noirq(dev); - } else { - ret = platform_legacy_resume_early(dev); } return ret; -- cgit v1.2.3-18-g5258 From 0810b51170570ed21cae56b8131db6a5e3efa584 Mon Sep 17 00:00:00 2001 From: Robert Schedel Date: Tue, 23 Jun 2009 11:26:48 +0200 Subject: HID: Support new variants of Samsung USB IR receiver (0419:0001) This patch extends the existing Samsung IrDA (0419:0001) quirk file with newly reported variants: * New device variants with 203 byte and 135 byte report descriptors were reported to be recognized incorrectly. This patch adds an autodetection for those two, using report descriptor size to enable new quirks. * Any other unknown 0419:0001 variants will now be treated without any quirk flags (i.e. IGNORE_HIDINPUT/HIDDEV_FORCE will not be set by default anymore). More details: 1. Descriptor size 184 bytes ("Satelco bundled remote") Already supported since kernel 2.6.25 (my old patch). 2. Descriptor size 203 bytes ("Optronix remote") This receiver mostly works with the regular HID input driver. Only when some keys are released, another spurious key press event is interpreted due to incorrect array ranges. According to HID 1.11, section 6.2.2.5, arrays should return a 0 value when no control is asserted, and ranges should go from 1 to the number of elements. The patch clips the value with a logical range from 1..15 (instead of originally 0..18). Ticket with more information available at https://bugs.launchpad.net/bugs/326986 3. Descriptor size 135 bytes ("Gotview remote") This receiver has a similar issue than the previous one, i.e. it mostly works with regular HID input, except some key press events get stuck on key release. The patch clips the array value from 1..14 (instead of originally 0..17). Ticket with more information available at http://bugs.archlinux.org/task/15216 4. Other unknown variants (found one report with 218 bytes, but no further information about issues) For such unknown variants we should refrain from changing any device flags. Currently, HIDINPUT is suppressed and HIDDEV is enforced (because in 2.6.25 the quirk table did not yet allow differentiating variants and we did not expect variants either). Now we should be as strict as possible and enable it only for the first variant above. Signed-off-by: Robert Schedel Signed-off-by: Jiri Kosina --- drivers/hid/hid-samsung.c | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c index 07083aa6c19..ba91d9485ad 100644 --- a/drivers/hid/hid-samsung.c +++ b/drivers/hid/hid-samsung.c @@ -25,25 +25,48 @@ /* * Samsung IrDA remote controller (reports as Cypress USB Mouse). * + * There are several variants for 0419:0001: + * + * 1. 184 byte report descriptor * Vendor specific report #4 has a size of 48 bit, * and therefore is not accepted when inspecting the descriptors. * As a workaround we reinterpret the report as: * Variable type, count 6, size 8 bit, log. maximum 255 * The burden to reconstruct the data is moved into user space. + * + * 2. 203 byte report descriptor + * Report #4 has an array field with logical range 0..18 instead of 1..15. + * + * 3. 135 byte report descriptor + * Report #4 has an array field with logical range 0..17 instead of 1..14. */ static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int rsize) { - if (rsize >= 182 && rdesc[175] == 0x25 && rdesc[176] == 0x40 && + if (rsize == 184 && rdesc[175] == 0x25 && rdesc[176] == 0x40 && rdesc[177] == 0x75 && rdesc[178] == 0x30 && rdesc[179] == 0x95 && rdesc[180] == 0x01 && rdesc[182] == 0x40) { - dev_info(&hdev->dev, "fixing up Samsung IrDA report " - "descriptor\n"); + dev_info(&hdev->dev, "fixing up Samsung IrDA %d byte report " + "descriptor\n", 184); rdesc[176] = 0xff; rdesc[178] = 0x08; rdesc[180] = 0x06; rdesc[182] = 0x42; + } else + if (rsize == 203 && rdesc[192] == 0x15 && rdesc[193] == 0x0 && + rdesc[194] == 0x25 && rdesc[195] == 0x12) { + dev_info(&hdev->dev, "fixing up Samsung IrDA %d byte report " + "descriptor\n", 203); + rdesc[193] = 0x1; + rdesc[195] = 0xf; + } else + if (rsize == 135 && rdesc[124] == 0x15 && rdesc[125] == 0x0 && + rdesc[126] == 0x25 && rdesc[127] == 0x11) { + dev_info(&hdev->dev, "fixing up Samsung IrDA %d byte report " + "descriptor\n", 135); + rdesc[125] = 0x1; + rdesc[127] = 0xe; } } @@ -51,6 +74,7 @@ static int samsung_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret; + unsigned int cmask = HID_CONNECT_DEFAULT; ret = hid_parse(hdev); if (ret) { @@ -58,8 +82,13 @@ static int samsung_probe(struct hid_device *hdev, goto err_free; } - ret = hid_hw_start(hdev, (HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDINPUT) | - HID_CONNECT_HIDDEV_FORCE); + if (hdev->rsize == 184) { + /* disable hidinput, force hiddev */ + cmask = (cmask & ~HID_CONNECT_HIDINPUT) | + HID_CONNECT_HIDDEV_FORCE; + } + + ret = hid_hw_start(hdev, cmask); if (ret) { dev_err(&hdev->dev, "hw start failed\n"); goto err_free; -- cgit v1.2.3-18-g5258 From fd30ea8c871552ddd6a5e1c0886de8fef4df53bc Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Tue, 23 Jun 2009 12:11:31 +0200 Subject: HID: add force feedback support for Logitech WingMan Formula Force GP Add force feedback support for Logitech WingMan Formula Force GP (0x046d/0xc293). Reported-by: wylda@volny.cz Tested-by: wylda@volny.cz Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-lg.c | 2 ++ drivers/hid/hid-lgff.c | 1 + 5 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 7831a0318d3..d3910c64bf0 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -176,6 +176,7 @@ config LOGITECH_FF - Logitech WingMan Cordless RumblePad 2 - Logitech WingMan Force 3D - Logitech Formula Force EX + - Logitech WingMan Formula Force GP - Logitech MOMO Force wheel and if you want to enable force feedback for them. diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 5eb10c2ce66..d51091df5c1 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1292,6 +1292,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 63010103792..398f731fd69 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -296,6 +296,7 @@ #define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283 #define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286 #define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294 +#define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG 0xc293 #define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295 #define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299 #define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index 7afbaa0efd1..b30af30a0b1 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -299,6 +299,8 @@ static const struct hid_device_id lg_devices[] = { .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL), .driver_data = LG_FF }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ), + .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2), .driver_data = LG_FF2 }, { } diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c index 56099709581..95835ea5690 100644 --- a/drivers/hid/hid-lgff.c +++ b/drivers/hid/hid-lgff.c @@ -67,6 +67,7 @@ static const struct dev_type devices[] = { { 0x046d, 0xc219, ff_rumble }, { 0x046d, 0xc283, ff_joystick }, { 0x046d, 0xc286, ff_joystick_ac }, + { 0x046d, 0xc293, ff_joystick }, { 0x046d, 0xc294, ff_wheel }, { 0x046d, 0xc295, ff_joystick }, { 0x046d, 0xca03, ff_wheel }, -- cgit v1.2.3-18-g5258 From 8b424887b603e953af7238fef96629424dc915cb Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 23 Jun 2009 15:32:19 +0200 Subject: HID: Avoid double spin_lock_init on usbhid->lock Avoid double spin_lock_init on usbhid->lock. Signed-off-by: Sergey Senozhatsky Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 3c1fcb7640a..9238bcffaf0 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -985,7 +985,6 @@ static int usbhid_start(struct hid_device *hid) INIT_WORK(&usbhid->restart_work, __usbhid_restart_queues); setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid); - spin_lock_init(&usbhid->lock); spin_lock_init(&usbhid->lock); usbhid->intf = intf; -- cgit v1.2.3-18-g5258 From 837b47533a6476ab3fb96b1f52edd3ce9f3162b8 Mon Sep 17 00:00:00 2001 From: Rafi Rubin Date: Tue, 23 Jun 2009 14:09:26 -0400 Subject: HID: ntrig tool separation and pen usages When both touch and pen are active send a tool announcement before sending any status changes so that event users may differentiate which tool is changing. Restored three usage codes used by the pen. Signed-off-by: Rafi Rubin Acked-by: Stephane Chatty Signed-off-by: Jiri Kosina --- drivers/hid/hid-ntrig.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index 75ed9d2c1a3..d7b3e61fbf8 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c @@ -27,6 +27,9 @@ struct ntrig_data { __s32 x, y, id, w, h; char reading_a_point, found_contact_id; + char pen_active; + char finger_active; + char inverted; }; /* @@ -63,10 +66,7 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_UP_DIGITIZER: switch (usage->hid) { /* we do not want to map these for now */ - case HID_DG_INVERT: /* value is always 0 */ - case HID_DG_ERASER: /* value is always 0 */ case HID_DG_CONTACTID: /* value is useless */ - case HID_DG_BARRELSWITCH: /* doubtful */ case HID_DG_INPUTMODE: case HID_DG_DEVICEINDEX: case HID_DG_CONTACTCOUNT: @@ -125,6 +125,18 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, if (hid->claimed & HID_CLAIMED_INPUT) { switch (usage->hid) { + + case HID_DG_INRANGE: + if (field->application & 0x3) + nd->pen_active = (value != 0); + else + nd->finger_active = (value != 0); + return 0; + + case HID_DG_INVERT: + nd->inverted = value; + return 0; + case HID_GD_X: nd->x = value; nd->reading_a_point = 1; @@ -147,7 +159,11 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, * report received in a finger event. We want * to emit a normal (X, Y) position */ - if (! nd->found_contact_id) { + if (!nd->found_contact_id) { + if (nd->pen_active && nd->finger_active) { + input_report_key(input, BTN_TOOL_DOUBLETAP, 0); + input_report_key(input, BTN_TOOL_DOUBLETAP, 1); + } input_event(input, EV_ABS, ABS_X, nd->x); input_event(input, EV_ABS, ABS_Y, nd->y); } @@ -159,6 +175,14 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, * to emit a normal (X, Y) position */ if (! nd->found_contact_id) { + if (nd->pen_active && nd->finger_active) { + input_report_key(input, + nd->inverted ? BTN_TOOL_RUBBER : BTN_TOOL_PEN + , 0); + input_report_key(input, + nd->inverted ? BTN_TOOL_RUBBER : BTN_TOOL_PEN + , 1); + } input_event(input, EV_ABS, ABS_X, nd->x); input_event(input, EV_ABS, ABS_Y, nd->y); input_event(input, EV_ABS, ABS_PRESSURE, value); @@ -233,6 +257,7 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) if (ret) kfree (nd); + return ret; } -- cgit v1.2.3-18-g5258 From 7a84b1336a145d683fb8cdfd6c2c67545a58b126 Mon Sep 17 00:00:00 2001 From: Ruben Aos Garralda Date: Mon, 29 Jun 2009 09:41:29 +0200 Subject: HID: add rumble support for Thrustmaster Dual Trigger 3-in-1 This patch enables rumble in Thrustmaster Dual 3-in-1 trigger gamepads (in both PC and PS3 modes). It uses the same code as Thrustmaster FireStorm Dual Power 2, so it only adds new USB IDs to hid-core.c and hid-tmff.c Signed-off-by: Ruben Aos Garralda Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 6 +++--- drivers/hid/hid-core.c | 2 ++ drivers/hid/hid-tmff.c | 6 +++++- 3 files changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index d3910c64bf0..a66ffe747d9 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -315,9 +315,9 @@ config THRUSTMASTER_FF depends on HID_THRUSTMASTER select INPUT_FF_MEMLESS ---help--- - Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or - a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel and - want to enable force feedback support for it. + Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or 3, + a THRUSTMASTER Dual Trigger 3-in-1 or a THRUSTMASTER Ferrari GT + Rumble Force or Force Feedback Wheel. config HID_WACOM tristate "Wacom Bluetooth devices support" if EMBEDDED diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index d51091df5c1..5601a1432e0 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1312,6 +1312,8 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) }, + { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323) }, + { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb324) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) }, { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) }, diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c index fcd6ccd02fe..6589a7c790e 100644 --- a/drivers/hid/hid-tmff.c +++ b/drivers/hid/hid-tmff.c @@ -243,7 +243,11 @@ err: static const struct hid_device_id tm_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300), .driver_data = (unsigned long)ff_rumble }, - { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304), + { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304), /* FireStorm Dual Power 2 (and 3) */ + .driver_data = (unsigned long)ff_rumble }, + { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323), /* Dual Trigger 3-in-1 (PC Mode) */ + .driver_data = (unsigned long)ff_rumble }, + { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb324), /* Dual Trigger 3-in-1 (PS3 Mode) */ .driver_data = (unsigned long)ff_rumble }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651), /* FGT Rumble Force Wheel */ .driver_data = (unsigned long)ff_rumble }, -- cgit v1.2.3-18-g5258 From a24f423bdf253ccee369adc6c5451b40a0716fbb Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Thu, 2 Jul 2009 19:08:38 +0200 Subject: HID: adding __init/__exit macros to module init/exit functions Trivial patch which adds the __init and __exit macros to the module_init / module_exit functions of several HID drivers from drivers/hid/ Signed-off-by: Peter Huewe Signed-off-by: Jiri Kosina --- drivers/hid/hid-a4tech.c | 4 ++-- drivers/hid/hid-apple.c | 4 ++-- drivers/hid/hid-belkin.c | 4 ++-- drivers/hid/hid-cherry.c | 4 ++-- drivers/hid/hid-chicony.c | 4 ++-- drivers/hid/hid-cypress.c | 4 ++-- drivers/hid/hid-ezkey.c | 4 ++-- drivers/hid/hid-gyration.c | 4 ++-- drivers/hid/hid-kensington.c | 4 ++-- drivers/hid/hid-kye.c | 4 ++-- drivers/hid/hid-lg.c | 4 ++-- drivers/hid/hid-microsoft.c | 4 ++-- drivers/hid/hid-monterey.c | 4 ++-- drivers/hid/hid-ntrig.c | 4 ++-- drivers/hid/hid-petalynx.c | 4 ++-- drivers/hid/hid-pl.c | 4 ++-- drivers/hid/hid-samsung.c | 4 ++-- drivers/hid/hid-sjoy.c | 4 ++-- drivers/hid/hid-sony.c | 4 ++-- drivers/hid/hid-sunplus.c | 4 ++-- drivers/hid/hid-tmff.c | 4 ++-- drivers/hid/hid-topseed.c | 4 ++-- drivers/hid/hid-wacom.c | 4 ++-- drivers/hid/hid-zpff.c | 4 ++-- 24 files changed, 48 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-a4tech.c b/drivers/hid/hid-a4tech.c index 42ea359e94c..df474c699fb 100644 --- a/drivers/hid/hid-a4tech.c +++ b/drivers/hid/hid-a4tech.c @@ -145,12 +145,12 @@ static struct hid_driver a4_driver = { .remove = a4_remove, }; -static int a4_init(void) +static int __init a4_init(void) { return hid_register_driver(&a4_driver); } -static void a4_exit(void) +static void __exit a4_exit(void) { hid_unregister_driver(&a4_driver); } diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 303ccce05bb..4b96e7a898c 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -451,7 +451,7 @@ static struct hid_driver apple_driver = { .input_mapped = apple_input_mapped, }; -static int apple_init(void) +static int __init apple_init(void) { int ret; @@ -462,7 +462,7 @@ static int apple_init(void) return ret; } -static void apple_exit(void) +static void __exit apple_exit(void) { hid_unregister_driver(&apple_driver); } diff --git a/drivers/hid/hid-belkin.c b/drivers/hid/hid-belkin.c index 2f6723133a4..4ce7aa3a519 100644 --- a/drivers/hid/hid-belkin.c +++ b/drivers/hid/hid-belkin.c @@ -88,12 +88,12 @@ static struct hid_driver belkin_driver = { .probe = belkin_probe, }; -static int belkin_init(void) +static int __init belkin_init(void) { return hid_register_driver(&belkin_driver); } -static void belkin_exit(void) +static void __exit belkin_exit(void) { hid_unregister_driver(&belkin_driver); } diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c index ab8209e7e45..7e597d7f770 100644 --- a/drivers/hid/hid-cherry.c +++ b/drivers/hid/hid-cherry.c @@ -70,12 +70,12 @@ static struct hid_driver ch_driver = { .input_mapping = ch_input_mapping, }; -static int ch_init(void) +static int __init ch_init(void) { return hid_register_driver(&ch_driver); } -static void ch_exit(void) +static void __exit ch_exit(void) { hid_unregister_driver(&ch_driver); } diff --git a/drivers/hid/hid-chicony.c b/drivers/hid/hid-chicony.c index 7f91076d849..8965ad93d51 100644 --- a/drivers/hid/hid-chicony.c +++ b/drivers/hid/hid-chicony.c @@ -63,12 +63,12 @@ static struct hid_driver ch_driver = { .input_mapping = ch_input_mapping, }; -static int ch_init(void) +static int __init ch_init(void) { return hid_register_driver(&ch_driver); } -static void ch_exit(void) +static void __exit ch_exit(void) { hid_unregister_driver(&ch_driver); } diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c index 9d6d3b91773..62e9cb10e88 100644 --- a/drivers/hid/hid-cypress.c +++ b/drivers/hid/hid-cypress.c @@ -141,12 +141,12 @@ static struct hid_driver cp_driver = { .probe = cp_probe, }; -static int cp_init(void) +static int __init cp_init(void) { return hid_register_driver(&cp_driver); } -static void cp_exit(void) +static void __exit cp_exit(void) { hid_unregister_driver(&cp_driver); } diff --git a/drivers/hid/hid-ezkey.c b/drivers/hid/hid-ezkey.c index 0a1fe054799..ca1163e9d42 100644 --- a/drivers/hid/hid-ezkey.c +++ b/drivers/hid/hid-ezkey.c @@ -78,12 +78,12 @@ static struct hid_driver ez_driver = { .event = ez_event, }; -static int ez_init(void) +static int __init ez_init(void) { return hid_register_driver(&ez_driver); } -static void ez_exit(void) +static void __exit ez_exit(void) { hid_unregister_driver(&ez_driver); } diff --git a/drivers/hid/hid-gyration.c b/drivers/hid/hid-gyration.c index d42d222097a..cab13e8c7d2 100644 --- a/drivers/hid/hid-gyration.c +++ b/drivers/hid/hid-gyration.c @@ -81,12 +81,12 @@ static struct hid_driver gyration_driver = { .event = gyration_event, }; -static int gyration_init(void) +static int __init gyration_init(void) { return hid_register_driver(&gyration_driver); } -static void gyration_exit(void) +static void __exit gyration_exit(void) { hid_unregister_driver(&gyration_driver); } diff --git a/drivers/hid/hid-kensington.c b/drivers/hid/hid-kensington.c index 7353bd79cbe..a5b4016e9bd 100644 --- a/drivers/hid/hid-kensington.c +++ b/drivers/hid/hid-kensington.c @@ -48,12 +48,12 @@ static struct hid_driver ks_driver = { .input_mapping = ks_input_mapping, }; -static int ks_init(void) +static int __init ks_init(void) { return hid_register_driver(&ks_driver); } -static void ks_exit(void) +static void __exit ks_exit(void) { hid_unregister_driver(&ks_driver); } diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c index 72ee3fec56d..f8871712b7b 100644 --- a/drivers/hid/hid-kye.c +++ b/drivers/hid/hid-kye.c @@ -54,12 +54,12 @@ static struct hid_driver kye_driver = { .report_fixup = kye_report_fixup, }; -static int kye_init(void) +static int __init kye_init(void) { return hid_register_driver(&kye_driver); } -static void kye_exit(void) +static void __exit kye_exit(void) { hid_unregister_driver(&kye_driver); } diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index b30af30a0b1..0f870a3243e 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -317,12 +317,12 @@ static struct hid_driver lg_driver = { .probe = lg_probe, }; -static int lg_init(void) +static int __init lg_init(void) { return hid_register_driver(&lg_driver); } -static void lg_exit(void) +static void __exit lg_exit(void) { hid_unregister_driver(&lg_driver); } diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index 5e9e37a0506..359cc447c6c 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -197,12 +197,12 @@ static struct hid_driver ms_driver = { .probe = ms_probe, }; -static int ms_init(void) +static int __init ms_init(void) { return hid_register_driver(&ms_driver); } -static void ms_exit(void) +static void __exit ms_exit(void) { hid_unregister_driver(&ms_driver); } diff --git a/drivers/hid/hid-monterey.c b/drivers/hid/hid-monterey.c index 240f87618be..2cd05aa244b 100644 --- a/drivers/hid/hid-monterey.c +++ b/drivers/hid/hid-monterey.c @@ -65,12 +65,12 @@ static struct hid_driver mr_driver = { .input_mapping = mr_input_mapping, }; -static int mr_init(void) +static int __init mr_init(void) { return hid_register_driver(&mr_driver); } -static void mr_exit(void) +static void __exit mr_exit(void) { hid_unregister_driver(&mr_driver); } diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index d7b3e61fbf8..49ce69d7bba 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c @@ -290,12 +290,12 @@ static struct hid_driver ntrig_driver = { .event = ntrig_event, }; -static int ntrig_init(void) +static int __init ntrig_init(void) { return hid_register_driver(&ntrig_driver); } -static void ntrig_exit(void) +static void __exit ntrig_exit(void) { hid_unregister_driver(&ntrig_driver); } diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c index 2e83e8ff891..500fbd0652d 100644 --- a/drivers/hid/hid-petalynx.c +++ b/drivers/hid/hid-petalynx.c @@ -105,12 +105,12 @@ static struct hid_driver pl_driver = { .probe = pl_probe, }; -static int pl_init(void) +static int __init pl_init(void) { return hid_register_driver(&pl_driver); } -static void pl_exit(void) +static void __exit pl_exit(void) { hid_unregister_driver(&pl_driver); } diff --git a/drivers/hid/hid-pl.c b/drivers/hid/hid-pl.c index 4db9a348376..c6d7dbc935b 100644 --- a/drivers/hid/hid-pl.c +++ b/drivers/hid/hid-pl.c @@ -217,12 +217,12 @@ static struct hid_driver pl_driver = { .probe = pl_probe, }; -static int pl_init(void) +static int __init pl_init(void) { return hid_register_driver(&pl_driver); } -static void pl_exit(void) +static void __exit pl_exit(void) { hid_unregister_driver(&pl_driver); } diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c index ba91d9485ad..5b222eed069 100644 --- a/drivers/hid/hid-samsung.c +++ b/drivers/hid/hid-samsung.c @@ -112,12 +112,12 @@ static struct hid_driver samsung_driver = { .probe = samsung_probe, }; -static int samsung_init(void) +static int __init samsung_init(void) { return hid_register_driver(&samsung_driver); } -static void samsung_exit(void) +static void __exit samsung_exit(void) { hid_unregister_driver(&samsung_driver); } diff --git a/drivers/hid/hid-sjoy.c b/drivers/hid/hid-sjoy.c index eab169e5c37..203c438b016 100644 --- a/drivers/hid/hid-sjoy.c +++ b/drivers/hid/hid-sjoy.c @@ -163,12 +163,12 @@ static struct hid_driver sjoy_driver = { .probe = sjoy_probe, }; -static int sjoy_init(void) +static int __init sjoy_init(void) { return hid_register_driver(&sjoy_driver); } -static void sjoy_exit(void) +static void __exit sjoy_exit(void) { hid_unregister_driver(&sjoy_driver); } diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index c2599388a35..4e8450228a2 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -135,12 +135,12 @@ static struct hid_driver sony_driver = { .report_fixup = sony_report_fixup, }; -static int sony_init(void) +static int __init sony_init(void) { return hid_register_driver(&sony_driver); } -static void sony_exit(void) +static void __exit sony_exit(void) { hid_unregister_driver(&sony_driver); } diff --git a/drivers/hid/hid-sunplus.c b/drivers/hid/hid-sunplus.c index e0a8fd36a85..438107d9f1b 100644 --- a/drivers/hid/hid-sunplus.c +++ b/drivers/hid/hid-sunplus.c @@ -65,12 +65,12 @@ static struct hid_driver sp_driver = { .input_mapping = sp_input_mapping, }; -static int sp_init(void) +static int __init sp_init(void) { return hid_register_driver(&sp_driver); } -static void sp_exit(void) +static void __exit sp_exit(void) { hid_unregister_driver(&sp_driver); } diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c index 6589a7c790e..167ea746fb9 100644 --- a/drivers/hid/hid-tmff.c +++ b/drivers/hid/hid-tmff.c @@ -263,12 +263,12 @@ static struct hid_driver tm_driver = { .probe = tm_probe, }; -static int tm_init(void) +static int __init tm_init(void) { return hid_register_driver(&tm_driver); } -static void tm_exit(void) +static void __exit tm_exit(void) { hid_unregister_driver(&tm_driver); } diff --git a/drivers/hid/hid-topseed.c b/drivers/hid/hid-topseed.c index 152ccfabeba..6925eda1081 100644 --- a/drivers/hid/hid-topseed.c +++ b/drivers/hid/hid-topseed.c @@ -60,12 +60,12 @@ static struct hid_driver ts_driver = { .input_mapping = ts_input_mapping, }; -static int ts_init(void) +static int __init ts_init(void) { return hid_register_driver(&ts_driver); } -static void ts_exit(void) +static void __exit ts_exit(void) { hid_unregister_driver(&ts_driver); } diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index 1f9237f511e..74754217224 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c @@ -237,7 +237,7 @@ static struct hid_driver wacom_driver = { .raw_event = wacom_raw_event, }; -static int wacom_init(void) +static int __init wacom_init(void) { int ret; @@ -248,7 +248,7 @@ static int wacom_init(void) return ret; } -static void wacom_exit(void) +static void __exit wacom_exit(void) { hid_unregister_driver(&wacom_driver); } diff --git a/drivers/hid/hid-zpff.c b/drivers/hid/hid-zpff.c index 57f710757bf..a79f0d78c6b 100644 --- a/drivers/hid/hid-zpff.c +++ b/drivers/hid/hid-zpff.c @@ -152,12 +152,12 @@ static struct hid_driver zp_driver = { .probe = zp_probe, }; -static int zp_init(void) +static int __init zp_init(void) { return hid_register_driver(&zp_driver); } -static void zp_exit(void) +static void __exit zp_exit(void) { hid_unregister_driver(&zp_driver); } -- cgit v1.2.3-18-g5258 From 711a680e35059bc5c7c28d3c4bd0bebd3b7bb6ee Mon Sep 17 00:00:00 2001 From: Bruno Premont Date: Mon, 13 Jul 2009 14:19:58 +0200 Subject: HID: driver for Twinhan USB 6253:0100 remote control Add explicit key mappings for TwinHan USB HID remote control. All dummy Ctrl, Alt, Meta, ... key press/release events generated by the remote are silenced by "unmapping" them. This makes Power and Volume keys single-key and strips the regular (even while idle) key release events for Ctrl, Alt, Meta, ... Signed-off-by: Bruno Premont Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 +++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 + drivers/hid/hid-twinhan.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 159 insertions(+) create mode 100644 drivers/hid/hid-twinhan.c (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index a66ffe747d9..aba8facecce 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -152,6 +152,13 @@ config HID_GYRATION ---help--- Support for Gyration remote control. +config HID_TWINHAN + tristate "Twinhan" if EMBEDDED + depends on USB_HID + default !EMBEDDED + ---help--- + Support for Twinhan IR remote control. + config HID_KENSINGTON tristate "Kensington" if EMBEDDED depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index db35151673b..9b9271d6527 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o +obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o obj-$(CONFIG_HID_WACOM) += hid-wacom.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 5601a1432e0..6164ed3a414 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1317,6 +1317,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) }, { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 398f731fd69..3058e472aeb 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -404,6 +404,9 @@ #define USB_VENDOR_ID_TURBOX 0x062a #define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201 +#define USB_VENDOR_ID_TWINHAN 0x6253 +#define USB_DEVICE_ID_TWINHAN_IR_REMOTE 0x0100 + #define USB_VENDOR_ID_UCLOGIC 0x5543 #define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209 0x0042 diff --git a/drivers/hid/hid-twinhan.c b/drivers/hid/hid-twinhan.c new file mode 100644 index 00000000000..b05f602c051 --- /dev/null +++ b/drivers/hid/hid-twinhan.c @@ -0,0 +1,147 @@ +/* + * HID driver for TwinHan IR remote control + * + * Based on hid-gyration.c + * + * Copyright (c) 2009 Bruno Prémont + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License. + */ + +#include +#include +#include +#include + +#include "hid-ids.h" + +/* Remote control key layout + listing: + * + * Full Screen Power + * KEY_SCREEN KEY_POWER2 + * + * 1 2 3 + * KEY_NUMERIC_1 KEY_NUMERIC_2 KEY_NUMERIC_3 + * + * 4 5 6 + * KEY_NUMERIC_4 KEY_NUMERIC_5 KEY_NUMERIC_6 + * + * 7 8 9 + * KEY_NUMERIC_7 KEY_NUMERIC_8 KEY_NUMERIC_9 + * + * REC 0 Favorite + * KEY_RECORD KEY_NUMERIC_0 KEY_FAVORITES + * + * Rewind Forward + * KEY_REWIND CH+ KEY_FORWARD + * KEY_CHANNELUP + * + * VOL- > VOL+ + * KEY_VOLUMEDOWN KEY_PLAY KEY_VOLUMEUP + * + * CH- + * KEY_CHANNELDOWN + * Recall Stop + * KEY_RESTART KEY_STOP + * + * Timeshift/Pause Mute Cancel + * KEY_PAUSE KEY_MUTE KEY_CANCEL + * + * Capture Preview EPG + * KEY_PRINT KEY_PROGRAM KEY_EPG + * + * Record List Tab Teletext + * KEY_LIST KEY_TAB KEY_TEXT + */ + +#define th_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ + EV_KEY, (c)) +static int twinhan_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_KEYBOARD) + return 0; + + switch (usage->hid & HID_USAGE) { + /* Map all keys from Twinhan Remote */ + case 0x004: th_map_key_clear(KEY_TEXT); break; + case 0x006: th_map_key_clear(KEY_RESTART); break; + case 0x008: th_map_key_clear(KEY_EPG); break; + case 0x00c: th_map_key_clear(KEY_REWIND); break; + case 0x00e: th_map_key_clear(KEY_PROGRAM); break; + case 0x00f: th_map_key_clear(KEY_LIST); break; + case 0x010: th_map_key_clear(KEY_MUTE); break; + case 0x011: th_map_key_clear(KEY_FORWARD); break; + case 0x013: th_map_key_clear(KEY_PRINT); break; + case 0x017: th_map_key_clear(KEY_PAUSE); break; + case 0x019: th_map_key_clear(KEY_FAVORITES); break; + case 0x01d: th_map_key_clear(KEY_SCREEN); break; + case 0x01e: th_map_key_clear(KEY_NUMERIC_1); break; + case 0x01f: th_map_key_clear(KEY_NUMERIC_2); break; + case 0x020: th_map_key_clear(KEY_NUMERIC_3); break; + case 0x021: th_map_key_clear(KEY_NUMERIC_4); break; + case 0x022: th_map_key_clear(KEY_NUMERIC_5); break; + case 0x023: th_map_key_clear(KEY_NUMERIC_6); break; + case 0x024: th_map_key_clear(KEY_NUMERIC_7); break; + case 0x025: th_map_key_clear(KEY_NUMERIC_8); break; + case 0x026: th_map_key_clear(KEY_NUMERIC_9); break; + case 0x027: th_map_key_clear(KEY_NUMERIC_0); break; + case 0x028: th_map_key_clear(KEY_PLAY); break; + case 0x029: th_map_key_clear(KEY_CANCEL); break; + case 0x02b: th_map_key_clear(KEY_TAB); break; + /* Power = 0x0e0 + 0x0e1 + 0x0e2 + 0x03f */ + case 0x03f: th_map_key_clear(KEY_POWER2); break; + case 0x04a: th_map_key_clear(KEY_RECORD); break; + case 0x04b: th_map_key_clear(KEY_CHANNELUP); break; + case 0x04d: th_map_key_clear(KEY_STOP); break; + case 0x04e: th_map_key_clear(KEY_CHANNELDOWN); break; + /* Volume down = 0x0e1 + 0x051 */ + case 0x051: th_map_key_clear(KEY_VOLUMEDOWN); break; + /* Volume up = 0x0e1 + 0x052 */ + case 0x052: th_map_key_clear(KEY_VOLUMEUP); break; + /* Kill the extra keys used for multi-key "power" and "volume" keys + * as well as continuously to release CTRL,ALT,META,... keys */ + case 0x0e0: + case 0x0e1: + case 0x0e2: + case 0x0e3: + case 0x0e4: + case 0x0e5: + case 0x0e6: + case 0x0e7: + default: + return -1; + } + return 1; +} + +static const struct hid_device_id twinhan_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) }, + { } +}; +MODULE_DEVICE_TABLE(hid, twinhan_devices); + +static struct hid_driver twinhan_driver = { + .name = "twinhan", + .id_table = twinhan_devices, + .input_mapping = twinhan_input_mapping, +}; + +static int twinhan_init(void) +{ + return hid_register_driver(&twinhan_driver); +} + +static void twinhan_exit(void) +{ + hid_unregister_driver(&twinhan_driver); +} + +module_init(twinhan_init); +module_exit(twinhan_exit); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-18-g5258 From 3040c8203d68a9a0564af81729085054fd6b5b03 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 12 Jul 2009 09:42:47 +0200 Subject: HID: Drop NULL test on list_entry result list_entry, which is an alias for container_of, cannot return NULL, as there is no way to add a NULL value to a doubly linked list. A simplified version of the semantic match that findds this problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r@ expression x,E; statement S1,S2; position p,p1; @@ *x = list_entry@p(...) ... when != x = E *if@p1 (x == NULL) S1 else S2 // Signed-off-by: Julia Lawall Signed-off-by: Jiri Kosina --- drivers/hid/hid-lgff.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c index 95835ea5690..987abebe082 100644 --- a/drivers/hid/hid-lgff.c +++ b/drivers/hid/hid-lgff.c @@ -151,11 +151,6 @@ int lgff_init(struct hid_device* hid) /* Check that the report looks ok */ report = list_entry(report_list->next, struct hid_report, list); - if (!report) { - err_hid("NULL output report"); - return -1; - } - field = report->field[0]; if (!field) { err_hid("NULL field"); -- cgit v1.2.3-18-g5258 From 52ec7752b457311f10f5a8d16faa8ac2e684eb65 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 22 Jul 2009 21:51:40 -0700 Subject: Input: pxa27x_keypad - remove extra clk_disable clk_disable() in remove method is not needed since we already have clk_disable in pxa27x_keypad_close(). Also make sure the driver uses resource_size() and helpers from include/input/matrix_keypad.h Tested-by: Mike Rapoport Acked-by: Eric Miao Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/pxa27x_keypad.c | 43 ++++++++++++++++------------------ 1 file changed, 20 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 0d2fc64a5e1..09432381939 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -107,7 +108,7 @@ struct pxa27x_keypad { int irq; /* matrix key code map */ - unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM]; + unsigned short matrix_keycodes[MAX_MATRIX_KEY_NUM]; /* state row bits of each column scan */ uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS]; @@ -124,21 +125,21 @@ static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad) { struct pxa27x_keypad_platform_data *pdata = keypad->pdata; struct input_dev *input_dev = keypad->input_dev; - unsigned int *key; int i; - key = &pdata->matrix_key_map[0]; - for (i = 0; i < pdata->matrix_key_map_size; i++, key++) { - int row = ((*key) >> 28) & 0xf; - int col = ((*key) >> 24) & 0xf; - int code = (*key) & 0xffffff; + for (i = 0; i < pdata->matrix_key_map_size; i++) { + unsigned int key = pdata->matrix_key_map[i]; + unsigned int row = KEY_ROW(key); + unsigned int col = KEY_COL(key); + unsigned short code = KEY_VAL(key); keypad->matrix_keycodes[(row << 3) + col] = code; - set_bit(code, input_dev->keybit); + __set_bit(code, input_dev->keybit); } + __clear_bit(KEY_RESERVED, input_dev->keybit); for (i = 0; i < pdata->direct_key_num; i++) - set_bit(pdata->direct_key_map[i], input_dev->keybit); + __set_bit(pdata->direct_key_map[i], input_dev->keybit); keypad->rotary_up_key[0] = pdata->rotary0_up_key; keypad->rotary_up_key[1] = pdata->rotary1_up_key; @@ -149,18 +150,18 @@ static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad) if (pdata->enable_rotary0) { if (pdata->rotary0_up_key && pdata->rotary0_down_key) { - set_bit(pdata->rotary0_up_key, input_dev->keybit); - set_bit(pdata->rotary0_down_key, input_dev->keybit); + __set_bit(pdata->rotary0_up_key, input_dev->keybit); + __set_bit(pdata->rotary0_down_key, input_dev->keybit); } else - set_bit(pdata->rotary0_rel_code, input_dev->relbit); + __set_bit(pdata->rotary0_rel_code, input_dev->relbit); } if (pdata->enable_rotary1) { if (pdata->rotary1_up_key && pdata->rotary1_down_key) { - set_bit(pdata->rotary1_up_key, input_dev->keybit); - set_bit(pdata->rotary1_down_key, input_dev->keybit); + __set_bit(pdata->rotary1_up_key, input_dev->keybit); + __set_bit(pdata->rotary1_down_key, input_dev->keybit); } else - set_bit(pdata->rotary1_rel_code, input_dev->relbit); + __set_bit(pdata->rotary1_rel_code, input_dev->relbit); } } @@ -425,8 +426,6 @@ static int pxa27x_keypad_resume(struct platform_device *pdev) #define pxa27x_keypad_resume NULL #endif -#define res_size(res) ((res)->end - (res)->start + 1) - static int __devinit pxa27x_keypad_probe(struct platform_device *pdev) { struct pxa27x_keypad *keypad; @@ -461,14 +460,14 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev) goto failed_free; } - res = request_mem_region(res->start, res_size(res), pdev->name); + res = request_mem_region(res->start, resource_size(res), pdev->name); if (res == NULL) { dev_err(&pdev->dev, "failed to request I/O memory\n"); error = -EBUSY; goto failed_free; } - keypad->mmio_base = ioremap(res->start, res_size(res)); + keypad->mmio_base = ioremap(res->start, resource_size(res)); if (keypad->mmio_base == NULL) { dev_err(&pdev->dev, "failed to remap I/O memory\n"); error = -ENXIO; @@ -540,7 +539,7 @@ failed_put_clk: failed_free_io: iounmap(keypad->mmio_base); failed_free_mem: - release_mem_region(res->start, res_size(res)); + release_mem_region(res->start, resource_size(res)); failed_free: kfree(keypad); return error; @@ -552,8 +551,6 @@ static int __devexit pxa27x_keypad_remove(struct platform_device *pdev) struct resource *res; free_irq(keypad->irq, pdev); - - clk_disable(keypad->clk); clk_put(keypad->clk); input_unregister_device(keypad->input_dev); @@ -562,7 +559,7 @@ static int __devexit pxa27x_keypad_remove(struct platform_device *pdev) iounmap(keypad->mmio_base); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res_size(res)); + release_mem_region(res->start, resource_size(res)); platform_set_drvdata(pdev, NULL); kfree(keypad); -- cgit v1.2.3-18-g5258 From 4832958218f96f98009c5e01729fbe2b48c7124c Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 22 Jul 2009 21:51:34 -0700 Subject: Input: add Blackfin rotary input driver This driver handles the Blackfin on-chip rotary peripheral. Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu Signed-off-by: Mike Frysinger Signed-off-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 10 ++ drivers/input/misc/Makefile | 1 + drivers/input/misc/bfin_rotary.c | 283 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 294 insertions(+) create mode 100644 drivers/input/misc/bfin_rotary.c (limited to 'drivers') diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 1acfa3a05aa..cbe21bc96b5 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -269,4 +269,14 @@ config INPUT_DM355EVM To compile this driver as a module, choose M here: the module will be called dm355evm_keys. + +config INPUT_BFIN_ROTARY + tristate "Blackfin Rotary support" + depends on BF54x || BF52x + help + Say Y here if you want to use the Blackfin Rotary. + + To compile this driver as a module, choose M here: the + module will be called bfin-rotary. + endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 0d979fd4cd5..79c1e9a5ea3 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_INPUT_APANEL) += apanel.o obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o +obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o obj-$(CONFIG_INPUT_CM109) += cm109.o obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o diff --git a/drivers/input/misc/bfin_rotary.c b/drivers/input/misc/bfin_rotary.c new file mode 100644 index 00000000000..690f3fafa03 --- /dev/null +++ b/drivers/input/misc/bfin_rotary.c @@ -0,0 +1,283 @@ +/* + * Rotary counter driver for Analog Devices Blackfin Processors + * + * Copyright 2008-2009 Analog Devices Inc. + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static const u16 per_cnt[] = { + P_CNT_CUD, + P_CNT_CDG, + P_CNT_CZM, + 0 +}; + +struct bfin_rot { + struct input_dev *input; + int irq; + unsigned int up_key; + unsigned int down_key; + unsigned int button_key; + unsigned int rel_code; + unsigned short cnt_config; + unsigned short cnt_imask; + unsigned short cnt_debounce; +}; + +static void report_key_event(struct input_dev *input, int keycode) +{ + /* simulate a press-n-release */ + input_report_key(input, keycode, 1); + input_sync(input); + input_report_key(input, keycode, 0); + input_sync(input); +} + +static void report_rotary_event(struct bfin_rot *rotary, int delta) +{ + struct input_dev *input = rotary->input; + + if (rotary->up_key) { + report_key_event(input, + delta > 0 ? rotary->up_key : rotary->down_key); + } else { + input_report_rel(input, rotary->rel_code, delta); + input_sync(input); + } +} + +static irqreturn_t bfin_rotary_isr(int irq, void *dev_id) +{ + struct platform_device *pdev = dev_id; + struct bfin_rot *rotary = platform_get_drvdata(pdev); + int delta; + + switch (bfin_read_CNT_STATUS()) { + + case ICII: + break; + + case UCII: + case DCII: + delta = bfin_read_CNT_COUNTER(); + if (delta) + report_rotary_event(rotary, delta); + break; + + case CZMII: + report_key_event(rotary->input, rotary->button_key); + break; + + default: + break; + } + + bfin_write_CNT_COMMAND(W1LCNT_ZERO); /* Clear COUNTER */ + bfin_write_CNT_STATUS(-1); /* Clear STATUS */ + + return IRQ_HANDLED; +} + +static int __devinit bfin_rotary_probe(struct platform_device *pdev) +{ + struct bfin_rotary_platform_data *pdata = pdev->dev.platform_data; + struct bfin_rot *rotary; + struct input_dev *input; + int error; + + /* Basic validation */ + if ((pdata->rotary_up_key && !pdata->rotary_down_key) || + (!pdata->rotary_up_key && pdata->rotary_down_key)) { + return -EINVAL; + } + + error = peripheral_request_list(per_cnt, dev_name(&pdev->dev)); + if (error) { + dev_err(&pdev->dev, "requesting peripherals failed\n"); + return error; + } + + rotary = kzalloc(sizeof(struct bfin_rot), GFP_KERNEL); + input = input_allocate_device(); + if (!rotary || !input) { + error = -ENOMEM; + goto out1; + } + + rotary->input = input; + + rotary->up_key = pdata->rotary_up_key; + rotary->down_key = pdata->rotary_down_key; + rotary->button_key = pdata->rotary_button_key; + rotary->rel_code = pdata->rotary_rel_code; + + error = rotary->irq = platform_get_irq(pdev, 0); + if (error < 0) + goto out1; + + input->name = pdev->name; + input->phys = "bfin-rotary/input0"; + input->dev.parent = &pdev->dev; + + input_set_drvdata(input, rotary); + + input->id.bustype = BUS_HOST; + input->id.vendor = 0x0001; + input->id.product = 0x0001; + input->id.version = 0x0100; + + if (rotary->up_key) { + __set_bit(EV_KEY, input->evbit); + __set_bit(rotary->up_key, input->keybit); + __set_bit(rotary->down_key, input->keybit); + } else { + __set_bit(EV_REL, input->evbit); + __set_bit(rotary->rel_code, input->relbit); + } + + if (rotary->button_key) { + __set_bit(EV_KEY, input->evbit); + __set_bit(rotary->button_key, input->keybit); + } + + error = request_irq(rotary->irq, bfin_rotary_isr, + 0, dev_name(&pdev->dev), pdev); + if (error) { + dev_err(&pdev->dev, + "unable to claim irq %d; error %d\n", + rotary->irq, error); + goto out1; + } + + error = input_register_device(input); + if (error) { + dev_err(&pdev->dev, + "unable to register input device (%d)\n", error); + goto out2; + } + + if (pdata->rotary_button_key) + bfin_write_CNT_IMASK(CZMIE); + + if (pdata->mode & ROT_DEBE) + bfin_write_CNT_DEBOUNCE(pdata->debounce & DPRESCALE); + + if (pdata->mode) + bfin_write_CNT_CONFIG(bfin_read_CNT_CONFIG() | + (pdata->mode & ~CNTE)); + + bfin_write_CNT_IMASK(bfin_read_CNT_IMASK() | UCIE | DCIE); + bfin_write_CNT_CONFIG(bfin_read_CNT_CONFIG() | CNTE); + + platform_set_drvdata(pdev, rotary); + device_init_wakeup(&pdev->dev, 1); + + return 0; + +out2: + free_irq(rotary->irq, pdev); +out1: + input_free_device(input); + kfree(rotary); + peripheral_free_list(per_cnt); + + return error; +} + +static int __devexit bfin_rotary_remove(struct platform_device *pdev) +{ + struct bfin_rot *rotary = platform_get_drvdata(pdev); + + bfin_write_CNT_CONFIG(0); + bfin_write_CNT_IMASK(0); + + free_irq(rotary->irq, pdev); + input_unregister_device(rotary->input); + peripheral_free_list(per_cnt); + + kfree(rotary); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#ifdef CONFIG_PM +static int bfin_rotary_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct bfin_rot *rotary = platform_get_drvdata(pdev); + + rotary->cnt_config = bfin_read_CNT_CONFIG(); + rotary->cnt_imask = bfin_read_CNT_IMASK(); + rotary->cnt_debounce = bfin_read_CNT_DEBOUNCE(); + + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(rotary->irq); + + return 0; +} + +static int bfin_rotary_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct bfin_rot *rotary = platform_get_drvdata(pdev); + + bfin_write_CNT_DEBOUNCE(rotary->cnt_debounce); + bfin_write_CNT_IMASK(rotary->cnt_imask); + bfin_write_CNT_CONFIG(rotary->cnt_config & ~CNTE); + + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(rotary->irq); + + if (rotary->cnt_config & CNTE) + bfin_write_CNT_CONFIG(rotary->cnt_config); + + return 0; +} + +static struct dev_pm_ops bfin_rotary_pm_ops = { + .suspend = bfin_rotary_suspend, + .resume = bfin_rotary_resume, +}; +#endif + +static struct platform_driver bfin_rotary_device_driver = { + .probe = bfin_rotary_probe, + .remove = __devexit_p(bfin_rotary_remove), + .driver = { + .name = "bfin-rotary", + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &bfin_rotary_pm_ops, +#endif + }, +}; + +static int __init bfin_rotary_init(void) +{ + return platform_driver_register(&bfin_rotary_device_driver); +} +module_init(bfin_rotary_init); + +static void __exit bfin_rotary_exit(void) +{ + platform_driver_unregister(&bfin_rotary_device_driver); +} +module_exit(bfin_rotary_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Michael Hennerich "); +MODULE_DESCRIPTION("Rotary Counter driver for Blackfin Processors"); +MODULE_ALIAS("platform:bfin-rotary"); -- cgit v1.2.3-18-g5258 From 11a79260916b00bcfe1bcfbd7a994321ee25b880 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 23 Jul 2009 01:14:15 -0700 Subject: Input: bf54x-keys - convert printk() to dev_*() Signed-off-by: Mike Frysinger Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/bf54x-keys.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c index d427f322e20..fe376a27fe5 100644 --- a/drivers/input/keyboard/bf54x-keys.c +++ b/drivers/input/keyboard/bf54x-keys.c @@ -184,14 +184,13 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev) int i, error; if (!pdata->rows || !pdata->cols || !pdata->keymap) { - printk(KERN_ERR DRV_NAME - ": No rows, cols or keymap from pdata\n"); + dev_err(&pdev->dev, "no rows, cols or keymap from pdata\n"); return -EINVAL; } if (!pdata->keymapsize || pdata->keymapsize > (pdata->rows * pdata->cols)) { - printk(KERN_ERR DRV_NAME ": Invalid keymapsize\n"); + dev_err(&pdev->dev, "invalid keymapsize\n"); return -EINVAL; } @@ -211,8 +210,8 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev) if (!pdata->debounce_time || pdata->debounce_time > MAX_MULT || !pdata->coldrive_time || pdata->coldrive_time > MAX_MULT) { - printk(KERN_WARNING DRV_NAME - ": Invalid Debounce/Columndrive Time in platform data\n"); + dev_warn(&pdev->dev, + "invalid platform debounce/columndrive time\n"); bfin_write_KPAD_MSEL(0xFF0); /* Default MSEL */ } else { bfin_write_KPAD_MSEL( @@ -231,16 +230,14 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev) if (peripheral_request_list((u16 *)&per_rows[MAX_RC - pdata->rows], DRV_NAME)) { - printk(KERN_ERR DRV_NAME - ": Requesting Peripherals failed\n"); + dev_err(&pdev->dev, "requesting peripherals failed\n"); error = -EFAULT; goto out0; } if (peripheral_request_list((u16 *)&per_cols[MAX_RC - pdata->cols], DRV_NAME)) { - printk(KERN_ERR DRV_NAME - ": Requesting Peripherals failed\n"); + dev_err(&pdev->dev, "requesting peripherals failed\n"); error = -EFAULT; goto out1; } @@ -254,9 +251,8 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev) error = request_irq(bf54x_kpad->irq, bfin_kpad_isr, 0, DRV_NAME, pdev); if (error) { - printk(KERN_ERR DRV_NAME - ": unable to claim irq %d; error %d\n", - bf54x_kpad->irq, error); + dev_err(&pdev->dev, "unable to claim irq %d\n", + bf54x_kpad->irq); goto out2; } @@ -297,8 +293,7 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev) error = input_register_device(input); if (error) { - printk(KERN_ERR DRV_NAME - ": Unable to register input device (%d)\n", error); + dev_err(&pdev->dev, "unable to register input device\n"); goto out4; } @@ -316,9 +311,6 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); - printk(KERN_ERR DRV_NAME - ": Blackfin BF54x Keypad registered IRQ %d\n", bf54x_kpad->irq); - return 0; out4: -- cgit v1.2.3-18-g5258 From 915190f7d4f08e413e5fde6b0abcd5375aeacdf4 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 21 Jul 2009 11:31:29 +0100 Subject: [ARM] 5614/1: at91: atmel_lcdfb: add at91sam9g10 support to atmel LCD driver Modify atmel LCD driver: atmel_lcdfb for at91sam9g10. This add a clock management equivalent to at91sam9261. Signed-off-by: Hong Xu Signed-off-by: Nicolas Ferre Acked-by: Andrew Victor Signed-off-by: Russell King --- drivers/video/Kconfig | 4 ++-- drivers/video/atmel_lcdfb.c | 6 ++++-- drivers/video/backlight/Kconfig | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 36281823fe5..f632c6682aa 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -933,7 +933,7 @@ config FB_S1D13XXX config FB_ATMEL tristate "AT91/AT32 LCD Controller support" - depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 || ARCH_AT91CAP9 || AVR32) + depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9G10 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 || ARCH_AT91CAP9 || AVR32) select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -949,7 +949,7 @@ config FB_INTSRAM config FB_ATMEL_STN bool "Use a STN display with AT91/AT32 LCD Controller" - depends on FB_ATMEL && MACH_AT91SAM9261EK + depends on FB_ATMEL && (MACH_AT91SAM9261EK || MACH_AT91SAM9G10EK) default n help Say Y if you want to connect a STN LCD display to the AT91/AT32 LCD diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 5afd64482f5..adc5bf01254 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -182,7 +182,8 @@ static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2) { unsigned long value; - if (!(cpu_is_at91sam9261() || cpu_is_at32ap7000())) + if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10() + || cpu_is_at32ap7000())) return xres; value = xres; @@ -821,7 +822,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) info->fix = atmel_lcdfb_fix; /* Enable LCDC Clocks */ - if (cpu_is_at91sam9261() || cpu_is_at32ap7000()) { + if (cpu_is_at91sam9261() || cpu_is_at91sam9g10() + || cpu_is_at32ap7000()) { sinfo->bus_clk = clk_get(dev, "hck1"); if (IS_ERR(sinfo->bus_clk)) { ret = PTR_ERR(sinfo->bus_clk); diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index f9d19be0554..90861cd9316 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -110,7 +110,7 @@ config BACKLIGHT_CLASS_DEVICE config BACKLIGHT_ATMEL_LCDC bool "Atmel LCDC Contrast-as-Backlight control" depends on BACKLIGHT_CLASS_DEVICE && FB_ATMEL - default y if MACH_SAM9261EK || MACH_SAM9263EK + default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK help This provides a backlight control internal to the Atmel LCDC driver. If the LCD "contrast control" on your board is wired -- cgit v1.2.3-18-g5258 From 878fa89f97954337d1dc41f0ccc3a8b5f89cfbc7 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Wed, 22 Jul 2009 18:51:24 +0200 Subject: IEEE80154: Add documentation to the IEEE80154 netlink and fakehard driver This adds some perfunctory documentation comments to the IEEE 802.15.4 fakehard.c driver (Fake hard MAC) and the nl802154.h (outgoing netlink messages) header. These comments are not necessarily complete, but they do reference the IEEE 802.15.4-2006 document where possible. Signed-off-by: Daniel Silverstone --- drivers/ieee802154/fakehard.c | 120 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) (limited to 'drivers') diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index 0384144c0b3..9ec07e8552f 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c @@ -31,6 +31,12 @@ #include #include +/** + * fake_get_pan_id - Retrieve the PAN ID of the device. + * @dev: The network device to retrieve the PAN of. + * + * Return the ID of the PAN from the PIB. + */ static u16 fake_get_pan_id(struct net_device *dev) { BUG_ON(dev->type != ARPHRD_IEEE802154); @@ -38,6 +44,14 @@ static u16 fake_get_pan_id(struct net_device *dev) return 0xeba1; } +/** + * fake_get_short_addr - Retrieve the short address of the device. + * @dev: The network device to retrieve the short address of. + * + * Returns the IEEE 802.15.4 short-form address cached for this + * device. If the device has not yet had a short address assigned + * then this should return 0xFFFF to indicate a lack of association. + */ static u16 fake_get_short_addr(struct net_device *dev) { BUG_ON(dev->type != ARPHRD_IEEE802154); @@ -45,6 +59,19 @@ static u16 fake_get_short_addr(struct net_device *dev) return 0x1; } +/** + * fake_get_dsn - Retrieve the DSN of the device. + * @dev: The network device to retrieve the DSN for. + * + * Returns the IEEE 802.15.4 DSN for the network device. + * The DSN is the sequence number which will be added to each + * packet or MAC command frame by the MAC during transmission. + * + * DSN means 'Data Sequence Number'. + * + * Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006 + * document. + */ static u8 fake_get_dsn(struct net_device *dev) { BUG_ON(dev->type != ARPHRD_IEEE802154); @@ -52,6 +79,19 @@ static u8 fake_get_dsn(struct net_device *dev) return 0x00; /* DSN are implemented in HW, so return just 0 */ } +/** + * fake_get_bsn - Retrieve the BSN of the device. + * @dev: The network device to retrieve the BSN for. + * + * Returns the IEEE 802.15.4 BSN for the network device. + * The BSN is the sequence number which will be added to each + * beacon frame sent by the MAC. + * + * BSN means 'Beacon Sequence Number'. + * + * Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006 + * document. + */ static u8 fake_get_bsn(struct net_device *dev) { BUG_ON(dev->type != ARPHRD_IEEE802154); @@ -59,6 +99,19 @@ static u8 fake_get_bsn(struct net_device *dev) return 0x00; /* BSN are implemented in HW, so return just 0 */ } +/** + * fake_assoc_req - Make an association request to the HW. + * @dev: The network device which we are associating to a network. + * @addr: The coordinator with which we wish to associate. + * @channel: The channel on which to associate. + * @cap: The capability information field to use in the association. + * + * Start an association with a coordinator. The coordinator's address + * and PAN ID can be found in @addr. + * + * Note: This is in section 7.3.1 and 7.5.3.1 of the IEEE + * 802.15.4-2006 document. + */ static int fake_assoc_req(struct net_device *dev, struct ieee802154_addr *addr, u8 channel, u8 cap) { @@ -67,18 +120,70 @@ static int fake_assoc_req(struct net_device *dev, IEEE802154_SUCCESS); } +/** + * fake_assoc_resp - Send an association response to a device. + * @dev: The network device on which to send the response. + * @addr: The address of the device to respond to. + * @short_addr: The assigned short address for the device (if any). + * @status: The result of the association request. + * + * Queue the association response of the coordinator to another + * device's attempt to associate with the network which we + * coordinate. This is then added to the indirect-send queue to be + * transmitted to the end device when it polls for data. + * + * Note: This is in section 7.3.2 and 7.5.3.1 of the IEEE + * 802.15.4-2006 document. + */ static int fake_assoc_resp(struct net_device *dev, struct ieee802154_addr *addr, u16 short_addr, u8 status) { return 0; } +/** + * fake_disassoc_req - Disassociate a device from a network. + * @dev: The network device on which we're disassociating a device. + * @addr: The device to disassociate from the network. + * @reason: The reason to give to the device for being disassociated. + * + * This sends a disassociation notification to the device being + * disassociated from the network. + * + * Note: This is in section 7.5.3.2 of the IEEE 802.15.4-2006 + * document, with the reason described in 7.3.3.2. + */ static int fake_disassoc_req(struct net_device *dev, struct ieee802154_addr *addr, u8 reason) { return ieee802154_nl_disassoc_confirm(dev, IEEE802154_SUCCESS); } +/** + * fake_start_req - Start an IEEE 802.15.4 PAN. + * @dev: The network device on which to start the PAN. + * @addr: The coordinator address to use when starting the PAN. + * @channel: The channel on which to start the PAN. + * @bcn_ord: Beacon order. + * @sf_ord: Superframe order. + * @pan_coord: Whether or not we are the PAN coordinator or just + * requesting a realignment perhaps? + * @blx: Battery Life Extension feature bitfield. + * @coord_realign: Something to realign something else. + * + * If pan_coord is non-zero then this starts a network with the + * provided parameters, otherwise it attempts a coordinator + * realignment of the stated network instead. + * + * Note: This is in section 7.5.2.3 of the IEEE 802.15.4-2006 + * document, with 7.3.8 describing coordinator realignment. + * + * Note: There is currently no way to notify the coordinator userland + * program of whether or not the PAN has started successfully. As + * such, the coordinator program cannot know when the MAC has + * completed starting the network and will simply have to assume + * completeness based on some form of time delay. + */ static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, u8 channel, u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, @@ -87,6 +192,21 @@ static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, return 0; } +/** + * fake_scan_req - Start a channel scan. + * @dev: The network device on which to perform a channel scan. + * @type: The type of scan to perform. + * @channels: The channel bitmask to scan. + * @duration: How long to spend on each channel. + * + * This starts either a passive (energy) scan or an active (PAN) scan + * on the channels indicated in the @channels bitmask. The duration of + * the scan is measured in terms of superframe duration. Specifically, + * the scan will spend aBaseSuperFrameDuration * ((2^n) + 1) on each + * channel. + * + * Note: This is in section 7.5.2.1 of the IEEE 802.15.4-2006 document. + */ static int fake_scan_req(struct net_device *dev, u8 type, u32 channels, u8 duration) { -- cgit v1.2.3-18-g5258 From f0166e5e3cdab66d5a31f796ce18e21fd3ce99dc Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 23 Jul 2009 16:56:29 +0400 Subject: ieee802154: move headers out of extra directory include/net/ieee802154/af_ieee802154.h (and others) naming seems to be too long and redundant. Drop one level of subdirectories. Signed-off-by: Dmitry Eremin-Solenikov --- drivers/ieee802154/fakehard.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index 9ec07e8552f..8a52e6efa23 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c @@ -26,10 +26,10 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include /** * fake_get_pan_id - Retrieve the PAN ID of the device. -- cgit v1.2.3-18-g5258 From d9ab77161d811ffb0bccf396f7155cc905c1b9e1 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 22 Jul 2009 00:37:25 +0200 Subject: Driver Core: Make PM operations a const pointer They are not supposed to be modified by drivers, so make them const. Signed-off-by: Dmitry Torokhov Acked-by: Greg Kroah-Hartman Signed-off-by: Rafael J. Wysocki --- drivers/base/platform.c | 2 +- drivers/base/power/main.c | 8 +++++--- drivers/pci/pci-driver.c | 16 ++++++++-------- 3 files changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 455e55971d0..ae5c4aa6d26 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -889,7 +889,7 @@ static int platform_pm_restore_noirq(struct device *dev) #endif /* !CONFIG_HIBERNATION */ -static struct dev_pm_ops platform_dev_pm_ops = { +static const struct dev_pm_ops platform_dev_pm_ops = { .prepare = platform_pm_prepare, .complete = platform_pm_complete, .suspend = platform_pm_suspend, diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 58a3e572f2c..1b1a786b7de 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -157,8 +157,9 @@ void device_pm_move_last(struct device *dev) * @ops: PM operations to choose from. * @state: PM transition of the system being carried out. */ -static int pm_op(struct device *dev, struct dev_pm_ops *ops, - pm_message_t state) +static int pm_op(struct device *dev, + const struct dev_pm_ops *ops, + pm_message_t state) { int error = 0; @@ -220,7 +221,8 @@ static int pm_op(struct device *dev, struct dev_pm_ops *ops, * The operation is executed with interrupts disabled by the only remaining * functional CPU in the system. */ -static int pm_noirq_op(struct device *dev, struct dev_pm_ops *ops, +static int pm_noirq_op(struct device *dev, + const struct dev_pm_ops *ops, pm_message_t state) { int error = 0; diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index d76c4c85367..0c2ea44ae5e 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -575,7 +575,7 @@ static void pci_pm_complete(struct device *dev) static int pci_pm_suspend(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; if (pci_has_legacy_pm_support(pci_dev)) return pci_legacy_suspend(dev, PMSG_SUSPEND); @@ -613,7 +613,7 @@ static int pci_pm_suspend(struct device *dev) static int pci_pm_suspend_noirq(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; if (pci_has_legacy_pm_support(pci_dev)) return pci_legacy_suspend_late(dev, PMSG_SUSPEND); @@ -672,7 +672,7 @@ static int pci_pm_resume_noirq(struct device *dev) static int pci_pm_resume(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; int error = 0; /* @@ -711,7 +711,7 @@ static int pci_pm_resume(struct device *dev) static int pci_pm_freeze(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; if (pci_has_legacy_pm_support(pci_dev)) return pci_legacy_suspend(dev, PMSG_FREEZE); @@ -780,7 +780,7 @@ static int pci_pm_thaw_noirq(struct device *dev) static int pci_pm_thaw(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; int error = 0; if (pci_has_legacy_pm_support(pci_dev)) @@ -799,7 +799,7 @@ static int pci_pm_thaw(struct device *dev) static int pci_pm_poweroff(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; if (pci_has_legacy_pm_support(pci_dev)) return pci_legacy_suspend(dev, PMSG_HIBERNATE); @@ -872,7 +872,7 @@ static int pci_pm_restore_noirq(struct device *dev) static int pci_pm_restore(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; int error = 0; /* @@ -910,7 +910,7 @@ static int pci_pm_restore(struct device *dev) #endif /* !CONFIG_HIBERNATION */ -struct dev_pm_ops pci_dev_pm_ops = { +const struct dev_pm_ops pci_dev_pm_ops = { .prepare = pci_pm_prepare, .complete = pci_pm_complete, .suspend = pci_pm_suspend, -- cgit v1.2.3-18-g5258 From 5be93b9a865344cf69958777c8d7c6f758cba416 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Tue, 21 Jul 2009 12:36:19 -0700 Subject: be2net: Add GRO support to the be2net driver. LRO is not supported anymore. This patch removes support for INET_LRO and switches over to GRO. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/benet/Kconfig | 1 - drivers/net/benet/be.h | 11 +---- drivers/net/benet/be_ethtool.c | 9 +--- drivers/net/benet/be_main.c | 104 ++++++++++++----------------------------- 4 files changed, 31 insertions(+), 94 deletions(-) (limited to 'drivers') diff --git a/drivers/net/benet/Kconfig b/drivers/net/benet/Kconfig index c6934f179c0..fdb6e81a437 100644 --- a/drivers/net/benet/Kconfig +++ b/drivers/net/benet/Kconfig @@ -1,7 +1,6 @@ config BE2NET tristate "ServerEngines' 10Gbps NIC - BladeEngine 2" depends on PCI && INET - select INET_LRO help This driver implements the NIC functionality for ServerEngines' 10Gbps network adapter - BladeEngine 2. diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 5b4bf3d2cdc..41cddbedbf2 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -28,11 +28,10 @@ #include #include #include -#include #include "be_hw.h" -#define DRV_VER "2.0.348" +#define DRV_VER "2.0.400" #define DRV_NAME "be2net" #define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC" #define OC_NAME "Emulex OneConnect 10Gbps NIC" @@ -72,9 +71,6 @@ static inline char *nic_name(struct pci_dev *pdev) #define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */ #define RX_FRAGS_REFILL_WM (RX_Q_LEN - MAX_RX_POST) -#define BE_MAX_LRO_DESCRIPTORS 16 -#define BE_MAX_FRAGS_PER_FRAME (min((u32) 16, (u32) MAX_SKB_FRAGS)) - struct be_dma_mem { void *va; dma_addr_t dma; @@ -189,8 +185,6 @@ struct be_drvr_stats { u32 be_polls; /* number of times NAPI called poll function */ u32 be_rx_events; /* number of ucast rx completion events */ u32 be_rx_compl; /* number of rx completion entries processed */ - u32 be_lro_hgram_data[8]; /* histogram of LRO data packets */ - u32 be_lro_hgram_ack[8]; /* histogram of LRO ACKs */ ulong be_rx_jiffies; u64 be_rx_bytes; u64 be_rx_bytes_prev; @@ -233,8 +227,6 @@ struct be_rx_obj { struct be_queue_info q; struct be_queue_info cq; struct be_rx_page_info page_info_tbl[RX_Q_LEN]; - struct net_lro_mgr lro_mgr; - struct net_lro_desc lro_desc[BE_MAX_LRO_DESCRIPTORS]; }; #define BE_NUM_MSIX_VECTORS 2 /* 1 each for Tx and Rx */ @@ -271,7 +263,6 @@ struct be_adapter { /* Ethtool knobs and info */ bool rx_csum; /* BE card must perform rx-checksumming */ - u32 max_rx_coal; char fw_ver[FW_VER_LEN]; u32 if_handle; /* Used to configure filtering */ u32 pmac_id; /* MAC addr handle used by BE card */ diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index cccc5419ad7..f3f0f91e38c 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -127,8 +127,6 @@ be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) struct be_eq_obj *rx_eq = &adapter->rx_eq; struct be_eq_obj *tx_eq = &adapter->tx_eq; - coalesce->rx_max_coalesced_frames = adapter->max_rx_coal; - coalesce->rx_coalesce_usecs = rx_eq->cur_eqd; coalesce->rx_coalesce_usecs_high = rx_eq->max_eqd; coalesce->rx_coalesce_usecs_low = rx_eq->min_eqd; @@ -144,8 +142,7 @@ be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) } /* - * This routine is used to set interrup coalescing delay *as well as* - * the number of pkts to coalesce for LRO. + * This routine is used to set interrup coalescing delay */ static int be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) @@ -161,10 +158,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) if (coalesce->use_adaptive_tx_coalesce == 1) return -EINVAL; - adapter->max_rx_coal = coalesce->rx_max_coalesced_frames; - if (adapter->max_rx_coal > BE_MAX_FRAGS_PER_FRAME) - adapter->max_rx_coal = BE_MAX_FRAGS_PER_FRAME; - /* if AIC is being turned on now, start with an EQD of 0 */ if (rx_eq->enable_aic == 0 && coalesce->use_adaptive_rx_coalesce == 1) { diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index c43f6a11929..45df8e2d092 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -742,7 +742,7 @@ done: return; } -/* Process the RX completion indicated by rxcp when LRO is disabled */ +/* Process the RX completion indicated by rxcp when GRO is disabled */ static void be_rx_compl_process(struct be_adapter *adapter, struct be_eth_rx_compl *rxcp) { @@ -789,13 +789,14 @@ static void be_rx_compl_process(struct be_adapter *adapter, return; } -/* Process the RX completion indicated by rxcp when LRO is enabled */ -static void be_rx_compl_process_lro(struct be_adapter *adapter, +/* Process the RX completion indicated by rxcp when GRO is enabled */ +static void be_rx_compl_process_gro(struct be_adapter *adapter, struct be_eth_rx_compl *rxcp) { struct be_rx_page_info *page_info; - struct skb_frag_struct rx_frags[BE_MAX_FRAGS_PER_FRAME]; + struct sk_buff *skb = NULL; struct be_queue_info *rxq = &adapter->rx_obj.q; + struct be_eq_obj *eq_obj = &adapter->rx_eq; u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len; u16 i, rxq_idx = 0, vid, j; @@ -804,6 +805,12 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter, vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp); rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp); + skb = napi_get_frags(&eq_obj->napi); + if (!skb) { + be_rx_compl_discard(adapter, rxcp); + return; + } + remaining = pkt_size; for (i = 0, j = -1; i < num_rcvd; i++) { page_info = get_rx_page_info(adapter, rxq_idx); @@ -814,13 +821,14 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter, if (i == 0 || page_info->page_offset == 0) { /* First frag or Fresh page */ j++; - rx_frags[j].page = page_info->page; - rx_frags[j].page_offset = page_info->page_offset; - rx_frags[j].size = 0; + skb_shinfo(skb)->frags[j].page = page_info->page; + skb_shinfo(skb)->frags[j].page_offset = + page_info->page_offset; + skb_shinfo(skb)->frags[j].size = 0; } else { put_page(page_info->page); } - rx_frags[j].size += curr_frag_len; + skb_shinfo(skb)->frags[j].size += curr_frag_len; remaining -= curr_frag_len; index_inc(&rxq_idx, rxq->len); @@ -828,9 +836,14 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter, } BUG_ON(j > MAX_SKB_FRAGS); + skb_shinfo(skb)->nr_frags = j + 1; + skb->len = pkt_size; + skb->data_len = pkt_size; + skb->truesize += pkt_size; + skb->ip_summed = CHECKSUM_UNNECESSARY; + if (likely(!vlanf)) { - lro_receive_frags(&adapter->rx_obj.lro_mgr, rx_frags, pkt_size, - pkt_size, NULL, 0); + napi_gro_frags(&eq_obj->napi); } else { vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp); vid = be16_to_cpu(vid); @@ -838,9 +851,7 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter, if (!adapter->vlan_grp || adapter->num_vlans == 0) return; - lro_vlan_hwaccel_receive_frags(&adapter->rx_obj.lro_mgr, - rx_frags, pkt_size, pkt_size, adapter->vlan_grp, - vid, NULL, 0); + vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, vid); } be_rx_stats_update(adapter, pkt_size, num_rcvd); @@ -1183,7 +1194,6 @@ static int be_rx_queues_create(struct be_adapter *adapter) struct be_queue_info *eq, *q, *cq; int rc; - adapter->max_rx_coal = BE_MAX_FRAGS_PER_FRAME; adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE; adapter->rx_eq.max_eqd = BE_MAX_EQD; adapter->rx_eq.min_eqd = 0; @@ -1305,7 +1315,7 @@ static irqreturn_t be_msix_tx_mcc(int irq, void *dev) return IRQ_HANDLED; } -static inline bool do_lro(struct be_adapter *adapter, +static inline bool do_gro(struct be_adapter *adapter, struct be_eth_rx_compl *rxcp) { int err = AMAP_GET_BITS(struct amap_eth_rx_compl, err, rxcp); @@ -1314,8 +1324,7 @@ static inline bool do_lro(struct be_adapter *adapter, if (err) drvr_stats(adapter)->be_rxcp_err++; - return (!tcp_frame || err || (adapter->max_rx_coal <= 1)) ? - false : true; + return (tcp_frame && !err) ? true : false; } int be_poll_rx(struct napi_struct *napi, int budget) @@ -1332,16 +1341,14 @@ int be_poll_rx(struct napi_struct *napi, int budget) if (!rxcp) break; - if (do_lro(adapter, rxcp)) - be_rx_compl_process_lro(adapter, rxcp); + if (do_gro(adapter, rxcp)) + be_rx_compl_process_gro(adapter, rxcp); else be_rx_compl_process(adapter, rxcp); be_rx_compl_reset(rxcp); } - lro_flush_all(&adapter->rx_obj.lro_mgr); - /* Refill the queue */ if (atomic_read(&adapter->rx_obj.q.used) < RX_FRAGS_REFILL_WM) be_post_rx_frags(adapter); @@ -1656,57 +1663,6 @@ static int be_close(struct net_device *netdev) return 0; } -static int be_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr, - void **ip_hdr, void **tcpudp_hdr, - u64 *hdr_flags, void *priv) -{ - struct ethhdr *eh; - struct vlan_ethhdr *veh; - struct iphdr *iph; - u8 *va = page_address(frag->page) + frag->page_offset; - unsigned long ll_hlen; - - prefetch(va); - eh = (struct ethhdr *)va; - *mac_hdr = eh; - ll_hlen = ETH_HLEN; - if (eh->h_proto != htons(ETH_P_IP)) { - if (eh->h_proto == htons(ETH_P_8021Q)) { - veh = (struct vlan_ethhdr *)va; - if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP)) - return -1; - - ll_hlen += VLAN_HLEN; - } else { - return -1; - } - } - *hdr_flags = LRO_IPV4; - iph = (struct iphdr *)(va + ll_hlen); - *ip_hdr = iph; - if (iph->protocol != IPPROTO_TCP) - return -1; - *hdr_flags |= LRO_TCP; - *tcpudp_hdr = (u8 *) (*ip_hdr) + (iph->ihl << 2); - - return 0; -} - -static void be_lro_init(struct be_adapter *adapter, struct net_device *netdev) -{ - struct net_lro_mgr *lro_mgr; - - lro_mgr = &adapter->rx_obj.lro_mgr; - lro_mgr->dev = netdev; - lro_mgr->features = LRO_F_NAPI; - lro_mgr->ip_summed = CHECKSUM_UNNECESSARY; - lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY; - lro_mgr->max_desc = BE_MAX_LRO_DESCRIPTORS; - lro_mgr->lro_arr = adapter->rx_obj.lro_desc; - lro_mgr->get_frag_header = be_get_frag_header; - lro_mgr->max_aggr = BE_MAX_FRAGS_PER_FRAME; -} - static struct net_device_ops be_netdev_ops = { .ndo_open = be_open, .ndo_stop = be_close, @@ -1727,7 +1683,7 @@ static void be_netdev_init(struct net_device *netdev) netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_IP_CSUM | - NETIF_F_IPV6_CSUM; + NETIF_F_IPV6_CSUM | NETIF_F_GRO; netdev->flags |= IFF_MULTICAST; @@ -1737,8 +1693,6 @@ static void be_netdev_init(struct net_device *netdev) SET_ETHTOOL_OPS(netdev, &be_ethtool_ops); - be_lro_init(adapter, netdev); - netif_napi_add(netdev, &adapter->rx_eq.napi, be_poll_rx, BE_NAPI_WEIGHT); netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc, -- cgit v1.2.3-18-g5258 From 69222e2cb01ac3faaa8ca758c5ee036c191b8b9f Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 21 Jul 2009 12:37:18 -0700 Subject: dm9000: switch to dev_pm_ops Signed-off-by: Mike Rapoport Acked-by: Ben Dooks Signed-off-by: David S. Miller --- drivers/net/dm9000.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 8603806be89..a2bc4158259 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -1483,9 +1483,10 @@ out: } static int -dm9000_drv_suspend(struct platform_device *dev, pm_message_t state) +dm9000_drv_suspend(struct device *dev) { - struct net_device *ndev = platform_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct net_device *ndev = platform_get_drvdata(pdev); board_info_t *db; if (ndev) { @@ -1501,9 +1502,10 @@ dm9000_drv_suspend(struct platform_device *dev, pm_message_t state) } static int -dm9000_drv_resume(struct platform_device *dev) +dm9000_drv_resume(struct device *dev) { - struct net_device *ndev = platform_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct net_device *ndev = platform_get_drvdata(pdev); board_info_t *db = netdev_priv(ndev); if (ndev) { @@ -1520,6 +1522,11 @@ dm9000_drv_resume(struct platform_device *dev) return 0; } +static struct dev_pm_ops dm9000_drv_pm_ops = { + .suspend = dm9000_drv_suspend, + .resume = dm9000_drv_resume, +}; + static int __devexit dm9000_drv_remove(struct platform_device *pdev) { @@ -1539,11 +1546,10 @@ static struct platform_driver dm9000_driver = { .driver = { .name = "dm9000", .owner = THIS_MODULE, + .pm = &dm9000_drv_pm_ops, }, .probe = dm9000_probe, .remove = __devexit_p(dm9000_drv_remove), - .suspend = dm9000_drv_suspend, - .resume = dm9000_drv_resume, }; static int __init -- cgit v1.2.3-18-g5258 From dd52856ba24ed2f67679c86f207e5a9bab1eb93b Mon Sep 17 00:00:00 2001 From: Sebastian Haas Date: Tue, 21 Jul 2009 12:38:13 -0700 Subject: can: sja1000: Add support for the new 4 channel EMS CPC-PCI cards This patch adds support to the ems_pci driver for the new, v2, 4 channel CPC-PCI/PCIe/104P CAN cards from EMS Dr. Thomas Wuensche. Signed-off-by: Sebastian Haas Signed-off-by: Wolfgang Grandegger Signed-off-by: David S. Miller --- drivers/net/can/Kconfig | 7 +- drivers/net/can/sja1000/ems_pci.c | 152 +++++++++++++++++++++++++++----------- 2 files changed, 112 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 33821a81cbf..30ae55d7167 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -61,11 +61,12 @@ config CAN_SJA1000_OF_PLATFORM you may want to enable this option. config CAN_EMS_PCI - tristate "EMS CPC-PCI and CPC-PCIe Card" + tristate "EMS CPC-PCI, CPC-PCIe and CPC-104P Card" depends on PCI && CAN_SJA1000 ---help--- - This driver is for the one or two channel CPC-PCI and CPC-PCIe - cards from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de). + This driver is for the one, two or four channel CPC-PCI, + CPC-PCIe and CPC-104P cards from EMS Dr. Thomas Wuensche + (http://www.ems-wuensche.de). config CAN_KVASER_PCI tristate "Kvaser PCIcanx and Kvaser PCIcan PCI Cards" diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c index 121b64101d7..7d84b8ac9c1 100644 --- a/drivers/net/can/sja1000/ems_pci.c +++ b/drivers/net/can/sja1000/ems_pci.c @@ -32,13 +32,16 @@ #define DRV_NAME "ems_pci" MODULE_AUTHOR("Sebastian Haas "); -MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe CAN cards"); -MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe CAN card"); +MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe/104P CAN cards"); +MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe/104P CAN card"); MODULE_LICENSE("GPL v2"); -#define EMS_PCI_MAX_CHAN 2 +#define EMS_PCI_V1_MAX_CHAN 2 +#define EMS_PCI_V2_MAX_CHAN 4 +#define EMS_PCI_MAX_CHAN EMS_PCI_V2_MAX_CHAN struct ems_pci_card { + int version; int channels; struct pci_dev *pci_dev; @@ -62,13 +65,23 @@ struct ems_pci_card { #define PITA2_MISC 0x1c /* Miscellaneous Register */ #define PITA2_MISC_CONFIG 0x04000000 /* Multiplexed parallel interface */ +/* + * Register definitions for the PLX 9030 + */ +#define PLX_ICSR 0x4c /* Interrupt Control/Status register */ +#define PLX_ICSR_LINTI1_ENA 0x0001 /* LINTi1 Enable */ +#define PLX_ICSR_PCIINT_ENA 0x0040 /* PCI Interrupt Enable */ +#define PLX_ICSR_LINTI1_CLR 0x0400 /* Local Edge Triggerable Interrupt Clear */ +#define PLX_ICSR_ENA_CLR (PLX_ICSR_LINTI1_ENA | PLX_ICSR_PCIINT_ENA | \ + PLX_ICSR_LINTI1_CLR) + /* * The board configuration is probably following: * RX1 is connected to ground. * TX1 is not connected. * CLKO is not connected. * Setting the OCR register to 0xDA is a good idea. - * This means normal output mode , push-pull and the correct polarity. + * This means normal output mode, push-pull and the correct polarity. */ #define EMS_PCI_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL) @@ -79,17 +92,21 @@ struct ems_pci_card { * is driven by the first one CLKOUT output. */ #define EMS_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK) -#define EMS_PCI_MEM_SIZE 4096 /* Size of the remapped io-memory */ + +#define EMS_PCI_V1_BASE_BAR 1 +#define EMS_PCI_V1_MEM_SIZE 4096 +#define EMS_PCI_V2_BASE_BAR 2 +#define EMS_PCI_V2_MEM_SIZE 128 #define EMS_PCI_CAN_BASE_OFFSET 0x400 /* offset where the controllers starts */ #define EMS_PCI_CAN_CTRL_SIZE 0x200 /* memory size for each controller */ -#define EMS_PCI_PORT_BYTES 0x4 /* Each register occupies 4 bytes */ - -#define EMS_PCI_VENDOR_ID 0x110a /* PCI device and vendor ID */ -#define EMS_PCI_DEVICE_ID 0x2104 - static struct pci_device_id ems_pci_tbl[] = { - {EMS_PCI_VENDOR_ID, EMS_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, + /* CPC-PCI v1 */ + {PCI_VENDOR_ID_SIEMENS, 0x2104, PCI_ANY_ID, PCI_ANY_ID,}, + /* CPC-PCI v2 */ + {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_PLX, 0x4000}, + /* CPC-104P v2 */ + {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_PLX, 0x4002}, {0,} }; MODULE_DEVICE_TABLE(pci, ems_pci_tbl); @@ -97,28 +114,47 @@ MODULE_DEVICE_TABLE(pci, ems_pci_tbl); /* * Helper to read internal registers from card logic (not CAN) */ -static u8 ems_pci_readb(struct ems_pci_card *card, unsigned int port) +static u8 ems_pci_v1_readb(struct ems_pci_card *card, unsigned int port) { - return readb(card->base_addr + (port * EMS_PCI_PORT_BYTES)); + return readb(card->base_addr + (port * 4)); } -static u8 ems_pci_read_reg(const struct sja1000_priv *priv, int port) +static u8 ems_pci_v1_read_reg(const struct sja1000_priv *priv, int port) { - return readb(priv->reg_base + (port * EMS_PCI_PORT_BYTES)); + return readb(priv->reg_base + (port * 4)); } -static void ems_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val) +static void ems_pci_v1_write_reg(const struct sja1000_priv *priv, + int port, u8 val) { - writeb(val, priv->reg_base + (port * EMS_PCI_PORT_BYTES)); + writeb(val, priv->reg_base + (port * 4)); } -static void ems_pci_post_irq(const struct sja1000_priv *priv) +static void ems_pci_v1_post_irq(const struct sja1000_priv *priv) { struct ems_pci_card *card = (struct ems_pci_card *)priv->priv; /* reset int flag of pita */ - writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0, card->conf_addr - + PITA2_ICR); + writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0, + card->conf_addr + PITA2_ICR); +} + +static u8 ems_pci_v2_read_reg(const struct sja1000_priv *priv, int port) +{ + return readb(priv->reg_base + port); +} + +static void ems_pci_v2_write_reg(const struct sja1000_priv *priv, + int port, u8 val) +{ + writeb(val, priv->reg_base + port); +} + +static void ems_pci_v2_post_irq(const struct sja1000_priv *priv) +{ + struct ems_pci_card *card = (struct ems_pci_card *)priv->priv; + + writel(PLX_ICSR_ENA_CLR, card->conf_addr + PLX_ICSR); } /* @@ -130,12 +166,12 @@ static inline int ems_pci_check_chan(const struct sja1000_priv *priv) unsigned char res; /* Make sure SJA1000 is in reset mode */ - ems_pci_write_reg(priv, REG_MOD, 1); + priv->write_reg(priv, REG_MOD, 1); - ems_pci_write_reg(priv, REG_CDR, CDR_PELICAN); + priv->write_reg(priv, REG_CDR, CDR_PELICAN); /* read reset-values */ - res = ems_pci_read_reg(priv, REG_CDR); + res = priv->read_reg(priv, REG_CDR); if (res == CDR_PELICAN) return 1; @@ -188,6 +224,7 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev, struct sja1000_priv *priv; struct net_device *dev; struct ems_pci_card *card; + int max_chan, mem_size, base_bar; int err, i; /* Enabling PCI device */ @@ -210,37 +247,52 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev, card->channels = 0; - /* Remap PITA configuration space, and controller memory area */ - card->conf_addr = pci_iomap(pdev, 0, EMS_PCI_MEM_SIZE); + if (pdev->vendor == PCI_VENDOR_ID_PLX) { + card->version = 2; /* CPC-PCI v2 */ + max_chan = EMS_PCI_V2_MAX_CHAN; + base_bar = EMS_PCI_V2_BASE_BAR; + mem_size = EMS_PCI_V2_MEM_SIZE; + } else { + card->version = 1; /* CPC-PCI v1 */ + max_chan = EMS_PCI_V1_MAX_CHAN; + base_bar = EMS_PCI_V1_BASE_BAR; + mem_size = EMS_PCI_V1_MEM_SIZE; + } + + /* Remap configuration space and controller memory area */ + card->conf_addr = pci_iomap(pdev, 0, mem_size); if (card->conf_addr == NULL) { err = -ENOMEM; goto failure_cleanup; } - card->base_addr = pci_iomap(pdev, 1, EMS_PCI_MEM_SIZE); + card->base_addr = pci_iomap(pdev, base_bar, mem_size); if (card->base_addr == NULL) { err = -ENOMEM; goto failure_cleanup; } - /* Configure PITA-2 parallel interface (enable MUX) */ - writel(PITA2_MISC_CONFIG, card->conf_addr + PITA2_MISC); - - /* Check for unique EMS CAN signature */ - if (ems_pci_readb(card, 0) != 0x55 || - ems_pci_readb(card, 1) != 0xAA || - ems_pci_readb(card, 2) != 0x01 || - ems_pci_readb(card, 3) != 0xCB || - ems_pci_readb(card, 4) != 0x11) { - dev_err(&pdev->dev, "Not EMS Dr. Thomas Wuensche interface\n"); - err = -ENODEV; - goto failure_cleanup; + if (card->version == 1) { + /* Configure PITA-2 parallel interface (enable MUX) */ + writel(PITA2_MISC_CONFIG, card->conf_addr + PITA2_MISC); + + /* Check for unique EMS CAN signature */ + if (ems_pci_v1_readb(card, 0) != 0x55 || + ems_pci_v1_readb(card, 1) != 0xAA || + ems_pci_v1_readb(card, 2) != 0x01 || + ems_pci_v1_readb(card, 3) != 0xCB || + ems_pci_v1_readb(card, 4) != 0x11) { + dev_err(&pdev->dev, + "Not EMS Dr. Thomas Wuensche interface\n"); + err = -ENODEV; + goto failure_cleanup; + } } ems_pci_card_reset(card); /* Detect available channels */ - for (i = 0; i < EMS_PCI_MAX_CHAN; i++) { + for (i = 0; i < max_chan; i++) { dev = alloc_sja1000dev(0); if (dev == NULL) { err = -ENOMEM; @@ -255,20 +307,32 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev, dev->irq = pdev->irq; priv->reg_base = card->base_addr + EMS_PCI_CAN_BASE_OFFSET + (i * EMS_PCI_CAN_CTRL_SIZE); + if (card->version == 1) { + priv->read_reg = ems_pci_v1_read_reg; + priv->write_reg = ems_pci_v1_write_reg; + priv->post_irq = ems_pci_v1_post_irq; + } else { + priv->read_reg = ems_pci_v2_read_reg; + priv->write_reg = ems_pci_v2_write_reg; + priv->post_irq = ems_pci_v2_post_irq; + } /* Check if channel is present */ if (ems_pci_check_chan(priv)) { - priv->read_reg = ems_pci_read_reg; - priv->write_reg = ems_pci_write_reg; - priv->post_irq = ems_pci_post_irq; priv->can.clock.freq = EMS_PCI_CAN_CLOCK; priv->ocr = EMS_PCI_OCR; priv->cdr = EMS_PCI_CDR; SET_NETDEV_DEV(dev, &pdev->dev); - /* Enable interrupts from card */ - writel(PITA2_ICR_INT0_EN, card->conf_addr + PITA2_ICR); + if (card->version == 1) + /* reset int flag of pita */ + writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0, + card->conf_addr + PITA2_ICR); + else + /* enable IRQ in PLX 9030 */ + writel(PLX_ICSR_ENA_CLR, + card->conf_addr + PLX_ICSR); /* Register SJA1000 device */ err = register_sja1000dev(dev); -- cgit v1.2.3-18-g5258 From 27a242e92f77c955433ce0347533f401ecdcd0f3 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 21 Jul 2009 12:50:02 -0700 Subject: veth: Zero timestamp in xmit path. This patch zero's the timestamp before handing the packet to the peer interface. This lets the peer recalculate the rx timestamp if it cares about timestamps. Signed-off-by: Ben Greear Signed-off-by: David S. Miller --- drivers/net/veth.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/veth.c b/drivers/net/veth.c index f1d753daa5b..190f784c9cf 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -171,6 +171,7 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->len > (rcv->mtu + MTU_PAD)) goto rx_drop; + skb->tstamp.tv64 = 0; skb->pkt_type = PACKET_HOST; skb->protocol = eth_type_trans(skb, rcv); if (dev->features & NETIF_F_NO_CSUM) -- cgit v1.2.3-18-g5258 From a65a688182cd7f5b69bd6dd9022be96ea771642c Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 21 Jul 2009 11:25:26 +0000 Subject: net: move sgiseeq's probe function to .devinit.text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A pointer to sgiseeq_probe is passed to the core via platform_driver_register and so the function must not disappear when the .init sections are discarded. Otherwise (if also having HOTPLUG=y) unbinding and binding a device to the driver via sysfs will result in an oops as does a device being registered late. An alternative to this patch is using platform_driver_probe instead of platform_driver_register plus removing the pointer to the probe function from the struct platform_driver. Signed-off-by: Uwe Kleine-König Cc: Wang Chen Cc: David S. Miller Cc: Andrew Morton Cc: Jeff Garzik Cc: Thomas Bogendoerfer Acked-by: Ralf Baechle Cc: Greg Kroah-Hartman Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller --- drivers/net/sgiseeq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 78f60089b55..ecf3279fbef 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -720,7 +720,7 @@ static const struct net_device_ops sgiseeq_netdev_ops = { .ndo_validate_addr = eth_validate_addr, }; -static int __init sgiseeq_probe(struct platform_device *pdev) +static int __devinit sgiseeq_probe(struct platform_device *pdev) { struct sgiseeq_platform_data *pd = pdev->dev.platform_data; struct hpc3_regs *hpcregs = pd->hpc; -- cgit v1.2.3-18-g5258 From 2e76baea67fa74442938afd3417170b28e7aac86 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 21 Jul 2009 11:25:22 +0000 Subject: net: move jazzsonic's probe function to .devinit.text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A pointer to jazz_sonic_probe is passed to the core via platform_driver_register and so the function must not disappear when the .init sections are discarded. Otherwise (if also having HOTPLUG=y) unbinding and binding a device to the driver via sysfs will result in an oops as does a device being registered late. As noticed by Geert Uytterhoeven sonic_probe1 is called by jazz_sonic_probe, so the former has to move to .devinit.text, too. An alternative to this patch is using platform_driver_probe instead of platform_driver_register plus removing the pointer to the probe function from the struct platform_driver. Signed-off-by: Uwe Kleine-König Acked-by: Ralf Baechle Cc: Jeff Garzik Cc: David S. Miller Cc: Thomas Bogendoerfer Cc: Finn Thain Cc: Geert Uytterhoeven Cc: Andrew Morton Cc: netdev@vger.kernel.org Cc: Greg Kroah-Hartman Signed-off-by: David S. Miller --- drivers/net/jazzsonic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index d12106b47bf..8baf5950731 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -108,7 +108,7 @@ static const struct net_device_ops sonic_netdev_ops = { .ndo_set_mac_address = eth_mac_addr, }; -static int __init sonic_probe1(struct net_device *dev) +static int __devinit sonic_probe1(struct net_device *dev) { static unsigned version_printed; unsigned int silicon_revision; @@ -211,7 +211,7 @@ out: * Probe for a SONIC ethernet controller on a Mips Jazz board. * Actually probing is superfluous but we're paranoid. */ -static int __init jazz_sonic_probe(struct platform_device *pdev) +static int __devinit jazz_sonic_probe(struct platform_device *pdev) { struct net_device *dev; struct sonic_local *lp; -- cgit v1.2.3-18-g5258 From dd93667711761362b393cfbd5959bb11aa1fa80d Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 21 Jul 2009 11:25:24 +0000 Subject: net: move meth's probe function to .devinit.text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A pointer to meth_probe is passed to the core via platform_driver_register and so the function must not disappear when the .init sections are discarded. Otherwise (if also having HOTPLUG=y) unbinding and binding a device to the driver via sysfs will result in an oops as does a device being registered late. An alternative to this patch is using platform_driver_probe instead of platform_driver_register plus removing the pointer to the probe function from the struct platform_driver. Signed-off-by: Uwe Kleine-König Cc: David S. Miller Cc: Thomas Bogendoerfer Cc: Christoph Lameter Cc: Jeff Garzik Acked-by: Ralf Baechle Cc: Andrew Morton Cc: netdev@vger.kernel.org Cc: Greg Kroah-Hartman Signed-off-by: David S. Miller --- drivers/net/meth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/meth.c b/drivers/net/meth.c index abea35de255..92ceb689b4d 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -784,7 +784,7 @@ static const struct net_device_ops meth_netdev_ops = { /* * The init function. */ -static int __init meth_probe(struct platform_device *pdev) +static int __devinit meth_probe(struct platform_device *pdev) { struct net_device *dev; struct meth_private *priv; -- cgit v1.2.3-18-g5258 From ffe8553f8871dabf61d49e7f97a2c6cbc7dc23cb Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 21 Jul 2009 11:25:25 +0000 Subject: net: move sb1250-mac's probe function to .devinit.text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A pointer to sbmac_probe is passed to the core via platform_driver_register and so the function must not disappear when the .init sections are discarded. Otherwise (if also having HOTPLUG=y) unbinding and binding a device to the driver via sysfs will result in an oops as does a device being registered late. An alternative to this patch is using platform_driver_probe instead of platform_driver_register plus removing the pointer to the probe function from the struct platform_driver. Signed-off-by: Uwe Kleine-König Cc: Weiwei Wang Cc: Jeff Garzik Cc: David S. Miller Cc: Stephen Hemminger Acked-by: Maciej W. Rozycki Cc: Andrew Morton Cc: Greg Kroah-Hartman Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller --- drivers/net/sb1250-mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 4c2450b6bd0..508551f1b3f 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2688,7 +2688,7 @@ static int sbmac_poll(struct napi_struct *napi, int budget) } -static int __init sbmac_probe(struct platform_device *pldev) +static int __devinit sbmac_probe(struct platform_device *pldev) { struct net_device *dev; struct sbmac_softc *sc; -- cgit v1.2.3-18-g5258 From 0c9cd395faca5ccf549e2bcb6b09086962c112b0 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 21 Jul 2009 11:25:27 +0000 Subject: net: move xtsonic's probe function to .devinit.text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A pointer to xtsonic_probe is passed to the core via platform_driver_register and so the function must not disappear when the .init sections are discarded. Otherwise (if also having HOTPLUG=y) unbinding and binding a device to the driver via sysfs will result in an oops as does a device being registered late. An alternative to this patch is using platform_driver_probe instead of platform_driver_register plus removing the pointer to the probe function from the struct platform_driver. Signed-off-by: Uwe Kleine-König Cc: Chris Zankel Cc: David S. Miller Cc: Andrew Morton Cc: Greg Kroah-Hartman Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller --- drivers/net/xtsonic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/xtsonic.c b/drivers/net/xtsonic.c index 5a4ad156f63..0c44135c0b1 100644 --- a/drivers/net/xtsonic.c +++ b/drivers/net/xtsonic.c @@ -239,7 +239,7 @@ out: * Actually probing is superfluous but we're paranoid. */ -int __init xtsonic_probe(struct platform_device *pdev) +int __devinit xtsonic_probe(struct platform_device *pdev) { struct net_device *dev; struct sonic_local *lp; -- cgit v1.2.3-18-g5258 From c9a73cdb772a487b2c59c2711ad8b10d58cbaca8 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 21 Jul 2009 11:25:23 +0000 Subject: net: move macsonic's probe function to .devinit.text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A pointer to mac_sonic_probe is passed to the core via platform_driver_register and so the function must not disappear when the .init sections are discarded. Otherwise (if also having HOTPLUG=y) unbinding and binding a device to the driver via sysfs will result in an oops as does a device being registered late. Various other functions that are called by mac_sonic_probe need to move to .devinit.text, too. An alternative to this patch is using platform_driver_probe instead of platform_driver_register plus removing the pointer to the probe function from the struct platform_driver. Signed-off-by: Uwe Kleine-König Cc: Jeff Garzik Cc: David S. Miller Tested-by: Finn Thain Cc: Geert Uytterhoeven Cc: Andrew Morton Cc: netdev@vger.kernel.org Cc: Greg Kroah-Hartman Signed-off-by: David S. Miller --- drivers/net/macsonic.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index acd143da161..8f492c7b809 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -179,7 +179,7 @@ static const struct net_device_ops macsonic_netdev_ops = { .ndo_set_mac_address = eth_mac_addr, }; -static int __init macsonic_init(struct net_device *dev) +static int __devinit macsonic_init(struct net_device *dev) { struct sonic_local* lp = netdev_priv(dev); @@ -223,7 +223,7 @@ static int __init macsonic_init(struct net_device *dev) return 0; } -static int __init mac_onboard_sonic_ethernet_addr(struct net_device *dev) +static int __devinit mac_onboard_sonic_ethernet_addr(struct net_device *dev) { struct sonic_local *lp = netdev_priv(dev); const int prom_addr = ONBOARD_SONIC_PROM_BASE; @@ -288,7 +288,7 @@ static int __init mac_onboard_sonic_ethernet_addr(struct net_device *dev) } else return 0; } -static int __init mac_onboard_sonic_probe(struct net_device *dev) +static int __devinit mac_onboard_sonic_probe(struct net_device *dev) { /* Bwahahaha */ static int once_is_more_than_enough; @@ -409,7 +409,7 @@ static int __init mac_onboard_sonic_probe(struct net_device *dev) return macsonic_init(dev); } -static int __init mac_nubus_sonic_ethernet_addr(struct net_device *dev, +static int __devinit mac_nubus_sonic_ethernet_addr(struct net_device *dev, unsigned long prom_addr, int id) { @@ -424,7 +424,7 @@ static int __init mac_nubus_sonic_ethernet_addr(struct net_device *dev, return 0; } -static int __init macsonic_ident(struct nubus_dev *ndev) +static int __devinit macsonic_ident(struct nubus_dev *ndev) { if (ndev->dr_hw == NUBUS_DRHW_ASANTE_LC && ndev->dr_sw == NUBUS_DRSW_SONIC_LC) @@ -449,7 +449,7 @@ static int __init macsonic_ident(struct nubus_dev *ndev) return -1; } -static int __init mac_nubus_sonic_probe(struct net_device *dev) +static int __devinit mac_nubus_sonic_probe(struct net_device *dev) { static int slots; struct nubus_dev* ndev = NULL; @@ -562,7 +562,7 @@ static int __init mac_nubus_sonic_probe(struct net_device *dev) return macsonic_init(dev); } -static int __init mac_sonic_probe(struct platform_device *pdev) +static int __devinit mac_sonic_probe(struct platform_device *pdev) { struct net_device *dev; struct sonic_local *lp; -- cgit v1.2.3-18-g5258 From 83c98a8cd04dd0f848574370594886ba3bf56750 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 21 Jul 2009 09:15:49 +0000 Subject: Remove unused zero-copy code from velocity NIC driver. This code hasn't been enabled in forever. Signed-off-by: Dave Jones Signed-off-by: David S. Miller --- drivers/net/via-velocity.c | 77 +++++++--------------------------------------- 1 file changed, 11 insertions(+), 66 deletions(-) (limited to 'drivers') diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 42365e5f931..4ebe2cacf50 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -976,9 +976,6 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi dev->netdev_ops = &velocity_netdev_ops; dev->ethtool_ops = &velocity_ethtool_ops; -#ifdef VELOCITY_ZERO_COPY_SUPPORT - dev->features |= NETIF_F_SG; -#endif dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_HW_VLAN_RX; @@ -1849,11 +1846,7 @@ static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_ pktlen = max_t(unsigned int, skb->len, ETH_ZLEN); for (i = 0; i < tdinfo->nskb_dma; i++) { -#ifdef VELOCITY_ZERO_COPY_SUPPORT - pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], le16_to_cpu(td->tdesc1.len), PCI_DMA_TODEVICE); -#else pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], pktlen, PCI_DMA_TODEVICE); -#endif tdinfo->skb_dma[i] = 0; } } @@ -2095,13 +2088,6 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) len = cpu_to_le16(pktlen); -#ifdef VELOCITY_ZERO_COPY_SUPPORT - if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) { - kfree_skb(skb); - return NETDEV_TX_OK; - } -#endif - spin_lock_irqsave(&vptr->lock, flags); index = vptr->tx.curr[qnum]; @@ -2111,59 +2097,18 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) td_ptr->tdesc1.TCR = TCR0_TIC; td_ptr->td_buf[0].size &= ~TD_QUEUE; -#ifdef VELOCITY_ZERO_COPY_SUPPORT - if (skb_shinfo(skb)->nr_frags > 0) { - int nfrags = skb_shinfo(skb)->nr_frags; - tdinfo->skb = skb; - if (nfrags > 6) { - skb_copy_from_linear_data(skb, tdinfo->buf, skb->len); - tdinfo->skb_dma[0] = tdinfo->buf_dma; - td_ptr->tdesc0.len = len; - td_ptr->tx.buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); - td_ptr->tx.buf[0].pa_high = 0; - td_ptr->tx.buf[0].size = len; /* queue is 0 anyway */ - tdinfo->nskb_dma = 1; - } else { - int i = 0; - tdinfo->nskb_dma = 0; - tdinfo->skb_dma[i] = pci_map_single(vptr->pdev, skb->data, - skb_headlen(skb), PCI_DMA_TODEVICE); - - td_ptr->tdesc0.len = len; - - /* FIXME: support 48bit DMA later */ - td_ptr->tx.buf[i].pa_low = cpu_to_le32(tdinfo->skb_dma); - td_ptr->tx.buf[i].pa_high = 0; - td_ptr->tx.buf[i].size = cpu_to_le16(skb_headlen(skb)); - - for (i = 0; i < nfrags; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - void *addr = (void *)page_address(frag->page) + frag->page_offset; - - tdinfo->skb_dma[i + 1] = pci_map_single(vptr->pdev, addr, frag->size, PCI_DMA_TODEVICE); - - td_ptr->tx.buf[i + 1].pa_low = cpu_to_le32(tdinfo->skb_dma[i + 1]); - td_ptr->tx.buf[i + 1].pa_high = 0; - td_ptr->tx.buf[i + 1].size = cpu_to_le16(frag->size); - } - tdinfo->nskb_dma = i - 1; - } + /* + * Map the linear network buffer into PCI space and + * add it to the transmit ring. + */ + tdinfo->skb = skb; + tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE); + td_ptr->tdesc0.len = len; + td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); + td_ptr->td_buf[0].pa_high = 0; + td_ptr->td_buf[0].size = len; + tdinfo->nskb_dma = 1; - } else -#endif - { - /* - * Map the linear network buffer into PCI space and - * add it to the transmit ring. - */ - tdinfo->skb = skb; - tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE); - td_ptr->tdesc0.len = len; - td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); - td_ptr->td_buf[0].pa_high = 0; - td_ptr->td_buf[0].size = len; - tdinfo->nskb_dma = 1; - } td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16; if (vptr->vlgrp && vlan_tx_tag_present(skb)) { -- cgit v1.2.3-18-g5258 From c40674001b162f9218ba2a6f26188177c6a4e763 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 20 Jul 2009 17:35:21 +0000 Subject: Fix up CodingStyle problems in via-velocity.c Signed-off-by: Dave Jones Signed-off-by: David S. Miller --- drivers/net/via-velocity.c | 175 +++++++++++++++++++++------------------------ 1 file changed, 80 insertions(+), 95 deletions(-) (limited to 'drivers') diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 4ebe2cacf50..d6a92b794f3 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -61,9 +61,9 @@ #include #include #include -#include +#include #include -#include +#include #include #include #include @@ -81,7 +81,7 @@ #include "via-velocity.h" -static int velocity_nics = 0; +static int velocity_nics; static int msglevel = MSG_LEVEL_INFO; /** @@ -93,7 +93,7 @@ static int msglevel = MSG_LEVEL_INFO; * provided mask buffer. */ -static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask) +static void mac_get_cam_mask(struct mac_regs __iomem *regs, u8 *mask) { int i; @@ -111,7 +111,6 @@ static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask) /* Select mar */ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); - } @@ -123,7 +122,7 @@ static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask) * Store a new mask into a CAM */ -static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask) +static void mac_set_cam_mask(struct mac_regs __iomem *regs, u8 *mask) { int i; /* Select CAM mask */ @@ -131,9 +130,9 @@ static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask) writeb(CAMADDR_CAMEN, ®s->CAMADDR); - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) writeb(*mask++, &(regs->MARCAM[i])); - } + /* disable CAMEN */ writeb(0, ®s->CAMADDR); @@ -141,7 +140,7 @@ static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask) BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); } -static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask) +static void mac_set_vlan_cam_mask(struct mac_regs __iomem *regs, u8 *mask) { int i; /* Select CAM mask */ @@ -149,9 +148,9 @@ static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask) writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, ®s->CAMADDR); - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) writeb(*mask++, &(regs->MARCAM[i])); - } + /* disable CAMEN */ writeb(0, ®s->CAMADDR); @@ -168,7 +167,7 @@ static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask) * Load an address or vlan tag into a CAM */ -static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr) +static void mac_set_cam(struct mac_regs __iomem *regs, int idx, const u8 *addr) { int i; @@ -179,9 +178,9 @@ static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr) writeb(CAMADDR_CAMEN | idx, ®s->CAMADDR); - for (i = 0; i < 6; i++) { + for (i = 0; i < 6; i++) writeb(*addr++, &(regs->MARCAM[i])); - } + BYTE_REG_BITS_ON(CAMCR_CAMWR, ®s->CAMCR); udelay(10); @@ -192,7 +191,7 @@ static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr) BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); } -static void mac_set_vlan_cam(struct mac_regs __iomem * regs, int idx, +static void mac_set_vlan_cam(struct mac_regs __iomem *regs, int idx, const u8 *addr) { @@ -224,7 +223,7 @@ static void mac_set_vlan_cam(struct mac_regs __iomem * regs, int idx, * the rest of the logic from the result of sleep/wakeup */ -static void mac_wol_reset(struct mac_regs __iomem * regs) +static void mac_wol_reset(struct mac_regs __iomem *regs) { /* Turn off SWPTAG right after leaving power mode */ @@ -253,10 +252,10 @@ MODULE_AUTHOR("VIA Networking Technologies, Inc."); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("VIA Networking Velocity Family Gigabit Ethernet Adapter Driver"); -#define VELOCITY_PARAM(N,D) \ - static int N[MAX_UNITS]=OPTION_DEFAULT;\ +#define VELOCITY_PARAM(N, D) \ + static int N[MAX_UNITS] = OPTION_DEFAULT;\ module_param_array(N, int, NULL, 0); \ - MODULE_PARM_DESC(N, D); + MODULE_PARM_DESC(N, D); #define RX_DESC_MIN 64 #define RX_DESC_MAX 255 @@ -336,8 +335,8 @@ VELOCITY_PARAM(flow_control, "Enable flow control ability"); 4: indicate 10Mbps full duplex mode Note: - if EEPROM have been set to the force mode, this option is ignored - by driver. + if EEPROM have been set to the force mode, this option is ignored + by driver. */ VELOCITY_PARAM(speed_duplex, "Setting the speed and duplex mode"); @@ -391,14 +390,14 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status); static u32 velocity_get_link(struct net_device *dev); static u32 velocity_get_opt_media_mode(struct velocity_info *vptr); static void velocity_print_link_status(struct velocity_info *vptr); -static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs); +static void safe_disable_mii_autopoll(struct mac_regs __iomem *regs); static void velocity_shutdown(struct velocity_info *vptr); static void enable_flow_control_ability(struct velocity_info *vptr); -static void enable_mii_autopoll(struct mac_regs __iomem * regs); -static int velocity_mii_read(struct mac_regs __iomem *, u8 byIdx, u16 * pdata); +static void enable_mii_autopoll(struct mac_regs __iomem *regs); +static int velocity_mii_read(struct mac_regs __iomem *, u8 byIdx, u16 *pdata); static int velocity_mii_write(struct mac_regs __iomem *, u8 byMiiAddr, u16 data); -static u32 mii_check_media_mode(struct mac_regs __iomem * regs); -static u32 check_connection_type(struct mac_regs __iomem * regs); +static u32 mii_check_media_mode(struct mac_regs __iomem *regs); +static u32 check_connection_type(struct mac_regs __iomem *regs); static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status); #ifdef CONFIG_PM @@ -550,7 +549,7 @@ static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max, * we don't duplicate code for each option. */ -static void __devinit velocity_set_bool_opt(u32 * opt, int val, int def, u32 flag, char *name, const char *devname) +static void __devinit velocity_set_bool_opt(u32 *opt, int val, int def, u32 flag, char *name, const char *devname) { (*opt) &= (~flag); if (val == -1) @@ -604,7 +603,7 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index, static void velocity_init_cam_filter(struct velocity_info *vptr) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; /* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */ WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, ®s->MCFG); @@ -647,19 +646,19 @@ static void velocity_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) { struct velocity_info *vptr = netdev_priv(dev); - spin_lock_irq(&vptr->lock); + spin_lock_irq(&vptr->lock); velocity_init_cam_filter(vptr); - spin_unlock_irq(&vptr->lock); + spin_unlock_irq(&vptr->lock); } static void velocity_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) { struct velocity_info *vptr = netdev_priv(dev); - spin_lock_irq(&vptr->lock); + spin_lock_irq(&vptr->lock); vlan_group_set_device(vptr->vlgrp, vid, NULL); velocity_init_cam_filter(vptr); - spin_unlock_irq(&vptr->lock); + spin_unlock_irq(&vptr->lock); } static void velocity_init_rx_ring_indexes(struct velocity_info *vptr) @@ -678,7 +677,7 @@ static void velocity_init_rx_ring_indexes(struct velocity_info *vptr) static void velocity_rx_reset(struct velocity_info *vptr) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; int i; velocity_init_rx_ring_indexes(vptr); @@ -707,7 +706,7 @@ static void velocity_rx_reset(struct velocity_info *vptr) static void velocity_init_registers(struct velocity_info *vptr, enum velocity_init_type type) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; int i, mii_status; mac_wol_reset(regs); @@ -750,9 +749,9 @@ static void velocity_init_registers(struct velocity_info *vptr, mdelay(5); mac_eeprom_reload(regs); - for (i = 0; i < 6; i++) { + for (i = 0; i < 6; i++) writeb(vptr->dev->dev_addr[i], &(regs->PAR[i])); - } + /* * clear Pre_ACPI bit. */ @@ -829,7 +828,7 @@ static void velocity_init_registers(struct velocity_info *vptr, static int velocity_soft_reset(struct velocity_info *vptr) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; int i = 0; writel(CR0_SFRST, ®s->CR0Set); @@ -881,7 +880,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi const char *drv_string; const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data]; struct velocity_info *vptr; - struct mac_regs __iomem * regs; + struct mac_regs __iomem *regs; int ret = -ENOMEM; /* FIXME: this driver, like almost all other ethernet drivers, @@ -1311,7 +1310,7 @@ static int velocity_init_td_ring(struct velocity_info *vptr) sizeof(struct velocity_td_info), GFP_KERNEL); if (!vptr->tx.infos[j]) { - while(--j >= 0) + while (--j >= 0) kfree(vptr->tx.infos[j]); return -ENOMEM; } @@ -1328,15 +1327,14 @@ static int velocity_init_td_ring(struct velocity_info *vptr) static void velocity_free_td_ring_entry(struct velocity_info *vptr, int q, int n) { - struct velocity_td_info * td_info = &(vptr->tx.infos[q][n]); + struct velocity_td_info *td_info = &(vptr->tx.infos[q][n]); int i; if (td_info == NULL) return; if (td_info->skb) { - for (i = 0; i < td_info->nskb_dma; i++) - { + for (i = 0; i < td_info->nskb_dma; i++) { if (td_info->skb_dma[i]) { pci_unmap_single(vptr->pdev, td_info->skb_dma[i], td_info->skb->len, PCI_DMA_TODEVICE); @@ -1363,10 +1361,9 @@ static void velocity_free_td_ring(struct velocity_info *vptr) for (j = 0; j < vptr->tx.numq; j++) { if (vptr->tx.infos[j] == NULL) continue; - for (i = 0; i < vptr->options.numtx; i++) { + for (i = 0; i < vptr->options.numtx; i++) velocity_free_td_ring_entry(vptr, j, i); - } kfree(vptr->tx.infos[j]); vptr->tx.infos[j] = NULL; } @@ -1447,9 +1444,8 @@ static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb) if (rd->rdesc1.CSM & CSM_IPOK) { if ((rd->rdesc1.CSM & CSM_TCPKT) || (rd->rdesc1.CSM & CSM_UDPKT)) { - if (!(rd->rdesc1.CSM & CSM_TUPOK)) { + if (!(rd->rdesc1.CSM & CSM_TUPOK)) return; - } } skb->ip_summed = CHECKSUM_UNNECESSARY; } @@ -1671,9 +1667,8 @@ static int velocity_tx_srv(struct velocity_info *vptr, u32 status) } vptr->tx.tail[qnum] = idx; - if (AVAIL_TD(vptr, qnum) < 1) { + if (AVAIL_TD(vptr, qnum) < 1) full = 1; - } } /* * Look to see if we should kick the transmit network @@ -1751,7 +1746,7 @@ static void velocity_error(struct velocity_info *vptr, int status) { if (status & ISR_TXSTLI) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; printk(KERN_ERR "TD structure error TDindex=%hx\n", readw(®s->TDIdx[0])); BYTE_REG_BITS_ON(TXESR_TDSTR, ®s->TXESR); @@ -1763,7 +1758,7 @@ static void velocity_error(struct velocity_info *vptr, int status) } if (status & ISR_SRCI) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; int linked; if (vptr->options.spd_dpx == SPD_DPX_AUTO) { @@ -1783,11 +1778,10 @@ static void velocity_error(struct velocity_info *vptr, int status) /* * Only enable CD heart beat counter in 10HD mode */ - if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10)) { + if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10)) BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); - } else { + else BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG); - } } /* * Get link status from PHYSR0 @@ -2023,7 +2017,7 @@ out_0: static void velocity_shutdown(struct velocity_info *vptr) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; mac_disable_int(regs); writel(CR0_STOP, ®s->CR0Set); writew(0xFFFF, ®s->TDCSRClr); @@ -2195,8 +2189,7 @@ static irqreturn_t velocity_intr(int irq, void *dev_instance) if (isr_status & (ISR_PTXI | ISR_PPTXI)) max_count += velocity_tx_srv(vptr, isr_status); isr_status = mac_read_isr(vptr->mac_regs); - if (max_count > vptr->options.int_works) - { + if (max_count > vptr->options.int_works) { printk(KERN_WARNING "%s: excessive work at interrupt.\n", dev->name); max_count = 0; @@ -2221,7 +2214,7 @@ static irqreturn_t velocity_intr(int irq, void *dev_instance) static void velocity_set_multi(struct net_device *dev) { struct velocity_info *vptr = netdev_priv(dev); - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; u8 rx_mode; int i; struct dev_mc_list *mclist; @@ -2270,7 +2263,7 @@ static struct net_device_stats *velocity_get_stats(struct net_device *dev) struct velocity_info *vptr = netdev_priv(dev); /* If the hardware is down, don't touch MII */ - if(!netif_running(dev)) + if (!netif_running(dev)) return &dev->stats; spin_lock_irq(&vptr->lock); @@ -2473,7 +2466,7 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status) * Turn off the autopoll and wait for it to disable on the chip */ -static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs) +static void safe_disable_mii_autopoll(struct mac_regs __iomem *regs) { u16 ww; @@ -2494,7 +2487,7 @@ static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs) * hardware. Wait for it to enable. */ -static void enable_mii_autopoll(struct mac_regs __iomem * regs) +static void enable_mii_autopoll(struct mac_regs __iomem *regs) { int ii; @@ -2644,7 +2637,7 @@ static void mii_set_auto_on(struct velocity_info *vptr) /* -static void mii_set_auto_off(struct velocity_info * vptr) +static void mii_set_auto_off(struct velocity_info *vptr) { MII_REG_BITS_OFF(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); } @@ -2698,7 +2691,7 @@ static void set_mii_flow_control(struct velocity_info *vptr) static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status) { u32 curr_status; - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; vptr->mii_status = mii_check_media_mode(vptr->mac_regs); curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL); @@ -2717,9 +2710,8 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status) } */ - if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) { + if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs); - } /* * If connection type is AUTO @@ -2768,11 +2760,11 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status) MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs); - if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10)) { + if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10)) BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); - } else { + else BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG); - } + /* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */ velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR); ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)); @@ -2805,7 +2797,7 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status) * accordingly */ -static u32 mii_check_media_mode(struct mac_regs __iomem * regs) +static u32 mii_check_media_mode(struct mac_regs __iomem *regs) { u32 status = 0; u16 ANAR; @@ -2841,7 +2833,7 @@ static u32 mii_check_media_mode(struct mac_regs __iomem * regs) return status; } -static u32 check_connection_type(struct mac_regs __iomem * regs) +static u32 check_connection_type(struct mac_regs __iomem *regs) { u32 status = 0; u8 PHYSR0; @@ -2886,7 +2878,7 @@ static u32 check_connection_type(struct mac_regs __iomem * regs) static void enable_flow_control_ability(struct velocity_info *vptr) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; switch (vptr->options.flow_cntl) { @@ -2963,7 +2955,7 @@ static void velocity_ethtool_down(struct net_device *dev) static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct velocity_info *vptr = netdev_priv(dev); - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; u32 status; status = check_connection_type(vptr->mac_regs); @@ -3020,7 +3012,7 @@ static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd static u32 velocity_get_link(struct net_device *dev) { struct velocity_info *vptr = netdev_priv(dev); - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, ®s->PHYSR0) ? 1 : 0; } @@ -3116,7 +3108,7 @@ static const struct ethtool_ops velocity_ethtool_ops = { static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct velocity_info *vptr = netdev_priv(dev); - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; unsigned long flags; struct mii_ioctl_data *miidata = if_mii(ifr); int err; @@ -3128,7 +3120,7 @@ static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd case SIOCGMIIREG: if (!capable(CAP_NET_ADMIN)) return -EPERM; - if(velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0) + if (velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0) return -ETIMEDOUT; break; case SIOCSMIIREG: @@ -3138,7 +3130,7 @@ static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in); spin_unlock_irqrestore(&vptr->lock, flags); check_connection_type(vptr->mac_regs); - if(err) + if (err) return err; break; default: @@ -3160,9 +3152,9 @@ static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd * power down states */ -static void velocity_save_context(struct velocity_info *vptr, struct velocity_context * context) +static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; u16 i; u8 __iomem *ptr = (u8 __iomem *)regs; @@ -3188,13 +3180,12 @@ static void velocity_save_context(struct velocity_info *vptr, struct velocity_co static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; int i; u8 __iomem *ptr = (u8 __iomem *)regs; - for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4) { + for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4) writel(*((u32 *) (context->mac_reg + i)), ptr + i); - } /* Just skip cr0 */ for (i = MAC_REG_CR1_SET; i < MAC_REG_CR0_CLR; i++) { @@ -3204,18 +3195,14 @@ static void velocity_restore_context(struct velocity_info *vptr, struct velocity writeb(*((u8 *) (context->mac_reg + i)), ptr + i); } - for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4) { + for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4) writel(*((u32 *) (context->mac_reg + i)), ptr + i); - } - for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) { + for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) writel(*((u32 *) (context->mac_reg + i)), ptr + i); - } - for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++) { + for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++) writeb(*((u8 *) (context->mac_reg + i)), ptr + i); - } - } /** @@ -3227,7 +3214,7 @@ static void velocity_restore_context(struct velocity_info *vptr, struct velocity * we are interested in. */ -static u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern) +static u16 wol_calc_crc(int size, u8 *pattern, u8 *mask_pattern) { u16 crc = 0xFFFF; u8 mask; @@ -3266,7 +3253,7 @@ static u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern) static int velocity_set_wol(struct velocity_info *vptr) { - struct mac_regs __iomem * regs = vptr->mac_regs; + struct mac_regs __iomem *regs = vptr->mac_regs; static u8 buf[256]; int i; @@ -3284,9 +3271,8 @@ static int velocity_set_wol(struct velocity_info *vptr) writew((WOLCR_LINKON_EN|WOLCR_LINKOFF_EN), ®s->WOLCRSet); */ - if (vptr->wol_opts & VELOCITY_WOL_UCAST) { + if (vptr->wol_opts & VELOCITY_WOL_UCAST) writew(WOLCR_UNICAST_EN, ®s->WOLCRSet); - } if (vptr->wol_opts & VELOCITY_WOL_ARP) { struct arp_packet *arp = (struct arp_packet *) buf; @@ -3347,7 +3333,7 @@ static int velocity_suspend(struct pci_dev *pdev, pm_message_t state) struct velocity_info *vptr = netdev_priv(dev); unsigned long flags; - if(!netif_running(vptr->dev)) + if (!netif_running(vptr->dev)) return 0; netif_device_detach(vptr->dev); @@ -3382,7 +3368,7 @@ static int velocity_resume(struct pci_dev *pdev) unsigned long flags; int i; - if(!netif_running(vptr->dev)) + if (!netif_running(vptr->dev)) return 0; pci_set_power_state(pdev, PCI_D0); @@ -3399,9 +3385,8 @@ static int velocity_resume(struct pci_dev *pdev) velocity_tx_srv(vptr, 0); for (i = 0; i < vptr->tx.numq; i++) { - if (vptr->tx.used[i]) { + if (vptr->tx.used[i]) mac_tx_queue_wake(vptr->mac_regs, i); - } } mac_enable_int(vptr->mac_regs); -- cgit v1.2.3-18-g5258 From 2cf71d2e388cb0076b03f40f2fadfc590c228461 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 23 Jul 2009 18:11:12 -0700 Subject: Remove unnecessary forward declarations from velocity NIC driver. By moving functions to before their first call, we eliminate the need to define forward references. Signed-off-by: Dave Jones Signed-off-by: David S. Miller --- drivers/net/via-velocity.c | 3961 +++++++++++++++++++++----------------------- 1 file changed, 1930 insertions(+), 2031 deletions(-) (limited to 'drivers') diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index d6a92b794f3..47be41a39d3 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -92,7 +92,6 @@ static int msglevel = MSG_LEVEL_INFO; * Fetch the mask bits of the selected CAM and store them into the * provided mask buffer. */ - static void mac_get_cam_mask(struct mac_regs __iomem *regs, u8 *mask) { int i; @@ -121,7 +120,6 @@ static void mac_get_cam_mask(struct mac_regs __iomem *regs, u8 *mask) * * Store a new mask into a CAM */ - static void mac_set_cam_mask(struct mac_regs __iomem *regs, u8 *mask) { int i; @@ -166,7 +164,6 @@ static void mac_set_vlan_cam_mask(struct mac_regs __iomem *regs, u8 *mask) * * Load an address or vlan tag into a CAM */ - static void mac_set_cam(struct mac_regs __iomem *regs, int idx, const u8 *addr) { int i; @@ -222,7 +219,6 @@ static void mac_set_vlan_cam(struct mac_regs __iomem *regs, int idx, * reset the Wake on lan features. This function doesn't restore * the rest of the logic from the result of sleep/wakeup */ - static void mac_wol_reset(struct mac_regs __iomem *regs) { @@ -241,7 +237,6 @@ static void mac_wol_reset(struct mac_regs __iomem *regs) writew(0xFFFF, ®s->WOLSRClr); } -static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static const struct ethtool_ops velocity_ethtool_ops; /* @@ -369,76 +364,14 @@ static int rx_copybreak = 200; module_param(rx_copybreak, int, 0644); MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames"); -static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, - const struct velocity_info_tbl *info); -static int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev); -static void velocity_print_info(struct velocity_info *vptr); -static int velocity_open(struct net_device *dev); -static int velocity_change_mtu(struct net_device *dev, int mtu); -static int velocity_xmit(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t velocity_intr(int irq, void *dev_instance); -static void velocity_set_multi(struct net_device *dev); -static struct net_device_stats *velocity_get_stats(struct net_device *dev); -static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static int velocity_close(struct net_device *dev); -static int velocity_receive_frame(struct velocity_info *, int idx); -static int velocity_alloc_rx_buf(struct velocity_info *, int idx); -static void velocity_free_rd_ring(struct velocity_info *vptr); -static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *); -static int velocity_soft_reset(struct velocity_info *vptr); -static void mii_init(struct velocity_info *vptr, u32 mii_status); -static u32 velocity_get_link(struct net_device *dev); -static u32 velocity_get_opt_media_mode(struct velocity_info *vptr); -static void velocity_print_link_status(struct velocity_info *vptr); -static void safe_disable_mii_autopoll(struct mac_regs __iomem *regs); -static void velocity_shutdown(struct velocity_info *vptr); -static void enable_flow_control_ability(struct velocity_info *vptr); -static void enable_mii_autopoll(struct mac_regs __iomem *regs); -static int velocity_mii_read(struct mac_regs __iomem *, u8 byIdx, u16 *pdata); -static int velocity_mii_write(struct mac_regs __iomem *, u8 byMiiAddr, u16 data); -static u32 mii_check_media_mode(struct mac_regs __iomem *regs); -static u32 check_connection_type(struct mac_regs __iomem *regs); -static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status); - #ifdef CONFIG_PM - -static int velocity_suspend(struct pci_dev *pdev, pm_message_t state); -static int velocity_resume(struct pci_dev *pdev); - static DEFINE_SPINLOCK(velocity_dev_list_lock); static LIST_HEAD(velocity_dev_list); - -#endif - -#if defined(CONFIG_PM) && defined(CONFIG_INET) - -static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr); - -static struct notifier_block velocity_inetaddr_notifier = { - .notifier_call = velocity_netdev_event, -}; - -static void velocity_register_notifier(void) -{ - register_inetaddr_notifier(&velocity_inetaddr_notifier); -} - -static void velocity_unregister_notifier(void) -{ - unregister_inetaddr_notifier(&velocity_inetaddr_notifier); -} - -#else - -#define velocity_register_notifier() do {} while (0) -#define velocity_unregister_notifier() do {} while (0) - #endif /* * Internal board variants. At the moment we have only one */ - static struct velocity_info_tbl chip_info_table[] = { {CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 1, 0x00FFFFFFUL}, { } @@ -448,7 +381,6 @@ static struct velocity_info_tbl chip_info_table[] = { * Describe the PCI device identifiers that we support in this * device driver. Used for hotplug autoloading. */ - static const struct pci_device_id velocity_id_table[] __devinitdata = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X) }, { } @@ -463,7 +395,6 @@ MODULE_DEVICE_TABLE(pci, velocity_id_table); * Given a chip identifier return a suitable description. Returns * a pointer a static string valid while the driver is loaded. */ - static const char __devinit *get_chip_name(enum chip_type chip_id) { int i; @@ -481,7 +412,6 @@ static const char __devinit *get_chip_name(enum chip_type chip_id) * unload for each active device that is present. Disconnects * the device from the network layer and frees all the resources */ - static void __devexit velocity_remove1(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); @@ -519,7 +449,6 @@ static void __devexit velocity_remove1(struct pci_dev *pdev) * all the verification and checking as well as reporting so that * we don't duplicate code for each option. */ - static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max, int def, char *name, const char *devname) { if (val == -1) @@ -548,7 +477,6 @@ static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max, * all the verification and checking as well as reporting so that * we don't duplicate code for each option. */ - static void __devinit velocity_set_bool_opt(u32 *opt, int val, int def, u32 flag, char *name, const char *devname) { (*opt) &= (~flag); @@ -574,7 +502,6 @@ static void __devinit velocity_set_bool_opt(u32 *opt, int val, int def, u32 flag * Turn the module and command options into a single structure * for the current device */ - static void __devinit velocity_get_options(struct velocity_opt *opts, int index, const char *devname) { @@ -600,7 +527,6 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index, * Initialize the content addressable memory used for filters. Load * appropriately according to the presence of VLAN */ - static void velocity_init_cam_filter(struct velocity_info *vptr) { struct mac_regs __iomem *regs = vptr->mac_regs; @@ -673,7 +599,6 @@ static void velocity_init_rx_ring_indexes(struct velocity_info *vptr) * Reset the ownership and status for the receive ring side. * Hand all the receive queue to the NIC. */ - static void velocity_rx_reset(struct velocity_info *vptr) { @@ -695,883 +620,846 @@ static void velocity_rx_reset(struct velocity_info *vptr) } /** - * velocity_init_registers - initialise MAC registers - * @vptr: velocity to init - * @type: type of initialisation (hot or cold) + * velocity_get_opt_media_mode - get media selection + * @vptr: velocity adapter * - * Initialise the MAC on a reset or on first set up on the - * hardware. + * Get the media mode stored in EEPROM or module options and load + * mii_status accordingly. The requested link state information + * is also returned. */ - -static void velocity_init_registers(struct velocity_info *vptr, - enum velocity_init_type type) +static u32 velocity_get_opt_media_mode(struct velocity_info *vptr) { - struct mac_regs __iomem *regs = vptr->mac_regs; - int i, mii_status; - - mac_wol_reset(regs); - - switch (type) { - case VELOCITY_INIT_RESET: - case VELOCITY_INIT_WOL: - - netif_stop_queue(vptr->dev); - - /* - * Reset RX to prevent RX pointer not on the 4X location - */ - velocity_rx_reset(vptr); - mac_rx_queue_run(regs); - mac_rx_queue_wake(regs); - - mii_status = velocity_get_opt_media_mode(vptr); - if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) { - velocity_print_link_status(vptr); - if (!(vptr->mii_status & VELOCITY_LINK_FAIL)) - netif_wake_queue(vptr->dev); - } - - enable_flow_control_ability(vptr); - - mac_clear_isr(regs); - writel(CR0_STOP, ®s->CR0Clr); - writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), - ®s->CR0Set); + u32 status = 0; + switch (vptr->options.spd_dpx) { + case SPD_DPX_AUTO: + status = VELOCITY_AUTONEG_ENABLE; break; + case SPD_DPX_100_FULL: + status = VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL; + break; + case SPD_DPX_10_FULL: + status = VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL; + break; + case SPD_DPX_100_HALF: + status = VELOCITY_SPEED_100; + break; + case SPD_DPX_10_HALF: + status = VELOCITY_SPEED_10; + break; + } + vptr->mii_status = status; + return status; +} - case VELOCITY_INIT_COLD: - default: - /* - * Do reset - */ - velocity_soft_reset(vptr); - mdelay(5); - - mac_eeprom_reload(regs); - for (i = 0; i < 6; i++) - writeb(vptr->dev->dev_addr[i], &(regs->PAR[i])); - - /* - * clear Pre_ACPI bit. - */ - BYTE_REG_BITS_OFF(CFGA_PACPI, &(regs->CFGA)); - mac_set_rx_thresh(regs, vptr->options.rx_thresh); - mac_set_dma_length(regs, vptr->options.DMA_length); - - writeb(WOLCFG_SAM | WOLCFG_SAB, ®s->WOLCFGSet); - /* - * Back off algorithm use original IEEE standard - */ - BYTE_REG_BITS_SET(CFGB_OFSET, (CFGB_CRANDOM | CFGB_CAP | CFGB_MBA | CFGB_BAKOPT), ®s->CFGB); +/** + * safe_disable_mii_autopoll - autopoll off + * @regs: velocity registers + * + * Turn off the autopoll and wait for it to disable on the chip + */ +static void safe_disable_mii_autopoll(struct mac_regs __iomem *regs) +{ + u16 ww; - /* - * Init CAM filter - */ - velocity_init_cam_filter(vptr); + /* turn off MAUTO */ + writeb(0, ®s->MIICR); + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + udelay(1); + if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, ®s->MIISR)) + break; + } +} - /* - * Set packet filter: Receive directed and broadcast address - */ - velocity_set_multi(vptr->dev); +/** + * enable_mii_autopoll - turn on autopolling + * @regs: velocity registers + * + * Enable the MII link status autopoll feature on the Velocity + * hardware. Wait for it to enable. + */ +static void enable_mii_autopoll(struct mac_regs __iomem *regs) +{ + int ii; - /* - * Enable MII auto-polling - */ - enable_mii_autopoll(regs); + writeb(0, &(regs->MIICR)); + writeb(MIIADR_SWMPL, ®s->MIIADR); - vptr->int_mask = INT_MASK_DEF; + for (ii = 0; ii < W_MAX_TIMEOUT; ii++) { + udelay(1); + if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, ®s->MIISR)) + break; + } - writel(vptr->rx.pool_dma, ®s->RDBaseLo); - writew(vptr->options.numrx - 1, ®s->RDCSize); - mac_rx_queue_run(regs); - mac_rx_queue_wake(regs); + writeb(MIICR_MAUTO, ®s->MIICR); - writew(vptr->options.numtx - 1, ®s->TDCSize); + for (ii = 0; ii < W_MAX_TIMEOUT; ii++) { + udelay(1); + if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, ®s->MIISR)) + break; + } - for (i = 0; i < vptr->tx.numq; i++) { - writel(vptr->tx.pool_dma[i], ®s->TDBaseLo[i]); - mac_tx_queue_run(regs, i); - } +} - init_flow_control_register(vptr); +/** + * velocity_mii_read - read MII data + * @regs: velocity registers + * @index: MII register index + * @data: buffer for received data + * + * Perform a single read of an MII 16bit register. Returns zero + * on success or -ETIMEDOUT if the PHY did not respond. + */ +static int velocity_mii_read(struct mac_regs __iomem *regs, u8 index, u16 *data) +{ + u16 ww; - writel(CR0_STOP, ®s->CR0Clr); - writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), ®s->CR0Set); + /* + * Disable MIICR_MAUTO, so that mii addr can be set normally + */ + safe_disable_mii_autopoll(regs); - mii_status = velocity_get_opt_media_mode(vptr); - netif_stop_queue(vptr->dev); + writeb(index, ®s->MIIADR); - mii_init(vptr, mii_status); + BYTE_REG_BITS_ON(MIICR_RCMD, ®s->MIICR); - if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) { - velocity_print_link_status(vptr); - if (!(vptr->mii_status & VELOCITY_LINK_FAIL)) - netif_wake_queue(vptr->dev); - } + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + if (!(readb(®s->MIICR) & MIICR_RCMD)) + break; + } - enable_flow_control_ability(vptr); - mac_hw_mibs_init(regs); - mac_write_int_mask(vptr->int_mask, regs); - mac_clear_isr(regs); + *data = readw(®s->MIIDATA); - } + enable_mii_autopoll(regs); + if (ww == W_MAX_TIMEOUT) + return -ETIMEDOUT; + return 0; } + /** - * velocity_soft_reset - soft reset - * @vptr: velocity to reset + * mii_check_media_mode - check media state + * @regs: velocity registers * - * Kick off a soft reset of the velocity adapter and then poll - * until the reset sequence has completed before returning. + * Check the current MII status and determine the link status + * accordingly */ - -static int velocity_soft_reset(struct velocity_info *vptr) +static u32 mii_check_media_mode(struct mac_regs __iomem *regs) { - struct mac_regs __iomem *regs = vptr->mac_regs; - int i = 0; + u32 status = 0; + u16 ANAR; - writel(CR0_SFRST, ®s->CR0Set); + if (!MII_REG_BITS_IS_ON(BMSR_LNK, MII_REG_BMSR, regs)) + status |= VELOCITY_LINK_FAIL; - for (i = 0; i < W_MAX_TIMEOUT; i++) { - udelay(5); - if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, ®s->CR0Set)) - break; + if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs)) + status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL; + else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs)) + status |= (VELOCITY_SPEED_1000); + else { + velocity_mii_read(regs, MII_REG_ANAR, &ANAR); + if (ANAR & ANAR_TXFD) + status |= (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL); + else if (ANAR & ANAR_TX) + status |= VELOCITY_SPEED_100; + else if (ANAR & ANAR_10FD) + status |= (VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL); + else + status |= (VELOCITY_SPEED_10); } - if (i == W_MAX_TIMEOUT) { - writel(CR0_FORSRST, ®s->CR0Set); - /* FIXME: PCI POSTING */ - /* delay 2ms */ - mdelay(2); + if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) { + velocity_mii_read(regs, MII_REG_ANAR, &ANAR); + if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) + == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) { + if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs)) + status |= VELOCITY_AUTONEG_ENABLE; + } } - return 0; -} -static const struct net_device_ops velocity_netdev_ops = { - .ndo_open = velocity_open, - .ndo_stop = velocity_close, - .ndo_start_xmit = velocity_xmit, - .ndo_get_stats = velocity_get_stats, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, - .ndo_set_multicast_list = velocity_set_multi, - .ndo_change_mtu = velocity_change_mtu, - .ndo_do_ioctl = velocity_ioctl, - .ndo_vlan_rx_add_vid = velocity_vlan_rx_add_vid, - .ndo_vlan_rx_kill_vid = velocity_vlan_rx_kill_vid, - .ndo_vlan_rx_register = velocity_vlan_rx_register, -}; + return status; +} /** - * velocity_found1 - set up discovered velocity card - * @pdev: PCI device - * @ent: PCI device table entry that matched + * velocity_mii_write - write MII data + * @regs: velocity registers + * @index: MII register index + * @data: 16bit data for the MII register * - * Configure a discovered adapter from scratch. Return a negative - * errno error code on failure paths. + * Perform a single write to an MII 16bit register. Returns zero + * on success or -ETIMEDOUT if the PHY did not respond. */ - -static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent) +static int velocity_mii_write(struct mac_regs __iomem *regs, u8 mii_addr, u16 data) { - static int first = 1; - struct net_device *dev; - int i; - const char *drv_string; - const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data]; - struct velocity_info *vptr; - struct mac_regs __iomem *regs; - int ret = -ENOMEM; + u16 ww; - /* FIXME: this driver, like almost all other ethernet drivers, - * can support more than MAX_UNITS. + /* + * Disable MIICR_MAUTO, so that mii addr can be set normally */ - if (velocity_nics >= MAX_UNITS) { - dev_notice(&pdev->dev, "already found %d NICs.\n", - velocity_nics); - return -ENODEV; - } + safe_disable_mii_autopoll(regs); - dev = alloc_etherdev(sizeof(struct velocity_info)); - if (!dev) { - dev_err(&pdev->dev, "allocate net device failed.\n"); - goto out; + /* MII reg offset */ + writeb(mii_addr, ®s->MIIADR); + /* set MII data */ + writew(data, ®s->MIIDATA); + + /* turn on MIICR_WCMD */ + BYTE_REG_BITS_ON(MIICR_WCMD, ®s->MIICR); + + /* W_MAX_TIMEOUT is the timeout period */ + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + udelay(5); + if (!(readb(®s->MIICR) & MIICR_WCMD)) + break; } + enable_mii_autopoll(regs); - /* Chain it all together */ + if (ww == W_MAX_TIMEOUT) + return -ETIMEDOUT; + return 0; +} - SET_NETDEV_DEV(dev, &pdev->dev); - vptr = netdev_priv(dev); +/** + * set_mii_flow_control - flow control setup + * @vptr: velocity interface + * + * Set up the flow control on this interface according to + * the supplied user/eeprom options. + */ +static void set_mii_flow_control(struct velocity_info *vptr) +{ + /*Enable or Disable PAUSE in ANAR */ + switch (vptr->options.flow_cntl) { + case FLOW_CNTL_TX: + MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); + MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); + break; + case FLOW_CNTL_RX: + MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); + MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); + break; - if (first) { - printk(KERN_INFO "%s Ver. %s\n", - VELOCITY_FULL_DRV_NAM, VELOCITY_VERSION); - printk(KERN_INFO "Copyright (c) 2002, 2003 VIA Networking Technologies, Inc.\n"); - printk(KERN_INFO "Copyright (c) 2004 Red Hat Inc.\n"); - first = 0; - } + case FLOW_CNTL_TX_RX: + MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); + MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); + break; - velocity_init_info(pdev, vptr, info); + case FLOW_CNTL_DISABLE: + MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); + MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); + break; + default: + break; + } +} - vptr->dev = dev; +/** + * mii_set_auto_on - autonegotiate on + * @vptr: velocity + * + * Enable autonegotation on this interface + */ +static void mii_set_auto_on(struct velocity_info *vptr) +{ + if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs)) + MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs); + else + MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); +} - dev->irq = pdev->irq; +static u32 check_connection_type(struct mac_regs __iomem *regs) +{ + u32 status = 0; + u8 PHYSR0; + u16 ANAR; + PHYSR0 = readb(®s->PHYSR0); - ret = pci_enable_device(pdev); - if (ret < 0) - goto err_free_dev; + /* + if (!(PHYSR0 & PHYSR0_LINKGD)) + status|=VELOCITY_LINK_FAIL; + */ - ret = velocity_get_pci_info(vptr, pdev); - if (ret < 0) { - /* error message already printed */ - goto err_disable; - } + if (PHYSR0 & PHYSR0_FDPX) + status |= VELOCITY_DUPLEX_FULL; - ret = pci_request_regions(pdev, VELOCITY_NAME); - if (ret < 0) { - dev_err(&pdev->dev, "No PCI resources.\n"); - goto err_disable; - } + if (PHYSR0 & PHYSR0_SPDG) + status |= VELOCITY_SPEED_1000; + else if (PHYSR0 & PHYSR0_SPD10) + status |= VELOCITY_SPEED_10; + else + status |= VELOCITY_SPEED_100; - regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE); - if (regs == NULL) { - ret = -EIO; - goto err_release_res; + if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) { + velocity_mii_read(regs, MII_REG_ANAR, &ANAR); + if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) + == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) { + if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs)) + status |= VELOCITY_AUTONEG_ENABLE; + } } - vptr->mac_regs = regs; - - mac_wol_reset(regs); + return status; +} - dev->base_addr = vptr->ioaddr; - for (i = 0; i < 6; i++) - dev->dev_addr[i] = readb(®s->PAR[i]); +/** + * velocity_set_media_mode - set media mode + * @mii_status: old MII link state + * + * Check the media link state and configure the flow control + * PHY and also velocity hardware setup accordingly. In particular + * we need to set up CD polling and frame bursting. + */ +static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status) +{ + u32 curr_status; + struct mac_regs __iomem *regs = vptr->mac_regs; - drv_string = dev_driver_string(&pdev->dev); + vptr->mii_status = mii_check_media_mode(vptr->mac_regs); + curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL); - velocity_get_options(&vptr->options, velocity_nics, drv_string); + /* Set mii link status */ + set_mii_flow_control(vptr); /* - * Mask out the options cannot be set to the chip + Check if new status is consisent with current status + if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE) + || (mii_status==curr_status)) { + vptr->mii_status=mii_check_media_mode(vptr->mac_regs); + vptr->mii_status=check_connection_type(vptr->mac_regs); + VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity link no change\n"); + return 0; + } */ - vptr->options.flags &= info->flags; + if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) + MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs); /* - * Enable the chip specified capbilities + * If connection type is AUTO */ + if (mii_status & VELOCITY_AUTONEG_ENABLE) { + VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity is AUTO mode\n"); + /* clear force MAC mode bit */ + BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, ®s->CHIPGCR); + /* set duplex mode of MAC according to duplex mode of MII */ + MII_REG_BITS_ON(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10, MII_REG_ANAR, vptr->mac_regs); + MII_REG_BITS_ON(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs); + MII_REG_BITS_ON(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); - vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL); + /* enable AUTO-NEGO mode */ + mii_set_auto_on(vptr); + } else { + u16 ANAR; + u8 CHIPGCR; - vptr->wol_opts = vptr->options.wol_opts; - vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; + /* + * 1. if it's 3119, disable frame bursting in halfduplex mode + * and enable it in fullduplex mode + * 2. set correct MII/GMII and half/full duplex mode in CHIPGCR + * 3. only enable CD heart beat counter in 10HD mode + */ - vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs); + /* set force MAC mode bit */ + BYTE_REG_BITS_ON(CHIPGCR_FCMODE, ®s->CHIPGCR); - dev->irq = pdev->irq; - dev->netdev_ops = &velocity_netdev_ops; - dev->ethtool_ops = &velocity_ethtool_ops; + CHIPGCR = readb(®s->CHIPGCR); + CHIPGCR &= ~CHIPGCR_FCGMII; - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | - NETIF_F_HW_VLAN_RX; + if (mii_status & VELOCITY_DUPLEX_FULL) { + CHIPGCR |= CHIPGCR_FCFDX; + writeb(CHIPGCR, ®s->CHIPGCR); + VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced full mode\n"); + if (vptr->rev_id < REV_ID_VT3216_A0) + BYTE_REG_BITS_OFF(TCR_TB2BDIS, ®s->TCR); + } else { + CHIPGCR &= ~CHIPGCR_FCFDX; + VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced half mode\n"); + writeb(CHIPGCR, ®s->CHIPGCR); + if (vptr->rev_id < REV_ID_VT3216_A0) + BYTE_REG_BITS_ON(TCR_TB2BDIS, ®s->TCR); + } - if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) - dev->features |= NETIF_F_IP_CSUM; + MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs); - ret = register_netdev(dev); - if (ret < 0) - goto err_iounmap; + if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10)) + BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); + else + BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG); - if (!velocity_get_link(dev)) { - netif_carrier_off(dev); - vptr->mii_status |= VELOCITY_LINK_FAIL; + /* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */ + velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR); + ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)); + if (mii_status & VELOCITY_SPEED_100) { + if (mii_status & VELOCITY_DUPLEX_FULL) + ANAR |= ANAR_TXFD; + else + ANAR |= ANAR_TX; + } else { + if (mii_status & VELOCITY_DUPLEX_FULL) + ANAR |= ANAR_10FD; + else + ANAR |= ANAR_10; + } + velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR); + /* enable AUTO-NEGO mode */ + mii_set_auto_on(vptr); + /* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */ } + /* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */ + /* vptr->mii_status=check_connection_type(vptr->mac_regs); */ + return VELOCITY_LINK_CHANGE; +} - velocity_print_info(vptr); - pci_set_drvdata(pdev, dev); +/** + * velocity_print_link_status - link status reporting + * @vptr: velocity to report on + * + * Turn the link status of the velocity card into a kernel log + * description of the new link state, detailing speed and duplex + * status + */ +static void velocity_print_link_status(struct velocity_info *vptr) +{ - /* and leave the chip powered down */ + if (vptr->mii_status & VELOCITY_LINK_FAIL) { + VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n", vptr->dev->name); + } else if (vptr->options.spd_dpx == SPD_DPX_AUTO) { + VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link auto-negotiation", vptr->dev->name); - pci_set_power_state(pdev, PCI_D3hot); -#ifdef CONFIG_PM - { - unsigned long flags; + if (vptr->mii_status & VELOCITY_SPEED_1000) + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps"); + else if (vptr->mii_status & VELOCITY_SPEED_100) + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps"); + else + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps"); - spin_lock_irqsave(&velocity_dev_list_lock, flags); - list_add(&vptr->list, &velocity_dev_list); - spin_unlock_irqrestore(&velocity_dev_list_lock, flags); + if (vptr->mii_status & VELOCITY_DUPLEX_FULL) + VELOCITY_PRT(MSG_LEVEL_INFO, " full duplex\n"); + else + VELOCITY_PRT(MSG_LEVEL_INFO, " half duplex\n"); + } else { + VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name); + switch (vptr->options.spd_dpx) { + case SPD_DPX_100_HALF: + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n"); + break; + case SPD_DPX_100_FULL: + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps full duplex\n"); + break; + case SPD_DPX_10_HALF: + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps half duplex\n"); + break; + case SPD_DPX_10_FULL: + VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps full duplex\n"); + break; + default: + break; + } } -#endif - velocity_nics++; -out: - return ret; - -err_iounmap: - iounmap(regs); -err_release_res: - pci_release_regions(pdev); -err_disable: - pci_disable_device(pdev); -err_free_dev: - free_netdev(dev); - goto out; } /** - * velocity_print_info - per driver data - * @vptr: velocity + * enable_flow_control_ability - flow control + * @vptr: veloity to configure * - * Print per driver data as the kernel driver finds Velocity - * hardware + * Set up flow control according to the flow control options + * determined by the eeprom/configuration. */ - -static void __devinit velocity_print_info(struct velocity_info *vptr) +static void enable_flow_control_ability(struct velocity_info *vptr) { - struct net_device *dev = vptr->dev; - printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id)); - printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", - dev->name, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); -} + struct mac_regs __iomem *regs = vptr->mac_regs; -/** - * velocity_init_info - init private data - * @pdev: PCI device - * @vptr: Velocity info - * @info: Board type - * - * Set up the initial velocity_info struct for the device that has been - * discovered. - */ + switch (vptr->options.flow_cntl) { -static void __devinit velocity_init_info(struct pci_dev *pdev, - struct velocity_info *vptr, - const struct velocity_info_tbl *info) -{ - memset(vptr, 0, sizeof(struct velocity_info)); + case FLOW_CNTL_DEFAULT: + if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, ®s->PHYSR0)) + writel(CR0_FDXRFCEN, ®s->CR0Set); + else + writel(CR0_FDXRFCEN, ®s->CR0Clr); + + if (BYTE_REG_BITS_IS_ON(PHYSR0_TXFLC, ®s->PHYSR0)) + writel(CR0_FDXTFCEN, ®s->CR0Set); + else + writel(CR0_FDXTFCEN, ®s->CR0Clr); + break; + + case FLOW_CNTL_TX: + writel(CR0_FDXTFCEN, ®s->CR0Set); + writel(CR0_FDXRFCEN, ®s->CR0Clr); + break; + + case FLOW_CNTL_RX: + writel(CR0_FDXRFCEN, ®s->CR0Set); + writel(CR0_FDXTFCEN, ®s->CR0Clr); + break; + + case FLOW_CNTL_TX_RX: + writel(CR0_FDXTFCEN, ®s->CR0Set); + writel(CR0_FDXRFCEN, ®s->CR0Set); + break; + + case FLOW_CNTL_DISABLE: + writel(CR0_FDXRFCEN, ®s->CR0Clr); + writel(CR0_FDXTFCEN, ®s->CR0Clr); + break; + + default: + break; + } - vptr->pdev = pdev; - vptr->chip_id = info->chip_id; - vptr->tx.numq = info->txqueue; - vptr->multicast_limit = MCAM_SIZE; - spin_lock_init(&vptr->lock); - INIT_LIST_HEAD(&vptr->list); } /** - * velocity_get_pci_info - retrieve PCI info for device - * @vptr: velocity device - * @pdev: PCI device it matches + * velocity_soft_reset - soft reset + * @vptr: velocity to reset * - * Retrieve the PCI configuration space data that interests us from - * the kernel PCI layer + * Kick off a soft reset of the velocity adapter and then poll + * until the reset sequence has completed before returning. */ - -static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev) +static int velocity_soft_reset(struct velocity_info *vptr) { - vptr->rev_id = pdev->revision; - - pci_set_master(pdev); - - vptr->ioaddr = pci_resource_start(pdev, 0); - vptr->memaddr = pci_resource_start(pdev, 1); + struct mac_regs __iomem *regs = vptr->mac_regs; + int i = 0; - if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) { - dev_err(&pdev->dev, - "region #0 is not an I/O resource, aborting.\n"); - return -EINVAL; - } + writel(CR0_SFRST, ®s->CR0Set); - if ((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) { - dev_err(&pdev->dev, - "region #1 is an I/O resource, aborting.\n"); - return -EINVAL; + for (i = 0; i < W_MAX_TIMEOUT; i++) { + udelay(5); + if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, ®s->CR0Set)) + break; } - if (pci_resource_len(pdev, 1) < VELOCITY_IO_SIZE) { - dev_err(&pdev->dev, "region #1 is too small.\n"); - return -EINVAL; + if (i == W_MAX_TIMEOUT) { + writel(CR0_FORSRST, ®s->CR0Set); + /* FIXME: PCI POSTING */ + /* delay 2ms */ + mdelay(2); } - vptr->pdev = pdev; - return 0; } /** - * velocity_init_dma_rings - set up DMA rings - * @vptr: Velocity to set up + * velocity_set_multi - filter list change callback + * @dev: network device * - * Allocate PCI mapped DMA rings for the receive and transmit layer - * to use. - */ - -static int velocity_init_dma_rings(struct velocity_info *vptr) -{ - struct velocity_opt *opt = &vptr->options; - const unsigned int rx_ring_size = opt->numrx * sizeof(struct rx_desc); - const unsigned int tx_ring_size = opt->numtx * sizeof(struct tx_desc); - struct pci_dev *pdev = vptr->pdev; - dma_addr_t pool_dma; - void *pool; - unsigned int i; - - /* - * Allocate all RD/TD rings a single pool. - * - * pci_alloc_consistent() fulfills the requirement for 64 bytes - * alignment - */ - pool = pci_alloc_consistent(pdev, tx_ring_size * vptr->tx.numq + - rx_ring_size, &pool_dma); - if (!pool) { - dev_err(&pdev->dev, "%s : DMA memory allocation failed.\n", - vptr->dev->name); - return -ENOMEM; - } - - vptr->rx.ring = pool; - vptr->rx.pool_dma = pool_dma; - - pool += rx_ring_size; - pool_dma += rx_ring_size; - - for (i = 0; i < vptr->tx.numq; i++) { - vptr->tx.rings[i] = pool; - vptr->tx.pool_dma[i] = pool_dma; - pool += tx_ring_size; - pool_dma += tx_ring_size; - } - - return 0; -} - -/** - * velocity_free_dma_rings - free PCI ring pointers - * @vptr: Velocity to free from - * - * Clean up the PCI ring buffers allocated to this velocity. + * Called by the network layer when the filter lists need to change + * for a velocity adapter. Reload the CAMs with the new address + * filter ruleset. */ - -static void velocity_free_dma_rings(struct velocity_info *vptr) -{ - const int size = vptr->options.numrx * sizeof(struct rx_desc) + - vptr->options.numtx * sizeof(struct tx_desc) * vptr->tx.numq; - - pci_free_consistent(vptr->pdev, size, vptr->rx.ring, vptr->rx.pool_dma); -} - -static void velocity_give_many_rx_descs(struct velocity_info *vptr) +static void velocity_set_multi(struct net_device *dev) { + struct velocity_info *vptr = netdev_priv(dev); struct mac_regs __iomem *regs = vptr->mac_regs; - int avail, dirty, unusable; - - /* - * RD number must be equal to 4X per hardware spec - * (programming guide rev 1.20, p.13) - */ - if (vptr->rx.filled < 4) - return; - - wmb(); - - unusable = vptr->rx.filled & 0x0003; - dirty = vptr->rx.dirty - unusable; - for (avail = vptr->rx.filled & 0xfffc; avail; avail--) { - dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1; - vptr->rx.ring[dirty].rdesc0.len |= OWNED_BY_NIC; - } - - writew(vptr->rx.filled & 0xfffc, ®s->RBRDU); - vptr->rx.filled = unusable; -} - -static int velocity_rx_refill(struct velocity_info *vptr) -{ - int dirty = vptr->rx.dirty, done = 0; - - do { - struct rx_desc *rd = vptr->rx.ring + dirty; + u8 rx_mode; + int i; + struct dev_mc_list *mclist; - /* Fine for an all zero Rx desc at init time as well */ - if (rd->rdesc0.len & OWNED_BY_NIC) - break; + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + writel(0xffffffff, ®s->MARCAM[0]); + writel(0xffffffff, ®s->MARCAM[4]); + rx_mode = (RCR_AM | RCR_AB | RCR_PROM); + } else if ((dev->mc_count > vptr->multicast_limit) + || (dev->flags & IFF_ALLMULTI)) { + writel(0xffffffff, ®s->MARCAM[0]); + writel(0xffffffff, ®s->MARCAM[4]); + rx_mode = (RCR_AM | RCR_AB); + } else { + int offset = MCAM_SIZE - vptr->multicast_limit; + mac_get_cam_mask(regs, vptr->mCAMmask); - if (!vptr->rx.info[dirty].skb) { - if (velocity_alloc_rx_buf(vptr, dirty) < 0) - break; + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { + mac_set_cam(regs, i + offset, mclist->dmi_addr); + vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7); } - done++; - dirty = (dirty < vptr->options.numrx - 1) ? dirty + 1 : 0; - } while (dirty != vptr->rx.curr); - if (done) { - vptr->rx.dirty = dirty; - vptr->rx.filled += done; + mac_set_cam_mask(regs, vptr->mCAMmask); + rx_mode = RCR_AM | RCR_AB | RCR_AP; } + if (dev->mtu > 1500) + rx_mode |= RCR_AL; - return done; -} + BYTE_REG_BITS_ON(rx_mode, ®s->RCR); -static void velocity_set_rxbufsize(struct velocity_info *vptr, int mtu) -{ - vptr->rx.buf_sz = (mtu <= ETH_DATA_LEN) ? PKT_BUF_SZ : mtu + 32; } -/** - * velocity_init_rd_ring - set up receive ring - * @vptr: velocity to configure - * - * Allocate and set up the receive buffers for each ring slot and - * assign them to the network adapter. +/* + * MII access , media link mode setting functions */ -static int velocity_init_rd_ring(struct velocity_info *vptr) -{ - int ret = -ENOMEM; - - vptr->rx.info = kcalloc(vptr->options.numrx, - sizeof(struct velocity_rd_info), GFP_KERNEL); - if (!vptr->rx.info) - goto out; - - velocity_init_rx_ring_indexes(vptr); - - if (velocity_rx_refill(vptr) != vptr->options.numrx) { - VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR - "%s: failed to allocate RX buffer.\n", vptr->dev->name); - velocity_free_rd_ring(vptr); - goto out; - } - - ret = 0; -out: - return ret; -} - /** - * velocity_free_rd_ring - free receive ring - * @vptr: velocity to clean up + * mii_init - set up MII + * @vptr: velocity adapter + * @mii_status: links tatus * - * Free the receive buffers for each ring slot and any - * attached socket buffers that need to go away. + * Set up the PHY for the current link state. */ - -static void velocity_free_rd_ring(struct velocity_info *vptr) +static void mii_init(struct velocity_info *vptr, u32 mii_status) { - int i; - - if (vptr->rx.info == NULL) - return; - - for (i = 0; i < vptr->options.numrx; i++) { - struct velocity_rd_info *rd_info = &(vptr->rx.info[i]); - struct rx_desc *rd = vptr->rx.ring + i; - - memset(rd, 0, sizeof(*rd)); + u16 BMCR; - if (!rd_info->skb) - continue; - pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx.buf_sz, - PCI_DMA_FROMDEVICE); - rd_info->skb_dma = 0; + switch (PHYID_GET_PHY_ID(vptr->phy_id)) { + case PHYID_CICADA_CS8201: + /* + * Reset to hardware default + */ + MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs); + /* + * Turn on ECHODIS bit in NWay-forced full mode and turn it + * off it in NWay-forced half mode for NWay-forced v.s. + * legacy-forced issue. + */ + if (vptr->mii_status & VELOCITY_DUPLEX_FULL) + MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs); + else + MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs); + /* + * Turn on Link/Activity LED enable bit for CIS8201 + */ + MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, vptr->mac_regs); + break; + case PHYID_VT3216_32BIT: + case PHYID_VT3216_64BIT: + /* + * Reset to hardware default + */ + MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs); + /* + * Turn on ECHODIS bit in NWay-forced full mode and turn it + * off it in NWay-forced half mode for NWay-forced v.s. + * legacy-forced issue + */ + if (vptr->mii_status & VELOCITY_DUPLEX_FULL) + MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs); + else + MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs); + break; - dev_kfree_skb(rd_info->skb); - rd_info->skb = NULL; + case PHYID_MARVELL_1000: + case PHYID_MARVELL_1000S: + /* + * Assert CRS on Transmit + */ + MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs); + /* + * Reset to hardware default + */ + MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs); + break; + default: + ; + } + velocity_mii_read(vptr->mac_regs, MII_REG_BMCR, &BMCR); + if (BMCR & BMCR_ISO) { + BMCR &= ~BMCR_ISO; + velocity_mii_write(vptr->mac_regs, MII_REG_BMCR, BMCR); } - - kfree(vptr->rx.info); - vptr->rx.info = NULL; } + /** - * velocity_init_td_ring - set up transmit ring - * @vptr: velocity + * velocity_init_registers - initialise MAC registers + * @vptr: velocity to init + * @type: type of initialisation (hot or cold) * - * Set up the transmit ring and chain the ring pointers together. - * Returns zero on success or a negative posix errno code for - * failure. + * Initialise the MAC on a reset or on first set up on the + * hardware. */ - -static int velocity_init_td_ring(struct velocity_info *vptr) +static void velocity_init_registers(struct velocity_info *vptr, + enum velocity_init_type type) { - dma_addr_t curr; - int j; - - /* Init the TD ring entries */ - for (j = 0; j < vptr->tx.numq; j++) { - curr = vptr->tx.pool_dma[j]; - - vptr->tx.infos[j] = kcalloc(vptr->options.numtx, - sizeof(struct velocity_td_info), - GFP_KERNEL); - if (!vptr->tx.infos[j]) { - while (--j >= 0) - kfree(vptr->tx.infos[j]); - return -ENOMEM; - } + struct mac_regs __iomem *regs = vptr->mac_regs; + int i, mii_status; - vptr->tx.tail[j] = vptr->tx.curr[j] = vptr->tx.used[j] = 0; - } - return 0; -} + mac_wol_reset(regs); -/* - * FIXME: could we merge this with velocity_free_tx_buf ? - */ + switch (type) { + case VELOCITY_INIT_RESET: + case VELOCITY_INIT_WOL: -static void velocity_free_td_ring_entry(struct velocity_info *vptr, - int q, int n) -{ - struct velocity_td_info *td_info = &(vptr->tx.infos[q][n]); - int i; + netif_stop_queue(vptr->dev); - if (td_info == NULL) - return; + /* + * Reset RX to prevent RX pointer not on the 4X location + */ + velocity_rx_reset(vptr); + mac_rx_queue_run(regs); + mac_rx_queue_wake(regs); - if (td_info->skb) { - for (i = 0; i < td_info->nskb_dma; i++) { - if (td_info->skb_dma[i]) { - pci_unmap_single(vptr->pdev, td_info->skb_dma[i], - td_info->skb->len, PCI_DMA_TODEVICE); - td_info->skb_dma[i] = 0; - } + mii_status = velocity_get_opt_media_mode(vptr); + if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) { + velocity_print_link_status(vptr); + if (!(vptr->mii_status & VELOCITY_LINK_FAIL)) + netif_wake_queue(vptr->dev); } - dev_kfree_skb(td_info->skb); - td_info->skb = NULL; - } -} - -/** - * velocity_free_td_ring - free td ring - * @vptr: velocity - * - * Free up the transmit ring for this particular velocity adapter. - * We free the ring contents but not the ring itself. - */ - -static void velocity_free_td_ring(struct velocity_info *vptr) -{ - int i, j; - - for (j = 0; j < vptr->tx.numq; j++) { - if (vptr->tx.infos[j] == NULL) - continue; - for (i = 0; i < vptr->options.numtx; i++) - velocity_free_td_ring_entry(vptr, j, i); - kfree(vptr->tx.infos[j]); - vptr->tx.infos[j] = NULL; - } -} + enable_flow_control_ability(vptr); -/** - * velocity_rx_srv - service RX interrupt - * @vptr: velocity - * @status: adapter status (unused) - * - * Walk the receive ring of the velocity adapter and remove - * any received packets from the receive queue. Hand the ring - * slots back to the adapter for reuse. - */ + mac_clear_isr(regs); + writel(CR0_STOP, ®s->CR0Clr); + writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), + ®s->CR0Set); -static int velocity_rx_srv(struct velocity_info *vptr, int status) -{ - struct net_device_stats *stats = &vptr->dev->stats; - int rd_curr = vptr->rx.curr; - int works = 0; + break; - do { - struct rx_desc *rd = vptr->rx.ring + rd_curr; + case VELOCITY_INIT_COLD: + default: + /* + * Do reset + */ + velocity_soft_reset(vptr); + mdelay(5); - if (!vptr->rx.info[rd_curr].skb) - break; + mac_eeprom_reload(regs); + for (i = 0; i < 6; i++) + writeb(vptr->dev->dev_addr[i], &(regs->PAR[i])); - if (rd->rdesc0.len & OWNED_BY_NIC) - break; + /* + * clear Pre_ACPI bit. + */ + BYTE_REG_BITS_OFF(CFGA_PACPI, &(regs->CFGA)); + mac_set_rx_thresh(regs, vptr->options.rx_thresh); + mac_set_dma_length(regs, vptr->options.DMA_length); - rmb(); + writeb(WOLCFG_SAM | WOLCFG_SAB, ®s->WOLCFGSet); + /* + * Back off algorithm use original IEEE standard + */ + BYTE_REG_BITS_SET(CFGB_OFSET, (CFGB_CRANDOM | CFGB_CAP | CFGB_MBA | CFGB_BAKOPT), ®s->CFGB); /* - * Don't drop CE or RL error frame although RXOK is off + * Init CAM filter */ - if (rd->rdesc0.RSR & (RSR_RXOK | RSR_CE | RSR_RL)) { - if (velocity_receive_frame(vptr, rd_curr) < 0) - stats->rx_dropped++; - } else { - if (rd->rdesc0.RSR & RSR_CRC) - stats->rx_crc_errors++; - if (rd->rdesc0.RSR & RSR_FAE) - stats->rx_frame_errors++; + velocity_init_cam_filter(vptr); - stats->rx_dropped++; - } + /* + * Set packet filter: Receive directed and broadcast address + */ + velocity_set_multi(vptr->dev); - rd->size |= RX_INTEN; + /* + * Enable MII auto-polling + */ + enable_mii_autopoll(regs); - rd_curr++; - if (rd_curr >= vptr->options.numrx) - rd_curr = 0; - } while (++works <= 15); + vptr->int_mask = INT_MASK_DEF; - vptr->rx.curr = rd_curr; + writel(vptr->rx.pool_dma, ®s->RDBaseLo); + writew(vptr->options.numrx - 1, ®s->RDCSize); + mac_rx_queue_run(regs); + mac_rx_queue_wake(regs); - if ((works > 0) && (velocity_rx_refill(vptr) > 0)) - velocity_give_many_rx_descs(vptr); + writew(vptr->options.numtx - 1, ®s->TDCSize); - VAR_USED(stats); - return works; -} + for (i = 0; i < vptr->tx.numq; i++) { + writel(vptr->tx.pool_dma[i], ®s->TDBaseLo[i]); + mac_tx_queue_run(regs, i); + } -/** - * velocity_rx_csum - checksum process - * @rd: receive packet descriptor - * @skb: network layer packet buffer - * - * Process the status bits for the received packet and determine - * if the checksum was computed and verified by the hardware - */ + init_flow_control_register(vptr); -static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb) -{ - skb->ip_summed = CHECKSUM_NONE; + writel(CR0_STOP, ®s->CR0Clr); + writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), ®s->CR0Set); - if (rd->rdesc1.CSM & CSM_IPKT) { - if (rd->rdesc1.CSM & CSM_IPOK) { - if ((rd->rdesc1.CSM & CSM_TCPKT) || - (rd->rdesc1.CSM & CSM_UDPKT)) { - if (!(rd->rdesc1.CSM & CSM_TUPOK)) - return; - } - skb->ip_summed = CHECKSUM_UNNECESSARY; - } - } -} + mii_status = velocity_get_opt_media_mode(vptr); + netif_stop_queue(vptr->dev); -/** - * velocity_rx_copy - in place Rx copy for small packets - * @rx_skb: network layer packet buffer candidate - * @pkt_size: received data size - * @rd: receive packet descriptor - * @dev: network device - * - * Replace the current skb that is scheduled for Rx processing by a - * shorter, immediatly allocated skb, if the received packet is small - * enough. This function returns a negative value if the received - * packet is too big or if memory is exhausted. - */ -static int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size, - struct velocity_info *vptr) -{ - int ret = -1; - if (pkt_size < rx_copybreak) { - struct sk_buff *new_skb; + mii_init(vptr, mii_status); - new_skb = netdev_alloc_skb(vptr->dev, pkt_size + 2); - if (new_skb) { - new_skb->ip_summed = rx_skb[0]->ip_summed; - skb_reserve(new_skb, 2); - skb_copy_from_linear_data(*rx_skb, new_skb->data, pkt_size); - *rx_skb = new_skb; - ret = 0; + if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) { + velocity_print_link_status(vptr); + if (!(vptr->mii_status & VELOCITY_LINK_FAIL)) + netif_wake_queue(vptr->dev); } + enable_flow_control_ability(vptr); + mac_hw_mibs_init(regs); + mac_write_int_mask(vptr->int_mask, regs); + mac_clear_isr(regs); + } - return ret; } -/** - * velocity_iph_realign - IP header alignment - * @vptr: velocity we are handling - * @skb: network layer packet buffer - * @pkt_size: received data size - * - * Align IP header on a 2 bytes boundary. This behavior can be - * configured by the user. - */ -static inline void velocity_iph_realign(struct velocity_info *vptr, - struct sk_buff *skb, int pkt_size) +static void velocity_give_many_rx_descs(struct velocity_info *vptr) { - if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) { - memmove(skb->data + 2, skb->data, pkt_size); - skb_reserve(skb, 2); + struct mac_regs __iomem *regs = vptr->mac_regs; + int avail, dirty, unusable; + + /* + * RD number must be equal to 4X per hardware spec + * (programming guide rev 1.20, p.13) + */ + if (vptr->rx.filled < 4) + return; + + wmb(); + + unusable = vptr->rx.filled & 0x0003; + dirty = vptr->rx.dirty - unusable; + for (avail = vptr->rx.filled & 0xfffc; avail; avail--) { + dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1; + vptr->rx.ring[dirty].rdesc0.len |= OWNED_BY_NIC; } + + writew(vptr->rx.filled & 0xfffc, ®s->RBRDU); + vptr->rx.filled = unusable; } /** - * velocity_receive_frame - received packet processor - * @vptr: velocity we are handling - * @idx: ring index + * velocity_init_dma_rings - set up DMA rings + * @vptr: Velocity to set up * - * A packet has arrived. We process the packet and if appropriate - * pass the frame up the network stack + * Allocate PCI mapped DMA rings for the receive and transmit layer + * to use. */ - -static int velocity_receive_frame(struct velocity_info *vptr, int idx) +static int velocity_init_dma_rings(struct velocity_info *vptr) { - void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int); - struct net_device_stats *stats = &vptr->dev->stats; - struct velocity_rd_info *rd_info = &(vptr->rx.info[idx]); - struct rx_desc *rd = &(vptr->rx.ring[idx]); - int pkt_len = le16_to_cpu(rd->rdesc0.len) & 0x3fff; - struct sk_buff *skb; - - if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) { - VELOCITY_PRT(MSG_LEVEL_VERBOSE, KERN_ERR " %s : the received frame span multple RDs.\n", vptr->dev->name); - stats->rx_length_errors++; - return -EINVAL; - } - - if (rd->rdesc0.RSR & RSR_MAR) - stats->multicast++; - - skb = rd_info->skb; - - pci_dma_sync_single_for_cpu(vptr->pdev, rd_info->skb_dma, - vptr->rx.buf_sz, PCI_DMA_FROMDEVICE); + struct velocity_opt *opt = &vptr->options; + const unsigned int rx_ring_size = opt->numrx * sizeof(struct rx_desc); + const unsigned int tx_ring_size = opt->numtx * sizeof(struct tx_desc); + struct pci_dev *pdev = vptr->pdev; + dma_addr_t pool_dma; + void *pool; + unsigned int i; /* - * Drop frame not meeting IEEE 802.3 + * Allocate all RD/TD rings a single pool. + * + * pci_alloc_consistent() fulfills the requirement for 64 bytes + * alignment */ - - if (vptr->flags & VELOCITY_FLAGS_VAL_PKT_LEN) { - if (rd->rdesc0.RSR & RSR_RL) { - stats->rx_length_errors++; - return -EINVAL; - } - } - - pci_action = pci_dma_sync_single_for_device; - - velocity_rx_csum(rd, skb); - - if (velocity_rx_copy(&skb, pkt_len, vptr) < 0) { - velocity_iph_realign(vptr, skb, pkt_len); - pci_action = pci_unmap_single; - rd_info->skb = NULL; + pool = pci_alloc_consistent(pdev, tx_ring_size * vptr->tx.numq + + rx_ring_size, &pool_dma); + if (!pool) { + dev_err(&pdev->dev, "%s : DMA memory allocation failed.\n", + vptr->dev->name); + return -ENOMEM; } - pci_action(vptr->pdev, rd_info->skb_dma, vptr->rx.buf_sz, - PCI_DMA_FROMDEVICE); - - skb_put(skb, pkt_len - 4); - skb->protocol = eth_type_trans(skb, vptr->dev); + vptr->rx.ring = pool; + vptr->rx.pool_dma = pool_dma; - if (vptr->vlgrp && (rd->rdesc0.RSR & RSR_DETAG)) { - vlan_hwaccel_rx(skb, vptr->vlgrp, - swab16(le16_to_cpu(rd->rdesc1.PQTAG))); - } else - netif_rx(skb); + pool += rx_ring_size; + pool_dma += rx_ring_size; - stats->rx_bytes += pkt_len; + for (i = 0; i < vptr->tx.numq; i++) { + vptr->tx.rings[i] = pool; + vptr->tx.pool_dma[i] = pool_dma; + pool += tx_ring_size; + pool_dma += tx_ring_size; + } return 0; } +static void velocity_set_rxbufsize(struct velocity_info *vptr, int mtu) +{ + vptr->rx.buf_sz = (mtu <= ETH_DATA_LEN) ? PKT_BUF_SZ : mtu + 32; +} + /** * velocity_alloc_rx_buf - allocate aligned receive buffer * @vptr: velocity @@ -1582,7 +1470,6 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx) * requires *64* byte alignment of the buffer which makes life * less fun than would be ideal. */ - static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx) { struct rx_desc *rd = &(vptr->rx.ring[idx]); @@ -1611,243 +1498,146 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx) return 0; } -/** - * tx_srv - transmit interrupt service - * @vptr; Velocity - * @status: - * - * Scan the queues looking for transmitted packets that - * we can complete and clean up. Update any statistics as - * necessary/ - */ -static int velocity_tx_srv(struct velocity_info *vptr, u32 status) +static int velocity_rx_refill(struct velocity_info *vptr) { - struct tx_desc *td; - int qnum; - int full = 0; - int idx; - int works = 0; - struct velocity_td_info *tdinfo; - struct net_device_stats *stats = &vptr->dev->stats; - - for (qnum = 0; qnum < vptr->tx.numq; qnum++) { - for (idx = vptr->tx.tail[qnum]; vptr->tx.used[qnum] > 0; - idx = (idx + 1) % vptr->options.numtx) { + int dirty = vptr->rx.dirty, done = 0; - /* - * Get Tx Descriptor - */ - td = &(vptr->tx.rings[qnum][idx]); - tdinfo = &(vptr->tx.infos[qnum][idx]); + do { + struct rx_desc *rd = vptr->rx.ring + dirty; - if (td->tdesc0.len & OWNED_BY_NIC) - break; + /* Fine for an all zero Rx desc at init time as well */ + if (rd->rdesc0.len & OWNED_BY_NIC) + break; - if ((works++ > 15)) + if (!vptr->rx.info[dirty].skb) { + if (velocity_alloc_rx_buf(vptr, dirty) < 0) break; - - if (td->tdesc0.TSR & TSR0_TERR) { - stats->tx_errors++; - stats->tx_dropped++; - if (td->tdesc0.TSR & TSR0_CDH) - stats->tx_heartbeat_errors++; - if (td->tdesc0.TSR & TSR0_CRS) - stats->tx_carrier_errors++; - if (td->tdesc0.TSR & TSR0_ABT) - stats->tx_aborted_errors++; - if (td->tdesc0.TSR & TSR0_OWC) - stats->tx_window_errors++; - } else { - stats->tx_packets++; - stats->tx_bytes += tdinfo->skb->len; - } - velocity_free_tx_buf(vptr, tdinfo); - vptr->tx.used[qnum]--; } - vptr->tx.tail[qnum] = idx; + done++; + dirty = (dirty < vptr->options.numrx - 1) ? dirty + 1 : 0; + } while (dirty != vptr->rx.curr); - if (AVAIL_TD(vptr, qnum) < 1) - full = 1; - } - /* - * Look to see if we should kick the transmit network - * layer for more work. - */ - if (netif_queue_stopped(vptr->dev) && (full == 0) - && (!(vptr->mii_status & VELOCITY_LINK_FAIL))) { - netif_wake_queue(vptr->dev); + if (done) { + vptr->rx.dirty = dirty; + vptr->rx.filled += done; } - return works; + + return done; } /** - * velocity_print_link_status - link status reporting - * @vptr: velocity to report on + * velocity_free_rd_ring - free receive ring + * @vptr: velocity to clean up * - * Turn the link status of the velocity card into a kernel log - * description of the new link state, detailing speed and duplex - * status + * Free the receive buffers for each ring slot and any + * attached socket buffers that need to go away. */ - -static void velocity_print_link_status(struct velocity_info *vptr) +static void velocity_free_rd_ring(struct velocity_info *vptr) { + int i; - if (vptr->mii_status & VELOCITY_LINK_FAIL) { - VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n", vptr->dev->name); - } else if (vptr->options.spd_dpx == SPD_DPX_AUTO) { - VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link auto-negotiation", vptr->dev->name); - - if (vptr->mii_status & VELOCITY_SPEED_1000) - VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps"); - else if (vptr->mii_status & VELOCITY_SPEED_100) - VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps"); - else - VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps"); - - if (vptr->mii_status & VELOCITY_DUPLEX_FULL) - VELOCITY_PRT(MSG_LEVEL_INFO, " full duplex\n"); - else - VELOCITY_PRT(MSG_LEVEL_INFO, " half duplex\n"); - } else { - VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name); - switch (vptr->options.spd_dpx) { - case SPD_DPX_100_HALF: - VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n"); - break; - case SPD_DPX_100_FULL: - VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps full duplex\n"); - break; - case SPD_DPX_10_HALF: - VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps half duplex\n"); - break; - case SPD_DPX_10_FULL: - VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps full duplex\n"); - break; - default: - break; - } - } -} - -/** - * velocity_error - handle error from controller - * @vptr: velocity - * @status: card status - * - * Process an error report from the hardware and attempt to recover - * the card itself. At the moment we cannot recover from some - * theoretically impossible errors but this could be fixed using - * the pci_device_failed logic to bounce the hardware - * - */ + if (vptr->rx.info == NULL) + return; -static void velocity_error(struct velocity_info *vptr, int status) -{ + for (i = 0; i < vptr->options.numrx; i++) { + struct velocity_rd_info *rd_info = &(vptr->rx.info[i]); + struct rx_desc *rd = vptr->rx.ring + i; - if (status & ISR_TXSTLI) { - struct mac_regs __iomem *regs = vptr->mac_regs; + memset(rd, 0, sizeof(*rd)); - printk(KERN_ERR "TD structure error TDindex=%hx\n", readw(®s->TDIdx[0])); - BYTE_REG_BITS_ON(TXESR_TDSTR, ®s->TXESR); - writew(TRDCSR_RUN, ®s->TDCSRClr); - netif_stop_queue(vptr->dev); + if (!rd_info->skb) + continue; + pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx.buf_sz, + PCI_DMA_FROMDEVICE); + rd_info->skb_dma = 0; - /* FIXME: port over the pci_device_failed code and use it - here */ + dev_kfree_skb(rd_info->skb); + rd_info->skb = NULL; } - if (status & ISR_SRCI) { - struct mac_regs __iomem *regs = vptr->mac_regs; - int linked; - - if (vptr->options.spd_dpx == SPD_DPX_AUTO) { - vptr->mii_status = check_connection_type(regs); + kfree(vptr->rx.info); + vptr->rx.info = NULL; +} - /* - * If it is a 3119, disable frame bursting in - * halfduplex mode and enable it in fullduplex - * mode - */ - if (vptr->rev_id < REV_ID_VT3216_A0) { - if (vptr->mii_status | VELOCITY_DUPLEX_FULL) - BYTE_REG_BITS_ON(TCR_TB2BDIS, ®s->TCR); - else - BYTE_REG_BITS_OFF(TCR_TB2BDIS, ®s->TCR); - } - /* - * Only enable CD heart beat counter in 10HD mode - */ - if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10)) - BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); - else - BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG); - } - /* - * Get link status from PHYSR0 - */ - linked = readb(®s->PHYSR0) & PHYSR0_LINKGD; - if (linked) { - vptr->mii_status &= ~VELOCITY_LINK_FAIL; - netif_carrier_on(vptr->dev); - } else { - vptr->mii_status |= VELOCITY_LINK_FAIL; - netif_carrier_off(vptr->dev); - } - velocity_print_link_status(vptr); - enable_flow_control_ability(vptr); +/** + * velocity_init_rd_ring - set up receive ring + * @vptr: velocity to configure + * + * Allocate and set up the receive buffers for each ring slot and + * assign them to the network adapter. + */ +static int velocity_init_rd_ring(struct velocity_info *vptr) +{ + int ret = -ENOMEM; - /* - * Re-enable auto-polling because SRCI will disable - * auto-polling - */ + vptr->rx.info = kcalloc(vptr->options.numrx, + sizeof(struct velocity_rd_info), GFP_KERNEL); + if (!vptr->rx.info) + goto out; - enable_mii_autopoll(regs); + velocity_init_rx_ring_indexes(vptr); - if (vptr->mii_status & VELOCITY_LINK_FAIL) - netif_stop_queue(vptr->dev); - else - netif_wake_queue(vptr->dev); + if (velocity_rx_refill(vptr) != vptr->options.numrx) { + VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR + "%s: failed to allocate RX buffer.\n", vptr->dev->name); + velocity_free_rd_ring(vptr); + goto out; + } - }; - if (status & ISR_MIBFI) - velocity_update_hw_mibs(vptr); - if (status & ISR_LSTEI) - mac_rx_queue_wake(vptr->mac_regs); + ret = 0; +out: + return ret; } /** - * velocity_free_tx_buf - free transmit buffer - * @vptr: velocity - * @tdinfo: buffer + * velocity_init_td_ring - set up transmit ring + * @vptr: velocity * - * Release an transmit buffer. If the buffer was preallocated then - * recycle it, if not then unmap the buffer. + * Set up the transmit ring and chain the ring pointers together. + * Returns zero on success or a negative posix errno code for + * failure. */ - -static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo) +static int velocity_init_td_ring(struct velocity_info *vptr) { - struct sk_buff *skb = tdinfo->skb; - int i; - int pktlen; + dma_addr_t curr; + int j; - /* - * Don't unmap the pre-allocated tx_bufs - */ - if (tdinfo->skb_dma) { + /* Init the TD ring entries */ + for (j = 0; j < vptr->tx.numq; j++) { + curr = vptr->tx.pool_dma[j]; - pktlen = max_t(unsigned int, skb->len, ETH_ZLEN); - for (i = 0; i < tdinfo->nskb_dma; i++) { - pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], pktlen, PCI_DMA_TODEVICE); - tdinfo->skb_dma[i] = 0; + vptr->tx.infos[j] = kcalloc(vptr->options.numtx, + sizeof(struct velocity_td_info), + GFP_KERNEL); + if (!vptr->tx.infos[j]) { + while (--j >= 0) + kfree(vptr->tx.infos[j]); + return -ENOMEM; } + + vptr->tx.tail[j] = vptr->tx.curr[j] = vptr->tx.used[j] = 0; } - dev_kfree_skb_irq(skb); - tdinfo->skb = NULL; + return 0; +} + +/** + * velocity_free_dma_rings - free PCI ring pointers + * @vptr: Velocity to free from + * + * Clean up the PCI ring buffers allocated to this velocity. + */ +static void velocity_free_dma_rings(struct velocity_info *vptr) +{ + const int size = vptr->options.numrx * sizeof(struct rx_desc) + + vptr->options.numtx * sizeof(struct tx_desc) * vptr->tx.numq; + + pci_free_consistent(vptr->pdev, size, vptr->rx.ring, vptr->rx.pool_dma); } + static int velocity_init_rings(struct velocity_info *vptr, int mtu) { int ret; @@ -1875,1138 +1665,979 @@ err_free_dma_rings_0: goto out; } -static void velocity_free_rings(struct velocity_info *vptr) -{ - velocity_free_td_ring(vptr); - velocity_free_rd_ring(vptr); - velocity_free_dma_rings(vptr); -} - /** - * velocity_open - interface activation callback - * @dev: network layer device to open - * - * Called when the network layer brings the interface up. Returns - * a negative posix error code on failure, or zero on success. + * velocity_free_tx_buf - free transmit buffer + * @vptr: velocity + * @tdinfo: buffer * - * All the ring allocation and set up is done on open for this - * adapter to minimise memory usage when inactive + * Release an transmit buffer. If the buffer was preallocated then + * recycle it, if not then unmap the buffer. */ - -static int velocity_open(struct net_device *dev) +static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo) { - struct velocity_info *vptr = netdev_priv(dev); - int ret; - - ret = velocity_init_rings(vptr, dev->mtu); - if (ret < 0) - goto out; - - /* Ensure chip is running */ - pci_set_power_state(vptr->pdev, PCI_D0); - - velocity_give_many_rx_descs(vptr); + struct sk_buff *skb = tdinfo->skb; + int i; + int pktlen; - velocity_init_registers(vptr, VELOCITY_INIT_COLD); + /* + * Don't unmap the pre-allocated tx_bufs + */ + if (tdinfo->skb_dma) { - ret = request_irq(vptr->pdev->irq, &velocity_intr, IRQF_SHARED, - dev->name, dev); - if (ret < 0) { - /* Power down the chip */ - pci_set_power_state(vptr->pdev, PCI_D3hot); - velocity_free_rings(vptr); - goto out; + pktlen = max_t(unsigned int, skb->len, ETH_ZLEN); + for (i = 0; i < tdinfo->nskb_dma; i++) { + pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], pktlen, PCI_DMA_TODEVICE); + tdinfo->skb_dma[i] = 0; + } } - - mac_enable_int(vptr->mac_regs); - netif_start_queue(dev); - vptr->flags |= VELOCITY_FLAGS_OPENED; -out: - return ret; + dev_kfree_skb_irq(skb); + tdinfo->skb = NULL; } -/** - * velocity_change_mtu - MTU change callback - * @dev: network device - * @new_mtu: desired MTU - * - * Handle requests from the networking layer for MTU change on - * this interface. It gets called on a change by the network layer. - * Return zero for success or negative posix error code. - */ -static int velocity_change_mtu(struct net_device *dev, int new_mtu) +/* + * FIXME: could we merge this with velocity_free_tx_buf ? + */ +static void velocity_free_td_ring_entry(struct velocity_info *vptr, + int q, int n) { - struct velocity_info *vptr = netdev_priv(dev); - int ret = 0; - - if ((new_mtu < VELOCITY_MIN_MTU) || new_mtu > (VELOCITY_MAX_MTU)) { - VELOCITY_PRT(MSG_LEVEL_ERR, KERN_NOTICE "%s: Invalid MTU.\n", - vptr->dev->name); - ret = -EINVAL; - goto out_0; - } - - if (!netif_running(dev)) { - dev->mtu = new_mtu; - goto out_0; - } + struct velocity_td_info *td_info = &(vptr->tx.infos[q][n]); + int i; - if (dev->mtu != new_mtu) { - struct velocity_info *tmp_vptr; - unsigned long flags; - struct rx_info rx; - struct tx_info tx; + if (td_info == NULL) + return; - tmp_vptr = kzalloc(sizeof(*tmp_vptr), GFP_KERNEL); - if (!tmp_vptr) { - ret = -ENOMEM; - goto out_0; + if (td_info->skb) { + for (i = 0; i < td_info->nskb_dma; i++) { + if (td_info->skb_dma[i]) { + pci_unmap_single(vptr->pdev, td_info->skb_dma[i], + td_info->skb->len, PCI_DMA_TODEVICE); + td_info->skb_dma[i] = 0; + } } - - tmp_vptr->dev = dev; - tmp_vptr->pdev = vptr->pdev; - tmp_vptr->options = vptr->options; - tmp_vptr->tx.numq = vptr->tx.numq; - - ret = velocity_init_rings(tmp_vptr, new_mtu); - if (ret < 0) - goto out_free_tmp_vptr_1; - - spin_lock_irqsave(&vptr->lock, flags); - - netif_stop_queue(dev); - velocity_shutdown(vptr); - - rx = vptr->rx; - tx = vptr->tx; - - vptr->rx = tmp_vptr->rx; - vptr->tx = tmp_vptr->tx; - - tmp_vptr->rx = rx; - tmp_vptr->tx = tx; - - dev->mtu = new_mtu; - - velocity_give_many_rx_descs(vptr); - - velocity_init_registers(vptr, VELOCITY_INIT_COLD); - - mac_enable_int(vptr->mac_regs); - netif_start_queue(dev); - - spin_unlock_irqrestore(&vptr->lock, flags); - - velocity_free_rings(tmp_vptr); - -out_free_tmp_vptr_1: - kfree(tmp_vptr); + dev_kfree_skb(td_info->skb); + td_info->skb = NULL; } -out_0: - return ret; -} - -/** - * velocity_shutdown - shut down the chip - * @vptr: velocity to deactivate - * - * Shuts down the internal operations of the velocity and - * disables interrupts, autopolling, transmit and receive - */ - -static void velocity_shutdown(struct velocity_info *vptr) -{ - struct mac_regs __iomem *regs = vptr->mac_regs; - mac_disable_int(regs); - writel(CR0_STOP, ®s->CR0Set); - writew(0xFFFF, ®s->TDCSRClr); - writeb(0xFF, ®s->RDCSRClr); - safe_disable_mii_autopoll(regs); - mac_clear_isr(regs); } /** - * velocity_close - close adapter callback - * @dev: network device + * velocity_free_td_ring - free td ring + * @vptr: velocity * - * Callback from the network layer when the velocity is being - * deactivated by the network layer - */ - -static int velocity_close(struct net_device *dev) -{ - struct velocity_info *vptr = netdev_priv(dev); - - netif_stop_queue(dev); - velocity_shutdown(vptr); + * Free up the transmit ring for this particular velocity adapter. + * We free the ring contents but not the ring itself. + */ +static void velocity_free_td_ring(struct velocity_info *vptr) +{ + int i, j; - if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) - velocity_get_ip(vptr); - if (dev->irq != 0) - free_irq(dev->irq, dev); + for (j = 0; j < vptr->tx.numq; j++) { + if (vptr->tx.infos[j] == NULL) + continue; + for (i = 0; i < vptr->options.numtx; i++) + velocity_free_td_ring_entry(vptr, j, i); - /* Power down the chip */ - pci_set_power_state(vptr->pdev, PCI_D3hot); + kfree(vptr->tx.infos[j]); + vptr->tx.infos[j] = NULL; + } +} - velocity_free_rings(vptr); - vptr->flags &= (~VELOCITY_FLAGS_OPENED); - return 0; +static void velocity_free_rings(struct velocity_info *vptr) +{ + velocity_free_td_ring(vptr); + velocity_free_rd_ring(vptr); + velocity_free_dma_rings(vptr); } /** - * velocity_xmit - transmit packet callback - * @skb: buffer to transmit - * @dev: network device + * velocity_error - handle error from controller + * @vptr: velocity + * @status: card status + * + * Process an error report from the hardware and attempt to recover + * the card itself. At the moment we cannot recover from some + * theoretically impossible errors but this could be fixed using + * the pci_device_failed logic to bounce the hardware * - * Called by the networ layer to request a packet is queued to - * the velocity. Returns zero on success. */ - -static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) +static void velocity_error(struct velocity_info *vptr, int status) { - struct velocity_info *vptr = netdev_priv(dev); - int qnum = 0; - struct tx_desc *td_ptr; - struct velocity_td_info *tdinfo; - unsigned long flags; - int pktlen; - __le16 len; - int index; - - - if (skb_padto(skb, ETH_ZLEN)) - goto out; - pktlen = max_t(unsigned int, skb->len, ETH_ZLEN); - len = cpu_to_le16(pktlen); + if (status & ISR_TXSTLI) { + struct mac_regs __iomem *regs = vptr->mac_regs; - spin_lock_irqsave(&vptr->lock, flags); + printk(KERN_ERR "TD structure error TDindex=%hx\n", readw(®s->TDIdx[0])); + BYTE_REG_BITS_ON(TXESR_TDSTR, ®s->TXESR); + writew(TRDCSR_RUN, ®s->TDCSRClr); + netif_stop_queue(vptr->dev); - index = vptr->tx.curr[qnum]; - td_ptr = &(vptr->tx.rings[qnum][index]); - tdinfo = &(vptr->tx.infos[qnum][index]); + /* FIXME: port over the pci_device_failed code and use it + here */ + } - td_ptr->tdesc1.TCR = TCR0_TIC; - td_ptr->td_buf[0].size &= ~TD_QUEUE; + if (status & ISR_SRCI) { + struct mac_regs __iomem *regs = vptr->mac_regs; + int linked; - /* - * Map the linear network buffer into PCI space and - * add it to the transmit ring. - */ - tdinfo->skb = skb; - tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE); - td_ptr->tdesc0.len = len; - td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); - td_ptr->td_buf[0].pa_high = 0; - td_ptr->td_buf[0].size = len; - tdinfo->nskb_dma = 1; + if (vptr->options.spd_dpx == SPD_DPX_AUTO) { + vptr->mii_status = check_connection_type(regs); - td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16; + /* + * If it is a 3119, disable frame bursting in + * halfduplex mode and enable it in fullduplex + * mode + */ + if (vptr->rev_id < REV_ID_VT3216_A0) { + if (vptr->mii_status | VELOCITY_DUPLEX_FULL) + BYTE_REG_BITS_ON(TCR_TB2BDIS, ®s->TCR); + else + BYTE_REG_BITS_OFF(TCR_TB2BDIS, ®s->TCR); + } + /* + * Only enable CD heart beat counter in 10HD mode + */ + if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10)) + BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); + else + BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG); + } + /* + * Get link status from PHYSR0 + */ + linked = readb(®s->PHYSR0) & PHYSR0_LINKGD; - if (vptr->vlgrp && vlan_tx_tag_present(skb)) { - td_ptr->tdesc1.vlan = cpu_to_le16(vlan_tx_tag_get(skb)); - td_ptr->tdesc1.TCR |= TCR0_VETAG; - } + if (linked) { + vptr->mii_status &= ~VELOCITY_LINK_FAIL; + netif_carrier_on(vptr->dev); + } else { + vptr->mii_status |= VELOCITY_LINK_FAIL; + netif_carrier_off(vptr->dev); + } - /* - * Handle hardware checksum - */ - if ((vptr->flags & VELOCITY_FLAGS_TX_CSUM) - && (skb->ip_summed == CHECKSUM_PARTIAL)) { - const struct iphdr *ip = ip_hdr(skb); - if (ip->protocol == IPPROTO_TCP) - td_ptr->tdesc1.TCR |= TCR0_TCPCK; - else if (ip->protocol == IPPROTO_UDP) - td_ptr->tdesc1.TCR |= (TCR0_UDPCK); - td_ptr->tdesc1.TCR |= TCR0_IPCK; - } - { + velocity_print_link_status(vptr); + enable_flow_control_ability(vptr); - int prev = index - 1; + /* + * Re-enable auto-polling because SRCI will disable + * auto-polling + */ - if (prev < 0) - prev = vptr->options.numtx - 1; - td_ptr->tdesc0.len |= OWNED_BY_NIC; - vptr->tx.used[qnum]++; - vptr->tx.curr[qnum] = (index + 1) % vptr->options.numtx; + enable_mii_autopoll(regs); - if (AVAIL_TD(vptr, qnum) < 1) - netif_stop_queue(dev); + if (vptr->mii_status & VELOCITY_LINK_FAIL) + netif_stop_queue(vptr->dev); + else + netif_wake_queue(vptr->dev); - td_ptr = &(vptr->tx.rings[qnum][prev]); - td_ptr->td_buf[0].size |= TD_QUEUE; - mac_tx_queue_wake(vptr->mac_regs, qnum); - } - dev->trans_start = jiffies; - spin_unlock_irqrestore(&vptr->lock, flags); -out: - return NETDEV_TX_OK; + }; + if (status & ISR_MIBFI) + velocity_update_hw_mibs(vptr); + if (status & ISR_LSTEI) + mac_rx_queue_wake(vptr->mac_regs); } /** - * velocity_intr - interrupt callback - * @irq: interrupt number - * @dev_instance: interrupting device + * tx_srv - transmit interrupt service + * @vptr; Velocity + * @status: * - * Called whenever an interrupt is generated by the velocity - * adapter IRQ line. We may not be the source of the interrupt - * and need to identify initially if we are, and if not exit as - * efficiently as possible. + * Scan the queues looking for transmitted packets that + * we can complete and clean up. Update any statistics as + * necessary/ */ - -static irqreturn_t velocity_intr(int irq, void *dev_instance) +static int velocity_tx_srv(struct velocity_info *vptr, u32 status) { - struct net_device *dev = dev_instance; - struct velocity_info *vptr = netdev_priv(dev); - u32 isr_status; - int max_count = 0; + struct tx_desc *td; + int qnum; + int full = 0; + int idx; + int works = 0; + struct velocity_td_info *tdinfo; + struct net_device_stats *stats = &vptr->dev->stats; + for (qnum = 0; qnum < vptr->tx.numq; qnum++) { + for (idx = vptr->tx.tail[qnum]; vptr->tx.used[qnum] > 0; + idx = (idx + 1) % vptr->options.numtx) { - spin_lock(&vptr->lock); - isr_status = mac_read_isr(vptr->mac_regs); + /* + * Get Tx Descriptor + */ + td = &(vptr->tx.rings[qnum][idx]); + tdinfo = &(vptr->tx.infos[qnum][idx]); - /* Not us ? */ - if (isr_status == 0) { - spin_unlock(&vptr->lock); - return IRQ_NONE; - } + if (td->tdesc0.len & OWNED_BY_NIC) + break; - mac_disable_int(vptr->mac_regs); + if ((works++ > 15)) + break; + + if (td->tdesc0.TSR & TSR0_TERR) { + stats->tx_errors++; + stats->tx_dropped++; + if (td->tdesc0.TSR & TSR0_CDH) + stats->tx_heartbeat_errors++; + if (td->tdesc0.TSR & TSR0_CRS) + stats->tx_carrier_errors++; + if (td->tdesc0.TSR & TSR0_ABT) + stats->tx_aborted_errors++; + if (td->tdesc0.TSR & TSR0_OWC) + stats->tx_window_errors++; + } else { + stats->tx_packets++; + stats->tx_bytes += tdinfo->skb->len; + } + velocity_free_tx_buf(vptr, tdinfo); + vptr->tx.used[qnum]--; + } + vptr->tx.tail[qnum] = idx; + if (AVAIL_TD(vptr, qnum) < 1) + full = 1; + } /* - * Keep processing the ISR until we have completed - * processing and the isr_status becomes zero + * Look to see if we should kick the transmit network + * layer for more work. */ + if (netif_queue_stopped(vptr->dev) && (full == 0) + && (!(vptr->mii_status & VELOCITY_LINK_FAIL))) { + netif_wake_queue(vptr->dev); + } + return works; +} + +/** + * velocity_rx_csum - checksum process + * @rd: receive packet descriptor + * @skb: network layer packet buffer + * + * Process the status bits for the received packet and determine + * if the checksum was computed and verified by the hardware + */ +static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb) +{ + skb->ip_summed = CHECKSUM_NONE; - while (isr_status != 0) { - mac_write_isr(vptr->mac_regs, isr_status); - if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI))) - velocity_error(vptr, isr_status); - if (isr_status & (ISR_PRXI | ISR_PPRXI)) - max_count += velocity_rx_srv(vptr, isr_status); - if (isr_status & (ISR_PTXI | ISR_PPTXI)) - max_count += velocity_tx_srv(vptr, isr_status); - isr_status = mac_read_isr(vptr->mac_regs); - if (max_count > vptr->options.int_works) { - printk(KERN_WARNING "%s: excessive work at interrupt.\n", - dev->name); - max_count = 0; + if (rd->rdesc1.CSM & CSM_IPKT) { + if (rd->rdesc1.CSM & CSM_IPOK) { + if ((rd->rdesc1.CSM & CSM_TCPKT) || + (rd->rdesc1.CSM & CSM_UDPKT)) { + if (!(rd->rdesc1.CSM & CSM_TUPOK)) + return; + } + skb->ip_summed = CHECKSUM_UNNECESSARY; } } - spin_unlock(&vptr->lock); - mac_enable_int(vptr->mac_regs); - return IRQ_HANDLED; - } - /** - * velocity_set_multi - filter list change callback + * velocity_rx_copy - in place Rx copy for small packets + * @rx_skb: network layer packet buffer candidate + * @pkt_size: received data size + * @rd: receive packet descriptor * @dev: network device * - * Called by the network layer when the filter lists need to change - * for a velocity adapter. Reload the CAMs with the new address - * filter ruleset. + * Replace the current skb that is scheduled for Rx processing by a + * shorter, immediatly allocated skb, if the received packet is small + * enough. This function returns a negative value if the received + * packet is too big or if memory is exhausted. */ - -static void velocity_set_multi(struct net_device *dev) +static int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size, + struct velocity_info *vptr) { - struct velocity_info *vptr = netdev_priv(dev); - struct mac_regs __iomem *regs = vptr->mac_regs; - u8 rx_mode; - int i; - struct dev_mc_list *mclist; - - if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ - writel(0xffffffff, ®s->MARCAM[0]); - writel(0xffffffff, ®s->MARCAM[4]); - rx_mode = (RCR_AM | RCR_AB | RCR_PROM); - } else if ((dev->mc_count > vptr->multicast_limit) - || (dev->flags & IFF_ALLMULTI)) { - writel(0xffffffff, ®s->MARCAM[0]); - writel(0xffffffff, ®s->MARCAM[4]); - rx_mode = (RCR_AM | RCR_AB); - } else { - int offset = MCAM_SIZE - vptr->multicast_limit; - mac_get_cam_mask(regs, vptr->mCAMmask); + int ret = -1; + if (pkt_size < rx_copybreak) { + struct sk_buff *new_skb; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { - mac_set_cam(regs, i + offset, mclist->dmi_addr); - vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7); + new_skb = netdev_alloc_skb(vptr->dev, pkt_size + 2); + if (new_skb) { + new_skb->ip_summed = rx_skb[0]->ip_summed; + skb_reserve(new_skb, 2); + skb_copy_from_linear_data(*rx_skb, new_skb->data, pkt_size); + *rx_skb = new_skb; + ret = 0; } - mac_set_cam_mask(regs, vptr->mCAMmask); - rx_mode = RCR_AM | RCR_AB | RCR_AP; } - if (dev->mtu > 1500) - rx_mode |= RCR_AL; - - BYTE_REG_BITS_ON(rx_mode, ®s->RCR); - + return ret; } /** - * velocity_get_status - statistics callback - * @dev: network device + * velocity_iph_realign - IP header alignment + * @vptr: velocity we are handling + * @skb: network layer packet buffer + * @pkt_size: received data size * - * Callback from the network layer to allow driver statistics - * to be resynchronized with hardware collected state. In the - * case of the velocity we need to pull the MIB counters from - * the hardware into the counters before letting the network - * layer display them. + * Align IP header on a 2 bytes boundary. This behavior can be + * configured by the user. */ - -static struct net_device_stats *velocity_get_stats(struct net_device *dev) +static inline void velocity_iph_realign(struct velocity_info *vptr, + struct sk_buff *skb, int pkt_size) { - struct velocity_info *vptr = netdev_priv(dev); + if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) { + memmove(skb->data + 2, skb->data, pkt_size); + skb_reserve(skb, 2); + } +} - /* If the hardware is down, don't touch MII */ - if (!netif_running(dev)) - return &dev->stats; - spin_lock_irq(&vptr->lock); - velocity_update_hw_mibs(vptr); - spin_unlock_irq(&vptr->lock); +/** + * velocity_receive_frame - received packet processor + * @vptr: velocity we are handling + * @idx: ring index + * + * A packet has arrived. We process the packet and if appropriate + * pass the frame up the network stack + */ +static int velocity_receive_frame(struct velocity_info *vptr, int idx) +{ + void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int); + struct net_device_stats *stats = &vptr->dev->stats; + struct velocity_rd_info *rd_info = &(vptr->rx.info[idx]); + struct rx_desc *rd = &(vptr->rx.ring[idx]); + int pkt_len = le16_to_cpu(rd->rdesc0.len) & 0x3fff; + struct sk_buff *skb; - dev->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts]; - dev->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts]; - dev->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors]; + if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) { + VELOCITY_PRT(MSG_LEVEL_VERBOSE, KERN_ERR " %s : the received frame span multple RDs.\n", vptr->dev->name); + stats->rx_length_errors++; + return -EINVAL; + } -// unsigned long rx_dropped; /* no space in linux buffers */ - dev->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions]; - /* detailed rx_errors: */ -// unsigned long rx_length_errors; -// unsigned long rx_over_errors; /* receiver ring buff overflow */ - dev->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE]; -// unsigned long rx_frame_errors; /* recv'd frame alignment error */ -// unsigned long rx_fifo_errors; /* recv'r fifo overrun */ -// unsigned long rx_missed_errors; /* receiver missed packet */ + if (rd->rdesc0.RSR & RSR_MAR) + stats->multicast++; - /* detailed tx_errors */ -// unsigned long tx_fifo_errors; + skb = rd_info->skb; - return &dev->stats; -} + pci_dma_sync_single_for_cpu(vptr->pdev, rd_info->skb_dma, + vptr->rx.buf_sz, PCI_DMA_FROMDEVICE); + /* + * Drop frame not meeting IEEE 802.3 + */ -/** - * velocity_ioctl - ioctl entry point - * @dev: network device - * @rq: interface request ioctl - * @cmd: command code - * - * Called when the user issues an ioctl request to the network - * device in question. The velocity interface supports MII. - */ + if (vptr->flags & VELOCITY_FLAGS_VAL_PKT_LEN) { + if (rd->rdesc0.RSR & RSR_RL) { + stats->rx_length_errors++; + return -EINVAL; + } + } -static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct velocity_info *vptr = netdev_priv(dev); - int ret; + pci_action = pci_dma_sync_single_for_device; - /* If we are asked for information and the device is power - saving then we need to bring the device back up to talk to it */ + velocity_rx_csum(rd, skb); - if (!netif_running(dev)) - pci_set_power_state(vptr->pdev, PCI_D0); + if (velocity_rx_copy(&skb, pkt_len, vptr) < 0) { + velocity_iph_realign(vptr, skb, pkt_len); + pci_action = pci_unmap_single; + rd_info->skb = NULL; + } - switch (cmd) { - case SIOCGMIIPHY: /* Get address of MII PHY in use. */ - case SIOCGMIIREG: /* Read MII PHY register. */ - case SIOCSMIIREG: /* Write to MII PHY register. */ - ret = velocity_mii_ioctl(dev, rq, cmd); - break; + pci_action(vptr->pdev, rd_info->skb_dma, vptr->rx.buf_sz, + PCI_DMA_FROMDEVICE); - default: - ret = -EOPNOTSUPP; - } - if (!netif_running(dev)) - pci_set_power_state(vptr->pdev, PCI_D3hot); + skb_put(skb, pkt_len - 4); + skb->protocol = eth_type_trans(skb, vptr->dev); + + if (vptr->vlgrp && (rd->rdesc0.RSR & RSR_DETAG)) { + vlan_hwaccel_rx(skb, vptr->vlgrp, + swab16(le16_to_cpu(rd->rdesc1.PQTAG))); + } else + netif_rx(skb); + stats->rx_bytes += pkt_len; - return ret; + return 0; } -/* - * Definition for our device driver. The PCI layer interface - * uses this to handle all our card discover and plugging - */ - -static struct pci_driver velocity_driver = { - .name = VELOCITY_NAME, - .id_table = velocity_id_table, - .probe = velocity_found1, - .remove = __devexit_p(velocity_remove1), -#ifdef CONFIG_PM - .suspend = velocity_suspend, - .resume = velocity_resume, -#endif -}; /** - * velocity_init_module - load time function + * velocity_rx_srv - service RX interrupt + * @vptr: velocity + * @status: adapter status (unused) * - * Called when the velocity module is loaded. The PCI driver - * is registered with the PCI layer, and in turn will call - * the probe functions for each velocity adapter installed - * in the system. + * Walk the receive ring of the velocity adapter and remove + * any received packets from the receive queue. Hand the ring + * slots back to the adapter for reuse. */ - -static int __init velocity_init_module(void) +static int velocity_rx_srv(struct velocity_info *vptr, int status) { - int ret; + struct net_device_stats *stats = &vptr->dev->stats; + int rd_curr = vptr->rx.curr; + int works = 0; + + do { + struct rx_desc *rd = vptr->rx.ring + rd_curr; + + if (!vptr->rx.info[rd_curr].skb) + break; + + if (rd->rdesc0.len & OWNED_BY_NIC) + break; + + rmb(); - velocity_register_notifier(); - ret = pci_register_driver(&velocity_driver); - if (ret < 0) - velocity_unregister_notifier(); - return ret; -} + /* + * Don't drop CE or RL error frame although RXOK is off + */ + if (rd->rdesc0.RSR & (RSR_RXOK | RSR_CE | RSR_RL)) { + if (velocity_receive_frame(vptr, rd_curr) < 0) + stats->rx_dropped++; + } else { + if (rd->rdesc0.RSR & RSR_CRC) + stats->rx_crc_errors++; + if (rd->rdesc0.RSR & RSR_FAE) + stats->rx_frame_errors++; -/** - * velocity_cleanup - module unload - * - * When the velocity hardware is unloaded this function is called. - * It will clean up the notifiers and the unregister the PCI - * driver interface for this hardware. This in turn cleans up - * all discovered interfaces before returning from the function - */ + stats->rx_dropped++; + } -static void __exit velocity_cleanup_module(void) -{ - velocity_unregister_notifier(); - pci_unregister_driver(&velocity_driver); -} + rd->size |= RX_INTEN; -module_init(velocity_init_module); -module_exit(velocity_cleanup_module); + rd_curr++; + if (rd_curr >= vptr->options.numrx) + rd_curr = 0; + } while (++works <= 15); + vptr->rx.curr = rd_curr; -/* - * MII access , media link mode setting functions - */ + if ((works > 0) && (velocity_rx_refill(vptr) > 0)) + velocity_give_many_rx_descs(vptr); + + VAR_USED(stats); + return works; +} /** - * mii_init - set up MII - * @vptr: velocity adapter - * @mii_status: links tatus + * velocity_intr - interrupt callback + * @irq: interrupt number + * @dev_instance: interrupting device * - * Set up the PHY for the current link state. + * Called whenever an interrupt is generated by the velocity + * adapter IRQ line. We may not be the source of the interrupt + * and need to identify initially if we are, and if not exit as + * efficiently as possible. */ - -static void mii_init(struct velocity_info *vptr, u32 mii_status) +static irqreturn_t velocity_intr(int irq, void *dev_instance) { - u16 BMCR; + struct net_device *dev = dev_instance; + struct velocity_info *vptr = netdev_priv(dev); + u32 isr_status; + int max_count = 0; - switch (PHYID_GET_PHY_ID(vptr->phy_id)) { - case PHYID_CICADA_CS8201: - /* - * Reset to hardware default - */ - MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs); - /* - * Turn on ECHODIS bit in NWay-forced full mode and turn it - * off it in NWay-forced half mode for NWay-forced v.s. - * legacy-forced issue. - */ - if (vptr->mii_status & VELOCITY_DUPLEX_FULL) - MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs); - else - MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs); - /* - * Turn on Link/Activity LED enable bit for CIS8201 - */ - MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, vptr->mac_regs); - break; - case PHYID_VT3216_32BIT: - case PHYID_VT3216_64BIT: - /* - * Reset to hardware default - */ - MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs); - /* - * Turn on ECHODIS bit in NWay-forced full mode and turn it - * off it in NWay-forced half mode for NWay-forced v.s. - * legacy-forced issue - */ - if (vptr->mii_status & VELOCITY_DUPLEX_FULL) - MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs); - else - MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs); - break; - case PHYID_MARVELL_1000: - case PHYID_MARVELL_1000S: - /* - * Assert CRS on Transmit - */ - MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs); - /* - * Reset to hardware default - */ - MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs); - break; - default: - ; - } - velocity_mii_read(vptr->mac_regs, MII_REG_BMCR, &BMCR); - if (BMCR & BMCR_ISO) { - BMCR &= ~BMCR_ISO; - velocity_mii_write(vptr->mac_regs, MII_REG_BMCR, BMCR); + spin_lock(&vptr->lock); + isr_status = mac_read_isr(vptr->mac_regs); + + /* Not us ? */ + if (isr_status == 0) { + spin_unlock(&vptr->lock); + return IRQ_NONE; } -} -/** - * safe_disable_mii_autopoll - autopoll off - * @regs: velocity registers - * - * Turn off the autopoll and wait for it to disable on the chip - */ + mac_disable_int(vptr->mac_regs); -static void safe_disable_mii_autopoll(struct mac_regs __iomem *regs) -{ - u16 ww; + /* + * Keep processing the ISR until we have completed + * processing and the isr_status becomes zero + */ - /* turn off MAUTO */ - writeb(0, ®s->MIICR); - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - udelay(1); - if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, ®s->MIISR)) - break; + while (isr_status != 0) { + mac_write_isr(vptr->mac_regs, isr_status); + if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI))) + velocity_error(vptr, isr_status); + if (isr_status & (ISR_PRXI | ISR_PPRXI)) + max_count += velocity_rx_srv(vptr, isr_status); + if (isr_status & (ISR_PTXI | ISR_PPTXI)) + max_count += velocity_tx_srv(vptr, isr_status); + isr_status = mac_read_isr(vptr->mac_regs); + if (max_count > vptr->options.int_works) { + printk(KERN_WARNING "%s: excessive work at interrupt.\n", + dev->name); + max_count = 0; + } } + spin_unlock(&vptr->lock); + mac_enable_int(vptr->mac_regs); + return IRQ_HANDLED; + } /** - * enable_mii_autopoll - turn on autopolling - * @regs: velocity registers + * velocity_open - interface activation callback + * @dev: network layer device to open * - * Enable the MII link status autopoll feature on the Velocity - * hardware. Wait for it to enable. + * Called when the network layer brings the interface up. Returns + * a negative posix error code on failure, or zero on success. + * + * All the ring allocation and set up is done on open for this + * adapter to minimise memory usage when inactive */ - -static void enable_mii_autopoll(struct mac_regs __iomem *regs) +static int velocity_open(struct net_device *dev) { - int ii; + struct velocity_info *vptr = netdev_priv(dev); + int ret; - writeb(0, &(regs->MIICR)); - writeb(MIIADR_SWMPL, ®s->MIIADR); + ret = velocity_init_rings(vptr, dev->mtu); + if (ret < 0) + goto out; - for (ii = 0; ii < W_MAX_TIMEOUT; ii++) { - udelay(1); - if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, ®s->MIISR)) - break; - } + /* Ensure chip is running */ + pci_set_power_state(vptr->pdev, PCI_D0); - writeb(MIICR_MAUTO, ®s->MIICR); + velocity_give_many_rx_descs(vptr); - for (ii = 0; ii < W_MAX_TIMEOUT; ii++) { - udelay(1); - if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, ®s->MIISR)) - break; + velocity_init_registers(vptr, VELOCITY_INIT_COLD); + + ret = request_irq(vptr->pdev->irq, &velocity_intr, IRQF_SHARED, + dev->name, dev); + if (ret < 0) { + /* Power down the chip */ + pci_set_power_state(vptr->pdev, PCI_D3hot); + velocity_free_rings(vptr); + goto out; } + mac_enable_int(vptr->mac_regs); + netif_start_queue(dev); + vptr->flags |= VELOCITY_FLAGS_OPENED; +out: + return ret; } /** - * velocity_mii_read - read MII data - * @regs: velocity registers - * @index: MII register index - * @data: buffer for received data + * velocity_shutdown - shut down the chip + * @vptr: velocity to deactivate * - * Perform a single read of an MII 16bit register. Returns zero - * on success or -ETIMEDOUT if the PHY did not respond. + * Shuts down the internal operations of the velocity and + * disables interrupts, autopolling, transmit and receive */ - -static int velocity_mii_read(struct mac_regs __iomem *regs, u8 index, u16 *data) +static void velocity_shutdown(struct velocity_info *vptr) { - u16 ww; - - /* - * Disable MIICR_MAUTO, so that mii addr can be set normally - */ + struct mac_regs __iomem *regs = vptr->mac_regs; + mac_disable_int(regs); + writel(CR0_STOP, ®s->CR0Set); + writew(0xFFFF, ®s->TDCSRClr); + writeb(0xFF, ®s->RDCSRClr); safe_disable_mii_autopoll(regs); + mac_clear_isr(regs); +} - writeb(index, ®s->MIIADR); +/** + * velocity_change_mtu - MTU change callback + * @dev: network device + * @new_mtu: desired MTU + * + * Handle requests from the networking layer for MTU change on + * this interface. It gets called on a change by the network layer. + * Return zero for success or negative posix error code. + */ +static int velocity_change_mtu(struct net_device *dev, int new_mtu) +{ + struct velocity_info *vptr = netdev_priv(dev); + int ret = 0; - BYTE_REG_BITS_ON(MIICR_RCMD, ®s->MIICR); + if ((new_mtu < VELOCITY_MIN_MTU) || new_mtu > (VELOCITY_MAX_MTU)) { + VELOCITY_PRT(MSG_LEVEL_ERR, KERN_NOTICE "%s: Invalid MTU.\n", + vptr->dev->name); + ret = -EINVAL; + goto out_0; + } - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - if (!(readb(®s->MIICR) & MIICR_RCMD)) - break; + if (!netif_running(dev)) { + dev->mtu = new_mtu; + goto out_0; } - *data = readw(®s->MIIDATA); + if (dev->mtu != new_mtu) { + struct velocity_info *tmp_vptr; + unsigned long flags; + struct rx_info rx; + struct tx_info tx; - enable_mii_autopoll(regs); - if (ww == W_MAX_TIMEOUT) - return -ETIMEDOUT; - return 0; -} + tmp_vptr = kzalloc(sizeof(*tmp_vptr), GFP_KERNEL); + if (!tmp_vptr) { + ret = -ENOMEM; + goto out_0; + } -/** - * velocity_mii_write - write MII data - * @regs: velocity registers - * @index: MII register index - * @data: 16bit data for the MII register - * - * Perform a single write to an MII 16bit register. Returns zero - * on success or -ETIMEDOUT if the PHY did not respond. - */ + tmp_vptr->dev = dev; + tmp_vptr->pdev = vptr->pdev; + tmp_vptr->options = vptr->options; + tmp_vptr->tx.numq = vptr->tx.numq; -static int velocity_mii_write(struct mac_regs __iomem *regs, u8 mii_addr, u16 data) -{ - u16 ww; + ret = velocity_init_rings(tmp_vptr, new_mtu); + if (ret < 0) + goto out_free_tmp_vptr_1; - /* - * Disable MIICR_MAUTO, so that mii addr can be set normally - */ - safe_disable_mii_autopoll(regs); + spin_lock_irqsave(&vptr->lock, flags); - /* MII reg offset */ - writeb(mii_addr, ®s->MIIADR); - /* set MII data */ - writew(data, ®s->MIIDATA); + netif_stop_queue(dev); + velocity_shutdown(vptr); - /* turn on MIICR_WCMD */ - BYTE_REG_BITS_ON(MIICR_WCMD, ®s->MIICR); + rx = vptr->rx; + tx = vptr->tx; - /* W_MAX_TIMEOUT is the timeout period */ - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - udelay(5); - if (!(readb(®s->MIICR) & MIICR_WCMD)) - break; - } - enable_mii_autopoll(regs); + vptr->rx = tmp_vptr->rx; + vptr->tx = tmp_vptr->tx; - if (ww == W_MAX_TIMEOUT) - return -ETIMEDOUT; - return 0; -} + tmp_vptr->rx = rx; + tmp_vptr->tx = tx; -/** - * velocity_get_opt_media_mode - get media selection - * @vptr: velocity adapter - * - * Get the media mode stored in EEPROM or module options and load - * mii_status accordingly. The requested link state information - * is also returned. - */ + dev->mtu = new_mtu; -static u32 velocity_get_opt_media_mode(struct velocity_info *vptr) -{ - u32 status = 0; + velocity_give_many_rx_descs(vptr); - switch (vptr->options.spd_dpx) { - case SPD_DPX_AUTO: - status = VELOCITY_AUTONEG_ENABLE; - break; - case SPD_DPX_100_FULL: - status = VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL; - break; - case SPD_DPX_10_FULL: - status = VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL; - break; - case SPD_DPX_100_HALF: - status = VELOCITY_SPEED_100; - break; - case SPD_DPX_10_HALF: - status = VELOCITY_SPEED_10; - break; - } - vptr->mii_status = status; - return status; -} + velocity_init_registers(vptr, VELOCITY_INIT_COLD); -/** - * mii_set_auto_on - autonegotiate on - * @vptr: velocity - * - * Enable autonegotation on this interface - */ + mac_enable_int(vptr->mac_regs); + netif_start_queue(dev); -static void mii_set_auto_on(struct velocity_info *vptr) -{ - if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs)) - MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs); - else - MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); -} + spin_unlock_irqrestore(&vptr->lock, flags); + velocity_free_rings(tmp_vptr); -/* -static void mii_set_auto_off(struct velocity_info *vptr) -{ - MII_REG_BITS_OFF(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); +out_free_tmp_vptr_1: + kfree(tmp_vptr); + } +out_0: + return ret; } -*/ /** - * set_mii_flow_control - flow control setup - * @vptr: velocity interface + * velocity_mii_ioctl - MII ioctl handler + * @dev: network device + * @ifr: the ifreq block for the ioctl + * @cmd: the command * - * Set up the flow control on this interface according to - * the supplied user/eeprom options. + * Process MII requests made via ioctl from the network layer. These + * are used by tools like kudzu to interrogate the link state of the + * hardware */ - -static void set_mii_flow_control(struct velocity_info *vptr) +static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - /*Enable or Disable PAUSE in ANAR */ - switch (vptr->options.flow_cntl) { - case FLOW_CNTL_TX: - MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); - MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); - break; + struct velocity_info *vptr = netdev_priv(dev); + struct mac_regs __iomem *regs = vptr->mac_regs; + unsigned long flags; + struct mii_ioctl_data *miidata = if_mii(ifr); + int err; - case FLOW_CNTL_RX: - MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); - MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); + switch (cmd) { + case SIOCGMIIPHY: + miidata->phy_id = readb(®s->MIIADR) & 0x1f; break; - - case FLOW_CNTL_TX_RX: - MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); - MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); + case SIOCGMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0) + return -ETIMEDOUT; break; - - case FLOW_CNTL_DISABLE: - MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); - MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); + case SIOCSMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + spin_lock_irqsave(&vptr->lock, flags); + err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in); + spin_unlock_irqrestore(&vptr->lock, flags); + check_connection_type(vptr->mac_regs); + if (err) + return err; break; default: - break; + return -EOPNOTSUPP; } + return 0; } + /** - * velocity_set_media_mode - set media mode - * @mii_status: old MII link state + * velocity_ioctl - ioctl entry point + * @dev: network device + * @rq: interface request ioctl + * @cmd: command code * - * Check the media link state and configure the flow control - * PHY and also velocity hardware setup accordingly. In particular - * we need to set up CD polling and frame bursting. + * Called when the user issues an ioctl request to the network + * device in question. The velocity interface supports MII. */ +static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct velocity_info *vptr = netdev_priv(dev); + int ret; -static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status) -{ - u32 curr_status; - struct mac_regs __iomem *regs = vptr->mac_regs; - - vptr->mii_status = mii_check_media_mode(vptr->mac_regs); - curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL); - - /* Set mii link status */ - set_mii_flow_control(vptr); - - /* - Check if new status is consisent with current status - if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE) - || (mii_status==curr_status)) { - vptr->mii_status=mii_check_media_mode(vptr->mac_regs); - vptr->mii_status=check_connection_type(vptr->mac_regs); - VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity link no change\n"); - return 0; - } - */ - - if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) - MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs); - - /* - * If connection type is AUTO - */ - if (mii_status & VELOCITY_AUTONEG_ENABLE) { - VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity is AUTO mode\n"); - /* clear force MAC mode bit */ - BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, ®s->CHIPGCR); - /* set duplex mode of MAC according to duplex mode of MII */ - MII_REG_BITS_ON(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10, MII_REG_ANAR, vptr->mac_regs); - MII_REG_BITS_ON(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs); - MII_REG_BITS_ON(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); - - /* enable AUTO-NEGO mode */ - mii_set_auto_on(vptr); - } else { - u16 ANAR; - u8 CHIPGCR; - - /* - * 1. if it's 3119, disable frame bursting in halfduplex mode - * and enable it in fullduplex mode - * 2. set correct MII/GMII and half/full duplex mode in CHIPGCR - * 3. only enable CD heart beat counter in 10HD mode - */ - - /* set force MAC mode bit */ - BYTE_REG_BITS_ON(CHIPGCR_FCMODE, ®s->CHIPGCR); + /* If we are asked for information and the device is power + saving then we need to bring the device back up to talk to it */ - CHIPGCR = readb(®s->CHIPGCR); - CHIPGCR &= ~CHIPGCR_FCGMII; + if (!netif_running(dev)) + pci_set_power_state(vptr->pdev, PCI_D0); - if (mii_status & VELOCITY_DUPLEX_FULL) { - CHIPGCR |= CHIPGCR_FCFDX; - writeb(CHIPGCR, ®s->CHIPGCR); - VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced full mode\n"); - if (vptr->rev_id < REV_ID_VT3216_A0) - BYTE_REG_BITS_OFF(TCR_TB2BDIS, ®s->TCR); - } else { - CHIPGCR &= ~CHIPGCR_FCFDX; - VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced half mode\n"); - writeb(CHIPGCR, ®s->CHIPGCR); - if (vptr->rev_id < REV_ID_VT3216_A0) - BYTE_REG_BITS_ON(TCR_TB2BDIS, ®s->TCR); - } + switch (cmd) { + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCSMIIREG: /* Write to MII PHY register. */ + ret = velocity_mii_ioctl(dev, rq, cmd); + break; - MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs); + default: + ret = -EOPNOTSUPP; + } + if (!netif_running(dev)) + pci_set_power_state(vptr->pdev, PCI_D3hot); - if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10)) - BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); - else - BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG); - /* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */ - velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR); - ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)); - if (mii_status & VELOCITY_SPEED_100) { - if (mii_status & VELOCITY_DUPLEX_FULL) - ANAR |= ANAR_TXFD; - else - ANAR |= ANAR_TX; - } else { - if (mii_status & VELOCITY_DUPLEX_FULL) - ANAR |= ANAR_10FD; - else - ANAR |= ANAR_10; - } - velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR); - /* enable AUTO-NEGO mode */ - mii_set_auto_on(vptr); - /* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */ - } - /* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */ - /* vptr->mii_status=check_connection_type(vptr->mac_regs); */ - return VELOCITY_LINK_CHANGE; + return ret; } /** - * mii_check_media_mode - check media state - * @regs: velocity registers + * velocity_get_status - statistics callback + * @dev: network device * - * Check the current MII status and determine the link status - * accordingly + * Callback from the network layer to allow driver statistics + * to be resynchronized with hardware collected state. In the + * case of the velocity we need to pull the MIB counters from + * the hardware into the counters before letting the network + * layer display them. */ - -static u32 mii_check_media_mode(struct mac_regs __iomem *regs) +static struct net_device_stats *velocity_get_stats(struct net_device *dev) { - u32 status = 0; - u16 ANAR; + struct velocity_info *vptr = netdev_priv(dev); - if (!MII_REG_BITS_IS_ON(BMSR_LNK, MII_REG_BMSR, regs)) - status |= VELOCITY_LINK_FAIL; + /* If the hardware is down, don't touch MII */ + if (!netif_running(dev)) + return &dev->stats; - if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs)) - status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL; - else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs)) - status |= (VELOCITY_SPEED_1000); - else { - velocity_mii_read(regs, MII_REG_ANAR, &ANAR); - if (ANAR & ANAR_TXFD) - status |= (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL); - else if (ANAR & ANAR_TX) - status |= VELOCITY_SPEED_100; - else if (ANAR & ANAR_10FD) - status |= (VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL); - else - status |= (VELOCITY_SPEED_10); - } + spin_lock_irq(&vptr->lock); + velocity_update_hw_mibs(vptr); + spin_unlock_irq(&vptr->lock); - if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) { - velocity_mii_read(regs, MII_REG_ANAR, &ANAR); - if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) - == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) { - if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs)) - status |= VELOCITY_AUTONEG_ENABLE; - } - } + dev->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts]; + dev->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts]; + dev->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors]; - return status; +// unsigned long rx_dropped; /* no space in linux buffers */ + dev->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions]; + /* detailed rx_errors: */ +// unsigned long rx_length_errors; +// unsigned long rx_over_errors; /* receiver ring buff overflow */ + dev->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE]; +// unsigned long rx_frame_errors; /* recv'd frame alignment error */ +// unsigned long rx_fifo_errors; /* recv'r fifo overrun */ +// unsigned long rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ +// unsigned long tx_fifo_errors; + + return &dev->stats; } -static u32 check_connection_type(struct mac_regs __iomem *regs) +/** + * velocity_close - close adapter callback + * @dev: network device + * + * Callback from the network layer when the velocity is being + * deactivated by the network layer + */ +static int velocity_close(struct net_device *dev) { - u32 status = 0; - u8 PHYSR0; - u16 ANAR; - PHYSR0 = readb(®s->PHYSR0); + struct velocity_info *vptr = netdev_priv(dev); - /* - if (!(PHYSR0 & PHYSR0_LINKGD)) - status|=VELOCITY_LINK_FAIL; - */ + netif_stop_queue(dev); + velocity_shutdown(vptr); - if (PHYSR0 & PHYSR0_FDPX) - status |= VELOCITY_DUPLEX_FULL; + if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) + velocity_get_ip(vptr); + if (dev->irq != 0) + free_irq(dev->irq, dev); - if (PHYSR0 & PHYSR0_SPDG) - status |= VELOCITY_SPEED_1000; - else if (PHYSR0 & PHYSR0_SPD10) - status |= VELOCITY_SPEED_10; - else - status |= VELOCITY_SPEED_100; + /* Power down the chip */ + pci_set_power_state(vptr->pdev, PCI_D3hot); - if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) { - velocity_mii_read(regs, MII_REG_ANAR, &ANAR); - if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) - == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) { - if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs)) - status |= VELOCITY_AUTONEG_ENABLE; - } - } + velocity_free_rings(vptr); - return status; + vptr->flags &= (~VELOCITY_FLAGS_OPENED); + return 0; } /** - * enable_flow_control_ability - flow control - * @vptr: veloity to configure + * velocity_xmit - transmit packet callback + * @skb: buffer to transmit + * @dev: network device * - * Set up flow control according to the flow control options - * determined by the eeprom/configuration. + * Called by the networ layer to request a packet is queued to + * the velocity. Returns zero on success. */ - -static void enable_flow_control_ability(struct velocity_info *vptr) +static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) { + struct velocity_info *vptr = netdev_priv(dev); + int qnum = 0; + struct tx_desc *td_ptr; + struct velocity_td_info *tdinfo; + unsigned long flags; + int pktlen; + __le16 len; + int index; - struct mac_regs __iomem *regs = vptr->mac_regs; + if (skb_padto(skb, ETH_ZLEN)) + goto out; + pktlen = max_t(unsigned int, skb->len, ETH_ZLEN); - switch (vptr->options.flow_cntl) { + len = cpu_to_le16(pktlen); - case FLOW_CNTL_DEFAULT: - if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, ®s->PHYSR0)) - writel(CR0_FDXRFCEN, ®s->CR0Set); - else - writel(CR0_FDXRFCEN, ®s->CR0Clr); + spin_lock_irqsave(&vptr->lock, flags); - if (BYTE_REG_BITS_IS_ON(PHYSR0_TXFLC, ®s->PHYSR0)) - writel(CR0_FDXTFCEN, ®s->CR0Set); - else - writel(CR0_FDXTFCEN, ®s->CR0Clr); - break; + index = vptr->tx.curr[qnum]; + td_ptr = &(vptr->tx.rings[qnum][index]); + tdinfo = &(vptr->tx.infos[qnum][index]); - case FLOW_CNTL_TX: - writel(CR0_FDXTFCEN, ®s->CR0Set); - writel(CR0_FDXRFCEN, ®s->CR0Clr); - break; + td_ptr->tdesc1.TCR = TCR0_TIC; + td_ptr->td_buf[0].size &= ~TD_QUEUE; - case FLOW_CNTL_RX: - writel(CR0_FDXRFCEN, ®s->CR0Set); - writel(CR0_FDXTFCEN, ®s->CR0Clr); - break; + /* + * Map the linear network buffer into PCI space and + * add it to the transmit ring. + */ + tdinfo->skb = skb; + tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE); + td_ptr->tdesc0.len = len; + td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); + td_ptr->td_buf[0].pa_high = 0; + td_ptr->td_buf[0].size = len; + tdinfo->nskb_dma = 1; + + td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16; + + if (vptr->vlgrp && vlan_tx_tag_present(skb)) { + td_ptr->tdesc1.vlan = cpu_to_le16(vlan_tx_tag_get(skb)); + td_ptr->tdesc1.TCR |= TCR0_VETAG; + } + + /* + * Handle hardware checksum + */ + if ((vptr->flags & VELOCITY_FLAGS_TX_CSUM) + && (skb->ip_summed == CHECKSUM_PARTIAL)) { + const struct iphdr *ip = ip_hdr(skb); + if (ip->protocol == IPPROTO_TCP) + td_ptr->tdesc1.TCR |= TCR0_TCPCK; + else if (ip->protocol == IPPROTO_UDP) + td_ptr->tdesc1.TCR |= (TCR0_UDPCK); + td_ptr->tdesc1.TCR |= TCR0_IPCK; + } + { - case FLOW_CNTL_TX_RX: - writel(CR0_FDXTFCEN, ®s->CR0Set); - writel(CR0_FDXRFCEN, ®s->CR0Set); - break; + int prev = index - 1; - case FLOW_CNTL_DISABLE: - writel(CR0_FDXRFCEN, ®s->CR0Clr); - writel(CR0_FDXTFCEN, ®s->CR0Clr); - break; + if (prev < 0) + prev = vptr->options.numtx - 1; + td_ptr->tdesc0.len |= OWNED_BY_NIC; + vptr->tx.used[qnum]++; + vptr->tx.curr[qnum] = (index + 1) % vptr->options.numtx; - default: - break; - } + if (AVAIL_TD(vptr, qnum) < 1) + netif_stop_queue(dev); + td_ptr = &(vptr->tx.rings[qnum][prev]); + td_ptr->td_buf[0].size |= TD_QUEUE; + mac_tx_queue_wake(vptr->mac_regs, qnum); + } + dev->trans_start = jiffies; + spin_unlock_irqrestore(&vptr->lock, flags); +out: + return NETDEV_TX_OK; } +static const struct net_device_ops velocity_netdev_ops = { + .ndo_open = velocity_open, + .ndo_stop = velocity_close, + .ndo_start_xmit = velocity_xmit, + .ndo_get_stats = velocity_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, + .ndo_set_multicast_list = velocity_set_multi, + .ndo_change_mtu = velocity_change_mtu, + .ndo_do_ioctl = velocity_ioctl, + .ndo_vlan_rx_add_vid = velocity_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = velocity_vlan_rx_kill_vid, + .ndo_vlan_rx_register = velocity_vlan_rx_register, +}; + /** - * velocity_ethtool_up - pre hook for ethtool - * @dev: network device + * velocity_init_info - init private data + * @pdev: PCI device + * @vptr: Velocity info + * @info: Board type * - * Called before an ethtool operation. We need to make sure the - * chip is out of D3 state before we poke at it. + * Set up the initial velocity_info struct for the device that has been + * discovered. */ - -static int velocity_ethtool_up(struct net_device *dev) +static void __devinit velocity_init_info(struct pci_dev *pdev, + struct velocity_info *vptr, + const struct velocity_info_tbl *info) { - struct velocity_info *vptr = netdev_priv(dev); - if (!netif_running(dev)) - pci_set_power_state(vptr->pdev, PCI_D0); - return 0; + memset(vptr, 0, sizeof(struct velocity_info)); + + vptr->pdev = pdev; + vptr->chip_id = info->chip_id; + vptr->tx.numq = info->txqueue; + vptr->multicast_limit = MCAM_SIZE; + spin_lock_init(&vptr->lock); + INIT_LIST_HEAD(&vptr->list); } /** - * velocity_ethtool_down - post hook for ethtool - * @dev: network device + * velocity_get_pci_info - retrieve PCI info for device + * @vptr: velocity device + * @pdev: PCI device it matches * - * Called after an ethtool operation. Restore the chip back to D3 - * state if it isn't running. + * Retrieve the PCI configuration space data that interests us from + * the kernel PCI layer */ - -static void velocity_ethtool_down(struct net_device *dev) +static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev) { - struct velocity_info *vptr = netdev_priv(dev); - if (!netif_running(dev)) - pci_set_power_state(vptr->pdev, PCI_D3hot); -} + vptr->rev_id = pdev->revision; -static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct velocity_info *vptr = netdev_priv(dev); - struct mac_regs __iomem *regs = vptr->mac_regs; - u32 status; - status = check_connection_type(vptr->mac_regs); + pci_set_master(pdev); - cmd->supported = SUPPORTED_TP | - SUPPORTED_Autoneg | - SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full; - if (status & VELOCITY_SPEED_1000) - cmd->speed = SPEED_1000; - else if (status & VELOCITY_SPEED_100) - cmd->speed = SPEED_100; - else - cmd->speed = SPEED_10; - cmd->autoneg = (status & VELOCITY_AUTONEG_ENABLE) ? AUTONEG_ENABLE : AUTONEG_DISABLE; - cmd->port = PORT_TP; - cmd->transceiver = XCVR_INTERNAL; - cmd->phy_address = readb(®s->MIIADR) & 0x1F; + vptr->ioaddr = pci_resource_start(pdev, 0); + vptr->memaddr = pci_resource_start(pdev, 1); - if (status & VELOCITY_DUPLEX_FULL) - cmd->duplex = DUPLEX_FULL; - else - cmd->duplex = DUPLEX_HALF; + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) { + dev_err(&pdev->dev, + "region #0 is not an I/O resource, aborting.\n"); + return -EINVAL; + } + + if ((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) { + dev_err(&pdev->dev, + "region #1 is an I/O resource, aborting.\n"); + return -EINVAL; + } + + if (pci_resource_len(pdev, 1) < VELOCITY_IO_SIZE) { + dev_err(&pdev->dev, "region #1 is too small.\n"); + return -EINVAL; + } + vptr->pdev = pdev; return 0; } -static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +/** + * velocity_print_info - per driver data + * @vptr: velocity + * + * Print per driver data as the kernel driver finds Velocity + * hardware + */ +static void __devinit velocity_print_info(struct velocity_info *vptr) { - struct velocity_info *vptr = netdev_priv(dev); - u32 curr_status; - u32 new_status = 0; - int ret = 0; - - curr_status = check_connection_type(vptr->mac_regs); - curr_status &= (~VELOCITY_LINK_FAIL); - - new_status |= ((cmd->autoneg) ? VELOCITY_AUTONEG_ENABLE : 0); - new_status |= ((cmd->speed == SPEED_100) ? VELOCITY_SPEED_100 : 0); - new_status |= ((cmd->speed == SPEED_10) ? VELOCITY_SPEED_10 : 0); - new_status |= ((cmd->duplex == DUPLEX_FULL) ? VELOCITY_DUPLEX_FULL : 0); - - if ((new_status & VELOCITY_AUTONEG_ENABLE) && (new_status != (curr_status | VELOCITY_AUTONEG_ENABLE))) - ret = -EINVAL; - else - velocity_set_media_mode(vptr, new_status); + struct net_device *dev = vptr->dev; - return ret; + printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id)); + printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", + dev->name, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); } static u32 velocity_get_link(struct net_device *dev) @@ -3016,195 +2647,165 @@ static u32 velocity_get_link(struct net_device *dev) return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, ®s->PHYSR0) ? 1 : 0; } -static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - struct velocity_info *vptr = netdev_priv(dev); - strcpy(info->driver, VELOCITY_NAME); - strcpy(info->version, VELOCITY_VERSION); - strcpy(info->bus_info, pci_name(vptr->pdev)); -} -static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +/** + * velocity_found1 - set up discovered velocity card + * @pdev: PCI device + * @ent: PCI device table entry that matched + * + * Configure a discovered adapter from scratch. Return a negative + * errno error code on failure paths. + */ +static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct velocity_info *vptr = netdev_priv(dev); - wol->supported = WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP; - wol->wolopts |= WAKE_MAGIC; - /* - if (vptr->wol_opts & VELOCITY_WOL_PHY) - wol.wolopts|=WAKE_PHY; - */ - if (vptr->wol_opts & VELOCITY_WOL_UCAST) - wol->wolopts |= WAKE_UCAST; - if (vptr->wol_opts & VELOCITY_WOL_ARP) - wol->wolopts |= WAKE_ARP; - memcpy(&wol->sopass, vptr->wol_passwd, 6); -} + static int first = 1; + struct net_device *dev; + int i; + const char *drv_string; + const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data]; + struct velocity_info *vptr; + struct mac_regs __iomem *regs; + int ret = -ENOMEM; -static int velocity_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -{ - struct velocity_info *vptr = netdev_priv(dev); + /* FIXME: this driver, like almost all other ethernet drivers, + * can support more than MAX_UNITS. + */ + if (velocity_nics >= MAX_UNITS) { + dev_notice(&pdev->dev, "already found %d NICs.\n", + velocity_nics); + return -ENODEV; + } - if (!(wol->wolopts & (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP))) - return -EFAULT; - vptr->wol_opts = VELOCITY_WOL_MAGIC; + dev = alloc_etherdev(sizeof(struct velocity_info)); + if (!dev) { + dev_err(&pdev->dev, "allocate net device failed.\n"); + goto out; + } - /* - if (wol.wolopts & WAKE_PHY) { - vptr->wol_opts|=VELOCITY_WOL_PHY; - vptr->flags |=VELOCITY_FLAGS_WOL_ENABLED; - } - */ + /* Chain it all together */ - if (wol->wolopts & WAKE_MAGIC) { - vptr->wol_opts |= VELOCITY_WOL_MAGIC; - vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; + SET_NETDEV_DEV(dev, &pdev->dev); + vptr = netdev_priv(dev); + + + if (first) { + printk(KERN_INFO "%s Ver. %s\n", + VELOCITY_FULL_DRV_NAM, VELOCITY_VERSION); + printk(KERN_INFO "Copyright (c) 2002, 2003 VIA Networking Technologies, Inc.\n"); + printk(KERN_INFO "Copyright (c) 2004 Red Hat Inc.\n"); + first = 0; + } + + velocity_init_info(pdev, vptr, info); + + vptr->dev = dev; + + dev->irq = pdev->irq; + + ret = pci_enable_device(pdev); + if (ret < 0) + goto err_free_dev; + + ret = velocity_get_pci_info(vptr, pdev); + if (ret < 0) { + /* error message already printed */ + goto err_disable; } - if (wol->wolopts & WAKE_UCAST) { - vptr->wol_opts |= VELOCITY_WOL_UCAST; - vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; + + ret = pci_request_regions(pdev, VELOCITY_NAME); + if (ret < 0) { + dev_err(&pdev->dev, "No PCI resources.\n"); + goto err_disable; } - if (wol->wolopts & WAKE_ARP) { - vptr->wol_opts |= VELOCITY_WOL_ARP; - vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; + + regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE); + if (regs == NULL) { + ret = -EIO; + goto err_release_res; } - memcpy(vptr->wol_passwd, wol->sopass, 6); - return 0; -} -static u32 velocity_get_msglevel(struct net_device *dev) -{ - return msglevel; -} + vptr->mac_regs = regs; -static void velocity_set_msglevel(struct net_device *dev, u32 value) -{ - msglevel = value; -} + mac_wol_reset(regs); -static const struct ethtool_ops velocity_ethtool_ops = { - .get_settings = velocity_get_settings, - .set_settings = velocity_set_settings, - .get_drvinfo = velocity_get_drvinfo, - .get_wol = velocity_ethtool_get_wol, - .set_wol = velocity_ethtool_set_wol, - .get_msglevel = velocity_get_msglevel, - .set_msglevel = velocity_set_msglevel, - .get_link = velocity_get_link, - .begin = velocity_ethtool_up, - .complete = velocity_ethtool_down -}; + dev->base_addr = vptr->ioaddr; -/** - * velocity_mii_ioctl - MII ioctl handler - * @dev: network device - * @ifr: the ifreq block for the ioctl - * @cmd: the command - * - * Process MII requests made via ioctl from the network layer. These - * are used by tools like kudzu to interrogate the link state of the - * hardware - */ + for (i = 0; i < 6; i++) + dev->dev_addr[i] = readb(®s->PAR[i]); -static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct velocity_info *vptr = netdev_priv(dev); - struct mac_regs __iomem *regs = vptr->mac_regs; - unsigned long flags; - struct mii_ioctl_data *miidata = if_mii(ifr); - int err; - switch (cmd) { - case SIOCGMIIPHY: - miidata->phy_id = readb(®s->MIIADR) & 0x1f; - break; - case SIOCGMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0) - return -ETIMEDOUT; - break; - case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - spin_lock_irqsave(&vptr->lock, flags); - err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in); - spin_unlock_irqrestore(&vptr->lock, flags); - check_connection_type(vptr->mac_regs); - if (err) - return err; - break; - default: - return -EOPNOTSUPP; - } - return 0; -} + drv_string = dev_driver_string(&pdev->dev); -#ifdef CONFIG_PM + velocity_get_options(&vptr->options, velocity_nics, drv_string); -/** - * velocity_save_context - save registers - * @vptr: velocity - * @context: buffer for stored context - * - * Retrieve the current configuration from the velocity hardware - * and stash it in the context structure, for use by the context - * restore functions. This allows us to save things we need across - * power down states - */ + /* + * Mask out the options cannot be set to the chip + */ -static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context) -{ - struct mac_regs __iomem *regs = vptr->mac_regs; - u16 i; - u8 __iomem *ptr = (u8 __iomem *)regs; + vptr->options.flags &= info->flags; - for (i = MAC_REG_PAR; i < MAC_REG_CR0_CLR; i += 4) - *((u32 *) (context->mac_reg + i)) = readl(ptr + i); + /* + * Enable the chip specified capbilities + */ - for (i = MAC_REG_MAR; i < MAC_REG_TDCSR_CLR; i += 4) - *((u32 *) (context->mac_reg + i)) = readl(ptr + i); + vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL); - for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) - *((u32 *) (context->mac_reg + i)) = readl(ptr + i); + vptr->wol_opts = vptr->options.wol_opts; + vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; -} + vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs); -/** - * velocity_restore_context - restore registers - * @vptr: velocity - * @context: buffer for stored context - * - * Reload the register configuration from the velocity context - * created by velocity_save_context. - */ + dev->irq = pdev->irq; + dev->netdev_ops = &velocity_netdev_ops; + dev->ethtool_ops = &velocity_ethtool_ops; -static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context) -{ - struct mac_regs __iomem *regs = vptr->mac_regs; - int i; - u8 __iomem *ptr = (u8 __iomem *)regs; + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | + NETIF_F_HW_VLAN_RX; - for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4) - writel(*((u32 *) (context->mac_reg + i)), ptr + i); + if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) + dev->features |= NETIF_F_IP_CSUM; - /* Just skip cr0 */ - for (i = MAC_REG_CR1_SET; i < MAC_REG_CR0_CLR; i++) { - /* Clear */ - writeb(~(*((u8 *) (context->mac_reg + i))), ptr + i + 4); - /* Set */ - writeb(*((u8 *) (context->mac_reg + i)), ptr + i); + ret = register_netdev(dev); + if (ret < 0) + goto err_iounmap; + + if (!velocity_get_link(dev)) { + netif_carrier_off(dev); + vptr->mii_status |= VELOCITY_LINK_FAIL; } - for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4) - writel(*((u32 *) (context->mac_reg + i)), ptr + i); + velocity_print_info(vptr); + pci_set_drvdata(pdev, dev); - for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) - writel(*((u32 *) (context->mac_reg + i)), ptr + i); + /* and leave the chip powered down */ - for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++) - writeb(*((u8 *) (context->mac_reg + i)), ptr + i); + pci_set_power_state(pdev, PCI_D3hot); +#ifdef CONFIG_PM + { + unsigned long flags; + + spin_lock_irqsave(&velocity_dev_list_lock, flags); + list_add(&vptr->list, &velocity_dev_list); + spin_unlock_irqrestore(&velocity_dev_list_lock, flags); + } +#endif + velocity_nics++; +out: + return ret; + +err_iounmap: + iounmap(regs); +err_release_res: + pci_release_regions(pdev); +err_disable: + pci_disable_device(pdev); +err_free_dev: + free_netdev(dev); + goto out; } + +#ifdef CONFIG_PM /** * wol_calc_crc - WOL CRC * @pattern: data pattern @@ -3213,7 +2814,6 @@ static void velocity_restore_context(struct velocity_info *vptr, struct velocity * Compute the wake on lan crc hashes for the packet header * we are interested in. */ - static u16 wol_calc_crc(int size, u8 *pattern, u8 *mask_pattern) { u16 crc = 0xFFFF; @@ -3250,7 +2850,6 @@ static u16 wol_calc_crc(int size, u8 *pattern, u8 *mask_pattern) * * FIXME: check static buffer is safe here */ - static int velocity_set_wol(struct velocity_info *vptr) { struct mac_regs __iomem *regs = vptr->mac_regs; @@ -3327,6 +2926,33 @@ static int velocity_set_wol(struct velocity_info *vptr) return 0; } +/** + * velocity_save_context - save registers + * @vptr: velocity + * @context: buffer for stored context + * + * Retrieve the current configuration from the velocity hardware + * and stash it in the context structure, for use by the context + * restore functions. This allows us to save things we need across + * power down states + */ +static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context) +{ + struct mac_regs __iomem *regs = vptr->mac_regs; + u16 i; + u8 __iomem *ptr = (u8 __iomem *)regs; + + for (i = MAC_REG_PAR; i < MAC_REG_CR0_CLR; i += 4) + *((u32 *) (context->mac_reg + i)) = readl(ptr + i); + + for (i = MAC_REG_MAR; i < MAC_REG_TDCSR_CLR; i += 4) + *((u32 *) (context->mac_reg + i)) = readl(ptr + i); + + for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) + *((u32 *) (context->mac_reg + i)) = readl(ptr + i); + +} + static int velocity_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); @@ -3354,11 +2980,46 @@ static int velocity_suspend(struct pci_dev *pdev, pm_message_t state) pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); } -#else - pci_set_power_state(pdev, pci_choose_state(pdev, state)); -#endif - spin_unlock_irqrestore(&vptr->lock, flags); - return 0; +#else + pci_set_power_state(pdev, pci_choose_state(pdev, state)); +#endif + spin_unlock_irqrestore(&vptr->lock, flags); + return 0; +} + +/** + * velocity_restore_context - restore registers + * @vptr: velocity + * @context: buffer for stored context + * + * Reload the register configuration from the velocity context + * created by velocity_save_context. + */ +static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context) +{ + struct mac_regs __iomem *regs = vptr->mac_regs; + int i; + u8 __iomem *ptr = (u8 __iomem *)regs; + + for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4) + writel(*((u32 *) (context->mac_reg + i)), ptr + i); + + /* Just skip cr0 */ + for (i = MAC_REG_CR1_SET; i < MAC_REG_CR0_CLR; i++) { + /* Clear */ + writeb(~(*((u8 *) (context->mac_reg + i))), ptr + i + 4); + /* Set */ + writeb(*((u8 *) (context->mac_reg + i)), ptr + i); + } + + for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4) + writel(*((u32 *) (context->mac_reg + i)), ptr + i); + + for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) + writel(*((u32 *) (context->mac_reg + i)), ptr + i); + + for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++) + writeb(*((u8 *) (context->mac_reg + i)), ptr + i); } static int velocity_resume(struct pci_dev *pdev) @@ -3395,9 +3056,190 @@ static int velocity_resume(struct pci_dev *pdev) return 0; } +#endif -#ifdef CONFIG_INET +/* + * Definition for our device driver. The PCI layer interface + * uses this to handle all our card discover and plugging + */ +static struct pci_driver velocity_driver = { + .name = VELOCITY_NAME, + .id_table = velocity_id_table, + .probe = velocity_found1, + .remove = __devexit_p(velocity_remove1), +#ifdef CONFIG_PM + .suspend = velocity_suspend, + .resume = velocity_resume, +#endif +}; + + +/** + * velocity_ethtool_up - pre hook for ethtool + * @dev: network device + * + * Called before an ethtool operation. We need to make sure the + * chip is out of D3 state before we poke at it. + */ +static int velocity_ethtool_up(struct net_device *dev) +{ + struct velocity_info *vptr = netdev_priv(dev); + if (!netif_running(dev)) + pci_set_power_state(vptr->pdev, PCI_D0); + return 0; +} + +/** + * velocity_ethtool_down - post hook for ethtool + * @dev: network device + * + * Called after an ethtool operation. Restore the chip back to D3 + * state if it isn't running. + */ +static void velocity_ethtool_down(struct net_device *dev) +{ + struct velocity_info *vptr = netdev_priv(dev); + if (!netif_running(dev)) + pci_set_power_state(vptr->pdev, PCI_D3hot); +} + +static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct velocity_info *vptr = netdev_priv(dev); + struct mac_regs __iomem *regs = vptr->mac_regs; + u32 status; + status = check_connection_type(vptr->mac_regs); + + cmd->supported = SUPPORTED_TP | + SUPPORTED_Autoneg | + SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full; + if (status & VELOCITY_SPEED_1000) + cmd->speed = SPEED_1000; + else if (status & VELOCITY_SPEED_100) + cmd->speed = SPEED_100; + else + cmd->speed = SPEED_10; + cmd->autoneg = (status & VELOCITY_AUTONEG_ENABLE) ? AUTONEG_ENABLE : AUTONEG_DISABLE; + cmd->port = PORT_TP; + cmd->transceiver = XCVR_INTERNAL; + cmd->phy_address = readb(®s->MIIADR) & 0x1F; + + if (status & VELOCITY_DUPLEX_FULL) + cmd->duplex = DUPLEX_FULL; + else + cmd->duplex = DUPLEX_HALF; + + return 0; +} + +static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct velocity_info *vptr = netdev_priv(dev); + u32 curr_status; + u32 new_status = 0; + int ret = 0; + + curr_status = check_connection_type(vptr->mac_regs); + curr_status &= (~VELOCITY_LINK_FAIL); + + new_status |= ((cmd->autoneg) ? VELOCITY_AUTONEG_ENABLE : 0); + new_status |= ((cmd->speed == SPEED_100) ? VELOCITY_SPEED_100 : 0); + new_status |= ((cmd->speed == SPEED_10) ? VELOCITY_SPEED_10 : 0); + new_status |= ((cmd->duplex == DUPLEX_FULL) ? VELOCITY_DUPLEX_FULL : 0); + + if ((new_status & VELOCITY_AUTONEG_ENABLE) && (new_status != (curr_status | VELOCITY_AUTONEG_ENABLE))) + ret = -EINVAL; + else + velocity_set_media_mode(vptr, new_status); + + return ret; +} + +static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + struct velocity_info *vptr = netdev_priv(dev); + strcpy(info->driver, VELOCITY_NAME); + strcpy(info->version, VELOCITY_VERSION); + strcpy(info->bus_info, pci_name(vptr->pdev)); +} + +static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct velocity_info *vptr = netdev_priv(dev); + wol->supported = WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP; + wol->wolopts |= WAKE_MAGIC; + /* + if (vptr->wol_opts & VELOCITY_WOL_PHY) + wol.wolopts|=WAKE_PHY; + */ + if (vptr->wol_opts & VELOCITY_WOL_UCAST) + wol->wolopts |= WAKE_UCAST; + if (vptr->wol_opts & VELOCITY_WOL_ARP) + wol->wolopts |= WAKE_ARP; + memcpy(&wol->sopass, vptr->wol_passwd, 6); +} + +static int velocity_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct velocity_info *vptr = netdev_priv(dev); + + if (!(wol->wolopts & (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP))) + return -EFAULT; + vptr->wol_opts = VELOCITY_WOL_MAGIC; + + /* + if (wol.wolopts & WAKE_PHY) { + vptr->wol_opts|=VELOCITY_WOL_PHY; + vptr->flags |=VELOCITY_FLAGS_WOL_ENABLED; + } + */ + + if (wol->wolopts & WAKE_MAGIC) { + vptr->wol_opts |= VELOCITY_WOL_MAGIC; + vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; + } + if (wol->wolopts & WAKE_UCAST) { + vptr->wol_opts |= VELOCITY_WOL_UCAST; + vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; + } + if (wol->wolopts & WAKE_ARP) { + vptr->wol_opts |= VELOCITY_WOL_ARP; + vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; + } + memcpy(vptr->wol_passwd, wol->sopass, 6); + return 0; +} + +static u32 velocity_get_msglevel(struct net_device *dev) +{ + return msglevel; +} + +static void velocity_set_msglevel(struct net_device *dev, u32 value) +{ + msglevel = value; +} + +static const struct ethtool_ops velocity_ethtool_ops = { + .get_settings = velocity_get_settings, + .set_settings = velocity_set_settings, + .get_drvinfo = velocity_get_drvinfo, + .get_wol = velocity_ethtool_get_wol, + .set_wol = velocity_ethtool_set_wol, + .get_msglevel = velocity_get_msglevel, + .set_msglevel = velocity_set_msglevel, + .get_link = velocity_get_link, + .begin = velocity_ethtool_up, + .complete = velocity_ethtool_down +}; +#ifdef CONFIG_PM +#ifdef CONFIG_INET static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr) { struct in_ifaddr *ifa = (struct in_ifaddr *) ptr; @@ -3419,6 +3261,63 @@ static int velocity_netdev_event(struct notifier_block *nb, unsigned long notifi return NOTIFY_DONE; } +#endif /* CONFIG_INET */ +#endif /* CONFIG_PM */ -#endif -#endif +#if defined(CONFIG_PM) && defined(CONFIG_INET) +static struct notifier_block velocity_inetaddr_notifier = { + .notifier_call = velocity_netdev_event, +}; + +static void velocity_register_notifier(void) +{ + register_inetaddr_notifier(&velocity_inetaddr_notifier); +} + +static void velocity_unregister_notifier(void) +{ + unregister_inetaddr_notifier(&velocity_inetaddr_notifier); +} + +#else + +#define velocity_register_notifier() do {} while (0) +#define velocity_unregister_notifier() do {} while (0) + +#endif /* defined(CONFIG_PM) && defined(CONFIG_INET) */ + +/** + * velocity_init_module - load time function + * + * Called when the velocity module is loaded. The PCI driver + * is registered with the PCI layer, and in turn will call + * the probe functions for each velocity adapter installed + * in the system. + */ +static int __init velocity_init_module(void) +{ + int ret; + + velocity_register_notifier(); + ret = pci_register_driver(&velocity_driver); + if (ret < 0) + velocity_unregister_notifier(); + return ret; +} + +/** + * velocity_cleanup - module unload + * + * When the velocity hardware is unloaded this function is called. + * It will clean up the notifiers and the unregister the PCI + * driver interface for this hardware. This in turn cleans up + * all discovered interfaces before returning from the function + */ +static void __exit velocity_cleanup_module(void) +{ + velocity_unregister_notifier(); + pci_unregister_driver(&velocity_driver); +} + +module_init(velocity_init_module); +module_exit(velocity_cleanup_module); -- cgit v1.2.3-18-g5258 From 5a6338db37885af06760d40cad589316e48431e9 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 20 Jul 2009 17:40:48 +0000 Subject: Fix typos in comments in via-velocity header. Signed-off-by: Dave Jones Signed-off-by: David S. Miller --- drivers/net/via-velocity.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h index 4cd3f6c9737..2f00c13ab50 100644 --- a/drivers/net/via-velocity.h +++ b/drivers/net/via-velocity.h @@ -96,8 +96,8 @@ * Bits in the CSM register */ -#define CSM_IPOK 0x40 //IP Checkusm validatiaon ok -#define CSM_TUPOK 0x20 //TCP/UDP Checkusm validatiaon ok +#define CSM_IPOK 0x40 //IP Checksum validation ok +#define CSM_TUPOK 0x20 //TCP/UDP Checksum validation ok #define CSM_FRAG 0x10 //Fragment IP datagram #define CSM_IPKT 0x04 //Received an IP packet #define CSM_TCPKT 0x02 //Received a TCP packet @@ -819,7 +819,7 @@ enum velocity_owner { * Bits in the EECSR register */ -#define EECSR_EMBP 0x40 /* eeprom embeded programming */ +#define EECSR_EMBP 0x40 /* eeprom embedded programming */ #define EECSR_RELOAD 0x20 /* eeprom content reload */ #define EECSR_DPM 0x10 /* eeprom direct programming */ #define EECSR_ECS 0x08 /* eeprom CS pin */ -- cgit v1.2.3-18-g5258 From e0f114e82e3781087a0ad0e92c94ff0d55012c1a Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 7 Jul 2009 19:08:07 +0200 Subject: p54: re-enable power save feature This patch re-enables p54's power save features and adds a workaround which temporarily alters the device's power state in order to allow ps-polls to be sent and buffered data to be retrieved during psm. (Incorporates patch originally posted as "p54: fix beacon template dtim IE corruption". -- JWL) Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/fwio.c | 7 ++-- drivers/net/wireless/p54/lmac.h | 3 ++ drivers/net/wireless/p54/main.c | 77 +++++++++++++++++++++++++---------------- drivers/net/wireless/p54/p54.h | 1 + drivers/net/wireless/p54/txrx.c | 42 ++++++++++++++++++++++ 5 files changed, 98 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index dc4f3f5ee0c..349375f4a14 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c @@ -585,7 +585,8 @@ int p54_set_ps(struct p54_common *priv) unsigned int i; u16 mode; - if (priv->hw->conf.flags & IEEE80211_CONF_PS) + if (priv->hw->conf.flags & IEEE80211_CONF_PS && + !priv->powersave_override) mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM | P54_PSM_CHECKSUM | P54_PSM_MCBC; else @@ -607,8 +608,8 @@ int p54_set_ps(struct p54_common *priv) psm->beacon_rssi_skip_max = 200; psm->rssi_delta_threshold = 0; - psm->nr = 10; - psm->exclude[0] = 0; + psm->nr = 1; + psm->exclude[0] = WLAN_EID_TIM; p54_tx(priv, skb); return 0; diff --git a/drivers/net/wireless/p54/lmac.h b/drivers/net/wireless/p54/lmac.h index 0496cff26b3..af35cfcd4fe 100644 --- a/drivers/net/wireless/p54/lmac.h +++ b/drivers/net/wireless/p54/lmac.h @@ -548,4 +548,7 @@ int p54_upload_key(struct p54_common *priv, u8 algo, int slot, int p54_download_eeprom(struct p54_common *priv, void *buf, u16 offset, u16 len); +/* utility */ +u8 *p54_find_ie(struct sk_buff *skb, u8 ie); + #endif /* LMAC_H */ diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index f9b4f6a238e..c9a054548d9 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -65,51 +65,64 @@ static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, return p54_update_beacon_tim(priv, sta->aid, set); } -static int p54_beacon_format_ie_tim(struct sk_buff *skb) +u8 *p54_find_ie(struct sk_buff *skb, u8 ie) { - /* - * the good excuse for this mess is ... the firmware. - * The dummy TIM MUST be at the end of the beacon frame, - * because it'll be overwritten! - */ - struct ieee80211_mgmt *mgmt = (void *)skb->data; u8 *pos, *end; if (skb->len <= sizeof(mgmt)) - return -EINVAL; + return NULL; pos = (u8 *)mgmt->u.beacon.variable; end = skb->data + skb->len; while (pos < end) { if (pos + 2 + pos[1] > end) - return -EINVAL; + return NULL; - if (pos[0] == WLAN_EID_TIM) { - u8 dtim_len = pos[1]; - u8 dtim_period = pos[3]; - u8 *next = pos + 2 + dtim_len; + if (pos[0] == ie) + return pos; - if (dtim_len < 3) - return -EINVAL; + pos += 2 + pos[1]; + } + return NULL; +} - memmove(pos, next, end - next); +static int p54_beacon_format_ie_tim(struct sk_buff *skb) +{ + /* + * the good excuse for this mess is ... the firmware. + * The dummy TIM MUST be at the end of the beacon frame, + * because it'll be overwritten! + */ + u8 *tim; + u8 dtim_len; + u8 dtim_period; + u8 *next; - if (dtim_len > 3) - skb_trim(skb, skb->len - (dtim_len - 3)); + tim = p54_find_ie(skb, WLAN_EID_TIM); + if (!tim) + return 0; - pos = end - (dtim_len + 2); + dtim_len = tim[1]; + dtim_period = tim[3]; + next = tim + 2 + dtim_len; + + if (dtim_len < 3) + return -EINVAL; + + memmove(tim, next, skb_tail_pointer(skb) - next); + tim = skb_tail_pointer(skb) - (dtim_len + 2); + + /* add the dummy at the end */ + tim[0] = WLAN_EID_TIM; + tim[1] = 3; + tim[2] = 0; + tim[3] = dtim_period; + tim[4] = 0; + + if (dtim_len > 3) + skb_trim(skb, skb->len - (dtim_len - 3)); - /* add the dummy at the end */ - pos[0] = WLAN_EID_TIM; - pos[1] = 3; - pos[2] = 0; - pos[3] = dtim_period; - pos[4] = 0; - return 0; - } - pos += 2 + pos[1]; - } return 0; } @@ -384,6 +397,9 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev, priv->wakeup_timer = info->beacon_int * info->dtim_period * 5; p54_setup_mac(priv); + } else { + priv->wakeup_timer = 500; + priv->aid = 0; } } @@ -517,6 +533,9 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) skb_queue_head_init(&priv->tx_pending); dev->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_PS_NULLFUNC_STACK | + IEEE80211_HW_BEACON_FILTER | IEEE80211_HW_NOISE_DBM; dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 19d085c73d7..6772ed505d4 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -208,6 +208,7 @@ struct p54_common { u32 tsf_low32, tsf_high32; u32 basic_rate_mask; u16 aid; + bool powersave_override; __le32 beacon_req_id; /* cryptographic engine information */ diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 6426d2cae6d..01eadb1683f 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -288,6 +288,45 @@ static int p54_rssi_to_dbm(struct p54_common *priv, int rssi) priv->rssical_db[band].add) / 4; } +/* + * Even if the firmware is capable of dealing with incoming traffic, + * while dozing, we have to prepared in case mac80211 uses PS-POLL + * to retrieve outstanding frames from our AP. + * (see comment in net/mac80211/mlme.c @ line 1993) + */ +static void p54_pspoll_workaround(struct p54_common *priv, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (void *) skb->data; + struct ieee80211_tim_ie *tim_ie; + u8 *tim; + u8 tim_len; + bool new_psm; + + /* only beacons have a TIM IE */ + if (!ieee80211_is_beacon(hdr->frame_control)) + return; + + if (!priv->aid) + return; + + /* only consider beacons from the associated BSSID */ + if (compare_ether_addr(hdr->addr3, priv->bssid)) + return; + + tim = p54_find_ie(skb, WLAN_EID_TIM); + if (!tim) + return; + + tim_len = tim[1]; + tim_ie = (struct ieee80211_tim_ie *) &tim[2]; + + new_psm = ieee80211_check_tim(tim_ie, tim_len, priv->aid); + if (new_psm != priv->powersave_override) { + priv->powersave_override = new_psm; + p54_set_ps(priv); + } +} + static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb) { struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data; @@ -340,6 +379,9 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb) skb_pull(skb, header_len); skb_trim(skb, le16_to_cpu(hdr->len)); + if (unlikely(priv->hw->conf.flags & IEEE80211_CONF_PS)) + p54_pspoll_workaround(priv, skb); + ieee80211_rx_irqsafe(priv->hw, skb); queue_delayed_work(priv->hw->workqueue, &priv->work, -- cgit v1.2.3-18-g5258 From f874011bb01e7fb19904db7f739bb343a0a53fd5 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Wed, 8 Jul 2009 22:03:13 +0200 Subject: wireless: fix supported cards for rtl8187 Different revisions of WUSB54GC-EU use different chipsets - v2 uses rtl8187, but v3 uses Ralink RT3070. Signed-off-by: Marcin Slusarz Cc: Przemyslaw Kulczycki Cc: John W. Linville Cc: Linux wireless Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 5bc00db21b2..7d5902d1349 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -431,7 +431,7 @@ config RTL8187 ASUS P5B Deluxe Toshiba Satellite Pro series of laptops Asus Wireless Link - Linksys WUSB54GC-EU + Linksys WUSB54GC-EU v2 Thanks to Realtek for their support! -- cgit v1.2.3-18-g5258 From f5ad69fa47e7b204d0032d569812544cd9a351fb Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 9 Jul 2009 10:33:36 -0700 Subject: iwlwifi: move show_qos to debugfs This move the show_qos file from sysfs to debugfs because the "one value per file" sysfs rule. The file is located in /sys/kernel/debug/ieee80211/phy0/iwlagn/data Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 21 --------------------- drivers/net/wireless/iwlwifi/iwl-debug.h | 1 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 25 +++++++++++++++++++++++++ 3 files changed, 26 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index e2cc5994d10..ad5002211ab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2627,26 +2627,6 @@ static ssize_t show_power_level(struct device *d, static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, store_power_level); -static ssize_t show_qos(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - char *p = buf; - int q; - - for (q = 0; q < AC_NUM; q++) { - p += sprintf(p, "\tcw_min\tcw_max\taifsn\ttxop\n"); - p += sprintf(p, "AC[%d]\t%u\t%u\t%u\t%u\n", q, - priv->qos_data.def_qos_parm.ac[q].cw_min, - priv->qos_data.def_qos_parm.ac[q].cw_max, - priv->qos_data.def_qos_parm.ac[q].aifsn, - priv->qos_data.def_qos_parm.ac[q].edca_txop); - } - - return p - buf + 1; -} - -static DEVICE_ATTR(qos, S_IRUGO, show_qos, NULL); static ssize_t show_statistics(struct device *d, struct device_attribute *attr, char *buf) @@ -2747,7 +2727,6 @@ static struct attribute *iwl_sysfs_entries[] = { &dev_attr_debug_level.attr, #endif &dev_attr_version.attr, - &dev_attr_qos.attr, NULL }; diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 65bbce0f171..1555676fc51 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -82,6 +82,7 @@ struct iwl_debugfs { struct dentry *file_channels; struct dentry *file_status; struct dentry *file_interrupt; + struct dentry *file_qos; } dbgfs_data_files; struct dir_rf_files { struct dentry *file_disable_sensitivity; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index f32ac74b69a..e38ec81b839 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -566,6 +566,28 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file, return count; } +static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0, i; + char buf[256]; + const size_t bufsz = sizeof(buf); + ssize_t ret; + + for (i = 0; i < AC_NUM; i++) { + pos += scnprintf(buf + pos, bufsz - pos, + "\tcw_min\tcw_max\taifsn\ttxop\n"); + pos += scnprintf(buf + pos, bufsz - pos, + "AC[%d]\t%u\t%u\t%u\t%u\n", i, + priv->qos_data.def_qos_parm.ac[i].cw_min, + priv->qos_data.def_qos_parm.ac[i].cw_max, + priv->qos_data.def_qos_parm.ac[i].aifsn, + priv->qos_data.def_qos_parm.ac[i].edca_txop); + } + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + return ret; +} DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_WRITE_FILE_OPS(log_event); @@ -576,6 +598,7 @@ DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_FILE_OPS(channels); DEBUGFS_READ_FILE_OPS(status); DEBUGFS_READ_WRITE_FILE_OPS(interrupt); +DEBUGFS_READ_FILE_OPS(qos); /* * Create the debugfs files and directories @@ -612,6 +635,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(channels, data); DEBUGFS_ADD_FILE(status, data); DEBUGFS_ADD_FILE(interrupt, data); + DEBUGFS_ADD_FILE(qos, data); DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); @@ -646,6 +670,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_qos); DEBUGFS_REMOVE(priv->dbgfs->dir_data); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); -- cgit v1.2.3-18-g5258 From fcf89d05404dafcde581d44dfa89bd8c8def27f9 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Thu, 9 Jul 2009 10:33:38 -0700 Subject: iwlwifi: fix permissions on debugfs files debugfs files are created with 644 permissions which gives everybody read access. This presents a security issue if a user opens the file and holds it open at the time the driver removes the file. At this point invalid memory will be accessed. Fix this by only allowing root to read debugfs files. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index e38ec81b839..0b9e824b67c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -49,7 +49,8 @@ #define DEBUGFS_ADD_FILE(name, parent) do { \ dbgfs->dbgfs_##parent##_files.file_##name = \ - debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv, \ + debugfs_create_file(#name, S_IWUSR | S_IRUSR, \ + dbgfs->dir_##parent, priv, \ &iwl_dbgfs_##name##_ops); \ if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \ goto err; \ @@ -57,7 +58,8 @@ #define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \ dbgfs->dbgfs_##parent##_files.file_##name = \ - debugfs_create_bool(#name, 0644, dbgfs->dir_##parent, ptr); \ + debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \ + dbgfs->dir_##parent, ptr); \ if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \ || !dbgfs->dbgfs_##parent##_files.file_##name) \ goto err; \ @@ -65,7 +67,7 @@ #define DEBUGFS_ADD_X32(name, parent, ptr) do { \ dbgfs->dbgfs_##parent##_files.file_##name = \ - debugfs_create_x32(#name, 0444, dbgfs->dir_##parent, ptr); \ + debugfs_create_x32(#name, S_IRUSR, dbgfs->dir_##parent, ptr); \ if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \ || !dbgfs->dbgfs_##parent##_files.file_##name) \ goto err; \ -- cgit v1.2.3-18-g5258 From 5905a1aa71488b5f78822100c865ed7c4f9fcd8f Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Thu, 9 Jul 2009 10:33:40 -0700 Subject: iwl3945: cleanup number of queues settings * Rename maximum number of queue (TFD_QUEUE_MAX) to IWL39_NUM_QUEUES to be consistent with rest of iwlwifi. * Remove unused defines. * Fix loops that iterate over number of TX queues to stop when maximum is reached (currently it is maximum + 1). * Remove queues_num module parameter as it is not used. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-hw.h | 7 ++----- drivers/net/wireless/iwlwifi/iwl-3945.c | 8 ++++---- drivers/net/wireless/iwlwifi/iwl-3945.h | 3 --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 15 +-------------- 4 files changed, 7 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index 73f93a0ff2d..b569c6f38e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -232,9 +232,8 @@ struct iwl3945_eeprom { #define PCI_CFG_REV_ID_BIT_BASIC_SKU (0x40) /* bit 6 */ #define PCI_CFG_REV_ID_BIT_RTP (0x80) /* bit 7 */ -#define TFD_QUEUE_MIN 0 -#define TFD_QUEUE_MAX 5 /* 4 DATA + 1 CMD */ - +/* 4 DATA + 1 CMD. There are 2 HCCA queues that are not used. */ +#define IWL39_NUM_QUEUES 5 #define IWL_NUM_SCAN_RATES (2) #define IWL_DEFAULT_TX_RETRY 15 @@ -280,8 +279,6 @@ struct iwl3945_eeprom { /* Size of uCode instruction memory in bootstrap state machine */ #define IWL39_MAX_BSM_SIZE IWL39_RTC_INST_SIZE -#define IWL39_MAX_NUM_QUEUES 8 - static inline int iwl3945_hw_valid_rtc_data_addr(u32 addr) { return (addr >= IWL39_RTC_DATA_LOWER_BOUND) && diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index b0246dbda99..1227ed2960f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -963,7 +963,7 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv) goto error; /* Tx queue(s) */ - for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) { + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num, @@ -1140,7 +1140,7 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv) int txq_id; /* Tx queues */ - for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) if (txq_id == IWL_CMD_QUEUE_NUM) iwl_cmd_queue_free(priv); else @@ -1156,7 +1156,7 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) iwl_write_prph(priv, ALM_SCD_MODE_REG, 0); /* reset TFD queues */ - for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) { + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { iwl_write_direct32(priv, FH39_TCSR_CONFIG(txq_id), 0x0); iwl_poll_direct_bit(priv, FH39_TSSR_TX_STATUS, FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id), @@ -2552,7 +2552,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv) } /* Assign number of Usable TX queues */ - priv->hw_params.max_txq_num = TFD_QUEUE_MAX; + priv->hw_params.max_txq_num = IWL39_NUM_QUEUES; priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd); priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index fbb3a573463..f2ffc48cbaf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -111,9 +111,6 @@ enum iwl3945_antenna { #define IWL_TX_FIFO_HCCA_2 6 #define IWL_TX_FIFO_NONE 7 -/* Minimum number of queues. MAX_NUM is defined in hw specific files */ -#define IWL_MIN_NUM_QUEUES 4 - #define IEEE80211_DATA_LEN 2304 #define IEEE80211_4ADDR_LEN 30 #define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 7ff95f80b81..c9b3ea92714 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -89,7 +89,7 @@ MODULE_LICENSE("GPL"); /* module parameters */ struct iwl_mod_params iwl3945_mod_params = { - .num_of_queues = IWL39_MAX_NUM_QUEUES, + .num_of_queues = IWL39_NUM_QUEUES, /* Not used */ .sw_crypto = 1, .restart_fw = 1, /* the rest are 0 by default */ @@ -3947,15 +3947,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv = hw->priv; SET_IEEE80211_DEV(hw, &pdev->dev); - if ((iwl3945_mod_params.num_of_queues > IWL39_MAX_NUM_QUEUES) || - (iwl3945_mod_params.num_of_queues < IWL_MIN_NUM_QUEUES)) { - IWL_ERR(priv, - "invalid queues_num, should be between %d and %d\n", - IWL_MIN_NUM_QUEUES, IWL39_MAX_NUM_QUEUES); - err = -EINVAL; - goto out_ieee80211_free_hw; - } - /* * Disabling hardware scan means that mac80211 will perform scans * "the hard way", rather than using device's scan. @@ -4272,10 +4263,6 @@ module_param_named(debug, iwl3945_mod_params.debug, uint, 0444); MODULE_PARM_DESC(debug, "debug output mask"); module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, int, 0444); MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); - -module_param_named(queues_num, iwl3945_mod_params.num_of_queues, int, 0444); -MODULE_PARM_DESC(queues_num, "number of hw queues."); - module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, 0444); MODULE_PARM_DESC(fw_restart3945, "restart firmware in case of error"); -- cgit v1.2.3-18-g5258 From 01a7e08436929271c6173b5daf3e193ef5b3561a Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Thu, 9 Jul 2009 10:33:41 -0700 Subject: iwlagn: fix minimum number of queues setting We need to provide a reasonable minimum that will result in a working setup if used. Set minimum to be 10 to provide for 4 standard TX queues + 1 command queue + 2 (unused) HCCA queues + 4 HT queues (one per AC). We allow the user to change the number of queues used via a module parameter and use this minimum value to check if it is valid. Without this patch a user can select a value for the number of queues that will result in a failing setup. Signed-off-by: Reinette Chatre Reviewed-by: Tomas Winkler Acked-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-dev.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1a2fe37d473..b989d5c08d3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -258,8 +258,10 @@ struct iwl_channel_info { #define IWL_TX_FIFO_HCCA_2 6 #define IWL_TX_FIFO_NONE 7 -/* Minimum number of queues. MAX_NUM is defined in hw specific files */ -#define IWL_MIN_NUM_QUEUES 4 +/* Minimum number of queues. MAX_NUM is defined in hw specific files. + * Set the minimum to accommodate the 4 standard TX queues, 1 command + * queue, 2 (unused) HCCA queues, and 4 HT queues (one for each AC) */ +#define IWL_MIN_NUM_QUEUES 10 /* Power management (not Tx power) structures */ -- cgit v1.2.3-18-g5258 From 4b14c96dfbf068acb85c3fa2446b3949c0230deb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 16:56:59 +0200 Subject: mac80211_hwsim: report fixed signal strength There's no reason to think that hwsim has any actual signal strength, but for testing it is very useful to have it report _some_ value to the stack so I can see if the value ends up being reported correctly Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index e9b5442f1dd..78431abc8b4 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -406,7 +406,8 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, rx_status.freq = data->channel->center_freq; rx_status.band = data->channel->band; rx_status.rate_idx = info->control.rates[0].idx; - /* TODO: simulate signal strength (and optional packet drop) */ + /* TODO: simulate real signal strength (and optional packet loss) */ + rx_status.signal = -50; if (data->ps != PS_DISABLED) hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); @@ -1024,7 +1025,8 @@ static int __init init_mac80211_hwsim(void) BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MESH_POINT); - hw->flags = IEEE80211_HW_MFP_CAPABLE; + hw->flags = IEEE80211_HW_MFP_CAPABLE | + IEEE80211_HW_SIGNAL_DBM; /* ask mac80211 to reserve space for magic */ hw->vif_data_size = sizeof(struct hwsim_vif_priv); -- cgit v1.2.3-18-g5258 From 930c06f27120fa8cf0bfb6fa000a701cfaf01ed6 Mon Sep 17 00:00:00 2001 From: Stefan Steuerwald Date: Fri, 10 Jul 2009 20:42:55 +0200 Subject: rt2x00: Implement set_tim callback for all drivers Implement set_tim callback for all rt2x00 drivers, this makes the device wake up powersaving stations properly while in AP mode. The only way to update the beacon is by simply calling mac80211 and requesting the new beacon. This means the set_tim() event is mostly the same as a beacon_done() event which was already defined in rt2x00lib. Signed-off-by: Stefan Steuerwald Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 1 + drivers/net/wireless/rt2x00/rt2500pci.c | 1 + drivers/net/wireless/rt2x00/rt2500usb.c | 1 + drivers/net/wireless/rt2x00/rt2800usb.c | 1 + drivers/net/wireless/rt2x00/rt2x00.h | 2 ++ drivers/net/wireless/rt2x00/rt2x00mac.c | 10 ++++++++++ drivers/net/wireless/rt2x00/rt61pci.c | 1 + drivers/net/wireless/rt2x00/rt73usb.c | 1 + 8 files changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index d8035e3575e..30185ad28d9 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1561,6 +1561,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .configure_filter = rt2x00mac_configure_filter, + .set_tim = rt2x00mac_set_tim, .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2400pci_conf_tx, diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index c123e28396d..3b3171578b1 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1860,6 +1860,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .configure_filter = rt2x00mac_configure_filter, + .set_tim = rt2x00mac_set_tim, .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 00611b32d08..de48c5c68ef 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1896,6 +1896,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .configure_filter = rt2x00mac_configure_filter, + .set_tim = rt2x00mac_set_tim, .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index a204e66753c..66e001c392b 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -2786,6 +2786,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = { .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .configure_filter = rt2x00mac_configure_filter, + .set_tim = rt2x00mac_set_tim, .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, .get_tkip_seq = rt2800usb_get_tkip_seq, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 71f37cb476b..3e177175e34 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -963,6 +963,8 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, int mc_count, struct dev_addr_list *mc_list); +int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + bool set); #ifdef CONFIG_RT2X00_LIB_CRYPTO int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index b7e0ddda38f..3425984a55c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -454,6 +454,16 @@ static void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len) sizeof(crypto->rx_mic)); } +int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + bool set) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + rt2x00lib_beacondone(rt2x00dev); + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_set_tim); + int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 8a49d99df68..b435c140cb9 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2716,6 +2716,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .configure_filter = rt2x00mac_configure_filter, + .set_tim = rt2x00mac_set_tim, .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index ad2898ca867..4f9b1772e1a 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2241,6 +2241,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .configure_filter = rt2x00mac_configure_filter, + .set_tim = rt2x00mac_set_tim, .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, -- cgit v1.2.3-18-g5258 From 1a9b6679adfb8ef1f1f3dbb7ebd2ee72e2ea4b56 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 11 Jul 2009 01:22:26 +0200 Subject: p54: generate channel list dynamically This patch enhances the eeprom parser to generate customized channel list for every device. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/eeprom.c | 323 ++++++++++++++++++++++++++++++-------- drivers/net/wireless/p54/main.c | 4 + drivers/net/wireless/p54/p54.h | 1 + 3 files changed, 261 insertions(+), 67 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c index a2a044ef101..549ef2d19cd 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -41,30 +42,6 @@ static struct ieee80211_rate p54_bgrates[] = { { .bitrate = 540, .hw_value = 11, }, }; -static struct ieee80211_channel p54_bgchannels[] = { - { .center_freq = 2412, .hw_value = 1, }, - { .center_freq = 2417, .hw_value = 2, }, - { .center_freq = 2422, .hw_value = 3, }, - { .center_freq = 2427, .hw_value = 4, }, - { .center_freq = 2432, .hw_value = 5, }, - { .center_freq = 2437, .hw_value = 6, }, - { .center_freq = 2442, .hw_value = 7, }, - { .center_freq = 2447, .hw_value = 8, }, - { .center_freq = 2452, .hw_value = 9, }, - { .center_freq = 2457, .hw_value = 10, }, - { .center_freq = 2462, .hw_value = 11, }, - { .center_freq = 2467, .hw_value = 12, }, - { .center_freq = 2472, .hw_value = 13, }, - { .center_freq = 2484, .hw_value = 14, }, -}; - -static struct ieee80211_supported_band band_2GHz = { - .channels = p54_bgchannels, - .n_channels = ARRAY_SIZE(p54_bgchannels), - .bitrates = p54_bgrates, - .n_bitrates = ARRAY_SIZE(p54_bgrates), -}; - static struct ieee80211_rate p54_arates[] = { { .bitrate = 60, .hw_value = 4, }, { .bitrate = 90, .hw_value = 5, }, @@ -76,51 +53,257 @@ static struct ieee80211_rate p54_arates[] = { { .bitrate = 540, .hw_value = 11, }, }; -static struct ieee80211_channel p54_achannels[] = { - { .center_freq = 4920 }, - { .center_freq = 4940 }, - { .center_freq = 4960 }, - { .center_freq = 4980 }, - { .center_freq = 5040 }, - { .center_freq = 5060 }, - { .center_freq = 5080 }, - { .center_freq = 5170 }, - { .center_freq = 5180 }, - { .center_freq = 5190 }, - { .center_freq = 5200 }, - { .center_freq = 5210 }, - { .center_freq = 5220 }, - { .center_freq = 5230 }, - { .center_freq = 5240 }, - { .center_freq = 5260 }, - { .center_freq = 5280 }, - { .center_freq = 5300 }, - { .center_freq = 5320 }, - { .center_freq = 5500 }, - { .center_freq = 5520 }, - { .center_freq = 5540 }, - { .center_freq = 5560 }, - { .center_freq = 5580 }, - { .center_freq = 5600 }, - { .center_freq = 5620 }, - { .center_freq = 5640 }, - { .center_freq = 5660 }, - { .center_freq = 5680 }, - { .center_freq = 5700 }, - { .center_freq = 5745 }, - { .center_freq = 5765 }, - { .center_freq = 5785 }, - { .center_freq = 5805 }, - { .center_freq = 5825 }, +#define CHAN_HAS_CAL BIT(0) +#define CHAN_HAS_LIMIT BIT(1) +#define CHAN_HAS_CURVE BIT(2) +#define CHAN_HAS_ALL (CHAN_HAS_CAL | CHAN_HAS_LIMIT | CHAN_HAS_CURVE) + +struct p54_channel_entry { + u16 freq; + u16 data; + int index; + enum ieee80211_band band; }; -static struct ieee80211_supported_band band_5GHz = { - .channels = p54_achannels, - .n_channels = ARRAY_SIZE(p54_achannels), - .bitrates = p54_arates, - .n_bitrates = ARRAY_SIZE(p54_arates), +struct p54_channel_list { + struct p54_channel_entry *channels; + size_t entries; + size_t max_entries; + size_t band_channel_num[IEEE80211_NUM_BANDS]; }; +static int p54_get_band_from_freq(u16 freq) +{ + /* FIXME: sync these values with the 802.11 spec */ + + if ((freq >= 2412) && (freq <= 2484)) + return IEEE80211_BAND_2GHZ; + + if ((freq >= 4920) && (freq <= 5825)) + return IEEE80211_BAND_5GHZ; + + return -1; +} + +static int p54_compare_channels(const void *_a, + const void *_b) +{ + const struct p54_channel_entry *a = _a; + const struct p54_channel_entry *b = _b; + + return a->index - b->index; +} + +static int p54_fill_band_bitrates(struct ieee80211_hw *dev, + struct ieee80211_supported_band *band_entry, + enum ieee80211_band band) +{ + /* TODO: generate rate array dynamically */ + + switch (band) { + case IEEE80211_BAND_2GHZ: + band_entry->bitrates = p54_bgrates; + band_entry->n_bitrates = ARRAY_SIZE(p54_bgrates); + break; + case IEEE80211_BAND_5GHZ: + band_entry->bitrates = p54_arates; + band_entry->n_bitrates = ARRAY_SIZE(p54_arates); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int p54_generate_band(struct ieee80211_hw *dev, + struct p54_channel_list *list, + enum ieee80211_band band) +{ + struct p54_common *priv = dev->priv; + struct ieee80211_supported_band *tmp, *old; + unsigned int i, j; + int ret = -ENOMEM; + + if ((!list->entries) || (!list->band_channel_num[band])) + return 0; + + tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) + goto err_out; + + tmp->channels = kzalloc(sizeof(struct ieee80211_channel) * + list->band_channel_num[band], GFP_KERNEL); + if (!tmp->channels) + goto err_out; + + ret = p54_fill_band_bitrates(dev, tmp, band); + if (ret) + goto err_out; + + for (i = 0, j = 0; (j < list->band_channel_num[band]) && + (i < list->entries); i++) { + + if (list->channels[i].band != band) + continue; + + if (list->channels[i].data != CHAN_HAS_ALL) { + printk(KERN_ERR "%s:%s%s%s is/are missing for " + "channel:%d [%d MHz].\n", + wiphy_name(dev->wiphy), + (list->channels[i].data & CHAN_HAS_CAL ? "" : + " [iqauto calibration data]"), + (list->channels[i].data & CHAN_HAS_LIMIT ? "" : + " [output power limits]"), + (list->channels[i].data & CHAN_HAS_CURVE ? "" : + " [curve data]"), + list->channels[i].index, list->channels[i].freq); + } + + tmp->channels[j].band = list->channels[i].band; + tmp->channels[j].center_freq = list->channels[i].freq; + j++; + } + + tmp->n_channels = list->band_channel_num[band]; + old = priv->band_table[band]; + priv->band_table[band] = tmp; + if (old) { + kfree(old->channels); + kfree(old); + } + + return 0; + +err_out: + if (tmp) { + kfree(tmp->channels); + kfree(tmp); + } + + return ret; +} + +static void p54_update_channel_param(struct p54_channel_list *list, + u16 freq, u16 data) +{ + int band, i; + + /* + * usually all lists in the eeprom are mostly sorted. + * so it's very likely that the entry we are looking for + * is right at the end of the list + */ + for (i = list->entries; i >= 0; i--) { + if (freq == list->channels[i].freq) { + list->channels[i].data |= data; + break; + } + } + + if ((i < 0) && (list->entries < list->max_entries)) { + /* entry does not exist yet. Initialize a new one. */ + band = p54_get_band_from_freq(freq); + + /* + * filter out frequencies which don't belong into + * any supported band. + */ + if (band < 0) + return ; + + i = list->entries++; + list->band_channel_num[band]++; + + list->channels[i].freq = freq; + list->channels[i].data = data; + list->channels[i].band = band; + list->channels[i].index = ieee80211_frequency_to_channel(freq); + /* TODO: parse output_limit and fill max_power */ + } +} + +static int p54_generate_channel_lists(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + struct p54_channel_list *list; + unsigned int i, j, max_channel_num; + int ret = -ENOMEM; + u16 freq; + + if ((priv->iq_autocal_len != priv->curve_data->entries) || + (priv->iq_autocal_len != priv->output_limit->entries)) + printk(KERN_ERR "%s: EEPROM is damaged... you may not be able" + "to use all channels with this device.\n", + wiphy_name(dev->wiphy)); + + max_channel_num = max_t(unsigned int, priv->output_limit->entries, + priv->iq_autocal_len); + max_channel_num = max_t(unsigned int, max_channel_num, + priv->curve_data->entries); + + list = kzalloc(sizeof(*list), GFP_KERNEL); + if (!list) + goto free; + + list->max_entries = max_channel_num; + list->channels = kzalloc(sizeof(struct p54_channel_entry) * + max_channel_num, GFP_KERNEL); + if (!list->channels) + goto free; + + for (i = 0; i < max_channel_num; i++) { + if (i < priv->iq_autocal_len) { + freq = le16_to_cpu(priv->iq_autocal[i].freq); + p54_update_channel_param(list, freq, CHAN_HAS_CAL); + } + + if (i < priv->output_limit->entries) { + freq = le16_to_cpup((__le16 *) (i * + priv->output_limit->entry_size + + priv->output_limit->offset + + priv->output_limit->data)); + + p54_update_channel_param(list, freq, CHAN_HAS_LIMIT); + } + + if (i < priv->curve_data->entries) { + freq = le16_to_cpup((__le16 *) (i * + priv->curve_data->entry_size + + priv->curve_data->offset + + priv->curve_data->data)); + + p54_update_channel_param(list, freq, CHAN_HAS_CURVE); + } + } + + /* sort the list by the channel index */ + sort(list->channels, list->entries, sizeof(struct p54_channel_entry), + p54_compare_channels, NULL); + + for (i = 0, j = 0; i < IEEE80211_NUM_BANDS; i++) { + if (list->band_channel_num[i]) { + ret = p54_generate_band(dev, list, i); + if (ret) + goto free; + + j++; + } + } + if (j == 0) { + /* no useable band available. */ + ret = -EINVAL; + } + +free: + if (list) { + kfree(list->channels); + kfree(list); + } + + return ret; +} + static int p54_convert_rev0(struct ieee80211_hw *dev, struct pda_pa_curve_data *curve_data) { @@ -487,13 +670,19 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) goto err; } + err = p54_generate_channel_lists(dev); + if (err) + goto err; + priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK; if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW) p54_init_xbow_synth(priv); if (!(synth & PDR_SYNTH_24_GHZ_DISABLED)) - dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; + dev->wiphy->bands[IEEE80211_BAND_2GHZ] = + priv->band_table[IEEE80211_BAND_2GHZ]; if (!(synth & PDR_SYNTH_5_GHZ_DISABLED)) - dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz; + dev->wiphy->bands[IEEE80211_BAND_5GHZ] = + priv->band_table[IEEE80211_BAND_5GHZ]; if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED) priv->rx_diversity_mask = 3; if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED) diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index c9a054548d9..f19add2c3ca 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -598,6 +598,10 @@ EXPORT_SYMBOL_GPL(p54_register_common); void p54_free_common(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; + unsigned int i; + + for (i = 0; i < IEEE80211_NUM_BANDS; i++) + kfree(priv->band_table[i]); kfree(priv->iq_autocal); kfree(priv->output_limit); diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 6772ed505d4..584b1560aff 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -198,6 +198,7 @@ struct p54_common { struct p54_cal_database *curve_data; struct p54_cal_database *output_limit; struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS]; + struct ieee80211_supported_band *band_table[IEEE80211_NUM_BANDS]; /* BBP/MAC state */ u8 mac_addr[ETH_ALEN]; -- cgit v1.2.3-18-g5258 From acbadf01ff6727a2c7dc6e12f70ce8d05a16dc06 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 11 Jul 2009 17:24:14 +0200 Subject: ar9170: implement transmit aggregation This patch roughly implements xmit aggregation for ar9170-like device. Not all AP are compatible with the driver(and firmware) yet, so YMMV. A more refined code will definitely need the final HT specification to be available for the public, lots of firmware modification and possibly a redesigned driver just for good measure. Sadly, these conditions won't come true anytime soon... Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/ar9170.h | 52 +++ drivers/net/wireless/ath/ar9170/main.c | 608 +++++++++++++++++++++++++++++-- 2 files changed, 634 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index bb97981fb24..e6c3ee3e058 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -109,11 +109,52 @@ struct ar9170_rxstream_mpdu_merge { bool has_plcp; }; +#define AR9170_NUM_MAX_BA_RETRY 5 +#define AR9170_NUM_TID 16 +#define WME_BA_BMP_SIZE 64 +#define AR9170_NUM_MAX_AGG_LEN (2 * WME_BA_BMP_SIZE) + +#define WME_AC_BE 2 +#define WME_AC_BK 3 +#define WME_AC_VI 1 +#define WME_AC_VO 0 + +#define TID_TO_WME_AC(_tid) \ + ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ + (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \ + (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ + WME_AC_VO) + +#define BAW_WITHIN(_start, _bawsz, _seqno) \ + ((((_seqno) - (_start)) & 0xfff) < (_bawsz)) + +enum ar9170_tid_state { + AR9170_TID_STATE_INVALID, + AR9170_TID_STATE_SHUTDOWN, + AR9170_TID_STATE_PROGRESS, + AR9170_TID_STATE_COMPLETE, +}; + +struct ar9170_sta_tid { + struct list_head list; + struct sk_buff_head queue; + u8 addr[ETH_ALEN]; + u16 ssn; + u16 tid; + enum ar9170_tid_state state; + bool active; + u8 retry; +}; + #define AR9170_QUEUE_TIMEOUT 64 #define AR9170_TX_TIMEOUT 8 +#define AR9170_BA_TIMEOUT 4 #define AR9170_JANITOR_DELAY 128 #define AR9170_TX_INVALID_RATE 0xffffffff +#define AR9170_NUM_TX_STATUS 128 +#define AR9170_NUM_TX_AGG_MAX 30 + struct ar9170 { struct ieee80211_hw *hw; struct mutex mutex; @@ -187,14 +228,25 @@ struct ar9170 { struct sk_buff_head tx_pending[__AR9170_NUM_TXQ]; struct sk_buff_head tx_status[__AR9170_NUM_TXQ]; struct delayed_work tx_janitor; + /* tx ampdu */ + struct sk_buff_head tx_status_ampdu; + spinlock_t tx_ampdu_list_lock; + struct list_head tx_ampdu_list; + unsigned int tx_ampdu_pending; /* rxstream mpdu merge */ struct ar9170_rxstream_mpdu_merge rx_mpdu; struct sk_buff *rx_failover; int rx_failover_missing; + + /* (cached) HW A-MPDU settings */ + u8 global_ampdu_density; + u8 global_ampdu_factor; }; struct ar9170_sta_info { + struct ar9170_sta_tid agg[AR9170_NUM_TID]; + unsigned int ampdu_max_len; }; #define AR9170_TX_FLAG_WAIT_FOR_ACK BIT(0) diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 51753ed1b8b..cfe6fc78067 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -49,6 +49,10 @@ static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); +static int modparam_ht; +module_param_named(ht, modparam_ht, bool, S_IRUGO); +MODULE_PARM_DESC(ht, "enable MPDU aggregation."); + #define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \ .bitrate = (_bitrate), \ .flags = (_flags), \ @@ -148,12 +152,15 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = { .cap = IEEE80211_HT_CAP_MAX_AMSDU | \ IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ IEEE80211_HT_CAP_SGI_40 | \ + IEEE80211_HT_CAP_GRN_FLD | \ IEEE80211_HT_CAP_DSSSCCK40 | \ IEEE80211_HT_CAP_SM_PS, \ .ampdu_factor = 3, \ .ampdu_density = 6, \ .mcs = { \ - .rx_mask = { 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, }, \ + .rx_mask = { 0xff, 0xff, 0, 0, 0x1, 0, 0, 0, 0, 0, }, \ + .rx_highest = cpu_to_le16(300), \ + .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ }, \ } @@ -174,8 +181,31 @@ static struct ieee80211_supported_band ar9170_band_5GHz = { }; static void ar9170_tx(struct ar9170 *ar); +static bool ar9170_tx_ampdu(struct ar9170 *ar); -#ifdef AR9170_QUEUE_DEBUG +static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr) +{ + return le16_to_cpu(hdr->seq_ctrl) >> 4; +} + +static inline u16 ar9170_get_seq(struct sk_buff *skb) +{ + struct ar9170_tx_control *txc = (void *) skb->data; + return ar9170_get_seq_h((void *) txc->frame_data); +} + +static inline u16 ar9170_get_tid(struct sk_buff *skb) +{ + struct ar9170_tx_control *txc = (void *) skb->data; + struct ieee80211_hdr *hdr = (void *) txc->frame_data; + + return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK; +} + +#define GET_NEXT_SEQ(seq) ((seq + 1) & 0x0fff) +#define GET_NEXT_SEQ_FROM_SKB(skb) (GET_NEXT_SEQ(ar9170_get_seq(skb))) + +#if (defined AR9170_QUEUE_DEBUG) || (defined AR9170_TXAGG_DEBUG) static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) { struct ar9170_tx_control *txc = (void *) skb->data; @@ -183,10 +213,10 @@ static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data; struct ieee80211_hdr *hdr = (void *) txc->frame_data; - printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x " + printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x s:%d " "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n", wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb), - ieee80211_get_DA(hdr), arinfo->flags, + ieee80211_get_DA(hdr), arinfo->flags, ar9170_get_seq_h(hdr), le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control), jiffies_to_msecs(arinfo->timeout - jiffies)); } @@ -210,7 +240,9 @@ static void __ar9170_dump_txqueue(struct ar9170 *ar, "mismatch %d != %d\n", skb_queue_len(queue), i); printk(KERN_DEBUG "---[ end ]---\n"); } +#endif /* AR9170_QUEUE_DEBUG || AR9170_TXAGG_DEBUG */ +#ifdef AR9170_QUEUE_DEBUG static void ar9170_dump_txqueue(struct ar9170 *ar, struct sk_buff_head *queue) { @@ -220,7 +252,9 @@ static void ar9170_dump_txqueue(struct ar9170 *ar, __ar9170_dump_txqueue(ar, queue); spin_unlock_irqrestore(&queue->lock, flags); } +#endif /* AR9170_QUEUE_DEBUG */ +#ifdef AR9170_QUEUE_STOP_DEBUG static void __ar9170_dump_txstats(struct ar9170 *ar) { int i; @@ -229,20 +263,27 @@ static void __ar9170_dump_txstats(struct ar9170 *ar) wiphy_name(ar->hw->wiphy)); for (i = 0; i < __AR9170_NUM_TXQ; i++) - printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d\n", - wiphy_name(ar->hw->wiphy), i, ar->tx_stats[i].limit, - ar->tx_stats[i].len, skb_queue_len(&ar->tx_status[i])); + printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d " + " stopped:%d\n", wiphy_name(ar->hw->wiphy), i, + ar->tx_stats[i].limit, ar->tx_stats[i].len, + skb_queue_len(&ar->tx_status[i]), + ieee80211_queue_stopped(ar->hw, i)); } +#endif /* AR9170_QUEUE_STOP_DEBUG */ -static void ar9170_dump_txstats(struct ar9170 *ar) +#ifdef AR9170_TXAGG_DEBUG +static void ar9170_dump_tx_status_ampdu(struct ar9170 *ar) { unsigned long flags; - spin_lock_irqsave(&ar->tx_stats_lock, flags); - __ar9170_dump_txstats(ar); - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); + spin_lock_irqsave(&ar->tx_status_ampdu.lock, flags); + printk(KERN_DEBUG "%s: A-MPDU tx_status queue => \n", + wiphy_name(ar->hw->wiphy)); + __ar9170_dump_txqueue(ar, &ar->tx_status_ampdu); + spin_unlock_irqrestore(&ar->tx_status_ampdu.lock, flags); } -#endif /* AR9170_QUEUE_DEBUG */ + +#endif /* AR9170_TXAGG_DEBUG */ /* caller must guarantee exclusive access for _bin_ queue. */ static void ar9170_recycle_expired(struct ar9170 *ar, @@ -315,6 +356,70 @@ static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, ieee80211_tx_status_irqsafe(ar->hw, skb); } +static void ar9170_tx_fake_ampdu_status(struct ar9170 *ar) +{ + struct sk_buff_head success; + struct sk_buff *skb; + unsigned int i; + unsigned long queue_bitmap = 0; + + skb_queue_head_init(&success); + + while (skb_queue_len(&ar->tx_status_ampdu) > AR9170_NUM_TX_STATUS) + __skb_queue_tail(&success, skb_dequeue(&ar->tx_status_ampdu)); + + ar9170_recycle_expired(ar, &ar->tx_status_ampdu, &success); + +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: collected %d A-MPDU frames.\n", + wiphy_name(ar->hw->wiphy), skb_queue_len(&success)); + __ar9170_dump_txqueue(ar, &success); +#endif /* AR9170_TXAGG_DEBUG */ + + while ((skb = __skb_dequeue(&success))) { + struct ieee80211_tx_info *txinfo; + + queue_bitmap |= BIT(skb_get_queue_mapping(skb)); + + txinfo = IEEE80211_SKB_CB(skb); + ieee80211_tx_info_clear_status(txinfo); + + txinfo->flags |= IEEE80211_TX_STAT_ACK; + txinfo->status.rates[0].count = 1; + + skb_pull(skb, sizeof(struct ar9170_tx_control)); + ieee80211_tx_status_irqsafe(ar->hw, skb); + } + + for_each_bit(i, &queue_bitmap, BITS_PER_BYTE) { +#ifdef AR9170_QUEUE_STOP_DEBUG + printk(KERN_DEBUG "%s: wake queue %d\n", + wiphy_name(ar->hw->wiphy), i); + __ar9170_dump_txstats(ar); +#endif /* AR9170_QUEUE_STOP_DEBUG */ + ieee80211_wake_queue(ar->hw, i); + } + + if (queue_bitmap) + ar9170_tx(ar); +} + +static void ar9170_tx_ampdu_callback(struct ar9170 *ar, struct sk_buff *skb) +{ + struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); + struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data; + + arinfo->timeout = jiffies + + msecs_to_jiffies(AR9170_BA_TIMEOUT); + + skb_queue_tail(&ar->tx_status_ampdu, skb); + ar9170_tx_fake_ampdu_status(ar); + ar->tx_ampdu_pending--; + + if (!list_empty(&ar->tx_ampdu_list) && !ar->tx_ampdu_pending) + ar9170_tx_ampdu(ar); +} + void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -336,7 +441,7 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb) spin_unlock_irqrestore(&ar->tx_stats_lock, flags); if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) { - dev_kfree_skb_any(skb); + ar9170_tx_ampdu_callback(ar, skb); } else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) { arinfo->timeout = jiffies + msecs_to_jiffies(AR9170_TX_TIMEOUT); @@ -420,6 +525,38 @@ static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar, return NULL; } +static void ar9170_handle_block_ack(struct ar9170 *ar, u16 count, u16 r) +{ + struct sk_buff *skb; + struct ieee80211_tx_info *txinfo; + + while (count) { + skb = ar9170_get_queued_skb(ar, NULL, &ar->tx_status_ampdu, r); + if (!skb) + break; + + txinfo = IEEE80211_SKB_CB(skb); + ieee80211_tx_info_clear_status(txinfo); + + /* FIXME: maybe more ? */ + txinfo->status.rates[0].count = 1; + + skb_pull(skb, sizeof(struct ar9170_tx_control)); + ieee80211_tx_status_irqsafe(ar->hw, skb); + count--; + } + +#ifdef AR9170_TXAGG_DEBUG + if (count) { + printk(KERN_DEBUG "%s: got %d more failed mpdus, but no more " + "suitable frames left in tx_status queue.\n", + wiphy_name(ar->hw->wiphy), count); + + ar9170_dump_tx_status_ampdu(ar); + } +#endif /* AR9170_TXAGG_DEBUG */ +} + /* * This worker tries to keeps an maintain tx_status queues. * So we can guarantee that incoming tx_status reports are @@ -456,6 +593,8 @@ static void ar9170_tx_janitor(struct work_struct *work) resched = true; } + ar9170_tx_fake_ampdu_status(ar); + if (resched) queue_delayed_work(ar->hw->workqueue, &ar->tx_janitor, @@ -528,8 +667,15 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) break; case 0xc4: + /* BlockACK bitmap */ + break; + case 0xc5: /* BlockACK events */ + ar9170_handle_block_ack(ar, + le16_to_cpu(cmd->ba_fail_cnt.failed), + le16_to_cpu(cmd->ba_fail_cnt.rate)); + ar9170_tx_fake_ampdu_status(ar); break; case 0xc6: @@ -1098,6 +1244,10 @@ static int ar9170_op_start(struct ieee80211_hw *hw) AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */ AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */ + /* set sane AMPDU defaults */ + ar->global_ampdu_density = 6; + ar->global_ampdu_factor = 3; + ar->bad_hw_nagger = jiffies; err = ar->open(ar); @@ -1143,6 +1293,7 @@ static void ar9170_op_stop(struct ieee80211_hw *hw) flush_workqueue(ar->hw->workqueue); cancel_delayed_work_sync(&ar->tx_janitor); + cancel_delayed_work_sync(&ar->led_work); cancel_work_sync(&ar->filter_config_work); cancel_work_sync(&ar->beacon_work); mutex_lock(&ar->mutex); @@ -1159,9 +1310,40 @@ static void ar9170_op_stop(struct ieee80211_hw *hw) skb_queue_purge(&ar->tx_pending[i]); skb_queue_purge(&ar->tx_status[i]); } + skb_queue_purge(&ar->tx_status_ampdu); + mutex_unlock(&ar->mutex); } +static void ar9170_tx_indicate_immba(struct ar9170 *ar, struct sk_buff *skb) +{ + struct ar9170_tx_control *txc = (void *) skb->data; + + txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_IMM_AMPDU); +} + +static void ar9170_tx_copy_phy(struct ar9170 *ar, struct sk_buff *dst, + struct sk_buff *src) +{ + struct ar9170_tx_control *dst_txc, *src_txc; + struct ieee80211_tx_info *dst_info, *src_info; + struct ar9170_tx_info *dst_arinfo, *src_arinfo; + + src_txc = (void *) src->data; + src_info = IEEE80211_SKB_CB(src); + src_arinfo = (void *) src_info->rate_driver_data; + + dst_txc = (void *) dst->data; + dst_info = IEEE80211_SKB_CB(dst); + dst_arinfo = (void *) dst_info->rate_driver_data; + + dst_txc->phy_control = src_txc->phy_control; + + /* same MCS for the whole aggregate */ + memcpy(dst_info->driver_rates, src_info->driver_rates, + sizeof(dst_info->driver_rates)); +} + static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) { struct ieee80211_hdr *hdr; @@ -1230,6 +1412,7 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK; + goto out; } @@ -1360,6 +1543,159 @@ static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb) txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT); } +static bool ar9170_tx_ampdu(struct ar9170 *ar) +{ + struct sk_buff_head agg; + struct ar9170_sta_tid *tid_info = NULL, *tmp; + struct sk_buff *skb, *first = NULL; + unsigned long flags, f2; + unsigned int i = 0; + u16 seq, queue, tmpssn; + bool run = false; + + skb_queue_head_init(&agg); + + spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags); + if (list_empty(&ar->tx_ampdu_list)) { +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: aggregation list is empty.\n", + wiphy_name(ar->hw->wiphy)); +#endif /* AR9170_TXAGG_DEBUG */ + goto out_unlock; + } + + list_for_each_entry_safe(tid_info, tmp, &ar->tx_ampdu_list, list) { + if (tid_info->state != AR9170_TID_STATE_COMPLETE) { +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: dangling aggregation entry!\n", + wiphy_name(ar->hw->wiphy)); +#endif /* AR9170_TXAGG_DEBUG */ + continue; + } + + if (++i > 64) { +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: enough frames aggregated.\n", + wiphy_name(ar->hw->wiphy)); +#endif /* AR9170_TXAGG_DEBUG */ + break; + } + + queue = TID_TO_WME_AC(tid_info->tid); + + if (skb_queue_len(&ar->tx_pending[queue]) >= + AR9170_NUM_TX_AGG_MAX) { +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: queue %d full.\n", + wiphy_name(ar->hw->wiphy), queue); +#endif /* AR9170_TXAGG_DEBUG */ + continue; + } + + list_del_init(&tid_info->list); + + spin_lock_irqsave(&tid_info->queue.lock, f2); + tmpssn = seq = tid_info->ssn; + first = skb_peek(&tid_info->queue); + + if (likely(first)) + tmpssn = ar9170_get_seq(first); + + if (unlikely(tmpssn != seq)) { +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: ssn mismatch [%d != %d]\n.", + wiphy_name(ar->hw->wiphy), seq, tmpssn); +#endif /* AR9170_TXAGG_DEBUG */ + tid_info->ssn = tmpssn; + } + +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: generate A-MPDU for tid:%d ssn:%d with " + "%d queued frames.\n", wiphy_name(ar->hw->wiphy), + tid_info->tid, tid_info->ssn, + skb_queue_len(&tid_info->queue)); + __ar9170_dump_txqueue(ar, &tid_info->queue); +#endif /* AR9170_TXAGG_DEBUG */ + + while ((skb = skb_peek(&tid_info->queue))) { + if (unlikely(ar9170_get_seq(skb) != seq)) + break; + + __skb_unlink(skb, &tid_info->queue); + tid_info->ssn = seq = GET_NEXT_SEQ(seq); + + if (unlikely(skb_get_queue_mapping(skb) != queue)) { +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: tid:%d(q:%d) queue:%d " + "!match.\n", wiphy_name(ar->hw->wiphy), + tid_info->tid, + TID_TO_WME_AC(tid_info->tid), + skb_get_queue_mapping(skb)); +#endif /* AR9170_TXAGG_DEBUG */ + dev_kfree_skb_any(skb); + continue; + } + + if (unlikely(first == skb)) { + ar9170_tx_prepare_phy(ar, skb); + __skb_queue_tail(&agg, skb); + first = skb; + } else { + ar9170_tx_copy_phy(ar, skb, first); + __skb_queue_tail(&agg, skb); + } + + if (unlikely(skb_queue_len(&agg) == + AR9170_NUM_TX_AGG_MAX)) + break; + } + + if (skb_queue_empty(&tid_info->queue)) + tid_info->active = false; + else + list_add_tail(&tid_info->list, + &ar->tx_ampdu_list); + + spin_unlock_irqrestore(&tid_info->queue.lock, f2); + + if (unlikely(skb_queue_empty(&agg))) { +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: queued empty list!\n", + wiphy_name(ar->hw->wiphy)); +#endif /* AR9170_TXAGG_DEBUG */ + continue; + } + + /* + * tell the FW/HW that this is the last frame, + * that way it will wait for the immediate block ack. + */ + if (likely(skb_peek_tail(&agg))) + ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg)); + +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: generated A-MPDU looks like this:\n", + wiphy_name(ar->hw->wiphy)); + __ar9170_dump_txqueue(ar, &agg); +#endif /* AR9170_TXAGG_DEBUG */ + + spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); + + spin_lock_irqsave(&ar->tx_pending[queue].lock, flags); + skb_queue_splice_tail_init(&agg, &ar->tx_pending[queue]); + spin_unlock_irqrestore(&ar->tx_pending[queue].lock, flags); + run = true; + + spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags); + } + +out_unlock: + spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); + __skb_queue_purge(&agg); + + return run; +} + static void ar9170_tx(struct ar9170 *ar) { struct sk_buff *skb; @@ -1384,11 +1720,17 @@ static void ar9170_tx(struct ar9170 *ar) printk(KERN_DEBUG "%s: queue %d full\n", wiphy_name(ar->hw->wiphy), i); - __ar9170_dump_txstats(ar); - printk(KERN_DEBUG "stuck frames: ===> \n"); + printk(KERN_DEBUG "%s: stuck frames: ===> \n", + wiphy_name(ar->hw->wiphy)); ar9170_dump_txqueue(ar, &ar->tx_pending[i]); ar9170_dump_txqueue(ar, &ar->tx_status[i]); #endif /* AR9170_QUEUE_DEBUG */ + +#ifdef AR9170_QUEUE_STOP_DEBUG + printk(KERN_DEBUG "%s: stop queue %d\n", + wiphy_name(ar->hw->wiphy), i); + __ar9170_dump_txstats(ar); +#endif /* AR9170_QUEUE_STOP_DEBUG */ ieee80211_stop_queue(ar->hw, i); spin_unlock_irqrestore(&ar->tx_stats_lock, flags); continue; @@ -1403,8 +1745,6 @@ static void ar9170_tx(struct ar9170 *ar) "remaining slots:%d, needed:%d\n", wiphy_name(ar->hw->wiphy), i, remaining_space, frames); - - ar9170_dump_txstats(ar); #endif /* AR9170_QUEUE_DEBUG */ frames = remaining_space; } @@ -1432,6 +1772,9 @@ static void ar9170_tx(struct ar9170 *ar) arinfo->timeout = jiffies + msecs_to_jiffies(AR9170_TX_TIMEOUT); + if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK) + ar->tx_ampdu_pending++; + #ifdef AR9170_QUEUE_DEBUG printk(KERN_DEBUG "%s: send frame q:%d =>\n", wiphy_name(ar->hw->wiphy), i); @@ -1440,6 +1783,9 @@ static void ar9170_tx(struct ar9170 *ar) err = ar->tx(ar, skb); if (unlikely(err)) { + if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK) + ar->tx_ampdu_pending--; + frames_failed++; dev_kfree_skb_any(skb); } else { @@ -1461,13 +1807,18 @@ static void ar9170_tx(struct ar9170 *ar) if (unlikely(frames_failed)) { #ifdef AR9170_QUEUE_DEBUG - printk(KERN_DEBUG "%s: frames failed =>\n", + printk(KERN_DEBUG "%s: frames failed %d =>\n", wiphy_name(ar->hw->wiphy), frames_failed); #endif /* AR9170_QUEUE_DEBUG */ spin_lock_irqsave(&ar->tx_stats_lock, flags); ar->tx_stats[i].len -= frames_failed; ar->tx_stats[i].count -= frames_failed; +#ifdef AR9170_QUEUE_STOP_DEBUG + printk(KERN_DEBUG "%s: wake queue %d\n", + wiphy_name(ar->hw->wiphy), i); + __ar9170_dump_txstats(ar); +#endif /* AR9170_QUEUE_STOP_DEBUG */ ieee80211_wake_queue(ar->hw, i); spin_unlock_irqrestore(&ar->tx_stats_lock, flags); } @@ -1479,6 +1830,90 @@ static void ar9170_tx(struct ar9170 *ar) msecs_to_jiffies(AR9170_JANITOR_DELAY)); } +static bool ar9170_tx_ampdu_queue(struct ar9170 *ar, struct sk_buff *skb) +{ + struct ieee80211_tx_info *txinfo; + struct ar9170_sta_info *sta_info; + struct ar9170_sta_tid *agg; + struct sk_buff *iter; + unsigned long flags, f2; + unsigned int max; + u16 tid, seq, qseq; + bool run = false, queue = false; + + tid = ar9170_get_tid(skb); + seq = ar9170_get_seq(skb); + txinfo = IEEE80211_SKB_CB(skb); + sta_info = (void *) txinfo->control.sta->drv_priv; + agg = &sta_info->agg[tid]; + max = sta_info->ampdu_max_len; + + spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags); + + if (unlikely(agg->state != AR9170_TID_STATE_COMPLETE)) { +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: BlockACK session not fully initialized " + "for ESS:%pM tid:%d state:%d.\n", + wiphy_name(ar->hw->wiphy), agg->addr, agg->tid, + agg->state); +#endif /* AR9170_TXAGG_DEBUG */ + goto err_unlock; + } + + if (!agg->active) { + agg->active = true; + agg->ssn = seq; + queue = true; + } + + /* check if seq is within the BA window */ + if (unlikely(!BAW_WITHIN(agg->ssn, max, seq))) { +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: frame with tid:%d seq:%d does not " + "fit into BA window (%d - %d)\n", + wiphy_name(ar->hw->wiphy), tid, seq, agg->ssn, + (agg->ssn + max) & 0xfff); +#endif /* AR9170_TXAGG_DEBUG */ + goto err_unlock; + } + + spin_lock_irqsave(&agg->queue.lock, f2); + + skb_queue_reverse_walk(&agg->queue, iter) { + qseq = ar9170_get_seq(iter); + + if (GET_NEXT_SEQ(qseq) == seq) { + __skb_queue_after(&agg->queue, iter, skb); + goto queued; + } + } + + __skb_queue_head(&agg->queue, skb); + +queued: + spin_unlock_irqrestore(&agg->queue.lock, f2); + +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_DEBUG "%s: new aggregate %p queued.\n", + wiphy_name(ar->hw->wiphy), skb); + __ar9170_dump_txqueue(ar, &agg->queue); +#endif /* AR9170_TXAGG_DEBUG */ + + if (skb_queue_len(&agg->queue) >= AR9170_NUM_TX_AGG_MAX) + run = true; + + if (queue) + list_add_tail(&agg->list, &ar->tx_ampdu_list); + + spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); + return run; + +err_unlock: + spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); + dev_kfree_skb_irq(skb); + return false; +} + int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ar9170 *ar = hw->priv; @@ -1492,8 +1927,10 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) info = IEEE80211_SKB_CB(skb); if (info->flags & IEEE80211_TX_CTL_AMPDU) { - /* drop frame, we do not allow TX A-MPDU aggregation yet. */ - goto err_free; + bool run = ar9170_tx_ampdu_queue(ar, skb); + + if (run || !ar->tx_ampdu_pending) + ar9170_tx_ampdu(ar); } else { unsigned int queue = skb_get_queue_mapping(skb); @@ -1931,6 +2368,53 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw, enum sta_notify_cmd cmd, struct ieee80211_sta *sta) { + struct ar9170 *ar = hw->priv; + struct ar9170_sta_info *sta_info = (void *) sta->drv_priv; + unsigned int i; + + switch (cmd) { + case STA_NOTIFY_ADD: + memset(sta_info, 0, sizeof(*sta_info)); + + if (!sta->ht_cap.ht_supported) + break; + + if (sta->ht_cap.ampdu_density > ar->global_ampdu_density) + ar->global_ampdu_density = sta->ht_cap.ampdu_density; + + if (sta->ht_cap.ampdu_factor < ar->global_ampdu_factor) + ar->global_ampdu_factor = sta->ht_cap.ampdu_factor; + + for (i = 0; i < AR9170_NUM_TID; i++) { + sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN; + sta_info->agg[i].active = false; + sta_info->agg[i].ssn = 0; + sta_info->agg[i].retry = 0; + sta_info->agg[i].tid = i; + INIT_LIST_HEAD(&sta_info->agg[i].list); + skb_queue_head_init(&sta_info->agg[i].queue); + } + + sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor); + break; + + case STA_NOTIFY_REMOVE: + if (!sta->ht_cap.ht_supported) + break; + + for (i = 0; i < AR9170_NUM_TID; i++) { + sta_info->agg[i].state = AR9170_TID_STATE_INVALID; + skb_queue_purge(&sta_info->agg[i].queue); + } + + break; + + default: + break; + } + + if (IS_STARTED(ar) && ar->filter_changed) + queue_work(ar->hw->workqueue, &ar->filter_config_work); } static int ar9170_get_stats(struct ieee80211_hw *hw, @@ -1985,18 +2469,65 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { + struct ar9170 *ar = hw->priv; + struct ar9170_sta_info *sta_info = (void *) sta->drv_priv; + struct ar9170_sta_tid *tid_info = &sta_info->agg[tid]; + unsigned long flags; + + if (!modparam_ht) + return -EOPNOTSUPP; + switch (action) { + case IEEE80211_AMPDU_TX_START: + spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags); + if (tid_info->state != AR9170_TID_STATE_SHUTDOWN || + !list_empty(&tid_info->list)) { + spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_INFO "%s: A-MPDU [ESS:[%pM] tid:[%d]] " + "is in a very bad state!\n", + wiphy_name(hw->wiphy), sta->addr, tid); +#endif /* AR9170_TXAGG_DEBUG */ + return -EBUSY; + } + + *ssn = tid_info->ssn; + tid_info->state = AR9170_TID_STATE_PROGRESS; + tid_info->active = false; + spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); + ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); + break; + + case IEEE80211_AMPDU_TX_STOP: + spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags); + tid_info->state = AR9170_TID_STATE_SHUTDOWN; + list_del_init(&tid_info->list); + tid_info->active = false; + skb_queue_purge(&tid_info->queue); + spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); + ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); + break; + + case IEEE80211_AMPDU_TX_OPERATIONAL: +#ifdef AR9170_TXAGG_DEBUG + printk(KERN_INFO "%s: A-MPDU for %pM [tid:%d] Operational.\n", + wiphy_name(hw->wiphy), sta->addr, tid); +#endif /* AR9170_TXAGG_DEBUG */ + spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags); + sta_info->agg[tid].state = AR9170_TID_STATE_COMPLETE; + spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); + break; + case IEEE80211_AMPDU_RX_START: case IEEE80211_AMPDU_RX_STOP: - /* - * Something goes wrong -- RX locks up - * after a while of receiving aggregated - * frames -- not enabling for now. - */ - return -EOPNOTSUPP; + /* Handled by firmware */ + break; + default: return -EOPNOTSUPP; } + + return 0; } static const struct ieee80211_ops ar9170_ops = { @@ -2045,6 +2576,8 @@ void *ar9170_alloc(size_t priv_size) mutex_init(&ar->mutex); spin_lock_init(&ar->cmdlock); spin_lock_init(&ar->tx_stats_lock); + spin_lock_init(&ar->tx_ampdu_list_lock); + skb_queue_head_init(&ar->tx_status_ampdu); for (i = 0; i < __AR9170_NUM_TXQ; i++) { skb_queue_head_init(&ar->tx_status[i]); skb_queue_head_init(&ar->tx_pending[i]); @@ -2053,6 +2586,7 @@ void *ar9170_alloc(size_t priv_size) INIT_WORK(&ar->filter_config_work, ar9170_set_filters); INIT_WORK(&ar->beacon_work, ar9170_new_beacon); INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor); + INIT_LIST_HEAD(&ar->tx_ampdu_list); /* all hw supports 2.4 GHz, so set channel to 1 by default */ ar->channel = &ar9170_2ghz_chantable[0]; @@ -2066,6 +2600,13 @@ void *ar9170_alloc(size_t priv_size) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; + if (modparam_ht) { + ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; + } else { + ar9170_band_2GHz.ht_cap.ht_supported = false; + ar9170_band_5GHz.ht_cap.ht_supported = false; + } + ar->hw->queues = __AR9170_NUM_TXQ; ar->hw->extra_tx_headroom = 8; ar->hw->sta_data_size = sizeof(struct ar9170_sta_info); @@ -2091,6 +2632,7 @@ static int ar9170_read_eeprom(struct ar9170 *ar) u8 *eeprom = (void *)&ar->eeprom; u8 *addr = ar->eeprom.mac_address; __le32 offsets[RW]; + unsigned int rx_streams, tx_streams, tx_params = 0; int i, j, err, bands = 0; BUILD_BUG_ON(sizeof(ar->eeprom) & 3); @@ -2127,6 +2669,20 @@ static int ar9170_read_eeprom(struct ar9170 *ar) ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz; bands++; } + + rx_streams = hweight8(ar->eeprom.rx_mask); + tx_streams = hweight8(ar->eeprom.tx_mask); + + if (rx_streams != tx_streams) + tx_params = IEEE80211_HT_MCS_TX_RX_DIFF; + + if (tx_streams >= 1 && tx_streams <= IEEE80211_HT_MCS_TX_MAX_STREAMS) + tx_params = (tx_streams - 1) << + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; + + ar9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params; + ar9170_band_5GHz.ht_cap.mcs.tx_params |= tx_params; + /* * I measured this, a bandswitch takes roughly * 135 ms and a frequency switch about 80. -- cgit v1.2.3-18-g5258 From 4b9631a4734e25e37c83e72c3e0ffcbb08de5791 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 11 Jul 2009 18:00:19 +0200 Subject: rt2x00: Remove DEVICE_STATE_DISABLED_RADIO_HW The DEVICE_STATE_DISABLED_RADIO_HW flag is only read but never set, it is an ancient part of one of the many versions of the rfkill implementations in rt2x00. It is about time is disappears. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 1 - drivers/net/wireless/rt2x00/rt2x00dev.c | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 3e177175e34..4c76c8d93cb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -594,7 +594,6 @@ enum rt2x00_flags { DEVICE_STATE_INITIALIZED, DEVICE_STATE_STARTED, DEVICE_STATE_ENABLED_RADIO, - DEVICE_STATE_DISABLED_RADIO_HW, /* * Driver requirements diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 4fff3a83f7d..658a63bfb76 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -40,8 +40,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) * Don't enable the radio twice. * And check if the hardware button has been disabled. */ - if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || - test_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return 0; /* -- cgit v1.2.3-18-g5258 From ec96cfd8215af1cda016837efb266409164e3a30 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 12 Jul 2009 22:05:33 +0200 Subject: drivers/net: Drop unnecessary NULL test The result of container_of should not be NULL. In particular, in this case the argument to the enclosing function has passed though INIT_WORK, which dereferences it, implying that its container cannot be NULL. A simplified version of the semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @@ identifier fn,work,x,fld; type T; expression E1,E2; statement S; @@ static fn(struct work_struct *work) { ... when != work = E1 x = container_of(work,T,fld) ... when != x = E2 - if (x == NULL) S ... } // Signed-off-by: Julia Lawall Acked-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2200.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index d726b3c6077..2dc1cdbb493 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -7250,9 +7250,6 @@ static void ipw_bg_qos_activate(struct work_struct *work) struct ipw_priv *priv = container_of(work, struct ipw_priv, qos_activate); - if (priv == NULL) - return; - mutex_lock(&priv->mutex); if (priv->status & STATUS_ASSOCIATED) -- cgit v1.2.3-18-g5258 From 8f75e07aa14107668d33f60fa4d78afa2d7aa22b Mon Sep 17 00:00:00 2001 From: Hin-Tak Leung Date: Mon, 13 Jul 2009 23:20:37 +0100 Subject: zd1211rw: adding Accton Technology Corp (083a:e501) as a ZD1211B device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New device supported by the zd1211rw driver reported to linux-wireless. Device string from lsusb: "ID 083a:e501 Accton Technology Corp. ZD1211B" RF type from dmesg: zd1211b chip 083a:e501 v4810 high 00-1a-2a AL2230_RF pa0 g--NS Signed-off-by: Hin-Tak Leung Tested-by: Adrián Cereto Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 07d7ab674a0..38688847d56 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -76,6 +76,7 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x083a, 0xe501), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x083a, 0xe503), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, -- cgit v1.2.3-18-g5258 From 256fc96028f0eae5f7a3f6f77358cdd30a72c988 Mon Sep 17 00:00:00 2001 From: Hin-Tak Leung Date: Tue, 14 Jul 2009 00:05:56 +0100 Subject: rtl8187: updating Kconfig with info of branded devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adding more detailed info about Asus motherboards and Ralink devices. Signed-off-by: Hin-Tak Leung Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 7d5902d1349..ca7a8a31d0b 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -428,10 +428,12 @@ config RTL8187 Micronet SP907GK V5 Encore ENUWI-G2 Trendnet TEW-424UB - ASUS P5B Deluxe + ASUS P5B Deluxe/P5K Premium motherboards Toshiba Satellite Pro series of laptops Asus Wireless Link Linksys WUSB54GC-EU v2 + (v1 = rt73usb; v3 is rt2070-based, + use staging/rt3070 or try rt2800usb) Thanks to Realtek for their support! -- cgit v1.2.3-18-g5258 From a94ca4e7af0e6b63ef5345750fad8e1400274ba4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 14 Jul 2009 15:48:11 +0200 Subject: iwlwifi: make some logging functions static/unexport iwl_dump_nic_error_log can be static and iwl_dump_nic_event_log doesn't need to be exported. Signed-off-by: Johannes Berg Acked-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 367 ++++++++++++++++---------------- drivers/net/wireless/iwlwifi/iwl-core.h | 1 - 2 files changed, 182 insertions(+), 186 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index d5cd9a20edc..b82480a5178 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1290,6 +1290,188 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv) } #endif +static const char *desc_lookup_text[] = { + "OK", + "FAIL", + "BAD_PARAM", + "BAD_CHECKSUM", + "NMI_INTERRUPT_WDG", + "SYSASSERT", + "FATAL_ERROR", + "BAD_COMMAND", + "HW_ERROR_TUNE_LOCK", + "HW_ERROR_TEMPERATURE", + "ILLEGAL_CHAN_FREQ", + "VCC_NOT_STABLE", + "FH_ERROR", + "NMI_INTERRUPT_HOST", + "NMI_INTERRUPT_ACTION_PT", + "NMI_INTERRUPT_UNKNOWN", + "UCODE_VERSION_MISMATCH", + "HW_ERROR_ABS_LOCK", + "HW_ERROR_CAL_LOCK_FAIL", + "NMI_INTERRUPT_INST_ACTION_PT", + "NMI_INTERRUPT_DATA_ACTION_PT", + "NMI_TRM_HW_ER", + "NMI_INTERRUPT_TRM", + "NMI_INTERRUPT_BREAK_POINT" + "DEBUG_0", + "DEBUG_1", + "DEBUG_2", + "DEBUG_3", + "UNKNOWN" +}; + +static const char *desc_lookup(int i) +{ + int max = ARRAY_SIZE(desc_lookup_text) - 1; + + if (i < 0 || i > max) + i = max; + + return desc_lookup_text[i]; +} + +#define ERROR_START_OFFSET (1 * sizeof(u32)) +#define ERROR_ELEM_SIZE (7 * sizeof(u32)) + +static void iwl_dump_nic_error_log(struct iwl_priv *priv) +{ + u32 data2, line; + u32 desc, time, count, base, data1; + u32 blink1, blink2, ilink1, ilink2; + + if (priv->ucode_type == UCODE_INIT) + base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); + else + base = le32_to_cpu(priv->card_alive.error_event_table_ptr); + + if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { + IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base); + return; + } + + count = iwl_read_targ_mem(priv, base); + + if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { + IWL_ERR(priv, "Start IWL Error Log Dump:\n"); + IWL_ERR(priv, "Status: 0x%08lX, count: %d\n", + priv->status, count); + } + + desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32)); + blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32)); + blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32)); + ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32)); + ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32)); + data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32)); + data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32)); + line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); + time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); + + IWL_ERR(priv, "Desc Time " + "data1 data2 line\n"); + IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n", + desc_lookup(desc), desc, time, data1, data2, line); + IWL_ERR(priv, "blink1 blink2 ilink1 ilink2\n"); + IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, + ilink1, ilink2); + +} + +#define EVENT_START_OFFSET (4 * sizeof(u32)) + +/** + * iwl_print_event_log - Dump error event log to syslog + * + */ +static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, + u32 num_events, u32 mode) +{ + u32 i; + u32 base; /* SRAM byte address of event log header */ + u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ + u32 ptr; /* SRAM byte address of log data */ + u32 ev, time, data; /* event log data */ + + if (num_events == 0) + return; + if (priv->ucode_type == UCODE_INIT) + base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); + else + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + + if (mode == 0) + event_size = 2 * sizeof(u32); + else + event_size = 3 * sizeof(u32); + + ptr = base + EVENT_START_OFFSET + (start_idx * event_size); + + /* "time" is actually "data" for mode 0 (no timestamp). + * place event id # at far right for easier visual parsing. */ + for (i = 0; i < num_events; i++) { + ev = iwl_read_targ_mem(priv, ptr); + ptr += sizeof(u32); + time = iwl_read_targ_mem(priv, ptr); + ptr += sizeof(u32); + if (mode == 0) { + /* data, ev */ + IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev); + } else { + data = iwl_read_targ_mem(priv, ptr); + ptr += sizeof(u32); + IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n", + time, data, ev); + } + } +} + +void iwl_dump_nic_event_log(struct iwl_priv *priv) +{ + u32 base; /* SRAM byte address of event log header */ + u32 capacity; /* event log capacity in # entries */ + u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ + u32 num_wraps; /* # times uCode wrapped to top of log */ + u32 next_entry; /* index of next entry to be written by uCode */ + u32 size; /* # entries that we'll print */ + + if (priv->ucode_type == UCODE_INIT) + base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); + else + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + + if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { + IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base); + return; + } + + /* event log header */ + capacity = iwl_read_targ_mem(priv, base); + mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); + num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); + next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); + + size = num_wraps ? capacity : next_entry; + + /* bail out if nothing in log */ + if (size == 0) { + IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); + return; + } + + IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n", + size, num_wraps); + + /* if uCode has wrapped back to top of log, start at the oldest entry, + * i.e the next one that uCode would fill. */ + if (num_wraps) + iwl_print_event_log(priv, next_entry, + capacity - next_entry, mode); + /* (then/else) start at top of log */ + iwl_print_event_log(priv, 0, next_entry, mode); + +} /** * iwl_irq_handle_error - called for HW or SW error interrupt from card */ @@ -2040,191 +2222,6 @@ int iwl_verify_ucode(struct iwl_priv *priv) EXPORT_SYMBOL(iwl_verify_ucode); -static const char *desc_lookup_text[] = { - "OK", - "FAIL", - "BAD_PARAM", - "BAD_CHECKSUM", - "NMI_INTERRUPT_WDG", - "SYSASSERT", - "FATAL_ERROR", - "BAD_COMMAND", - "HW_ERROR_TUNE_LOCK", - "HW_ERROR_TEMPERATURE", - "ILLEGAL_CHAN_FREQ", - "VCC_NOT_STABLE", - "FH_ERROR", - "NMI_INTERRUPT_HOST", - "NMI_INTERRUPT_ACTION_PT", - "NMI_INTERRUPT_UNKNOWN", - "UCODE_VERSION_MISMATCH", - "HW_ERROR_ABS_LOCK", - "HW_ERROR_CAL_LOCK_FAIL", - "NMI_INTERRUPT_INST_ACTION_PT", - "NMI_INTERRUPT_DATA_ACTION_PT", - "NMI_TRM_HW_ER", - "NMI_INTERRUPT_TRM", - "NMI_INTERRUPT_BREAK_POINT" - "DEBUG_0", - "DEBUG_1", - "DEBUG_2", - "DEBUG_3", - "UNKNOWN" -}; - -static const char *desc_lookup(int i) -{ - int max = ARRAY_SIZE(desc_lookup_text) - 1; - - if (i < 0 || i > max) - i = max; - - return desc_lookup_text[i]; -} - -#define ERROR_START_OFFSET (1 * sizeof(u32)) -#define ERROR_ELEM_SIZE (7 * sizeof(u32)) - -void iwl_dump_nic_error_log(struct iwl_priv *priv) -{ - u32 data2, line; - u32 desc, time, count, base, data1; - u32 blink1, blink2, ilink1, ilink2; - - if (priv->ucode_type == UCODE_INIT) - base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); - else - base = le32_to_cpu(priv->card_alive.error_event_table_ptr); - - if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { - IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base); - return; - } - - count = iwl_read_targ_mem(priv, base); - - if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { - IWL_ERR(priv, "Start IWL Error Log Dump:\n"); - IWL_ERR(priv, "Status: 0x%08lX, count: %d\n", - priv->status, count); - } - - desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32)); - blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32)); - blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32)); - ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32)); - ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32)); - data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32)); - data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32)); - line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); - time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); - - IWL_ERR(priv, "Desc Time " - "data1 data2 line\n"); - IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n", - desc_lookup(desc), desc, time, data1, data2, line); - IWL_ERR(priv, "blink1 blink2 ilink1 ilink2\n"); - IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, - ilink1, ilink2); - -} -EXPORT_SYMBOL(iwl_dump_nic_error_log); - -#define EVENT_START_OFFSET (4 * sizeof(u32)) - -/** - * iwl_print_event_log - Dump error event log to syslog - * - */ -static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, - u32 num_events, u32 mode) -{ - u32 i; - u32 base; /* SRAM byte address of event log header */ - u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ - u32 ptr; /* SRAM byte address of log data */ - u32 ev, time, data; /* event log data */ - - if (num_events == 0) - return; - if (priv->ucode_type == UCODE_INIT) - base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); - else - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - - if (mode == 0) - event_size = 2 * sizeof(u32); - else - event_size = 3 * sizeof(u32); - - ptr = base + EVENT_START_OFFSET + (start_idx * event_size); - - /* "time" is actually "data" for mode 0 (no timestamp). - * place event id # at far right for easier visual parsing. */ - for (i = 0; i < num_events; i++) { - ev = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); - time = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); - if (mode == 0) { - /* data, ev */ - IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev); - } else { - data = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); - IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n", - time, data, ev); - } - } -} - -void iwl_dump_nic_event_log(struct iwl_priv *priv) -{ - u32 base; /* SRAM byte address of event log header */ - u32 capacity; /* event log capacity in # entries */ - u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ - u32 num_wraps; /* # times uCode wrapped to top of log */ - u32 next_entry; /* index of next entry to be written by uCode */ - u32 size; /* # entries that we'll print */ - - if (priv->ucode_type == UCODE_INIT) - base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); - else - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - - if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { - IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base); - return; - } - - /* event log header */ - capacity = iwl_read_targ_mem(priv, base); - mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); - num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); - next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); - - size = num_wraps ? capacity : next_entry; - - /* bail out if nothing in log */ - if (size == 0) { - IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); - return; - } - - IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n", - size, num_wraps); - - /* if uCode has wrapped back to top of log, start at the oldest entry, - * i.e the next one that uCode would fill. */ - if (num_wraps) - iwl_print_event_log(priv, next_entry, - capacity - next_entry, mode); - /* (then/else) start at top of log */ - iwl_print_event_log(priv, 0, next_entry, mode); - -} -EXPORT_SYMBOL(iwl_dump_nic_event_log); - void iwl_rf_kill_ct_config(struct iwl_priv *priv) { struct iwl_ct_kill_config cmd; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a658410e66a..640c4644a16 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -472,7 +472,6 @@ int iwl_pci_resume(struct pci_dev *pdev); /***************************************************** * Error Handling Debugging ******************************************************/ -void iwl_dump_nic_error_log(struct iwl_priv *priv); void iwl_dump_nic_event_log(struct iwl_priv *priv); void iwl_clear_isr_stats(struct iwl_priv *priv); -- cgit v1.2.3-18-g5258 From fe643414dbf330d6d910e01edd48dd93dc6f2942 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 14 Jul 2009 22:37:13 +0200 Subject: wireless: wl12xx, fix lock imbalance Add omitted mutex_unlock to one of wl12xx_op_start fail paths (when wl12xx_chip_wakeup fails). [v2] Power off the device, because: \= cite from http://marc.info/?l=linux-kernel&m=124755028209880&w=2 If the chip cannot be booted, why should it remain powered on? In some rare cases, the chip might fail to initialize, but can recover if powered off and on again, so turning it off at this point is the right thing to do. =/ Signed-off-by: Jiri Slaby Reviewed-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index cf5e0549fa1..106b0f26519 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -349,7 +349,7 @@ static int wl1251_op_start(struct ieee80211_hw *hw) ret = wl1251_chip_wakeup(wl); if (ret < 0) - return ret; + goto out; ret = wl->chip.op_boot(wl); if (ret < 0) -- cgit v1.2.3-18-g5258 From e43419f9ad99112a2715ee34c634ffeac3bf730d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:13:54 -0400 Subject: ath9k: downgrade assert in rc.c for invalid rate The case where no vaid rate is found should not happen now but to help debugging and downgrade this to a warn. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index ba06e78b2f5..d7f403080f7 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -741,10 +741,18 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, if (rate > (ath_rc_priv->rate_table_size - 1)) rate = ath_rc_priv->rate_table_size - 1; - ASSERT((rate_table->info[rate].valid && - (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)) || - (rate_table->info[rate].valid_single_stream && - !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG))); + if (rate_table->info[rate].valid && + (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)) + return rate; + + if (rate_table->info[rate].valid_single_stream && + !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)); + return rate; + + /* This should not happen */ + WARN_ON(1); + + rate = ath_rc_priv->valid_rate_index[0]; return rate; } -- cgit v1.2.3-18-g5258 From 0ab216d9727c0728c8b5f9ad627b6955570303d7 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:13:55 -0400 Subject: iwlwifi: remove rs_get_rate workaround This removes the work around implemented for transmitting on an unsupported band on iwlwifi. This was added via the patch: 8e1856e82cb8f541e925738bebfbc473420cda68: iwlwifi: fix rs_get_rate WARN_ON() Cc: Mohamed Abbas Cc: Reinette Chatre Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 12 ++---------- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 11 +---------- 2 files changed, 3 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 5eb538d18a8..b23fd537f21 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -674,28 +674,20 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, unsigned long flags; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; u16 fc; - u16 rate_mask = 0; + u16 rate_mask = sta ? sta->supp_rates[sband->band] : 0; s8 max_rate_idx = -1; struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); IWL_DEBUG_RATE(priv, "enter\n"); - if (sta) - rate_mask = sta->supp_rates[sband->band]; - /* Send management frames and NO_ACK data using lowest rate. */ fc = le16_to_cpu(hdr->frame_control); if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || info->flags & IEEE80211_TX_CTL_NO_ACK || !sta || !priv_sta) { IWL_DEBUG_RATE(priv, "leave: No STA priv data to update!\n"); - if (!rate_mask) - info->control.rates[0].idx = - rate_lowest_index(sband, NULL); - else - info->control.rates[0].idx = - rate_lowest_index(sband, sta); + info->control.rates[0].idx = rate_lowest_index(sband, sta); if (info->flags & IEEE80211_TX_CTL_NO_ACK) info->control.rates[0].count = 1; return; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index ff20e5048a5..3fea027f35d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2466,7 +2466,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_lq_sta *lq_sta = priv_sta; int rate_idx; - u64 mask_bit = 0; IWL_DEBUG_RATE_LIMIT(priv, "rate scale calculate new rate for skb\n"); @@ -2481,18 +2480,10 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, lq_sta->max_rate_idx = -1; } - if (sta) - mask_bit = sta->supp_rates[sband->band]; - /* Send management frames and NO_ACK data using lowest rate. */ if (!ieee80211_is_data(hdr->frame_control) || info->flags & IEEE80211_TX_CTL_NO_ACK || !sta || !lq_sta) { - if (!mask_bit) - info->control.rates[0].idx = - rate_lowest_index(sband, NULL); - else - info->control.rates[0].idx = - rate_lowest_index(sband, sta); + info->control.rates[0].idx = rate_lowest_index(sband, sta); if (info->flags & IEEE80211_TX_CTL_NO_ACK) info->control.rates[0].count = 1; return; -- cgit v1.2.3-18-g5258 From dd1901830ca7baaaae2e58f549f770f215c6f3af Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:13:56 -0400 Subject: ath9k: cleanup try count for MRR in rate control This has no functional change and just cleans up the code to be more legible and removes a useless variable for Multi Rate Retry. For regular frames we use 2 retries for MRR segments [0-2]. For the last MRR segment [3] we use 4. MRR[0] = 2 MRR[1] = 2 MRR[2] = 2 MRR[3] = 4 Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/main.c | 3 ++- drivers/net/wireless/ath/ath9k/rc.c | 29 ++++++++++++++++++++--------- 3 files changed, 22 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index eb9d5228cb6..3afd7ee41a6 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -164,7 +164,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, #define WME_NUM_TID 16 #define ATH_TXBUF 512 #define ATH_TXMAXTRY 13 -#define ATH_11N_TXMAXTRY 10 #define ATH_MGT_TXMAXTRY 4 #define WME_BA_BMP_SIZE 64 #define WME_MAX_BA WME_BA_BMP_SIZE diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 961b0ce6ef3..19df7882d0d 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1540,7 +1540,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->max_rates = 4; hw->channel_change_time = 5000; hw->max_listen_interval = 10; - hw->max_rate_tries = ATH_11N_TXMAXTRY; + /* Hardware supports 10 but we use 4 */ + hw->max_rate_tries = 4; hw->sta_data_size = sizeof(struct ath_node); hw->vif_data_size = sizeof(struct ath_vif); diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index d7f403080f7..a23b66bdbe9 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -853,9 +853,21 @@ static void ath_rc_ratefind(struct ath_softc *sc, struct ieee80211_tx_rate *rates = tx_info->control.rates; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; __le16 fc = hdr->frame_control; - u8 try_per_rate = 0, i = 0, rix, nrix; + u8 try_per_rate, i = 0, rix, nrix; int is_probe = 0; + /* + * For Multi Rate Retry we use a different number of + * retry attempt counts. This ends up looking like this: + * + * MRR[0] = 2 + * MRR[1] = 2 + * MRR[2] = 2 + * MRR[3] = 4 + * + */ + try_per_rate = sc->hw->max_rate_tries; + rate_table = sc->cur_rate_table; rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, &is_probe); nrix = rix; @@ -866,7 +878,6 @@ static void ath_rc_ratefind(struct ath_softc *sc, ath_rc_rate_set_series(rate_table, &rates[i++], txrc, 1, nrix, 0); - try_per_rate = (ATH_11N_TXMAXTRY/4); /* Get the next tried/allowed rate. No RTS for the next series * after the probe rate */ @@ -877,7 +888,6 @@ static void ath_rc_ratefind(struct ath_softc *sc, tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; } else { - try_per_rate = (ATH_11N_TXMAXTRY/4); /* Set the choosen rate. No RTS for first series entry. */ ath_rc_rate_set_series(rate_table, &rates[i++], txrc, try_per_rate, nrix, 0); @@ -885,18 +895,19 @@ static void ath_rc_ratefind(struct ath_softc *sc, /* Fill in the other rates for multirate retry */ for ( ; i < 4; i++) { - u8 try_num; u8 min_rate; - try_num = ((i + 1) == 4) ? - ATH_11N_TXMAXTRY - (try_per_rate * i) : try_per_rate ; + /* Use twice the number of tries for the last MRR segment. */ + if (i + 1 == 4) + try_per_rate = 4; + min_rate = (((i + 1) == 4) && 0); nrix = ath_rc_rate_getidx(sc, ath_rc_priv, rate_table, nrix, 1, min_rate); /* All other rates in the series have RTS enabled */ ath_rc_rate_set_series(rate_table, &rates[i], txrc, - try_num, nrix, 1); + try_per_rate, nrix, 1); } /* @@ -1529,7 +1540,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, /* * If underrun error is seen assume it as an excessive retry only * if prefetch trigger level have reached the max (0x3f for 5416) - * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY + * Adjust the long retry as if the frame was tried hw->max_rate_tries * times. This affects how ratectrl updates PER for the failed rate. */ if (tx_info_priv->tx.ts_flags & @@ -1544,7 +1555,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, tx_status = 1; ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status, - (is_underrun) ? ATH_11N_TXMAXTRY : + (is_underrun) ? sc->hw->max_rate_tries : tx_info_priv->tx.ts_longretry); /* Check if aggregation has to be enabled for this tid */ -- cgit v1.2.3-18-g5258 From 984d021d56f036e5ffbef191cb5e498cf159784d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:13:57 -0400 Subject: ath9k: remove unused min rate calculation code This is not used, and when we need to get the lowest rate we should simply use mac80211's own rate_lowest_index(sband, sta). Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index a23b66bdbe9..7b37b2798df 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -817,28 +817,17 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc, static u8 ath_rc_rate_getidx(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, const struct ath_rate_table *rate_table, - u8 rix, u16 stepdown, - u16 min_rate) + u8 rix, u16 stepdown) { u32 j; u8 nextindex = 0; - if (min_rate) { - for (j = RATE_TABLE_SIZE; j > 0; j--) { - if (ath_rc_get_nextlowervalid_txrate(rate_table, - ath_rc_priv, rix, &nextindex)) - rix = nextindex; - else - break; - } - } else { - for (j = stepdown; j > 0; j--) { - if (ath_rc_get_nextlowervalid_txrate(rate_table, - ath_rc_priv, rix, &nextindex)) - rix = nextindex; - else - break; - } + for (j = stepdown; j > 0; j--) { + if (ath_rc_get_nextlowervalid_txrate(rate_table, + ath_rc_priv, rix, &nextindex)) + rix = nextindex; + else + break; } return rix; } @@ -882,7 +871,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, * after the probe rate */ nrix = ath_rc_rate_getidx(sc, ath_rc_priv, - rate_table, nrix, 1, 0); + rate_table, nrix, 1); ath_rc_rate_set_series(rate_table, &rates[i++], txrc, try_per_rate, nrix, 0); @@ -895,16 +884,12 @@ static void ath_rc_ratefind(struct ath_softc *sc, /* Fill in the other rates for multirate retry */ for ( ; i < 4; i++) { - u8 min_rate; - /* Use twice the number of tries for the last MRR segment. */ if (i + 1 == 4) try_per_rate = 4; - min_rate = (((i + 1) == 4) && 0); - nrix = ath_rc_rate_getidx(sc, ath_rc_priv, - rate_table, nrix, 1, min_rate); + rate_table, nrix, 1); /* All other rates in the series have RTS enabled */ ath_rc_rate_set_series(rate_table, &rates[i], txrc, try_per_rate, nrix, 1); -- cgit v1.2.3-18-g5258 From 7466c524a42110e921e79b390b58bfc6ca6d249e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:13:58 -0400 Subject: ath9k: remove unused stepdown when looking for the next rate This is not used, remove this. Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 7b37b2798df..64cb697805b 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -817,19 +817,14 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc, static u8 ath_rc_rate_getidx(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, const struct ath_rate_table *rate_table, - u8 rix, u16 stepdown) + u8 rix) { - u32 j; u8 nextindex = 0; - - for (j = stepdown; j > 0; j--) { - if (ath_rc_get_nextlowervalid_txrate(rate_table, - ath_rc_priv, rix, &nextindex)) - rix = nextindex; - else - break; - } - return rix; + if (ath_rc_get_nextlowervalid_txrate(rate_table, + ath_rc_priv, rix, &nextindex)) + return nextindex; + else + return rix; } static void ath_rc_ratefind(struct ath_softc *sc, @@ -871,7 +866,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, * after the probe rate */ nrix = ath_rc_rate_getidx(sc, ath_rc_priv, - rate_table, nrix, 1); + rate_table, nrix); ath_rc_rate_set_series(rate_table, &rates[i++], txrc, try_per_rate, nrix, 0); @@ -889,7 +884,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, try_per_rate = 4; nrix = ath_rc_rate_getidx(sc, ath_rc_priv, - rate_table, nrix, 1); + rate_table, nrix); /* All other rates in the series have RTS enabled */ ath_rc_rate_set_series(rate_table, &rates[i], txrc, try_per_rate, nrix, 1); -- cgit v1.2.3-18-g5258 From 20f57215a2ff75f7c2e4004b7583e1fec925679e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:13:59 -0400 Subject: ath9k: remove pointless wrapper ath_rc_rate_getidx() This is just calling another helper, so just use the other helper directly. This should make it clear that when do not find the next rate we stick to the current one. Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 64cb697805b..03e7df42675 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -814,19 +814,6 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc, tx_info->control.rts_cts_rate_idx = cix; } -static u8 ath_rc_rate_getidx(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv, - const struct ath_rate_table *rate_table, - u8 rix) -{ - u8 nextindex = 0; - if (ath_rc_get_nextlowervalid_txrate(rate_table, - ath_rc_priv, rix, &nextindex)) - return nextindex; - else - return rix; -} - static void ath_rc_ratefind(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, struct ieee80211_tx_rate_control *txrc) @@ -865,8 +852,8 @@ static void ath_rc_ratefind(struct ath_softc *sc, /* Get the next tried/allowed rate. No RTS for the next series * after the probe rate */ - nrix = ath_rc_rate_getidx(sc, ath_rc_priv, - rate_table, nrix); + ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv, + rix, &nrix); ath_rc_rate_set_series(rate_table, &rates[i++], txrc, try_per_rate, nrix, 0); @@ -883,8 +870,8 @@ static void ath_rc_ratefind(struct ath_softc *sc, if (i + 1 == 4) try_per_rate = 4; - nrix = ath_rc_rate_getidx(sc, ath_rc_priv, - rate_table, nrix); + ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv, + rix, &nrix); /* All other rates in the series have RTS enabled */ ath_rc_rate_set_series(rate_table, &rates[i], txrc, try_per_rate, nrix, 1); -- cgit v1.2.3-18-g5258 From 39448b0a27529f2feecd876729ef0fba25354363 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:14:00 -0400 Subject: ath9k: rename ath_rc_get_nextlowervalid_txrate() What this does is get us our next lower rate so call it that, ath_rc_get_lower_rix(). Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 03e7df42675..c8f800e6c29 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -501,9 +501,9 @@ static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw) } static inline int -ath_rc_get_nextlowervalid_txrate(const struct ath_rate_table *rate_table, - struct ath_rate_priv *ath_rc_priv, - u8 cur_valid_txrate, u8 *next_idx) +ath_rc_get_lower_rix(const struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, + u8 cur_valid_txrate, u8 *next_idx) { int8_t i; @@ -852,8 +852,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, /* Get the next tried/allowed rate. No RTS for the next series * after the probe rate */ - ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv, - rix, &nrix); + ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix); ath_rc_rate_set_series(rate_table, &rates[i++], txrc, try_per_rate, nrix, 0); @@ -870,8 +869,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, if (i + 1 == 4) try_per_rate = 4; - ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv, - rix, &nrix); + ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix); /* All other rates in the series have RTS enabled */ ath_rc_rate_set_series(rate_table, &rates[i], txrc, try_per_rate, nrix, 1); @@ -1156,8 +1154,8 @@ static void ath_rc_update_ht(struct ath_softc *sc, if (ath_rc_priv->state[tx_rate].per >= 55 && tx_rate > 0 && rate_table->info[tx_rate].ratekbps <= rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) { - ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv, - (u8)tx_rate, &ath_rc_priv->rate_max_phy); + ath_rc_get_lower_rix(rate_table, ath_rc_priv, + (u8)tx_rate, &ath_rc_priv->rate_max_phy); /* Don't probe for a little while. */ ath_rc_priv->probe_time = now_msec; -- cgit v1.2.3-18-g5258 From 4e6df85dacedbc68b551fdd8677f7df68639c181 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:14:01 -0400 Subject: ath9k: remove unused ath_rc_isvalid_txmask() Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index c8f800e6c29..b0e3702ca06 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -454,13 +454,6 @@ static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv, ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? 1 : 0; } -static inline int ath_rc_isvalid_txmask(struct ath_rate_priv *ath_rc_priv, - u8 index) -{ - ASSERT(index <= ath_rc_priv->rate_table_size); - return ath_rc_priv->valid_rate_index[index]; -} - static inline int ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table, struct ath_rate_priv *ath_rc_priv, -- cgit v1.2.3-18-g5258 From dfe80a3fd2199c31d0a2dc24044abaadb64c26c2 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:14:02 -0400 Subject: ath9k: remove ATH9K_MODE_11B This saves us 2733 bytes. text data bss dec hex filename 252265 3628 1584 257477 3edc5 ath9k-has-b-rate.ko 249905 3628 1584 255117 3e48d ath9k.ko Cc: Derek Smithies Cc: Chittajit Mitra Siged-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 1 - drivers/net/wireless/ath/ath9k/hw.h | 1 - drivers/net/wireless/ath/ath9k/rc.c | 23 ----------------------- 3 files changed, 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index cffb0789f66..a115c8ceabe 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3305,7 +3305,6 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) } if (eeval & AR5416_OPFLAGS_11G) { - set_bit(ATH9K_MODE_11B, pCap->wireless_modes); set_bit(ATH9K_MODE_11G, pCap->wireless_modes); if (ah->config.ht_enable) { if (!(eeval & AR5416_OPFLAGS_N_2G_HT20)) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 9d0b31ad460..5e40223259c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -113,7 +113,6 @@ enum wireless_mode { ATH9K_MODE_11A = 0, - ATH9K_MODE_11B = 2, ATH9K_MODE_11G = 3, ATH9K_MODE_11NA_HT20 = 6, ATH9K_MODE_11NG_HT20 = 7, diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index b0e3702ca06..112a0ec0df4 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -380,27 +380,6 @@ static const struct ath_rate_table ar5416_11g_ratetable = { 0, /* Phy rates allowed initially */ }; -static const struct ath_rate_table ar5416_11b_ratetable = { - 4, - { - { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ - 900, 0x1b, 0x00, (0x80|2), - 0, 0, 1, 0, 0 }, - { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ - 1800, 0x1a, 0x04, (0x80|4), - 1, 1, 1, 1, 0 }, - { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ - 4300, 0x19, 0x04, (0x80|11), - 1, 2, 2, 2, 0 }, - { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ - 7100, 0x18, 0x04, (0x80|22), - 1, 4, 100, 3, 0 }, - }, - 100, /* probe interval */ - 100, /* rssi reduce interval */ - 0, /* Phy rates allowed initially */ -}; - static inline int8_t median(int8_t a, int8_t b, int8_t c) { if (a >= b) { @@ -1702,8 +1681,6 @@ static struct rate_control_ops ath_rate_ops = { void ath_rate_attach(struct ath_softc *sc) { - sc->hw_rate_table[ATH9K_MODE_11B] = - &ar5416_11b_ratetable; sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable; sc->hw_rate_table[ATH9K_MODE_11G] = -- cgit v1.2.3-18-g5258 From b9b6e15a9481441108ad2527db0187f729c88970 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:14:03 -0400 Subject: ath9k: remap ATH9K_MODE_* There are a lot of gaps here. Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 5e40223259c..9a4570d7ecb 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -113,14 +113,14 @@ enum wireless_mode { ATH9K_MODE_11A = 0, - ATH9K_MODE_11G = 3, - ATH9K_MODE_11NA_HT20 = 6, - ATH9K_MODE_11NG_HT20 = 7, - ATH9K_MODE_11NA_HT40PLUS = 8, - ATH9K_MODE_11NA_HT40MINUS = 9, - ATH9K_MODE_11NG_HT40PLUS = 10, - ATH9K_MODE_11NG_HT40MINUS = 11, - ATH9K_MODE_MAX + ATH9K_MODE_11G, + ATH9K_MODE_11NA_HT20, + ATH9K_MODE_11NG_HT20, + ATH9K_MODE_11NA_HT40PLUS, + ATH9K_MODE_11NA_HT40MINUS, + ATH9K_MODE_11NG_HT40PLUS, + ATH9K_MODE_11NG_HT40MINUS, + ATH9K_MODE_MAX, }; enum ath9k_hw_caps { -- cgit v1.2.3-18-g5258 From 201c3b414b4b759f399502b059189d7802bbfbb6 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:14:04 -0400 Subject: ath9k: rename ath_rc_ratefind_ht() to ath_rc_get_highest_rix() The purpose is to find the highest rate we can use. Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 112a0ec0df4..96d46d697e9 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -601,10 +601,11 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, return hi; } -static u8 ath_rc_ratefind_ht(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv, - const struct ath_rate_table *rate_table, - int *is_probing) +/* Finds the highest rate index we can use */ +static u8 ath_rc_get_highest_rix(struct ath_softc *sc, + struct ath_rate_priv *ath_rc_priv, + const struct ath_rate_table *rate_table, + int *is_probing) { u32 dt, best_thruput, this_thruput, now_msec; u8 rate, next_rate, best_rate, maxindex, minindex; @@ -812,7 +813,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, try_per_rate = sc->hw->max_rate_tries; rate_table = sc->cur_rate_table; - rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, &is_probe); + rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe); nrix = rix; if (is_probe) { -- cgit v1.2.3-18-g5258 From 7682a76df8f4e875e4029d95b799c712ee740ddc Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:14:05 -0400 Subject: ath9k: remove unnecessary IEEE80211_TX_CTL_NO_ACK checks We check for this condition early on in our mac80211 get_rate() callback ath_get_rate(), so remove this check later down the path. Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 96d46d697e9..2c72901adbe 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -777,7 +777,6 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc, * just CTS. Note that this is only done for OFDM/HT unicast frames. */ if ((sc->sc_flags & SC_OP_PROTECT_ENABLE) && - !(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) && (rate_table->info[rix].phy == WLAN_RC_PHY_OFDM || WLAN_RC_PHY_HT(rate_table->info[rix].phy))) { rates[0].flags |= IEEE80211_TX_RC_USE_CTS_PROTECT; @@ -882,9 +881,8 @@ static void ath_rc_ratefind(struct ath_softc *sc, * * FIXME: Fix duration */ - if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) && - (ieee80211_has_morefrags(fc) || - (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG))) { + if (ieee80211_has_morefrags(fc) || + (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { rates[1].count = rates[2].count = rates[3].count = 0; rates[1].idx = rates[2].idx = rates[3].idx = 0; rates[0].count = ATH_TXMAXTRY; -- cgit v1.2.3-18-g5258 From 943ab70f6aebfdc0005ef7e58ae982e9ec22224b Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:14:07 -0400 Subject: iwlwifi: use ieee80211_is_data(fc) iwl-agn-rs.c already uses this. Cc: Zhu Yi Cc: Reinette Chatre Cc: ipw3945-devel@lists.sourceforge.net Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 7 +++---- drivers/net/wireless/iwlwifi/iwl-sta.c | 5 ++--- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index b23fd537f21..2b776924d5e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -673,7 +673,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, s8 scale_action = 0; unsigned long flags; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - u16 fc; + __le16 fc; u16 rate_mask = sta ? sta->supp_rates[sband->band] : 0; s8 max_rate_idx = -1; struct iwl_priv *priv = (struct iwl_priv *)priv_r; @@ -682,9 +682,8 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, IWL_DEBUG_RATE(priv, "enter\n"); /* Send management frames and NO_ACK data using lowest rate. */ - fc = le16_to_cpu(hdr->frame_control); - if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || - info->flags & IEEE80211_TX_CTL_NO_ACK || + fc = hdr->frame_control; + if (!ieee80211_is_data(fc) || info->flags & IEEE80211_TX_CTL_NO_ACK || !sta || !priv_sta) { IWL_DEBUG_RATE(priv, "leave: No STA priv data to update!\n"); info->control.rates[0].idx = rate_lowest_index(sband, sta); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 2addf735b19..afa1633602a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1044,11 +1044,10 @@ EXPORT_SYMBOL(iwl_rxon_add_station); int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) { int sta_id; - u16 fc = le16_to_cpu(hdr->frame_control); + __le16 fc = hdr->frame_control; /* If this frame is broadcast or management, use broadcast station id */ - if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || - is_multicast_ether_addr(hdr->addr1)) + if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) return priv->hw_params.bcast_sta_id; switch (priv->iw_mode) { -- cgit v1.2.3-18-g5258 From 4c6d4f5c33fbe19b134c1af43af166fee79eb986 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 16 Jul 2009 10:05:41 -0700 Subject: mac80211: add helper for management / no-ack frame rate decision All current rate control algorithms agree to send management and no-ack frames at the lowest rate. They also agree to do this when sta and the private rate control data is NULL. We add a hlper to mac80211 for this and simplify the rate control algorithm code. Developers wishing to make enhancements to rate control algorithms are for broadcast/multicast can opt to not use this in their gate_rate() mac80211 callback. Cc: Zhu Yi Acked-by: Reinette Chatre Cc: ipw3945-devel@lists.sourceforge.net Cc: Gabor Juhos Acked-by: Felix Fietkau Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 14 +------------- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 13 +++---------- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 7 +------ 3 files changed, 5 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 2c72901adbe..630fcf46e0d 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1518,23 +1518,11 @@ exit: static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_tx_rate_control *txrc) { - struct ieee80211_supported_band *sband = txrc->sband; - struct sk_buff *skb = txrc->skb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ath_softc *sc = priv; struct ath_rate_priv *ath_rc_priv = priv_sta; - __le16 fc = hdr->frame_control; - /* lowest rate for management and NO_ACK frames */ - if (!ieee80211_is_data(fc) || - tx_info->flags & IEEE80211_TX_CTL_NO_ACK || !sta) { - tx_info->control.rates[0].idx = rate_lowest_index(sband, sta); - tx_info->control.rates[0].count = - (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) ? - 1 : ATH_MGT_TXMAXTRY; + if (rate_control_send_low(sta, priv_sta, txrc)) return; - } /* Find tx rate for unicast frames */ ath_rc_ratefind(sc, ath_rc_priv, txrc); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 2b776924d5e..a16bd4147ea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -673,7 +673,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, s8 scale_action = 0; unsigned long flags; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - __le16 fc; u16 rate_mask = sta ? sta->supp_rates[sband->band] : 0; s8 max_rate_idx = -1; struct iwl_priv *priv = (struct iwl_priv *)priv_r; @@ -681,16 +680,10 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, IWL_DEBUG_RATE(priv, "enter\n"); - /* Send management frames and NO_ACK data using lowest rate. */ - fc = hdr->frame_control; - if (!ieee80211_is_data(fc) || info->flags & IEEE80211_TX_CTL_NO_ACK || - !sta || !priv_sta) { - IWL_DEBUG_RATE(priv, "leave: No STA priv data to update!\n"); - info->control.rates[0].idx = rate_lowest_index(sband, sta); - if (info->flags & IEEE80211_TX_CTL_NO_ACK) - info->control.rates[0].count = 1; + if (rate_control_send_low(sta, priv_sta, txrc)) return; - } + + rate_mask = sta->supp_rates[sband->band]; /* get user max rate if set */ max_rate_idx = txrc->max_rate_idx; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 3fea027f35d..63280411fd5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2481,13 +2481,8 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, } /* Send management frames and NO_ACK data using lowest rate. */ - if (!ieee80211_is_data(hdr->frame_control) || - info->flags & IEEE80211_TX_CTL_NO_ACK || !sta || !lq_sta) { - info->control.rates[0].idx = rate_lowest_index(sband, sta); - if (info->flags & IEEE80211_TX_CTL_NO_ACK) - info->control.rates[0].count = 1; + if (rate_control_send_low(sta, priv_sta, txrc)) return; - } rate_idx = lq_sta->last_txrate_idx; -- cgit v1.2.3-18-g5258 From e25739a171d7352168346dbab7f006e1f9275995 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:14:09 -0400 Subject: ath9k: remove rate control wraper After the cleanup we just use get_rate as a wrapper, skip the wrapper. Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 630fcf46e0d..e66734c2cae 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -786,10 +786,11 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc, tx_info->control.rts_cts_rate_idx = cix; } -static void ath_rc_ratefind(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv, - struct ieee80211_tx_rate_control *txrc) +static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, + struct ieee80211_tx_rate_control *txrc) { + struct ath_softc *sc = priv; + struct ath_rate_priv *ath_rc_priv = priv_sta; const struct ath_rate_table *rate_table; struct sk_buff *skb = txrc->skb; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); @@ -799,6 +800,9 @@ static void ath_rc_ratefind(struct ath_softc *sc, u8 try_per_rate, i = 0, rix, nrix; int is_probe = 0; + if (rate_control_send_low(sta, priv_sta, txrc)) + return; + /* * For Multi Rate Retry we use a different number of * retry attempt counts. This ends up looking like this: @@ -1515,19 +1519,6 @@ exit: kfree(tx_info_priv); } -static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, - struct ieee80211_tx_rate_control *txrc) -{ - struct ath_softc *sc = priv; - struct ath_rate_priv *ath_rc_priv = priv_sta; - - if (rate_control_send_low(sta, priv_sta, txrc)) - return; - - /* Find tx rate for unicast frames */ - ath_rc_ratefind(sc, ath_rc_priv, txrc); -} - static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta) { -- cgit v1.2.3-18-g5258 From 39a4cafe1638bb21f335b210d037cd2cd8ce6c08 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 14 Jul 2009 20:14:10 -0400 Subject: ath9k: Remove dead code in rate control ath9k rate control is based on only PER (packet error rate), remove unused code which was intented to do rssi based rate selection. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 163 +----------------------------------- 1 file changed, 4 insertions(+), 159 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index e66734c2cae..a39b1a7d377 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -607,47 +607,14 @@ static u8 ath_rc_get_highest_rix(struct ath_softc *sc, const struct ath_rate_table *rate_table, int *is_probing) { - u32 dt, best_thruput, this_thruput, now_msec; + u32 best_thruput, this_thruput, now_msec; u8 rate, next_rate, best_rate, maxindex, minindex; - int8_t rssi_last, rssi_reduce = 0, index = 0; - - *is_probing = 0; - - rssi_last = median(ath_rc_priv->rssi_last, - ath_rc_priv->rssi_last_prev, - ath_rc_priv->rssi_last_prev2); - - /* - * Age (reduce) last ack rssi based on how old it is. - * The bizarre numbers are so the delta is 160msec, - * meaning we divide by 16. - * 0msec <= dt <= 25msec: don't derate - * 25msec <= dt <= 185msec: derate linearly from 0 to 10dB - * 185msec <= dt: derate by 10dB - */ + int8_t index = 0; now_msec = jiffies_to_msecs(jiffies); - dt = now_msec - ath_rc_priv->rssi_time; - - if (dt >= 185) - rssi_reduce = 10; - else if (dt >= 25) - rssi_reduce = (u8)((dt - 25) >> 4); - - /* Now reduce rssi_last by rssi_reduce */ - if (rssi_last < rssi_reduce) - rssi_last = 0; - else - rssi_last -= rssi_reduce; - - /* - * Now look up the rate in the rssi table and return it. - * If no rates match then we return 0 (lowest rate) - */ - + *is_probing = 0; best_thruput = 0; maxindex = ath_rc_priv->max_valid_rate-1; - minindex = 0; best_rate = minindex; @@ -687,7 +654,6 @@ static u8 ath_rc_get_highest_rix(struct ath_softc *sc, } rate = best_rate; - ath_rc_priv->rssi_last_lookup = rssi_last; /* * Must check the actual rate (ratekbps) to account for @@ -977,10 +943,6 @@ static bool ath_rc_update_per(struct ath_softc *sc, (nretry_to_per_lookup[retries] >> 3)); } - ath_rc_priv->rssi_last_prev2 = ath_rc_priv->rssi_last_prev; - ath_rc_priv->rssi_last_prev = ath_rc_priv->rssi_last; - ath_rc_priv->rssi_last = tx_info_priv->tx.ts_rssi; - ath_rc_priv->rssi_time = now_msec; /* * If we got at most one retry then increase the max rate if @@ -1024,18 +986,9 @@ static bool ath_rc_update_per(struct ath_softc *sc, /* * Don't update anything. We don't know if * this was because of collisions or poor signal. - * - * Later: if rssi_ack is close to - * ath_rc_priv->state[txRate].rssi_thres and we see lots - * of retries, then we could increase - * ath_rc_priv->state[txRate].rssi_thres. */ ath_rc_priv->hw_maxretry_pktcnt = 0; } else { - int32_t rssi_ackAvg; - int8_t rssi_thres; - int8_t rssi_ack_vmin; - /* * It worked with no retries. First ignore bogus (small) * rssi_ack values. @@ -1045,43 +998,9 @@ static bool ath_rc_update_per(struct ath_softc *sc, ath_rc_priv->hw_maxretry_pktcnt++; } - if (tx_info_priv->tx.ts_rssi < - rate_table->info[tx_rate].rssi_ack_validmin) - goto exit; - - /* Average the rssi */ - if (tx_rate != ath_rc_priv->rssi_sum_rate) { - ath_rc_priv->rssi_sum_rate = tx_rate; - ath_rc_priv->rssi_sum = - ath_rc_priv->rssi_sum_cnt = 0; - } - - ath_rc_priv->rssi_sum += tx_info_priv->tx.ts_rssi; - ath_rc_priv->rssi_sum_cnt++; - - if (ath_rc_priv->rssi_sum_cnt < 4) - goto exit; - - rssi_ackAvg = - (ath_rc_priv->rssi_sum + 2) / 4; - rssi_thres = - ath_rc_priv->state[tx_rate].rssi_thres; - rssi_ack_vmin = - rate_table->info[tx_rate].rssi_ack_validmin; - - ath_rc_priv->rssi_sum = - ath_rc_priv->rssi_sum_cnt = 0; - - /* Now reduce the current rssi threshold */ - if ((rssi_ackAvg < rssi_thres + 2) && - (rssi_thres > rssi_ack_vmin)) { - ath_rc_priv->state[tx_rate].rssi_thres--; - } - - state_change = true; } } -exit: + return state_change; } @@ -1093,11 +1012,6 @@ static void ath_rc_update_ht(struct ath_softc *sc, struct ath_tx_info_priv *tx_info_priv, int tx_rate, int xretries, int retries) { -#define CHK_RSSI(rate) \ - ((ath_rc_priv->state[(rate)].rssi_thres + \ - rate_table->info[(rate)].rssi_ack_deltamin) > \ - ath_rc_priv->state[(rate)+1].rssi_thres) - u32 now_msec = jiffies_to_msecs(jiffies); int rate; u8 last_per; @@ -1108,13 +1022,6 @@ static void ath_rc_update_ht(struct ath_softc *sc, if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt)) return; - /* To compensate for some imbalance between ctrl and ext. channel */ - - if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy)) - tx_info_priv->tx.ts_rssi = - tx_info_priv->tx.ts_rssi < 3 ? 0 : - tx_info_priv->tx.ts_rssi - 3; - last_per = ath_rc_priv->state[tx_rate].per; /* Update PER first */ @@ -1136,51 +1043,6 @@ static void ath_rc_update_ht(struct ath_softc *sc, ath_rc_priv->probe_time = now_msec; } - if (state_change) { - /* - * Make sure the rates above this have higher rssi thresholds. - * (Note: Monotonicity is kept within the OFDM rates and - * within the CCK rates. However, no adjustment is - * made to keep the rssi thresholds monotonically - * increasing between the CCK and OFDM rates.) - */ - for (rate = tx_rate; rate < size - 1; rate++) { - if (rate_table->info[rate+1].phy != - rate_table->info[tx_rate].phy) - break; - - if (CHK_RSSI(rate)) { - ath_rc_priv->state[rate+1].rssi_thres = - ath_rc_priv->state[rate].rssi_thres + - rate_table->info[rate].rssi_ack_deltamin; - } - } - - /* Make sure the rates below this have lower rssi thresholds. */ - for (rate = tx_rate - 1; rate >= 0; rate--) { - if (rate_table->info[rate].phy != - rate_table->info[tx_rate].phy) - break; - - if (CHK_RSSI(rate)) { - if (ath_rc_priv->state[rate+1].rssi_thres < - rate_table->info[rate].rssi_ack_deltamin) - ath_rc_priv->state[rate].rssi_thres = 0; - else { - ath_rc_priv->state[rate].rssi_thres = - ath_rc_priv->state[rate+1].rssi_thres - - rate_table->info[rate].rssi_ack_deltamin; - } - - if (ath_rc_priv->state[rate].rssi_thres < - rate_table->info[rate].rssi_ack_validmin) { - ath_rc_priv->state[rate].rssi_thres = - rate_table->info[rate].rssi_ack_validmin; - } - } - } - } - /* Make sure the rates below this have lower PER */ /* Monotonicity is kept only for rates below the current rate. */ if (ath_rc_priv->state[tx_rate].per < last_per) { @@ -1205,19 +1067,6 @@ static void ath_rc_update_ht(struct ath_softc *sc, ath_rc_priv->state[rate].per; } - /* Every so often, we reduce the thresholds and - * PER (different for CCK and OFDM). */ - if (now_msec - ath_rc_priv->rssi_down_time >= - rate_table->rssi_reduce_interval) { - - for (rate = 0; rate < size; rate++) { - if (ath_rc_priv->state[rate].rssi_thres > - rate_table->info[rate].rssi_ack_validmin) - ath_rc_priv->state[rate].rssi_thres -= 1; - } - ath_rc_priv->rssi_down_time = now_msec; - } - /* Every so often, we reduce the thresholds * and PER (different for CCK and OFDM). */ if (now_msec - ath_rc_priv->per_down_time >= @@ -1233,7 +1082,6 @@ static void ath_rc_update_ht(struct ath_softc *sc, ath_debug_stat_retries(sc, tx_rate, xretries, retries, ath_rc_priv->state[tx_rate].per); -#undef CHK_RSSI } static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table, @@ -1369,8 +1217,6 @@ static void ath_rc_init(struct ath_softc *sc, /* Initialize thresholds according to the global rate table */ for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) { - ath_rc_priv->state[i].rssi_thres = - rate_table->info[i].rssi_ack_validmin; ath_rc_priv->state[i].per = 0; } @@ -1631,7 +1477,6 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp return NULL; } - rate_priv->rssi_down_time = jiffies_to_msecs(jiffies); rate_priv->tx_triglevel_max = sc->sc_ah->caps.tx_triglevel_max; return rate_priv; -- cgit v1.2.3-18-g5258 From ddf4a2db72c1073b31d0ad28911d137b1745cfca Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 14 Jul 2009 20:14:11 -0400 Subject: ath9k: Remove unused members from rate control structure Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 216 ++++++++++++++++++------------------ drivers/net/wireless/ath/ath9k/rc.h | 21 ---- 2 files changed, 108 insertions(+), 129 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index a39b1a7d377..731967c74a1 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -22,130 +22,130 @@ static const struct ath_rate_table ar5416_11na_ratetable = { { { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, 12, - 0, 2, 1, 0, 0, 0, 0, 0 }, + 0, 0, 0, 0, 0, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, - 0, 3, 1, 1, 1, 1, 1, 0 }, + 0, 1, 1, 1, 1, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10000, 0x0a, 0x00, 24, - 2, 4, 2, 2, 2, 2, 2, 0 }, + 2, 2, 2, 2, 2, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 13900, 0x0e, 0x00, 36, - 2, 6, 2, 3, 3, 3, 3, 0 }, + 2, 3, 3, 3, 3, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17300, 0x09, 0x00, 48, - 4, 10, 3, 4, 4, 4, 4, 0 }, + 4, 4, 4, 4, 4, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23000, 0x0d, 0x00, 72, - 4, 14, 3, 5, 5, 5, 5, 0 }, + 4, 5, 5, 5, 5, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 0x08, 0x00, 96, - 4, 20, 3, 6, 6, 6, 6, 0 }, + 4, 6, 6, 6, 6, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 29300, 0x0c, 0x00, 108, - 4, 23, 3, 7, 7, 7, 7, 0 }, + 4, 7, 7, 7, 7, 0 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ 6400, 0x80, 0x00, 0, - 0, 2, 3, 8, 24, 8, 24, 3216 }, + 0, 8, 24, 8, 24, 3216 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */ 12700, 0x81, 0x00, 1, - 2, 4, 3, 9, 25, 9, 25, 6434 }, + 2, 9, 25, 9, 25, 6434 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */ 18800, 0x82, 0x00, 2, - 2, 6, 3, 10, 26, 10, 26, 9650 }, + 2, 10, 26, 10, 26, 9650 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */ 25000, 0x83, 0x00, 3, - 4, 10, 3, 11, 27, 11, 27, 12868 }, + 4, 11, 27, 11, 27, 12868 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */ 36700, 0x84, 0x00, 4, - 4, 14, 3, 12, 28, 12, 28, 19304 }, + 4, 12, 28, 12, 28, 19304 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */ 48100, 0x85, 0x00, 5, - 4, 20, 3, 13, 29, 13, 29, 25740 }, + 4, 13, 29, 13, 29, 25740 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */ 53500, 0x86, 0x00, 6, - 4, 23, 3, 14, 30, 14, 30, 28956 }, + 4, 14, 30, 14, 30, 28956 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */ 59000, 0x87, 0x00, 7, - 4, 25, 3, 15, 31, 15, 32, 32180 }, + 4, 15, 31, 15, 32, 32180 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */ 12700, 0x88, 0x00, - 8, 0, 2, 3, 16, 33, 16, 33, 6430 }, + 8, 3, 16, 33, 16, 33, 6430 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */ 24800, 0x89, 0x00, 9, - 2, 4, 3, 17, 34, 17, 34, 12860 }, + 2, 17, 34, 17, 34, 12860 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */ 36600, 0x8a, 0x00, 10, - 2, 6, 3, 18, 35, 18, 35, 19300 }, + 2, 18, 35, 18, 35, 19300 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */ 48100, 0x8b, 0x00, 11, - 4, 10, 3, 19, 36, 19, 36, 25736 }, + 4, 19, 36, 19, 36, 25736 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */ 69500, 0x8c, 0x00, 12, - 4, 14, 3, 20, 37, 20, 37, 38600 }, + 4, 20, 37, 20, 37, 38600 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */ 89500, 0x8d, 0x00, 13, - 4, 20, 3, 21, 38, 21, 38, 51472 }, + 4, 21, 38, 21, 38, 51472 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */ 98900, 0x8e, 0x00, 14, - 4, 23, 3, 22, 39, 22, 39, 57890 }, + 4, 22, 39, 22, 39, 57890 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */ 108300, 0x8f, 0x00, 15, - 4, 25, 3, 23, 40, 23, 41, 64320 }, + 4, 23, 40, 23, 41, 64320 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */ 13200, 0x80, 0x00, 0, - 0, 2, 3, 8, 24, 24, 24, 6684 }, + 0, 8, 24, 24, 24, 6684 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */ 25900, 0x81, 0x00, 1, - 2, 4, 3, 9, 25, 25, 25, 13368 }, + 2, 9, 25, 25, 25, 13368 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */ 38600, 0x82, 0x00, 2, - 2, 6, 3, 10, 26, 26, 26, 20052 }, + 2, 10, 26, 26, 26, 20052 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */ 49800, 0x83, 0x00, 3, - 4, 10, 3, 11, 27, 27, 27, 26738 }, + 4, 11, 27, 27, 27, 26738 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */ 72200, 0x84, 0x00, 4, - 4, 14, 3, 12, 28, 28, 28, 40104 }, + 4, 12, 28, 28, 28, 40104 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */ 92900, 0x85, 0x00, 5, - 4, 20, 3, 13, 29, 29, 29, 53476 }, + 4, 13, 29, 29, 29, 53476 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */ 102700, 0x86, 0x00, 6, - 4, 23, 3, 14, 30, 30, 30, 60156 }, + 4, 14, 30, 30, 30, 60156 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */ 112000, 0x87, 0x00, 7, - 4, 25, 3, 15, 31, 32, 32, 66840 }, + 4, 15, 31, 32, 32, 66840 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ 122000, 0x87, 0x00, 7, - 4, 25, 3, 15, 31, 32, 32, 74200 }, + 4, 15, 31, 32, 32, 74200 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */ 25800, 0x88, 0x00, 8, - 0, 2, 3, 16, 33, 33, 33, 13360 }, + 0, 16, 33, 33, 33, 13360 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */ 49800, 0x89, 0x00, 9, - 2, 4, 3, 17, 34, 34, 34, 26720 }, + 2, 17, 34, 34, 34, 26720 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */ 71900, 0x8a, 0x00, 10, - 2, 6, 3, 18, 35, 35, 35, 40080 }, + 2, 18, 35, 35, 35, 40080 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */ 92500, 0x8b, 0x00, 11, - 4, 10, 3, 19, 36, 36, 36, 53440 }, + 4, 19, 36, 36, 36, 53440 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */ 130300, 0x8c, 0x00, 12, - 4, 14, 3, 20, 37, 37, 37, 80160 }, + 4, 20, 37, 37, 37, 80160 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */ 162800, 0x8d, 0x00, 13, - 4, 20, 3, 21, 38, 38, 38, 106880 }, + 4, 21, 38, 38, 38, 106880 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */ 178200, 0x8e, 0x00, 14, - 4, 23, 3, 22, 39, 39, 39, 120240 }, + 4, 22, 39, 39, 39, 120240 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */ 192100, 0x8f, 0x00, 15, - 4, 25, 3, 23, 40, 41, 41, 133600 }, + 4, 23, 40, 41, 41, 133600 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ 207000, 0x8f, 0x00, 15, - 4, 25, 3, 23, 40, 41, 41, 148400 }, + 4, 23, 40, 41, 41, 148400 }, }, 50, /* probe interval */ 50, /* rssi reduce interval */ @@ -160,142 +160,142 @@ static const struct ath_rate_table ar5416_11ng_ratetable = { { { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ 900, 0x1b, 0x00, 2, - 0, 0, 1, 0, 0, 0, 0, 0 }, + 0, 0, 0, 0, 0, 0 }, { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ 1900, 0x1a, 0x04, 4, - 1, 1, 1, 1, 1, 1, 1, 0 }, + 1, 1, 1, 1, 1, 0 }, { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ 4900, 0x19, 0x04, 11, - 2, 2, 2, 2, 2, 2, 2, 0 }, + 2, 2, 2, 2, 2, 0 }, { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ 8100, 0x18, 0x04, 22, - 3, 3, 2, 3, 3, 3, 3, 0 }, + 3, 3, 3, 3, 3, 0 }, { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, 12, - 4, 2, 1, 4, 4, 4, 4, 0 }, + 4, 4, 4, 4, 4, 0 }, { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, - 4, 3, 1, 5, 5, 5, 5, 0 }, + 4, 5, 5, 5, 5, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10100, 0x0a, 0x00, 24, - 6, 4, 1, 6, 6, 6, 6, 0 }, + 6, 6, 6, 6, 6, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 14100, 0x0e, 0x00, 36, - 6, 6, 2, 7, 7, 7, 7, 0 }, + 6, 7, 7, 7, 7, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17700, 0x09, 0x00, 48, - 8, 10, 3, 8, 8, 8, 8, 0 }, + 8, 8, 8, 8, 8, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23700, 0x0d, 0x00, 72, - 8, 14, 3, 9, 9, 9, 9, 0 }, + 8, 9, 9, 9, 9, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 0x08, 0x00, 96, - 8, 20, 3, 10, 10, 10, 10, 0 }, + 8, 10, 10, 10, 10, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 30900, 0x0c, 0x00, 108, - 8, 23, 3, 11, 11, 11, 11, 0 }, + 8, 11, 11, 11, 11, 0 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ 6400, 0x80, 0x00, 0, - 4, 2, 3, 12, 28, 12, 28, 3216 }, + 4, 12, 28, 12, 28, 3216 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */ 12700, 0x81, 0x00, 1, - 6, 4, 3, 13, 29, 13, 29, 6434 }, + 6, 13, 29, 13, 29, 6434 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */ 18800, 0x82, 0x00, 2, - 6, 6, 3, 14, 30, 14, 30, 9650 }, + 6, 14, 30, 14, 30, 9650 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */ 25000, 0x83, 0x00, 3, - 8, 10, 3, 15, 31, 15, 31, 12868 }, + 8, 15, 31, 15, 31, 12868 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */ 36700, 0x84, 0x00, 4, - 8, 14, 3, 16, 32, 16, 32, 19304 }, + 8, 16, 32, 16, 32, 19304 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */ 48100, 0x85, 0x00, 5, - 8, 20, 3, 17, 33, 17, 33, 25740 }, + 8, 17, 33, 17, 33, 25740 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */ 53500, 0x86, 0x00, 6, - 8, 23, 3, 18, 34, 18, 34, 28956 }, + 8, 18, 34, 18, 34, 28956 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */ 59000, 0x87, 0x00, 7, - 8, 25, 3, 19, 35, 19, 36, 32180 }, + 8, 19, 35, 19, 36, 32180 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */ 12700, 0x88, 0x00, 8, - 4, 2, 3, 20, 37, 20, 37, 6430 }, + 4, 20, 37, 20, 37, 6430 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */ 24800, 0x89, 0x00, 9, - 6, 4, 3, 21, 38, 21, 38, 12860 }, + 6, 21, 38, 21, 38, 12860 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */ 36600, 0x8a, 0x00, 10, - 6, 6, 3, 22, 39, 22, 39, 19300 }, + 6, 22, 39, 22, 39, 19300 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */ 48100, 0x8b, 0x00, 11, - 8, 10, 3, 23, 40, 23, 40, 25736 }, + 8, 23, 40, 23, 40, 25736 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */ 69500, 0x8c, 0x00, 12, - 8, 14, 3, 24, 41, 24, 41, 38600 }, + 8, 24, 41, 24, 41, 38600 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */ 89500, 0x8d, 0x00, 13, - 8, 20, 3, 25, 42, 25, 42, 51472 }, + 8, 25, 42, 25, 42, 51472 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */ 98900, 0x8e, 0x00, 14, - 8, 23, 3, 26, 43, 26, 44, 57890 }, + 8, 26, 43, 26, 44, 57890 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */ 108300, 0x8f, 0x00, 15, - 8, 25, 3, 27, 44, 27, 45, 64320 }, + 8, 27, 44, 27, 45, 64320 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */ 13200, 0x80, 0x00, 0, - 8, 2, 3, 12, 28, 28, 28, 6684 }, + 8, 12, 28, 28, 28, 6684 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */ 25900, 0x81, 0x00, 1, - 8, 4, 3, 13, 29, 29, 29, 13368 }, + 8, 13, 29, 29, 29, 13368 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */ 38600, 0x82, 0x00, 2, - 8, 6, 3, 14, 30, 30, 30, 20052 }, + 8, 14, 30, 30, 30, 20052 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */ 49800, 0x83, 0x00, 3, - 8, 10, 3, 15, 31, 31, 31, 26738 }, + 8, 15, 31, 31, 31, 26738 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */ 72200, 0x84, 0x00, 4, - 8, 14, 3, 16, 32, 32, 32, 40104 }, + 8, 16, 32, 32, 32, 40104 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */ 92900, 0x85, 0x00, 5, - 8, 20, 3, 17, 33, 33, 33, 53476 }, + 8, 17, 33, 33, 33, 53476 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */ 102700, 0x86, 0x00, 6, - 8, 23, 3, 18, 34, 34, 34, 60156 }, + 8, 18, 34, 34, 34, 60156 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */ 112000, 0x87, 0x00, 7, - 8, 23, 3, 19, 35, 36, 36, 66840 }, + 8, 19, 35, 36, 36, 66840 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ 122000, 0x87, 0x00, 7, - 8, 25, 3, 19, 35, 36, 36, 74200 }, + 8, 19, 35, 36, 36, 74200 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */ 25800, 0x88, 0x00, 8, - 8, 2, 3, 20, 37, 37, 37, 13360 }, + 8, 20, 37, 37, 37, 13360 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */ 49800, 0x89, 0x00, 9, - 8, 4, 3, 21, 38, 38, 38, 26720 }, + 8, 21, 38, 38, 38, 26720 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */ 71900, 0x8a, 0x00, 10, - 8, 6, 3, 22, 39, 39, 39, 40080 }, + 8, 22, 39, 39, 39, 40080 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */ 92500, 0x8b, 0x00, 11, - 8, 10, 3, 23, 40, 40, 40, 53440 }, + 8, 23, 40, 40, 40, 53440 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */ 130300, 0x8c, 0x00, 12, - 8, 14, 3, 24, 41, 41, 41, 80160 }, + 8, 24, 41, 41, 41, 80160 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */ 162800, 0x8d, 0x00, 13, - 8, 20, 3, 25, 42, 42, 42, 106880 }, + 8, 25, 42, 42, 42, 106880 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */ 178200, 0x8e, 0x00, 14, - 8, 23, 3, 26, 43, 43, 43, 120240 }, + 8, 26, 43, 43, 43, 120240 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */ 192100, 0x8f, 0x00, 15, - 8, 23, 3, 27, 44, 45, 45, 133600 }, + 8, 27, 44, 45, 45, 133600 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ 207000, 0x8f, 0x00, 15, - 8, 25, 3, 27, 44, 45, 45, 148400 }, + 8, 27, 44, 45, 45, 148400 }, }, 50, /* probe interval */ 50, /* rssi reduce interval */ @@ -307,28 +307,28 @@ static const struct ath_rate_table ar5416_11a_ratetable = { { { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, (0x80|12), - 0, 2, 1, 0, 0 }, + 0, 0, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, - 0, 3, 1, 1, 0 }, + 0, 1, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10000, 0x0a, 0x00, (0x80|24), - 2, 4, 2, 2, 0 }, + 2, 2, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 13900, 0x0e, 0x00, 36, - 2, 6, 2, 3, 0 }, + 2, 3, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17300, 0x09, 0x00, (0x80|48), - 4, 10, 3, 4, 0 }, + 4, 4, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23000, 0x0d, 0x00, 72, - 4, 14, 3, 5, 0 }, + 4, 5, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 0x08, 0x00, 96, - 4, 19, 3, 6, 0 }, + 4, 6, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 29300, 0x0c, 0x00, 108, - 4, 23, 3, 7, 0 }, + 4, 7, 0 }, }, 50, /* probe interval */ 50, /* rssi reduce interval */ @@ -340,40 +340,40 @@ static const struct ath_rate_table ar5416_11g_ratetable = { { { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ 900, 0x1b, 0x00, 2, - 0, 0, 1, 0, 0 }, + 0, 0, 0 }, { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ 1900, 0x1a, 0x04, 4, - 1, 1, 1, 1, 0 }, + 1, 1, 0 }, { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ 4900, 0x19, 0x04, 11, - 2, 2, 2, 2, 0 }, + 2, 2, 0 }, { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ 8100, 0x18, 0x04, 22, - 3, 3, 2, 3, 0 }, + 3, 3, 0 }, { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, 12, - 4, 2, 1, 4, 0 }, + 4, 4, 0 }, { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, - 4, 3, 1, 5, 0 }, + 4, 5, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10000, 0x0a, 0x00, 24, - 6, 4, 1, 6, 0 }, + 6, 6, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 13900, 0x0e, 0x00, 36, - 6, 6, 2, 7, 0 }, + 6, 7, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17300, 0x09, 0x00, 48, - 8, 10, 3, 8, 0 }, + 8, 8, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23000, 0x0d, 0x00, 72, - 8, 14, 3, 9, 0 }, + 8, 9, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 0x08, 0x00, 96, - 8, 19, 3, 10, 0 }, + 8, 10, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 29300, 0x0c, 0x00, 108, - 8, 23, 3, 11, 0 }, + 8, 11, 0 }, }, 50, /* probe interval */ 50, /* rssi reduce interval */ diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index e3abd76103f..6797df0b196 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -112,8 +112,6 @@ struct ath_rate_table { u8 short_preamble; u8 dot11rate; u8 ctrl_rate; - int8_t rssi_ack_validmin; - int8_t rssi_ack_deltamin; u8 base_index; u8 cw40index; u8 sgi_index; @@ -126,7 +124,6 @@ struct ath_rate_table { }; struct ath_tx_ratectrl_state { - int8_t rssi_thres; /* required rssi for this rate (dB) */ u8 per; /* recent estimate of packet error rate (%) */ }; @@ -138,16 +135,7 @@ struct ath_rateset { /** * struct ath_rate_priv - Rate Control priv data * @state: RC state - * @rssi_last: last ACK rssi - * @rssi_last_lookup: last ACK rssi used for lookup - * @rssi_last_prev: previous last ACK rssi - * @rssi_last_prev2: 2nd previous last ACK rssi - * @rssi_sum_cnt: count of rssi_sum for averaging - * @rssi_sum_rate: rate that we are averaging - * @rssi_sum: running sum of rssi for averaging * @probe_rate: rate we are probing at - * @rssi_time: msec timestamp for last ack rssi - * @rssi_down_time: msec timestamp for last down step * @probe_time: msec timestamp for last probe * @hw_maxretry_pktcnt: num of packets since we got HW max retry error * @max_valid_rate: maximum number of valid rate @@ -161,13 +149,6 @@ struct ath_rateset { * @neg_ht_rates: Negotiated HT rates */ struct ath_rate_priv { - int8_t rssi_last; - int8_t rssi_last_lookup; - int8_t rssi_last_prev; - int8_t rssi_last_prev2; - int32_t rssi_sum_cnt; - int32_t rssi_sum_rate; - int32_t rssi_sum; u8 rate_table_size; u8 probe_rate; u8 hw_maxretry_pktcnt; @@ -177,8 +158,6 @@ struct ath_rate_priv { u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE]; u8 rate_max_phy; - u32 rssi_time; - u32 rssi_down_time; u32 probe_time; u32 per_down_time; u32 probe_interval; -- cgit v1.2.3-18-g5258 From c41304653e120749dae8b04332b92ffb5f4dbbfd Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 14 Jul 2009 20:14:12 -0400 Subject: ath9k: Use probe interval instead of rssi reduce interval Get rid of rssi reduce interval. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 6 +----- drivers/net/wireless/ath/ath9k/rc.h | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 731967c74a1..a97dd7b6b70 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -148,7 +148,6 @@ static const struct ath_rate_table ar5416_11na_ratetable = { 4, 23, 40, 41, 41, 148400 }, }, 50, /* probe interval */ - 50, /* rssi reduce interval */ WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ }; @@ -298,7 +297,6 @@ static const struct ath_rate_table ar5416_11ng_ratetable = { 8, 27, 44, 45, 45, 148400 }, }, 50, /* probe interval */ - 50, /* rssi reduce interval */ WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ }; @@ -331,7 +329,6 @@ static const struct ath_rate_table ar5416_11a_ratetable = { 4, 7, 0 }, }, 50, /* probe interval */ - 50, /* rssi reduce interval */ 0, /* Phy rates allowed initially */ }; @@ -376,7 +373,6 @@ static const struct ath_rate_table ar5416_11g_ratetable = { 8, 11, 0 }, }, 50, /* probe interval */ - 50, /* rssi reduce interval */ 0, /* Phy rates allowed initially */ }; @@ -1070,7 +1066,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, /* Every so often, we reduce the thresholds * and PER (different for CCK and OFDM). */ if (now_msec - ath_rc_priv->per_down_time >= - rate_table->rssi_reduce_interval) { + rate_table->probe_interval) { for (rate = 0; rate < size; rate++) { ath_rc_priv->state[rate].per = 7 * ath_rc_priv->state[rate].per / 8; diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index 6797df0b196..c794d6c82ad 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -119,7 +119,6 @@ struct ath_rate_table { u32 max_4ms_framelen; } info[RATE_TABLE_SIZE]; u32 probe_interval; - u32 rssi_reduce_interval; u8 initial_ratemax; }; -- cgit v1.2.3-18-g5258 From 922bac602255d4557c289cabba7857c5be332d34 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 14 Jul 2009 20:14:13 -0400 Subject: ath9k: Nuke struct ath_tx_ratectrl_state Move its only member (u8 per) to struct ath_rate_priv. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 50 ++++++++++++++++++------------------- drivers/net/wireless/ath/ath9k/rc.h | 7 ++---- 2 files changed, 27 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index a97dd7b6b70..a07efa22551 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -636,7 +636,7 @@ static u8 ath_rc_get_highest_rix(struct ath_softc *sc, * 10-15 and we would be worse off then staying * at the current rate. */ - per_thres = ath_rc_priv->state[rate].per; + per_thres = ath_rc_priv->per[rate]; if (per_thres < 12) per_thres = 12; @@ -881,13 +881,13 @@ static bool ath_rc_update_per(struct ath_softc *sc, 100 * 9 / 10 }; - last_per = ath_rc_priv->state[tx_rate].per; + last_per = ath_rc_priv->per[tx_rate]; if (xretries) { if (xretries == 1) { - ath_rc_priv->state[tx_rate].per += 30; - if (ath_rc_priv->state[tx_rate].per > 100) - ath_rc_priv->state[tx_rate].per = 100; + ath_rc_priv->per[tx_rate] += 30; + if (ath_rc_priv->per[tx_rate] > 100) + ath_rc_priv->per[tx_rate] = 100; } else { /* xretries == 2 */ count = ARRAY_SIZE(nretry_to_per_lookup); @@ -895,7 +895,7 @@ static bool ath_rc_update_per(struct ath_softc *sc, retries = count - 1; /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ - ath_rc_priv->state[tx_rate].per = + ath_rc_priv->per[tx_rate] = (u8)(last_per - (last_per >> 3) + (100 >> 3)); } @@ -931,10 +931,10 @@ static bool ath_rc_update_per(struct ath_softc *sc, n_frames = tx_info_priv->n_frames * (retries + 1); cur_per = (100 * n_bad_frames / n_frames) >> 3; new_per = (u8)(last_per - (last_per >> 3) + cur_per); - ath_rc_priv->state[tx_rate].per = new_per; + ath_rc_priv->per[tx_rate] = new_per; } } else { - ath_rc_priv->state[tx_rate].per = + ath_rc_priv->per[tx_rate] = (u8)(last_per - (last_per >> 3) + (nretry_to_per_lookup[retries] >> 3)); } @@ -962,8 +962,8 @@ static bool ath_rc_update_per(struct ath_softc *sc, ath_rc_priv->probe_rate; probe_rate = ath_rc_priv->probe_rate; - if (ath_rc_priv->state[probe_rate].per > 30) - ath_rc_priv->state[probe_rate].per = 20; + if (ath_rc_priv->per[probe_rate] > 30) + ath_rc_priv->per[probe_rate] = 20; ath_rc_priv->probe_rate = 0; @@ -1018,7 +1018,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt)) return; - last_per = ath_rc_priv->state[tx_rate].per; + last_per = ath_rc_priv->per[tx_rate]; /* Update PER first */ state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv, @@ -1029,7 +1029,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, * If this rate looks bad (high PER) then stop using it for * a while (except if we are probing). */ - if (ath_rc_priv->state[tx_rate].per >= 55 && tx_rate > 0 && + if (ath_rc_priv->per[tx_rate] >= 55 && tx_rate > 0 && rate_table->info[tx_rate].ratekbps <= rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) { ath_rc_get_lower_rix(rate_table, ath_rc_priv, @@ -1041,26 +1041,26 @@ static void ath_rc_update_ht(struct ath_softc *sc, /* Make sure the rates below this have lower PER */ /* Monotonicity is kept only for rates below the current rate. */ - if (ath_rc_priv->state[tx_rate].per < last_per) { + if (ath_rc_priv->per[tx_rate] < last_per) { for (rate = tx_rate - 1; rate >= 0; rate--) { if (rate_table->info[rate].phy != rate_table->info[tx_rate].phy) break; - if (ath_rc_priv->state[rate].per > - ath_rc_priv->state[rate+1].per) { - ath_rc_priv->state[rate].per = - ath_rc_priv->state[rate+1].per; + if (ath_rc_priv->per[rate] > + ath_rc_priv->per[rate+1]) { + ath_rc_priv->per[rate] = + ath_rc_priv->per[rate+1]; } } } /* Maintain monotonicity for rates above the current rate */ for (rate = tx_rate; rate < size - 1; rate++) { - if (ath_rc_priv->state[rate+1].per < - ath_rc_priv->state[rate].per) - ath_rc_priv->state[rate+1].per = - ath_rc_priv->state[rate].per; + if (ath_rc_priv->per[rate+1] < + ath_rc_priv->per[rate]) + ath_rc_priv->per[rate+1] = + ath_rc_priv->per[rate]; } /* Every so often, we reduce the thresholds @@ -1068,15 +1068,15 @@ static void ath_rc_update_ht(struct ath_softc *sc, if (now_msec - ath_rc_priv->per_down_time >= rate_table->probe_interval) { for (rate = 0; rate < size; rate++) { - ath_rc_priv->state[rate].per = - 7 * ath_rc_priv->state[rate].per / 8; + ath_rc_priv->per[rate] = + 7 * ath_rc_priv->per[rate] / 8; } ath_rc_priv->per_down_time = now_msec; } ath_debug_stat_retries(sc, tx_rate, xretries, retries, - ath_rc_priv->state[tx_rate].per); + ath_rc_priv->per[tx_rate]); } @@ -1213,7 +1213,7 @@ static void ath_rc_init(struct ath_softc *sc, /* Initialize thresholds according to the global rate table */ for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) { - ath_rc_priv->state[i].per = 0; + ath_rc_priv->per[i] = 0; } /* Determine the valid rates */ diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index c794d6c82ad..fa21a628ddd 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -122,10 +122,6 @@ struct ath_rate_table { u8 initial_ratemax; }; -struct ath_tx_ratectrl_state { - u8 per; /* recent estimate of packet error rate (%) */ -}; - struct ath_rateset { u8 rs_nrates; u8 rs_rates[ATH_RATE_MAX]; @@ -141,6 +137,7 @@ struct ath_rateset { * @per_down_time: msec timestamp for last PER down step * @valid_phy_ratecnt: valid rate count * @rate_max_phy: phy index for the max rate + * @per: PER for every valid rate in % * @probe_interval: interval for ratectrl to probe for other rates * @prev_data_rix: rate idx of last data frame * @ht_cap: HT capabilities @@ -157,12 +154,12 @@ struct ath_rate_priv { u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE]; u8 rate_max_phy; + u8 per[RATE_TABLE_SIZE]; u32 probe_time; u32 per_down_time; u32 probe_interval; u32 prev_data_rix; u32 tx_triglevel_max; - struct ath_tx_ratectrl_state state[RATE_TABLE_SIZE]; struct ath_rateset neg_rates; struct ath_rateset neg_ht_rates; struct ath_rate_softc *asc; -- cgit v1.2.3-18-g5258 From a59b5a5e684652eec035c869ab8911a1689c8f53 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Tue, 14 Jul 2009 20:17:07 -0400 Subject: ath9k: Manipulate and report the correct RSSI RSSI reported by the RX descriptor requires little manipulation. Manipulate and report the correct RSSI to the stack. This will fix the improper signal levels reported by iwconfig iw dev wlanX station dump. Also the Link Quality reported seems to be varying (falls to zero also sometimes) when iperf is run from STA to AP. Also use the default noise floor for now as the one reported during the caliberation seems to be wrong. The Signal and Link Quality before this patch (taken while TX is in progress from STA to AP) 09:59:13.285428037 Link Quality=29/70 Signal level=-81 dBm 09:59:13.410660084 Link Quality=20/70 Signal level=-90 dBm 09:59:13.586864392 Link Quality=21/70 Signal level=-89 dBm 09:59:13.710296281 Link Quality=21/70 Signal level=-89 dBm 09:59:13.821683064 Link Quality=25/70 Signal level=-85 dBm 09:59:13.933402989 Link Quality=24/70 Signal level=-86 dBm 09:59:14.045839276 Link Quality=26/70 Signal level=-84 dBm 09:59:14.193926673 Link Quality=23/70 Signal level=-87 dBm 09:59:14.306230262 Link Quality=31/70 Signal level=-79 dBm 09:59:14.419459667 Link Quality=26/70 Signal level=-84 dBm 09:59:14.530711167 Link Quality=37/70 Signal level=-73 dBm 09:59:14.642593962 Link Quality=29/70 Signal level=-81 dBm 09:59:14.754361169 Link Quality=21/70 Signal level=-89 dBm 09:59:14.866217355 Link Quality=21/70 Signal level=-89 dBm 09:59:14.976963623 Link Quality=28/70 Signal level=-82 dBm 09:59:15.089149809 Link Quality=26/70 Signal level=-84 dBm 09:59:15.205039887 Link Quality=27/70 Signal level=-83 dBm 09:59:15.316368003 Link Quality=23/70 Signal level=-87 dBm 09:59:15.427684036 Link Quality=36/70 Signal level=-74 dBm 09:59:15.539756380 Link Quality=21/70 Signal level=-89 dBm 09:59:15.650549093 Link Quality=22/70 Signal level=-88 dBm 09:59:15.761171672 Link Quality=32/70 Signal level=-78 dBm 09:59:15.872793750 Link Quality=23/70 Signal level=-87 dBm 09:59:15.984421694 Link Quality=22/70 Signal level=-88 dBm 09:59:16.097315093 Link Quality=21/70 Signal level=-89 dBm The link quality and signal level after this patch (take while TX is in progress from STA to AP) 17:21:25.627848091 Link Quality=65/70 Signal level=-45 dBm 17:21:25.762805607 Link Quality=65/70 Signal level=-45 dBm 17:21:25.875521888 Link Quality=66/70 Signal level=-44 dBm 17:21:25.987468448 Link Quality=66/70 Signal level=-44 dBm 17:21:26.100628151 Link Quality=66/70 Signal level=-44 dBm 17:21:26.213129671 Link Quality=66/70 Signal level=-44 dBm 17:21:26.324923070 Link Quality=65/70 Signal level=-45 dBm 17:21:26.436831357 Link Quality=65/70 Signal level=-45 dBm 17:21:26.610356973 Link Quality=65/70 Signal level=-45 dBm 17:21:26.723340047 Link Quality=65/70 Signal level=-45 dBm 17:21:26.835715293 Link Quality=64/70 Signal level=-46 dBm 17:21:26.949542748 Link Quality=64/70 Signal level=-46 dBm 17:21:27.062261613 Link Quality=65/70 Signal level=-45 dBm 17:21:27.174511563 Link Quality=64/70 Signal level=-46 dBm 17:21:27.287616232 Link Quality=64/70 Signal level=-46 dBm 17:21:27.400598119 Link Quality=64/70 Signal level=-46 dBm 17:21:27.511381404 Link Quality=64/70 Signal level=-46 dBm 17:21:27.624530421 Link Quality=65/70 Signal level=-45 dBm 17:21:27.737807109 Link Quality=64/70 Signal level=-46 dBm 17:21:27.850861352 Link Quality=65/70 Signal level=-45 dBm 17:21:27.963369436 Link Quality=64/70 Signal level=-46 dBm 17:21:28.076582289 Link Quality=64/70 Signal level=-46 dBm Signed-off-by: Senthil Balasubramanian Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 16 ++++++++++++++++ drivers/net/wireless/ath/ath9k/calib.c | 13 ++++++++++--- drivers/net/wireless/ath/ath9k/calib.h | 4 +++- drivers/net/wireless/ath/ath9k/main.c | 1 + drivers/net/wireless/ath/ath9k/recv.c | 25 ++++++++++++++++++++++++- 5 files changed, 54 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 3afd7ee41a6..544599b826c 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -290,12 +290,28 @@ struct ath_tx_control { #define ATH_TX_XRETRY 0x02 #define ATH_TX_BAR 0x04 +#define ATH_RSSI_LPF_LEN 10 +#define RSSI_LPF_THRESHOLD -20 +#define ATH9K_RSSI_BAD 0x80 +#define ATH_RSSI_EP_MULTIPLIER (1<<7) +#define ATH_EP_MUL(x, mul) ((x) * (mul)) +#define ATH_RSSI_IN(x) (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER)) +#define ATH_LPF_RSSI(x, y, len) \ + ((x != ATH_RSSI_DUMMY_MARKER) ? (((x) * ((len) - 1) + (y)) / (len)) : (y)) +#define ATH_RSSI_LPF(x, y) do { \ + if ((y) >= RSSI_LPF_THRESHOLD) \ + x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \ +} while (0) +#define ATH_EP_RND(x, mul) \ + ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) + struct ath_node { struct ath_softc *an_sc; struct ath_atx_tid tid[WME_NUM_TID]; struct ath_atx_ac ac[WME_NUM_AC]; u16 maxampdu; u8 mpdudensity; + int last_rssi; }; struct ath_tx { diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index a32d7e7fecb..1f0c5fe4a68 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -691,15 +691,22 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah, void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah) { int i, j; + s16 noise_floor; + + if (AR_SREV_9280(ah)) + noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE; + else if (AR_SREV_9285(ah)) + noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE; + else + noise_floor = AR_PHY_CCA_MAX_AR5416_GOOD_VALUE; for (i = 0; i < NUM_NF_READINGS; i++) { ah->nfCalHist[i].currIndex = 0; - ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE; + ah->nfCalHist[i].privNF = noise_floor; ah->nfCalHist[i].invalidNFcount = AR_PHY_CCA_FILTERWINDOW_LENGTH; for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { - ah->nfCalHist[i].nfCalBuffer[j] = - AR_PHY_CCA_MAX_GOOD_VALUE; + ah->nfCalHist[i].nfCalBuffer[j] = noise_floor; } } } diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index fe5367f1414..547e697b905 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -25,7 +25,9 @@ extern const struct ath9k_percal_data adc_dc_cal_multi_sample; extern const struct ath9k_percal_data adc_dc_cal_single_sample; extern const struct ath9k_percal_data adc_init_dc_cal; -#define AR_PHY_CCA_MAX_GOOD_VALUE -85 +#define AR_PHY_CCA_MAX_AR5416_GOOD_VALUE -85 +#define AR_PHY_CCA_MAX_AR9280_GOOD_VALUE -112 +#define AR_PHY_CCA_MAX_AR9285_GOOD_VALUE -118 #define AR_PHY_CCA_MAX_HIGH_VALUE -62 #define AR_PHY_CCA_MIN_BAD_VALUE -140 #define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3 diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 19df7882d0d..2ad718489c0 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -465,6 +465,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + sta->ht_cap.ampdu_factor); an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); + an->last_rssi = ATH_RSSI_DUMMY_MARKER; } } diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index b3da81db453..61edfab20ff 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -145,6 +145,10 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, u8 ratecode; __le16 fc; struct ieee80211_hw *hw; + struct ieee80211_sta *sta; + struct ath_node *an; + int last_rssi = ATH_RSSI_DUMMY_MARKER; + hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; @@ -229,11 +233,30 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, } } + rcu_read_lock(); + sta = ieee80211_find_sta(sc->hw, hdr->addr2); + if (sta) { + an = (struct ath_node *) sta->drv_priv; + if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD && + !ds->ds_rxstat.rs_moreaggr) + ATH_RSSI_LPF(an->last_rssi, ds->ds_rxstat.rs_rssi); + last_rssi = an->last_rssi; + } + rcu_read_unlock(); + + if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) + ds->ds_rxstat.rs_rssi = ATH_EP_RND(last_rssi, + ATH_RSSI_EP_MULTIPLIER); + if (ds->ds_rxstat.rs_rssi < 0) + ds->ds_rxstat.rs_rssi = 0; + else if (ds->ds_rxstat.rs_rssi > 127) + ds->ds_rxstat.rs_rssi = 127; + rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); rx_status->band = hw->conf.channel->band; rx_status->freq = hw->conf.channel->center_freq; rx_status->noise = sc->ani.noise_floor; - rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi; + rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + ds->ds_rxstat.rs_rssi; rx_status->antenna = ds->ds_rxstat.rs_antenna; /* -- cgit v1.2.3-18-g5258 From dd8b15b027d96f7097ae9dbaebd822a114a03c34 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Tue, 14 Jul 2009 20:17:08 -0400 Subject: ath9k: RX stucks during heavy traffic in HT40 mode. Running iperf along with p2p traffic on both TX and RX side then stop one side, then stop the other side, then start it up again, eventually the STA gets into a mode that it can not pass data at all. A hardware workaround for invalid RSSI can make FIFO write pointer to jump over read pointer, causing RX data corruption and repeated DMA. Both TX and RX works fine when the workaround is disabled. To replace the original hardware work around, software looks for frames with post delimiter CRC error and mark the RSSI invalid so that the upperlayer will not use the RSSI associated with this frame. So disable the hardware workaround by updating the appropriate registers. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom.c | 20 ++++++++++++- drivers/net/wireless/ath/ath9k/initvals.h | 47 ++++++++++++++++--------------- drivers/net/wireless/ath/ath9k/mac.c | 30 +++++++++++++++----- 3 files changed, 67 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index d82a0f97e6f..df41ed5fd7c 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -1208,6 +1208,19 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah, pModal->xatten2Margin[0]); REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); + + /* Set the block 1 value to block 0 value */ + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, + pModal->bswMargin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, + AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, + pModal->xatten2Margin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, + AR_PHY_GAIN_2GHZ_XATTEN2_DB, + pModal->xatten2Db[0]); } REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, @@ -1215,6 +1228,11 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah, REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, + AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, + AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); + if (AR_SREV_9285_11(ah)) REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); } @@ -1239,7 +1257,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0); /* Initialize Ant Diversity settings from EEPROM */ - if (pModal->version == 3) { + if (pModal->version >= 3) { ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf); ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf); regVal = REG_READ(ah, 0x99ac); diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h index e2f0a34b79a..f67a2a96cc5 100644 --- a/drivers/net/wireless/ath/ath9k/initvals.h +++ b/drivers/net/wireless/ath/ath9k/initvals.h @@ -2782,7 +2782,7 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00008338, 0x00ff0000 }, { 0x0000833c, 0x00000000 }, { 0x00008340, 0x000107ff }, - { 0x00008344, 0x00581043 }, + { 0x00008344, 0x00481043 }, { 0x00009808, 0x00000000 }, { 0x0000980c, 0xafa68e30 }, { 0x00009810, 0xfd14e000 }, @@ -3439,7 +3439,7 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = { {0x00004044, 0x00000000 }, }; -/* AR9285 */ +/* AR9285 Revsion 10*/ static const u_int32_t ar9285Modes_9285[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -3955,7 +3955,7 @@ static const u_int32_t ar9285Common_9285[][2] = { { 0x00008338, 0x00000000 }, { 0x0000833c, 0x00000000 }, { 0x00008340, 0x00010380 }, - { 0x00008344, 0x00581043 }, + { 0x00008344, 0x00481043 }, { 0x00009808, 0x00000000 }, { 0x0000980c, 0xafe68e30 }, { 0x00009810, 0xfd14e000 }, @@ -4121,8 +4121,9 @@ static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = { {0x00004044, 0x00000000 }, }; -/* AR9285 v1_2 PCI Register Writes. Created: 03/04/09 */ +/* AR9285 v1_2 PCI Register Writes. Created: 04/13/09 */ static const u_int32_t ar9285Modes_9285_1_2[][6] = { + /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, @@ -4139,6 +4140,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = { { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e }, { 0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0 }, { 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 }, + { 0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 }, { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, { 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e }, @@ -4419,6 +4421,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = { { 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 }, { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 }, + { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 }, { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 }, @@ -4618,7 +4621,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { { 0x00008338, 0x00ff0000 }, { 0x0000833c, 0x00000000 }, { 0x00008340, 0x00010380 }, - { 0x00008344, 0x00581043 }, + { 0x00008344, 0x00481043 }, { 0x00009808, 0x00000000 }, { 0x0000980c, 0xafe68e30 }, { 0x00009810, 0xfd14e000 }, @@ -4752,18 +4755,18 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = { /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a304, 0x00000000, 0x00000000, 0x00005200, 0x00005200, 0x00000000 }, - { 0x0000a308, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000 }, { 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 }, { 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 }, - { 0x0000a314, 0x00000000, 0x00000000, 0x0000f440, 0x0000f440, 0x00000000 }, - { 0x0000a318, 0x00000000, 0x00000000, 0x00014640, 0x00014640, 0x00000000 }, - { 0x0000a31c, 0x00000000, 0x00000000, 0x00018680, 0x00018680, 0x00000000 }, - { 0x0000a320, 0x00000000, 0x00000000, 0x00019841, 0x00019841, 0x00000000 }, - { 0x0000a324, 0x00000000, 0x00000000, 0x0001ca40, 0x0001ca40, 0x00000000 }, - { 0x0000a328, 0x00000000, 0x00000000, 0x0001fa80, 0x0001fa80, 0x00000000 }, - { 0x0000a32c, 0x00000000, 0x00000000, 0x00023ac0, 0x00023ac0, 0x00000000 }, - { 0x0000a330, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000 }, { 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 }, { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, @@ -4776,13 +4779,13 @@ static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = { { 0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803 }, { 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe }, { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 }, - { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a21a652, 0x0a21a652, 0x0a22a652 }, - { 0x0000a278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce }, - { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce }, - { 0x0000a394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce }, - { 0x0000a398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce }, - { 0x0000a3dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce }, - { 0x0000a3e0, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce }, + { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652 }, + { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 }, + { 0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7 }, + { 0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 }, + { 0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 }, + { 0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 }, + { 0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 }, }; static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = { diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 8ae4ec21667..6f923e31872 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -825,13 +825,29 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen; ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp; - ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined); - ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00); - ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01); - ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02); - ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10); - ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11); - ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12); + if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) { + ds->ds_rxstat.rs_rssi = ATH9K_RSSI_BAD; + ds->ds_rxstat.rs_rssi_ctl0 = ATH9K_RSSI_BAD; + ds->ds_rxstat.rs_rssi_ctl1 = ATH9K_RSSI_BAD; + ds->ds_rxstat.rs_rssi_ctl2 = ATH9K_RSSI_BAD; + ds->ds_rxstat.rs_rssi_ext0 = ATH9K_RSSI_BAD; + ds->ds_rxstat.rs_rssi_ext1 = ATH9K_RSSI_BAD; + ds->ds_rxstat.rs_rssi_ext2 = ATH9K_RSSI_BAD; + } else { + ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined); + ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, + AR_RxRSSIAnt00); + ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, + AR_RxRSSIAnt01); + ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, + AR_RxRSSIAnt02); + ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, + AR_RxRSSIAnt10); + ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, + AR_RxRSSIAnt11); + ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, + AR_RxRSSIAnt12); + } if (ads.ds_rxstatus8 & AR_RxKeyIdxValid) ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx); else -- cgit v1.2.3-18-g5258 From 164ace38536849966ffa377b1b1132993a5a375d Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Tue, 14 Jul 2009 20:17:09 -0400 Subject: ath9k: Fix TX hang issue with Atheros chipsets The hardware doesn't generate interrupts in some cases and so work around this by monitoring the TX status periodically and reset the chip if required. This behavior of the hardware not generating the TX interrupts can be noticed through ath9k debugfs interrupt statistics when heavy traffic is being sent from STA to AP. One can easily see this behavior when the STA is transmitting at a higher rates. The interrupt statistics in the debugfs interface clearly shows that only RX interrupts alone being generated and TX being stuck. TX should be monitored through a timer and reset the chip only when frames are queued to the hardware but TX interrupts are not generated for the same even after one second. Also, we shouldn't remove holding descriptor from AC queue if it happens to be the only descriptor and schedule TX aggregation regarless of queue depth as it improves scheduling of AMPDUs from software to hardware queue. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 4 +++ drivers/net/wireless/ath/ath9k/main.c | 3 ++ drivers/net/wireless/ath/ath9k/xmit.c | 57 +++++++++++++++++++++++++--------- 3 files changed, 50 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 544599b826c..20bf4a7f896 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -225,6 +225,8 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, #define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA) #define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)]) +#define ATH_TX_COMPLETE_POLL_INT 1000 + enum ATH_AGGR_STATUS { ATH_AGGR_DONE, ATH_AGGR_BAW_CLOSED, @@ -240,6 +242,7 @@ struct ath_txq { u8 axq_aggr_depth; u32 axq_totalqueued; bool stopped; + bool axq_tx_inprogress; struct ath_buf *axq_linkbuf; /* first desc of the last descriptor that contains CTS */ @@ -605,6 +608,7 @@ struct ath_softc { #endif struct ath_bus_ops *bus_ops; struct ath_beacon_config cur_beacon_conf; + struct delayed_work tx_complete_work; }; struct ath_wiphy { diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 2ad718489c0..46f4a692c8d 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1259,6 +1259,7 @@ void ath_detach(struct ath_softc *sc) ath_deinit_leds(sc); cancel_work_sync(&sc->chan_work); cancel_delayed_work_sync(&sc->wiphy_work); + cancel_delayed_work_sync(&sc->tx_complete_work); for (i = 0; i < sc->num_sec_wiphy; i++) { struct ath_wiphy *aphy = sc->sec_wiphy[i]; @@ -1979,6 +1980,8 @@ static int ath9k_start(struct ieee80211_hw *hw) ieee80211_wake_queues(hw); + queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work, 0); + mutex_unlock: mutex_unlock(&sc->mutex); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 5de9878d2c1..a3bc4310a67 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -857,6 +857,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) txq->axq_aggr_depth = 0; txq->axq_totalqueued = 0; txq->axq_linkbuf = NULL; + txq->axq_tx_inprogress = false; sc->tx.txqsetup |= 1<tx.txq[qnum]; @@ -1023,6 +1024,10 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); } + spin_lock_bh(&txq->axq_lock); + txq->axq_tx_inprogress = false; + spin_unlock_bh(&txq->axq_lock); + /* flush any pending frames if aggregation is enabled */ if (sc->sc_flags & SC_OP_TXAGGR) { if (!retry_tx) { @@ -1103,8 +1108,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) if (tid->paused) continue; - if ((txq->axq_depth % 2) == 0) - ath_tx_sched_aggr(sc, txq, tid); + ath_tx_sched_aggr(sc, txq, tid); /* * add tid to round-robin queue if more frames @@ -1947,19 +1951,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) if (bf->bf_stale) { bf_held = bf; if (list_is_last(&bf_held->list, &txq->axq_q)) { - txq->axq_link = NULL; - txq->axq_linkbuf = NULL; spin_unlock_bh(&txq->axq_lock); - - /* - * The holding descriptor is the last - * descriptor in queue. It's safe to remove - * the last holding descriptor in BH context. - */ - spin_lock_bh(&sc->tx.txbuflock); - list_move_tail(&bf_held->list, &sc->tx.txbuf); - spin_unlock_bh(&sc->tx.txbuflock); - break; } else { bf = list_entry(bf_held->list.next, @@ -1996,6 +1988,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) txq->axq_aggr_depth--; txok = (ds->ds_txstat.ts_status == 0); + txq->axq_tx_inprogress = false; spin_unlock_bh(&txq->axq_lock); if (bf_held) { @@ -2029,6 +2022,40 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) } } +void ath_tx_complete_poll_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + tx_complete_work.work); + struct ath_txq *txq; + int i; + bool needreset = false; + + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) { + txq = &sc->tx.txq[i]; + spin_lock_bh(&txq->axq_lock); + if (txq->axq_depth) { + if (txq->axq_tx_inprogress) { + needreset = true; + spin_unlock_bh(&txq->axq_lock); + break; + } else { + txq->axq_tx_inprogress = true; + } + } + spin_unlock_bh(&txq->axq_lock); + } + + if (needreset) { + DPRINTF(sc, ATH_DBG_RESET, "tx hung, resetting the chip\n"); + ath_reset(sc, false); + } + + queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work, + msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT)); +} + + void ath_tx_tasklet(struct ath_softc *sc) { @@ -2069,6 +2096,8 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) goto err; } + INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work); + err: if (error != 0) ath_tx_cleanup(sc); -- cgit v1.2.3-18-g5258 From 8e7f98b5690fc295e3a39b99aeed475d28c60c90 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 14 Jul 2009 20:17:10 -0400 Subject: ath9k: Remove bogus assert in ath_clone_txbuf() oops, this one should be part of the original patch "ath9k: downgrade assert in ath_clone_txbuf()" Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index a3bc4310a67..24663ce10ef 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -242,7 +242,6 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) spin_unlock_bh(&sc->tx.txbuflock); return NULL; } - ASSERT(!list_empty((&sc->tx.txbuf))); tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); list_del(&tbf->list); spin_unlock_bh(&sc->tx.txbuflock); -- cgit v1.2.3-18-g5258 From c41d92dc9d9a1afcec0095c32698ea7deff01098 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 14 Jul 2009 20:17:11 -0400 Subject: ath9k: Handle tx desc shortage more appropriately Update tx BA window and complete the frame as failed one if we can't clone the holding descriptor due to unavailability of descriptors. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 24663ce10ef..4ff155e8ee5 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -382,8 +382,24 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *tbf; tbf = ath_clone_txbuf(sc, bf_last); - if (!tbf) + /* + * Update tx baw and complete the frame with + * failed status if we run out of tx buf + */ + if (!tbf) { + spin_lock_bh(&txq->axq_lock); + ath_tx_update_baw(sc, tid, + bf->bf_seqno); + spin_unlock_bh(&txq->axq_lock); + + bf->bf_state.bf_type |= BUF_XRETRY; + ath_tx_rc_status(bf, ds, nbad, + 0, false); + ath_tx_complete_buf(sc, bf, &bf_head, + 0, 0); break; + } + ath9k_hw_cleartxdesc(sc->sc_ah, tbf->bf_desc); list_add_tail(&tbf->list, &bf_head); } else { -- cgit v1.2.3-18-g5258 From ebaa24534ef54a8f665558536dbef3a761a9b841 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 14 Jul 2009 20:17:12 -0400 Subject: ath9k: Remove pointless ath9k_ps_restore() in ath_detach() Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 46f4a692c8d..90cecce8d5f 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1286,7 +1286,6 @@ void ath_detach(struct ath_softc *sc) ath9k_hw_detach(sc->sc_ah); ath9k_exit_debug(sc); - ath9k_ps_restore(sc); } static int ath9k_reg_notifier(struct wiphy *wiphy, -- cgit v1.2.3-18-g5258 From 04717ccd80e5acc500239222684fcf8d2c759a84 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Tue, 14 Jul 2009 20:17:13 -0400 Subject: ath9k: serialize ath9k_hw_setpower calls Because ath9k_setpower is called from various contexts, we have to protect it against concurrent calls. Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/hw.c | 15 ++++++++++++++- drivers/net/wireless/ath/ath9k/main.c | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 20bf4a7f896..b37eb592b52 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -559,6 +559,7 @@ struct ath_softc { spinlock_t sc_resetlock; spinlock_t sc_serial_rw; spinlock_t ani_lock; + spinlock_t sc_pm_lock; struct mutex mutex; u8 curbssid[ETH_ALEN]; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index a115c8ceabe..6740a6b98a6 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2728,7 +2728,8 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) return true; } -bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) +static bool ath9k_hw_setpower_nolock(struct ath_hw *ah, + enum ath9k_power_mode mode) { int status = true, setChip = true; static const char *modes[] = { @@ -2762,6 +2763,18 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) return status; } +bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) +{ + unsigned long flags; + bool ret; + + spin_lock_irqsave(&ah->ah_sc->sc_pm_lock, flags); + ret = ath9k_hw_setpower_nolock(ah, mode); + spin_unlock_irqrestore(&ah->ah_sc->sc_pm_lock, flags); + + return ret; +} + /* * Helper for ASPM support. * diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 90cecce8d5f..d14f8c9cef6 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1316,6 +1316,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) spin_lock_init(&sc->sc_resetlock); spin_lock_init(&sc->sc_serial_rw); spin_lock_init(&sc->ani_lock); + spin_lock_init(&sc->sc_pm_lock); mutex_init(&sc->mutex); tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, -- cgit v1.2.3-18-g5258 From 0bc0798b7605664c3ab8d577b398dc7ae0b2e58c Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Tue, 14 Jul 2009 20:17:14 -0400 Subject: ath9k: uninline ath9k_ps_{wakeup,restore} functions Uninline these functions before we add functional changes to them. Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 23 ++--------------------- drivers/net/wireless/ath/ath9k/hw.c | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index b37eb592b52..8b38c0a5d7e 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -674,27 +674,8 @@ static inline int ath_ahb_init(void) { return 0; }; static inline void ath_ahb_exit(void) {}; #endif -static inline void ath9k_ps_wakeup(struct ath_softc *sc) -{ - if (atomic_inc_return(&sc->ps_usecount) == 1) - if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) { - sc->sc_ah->restore_mode = sc->sc_ah->power_mode; - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); - } -} - -static inline void ath9k_ps_restore(struct ath_softc *sc) -{ - if (atomic_dec_and_test(&sc->ps_usecount)) - if ((sc->hw->conf.flags & IEEE80211_CONF_PS) && - !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | - SC_OP_WAIT_FOR_CAB | - SC_OP_WAIT_FOR_PSPOLL_DATA | - SC_OP_WAIT_FOR_TX_ACK))) - ath9k_hw_setpower(sc->sc_ah, - sc->sc_ah->restore_mode); -} - +void ath9k_ps_wakeup(struct ath_softc *sc); +void ath9k_ps_restore(struct ath_softc *sc); void ath9k_set_bssid_mask(struct ieee80211_hw *hw); int ath9k_wiphy_add(struct ath_softc *sc); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 6740a6b98a6..df278fd807b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2775,6 +2775,27 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) return ret; } +void ath9k_ps_wakeup(struct ath_softc *sc) +{ + if (atomic_inc_return(&sc->ps_usecount) == 1) + if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) { + sc->sc_ah->restore_mode = sc->sc_ah->power_mode; + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); + } +} + +void ath9k_ps_restore(struct ath_softc *sc) +{ + if (atomic_dec_and_test(&sc->ps_usecount)) + if ((sc->hw->conf.flags & IEEE80211_CONF_PS) && + !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_CAB | + SC_OP_WAIT_FOR_PSPOLL_DATA | + SC_OP_WAIT_FOR_TX_ACK))) + ath9k_hw_setpower(sc->sc_ah, + sc->sc_ah->restore_mode); +} + /* * Helper for ASPM support. * -- cgit v1.2.3-18-g5258 From 709ade9eb8ef06e03526115408e2fc93a9feabbd Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Tue, 14 Jul 2009 20:17:15 -0400 Subject: ath9k: serialize ath9k_ps_{wakeup,restore} calls These functions are changing the power mode of the chip, but this may have unpredictable effects, if another code are trying to set the power mode via 'ath9k_hw_setpower' in the same time from another context. Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 +- drivers/net/wireless/ath/ath9k/hw.c | 42 +++++++++++++++++++++++----------- 2 files changed, 30 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 8b38c0a5d7e..15768124173 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -576,7 +576,7 @@ struct ath_softc { u32 keymax; DECLARE_BITMAP(keymap, ATH_KEYMAX); u8 splitmic; - atomic_t ps_usecount; + unsigned long ps_usecount; enum ath9k_int imask; enum ath9k_ht_extprotspacing ht_extprotspacing; enum ath9k_ht_macmode tx_chan_width; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index df278fd807b..b9d1a13ba16 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2777,23 +2777,39 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) void ath9k_ps_wakeup(struct ath_softc *sc) { - if (atomic_inc_return(&sc->ps_usecount) == 1) - if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) { - sc->sc_ah->restore_mode = sc->sc_ah->power_mode; - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); - } + unsigned long flags; + + spin_lock_irqsave(&sc->sc_pm_lock, flags); + if (++sc->ps_usecount != 1) + goto unlock; + + if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) { + sc->sc_ah->restore_mode = sc->sc_ah->power_mode; + ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE); + } + + unlock: + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); } void ath9k_ps_restore(struct ath_softc *sc) { - if (atomic_dec_and_test(&sc->ps_usecount)) - if ((sc->hw->conf.flags & IEEE80211_CONF_PS) && - !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | - SC_OP_WAIT_FOR_CAB | - SC_OP_WAIT_FOR_PSPOLL_DATA | - SC_OP_WAIT_FOR_TX_ACK))) - ath9k_hw_setpower(sc->sc_ah, - sc->sc_ah->restore_mode); + unsigned long flags; + + spin_lock_irqsave(&sc->sc_pm_lock, flags); + if (--sc->ps_usecount != 0) + goto unlock; + + if ((sc->hw->conf.flags & IEEE80211_CONF_PS) && + !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_CAB | + SC_OP_WAIT_FOR_PSPOLL_DATA | + SC_OP_WAIT_FOR_TX_ACK))) + ath9k_hw_setpower_nolock(sc->sc_ah, + sc->sc_ah->restore_mode); + + unlock: + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); } /* -- cgit v1.2.3-18-g5258 From 64839170be296e6348fbaf83fd103711978669b9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:22:53 -0400 Subject: ath9k: disable radio when all devices are marked idle This uses the new configuration changes indicated up by mac80211 when all interfaces are marked idle. We need to do a little more work as we have our own set of virtual wiphys within ath9k. Only when all virtual wiphys are inactive do we allow an idle state change for a wiphy to trigger disabling the radio. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/main.c | 24 ++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/virtual.c | 17 +++++++++++++++++ 3 files changed, 42 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 15768124173..751885a5df4 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -691,6 +691,7 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, struct ath_wiphy *selected); bool ath9k_wiphy_scanning(struct ath_softc *sc); void ath9k_wiphy_work(struct work_struct *work); +bool ath9k_all_wiphys_idle(struct ath_softc *sc); void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val); unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d14f8c9cef6..254e78786ee 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2260,9 +2260,28 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) struct ath_softc *sc = aphy->sc; struct ieee80211_conf *conf = &hw->conf; struct ath_hw *ah = sc->sc_ah; + bool all_wiphys_idle = false, disable_radio = false; mutex_lock(&sc->mutex); + /* Leave this as the first check */ + if (changed & IEEE80211_CONF_CHANGE_IDLE) { + + spin_lock_bh(&sc->wiphy_lock); + all_wiphys_idle = ath9k_all_wiphys_idle(sc); + spin_unlock_bh(&sc->wiphy_lock); + + if (conf->flags & IEEE80211_CONF_IDLE){ + if (all_wiphys_idle) + disable_radio = true; + } + else if (all_wiphys_idle) { + ath_radio_enable(sc); + DPRINTF(sc, ATH_DBG_CONFIG, + "not-idle: enabling radio\n"); + } + } + if (changed & IEEE80211_CONF_CHANGE_PS) { if (conf->flags & IEEE80211_CONF_PS) { if (!(ah->caps.hw_caps & @@ -2330,6 +2349,11 @@ skip_chan_change: if (changed & IEEE80211_CONF_CHANGE_POWER) sc->config.txpowlimit = 2 * conf->power_level; + if (disable_radio) { + DPRINTF(sc, ATH_DBG_CONFIG, "idle: disabling radio\n"); + ath_radio_disable(sc); + } + mutex_unlock(&sc->mutex); return 0; diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index 1ff429b027d..e1d419e02b4 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -660,3 +660,20 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int) queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work, sc->wiphy_scheduler_int); } + +/* caller must hold wiphy_lock */ +bool ath9k_all_wiphys_idle(struct ath_softc *sc) +{ + unsigned int i; + if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) { + return false; + } + for (i = 0; i < sc->num_sec_wiphy; i++) { + struct ath_wiphy *aphy = sc->sec_wiphy[i]; + if (!aphy) + continue; + if (aphy->state != ATH_WIPHY_INACTIVE) + return false; + } + return true; +} -- cgit v1.2.3-18-g5258 From 04dc882d601ec6fae5dfcb47c43f7af343e9a135 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Wed, 15 Jul 2009 08:51:17 +0530 Subject: ath9k: Add AR9287 based chipsets' register information. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/reg.h | 93 ++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 52605246679..8302aeb62e5 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -574,6 +574,7 @@ #define AR_D_GBL_IFS_SIFS 0x1030 #define AR_D_GBL_IFS_SIFS_M 0x0000FFFF +#define AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR 0x000003AB #define AR_D_GBL_IFS_SIFS_RESV0 0xFFFFFFFF #define AR_D_TXBLK_BASE 0x1038 @@ -589,10 +590,12 @@ #define AR_D_GBL_IFS_SLOT 0x1070 #define AR_D_GBL_IFS_SLOT_M 0x0000FFFF #define AR_D_GBL_IFS_SLOT_RESV0 0xFFFF0000 +#define AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR 0x00000420 #define AR_D_GBL_IFS_EIFS 0x10b0 #define AR_D_GBL_IFS_EIFS_M 0x0000FFFF #define AR_D_GBL_IFS_EIFS_RESV0 0xFFFF0000 +#define AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR 0x0000A5EB #define AR_D_GBL_IFS_MISC 0x10f0 #define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL 0x00000007 @@ -738,6 +741,9 @@ #define AR_SREV_REVISION_9285_10 0 #define AR_SREV_REVISION_9285_11 1 #define AR_SREV_REVISION_9285_12 2 +#define AR_SREV_VERSION_9287 0x180 +#define AR_SREV_REVISION_9287_10 0 +#define AR_SREV_REVISION_9287_11 1 #define AR_SREV_5416(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ @@ -794,6 +800,21 @@ (AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \ AR_SREV_REVISION_9285_12))) +#define AR_SREV_9287(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287)) +#define AR_SREV_9287_10_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9287)) +#define AR_SREV_9287_10(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_10)) +#define AR_SREV_9287_11(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_11)) +#define AR_SREV_9287_11_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ + ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_11))) + #define AR_RADIO_SREV_MAJOR 0xf0 #define AR_RAD5133_SREV_MAJOR 0xc0 #define AR_RAD2133_SREV_MAJOR 0xd0 @@ -809,6 +830,9 @@ #define AR_AHB_PAGE_SIZE_1K 0x00000000 #define AR_AHB_PAGE_SIZE_2K 0x00000008 #define AR_AHB_PAGE_SIZE_4K 0x00000010 +#define AR_AHB_CUSTOM_BURST_EN 0x000000C0 +#define AR_AHB_CUSTOM_BURST_EN_S 6 +#define AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL 3 #define AR_INTR_RTC_IRQ 0x00000001 #define AR_INTR_MAC_IRQ 0x00000002 @@ -885,6 +909,7 @@ enum { #define AR_NUM_GPIO 14 #define AR928X_NUM_GPIO 10 #define AR9285_NUM_GPIO 12 +#define AR9287_NUM_GPIO 11 #define AR_GPIO_IN_OUT 0x4048 #define AR_GPIO_IN_VAL 0x0FFFC000 @@ -893,6 +918,8 @@ enum { #define AR928X_GPIO_IN_VAL_S 10 #define AR9285_GPIO_IN_VAL 0x00FFF000 #define AR9285_GPIO_IN_VAL_S 12 +#define AR9287_GPIO_IN_VAL 0x003FF800 +#define AR9287_GPIO_IN_VAL_S 11 #define AR_GPIO_OE_OUT 0x404c #define AR_GPIO_OE_OUT_DRV 0x3 @@ -1154,6 +1181,33 @@ enum { #define AR9285_AN_TOP4 0x7870 #define AR9285_AN_TOP4_DEFAULT 0x10142c00 +#define AR9287_AN_RF2G3_CH0 0x7808 +#define AR9287_AN_RF2G3_CH1 0x785c +#define AR9287_AN_RF2G3_DB1 0xE0000000 +#define AR9287_AN_RF2G3_DB1_S 29 +#define AR9287_AN_RF2G3_DB2 0x1C000000 +#define AR9287_AN_RF2G3_DB2_S 26 +#define AR9287_AN_RF2G3_OB_CCK 0x03800000 +#define AR9287_AN_RF2G3_OB_CCK_S 23 +#define AR9287_AN_RF2G3_OB_PSK 0x00700000 +#define AR9287_AN_RF2G3_OB_PSK_S 20 +#define AR9287_AN_RF2G3_OB_QAM 0x000E0000 +#define AR9287_AN_RF2G3_OB_QAM_S 17 +#define AR9287_AN_RF2G3_OB_PAL_OFF 0x0001C000 +#define AR9287_AN_RF2G3_OB_PAL_OFF_S 14 + +#define AR9287_AN_TXPC0 0x7898 +#define AR9287_AN_TXPC0_TXPCMODE 0x0000C000 +#define AR9287_AN_TXPC0_TXPCMODE_S 14 +#define AR9287_AN_TXPC0_TXPCMODE_NORMAL 0 +#define AR9287_AN_TXPC0_TXPCMODE_TEST 1 +#define AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE 2 +#define AR9287_AN_TXPC0_TXPCMODE_ATBTEST 3 + +#define AR9287_AN_TOP2 0x78b4 +#define AR9287_AN_TOP2_XPABIAS_LVL 0xC0000000 +#define AR9287_AN_TOP2_XPABIAS_LVL_S 30 + #define AR_STA_ID0 0x8000 #define AR_STA_ID1 0x8004 #define AR_STA_ID1_SADH_MASK 0x0000FFFF @@ -1188,6 +1242,7 @@ enum { #define AR_TIME_OUT_ACK_S 0 #define AR_TIME_OUT_CTS 0x3FFF0000 #define AR_TIME_OUT_CTS_S 16 +#define AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR 0x16001D56 #define AR_RSSI_THR 0x8018 #define AR_RSSI_THR_MASK 0x000000FF @@ -1203,6 +1258,7 @@ enum { #define AR_USEC_TX_LAT_S 14 #define AR_USEC_RX_LAT 0x1F800000 #define AR_USEC_RX_LAT_S 23 +#define AR_USEC_ASYNC_FIFO_DUR 0x12e00074 #define AR_RESET_TSF 0x8020 #define AR_RESET_TSF_ONCE 0x01000000 @@ -1468,6 +1524,10 @@ enum { #define AR_SLP_MIB_CLEAR 0x00000001 #define AR_SLP_MIB_PENDING 0x00000002 +#define AR_MAC_PCU_LOGIC_ANALYZER 0x8264 +#define AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768 0x20000000 + + #define AR_2040_MODE 0x8318 #define AR_2040_JOINED_RX_CLEAR 0x00000001 @@ -1485,6 +1545,39 @@ enum { #define AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE 0x00000002 #define AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT 0x00000004 +#define AR_PCU_MISC_MODE2_RESERVED 0x00000038 +#define AR_PCU_MISC_MODE2_ADHOC_MCAST_KEYID_ENABLE 0x00000040 +#define AR_PCU_MISC_MODE2_CFP_IGNORE 0x00000080 +#define AR_PCU_MISC_MODE2_MGMT_QOS 0x0000FF00 +#define AR_PCU_MISC_MODE2_MGMT_QOS_S 8 +#define AR_PCU_MISC_MODE2_ENABLE_LOAD_NAV_BEACON_DURATION 0x00010000 +#define AR_PCU_MISC_MODE2_ENABLE_AGGWEP 0x00020000 +#define AR_PCU_MISC_MODE2_HWWAR1 0x00100000 +#define AR_PCU_MISC_MODE2_HWWAR2 0x02000000 +#define AR_PCU_MISC_MODE2_RESERVED2 0xFFFE0000 + +#define AR_MAC_PCU_ASYNC_FIFO_REG3 0x8358 +#define AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL 0x00000400 +#define AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET 0x80000000 + + +#define AR_AES_MUTE_MASK0 0x805c +#define AR_AES_MUTE_MASK0_FC 0x0000FFFF +#define AR_AES_MUTE_MASK0_QOS 0xFFFF0000 +#define AR_AES_MUTE_MASK0_QOS_S 16 + +#define AR_AES_MUTE_MASK1 0x8060 +#define AR_AES_MUTE_MASK1_SEQ 0x0000FFFF +#define AR_AES_MUTE_MASK1_SEQ_S 0 +#define AR_AES_MUTE_MASK1_FC_MGMT 0xFFFF0000 +#define AR_AES_MUTE_MASK1_FC_MGMT_S 16 + +#define AR_RATE_DURATION_0 0x8700 +#define AR_RATE_DURATION_31 0x87CC +#define AR_RATE_DURATION_32 0x8780 +#define AR_RATE_DURATION(_n) (AR_RATE_DURATION_0 + ((_n)<<2)) + + #define AR_KEYTABLE_0 0x8800 #define AR_KEYTABLE(_n) (AR_KEYTABLE_0 + ((_n)*32)) #define AR_KEY_CACHE_SIZE 128 -- cgit v1.2.3-18-g5258 From e91d83346ad9b30f44469c92b982206dcd7dcaf0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Jul 2009 17:21:41 +0200 Subject: wireless: remove print_mac uses Use %pM instead, and also remove stray variables declared with DECLARE_MAC_BUF. Signed-off-by: Johannes Berg Acked-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/main.c | 1 - drivers/net/wireless/b43/main.c | 4 +--- drivers/net/wireless/libertas/assoc.c | 10 +++------- drivers/net/wireless/mac80211_hwsim.c | 2 -- drivers/net/wireless/mwl8k.c | 6 ++---- drivers/net/wireless/rt2x00/rt2800usb.c | 4 +--- drivers/net/wireless/wl12xx/wl1251_main.c | 5 ++--- 7 files changed, 9 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index cfe6fc78067..c7287a883a4 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -2628,7 +2628,6 @@ static int ar9170_read_eeprom(struct ar9170 *ar) { #define RW 8 /* number of words to read at once */ #define RB (sizeof(u32) * RW) - DECLARE_MAC_BUF(mbuf); u8 *eeprom = (void *)&ar->eeprom; u8 *addr = ar->eeprom.mac_address; __le32 offsets[RW]; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index e71c8d9cd70..3f4360ad0e4 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -938,7 +938,6 @@ static void b43_clear_keys(struct b43_wldev *dev) static void b43_dump_keymemory(struct b43_wldev *dev) { unsigned int i, index, offset; - DECLARE_MAC_BUF(macbuf); u8 mac[ETH_ALEN]; u16 algo; u32 rcmta0; @@ -973,8 +972,7 @@ static void b43_dump_keymemory(struct b43_wldev *dev) ((index - 4) * 2) + 1); *((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0); *((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1); - printk(" MAC: %s", - print_mac(macbuf, mac)); + printk(" MAC: %pM", mac); } else printk(" DEFAULT KEY"); printk("\n"); diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index fbf26499c9a..385b50f4b10 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -129,7 +129,6 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth { struct cmd_ds_802_11_authenticate cmd; int ret = -1; - DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_JOIN); @@ -138,8 +137,7 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth cmd.authtype = iw_auth_to_ieee_auth(auth); - lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", - print_mac(mac, bssid), cmd.authtype); + lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", bssid, cmd.authtype); ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd); @@ -342,8 +340,6 @@ static int lbs_associate(struct lbs_private *priv, /* Firmware v9+ indicate authentication suites as a TLV */ if (priv->fwrelease >= 0x09000000) { - DECLARE_MAC_BUF(mac); - auth = (struct mrvl_ie_auth_type *) pos; auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); auth->header.len = cpu_to_le16(2); @@ -351,8 +347,8 @@ static int lbs_associate(struct lbs_private *priv, auth->auth = cpu_to_le16(tmpauth); pos += sizeof(auth->header) + 2; - lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", - print_mac(mac, bss->bssid), priv->secinfo.auth_mode); + lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", + bss->bssid, priv->secinfo.auth_mode); } /* WPA/WPA2 IEs */ diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 78431abc8b4..930f5c7da4a 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -837,7 +837,6 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) { struct mac80211_hwsim_data *data = dat; struct hwsim_vif_priv *vp = (void *)vif->drv_priv; - DECLARE_MAC_BUF(buf); struct sk_buff *skb; struct ieee80211_pspoll *pspoll; @@ -867,7 +866,6 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, struct ieee80211_vif *vif, int ps) { struct hwsim_vif_priv *vp = (void *)vif->drv_priv; - DECLARE_MAC_BUF(buf); struct sk_buff *skb; struct ieee80211_hdr *hdr; diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index b9eded88c32..4f725473fb7 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2271,7 +2271,6 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw, struct mwl8k_cmd_update_sta_db *cmd; struct peer_capability_info *peer_info; struct ieee80211_rate *bitrates = mv_vif->legacy_rates; - DECLARE_MAC_BUF(mac); int rc; __u8 count, *rates; @@ -3480,7 +3479,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, { struct ieee80211_hw *hw; struct mwl8k_priv *priv; - DECLARE_MAC_BUF(mac); int rc; int i; u8 *fw; @@ -3669,8 +3667,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, MWL8K_DESC); printk(KERN_INFO "%s: Driver Ver:%s Firmware Ver:%u.%u.%u.%u\n", priv->name, MWL8K_VERSION, fw[3], fw[2], fw[1], fw[0]); - printk(KERN_INFO "%s: MAC Address: %s\n", priv->name, - print_mac(mac, hw->wiphy->perm_addr)); + printk(KERN_INFO "%s: MAC Address: %pM\n", priv->name, + hw->wiphy->perm_addr); return 0; diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 66e001c392b..f35b3d6649c 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -2220,10 +2220,8 @@ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { - DECLARE_MAC_BUF(macbuf); - random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); + EEPROM(rt2x00dev, "MAC: %pM\n", mac); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 106b0f26519..509cbef5e27 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -435,11 +435,10 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct wl1251 *wl = hw->priv; - DECLARE_MAC_BUF(mac); int ret = 0; - wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", - conf->type, print_mac(mac, conf->mac_addr)); + wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", + conf->type, conf->mac_addr); mutex_lock(&wl->mutex); -- cgit v1.2.3-18-g5258 From ea9edaf6bc0e3f3a7bd167d9ba369276a30c9953 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 15 Jul 2009 22:49:27 -0500 Subject: hostap_cs: Enable shared interrupts The hostap_cs driver is programmed for exclusive rather that shared interrupts. Signed-off-by: Larry Finger Reported-and-Tested-by: Jack Schneider Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_cs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 63374027735..ad8eab4a639 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -666,7 +666,8 @@ static int prism2_config(struct pcmcia_device *link) * irq structure is initialized. */ if (link->conf.Attributes & CONF_ENABLE_IRQ) { - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | + IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = prism2_interrupt; link->irq.Instance = dev; -- cgit v1.2.3-18-g5258 From 1cc589b9e7d95888bb8cc806c210d8ab5371d40f Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 16 Jul 2009 17:34:06 +0800 Subject: iwmc3200wifi: fix UMAC INIT_COMPLETE notification handling The patch fixes the missing UMAC iwm_umac_wifi_in_hdr header in the UMAC INIT_COMPLETE (iwm_umac_notif_init_complete) notification. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/rx.c | 1 - drivers/net/wireless/iwmc3200wifi/umac.h | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 3909477fb3b..59ef69ca3ca 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -102,7 +102,6 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf, error = (struct iwm_umac_notif_error *)buf; fw_err = &error->err; - IWM_ERR(iwm, "%cMAC FW ERROR:\n", (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U'); IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category)); diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h index 0af2a3c7628..c5a14ae3160 100644 --- a/drivers/net/wireless/iwmc3200wifi/umac.h +++ b/drivers/net/wireless/iwmc3200wifi/umac.h @@ -615,6 +615,7 @@ struct iwm_umac_notif_alive { } __attribute__ ((packed)); struct iwm_umac_notif_init_complete { + struct iwm_umac_wifi_in_hdr hdr; __le16 status; __le16 reserved; } __attribute__ ((packed)); @@ -643,6 +644,11 @@ struct iwm_fw_error_hdr { __le32 umac_status; __le32 lmac_status; __le32 sdio_status; + __le32 dbm_sample_ctrl; + __le32 dbm_buf_base; + __le32 dbm_buf_end; + __le32 dbm_buf_write_ptr; + __le32 dbm_buf_cycle_cnt; } __attribute__ ((packed)); struct iwm_umac_notif_error { -- cgit v1.2.3-18-g5258 From 3a0e4851c97328ee455a57cb3e4097bb43934a87 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 16 Jul 2009 17:34:07 +0800 Subject: iwmc3200wifi: hardware does not support IP checksum The iwmc3200wifi hardware doesn't support IP checksum. So mark the skb->ip_summed to CHECKSUM_NONE instead of CHECKSUM_UNNECESSARY. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 59ef69ca3ca..9fb498b514e 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -1359,7 +1359,7 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm, skb->dev = iwm_to_ndev(iwm); skb->protocol = eth_type_trans(skb, ndev); - skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->ip_summed = CHECKSUM_NONE; memset(skb->cb, 0, sizeof(skb->cb)); ndev->stats.rx_packets++; -- cgit v1.2.3-18-g5258 From 49b7772776359b8306ce740bfc52d32b344adc83 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 16 Jul 2009 17:34:08 +0800 Subject: iwmc3200wifi: set cipher_suites before registering wiphy We need to specify all the cipher suites we supported. Otherwise cfg80211_validate_key_settings() will fail when we are setting keys. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 54bebba8e27..0aa389564c7 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -558,6 +558,13 @@ static struct cfg80211_ops iwm_cfg80211_ops = { .set_power_mgmt = iwm_cfg80211_set_power_mgmt, }; +static const u32 cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, +}; + struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev) { int ret = 0; @@ -600,6 +607,9 @@ struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev) wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz; wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + wdev->wiphy->cipher_suites = cipher_suites; + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + ret = wiphy_register(wdev->wiphy); if (ret < 0) { dev_err(dev, "Couldn't register wiphy device\n"); -- cgit v1.2.3-18-g5258 From 4fdd81f5f2e6fc55b67938f09b3495d679428cd7 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 16 Jul 2009 17:34:09 +0800 Subject: iwmc3200wifi: use correct debug level This patch uses TX and RX instead of NTF debug levels in some hot paths. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/rx.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 9fb498b514e..218933b8800 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -218,17 +218,17 @@ static int iwm_ntf_tx(struct iwm_priv *iwm, u8 *buf, (buf + sizeof(struct iwm_umac_wifi_in_hdr)); hdr = (struct iwm_umac_wifi_in_hdr *)buf; - IWM_DBG_NTF(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size); - - IWM_DBG_NTF(iwm, DBG, "Seqnum: %d\n", - le16_to_cpu(hdr->sw_hdr.cmd.seq_num)); - IWM_DBG_NTF(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt); - IWM_DBG_NTF(iwm, DBG, "\tRetry cnt: %d\n", - le16_to_cpu(tx_resp->retry_cnt)); - IWM_DBG_NTF(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl)); - IWM_DBG_NTF(iwm, DBG, "\tByte cnt: %d\n", - le16_to_cpu(tx_resp->byte_cnt)); - IWM_DBG_NTF(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status)); + IWM_DBG_TX(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size); + + IWM_DBG_TX(iwm, DBG, "Seqnum: %d\n", + le16_to_cpu(hdr->sw_hdr.cmd.seq_num)); + IWM_DBG_TX(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt); + IWM_DBG_TX(iwm, DBG, "\tRetry cnt: %d\n", + le16_to_cpu(tx_resp->retry_cnt)); + IWM_DBG_TX(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl)); + IWM_DBG_TX(iwm, DBG, "\tByte cnt: %d\n", + le16_to_cpu(tx_resp->byte_cnt)); + IWM_DBG_TX(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status)); return 0; } @@ -418,8 +418,8 @@ static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf, if (IS_ERR(ticket_node)) return PTR_ERR(ticket_node); - IWM_DBG_NTF(iwm, DBG, "TICKET RELEASE(%d)\n", - ticket->id); + IWM_DBG_RX(iwm, DBG, "TICKET RELEASE(%d)\n", + ticket->id); list_add_tail(&ticket_node->node, &iwm->rx_tickets); /* @@ -454,15 +454,15 @@ static int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf, u16 id, buf_offset; u32 packet_size; - IWM_DBG_NTF(iwm, DBG, "\n"); + IWM_DBG_RX(iwm, DBG, "\n"); wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num); buf_offset = sizeof(struct iwm_umac_wifi_in_hdr); packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr); - IWM_DBG_NTF(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n", - wifi_hdr->sw_hdr.cmd.cmd, id, packet_size); + IWM_DBG_RX(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n", + wifi_hdr->sw_hdr.cmd.cmd, id, packet_size); IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id); IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size); -- cgit v1.2.3-18-g5258 From 9967d46aa5ba065650d3352ab5d906f56ba17648 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 16 Jul 2009 17:34:10 +0800 Subject: iwmc3200wifi: cfg80211 managed mode port This patch ports iwmc3200wifi to the cfg80211 managed mode API. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 195 ++++++++++++++++ drivers/net/wireless/iwmc3200wifi/rx.c | 16 +- drivers/net/wireless/iwmc3200wifi/wext.c | 320 +++------------------------ 3 files changed, 239 insertions(+), 292 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 0aa389564c7..ee403176438 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -305,6 +305,25 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy, return iwm_reset_profile(iwm); } +int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, + u8 *mac, struct station_info *sinfo) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + + if (memcmp(mac, iwm->bssid, ETH_ALEN)) + return -ENOENT; + + sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->txrate.legacy = iwm->rate * 10; + + if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { + sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->signal = iwm->wstats.qual.level; + } + + return 0; +} + int iwm_cfg80211_inform_bss(struct iwm_priv *iwm) { @@ -500,6 +519,179 @@ static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) return 0; } +static int iwm_set_auth_type(struct iwm_priv *iwm, + enum nl80211_auth_type sme_auth_type) +{ + u8 *auth_type = &iwm->umac_profile->sec.auth_type; + + switch (sme_auth_type) { + case NL80211_AUTHTYPE_AUTOMATIC: + case NL80211_AUTHTYPE_OPEN_SYSTEM: + IWM_DBG_WEXT(iwm, DBG, "OPEN auth\n"); + *auth_type = UMAC_AUTH_TYPE_OPEN; + break; + case NL80211_AUTHTYPE_SHARED_KEY: + if (iwm->umac_profile->sec.flags & + (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) { + IWM_DBG_WEXT(iwm, DBG, "WPA auth alg\n"); + *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; + } else { + IWM_DBG_WEXT(iwm, DBG, "WEP shared key auth alg\n"); + *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; + } + + break; + default: + IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", sme_auth_type); + return -ENOTSUPP; + } + + return 0; +} + +static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version) +{ + if (!wpa_version) { + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE; + return 0; + } + + if (wpa_version & NL80211_WPA_VERSION_2) + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK; + + if (wpa_version & NL80211_WPA_VERSION_1) + iwm->umac_profile->sec.flags |= UMAC_SEC_FLG_WPA_ON_MSK; + + return 0; +} + +static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast) +{ + u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher : + &iwm->umac_profile->sec.mcast_cipher; + + if (!cipher) { + *profile_cipher = UMAC_CIPHER_TYPE_NONE; + return 0; + } + + switch (cipher) { + case IW_AUTH_CIPHER_NONE: + *profile_cipher = UMAC_CIPHER_TYPE_NONE; + break; + case WLAN_CIPHER_SUITE_WEP40: + *profile_cipher = UMAC_CIPHER_TYPE_WEP_40; + break; + case WLAN_CIPHER_SUITE_WEP104: + *profile_cipher = UMAC_CIPHER_TYPE_WEP_104; + break; + case WLAN_CIPHER_SUITE_TKIP: + *profile_cipher = UMAC_CIPHER_TYPE_TKIP; + break; + case WLAN_CIPHER_SUITE_CCMP: + *profile_cipher = UMAC_CIPHER_TYPE_CCMP; + break; + default: + IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher); + return -ENOTSUPP; + } + + return 0; +} + +static int iwm_set_key_mgt(struct iwm_priv *iwm, u32 key_mgt) +{ + u8 *auth_type = &iwm->umac_profile->sec.auth_type; + + IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt); + + if (key_mgt == WLAN_AKM_SUITE_8021X) + *auth_type = UMAC_AUTH_TYPE_8021X; + else if (key_mgt == WLAN_AKM_SUITE_PSK) { + if (iwm->umac_profile->sec.flags & + (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) + *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; + else + *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; + } else { + IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt); + return -EINVAL; + } + + return 0; +} + + +static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + struct ieee80211_channel *chan = sme->channel; + int ret; + + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return -EIO; + + if (!sme->ssid) + return -EINVAL; + + if (chan) + iwm->channel = + ieee80211_frequency_to_channel(chan->center_freq); + + iwm->umac_profile->ssid.ssid_len = sme->ssid_len; + memcpy(iwm->umac_profile->ssid.ssid, sme->ssid, sme->ssid_len); + + if (sme->bssid) { + IWM_DBG_WEXT(iwm, DBG, "BSSID: %pM\n", sme->bssid); + memcpy(&iwm->umac_profile->bssid[0], sme->bssid, ETH_ALEN); + iwm->umac_profile->bss_num = 1; + } else { + memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN); + iwm->umac_profile->bss_num = 0; + } + + ret = iwm_set_auth_type(iwm, sme->auth_type); + if (ret < 0) + return ret; + + ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions); + if (ret < 0) + return ret; + + if (sme->crypto.n_ciphers_pairwise) { + ret = iwm_set_cipher(iwm, sme->crypto.ciphers_pairwise[0], + true); + if (ret < 0) + return ret; + } + + ret = iwm_set_cipher(iwm, sme->crypto.cipher_group, false); + if (ret < 0) + return ret; + + if (sme->crypto.n_akm_suites) { + ret = iwm_set_key_mgt(iwm, sme->crypto.akm_suites[0]); + if (ret < 0) + return ret; + } + + return iwm_send_mlme_profile(iwm); +} + +static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + + IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active); + + if (iwm->umac_profile_active) + return iwm_invalidate_mlme_profile(iwm); + + return 0; +} + static int iwm_cfg80211_set_txpower(struct wiphy *wiphy, enum tx_power_setting type, int dbm) { @@ -549,8 +741,11 @@ static struct cfg80211_ops iwm_cfg80211_ops = { .get_key = iwm_cfg80211_get_key, .del_key = iwm_cfg80211_del_key, .set_default_key = iwm_cfg80211_set_default_key, + .get_station = iwm_cfg80211_get_station, .scan = iwm_cfg80211_scan, .set_wiphy_params = iwm_cfg80211_set_wiphy_params, + .connect = iwm_cfg80211_connect, + .disconnect = iwm_cfg80211_disconnect, .join_ibss = iwm_cfg80211_join_ibss, .leave_ibss = iwm_cfg80211_leave_ibss, .set_tx_power = iwm_cfg80211_set_txpower, diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 218933b8800..82b572a6fc0 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -503,13 +503,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, { struct iwm_umac_notif_assoc_complete *complete = (struct iwm_umac_notif_assoc_complete *)buf; - union iwreq_data wrqu; IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n", complete->bssid, complete->status); - memset(&wrqu, 0, sizeof(wrqu)); - clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status); switch (le32_to_cpu(complete->status)) { @@ -520,7 +517,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, iwm_link_on(iwm); - memcpy(wrqu.ap_addr.sa_data, complete->bssid, ETH_ALEN); + cfg80211_connect_result(iwm_to_ndev(iwm), + complete->bssid, + NULL, 0, NULL, 0, + WLAN_STATUS_SUCCESS, GFP_KERNEL); break; case UMAC_ASSOC_COMPLETE_FAILURE: clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); @@ -528,6 +528,11 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, iwm->channel = 0; iwm_link_off(iwm); + + cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid, + NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); default: break; } @@ -537,9 +542,6 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, return 0; } - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(iwm_to_ndev(iwm), SIOCGIWAP, &wrqu, NULL); - return 0; } diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c index 2e7eaf96cf9..c3c90d5963b 100644 --- a/drivers/net/wireless/iwmc3200wifi/wext.c +++ b/drivers/net/wireless/iwmc3200wifi/wext.c @@ -21,31 +21,11 @@ * */ -#include -#include #include -#include -#include #include -#include #include "iwm.h" -#include "umac.h" #include "commands.h" -#include "debug.h" - -static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - struct iw_statistics *wstats = &iwm->wstats; - - if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { - memset(wstats, 0, sizeof(struct iw_statistics)); - wstats->qual.updated = IW_QUAL_ALL_INVALID; - } - - return wstats; -} static int iwm_wext_siwfreq(struct net_device *dev, struct iw_request_info *info, @@ -53,14 +33,12 @@ static int iwm_wext_siwfreq(struct net_device *dev, { struct iwm_priv *iwm = ndev_to_iwm(dev); - if (freq->flags == IW_FREQ_AUTO) - return 0; - - /* frequency/channel can only be set in IBSS mode */ - if (iwm->conf.mode != UMAC_MODE_IBSS) + switch (iwm->conf.mode) { + case UMAC_MODE_IBSS: + return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); + default: return -EOPNOTSUPP; - - return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); + } } static int iwm_wext_giwfreq(struct net_device *dev, @@ -69,69 +47,29 @@ static int iwm_wext_giwfreq(struct net_device *dev, { struct iwm_priv *iwm = ndev_to_iwm(dev); - if (iwm->conf.mode == UMAC_MODE_IBSS) + switch (iwm->conf.mode) { + case UMAC_MODE_IBSS: return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); - - freq->e = 0; - freq->m = iwm->channel; - - return 0; + case UMAC_MODE_BSS: + return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra); + default: + return -EOPNOTSUPP; + } } static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { struct iwm_priv *iwm = ndev_to_iwm(dev); - int ret; - - IWM_DBG_WEXT(iwm, DBG, "Set BSSID: %pM\n", ap_addr->sa_data); - if (iwm->conf.mode == UMAC_MODE_IBSS) + switch (iwm->conf.mode) { + case UMAC_MODE_IBSS: return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); - - if (!test_bit(IWM_STATUS_READY, &iwm->status)) - return -EIO; - - if (is_zero_ether_addr(ap_addr->sa_data) || - is_broadcast_ether_addr(ap_addr->sa_data)) { - IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n", - iwm->umac_profile->bssid[0]); - memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN); - iwm->umac_profile->bss_num = 0; - } else { - IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n", - ap_addr->sa_data); - memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data, - ETH_ALEN); - iwm->umac_profile->bss_num = 1; - } - - if (iwm->umac_profile_active) { - int i; - - if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN)) - return 0; - - /* - * If we're clearing the BSSID, and we're associated, - * we have to clear the keys as they're no longer valid. - */ - if (is_zero_ether_addr(ap_addr->sa_data)) { - for (i = 0; i < IWM_NUM_KEYS; i++) - iwm->keys[i].key_len = 0; - } - - ret = iwm_invalidate_mlme_profile(iwm); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't invalidate profile\n"); - return ret; - } + case UMAC_MODE_BSS: + return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra); + default: + return -EOPNOTSUPP; } - - if (iwm->umac_profile->ssid.ssid_len) - return iwm_send_mlme_profile(iwm); - - return 0; } static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info, @@ -143,17 +81,10 @@ static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info, case UMAC_MODE_IBSS: return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); case UMAC_MODE_BSS: - if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { - ap_addr->sa_family = ARPHRD_ETHER; - memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN); - } else - memset(&ap_addr->sa_data, 0, ETH_ALEN); - break; + return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra); default: return -EOPNOTSUPP; } - - return 0; } static int iwm_wext_siwessid(struct net_device *dev, @@ -161,36 +92,15 @@ static int iwm_wext_siwessid(struct net_device *dev, struct iw_point *data, char *ssid) { struct iwm_priv *iwm = ndev_to_iwm(dev); - size_t len = data->length; - int ret; - - IWM_DBG_WEXT(iwm, DBG, "Set ESSID: >%s<\n", ssid); - if (iwm->conf.mode == UMAC_MODE_IBSS) + switch (iwm->conf.mode) { + case UMAC_MODE_IBSS: return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); - - if (!test_bit(IWM_STATUS_READY, &iwm->status)) - return -EIO; - - if (len > 0 && ssid[len - 1] == '\0') - len--; - - if (iwm->umac_profile_active) { - if (iwm->umac_profile->ssid.ssid_len == len && - !memcmp(iwm->umac_profile->ssid.ssid, ssid, len)) - return 0; - - ret = iwm_invalidate_mlme_profile(iwm); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't invalidate profile\n"); - return ret; - } + case UMAC_MODE_BSS: + return cfg80211_mgd_wext_siwessid(dev, info, data, ssid); + default: + return -EOPNOTSUPP; } - - iwm->umac_profile->ssid.ssid_len = len; - memcpy(iwm->umac_profile->ssid.ssid, ssid, len); - - return iwm_send_mlme_profile(iwm); } static int iwm_wext_giwessid(struct net_device *dev, @@ -199,174 +109,14 @@ static int iwm_wext_giwessid(struct net_device *dev, { struct iwm_priv *iwm = ndev_to_iwm(dev); - if (iwm->conf.mode == UMAC_MODE_IBSS) + switch (iwm->conf.mode) { + case UMAC_MODE_IBSS: return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); - - if (!test_bit(IWM_STATUS_READY, &iwm->status)) - return -EIO; - - data->length = iwm->umac_profile->ssid.ssid_len; - if (data->length) { - memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length); - data->flags = 1; - } else - data->flags = 0; - - return 0; -} - -static int iwm_wext_giwrate(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rate, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - rate->value = iwm->rate * 1000000; - - return 0; -} - -static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version) -{ - if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) - iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK; - else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) - iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK; - else - iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE; - - return 0; -} - -static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt) -{ - u8 *auth_type = &iwm->umac_profile->sec.auth_type; - - IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt); - - if (key_mgt == IW_AUTH_KEY_MGMT_802_1X) - *auth_type = UMAC_AUTH_TYPE_8021X; - else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) { - if (iwm->umac_profile->sec.flags & - (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) - *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; - else - *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; - } else { - IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt); - return -EINVAL; - } - - return 0; -} - -static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast) -{ - u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher : - &iwm->umac_profile->sec.mcast_cipher; - - switch (cipher) { - case IW_AUTH_CIPHER_NONE: - *profile_cipher = UMAC_CIPHER_TYPE_NONE; - break; - case IW_AUTH_CIPHER_WEP40: - *profile_cipher = UMAC_CIPHER_TYPE_WEP_40; - break; - case IW_AUTH_CIPHER_TKIP: - *profile_cipher = UMAC_CIPHER_TYPE_TKIP; - break; - case IW_AUTH_CIPHER_CCMP: - *profile_cipher = UMAC_CIPHER_TYPE_CCMP; - break; - case IW_AUTH_CIPHER_WEP104: - *profile_cipher = UMAC_CIPHER_TYPE_WEP_104; - break; - default: - IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher); - return -ENOTSUPP; - } - - return 0; -} - -static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg) -{ - u8 *auth_type = &iwm->umac_profile->sec.auth_type; - - IWM_DBG_WEXT(iwm, DBG, "auth_alg: 0x%x\n", auth_alg); - - switch (auth_alg) { - case IW_AUTH_ALG_OPEN_SYSTEM: - *auth_type = UMAC_AUTH_TYPE_OPEN; - break; - case IW_AUTH_ALG_SHARED_KEY: - if (iwm->umac_profile->sec.flags & - (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) { - if (*auth_type == UMAC_AUTH_TYPE_8021X) - return -EINVAL; - *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; - } else { - IWM_DBG_WEXT(iwm, DBG, "WEP shared key\n"); - *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; - } - break; - case IW_AUTH_ALG_LEAP: - default: - IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg); - return -ENOTSUPP; - } - - return 0; -} - -static int iwm_wext_siwauth(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *data, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - int ret; - - if ((data->flags) & - (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT | - IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) { - /* We need to invalidate the current profile */ - if (iwm->umac_profile_active) { - ret = iwm_invalidate_mlme_profile(iwm); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't invalidate profile\n"); - return ret; - } - } - } - - switch (data->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - return iwm_set_wpa_version(iwm, data->value); - break; - case IW_AUTH_CIPHER_PAIRWISE: - return iwm_set_cipher(iwm, data->value, 1); - break; - case IW_AUTH_CIPHER_GROUP: - return iwm_set_cipher(iwm, data->value, 0); - break; - case IW_AUTH_KEY_MGMT: - return iwm_set_key_mgt(iwm, data->value); - break; - case IW_AUTH_80211_AUTH_ALG: - return iwm_set_auth_alg(iwm, data->value); - break; + case UMAC_MODE_BSS: + return cfg80211_mgd_wext_giwessid(dev, info, data, ssid); default: - return -ENOTSUPP; + return -EOPNOTSUPP; } - - return 0; -} - -static int iwm_wext_giwauth(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *data, char *extra) -{ - return 0; } static const iw_handler iwm_handlers[] = @@ -404,7 +154,7 @@ static const iw_handler iwm_handlers[] = (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* SIOCSIWRATE */ - (iw_handler) iwm_wext_giwrate, /* SIOCGIWRATE */ + (iw_handler) cfg80211_wext_giwrate, /* SIOCGIWRATE */ (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */ (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ @@ -419,10 +169,10 @@ static const iw_handler iwm_handlers[] = (iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* SIOCSIWGENIE */ + (iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */ (iw_handler) NULL, /* SIOCGIWGENIE */ - (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */ - (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */ + (iw_handler) cfg80211_wext_siwauth, /* SIOCSIWAUTH */ + (iw_handler) cfg80211_wext_giwauth, /* SIOCGIWAUTH */ (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */ (iw_handler) NULL, /* SIOCGIWENCODEEXT */ (iw_handler) NULL, /* SIOCSIWPMKSA */ @@ -432,6 +182,6 @@ static const iw_handler iwm_handlers[] = const struct iw_handler_def iwm_iw_handler_def = { .num_standard = ARRAY_SIZE(iwm_handlers), .standard = (iw_handler *) iwm_handlers, - .get_wireless_stats = iwm_get_wireless_stats, + .get_wireless_stats = cfg80211_wireless_stats, }; -- cgit v1.2.3-18-g5258 From 0e371f1a0c0acd4abfa052b01e7b1f4a71ef6590 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 16 Jul 2009 17:34:11 +0800 Subject: iwmc3200wifi: remove setting WEP keys before setting essid support The recent cfg80211 "rework key operation" patch from Johannes Berg makes sure keys are set only after the connection has been established. So we can remove the setting WEP keys before essid support from the driver. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 26 -------------------------- 1 file changed, 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index ee403176438..0372658bac9 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -203,32 +203,6 @@ static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, return ret; } - /* - * The WEP keys can be set before or after setting the essid. - * We need to handle both cases by simply pushing the keys after - * we send the profile. - * If the profile is not set yet (i.e. we're pushing keys before - * the essid), we set the cipher appropriately. - * If the profile is set, we havent associated yet because our - * cipher was incorrectly set. So we invalidate and send the - * profile again. - */ - if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || - key->cipher == WLAN_CIPHER_SUITE_WEP104) { - u8 *ucast_cipher = &iwm->umac_profile->sec.ucast_cipher; - u8 *mcast_cipher = &iwm->umac_profile->sec.mcast_cipher; - - IWM_DBG_WEXT(iwm, DBG, "WEP key\n"); - - if (key->cipher == WLAN_CIPHER_SUITE_WEP40) - *ucast_cipher = *mcast_cipher = UMAC_CIPHER_TYPE_WEP_40; - if (key->cipher == WLAN_CIPHER_SUITE_WEP104) - *ucast_cipher = *mcast_cipher = - UMAC_CIPHER_TYPE_WEP_104; - - return iwm_reset_profile(iwm); - } - return iwm_set_key(iwm, 0, key); } -- cgit v1.2.3-18-g5258 From b6c321718e1376b1a55afc63cce090a2c4573417 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 16 Jul 2009 17:34:12 +0800 Subject: iwmc3200wifi: make iwm_send_wifi_if_cmd return 0 on success We used to return the result of wait_event_interruptible_timeout() which is the remaining timeout on success. But this information is not used by any of its callers. So we just return 0 on success. This fixed a erroneous return value bug for iwm_set_key(). Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 0d35afefb61..e6be29704a1 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -87,8 +87,7 @@ int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, test_and_clear_bit(oid, &iwm->wifi_ntfy[0]), 3 * HZ); - if (!ret) - ret = -EBUSY; + return ret ? 0 : -EBUSY; } return ret; @@ -480,8 +479,10 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address, target_cmd.eop = 1; ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); - if (ret < 0) + if (ret < 0) { IWM_ERR(iwm, "Couldn't send READ command\n"); + return ret; + } /* When succeding, the send_target routine returns the seq number */ seq_num = ret; @@ -501,7 +502,7 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address, kfree(cmd); - return ret; + return 0; } int iwm_read_mac(struct iwm_priv *iwm, u8 *mac) @@ -511,7 +512,7 @@ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac) ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR), mac_align, sizeof(mac_align)); - if (ret < 0) + if (ret) return ret; if (is_valid_ether_addr(mac_align)) @@ -714,7 +715,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) ret = iwm_send_wifi_if_cmd(iwm, &key_remove, sizeof(struct iwm_umac_key_remove), 1); - if (ret < 0) + if (ret) return ret; iwm->keys[key_idx].key_len = 0; @@ -736,7 +737,7 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm) sizeof(struct iwm_umac_wifi_if)); ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1); - if (ret < 0) { + if (ret) { IWM_ERR(iwm, "Send profile command failed\n"); return ret; } @@ -752,12 +753,12 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm) 3 * HZ); ret = iwm_set_key(iwm, 0, key); - if (ret < 0) + if (ret) return ret; if (iwm->default_key == i) { ret = iwm_set_tx_key(iwm, i); - if (ret < 0) + if (ret) return ret; } } @@ -778,15 +779,13 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm) invalid.reason = WLAN_REASON_UNSPECIFIED; ret = iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1); - if (ret < 0) + if (ret) return ret; ret = wait_event_interruptible_timeout(iwm->mlme_queue, (iwm->umac_profile_active == 0), 2 * HZ); - if (!ret) - return -EBUSY; - return 0; + return ret ? 0 : -EBUSY; } int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags) @@ -869,7 +868,7 @@ int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, } ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0); - if (ret < 0) { + if (ret) { IWM_ERR(iwm, "Couldn't send scan request\n"); return ret; } -- cgit v1.2.3-18-g5258 From 6e5db0a8454b44bf88fa74cf437a507ec08f436d Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 16 Jul 2009 17:34:13 +0800 Subject: iwmc3200wifi: remove key caches in driver cfg80211 now guarantees keys are set after connecting. We can remove the key cache code from the driver now. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 43 +--------------------------- drivers/net/wireless/iwmc3200wifi/commands.c | 29 +------------------ 2 files changed, 2 insertions(+), 70 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 0372658bac9..3f5a08fa401 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -158,34 +158,6 @@ static int iwm_key_init(struct iwm_key *key, u8 key_index, return 0; } -static int iwm_reset_profile(struct iwm_priv *iwm) -{ - int ret; - - if (!iwm->umac_profile_active) - return 0; - - /* - * If there is a current active profile, but no - * default key, it's not worth trying to associate again. - */ - if (iwm->default_key < 0) - return 0; - - /* - * Here we have an active profile, but a key setting changed. - * We thus have to invalidate the current profile, and push the - * new one. Keys will be pushed when association takes place. - */ - ret = iwm_invalidate_mlme_profile(iwm); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't invalidate profile\n"); - return ret; - } - - return iwm_send_mlme_profile(iwm); -} - static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, const u8 *mac_addr, struct key_params *params) @@ -245,10 +217,6 @@ static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, if (key_index == iwm->default_key) iwm->default_key = -1; - /* If the interface is down, we just cache this */ - if (!test_bit(IWM_STATUS_READY, &iwm->status)) - return 0; - return iwm_set_key(iwm, 1, key); } @@ -257,7 +225,6 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy, u8 key_index) { struct iwm_priv *iwm = ndev_to_iwm(ndev); - int ret; IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index); @@ -268,15 +235,7 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy, iwm->default_key = key_index; - /* If the interface is down, we just cache this */ - if (!test_bit(IWM_STATUS_READY, &iwm->status)) - return 0; - - ret = iwm_set_tx_key(iwm, key_index); - if (ret < 0) - return ret; - - return iwm_reset_profile(iwm); + return iwm_set_tx_key(iwm, key_index); } int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index e6be29704a1..0d6637005f4 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -584,12 +584,6 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd; struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd; - /* - * We check if our current profile is valid. - * If not, we dont push the key, we just cache them, - * so that with the next siwsessid call, the keys - * will be actually pushed. - */ if (!remove) { ret = iwm_check_profile(iwm); if (ret < 0) @@ -727,7 +721,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) int iwm_send_mlme_profile(struct iwm_priv *iwm) { - int ret, i; + int ret; struct iwm_umac_profile profile; memcpy(&profile, iwm->umac_profile, sizeof(profile)); @@ -742,27 +736,6 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm) return ret; } - for (i = 0; i < IWM_NUM_KEYS; i++) - if (iwm->keys[i].key_len) { - struct iwm_key *key = &iwm->keys[i]; - - /* Wait for the profile before sending the keys */ - wait_event_interruptible_timeout(iwm->mlme_queue, - (test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) || - test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)), - 3 * HZ); - - ret = iwm_set_key(iwm, 0, key); - if (ret) - return ret; - - if (iwm->default_key == i) { - ret = iwm_set_tx_key(iwm, i); - if (ret) - return ret; - } - } - return 0; } -- cgit v1.2.3-18-g5258 From 12f49a79cd32d97a11f864a7b67660438ee3e6c8 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Thu, 16 Jul 2009 20:03:17 +0200 Subject: p54: remove useless code This patch removes some useless checks in recv/xmit code. Acked-by: Larry Finger Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/txrx.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 01eadb1683f..416400c4ad0 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -87,9 +87,6 @@ static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb) u32 target_addr = priv->rx_start; u16 len = priv->headroom + skb->len + priv->tailroom + 3; - if (unlikely(WARN_ON(!skb || !priv))) - return -EINVAL; - info = IEEE80211_SKB_CB(skb); range = (void *) info->rate_driver_data; len = (range->extra_len + len) & ~0x3; @@ -111,11 +108,6 @@ static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb) range = (void *) info->rate_driver_data; hole_size = range->start_addr - last_addr; - if (!entry->next) { - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - return -ENOSPC; - } - if (!target_skb && hole_size >= len) { target_skb = entry->prev; hole_size -= len; @@ -153,9 +145,6 @@ static void p54_tx_pending(struct p54_common *priv) struct sk_buff *skb; int ret; - if (unlikely(WARN_ON(!priv))) - return ; - skb = skb_dequeue(&priv->tx_pending); if (unlikely(!skb)) return ; @@ -219,7 +208,7 @@ static int p54_tx_qos_accounting_alloc(struct p54_common *priv, static void p54_tx_qos_accounting_free(struct p54_common *priv, struct sk_buff *skb) { - if (skb && IS_DATA_FRAME(skb)) { + if (IS_DATA_FRAME(skb)) { struct p54_hdr *hdr = (void *) skb->data; struct p54_tx_data *data = (void *) hdr->data; unsigned long flags; @@ -266,9 +255,6 @@ static struct sk_buff *p54_find_and_unlink_skb(struct p54_common *priv, void p54_tx(struct p54_common *priv, struct sk_buff *skb) { - if (unlikely(WARN_ON(!priv))) - return ; - skb_queue_tail(&priv->tx_pending, skb); p54_tx_pending(priv); } -- cgit v1.2.3-18-g5258 From 46df10ae44b4488176bae16da0b31541eb0f8f48 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Thu, 16 Jul 2009 20:03:47 +0200 Subject: p54: fix beaconing related firmware crash This patch fixes a firmware crash which can be provoked by changing operation mode. Acked-by: Larry Finger Signed-off-by: Christian Lamparter Tested-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/p54/lmac.h | 4 ++++ drivers/net/wireless/p54/main.c | 31 +++++++++++++++++++------------ drivers/net/wireless/p54/p54.h | 1 + drivers/net/wireless/p54/txrx.c | 22 ++++++++++++++-------- 4 files changed, 38 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/lmac.h b/drivers/net/wireless/p54/lmac.h index af35cfcd4fe..04b63ec80fa 100644 --- a/drivers/net/wireless/p54/lmac.h +++ b/drivers/net/wireless/p54/lmac.h @@ -98,6 +98,10 @@ struct p54_hdr { (!((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \ flags) & cpu_to_le16(P54_HDR_FLAG_CONTROL))) +#define GET_HW_QUEUE(skb) \ + (((struct p54_tx_data *)((struct p54_hdr *) \ + skb->data)->data)->hw_queue) + /* * shared interface ID definitions * The interface ID is a unique identification of a specific interface. diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index f19add2c3ca..955f6d7ec16 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -130,7 +130,6 @@ static int p54_beacon_update(struct p54_common *priv, struct ieee80211_vif *vif) { struct sk_buff *beacon; - __le32 old_beacon_req_id; int ret; beacon = ieee80211_beacon_get(priv->hw, vif); @@ -140,15 +139,16 @@ static int p54_beacon_update(struct p54_common *priv, if (ret) return ret; - old_beacon_req_id = priv->beacon_req_id; - priv->beacon_req_id = GET_REQ_ID(beacon); - - ret = p54_tx_80211(priv->hw, beacon); - if (ret) { - priv->beacon_req_id = old_beacon_req_id; - return -ENOSPC; - } - + /* + * During operation, the firmware takes care of beaconing. + * The driver only needs to upload a new beacon template, once + * the template was changed by the stack or userspace. + * + * LMAC API 3.2.2 also specifies that the driver does not need + * to cancel the old beacon template by hand, instead the firmware + * will release the previous one through the feedback mechanism. + */ + WARN_ON(p54_tx_80211(priv->hw, beacon)); priv->tsf_high32 = 0; priv->tsf_low32 = 0; @@ -253,9 +253,14 @@ static void p54_remove_interface(struct ieee80211_hw *dev, mutex_lock(&priv->conf_mutex); priv->vif = NULL; - if (priv->beacon_req_id) { + + /* + * LMAC API 3.2.2 states that any active beacon template must be + * canceled by the driver before attempting a mode transition. + */ + if (le32_to_cpu(priv->beacon_req_id) != 0) { p54_tx_cancel(priv, priv->beacon_req_id); - priv->beacon_req_id = cpu_to_le32(0); + wait_for_completion_interruptible_timeout(&priv->beacon_comp, HZ); } priv->mode = NL80211_IFTYPE_MONITOR; memset(priv->mac_addr, 0, ETH_ALEN); @@ -544,6 +549,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) BIT(NL80211_IFTYPE_MESH_POINT); dev->channel_change_time = 1000; /* TODO: find actual value */ + priv->beacon_req_id = cpu_to_le32(0); priv->tx_stats[P54_QUEUE_BEACON].limit = 1; priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1; priv->tx_stats[P54_QUEUE_MGMT].limit = 3; @@ -567,6 +573,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) mutex_init(&priv->conf_mutex); mutex_init(&priv->eeprom_mutex); init_completion(&priv->eeprom_comp); + init_completion(&priv->beacon_comp); INIT_DELAYED_WORK(&priv->work, p54_work); return dev; diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 584b1560aff..1afc39410e8 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -211,6 +211,7 @@ struct p54_common { u16 aid; bool powersave_override; __le32 beacon_req_id; + struct completion beacon_comp; /* cryptographic engine information */ u8 privacy_caps; diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 416400c4ad0..0d589d68e54 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -134,9 +134,13 @@ static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb) range = (void *) info->rate_driver_data; range->start_addr = target_addr; range->end_addr = target_addr + len; + data->req_id = cpu_to_le32(target_addr + priv->headroom); + if (IS_DATA_FRAME(skb) && + unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON)) + priv->beacon_req_id = data->req_id; + __skb_queue_after(&priv->tx_queue, target_skb, skb); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); - data->req_id = cpu_to_le32(target_addr + priv->headroom); return 0; } @@ -209,13 +213,19 @@ static void p54_tx_qos_accounting_free(struct p54_common *priv, struct sk_buff *skb) { if (IS_DATA_FRAME(skb)) { - struct p54_hdr *hdr = (void *) skb->data; - struct p54_tx_data *data = (void *) hdr->data; unsigned long flags; spin_lock_irqsave(&priv->tx_stats_lock, flags); - priv->tx_stats[data->hw_queue].len--; + priv->tx_stats[GET_HW_QUEUE(skb)].len--; spin_unlock_irqrestore(&priv->tx_stats_lock, flags); + + if (unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON)) { + if (priv->beacon_req_id == GET_REQ_ID(skb)) { + /* this is the active beacon set anymore */ + priv->beacon_req_id = 0; + } + complete(&priv->beacon_comp); + } } p54_wake_queues(priv); } @@ -403,10 +413,6 @@ static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb) * and we don't want to confuse the mac80211 stack. */ if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) { - if (entry_data->hw_queue == P54_QUEUE_BEACON && - hdr->req_id == priv->beacon_req_id) - priv->beacon_req_id = cpu_to_le32(0); - dev_kfree_skb_any(entry); return ; } -- cgit v1.2.3-18-g5258 From 436b37c59416d0d8e21430f7980857fc932eb1e6 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Thu, 16 Jul 2009 20:05:41 +0200 Subject: p54: fix a fw crash caused by statistic feedback This patch fixes a bug which crawled into the tree with the split-up changes. The memory-manager wasn't aware of the statistic feedback extra_len space requirements and happily placed following frames into the allegedly free spots. Thanks fly out to Larry Finger for taking the time to test all (permutations of) patches and theories all day long. Acked-by: Larry Finger Signed-off-by: Christian Lamparter Tested-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/p54/fwio.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index 349375f4a14..21f19018fab 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c @@ -686,6 +686,8 @@ int p54_upload_key(struct p54_common *priv, u8 algo, int slot, u8 idx, u8 len, int p54_fetch_statistics(struct p54_common *priv) { + struct ieee80211_tx_info *txinfo; + struct p54_tx_info *p54info; struct sk_buff *skb; skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL, @@ -694,6 +696,20 @@ int p54_fetch_statistics(struct p54_common *priv) if (!skb) return -ENOMEM; + /* + * The statistic feedback causes some extra headaches here, if it + * is not to crash/corrupt the firmware data structures. + * + * Unlike all other Control Get OIDs we can not use helpers like + * skb_put to reserve the space for the data we're requesting. + * Instead the extra frame length -which will hold the results later- + * will only be told to the p54_assign_address, so that following + * frames won't be placed into the allegedly empty area. + */ + txinfo = IEEE80211_SKB_CB(skb); + p54info = (void *) txinfo->rate_driver_data; + p54info->extra_len = sizeof(struct p54_statistics); + p54_tx(priv, skb); return 0; } -- cgit v1.2.3-18-g5258 From 02c06e4abc0680afd31bf481a803541556757fb6 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 17 Jul 2009 09:30:14 -0700 Subject: iwlagn: modify digital SVR for 1000 On 1000, there are two Switching Voltage Regulators (SVR). The first one apply digital voltage level (1.32V) for PCIe block and core. We need to use this regulator to solve a stability issue related to noisy DC2DC line in the silicon. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 7 +++++++ drivers/net/wireless/iwlwifi/iwl-prph.h | 5 ++++- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 85e8bac499a..3f9da6e4710 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -239,6 +239,13 @@ static void iwl5000_nic_config(struct iwl_priv *priv) APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); + if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_1000) { + /* Setting digital SVR for 1000 card to 1.32V */ + iwl_set_bits_mask_prph(priv, APMG_DIGITAL_SVR_REG, + APMG_SVR_DIGITAL_VOLTAGE_1_32, + ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK); + } + spin_unlock_irqrestore(&priv->lock, flags); } diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 3b9cac3fd21..d393e8f0210 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -80,6 +80,8 @@ #define APMG_RFKILL_REG (APMG_BASE + 0x0014) #define APMG_RTC_INT_STT_REG (APMG_BASE + 0x001c) #define APMG_RTC_INT_MSK_REG (APMG_BASE + 0x0020) +#define APMG_DIGITAL_SVR_REG (APMG_BASE + 0x0058) +#define APMG_ANALOG_SVR_REG (APMG_BASE + 0x006C) #define APMG_CLK_VAL_DMA_CLK_RQT (0x00000200) #define APMG_CLK_VAL_BSM_CLK_RQT (0x00000800) @@ -91,7 +93,8 @@ #define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000) #define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */ #define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000) - +#define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */ +#define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060) #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) -- cgit v1.2.3-18-g5258 From 244294e83f7637e31bbf64060301904860a32051 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 17 Jul 2009 09:30:15 -0700 Subject: iwlwifi: fix rx signal quality reporting in dmesg Fix quality incorrectly reported as signal strength value. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 66fe365dd08..fc7edd1d34d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -1065,7 +1065,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, iwl_dbg_report_frame(priv, rx_start, len, header, 1); #endif IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n", - rx_status.signal, rx_status.noise, rx_status.signal, + rx_status.signal, rx_status.noise, rx_status.qual, (unsigned long long)rx_status.mactime); /* -- cgit v1.2.3-18-g5258 From cc0f555d511a5fe9d4519334c8f674a1dbab9e3a Mon Sep 17 00:00:00 2001 From: Jay Sternberg Date: Fri, 17 Jul 2009 09:30:16 -0700 Subject: iwlwifi: Handle new firmware file with ucode build number in header Adding new API version to account for change to ucode file format. New header includes the build number of the ucode. This build number is the SVN revision thus allowing for exact correlation to the code that generated it. The header adds the build number so that older ucode images can also be enhanced to include the build in the future. some cleanup in iwl_read_ucode needed to ensure old header not used and reduce unnecessary references through pointer with the data is already in heap variable. Signed-off-by: Jay Sternberg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 40 +++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-4965.c | 39 ++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-5000.c | 51 ++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-6000.c | 5 +-- drivers/net/wireless/iwlwifi/iwl-agn.c | 55 +++++++++++++++++------------ drivers/net/wireless/iwlwifi/iwl-core.h | 12 +++++++ drivers/net/wireless/iwlwifi/iwl-dev.h | 31 +++++++++++----- drivers/net/wireless/iwlwifi/iwl3945-base.c | 45 ++++++++++++----------- 8 files changed, 224 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 1227ed2960f..14a47c0a158 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2786,11 +2786,50 @@ static int iwl3945_load_bsm(struct iwl_priv *priv) return 0; } +#define IWL3945_UCODE_GET(item) \ +static u32 iwl3945_ucode_get_##item(const struct iwl_ucode_header *ucode,\ + u32 api_ver) \ +{ \ + return le32_to_cpu(ucode->u.v1.item); \ +} + +static u32 iwl3945_ucode_get_header_size(u32 api_ver) +{ + return UCODE_HEADER_SIZE(1); +} +static u32 iwl3945_ucode_get_build(const struct iwl_ucode_header *ucode, + u32 api_ver) +{ + return 0; +} +static u8 *iwl3945_ucode_get_data(const struct iwl_ucode_header *ucode, + u32 api_ver) +{ + return (u8 *) ucode->u.v1.data; +} + +IWL3945_UCODE_GET(inst_size); +IWL3945_UCODE_GET(data_size); +IWL3945_UCODE_GET(init_size); +IWL3945_UCODE_GET(init_data_size); +IWL3945_UCODE_GET(boot_size); + static struct iwl_hcmd_ops iwl3945_hcmd = { .rxon_assoc = iwl3945_send_rxon_assoc, .commit_rxon = iwl3945_commit_rxon, }; +static struct iwl_ucode_ops iwl3945_ucode = { + .get_header_size = iwl3945_ucode_get_header_size, + .get_build = iwl3945_ucode_get_build, + .get_inst_size = iwl3945_ucode_get_inst_size, + .get_data_size = iwl3945_ucode_get_data_size, + .get_init_size = iwl3945_ucode_get_init_size, + .get_init_data_size = iwl3945_ucode_get_init_data_size, + .get_boot_size = iwl3945_ucode_get_boot_size, + .get_data = iwl3945_ucode_get_data, +}; + static struct iwl_lib_ops iwl3945_lib = { .txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl3945_hw_txq_free_tfd, @@ -2831,6 +2870,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { }; static struct iwl_ops iwl3945_ops = { + .ucode = &iwl3945_ucode, .lib = &iwl3945_lib, .hcmd = &iwl3945_hcmd, .utils = &iwl3945_hcmd_utils, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index edbb0bfd8cb..f4eb683aa2d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2221,12 +2221,50 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv) cancel_work_sync(&priv->txpower_work); } +#define IWL4965_UCODE_GET(item) \ +static u32 iwl4965_ucode_get_##item(const struct iwl_ucode_header *ucode,\ + u32 api_ver) \ +{ \ + return le32_to_cpu(ucode->u.v1.item); \ +} + +static u32 iwl4965_ucode_get_header_size(u32 api_ver) +{ + return UCODE_HEADER_SIZE(1); +} +static u32 iwl4965_ucode_get_build(const struct iwl_ucode_header *ucode, + u32 api_ver) +{ + return 0; +} +static u8 *iwl4965_ucode_get_data(const struct iwl_ucode_header *ucode, + u32 api_ver) +{ + return (u8 *) ucode->u.v1.data; +} + +IWL4965_UCODE_GET(inst_size); +IWL4965_UCODE_GET(data_size); +IWL4965_UCODE_GET(init_size); +IWL4965_UCODE_GET(init_data_size); +IWL4965_UCODE_GET(boot_size); + static struct iwl_hcmd_ops iwl4965_hcmd = { .rxon_assoc = iwl4965_send_rxon_assoc, .commit_rxon = iwl_commit_rxon, .set_rxon_chain = iwl_set_rxon_chain, }; +static struct iwl_ucode_ops iwl4965_ucode = { + .get_header_size = iwl4965_ucode_get_header_size, + .get_build = iwl4965_ucode_get_build, + .get_inst_size = iwl4965_ucode_get_inst_size, + .get_data_size = iwl4965_ucode_get_data_size, + .get_init_size = iwl4965_ucode_get_init_size, + .get_init_data_size = iwl4965_ucode_get_init_data_size, + .get_boot_size = iwl4965_ucode_get_boot_size, + .get_data = iwl4965_ucode_get_data, +}; static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { .get_hcmd_size = iwl4965_get_hcmd_size, .build_addsta_hcmd = iwl4965_build_addsta_hcmd, @@ -2287,6 +2325,7 @@ static struct iwl_lib_ops iwl4965_lib = { }; static struct iwl_ops iwl4965_ops = { + .ucode = &iwl4965_ucode, .lib = &iwl4965_lib, .hcmd = &iwl4965_hcmd, .utils = &iwl4965_hcmd_utils, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 3f9da6e4710..74103cfcace 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1456,6 +1456,44 @@ int iwl5000_calc_rssi(struct iwl_priv *priv, return max_rssi - agc - IWL49_RSSI_OFFSET; } +#define IWL5000_UCODE_GET(item) \ +static u32 iwl5000_ucode_get_##item(const struct iwl_ucode_header *ucode,\ + u32 api_ver) \ +{ \ + if (api_ver <= 2) \ + return le32_to_cpu(ucode->u.v1.item); \ + return le32_to_cpu(ucode->u.v2.item); \ +} + +static u32 iwl5000_ucode_get_header_size(u32 api_ver) +{ + if (api_ver <= 2) + return UCODE_HEADER_SIZE(1); + return UCODE_HEADER_SIZE(2); +} + +static u32 iwl5000_ucode_get_build(const struct iwl_ucode_header *ucode, + u32 api_ver) +{ + if (api_ver <= 2) + return 0; + return le32_to_cpu(ucode->u.v2.build); +} + +static u8 *iwl5000_ucode_get_data(const struct iwl_ucode_header *ucode, + u32 api_ver) +{ + if (api_ver <= 2) + return (u8 *) ucode->u.v1.data; + return (u8 *) ucode->u.v2.data; +} + +IWL5000_UCODE_GET(inst_size); +IWL5000_UCODE_GET(data_size); +IWL5000_UCODE_GET(init_size); +IWL5000_UCODE_GET(init_data_size); +IWL5000_UCODE_GET(boot_size); + struct iwl_hcmd_ops iwl5000_hcmd = { .rxon_assoc = iwl5000_send_rxon_assoc, .commit_rxon = iwl_commit_rxon, @@ -1471,6 +1509,17 @@ struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { .calc_rssi = iwl5000_calc_rssi, }; +struct iwl_ucode_ops iwl5000_ucode = { + .get_header_size = iwl5000_ucode_get_header_size, + .get_build = iwl5000_ucode_get_build, + .get_inst_size = iwl5000_ucode_get_inst_size, + .get_data_size = iwl5000_ucode_get_data_size, + .get_init_size = iwl5000_ucode_get_init_size, + .get_init_data_size = iwl5000_ucode_get_init_data_size, + .get_boot_size = iwl5000_ucode_get_boot_size, + .get_data = iwl5000_ucode_get_data, +}; + struct iwl_lib_ops iwl5000_lib = { .set_hw_params = iwl5000_hw_set_hw_params, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, @@ -1572,12 +1621,14 @@ static struct iwl_lib_ops iwl5150_lib = { }; struct iwl_ops iwl5000_ops = { + .ucode = &iwl5000_ucode, .lib = &iwl5000_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl5000_hcmd_utils, }; static struct iwl_ops iwl5150_ops = { + .ucode = &iwl5000_ucode, .lib = &iwl5150_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl5000_hcmd_utils, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index bd438d8acf5..26c5d4a60d1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -46,8 +46,8 @@ #include "iwl-5000-hw.h" /* Highest firmware API version supported */ -#define IWL6000_UCODE_API_MAX 2 -#define IWL6050_UCODE_API_MAX 2 +#define IWL6000_UCODE_API_MAX 3 +#define IWL6050_UCODE_API_MAX 3 /* Lowest firmware API version supported */ #define IWL6000_UCODE_API_MIN 1 @@ -69,6 +69,7 @@ static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = { }; static struct iwl_ops iwl6000_ops = { + .ucode = &iwl5000_ucode, .lib = &iwl5000_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl6000_hcmd_utils, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ad5002211ab..6b874dab412 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1284,7 +1284,7 @@ static void iwl_nic_start(struct iwl_priv *priv) */ static int iwl_read_ucode(struct iwl_priv *priv) { - struct iwl_ucode *ucode; + struct iwl_ucode_header *ucode; int ret = -EINVAL, index; const struct firmware *ucode_raw; const char *name_pre = priv->cfg->fw_name_pre; @@ -1293,7 +1293,8 @@ static int iwl_read_ucode(struct iwl_priv *priv) char buf[25]; u8 *src; size_t len; - u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size; + u32 api_ver, build; + u32 inst_size, data_size, init_size, init_data_size, boot_size; /* Ask kernel firmware_class module to get the boot firmware off disk. * request_firmware() is synchronous, file is in memory on return. */ @@ -1323,23 +1324,26 @@ static int iwl_read_ucode(struct iwl_priv *priv) if (ret < 0) goto error; - /* Make sure that we got at least our header! */ - if (ucode_raw->size < sizeof(*ucode)) { + /* Make sure that we got at least the v1 header! */ + if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) { IWL_ERR(priv, "File size way too small!\n"); ret = -EINVAL; goto err_release; } /* Data from ucode file: header followed by uCode images */ - ucode = (void *)ucode_raw->data; + ucode = (struct iwl_ucode_header *)ucode_raw->data; priv->ucode_ver = le32_to_cpu(ucode->ver); api_ver = IWL_UCODE_API(priv->ucode_ver); - inst_size = le32_to_cpu(ucode->inst_size); - data_size = le32_to_cpu(ucode->data_size); - init_size = le32_to_cpu(ucode->init_size); - init_data_size = le32_to_cpu(ucode->init_data_size); - boot_size = le32_to_cpu(ucode->boot_size); + build = priv->cfg->ops->ucode->get_build(ucode, api_ver); + inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver); + data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver); + init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver); + init_data_size = + priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver); + boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver); + src = priv->cfg->ops->ucode->get_data(ucode, api_ver); /* api_ver should match the api version forming part of the * firmware filename ... but we don't check for that and only rely @@ -1365,6 +1369,9 @@ static int iwl_read_ucode(struct iwl_priv *priv) IWL_UCODE_API(priv->ucode_ver), IWL_UCODE_SERIAL(priv->ucode_ver)); + if (build) + IWL_DEBUG_INFO(priv, "Build %u\n", build); + IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n", priv->ucode_ver); IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n", @@ -1379,12 +1386,14 @@ static int iwl_read_ucode(struct iwl_priv *priv) boot_size); /* Verify size of file vs. image size info in file's header */ - if (ucode_raw->size < sizeof(*ucode) + + if (ucode_raw->size != + priv->cfg->ops->ucode->get_header_size(api_ver) + inst_size + data_size + init_size + init_data_size + boot_size) { - IWL_DEBUG_INFO(priv, "uCode file size %d too small\n", - (int)ucode_raw->size); + IWL_DEBUG_INFO(priv, + "uCode file size %d does not match expected size\n", + (int)ucode_raw->size); ret = -EINVAL; goto err_release; } @@ -1464,42 +1473,42 @@ static int iwl_read_ucode(struct iwl_priv *priv) /* Copy images into buffers for card's bus-master reads ... */ /* Runtime instructions (first block of data in file) */ - src = &ucode->data[0]; - len = priv->ucode_code.len; + len = inst_size; IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", len); memcpy(priv->ucode_code.v_addr, src, len); + src += len; + IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); /* Runtime data (2nd block) * NOTE: Copy into backup buffer will be done in iwl_up() */ - src = &ucode->data[inst_size]; - len = priv->ucode_data.len; + len = data_size; IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", len); memcpy(priv->ucode_data.v_addr, src, len); memcpy(priv->ucode_data_backup.v_addr, src, len); + src += len; /* Initialization instructions (3rd block) */ if (init_size) { - src = &ucode->data[inst_size + data_size]; - len = priv->ucode_init.len; + len = init_size; IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n", len); memcpy(priv->ucode_init.v_addr, src, len); + src += len; } /* Initialization data (4th block) */ if (init_data_size) { - src = &ucode->data[inst_size + data_size + init_size]; - len = priv->ucode_init_data.len; + len = init_data_size; IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n", len); memcpy(priv->ucode_init_data.v_addr, src, len); + src += len; } /* Bootstrap instructions (5th block) */ - src = &ucode->data[inst_size + data_size + init_size + init_data_size]; - len = priv->ucode_boot.len; + len = boot_size; IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len); memcpy(priv->ucode_boot.v_addr, src, len); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 640c4644a16..c844fab95ab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -116,6 +116,17 @@ struct iwl_temp_ops { void (*set_ct_kill)(struct iwl_priv *priv); }; +struct iwl_ucode_ops { + u32 (*get_header_size)(u32); + u32 (*get_build)(const struct iwl_ucode_header *, u32); + u32 (*get_inst_size)(const struct iwl_ucode_header *, u32); + u32 (*get_data_size)(const struct iwl_ucode_header *, u32); + u32 (*get_init_size)(const struct iwl_ucode_header *, u32); + u32 (*get_init_data_size)(const struct iwl_ucode_header *, u32); + u32 (*get_boot_size)(const struct iwl_ucode_header *, u32); + u8 * (*get_data)(const struct iwl_ucode_header *, u32); +}; + struct iwl_lib_ops { /* set hw dependent parameters */ int (*set_hw_params)(struct iwl_priv *priv); @@ -171,6 +182,7 @@ struct iwl_lib_ops { }; struct iwl_ops { + const struct iwl_ucode_ops *ucode; const struct iwl_lib_ops *lib; const struct iwl_hcmd_ops *hcmd; const struct iwl_hcmd_utils_ops *utils; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index b989d5c08d3..f4afd0c3265 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -66,6 +66,7 @@ extern struct iwl_cfg iwl1000_bgn_cfg; /* shared structures from iwl-5000.c */ extern struct iwl_mod_params iwl50_mod_params; extern struct iwl_ops iwl5000_ops; +extern struct iwl_ucode_ops iwl5000_ucode; extern struct iwl_lib_ops iwl5000_lib; extern struct iwl_hcmd_ops iwl5000_hcmd; extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils; @@ -525,15 +526,29 @@ struct fw_desc { }; /* uCode file layout */ -struct iwl_ucode { - __le32 ver; /* major/minor/API/serial */ - __le32 inst_size; /* bytes of runtime instructions */ - __le32 data_size; /* bytes of runtime data */ - __le32 init_size; /* bytes of initialization instructions */ - __le32 init_data_size; /* bytes of initialization data */ - __le32 boot_size; /* bytes of bootstrap instructions */ - u8 data[0]; /* data in same order as "size" elements */ +struct iwl_ucode_header { + __le32 ver; /* major/minor/API/serial */ + union { + struct { + __le32 inst_size; /* bytes of runtime code */ + __le32 data_size; /* bytes of runtime data */ + __le32 init_size; /* bytes of init code */ + __le32 init_data_size; /* bytes of init data */ + __le32 boot_size; /* bytes of bootstrap code */ + u8 data[0]; /* in same order as sizes */ + } v1; + struct { + __le32 build; /* build number */ + __le32 inst_size; /* bytes of runtime code */ + __le32 data_size; /* bytes of runtime data */ + __le32 init_size; /* bytes of init code */ + __le32 init_data_size; /* bytes of init data */ + __le32 boot_size; /* bytes of bootstrap code */ + u8 data[0]; /* in same order as sizes */ + } v2; + } u; }; +#define UCODE_HEADER_SIZE(ver) ((ver) == 1 ? 24 : 28) struct iwl4965_ibss_seq { u8 mac[ETH_ALEN]; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index c9b3ea92714..bd6a067b488 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2041,7 +2041,7 @@ static void iwl3945_nic_start(struct iwl_priv *priv) */ static int iwl3945_read_ucode(struct iwl_priv *priv) { - struct iwl_ucode *ucode; + const struct iwl_ucode_header *ucode; int ret = -EINVAL, index; const struct firmware *ucode_raw; /* firmware file name contains uCode/driver compatibility version */ @@ -2082,22 +2082,24 @@ static int iwl3945_read_ucode(struct iwl_priv *priv) goto error; /* Make sure that we got at least our header! */ - if (ucode_raw->size < sizeof(*ucode)) { + if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) { IWL_ERR(priv, "File size way too small!\n"); ret = -EINVAL; goto err_release; } /* Data from ucode file: header followed by uCode images */ - ucode = (void *)ucode_raw->data; + ucode = (struct iwl_ucode_header *)ucode_raw->data; priv->ucode_ver = le32_to_cpu(ucode->ver); api_ver = IWL_UCODE_API(priv->ucode_ver); - inst_size = le32_to_cpu(ucode->inst_size); - data_size = le32_to_cpu(ucode->data_size); - init_size = le32_to_cpu(ucode->init_size); - init_data_size = le32_to_cpu(ucode->init_data_size); - boot_size = le32_to_cpu(ucode->boot_size); + inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver); + data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver); + init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver); + init_data_size = + priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver); + boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver); + src = priv->cfg->ops->ucode->get_data(ucode, api_ver); /* api_ver should match the api version forming part of the * firmware filename ... but we don't check for that and only rely @@ -2138,12 +2140,13 @@ static int iwl3945_read_ucode(struct iwl_priv *priv) /* Verify size of file vs. image size info in file's header */ - if (ucode_raw->size < sizeof(*ucode) + + if (ucode_raw->size != priv->cfg->ops->ucode->get_header_size(api_ver) + inst_size + data_size + init_size + init_data_size + boot_size) { - IWL_DEBUG_INFO(priv, "uCode file size %zd too small\n", - ucode_raw->size); + IWL_DEBUG_INFO(priv, + "uCode file size %zd does not match expected size\n", + ucode_raw->size); ret = -EINVAL; goto err_release; } @@ -2226,44 +2229,44 @@ static int iwl3945_read_ucode(struct iwl_priv *priv) /* Copy images into buffers for card's bus-master reads ... */ /* Runtime instructions (first block of data in file) */ - src = &ucode->data[0]; - len = priv->ucode_code.len; + len = inst_size; IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %zd\n", len); memcpy(priv->ucode_code.v_addr, src, len); + src += len; + IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); /* Runtime data (2nd block) * NOTE: Copy into backup buffer will be done in iwl3945_up() */ - src = &ucode->data[inst_size]; - len = priv->ucode_data.len; + len = data_size; IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %zd\n", len); memcpy(priv->ucode_data.v_addr, src, len); memcpy(priv->ucode_data_backup.v_addr, src, len); + src += len; /* Initialization instructions (3rd block) */ if (init_size) { - src = &ucode->data[inst_size + data_size]; - len = priv->ucode_init.len; + len = init_size; IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %zd\n", len); memcpy(priv->ucode_init.v_addr, src, len); + src += len; } /* Initialization data (4th block) */ if (init_data_size) { - src = &ucode->data[inst_size + data_size + init_size]; - len = priv->ucode_init_data.len; + len = init_data_size; IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %zd\n", len); memcpy(priv->ucode_init_data.v_addr, src, len); + src += len; } /* Bootstrap instructions (5th block) */ - src = &ucode->data[inst_size + data_size + init_size + init_data_size]; - len = priv->ucode_boot.len; + len = boot_size; IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %zd\n", len); memcpy(priv->ucode_boot.v_addr, src, len); -- cgit v1.2.3-18-g5258 From 5e215169f466e48561e40d1fa142f02e0e44a3d0 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 17 Jul 2009 09:30:17 -0700 Subject: iwlwifi: make led functions generic Led functions are generic for all the devices except 3945, so remove the reference to 4965 Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-led.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 5e64252f80f..36d88a04504 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -104,7 +104,7 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) } /* Set led pattern command */ -static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id, +static int iwl_led_pattern(struct iwl_priv *priv, int led_id, unsigned int idx) { struct iwl_led_cmd led_cmd = { @@ -121,7 +121,7 @@ static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id, } /* Set led register off */ -static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id) +static int iwl_led_on_reg(struct iwl_priv *priv, int led_id) { IWL_DEBUG_LED(priv, "led on %d\n", led_id); iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON); @@ -130,7 +130,7 @@ static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id) #if 0 /* Set led on command */ -static int iwl4965_led_on(struct iwl_priv *priv, int led_id) +static int iwl_led_on(struct iwl_priv *priv, int led_id) { struct iwl_led_cmd led_cmd = { .id = led_id, @@ -142,7 +142,7 @@ static int iwl4965_led_on(struct iwl_priv *priv, int led_id) } /* Set led off command */ -int iwl4965_led_off(struct iwl_priv *priv, int led_id) +int iwl_led_off(struct iwl_priv *priv, int led_id) { struct iwl_led_cmd led_cmd = { .id = led_id, @@ -157,7 +157,7 @@ int iwl4965_led_off(struct iwl_priv *priv, int led_id) /* Set led register off */ -static int iwl4965_led_off_reg(struct iwl_priv *priv, int led_id) +static int iwl_led_off_reg(struct iwl_priv *priv, int led_id) { IWL_DEBUG_LED(priv, "LED Reg off\n"); iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF); @@ -171,7 +171,7 @@ static int iwl_led_associate(struct iwl_priv *priv, int led_id) { IWL_DEBUG_LED(priv, "Associated\n"); priv->allow_blinking = 1; - return iwl4965_led_on_reg(priv, led_id); + return iwl_led_on_reg(priv, led_id); } static int iwl_led_disassociate(struct iwl_priv *priv, int led_id) { @@ -314,7 +314,7 @@ void iwl_leds_background(struct iwl_priv *priv) priv->last_blink_time = 0; if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) { priv->last_blink_rate = IWL_SOLID_BLINK_IDX; - iwl4965_led_pattern(priv, IWL_LED_LINK, + iwl_led_pattern(priv, IWL_LED_LINK, IWL_SOLID_BLINK_IDX); } return; @@ -328,7 +328,7 @@ void iwl_leds_background(struct iwl_priv *priv) /* call only if blink rate change */ if (blink_idx != priv->last_blink_rate) - iwl4965_led_pattern(priv, IWL_LED_LINK, blink_idx); + iwl_led_pattern(priv, IWL_LED_LINK, blink_idx); priv->last_blink_time = jiffies; priv->last_blink_rate = blink_idx; @@ -351,8 +351,8 @@ int iwl_leds_register(struct iwl_priv *priv) sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio", wiphy_name(priv->hw->wiphy)); - priv->led[IWL_LED_TRG_RADIO].led_on = iwl4965_led_on_reg; - priv->led[IWL_LED_TRG_RADIO].led_off = iwl4965_led_off_reg; + priv->led[IWL_LED_TRG_RADIO].led_on = iwl_led_on_reg; + priv->led[IWL_LED_TRG_RADIO].led_off = iwl_led_off_reg; priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL; ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RADIO], @@ -386,7 +386,7 @@ int iwl_leds_register(struct iwl_priv *priv) priv->led[IWL_LED_TRG_RX].led_on = iwl_led_associated; priv->led[IWL_LED_TRG_RX].led_off = iwl_led_associated; - priv->led[IWL_LED_TRG_RX].led_pattern = iwl4965_led_pattern; + priv->led[IWL_LED_TRG_RX].led_pattern = iwl_led_pattern; if (ret) goto exit_fail; @@ -401,7 +401,7 @@ int iwl_leds_register(struct iwl_priv *priv) priv->led[IWL_LED_TRG_TX].led_on = iwl_led_associated; priv->led[IWL_LED_TRG_TX].led_off = iwl_led_associated; - priv->led[IWL_LED_TRG_TX].led_pattern = iwl4965_led_pattern; + priv->led[IWL_LED_TRG_TX].led_pattern = iwl_led_pattern; if (ret) goto exit_fail; -- cgit v1.2.3-18-g5258 From 2d1bb9e58c2b13df13741d1efe1129cf1098405d Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 17 Jul 2009 09:30:18 -0700 Subject: iwlagn: do not send key clear commands when rfkill enabled Do all key clearing except sending sommands to device when rfkill enabled. When rfkill enabled the interface is brought down and will be brought back up correctly after rfkill is enabled again. Same change is not needed for iwl3945 as it ignores return code when sending key clearing command to device. This fixes http://bugzilla.kernel.org/show_bug.cgi?id=13742 Signed-off-by: Reinette Chatre Tested-by: Frans Pop Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-sta.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index afa1633602a..7fd806d33a6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -566,6 +566,8 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv, unsigned long flags; spin_lock_irqsave(&priv->sta_lock, flags); + IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n", + keyconf->keyidx); if (!test_and_clear_bit(keyconf->keyidx, &priv->ucode_key_table)) IWL_ERR(priv, "index %d not used in uCode key table.\n", @@ -573,6 +575,11 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv, priv->default_wep_key--; memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0])); + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n"); + spin_unlock_irqrestore(&priv->sta_lock, flags); + return 0; + } ret = iwl_send_static_wepkey_cmd(priv, 1); IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n", keyconf->keyidx, ret); @@ -853,6 +860,11 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_WEP(priv, "Not sending REPLY_ADD_STA command because RFKILL enabled. \n"); + spin_unlock_irqrestore(&priv->sta_lock, flags); + return 0; + } ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); spin_unlock_irqrestore(&priv->sta_lock, flags); return ret; -- cgit v1.2.3-18-g5258 From a283c0116b0cc5e82327e50ad4d05f6d4d42c603 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 17 Jul 2009 09:30:19 -0700 Subject: iwlwifi: add led debugfs function Adding debugfs file to show current led blinking rate /sys/kernel/debug/ieee80211/phy0/iwlagn/data/led Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debug.h | 3 +++ drivers/net/wireless/iwlwifi/iwl-debugfs.c | 36 ++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 1555676fc51..e4a4dbd20c9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -83,6 +83,9 @@ struct iwl_debugfs { struct dentry *file_status; struct dentry *file_interrupt; struct dentry *file_qos; +#ifdef CONFIG_IWLWIFI_LEDS + struct dentry *file_led; +#endif } dbgfs_data_files; struct dir_rf_files { struct dentry *file_disable_sensitivity; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 0b9e824b67c..0ab3463aa07 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -591,6 +591,33 @@ static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf, return ret; } +#ifdef CONFIG_IWLWIFI_LEDS +static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char buf[256]; + const size_t bufsz = sizeof(buf); + ssize_t ret; + + pos += scnprintf(buf + pos, bufsz - pos, + "allow blinking: %s\n", + (priv->allow_blinking) ? "True" : "False"); + if (priv->allow_blinking) { + pos += scnprintf(buf + pos, bufsz - pos, + "Led blinking rate: %u\n", + priv->last_blink_rate); + pos += scnprintf(buf + pos, bufsz - pos, + "Last blink time: %lu\n", + priv->last_blink_time); + } + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + return ret; +} +#endif + DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_WRITE_FILE_OPS(log_event); DEBUGFS_READ_FILE_OPS(nvm); @@ -601,6 +628,9 @@ DEBUGFS_READ_FILE_OPS(channels); DEBUGFS_READ_FILE_OPS(status); DEBUGFS_READ_WRITE_FILE_OPS(interrupt); DEBUGFS_READ_FILE_OPS(qos); +#ifdef CONFIG_IWLWIFI_LEDS +DEBUGFS_READ_FILE_OPS(led); +#endif /* * Create the debugfs files and directories @@ -638,6 +668,9 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(status, data); DEBUGFS_ADD_FILE(interrupt, data); DEBUGFS_ADD_FILE(qos, data); +#ifdef CONFIG_IWLWIFI_LEDS + DEBUGFS_ADD_FILE(led, data); +#endif DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); @@ -673,6 +706,9 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_qos); +#ifdef CONFIG_IWLWIFI_LEDS + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led); +#endif DEBUGFS_REMOVE(priv->dbgfs->dir_data); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); -- cgit v1.2.3-18-g5258 From e5108d075c705ed3336163d9ead2b8fe629f680d Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 17 Jul 2009 09:30:20 -0700 Subject: iwlwifi: Led blinking counting both tx and rx For controlling led blinking, counting both tx and rx data traffic; this will be able to handle traffic in either direction Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-led.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 36d88a04504..8c8115293b3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -54,7 +54,7 @@ static const char *led_type_str[] = { static const struct { - u16 tpt; + u16 tpt; /* Mb/s */ u8 on_time; u8 off_time; } blink_tbl[] = @@ -264,13 +264,15 @@ static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led, /* - * calculate blink rate according to last 2 sec Tx/Rx activities + * calculate blink rate according to last second Tx/Rx activities */ static int iwl_get_blink_rate(struct iwl_priv *priv) { int i; - u64 current_tpt = priv->tx_stats[2].bytes; - /* FIXME: + priv->rx_stats[2].bytes; */ + /* count both tx and rx traffic to be able to + * handle traffic in either direction + */ + u64 current_tpt = priv->tx_stats[2].bytes + priv->rx_stats[2].bytes; s64 tpt = current_tpt - priv->led_tpt; if (tpt < 0) /* wraparound */ -- cgit v1.2.3-18-g5258 From b23a0524a38b146f85be44ae0d71abd2a710f4ab Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 17 Jul 2009 09:30:21 -0700 Subject: iwlwifi: checking unknown HW type When deciding NVM type, if the HW type is unknown, report error and exit with -ENOENT. This check should prevent incorrect behavior by assuming the wrong NVM type. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 7d7554a2f34..51eed722666 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -159,6 +159,9 @@ static int iwlcore_get_nvm_type(struct iwl_priv *priv) /* OTP only valid for CP/PP and after */ switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { + case CSR_HW_REV_TYPE_NONE: + IWL_ERR(priv, "Unknown hardware type\n"); + return -ENOENT; case CSR_HW_REV_TYPE_3945: case CSR_HW_REV_TYPE_4965: case CSR_HW_REV_TYPE_5300: @@ -266,7 +269,8 @@ int iwl_eeprom_init(struct iwl_priv *priv) u32 otpgp; priv->nvm_device_type = iwlcore_get_nvm_type(priv); - + if (priv->nvm_device_type == -ENOENT) + return -ENOENT; /* allocate eeprom */ if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) priv->cfg->eeprom_size = -- cgit v1.2.3-18-g5258 From cce53aa347c1e023d967b1cb1aa393c725aedba5 Mon Sep 17 00:00:00 2001 From: Jay Sternberg Date: Fri, 17 Jul 2009 09:30:22 -0700 Subject: iwlwifi: update 1000 series API version to match firmware firmware file now contains build number so API needs to be updated. Signed-off-by: Jay Sternberg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 7da52f1cc1d..a899be914eb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -46,7 +46,7 @@ #include "iwl-5000-hw.h" /* Highest firmware API version supported */ -#define IWL1000_UCODE_API_MAX 2 +#define IWL1000_UCODE_API_MAX 3 /* Lowest firmware API version supported */ #define IWL1000_UCODE_API_MIN 1 -- cgit v1.2.3-18-g5258 From 34a66de628b5dcc4a93129610ccd24814935e8cd Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 17 Jul 2009 09:30:23 -0700 Subject: iwlwifi: uCode Alive notification with timeout Wait for REPLY_ALIVE notification from init and runtime uCode. based on the type of REPLY_ALIVE, different status bit will be set to wake up the queue: STATUS_INIT_UCODE_ALIVE for init uCode STATUS_RT_UCODE_ALIVE for runtime uCode. If timeout, attempt to download the failing uCode image again. This can only be done for the init ucode images of all iwlagn devices and the runtime ucode image of the 5000 series and up. If there is a problem with the 4965 runtime ucode coming up we restart the interface and thus trigger a new download of the init ucode also. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 26 ++++++++++++++++- drivers/net/wireless/iwlwifi/iwl-agn.c | 50 +++++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.c | 39 +++++++++++++++++++------ drivers/net/wireless/iwlwifi/iwl-core.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-dev.h | 2 ++ 5 files changed, 109 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index f4eb683aa2d..272409c8061 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -146,7 +146,7 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "Begin load bsm\n"); - priv->ucode_type = UCODE_RT; + priv->ucode_type = UCODE_INIT; /* make sure bootstrap program is no larger than BSM's SRAM size */ if (len > IWL49_MAX_BSM_SIZE) @@ -256,6 +256,8 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) */ static void iwl4965_init_alive_start(struct iwl_priv *priv) { + int ret; + /* Check alive response for "valid" sign from uCode */ if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { /* We had an error bringing up the hardware, so take it @@ -287,6 +289,28 @@ static void iwl4965_init_alive_start(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "Couldn't set up uCode pointers.\n"); goto restart; } + priv->ucode_type = UCODE_RT; + if (test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) { + IWL_WARN(priv, "Runtime uCode already alive? " + "Waiting for alive anyway\n"); + clear_bit(STATUS_RT_UCODE_ALIVE, &priv->status); + } + ret = wait_event_interruptible_timeout( + priv->wait_command_queue, + test_bit(STATUS_RT_UCODE_ALIVE, &priv->status), + UCODE_ALIVE_TIMEOUT); + if (!ret) { + /* FIXME: if STATUS_RT_UCODE_ALIVE timeout + * go back to restart the download Init uCode again + * this might cause to trap in the restart loop + */ + priv->ucode_type = UCODE_NONE; + if (!test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) { + IWL_ERR(priv, "Runtime timeout after %dms\n", + jiffies_to_msecs(UCODE_ALIVE_TIMEOUT)); + goto restart; + } + } return; restart: diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6b874dab412..f61f653a1b7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -533,12 +533,16 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv, if (palive->ver_subtype == INITIALIZE_SUBTYPE) { IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); + set_bit(STATUS_INIT_UCODE_ALIVE, &priv->status); + wake_up_interruptible(&priv->wait_command_queue); memcpy(&priv->card_alive_init, &pkt->u.alive_frame, sizeof(struct iwl_init_alive_resp)); pwork = &priv->init_alive_start; } else { IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); + set_bit(STATUS_RT_UCODE_ALIVE, &priv->status); + wake_up_interruptible(&priv->wait_command_queue); memcpy(&priv->card_alive, &pkt->u.alive_frame, sizeof(struct iwl_alive_resp)); pwork = &priv->alive_start; @@ -1782,6 +1786,7 @@ static int __iwl_up(struct iwl_priv *priv) { int i; int ret; + unsigned long status; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { IWL_WARN(priv, "Exit pending; will not bring the NIC up\n"); @@ -1859,6 +1864,51 @@ static int __iwl_up(struct iwl_priv *priv) /* start card; "initialize" will load runtime ucode */ iwl_nic_start(priv); + /* Just finish download Init or Runtime uCode image to device + * now we wait here for uCode send REPLY_ALIVE notification + * to indicate uCode is ready. + * 1) For Init uCode image, all iwlagn devices should wait here + * on STATUS_INIT_UCODE_ALIVE status bit; if timeout before + * receive the REPLY_ALIVE notification, go back and try to + * download the Init uCode image again. + * 2) For Runtime uCode image, all iwlagn devices except 4965 + * wait here on STATUS_RT_UCODE_ALIVE status bit; if + * timeout before receive the REPLY_ALIVE notification, go back + * and download the Runtime uCode image again. + * 3) For 4965 Runtime uCode, it will not go through this path, + * need to wait for STATUS_RT_UCODE_ALIVE status bit in + * iwl4965_init_alive_start() function; if timeout, need to + * restart and download Init uCode image. + */ + if (priv->ucode_type == UCODE_INIT) + status = STATUS_INIT_UCODE_ALIVE; + else + status = STATUS_RT_UCODE_ALIVE; + if (test_bit(status, &priv->status)) { + IWL_WARN(priv, + "%s uCode already alive? " + "Waiting for alive anyway\n", + (status == STATUS_INIT_UCODE_ALIVE) + ? "INIT" : "Runtime"); + clear_bit(status, &priv->status); + } + ret = wait_event_interruptible_timeout( + priv->wait_command_queue, + test_bit(status, &priv->status), + UCODE_ALIVE_TIMEOUT); + if (!ret) { + if (!test_bit(status, &priv->status)) { + priv->ucode_type = + (status == STATUS_INIT_UCODE_ALIVE) + ? UCODE_NONE : UCODE_INIT; + IWL_ERR(priv, + "%s timeout after %dms\n", + (status == STATUS_INIT_UCODE_ALIVE) + ? "INIT" : "Runtime", + jiffies_to_msecs(UCODE_ALIVE_TIMEOUT)); + continue; + } + } IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n"); return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index b82480a5178..8655e092fca 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1341,10 +1341,17 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv) u32 desc, time, count, base, data1; u32 blink1, blink2, ilink1, ilink2; - if (priv->ucode_type == UCODE_INIT) - base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); - else + switch (priv->ucode_type) { + case UCODE_RT: base = le32_to_cpu(priv->card_alive.error_event_table_ptr); + break; + case UCODE_INIT: + base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); + break; + default: + IWL_ERR(priv, "uCode image not available\n"); + return; + } if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base); @@ -1396,10 +1403,17 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, if (num_events == 0) return; - if (priv->ucode_type == UCODE_INIT) - base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); - else + switch (priv->ucode_type) { + case UCODE_RT: base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + break; + case UCODE_INIT: + base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); + break; + default: + IWL_ERR(priv, "uCode image not available\n"); + return; + } if (mode == 0) event_size = 2 * sizeof(u32); @@ -1436,10 +1450,17 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) u32 next_entry; /* index of next entry to be written by uCode */ u32 size; /* # entries that we'll print */ - if (priv->ucode_type == UCODE_INIT) - base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); - else + switch (priv->ucode_type) { + case UCODE_RT: base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + break; + case UCODE_INIT: + base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); + break; + default: + IWL_ERR(priv, "uCode image not available\n"); + return; + } if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index c844fab95ab..a697b843863 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -512,6 +512,8 @@ void iwlcore_free_geos(struct iwl_priv *priv); #define STATUS_POWER_PMI 16 #define STATUS_FW_ERROR 17 #define STATUS_MODE_PENDING 18 +#define STATUS_INIT_UCODE_ALIVE 19 +#define STATUS_RT_UCODE_ALIVE 20 static inline int iwl_is_ready(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index f4afd0c3265..926df3ae241 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -772,6 +772,8 @@ struct iwl_calib_result { size_t buf_len; }; +#define UCODE_ALIVE_TIMEOUT (5 * HZ) + enum ucode_type { UCODE_NONE = 0, UCODE_INIT, -- cgit v1.2.3-18-g5258 From a562a9dda7f47e7cac58d80bf1ffe441feca510e Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 17 Jul 2009 09:30:24 -0700 Subject: iwlwifi: make debug level more user friendly * Deprecate the "debug50" module parameter used to obtain 5000 series and up debugging. Replace it with "debug" module parameter to match with original driver and be consistent between them. The "debug50" module parameter can still be used, except that the module parameter is not writable in keeping with its previous state. We currently just mark it as "deprecated" and do not have it in the feature-removal-schedule. Some more cleanup of module parameters needs to be done and can then be entered together. * Only make "debug" module parameters visible if the driver is compiled with CONFIG_IWLWIFI_DEBUG. This will eliminate a lot of confusion where users think they have set debug flags but yet cannot see any debug output. * Make module parameters writable. This eliminates the need for the "debug_level" sysfs file, which can now also be deprecated and added to feature-removal-schedule. This file is in significant use though with many iwlwifi documents and text referring users to it. We can thus not take its removal lightly and keep it around. With iwlcore shared between iwlagn and iwl3945 we really do not need debug module parameters for each but can instead have one debug module parameter for the iwlcore module. The same issue is here as with the sysfs file - a lot of iwlwifi documentation and text (like bug reports) rely on iwlagn and iwl3945 having this module parameter, so changing this to a module parameter of iwlcore will have significant impact and we do not do this for that reason. One consequence of this patch is that if a user is running a system with both 3945 and later hardware then the setting of the one module parameter will affect the value of the other. The likelihood of this seems low - and even if this setup is present it does not seem like an issue for both modules to run with the same debug level. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 -- drivers/net/wireless/iwlwifi/iwl-5000.c | 2 -- drivers/net/wireless/iwlwifi/iwl-agn.c | 31 +++++++++++++++++++---------- drivers/net/wireless/iwlwifi/iwl-core.c | 11 ++++++---- drivers/net/wireless/iwlwifi/iwl-core.h | 1 - drivers/net/wireless/iwlwifi/iwl-debug.h | 12 +++++------ drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - drivers/net/wireless/iwlwifi/iwl-rx.c | 6 +++--- drivers/net/wireless/iwlwifi/iwl-sta.c | 2 +- drivers/net/wireless/iwlwifi/iwl-tx.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 25 +++++++++++++---------- 12 files changed, 55 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 14a47c0a158..8ee403cd9b9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -502,14 +502,14 @@ static void _iwl3945_dbg_report_frame(struct iwl_priv *priv, } } if (print_dump) - iwl_print_hex_dump(priv, IWL_DL_RX, data, length); + iwl_print_hex_dump(IWL_DL_RX, data, length); } static void iwl3945_dbg_report_frame(struct iwl_priv *priv, struct iwl_rx_packet *pkt, struct ieee80211_hdr *header, int group100) { - if (priv->debug_level & IWL_DL_RX) + if (iwl_debug_level & IWL_DL_RX) _iwl3945_dbg_report_frame(priv, pkt, header, group100); } diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 272409c8061..c30a1b96057 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2376,8 +2376,6 @@ module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444); MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); -module_param_named(debug, iwl4965_mod_params.debug, uint, 0444); -MODULE_PARM_DESC(debug, "debug output mask"); module_param_named( disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444); MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 74103cfcace..702db07fa38 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1745,8 +1745,6 @@ MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX)); module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444); MODULE_PARM_DESC(swcrypto50, "using software crypto engine (default 0 [hardware])\n"); -module_param_named(debug50, iwl50_mod_params.debug, uint, 0444); -MODULE_PARM_DESC(debug50, "50XX debug output mask"); module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444); MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series"); module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index f61f653a1b7..ff4a546f1e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -904,7 +904,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); #ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & IWL_DL_ISR) { + if (iwl_debug_level & IWL_DL_ISR) { /* just for debug */ inta_mask = iwl_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", @@ -939,7 +939,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) } #ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & (IWL_DL_ISR)) { + if (iwl_debug_level & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ if (inta & CSR_INT_BIT_SCD) { IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " @@ -1053,7 +1053,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) iwl_enable_interrupts(priv); #ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & (IWL_DL_ISR)) { + if (iwl_debug_level & (IWL_DL_ISR)) { inta = iwl_read32(priv, CSR_INT); inta_mask = iwl_read32(priv, CSR_INT_MASK); inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); @@ -1084,7 +1084,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) inta = priv->inta; #ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & IWL_DL_ISR) { + if (iwl_debug_level & IWL_DL_ISR) { /* just for debug */ inta_mask = iwl_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ", @@ -1112,7 +1112,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) } #ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & (IWL_DL_ISR)) { + if (iwl_debug_level & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ if (inta & CSR_INT_BIT_SCD) { IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " @@ -2456,14 +2456,16 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw, * used for controlling the debug level. * * See the level definitions in iwl for details. + * + * FIXME This file can be deprecated as the module parameter is + * writable and users can thus also change the debug level + * using the /sys/module/iwl3945/parameters/debug file. */ static ssize_t show_debug_level(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = dev_get_drvdata(d); - - return sprintf(buf, "0x%08X\n", priv->debug_level); + return sprintf(buf, "0x%08X\n", iwl_debug_level); } static ssize_t store_debug_level(struct device *d, struct device_attribute *attr, @@ -2477,7 +2479,7 @@ static ssize_t store_debug_level(struct device *d, if (ret) IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf); else - priv->debug_level = val; + iwl_debug_level = val; return strnlen(buf, count); } @@ -2829,7 +2831,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Disabling hardware scan means that mac80211 will perform scans * "the hard way", rather than using device's scan. */ if (cfg->mod_params->disable_hw_scan) { - if (cfg->mod_params->debug & IWL_DL_INFO) + if (iwl_debug_level & IWL_DL_INFO) dev_printk(KERN_DEBUG, &(pdev->dev), "Disabling hw_scan\n"); iwl_hw_ops.hw_scan = NULL; @@ -2851,7 +2853,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv->inta_mask = CSR_INI_SET_MASK; #ifdef CONFIG_IWLWIFI_DEBUG - priv->debug_level = priv->cfg->mod_params->debug; atomic_set(&priv->restrict_refcnt, 0); #endif @@ -3211,3 +3212,11 @@ static void __exit iwl_exit(void) module_exit(iwl_exit); module_init(iwl_init); + +#ifdef CONFIG_IWLWIFI_DEBUG +module_param_named(debug50, iwl_debug_level, uint, 0444); +MODULE_PARM_DESC(debug50, "50XX debug output mask (deprecated)"); +module_param_named(debug, iwl_debug_level, uint, 0644); +MODULE_PARM_DESC(debug, "debug output mask"); +#endif + diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 8655e092fca..976004f6c7d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -59,6 +59,9 @@ MODULE_LICENSE("GPL"); IWL_RATE_##pp##M_INDEX, \ IWL_RATE_##np##M_INDEX } +u32 iwl_debug_level; +EXPORT_SYMBOL(iwl_debug_level); + static irqreturn_t iwl_isr(int irq, void *data); /* @@ -1275,7 +1278,7 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv) struct iwl_rxon_cmd *rxon = &priv->staging_rxon; IWL_DEBUG_RADIO(priv, "RX CONFIG:\n"); - iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); + iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n", @@ -1505,7 +1508,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv) clear_bit(STATUS_HCMD_ACTIVE, &priv->status); #ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & IWL_DL_FW_ERRORS) { + if (iwl_debug_level & IWL_DL_FW_ERRORS) { iwl_dump_nic_error_log(priv); iwl_dump_nic_event_log(priv); iwl_print_rx_config_cmd(priv); @@ -2004,7 +2007,7 @@ static irqreturn_t iwl_isr(int irq, void *data) } #ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & (IWL_DL_ISR)) { + if (iwl_debug_level & (IWL_DL_ISR)) { inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, " "fh 0x%08x\n", inta, inta_mask, inta_fh); @@ -2311,7 +2314,7 @@ void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " "notification for %s:\n", le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); - iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); + iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); } EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a697b843863..f82ec9e4da0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -190,7 +190,6 @@ struct iwl_ops { struct iwl_mod_params { int sw_crypto; /* def: 0 = using hardware encryption */ - u32 debug; /* def: 0 = minimal debug log messages */ int disable_hw_scan; /* def: 0 = use h/w scan */ int num_of_queues; /* def: HW dependent */ int num_of_ampdu_queues;/* def: HW dependent */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index e4a4dbd20c9..9faf0c2ff60 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -30,6 +30,7 @@ #define __iwl_debug_h__ struct iwl_priv; +extern u32 iwl_debug_level; #define IWL_ERR(p, f, a...) dev_err(&((p)->pci_dev->dev), f, ## a) #define IWL_WARN(p, f, a...) dev_warn(&((p)->pci_dev->dev), f, ## a) @@ -45,7 +46,7 @@ do { \ #ifdef CONFIG_IWLWIFI_DEBUG #define IWL_DEBUG(__priv, level, fmt, args...) \ do { \ - if (__priv->debug_level & (level)) \ + if (iwl_debug_level & (level)) \ dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \ "%c %s " fmt, in_interrupt() ? 'I' : 'U', \ __func__ , ## args); \ @@ -53,15 +54,15 @@ do { \ #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) \ do { \ - if ((__priv->debug_level & (level)) && net_ratelimit()) \ + if ((iwl_debug_level & (level)) && net_ratelimit()) \ dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \ "%c %s " fmt, in_interrupt() ? 'I' : 'U', \ __func__ , ## args); \ } while (0) -#define iwl_print_hex_dump(priv, level, p, len) \ +#define iwl_print_hex_dump(level, p, len) \ do { \ - if (priv->debug_level & level) \ + if (iwl_debug_level & level) \ print_hex_dump(KERN_DEBUG, "iwl data: ", \ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ } while (0) @@ -103,8 +104,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv); #else #define IWL_DEBUG(__priv, level, fmt, args...) #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) -static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, - void *p, u32 len) +static inline void iwl_print_hex_dump(int level, void *p, u32 len) {} #endif /* CONFIG_IWLWIFI_DEBUG */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 926df3ae241..0751891f4ab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1111,7 +1111,6 @@ struct iwl_priv { #ifdef CONFIG_IWLWIFI_DEBUG /* debugging info */ - u32 debug_level; u32 framecnt_to_us; atomic_t restrict_refcnt; #ifdef CONFIG_IWLWIFI_DEBUGFS diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index fc7edd1d34d..5d5f2153f44 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -646,7 +646,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, u32 tsf_low; int rssi; - if (likely(!(priv->debug_level & IWL_DL_RX))) + if (likely(!(iwl_debug_level & IWL_DL_RX))) return; /* MAC header */ @@ -742,7 +742,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, } } if (print_dump) - iwl_print_hex_dump(priv, IWL_DL_RX, header, length); + iwl_print_hex_dump(IWL_DL_RX, header, length); } #endif @@ -1061,7 +1061,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, /* Set "1" to report good data frames in groups of 100 */ #ifdef CONFIG_IWLWIFI_DEBUG - if (unlikely(priv->debug_level & IWL_DL_RX)) + if (unlikely(iwl_debug_level & IWL_DL_RX)) iwl_dbg_report_frame(priv, rx_start, len, header, 1); #endif IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 7fd806d33a6..cbe4e26d053 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1093,7 +1093,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) IWL_DEBUG_DROP(priv, "Station %pM not in station map. " "Defaulting to broadcast...\n", hdr->addr1); - iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); + iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_params.bcast_sta_id; default: diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 7073069a61a..ef7e6bdb067 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -869,8 +869,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n", le16_to_cpu(out_cmd->hdr.sequence)); IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags)); - iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); - iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); + iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); + iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); /* Set up entry for this TFD in Tx byte-count array */ if (info->flags & IEEE80211_TX_CTL_AMPDU) diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index bd6a067b488..221a875b016 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -612,8 +612,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n", le16_to_cpu(out_cmd->hdr.sequence)); IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx->tx_flags)); - iwl_print_hex_dump(priv, IWL_DL_TX, tx, sizeof(*tx)); - iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx->hdr, + iwl_print_hex_dump(IWL_DL_TX, tx, sizeof(*tx)); + iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx->hdr, ieee80211_hdrlen(fc)); /* @@ -1644,7 +1644,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); #ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & IWL_DL_ISR) { + if (iwl_debug_level & IWL_DL_ISR) { /* just for debug */ inta_mask = iwl_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", @@ -1679,7 +1679,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) } #ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & (IWL_DL_ISR)) { + if (iwl_debug_level & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ if (inta & CSR_INT_BIT_SCD) { IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " @@ -1758,7 +1758,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) iwl_enable_interrupts(priv); #ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & (IWL_DL_ISR)) { + if (iwl_debug_level & (IWL_DL_ISR)) { inta = iwl_read32(priv, CSR_INT); inta_mask = iwl_read32(priv, CSR_INT_MASK); inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); @@ -3308,13 +3308,15 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, * used for controlling the debug level. * * See the level definitions in iwl for details. + * + * FIXME This file can be deprecated as the module parameter is + * writable and users can thus also change the debug level + * using the /sys/module/iwl3945/parameters/debug file. */ static ssize_t show_debug_level(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = dev_get_drvdata(d); - - return sprintf(buf, "0x%08X\n", priv->debug_level); + return sprintf(buf, "0x%08X\n", iwl_debug_level); } static ssize_t store_debug_level(struct device *d, struct device_attribute *attr, @@ -3328,7 +3330,7 @@ static ssize_t store_debug_level(struct device *d, if (ret) IWL_INFO(priv, "%s is not in hex or decimal form.\n", buf); else - priv->debug_level = val; + iwl_debug_level = val; return strnlen(buf, count); } @@ -3966,7 +3968,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->inta_mask = CSR_INI_SET_MASK; #ifdef CONFIG_IWLWIFI_DEBUG - priv->debug_level = iwl3945_mod_params.debug; atomic_set(&priv->restrict_refcnt, 0); #endif @@ -4262,8 +4263,10 @@ MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, 0444); MODULE_PARM_DESC(swcrypto, "using software crypto (default 1 [software])\n"); -module_param_named(debug, iwl3945_mod_params.debug, uint, 0444); +#ifdef CONFIG_IWLWIFI_DEBUG +module_param_named(debug, iwl_debug_level, uint, 0644); MODULE_PARM_DESC(debug, "debug output mask"); +#endif module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, int, 0444); MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, 0444); -- cgit v1.2.3-18-g5258 From 58dba728b1b727cb3d95a1f76ca4e88a1e628ee1 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 17 Jul 2009 09:30:25 -0700 Subject: iwlwifi: clarify hardware error message When a hardware error is detected we need to be clear about that and not create impression that the microcode is able to deal with it. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ff4a546f1e6..b7ac4ee794c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -923,7 +923,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) /* Now service all interrupt bits discovered above. */ if (inta & CSR_INT_BIT_HW_ERR) { - IWL_ERR(priv, "Microcode HW error detected. Restarting.\n"); + IWL_ERR(priv, "Hardware error detected. Restarting.\n"); /* Tell the device to stop sending interrupts */ iwl_disable_interrupts(priv); @@ -1096,7 +1096,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) /* Now service all interrupt bits discovered above. */ if (inta & CSR_INT_BIT_HW_ERR) { - IWL_ERR(priv, "Microcode HW error detected. Restarting.\n"); + IWL_ERR(priv, "Hardware error detected. Restarting.\n"); /* Tell the device to stop sending interrupts */ iwl_disable_interrupts(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 221a875b016..8891d6e3a0f 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1663,7 +1663,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) /* Now service all interrupt bits discovered above. */ if (inta & CSR_INT_BIT_HW_ERR) { - IWL_ERR(priv, "Microcode HW error detected. Restarting.\n"); + IWL_ERR(priv, "Hardware error detected. Restarting.\n"); /* Tell the device to stop sending interrupts */ iwl_disable_interrupts(priv); -- cgit v1.2.3-18-g5258 From 4c423a2b0cc3c85137988962e6ba3f01baef0b4e Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 17 Jul 2009 09:30:26 -0700 Subject: iwlwifi: inform user about rfkill state changes rfkill state changes are mostly available through debug messages. These are significant enough to always make user aware of so we turn them into warnings. Also insert a missing newline in some rfkill related debug message. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-tx.c | 2 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b7ac4ee794c..44c7f236a7a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -964,7 +964,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) hw_rf_kill = 1; - IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n", + IWL_WARN(priv, "RF_KILL bit toggled to %s.\n", hw_rf_kill ? "disable radio" : "enable radio"); priv->isr_stats.rfkill++; @@ -1137,7 +1137,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) hw_rf_kill = 1; - IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n", + IWL_WARN(priv, "RF_KILL bit toggled to %s.\n", hw_rf_kill ? "disable radio" : "enable radio"); priv->isr_stats.rfkill++; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index ef7e6bdb067..0912987af60 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -940,7 +940,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) !(cmd->meta.flags & CMD_SIZE_HUGE)); if (iwl_is_rfkill(priv)) { - IWL_DEBUG_INFO(priv, "Not sending command - RF KILL"); + IWL_DEBUG_INFO(priv, "Not sending command - RF KILL\n"); return -EIO; } diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 8891d6e3a0f..2cc7e30d774 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -926,7 +926,7 @@ static void iwl3945_rx_card_state_notif(struct iwl_priv *priv, u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); unsigned long status = priv->status; - IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n", + IWL_WARN(priv, "Card state received: HW:%s SW:%s\n", (flags & HW_CARD_DISABLED) ? "Kill" : "On", (flags & SW_CARD_DISABLED) ? "Kill" : "On"); -- cgit v1.2.3-18-g5258 From 30a12a8fbbd530b016277dd2ab65246b516540a8 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 17 Jul 2009 09:30:27 -0700 Subject: iwlwifi: change iwl_enable/disable_interrupts to "inline" iwl_enable_interrupts is being called inside the interrupt, change from function call to inline Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 25 ------------------------- drivers/net/wireless/iwlwifi/iwl-core.h | 2 -- drivers/net/wireless/iwlwifi/iwl-helpers.h | 21 +++++++++++++++++++++ 3 files changed, 21 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 976004f6c7d..6aea0264480 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1749,31 +1749,6 @@ void iwl_uninit_drv(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_uninit_drv); - -void iwl_disable_interrupts(struct iwl_priv *priv) -{ - clear_bit(STATUS_INT_ENABLED, &priv->status); - - /* disable interrupts from uCode/NIC to host */ - iwl_write32(priv, CSR_INT_MASK, 0x00000000); - - /* acknowledge/clear/reset any interrupts still pending - * from uCode or flow handler (Rx/Tx DMA) */ - iwl_write32(priv, CSR_INT, 0xffffffff); - iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff); - IWL_DEBUG_ISR(priv, "Disabled interrupts\n"); -} -EXPORT_SYMBOL(iwl_disable_interrupts); - -void iwl_enable_interrupts(struct iwl_priv *priv) -{ - IWL_DEBUG_ISR(priv, "Enabling interrupts\n"); - set_bit(STATUS_INT_ENABLED, &priv->status); - iwl_write32(priv, CSR_INT_MASK, priv->inta_mask); -} -EXPORT_SYMBOL(iwl_enable_interrupts); - - #define ICT_COUNT (PAGE_SIZE/sizeof(u32)) /* Free dram table */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index f82ec9e4da0..614ec7cc5b3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -458,8 +458,6 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, /***************************************************** * PCI * *****************************************************/ -void iwl_disable_interrupts(struct iwl_priv *priv); -void iwl_enable_interrupts(struct iwl_priv *priv); irqreturn_t iwl_isr_legacy(int irq, void *data); int iwl_reset_ict(struct iwl_priv *priv); void iwl_disable_ict(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index a1328c3c81a..bd0b12efb5c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -145,4 +145,25 @@ static inline void iwl_stop_queue(struct iwl_priv *priv, u8 queue) #define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue #define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue +static inline void iwl_disable_interrupts(struct iwl_priv *priv) +{ + clear_bit(STATUS_INT_ENABLED, &priv->status); + + /* disable interrupts from uCode/NIC to host */ + iwl_write32(priv, CSR_INT_MASK, 0x00000000); + + /* acknowledge/clear/reset any interrupts still pending + * from uCode or flow handler (Rx/Tx DMA) */ + iwl_write32(priv, CSR_INT, 0xffffffff); + iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff); + IWL_DEBUG_ISR(priv, "Disabled interrupts\n"); +} + +static inline void iwl_enable_interrupts(struct iwl_priv *priv) +{ + IWL_DEBUG_ISR(priv, "Enabling interrupts\n"); + set_bit(STATUS_INT_ENABLED, &priv->status); + iwl_write32(priv, CSR_INT_MASK, priv->inta_mask); +} + #endif /* __iwl_helpers_h__ */ -- cgit v1.2.3-18-g5258 From 4951348109c334f2b839816bd161522d089cb782 Mon Sep 17 00:00:00 2001 From: Luis Correia Date: Fri, 17 Jul 2009 21:39:19 +0200 Subject: rt2x00: Comment spellchecking Fix a bunch of spelling errors in the rt2x00 drivers Signed-off-by: Luis Correia Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.h | 2 +- drivers/net/wireless/rt2x00/rt2500pci.h | 2 +- drivers/net/wireless/rt2x00/rt2500usb.h | 2 +- drivers/net/wireless/rt2x00/rt2800usb.c | 4 ++-- drivers/net/wireless/rt2x00/rt2800usb.h | 2 +- drivers/net/wireless/rt2x00/rt2x00.h | 4 ++-- drivers/net/wireless/rt2x00/rt2x00config.c | 2 +- drivers/net/wireless/rt2x00/rt2x00crypto.c | 2 +- drivers/net/wireless/rt2x00/rt2x00link.c | 2 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 4 ++-- drivers/net/wireless/rt2x00/rt2x00queue.h | 10 +++++----- drivers/net/wireless/rt2x00/rt2x00reg.h | 4 ++-- drivers/net/wireless/rt2x00/rt61pci.c | 2 +- drivers/net/wireless/rt2x00/rt61pci.h | 2 +- drivers/net/wireless/rt2x00/rt73usb.h | 4 ++-- 15 files changed, 24 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index ec3b004ddc3..ccd644104ad 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h @@ -928,7 +928,7 @@ #define RXD_W7_RESERVED FIELD32(0xffffffff) /* - * Macro's for converting txpower from EEPROM to mac80211 value + * Macros for converting txpower from EEPROM to mac80211 value * and from mac80211 value to register value. * NOTE: Logics in rt2400pci for txpower are reversed * compared to the other rt2x00 drivers. A higher txpower diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h index ce2f065c748..54d37957883 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.h +++ b/drivers/net/wireless/rt2x00/rt2500pci.h @@ -1218,7 +1218,7 @@ #define RXD_W10_DROP FIELD32(0x00000001) /* - * Macro's for converting txpower from EEPROM to mac80211 value + * Macros for converting txpower from EEPROM to mac80211 value * and from mac80211 value to register value. */ #define MIN_TXPOWER 0 diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index 5bc46fe7217..b01edca4258 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -831,7 +831,7 @@ #define RXD_W3_EIV FIELD32(0xffffffff) /* - * Macro's for converting txpower from EEPROM to mac80211 value + * Macros for converting txpower from EEPROM to mac80211 value * and from mac80211 value to register value. */ #define MIN_TXPOWER 0 diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index f35b3d6649c..9efb4171050 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1910,7 +1910,7 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev, /* * Before the radio can be enabled, the device first has * to be woken up. After that it needs a bit of time - * to be fully awake and the radio can be enabled. + * to be fully awake and then the radio can be enabled. */ rt2800usb_set_state(rt2x00dev, STATE_AWAKE); msleep(1); @@ -1918,7 +1918,7 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev, break; case STATE_RADIO_OFF: /* - * After the radio has been disablee, the device should + * After the radio has been disabled, the device should * be put to sleep for powersaving. */ rt2800usb_disable_radio(rt2x00dev); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 61a8be61d3f..2d9dc378336 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -1921,7 +1921,7 @@ struct mac_iveiv_entry { #define RXWI_W3_SNR1 FIELD32(0x0000ff00) /* - * Macro's for converting txpower from EEPROM to mac80211 value + * Macros for converting txpower from EEPROM to mac80211 value * and from mac80211 value to register value. */ #define MIN_G_TXPOWER 0 diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 4c76c8d93cb..cbec91ef6f7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -245,7 +245,7 @@ struct link_ant { struct antenna_setup active; /* - * RSSI information for the different antenna's. + * RSSI information for the different antennas. * These statistics are used to determine when * to switch antenna when using software diversity. * @@ -633,7 +633,7 @@ struct rt2x00_dev { * The structure stored in here depends on the * system bus (PCI or USB). * When accessing this variable, the rt2x00dev_{pci,usb} - * macro's should be used for correct typecasting. + * macros should be used for correct typecasting. */ struct device *dev; diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 3e019a12df2..c6e0bcf78e9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -132,7 +132,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, /* * Failsafe: Make sure we are not sending the * ANTENNA_SW_DIVERSITY state to the driver. - * If that happes fallback to hardware default, + * If that happens, fallback to hardware defaults, * or our own default. * The calls to rt2x00lib_config_antenna_check() * might have caused that we restore back to the already diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index c54eda3c2db..30fbd3bbe08 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -129,7 +129,7 @@ void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, struct txentry_desc *txdesc) /* Pull buffer to correct size */ skb_pull(skb, txdesc->iv_len); - /* IV/EIV data has officially be stripped */ + /* IV/EIV data has officially been stripped */ skbdesc->flags |= SKBDESC_IV_STRIPPED; } diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index eb9b981b913..32570758e67 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -158,7 +158,7 @@ static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev) /* * During the last period we have sampled the RSSI - * from both antenna's. It now is time to determine + * from both antennas. It now is time to determine * which antenna demonstrated the best performance. * When we are already on the antenna with the best * performance, then there really is nothing for us diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 3425984a55c..9d31c23b92f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -341,7 +341,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) int status; /* - * Mac80211 might be calling this function while we are trying + * mac80211 might be calling this function while we are trying * to remove the device or perhaps suspending it. */ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) @@ -587,7 +587,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, int update_bssid = 0; /* - * Mac80211 might be calling this function while we are trying + * mac80211 might be calling this function while we are trying * to remove the device or perhaps suspending it. */ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index b5e06347c8a..47d175a1379 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -29,7 +29,7 @@ #include /** - * DOC: Entrie frame size + * DOC: Entry frame size * * Ralink PCI devices demand the Frame size to be a multiple of 128 bytes, * for USB devices this restriction does not apply, but the value of @@ -45,13 +45,13 @@ /** * DOC: Number of entries per queue * - * Under normal load without fragmentation 12 entries are sufficient + * Under normal load without fragmentation, 12 entries are sufficient * without the queue being filled up to the maximum. When using fragmentation - * and the queue threshold code we need to add some additional margins to + * and the queue threshold code, we need to add some additional margins to * make sure the queue will never (or only under extreme load) fill up * completely. - * Since we don't use preallocated DMA having a large number of queue entries - * will have only minimal impact on the memory requirements for the queue. + * Since we don't use preallocated DMA, having a large number of queue entries + * will have minimal impact on the memory requirements for the queue. */ #define RX_ENTRIES 24 #define TX_ENTRIES 24 diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index 861322d97fc..983e52e127a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h @@ -176,8 +176,8 @@ struct rt2x00_field32 { #define is_valid_mask(x) is_power_of_two(1LU + (x) + low_bit_mask(x)) /* - * Macro's to find first set bit in a variable. - * These macro's behaves the same as the __ffs() function with + * Macros to find first set bit in a variable. + * These macros behave the same as the __ffs() functions but * the most important difference that this is done during * compile-time rather then run-time. */ diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index b435c140cb9..fb95b8cc4fe 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2312,7 +2312,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) } /* - * Determine number of antenna's. + * Determine number of antennas. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2) __set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags); diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 6c71f77c816..93eb699165c 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -1476,7 +1476,7 @@ struct hw_pairwise_ta_entry { #define RXD_W15_RESERVED FIELD32(0xffffffff) /* - * Macro's for converting txpower from EEPROM to mac80211 value + * Macros for converting txpower from EEPROM to mac80211 value * and from mac80211 value to register value. */ #define MIN_TXPOWER 0 diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index c8016f65b4b..81fe0be51c4 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -809,7 +809,7 @@ struct hw_pairwise_ta_entry { /* * EEPROM antenna. - * ANTENNA_NUM: Number of antenna's. + * ANTENNA_NUM: Number of antennas. * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. * FRAME_TYPE: 0: DPDT , 1: SPDT , noted this bit is valid for g only. @@ -1058,7 +1058,7 @@ struct hw_pairwise_ta_entry { #define RXD_W5_RESERVED FIELD32(0xffffffff) /* - * Macro's for converting txpower from EEPROM to mac80211 value + * Macros for converting txpower from EEPROM to mac80211 value * and from mac80211 value to register value. */ #define MIN_TXPOWER 0 -- cgit v1.2.3-18-g5258 From da3c821f549419e09b4b64f07d99f52174daae6d Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sun, 19 Jul 2009 15:00:39 +0200 Subject: wl12xx: fix spelling Changes (comments and debug output): * couldnt -> couldn't * frmware -> firmware * recevied -> received Signed-off-by: Stefan Weil Acked-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_acx.c | 4 ++-- drivers/net/wireless/wl12xx/wl1251_ops.c | 4 ++-- drivers/net/wireless/wl12xx/wl1251_rx.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index 5a8d21c3192..a46c92a2952 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -84,7 +84,7 @@ int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id) ret = wl1251_cmd_configure(wl, DOT11_DEFAULT_KEY, default_key, sizeof(*default_key)); if (ret < 0) { - wl1251_error("Couldnt set default key"); + wl1251_error("Couldn't set default key"); goto out; } @@ -231,7 +231,7 @@ int wl1251_acx_feature_cfg(struct wl1251 *wl) ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG, feature, sizeof(*feature)); if (ret < 0) { - wl1251_error("Couldnt set HW encryption"); + wl1251_error("Couldn't set HW encryption"); goto out; } diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.c b/drivers/net/wireless/wl12xx/wl1251_ops.c index 96a45f59529..e7b9aab3682 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ops.c +++ b/drivers/net/wireless/wl12xx/wl1251_ops.c @@ -423,7 +423,7 @@ static void wl1251_irq_work(struct work_struct *work) wl->rx_counter = wl1251_mem_read32(wl, wl->data_path->rx_control_addr); - /* We handle a frmware bug here */ + /* We handle a firmware bug here */ switch ((wl->rx_counter - wl->rx_handled) & 0xf) { case 0: wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync"); @@ -575,7 +575,7 @@ static int wl1251_hw_init_data_path_config(struct wl1251 *wl) wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), GFP_KERNEL); if (!wl->data_path) { - wl1251_error("Couldnt allocate data path parameters"); + wl1251_error("Couldn't allocate data path parameters"); return -ENOMEM; } diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.h b/drivers/net/wireless/wl12xx/wl1251_rx.h index 81156b9c475..563a3fde40f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.h +++ b/drivers/net/wireless/wl12xx/wl1251_rx.h @@ -88,7 +88,7 @@ struct wl1251_rx_descriptor { u8 type; /* - * Recevied Rate: + * Received Rate: * 0x0A - 1MBPS * 0x14 - 2MBPS * 0x37 - 5_5MBPS -- cgit v1.2.3-18-g5258 From 1b7e528b2e39bfed37228eedaaf0665196d8ddc9 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sun, 21 Jun 2009 00:02:14 +0200 Subject: ath9k: wake up the chip for TSF reset If we are in NETWORK SLEEP state, AR_SLP32_TSF_WRITE_STATUS limit always exceeds in 'ath9k_hw_reset_tsf', because reading of the AR_SLP3 register always return with the magic 0xdeadbeef value. Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index b9d1a13ba16..98537698be2 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3842,6 +3842,7 @@ void ath9k_hw_reset_tsf(struct ath_hw *ah) { int count; + ath9k_ps_wakeup(ah->ah_sc); count = 0; while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) { count++; @@ -3853,6 +3854,7 @@ void ath9k_hw_reset_tsf(struct ath_hw *ah) udelay(10); } REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); + ath9k_ps_restore(ah->ah_sc); } bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting) -- cgit v1.2.3-18-g5258 From f9b604f6c24ad161e9c9e30a138d5899724225c8 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sun, 21 Jun 2009 00:02:15 +0200 Subject: ath9k: make use ath9k_hw_wait int ath9k_hw_reset_tsf We have a dedicated function for this kind of checks, use that instead of duplicating the code. Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 17 +++++------------ drivers/net/wireless/ath/ath9k/hw.h | 1 + 2 files changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 98537698be2..605803ae9ed 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3840,19 +3840,12 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64) void ath9k_hw_reset_tsf(struct ath_hw *ah) { - int count; - ath9k_ps_wakeup(ah->ah_sc); - count = 0; - while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) { - count++; - if (count > 10) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n"); - break; - } - udelay(10); - } + if (!ath9k_hw_wait(ah, AR_SLP32_MODE, AR_SLP32_TSF_WRITE_STATUS, 0, + AH_TSF_WRITE_TIMEOUT)) + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n"); + REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); ath9k_ps_restore(ah->ah_sc); } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 9a4570d7ecb..28bffdb365a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -95,6 +95,7 @@ #define MAX_RATE_POWER 63 #define AH_WAIT_TIMEOUT 100000 /* (us) */ +#define AH_TSF_WRITE_TIMEOUT 100 /* (us) */ #define AH_TIME_QUANTUM 10 #define AR_KEYTABLE_SIZE 128 #define POWER_UP_TIME 200000 -- cgit v1.2.3-18-g5258 From 9ab56078e638efb75ac4ccd27c7196cdfed2e6c8 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Mon, 13 Jul 2009 00:10:07 +0200 Subject: arlan: inverted logic? Inverted logic Signed-off-by: Roel Kluin Signed-off-by: John W. Linville --- drivers/net/wireless/arlan-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index d479f4735aa..f96c634e2d3 100644 --- a/drivers/net/wireless/arlan-main.c +++ b/drivers/net/wireless/arlan-main.c @@ -1022,7 +1022,7 @@ static int arlan_mac_addr(struct net_device *dev, void *p) ARLAN_DEBUG_ENTRY("arlan_mac_addr"); return -EINVAL; - if (!netif_running(dev)) + if (netif_running(dev)) return -EBUSY; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); -- cgit v1.2.3-18-g5258 From e6a3f551bc236010c4d4d99e626e150e98a4c3e6 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sun, 19 Jul 2009 21:53:14 -0500 Subject: p54: Eliminate unnecessary initialization In two places, variables are unnecessilarly initialized to NULL. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/p54/eeprom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c index 549ef2d19cd..0efe67deede 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c @@ -529,7 +529,7 @@ static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src, int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) { struct p54_common *priv = dev->priv; - struct eeprom_pda_wrap *wrap = NULL; + struct eeprom_pda_wrap *wrap; struct pda_entry *entry; unsigned int data_len, entry_len; void *tmp; @@ -722,7 +722,7 @@ int p54_read_eeprom(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize; int ret = -ENOMEM; - void *eeprom = NULL; + void *eeprom; maxblocksize = EEPROM_READBACK_LEN; if (priv->fw_var >= 0x509) -- cgit v1.2.3-18-g5258 From b68518fcbc6e0fe8c06a218cd2b92f62f3730cf9 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 20 Jul 2009 11:47:45 +0800 Subject: iwmc3200wifi: use cfg80211_connect_result to send req/resp IE cfg80211_connect_result() let us specify associate request and response IEs as parameters after we are connected. We use this capability instead of doing it ourselves with WEXT. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/iwm.h | 5 +++++ drivers/net/wireless/iwmc3200wifi/main.c | 7 +++++++ drivers/net/wireless/iwmc3200wifi/rx.c | 36 ++++++++++++++++++++------------ 3 files changed, 35 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 79d9d89d47a..2175a481d2f 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -281,6 +281,11 @@ struct iwm_priv { struct work_struct reset_worker; struct mutex mutex; + u8 *req_ie; + int req_ie_len; + u8 *resp_ie; + int resp_ie_len; + char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); }; diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 484f110151b..cf2574442b5 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -497,6 +497,13 @@ void iwm_link_off(struct iwm_priv *iwm) memset(wstats, 0, sizeof(struct iw_statistics)); wstats->qual.updated = IW_QUAL_ALL_INVALID; + kfree(iwm->req_ie); + iwm->req_ie = NULL; + iwm->req_ie_len = 0; + kfree(iwm->resp_ie); + iwm->resp_ie = NULL; + iwm->resp_ie_len = 0; + del_timer_sync(&iwm->watchdog); } diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 82b572a6fc0..6743391a45b 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -519,7 +519,8 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid, - NULL, 0, NULL, 0, + iwm->req_ie, iwm->req_ie_len, + iwm->resp_ie, iwm->resp_ie_len, WLAN_STATUS_SUCCESS, GFP_KERNEL); break; case UMAC_ASSOC_COMPLETE_FAILURE: @@ -771,37 +772,46 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, struct iwm_wifi_cmd *cmd) { struct iwm_umac_notif_mgt_frame *mgt_frame = - (struct iwm_umac_notif_mgt_frame *)buf; + (struct iwm_umac_notif_mgt_frame *)buf; struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame; u8 *ie; - unsigned int event; - union iwreq_data wrqu; IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame, le16_to_cpu(mgt_frame->len)); if (ieee80211_is_assoc_req(mgt->frame_control)) { ie = mgt->u.assoc_req.variable;; - event = IWEVASSOCREQIE; + iwm->req_ie_len = + le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); + kfree(iwm->req_ie); + iwm->req_ie = kmemdup(mgt->u.assoc_req.variable, + iwm->req_ie_len, GFP_KERNEL); } else if (ieee80211_is_reassoc_req(mgt->frame_control)) { ie = mgt->u.reassoc_req.variable;; - event = IWEVASSOCREQIE; + iwm->req_ie_len = + le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); + kfree(iwm->req_ie); + iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable, + iwm->req_ie_len, GFP_KERNEL); } else if (ieee80211_is_assoc_resp(mgt->frame_control)) { ie = mgt->u.assoc_resp.variable;; - event = IWEVASSOCRESPIE; + iwm->resp_ie_len = + le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); + kfree(iwm->resp_ie); + iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable, + iwm->resp_ie_len, GFP_KERNEL); } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) { ie = mgt->u.reassoc_resp.variable;; - event = IWEVASSOCRESPIE; + iwm->resp_ie_len = + le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); + kfree(iwm->resp_ie); + iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable, + iwm->resp_ie_len, GFP_KERNEL); } else { IWM_ERR(iwm, "Unsupported management frame"); return 0; } - wrqu.data.length = le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); - - IWM_HEXDUMP(iwm, DBG, MLME, "EVT: ", ie, wrqu.data.length); - wireless_send_event(iwm_to_ndev(iwm), event, &wrqu, ie); - return 0; } -- cgit v1.2.3-18-g5258 From 9c7c0cdd24e64f9aed39453a1bffc3b3fd16ef99 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 20 Jul 2009 11:47:46 +0800 Subject: iwmc3200wifi: fix cfg80211_connect_result is called in IBSS Avoid calling cfg80211_connect_result() in IBSS mode. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/rx.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 6743391a45b..86079a187ee 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -517,6 +517,9 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, iwm_link_on(iwm); + if (iwm->conf.mode == UMAC_MODE_IBSS) + goto ibss; + cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid, iwm->req_ie, iwm->req_ie_len, @@ -530,6 +533,9 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, iwm_link_off(iwm); + if (iwm->conf.mode == UMAC_MODE_IBSS) + goto ibss; + cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, @@ -538,11 +544,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, break; } - if (iwm->conf.mode == UMAC_MODE_IBSS) { - cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL); - return 0; - } + return 0; + ibss: + cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL); return 0; } -- cgit v1.2.3-18-g5258 From 971ad01169398170976951d3a9479a29d231c734 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 20 Jul 2009 11:47:47 +0800 Subject: iwmc3200wifi: fix a use-after-free bug The patch fixes a use-after-free bug for cmd->seq_num; Reported-by: Dan Carpenter Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/hal.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c index ee127fe4f43..c430418248b 100644 --- a/drivers/net/wireless/iwmc3200wifi/hal.c +++ b/drivers/net/wireless/iwmc3200wifi/hal.c @@ -105,9 +105,9 @@ #include "umac.h" #include "debug.h" -static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm, - struct iwm_nonwifi_cmd *cmd, - struct iwm_udma_nonwifi_cmd *udma_cmd) +static int iwm_nonwifi_cmd_init(struct iwm_priv *iwm, + struct iwm_nonwifi_cmd *cmd, + struct iwm_udma_nonwifi_cmd *udma_cmd) { INIT_LIST_HEAD(&cmd->pending); @@ -118,7 +118,7 @@ static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm, cmd->seq_num = iwm->nonwifi_seq_num; udma_cmd->seq_num = cpu_to_le16(cmd->seq_num); - cmd->seq_num = iwm->nonwifi_seq_num++; + iwm->nonwifi_seq_num++; iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX; if (udma_cmd->resp) @@ -130,6 +130,8 @@ static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm, cmd->buf.len = 0; memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd)); + + return cmd->seq_num; } u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm) @@ -369,7 +371,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm, const void *payload) { struct iwm_nonwifi_cmd *cmd; - int ret; + int ret, seq_num; cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL); if (!cmd) { @@ -377,7 +379,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm, return -ENOMEM; } - iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd); + seq_num = iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd); if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE || cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) { @@ -393,7 +395,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm, if (ret < 0) return ret; - return cmd->seq_num; + return seq_num; } static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr, -- cgit v1.2.3-18-g5258 From f974cfdd8112a081fb1a402bf77835f28f37fcad Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Mon, 20 Jul 2009 08:00:30 -0400 Subject: ath5k: fix values for bus error bits in ISR2 The new values are taken from the recently open sourced Atheros HAL. Correctness is also confirmed by the users with access to Atheros documentation. Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/reg.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index 6809b54a2ad..debad07d990 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -339,9 +339,9 @@ #define AR5K_SISR2 0x008c /* Register Address [5211+] */ #define AR5K_SISR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */ #define AR5K_SISR2_QCU_TXURN_S 0 -#define AR5K_SISR2_MCABT 0x00100000 /* Master Cycle Abort */ -#define AR5K_SISR2_SSERR 0x00200000 /* Signaled System Error */ -#define AR5K_SISR2_DPERR 0x00400000 /* Bus parity error */ +#define AR5K_SISR2_MCABT 0x00010000 /* Master Cycle Abort */ +#define AR5K_SISR2_SSERR 0x00020000 /* Signaled System Error */ +#define AR5K_SISR2_DPERR 0x00040000 /* Bus parity error */ #define AR5K_SISR2_TIM 0x01000000 /* [5212+] */ #define AR5K_SISR2_CAB_END 0x02000000 /* [5212+] */ #define AR5K_SISR2_DTIM_SYNC 0x04000000 /* DTIM sync lost [5212+] */ @@ -430,9 +430,9 @@ #define AR5K_SIMR2 0x00ac /* Register Address [5211+] */ #define AR5K_SIMR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */ #define AR5K_SIMR2_QCU_TXURN_S 0 -#define AR5K_SIMR2_MCABT 0x00100000 /* Master Cycle Abort */ -#define AR5K_SIMR2_SSERR 0x00200000 /* Signaled System Error */ -#define AR5K_SIMR2_DPERR 0x00400000 /* Bus parity error */ +#define AR5K_SIMR2_MCABT 0x00010000 /* Master Cycle Abort */ +#define AR5K_SIMR2_SSERR 0x00020000 /* Signaled System Error */ +#define AR5K_SIMR2_DPERR 0x00040000 /* Bus parity error */ #define AR5K_SIMR2_TIM 0x01000000 /* [5212+] */ #define AR5K_SIMR2_CAB_END 0x02000000 /* [5212+] */ #define AR5K_SIMR2_DTIM_SYNC 0x04000000 /* DTIM Sync lost [5212+] */ -- cgit v1.2.3-18-g5258 From f298c282a5233126ffe6385c02a9e79f695bed0f Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 21 Jul 2009 14:25:53 +0300 Subject: wl1251: remove accidentally added wl1251_netlink.c Commit "wl1251: add wl1251 prefix to all 1251 files" accidentally added wl1251_netlink.c which contains a private netlink interface. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_netlink.c | 679 --------------------------- 1 file changed, 679 deletions(-) delete mode 100644 drivers/net/wireless/wl12xx/wl1251_netlink.c (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.c b/drivers/net/wireless/wl12xx/wl1251_netlink.c deleted file mode 100644 index 67d3d5a3b51..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_netlink.c +++ /dev/null @@ -1,679 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ -#include "wl1251_netlink.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "wl1251.h" -#include "wl1251_spi.h" -#include "wl1251_acx.h" - -/* FIXME: this should be changed as soon as user space catches up */ -#define WL1251_NL_NAME "wl1251" -#define WL1251_NL_VERSION 1 - -#define WL1251_MAX_TEST_LENGTH 1024 -#define WL1251_MAX_NVS_LENGTH 1024 - -enum wl1251_nl_commands { - WL1251_NL_CMD_UNSPEC, - WL1251_NL_CMD_TEST, - WL1251_NL_CMD_INTERROGATE, - WL1251_NL_CMD_CONFIGURE, - WL1251_NL_CMD_PHY_REG_READ, - WL1251_NL_CMD_NVS_PUSH, - WL1251_NL_CMD_REG_WRITE, - WL1251_NL_CMD_REG_READ, - WL1251_NL_CMD_SET_PLT_MODE, - - __WL1251_NL_CMD_AFTER_LAST -}; -#define WL1251_NL_CMD_MAX (__WL1251_NL_CMD_AFTER_LAST - 1) - -enum wl1251_nl_attrs { - WL1251_NL_ATTR_UNSPEC, - WL1251_NL_ATTR_IFNAME, - WL1251_NL_ATTR_CMD_TEST_PARAM, - WL1251_NL_ATTR_CMD_TEST_ANSWER, - WL1251_NL_ATTR_CMD_IE, - WL1251_NL_ATTR_CMD_IE_LEN, - WL1251_NL_ATTR_CMD_IE_BUFFER, - WL1251_NL_ATTR_CMD_IE_ANSWER, - WL1251_NL_ATTR_REG_ADDR, - WL1251_NL_ATTR_REG_VAL, - WL1251_NL_ATTR_NVS_BUFFER, - WL1251_NL_ATTR_NVS_LEN, - WL1251_NL_ATTR_PLT_MODE, - - __WL1251_NL_ATTR_AFTER_LAST -}; -#define WL1251_NL_ATTR_MAX (__WL1251_NL_ATTR_AFTER_LAST - 1) - -static struct genl_family wl1251_nl_family = { - .id = GENL_ID_GENERATE, - .name = WL1251_NL_NAME, - .hdrsize = 0, - .version = WL1251_NL_VERSION, - .maxattr = WL1251_NL_ATTR_MAX, -}; - -static struct net_device *ifname_to_netdev(struct net *net, - struct genl_info *info) -{ - char *ifname; - - if (!info->attrs[WL1251_NL_ATTR_IFNAME]) - return NULL; - - ifname = nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]); - - wl1251_debug(DEBUG_NETLINK, "Looking for %s", ifname); - - return dev_get_by_name(net, ifname); -} - -static struct wl1251 *ifname_to_wl1251(struct net *net, struct genl_info *info) -{ - struct net_device *netdev; - struct wireless_dev *wdev; - struct wiphy *wiphy; - struct ieee80211_hw *hw; - - netdev = ifname_to_netdev(net, info); - if (netdev == NULL) { - wl1251_error("Wrong interface"); - return NULL; - } - - wdev = netdev->ieee80211_ptr; - if (wdev == NULL) { - wl1251_error("ieee80211_ptr is NULL"); - return NULL; - } - - wiphy = wdev->wiphy; - if (wiphy == NULL) { - wl1251_error("wiphy is NULL"); - return NULL; - } - - hw = wiphy_priv(wiphy); - if (hw == NULL) { - wl1251_error("hw is NULL"); - return NULL; - } - - dev_put(netdev); - - return hw->priv; -} - -static int wl1251_nl_test_cmd(struct sk_buff *skb, struct genl_info *info) -{ - struct wl1251 *wl; - struct wl1251_command *cmd; - char *buf; - int buf_len, ret, cmd_len; - u8 answer; - - if (!info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]) - return -EINVAL; - - wl = ifname_to_wl1251(&init_net, info); - if (wl == NULL) { - wl1251_error("wl1251 not found"); - return -EINVAL; - } - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - buf = nla_data(info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]); - buf_len = nla_len(info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]); - answer = nla_get_u8(info->attrs[WL1251_NL_ATTR_CMD_TEST_ANSWER]); - - cmd->header.id = CMD_TEST; - memcpy(cmd->parameters, buf, buf_len); - cmd_len = sizeof(struct wl1251_cmd_header) + buf_len; - - mutex_lock(&wl->mutex); - ret = wl1251_cmd_test(wl, cmd, cmd_len, answer); - mutex_unlock(&wl->mutex); - - if (ret < 0) { - wl1251_error("%s() failed", __func__); - goto out; - } - - if (answer) { - struct sk_buff *msg; - void *hdr; - - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); - if (!msg) { - ret = -ENOMEM; - goto out; - } - - hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, - &wl1251_nl_family, 0, WL1251_NL_CMD_TEST); - if (IS_ERR(hdr)) { - ret = PTR_ERR(hdr); - goto nla_put_failure; - } - - NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME, - nla_data(info->attrs[WL1251_NL_ATTR_IFNAME])); - NLA_PUT(msg, WL1251_NL_ATTR_CMD_TEST_ANSWER, - sizeof(*cmd), cmd); - - ret = genlmsg_end(msg, hdr); - if (ret < 0) { - wl1251_error("%s() failed", __func__); - goto nla_put_failure; - } - - wl1251_debug(DEBUG_NETLINK, "TEST cmd sent, answer"); - ret = genlmsg_reply(msg, info); - goto out; - - nla_put_failure: - nlmsg_free(msg); - } else - wl1251_debug(DEBUG_NETLINK, "TEST cmd sent"); - -out: - kfree(cmd); - return ret; -} - -static int wl1251_nl_interrogate(struct sk_buff *skb, struct genl_info *info) -{ - struct wl1251 *wl; - struct sk_buff *msg; - int ret = -ENOBUFS, cmd_ie, cmd_ie_len; - struct wl1251_command *cmd; - void *hdr; - - if (!info->attrs[WL1251_NL_ATTR_CMD_IE]) - return -EINVAL; - - if (!info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]) - return -EINVAL; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); - if (!msg) - return -ENOMEM; - - wl = ifname_to_wl1251(&init_net, info); - if (wl == NULL) { - wl1251_error("wl1251 not found"); - ret = -EINVAL; - goto nla_put_failure; - } - - /* acx id */ - cmd_ie = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE]); - - /* maximum length of acx, including all headers */ - cmd_ie_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]); - - wl1251_debug(DEBUG_NETLINK, "Getting IE 0x%x (len %d)", - cmd_ie, cmd_ie_len); - - mutex_lock(&wl->mutex); - ret = wl1251_cmd_interrogate(wl, cmd_ie, cmd, cmd_ie_len); - mutex_unlock(&wl->mutex); - - if (ret < 0) { - wl1251_error("%s() failed", __func__); - goto nla_put_failure; - } - - hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, - &wl1251_nl_family, 0, WL1251_NL_CMD_INTERROGATE); - if (IS_ERR(hdr)) { - ret = PTR_ERR(hdr); - goto nla_put_failure; - } - - NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME, - nla_data(info->attrs[WL1251_NL_ATTR_IFNAME])); - NLA_PUT(msg, WL1251_NL_ATTR_CMD_IE_ANSWER, cmd_ie_len, cmd); - - ret = genlmsg_end(msg, hdr); - if (ret < 0) { - wl1251_error("%s() failed", __func__); - goto nla_put_failure; - } - - kfree(cmd); - return genlmsg_reply(msg, info); - - nla_put_failure: - kfree(cmd); - nlmsg_free(msg); - - return ret; -} - -static int wl1251_nl_configure(struct sk_buff *skb, struct genl_info *info) -{ - int ret = 0, cmd_ie_len, acx_len; - struct acx_header *acx = NULL; - struct sk_buff *msg; - struct wl1251 *wl; - void *cmd_ie; - u16 *id; - - if (!info->attrs[WL1251_NL_ATTR_CMD_IE_BUFFER]) - return -EINVAL; - - if (!info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]) - return -EINVAL; - - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); - if (!msg) - return -ENOMEM; - - wl = ifname_to_wl1251(&init_net, info); - if (wl == NULL) { - wl1251_error("wl1251 not found"); - ret = -EINVAL; - goto nla_put_failure; - } - - /* contains the acx header but not the cmd header */ - cmd_ie = nla_data(info->attrs[WL1251_NL_ATTR_CMD_IE_BUFFER]); - - cmd_ie_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]); - - /* acx id is in the first two bytes */ - id = cmd_ie; - - /* need to add acx_header before cmd_ie, so create a new command */ - acx_len = sizeof(struct acx_header) + cmd_ie_len; - acx = kzalloc(acx_len, GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto nla_put_failure; - } - - /* copy the acx header and the payload */ - memcpy(&acx->id, cmd_ie, cmd_ie_len); - - mutex_lock(&wl->mutex); - ret = wl1251_cmd_configure(wl, *id, acx, acx_len); - mutex_unlock(&wl->mutex); - - if (ret < 0) { - wl1251_error("%s() failed", __func__); - goto nla_put_failure; - } - - wl1251_debug(DEBUG_NETLINK, "CONFIGURE cmd sent"); - - nla_put_failure: - kfree(acx); - nlmsg_free(msg); - - return ret; -} - -static int wl1251_nl_phy_reg_read(struct sk_buff *skb, struct genl_info *info) -{ - struct wl1251 *wl; - struct sk_buff *msg; - u32 reg_addr, *reg_value = NULL; - int ret = 0; - void *hdr; - - if (!info->attrs[WL1251_NL_ATTR_REG_ADDR]) - return -EINVAL; - - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); - if (!msg) - return -ENOMEM; - - wl = ifname_to_wl1251(&init_net, info); - if (wl == NULL) { - wl1251_error("wl1251 not found"); - ret = -EINVAL; - goto nla_put_failure; - } - - reg_value = kmalloc(sizeof(*reg_value), GFP_KERNEL); - if (!reg_value) { - ret = -ENOMEM; - goto nla_put_failure; - } - - reg_addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]); - - wl1251_debug(DEBUG_NETLINK, "Reading PHY reg 0x%x", reg_addr); - - mutex_lock(&wl->mutex); - ret = wl1251_cmd_read_memory(wl, reg_addr, reg_value, - sizeof(*reg_value)); - mutex_unlock(&wl->mutex); - - if (ret < 0) { - wl1251_error("%s() failed", __func__); - goto nla_put_failure; - } - - - hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, - &wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ); - if (IS_ERR(hdr)) { - ret = PTR_ERR(hdr); - goto nla_put_failure; - } - - NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME, - nla_data(info->attrs[WL1251_NL_ATTR_IFNAME])); - - NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, *reg_value); - - ret = genlmsg_end(msg, hdr); - if (ret < 0) { - wl1251_error("%s() failed", __func__); - goto nla_put_failure; - } - - kfree(reg_value); - - return genlmsg_reply(msg, info); - - nla_put_failure: - nlmsg_free(msg); - kfree(reg_value); - - return ret; -} - -static int wl1251_nl_nvs_push(struct sk_buff *skb, struct genl_info *info) -{ - struct wl1251 *wl; - int ret = 0; - - if (!info->attrs[WL1251_NL_ATTR_NVS_BUFFER]) - return -EINVAL; - - if (!info->attrs[WL1251_NL_ATTR_NVS_LEN]) - return -EINVAL; - - wl = ifname_to_wl1251(&init_net, info); - if (wl == NULL) { - wl1251_error("wl1251 not found"); - return -EINVAL; - } - - mutex_lock(&wl->mutex); - wl->nvs_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_NVS_LEN]); - if (wl->nvs_len % 4) { - wl1251_error("NVS size is not multiple of 32: %d", wl->nvs_len); - ret = -EILSEQ; - goto out; - } - - /* If we already have an NVS, we should free it */ - kfree(wl->nvs); - - wl->nvs = kzalloc(wl->nvs_len, GFP_KERNEL); - if (wl->nvs == NULL) { - wl1251_error("Can't allocate NVS"); - ret = -ENOMEM; - goto out; - } - - memcpy(wl->nvs, - nla_data(info->attrs[WL1251_NL_ATTR_NVS_BUFFER]), - wl->nvs_len); - - wl1251_debug(DEBUG_NETLINK, "got NVS from userspace, %d bytes", - wl->nvs_len); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static int wl1251_nl_reg_read(struct sk_buff *skb, struct genl_info *info) -{ - struct wl1251 *wl; - u32 addr, val; - int ret = 0; - struct sk_buff *msg; - void *hdr; - - if (!info->attrs[WL1251_NL_ATTR_REG_ADDR]) - return -EINVAL; - - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); - if (!msg) - return -ENOMEM; - - wl = ifname_to_wl1251(&init_net, info); - if (wl == NULL) { - wl1251_error("wl1251 not found"); - return -EINVAL; - } - - addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]); - - mutex_lock(&wl->mutex); - val = wl1251_reg_read32(wl, addr); - mutex_unlock(&wl->mutex); - - hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, - &wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ); - if (IS_ERR(hdr)) { - ret = PTR_ERR(hdr); - goto nla_put_failure; - } - - NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME, - nla_data(info->attrs[WL1251_NL_ATTR_IFNAME])); - - NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, val); - - ret = genlmsg_end(msg, hdr); - if (ret < 0) { - wl1251_error("%s() failed", __func__); - goto nla_put_failure; - } - - return genlmsg_reply(msg, info); - - nla_put_failure: - nlmsg_free(msg); - - return ret; -} - -static int wl1251_nl_reg_write(struct sk_buff *skb, struct genl_info *info) -{ - struct wl1251 *wl; - u32 addr, val; - - if (!info->attrs[WL1251_NL_ATTR_REG_ADDR]) - return -EINVAL; - - if (!info->attrs[WL1251_NL_ATTR_REG_VAL]) - return -EINVAL; - - wl = ifname_to_wl1251(&init_net, info); - if (wl == NULL) { - wl1251_error("wl1251 not found"); - return -EINVAL; - } - - addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]); - val = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_VAL]); - - mutex_lock(&wl->mutex); - wl1251_reg_write32(wl, addr, val); - mutex_unlock(&wl->mutex); - - return 0; -} - -static int wl1251_nl_set_plt_mode(struct sk_buff *skb, struct genl_info *info) -{ - struct wl1251 *wl; - u32 val; - int ret; - - if (!info->attrs[WL1251_NL_ATTR_PLT_MODE]) - return -EINVAL; - - wl = ifname_to_wl1251(&init_net, info); - if (wl == NULL) { - wl1251_error("wl1251 not found"); - return -EINVAL; - } - - val = nla_get_u32(info->attrs[WL1251_NL_ATTR_PLT_MODE]); - - switch (val) { - case 0: - ret = wl1251_plt_stop(wl); - break; - case 1: - ret = wl1251_plt_start(wl); - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static struct nla_policy wl1251_nl_policy[WL1251_NL_ATTR_MAX + 1] = { - [WL1251_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING, - .len = IFNAMSIZ-1 }, - [WL1251_NL_ATTR_CMD_TEST_PARAM] = { .type = NLA_BINARY, - .len = WL1251_MAX_TEST_LENGTH }, - [WL1251_NL_ATTR_CMD_TEST_ANSWER] = { .type = NLA_U8 }, - [WL1251_NL_ATTR_CMD_IE] = { .type = NLA_U32 }, - [WL1251_NL_ATTR_CMD_IE_LEN] = { .type = NLA_U32 }, - [WL1251_NL_ATTR_CMD_IE_BUFFER] = { .type = NLA_BINARY, - .len = WL1251_MAX_TEST_LENGTH }, - [WL1251_NL_ATTR_CMD_IE_ANSWER] = { .type = NLA_BINARY, - .len = WL1251_MAX_TEST_LENGTH }, - [WL1251_NL_ATTR_REG_ADDR] = { .type = NLA_U32 }, - [WL1251_NL_ATTR_REG_VAL] = { .type = NLA_U32 }, - [WL1251_NL_ATTR_NVS_BUFFER] = { .type = NLA_BINARY, - .len = WL1251_MAX_NVS_LENGTH }, - [WL1251_NL_ATTR_NVS_LEN] = { .type = NLA_U32 }, - [WL1251_NL_ATTR_PLT_MODE] = { .type = NLA_U32 }, -}; - -static struct genl_ops wl1251_nl_ops[] = { - { - .cmd = WL1251_NL_CMD_TEST, - .doit = wl1251_nl_test_cmd, - .policy = wl1251_nl_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = WL1251_NL_CMD_INTERROGATE, - .doit = wl1251_nl_interrogate, - .policy = wl1251_nl_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = WL1251_NL_CMD_CONFIGURE, - .doit = wl1251_nl_configure, - .policy = wl1251_nl_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = WL1251_NL_CMD_PHY_REG_READ, - .doit = wl1251_nl_phy_reg_read, - .policy = wl1251_nl_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = WL1251_NL_CMD_NVS_PUSH, - .doit = wl1251_nl_nvs_push, - .policy = wl1251_nl_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = WL1251_NL_CMD_REG_WRITE, - .doit = wl1251_nl_reg_write, - .policy = wl1251_nl_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = WL1251_NL_CMD_REG_READ, - .doit = wl1251_nl_reg_read, - .policy = wl1251_nl_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = WL1251_NL_CMD_SET_PLT_MODE, - .doit = wl1251_nl_set_plt_mode, - .policy = wl1251_nl_policy, - .flags = GENL_ADMIN_PERM, - }, -}; - -int wl1251_nl_register(void) -{ - int err, i; - - err = genl_register_family(&wl1251_nl_family); - if (err) - return err; - - for (i = 0; i < ARRAY_SIZE(wl1251_nl_ops); i++) { - err = genl_register_ops(&wl1251_nl_family, &wl1251_nl_ops[i]); - if (err) - goto err_out; - } - return 0; - err_out: - genl_unregister_family(&wl1251_nl_family); - return err; -} - -void wl1251_nl_unregister(void) -{ - genl_unregister_family(&wl1251_nl_family); -} -- cgit v1.2.3-18-g5258 From 270b7588b376968d4db3af01e6d9907814c45552 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 21 Jul 2009 14:26:01 +0300 Subject: wl1251: remove wl1251_plt_start/stop() This Production Line Testing code is currently unused and can be removed. It can be reintroduced when nl80211 test mode implemented for the driver. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 54 ------------------------------- 1 file changed, 54 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 509cbef5e27..da4c688c46a 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -246,60 +246,6 @@ out: mutex_unlock(&wl->mutex); } -int wl1251_plt_start(struct wl1251 *wl) -{ - int ret; - - mutex_lock(&wl->mutex); - - wl1251_notice("power up"); - - if (wl->state != WL1251_STATE_OFF) { - wl1251_error("cannot go into PLT state because not " - "in off state: %d", wl->state); - return -EBUSY; - } - - wl->state = WL1251_STATE_PLT; - - ret = wl1251_chip_wakeup(wl); - if (ret < 0) - return ret; - - ret = wl->chip.op_boot(wl); - if (ret < 0) - return ret; - - wl1251_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); - - ret = wl->chip.op_plt_init(wl); - if (ret < 0) - return ret; - - return 0; -} - -int wl1251_plt_stop(struct wl1251 *wl) -{ - mutex_lock(&wl->mutex); - - wl1251_notice("power down"); - - if (wl->state != WL1251_STATE_PLT) { - wl1251_error("cannot power down because not in PLT " - "state: %d", wl->state); - return -EBUSY; - } - - wl1251_disable_interrupts(wl); - wl1251_power_off(wl); - - wl->state = WL1251_STATE_OFF; - - return 0; -} - - static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct wl1251 *wl = hw->priv; -- cgit v1.2.3-18-g5258 From 95a2b2ef82dc0bd10475c02e9d1fc7c93e708d03 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 21 Jul 2009 21:03:10 -0400 Subject: ath9k: do not stop the queues in driver stop mac80211 will have disabled the queues for us when needed. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 254e78786ee..3436295e050 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2101,8 +2101,6 @@ static void ath9k_stop(struct ieee80211_hw *hw) mutex_lock(&sc->mutex); - ieee80211_stop_queues(hw); - if (ath9k_wiphy_started(sc)) { mutex_unlock(&sc->mutex); return; /* another wiphy still in use */ -- cgit v1.2.3-18-g5258 From ccc78ec5d463e6c99f4a384be52b31222ffe2e21 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 21 Jul 2009 21:03:42 -0400 Subject: adm8211: remove uneeded code during suspend/resume mac80211 drivers do not need to stop the software queues or call their own stop() callback upon suspend as we do it for drivers. Equally drivers don't have to call their own start() or start the queues as mac80211 will do it for us. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index ecc93834533..5695911bc60 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1964,14 +1964,6 @@ static void __devexit adm8211_remove(struct pci_dev *pdev) #ifdef CONFIG_PM static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state) { - struct ieee80211_hw *dev = pci_get_drvdata(pdev); - struct adm8211_priv *priv = dev->priv; - - if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) { - ieee80211_stop_queues(dev); - adm8211_stop(dev); - } - pci_save_state(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; @@ -1979,17 +1971,8 @@ static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state) static int adm8211_resume(struct pci_dev *pdev) { - struct ieee80211_hw *dev = pci_get_drvdata(pdev); - struct adm8211_priv *priv = dev->priv; - pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - - if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) { - adm8211_start(dev); - ieee80211_wake_queues(dev); - } - return 0; } #endif /* CONFIG_PM */ -- cgit v1.2.3-18-g5258 From 8150f32b90f630ad3e460f026ce338cb81685bc9 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 24 Jul 2009 22:11:32 -0700 Subject: Driver Core: Make PM operations a const pointer They are not supposed to be modified by drivers, so make them const. Signed-off-by: Dmitry Torokhov Acked-by: Greg Kroah-Hartman Signed-off-by: Rafael J. Wysocki --- drivers/base/platform.c | 2 +- drivers/base/power/main.c | 8 +++++--- drivers/pci/pci-driver.c | 16 ++++++++-------- 3 files changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 81cb01bfc35..c4b3fcee17b 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -925,7 +925,7 @@ static int platform_pm_restore_noirq(struct device *dev) #endif /* !CONFIG_HIBERNATION */ -static struct dev_pm_ops platform_dev_pm_ops = { +static const struct dev_pm_ops platform_dev_pm_ops = { .prepare = platform_pm_prepare, .complete = platform_pm_complete, .suspend = platform_pm_suspend, diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 58a3e572f2c..1b1a786b7de 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -157,8 +157,9 @@ void device_pm_move_last(struct device *dev) * @ops: PM operations to choose from. * @state: PM transition of the system being carried out. */ -static int pm_op(struct device *dev, struct dev_pm_ops *ops, - pm_message_t state) +static int pm_op(struct device *dev, + const struct dev_pm_ops *ops, + pm_message_t state) { int error = 0; @@ -220,7 +221,8 @@ static int pm_op(struct device *dev, struct dev_pm_ops *ops, * The operation is executed with interrupts disabled by the only remaining * functional CPU in the system. */ -static int pm_noirq_op(struct device *dev, struct dev_pm_ops *ops, +static int pm_noirq_op(struct device *dev, + const struct dev_pm_ops *ops, pm_message_t state) { int error = 0; diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index d76c4c85367..0c2ea44ae5e 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -575,7 +575,7 @@ static void pci_pm_complete(struct device *dev) static int pci_pm_suspend(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; if (pci_has_legacy_pm_support(pci_dev)) return pci_legacy_suspend(dev, PMSG_SUSPEND); @@ -613,7 +613,7 @@ static int pci_pm_suspend(struct device *dev) static int pci_pm_suspend_noirq(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; if (pci_has_legacy_pm_support(pci_dev)) return pci_legacy_suspend_late(dev, PMSG_SUSPEND); @@ -672,7 +672,7 @@ static int pci_pm_resume_noirq(struct device *dev) static int pci_pm_resume(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; int error = 0; /* @@ -711,7 +711,7 @@ static int pci_pm_resume(struct device *dev) static int pci_pm_freeze(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; if (pci_has_legacy_pm_support(pci_dev)) return pci_legacy_suspend(dev, PMSG_FREEZE); @@ -780,7 +780,7 @@ static int pci_pm_thaw_noirq(struct device *dev) static int pci_pm_thaw(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; int error = 0; if (pci_has_legacy_pm_support(pci_dev)) @@ -799,7 +799,7 @@ static int pci_pm_thaw(struct device *dev) static int pci_pm_poweroff(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; if (pci_has_legacy_pm_support(pci_dev)) return pci_legacy_suspend(dev, PMSG_HIBERNATE); @@ -872,7 +872,7 @@ static int pci_pm_restore_noirq(struct device *dev) static int pci_pm_restore(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; int error = 0; /* @@ -910,7 +910,7 @@ static int pci_pm_restore(struct device *dev) #endif /* !CONFIG_HIBERNATION */ -struct dev_pm_ops pci_dev_pm_ops = { +const struct dev_pm_ops pci_dev_pm_ops = { .prepare = pci_pm_prepare, .complete = pci_pm_complete, .suspend = pci_pm_suspend, -- cgit v1.2.3-18-g5258 From ae78e0e0e49885bef3bffee2a56254db6abf562c Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 22 Jul 2009 23:02:54 -0700 Subject: Input: gpio_keys - swtich to dev_pm_ops Signed-off-by: Mike Rapoport Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index efed0c9e242..a88aff3816a 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -216,8 +216,9 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev) #ifdef CONFIG_PM -static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state) +static int gpio_keys_suspend(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; int i; @@ -234,8 +235,9 @@ static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state) return 0; } -static int gpio_keys_resume(struct platform_device *pdev) +static int gpio_keys_resume(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; int i; @@ -251,19 +253,22 @@ static int gpio_keys_resume(struct platform_device *pdev) return 0; } -#else -#define gpio_keys_suspend NULL -#define gpio_keys_resume NULL + +static const struct dev_pm_ops gpio_keys_pm_ops = { + .suspend = gpio_keys_suspend, + .resume = gpio_keys_resume, +}; #endif static struct platform_driver gpio_keys_device_driver = { .probe = gpio_keys_probe, .remove = __devexit_p(gpio_keys_remove), - .suspend = gpio_keys_suspend, - .resume = gpio_keys_resume, .driver = { .name = "gpio-keys", .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &gpio_keys_pm_ops, +#endif } }; -- cgit v1.2.3-18-g5258 From cb3824bade2549d7ad059d5802da43312540fdee Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 8 Jul 2009 14:21:12 +0200 Subject: ISDN: Make isdnhdlc usable for other ISDN drivers isdnhdlc is useful for other ISDN drivers as well. Move the include file to a central location and the source to the central isdn location. Signed-off-by: Karsten Keil --- drivers/isdn/Kconfig | 6 +- drivers/isdn/hisax/Kconfig | 6 +- drivers/isdn/hisax/Makefile | 4 - drivers/isdn/hisax/isdnhdlc.c | 603 ------------------------------------------ drivers/isdn/hisax/isdnhdlc.h | 70 ----- drivers/isdn/hisax/st5481.h | 2 +- drivers/isdn/i4l/Kconfig | 11 + drivers/isdn/i4l/Makefile | 1 + drivers/isdn/i4l/isdnhdlc.c | 603 ++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 619 insertions(+), 687 deletions(-) delete mode 100644 drivers/isdn/hisax/isdnhdlc.c delete mode 100644 drivers/isdn/hisax/isdnhdlc.h create mode 100644 drivers/isdn/i4l/isdnhdlc.c (limited to 'drivers') diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig index 02bdca6f95c..022a1945295 100644 --- a/drivers/isdn/Kconfig +++ b/drivers/isdn/Kconfig @@ -21,8 +21,6 @@ menuconfig ISDN if ISDN -source "drivers/isdn/mISDN/Kconfig" - menuconfig ISDN_I4L tristate "Old ISDN4Linux (deprecated)" ---help--- @@ -41,9 +39,9 @@ menuconfig ISDN_I4L It is still available, though, for use with adapters that are not supported by the new CAPI subsystem yet. -if ISDN_I4L +source "drivers/isdn/mISDN/Kconfig" + source "drivers/isdn/i4l/Kconfig" -endif menuconfig ISDN_CAPI tristate "CAPI 2.0 subsystem" diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig index 7832d8ba8e4..3464ebc4cdb 100644 --- a/drivers/isdn/hisax/Kconfig +++ b/drivers/isdn/hisax/Kconfig @@ -391,6 +391,7 @@ comment "HiSax sub driver modules" config HISAX_ST5481 tristate "ST5481 USB ISDN modem (EXPERIMENTAL)" depends on USB && EXPERIMENTAL + select ISDN_HDLC select CRC_CCITT select BITREVERSE help @@ -418,11 +419,6 @@ config HISAX_FRITZ_PCIPNP (the latter also needs you to select "ISA Plug and Play support" from the menu "Plug and Play configuration") -config HISAX_HDLC - bool - depends on HISAX_ST5481 - default y - config HISAX_AVM_A1_PCMCIA bool depends on HISAX_AVM_A1_CS diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile index c7a3794bdae..ab638b083df 100644 --- a/drivers/isdn/hisax/Makefile +++ b/drivers/isdn/hisax/Makefile @@ -16,10 +16,6 @@ obj-$(CONFIG_HISAX_HFCUSB) += hfc_usb.o obj-$(CONFIG_HISAX_HFC4S8S) += hfc4s8s_l1.o obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o -ifdef CONFIG_HISAX_HDLC -obj-$(CONFIG_ISDN_DRV_HISAX) += isdnhdlc.o -endif - # Multipart objects. hisax_st5481-y := st5481_init.o st5481_usb.o st5481_d.o \ diff --git a/drivers/isdn/hisax/isdnhdlc.c b/drivers/isdn/hisax/isdnhdlc.c deleted file mode 100644 index c69a77a8006..00000000000 --- a/drivers/isdn/hisax/isdnhdlc.c +++ /dev/null @@ -1,603 +0,0 @@ -/* - * isdnhdlc.c -- General purpose ISDN HDLC decoder. - * - *Copyright (C) 2002 Wolfgang Mües - * 2001 Frode Isaksen - * 2001 Kai Germaschewski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include "isdnhdlc.h" - -/*-------------------------------------------------------------------*/ - -MODULE_AUTHOR("Wolfgang Mües , " - "Frode Isaksen , " - "Kai Germaschewski "); -MODULE_DESCRIPTION("General purpose ISDN HDLC decoder"); -MODULE_LICENSE("GPL"); - -/*-------------------------------------------------------------------*/ - -enum { - HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7, - HDLC_GET_DATA,HDLC_FAST_FLAG -}; - -enum { - HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG, - HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG, - HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0, - HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED -}; - -void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56) -{ - hdlc->bit_shift = 0; - hdlc->hdlc_bits1 = 0; - hdlc->data_bits = 0; - hdlc->ffbit_shift = 0; - hdlc->data_received = 0; - hdlc->state = HDLC_GET_DATA; - hdlc->do_adapt56 = do_adapt56; - hdlc->dchannel = 0; - hdlc->crc = 0; - hdlc->cbin = 0; - hdlc->shift_reg = 0; - hdlc->ffvalue = 0; - hdlc->dstpos = 0; -} - -void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_adapt56) -{ - hdlc->bit_shift = 0; - hdlc->hdlc_bits1 = 0; - hdlc->data_bits = 0; - hdlc->ffbit_shift = 0; - hdlc->data_received = 0; - hdlc->do_closing = 0; - hdlc->ffvalue = 0; - if (is_d_channel) { - hdlc->dchannel = 1; - hdlc->state = HDLC_SEND_FIRST_FLAG; - } else { - hdlc->dchannel = 0; - hdlc->state = HDLC_SEND_FAST_FLAG; - hdlc->ffvalue = 0x7e; - } - hdlc->cbin = 0x7e; - hdlc->bit_shift = 0; - if(do_adapt56){ - hdlc->do_adapt56 = 1; - hdlc->data_bits = 0; - hdlc->state = HDLC_SENDFLAG_B0; - } else { - hdlc->do_adapt56 = 0; - hdlc->data_bits = 8; - } - hdlc->shift_reg = 0; -} - -/* - isdnhdlc_decode - decodes HDLC frames from a transparent bit stream. - - The source buffer is scanned for valid HDLC frames looking for - flags (01111110) to indicate the start of a frame. If the start of - the frame is found, the bit stuffing is removed (0 after 5 1's). - When a new flag is found, the complete frame has been received - and the CRC is checked. - If a valid frame is found, the function returns the frame length - excluding the CRC with the bit HDLC_END_OF_FRAME set. - If the beginning of a valid frame is found, the function returns - the length. - If a framing error is found (too many 1s and not a flag) the function - returns the length with the bit HDLC_FRAMING_ERROR set. - If a CRC error is found the function returns the length with the - bit HDLC_CRC_ERROR set. - If the frame length exceeds the destination buffer size, the function - returns the length with the bit HDLC_LENGTH_ERROR set. - - src - source buffer - slen - source buffer length - count - number of bytes removed (decoded) from the source buffer - dst _ destination buffer - dsize - destination buffer size - returns - number of decoded bytes in the destination buffer and status - flag. - */ -int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, - int slen, int *count, unsigned char *dst, int dsize) -{ - int status=0; - - static const unsigned char fast_flag[]={ - 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f - }; - - static const unsigned char fast_flag_value[]={ - 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f - }; - - static const unsigned char fast_abort[]={ - 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff - }; - - *count = slen; - - while(slen > 0){ - if(hdlc->bit_shift==0){ - hdlc->cbin = *src++; - slen--; - hdlc->bit_shift = 8; - if(hdlc->do_adapt56){ - hdlc->bit_shift --; - } - } - - switch(hdlc->state){ - case STOPPED: - return 0; - case HDLC_FAST_IDLE: - if(hdlc->cbin == 0xff){ - hdlc->bit_shift = 0; - break; - } - hdlc->state = HDLC_GET_FLAG_B0; - hdlc->hdlc_bits1 = 0; - hdlc->bit_shift = 8; - break; - case HDLC_GET_FLAG_B0: - if(!(hdlc->cbin & 0x80)) { - hdlc->state = HDLC_GETFLAG_B1A6; - hdlc->hdlc_bits1 = 0; - } else { - if(!hdlc->do_adapt56){ - if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1) - hdlc->state = HDLC_FAST_IDLE; - } - } - hdlc->cbin<<=1; - hdlc->bit_shift --; - break; - case HDLC_GETFLAG_B1A6: - if(hdlc->cbin & 0x80){ - hdlc->hdlc_bits1++; - if(hdlc->hdlc_bits1==6){ - hdlc->state = HDLC_GETFLAG_B7; - } - } else { - hdlc->hdlc_bits1 = 0; - } - hdlc->cbin<<=1; - hdlc->bit_shift --; - break; - case HDLC_GETFLAG_B7: - if(hdlc->cbin & 0x80) { - hdlc->state = HDLC_GET_FLAG_B0; - } else { - hdlc->state = HDLC_GET_DATA; - hdlc->crc = 0xffff; - hdlc->shift_reg = 0; - hdlc->hdlc_bits1 = 0; - hdlc->data_bits = 0; - hdlc->data_received = 0; - } - hdlc->cbin<<=1; - hdlc->bit_shift --; - break; - case HDLC_GET_DATA: - if(hdlc->cbin & 0x80){ - hdlc->hdlc_bits1++; - switch(hdlc->hdlc_bits1){ - case 6: - break; - case 7: - if(hdlc->data_received) { - // bad frame - status = -HDLC_FRAMING_ERROR; - } - if(!hdlc->do_adapt56){ - if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){ - hdlc->state = HDLC_FAST_IDLE; - hdlc->bit_shift=1; - break; - } - } else { - hdlc->state = HDLC_GET_FLAG_B0; - } - break; - default: - hdlc->shift_reg>>=1; - hdlc->shift_reg |= 0x80; - hdlc->data_bits++; - break; - } - } else { - switch(hdlc->hdlc_bits1){ - case 5: - break; - case 6: - if(hdlc->data_received){ - if (hdlc->dstpos < 2) { - status = -HDLC_FRAMING_ERROR; - } else if (hdlc->crc != 0xf0b8){ - // crc error - status = -HDLC_CRC_ERROR; - } else { - // remove CRC - hdlc->dstpos -= 2; - // good frame - status = hdlc->dstpos; - } - } - hdlc->crc = 0xffff; - hdlc->shift_reg = 0; - hdlc->data_bits = 0; - if(!hdlc->do_adapt56){ - if(hdlc->cbin==fast_flag[hdlc->bit_shift]){ - hdlc->ffvalue = fast_flag_value[hdlc->bit_shift]; - hdlc->state = HDLC_FAST_FLAG; - hdlc->ffbit_shift = hdlc->bit_shift; - hdlc->bit_shift = 1; - } else { - hdlc->state = HDLC_GET_DATA; - hdlc->data_received = 0; - } - } else { - hdlc->state = HDLC_GET_DATA; - hdlc->data_received = 0; - } - break; - default: - hdlc->shift_reg>>=1; - hdlc->data_bits++; - break; - } - hdlc->hdlc_bits1 = 0; - } - if (status) { - hdlc->dstpos = 0; - *count -= slen; - hdlc->cbin <<= 1; - hdlc->bit_shift--; - return status; - } - if(hdlc->data_bits==8){ - hdlc->data_bits = 0; - hdlc->data_received = 1; - hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); - - // good byte received - if (hdlc->dstpos < dsize) { - dst[hdlc->dstpos++] = hdlc->shift_reg; - } else { - // frame too long - status = -HDLC_LENGTH_ERROR; - hdlc->dstpos = 0; - } - } - hdlc->cbin <<= 1; - hdlc->bit_shift--; - break; - case HDLC_FAST_FLAG: - if(hdlc->cbin==hdlc->ffvalue){ - hdlc->bit_shift = 0; - break; - } else { - if(hdlc->cbin == 0xff){ - hdlc->state = HDLC_FAST_IDLE; - hdlc->bit_shift=0; - } else if(hdlc->ffbit_shift==8){ - hdlc->state = HDLC_GETFLAG_B7; - break; - } else { - hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1]; - hdlc->hdlc_bits1 = hdlc->ffbit_shift-2; - if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0; - hdlc->data_bits = hdlc->ffbit_shift-1; - hdlc->state = HDLC_GET_DATA; - hdlc->data_received = 0; - } - } - break; - default: - break; - } - } - *count -= slen; - return 0; -} - -/* - isdnhdlc_encode - encodes HDLC frames to a transparent bit stream. - - The bit stream starts with a beginning flag (01111110). After - that each byte is added to the bit stream with bit stuffing added - (0 after 5 1's). - When the last byte has been removed from the source buffer, the - CRC (2 bytes is added) and the frame terminates with the ending flag. - For the dchannel, the idle character (all 1's) is also added at the end. - If this function is called with empty source buffer (slen=0), flags or - idle character will be generated. - - src - source buffer - slen - source buffer length - count - number of bytes removed (encoded) from source buffer - dst _ destination buffer - dsize - destination buffer size - returns - number of encoded bytes in the destination buffer -*/ -int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, - unsigned short slen, int *count, - unsigned char *dst, int dsize) -{ - static const unsigned char xfast_flag_value[] = { - 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e - }; - - int len = 0; - - *count = slen; - - while (dsize > 0) { - if(hdlc->bit_shift==0){ - if(slen && !hdlc->do_closing){ - hdlc->shift_reg = *src++; - slen--; - if (slen == 0) - hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */ - hdlc->bit_shift = 8; - } else { - if(hdlc->state == HDLC_SEND_DATA){ - if(hdlc->data_received){ - hdlc->state = HDLC_SEND_CRC1; - hdlc->crc ^= 0xffff; - hdlc->bit_shift = 8; - hdlc->shift_reg = hdlc->crc & 0xff; - } else if(!hdlc->do_adapt56){ - hdlc->state = HDLC_SEND_FAST_FLAG; - } else { - hdlc->state = HDLC_SENDFLAG_B0; - } - } - - } - } - - switch(hdlc->state){ - case STOPPED: - while (dsize--) - *dst++ = 0xff; - - return dsize; - case HDLC_SEND_FAST_FLAG: - hdlc->do_closing = 0; - if(slen == 0){ - *dst++ = hdlc->ffvalue; - len++; - dsize--; - break; - } - if(hdlc->bit_shift==8){ - hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits); - hdlc->state = HDLC_SEND_DATA; - hdlc->crc = 0xffff; - hdlc->hdlc_bits1 = 0; - hdlc->data_received = 1; - } - break; - case HDLC_SENDFLAG_B0: - hdlc->do_closing = 0; - hdlc->cbin <<= 1; - hdlc->data_bits++; - hdlc->hdlc_bits1 = 0; - hdlc->state = HDLC_SENDFLAG_B1A6; - break; - case HDLC_SENDFLAG_B1A6: - hdlc->cbin <<= 1; - hdlc->data_bits++; - hdlc->cbin++; - if(++hdlc->hdlc_bits1 == 6) - hdlc->state = HDLC_SENDFLAG_B7; - break; - case HDLC_SENDFLAG_B7: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if(slen == 0){ - hdlc->state = HDLC_SENDFLAG_B0; - break; - } - if(hdlc->bit_shift==8){ - hdlc->state = HDLC_SEND_DATA; - hdlc->crc = 0xffff; - hdlc->hdlc_bits1 = 0; - hdlc->data_received = 1; - } - break; - case HDLC_SEND_FIRST_FLAG: - hdlc->data_received = 1; - if(hdlc->data_bits==8){ - hdlc->state = HDLC_SEND_DATA; - hdlc->crc = 0xffff; - hdlc->hdlc_bits1 = 0; - break; - } - hdlc->cbin <<= 1; - hdlc->data_bits++; - if(hdlc->shift_reg & 0x01) - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - if(hdlc->bit_shift==0){ - hdlc->state = HDLC_SEND_DATA; - hdlc->crc = 0xffff; - hdlc->hdlc_bits1 = 0; - } - break; - case HDLC_SEND_DATA: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ - hdlc->hdlc_bits1 = 0; - break; - } - if(hdlc->bit_shift==8){ - hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); - } - if(hdlc->shift_reg & 0x01){ - hdlc->hdlc_bits1++; - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } else { - hdlc->hdlc_bits1 = 0; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } - break; - case HDLC_SEND_CRC1: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ - hdlc->hdlc_bits1 = 0; - break; - } - if(hdlc->shift_reg & 0x01){ - hdlc->hdlc_bits1++; - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } else { - hdlc->hdlc_bits1 = 0; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } - if(hdlc->bit_shift==0){ - hdlc->shift_reg = (hdlc->crc >> 8); - hdlc->state = HDLC_SEND_CRC2; - hdlc->bit_shift = 8; - } - break; - case HDLC_SEND_CRC2: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ - hdlc->hdlc_bits1 = 0; - break; - } - if(hdlc->shift_reg & 0x01){ - hdlc->hdlc_bits1++; - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } else { - hdlc->hdlc_bits1 = 0; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } - if(hdlc->bit_shift==0){ - hdlc->shift_reg = 0x7e; - hdlc->state = HDLC_SEND_CLOSING_FLAG; - hdlc->bit_shift = 8; - } - break; - case HDLC_SEND_CLOSING_FLAG: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ - hdlc->hdlc_bits1 = 0; - break; - } - if(hdlc->shift_reg & 0x01){ - hdlc->cbin++; - } - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - if(hdlc->bit_shift==0){ - hdlc->ffvalue = xfast_flag_value[hdlc->data_bits]; - if(hdlc->dchannel){ - hdlc->ffvalue = 0x7e; - hdlc->state = HDLC_SEND_IDLE1; - hdlc->bit_shift = 8-hdlc->data_bits; - if(hdlc->bit_shift==0) - hdlc->state = HDLC_SEND_FAST_IDLE; - } else { - if(!hdlc->do_adapt56){ - hdlc->state = HDLC_SEND_FAST_FLAG; - hdlc->data_received = 0; - } else { - hdlc->state = HDLC_SENDFLAG_B0; - hdlc->data_received = 0; - } - // Finished with this frame, send flags - if (dsize > 1) dsize = 1; - } - } - break; - case HDLC_SEND_IDLE1: - hdlc->do_closing = 0; - hdlc->cbin <<= 1; - hdlc->cbin++; - hdlc->data_bits++; - hdlc->bit_shift--; - if(hdlc->bit_shift==0){ - hdlc->state = HDLC_SEND_FAST_IDLE; - hdlc->bit_shift = 0; - } - break; - case HDLC_SEND_FAST_IDLE: - hdlc->do_closing = 0; - hdlc->cbin = 0xff; - hdlc->data_bits = 8; - if(hdlc->bit_shift == 8){ - hdlc->cbin = 0x7e; - hdlc->state = HDLC_SEND_FIRST_FLAG; - } else { - *dst++ = hdlc->cbin; - hdlc->bit_shift = hdlc->data_bits = 0; - len++; - dsize = 0; - } - break; - default: - break; - } - if(hdlc->do_adapt56){ - if(hdlc->data_bits==7){ - hdlc->cbin <<= 1; - hdlc->cbin++; - hdlc->data_bits++; - } - } - if(hdlc->data_bits==8){ - *dst++ = hdlc->cbin; - hdlc->data_bits = 0; - len++; - dsize--; - } - } - *count -= slen; - - return len; -} - -EXPORT_SYMBOL(isdnhdlc_rcv_init); -EXPORT_SYMBOL(isdnhdlc_decode); -EXPORT_SYMBOL(isdnhdlc_out_init); -EXPORT_SYMBOL(isdnhdlc_encode); diff --git a/drivers/isdn/hisax/isdnhdlc.h b/drivers/isdn/hisax/isdnhdlc.h deleted file mode 100644 index cf0a95a2401..00000000000 --- a/drivers/isdn/hisax/isdnhdlc.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * isdnhdlc.h -- General purpose ISDN HDLC decoder. - * - * Implementation of a HDLC decoder/encoder in software. - * Neccessary because some ISDN devices don't have HDLC - * controllers. Also included: a bit reversal table. - * - *Copyright (C) 2002 Wolfgang Mües - * 2001 Frode Isaksen - * 2001 Kai Germaschewski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __ISDNHDLC_H__ -#define __ISDNHDLC_H__ - -struct isdnhdlc_vars { - int bit_shift; - int hdlc_bits1; - int data_bits; - int ffbit_shift; // encoding only - int state; - int dstpos; - - unsigned short crc; - - unsigned char cbin; - unsigned char shift_reg; - unsigned char ffvalue; - - unsigned int data_received:1; // set if transferring data - unsigned int dchannel:1; // set if D channel (send idle instead of flags) - unsigned int do_adapt56:1; // set if 56K adaptation - unsigned int do_closing:1; // set if in closing phase (need to send CRC + flag -}; - - -/* - The return value from isdnhdlc_decode is - the frame length, 0 if no complete frame was decoded, - or a negative error number -*/ -#define HDLC_FRAMING_ERROR 1 -#define HDLC_CRC_ERROR 2 -#define HDLC_LENGTH_ERROR 3 - -extern void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56); - -extern int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, int slen,int *count, - unsigned char *dst, int dsize); - -extern void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc,int is_d_channel,int do_adapt56); - -extern int isdnhdlc_encode (struct isdnhdlc_vars *hdlc,const unsigned char *src,unsigned short slen,int *count, - unsigned char *dst,int dsize); - -#endif /* __ISDNHDLC_H__ */ diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h index cff7a635433..64f78a8c28c 100644 --- a/drivers/isdn/hisax/st5481.h +++ b/drivers/isdn/hisax/st5481.h @@ -226,7 +226,7 @@ printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__, __func__ , ## arg) #define INFO(format, arg...) \ printk(KERN_INFO "%s:%s: " format "\n" , __FILE__, __func__ , ## arg) -#include "isdnhdlc.h" +#include #include "fsm.h" #include "hisax_if.h" #include diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig index ed3510f273d..dd744ffd240 100644 --- a/drivers/isdn/i4l/Kconfig +++ b/drivers/isdn/i4l/Kconfig @@ -2,6 +2,8 @@ # Old ISDN4Linux config # +if ISDN_I4L + config ISDN_PPP bool "Support synchronous PPP" depends on INET @@ -135,3 +137,12 @@ source "drivers/isdn/act2000/Kconfig" source "drivers/isdn/hysdn/Kconfig" endmenu +# end ISDN_I4L +endif + +config ISDN_HDLC + tristate + depends on HISAX_ST5481 + select CRC_CCITT + select BITREVERSE + diff --git a/drivers/isdn/i4l/Makefile b/drivers/isdn/i4l/Makefile index 49a06c0005d..cb9d3bb9fae 100644 --- a/drivers/isdn/i4l/Makefile +++ b/drivers/isdn/i4l/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_ISDN_I4L) += isdn.o obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o +obj-$(CONFIG_ISDN_HDLC) += isdnhdlc.o # Multipart objects. diff --git a/drivers/isdn/i4l/isdnhdlc.c b/drivers/isdn/i4l/isdnhdlc.c new file mode 100644 index 00000000000..44ec7418496 --- /dev/null +++ b/drivers/isdn/i4l/isdnhdlc.c @@ -0,0 +1,603 @@ +/* + * isdnhdlc.c -- General purpose ISDN HDLC decoder. + * + *Copyright (C) 2002 Wolfgang Mües + * 2001 Frode Isaksen + * 2001 Kai Germaschewski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +/*-------------------------------------------------------------------*/ + +MODULE_AUTHOR("Wolfgang Mües , " + "Frode Isaksen , " + "Kai Germaschewski "); +MODULE_DESCRIPTION("General purpose ISDN HDLC decoder"); +MODULE_LICENSE("GPL"); + +/*-------------------------------------------------------------------*/ + +enum { + HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7, + HDLC_GET_DATA,HDLC_FAST_FLAG +}; + +enum { + HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG, + HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG, + HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0, + HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED +}; + +void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56) +{ + hdlc->bit_shift = 0; + hdlc->hdlc_bits1 = 0; + hdlc->data_bits = 0; + hdlc->ffbit_shift = 0; + hdlc->data_received = 0; + hdlc->state = HDLC_GET_DATA; + hdlc->do_adapt56 = do_adapt56; + hdlc->dchannel = 0; + hdlc->crc = 0; + hdlc->cbin = 0; + hdlc->shift_reg = 0; + hdlc->ffvalue = 0; + hdlc->dstpos = 0; +} + +void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_adapt56) +{ + hdlc->bit_shift = 0; + hdlc->hdlc_bits1 = 0; + hdlc->data_bits = 0; + hdlc->ffbit_shift = 0; + hdlc->data_received = 0; + hdlc->do_closing = 0; + hdlc->ffvalue = 0; + if (is_d_channel) { + hdlc->dchannel = 1; + hdlc->state = HDLC_SEND_FIRST_FLAG; + } else { + hdlc->dchannel = 0; + hdlc->state = HDLC_SEND_FAST_FLAG; + hdlc->ffvalue = 0x7e; + } + hdlc->cbin = 0x7e; + hdlc->bit_shift = 0; + if(do_adapt56){ + hdlc->do_adapt56 = 1; + hdlc->data_bits = 0; + hdlc->state = HDLC_SENDFLAG_B0; + } else { + hdlc->do_adapt56 = 0; + hdlc->data_bits = 8; + } + hdlc->shift_reg = 0; +} + +/* + isdnhdlc_decode - decodes HDLC frames from a transparent bit stream. + + The source buffer is scanned for valid HDLC frames looking for + flags (01111110) to indicate the start of a frame. If the start of + the frame is found, the bit stuffing is removed (0 after 5 1's). + When a new flag is found, the complete frame has been received + and the CRC is checked. + If a valid frame is found, the function returns the frame length + excluding the CRC with the bit HDLC_END_OF_FRAME set. + If the beginning of a valid frame is found, the function returns + the length. + If a framing error is found (too many 1s and not a flag) the function + returns the length with the bit HDLC_FRAMING_ERROR set. + If a CRC error is found the function returns the length with the + bit HDLC_CRC_ERROR set. + If the frame length exceeds the destination buffer size, the function + returns the length with the bit HDLC_LENGTH_ERROR set. + + src - source buffer + slen - source buffer length + count - number of bytes removed (decoded) from the source buffer + dst _ destination buffer + dsize - destination buffer size + returns - number of decoded bytes in the destination buffer and status + flag. + */ +int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, + int slen, int *count, unsigned char *dst, int dsize) +{ + int status=0; + + static const unsigned char fast_flag[]={ + 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f + }; + + static const unsigned char fast_flag_value[]={ + 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f + }; + + static const unsigned char fast_abort[]={ + 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff + }; + + *count = slen; + + while(slen > 0){ + if(hdlc->bit_shift==0){ + hdlc->cbin = *src++; + slen--; + hdlc->bit_shift = 8; + if(hdlc->do_adapt56){ + hdlc->bit_shift --; + } + } + + switch(hdlc->state){ + case STOPPED: + return 0; + case HDLC_FAST_IDLE: + if(hdlc->cbin == 0xff){ + hdlc->bit_shift = 0; + break; + } + hdlc->state = HDLC_GET_FLAG_B0; + hdlc->hdlc_bits1 = 0; + hdlc->bit_shift = 8; + break; + case HDLC_GET_FLAG_B0: + if(!(hdlc->cbin & 0x80)) { + hdlc->state = HDLC_GETFLAG_B1A6; + hdlc->hdlc_bits1 = 0; + } else { + if(!hdlc->do_adapt56){ + if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1) + hdlc->state = HDLC_FAST_IDLE; + } + } + hdlc->cbin<<=1; + hdlc->bit_shift --; + break; + case HDLC_GETFLAG_B1A6: + if(hdlc->cbin & 0x80){ + hdlc->hdlc_bits1++; + if(hdlc->hdlc_bits1==6){ + hdlc->state = HDLC_GETFLAG_B7; + } + } else { + hdlc->hdlc_bits1 = 0; + } + hdlc->cbin<<=1; + hdlc->bit_shift --; + break; + case HDLC_GETFLAG_B7: + if(hdlc->cbin & 0x80) { + hdlc->state = HDLC_GET_FLAG_B0; + } else { + hdlc->state = HDLC_GET_DATA; + hdlc->crc = 0xffff; + hdlc->shift_reg = 0; + hdlc->hdlc_bits1 = 0; + hdlc->data_bits = 0; + hdlc->data_received = 0; + } + hdlc->cbin<<=1; + hdlc->bit_shift --; + break; + case HDLC_GET_DATA: + if(hdlc->cbin & 0x80){ + hdlc->hdlc_bits1++; + switch(hdlc->hdlc_bits1){ + case 6: + break; + case 7: + if(hdlc->data_received) { + // bad frame + status = -HDLC_FRAMING_ERROR; + } + if(!hdlc->do_adapt56){ + if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){ + hdlc->state = HDLC_FAST_IDLE; + hdlc->bit_shift=1; + break; + } + } else { + hdlc->state = HDLC_GET_FLAG_B0; + } + break; + default: + hdlc->shift_reg>>=1; + hdlc->shift_reg |= 0x80; + hdlc->data_bits++; + break; + } + } else { + switch(hdlc->hdlc_bits1){ + case 5: + break; + case 6: + if(hdlc->data_received){ + if (hdlc->dstpos < 2) { + status = -HDLC_FRAMING_ERROR; + } else if (hdlc->crc != 0xf0b8){ + // crc error + status = -HDLC_CRC_ERROR; + } else { + // remove CRC + hdlc->dstpos -= 2; + // good frame + status = hdlc->dstpos; + } + } + hdlc->crc = 0xffff; + hdlc->shift_reg = 0; + hdlc->data_bits = 0; + if(!hdlc->do_adapt56){ + if(hdlc->cbin==fast_flag[hdlc->bit_shift]){ + hdlc->ffvalue = fast_flag_value[hdlc->bit_shift]; + hdlc->state = HDLC_FAST_FLAG; + hdlc->ffbit_shift = hdlc->bit_shift; + hdlc->bit_shift = 1; + } else { + hdlc->state = HDLC_GET_DATA; + hdlc->data_received = 0; + } + } else { + hdlc->state = HDLC_GET_DATA; + hdlc->data_received = 0; + } + break; + default: + hdlc->shift_reg>>=1; + hdlc->data_bits++; + break; + } + hdlc->hdlc_bits1 = 0; + } + if (status) { + hdlc->dstpos = 0; + *count -= slen; + hdlc->cbin <<= 1; + hdlc->bit_shift--; + return status; + } + if(hdlc->data_bits==8){ + hdlc->data_bits = 0; + hdlc->data_received = 1; + hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); + + // good byte received + if (hdlc->dstpos < dsize) { + dst[hdlc->dstpos++] = hdlc->shift_reg; + } else { + // frame too long + status = -HDLC_LENGTH_ERROR; + hdlc->dstpos = 0; + } + } + hdlc->cbin <<= 1; + hdlc->bit_shift--; + break; + case HDLC_FAST_FLAG: + if(hdlc->cbin==hdlc->ffvalue){ + hdlc->bit_shift = 0; + break; + } else { + if(hdlc->cbin == 0xff){ + hdlc->state = HDLC_FAST_IDLE; + hdlc->bit_shift=0; + } else if(hdlc->ffbit_shift==8){ + hdlc->state = HDLC_GETFLAG_B7; + break; + } else { + hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1]; + hdlc->hdlc_bits1 = hdlc->ffbit_shift-2; + if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0; + hdlc->data_bits = hdlc->ffbit_shift-1; + hdlc->state = HDLC_GET_DATA; + hdlc->data_received = 0; + } + } + break; + default: + break; + } + } + *count -= slen; + return 0; +} + +/* + isdnhdlc_encode - encodes HDLC frames to a transparent bit stream. + + The bit stream starts with a beginning flag (01111110). After + that each byte is added to the bit stream with bit stuffing added + (0 after 5 1's). + When the last byte has been removed from the source buffer, the + CRC (2 bytes is added) and the frame terminates with the ending flag. + For the dchannel, the idle character (all 1's) is also added at the end. + If this function is called with empty source buffer (slen=0), flags or + idle character will be generated. + + src - source buffer + slen - source buffer length + count - number of bytes removed (encoded) from source buffer + dst _ destination buffer + dsize - destination buffer size + returns - number of encoded bytes in the destination buffer +*/ +int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, + unsigned short slen, int *count, + unsigned char *dst, int dsize) +{ + static const unsigned char xfast_flag_value[] = { + 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e + }; + + int len = 0; + + *count = slen; + + while (dsize > 0) { + if(hdlc->bit_shift==0){ + if(slen && !hdlc->do_closing){ + hdlc->shift_reg = *src++; + slen--; + if (slen == 0) + hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */ + hdlc->bit_shift = 8; + } else { + if(hdlc->state == HDLC_SEND_DATA){ + if(hdlc->data_received){ + hdlc->state = HDLC_SEND_CRC1; + hdlc->crc ^= 0xffff; + hdlc->bit_shift = 8; + hdlc->shift_reg = hdlc->crc & 0xff; + } else if(!hdlc->do_adapt56){ + hdlc->state = HDLC_SEND_FAST_FLAG; + } else { + hdlc->state = HDLC_SENDFLAG_B0; + } + } + + } + } + + switch(hdlc->state){ + case STOPPED: + while (dsize--) + *dst++ = 0xff; + + return dsize; + case HDLC_SEND_FAST_FLAG: + hdlc->do_closing = 0; + if(slen == 0){ + *dst++ = hdlc->ffvalue; + len++; + dsize--; + break; + } + if(hdlc->bit_shift==8){ + hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits); + hdlc->state = HDLC_SEND_DATA; + hdlc->crc = 0xffff; + hdlc->hdlc_bits1 = 0; + hdlc->data_received = 1; + } + break; + case HDLC_SENDFLAG_B0: + hdlc->do_closing = 0; + hdlc->cbin <<= 1; + hdlc->data_bits++; + hdlc->hdlc_bits1 = 0; + hdlc->state = HDLC_SENDFLAG_B1A6; + break; + case HDLC_SENDFLAG_B1A6: + hdlc->cbin <<= 1; + hdlc->data_bits++; + hdlc->cbin++; + if(++hdlc->hdlc_bits1 == 6) + hdlc->state = HDLC_SENDFLAG_B7; + break; + case HDLC_SENDFLAG_B7: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(slen == 0){ + hdlc->state = HDLC_SENDFLAG_B0; + break; + } + if(hdlc->bit_shift==8){ + hdlc->state = HDLC_SEND_DATA; + hdlc->crc = 0xffff; + hdlc->hdlc_bits1 = 0; + hdlc->data_received = 1; + } + break; + case HDLC_SEND_FIRST_FLAG: + hdlc->data_received = 1; + if(hdlc->data_bits==8){ + hdlc->state = HDLC_SEND_DATA; + hdlc->crc = 0xffff; + hdlc->hdlc_bits1 = 0; + break; + } + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(hdlc->shift_reg & 0x01) + hdlc->cbin++; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + if(hdlc->bit_shift==0){ + hdlc->state = HDLC_SEND_DATA; + hdlc->crc = 0xffff; + hdlc->hdlc_bits1 = 0; + } + break; + case HDLC_SEND_DATA: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(hdlc->hdlc_bits1 == 5){ + hdlc->hdlc_bits1 = 0; + break; + } + if(hdlc->bit_shift==8){ + hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); + } + if(hdlc->shift_reg & 0x01){ + hdlc->hdlc_bits1++; + hdlc->cbin++; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } else { + hdlc->hdlc_bits1 = 0; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } + break; + case HDLC_SEND_CRC1: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(hdlc->hdlc_bits1 == 5){ + hdlc->hdlc_bits1 = 0; + break; + } + if(hdlc->shift_reg & 0x01){ + hdlc->hdlc_bits1++; + hdlc->cbin++; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } else { + hdlc->hdlc_bits1 = 0; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } + if(hdlc->bit_shift==0){ + hdlc->shift_reg = (hdlc->crc >> 8); + hdlc->state = HDLC_SEND_CRC2; + hdlc->bit_shift = 8; + } + break; + case HDLC_SEND_CRC2: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(hdlc->hdlc_bits1 == 5){ + hdlc->hdlc_bits1 = 0; + break; + } + if(hdlc->shift_reg & 0x01){ + hdlc->hdlc_bits1++; + hdlc->cbin++; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } else { + hdlc->hdlc_bits1 = 0; + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + } + if(hdlc->bit_shift==0){ + hdlc->shift_reg = 0x7e; + hdlc->state = HDLC_SEND_CLOSING_FLAG; + hdlc->bit_shift = 8; + } + break; + case HDLC_SEND_CLOSING_FLAG: + hdlc->cbin <<= 1; + hdlc->data_bits++; + if(hdlc->hdlc_bits1 == 5){ + hdlc->hdlc_bits1 = 0; + break; + } + if(hdlc->shift_reg & 0x01){ + hdlc->cbin++; + } + hdlc->shift_reg >>= 1; + hdlc->bit_shift--; + if(hdlc->bit_shift==0){ + hdlc->ffvalue = xfast_flag_value[hdlc->data_bits]; + if(hdlc->dchannel){ + hdlc->ffvalue = 0x7e; + hdlc->state = HDLC_SEND_IDLE1; + hdlc->bit_shift = 8-hdlc->data_bits; + if(hdlc->bit_shift==0) + hdlc->state = HDLC_SEND_FAST_IDLE; + } else { + if(!hdlc->do_adapt56){ + hdlc->state = HDLC_SEND_FAST_FLAG; + hdlc->data_received = 0; + } else { + hdlc->state = HDLC_SENDFLAG_B0; + hdlc->data_received = 0; + } + // Finished with this frame, send flags + if (dsize > 1) dsize = 1; + } + } + break; + case HDLC_SEND_IDLE1: + hdlc->do_closing = 0; + hdlc->cbin <<= 1; + hdlc->cbin++; + hdlc->data_bits++; + hdlc->bit_shift--; + if(hdlc->bit_shift==0){ + hdlc->state = HDLC_SEND_FAST_IDLE; + hdlc->bit_shift = 0; + } + break; + case HDLC_SEND_FAST_IDLE: + hdlc->do_closing = 0; + hdlc->cbin = 0xff; + hdlc->data_bits = 8; + if(hdlc->bit_shift == 8){ + hdlc->cbin = 0x7e; + hdlc->state = HDLC_SEND_FIRST_FLAG; + } else { + *dst++ = hdlc->cbin; + hdlc->bit_shift = hdlc->data_bits = 0; + len++; + dsize = 0; + } + break; + default: + break; + } + if(hdlc->do_adapt56){ + if(hdlc->data_bits==7){ + hdlc->cbin <<= 1; + hdlc->cbin++; + hdlc->data_bits++; + } + } + if(hdlc->data_bits==8){ + *dst++ = hdlc->cbin; + hdlc->data_bits = 0; + len++; + dsize--; + } + } + *count -= slen; + + return len; +} + +EXPORT_SYMBOL(isdnhdlc_rcv_init); +EXPORT_SYMBOL(isdnhdlc_decode); +EXPORT_SYMBOL(isdnhdlc_out_init); +EXPORT_SYMBOL(isdnhdlc_encode); -- cgit v1.2.3-18-g5258 From 6bd4bcd3cd8affc09eaee7efbc037f65f4a71501 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 8 Jul 2009 19:11:09 +0200 Subject: ISDN: Clean up isdnhdlc code Clean up isdnhdlc to meet current code standard. Remove hint to already removed bit reversal table. Signed-off-by: Karsten Keil --- drivers/isdn/i4l/isdnhdlc.c | 366 +++++++++++++++++++++++--------------------- 1 file changed, 194 insertions(+), 172 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/i4l/isdnhdlc.c b/drivers/isdn/i4l/isdnhdlc.c index 44ec7418496..b80e55ab891 100644 --- a/drivers/isdn/i4l/isdnhdlc.c +++ b/drivers/isdn/i4l/isdnhdlc.c @@ -1,23 +1,24 @@ /* * isdnhdlc.c -- General purpose ISDN HDLC decoder. * - *Copyright (C) 2002 Wolfgang Mües - * 2001 Frode Isaksen - * 2001 Kai Germaschewski + * Copyright (C) + * 2002 Wolfgang Mües + * 2001 Frode Isaksen + * 2001 Kai Germaschewski * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include @@ -36,20 +37,20 @@ MODULE_LICENSE("GPL"); /*-------------------------------------------------------------------*/ enum { - HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7, - HDLC_GET_DATA,HDLC_FAST_FLAG + HDLC_FAST_IDLE, HDLC_GET_FLAG_B0, HDLC_GETFLAG_B1A6, HDLC_GETFLAG_B7, + HDLC_GET_DATA, HDLC_FAST_FLAG }; enum { - HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG, - HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG, - HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0, - HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED + HDLC_SEND_DATA, HDLC_SEND_CRC1, HDLC_SEND_FAST_FLAG, + HDLC_SEND_FIRST_FLAG, HDLC_SEND_CRC2, HDLC_SEND_CLOSING_FLAG, + HDLC_SEND_IDLE1, HDLC_SEND_FAST_IDLE, HDLC_SENDFLAG_B0, + HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED }; -void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56) +void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, int do_adapt56) { - hdlc->bit_shift = 0; + hdlc->bit_shift = 0; hdlc->hdlc_bits1 = 0; hdlc->data_bits = 0; hdlc->ffbit_shift = 0; @@ -63,10 +64,12 @@ void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56) hdlc->ffvalue = 0; hdlc->dstpos = 0; } +EXPORT_SYMBOL(isdnhdlc_out_init); -void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_adapt56) +void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, int is_d_channel, + int do_adapt56) { - hdlc->bit_shift = 0; + hdlc->bit_shift = 0; hdlc->hdlc_bits1 = 0; hdlc->data_bits = 0; hdlc->ffbit_shift = 0; @@ -83,7 +86,7 @@ void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_ada } hdlc->cbin = 0x7e; hdlc->bit_shift = 0; - if(do_adapt56){ + if (do_adapt56) { hdlc->do_adapt56 = 1; hdlc->data_bits = 0; hdlc->state = HDLC_SENDFLAG_B0; @@ -93,6 +96,25 @@ void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_ada } hdlc->shift_reg = 0; } +EXPORT_SYMBOL(isdnhdlc_rcv_init); + +static int +check_frame(struct isdnhdlc_vars *hdlc) +{ + int status; + + if (hdlc->dstpos < 2) /* too small - framing error */ + status = -HDLC_FRAMING_ERROR; + else if (hdlc->crc != 0xf0b8) /* crc error */ + status = -HDLC_CRC_ERROR; + else { + /* remove CRC */ + hdlc->dstpos -= 2; + /* good frame */ + status = hdlc->dstpos; + } + return status; +} /* isdnhdlc_decode - decodes HDLC frames from a transparent bit stream. @@ -121,40 +143,63 @@ void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_ada returns - number of decoded bytes in the destination buffer and status flag. */ -int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, - int slen, int *count, unsigned char *dst, int dsize) +int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen, + int *count, u8 *dst, int dsize) { - int status=0; + int status = 0; - static const unsigned char fast_flag[]={ - 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f + static const unsigned char fast_flag[] = { + 0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x3c, 0x3e, 0x3f }; - static const unsigned char fast_flag_value[]={ - 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f + static const unsigned char fast_flag_value[] = { + 0x00, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f }; - static const unsigned char fast_abort[]={ - 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff + static const unsigned char fast_abort[] = { + 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; +#define handle_fast_flag(h) \ + do {\ + if (h->cbin == fast_flag[h->bit_shift]) {\ + h->ffvalue = fast_flag_value[h->bit_shift];\ + h->state = HDLC_FAST_FLAG;\ + h->ffbit_shift = h->bit_shift;\ + h->bit_shift = 1;\ + } else {\ + h->state = HDLC_GET_DATA;\ + h->data_received = 0;\ + } \ + } while (0) + +#define handle_abort(h) \ + do {\ + h->shift_reg = fast_abort[h->ffbit_shift - 1];\ + h->hdlc_bits1 = h->ffbit_shift - 2;\ + if (h->hdlc_bits1 < 0)\ + h->hdlc_bits1 = 0;\ + h->data_bits = h->ffbit_shift - 1;\ + h->state = HDLC_GET_DATA;\ + h->data_received = 0;\ + } while (0) + *count = slen; - while(slen > 0){ - if(hdlc->bit_shift==0){ + while (slen > 0) { + if (hdlc->bit_shift == 0) { hdlc->cbin = *src++; slen--; hdlc->bit_shift = 8; - if(hdlc->do_adapt56){ - hdlc->bit_shift --; - } + if (hdlc->do_adapt56) + hdlc->bit_shift--; } - switch(hdlc->state){ + switch (hdlc->state) { case STOPPED: return 0; case HDLC_FAST_IDLE: - if(hdlc->cbin == 0xff){ + if (hdlc->cbin == 0xff) { hdlc->bit_shift = 0; break; } @@ -163,32 +208,30 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->bit_shift = 8; break; case HDLC_GET_FLAG_B0: - if(!(hdlc->cbin & 0x80)) { + if (!(hdlc->cbin & 0x80)) { hdlc->state = HDLC_GETFLAG_B1A6; hdlc->hdlc_bits1 = 0; } else { - if(!hdlc->do_adapt56){ - if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1) + if ((!hdlc->do_adapt56) && + (++hdlc->hdlc_bits1 >= 8) && + (hdlc->bit_shift == 1)) hdlc->state = HDLC_FAST_IDLE; - } } - hdlc->cbin<<=1; - hdlc->bit_shift --; + hdlc->cbin <<= 1; + hdlc->bit_shift--; break; case HDLC_GETFLAG_B1A6: - if(hdlc->cbin & 0x80){ + if (hdlc->cbin & 0x80) { hdlc->hdlc_bits1++; - if(hdlc->hdlc_bits1==6){ + if (hdlc->hdlc_bits1 == 6) hdlc->state = HDLC_GETFLAG_B7; - } - } else { + } else hdlc->hdlc_bits1 = 0; - } - hdlc->cbin<<=1; - hdlc->bit_shift --; + hdlc->cbin <<= 1; + hdlc->bit_shift--; break; case HDLC_GETFLAG_B7: - if(hdlc->cbin & 0x80) { + if (hdlc->cbin & 0x80) { hdlc->state = HDLC_GET_FLAG_B0; } else { hdlc->state = HDLC_GET_DATA; @@ -198,74 +241,55 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->data_bits = 0; hdlc->data_received = 0; } - hdlc->cbin<<=1; - hdlc->bit_shift --; + hdlc->cbin <<= 1; + hdlc->bit_shift--; break; case HDLC_GET_DATA: - if(hdlc->cbin & 0x80){ + if (hdlc->cbin & 0x80) { hdlc->hdlc_bits1++; - switch(hdlc->hdlc_bits1){ + switch (hdlc->hdlc_bits1) { case 6: break; case 7: - if(hdlc->data_received) { - // bad frame + if (hdlc->data_received) + /* bad frame */ status = -HDLC_FRAMING_ERROR; - } - if(!hdlc->do_adapt56){ - if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){ - hdlc->state = HDLC_FAST_IDLE; - hdlc->bit_shift=1; + if (!hdlc->do_adapt56) { + if (hdlc->cbin == fast_abort + [hdlc->bit_shift + 1]) { + hdlc->state = + HDLC_FAST_IDLE; + hdlc->bit_shift = 1; break; } - } else { + } else hdlc->state = HDLC_GET_FLAG_B0; - } break; default: - hdlc->shift_reg>>=1; + hdlc->shift_reg >>= 1; hdlc->shift_reg |= 0x80; hdlc->data_bits++; break; } } else { - switch(hdlc->hdlc_bits1){ + switch (hdlc->hdlc_bits1) { case 5: break; case 6: - if(hdlc->data_received){ - if (hdlc->dstpos < 2) { - status = -HDLC_FRAMING_ERROR; - } else if (hdlc->crc != 0xf0b8){ - // crc error - status = -HDLC_CRC_ERROR; - } else { - // remove CRC - hdlc->dstpos -= 2; - // good frame - status = hdlc->dstpos; - } - } + if (hdlc->data_received) + status = check_frame(hdlc); hdlc->crc = 0xffff; hdlc->shift_reg = 0; hdlc->data_bits = 0; - if(!hdlc->do_adapt56){ - if(hdlc->cbin==fast_flag[hdlc->bit_shift]){ - hdlc->ffvalue = fast_flag_value[hdlc->bit_shift]; - hdlc->state = HDLC_FAST_FLAG; - hdlc->ffbit_shift = hdlc->bit_shift; - hdlc->bit_shift = 1; - } else { - hdlc->state = HDLC_GET_DATA; - hdlc->data_received = 0; - } - } else { + if (!hdlc->do_adapt56) + handle_fast_flag(hdlc); + else { hdlc->state = HDLC_GET_DATA; hdlc->data_received = 0; } break; default: - hdlc->shift_reg>>=1; + hdlc->shift_reg >>= 1; hdlc->data_bits++; break; } @@ -278,16 +302,17 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->bit_shift--; return status; } - if(hdlc->data_bits==8){ + if (hdlc->data_bits == 8) { hdlc->data_bits = 0; hdlc->data_received = 1; - hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); + hdlc->crc = crc_ccitt_byte(hdlc->crc, + hdlc->shift_reg); - // good byte received - if (hdlc->dstpos < dsize) { + /* good byte received */ + if (hdlc->dstpos < dsize) dst[hdlc->dstpos++] = hdlc->shift_reg; - } else { - // frame too long + else { + /* frame too long */ status = -HDLC_LENGTH_ERROR; hdlc->dstpos = 0; } @@ -296,24 +321,18 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->bit_shift--; break; case HDLC_FAST_FLAG: - if(hdlc->cbin==hdlc->ffvalue){ + if (hdlc->cbin == hdlc->ffvalue) { hdlc->bit_shift = 0; break; } else { - if(hdlc->cbin == 0xff){ + if (hdlc->cbin == 0xff) { hdlc->state = HDLC_FAST_IDLE; - hdlc->bit_shift=0; - } else if(hdlc->ffbit_shift==8){ + hdlc->bit_shift = 0; + } else if (hdlc->ffbit_shift == 8) { hdlc->state = HDLC_GETFLAG_B7; break; - } else { - hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1]; - hdlc->hdlc_bits1 = hdlc->ffbit_shift-2; - if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0; - hdlc->data_bits = hdlc->ffbit_shift-1; - hdlc->state = HDLC_GET_DATA; - hdlc->data_received = 0; - } + } else + handle_abort(hdlc); } break; default: @@ -323,7 +342,7 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, *count -= slen; return 0; } - +EXPORT_SYMBOL(isdnhdlc_decode); /* isdnhdlc_encode - encodes HDLC frames to a transparent bit stream. @@ -343,12 +362,11 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, dsize - destination buffer size returns - number of encoded bytes in the destination buffer */ -int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, - unsigned short slen, int *count, - unsigned char *dst, int dsize) +int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, + int *count, u8 *dst, int dsize) { static const unsigned char xfast_flag_value[] = { - 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e + 0x7e, 0x3f, 0x9f, 0xcf, 0xe7, 0xf3, 0xf9, 0xfc, 0x7e }; int len = 0; @@ -356,31 +374,34 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, *count = slen; while (dsize > 0) { - if(hdlc->bit_shift==0){ - if(slen && !hdlc->do_closing){ + if (hdlc->bit_shift == 0) { + if (slen && !hdlc->do_closing) { hdlc->shift_reg = *src++; slen--; if (slen == 0) - hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */ + /* closing sequence, CRC + flag(s) */ + hdlc->do_closing = 1; hdlc->bit_shift = 8; } else { - if(hdlc->state == HDLC_SEND_DATA){ - if(hdlc->data_received){ + if (hdlc->state == HDLC_SEND_DATA) { + if (hdlc->data_received) { hdlc->state = HDLC_SEND_CRC1; hdlc->crc ^= 0xffff; hdlc->bit_shift = 8; - hdlc->shift_reg = hdlc->crc & 0xff; - } else if(!hdlc->do_adapt56){ - hdlc->state = HDLC_SEND_FAST_FLAG; - } else { - hdlc->state = HDLC_SENDFLAG_B0; - } + hdlc->shift_reg = + hdlc->crc & 0xff; + } else if (!hdlc->do_adapt56) + hdlc->state = + HDLC_SEND_FAST_FLAG; + else + hdlc->state = + HDLC_SENDFLAG_B0; } } } - switch(hdlc->state){ + switch (hdlc->state) { case STOPPED: while (dsize--) *dst++ = 0xff; @@ -388,14 +409,15 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, return dsize; case HDLC_SEND_FAST_FLAG: hdlc->do_closing = 0; - if(slen == 0){ + if (slen == 0) { *dst++ = hdlc->ffvalue; len++; dsize--; break; } - if(hdlc->bit_shift==8){ - hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits); + if (hdlc->bit_shift == 8) { + hdlc->cbin = hdlc->ffvalue >> + (8 - hdlc->data_bits); hdlc->state = HDLC_SEND_DATA; hdlc->crc = 0xffff; hdlc->hdlc_bits1 = 0; @@ -413,17 +435,17 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->cbin <<= 1; hdlc->data_bits++; hdlc->cbin++; - if(++hdlc->hdlc_bits1 == 6) + if (++hdlc->hdlc_bits1 == 6) hdlc->state = HDLC_SENDFLAG_B7; break; case HDLC_SENDFLAG_B7: hdlc->cbin <<= 1; hdlc->data_bits++; - if(slen == 0){ + if (slen == 0) { hdlc->state = HDLC_SENDFLAG_B0; break; } - if(hdlc->bit_shift==8){ + if (hdlc->bit_shift == 8) { hdlc->state = HDLC_SEND_DATA; hdlc->crc = 0xffff; hdlc->hdlc_bits1 = 0; @@ -432,7 +454,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, break; case HDLC_SEND_FIRST_FLAG: hdlc->data_received = 1; - if(hdlc->data_bits==8){ + if (hdlc->data_bits == 8) { hdlc->state = HDLC_SEND_DATA; hdlc->crc = 0xffff; hdlc->hdlc_bits1 = 0; @@ -440,11 +462,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, } hdlc->cbin <<= 1; hdlc->data_bits++; - if(hdlc->shift_reg & 0x01) + if (hdlc->shift_reg & 0x01) hdlc->cbin++; hdlc->shift_reg >>= 1; hdlc->bit_shift--; - if(hdlc->bit_shift==0){ + if (hdlc->bit_shift == 0) { hdlc->state = HDLC_SEND_DATA; hdlc->crc = 0xffff; hdlc->hdlc_bits1 = 0; @@ -453,14 +475,14 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, case HDLC_SEND_DATA: hdlc->cbin <<= 1; hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ + if (hdlc->hdlc_bits1 == 5) { hdlc->hdlc_bits1 = 0; break; } - if(hdlc->bit_shift==8){ - hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); - } - if(hdlc->shift_reg & 0x01){ + if (hdlc->bit_shift == 8) + hdlc->crc = crc_ccitt_byte(hdlc->crc, + hdlc->shift_reg); + if (hdlc->shift_reg & 0x01) { hdlc->hdlc_bits1++; hdlc->cbin++; hdlc->shift_reg >>= 1; @@ -474,11 +496,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, case HDLC_SEND_CRC1: hdlc->cbin <<= 1; hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ + if (hdlc->hdlc_bits1 == 5) { hdlc->hdlc_bits1 = 0; break; } - if(hdlc->shift_reg & 0x01){ + if (hdlc->shift_reg & 0x01) { hdlc->hdlc_bits1++; hdlc->cbin++; hdlc->shift_reg >>= 1; @@ -488,7 +510,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->shift_reg >>= 1; hdlc->bit_shift--; } - if(hdlc->bit_shift==0){ + if (hdlc->bit_shift == 0) { hdlc->shift_reg = (hdlc->crc >> 8); hdlc->state = HDLC_SEND_CRC2; hdlc->bit_shift = 8; @@ -497,11 +519,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, case HDLC_SEND_CRC2: hdlc->cbin <<= 1; hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ + if (hdlc->hdlc_bits1 == 5) { hdlc->hdlc_bits1 = 0; break; } - if(hdlc->shift_reg & 0x01){ + if (hdlc->shift_reg & 0x01) { hdlc->hdlc_bits1++; hdlc->cbin++; hdlc->shift_reg >>= 1; @@ -511,7 +533,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->shift_reg >>= 1; hdlc->bit_shift--; } - if(hdlc->bit_shift==0){ + if (hdlc->bit_shift == 0) { hdlc->shift_reg = 0x7e; hdlc->state = HDLC_SEND_CLOSING_FLAG; hdlc->bit_shift = 8; @@ -520,33 +542,36 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, case HDLC_SEND_CLOSING_FLAG: hdlc->cbin <<= 1; hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ + if (hdlc->hdlc_bits1 == 5) { hdlc->hdlc_bits1 = 0; break; } - if(hdlc->shift_reg & 0x01){ + if (hdlc->shift_reg & 0x01) hdlc->cbin++; - } hdlc->shift_reg >>= 1; hdlc->bit_shift--; - if(hdlc->bit_shift==0){ - hdlc->ffvalue = xfast_flag_value[hdlc->data_bits]; - if(hdlc->dchannel){ + if (hdlc->bit_shift == 0) { + hdlc->ffvalue = + xfast_flag_value[hdlc->data_bits]; + if (hdlc->dchannel) { hdlc->ffvalue = 0x7e; hdlc->state = HDLC_SEND_IDLE1; hdlc->bit_shift = 8-hdlc->data_bits; - if(hdlc->bit_shift==0) - hdlc->state = HDLC_SEND_FAST_IDLE; + if (hdlc->bit_shift == 0) + hdlc->state = + HDLC_SEND_FAST_IDLE; } else { - if(!hdlc->do_adapt56){ - hdlc->state = HDLC_SEND_FAST_FLAG; + if (!hdlc->do_adapt56) { + hdlc->state = + HDLC_SEND_FAST_FLAG; hdlc->data_received = 0; } else { hdlc->state = HDLC_SENDFLAG_B0; hdlc->data_received = 0; } - // Finished with this frame, send flags - if (dsize > 1) dsize = 1; + /* Finished this frame, send flags */ + if (dsize > 1) + dsize = 1; } } break; @@ -556,7 +581,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->cbin++; hdlc->data_bits++; hdlc->bit_shift--; - if(hdlc->bit_shift==0){ + if (hdlc->bit_shift == 0) { hdlc->state = HDLC_SEND_FAST_IDLE; hdlc->bit_shift = 0; } @@ -565,12 +590,13 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, hdlc->do_closing = 0; hdlc->cbin = 0xff; hdlc->data_bits = 8; - if(hdlc->bit_shift == 8){ + if (hdlc->bit_shift == 8) { hdlc->cbin = 0x7e; hdlc->state = HDLC_SEND_FIRST_FLAG; } else { *dst++ = hdlc->cbin; - hdlc->bit_shift = hdlc->data_bits = 0; + hdlc->bit_shift = 0; + hdlc->data_bits = 0; len++; dsize = 0; } @@ -578,14 +604,14 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, default: break; } - if(hdlc->do_adapt56){ - if(hdlc->data_bits==7){ + if (hdlc->do_adapt56) { + if (hdlc->data_bits == 7) { hdlc->cbin <<= 1; hdlc->cbin++; hdlc->data_bits++; } } - if(hdlc->data_bits==8){ + if (hdlc->data_bits == 8) { *dst++ = hdlc->cbin; hdlc->data_bits = 0; len++; @@ -596,8 +622,4 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src, return len; } - -EXPORT_SYMBOL(isdnhdlc_rcv_init); -EXPORT_SYMBOL(isdnhdlc_decode); -EXPORT_SYMBOL(isdnhdlc_out_init); EXPORT_SYMBOL(isdnhdlc_encode); -- cgit v1.2.3-18-g5258 From c38fc3bc2ecddd4f5278131603e6964cbed071b2 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 8 Jul 2009 20:31:42 +0200 Subject: ISDN: Add support for none reverse bitstreams to isdnhdc The original isdnhdlc code was developed for devices which had reversed bitorder in the byte stream. Adding code to handle normal bitstreams as well. Signed-off-by: Karsten Keil --- drivers/isdn/hisax/st5481_b.c | 5 ++- drivers/isdn/hisax/st5481_d.c | 2 +- drivers/isdn/hisax/st5481_usb.c | 11 ++++--- drivers/isdn/i4l/isdnhdlc.c | 70 ++++++++++++++++++++--------------------- 4 files changed, 47 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c index 0074b600a0e..95b1cdd9795 100644 --- a/drivers/isdn/hisax/st5481_b.c +++ b/drivers/isdn/hisax/st5481_b.c @@ -218,7 +218,10 @@ static void st5481B_mode(struct st5481_bcs *bcs, int mode) if (bcs->mode != L1_MODE_NULL) { // Open the B channel if (bcs->mode != L1_MODE_TRANS) { - isdnhdlc_out_init(&b_out->hdlc_state, 0, bcs->mode == L1_MODE_HDLC_56K); + u32 features = HDLC_BITREVERSE; + if (bcs->mode == L1_MODE_HDLC_56K) + features |= HDLC_56KBIT; + isdnhdlc_out_init(&b_out->hdlc_state, features); } st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2, NULL, NULL); diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c index 077991c1cd0..39e8e49cfd2 100644 --- a/drivers/isdn/hisax/st5481_d.c +++ b/drivers/isdn/hisax/st5481_d.c @@ -417,7 +417,7 @@ static void dout_start_xmit(struct FsmInst *fsm, int event, void *arg) DBG(2,"len=%d",skb->len); - isdnhdlc_out_init(&d_out->hdlc_state, 1, 0); + isdnhdlc_out_init(&d_out->hdlc_state, HDLC_DCHANNEL | HDLC_BITREVERSE); if (test_and_set_bit(buf_nr, &d_out->busy)) { WARNING("ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy); diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c index 2b3a055059e..10d41c5d73e 100644 --- a/drivers/isdn/hisax/st5481_usb.c +++ b/drivers/isdn/hisax/st5481_usb.c @@ -637,10 +637,13 @@ void st5481_in_mode(struct st5481_in *in, int mode) usb_unlink_urb(in->urb[1]); if (in->mode != L1_MODE_NULL) { - if (in->mode != L1_MODE_TRANS) - isdnhdlc_rcv_init(&in->hdlc_state, - in->mode == L1_MODE_HDLC_56K); - + if (in->mode != L1_MODE_TRANS) { + u32 features = HDLC_BITREVERSE; + + if (in->mode == L1_MODE_HDLC_56K) + features |= HDLC_56KBIT; + isdnhdlc_rcv_init(&in->hdlc_state, features); + } st5481_usb_pipe_reset(in->adapter, in->ep, NULL, NULL); st5481_usb_device_ctrl_msg(in->adapter, in->counter, in->packet_size, diff --git a/drivers/isdn/i4l/isdnhdlc.c b/drivers/isdn/i4l/isdnhdlc.c index b80e55ab891..df345ce73f4 100644 --- a/drivers/isdn/i4l/isdnhdlc.c +++ b/drivers/isdn/i4l/isdnhdlc.c @@ -2,6 +2,7 @@ * isdnhdlc.c -- General purpose ISDN HDLC decoder. * * Copyright (C) + * 2009 Karsten Keil * 2002 Wolfgang Mües * 2001 Frode Isaksen * 2001 Kai Germaschewski @@ -25,6 +26,7 @@ #include #include #include +#include /*-------------------------------------------------------------------*/ @@ -48,35 +50,21 @@ enum { HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED }; -void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, int do_adapt56) +void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features) { - hdlc->bit_shift = 0; - hdlc->hdlc_bits1 = 0; - hdlc->data_bits = 0; - hdlc->ffbit_shift = 0; - hdlc->data_received = 0; + memset(hdlc, 0, sizeof(struct isdnhdlc_vars)); hdlc->state = HDLC_GET_DATA; - hdlc->do_adapt56 = do_adapt56; - hdlc->dchannel = 0; - hdlc->crc = 0; - hdlc->cbin = 0; - hdlc->shift_reg = 0; - hdlc->ffvalue = 0; - hdlc->dstpos = 0; + if (features & HDLC_56KBIT) + hdlc->do_adapt56 = 1; + if (features & HDLC_BITREVERSE) + hdlc->do_bitreverse = 1; } EXPORT_SYMBOL(isdnhdlc_out_init); -void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, int is_d_channel, - int do_adapt56) +void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features) { - hdlc->bit_shift = 0; - hdlc->hdlc_bits1 = 0; - hdlc->data_bits = 0; - hdlc->ffbit_shift = 0; - hdlc->data_received = 0; - hdlc->do_closing = 0; - hdlc->ffvalue = 0; - if (is_d_channel) { + memset(hdlc, 0, sizeof(struct isdnhdlc_vars)); + if (features & HDLC_DCHANNEL) { hdlc->dchannel = 1; hdlc->state = HDLC_SEND_FIRST_FLAG; } else { @@ -85,16 +73,13 @@ void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, int is_d_channel, hdlc->ffvalue = 0x7e; } hdlc->cbin = 0x7e; - hdlc->bit_shift = 0; - if (do_adapt56) { + if (features & HDLC_56KBIT) { hdlc->do_adapt56 = 1; - hdlc->data_bits = 0; hdlc->state = HDLC_SENDFLAG_B0; - } else { - hdlc->do_adapt56 = 0; + } else hdlc->data_bits = 8; - } - hdlc->shift_reg = 0; + if (features & HDLC_BITREVERSE) + hdlc->do_bitreverse = 1; } EXPORT_SYMBOL(isdnhdlc_rcv_init); @@ -188,7 +173,11 @@ int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen, while (slen > 0) { if (hdlc->bit_shift == 0) { - hdlc->cbin = *src++; + /* the code is for bitreverse streams */ + if (hdlc->do_bitreverse == 0) + hdlc->cbin = bitrev8(*src++); + else + hdlc->cbin = *src++; slen--; hdlc->bit_shift = 8; if (hdlc->do_adapt56) @@ -405,12 +394,15 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, case STOPPED: while (dsize--) *dst++ = 0xff; - return dsize; case HDLC_SEND_FAST_FLAG: hdlc->do_closing = 0; if (slen == 0) { - *dst++ = hdlc->ffvalue; + /* the code is for bitreverse streams */ + if (hdlc->do_bitreverse == 0) + *dst++ = bitrev8(hdlc->ffvalue); + else + *dst++ = hdlc->ffvalue; len++; dsize--; break; @@ -594,7 +586,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, hdlc->cbin = 0x7e; hdlc->state = HDLC_SEND_FIRST_FLAG; } else { - *dst++ = hdlc->cbin; + /* the code is for bitreverse streams */ + if (hdlc->do_bitreverse == 0) + *dst++ = bitrev8(hdlc->cbin); + else + *dst++ = hdlc->cbin; hdlc->bit_shift = 0; hdlc->data_bits = 0; len++; @@ -612,7 +608,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, } } if (hdlc->data_bits == 8) { - *dst++ = hdlc->cbin; + /* the code is for bitreverse streams */ + if (hdlc->do_bitreverse == 0) + *dst++ = bitrev8(hdlc->cbin); + else + *dst++ = hdlc->cbin; hdlc->data_bits = 0; len++; dsize--; -- cgit v1.2.3-18-g5258 From f3fad223ed69f406f33c9619c256858d5a5fc5c7 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 8 Jul 2009 20:58:33 +0200 Subject: ISDN: Fix isdnhdlc for one byte hdlc packets Normally HDLC packets contain more as one byte (e.g a X25/X75 header). But if you use plain HDLC framing, the current code do not encode 1 byte payloads, this patch fix that. Signed-off-by: Karsten Keil --- drivers/isdn/i4l/isdnhdlc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/isdn/i4l/isdnhdlc.c b/drivers/isdn/i4l/isdnhdlc.c index df345ce73f4..c989aa35dc2 100644 --- a/drivers/isdn/i4l/isdnhdlc.c +++ b/drivers/isdn/i4l/isdnhdlc.c @@ -47,7 +47,7 @@ enum { HDLC_SEND_DATA, HDLC_SEND_CRC1, HDLC_SEND_FAST_FLAG, HDLC_SEND_FIRST_FLAG, HDLC_SEND_CRC2, HDLC_SEND_CLOSING_FLAG, HDLC_SEND_IDLE1, HDLC_SEND_FAST_IDLE, HDLC_SENDFLAG_B0, - HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED + HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED, HDLC_SENDFLAG_ONE }; void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features) @@ -362,6 +362,9 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, *count = slen; + /* special handling for one byte frames */ + if ((slen == 1) && (hdlc->state == HDLC_SEND_FAST_FLAG)) + hdlc->state = HDLC_SENDFLAG_ONE; while (dsize > 0) { if (hdlc->bit_shift == 0) { if (slen && !hdlc->do_closing) { @@ -407,6 +410,8 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, dsize--; break; } + /* fall through */ + case HDLC_SENDFLAG_ONE: if (hdlc->bit_shift == 8) { hdlc->cbin = hdlc->ffvalue >> (8 - hdlc->data_bits); -- cgit v1.2.3-18-g5258 From fb286f0471a04ef646c8e5c79750ae6718183745 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Thu, 9 Jul 2009 10:02:29 +0200 Subject: mISDN: Make clearing B-channel a common function Clearing B-channel is needed in every driver, so it makes sense to have it as common function. Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/hfcmulti.c | 16 +--------------- drivers/isdn/hardware/mISDN/hfcpci.c | 16 +--------------- drivers/isdn/hardware/mISDN/hfcsusb.c | 16 +--------------- drivers/isdn/mISDN/hwchannel.c | 15 +++++++++++++-- 4 files changed, 16 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index e1dab30aed3..fd77bb15d79 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -3416,22 +3416,8 @@ deactivate_bchannel(struct bchannel *bch) u_long flags; spin_lock_irqsave(&hc->lock, flags); - if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) { - dev_kfree_skb(bch->next_skb); - bch->next_skb = NULL; - } - if (bch->tx_skb) { - dev_kfree_skb(bch->tx_skb); - bch->tx_skb = NULL; - } - bch->tx_idx = 0; - if (bch->rx_skb) { - dev_kfree_skb(bch->rx_skb); - bch->rx_skb = NULL; - } + mISDN_clear_bchannel(bch); hc->chan[bch->slot].coeff_count = 0; - test_and_clear_bit(FLG_ACTIVE, &bch->Flags); - test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); hc->chan[bch->slot].rx_off = 0; hc->chan[bch->slot].conf = -1; mode_hfcmulti(hc, bch->slot, ISDN_P_NONE, -1, 0, -1, 0); diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 228ffbed128..70e6b0e0112 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -1522,22 +1522,8 @@ deactivate_bchannel(struct bchannel *bch) u_long flags; spin_lock_irqsave(&hc->lock, flags); - if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) { - dev_kfree_skb(bch->next_skb); - bch->next_skb = NULL; - } - if (bch->tx_skb) { - dev_kfree_skb(bch->tx_skb); - bch->tx_skb = NULL; - } - bch->tx_idx = 0; - if (bch->rx_skb) { - dev_kfree_skb(bch->rx_skb); - bch->rx_skb = NULL; - } + mISDN_clear_bchannel(bch); mode_hfcpci(bch, bch->nr, ISDN_P_NONE); - test_and_clear_bit(FLG_ACTIVE, &bch->Flags); - test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); spin_unlock_irqrestore(&hc->lock, flags); } diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c index 6b7704c41b9..fc46a26cb14 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c @@ -1809,21 +1809,7 @@ deactivate_bchannel(struct bchannel *bch) hw->name, __func__, bch->nr); spin_lock_irqsave(&hw->lock, flags); - if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) { - dev_kfree_skb(bch->next_skb); - bch->next_skb = NULL; - } - if (bch->tx_skb) { - dev_kfree_skb(bch->tx_skb); - bch->tx_skb = NULL; - } - bch->tx_idx = 0; - if (bch->rx_skb) { - dev_kfree_skb(bch->rx_skb); - bch->rx_skb = NULL; - } - clear_bit(FLG_ACTIVE, &bch->Flags); - clear_bit(FLG_TX_BUSY, &bch->Flags); + mISDN_clear_bchannel(bch); spin_unlock_irqrestore(&hw->lock, flags); hfcsusb_setup_bch(bch, ISDN_P_NONE); hfcsusb_stop_endpoint(hw, bch->nr); diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c index 0481a0cdf6d..e8049be552a 100644 --- a/drivers/isdn/mISDN/hwchannel.c +++ b/drivers/isdn/mISDN/hwchannel.c @@ -114,13 +114,14 @@ mISDN_freedchannel(struct dchannel *ch) } EXPORT_SYMBOL(mISDN_freedchannel); -int -mISDN_freebchannel(struct bchannel *ch) +void +mISDN_clear_bchannel(struct bchannel *ch) { if (ch->tx_skb) { dev_kfree_skb(ch->tx_skb); ch->tx_skb = NULL; } + ch->tx_idx = 0; if (ch->rx_skb) { dev_kfree_skb(ch->rx_skb); ch->rx_skb = NULL; @@ -129,6 +130,16 @@ mISDN_freebchannel(struct bchannel *ch) dev_kfree_skb(ch->next_skb); ch->next_skb = NULL; } + test_and_clear_bit(FLG_TX_BUSY, &ch->Flags); + test_and_clear_bit(FLG_TX_NEXT, &ch->Flags); + test_and_clear_bit(FLG_ACTIVE, &ch->Flags); +} +EXPORT_SYMBOL(mISDN_clear_bchannel); + +int +mISDN_freebchannel(struct bchannel *ch) +{ + mISDN_clear_bchannel(ch); skb_queue_purge(&ch->rqueue); ch->rcount = 0; flush_scheduled_work(); -- cgit v1.2.3-18-g5258 From cae86d4a4e56eeda1afdea38f230d222edda7dd5 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 22 Jul 2009 19:42:46 +0200 Subject: mISDN: Add driver for Infineon ISDN chipset family This driver supports cards with Infineon ISAC/HSCX, ISACX, IPAC and IPACX chips from various manufacturers. Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/Kconfig | 14 + drivers/isdn/hardware/mISDN/Makefile | 3 + drivers/isdn/hardware/mISDN/iohelper.h | 109 ++ drivers/isdn/hardware/mISDN/ipac.h | 405 +++++++ drivers/isdn/hardware/mISDN/mISDNinfineon.c | 1178 +++++++++++++++++++ drivers/isdn/hardware/mISDN/mISDNipac.c | 1655 +++++++++++++++++++++++++++ 6 files changed, 3364 insertions(+) create mode 100644 drivers/isdn/hardware/mISDN/iohelper.h create mode 100644 drivers/isdn/hardware/mISDN/ipac.h create mode 100644 drivers/isdn/hardware/mISDN/mISDNinfineon.c create mode 100644 drivers/isdn/hardware/mISDN/mISDNipac.c (limited to 'drivers') diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig index 3024566dd09..a8542b81f95 100644 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ b/drivers/isdn/hardware/mISDN/Kconfig @@ -39,3 +39,17 @@ config MISDN_HFCUSB Enable support for USB ISDN TAs with Cologne Chip AG's HFC-S USB ISDN Controller +config MISDN_INFINEON + tristate "Support for cards with Infineon chipset" + depends on MISDN + depends on PCI + select MISDN_IPAC + help + Enable support for cards with ISAC + HSCX, IPAC or IPAC-SX + chip from Infineon (former manufacturer Siemens). + + +config MISDN_IPAC + tristate + depends on MISDN + diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile index b0403526bbb..2863455b493 100644 --- a/drivers/isdn/hardware/mISDN/Makefile +++ b/drivers/isdn/hardware/mISDN/Makefile @@ -6,3 +6,6 @@ obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o +obj-$(CONFIG_MISDN_INFINEON) += mISDNinfineon.o +# chip modules +obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o diff --git a/drivers/isdn/hardware/mISDN/iohelper.h b/drivers/isdn/hardware/mISDN/iohelper.h new file mode 100644 index 00000000000..c16a217301e --- /dev/null +++ b/drivers/isdn/hardware/mISDN/iohelper.h @@ -0,0 +1,109 @@ +/* + * iohelper.h + * helper for define functions to access ISDN hardware + * supported are memory mapped IO + * indirect port IO (one port for address, one for data) + * + * Author Karsten Keil + * + * Copyright 2009 by Karsten Keil + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _IOHELPER_H +#define _IOHELPER_H + +typedef u8 (read_reg_t)(void *, u8); +typedef void (write_reg_t)(void *, u8, u8); +typedef void (fifo_func_t)(void *, u8, u8 *, int); + +struct _ioport { + u32 port; + u32 ale; +}; + +#define IOFUNC_IO(name, hws, ap) \ + static u8 Read##name##_IO(void *p, u8 off) {\ + struct hws *hw = p;\ + return inb(hw->ap.port + off);\ + } \ + static void Write##name##_IO(void *p, u8 off, u8 val) {\ + struct hws *hw = p;\ + outb(val, hw->ap.port + off);\ + } \ + static void ReadFiFo##name##_IO(void *p, u8 off, u8 *dp, int size) {\ + struct hws *hw = p;\ + insb(hw->ap.port + off, dp, size);\ + } \ + static void WriteFiFo##name##_IO(void *p, u8 off, u8 *dp, int size) {\ + struct hws *hw = p;\ + outsb(hw->ap.port + off, dp, size);\ + } + +#define IOFUNC_IND(name, hws, ap) \ + static u8 Read##name##_IND(void *p, u8 off) {\ + struct hws *hw = p;\ + outb(off, hw->ap.ale);\ + return inb(hw->ap.port);\ + } \ + static void Write##name##_IND(void *p, u8 off, u8 val) {\ + struct hws *hw = p;\ + outb(off, hw->ap.ale);\ + outb(val, hw->ap.port);\ + } \ + static void ReadFiFo##name##_IND(void *p, u8 off, u8 *dp, int size) {\ + struct hws *hw = p;\ + outb(off, hw->ap.ale);\ + insb(hw->ap.port, dp, size);\ + } \ + static void WriteFiFo##name##_IND(void *p, u8 off, u8 *dp, int size) {\ + struct hws *hw = p;\ + outb(off, hw->ap.ale);\ + outsb(hw->ap.port, dp, size);\ + } + +#define IOFUNC_MEMIO(name, hws, typ, adr) \ + static u8 Read##name##_MIO(void *p, u8 off) {\ + struct hws *hw = p;\ + return readb(((typ *)hw->adr) + off);\ + } \ + static void Write##name##_MIO(void *p, u8 off, u8 val) {\ + struct hws *hw = p;\ + writeb(val, ((typ *)hw->adr) + off);\ + } \ + static void ReadFiFo##name##_MIO(void *p, u8 off, u8 *dp, int size) {\ + struct hws *hw = p;\ + while (size--)\ + *dp++ = readb(((typ *)hw->adr) + off);\ + } \ + static void WriteFiFo##name##_MIO(void *p, u8 off, u8 *dp, int size) {\ + struct inf_hw *hw = p;\ + while (size--)\ + writeb(*dp++, ((typ *)hw->adr) + off);\ + } + +#define ASSIGN_FUNC(typ, name, dest) do {\ + dest.read_reg = &Read##name##_##typ;\ + dest.write_reg = &Write##name##_##typ;\ + dest.read_fifo = &ReadFiFo##name##_##typ;\ + dest.write_fifo = &WriteFiFo##name##_##typ;\ + } while (0) +#define ASSIGN_FUNC_IPAC(typ, target) do {\ + ASSIGN_FUNC(typ, ISAC, target.isac);\ + ASSIGN_FUNC(typ, IPAC, target);\ + } while (0) + +#endif \ No newline at end of file diff --git a/drivers/isdn/hardware/mISDN/ipac.h b/drivers/isdn/hardware/mISDN/ipac.h new file mode 100644 index 00000000000..f9601d55dbc --- /dev/null +++ b/drivers/isdn/hardware/mISDN/ipac.h @@ -0,0 +1,405 @@ +/* + * + * ipac.h Defines for the Infineon (former Siemens) ISDN + * chip series + * + * Author Karsten Keil + * + * Copyright 2009 by Karsten Keil + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "iohelper.h" + +struct isac_hw { + struct dchannel dch; + u32 type; + u32 off; /* offset to isac regs */ + char *name; + spinlock_t *hwlock; /* lock HW acccess */ + read_reg_t *read_reg; + write_reg_t *write_reg; + fifo_func_t *read_fifo; + fifo_func_t *write_fifo; + int (*monitor)(void *, u32, u8 *, int); + void (*release)(struct isac_hw *); + int (*init)(struct isac_hw *); + int (*ctrl)(struct isac_hw *, u32, u_long); + int (*open)(struct isac_hw *, struct channel_req *); + u8 *mon_tx; + u8 *mon_rx; + int mon_txp; + int mon_txc; + int mon_rxp; + struct arcofi_msg *arcofi_list; + struct timer_list arcofitimer; + wait_queue_head_t arcofi_wait; + u8 arcofi_bc; + u8 arcofi_state; + u8 mocr; + u8 adf2; + u8 state; +}; + +struct ipac_hw; + +struct hscx_hw { + struct bchannel bch; + struct ipac_hw *ip; + u8 fifo_size; + u8 off; /* offset to ICA or ICB */ + u8 slot; + char log[64]; +}; + +struct ipac_hw { + struct isac_hw isac; + struct hscx_hw hscx[2]; + char *name; + void *hw; + spinlock_t *hwlock; /* lock HW acccess */ + struct module *owner; + u32 type; + read_reg_t *read_reg; + write_reg_t *write_reg; + fifo_func_t *read_fifo; + fifo_func_t *write_fifo; + void (*release)(struct ipac_hw *); + int (*init)(struct ipac_hw *); + int (*ctrl)(struct ipac_hw *, u32, u_long); + u8 conf; +}; + +#define IPAC_TYPE_ISAC 0x0010 +#define IPAC_TYPE_IPAC 0x0020 +#define IPAC_TYPE_ISACX 0x0040 +#define IPAC_TYPE_IPACX 0x0080 +#define IPAC_TYPE_HSCX 0x0100 + +#define ISAC_USE_ARCOFI 0x1000 + +/* Monitor functions */ +#define MONITOR_RX_0 0x1000 +#define MONITOR_RX_1 0x1001 +#define MONITOR_TX_0 0x2000 +#define MONITOR_TX_1 0x2001 + +/* All registers original Siemens Spec */ +/* IPAC/ISAC registers */ +#define ISAC_MASK 0x20 +#define ISAC_ISTA 0x20 +#define ISAC_STAR 0x21 +#define ISAC_CMDR 0x21 +#define ISAC_EXIR 0x24 +#define ISAC_ADF2 0x39 +#define ISAC_SPCR 0x30 +#define ISAC_ADF1 0x38 +#define ISAC_CIR0 0x31 +#define ISAC_CIX0 0x31 +#define ISAC_CIR1 0x33 +#define ISAC_CIX1 0x33 +#define ISAC_STCR 0x37 +#define ISAC_MODE 0x22 +#define ISAC_RSTA 0x27 +#define ISAC_RBCL 0x25 +#define ISAC_RBCH 0x2A +#define ISAC_TIMR 0x23 +#define ISAC_SQXR 0x3b +#define ISAC_SQRR 0x3b +#define ISAC_MOSR 0x3a +#define ISAC_MOCR 0x3a +#define ISAC_MOR0 0x32 +#define ISAC_MOX0 0x32 +#define ISAC_MOR1 0x34 +#define ISAC_MOX1 0x34 + +#define ISAC_RBCH_XAC 0x80 + +#define IPAC_D_TIN2 0x01 + +/* IPAC/HSCX */ +#define IPAC_ISTAB 0x20 /* RD */ +#define IPAC_MASKB 0x20 /* WR */ +#define IPAC_STARB 0x21 /* RD */ +#define IPAC_CMDRB 0x21 /* WR */ +#define IPAC_MODEB 0x22 /* R/W */ +#define IPAC_EXIRB 0x24 /* RD */ +#define IPAC_RBCLB 0x25 /* RD */ +#define IPAC_RAH1 0x26 /* WR */ +#define IPAC_RAH2 0x27 /* WR */ +#define IPAC_RSTAB 0x27 /* RD */ +#define IPAC_RAL1 0x28 /* R/W */ +#define IPAC_RAL2 0x29 /* WR */ +#define IPAC_RHCRB 0x29 /* RD */ +#define IPAC_XBCL 0x2A /* WR */ +#define IPAC_CCR2 0x2C /* R/W */ +#define IPAC_RBCHB 0x2D /* RD */ +#define IPAC_XBCH 0x2D /* WR */ +#define HSCX_VSTR 0x2E /* RD */ +#define IPAC_RLCR 0x2E /* WR */ +#define IPAC_CCR1 0x2F /* R/W */ +#define IPAC_TSAX 0x30 /* WR */ +#define IPAC_TSAR 0x31 /* WR */ +#define IPAC_XCCR 0x32 /* WR */ +#define IPAC_RCCR 0x33 /* WR */ + +/* IPAC_ISTAB/IPAC_MASKB bits */ +#define IPAC_B_XPR 0x10 +#define IPAC_B_RPF 0x40 +#define IPAC_B_RME 0x80 +#define IPAC_B_ON 0x2F + +/* IPAC_EXIRB bits */ +#define IPAC_B_RFS 0x04 +#define IPAC_B_RFO 0x10 +#define IPAC_B_XDU 0x40 +#define IPAC_B_XMR 0x80 + +/* IPAC special registers */ +#define IPAC_CONF 0xC0 /* R/W */ +#define IPAC_ISTA 0xC1 /* RD */ +#define IPAC_MASK 0xC1 /* WR */ +#define IPAC_ID 0xC2 /* RD */ +#define IPAC_ACFG 0xC3 /* R/W */ +#define IPAC_AOE 0xC4 /* R/W */ +#define IPAC_ARX 0xC5 /* RD */ +#define IPAC_ATX 0xC5 /* WR */ +#define IPAC_PITA1 0xC6 /* R/W */ +#define IPAC_PITA2 0xC7 /* R/W */ +#define IPAC_POTA1 0xC8 /* R/W */ +#define IPAC_POTA2 0xC9 /* R/W */ +#define IPAC_PCFG 0xCA /* R/W */ +#define IPAC_SCFG 0xCB /* R/W */ +#define IPAC_TIMR2 0xCC /* R/W */ + +/* IPAC_ISTA/_MASK bits */ +#define IPAC__EXB 0x01 +#define IPAC__ICB 0x02 +#define IPAC__EXA 0x04 +#define IPAC__ICA 0x08 +#define IPAC__EXD 0x10 +#define IPAC__ICD 0x20 +#define IPAC__INT0 0x40 +#define IPAC__INT1 0x80 +#define IPAC__ON 0xC0 + +/* HSCX ISTA/MASK bits */ +#define HSCX__EXB 0x01 +#define HSCX__EXA 0x02 +#define HSCX__ICA 0x04 + +/* ISAC/ISACX/IPAC/IPACX L1 commands */ +#define ISAC_CMD_TIM 0x0 +#define ISAC_CMD_RS 0x1 +#define ISAC_CMD_SCZ 0x4 +#define ISAC_CMD_SSZ 0x2 +#define ISAC_CMD_AR8 0x8 +#define ISAC_CMD_AR10 0x9 +#define ISAC_CMD_ARL 0xA +#define ISAC_CMD_DUI 0xF + +/* ISAC/ISACX/IPAC/IPACX L1 indications */ +#define ISAC_IND_RS 0x1 +#define ISAC_IND_PU 0x7 +#define ISAC_IND_DR 0x0 +#define ISAC_IND_SD 0x2 +#define ISAC_IND_DIS 0x3 +#define ISAC_IND_EI 0x6 +#define ISAC_IND_RSY 0x4 +#define ISAC_IND_ARD 0x8 +#define ISAC_IND_TI 0xA +#define ISAC_IND_ATI 0xB +#define ISAC_IND_AI8 0xC +#define ISAC_IND_AI10 0xD +#define ISAC_IND_DID 0xF + +/* the new ISACX / IPACX */ +/* D-channel registers */ +#define ISACX_RFIFOD 0x00 /* RD */ +#define ISACX_XFIFOD 0x00 /* WR */ +#define ISACX_ISTAD 0x20 /* RD */ +#define ISACX_MASKD 0x20 /* WR */ +#define ISACX_STARD 0x21 /* RD */ +#define ISACX_CMDRD 0x21 /* WR */ +#define ISACX_MODED 0x22 /* R/W */ +#define ISACX_EXMD1 0x23 /* R/W */ +#define ISACX_TIMR1 0x24 /* R/W */ +#define ISACX_SAP1 0x25 /* WR */ +#define ISACX_SAP2 0x26 /* WR */ +#define ISACX_RBCLD 0x26 /* RD */ +#define ISACX_RBCHD 0x27 /* RD */ +#define ISACX_TEI1 0x27 /* WR */ +#define ISACX_TEI2 0x28 /* WR */ +#define ISACX_RSTAD 0x28 /* RD */ +#define ISACX_TMD 0x29 /* R/W */ +#define ISACX_CIR0 0x2E /* RD */ +#define ISACX_CIX0 0x2E /* WR */ +#define ISACX_CIR1 0x2F /* RD */ +#define ISACX_CIX1 0x2F /* WR */ + +/* Transceiver registers */ +#define ISACX_TR_CONF0 0x30 /* R/W */ +#define ISACX_TR_CONF1 0x31 /* R/W */ +#define ISACX_TR_CONF2 0x32 /* R/W */ +#define ISACX_TR_STA 0x33 /* RD */ +#define ISACX_TR_CMD 0x34 /* R/W */ +#define ISACX_SQRR1 0x35 /* RD */ +#define ISACX_SQXR1 0x35 /* WR */ +#define ISACX_SQRR2 0x36 /* RD */ +#define ISACX_SQXR2 0x36 /* WR */ +#define ISACX_SQRR3 0x37 /* RD */ +#define ISACX_SQXR3 0x37 /* WR */ +#define ISACX_ISTATR 0x38 /* RD */ +#define ISACX_MASKTR 0x39 /* R/W */ +#define ISACX_TR_MODE 0x3A /* R/W */ +#define ISACX_ACFG1 0x3C /* R/W */ +#define ISACX_ACFG2 0x3D /* R/W */ +#define ISACX_AOE 0x3E /* R/W */ +#define ISACX_ARX 0x3F /* RD */ +#define ISACX_ATX 0x3F /* WR */ + +/* IOM: Timeslot, DPS, CDA */ +#define ISACX_CDA10 0x40 /* R/W */ +#define ISACX_CDA11 0x41 /* R/W */ +#define ISACX_CDA20 0x42 /* R/W */ +#define ISACX_CDA21 0x43 /* R/W */ +#define ISACX_CDA_TSDP10 0x44 /* R/W */ +#define ISACX_CDA_TSDP11 0x45 /* R/W */ +#define ISACX_CDA_TSDP20 0x46 /* R/W */ +#define ISACX_CDA_TSDP21 0x47 /* R/W */ +#define ISACX_BCHA_TSDP_BC1 0x48 /* R/W */ +#define ISACX_BCHA_TSDP_BC2 0x49 /* R/W */ +#define ISACX_BCHB_TSDP_BC1 0x4A /* R/W */ +#define ISACX_BCHB_TSDP_BC2 0x4B /* R/W */ +#define ISACX_TR_TSDP_BC1 0x4C /* R/W */ +#define ISACX_TR_TSDP_BC2 0x4D /* R/W */ +#define ISACX_CDA1_CR 0x4E /* R/W */ +#define ISACX_CDA2_CR 0x4F /* R/W */ + +/* IOM: Contol, Sync transfer, Monitor */ +#define ISACX_TR_CR 0x50 /* R/W */ +#define ISACX_TRC_CR 0x50 /* R/W */ +#define ISACX_BCHA_CR 0x51 /* R/W */ +#define ISACX_BCHB_CR 0x52 /* R/W */ +#define ISACX_DCI_CR 0x53 /* R/W */ +#define ISACX_DCIC_CR 0x53 /* R/W */ +#define ISACX_MON_CR 0x54 /* R/W */ +#define ISACX_SDS1_CR 0x55 /* R/W */ +#define ISACX_SDS2_CR 0x56 /* R/W */ +#define ISACX_IOM_CR 0x57 /* R/W */ +#define ISACX_STI 0x58 /* RD */ +#define ISACX_ASTI 0x58 /* WR */ +#define ISACX_MSTI 0x59 /* R/W */ +#define ISACX_SDS_CONF 0x5A /* R/W */ +#define ISACX_MCDA 0x5B /* RD */ +#define ISACX_MOR 0x5C /* RD */ +#define ISACX_MOX 0x5C /* WR */ +#define ISACX_MOSR 0x5D /* RD */ +#define ISACX_MOCR 0x5E /* R/W */ +#define ISACX_MSTA 0x5F /* RD */ +#define ISACX_MCONF 0x5F /* WR */ + +/* Interrupt and general registers */ +#define ISACX_ISTA 0x60 /* RD */ +#define ISACX_MASK 0x60 /* WR */ +#define ISACX_AUXI 0x61 /* RD */ +#define ISACX_AUXM 0x61 /* WR */ +#define ISACX_MODE1 0x62 /* R/W */ +#define ISACX_MODE2 0x63 /* R/W */ +#define ISACX_ID 0x64 /* RD */ +#define ISACX_SRES 0x64 /* WR */ +#define ISACX_TIMR2 0x65 /* R/W */ + +/* Register Bits */ +/* ISACX/IPACX _ISTAD (R) and _MASKD (W) */ +#define ISACX_D_XDU 0x04 +#define ISACX_D_XMR 0x08 +#define ISACX_D_XPR 0x10 +#define ISACX_D_RFO 0x20 +#define ISACX_D_RPF 0x40 +#define ISACX_D_RME 0x80 + +/* ISACX/IPACX _ISTA (R) and _MASK (W) */ +#define ISACX__ICD 0x01 +#define ISACX__MOS 0x02 +#define ISACX__TRAN 0x04 +#define ISACX__AUX 0x08 +#define ISACX__CIC 0x10 +#define ISACX__ST 0x20 +#define IPACX__ICB 0x40 +#define IPACX__ICA 0x80 +#define IPACX__ON 0x2C + +/* ISACX/IPACX _CMDRD (W) */ +#define ISACX_CMDRD_XRES 0x01 +#define ISACX_CMDRD_XME 0x02 +#define ISACX_CMDRD_XTF 0x08 +#define ISACX_CMDRD_STI 0x10 +#define ISACX_CMDRD_RRES 0x40 +#define ISACX_CMDRD_RMC 0x80 + +/* ISACX/IPACX _RSTAD (R) */ +#define ISACX_RSTAD_TA 0x01 +#define ISACX_RSTAD_CR 0x02 +#define ISACX_RSTAD_SA0 0x04 +#define ISACX_RSTAD_SA1 0x08 +#define ISACX_RSTAD_RAB 0x10 +#define ISACX_RSTAD_CRC 0x20 +#define ISACX_RSTAD_RDO 0x40 +#define ISACX_RSTAD_VFR 0x80 + +/* ISACX/IPACX _CIR0 (R) */ +#define ISACX_CIR0_BAS 0x01 +#define ISACX_CIR0_SG 0x08 +#define ISACX_CIR0_CIC1 0x08 +#define ISACX_CIR0_CIC0 0x08 + +/* B-channel registers */ +#define IPACX_OFF_ICA 0x70 +#define IPACX_OFF_ICB 0x80 + +/* ICA: IPACX_OFF_ICA + Reg ICB: IPACX_OFF_ICB + Reg */ + +#define IPACX_ISTAB 0x00 /* RD */ +#define IPACX_MASKB 0x00 /* WR */ +#define IPACX_STARB 0x01 /* RD */ +#define IPACX_CMDRB 0x01 /* WR */ +#define IPACX_MODEB 0x02 /* R/W */ +#define IPACX_EXMB 0x03 /* R/W */ +#define IPACX_RAH1 0x05 /* WR */ +#define IPACX_RAH2 0x06 /* WR */ +#define IPACX_RBCLB 0x06 /* RD */ +#define IPACX_RBCHB 0x07 /* RD */ +#define IPACX_RAL1 0x07 /* WR */ +#define IPACX_RAL2 0x08 /* WR */ +#define IPACX_RSTAB 0x08 /* RD */ +#define IPACX_TMB 0x09 /* R/W */ +#define IPACX_RFIFOB 0x0A /* RD */ +#define IPACX_XFIFOB 0x0A /* WR */ + +/* IPACX_ISTAB / IPACX_MASKB bits */ +#define IPACX_B_XDU 0x04 +#define IPACX_B_XPR 0x10 +#define IPACX_B_RFO 0x20 +#define IPACX_B_RPF 0x40 +#define IPACX_B_RME 0x80 + +#define IPACX_B_ON 0x0B + +extern int mISDNisac_init(struct isac_hw *, void *); +extern irqreturn_t mISDNisac_irq(struct isac_hw *, u8); +extern u32 mISDNipac_init(struct ipac_hw *, void *); +extern irqreturn_t mISDNipac_irq(struct ipac_hw *, int); diff --git a/drivers/isdn/hardware/mISDN/mISDNinfineon.c b/drivers/isdn/hardware/mISDN/mISDNinfineon.c new file mode 100644 index 00000000000..62441ba53b9 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/mISDNinfineon.c @@ -0,0 +1,1178 @@ +/* + * mISDNinfineon.c + * Support for cards based on following Infineon ISDN chipsets + * - ISAC + HSCX + * - IPAC and IPAC-X + * - ISAC-SX + HSCX + * + * Supported cards: + * - Dialogic Diva 2.0 + * - Dialogic Diva 2.0U + * - Dialogic Diva 2.01 + * - Dialogic Diva 2.02 + * - Sedlbauer Speedwin + * - HST Saphir3 + * - Develo (former ELSA) Microlink PCI (Quickstep 1000) + * - Develo (former ELSA) Quickstep 3000 + * - Berkom Scitel BRIX Quadro + * - Dr.Neuhaus (Sagem) Niccy + * + * + * + * Author Karsten Keil + * + * Copyright 2009 by Karsten Keil + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include "ipac.h" + +#define INFINEON_REV "1.0" + +static int inf_cnt; +static u32 debug; +static u32 irqloops = 4; + +enum inf_types { + INF_NONE, + INF_DIVA20, + INF_DIVA20U, + INF_DIVA201, + INF_DIVA202, + INF_SPEEDWIN, + INF_SAPHIR3, + INF_QS1000, + INF_QS3000, + INF_NICCY, + INF_SCT_1, + INF_SCT_2, + INF_SCT_3, + INF_SCT_4, + INF_GAZEL_R685, + INF_GAZEL_R753 +}; + +enum addr_mode { + AM_NONE = 0, + AM_IO, + AM_MEMIO, + AM_IND_IO, +}; + +struct inf_cinfo { + enum inf_types typ; + const char *full; + const char *name; + enum addr_mode cfg_mode; + enum addr_mode addr_mode; + u8 cfg_bar; + u8 addr_bar; + void *irqfunc; +}; + +struct _ioaddr { + enum addr_mode mode; + union { + void __iomem *p; + struct _ioport io; + } a; +}; + +struct _iohandle { + enum addr_mode mode; + resource_size_t size; + resource_size_t start; + void __iomem *p; +}; + +struct inf_hw { + struct list_head list; + struct pci_dev *pdev; + const struct inf_cinfo *ci; + char name[MISDN_MAX_IDLEN]; + u32 irq; + u32 irqcnt; + struct _iohandle cfg; + struct _iohandle addr; + struct _ioaddr isac; + struct _ioaddr hscx; + spinlock_t lock; /* HW access lock */ + struct ipac_hw ipac; + struct inf_hw *sc[3]; /* slave cards */ +}; + + +#define PCI_SUBVENDOR_HST_SAPHIR3 0x52 +#define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53 +#define PCI_SUB_ID_SEDLBAUER 0x01 + +static struct pci_device_id infineon_ids[] __devinitdata = { + { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA20}, + { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20_U, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA20U}, + { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA201, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA201}, + { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA202, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA202}, + { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, + PCI_SUBVENDOR_SEDLBAUER_PCI, PCI_SUB_ID_SEDLBAUER, 0, 0, + INF_SPEEDWIN}, + { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, + PCI_SUBVENDOR_HST_SAPHIR3, PCI_SUB_ID_SEDLBAUER, 0, 0, INF_SAPHIR3}, + { PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_MICROLINK, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_QS1000}, + { PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_QS3000, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_QS3000}, + { PCI_VENDOR_ID_SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_NICCY}, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO, 0, 0, + INF_SCT_1}, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_R685, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R685}, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_R753, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753}, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753}, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_OLITEC, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753}, + { } +}; +MODULE_DEVICE_TABLE(pci, infineon_ids); + +/* PCI interface specific defines */ +/* Diva 2.0/2.0U */ +#define DIVA_HSCX_PORT 0x00 +#define DIVA_HSCX_ALE 0x04 +#define DIVA_ISAC_PORT 0x08 +#define DIVA_ISAC_ALE 0x0C +#define DIVA_PCI_CTRL 0x10 + +/* DIVA_PCI_CTRL bits */ +#define DIVA_IRQ_BIT 0x01 +#define DIVA_RESET_BIT 0x08 +#define DIVA_EEPROM_CLK 0x40 +#define DIVA_LED_A 0x10 +#define DIVA_LED_B 0x20 +#define DIVA_IRQ_CLR 0x80 + +/* Diva 2.01/2.02 */ +/* Siemens PITA */ +#define PITA_ICR_REG 0x00 +#define PITA_INT0_STATUS 0x02 + +#define PITA_MISC_REG 0x1c +#define PITA_PARA_SOFTRESET 0x01000000 +#define PITA_SER_SOFTRESET 0x02000000 +#define PITA_PARA_MPX_MODE 0x04000000 +#define PITA_INT0_ENABLE 0x00020000 + +/* TIGER 100 Registers */ +#define TIGER_RESET_ADDR 0x00 +#define TIGER_EXTERN_RESET 0x01 +#define TIGER_AUX_CTRL 0x02 +#define TIGER_AUX_DATA 0x03 +#define TIGER_AUX_IRQMASK 0x05 +#define TIGER_AUX_STATUS 0x07 + +/* Tiger AUX BITs */ +#define TIGER_IOMASK 0xdd /* 1 and 5 are inputs */ +#define TIGER_IRQ_BIT 0x02 + +#define TIGER_IPAC_ALE 0xC0 +#define TIGER_IPAC_PORT 0xC8 + +/* ELSA (now Develo) PCI cards */ +#define ELSA_IRQ_ADDR 0x4c +#define ELSA_IRQ_MASK 0x04 +#define QS1000_IRQ_OFF 0x01 +#define QS3000_IRQ_OFF 0x03 +#define QS1000_IRQ_ON 0x41 +#define QS3000_IRQ_ON 0x43 + +/* Dr Neuhaus/Sagem Niccy */ +#define NICCY_ISAC_PORT 0x00 +#define NICCY_HSCX_PORT 0x01 +#define NICCY_ISAC_ALE 0x02 +#define NICCY_HSCX_ALE 0x03 + +#define NICCY_IRQ_CTRL_REG 0x38 +#define NICCY_IRQ_ENABLE 0x001f00 +#define NICCY_IRQ_DISABLE 0xff0000 +#define NICCY_IRQ_BIT 0x800000 + + +/* Scitel PLX */ +#define SCT_PLX_IRQ_ADDR 0x4c +#define SCT_PLX_RESET_ADDR 0x50 +#define SCT_PLX_IRQ_ENABLE 0x41 +#define SCT_PLX_RESET_BIT 0x04 + +/* Gazel */ +#define GAZEL_IPAC_DATA_PORT 0x04 +/* Gazel PLX */ +#define GAZEL_CNTRL 0x50 +#define GAZEL_RESET 0x04 +#define GAZEL_RESET_9050 0x40000000 +#define GAZEL_INCSR 0x4C +#define GAZEL_ISAC_EN 0x08 +#define GAZEL_INT_ISAC 0x20 +#define GAZEL_HSCX_EN 0x01 +#define GAZEL_INT_HSCX 0x04 +#define GAZEL_PCI_EN 0x40 +#define GAZEL_IPAC_EN 0x03 + + +static LIST_HEAD(Cards); +static DEFINE_RWLOCK(card_lock); /* protect Cards */ + +static void +_set_debug(struct inf_hw *card) +{ + card->ipac.isac.dch.debug = debug; + card->ipac.hscx[0].bch.debug = debug; + card->ipac.hscx[1].bch.debug = debug; +} + +static int +set_debug(const char *val, struct kernel_param *kp) +{ + int ret; + struct inf_hw *card; + + ret = param_set_uint(val, kp); + if (!ret) { + read_lock(&card_lock); + list_for_each_entry(card, &Cards, list) + _set_debug(card); + read_unlock(&card_lock); + } + return ret; +} + +MODULE_AUTHOR("Karsten Keil"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(INFINEON_REV); +module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "infineon debug mask"); +module_param(irqloops, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(irqloops, "infineon maximal irqloops (default 4)"); + +/* Interface functions */ + +IOFUNC_IO(ISAC, inf_hw, isac.a.io) +IOFUNC_IO(IPAC, inf_hw, hscx.a.io) +IOFUNC_IND(ISAC, inf_hw, isac.a.io) +IOFUNC_IND(IPAC, inf_hw, hscx.a.io) +IOFUNC_MEMIO(ISAC, inf_hw, u32, isac.a.p) +IOFUNC_MEMIO(IPAC, inf_hw, u32, hscx.a.p) + +static irqreturn_t +diva_irq(int intno, void *dev_id) +{ + struct inf_hw *hw = dev_id; + u8 val; + + spin_lock(&hw->lock); + val = inb((u32)hw->cfg.start + DIVA_PCI_CTRL); + if (!(val & DIVA_IRQ_BIT)) { /* for us or shared ? */ + spin_unlock(&hw->lock); + return IRQ_NONE; /* shared */ + } + hw->irqcnt++; + mISDNipac_irq(&hw->ipac, irqloops); + spin_unlock(&hw->lock); + return IRQ_HANDLED; +} + +static irqreturn_t +diva20x_irq(int intno, void *dev_id) +{ + struct inf_hw *hw = dev_id; + u8 val; + + spin_lock(&hw->lock); + val = readb(hw->cfg.p); + if (!(val & PITA_INT0_STATUS)) { /* for us or shared ? */ + spin_unlock(&hw->lock); + return IRQ_NONE; /* shared */ + } + hw->irqcnt++; + mISDNipac_irq(&hw->ipac, irqloops); + writeb(PITA_INT0_STATUS, hw->cfg.p); /* ACK PITA INT0 */ + spin_unlock(&hw->lock); + return IRQ_HANDLED; +} + +static irqreturn_t +tiger_irq(int intno, void *dev_id) +{ + struct inf_hw *hw = dev_id; + u8 val; + + spin_lock(&hw->lock); + val = inb((u32)hw->cfg.start + TIGER_AUX_STATUS); + if (val & TIGER_IRQ_BIT) { /* for us or shared ? */ + spin_unlock(&hw->lock); + return IRQ_NONE; /* shared */ + } + hw->irqcnt++; + mISDNipac_irq(&hw->ipac, irqloops); + spin_unlock(&hw->lock); + return IRQ_HANDLED; +} + +static irqreturn_t +elsa_irq(int intno, void *dev_id) +{ + struct inf_hw *hw = dev_id; + u8 val; + + spin_lock(&hw->lock); + val = inb((u32)hw->cfg.start + ELSA_IRQ_ADDR); + if (!(val & ELSA_IRQ_MASK)) { + spin_unlock(&hw->lock); + return IRQ_NONE; /* shared */ + } + hw->irqcnt++; + mISDNipac_irq(&hw->ipac, irqloops); + spin_unlock(&hw->lock); + return IRQ_HANDLED; +} + +static irqreturn_t +niccy_irq(int intno, void *dev_id) +{ + struct inf_hw *hw = dev_id; + u32 val; + + spin_lock(&hw->lock); + val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); + if (!(val & NICCY_IRQ_BIT)) { /* for us or shared ? */ + spin_unlock(&hw->lock); + return IRQ_NONE; /* shared */ + } + outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); + hw->irqcnt++; + mISDNipac_irq(&hw->ipac, irqloops); + spin_unlock(&hw->lock); + return IRQ_HANDLED; +} + +static irqreturn_t +gazel_irq(int intno, void *dev_id) +{ + struct inf_hw *hw = dev_id; + irqreturn_t ret; + + spin_lock(&hw->lock); + ret = mISDNipac_irq(&hw->ipac, irqloops); + spin_unlock(&hw->lock); + return ret; +} + +static irqreturn_t +ipac_irq(int intno, void *dev_id) +{ + struct inf_hw *hw = dev_id; + u8 val; + + spin_lock(&hw->lock); + val = hw->ipac.read_reg(hw, IPAC_ISTA); + if (!(val & 0x3f)) { + spin_unlock(&hw->lock); + return IRQ_NONE; /* shared */ + } + hw->irqcnt++; + mISDNipac_irq(&hw->ipac, irqloops); + spin_unlock(&hw->lock); + return IRQ_HANDLED; +} + +static void +enable_hwirq(struct inf_hw *hw) +{ + u16 w; + u32 val; + + switch (hw->ci->typ) { + case INF_DIVA201: + case INF_DIVA202: + writel(PITA_INT0_ENABLE, hw->cfg.p); + break; + case INF_SPEEDWIN: + case INF_SAPHIR3: + outb(TIGER_IRQ_BIT, (u32)hw->cfg.start + TIGER_AUX_IRQMASK); + break; + case INF_QS1000: + outb(QS1000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR); + break; + case INF_QS3000: + outb(QS3000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR); + break; + case INF_NICCY: + val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); + val |= NICCY_IRQ_ENABLE;; + outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); + break; + case INF_SCT_1: + w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR); + w |= SCT_PLX_IRQ_ENABLE; + outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR); + break; + case INF_GAZEL_R685: + outb(GAZEL_ISAC_EN + GAZEL_HSCX_EN + GAZEL_PCI_EN, + (u32)hw->cfg.start + GAZEL_INCSR); + break; + case INF_GAZEL_R753: + outb(GAZEL_IPAC_EN + GAZEL_PCI_EN, + (u32)hw->cfg.start + GAZEL_INCSR); + break; + default: + break; + } +} + +static void +disable_hwirq(struct inf_hw *hw) +{ + u16 w; + u32 val; + + switch (hw->ci->typ) { + case INF_DIVA201: + case INF_DIVA202: + writel(0, hw->cfg.p); + break; + case INF_SPEEDWIN: + case INF_SAPHIR3: + outb(0, (u32)hw->cfg.start + TIGER_AUX_IRQMASK); + break; + case INF_QS1000: + outb(QS1000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR); + break; + case INF_QS3000: + outb(QS3000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR); + break; + case INF_NICCY: + val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); + val &= NICCY_IRQ_DISABLE; + outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); + break; + case INF_SCT_1: + w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR); + w &= (~SCT_PLX_IRQ_ENABLE); + outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR); + break; + case INF_GAZEL_R685: + case INF_GAZEL_R753: + outb(0, (u32)hw->cfg.start + GAZEL_INCSR); + break; + default: + break; + } +} + +static void +ipac_chip_reset(struct inf_hw *hw) +{ + hw->ipac.write_reg(hw, IPAC_POTA2, 0x20); + mdelay(5); + hw->ipac.write_reg(hw, IPAC_POTA2, 0x00); + mdelay(5); + hw->ipac.write_reg(hw, IPAC_CONF, hw->ipac.conf); + hw->ipac.write_reg(hw, IPAC_MASK, 0xc0); +} + +static void +reset_inf(struct inf_hw *hw) +{ + u16 w; + u32 val; + + if (debug & DEBUG_HW) + pr_notice("%s: resetting card\n", hw->name); + switch (hw->ci->typ) { + case INF_DIVA20: + case INF_DIVA20U: + outb(0, (u32)hw->cfg.start + DIVA_PCI_CTRL); + mdelay(10); + outb(DIVA_RESET_BIT, (u32)hw->cfg.start + DIVA_PCI_CTRL); + mdelay(10); + /* Workaround PCI9060 */ + outb(9, (u32)hw->cfg.start + 0x69); + outb(DIVA_RESET_BIT | DIVA_LED_A, + (u32)hw->cfg.start + DIVA_PCI_CTRL); + break; + case INF_DIVA201: + writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE, + hw->cfg.p + PITA_MISC_REG); + mdelay(1); + writel(PITA_PARA_MPX_MODE, hw->cfg.p + PITA_MISC_REG); + mdelay(10); + break; + case INF_DIVA202: + writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE, + hw->cfg.p + PITA_MISC_REG); + mdelay(1); + writel(PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET, + hw->cfg.p + PITA_MISC_REG); + mdelay(10); + break; + case INF_SPEEDWIN: + case INF_SAPHIR3: + ipac_chip_reset(hw); + hw->ipac.write_reg(hw, IPAC_ACFG, 0xff); + hw->ipac.write_reg(hw, IPAC_AOE, 0x00); + hw->ipac.write_reg(hw, IPAC_PCFG, 0x12); + break; + case INF_QS1000: + case INF_QS3000: + ipac_chip_reset(hw); + hw->ipac.write_reg(hw, IPAC_ACFG, 0x00); + hw->ipac.write_reg(hw, IPAC_AOE, 0x3c); + hw->ipac.write_reg(hw, IPAC_ATX, 0xff); + break; + case INF_NICCY: + break; + case INF_SCT_1: + w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR); + w &= (~SCT_PLX_RESET_BIT); + outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR); + mdelay(10); + w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR); + w |= SCT_PLX_RESET_BIT; + outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR); + mdelay(10); + break; + case INF_GAZEL_R685: + val = inl((u32)hw->cfg.start + GAZEL_CNTRL); + val |= (GAZEL_RESET_9050 + GAZEL_RESET); + outl(val, (u32)hw->cfg.start + GAZEL_CNTRL); + val &= ~(GAZEL_RESET_9050 + GAZEL_RESET); + mdelay(4); + outl(val, (u32)hw->cfg.start + GAZEL_CNTRL); + mdelay(10); + hw->ipac.isac.adf2 = 0x87; + hw->ipac.hscx[0].slot = 0x1f; + hw->ipac.hscx[0].slot = 0x23; + break; + case INF_GAZEL_R753: + val = inl((u32)hw->cfg.start + GAZEL_CNTRL); + val |= (GAZEL_RESET_9050 + GAZEL_RESET); + outl(val, (u32)hw->cfg.start + GAZEL_CNTRL); + val &= ~(GAZEL_RESET_9050 + GAZEL_RESET); + mdelay(4); + outl(val, (u32)hw->cfg.start + GAZEL_CNTRL); + mdelay(10); + ipac_chip_reset(hw); + hw->ipac.write_reg(hw, IPAC_ACFG, 0xff); + hw->ipac.write_reg(hw, IPAC_AOE, 0x00); + hw->ipac.conf = 0x01; /* IOM off */ + break; + default: + return; + } + enable_hwirq(hw); +} + +static int +inf_ctrl(struct inf_hw *hw, u32 cmd, u_long arg) +{ + int ret = 0; + + switch (cmd) { + case HW_RESET_REQ: + reset_inf(hw); + break; + default: + pr_info("%s: %s unknown command %x %lx\n", + hw->name, __func__, cmd, arg); + ret = -EINVAL; + break; + } + return ret; +} + +static int __devinit +init_irq(struct inf_hw *hw) +{ + int ret, cnt = 3; + u_long flags; + + if (!hw->ci->irqfunc) + return -EINVAL; + ret = request_irq(hw->irq, hw->ci->irqfunc, IRQF_SHARED, hw->name, hw); + if (ret) { + pr_info("%s: couldn't get interrupt %d\n", hw->name, hw->irq); + return ret; + } + while (cnt--) { + spin_lock_irqsave(&hw->lock, flags); + reset_inf(hw); + ret = hw->ipac.init(&hw->ipac); + if (ret) { + spin_unlock_irqrestore(&hw->lock, flags); + pr_info("%s: ISAC init failed with %d\n", + hw->name, ret); + break; + } + spin_unlock_irqrestore(&hw->lock, flags); + msleep_interruptible(10); + if (debug & DEBUG_HW) + pr_notice("%s: IRQ %d count %d\n", hw->name, + hw->irq, hw->irqcnt); + if (!hw->irqcnt) { + pr_info("%s: IRQ(%d) got no requests during init %d\n", + hw->name, hw->irq, 3 - cnt); + } else + return 0; + } + free_irq(hw->irq, hw); + return -EIO; +} + +static void +release_io(struct inf_hw *hw) +{ + if (hw->cfg.mode) { + if (hw->cfg.p) { + release_mem_region(hw->cfg.start, hw->cfg.size); + iounmap(hw->cfg.p); + } else + release_region(hw->cfg.start, hw->cfg.size); + hw->cfg.mode = AM_NONE; + } + if (hw->addr.mode) { + if (hw->addr.p) { + release_mem_region(hw->addr.start, hw->addr.size); + iounmap(hw->addr.p); + } else + release_region(hw->addr.start, hw->addr.size); + hw->addr.mode = AM_NONE; + } +} + +static int __devinit +setup_io(struct inf_hw *hw) +{ + int err = 0; + + if (hw->ci->cfg_mode) { + hw->cfg.start = pci_resource_start(hw->pdev, hw->ci->cfg_bar); + hw->cfg.size = pci_resource_len(hw->pdev, hw->ci->cfg_bar); + if (hw->ci->cfg_mode == AM_MEMIO) { + if (!request_mem_region(hw->cfg.start, hw->cfg.size, + hw->name)) + err = -EBUSY; + } else { + if (!request_region(hw->cfg.start, hw->cfg.size, + hw->name)) + err = -EBUSY; + } + if (err) { + pr_info("mISDN: %s config port %lx (%lu bytes)" + "already in use\n", hw->name, + (ulong)hw->cfg.start, (ulong)hw->cfg.size); + return err; + } + if (hw->ci->cfg_mode == AM_MEMIO) + hw->cfg.p = ioremap(hw->cfg.start, hw->cfg.size); + hw->cfg.mode = hw->ci->cfg_mode; + if (debug & DEBUG_HW) + pr_notice("%s: IO cfg %lx (%lu bytes) mode%d\n", + hw->name, (ulong)hw->cfg.start, + (ulong)hw->cfg.size, hw->ci->cfg_mode); + + } + if (hw->ci->addr_mode) { + hw->addr.start = pci_resource_start(hw->pdev, hw->ci->addr_bar); + hw->addr.size = pci_resource_len(hw->pdev, hw->ci->addr_bar); + if (hw->ci->addr_mode == AM_MEMIO) { + if (!request_mem_region(hw->addr.start, hw->addr.size, + hw->name)) + err = -EBUSY; + } else { + if (!request_region(hw->addr.start, hw->addr.size, + hw->name)) + err = -EBUSY; + } + if (err) { + pr_info("mISDN: %s address port %lx (%lu bytes)" + "already in use\n", hw->name, + (ulong)hw->addr.start, (ulong)hw->addr.size); + return err; + } + if (hw->ci->addr_mode == AM_MEMIO) + hw->addr.p = ioremap(hw->addr.start, hw->addr.size); + hw->addr.mode = hw->ci->addr_mode; + if (debug & DEBUG_HW) + pr_notice("%s: IO addr %lx (%lu bytes) mode%d\n", + hw->name, (ulong)hw->addr.start, + (ulong)hw->addr.size, hw->ci->addr_mode); + + } + + switch (hw->ci->typ) { + case INF_DIVA20: + case INF_DIVA20U: + hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX; + hw->isac.mode = hw->cfg.mode; + hw->isac.a.io.ale = (u32)hw->cfg.start + DIVA_ISAC_ALE; + hw->isac.a.io.port = (u32)hw->cfg.start + DIVA_ISAC_PORT; + hw->hscx.mode = hw->cfg.mode; + hw->hscx.a.io.ale = (u32)hw->cfg.start + DIVA_HSCX_ALE; + hw->hscx.a.io.port = (u32)hw->cfg.start + DIVA_HSCX_PORT; + break; + case INF_DIVA201: + hw->ipac.type = IPAC_TYPE_IPAC; + hw->ipac.isac.off = 0x80; + hw->isac.mode = hw->addr.mode; + hw->isac.a.p = hw->addr.p; + hw->hscx.mode = hw->addr.mode; + hw->hscx.a.p = hw->addr.p; + break; + case INF_DIVA202: + hw->ipac.type = IPAC_TYPE_IPACX; + hw->isac.mode = hw->addr.mode; + hw->isac.a.p = hw->addr.p; + hw->hscx.mode = hw->addr.mode; + hw->hscx.a.p = hw->addr.p; + break; + case INF_SPEEDWIN: + case INF_SAPHIR3: + hw->ipac.type = IPAC_TYPE_IPAC; + hw->ipac.isac.off = 0x80; + hw->isac.mode = hw->cfg.mode; + hw->isac.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE; + hw->isac.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT; + hw->hscx.mode = hw->cfg.mode; + hw->hscx.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE; + hw->hscx.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT; + outb(0xff, (ulong)hw->cfg.start); + mdelay(1); + outb(0x00, (ulong)hw->cfg.start); + mdelay(1); + outb(TIGER_IOMASK, (ulong)hw->cfg.start + TIGER_AUX_CTRL); + break; + case INF_QS1000: + case INF_QS3000: + hw->ipac.type = IPAC_TYPE_IPAC; + hw->ipac.isac.off = 0x80; + hw->isac.a.io.ale = (u32)hw->addr.start; + hw->isac.a.io.port = (u32)hw->addr.start + 1; + hw->isac.mode = hw->addr.mode; + hw->hscx.a.io.ale = (u32)hw->addr.start; + hw->hscx.a.io.port = (u32)hw->addr.start + 1; + hw->hscx.mode = hw->addr.mode; + break; + case INF_NICCY: + hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX; + hw->isac.mode = hw->addr.mode; + hw->isac.a.io.ale = (u32)hw->addr.start + NICCY_ISAC_ALE; + hw->isac.a.io.port = (u32)hw->addr.start + NICCY_ISAC_PORT; + hw->hscx.mode = hw->addr.mode; + hw->hscx.a.io.ale = (u32)hw->addr.start + NICCY_HSCX_ALE; + hw->hscx.a.io.port = (u32)hw->addr.start + NICCY_HSCX_PORT; + break; + case INF_SCT_1: + hw->ipac.type = IPAC_TYPE_IPAC; + hw->ipac.isac.off = 0x80; + hw->isac.a.io.ale = (u32)hw->addr.start; + hw->isac.a.io.port = hw->isac.a.io.ale + 4; + hw->isac.mode = hw->addr.mode; + hw->hscx.a.io.ale = hw->isac.a.io.ale; + hw->hscx.a.io.port = hw->isac.a.io.port; + hw->hscx.mode = hw->addr.mode; + break; + case INF_SCT_2: + hw->ipac.type = IPAC_TYPE_IPAC; + hw->ipac.isac.off = 0x80; + hw->isac.a.io.ale = (u32)hw->addr.start + 0x08; + hw->isac.a.io.port = hw->isac.a.io.ale + 4; + hw->isac.mode = hw->addr.mode; + hw->hscx.a.io.ale = hw->isac.a.io.ale; + hw->hscx.a.io.port = hw->isac.a.io.port; + hw->hscx.mode = hw->addr.mode; + break; + case INF_SCT_3: + hw->ipac.type = IPAC_TYPE_IPAC; + hw->ipac.isac.off = 0x80; + hw->isac.a.io.ale = (u32)hw->addr.start + 0x10; + hw->isac.a.io.port = hw->isac.a.io.ale + 4; + hw->isac.mode = hw->addr.mode; + hw->hscx.a.io.ale = hw->isac.a.io.ale; + hw->hscx.a.io.port = hw->isac.a.io.port; + hw->hscx.mode = hw->addr.mode; + break; + case INF_SCT_4: + hw->ipac.type = IPAC_TYPE_IPAC; + hw->ipac.isac.off = 0x80; + hw->isac.a.io.ale = (u32)hw->addr.start + 0x20; + hw->isac.a.io.port = hw->isac.a.io.ale + 4; + hw->isac.mode = hw->addr.mode; + hw->hscx.a.io.ale = hw->isac.a.io.ale; + hw->hscx.a.io.port = hw->isac.a.io.port; + hw->hscx.mode = hw->addr.mode; + break; + case INF_GAZEL_R685: + hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX; + hw->ipac.isac.off = 0x80; + hw->isac.mode = hw->addr.mode; + hw->isac.a.io.port = (u32)hw->addr.start; + hw->hscx.mode = hw->addr.mode; + hw->hscx.a.io.port = hw->isac.a.io.port; + break; + case INF_GAZEL_R753: + hw->ipac.type = IPAC_TYPE_IPAC; + hw->ipac.isac.off = 0x80; + hw->isac.mode = hw->addr.mode; + hw->isac.a.io.ale = (u32)hw->addr.start; + hw->isac.a.io.port = (u32)hw->addr.start + GAZEL_IPAC_DATA_PORT; + hw->hscx.mode = hw->addr.mode; + hw->hscx.a.io.ale = hw->isac.a.io.ale; + hw->hscx.a.io.port = hw->isac.a.io.port; + break; + default: + return -EINVAL; + } + switch (hw->isac.mode) { + case AM_MEMIO: + ASSIGN_FUNC_IPAC(MIO, hw->ipac); + break; + case AM_IND_IO: + ASSIGN_FUNC_IPAC(IND, hw->ipac); + break; + case AM_IO: + ASSIGN_FUNC_IPAC(IO, hw->ipac); + break; + default: + return -EINVAL; + } + return 0; +} + +static void +release_card(struct inf_hw *card) { + ulong flags; + int i; + + spin_lock_irqsave(&card->lock, flags); + disable_hwirq(card); + spin_unlock_irqrestore(&card->lock, flags); + card->ipac.isac.release(&card->ipac.isac); + free_irq(card->irq, card); + mISDN_unregister_device(&card->ipac.isac.dch.dev); + release_io(card); + write_lock_irqsave(&card_lock, flags); + list_del(&card->list); + write_unlock_irqrestore(&card_lock, flags); + switch (card->ci->typ) { + case INF_SCT_2: + case INF_SCT_3: + case INF_SCT_4: + break; + case INF_SCT_1: + for (i = 0; i < 3; i++) { + if (card->sc[i]) + release_card(card->sc[i]); + card->sc[i] = NULL; + } + default: + pci_disable_device(card->pdev); + pci_set_drvdata(card->pdev, NULL); + break; + } + kfree(card); + inf_cnt--; +} + +static int __devinit +setup_instance(struct inf_hw *card) +{ + int err; + ulong flags; + + snprintf(card->name, MISDN_MAX_IDLEN - 1, "%s.%d", card->ci->name, + inf_cnt + 1); + write_lock_irqsave(&card_lock, flags); + list_add_tail(&card->list, &Cards); + write_unlock_irqrestore(&card_lock, flags); + + _set_debug(card); + card->ipac.isac.name = card->name; + card->ipac.name = card->name; + card->ipac.owner = THIS_MODULE; + spin_lock_init(&card->lock); + card->ipac.isac.hwlock = &card->lock; + card->ipac.hwlock = &card->lock; + card->ipac.ctrl = (void *)&inf_ctrl; + + err = setup_io(card); + if (err) + goto error_setup; + + card->ipac.isac.dch.dev.Bprotocols = + mISDNipac_init(&card->ipac, card); + + if (card->ipac.isac.dch.dev.Bprotocols == 0) + goto error_setup;; + + err = mISDN_register_device(&card->ipac.isac.dch.dev, + &card->pdev->dev, card->name); + if (err) + goto error; + + err = init_irq(card); + if (!err) { + inf_cnt++; + pr_notice("Infineon %d cards installed\n", inf_cnt); + return 0; + } + mISDN_unregister_device(&card->ipac.isac.dch.dev); +error: + card->ipac.release(&card->ipac); +error_setup: + release_io(card); + write_lock_irqsave(&card_lock, flags); + list_del(&card->list); + write_unlock_irqrestore(&card_lock, flags); + return err; +} + +static const struct inf_cinfo inf_card_info[] = { + { + INF_DIVA20, + "Dialogic Diva 2.0", + "diva20", + AM_IND_IO, AM_NONE, 2, 0, + &diva_irq + }, + { + INF_DIVA20U, + "Dialogic Diva 2.0U", + "diva20U", + AM_IND_IO, AM_NONE, 2, 0, + &diva_irq + }, + { + INF_DIVA201, + "Dialogic Diva 2.01", + "diva201", + AM_MEMIO, AM_MEMIO, 0, 1, + &diva20x_irq + }, + { + INF_DIVA202, + "Dialogic Diva 2.02", + "diva202", + AM_MEMIO, AM_MEMIO, 0, 1, + &diva20x_irq + }, + { + INF_SPEEDWIN, + "Sedlbauer SpeedWin PCI", + "speedwin", + AM_IND_IO, AM_NONE, 0, 0, + &tiger_irq + }, + { + INF_SAPHIR3, + "HST Saphir 3", + "saphir", + AM_IND_IO, AM_NONE, 0, 0, + &tiger_irq + }, + { + INF_QS1000, + "Develo Microlink PCI", + "qs1000", + AM_IO, AM_IND_IO, 1, 3, + &elsa_irq + }, + { + INF_QS3000, + "Develo QuickStep 3000", + "qs3000", + AM_IO, AM_IND_IO, 1, 3, + &elsa_irq + }, + { + INF_NICCY, + "Sagem NICCY", + "niccy", + AM_IO, AM_IND_IO, 0, 1, + &niccy_irq + }, + { + INF_SCT_1, + "SciTel Quadro", + "p1_scitel", + AM_IO, AM_IND_IO, 1, 5, + &ipac_irq + }, + { + INF_SCT_2, + "SciTel Quadro", + "p2_scitel", + AM_NONE, AM_IND_IO, 0, 4, + &ipac_irq + }, + { + INF_SCT_3, + "SciTel Quadro", + "p3_scitel", + AM_NONE, AM_IND_IO, 0, 3, + &ipac_irq + }, + { + INF_SCT_4, + "SciTel Quadro", + "p4_scitel", + AM_NONE, AM_IND_IO, 0, 2, + &ipac_irq + }, + { + INF_GAZEL_R685, + "Gazel R685", + "gazel685", + AM_IO, AM_IO, 1, 2, + &gazel_irq + }, + { + INF_GAZEL_R753, + "Gazel R753", + "gazel753", + AM_IO, AM_IND_IO, 1, 2, + &ipac_irq + }, + { + INF_NONE, + } +}; + +static const struct inf_cinfo * __devinit +get_card_info(enum inf_types typ) +{ + const struct inf_cinfo *ci = inf_card_info; + + while (ci->typ != INF_NONE) { + if (ci->typ == typ) + return ci; + ci++; + } + return NULL; +} + +static int __devinit +inf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int err = -ENOMEM; + struct inf_hw *card; + + card = kzalloc(sizeof(struct inf_hw), GFP_KERNEL); + if (!card) { + pr_info("No memory for Infineon ISDN card\n"); + return err; + } + card->pdev = pdev; + err = pci_enable_device(pdev); + if (err) { + kfree(card); + return err; + } + card->ci = get_card_info(ent->driver_data); + if (!card->ci) { + pr_info("mISDN: do not have informations about adapter at %s\n", + pci_name(pdev)); + kfree(card); + return -EINVAL; + } else + pr_notice("mISDN: found adapter %s at %s\n", + card->ci->full, pci_name(pdev)); + + card->irq = pdev->irq; + pci_set_drvdata(pdev, card); + err = setup_instance(card); + if (err) { + pci_disable_device(card->pdev); + kfree(card); + pci_set_drvdata(pdev, NULL); + } else if (ent->driver_data == INF_SCT_1) { + int i; + struct inf_hw *sc; + + for (i = 1; i < 4; i++) { + sc = kzalloc(sizeof(struct inf_hw), GFP_KERNEL); + if (!sc) { + release_card(card); + return -ENOMEM; + } + sc->irq = card->irq; + sc->pdev = card->pdev; + sc->ci = card->ci + i; + err = setup_instance(sc); + if (err) { + kfree(sc); + release_card(card); + } else + card->sc[i - 1] = sc; + } + } + return err; +} + +static void __devexit +inf_remove(struct pci_dev *pdev) +{ + struct inf_hw *card = pci_get_drvdata(pdev); + + if (card) + release_card(card); + else + pr_debug("%s: drvdata allready removed\n", __func__); +} + +static struct pci_driver infineon_driver = { + .name = "ISDN Infineon pci", + .probe = inf_probe, + .remove = __devexit_p(inf_remove), + .id_table = infineon_ids, +}; + +static int __init +infineon_init(void) +{ + int err; + + pr_notice("Infineon ISDN Driver Rev. %s\n", INFINEON_REV); + err = pci_register_driver(&infineon_driver); + return err; +} + +static void __exit +infineon_cleanup(void) +{ + pci_unregister_driver(&infineon_driver); +} + +module_init(infineon_init); +module_exit(infineon_cleanup); diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c new file mode 100644 index 00000000000..613ba043537 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/mISDNipac.c @@ -0,0 +1,1655 @@ +/* + * isac.c ISAC specific routines + * + * Author Karsten Keil + * + * Copyright 2009 by Karsten Keil + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include "ipac.h" + + +#define DBUSY_TIMER_VALUE 80 +#define ARCOFI_USE 1 + +#define ISAC_REV "2.0" + +MODULE_AUTHOR("Karsten Keil"); +MODULE_VERSION(ISAC_REV); +MODULE_LICENSE("GPL v2"); + +#define ReadISAC(is, o) (is->read_reg(is->dch.hw, o + is->off)) +#define WriteISAC(is, o, v) (is->write_reg(is->dch.hw, o + is->off, v)) +#define ReadHSCX(h, o) (h->ip->read_reg(h->ip->hw, h->off + o)) +#define WriteHSCX(h, o, v) (h->ip->write_reg(h->ip->hw, h->off + o, v)) +#define ReadIPAC(ip, o) (ip->read_reg(ip->hw, o)) +#define WriteIPAC(ip, o, v) (ip->write_reg(ip->hw, o, v)) + +static inline void +ph_command(struct isac_hw *isac, u8 command) +{ + pr_debug("%s: ph_command %x\n", isac->name, command); + if (isac->type & IPAC_TYPE_ISACX) + WriteISAC(isac, ISACX_CIX0, (command << 4) | 0xE); + else + WriteISAC(isac, ISAC_CIX0, (command << 2) | 3); +} + +static void +isac_ph_state_change(struct isac_hw *isac) +{ + switch (isac->state) { + case (ISAC_IND_RS): + case (ISAC_IND_EI): + ph_command(isac, ISAC_CMD_DUI); + } + schedule_event(&isac->dch, FLG_PHCHANGE); +} + +static void +isac_ph_state_bh(struct dchannel *dch) +{ + struct isac_hw *isac = container_of(dch, struct isac_hw, dch); + + switch (isac->state) { + case ISAC_IND_RS: + case ISAC_IND_EI: + dch->state = 0; + l1_event(dch->l1, HW_RESET_IND); + break; + case ISAC_IND_DID: + dch->state = 3; + l1_event(dch->l1, HW_DEACT_CNF); + break; + case ISAC_IND_DR: + dch->state = 3; + l1_event(dch->l1, HW_DEACT_IND); + break; + case ISAC_IND_PU: + dch->state = 4; + l1_event(dch->l1, HW_POWERUP_IND); + break; + case ISAC_IND_RSY: + if (dch->state <= 5) { + dch->state = 5; + l1_event(dch->l1, ANYSIGNAL); + } else { + dch->state = 8; + l1_event(dch->l1, LOSTFRAMING); + } + break; + case ISAC_IND_ARD: + dch->state = 6; + l1_event(dch->l1, INFO2); + break; + case ISAC_IND_AI8: + dch->state = 7; + l1_event(dch->l1, INFO4_P8); + break; + case ISAC_IND_AI10: + dch->state = 7; + l1_event(dch->l1, INFO4_P10); + break; + } + pr_debug("%s: TE newstate %x\n", isac->name, dch->state); +} + +void +isac_empty_fifo(struct isac_hw *isac, int count) +{ + u8 *ptr; + + pr_debug("%s: %s %d\n", isac->name, __func__, count); + + if (!isac->dch.rx_skb) { + isac->dch.rx_skb = mI_alloc_skb(isac->dch.maxlen, GFP_ATOMIC); + if (!isac->dch.rx_skb) { + pr_info("%s: D receive out of memory\n", isac->name); + WriteISAC(isac, ISAC_CMDR, 0x80); + return; + } + } + if ((isac->dch.rx_skb->len + count) >= isac->dch.maxlen) { + pr_debug("%s: %s overrun %d\n", isac->name, __func__, + isac->dch.rx_skb->len + count); + WriteISAC(isac, ISAC_CMDR, 0x80); + return; + } + ptr = skb_put(isac->dch.rx_skb, count); + isac->read_fifo(isac->dch.hw, isac->off, ptr, count); + WriteISAC(isac, ISAC_CMDR, 0x80); + if (isac->dch.debug & DEBUG_HW_DFIFO) { + char pfx[MISDN_MAX_IDLEN + 16]; + + snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-recv %s %d ", + isac->name, count); + print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count); + } +} + +static void +isac_fill_fifo(struct isac_hw *isac) +{ + int count, more; + u8 *ptr; + + if (!isac->dch.tx_skb) + return; + count = isac->dch.tx_skb->len - isac->dch.tx_idx; + if (count <= 0) + return; + + more = 0; + if (count > 32) { + more = !0; + count = 32; + } + pr_debug("%s: %s %d\n", isac->name, __func__, count); + ptr = isac->dch.tx_skb->data + isac->dch.tx_idx; + isac->dch.tx_idx += count; + isac->write_fifo(isac->dch.hw, isac->off, ptr, count); + WriteISAC(isac, ISAC_CMDR, more ? 0x8 : 0xa); + if (test_and_set_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) { + pr_debug("%s: %s dbusytimer running\n", isac->name, __func__); + del_timer(&isac->dch.timer); + } + init_timer(&isac->dch.timer); + isac->dch.timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); + add_timer(&isac->dch.timer); + if (isac->dch.debug & DEBUG_HW_DFIFO) { + char pfx[MISDN_MAX_IDLEN + 16]; + + snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-send %s %d ", + isac->name, count); + print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count); + } +} + +static void +isac_rme_irq(struct isac_hw *isac) +{ + u8 val, count; + + val = ReadISAC(isac, ISAC_RSTA); + if ((val & 0x70) != 0x20) { + if (val & 0x40) { + pr_debug("%s: ISAC RDO\n", isac->name); +#ifdef ERROR_STATISTIC + isac->dch.err_rx++; +#endif + } + if (!(val & 0x20)) { + pr_debug("%s: ISAC CRC error\n", isac->name); +#ifdef ERROR_STATISTIC + isac->dch.err_crc++; +#endif + } + WriteISAC(isac, ISAC_CMDR, 0x80); + if (isac->dch.rx_skb) + dev_kfree_skb(isac->dch.rx_skb); + isac->dch.rx_skb = NULL; + } else { + count = ReadISAC(isac, ISAC_RBCL) & 0x1f; + if (count == 0) + count = 32; + isac_empty_fifo(isac, count); + recv_Dchannel(&isac->dch); + } +} + +static void +isac_xpr_irq(struct isac_hw *isac) +{ + if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) + del_timer(&isac->dch.timer); + if (isac->dch.tx_skb && isac->dch.tx_idx < isac->dch.tx_skb->len) { + isac_fill_fifo(isac); + } else { + if (isac->dch.tx_skb) + dev_kfree_skb(isac->dch.tx_skb); + if (get_next_dframe(&isac->dch)) + isac_fill_fifo(isac); + } +} + +static void +isac_retransmit(struct isac_hw *isac) +{ + if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) + del_timer(&isac->dch.timer); + if (test_bit(FLG_TX_BUSY, &isac->dch.Flags)) { + /* Restart frame */ + isac->dch.tx_idx = 0; + isac_fill_fifo(isac); + } else if (isac->dch.tx_skb) { /* should not happen */ + pr_info("%s: tx_skb exist but not busy\n", isac->name); + test_and_set_bit(FLG_TX_BUSY, &isac->dch.Flags); + isac->dch.tx_idx = 0; + isac_fill_fifo(isac); + } else { + pr_info("%s: ISAC XDU no TX_BUSY\n", isac->name); + if (get_next_dframe(&isac->dch)) + isac_fill_fifo(isac); + } +} + +static void +isac_mos_irq(struct isac_hw *isac) +{ + u8 val; + int ret; + + val = ReadISAC(isac, ISAC_MOSR); + pr_debug("%s: ISAC MOSR %02x\n", isac->name, val); +#if ARCOFI_USE + if (val & 0x08) { + if (!isac->mon_rx) { + isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC); + if (!isac->mon_rx) { + pr_info("%s: ISAC MON RX out of memory!\n", + isac->name); + isac->mocr &= 0xf0; + isac->mocr |= 0x0a; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + goto afterMONR0; + } else + isac->mon_rxp = 0; + } + if (isac->mon_rxp >= MAX_MON_FRAME) { + isac->mocr &= 0xf0; + isac->mocr |= 0x0a; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + isac->mon_rxp = 0; + pr_debug("%s: ISAC MON RX overflow!\n", isac->name); + goto afterMONR0; + } + isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR0); + pr_debug("%s: ISAC MOR0 %02x\n", isac->name, + isac->mon_rx[isac->mon_rxp - 1]); + if (isac->mon_rxp == 1) { + isac->mocr |= 0x04; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + } + } +afterMONR0: + if (val & 0x80) { + if (!isac->mon_rx) { + isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC); + if (!isac->mon_rx) { + pr_info("%s: ISAC MON RX out of memory!\n", + isac->name); + isac->mocr &= 0x0f; + isac->mocr |= 0xa0; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + goto afterMONR1; + } else + isac->mon_rxp = 0; + } + if (isac->mon_rxp >= MAX_MON_FRAME) { + isac->mocr &= 0x0f; + isac->mocr |= 0xa0; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + isac->mon_rxp = 0; + pr_debug("%s: ISAC MON RX overflow!\n", isac->name); + goto afterMONR1; + } + isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR1); + pr_debug("%s: ISAC MOR1 %02x\n", isac->name, + isac->mon_rx[isac->mon_rxp - 1]); + isac->mocr |= 0x40; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + } +afterMONR1: + if (val & 0x04) { + isac->mocr &= 0xf0; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + isac->mocr |= 0x0a; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + if (isac->monitor) { + ret = isac->monitor(isac->dch.hw, MONITOR_RX_0, + isac->mon_rx, isac->mon_rxp); + if (ret) + kfree(isac->mon_rx); + } else { + pr_info("%s: MONITOR 0 received %d but no user\n", + isac->name, isac->mon_rxp); + kfree(isac->mon_rx); + } + isac->mon_rx = NULL; + isac->mon_rxp = 0; + } + if (val & 0x40) { + isac->mocr &= 0x0f; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + isac->mocr |= 0xa0; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + if (isac->monitor) { + ret = isac->monitor(isac->dch.hw, MONITOR_RX_1, + isac->mon_rx, isac->mon_rxp); + if (ret) + kfree(isac->mon_rx); + } else { + pr_info("%s: MONITOR 1 received %d but no user\n", + isac->name, isac->mon_rxp); + kfree(isac->mon_rx); + } + isac->mon_rx = NULL; + isac->mon_rxp = 0; + } + if (val & 0x02) { + if ((!isac->mon_tx) || (isac->mon_txc && + (isac->mon_txp >= isac->mon_txc) && !(val & 0x08))) { + isac->mocr &= 0xf0; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + isac->mocr |= 0x0a; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { + if (isac->monitor) + ret = isac->monitor(isac->dch.hw, + MONITOR_TX_0, NULL, 0); + } + kfree(isac->mon_tx); + isac->mon_tx = NULL; + isac->mon_txc = 0; + isac->mon_txp = 0; + goto AfterMOX0; + } + if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { + if (isac->monitor) + ret = isac->monitor(isac->dch.hw, + MONITOR_TX_0, NULL, 0); + kfree(isac->mon_tx); + isac->mon_tx = NULL; + isac->mon_txc = 0; + isac->mon_txp = 0; + goto AfterMOX0; + } + WriteISAC(isac, ISAC_MOX0, isac->mon_tx[isac->mon_txp++]); + pr_debug("%s: ISAC %02x -> MOX0\n", isac->name, + isac->mon_tx[isac->mon_txp - 1]); + } +AfterMOX0: + if (val & 0x20) { + if ((!isac->mon_tx) || (isac->mon_txc && + (isac->mon_txp >= isac->mon_txc) && !(val & 0x80))) { + isac->mocr &= 0x0f; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + isac->mocr |= 0xa0; + WriteISAC(isac, ISAC_MOCR, isac->mocr); + if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { + if (isac->monitor) + ret = isac->monitor(isac->dch.hw, + MONITOR_TX_1, NULL, 0); + } + kfree(isac->mon_tx); + isac->mon_tx = NULL; + isac->mon_txc = 0; + isac->mon_txp = 0; + goto AfterMOX1; + } + if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { + if (isac->monitor) + ret = isac->monitor(isac->dch.hw, + MONITOR_TX_1, NULL, 0); + kfree(isac->mon_tx); + isac->mon_tx = NULL; + isac->mon_txc = 0; + isac->mon_txp = 0; + goto AfterMOX1; + } + WriteISAC(isac, ISAC_MOX1, isac->mon_tx[isac->mon_txp++]); + pr_debug("%s: ISAC %02x -> MOX1\n", isac->name, + isac->mon_tx[isac->mon_txp - 1]); + } +AfterMOX1: + val = 0; /* dummy to avoid warning */ +#endif +} + +static void +isac_cisq_irq(struct isac_hw *isac) { + u8 val; + + val = ReadISAC(isac, ISAC_CIR0); + pr_debug("%s: ISAC CIR0 %02X\n", isac->name, val); + if (val & 2) { + pr_debug("%s: ph_state change %x->%x\n", isac->name, + isac->state, (val >> 2) & 0xf); + isac->state = (val >> 2) & 0xf; + isac_ph_state_change(isac); + } + if (val & 1) { + val = ReadISAC(isac, ISAC_CIR1); + pr_debug("%s: ISAC CIR1 %02X\n", isac->name, val); + } +} + +static void +isacsx_cic_irq(struct isac_hw *isac) +{ + u8 val; + + val = ReadISAC(isac, ISACX_CIR0); + pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val); + if (val & ISACX_CIR0_CIC0) { + pr_debug("%s: ph_state change %x->%x\n", isac->name, + isac->state, val >> 4); + isac->state = val >> 4; + isac_ph_state_change(isac); + } +} + +static void +isacsx_rme_irq(struct isac_hw *isac) +{ + int count; + u8 val; + + val = ReadISAC(isac, ISACX_RSTAD); + if ((val & (ISACX_RSTAD_VFR | + ISACX_RSTAD_RDO | + ISACX_RSTAD_CRC | + ISACX_RSTAD_RAB)) + != (ISACX_RSTAD_VFR | ISACX_RSTAD_CRC)) { + pr_debug("%s: RSTAD %#x, dropped\n", isac->name, val); +#ifdef ERROR_STATISTIC + if (val & ISACX_RSTAD_CRC) + isac->dch.err_rx++; + else + isac->dch.err_crc++; +#endif + WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC); + if (isac->dch.rx_skb) + dev_kfree_skb(isac->dch.rx_skb); + isac->dch.rx_skb = NULL; + } else { + count = ReadISAC(isac, ISACX_RBCLD) & 0x1f; + if (count == 0) + count = 32; + isac_empty_fifo(isac, count); + if (isac->dch.rx_skb) { + skb_trim(isac->dch.rx_skb, isac->dch.rx_skb->len - 1); + pr_debug("%s: dchannel received %d\n", isac->name, + isac->dch.rx_skb->len); + recv_Dchannel(&isac->dch); + } + } +} + +irqreturn_t +mISDNisac_irq(struct isac_hw *isac, u8 val) +{ + if (unlikely(!val)) + return IRQ_NONE; + pr_debug("%s: ISAC interrupt %02x\n", isac->name, val); + if (isac->type & IPAC_TYPE_ISACX) { + if (val & ISACX__CIC) + isacsx_cic_irq(isac); + if (val & ISACX__ICD) { + val = ReadISAC(isac, ISACX_ISTAD); + pr_debug("%s: ISTAD %02x\n", isac->name, val); + if (val & ISACX_D_XDU) { + pr_debug("%s: ISAC XDU\n", isac->name); +#ifdef ERROR_STATISTIC + isac->dch.err_tx++; +#endif + isac_retransmit(isac); + } + if (val & ISACX_D_XMR) { + pr_debug("%s: ISAC XMR\n", isac->name); +#ifdef ERROR_STATISTIC + isac->dch.err_tx++; +#endif + isac_retransmit(isac); + } + if (val & ISACX_D_XPR) + isac_xpr_irq(isac); + if (val & ISACX_D_RFO) { + pr_debug("%s: ISAC RFO\n", isac->name); + WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC); + } + if (val & ISACX_D_RME) + isacsx_rme_irq(isac); + if (val & ISACX_D_RPF) + isac_empty_fifo(isac, 0x20); + } + } else { + if (val & 0x80) /* RME */ + isac_rme_irq(isac); + if (val & 0x40) /* RPF */ + isac_empty_fifo(isac, 32); + if (val & 0x10) /* XPR */ + isac_xpr_irq(isac); + if (val & 0x04) /* CISQ */ + isac_cisq_irq(isac); + if (val & 0x20) /* RSC - never */ + pr_debug("%s: ISAC RSC interrupt\n", isac->name); + if (val & 0x02) /* SIN - never */ + pr_debug("%s: ISAC SIN interrupt\n", isac->name); + if (val & 0x01) { /* EXI */ + val = ReadISAC(isac, ISAC_EXIR); + pr_debug("%s: ISAC EXIR %02x\n", isac->name, val); + if (val & 0x80) /* XMR */ + pr_debug("%s: ISAC XMR\n", isac->name); + if (val & 0x40) { /* XDU */ + pr_debug("%s: ISAC XDU\n", isac->name); +#ifdef ERROR_STATISTIC + isac->dch.err_tx++; +#endif + isac_retransmit(isac); + } + if (val & 0x04) /* MOS */ + isac_mos_irq(isac); + } + } + return IRQ_HANDLED; +} +EXPORT_SYMBOL(mISDNisac_irq); + +static int +isac_l1hw(struct mISDNchannel *ch, struct sk_buff *skb) +{ + struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); + struct dchannel *dch = container_of(dev, struct dchannel, dev); + struct isac_hw *isac = container_of(dch, struct isac_hw, dch); + int ret = -EINVAL; + struct mISDNhead *hh = mISDN_HEAD_P(skb); + u32 id; + u_long flags; + + switch (hh->prim) { + case PH_DATA_REQ: + spin_lock_irqsave(isac->hwlock, flags); + ret = dchannel_senddata(dch, skb); + if (ret > 0) { /* direct TX */ + id = hh->id; /* skb can be freed */ + isac_fill_fifo(isac); + ret = 0; + spin_unlock_irqrestore(isac->hwlock, flags); + queue_ch_frame(ch, PH_DATA_CNF, id, NULL); + } else + spin_unlock_irqrestore(isac->hwlock, flags); + return ret; + case PH_ACTIVATE_REQ: + ret = l1_event(dch->l1, hh->prim); + break; + case PH_DEACTIVATE_REQ: + test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); + ret = l1_event(dch->l1, hh->prim); + break; + } + + if (!ret) + dev_kfree_skb(skb); + return ret; +} + +static int +isac_ctrl(struct isac_hw *isac, u32 cmd, u_long para) +{ + u8 tl = 0; + u_long flags; + + switch (cmd) { + case HW_TESTLOOP: + spin_lock_irqsave(isac->hwlock, flags); + if (!(isac->type & IPAC_TYPE_ISACX)) { + /* TODO: implement for IPAC_TYPE_ISACX */ + if (para & 1) /* B1 */ + tl |= 0x0c; + else if (para & 2) /* B2 */ + tl |= 0x3; + /* we only support IOM2 mode */ + WriteISAC(isac, ISAC_SPCR, tl); + if (tl) + WriteISAC(isac, ISAC_ADF1, 0x8); + else + WriteISAC(isac, ISAC_ADF1, 0x0); + } + spin_unlock_irqrestore(isac->hwlock, flags); + break; + default: + pr_debug("%s: %s unknown command %x %lx\n", isac->name, + __func__, cmd, para); + return -1; + } + return 0; +} + +static int +isac_l1cmd(struct dchannel *dch, u32 cmd) +{ + struct isac_hw *isac = container_of(dch, struct isac_hw, dch); + u_long flags; + + pr_debug("%s: cmd(%x) state(%02x)\n", isac->name, cmd, isac->state); + switch (cmd) { + case INFO3_P8: + spin_lock_irqsave(isac->hwlock, flags); + ph_command(isac, ISAC_CMD_AR8); + spin_unlock_irqrestore(isac->hwlock, flags); + break; + case INFO3_P10: + spin_lock_irqsave(isac->hwlock, flags); + ph_command(isac, ISAC_CMD_AR10); + spin_unlock_irqrestore(isac->hwlock, flags); + break; + case HW_RESET_REQ: + spin_lock_irqsave(isac->hwlock, flags); + if ((isac->state == ISAC_IND_EI) || + (isac->state == ISAC_IND_DR) || + (isac->state == ISAC_IND_RS)) + ph_command(isac, ISAC_CMD_TIM); + else + ph_command(isac, ISAC_CMD_RS); + spin_unlock_irqrestore(isac->hwlock, flags); + break; + case HW_DEACT_REQ: + skb_queue_purge(&dch->squeue); + if (dch->tx_skb) { + dev_kfree_skb(dch->tx_skb); + dch->tx_skb = NULL; + } + dch->tx_idx = 0; + if (dch->rx_skb) { + dev_kfree_skb(dch->rx_skb); + dch->rx_skb = NULL; + } + test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); + if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) + del_timer(&dch->timer); + break; + case HW_POWERUP_REQ: + spin_lock_irqsave(isac->hwlock, flags); + ph_command(isac, ISAC_CMD_TIM); + spin_unlock_irqrestore(isac->hwlock, flags); + break; + case PH_ACTIVATE_IND: + test_and_set_bit(FLG_ACTIVE, &dch->Flags); + _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, + GFP_ATOMIC); + break; + case PH_DEACTIVATE_IND: + test_and_clear_bit(FLG_ACTIVE, &dch->Flags); + _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, + GFP_ATOMIC); + break; + default: + pr_debug("%s: %s unknown command %x\n", isac->name, + __func__, cmd); + return -1; + } + return 0; +} + +static void +isac_release(struct isac_hw *isac) +{ + if (isac->type & IPAC_TYPE_ISACX) + WriteISAC(isac, ISACX_MASK, 0xff); + else + WriteISAC(isac, ISAC_MASK, 0xff); + if (isac->dch.timer.function != NULL) { + del_timer(&isac->dch.timer); + isac->dch.timer.function = NULL; + } + kfree(isac->mon_rx); + isac->mon_rx = NULL; + kfree(isac->mon_tx); + isac->mon_tx = NULL; + if (isac->dch.l1) + l1_event(isac->dch.l1, CLOSE_CHANNEL); + mISDN_freedchannel(&isac->dch); +} + +static void +dbusy_timer_handler(struct isac_hw *isac) +{ + int rbch, star; + u_long flags; + + if (test_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) { + spin_lock_irqsave(isac->hwlock, flags); + rbch = ReadISAC(isac, ISAC_RBCH); + star = ReadISAC(isac, ISAC_STAR); + pr_debug("%s: D-Channel Busy RBCH %02x STAR %02x\n", + isac->name, rbch, star); + if (rbch & ISAC_RBCH_XAC) /* D-Channel Busy */ + test_and_set_bit(FLG_L1_BUSY, &isac->dch.Flags); + else { + /* discard frame; reset transceiver */ + test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags); + if (isac->dch.tx_idx) + isac->dch.tx_idx = 0; + else + pr_info("%s: ISAC D-Channel Busy no tx_idx\n", + isac->name); + /* Transmitter reset */ + WriteISAC(isac, ISAC_CMDR, 0x01); + } + spin_unlock_irqrestore(isac->hwlock, flags); + } +} + +static int +open_dchannel(struct isac_hw *isac, struct channel_req *rq) +{ + pr_debug("%s: %s dev(%d) open from %p\n", isac->name, __func__, + isac->dch.dev.id, __builtin_return_address(1)); + if (rq->protocol != ISDN_P_TE_S0) + return -EINVAL; + if (rq->adr.channel == 1) + /* E-Channel not supported */ + return -EINVAL; + rq->ch = &isac->dch.dev.D; + rq->ch->protocol = rq->protocol; + if (isac->dch.state == 7) + _queue_data(rq->ch, PH_ACTIVATE_IND, MISDN_ID_ANY, + 0, NULL, GFP_KERNEL); + return 0; +} + +static const char *ISACVer[] = +{"2086/2186 V1.1", "2085 B1", "2085 B2", + "2085 V2.3"}; + +static int +isac_init(struct isac_hw *isac) +{ + u8 val; + int err = 0; + + if (!isac->dch.l1) { + err = create_l1(&isac->dch, isac_l1cmd); + if (err) + return err; + } + isac->mon_tx = NULL; + isac->mon_rx = NULL; + isac->dch.timer.function = (void *) dbusy_timer_handler; + isac->dch.timer.data = (long)isac; + init_timer(&isac->dch.timer); + isac->mocr = 0xaa; + if (isac->type & IPAC_TYPE_ISACX) { + /* Disable all IRQ */ + WriteISAC(isac, ISACX_MASK, 0xff); + val = ReadISAC(isac, ISACX_STARD); + pr_debug("%s: ISACX STARD %x\n", isac->name, val); + val = ReadISAC(isac, ISACX_ISTAD); + pr_debug("%s: ISACX ISTAD %x\n", isac->name, val); + val = ReadISAC(isac, ISACX_ISTA); + pr_debug("%s: ISACX ISTA %x\n", isac->name, val); + /* clear LDD */ + WriteISAC(isac, ISACX_TR_CONF0, 0x00); + /* enable transmitter */ + WriteISAC(isac, ISACX_TR_CONF2, 0x00); + /* transparent mode 0, RAC, stop/go */ + WriteISAC(isac, ISACX_MODED, 0xc9); + /* all HDLC IRQ unmasked */ + val = ReadISAC(isac, ISACX_ID); + if (isac->dch.debug & DEBUG_HW) + pr_notice("%s: ISACX Design ID %x\n", + isac->name, val & 0x3f); + val = ReadISAC(isac, ISACX_CIR0); + pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val); + isac->state = val >> 4; + isac_ph_state_change(isac); + ph_command(isac, ISAC_CMD_RS); + WriteISAC(isac, ISACX_MASK, IPACX__ON); + WriteISAC(isac, ISACX_MASKD, 0x00); + } else { /* old isac */ + WriteISAC(isac, ISAC_MASK, 0xff); + val = ReadISAC(isac, ISAC_STAR); + pr_debug("%s: ISAC STAR %x\n", isac->name, val); + val = ReadISAC(isac, ISAC_MODE); + pr_debug("%s: ISAC MODE %x\n", isac->name, val); + val = ReadISAC(isac, ISAC_ADF2); + pr_debug("%s: ISAC ADF2 %x\n", isac->name, val); + val = ReadISAC(isac, ISAC_ISTA); + pr_debug("%s: ISAC ISTA %x\n", isac->name, val); + if (val & 0x01) { + val = ReadISAC(isac, ISAC_EXIR); + pr_debug("%s: ISAC EXIR %x\n", isac->name, val); + } + val = ReadISAC(isac, ISAC_RBCH); + if (isac->dch.debug & DEBUG_HW) + pr_notice("%s: ISAC version (%x): %s\n", isac->name, + val, ISACVer[(val >> 5) & 3]); + isac->type |= ((val >> 5) & 3); + if (!isac->adf2) + isac->adf2 = 0x80; + if (!(isac->adf2 & 0x80)) { /* only IOM 2 Mode */ + pr_info("%s: only support IOM2 mode but adf2=%02x\n", + isac->name, isac->adf2); + isac_release(isac); + return -EINVAL; + } + WriteISAC(isac, ISAC_ADF2, isac->adf2); + WriteISAC(isac, ISAC_SQXR, 0x2f); + WriteISAC(isac, ISAC_SPCR, 0x00); + WriteISAC(isac, ISAC_STCR, 0x70); + WriteISAC(isac, ISAC_MODE, 0xc9); + WriteISAC(isac, ISAC_TIMR, 0x00); + WriteISAC(isac, ISAC_ADF1, 0x00); + val = ReadISAC(isac, ISAC_CIR0); + pr_debug("%s: ISAC CIR0 %x\n", isac->name, val); + isac->state = (val >> 2) & 0xf; + isac_ph_state_change(isac); + ph_command(isac, ISAC_CMD_RS); + WriteISAC(isac, ISAC_MASK, 0); + } + return err; +} + +int +mISDNisac_init(struct isac_hw *isac, void *hw) +{ + mISDN_initdchannel(&isac->dch, MAX_DFRAME_LEN_L1, isac_ph_state_bh); + isac->dch.hw = hw; + isac->dch.dev.D.send = isac_l1hw; + isac->init = isac_init; + isac->release = isac_release; + isac->ctrl = isac_ctrl; + isac->open = open_dchannel; + isac->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0); + isac->dch.dev.nrbchan = 2; + return 0; +} +EXPORT_SYMBOL(mISDNisac_init); + +static void +waitforCEC(struct hscx_hw *hx) +{ + u8 starb, to = 50; + + while (to) { + starb = ReadHSCX(hx, IPAC_STARB); + if (!(starb & 0x04)) + break; + udelay(1); + to--; + } + if (to < 50) + pr_debug("%s: B%1d CEC %d us\n", hx->ip->name, hx->bch.nr, + 50 - to); + if (!to) + pr_info("%s: B%1d CEC timeout\n", hx->ip->name, hx->bch.nr); +} + + +static void +waitforXFW(struct hscx_hw *hx) +{ + u8 starb, to = 50; + + while (to) { + starb = ReadHSCX(hx, IPAC_STARB); + if ((starb & 0x44) == 0x40) + break; + udelay(1); + to--; + } + if (to < 50) + pr_debug("%s: B%1d XFW %d us\n", hx->ip->name, hx->bch.nr, + 50 - to); + if (!to) + pr_info("%s: B%1d XFW timeout\n", hx->ip->name, hx->bch.nr); +} + +static void +hscx_cmdr(struct hscx_hw *hx, u8 cmd) +{ + if (hx->ip->type & IPAC_TYPE_IPACX) + WriteHSCX(hx, IPACX_CMDRB, cmd); + else { + waitforCEC(hx); + WriteHSCX(hx, IPAC_CMDRB, cmd); + } +} + +static void +hscx_empty_fifo(struct hscx_hw *hscx, u8 count) +{ + u8 *p; + + pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count); + if (!hscx->bch.rx_skb) { + hscx->bch.rx_skb = mI_alloc_skb(hscx->bch.maxlen, GFP_ATOMIC); + if (!hscx->bch.rx_skb) { + pr_info("%s: B receive out of memory\n", + hscx->ip->name); + hscx_cmdr(hscx, 0x80); /* RMC */ + return; + } + } + if ((hscx->bch.rx_skb->len + count) > hscx->bch.maxlen) { + pr_debug("%s: overrun %d\n", hscx->ip->name, + hscx->bch.rx_skb->len + count); + skb_trim(hscx->bch.rx_skb, 0); + hscx_cmdr(hscx, 0x80); /* RMC */ + return; + } + p = skb_put(hscx->bch.rx_skb, count); + + if (hscx->ip->type & IPAC_TYPE_IPACX) + hscx->ip->read_fifo(hscx->ip->hw, + hscx->off + IPACX_RFIFOB, p, count); + else + hscx->ip->read_fifo(hscx->ip->hw, + hscx->off, p, count); + + hscx_cmdr(hscx, 0x80); /* RMC */ + + if (hscx->bch.debug & DEBUG_HW_BFIFO) { + snprintf(hscx->log, 64, "B%1d-recv %s %d ", + hscx->bch.nr, hscx->ip->name, count); + print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count); + } +} + +static void +hscx_fill_fifo(struct hscx_hw *hscx) +{ + int count, more; + u8 *p; + + if (!hscx->bch.tx_skb) + return; + count = hscx->bch.tx_skb->len - hscx->bch.tx_idx; + if (count <= 0) + return; + p = hscx->bch.tx_skb->data + hscx->bch.tx_idx; + + more = test_bit(FLG_TRANSPARENT, &hscx->bch.Flags) ? 1 : 0; + if (count > hscx->fifo_size) { + count = hscx->fifo_size; + more = 1; + } + pr_debug("%s: B%1d %d/%d/%d\n", hscx->ip->name, hscx->bch.nr, count, + hscx->bch.tx_idx, hscx->bch.tx_skb->len); + hscx->bch.tx_idx += count; + + if (hscx->ip->type & IPAC_TYPE_IPACX) + hscx->ip->write_fifo(hscx->ip->hw, + hscx->off + IPACX_XFIFOB, p, count); + else { + waitforXFW(hscx); + hscx->ip->write_fifo(hscx->ip->hw, + hscx->off, p, count); + } + hscx_cmdr(hscx, more ? 0x08 : 0x0a); + + if (hscx->bch.debug & DEBUG_HW_BFIFO) { + snprintf(hscx->log, 64, "B%1d-send %s %d ", + hscx->bch.nr, hscx->ip->name, count); + print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count); + } +} + +static void +hscx_xpr(struct hscx_hw *hx) +{ + if (hx->bch.tx_skb && hx->bch.tx_idx < hx->bch.tx_skb->len) + hscx_fill_fifo(hx); + else { + if (hx->bch.tx_skb) { + /* send confirm, on trans, free on hdlc. */ + if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) + confirm_Bsend(&hx->bch); + dev_kfree_skb(hx->bch.tx_skb); + } + if (get_next_bframe(&hx->bch)) + hscx_fill_fifo(hx); + } +} + +static void +ipac_rme(struct hscx_hw *hx) +{ + int count; + u8 rstab; + + if (hx->ip->type & IPAC_TYPE_IPACX) + rstab = ReadHSCX(hx, IPACX_RSTAB); + else + rstab = ReadHSCX(hx, IPAC_RSTAB); + pr_debug("%s: B%1d RSTAB %02x\n", hx->ip->name, hx->bch.nr, rstab); + if ((rstab & 0xf0) != 0xa0) { + /* !(VFR && !RDO && CRC && !RAB) */ + if (!(rstab & 0x80)) { + if (hx->bch.debug & DEBUG_HW_BCHANNEL) + pr_notice("%s: B%1d invalid frame\n", + hx->ip->name, hx->bch.nr); + } + if (rstab & 0x40) { + if (hx->bch.debug & DEBUG_HW_BCHANNEL) + pr_notice("%s: B%1d RDO proto=%x\n", + hx->ip->name, hx->bch.nr, + hx->bch.state); + } + if (!(rstab & 0x20)) { + if (hx->bch.debug & DEBUG_HW_BCHANNEL) + pr_notice("%s: B%1d CRC error\n", + hx->ip->name, hx->bch.nr); + } + hscx_cmdr(hx, 0x80); /* Do RMC */ + return; + } + if (hx->ip->type & IPAC_TYPE_IPACX) + count = ReadHSCX(hx, IPACX_RBCLB); + else + count = ReadHSCX(hx, IPAC_RBCLB); + count &= (hx->fifo_size - 1); + if (count == 0) + count = hx->fifo_size; + hscx_empty_fifo(hx, count); + if (!hx->bch.rx_skb) + return; + if (hx->bch.rx_skb->len < 2) { + pr_debug("%s: B%1d frame to short %d\n", + hx->ip->name, hx->bch.nr, hx->bch.rx_skb->len); + skb_trim(hx->bch.rx_skb, 0); + } else { + skb_trim(hx->bch.rx_skb, hx->bch.rx_skb->len - 1); + recv_Bchannel(&hx->bch, 0); + } +} + +static void +ipac_irq(struct hscx_hw *hx, u8 ista) +{ + u8 istab, m, exirb = 0; + + if (hx->ip->type & IPAC_TYPE_IPACX) + istab = ReadHSCX(hx, IPACX_ISTAB); + else if (hx->ip->type & IPAC_TYPE_IPAC) { + istab = ReadHSCX(hx, IPAC_ISTAB); + m = (hx->bch.nr & 1) ? IPAC__EXA : IPAC__EXB; + if (m & ista) { + exirb = ReadHSCX(hx, IPAC_EXIRB); + pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name, + hx->bch.nr, exirb); + } + } else if (hx->bch.nr & 2) { /* HSCX B */ + if (ista & (HSCX__EXA | HSCX__ICA)) + ipac_irq(&hx->ip->hscx[0], ista); + if (ista & HSCX__EXB) { + exirb = ReadHSCX(hx, IPAC_EXIRB); + pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name, + hx->bch.nr, exirb); + } + istab = ista & 0xF8; + } else { /* HSCX A */ + istab = ReadHSCX(hx, IPAC_ISTAB); + if (ista & HSCX__EXA) { + exirb = ReadHSCX(hx, IPAC_EXIRB); + pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name, + hx->bch.nr, exirb); + } + istab = istab & 0xF8; + } + if (exirb & IPAC_B_XDU) + istab |= IPACX_B_XDU; + if (exirb & IPAC_B_RFO) + istab |= IPACX_B_RFO; + pr_debug("%s: B%1d ISTAB %02x\n", hx->ip->name, hx->bch.nr, istab); + + if (!test_bit(FLG_ACTIVE, &hx->bch.Flags)) + return; + + if (istab & IPACX_B_RME) + ipac_rme(hx); + + if (istab & IPACX_B_RPF) { + hscx_empty_fifo(hx, hx->fifo_size); + if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) { + /* receive transparent audio data */ + if (hx->bch.rx_skb) + recv_Bchannel(&hx->bch, 0); + } + } + + if (istab & IPACX_B_RFO) { + pr_debug("%s: B%1d RFO error\n", hx->ip->name, hx->bch.nr); + hscx_cmdr(hx, 0x40); /* RRES */ + } + + if (istab & IPACX_B_XPR) + hscx_xpr(hx); + + if (istab & IPACX_B_XDU) { + if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) { + hscx_fill_fifo(hx); + return; + } + pr_debug("%s: B%1d XDU error at len %d\n", hx->ip->name, + hx->bch.nr, hx->bch.tx_idx); + hx->bch.tx_idx = 0; + hscx_cmdr(hx, 0x01); /* XRES */ + } +} + +irqreturn_t +mISDNipac_irq(struct ipac_hw *ipac, int maxloop) +{ + int cnt = maxloop + 1; + u8 ista, istad; + struct isac_hw *isac = &ipac->isac; + + if (ipac->type & IPAC_TYPE_IPACX) { + ista = ReadIPAC(ipac, ISACX_ISTA); + while (ista && cnt--) { + pr_debug("%s: ISTA %02x\n", ipac->name, ista); + if (ista & IPACX__ICA) + ipac_irq(&ipac->hscx[0], ista); + if (ista & IPACX__ICB) + ipac_irq(&ipac->hscx[1], ista); + if (ista & (ISACX__ICD | ISACX__CIC)) + mISDNisac_irq(&ipac->isac, ista); + ista = ReadIPAC(ipac, ISACX_ISTA); + } + } else if (ipac->type & IPAC_TYPE_IPAC) { + ista = ReadIPAC(ipac, IPAC_ISTA); + while (ista && cnt--) { + pr_debug("%s: ISTA %02x\n", ipac->name, ista); + if (ista & (IPAC__ICD | IPAC__EXD)) { + istad = ReadISAC(isac, ISAC_ISTA); + pr_debug("%s: ISTAD %02x\n", ipac->name, istad); + if (istad & IPAC_D_TIN2) + pr_debug("%s TIN2 irq\n", ipac->name); + if (ista & IPAC__EXD) + istad |= 1; /* ISAC EXI */ + mISDNisac_irq(isac, istad); + } + if (ista & (IPAC__ICA | IPAC__EXA)) + ipac_irq(&ipac->hscx[0], ista); + if (ista & (IPAC__ICB | IPAC__EXB)) + ipac_irq(&ipac->hscx[1], ista); + ista = ReadIPAC(ipac, IPAC_ISTA); + } + } else if (ipac->type & IPAC_TYPE_HSCX) { + while (cnt) { + ista = ReadIPAC(ipac, IPAC_ISTAB + ipac->hscx[1].off); + pr_debug("%s: B2 ISTA %02x\n", ipac->name, ista); + if (ista) + ipac_irq(&ipac->hscx[1], ista); + istad = ReadISAC(isac, ISAC_ISTA); + pr_debug("%s: ISTAD %02x\n", ipac->name, istad); + if (istad) + mISDNisac_irq(isac, istad); + if (0 == (ista | istad)) + break; + cnt--; + } + } + if (cnt > maxloop) /* only for ISAC/HSCX without PCI IRQ test */ + return IRQ_NONE; + if (cnt < maxloop) + pr_debug("%s: %d irqloops cpu%d\n", ipac->name, + maxloop - cnt, smp_processor_id()); + if (maxloop && !cnt) + pr_notice("%s: %d IRQ LOOP cpu%d\n", ipac->name, + maxloop, smp_processor_id()); + return IRQ_HANDLED; +} +EXPORT_SYMBOL(mISDNipac_irq); + +static int +hscx_mode(struct hscx_hw *hscx, u32 bprotocol) +{ + pr_debug("%s: HSCX %c protocol %x-->%x ch %d\n", hscx->ip->name, + '@' + hscx->bch.nr, hscx->bch.state, bprotocol, hscx->bch.nr); + if (hscx->ip->type & IPAC_TYPE_IPACX) { + if (hscx->bch.nr & 1) { /* B1 and ICA */ + WriteIPAC(hscx->ip, ISACX_BCHA_TSDP_BC1, 0x80); + WriteIPAC(hscx->ip, ISACX_BCHA_CR, 0x88); + } else { /* B2 and ICB */ + WriteIPAC(hscx->ip, ISACX_BCHB_TSDP_BC1, 0x81); + WriteIPAC(hscx->ip, ISACX_BCHB_CR, 0x88); + } + switch (bprotocol) { + case ISDN_P_NONE: /* init */ + WriteHSCX(hscx, IPACX_MODEB, 0xC0); /* rec off */ + WriteHSCX(hscx, IPACX_EXMB, 0x30); /* std adj. */ + WriteHSCX(hscx, IPACX_MASKB, 0xFF); /* ints off */ + hscx_cmdr(hscx, 0x41); + test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags); + test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags); + break; + case ISDN_P_B_RAW: + WriteHSCX(hscx, IPACX_MODEB, 0x88); /* ex trans */ + WriteHSCX(hscx, IPACX_EXMB, 0x00); /* trans */ + hscx_cmdr(hscx, 0x41); + WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON); + test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags); + break; + case ISDN_P_B_HDLC: + WriteHSCX(hscx, IPACX_MODEB, 0xC0); /* trans */ + WriteHSCX(hscx, IPACX_EXMB, 0x00); /* hdlc,crc */ + hscx_cmdr(hscx, 0x41); + WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON); + test_and_set_bit(FLG_HDLC, &hscx->bch.Flags); + break; + default: + pr_info("%s: protocol not known %x\n", hscx->ip->name, + bprotocol); + return -ENOPROTOOPT; + } + } else if (hscx->ip->type & IPAC_TYPE_IPAC) { /* IPAC */ + WriteHSCX(hscx, IPAC_CCR1, 0x82); + WriteHSCX(hscx, IPAC_CCR2, 0x30); + WriteHSCX(hscx, IPAC_XCCR, 0x07); + WriteHSCX(hscx, IPAC_RCCR, 0x07); + WriteHSCX(hscx, IPAC_TSAX, hscx->slot); + WriteHSCX(hscx, IPAC_TSAR, hscx->slot); + switch (bprotocol) { + case ISDN_P_NONE: + WriteHSCX(hscx, IPAC_TSAX, 0x1F); + WriteHSCX(hscx, IPAC_TSAR, 0x1F); + WriteHSCX(hscx, IPAC_MODEB, 0x84); + WriteHSCX(hscx, IPAC_CCR1, 0x82); + WriteHSCX(hscx, IPAC_MASKB, 0xFF); /* ints off */ + test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags); + test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags); + break; + case ISDN_P_B_RAW: + WriteHSCX(hscx, IPAC_MODEB, 0xe4); /* ex trans */ + WriteHSCX(hscx, IPAC_CCR1, 0x82); + hscx_cmdr(hscx, 0x41); + WriteHSCX(hscx, IPAC_MASKB, 0); + test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags); + break; + case ISDN_P_B_HDLC: + WriteHSCX(hscx, IPAC_MODEB, 0x8c); + WriteHSCX(hscx, IPAC_CCR1, 0x8a); + hscx_cmdr(hscx, 0x41); + WriteHSCX(hscx, IPAC_MASKB, 0); + test_and_set_bit(FLG_HDLC, &hscx->bch.Flags); + break; + default: + pr_info("%s: protocol not known %x\n", hscx->ip->name, + bprotocol); + return -ENOPROTOOPT; + } + } else if (hscx->ip->type & IPAC_TYPE_HSCX) { /* HSCX */ + WriteHSCX(hscx, IPAC_CCR1, 0x85); + WriteHSCX(hscx, IPAC_CCR2, 0x30); + WriteHSCX(hscx, IPAC_XCCR, 0x07); + WriteHSCX(hscx, IPAC_RCCR, 0x07); + WriteHSCX(hscx, IPAC_TSAX, hscx->slot); + WriteHSCX(hscx, IPAC_TSAR, hscx->slot); + switch (bprotocol) { + case ISDN_P_NONE: + WriteHSCX(hscx, IPAC_TSAX, 0x1F); + WriteHSCX(hscx, IPAC_TSAR, 0x1F); + WriteHSCX(hscx, IPAC_MODEB, 0x84); + WriteHSCX(hscx, IPAC_CCR1, 0x85); + WriteHSCX(hscx, IPAC_MASKB, 0xFF); /* ints off */ + test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags); + test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags); + break; + case ISDN_P_B_RAW: + WriteHSCX(hscx, IPAC_MODEB, 0xe4); /* ex trans */ + WriteHSCX(hscx, IPAC_CCR1, 0x85); + hscx_cmdr(hscx, 0x41); + WriteHSCX(hscx, IPAC_MASKB, 0); + test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags); + break; + case ISDN_P_B_HDLC: + WriteHSCX(hscx, IPAC_MODEB, 0x8c); + WriteHSCX(hscx, IPAC_CCR1, 0x8d); + hscx_cmdr(hscx, 0x41); + WriteHSCX(hscx, IPAC_MASKB, 0); + test_and_set_bit(FLG_HDLC, &hscx->bch.Flags); + break; + default: + pr_info("%s: protocol not known %x\n", hscx->ip->name, + bprotocol); + return -ENOPROTOOPT; + } + } else + return -EINVAL; + hscx->bch.state = bprotocol; + return 0; +} + +static int +hscx_l2l1(struct mISDNchannel *ch, struct sk_buff *skb) +{ + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch); + int ret = -EINVAL; + struct mISDNhead *hh = mISDN_HEAD_P(skb); + u32 id; + u_long flags; + + switch (hh->prim) { + case PH_DATA_REQ: + spin_lock_irqsave(hx->ip->hwlock, flags); + ret = bchannel_senddata(bch, skb); + if (ret > 0) { /* direct TX */ + id = hh->id; /* skb can be freed */ + ret = 0; + hscx_fill_fifo(hx); + spin_unlock_irqrestore(hx->ip->hwlock, flags); + if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) + queue_ch_frame(ch, PH_DATA_CNF, id, NULL); + } else + spin_unlock_irqrestore(hx->ip->hwlock, flags); + return ret; + case PH_ACTIVATE_REQ: + spin_lock_irqsave(hx->ip->hwlock, flags); + if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) + ret = hscx_mode(hx, ch->protocol); + else + ret = 0; + spin_unlock_irqrestore(hx->ip->hwlock, flags); + if (!ret) + _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_KERNEL); + break; + case PH_DEACTIVATE_REQ: + spin_lock_irqsave(hx->ip->hwlock, flags); + mISDN_clear_bchannel(bch); + hscx_mode(hx, ISDN_P_NONE); + spin_unlock_irqrestore(hx->ip->hwlock, flags); + _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_KERNEL); + ret = 0; + break; + default: + pr_info("%s: %s unknown prim(%x,%x)\n", + hx->ip->name, __func__, hh->prim, hh->id); + ret = -EINVAL; + } + if (!ret) + dev_kfree_skb(skb); + return ret; +} + +static int +channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = 0; + break; + /* Nothing implemented yet */ + case MISDN_CTRL_FILL_EMPTY: + default: + pr_info("%s: unknown Op %x\n", __func__, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +hscx_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) +{ + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch); + int ret = -EINVAL; + u_long flags; + + pr_debug("%s: %s cmd:%x %p\n", hx->ip->name, __func__, cmd, arg); + switch (cmd) { + case CLOSE_CHANNEL: + test_and_clear_bit(FLG_OPEN, &bch->Flags); + if (test_bit(FLG_ACTIVE, &bch->Flags)) { + spin_lock_irqsave(hx->ip->hwlock, flags); + mISDN_freebchannel(bch); + hscx_mode(hx, ISDN_P_NONE); + spin_unlock_irqrestore(hx->ip->hwlock, flags); + } else { + skb_queue_purge(&bch->rqueue); + bch->rcount = 0; + } + ch->protocol = ISDN_P_NONE; + ch->peer = NULL; + module_put(hx->ip->owner); + ret = 0; + break; + case CONTROL_CHANNEL: + ret = channel_bctrl(bch, arg); + break; + default: + pr_info("%s: %s unknown prim(%x)\n", + hx->ip->name, __func__, cmd); + } + return ret; +} + +static void +free_ipac(struct ipac_hw *ipac) +{ + isac_release(&ipac->isac); +} + +static const char *HSCXVer[] = +{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7", + "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"}; + + + +static void +hscx_init(struct hscx_hw *hx) +{ + u8 val; + + WriteHSCX(hx, IPAC_RAH2, 0xFF); + WriteHSCX(hx, IPAC_XBCH, 0x00); + WriteHSCX(hx, IPAC_RLCR, 0x00); + + if (hx->ip->type & IPAC_TYPE_HSCX) { + WriteHSCX(hx, IPAC_CCR1, 0x85); + val = ReadHSCX(hx, HSCX_VSTR); + pr_debug("%s: HSCX VSTR %02x\n", hx->ip->name, val); + if (hx->bch.debug & DEBUG_HW) + pr_notice("%s: HSCX version %s\n", hx->ip->name, + HSCXVer[val & 0x0f]); + } else + WriteHSCX(hx, IPAC_CCR1, 0x82); + WriteHSCX(hx, IPAC_CCR2, 0x30); + WriteHSCX(hx, IPAC_XCCR, 0x07); + WriteHSCX(hx, IPAC_RCCR, 0x07); +} + +static int +ipac_init(struct ipac_hw *ipac) +{ + u8 val; + + if (ipac->type & IPAC_TYPE_HSCX) { + hscx_init(&ipac->hscx[0]); + hscx_init(&ipac->hscx[1]); + val = ReadIPAC(ipac, IPAC_ID); + } else if (ipac->type & IPAC_TYPE_IPAC) { + hscx_init(&ipac->hscx[0]); + hscx_init(&ipac->hscx[1]); + WriteIPAC(ipac, IPAC_MASK, IPAC__ON); + val = ReadIPAC(ipac, IPAC_CONF); + /* conf is default 0, but can be overwritten by card setup */ + pr_debug("%s: IPAC CONF %02x/%02x\n", ipac->name, + val, ipac->conf); + WriteIPAC(ipac, IPAC_CONF, ipac->conf); + val = ReadIPAC(ipac, IPAC_ID); + if (ipac->hscx[0].bch.debug & DEBUG_HW) + pr_notice("%s: IPAC Design ID %02x\n", ipac->name, val); + } + /* nothing special for IPACX to do here */ + return isac_init(&ipac->isac); +} + +static int +open_bchannel(struct ipac_hw *ipac, struct channel_req *rq) +{ + struct bchannel *bch; + + if (rq->adr.channel > 2) + return -EINVAL; + if (rq->protocol == ISDN_P_NONE) + return -EINVAL; + bch = &ipac->hscx[rq->adr.channel - 1].bch; + if (test_and_set_bit(FLG_OPEN, &bch->Flags)) + return -EBUSY; /* b-channel can be only open once */ + test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); + bch->ch.protocol = rq->protocol; + rq->ch = &bch->ch; + return 0; +} + +static int +channel_ctrl(struct ipac_hw *ipac, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = MISDN_CTRL_LOOP; + break; + case MISDN_CTRL_LOOP: + /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ + if (cq->channel < 0 || cq->channel > 3) { + ret = -EINVAL; + break; + } + ret = ipac->ctrl(ipac, HW_TESTLOOP, cq->channel); + break; + default: + pr_info("%s: unknown CTRL OP %x\n", ipac->name, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +ipac_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) +{ + struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); + struct dchannel *dch = container_of(dev, struct dchannel, dev); + struct isac_hw *isac = container_of(dch, struct isac_hw, dch); + struct ipac_hw *ipac = container_of(isac, struct ipac_hw, isac); + struct channel_req *rq; + int err = 0; + + pr_debug("%s: DCTRL: %x %p\n", ipac->name, cmd, arg); + switch (cmd) { + case OPEN_CHANNEL: + rq = arg; + if (rq->protocol == ISDN_P_TE_S0) + err = open_dchannel(isac, rq); + else + err = open_bchannel(ipac, rq); + if (err) + break; + if (!try_module_get(ipac->owner)) + pr_info("%s: cannot get module\n", ipac->name); + break; + case CLOSE_CHANNEL: + pr_debug("%s: dev(%d) close from %p\n", ipac->name, + dch->dev.id, __builtin_return_address(0)); + module_put(ipac->owner); + break; + case CONTROL_CHANNEL: + err = channel_ctrl(ipac, arg); + break; + default: + pr_debug("%s: unknown DCTRL command %x\n", ipac->name, cmd); + return -EINVAL; + } + return err; +} + +u32 +mISDNipac_init(struct ipac_hw *ipac, void *hw) +{ + u32 ret; + u8 i; + + ipac->hw = hw; + if (ipac->isac.dch.debug & DEBUG_HW) + pr_notice("%s: ipac type %x\n", ipac->name, ipac->type); + if (ipac->type & IPAC_TYPE_HSCX) { + ipac->isac.type = IPAC_TYPE_ISAC; + ipac->hscx[0].off = 0; + ipac->hscx[1].off = 0x40; + ipac->hscx[0].fifo_size = 32; + ipac->hscx[1].fifo_size = 32; + } else if (ipac->type & IPAC_TYPE_IPAC) { + ipac->isac.type = IPAC_TYPE_IPAC | IPAC_TYPE_ISAC; + ipac->hscx[0].off = 0; + ipac->hscx[1].off = 0x40; + ipac->hscx[0].fifo_size = 64; + ipac->hscx[1].fifo_size = 64; + } else if (ipac->type & IPAC_TYPE_IPACX) { + ipac->isac.type = IPAC_TYPE_IPACX | IPAC_TYPE_ISACX; + ipac->hscx[0].off = IPACX_OFF_ICA; + ipac->hscx[1].off = IPACX_OFF_ICB; + ipac->hscx[0].fifo_size = 64; + ipac->hscx[1].fifo_size = 64; + } else + return 0; + + mISDNisac_init(&ipac->isac, hw); + + ipac->isac.dch.dev.D.ctrl = ipac_dctrl; + + for (i = 0; i < 2; i++) { + ipac->hscx[i].bch.nr = i + 1; + set_channelmap(i + 1, ipac->isac.dch.dev.channelmap); + list_add(&ipac->hscx[i].bch.ch.list, + &ipac->isac.dch.dev.bchannels); + mISDN_initbchannel(&ipac->hscx[i].bch, MAX_DATA_MEM); + ipac->hscx[i].bch.ch.nr = i + 1; + ipac->hscx[i].bch.ch.send = &hscx_l2l1; + ipac->hscx[i].bch.ch.ctrl = hscx_bctrl; + ipac->hscx[i].bch.hw = hw; + ipac->hscx[i].ip = ipac; + /* default values for IOM time slots + * can be overwriten by card */ + ipac->hscx[i].slot = (i == 0) ? 0x2f : 0x03; + } + + ipac->init = ipac_init; + ipac->release = free_ipac; + + ret = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | + (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); + return ret; +} +EXPORT_SYMBOL(mISDNipac_init); + +static int __init +isac_mod_init(void) +{ + pr_notice("mISDNipac module version %s\n", ISAC_REV); + return 0; +} + +static void __exit +isac_mod_cleanup(void) +{ + pr_notice("mISDNipac module unloaded\n"); +} +module_init(isac_mod_init); +module_exit(isac_mod_cleanup); -- cgit v1.2.3-18-g5258 From 6115d2f3fcaebed5b88fa9cefd178bb5b07461ff Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 22 Jul 2009 19:52:24 +0200 Subject: mISDN: Driver for AVM Fritz!CARD PCI Add mISDN driver for AVM FRITZ!CARD PCI (all versions). Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/Kconfig | 8 + drivers/isdn/hardware/mISDN/Makefile | 1 + drivers/isdn/hardware/mISDN/avmfritz.c | 1152 ++++++++++++++++++++++++++++++++ 3 files changed, 1161 insertions(+) create mode 100644 drivers/isdn/hardware/mISDN/avmfritz.c (limited to 'drivers') diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig index a8542b81f95..212dee6adec 100644 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ b/drivers/isdn/hardware/mISDN/Kconfig @@ -39,6 +39,14 @@ config MISDN_HFCUSB Enable support for USB ISDN TAs with Cologne Chip AG's HFC-S USB ISDN Controller +config MISDN_AVMFRITZ + tristate "Support for AVM FRITZ!CARD PCI" + depends on MISDN + depends on PCI + select MISDN_IPAC + help + Enable support for AVMs FRITZ!CARD PCI cards + config MISDN_INFINEON tristate "Support for cards with Infineon chipset" depends on MISDN diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile index 2863455b493..8204d84af70 100644 --- a/drivers/isdn/hardware/mISDN/Makefile +++ b/drivers/isdn/hardware/mISDN/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o +obj-$(CONFIG_MISDN_AVMFRITZ) += avmfritz.o obj-$(CONFIG_MISDN_INFINEON) += mISDNinfineon.o # chip modules obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c new file mode 100644 index 00000000000..81ac541d40d --- /dev/null +++ b/drivers/isdn/hardware/mISDN/avmfritz.c @@ -0,0 +1,1152 @@ +/* + * avm_fritz.c low level stuff for AVM FRITZ!CARD PCI ISDN cards + * Thanks to AVM, Berlin for informations + * + * Author Karsten Keil + * + * Copyright 2009 by Karsten Keil + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include +#include +#include +#include +#include +#include "ipac.h" + + +#define AVMFRITZ_REV "2.1" + +static int AVM_cnt; +static int debug; + +enum { + AVM_FRITZ_PCI, + AVM_FRITZ_PCIV2, +}; + +#define HDLC_FIFO 0x0 +#define HDLC_STATUS 0x4 +#define CHIP_WINDOW 0x10 + +#define CHIP_INDEX 0x4 +#define AVM_HDLC_1 0x00 +#define AVM_HDLC_2 0x01 +#define AVM_ISAC_FIFO 0x02 +#define AVM_ISAC_REG_LOW 0x04 +#define AVM_ISAC_REG_HIGH 0x06 + +#define AVM_STATUS0_IRQ_ISAC 0x01 +#define AVM_STATUS0_IRQ_HDLC 0x02 +#define AVM_STATUS0_IRQ_TIMER 0x04 +#define AVM_STATUS0_IRQ_MASK 0x07 + +#define AVM_STATUS0_RESET 0x01 +#define AVM_STATUS0_DIS_TIMER 0x02 +#define AVM_STATUS0_RES_TIMER 0x04 +#define AVM_STATUS0_ENA_IRQ 0x08 +#define AVM_STATUS0_TESTBIT 0x10 + +#define AVM_STATUS1_INT_SEL 0x0f +#define AVM_STATUS1_ENA_IOM 0x80 + +#define HDLC_MODE_ITF_FLG 0x01 +#define HDLC_MODE_TRANS 0x02 +#define HDLC_MODE_CCR_7 0x04 +#define HDLC_MODE_CCR_16 0x08 +#define HDLC_MODE_TESTLOOP 0x80 + +#define HDLC_INT_XPR 0x80 +#define HDLC_INT_XDU 0x40 +#define HDLC_INT_RPR 0x20 +#define HDLC_INT_MASK 0xE0 + +#define HDLC_STAT_RME 0x01 +#define HDLC_STAT_RDO 0x10 +#define HDLC_STAT_CRCVFRRAB 0x0E +#define HDLC_STAT_CRCVFR 0x06 +#define HDLC_STAT_RML_MASK 0x3f00 + +#define HDLC_CMD_XRS 0x80 +#define HDLC_CMD_XME 0x01 +#define HDLC_CMD_RRS 0x20 +#define HDLC_CMD_XML_MASK 0x3f00 +#define HDLC_FIFO_SIZE 32 + +/* Fritz PCI v2.0 */ + +#define AVM_HDLC_FIFO_1 0x10 +#define AVM_HDLC_FIFO_2 0x18 + +#define AVM_HDLC_STATUS_1 0x14 +#define AVM_HDLC_STATUS_2 0x1c + +#define AVM_ISACX_INDEX 0x04 +#define AVM_ISACX_DATA 0x08 + +/* data struct */ +#define LOG_SIZE 63 + +struct hdlc_stat_reg { +#ifdef __BIG_ENDIAN + u8 fill; + u8 mode; + u8 xml; + u8 cmd; +#else + u8 cmd; + u8 xml; + u8 mode; + u8 fill; +#endif +} __attribute__((packed)); + +struct hdlc_hw { + union { + u32 ctrl; + struct hdlc_stat_reg sr; + } ctrl; + u32 stat; +}; + +struct fritzcard { + struct list_head list; + struct pci_dev *pdev; + char name[MISDN_MAX_IDLEN]; + u8 type; + u8 ctrlreg; + u16 irq; + u32 irqcnt; + u32 addr; + spinlock_t lock; /* hw lock */ + struct isac_hw isac; + struct hdlc_hw hdlc[2]; + struct bchannel bch[2]; + char log[LOG_SIZE + 1]; +}; + +static LIST_HEAD(Cards); +static DEFINE_RWLOCK(card_lock); /* protect Cards */ + +static void +_set_debug(struct fritzcard *card) +{ + card->isac.dch.debug = debug; + card->bch[0].debug = debug; + card->bch[1].debug = debug; +} + +static int +set_debug(const char *val, struct kernel_param *kp) +{ + int ret; + struct fritzcard *card; + + ret = param_set_uint(val, kp); + if (!ret) { + read_lock(&card_lock); + list_for_each_entry(card, &Cards, list) + _set_debug(card); + read_unlock(&card_lock); + } + return ret; +} + +MODULE_AUTHOR("Karsten Keil"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(AVMFRITZ_REV); +module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "avmfritz debug mask"); + +/* Interface functions */ + +static u8 +ReadISAC_V1(void *p, u8 offset) +{ + struct fritzcard *fc = p; + u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; + + outb(idx, fc->addr + CHIP_INDEX); + return inb(fc->addr + CHIP_WINDOW + (offset & 0xf)); +} + +static void +WriteISAC_V1(void *p, u8 offset, u8 value) +{ + struct fritzcard *fc = p; + u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; + + outb(idx, fc->addr + CHIP_INDEX); + outb(value, fc->addr + CHIP_WINDOW + (offset & 0xf)); +} + +static void +ReadFiFoISAC_V1(void *p, u8 off, u8 *data, int size) +{ + struct fritzcard *fc = p; + + outb(AVM_ISAC_FIFO, fc->addr + CHIP_INDEX); + insb(fc->addr + CHIP_WINDOW, data, size); +} + +static void +WriteFiFoISAC_V1(void *p, u8 off, u8 *data, int size) +{ + struct fritzcard *fc = p; + + outb(AVM_ISAC_FIFO, fc->addr + CHIP_INDEX); + outsb(fc->addr + CHIP_WINDOW, data, size); +} + +static u8 +ReadISAC_V2(void *p, u8 offset) +{ + struct fritzcard *fc = p; + + outl(offset, fc->addr + AVM_ISACX_INDEX); + return 0xff & inl(fc->addr + AVM_ISACX_DATA); +} + +static void +WriteISAC_V2(void *p, u8 offset, u8 value) +{ + struct fritzcard *fc = p; + + outl(offset, fc->addr + AVM_ISACX_INDEX); + outl(value, fc->addr + AVM_ISACX_DATA); +} + +static void +ReadFiFoISAC_V2(void *p, u8 off, u8 *data, int size) +{ + struct fritzcard *fc = p; + int i; + + outl(off, fc->addr + AVM_ISACX_INDEX); + for (i = 0; i < size; i++) + data[i] = 0xff & inl(fc->addr + AVM_ISACX_DATA); +} + +static void +WriteFiFoISAC_V2(void *p, u8 off, u8 *data, int size) +{ + struct fritzcard *fc = p; + int i; + + outl(off, fc->addr + AVM_ISACX_INDEX); + for (i = 0; i < size; i++) + outl(data[i], fc->addr + AVM_ISACX_DATA); +} + +static struct bchannel * +Sel_BCS(struct fritzcard *fc, u32 channel) +{ + if (test_bit(FLG_ACTIVE, &fc->bch[0].Flags) && + (fc->bch[0].nr & channel)) + return &fc->bch[0]; + else if (test_bit(FLG_ACTIVE, &fc->bch[1].Flags) && + (fc->bch[1].nr & channel)) + return &fc->bch[1]; + else + return NULL; +} + +static inline void +__write_ctrl_pci(struct fritzcard *fc, struct hdlc_hw *hdlc, u32 channel) { + u32 idx = channel == 2 ? AVM_HDLC_2 : AVM_HDLC_1; + + outl(idx, fc->addr + CHIP_INDEX); + outl(hdlc->ctrl.ctrl, fc->addr + CHIP_WINDOW + HDLC_STATUS); +} + +static inline void +__write_ctrl_pciv2(struct fritzcard *fc, struct hdlc_hw *hdlc, u32 channel) { + outl(hdlc->ctrl.ctrl, fc->addr + (channel == 2 ? AVM_HDLC_STATUS_2 : + AVM_HDLC_STATUS_1)); +} + +void +write_ctrl(struct bchannel *bch, int which) { + struct fritzcard *fc = bch->hw; + struct hdlc_hw *hdlc; + + hdlc = &fc->hdlc[(bch->nr - 1) & 1]; + pr_debug("%s: hdlc %c wr%x ctrl %x\n", fc->name, '@' + bch->nr, + which, hdlc->ctrl.ctrl); + switch (fc->type) { + case AVM_FRITZ_PCIV2: + __write_ctrl_pciv2(fc, hdlc, bch->nr); + break; + case AVM_FRITZ_PCI: + __write_ctrl_pci(fc, hdlc, bch->nr); + break; + } +} + + +static inline u32 +__read_status_pci(u_long addr, u32 channel) +{ + outl(channel == 2 ? AVM_HDLC_2 : AVM_HDLC_1, addr + CHIP_INDEX); + return inl(addr + CHIP_WINDOW + HDLC_STATUS); +} + +static inline u32 +__read_status_pciv2(u_long addr, u32 channel) +{ + return inl(addr + (channel == 2 ? AVM_HDLC_STATUS_2 : + AVM_HDLC_STATUS_1)); +} + + +static u32 +read_status(struct fritzcard *fc, u32 channel) +{ + switch (fc->type) { + case AVM_FRITZ_PCIV2: + return __read_status_pciv2(fc->addr, channel); + case AVM_FRITZ_PCI: + return __read_status_pci(fc->addr, channel); + } + /* dummy */ + return 0; +} + +static void +enable_hwirq(struct fritzcard *fc) +{ + fc->ctrlreg |= AVM_STATUS0_ENA_IRQ; + outb(fc->ctrlreg, fc->addr + 2); +} + +static void +disable_hwirq(struct fritzcard *fc) +{ + fc->ctrlreg &= ~AVM_STATUS0_ENA_IRQ; + outb(fc->ctrlreg, fc->addr + 2); +} + +static int +modehdlc(struct bchannel *bch, int protocol) +{ + struct fritzcard *fc = bch->hw; + struct hdlc_hw *hdlc; + + hdlc = &fc->hdlc[(bch->nr - 1) & 1]; + pr_debug("%s: hdlc %c protocol %x-->%x ch %d\n", fc->name, + '@' + bch->nr, bch->state, protocol, bch->nr); + hdlc->ctrl.ctrl = 0; + switch (protocol) { + case -1: /* used for init */ + bch->state = -1; + case ISDN_P_NONE: + if (bch->state == ISDN_P_NONE) + break; + hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; + hdlc->ctrl.sr.mode = HDLC_MODE_TRANS; + write_ctrl(bch, 5); + bch->state = ISDN_P_NONE; + test_and_clear_bit(FLG_HDLC, &bch->Flags); + test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags); + break; + case ISDN_P_B_RAW: + bch->state = protocol; + hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; + hdlc->ctrl.sr.mode = HDLC_MODE_TRANS; + write_ctrl(bch, 5); + hdlc->ctrl.sr.cmd = HDLC_CMD_XRS; + write_ctrl(bch, 1); + hdlc->ctrl.sr.cmd = 0; + test_and_set_bit(FLG_TRANSPARENT, &bch->Flags); + break; + case ISDN_P_B_HDLC: + bch->state = protocol; + hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; + hdlc->ctrl.sr.mode = HDLC_MODE_ITF_FLG; + write_ctrl(bch, 5); + hdlc->ctrl.sr.cmd = HDLC_CMD_XRS; + write_ctrl(bch, 1); + hdlc->ctrl.sr.cmd = 0; + test_and_set_bit(FLG_HDLC, &bch->Flags); + break; + default: + pr_info("%s: protocol not known %x\n", fc->name, protocol); + return -ENOPROTOOPT; + } + return 0; +} + +static void +hdlc_empty_fifo(struct bchannel *bch, int count) +{ + u32 *ptr; + u8 *p; + u32 val, addr; + int cnt = 0; + struct fritzcard *fc = bch->hw; + + pr_debug("%s: %s %d\n", fc->name, __func__, count); + if (!bch->rx_skb) { + bch->rx_skb = mI_alloc_skb(bch->maxlen, GFP_ATOMIC); + if (!bch->rx_skb) { + pr_info("%s: B receive out of memory\n", + fc->name); + return; + } + } + if ((bch->rx_skb->len + count) > bch->maxlen) { + pr_debug("%s: overrun %d\n", fc->name, + bch->rx_skb->len + count); + return; + } + p = skb_put(bch->rx_skb, count); + ptr = (u32 *)p; + if (AVM_FRITZ_PCIV2 == fc->type) + addr = fc->addr + (bch->nr == 2 ? + AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1); + else { + addr = fc->addr + CHIP_WINDOW; + outl(bch->nr == 2 ? AVM_HDLC_2 : AVM_HDLC_1, fc->addr); + } + while (cnt < count) { + val = le32_to_cpu(inl(addr)); + put_unaligned(val, ptr); + ptr++; + cnt += 4; + } + if (debug & DEBUG_HW_BFIFO) { + snprintf(fc->log, LOG_SIZE, "B%1d-recv %s %d ", + bch->nr, fc->name, count); + print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count); + } +} + +static void +hdlc_fill_fifo(struct bchannel *bch) +{ + struct fritzcard *fc = bch->hw; + struct hdlc_hw *hdlc; + int count, cnt = 0; + u8 *p; + u32 *ptr, val, addr; + + hdlc = &fc->hdlc[(bch->nr - 1) & 1]; + if (!bch->tx_skb) + return; + count = bch->tx_skb->len - bch->tx_idx; + if (count <= 0) + return; + p = bch->tx_skb->data + bch->tx_idx; + hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME; + if (count > HDLC_FIFO_SIZE) { + count = HDLC_FIFO_SIZE; + } else { + if (test_bit(FLG_HDLC, &bch->Flags)) + hdlc->ctrl.sr.cmd |= HDLC_CMD_XME; + } + pr_debug("%s: %s %d/%d/%d", fc->name, __func__, count, + bch->tx_idx, bch->tx_skb->len); + ptr = (u32 *)p; + bch->tx_idx += count; + hdlc->ctrl.sr.xml = ((count == HDLC_FIFO_SIZE) ? 0 : count); + if (AVM_FRITZ_PCIV2 == fc->type) { + __write_ctrl_pciv2(fc, hdlc, bch->nr); + addr = fc->addr + (bch->nr == 2 ? + AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1); + } else { + __write_ctrl_pci(fc, hdlc, bch->nr); + addr = fc->addr + CHIP_WINDOW; + } + while (cnt < count) { + val = get_unaligned(ptr); + outl(cpu_to_le32(val), addr); + ptr++; + cnt += 4; + } + if (debug & DEBUG_HW_BFIFO) { + snprintf(fc->log, LOG_SIZE, "B%1d-send %s %d ", + bch->nr, fc->name, count); + print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count); + } +} + +static void +HDLC_irq_xpr(struct bchannel *bch) +{ + if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len) + hdlc_fill_fifo(bch); + else { + if (bch->tx_skb) { + /* send confirm, on trans, free on hdlc. */ + if (test_bit(FLG_TRANSPARENT, &bch->Flags)) + confirm_Bsend(bch); + dev_kfree_skb(bch->tx_skb); + } + if (get_next_bframe(bch)) + hdlc_fill_fifo(bch); + } +} + +static void +HDLC_irq(struct bchannel *bch, u32 stat) +{ + struct fritzcard *fc = bch->hw; + int len; + struct hdlc_hw *hdlc; + + hdlc = &fc->hdlc[(bch->nr - 1) & 1]; + pr_debug("%s: ch%d stat %#x\n", fc->name, bch->nr, stat); + if (stat & HDLC_INT_RPR) { + if (stat & HDLC_STAT_RDO) { + hdlc->ctrl.sr.xml = 0; + hdlc->ctrl.sr.cmd |= HDLC_CMD_RRS; + write_ctrl(bch, 1); + hdlc->ctrl.sr.cmd &= ~HDLC_CMD_RRS; + write_ctrl(bch, 1); + if (bch->rx_skb) + skb_trim(bch->rx_skb, 0); + } else { + len = (stat & HDLC_STAT_RML_MASK) >> 8; + if (!len) + len = 32; + hdlc_empty_fifo(bch, len); + if (!bch->rx_skb) + goto handle_tx; + if ((stat & HDLC_STAT_RME) || test_bit(FLG_TRANSPARENT, + &bch->Flags)) { + if (((stat & HDLC_STAT_CRCVFRRAB) == + HDLC_STAT_CRCVFR) || + test_bit(FLG_TRANSPARENT, &bch->Flags)) { + recv_Bchannel(bch, 0); + } else { + pr_debug("%s: got invalid frame\n", + fc->name); + skb_trim(bch->rx_skb, 0); + } + } + } + } +handle_tx: + if (stat & HDLC_INT_XDU) { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame on HDLC + * in transparent mode we send the next data + */ + if (bch->tx_skb) + pr_debug("%s: ch%d XDU len(%d) idx(%d) Flags(%lx)\n", + fc->name, bch->nr, bch->tx_skb->len, + bch->tx_idx, bch->Flags); + else + pr_debug("%s: ch%d XDU no tx_skb Flags(%lx)\n", + fc->name, bch->nr, bch->Flags); + if (bch->tx_skb && bch->tx_skb->len) { + if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) + bch->tx_idx = 0; + } + hdlc->ctrl.sr.xml = 0; + hdlc->ctrl.sr.cmd |= HDLC_CMD_XRS; + write_ctrl(bch, 1); + hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XRS; + HDLC_irq_xpr(bch); + return; + } else if (stat & HDLC_INT_XPR) + HDLC_irq_xpr(bch); +} + +static inline void +HDLC_irq_main(struct fritzcard *fc) +{ + u32 stat; + struct bchannel *bch; + + stat = read_status(fc, 1); + if (stat & HDLC_INT_MASK) { + bch = Sel_BCS(fc, 1); + if (bch) + HDLC_irq(bch, stat); + else + pr_debug("%s: spurious ch1 IRQ\n", fc->name); + } + stat = read_status(fc, 2); + if (stat & HDLC_INT_MASK) { + bch = Sel_BCS(fc, 2); + if (bch) + HDLC_irq(bch, stat); + else + pr_debug("%s: spurious ch2 IRQ\n", fc->name); + } +} + +static irqreturn_t +avm_fritz_interrupt(int intno, void *dev_id) +{ + struct fritzcard *fc = dev_id; + u8 val; + u8 sval; + + spin_lock(&fc->lock); + sval = inb(fc->addr + 2); + pr_debug("%s: irq stat0 %x\n", fc->name, sval); + if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) { + /* shared IRQ from other HW */ + spin_unlock(&fc->lock); + return IRQ_NONE; + } + fc->irqcnt++; + + if (!(sval & AVM_STATUS0_IRQ_ISAC)) { + val = ReadISAC_V1(fc, ISAC_ISTA); + mISDNisac_irq(&fc->isac, val); + } + if (!(sval & AVM_STATUS0_IRQ_HDLC)) + HDLC_irq_main(fc); + spin_unlock(&fc->lock); + return IRQ_HANDLED; +} + +static irqreturn_t +avm_fritzv2_interrupt(int intno, void *dev_id) +{ + struct fritzcard *fc = dev_id; + u8 val; + u8 sval; + + spin_lock(&fc->lock); + sval = inb(fc->addr + 2); + pr_debug("%s: irq stat0 %x\n", fc->name, sval); + if (!(sval & AVM_STATUS0_IRQ_MASK)) { + /* shared IRQ from other HW */ + spin_unlock(&fc->lock); + return IRQ_NONE; + } + fc->irqcnt++; + + if (sval & AVM_STATUS0_IRQ_HDLC) + HDLC_irq_main(fc); + if (sval & AVM_STATUS0_IRQ_ISAC) { + val = ReadISAC_V2(fc, ISACX_ISTA); + mISDNisac_irq(&fc->isac, val); + } + if (sval & AVM_STATUS0_IRQ_TIMER) { + pr_debug("%s: timer irq\n", fc->name); + outb(fc->ctrlreg | AVM_STATUS0_RES_TIMER, fc->addr + 2); + udelay(1); + outb(fc->ctrlreg, fc->addr + 2); + } + spin_unlock(&fc->lock); + return IRQ_HANDLED; +} + +static int +avm_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) +{ + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct fritzcard *fc = bch->hw; + int ret = -EINVAL; + struct mISDNhead *hh = mISDN_HEAD_P(skb); + u32 id; + u_long flags; + + switch (hh->prim) { + case PH_DATA_REQ: + spin_lock_irqsave(&fc->lock, flags); + ret = bchannel_senddata(bch, skb); + if (ret > 0) { /* direct TX */ + id = hh->id; /* skb can be freed */ + hdlc_fill_fifo(bch); + ret = 0; + spin_unlock_irqrestore(&fc->lock, flags); + if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) + queue_ch_frame(ch, PH_DATA_CNF, id, NULL); + } else + spin_unlock_irqrestore(&fc->lock, flags); + return ret; + case PH_ACTIVATE_REQ: + spin_lock_irqsave(&fc->lock, flags); + if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) + ret = modehdlc(bch, ch->protocol); + else + ret = 0; + spin_unlock_irqrestore(&fc->lock, flags); + if (!ret) + _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_KERNEL); + break; + case PH_DEACTIVATE_REQ: + spin_lock_irqsave(&fc->lock, flags); + mISDN_clear_bchannel(bch); + modehdlc(bch, ISDN_P_NONE); + spin_unlock_irqrestore(&fc->lock, flags); + _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_KERNEL); + ret = 0; + break; + } + if (!ret) + dev_kfree_skb(skb); + return ret; +} + +static void +inithdlc(struct fritzcard *fc) +{ + modehdlc(&fc->bch[0], -1); + modehdlc(&fc->bch[1], -1); +} + +void +clear_pending_hdlc_ints(struct fritzcard *fc) +{ + u32 val; + + val = read_status(fc, 1); + pr_debug("%s: HDLC 1 STA %x\n", fc->name, val); + val = read_status(fc, 2); + pr_debug("%s: HDLC 2 STA %x\n", fc->name, val); +} + +static void +reset_avm(struct fritzcard *fc) +{ + switch (fc->type) { + case AVM_FRITZ_PCI: + fc->ctrlreg = AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER; + break; + case AVM_FRITZ_PCIV2: + fc->ctrlreg = AVM_STATUS0_RESET; + break; + } + if (debug & DEBUG_HW) + pr_notice("%s: reset\n", fc->name); + disable_hwirq(fc); + mdelay(5); + switch (fc->type) { + case AVM_FRITZ_PCI: + fc->ctrlreg = AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER; + disable_hwirq(fc); + outb(AVM_STATUS1_ENA_IOM, fc->addr + 3); + break; + case AVM_FRITZ_PCIV2: + fc->ctrlreg = 0; + disable_hwirq(fc); + break; + } + mdelay(1); + if (debug & DEBUG_HW) + pr_notice("%s: S0/S1 %x/%x\n", fc->name, + inb(fc->addr + 2), inb(fc->addr + 3)); +} + +static int +init_card(struct fritzcard *fc) +{ + int ret, cnt = 3; + u_long flags; + + reset_avm(fc); /* disable IRQ */ + if (fc->type == AVM_FRITZ_PCIV2) + ret = request_irq(fc->irq, avm_fritzv2_interrupt, + IRQF_SHARED, fc->name, fc); + else + ret = request_irq(fc->irq, avm_fritz_interrupt, + IRQF_SHARED, fc->name, fc); + if (ret) { + pr_info("%s: couldn't get interrupt %d\n", + fc->name, fc->irq); + return ret; + } + while (cnt--) { + spin_lock_irqsave(&fc->lock, flags); + ret = fc->isac.init(&fc->isac); + if (ret) { + spin_unlock_irqrestore(&fc->lock, flags); + pr_info("%s: ISAC init failed with %d\n", + fc->name, ret); + break; + } + clear_pending_hdlc_ints(fc); + inithdlc(fc); + enable_hwirq(fc); + /* RESET Receiver and Transmitter */ + if (AVM_FRITZ_PCIV2 == fc->type) { + WriteISAC_V2(fc, ISACX_MASK, 0); + WriteISAC_V2(fc, ISACX_CMDRD, 0x41); + } else { + WriteISAC_V1(fc, ISAC_MASK, 0); + WriteISAC_V1(fc, ISAC_CMDR, 0x41); + } + spin_unlock_irqrestore(&fc->lock, flags); + /* Timeout 10ms */ + msleep_interruptible(10); + if (debug & DEBUG_HW) + pr_notice("%s: IRQ %d count %d\n", fc->name, + fc->irq, fc->irqcnt); + if (!fc->irqcnt) { + pr_info("%s: IRQ(%d) getting no IRQs during init %d\n", + fc->name, fc->irq, 3 - cnt); + reset_avm(fc); + } else + return 0; + } + free_irq(fc->irq, fc); + return -EIO; +} + +static int +channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + struct fritzcard *fc = bch->hw; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = 0; + break; + /* Nothing implemented yet */ + case MISDN_CTRL_FILL_EMPTY: + default: + pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +avm_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) +{ + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct fritzcard *fc = bch->hw; + int ret = -EINVAL; + u_long flags; + + pr_debug("%s: %s cmd:%x %p\n", fc->name, __func__, cmd, arg); + switch (cmd) { + case CLOSE_CHANNEL: + test_and_clear_bit(FLG_OPEN, &bch->Flags); + if (test_bit(FLG_ACTIVE, &bch->Flags)) { + spin_lock_irqsave(&fc->lock, flags); + mISDN_freebchannel(bch); + test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); + test_and_clear_bit(FLG_ACTIVE, &bch->Flags); + modehdlc(bch, ISDN_P_NONE); + spin_unlock_irqrestore(&fc->lock, flags); + } + ch->protocol = ISDN_P_NONE; + ch->peer = NULL; + module_put(THIS_MODULE); + ret = 0; + break; + case CONTROL_CHANNEL: + ret = channel_bctrl(bch, arg); + break; + default: + pr_info("%s: %s unknown prim(%x)\n", fc->name, __func__, cmd); + } + return ret; +} + +static int +channel_ctrl(struct fritzcard *fc, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = MISDN_CTRL_LOOP; + break; + case MISDN_CTRL_LOOP: + /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ + if (cq->channel < 0 || cq->channel > 3) { + ret = -EINVAL; + break; + } + ret = fc->isac.ctrl(&fc->isac, HW_TESTLOOP, cq->channel); + break; + default: + pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +open_bchannel(struct fritzcard *fc, struct channel_req *rq) +{ + struct bchannel *bch; + + if (rq->adr.channel > 2) + return -EINVAL; + if (rq->protocol == ISDN_P_NONE) + return -EINVAL; + bch = &fc->bch[rq->adr.channel - 1]; + if (test_and_set_bit(FLG_OPEN, &bch->Flags)) + return -EBUSY; /* b-channel can be only open once */ + test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); + bch->ch.protocol = rq->protocol; + rq->ch = &bch->ch; + return 0; +} + +/* + * device control function + */ +static int +avm_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) +{ + struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); + struct dchannel *dch = container_of(dev, struct dchannel, dev); + struct fritzcard *fc = dch->hw; + struct channel_req *rq; + int err = 0; + + pr_debug("%s: %s cmd:%x %p\n", fc->name, __func__, cmd, arg); + switch (cmd) { + case OPEN_CHANNEL: + rq = arg; + if (rq->protocol == ISDN_P_TE_S0) + err = fc->isac.open(&fc->isac, rq); + else + err = open_bchannel(fc, rq); + if (err) + break; + if (!try_module_get(THIS_MODULE)) + pr_info("%s: cannot get module\n", fc->name); + break; + case CLOSE_CHANNEL: + pr_debug("%s: dev(%d) close from %p\n", fc->name, dch->dev.id, + __builtin_return_address(0)); + module_put(THIS_MODULE); + break; + case CONTROL_CHANNEL: + err = channel_ctrl(fc, arg); + break; + default: + pr_debug("%s: %s unknown command %x\n", + fc->name, __func__, cmd); + return -EINVAL; + } + return err; +} + +int +setup_fritz(struct fritzcard *fc) +{ + u32 val, ver; + + if (!request_region(fc->addr, 32, fc->name)) { + pr_info("%s: AVM config port %x-%x already in use\n", + fc->name, fc->addr, fc->addr + 31); + return -EIO; + } + switch (fc->type) { + case AVM_FRITZ_PCI: + val = inl(fc->addr); + outl(AVM_HDLC_1, fc->addr + CHIP_INDEX); + ver = inl(fc->addr + CHIP_WINDOW + HDLC_STATUS) >> 24; + if (debug & DEBUG_HW) { + pr_notice("%s: PCI stat %#x\n", fc->name, val); + pr_notice("%s: PCI Class %X Rev %d\n", fc->name, + val & 0xff, (val >> 8) & 0xff); + pr_notice("%s: HDLC version %x\n", fc->name, ver & 0xf); + } + ASSIGN_FUNC(V1, ISAC, fc->isac); + fc->isac.type = IPAC_TYPE_ISAC; + break; + case AVM_FRITZ_PCIV2: + val = inl(fc->addr); + ver = inl(fc->addr + AVM_HDLC_STATUS_1) >> 24; + if (debug & DEBUG_HW) { + pr_notice("%s: PCI V2 stat %#x\n", fc->name, val); + pr_notice("%s: PCI V2 Class %X Rev %d\n", fc->name, + val & 0xff, (val>>8) & 0xff); + pr_notice("%s: HDLC version %x\n", fc->name, ver & 0xf); + } + ASSIGN_FUNC(V2, ISAC, fc->isac); + fc->isac.type = IPAC_TYPE_ISACX; + break; + default: + release_region(fc->addr, 32); + pr_info("%s: AVM unknown type %d\n", fc->name, fc->type); + return -ENODEV; + } + pr_notice("%s: %s config irq:%d base:0x%X\n", fc->name, + (fc->type == AVM_FRITZ_PCI) ? "AVM Fritz!CARD PCI" : + "AVM Fritz!CARD PCIv2", fc->irq, fc->addr); + return 0; +} + +static void +release_card(struct fritzcard *card) +{ + u_long flags; + + disable_hwirq(card); + spin_lock_irqsave(&card->lock, flags); + modehdlc(&card->bch[0], ISDN_P_NONE); + modehdlc(&card->bch[1], ISDN_P_NONE); + spin_unlock_irqrestore(&card->lock, flags); + card->isac.release(&card->isac); + free_irq(card->irq, card); + mISDN_freebchannel(&card->bch[1]); + mISDN_freebchannel(&card->bch[0]); + mISDN_unregister_device(&card->isac.dch.dev); + release_region(card->addr, 32); + pci_disable_device(card->pdev); + pci_set_drvdata(card->pdev, NULL); + write_lock_irqsave(&card_lock, flags); + list_del(&card->list); + write_unlock_irqrestore(&card_lock, flags); + kfree(card); + AVM_cnt--; +} + +static int __devinit +setup_instance(struct fritzcard *card) +{ + int i, err; + u_long flags; + + snprintf(card->name, MISDN_MAX_IDLEN - 1, "AVM.%d", AVM_cnt + 1); + write_lock_irqsave(&card_lock, flags); + list_add_tail(&card->list, &Cards); + write_unlock_irqrestore(&card_lock, flags); + + _set_debug(card); + card->isac.name = card->name; + spin_lock_init(&card->lock); + card->isac.hwlock = &card->lock; + mISDNisac_init(&card->isac, card); + + card->isac.dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | + (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); + card->isac.dch.dev.D.ctrl = avm_dctrl; + for (i = 0; i < 2; i++) { + card->bch[i].nr = i + 1; + set_channelmap(i + 1, card->isac.dch.dev.channelmap); + mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM); + card->bch[i].hw = card; + card->bch[i].ch.send = avm_l2l1B; + card->bch[i].ch.ctrl = avm_bctrl; + card->bch[i].ch.nr = i + 1; + list_add(&card->bch[i].ch.list, &card->isac.dch.dev.bchannels); + } + err = setup_fritz(card); + if (err) + goto error; + err = mISDN_register_device(&card->isac.dch.dev, &card->pdev->dev, + card->name); + if (err) + goto error_reg; + err = init_card(card); + if (!err) { + AVM_cnt++; + pr_notice("AVM %d cards installed DEBUG\n", AVM_cnt); + return 0; + } + mISDN_unregister_device(&card->isac.dch.dev); +error_reg: + release_region(card->addr, 32); +error: + card->isac.release(&card->isac); + mISDN_freebchannel(&card->bch[1]); + mISDN_freebchannel(&card->bch[0]); + write_lock_irqsave(&card_lock, flags); + list_del(&card->list); + write_unlock_irqrestore(&card_lock, flags); + kfree(card); + return err; +} + +static int __devinit +fritzpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int err = -ENOMEM; + struct fritzcard *card; + + card = kzalloc(sizeof(struct fritzcard), GFP_KERNEL); + if (!card) { + pr_info("No kmem for fritzcard\n"); + return err; + } + if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2) + card->type = AVM_FRITZ_PCIV2; + else + card->type = AVM_FRITZ_PCI; + card->pdev = pdev; + err = pci_enable_device(pdev); + if (err) { + kfree(card); + return err; + } + + pr_notice("mISDN: found adapter %s at %s\n", + (char *) ent->driver_data, pci_name(pdev)); + + card->addr = pci_resource_start(pdev, 1); + card->irq = pdev->irq; + pci_set_drvdata(pdev, card); + err = setup_instance(card); + if (err) + pci_set_drvdata(pdev, NULL); + return err; +} + +static void __devexit +fritz_remove_pci(struct pci_dev *pdev) +{ + struct fritzcard *card = pci_get_drvdata(pdev); + + if (card) + release_card(card); + else + if (debug) + pr_info("%s: drvdata allready removed\n", __func__); +} + +static struct pci_device_id fcpci_ids[] __devinitdata = { + { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID, + 0, 0, (unsigned long) "Fritz!Card PCI"}, + { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1_V2, PCI_ANY_ID, PCI_ANY_ID, + 0, 0, (unsigned long) "Fritz!Card PCI v2" }, + { } +}; +MODULE_DEVICE_TABLE(pci, fcpci_ids); + +static struct pci_driver fcpci_driver = { + .name = "fcpci", + .probe = fritzpci_probe, + .remove = __devexit_p(fritz_remove_pci), + .id_table = fcpci_ids, +}; + +static int __init AVM_init(void) +{ + int err; + + pr_notice("AVM Fritz PCI driver Rev. %s\n", AVMFRITZ_REV); + err = pci_register_driver(&fcpci_driver); + return err; +} + +static void __exit AVM_cleanup(void) +{ + pci_unregister_driver(&fcpci_driver); +} + +module_init(AVM_init); +module_exit(AVM_cleanup); -- cgit v1.2.3-18-g5258 From da2272c91ae81b41ae6fa6ebdc767a6cef73b770 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 22 Jul 2009 20:01:59 +0200 Subject: mISDN: Add support for Speedfax+ cards Add support for the Siemens ISAR DSP chip and cards based on it, including analog modem protocols. Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/Kconfig | 13 + drivers/isdn/hardware/mISDN/Makefile | 2 + drivers/isdn/hardware/mISDN/isar.h | 269 +++++ drivers/isdn/hardware/mISDN/mISDNisar.c | 1726 +++++++++++++++++++++++++++++++ drivers/isdn/hardware/mISDN/speedfax.c | 526 ++++++++++ 5 files changed, 2536 insertions(+) create mode 100644 drivers/isdn/hardware/mISDN/isar.h create mode 100644 drivers/isdn/hardware/mISDN/mISDNisar.c create mode 100644 drivers/isdn/hardware/mISDN/speedfax.c (limited to 'drivers') diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig index 212dee6adec..2600534be07 100644 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ b/drivers/isdn/hardware/mISDN/Kconfig @@ -47,6 +47,15 @@ config MISDN_AVMFRITZ help Enable support for AVMs FRITZ!CARD PCI cards +config MISDN_SPEEDFAX + tristate "Support for Sedlbauer Speedfax+" + depends on MISDN + depends on PCI + select MISDN_IPAC + select MISDN_ISAR + help + Enable support for Sedlbauer Speedfax+. + config MISDN_INFINEON tristate "Support for cards with Infineon chipset" depends on MISDN @@ -61,3 +70,7 @@ config MISDN_IPAC tristate depends on MISDN +config MISDN_ISAR + tristate + depends on MISDN + diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile index 8204d84af70..e18f964e185 100644 --- a/drivers/isdn/hardware/mISDN/Makefile +++ b/drivers/isdn/hardware/mISDN/Makefile @@ -7,6 +7,8 @@ obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o obj-$(CONFIG_MISDN_AVMFRITZ) += avmfritz.o +obj-$(CONFIG_MISDN_SPEEDFAX) += speedfax.o obj-$(CONFIG_MISDN_INFINEON) += mISDNinfineon.o # chip modules obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o +obj-$(CONFIG_MISDN_ISAR) += mISDNisar.o diff --git a/drivers/isdn/hardware/mISDN/isar.h b/drivers/isdn/hardware/mISDN/isar.h new file mode 100644 index 00000000000..092351acd2a --- /dev/null +++ b/drivers/isdn/hardware/mISDN/isar.h @@ -0,0 +1,269 @@ +/* + * + * isar.h ISAR (Siemens PSB 7110) specific defines + * + * Author Karsten Keil (keil@isdn4linux.de) + * + * Copyright 2009 by Karsten Keil + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "iohelper.h" + +struct isar_hw; + +struct isar_ch { + struct bchannel bch; + struct isar_hw *is; + struct timer_list ftimer; + u8 nr; + u8 dpath; + u8 mml; + u8 state; + u8 cmd; + u8 mod; + u8 newcmd; + u8 newmod; + u8 try_mod; + u8 conmsg[16]; +}; + +struct isar_hw { + struct isar_ch ch[2]; + void *hw; + spinlock_t *hwlock; /* lock HW acccess */ + char *name; + struct module *owner; + read_reg_t *read_reg; + write_reg_t *write_reg; + fifo_func_t *read_fifo; + fifo_func_t *write_fifo; + int (*ctrl)(void *, u32, u_long); + void (*release)(struct isar_hw *); + int (*init)(struct isar_hw *); + int (*open)(struct isar_hw *, struct channel_req *); + int (*firmware)(struct isar_hw *, const u8 *, int); + unsigned long Flags; + int version; + u8 bstat; + u8 iis; + u8 cmsb; + u8 clsb; + u8 buf[256]; + u8 log[256]; +}; + +#define ISAR_IRQMSK 0x04 +#define ISAR_IRQSTA 0x04 +#define ISAR_IRQBIT 0x75 +#define ISAR_CTRL_H 0x61 +#define ISAR_CTRL_L 0x60 +#define ISAR_IIS 0x58 +#define ISAR_IIA 0x58 +#define ISAR_HIS 0x50 +#define ISAR_HIA 0x50 +#define ISAR_MBOX 0x4c +#define ISAR_WADR 0x4a +#define ISAR_RADR 0x48 + +#define ISAR_HIS_VNR 0x14 +#define ISAR_HIS_DKEY 0x02 +#define ISAR_HIS_FIRM 0x1e +#define ISAR_HIS_STDSP 0x08 +#define ISAR_HIS_DIAG 0x05 +#define ISAR_HIS_P0CFG 0x3c +#define ISAR_HIS_P12CFG 0x24 +#define ISAR_HIS_SARTCFG 0x25 +#define ISAR_HIS_PUMPCFG 0x26 +#define ISAR_HIS_PUMPCTRL 0x2a +#define ISAR_HIS_IOM2CFG 0x27 +#define ISAR_HIS_IOM2REQ 0x07 +#define ISAR_HIS_IOM2CTRL 0x2b +#define ISAR_HIS_BSTREQ 0x0c +#define ISAR_HIS_PSTREQ 0x0e +#define ISAR_HIS_SDATA 0x20 +#define ISAR_HIS_DPS1 0x40 +#define ISAR_HIS_DPS2 0x80 +#define SET_DPS(x) ((x<<6) & 0xc0) + +#define ISAR_IIS_MSCMSD 0x3f +#define ISAR_IIS_VNR 0x15 +#define ISAR_IIS_DKEY 0x03 +#define ISAR_IIS_FIRM 0x1f +#define ISAR_IIS_STDSP 0x09 +#define ISAR_IIS_DIAG 0x25 +#define ISAR_IIS_GSTEV 0x00 +#define ISAR_IIS_BSTEV 0x28 +#define ISAR_IIS_BSTRSP 0x2c +#define ISAR_IIS_PSTRSP 0x2e +#define ISAR_IIS_PSTEV 0x2a +#define ISAR_IIS_IOM2RSP 0x27 +#define ISAR_IIS_RDATA 0x20 +#define ISAR_IIS_INVMSG 0x3f + +#define ISAR_CTRL_SWVER 0x10 +#define ISAR_CTRL_STST 0x40 + +#define ISAR_MSG_HWVER 0x20 + +#define ISAR_DP1_USE 1 +#define ISAR_DP2_USE 2 +#define ISAR_RATE_REQ 3 + +#define PMOD_DISABLE 0 +#define PMOD_FAX 1 +#define PMOD_DATAMODEM 2 +#define PMOD_HALFDUPLEX 3 +#define PMOD_V110 4 +#define PMOD_DTMF 5 +#define PMOD_DTMF_TRANS 6 +#define PMOD_BYPASS 7 + +#define PCTRL_ORIG 0x80 +#define PV32P2_V23R 0x40 +#define PV32P2_V22A 0x20 +#define PV32P2_V22B 0x10 +#define PV32P2_V22C 0x08 +#define PV32P2_V21 0x02 +#define PV32P2_BEL 0x01 + +/* LSB MSB in ISAR doc wrong !!! Arghhh */ +#define PV32P3_AMOD 0x80 +#define PV32P3_V32B 0x02 +#define PV32P3_V23B 0x01 +#define PV32P4_48 0x11 +#define PV32P5_48 0x05 +#define PV32P4_UT48 0x11 +#define PV32P5_UT48 0x0d +#define PV32P4_96 0x11 +#define PV32P5_96 0x03 +#define PV32P4_UT96 0x11 +#define PV32P5_UT96 0x0f +#define PV32P4_B96 0x91 +#define PV32P5_B96 0x0b +#define PV32P4_UTB96 0xd1 +#define PV32P5_UTB96 0x0f +#define PV32P4_120 0xb1 +#define PV32P5_120 0x09 +#define PV32P4_UT120 0xf1 +#define PV32P5_UT120 0x0f +#define PV32P4_144 0x99 +#define PV32P5_144 0x09 +#define PV32P4_UT144 0xf9 +#define PV32P5_UT144 0x0f +#define PV32P6_CTN 0x01 +#define PV32P6_ATN 0x02 + +#define PFAXP2_CTN 0x01 +#define PFAXP2_ATN 0x04 + +#define PSEV_10MS_TIMER 0x02 +#define PSEV_CON_ON 0x18 +#define PSEV_CON_OFF 0x19 +#define PSEV_V24_OFF 0x20 +#define PSEV_CTS_ON 0x21 +#define PSEV_CTS_OFF 0x22 +#define PSEV_DCD_ON 0x23 +#define PSEV_DCD_OFF 0x24 +#define PSEV_DSR_ON 0x25 +#define PSEV_DSR_OFF 0x26 +#define PSEV_REM_RET 0xcc +#define PSEV_REM_REN 0xcd +#define PSEV_GSTN_CLR 0xd4 + +#define PSEV_RSP_READY 0xbc +#define PSEV_LINE_TX_H 0xb3 +#define PSEV_LINE_TX_B 0xb2 +#define PSEV_LINE_RX_H 0xb1 +#define PSEV_LINE_RX_B 0xb0 +#define PSEV_RSP_CONN 0xb5 +#define PSEV_RSP_DISC 0xb7 +#define PSEV_RSP_FCERR 0xb9 +#define PSEV_RSP_SILDET 0xbe +#define PSEV_RSP_SILOFF 0xab +#define PSEV_FLAGS_DET 0xba + +#define PCTRL_CMD_TDTMF 0x5a + +#define PCTRL_CMD_FTH 0xa7 +#define PCTRL_CMD_FRH 0xa5 +#define PCTRL_CMD_FTM 0xa8 +#define PCTRL_CMD_FRM 0xa6 +#define PCTRL_CMD_SILON 0xac +#define PCTRL_CMD_CONT 0xa2 +#define PCTRL_CMD_ESC 0xa4 +#define PCTRL_CMD_SILOFF 0xab +#define PCTRL_CMD_HALT 0xa9 + +#define PCTRL_LOC_RET 0xcf +#define PCTRL_LOC_REN 0xce + +#define SMODE_DISABLE 0 +#define SMODE_V14 2 +#define SMODE_HDLC 3 +#define SMODE_BINARY 4 +#define SMODE_FSK_V14 5 + +#define SCTRL_HDMC_BOTH 0x00 +#define SCTRL_HDMC_DTX 0x80 +#define SCTRL_HDMC_DRX 0x40 +#define S_P1_OVSP 0x40 +#define S_P1_SNP 0x20 +#define S_P1_EOP 0x10 +#define S_P1_EDP 0x08 +#define S_P1_NSB 0x04 +#define S_P1_CHS_8 0x03 +#define S_P1_CHS_7 0x02 +#define S_P1_CHS_6 0x01 +#define S_P1_CHS_5 0x00 + +#define S_P2_BFT_DEF 0x10 + +#define IOM_CTRL_ENA 0x80 +#define IOM_CTRL_NOPCM 0x00 +#define IOM_CTRL_ALAW 0x02 +#define IOM_CTRL_ULAW 0x04 +#define IOM_CTRL_RCV 0x01 + +#define IOM_P1_TXD 0x10 + +#define HDLC_FED 0x40 +#define HDLC_FSD 0x20 +#define HDLC_FST 0x20 +#define HDLC_ERROR 0x1c +#define HDLC_ERR_FAD 0x10 +#define HDLC_ERR_RER 0x08 +#define HDLC_ERR_CER 0x04 +#define SART_NMD 0x01 + +#define BSTAT_RDM0 0x1 +#define BSTAT_RDM1 0x2 +#define BSTAT_RDM2 0x4 +#define BSTAT_RDM3 0x8 +#define BSTEV_TBO 0x1f +#define BSTEV_RBO 0x2f + +/* FAX State Machine */ +#define STFAX_NULL 0 +#define STFAX_READY 1 +#define STFAX_LINE 2 +#define STFAX_CONT 3 +#define STFAX_ACTIV 4 +#define STFAX_ESCAPE 5 +#define STFAX_SILDET 6 + +extern u32 mISDNisar_init(struct isar_hw *, void *); +extern void mISDNisar_irq(struct isar_hw *); diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c new file mode 100644 index 00000000000..de352a17673 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/mISDNisar.c @@ -0,0 +1,1726 @@ +/* + * mISDNisar.c ISAR (Siemens PSB 7110) specific functions + * + * Author Karsten Keil (keil@isdn4linux.de) + * + * Copyright 2009 by Karsten Keil + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* define this to enable static debug messages, if you kernel supports + * dynamic debugging, you should use debugfs for this + */ +/* #define DEBUG */ + +#include +#include +#include +#include "isar.h" + +#define ISAR_REV "2.1" + +MODULE_AUTHOR("Karsten Keil"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(ISAR_REV); + +#define DEBUG_HW_FIRMWARE_FIFO 0x10000 + +static const u8 faxmodulation_s[] = "3,24,48,72,73,74,96,97,98,121,122,145,146"; +static const u8 faxmodulation[] = {3, 24, 48, 72, 73, 74, 96, 97, 98, 121, + 122, 145, 146}; +#define FAXMODCNT 13 + +static void isar_setup(struct isar_hw *); + +static inline int +waitforHIA(struct isar_hw *isar, int timeout) +{ + int t = timeout; + u8 val = isar->read_reg(isar->hw, ISAR_HIA); + + while ((val & 1) && t) { + udelay(1); + t--; + val = isar->read_reg(isar->hw, ISAR_HIA); + } + pr_debug("%s: HIA after %dus\n", isar->name, timeout - t); + return timeout; +} + +/* + * send msg to ISAR mailbox + * if msg is NULL use isar->buf + */ +static int +send_mbox(struct isar_hw *isar, u8 his, u8 creg, u8 len, u8 *msg) +{ + if (!waitforHIA(isar, 1000)) + return 0; + pr_debug("send_mbox(%02x,%02x,%d)\n", his, creg, len); + isar->write_reg(isar->hw, ISAR_CTRL_H, creg); + isar->write_reg(isar->hw, ISAR_CTRL_L, len); + isar->write_reg(isar->hw, ISAR_WADR, 0); + if (!msg) + msg = isar->buf; + if (msg && len) { + isar->write_fifo(isar->hw, ISAR_MBOX, msg, len); + if (isar->ch[0].bch.debug & DEBUG_HW_BFIFO) { + int l = 0; + + while (l < (int)len) { + hex_dump_to_buffer(msg + l, len - l, 32, 1, + isar->log, 256, 1); + pr_debug("%s: %s %02x: %s\n", isar->name, + __func__, l, isar->log); + l += 32; + } + } + } + isar->write_reg(isar->hw, ISAR_HIS, his); + waitforHIA(isar, 1000); + return 1; +} + +/* + * receive message from ISAR mailbox + * if msg is NULL use isar->buf + */ +static void +rcv_mbox(struct isar_hw *isar, u8 *msg) +{ + if (!msg) + msg = isar->buf; + isar->write_reg(isar->hw, ISAR_RADR, 0); + if (msg && isar->clsb) { + isar->read_fifo(isar->hw, ISAR_MBOX, msg, isar->clsb); + if (isar->ch[0].bch.debug & DEBUG_HW_BFIFO) { + int l = 0; + + while (l < (int)isar->clsb) { + hex_dump_to_buffer(msg + l, isar->clsb - l, 32, + 1, isar->log, 256, 1); + pr_debug("%s: %s %02x: %s\n", isar->name, + __func__, l, isar->log); + l += 32; + } + } + } + isar->write_reg(isar->hw, ISAR_IIA, 0); +} + +static inline void +get_irq_infos(struct isar_hw *isar) +{ + isar->iis = isar->read_reg(isar->hw, ISAR_IIS); + isar->cmsb = isar->read_reg(isar->hw, ISAR_CTRL_H); + isar->clsb = isar->read_reg(isar->hw, ISAR_CTRL_L); + pr_debug("%s: rcv_mbox(%02x,%02x,%d)\n", isar->name, + isar->iis, isar->cmsb, isar->clsb); +} + +/* + * poll answer message from ISAR mailbox + * should be used only with ISAR IRQs disabled before DSP was started + * + */ +static int +poll_mbox(struct isar_hw *isar, int maxdelay) +{ + int t = maxdelay; + u8 irq; + + irq = isar->read_reg(isar->hw, ISAR_IRQBIT); + while (t && !(irq & ISAR_IRQSTA)) { + udelay(1); + t--; + } + if (t) { + get_irq_infos(isar); + rcv_mbox(isar, NULL); + } + pr_debug("%s: pulled %d bytes after %d us\n", + isar->name, isar->clsb, maxdelay - t); + return t; +} + +static int +ISARVersion(struct isar_hw *isar) +{ + int ver; + + /* disable ISAR IRQ */ + isar->write_reg(isar->hw, ISAR_IRQBIT, 0); + isar->buf[0] = ISAR_MSG_HWVER; + isar->buf[1] = 0; + isar->buf[2] = 1; + if (!send_mbox(isar, ISAR_HIS_VNR, 0, 3, NULL)) + return -1; + if (!poll_mbox(isar, 1000)) + return -2; + if (isar->iis == ISAR_IIS_VNR) { + if (isar->clsb == 1) { + ver = isar->buf[0] & 0xf; + return ver; + } + return -3; + } + return -4; +} + +static int +load_firmware(struct isar_hw *isar, const u8 *buf, int size) +{ + u32 saved_debug = isar->ch[0].bch.debug; + int ret, cnt; + u8 nom, noc; + u16 left, val, *sp = (u16 *)buf; + u8 *mp; + u_long flags; + + struct { + u16 sadr; + u16 len; + u16 d_key; + } blk_head; + + if (1 != isar->version) { + pr_err("%s: ISAR wrong version %d firmware download aborted\n", + isar->name, isar->version); + return -EINVAL; + } + if (!(saved_debug & DEBUG_HW_FIRMWARE_FIFO)) + isar->ch[0].bch.debug &= ~DEBUG_HW_BFIFO; + pr_debug("%s: load firmware %d words (%d bytes)\n", + isar->name, size/2, size); + cnt = 0; + size /= 2; + /* disable ISAR IRQ */ + spin_lock_irqsave(isar->hwlock, flags); + isar->write_reg(isar->hw, ISAR_IRQBIT, 0); + spin_unlock_irqrestore(isar->hwlock, flags); + while (cnt < size) { + blk_head.sadr = le16_to_cpu(*sp++); + blk_head.len = le16_to_cpu(*sp++); + blk_head.d_key = le16_to_cpu(*sp++); + cnt += 3; + pr_debug("ISAR firmware block (%#x,%d,%#x)\n", + blk_head.sadr, blk_head.len, blk_head.d_key & 0xff); + left = blk_head.len; + if (cnt + left > size) { + pr_info("%s: firmware error have %d need %d words\n", + isar->name, size, cnt + left); + ret = -EINVAL; + goto reterrflg; + } + spin_lock_irqsave(isar->hwlock, flags); + if (!send_mbox(isar, ISAR_HIS_DKEY, blk_head.d_key & 0xff, + 0, NULL)) { + pr_info("ISAR send_mbox dkey failed\n"); + ret = -ETIME; + goto reterror; + } + if (!poll_mbox(isar, 1000)) { + pr_warning("ISAR poll_mbox dkey failed\n"); + ret = -ETIME; + goto reterror; + } + spin_unlock_irqrestore(isar->hwlock, flags); + if ((isar->iis != ISAR_IIS_DKEY) || isar->cmsb || isar->clsb) { + pr_info("ISAR wrong dkey response (%x,%x,%x)\n", + isar->iis, isar->cmsb, isar->clsb); + ret = 1; + goto reterrflg; + } + while (left > 0) { + if (left > 126) + noc = 126; + else + noc = left; + nom = (2 * noc) + 3; + mp = isar->buf; + /* the ISAR is big endian */ + *mp++ = blk_head.sadr >> 8; + *mp++ = blk_head.sadr & 0xFF; + left -= noc; + cnt += noc; + *mp++ = noc; + pr_debug("%s: load %3d words at %04x\n", isar->name, + noc, blk_head.sadr); + blk_head.sadr += noc; + while (noc) { + val = le16_to_cpu(*sp++); + *mp++ = val >> 8; + *mp++ = val & 0xFF;; + noc--; + } + spin_lock_irqsave(isar->hwlock, flags); + if (!send_mbox(isar, ISAR_HIS_FIRM, 0, nom, NULL)) { + pr_info("ISAR send_mbox prog failed\n"); + ret = -ETIME; + goto reterror; + } + if (!poll_mbox(isar, 1000)) { + pr_info("ISAR poll_mbox prog failed\n"); + ret = -ETIME; + goto reterror; + } + spin_unlock_irqrestore(isar->hwlock, flags); + if ((isar->iis != ISAR_IIS_FIRM) || + isar->cmsb || isar->clsb) { + pr_info("ISAR wrong prog response (%x,%x,%x)\n", + isar->iis, isar->cmsb, isar->clsb); + ret = -EIO; + goto reterrflg; + } + } + pr_debug("%s: ISAR firmware block %d words loaded\n", + isar->name, blk_head.len); + } + isar->ch[0].bch.debug = saved_debug; + /* 10ms delay */ + cnt = 10; + while (cnt--) + mdelay(1); + isar->buf[0] = 0xff; + isar->buf[1] = 0xfe; + isar->bstat = 0; + spin_lock_irqsave(isar->hwlock, flags); + if (!send_mbox(isar, ISAR_HIS_STDSP, 0, 2, NULL)) { + pr_info("ISAR send_mbox start dsp failed\n"); + ret = -ETIME; + goto reterror; + } + if (!poll_mbox(isar, 1000)) { + pr_info("ISAR poll_mbox start dsp failed\n"); + ret = -ETIME; + goto reterror; + } + if ((isar->iis != ISAR_IIS_STDSP) || isar->cmsb || isar->clsb) { + pr_info("ISAR wrong start dsp response (%x,%x,%x)\n", + isar->iis, isar->cmsb, isar->clsb); + ret = -EIO; + goto reterror; + } else + pr_debug("%s: ISAR start dsp success\n", isar->name); + + /* NORMAL mode entered */ + /* Enable IRQs of ISAR */ + isar->write_reg(isar->hw, ISAR_IRQBIT, ISAR_IRQSTA); + spin_unlock_irqrestore(isar->hwlock, flags); + cnt = 1000; /* max 1s */ + while ((!isar->bstat) && cnt) { + mdelay(1); + cnt--; + } + if (!cnt) { + pr_info("ISAR no general status event received\n"); + ret = -ETIME; + goto reterrflg; + } else + pr_debug("%s: ISAR general status event %x\n", + isar->name, isar->bstat); + /* 10ms delay */ + cnt = 10; + while (cnt--) + mdelay(1); + isar->iis = 0; + spin_lock_irqsave(isar->hwlock, flags); + if (!send_mbox(isar, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) { + pr_info("ISAR send_mbox self tst failed\n"); + ret = -ETIME; + goto reterror; + } + spin_unlock_irqrestore(isar->hwlock, flags); + cnt = 10000; /* max 100 ms */ + while ((isar->iis != ISAR_IIS_DIAG) && cnt) { + udelay(10); + cnt--; + } + mdelay(1); + if (!cnt) { + pr_info("ISAR no self tst response\n"); + ret = -ETIME; + goto reterrflg; + } + if ((isar->cmsb == ISAR_CTRL_STST) && (isar->clsb == 1) + && (isar->buf[0] == 0)) + pr_debug("%s: ISAR selftest OK\n", isar->name); + else { + pr_info("ISAR selftest not OK %x/%x/%x\n", + isar->cmsb, isar->clsb, isar->buf[0]); + ret = -EIO; + goto reterrflg; + } + spin_lock_irqsave(isar->hwlock, flags); + isar->iis = 0; + if (!send_mbox(isar, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) { + pr_info("ISAR RQST SVN failed\n"); + ret = -ETIME; + goto reterror; + } + spin_unlock_irqrestore(isar->hwlock, flags); + cnt = 30000; /* max 300 ms */ + while ((isar->iis != ISAR_IIS_DIAG) && cnt) { + udelay(10); + cnt--; + } + mdelay(1); + if (!cnt) { + pr_info("ISAR no SVN response\n"); + ret = -ETIME; + goto reterrflg; + } else { + if ((isar->cmsb == ISAR_CTRL_SWVER) && (isar->clsb == 1)) { + pr_notice("%s: ISAR software version %#x\n", + isar->name, isar->buf[0]); + } else { + pr_info("%s: ISAR wrong swver response (%x,%x)" + " cnt(%d)\n", isar->name, isar->cmsb, + isar->clsb, cnt); + ret = -EIO; + goto reterrflg; + } + } + spin_lock_irqsave(isar->hwlock, flags); + isar_setup(isar); + spin_unlock_irqrestore(isar->hwlock, flags); + ret = 0; +reterrflg: + spin_lock_irqsave(isar->hwlock, flags); +reterror: + isar->ch[0].bch.debug = saved_debug; + if (ret) + /* disable ISAR IRQ */ + isar->write_reg(isar->hw, ISAR_IRQBIT, 0); + spin_unlock_irqrestore(isar->hwlock, flags); + return ret; +} + +static inline void +deliver_status(struct isar_ch *ch, int status) +{ + pr_debug("%s: HL->LL FAXIND %x\n", ch->is->name, status); + _queue_data(&ch->bch.ch, PH_CONTROL_IND, status, 0, NULL, GFP_ATOMIC); +} + +static inline void +isar_rcv_frame(struct isar_ch *ch) +{ + u8 *ptr; + + if (!ch->is->clsb) { + pr_debug("%s; ISAR zero len frame\n", ch->is->name); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + return; + } + switch (ch->bch.state) { + case ISDN_P_NONE: + pr_debug("%s: ISAR protocol 0 spurious IIS_RDATA %x/%x/%x\n", + ch->is->name, ch->is->iis, ch->is->cmsb, ch->is->clsb); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + break; + case ISDN_P_B_RAW: + case ISDN_P_B_L2DTMF: + case ISDN_P_B_MODEM_ASYNC: + if (!ch->bch.rx_skb) { + ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, + GFP_ATOMIC); + if (unlikely(!ch->bch.rx_skb)) { + pr_info("%s: B receive out of memory\n", + ch->is->name); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + break; + } + } + rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); + recv_Bchannel(&ch->bch, 0); + break; + case ISDN_P_B_HDLC: + if (!ch->bch.rx_skb) { + ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, + GFP_ATOMIC); + if (unlikely(!ch->bch.rx_skb)) { + pr_info("%s: B receive out of memory\n", + ch->is->name); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + break; + } + } + if ((ch->bch.rx_skb->len + ch->is->clsb) > + (ch->bch.maxlen + 2)) { + pr_debug("%s: incoming packet too large\n", + ch->is->name); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + skb_trim(ch->bch.rx_skb, 0); + break; + } + if (ch->is->cmsb & HDLC_ERROR) { + pr_debug("%s: ISAR frame error %x len %d\n", + ch->is->name, ch->is->cmsb, ch->is->clsb); +#ifdef ERROR_STATISTIC + if (ch->is->cmsb & HDLC_ERR_RER) + ch->bch.err_inv++; + if (ch->is->cmsb & HDLC_ERR_CER) + ch->bch.err_crc++; +#endif + skb_trim(ch->bch.rx_skb, 0); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + break; + } + if (ch->is->cmsb & HDLC_FSD) + skb_trim(ch->bch.rx_skb, 0); + ptr = skb_put(ch->bch.rx_skb, ch->is->clsb); + rcv_mbox(ch->is, ptr); + if (ch->is->cmsb & HDLC_FED) { + if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */ + pr_debug("%s: ISAR frame to short %d\n", + ch->is->name, ch->bch.rx_skb->len); + skb_trim(ch->bch.rx_skb, 0); + break; + } + skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2); + recv_Bchannel(&ch->bch, 0); + } + break; + case ISDN_P_B_T30_FAX: + if (ch->state != STFAX_ACTIV) { + pr_debug("%s: isar_rcv_frame: not ACTIV\n", + ch->is->name); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + if (ch->bch.rx_skb) + skb_trim(ch->bch.rx_skb, 0); + break; + } + if (!ch->bch.rx_skb) { + ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, + GFP_ATOMIC); + if (unlikely(!ch->bch.rx_skb)) { + pr_info("%s: B receive out of memory\n", + __func__); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + break; + } + } + if (ch->cmd == PCTRL_CMD_FRM) { + rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); + pr_debug("%s: isar_rcv_frame: %d\n", + ch->is->name, ch->bch.rx_skb->len); + if (ch->is->cmsb & SART_NMD) { /* ABORT */ + pr_debug("%s: isar_rcv_frame: no more data\n", + ch->is->name); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + send_mbox(ch->is, SET_DPS(ch->dpath) | + ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, + 0, NULL); + ch->state = STFAX_ESCAPE; + /* set_skb_flag(skb, DF_NOMOREDATA); */ + } + recv_Bchannel(&ch->bch, 0); + if (ch->is->cmsb & SART_NMD) + deliver_status(ch, HW_MOD_NOCARR); + break; + } + if (ch->cmd != PCTRL_CMD_FRH) { + pr_debug("%s: isar_rcv_frame: unknown fax mode %x\n", + ch->is->name, ch->cmd); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + if (ch->bch.rx_skb) + skb_trim(ch->bch.rx_skb, 0); + break; + } + /* PCTRL_CMD_FRH */ + if ((ch->bch.rx_skb->len + ch->is->clsb) > + (ch->bch.maxlen + 2)) { + pr_info("%s: %s incoming packet too large\n", + ch->is->name, __func__); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + skb_trim(ch->bch.rx_skb, 0); + break; + } else if (ch->is->cmsb & HDLC_ERROR) { + pr_info("%s: ISAR frame error %x len %d\n", + ch->is->name, ch->is->cmsb, ch->is->clsb); + skb_trim(ch->bch.rx_skb, 0); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + break; + } + if (ch->is->cmsb & HDLC_FSD) + skb_trim(ch->bch.rx_skb, 0); + ptr = skb_put(ch->bch.rx_skb, ch->is->clsb); + rcv_mbox(ch->is, ptr); + if (ch->is->cmsb & HDLC_FED) { + if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */ + pr_info("%s: ISAR frame to short %d\n", + ch->is->name, ch->bch.rx_skb->len); + skb_trim(ch->bch.rx_skb, 0); + break; + } + skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2); + recv_Bchannel(&ch->bch, 0); + } + if (ch->is->cmsb & SART_NMD) { /* ABORT */ + pr_debug("%s: isar_rcv_frame: no more data\n", + ch->is->name); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + if (ch->bch.rx_skb) + skb_trim(ch->bch.rx_skb, 0); + send_mbox(ch->is, SET_DPS(ch->dpath) | + ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); + ch->state = STFAX_ESCAPE; + deliver_status(ch, HW_MOD_NOCARR); + } + break; + default: + pr_info("isar_rcv_frame protocol (%x)error\n", ch->bch.state); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + break; + } +} + +static void +isar_fill_fifo(struct isar_ch *ch) +{ + int count; + u8 msb; + u8 *ptr; + + pr_debug("%s: ch%d tx_skb %p tx_idx %d\n", + ch->is->name, ch->bch.nr, ch->bch.tx_skb, ch->bch.tx_idx); + if (!ch->bch.tx_skb) + return; + count = ch->bch.tx_skb->len - ch->bch.tx_idx; + if (count <= 0) + return; + if (!(ch->is->bstat & + (ch->dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2))) + return; + if (count > ch->mml) { + msb = 0; + count = ch->mml; + } else { + msb = HDLC_FED; + } + ptr = ch->bch.tx_skb->data + ch->bch.tx_idx; + if (!ch->bch.tx_idx) { + pr_debug("%s: frame start\n", ch->is->name); + if ((ch->bch.state == ISDN_P_B_T30_FAX) && + (ch->cmd == PCTRL_CMD_FTH)) { + if (count > 1) { + if ((ptr[0] == 0xff) && (ptr[1] == 0x13)) { + /* last frame */ + test_and_set_bit(FLG_LASTDATA, + &ch->bch.Flags); + pr_debug("%s: set LASTDATA\n", + ch->is->name); + if (msb == HDLC_FED) + test_and_set_bit(FLG_DLEETX, + &ch->bch.Flags); + } + } + } + msb |= HDLC_FST; + } + ch->bch.tx_idx += count; + switch (ch->bch.state) { + case ISDN_P_NONE: + pr_info("%s: wrong protocol 0\n", __func__); + break; + case ISDN_P_B_RAW: + case ISDN_P_B_L2DTMF: + case ISDN_P_B_MODEM_ASYNC: + send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, + 0, count, ptr); + break; + case ISDN_P_B_HDLC: + send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, + msb, count, ptr); + break; + case ISDN_P_B_T30_FAX: + if (ch->state != STFAX_ACTIV) + pr_debug("%s: not ACTIV\n", ch->is->name); + else if (ch->cmd == PCTRL_CMD_FTH) + send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, + msb, count, ptr); + else if (ch->cmd == PCTRL_CMD_FTM) + send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, + 0, count, ptr); + else + pr_debug("%s: not FTH/FTM\n", ch->is->name); + break; + default: + pr_info("%s: protocol(%x) error\n", + __func__, ch->bch.state); + break; + } +} + +static inline struct isar_ch * +sel_bch_isar(struct isar_hw *isar, u8 dpath) +{ + struct isar_ch *base = &isar->ch[0]; + + if ((!dpath) || (dpath > 2)) + return NULL; + if (base->dpath == dpath) + return base; + base++; + if (base->dpath == dpath) + return base; + return NULL; +} + +static void +send_next(struct isar_ch *ch) +{ + pr_debug("%s: %s ch%d tx_skb %p tx_idx %d\n", + ch->is->name, __func__, ch->bch.nr, + ch->bch.tx_skb, ch->bch.tx_idx); + if (ch->bch.state == ISDN_P_B_T30_FAX) { + if (ch->cmd == PCTRL_CMD_FTH) { + if (test_bit(FLG_LASTDATA, &ch->bch.Flags)) { + pr_debug("set NMD_DATA\n"); + test_and_set_bit(FLG_NMD_DATA, &ch->bch.Flags); + } + } else if (ch->cmd == PCTRL_CMD_FTM) { + if (test_bit(FLG_DLEETX, &ch->bch.Flags)) { + test_and_set_bit(FLG_LASTDATA, &ch->bch.Flags); + test_and_set_bit(FLG_NMD_DATA, &ch->bch.Flags); + } + } + } + if (ch->bch.tx_skb) { + /* send confirm, on trans, free on hdlc. */ + if (test_bit(FLG_TRANSPARENT, &ch->bch.Flags)) + confirm_Bsend(&ch->bch); + dev_kfree_skb(ch->bch.tx_skb); + } + if (get_next_bframe(&ch->bch)) + isar_fill_fifo(ch); + else { + if (test_and_clear_bit(FLG_DLEETX, &ch->bch.Flags)) { + if (test_and_clear_bit(FLG_LASTDATA, + &ch->bch.Flags)) { + if (test_and_clear_bit(FLG_NMD_DATA, + &ch->bch.Flags)) { + u8 zd = 0; + send_mbox(ch->is, SET_DPS(ch->dpath) | + ISAR_HIS_SDATA, 0x01, 1, &zd); + } + test_and_set_bit(FLG_LL_OK, &ch->bch.Flags); + } else { + deliver_status(ch, HW_MOD_CONNECT); + } + } + } +} + +static void +check_send(struct isar_hw *isar, u8 rdm) +{ + struct isar_ch *ch; + + pr_debug("%s: rdm %x\n", isar->name, rdm); + if (rdm & BSTAT_RDM1) { + ch = sel_bch_isar(isar, 1); + if (ch && test_bit(FLG_ACTIVE, &ch->bch.Flags)) { + if (ch->bch.tx_skb && (ch->bch.tx_skb->len > + ch->bch.tx_idx)) + isar_fill_fifo(ch); + else + send_next(ch); + } + } + if (rdm & BSTAT_RDM2) { + ch = sel_bch_isar(isar, 2); + if (ch && test_bit(FLG_ACTIVE, &ch->bch.Flags)) { + if (ch->bch.tx_skb && (ch->bch.tx_skb->len > + ch->bch.tx_idx)) + isar_fill_fifo(ch); + else + send_next(ch); + } + } +} + +const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4", + "300", "600", "1200", "2400", "4800", "7200", + "9600nt", "9600t", "12000", "14400", "WRONG"}; +const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21", + "Bell103", "V23", "Bell202", "V17", "V29", "V27ter"}; + +static void +isar_pump_status_rsp(struct isar_ch *ch) { + u8 ril = ch->is->buf[0]; + u8 rim; + + if (!test_and_clear_bit(ISAR_RATE_REQ, &ch->is->Flags)) + return; + if (ril > 14) { + pr_info("%s: wrong pstrsp ril=%d\n", ch->is->name, ril); + ril = 15; + } + switch (ch->is->buf[1]) { + case 0: + rim = 0; + break; + case 0x20: + rim = 2; + break; + case 0x40: + rim = 3; + break; + case 0x41: + rim = 4; + break; + case 0x51: + rim = 5; + break; + case 0x61: + rim = 6; + break; + case 0x71: + rim = 7; + break; + case 0x82: + rim = 8; + break; + case 0x92: + rim = 9; + break; + case 0xa2: + rim = 10; + break; + default: + rim = 1; + break; + } + sprintf(ch->conmsg, "%s %s", dmril[ril], dmrim[rim]); + pr_debug("%s: pump strsp %s\n", ch->is->name, ch->conmsg); +} + +static void +isar_pump_statev_modem(struct isar_ch *ch, u8 devt) { + u8 dps = SET_DPS(ch->dpath); + + switch (devt) { + case PSEV_10MS_TIMER: + pr_debug("%s: pump stev TIMER\n", ch->is->name); + break; + case PSEV_CON_ON: + pr_debug("%s: pump stev CONNECT\n", ch->is->name); + deliver_status(ch, HW_MOD_CONNECT); + break; + case PSEV_CON_OFF: + pr_debug("%s: pump stev NO CONNECT\n", ch->is->name); + send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); + deliver_status(ch, HW_MOD_NOCARR); + break; + case PSEV_V24_OFF: + pr_debug("%s: pump stev V24 OFF\n", ch->is->name); + break; + case PSEV_CTS_ON: + pr_debug("%s: pump stev CTS ON\n", ch->is->name); + break; + case PSEV_CTS_OFF: + pr_debug("%s pump stev CTS OFF\n", ch->is->name); + break; + case PSEV_DCD_ON: + pr_debug("%s: pump stev CARRIER ON\n", ch->is->name); + test_and_set_bit(ISAR_RATE_REQ, &ch->is->Flags); + send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); + break; + case PSEV_DCD_OFF: + pr_debug("%s: pump stev CARRIER OFF\n", ch->is->name); + break; + case PSEV_DSR_ON: + pr_debug("%s: pump stev DSR ON\n", ch->is->name); + break; + case PSEV_DSR_OFF: + pr_debug("%s: pump stev DSR_OFF\n", ch->is->name); + break; + case PSEV_REM_RET: + pr_debug("%s: pump stev REMOTE RETRAIN\n", ch->is->name); + break; + case PSEV_REM_REN: + pr_debug("%s: pump stev REMOTE RENEGOTIATE\n", ch->is->name); + break; + case PSEV_GSTN_CLR: + pr_debug("%s: pump stev GSTN CLEAR\n", ch->is->name); + break; + default: + pr_info("u%s: nknown pump stev %x\n", ch->is->name, devt); + break; + } +} + +static void +isar_pump_statev_fax(struct isar_ch *ch, u8 devt) { + u8 dps = SET_DPS(ch->dpath); + u8 p1; + + switch (devt) { + case PSEV_10MS_TIMER: + pr_debug("%s: pump stev TIMER\n", ch->is->name); + break; + case PSEV_RSP_READY: + pr_debug("%s: pump stev RSP_READY\n", ch->is->name); + ch->state = STFAX_READY; + deliver_status(ch, HW_MOD_READY); +#ifdef AUTOCON + if (test_bit(BC_FLG_ORIG, &ch->bch.Flags)) + isar_pump_cmd(bch, HW_MOD_FRH, 3); + else + isar_pump_cmd(bch, HW_MOD_FTH, 3); +#endif + break; + case PSEV_LINE_TX_H: + if (ch->state == STFAX_LINE) { + pr_debug("%s: pump stev LINE_TX_H\n", ch->is->name); + ch->state = STFAX_CONT; + send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, + PCTRL_CMD_CONT, 0, NULL); + } else { + pr_debug("%s: pump stev LINE_TX_H wrong st %x\n", + ch->is->name, ch->state); + } + break; + case PSEV_LINE_RX_H: + if (ch->state == STFAX_LINE) { + pr_debug("%s: pump stev LINE_RX_H\n", ch->is->name); + ch->state = STFAX_CONT; + send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, + PCTRL_CMD_CONT, 0, NULL); + } else { + pr_debug("%s: pump stev LINE_RX_H wrong st %x\n", + ch->is->name, ch->state); + } + break; + case PSEV_LINE_TX_B: + if (ch->state == STFAX_LINE) { + pr_debug("%s: pump stev LINE_TX_B\n", ch->is->name); + ch->state = STFAX_CONT; + send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, + PCTRL_CMD_CONT, 0, NULL); + } else { + pr_debug("%s: pump stev LINE_TX_B wrong st %x\n", + ch->is->name, ch->state); + } + break; + case PSEV_LINE_RX_B: + if (ch->state == STFAX_LINE) { + pr_debug("%s: pump stev LINE_RX_B\n", ch->is->name); + ch->state = STFAX_CONT; + send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, + PCTRL_CMD_CONT, 0, NULL); + } else { + pr_debug("%s: pump stev LINE_RX_B wrong st %x\n", + ch->is->name, ch->state); + } + break; + case PSEV_RSP_CONN: + if (ch->state == STFAX_CONT) { + pr_debug("%s: pump stev RSP_CONN\n", ch->is->name); + ch->state = STFAX_ACTIV; + test_and_set_bit(ISAR_RATE_REQ, &ch->is->Flags); + send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); + if (ch->cmd == PCTRL_CMD_FTH) { + int delay = (ch->mod == 3) ? 1000 : 200; + /* 1s (200 ms) Flags before data */ + if (test_and_set_bit(FLG_FTI_RUN, + &ch->bch.Flags)) + del_timer(&ch->ftimer); + ch->ftimer.expires = + jiffies + ((delay * HZ)/1000); + test_and_set_bit(FLG_LL_CONN, + &ch->bch.Flags); + add_timer(&ch->ftimer); + } else { + deliver_status(ch, HW_MOD_CONNECT); + } + } else { + pr_debug("%s: pump stev RSP_CONN wrong st %x\n", + ch->is->name, ch->state); + } + break; + case PSEV_FLAGS_DET: + pr_debug("%s: pump stev FLAGS_DET\n", ch->is->name); + break; + case PSEV_RSP_DISC: + pr_debug("%s: pump stev RSP_DISC state(%d)\n", + ch->is->name, ch->state); + if (ch->state == STFAX_ESCAPE) { + p1 = 5; + switch (ch->newcmd) { + case 0: + ch->state = STFAX_READY; + break; + case PCTRL_CMD_FTM: + p1 = 2; + case PCTRL_CMD_FTH: + send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, + PCTRL_CMD_SILON, 1, &p1); + ch->state = STFAX_SILDET; + break; + case PCTRL_CMD_FRH: + case PCTRL_CMD_FRM: + ch->mod = ch->newmod; + p1 = ch->newmod; + ch->newmod = 0; + ch->cmd = ch->newcmd; + ch->newcmd = 0; + send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, + ch->cmd, 1, &p1); + ch->state = STFAX_LINE; + ch->try_mod = 3; + break; + default: + pr_debug("%s: RSP_DISC unknown newcmd %x\n", + ch->is->name, ch->newcmd); + break; + } + } else if (ch->state == STFAX_ACTIV) { + if (test_and_clear_bit(FLG_LL_OK, &ch->bch.Flags)) + deliver_status(ch, HW_MOD_OK); + else if (ch->cmd == PCTRL_CMD_FRM) + deliver_status(ch, HW_MOD_NOCARR); + else + deliver_status(ch, HW_MOD_FCERROR); + ch->state = STFAX_READY; + } else if (ch->state != STFAX_SILDET) { + /* ignore in STFAX_SILDET */ + ch->state = STFAX_READY; + deliver_status(ch, HW_MOD_FCERROR); + } + break; + case PSEV_RSP_SILDET: + pr_debug("%s: pump stev RSP_SILDET\n", ch->is->name); + if (ch->state == STFAX_SILDET) { + ch->mod = ch->newmod; + p1 = ch->newmod; + ch->newmod = 0; + ch->cmd = ch->newcmd; + ch->newcmd = 0; + send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, + ch->cmd, 1, &p1); + ch->state = STFAX_LINE; + ch->try_mod = 3; + } + break; + case PSEV_RSP_SILOFF: + pr_debug("%s: pump stev RSP_SILOFF\n", ch->is->name); + break; + case PSEV_RSP_FCERR: + if (ch->state == STFAX_LINE) { + pr_debug("%s: pump stev RSP_FCERR try %d\n", + ch->is->name, ch->try_mod); + if (ch->try_mod--) { + send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, + ch->cmd, 1, &ch->mod); + break; + } + } + pr_debug("%s: pump stev RSP_FCERR\n", ch->is->name); + ch->state = STFAX_ESCAPE; + send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, + 0, NULL); + deliver_status(ch, HW_MOD_FCERROR); + break; + default: + break; + } +} + +void +mISDNisar_irq(struct isar_hw *isar) +{ + struct isar_ch *ch; + + get_irq_infos(isar); + switch (isar->iis & ISAR_IIS_MSCMSD) { + case ISAR_IIS_RDATA: + ch = sel_bch_isar(isar, isar->iis >> 6); + if (ch) + isar_rcv_frame(ch); + else { + pr_debug("%s: ISAR spurious IIS_RDATA %x/%x/%x\n", + isar->name, isar->iis, isar->cmsb, + isar->clsb); + isar->write_reg(isar->hw, ISAR_IIA, 0); + } + break; + case ISAR_IIS_GSTEV: + isar->write_reg(isar->hw, ISAR_IIA, 0); + isar->bstat |= isar->cmsb; + check_send(isar, isar->cmsb); + break; + case ISAR_IIS_BSTEV: +#ifdef ERROR_STATISTIC + ch = sel_bch_isar(isar, isar->iis >> 6); + if (ch) { + if (isar->cmsb == BSTEV_TBO) + ch->bch.err_tx++; + if (isar->cmsb == BSTEV_RBO) + ch->bch.err_rdo++; + } +#endif + pr_debug("%s: Buffer STEV dpath%d msb(%x)\n", + isar->name, isar->iis>>6, isar->cmsb); + isar->write_reg(isar->hw, ISAR_IIA, 0); + break; + case ISAR_IIS_PSTEV: + ch = sel_bch_isar(isar, isar->iis >> 6); + if (ch) { + rcv_mbox(isar, NULL); + if (ch->bch.state == ISDN_P_B_MODEM_ASYNC) + isar_pump_statev_modem(ch, isar->cmsb); + else if (ch->bch.state == ISDN_P_B_T30_FAX) + isar_pump_statev_fax(ch, isar->cmsb); + else if (ch->bch.state == ISDN_P_B_RAW) { + int tt; + tt = isar->cmsb | 0x30; + if (tt == 0x3e) + tt = '*'; + else if (tt == 0x3f) + tt = '#'; + else if (tt > '9') + tt += 7; + tt |= DTMF_TONE_VAL; + _queue_data(&ch->bch.ch, PH_CONTROL_IND, + MISDN_ID_ANY, sizeof(tt), &tt, + GFP_ATOMIC); + } else + pr_debug("%s: ISAR IIS_PSTEV pm %d sta %x\n", + isar->name, ch->bch.state, + isar->cmsb); + } else { + pr_debug("%s: ISAR spurious IIS_PSTEV %x/%x/%x\n", + isar->name, isar->iis, isar->cmsb, + isar->clsb); + isar->write_reg(isar->hw, ISAR_IIA, 0); + } + break; + case ISAR_IIS_PSTRSP: + ch = sel_bch_isar(isar, isar->iis >> 6); + if (ch) { + rcv_mbox(isar, NULL); + isar_pump_status_rsp(ch); + } else { + pr_debug("%s: ISAR spurious IIS_PSTRSP %x/%x/%x\n", + isar->name, isar->iis, isar->cmsb, + isar->clsb); + isar->write_reg(isar->hw, ISAR_IIA, 0); + } + break; + case ISAR_IIS_DIAG: + case ISAR_IIS_BSTRSP: + case ISAR_IIS_IOM2RSP: + rcv_mbox(isar, NULL); + break; + case ISAR_IIS_INVMSG: + rcv_mbox(isar, NULL); + pr_debug("%s: invalid msg his:%x\n", isar->name, isar->cmsb); + break; + default: + rcv_mbox(isar, NULL); + pr_debug("%s: unhandled msg iis(%x) ctrl(%x/%x)\n", + isar->name, isar->iis, isar->cmsb, isar->clsb); + break; + } +} +EXPORT_SYMBOL(mISDNisar_irq); + +static void +ftimer_handler(unsigned long data) +{ + struct isar_ch *ch = (struct isar_ch *)data; + + pr_debug("%s: ftimer flags %lx\n", ch->is->name, ch->bch.Flags); + test_and_clear_bit(FLG_FTI_RUN, &ch->bch.Flags); + if (test_and_clear_bit(FLG_LL_CONN, &ch->bch.Flags)) + deliver_status(ch, HW_MOD_CONNECT); +} + +static void +setup_pump(struct isar_ch *ch) { + u8 dps = SET_DPS(ch->dpath); + u8 ctrl, param[6]; + + switch (ch->bch.state) { + case ISDN_P_NONE: + case ISDN_P_B_RAW: + case ISDN_P_B_HDLC: + send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL); + break; + case ISDN_P_B_L2DTMF: + if (test_bit(FLG_DTMFSEND, &ch->bch.Flags)) { + param[0] = 5; /* TOA 5 db */ + send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, + PMOD_DTMF_TRANS, 1, param); + } else { + param[0] = 40; /* REL -46 dbm */ + send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, + PMOD_DTMF, 1, param); + } + case ISDN_P_B_MODEM_ASYNC: + ctrl = PMOD_DATAMODEM; + if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) { + ctrl |= PCTRL_ORIG; + param[5] = PV32P6_CTN; + } else { + param[5] = PV32P6_ATN; + } + param[0] = 6; /* 6 db */ + param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B | + PV32P2_V22C | PV32P2_V21 | PV32P2_BEL; + param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B; + param[3] = PV32P4_UT144; + param[4] = PV32P5_UT144; + send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param); + break; + case ISDN_P_B_T30_FAX: + ctrl = PMOD_FAX; + if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) { + ctrl |= PCTRL_ORIG; + param[1] = PFAXP2_CTN; + } else { + param[1] = PFAXP2_ATN; + } + param[0] = 6; /* 6 db */ + send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param); + ch->state = STFAX_NULL; + ch->newcmd = 0; + ch->newmod = 0; + test_and_set_bit(FLG_FTI_RUN, &ch->bch.Flags); + break; + } + udelay(1000); + send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); + udelay(1000); +} + +static void +setup_sart(struct isar_ch *ch) { + u8 dps = SET_DPS(ch->dpath); + u8 ctrl, param[2] = {0, 0}; + + switch (ch->bch.state) { + case ISDN_P_NONE: + send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, + 0, NULL); + break; + case ISDN_P_B_RAW: + case ISDN_P_B_L2DTMF: + send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, + 2, param); + break; + case ISDN_P_B_HDLC: + case ISDN_P_B_T30_FAX: + send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, + 1, param); + break; + case ISDN_P_B_MODEM_ASYNC: + ctrl = SMODE_V14 | SCTRL_HDMC_BOTH; + param[0] = S_P1_CHS_8; + param[1] = S_P2_BFT_DEF; + send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, ctrl, 2, param); + break; + } + udelay(1000); + send_mbox(ch->is, dps | ISAR_HIS_BSTREQ, 0, 0, NULL); + udelay(1000); +} + +static void +setup_iom2(struct isar_ch *ch) { + u8 dps = SET_DPS(ch->dpath); + u8 cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD, 0, 0, 0, 0}; + + if (ch->bch.nr == 2) { + msg[1] = 1; + msg[3] = 1; + } + switch (ch->bch.state) { + case ISDN_P_NONE: + cmsb = 0; + /* dummy slot */ + msg[1] = ch->dpath + 2; + msg[3] = ch->dpath + 2; + break; + case ISDN_P_B_RAW: + case ISDN_P_B_HDLC: + break; + case ISDN_P_B_MODEM_ASYNC: + case ISDN_P_B_T30_FAX: + cmsb |= IOM_CTRL_RCV; + case ISDN_P_B_L2DTMF: + if (test_bit(FLG_DTMFSEND, &ch->bch.Flags)) + cmsb |= IOM_CTRL_RCV; + cmsb |= IOM_CTRL_ALAW; + break; + } + send_mbox(ch->is, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg); + udelay(1000); + send_mbox(ch->is, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL); + udelay(1000); +} + +static int +modeisar(struct isar_ch *ch, u32 bprotocol) +{ + /* Here we are selecting the best datapath for requested protocol */ + if (ch->bch.state == ISDN_P_NONE) { /* New Setup */ + switch (bprotocol) { + case ISDN_P_NONE: /* init */ + if (!ch->dpath) + /* no init for dpath 0 */ + return 0; + test_and_clear_bit(FLG_HDLC, &ch->bch.Flags); + test_and_clear_bit(FLG_TRANSPARENT, &ch->bch.Flags); + break; + case ISDN_P_B_RAW: + case ISDN_P_B_HDLC: + /* best is datapath 2 */ + if (!test_and_set_bit(ISAR_DP2_USE, &ch->is->Flags)) + ch->dpath = 2; + else if (!test_and_set_bit(ISAR_DP1_USE, + &ch->is->Flags)) + ch->dpath = 1; + else { + pr_info("modeisar both pathes in use\n"); + return -EBUSY; + } + if (bprotocol == ISDN_P_B_HDLC) + test_and_set_bit(FLG_HDLC, &ch->bch.Flags); + else + test_and_set_bit(FLG_TRANSPARENT, + &ch->bch.Flags); + break; + case ISDN_P_B_MODEM_ASYNC: + case ISDN_P_B_T30_FAX: + case ISDN_P_B_L2DTMF: + /* only datapath 1 */ + if (!test_and_set_bit(ISAR_DP1_USE, &ch->is->Flags)) + ch->dpath = 1; + else { + pr_info("%s: ISAR modeisar analog functions" + "only with DP1\n", ch->is->name); + return -EBUSY; + } + break; + default: + pr_info("%s: protocol not known %x\n", ch->is->name, + bprotocol); + return -ENOPROTOOPT; + } + } + pr_debug("%s: ISAR ch%d dp%d protocol %x->%x\n", ch->is->name, + ch->bch.nr, ch->dpath, ch->bch.state, bprotocol); + ch->bch.state = bprotocol; + setup_pump(ch); + setup_iom2(ch); + setup_sart(ch); + if (ch->bch.state == ISDN_P_NONE) { + /* Clear resources */ + if (ch->dpath == 1) + test_and_clear_bit(ISAR_DP1_USE, &ch->is->Flags); + else if (ch->dpath == 2) + test_and_clear_bit(ISAR_DP2_USE, &ch->is->Flags); + ch->dpath = 0; + ch->is->ctrl(ch->is->hw, HW_DEACT_IND, ch->bch.nr); + } else + ch->is->ctrl(ch->is->hw, HW_ACTIVATE_IND, ch->bch.nr); + return 0; +} + +static void +isar_pump_cmd(struct isar_ch *ch, u32 cmd, u8 para) +{ + u8 dps = SET_DPS(ch->dpath); + u8 ctrl = 0, nom = 0, p1 = 0; + + pr_debug("%s: isar_pump_cmd %x/%x state(%x)\n", + ch->is->name, cmd, para, ch->bch.state); + switch (cmd) { + case HW_MOD_FTM: + if (ch->state == STFAX_READY) { + p1 = para; + ctrl = PCTRL_CMD_FTM; + nom = 1; + ch->state = STFAX_LINE; + ch->cmd = ctrl; + ch->mod = para; + ch->newmod = 0; + ch->newcmd = 0; + ch->try_mod = 3; + } else if ((ch->state == STFAX_ACTIV) && + (ch->cmd == PCTRL_CMD_FTM) && (ch->mod == para)) + deliver_status(ch, HW_MOD_CONNECT); + else { + ch->newmod = para; + ch->newcmd = PCTRL_CMD_FTM; + nom = 0; + ctrl = PCTRL_CMD_ESC; + ch->state = STFAX_ESCAPE; + } + break; + case HW_MOD_FTH: + if (ch->state == STFAX_READY) { + p1 = para; + ctrl = PCTRL_CMD_FTH; + nom = 1; + ch->state = STFAX_LINE; + ch->cmd = ctrl; + ch->mod = para; + ch->newmod = 0; + ch->newcmd = 0; + ch->try_mod = 3; + } else if ((ch->state == STFAX_ACTIV) && + (ch->cmd == PCTRL_CMD_FTH) && (ch->mod == para)) + deliver_status(ch, HW_MOD_CONNECT); + else { + ch->newmod = para; + ch->newcmd = PCTRL_CMD_FTH; + nom = 0; + ctrl = PCTRL_CMD_ESC; + ch->state = STFAX_ESCAPE; + } + break; + case HW_MOD_FRM: + if (ch->state == STFAX_READY) { + p1 = para; + ctrl = PCTRL_CMD_FRM; + nom = 1; + ch->state = STFAX_LINE; + ch->cmd = ctrl; + ch->mod = para; + ch->newmod = 0; + ch->newcmd = 0; + ch->try_mod = 3; + } else if ((ch->state == STFAX_ACTIV) && + (ch->cmd == PCTRL_CMD_FRM) && (ch->mod == para)) + deliver_status(ch, HW_MOD_CONNECT); + else { + ch->newmod = para; + ch->newcmd = PCTRL_CMD_FRM; + nom = 0; + ctrl = PCTRL_CMD_ESC; + ch->state = STFAX_ESCAPE; + } + break; + case HW_MOD_FRH: + if (ch->state == STFAX_READY) { + p1 = para; + ctrl = PCTRL_CMD_FRH; + nom = 1; + ch->state = STFAX_LINE; + ch->cmd = ctrl; + ch->mod = para; + ch->newmod = 0; + ch->newcmd = 0; + ch->try_mod = 3; + } else if ((ch->state == STFAX_ACTIV) && + (ch->cmd == PCTRL_CMD_FRH) && (ch->mod == para)) + deliver_status(ch, HW_MOD_CONNECT); + else { + ch->newmod = para; + ch->newcmd = PCTRL_CMD_FRH; + nom = 0; + ctrl = PCTRL_CMD_ESC; + ch->state = STFAX_ESCAPE; + } + break; + case PCTRL_CMD_TDTMF: + p1 = para; + nom = 1; + ctrl = PCTRL_CMD_TDTMF; + break; + } + if (ctrl) + send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1); +} + +static void +isar_setup(struct isar_hw *isar) +{ + u8 msg; + int i; + + /* Dpath 1, 2 */ + msg = 61; + for (i = 0; i < 2; i++) { + /* Buffer Config */ + send_mbox(isar, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) | + ISAR_HIS_P12CFG, 4, 1, &msg); + isar->ch[i].mml = msg; + isar->ch[i].bch.state = 0; + isar->ch[i].dpath = i + 1; + modeisar(&isar->ch[i], ISDN_P_NONE); + } +} + +static int +isar_l2l1(struct mISDNchannel *ch, struct sk_buff *skb) +{ + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct isar_ch *ich = container_of(bch, struct isar_ch, bch); + int ret = -EINVAL; + struct mISDNhead *hh = mISDN_HEAD_P(skb); + u32 id, *val; + u_long flags; + + switch (hh->prim) { + case PH_DATA_REQ: + spin_lock_irqsave(ich->is->hwlock, flags); + ret = bchannel_senddata(bch, skb); + if (ret > 0) { /* direct TX */ + id = hh->id; /* skb can be freed */ + ret = 0; + isar_fill_fifo(ich); + spin_unlock_irqrestore(ich->is->hwlock, flags); + if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) + queue_ch_frame(ch, PH_DATA_CNF, id, NULL); + } else + spin_unlock_irqrestore(ich->is->hwlock, flags); + return ret; + case PH_ACTIVATE_REQ: + spin_lock_irqsave(ich->is->hwlock, flags); + if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) + ret = modeisar(ich, ch->protocol); + else + ret = 0; + spin_unlock_irqrestore(ich->is->hwlock, flags); + if (!ret) + _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_KERNEL); + break; + case PH_DEACTIVATE_REQ: + spin_lock_irqsave(ich->is->hwlock, flags); + mISDN_clear_bchannel(bch); + modeisar(ich, ISDN_P_NONE); + spin_unlock_irqrestore(ich->is->hwlock, flags); + _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_KERNEL); + ret = 0; + break; + case PH_CONTROL_REQ: + val = (u32 *)skb->data; + pr_debug("%s: PH_CONTROL | REQUEST %x/%x\n", ich->is->name, + hh->id, *val); + if ((hh->id == 0) && ((*val & ~DTMF_TONE_MASK) == + DTMF_TONE_VAL)) { + if (bch->state == ISDN_P_B_L2DTMF) { + char tt = *val & DTMF_TONE_MASK; + + if (tt == '*') + tt = 0x1e; + else if (tt == '#') + tt = 0x1f; + else if (tt > '9') + tt -= 7; + tt &= 0x1f; + spin_lock_irqsave(ich->is->hwlock, flags); + isar_pump_cmd(ich, PCTRL_CMD_TDTMF, tt); + spin_unlock_irqrestore(ich->is->hwlock, flags); + } else { + pr_info("%s: DTMF send wrong protocol %x\n", + __func__, bch->state); + return -EINVAL; + } + } else if ((hh->id == HW_MOD_FRM) || (hh->id == HW_MOD_FRH) || + (hh->id == HW_MOD_FTM) || (hh->id == HW_MOD_FTH)) { + for (id = 0; id < FAXMODCNT; id++) + if (faxmodulation[id] == *val) + break; + if ((FAXMODCNT > id) && + test_bit(FLG_INITIALIZED, &bch->Flags)) { + pr_debug("%s: isar: new mod\n", ich->is->name); + isar_pump_cmd(ich, hh->id, *val); + ret = 0; + } else { + pr_info("%s: wrong modulation\n", + ich->is->name); + ret = -EINVAL; + } + } else if (hh->id == HW_MOD_LASTDATA) + test_and_set_bit(FLG_DLEETX, &bch->Flags); + else { + pr_info("%s: unknown PH_CONTROL_REQ %x\n", + ich->is->name, hh->id); + ret = -EINVAL; + } + default: + pr_info("%s: %s unknown prim(%x,%x)\n", + ich->is->name, __func__, hh->prim, hh->id); + ret = -EINVAL; + } + if (!ret) + dev_kfree_skb(skb); + return ret; +} + +static int +channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = 0; + break; + /* Nothing implemented yet */ + case MISDN_CTRL_FILL_EMPTY: + default: + pr_info("%s: unknown Op %x\n", __func__, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +isar_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) +{ + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct isar_ch *ich = container_of(bch, struct isar_ch, bch); + int ret = -EINVAL; + u_long flags; + + pr_debug("%s: %s cmd:%x %p\n", ich->is->name, __func__, cmd, arg); + switch (cmd) { + case CLOSE_CHANNEL: + test_and_clear_bit(FLG_OPEN, &bch->Flags); + if (test_bit(FLG_ACTIVE, &bch->Flags)) { + spin_lock_irqsave(ich->is->hwlock, flags); + mISDN_freebchannel(bch); + modeisar(ich, ISDN_P_NONE); + spin_unlock_irqrestore(ich->is->hwlock, flags); + } else { + skb_queue_purge(&bch->rqueue); + bch->rcount = 0; + } + ch->protocol = ISDN_P_NONE; + ch->peer = NULL; + module_put(ich->is->owner); + ret = 0; + break; + case CONTROL_CHANNEL: + ret = channel_bctrl(bch, arg); + break; + default: + pr_info("%s: %s unknown prim(%x)\n", + ich->is->name, __func__, cmd); + } + return ret; +} + +static void +free_isar(struct isar_hw *isar) +{ + modeisar(&isar->ch[0], ISDN_P_NONE); + modeisar(&isar->ch[1], ISDN_P_NONE); + del_timer(&isar->ch[0].ftimer); + del_timer(&isar->ch[1].ftimer); + test_and_clear_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags); + test_and_clear_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags); +} + +static int +init_isar(struct isar_hw *isar) +{ + int cnt = 3; + + while (cnt--) { + isar->version = ISARVersion(isar); + if (isar->ch[0].bch.debug & DEBUG_HW) + pr_notice("%s: Testing version %d (%d time)\n", + isar->name, isar->version, 3 - cnt); + if (isar->version == 1) + break; + isar->ctrl(isar->hw, HW_RESET_REQ, 0); + } + if (isar->version != 1) + return -EINVAL; + isar->ch[0].ftimer.function = &ftimer_handler; + isar->ch[0].ftimer.data = (long)&isar->ch[0]; + init_timer(&isar->ch[0].ftimer); + test_and_set_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags); + isar->ch[1].ftimer.function = &ftimer_handler; + isar->ch[1].ftimer.data = (long)&isar->ch[1]; + init_timer(&isar->ch[1].ftimer); + test_and_set_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags); + return 0; +} + +static int +isar_open(struct isar_hw *isar, struct channel_req *rq) +{ + struct bchannel *bch; + + if (rq->adr.channel > 2) + return -EINVAL; + if (rq->protocol == ISDN_P_NONE) + return -EINVAL; + bch = &isar->ch[rq->adr.channel - 1].bch; + if (test_and_set_bit(FLG_OPEN, &bch->Flags)) + return -EBUSY; /* b-channel can be only open once */ + test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); + bch->ch.protocol = rq->protocol; + rq->ch = &bch->ch; + return 0; +} + +u32 +mISDNisar_init(struct isar_hw *isar, void *hw) +{ + u32 ret, i; + + isar->hw = hw; + for (i = 0; i < 2; i++) { + isar->ch[i].bch.nr = i + 1; + mISDN_initbchannel(&isar->ch[i].bch, MAX_DATA_MEM); + isar->ch[i].bch.ch.nr = i + 1; + isar->ch[i].bch.ch.send = &isar_l2l1; + isar->ch[i].bch.ch.ctrl = isar_bctrl; + isar->ch[i].bch.hw = hw; + isar->ch[i].is = isar; + } + + isar->init = &init_isar; + isar->release = &free_isar; + isar->firmware = &load_firmware; + isar->open = &isar_open; + + ret = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | + (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)) | + (1 << (ISDN_P_B_L2DTMF & ISDN_P_B_MASK)) | + (1 << (ISDN_P_B_MODEM_ASYNC & ISDN_P_B_MASK)) | + (1 << (ISDN_P_B_T30_FAX & ISDN_P_B_MASK)); + + return ret; +} +EXPORT_SYMBOL(mISDNisar_init); + +static int isar_mod_init(void) +{ + pr_notice("mISDN: ISAR driver Rev. %s\n", ISAR_REV); + return 0; +} + +static void isar_mod_cleanup(void) +{ + pr_notice("mISDN: ISAR module unloaded\n"); +} +module_init(isar_mod_init); +module_exit(isar_mod_cleanup); diff --git a/drivers/isdn/hardware/mISDN/speedfax.c b/drivers/isdn/hardware/mISDN/speedfax.c new file mode 100644 index 00000000000..ff3a4e290da --- /dev/null +++ b/drivers/isdn/hardware/mISDN/speedfax.c @@ -0,0 +1,526 @@ +/* + * speedfax.c low level stuff for Sedlbauer Speedfax+ cards + * based on the ISAR DSP + * Thanks to Sedlbauer AG for informations and HW + * + * Author Karsten Keil + * + * Copyright 2009 by Karsten Keil + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include "ipac.h" +#include "isar.h" + +#define SPEEDFAX_REV "2.0" + +#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51 +#define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54 +#define PCI_SUB_ID_SEDLBAUER 0x01 + +#define SFAX_PCI_ADDR 0xc8 +#define SFAX_PCI_ISAC 0xd0 +#define SFAX_PCI_ISAR 0xe0 + +/* TIGER 100 Registers */ + +#define TIGER_RESET_ADDR 0x00 +#define TIGER_EXTERN_RESET_ON 0x01 +#define TIGER_EXTERN_RESET_OFF 0x00 +#define TIGER_AUX_CTRL 0x02 +#define TIGER_AUX_DATA 0x03 +#define TIGER_AUX_IRQMASK 0x05 +#define TIGER_AUX_STATUS 0x07 + +/* Tiger AUX BITs */ +#define SFAX_AUX_IOMASK 0xdd /* 1 and 5 are inputs */ +#define SFAX_ISAR_RESET_BIT_OFF 0x00 +#define SFAX_ISAR_RESET_BIT_ON 0x01 +#define SFAX_TIGER_IRQ_BIT 0x02 +#define SFAX_LED1_BIT 0x08 +#define SFAX_LED2_BIT 0x10 + +#define SFAX_PCI_RESET_ON (SFAX_ISAR_RESET_BIT_ON) +#define SFAX_PCI_RESET_OFF (SFAX_LED1_BIT | SFAX_LED2_BIT) + +static int sfax_cnt; +static u32 debug; +static u32 irqloops = 4; + +struct sfax_hw { + struct list_head list; + struct pci_dev *pdev; + char name[MISDN_MAX_IDLEN]; + u32 irq; + u32 irqcnt; + u32 cfg; + struct _ioport p_isac; + struct _ioport p_isar; + u8 aux_data; + spinlock_t lock; /* HW access lock */ + struct isac_hw isac; + struct isar_hw isar; +}; + +static LIST_HEAD(Cards); +static DEFINE_RWLOCK(card_lock); /* protect Cards */ + +static void +_set_debug(struct sfax_hw *card) +{ + card->isac.dch.debug = debug; + card->isar.ch[0].bch.debug = debug; + card->isar.ch[1].bch.debug = debug; +} + +static int +set_debug(const char *val, struct kernel_param *kp) +{ + int ret; + struct sfax_hw *card; + + ret = param_set_uint(val, kp); + if (!ret) { + read_lock(&card_lock); + list_for_each_entry(card, &Cards, list) + _set_debug(card); + read_unlock(&card_lock); + } + return ret; +} + +MODULE_AUTHOR("Karsten Keil"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(SPEEDFAX_REV); +module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Speedfax debug mask"); +module_param(irqloops, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(irqloops, "Speedfax maximal irqloops (default 4)"); + +IOFUNC_IND(ISAC, sfax_hw, p_isac) +IOFUNC_IND(ISAR, sfax_hw, p_isar) + +static irqreturn_t +speedfax_irq(int intno, void *dev_id) +{ + struct sfax_hw *sf = dev_id; + u8 val; + int cnt = irqloops; + + spin_lock(&sf->lock); + val = inb(sf->cfg + TIGER_AUX_STATUS); + if (val & SFAX_TIGER_IRQ_BIT) { /* for us or shared ? */ + spin_unlock(&sf->lock); + return IRQ_NONE; /* shared */ + } + sf->irqcnt++; + val = ReadISAR_IND(sf, ISAR_IRQBIT); +Start_ISAR: + if (val & ISAR_IRQSTA) + mISDNisar_irq(&sf->isar); + val = ReadISAC_IND(sf, ISAC_ISTA); + if (val) + mISDNisac_irq(&sf->isac, val); + val = ReadISAR_IND(sf, ISAR_IRQBIT); + if ((val & ISAR_IRQSTA) && cnt--) + goto Start_ISAR; + if (cnt < irqloops) + pr_debug("%s: %d irqloops cpu%d\n", sf->name, + irqloops - cnt, smp_processor_id()); + if (irqloops && !cnt) + pr_notice("%s: %d IRQ LOOP cpu%d\n", sf->name, + irqloops, smp_processor_id()); + spin_unlock(&sf->lock); + return IRQ_HANDLED; +} + +static void +enable_hwirq(struct sfax_hw *sf) +{ + WriteISAC_IND(sf, ISAC_MASK, 0); + WriteISAR_IND(sf, ISAR_IRQBIT, ISAR_IRQMSK); + outb(SFAX_TIGER_IRQ_BIT, sf->cfg + TIGER_AUX_IRQMASK); +} + +static void +disable_hwirq(struct sfax_hw *sf) +{ + WriteISAC_IND(sf, ISAC_MASK, 0xFF); + WriteISAR_IND(sf, ISAR_IRQBIT, 0); + outb(0, sf->cfg + TIGER_AUX_IRQMASK); +} + +static void +reset_speedfax(struct sfax_hw *sf) +{ + + pr_debug("%s: resetting card\n", sf->name); + outb(TIGER_EXTERN_RESET_ON, sf->cfg + TIGER_RESET_ADDR); + outb(SFAX_PCI_RESET_ON, sf->cfg + TIGER_AUX_DATA); + mdelay(1); + outb(TIGER_EXTERN_RESET_OFF, sf->cfg + TIGER_RESET_ADDR); + sf->aux_data = SFAX_PCI_RESET_OFF; + outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA); + mdelay(1); +} + +static int +sfax_ctrl(struct sfax_hw *sf, u32 cmd, u_long arg) +{ + int ret = 0; + + switch (cmd) { + case HW_RESET_REQ: + reset_speedfax(sf); + break; + case HW_ACTIVATE_IND: + if (arg & 1) + sf->aux_data &= ~SFAX_LED1_BIT; + if (arg & 2) + sf->aux_data &= ~SFAX_LED2_BIT; + outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA); + break; + case HW_DEACT_IND: + if (arg & 1) + sf->aux_data |= SFAX_LED1_BIT; + if (arg & 2) + sf->aux_data |= SFAX_LED2_BIT; + outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA); + break; + default: + pr_info("%s: %s unknown command %x %lx\n", + sf->name, __func__, cmd, arg); + ret = -EINVAL; + break; + } + return ret; +} + +static int +channel_ctrl(struct sfax_hw *sf, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = MISDN_CTRL_LOOP; + break; + case MISDN_CTRL_LOOP: + /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ + if (cq->channel < 0 || cq->channel > 3) { + ret = -EINVAL; + break; + } + ret = sf->isac.ctrl(&sf->isac, HW_TESTLOOP, cq->channel); + break; + default: + pr_info("%s: unknown Op %x\n", sf->name, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +sfax_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) +{ + struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); + struct dchannel *dch = container_of(dev, struct dchannel, dev); + struct sfax_hw *sf = dch->hw; + struct channel_req *rq; + int err = 0; + + pr_debug("%s: cmd:%x %p\n", sf->name, cmd, arg); + switch (cmd) { + case OPEN_CHANNEL: + rq = arg; + if (rq->protocol == ISDN_P_TE_S0) + err = sf->isac.open(&sf->isac, rq); + else + err = sf->isar.open(&sf->isar, rq); + if (err) + break; + if (!try_module_get(THIS_MODULE)) + pr_info("%s: cannot get module\n", sf->name); + break; + case CLOSE_CHANNEL: + pr_debug("%s: dev(%d) close from %p\n", sf->name, + dch->dev.id, __builtin_return_address(0)); + module_put(THIS_MODULE); + break; + case CONTROL_CHANNEL: + err = channel_ctrl(sf, arg); + break; + default: + pr_debug("%s: unknown command %x\n", sf->name, cmd); + return -EINVAL; + } + return err; +} + +static int __devinit +init_card(struct sfax_hw *sf) +{ + int ret, cnt = 3; + u_long flags; + + ret = request_irq(sf->irq, speedfax_irq, IRQF_SHARED, sf->name, sf); + if (ret) { + pr_info("%s: couldn't get interrupt %d\n", sf->name, sf->irq); + return ret; + } + while (cnt--) { + spin_lock_irqsave(&sf->lock, flags); + ret = sf->isac.init(&sf->isac); + if (ret) { + spin_unlock_irqrestore(&sf->lock, flags); + pr_info("%s: ISAC init failed with %d\n", + sf->name, ret); + break; + } + enable_hwirq(sf); + /* RESET Receiver and Transmitter */ + WriteISAC_IND(sf, ISAC_CMDR, 0x41); + spin_unlock_irqrestore(&sf->lock, flags); + msleep_interruptible(10); + if (debug & DEBUG_HW) + pr_notice("%s: IRQ %d count %d\n", sf->name, + sf->irq, sf->irqcnt); + if (!sf->irqcnt) { + pr_info("%s: IRQ(%d) got no requests during init %d\n", + sf->name, sf->irq, 3 - cnt); + } else + return 0; + } + free_irq(sf->irq, sf); + return -EIO; +} + + +static int __devinit +setup_speedfax(struct sfax_hw *sf) +{ + u_long flags; + + if (!request_region(sf->cfg, 256, sf->name)) { + pr_info("mISDN: %s config port %x-%x already in use\n", + sf->name, sf->cfg, sf->cfg + 255); + return -EIO; + } + outb(0xff, sf->cfg); + outb(0, sf->cfg); + outb(0xdd, sf->cfg + TIGER_AUX_CTRL); + outb(0, sf->cfg + TIGER_AUX_IRQMASK); + + sf->isac.type = IPAC_TYPE_ISAC; + sf->p_isac.ale = sf->cfg + SFAX_PCI_ADDR; + sf->p_isac.port = sf->cfg + SFAX_PCI_ISAC; + sf->p_isar.ale = sf->cfg + SFAX_PCI_ADDR; + sf->p_isar.port = sf->cfg + SFAX_PCI_ISAR; + ASSIGN_FUNC(IND, ISAC, sf->isac); + ASSIGN_FUNC(IND, ISAR, sf->isar); + spin_lock_irqsave(&sf->lock, flags); + reset_speedfax(sf); + disable_hwirq(sf); + spin_unlock_irqrestore(&sf->lock, flags); + return 0; +} + +static void +release_card(struct sfax_hw *card) { + u_long flags; + + spin_lock_irqsave(&card->lock, flags); + disable_hwirq(card); + spin_unlock_irqrestore(&card->lock, flags); + card->isac.release(&card->isac); + free_irq(card->irq, card); + card->isar.release(&card->isar); + mISDN_unregister_device(&card->isac.dch.dev); + release_region(card->cfg, 256); + pci_disable_device(card->pdev); + pci_set_drvdata(card->pdev, NULL); + write_lock_irqsave(&card_lock, flags); + list_del(&card->list); + write_unlock_irqrestore(&card_lock, flags); + kfree(card); + sfax_cnt--; +} + +static int __devinit +setup_instance(struct sfax_hw *card) +{ + const struct firmware *firmware; + int i, err; + u_long flags; + + snprintf(card->name, MISDN_MAX_IDLEN - 1, "Speedfax.%d", sfax_cnt + 1); + write_lock_irqsave(&card_lock, flags); + list_add_tail(&card->list, &Cards); + write_unlock_irqrestore(&card_lock, flags); + _set_debug(card); + spin_lock_init(&card->lock); + card->isac.hwlock = &card->lock; + card->isar.hwlock = &card->lock; + card->isar.ctrl = (void *)&sfax_ctrl; + card->isac.name = card->name; + card->isar.name = card->name; + card->isar.owner = THIS_MODULE; + + err = request_firmware(&firmware, "isdn/ISAR.BIN", &card->pdev->dev); + if (err < 0) { + pr_info("%s: firmware request failed %d\n", + card->name, err); + goto error_fw; + } + if (debug & DEBUG_HW) + pr_notice("%s: got firmware %zu bytes\n", + card->name, firmware->size); + + mISDNisac_init(&card->isac, card); + + card->isac.dch.dev.D.ctrl = sfax_dctrl; + card->isac.dch.dev.Bprotocols = + mISDNisar_init(&card->isar, card); + for (i = 0; i < 2; i++) { + set_channelmap(i + 1, card->isac.dch.dev.channelmap); + list_add(&card->isar.ch[i].bch.ch.list, + &card->isac.dch.dev.bchannels); + } + + err = setup_speedfax(card); + if (err) + goto error_setup; + err = card->isar.init(&card->isar); + if (err) + goto error; + err = mISDN_register_device(&card->isac.dch.dev, + &card->pdev->dev, card->name); + if (err) + goto error; + err = init_card(card); + if (err) + goto error_init; + err = card->isar.firmware(&card->isar, firmware->data, firmware->size); + if (!err) { + release_firmware(firmware); + sfax_cnt++; + pr_notice("SpeedFax %d cards installed\n", sfax_cnt); + return 0; + } + disable_hwirq(card); + free_irq(card->irq, card); +error_init: + mISDN_unregister_device(&card->isac.dch.dev); +error: + release_region(card->cfg, 256); +error_setup: + card->isac.release(&card->isac); + card->isar.release(&card->isar); + release_firmware(firmware); +error_fw: + pci_disable_device(card->pdev); + write_lock_irqsave(&card_lock, flags); + list_del(&card->list); + write_unlock_irqrestore(&card_lock, flags); + kfree(card); + return err; +} + +static int __devinit +sfaxpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int err = -ENOMEM; + struct sfax_hw *card = kzalloc(sizeof(struct sfax_hw), GFP_KERNEL); + + if (!card) { + pr_info("No memory for Speedfax+ PCI\n"); + return err; + } + card->pdev = pdev; + err = pci_enable_device(pdev); + if (err) { + kfree(card); + return err; + } + + pr_notice("mISDN: Speedfax found adapter %s at %s\n", + (char *)ent->driver_data, pci_name(pdev)); + + card->cfg = pci_resource_start(pdev, 0); + card->irq = pdev->irq; + pci_set_drvdata(pdev, card); + err = setup_instance(card); + if (err) + pci_set_drvdata(pdev, NULL); + return err; +} + +static void __devexit +sfax_remove_pci(struct pci_dev *pdev) +{ + struct sfax_hw *card = pci_get_drvdata(pdev); + + if (card) + release_card(card); + else + pr_debug("%s: drvdata allready removed\n", __func__); +} + +static struct pci_device_id sfaxpci_ids[] __devinitdata = { + { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, + PCI_SUBVENDOR_SPEEDFAX_PYRAMID, PCI_SUB_ID_SEDLBAUER, + 0, 0, (unsigned long) "Pyramid Speedfax + PCI" + }, + { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, + PCI_SUBVENDOR_SPEEDFAX_PCI, PCI_SUB_ID_SEDLBAUER, + 0, 0, (unsigned long) "Sedlbauer Speedfax + PCI" + }, + { } +}; +MODULE_DEVICE_TABLE(pci, sfaxpci_ids); + +static struct pci_driver sfaxpci_driver = { + .name = "speedfax+ pci", + .probe = sfaxpci_probe, + .remove = __devexit_p(sfax_remove_pci), + .id_table = sfaxpci_ids, +}; + +static int __init +Speedfax_init(void) +{ + int err; + + pr_notice("Sedlbauer Speedfax+ Driver Rev. %s\n", + SPEEDFAX_REV); + err = pci_register_driver(&sfaxpci_driver); + return err; +} + +static void __exit +Speedfax_cleanup(void) +{ + pci_unregister_driver(&sfaxpci_driver); +} + +module_init(Speedfax_init); +module_exit(Speedfax_cleanup); -- cgit v1.2.3-18-g5258 From 707b2ce6c1f4f1261788f2ff09ad82c35e0e6240 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 22 Jul 2009 20:06:05 +0200 Subject: mISDN: Add driver for Winbond cards Add driver for Winbond W6692 based PCI cards. Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/Kconfig | 7 + drivers/isdn/hardware/mISDN/Makefile | 1 + drivers/isdn/hardware/mISDN/w6692.c | 1440 ++++++++++++++++++++++++++++++++++ drivers/isdn/hardware/mISDN/w6692.h | 190 +++++ 4 files changed, 1638 insertions(+) create mode 100644 drivers/isdn/hardware/mISDN/w6692.c create mode 100644 drivers/isdn/hardware/mISDN/w6692.h (limited to 'drivers') diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig index 2600534be07..d72586e6838 100644 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ b/drivers/isdn/hardware/mISDN/Kconfig @@ -65,6 +65,13 @@ config MISDN_INFINEON Enable support for cards with ISAC + HSCX, IPAC or IPAC-SX chip from Infineon (former manufacturer Siemens). +config MISDN_W6692 + tristate "Support for cards with Winbond 6692" + depends on MISDN + depends on PCI + help + Enable support for Winbond 6692 PCI chip based cards. + config MISDN_IPAC tristate diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile index e18f964e185..61dd5a5f300 100644 --- a/drivers/isdn/hardware/mISDN/Makefile +++ b/drivers/isdn/hardware/mISDN/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o obj-$(CONFIG_MISDN_AVMFRITZ) += avmfritz.o obj-$(CONFIG_MISDN_SPEEDFAX) += speedfax.o obj-$(CONFIG_MISDN_INFINEON) += mISDNinfineon.o +obj-$(CONFIG_MISDN_W6692) += w6692.o # chip modules obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o obj-$(CONFIG_MISDN_ISAR) += mISDNisar.o diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c new file mode 100644 index 00000000000..1b9008f13d6 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/w6692.c @@ -0,0 +1,1440 @@ +/* + * w6692.c mISDN driver for Winbond w6692 based cards + * + * Author Karsten Keil + * based on the w6692 I4L driver from Petr Novak + * + * Copyright 2009 by Karsten Keil + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include "w6692.h" + +#define W6692_REV "2.0" + +#define DBUSY_TIMER_VALUE 80 + +enum { + W6692_ASUS, + W6692_WINBOND, + W6692_USR +}; + +/* private data in the PCI devices list */ +struct w6692map { + u_int subtype; + char *name; +}; + +static const struct w6692map w6692_map[] = +{ + {W6692_ASUS, "Dynalink/AsusCom IS64PH"}, + {W6692_WINBOND, "Winbond W6692"}, + {W6692_USR, "USR W6692"} +}; + +#ifndef PCI_VENDOR_ID_USR +#define PCI_VENDOR_ID_USR 0x16ec +#define PCI_DEVICE_ID_USR_6692 0x3409 +#endif + +struct w6692_ch { + struct bchannel bch; + u32 addr; + struct timer_list timer; + u8 b_mode; +}; + +struct w6692_hw { + struct list_head list; + struct pci_dev *pdev; + char name[MISDN_MAX_IDLEN]; + u32 irq; + u32 irqcnt; + u32 addr; + u32 fmask; /* feature mask - bit set per card nr */ + int subtype; + spinlock_t lock; /* hw lock */ + u8 imask; + u8 pctl; + u8 xaddr; + u8 xdata; + u8 state; + struct w6692_ch bc[2]; + struct dchannel dch; + char log[64]; +}; + +static LIST_HEAD(Cards); +static DEFINE_RWLOCK(card_lock); /* protect Cards */ + +static int w6692_cnt; +static int debug; +static u32 led; +static u32 pots; + +static void +_set_debug(struct w6692_hw *card) +{ + card->dch.debug = debug; + card->bc[0].bch.debug = debug; + card->bc[1].bch.debug = debug; +} + +static int +set_debug(const char *val, struct kernel_param *kp) +{ + int ret; + struct w6692_hw *card; + + ret = param_set_uint(val, kp); + if (!ret) { + read_lock(&card_lock); + list_for_each_entry(card, &Cards, list) + _set_debug(card); + read_unlock(&card_lock); + } + return ret; +} + +MODULE_AUTHOR("Karsten Keil"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(W6692_REV); +module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "W6692 debug mask"); +module_param(led, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(led, "W6692 LED support bitmask (one bit per card)"); +module_param(pots, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(pots, "W6692 POTS support bitmask (one bit per card)"); + +static inline u8 +ReadW6692(struct w6692_hw *card, u8 offset) +{ + return inb(card->addr + offset); +} + +static inline void +WriteW6692(struct w6692_hw *card, u8 offset, u8 value) +{ + outb(value, card->addr + offset); +} + +static inline u8 +ReadW6692B(struct w6692_ch *bc, u8 offset) +{ + return inb(bc->addr + offset); +} + +static inline void +WriteW6692B(struct w6692_ch *bc, u8 offset, u8 value) +{ + outb(value, bc->addr + offset); +} + +static void +enable_hwirq(struct w6692_hw *card) +{ + WriteW6692(card, W_IMASK, card->imask); +} + +static void +disable_hwirq(struct w6692_hw *card) +{ + WriteW6692(card, W_IMASK, 0xff); +} + +static const char *W6692Ver[] = {"V00", "V01", "V10", "V11"}; + +static void +W6692Version(struct w6692_hw *card) +{ + int val; + + val = ReadW6692(card, W_D_RBCH); + pr_notice("%s: Winbond W6692 version: %s\n", card->name, + W6692Ver[(val >> 6) & 3]); +} + +static void +w6692_led_handler(struct w6692_hw *card, int on) +{ + if ((!(card->fmask & led)) || card->subtype == W6692_USR) + return; + if (on) { + card->xdata &= 0xfb; /* LED ON */ + WriteW6692(card, W_XDATA, card->xdata); + } else { + card->xdata |= 0x04; /* LED OFF */ + WriteW6692(card, W_XDATA, card->xdata); + } +} + +static void +ph_command(struct w6692_hw *card, u8 cmd) +{ + pr_debug("%s: ph_command %x\n", card->name, cmd); + WriteW6692(card, W_CIX, cmd); +} + +static void +W6692_new_ph(struct w6692_hw *card) +{ + if (card->state == W_L1CMD_RST) + ph_command(card, W_L1CMD_DRC); + schedule_event(&card->dch, FLG_PHCHANGE); +} + +static void +W6692_ph_bh(struct dchannel *dch) +{ + struct w6692_hw *card = dch->hw; + + switch (card->state) { + case W_L1CMD_RST: + dch->state = 0; + l1_event(dch->l1, HW_RESET_IND); + break; + case W_L1IND_CD: + dch->state = 3; + l1_event(dch->l1, HW_DEACT_CNF); + break; + case W_L1IND_DRD: + dch->state = 3; + l1_event(dch->l1, HW_DEACT_IND); + break; + case W_L1IND_CE: + dch->state = 4; + l1_event(dch->l1, HW_POWERUP_IND); + break; + case W_L1IND_LD: + if (dch->state <= 5) { + dch->state = 5; + l1_event(dch->l1, ANYSIGNAL); + } else { + dch->state = 8; + l1_event(dch->l1, LOSTFRAMING); + } + break; + case W_L1IND_ARD: + dch->state = 6; + l1_event(dch->l1, INFO2); + break; + case W_L1IND_AI8: + dch->state = 7; + l1_event(dch->l1, INFO4_P8); + break; + case W_L1IND_AI10: + dch->state = 7; + l1_event(dch->l1, INFO4_P10); + break; + default: + pr_debug("%s: TE unknown state %02x dch state %02x\n", + card->name, card->state, dch->state); + break; + } + pr_debug("%s: TE newstate %02x\n", card->name, dch->state); +} + +static void +W6692_empty_Dfifo(struct w6692_hw *card, int count) +{ + struct dchannel *dch = &card->dch; + u8 *ptr; + + pr_debug("%s: empty_Dfifo %d\n", card->name, count); + if (!dch->rx_skb) { + dch->rx_skb = mI_alloc_skb(card->dch.maxlen, GFP_ATOMIC); + if (!dch->rx_skb) { + pr_info("%s: D receive out of memory\n", card->name); + WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK); + return; + } + } + if ((dch->rx_skb->len + count) >= dch->maxlen) { + pr_debug("%s: empty_Dfifo overrun %d\n", card->name, + dch->rx_skb->len + count); + WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK); + return; + } + ptr = skb_put(dch->rx_skb, count); + insb(card->addr + W_D_RFIFO, ptr, count); + WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK); + if (debug & DEBUG_HW_DFIFO) { + snprintf(card->log, 63, "D-recv %s %d ", + card->name, count); + print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); + } +} + +static void +W6692_fill_Dfifo(struct w6692_hw *card) +{ + struct dchannel *dch = &card->dch; + int count; + u8 *ptr; + u8 cmd = W_D_CMDR_XMS; + + pr_debug("%s: fill_Dfifo\n", card->name); + if (!dch->tx_skb) + return; + count = dch->tx_skb->len - dch->tx_idx; + if (count <= 0) + return; + if (count > W_D_FIFO_THRESH) + count = W_D_FIFO_THRESH; + else + cmd |= W_D_CMDR_XME; + ptr = dch->tx_skb->data + dch->tx_idx; + dch->tx_idx += count; + outsb(card->addr + W_D_XFIFO, ptr, count); + WriteW6692(card, W_D_CMDR, cmd); + if (test_and_set_bit(FLG_BUSY_TIMER, &dch->Flags)) { + pr_debug("%s: fill_Dfifo dbusytimer running\n", card->name); + del_timer(&dch->timer); + } + init_timer(&dch->timer); + dch->timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); + add_timer(&dch->timer); + if (debug & DEBUG_HW_DFIFO) { + snprintf(card->log, 63, "D-send %s %d ", + card->name, count); + print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); + } +} + +static void +d_retransmit(struct w6692_hw *card) +{ + struct dchannel *dch = &card->dch; + + if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) + del_timer(&dch->timer); +#ifdef FIXME + if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) + dchannel_sched_event(dch, D_CLEARBUSY); +#endif + if (test_bit(FLG_TX_BUSY, &dch->Flags)) { + /* Restart frame */ + dch->tx_idx = 0; + W6692_fill_Dfifo(card); + } else if (dch->tx_skb) { /* should not happen */ + pr_info("%s: %s without TX_BUSY\n", card->name, __func__); + test_and_set_bit(FLG_TX_BUSY, &dch->Flags); + dch->tx_idx = 0; + W6692_fill_Dfifo(card); + } else { + pr_info("%s: XDU no TX_BUSY\n", card->name); + if (get_next_dframe(dch)) + W6692_fill_Dfifo(card); + } +} + +static void +handle_rxD(struct w6692_hw *card) { + u8 stat; + int count; + + stat = ReadW6692(card, W_D_RSTA); + if (stat & (W_D_RSTA_RDOV | W_D_RSTA_CRCE | W_D_RSTA_RMB)) { + if (stat & W_D_RSTA_RDOV) { + pr_debug("%s: D-channel RDOV\n", card->name); +#ifdef ERROR_STATISTIC + card->dch.err_rx++; +#endif + } + if (stat & W_D_RSTA_CRCE) { + pr_debug("%s: D-channel CRC error\n", card->name); +#ifdef ERROR_STATISTIC + card->dch.err_crc++; +#endif + } + if (stat & W_D_RSTA_RMB) { + pr_debug("%s: D-channel ABORT\n", card->name); +#ifdef ERROR_STATISTIC + card->dch.err_rx++; +#endif + } + if (card->dch.rx_skb) + dev_kfree_skb(card->dch.rx_skb); + card->dch.rx_skb = NULL; + WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST); + } else { + count = ReadW6692(card, W_D_RBCL) & (W_D_FIFO_THRESH - 1); + if (count == 0) + count = W_D_FIFO_THRESH; + W6692_empty_Dfifo(card, count); + recv_Dchannel(&card->dch); + } +} + +static void +handle_txD(struct w6692_hw *card) { + if (test_and_clear_bit(FLG_BUSY_TIMER, &card->dch.Flags)) + del_timer(&card->dch.timer); + if (card->dch.tx_skb && card->dch.tx_idx < card->dch.tx_skb->len) { + W6692_fill_Dfifo(card); + } else { + if (card->dch.tx_skb) + dev_kfree_skb(card->dch.tx_skb); + if (get_next_dframe(&card->dch)) + W6692_fill_Dfifo(card); + } +} + +static void +handle_statusD(struct w6692_hw *card) +{ + struct dchannel *dch = &card->dch; + u8 exval, v1, cir; + + exval = ReadW6692(card, W_D_EXIR); + + pr_debug("%s: D_EXIR %02x\n", card->name, exval); + if (exval & (W_D_EXI_XDUN | W_D_EXI_XCOL)) { + /* Transmit underrun/collision */ + pr_debug("%s: D-channel underrun/collision\n", card->name); +#ifdef ERROR_STATISTIC + dch->err_tx++; +#endif + d_retransmit(card); + } + if (exval & W_D_EXI_RDOV) { /* RDOV */ + pr_debug("%s: D-channel RDOV\n", card->name); + WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST); + } + if (exval & W_D_EXI_TIN2) /* TIN2 - never */ + pr_debug("%s: spurious TIN2 interrupt\n", card->name); + if (exval & W_D_EXI_MOC) { /* MOC - not supported */ + v1 = ReadW6692(card, W_MOSR); + pr_debug("%s: spurious MOC interrupt MOSR %02x\n", + card->name, v1); + } + if (exval & W_D_EXI_ISC) { /* ISC - Level1 change */ + cir = ReadW6692(card, W_CIR); + pr_debug("%s: ISC CIR %02X\n", card->name, cir); + if (cir & W_CIR_ICC) { + v1 = cir & W_CIR_COD_MASK; + pr_debug("%s: ph_state_change %x -> %x\n", card->name, + dch->state, v1); + card->state = v1; + if (card->fmask & led) { + switch (v1) { + case W_L1IND_AI8: + case W_L1IND_AI10: + w6692_led_handler(card, 1); + break; + default: + w6692_led_handler(card, 0); + break; + } + } + W6692_new_ph(card); + } + if (cir & W_CIR_SCC) { + v1 = ReadW6692(card, W_SQR); + pr_debug("%s: SCC SQR %02X\n", card->name, v1); + } + } + if (exval & W_D_EXI_WEXP) + pr_debug("%s: spurious WEXP interrupt!\n", card->name); + if (exval & W_D_EXI_TEXP) + pr_debug("%s: spurious TEXP interrupt!\n", card->name); +} + +static void +W6692_empty_Bfifo(struct w6692_ch *wch, int count) +{ + struct w6692_hw *card = wch->bch.hw; + u8 *ptr; + + pr_debug("%s: empty_Bfifo %d\n", card->name, count); + if (unlikely(wch->bch.state == ISDN_P_NONE)) { + pr_debug("%s: empty_Bfifo ISDN_P_NONE\n", card->name); + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); + if (wch->bch.rx_skb) + skb_trim(wch->bch.rx_skb, 0); + return; + } + if (!wch->bch.rx_skb) { + wch->bch.rx_skb = mI_alloc_skb(wch->bch.maxlen, GFP_ATOMIC); + if (unlikely(!wch->bch.rx_skb)) { + pr_info("%s: B receive out of memory\n", card->name); + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | + W_B_CMDR_RACT); + return; + } + } + if (wch->bch.rx_skb->len + count > wch->bch.maxlen) { + pr_debug("%s: empty_Bfifo incoming packet too large\n", + card->name); + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); + skb_trim(wch->bch.rx_skb, 0); + return; + } + ptr = skb_put(wch->bch.rx_skb, count); + insb(wch->addr + W_B_RFIFO, ptr, count); + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); + if (debug & DEBUG_HW_DFIFO) { + snprintf(card->log, 63, "B%1d-recv %s %d ", + wch->bch.nr, card->name, count); + print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); + } +} + +static void +W6692_fill_Bfifo(struct w6692_ch *wch) +{ + struct w6692_hw *card = wch->bch.hw; + int count; + u8 *ptr, cmd = W_B_CMDR_RACT | W_B_CMDR_XMS; + + pr_debug("%s: fill Bfifo\n", card->name); + if (!wch->bch.tx_skb) + return; + count = wch->bch.tx_skb->len - wch->bch.tx_idx; + if (count <= 0) + return; + ptr = wch->bch.tx_skb->data + wch->bch.tx_idx; + if (count > W_B_FIFO_THRESH) + count = W_B_FIFO_THRESH; + else if (test_bit(FLG_HDLC, &wch->bch.Flags)) + cmd |= W_B_CMDR_XME; + + pr_debug("%s: fill Bfifo%d/%d\n", card->name, + count, wch->bch.tx_idx); + wch->bch.tx_idx += count; + outsb(wch->addr + W_B_XFIFO, ptr, count); + WriteW6692B(wch, W_B_CMDR, cmd); + if (debug & DEBUG_HW_DFIFO) { + snprintf(card->log, 63, "B%1d-send %s %d ", + wch->bch.nr, card->name, count); + print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); + } +} + +static int +setvolume(struct w6692_ch *wch, int mic, struct sk_buff *skb) +{ + struct w6692_hw *card = wch->bch.hw; + u16 *vol = (u16 *)skb->data; + u8 val; + + if ((!(card->fmask & pots)) || + !test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) + return -ENODEV; + if (skb->len < 2) + return -EINVAL; + if (*vol > 7) + return -EINVAL; + val = *vol & 7; + val = 7 - val; + if (mic) { + val <<= 3; + card->xaddr &= 0xc7; + } else { + card->xaddr &= 0xf8; + } + card->xaddr |= val; + WriteW6692(card, W_XADDR, card->xaddr); + return 0; +} + +static int +enable_pots(struct w6692_ch *wch) +{ + struct w6692_hw *card = wch->bch.hw; + + if ((!(card->fmask & pots)) || + !test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) + return -ENODEV; + wch->b_mode |= W_B_MODE_EPCM | W_B_MODE_BSW0; + WriteW6692B(wch, W_B_MODE, wch->b_mode); + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); + card->pctl |= ((wch->bch.nr & 2) ? W_PCTL_PCX : 0); + WriteW6692(card, W_PCTL, card->pctl); + return 0; +} + +static int +disable_pots(struct w6692_ch *wch) +{ + struct w6692_hw *card = wch->bch.hw; + + if (!(card->fmask & pots)) + return -ENODEV; + wch->b_mode &= ~(W_B_MODE_EPCM | W_B_MODE_BSW0); + WriteW6692B(wch, W_B_MODE, wch->b_mode); + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | + W_B_CMDR_XRST); + return 0; +} + +static int +w6692_mode(struct w6692_ch *wch, u32 pr) +{ + struct w6692_hw *card; + + card = wch->bch.hw; + pr_debug("%s: B%d protocol %x-->%x\n", card->name, + wch->bch.nr, wch->bch.state, pr); + switch (pr) { + case ISDN_P_NONE: + if ((card->fmask & pots) && (wch->b_mode & W_B_MODE_EPCM)) + disable_pots(wch); + wch->b_mode = 0; + mISDN_clear_bchannel(&wch->bch); + WriteW6692B(wch, W_B_MODE, wch->b_mode); + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); + test_and_clear_bit(FLG_HDLC, &wch->bch.Flags); + test_and_clear_bit(FLG_TRANSPARENT, &wch->bch.Flags); + break; + case ISDN_P_B_RAW: + wch->b_mode = W_B_MODE_MMS; + WriteW6692B(wch, W_B_MODE, wch->b_mode); + WriteW6692B(wch, W_B_EXIM, 0); + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | + W_B_CMDR_XRST); + test_and_set_bit(FLG_TRANSPARENT, &wch->bch.Flags); + break; + case ISDN_P_B_HDLC: + wch->b_mode = W_B_MODE_ITF; + WriteW6692B(wch, W_B_MODE, wch->b_mode); + WriteW6692B(wch, W_B_ADM1, 0xff); + WriteW6692B(wch, W_B_ADM2, 0xff); + WriteW6692B(wch, W_B_EXIM, 0); + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | + W_B_CMDR_XRST); + test_and_set_bit(FLG_HDLC, &wch->bch.Flags); + break; + default: + pr_info("%s: protocol %x not known\n", card->name, pr); + return -ENOPROTOOPT; + } + wch->bch.state = pr; + return 0; +} + +static void +send_next(struct w6692_ch *wch) +{ + if (wch->bch.tx_skb && wch->bch.tx_idx < wch->bch.tx_skb->len) + W6692_fill_Bfifo(wch); + else { + if (wch->bch.tx_skb) { + /* send confirm, on trans, free on hdlc. */ + if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) + confirm_Bsend(&wch->bch); + dev_kfree_skb(wch->bch.tx_skb); + } + if (get_next_bframe(&wch->bch)) + W6692_fill_Bfifo(wch); + } +} + +static void +W6692B_interrupt(struct w6692_hw *card, int ch) +{ + struct w6692_ch *wch = &card->bc[ch]; + int count; + u8 stat, star = 0; + + stat = ReadW6692B(wch, W_B_EXIR); + pr_debug("%s: B%d EXIR %02x\n", card->name, wch->bch.nr, stat); + if (stat & W_B_EXI_RME) { + star = ReadW6692B(wch, W_B_STAR); + if (star & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB)) { + if ((star & W_B_STAR_RDOV) && + test_bit(FLG_ACTIVE, &wch->bch.Flags)) { + pr_debug("%s: B%d RDOV proto=%x\n", card->name, + wch->bch.nr, wch->bch.state); +#ifdef ERROR_STATISTIC + wch->bch.err_rdo++; +#endif + } + if (test_bit(FLG_HDLC, &wch->bch.Flags)) { + if (star & W_B_STAR_CRCE) { + pr_debug("%s: B%d CRC error\n", + card->name, wch->bch.nr); +#ifdef ERROR_STATISTIC + wch->bch.err_crc++; +#endif + } + if (star & W_B_STAR_RMB) { + pr_debug("%s: B%d message abort\n", + card->name, wch->bch.nr); +#ifdef ERROR_STATISTIC + wch->bch.err_inv++; +#endif + } + } + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | + W_B_CMDR_RRST | W_B_CMDR_RACT); + if (wch->bch.rx_skb) + skb_trim(wch->bch.rx_skb, 0); + } else { + count = ReadW6692B(wch, W_B_RBCL) & + (W_B_FIFO_THRESH - 1); + if (count == 0) + count = W_B_FIFO_THRESH; + W6692_empty_Bfifo(wch, count); + recv_Bchannel(&wch->bch, 0); + } + } + if (stat & W_B_EXI_RMR) { + if (!(stat & W_B_EXI_RME)) + star = ReadW6692B(wch, W_B_STAR); + if (star & W_B_STAR_RDOV) { + pr_debug("%s: B%d RDOV proto=%x\n", card->name, + wch->bch.nr, wch->bch.state); +#ifdef ERROR_STATISTIC + wch->bch.err_rdo++; +#endif + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | + W_B_CMDR_RRST | W_B_CMDR_RACT); + } else { + W6692_empty_Bfifo(wch, W_B_FIFO_THRESH); + if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags) && + wch->bch.rx_skb && (wch->bch.rx_skb->len > 0)) + recv_Bchannel(&wch->bch, 0); + } + } + if (stat & W_B_EXI_RDOV) { + /* only if it is not handled yet */ + if (!(star & W_B_STAR_RDOV)) { + pr_debug("%s: B%d RDOV IRQ proto=%x\n", card->name, + wch->bch.nr, wch->bch.state); +#ifdef ERROR_STATISTIC + wch->bch.err_rdo++; +#endif + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | + W_B_CMDR_RRST | W_B_CMDR_RACT); + } + } + if (stat & W_B_EXI_XFR) { + if (!(stat & (W_B_EXI_RME | W_B_EXI_RMR))) { + star = ReadW6692B(wch, W_B_STAR); + pr_debug("%s: B%d star %02x\n", card->name, + wch->bch.nr, star); + } + if (star & W_B_STAR_XDOW) { + pr_debug("%s: B%d XDOW proto=%x\n", card->name, + wch->bch.nr, wch->bch.state); +#ifdef ERROR_STATISTIC + wch->bch.err_xdu++; +#endif + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_XRST | + W_B_CMDR_RACT); + /* resend */ + if (wch->bch.tx_skb) { + if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) + wch->bch.tx_idx = 0; + } + } + send_next(wch); + if (stat & W_B_EXI_XDUN) + return; /* handle XDOW only once */ + } + if (stat & W_B_EXI_XDUN) { + pr_debug("%s: B%d XDUN proto=%x\n", card->name, + wch->bch.nr, wch->bch.state); +#ifdef ERROR_STATISTIC + wch->bch.err_xdu++; +#endif + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); + /* resend */ + if (wch->bch.tx_skb) { + if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) + wch->bch.tx_idx = 0; + } + send_next(wch); + } +} + +static irqreturn_t +w6692_irq(int intno, void *dev_id) +{ + struct w6692_hw *card = dev_id; + u8 ista; + + spin_lock(&card->lock); + ista = ReadW6692(card, W_ISTA); + if ((ista | card->imask) == card->imask) { + /* possible a shared IRQ reqest */ + spin_unlock(&card->lock); + return IRQ_NONE; + } + card->irqcnt++; + pr_debug("%s: ista %02x\n", card->name, ista); + ista &= ~card->imask; + if (ista & W_INT_B1_EXI) + W6692B_interrupt(card, 0); + if (ista & W_INT_B2_EXI) + W6692B_interrupt(card, 1); + if (ista & W_INT_D_RME) + handle_rxD(card); + if (ista & W_INT_D_RMR) + W6692_empty_Dfifo(card, W_D_FIFO_THRESH); + if (ista & W_INT_D_XFR) + handle_txD(card); + if (ista & W_INT_D_EXI) + handle_statusD(card); + if (ista & (W_INT_XINT0 | W_INT_XINT1)) /* XINT0/1 - never */ + pr_debug("%s: W6692 spurious XINT!\n", card->name); +/* End IRQ Handler */ + spin_unlock(&card->lock); + return IRQ_HANDLED; +} + +static void +dbusy_timer_handler(struct dchannel *dch) +{ + struct w6692_hw *card = dch->hw; + int rbch, star; + u_long flags; + + if (test_bit(FLG_BUSY_TIMER, &dch->Flags)) { + spin_lock_irqsave(&card->lock, flags); + rbch = ReadW6692(card, W_D_RBCH); + star = ReadW6692(card, W_D_STAR); + pr_debug("%s: D-Channel Busy RBCH %02x STAR %02x\n", + card->name, rbch, star); + if (star & W_D_STAR_XBZ) /* D-Channel Busy */ + test_and_set_bit(FLG_L1_BUSY, &dch->Flags); + else { + /* discard frame; reset transceiver */ + test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags); + if (dch->tx_idx) + dch->tx_idx = 0; + else + pr_info("%s: W6692 D-Channel Busy no tx_idx\n", + card->name); + /* Transmitter reset */ + WriteW6692(card, W_D_CMDR, W_D_CMDR_XRST); + } + spin_unlock_irqrestore(&card->lock, flags); + } +} + +void initW6692(struct w6692_hw *card) +{ + u8 val; + + card->dch.timer.function = (void *)dbusy_timer_handler; + card->dch.timer.data = (u_long)&card->dch; + init_timer(&card->dch.timer); + w6692_mode(&card->bc[0], ISDN_P_NONE); + w6692_mode(&card->bc[1], ISDN_P_NONE); + WriteW6692(card, W_D_CTL, 0x00); + disable_hwirq(card); + WriteW6692(card, W_D_SAM, 0xff); + WriteW6692(card, W_D_TAM, 0xff); + WriteW6692(card, W_D_MODE, W_D_MODE_RACT); + card->state = W_L1CMD_RST; + ph_command(card, W_L1CMD_RST); + ph_command(card, W_L1CMD_ECK); + /* enable all IRQ but extern */ + card->imask = 0x18; + WriteW6692(card, W_D_EXIM, 0x00); + WriteW6692B(&card->bc[0], W_B_EXIM, 0); + WriteW6692B(&card->bc[1], W_B_EXIM, 0); + /* Reset D-chan receiver and transmitter */ + WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST | W_D_CMDR_XRST); + /* Reset B-chan receiver and transmitter */ + WriteW6692B(&card->bc[0], W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); + WriteW6692B(&card->bc[1], W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); + /* enable peripheral */ + if (card->subtype == W6692_USR) { + /* seems that USR implemented some power control features + * Pin 79 is connected to the oscilator circuit so we + * have to handle it here + */ + card->pctl = 0x80; + card->xdata = 0; + WriteW6692(card, W_PCTL, card->pctl); + WriteW6692(card, W_XDATA, card->xdata); + } else { + card->pctl = W_PCTL_OE5 | W_PCTL_OE4 | W_PCTL_OE2 | + W_PCTL_OE1 | W_PCTL_OE0; + card->xaddr = 0x00;/* all sw off */ + if (card->fmask & pots) + card->xdata |= 0x06; /* POWER UP/ LED OFF / ALAW */ + if (card->fmask & led) + card->xdata |= 0x04; /* LED OFF */ + if ((card->fmask & pots) || (card->fmask & led)) { + WriteW6692(card, W_PCTL, card->pctl); + WriteW6692(card, W_XADDR, card->xaddr); + WriteW6692(card, W_XDATA, card->xdata); + val = ReadW6692(card, W_XADDR); + if (debug & DEBUG_HW) + pr_notice("%s: W_XADDR=%02x\n", + card->name, val); + } + } +} + +static void +reset_w6692(struct w6692_hw *card) +{ + WriteW6692(card, W_D_CTL, W_D_CTL_SRST); + mdelay(10); + WriteW6692(card, W_D_CTL, 0); +} + +static int +init_card(struct w6692_hw *card) +{ + int cnt = 3; + u_long flags; + + spin_lock_irqsave(&card->lock, flags); + disable_hwirq(card); + spin_unlock_irqrestore(&card->lock, flags); + if (request_irq(card->irq, w6692_irq, IRQF_SHARED, card->name, card)) { + pr_info("%s: couldn't get interrupt %d\n", card->name, + card->irq); + return -EIO; + } + while (cnt--) { + spin_lock_irqsave(&card->lock, flags); + initW6692(card); + enable_hwirq(card); + spin_unlock_irqrestore(&card->lock, flags); + /* Timeout 10ms */ + msleep_interruptible(10); + if (debug & DEBUG_HW) + pr_notice("%s: IRQ %d count %d\n", card->name, + card->irq, card->irqcnt); + if (!card->irqcnt) { + pr_info("%s: IRQ(%d) getting no IRQs during init %d\n", + card->name, card->irq, 3 - cnt); + reset_w6692(card); + } else + return 0; + } + free_irq(card->irq, card); + return -EIO; +} + +static int +w6692_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) +{ + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct w6692_ch *bc = container_of(bch, struct w6692_ch, bch); + struct w6692_hw *card = bch->hw; + int ret = -EINVAL; + struct mISDNhead *hh = mISDN_HEAD_P(skb); + u32 id; + u_long flags; + + switch (hh->prim) { + case PH_DATA_REQ: + spin_lock_irqsave(&card->lock, flags); + ret = bchannel_senddata(bch, skb); + if (ret > 0) { /* direct TX */ + id = hh->id; /* skb can be freed */ + ret = 0; + W6692_fill_Bfifo(bc); + spin_unlock_irqrestore(&card->lock, flags); + if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) + queue_ch_frame(ch, PH_DATA_CNF, id, NULL); + } else + spin_unlock_irqrestore(&card->lock, flags); + return ret; + case PH_ACTIVATE_REQ: + spin_lock_irqsave(&card->lock, flags); + if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) + ret = w6692_mode(bc, ch->protocol); + else + ret = 0; + spin_unlock_irqrestore(&card->lock, flags); + if (!ret) + _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_KERNEL); + break; + case PH_DEACTIVATE_REQ: + spin_lock_irqsave(&card->lock, flags); + mISDN_clear_bchannel(bch); + w6692_mode(bc, ISDN_P_NONE); + spin_unlock_irqrestore(&card->lock, flags); + _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_KERNEL); + ret = 0; + break; + default: + pr_info("%s: %s unknown prim(%x,%x)\n", + card->name, __func__, hh->prim, hh->id); + ret = -EINVAL; + } + if (!ret) + dev_kfree_skb(skb); + return ret; +} + +static int +channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = 0; + break; + /* Nothing implemented yet */ + case MISDN_CTRL_FILL_EMPTY: + default: + pr_info("%s: unknown Op %x\n", __func__, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +open_bchannel(struct w6692_hw *card, struct channel_req *rq) +{ + struct bchannel *bch; + + if (rq->adr.channel > 2) + return -EINVAL; + if (rq->protocol == ISDN_P_NONE) + return -EINVAL; + bch = &card->bc[rq->adr.channel - 1].bch; + if (test_and_set_bit(FLG_OPEN, &bch->Flags)) + return -EBUSY; /* b-channel can be only open once */ + test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); + bch->ch.protocol = rq->protocol; + rq->ch = &bch->ch; + return 0; +} + +static int +channel_ctrl(struct w6692_hw *card, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = 0; + break; + default: + pr_info("%s: unknown CTRL OP %x\n", card->name, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +w6692_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) +{ + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct w6692_ch *bc = container_of(bch, struct w6692_ch, bch); + struct w6692_hw *card = bch->hw; + int ret = -EINVAL; + u_long flags; + + pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg); + switch (cmd) { + case CLOSE_CHANNEL: + test_and_clear_bit(FLG_OPEN, &bch->Flags); + if (test_bit(FLG_ACTIVE, &bch->Flags)) { + spin_lock_irqsave(&card->lock, flags); + mISDN_freebchannel(bch); + w6692_mode(bc, ISDN_P_NONE); + spin_unlock_irqrestore(&card->lock, flags); + } else { + skb_queue_purge(&bch->rqueue); + bch->rcount = 0; + } + ch->protocol = ISDN_P_NONE; + ch->peer = NULL; + module_put(THIS_MODULE); + ret = 0; + break; + case CONTROL_CHANNEL: + ret = channel_bctrl(bch, arg); + break; + default: + pr_info("%s: %s unknown prim(%x)\n", + card->name, __func__, cmd); + } + return ret; +} + +static int +w6692_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb) +{ + struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); + struct dchannel *dch = container_of(dev, struct dchannel, dev); + struct w6692_hw *card = container_of(dch, struct w6692_hw, dch); + int ret = -EINVAL; + struct mISDNhead *hh = mISDN_HEAD_P(skb); + u32 id; + u_long flags; + + switch (hh->prim) { + case PH_DATA_REQ: + spin_lock_irqsave(&card->lock, flags); + ret = dchannel_senddata(dch, skb); + if (ret > 0) { /* direct TX */ + id = hh->id; /* skb can be freed */ + W6692_fill_Dfifo(card); + ret = 0; + spin_unlock_irqrestore(&card->lock, flags); + queue_ch_frame(ch, PH_DATA_CNF, id, NULL); + } else + spin_unlock_irqrestore(&card->lock, flags); + return ret; + case PH_ACTIVATE_REQ: + ret = l1_event(dch->l1, hh->prim); + break; + case PH_DEACTIVATE_REQ: + test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); + ret = l1_event(dch->l1, hh->prim); + break; + } + + if (!ret) + dev_kfree_skb(skb); + return ret; +} + +static int +w6692_l1callback(struct dchannel *dch, u32 cmd) +{ + struct w6692_hw *card = container_of(dch, struct w6692_hw, dch); + u_long flags; + + pr_debug("%s: cmd(%x) state(%02x)\n", card->name, cmd, card->state); + switch (cmd) { + case INFO3_P8: + spin_lock_irqsave(&card->lock, flags); + ph_command(card, W_L1CMD_AR8); + spin_unlock_irqrestore(&card->lock, flags); + break; + case INFO3_P10: + spin_lock_irqsave(&card->lock, flags); + ph_command(card, W_L1CMD_AR10); + spin_unlock_irqrestore(&card->lock, flags); + break; + case HW_RESET_REQ: + spin_lock_irqsave(&card->lock, flags); + if (card->state != W_L1IND_DRD) + ph_command(card, W_L1CMD_RST); + ph_command(card, W_L1CMD_ECK); + spin_unlock_irqrestore(&card->lock, flags); + break; + case HW_DEACT_REQ: + skb_queue_purge(&dch->squeue); + if (dch->tx_skb) { + dev_kfree_skb(dch->tx_skb); + dch->tx_skb = NULL; + } + dch->tx_idx = 0; + if (dch->rx_skb) { + dev_kfree_skb(dch->rx_skb); + dch->rx_skb = NULL; + } + test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); + if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) + del_timer(&dch->timer); + break; + case HW_POWERUP_REQ: + spin_lock_irqsave(&card->lock, flags); + ph_command(card, W_L1CMD_ECK); + spin_unlock_irqrestore(&card->lock, flags); + break; + case PH_ACTIVATE_IND: + test_and_set_bit(FLG_ACTIVE, &dch->Flags); + _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, + GFP_ATOMIC); + break; + case PH_DEACTIVATE_IND: + test_and_clear_bit(FLG_ACTIVE, &dch->Flags); + _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, + GFP_ATOMIC); + break; + default: + pr_debug("%s: %s unknown command %x\n", card->name, + __func__, cmd); + return -1; + } + return 0; +} + +static int +open_dchannel(struct w6692_hw *card, struct channel_req *rq) +{ + pr_debug("%s: %s dev(%d) open from %p\n", card->name, __func__, + card->dch.dev.id, __builtin_return_address(1)); + if (rq->protocol != ISDN_P_TE_S0) + return -EINVAL; + if (rq->adr.channel == 1) + /* E-Channel not supported */ + return -EINVAL; + rq->ch = &card->dch.dev.D; + rq->ch->protocol = rq->protocol; + if (card->dch.state == 7) + _queue_data(rq->ch, PH_ACTIVATE_IND, MISDN_ID_ANY, + 0, NULL, GFP_KERNEL); + return 0; +} + +static int +w6692_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) +{ + struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); + struct dchannel *dch = container_of(dev, struct dchannel, dev); + struct w6692_hw *card = container_of(dch, struct w6692_hw, dch); + struct channel_req *rq; + int err = 0; + + pr_debug("%s: DCTRL: %x %p\n", card->name, cmd, arg); + switch (cmd) { + case OPEN_CHANNEL: + rq = arg; + if (rq->protocol == ISDN_P_TE_S0) + err = open_dchannel(card, rq); + else + err = open_bchannel(card, rq); + if (err) + break; + if (!try_module_get(THIS_MODULE)) + pr_info("%s: cannot get module\n", card->name); + break; + case CLOSE_CHANNEL: + pr_debug("%s: dev(%d) close from %p\n", card->name, + dch->dev.id, __builtin_return_address(0)); + module_put(THIS_MODULE); + break; + case CONTROL_CHANNEL: + err = channel_ctrl(card, arg); + break; + default: + pr_debug("%s: unknown DCTRL command %x\n", card->name, cmd); + return -EINVAL; + } + return err; +} + +int +setup_w6692(struct w6692_hw *card) +{ + u32 val; + + if (!request_region(card->addr, 256, card->name)) { + pr_info("%s: config port %x-%x already in use\n", card->name, + card->addr, card->addr + 255); + return -EIO; + } + W6692Version(card); + card->bc[0].addr = card->addr; + card->bc[1].addr = card->addr + 0x40; + val = ReadW6692(card, W_ISTA); + if (debug & DEBUG_HW) + pr_notice("%s ISTA=%02x\n", card->name, val); + val = ReadW6692(card, W_IMASK); + if (debug & DEBUG_HW) + pr_notice("%s IMASK=%02x\n", card->name, val); + val = ReadW6692(card, W_D_EXIR); + if (debug & DEBUG_HW) + pr_notice("%s D_EXIR=%02x\n", card->name, val); + val = ReadW6692(card, W_D_EXIM); + if (debug & DEBUG_HW) + pr_notice("%s D_EXIM=%02x\n", card->name, val); + val = ReadW6692(card, W_D_RSTA); + if (debug & DEBUG_HW) + pr_notice("%s D_RSTA=%02x\n", card->name, val); + return 0; +} + +static void +release_card(struct w6692_hw *card) +{ + u_long flags; + + spin_lock_irqsave(&card->lock, flags); + disable_hwirq(card); + w6692_mode(&card->bc[0], ISDN_P_NONE); + w6692_mode(&card->bc[1], ISDN_P_NONE); + if ((card->fmask & led) || card->subtype == W6692_USR) { + card->xdata |= 0x04; /* LED OFF */ + WriteW6692(card, W_XDATA, card->xdata); + } + spin_unlock_irqrestore(&card->lock, flags); + free_irq(card->irq, card); + l1_event(card->dch.l1, CLOSE_CHANNEL); + mISDN_unregister_device(&card->dch.dev); + release_region(card->addr, 256); + mISDN_freebchannel(&card->bc[1].bch); + mISDN_freebchannel(&card->bc[0].bch); + mISDN_freedchannel(&card->dch); + write_lock_irqsave(&card_lock, flags); + list_del(&card->list); + write_unlock_irqrestore(&card_lock, flags); + pci_disable_device(card->pdev); + pci_set_drvdata(card->pdev, NULL); + kfree(card); +} + +static int +setup_instance(struct w6692_hw *card) +{ + int i, err; + u_long flags; + + snprintf(card->name, MISDN_MAX_IDLEN - 1, "w6692.%d", w6692_cnt + 1); + write_lock_irqsave(&card_lock, flags); + list_add_tail(&card->list, &Cards); + write_unlock_irqrestore(&card_lock, flags); + card->fmask = (1 << w6692_cnt); + _set_debug(card); + spin_lock_init(&card->lock); + mISDN_initdchannel(&card->dch, MAX_DFRAME_LEN_L1, W6692_ph_bh); + card->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0); + card->dch.dev.D.send = w6692_l2l1D; + card->dch.dev.D.ctrl = w6692_dctrl; + card->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | + (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); + card->dch.hw = card; + card->dch.dev.nrbchan = 2; + for (i = 0; i < 2; i++) { + mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM); + card->bc[i].bch.hw = card; + card->bc[i].bch.nr = i + 1; + card->bc[i].bch.ch.nr = i + 1; + card->bc[i].bch.ch.send = w6692_l2l1B; + card->bc[i].bch.ch.ctrl = w6692_bctrl; + set_channelmap(i + 1, card->dch.dev.channelmap); + list_add(&card->bc[i].bch.ch.list, &card->dch.dev.bchannels); + } + err = setup_w6692(card); + if (err) + goto error_setup; + err = mISDN_register_device(&card->dch.dev, &card->pdev->dev, + card->name); + if (err) + goto error_reg; + err = init_card(card); + if (err) + goto error_init; + err = create_l1(&card->dch, w6692_l1callback); + if (!err) { + w6692_cnt++; + pr_notice("W6692 %d cards installed\n", w6692_cnt); + return 0; + } + + free_irq(card->irq, card); +error_init: + mISDN_unregister_device(&card->dch.dev); +error_reg: + release_region(card->addr, 256); +error_setup: + mISDN_freebchannel(&card->bc[1].bch); + mISDN_freebchannel(&card->bc[0].bch); + mISDN_freedchannel(&card->dch); + write_lock_irqsave(&card_lock, flags); + list_del(&card->list); + write_unlock_irqrestore(&card_lock, flags); + kfree(card); + return err; +} + +static int __devinit +w6692_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int err = -ENOMEM; + struct w6692_hw *card; + struct w6692map *m = (struct w6692map *)ent->driver_data; + + card = kzalloc(sizeof(struct w6692_hw), GFP_KERNEL); + if (!card) { + pr_info("No kmem for w6692 card\n"); + return err; + } + card->pdev = pdev; + card->subtype = m->subtype; + err = pci_enable_device(pdev); + if (err) { + kfree(card); + return err; + } + + printk(KERN_INFO "mISDN_w6692: found adapter %s at %s\n", + m->name, pci_name(pdev)); + + card->addr = pci_resource_start(pdev, 1); + card->irq = pdev->irq; + pci_set_drvdata(pdev, card); + err = setup_instance(card); + if (err) + pci_set_drvdata(pdev, NULL); + return err; +} + +static void __devexit +w6692_remove_pci(struct pci_dev *pdev) +{ + struct w6692_hw *card = pci_get_drvdata(pdev); + + if (card) + release_card(card); + else + if (debug) + pr_notice("%s: drvdata allready removed\n", __func__); +} + +static struct pci_device_id w6692_ids[] = { + { PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, (ulong)&w6692_map[0]}, + { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, + PCI_VENDOR_ID_USR, PCI_DEVICE_ID_USR_6692, 0, 0, + (ulong)&w6692_map[2]}, + { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, (ulong)&w6692_map[1]}, + { } +}; +MODULE_DEVICE_TABLE(pci, w6692_ids); + +static struct pci_driver w6692_driver = { + .name = "w6692", + .probe = w6692_probe, + .remove = __devexit_p(w6692_remove_pci), + .id_table = w6692_ids, +}; + +static int __init w6692_init(void) +{ + int err; + + pr_notice("Winbond W6692 PCI driver Rev. %s\n", W6692_REV); + + err = pci_register_driver(&w6692_driver); + return err; +} + +static void __exit w6692_cleanup(void) +{ + pci_unregister_driver(&w6692_driver); +} + +module_init(w6692_init); +module_exit(w6692_cleanup); diff --git a/drivers/isdn/hardware/mISDN/w6692.h b/drivers/isdn/hardware/mISDN/w6692.h new file mode 100644 index 00000000000..f95697757fd --- /dev/null +++ b/drivers/isdn/hardware/mISDN/w6692.h @@ -0,0 +1,190 @@ +/* + * Winbond W6692 specific defines + * + * Author Karsten Keil + * based on the w6692 I4L driver from Petr Novak + * + * Copyright 2009 by Karsten Keil + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* Specifications of W6692 registers */ + +#define W_D_RFIFO 0x00 /* R */ +#define W_D_XFIFO 0x04 /* W */ +#define W_D_CMDR 0x08 /* W */ +#define W_D_MODE 0x0c /* R/W */ +#define W_D_TIMR 0x10 /* R/W */ +#define W_ISTA 0x14 /* R_clr */ +#define W_IMASK 0x18 /* R/W */ +#define W_D_EXIR 0x1c /* R_clr */ +#define W_D_EXIM 0x20 /* R/W */ +#define W_D_STAR 0x24 /* R */ +#define W_D_RSTA 0x28 /* R */ +#define W_D_SAM 0x2c /* R/W */ +#define W_D_SAP1 0x30 /* R/W */ +#define W_D_SAP2 0x34 /* R/W */ +#define W_D_TAM 0x38 /* R/W */ +#define W_D_TEI1 0x3c /* R/W */ +#define W_D_TEI2 0x40 /* R/W */ +#define W_D_RBCH 0x44 /* R */ +#define W_D_RBCL 0x48 /* R */ +#define W_TIMR2 0x4c /* W */ +#define W_L1_RC 0x50 /* R/W */ +#define W_D_CTL 0x54 /* R/W */ +#define W_CIR 0x58 /* R */ +#define W_CIX 0x5c /* W */ +#define W_SQR 0x60 /* R */ +#define W_SQX 0x64 /* W */ +#define W_PCTL 0x68 /* R/W */ +#define W_MOR 0x6c /* R */ +#define W_MOX 0x70 /* R/W */ +#define W_MOSR 0x74 /* R_clr */ +#define W_MOCR 0x78 /* R/W */ +#define W_GCR 0x7c /* R/W */ + +#define W_B_RFIFO 0x80 /* R */ +#define W_B_XFIFO 0x84 /* W */ +#define W_B_CMDR 0x88 /* W */ +#define W_B_MODE 0x8c /* R/W */ +#define W_B_EXIR 0x90 /* R_clr */ +#define W_B_EXIM 0x94 /* R/W */ +#define W_B_STAR 0x98 /* R */ +#define W_B_ADM1 0x9c /* R/W */ +#define W_B_ADM2 0xa0 /* R/W */ +#define W_B_ADR1 0xa4 /* R/W */ +#define W_B_ADR2 0xa8 /* R/W */ +#define W_B_RBCL 0xac /* R */ +#define W_B_RBCH 0xb0 /* R */ + +#define W_XADDR 0xf4 /* R/W */ +#define W_XDATA 0xf8 /* R/W */ +#define W_EPCTL 0xfc /* W */ + +/* W6692 register bits */ + +#define W_D_CMDR_XRST 0x01 +#define W_D_CMDR_XME 0x02 +#define W_D_CMDR_XMS 0x08 +#define W_D_CMDR_STT 0x10 +#define W_D_CMDR_RRST 0x40 +#define W_D_CMDR_RACK 0x80 + +#define W_D_MODE_RLP 0x01 +#define W_D_MODE_DLP 0x02 +#define W_D_MODE_MFD 0x04 +#define W_D_MODE_TEE 0x08 +#define W_D_MODE_TMS 0x10 +#define W_D_MODE_RACT 0x40 +#define W_D_MODE_MMS 0x80 + +#define W_INT_B2_EXI 0x01 +#define W_INT_B1_EXI 0x02 +#define W_INT_D_EXI 0x04 +#define W_INT_XINT0 0x08 +#define W_INT_XINT1 0x10 +#define W_INT_D_XFR 0x20 +#define W_INT_D_RME 0x40 +#define W_INT_D_RMR 0x80 + +#define W_D_EXI_WEXP 0x01 +#define W_D_EXI_TEXP 0x02 +#define W_D_EXI_ISC 0x04 +#define W_D_EXI_MOC 0x08 +#define W_D_EXI_TIN2 0x10 +#define W_D_EXI_XCOL 0x20 +#define W_D_EXI_XDUN 0x40 +#define W_D_EXI_RDOV 0x80 + +#define W_D_STAR_DRDY 0x10 +#define W_D_STAR_XBZ 0x20 +#define W_D_STAR_XDOW 0x80 + +#define W_D_RSTA_RMB 0x10 +#define W_D_RSTA_CRCE 0x20 +#define W_D_RSTA_RDOV 0x40 + +#define W_D_CTL_SRST 0x20 + +#define W_CIR_SCC 0x80 +#define W_CIR_ICC 0x40 +#define W_CIR_COD_MASK 0x0f + +#define W_PCTL_PCX 0x01 +#define W_PCTL_XMODE 0x02 +#define W_PCTL_OE0 0x04 +#define W_PCTL_OE1 0x08 +#define W_PCTL_OE2 0x10 +#define W_PCTL_OE3 0x20 +#define W_PCTL_OE4 0x40 +#define W_PCTL_OE5 0x80 + +#define W_B_CMDR_XRST 0x01 +#define W_B_CMDR_XME 0x02 +#define W_B_CMDR_XMS 0x04 +#define W_B_CMDR_RACT 0x20 +#define W_B_CMDR_RRST 0x40 +#define W_B_CMDR_RACK 0x80 + +#define W_B_MODE_FTS0 0x01 +#define W_B_MODE_FTS1 0x02 +#define W_B_MODE_SW56 0x04 +#define W_B_MODE_BSW0 0x08 +#define W_B_MODE_BSW1 0x10 +#define W_B_MODE_EPCM 0x20 +#define W_B_MODE_ITF 0x40 +#define W_B_MODE_MMS 0x80 + +#define W_B_EXI_XDUN 0x01 +#define W_B_EXI_XFR 0x02 +#define W_B_EXI_RDOV 0x10 +#define W_B_EXI_RME 0x20 +#define W_B_EXI_RMR 0x40 + +#define W_B_STAR_XBZ 0x01 +#define W_B_STAR_XDOW 0x04 +#define W_B_STAR_RMB 0x10 +#define W_B_STAR_CRCE 0x20 +#define W_B_STAR_RDOV 0x40 + +#define W_B_RBCH_LOV 0x20 + +/* W6692 Layer1 commands */ + +#define W_L1CMD_ECK 0x00 +#define W_L1CMD_RST 0x01 +#define W_L1CMD_SCP 0x04 +#define W_L1CMD_SSP 0x02 +#define W_L1CMD_AR8 0x08 +#define W_L1CMD_AR10 0x09 +#define W_L1CMD_EAL 0x0a +#define W_L1CMD_DRC 0x0f + +/* W6692 Layer1 indications */ + +#define W_L1IND_CE 0x07 +#define W_L1IND_DRD 0x00 +#define W_L1IND_LD 0x04 +#define W_L1IND_ARD 0x08 +#define W_L1IND_TI 0x0a +#define W_L1IND_ATI 0x0b +#define W_L1IND_AI8 0x0c +#define W_L1IND_AI10 0x0d +#define W_L1IND_CD 0x0f + +/* FIFO thresholds */ +#define W_D_FIFO_THRESH 64 +#define W_B_FIFO_THRESH 64 -- cgit v1.2.3-18-g5258 From a900845e56617edc005fd8f35bfd5a407aaf96c8 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Thu, 23 Jul 2009 10:03:05 +0200 Subject: mISDN: Add support for Traverse Technologies NETJet PCI cards Add support for cards based on the Tiger 300 and Tiger 320 ISDN PCI chip. Currently only the ISAC ISDN line interface is supported. Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/Kconfig | 9 + drivers/isdn/hardware/mISDN/Makefile | 1 + drivers/isdn/hardware/mISDN/netjet.c | 1156 ++++++++++++++++++++++++++++++++++ drivers/isdn/hardware/mISDN/netjet.h | 58 ++ 4 files changed, 1224 insertions(+) create mode 100644 drivers/isdn/hardware/mISDN/netjet.c create mode 100644 drivers/isdn/hardware/mISDN/netjet.h (limited to 'drivers') diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig index d72586e6838..bde55d7287f 100644 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ b/drivers/isdn/hardware/mISDN/Kconfig @@ -72,6 +72,15 @@ config MISDN_W6692 help Enable support for Winbond 6692 PCI chip based cards. +config MISDN_NETJET + tristate "Support for NETJet cards" + depends on MISDN + depends on PCI + select MISDN_IPAC + select ISDN_HDLC + help + Enable support for Traverse Technologies NETJet PCI cards. + config MISDN_IPAC tristate diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile index 61dd5a5f300..2987d990993 100644 --- a/drivers/isdn/hardware/mISDN/Makefile +++ b/drivers/isdn/hardware/mISDN/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_MISDN_AVMFRITZ) += avmfritz.o obj-$(CONFIG_MISDN_SPEEDFAX) += speedfax.o obj-$(CONFIG_MISDN_INFINEON) += mISDNinfineon.o obj-$(CONFIG_MISDN_W6692) += w6692.o +obj-$(CONFIG_MISDN_NETJET) += netjet.o # chip modules obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o obj-$(CONFIG_MISDN_ISAR) += mISDNisar.o diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c new file mode 100644 index 00000000000..6c1b164937a --- /dev/null +++ b/drivers/isdn/hardware/mISDN/netjet.c @@ -0,0 +1,1156 @@ +/* + * NETJet mISDN driver + * + * Author Karsten Keil + * + * Copyright 2009 by Karsten Keil + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include "ipac.h" +#include "iohelper.h" +#include "netjet.h" +#include + +#define NETJET_REV "2.0" + +enum nj_types { + NETJET_S_TJ300, + NETJET_S_TJ320, + ENTERNOW__TJ320, +}; + +struct tiger_dma { + size_t size; + u32 *start; + int idx; + u32 dmastart; + u32 dmairq; + u32 dmaend; + u32 dmacur; +}; + +struct tiger_hw; + +struct tiger_ch { + struct bchannel bch; + struct tiger_hw *nj; + int idx; + int free; + int lastrx; + u16 rxstate; + u16 txstate; + struct isdnhdlc_vars hsend; + struct isdnhdlc_vars hrecv; + u8 *hsbuf; + u8 *hrbuf; +}; + +#define TX_INIT 0x0001 +#define TX_IDLE 0x0002 +#define TX_RUN 0x0004 +#define TX_UNDERRUN 0x0100 +#define RX_OVERRUN 0x0100 + +#define LOG_SIZE 64 + +struct tiger_hw { + struct list_head list; + struct pci_dev *pdev; + char name[MISDN_MAX_IDLEN]; + enum nj_types typ; + int irq; + u32 irqcnt; + u32 base; + size_t base_s; + dma_addr_t dma; + void *dma_p; + spinlock_t lock; /* lock HW */ + struct isac_hw isac; + struct tiger_dma send; + struct tiger_dma recv; + struct tiger_ch bc[2]; + u8 ctrlreg; + u8 dmactrl; + u8 auxd; + u8 last_is0; + u8 irqmask0; + char log[LOG_SIZE]; +}; + +static LIST_HEAD(Cards); +static DEFINE_RWLOCK(card_lock); /* protect Cards */ +static u32 debug; +static int nj_cnt; + +static void +_set_debug(struct tiger_hw *card) +{ + card->isac.dch.debug = debug; + card->bc[0].bch.debug = debug; + card->bc[1].bch.debug = debug; +} + +static int +set_debug(const char *val, struct kernel_param *kp) +{ + int ret; + struct tiger_hw *card; + + ret = param_set_uint(val, kp); + if (!ret) { + read_lock(&card_lock); + list_for_each_entry(card, &Cards, list) + _set_debug(card); + read_unlock(&card_lock); + } + return ret; +} + +MODULE_AUTHOR("Karsten Keil"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(NETJET_REV); +module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Netjet debug mask"); + +static void +nj_disable_hwirq(struct tiger_hw *card) +{ + outb(0, card->base + NJ_IRQMASK0); + outb(0, card->base + NJ_IRQMASK1); +} + + +static u8 +ReadISAC_nj(void *p, u8 offset) +{ + struct tiger_hw *card = p; + u8 ret; + + card->auxd &= 0xfc; + card->auxd |= (offset >> 4) & 3; + outb(card->auxd, card->base + NJ_AUXDATA); + ret = inb(card->base + NJ_ISAC_OFF + ((offset & 0x0f) << 2)); + return ret; +} + +static void +WriteISAC_nj(void *p, u8 offset, u8 value) +{ + struct tiger_hw *card = p; + + card->auxd &= 0xfc; + card->auxd |= (offset >> 4) & 3; + outb(card->auxd, card->base + NJ_AUXDATA); + outb(value, card->base + NJ_ISAC_OFF + ((offset & 0x0f) << 2)); +} + +static void +ReadFiFoISAC_nj(void *p, u8 offset, u8 *data, int size) +{ + struct tiger_hw *card = p; + + card->auxd &= 0xfc; + outb(card->auxd, card->base + NJ_AUXDATA); + insb(card->base + NJ_ISAC_OFF, data, size); +} + +static void +WriteFiFoISAC_nj(void *p, u8 offset, u8 *data, int size) +{ + struct tiger_hw *card = p; + + card->auxd &= 0xfc; + outb(card->auxd, card->base + NJ_AUXDATA); + outsb(card->base + NJ_ISAC_OFF, data, size); +} + +static void +fill_mem(struct tiger_ch *bc, u32 idx, u32 cnt, u32 fill) +{ + struct tiger_hw *card = bc->bch.hw; + u32 mask = 0xff, val; + + pr_debug("%s: B%1d fill %02x len %d idx %d/%d\n", card->name, + bc->bch.nr, fill, cnt, idx, card->send.idx); + if (bc->bch.nr & 2) { + fill <<= 8; + mask <<= 8; + } + mask ^= 0xffffffff; + while (cnt--) { + val = card->send.start[idx]; + val &= mask; + val |= fill; + card->send.start[idx++] = val; + if (idx >= card->send.size) + idx = 0; + } +} + +static int +mode_tiger(struct tiger_ch *bc, u32 protocol) +{ + struct tiger_hw *card = bc->bch.hw; + + pr_debug("%s: B%1d protocol %x-->%x\n", card->name, + bc->bch.nr, bc->bch.state, protocol); + switch (protocol) { + case ISDN_P_NONE: + if (bc->bch.state == ISDN_P_NONE) + break; + fill_mem(bc, 0, card->send.size, 0xff); + bc->bch.state = protocol; + /* only stop dma and interrupts if both channels NULL */ + if ((card->bc[0].bch.state == ISDN_P_NONE) && + (card->bc[1].bch.state == ISDN_P_NONE)) { + card->dmactrl = 0; + outb(card->dmactrl, card->base + NJ_DMACTRL); + outb(0, card->base + NJ_IRQMASK0); + } + test_and_clear_bit(FLG_HDLC, &bc->bch.Flags); + test_and_clear_bit(FLG_TRANSPARENT, &bc->bch.Flags); + bc->txstate = 0; + bc->rxstate = 0; + bc->lastrx = -1; + break; + case ISDN_P_B_RAW: + test_and_set_bit(FLG_TRANSPARENT, &bc->bch.Flags); + bc->bch.state = protocol; + bc->idx = 0; + bc->free = card->send.size/2; + bc->rxstate = 0; + bc->txstate = TX_INIT | TX_IDLE; + bc->lastrx = -1; + if (!card->dmactrl) { + card->dmactrl = 1; + outb(card->dmactrl, card->base + NJ_DMACTRL); + outb(0x0f, card->base + NJ_IRQMASK0); + } + break; + case ISDN_P_B_HDLC: + test_and_set_bit(FLG_HDLC, &bc->bch.Flags); + bc->bch.state = protocol; + bc->idx = 0; + bc->free = card->send.size/2; + bc->rxstate = 0; + bc->txstate = TX_INIT | TX_IDLE; + isdnhdlc_rcv_init(&bc->hrecv, 0); + isdnhdlc_out_init(&bc->hsend, 0); + bc->lastrx = -1; + if (!card->dmactrl) { + card->dmactrl = 1; + outb(card->dmactrl, card->base + NJ_DMACTRL); + outb(0x0f, card->base + NJ_IRQMASK0); + } + break; + default: + pr_info("%s: %s protocol %x not handled\n", card->name, + __func__, protocol); + return -ENOPROTOOPT; + } + card->send.dmacur = inl(card->base + NJ_DMA_READ_ADR); + card->recv.dmacur = inl(card->base + NJ_DMA_WRITE_ADR); + card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2; + card->recv.idx = (card->recv.dmacur - card->recv.dmastart) >> 2; + pr_debug("%s: %s ctrl %x irq %02x/%02x idx %d/%d\n", + card->name, __func__, + inb(card->base + NJ_DMACTRL), + inb(card->base + NJ_IRQMASK0), + inb(card->base + NJ_IRQSTAT0), + card->send.idx, + card->recv.idx); + return 0; +} + +static void +nj_reset(struct tiger_hw *card) +{ + outb(0xff, card->base + NJ_CTRL); /* Reset On */ + mdelay(1); + + /* now edge triggered for TJ320 GE 13/07/00 */ + /* see comment in IRQ function */ + if (card->typ == NETJET_S_TJ320) /* TJ320 */ + card->ctrlreg = 0x40; /* Reset Off and status read clear */ + else + card->ctrlreg = 0x00; /* Reset Off and status read clear */ + outb(card->ctrlreg, card->base + NJ_CTRL); + mdelay(10); + + /* configure AUX pins (all output except ISAC IRQ pin) */ + card->auxd = 0; + card->dmactrl = 0; + outb(~NJ_ISACIRQ, card->base + NJ_AUXCTRL); + outb(NJ_ISACIRQ, card->base + NJ_IRQMASK1); + outb(card->auxd, card->base + NJ_AUXDATA); +} + +static int +inittiger(struct tiger_hw *card) +{ + int i; + + card->dma_p = pci_alloc_consistent(card->pdev, NJ_DMA_SIZE, + &card->dma); + if (!card->dma_p) { + pr_info("%s: No DMA memory\n", card->name); + return -ENOMEM; + } + if ((u64)card->dma > 0xffffffff) { + pr_info("%s: DMA outside 32 bit\n", card->name); + return -ENOMEM; + } + for (i = 0; i < 2; i++) { + card->bc[i].hsbuf = kmalloc(NJ_DMA_TXSIZE, GFP_KERNEL); + if (!card->bc[i].hsbuf) { + pr_info("%s: no B%d send buffer\n", card->name, i + 1); + return -ENOMEM; + } + card->bc[i].hrbuf = kmalloc(NJ_DMA_RXSIZE, GFP_KERNEL); + if (!card->bc[i].hrbuf) { + pr_info("%s: no B%d recv buffer\n", card->name, i + 1); + return -ENOMEM; + } + } + memset(card->dma_p, 0xff, NJ_DMA_SIZE); + + card->send.start = card->dma_p; + card->send.dmastart = (u32)card->dma; + card->send.dmaend = card->send.dmastart + + (4 * (NJ_DMA_TXSIZE - 1)); + card->send.dmairq = card->send.dmastart + + (4 * ((NJ_DMA_TXSIZE / 2) - 1)); + card->send.size = NJ_DMA_TXSIZE; + + if (debug & DEBUG_HW) + pr_notice("%s: send buffer phy %#x - %#x - %#x virt %p" + " size %zu u32\n", card->name, + card->send.dmastart, card->send.dmairq, + card->send.dmaend, card->send.start, card->send.size); + + outl(card->send.dmastart, card->base + NJ_DMA_READ_START); + outl(card->send.dmairq, card->base + NJ_DMA_READ_IRQ); + outl(card->send.dmaend, card->base + NJ_DMA_READ_END); + + card->recv.start = card->dma_p + (NJ_DMA_SIZE / 2); + card->recv.dmastart = (u32)card->dma + (NJ_DMA_SIZE / 2); + card->recv.dmaend = card->recv.dmastart + + (4 * (NJ_DMA_RXSIZE - 1)); + card->recv.dmairq = card->recv.dmastart + + (4 * ((NJ_DMA_RXSIZE / 2) - 1)); + card->recv.size = NJ_DMA_RXSIZE; + + if (debug & DEBUG_HW) + pr_notice("%s: recv buffer phy %#x - %#x - %#x virt %p" + " size %zu u32\n", card->name, + card->recv.dmastart, card->recv.dmairq, + card->recv.dmaend, card->recv.start, card->recv.size); + + outl(card->recv.dmastart, card->base + NJ_DMA_WRITE_START); + outl(card->recv.dmairq, card->base + NJ_DMA_WRITE_IRQ); + outl(card->recv.dmaend, card->base + NJ_DMA_WRITE_END); + return 0; +} + +static void +read_dma(struct tiger_ch *bc, u32 idx, int cnt) +{ + struct tiger_hw *card = bc->bch.hw; + int i, stat; + u32 val; + u8 *p, *pn; + + if (bc->lastrx == idx) { + bc->rxstate |= RX_OVERRUN; + pr_info("%s: B%1d overrun at idx %d\n", card->name, + bc->bch.nr, idx); + } + bc->lastrx = idx; + if (!bc->bch.rx_skb) { + bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen, GFP_ATOMIC); + if (!bc->bch.rx_skb) { + pr_info("%s: B%1d receive out of memory\n", + card->name, bc->bch.nr); + return; + } + } + + if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) { + if ((bc->bch.rx_skb->len + cnt) > bc->bch.maxlen) { + pr_debug("%s: B%1d overrun %d\n", card->name, + bc->bch.nr, bc->bch.rx_skb->len + cnt); + skb_trim(bc->bch.rx_skb, 0); + return; + } + p = skb_put(bc->bch.rx_skb, cnt); + } else + p = bc->hrbuf; + + for (i = 0; i < cnt; i++) { + val = card->recv.start[idx++]; + if (bc->bch.nr & 2) + val >>= 8; + if (idx >= card->recv.size) + idx = 0; + p[i] = val & 0xff; + } + pn = bc->hrbuf; +next_frame: + if (test_bit(FLG_HDLC, &bc->bch.Flags)) { + stat = isdnhdlc_decode(&bc->hrecv, pn, cnt, &i, + bc->bch.rx_skb->data, bc->bch.maxlen); + if (stat > 0) /* valid frame received */ + p = skb_put(bc->bch.rx_skb, stat); + else if (stat == -HDLC_CRC_ERROR) + pr_info("%s: B%1d receive frame CRC error\n", + card->name, bc->bch.nr); + else if (stat == -HDLC_FRAMING_ERROR) + pr_info("%s: B%1d receive framing error\n", + card->name, bc->bch.nr); + else if (stat == -HDLC_LENGTH_ERROR) + pr_info("%s: B%1d receive frame too long (> %d)\n", + card->name, bc->bch.nr, bc->bch.maxlen); + } else + stat = cnt; + + if (stat > 0) { + if (debug & DEBUG_HW_BFIFO) { + snprintf(card->log, LOG_SIZE, "B%1d-recv %s %d ", + bc->bch.nr, card->name, stat); + print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, + p, stat); + } + recv_Bchannel(&bc->bch, 0); + } + if (test_bit(FLG_HDLC, &bc->bch.Flags)) { + pn += i; + cnt -= i; + if (!bc->bch.rx_skb) { + bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen, + GFP_ATOMIC); + if (!bc->bch.rx_skb) { + pr_info("%s: B%1d receive out of memory\n", + card->name, bc->bch.nr); + return; + } + } + if (cnt > 0) + goto next_frame; + } +} + +static void +recv_tiger(struct tiger_hw *card, u8 irq_stat) +{ + u32 idx; + int cnt = card->recv.size / 2; + + /* Note receive is via the WRITE DMA channel */ + card->last_is0 &= ~NJ_IRQM0_WR_MASK; + card->last_is0 |= (irq_stat & NJ_IRQM0_WR_MASK); + + if (irq_stat & NJ_IRQM0_WR_END) + idx = cnt - 1; + else + idx = card->recv.size - 1; + + if (test_bit(FLG_ACTIVE, &card->bc[0].bch.Flags)) + read_dma(&card->bc[0], idx, cnt); + if (test_bit(FLG_ACTIVE, &card->bc[1].bch.Flags)) + read_dma(&card->bc[1], idx, cnt); +} + +/* sync with current DMA address at start or after exception */ +static void +resync(struct tiger_ch *bc, struct tiger_hw *card) +{ + card->send.dmacur = inl(card->base | NJ_DMA_READ_ADR); + card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2; + if (bc->free > card->send.size / 2) + bc->free = card->send.size / 2; + /* currently we simple sync to the next complete free area + * this hast the advantage that we have always maximum time to + * handle TX irq + */ + if (card->send.idx < ((card->send.size / 2) - 1)) + bc->idx = (card->recv.size / 2) - 1; + else + bc->idx = card->recv.size - 1; + bc->txstate = TX_RUN; + pr_debug("%s: %s B%1d free %d idx %d/%d\n", card->name, + __func__, bc->bch.nr, bc->free, bc->idx, card->send.idx); +} + +static int bc_next_frame(struct tiger_ch *); + +static void +fill_hdlc_flag(struct tiger_ch *bc) +{ + struct tiger_hw *card = bc->bch.hw; + int count, i; + u32 m, v; + u8 *p; + + if (bc->free == 0) + return; + pr_debug("%s: %s B%1d %d state %x idx %d/%d\n", card->name, + __func__, bc->bch.nr, bc->free, bc->txstate, + bc->idx, card->send.idx); + if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN)) + resync(bc, card); + count = isdnhdlc_encode(&bc->hsend, NULL, 0, &i, + bc->hsbuf, bc->free); + pr_debug("%s: B%1d hdlc encoded %d flags\n", card->name, + bc->bch.nr, count); + bc->free -= count; + p = bc->hsbuf; + m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff; + for (i = 0; i < count; i++) { + if (bc->idx >= card->send.size) + bc->idx = 0; + v = card->send.start[bc->idx]; + v &= m; + v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8; + card->send.start[bc->idx++] = v; + } + if (debug & DEBUG_HW_BFIFO) { + snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ", + bc->bch.nr, card->name, count); + print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, p, count); + } +} + +static void +fill_dma(struct tiger_ch *bc) +{ + struct tiger_hw *card = bc->bch.hw; + int count, i; + u32 m, v; + u8 *p; + + if (bc->free == 0) + return; + count = bc->bch.tx_skb->len - bc->bch.tx_idx; + if (count <= 0) + return; + pr_debug("%s: %s B%1d %d/%d/%d/%d state %x idx %d/%d\n", card->name, + __func__, bc->bch.nr, count, bc->free, bc->bch.tx_idx, + bc->bch.tx_skb->len, bc->txstate, bc->idx, card->send.idx); + if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN)) + resync(bc, card); + p = bc->bch.tx_skb->data + bc->bch.tx_idx; + if (test_bit(FLG_HDLC, &bc->bch.Flags)) { + count = isdnhdlc_encode(&bc->hsend, p, count, &i, + bc->hsbuf, bc->free); + pr_debug("%s: B%1d hdlc encoded %d in %d\n", card->name, + bc->bch.nr, i, count); + bc->bch.tx_idx += i; + bc->free -= count; + p = bc->hsbuf; + } else { + if (count > bc->free) + count = bc->free; + bc->bch.tx_idx += count; + bc->free -= count; + } + m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff; + for (i = 0; i < count; i++) { + if (bc->idx >= card->send.size) + bc->idx = 0; + v = card->send.start[bc->idx]; + v &= m; + v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8; + card->send.start[bc->idx++] = v; + } + if (debug & DEBUG_HW_BFIFO) { + snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ", + bc->bch.nr, card->name, count); + print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, p, count); + } + if (bc->free) + bc_next_frame(bc); +} + + +static int +bc_next_frame(struct tiger_ch *bc) +{ + if (bc->bch.tx_skb && bc->bch.tx_idx < bc->bch.tx_skb->len) + fill_dma(bc); + else { + if (bc->bch.tx_skb) { + /* send confirm, on trans, free on hdlc. */ + if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) + confirm_Bsend(&bc->bch); + dev_kfree_skb(bc->bch.tx_skb); + } + if (get_next_bframe(&bc->bch)) + fill_dma(bc); + else + return 0; + } + return 1; +} + +static void +send_tiger_bc(struct tiger_hw *card, struct tiger_ch *bc) +{ + int ret; + + bc->free += card->send.size / 2; + if (bc->free >= card->send.size) { + if (!(bc->txstate & (TX_UNDERRUN | TX_INIT))) { + pr_info("%s: B%1d TX underrun state %x\n", card->name, + bc->bch.nr, bc->txstate); + bc->txstate |= TX_UNDERRUN; + } + bc->free = card->send.size; + } + ret = bc_next_frame(bc); + if (!ret) { + if (test_bit(FLG_HDLC, &bc->bch.Flags)) { + fill_hdlc_flag(bc); + return; + } + pr_debug("%s: B%1d TX no data free %d idx %d/%d\n", card->name, + bc->bch.nr, bc->free, bc->idx, card->send.idx); + if (!(bc->txstate & (TX_IDLE | TX_INIT))) { + fill_mem(bc, bc->idx, bc->free, 0xff); + if (bc->free == card->send.size) + bc->txstate |= TX_IDLE; + } + } +} + +static void +send_tiger(struct tiger_hw *card, u8 irq_stat) +{ + int i; + + /* Note send is via the READ DMA channel */ + if ((irq_stat & card->last_is0) & NJ_IRQM0_RD_MASK) { + pr_info("%s: tiger warn write double dma %x/%x\n", + card->name, irq_stat, card->last_is0); + return; + } else { + card->last_is0 &= ~NJ_IRQM0_RD_MASK; + card->last_is0 |= (irq_stat & NJ_IRQM0_RD_MASK); + } + for (i = 0; i < 2; i++) { + if (test_bit(FLG_ACTIVE, &card->bc[i].bch.Flags)) + send_tiger_bc(card, &card->bc[i]); + } +} + +static irqreturn_t +nj_irq(int intno, void *dev_id) +{ + struct tiger_hw *card = dev_id; + u8 val, s1val, s0val; + + spin_lock(&card->lock); + s0val = inb(card->base | NJ_IRQSTAT0); + s1val = inb(card->base | NJ_IRQSTAT1); + if ((s1val & NJ_ISACIRQ) && (s0val == 0)) { + /* shared IRQ */ + spin_unlock(&card->lock); + return IRQ_NONE; + } + pr_debug("%s: IRQSTAT0 %02x IRQSTAT1 %02x\n", card->name, s0val, s1val); + card->irqcnt++; + if (!(s1val & NJ_ISACIRQ)) { + val = ReadISAC_nj(card, ISAC_ISTA); + if (val) + mISDNisac_irq(&card->isac, val); + } + + if (s0val) + /* write to clear */ + outb(s0val, card->base | NJ_IRQSTAT0); + else + goto end; + s1val = s0val; + /* set bits in sval to indicate which page is free */ + card->recv.dmacur = inl(card->base | NJ_DMA_WRITE_ADR); + card->recv.idx = (card->recv.dmacur - card->recv.dmastart) >> 2; + if (card->recv.dmacur < card->recv.dmairq) + s0val = 0x08; /* the 2nd write area is free */ + else + s0val = 0x04; /* the 1st write area is free */ + + card->send.dmacur = inl(card->base | NJ_DMA_READ_ADR); + card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2; + if (card->send.dmacur < card->send.dmairq) + s0val |= 0x02; /* the 2nd read area is free */ + else + s0val |= 0x01; /* the 1st read area is free */ + + pr_debug("%s: DMA Status %02x/%02x/%02x %d/%d\n", card->name, + s1val, s0val, card->last_is0, + card->recv.idx, card->send.idx); + /* test if we have a DMA interrupt */ + if (s0val != card->last_is0) { + if ((s0val & NJ_IRQM0_RD_MASK) != + (card->last_is0 & NJ_IRQM0_RD_MASK)) + /* got a write dma int */ + send_tiger(card, s0val); + if ((s0val & NJ_IRQM0_WR_MASK) != + (card->last_is0 & NJ_IRQM0_WR_MASK)) + /* got a read dma int */ + recv_tiger(card, s0val); + } +end: + spin_unlock(&card->lock); + return IRQ_HANDLED; +} + +static int +nj_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) +{ + int ret = -EINVAL; + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch); + struct tiger_hw *card = bch->hw; + struct mISDNhead *hh = mISDN_HEAD_P(skb); + u32 id; + u_long flags; + + switch (hh->prim) { + case PH_DATA_REQ: + spin_lock_irqsave(&card->lock, flags); + ret = bchannel_senddata(bch, skb); + if (ret > 0) { /* direct TX */ + id = hh->id; /* skb can be freed */ + fill_dma(bc); + ret = 0; + spin_unlock_irqrestore(&card->lock, flags); + if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) + queue_ch_frame(ch, PH_DATA_CNF, id, NULL); + } else + spin_unlock_irqrestore(&card->lock, flags); + return ret; + case PH_ACTIVATE_REQ: + spin_lock_irqsave(&card->lock, flags); + if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) + ret = mode_tiger(bc, ch->protocol); + else + ret = 0; + spin_unlock_irqrestore(&card->lock, flags); + if (!ret) + _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_KERNEL); + break; + case PH_DEACTIVATE_REQ: + spin_lock_irqsave(&card->lock, flags); + mISDN_clear_bchannel(bch); + mode_tiger(bc, ISDN_P_NONE); + spin_unlock_irqrestore(&card->lock, flags); + _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_KERNEL); + ret = 0; + break; + } + if (!ret) + dev_kfree_skb(skb); + return ret; +} + +static int +channel_bctrl(struct tiger_ch *bc, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + struct tiger_hw *card = bc->bch.hw; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = 0; + break; + /* Nothing implemented yet */ + case MISDN_CTRL_FILL_EMPTY: + default: + pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +nj_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) +{ + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch); + struct tiger_hw *card = bch->hw; + int ret = -EINVAL; + u_long flags; + + pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg); + switch (cmd) { + case CLOSE_CHANNEL: + test_and_clear_bit(FLG_OPEN, &bch->Flags); + if (test_bit(FLG_ACTIVE, &bch->Flags)) { + spin_lock_irqsave(&card->lock, flags); + mISDN_freebchannel(bch); + test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); + test_and_clear_bit(FLG_ACTIVE, &bch->Flags); + mode_tiger(bc, ISDN_P_NONE); + spin_unlock_irqrestore(&card->lock, flags); + } + ch->protocol = ISDN_P_NONE; + ch->peer = NULL; + module_put(THIS_MODULE); + ret = 0; + break; + case CONTROL_CHANNEL: + ret = channel_bctrl(bc, arg); + break; + default: + pr_info("%s: %s unknown prim(%x)\n", card->name, __func__, cmd); + } + return ret; +} + +static int +channel_ctrl(struct tiger_hw *card, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = MISDN_CTRL_LOOP; + break; + case MISDN_CTRL_LOOP: + /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ + if (cq->channel < 0 || cq->channel > 3) { + ret = -EINVAL; + break; + } + ret = card->isac.ctrl(&card->isac, HW_TESTLOOP, cq->channel); + break; + default: + pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +open_bchannel(struct tiger_hw *card, struct channel_req *rq) +{ + struct bchannel *bch; + + if (rq->adr.channel > 2) + return -EINVAL; + if (rq->protocol == ISDN_P_NONE) + return -EINVAL; + bch = &card->bc[rq->adr.channel - 1].bch; + if (test_and_set_bit(FLG_OPEN, &bch->Flags)) + return -EBUSY; /* b-channel can be only open once */ + test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); + bch->ch.protocol = rq->protocol; + rq->ch = &bch->ch; + return 0; +} + +/* + * device control function + */ +static int +nj_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) +{ + struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); + struct dchannel *dch = container_of(dev, struct dchannel, dev); + struct tiger_hw *card = dch->hw; + struct channel_req *rq; + int err = 0; + + pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg); + switch (cmd) { + case OPEN_CHANNEL: + rq = arg; + if (rq->protocol == ISDN_P_TE_S0) + err = card->isac.open(&card->isac, rq); + else + err = open_bchannel(card, rq); + if (err) + break; + if (!try_module_get(THIS_MODULE)) + pr_info("%s: cannot get module\n", card->name); + break; + case CLOSE_CHANNEL: + pr_debug("%s: dev(%d) close from %p\n", card->name, dch->dev.id, + __builtin_return_address(0)); + module_put(THIS_MODULE); + break; + case CONTROL_CHANNEL: + err = channel_ctrl(card, arg); + break; + default: + pr_debug("%s: %s unknown command %x\n", + card->name, __func__, cmd); + return -EINVAL; + } + return err; +} + +static int +nj_init_card(struct tiger_hw *card) +{ + u_long flags; + int ret; + + spin_lock_irqsave(&card->lock, flags); + nj_disable_hwirq(card); + spin_unlock_irqrestore(&card->lock, flags); + + card->irq = card->pdev->irq; + if (request_irq(card->irq, nj_irq, IRQF_SHARED, card->name, card)) { + pr_info("%s: couldn't get interrupt %d\n", + card->name, card->irq); + card->irq = -1; + return -EIO; + } + + spin_lock_irqsave(&card->lock, flags); + nj_reset(card); + ret = card->isac.init(&card->isac); + if (ret) + goto error; + ret = inittiger(card); + if (ret) + goto error; + mode_tiger(&card->bc[0], ISDN_P_NONE); + mode_tiger(&card->bc[1], ISDN_P_NONE); +error: + spin_unlock_irqrestore(&card->lock, flags); + return ret; +} + + +static void +nj_release(struct tiger_hw *card) +{ + u_long flags; + int i; + + if (card->base_s) { + spin_lock_irqsave(&card->lock, flags); + nj_disable_hwirq(card); + mode_tiger(&card->bc[0], ISDN_P_NONE); + mode_tiger(&card->bc[1], ISDN_P_NONE); + card->isac.release(&card->isac); + spin_unlock_irqrestore(&card->lock, flags); + release_region(card->base, card->base_s); + card->base_s = 0; + } + if (card->irq > 0) + free_irq(card->irq, card); + if (card->isac.dch.dev.dev.class) + mISDN_unregister_device(&card->isac.dch.dev); + + for (i = 0; i < 2; i++) { + mISDN_freebchannel(&card->bc[i].bch); + kfree(card->bc[i].hsbuf); + kfree(card->bc[i].hrbuf); + } + if (card->dma_p) + pci_free_consistent(card->pdev, NJ_DMA_SIZE, + card->dma_p, card->dma); + write_lock_irqsave(&card_lock, flags); + list_del(&card->list); + write_unlock_irqrestore(&card_lock, flags); + pci_clear_master(card->pdev); + pci_disable_device(card->pdev); + pci_set_drvdata(card->pdev, NULL); + kfree(card); +} + + +static int +nj_setup(struct tiger_hw *card) +{ + card->base = pci_resource_start(card->pdev, 0); + card->base_s = pci_resource_len(card->pdev, 0); + if (!request_region(card->base, card->base_s, card->name)) { + pr_info("%s: NETjet config port %#x-%#x already in use\n", + card->name, card->base, + (u32)(card->base + card->base_s - 1)); + card->base_s = 0; + return -EIO; + } + ASSIGN_FUNC(nj, ISAC, card->isac); + return 0; +} + + +static int __devinit +setup_instance(struct tiger_hw *card) +{ + int i, err; + u_long flags; + + snprintf(card->name, MISDN_MAX_IDLEN - 1, "netjet.%d", nj_cnt + 1); + write_lock_irqsave(&card_lock, flags); + list_add_tail(&card->list, &Cards); + write_unlock_irqrestore(&card_lock, flags); + + _set_debug(card); + card->isac.name = card->name; + spin_lock_init(&card->lock); + card->isac.hwlock = &card->lock; + mISDNisac_init(&card->isac, card); + + card->isac.dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | + (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); + card->isac.dch.dev.D.ctrl = nj_dctrl; + for (i = 0; i < 2; i++) { + card->bc[i].bch.nr = i + 1; + set_channelmap(i + 1, card->isac.dch.dev.channelmap); + mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM); + card->bc[i].bch.hw = card; + card->bc[i].bch.ch.send = nj_l2l1B; + card->bc[i].bch.ch.ctrl = nj_bctrl; + card->bc[i].bch.ch.nr = i + 1; + list_add(&card->bc[i].bch.ch.list, + &card->isac.dch.dev.bchannels); + card->bc[i].bch.hw = card; + } + err = nj_setup(card); + if (err) + goto error; + err = mISDN_register_device(&card->isac.dch.dev, &card->pdev->dev, + card->name); + if (err) + goto error; + err = nj_init_card(card); + if (!err) { + nj_cnt++; + pr_notice("Netjet %d cards installed\n", nj_cnt); + return 0; + } +error: + nj_release(card); + return err; +} + +static int __devinit +nj_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int err = -ENOMEM; + int cfg; + struct tiger_hw *card; + + if (pdev->subsystem_vendor == 0x8086 && + pdev->subsystem_device == 0x0003) { + pr_notice("Netjet: Digium X100P/X101P not handled\n"); + return -ENODEV; + } + + if (pdev->subsystem_vendor == 0x55 && + pdev->subsystem_device == 0x02) { + pr_notice("Netjet: Enter!Now not handled yet\n"); + return -ENODEV; + } + + card = kzalloc(sizeof(struct tiger_hw), GFP_ATOMIC); + if (!card) { + pr_info("No kmem for Netjet\n"); + return err; + } + + card->pdev = pdev; + + err = pci_enable_device(pdev); + if (err) { + kfree(card); + return err; + } + + printk(KERN_INFO "nj_probe(mISDN): found adapter at %s\n", + pci_name(pdev)); + + pci_set_master(pdev); + + /* the TJ300 and TJ320 must be detected, the IRQ handling is different + * unfortunately the chips use the same device ID, but the TJ320 has + * the bit20 in status PCI cfg register set + */ + pci_read_config_dword(pdev, 0x04, &cfg); + if (cfg & 0x00100000) + card->typ = NETJET_S_TJ320; + else + card->typ = NETJET_S_TJ300; + + card->base = pci_resource_start(pdev, 0); + card->irq = pdev->irq; + pci_set_drvdata(pdev, card); + err = setup_instance(card); + if (err) + pci_set_drvdata(pdev, NULL); + + return err; +} + + +static void __devexit nj_remove(struct pci_dev *pdev) +{ + struct tiger_hw *card = pci_get_drvdata(pdev); + + if (card) + nj_release(card); + else + pr_info("%s drvdata already removed\n", __func__); +} + +/* We cannot select cards with PCI_SUB... IDs, since here are cards with + * SUB IDs set to PCI_ANY_ID, so we need to match all and reject + * known other cards which not work with this driver - see probe function */ +static struct pci_device_id nj_pci_ids[] __devinitdata = { + { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_300, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { } +}; +MODULE_DEVICE_TABLE(pci, nj_pci_ids); + +static struct pci_driver nj_driver = { + .name = "netjet", + .probe = nj_probe, + .remove = __devexit_p(nj_remove), + .id_table = nj_pci_ids, +}; + +static int __init nj_init(void) +{ + int err; + + pr_notice("Netjet PCI driver Rev. %s\n", NETJET_REV); + err = pci_register_driver(&nj_driver); + return err; +} + +static void __exit nj_cleanup(void) +{ + pci_unregister_driver(&nj_driver); +} + +module_init(nj_init); +module_exit(nj_cleanup); diff --git a/drivers/isdn/hardware/mISDN/netjet.h b/drivers/isdn/hardware/mISDN/netjet.h new file mode 100644 index 00000000000..d061ff99560 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/netjet.h @@ -0,0 +1,58 @@ +/* + * NETjet common header file + * + * Author Karsten Keil + * based on work of Matt Henderson and Daniel Potts, + * Traverse Technologies P/L www.traverse.com.au + * + * Copyright 2009 by Karsten Keil + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#define NJ_CTRL 0x00 +#define NJ_DMACTRL 0x01 +#define NJ_AUXCTRL 0x02 +#define NJ_AUXDATA 0x03 +#define NJ_IRQMASK0 0x04 +#define NJ_IRQMASK1 0x05 +#define NJ_IRQSTAT0 0x06 +#define NJ_IRQSTAT1 0x07 +#define NJ_DMA_READ_START 0x08 +#define NJ_DMA_READ_IRQ 0x0c +#define NJ_DMA_READ_END 0x10 +#define NJ_DMA_READ_ADR 0x14 +#define NJ_DMA_WRITE_START 0x18 +#define NJ_DMA_WRITE_IRQ 0x1c +#define NJ_DMA_WRITE_END 0x20 +#define NJ_DMA_WRITE_ADR 0x24 +#define NJ_PULSE_CNT 0x28 + +#define NJ_ISAC_OFF 0xc0 +#define NJ_ISACIRQ 0x10 + +#define NJ_IRQM0_RD_MASK 0x03 +#define NJ_IRQM0_RD_IRQ 0x01 +#define NJ_IRQM0_RD_END 0x02 +#define NJ_IRQM0_WR_MASK 0x0c +#define NJ_IRQM0_WR_IRQ 0x04 +#define NJ_IRQM0_WR_END 0x08 + +/* one page here is no need to be smaller */ +#define NJ_DMA_SIZE 4096 +/* 2 * 64 byte is a compromise between IRQ count and latency */ +#define NJ_DMA_RXSIZE 128 /* 2 * 64 */ +#define NJ_DMA_TXSIZE 128 /* 2 * 64 */ + -- cgit v1.2.3-18-g5258 From 3cad3da3ed9ece03704f7d67e038b8ae710fa312 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 12 Jul 2009 22:05:03 +0200 Subject: drivers/isdn: Drop unnecessary NULL test The result of container_of should not be NULL. In particular, in this case the argument to the enclosing function has passed though INIT_WORK, which dereferences it, implying that its container cannot be NULL. A simplified version of the semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @@ identifier fn,work,x,fld; type T; expression E1,E2; statement S; @@ static fn(struct work_struct *work) { ... when != work = E1 x = container_of(work,T,fld) ... when != x = E2 - if (x == NULL) S ... } // Signed-off-by: Julia Lawall Signed-off-by: Karsten Keil --- drivers/isdn/hisax/amd7930_fn.c | 2 -- drivers/isdn/hisax/hfc_pci.c | 2 -- drivers/isdn/hisax/hfc_sx.c | 2 -- drivers/isdn/hisax/icc.c | 2 -- drivers/isdn/hisax/isac.c | 2 -- drivers/isdn/hisax/w6692.c | 2 -- 6 files changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c index 341faf58a65..bf526a7a63a 100644 --- a/drivers/isdn/hisax/amd7930_fn.c +++ b/drivers/isdn/hisax/amd7930_fn.c @@ -238,8 +238,6 @@ Amd7930_bh(struct work_struct *work) container_of(work, struct IsdnCardState, tqueue); struct PStack *stptr; - if (!cs) - return; if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { if (cs->debug) debugl1(cs, "Amd7930: bh, D-Channel Busy cleared"); diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index 3d337d924c2..d110a77940a 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -1506,8 +1506,6 @@ hfcpci_bh(struct work_struct *work) u_long flags; // struct PStack *stptr; - if (!cs) - return; if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { if (!cs->hw.hfcpci.nt_mode) switch (cs->dc.hfcpci.ph_state) { diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c index d92e8d6c2ae..419f87cad8c 100644 --- a/drivers/isdn/hisax/hfc_sx.c +++ b/drivers/isdn/hisax/hfc_sx.c @@ -1255,8 +1255,6 @@ hfcsx_bh(struct work_struct *work) container_of(work, struct IsdnCardState, tqueue); u_long flags; - if (!cs) - return; if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { if (!cs->hw.hfcsx.nt_mode) switch (cs->dc.hfcsx.ph_state) { diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c index 682cac32f25..9aba646ba22 100644 --- a/drivers/isdn/hisax/icc.c +++ b/drivers/isdn/hisax/icc.c @@ -83,8 +83,6 @@ icc_bh(struct work_struct *work) container_of(work, struct IsdnCardState, tqueue); struct PStack *stptr; - if (!cs) - return; if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { if (cs->debug) debugl1(cs, "D-Channel Busy cleared"); diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c index 07b1673122b..a19354d9434 100644 --- a/drivers/isdn/hisax/isac.c +++ b/drivers/isdn/hisax/isac.c @@ -86,8 +86,6 @@ isac_bh(struct work_struct *work) container_of(work, struct IsdnCardState, tqueue); struct PStack *stptr; - if (!cs) - return; if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { if (cs->debug) debugl1(cs, "D-Channel Busy cleared"); diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index bb1c8dd1a23..c4d862c11a6 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -105,8 +105,6 @@ W6692_bh(struct work_struct *work) container_of(work, struct IsdnCardState, tqueue); struct PStack *stptr; - if (!cs) - return; if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { if (cs->debug) debugl1(cs, "D-Channel Busy cleared"); -- cgit v1.2.3-18-g5258 From ba2d6ccb1df6ebb2c1b2322518ce7be25c1e3469 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Fri, 24 Jul 2009 18:26:08 +0200 Subject: ISDN: ARRAY_SIZE changes These changes were a direct result of using a semantic patch More information can be found at http://www.emn.fr/x-info/coccinelle/ Modified some of the changes to avoid the extra define. Signed-off-by: Stoyan Gaydarov Signed-off-by: Karsten Keil --- drivers/isdn/act2000/capi.c | 3 +-- drivers/isdn/act2000/module.c | 31 +++++++++++++++---------------- drivers/isdn/hardware/eicon/message.c | 4 +--- drivers/isdn/hardware/eicon/os_4bri.c | 3 +-- drivers/isdn/hisax/callc.c | 4 +--- drivers/isdn/hisax/isdnl1.c | 12 +++--------- drivers/isdn/hisax/isdnl2.c | 4 +--- drivers/isdn/hisax/isdnl3.c | 4 +--- drivers/isdn/hisax/l3_1tr6.c | 20 ++++++-------------- drivers/isdn/hisax/l3dss1.c | 26 ++++++++------------------ drivers/isdn/hisax/l3ni1.c | 26 ++++++++------------------ drivers/isdn/hisax/q931.c | 24 ++++++++++++------------ drivers/isdn/hisax/tei.c | 4 +--- drivers/isdn/mISDN/layer2.c | 2 -- 14 files changed, 59 insertions(+), 108 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/act2000/capi.c b/drivers/isdn/act2000/capi.c index 946c38cf6f8..1f0a9490646 100644 --- a/drivers/isdn/act2000/capi.c +++ b/drivers/isdn/act2000/capi.c @@ -78,7 +78,6 @@ static actcapi_msgdsc valid_msg[] = { #endif {{ 0x00, 0x00}, NULL}, }; -#define num_valid_msg (sizeof(valid_msg)/sizeof(actcapi_msgdsc)) #define num_valid_imsg 27 /* MANUFACTURER_IND */ /* @@ -1025,7 +1024,7 @@ actcapi_debug_msg(struct sk_buff *skb, int direction) #ifdef DEBUG_DUMP_SKB dump_skb(skb); #endif - for (i = 0; i < num_valid_msg; i++) + for (i = 0; i < ARRAY_SIZE(valid_msg); i++) if ((msg->hdr.cmd.cmd == valid_msg[i].cmd.cmd) && (msg->hdr.cmd.subcmd == valid_msg[i].cmd.subcmd)) { descr = valid_msg[i].description; diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c index 8325022e2be..f774e12bb64 100644 --- a/drivers/isdn/act2000/module.c +++ b/drivers/isdn/act2000/module.c @@ -23,7 +23,6 @@ static unsigned short act2000_isa_ports[] = 0x0200, 0x0240, 0x0280, 0x02c0, 0x0300, 0x0340, 0x0380, 0xcfe0, 0xcfa0, 0xcf60, 0xcf20, 0xcee0, 0xcea0, 0xce60, }; -#define ISA_NRPORTS (sizeof(act2000_isa_ports)/sizeof(unsigned short)) static act2000_card *cards = (act2000_card *) NULL; @@ -686,21 +685,21 @@ act2000_addcard(int bus, int port, int irq, char *id) * This may result in more than one card detected. */ switch (bus) { - case ACT2000_BUS_ISA: - for (i = 0; i < ISA_NRPORTS; i++) - if (act2000_isa_detect(act2000_isa_ports[i])) { - printk(KERN_INFO - "act2000: Detected ISA card at port 0x%x\n", - act2000_isa_ports[i]); - act2000_alloccard(bus, act2000_isa_ports[i], irq, id); - } - break; - case ACT2000_BUS_MCA: - case ACT2000_BUS_PCMCIA: - default: - printk(KERN_WARNING - "act2000: addcard: Invalid BUS type %d\n", - bus); + case ACT2000_BUS_ISA: + for (i = 0; i < ARRAY_SIZE(act2000_isa_ports); i++) + if (act2000_isa_detect(act2000_isa_ports[i])) { + printk(KERN_INFO "act2000: Detected " + "ISA card at port 0x%x\n", + act2000_isa_ports[i]); + act2000_alloccard(bus, + act2000_isa_ports[i], irq, id); + } + break; + case ACT2000_BUS_MCA: + case ACT2000_BUS_PCMCIA: + default: + printk(KERN_WARNING + "act2000: addcard: Invalid BUS type %d\n", bus); } } if (!cards) diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c index 31f91c18c69..27d5dd68f4f 100644 --- a/drivers/isdn/hardware/eicon/message.c +++ b/drivers/isdn/hardware/eicon/message.c @@ -551,9 +551,7 @@ word api_put(APPL * appl, CAPI_MSG * msg) dbug(1,dprintf("com=%x",msg->header.command)); for(j=0;jheader.command) { /* break loop if the message is correct, otherwise continue scan */ diff --git a/drivers/isdn/hardware/eicon/os_4bri.c b/drivers/isdn/hardware/eicon/os_4bri.c index c964b8d91ad..cb7616c5b60 100644 --- a/drivers/isdn/hardware/eicon/os_4bri.c +++ b/drivers/isdn/hardware/eicon/os_4bri.c @@ -149,8 +149,7 @@ int diva_4bri_init_card(diva_os_xdi_adapter_t * a) diva_os_xdi_adapter_t *diva_current; diva_os_xdi_adapter_t *adapter_list[4]; PISDN_ADAPTER Slave; - unsigned long bar_length[sizeof(_4bri_bar_length) / - sizeof(_4bri_bar_length[0])]; + unsigned long bar_length[ARRAY_SIZE(_4bri_bar_length)]; int v2 = _4bri_is_rev_2_card(a->CardOrdinal); int tasks = _4bri_is_rev_2_bri_card(a->CardOrdinal) ? 1 : MQ_INSTANCE_COUNT; int factor = (tasks == 1) ? 1 : 2; diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c index 025a20d487c..475b1a02000 100644 --- a/drivers/isdn/hisax/callc.c +++ b/drivers/isdn/hisax/callc.c @@ -833,8 +833,6 @@ static struct FsmNode fnlist[] __initdata = }; /* *INDENT-ON* */ -#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode)) - int __init CallcNew(void) { @@ -842,7 +840,7 @@ CallcNew(void) callcfsm.event_count = EVENT_COUNT; callcfsm.strEvent = strEvent; callcfsm.strState = strState; - return FsmNew(&callcfsm, fnlist, FNCOUNT); + return FsmNew(&callcfsm, fnlist, ARRAY_SIZE(fnlist)); } void diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c index 317f16f516f..9ce6abe05b1 100644 --- a/drivers/isdn/hisax/isdnl1.c +++ b/drivers/isdn/hisax/isdnl1.c @@ -647,8 +647,6 @@ static struct FsmNode L1SFnList[] __initdata = {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact}, }; -#define L1S_FN_COUNT (sizeof(L1SFnList)/sizeof(struct FsmNode)) - #ifdef HISAX_UINTERFACE static void l1_deact_req_u(struct FsmInst *fi, int event, void *arg) @@ -706,8 +704,6 @@ static struct FsmNode L1UFnList[] __initdata = {ST_L1_RESET, EV_TIMER_DEACT, l1_timer_deact}, }; -#define L1U_FN_COUNT (sizeof(L1UFnList)/sizeof(struct FsmNode)) - #endif static void @@ -754,8 +750,6 @@ static struct FsmNode L1BFnList[] __initdata = {ST_L1_WAIT_DEACT, EV_TIMER_DEACT, l1b_timer_deact}, }; -#define L1B_FN_COUNT (sizeof(L1BFnList)/sizeof(struct FsmNode)) - int __init Isdnl1New(void) { @@ -765,7 +759,7 @@ Isdnl1New(void) l1fsm_s.event_count = L1_EVENT_COUNT; l1fsm_s.strEvent = strL1Event; l1fsm_s.strState = strL1SState; - retval = FsmNew(&l1fsm_s, L1SFnList, L1S_FN_COUNT); + retval = FsmNew(&l1fsm_s, L1SFnList, ARRAY_SIZE(L1SFnList)); if (retval) return retval; @@ -773,7 +767,7 @@ Isdnl1New(void) l1fsm_b.event_count = L1_EVENT_COUNT; l1fsm_b.strEvent = strL1Event; l1fsm_b.strState = strL1BState; - retval = FsmNew(&l1fsm_b, L1BFnList, L1B_FN_COUNT); + retval = FsmNew(&l1fsm_b, L1BFnList, ARRAY_SIZE(L1BFnList)); if (retval) { FsmFree(&l1fsm_s); return retval; @@ -783,7 +777,7 @@ Isdnl1New(void) l1fsm_u.event_count = L1_EVENT_COUNT; l1fsm_u.strEvent = strL1Event; l1fsm_u.strState = strL1UState; - retval = FsmNew(&l1fsm_u, L1UFnList, L1U_FN_COUNT); + retval = FsmNew(&l1fsm_u, L1UFnList, ARRAY_SIZE(L1UFnList)); if (retval) { FsmFree(&l1fsm_s); FsmFree(&l1fsm_b); diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c index 3446f249d67..7b9496a63b5 100644 --- a/drivers/isdn/hisax/isdnl2.c +++ b/drivers/isdn/hisax/isdnl2.c @@ -1623,8 +1623,6 @@ static struct FsmNode L2FnList[] __initdata = {ST_L2_8, EV_L1_DEACTIVATE, l2_persistent_da}, }; -#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode)) - static void isdnl2_l1l2(struct PStack *st, int pr, void *arg) { @@ -1836,7 +1834,7 @@ Isdnl2New(void) l2fsm.event_count = L2_EVENT_COUNT; l2fsm.strEvent = strL2Event; l2fsm.strState = strL2State; - return FsmNew(&l2fsm, L2FnList, L2_FN_COUNT); + return FsmNew(&l2fsm, L2FnList, ARRAY_SIZE(L2FnList)); } void diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c index 935f23356fa..06766022d3a 100644 --- a/drivers/isdn/hisax/isdnl3.c +++ b/drivers/isdn/hisax/isdnl3.c @@ -543,8 +543,6 @@ static struct FsmNode L3FnList[] __initdata = }; /* *INDENT-ON* */ -#define L3_FN_COUNT (sizeof(L3FnList)/sizeof(struct FsmNode)) - void l3_msg(struct PStack *st, int pr, void *arg) { @@ -587,7 +585,7 @@ Isdnl3New(void) l3fsm.event_count = L3_EVENT_COUNT; l3fsm.strEvent = strL3Event; l3fsm.strState = strL3State; - return FsmNew(&l3fsm, L3FnList, L3_FN_COUNT); + return FsmNew(&l3fsm, L3FnList, ARRAY_SIZE(L3FnList)); } void diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c index c5c36eeff26..b0554f80bfb 100644 --- a/drivers/isdn/hisax/l3_1tr6.c +++ b/drivers/isdn/hisax/l3_1tr6.c @@ -698,9 +698,6 @@ static struct stateentry downstl[] = CC_T308_2, l3_1tr6_t308_2}, }; -#define DOWNSTL_LEN \ - (sizeof(downstl) / sizeof(struct stateentry)) - static struct stateentry datastln1[] = { {SBIT(0), @@ -735,9 +732,6 @@ static struct stateentry datastln1[] = MT_N1_REL_ACK, l3_1tr6_rel_ack} }; -#define DATASTLN1_LEN \ - (sizeof(datastln1) / sizeof(struct stateentry)) - static struct stateentry manstatelist[] = { {SBIT(2), @@ -746,8 +740,6 @@ static struct stateentry manstatelist[] = DL_RELEASE | INDICATION, l3_1tr6_dl_release}, }; -#define MANSLLEN \ - (sizeof(manstatelist) / sizeof(struct stateentry)) /* *INDENT-ON* */ static void @@ -840,11 +832,11 @@ up1tr6(struct PStack *st, int pr, void *arg) mt = MT_N1_INVALID; } } - for (i = 0; i < DATASTLN1_LEN; i++) + for (i = 0; i < ARRAY_SIZE(datastln1); i++) if ((mt == datastln1[i].primitive) && ((1 << proc->state) & datastln1[i].state)) break; - if (i == DATASTLN1_LEN) { + if (i == ARRAY_SIZE(datastln1)) { dev_kfree_skb(skb); if (st->l3.debug & L3_DEB_STATE) { sprintf(tmp, "up1tr6%sstate %d mt %x unhandled", @@ -892,11 +884,11 @@ down1tr6(struct PStack *st, int pr, void *arg) proc = arg; } - for (i = 0; i < DOWNSTL_LEN; i++) + for (i = 0; i < ARRAY_SIZE(downstl); i++) if ((pr == downstl[i].primitive) && ((1 << proc->state) & downstl[i].state)) break; - if (i == DOWNSTL_LEN) { + if (i == ARRAY_SIZE(downstl)) { if (st->l3.debug & L3_DEB_STATE) { sprintf(tmp, "down1tr6 state %d prim %d unhandled", proc->state, pr); @@ -922,11 +914,11 @@ man1tr6(struct PStack *st, int pr, void *arg) printk(KERN_ERR "HiSax man1tr6 without proc pr=%04x\n", pr); return; } - for (i = 0; i < MANSLLEN; i++) + for (i = 0; i < ARRAY_SIZE(manstatelist); i++) if ((pr == manstatelist[i].primitive) && ((1 << proc->state) & manstatelist[i].state)) break; - if (i == MANSLLEN) { + if (i == ARRAY_SIZE(manstatelist)) { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "cr %d man1tr6 state %d prim %d unhandled", proc->callref & 0x7f, proc->state, pr); diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c index 99feae8b921..a12fa4d3490 100644 --- a/drivers/isdn/hisax/l3dss1.c +++ b/drivers/isdn/hisax/l3dss1.c @@ -2820,9 +2820,6 @@ static struct stateentry downstatelist[] = CC_T309, l3dss1_dl_release}, }; -#define DOWNSLLEN \ - (sizeof(downstatelist) / sizeof(struct stateentry)) - static struct stateentry datastatelist[] = { {ALL_STATES, @@ -2875,9 +2872,6 @@ static struct stateentry datastatelist[] = MT_RESUME_REJECT, l3dss1_resume_rej}, }; -#define DATASLLEN \ - (sizeof(datastatelist) / sizeof(struct stateentry)) - static struct stateentry globalmes_list[] = { {ALL_STATES, @@ -2888,8 +2882,6 @@ static struct stateentry globalmes_list[] = MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack}, */ }; -#define GLOBALM_LEN \ - (sizeof(globalmes_list) / sizeof(struct stateentry)) static struct stateentry manstatelist[] = { @@ -2903,8 +2895,6 @@ static struct stateentry manstatelist[] = DL_RELEASE | INDICATION, l3dss1_dl_release}, }; -#define MANSLLEN \ - (sizeof(manstatelist) / sizeof(struct stateentry)) /* *INDENT-ON* */ @@ -2918,11 +2908,11 @@ global_handler(struct PStack *st, int mt, struct sk_buff *skb) struct l3_process *proc = st->l3.global; proc->callref = skb->data[2]; /* cr flag */ - for (i = 0; i < GLOBALM_LEN; i++) + for (i = 0; i < ARRAY_SIZE(globalmes_list); i++) if ((mt == globalmes_list[i].primitive) && ((1 << proc->state) & globalmes_list[i].state)) break; - if (i == GLOBALM_LEN) { + if (i == ARRAY_SIZE(globalmes_list)) { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "dss1 global state %d mt %x unhandled", proc->state, mt); @@ -3097,11 +3087,11 @@ dss1up(struct PStack *st, int pr, void *arg) } if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL) l3dss1_deliver_display(proc, pr, p); /* Display IE included */ - for (i = 0; i < DATASLLEN; i++) + for (i = 0; i < ARRAY_SIZE(datastatelist); i++) if ((mt == datastatelist[i].primitive) && ((1 << proc->state) & datastatelist[i].state)) break; - if (i == DATASLLEN) { + if (i == ARRAY_SIZE(datastatelist)) { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "dss1up%sstate %d mt %#x unhandled", (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", @@ -3156,11 +3146,11 @@ dss1down(struct PStack *st, int pr, void *arg) return; } - for (i = 0; i < DOWNSLLEN; i++) + for (i = 0; i < ARRAY_SIZE(downstatelist); i++) if ((pr == downstatelist[i].primitive) && ((1 << proc->state) & downstatelist[i].state)) break; - if (i == DOWNSLLEN) { + if (i == ARRAY_SIZE(downstatelist)) { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "dss1down state %d prim %#x unhandled", proc->state, pr); @@ -3184,11 +3174,11 @@ dss1man(struct PStack *st, int pr, void *arg) printk(KERN_ERR "HiSax dss1man without proc pr=%04x\n", pr); return; } - for (i = 0; i < MANSLLEN; i++) + for (i = 0; i < ARRAY_SIZE(manstatelist); i++) if ((pr == manstatelist[i].primitive) && ((1 << proc->state) & manstatelist[i].state)) break; - if (i == MANSLLEN) { + if (i == ARRAY_SIZE(manstatelist)) { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "cr %d dss1man state %d prim %#x unhandled", proc->callref & 0x7f, proc->state, pr); diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c index f7041d5ba64..4622d43c7e1 100644 --- a/drivers/isdn/hisax/l3ni1.c +++ b/drivers/isdn/hisax/l3ni1.c @@ -2755,9 +2755,6 @@ static struct stateentry downstatelist[] = CC_TSPID, l3ni1_spid_tout }, }; -#define DOWNSLLEN \ - (sizeof(downstatelist) / sizeof(struct stateentry)) - static struct stateentry datastatelist[] = { {ALL_STATES, @@ -2810,9 +2807,6 @@ static struct stateentry datastatelist[] = MT_RESUME_REJECT, l3ni1_resume_rej}, }; -#define DATASLLEN \ - (sizeof(datastatelist) / sizeof(struct stateentry)) - static struct stateentry globalmes_list[] = { {ALL_STATES, @@ -2825,8 +2819,6 @@ static struct stateentry globalmes_list[] = { SBIT( 0 ), MT_DL_ESTABLISHED, l3ni1_spid_send }, { SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ), MT_INFORMATION, l3ni1_spid_epid }, }; -#define GLOBALM_LEN \ - (sizeof(globalmes_list) / sizeof(struct stateentry)) static struct stateentry manstatelist[] = { @@ -2840,8 +2832,6 @@ static struct stateentry manstatelist[] = DL_RELEASE | INDICATION, l3ni1_dl_release}, }; -#define MANSLLEN \ - (sizeof(manstatelist) / sizeof(struct stateentry)) /* *INDENT-ON* */ @@ -2858,11 +2848,11 @@ global_handler(struct PStack *st, int mt, struct sk_buff *skb) proc->callref = skb->data[2]; /* cr flag */ else proc->callref = 0; - for (i = 0; i < GLOBALM_LEN; i++) + for (i = 0; i < ARRAY_SIZE(globalmes_list); i++) if ((mt == globalmes_list[i].primitive) && ((1 << proc->state) & globalmes_list[i].state)) break; - if (i == GLOBALM_LEN) { + if (i == ARRAY_SIZE(globalmes_list)) { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "ni1 global state %d mt %x unhandled", proc->state, mt); @@ -3049,11 +3039,11 @@ ni1up(struct PStack *st, int pr, void *arg) } if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL) l3ni1_deliver_display(proc, pr, p); /* Display IE included */ - for (i = 0; i < DATASLLEN; i++) + for (i = 0; i < ARRAY_SIZE(datastatelist); i++) if ((mt == datastatelist[i].primitive) && ((1 << proc->state) & datastatelist[i].state)) break; - if (i == DATASLLEN) { + if (i == ARRAY_SIZE(datastatelist)) { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "ni1up%sstate %d mt %#x unhandled", (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", @@ -3108,11 +3098,11 @@ ni1down(struct PStack *st, int pr, void *arg) return; } - for (i = 0; i < DOWNSLLEN; i++) + for (i = 0; i < ARRAY_SIZE(downstatelist); i++) if ((pr == downstatelist[i].primitive) && ((1 << proc->state) & downstatelist[i].state)) break; - if (i == DOWNSLLEN) { + if (i == ARRAY_SIZE(downstatelist)) { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "ni1down state %d prim %#x unhandled", proc->state, pr); @@ -3136,11 +3126,11 @@ ni1man(struct PStack *st, int pr, void *arg) printk(KERN_ERR "HiSax ni1man without proc pr=%04x\n", pr); return; } - for (i = 0; i < MANSLLEN; i++) + for (i = 0; i < ARRAY_SIZE(manstatelist); i++) if ((pr == manstatelist[i].primitive) && ((1 << proc->state) & manstatelist[i].state)) break; - if (i == MANSLLEN) { + if (i == ARRAY_SIZE(manstatelist)) { if (st->l3.debug & L3_DEB_STATE) { l3_debug(st, "cr %d ni1man state %d prim %#x unhandled", proc->callref & 0x7f, proc->state, pr); diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c index aacbf0d14b6..8b853d58e82 100644 --- a/drivers/isdn/hisax/q931.c +++ b/drivers/isdn/hisax/q931.c @@ -140,7 +140,7 @@ struct MessageType { } }; -#define MTSIZE sizeof(mtlist)/sizeof(struct MessageType) +#define MTSIZE ARRAY_SIZE(mtlist) static struct MessageType mt_n0[] = @@ -157,7 +157,7 @@ struct MessageType mt_n0[] = {MT_N0_CLO_ACK, "CLOse ACKnowledge"} }; -#define MT_N0_LEN (sizeof(mt_n0) / sizeof(struct MessageType)) +#define MT_N0_LEN ARRAY_SIZE(mt_n0) static struct MessageType mt_n1[] = @@ -194,7 +194,7 @@ struct MessageType mt_n1[] = {MT_N1_STAT, "STATus"} }; -#define MT_N1_LEN (sizeof(mt_n1) / sizeof(struct MessageType)) +#define MT_N1_LEN ARRAY_SIZE(mt_n1) static int @@ -438,7 +438,7 @@ struct CauseValue { }, }; -#define CVSIZE sizeof(cvlist)/sizeof(struct CauseValue) +#define CVSIZE ARRAY_SIZE(cvlist) static int @@ -516,7 +516,7 @@ struct MessageType cause_1tr6[] = {CAUSE_UserInfoDiscarded, "User Info Discarded"} }; -static int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType)); +static int cause_1tr6_len = ARRAY_SIZE(cause_1tr6); static int prcause_1tr6(char *dest, u_char * p) @@ -865,7 +865,7 @@ struct DTag { /* Display tags */ { 0x96, "Redirection name" }, { 0x9e, "Text" }, }; -#define DTAGSIZE sizeof(dtaglist)/sizeof(struct DTag) +#define DTAGSIZE ARRAY_SIZE(dtaglist) static int disptext_ni1(char *dest, u_char * p) @@ -1074,7 +1074,7 @@ struct InformationElement { }; -#define IESIZE sizeof(ielist)/sizeof(struct InformationElement) +#define IESIZE ARRAY_SIZE(ielist) static struct InformationElement ielist_ni1[] = { @@ -1102,7 +1102,7 @@ struct InformationElement ielist_ni1[] = { }; -#define IESIZE_NI1 sizeof(ielist_ni1)/sizeof(struct InformationElement) +#define IESIZE_NI1 ARRAY_SIZE(ielist_ni1) static struct InformationElement ielist_ni1_cs5[] = { @@ -1110,14 +1110,14 @@ struct InformationElement ielist_ni1_cs5[] = { { 0x2a, "Display text", disptext_ni1 }, }; -#define IESIZE_NI1_CS5 sizeof(ielist_ni1_cs5)/sizeof(struct InformationElement) +#define IESIZE_NI1_CS5 ARRAY_SIZE(ielist_ni1_cs5) static struct InformationElement ielist_ni1_cs6[] = { { 0x7b, "Call appearance", general_ni1 }, }; -#define IESIZE_NI1_CS6 sizeof(ielist_ni1_cs6)/sizeof(struct InformationElement) +#define IESIZE_NI1_CS6 ARRAY_SIZE(ielist_ni1_cs6) static struct InformationElement we_0[] = { @@ -1133,7 +1133,7 @@ static struct InformationElement we_0[] = {WE0_userInfo, "User Info", general} }; -#define WE_0_LEN (sizeof(we_0) / sizeof(struct InformationElement)) +#define WE_0_LEN ARRAY_SIZE(we_0) static struct InformationElement we_6[] = { @@ -1145,7 +1145,7 @@ static struct InformationElement we_6[] = {WE6_statusCalled, "Status Called", general}, {WE6_addTransAttr, "Additional Transmission Attributes", general} }; -#define WE_6_LEN (sizeof(we_6) / sizeof(struct InformationElement)) +#define WE_6_LEN ARRAY_SIZE(we_6) int QuickHex(char *txt, u_char * p, int cnt) diff --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c index ceb0df92fd3..6e65424f1f0 100644 --- a/drivers/isdn/hisax/tei.c +++ b/drivers/isdn/hisax/tei.c @@ -447,8 +447,6 @@ static struct FsmNode TeiFnList[] __initdata = {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req}, }; -#define TEI_FN_COUNT (sizeof(TeiFnList)/sizeof(struct FsmNode)) - int __init TeiNew(void) { @@ -456,7 +454,7 @@ TeiNew(void) teifsm.event_count = TEI_EVENT_COUNT; teifsm.strEvent = strTeiEvent; teifsm.strState = strTeiState; - return FsmNew(&teifsm, TeiFnList, TEI_FN_COUNT); + return FsmNew(&teifsm, TeiFnList, ARRAY_SIZE(TeiFnList)); } void diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c index 9c2589e986d..e17f0044e0b 100644 --- a/drivers/isdn/mISDN/layer2.c +++ b/drivers/isdn/mISDN/layer2.c @@ -1832,8 +1832,6 @@ static struct FsmNode L2FnList[] = {ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da}, }; -#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode)) - static int ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) { -- cgit v1.2.3-18-g5258 From f70e75e11069edfbe55be06960854c46860da0a3 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Fri, 24 Jul 2009 18:41:23 +0200 Subject: mISDN: hfcmulti display real PCI ids for not supported cards In the PCI probe function struct pci_device_id points to the matched entry of the ID table, but for devices which are matched with PCI_ANY_ID sub IDs we want display the IDs of the device itself. Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/hfcmulti.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index fd77bb15d79..faed794cf75 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -5370,9 +5370,10 @@ hfcmulti_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ent->device == PCI_DEVICE_ID_CCD_HFC8S || ent->device == PCI_DEVICE_ID_CCD_HFCE1)) { printk(KERN_ERR - "Unknown HFC multiport controller (vendor:%x device:%x " - "subvendor:%x subdevice:%x)\n", ent->vendor, ent->device, - ent->subvendor, ent->subdevice); + "Unknown HFC multiport controller (vendor:%04x device:%04x " + "subvendor:%04x subdevice:%04x)\n", pdev->vendor, + pdev->device, pdev->subsystem_vendor, + pdev->subsystem_device); printk(KERN_ERR "Please contact the driver maintainer for support.\n"); return -ENODEV; -- cgit v1.2.3-18-g5258 From dcc3ae9a5252ea4ffe65b43cdc09ec2654b48000 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:07:20 +0000 Subject: igb: remove media type fiber as it is misleading The current igb driver only supports copper and serdes. The fiber media type is a holdover from earlier NICs as the current nics supported by igb all use serdes when communicating over a fiber connection. As a result we can remove media type fiber without losing any functionality. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/e1000_82575.c | 3 +-- drivers/net/igb/e1000_hw.h | 3 +-- drivers/net/igb/e1000_mac.c | 37 +++++++++++-------------------------- drivers/net/igb/igb_ethtool.c | 25 +++++++++---------------- drivers/net/igb/igb_main.c | 12 ------------ 5 files changed, 22 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index ac28dd5a4fd..bd3efdb95c6 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -867,8 +867,7 @@ void igb_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw) u32 reg; if (hw->mac.type != e1000_82576 || - (hw->phy.media_type != e1000_media_type_fiber && - hw->phy.media_type != e1000_media_type_internal_serdes)) + hw->phy.media_type != e1000_media_type_internal_serdes) return; /* if the management interface is not enabled, then power down */ diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h index 68aac20c31c..f096ddd8429 100644 --- a/drivers/net/igb/e1000_hw.h +++ b/drivers/net/igb/e1000_hw.h @@ -61,8 +61,7 @@ enum e1000_mac_type { enum e1000_media_type { e1000_media_type_unknown = 0, e1000_media_type_copper = 1, - e1000_media_type_fiber = 2, - e1000_media_type_internal_serdes = 3, + e1000_media_type_internal_serdes = 2, e1000_num_media_types }; diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index 472f3f12484..37706d9981e 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -713,8 +713,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) * configuration of the MAC to match the "fc" parameter. */ if (mac->autoneg_failed) { - if (hw->phy.media_type == e1000_media_type_fiber || - hw->phy.media_type == e1000_media_type_internal_serdes) + if (hw->phy.media_type == e1000_media_type_internal_serdes) ret_val = igb_force_mac_fc(hw); } else { if (hw->phy.media_type == e1000_media_type_copper) @@ -1161,22 +1160,16 @@ s32 igb_blink_led(struct e1000_hw *hw) u32 ledctl_blink = 0; u32 i; - if (hw->phy.media_type == e1000_media_type_fiber) { - /* always blink LED0 for PCI-E fiber */ - ledctl_blink = E1000_LEDCTL_LED0_BLINK | - (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT); - } else { - /* - * set the blink bit for each LED that's "on" (0x0E) - * in ledctl_mode2 - */ - ledctl_blink = hw->mac.ledctl_mode2; - for (i = 0; i < 4; i++) - if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) == - E1000_LEDCTL_MODE_LED_ON) - ledctl_blink |= (E1000_LEDCTL_LED0_BLINK << - (i * 8)); - } + /* + * set the blink bit for each LED that's "on" (0x0E) + * in ledctl_mode2 + */ + ledctl_blink = hw->mac.ledctl_mode2; + for (i = 0; i < 4; i++) + if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) == + E1000_LEDCTL_MODE_LED_ON) + ledctl_blink |= (E1000_LEDCTL_LED0_BLINK << + (i * 8)); wr32(E1000_LEDCTL, ledctl_blink); @@ -1191,15 +1184,7 @@ s32 igb_blink_led(struct e1000_hw *hw) **/ s32 igb_led_off(struct e1000_hw *hw) { - u32 ctrl; - switch (hw->phy.media_type) { - case e1000_media_type_fiber: - ctrl = rd32(E1000_CTRL); - ctrl |= E1000_CTRL_SWDPIN0; - ctrl |= E1000_CTRL_SWDPIO0; - wr32(E1000_CTRL, ctrl); - break; case e1000_media_type_copper: wr32(E1000_LEDCTL, hw->mac.ledctl_mode1); break; diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 9598ac09f4b..a9c37cb1bd7 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -168,8 +168,7 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ecmd->duplex = -1; } - ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) || - hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE; + ecmd->autoneg = hw->mac.autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE; return 0; } @@ -191,23 +190,18 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) if (ecmd->autoneg == AUTONEG_ENABLE) { hw->mac.autoneg = 1; - if (hw->phy.media_type == e1000_media_type_fiber) - hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full | - ADVERTISED_FIBRE | - ADVERTISED_Autoneg; - else - hw->phy.autoneg_advertised = ecmd->advertising | - ADVERTISED_TP | - ADVERTISED_Autoneg; + hw->phy.autoneg_advertised = ecmd->advertising | + ADVERTISED_TP | + ADVERTISED_Autoneg; ecmd->advertising = hw->phy.autoneg_advertised; - } else + } else { if (igb_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { clear_bit(__IGB_RESETTING, &adapter->state); return -EINVAL; } + } /* reset the link */ - if (netif_running(adapter->netdev)) { igb_down(adapter); igb_up(adapter); @@ -267,8 +261,8 @@ static int igb_set_pauseparam(struct net_device *netdev, } else igb_reset(adapter); } else - retval = ((hw->phy.media_type == e1000_media_type_fiber) ? - igb_setup_link(hw) : igb_force_mac_fc(hw)); + retval = ((hw->phy.media_type == e1000_media_type_copper) ? + igb_force_mac_fc(hw) : igb_setup_link(hw)); clear_bit(__IGB_RESETTING, &adapter->state); return retval; @@ -1483,8 +1477,7 @@ static int igb_setup_loopback_test(struct igb_adapter *adapter) struct e1000_hw *hw = &adapter->hw; u32 reg; - if (hw->phy.media_type == e1000_media_type_fiber || - hw->phy.media_type == e1000_media_type_internal_serdes) { + if (hw->phy.media_type == e1000_media_type_internal_serdes) { reg = rd32(E1000_RCTL); reg |= E1000_RCTL_LBM_TCVR; wr32(E1000_RCTL, reg); diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index adb09d32625..39b3b6aa650 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -2618,10 +2618,6 @@ static bool igb_has_link(struct igb_adapter *adapter) link_active = true; } break; - case e1000_media_type_fiber: - ret_val = hw->mac.ops.check_for_link(hw); - link_active = !!(rd32(E1000_STATUS) & E1000_STATUS_LU); - break; case e1000_media_type_internal_serdes: ret_val = hw->mac.ops.check_for_link(hw); link_active = hw->mac.serdes_has_link; @@ -5136,14 +5132,6 @@ int igb_set_spd_dplx(struct igb_adapter *adapter, u16 spddplx) mac->autoneg = 0; - /* Fiber NICs only allow 1000 gbps Full duplex */ - if ((adapter->hw.phy.media_type == e1000_media_type_fiber) && - spddplx != (SPEED_1000 + DUPLEX_FULL)) { - dev_err(&adapter->pdev->dev, - "Unsupported Speed/Duplex configuration\n"); - return -EINVAL; - } - switch (spddplx) { case SPEED_10 + DUPLEX_HALF: mac->forced_speed_duplex = ADVERTISE_10_HALF; -- cgit v1.2.3-18-g5258 From 099e1cb700da6359b784ac7fb65099091b7b961e Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:07:40 +0000 Subject: igb: make serdes power down available for 82575 in addition to 82576 parts There was a serdes power down workaround that was originally added for 82576 fiber. However it has also been found that this workaround is needed for serdes connections as well. In addition it is also needed for 82575 serdes so we we need to remove the checks restricting it to 82576. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/e1000_82575.c | 7 +------ drivers/net/igb/e1000_82575.h | 5 +++++ drivers/net/igb/e1000_mac.c | 14 +++++++++++--- 3 files changed, 17 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index bd3efdb95c6..fa4a76299e0 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -866,8 +866,7 @@ void igb_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw) { u32 reg; - if (hw->mac.type != e1000_82576 || - hw->phy.media_type != e1000_media_type_internal_serdes) + if (hw->phy.media_type != e1000_media_type_internal_serdes) return; /* if the management interface is not enabled, then power down */ @@ -1228,10 +1227,6 @@ out: static bool igb_sgmii_active_82575(struct e1000_hw *hw) { struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575; - - if (hw->mac.type != e1000_82575 && hw->mac.type != e1000_82576) - return false; - return dev_spec->sgmii_active; } diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h index 0f16abab256..b674417ae06 100644 --- a/drivers/net/igb/e1000_82575.h +++ b/drivers/net/igb/e1000_82575.h @@ -32,6 +32,11 @@ void igb_update_mc_addr_list(struct e1000_hw*, u8*, u32, u32, u32); extern void igb_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw); extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw); +#define ID_LED_DEFAULT_82575_SERDES ((ID_LED_DEF1_DEF2 << 12) | \ + (ID_LED_DEF1_DEF2 << 8) | \ + (ID_LED_DEF1_DEF2 << 4) | \ + (ID_LED_OFF1_ON2)) + #define E1000_RAR_ENTRIES_82575 16 #define E1000_RAR_ENTRIES_82576 24 diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index 37706d9981e..34f1a370b06 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -1064,9 +1064,17 @@ static s32 igb_valid_led_default(struct e1000_hw *hw, u16 *data) goto out; } - if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) - *data = ID_LED_DEFAULT; - + if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) { + switch(hw->phy.media_type) { + case e1000_media_type_internal_serdes: + *data = ID_LED_DEFAULT_82575_SERDES; + break; + case e1000_media_type_copper: + default: + *data = ID_LED_DEFAULT; + break; + } + } out: return ret_val; } -- cgit v1.2.3-18-g5258 From f3e7841ca3608db6e0207cd8af5561f065882517 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:07:58 +0000 Subject: igb: change configure_pcs_link to void since it always returns 0 Since igb_configure_pcs_link always returns 0 there isn't really much point to checking for the result so it is best just to change this to a void so we can properly ignore the return result. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/e1000_82575.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index fa4a76299e0..f946bed66c7 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -53,7 +53,7 @@ static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *); static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *, u32, u16); static void igb_clear_hw_cntrs_82575(struct e1000_hw *); static s32 igb_acquire_swfw_sync_82575(struct e1000_hw *, u16); -static s32 igb_configure_pcs_link_82575(struct e1000_hw *); +static void igb_configure_pcs_link_82575(struct e1000_hw *); static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *, u16 *, u16 *); static s32 igb_get_phy_id_82575(struct e1000_hw *); @@ -1050,9 +1050,7 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw) } } - ret_val = igb_configure_pcs_link_82575(hw); - if (ret_val) - goto out; + igb_configure_pcs_link_82575(hw); /* * Check link status. Wait up to 100 microseconds for link to become @@ -1161,14 +1159,14 @@ static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *hw) * independent interface (sgmii) is being used. Configures the link * for auto-negotiation or forces speed/duplex. **/ -static s32 igb_configure_pcs_link_82575(struct e1000_hw *hw) +static void igb_configure_pcs_link_82575(struct e1000_hw *hw) { struct e1000_mac_info *mac = &hw->mac; u32 reg = 0; if (hw->phy.media_type != e1000_media_type_copper || !(igb_sgmii_active_82575(hw))) - goto out; + return; /* For SGMII, we need to issue a PCS autoneg restart */ reg = rd32(E1000_PCS_LCTL); @@ -1211,9 +1209,6 @@ static s32 igb_configure_pcs_link_82575(struct e1000_hw *hw) reg); } wr32(E1000_PCS_LCTL, reg); - -out: - return 0; } /** -- cgit v1.2.3-18-g5258 From 12645a196eccb9209f88915f56a686086dea1a16 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:08:16 +0000 Subject: igb: do not overwrite EEPROM LED settings The igb driver was overwritting the LED settings that were configured via EEPROM. This is not correct behavior as the LED settings are meant to be configured by EEPROM and not changed. This change removes the code that was setting the LED behavior on the interface. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/e1000_82575.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index f946bed66c7..606c25c56a0 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -1000,7 +1000,7 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw) **/ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw) { - u32 ctrl, led_ctrl; + u32 ctrl; s32 ret_val; bool link; @@ -1015,11 +1015,6 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw) break; case e1000_phy_igp_3: ret_val = igb_copper_link_setup_igp(hw); - /* Setup activity LED */ - led_ctrl = rd32(E1000_LEDCTL); - led_ctrl &= IGP_ACTIVITY_LED_MASK; - led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); - wr32(E1000_LEDCTL, led_ctrl); break; default: ret_val = -E1000_ERR_PHY; -- cgit v1.2.3-18-g5258 From 009bc06e5311b48c77b7708d9e226ae0f110373a Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:08:35 +0000 Subject: igb: add completion timeout workaround for 82575/82576 The 82575 and 82576 hardware can both experience data corruption issues if a pci-e completion arrives after the timeout value. In order to avoid this we need to increase the timeout value while pci-e master is disabled. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/e1000_82575.c | 58 +++++++++++++++++++++++++++++++++++++++++ drivers/net/igb/e1000_defines.h | 8 ++++++ drivers/net/igb/e1000_hw.h | 4 ++- drivers/net/igb/e1000_mac.c | 14 ---------- drivers/net/igb/e1000_regs.h | 1 + drivers/net/igb/igb_main.c | 28 ++++++++++++++++++++ 6 files changed, 98 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index 606c25c56a0..c4506bf1fca 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -61,6 +61,7 @@ static void igb_release_swfw_sync_82575(struct e1000_hw *, u16); static bool igb_sgmii_active_82575(struct e1000_hw *); static s32 igb_reset_init_script_82575(struct e1000_hw *); static s32 igb_read_mac_addr_82575(struct e1000_hw *); +static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw); static s32 igb_get_invariants_82575(struct e1000_hw *hw) { @@ -909,6 +910,12 @@ static s32 igb_reset_hw_82575(struct e1000_hw *hw) if (ret_val) hw_dbg("PCI-E Master disable polling has failed.\n"); + /* set the completion timeout for interface */ + ret_val = igb_set_pcie_completion_timeout(hw); + if (ret_val) { + hw_dbg("PCI-E Set completion timeout has failed.\n"); + } + hw_dbg("Masking off all interrupts\n"); wr32(E1000_IMC, 0xffffffff); @@ -1407,6 +1414,57 @@ void igb_rx_fifo_flush_82575(struct e1000_hw *hw) rd32(E1000_MPC); } +/** + * igb_set_pcie_completion_timeout - set pci-e completion timeout + * @hw: pointer to the HW structure + * + * The defaults for 82575 and 82576 should be in the range of 50us to 50ms, + * however the hardware default for these parts is 500us to 1ms which is less + * than the 10ms recommended by the pci-e spec. To address this we need to + * increase the value to either 10ms to 200ms for capability version 1 config, + * or 16ms to 55ms for version 2. + **/ +static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw) +{ + u32 gcr = rd32(E1000_GCR); + s32 ret_val = 0; + u16 pcie_devctl2; + + /* only take action if timeout value is defaulted to 0 */ + if (gcr & E1000_GCR_CMPL_TMOUT_MASK) + goto out; + + /* + * if capababilities version is type 1 we can write the + * timeout of 10ms to 200ms through the GCR register + */ + if (!(gcr & E1000_GCR_CAP_VER2)) { + gcr |= E1000_GCR_CMPL_TMOUT_10ms; + goto out; + } + + /* + * for version 2 capabilities we need to write the config space + * directly in order to set the completion timeout value for + * 16ms to 55ms + */ + ret_val = igb_read_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2, + &pcie_devctl2); + if (ret_val) + goto out; + + pcie_devctl2 |= PCIE_DEVICE_CONTROL2_16ms; + + ret_val = igb_write_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2, + &pcie_devctl2); +out: + /* disable completion timeout resend */ + gcr &= ~E1000_GCR_CMPL_TMOUT_RESEND; + + wr32(E1000_GCR, gcr); + return ret_val; +} + /** * igb_vmdq_set_loopback_pf - enable or disable vmdq loopback * @hw: pointer to the hardware struct diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h index 3bda3db73f1..c85829355d5 100644 --- a/drivers/net/igb/e1000_defines.h +++ b/drivers/net/igb/e1000_defines.h @@ -435,6 +435,12 @@ /* Flow Control */ #define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */ +/* PCI Express Control */ +#define E1000_GCR_CMPL_TMOUT_MASK 0x0000F000 +#define E1000_GCR_CMPL_TMOUT_10ms 0x00001000 +#define E1000_GCR_CMPL_TMOUT_RESEND 0x00010000 +#define E1000_GCR_CAP_VER2 0x00040000 + /* PHY Control Register */ #define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ #define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ @@ -569,9 +575,11 @@ /* PCI/PCI-X/PCI-EX Config space */ #define PCIE_LINK_STATUS 0x12 +#define PCIE_DEVICE_CONTROL2 0x28 #define PCIE_LINK_WIDTH_MASK 0x3F0 #define PCIE_LINK_WIDTH_SHIFT 4 +#define PCIE_DEVICE_CONTROL2_16ms 0x0005 #define PHY_REVISION_MASK 0xFFFFFFF0 #define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h index f096ddd8429..eb41f3b8234 100644 --- a/drivers/net/igb/e1000_hw.h +++ b/drivers/net/igb/e1000_hw.h @@ -494,5 +494,7 @@ extern char *igb_get_hw_dev_name(struct e1000_hw *hw); #else #define hw_dbg(format, arg...) #endif - #endif +/* These functions must be implemented by drivers */ +s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value); +s32 igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value); diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index 34f1a370b06..60343b58364 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -37,20 +37,6 @@ static s32 igb_set_default_fc(struct e1000_hw *hw); static s32 igb_set_fc_watermarks(struct e1000_hw *hw); -static s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value) -{ - struct igb_adapter *adapter = hw->back; - u16 cap_offset; - - cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP); - if (!cap_offset) - return -E1000_ERR_CONFIG; - - pci_read_config_word(adapter->pdev, cap_offset + reg, value); - - return 0; -} - /** * igb_get_bus_info_pcie - Get PCIe bus information * @hw: pointer to the HW structure diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h index 6e5924511e4..345d1442d6d 100644 --- a/drivers/net/igb/e1000_regs.h +++ b/drivers/net/igb/e1000_regs.h @@ -305,6 +305,7 @@ enum { #define E1000_CCMCTL 0x05B48 /* CCM Control Register */ #define E1000_GIOCTL 0x05B44 /* GIO Analog Control Register */ #define E1000_SCCTL 0x05B4C /* PCIc PLL Configuration Register */ +#define E1000_GCR 0x05B00 /* PCI-Ex Control */ #define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */ #define E1000_SWSM 0x05B50 /* SW Semaphore */ #define E1000_FWSM 0x05B54 /* FW Semaphore */ diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 39b3b6aa650..2cb546078c5 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -5029,6 +5029,34 @@ static int igb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) } } +s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value) +{ + struct igb_adapter *adapter = hw->back; + u16 cap_offset; + + cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP); + if (!cap_offset) + return -E1000_ERR_CONFIG; + + pci_read_config_word(adapter->pdev, cap_offset + reg, value); + + return 0; +} + +s32 igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value) +{ + struct igb_adapter *adapter = hw->back; + u16 cap_offset; + + cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP); + if (!cap_offset) + return -E1000_ERR_CONFIG; + + pci_write_config_word(adapter->pdev, cap_offset + reg, *value); + + return 0; +} + static void igb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) { -- cgit v1.2.3-18-g5258 From 28fc06f58b1fe567bb86c7d0e3d93137e5c0126e Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:08:54 +0000 Subject: igb: move all multicast addresses into multicast table array This patch moves all of the multicast addresses out of the free Receive address registers and instead programs them all into the multicast table array. As a result the multicast filtering may not be as precise, but it also greatly reduces the overhead for multicast addresses. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/e1000_82575.c | 59 ------------------------------------------- drivers/net/igb/e1000_82575.h | 1 - drivers/net/igb/e1000_hw.h | 4 +++ drivers/net/igb/e1000_mac.c | 35 +++++++++++++++++++++++++ drivers/net/igb/e1000_mac.h | 2 ++ drivers/net/igb/igb_main.c | 44 +++++++++++--------------------- 6 files changed, 56 insertions(+), 89 deletions(-) (limited to 'drivers') diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index c4506bf1fca..5d2c2fbf926 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -797,65 +797,6 @@ static void igb_init_rx_addrs_82575(struct e1000_hw *hw, u16 rar_count) hw->mac.ops.rar_set(hw, addr, i); } -/** - * igb_update_mc_addr_list - Update Multicast addresses - * @hw: pointer to the HW structure - * @mc_addr_list: array of multicast addresses to program - * @mc_addr_count: number of multicast addresses to program - * @rar_used_count: the first RAR register free to program - * @rar_count: total number of supported Receive Address Registers - * - * Updates the Receive Address Registers and Multicast Table Array. - * The caller must have a packed mc_addr_list of multicast addresses. - * The parameter rar_count will usually be hw->mac.rar_entry_count - * unless there are workarounds that change this. - **/ -void igb_update_mc_addr_list(struct e1000_hw *hw, - u8 *mc_addr_list, u32 mc_addr_count, - u32 rar_used_count, u32 rar_count) -{ - u32 hash_value; - u32 i; - u8 addr[6] = {0,0,0,0,0,0}; - /* - * This function is essentially the same as that of - * igb_update_mc_addr_list_generic. However it also takes care - * of the special case where the register offset of the - * second set of RARs begins elsewhere. This is implicitly taken care by - * function e1000_rar_set_generic. - */ - - /* - * Load the first set of multicast addresses into the exact - * filters (RAR). If there are not enough to fill the RAR - * array, clear the filters. - */ - for (i = rar_used_count; i < rar_count; i++) { - if (mc_addr_count) { - igb_rar_set(hw, mc_addr_list, i); - mc_addr_count--; - mc_addr_list += ETH_ALEN; - } else { - igb_rar_set(hw, addr, i); - } - } - - /* Clear the old settings from the MTA */ - hw_dbg("Clearing MTA\n"); - for (i = 0; i < hw->mac.mta_reg_count; i++) { - array_wr32(E1000_MTA, i, 0); - wrfl(); - } - - /* Load any remaining multicast addresses into the hash table. */ - for (; mc_addr_count > 0; mc_addr_count--) { - hash_value = igb_hash_mc_addr(hw, mc_addr_list); - hw_dbg("Hash value = 0x%03X\n", hash_value); - igb_mta_set(hw, hash_value); - mc_addr_list += ETH_ALEN; - } -} - /** * igb_shutdown_fiber_serdes_link_82575 - Remove link during power down * @hw: pointer to the HW structure diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h index b674417ae06..8a1e6597061 100644 --- a/drivers/net/igb/e1000_82575.h +++ b/drivers/net/igb/e1000_82575.h @@ -28,7 +28,6 @@ #ifndef _E1000_82575_H_ #define _E1000_82575_H_ -void igb_update_mc_addr_list(struct e1000_hw*, u8*, u32, u32, u32); extern void igb_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw); extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw); diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h index eb41f3b8234..83f9b4f6d5e 100644 --- a/drivers/net/igb/e1000_hw.h +++ b/drivers/net/igb/e1000_hw.h @@ -338,6 +338,10 @@ struct e1000_mac_info { u16 ifs_ratio; u16 ifs_step_size; u16 mta_reg_count; + + /* Maximum size of the MTA register table in all supported adapters */ + #define MAX_MTA_REG 128 + u32 mta_shadow[MAX_MTA_REG]; u16 rar_entry_count; u8 forced_speed_duplex; diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index 60343b58364..46e27e98254 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -260,6 +260,41 @@ void igb_mta_set(struct e1000_hw *hw, u32 hash_value) wrfl(); } +/** + * igb_update_mc_addr_list - Update Multicast addresses + * @hw: pointer to the HW structure + * @mc_addr_list: array of multicast addresses to program + * @mc_addr_count: number of multicast addresses to program + * + * Updates entire Multicast Table Array. + * The caller must have a packed mc_addr_list of multicast addresses. + **/ +void igb_update_mc_addr_list(struct e1000_hw *hw, + u8 *mc_addr_list, u32 mc_addr_count) +{ + u32 hash_value, hash_bit, hash_reg; + int i; + + /* clear mta_shadow */ + memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow)); + + /* update mta_shadow from mc_addr_list */ + for (i = 0; (u32) i < mc_addr_count; i++) { + hash_value = igb_hash_mc_addr(hw, mc_addr_list); + + hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); + hash_bit = hash_value & 0x1F; + + hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit); + mc_addr_list += (ETH_ALEN); + } + + /* replace the entire MTA table */ + for (i = hw->mac.mta_reg_count - 1; i >= 0; i--) + array_wr32(E1000_MTA, i, hw->mac.mta_shadow[i]); + wrfl(); +} + /** * igb_hash_mc_addr - Generate a multicast hash value * @hw: pointer to the HW structure diff --git a/drivers/net/igb/e1000_mac.h b/drivers/net/igb/e1000_mac.h index 1d690b4c9ae..f9ebfb3f234 100644 --- a/drivers/net/igb/e1000_mac.h +++ b/drivers/net/igb/e1000_mac.h @@ -51,6 +51,8 @@ s32 igb_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex); s32 igb_id_led_init(struct e1000_hw *hw); s32 igb_led_off(struct e1000_hw *hw); +void igb_update_mc_addr_list(struct e1000_hw *hw, + u8 *mc_addr_list, u32 mc_addr_count); s32 igb_setup_link(struct e1000_hw *hw); s32 igb_validate_mdi_setting(struct e1000_hw *hw); s32 igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg, diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 2cb546078c5..e4f4526e5be 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -127,7 +127,7 @@ static void igb_restore_vlan(struct igb_adapter *); static void igb_ping_all_vfs(struct igb_adapter *); static void igb_msg_task(struct igb_adapter *); static int igb_rcv_msg_from_vf(struct igb_adapter *, u32); -static void igb_set_mc_list_pools(struct igb_adapter *, int, u16); +static inline void igb_set_rah_pool(struct e1000_hw *, int , int); static void igb_vmm_control(struct igb_adapter *); static int igb_set_vf_mac(struct igb_adapter *adapter, int, unsigned char *); static void igb_restore_vf_multicasts(struct igb_adapter *adapter); @@ -2535,7 +2535,6 @@ static void igb_set_multi(struct net_device *netdev) { struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - struct e1000_mac_info *mac = &hw->mac; struct dev_mc_list *mc_ptr; u8 *mta_list = NULL; u32 rctl; @@ -2558,13 +2557,18 @@ static void igb_set_multi(struct net_device *netdev) } wr32(E1000_RCTL, rctl); - if (netdev->mc_count) { - mta_list = kzalloc(netdev->mc_count * 6, GFP_ATOMIC); - if (!mta_list) { - dev_err(&adapter->pdev->dev, - "failed to allocate multicast filter list\n"); - return; - } + if (!netdev->mc_count) { + /* nothing to program, so clear mc list */ + igb_update_mc_addr_list(hw, NULL, 0); + igb_restore_vf_multicasts(adapter); + return; + } + + mta_list = kzalloc(netdev->mc_count * 6, GFP_ATOMIC); + if (!mta_list) { + dev_err(&adapter->pdev->dev, + "failed to allocate multicast filter list\n"); + return; } /* The shared function expects a packed array of only addresses. */ @@ -2576,14 +2580,9 @@ static void igb_set_multi(struct net_device *netdev) memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, ETH_ALEN); mc_ptr = mc_ptr->next; } - igb_update_mc_addr_list(hw, mta_list, i, - adapter->vfs_allocated_count + 1, - mac->rar_entry_count); - - igb_set_mc_list_pools(adapter, i, mac->rar_entry_count); - igb_restore_vf_multicasts(adapter); - + igb_update_mc_addr_list(hw, mta_list, i); kfree(mta_list); + igb_restore_vf_multicasts(adapter); } /* Need to wait a few seconds after link up to get diagnostic information from @@ -5468,19 +5467,6 @@ static void igb_io_resume(struct pci_dev *pdev) igb_get_hw_control(adapter); } -static void igb_set_mc_list_pools(struct igb_adapter *adapter, - int entry_count, u16 total_rar_filters) -{ - struct e1000_hw *hw = &adapter->hw; - int i = adapter->vfs_allocated_count + 1; - - if ((i + entry_count) < total_rar_filters) - total_rar_filters = i + entry_count; - - for (; i < total_rar_filters; i++) - igb_set_rah_pool(hw, adapter->vfs_allocated_count, i); -} - static int igb_set_vf_mac(struct igb_adapter *adapter, int vf, unsigned char *mac_addr) { -- cgit v1.2.3-18-g5258 From 5ac1665906559768029c398d9ede8e7cdd73004e Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:09:12 +0000 Subject: igb: cleanup receive address register initialization This update cleans up the receive address register initialization. The main purpose of this is to clean out some redundancy that was introduced due to having multiple ways of setting the receive address registers. Instead of having a specialized function to set one register and one to set all of them it makes more sense to just go through the list calling the function that is needed to set the individual registers. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/e1000_82575.c | 39 ++++----------------------------------- drivers/net/igb/e1000_mac.c | 25 +++++++++++++++++++++++++ drivers/net/igb/e1000_mac.h | 1 + 3 files changed, 30 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index 5d2c2fbf926..95360dc4a56 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -764,39 +764,6 @@ static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw, u16 *speed, return 0; } -/** - * igb_init_rx_addrs_82575 - Initialize receive address's - * @hw: pointer to the HW structure - * @rar_count: receive address registers - * - * Setups the receive address registers by setting the base receive address - * register to the devices MAC address and clearing all the other receive - * address registers to 0. - **/ -static void igb_init_rx_addrs_82575(struct e1000_hw *hw, u16 rar_count) -{ - u32 i; - u8 addr[6] = {0,0,0,0,0,0}; - /* - * This function is essentially the same as that of - * e1000_init_rx_addrs_generic. However it also takes care - * of the special case where the register offset of the - * second set of RARs begins elsewhere. This is implicitly taken care by - * function e1000_rar_set_generic. - */ - - hw_dbg("e1000_init_rx_addrs_82575"); - - /* Setup the receive address */ - hw_dbg("Programming MAC Address into RAR[0]\n"); - hw->mac.ops.rar_set(hw, hw->mac.addr, 0); - - /* Zero out the other (rar_entry_count - 1) receive addresses */ - hw_dbg("Clearing RAR[1-%u]\n", rar_count-1); - for (i = 1; i < rar_count; i++) - hw->mac.ops.rar_set(hw, addr, i); -} - /** * igb_shutdown_fiber_serdes_link_82575 - Remove link during power down * @hw: pointer to the HW structure @@ -889,7 +856,8 @@ static s32 igb_reset_hw_82575(struct e1000_hw *hw) wr32(E1000_IMC, 0xffffffff); icr = rd32(E1000_ICR); - igb_check_alt_mac_addr(hw); + /* Install any alternate MAC address into RAR0 */ + ret_val = igb_check_alt_mac_addr(hw); return ret_val; } @@ -918,7 +886,8 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw) igb_clear_vfta(hw); /* Setup the receive address */ - igb_init_rx_addrs_82575(hw, rar_count); + igb_init_rx_addrs(hw, rar_count); + /* Zero out the Multicast HASH table */ hw_dbg("Zeroing the MTA\n"); for (i = 0; i < mac->mta_reg_count; i++) diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index 46e27e98254..a1e3da78dbb 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -103,6 +103,31 @@ static void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value) wrfl(); } +/** + * igb_init_rx_addrs - Initialize receive address's + * @hw: pointer to the HW structure + * @rar_count: receive address registers + * + * Setups the receive address registers by setting the base receive address + * register to the devices MAC address and clearing all the other receive + * address registers to 0. + **/ +void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count) +{ + u32 i; + u8 mac_addr[ETH_ALEN] = {0}; + + /* Setup the receive address */ + hw_dbg("Programming MAC Address into RAR[0]\n"); + + hw->mac.ops.rar_set(hw, hw->mac.addr, 0); + + /* Zero out the other (rar_entry_count - 1) receive addresses */ + hw_dbg("Clearing RAR[1-%u]\n", rar_count-1); + for (i = 1; i < rar_count; i++) + hw->mac.ops.rar_set(hw, mac_addr, i); +} + /** * igb_vfta_set - enable or disable vlan in VLAN filter table * @hw: pointer to the HW structure diff --git a/drivers/net/igb/e1000_mac.h b/drivers/net/igb/e1000_mac.h index f9ebfb3f234..7518af8cbbf 100644 --- a/drivers/net/igb/e1000_mac.h +++ b/drivers/net/igb/e1000_mac.h @@ -62,6 +62,7 @@ void igb_clear_hw_cntrs_base(struct e1000_hw *hw); void igb_clear_vfta(struct e1000_hw *hw); s32 igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add); void igb_config_collision_dist(struct e1000_hw *hw); +void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count); void igb_mta_set(struct e1000_hw *hw, u32 hash_value); void igb_put_hw_semaphore(struct e1000_hw *hw); void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index); -- cgit v1.2.3-18-g5258 From 08a72b5dced32889594e08008cca0d0582f2d3d8 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:09:30 +0000 Subject: igb: remove unused switch statement from igb_set_wol There is a switch statement in igb_set_wol that defaults to break and doesn't actually do anything. As such it should be removed. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/igb_ethtool.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index a9c37cb1bd7..df2d234be22 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -1836,7 +1836,6 @@ static void igb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { struct igb_adapter *adapter = netdev_priv(netdev); - struct e1000_hw *hw = &adapter->hw; if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)) return -EOPNOTSUPP; @@ -1845,11 +1844,6 @@ static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) !device_can_wakeup(&adapter->pdev->dev)) return wol->wolopts ? -EOPNOTSUPP : 0; - switch (hw->device_id) { - default: - break; - } - /* these settings will always override what we currently have */ adapter->wol = 0; -- cgit v1.2.3-18-g5258 From 4703bf73bd5b0d43c3eb5b547398d4f62dc5d4e1 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:09:48 +0000 Subject: igb: add support for 82576 mezzanine card This patch adds support for a new 82576 mezzanine adapter. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/e1000_82575.c | 1 + drivers/net/igb/e1000_hw.h | 1 + drivers/net/igb/igb_main.c | 1 + 3 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index 95360dc4a56..dbbd72f3555 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -85,6 +85,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) case E1000_DEV_ID_82576_FIBER: case E1000_DEV_ID_82576_SERDES: case E1000_DEV_ID_82576_QUAD_COPPER: + case E1000_DEV_ID_82576_SERDES_QUAD: mac->type = e1000_82576; break; default: diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h index 83f9b4f6d5e..0469e2e7e63 100644 --- a/drivers/net/igb/e1000_hw.h +++ b/drivers/net/igb/e1000_hw.h @@ -42,6 +42,7 @@ struct e1000_hw; #define E1000_DEV_ID_82576_SERDES 0x10E7 #define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8 #define E1000_DEV_ID_82576_NS 0x150A +#define E1000_DEV_ID_82576_SERDES_QUAD 0x150D #define E1000_DEV_ID_82575EB_COPPER 0x10A7 #define E1000_DEV_ID_82575EB_FIBER_SERDES 0x10A9 #define E1000_DEV_ID_82575GB_QUAD_COPPER 0x10D6 diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index e4f4526e5be..2ffb51d6c95 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -65,6 +65,7 @@ static struct pci_device_id igb_pci_tbl[] = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_FIBER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES), board_82575 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES_QUAD), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), board_82575 }, -- cgit v1.2.3-18-g5258 From 2d94d8ab76ea6c858c6e2eb0ab0403b00b031039 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:10:06 +0000 Subject: igb: use buffer_info->dma instead of shinfo->nr_frags to determine unmap This change makes it so that we use buffer_info->dma instead of shinfo->nr_frags to determine if we need to unmap a received skb. By doing this we can avoid a cache miss on small packets since the buffer_info structure should already be prefetched. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/igb_main.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 2ffb51d6c95..12d8683c231 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -4538,6 +4538,20 @@ static inline void igb_rx_checksum_adv(struct igb_adapter *adapter, adapter->hw_csum_good++; } +static inline u16 igb_get_hlen(struct igb_adapter *adapter, + union e1000_adv_rx_desc *rx_desc) +{ + /* HW will not DMA in data larger than the given buffer, even if it + * parses the (NFS, of course) header to be larger. In that case, it + * fills the header buffer and spills the rest into the page. + */ + u16 hlen = (le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info) & + E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT; + if (hlen > adapter->rx_ps_hdr_size) + hlen = adapter->rx_ps_hdr_size; + return hlen; +} + static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring, int *work_done, int budget) { @@ -4552,7 +4566,8 @@ static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring, int cleaned_count = 0; unsigned int total_bytes = 0, total_packets = 0; unsigned int i; - u32 length, hlen, staterr; + u32 staterr; + u16 length; i = rx_ring->next_to_clean; buffer_info = &rx_ring->buffer_info[i]; @@ -4589,17 +4604,8 @@ static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring, goto send_up; } - /* HW will not DMA in data larger than the given buffer, even - * if it parses the (NFS, of course) header to be larger. In - * that case, it fills the header buffer and spills the rest - * into the page. - */ - hlen = (le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info) & - E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT; - if (hlen > adapter->rx_ps_hdr_size) - hlen = adapter->rx_ps_hdr_size; - - if (!skb_shinfo(skb)->nr_frags) { + if (buffer_info->dma) { + u16 hlen = igb_get_hlen(adapter, rx_desc); pci_unmap_single(pdev, buffer_info->dma, adapter->rx_ps_hdr_size, PCI_DMA_FROMDEVICE); -- cgit v1.2.3-18-g5258 From 0cce119aa977dba00467985c0ae93fe43d28740a Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:10:24 +0000 Subject: igb: cleanup flow control configuration to make requested/current more clear This patch cleans up the flow control configuration for igb to make it a bit more readable in regards to what the requested and current modes are. This should help with the maintainability of the current igb driver in regards to flow control. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/e1000_hw.h | 6 +++--- drivers/net/igb/e1000_mac.c | 50 ++++++++++++++++++++++++------------------- drivers/net/igb/e1000_phy.c | 4 ++-- drivers/net/igb/igb_ethtool.c | 34 ++++++++++++++++------------- drivers/net/igb/igb_main.c | 6 +++--- 5 files changed, 55 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h index 0469e2e7e63..119869b1124 100644 --- a/drivers/net/igb/e1000_hw.h +++ b/drivers/net/igb/e1000_hw.h @@ -137,7 +137,7 @@ enum e1000_rev_polarity { e1000_rev_polarity_undefined = 0xFF }; -enum e1000_fc_type { +enum e1000_fc_mode { e1000_fc_none = 0, e1000_fc_rx_pause, e1000_fc_tx_pause, @@ -429,8 +429,8 @@ struct e1000_fc_info { u16 pause_time; /* Flow control pause timer */ bool send_xon; /* Flow control send XON */ bool strict_ieee; /* Strict IEEE mode */ - enum e1000_fc_type type; /* Type of flow control */ - enum e1000_fc_type original_type; + enum e1000_fc_mode current_mode; /* Type of flow control */ + enum e1000_fc_mode requested_mode; }; struct e1000_mbx_operations { diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index a1e3da78dbb..a0231cd079f 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -536,18 +536,24 @@ s32 igb_setup_link(struct e1000_hw *hw) if (igb_check_reset_block(hw)) goto out; - ret_val = igb_set_default_fc(hw); - if (ret_val) - goto out; + /* + * If requested flow control is set to default, set flow control + * based on the EEPROM flow control settings. + */ + if (hw->fc.requested_mode == e1000_fc_default) { + ret_val = igb_set_default_fc(hw); + if (ret_val) + goto out; + } /* * We want to save off the original Flow Control configuration just * in case we get disconnected and then reconnected into a different * hub or switch with different Flow Control capabilities. */ - hw->fc.original_type = hw->fc.type; + hw->fc.current_mode = hw->fc.requested_mode; - hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.type); + hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.current_mode); /* Call the necessary media_type subroutine to configure the link. */ ret_val = hw->mac.ops.setup_physical_interface(hw); @@ -614,7 +620,7 @@ static s32 igb_set_fc_watermarks(struct e1000_hw *hw) * ability to transmit pause frames is not enabled, then these * registers will be set to 0. */ - if (hw->fc.type & e1000_fc_tx_pause) { + if (hw->fc.current_mode & e1000_fc_tx_pause) { /* * We need to set up the Receive Threshold high and low water * marks as well as (optionally) enabling the transmission of @@ -661,12 +667,12 @@ static s32 igb_set_default_fc(struct e1000_hw *hw) } if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0) - hw->fc.type = e1000_fc_none; + hw->fc.requested_mode = e1000_fc_none; else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == NVM_WORD0F_ASM_DIR) - hw->fc.type = e1000_fc_tx_pause; + hw->fc.requested_mode = e1000_fc_tx_pause; else - hw->fc.type = e1000_fc_full; + hw->fc.requested_mode = e1000_fc_full; out: return ret_val; @@ -696,7 +702,7 @@ s32 igb_force_mac_fc(struct e1000_hw *hw) * receive flow control. * * The "Case" statement below enables/disable flow control - * according to the "hw->fc.type" parameter. + * according to the "hw->fc.current_mode" parameter. * * The possible values of the "fc" parameter are: * 0: Flow control is completely disabled @@ -707,9 +713,9 @@ s32 igb_force_mac_fc(struct e1000_hw *hw) * 3: Both Rx and TX flow control (symmetric) is enabled. * other: No other values should be possible at this point. */ - hw_dbg("hw->fc.type = %u\n", hw->fc.type); + hw_dbg("hw->fc.current_mode = %u\n", hw->fc.current_mode); - switch (hw->fc.type) { + switch (hw->fc.current_mode) { case e1000_fc_none: ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); break; @@ -857,11 +863,11 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) * ONLY. Hence, we must now check to see if we need to * turn OFF the TRANSMISSION of PAUSE frames. */ - if (hw->fc.original_type == e1000_fc_full) { - hw->fc.type = e1000_fc_full; + if (hw->fc.requested_mode == e1000_fc_full) { + hw->fc.current_mode = e1000_fc_full; hw_dbg("Flow Control = FULL.\r\n"); } else { - hw->fc.type = e1000_fc_rx_pause; + hw->fc.current_mode = e1000_fc_rx_pause; hw_dbg("Flow Control = " "RX PAUSE frames only.\r\n"); } @@ -878,7 +884,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { - hw->fc.type = e1000_fc_tx_pause; + hw->fc.current_mode = e1000_fc_tx_pause; hw_dbg("Flow Control = TX PAUSE frames only.\r\n"); } /* @@ -893,7 +899,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { - hw->fc.type = e1000_fc_rx_pause; + hw->fc.current_mode = e1000_fc_rx_pause; hw_dbg("Flow Control = RX PAUSE frames only.\r\n"); } /* @@ -917,13 +923,13 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) * be asked to delay transmission of packets than asking * our link partner to pause transmission of frames. */ - else if ((hw->fc.original_type == e1000_fc_none || - hw->fc.original_type == e1000_fc_tx_pause) || + else if ((hw->fc.requested_mode == e1000_fc_none || + hw->fc.requested_mode == e1000_fc_tx_pause) || hw->fc.strict_ieee) { - hw->fc.type = e1000_fc_none; + hw->fc.current_mode = e1000_fc_none; hw_dbg("Flow Control = NONE.\r\n"); } else { - hw->fc.type = e1000_fc_rx_pause; + hw->fc.current_mode = e1000_fc_rx_pause; hw_dbg("Flow Control = RX PAUSE frames only.\r\n"); } @@ -939,7 +945,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw) } if (duplex == HALF_DUPLEX) - hw->fc.type = e1000_fc_none; + hw->fc.current_mode = e1000_fc_none; /* * Now we call a subroutine to actually force the MAC diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c index f50fac25be4..c1f4da63042 100644 --- a/drivers/net/igb/e1000_phy.c +++ b/drivers/net/igb/e1000_phy.c @@ -735,7 +735,7 @@ static s32 igb_phy_setup_autoneg(struct e1000_hw *hw) * other: No software override. The flow control configuration * in the EEPROM is used. */ - switch (hw->fc.type) { + switch (hw->fc.current_mode) { case e1000_fc_none: /* * Flow control (RX & TX) is completely disabled by a @@ -992,7 +992,7 @@ static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw, u32 ctrl; /* Turn off flow control when forcing speed/duplex */ - hw->fc.type = e1000_fc_none; + hw->fc.current_mode = e1000_fc_none; /* Force speed/duplex on the mac */ ctrl = rd32(E1000_CTRL); diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index df2d234be22..114ccab1f2b 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -194,6 +194,8 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ADVERTISED_TP | ADVERTISED_Autoneg; ecmd->advertising = hw->phy.autoneg_advertised; + if (adapter->fc_autoneg) + hw->fc.requested_mode = e1000_fc_default; } else { if (igb_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { clear_bit(__IGB_RESETTING, &adapter->state); @@ -221,11 +223,11 @@ static void igb_get_pauseparam(struct net_device *netdev, pause->autoneg = (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); - if (hw->fc.type == e1000_fc_rx_pause) + if (hw->fc.current_mode == e1000_fc_rx_pause) pause->rx_pause = 1; - else if (hw->fc.type == e1000_fc_tx_pause) + else if (hw->fc.current_mode == e1000_fc_tx_pause) pause->tx_pause = 1; - else if (hw->fc.type == e1000_fc_full) { + else if (hw->fc.current_mode == e1000_fc_full) { pause->rx_pause = 1; pause->tx_pause = 1; } @@ -243,26 +245,28 @@ static int igb_set_pauseparam(struct net_device *netdev, while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) msleep(1); - if (pause->rx_pause && pause->tx_pause) - hw->fc.type = e1000_fc_full; - else if (pause->rx_pause && !pause->tx_pause) - hw->fc.type = e1000_fc_rx_pause; - else if (!pause->rx_pause && pause->tx_pause) - hw->fc.type = e1000_fc_tx_pause; - else if (!pause->rx_pause && !pause->tx_pause) - hw->fc.type = e1000_fc_none; - - hw->fc.original_type = hw->fc.type; - if (adapter->fc_autoneg == AUTONEG_ENABLE) { + hw->fc.requested_mode = e1000_fc_default; if (netif_running(adapter->netdev)) { igb_down(adapter); igb_up(adapter); } else igb_reset(adapter); - } else + } else { + if (pause->rx_pause && pause->tx_pause) + hw->fc.requested_mode = e1000_fc_full; + else if (pause->rx_pause && !pause->tx_pause) + hw->fc.requested_mode = e1000_fc_rx_pause; + else if (!pause->rx_pause && pause->tx_pause) + hw->fc.requested_mode = e1000_fc_tx_pause; + else if (!pause->rx_pause && !pause->tx_pause) + hw->fc.requested_mode = e1000_fc_none; + + hw->fc.current_mode = hw->fc.requested_mode; + retval = ((hw->phy.media_type == e1000_media_type_copper) ? igb_force_mac_fc(hw) : igb_setup_link(hw)); + } clear_bit(__IGB_RESETTING, &adapter->state); return retval; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 12d8683c231..fb327351758 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -1130,7 +1130,7 @@ void igb_reset(struct igb_adapter *adapter) } fc->pause_time = 0xFFFF; fc->send_xon = 1; - fc->type = fc->original_type; + fc->current_mode = fc->requested_mode; /* disable receive for all VFs and wait one second */ if (adapter->vfs_allocated_count) { @@ -1427,8 +1427,8 @@ static int __devinit igb_probe(struct pci_dev *pdev, hw->mac.autoneg = true; hw->phy.autoneg_advertised = 0x2f; - hw->fc.original_type = e1000_fc_default; - hw->fc.type = e1000_fc_default; + hw->fc.requested_mode = e1000_fc_default; + hw->fc.current_mode = e1000_fc_default; adapter->itr_setting = IGB_DEFAULT_ITR; adapter->itr = IGB_START_ITR; -- cgit v1.2.3-18-g5258 From a0c98605d7237fc4bf26a345db5f950f46e69834 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:10:43 +0000 Subject: igb: initialize mailbox function pointers prior to phy init The igb driver is currently initializing the mailbox function pointers after the phy. This causes issues as the phy init will return from the function early if there is no phy present. To resolve this I have moved the function pointer init to a location prior to the phy initialization so that serdes based adapters can also make use of SR-IOV. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/e1000_82575.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index dbbd72f3555..6158c0f3b20 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -172,6 +172,10 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) size = 14; nvm->word_size = 1 << size; + /* if 82576 then initialize mailbox parameters */ + if (mac->type == e1000_82576) + igb_init_mbx_params_pf(hw); + /* setup PHY parameters */ if (phy->media_type != e1000_media_type_copper) { phy->type = e1000_phy_none; @@ -221,10 +225,6 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) return -E1000_ERR_PHY; } - /* if 82576 then initialize mailbox parameters */ - if (mac->type == e1000_82576) - igb_init_mbx_params_pf(hw); - return 0; } -- cgit v1.2.3-18-g5258 From 92d947b77436437f4fe6f9b7b7cd35f1a294fa9d Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 23 Jul 2009 18:11:01 +0000 Subject: igbvf: resolve "frees DMA memory with different size" warnings This change resolves some warnings seen with DMA debugging enabled in which we were mapping skb->data with size + NET_IP_ALIGN and unmapping it with just size. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igbvf/netdev.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index 2bc9d63027d..926c31b4726 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -149,7 +149,6 @@ static void igbvf_alloc_rx_buffers(struct igbvf_ring *rx_ring, bufsz = adapter->rx_ps_hdr_size; else bufsz = adapter->rx_buffer_len; - bufsz += NET_IP_ALIGN; while (cleaned_count--) { rx_desc = IGBVF_RX_DESC_ADV(*rx_ring, i); @@ -173,7 +172,7 @@ static void igbvf_alloc_rx_buffers(struct igbvf_ring *rx_ring, } if (!buffer_info->skb) { - skb = netdev_alloc_skb(netdev, bufsz); + skb = netdev_alloc_skb(netdev, bufsz + NET_IP_ALIGN); if (!skb) { adapter->alloc_rx_buff_failed++; goto no_buffers; @@ -286,7 +285,7 @@ static bool igbvf_clean_rx_irq(struct igbvf_adapter *adapter, if (!skb_shinfo(skb)->nr_frags) { pci_unmap_single(pdev, buffer_info->dma, - adapter->rx_ps_hdr_size + NET_IP_ALIGN, + adapter->rx_ps_hdr_size, PCI_DMA_FROMDEVICE); skb_put(skb, hlen); } -- cgit v1.2.3-18-g5258 From ebd7768daeb39b0691e25175e25b980f13e913e2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 22 Jul 2009 21:51:32 -0700 Subject: Input: i8042 - switch to using dev_pm_ops Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042.c | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 582245c497e..9f5c0506242 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -923,41 +923,27 @@ static void i8042_dritek_enable(void) #ifdef CONFIG_PM -static bool i8042_suspended; - /* - * Here we try to restore the original BIOS settings. We only want to - * do that once, when we really suspend, not when we taking memory - * snapshot for swsusp (in this case we'll perform required cleanup - * as part of shutdown process). + * Here we try to restore the original BIOS settings to avoid + * upsetting it. */ -static int i8042_suspend(struct platform_device *dev, pm_message_t state) +static int i8042_pm_reset(struct device *dev) { - if (!i8042_suspended && state.event == PM_EVENT_SUSPEND) - i8042_controller_reset(); - - i8042_suspended = state.event == PM_EVENT_SUSPEND || - state.event == PM_EVENT_FREEZE; + i8042_controller_reset(); return 0; } - /* - * Here we try to reset everything back to a state in which suspended + * Here we try to reset everything back to a state we had + * before suspending. */ -static int i8042_resume(struct platform_device *dev) +static int i8042_pm_restore(struct device *dev) { int error; -/* - * Do not bother with restoring state if we haven't suspened yet - */ - if (!i8042_suspended) - return 0; - error = i8042_controller_check(); if (error) return error; @@ -1001,11 +987,18 @@ static int i8042_resume(struct platform_device *dev) if (i8042_ports[I8042_KBD_PORT_NO].serio) i8042_enable_kbd_port(); - i8042_suspended = false; i8042_interrupt(0, NULL); return 0; } + +static const struct dev_pm_ops i8042_pm_ops = { + .suspend = i8042_pm_reset, + .resume = i8042_pm_restore, + .poweroff = i8042_pm_reset, + .restore = i8042_pm_restore, +}; + #endif /* CONFIG_PM */ /* @@ -1251,14 +1244,13 @@ static struct platform_driver i8042_driver = { .driver = { .name = "i8042", .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &i8042_pm_ops, +#endif }, .probe = i8042_probe, .remove = __devexit_p(i8042_remove), .shutdown = i8042_shutdown, -#ifdef CONFIG_PM - .suspend = i8042_suspend, - .resume = i8042_resume, -#endif }; static int __init i8042_init(void) -- cgit v1.2.3-18-g5258 From 633aae23ff31bef692a70772652e753a0ae59b81 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 22 Jul 2009 21:51:36 -0700 Subject: Input: serio - switch to using dev_pm_ops Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index d66f4944f2a..0236f0d5fd9 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -931,15 +931,11 @@ static int serio_uevent(struct device *dev, struct kobj_uevent_env *env) #endif /* CONFIG_HOTPLUG */ #ifdef CONFIG_PM -static int serio_suspend(struct device *dev, pm_message_t state) +static int serio_suspend(struct device *dev) { struct serio *serio = to_serio_port(dev); - if (!serio->suspended && state.event == PM_EVENT_SUSPEND) - serio_cleanup(serio); - - serio->suspended = state.event == PM_EVENT_SUSPEND || - state.event == PM_EVENT_FREEZE; + serio_cleanup(serio); return 0; } @@ -952,13 +948,17 @@ static int serio_resume(struct device *dev) * Driver reconnect can take a while, so better let kseriod * deal with it. */ - if (serio->suspended) { - serio->suspended = false; - serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT); - } + serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT); return 0; } + +static const struct dev_pm_ops serio_pm_ops = { + .suspend = serio_suspend, + .resume = serio_resume, + .poweroff = serio_suspend, + .restore = serio_resume, +}; #endif /* CONFIG_PM */ /* called from serio_driver->connect/disconnect methods under serio_mutex */ @@ -1015,8 +1015,7 @@ static struct bus_type serio_bus = { .remove = serio_driver_remove, .shutdown = serio_shutdown, #ifdef CONFIG_PM - .suspend = serio_suspend, - .resume = serio_resume, + .pm = &serio_pm_ops, #endif }; -- cgit v1.2.3-18-g5258 From b0010911d52dc7836a78c9f5c3b32ce4ac05b3c3 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 24 Jul 2009 22:01:43 -0700 Subject: Input: pxa27x_keypad - switch to using dev_pm_ops Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/pxa27x_keypad.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 09432381939..c987cc75674 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -389,8 +389,9 @@ static void pxa27x_keypad_close(struct input_dev *dev) } #ifdef CONFIG_PM -static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t state) +static int pxa27x_keypad_suspend(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); clk_disable(keypad->clk); @@ -401,8 +402,9 @@ static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t stat return 0; } -static int pxa27x_keypad_resume(struct platform_device *pdev) +static int pxa27x_keypad_resume(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); struct input_dev *input_dev = keypad->input_dev; @@ -421,9 +423,11 @@ static int pxa27x_keypad_resume(struct platform_device *pdev) return 0; } -#else -#define pxa27x_keypad_suspend NULL -#define pxa27x_keypad_resume NULL + +static const struct dev_pm_ops pxa27x_keypad_pm_ops = { + .suspend = pxa27x_keypad_suspend, + .resume = pxa27x_keypad_resume, +}; #endif static int __devinit pxa27x_keypad_probe(struct platform_device *pdev) @@ -572,11 +576,12 @@ MODULE_ALIAS("platform:pxa27x-keypad"); static struct platform_driver pxa27x_keypad_driver = { .probe = pxa27x_keypad_probe, .remove = __devexit_p(pxa27x_keypad_remove), - .suspend = pxa27x_keypad_suspend, - .resume = pxa27x_keypad_resume, .driver = { .name = "pxa27x-keypad", .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &pxa27x_keypad_pm_ops, +#endif }, }; -- cgit v1.2.3-18-g5258 From 75fba3b05d6ed82b975c1f8df8f8e08d5d81dee5 Mon Sep 17 00:00:00 2001 From: Richard Röjfors Date: Fri, 24 Jul 2009 22:01:39 -0700 Subject: Input: tsc2007 - remove HR timer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since it's not allowed to do synchronous I2C in the HR timer callback context we have to switch to using the global workqueue. The work is scheduled every 1ms when polling rather than 5 us. Signed-off-by: Richard Röjfors Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007.c | 48 ++++++++++--------------------------- 1 file changed, 13 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 880f58c6a7c..b512697b227 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -21,15 +21,13 @@ */ #include -#include #include #include #include #include #include -#define TS_POLL_DELAY (10 * 1000) /* ns delay before the first sample */ -#define TS_POLL_PERIOD (5 * 1000) /* ns delay between samples */ +#define TS_POLL_PERIOD msecs_to_jiffies(1) /* ms delay between samples */ #define TSC2007_MEASURE_TEMP0 (0x0 << 4) #define TSC2007_MEASURE_AUX (0x2 << 4) @@ -70,13 +68,11 @@ struct ts_event { struct tsc2007 { struct input_dev *input; char phys[32]; - struct hrtimer timer; + struct delayed_work work; struct ts_event tc; struct i2c_client *client; - spinlock_t lock; - u16 model; u16 x_plate_ohms; @@ -142,8 +138,7 @@ static void tsc2007_send_event(void *tsc) if (rt > MAX_12BIT) { dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt); - hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), - HRTIMER_MODE_REL); + schedule_delayed_work(&ts->work, TS_POLL_PERIOD); return; } @@ -153,7 +148,7 @@ static void tsc2007_send_event(void *tsc) * in some cases may not even settle at the expected value. * * The only safe way to check for the pen up condition is in the - * timer by reading the pen signal state (it's a GPIO _and_ IRQ). + * work function by reading the pen signal state (it's a GPIO and IRQ). */ if (rt) { struct input_dev *input = ts->input; @@ -175,8 +170,7 @@ static void tsc2007_send_event(void *tsc) x, y, rt); } - hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), - HRTIMER_MODE_REL); + schedule_delayed_work(&ts->work, TS_POLL_PERIOD); } static int tsc2007_read_values(struct tsc2007 *tsc) @@ -197,13 +191,10 @@ static int tsc2007_read_values(struct tsc2007 *tsc) return 0; } -static enum hrtimer_restart tsc2007_timer(struct hrtimer *handle) +static void tsc2007_work(struct work_struct *work) { - struct tsc2007 *ts = container_of(handle, struct tsc2007, timer); - unsigned long flags; - - spin_lock_irqsave(&ts->lock, flags); - + struct tsc2007 *ts = + container_of(to_delayed_work(work), struct tsc2007, work); if (unlikely(!ts->get_pendown_state() && ts->pendown)) { struct input_dev *input = ts->input; @@ -222,30 +213,20 @@ static enum hrtimer_restart tsc2007_timer(struct hrtimer *handle) tsc2007_read_values(ts); tsc2007_send_event(ts); } - - spin_unlock_irqrestore(&ts->lock, flags); - - return HRTIMER_NORESTART; } static irqreturn_t tsc2007_irq(int irq, void *handle) { struct tsc2007 *ts = handle; - unsigned long flags; - - spin_lock_irqsave(&ts->lock, flags); if (likely(ts->get_pendown_state())) { disable_irq_nosync(ts->irq); - hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY), - HRTIMER_MODE_REL); + schedule_delayed_work(&ts->work, 0); } if (ts->clear_penirq) ts->clear_penirq(); - spin_unlock_irqrestore(&ts->lock, flags); - return IRQ_HANDLED; } @@ -278,11 +259,6 @@ static int tsc2007_probe(struct i2c_client *client, ts->input = input_dev; - hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - ts->timer.function = tsc2007_timer; - - spin_lock_init(&ts->lock); - ts->model = pdata->model; ts->x_plate_ohms = pdata->x_plate_ohms; ts->get_pendown_state = pdata->get_pendown_state; @@ -308,6 +284,8 @@ static int tsc2007_probe(struct i2c_client *client, ts->irq = client->irq; + INIT_DELAYED_WORK(&ts->work, tsc2007_work); + err = request_irq(ts->irq, tsc2007_irq, 0, client->dev.driver->name, ts); if (err < 0) { @@ -325,7 +303,6 @@ static int tsc2007_probe(struct i2c_client *client, err_free_irq: free_irq(ts->irq, ts); - hrtimer_cancel(&ts->timer); err_free_mem: input_free_device(input_dev); kfree(ts); @@ -337,11 +314,12 @@ static int tsc2007_remove(struct i2c_client *client) struct tsc2007 *ts = i2c_get_clientdata(client); struct tsc2007_platform_data *pdata; + cancel_delayed_work_sync(&ts->work); + pdata = client->dev.platform_data; pdata->exit_platform_hw(); free_irq(ts->irq, ts); - hrtimer_cancel(&ts->timer); input_unregister_device(ts->input); kfree(ts); -- cgit v1.2.3-18-g5258 From 141586bc57f6083f36c18d86e1cfa5916a1e7c05 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 24 Jul 2009 23:14:16 -0700 Subject: Input: tsc2007 - properly shut off interrupts/delayed work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Properly shut off interrupts/delayed work by free-ing IRQ first and then ensuring that enable/disable is balanced. Also add __devinit/__devexit markings, restore poll delay/period scheduling logic, make sure we call exit_platform_hw() method when probe fails. Tested-by: Richard Röjfors Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007.c | 72 +++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index b512697b227..75fbd753a4d 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -27,7 +27,8 @@ #include #include -#define TS_POLL_PERIOD msecs_to_jiffies(1) /* ms delay between samples */ +#define TS_POLL_DELAY 1 /* ms delay between samples */ +#define TS_POLL_PERIOD 1 /* ms delay between samples */ #define TSC2007_MEASURE_TEMP0 (0x0 << 4) #define TSC2007_MEASURE_AUX (0x2 << 4) @@ -76,7 +77,7 @@ struct tsc2007 { u16 model; u16 x_plate_ohms; - unsigned pendown; + bool pendown; int irq; int (*get_pendown_state)(void); @@ -131,18 +132,18 @@ static void tsc2007_send_event(void *tsc) } else rt = 0; - /* Sample found inconsistent by debouncing or pressure is beyond + /* + * Sample found inconsistent by debouncing or pressure is beyond * the maximum. Don't report it to user space, repeat at least * once more the measurement */ if (rt > MAX_12BIT) { dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt); - - schedule_delayed_work(&ts->work, TS_POLL_PERIOD); return; } - /* NOTE: We can't rely on the pressure to determine the pen down + /* + * NOTE: We can't rely on the pressure to determine the pen down * state, even this controller has a pressure sensor. The pressure * value can fluctuate for quite a while after lifting the pen and * in some cases may not even settle at the expected value. @@ -157,7 +158,7 @@ static void tsc2007_send_event(void *tsc) dev_dbg(&ts->client->dev, "DOWN\n"); input_report_key(input, BTN_TOUCH, 1); - ts->pendown = 1; + ts->pendown = true; } input_report_abs(input, ABS_X, x); @@ -169,8 +170,6 @@ static void tsc2007_send_event(void *tsc) dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n", x, y, rt); } - - schedule_delayed_work(&ts->work, TS_POLL_PERIOD); } static int tsc2007_read_values(struct tsc2007 *tsc) @@ -195,6 +194,7 @@ static void tsc2007_work(struct work_struct *work) { struct tsc2007 *ts = container_of(to_delayed_work(work), struct tsc2007, work); + if (unlikely(!ts->get_pendown_state() && ts->pendown)) { struct input_dev *input = ts->input; @@ -204,7 +204,7 @@ static void tsc2007_work(struct work_struct *work) input_report_abs(input, ABS_PRESSURE, 0); input_sync(input); - ts->pendown = 0; + ts->pendown = false; enable_irq(ts->irq); } else { /* pen is still down, continue with the measurement */ @@ -212,6 +212,9 @@ static void tsc2007_work(struct work_struct *work) tsc2007_read_values(ts); tsc2007_send_event(ts); + + schedule_delayed_work(&ts->work, + msecs_to_jiffies(TS_POLL_PERIOD)); } } @@ -221,7 +224,8 @@ static irqreturn_t tsc2007_irq(int irq, void *handle) if (likely(ts->get_pendown_state())) { disable_irq_nosync(ts->irq); - schedule_delayed_work(&ts->work, 0); + schedule_delayed_work(&ts->work, + msecs_to_jiffies(TS_POLL_DELAY)); } if (ts->clear_penirq) @@ -230,8 +234,21 @@ static irqreturn_t tsc2007_irq(int irq, void *handle) return IRQ_HANDLED; } -static int tsc2007_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static void tsc2007_free_irq(struct tsc2007 *ts) +{ + free_irq(ts->irq, ts); + if (cancel_delayed_work_sync(&ts->work)) { + /* + * Work was pending, therefore we need to enable + * IRQ here to balance the disable_irq() done in the + * interrupt handler. + */ + enable_irq(ts->irq); + } +} + +static int __devinit tsc2007_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct tsc2007 *ts; struct tsc2007_platform_data *pdata = pdata = client->dev.platform_data; @@ -255,17 +272,15 @@ static int tsc2007_probe(struct i2c_client *client, } ts->client = client; - i2c_set_clientdata(client, ts); - + ts->irq = client->irq; ts->input = input_dev; + INIT_DELAYED_WORK(&ts->work, tsc2007_work); ts->model = pdata->model; ts->x_plate_ohms = pdata->x_plate_ohms; ts->get_pendown_state = pdata->get_pendown_state; ts->clear_penirq = pdata->clear_penirq; - pdata->init_platform_hw(); - snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&client->dev)); @@ -280,11 +295,7 @@ static int tsc2007_probe(struct i2c_client *client, input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); - tsc2007_read_values(ts); - - ts->irq = client->irq; - - INIT_DELAYED_WORK(&ts->work, tsc2007_work); + pdata->init_platform_hw(); err = request_irq(ts->irq, tsc2007_irq, 0, client->dev.driver->name, ts); @@ -297,29 +308,30 @@ static int tsc2007_probe(struct i2c_client *client, if (err) goto err_free_irq; - dev_info(&client->dev, "registered with irq (%d)\n", ts->irq); + i2c_set_clientdata(client, ts); + + tsc2007_read_values(ts); return 0; err_free_irq: - free_irq(ts->irq, ts); + tsc2007_free_irq(ts); + pdata->exit_platform_hw(); err_free_mem: input_free_device(input_dev); kfree(ts); return err; } -static int tsc2007_remove(struct i2c_client *client) +static int __devexit tsc2007_remove(struct i2c_client *client) { struct tsc2007 *ts = i2c_get_clientdata(client); - struct tsc2007_platform_data *pdata; + struct tsc2007_platform_data *pdata = client->dev.platform_data; - cancel_delayed_work_sync(&ts->work); + tsc2007_free_irq(ts); - pdata = client->dev.platform_data; pdata->exit_platform_hw(); - free_irq(ts->irq, ts); input_unregister_device(ts->input); kfree(ts); @@ -340,7 +352,7 @@ static struct i2c_driver tsc2007_driver = { }, .id_table = tsc2007_idtable, .probe = tsc2007_probe, - .remove = tsc2007_remove, + .remove = __devexit_p(tsc2007_remove), }; static int __init tsc2007_init(void) -- cgit v1.2.3-18-g5258 From cad065fd1e95003444e8528f801f52164cb78561 Mon Sep 17 00:00:00 2001 From: Richard Röjfors Date: Fri, 24 Jul 2009 23:14:17 -0700 Subject: Input: tsc2007 - make init/exit platform hw callbacks optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make init_platform_hw and exit_platform_hw callbacks optional since they are not needed on all platforms. Signed-off-by: Richard Röjfors Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 75fbd753a4d..8105bf64015 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -295,7 +295,8 @@ static int __devinit tsc2007_probe(struct i2c_client *client, input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); - pdata->init_platform_hw(); + if (pdata->init_platform_hw) + pdata->init_platform_hw(); err = request_irq(ts->irq, tsc2007_irq, 0, client->dev.driver->name, ts); @@ -316,7 +317,8 @@ static int __devinit tsc2007_probe(struct i2c_client *client, err_free_irq: tsc2007_free_irq(ts); - pdata->exit_platform_hw(); + if (pdata->exit_platform_hw) + pdata->exit_platform_hw(); err_free_mem: input_free_device(input_dev); kfree(ts); @@ -330,7 +332,8 @@ static int __devexit tsc2007_remove(struct i2c_client *client) tsc2007_free_irq(ts); - pdata->exit_platform_hw(); + if (pdata->exit_platform_hw) + pdata->exit_platform_hw(); input_unregister_device(ts->input); kfree(ts); -- cgit v1.2.3-18-g5258 From 703490ff7eaff03e412683da3d8367b5190a71ca Mon Sep 17 00:00:00 2001 From: Richard Röjfors Date: Fri, 24 Jul 2009 23:14:17 -0700 Subject: Input: tsc2007 - do not read coordinates during probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't read coordinates during probe of the driver, just power down the controller and wait for interrupts. Signed-off-by: Richard Röjfors Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 8105bf64015..f710af4d0ff 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -184,7 +184,7 @@ static int tsc2007_read_values(struct tsc2007 *tsc) tsc->tc.z1 = tsc2007_xfer(tsc, READ_Z1); tsc->tc.z2 = tsc2007_xfer(tsc, READ_Z2); - /* power down */ + /* Prepare for next touch reading - power down ADC, enable PENIRQ */ tsc2007_xfer(tsc, PWRDOWN); return 0; @@ -311,7 +311,8 @@ static int __devinit tsc2007_probe(struct i2c_client *client, i2c_set_clientdata(client, ts); - tsc2007_read_values(ts); + /* Prepare for touch readings - power down ADC and enable PENIRQ */ + tsc2007_xfer(ts, PWRDOWN); return 0; -- cgit v1.2.3-18-g5258 From c409c34bc472cc62da6c619acf786120b56c2dc2 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Tue, 21 Jul 2009 14:51:20 +0000 Subject: sky2: remove unnecessary assignment Signed-off-by: Mike McCormack Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 3550c5dcd93..661abd0492a 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -4117,7 +4117,7 @@ static int sky2_debug_show(struct seq_file *seq, void *v) seq_printf(seq, "\nRx ring hw get=%d put=%d last=%d\n", sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_GET_IDX)), - last = sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_PUT_IDX)), + sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_PUT_IDX)), sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_LAST_IDX))); sky2_read32(hw, B0_Y2_SP_LISR); -- cgit v1.2.3-18-g5258 From 7d073c68a49b23b5ba2bc23c3bb5b3bcaa0b4f20 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 23 Jul 2009 21:21:19 +0000 Subject: bnx2x: Dont update vlan_features in bnx2x_set_tso() Patrick said : "vlan_features doesn't need to be updated, the resulting dev->features of the VLAN device is computed as the intersection of dev->features and dev->vlan_features." Signed-off-by: Eric Dumazet Acked-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index c4c42b38bbb..a2de0cd9c9f 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -9349,17 +9349,9 @@ static int bnx2x_set_tso(struct net_device *dev, u32 data) if (data) { dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); dev->features |= NETIF_F_TSO6; -#ifdef BCM_VLAN - dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); - dev->vlan_features |= NETIF_F_TSO6; -#endif } else { dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN); dev->features &= ~NETIF_F_TSO6; -#ifdef BCM_VLAN - dev->vlan_features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN); - dev->vlan_features &= ~NETIF_F_TSO6; -#endif } return 0; -- cgit v1.2.3-18-g5258 From 51def0bea92629dff02ff1de40603eb90c609c55 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 22 Jul 2009 14:06:56 +0000 Subject: imwc3200: move iwmc3200 SDIO ids to sdio_ids.h 1. add intel's sdio vendor id to sdio_ids.h 2. move iwmc3200 sdio devices' ids to sdio_ids.h Signed-off-by: Tomas Winkler Signed-off-by: David S. Miller --- drivers/net/wimax/i2400m/sdio.c | 12 +++++------- drivers/net/wireless/iwmc3200wifi/sdio.c | 4 +++- drivers/net/wireless/iwmc3200wifi/sdio.h | 3 --- 3 files changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index 2538825d1c6..ea7b29034aa 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c @@ -58,6 +58,7 @@ */ #include +#include #include #include #include "i2400m-sdio.h" @@ -501,15 +502,12 @@ void i2400ms_remove(struct sdio_func *func) d_fnend(3, dev, "SDIO func %p\n", func); } -enum { - I2400MS_INTEL_VID = 0x89, -}; - static const struct sdio_device_id i2400ms_sdio_ids[] = { - /* Intel: i2400m WiMAX over SDIO */ - { SDIO_DEVICE(I2400MS_INTEL_VID, 0x1402) }, - { }, /* end: all zeroes */ + /* Intel: i2400m WiMAX (iwmc3200) over SDIO */ + { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, + SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX) }, + { /* end: all zeroes */ }, }; MODULE_DEVICE_TABLE(sdio, i2400ms_sdio_ids); diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c index b93f620ee4f..8b1de84003c 100644 --- a/drivers/net/wireless/iwmc3200wifi/sdio.c +++ b/drivers/net/wireless/iwmc3200wifi/sdio.c @@ -65,6 +65,7 @@ #include #include #include +#include #include #include @@ -492,7 +493,8 @@ static void iwm_sdio_remove(struct sdio_func *func) } static const struct sdio_device_id iwm_sdio_ids[] = { - { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, SDIO_DEVICE_ID_IWM) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, + SDIO_DEVICE_ID_INTEL_IWMC3200WIFI) }, { /* end: all zeroes */ }, }; MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids); diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.h b/drivers/net/wireless/iwmc3200wifi/sdio.h index b3c156b08dd..aab6b6892e4 100644 --- a/drivers/net/wireless/iwmc3200wifi/sdio.h +++ b/drivers/net/wireless/iwmc3200wifi/sdio.h @@ -39,9 +39,6 @@ #ifndef __IWM_SDIO_H__ #define __IWM_SDIO_H__ -#define SDIO_VENDOR_ID_INTEL 0x89 -#define SDIO_DEVICE_ID_IWM 0x1403 - #define IWM_SDIO_DATA_ADDR 0x0 #define IWM_SDIO_INTR_ENABLE_ADDR 0x14 #define IWM_SDIO_INTR_STATUS_ADDR 0x13 -- cgit v1.2.3-18-g5258 From 72dccb01e8632aa5ffe58070003d0fa19d007116 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 23 Jul 2009 02:01:38 +0000 Subject: bnx2: Update vlan_features [PATCH net-next-2.6] bnx2: Update vlan_features In order to get full use of some advanced features of BNX2, we now need to fill dev->vlan_features. Patch successfully tested with vlan devices built on top of bonding. (bond0 : one bnx2 slave, one tg3 slave (not yet vlan_features enabled) Signed-off-by: Eric Dumazet Acked-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index b70cc99962f..cec1b1746ae 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -8023,6 +8023,13 @@ static const struct net_device_ops bnx2_netdev_ops = { #endif }; +static void inline vlan_features_add(struct net_device *dev, unsigned long flags) +{ +#ifdef BCM_VLAN + dev->vlan_features |= flags; +#endif +} + static int __devinit bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -8064,16 +8071,20 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) memcpy(dev->perm_addr, bp->mac_addr, 6); dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; - if (CHIP_NUM(bp) == CHIP_NUM_5709) + vlan_features_add(dev, NETIF_F_IP_CSUM | NETIF_F_SG); + if (CHIP_NUM(bp) == CHIP_NUM_5709) { dev->features |= NETIF_F_IPV6_CSUM; - + vlan_features_add(dev, NETIF_F_IPV6_CSUM); + } #ifdef BCM_VLAN dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; #endif dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN; - if (CHIP_NUM(bp) == CHIP_NUM_5709) + vlan_features_add(dev, NETIF_F_TSO | NETIF_F_TSO_ECN); + if (CHIP_NUM(bp) == CHIP_NUM_5709) { dev->features |= NETIF_F_TSO6; - + vlan_features_add(dev, NETIF_F_TSO6); + } if ((rc = register_netdev(dev))) { dev_err(&pdev->dev, "Cannot register net device\n"); goto error; -- cgit v1.2.3-18-g5258 From 70034918930d2e5b68c09bced637228c50d9561a Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 27 Jul 2009 08:05:52 -0700 Subject: net: fix multiple definitions of setup_w6692 Signed-off-by: Stephen Rothwell Acked-by: Karsten Keil Signed-off-by: David S. Miller --- drivers/isdn/hardware/mISDN/w6692.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c index 1b9008f13d6..d3f1077b709 100644 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ b/drivers/isdn/hardware/mISDN/w6692.c @@ -1234,7 +1234,7 @@ w6692_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) return err; } -int +static int setup_w6692(struct w6692_hw *card) { u32 val; -- cgit v1.2.3-18-g5258 From 663a31ce5bbef2d14fa325023e48bf02b4249f27 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Mon, 27 Jul 2009 08:20:55 -0700 Subject: mISDN: Fix wrong struct name in macro and clarifications Based on comments from Joe Perches . Thanks. Fix IOFUNC_MEMIO macro. WriteFiFo##name##_MIO use the wrong struct name, this was missed because the macro was only called with this name. Clarify with _func that the defined types are functions. Add names to the parameters for better understanding the purpose. Signed-off-by: Karsten Keil Signed-off-by: David S. Miller --- drivers/isdn/hardware/mISDN/iohelper.h | 10 +++++----- drivers/isdn/hardware/mISDN/ipac.h | 16 ++++++++-------- drivers/isdn/hardware/mISDN/isar.h | 8 ++++---- 3 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hardware/mISDN/iohelper.h b/drivers/isdn/hardware/mISDN/iohelper.h index c16a217301e..b438981107a 100644 --- a/drivers/isdn/hardware/mISDN/iohelper.h +++ b/drivers/isdn/hardware/mISDN/iohelper.h @@ -26,9 +26,9 @@ #ifndef _IOHELPER_H #define _IOHELPER_H -typedef u8 (read_reg_t)(void *, u8); -typedef void (write_reg_t)(void *, u8, u8); -typedef void (fifo_func_t)(void *, u8, u8 *, int); +typedef u8 (read_reg_func)(void *hwp, u8 offset); +typedef void (write_reg_func)(void *hwp, u8 offset, u8 value); +typedef void (fifo_func)(void *hwp, u8 offset, u8 *datap, int size); struct _ioport { u32 port; @@ -90,7 +90,7 @@ struct _ioport { *dp++ = readb(((typ *)hw->adr) + off);\ } \ static void WriteFiFo##name##_MIO(void *p, u8 off, u8 *dp, int size) {\ - struct inf_hw *hw = p;\ + struct hws *hw = p;\ while (size--)\ writeb(*dp++, ((typ *)hw->adr) + off);\ } @@ -106,4 +106,4 @@ struct _ioport { ASSIGN_FUNC(typ, IPAC, target);\ } while (0) -#endif \ No newline at end of file +#endif diff --git a/drivers/isdn/hardware/mISDN/ipac.h b/drivers/isdn/hardware/mISDN/ipac.h index f9601d55dbc..74a6ccf9065 100644 --- a/drivers/isdn/hardware/mISDN/ipac.h +++ b/drivers/isdn/hardware/mISDN/ipac.h @@ -30,10 +30,10 @@ struct isac_hw { u32 off; /* offset to isac regs */ char *name; spinlock_t *hwlock; /* lock HW acccess */ - read_reg_t *read_reg; - write_reg_t *write_reg; - fifo_func_t *read_fifo; - fifo_func_t *write_fifo; + read_reg_func *read_reg; + write_reg_func *write_reg; + fifo_func *read_fifo; + fifo_func *write_fifo; int (*monitor)(void *, u32, u8 *, int); void (*release)(struct isac_hw *); int (*init)(struct isac_hw *); @@ -73,10 +73,10 @@ struct ipac_hw { spinlock_t *hwlock; /* lock HW acccess */ struct module *owner; u32 type; - read_reg_t *read_reg; - write_reg_t *write_reg; - fifo_func_t *read_fifo; - fifo_func_t *write_fifo; + read_reg_func *read_reg; + write_reg_func *write_reg; + fifo_func *read_fifo; + fifo_func *write_fifo; void (*release)(struct ipac_hw *); int (*init)(struct ipac_hw *); int (*ctrl)(struct ipac_hw *, u32, u_long); diff --git a/drivers/isdn/hardware/mISDN/isar.h b/drivers/isdn/hardware/mISDN/isar.h index 092351acd2a..4a134acd44d 100644 --- a/drivers/isdn/hardware/mISDN/isar.h +++ b/drivers/isdn/hardware/mISDN/isar.h @@ -47,10 +47,10 @@ struct isar_hw { spinlock_t *hwlock; /* lock HW acccess */ char *name; struct module *owner; - read_reg_t *read_reg; - write_reg_t *write_reg; - fifo_func_t *read_fifo; - fifo_func_t *write_fifo; + read_reg_func *read_reg; + write_reg_func *write_reg; + fifo_func *read_fifo; + fifo_func *write_fifo; int (*ctrl)(void *, u32, u_long); void (*release)(struct isar_hw *); int (*init)(struct isar_hw *); -- cgit v1.2.3-18-g5258 From 68b3cae0824b98d1f469a80cc65dcaab81771f45 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 26 Jul 2009 20:07:36 +0000 Subject: netxen: refresh firmware info after reset o move dma mask update to netxen_start_firmware() so that if firmware changes across suspend (e.g. file -> flash) it reflects right dma mask. o re-read firmware capabilities after firmware reset. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_hw.c | 3 +++ drivers/net/netxen/netxen_nic_init.c | 4 ---- drivers/net/netxen/netxen_nic_main.c | 9 ++++----- 3 files changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index b9123d445c9..3c614c3cc62 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -2047,6 +2047,9 @@ void netxen_nic_get_firmware_info(struct netxen_adapter *adapter) dev_info(&pdev->dev, "firmware running in %s mode\n", adapter->ahw.cut_through ? "cut-through" : "legacy"); } + + if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222)) + adapter->capabilities = NXRD32(adapter, CRB_FW_CAPABILITIES_1); } int diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 5d3343ef3d8..847f78b1868 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1083,10 +1083,6 @@ int netxen_init_firmware(struct netxen_adapter *adapter) NXWR32(adapter, CRB_MPORT_MODE, MPORT_MULTI_FUNCTION_MODE); NXWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK); - if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222)) { - adapter->capabilities = NXRD32(adapter, CRB_FW_CAPABILITIES_1); - } - return err; } diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 637ac8b89ba..4c7e4c28bf6 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -764,6 +764,10 @@ wait_init: return err; } + nx_update_dma_mask(adapter); + + netxen_nic_get_firmware_info(adapter); + return 0; } @@ -1071,11 +1075,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = netxen_start_firmware(adapter, 1); if (err) goto err_out_iounmap; - - nx_update_dma_mask(adapter); - - netxen_nic_get_firmware_info(adapter); - /* * See if the firmware gave us a virtual-physical port mapping. */ -- cgit v1.2.3-18-g5258 From 6598b169b856793f8f9b80a3f3c5a48f5eaf40e3 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 26 Jul 2009 20:07:37 +0000 Subject: netxen: enable ip addr hashing NX3031 hardware requires local IP addresses for packet accumulation (LRO). IP address hashing is required to distinguish a local TCP flow from others (forwarded or guest). This patch adds listener for IP and netdev events and configures IP address in the firmware. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 5 ++ drivers/net/netxen/netxen_nic_hw.c | 24 +++++++ drivers/net/netxen/netxen_nic_init.c | 52 ++++++++------- drivers/net/netxen/netxen_nic_main.c | 126 +++++++++++++++++++++++++++++++++++ 4 files changed, 182 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index f86e05047d1..6b9e759d352 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -380,6 +380,7 @@ struct rcv_desc { }; /* opcode field in status_desc */ +#define NETXEN_NIC_SYN_OFFLOAD 0x03 #define NETXEN_NIC_RXPKT_DESC 0x04 #define NETXEN_OLD_RXPKT_DESC 0x3f #define NETXEN_NIC_RESPONSE_DESC 0x05 @@ -1078,6 +1079,9 @@ typedef struct { #define NX_MAC_EVENT 0x1 +#define NX_IP_UP 2 +#define NX_IP_DOWN 3 + /* * Driver --> Firmware */ @@ -1443,6 +1447,7 @@ void netxen_p3_free_mac_list(struct netxen_adapter *adapter); int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32); int netxen_config_intr_coalesce(struct netxen_adapter *adapter); int netxen_config_rss(struct netxen_adapter *adapter, int enable); +int netxen_config_ipaddr(struct netxen_adapter *adapter, u32 ip, int cmd); int netxen_linkevent_request(struct netxen_adapter *adapter, int enable); void netxen_advert_link_change(struct netxen_adapter *adapter, int linkup); diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 3c614c3cc62..088611bb5bd 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -706,6 +706,30 @@ int netxen_config_rss(struct netxen_adapter *adapter, int enable) return rv; } +int netxen_config_ipaddr(struct netxen_adapter *adapter, u32 ip, int cmd) +{ + nx_nic_req_t req; + u64 word; + int rv; + + memset(&req, 0, sizeof(nx_nic_req_t)); + req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23); + + word = NX_NIC_H2C_OPCODE_CONFIG_IPADDR | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + + req.words[0] = cpu_to_le64(cmd); + req.words[1] = cpu_to_le64(ip); + + rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) { + printk(KERN_ERR "%s: could not notify %s IP 0x%x reuqest\n", + adapter->netdev->name, + (cmd == NX_IP_UP) ? "Add" : "Remove", ip); + } + return rv; +} + int netxen_linkevent_request(struct netxen_adapter *adapter, int enable) { nx_nic_req_t req; diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 847f78b1868..5d7a2c45336 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -880,22 +880,10 @@ netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname) return 0; } -void netxen_request_firmware(struct netxen_adapter *adapter) +static int +netxen_p3_has_mn(struct netxen_adapter *adapter) { u32 capability, flashed_ver; - u8 fw_type; - struct pci_dev *pdev = adapter->pdev; - int rc = 0; - - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { - fw_type = NX_P2_MN_ROMIMAGE; - goto request_fw; - } else { - fw_type = NX_P3_CT_ROMIMAGE; - goto request_fw; - } - -request_mn: capability = 0; netxen_rom_fast_read(adapter, @@ -903,23 +891,35 @@ request_mn: flashed_ver = NETXEN_DECODE_VERSION(flashed_ver); if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) { + capability = NXRD32(adapter, NX_PEG_TUNE_CAPABILITY); - if (capability & NX_PEG_TUNE_MN_PRESENT) { - fw_type = NX_P3_MN_ROMIMAGE; - goto request_fw; - } + if (capability & NX_PEG_TUNE_MN_PRESENT) + return 1; + } + return 0; +} + +void netxen_request_firmware(struct netxen_adapter *adapter) +{ + u8 fw_type; + struct pci_dev *pdev = adapter->pdev; + int rc = 0; + + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + fw_type = NX_P2_MN_ROMIMAGE; + goto request_fw; } - fw_type = NX_FLASH_ROMIMAGE; - adapter->fw = NULL; - goto done; + fw_type = netxen_p3_has_mn(adapter) ? + NX_P3_MN_ROMIMAGE : NX_P3_CT_ROMIMAGE; request_fw: rc = request_firmware(&adapter->fw, fw_name[fw_type], &pdev->dev); if (rc != 0) { - if (fw_type == NX_P3_CT_ROMIMAGE) { + if (fw_type == NX_P3_MN_ROMIMAGE) { msleep(1); - goto request_mn; + fw_type = NX_P3_CT_ROMIMAGE; + goto request_fw; } fw_type = NX_FLASH_ROMIMAGE; @@ -931,9 +931,10 @@ request_fw: if (rc != 0) { release_firmware(adapter->fw); - if (fw_type == NX_P3_CT_ROMIMAGE) { + if (fw_type == NX_P3_MN_ROMIMAGE) { msleep(1); - goto request_mn; + fw_type = NX_P3_CT_ROMIMAGE; + goto request_fw; } fw_type = NX_FLASH_ROMIMAGE; @@ -1292,6 +1293,7 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max) switch (opcode) { case NETXEN_NIC_RXPKT_DESC: case NETXEN_OLD_RXPKT_DESC: + case NETXEN_NIC_SYN_OFFLOAD: break; case NETXEN_NIC_RESPONSE_DESC: netxen_handle_fw_message(desc_cnt, consumer, sds_ring); diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 4c7e4c28bf6..b3683260a0b 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -39,6 +39,7 @@ #include #include #include +#include MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver"); MODULE_LICENSE("GPL"); @@ -1780,6 +1781,125 @@ static void netxen_nic_poll_controller(struct net_device *netdev) } #endif +#define is_netxen_netdev(dev) (dev->netdev_ops == &netxen_netdev_ops) + +static int +netxen_destip_supported(struct netxen_adapter *adapter) +{ + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) + return 0; + + if (adapter->ahw.cut_through) + return 0; + + return 1; +} + +static int netxen_netdev_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct netxen_adapter *adapter; + struct net_device *dev = (struct net_device *)ptr; + struct in_device *indev; + +recheck: + if (dev == NULL) + goto done; + + if (dev->priv_flags & IFF_802_1Q_VLAN) { + dev = vlan_dev_real_dev(dev); + goto recheck; + } + + if (!is_netxen_netdev(dev)) + goto done; + + adapter = netdev_priv(dev); + + if (!adapter || !netxen_destip_supported(adapter)) + goto done; + + if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) + goto done; + + indev = in_dev_get(dev); + if (!indev) + goto done; + + for_ifa(indev) { + switch (event) { + case NETDEV_UP: + netxen_config_ipaddr(adapter, + ifa->ifa_address, NX_IP_UP); + break; + case NETDEV_DOWN: + netxen_config_ipaddr(adapter, + ifa->ifa_address, NX_IP_DOWN); + break; + default: + break; + } + } endfor_ifa(indev); + + in_dev_put(indev); +done: + return NOTIFY_DONE; +} + +static int +netxen_inetaddr_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct netxen_adapter *adapter; + struct net_device *dev; + + struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; + + dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL; + +recheck: + if (dev == NULL || !netif_running(dev)) + goto done; + + if (dev->priv_flags & IFF_802_1Q_VLAN) { + dev = vlan_dev_real_dev(dev); + goto recheck; + } + + if (!is_netxen_netdev(dev)) + goto done; + + adapter = netdev_priv(dev); + + if (!adapter || !netxen_destip_supported(adapter)) + goto done; + + if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) + goto done; + + switch (event) { + case NETDEV_UP: + netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_UP); + break; + case NETDEV_DOWN: + netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_DOWN); + break; + default: + break; + } + +done: + return NOTIFY_DONE; +} + +static struct notifier_block netxen_netdev_cb = { + .notifier_call = netxen_netdev_event, +}; + +static struct notifier_block netxen_inetaddr_cb = { + .notifier_call = netxen_inetaddr_event, +}; + static struct pci_driver netxen_driver = { .name = netxen_nic_driver_name, .id_table = netxen_pci_tbl, @@ -1800,6 +1920,9 @@ static int __init netxen_init_module(void) if ((netxen_workq = create_singlethread_workqueue("netxen")) == NULL) return -ENOMEM; + register_netdevice_notifier(&netxen_netdev_cb); + register_inetaddr_notifier(&netxen_inetaddr_cb); + return pci_register_driver(&netxen_driver); } @@ -1808,6 +1931,9 @@ module_init(netxen_init_module); static void __exit netxen_exit_module(void) { pci_unregister_driver(&netxen_driver); + + unregister_inetaddr_notifier(&netxen_inetaddr_cb); + unregister_netdevice_notifier(&netxen_netdev_cb); destroy_workqueue(netxen_workq); } -- cgit v1.2.3-18-g5258 From ca2ef330b5eb30e3bc7047f99fd4be9f1bad22be Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 26 Jul 2009 20:07:38 +0000 Subject: netxen: configure interrupt coalesce defaults Initialize and configure interrupt coalesing defaults in the firmware, so that these also reflect in "ethool -c". Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_main.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index b3683260a0b..76bdd5cee43 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -819,6 +819,20 @@ netxen_nic_free_irq(struct netxen_adapter *adapter) } } +static void +netxen_nic_init_coalesce_defaults(struct netxen_adapter *adapter) +{ + adapter->coal.flags = NETXEN_NIC_INTR_DEFAULT; + adapter->coal.normal.data.rx_time_us = + NETXEN_DEFAULT_INTR_COALESCE_RX_TIME_US; + adapter->coal.normal.data.rx_packets = + NETXEN_DEFAULT_INTR_COALESCE_RX_PACKETS; + adapter->coal.normal.data.tx_time_us = + NETXEN_DEFAULT_INTR_COALESCE_TX_TIME_US; + adapter->coal.normal.data.tx_packets = + NETXEN_DEFAULT_INTR_COALESCE_TX_PACKETS; +} + static int netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) { @@ -841,6 +855,9 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) if (adapter->max_sds_rings > 1) netxen_config_rss(adapter, 1); + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + netxen_config_intr_coalesce(adapter); + netxen_napi_enable(adapter); if (adapter->capabilities & NX_FW_CAPABILITY_LINK_NOTIFICATION) @@ -936,6 +953,9 @@ netxen_nic_attach(struct netxen_adapter *adapter) goto err_out_free_rxbuf; } + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + netxen_nic_init_coalesce_defaults(adapter); + adapter->is_up = NETXEN_ADAPTER_UP_MAGIC; return 0; -- cgit v1.2.3-18-g5258 From 83ac51fa747c3a74372417629fcad4b110857b77 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 26 Jul 2009 20:07:39 +0000 Subject: netxen: annotate dma watchdog setup o remove superfluous code to setup PCI dma watchdog for NX2031. o disable dma watchdog completely for NX3031 (not required). Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 73 ++---------------------------------- drivers/net/netxen/netxen_nic_hdr.h | 2 +- drivers/net/netxen/netxen_nic_init.c | 59 +++++++++++++++++------------ drivers/net/netxen/netxen_nic_main.c | 8 ++-- 4 files changed, 43 insertions(+), 99 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 6b9e759d352..3368af0c129 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1324,24 +1324,6 @@ struct netxen_adapter { const struct firmware *fw; }; -/* - * NetXen dma watchdog control structure - * - * Bit 0 : enabled => R/O: 1 watchdog active, 0 inactive - * Bit 1 : disable_request => 1 req disable dma watchdog - * Bit 2 : enable_request => 1 req enable dma watchdog - * Bit 3-31 : unused - */ - -#define netxen_set_dma_watchdog_disable_req(config_word) \ - _netxen_set_bits(config_word, 1, 1, 1) -#define netxen_set_dma_watchdog_enable_req(config_word) \ - _netxen_set_bits(config_word, 2, 1, 1) -#define netxen_get_dma_watchdog_enabled(config_word) \ - ((config_word) & 0x1) -#define netxen_get_dma_watchdog_disabled(config_word) \ - (((config_word) >> 1) & 0x1) - int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter); int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter); int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter); @@ -1402,8 +1384,9 @@ unsigned long netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, unsigned long long addr); /* Functions from netxen_nic_init.c */ -void netxen_free_adapter_offload(struct netxen_adapter *adapter); -int netxen_initialize_adapter_offload(struct netxen_adapter *adapter); +int netxen_init_dummy_dma(struct netxen_adapter *adapter); +void netxen_free_dummy_dma(struct netxen_adapter *adapter); + int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val); int netxen_load_firmware(struct netxen_adapter *adapter); int netxen_need_fw_reset(struct netxen_adapter *adapter); @@ -1510,56 +1493,6 @@ static inline void get_brd_name_by_type(u32 type, char *name) name = "Unknown"; } -static inline int -dma_watchdog_shutdown_request(struct netxen_adapter *adapter) -{ - u32 ctrl; - - /* check if already inactive */ - ctrl = adapter->hw_read_wx(adapter, - NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL)); - - if (netxen_get_dma_watchdog_enabled(ctrl) == 0) - return 1; - - /* Send the disable request */ - netxen_set_dma_watchdog_disable_req(ctrl); - NXWR32(adapter, NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), ctrl); - - return 0; -} - -static inline int -dma_watchdog_shutdown_poll_result(struct netxen_adapter *adapter) -{ - u32 ctrl; - - ctrl = adapter->hw_read_wx(adapter, - NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL)); - - return (netxen_get_dma_watchdog_enabled(ctrl) == 0); -} - -static inline int -dma_watchdog_wakeup(struct netxen_adapter *adapter) -{ - u32 ctrl; - - ctrl = adapter->hw_read_wx(adapter, - NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL)); - - if (netxen_get_dma_watchdog_enabled(ctrl)) - return 1; - - /* send the wakeup request */ - netxen_set_dma_watchdog_enable_req(ctrl); - - NXWR32(adapter, NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), ctrl); - - return 0; -} - - static inline u32 netxen_tx_avail(struct nx_host_tx_ring *tx_ring) { smp_mb(); diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index 82410367564..a7328584a21 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h @@ -852,7 +852,7 @@ enum { #define NX_PEG_TUNE_MN_PRESENT 0x1 #define NX_PEG_TUNE_CAPABILITY (NETXEN_CAM_RAM(0x02c)) -#define NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL (0x14) +#define NETXEN_DMA_WATCHDOG_CTRL (NETXEN_CAM_RAM(0x14)) #define NETXEN_PEG_ALIVE_COUNTER (NETXEN_CAM_RAM(0xb0)) #define ISR_MSI_INT_TRIGGER(FUNC) (NETXEN_PCIX_PS_REG(PCIX_MSI_F(FUNC))) diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 5d7a2c45336..91358459adb 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -954,19 +954,20 @@ netxen_release_firmware(struct netxen_adapter *adapter) release_firmware(adapter->fw); } -int netxen_initialize_adapter_offload(struct netxen_adapter *adapter) +int netxen_init_dummy_dma(struct netxen_adapter *adapter) { - uint64_t addr; - uint32_t hi; - uint32_t lo; + u64 addr; + u32 hi, lo; - adapter->dummy_dma.addr = - pci_alloc_consistent(adapter->pdev, + if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) + return 0; + + adapter->dummy_dma.addr = pci_alloc_consistent(adapter->pdev, NETXEN_HOST_DUMMY_DMA_SIZE, &adapter->dummy_dma.phys_addr); if (adapter->dummy_dma.addr == NULL) { - printk("%s: ERROR: Could not allocate dummy DMA memory\n", - __func__); + dev_err(&adapter->pdev->dev, + "ERROR: Could not allocate dummy DMA memory\n"); return -ENOMEM; } @@ -977,29 +978,41 @@ int netxen_initialize_adapter_offload(struct netxen_adapter *adapter) NXWR32(adapter, CRB_HOST_DUMMY_BUF_ADDR_HI, hi); NXWR32(adapter, CRB_HOST_DUMMY_BUF_ADDR_LO, lo); - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { - uint32_t temp = 0; - NXWR32(adapter, CRB_HOST_DUMMY_BUF, temp); - } - return 0; } -void netxen_free_adapter_offload(struct netxen_adapter *adapter) +/* + * NetXen DMA watchdog control: + * + * Bit 0 : enabled => R/O: 1 watchdog active, 0 inactive + * Bit 1 : disable_request => 1 req disable dma watchdog + * Bit 2 : enable_request => 1 req enable dma watchdog + * Bit 3-31 : unused + */ +void netxen_free_dummy_dma(struct netxen_adapter *adapter) { int i = 100; + u32 ctrl; + + if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) + return; if (!adapter->dummy_dma.addr) return; - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { - do { - if (dma_watchdog_shutdown_request(adapter) == 1) - break; + ctrl = NXRD32(adapter, NETXEN_DMA_WATCHDOG_CTRL); + if ((ctrl & 0x1) != 0) { + NXWR32(adapter, NETXEN_DMA_WATCHDOG_CTRL, (ctrl | 0x2)); + + while ((ctrl & 0x1) != 0) { + msleep(50); - if (dma_watchdog_shutdown_poll_result(adapter) == 1) + + ctrl = NXRD32(adapter, NETXEN_DMA_WATCHDOG_CTRL); + + if (--i == 0) break; - } while (--i); + }; } if (i) { @@ -1008,10 +1021,8 @@ void netxen_free_adapter_offload(struct netxen_adapter *adapter) adapter->dummy_dma.addr, adapter->dummy_dma.phys_addr); adapter->dummy_dma.addr = NULL; - } else { - printk(KERN_ERR "%s: dma_watchdog_shutdown failed\n", - adapter->netdev->name); - } + } else + dev_err(&adapter->pdev->dev, "dma_watchdog_shutdown failed\n"); } int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val) diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 76bdd5cee43..fb976cbf9c7 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -745,7 +745,7 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) } - err = netxen_initialize_adapter_offload(adapter); + err = netxen_init_dummy_dma(adapter); if (err) return err; @@ -761,7 +761,7 @@ wait_init: /* Handshake with the card before we register the devices. */ err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); if (err) { - netxen_free_adapter_offload(adapter); + netxen_free_dummy_dma(adapter); return err; } @@ -1154,7 +1154,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err_out_disable_msi: netxen_teardown_intr(adapter); - netxen_free_adapter_offload(adapter); + netxen_free_dummy_dma(adapter); err_out_iounmap: netxen_cleanup_pci_map(adapter); @@ -1189,7 +1189,7 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) } if (adapter->portnum == 0) - netxen_free_adapter_offload(adapter); + netxen_free_dummy_dma(adapter); netxen_teardown_intr(adapter); netxen_free_sds_rings(&adapter->recv_ctx); -- cgit v1.2.3-18-g5258 From 1bcfd790c49341fcbdce9526a007c4e2b9d54c7c Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 26 Jul 2009 20:07:40 +0000 Subject: netxen: refactor tso code o move all tso / checksum offload code into netxen_tso_check(). o optimize the tso header copy into simple loop. o clean up unnecessary unions from cmd_desc_type0 struct. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 49 +++-------- drivers/net/netxen/netxen_nic_main.c | 152 +++++++++++++++++------------------ 2 files changed, 83 insertions(+), 118 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 3368af0c129..3a4cbd5dcbd 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -316,56 +316,29 @@ struct netxen_ring_ctx { cpu_to_le16(((_flags) & 0x7f) | (((_opcode) & 0x3f) << 7)) #define netxen_set_tx_frags_len(_desc, _frags, _len) \ - (_desc)->num_of_buffers_total_length = \ + (_desc)->nfrags__length = \ cpu_to_le32(((_frags) & 0xff) | (((_len) & 0xffffff) << 8)) struct cmd_desc_type0 { u8 tcp_hdr_offset; /* For LSO only */ u8 ip_hdr_offset; /* For LSO only */ - /* Bit pattern: 0-6 flags, 7-12 opcode, 13-15 unused */ - __le16 flags_opcode; - /* Bit pattern: 0-7 total number of segments, - 8-31 Total size of the packet */ - __le32 num_of_buffers_total_length; - union { - struct { - __le32 addr_low_part2; - __le32 addr_high_part2; - }; - __le64 addr_buffer2; - }; + __le16 flags_opcode; /* 15:13 unused, 12:7 opcode, 6:0 flags */ + __le32 nfrags__length; /* 31:8 total len, 7:0 frag count */ + + __le64 addr_buffer2; - __le16 reference_handle; /* changed to u16 to add mss */ - __le16 mss; /* passed by NDIS_PACKET for LSO */ - /* Bit pattern 0-3 port, 0-3 ctx id */ - u8 port_ctxid; + __le16 reference_handle; + __le16 mss; + u8 port_ctxid; /* 7:4 ctxid 3:0 port */ u8 total_hdr_length; /* LSO only : MAC+IP+TCP Hdr size */ __le16 conn_id; /* IPSec offoad only */ - union { - struct { - __le32 addr_low_part3; - __le32 addr_high_part3; - }; - __le64 addr_buffer3; - }; - union { - struct { - __le32 addr_low_part1; - __le32 addr_high_part1; - }; - __le64 addr_buffer1; - }; + __le64 addr_buffer3; + __le64 addr_buffer1; __le16 buffer_length[4]; - union { - struct { - __le32 addr_low_part4; - __le32 addr_high_part4; - }; - __le64 addr_buffer4; - }; + __le64 addr_buffer4; __le64 unused; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index fb976cbf9c7..381bd8f027c 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1310,13 +1310,18 @@ static int netxen_nic_close(struct net_device *netdev) return 0; } -static bool netxen_tso_check(struct net_device *netdev, - struct cmd_desc_type0 *desc, struct sk_buff *skb) +static void +netxen_tso_check(struct net_device *netdev, + struct nx_host_tx_ring *tx_ring, + struct cmd_desc_type0 *first_desc, + struct sk_buff *skb) { - bool tso = false; u8 opcode = TX_ETHER_PKT; __be16 protocol = skb->protocol; u16 flags = 0; + u32 producer; + int copied, offset, copy_len, hdr_len = 0, tso = 0; + struct cmd_desc_type0 *hwdesc; if (protocol == cpu_to_be16(ETH_P_8021Q)) { struct vlan_ethhdr *vh = (struct vlan_ethhdr *)skb->data; @@ -1327,13 +1332,14 @@ static bool netxen_tso_check(struct net_device *netdev, if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) && skb_shinfo(skb)->gso_size > 0) { - desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); - desc->total_hdr_length = - skb_transport_offset(skb) + tcp_hdrlen(skb); + hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + + first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); + first_desc->total_hdr_length = hdr_len; opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ? TX_TCP_LSO6 : TX_TCP_LSO; - tso = true; + tso = 1; } else if (skb->ip_summed == CHECKSUM_PARTIAL) { u8 l4proto; @@ -1354,10 +1360,39 @@ static bool netxen_tso_check(struct net_device *netdev, opcode = TX_UDPV6_PKT; } } - desc->tcp_hdr_offset = skb_transport_offset(skb); - desc->ip_hdr_offset = skb_network_offset(skb); - netxen_set_tx_flags_opcode(desc, flags, opcode); - return tso; + first_desc->tcp_hdr_offset = skb_transport_offset(skb); + first_desc->ip_hdr_offset = skb_network_offset(skb); + netxen_set_tx_flags_opcode(first_desc, flags, opcode); + + if (!tso) + return; + + /* For LSO, we need to copy the MAC/IP/TCP headers into + * the descriptor ring + */ + producer = tx_ring->producer; + copied = 0; + offset = 2; + + while (copied < hdr_len) { + + copy_len = min((int)sizeof(struct cmd_desc_type0) - offset, + (hdr_len - copied)); + + hwdesc = &tx_ring->desc_head[producer]; + tx_ring->cmd_buf_arr[producer].skb = NULL; + + skb_copy_from_linear_data_offset(skb, copied, + (char *)hwdesc + offset, copy_len); + + copied += copy_len; + offset = 0; + + producer = get_next_index(producer, tx_ring->num_desc); + } + + tx_ring->producer = producer; + barrier(); } static void @@ -1381,9 +1416,8 @@ netxen_clean_tx_dma_mapping(struct pci_dev *pdev, static inline void netxen_clear_cmddesc(u64 *desc) { - int i; - for (i = 0; i < 8; i++) - desc[i] = 0ULL; + desc[0] = 0ULL; + desc[2] = 0ULL; } static int @@ -1391,18 +1425,18 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct netxen_adapter *adapter = netdev_priv(netdev); struct nx_host_tx_ring *tx_ring = adapter->tx_ring; - unsigned int first_seg_len = skb->len - skb->data_len; + struct skb_frag_struct *frag; struct netxen_cmd_buffer *pbuf; struct netxen_skb_frag *buffrag; - struct cmd_desc_type0 *hwdesc; - struct pci_dev *pdev = adapter->pdev; + struct cmd_desc_type0 *hwdesc, *first_desc; + struct pci_dev *pdev; dma_addr_t temp_dma; int i, k; + unsigned long offset; u32 producer; - int frag_count, no_of_desc; + int len, frag_count, no_of_desc; u32 num_txd = tx_ring->num_desc; - bool is_tso = false; frag_count = skb_shinfo(skb)->nr_frags + 1; @@ -1416,32 +1450,30 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) producer = tx_ring->producer; - hwdesc = &tx_ring->desc_head[producer]; - netxen_clear_cmddesc((u64 *)hwdesc); - pbuf = &tx_ring->cmd_buf_arr[producer]; + pdev = adapter->pdev; + len = skb->len - skb->data_len; - is_tso = netxen_tso_check(netdev, hwdesc, skb); + temp_dma = pci_map_single(pdev, skb->data, len, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, temp_dma)) + goto drop_packet; + pbuf = &tx_ring->cmd_buf_arr[producer]; pbuf->skb = skb; pbuf->frag_count = frag_count; - buffrag = &pbuf->frag_array[0]; - temp_dma = pci_map_single(pdev, skb->data, first_seg_len, - PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(pdev, temp_dma)) - goto drop_packet; + buffrag = &pbuf->frag_array[0]; buffrag->dma = temp_dma; - buffrag->length = first_seg_len; + buffrag->length = len; + + first_desc = hwdesc = &tx_ring->desc_head[producer]; + netxen_clear_cmddesc((u64 *)hwdesc); netxen_set_tx_frags_len(hwdesc, frag_count, skb->len); netxen_set_tx_port(hwdesc, adapter->portnum); - hwdesc->buffer_length[0] = cpu_to_le16(first_seg_len); - hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma); + hwdesc->buffer_length[0] = cpu_to_le16(len); + hwdesc->addr_buffer1 = cpu_to_le64(temp_dma); for (i = 1, k = 1; i < frag_count; i++, k++) { - struct skb_frag_struct *frag; - int len, temp_len; - unsigned long offset; /* move to next desc. if there is a need */ if ((i & 0x3) == 0) { @@ -1452,11 +1484,11 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) pbuf = &tx_ring->cmd_buf_arr[producer]; pbuf->skb = NULL; } + buffrag = &pbuf->frag_array[i]; frag = &skb_shinfo(skb)->frags[i - 1]; len = frag->size; offset = frag->page_offset; - temp_len = len; temp_dma = pci_map_page(pdev, frag->page, offset, len, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(pdev, temp_dma)) { @@ -1464,11 +1496,10 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) goto drop_packet; } - buffrag++; buffrag->dma = temp_dma; - buffrag->length = temp_len; + buffrag->length = len; - hwdesc->buffer_length[k] = cpu_to_le16(temp_len); + hwdesc->buffer_length[k] = cpu_to_le16(len); switch (k) { case 0: hwdesc->addr_buffer1 = cpu_to_le64(temp_dma); @@ -1483,53 +1514,14 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) hwdesc->addr_buffer4 = cpu_to_le64(temp_dma); break; } - frag++; } - producer = get_next_index(producer, num_txd); + tx_ring->producer = get_next_index(producer, num_txd); - /* For LSO, we need to copy the MAC/IP/TCP headers into - * the descriptor ring - */ - if (is_tso) { - int hdr_len, first_hdr_len, more_hdr; - hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); - if (hdr_len > (sizeof(struct cmd_desc_type0) - 2)) { - first_hdr_len = sizeof(struct cmd_desc_type0) - 2; - more_hdr = 1; - } else { - first_hdr_len = hdr_len; - more_hdr = 0; - } - /* copy the MAC/IP/TCP headers to the cmd descriptor list */ - hwdesc = &tx_ring->desc_head[producer]; - pbuf = &tx_ring->cmd_buf_arr[producer]; - pbuf->skb = NULL; - - /* copy the first 64 bytes */ - memcpy(((void *)hwdesc) + 2, - (void *)(skb->data), first_hdr_len); - producer = get_next_index(producer, num_txd); - - if (more_hdr) { - hwdesc = &tx_ring->desc_head[producer]; - pbuf = &tx_ring->cmd_buf_arr[producer]; - pbuf->skb = NULL; - /* copy the next 64 bytes - should be enough except - * for pathological case - */ - skb_copy_from_linear_data_offset(skb, first_hdr_len, - hwdesc, - (hdr_len - - first_hdr_len)); - producer = get_next_index(producer, num_txd); - } - } - - tx_ring->producer = producer; - adapter->stats.txbytes += skb->len; + netxen_tso_check(netdev, tx_ring, first_desc, skb); netxen_nic_update_cmd_producer(adapter, tx_ring); + adapter->stats.txbytes += skb->len; adapter->stats.xmitcalled++; return NETDEV_TX_OK; -- cgit v1.2.3-18-g5258 From 24767ab16913bc27ba7a85698e5c0f591368647d Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Mon, 27 Jul 2009 11:08:00 -0700 Subject: netxen: Add default and limit macros for ring sizes. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 19 +++++++++++++------ drivers/net/netxen/netxen_nic_ethtool.c | 21 +++++++++++---------- drivers/net/netxen/netxen_nic_main.c | 33 +++++++++++++++++---------------- 3 files changed, 41 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 3a4cbd5dcbd..e017827472a 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -200,13 +200,20 @@ #define RCV_RING_JUMBO 1 #define RCV_RING_LRO 2 -#define MAX_CMD_DESCRIPTORS 4096 -#define MAX_RCV_DESCRIPTORS 16384 -#define MAX_CMD_DESCRIPTORS_HOST 1024 -#define MAX_RCV_DESCRIPTORS_1G 2048 -#define MAX_RCV_DESCRIPTORS_10G 4096 -#define MAX_JUMBO_RCV_DESCRIPTORS 1024 +#define MIN_CMD_DESCRIPTORS 64 +#define MIN_RCV_DESCRIPTORS 64 +#define MIN_JUMBO_DESCRIPTORS 32 + +#define MAX_CMD_DESCRIPTORS 1024 +#define MAX_RCV_DESCRIPTORS_1G 4096 +#define MAX_RCV_DESCRIPTORS_10G 8192 +#define MAX_JUMBO_RCV_DESCRIPTORS_1G 512 +#define MAX_JUMBO_RCV_DESCRIPTORS_10G 1024 #define MAX_LRO_RCV_DESCRIPTORS 8 + +#define DEFAULT_RCV_DESCRIPTORS_1G 2048 +#define DEFAULT_RCV_DESCRIPTORS_10G 4096 + #define NETXEN_CTX_SIGNATURE 0xdee0 #define NETXEN_CTX_SIGNATURE_V2 0x0002dee0 #define NETXEN_CTX_RESET 0xbad0 diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index e16ea46c24b..80d286db8eb 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -494,20 +494,21 @@ netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) { struct netxen_adapter *adapter = netdev_priv(dev); - ring->rx_pending = 0; - ring->rx_jumbo_pending = 0; - ring->rx_pending += adapter->recv_ctx. - rds_rings[RCV_RING_NORMAL].num_desc; - ring->rx_jumbo_pending += adapter->recv_ctx. - rds_rings[RCV_RING_JUMBO].num_desc; + ring->rx_pending = adapter->num_rxd; + ring->rx_jumbo_pending = adapter->num_jumbo_rxd; + ring->rx_jumbo_pending += adapter->num_lro_rxd; ring->tx_pending = adapter->num_txd; - if (adapter->ahw.port_type == NETXEN_NIC_GBE) + if (adapter->ahw.port_type == NETXEN_NIC_GBE) { ring->rx_max_pending = MAX_RCV_DESCRIPTORS_1G; - else + ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_1G; + } else { ring->rx_max_pending = MAX_RCV_DESCRIPTORS_10G; - ring->tx_max_pending = MAX_CMD_DESCRIPTORS_HOST; - ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS; + ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_10G; + } + + ring->tx_max_pending = MAX_CMD_DESCRIPTORS; + ring->rx_mini_max_pending = 0; ring->rx_mini_pending = 0; } diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 381bd8f027c..1aa850a0b89 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -283,12 +283,16 @@ nx_update_dma_mask(struct netxen_adapter *adapter) return 0; } -static void netxen_check_options(struct netxen_adapter *adapter) +static void +netxen_check_options(struct netxen_adapter *adapter) { - if (adapter->ahw.port_type == NETXEN_NIC_XGBE) - adapter->num_rxd = MAX_RCV_DESCRIPTORS_10G; - else if (adapter->ahw.port_type == NETXEN_NIC_GBE) - adapter->num_rxd = MAX_RCV_DESCRIPTORS_1G; + if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { + adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G; + adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G; + } else if (adapter->ahw.port_type == NETXEN_NIC_GBE) { + adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G; + adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G; + } adapter->msix_supported = 0; if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { @@ -306,11 +310,15 @@ static void netxen_check_options(struct netxen_adapter *adapter) } } - adapter->num_txd = MAX_CMD_DESCRIPTORS_HOST; - adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS; - adapter->num_lro_rxd = MAX_LRO_RCV_DESCRIPTORS; + adapter->num_txd = MAX_CMD_DESCRIPTORS; - return; + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + adapter->num_lro_rxd = MAX_LRO_RCV_DESCRIPTORS; + adapter->max_rds_rings = 3; + } else { + adapter->num_lro_rxd = 0; + adapter->max_rds_rings = 2; + } } static int @@ -908,11 +916,6 @@ netxen_nic_attach(struct netxen_adapter *adapter) return -EIO; } - if (adapter->fw_major < 4) - adapter->max_rds_rings = 3; - else - adapter->max_rds_rings = 2; - err = netxen_alloc_sw_resources(adapter); if (err) { printk(KERN_ERR "%s: Error in setting sw resources\n", @@ -1923,8 +1926,6 @@ static struct pci_driver netxen_driver = { #endif }; -/* Driver Registration on NetXen card */ - static int __init netxen_init_module(void) { printk(KERN_INFO "%s\n", netxen_nic_driver_string); -- cgit v1.2.3-18-g5258 From 4f96b988e8d404b8b32aefed27503b4538949a3c Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 26 Jul 2009 20:07:42 +0000 Subject: netxen: clean up firmware version checks NX2031 firmware version will never be > 4.0.0, so replace (adapter->fw_major < 4) checks with pci revision ID check. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 2 +- drivers/net/netxen/netxen_nic_ctx.c | 6 +++--- drivers/net/netxen/netxen_nic_hw.c | 1 - drivers/net/netxen/netxen_nic_init.c | 2 +- drivers/net/netxen/netxen_nic_main.c | 6 +++--- 5 files changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index e017827472a..b58d0b21742 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1299,7 +1299,7 @@ struct netxen_adapter { nx_nic_intr_coalesce_t coal; - u32 fw_major; + u32 resv5; u32 fw_version; const struct firmware *fw; }; diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 9f8ae4719e2..9e0469643d3 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -647,7 +647,7 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) } rds_ring->desc_head = (struct rcv_desc *)addr; - if (adapter->fw_major < 4) + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) rds_ring->crb_rcv_producer = recv_crb_registers[port].crb_rcv_producer[ring]; } @@ -675,7 +675,7 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) } - if (adapter->fw_major >= 4) { + if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) { err = nx_fw_cmd_create_rx_ctx(adapter); if (err) goto err_out_free; @@ -705,7 +705,7 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter) int port = adapter->portnum; - if (adapter->fw_major >= 4) { + if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) { nx_fw_cmd_destroy_rx_ctx(adapter); nx_fw_cmd_destroy_tx_ctx(adapter); } else { diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 088611bb5bd..ddb9deb12b3 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -2045,7 +2045,6 @@ void netxen_nic_get_firmware_info(struct netxen_adapter *adapter) fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR); fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB); - adapter->fw_major = fw_major; adapter->fw_version = NETXEN_VERSION_CODE(fw_major, fw_minor, fw_build); if (adapter->portnum == 0) { diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 91358459adb..ef7f1b1b845 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1477,7 +1477,7 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid, NXWR32(adapter, rds_ring->crb_rcv_producer, (producer-1) & (rds_ring->num_desc-1)); - if (adapter->fw_major < 4) { + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { /* * Write a doorbell msg to tell phanmon of change in * receive ring producer diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 1aa850a0b89..5d52630ecd8 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -932,7 +932,7 @@ netxen_nic_attach(struct netxen_adapter *adapter) goto err_out_free_sw; } - if (adapter->fw_major < 4) { + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { tx_ring = adapter->tx_ring; tx_ring->crb_cmd_producer = crb_cmd_producer[adapter->portnum]; tx_ring->crb_cmd_consumer = crb_cmd_consumer[adapter->portnum]; @@ -1103,7 +1103,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * See if the firmware gave us a virtual-physical port mapping. */ adapter->physical_port = adapter->portnum; - if (adapter->fw_major < 4) { + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { i = NXRD32(adapter, CRB_V2P(adapter->portnum)); if (i != 0x55555555) adapter->physical_port = i; @@ -1727,7 +1727,7 @@ static irqreturn_t netxen_intr(int irq, void *data) } /* clear interrupt */ - if (adapter->fw_major < 4) + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) netxen_nic_disable_int(sds_ring); adapter->pci_write_immediate(adapter, -- cgit v1.2.3-18-g5258 From f17443f4b01659a5c44d5fc6f5c502c39c293959 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 26 Jul 2009 20:07:43 +0000 Subject: netxen: refactor net_device setup code Move all net_device initialization into one function netxen_setup_netdev(). Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_main.c | 138 +++++++++++++++++++---------------- 1 file changed, 75 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 5d52630ecd8..43a99f6a23d 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -66,7 +66,7 @@ static int netxen_nic_open(struct net_device *netdev); static int netxen_nic_close(struct net_device *netdev); static int netxen_nic_xmit_frame(struct sk_buff *, struct net_device *); static void netxen_tx_timeout(struct net_device *netdev); -static void netxen_tx_timeout_task(struct work_struct *work); +static void netxen_reset_task(struct work_struct *work); static void netxen_watchdog(unsigned long); static int netxen_nic_poll(struct napi_struct *napi, int budget); #ifdef CONFIG_NET_POLL_CONTROLLER @@ -182,7 +182,7 @@ netxen_napi_add(struct netxen_adapter *adapter, struct net_device *netdev) struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; if (netxen_alloc_sds_rings(recv_ctx, adapter->max_sds_rings)) - return 1; + return -ENOMEM; for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; @@ -981,6 +981,68 @@ netxen_nic_detach(struct netxen_adapter *adapter) adapter->is_up = 0; } +static int +netxen_setup_netdev(struct netxen_adapter *adapter, + struct net_device *netdev) +{ + int err = 0; + struct pci_dev *pdev = adapter->pdev; + + adapter->rx_csum = 1; + adapter->mc_enabled = 0; + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + adapter->max_mc_count = 38; + else + adapter->max_mc_count = 16; + + netdev->netdev_ops = &netxen_netdev_ops; + netdev->watchdog_timeo = 2*HZ; + + netxen_nic_change_mtu(netdev, netdev->mtu); + + SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops); + + netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); + netdev->features |= (NETIF_F_GRO); + netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); + + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { + netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6); + netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6); + } + + if (adapter->pci_using_dac) { + netdev->features |= NETIF_F_HIGHDMA; + netdev->vlan_features |= NETIF_F_HIGHDMA; + } + + netdev->irq = adapter->msix_entries[0].vector; + + err = netxen_napi_add(adapter, netdev); + if (err) + return err; + + init_timer(&adapter->watchdog_timer); + adapter->watchdog_timer.function = &netxen_watchdog; + adapter->watchdog_timer.data = (unsigned long)adapter; + INIT_WORK(&adapter->watchdog_task, netxen_watchdog_task); + INIT_WORK(&adapter->tx_timeout_task, netxen_reset_task); + + if (netxen_read_mac_addr(adapter)) + dev_warn(&pdev->dev, "failed to read mac addr\n"); + + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + err = register_netdev(netdev); + if (err) { + dev_err(&pdev->dev, "failed to register net device\n"); + return err; + } + + return 0; +} + static int __devinit netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1018,9 +1080,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev = alloc_etherdev(sizeof(struct netxen_adapter)); if(!netdev) { - printk(KERN_ERR"%s: Failed to allocate memory for the " - "device block.Check system memory resource" - " usage.\n", netxen_nic_driver_name); + dev_err(&pdev->dev, "failed to allocate net_device\n"); + err = -ENOMEM; goto err_out_free_res; } @@ -1048,38 +1109,10 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* This will be reset for mezz cards */ adapter->portnum = pci_func_id; - adapter->rx_csum = 1; - adapter->mc_enabled = 0; - if (NX_IS_REVISION_P3(revision_id)) - adapter->max_mc_count = 38; - else - adapter->max_mc_count = 16; - - netdev->netdev_ops = &netxen_netdev_ops; - netdev->watchdog_timeo = 2*HZ; - - netxen_nic_change_mtu(netdev, netdev->mtu); - - SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops); - - netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); - netdev->features |= (NETIF_F_GRO); - netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); - - if (NX_IS_REVISION_P3(revision_id)) { - netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6); - netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6); - } - - if (adapter->pci_using_dac) { - netdev->features |= NETIF_F_HIGHDMA; - netdev->vlan_features |= NETIF_F_HIGHDMA; - } - if (netxen_nic_get_board_info(adapter) != 0) { - printk("%s: Error getting board config info.\n", - netxen_nic_driver_name); - err = -EIO; + err = netxen_nic_get_board_info(adapter); + if (err) { + dev_err(&pdev->dev, "Error getting board config info.\n"); goto err_out_iounmap; } @@ -1099,6 +1132,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = netxen_start_firmware(adapter, 1); if (err) goto err_out_iounmap; + /* * See if the firmware gave us a virtual-physical port mapping. */ @@ -1113,31 +1147,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netxen_setup_intr(adapter); - netdev->irq = adapter->msix_entries[0].vector; - - if (netxen_napi_add(adapter, netdev)) - goto err_out_disable_msi; - - init_timer(&adapter->watchdog_timer); - adapter->watchdog_timer.function = &netxen_watchdog; - adapter->watchdog_timer.data = (unsigned long)adapter; - INIT_WORK(&adapter->watchdog_task, netxen_watchdog_task); - INIT_WORK(&adapter->tx_timeout_task, netxen_tx_timeout_task); - - err = netxen_read_mac_addr(adapter); + err = netxen_setup_netdev(adapter, netdev); if (err) - dev_warn(&pdev->dev, "failed to read mac addr\n"); - - netif_carrier_off(netdev); - netif_stop_queue(netdev); - - if ((err = register_netdev(netdev))) { - printk(KERN_ERR "%s: register_netdev failed port #%d" - " aborting\n", netxen_nic_driver_name, - adapter->portnum); - err = -EIO; goto err_out_disable_msi; - } pci_set_drvdata(pdev, adapter); @@ -1656,10 +1668,13 @@ static void netxen_tx_timeout(struct net_device *netdev) { struct netxen_adapter *adapter = (struct netxen_adapter *) netdev_priv(netdev); + + dev_err(&netdev->dev, "transmit timeout, resetting.\n"); + SCHEDULE_WORK(&adapter->tx_timeout_task); } -static void netxen_tx_timeout_task(struct work_struct *work) +static void netxen_reset_task(struct work_struct *work) { struct netxen_adapter *adapter = container_of(work, struct netxen_adapter, tx_timeout_task); @@ -1667,9 +1682,6 @@ static void netxen_tx_timeout_task(struct work_struct *work) if (!netif_running(adapter->netdev)) return; - printk(KERN_ERR "%s %s: transmit timeout, resetting.\n", - netxen_nic_driver_name, adapter->netdev->name); - netxen_napi_disable(adapter); adapter->netdev->trans_start = jiffies; -- cgit v1.2.3-18-g5258 From 9b08beba2d1bf7e4598deba2800a9ea5e5c3a282 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 26 Jul 2009 20:07:44 +0000 Subject: netxen: fix skb alloc size for legacy firmware Request 1532 bytes skb data size for NX3031. NX2031 firmware needs 1760 sized buffers. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 11 +++-------- drivers/net/netxen/netxen_nic_init.c | 13 +++++++++---- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index b58d0b21742..e7702f60334 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -143,18 +143,13 @@ #define NX_ETHERMTU 1500 #define NX_MAX_ETHERHDR 32 /* This contains some padding */ -#define NX_RX_NORMAL_BUF_MAX_LEN (NX_MAX_ETHERHDR + NX_ETHERMTU) +#define NX_P2_RX_BUF_MAX_LEN 1760 +#define NX_P3_RX_BUF_MAX_LEN (NX_MAX_ETHERHDR + NX_ETHERMTU) #define NX_P2_RX_JUMBO_BUF_MAX_LEN (NX_MAX_ETHERHDR + P2_MAX_MTU) #define NX_P3_RX_JUMBO_BUF_MAX_LEN (NX_MAX_ETHERHDR + P3_MAX_MTU) #define NX_CT_DEFAULT_RX_BUF_LEN 2048 -#define MAX_RX_BUFFER_LENGTH 1760 -#define MAX_RX_JUMBO_BUFFER_LENGTH 8062 -#define MAX_RX_LRO_BUFFER_LENGTH (8062) -#define RX_DMA_MAP_LEN (MAX_RX_BUFFER_LENGTH - 2) -#define RX_JUMBO_DMA_MAP_LEN \ - (MAX_RX_JUMBO_BUFFER_LENGTH - 2) -#define RX_LRO_DMA_MAP_LEN (MAX_RX_LRO_BUFFER_LENGTH - 2) +#define NX_RX_LRO_BUFFER_LENGTH (8060) /* * Maximum number of ring contexts diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index ef7f1b1b845..a6b244a9f4a 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -247,9 +247,14 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter) rds_ring->skb_size = NX_CT_DEFAULT_RX_BUF_LEN; } else { - rds_ring->dma_size = RX_DMA_MAP_LEN; + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + rds_ring->dma_size = + NX_P3_RX_BUF_MAX_LEN; + else + rds_ring->dma_size = + NX_P2_RX_BUF_MAX_LEN; rds_ring->skb_size = - MAX_RX_BUFFER_LENGTH; + rds_ring->dma_size + NET_IP_ALIGN; } break; @@ -267,8 +272,8 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter) case RCV_RING_LRO: rds_ring->num_desc = adapter->num_lro_rxd; - rds_ring->dma_size = RX_LRO_DMA_MAP_LEN; - rds_ring->skb_size = MAX_RX_LRO_BUFFER_LENGTH; + rds_ring->dma_size = NX_RX_LRO_BUFFER_LENGTH; + rds_ring->skb_size = rds_ring->dma_size + NET_IP_ALIGN; break; } -- cgit v1.2.3-18-g5258 From 028afe719855a157e32450c36b7a12e1f9e85abe Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 26 Jul 2009 20:07:45 +0000 Subject: netxen: add vlan tx acceleration support Enable vlan tx acceleration for NX3031 if firmware advertises capability. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 11 +++++++- drivers/net/netxen/netxen_nic_main.c | 52 ++++++++++++++++++++++++++++++++---- 2 files changed, 57 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index e7702f60334..d01cc092450 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -304,6 +304,10 @@ struct netxen_ring_ctx { #define FLAGS_IPSEC_SA_ADD 0x04 #define FLAGS_IPSEC_SA_DELETE 0x08 #define FLAGS_VLAN_TAGGED 0x10 +#define FLAGS_VLAN_OOB 0x40 + +#define netxen_set_tx_vlan_tci(cmd_desc, v) \ + (cmd_desc)->vlan_TCI = cpu_to_le16(v); #define netxen_set_cmd_desc_port(cmd_desc, var) \ ((cmd_desc)->port_ctxid |= ((var) & 0x0F)) @@ -342,7 +346,9 @@ struct cmd_desc_type0 { __le64 addr_buffer4; - __le64 unused; + __le16 vlan_TCI; + __le16 reserved; + __le32 reserved2; } __attribute__ ((aligned(64))); @@ -1111,6 +1117,9 @@ typedef struct { #define NX_FW_CAPABILITY_LINK_NOTIFICATION (1 << 5) #define NX_FW_CAPABILITY_SWITCHING (1 << 6) +#define NX_FW_CAPABILITY_PEXQ (1 << 7) +#define NX_FW_CAPABILITY_BDG (1 << 8) +#define NX_FW_CAPABILITY_FVLANTX (1 << 9) /* module types */ #define LINKEVENT_MODULE_NOT_PRESENT 1 diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 43a99f6a23d..ff7ee9c43ef 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1016,6 +1016,9 @@ netxen_setup_netdev(struct netxen_adapter *adapter, netdev->vlan_features |= NETIF_F_HIGHDMA; } + if (adapter->capabilities & NX_FW_CAPABILITY_FVLANTX) + netdev->features |= (NETIF_F_HW_VLAN_TX); + netdev->irq = adapter->msix_entries[0].vector; err = netxen_napi_add(adapter, netdev); @@ -1333,15 +1336,24 @@ netxen_tso_check(struct net_device *netdev, { u8 opcode = TX_ETHER_PKT; __be16 protocol = skb->protocol; - u16 flags = 0; + u16 flags = 0, vid = 0; u32 producer; - int copied, offset, copy_len, hdr_len = 0, tso = 0; + int copied, offset, copy_len, hdr_len = 0, tso = 0, vlan_oob = 0; struct cmd_desc_type0 *hwdesc; + struct vlan_ethhdr *vh; if (protocol == cpu_to_be16(ETH_P_8021Q)) { - struct vlan_ethhdr *vh = (struct vlan_ethhdr *)skb->data; + + vh = (struct vlan_ethhdr *)skb->data; protocol = vh->h_vlan_encapsulated_proto; flags = FLAGS_VLAN_TAGGED; + + } else if (vlan_tx_tag_present(skb)) { + + flags = FLAGS_VLAN_OOB; + vid = vlan_tx_tag_get(skb); + netxen_set_tx_vlan_tci(first_desc, vid); + vlan_oob = 1; } if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) && @@ -1351,6 +1363,13 @@ netxen_tso_check(struct net_device *netdev, first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); first_desc->total_hdr_length = hdr_len; + if (vlan_oob) { + first_desc->total_hdr_length += VLAN_HLEN; + first_desc->tcp_hdr_offset = VLAN_HLEN; + first_desc->ip_hdr_offset = VLAN_HLEN; + /* Only in case of TSO on vlan device */ + flags |= FLAGS_VLAN_TAGGED; + } opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ? TX_TCP_LSO6 : TX_TCP_LSO; @@ -1375,8 +1394,9 @@ netxen_tso_check(struct net_device *netdev, opcode = TX_UDPV6_PKT; } } - first_desc->tcp_hdr_offset = skb_transport_offset(skb); - first_desc->ip_hdr_offset = skb_network_offset(skb); + + first_desc->tcp_hdr_offset += skb_transport_offset(skb); + first_desc->ip_hdr_offset += skb_network_offset(skb); netxen_set_tx_flags_opcode(first_desc, flags, opcode); if (!tso) @@ -1389,6 +1409,28 @@ netxen_tso_check(struct net_device *netdev, copied = 0; offset = 2; + if (vlan_oob) { + /* Create a TSO vlan header template for firmware */ + + hwdesc = &tx_ring->desc_head[producer]; + tx_ring->cmd_buf_arr[producer].skb = NULL; + + copy_len = min((int)sizeof(struct cmd_desc_type0) - offset, + hdr_len + VLAN_HLEN); + + vh = (struct vlan_ethhdr *)((char *)hwdesc + 2); + skb_copy_from_linear_data(skb, vh, 12); + vh->h_vlan_proto = htons(ETH_P_8021Q); + vh->h_vlan_TCI = htons(vid); + skb_copy_from_linear_data_offset(skb, 12, + (char *)vh + 16, copy_len - 16); + + copied = copy_len; + offset = 0; + + producer = get_next_index(producer, tx_ring->num_desc); + } + while (copied < hdr_len) { copy_len = min((int)sizeof(struct cmd_desc_type0) - offset, -- cgit v1.2.3-18-g5258 From 7042cd8f148345bfca6c336f009c96a416674f5e Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Mon, 27 Jul 2009 11:15:54 -0700 Subject: netxen: support for ethtool set ringparam Add support for ethtool -G to tune rx and tx ring sizes per interface basis. This is only supported for NX3031 based cards. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 3 ++ drivers/net/netxen/netxen_nic_ethtool.c | 60 ++++++++++++++++++++++++++++++++- drivers/net/netxen/netxen_nic_main.c | 45 +++++++++++++++++++------ 3 files changed, 97 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index d01cc092450..b68a70dc720 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1427,6 +1427,9 @@ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev); void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter, struct nx_host_tx_ring *tx_ring); +/* Functions from netxen_nic_main.c */ +int netxen_nic_reset_context(struct netxen_adapter *); + /* * NetXen Board information */ diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 80d286db8eb..39a308c363c 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -490,7 +490,8 @@ netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, } static void -netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) +netxen_nic_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *ring) { struct netxen_adapter *adapter = netdev_priv(dev); @@ -513,6 +514,62 @@ netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) ring->rx_mini_pending = 0; } +static u32 +netxen_validate_ringparam(u32 val, u32 min, u32 max, char *r_name) +{ + u32 num_desc; + num_desc = max(val, min); + num_desc = min(num_desc, max); + num_desc = roundup_pow_of_two(num_desc); + + if (val != num_desc) { + printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n", + netxen_nic_driver_name, r_name, num_desc, val); + } + + return num_desc; +} + +static int +netxen_nic_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *ring) +{ + struct netxen_adapter *adapter = netdev_priv(dev); + u16 max_rcv_desc = MAX_RCV_DESCRIPTORS_10G; + u16 max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G; + u16 num_rxd, num_jumbo_rxd, num_txd; + + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) + return -EOPNOTSUPP; + + if (ring->rx_mini_pending) + return -EOPNOTSUPP; + + if (adapter->ahw.port_type == NETXEN_NIC_GBE) { + max_rcv_desc = MAX_RCV_DESCRIPTORS_1G; + max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G; + } + + num_rxd = netxen_validate_ringparam(ring->rx_pending, + MIN_RCV_DESCRIPTORS, max_rcv_desc, "rx"); + + num_jumbo_rxd = netxen_validate_ringparam(ring->rx_jumbo_pending, + MIN_JUMBO_DESCRIPTORS, max_jumbo_desc, "rx jumbo"); + + num_txd = netxen_validate_ringparam(ring->tx_pending, + MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx"); + + if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd && + num_jumbo_rxd == adapter->num_jumbo_rxd) + return 0; + + adapter->num_rxd = num_rxd; + adapter->num_jumbo_rxd = num_jumbo_rxd; + adapter->num_txd = num_txd; + + return netxen_nic_reset_context(adapter); +} + static void netxen_nic_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause) @@ -894,6 +951,7 @@ struct ethtool_ops netxen_nic_ethtool_ops = { .get_eeprom_len = netxen_nic_get_eeprom_len, .get_eeprom = netxen_nic_get_eeprom, .get_ringparam = netxen_nic_get_ringparam, + .set_ringparam = netxen_nic_set_ringparam, .get_pauseparam = netxen_nic_get_pauseparam, .set_pauseparam = netxen_nic_set_pauseparam, .set_tx_csum = ethtool_op_set_tx_csum, diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index ff7ee9c43ef..2bbefa6a37b 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -910,6 +910,9 @@ netxen_nic_attach(struct netxen_adapter *adapter) struct nx_host_rds_ring *rds_ring; struct nx_host_tx_ring *tx_ring; + if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) + return 0; + err = netxen_init_firmware(adapter); if (err != 0) { printk(KERN_ERR "Failed to init firmware\n"); @@ -973,6 +976,9 @@ err_out_free_sw: static void netxen_nic_detach(struct netxen_adapter *adapter) { + if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) + return; + netxen_free_hw_resources(adapter); netxen_release_rx_buffers(adapter); netxen_nic_free_irq(adapter); @@ -981,6 +987,30 @@ netxen_nic_detach(struct netxen_adapter *adapter) adapter->is_up = 0; } +int +netxen_nic_reset_context(struct netxen_adapter *adapter) +{ + int err = 0; + struct net_device *netdev = adapter->netdev; + + if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) { + + if (netif_running(netdev)) + netxen_nic_down(adapter, netdev); + + netxen_nic_detach(adapter); + + err = netxen_nic_attach(adapter); + if (err) + goto done; + + if (netif_running(netdev)) + err = netxen_nic_up(adapter, netdev); + } +done: + return err; +} + static int netxen_setup_netdev(struct netxen_adapter *adapter, struct net_device *netdev) @@ -1202,9 +1232,7 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) unregister_netdev(netdev); - if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) { - netxen_nic_detach(adapter); - } + netxen_nic_detach(adapter); if (adapter->portnum == 0) netxen_free_dummy_dma(adapter); @@ -1236,8 +1264,7 @@ netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state) if (netif_running(netdev)) netxen_nic_down(adapter, netdev); - if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) - netxen_nic_detach(adapter); + netxen_nic_detach(adapter); pci_save_state(pdev); @@ -1298,11 +1325,9 @@ static int netxen_nic_open(struct net_device *netdev) if (adapter->driver_mismatch) return -EIO; - if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) { - err = netxen_nic_attach(adapter); - if (err) - return err; - } + err = netxen_nic_attach(adapter); + if (err) + return err; err = netxen_nic_up(adapter, netdev); if (err) -- cgit v1.2.3-18-g5258 From c685bfc6c6bcb9bcc42d1345a3650d3ce5185c52 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 26 Jul 2009 20:07:47 +0000 Subject: netxen: update version to 4.0.41 Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index b68a70dc720..e22d0861589 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -57,8 +57,8 @@ #define _NETXEN_NIC_LINUX_MAJOR 4 #define _NETXEN_NIC_LINUX_MINOR 0 -#define _NETXEN_NIC_LINUX_SUBVERSION 30 -#define NETXEN_NIC_LINUX_VERSIONID "4.0.30" +#define _NETXEN_NIC_LINUX_SUBVERSION 41 +#define NETXEN_NIC_LINUX_VERSIONID "4.0.41" #define NETXEN_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c)) #define _major(v) (((v) >> 24) & 0xff) -- cgit v1.2.3-18-g5258 From 463889e27e6f4f097374a6c9de5611f520766dad Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 27 Jul 2009 06:13:30 +0000 Subject: drivers/net: Correct redundant test res has already been tested. It seems that this test should be on the recently returned value mmio. A simplified version of the semantic match that finds this problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; expression E; @@ if (x == NULL || ...) { ... when forall return ...; } ... when != \(x=E\|x--\|x++\|--x\|++x\|x-=E\|x+=E\|x|=E\|x&=E\|&x\) ( *x == NULL | *x != NULL ) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/ethoc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index ceb6a9c357a..4dbe5f17327 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -894,7 +894,7 @@ static int ethoc_probe(struct platform_device *pdev) mmio = devm_request_mem_region(&pdev->dev, res->start, res->end - res->start + 1, res->name); - if (!res) { + if (!mmio) { dev_err(&pdev->dev, "cannot request I/O memory space\n"); ret = -ENXIO; goto free; -- cgit v1.2.3-18-g5258 From 6cf5767c7107c606644503f3e95bc1855386a70f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 27 Jul 2009 11:38:52 -0700 Subject: drivers/atm: Correct redundant test str has already been tested. It seems that this test should be on the recently returned value snr. A simplified version of the semantic match that finds this problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; expression E; @@ if (x == NULL || ...) { ... when forall return ...; } ... when != \(x=E\|x--\|x++\|--x\|++x\|x-=E\|x+=E\|x|=E\|x&=E\|&x\) ( *x == NULL | *x != NULL ) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/atm/solos-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 9359613addc..307321b32cb 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -372,7 +372,7 @@ static int process_status(struct solos_card *card, int port, struct sk_buff *skb } snr = next_string(skb); - if (!str) + if (!snr) return -EIO; attn = next_string(skb); if (!attn) -- cgit v1.2.3-18-g5258 From eb87eaac52e916e28bcf3bd5974f3b581f6c0ae9 Mon Sep 17 00:00:00 2001 From: Lars Ericsson Date: Sat, 18 Jul 2009 20:21:52 +0200 Subject: rt2x00: Don't alter rt2x00dev->default_ant rt2x00dev->default_ant should be initialized once by the driver, and should not be changed afterwards. Because rt2x00lib_config_antenna() was using a reference to the struct antenna_setup it actually had the oppurtunity to change the default antenna setting and it actually did that during the validation. Instead of passing a pointer to antenna_setup the entire structure should be copied. Signed-off-by: Lars Ericsson Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00config.c | 12 ++++++------ drivers/net/wireless/rt2x00/rt2x00lib.h | 2 +- drivers/net/wireless/rt2x00/rt2x00link.c | 4 ++-- drivers/net/wireless/rt2x00/rt2x00mac.c | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index c6e0bcf78e9..3845316ccd3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -124,7 +124,7 @@ enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant, } void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant) + struct antenna_setup ant) { struct antenna_setup *def = &rt2x00dev->default_ant; struct antenna_setup *active = &rt2x00dev->link.ant.active; @@ -138,10 +138,10 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, * might have caused that we restore back to the already * active setting. If that has happened we can quit. */ - ant->rx = rt2x00lib_config_antenna_check(ant->rx, def->rx); - ant->tx = rt2x00lib_config_antenna_check(ant->tx, def->tx); + ant.rx = rt2x00lib_config_antenna_check(ant.rx, def->rx); + ant.tx = rt2x00lib_config_antenna_check(ant.tx, def->tx); - if (ant->rx == active->rx && ant->tx == active->tx) + if (ant.rx == active->rx && ant.tx == active->tx) return; /* @@ -156,11 +156,11 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, * The latter is required since we need to recalibrate the * noise-sensitivity ratio for the new setup. */ - rt2x00dev->ops->lib->config_ant(rt2x00dev, ant); + rt2x00dev->ops->lib->config_ant(rt2x00dev, &ant); rt2x00link_reset_tuner(rt2x00dev, true); - memcpy(active, ant, sizeof(*ant)); + memcpy(active, &ant, sizeof(ant)); if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK); diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 512fa2bc3a1..eeb2881e818 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -88,7 +88,7 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, struct ieee80211_bss_conf *conf); void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant); + struct antenna_setup ant); void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf, const unsigned int changed_flags); diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 32570758e67..79915687e74 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -173,7 +173,7 @@ static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev) if (ant->flags & ANTENNA_TX_DIVERSITY) new_ant.tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; - rt2x00lib_config_antenna(rt2x00dev, &new_ant); + rt2x00lib_config_antenna(rt2x00dev, new_ant); } static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev) @@ -213,7 +213,7 @@ static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev) if (ant->flags & ANTENNA_TX_DIVERSITY) new_ant.tx = (new_ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; - rt2x00lib_config_antenna(rt2x00dev, &new_ant); + rt2x00lib_config_antenna(rt2x00dev, new_ant); } static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 9d31c23b92f..7de1a2cdcf8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -378,7 +378,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) */ if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) rt2x00lib_config_antenna(rt2x00dev, - &rt2x00dev->default_ant); + rt2x00dev->default_ant); /* Turn RX back on */ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); -- cgit v1.2.3-18-g5258 From 58d30d14a1e5fbc3db6351e5af178ba71e2710f0 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 22 Jul 2009 10:41:14 -0700 Subject: ath: map TH to FCC3_WORLD TH gets 5 GHz. Cc: David Quan Cc: Michael Green Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 4d0e298cd1c..ad6d938d3cf 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -450,7 +450,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_SWITZERLAND, ETSI1_WORLD, "CH"}, {CTRY_SYRIA, NULL1_WORLD, "SY"}, {CTRY_TAIWAN, APL3_FCCA, "TW"}, - {CTRY_THAILAND, NULL1_WORLD, "TH"}, + {CTRY_THAILAND, FCC3_WORLD, "TH"}, {CTRY_TRINIDAD_Y_TOBAGO, ETSI4_WORLD, "TT"}, {CTRY_TUNISIA, ETSI3_WORLD, "TN"}, {CTRY_TURKEY, ETSI3_WORLD, "TR"}, -- cgit v1.2.3-18-g5258 From d9db5fa2c5cada8d8c20219ad4bab254e866409d Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Thu, 23 Jul 2009 12:01:50 +0530 Subject: ath9k: Add init values for AR9287 based chipsets. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/initvals.h | 1516 +++++++++++++++++++++++++++++ 1 file changed, 1516 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h index f67a2a96cc5..af4a1bafa7e 100644 --- a/drivers/net/wireless/ath/ath9k/initvals.h +++ b/drivers/net/wireless/ath/ath9k/initvals.h @@ -4849,3 +4849,1519 @@ static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = { {0x00004040, 0x00043007 }, {0x00004044, 0x00000000 }, }; + +/* AR9287 Revision 10 */ +static const u_int32_t ar9287Modes_9287_1_0[][6] = { + /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ + { 0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000000, 0x00000000, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }, + { 0x00008014, 0x00000000, 0x00000000, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x00000000, 0x00000000, 0x12e00057, 0x12e0002b, 0x0988004f }, + { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 }, + { 0x000081d0, 0x00003200, 0x00003200, 0x0000320a, 0x0000320a, 0x0000320a }, + { 0x00008318, 0x00000000, 0x00000000, 0x00006880, 0x00003440, 0x00006880 }, + { 0x00009804, 0x00000000, 0x00000000, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x00000000, 0x00000000, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000000, 0x00000000, 0x01000e0e, 0x01000e0e, 0x01000e0e }, + { 0x00009828, 0x00000000, 0x00000000, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000000, 0x00000000, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000003, 0x00000003, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009840, 0x206a002e, 0x206a002e, 0x206a012e, 0x206a012e, 0x206a012e }, + { 0x00009844, 0x03720000, 0x03720000, 0x037216a0, 0x037216a0, 0x037216a0 }, + { 0x00009850, 0x60000000, 0x60000000, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 }, + { 0x00009858, 0x7c000d00, 0x7c000d00, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, + { 0x0000985c, 0x3100005e, 0x3100005e, 0x3139605e, 0x31395d5e, 0x31395d5e }, + { 0x00009860, 0x00058d00, 0x00058d00, 0x00058d20, 0x00058d20, 0x00058d18 }, + { 0x00009864, 0x00000e00, 0x00000e00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x000040c0, 0x000040c0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, + { 0x0000986c, 0x00000080, 0x00000080, 0x06903881, 0x06903881, 0x06903881 }, + { 0x00009914, 0x00000000, 0x00000000, 0x00001130, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x00000000, 0x00000000, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8a01, 0xd00a8a01, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, + { 0x00009944, 0xefbc0000, 0xefbc0000, 0xefbc1010, 0xefbc1010, 0xefbc1010 }, + { 0x00009960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 }, + { 0x0000a960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 }, + { 0x00009964, 0x00000000, 0x00000000, 0x00000210, 0x00000210, 0x00000210 }, + { 0x0000c968, 0x00000200, 0x00000200, 0x000003ce, 0x000003ce, 0x000003ce }, + { 0x000099b8, 0x00000000, 0x00000000, 0x0000001c, 0x0000001c, 0x0000001c }, + { 0x000099bc, 0x00000000, 0x00000000, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x000099c0, 0x00000000, 0x00000000, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, + { 0x0000a204, 0x00000440, 0x00000440, 0x00000444, 0x00000444, 0x00000444 }, + { 0x0000a20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000b20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a21c, 0x1803800a, 0x1803800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a250, 0x00000000, 0x00000000, 0x0004a000, 0x0004a000, 0x0004a000 }, + { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, + { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, +}; + +static const u_int32_t ar9287Common_9287_1_0[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020015 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00004024, 0x0000001f }, + { 0x00004060, 0x00000000 }, + { 0x00004064, 0x00000000 }, + { 0x00007010, 0x00000033 }, + { 0x00007020, 0x00000000 }, + { 0x00007034, 0x00000002 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x40000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x00008070, 0x00000000 }, + { 0x000080c0, 0x2a80001a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0xffffffff }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x18487320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c0, 0x00000000 }, + { 0x000081c4, 0x00000000 }, + { 0x000081d4, 0x00000000 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008264, 0xa8a00010 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x000000ff }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x0000829c, 0x00000000 }, + { 0x00008300, 0x00000040 }, + { 0x00008314, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000007 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00ff0000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x000107ff }, + { 0x00008344, 0x01c81043 }, + { 0x00008360, 0xffffffff }, + { 0x00008364, 0xffffffff }, + { 0x00008368, 0x00000000 }, + { 0x00008370, 0x00000000 }, + { 0x00008374, 0x000000ff }, + { 0x00008378, 0x00000000 }, + { 0x0000837c, 0x00000000 }, + { 0x00008380, 0xffffffff }, + { 0x00008384, 0xffffffff }, + { 0x00008390, 0x0fffffff }, + { 0x00008394, 0x0fffffff }, + { 0x00008398, 0x00000000 }, + { 0x0000839c, 0x00000000 }, + { 0x000083a0, 0x00000000 }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xafe68e30 }, + { 0x00009810, 0xfd14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x0040233c }, + { 0x0000a84c, 0x0040233c }, + { 0x00009854, 0x00000044 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x00009910, 0x10002310 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x04900000 }, + { 0x0000a920, 0x04900000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009930, 0x00000000 }, + { 0x0000a930, 0x00000000 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009948, 0x9280c00a }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5f3ca3de }, + { 0x00009958, 0x0108ecff }, + { 0x00009940, 0x14750604 }, + { 0x0000c95c, 0x004b6a8e }, + { 0x00009970, 0x990bb515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x0c6f0000 }, + { 0x000099b0, 0x03051000 }, + { 0x000099b4, 0x00000820 }, + { 0x000099c4, 0x06336f77 }, + { 0x000099c8, 0x6af65329 }, + { 0x000099cc, 0x08f186c8 }, + { 0x000099d0, 0x00046384 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099f0, 0x00000000 }, + { 0x000099fc, 0x00001042 }, + { 0x0000a1f4, 0x00fffeff }, + { 0x0000a1f8, 0x00f5f9ff }, + { 0x0000a1fc, 0xb79f6427 }, + { 0x0000a208, 0x803e4788 }, + { 0x0000a210, 0x4080a333 }, + { 0x0000a214, 0x40206c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x01834061 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x000003b5 }, + { 0x0000a22c, 0x233f7180 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a23c, 0x13c889af }, + { 0x0000a240, 0x38490a20 }, + { 0x0000a244, 0x00000000 }, + { 0x0000a248, 0xfffffffc }, + { 0x0000a24c, 0x00000000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cdbd380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0xdfa91f01 }, + { 0x0000a264, 0x00418a11 }, + { 0x0000b264, 0x00418a11 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0e79e5c6 }, + { 0x0000b26c, 0x0e79e5c6 }, + { 0x0000d270, 0x00820820 }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000a27c, 0x050701ce }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x1ce739ce }, + { 0x0000a398, 0x000001ce }, + { 0x0000b398, 0x000001ce }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3c8, 0x00000246 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x1ce739ce }, + { 0x0000a3e0, 0x000001ce }, + { 0x0000a3e4, 0x00000000 }, + { 0x0000a3e8, 0x18c43433 }, + { 0x0000a3ec, 0x00f70081 }, + { 0x0000a3f0, 0x01036a1e }, + { 0x0000a3f4, 0x00000000 }, + { 0x0000b3f4, 0x00000000 }, + { 0x0000a7d8, 0x00000001 }, + { 0x00007800, 0x00000800 }, + { 0x00007804, 0x6c35ffb0 }, + { 0x00007808, 0x6db6c000 }, + { 0x0000780c, 0x6db6cb30 }, + { 0x00007810, 0x6db6cb6c }, + { 0x00007814, 0x0501e200 }, + { 0x00007818, 0x0094128d }, + { 0x0000781c, 0x976ee392 }, + { 0x00007820, 0xf75ff6fc }, + { 0x00007824, 0x00040000 }, + { 0x00007828, 0xdb003012 }, + { 0x0000782c, 0x04924914 }, + { 0x00007830, 0x21084210 }, + { 0x00007834, 0x00140000 }, + { 0x00007838, 0x0e4548d8 }, + { 0x0000783c, 0x54214514 }, + { 0x00007840, 0x02025820 }, + { 0x00007844, 0x71c0d388 }, + { 0x00007848, 0x934934a8 }, + { 0x00007850, 0x00000000 }, + { 0x00007854, 0x00000800 }, + { 0x00007858, 0x6c35ffb0 }, + { 0x0000785c, 0x6db6c000 }, + { 0x00007860, 0x6db6cb2c }, + { 0x00007864, 0x6db6cb6c }, + { 0x00007868, 0x0501e200 }, + { 0x0000786c, 0x0094128d }, + { 0x00007870, 0x976ee392 }, + { 0x00007874, 0xf75ff6fc }, + { 0x00007878, 0x00040000 }, + { 0x0000787c, 0xdb003012 }, + { 0x00007880, 0x04924914 }, + { 0x00007884, 0x21084210 }, + { 0x00007888, 0x001b6db0 }, + { 0x0000788c, 0x00376b63 }, + { 0x00007890, 0x06db6db6 }, + { 0x00007894, 0x006d8000 }, + { 0x00007898, 0x48100000 }, + { 0x0000789c, 0x00000000 }, + { 0x000078a0, 0x08000000 }, + { 0x000078a4, 0x0007ffd8 }, + { 0x000078a8, 0x0007ffd8 }, + { 0x000078ac, 0x001c0020 }, + { 0x000078b0, 0x000611eb }, + { 0x000078b4, 0x40008080 }, + { 0x000078b8, 0x2a850160 }, +}; + +static const u_int32_t ar9287Modes_tx_gain_9287_1_0[][6] = { + /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00008004, 0x00008004, 0x00008004 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x0000c00a, 0x0000c00a, 0x0000c00a }, + { 0x0000a310, 0x00000000, 0x00000000, 0x0001000c, 0x0001000c, 0x0001000c }, + { 0x0000a314, 0x00000000, 0x00000000, 0x0001420b, 0x0001420b, 0x0001420b }, + { 0x0000a318, 0x00000000, 0x00000000, 0x0001824a, 0x0001824a, 0x0001824a }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x0001c44a, 0x0001c44a, 0x0001c44a }, + { 0x0000a320, 0x00000000, 0x00000000, 0x0002064a, 0x0002064a, 0x0002064a }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0002484a, 0x0002484a, 0x0002484a }, + { 0x0000a328, 0x00000000, 0x00000000, 0x00028a4a, 0x00028a4a, 0x00028a4a }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a }, + { 0x0000a330, 0x00000000, 0x00000000, 0x00030e4a, 0x00030e4a, 0x00030e4a }, + { 0x0000a334, 0x00000000, 0x00000000, 0x00034e8a, 0x00034e8a, 0x00034e8a }, + { 0x0000a338, 0x00000000, 0x00000000, 0x00038e8c, 0x00038e8c, 0x00038e8c }, + { 0x0000a33c, 0x00000000, 0x00000000, 0x0003cecc, 0x0003cecc, 0x0003cecc }, + { 0x0000a340, 0x00000000, 0x00000000, 0x00040ed4, 0x00040ed4, 0x00040ed4 }, + { 0x0000a344, 0x00000000, 0x00000000, 0x00044edc, 0x00044edc, 0x00044edc }, + { 0x0000a348, 0x00000000, 0x00000000, 0x00048ede, 0x00048ede, 0x00048ede }, + { 0x0000a34c, 0x00000000, 0x00000000, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e }, + { 0x0000a350, 0x00000000, 0x00000000, 0x00050f5e, 0x00050f5e, 0x00050f5e }, + { 0x0000a354, 0x00000000, 0x00000000, 0x00054f9e, 0x00054f9e, 0x00054f9e }, + { 0x0000a780, 0x00000000, 0x00000000, 0x00000060, 0x00000060, 0x00000060 }, + { 0x0000a784, 0x00000000, 0x00000000, 0x00004062, 0x00004062, 0x00004062 }, + { 0x0000a788, 0x00000000, 0x00000000, 0x00008064, 0x00008064, 0x00008064 }, + { 0x0000a78c, 0x00000000, 0x00000000, 0x0000c0a4, 0x0000c0a4, 0x0000c0a4 }, + { 0x0000a790, 0x00000000, 0x00000000, 0x000100b0, 0x000100b0, 0x000100b0 }, + { 0x0000a794, 0x00000000, 0x00000000, 0x000140b2, 0x000140b2, 0x000140b2 }, + { 0x0000a798, 0x00000000, 0x00000000, 0x000180b4, 0x000180b4, 0x000180b4 }, + { 0x0000a79c, 0x00000000, 0x00000000, 0x0001c0f4, 0x0001c0f4, 0x0001c0f4 }, + { 0x0000a7a0, 0x00000000, 0x00000000, 0x00020134, 0x00020134, 0x00020134 }, + { 0x0000a7a4, 0x00000000, 0x00000000, 0x000240fe, 0x000240fe, 0x000240fe }, + { 0x0000a7a8, 0x00000000, 0x00000000, 0x0002813e, 0x0002813e, 0x0002813e }, + { 0x0000a7ac, 0x00000000, 0x00000000, 0x0002c17e, 0x0002c17e, 0x0002c17e }, + { 0x0000a7b0, 0x00000000, 0x00000000, 0x000301be, 0x000301be, 0x000301be }, + { 0x0000a7b4, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe }, + { 0x0000a7b8, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe }, + { 0x0000a7bc, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe }, + { 0x0000a7c0, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe }, + { 0x0000a7c4, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe }, + { 0x0000a7c8, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe }, + { 0x0000a7cc, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe }, + { 0x0000a7d0, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe }, + { 0x0000a7d4, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe }, + { 0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000, 0x0a1aa000 }, +}; + + +static const u_int32_t ar9287Modes_rx_gain_9287_1_0[][6] = { + /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ + { 0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 }, + { 0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 }, + { 0x00009a08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 }, + { 0x00009a0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c }, + { 0x00009a10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 }, + { 0x00009a14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 }, + { 0x00009a18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 }, + { 0x00009a1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c }, + { 0x00009a20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 }, + { 0x00009a24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 }, + { 0x00009a28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 }, + { 0x00009a2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c }, + { 0x00009a30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 }, + { 0x00009a34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 }, + { 0x00009a38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 }, + { 0x00009a3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 }, + { 0x00009a40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 }, + { 0x00009a44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac }, + { 0x00009a48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 }, + { 0x00009a4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 }, + { 0x00009a50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 }, + { 0x00009a54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 }, + { 0x00009a58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 }, + { 0x00009a5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c }, + { 0x00009a60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 }, + { 0x00009a64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 }, + { 0x00009a68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 }, + { 0x00009a6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c }, + { 0x00009a70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 }, + { 0x00009a74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 }, + { 0x00009a78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 }, + { 0x00009a7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c }, + { 0x00009a80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 }, + { 0x00009a84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 }, + { 0x00009a88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 }, + { 0x00009a8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 }, + { 0x00009a90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 }, + { 0x00009a94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 }, + { 0x00009a98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 }, + { 0x00009a9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c }, + { 0x00009aa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 }, + { 0x00009aa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 }, + { 0x00009aa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 }, + { 0x00009aac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c }, + { 0x00009ab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 }, + { 0x00009ab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 }, + { 0x00009ab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 }, + { 0x00009abc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 }, + { 0x00009ac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 }, + { 0x00009ac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 }, + { 0x00009ac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c }, + { 0x00009acc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 }, + { 0x00009ad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 }, + { 0x00009ad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 }, + { 0x00009ad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 }, + { 0x00009adc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 }, + { 0x00009ae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac }, + { 0x00009ae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 }, + { 0x00009ae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 }, + { 0x00009aec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 }, + { 0x00009af0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 }, + { 0x00009af4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 }, + { 0x00009af8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 }, + { 0x00009afc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 }, + { 0x00009b00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 }, + { 0x00009b04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 }, + { 0x00009b08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 }, + { 0x00009b0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c }, + { 0x00009b10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 }, + { 0x00009b14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 }, + { 0x00009b18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c }, + { 0x00009b1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 }, + { 0x00009b20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 }, + { 0x00009b24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 }, + { 0x00009b28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 }, + { 0x00009b2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 }, + { 0x00009b30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac }, + { 0x00009b34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 }, + { 0x00009b38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 }, + { 0x00009b3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 }, + { 0x00009b40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 }, + { 0x00009b44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 }, + { 0x00009b48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad }, + { 0x00009b4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 }, + { 0x00009b50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 }, + { 0x00009b54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 }, + { 0x00009b58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 }, + { 0x00009b5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 }, + { 0x00009b60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd }, + { 0x00009b64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 }, + { 0x00009b68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 }, + { 0x00009b6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 }, + { 0x00009b70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 }, + { 0x00009b74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca }, + { 0x00009b78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce }, + { 0x00009b7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 }, + { 0x00009b80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 }, + { 0x00009b84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda }, + { 0x00009b88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 }, + { 0x00009b8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb }, + { 0x00009b90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf }, + { 0x00009b94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 }, + { 0x00009b98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 }, + { 0x00009b9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009ba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009ba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009ba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009be0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009be4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009be8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000aa00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 }, + { 0x0000aa04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 }, + { 0x0000aa08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 }, + { 0x0000aa0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c }, + { 0x0000aa10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 }, + { 0x0000aa14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 }, + { 0x0000aa18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 }, + { 0x0000aa1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c }, + { 0x0000aa20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 }, + { 0x0000aa24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 }, + { 0x0000aa28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 }, + { 0x0000aa2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c }, + { 0x0000aa30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 }, + { 0x0000aa34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 }, + { 0x0000aa38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 }, + { 0x0000aa3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 }, + { 0x0000aa40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 }, + { 0x0000aa44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac }, + { 0x0000aa48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 }, + { 0x0000aa4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 }, + { 0x0000aa50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 }, + { 0x0000aa54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 }, + { 0x0000aa58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 }, + { 0x0000aa5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c }, + { 0x0000aa60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 }, + { 0x0000aa64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 }, + { 0x0000aa68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 }, + { 0x0000aa6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c }, + { 0x0000aa70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 }, + { 0x0000aa74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 }, + { 0x0000aa78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 }, + { 0x0000aa7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c }, + { 0x0000aa80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 }, + { 0x0000aa84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 }, + { 0x0000aa88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 }, + { 0x0000aa8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 }, + { 0x0000aa90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 }, + { 0x0000aa94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 }, + { 0x0000aa98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 }, + { 0x0000aa9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c }, + { 0x0000aaa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 }, + { 0x0000aaa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 }, + { 0x0000aaa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 }, + { 0x0000aaac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c }, + { 0x0000aab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 }, + { 0x0000aab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 }, + { 0x0000aab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 }, + { 0x0000aabc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 }, + { 0x0000aac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 }, + { 0x0000aac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 }, + { 0x0000aac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c }, + { 0x0000aacc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 }, + { 0x0000aad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 }, + { 0x0000aad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 }, + { 0x0000aad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 }, + { 0x0000aadc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 }, + { 0x0000aae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac }, + { 0x0000aae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 }, + { 0x0000aae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 }, + { 0x0000aaec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 }, + { 0x0000aaf0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 }, + { 0x0000aaf4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 }, + { 0x0000aaf8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 }, + { 0x0000aafc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 }, + { 0x0000ab00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 }, + { 0x0000ab04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 }, + { 0x0000ab08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 }, + { 0x0000ab0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c }, + { 0x0000ab10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 }, + { 0x0000ab14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 }, + { 0x0000ab18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c }, + { 0x0000ab1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 }, + { 0x0000ab20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 }, + { 0x0000ab24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 }, + { 0x0000ab28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 }, + { 0x0000ab2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 }, + { 0x0000ab30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac }, + { 0x0000ab34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 }, + { 0x0000ab38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 }, + { 0x0000ab3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 }, + { 0x0000ab40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 }, + { 0x0000ab44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 }, + { 0x0000ab48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad }, + { 0x0000ab4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 }, + { 0x0000ab50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 }, + { 0x0000ab54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 }, + { 0x0000ab58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 }, + { 0x0000ab5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 }, + { 0x0000ab60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd }, + { 0x0000ab64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 }, + { 0x0000ab68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 }, + { 0x0000ab6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 }, + { 0x0000ab70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 }, + { 0x0000ab74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca }, + { 0x0000ab78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce }, + { 0x0000ab7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 }, + { 0x0000ab80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 }, + { 0x0000ab84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda }, + { 0x0000ab88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 }, + { 0x0000ab8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb }, + { 0x0000ab90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf }, + { 0x0000ab94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 }, + { 0x0000ab98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 }, + { 0x0000ab9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000aba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000aba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000aba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abe0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abe4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abe8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 }, + { 0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 }, +}; + +static const u_int32_t ar9287PciePhy_clkreq_always_on_L1_9287_1_0[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffd }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +static const u_int32_t ar9287PciePhy_clkreq_off_L1_9287_1_0[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffc }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +/* AR9287 Revision 11 */ + +static const u_int32_t ar9287Modes_9287_1_1[][6] = { + /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ + { 0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000000, 0x00000000, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }, + { 0x00008014, 0x00000000, 0x00000000, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x00000000, 0x00000000, 0x12e00057, 0x12e0002b, 0x0988004f }, + { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 }, + { 0x000081d0, 0x00003200, 0x00003200, 0x0000320a, 0x0000320a, 0x0000320a }, + { 0x00008318, 0x00000000, 0x00000000, 0x00006880, 0x00003440, 0x00006880 }, + { 0x00009804, 0x00000000, 0x00000000, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x00000000, 0x00000000, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000000, 0x00000000, 0x01000e0e, 0x01000e0e, 0x01000e0e }, + { 0x00009828, 0x00000000, 0x00000000, 0x3a020001, 0x3a020001, 0x3a020001 }, + { 0x00009834, 0x00000000, 0x00000000, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000003, 0x00000003, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009840, 0x206a002e, 0x206a002e, 0x206a012e, 0x206a012e, 0x206a012e }, + { 0x00009844, 0x03720000, 0x03720000, 0x037216a0, 0x037216a0, 0x037216a0 }, + { 0x00009850, 0x60000000, 0x60000000, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 }, + { 0x00009858, 0x7c000d00, 0x7c000d00, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, + { 0x0000985c, 0x3100005e, 0x3100005e, 0x3139605e, 0x31395d5e, 0x31395d5e }, + { 0x00009860, 0x00058d00, 0x00058d00, 0x00058d20, 0x00058d20, 0x00058d18 }, + { 0x00009864, 0x00000e00, 0x00000e00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x000040c0, 0x000040c0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, + { 0x0000986c, 0x00000080, 0x00000080, 0x06903881, 0x06903881, 0x06903881 }, + { 0x00009914, 0x00000000, 0x00000000, 0x00001130, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x00000000, 0x00000000, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8a01, 0xd00a8a01, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, + { 0x00009944, 0xefbc0000, 0xefbc0000, 0xefbc1010, 0xefbc1010, 0xefbc1010 }, + { 0x00009960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 }, + { 0x0000a960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 }, + { 0x00009964, 0x00000000, 0x00000000, 0x00000210, 0x00000210, 0x00000210 }, + { 0x0000c968, 0x00000200, 0x00000200, 0x000003ce, 0x000003ce, 0x000003ce }, + { 0x000099b8, 0x00000000, 0x00000000, 0x0000001c, 0x0000001c, 0x0000001c }, + { 0x000099bc, 0x00000000, 0x00000000, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x000099c0, 0x00000000, 0x00000000, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, + { 0x0000a204, 0x00000440, 0x00000440, 0x00000444, 0x00000444, 0x00000444 }, + { 0x0000a20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000b20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a21c, 0x1803800a, 0x1803800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a250, 0x00000000, 0x00000000, 0x0004a000, 0x0004a000, 0x0004a000 }, + { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, + { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, +}; + +static const u_int32_t ar9287Common_9287_1_1[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020015 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00004024, 0x0000001f }, + { 0x00004060, 0x00000000 }, + { 0x00004064, 0x00000000 }, + { 0x00007010, 0x00000033 }, + { 0x00007020, 0x00000000 }, + { 0x00007034, 0x00000002 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x40000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x00008070, 0x00000000 }, + { 0x000080c0, 0x2a80001a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0xffffffff }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x18487320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c0, 0x00000000 }, + { 0x000081c4, 0x00000000 }, + { 0x000081d4, 0x00000000 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008264, 0x88a00010 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x000000ff }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x0000829c, 0x00000000 }, + { 0x00008300, 0x00000040 }, + { 0x00008314, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000007 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00ff0000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x000107ff }, + { 0x00008344, 0x01c81043 }, + { 0x00008360, 0xffffffff }, + { 0x00008364, 0xffffffff }, + { 0x00008368, 0x00000000 }, + { 0x00008370, 0x00000000 }, + { 0x00008374, 0x000000ff }, + { 0x00008378, 0x00000000 }, + { 0x0000837c, 0x00000000 }, + { 0x00008380, 0xffffffff }, + { 0x00008384, 0xffffffff }, + { 0x00008390, 0x0fffffff }, + { 0x00008394, 0x0fffffff }, + { 0x00008398, 0x00000000 }, + { 0x0000839c, 0x00000000 }, + { 0x000083a0, 0x00000000 }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xafe68e30 }, + { 0x00009810, 0xfd14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x0040233c }, + { 0x0000a84c, 0x0040233c }, + { 0x00009854, 0x00000044 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x00009910, 0x10002310 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x04900000 }, + { 0x0000a920, 0x04900000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009930, 0x00000000 }, + { 0x0000a930, 0x00000000 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009948, 0x9280c00a }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5f3ca3de }, + { 0x00009958, 0x0108ecff }, + { 0x00009940, 0x14750604 }, + { 0x0000c95c, 0x004b6a8e }, + { 0x00009970, 0x990bb514 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x0c6f0000 }, + { 0x000099b0, 0x03051000 }, + { 0x000099b4, 0x00000820 }, + { 0x000099c4, 0x06336f77 }, + { 0x000099c8, 0x6af6532f }, + { 0x000099cc, 0x08f186c8 }, + { 0x000099d0, 0x00046384 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099f0, 0x00000000 }, + { 0x000099fc, 0x00001042 }, + { 0x0000a1f4, 0x00fffeff }, + { 0x0000a1f8, 0x00f5f9ff }, + { 0x0000a1fc, 0xb79f6427 }, + { 0x0000a208, 0x803e4788 }, + { 0x0000a210, 0x4080a333 }, + { 0x0000a214, 0x40206c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x01834061 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x000003b5 }, + { 0x0000a22c, 0x233f7180 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a23c, 0x13c889af }, + { 0x0000a240, 0x38490a20 }, + { 0x0000a244, 0x00000000 }, + { 0x0000a248, 0xfffffffc }, + { 0x0000a24c, 0x00000000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cdbd380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0xdfa91f01 }, + { 0x0000a264, 0x00418a11 }, + { 0x0000b264, 0x00418a11 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0e79e5c6 }, + { 0x0000b26c, 0x0e79e5c6 }, + { 0x0000d270, 0x00820820 }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000a27c, 0x050701ce }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x1ce739ce }, + { 0x0000a398, 0x000001ce }, + { 0x0000b398, 0x000001ce }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3c8, 0x00000246 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x1ce739ce }, + { 0x0000a3e0, 0x000001ce }, + { 0x0000a3e4, 0x00000000 }, + { 0x0000a3e8, 0x18c43433 }, + { 0x0000a3ec, 0x00f70081 }, + { 0x0000a3f0, 0x01036a1e }, + { 0x0000a3f4, 0x00000000 }, + { 0x0000b3f4, 0x00000000 }, + { 0x0000a7d8, 0x000003f1 }, + { 0x00007800, 0x00000800 }, + { 0x00007804, 0x6c35ffc2 }, + { 0x00007808, 0x6db6c000 }, + { 0x0000780c, 0x6db6cb30 }, + { 0x00007810, 0x6db6cb6c }, + { 0x00007814, 0x0501e200 }, + { 0x00007818, 0x0094128d }, + { 0x0000781c, 0x976ee392 }, + { 0x00007820, 0xf75ff6fc }, + { 0x00007824, 0x00040000 }, + { 0x00007828, 0xdb003012 }, + { 0x0000782c, 0x04924914 }, + { 0x00007830, 0x21084210 }, + { 0x00007834, 0x00140000 }, + { 0x00007838, 0x0e4548d8 }, + { 0x0000783c, 0x54214514 }, + { 0x00007840, 0x02025830 }, + { 0x00007844, 0x71c0d388 }, + { 0x00007848, 0x934934a8 }, + { 0x00007850, 0x00000000 }, + { 0x00007854, 0x00000800 }, + { 0x00007858, 0x6c35ffc2 }, + { 0x0000785c, 0x6db6c000 }, + { 0x00007860, 0x6db6cb30 }, + { 0x00007864, 0x6db6cb6c }, + { 0x00007868, 0x0501e200 }, + { 0x0000786c, 0x0094128d }, + { 0x00007870, 0x976ee392 }, + { 0x00007874, 0xf75ff6fc }, + { 0x00007878, 0x00040000 }, + { 0x0000787c, 0xdb003012 }, + { 0x00007880, 0x04924914 }, + { 0x00007884, 0x21084210 }, + { 0x00007888, 0x001b6db0 }, + { 0x0000788c, 0x00376b63 }, + { 0x00007890, 0x06db6db6 }, + { 0x00007894, 0x006d8000 }, + { 0x00007898, 0x48100000 }, + { 0x0000789c, 0x00000000 }, + { 0x000078a0, 0x08000000 }, + { 0x000078a4, 0x0007ffd8 }, + { 0x000078a8, 0x0007ffd8 }, + { 0x000078ac, 0x001c0020 }, + { 0x000078b0, 0x00060aeb }, + { 0x000078b4, 0x40008080 }, + { 0x000078b8, 0x2a850160 }, +}; + +static const u_int32_t ar9287Modes_tx_gain_9287_1_1[][6] = { + /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00008004, 0x00008004, 0x00008004 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x0000c00a, 0x0000c00a, 0x0000c00a }, + { 0x0000a310, 0x00000000, 0x00000000, 0x0001000c, 0x0001000c, 0x0001000c }, + { 0x0000a314, 0x00000000, 0x00000000, 0x0001420b, 0x0001420b, 0x0001420b }, + { 0x0000a318, 0x00000000, 0x00000000, 0x0001824a, 0x0001824a, 0x0001824a }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x0001c44a, 0x0001c44a, 0x0001c44a }, + { 0x0000a320, 0x00000000, 0x00000000, 0x0002064a, 0x0002064a, 0x0002064a }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0002484a, 0x0002484a, 0x0002484a }, + { 0x0000a328, 0x00000000, 0x00000000, 0x00028a4a, 0x00028a4a, 0x00028a4a }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a }, + { 0x0000a330, 0x00000000, 0x00000000, 0x00030e4a, 0x00030e4a, 0x00030e4a }, + { 0x0000a334, 0x00000000, 0x00000000, 0x00034e8a, 0x00034e8a, 0x00034e8a }, + { 0x0000a338, 0x00000000, 0x00000000, 0x00038e8c, 0x00038e8c, 0x00038e8c }, + { 0x0000a33c, 0x00000000, 0x00000000, 0x0003cecc, 0x0003cecc, 0x0003cecc }, + { 0x0000a340, 0x00000000, 0x00000000, 0x00040ed4, 0x00040ed4, 0x00040ed4 }, + { 0x0000a344, 0x00000000, 0x00000000, 0x00044edc, 0x00044edc, 0x00044edc }, + { 0x0000a348, 0x00000000, 0x00000000, 0x00048ede, 0x00048ede, 0x00048ede }, + { 0x0000a34c, 0x00000000, 0x00000000, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e }, + { 0x0000a350, 0x00000000, 0x00000000, 0x00050f5e, 0x00050f5e, 0x00050f5e }, + { 0x0000a354, 0x00000000, 0x00000000, 0x00054f9e, 0x00054f9e, 0x00054f9e }, + { 0x0000a780, 0x00000000, 0x00000000, 0x00000062, 0x00000062, 0x00000062 }, + { 0x0000a784, 0x00000000, 0x00000000, 0x00004064, 0x00004064, 0x00004064 }, + { 0x0000a788, 0x00000000, 0x00000000, 0x000080a4, 0x000080a4, 0x000080a4 }, + { 0x0000a78c, 0x00000000, 0x00000000, 0x0000c0aa, 0x0000c0aa, 0x0000c0aa }, + { 0x0000a790, 0x00000000, 0x00000000, 0x000100ac, 0x000100ac, 0x000100ac }, + { 0x0000a794, 0x00000000, 0x00000000, 0x000140b4, 0x000140b4, 0x000140b4 }, + { 0x0000a798, 0x00000000, 0x00000000, 0x000180f4, 0x000180f4, 0x000180f4 }, + { 0x0000a79c, 0x00000000, 0x00000000, 0x0001c134, 0x0001c134, 0x0001c134 }, + { 0x0000a7a0, 0x00000000, 0x00000000, 0x00020174, 0x00020174, 0x00020174 }, + { 0x0000a7a4, 0x00000000, 0x00000000, 0x0002417c, 0x0002417c, 0x0002417c }, + { 0x0000a7a8, 0x00000000, 0x00000000, 0x0002817e, 0x0002817e, 0x0002817e }, + { 0x0000a7ac, 0x00000000, 0x00000000, 0x0002c1be, 0x0002c1be, 0x0002c1be }, + { 0x0000a7b0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe }, + { 0x0000a7b4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe }, + { 0x0000a7b8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe }, + { 0x0000a7bc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe }, + { 0x0000a7c0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe }, + { 0x0000a7c4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe }, + { 0x0000a7c8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe }, + { 0x0000a7cc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe }, + { 0x0000a7d0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe }, + { 0x0000a7d4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe }, + { 0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000, 0x0a1aa000 }, +}; + +static const u_int32_t ar9287Modes_rx_gain_9287_1_1[][6] = { + /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ + { 0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 }, + { 0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 }, + { 0x00009a08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 }, + { 0x00009a0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c }, + { 0x00009a10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 }, + { 0x00009a14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 }, + { 0x00009a18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 }, + { 0x00009a1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c }, + { 0x00009a20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 }, + { 0x00009a24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 }, + { 0x00009a28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 }, + { 0x00009a2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c }, + { 0x00009a30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 }, + { 0x00009a34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 }, + { 0x00009a38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 }, + { 0x00009a3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 }, + { 0x00009a40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 }, + { 0x00009a44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac }, + { 0x00009a48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 }, + { 0x00009a4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 }, + { 0x00009a50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 }, + { 0x00009a54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 }, + { 0x00009a58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 }, + { 0x00009a5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c }, + { 0x00009a60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 }, + { 0x00009a64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 }, + { 0x00009a68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 }, + { 0x00009a6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c }, + { 0x00009a70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 }, + { 0x00009a74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 }, + { 0x00009a78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 }, + { 0x00009a7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c }, + { 0x00009a80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 }, + { 0x00009a84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 }, + { 0x00009a88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 }, + { 0x00009a8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 }, + { 0x00009a90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 }, + { 0x00009a94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 }, + { 0x00009a98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 }, + { 0x00009a9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c }, + { 0x00009aa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 }, + { 0x00009aa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 }, + { 0x00009aa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 }, + { 0x00009aac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c }, + { 0x00009ab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 }, + { 0x00009ab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 }, + { 0x00009ab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 }, + { 0x00009abc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 }, + { 0x00009ac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 }, + { 0x00009ac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 }, + { 0x00009ac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c }, + { 0x00009acc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 }, + { 0x00009ad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 }, + { 0x00009ad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 }, + { 0x00009ad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 }, + { 0x00009adc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 }, + { 0x00009ae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac }, + { 0x00009ae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 }, + { 0x00009ae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 }, + { 0x00009aec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 }, + { 0x00009af0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 }, + { 0x00009af4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 }, + { 0x00009af8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 }, + { 0x00009afc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 }, + { 0x00009b00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 }, + { 0x00009b04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 }, + { 0x00009b08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 }, + { 0x00009b0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c }, + { 0x00009b10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 }, + { 0x00009b14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 }, + { 0x00009b18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c }, + { 0x00009b1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 }, + { 0x00009b20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 }, + { 0x00009b24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 }, + { 0x00009b28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 }, + { 0x00009b2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 }, + { 0x00009b30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac }, + { 0x00009b34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 }, + { 0x00009b38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 }, + { 0x00009b3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 }, + { 0x00009b40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 }, + { 0x00009b44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 }, + { 0x00009b48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad }, + { 0x00009b4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 }, + { 0x00009b50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 }, + { 0x00009b54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 }, + { 0x00009b58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 }, + { 0x00009b5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 }, + { 0x00009b60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd }, + { 0x00009b64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 }, + { 0x00009b68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 }, + { 0x00009b6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 }, + { 0x00009b70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 }, + { 0x00009b74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca }, + { 0x00009b78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce }, + { 0x00009b7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 }, + { 0x00009b80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 }, + { 0x00009b84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda }, + { 0x00009b88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 }, + { 0x00009b8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb }, + { 0x00009b90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf }, + { 0x00009b94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 }, + { 0x00009b98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 }, + { 0x00009b9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009ba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009ba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009ba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009be0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009be4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009be8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009bfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000aa00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 }, + { 0x0000aa04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 }, + { 0x0000aa08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 }, + { 0x0000aa0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c }, + { 0x0000aa10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 }, + { 0x0000aa14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 }, + { 0x0000aa18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 }, + { 0x0000aa1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c }, + { 0x0000aa20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 }, + { 0x0000aa24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 }, + { 0x0000aa28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 }, + { 0x0000aa2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c }, + { 0x0000aa30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 }, + { 0x0000aa34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 }, + { 0x0000aa38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 }, + { 0x0000aa3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 }, + { 0x0000aa40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 }, + { 0x0000aa44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac }, + { 0x0000aa48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 }, + { 0x0000aa4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 }, + { 0x0000aa50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 }, + { 0x0000aa54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 }, + { 0x0000aa58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 }, + { 0x0000aa5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c }, + { 0x0000aa60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 }, + { 0x0000aa64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 }, + { 0x0000aa68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 }, + { 0x0000aa6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c }, + { 0x0000aa70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 }, + { 0x0000aa74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 }, + { 0x0000aa78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 }, + { 0x0000aa7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c }, + { 0x0000aa80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 }, + { 0x0000aa84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 }, + { 0x0000aa88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 }, + { 0x0000aa8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 }, + { 0x0000aa90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 }, + { 0x0000aa94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 }, + { 0x0000aa98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 }, + { 0x0000aa9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c }, + { 0x0000aaa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 }, + { 0x0000aaa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 }, + { 0x0000aaa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 }, + { 0x0000aaac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c }, + { 0x0000aab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 }, + { 0x0000aab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 }, + { 0x0000aab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 }, + { 0x0000aabc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 }, + { 0x0000aac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 }, + { 0x0000aac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 }, + { 0x0000aac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c }, + { 0x0000aacc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 }, + { 0x0000aad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 }, + { 0x0000aad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 }, + { 0x0000aad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 }, + { 0x0000aadc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 }, + { 0x0000aae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac }, + { 0x0000aae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 }, + { 0x0000aae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 }, + { 0x0000aaec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 }, + { 0x0000aaf0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 }, + { 0x0000aaf4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 }, + { 0x0000aaf8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 }, + { 0x0000aafc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 }, + { 0x0000ab00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 }, + { 0x0000ab04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 }, + { 0x0000ab08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 }, + { 0x0000ab0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c }, + { 0x0000ab10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 }, + { 0x0000ab14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 }, + { 0x0000ab18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c }, + { 0x0000ab1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 }, + { 0x0000ab20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 }, + { 0x0000ab24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 }, + { 0x0000ab28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 }, + { 0x0000ab2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 }, + { 0x0000ab30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac }, + { 0x0000ab34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 }, + { 0x0000ab38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 }, + { 0x0000ab3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 }, + { 0x0000ab40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 }, + { 0x0000ab44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 }, + { 0x0000ab48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad }, + { 0x0000ab4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 }, + { 0x0000ab50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 }, + { 0x0000ab54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 }, + { 0x0000ab58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 }, + { 0x0000ab5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 }, + { 0x0000ab60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd }, + { 0x0000ab64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 }, + { 0x0000ab68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 }, + { 0x0000ab6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 }, + { 0x0000ab70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 }, + { 0x0000ab74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca }, + { 0x0000ab78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce }, + { 0x0000ab7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 }, + { 0x0000ab80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 }, + { 0x0000ab84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda }, + { 0x0000ab88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 }, + { 0x0000ab8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb }, + { 0x0000ab90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf }, + { 0x0000ab94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 }, + { 0x0000ab98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 }, + { 0x0000ab9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000aba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000aba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000aba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abe0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abe4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abe8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x0000abfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb }, + { 0x00009848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 }, + { 0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 }, +}; + +static const u_int32_t ar9287PciePhy_clkreq_always_on_L1_9287_1_1[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffd }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +static const u_int32_t ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffc }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + + -- cgit v1.2.3-18-g5258 From c49fd520d10eb277d94c570f2fdb35d2974a30ee Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 23 Jul 2009 15:32:25 +0530 Subject: ath9k: Trivial fix in Kconfig Update filename for debug information. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 2d79610bce1..0f4a6d862d3 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -18,6 +18,6 @@ config ATH9K_DEBUG Say Y, if you need ath9k to display debug messages. Pass the debug mask as a module parameter: - modprobe ath9k debug=0x00002000 + modprobe ath9k debug=0x00000200 - Look in ath9k/core.h for possible debug masks + Look in ath9k/debug.h for possible debug masks -- cgit v1.2.3-18-g5258 From 305fe47fb8ac1279f01284c1ba5875fa9a355d22 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 23 Jul 2009 15:32:29 +0530 Subject: ath9k: Fix a sparse warning Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 4ff155e8ee5..c039d0ac5ff 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2037,7 +2037,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) } } -void ath_tx_complete_poll_work(struct work_struct *work) +static void ath_tx_complete_poll_work(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, tx_complete_work.work); -- cgit v1.2.3-18-g5258 From 9e98ac65a39df54fb0520cd86d1e7373319df00f Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 23 Jul 2009 15:32:34 +0530 Subject: ath9k: Remove redundant HT macros These can be obtained from mac80211. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 -- drivers/net/wireless/ath/ath9k/main.c | 8 +++----- 2 files changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 751885a5df4..ebcf78b1ba7 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -194,8 +194,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, #define IEEE80211_SEQ_SEQ_SHIFT 4 #define IEEE80211_SEQ_MAX 4096 -#define IEEE80211_MIN_AMPDU_BUF 0x8 -#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 #define IEEE80211_WEP_IVLEN 3 #define IEEE80211_WEP_KIDLEN 1 #define IEEE80211_WEP_CRCLEN 4 diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3436295e050..3834678f622 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -462,7 +462,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) if (sc->sc_flags & SC_OP_TXAGGR) { ath_tx_node_init(sc, an); - an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + + an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + sta->ht_cap.ampdu_factor); an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); an->last_rssi = ATH_RSSI_DUMMY_MARKER; @@ -888,8 +888,6 @@ static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) static void setup_ht_cap(struct ath_softc *sc, struct ieee80211_sta_ht_cap *ht_info) { -#define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */ -#define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */ u8 tx_streams, rx_streams; ht_info->ht_supported = true; @@ -898,8 +896,8 @@ static void setup_ht_cap(struct ath_softc *sc, IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_DSSSCCK40; - ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536; - ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8; + ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; /* set up supported mcs set */ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); -- cgit v1.2.3-18-g5258 From f83da96564b2a2f4ae75ea971b357458e5240b61 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 23 Jul 2009 15:32:37 +0530 Subject: ath9k: Cleanup return values Cleanup aggregation start/stop function interfaces. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 6 +++--- drivers/net/wireless/ath/ath9k/main.c | 14 +++----------- drivers/net/wireless/ath/ath9k/xmit.c | 25 +++++++++---------------- 3 files changed, 15 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index ebcf78b1ba7..d816c9df1f6 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -363,9 +363,9 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, void ath_tx_tasklet(struct ath_softc *sc); void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb); bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno); -int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, - u16 tid, u16 *ssn); -int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); +void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, + u16 tid, u16 *ssn); +void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); /********/ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3834678f622..b3e07e79dae 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2669,19 +2669,11 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_RX_STOP: break; case IEEE80211_AMPDU_TX_START: - ret = ath_tx_aggr_start(sc, sta, tid, ssn); - if (ret < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to start TX aggregation\n"); - else - ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); + ath_tx_aggr_start(sc, sta, tid, ssn); + ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); break; case IEEE80211_AMPDU_TX_STOP: - ret = ath_tx_aggr_stop(sc, sta, tid); - if (ret < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to stop TX aggregation\n"); - + ath_tx_aggr_stop(sc, sta, tid); ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index c039d0ac5ff..2c01fda5b72 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -695,25 +695,20 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, status != ATH_AGGR_BAW_CLOSED); } -int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, - u16 tid, u16 *ssn) +void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, + u16 tid, u16 *ssn) { struct ath_atx_tid *txtid; struct ath_node *an; an = (struct ath_node *)sta->drv_priv; - - if (sc->sc_flags & SC_OP_TXAGGR) { - txtid = ATH_AN_2_TID(an, tid); - txtid->state |= AGGR_ADDBA_PROGRESS; - ath_tx_pause_tid(sc, txtid); - *ssn = txtid->seq_start; - } - - return 0; + txtid = ATH_AN_2_TID(an, tid); + txtid->state |= AGGR_ADDBA_PROGRESS; + ath_tx_pause_tid(sc, txtid); + *ssn = txtid->seq_start; } -int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) +void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) { struct ath_node *an = (struct ath_node *)sta->drv_priv; struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); @@ -723,11 +718,11 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) INIT_LIST_HEAD(&bf_head); if (txtid->state & AGGR_CLEANUP) - return 0; + return; if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { txtid->state &= ~AGGR_ADDBA_PROGRESS; - return 0; + return; } ath_tx_pause_tid(sc, txtid); @@ -756,8 +751,6 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) txtid->state &= ~AGGR_ADDBA_COMPLETE; ath_tx_flush_tid(sc, txtid); } - - return 0; } void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) -- cgit v1.2.3-18-g5258 From 4ef7084173e22cfdd4bb3aa3858ba8dd5d76f22f Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 23 Jul 2009 15:32:41 +0530 Subject: ath9k: Remove a few redundant variables/macros Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/xmit.c | 24 ++++++++++-------------- 2 files changed, 10 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index d816c9df1f6..e2ebf1a56c0 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -190,7 +190,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, #define ATH_AGGR_MIN_QDEPTH 2 #define ATH_AMPDU_SUBFRAME_DEFAULT 32 #define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1) -#define ATH_AMPDU_LIMIT_DEFAULT ATH_AMPDU_LIMIT_MAX #define IEEE80211_SEQ_SEQ_SHIFT 4 #define IEEE80211_SEQ_MAX 4096 diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 2c01fda5b72..6eb2927c8ae 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -455,7 +455,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, struct ieee80211_tx_rate *rates; struct ath_tx_info_priv *tx_info_priv; u32 max_4ms_framelen, frmlen; - u16 aggr_limit, legacy = 0, maxampdu; + u16 aggr_limit, legacy = 0; int i; skb = bf->bf_mpdu; @@ -490,16 +490,15 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy) return 0; - aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_DEFAULT); + aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_MAX); /* * h/w can accept aggregates upto 16 bit lengths (65535). * The IE, however can hold upto 65536, which shows up here * as zero. Ignore 65536 since we are constrained by hw. */ - maxampdu = tid->an->maxampdu; - if (maxampdu) - aggr_limit = min(aggr_limit, maxampdu); + if (tid->an->maxampdu) + aggr_limit = min(aggr_limit, tid->an->maxampdu); return aggr_limit; } @@ -507,7 +506,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, /* * Returns the number of delimiters to be added to * meet the minimum required mpdudensity. - * caller should make sure that the rate is HT rate . */ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, struct ath_buf *bf, u16 frmlen) @@ -515,7 +513,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, const struct ath_rate_table *rt = sc->cur_rate_table; struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - u32 nsymbits, nsymbols, mpdudensity; + u32 nsymbits, nsymbols; u16 minlen; u8 rc, flags, rix; int width, half_gi, ndelim, mindelim; @@ -537,14 +535,12 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, * on highest rate in rate series (i.e. first rate) to determine * required minimum length for subframe. Take into account * whether high rate is 20 or 40Mhz and half or full GI. - */ - mpdudensity = tid->an->mpdudensity; - - /* + * * If there is no mpdu density restriction, no further calculation * is needed. */ - if (mpdudensity == 0) + + if (tid->an->mpdudensity == 0) return ndelim; rix = tx_info->control.rates[0].idx; @@ -554,9 +550,9 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0; if (half_gi) - nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity); + nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity); else - nsymbols = NUM_SYMBOLS_PER_USEC(mpdudensity); + nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity); if (nsymbols == 0) nsymbols = 1; -- cgit v1.2.3-18-g5258 From 3fa52056f3a8e755708241d5795e6d3e6f55ad85 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jul 2009 13:23:09 +0200 Subject: mac80211: fix PS-poll response, race When a station queries us for a PS-poll response, we wrongly queue the frame on the virtual interface's queue rather than the pending queue. Additionally, fix a race condition where we could potentially send multiple frames to the sleeping station due to using a station flag rather than a packet flag. When converting to a packet flag, we can also convert p54 and remove the filter clearing we added for it. (Also remove a now dead function) Signed-off-by: Johannes Berg Reported-by: Bob Copeland Tested-by: Bob Copeland Cc: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 0d589d68e54..c32a0d2fa1f 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -614,7 +614,7 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb, if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR; - if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) + if (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE) *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; *queue = skb_get_queue_mapping(skb) + P54_QUEUE_DATA; -- cgit v1.2.3-18-g5258 From ac88b6ecdfa629fd1261dab1504d78a56fd4cabf Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Thu, 23 Jul 2009 10:59:57 +0530 Subject: ath9k: Add support for AR9287 based chipsets. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/calib.c | 22 +- drivers/net/wireless/ath/ath9k/eeprom.c | 1203 ++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath9k/eeprom.h | 163 ++++- drivers/net/wireless/ath/ath9k/hw.c | 110 ++- drivers/net/wireless/ath/ath9k/hw.h | 4 + drivers/net/wireless/ath/ath9k/main.c | 3 +- drivers/net/wireless/ath/ath9k/pci.c | 2 + drivers/net/wireless/ath/ath9k/phy.h | 1 + 8 files changed, 1482 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 1f0c5fe4a68..d1bbb02af8d 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -116,7 +116,7 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah, "NF calibrated [ctl] [chain 1] is %d\n", nf); nfarray[1] = nf; - if (!AR_SREV_9280(ah)) { + if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) { nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), AR_PHY_CH2_MINCCA_PWR); if (nf & 0x100) @@ -154,7 +154,7 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah, "NF calibrated [ext] [chain 1] is %d\n", nf); nfarray[4] = nf; - if (!AR_SREV_9280(ah)) { + if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) { nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), AR_PHY_CH2_EXT_MINCCA_PWR); if (nf & 0x100) @@ -613,7 +613,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) if (AR_SREV_9285(ah)) chainmask = 0x9; - else if (AR_SREV_9280(ah)) + else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) chainmask = 0x1B; else chainmask = 0x3F; @@ -873,7 +873,7 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, if (AR_SREV_9285_11_OR_LATER(ah)) ath9k_hw_9285_pa_cal(ah); - if (OLC_FOR_AR9280_20_LATER) + if (OLC_FOR_AR9280_20_LATER || OLC_FOR_AR9287_10_LATER) ath9k_olc_temp_compensation(ah); ath9k_hw_getnf(ah, chan); ath9k_hw_loadnf(ah, ah->curchan); @@ -929,8 +929,11 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) return false; } else { if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + if (!AR_SREV_9287_10_OR_LATER(ah)) + REG_CLR_BIT(ah, AR_PHY_ADC_CTL, + AR_PHY_ADC_CTL_OFF_PWDADC); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_FLTR_CAL); } /* Calibrate the AGC */ @@ -948,8 +951,11 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) } if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + if (!AR_SREV_9287_10_OR_LATER(ah)) + REG_SET_BIT(ah, AR_PHY_ADC_CTL, + AR_PHY_ADC_CTL_OFF_PWDADC); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_FLTR_CAL); } } diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index df41ed5fd7c..9b1d960dc80 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -2781,11 +2781,1210 @@ static struct eeprom_ops eep_def_ops = { .get_spur_channel = ath9k_hw_def_get_spur_channel }; + +static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah) +{ + return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF; +} + +static int ath9k_hw_AR9287_get_eeprom_rev(struct ath_hw *ah) +{ + return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF; +} + +static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) +{ + struct ar9287_eeprom_t *eep = &ah->eeprom.map9287; + u16 *eep_data; + int addr, eep_start_loc = AR9287_EEP_START_LOC; + eep_data = (u16 *)eep; + if (!ath9k_hw_use_flash(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); + } + + for (addr = 0; addr < sizeof(struct ar9287_eeprom_t) / sizeof(u16); + addr++) { + if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Unable to read eeprom region \n"); + return false; + } + eep_data++; + } + return true; +} +static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) +{ +#define SIZE_EEPROM_87 (sizeof(struct ar9287_eeprom_t) / sizeof(u16)) + u32 sum = 0, el, integer; + u16 temp, word, magic, magic2, *eepdata; + int i, addr; + bool need_swap = false; + struct ar9287_eeprom_t *eep = &ah->eeprom.map9287; + + if (!ath9k_hw_use_flash(ah)) { + if (!ath9k_hw_nvram_read + (ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Reading Magic # failed\n"); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); + if (magic != AR5416_EEPROM_MAGIC) { + + + magic2 = swab16(magic); + + if (magic2 == AR5416_EEPROM_MAGIC) { + need_swap = true; + eepdata = (u16 *)(&ah->eeprom); + + for (addr = 0; addr < SIZE_EEPROM_87; addr++) { + temp = swab16(*eepdata); + *eepdata = temp; + eepdata++; + } + } else { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Invalid EEPROM Magic. " + "endianness mismatch.\n"); + return -EINVAL; } + } + } + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ? + "True" : "False"); + + if (need_swap) + el = swab16(ah->eeprom.map9287.baseEepHeader.length); + else + el = ah->eeprom.map9287.baseEepHeader.length; + + eepdata = (u16 *)(&ah->eeprom); + for (i = 0; i < min(el, SIZE_EEPROM_87); i++) + sum ^= *eepdata++; + + if (need_swap) { + word = swab16(eep->baseEepHeader.length); + eep->baseEepHeader.length = word; + + word = swab16(eep->baseEepHeader.checksum); + eep->baseEepHeader.checksum = word; + + word = swab16(eep->baseEepHeader.version); + eep->baseEepHeader.version = word; + + word = swab16(eep->baseEepHeader.regDmn[0]); + eep->baseEepHeader.regDmn[0] = word; + + word = swab16(eep->baseEepHeader.regDmn[1]); + eep->baseEepHeader.regDmn[1] = word; + + word = swab16(eep->baseEepHeader.rfSilent); + eep->baseEepHeader.rfSilent = word; + + word = swab16(eep->baseEepHeader.blueToothOptions); + eep->baseEepHeader.blueToothOptions = word; + + word = swab16(eep->baseEepHeader.deviceCap); + eep->baseEepHeader.deviceCap = word; + + integer = swab32(eep->modalHeader.antCtrlCommon); + eep->modalHeader.antCtrlCommon = integer; + + for (i = 0; i < AR9287_MAX_CHAINS; i++) { + integer = swab32(eep->modalHeader.antCtrlChain[i]); + eep->modalHeader.antCtrlChain[i] = integer; + } + + for (i = 0; i < AR9287_EEPROM_MODAL_SPURS; i++) { + word = swab16(eep->modalHeader.spurChans[i].spurChan); + eep->modalHeader.spurChans[i].spurChan = word; + } + } + + if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER + || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Bad EEPROM checksum 0x%x or revision 0x%04x\n", + sum, ah->eep_ops->get_eeprom_ver(ah)); + return -EINVAL; + } + + return 0; +#undef SIZE_EEPROM_87 +} + +static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah, + enum eeprom_param param) +{ + struct ar9287_eeprom_t *eep = &ah->eeprom.map9287; + struct modal_eep_ar9287_header *pModal = &eep->modalHeader; + struct base_eep_ar9287_header *pBase = &eep->baseEepHeader; + u16 ver_minor; + + ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK; + switch (param) { + case EEP_NFTHRESH_2: + return pModal->noiseFloorThreshCh[0]; + case AR_EEPROM_MAC(0): + return pBase->macAddr[0] << 8 | pBase->macAddr[1]; + case AR_EEPROM_MAC(1): + return pBase->macAddr[2] << 8 | pBase->macAddr[3]; + case AR_EEPROM_MAC(2): + return pBase->macAddr[4] << 8 | pBase->macAddr[5]; + case EEP_REG_0: + return pBase->regDmn[0]; + case EEP_REG_1: + return pBase->regDmn[1]; + case EEP_OP_CAP: + return pBase->deviceCap; + case EEP_OP_MODE: + return pBase->opCapFlags; + case EEP_RF_SILENT: + return pBase->rfSilent; + case EEP_MINOR_REV: + return ver_minor; + case EEP_TX_MASK: + return pBase->txMask; + case EEP_RX_MASK: + return pBase->rxMask; + case EEP_DEV_TYPE: + return pBase->deviceType; + case EEP_OL_PWRCTRL: + return pBase->openLoopPwrCntl; + case EEP_TEMPSENSE_SLOPE: + if (ver_minor >= AR9287_EEP_MINOR_VER_2) + return pBase->tempSensSlope; + else + return 0; + case EEP_TEMPSENSE_SLOPE_PAL_ON: + if (ver_minor >= AR9287_EEP_MINOR_VER_3) + return pBase->tempSensSlopePalOn; + else + return 0; + default: + return 0; + } +} + + +static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_data_per_freq_ar9287 *pRawDataSet, + u8 *bChans, u16 availPiers, + u16 tPdGainOverlap, int16_t *pMinCalPower, + u16 *pPdGainBoundaries, u8 *pPDADCValues, + u16 numXpdGains) +{ +#define TMP_VAL_VPD_TABLE \ + ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); + int i, j, k; + int16_t ss; + u16 idxL = 0, idxR = 0, numPiers; + u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; + u8 minPwrT4[AR9287_NUM_PD_GAINS]; + u8 maxPwrT4[AR9287_NUM_PD_GAINS]; + int16_t vpdStep; + int16_t tmpVal; + u16 sizeCurrVpdTable, maxIndex, tgtIndex; + bool match; + int16_t minDelta = 0; + struct chan_centers centers; + static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (bChans[numPiers] == AR9287_BCHAN_UNUSED) + break; + } + + match = ath9k_hw_get_lower_upper_index( + (u8)FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)), bChans, numPiers, + &idxL, &idxR); + + if (match) { + for (i = 0; i < numXpdGains; i++) { + minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; + maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pRawDataSet[idxL].pwrPdg[i], + pRawDataSet[idxL].vpdPdg[i], + AR9287_PD_GAIN_ICEPTS, vpdTableI[i]); + } + } else { + for (i = 0; i < numXpdGains; i++) { + pVpdL = pRawDataSet[idxL].vpdPdg[i]; + pPwrL = pRawDataSet[idxL].pwrPdg[i]; + pVpdR = pRawDataSet[idxR].vpdPdg[i]; + pPwrR = pRawDataSet[idxR].pwrPdg[i]; + + minPwrT4[i] = max(pPwrL[0], pPwrR[0]); + + maxPwrT4[i] = + min(pPwrL[AR9287_PD_GAIN_ICEPTS - 1], + pPwrR[AR9287_PD_GAIN_ICEPTS - 1]); + + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrL, pVpdL, + AR9287_PD_GAIN_ICEPTS, + vpdTableL[i]); + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrR, pVpdR, + AR9287_PD_GAIN_ICEPTS, + vpdTableR[i]); + + for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { + vpdTableI[i][j] = + (u8)(ath9k_hw_interpolate((u16) + FREQ2FBIN(centers. synth_center, + IS_CHAN_2GHZ(chan)), + bChans[idxL], bChans[idxR], + vpdTableL[i][j], vpdTableR[i][j])); + } + } + } + *pMinCalPower = (int16_t)(minPwrT4[0] / 2); + + k = 0; + for (i = 0; i < numXpdGains; i++) { + if (i == (numXpdGains - 1)) + pPdGainBoundaries[i] = (u16)(maxPwrT4[i] / 2); + else + pPdGainBoundaries[i] = (u16)((maxPwrT4[i] + + minPwrT4[i+1]) / 4); + + pPdGainBoundaries[i] = min((u16)AR5416_MAX_RATE_POWER, + pPdGainBoundaries[i]); + + + if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { + minDelta = pPdGainBoundaries[0] - 23; + pPdGainBoundaries[0] = 23; + } else + minDelta = 0; + + if (i == 0) { + if (AR_SREV_9280_10_OR_LATER(ah)) + ss = (int16_t)(0 - (minPwrT4[i] / 2)); + else + ss = 0; + } else + ss = (int16_t)((pPdGainBoundaries[i-1] - + (minPwrT4[i] / 2)) - + tPdGainOverlap + 1 + minDelta); + + vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + while ((ss < 0) && (k < (AR9287_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); + pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = (u8)((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); + tgtIndex = (u8)(pPdGainBoundaries[i] + + tPdGainOverlap - (minPwrT4[i] / 2)); + maxIndex = (tgtIndex < sizeCurrVpdTable) ? + tgtIndex : sizeCurrVpdTable; + + while ((ss < maxIndex) && (k < (AR9287_NUM_PDADC_VALUES - 1))) + pPDADCValues[k++] = vpdTableI[i][ss++]; + + vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - + vpdTableI[i][sizeCurrVpdTable - 2]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + if (tgtIndex > maxIndex) { + while ((ss <= tgtIndex) && + (k < (AR9287_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t) TMP_VAL_VPD_TABLE; + pPDADCValues[k++] = (u8)((tmpVal > 255) ? + 255 : tmpVal); + ss++; + } + } + } + + while (i < AR9287_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = pPdGainBoundaries[i-1]; + i++; + } + + while (k < AR9287_NUM_PDADC_VALUES) { + pPDADCValues[k] = pPDADCValues[k-1]; + k++; + } + +#undef TMP_VAL_VPD_TABLE +} + +static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop, + u8 *pCalChans, u16 availPiers, + int8_t *pPwr) +{ + u8 pcdac, i = 0; + u16 idxL = 0, idxR = 0, numPiers; + bool match; + struct chan_centers centers; + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (pCalChans[numPiers] == AR9287_BCHAN_UNUSED) + break; + } + + match = ath9k_hw_get_lower_upper_index( + (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), + pCalChans, numPiers, + &idxL, &idxR); + + if (match) { + pcdac = pRawDatasetOpLoop[idxL].pcdac[0][0]; + *pPwr = pRawDatasetOpLoop[idxL].pwrPdg[0][0]; + } else { + pcdac = pRawDatasetOpLoop[idxR].pcdac[0][0]; + *pPwr = (pRawDatasetOpLoop[idxL].pwrPdg[0][0] + + pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; + } + + while ((pcdac > ah->originalGain[i]) && + (i < (AR9280_TX_GAIN_TABLE_SIZE - 1))) + i++; +} + +static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah, + int32_t txPower, u16 chain) +{ + u32 tmpVal; + u32 a; + + tmpVal = REG_READ(ah, 0xa270); + tmpVal = tmpVal & 0xFCFFFFFF; + tmpVal = tmpVal | (0x3 << 24); + REG_WRITE(ah, 0xa270, tmpVal); + + tmpVal = REG_READ(ah, 0xb270); + tmpVal = tmpVal & 0xFCFFFFFF; + tmpVal = tmpVal | (0x3 << 24); + REG_WRITE(ah, 0xb270, tmpVal); + + if (chain == 0) { + tmpVal = REG_READ(ah, 0xa398); + tmpVal = tmpVal & 0xff00ffff; + a = (txPower)&0xff; + tmpVal = tmpVal | (a << 16); + REG_WRITE(ah, 0xa398, tmpVal); + } + + if (chain == 1) { + tmpVal = REG_READ(ah, 0xb398); + tmpVal = tmpVal & 0xff00ffff; + a = (txPower)&0xff; + tmpVal = tmpVal | (a << 16); + REG_WRITE(ah, 0xb398, tmpVal); + } +} + + +static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, + struct ath9k_channel *chan, int16_t *pTxPowerIndexOffset) +{ + struct cal_data_per_freq_ar9287 *pRawDataset; + struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop; + u8 *pCalBChans = NULL; + u16 pdGainOverlap_t2; + u8 pdadcValues[AR9287_NUM_PDADC_VALUES]; + u16 gainBoundaries[AR9287_PD_GAINS_IN_MASK]; + u16 numPiers = 0, i, j; + int16_t tMinCalPower; + u16 numXpdGain, xpdMask; + u16 xpdGainValues[AR9287_NUM_PD_GAINS] = {0, 0, 0, 0}; + u32 reg32, regOffset, regChainOffset; + int16_t modalIdx, diff = 0; + struct ar9287_eeprom_t *pEepData = &ah->eeprom.map9287; + modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; + xpdMask = pEepData->modalHeader.xpdGain; + if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= + AR9287_EEP_MINOR_VER_2) + pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap; + else + pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); + + if (IS_CHAN_2GHZ(chan)) { + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR9287_NUM_2G_CAL_PIERS; + if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { + pRawDatasetOpenLoop = + (struct cal_data_op_loop_ar9287 *) + pEepData->calPierData2G[0]; + ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0]; + } + } + + numXpdGain = 0; + for (i = 1; i <= AR9287_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR9287_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR9287_NUM_PD_GAINS) + break; + xpdGainValues[numXpdGain] = + (u16)(AR9287_PD_GAINS_IN_MASK-i); + numXpdGain++; + } + } + + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (numXpdGain - 1) & 0x3); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, + xpdGainValues[0]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, + xpdGainValues[1]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, + xpdGainValues[2]); + + for (i = 0; i < AR9287_MAX_CHAINS; i++) { + regChainOffset = i * 0x1000; + if (pEepData->baseEepHeader.txMask & (1 << i)) { + pRawDatasetOpenLoop = (struct cal_data_op_loop_ar9287 *) + pEepData->calPierData2G[i]; + if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { + int8_t txPower; + ar9287_eeprom_get_tx_gain_index(ah, chan, + pRawDatasetOpenLoop, + pCalBChans, numPiers, + &txPower); + ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i); + } else { + pRawDataset = + (struct cal_data_per_freq_ar9287 *) + pEepData->calPierData2G[i]; + ath9k_hw_get_AR9287_gain_boundaries_pdadcs( + ah, chan, pRawDataset, + pCalBChans, numPiers, + pdGainOverlap_t2, + &tMinCalPower, gainBoundaries, + pdadcValues, numXpdGain); + } + + if (i == 0) { + if (!ath9k_hw_AR9287_get_eeprom( + ah, EEP_OL_PWRCTRL)) { + REG_WRITE(ah, AR_PHY_TPCRG5 + + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | + SM(gainBoundaries[0], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) + | SM(gainBoundaries[1], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) + | SM(gainBoundaries[2], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) + | SM(gainBoundaries[3], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + } + } + + if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB != + pEepData->baseEepHeader.pwrTableOffset) { + diff = (u16) + (pEepData->baseEepHeader.pwrTableOffset + - (int32_t)AR9287_PWR_TABLE_OFFSET_DB); + diff *= 2; + + for (j = 0; + j < ((u16)AR9287_NUM_PDADC_VALUES-diff); + j++) + pdadcValues[j] = pdadcValues[j+diff]; + + for (j = (u16)(AR9287_NUM_PDADC_VALUES-diff); + j < AR9287_NUM_PDADC_VALUES; j++) + pdadcValues[j] = + pdadcValues[ + AR9287_NUM_PDADC_VALUES-diff]; + } + if (!ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { + regOffset = AR_PHY_BASE + (672 << 2) + + regChainOffset; + for (j = 0; j < 32; j++) { + reg32 = ((pdadcValues[4*j + 0] + & 0xFF) << 0) | + ((pdadcValues[4*j + 1] + & 0xFF) << 8) | + ((pdadcValues[4*j + 2] + & 0xFF) << 16) | + ((pdadcValues[4*j + 3] + & 0xFF) << 24) ; + REG_WRITE(ah, regOffset, reg32); + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PDADC (%d,%4x): %4.4x %8.8x\n", + i, regChainOffset, regOffset, + reg32); + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PDADC: Chain %d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, + pdadcValues[4 * j + 1], + 4 * j + 2, + pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); + + regOffset += 4; + } + } + } + } + + *pTxPowerIndexOffset = 0; +} + + +static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, + struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl, + u16 AntennaReduction, u16 twiceMaxRegulatoryPower, + u16 powerLimit) +{ +#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 +#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 + + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + static const u16 tpScaleReductionTable[5] = { 0, 3, 6, 9, + AR5416_MAX_RATE_POWER }; + int i; + int16_t twiceLargestAntenna; + struct cal_ctl_data_ar9287 *rep; + struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} }, + targetPowerCck = {0, {0, 0, 0, 0} }; + struct cal_target_power_leg targetPowerOfdmExt = {0, {0, 0, 0, 0} }, + targetPowerCckExt = {0, {0, 0, 0, 0} }; + struct cal_target_power_ht targetPowerHt20, + targetPowerHt40 = {0, {0, 0, 0, 0} }; + u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 ctlModesFor11g[] = {CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, + CTL_11G_EXT, CTL_2GHT40}; + u16 numCtlModes = 0, *pCtlMode = NULL, ctlMode, freq; + struct chan_centers centers; + int tx_chainmask; + u16 twiceMinEdgePower; + struct ar9287_eeprom_t *pEepData = &ah->eeprom.map9287; + tx_chainmask = ah->txchainmask; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0], + pEepData->modalHeader.antennaGainCh[1]); + + twiceLargestAntenna = (int16_t)min((AntennaReduction) - + twiceLargestAntenna, 0); + + maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; + if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) + maxRegAllowedPower -= + (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); + + scaledPower = min(powerLimit, maxRegAllowedPower); + + switch (ar5416_get_ntxchains(tx_chainmask)) { + case 1: + break; + case 2: + scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; + break; + case 3: + scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; + break; + } + scaledPower = max((u16)0, scaledPower); + + if (IS_CHAN_2GHZ(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g) - + SUB_NUM_CTL_MODES_AT_2G_40; + pCtlMode = ctlModesFor11g; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR9287_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCck, 4, false); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR9287_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT20, + AR9287_NUM_2G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT40, + AR9287_NUM_2G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR9287_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCckExt, 4, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR9287_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + } + + for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { + + bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || + (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) + freq = centers.synth_center; + else if (pCtlMode[ctlMode] & EXT_ADDITIVE) + freq = centers.ext_center; + else + freq = centers.ctl_center; + + + if (ah->eep_ops->get_eeprom_ver(ah) == 14 && + ah->eep_ops->get_eeprom_rev(ah) <= 2) + twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d," + "EXT_ADDITIVE %d\n", ctlMode, numCtlModes, + isHt40CtlMode, (pCtlMode[ctlMode] & EXT_ADDITIVE)); + for (i = 0; (i < AR9287_NUM_CTLS) + && pEepData->ctlIndex[i]; i++) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "LOOP-Ctlidx %d: cfgCtl 0x%2.2x" + "pCtlMode 0x%2.2x ctlIndex 0x%2.2x" + "chan %d chanctl=xxxx\n", + i, cfgCtl, pCtlMode[ctlMode], + pEepData->ctlIndex[i], chan->channel); + + if ((((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + pEepData->ctlIndex[i]) || + (((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & + CTL_MODE_M) | SD_NO_CTL))) { + + rep = &(pEepData->ctlData[i]); + twiceMinEdgePower = ath9k_hw_get_max_edge_power( + freq, + rep->ctlEdges[ar5416_get_ntxchains( + tx_chainmask) - 1], + IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "MATCH-EE_IDX %d: ch %d is2 %d" + "2xMinEdge %d chainmask %d chains %d\n", + i, freq, IS_CHAN_2GHZ(chan), + twiceMinEdgePower, tx_chainmask, + ar5416_get_ntxchains(tx_chainmask)); + + if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) + twiceMaxEdgePower = min( + twiceMaxEdgePower, + twiceMinEdgePower); + else { + twiceMaxEdgePower = twiceMinEdgePower; + break; + } + } + } + + minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d" + "sP %d minCtlPwr %d\n", + ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, + scaledPower, minCtlPower); + + + switch (pCtlMode[ctlMode]) { + + case CTL_11B: + for (i = 0; + i < ARRAY_SIZE(targetPowerCck.tPow2x); + i++) { + targetPowerCck.tPow2x[i] = (u8)min( + (u16)targetPowerCck.tPow2x[i], + minCtlPower); + } + break; + case CTL_11A: + case CTL_11G: + for (i = 0; + i < ARRAY_SIZE(targetPowerOfdm.tPow2x); + i++) { + targetPowerOfdm.tPow2x[i] = (u8)min( + (u16)targetPowerOfdm.tPow2x[i], + minCtlPower); + } + break; + case CTL_5GHT20: + case CTL_2GHT20: + for (i = 0; + i < ARRAY_SIZE(targetPowerHt20.tPow2x); + i++) { + targetPowerHt20.tPow2x[i] = (u8)min( + (u16)targetPowerHt20.tPow2x[i], + minCtlPower); + } + break; + case CTL_11B_EXT: + targetPowerCckExt.tPow2x[0] = (u8)min( + (u16)targetPowerCckExt.tPow2x[0], + minCtlPower); + break; + case CTL_11A_EXT: + case CTL_11G_EXT: + targetPowerOfdmExt.tPow2x[0] = (u8)min( + (u16)targetPowerOfdmExt.tPow2x[0], + minCtlPower); + break; + case CTL_5GHT40: + case CTL_2GHT40: + for (i = 0; + i < ARRAY_SIZE(targetPowerHt40.tPow2x); + i++) { + targetPowerHt40.tPow2x[i] = (u8)min( + (u16)targetPowerHt40.tPow2x[i], + minCtlPower); + } + break; + default: + break; + } + } + + ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = + ratesArray[rate18mb] = ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; + ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; + ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; + ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; + + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) + ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; + + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate2s] = ratesArray[rate2l] = + targetPowerCck.tPow2x[1]; + ratesArray[rate5_5s] = ratesArray[rate5_5l] = + targetPowerCck.tPow2x[2]; + ratesArray[rate11s] = ratesArray[rate11l] = + targetPowerCck.tPow2x[3]; + } + if (IS_CHAN_HT40(chan)) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) + ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i]; + + ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; + ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; + ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; + if (IS_CHAN_2GHZ(chan)) + ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; + } +#undef REDUCE_SCALED_POWER_BY_TWO_CHAIN +#undef REDUCE_SCALED_POWER_BY_THREE_CHAIN +} + +static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, + struct ath9k_channel *chan, u16 cfgCtl, + u8 twiceAntennaReduction, u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ +#define INCREASE_MAXPOW_BY_TWO_CHAIN 6 +#define INCREASE_MAXPOW_BY_THREE_CHAIN 10 + struct ar9287_eeprom_t *pEepData = &ah->eeprom.map9287; + struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; + int16_t ratesArray[Ar5416RateSize]; + int16_t txPowerIndexOffset = 0; + u8 ht40PowerIncForPdadc = 2; + int i; + memset(ratesArray, 0, sizeof(ratesArray)); + + if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= + AR9287_EEP_MINOR_VER_2) + ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; + + ath9k_hw_set_AR9287_power_per_rate_table(ah, chan, + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit); + + + ath9k_hw_set_AR9287_power_cal_table(ah, chan, &txPowerIndexOffset); + + for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { + ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); + if (ratesArray[i] > AR9287_MAX_RATE_POWER) + ratesArray[i] = AR9287_MAX_RATE_POWER; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + for (i = 0; i < Ar5416RateSize; i++) + ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; + } + + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) + | ATH9K_POW_SM(ratesArray[rate9mb], 8) + | ATH9K_POW_SM(ratesArray[rate6mb], 0) + ); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + ATH9K_POW_SM(ratesArray[rate54mb], 24) + | ATH9K_POW_SM(ratesArray[rate48mb], 16) + | ATH9K_POW_SM(ratesArray[rate36mb], 8) + | ATH9K_POW_SM(ratesArray[rate24mb], 0) + ); + + if (IS_CHAN_2GHZ(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0) + ); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0) + ); + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, + ATH9K_POW_SM(ratesArray[rateHt20_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_0], 0) + ); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, + ATH9K_POW_SM(ratesArray[rateHt20_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_4], 0) + ); + + if (IS_CHAN_HT40(chan)) { + if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0], 0) + ); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4], 0) + ); + } else { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0] + + ht40PowerIncForPdadc, 0) + ); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4] + + ht40PowerIncForPdadc, 0) + ); + + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(ratesArray[rateExtCck], 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0) + ); + } + + + if (IS_CHAN_2GHZ(chan)) + i = rate1l; + else + i = rate6mb; + + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->regulatory.max_power_level = + ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2; + else + ah->regulatory.max_power_level = ratesArray[i]; + + switch (ar5416_get_ntxchains(ah->txchainmask)) { + case 1: + break; + case 2: + ah->regulatory.max_power_level += + INCREASE_MAXPOW_BY_TWO_CHAIN; + break; + case 3: + ah->regulatory.max_power_level += + INCREASE_MAXPOW_BY_THREE_CHAIN; + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Invalid chainmask configuration\n"); + break; + } +} + +static void ath9k_hw_AR9287_set_addac(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + return; +} + +static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct ar9287_eeprom_t *eep = &ah->eeprom.map9287; + struct modal_eep_ar9287_header *pModal = &eep->modalHeader; + + u16 antWrites[AR9287_ANT_16S]; + u32 regChainOffset; + u8 txRxAttenLocal; + int i, j, offset_num; + + pModal = &eep->modalHeader; + + antWrites[0] = (u16)((pModal->antCtrlCommon >> 28) & 0xF); + antWrites[1] = (u16)((pModal->antCtrlCommon >> 24) & 0xF); + antWrites[2] = (u16)((pModal->antCtrlCommon >> 20) & 0xF); + antWrites[3] = (u16)((pModal->antCtrlCommon >> 16) & 0xF); + antWrites[4] = (u16)((pModal->antCtrlCommon >> 12) & 0xF); + antWrites[5] = (u16)((pModal->antCtrlCommon >> 8) & 0xF); + antWrites[6] = (u16)((pModal->antCtrlCommon >> 4) & 0xF); + antWrites[7] = (u16)(pModal->antCtrlCommon & 0xF); + + offset_num = 8; + + for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) { + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 28) & 0xf); + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 10) & 0x3); + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 8) & 0x3); + antWrites[j++] = 0; + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 6) & 0x3); + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 4) & 0x3); + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 2) & 0x3); + antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3); + } + + + REG_WRITE(ah, AR_PHY_SWITCH_COM, + ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); + + for (i = 0; i < AR9287_MAX_CHAINS; i++) { + regChainOffset = i * 0x1000; + + REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, + pModal->antCtrlChain[i]); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, + (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) + & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + + txRxAttenLocal = pModal->txRxAttenCh[i]; + + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, + pModal->bswMargin[i]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, + pModal->bswAtten[i]); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_ATTEN, + txRxAttenLocal); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_MARGIN, + pModal->rxTxMarginCh[i]); + } + + + if (IS_CHAN_HT40(chan)) + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); + else + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, pModal->switchSettling); + + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, + AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize); + + REG_WRITE(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) + | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) + | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) + | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, + AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); + + REG_RMW_FIELD(ah, AR_PHY_CCA, + AR9280_PHY_CCA_THRESH62, pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, + AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62); + + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB1, + AR9287_AN_RF2G3_DB1_S, pModal->db1); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB2, + AR9287_AN_RF2G3_DB2_S, pModal->db2); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, + AR9287_AN_RF2G3_OB_CCK, + AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, + AR9287_AN_RF2G3_OB_PSK, + AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, + AR9287_AN_RF2G3_OB_QAM, + AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, + AR9287_AN_RF2G3_OB_PAL_OFF, + AR9287_AN_RF2G3_OB_PAL_OFF_S, + pModal->ob_pal_off); + + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, + AR9287_AN_RF2G3_DB1, AR9287_AN_RF2G3_DB1_S, + pModal->db1); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, AR9287_AN_RF2G3_DB2, + AR9287_AN_RF2G3_DB2_S, pModal->db2); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, + AR9287_AN_RF2G3_OB_CCK, + AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, + AR9287_AN_RF2G3_OB_PSK, + AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, + AR9287_AN_RF2G3_OB_QAM, + AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, + AR9287_AN_RF2G3_OB_PAL_OFF, + AR9287_AN_RF2G3_OB_PAL_OFF_S, + pModal->ob_pal_off); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, + AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart); + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, + AR_PHY_TX_END_PA_ON, pModal->txFrameToPaOn); + + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TOP2, + AR9287_AN_TOP2_XPABIAS_LVL, + AR9287_AN_TOP2_XPABIAS_LVL_S, + pModal->xpaBiasLvl); +} + +static u8 ath9k_hw_AR9287_get_num_ant_config(struct ath_hw *ah, + enum ieee80211_band freq_band) +{ + return 1; +} + + + + +static u16 ath9k_hw_AR9287_get_eeprom_antenna_cfg(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct ar9287_eeprom_t *eep = &ah->eeprom.map9287; + struct modal_eep_ar9287_header *pModal = &eep->modalHeader; + return pModal->antCtrlCommon & 0xFFFF; +} + + +static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah, + u16 i, bool is2GHz) +{ +#define EEP_MAP9287_SPURCHAN \ + (ah->eeprom.map9287.modalHeader.spurChans[i].spurChan) + u16 spur_val = AR_NO_SPUR; + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur idx %d is2Ghz. %d val %x\n", + i, is2GHz, ah->config.spurchans[i][is2GHz]); + + switch (ah->config.spurmode) { + case SPUR_DISABLE: + break; + case SPUR_ENABLE_IOCTL: + spur_val = ah->config.spurchans[i][is2GHz]; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur val from new loc. %d\n", spur_val); + break; + case SPUR_ENABLE_EEPROM: + spur_val = EEP_MAP9287_SPURCHAN; + break; + } + + return spur_val; + +#undef EEP_MAP9287_SPURCHAN +} + +static struct eeprom_ops eep_AR9287_ops = { + .check_eeprom = ath9k_hw_AR9287_check_eeprom, + .get_eeprom = ath9k_hw_AR9287_get_eeprom, + .fill_eeprom = ath9k_hw_AR9287_fill_eeprom, + .get_eeprom_ver = ath9k_hw_AR9287_get_eeprom_ver, + .get_eeprom_rev = ath9k_hw_AR9287_get_eeprom_rev, + .get_num_ant_config = ath9k_hw_AR9287_get_num_ant_config, + .get_eeprom_antenna_cfg = ath9k_hw_AR9287_get_eeprom_antenna_cfg, + .set_board_values = ath9k_hw_AR9287_set_board_values, + .set_addac = ath9k_hw_AR9287_set_addac, + .set_txpower = ath9k_hw_AR9287_set_txpower, + .get_spur_channel = ath9k_hw_AR9287_get_spur_channel +}; + + int ath9k_hw_eeprom_attach(struct ath_hw *ah) { int status; - - if (AR_SREV_9285(ah)) { + if (AR_SREV_9287(ah)) { + ah->eep_map = EEP_MAP_AR9287; + ah->eep_ops = &eep_AR9287_ops; + } else if (AR_SREV_9285(ah)) { ah->eep_map = EEP_MAP_4KBITS; ah->eep_ops = &eep_4k_ops; } else { diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 67b8bd12941..7ddd016a99f 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -100,6 +100,8 @@ #define AR5416_VER_MASK (eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) #define OLC_FOR_AR9280_20_LATER (AR_SREV_9280_20_OR_LATER(ah) && \ ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) +#define OLC_FOR_AR9287_10_LATER (AR_SREV_9287_10_OR_LATER(ah) && \ + ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) #define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c #define AR_EEPROM_RFSILENT_GPIO_SEL_S 2 @@ -176,6 +178,57 @@ #define AR9280_TX_GAIN_TABLE_SIZE 22 +#define AR9287_EEP_VER 0xE +#define AR9287_EEP_VER_MINOR_MASK 0xFFF +#define AR9287_EEP_MINOR_VER_1 0x1 +#define AR9287_EEP_MINOR_VER_2 0x2 +#define AR9287_EEP_MINOR_VER_3 0x3 +#define AR9287_EEP_MINOR_VER AR9287_EEP_MINOR_VER_3 +#define AR9287_EEP_MINOR_VER_b AR9287_EEP_MINOR_VER +#define AR9287_EEP_NO_BACK_VER AR9287_EEP_MINOR_VER_1 + +#define AR9287_EEP_START_LOC 128 +#define AR9287_NUM_2G_CAL_PIERS 3 +#define AR9287_NUM_2G_CCK_TARGET_POWERS 3 +#define AR9287_NUM_2G_20_TARGET_POWERS 3 +#define AR9287_NUM_2G_40_TARGET_POWERS 3 +#define AR9287_NUM_CTLS 12 +#define AR9287_NUM_BAND_EDGES 4 +#define AR9287_NUM_PD_GAINS 4 +#define AR9287_PD_GAINS_IN_MASK 4 +#define AR9287_PD_GAIN_ICEPTS 1 +#define AR9287_EEPROM_MODAL_SPURS 5 +#define AR9287_MAX_RATE_POWER 63 +#define AR9287_NUM_PDADC_VALUES 128 +#define AR9287_NUM_RATES 16 +#define AR9287_BCHAN_UNUSED 0xFF +#define AR9287_MAX_PWR_RANGE_IN_HALF_DB 64 +#define AR9287_OPFLAGS_11A 0x01 +#define AR9287_OPFLAGS_11G 0x02 +#define AR9287_OPFLAGS_2G_HT40 0x08 +#define AR9287_OPFLAGS_2G_HT20 0x20 +#define AR9287_OPFLAGS_5G_HT40 0x04 +#define AR9287_OPFLAGS_5G_HT20 0x10 +#define AR9287_EEPMISC_BIG_ENDIAN 0x01 +#define AR9287_EEPMISC_WOW 0x02 +#define AR9287_MAX_CHAINS 2 +#define AR9287_ANT_16S 32 +#define AR9287_custdatasize 20 + +#define AR9287_NUM_ANT_CHAIN_FIELDS 6 +#define AR9287_NUM_ANT_COMMON_FIELDS 4 +#define AR9287_SIZE_ANT_CHAIN_FIELD 2 +#define AR9287_SIZE_ANT_COMMON_FIELD 4 +#define AR9287_ANT_CHAIN_MASK 0x3 +#define AR9287_ANT_COMMON_MASK 0xf +#define AR9287_CHAIN_0_IDX 0 +#define AR9287_CHAIN_1_IDX 1 +#define AR9287_DATA_SZ 32 + +#define AR9287_PWR_TABLE_OFFSET_DB -5 + +#define AR9287_CHECKSUM_LOCATION (AR9287_EEP_START_LOC + 1) + enum eeprom_param { EEP_NFTHRESH_5, EEP_NFTHRESH_2, @@ -199,7 +252,11 @@ enum eeprom_param { EEP_OL_PWRCTRL, EEP_RC_CHAIN_MASK, EEP_DAC_HPWR_5G, - EEP_FRAC_N_5G + EEP_FRAC_N_5G, + EEP_DEV_TYPE, + EEP_TEMPSENSE_SLOPE, + EEP_TEMPSENSE_SLOPE_PAL_ON, + EEP_PWR_TABLE_OFFSET }; enum ar5416_rates { @@ -368,6 +425,65 @@ struct modal_eep_4k_header { struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; } __packed; +struct base_eep_ar9287_header { + u16 length; + u16 checksum; + u16 version; + u8 opCapFlags; + u8 eepMisc; + u16 regDmn[2]; + u8 macAddr[6]; + u8 rxMask; + u8 txMask; + u16 rfSilent; + u16 blueToothOptions; + u16 deviceCap; + u32 binBuildNumber; + u8 deviceType; + u8 openLoopPwrCntl; + int8_t pwrTableOffset; + int8_t tempSensSlope; + int8_t tempSensSlopePalOn; + u8 futureBase[29]; +} __packed; + +struct modal_eep_ar9287_header { + u32 antCtrlChain[AR9287_MAX_CHAINS]; + u32 antCtrlCommon; + int8_t antennaGainCh[AR9287_MAX_CHAINS]; + u8 switchSettling; + u8 txRxAttenCh[AR9287_MAX_CHAINS]; + u8 rxTxMarginCh[AR9287_MAX_CHAINS]; + int8_t adcDesiredSize; + u8 txEndToXpaOff; + u8 txEndToRxOn; + u8 txFrameToXpaOn; + u8 thresh62; + int8_t noiseFloorThreshCh[AR9287_MAX_CHAINS]; + u8 xpdGain; + u8 xpd; + int8_t iqCalICh[AR9287_MAX_CHAINS]; + int8_t iqCalQCh[AR9287_MAX_CHAINS]; + u8 pdGainOverlap; + u8 xpaBiasLvl; + u8 txFrameToDataStart; + u8 txFrameToPaOn; + u8 ht40PowerIncForPdadc; + u8 bswAtten[AR9287_MAX_CHAINS]; + u8 bswMargin[AR9287_MAX_CHAINS]; + u8 swSettleHt40; + u8 version; + u8 db1; + u8 db2; + u8 ob_cck; + u8 ob_psk; + u8 ob_qam; + u8 ob_pal_off; + u8 futureModal[30]; + struct spur_chan spurChans[AR9287_EEPROM_MODAL_SPURS]; +} __packed; + + struct cal_data_per_freq { u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; @@ -402,6 +518,29 @@ struct cal_ctl_edges { } __packed; #endif +struct cal_data_op_loop_ar9287 { + u8 pwrPdg[2][5]; + u8 vpdPdg[2][5]; + u8 pcdac[2][5]; + u8 empty[2][5]; +} __packed; + + +struct cal_data_per_freq_ar9287 { + u8 pwrPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS]; + u8 vpdPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS]; +} __packed; + +union cal_data_per_freq_ar9287_u { + struct cal_data_op_loop_ar9287 calDataOpen; + struct cal_data_per_freq_ar9287 calDataClose; +} __packed; + +struct cal_ctl_data_ar9287 { + struct cal_ctl_edges + ctlEdges[AR9287_MAX_CHAINS][AR9287_NUM_BAND_EDGES]; +} __packed; + struct cal_ctl_data { struct cal_ctl_edges ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; @@ -461,6 +600,27 @@ struct ar5416_eeprom_4k { u8 padding; } __packed; +struct ar9287_eeprom_t { + struct base_eep_ar9287_header baseEepHeader; + u8 custData[AR9287_DATA_SZ]; + struct modal_eep_ar9287_header modalHeader; + u8 calFreqPier2G[AR9287_NUM_2G_CAL_PIERS]; + union cal_data_per_freq_ar9287_u + calPierData2G[AR9287_MAX_CHAINS][AR9287_NUM_2G_CAL_PIERS]; + struct cal_target_power_leg + calTargetPowerCck[AR9287_NUM_2G_CCK_TARGET_POWERS]; + struct cal_target_power_leg + calTargetPower2G[AR9287_NUM_2G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower2GHT20[AR9287_NUM_2G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower2GHT40[AR9287_NUM_2G_40_TARGET_POWERS]; + u8 ctlIndex[AR9287_NUM_CTLS]; + struct cal_ctl_data_ar9287 ctlData[AR9287_NUM_CTLS]; + u8 padding; +} __packed; + + enum reg_ext_bitmap { REG_EXT_JAPAN_MIDBAND = 1, REG_EXT_FCC_DFS_HT40 = 2, @@ -480,6 +640,7 @@ struct ath9k_country_entry { enum ath9k_eep_map { EEP_MAP_DEFAULT = 0x0, EEP_MAP_4KBITS, + EEP_MAP_AR9287, EEP_MAP_MAX }; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 605803ae9ed..da3226994de 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -380,6 +380,9 @@ static const char *ath9k_hw_devname(u16 devid) return "Atheros 9280"; case AR9285_DEVID_PCIE: return "Atheros 9285"; + case AR5416_DEVID_AR9287_PCI: + case AR5416_DEVID_AR9287_PCIE: + return "Atheros 9287"; } return NULL; @@ -660,7 +663,8 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, if ((ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCI) && (ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) && (ah->hw_version.macVersion != AR_SREV_VERSION_9160) && - (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) { + (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && + (!AR_SREV_9285(ah)) && (!AR_SREV_9287(ah))) { DPRINTF(sc, ATH_DBG_FATAL, "Mac Chip Rev 0x%02x.%x is not supported by " "this driver\n", ah->hw_version.macVersion, @@ -700,8 +704,37 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, ah->ani_function = ATH9K_ANI_ALL; if (AR_SREV_9280_10_OR_LATER(ah)) ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; + if (AR_SREV_9287_11_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1, + ARRAY_SIZE(ar9287Modes_9287_1_1), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_1, + ARRAY_SIZE(ar9287Common_9287_1_1), 2); + if (ah->config.pcie_clock_req) + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9287PciePhy_clkreq_off_L1_9287_1_1, + ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_1), 2); + else + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9287PciePhy_clkreq_always_on_L1_9287_1_1, + ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_1), + 2); + } else if (AR_SREV_9287_10_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_0, + ARRAY_SIZE(ar9287Modes_9287_1_0), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_0, + ARRAY_SIZE(ar9287Common_9287_1_0), 2); + + if (ah->config.pcie_clock_req) + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9287PciePhy_clkreq_off_L1_9287_1_0, + ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_0), 2); + else + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9287PciePhy_clkreq_always_on_L1_9287_1_0, + ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_0), + 2); + } else if (AR_SREV_9285_12_OR_LATER(ah)) { - if (AR_SREV_9285_12_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2, ARRAY_SIZE(ar9285Modes_9285_1_2), 6); @@ -842,7 +875,28 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, if (ecode != 0) goto bad; - if (AR_SREV_9285_12_OR_LATER(ah)) { + if (AR_SREV_9287_11(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9287Modes_rx_gain_9287_1_1, + ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_1), 6); + else if (AR_SREV_9287_10(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9287Modes_rx_gain_9287_1_0, + ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_0), 6); + else if (AR_SREV_9280_20(ah)) + ath9k_hw_init_rxgain_ini(ah); + + if (AR_SREV_9287_11(ah)) { + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9287Modes_tx_gain_9287_1_1, + ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 6); + } else if (AR_SREV_9287_10(ah)) { + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9287Modes_tx_gain_9287_1_0, + ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_0), 6); + } else if (AR_SREV_9280_20(ah)) { + ath9k_hw_init_txgain_ini(ah); + } else if (AR_SREV_9285_12_OR_LATER(ah)) { u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE); /* txgain table */ @@ -858,14 +912,6 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, } - /* rxgain table */ - if (AR_SREV_9280_20(ah)) - ath9k_hw_init_rxgain_ini(ah); - - /* txgain table */ - if (AR_SREV_9280_20(ah)) - ath9k_hw_init_txgain_ini(ah); - ath9k_hw_fill_cap_info(ah); if ((ah->hw_version.devid == AR9280_DEVID_PCI) && @@ -1165,6 +1211,8 @@ struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error) case AR9280_DEVID_PCI: case AR9280_DEVID_PCIE: case AR9285_DEVID_PCIE: + case AR5416_DEVID_AR9287_PCI: + case AR5416_DEVID_AR9287_PCIE: ah = ath9k_hw_do_attach(devid, sc, error); break; default: @@ -1341,10 +1389,11 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, DO_DELAY(regWrites); } - if (AR_SREV_9280(ah)) + if (AR_SREV_9280(ah) || AR_SREV_9287_10_OR_LATER(ah)) REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites); - if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah)) + if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah) || + AR_SREV_9287_10_OR_LATER(ah)) REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); for (i = 0; i < ah->iniCommon.ia_rows; i++) { @@ -2254,6 +2303,16 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (AR_SREV_9280_10_OR_LATER(ah)) REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); + if (AR_SREV_9287_10_OR_LATER(ah)) { + /* Enable ASYNC FIFO */ + REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3, + AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL); + REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO); + REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3, + AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET); + REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3, + AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET); + } r = ath9k_hw_process_ini(ah, chan, sc->tx_chan_width); if (r) return r; @@ -2330,6 +2389,27 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_init_user_settings(ah); + if (AR_SREV_9287_10_OR_LATER(ah)) { + REG_WRITE(ah, AR_D_GBL_IFS_SIFS, + AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR); + REG_WRITE(ah, AR_D_GBL_IFS_SLOT, + AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR); + REG_WRITE(ah, AR_D_GBL_IFS_EIFS, + AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR); + + REG_WRITE(ah, AR_TIME_OUT, AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR); + REG_WRITE(ah, AR_USEC, AR_USEC_ASYNC_FIFO_DUR); + + REG_SET_BIT(ah, AR_MAC_PCU_LOGIC_ANALYZER, + AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768); + REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN, + AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL); + } + if (AR_SREV_9287_10_OR_LATER(ah)) { + REG_SET_BIT(ah, AR_PCU_MISC_MODE2, + AR_PCU_MISC_MODE2_ENABLE_AGGWEP); + } + REG_WRITE(ah, AR_STA_ID1, REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM); @@ -3644,7 +3724,9 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio) if (gpio >= ah->caps.num_gpio_pins) return 0xffffffff; - if (AR_SREV_9285_10_OR_LATER(ah)) + if (AR_SREV_9287_10_OR_LATER(ah)) + return MS_REG_READ(AR9287, gpio) != 0; + else if (AR_SREV_9285_10_OR_LATER(ah)) return MS_REG_READ(AR9285, gpio) != 0; else if (AR_SREV_9280_10_OR_LATER(ah)) return MS_REG_READ(AR928X, gpio) != 0; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 28bffdb365a..37f7d3defb8 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -42,6 +42,9 @@ #define AR_SUBVENDOR_ID_NEW_A 0x7065 #define AR5416_MAGIC 0x19641014 +#define AR5416_DEVID_AR9287_PCI 0x002D +#define AR5416_DEVID_AR9287_PCIE 0x002E + /* Register read/write primitives */ #define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val)) #define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg)) @@ -400,6 +403,7 @@ struct ath_hw { union { struct ar5416_eeprom_def def; struct ar5416_eeprom_4k map4k; + struct ar9287_eeprom_t map9287; } eeprom; const struct eeprom_ops *eep_ops; enum ath9k_eep_map eep_map; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b3e07e79dae..1c648db1092 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2751,7 +2751,8 @@ static struct { { AR_SREV_VERSION_9100, "9100" }, { AR_SREV_VERSION_9160, "9160" }, { AR_SREV_VERSION_9280, "9280" }, - { AR_SREV_VERSION_9285, "9285" } + { AR_SREV_VERSION_9285, "9285" }, + { AR_SREV_VERSION_9287, "9287" } }; static struct { diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 170c5b32e49..cd4841be80a 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -25,6 +25,8 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = { { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ + { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */ + { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */ { 0 } }; diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index c70f530642f..de4fadadbce 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -375,6 +375,7 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, #define AR_PHY_CHAN_INFO_GAIN 0x9CFC #define AR_PHY_MODE 0xA200 +#define AR_PHY_MODE_ASYNCFIFO 0x80 #define AR_PHY_MODE_AR2133 0x08 #define AR_PHY_MODE_AR5111 0x00 #define AR_PHY_MODE_AR5112 0x08 -- cgit v1.2.3-18-g5258 From e3139fe741b25a0f8a27fd2cdf2ad11734c3d4d3 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 24 Jul 2009 11:13:00 -0700 Subject: iwlwifi: revert to active table when rate is not valid When performing rate scaling, if detected that the new rate index is invalid, clear the search_better_tbl flag so it will not be stuck in the loop. Since the search table is already set up in uCode, we need to empty out the the search table; revert back to the "active" rate and throughput info. Also pass the "active" table setup to uCode to make sure the rate scale is functioning correctly. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 37 ++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 63280411fd5..40207dac6db 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2002,6 +2002,25 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta) } } +/* + * setup rate table in uCode + * return rate_n_flags as used in the table + */ +static u32 rs_update_rate_tbl(struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, + struct iwl_scale_tbl_info *tbl, + int index, u8 is_green) +{ + u32 rate; + + /* Update uCode's rate table. */ + rate = rate_n_flags_from_tbl(priv, tbl, index, is_green); + rs_fill_link_cmd(priv, lq_sta, rate); + iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); + + return rate; +} + /* * Do rate scaling and search for new modulation mode. */ @@ -2098,6 +2117,16 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, if (!((1 << index) & rate_scale_index_msk)) { IWL_ERR(priv, "Current Rate is not valid\n"); + if (lq_sta->search_better_tbl) { + /* revert to active table if search table is not valid*/ + tbl->lq_type = LQ_NONE; + lq_sta->search_better_tbl = 0; + tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); + /* get "active" rate info */ + index = iwl_hwrate_to_plcp_idx(tbl->current_rate); + rate = rs_update_rate_tbl(priv, lq_sta, + tbl, index, is_green); + } return; } @@ -2308,11 +2337,9 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, lq_update: /* Replace uCode's rate table for the destination station. */ - if (update_lq) { - rate = rate_n_flags_from_tbl(priv, tbl, index, is_green); - rs_fill_link_cmd(priv, lq_sta, rate); - iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); - } + if (update_lq) + rate = rs_update_rate_tbl(priv, lq_sta, + tbl, index, is_green); /* Should we stay with this modulation mode, or search for a new one? */ rs_stay_in_table(lq_sta); -- cgit v1.2.3-18-g5258 From 672639de13c4db92ed6a47e68043a4317e219902 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 24 Jul 2009 11:13:01 -0700 Subject: iwlwifi: critical temperature enter/exit condition If advance thermal throttling is used the driver need to pass both "enter" and "exit" temperature to uCode. Using different critical temperature threshold for legacy and advance thermal throttling management based on the type of thermal throttling method is used except 1000. For 1000, it use advance thermal throttling critical temperature threshold, but with legacy thermal management implementation until ucode has the necessary implementations in place. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 76 ++++++++++++++++++++++++++++- drivers/net/wireless/iwlwifi/iwl-4965.c | 3 +- drivers/net/wireless/iwlwifi/iwl-5000.c | 44 ++++++++--------- drivers/net/wireless/iwlwifi/iwl-6000.c | 59 +++++++++++++++++++++- drivers/net/wireless/iwlwifi/iwl-commands.h | 7 +++ drivers/net/wireless/iwlwifi/iwl-core.c | 22 ++++++++- drivers/net/wireless/iwlwifi/iwl-dev.h | 34 ++++++++++++- 7 files changed, 217 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index a899be914eb..80a28184a37 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -55,13 +55,87 @@ #define _IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode" #define IWL1000_MODULE_FIRMWARE(api) _IWL1000_MODULE_FIRMWARE(api) + +/* + * For 1000, use advance thermal throttling critical temperature threshold, + * but legacy thermal management implementation for now. + * This is for the reason of 1000 uCode using advance thermal throttling API + * but not implement ct_kill_exit based on ct_kill exit temperature + * so the thermal throttling will still based on legacy thermal throttling + * management. + * The code here need to be modified once 1000 uCode has the advanced thermal + * throttling algorithm in place + */ +static void iwl1000_set_ct_threshold(struct iwl_priv *priv) +{ + /* want Celsius */ + priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY; + priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; +} + +static struct iwl_lib_ops iwl1000_lib = { + .set_hw_params = iwl5000_hw_set_hw_params, + .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, + .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl, + .txq_set_sched = iwl5000_txq_set_sched, + .txq_agg_enable = iwl5000_txq_agg_enable, + .txq_agg_disable = iwl5000_txq_agg_disable, + .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, + .txq_free_tfd = iwl_hw_txq_free_tfd, + .txq_init = iwl_hw_tx_queue_init, + .rx_handler_setup = iwl5000_rx_handler_setup, + .setup_deferred_work = iwl5000_setup_deferred_work, + .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, + .load_ucode = iwl5000_load_ucode, + .init_alive_start = iwl5000_init_alive_start, + .alive_notify = iwl5000_alive_notify, + .send_tx_power = iwl5000_send_tx_power, + .update_chain_flags = iwl_update_chain_flags, + .apm_ops = { + .init = iwl5000_apm_init, + .reset = iwl5000_apm_reset, + .stop = iwl5000_apm_stop, + .config = iwl5000_nic_config, + .set_pwr_src = iwl_set_pwr_src, + }, + .eeprom_ops = { + .regulatory_bands = { + EEPROM_5000_REG_BAND_1_CHANNELS, + EEPROM_5000_REG_BAND_2_CHANNELS, + EEPROM_5000_REG_BAND_3_CHANNELS, + EEPROM_5000_REG_BAND_4_CHANNELS, + EEPROM_5000_REG_BAND_5_CHANNELS, + EEPROM_5000_REG_BAND_24_FAT_CHANNELS, + EEPROM_5000_REG_BAND_52_FAT_CHANNELS + }, + .verify_signature = iwlcore_eeprom_verify_signature, + .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, + .release_semaphore = iwlcore_eeprom_release_semaphore, + .calib_version = iwl5000_eeprom_calib_version, + .query_addr = iwl5000_eeprom_query_addr, + }, + .post_associate = iwl_post_associate, + .isr = iwl_isr_ict, + .config_ap = iwl_config_ap, + .temp_ops = { + .temperature = iwl5000_temperature, + .set_ct_kill = iwl1000_set_ct_threshold, + }, +}; + +static struct iwl_ops iwl1000_ops = { + .lib = &iwl1000_lib, + .hcmd = &iwl5000_hcmd, + .utils = &iwl5000_hcmd_utils, +}; + struct iwl_cfg iwl1000_bgn_cfg = { .name = "1000 Series BGN", .fw_name_pre = IWL1000_FW_PRE, .ucode_api_max = IWL1000_UCODE_API_MAX, .ucode_api_min = IWL1000_UCODE_API_MIN, .sku = IWL_SKU_G|IWL_SKU_N, - .ops = &iwl5000_ops, + .ops = &iwl1000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index c30a1b96057..23925bd81c6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -776,7 +776,8 @@ static struct iwl_sensitivity_ranges iwl4965_sensitivity = { static void iwl4965_set_ct_threshold(struct iwl_priv *priv) { /* want Kelvin */ - priv->hw_params.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD); + priv->hw_params.ct_kill_threshold = + CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY); } /** diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 702db07fa38..076acb13ba6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -91,7 +91,7 @@ static int iwl5000_apm_stop_master(struct iwl_priv *priv) } -static int iwl5000_apm_init(struct iwl_priv *priv) +int iwl5000_apm_init(struct iwl_priv *priv) { int ret = 0; @@ -137,7 +137,7 @@ static int iwl5000_apm_init(struct iwl_priv *priv) } /* FIXME: this is identical to 4965 */ -static void iwl5000_apm_stop(struct iwl_priv *priv) +void iwl5000_apm_stop(struct iwl_priv *priv) { unsigned long flags; @@ -156,7 +156,7 @@ static void iwl5000_apm_stop(struct iwl_priv *priv) } -static int iwl5000_apm_reset(struct iwl_priv *priv) +int iwl5000_apm_reset(struct iwl_priv *priv) { int ret = 0; @@ -198,7 +198,7 @@ out: } -static void iwl5000_nic_config(struct iwl_priv *priv) +void iwl5000_nic_config(struct iwl_priv *priv) { unsigned long flags; u16 radio_cfg; @@ -290,7 +290,7 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address) return (address & ADDRESS_MSK) + (offset << 1); } -static u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv) +u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv) { struct iwl_eeprom_calib_hdr { u8 version; @@ -436,7 +436,7 @@ static struct iwl_sensitivity_ranges iwl5150_sensitivity = { .nrg_th_ofdm = 95, }; -static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, +const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) { u32 address = eeprom_indirect_address(priv, offset); @@ -447,7 +447,7 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, static void iwl5150_set_ct_threshold(struct iwl_priv *priv) { const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF; - s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) - + s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) - iwl_temp_calib_to_offset(priv); priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef; @@ -456,7 +456,7 @@ static void iwl5150_set_ct_threshold(struct iwl_priv *priv) static void iwl5000_set_ct_threshold(struct iwl_priv *priv) { /* want Celsius */ - priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; + priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY; } /* @@ -631,7 +631,7 @@ static int iwl5000_load_given_ucode(struct iwl_priv *priv, return ret; } -static int iwl5000_load_ucode(struct iwl_priv *priv) +int iwl5000_load_ucode(struct iwl_priv *priv) { int ret = 0; @@ -658,7 +658,7 @@ static int iwl5000_load_ucode(struct iwl_priv *priv) return ret; } -static void iwl5000_init_alive_start(struct iwl_priv *priv) +void iwl5000_init_alive_start(struct iwl_priv *priv) { int ret = 0; @@ -734,7 +734,7 @@ static int iwl5000_send_wimax_coex(struct iwl_priv *priv) sizeof(coex_cmd), &coex_cmd); } -static int iwl5000_alive_notify(struct iwl_priv *priv) +int iwl5000_alive_notify(struct iwl_priv *priv) { u32 a; unsigned long flags; @@ -821,7 +821,7 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) return 0; } -static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) +int iwl5000_hw_set_hw_params(struct iwl_priv *priv) { if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) { @@ -892,7 +892,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) /** * iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array */ -static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, +void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, struct iwl_tx_queue *txq, u16 byte_cnt) { @@ -932,7 +932,7 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; } -static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, +void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, struct iwl_tx_queue *txq) { struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; @@ -987,7 +987,7 @@ static void iwl5000_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id) (1 << IWL50_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); } -static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, +int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, int tx_fifo, int sta_id, int tid, u16 ssn_idx) { unsigned long flags; @@ -1048,7 +1048,7 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, return 0; } -static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, +int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx, u8 tx_fifo) { if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) || @@ -1091,7 +1091,7 @@ u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask * must be called under priv->lock and mac access */ -static void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask) +void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask) { iwl_write_prph(priv, IWL50_SCD_TXFACT, mask); } @@ -1312,13 +1312,13 @@ u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len) return len; } -static void iwl5000_setup_deferred_work(struct iwl_priv *priv) +void iwl5000_setup_deferred_work(struct iwl_priv *priv) { /* in 5000 the tx power calibration is done in uCode */ priv->disable_tx_power_cal = 1; } -static void iwl5000_rx_handler_setup(struct iwl_priv *priv) +void iwl5000_rx_handler_setup(struct iwl_priv *priv) { /* init calibration handlers */ priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] = @@ -1329,7 +1329,7 @@ static void iwl5000_rx_handler_setup(struct iwl_priv *priv) } -static int iwl5000_hw_valid_rtc_data_addr(u32 addr) +int iwl5000_hw_valid_rtc_data_addr(u32 addr) { return (addr >= IWL50_RTC_DATA_LOWER_BOUND) && (addr < IWL50_RTC_DATA_UPPER_BOUND); @@ -1381,7 +1381,7 @@ static int iwl5000_send_rxon_assoc(struct iwl_priv *priv) return ret; } -static int iwl5000_send_tx_power(struct iwl_priv *priv) +int iwl5000_send_tx_power(struct iwl_priv *priv) { struct iwl5000_tx_power_dbm_cmd tx_power_cmd; u8 tx_ant_cfg_cmd; @@ -1401,7 +1401,7 @@ static int iwl5000_send_tx_power(struct iwl_priv *priv) NULL); } -static void iwl5000_temperature(struct iwl_priv *priv) +void iwl5000_temperature(struct iwl_priv *priv) { /* store temperature from statistics (in Celsius) */ priv->temperature = le32_to_cpu(priv->statistics.general.temperature); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 26c5d4a60d1..59ff73536f3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -61,6 +61,63 @@ #define _IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode" #define IWL6050_MODULE_FIRMWARE(api) _IWL6050_MODULE_FIRMWARE(api) +static void iwl6000_set_ct_threshold(struct iwl_priv *priv) +{ + /* want Celsius */ + priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; + priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; +} + +static struct iwl_lib_ops iwl6000_lib = { + .set_hw_params = iwl5000_hw_set_hw_params, + .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, + .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl, + .txq_set_sched = iwl5000_txq_set_sched, + .txq_agg_enable = iwl5000_txq_agg_enable, + .txq_agg_disable = iwl5000_txq_agg_disable, + .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, + .txq_free_tfd = iwl_hw_txq_free_tfd, + .txq_init = iwl_hw_tx_queue_init, + .rx_handler_setup = iwl5000_rx_handler_setup, + .setup_deferred_work = iwl5000_setup_deferred_work, + .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, + .load_ucode = iwl5000_load_ucode, + .init_alive_start = iwl5000_init_alive_start, + .alive_notify = iwl5000_alive_notify, + .send_tx_power = iwl5000_send_tx_power, + .update_chain_flags = iwl_update_chain_flags, + .apm_ops = { + .init = iwl5000_apm_init, + .reset = iwl5000_apm_reset, + .stop = iwl5000_apm_stop, + .config = iwl5000_nic_config, + .set_pwr_src = iwl_set_pwr_src, + }, + .eeprom_ops = { + .regulatory_bands = { + EEPROM_5000_REG_BAND_1_CHANNELS, + EEPROM_5000_REG_BAND_2_CHANNELS, + EEPROM_5000_REG_BAND_3_CHANNELS, + EEPROM_5000_REG_BAND_4_CHANNELS, + EEPROM_5000_REG_BAND_5_CHANNELS, + EEPROM_5000_REG_BAND_24_FAT_CHANNELS, + EEPROM_5000_REG_BAND_52_FAT_CHANNELS + }, + .verify_signature = iwlcore_eeprom_verify_signature, + .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, + .release_semaphore = iwlcore_eeprom_release_semaphore, + .calib_version = iwl5000_eeprom_calib_version, + .query_addr = iwl5000_eeprom_query_addr, + }, + .post_associate = iwl_post_associate, + .isr = iwl_isr_ict, + .config_ap = iwl_config_ap, + .temp_ops = { + .temperature = iwl5000_temperature, + .set_ct_kill = iwl6000_set_ct_threshold, + }, +}; + static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = { .get_hcmd_size = iwl5000_get_hcmd_size, .build_addsta_hcmd = iwl5000_build_addsta_hcmd, @@ -70,7 +127,7 @@ static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = { static struct iwl_ops iwl6000_ops = { .ucode = &iwl5000_ucode, - .lib = &iwl5000_lib, + .lib = &iwl6000_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl6000_hcmd_utils, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index ebb2fbce536..39ede5727fe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2413,6 +2413,13 @@ struct iwl_ct_kill_config { __le32 critical_temperature_R; } __attribute__ ((packed)); +/* 1000, and 6x00 */ +struct iwl_ct_kill_throttling_config { + __le32 critical_temperature_exit; + __le32 reserved; + __le32 critical_temperature_enter; +} __attribute__ ((packed)); + /****************************************************************************** * (8) * Scan Commands, Responses, Notifications: diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 6aea0264480..5ef3c37b581 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2224,6 +2224,7 @@ EXPORT_SYMBOL(iwl_verify_ucode); void iwl_rf_kill_ct_config(struct iwl_priv *priv) { struct iwl_ct_kill_config cmd; + struct iwl_ct_kill_throttling_config adv_cmd; unsigned long flags; int ret = 0; @@ -2232,9 +2233,26 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); spin_unlock_irqrestore(&priv->lock, flags); - cmd.critical_temperature_R = - cpu_to_le32(priv->hw_params.ct_kill_threshold); + switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { + case CSR_HW_REV_TYPE_1000: + case CSR_HW_REV_TYPE_6x00: + case CSR_HW_REV_TYPE_6x50: + adv_cmd.critical_temperature_enter = + cpu_to_le32(priv->hw_params.ct_kill_threshold); + adv_cmd.critical_temperature_exit = + cpu_to_le32(priv->hw_params.ct_kill_exit_threshold); + + ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, + sizeof(adv_cmd), &adv_cmd); + break; + default: + cmd.critical_temperature_R = + cpu_to_le32(priv->hw_params.ct_kill_threshold); + ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, + sizeof(cmd), &cmd); + break; + } ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, sizeof(cmd), &cmd); if (ret) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0751891f4ab..cddf17350c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -63,6 +63,8 @@ extern struct iwl_cfg iwl6050_2agn_cfg; extern struct iwl_cfg iwl6050_3agn_cfg; extern struct iwl_cfg iwl1000_bgn_cfg; +struct iwl_tx_queue; + /* shared structures from iwl-5000.c */ extern struct iwl_mod_params iwl50_mod_params; extern struct iwl_ops iwl5000_ops; @@ -79,9 +81,37 @@ extern void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info, __le32 *tx_flags); extern int iwl5000_calc_rssi(struct iwl_priv *priv, struct iwl_rx_phy_res *rx_resp); +extern int iwl5000_apm_init(struct iwl_priv *priv); +extern void iwl5000_apm_stop(struct iwl_priv *priv); +extern int iwl5000_apm_reset(struct iwl_priv *priv); +extern void iwl5000_nic_config(struct iwl_priv *priv); +extern u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv); +extern const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, + size_t offset); +extern void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, + struct iwl_tx_queue *txq, + u16 byte_cnt); +extern void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, + struct iwl_tx_queue *txq); +extern int iwl5000_load_ucode(struct iwl_priv *priv); +extern void iwl5000_init_alive_start(struct iwl_priv *priv); +extern int iwl5000_alive_notify(struct iwl_priv *priv); +extern int iwl5000_hw_set_hw_params(struct iwl_priv *priv); +extern int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, + int tx_fifo, int sta_id, int tid, u16 ssn_idx); +extern int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, + u16 ssn_idx, u8 tx_fifo); +extern void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask); +extern void iwl5000_setup_deferred_work(struct iwl_priv *priv); +extern void iwl5000_rx_handler_setup(struct iwl_priv *priv); +extern int iwl5000_hw_valid_rtc_data_addr(u32 addr); +extern int iwl5000_send_tx_power(struct iwl_priv *priv); +extern void iwl5000_temperature(struct iwl_priv *priv); /* CT-KILL constants */ -#define CT_KILL_THRESHOLD 110 /* in Celsius */ +#define CT_KILL_THRESHOLD_LEGACY 110 /* in Celsius */ +#define CT_KILL_THRESHOLD 114 /* in Celsius */ +#define CT_KILL_EXIT_THRESHOLD 95 /* in Celsius */ /* Default noise level to report when noise measurement is not available. * This may be because we're: @@ -630,6 +660,8 @@ struct iwl_hw_params { u32 max_data_size; u32 max_bsm_size; u32 ct_kill_threshold; /* value in hw-dependent units */ + u32 ct_kill_exit_threshold; /* value in hw-dependent units */ + /* for 1000, 6000 series and up */ u32 calib_init_cfg; const struct iwl_sensitivity_ranges *sens; }; -- cgit v1.2.3-18-g5258 From 39b73fb15e4704fd4d1e33688135810637f5f3fb Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 24 Jul 2009 11:13:02 -0700 Subject: iwlwifi: Thermal Throttling Management - Part 1 Part 1 of Thermal Throttling Management - Thermal Throttling feature is used to put NIC into low power state when driver detect the Radio temperature reach pre-defined threshold Two Thermal Throttling Management Methods; this patch introduce the Legacy Thermal Management: IWL_TI_0: normal temperature, system power state IWL_TI_1: high temperature detect, low power state IWL_TI_2: higher temperature detected, lower power state IWL_TI_CT_KILL: critical temperature detected, lowest power state Once get into CT_KILL state, uCode go into sleep, driver will stop all the active queues, then move to IWL_TI_CT_KILL state; also set up 5 seconds timer to toggle CSR flag, uCode wake up upon CSR flag change, then measure the temperature. If temperature is above CT_KILL exit threshold, uCode go backto sleep; if temperature is below CT_KILL exit threshold, uCode send Card State Notification response with appropriate CT_KILL status flag, and uCode remain awake, Driver receive Card State Notification Response and update the card temperature to the CT_KILL exit threshold. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 1 + drivers/net/wireless/iwlwifi/iwl-5000.c | 1 + drivers/net/wireless/iwlwifi/iwl-agn.c | 19 +-- drivers/net/wireless/iwlwifi/iwl-core.c | 1 + drivers/net/wireless/iwlwifi/iwl-power.c | 249 +++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-power.h | 42 ++++++ 6 files changed, 301 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 23925bd81c6..670214823cb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1797,6 +1797,7 @@ static void iwl4965_temperature_calib(struct iwl_priv *priv) } priv->temperature = temp; + iwl_tt_handler(priv); set_bit(STATUS_TEMPERATURE, &priv->status); if (!priv->disable_tx_power_cal && diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 076acb13ba6..ddd64fef303 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1405,6 +1405,7 @@ void iwl5000_temperature(struct iwl_priv *priv) { /* store temperature from statistics (in Celsius) */ priv->temperature = le32_to_cpu(priv->statistics.general.temperature); + iwl_tt_handler(priv); } static void iwl5150_temperature(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 44c7f236a7a..23ae9914c84 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -637,7 +637,6 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); unsigned long status = priv->status; - unsigned long reg_flags; IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n", (flags & HW_CARD_DISABLED) ? "Kill" : "On", @@ -657,19 +656,12 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); iwl_write_direct32(priv, HBUS_TARG_MBX_C, HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); - - } - - if (flags & RF_CARD_DISABLED) { - iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, - CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); - iwl_read32(priv, CSR_UCODE_DRV_GP1); - spin_lock_irqsave(&priv->reg_lock, reg_flags); - if (!iwl_grab_nic_access(priv)) - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } + if (flags & RF_CARD_DISABLED) + iwl_tt_enter_ct_kill(priv); } + if (!(flags & RF_CARD_DISABLED)) + iwl_tt_exit_ct_kill(priv); if (flags & HW_CARD_DISABLED) set_bit(STATUS_RF_KILL_HW, &priv->status); @@ -3015,6 +3007,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) test_bit(STATUS_RF_KILL_HW, &priv->status)); iwl_power_initialize(priv); + iwl_tt_initialize(priv); return 0; out_remove_sysfs: @@ -3067,6 +3060,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) iwl_down(priv); } + iwl_tt_exit(priv); + /* make sure we flush any pending irq or * tasklet for the driver */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 5ef3c37b581..d8aeb24db90 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2232,6 +2232,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); spin_unlock_irqrestore(&priv->lock, flags); + priv->power_data.ct_kill_toggle = false; switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_1000: diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index f2ea3f05f6e..d7fdb582545 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -36,6 +36,7 @@ #include "iwl-eeprom.h" #include "iwl-dev.h" #include "iwl-core.h" +#include "iwl-io.h" #include "iwl-commands.h" #include "iwl-debug.h" #include "iwl-power.h" @@ -211,6 +212,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) { struct iwl_power_mgr *setting = &(priv->power_data); int ret = 0; + struct iwl_tt_mgmt *tt = &priv->power_data.tt; u16 uninitialized_var(final_mode); bool update_chains; @@ -223,6 +225,10 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) if (setting->power_disabled) final_mode = IWL_POWER_MODE_CAM; + if (tt->state >= IWL_TI_1) { + /* TT power setting overwrite user & system power setting */ + final_mode = tt->tt_power_mode; + } if (iwl_is_ready_rf(priv) && ((setting->power_mode != final_mode) || force)) { struct iwl_powertable_cmd cmd; @@ -267,6 +273,249 @@ int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) } EXPORT_SYMBOL(iwl_power_set_user_mode); +#define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */ + +/* + * toggle the bit to wake up uCode and check the temperature + * if the temperature is below CT, uCode will stay awake and send card + * state notification with CT_KILL bit clear to inform Thermal Throttling + * Management to change state. Otherwise, uCode will go back to sleep + * without doing anything, driver should continue the 5 seconds timer + * to wake up uCode for temperature check until temperature drop below CT + */ +static void iwl_tt_check_exit_ct_kill(unsigned long data) +{ + struct iwl_priv *priv = (struct iwl_priv *)data; + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + unsigned long flags; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + if (tt->state == IWL_TI_CT_KILL) { + if (priv->power_data.ct_kill_toggle) { + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); + priv->power_data.ct_kill_toggle = false; + } else { + iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); + priv->power_data.ct_kill_toggle = true; + } + iwl_read32(priv, CSR_UCODE_DRV_GP1); + spin_lock_irqsave(&priv->reg_lock, flags); + if (!iwl_grab_nic_access(priv)) + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); + + /* Reschedule the ct_kill timer to occur in + * CT_KILL_EXIT_DURATION seconds to ensure we get a + * thermal update */ + mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies + + CT_KILL_EXIT_DURATION * HZ); + } +} + +static void iwl_perform_ct_kill_task(struct iwl_priv *priv, + bool stop) +{ + if (stop) { + IWL_DEBUG_POWER(priv, "Stop all queues\n"); + if (priv->mac80211_registered) + ieee80211_stop_queues(priv->hw); + IWL_DEBUG_POWER(priv, + "Schedule 5 seconds CT_KILL Timer\n"); + mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies + + CT_KILL_EXIT_DURATION * HZ); + } else { + IWL_DEBUG_POWER(priv, "Wake all queues\n"); + if (priv->mac80211_registered) + ieee80211_wake_queues(priv->hw); + } +} + +#define IWL_MINIMAL_POWER_THRESHOLD (CT_KILL_THRESHOLD_LEGACY) +#define IWL_REDUCED_PERFORMANCE_THRESHOLD_2 (100) +#define IWL_REDUCED_PERFORMANCE_THRESHOLD_1 (90) + +/* + * Legacy thermal throttling + * 1) Avoid NIC destruction due to high temperatures + * Chip will identify dangerously high temperatures that can + * harm the device and will power down + * 2) Avoid the NIC power down due to high temperature + * Throttle early enough to lower the power consumption before + * drastic steps are needed + */ +static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) +{ + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + enum iwl_tt_state new_state; + struct iwl_power_mgr *setting = &priv->power_data; + +#ifdef CONFIG_IWLWIFI_DEBUG + if ((tt->tt_previous_temp) && + (temp > tt->tt_previous_temp) && + ((temp - tt->tt_previous_temp) > + IWL_TT_INCREASE_MARGIN)) { + IWL_DEBUG_POWER(priv, + "Temperature increase %d degree Celsius\n", + (temp - tt->tt_previous_temp)); + } +#endif + /* in Celsius */ + if (temp >= IWL_MINIMAL_POWER_THRESHOLD) + new_state = IWL_TI_CT_KILL; + else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2) + new_state = IWL_TI_2; + else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1) + new_state = IWL_TI_1; + else + new_state = IWL_TI_0; + +#ifdef CONFIG_IWLWIFI_DEBUG + tt->tt_previous_temp = temp; +#endif + if (tt->state != new_state) { + if (tt->state == IWL_TI_0) { + tt->sys_power_mode = setting->power_mode; + IWL_DEBUG_POWER(priv, "current power mode: %u\n", + setting->power_mode); + } + switch (new_state) { + case IWL_TI_0: + /* when system ready to go back to IWL_TI_0 state + * using system power mode instead of TT power mode + * revert back to the orginal power mode which was saved + * before enter Thermal Throttling state + * update priv->power_data.user_power_setting to the + * required power mode to make sure + * iwl_power_update_mode() will update power correctly. + */ + priv->power_data.user_power_setting = + tt->sys_power_mode; + tt->tt_power_mode = tt->sys_power_mode; + break; + case IWL_TI_1: + tt->tt_power_mode = IWL_POWER_INDEX_3; + break; + case IWL_TI_2: + tt->tt_power_mode = IWL_POWER_INDEX_4; + break; + default: + tt->tt_power_mode = IWL_POWER_INDEX_5; + break; + } + if (iwl_power_update_mode(priv, true)) { + /* TT state not updated + * try again during next temperature read + */ + IWL_ERR(priv, "Cannot update power mode, " + "TT state not updated\n"); + } else { + if (new_state == IWL_TI_CT_KILL) + iwl_perform_ct_kill_task(priv, true); + else if (tt->state == IWL_TI_CT_KILL && + new_state != IWL_TI_CT_KILL) + iwl_perform_ct_kill_task(priv, false); + tt->state = new_state; + IWL_DEBUG_POWER(priv, "Temperature state changed %u\n", + tt->state); + IWL_DEBUG_POWER(priv, "Power Index change to %u\n", + tt->tt_power_mode); + } + } +} + +/* Card State Notification indicated reach critical temperature + * if PSP not enable, no Thermal Throttling function will be performed + * just set the GP1 bit to acknowledge the event + * otherwise, go into IWL_TI_CT_KILL state + * since Card State Notification will not provide any temperature reading + * so just pass the CT_KILL temperature to iwl_legacy_tt_handler() + */ +void iwl_tt_enter_ct_kill(struct iwl_priv *priv) +{ + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + if (tt->state != IWL_TI_CT_KILL) { + IWL_ERR(priv, "Device reached critical temperature " + "- ucode going to sleep!\n"); + iwl_legacy_tt_handler(priv, IWL_MINIMAL_POWER_THRESHOLD); + } +} +EXPORT_SYMBOL(iwl_tt_enter_ct_kill); + +/* Card State Notification indicated out of critical temperature + * since Card State Notification will not provide any temperature reading + * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature + * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state + */ +void iwl_tt_exit_ct_kill(struct iwl_priv *priv) +{ + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + /* stop ct_kill_exit_tm timer */ + del_timer_sync(&priv->power_data.ct_kill_exit_tm); + + if (tt->state == IWL_TI_CT_KILL) { + IWL_ERR(priv, + "Device temperature below critical" + "- ucode awake!\n"); + iwl_legacy_tt_handler(priv, + IWL_REDUCED_PERFORMANCE_THRESHOLD_2); + } +} +EXPORT_SYMBOL(iwl_tt_exit_ct_kill); + +void iwl_tt_handler(struct iwl_priv *priv) +{ + s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */ + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) + temp = KELVIN_TO_CELSIUS(priv->temperature); + + iwl_legacy_tt_handler(priv, temp); +} +EXPORT_SYMBOL(iwl_tt_handler); + +/* Thermal throttling initialization + */ +void iwl_tt_initialize(struct iwl_priv *priv) +{ + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_power_mgr *setting = &priv->power_data; + + IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling \n"); + + memset(tt, 0, sizeof(struct iwl_tt_mgmt)); + + tt->state = IWL_TI_0; + tt->sys_power_mode = setting->power_mode; + tt->tt_power_mode = tt->sys_power_mode; + init_timer(&priv->power_data.ct_kill_exit_tm); + priv->power_data.ct_kill_exit_tm.data = (unsigned long)priv; + priv->power_data.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; +} +EXPORT_SYMBOL(iwl_tt_initialize); + +/* cleanup thermal throttling management related memory and timer */ +void iwl_tt_exit(struct iwl_priv *priv) +{ + /* stop ct_kill_exit_tm timer if activated */ + del_timer_sync(&priv->power_data.ct_kill_exit_tm); +} +EXPORT_SYMBOL(iwl_tt_exit); + /* initialize to default */ void iwl_power_initialize(struct iwl_priv *priv) { diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 37ba3bb7a25..7bb10d41ae5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -33,6 +33,38 @@ struct iwl_priv; +#define IWL_TT_INCREASE_MARGIN 5 + +/* Thermal Throttling State Machine states */ +enum iwl_tt_state { + IWL_TI_0, /* normal temperature, system power state */ + IWL_TI_1, /* high temperature detect, low power state */ + IWL_TI_2, /* higher temperature detected, lower power state */ + IWL_TI_CT_KILL, /* critical temperature detected, lowest power state */ + IWL_TI_STATE_MAX +}; + +/** + * struct iwl_tt_mgnt - Thermal Throttling Management structure + * @state: current Thermal Throttling state + * @tt_power_mode: Thermal Throttling power mode index + * being used to set power level when + * when thermal throttling state != IWL_TI_0 + * the tt_power_mode should set to different + * power mode based on the current tt state + * @sys_power_mode: previous system power mode + * before transition into TT state + * @tt_previous_temperature: last measured temperature + */ +struct iwl_tt_mgmt { + enum iwl_tt_state state; + u8 tt_power_mode; + u8 sys_power_mode; +#ifdef CONFIG_IWLWIFI_DEBUG + s32 tt_previous_temp; +#endif +}; + enum { IWL_POWER_MODE_CAM, /* Continuously Aware Mode, always on */ IWL_POWER_INDEX_1, @@ -59,10 +91,20 @@ struct iwl_power_mgr { u8 power_mode; u8 user_power_setting; /* set by user through sysfs */ u8 power_disabled; /* set by mac80211's CONF_PS */ + struct iwl_tt_mgmt tt; /* Thermal Throttling Management */ + bool ct_kill_toggle; /* use to toggle the CSR bit when + * checking uCode temperature + */ + struct timer_list ct_kill_exit_tm; }; int iwl_power_update_mode(struct iwl_priv *priv, bool force); int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); +void iwl_tt_enter_ct_kill(struct iwl_priv *priv); +void iwl_tt_exit_ct_kill(struct iwl_priv *priv); +void iwl_tt_handler(struct iwl_priv *priv); +void iwl_tt_initialize(struct iwl_priv *priv); +void iwl_tt_exit(struct iwl_priv *priv); void iwl_power_initialize(struct iwl_priv *priv); #endif /* __iwl_power_setting_h__ */ -- cgit v1.2.3-18-g5258 From 46f9381aa3fb62f6a141bfd41dcbeda1ec5fa26e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 24 Jul 2009 11:13:03 -0700 Subject: iwlwifi: Thermal Throttling Management - part 2 Part 2 of Thermal Throttling Management - Thermal Throttling feature is used to put NIC into low power state when driver detect the Radio temperature reach pre-defined threshold Two Thermal Throttling Management Methods; this patch introduce the Advance Thermal Throttling: TI-0: system power index, no tx/rx restriction, HT enabled TI-1: power index 5, 1 spatial stream Tx, multiple spatial stream Rx, HT enabled TI-2: power index 5: 1 spatial stream Tx, 1 spatial stream Rx, HT disabled TI-CT-KILL: power index 5, no Tx, no Rx, HT disabled For advance Thermal Throttling, CT_KILL_ENTER threshold and CT_KILL_EXIT threshold are different; uCode will not stay awake until reach CT_KILL_EXIT threshold. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 48 ++++- drivers/net/wireless/iwlwifi/iwl-power.c | 285 +++++++++++++++++++++++++++++- drivers/net/wireless/iwlwifi/iwl-power.h | 51 ++++++ 3 files changed, 371 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 40207dac6db..52a4810274e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -177,7 +177,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, struct sk_buff *skb, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta); -static void rs_fill_link_cmd(const struct iwl_priv *priv, +static void rs_fill_link_cmd(struct iwl_priv *priv, struct iwl_lq_sta *lq_sta, u32 rate_n_flags); @@ -1398,6 +1398,12 @@ static int rs_move_legacy_other(struct iwl_priv *priv, int ret = 0; u8 update_search_tbl_counter = 0; + if (!iwl_ht_enabled(priv)) + /* stay in Legacy */ + tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; + else if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE && + tbl->action > IWL_LEGACY_SWITCH_SISO) + tbl->action = IWL_LEGACY_SWITCH_SISO; for (; ;) { lq_sta->action_counter++; switch (tbl->action) { @@ -1529,6 +1535,11 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, u8 update_search_tbl_counter = 0; int ret; + if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE && + tbl->action > IWL_SISO_SWITCH_ANTENNA2) { + /* stay in SISO */ + tbl->action = IWL_SISO_SWITCH_ANTENNA1; + } for (;;) { lq_sta->action_counter++; switch (tbl->action) { @@ -1663,6 +1674,12 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, u8 update_search_tbl_counter = 0; int ret; + if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) && + (tbl->action < IWL_MIMO2_SWITCH_SISO_A || + tbl->action > IWL_MIMO2_SWITCH_SISO_C)) { + /* switch in SISO */ + tbl->action = IWL_MIMO2_SWITCH_SISO_A; + } for (;;) { lq_sta->action_counter++; switch (tbl->action) { @@ -1799,6 +1816,12 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, int ret; u8 update_search_tbl_counter = 0; + if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) && + (tbl->action < IWL_MIMO3_SWITCH_SISO_A || + tbl->action > IWL_MIMO3_SWITCH_SISO_C)) { + /* switch in SISO */ + tbl->action = IWL_MIMO3_SWITCH_SISO_A; + } for (;;) { lq_sta->action_counter++; switch (tbl->action) { @@ -2178,8 +2201,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, tbl->expected_tpt[index] + 64) / 128)); /* If we are searching for better modulation mode, check success. */ - if (lq_sta->search_better_tbl) { - + if (lq_sta->search_better_tbl && + (iwl_tx_ant_restriction(priv) == IWL_TX_MULTI)) { /* If good success, continue using the "search" mode; * no need to send new link quality command, since we're * continuing to use the setup that we've been trying. */ @@ -2307,7 +2330,11 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, ((sr > IWL_RATE_HIGH_TH) || (current_tpt > (100 * tbl->expected_tpt[low])))) scale_action = 0; - + if (!iwl_ht_enabled(priv) && !is_legacy(tbl->lq_type)) + scale_action = -1; + if (iwl_tx_ant_restriction(priv) != IWL_TX_MULTI && + (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) + scale_action = -1; switch (scale_action) { case -1: /* Decrease starting rate, update uCode's rate table */ @@ -2341,9 +2368,11 @@ lq_update: rate = rs_update_rate_tbl(priv, lq_sta, tbl, index, is_green); - /* Should we stay with this modulation mode, or search for a new one? */ - rs_stay_in_table(lq_sta); - + if (iwl_tx_ant_restriction(priv) == IWL_TX_MULTI) { + /* Should we stay with this modulation mode, + * or search for a new one? */ + rs_stay_in_table(lq_sta); + } /* * Search for new modulation mode if we're: * 1) Not changing rates right now @@ -2400,7 +2429,8 @@ lq_update: * have been tried and compared, stay in this best modulation * mode for a while before next round of mode comparisons. */ if (lq_sta->enable_counter && - (lq_sta->action_counter >= tbl1->max_search)) { + (lq_sta->action_counter >= tbl1->max_search) && + iwl_ht_enabled(priv)) { if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) && (lq_sta->tx_agg_tid_en & (1 << tid)) && (tid != MAX_TID_COUNT)) { @@ -2686,7 +2716,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, rs_initialize_lq(priv, conf, sta, lq_sta); } -static void rs_fill_link_cmd(const struct iwl_priv *priv, +static void rs_fill_link_cmd(struct iwl_priv *priv, struct iwl_lq_sta *lq_sta, u32 new_rate) { struct iwl_scale_tbl_info tbl_type; diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index d7fdb582545..00937b3ee8e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -98,6 +98,45 @@ static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} }; +/* default Thermal Throttling transaction table + * Current state | Throttling Down | Throttling Up + *============================================================================= + * Condition Nxt State Condition Nxt State Condition Nxt State + *----------------------------------------------------------------------------- + * IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A + * IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0 + * IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1 + * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0 + *============================================================================= + */ +static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = { + {IWL_TI_0, IWL_ABSOLUTE_ZERO, 104}, + {IWL_TI_1, 105, CT_KILL_THRESHOLD}, + {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} +}; +static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = { + {IWL_TI_0, IWL_ABSOLUTE_ZERO, 95}, + {IWL_TI_2, 110, CT_KILL_THRESHOLD}, + {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} +}; +static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = { + {IWL_TI_1, IWL_ABSOLUTE_ZERO, 100}, + {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}, + {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} +}; +static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = { + {IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD}, + {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}, + {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX} +}; + +/* Advance Thermal Throttling default restriction table */ +static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = { + {IWL_TX_MULTI, true, IWL_RX_MULTI}, + {IWL_TX_SINGLE, true, IWL_RX_MULTI}, + {IWL_TX_SINGLE, false, IWL_RX_SINGLE}, + {IWL_TX_NONE, false, IWL_RX_NONE} +}; /* set card power command */ static int iwl_set_power(struct iwl_priv *priv, void *cmd) @@ -273,6 +312,42 @@ int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) } EXPORT_SYMBOL(iwl_power_set_user_mode); +bool iwl_ht_enabled(struct iwl_priv *priv) +{ + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_restriction *restriction; + + if (!priv->power_data.adv_tt) + return true; + restriction = tt->restriction + tt->state; + return restriction->is_ht; +} +EXPORT_SYMBOL(iwl_ht_enabled); + +u8 iwl_tx_ant_restriction(struct iwl_priv *priv) +{ + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_restriction *restriction; + + if (!priv->power_data.adv_tt) + return IWL_TX_MULTI; + restriction = tt->restriction + tt->state; + return restriction->tx_stream; +} +EXPORT_SYMBOL(iwl_tx_ant_restriction); + +u8 iwl_rx_ant_restriction(struct iwl_priv *priv) +{ + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_restriction *restriction; + + if (!priv->power_data.adv_tt) + return IWL_RX_MULTI; + restriction = tt->restriction + tt->state; + return restriction->rx_stream; +} +EXPORT_SYMBOL(iwl_rx_ant_restriction); + #define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */ /* @@ -427,12 +502,147 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) } } +/* + * Advance thermal throttling + * 1) Avoid NIC destruction due to high temperatures + * Chip will identify dangerously high temperatures that can + * harm the device and will power down + * 2) Avoid the NIC power down due to high temperature + * Throttle early enough to lower the power consumption before + * drastic steps are needed + * Actions include relaxing the power down sleep thresholds and + * decreasing the number of TX streams + * 3) Avoid throughput performance impact as much as possible + * + *============================================================================= + * Condition Nxt State Condition Nxt State Condition Nxt State + *----------------------------------------------------------------------------- + * IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A + * IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0 + * IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1 + * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0 + *============================================================================= + */ +static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) +{ + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + int i; + bool changed = false; + enum iwl_tt_state old_state; + struct iwl_tt_trans *transaction; + + old_state = tt->state; + for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) { + /* based on the current TT state, + * find the curresponding transaction table + * each table has (IWL_TI_STATE_MAX - 1) entries + * tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1)) + * will advance to the correct table. + * then based on the current temperature + * find the next state need to transaction to + * go through all the possible (IWL_TI_STATE_MAX - 1) entries + * in the current table to see if transaction is needed + */ + transaction = tt->transaction + + ((old_state * (IWL_TI_STATE_MAX - 1)) + i); + if (temp >= transaction->tt_low && + temp <= transaction->tt_high) { +#ifdef CONFIG_IWLWIFI_DEBUG + if ((tt->tt_previous_temp) && + (temp > tt->tt_previous_temp) && + ((temp - tt->tt_previous_temp) > + IWL_TT_INCREASE_MARGIN)) { + IWL_DEBUG_POWER(priv, + "Temperature increase %d " + "degree Celsius\n", + (temp - tt->tt_previous_temp)); + } + tt->tt_previous_temp = temp; +#endif + if (old_state != + transaction->next_state) { + changed = true; + tt->state = + transaction->next_state; + } + break; + } + } + if (changed) { + struct iwl_rxon_cmd *rxon = &priv->staging_rxon; + struct iwl_power_mgr *setting = &priv->power_data; + + if (tt->state >= IWL_TI_1) { + /* if switching from IWL_TI_0 to other TT state + * save previous power setting in tt->sys_power_mode */ + if (old_state == IWL_TI_0) + tt->sys_power_mode = setting->power_mode; + /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */ + tt->tt_power_mode = IWL_POWER_INDEX_5; + if (!iwl_ht_enabled(priv)) + /* disable HT */ + rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | + RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | + RXON_FLG_FAT_PROT_MSK | + RXON_FLG_HT_PROT_MSK); + else { + /* check HT capability and set + * according to the system HT capability + * in case get disabled before */ + iwl_set_rxon_ht(priv, &priv->current_ht_config); + } + + } else { + /* restore system power setting */ + /* the previous power mode was saved in + * tt->sys_power_mode when system move into + * Thermal Throttling state + * set power_data.user_power_setting to the previous + * system power mode to make sure power will get + * updated correctly + */ + priv->power_data.user_power_setting = + tt->sys_power_mode; + tt->tt_power_mode = tt->sys_power_mode; + /* check HT capability and set + * according to the system HT capability + * in case get disabled before */ + iwl_set_rxon_ht(priv, &priv->current_ht_config); + } + if (iwl_power_update_mode(priv, true)) { + /* TT state not updated + * try again during next temperature read + */ + IWL_ERR(priv, "Cannot update power mode, " + "TT state not updated\n"); + tt->state = old_state; + } else { + IWL_DEBUG_POWER(priv, + "Thermal Throttling to new state: %u\n", + tt->state); + if (old_state != IWL_TI_CT_KILL && + tt->state == IWL_TI_CT_KILL) { + IWL_DEBUG_POWER(priv, "Enter IWL_TI_CT_KILL\n"); + iwl_perform_ct_kill_task(priv, true); + + } else if (old_state == IWL_TI_CT_KILL && + tt->state != IWL_TI_CT_KILL) { + IWL_DEBUG_POWER(priv, "Exit IWL_TI_CT_KILL\n"); + iwl_perform_ct_kill_task(priv, false); + } + } + } +} + /* Card State Notification indicated reach critical temperature * if PSP not enable, no Thermal Throttling function will be performed * just set the GP1 bit to acknowledge the event * otherwise, go into IWL_TI_CT_KILL state * since Card State Notification will not provide any temperature reading + * for Legacy mode * so just pass the CT_KILL temperature to iwl_legacy_tt_handler() + * for advance mode + * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state */ void iwl_tt_enter_ct_kill(struct iwl_priv *priv) { @@ -444,7 +654,12 @@ void iwl_tt_enter_ct_kill(struct iwl_priv *priv) if (tt->state != IWL_TI_CT_KILL) { IWL_ERR(priv, "Device reached critical temperature " "- ucode going to sleep!\n"); - iwl_legacy_tt_handler(priv, IWL_MINIMAL_POWER_THRESHOLD); + if (!priv->power_data.adv_tt) + iwl_legacy_tt_handler(priv, + IWL_MINIMAL_POWER_THRESHOLD); + else + iwl_advance_tt_handler(priv, + CT_KILL_THRESHOLD + 1); } } EXPORT_SYMBOL(iwl_tt_enter_ct_kill); @@ -468,8 +683,11 @@ void iwl_tt_exit_ct_kill(struct iwl_priv *priv) IWL_ERR(priv, "Device temperature below critical" "- ucode awake!\n"); - iwl_legacy_tt_handler(priv, - IWL_REDUCED_PERFORMANCE_THRESHOLD_2); + if (!priv->power_data.adv_tt) + iwl_legacy_tt_handler(priv, + IWL_REDUCED_PERFORMANCE_THRESHOLD_2); + else + iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD); } } EXPORT_SYMBOL(iwl_tt_exit_ct_kill); @@ -484,16 +702,24 @@ void iwl_tt_handler(struct iwl_priv *priv) if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) temp = KELVIN_TO_CELSIUS(priv->temperature); - iwl_legacy_tt_handler(priv, temp); + if (!priv->power_data.adv_tt) + iwl_legacy_tt_handler(priv, temp); + else + iwl_advance_tt_handler(priv, temp); } EXPORT_SYMBOL(iwl_tt_handler); /* Thermal throttling initialization + * For advance thermal throttling: + * Initialize Thermal Index and temperature threshold table + * Initialize thermal throttling restriction table */ void iwl_tt_initialize(struct iwl_priv *priv) { struct iwl_tt_mgmt *tt = &priv->power_data.tt; struct iwl_power_mgr *setting = &priv->power_data; + int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1); + struct iwl_tt_trans *transaction; IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling \n"); @@ -505,14 +731,65 @@ void iwl_tt_initialize(struct iwl_priv *priv) init_timer(&priv->power_data.ct_kill_exit_tm); priv->power_data.ct_kill_exit_tm.data = (unsigned long)priv; priv->power_data.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; + switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { + case CSR_HW_REV_TYPE_6x00: + case CSR_HW_REV_TYPE_6x50: + IWL_DEBUG_POWER(priv, "Advanced Thermal Throttling\n"); + tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) * + IWL_TI_STATE_MAX, GFP_KERNEL); + tt->transaction = kzalloc(sizeof(struct iwl_tt_trans) * + IWL_TI_STATE_MAX * (IWL_TI_STATE_MAX - 1), + GFP_KERNEL); + if (!tt->restriction || !tt->transaction) { + IWL_ERR(priv, "Fallback to Legacy Throttling\n"); + priv->power_data.adv_tt = false; + kfree(tt->restriction); + tt->restriction = NULL; + kfree(tt->transaction); + tt->transaction = NULL; + } else { + transaction = tt->transaction + + (IWL_TI_0 * (IWL_TI_STATE_MAX - 1)); + memcpy(transaction, &tt_range_0[0], size); + transaction = tt->transaction + + (IWL_TI_1 * (IWL_TI_STATE_MAX - 1)); + memcpy(transaction, &tt_range_1[0], size); + transaction = tt->transaction + + (IWL_TI_2 * (IWL_TI_STATE_MAX - 1)); + memcpy(transaction, &tt_range_2[0], size); + transaction = tt->transaction + + (IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1)); + memcpy(transaction, &tt_range_3[0], size); + size = sizeof(struct iwl_tt_restriction) * + IWL_TI_STATE_MAX; + memcpy(tt->restriction, + &restriction_range[0], size); + priv->power_data.adv_tt = true; + } + break; + default: + IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n"); + priv->power_data.adv_tt = false; + break; + } } EXPORT_SYMBOL(iwl_tt_initialize); /* cleanup thermal throttling management related memory and timer */ void iwl_tt_exit(struct iwl_priv *priv) { + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + /* stop ct_kill_exit_tm timer if activated */ del_timer_sync(&priv->power_data.ct_kill_exit_tm); + + if (priv->power_data.adv_tt) { + /* free advance thermal throttling memory */ + kfree(tt->restriction); + tt->restriction = NULL; + kfree(tt->transaction); + tt->transaction = NULL; + } } EXPORT_SYMBOL(iwl_tt_exit); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 7bb10d41ae5..3d49b7a45b7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -33,8 +33,18 @@ struct iwl_priv; +#define IWL_ABSOLUTE_ZERO 0 +#define IWL_ABSOLUTE_MAX 0xFFFFFFFF #define IWL_TT_INCREASE_MARGIN 5 +/* Tx/Rx restrictions */ +#define IWL_TX_MULTI 0x02 +#define IWL_TX_SINGLE 0x01 +#define IWL_TX_NONE 0x00 +#define IWL_RX_MULTI 0x02 +#define IWL_RX_SINGLE 0x01 +#define IWL_RX_NONE 0x00 + /* Thermal Throttling State Machine states */ enum iwl_tt_state { IWL_TI_0, /* normal temperature, system power state */ @@ -44,6 +54,35 @@ enum iwl_tt_state { IWL_TI_STATE_MAX }; +/** + * struct iwl_tt_restriction - Thermal Throttling restriction table used + * by advance thermal throttling management + * based on the current thermal throttling state, determine + * number of tx/rx streams; and the status of HT operation + * @tx_stream: number of tx stream allowed + * @is_ht: ht enable/disable + * @rx_stream: number of rx stream allowed + */ +struct iwl_tt_restriction { + u8 tx_stream; + bool is_ht; + u8 rx_stream; +}; + +/** + * struct iwl_tt_trans - Thermal Throttling transaction table; used by + * advance thermal throttling algorithm to determine next + * thermal state to go based on the current temperature + * @next_state: next thermal throttling mode + * @tt_low: low temperature threshold to change state + * @tt_high: high temperature threshold to change state + */ +struct iwl_tt_trans { + enum iwl_tt_state next_state; + u32 tt_low; + u32 tt_high; +}; + /** * struct iwl_tt_mgnt - Thermal Throttling Management structure * @state: current Thermal Throttling state @@ -55,6 +94,11 @@ enum iwl_tt_state { * @sys_power_mode: previous system power mode * before transition into TT state * @tt_previous_temperature: last measured temperature + * @iwl_tt_restriction: ptr to restriction tbl, used by advance + * thermal throttling to determine how many tx/rx streams + * should be used in tt state; and can HT be enabled or not + * @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling + * state transaction */ struct iwl_tt_mgmt { enum iwl_tt_state state; @@ -63,6 +107,8 @@ struct iwl_tt_mgmt { #ifdef CONFIG_IWLWIFI_DEBUG s32 tt_previous_temp; #endif + struct iwl_tt_restriction *restriction; + struct iwl_tt_trans *transaction; }; enum { @@ -92,6 +138,8 @@ struct iwl_power_mgr { u8 user_power_setting; /* set by user through sysfs */ u8 power_disabled; /* set by mac80211's CONF_PS */ struct iwl_tt_mgmt tt; /* Thermal Throttling Management */ + bool adv_tt; /* false: legacy mode */ + /* true: advance mode */ bool ct_kill_toggle; /* use to toggle the CSR bit when * checking uCode temperature */ @@ -100,6 +148,9 @@ struct iwl_power_mgr { int iwl_power_update_mode(struct iwl_priv *priv, bool force); int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); +bool iwl_ht_enabled(struct iwl_priv *priv); +u8 iwl_tx_ant_restriction(struct iwl_priv *priv); +u8 iwl_rx_ant_restriction(struct iwl_priv *priv); void iwl_tt_enter_ct_kill(struct iwl_priv *priv); void iwl_tt_exit_ct_kill(struct iwl_priv *priv); void iwl_tt_handler(struct iwl_priv *priv); -- cgit v1.2.3-18-g5258 From fbf3a2af3834e8e93e9c2876de62c5b49988e352 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 24 Jul 2009 11:13:04 -0700 Subject: iwlwifi: Thermal Throttling debugfs function Add debugfs function to display current thermal throttling status for both Legacy and Advance Thermal Throttling Management Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debug.h | 1 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 38 ++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 9faf0c2ff60..609a68184db 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -84,6 +84,7 @@ struct iwl_debugfs { struct dentry *file_status; struct dentry *file_interrupt; struct dentry *file_qos; + struct dentry *file_thermal_throttling; #ifdef CONFIG_IWLWIFI_LEDS struct dentry *file_led; #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 0ab3463aa07..748dc31877b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -618,6 +618,41 @@ static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf, } #endif +static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_restriction *restriction; + char buf[100]; + int pos = 0; + const size_t bufsz = sizeof(buf); + ssize_t ret; + + pos += scnprintf(buf + pos, bufsz - pos, + "Thermal Throttling Mode: %s\n", + (priv->power_data.adv_tt) + ? "Advance" : "Legacy"); + pos += scnprintf(buf + pos, bufsz - pos, + "Thermal Throttling State: %d\n", + tt->state); + if (priv->power_data.adv_tt) { + restriction = tt->restriction + tt->state; + pos += scnprintf(buf + pos, bufsz - pos, + "Tx mode: %d\n", + restriction->tx_stream); + pos += scnprintf(buf + pos, bufsz - pos, + "Rx mode: %d\n", + restriction->rx_stream); + pos += scnprintf(buf + pos, bufsz - pos, + "HT mode: %d\n", + restriction->is_ht); + } + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + return ret; +} + DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_WRITE_FILE_OPS(log_event); DEBUGFS_READ_FILE_OPS(nvm); @@ -631,6 +666,7 @@ DEBUGFS_READ_FILE_OPS(qos); #ifdef CONFIG_IWLWIFI_LEDS DEBUGFS_READ_FILE_OPS(led); #endif +DEBUGFS_READ_FILE_OPS(thermal_throttling); /* * Create the debugfs files and directories @@ -671,6 +707,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) #ifdef CONFIG_IWLWIFI_LEDS DEBUGFS_ADD_FILE(led, data); #endif + DEBUGFS_ADD_FILE(thermal_throttling, data); DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); @@ -709,6 +746,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) #ifdef CONFIG_IWLWIFI_LEDS DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led); #endif + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling); DEBUGFS_REMOVE(priv->dbgfs->dir_data); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); -- cgit v1.2.3-18-g5258 From c2acea8e9b86ba5a5469ff477445676a223af4e2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jul 2009 11:13:05 -0700 Subject: iwlwifi: fix up command sending The current command sending in iwlwifi is a bit of a mess: 1) there is a struct, iwl_cmd, that contains both driver and device data in a single packed structure -- this is very confusing 2) the on-stack data and the command metadata share a structure by embedding the latter in the former, which is also rather confusing because it leads to weird unions and similarly odd constructs 3) each txq always has enough space for 256 commands, even if only 32 end up being used This patch fixes these things: 1) rename iwl_cmd to iwl_device_cmd and keep track of command metadata and device command separately, in two arrays in each tx queue 2) remove the 'meta' member from iwl_host_cmd and only put in the required members 3) allocate the cmd/meta arrays separately instead of embedding them into the txq structure Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-led.c | 6 +- drivers/net/wireless/iwlwifi/iwl-3945.c | 18 +++--- drivers/net/wireless/iwlwifi/iwl-3945.h | 9 +-- drivers/net/wireless/iwlwifi/iwl-agn.c | 4 +- drivers/net/wireless/iwlwifi/iwl-calib.c | 4 +- drivers/net/wireless/iwlwifi/iwl-core.c | 4 +- drivers/net/wireless/iwlwifi/iwl-core.h | 2 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 69 ++++++++++++--------- drivers/net/wireless/iwlwifi/iwl-hcmd.c | 48 +++++++-------- drivers/net/wireless/iwlwifi/iwl-led.c | 4 +- drivers/net/wireless/iwlwifi/iwl-scan.c | 8 +-- drivers/net/wireless/iwlwifi/iwl-sta.c | 30 ++++----- drivers/net/wireless/iwlwifi/iwl-tx.c | 96 ++++++++++++++++++----------- drivers/net/wireless/iwlwifi/iwl3945-base.c | 20 +++--- 14 files changed, 180 insertions(+), 142 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index 225e5f88934..b37938217f5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -80,7 +80,7 @@ static const struct { #define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1) static int iwl3945_led_cmd_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, + struct iwl_device_cmd *cmd, struct sk_buff *skb) { return 1; @@ -99,8 +99,8 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, .id = REPLY_LEDS_CMD, .len = sizeof(struct iwl_led_cmd), .data = led_cmd, - .meta.flags = CMD_ASYNC, - .meta.u.callback = iwl3945_led_cmd_callback, + .flags = CMD_ASYNC, + .callback = iwl3945_led_cmd_callback, }; return iwl_send_cmd(priv, &cmd); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 8ee403cd9b9..e1b0ef3c56a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -749,8 +749,8 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) /* Unmap tx_cmd */ if (counter) pci_unmap_single(dev, - pci_unmap_addr(&txq->cmd[index]->meta, mapping), - pci_unmap_len(&txq->cmd[index]->meta, len), + pci_unmap_addr(&txq->meta[index], mapping), + pci_unmap_len(&txq->meta[index], len), PCI_DMA_TODEVICE); /* unmap chunks if any */ @@ -774,9 +774,11 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) * iwl3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD: * */ -void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd, - struct ieee80211_tx_info *info, - struct ieee80211_hdr *hdr, int sta_id, int tx_id) +void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct ieee80211_tx_info *info, + struct ieee80211_hdr *hdr, + int sta_id, int tx_id) { u16 hw_value = ieee80211_get_tx_rate(priv->hw, info)->hw_value; u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1); @@ -1858,7 +1860,7 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv) struct iwl_host_cmd cmd = { .id = REPLY_RXON_ASSOC, .len = sizeof(rxon_assoc), - .meta.flags = CMD_WANT_SKB, + .flags = CMD_WANT_SKB, .data = &rxon_assoc, }; const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon; @@ -1882,14 +1884,14 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv) if (rc) return rc; - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl_rx_packet *)cmd.reply_skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n"); rc = -EIO; } priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.meta.u.skb); + dev_kfree_skb_any(cmd.reply_skb); return rc; } diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index f2ffc48cbaf..f2403690991 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -254,10 +254,11 @@ extern int iwl3945_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq); extern unsigned int iwl3945_hw_get_beacon_cmd(struct iwl_priv *priv, struct iwl3945_frame *frame, u8 rate); -void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd, - struct ieee80211_tx_info *info, - struct ieee80211_hdr *hdr, - int sta_id, int tx_id); +void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct ieee80211_tx_info *info, + struct ieee80211_hdr *hdr, + int sta_id, int tx_id); extern int iwl3945_hw_reg_send_txpower(struct iwl_priv *priv); extern int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power); extern void iwl3945_hw_rx_statistics(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 23ae9914c84..4cb1a1b7348 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -442,8 +442,8 @@ void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) /* Unmap tx_cmd */ if (num_tbs) pci_unmap_single(dev, - pci_unmap_addr(&txq->cmd[index]->meta, mapping), - pci_unmap_len(&txq->cmd[index]->meta, len), + pci_unmap_addr(&txq->meta[index], mapping), + pci_unmap_len(&txq->meta[index], len), PCI_DMA_BIDIRECTIONAL); /* Unmap chunks, if any. */ diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index f8bf592e939..13180d6ee2f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -86,7 +86,7 @@ int iwl_send_calib_results(struct iwl_priv *priv) struct iwl_host_cmd hcmd = { .id = REPLY_PHY_CALIBRATION_CMD, - .meta.flags = CMD_SIZE_HUGE, + .flags = CMD_SIZE_HUGE, }; for (i = 0; i < IWL_CALIB_MAX; i++) { @@ -419,7 +419,7 @@ static int iwl_sensitivity_write(struct iwl_priv *priv) struct iwl_host_cmd cmd_out = { .id = SENSITIVITY_CMD, .len = sizeof(struct iwl_sensitivity_cmd), - .meta.flags = CMD_ASYNC, + .flags = CMD_ASYNC, .data = &cmd, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index d8aeb24db90..710dd41c341 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2089,7 +2089,7 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags) u32 stat_flags = 0; struct iwl_host_cmd cmd = { .id = REPLY_STATISTICS_CMD, - .meta.flags = flags, + .flags = flags, .len = sizeof(stat_flags), .data = (u8 *) &stat_flags, }; @@ -2282,7 +2282,7 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) .id = REPLY_CARD_STATE_CMD, .len = sizeof(u32), .data = &flags, - .meta.flags = meta_flag, + .flags = meta_flag, }; return iwl_send_cmd(priv, &cmd); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 614ec7cc5b3..4156debec39 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -447,7 +447,7 @@ int __must_check iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, const void *data, int (*callback)(struct iwl_priv *priv, - struct iwl_cmd *cmd, + struct iwl_device_cmd *cmd, struct sk_buff *skb)); int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index cddf17350c4..ce765f79275 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -150,6 +150,31 @@ struct iwl_rx_mem_buffer { struct list_head list; }; +/* defined below */ +struct iwl_device_cmd; + +struct iwl_cmd_meta { + /* only for SYNC commands, iff the reply skb is wanted */ + struct iwl_host_cmd *source; + /* + * only for ASYNC commands + * (which is somewhat stupid -- look at iwl-sta.c for instance + * which duplicates a bunch of code because the callback isn't + * invoked for SYNC commands, if it were and its result passed + * through it would be simpler...) + */ + int (*callback)(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct sk_buff *skb); + + /* The CMD_SIZE_HUGE flag bit indicates that the command + * structure is stored at the end of the shared queue memory. */ + u32 flags; + + DECLARE_PCI_UNMAP_ADDR(mapping) + DECLARE_PCI_UNMAP_LEN(len) +}; + /* * Generic queue structure * @@ -177,7 +202,8 @@ struct iwl_tx_info { * struct iwl_tx_queue - Tx Queue for DMA * @q: generic Rx/Tx queue descriptor * @bd: base of circular buffer of TFDs - * @cmd: array of command/Tx buffers + * @cmd: array of command/TX buffer pointers + * @meta: array of meta data for each command/tx buffer * @dma_addr_cmd: physical address of cmd/tx buffer array * @txb: array of per-TFD driver data * @need_update: indicates need to update read/write index @@ -192,7 +218,8 @@ struct iwl_tx_info { struct iwl_tx_queue { struct iwl_queue q; void *tfds; - struct iwl_cmd *cmd[TFD_TX_CMD_SLOTS]; + struct iwl_device_cmd **cmd; + struct iwl_cmd_meta *meta; struct iwl_tx_info *txb; u8 need_update; u8 sched_retry; @@ -329,35 +356,16 @@ enum { CMD_WANT_SKB = (1 << 2), }; -struct iwl_cmd; -struct iwl_priv; - -struct iwl_cmd_meta { - struct iwl_cmd_meta *source; - union { - struct sk_buff *skb; - int (*callback)(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb); - } __attribute__ ((packed)) u; - - /* The CMD_SIZE_HUGE flag bit indicates that the command - * structure is stored at the end of the shared queue memory. */ - u32 flags; - DECLARE_PCI_UNMAP_ADDR(mapping) - DECLARE_PCI_UNMAP_LEN(len) -} __attribute__ ((packed)); - #define IWL_CMD_MAX_PAYLOAD 320 /** - * struct iwl_cmd + * struct iwl_device_cmd * * For allocation of the command and tx queues, this establishes the overall * size of the largest command we send to uCode, except for a scan command * (which is relatively huge; space is allocated separately). */ -struct iwl_cmd { - struct iwl_cmd_meta meta; /* driver data */ +struct iwl_device_cmd { struct iwl_cmd_header hdr; /* uCode API */ union { u32 flags; @@ -369,17 +377,20 @@ struct iwl_cmd { } __attribute__ ((packed)) cmd; } __attribute__ ((packed)); +#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd)) + struct iwl_host_cmd { - u8 id; - u16 len; - struct iwl_cmd_meta meta; const void *data; + struct sk_buff *reply_skb; + int (*callback)(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct sk_buff *skb); + u32 flags; + u16 len; + u8 id; }; -#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \ - sizeof(struct iwl_cmd_meta)) - /* * RX related structures and functions */ diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 17d61ac8ed6..d8a3eac8ceb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -104,7 +104,8 @@ EXPORT_SYMBOL(get_cmd_string); #define HOST_COMPLETE_TIMEOUT (HZ / 2) static int iwl_generic_cmd_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb) + struct iwl_device_cmd *cmd, + struct sk_buff *skb) { struct iwl_rx_packet *pkt = NULL; @@ -142,14 +143,14 @@ static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { int ret; - BUG_ON(!(cmd->meta.flags & CMD_ASYNC)); + BUG_ON(!(cmd->flags & CMD_ASYNC)); /* An asynchronous command can not expect an SKB to be set. */ - BUG_ON(cmd->meta.flags & CMD_WANT_SKB); + BUG_ON(cmd->flags & CMD_WANT_SKB); /* Assign a generic callback if one is not provided */ - if (!cmd->meta.u.callback) - cmd->meta.u.callback = iwl_generic_cmd_callback; + if (!cmd->callback) + cmd->callback = iwl_generic_cmd_callback; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return -EBUSY; @@ -168,10 +169,10 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) int cmd_idx; int ret; - BUG_ON(cmd->meta.flags & CMD_ASYNC); + BUG_ON(cmd->flags & CMD_ASYNC); /* A synchronous command can not have a callback set. */ - BUG_ON(cmd->meta.u.callback != NULL); + BUG_ON(cmd->callback); if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) { IWL_ERR(priv, @@ -183,9 +184,6 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) set_bit(STATUS_HCMD_ACTIVE, &priv->status); - if (cmd->meta.flags & CMD_WANT_SKB) - cmd->meta.source = &cmd->meta; - cmd_idx = iwl_enqueue_hcmd(priv, cmd); if (cmd_idx < 0) { ret = cmd_idx; @@ -222,7 +220,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) ret = -EIO; goto fail; } - if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) { + if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_skb) { IWL_ERR(priv, "Error: Response NULL in '%s'\n", get_cmd_string(cmd->id)); ret = -EIO; @@ -233,20 +231,20 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) goto out; cancel: - if (cmd->meta.flags & CMD_WANT_SKB) { - struct iwl_cmd *qcmd; - - /* Cancel the CMD_WANT_SKB flag for the cmd in the + if (cmd->flags & CMD_WANT_SKB) { + /* + * Cancel the CMD_WANT_SKB flag for the cmd in the * TX cmd queue. Otherwise in case the cmd comes * in later, it will possibly set an invalid - * address (cmd->meta.source). */ - qcmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx]; - qcmd->meta.flags &= ~CMD_WANT_SKB; + * address (cmd->meta.source). + */ + priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_idx].flags &= + ~CMD_WANT_SKB; } fail: - if (cmd->meta.u.skb) { - dev_kfree_skb_any(cmd->meta.u.skb); - cmd->meta.u.skb = NULL; + if (cmd->reply_skb) { + dev_kfree_skb_any(cmd->reply_skb); + cmd->reply_skb = NULL; } out: clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status); @@ -256,7 +254,7 @@ EXPORT_SYMBOL(iwl_send_cmd_sync); int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { - if (cmd->meta.flags & CMD_ASYNC) + if (cmd->flags & CMD_ASYNC) return iwl_send_cmd_async(priv, cmd); return iwl_send_cmd_sync(priv, cmd); @@ -278,7 +276,7 @@ EXPORT_SYMBOL(iwl_send_cmd_pdu); int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, const void *data, int (*callback)(struct iwl_priv *priv, - struct iwl_cmd *cmd, + struct iwl_device_cmd *cmd, struct sk_buff *skb)) { struct iwl_host_cmd cmd = { @@ -287,8 +285,8 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, .data = data, }; - cmd.meta.flags |= CMD_ASYNC; - cmd.meta.u.callback = callback; + cmd.flags |= CMD_ASYNC; + cmd.callback = callback; return iwl_send_cmd_async(priv, &cmd); } diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 8c8115293b3..7cce8f85bcc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -91,8 +91,8 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) .id = REPLY_LEDS_CMD, .len = sizeof(struct iwl_led_cmd), .data = led_cmd, - .meta.flags = CMD_ASYNC, - .meta.u.callback = NULL, + .flags = CMD_ASYNC, + .callback = NULL, }; u32 reg; diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 00398d973a0..c4c916df4a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -115,7 +115,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) struct iwl_rx_packet *res; struct iwl_host_cmd cmd = { .id = REPLY_SCAN_ABORT_CMD, - .meta.flags = CMD_WANT_SKB, + .flags = CMD_WANT_SKB, }; /* If there isn't a scan actively going on in the hardware @@ -132,7 +132,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) return ret; } - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl_rx_packet *)cmd.reply_skb->data; if (res->u.status != CAN_ABORT_STATUS) { /* The scan abort will return 1 for success or * 2 for "failure". A failure condition can be @@ -146,7 +146,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) } priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.meta.u.skb); + dev_kfree_skb_any(cmd.reply_skb); return ret; } @@ -567,7 +567,7 @@ static void iwl_bg_request_scan(struct work_struct *data) struct iwl_host_cmd cmd = { .id = REPLY_SCAN_CMD, .len = sizeof(struct iwl_scan_cmd), - .meta.flags = CMD_SIZE_HUGE, + .flags = CMD_SIZE_HUGE, }; struct iwl_scan_cmd *scan; struct ieee80211_conf *conf = NULL; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index cbe4e26d053..1571ace05dd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -98,7 +98,8 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) } static int iwl_add_sta_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb) + struct iwl_device_cmd *cmd, + struct sk_buff *skb) { struct iwl_rx_packet *res = NULL; struct iwl_addsta_cmd *addsta = @@ -139,14 +140,14 @@ int iwl_send_add_sta(struct iwl_priv *priv, u8 data[sizeof(*sta)]; struct iwl_host_cmd cmd = { .id = REPLY_ADD_STA, - .meta.flags = flags, + .flags = flags, .data = data, }; if (flags & CMD_ASYNC) - cmd.meta.u.callback = iwl_add_sta_callback; + cmd.callback = iwl_add_sta_callback; else - cmd.meta.flags |= CMD_WANT_SKB; + cmd.flags |= CMD_WANT_SKB; cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data); ret = iwl_send_cmd(priv, &cmd); @@ -154,7 +155,7 @@ int iwl_send_add_sta(struct iwl_priv *priv, if (ret || (flags & CMD_ASYNC)) return ret; - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl_rx_packet *)cmd.reply_skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", res->hdr.flags); @@ -175,7 +176,7 @@ int iwl_send_add_sta(struct iwl_priv *priv, } priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.meta.u.skb); + dev_kfree_skb_any(cmd.reply_skb); return ret; } @@ -325,7 +326,8 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) } static int iwl_remove_sta_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb) + struct iwl_device_cmd *cmd, + struct sk_buff *skb) { struct iwl_rx_packet *res = NULL; struct iwl_rem_sta_cmd *rm_sta = @@ -368,7 +370,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, struct iwl_host_cmd cmd = { .id = REPLY_REMOVE_STA, .len = sizeof(struct iwl_rem_sta_cmd), - .meta.flags = flags, + .flags = flags, .data = &rm_sta_cmd, }; @@ -377,15 +379,15 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, memcpy(&rm_sta_cmd.addr, addr , ETH_ALEN); if (flags & CMD_ASYNC) - cmd.meta.u.callback = iwl_remove_sta_callback; + cmd.callback = iwl_remove_sta_callback; else - cmd.meta.flags |= CMD_WANT_SKB; + cmd.flags |= CMD_WANT_SKB; ret = iwl_send_cmd(priv, &cmd); if (ret || (flags & CMD_ASYNC)) return ret; - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl_rx_packet *)cmd.reply_skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", res->hdr.flags); @@ -406,7 +408,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, } priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.meta.u.skb); + dev_kfree_skb_any(cmd.reply_skb); return ret; } @@ -525,7 +527,7 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty) struct iwl_host_cmd cmd = { .id = REPLY_WEPKEY, .data = wep_cmd, - .meta.flags = CMD_ASYNC, + .flags = CMD_ASYNC, }; memset(wep_cmd, 0, cmd_size + @@ -930,7 +932,7 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_host_cmd cmd = { .id = REPLY_TX_LINK_QUALITY_CMD, .len = sizeof(struct iwl_link_quality_cmd), - .meta.flags = flags, + .flags = flags, .data = lq, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 0912987af60..51ddbab63c2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -141,7 +141,7 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) priv->cfg->ops->lib->txq_free_tfd(priv, txq); - len = sizeof(struct iwl_cmd) * q->n_window; + len = sizeof(struct iwl_device_cmd) * q->n_window; /* De-alloc array of command/tx buffers */ for (i = 0; i < TFD_TX_CMD_SLOTS; i++) @@ -156,6 +156,12 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) kfree(txq->txb); txq->txb = NULL; + /* deallocate arrays */ + kfree(txq->cmd); + kfree(txq->meta); + txq->cmd = NULL; + txq->meta = NULL; + /* 0-fill queue descriptor structure */ memset(txq, 0, sizeof(*txq)); } @@ -179,7 +185,7 @@ void iwl_cmd_queue_free(struct iwl_priv *priv) if (q->n_bd == 0) return; - len = sizeof(struct iwl_cmd) * q->n_window; + len = sizeof(struct iwl_device_cmd) * q->n_window; len += IWL_MAX_SCAN_SIZE; /* De-alloc array of command/tx buffers */ @@ -318,6 +324,7 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, { int i, len; int ret; + int actual_slots = slots_num; /* * Alloc buffer array for commands (Tx or other types of commands). @@ -327,14 +334,22 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, * For normal Tx queues (all other queues), no super-size command * space is needed. */ - len = sizeof(struct iwl_cmd); - for (i = 0; i <= slots_num; i++) { - if (i == slots_num) { - if (txq_id == IWL_CMD_QUEUE_NUM) - len += IWL_MAX_SCAN_SIZE; - else - continue; - } + if (txq_id == IWL_CMD_QUEUE_NUM) + actual_slots++; + + txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * actual_slots, + GFP_KERNEL); + txq->cmd = kzalloc(sizeof(struct iwl_device_cmd *) * actual_slots, + GFP_KERNEL); + + if (!txq->meta || !txq->cmd) + goto out_free_arrays; + + len = sizeof(struct iwl_device_cmd); + for (i = 0; i < actual_slots; i++) { + /* only happens for cmd queue */ + if (i == slots_num) + len += IWL_MAX_SCAN_SIZE; txq->cmd[i] = kmalloc(len, GFP_KERNEL); if (!txq->cmd[i]) @@ -364,15 +379,12 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, return 0; err: - for (i = 0; i < slots_num; i++) { + for (i = 0; i < actual_slots; i++) kfree(txq->cmd[i]); - txq->cmd[i] = NULL; - } +out_free_arrays: + kfree(txq->meta); + kfree(txq->cmd); - if (txq_id == IWL_CMD_QUEUE_NUM) { - kfree(txq->cmd[slots_num]); - txq->cmd[slots_num] = NULL; - } return -ENOMEM; } EXPORT_SYMBOL(iwl_tx_queue_init); @@ -673,7 +685,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_tx_queue *txq; struct iwl_queue *q; - struct iwl_cmd *out_cmd; + struct iwl_device_cmd *out_cmd; + struct iwl_cmd_meta *out_meta; struct iwl_tx_cmd *tx_cmd; int swq_id, txq_id; dma_addr_t phys_addr; @@ -766,6 +779,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Set up first empty entry in queue's array of Tx/cmd buffers */ out_cmd = txq->cmd[q->write_ptr]; + out_meta = &txq->meta[q->write_ptr]; tx_cmd = &out_cmd->cmd.tx; memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd)); @@ -828,8 +842,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) txcmd_phys = pci_map_single(priv->pci_dev, &out_cmd->hdr, len, PCI_DMA_BIDIRECTIONAL); - pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys); - pci_unmap_len_set(&out_cmd->meta, len, len); + pci_unmap_addr_set(out_meta, mapping, txcmd_phys); + pci_unmap_len_set(out_meta, len, len); /* Add buffer containing Tx command and MAC(!) header to TFD's * first entry */ priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, @@ -923,7 +937,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; struct iwl_queue *q = &txq->q; - struct iwl_cmd *out_cmd; + struct iwl_device_cmd *out_cmd; + struct iwl_cmd_meta *out_meta; dma_addr_t phys_addr; unsigned long flags; int len, ret; @@ -937,25 +952,31 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then * we will need to increase the size of the TFD entries */ BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && - !(cmd->meta.flags & CMD_SIZE_HUGE)); + !(cmd->flags & CMD_SIZE_HUGE)); if (iwl_is_rfkill(priv)) { IWL_DEBUG_INFO(priv, "Not sending command - RF KILL\n"); return -EIO; } - if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { + if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { IWL_ERR(priv, "No space for Tx\n"); return -ENOSPC; } spin_lock_irqsave(&priv->hcmd_lock, flags); - idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE); + idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE); out_cmd = txq->cmd[idx]; + out_meta = &txq->meta[idx]; + + out_meta->flags = cmd->flags; + if (cmd->flags & CMD_WANT_SKB) + out_meta->source = cmd; + if (cmd->flags & CMD_ASYNC) + out_meta->callback = cmd->callback; out_cmd->hdr.cmd = cmd->id; - memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta)); memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len); /* At this point, the out_cmd now has all of the incoming cmd @@ -964,9 +985,9 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) out_cmd->hdr.flags = 0; out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) | INDEX_TO_SEQ(q->write_ptr)); - if (out_cmd->meta.flags & CMD_SIZE_HUGE) + if (cmd->flags & CMD_SIZE_HUGE) out_cmd->hdr.sequence |= SEQ_HUGE_FRAME; - len = sizeof(struct iwl_cmd) - sizeof(struct iwl_cmd_meta); + len = sizeof(struct iwl_device_cmd); len += (idx == TFD_CMD_SLOTS) ? IWL_MAX_SCAN_SIZE : 0; @@ -998,8 +1019,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr, fix_size, PCI_DMA_BIDIRECTIONAL); - pci_unmap_addr_set(&out_cmd->meta, mapping, phys_addr); - pci_unmap_len_set(&out_cmd->meta, len, fix_size); + pci_unmap_addr_set(out_meta, mapping, phys_addr); + pci_unmap_len_set(out_meta, len, fix_size); priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, phys_addr, fix_size, 1, @@ -1068,8 +1089,8 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, } pci_unmap_single(priv->pci_dev, - pci_unmap_addr(&txq->cmd[cmd_idx]->meta, mapping), - pci_unmap_len(&txq->cmd[cmd_idx]->meta, len), + pci_unmap_addr(&txq->meta[cmd_idx], mapping), + pci_unmap_len(&txq->meta[cmd_idx], len), PCI_DMA_BIDIRECTIONAL); for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx; @@ -1100,7 +1121,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) int index = SEQ_TO_INDEX(sequence); int cmd_index; bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME); - struct iwl_cmd *cmd; + struct iwl_device_cmd *cmd; + struct iwl_cmd_meta *meta; /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced @@ -1116,18 +1138,18 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; + meta = &priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_index]; /* Input error checking is done when commands are added to queue. */ - if (cmd->meta.flags & CMD_WANT_SKB) { - cmd->meta.source->u.skb = rxb->skb; + if (meta->flags & CMD_WANT_SKB) { + meta->source->reply_skb = rxb->skb; rxb->skb = NULL; - } else if (cmd->meta.u.callback && - !cmd->meta.u.callback(priv, cmd, rxb->skb)) + } else if (meta->callback && !meta->callback(priv, cmd, rxb->skb)) rxb->skb = NULL; iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); - if (!(cmd->meta.flags & CMD_ASYNC)) { + if (!(meta->flags & CMD_ASYNC)) { clear_bit(STATUS_HCMD_ACTIVE, &priv->status); wake_up_interruptible(&priv->wait_command_queue); } diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 2cc7e30d774..5ded8983b91 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -363,7 +363,7 @@ static void iwl3945_unset_hw_params(struct iwl_priv *priv) static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, struct ieee80211_tx_info *info, - struct iwl_cmd *cmd, + struct iwl_device_cmd *cmd, struct sk_buff *skb_frag, int sta_id) { @@ -403,7 +403,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, * handle build REPLY_TX command notification. */ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv, - struct iwl_cmd *cmd, + struct iwl_device_cmd *cmd, struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, u8 std_id) { @@ -476,7 +476,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) struct iwl3945_tx_cmd *tx; struct iwl_tx_queue *txq = NULL; struct iwl_queue *q = NULL; - struct iwl_cmd *out_cmd = NULL; + struct iwl_device_cmd *out_cmd; + struct iwl_cmd_meta *out_meta; dma_addr_t phys_addr; dma_addr_t txcmd_phys; int txq_id = skb_get_queue_mapping(skb); @@ -565,6 +566,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Init first empty entry in queue's array of Tx/cmd buffers */ out_cmd = txq->cmd[idx]; + out_meta = &txq->meta[idx]; tx = (struct iwl3945_tx_cmd *)out_cmd->cmd.payload; memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); memset(tx, 0, sizeof(*tx)); @@ -642,8 +644,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) len, PCI_DMA_TODEVICE); /* we do not map meta data ... so we can safely access address to * provide to unmap command*/ - pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys); - pci_unmap_len_set(&out_cmd->meta, len, len); + pci_unmap_addr_set(out_meta, mapping, txcmd_phys); + pci_unmap_len_set(out_meta, len, len); /* Add buffer containing Tx command and MAC(!) header to TFD's * first entry */ @@ -753,7 +755,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv, struct iwl_host_cmd cmd = { .id = REPLY_SPECTRUM_MEASUREMENT_CMD, .data = (void *)&spectrum, - .meta.flags = CMD_WANT_SKB, + .flags = CMD_WANT_SKB, }; u32 add_time = le64_to_cpu(params->start_time); int rc; @@ -794,7 +796,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv, if (rc) return rc; - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl_rx_packet *)cmd.reply_skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_RX_ON_ASSOC command\n"); rc = -EIO; @@ -817,7 +819,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv, break; } - dev_kfree_skb_any(cmd.meta.u.skb); + dev_kfree_skb_any(cmd.reply_skb); return rc; } @@ -2717,7 +2719,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) struct iwl_host_cmd cmd = { .id = REPLY_SCAN_CMD, .len = sizeof(struct iwl3945_scan_cmd), - .meta.flags = CMD_SIZE_HUGE, + .flags = CMD_SIZE_HUGE, }; int rc = 0; struct iwl3945_scan_cmd *scan; -- cgit v1.2.3-18-g5258 From 5696aea6f243e40013d2b00cd140fd006ec20b9c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jul 2009 11:13:06 -0700 Subject: iwlwifi: remove command callback return value No existing callbacks use anything other than the return value 1, which means that the caller should free the reply skb, so it seems safer in terms of not introducing memory leaks to simply remove the return value and let the caller always free the skb. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-led.c | 7 +++---- drivers/net/wireless/iwlwifi/iwl-core.h | 6 +++--- drivers/net/wireless/iwlwifi/iwl-dev.h | 12 ++++++------ drivers/net/wireless/iwlwifi/iwl-hcmd.c | 21 +++++++++------------ drivers/net/wireless/iwlwifi/iwl-sta.c | 26 ++++++++++---------------- drivers/net/wireless/iwlwifi/iwl-tx.c | 4 ++-- 6 files changed, 33 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index b37938217f5..8c29ded7d02 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -79,11 +79,10 @@ static const struct { #define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /*Exclude Solid on*/ #define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1) -static int iwl3945_led_cmd_callback(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct sk_buff *skb) +static void iwl3945_led_cmd_callback(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct sk_buff *skb) { - return 1; } static inline int iwl3945_brightness_to_idx(enum led_brightness brightness) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 4156debec39..febcf76e1d4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -446,9 +446,9 @@ int __must_check iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data); int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, const void *data, - int (*callback)(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct sk_buff *skb)); + void (*callback)(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct sk_buff *skb)); int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index ce765f79275..3ca188a9592 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -163,9 +163,9 @@ struct iwl_cmd_meta { * invoked for SYNC commands, if it were and its result passed * through it would be simpler...) */ - int (*callback)(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct sk_buff *skb); + void (*callback)(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct sk_buff *skb); /* The CMD_SIZE_HUGE flag bit indicates that the command * structure is stored at the end of the shared queue memory. */ @@ -383,9 +383,9 @@ struct iwl_device_cmd { struct iwl_host_cmd { const void *data; struct sk_buff *reply_skb; - int (*callback)(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct sk_buff *skb); + void (*callback)(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct sk_buff *skb); u32 flags; u16 len; u8 id; diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index d8a3eac8ceb..b82ad15d518 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -103,23 +103,23 @@ EXPORT_SYMBOL(get_cmd_string); #define HOST_COMPLETE_TIMEOUT (HZ / 2) -static int iwl_generic_cmd_callback(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct sk_buff *skb) +static void iwl_generic_cmd_callback(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct sk_buff *skb) { struct iwl_rx_packet *pkt = NULL; if (!skb) { IWL_ERR(priv, "Error: Response NULL in %s.\n", get_cmd_string(cmd->hdr.cmd)); - return 1; + return; } pkt = (struct iwl_rx_packet *)skb->data; if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from %s (0x%08X)\n", get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); - return 1; + return; } #ifdef CONFIG_IWLWIFI_DEBUG @@ -128,15 +128,12 @@ static int iwl_generic_cmd_callback(struct iwl_priv *priv, case SENSITIVITY_CMD: IWL_DEBUG_HC_DUMP(priv, "back from %s (0x%08X)\n", get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); - break; + break; default: IWL_DEBUG_HC(priv, "back from %s (0x%08X)\n", get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); } #endif - - /* Let iwl_tx_complete free the response skb */ - return 1; } static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) @@ -275,9 +272,9 @@ EXPORT_SYMBOL(iwl_send_cmd_pdu); int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, const void *data, - int (*callback)(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct sk_buff *skb)) + void (*callback)(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct sk_buff *skb)) { struct iwl_host_cmd cmd = { .id = id, diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 1571ace05dd..79ea5cc2c89 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -97,9 +97,9 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) spin_unlock_irqrestore(&priv->sta_lock, flags); } -static int iwl_add_sta_callback(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct sk_buff *skb) +static void iwl_add_sta_callback(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct sk_buff *skb) { struct iwl_rx_packet *res = NULL; struct iwl_addsta_cmd *addsta = @@ -108,14 +108,14 @@ static int iwl_add_sta_callback(struct iwl_priv *priv, if (!skb) { IWL_ERR(priv, "Error: Response NULL in REPLY_ADD_STA.\n"); - return 1; + return; } res = (struct iwl_rx_packet *)skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", res->hdr.flags); - return 1; + return; } switch (res->u.add_sta.status) { @@ -127,9 +127,6 @@ static int iwl_add_sta_callback(struct iwl_priv *priv, res->u.add_sta.status); break; } - - /* We didn't cache the SKB; let the caller free it */ - return 1; } int iwl_send_add_sta(struct iwl_priv *priv, @@ -325,9 +322,9 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) spin_unlock_irqrestore(&priv->sta_lock, flags); } -static int iwl_remove_sta_callback(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct sk_buff *skb) +static void iwl_remove_sta_callback(struct iwl_priv *priv, + struct iwl_device_cmd *cmd, + struct sk_buff *skb) { struct iwl_rx_packet *res = NULL; struct iwl_rem_sta_cmd *rm_sta = @@ -336,14 +333,14 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv, if (!skb) { IWL_ERR(priv, "Error: Response NULL in REPLY_REMOVE_STA.\n"); - return 1; + return; } res = (struct iwl_rx_packet *)skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", res->hdr.flags); - return 1; + return; } switch (res->u.rem_sta.status) { @@ -354,9 +351,6 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv, IWL_ERR(priv, "REPLY_REMOVE_STA failed\n"); break; } - - /* We didn't cache the SKB; let the caller free it */ - return 1; } static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 51ddbab63c2..e1558db97ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1144,8 +1144,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) if (meta->flags & CMD_WANT_SKB) { meta->source->reply_skb = rxb->skb; rxb->skb = NULL; - } else if (meta->callback && !meta->callback(priv, cmd, rxb->skb)) - rxb->skb = NULL; + } else if (meta->callback) + meta->callback(priv, cmd, rxb->skb); iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); -- cgit v1.2.3-18-g5258 From ec74116487278adf6c3db9c3bbdc81c6409c1cbb Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 24 Jul 2009 11:13:08 -0700 Subject: iwlwifi: print packet contents in error case This data is more useful to debugging that the receive buffer contents. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index e1558db97ec..660d1a76292 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1132,7 +1132,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) txq_id, sequence, priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr, priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) { - iwl_print_hex_error(priv, rxb, 32); + iwl_print_hex_error(priv, pkt, 32); return; } -- cgit v1.2.3-18-g5258 From bcc693a14ddf46170752c185e415ff8609b9f82f Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 24 Jul 2009 11:13:09 -0700 Subject: iwlwifi: Name fix for MPDU density for TX aggregation Fix incorrect name for HT MPDU Density. default set to 4 uSec Reported-by: Sujith Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-dev.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 3ca188a9592..facbc3daf55 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -491,8 +491,16 @@ union iwl_ht_rate_supp { }; #define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3) -#define CFG_HT_MPDU_DENSITY_2USEC (0x5) -#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC + +/* + * Maximal MPDU density for TX aggregation + * 4 - 2us density + * 5 - 4us density + * 6 - 8us density + * 7 - 16us density + */ +#define CFG_HT_MPDU_DENSITY_4USEC (0x5) +#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_4USEC struct iwl_ht_info { /* self configuration data */ -- cgit v1.2.3-18-g5258 From 1da46bebb1bb01a77333e6509e74e12b85df5729 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Fri, 24 Jul 2009 11:13:10 -0700 Subject: iwlwifi: fix LED config option IWLWIFI_LEDS option should certainly have help comment, and should default to y. Signed-off-by: Pavel Machek Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Kconfig | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index e092af09d6b..99310c03325 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -9,6 +9,9 @@ config IWLWIFI config IWLWIFI_LEDS bool "Enable LED support in iwlagn and iwl3945 drivers" depends on IWLWIFI + default y + ---help--- + Select this if you want LED support. config IWLWIFI_SPECTRUM_MEASUREMENT bool "Enable Spectrum Measurement in iwlagn driver" -- cgit v1.2.3-18-g5258 From 9e3b25837a20f4d48fef57b0cb8bf750a8cfa8e2 Mon Sep 17 00:00:00 2001 From: Florian Echtler Date: Mon, 27 Jul 2009 17:35:39 -0700 Subject: Input: usbtouchscreen - add support for e2i touchscreen controller This patch adds support for the e2i touchscreen controller used in the Mimo 740 (and probably in other e2i touchscreen products). Tested on Mimo 740. Signed-off-by: Florian Echtler Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 5 +++ drivers/input/touchscreen/usbtouchscreen.c | 49 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) (limited to 'drivers') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 07703bcb64c..87a1ae63bcc 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -474,6 +474,11 @@ config TOUCHSCREEN_USB_JASTEC bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EMBEDDED depends on TOUCHSCREEN_USB_COMPOSITE +config TOUCHSCREEN_USB_E2I + default y + bool "e2i Touchscreen controller (e.g. from Mimo 740)" + depends on TOUCHSCREEN_USB_COMPOSITE + config TOUCHSCREEN_TOUCHIT213 tristate "Sahara TouchIT-213 touchscreen" select SERIO diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index c07be07a69b..68ece5801a5 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -120,6 +120,7 @@ enum { DEVTYPE_GENERAL_TOUCH, DEVTYPE_GOTOP, DEVTYPE_JASTEC, + DEVTYPE_E2I, }; #define USB_DEVICE_HID_CLASS(vend, prod) \ @@ -197,10 +198,46 @@ static struct usb_device_id usbtouch_devices[] = { {USB_DEVICE(0x0f92, 0x0001), .driver_info = DEVTYPE_JASTEC}, #endif +#ifdef CONFIG_TOUCHSCREEN_USB_E2I + {USB_DEVICE(0x1ac7, 0x0001), .driver_info = DEVTYPE_E2I}, +#endif {} }; +/***************************************************************************** + * e2i Part + */ + +#ifdef CONFIG_TOUCHSCREEN_USB_E2I +static int e2i_init(struct usbtouch_usb *usbtouch) +{ + int ret; + + ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0), + 0x01, 0x02, 0x0000, 0x0081, + NULL, 0, USB_CTRL_SET_TIMEOUT); + + dbg("%s - usb_control_msg - E2I_RESET - bytes|err: %d", + __func__, ret); + return ret; +} + +static int e2i_read_data(struct usbtouch_usb *dev, unsigned char *pkt) +{ + int tmp = (pkt[0] << 8) | pkt[1]; + dev->x = (pkt[2] << 8) | pkt[3]; + dev->y = (pkt[4] << 8) | pkt[5]; + + tmp = tmp - 0xA000; + dev->touch = (tmp > 0); + dev->press = (tmp > 0 ? tmp : 0); + + return 1; +} +#endif + + /***************************************************************************** * eGalax part */ @@ -734,6 +771,18 @@ static struct usbtouch_device_info usbtouch_dev_info[] = { .read_data = jastec_read_data, }, #endif + +#ifdef CONFIG_TOUCHSCREEN_USB_E2I + [DEVTYPE_E2I] = { + .min_xc = 0x0, + .max_xc = 0x7fff, + .min_yc = 0x0, + .max_yc = 0x7fff, + .rept_size = 6, + .init = e2i_init, + .read_data = e2i_read_data, + }, +#endif }; -- cgit v1.2.3-18-g5258 From f7ea097d9b4e61a816c041c92548aad7c7ed7915 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 24 Jul 2009 11:13:12 -0700 Subject: iwlagn: fix null pointer access during ucode load on 1000 Commit "iwlwifi: Handle new firmware file with ucode build number in header" introduced new ucode header parsing routines, but neglected to initialize these routines for 1000. The system thus goes into infinite loop trying to load ucode, failing every time with a null pointer exception as it tries to parse the header. Signed-off-by: Reinette Chatre Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 80a28184a37..5f7c52053c1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -124,6 +124,7 @@ static struct iwl_lib_ops iwl1000_lib = { }; static struct iwl_ops iwl1000_ops = { + .ucode = &iwl5000_ucode, .lib = &iwl1000_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl5000_hcmd_utils, -- cgit v1.2.3-18-g5258 From 6686d17e161dcd0dc6801bcde9e397020bf9edf7 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 24 Jul 2009 11:13:13 -0700 Subject: iwlagn: fix sparse warning when compiling without debug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit C [M] drivers/net/wireless/iwlwifi/iwl-core.o drivers/net/wireless/iwlwifi/iwl-core.c:1341: warning: ‘iwl_dump_nic_error_log’ defined but not used Reported-by: Luis R. Rodriguez Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 710dd41c341..aafa9fdd647 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1291,7 +1291,6 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv) IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr); IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); } -#endif static const char *desc_lookup_text[] = { "OK", @@ -1496,6 +1495,7 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) iwl_print_event_log(priv, 0, next_entry, mode); } +#endif /** * iwl_irq_handle_error - called for HW or SW error interrupt from card */ -- cgit v1.2.3-18-g5258 From 11866efa9b5d6f321a2625b7f6837ba55c4c2e4b Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 27 Jul 2009 10:56:41 -0400 Subject: ray_cs: remove bogus NULL check at head of ray_get_wireless_stats Reported-by: Johannes Berg Cc: Martin Ettl Signed-off-by: John W. Linville --- drivers/net/wireless/ray_cs.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 64e574c3655..2be78201633 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -1511,9 +1511,6 @@ static iw_stats *ray_get_wireless_stats(struct net_device *dev) struct pcmcia_device *link = local->finder; struct status __iomem *p = local->sram + STATUS_BASE; - if (local == (ray_dev_t *) NULL) - return (iw_stats *) NULL; - local->wstats.status = local->card_status; #ifdef WIRELESS_SPY if ((local->spy_data.spy_number > 0) -- cgit v1.2.3-18-g5258 From ff8365ca889cb86ba5bd40fe3047d047bc632f4c Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Fri, 24 Jul 2009 11:55:44 +0400 Subject: ar9170: fix build error when !CONFIG_AR9170_LEDS Fix this build error when CONFIG_AR9170_LEDS is not set drivers/net/wireless/ath/ar9170/main.c:1296: error: 'struct ar9170' has no member named 'led_work' Signed-off-by: Alexander Beregalov Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index c7287a883a4..85a1452a7c3 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -1293,7 +1293,9 @@ static void ar9170_op_stop(struct ieee80211_hw *hw) flush_workqueue(ar->hw->workqueue); cancel_delayed_work_sync(&ar->tx_janitor); +#ifdef CONFIG_AR9170_LEDS cancel_delayed_work_sync(&ar->led_work); +#endif cancel_work_sync(&ar->filter_config_work); cancel_work_sync(&ar->beacon_work); mutex_lock(&ar->mutex); -- cgit v1.2.3-18-g5258 From 96148326c4b54db5c384def1a5ab285c359d1395 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 24 Jul 2009 17:27:21 +0200 Subject: ath9k: fix race with IEEE80211_CONF_PS checks There is a small window where the mac80211 changes the IEEE80211_CONF_PS flag, and then informs the driver about the change. We have a race condition if we are checking the flag in the same time. Avoid it by introducing a local variable, and using that instead of checking the IEEE80211_CONF_PS flag directly. This fix the problem reported by Luis: http://article.gmane.org/gmane.linux.kernel.wireless.general/34363 Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/hw.c | 17 +++++++---------- drivers/net/wireless/ath/ath9k/hw.h | 1 - drivers/net/wireless/ath/ath9k/main.c | 8 ++++---- 4 files changed, 12 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index e2ebf1a56c0..3a978bfa246 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -573,6 +573,7 @@ struct ath_softc { u32 keymax; DECLARE_BITMAP(keymap, ATH_KEYMAX); u8 splitmic; + bool ps_enabled; unsigned long ps_usecount; enum ath9k_int imask; enum ath9k_ht_extprotspacing ht_extprotspacing; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index da3226994de..e6e52f48e71 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2863,10 +2863,8 @@ void ath9k_ps_wakeup(struct ath_softc *sc) if (++sc->ps_usecount != 1) goto unlock; - if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) { - sc->sc_ah->restore_mode = sc->sc_ah->power_mode; + if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE); - } unlock: spin_unlock_irqrestore(&sc->sc_pm_lock, flags); @@ -2880,13 +2878,12 @@ void ath9k_ps_restore(struct ath_softc *sc) if (--sc->ps_usecount != 0) goto unlock; - if ((sc->hw->conf.flags & IEEE80211_CONF_PS) && - !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | - SC_OP_WAIT_FOR_CAB | - SC_OP_WAIT_FOR_PSPOLL_DATA | - SC_OP_WAIT_FOR_TX_ACK))) - ath9k_hw_setpower_nolock(sc->sc_ah, - sc->sc_ah->restore_mode); + if (sc->ps_enabled && + !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_CAB | + SC_OP_WAIT_FOR_PSPOLL_DATA | + SC_OP_WAIT_FOR_TX_ACK))) + ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); unlock: spin_unlock_irqrestore(&sc->sc_pm_lock, flags); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 37f7d3defb8..2e196df1089 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -421,7 +421,6 @@ struct ath_hw { enum nl80211_iftype opmode; enum ath9k_power_mode power_mode; - enum ath9k_power_mode restore_mode; struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; struct ar5416Stats stats; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 1c648db1092..87f99718393 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -499,8 +499,7 @@ static void ath9k_tasklet(unsigned long data) if (status & ATH9K_INT_TX) ath_tx_tasklet(sc); - if ((status & ATH9K_INT_TSFOOR) && - (sc->hw->conf.flags & IEEE80211_CONF_PS)) { + if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) { /* * TSF sync does not look correct; remain awake to sync with * the next Beacon. @@ -2001,7 +2000,7 @@ static int ath9k_tx(struct ieee80211_hw *hw, goto exit; } - if (sc->hw->conf.flags & IEEE80211_CONF_PS) { + if (sc->ps_enabled) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; /* * mac80211 does not set PM field for normal data frames, so we @@ -2289,8 +2288,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) } ath9k_hw_setrxabort(sc->sc_ah, 1); } - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); + sc->ps_enabled = true; } else { + sc->ps_enabled = false; ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { -- cgit v1.2.3-18-g5258 From cbdec9758736c30ecbb03651b0c2915c442a5895 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 24 Jul 2009 17:27:22 +0200 Subject: ath9k: get rid of unnecessary setpower calls We are using setpower routines regardless of the current power mode. Don't bother the hardware, if it is not necessary. Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index e6e52f48e71..431854ccb65 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -478,6 +478,8 @@ static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc, ah->gbeacon_rate = 0; + ah->power_mode = ATH9K_PM_UNDEFINED; + return ah; } @@ -2819,6 +2821,9 @@ static bool ath9k_hw_setpower_nolock(struct ath_hw *ah, "UNDEFINED" }; + if (ah->power_mode == mode) + return status; + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s -> %s\n", modes[ah->power_mode], modes[mode]); @@ -2863,8 +2868,7 @@ void ath9k_ps_wakeup(struct ath_softc *sc) if (++sc->ps_usecount != 1) goto unlock; - if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) - ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE); + ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE); unlock: spin_unlock_irqrestore(&sc->sc_pm_lock, flags); -- cgit v1.2.3-18-g5258 From fec247c0d5bfbaa0861774ce31d515bbd48f7fce Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 27 Jul 2009 12:08:16 +0530 Subject: ath9k: Add debug counters for TX Location: ath9k/phy#/xmit Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/debug.c | 85 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/debug.h | 54 +++++++++++++++++++++ drivers/net/wireless/ath/ath9k/xmit.c | 34 ++++++++------ 4 files changed, 160 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 3a978bfa246..bda0f302340 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -237,7 +237,6 @@ struct ath_txq { spinlock_t axq_lock; u32 axq_depth; u8 axq_aggr_depth; - u32 axq_totalqueued; bool stopped; bool axq_tx_inprogress; struct ath_buf *axq_linkbuf; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 9f99f00c144..9e369208f7d 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -486,6 +486,83 @@ static const struct file_operations fops_wiphy = { .owner = THIS_MODULE }; +#define PR(str, elem) \ + do { \ + len += snprintf(buf + len, size - len, \ + "%s%13u%11u%10u%10u\n", str, \ + sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_BE]].elem, \ + sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_BK]].elem, \ + sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_VI]].elem, \ + sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_VO]].elem); \ +} while(0) + +static ssize_t read_file_xmit(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char *buf; + unsigned int len = 0, size = 2048; + ssize_t retval = 0; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return 0; + + len += sprintf(buf, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO"); + + PR("MPDUs Queued: ", queued); + PR("MPDUs Completed: ", completed); + PR("Aggregates: ", a_aggr); + PR("AMPDUs Queued: ", a_queued); + PR("AMPDUs Completed:", a_completed); + PR("AMPDUs Retried: ", a_retries); + PR("AMPDUs XRetried: ", a_xretries); + PR("FIFO Underrun: ", fifo_underrun); + PR("TXOP Exceeded: ", xtxop); + PR("TXTIMER Expiry: ", timer_exp); + PR("DESC CFG Error: ", desc_cfg_err); + PR("DATA Underrun: ", data_underrun); + PR("DELIM Underrun: ", delim_underrun); + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, + struct ath_buf *bf) +{ + struct ath_desc *ds = bf->bf_desc; + + if (bf_isampdu(bf)) { + if (bf_isxretried(bf)) + TX_STAT_INC(txq->axq_qnum, a_xretries); + else + TX_STAT_INC(txq->axq_qnum, a_completed); + } else { + TX_STAT_INC(txq->axq_qnum, completed); + } + + if (ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO) + TX_STAT_INC(txq->axq_qnum, fifo_underrun); + if (ds->ds_txstat.ts_status & ATH9K_TXERR_XTXOP) + TX_STAT_INC(txq->axq_qnum, xtxop); + if (ds->ds_txstat.ts_status & ATH9K_TXERR_TIMER_EXPIRED) + TX_STAT_INC(txq->axq_qnum, timer_exp); + if (ds->ds_txstat.ts_flags & ATH9K_TX_DESC_CFG_ERR) + TX_STAT_INC(txq->axq_qnum, desc_cfg_err); + if (ds->ds_txstat.ts_flags & ATH9K_TX_DATA_UNDERRUN) + TX_STAT_INC(txq->axq_qnum, data_underrun); + if (ds->ds_txstat.ts_flags & ATH9K_TX_DELIM_UNDERRUN) + TX_STAT_INC(txq->axq_qnum, delim_underrun); +} + +static const struct file_operations fops_xmit = { + .read = read_file_xmit, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; int ath9k_init_debug(struct ath_softc *sc) { @@ -529,6 +606,13 @@ int ath9k_init_debug(struct ath_softc *sc) if (!sc->debug.debugfs_wiphy) goto err; + sc->debug.debugfs_xmit = debugfs_create_file("xmit", + S_IRUSR, + sc->debug.debugfs_phy, + sc, &fops_xmit); + if (!sc->debug.debugfs_xmit) + goto err; + return 0; err: ath9k_exit_debug(sc); @@ -537,6 +621,7 @@ err: void ath9k_exit_debug(struct ath_softc *sc) { + debugfs_remove(sc->debug.debugfs_xmit); debugfs_remove(sc->debug.debugfs_wiphy); debugfs_remove(sc->debug.debugfs_rcstat); debugfs_remove(sc->debug.debugfs_interrupt); diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index edda15bf2c1..5e56b79d0cb 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -35,6 +35,15 @@ enum ATH_DEBUG { #define DBG_DEFAULT (ATH_DBG_FATAL) +struct ath_txq; +struct ath_buf; + +#ifdef CONFIG_ATH9K_DEBUG +#define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++ +#else +#define TX_STAT_INC(q, c) do { } while (0) +#endif + #ifdef CONFIG_ATH9K_DEBUG /** @@ -87,9 +96,45 @@ struct ath_rc_stats { u8 per; }; +/** + * struct ath_tx_stats - Statistics about TX + * @queued: Total MPDUs (non-aggr) queued + * @completed: Total MPDUs (non-aggr) completed + * @a_aggr: Total no. of aggregates queued + * @a_queued: Total AMPDUs queued + * @a_completed: Total AMPDUs completed + * @a_retries: No. of AMPDUs retried (SW) + * @a_xretries: No. of AMPDUs dropped due to xretries + * @fifo_underrun: FIFO underrun occurrences + Valid only for: + - non-aggregate condition. + - first packet of aggregate. + * @xtxop: No. of frames filtered because of TXOP limit + * @timer_exp: Transmit timer expiry + * @desc_cfg_err: Descriptor configuration errors + * @data_urn: TX data underrun errors + * @delim_urn: TX delimiter underrun errors + */ +struct ath_tx_stats { + u32 queued; + u32 completed; + u32 a_aggr; + u32 a_queued; + u32 a_completed; + u32 a_retries; + u32 a_xretries; + u32 fifo_underrun; + u32 xtxop; + u32 timer_exp; + u32 desc_cfg_err; + u32 data_underrun; + u32 delim_underrun; +}; + struct ath_stats { struct ath_interrupt_stats istats; struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; + struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES]; }; struct ath9k_debug { @@ -100,6 +145,7 @@ struct ath9k_debug { struct dentry *debugfs_interrupt; struct dentry *debugfs_rcstat; struct dentry *debugfs_wiphy; + struct dentry *debugfs_xmit; struct ath_stats stats; }; @@ -110,6 +156,8 @@ int ath9k_debug_create_root(void); void ath9k_debug_remove_root(void); void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb); +void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, + struct ath_buf *bf); void ath_debug_stat_retries(struct ath_softc *sc, int rix, int xretries, int retries, u8 per); @@ -148,6 +196,12 @@ static inline void ath_debug_stat_rc(struct ath_softc *sc, { } +static inline void ath_debug_stat_tx(struct ath_softc *sc, + struct ath_txq *txq, + struct ath_buf *bf) +{ +} + static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix, int xretries, int retries, u8 per) { diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 6eb2927c8ae..b7806e2ca0e 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -59,6 +59,7 @@ static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, struct list_head *bf_head); static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, + struct ath_txq *txq, struct list_head *bf_q, int txok, int sendbar); static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, @@ -212,7 +213,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, ath_tx_update_baw(sc, tid, bf->bf_seqno); spin_unlock(&txq->axq_lock); - ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); + ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0); spin_lock(&txq->axq_lock); } @@ -220,13 +221,15 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, tid->baw_tail = tid->baw_head; } -static void ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf) +static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq, + struct ath_buf *bf) { struct sk_buff *skb; struct ieee80211_hdr *hdr; bf->bf_state.bf_type |= BUF_RETRY; bf->bf_retries++; + TX_STAT_INC(txq->axq_qnum, a_retries); skb = bf->bf_mpdu; hdr = (struct ieee80211_hdr *)skb->data; @@ -328,7 +331,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, if (!(tid->state & AGGR_CLEANUP) && ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) { if (bf->bf_retries < ATH_MAX_SW_RETRIES) { - ath_tx_set_retry(sc, bf); + ath_tx_set_retry(sc, txq, bf); txpending = 1; } else { bf->bf_state.bf_type |= BUF_XRETRY; @@ -375,7 +378,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ath_tx_rc_status(bf, ds, nbad, txok, false); } - ath_tx_complete_buf(sc, bf, &bf_head, !txfail, sendbar); + ath_tx_complete_buf(sc, bf, txq, &bf_head, !txfail, sendbar); } else { /* retry the un-acked ones */ if (bf->bf_next == NULL && bf_last->bf_stale) { @@ -395,8 +398,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, bf->bf_state.bf_type |= BUF_XRETRY; ath_tx_rc_status(bf, ds, nbad, 0, false); - ath_tx_complete_buf(sc, bf, &bf_head, - 0, 0); + ath_tx_complete_buf(sc, bf, txq, + &bf_head, 0, 0); break; } @@ -569,6 +572,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, } static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, + struct ath_txq *txq, struct ath_atx_tid *tid, struct list_head *bf_q) { @@ -633,6 +637,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, bf_prev->bf_desc->ds_link = bf->bf_daddr; } bf_prev = bf; + } while (!list_empty(&tid->buf_q)); bf_first->bf_al = al; @@ -655,7 +660,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, INIT_LIST_HEAD(&bf_q); - status = ath_tx_form_aggr(sc, tid, &bf_q); + status = ath_tx_form_aggr(sc, txq, tid, &bf_q); /* * no frames picked up to be aggregated; @@ -686,6 +691,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, txq->axq_aggr_depth++; ath_tx_txqaddbuf(sc, txq, &bf_q); + TX_STAT_INC(txq->axq_qnum, a_aggr); } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH && status != ATH_AGGR_BAW_CLOSED); @@ -737,7 +743,7 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) } list_move_tail(&bf->list, &bf_head); ath_tx_update_baw(sc, txtid, bf->bf_seqno); - ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); + ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0); } spin_unlock_bh(&txq->axq_lock); @@ -859,7 +865,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) spin_lock_init(&txq->axq_lock); txq->axq_depth = 0; txq->axq_aggr_depth = 0; - txq->axq_totalqueued = 0; txq->axq_linkbuf = NULL; txq->axq_tx_inprogress = false; sc->tx.txqsetup |= 1<axq_lock); @@ -1176,7 +1181,6 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, list_splice_tail_init(head, &txq->axq_q); txq->axq_depth++; - txq->axq_totalqueued++; txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list); DPRINTF(sc, ATH_DBG_QUEUE, @@ -1224,6 +1228,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, bf = list_first_entry(bf_head, struct ath_buf, list); bf->bf_state.bf_type |= BUF_AMPDU; + TX_STAT_INC(txctl->txq->axq_qnum, a_queued); /* * Do not queue to h/w when any of the following conditions is true: @@ -1270,6 +1275,7 @@ static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq, bf->bf_lastbf = bf; ath_buf_set_rate(sc, bf); ath_tx_txqaddbuf(sc, txq, bf_head); + TX_STAT_INC(txq->axq_qnum, queued); } static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, @@ -1283,6 +1289,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, bf->bf_nframes = 1; ath_buf_set_rate(sc, bf); ath_tx_txqaddbuf(sc, txq, bf_head); + TX_STAT_INC(txq->axq_qnum, queued); } static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) @@ -1808,6 +1815,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, } static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, + struct ath_txq *txq, struct list_head *bf_q, int txok, int sendbar) { @@ -1815,7 +1823,6 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, unsigned long flags; int tx_flags = 0; - if (sendbar) tx_flags = ATH_TX_BAR; @@ -1828,6 +1835,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); ath_tx_complete(sc, skb, tx_flags); + ath_debug_stat_tx(sc, txq, bf); /* * Return the list of ath_buf of this mpdu to free queue @@ -2015,7 +2023,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) if (bf_isampdu(bf)) ath_tx_complete_aggr(sc, txq, bf, &bf_head, txok); else - ath_tx_complete_buf(sc, bf, &bf_head, txok, 0); + ath_tx_complete_buf(sc, bf, txq, &bf_head, txok, 0); ath_wake_mac80211_queue(sc, txq); -- cgit v1.2.3-18-g5258 From 0e82ffe3b90bcad72cfe80e4379946b8fb0691ca Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jul 2009 12:01:50 +0200 Subject: cfg80211: combine iwfreq implementations Until now we implemented iwfreq for managed mode, we needed to keep the implementations separate, but now that we have all versions implemented we can combine them and export just one handler. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/wext.c | 34 ++------------------------------ 1 file changed, 2 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c index c3c90d5963b..8058e9991c3 100644 --- a/drivers/net/wireless/iwmc3200wifi/wext.c +++ b/drivers/net/wireless/iwmc3200wifi/wext.c @@ -27,36 +27,6 @@ #include "iwm.h" #include "commands.h" -static int iwm_wext_siwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - switch (iwm->conf.mode) { - case UMAC_MODE_IBSS: - return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); - default: - return -EOPNOTSUPP; - } -} - -static int iwm_wext_giwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - switch (iwm->conf.mode) { - case UMAC_MODE_IBSS: - return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); - case UMAC_MODE_BSS: - return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra); - default: - return -EOPNOTSUPP; - } -} - static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { @@ -125,8 +95,8 @@ static const iw_handler iwm_handlers[] = (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */ (iw_handler) NULL, /* SIOCSIWNWID */ (iw_handler) NULL, /* SIOCGIWNWID */ - (iw_handler) iwm_wext_siwfreq, /* SIOCSIWFREQ */ - (iw_handler) iwm_wext_giwfreq, /* SIOCGIWFREQ */ + (iw_handler) cfg80211_wext_siwfreq, /* SIOCSIWFREQ */ + (iw_handler) cfg80211_wext_giwfreq, /* SIOCGIWFREQ */ (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */ (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */ (iw_handler) NULL, /* SIOCSIWSENS */ -- cgit v1.2.3-18-g5258 From 562e482265ac4d660d9f0114419591d62f44361d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jul 2009 12:01:51 +0200 Subject: cfg80211: combine IWAP handlers Since we now have IWAP handlers for all modes, we can combine them into one. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/wext.c | 34 ++------------------------------ 1 file changed, 2 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c index 8058e9991c3..5319b16474e 100644 --- a/drivers/net/wireless/iwmc3200wifi/wext.c +++ b/drivers/net/wireless/iwmc3200wifi/wext.c @@ -27,36 +27,6 @@ #include "iwm.h" #include "commands.h" -static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - switch (iwm->conf.mode) { - case UMAC_MODE_IBSS: - return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); - case UMAC_MODE_BSS: - return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra); - default: - return -EOPNOTSUPP; - } -} - -static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - switch (iwm->conf.mode) { - case UMAC_MODE_IBSS: - return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); - case UMAC_MODE_BSS: - return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra); - default: - return -EOPNOTSUPP; - } -} - static int iwm_wext_siwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid) @@ -111,8 +81,8 @@ static const iw_handler iwm_handlers[] = (iw_handler) NULL, /* SIOCGIWSPY */ (iw_handler) NULL, /* SIOCSIWTHRSPY */ (iw_handler) NULL, /* SIOCGIWTHRSPY */ - (iw_handler) iwm_wext_siwap, /* SIOCSIWAP */ - (iw_handler) iwm_wext_giwap, /* SIOCGIWAP */ + (iw_handler) cfg80211_wext_siwap, /* SIOCSIWAP */ + (iw_handler) cfg80211_wext_giwap, /* SIOCGIWAP */ (iw_handler) NULL, /* SIOCSIWMLME */ (iw_handler) NULL, /* SIOCGIWAPLIST */ (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ -- cgit v1.2.3-18-g5258 From 1f9298f96082692bdfe73af6fc2167f627f21647 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jul 2009 12:01:52 +0200 Subject: cfg80211: combine IWESSID handlers Since we now have handlers IWESSID for all modes, we can combine them into one. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/wext.c | 36 ++------------------------------ 1 file changed, 2 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c index 5319b16474e..9196024a289 100644 --- a/drivers/net/wireless/iwmc3200wifi/wext.c +++ b/drivers/net/wireless/iwmc3200wifi/wext.c @@ -27,38 +27,6 @@ #include "iwm.h" #include "commands.h" -static int iwm_wext_siwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *ssid) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - switch (iwm->conf.mode) { - case UMAC_MODE_IBSS: - return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); - case UMAC_MODE_BSS: - return cfg80211_mgd_wext_siwessid(dev, info, data, ssid); - default: - return -EOPNOTSUPP; - } -} - -static int iwm_wext_giwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *ssid) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - switch (iwm->conf.mode) { - case UMAC_MODE_IBSS: - return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); - case UMAC_MODE_BSS: - return cfg80211_mgd_wext_giwessid(dev, info, data, ssid); - default: - return -EOPNOTSUPP; - } -} - static const iw_handler iwm_handlers[] = { (iw_handler) NULL, /* SIOCSIWCOMMIT */ @@ -87,8 +55,8 @@ static const iw_handler iwm_handlers[] = (iw_handler) NULL, /* SIOCGIWAPLIST */ (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */ - (iw_handler) iwm_wext_siwessid, /* SIOCSIWESSID */ - (iw_handler) iwm_wext_giwessid, /* SIOCGIWESSID */ + (iw_handler) cfg80211_wext_siwessid, /* SIOCSIWESSID */ + (iw_handler) cfg80211_wext_giwessid, /* SIOCGIWESSID */ (iw_handler) NULL, /* SIOCSIWNICKN */ (iw_handler) NULL, /* SIOCGIWNICKN */ (iw_handler) NULL, /* -- hole -- */ -- cgit v1.2.3-18-g5258 From a9a11622c5c742c115fad371c0397ae86dd3bb67 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jul 2009 12:01:53 +0200 Subject: cfg80211: self-contained wext handling where possible Finally! This is what you've all been waiting for! This patch makes cfg80211 take care of wext emulation _completely_ by itself, drivers that don't need things cfg80211 doesn't do yet don't even need to be aware of wireless extensions. This means we can also clean up mac80211's and iwm's Kconfig and make it possible to build them w/o wext now! RIP wext. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/Kconfig | 1 - drivers/net/wireless/iwmc3200wifi/Makefile | 2 +- drivers/net/wireless/iwmc3200wifi/iwm.h | 2 - drivers/net/wireless/iwmc3200wifi/netdev.c | 1 - drivers/net/wireless/iwmc3200wifi/wext.c | 95 ------------------------------ 5 files changed, 1 insertion(+), 100 deletions(-) delete mode 100644 drivers/net/wireless/iwmc3200wifi/wext.c (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig index 030401d367d..c62da435285 100644 --- a/drivers/net/wireless/iwmc3200wifi/Kconfig +++ b/drivers/net/wireless/iwmc3200wifi/Kconfig @@ -2,7 +2,6 @@ config IWM tristate "Intel Wireless Multicomm 3200 WiFi driver" depends on MMC && WLAN_80211 && EXPERIMENTAL depends on CFG80211 - select WIRELESS_EXT select FW_LOADER help The Intel Wireless Multicomm 3200 hardware is a combo diff --git a/drivers/net/wireless/iwmc3200wifi/Makefile b/drivers/net/wireless/iwmc3200wifi/Makefile index 927f022545c..d34291b652d 100644 --- a/drivers/net/wireless/iwmc3200wifi/Makefile +++ b/drivers/net/wireless/iwmc3200wifi/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_IWM) := iwmc3200wifi.o iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o -iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o +iwmc3200wifi-objs += commands.o cfg80211.o eeprom.o iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 2175a481d2f..7a51bc340fd 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -306,8 +306,6 @@ static inline void *iwm_private(struct iwm_priv *iwm) #define skb_to_rx_info(s) ((struct iwm_rx_info *)(s->cb)) #define skb_to_tx_info(s) ((struct iwm_tx_info *)s->cb) -extern const struct iw_handler_def iwm_iw_handler_def; - void *iwm_if_alloc(int sizeof_bus, struct device *dev, struct iwm_if_ops *if_ops); void iwm_if_free(struct iwm_priv *iwm); diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c index 092d28ae56a..30116d1b448 100644 --- a/drivers/net/wireless/iwmc3200wifi/netdev.c +++ b/drivers/net/wireless/iwmc3200wifi/netdev.c @@ -123,7 +123,6 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev, } ndev->netdev_ops = &iwm_netdev_ops; - ndev->wireless_handlers = &iwm_iw_handler_def; ndev->ieee80211_ptr = wdev; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); wdev->netdev = ndev; diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c deleted file mode 100644 index 9196024a289..00000000000 --- a/drivers/net/wireless/iwmc3200wifi/wext.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation - * Samuel Ortiz - * Zhu Yi - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#include -#include - -#include "iwm.h" -#include "commands.h" - -static const iw_handler iwm_handlers[] = -{ - (iw_handler) NULL, /* SIOCSIWCOMMIT */ - (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */ - (iw_handler) NULL, /* SIOCSIWNWID */ - (iw_handler) NULL, /* SIOCGIWNWID */ - (iw_handler) cfg80211_wext_siwfreq, /* SIOCSIWFREQ */ - (iw_handler) cfg80211_wext_giwfreq, /* SIOCGIWFREQ */ - (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */ - (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */ - (iw_handler) NULL, /* SIOCSIWSENS */ - (iw_handler) NULL, /* SIOCGIWSENS */ - (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ - (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */ - (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ - (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ - (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ - (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */ - (iw_handler) NULL, /* SIOCSIWSPY */ - (iw_handler) NULL, /* SIOCGIWSPY */ - (iw_handler) NULL, /* SIOCSIWTHRSPY */ - (iw_handler) NULL, /* SIOCGIWTHRSPY */ - (iw_handler) cfg80211_wext_siwap, /* SIOCSIWAP */ - (iw_handler) cfg80211_wext_giwap, /* SIOCGIWAP */ - (iw_handler) NULL, /* SIOCSIWMLME */ - (iw_handler) NULL, /* SIOCGIWAPLIST */ - (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ - (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */ - (iw_handler) cfg80211_wext_siwessid, /* SIOCSIWESSID */ - (iw_handler) cfg80211_wext_giwessid, /* SIOCGIWESSID */ - (iw_handler) NULL, /* SIOCSIWNICKN */ - (iw_handler) NULL, /* SIOCGIWNICKN */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* SIOCSIWRATE */ - (iw_handler) cfg80211_wext_giwrate, /* SIOCGIWRATE */ - (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */ - (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ - (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ - (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */ - (iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */ - (iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */ - (iw_handler) NULL, /* SIOCSIWRETRY */ - (iw_handler) NULL, /* SIOCGIWRETRY */ - (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ - (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */ - (iw_handler) cfg80211_wext_siwpower, /* SIOCSIWPOWER */ - (iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */ - (iw_handler) NULL, /* SIOCGIWGENIE */ - (iw_handler) cfg80211_wext_siwauth, /* SIOCSIWAUTH */ - (iw_handler) cfg80211_wext_giwauth, /* SIOCGIWAUTH */ - (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */ - (iw_handler) NULL, /* SIOCGIWENCODEEXT */ - (iw_handler) NULL, /* SIOCSIWPMKSA */ - (iw_handler) NULL, /* -- hole -- */ -}; - -const struct iw_handler_def iwm_iw_handler_def = { - .num_standard = ARRAY_SIZE(iwm_handlers), - .standard = (iw_handler *) iwm_handlers, - .get_wireless_stats = cfg80211_wireless_stats, -}; - -- cgit v1.2.3-18-g5258 From 35a1e70dfe74aafa350325f79687153b9852c3f1 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 08:30:00 -0700 Subject: ath9k: remove unused ATH_PCI_VERSION Our version goes by the kernel release. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 87f99718393..75ddb2acb64 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -17,8 +17,6 @@ #include #include "ath9k.h" -#define ATH_PCI_VERSION "0.1" - static char *dev_info = "ath9k"; MODULE_AUTHOR("Atheros Communications"); -- cgit v1.2.3-18-g5258 From 1e4247d457c6a42e4a05cb7dfa4e6ea1fa65c112 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Mon, 27 Jul 2009 13:50:15 -0700 Subject: iwlwifi: debugFs to enable/disable HT40 support Add debugfs file to enable/disable HT40(40MHz) channel support. By default, 40MHz is supported if AP can support the function. By echo "1" to "disable_ht40" file, iwlwifi driver will disable the 40MHz support and only allow 20MHz channel. Because the information exchange happen during association time, so enable/disable ht40 channel only can be performed when it is not associated with AP. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 4 +++ drivers/net/wireless/iwlwifi/iwl-debug.h | 1 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 46 ++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-dev.h | 1 + 4 files changed, 52 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index aafa9fdd647..8570d56b312 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -632,6 +632,10 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, if (!sta_ht_inf->ht_supported) return 0; } +#ifdef CONFIG_IWLWIFI_DEBUG + if (priv->disable_ht40) + return 0; +#endif return iwl_is_channel_extension(priv, priv->band, le16_to_cpu(priv->staging_rxon.channel), iwl_ht_conf->extension_chan_offset); diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 609a68184db..fbe177608bc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -88,6 +88,7 @@ struct iwl_debugfs { #ifdef CONFIG_IWLWIFI_LEDS struct dentry *file_led; #endif + struct dentry *file_disable_ht40; } dbgfs_data_files; struct dir_rf_files { struct dentry *file_disable_sensitivity; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 748dc31877b..7707a265599 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -653,6 +653,49 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file, return ret; } +static ssize_t iwl_dbgfs_disable_ht40_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[8]; + int buf_size; + int ht40; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%d", &ht40) != 1) + return -EFAULT; + if (!iwl_is_associated(priv)) + priv->disable_ht40 = ht40 ? true : false; + else { + IWL_ERR(priv, "Sta associated with AP - " + "Change to 40MHz channel support is not allowed\n"); + return -EINVAL; + } + + return count; +} + +static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + char buf[100]; + int pos = 0; + const size_t bufsz = sizeof(buf); + ssize_t ret; + + pos += scnprintf(buf + pos, bufsz - pos, + "11n 40MHz Mode: %s\n", + priv->disable_ht40 ? "Disabled" : "Enabled"); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + return ret; +} + DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_WRITE_FILE_OPS(log_event); DEBUGFS_READ_FILE_OPS(nvm); @@ -667,6 +710,7 @@ DEBUGFS_READ_FILE_OPS(qos); DEBUGFS_READ_FILE_OPS(led); #endif DEBUGFS_READ_FILE_OPS(thermal_throttling); +DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40); /* * Create the debugfs files and directories @@ -708,6 +752,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(led, data); #endif DEBUGFS_ADD_FILE(thermal_throttling, data); + DEBUGFS_ADD_FILE(disable_ht40, data); DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); @@ -747,6 +792,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led); #endif DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_ht40); DEBUGFS_REMOVE(priv->dbgfs->dir_data); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index facbc3daf55..0ee3ad24569 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1164,6 +1164,7 @@ struct iwl_priv { /* debugging info */ u32 framecnt_to_us; atomic_t restrict_refcnt; + bool disable_ht40; #ifdef CONFIG_IWLWIFI_DEBUGFS /* debugfs */ struct iwl_debugfs *dbgfs; -- cgit v1.2.3-18-g5258 From 044824d96208c8ec4863f9c54a529e00a1f1d37c Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Tue, 28 Jul 2009 09:10:03 +0000 Subject: netxen: fix CONFIG_INET=n build Wrap dest IP hashing code with #ifdef CONFIG_INET, this feature makes no sense without INET, but other driver can still work. Signed-off-by: Dhananjay Phadke Acked-by: Randy Dunlap Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_main.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 2bbefa6a37b..40549a0e9ff 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1875,6 +1875,8 @@ static void netxen_nic_poll_controller(struct net_device *netdev) } #endif +#ifdef CONFIG_INET + #define is_netxen_netdev(dev) (dev->netdev_ops == &netxen_netdev_ops) static int @@ -1993,6 +1995,7 @@ static struct notifier_block netxen_netdev_cb = { static struct notifier_block netxen_inetaddr_cb = { .notifier_call = netxen_inetaddr_event, }; +#endif static struct pci_driver netxen_driver = { .name = netxen_nic_driver_name, @@ -2012,8 +2015,10 @@ static int __init netxen_init_module(void) if ((netxen_workq = create_singlethread_workqueue("netxen")) == NULL) return -ENOMEM; +#ifdef CONFIG_INET register_netdevice_notifier(&netxen_netdev_cb); register_inetaddr_notifier(&netxen_inetaddr_cb); +#endif return pci_register_driver(&netxen_driver); } @@ -2024,8 +2029,10 @@ static void __exit netxen_exit_module(void) { pci_unregister_driver(&netxen_driver); +#ifdef CONFIG_INET unregister_inetaddr_notifier(&netxen_inetaddr_cb); unregister_netdevice_notifier(&netxen_netdev_cb); +#endif destroy_workqueue(netxen_workq); } -- cgit v1.2.3-18-g5258 From ef12379f205bed7e92434e12ddd44e62d13bebe1 Mon Sep 17 00:00:00 2001 From: Hartley Sweeten Date: Wed, 29 Jul 2009 22:41:06 +0100 Subject: ARM: 5628/1: ep93xx: Introduce Pulse Width Modulator (PWM) driver The EP93xx features two PWMs (one on the EP9307) with the following features: * Configurable dual output * Separate input clocks for each PWM output * 16-bit resolution * Programmable pulse width (duty cycle), interval (frequency), and polarity This adds the necessary core support as well as the driver. A sysfs interface is provided to control the PWM outputs. Signed-off-by: Matthieu Crapet Signed-off-by: H Hartley Sweeten Acked-by: Ryan Mallon Signed-off-by: Russell King --- drivers/misc/Kconfig | 13 ++ drivers/misc/Makefile | 1 + drivers/misc/ep93xx_pwm.c | 384 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 398 insertions(+) create mode 100644 drivers/misc/ep93xx_pwm.c (limited to 'drivers') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 68ab39d7cb3..df1f86b5c83 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -233,6 +233,19 @@ config ISL29003 This driver can also be built as a module. If so, the module will be called isl29003. +config EP93XX_PWM + tristate "EP93xx PWM support" + depends on ARCH_EP93XX + help + This option enables device driver support for the PWM channels + on the Cirrus EP93xx processors. The EP9307 chip only has one + PWM channel all the others have two, the second channel is an + alternate function of the EGPIO14 pin. A sysfs interface is + provided to control the PWM channels. + + To compile this driver as a module, choose M here: the module will + be called ep93xx_pwm. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 36f733cd60e..f982d2ecfde 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_SGI_XP) += sgi-xp/ obj-$(CONFIG_SGI_GRU) += sgi-gru/ obj-$(CONFIG_HP_ILO) += hpilo.o obj-$(CONFIG_ISL29003) += isl29003.o +obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o obj-$(CONFIG_C2PORT) += c2port/ obj-y += eeprom/ obj-y += cb710/ diff --git a/drivers/misc/ep93xx_pwm.c b/drivers/misc/ep93xx_pwm.c new file mode 100644 index 00000000000..ba4694169d7 --- /dev/null +++ b/drivers/misc/ep93xx_pwm.c @@ -0,0 +1,384 @@ +/* + * Simple PWM driver for EP93XX + * + * (c) Copyright 2009 Matthieu Crapet + * (c) Copyright 2009 H Hartley Sweeten + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * EP9307 has only one channel: + * - PWMOUT + * + * EP9301/02/12/15 have two channels: + * - PWMOUT + * - PWMOUT1 (alternate function for EGPIO14) + */ + +#include +#include +#include +#include +#include + +#include + +#define EP93XX_PWMx_TERM_COUNT 0x00 +#define EP93XX_PWMx_DUTY_CYCLE 0x04 +#define EP93XX_PWMx_ENABLE 0x08 +#define EP93XX_PWMx_INVERT 0x0C + +#define EP93XX_PWM_MAX_COUNT 0xFFFF + +struct ep93xx_pwm { + void __iomem *mmio_base; + struct clk *clk; + u32 duty_percent; +}; + +static inline void ep93xx_pwm_writel(struct ep93xx_pwm *pwm, + unsigned int val, unsigned int off) +{ + __raw_writel(val, pwm->mmio_base + off); +} + +static inline unsigned int ep93xx_pwm_readl(struct ep93xx_pwm *pwm, + unsigned int off) +{ + return __raw_readl(pwm->mmio_base + off); +} + +static inline void ep93xx_pwm_write_tc(struct ep93xx_pwm *pwm, u16 value) +{ + ep93xx_pwm_writel(pwm, value, EP93XX_PWMx_TERM_COUNT); +} + +static inline u16 ep93xx_pwm_read_tc(struct ep93xx_pwm *pwm) +{ + return ep93xx_pwm_readl(pwm, EP93XX_PWMx_TERM_COUNT); +} + +static inline void ep93xx_pwm_write_dc(struct ep93xx_pwm *pwm, u16 value) +{ + ep93xx_pwm_writel(pwm, value, EP93XX_PWMx_DUTY_CYCLE); +} + +static inline void ep93xx_pwm_enable(struct ep93xx_pwm *pwm) +{ + ep93xx_pwm_writel(pwm, 0x1, EP93XX_PWMx_ENABLE); +} + +static inline void ep93xx_pwm_disable(struct ep93xx_pwm *pwm) +{ + ep93xx_pwm_writel(pwm, 0x0, EP93XX_PWMx_ENABLE); +} + +static inline int ep93xx_pwm_is_enabled(struct ep93xx_pwm *pwm) +{ + return ep93xx_pwm_readl(pwm, EP93XX_PWMx_ENABLE) & 0x1; +} + +static inline void ep93xx_pwm_invert(struct ep93xx_pwm *pwm) +{ + ep93xx_pwm_writel(pwm, 0x1, EP93XX_PWMx_INVERT); +} + +static inline void ep93xx_pwm_normal(struct ep93xx_pwm *pwm) +{ + ep93xx_pwm_writel(pwm, 0x0, EP93XX_PWMx_INVERT); +} + +static inline int ep93xx_pwm_is_inverted(struct ep93xx_pwm *pwm) +{ + return ep93xx_pwm_readl(pwm, EP93XX_PWMx_INVERT) & 0x1; +} + +/* + * /sys/devices/platform/ep93xx-pwm.N + * /min_freq read-only minimum pwm output frequency + * /max_req read-only maximum pwm output frequency + * /freq read-write pwm output frequency (0 = disable output) + * /duty_percent read-write pwm duty cycle percent (1..99) + * /invert read-write invert pwm output + */ + +static ssize_t ep93xx_pwm_get_min_freq(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ep93xx_pwm *pwm = platform_get_drvdata(pdev); + unsigned long rate = clk_get_rate(pwm->clk); + + return sprintf(buf, "%ld\n", rate / (EP93XX_PWM_MAX_COUNT + 1)); +} + +static ssize_t ep93xx_pwm_get_max_freq(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ep93xx_pwm *pwm = platform_get_drvdata(pdev); + unsigned long rate = clk_get_rate(pwm->clk); + + return sprintf(buf, "%ld\n", rate / 2); +} + +static ssize_t ep93xx_pwm_get_freq(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ep93xx_pwm *pwm = platform_get_drvdata(pdev); + + if (ep93xx_pwm_is_enabled(pwm)) { + unsigned long rate = clk_get_rate(pwm->clk); + u16 term = ep93xx_pwm_read_tc(pwm); + + return sprintf(buf, "%ld\n", rate / (term + 1)); + } else { + return sprintf(buf, "disabled\n"); + } +} + +static ssize_t ep93xx_pwm_set_freq(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ep93xx_pwm *pwm = platform_get_drvdata(pdev); + long val; + int err; + + err = strict_strtol(buf, 10, &val); + if (err) + return -EINVAL; + + if (val == 0) { + ep93xx_pwm_disable(pwm); + } else if (val <= (clk_get_rate(pwm->clk) / 2)) { + u32 term, duty; + + val = (clk_get_rate(pwm->clk) / val) - 1; + if (val > EP93XX_PWM_MAX_COUNT) + val = EP93XX_PWM_MAX_COUNT; + if (val < 1) + val = 1; + + term = ep93xx_pwm_read_tc(pwm); + duty = ((val + 1) * pwm->duty_percent / 100) - 1; + + /* If pwm is running, order is important */ + if (val > term) { + ep93xx_pwm_write_tc(pwm, val); + ep93xx_pwm_write_dc(pwm, duty); + } else { + ep93xx_pwm_write_dc(pwm, duty); + ep93xx_pwm_write_tc(pwm, val); + } + + if (!ep93xx_pwm_is_enabled(pwm)) + ep93xx_pwm_enable(pwm); + } else { + return -EINVAL; + } + + return count; +} + +static ssize_t ep93xx_pwm_get_duty_percent(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ep93xx_pwm *pwm = platform_get_drvdata(pdev); + + return sprintf(buf, "%d\n", pwm->duty_percent); +} + +static ssize_t ep93xx_pwm_set_duty_percent(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ep93xx_pwm *pwm = platform_get_drvdata(pdev); + long val; + int err; + + err = strict_strtol(buf, 10, &val); + if (err) + return -EINVAL; + + if (val > 0 && val < 100) { + u32 term = ep93xx_pwm_read_tc(pwm); + ep93xx_pwm_write_dc(pwm, ((term + 1) * val / 100) - 1); + pwm->duty_percent = val; + return count; + } + + return -EINVAL; +} + +static ssize_t ep93xx_pwm_get_invert(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ep93xx_pwm *pwm = platform_get_drvdata(pdev); + + return sprintf(buf, "%d\n", ep93xx_pwm_is_inverted(pwm)); +} + +static ssize_t ep93xx_pwm_set_invert(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ep93xx_pwm *pwm = platform_get_drvdata(pdev); + long val; + int err; + + err = strict_strtol(buf, 10, &val); + if (err) + return -EINVAL; + + if (val == 0) + ep93xx_pwm_normal(pwm); + else if (val == 1) + ep93xx_pwm_invert(pwm); + else + return -EINVAL; + + return count; +} + +static DEVICE_ATTR(min_freq, S_IRUGO, ep93xx_pwm_get_min_freq, NULL); +static DEVICE_ATTR(max_freq, S_IRUGO, ep93xx_pwm_get_max_freq, NULL); +static DEVICE_ATTR(freq, S_IWUGO | S_IRUGO, + ep93xx_pwm_get_freq, ep93xx_pwm_set_freq); +static DEVICE_ATTR(duty_percent, S_IWUGO | S_IRUGO, + ep93xx_pwm_get_duty_percent, ep93xx_pwm_set_duty_percent); +static DEVICE_ATTR(invert, S_IWUGO | S_IRUGO, + ep93xx_pwm_get_invert, ep93xx_pwm_set_invert); + +static struct attribute *ep93xx_pwm_attrs[] = { + &dev_attr_min_freq.attr, + &dev_attr_max_freq.attr, + &dev_attr_freq.attr, + &dev_attr_duty_percent.attr, + &dev_attr_invert.attr, + NULL +}; + +static const struct attribute_group ep93xx_pwm_sysfs_files = { + .attrs = ep93xx_pwm_attrs, +}; + +static int __init ep93xx_pwm_probe(struct platform_device *pdev) +{ + struct ep93xx_pwm *pwm; + struct resource *res; + int err; + + err = ep93xx_pwm_acquire_gpio(pdev); + if (err) + return err; + + pwm = kzalloc(sizeof(struct ep93xx_pwm), GFP_KERNEL); + if (!pwm) { + err = -ENOMEM; + goto fail_no_mem; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + err = -ENXIO; + goto fail_no_mem_resource; + } + + res = request_mem_region(res->start, resource_size(res), pdev->name); + if (res == NULL) { + err = -EBUSY; + goto fail_no_mem_resource; + } + + pwm->mmio_base = ioremap(res->start, resource_size(res)); + if (pwm->mmio_base == NULL) { + err = -ENXIO; + goto fail_no_ioremap; + } + + err = sysfs_create_group(&pdev->dev.kobj, &ep93xx_pwm_sysfs_files); + if (err) + goto fail_no_sysfs; + + pwm->clk = clk_get(&pdev->dev, "pwm_clk"); + if (IS_ERR(pwm->clk)) { + err = PTR_ERR(pwm->clk); + goto fail_no_clk; + } + + pwm->duty_percent = 50; + + platform_set_drvdata(pdev, pwm); + + /* disable pwm at startup. Avoids zero value. */ + ep93xx_pwm_disable(pwm); + ep93xx_pwm_write_tc(pwm, EP93XX_PWM_MAX_COUNT); + ep93xx_pwm_write_dc(pwm, EP93XX_PWM_MAX_COUNT / 2); + + clk_enable(pwm->clk); + + return 0; + +fail_no_clk: + sysfs_remove_group(&pdev->dev.kobj, &ep93xx_pwm_sysfs_files); +fail_no_sysfs: + iounmap(pwm->mmio_base); +fail_no_ioremap: + release_mem_region(res->start, resource_size(res)); +fail_no_mem_resource: + kfree(pwm); +fail_no_mem: + ep93xx_pwm_release_gpio(pdev); + return err; +} + +static int __exit ep93xx_pwm_remove(struct platform_device *pdev) +{ + struct ep93xx_pwm *pwm = platform_get_drvdata(pdev); + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + ep93xx_pwm_disable(pwm); + clk_disable(pwm->clk); + clk_put(pwm->clk); + platform_set_drvdata(pdev, NULL); + sysfs_remove_group(&pdev->dev.kobj, &ep93xx_pwm_sysfs_files); + iounmap(pwm->mmio_base); + release_mem_region(res->start, resource_size(res)); + kfree(pwm); + ep93xx_pwm_release_gpio(pdev); + + return 0; +} + +static struct platform_driver ep93xx_pwm_driver = { + .driver = { + .name = "ep93xx-pwm", + .owner = THIS_MODULE, + }, + .remove = __exit_p(ep93xx_pwm_remove), +}; + +static int __init ep93xx_pwm_init(void) +{ + return platform_driver_probe(&ep93xx_pwm_driver, ep93xx_pwm_probe); +} + +static void __exit ep93xx_pwm_exit(void) +{ + platform_driver_unregister(&ep93xx_pwm_driver); +} + +module_init(ep93xx_pwm_init); +module_exit(ep93xx_pwm_exit); + +MODULE_AUTHOR("Matthieu Crapet , " + "H Hartley Sweeten "); +MODULE_DESCRIPTION("EP93xx PWM driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ep93xx-pwm"); -- cgit v1.2.3-18-g5258 From 581ce43d269bb9f9ea85d8f6e6acf68bad129740 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 29 Jul 2009 00:20:04 +0000 Subject: bnx2x: Receive traffic that maches management filtering rules Due to lack of configuration, if the BMC configures the chip to pass all broadcast/multicast traffic to it, the host will not receive it. On top of fixing it, also make sure that in promiscuous mode, the host will receive the management traffic as well. Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 13 +++++++++++++ drivers/net/bnx2x_reg.h | 5 +++++ 2 files changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index a2de0cd9c9f..5273988359e 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -4831,7 +4831,14 @@ static void bnx2x_set_storm_rx_mode(struct bnx2x *bp) int mode = bp->rx_mode; int mask = (1 << BP_L_ID(bp)); int func = BP_FUNC(bp); + int port = BP_PORT(bp); int i; + /* All but management unicast packets should pass to the host as well */ + u32 llh_mask = + NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_BRCST | + NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_MLCST | + NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_VLAN | + NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_NO_VLAN; DP(NETIF_MSG_IFUP, "rx mode %d mask 0x%x\n", mode, mask); @@ -4855,6 +4862,8 @@ static void bnx2x_set_storm_rx_mode(struct bnx2x *bp) tstorm_mac_filter.ucast_accept_all = mask; tstorm_mac_filter.mcast_accept_all = mask; tstorm_mac_filter.bcast_accept_all = mask; + /* pass management unicast packets as well */ + llh_mask |= NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST; break; default: @@ -4862,6 +4871,10 @@ static void bnx2x_set_storm_rx_mode(struct bnx2x *bp) break; } + REG_WR(bp, + (port ? NIG_REG_LLH1_BRB1_DRV_MASK : NIG_REG_LLH0_BRB1_DRV_MASK), + llh_mask); + for (i = 0; i < sizeof(struct tstorm_eth_mac_filter_config)/4; i++) { REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_MAC_FILTER_CONFIG_OFFSET(func) + i * 4, diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h index d771168ec20..8e9e7a24f2f 100644 --- a/drivers/net/bnx2x_reg.h +++ b/drivers/net/bnx2x_reg.h @@ -1616,6 +1616,11 @@ /* [RW 1] Set by the MCP to remember if one or more of the drivers is/are loaded; 0-prepare; -unprepare */ #define MISC_REG_UNPREPARED 0xa424 +#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_BRCST (0x1<<0) +#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_MLCST (0x1<<1) +#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_NO_VLAN (0x1<<4) +#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST (0x1<<2) +#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_VLAN (0x1<<3) #define NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT (0x1<<0) #define NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS (0x1<<9) #define NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G (0x1<<15) -- cgit v1.2.3-18-g5258 From c1f1a06f926acc267c62a26d5d7435a3b5c7e429 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 29 Jul 2009 00:20:08 +0000 Subject: bnx2x: Self-test kills management traffic Self test used to play with the management FIFO possibly while management was running... Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 5273988359e..b47b5311549 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -9415,10 +9415,9 @@ static int bnx2x_test_registers(struct bnx2x *bp) { XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 4, 0x00000001 }, { XCM_REG_WU_DA_CNT_CMD00, 4, 0x00000003 }, { XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 4, 0x000000ff }, - { NIG_REG_EGRESS_MNG0_FIFO, 20, 0xffffffff }, { NIG_REG_LLH0_T_BIT, 4, 0x00000001 }, -/* 20 */ { NIG_REG_EMAC0_IN_EN, 4, 0x00000001 }, - { NIG_REG_BMAC0_IN_EN, 4, 0x00000001 }, + { NIG_REG_EMAC0_IN_EN, 4, 0x00000001 }, +/* 20 */ { NIG_REG_BMAC0_IN_EN, 4, 0x00000001 }, { NIG_REG_XCM0_OUT_EN, 4, 0x00000001 }, { NIG_REG_BRB0_OUT_EN, 4, 0x00000001 }, { NIG_REG_LLH0_XCM_MASK, 4, 0x00000007 }, @@ -9427,8 +9426,8 @@ static int bnx2x_test_registers(struct bnx2x *bp) { NIG_REG_LLH0_DEST_MAC_0_0, 160, 0xffffffff }, { NIG_REG_LLH0_DEST_IP_0_1, 160, 0xffffffff }, { NIG_REG_LLH0_IPV4_IPV6_0, 160, 0x00000001 }, -/* 30 */ { NIG_REG_LLH0_DEST_UDP_0, 160, 0x0000ffff }, - { NIG_REG_LLH0_DEST_TCP_0, 160, 0x0000ffff }, + { NIG_REG_LLH0_DEST_UDP_0, 160, 0x0000ffff }, +/* 30 */ { NIG_REG_LLH0_DEST_TCP_0, 160, 0x0000ffff }, { NIG_REG_LLH0_VLAN_ID_0, 160, 0x00000fff }, { NIG_REG_XGXS_SERDES0_MODE_SEL, 4, 0x00000001 }, { NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0, 4, 0x00000001 }, -- cgit v1.2.3-18-g5258 From 7d0446c2349da54f2967fb34d984db572fbfc6ac Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 29 Jul 2009 00:20:10 +0000 Subject: bnx2x: WoL only with current MAC address In some cases with 57711E, depending on the functions unload sequence, other functions MAC address could have been used to wake the system as well. Make sure to block all but the current function if WoL is required by changing the mode to single function WoL. Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index b47b5311549..424541239f5 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -7354,17 +7354,17 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode) for (i = 0; i < MC_HASH_SIZE; i++) REG_WR(bp, MC_HASH_OFFSET(bp, i), 0); + + REG_WR(bp, MISC_REG_E1HMF_MODE, 0); } if (unload_mode == UNLOAD_NORMAL) reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS; - else if (bp->flags & NO_WOL_FLAG) { + else if (bp->flags & NO_WOL_FLAG) reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP; - if (CHIP_IS_E1H(bp)) - REG_WR(bp, MISC_REG_E1HMF_MODE, 0); - } else if (bp->wol) { + else if (bp->wol) { u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; u8 *mac_addr = bp->dev->dev_addr; u32 val; -- cgit v1.2.3-18-g5258 From 573dd788ccd919f90c78f971c0da124ffa4b8bff Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 29 Jul 2009 00:20:11 +0000 Subject: bnx2x: Version 1.48.114-1 Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 424541239f5..2d035d795f0 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -56,8 +56,8 @@ #include "bnx2x_init_ops.h" #include "bnx2x_dump.h" -#define DRV_MODULE_VERSION "1.48.113-1" -#define DRV_MODULE_RELDATE "2009/07/21" +#define DRV_MODULE_VERSION "1.48.114-1" +#define DRV_MODULE_RELDATE "2009/07/29" #define BNX2X_BC_VER 0x040200 #include -- cgit v1.2.3-18-g5258 From 8788fdc2a53cf012a43808877eaa6ac7e3c923b4 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 27 Jul 2009 22:52:03 +0000 Subject: be2net: get rid of be_ctrl_info struct/abstraction Currently only the be_ctrl_info struct ptr (instead of adapter) is passed to all the routines in be_cmds.c. Instead pass be_adapter ptr to allow access to all its fields. Merge the contents of struct be_ctrl_info into be_adapter. The resulting code is simpler. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/benet/be.h | 47 +++---- drivers/net/benet/be_cmds.c | 293 +++++++++++++++++++++-------------------- drivers/net/benet/be_cmds.h | 51 ++++--- drivers/net/benet/be_ethtool.c | 12 +- drivers/net/benet/be_main.c | 229 +++++++++++++++----------------- 5 files changed, 299 insertions(+), 333 deletions(-) (limited to 'drivers') diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 41cddbedbf2..d8a157f8caf 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -71,6 +71,8 @@ static inline char *nic_name(struct pci_dev *pdev) #define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */ #define RX_FRAGS_REFILL_WM (RX_Q_LEN - MAX_RX_POST) +#define FW_VER_LEN 32 + struct be_dma_mem { void *va; dma_addr_t dma; @@ -123,7 +125,6 @@ static inline void queue_tail_inc(struct be_queue_info *q) index_inc(&q->tail, q->len); } - struct be_eq_obj { struct be_queue_info q; char desc[32]; @@ -142,31 +143,6 @@ struct be_mcc_obj { struct be_queue_info cq; }; -struct be_ctrl_info { - u8 __iomem *csr; - u8 __iomem *db; /* Door Bell */ - u8 __iomem *pcicfg; /* PCI config space */ - int pci_func; - - /* Mbox used for cmd request/response */ - spinlock_t mbox_lock; /* For serializing mbox cmds to BE card */ - struct be_dma_mem mbox_mem; - /* Mbox mem is adjusted to align to 16 bytes. The allocated addr - * is stored for freeing purpose */ - struct be_dma_mem mbox_mem_alloced; - - /* MCC Rings */ - struct be_mcc_obj mcc_obj; - spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */ - spinlock_t mcc_cq_lock; - - /* MCC Async callback */ - void (*async_cb)(void *adapter, bool link_up); - void *adapter_ctxt; -}; - -#include "be_cmds.h" - struct be_drvr_stats { u32 be_tx_reqs; /* number of TX requests initiated */ u32 be_tx_stops; /* number of times TX Q was stopped */ @@ -234,8 +210,20 @@ struct be_adapter { struct pci_dev *pdev; struct net_device *netdev; - /* Mbox, pci config, csr address information */ - struct be_ctrl_info ctrl; + u8 __iomem *csr; + u8 __iomem *db; /* Door Bell */ + u8 __iomem *pcicfg; /* PCI config space */ + int pci_func; + + spinlock_t mbox_lock; /* For serializing mbox cmds to BE card */ + struct be_dma_mem mbox_mem; + /* Mbox mem is adjusted to align to 16 bytes. The allocated addr + * is stored for freeing purpose */ + struct be_dma_mem mbox_mem_alloced; + + struct be_mcc_obj mcc_obj; + spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */ + spinlock_t mcc_cq_lock; struct msix_entry msix_entries[BE_NUM_MSIX_VECTORS]; bool msix_enabled; @@ -366,6 +354,7 @@ static inline u8 is_udp_pkt(struct sk_buff *skb) return val; } -extern void be_cq_notify(struct be_ctrl_info *ctrl, u16 qid, bool arm, +extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped); +extern void be_link_status_update(struct be_adapter *adapter, bool link_up); #endif /* BE_H */ diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 583517ed56f..20278b9d5ed 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -16,15 +16,16 @@ */ #include "be.h" +#include "be_cmds.h" -static void be_mcc_notify(struct be_ctrl_info *ctrl) +static void be_mcc_notify(struct be_adapter *adapter) { - struct be_queue_info *mccq = &ctrl->mcc_obj.q; + struct be_queue_info *mccq = &adapter->mcc_obj.q; u32 val = 0; val |= mccq->id & DB_MCCQ_RING_ID_MASK; val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT; - iowrite32(val, ctrl->db + DB_MCCQ_OFFSET); + iowrite32(val, adapter->db + DB_MCCQ_OFFSET); } /* To check if valid bit is set, check the entire word as we don't know @@ -47,7 +48,7 @@ static inline void be_mcc_compl_use(struct be_mcc_cq_entry *compl) compl->flags = 0; } -static int be_mcc_compl_process(struct be_ctrl_info *ctrl, +static int be_mcc_compl_process(struct be_adapter *adapter, struct be_mcc_cq_entry *compl) { u16 compl_status, extd_status; @@ -70,11 +71,11 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl, } /* Link state evt is a string of bytes; no need for endian swapping */ -static void be_async_link_state_process(struct be_ctrl_info *ctrl, +static void be_async_link_state_process(struct be_adapter *adapter, struct be_async_event_link_state *evt) { - ctrl->async_cb(ctrl->adapter_ctxt, - evt->port_link_status == ASYNC_EVENT_LINK_UP ? true : false); + be_link_status_update(adapter, + evt->port_link_status == ASYNC_EVENT_LINK_UP); } static inline bool is_link_state_evt(u32 trailer) @@ -84,9 +85,9 @@ static inline bool is_link_state_evt(u32 trailer) ASYNC_EVENT_CODE_LINK_STATE); } -static struct be_mcc_cq_entry *be_mcc_compl_get(struct be_ctrl_info *ctrl) +static struct be_mcc_cq_entry *be_mcc_compl_get(struct be_adapter *adapter) { - struct be_queue_info *mcc_cq = &ctrl->mcc_obj.cq; + struct be_queue_info *mcc_cq = &adapter->mcc_obj.cq; struct be_mcc_cq_entry *compl = queue_tail_node(mcc_cq); if (be_mcc_compl_is_new(compl)) { @@ -96,40 +97,40 @@ static struct be_mcc_cq_entry *be_mcc_compl_get(struct be_ctrl_info *ctrl) return NULL; } -void be_process_mcc(struct be_ctrl_info *ctrl) +void be_process_mcc(struct be_adapter *adapter) { struct be_mcc_cq_entry *compl; int num = 0; - spin_lock_bh(&ctrl->mcc_cq_lock); - while ((compl = be_mcc_compl_get(ctrl))) { + spin_lock_bh(&adapter->mcc_cq_lock); + while ((compl = be_mcc_compl_get(adapter))) { if (compl->flags & CQE_FLAGS_ASYNC_MASK) { /* Interpret flags as an async trailer */ BUG_ON(!is_link_state_evt(compl->flags)); /* Interpret compl as a async link evt */ - be_async_link_state_process(ctrl, + be_async_link_state_process(adapter, (struct be_async_event_link_state *) compl); } else { - be_mcc_compl_process(ctrl, compl); - atomic_dec(&ctrl->mcc_obj.q.used); + be_mcc_compl_process(adapter, compl); + atomic_dec(&adapter->mcc_obj.q.used); } be_mcc_compl_use(compl); num++; } if (num) - be_cq_notify(ctrl, ctrl->mcc_obj.cq.id, true, num); - spin_unlock_bh(&ctrl->mcc_cq_lock); + be_cq_notify(adapter, adapter->mcc_obj.cq.id, true, num); + spin_unlock_bh(&adapter->mcc_cq_lock); } /* Wait till no more pending mcc requests are present */ -static void be_mcc_wait_compl(struct be_ctrl_info *ctrl) +static void be_mcc_wait_compl(struct be_adapter *adapter) { #define mcc_timeout 50000 /* 5s timeout */ int i; for (i = 0; i < mcc_timeout; i++) { - be_process_mcc(ctrl); - if (atomic_read(&ctrl->mcc_obj.q.used) == 0) + be_process_mcc(adapter); + if (atomic_read(&adapter->mcc_obj.q.used) == 0) break; udelay(100); } @@ -138,10 +139,10 @@ static void be_mcc_wait_compl(struct be_ctrl_info *ctrl) } /* Notify MCC requests and wait for completion */ -static void be_mcc_notify_wait(struct be_ctrl_info *ctrl) +static void be_mcc_notify_wait(struct be_adapter *adapter) { - be_mcc_notify(ctrl); - be_mcc_wait_compl(ctrl); + be_mcc_notify(adapter); + be_mcc_wait_compl(adapter); } static int be_mbox_db_ready_wait(void __iomem *db) @@ -173,12 +174,12 @@ static int be_mbox_db_ready_wait(void __iomem *db) * Insert the mailbox address into the doorbell in two steps * Polls on the mbox doorbell till a command completion (or a timeout) occurs */ -static int be_mbox_db_ring(struct be_ctrl_info *ctrl) +static int be_mbox_db_ring(struct be_adapter *adapter) { int status; u32 val = 0; - void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET; - struct be_dma_mem *mbox_mem = &ctrl->mbox_mem; + void __iomem *db = adapter->db + MPU_MAILBOX_DB_OFFSET; + struct be_dma_mem *mbox_mem = &adapter->mbox_mem; struct be_mcc_mailbox *mbox = mbox_mem->va; struct be_mcc_cq_entry *cqe = &mbox->cqe; @@ -208,7 +209,7 @@ static int be_mbox_db_ring(struct be_ctrl_info *ctrl) /* A cq entry has been made now */ if (be_mcc_compl_is_new(cqe)) { - status = be_mcc_compl_process(ctrl, &mbox->cqe); + status = be_mcc_compl_process(adapter, &mbox->cqe); be_mcc_compl_use(cqe); if (status) return status; @@ -219,9 +220,9 @@ static int be_mbox_db_ring(struct be_ctrl_info *ctrl) return 0; } -static int be_POST_stage_get(struct be_ctrl_info *ctrl, u16 *stage) +static int be_POST_stage_get(struct be_adapter *adapter, u16 *stage) { - u32 sem = ioread32(ctrl->csr + MPU_EP_SEMAPHORE_OFFSET); + u32 sem = ioread32(adapter->csr + MPU_EP_SEMAPHORE_OFFSET); *stage = sem & EP_SEMAPHORE_POST_STAGE_MASK; if ((sem >> EP_SEMAPHORE_POST_ERR_SHIFT) & EP_SEMAPHORE_POST_ERR_MASK) @@ -230,11 +231,11 @@ static int be_POST_stage_get(struct be_ctrl_info *ctrl, u16 *stage) return 0; } -static int be_POST_stage_poll(struct be_ctrl_info *ctrl, u16 poll_stage) +static int be_POST_stage_poll(struct be_adapter *adapter, u16 poll_stage) { u16 stage, cnt, error; for (cnt = 0; cnt < 5000; cnt++) { - error = be_POST_stage_get(ctrl, &stage); + error = be_POST_stage_get(adapter, &stage); if (error) return -1; @@ -248,11 +249,11 @@ static int be_POST_stage_poll(struct be_ctrl_info *ctrl, u16 poll_stage) } -int be_cmd_POST(struct be_ctrl_info *ctrl) +int be_cmd_POST(struct be_adapter *adapter) { u16 stage, error; - error = be_POST_stage_get(ctrl, &stage); + error = be_POST_stage_get(adapter, &stage); if (error) goto err; @@ -263,14 +264,14 @@ int be_cmd_POST(struct be_ctrl_info *ctrl) goto err; /* On awaiting host rdy, reset and again poll on awaiting host rdy */ - iowrite32(POST_STAGE_BE_RESET, ctrl->csr + MPU_EP_SEMAPHORE_OFFSET); - error = be_POST_stage_poll(ctrl, POST_STAGE_AWAITING_HOST_RDY); + iowrite32(POST_STAGE_BE_RESET, adapter->csr + MPU_EP_SEMAPHORE_OFFSET); + error = be_POST_stage_poll(adapter, POST_STAGE_AWAITING_HOST_RDY); if (error) goto err; /* Now kickoff POST and poll on armfw ready */ - iowrite32(POST_STAGE_HOST_RDY, ctrl->csr + MPU_EP_SEMAPHORE_OFFSET); - error = be_POST_stage_poll(ctrl, POST_STAGE_ARMFW_RDY); + iowrite32(POST_STAGE_HOST_RDY, adapter->csr + MPU_EP_SEMAPHORE_OFFSET); + error = be_POST_stage_poll(adapter, POST_STAGE_ARMFW_RDY); if (error) goto err; @@ -367,16 +368,16 @@ static inline struct be_mcc_wrb *wrb_from_mcc(struct be_queue_info *mccq) return wrb; } -int be_cmd_eq_create(struct be_ctrl_info *ctrl, +int be_cmd_eq_create(struct be_adapter *adapter, struct be_queue_info *eq, int eq_delay) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_eq_create *req = embedded_payload(wrb); struct be_cmd_resp_eq_create *resp = embedded_payload(wrb); struct be_dma_mem *q_mem = &eq->dma_mem; int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -387,7 +388,7 @@ int be_cmd_eq_create(struct be_ctrl_info *ctrl, req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); AMAP_SET_BITS(struct amap_eq_context, func, req->context, - ctrl->pci_func); + adapter->pci_func); AMAP_SET_BITS(struct amap_eq_context, valid, req->context, 1); /* 4byte eqe*/ AMAP_SET_BITS(struct amap_eq_context, size, req->context, 0); @@ -399,24 +400,24 @@ int be_cmd_eq_create(struct be_ctrl_info *ctrl, be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { eq->id = le16_to_cpu(resp->eq_id); eq->created = true; } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_mac_addr_query(struct be_ctrl_info *ctrl, u8 *mac_addr, +int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, u8 type, bool permanent, u32 if_handle) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_mac_query *req = embedded_payload(wrb); struct be_cmd_resp_mac_query *resp = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -432,22 +433,22 @@ int be_cmd_mac_addr_query(struct be_ctrl_info *ctrl, u8 *mac_addr, req->permanent = 0; } - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) memcpy(mac_addr, resp->mac.addr, ETH_ALEN); - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_pmac_add(struct be_ctrl_info *ctrl, u8 *mac_addr, +int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, u32 if_id, u32 *pmac_id) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_pmac_add *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -458,23 +459,23 @@ int be_cmd_pmac_add(struct be_ctrl_info *ctrl, u8 *mac_addr, req->if_id = cpu_to_le32(if_id); memcpy(req->mac_address, mac_addr, ETH_ALEN); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { struct be_cmd_resp_pmac_add *resp = embedded_payload(wrb); *pmac_id = le32_to_cpu(resp->pmac_id); } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_pmac_del(struct be_ctrl_info *ctrl, u32 if_id, u32 pmac_id) +int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_pmac_del *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -485,24 +486,24 @@ int be_cmd_pmac_del(struct be_ctrl_info *ctrl, u32 if_id, u32 pmac_id) req->if_id = cpu_to_le32(if_id); req->pmac_id = cpu_to_le32(pmac_id); - status = be_mbox_db_ring(ctrl); - spin_unlock(&ctrl->mbox_lock); + status = be_mbox_db_ring(adapter); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_cq_create(struct be_ctrl_info *ctrl, +int be_cmd_cq_create(struct be_adapter *adapter, struct be_queue_info *cq, struct be_queue_info *eq, bool sol_evts, bool no_delay, int coalesce_wm) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_cq_create *req = embedded_payload(wrb); struct be_cmd_resp_cq_create *resp = embedded_payload(wrb); struct be_dma_mem *q_mem = &cq->dma_mem; void *ctxt = &req->context; int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -521,17 +522,17 @@ int be_cmd_cq_create(struct be_ctrl_info *ctrl, AMAP_SET_BITS(struct amap_cq_context, eventable, ctxt, 1); AMAP_SET_BITS(struct amap_cq_context, eqid, ctxt, eq->id); AMAP_SET_BITS(struct amap_cq_context, armed, ctxt, 1); - AMAP_SET_BITS(struct amap_cq_context, func, ctxt, ctrl->pci_func); + AMAP_SET_BITS(struct amap_cq_context, func, ctxt, adapter->pci_func); be_dws_cpu_to_le(ctxt, sizeof(req->context)); be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { cq->id = le16_to_cpu(resp->cq_id); cq->created = true; } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } @@ -544,17 +545,17 @@ static u32 be_encoded_q_len(int q_len) return len_encoded; } -int be_cmd_mccq_create(struct be_ctrl_info *ctrl, +int be_cmd_mccq_create(struct be_adapter *adapter, struct be_queue_info *mccq, struct be_queue_info *cq) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_mcc_create *req = embedded_payload(wrb); struct be_dma_mem *q_mem = &mccq->dma_mem; void *ctxt = &req->context; int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -564,7 +565,7 @@ int be_cmd_mccq_create(struct be_ctrl_info *ctrl, req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size); - AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt, ctrl->pci_func); + AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt, adapter->pci_func); AMAP_SET_BITS(struct amap_mcc_context, valid, ctxt, 1); AMAP_SET_BITS(struct amap_mcc_context, ring_size, ctxt, be_encoded_q_len(mccq->len)); @@ -574,29 +575,29 @@ int be_cmd_mccq_create(struct be_ctrl_info *ctrl, be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb); mccq->id = le16_to_cpu(resp->id); mccq->created = true; } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_txq_create(struct be_ctrl_info *ctrl, +int be_cmd_txq_create(struct be_adapter *adapter, struct be_queue_info *txq, struct be_queue_info *cq) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_eth_tx_create *req = embedded_payload(wrb); struct be_dma_mem *q_mem = &txq->dma_mem; void *ctxt = &req->context; int status; u32 len_encoded; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -613,7 +614,7 @@ int be_cmd_txq_create(struct be_ctrl_info *ctrl, len_encoded = 0; AMAP_SET_BITS(struct amap_tx_context, tx_ring_size, ctxt, len_encoded); AMAP_SET_BITS(struct amap_tx_context, pci_func_id, ctxt, - ctrl->pci_func); + adapter->pci_func); AMAP_SET_BITS(struct amap_tx_context, ctx_valid, ctxt, 1); AMAP_SET_BITS(struct amap_tx_context, cq_id_send, ctxt, cq->id); @@ -621,27 +622,27 @@ int be_cmd_txq_create(struct be_ctrl_info *ctrl, be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { struct be_cmd_resp_eth_tx_create *resp = embedded_payload(wrb); txq->id = le16_to_cpu(resp->cid); txq->created = true; } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_rxq_create(struct be_ctrl_info *ctrl, +int be_cmd_rxq_create(struct be_adapter *adapter, struct be_queue_info *rxq, u16 cq_id, u16 frag_size, u16 max_frame_size, u32 if_id, u32 rss) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_eth_rx_create *req = embedded_payload(wrb); struct be_dma_mem *q_mem = &rxq->dma_mem; int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -657,27 +658,27 @@ int be_cmd_rxq_create(struct be_ctrl_info *ctrl, req->max_frame_size = cpu_to_le16(max_frame_size); req->rss_queue = cpu_to_le32(rss); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { struct be_cmd_resp_eth_rx_create *resp = embedded_payload(wrb); rxq->id = le16_to_cpu(resp->id); rxq->created = true; } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } /* Generic destroyer function for all types of queues */ -int be_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, +int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, int queue_type) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_q_destroy *req = embedded_payload(wrb); u8 subsys = 0, opcode = 0; int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -711,22 +712,22 @@ int be_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req)); req->id = cpu_to_le16(q->id); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); err: - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } /* Create an rx filtering policy configuration on an i/f */ -int be_cmd_if_create(struct be_ctrl_info *ctrl, u32 flags, u8 *mac, +int be_cmd_if_create(struct be_adapter *adapter, u32 flags, u8 *mac, bool pmac_invalid, u32 *if_handle, u32 *pmac_id) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_if_create *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -739,7 +740,7 @@ int be_cmd_if_create(struct be_ctrl_info *ctrl, u32 flags, u8 *mac, if (!pmac_invalid) memcpy(req->mac_addr, mac, ETH_ALEN); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { struct be_cmd_resp_if_create *resp = embedded_payload(wrb); *if_handle = le32_to_cpu(resp->interface_id); @@ -747,17 +748,17 @@ int be_cmd_if_create(struct be_ctrl_info *ctrl, u32 flags, u8 *mac, *pmac_id = le32_to_cpu(resp->pmac_id); } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_if_destroy(struct be_ctrl_info *ctrl, u32 interface_id) +int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_if_destroy *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -766,9 +767,9 @@ int be_cmd_if_destroy(struct be_ctrl_info *ctrl, u32 interface_id) OPCODE_COMMON_NTWK_INTERFACE_DESTROY, sizeof(*req)); req->interface_id = cpu_to_le32(interface_id); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } @@ -776,14 +777,14 @@ int be_cmd_if_destroy(struct be_ctrl_info *ctrl, u32 interface_id) /* Get stats is a non embedded command: the request is not embedded inside * WRB but is a separate dma memory block */ -int be_cmd_get_stats(struct be_ctrl_info *ctrl, struct be_dma_mem *nonemb_cmd) +int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_get_stats *req = nonemb_cmd->va; struct be_sge *sge = nonembedded_sgl(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); memset(req, 0, sizeof(*req)); @@ -796,24 +797,24 @@ int be_cmd_get_stats(struct be_ctrl_info *ctrl, struct be_dma_mem *nonemb_cmd) sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); sge->len = cpu_to_le32(nonemb_cmd->size); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { struct be_cmd_resp_get_stats *resp = nonemb_cmd->va; be_dws_le_to_cpu(&resp->hw_stats, sizeof(resp->hw_stats)); } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_link_status_query(struct be_ctrl_info *ctrl, +int be_cmd_link_status_query(struct be_adapter *adapter, bool *link_up) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_link_status *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); *link_up = false; memset(wrb, 0, sizeof(*wrb)); @@ -823,24 +824,24 @@ int be_cmd_link_status_query(struct be_ctrl_info *ctrl, be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, sizeof(*req)); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { struct be_cmd_resp_link_status *resp = embedded_payload(wrb); if (resp->mac_speed != PHY_LINK_SPEED_ZERO) *link_up = true; } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_get_fw_ver(struct be_ctrl_info *ctrl, char *fw_ver) +int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_get_fw_version *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -848,24 +849,24 @@ int be_cmd_get_fw_ver(struct be_ctrl_info *ctrl, char *fw_ver) be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_GET_FW_VERSION, sizeof(*req)); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { struct be_cmd_resp_get_fw_version *resp = embedded_payload(wrb); strncpy(fw_ver, resp->firmware_version_string, FW_VER_LEN); } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } /* set the EQ delay interval of an EQ to specified value */ -int be_cmd_modify_eqd(struct be_ctrl_info *ctrl, u32 eq_id, u32 eqd) +int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_modify_eq_delay *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -878,20 +879,20 @@ int be_cmd_modify_eqd(struct be_ctrl_info *ctrl, u32 eq_id, u32 eqd) req->delay[0].phase = 0; req->delay[0].delay_multiplier = cpu_to_le32(eqd); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_vlan_config(struct be_ctrl_info *ctrl, u32 if_id, u16 *vtag_array, +int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array, u32 num, bool untagged, bool promiscuous) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_vlan_config *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -908,21 +909,21 @@ int be_cmd_vlan_config(struct be_ctrl_info *ctrl, u32 if_id, u16 *vtag_array, req->num_vlan * sizeof(vtag_array[0])); } - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } /* Use MCC for this command as it may be called in BH context */ -int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl, u8 port_num, bool en) +int be_cmd_promiscuous_config(struct be_adapter *adapter, u8 port_num, bool en) { struct be_mcc_wrb *wrb; struct be_cmd_req_promiscuous_config *req; - spin_lock_bh(&ctrl->mcc_lock); + spin_lock_bh(&adapter->mcc_lock); - wrb = wrb_from_mcc(&ctrl->mcc_obj.q); + wrb = wrb_from_mcc(&adapter->mcc_obj.q); BUG_ON(!wrb); req = embedded_payload(wrb); @@ -937,9 +938,9 @@ int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl, u8 port_num, bool en) else req->port0_promiscuous = en; - be_mcc_notify_wait(ctrl); + be_mcc_notify_wait(adapter); - spin_unlock_bh(&ctrl->mcc_lock); + spin_unlock_bh(&adapter->mcc_lock); return 0; } @@ -947,16 +948,16 @@ int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl, u8 port_num, bool en) * Use MCC for this command as it may be called in BH context * (mc == NULL) => multicast promiscous */ -int be_cmd_multicast_set(struct be_ctrl_info *ctrl, u32 if_id, +int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id, struct dev_mc_list *mc_list, u32 mc_count) { #define BE_MAX_MC 32 /* set mcast promisc if > 32 */ struct be_mcc_wrb *wrb; struct be_cmd_req_mcast_mac_config *req; - spin_lock_bh(&ctrl->mcc_lock); + spin_lock_bh(&adapter->mcc_lock); - wrb = wrb_from_mcc(&ctrl->mcc_obj.q); + wrb = wrb_from_mcc(&adapter->mcc_obj.q); BUG_ON(!wrb); req = embedded_payload(wrb); @@ -979,20 +980,20 @@ int be_cmd_multicast_set(struct be_ctrl_info *ctrl, u32 if_id, req->promiscuous = 1; } - be_mcc_notify_wait(ctrl); + be_mcc_notify_wait(adapter); - spin_unlock_bh(&ctrl->mcc_lock); + spin_unlock_bh(&adapter->mcc_lock); return 0; } -int be_cmd_set_flow_control(struct be_ctrl_info *ctrl, u32 tx_fc, u32 rx_fc) +int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_set_flow_control *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); @@ -1004,19 +1005,19 @@ int be_cmd_set_flow_control(struct be_ctrl_info *ctrl, u32 tx_fc, u32 rx_fc) req->tx_flow_control = cpu_to_le16((u16)tx_fc); req->rx_flow_control = cpu_to_le16((u16)rx_fc); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_get_flow_control(struct be_ctrl_info *ctrl, u32 *tx_fc, u32 *rx_fc) +int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_get_flow_control *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); @@ -1025,7 +1026,7 @@ int be_cmd_get_flow_control(struct be_ctrl_info *ctrl, u32 *tx_fc, u32 *rx_fc) be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_GET_FLOW_CONTROL, sizeof(*req)); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { struct be_cmd_resp_get_flow_control *resp = embedded_payload(wrb); @@ -1033,17 +1034,17 @@ int be_cmd_get_flow_control(struct be_ctrl_info *ctrl, u32 *tx_fc, u32 *rx_fc) *rx_fc = le16_to_cpu(resp->rx_flow_control); } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } -int be_cmd_query_fw_cfg(struct be_ctrl_info *ctrl, u32 *port_num) +int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); struct be_cmd_req_query_fw_cfg *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->mbox_lock); + spin_lock(&adapter->mbox_lock); memset(wrb, 0, sizeof(*wrb)); @@ -1052,12 +1053,12 @@ int be_cmd_query_fw_cfg(struct be_ctrl_info *ctrl, u32 *port_num) be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, sizeof(*req)); - status = be_mbox_db_ring(ctrl); + status = be_mbox_db_ring(adapter); if (!status) { struct be_cmd_resp_query_fw_cfg *resp = embedded_payload(wrb); *port_num = le32_to_cpu(resp->phys_port); } - spin_unlock(&ctrl->mbox_lock); + spin_unlock(&adapter->mbox_lock); return status; } diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 747626da7b4..164ab927782 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -634,7 +634,6 @@ struct be_cmd_resp_link_status { } __packed; /******************** Get FW Version *******************/ -#define FW_VER_LEN 32 struct be_cmd_req_get_fw_version { struct be_cmd_req_hdr hdr; u8 rsvd0[FW_VER_LEN]; @@ -697,52 +696,52 @@ struct be_cmd_resp_query_fw_cfg { u32 rsvd[26]; }; -extern int be_pci_fnum_get(struct be_ctrl_info *ctrl); -extern int be_cmd_POST(struct be_ctrl_info *ctrl); -extern int be_cmd_mac_addr_query(struct be_ctrl_info *ctrl, u8 *mac_addr, +extern int be_pci_fnum_get(struct be_adapter *adapter); +extern int be_cmd_POST(struct be_adapter *adapter); +extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, u8 type, bool permanent, u32 if_handle); -extern int be_cmd_pmac_add(struct be_ctrl_info *ctrl, u8 *mac_addr, +extern int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, u32 if_id, u32 *pmac_id); -extern int be_cmd_pmac_del(struct be_ctrl_info *ctrl, u32 if_id, u32 pmac_id); -extern int be_cmd_if_create(struct be_ctrl_info *ctrl, u32 if_flags, u8 *mac, +extern int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id); +extern int be_cmd_if_create(struct be_adapter *adapter, u32 if_flags, u8 *mac, bool pmac_invalid, u32 *if_handle, u32 *pmac_id); -extern int be_cmd_if_destroy(struct be_ctrl_info *ctrl, u32 if_handle); -extern int be_cmd_eq_create(struct be_ctrl_info *ctrl, +extern int be_cmd_if_destroy(struct be_adapter *adapter, u32 if_handle); +extern int be_cmd_eq_create(struct be_adapter *adapter, struct be_queue_info *eq, int eq_delay); -extern int be_cmd_cq_create(struct be_ctrl_info *ctrl, +extern int be_cmd_cq_create(struct be_adapter *adapter, struct be_queue_info *cq, struct be_queue_info *eq, bool sol_evts, bool no_delay, int num_cqe_dma_coalesce); -extern int be_cmd_mccq_create(struct be_ctrl_info *ctrl, +extern int be_cmd_mccq_create(struct be_adapter *adapter, struct be_queue_info *mccq, struct be_queue_info *cq); -extern int be_cmd_txq_create(struct be_ctrl_info *ctrl, +extern int be_cmd_txq_create(struct be_adapter *adapter, struct be_queue_info *txq, struct be_queue_info *cq); -extern int be_cmd_rxq_create(struct be_ctrl_info *ctrl, +extern int be_cmd_rxq_create(struct be_adapter *adapter, struct be_queue_info *rxq, u16 cq_id, u16 frag_size, u16 max_frame_size, u32 if_id, u32 rss); -extern int be_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, +extern int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, int type); -extern int be_cmd_link_status_query(struct be_ctrl_info *ctrl, +extern int be_cmd_link_status_query(struct be_adapter *adapter, bool *link_up); -extern int be_cmd_reset(struct be_ctrl_info *ctrl); -extern int be_cmd_get_stats(struct be_ctrl_info *ctrl, +extern int be_cmd_reset(struct be_adapter *adapter); +extern int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd); -extern int be_cmd_get_fw_ver(struct be_ctrl_info *ctrl, char *fw_ver); +extern int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver); -extern int be_cmd_modify_eqd(struct be_ctrl_info *ctrl, u32 eq_id, u32 eqd); -extern int be_cmd_vlan_config(struct be_ctrl_info *ctrl, u32 if_id, +extern int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd); +extern int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array, u32 num, bool untagged, bool promiscuous); -extern int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl, +extern int be_cmd_promiscuous_config(struct be_adapter *adapter, u8 port_num, bool en); -extern int be_cmd_multicast_set(struct be_ctrl_info *ctrl, u32 if_id, +extern int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id, struct dev_mc_list *mc_list, u32 mc_count); -extern int be_cmd_set_flow_control(struct be_ctrl_info *ctrl, +extern int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc); -extern int be_cmd_get_flow_control(struct be_ctrl_info *ctrl, +extern int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc); -extern int be_cmd_query_fw_cfg(struct be_ctrl_info *ctrl, u32 *port_num); -extern void be_process_mcc(struct be_ctrl_info *ctrl); +extern int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num); +extern void be_process_mcc(struct be_adapter *adapter); diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index f3f0f91e38c..c480c19200d 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -16,6 +16,7 @@ */ #include "be.h" +#include "be_cmds.h" #include struct be_ethtool_stat { @@ -148,7 +149,6 @@ static int be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) { struct be_adapter *adapter = netdev_priv(netdev); - struct be_ctrl_info *ctrl = &adapter->ctrl; struct be_eq_obj *rx_eq = &adapter->rx_eq; struct be_eq_obj *tx_eq = &adapter->tx_eq; u32 tx_max, tx_min, tx_cur; @@ -176,7 +176,7 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) if (tx_cur > BE_MAX_EQD) tx_cur = BE_MAX_EQD; if (tx_eq->cur_eqd != tx_cur) { - status = be_cmd_modify_eqd(ctrl, tx_eq->q.id, tx_cur); + status = be_cmd_modify_eqd(adapter, tx_eq->q.id, tx_cur); if (!status) tx_eq->cur_eqd = tx_cur; } @@ -196,7 +196,8 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) if (rx_cur > BE_MAX_EQD) rx_cur = BE_MAX_EQD; if (rx_eq->cur_eqd != rx_cur) { - status = be_cmd_modify_eqd(ctrl, rx_eq->q.id, rx_cur); + status = be_cmd_modify_eqd(adapter, rx_eq->q.id, + rx_cur); if (!status) rx_eq->cur_eqd = rx_cur; } @@ -310,8 +311,7 @@ be_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) { struct be_adapter *adapter = netdev_priv(netdev); - be_cmd_get_flow_control(&adapter->ctrl, &ecmd->tx_pause, - &ecmd->rx_pause); + be_cmd_get_flow_control(adapter, &ecmd->tx_pause, &ecmd->rx_pause); ecmd->autoneg = 0; } @@ -324,7 +324,7 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) if (ecmd->autoneg != 0) return -EINVAL; - status = be_cmd_set_flow_control(&adapter->ctrl, ecmd->tx_pause, + status = be_cmd_set_flow_control(adapter, ecmd->tx_pause, ecmd->rx_pause); if (!status) dev_warn(&adapter->pdev->dev, "Pause param set failed.\n"); diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index c56487e3700..da5341f1038 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -16,6 +16,7 @@ */ #include "be.h" +#include "be_cmds.h" #include MODULE_VERSION(DRV_VER); @@ -60,9 +61,9 @@ static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q, return 0; } -static void be_intr_set(struct be_ctrl_info *ctrl, bool enable) +static void be_intr_set(struct be_adapter *adapter, bool enable) { - u8 __iomem *addr = ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET; + u8 __iomem *addr = adapter->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET; u32 reg = ioread32(addr); u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; if (!enabled && enable) { @@ -77,23 +78,23 @@ static void be_intr_set(struct be_ctrl_info *ctrl, bool enable) iowrite32(reg, addr); } -static void be_rxq_notify(struct be_ctrl_info *ctrl, u16 qid, u16 posted) +static void be_rxq_notify(struct be_adapter *adapter, u16 qid, u16 posted) { u32 val = 0; val |= qid & DB_RQ_RING_ID_MASK; val |= posted << DB_RQ_NUM_POSTED_SHIFT; - iowrite32(val, ctrl->db + DB_RQ_OFFSET); + iowrite32(val, adapter->db + DB_RQ_OFFSET); } -static void be_txq_notify(struct be_ctrl_info *ctrl, u16 qid, u16 posted) +static void be_txq_notify(struct be_adapter *adapter, u16 qid, u16 posted) { u32 val = 0; val |= qid & DB_TXULP_RING_ID_MASK; val |= (posted & DB_TXULP_NUM_POSTED_MASK) << DB_TXULP_NUM_POSTED_SHIFT; - iowrite32(val, ctrl->db + DB_TXULP1_OFFSET); + iowrite32(val, adapter->db + DB_TXULP1_OFFSET); } -static void be_eq_notify(struct be_ctrl_info *ctrl, u16 qid, +static void be_eq_notify(struct be_adapter *adapter, u16 qid, bool arm, bool clear_int, u16 num_popped) { u32 val = 0; @@ -104,18 +105,17 @@ static void be_eq_notify(struct be_ctrl_info *ctrl, u16 qid, val |= 1 << DB_EQ_CLR_SHIFT; val |= 1 << DB_EQ_EVNT_SHIFT; val |= num_popped << DB_EQ_NUM_POPPED_SHIFT; - iowrite32(val, ctrl->db + DB_EQ_OFFSET); + iowrite32(val, adapter->db + DB_EQ_OFFSET); } -void be_cq_notify(struct be_ctrl_info *ctrl, u16 qid, - bool arm, u16 num_popped) +void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped) { u32 val = 0; val |= qid & DB_CQ_RING_ID_MASK; if (arm) val |= 1 << DB_CQ_REARM_SHIFT; val |= num_popped << DB_CQ_NUM_POPPED_SHIFT; - iowrite32(val, ctrl->db + DB_CQ_OFFSET); + iowrite32(val, adapter->db + DB_CQ_OFFSET); } @@ -126,12 +126,12 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) int status = 0; if (netif_running(netdev)) { - status = be_cmd_pmac_del(&adapter->ctrl, adapter->if_handle, + status = be_cmd_pmac_del(adapter, adapter->if_handle, adapter->pmac_id); if (status) return status; - status = be_cmd_pmac_add(&adapter->ctrl, (u8 *)addr->sa_data, + status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data, adapter->if_handle, &adapter->pmac_id); } @@ -214,9 +214,8 @@ static void netdev_stats_update(struct be_adapter *adapter) dev_stats->tx_window_errors = 0; } -void be_link_status_update(void *ctxt, bool link_up) +void be_link_status_update(struct be_adapter *adapter, bool link_up) { - struct be_adapter *adapter = ctxt; struct net_device *netdev = adapter->netdev; /* If link came up or went down */ @@ -237,7 +236,6 @@ void be_link_status_update(void *ctxt, bool link_up) /* Update the EQ delay n BE based on the RX frags consumed / sec */ static void be_rx_eqd_update(struct be_adapter *adapter) { - struct be_ctrl_info *ctrl = &adapter->ctrl; struct be_eq_obj *rx_eq = &adapter->rx_eq; struct be_drvr_stats *stats = &adapter->stats.drvr_stats; ulong now = jiffies; @@ -270,7 +268,7 @@ static void be_rx_eqd_update(struct be_adapter *adapter) if (eqd < 10) eqd = 0; if (eqd != rx_eq->cur_eqd) - be_cmd_modify_eqd(ctrl, rx_eq->q.id, eqd); + be_cmd_modify_eqd(adapter, rx_eq->q.id, eqd); rx_eq->cur_eqd = eqd; } @@ -412,8 +410,8 @@ static int make_tx_wrbs(struct be_adapter *adapter, struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; busaddr = pci_map_page(pdev, frag->page, - frag->page_offset, - frag->size, PCI_DMA_TODEVICE); + frag->page_offset, + frag->size, PCI_DMA_TODEVICE); wrb = queue_head_node(txq); wrb_fill(wrb, busaddr, frag->size); be_dws_cpu_to_le(wrb, sizeof(*wrb)); @@ -461,7 +459,7 @@ static int be_xmit(struct sk_buff *skb, struct net_device *netdev) stopped = true; } - be_txq_notify(&adapter->ctrl, txq->id, wrb_cnt); + be_txq_notify(adapter, txq->id, wrb_cnt); be_tx_stats_update(adapter, wrb_cnt, copied, stopped); return NETDEV_TX_OK; @@ -502,10 +500,10 @@ static void be_vid_config(struct net_device *netdev) ntags++; } } - be_cmd_vlan_config(&adapter->ctrl, adapter->if_handle, + be_cmd_vlan_config(adapter, adapter->if_handle, vtag, ntags, 1, 0); } else { - be_cmd_vlan_config(&adapter->ctrl, adapter->if_handle, + be_cmd_vlan_config(adapter, adapter->if_handle, NULL, 0, 1, 1); } } @@ -515,13 +513,12 @@ static void be_vlan_register(struct net_device *netdev, struct vlan_group *grp) struct be_adapter *adapter = netdev_priv(netdev); struct be_eq_obj *rx_eq = &adapter->rx_eq; struct be_eq_obj *tx_eq = &adapter->tx_eq; - struct be_ctrl_info *ctrl = &adapter->ctrl; - be_eq_notify(ctrl, rx_eq->q.id, false, false, 0); - be_eq_notify(ctrl, tx_eq->q.id, false, false, 0); + be_eq_notify(adapter, rx_eq->q.id, false, false, 0); + be_eq_notify(adapter, tx_eq->q.id, false, false, 0); adapter->vlan_grp = grp; - be_eq_notify(ctrl, rx_eq->q.id, true, false, 0); - be_eq_notify(ctrl, tx_eq->q.id, true, false, 0); + be_eq_notify(adapter, rx_eq->q.id, true, false, 0); + be_eq_notify(adapter, tx_eq->q.id, true, false, 0); } static void be_vlan_add_vid(struct net_device *netdev, u16 vid) @@ -548,10 +545,9 @@ static void be_vlan_rem_vid(struct net_device *netdev, u16 vid) static void be_set_multicast_list(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); - struct be_ctrl_info *ctrl = &adapter->ctrl; if (netdev->flags & IFF_PROMISC) { - be_cmd_promiscuous_config(ctrl, adapter->port_num, 1); + be_cmd_promiscuous_config(adapter, adapter->port_num, 1); adapter->promiscuous = true; goto done; } @@ -559,15 +555,15 @@ static void be_set_multicast_list(struct net_device *netdev) /* BE was previously in promiscous mode; disable it */ if (adapter->promiscuous) { adapter->promiscuous = false; - be_cmd_promiscuous_config(ctrl, adapter->port_num, 0); + be_cmd_promiscuous_config(adapter, adapter->port_num, 0); } if (netdev->flags & IFF_ALLMULTI) { - be_cmd_multicast_set(ctrl, adapter->if_handle, NULL, 0); + be_cmd_multicast_set(adapter, adapter->if_handle, NULL, 0); goto done; } - be_cmd_multicast_set(ctrl, adapter->if_handle, netdev->mc_list, + be_cmd_multicast_set(adapter, adapter->if_handle, netdev->mc_list, netdev->mc_count); done: return; @@ -942,7 +938,7 @@ static void be_post_rx_frags(struct be_adapter *adapter) if (posted) { atomic_add(posted, &rxq->used); - be_rxq_notify(&adapter->ctrl, rxq->id, posted); + be_rxq_notify(adapter, rxq->id, posted); } else if (atomic_read(&rxq->used) == 0) { /* Let be_worker replenish when memory is available */ adapter->rx_post_starved = true; @@ -1010,7 +1006,7 @@ static void be_rx_q_clean(struct be_adapter *adapter) while ((rxcp = be_rx_compl_get(adapter)) != NULL) { be_rx_compl_discard(adapter, rxcp); be_rx_compl_reset(rxcp); - be_cq_notify(&adapter->ctrl, rx_cq->id, true, 1); + be_cq_notify(adapter, rx_cq->id, true, 1); } /* Then free posted rx buffer that were not used */ @@ -1043,16 +1039,15 @@ static void be_tx_q_clean(struct be_adapter *adapter) static void be_mcc_queues_destroy(struct be_adapter *adapter) { struct be_queue_info *q; - struct be_ctrl_info *ctrl = &adapter->ctrl; - q = &ctrl->mcc_obj.q; + q = &adapter->mcc_obj.q; if (q->created) - be_cmd_q_destroy(ctrl, q, QTYPE_MCCQ); + be_cmd_q_destroy(adapter, q, QTYPE_MCCQ); be_queue_free(adapter, q); - q = &ctrl->mcc_obj.cq; + q = &adapter->mcc_obj.cq; if (q->created) - be_cmd_q_destroy(ctrl, q, QTYPE_CQ); + be_cmd_q_destroy(adapter, q, QTYPE_CQ); be_queue_free(adapter, q); } @@ -1060,25 +1055,24 @@ static void be_mcc_queues_destroy(struct be_adapter *adapter) static int be_mcc_queues_create(struct be_adapter *adapter) { struct be_queue_info *q, *cq; - struct be_ctrl_info *ctrl = &adapter->ctrl; /* Alloc MCC compl queue */ - cq = &ctrl->mcc_obj.cq; + cq = &adapter->mcc_obj.cq; if (be_queue_alloc(adapter, cq, MCC_CQ_LEN, sizeof(struct be_mcc_cq_entry))) goto err; /* Ask BE to create MCC compl queue; share TX's eq */ - if (be_cmd_cq_create(ctrl, cq, &adapter->tx_eq.q, false, true, 0)) + if (be_cmd_cq_create(adapter, cq, &adapter->tx_eq.q, false, true, 0)) goto mcc_cq_free; /* Alloc MCC queue */ - q = &ctrl->mcc_obj.q; + q = &adapter->mcc_obj.q; if (be_queue_alloc(adapter, q, MCC_Q_LEN, sizeof(struct be_mcc_wrb))) goto mcc_cq_destroy; /* Ask BE to create MCC queue */ - if (be_cmd_mccq_create(ctrl, q, cq)) + if (be_cmd_mccq_create(adapter, q, cq)) goto mcc_q_free; return 0; @@ -1086,7 +1080,7 @@ static int be_mcc_queues_create(struct be_adapter *adapter) mcc_q_free: be_queue_free(adapter, q); mcc_cq_destroy: - be_cmd_q_destroy(ctrl, cq, QTYPE_CQ); + be_cmd_q_destroy(adapter, cq, QTYPE_CQ); mcc_cq_free: be_queue_free(adapter, cq); err: @@ -1099,7 +1093,7 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) q = &adapter->tx_obj.q; if (q->created) { - be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_TXQ); + be_cmd_q_destroy(adapter, q, QTYPE_TXQ); /* No more tx completions can be rcvd now; clean up if there * are any pending completions or pending tx requests */ @@ -1109,12 +1103,12 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) q = &adapter->tx_obj.cq; if (q->created) - be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_CQ); + be_cmd_q_destroy(adapter, q, QTYPE_CQ); be_queue_free(adapter, q); q = &adapter->tx_eq.q; if (q->created) - be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_EQ); + be_cmd_q_destroy(adapter, q, QTYPE_EQ); be_queue_free(adapter, q); } @@ -1132,7 +1126,7 @@ static int be_tx_queues_create(struct be_adapter *adapter) return -1; /* Ask BE to create Tx Event queue */ - if (be_cmd_eq_create(&adapter->ctrl, eq, adapter->tx_eq.cur_eqd)) + if (be_cmd_eq_create(adapter, eq, adapter->tx_eq.cur_eqd)) goto tx_eq_free; /* Alloc TX eth compl queue */ cq = &adapter->tx_obj.cq; @@ -1141,7 +1135,7 @@ static int be_tx_queues_create(struct be_adapter *adapter) goto tx_eq_destroy; /* Ask BE to create Tx eth compl queue */ - if (be_cmd_cq_create(&adapter->ctrl, cq, eq, false, false, 3)) + if (be_cmd_cq_create(adapter, cq, eq, false, false, 3)) goto tx_cq_free; /* Alloc TX eth queue */ @@ -1150,18 +1144,18 @@ static int be_tx_queues_create(struct be_adapter *adapter) goto tx_cq_destroy; /* Ask BE to create Tx eth queue */ - if (be_cmd_txq_create(&adapter->ctrl, q, cq)) + if (be_cmd_txq_create(adapter, q, cq)) goto tx_q_free; return 0; tx_q_free: be_queue_free(adapter, q); tx_cq_destroy: - be_cmd_q_destroy(&adapter->ctrl, cq, QTYPE_CQ); + be_cmd_q_destroy(adapter, cq, QTYPE_CQ); tx_cq_free: be_queue_free(adapter, cq); tx_eq_destroy: - be_cmd_q_destroy(&adapter->ctrl, eq, QTYPE_EQ); + be_cmd_q_destroy(adapter, eq, QTYPE_EQ); tx_eq_free: be_queue_free(adapter, eq); return -1; @@ -1173,19 +1167,19 @@ static void be_rx_queues_destroy(struct be_adapter *adapter) q = &adapter->rx_obj.q; if (q->created) { - be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_RXQ); + be_cmd_q_destroy(adapter, q, QTYPE_RXQ); be_rx_q_clean(adapter); } be_queue_free(adapter, q); q = &adapter->rx_obj.cq; if (q->created) - be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_CQ); + be_cmd_q_destroy(adapter, q, QTYPE_CQ); be_queue_free(adapter, q); q = &adapter->rx_eq.q; if (q->created) - be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_EQ); + be_cmd_q_destroy(adapter, q, QTYPE_EQ); be_queue_free(adapter, q); } @@ -1208,7 +1202,7 @@ static int be_rx_queues_create(struct be_adapter *adapter) return rc; /* Ask BE to create Rx Event queue */ - rc = be_cmd_eq_create(&adapter->ctrl, eq, adapter->rx_eq.cur_eqd); + rc = be_cmd_eq_create(adapter, eq, adapter->rx_eq.cur_eqd); if (rc) goto rx_eq_free; @@ -1220,7 +1214,7 @@ static int be_rx_queues_create(struct be_adapter *adapter) goto rx_eq_destroy; /* Ask BE to create Rx eth compl queue */ - rc = be_cmd_cq_create(&adapter->ctrl, cq, eq, false, false, 3); + rc = be_cmd_cq_create(adapter, cq, eq, false, false, 3); if (rc) goto rx_cq_free; @@ -1231,7 +1225,7 @@ static int be_rx_queues_create(struct be_adapter *adapter) goto rx_cq_destroy; /* Ask BE to create Rx eth queue */ - rc = be_cmd_rxq_create(&adapter->ctrl, q, cq->id, rx_frag_size, + rc = be_cmd_rxq_create(adapter, q, cq->id, rx_frag_size, BE_MAX_JUMBO_FRAME_SIZE, adapter->if_handle, false); if (rc) goto rx_q_free; @@ -1240,11 +1234,11 @@ static int be_rx_queues_create(struct be_adapter *adapter) rx_q_free: be_queue_free(adapter, q); rx_cq_destroy: - be_cmd_q_destroy(&adapter->ctrl, cq, QTYPE_CQ); + be_cmd_q_destroy(adapter, cq, QTYPE_CQ); rx_cq_free: be_queue_free(adapter, cq); rx_eq_destroy: - be_cmd_q_destroy(&adapter->ctrl, eq, QTYPE_EQ); + be_cmd_q_destroy(adapter, eq, QTYPE_EQ); rx_eq_free: be_queue_free(adapter, eq); return rc; @@ -1264,8 +1258,7 @@ static bool event_get(struct be_eq_obj *eq_obj, u16 *rid) return true; } -static int event_handle(struct be_ctrl_info *ctrl, - struct be_eq_obj *eq_obj) +static int event_handle(struct be_adapter *adapter, struct be_eq_obj *eq_obj) { u16 rid = 0, num = 0; @@ -1273,7 +1266,7 @@ static int event_handle(struct be_ctrl_info *ctrl, num++; /* We can see an interrupt and no event */ - be_eq_notify(ctrl, eq_obj->q.id, true, true, num); + be_eq_notify(adapter, eq_obj->q.id, true, true, num); if (num) napi_schedule(&eq_obj->napi); @@ -1283,25 +1276,24 @@ static int event_handle(struct be_ctrl_info *ctrl, static irqreturn_t be_intx(int irq, void *dev) { struct be_adapter *adapter = dev; - struct be_ctrl_info *ctrl = &adapter->ctrl; - int isr; + int isr; - isr = ioread32(ctrl->csr + CEV_ISR0_OFFSET + - ctrl->pci_func * CEV_ISR_SIZE); + isr = ioread32(adapter->csr + CEV_ISR0_OFFSET + + adapter->pci_func * CEV_ISR_SIZE); if (!isr) - return IRQ_NONE; + return IRQ_NONE; - event_handle(ctrl, &adapter->tx_eq); - event_handle(ctrl, &adapter->rx_eq); + event_handle(adapter, &adapter->tx_eq); + event_handle(adapter, &adapter->rx_eq); - return IRQ_HANDLED; + return IRQ_HANDLED; } static irqreturn_t be_msix_rx(int irq, void *dev) { struct be_adapter *adapter = dev; - event_handle(&adapter->ctrl, &adapter->rx_eq); + event_handle(adapter, &adapter->rx_eq); return IRQ_HANDLED; } @@ -1310,7 +1302,7 @@ static irqreturn_t be_msix_tx_mcc(int irq, void *dev) { struct be_adapter *adapter = dev; - event_handle(&adapter->ctrl, &adapter->tx_eq); + event_handle(adapter, &adapter->tx_eq); return IRQ_HANDLED; } @@ -1356,10 +1348,10 @@ int be_poll_rx(struct napi_struct *napi, int budget) /* All consumed */ if (work_done < budget) { napi_complete(napi); - be_cq_notify(&adapter->ctrl, rx_cq->id, true, work_done); + be_cq_notify(adapter, rx_cq->id, true, work_done); } else { /* More to be consumed; continue with interrupts disabled */ - be_cq_notify(&adapter->ctrl, rx_cq->id, false, work_done); + be_cq_notify(adapter, rx_cq->id, false, work_done); } return work_done; } @@ -1380,7 +1372,7 @@ void be_process_tx(struct be_adapter *adapter) } if (num_cmpl) { - be_cq_notify(&adapter->ctrl, tx_cq->id, true, num_cmpl); + be_cq_notify(adapter, tx_cq->id, true, num_cmpl); /* As Tx wrbs have been freed up, wake up netdev queue if * it was stopped due to lack of tx wrbs. @@ -1408,7 +1400,7 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget) be_process_tx(adapter); - be_process_mcc(&adapter->ctrl); + be_process_mcc(adapter); return 1; } @@ -1420,7 +1412,7 @@ static void be_worker(struct work_struct *work) int status; /* Get Stats */ - status = be_cmd_get_stats(&adapter->ctrl, &adapter->stats.cmd); + status = be_cmd_get_stats(adapter, &adapter->stats.cmd); if (!status) netdev_stats_update(adapter); @@ -1454,8 +1446,7 @@ static void be_msix_enable(struct be_adapter *adapter) static inline int be_msix_vec_get(struct be_adapter *adapter, u32 eq_id) { - return adapter->msix_entries[eq_id - - 8 * adapter->ctrl.pci_func].vector; + return adapter->msix_entries[eq_id - 8 * adapter->pci_func].vector; } static int be_msix_register(struct be_adapter *adapter) @@ -1540,7 +1531,6 @@ done: static int be_open(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); - struct be_ctrl_info *ctrl = &adapter->ctrl; struct be_eq_obj *rx_eq = &adapter->rx_eq; struct be_eq_obj *tx_eq = &adapter->tx_eq; bool link_up; @@ -1554,16 +1544,16 @@ static int be_open(struct net_device *netdev) be_irq_register(adapter); - be_intr_set(ctrl, true); + be_intr_set(adapter, true); /* The evt queues are created in unarmed state; arm them */ - be_eq_notify(ctrl, rx_eq->q.id, true, false, 0); - be_eq_notify(ctrl, tx_eq->q.id, true, false, 0); + be_eq_notify(adapter, rx_eq->q.id, true, false, 0); + be_eq_notify(adapter, tx_eq->q.id, true, false, 0); /* Rx compl queue may be in unarmed state; rearm it */ - be_cq_notify(ctrl, adapter->rx_obj.cq.id, true, 0); + be_cq_notify(adapter, adapter->rx_obj.cq.id, true, 0); - status = be_cmd_link_status_query(ctrl, &link_up); + status = be_cmd_link_status_query(adapter, &link_up); if (status) return status; be_link_status_update(adapter, link_up); @@ -1574,7 +1564,6 @@ static int be_open(struct net_device *netdev) static int be_setup(struct be_adapter *adapter) { - struct be_ctrl_info *ctrl = &adapter->ctrl; struct net_device *netdev = adapter->netdev; u32 if_flags; int status; @@ -1582,7 +1571,7 @@ static int be_setup(struct be_adapter *adapter) if_flags = BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_PROMISCUOUS | BE_IF_FLAGS_MCAST_PROMISCUOUS | BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_PASS_L3L4_ERRORS; - status = be_cmd_if_create(ctrl, if_flags, netdev->dev_addr, + status = be_cmd_if_create(adapter, if_flags, netdev->dev_addr, false/* pmac_invalid */, &adapter->if_handle, &adapter->pmac_id); if (status != 0) @@ -1590,7 +1579,7 @@ static int be_setup(struct be_adapter *adapter) be_vid_config(netdev); - status = be_cmd_set_flow_control(ctrl, true, true); + status = be_cmd_set_flow_control(adapter, true, true); if (status != 0) goto if_destroy; @@ -1613,19 +1602,17 @@ rx_qs_destroy: tx_qs_destroy: be_tx_queues_destroy(adapter); if_destroy: - be_cmd_if_destroy(ctrl, adapter->if_handle); + be_cmd_if_destroy(adapter, adapter->if_handle); do_none: return status; } static int be_clear(struct be_adapter *adapter) { - struct be_ctrl_info *ctrl = &adapter->ctrl; - be_rx_queues_destroy(adapter); be_tx_queues_destroy(adapter); - be_cmd_if_destroy(ctrl, adapter->if_handle); + be_cmd_if_destroy(adapter, adapter->if_handle); be_mcc_queues_destroy(adapter); return 0; @@ -1634,7 +1621,6 @@ static int be_clear(struct be_adapter *adapter) static int be_close(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); - struct be_ctrl_info *ctrl = &adapter->ctrl; struct be_eq_obj *rx_eq = &adapter->rx_eq; struct be_eq_obj *tx_eq = &adapter->tx_eq; int vec; @@ -1645,7 +1631,7 @@ static int be_close(struct net_device *netdev) netif_carrier_off(netdev); adapter->link_up = false; - be_intr_set(ctrl, false); + be_intr_set(adapter, false); if (adapter->msix_enabled) { vec = be_msix_vec_get(adapter, tx_eq->q.id); @@ -1704,13 +1690,12 @@ static void be_netdev_init(struct net_device *netdev) static void be_unmap_pci_bars(struct be_adapter *adapter) { - struct be_ctrl_info *ctrl = &adapter->ctrl; - if (ctrl->csr) - iounmap(ctrl->csr); - if (ctrl->db) - iounmap(ctrl->db); - if (ctrl->pcicfg) - iounmap(ctrl->pcicfg); + if (adapter->csr) + iounmap(adapter->csr); + if (adapter->db) + iounmap(adapter->db); + if (adapter->pcicfg) + iounmap(adapter->pcicfg); } static int be_map_pci_bars(struct be_adapter *adapter) @@ -1721,19 +1706,19 @@ static int be_map_pci_bars(struct be_adapter *adapter) pci_resource_len(adapter->pdev, 2)); if (addr == NULL) return -ENOMEM; - adapter->ctrl.csr = addr; + adapter->csr = addr; addr = ioremap_nocache(pci_resource_start(adapter->pdev, 4), 128 * 1024); if (addr == NULL) goto pci_map_err; - adapter->ctrl.db = addr; + adapter->db = addr; addr = ioremap_nocache(pci_resource_start(adapter->pdev, 1), pci_resource_len(adapter->pdev, 1)); if (addr == NULL) goto pci_map_err; - adapter->ctrl.pcicfg = addr; + adapter->pcicfg = addr; return 0; pci_map_err: @@ -1744,7 +1729,7 @@ pci_map_err: static void be_ctrl_cleanup(struct be_adapter *adapter) { - struct be_dma_mem *mem = &adapter->ctrl.mbox_mem_alloced; + struct be_dma_mem *mem = &adapter->mbox_mem_alloced; be_unmap_pci_bars(adapter); @@ -1753,12 +1738,10 @@ static void be_ctrl_cleanup(struct be_adapter *adapter) mem->va, mem->dma); } -/* Initialize the mbox required to send cmds to BE */ static int be_ctrl_init(struct be_adapter *adapter) { - struct be_ctrl_info *ctrl = &adapter->ctrl; - struct be_dma_mem *mbox_mem_alloc = &ctrl->mbox_mem_alloced; - struct be_dma_mem *mbox_mem_align = &ctrl->mbox_mem; + struct be_dma_mem *mbox_mem_alloc = &adapter->mbox_mem_alloced; + struct be_dma_mem *mbox_mem_align = &adapter->mbox_mem; int status; u32 val; @@ -1777,15 +1760,12 @@ static int be_ctrl_init(struct be_adapter *adapter) mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16); mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16); memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox)); - spin_lock_init(&ctrl->mbox_lock); - spin_lock_init(&ctrl->mcc_lock); - spin_lock_init(&ctrl->mcc_cq_lock); - - ctrl->async_cb = be_link_status_update; - ctrl->adapter_ctxt = adapter; + spin_lock_init(&adapter->mbox_lock); + spin_lock_init(&adapter->mcc_lock); + spin_lock_init(&adapter->mcc_cq_lock); - val = ioread32(ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET); - ctrl->pci_func = (val >> MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT) & + val = ioread32(adapter->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET); + adapter->pci_func = (val >> MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT) & MEMBAR_CTRL_INT_CTRL_PFUNC_MASK; return 0; } @@ -1840,18 +1820,17 @@ static void __devexit be_remove(struct pci_dev *pdev) static int be_hw_up(struct be_adapter *adapter) { - struct be_ctrl_info *ctrl = &adapter->ctrl; int status; - status = be_cmd_POST(ctrl); + status = be_cmd_POST(adapter); if (status) return status; - status = be_cmd_get_fw_ver(ctrl, adapter->fw_ver); + status = be_cmd_get_fw_ver(adapter, adapter->fw_ver); if (status) return status; - status = be_cmd_query_fw_cfg(ctrl, &adapter->port_num); + status = be_cmd_query_fw_cfg(adapter, &adapter->port_num); return status; } @@ -1861,7 +1840,6 @@ static int __devinit be_probe(struct pci_dev *pdev, int status = 0; struct be_adapter *adapter; struct net_device *netdev; - struct be_ctrl_info *ctrl; u8 mac[ETH_ALEN]; status = pci_enable_device(pdev); @@ -1896,7 +1874,6 @@ static int __devinit be_probe(struct pci_dev *pdev, } } - ctrl = &adapter->ctrl; status = be_ctrl_init(adapter); if (status) goto free_netdev; @@ -1909,7 +1886,7 @@ static int __devinit be_probe(struct pci_dev *pdev, if (status) goto stats_clean; - status = be_cmd_mac_addr_query(ctrl, mac, MAC_ADDRESS_TYPE_NETWORK, + status = be_cmd_mac_addr_query(adapter, mac, MAC_ADDRESS_TYPE_NETWORK, true /* permanent */, 0); if (status) goto stats_clean; -- cgit v1.2.3-18-g5258 From eec368fb3ce3ee9e7bb042bbafb03f297d96e55e Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 27 Jul 2009 22:52:23 +0000 Subject: be2net: remove pci_func field from be_adapter struct pci function is available as PCI_FUNC(pdev->devfn); no need for a separate field. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/benet/be.h | 6 +++++- drivers/net/benet/be_cmds.c | 8 ++++---- drivers/net/benet/be_hw.h | 3 --- drivers/net/benet/be_main.c | 8 ++------ 4 files changed, 11 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index d8a157f8caf..beb13139923 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -213,7 +213,6 @@ struct be_adapter { u8 __iomem *csr; u8 __iomem *db; /* Door Bell */ u8 __iomem *pcicfg; /* PCI config space */ - int pci_func; spinlock_t mbox_lock; /* For serializing mbox cmds to BE card */ struct be_dma_mem mbox_mem; @@ -264,6 +263,11 @@ extern struct ethtool_ops be_ethtool_ops; #define drvr_stats(adapter) (&adapter->stats.drvr_stats) +static inline unsigned int be_pci_func(struct be_adapter *adapter) +{ + return PCI_FUNC(adapter->pdev->devfn); +} + #define BE_SET_NETDEV_OPS(netdev, ops) (netdev->netdev_ops = ops) #define PAGE_SHIFT_4K 12 diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 20278b9d5ed..daa2fe82b64 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -388,7 +388,7 @@ int be_cmd_eq_create(struct be_adapter *adapter, req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); AMAP_SET_BITS(struct amap_eq_context, func, req->context, - adapter->pci_func); + be_pci_func(adapter)); AMAP_SET_BITS(struct amap_eq_context, valid, req->context, 1); /* 4byte eqe*/ AMAP_SET_BITS(struct amap_eq_context, size, req->context, 0); @@ -522,7 +522,7 @@ int be_cmd_cq_create(struct be_adapter *adapter, AMAP_SET_BITS(struct amap_cq_context, eventable, ctxt, 1); AMAP_SET_BITS(struct amap_cq_context, eqid, ctxt, eq->id); AMAP_SET_BITS(struct amap_cq_context, armed, ctxt, 1); - AMAP_SET_BITS(struct amap_cq_context, func, ctxt, adapter->pci_func); + AMAP_SET_BITS(struct amap_cq_context, func, ctxt, be_pci_func(adapter)); be_dws_cpu_to_le(ctxt, sizeof(req->context)); be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); @@ -565,7 +565,7 @@ int be_cmd_mccq_create(struct be_adapter *adapter, req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size); - AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt, adapter->pci_func); + AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt, be_pci_func(adapter)); AMAP_SET_BITS(struct amap_mcc_context, valid, ctxt, 1); AMAP_SET_BITS(struct amap_mcc_context, ring_size, ctxt, be_encoded_q_len(mccq->len)); @@ -614,7 +614,7 @@ int be_cmd_txq_create(struct be_adapter *adapter, len_encoded = 0; AMAP_SET_BITS(struct amap_tx_context, tx_ring_size, ctxt, len_encoded); AMAP_SET_BITS(struct amap_tx_context, pci_func_id, ctxt, - adapter->pci_func); + be_pci_func(adapter)); AMAP_SET_BITS(struct amap_tx_context, ctx_valid, ctxt, 1); AMAP_SET_BITS(struct amap_tx_context, cq_id_send, ctxt, cq->id); diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h index 29c33c709c6..d28f0c679bc 100644 --- a/drivers/net/benet/be_hw.h +++ b/drivers/net/benet/be_hw.h @@ -51,9 +51,6 @@ * with the OS. */ #define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK (1 << 29) /* bit 29 */ -/* PCI physical function number */ -#define MEMBAR_CTRL_INT_CTRL_PFUNC_MASK 0x7 /* bits 26 - 28 */ -#define MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT 26 /********* ISR0 Register offset **********/ #define CEV_ISR0_OFFSET 0xC18 diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index da5341f1038..9c8654d9c50 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1279,7 +1279,7 @@ static irqreturn_t be_intx(int irq, void *dev) int isr; isr = ioread32(adapter->csr + CEV_ISR0_OFFSET + - adapter->pci_func * CEV_ISR_SIZE); + be_pci_func(adapter) * CEV_ISR_SIZE); if (!isr) return IRQ_NONE; @@ -1446,7 +1446,7 @@ static void be_msix_enable(struct be_adapter *adapter) static inline int be_msix_vec_get(struct be_adapter *adapter, u32 eq_id) { - return adapter->msix_entries[eq_id - 8 * adapter->pci_func].vector; + return adapter->msix_entries[eq_id - 8 * be_pci_func(adapter)].vector; } static int be_msix_register(struct be_adapter *adapter) @@ -1743,7 +1743,6 @@ static int be_ctrl_init(struct be_adapter *adapter) struct be_dma_mem *mbox_mem_alloc = &adapter->mbox_mem_alloced; struct be_dma_mem *mbox_mem_align = &adapter->mbox_mem; int status; - u32 val; status = be_map_pci_bars(adapter); if (status) @@ -1764,9 +1763,6 @@ static int be_ctrl_init(struct be_adapter *adapter) spin_lock_init(&adapter->mcc_lock); spin_lock_init(&adapter->mcc_cq_lock); - val = ioread32(adapter->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET); - adapter->pci_func = (val >> MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT) & - MEMBAR_CTRL_INT_CTRL_PFUNC_MASK; return 0; } -- cgit v1.2.3-18-g5258 From 5f0b849eb35d09cd2f332d5031051c1a8976c30b Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 27 Jul 2009 22:52:56 +0000 Subject: be2net: replace some printks with dev_err()/dev_warn() And get rid of some unnecessary printks. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/benet/be_cmds.c | 26 ++++++++++---------------- drivers/net/benet/be_main.c | 17 +++++------------ 2 files changed, 15 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index daa2fe82b64..7c1724eaf76 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -62,8 +62,8 @@ static int be_mcc_compl_process(struct be_adapter *adapter, if (compl_status != MCC_STATUS_SUCCESS) { extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) & CQE_STATUS_EXTD_MASK; - printk(KERN_WARNING DRV_NAME - " error in cmd completion: status(compl/extd)=%d/%d\n", + dev_warn(&adapter->pdev->dev, + "Error in cmd completion: status(compl/extd)=%d/%d\n", compl_status, extd_status); return -1; } @@ -135,7 +135,7 @@ static void be_mcc_wait_compl(struct be_adapter *adapter) udelay(100); } if (i == mcc_timeout) - printk(KERN_WARNING DRV_NAME "mcc poll timed out\n"); + dev_err(&adapter->pdev->dev, "mccq poll timed out\n"); } /* Notify MCC requests and wait for completion */ @@ -145,7 +145,7 @@ static void be_mcc_notify_wait(struct be_adapter *adapter) be_mcc_wait_compl(adapter); } -static int be_mbox_db_ready_wait(void __iomem *db) +static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) { int cnt = 0, wait = 5; u32 ready; @@ -156,8 +156,7 @@ static int be_mbox_db_ready_wait(void __iomem *db) break; if (cnt > 200000) { - printk(KERN_WARNING DRV_NAME - ": mbox_db poll timed out\n"); + dev_err(&adapter->pdev->dev, "mbox poll timed out\n"); return -1; } @@ -185,25 +184,22 @@ static int be_mbox_db_ring(struct be_adapter *adapter) memset(cqe, 0, sizeof(*cqe)); - val &= ~MPU_MAILBOX_DB_RDY_MASK; val |= MPU_MAILBOX_DB_HI_MASK; /* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */ val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2; iowrite32(val, db); /* wait for ready to be set */ - status = be_mbox_db_ready_wait(db); + status = be_mbox_db_ready_wait(adapter, db); if (status != 0) return status; val = 0; - val &= ~MPU_MAILBOX_DB_RDY_MASK; - val &= ~MPU_MAILBOX_DB_HI_MASK; /* at bits 2 - 31 place mbox dma addr lsb bits 4 - 33 */ val |= (u32)(mbox_mem->dma >> 4) << 2; iowrite32(val, db); - status = be_mbox_db_ready_wait(db); + status = be_mbox_db_ready_wait(adapter, db); if (status != 0) return status; @@ -214,7 +210,7 @@ static int be_mbox_db_ring(struct be_adapter *adapter) if (status) return status; } else { - printk(KERN_WARNING DRV_NAME "invalid mailbox completion\n"); + dev_err(&adapter->pdev->dev, "invalid mailbox completion\n"); return -1; } return 0; @@ -705,15 +701,13 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, opcode = OPCODE_COMMON_MCC_DESTROY; break; default: - printk(KERN_WARNING DRV_NAME ":bad Q type in Q destroy cmd\n"); - status = -1; - goto err; + BUG(); } be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req)); req->id = cpu_to_le16(q->id); status = be_mbox_db_ring(adapter); -err: + spin_unlock(&adapter->mbox_lock); return status; diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 9c8654d9c50..ab5fcc0c5b1 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -66,15 +66,14 @@ static void be_intr_set(struct be_adapter *adapter, bool enable) u8 __iomem *addr = adapter->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET; u32 reg = ioread32(addr); u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; - if (!enabled && enable) { + + if (!enabled && enable) reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; - } else if (enabled && !enable) { + else if (enabled && !enable) reg &= ~MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; - } else { - printk(KERN_WARNING DRV_NAME - ": bad value in membar_int_ctrl reg=0x%x\n", reg); + else return; - } + iowrite32(reg, addr); } @@ -1981,12 +1980,6 @@ static int __init be_init_module(void) " Using 2048\n"); rx_frag_size = 2048; } - /* Ensure rx_frag_size is aligned to chache line */ - if (SKB_DATA_ALIGN(rx_frag_size) != rx_frag_size) { - printk(KERN_WARNING DRV_NAME - " : Bad module param rx_frag_size. Using 2048\n"); - rx_frag_size = 2048; - } return pci_register_driver(&be_driver); } -- cgit v1.2.3-18-g5258 From efd2e40a8cc891e8f90e0bdde000006bd6201530 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 27 Jul 2009 22:53:10 +0000 Subject: be2net: some name changes for consistency be_mbox_db_ring() has been changed to be_mbox_notify() (to be consistent with be_mcc_notify()) and struct be_mcc_cq_entry changed to be_mcc_compl to be consistent with rx/tx_compl. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/benet/be_cmds.c | 62 ++++++++++++++++++++++----------------------- drivers/net/benet/be_cmds.h | 4 +-- drivers/net/benet/be_main.c | 2 +- 3 files changed, 34 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 7c1724eaf76..ebf65c78819 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -31,7 +31,7 @@ static void be_mcc_notify(struct be_adapter *adapter) /* To check if valid bit is set, check the entire word as we don't know * the endianness of the data (old entry is host endian while a new entry is * little endian) */ -static inline bool be_mcc_compl_is_new(struct be_mcc_cq_entry *compl) +static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl) { if (compl->flags != 0) { compl->flags = le32_to_cpu(compl->flags); @@ -43,13 +43,13 @@ static inline bool be_mcc_compl_is_new(struct be_mcc_cq_entry *compl) } /* Need to reset the entire word that houses the valid bit */ -static inline void be_mcc_compl_use(struct be_mcc_cq_entry *compl) +static inline void be_mcc_compl_use(struct be_mcc_compl *compl) { compl->flags = 0; } static int be_mcc_compl_process(struct be_adapter *adapter, - struct be_mcc_cq_entry *compl) + struct be_mcc_compl *compl) { u16 compl_status, extd_status; @@ -85,10 +85,10 @@ static inline bool is_link_state_evt(u32 trailer) ASYNC_EVENT_CODE_LINK_STATE); } -static struct be_mcc_cq_entry *be_mcc_compl_get(struct be_adapter *adapter) +static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter) { struct be_queue_info *mcc_cq = &adapter->mcc_obj.cq; - struct be_mcc_cq_entry *compl = queue_tail_node(mcc_cq); + struct be_mcc_compl *compl = queue_tail_node(mcc_cq); if (be_mcc_compl_is_new(compl)) { queue_tail_inc(mcc_cq); @@ -99,7 +99,7 @@ static struct be_mcc_cq_entry *be_mcc_compl_get(struct be_adapter *adapter) void be_process_mcc(struct be_adapter *adapter) { - struct be_mcc_cq_entry *compl; + struct be_mcc_compl *compl; int num = 0; spin_lock_bh(&adapter->mcc_cq_lock); @@ -173,16 +173,16 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) * Insert the mailbox address into the doorbell in two steps * Polls on the mbox doorbell till a command completion (or a timeout) occurs */ -static int be_mbox_db_ring(struct be_adapter *adapter) +static int be_mbox_notify(struct be_adapter *adapter) { int status; u32 val = 0; void __iomem *db = adapter->db + MPU_MAILBOX_DB_OFFSET; struct be_dma_mem *mbox_mem = &adapter->mbox_mem; struct be_mcc_mailbox *mbox = mbox_mem->va; - struct be_mcc_cq_entry *cqe = &mbox->cqe; + struct be_mcc_compl *compl = &mbox->compl; - memset(cqe, 0, sizeof(*cqe)); + memset(compl, 0, sizeof(*compl)); val |= MPU_MAILBOX_DB_HI_MASK; /* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */ @@ -204,9 +204,9 @@ static int be_mbox_db_ring(struct be_adapter *adapter) return status; /* A cq entry has been made now */ - if (be_mcc_compl_is_new(cqe)) { - status = be_mcc_compl_process(adapter, &mbox->cqe); - be_mcc_compl_use(cqe); + if (be_mcc_compl_is_new(compl)) { + status = be_mcc_compl_process(adapter, &mbox->compl); + be_mcc_compl_use(compl); if (status) return status; } else { @@ -396,7 +396,7 @@ int be_cmd_eq_create(struct be_adapter *adapter, be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { eq->id = le16_to_cpu(resp->eq_id); eq->created = true; @@ -429,7 +429,7 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, req->permanent = 0; } - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) memcpy(mac_addr, resp->mac.addr, ETH_ALEN); @@ -455,7 +455,7 @@ int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, req->if_id = cpu_to_le32(if_id); memcpy(req->mac_address, mac_addr, ETH_ALEN); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { struct be_cmd_resp_pmac_add *resp = embedded_payload(wrb); *pmac_id = le32_to_cpu(resp->pmac_id); @@ -482,7 +482,7 @@ int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id) req->if_id = cpu_to_le32(if_id); req->pmac_id = cpu_to_le32(pmac_id); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); spin_unlock(&adapter->mbox_lock); return status; @@ -523,7 +523,7 @@ int be_cmd_cq_create(struct be_adapter *adapter, be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { cq->id = le16_to_cpu(resp->cq_id); cq->created = true; @@ -571,7 +571,7 @@ int be_cmd_mccq_create(struct be_adapter *adapter, be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb); mccq->id = le16_to_cpu(resp->id); @@ -618,7 +618,7 @@ int be_cmd_txq_create(struct be_adapter *adapter, be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { struct be_cmd_resp_eth_tx_create *resp = embedded_payload(wrb); txq->id = le16_to_cpu(resp->cid); @@ -654,7 +654,7 @@ int be_cmd_rxq_create(struct be_adapter *adapter, req->max_frame_size = cpu_to_le16(max_frame_size); req->rss_queue = cpu_to_le32(rss); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { struct be_cmd_resp_eth_rx_create *resp = embedded_payload(wrb); rxq->id = le16_to_cpu(resp->id); @@ -706,7 +706,7 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req)); req->id = cpu_to_le16(q->id); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); spin_unlock(&adapter->mbox_lock); @@ -734,7 +734,7 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 flags, u8 *mac, if (!pmac_invalid) memcpy(req->mac_addr, mac, ETH_ALEN); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { struct be_cmd_resp_if_create *resp = embedded_payload(wrb); *if_handle = le32_to_cpu(resp->interface_id); @@ -761,7 +761,7 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id) OPCODE_COMMON_NTWK_INTERFACE_DESTROY, sizeof(*req)); req->interface_id = cpu_to_le32(interface_id); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); spin_unlock(&adapter->mbox_lock); @@ -791,7 +791,7 @@ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); sge->len = cpu_to_le32(nonemb_cmd->size); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { struct be_cmd_resp_get_stats *resp = nonemb_cmd->va; be_dws_le_to_cpu(&resp->hw_stats, sizeof(resp->hw_stats)); @@ -818,7 +818,7 @@ int be_cmd_link_status_query(struct be_adapter *adapter, be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, sizeof(*req)); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { struct be_cmd_resp_link_status *resp = embedded_payload(wrb); if (resp->mac_speed != PHY_LINK_SPEED_ZERO) @@ -843,7 +843,7 @@ int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver) be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_GET_FW_VERSION, sizeof(*req)); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { struct be_cmd_resp_get_fw_version *resp = embedded_payload(wrb); strncpy(fw_ver, resp->firmware_version_string, FW_VER_LEN); @@ -873,7 +873,7 @@ int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd) req->delay[0].phase = 0; req->delay[0].delay_multiplier = cpu_to_le32(eqd); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); spin_unlock(&adapter->mbox_lock); return status; @@ -903,7 +903,7 @@ int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array, req->num_vlan * sizeof(vtag_array[0])); } - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); spin_unlock(&adapter->mbox_lock); return status; @@ -999,7 +999,7 @@ int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc) req->tx_flow_control = cpu_to_le16((u16)tx_fc); req->rx_flow_control = cpu_to_le16((u16)rx_fc); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); spin_unlock(&adapter->mbox_lock); return status; @@ -1020,7 +1020,7 @@ int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc) be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_GET_FLOW_CONTROL, sizeof(*req)); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { struct be_cmd_resp_get_flow_control *resp = embedded_payload(wrb); @@ -1047,7 +1047,7 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num) be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, sizeof(*req)); - status = be_mbox_db_ring(adapter); + status = be_mbox_notify(adapter); if (!status) { struct be_cmd_resp_query_fw_cfg *resp = embedded_payload(wrb); *port_num = le32_to_cpu(resp->phys_port); diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 164ab927782..5c5de3540d2 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -69,7 +69,7 @@ enum { #define CQE_STATUS_EXTD_MASK 0xFFFF #define CQE_STATUS_EXTD_SHIFT 0 /* bits 0 - 15 */ -struct be_mcc_cq_entry { +struct be_mcc_compl { u32 status; /* dword 0 */ u32 tag0; /* dword 1 */ u32 tag1; /* dword 2 */ @@ -106,7 +106,7 @@ struct be_async_event_link_state { struct be_mcc_mailbox { struct be_mcc_wrb wrb; - struct be_mcc_cq_entry cqe; + struct be_mcc_compl compl; }; #define CMD_SUBSYSTEM_COMMON 0x1 diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index ab5fcc0c5b1..ef82a52f393 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1058,7 +1058,7 @@ static int be_mcc_queues_create(struct be_adapter *adapter) /* Alloc MCC compl queue */ cq = &adapter->mcc_obj.cq; if (be_queue_alloc(adapter, cq, MCC_CQ_LEN, - sizeof(struct be_mcc_cq_entry))) + sizeof(struct be_mcc_compl))) goto err; /* Ask BE to create MCC compl queue; share TX's eq */ -- cgit v1.2.3-18-g5258 From d9509ac1295ce2ec121333d29b8a85a9e564f817 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 27 Jul 2009 22:53:30 +0000 Subject: be2net: delete unnecessary code from be_cmd_POST() When the driver loads the POST stage of the card is expected to be POST_STAGE_ARMFW_RDY. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/benet/be_cmds.c | 45 ++++----------------------------------------- 1 file changed, 4 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index ebf65c78819..de107732dcd 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -227,54 +227,17 @@ static int be_POST_stage_get(struct be_adapter *adapter, u16 *stage) return 0; } -static int be_POST_stage_poll(struct be_adapter *adapter, u16 poll_stage) -{ - u16 stage, cnt, error; - for (cnt = 0; cnt < 5000; cnt++) { - error = be_POST_stage_get(adapter, &stage); - if (error) - return -1; - - if (stage == poll_stage) - break; - udelay(1000); - } - if (stage != poll_stage) - return -1; - return 0; -} - - int be_cmd_POST(struct be_adapter *adapter) { u16 stage, error; error = be_POST_stage_get(adapter, &stage); - if (error) - goto err; - - if (stage == POST_STAGE_ARMFW_RDY) - return 0; - - if (stage != POST_STAGE_AWAITING_HOST_RDY) - goto err; - - /* On awaiting host rdy, reset and again poll on awaiting host rdy */ - iowrite32(POST_STAGE_BE_RESET, adapter->csr + MPU_EP_SEMAPHORE_OFFSET); - error = be_POST_stage_poll(adapter, POST_STAGE_AWAITING_HOST_RDY); - if (error) - goto err; - - /* Now kickoff POST and poll on armfw ready */ - iowrite32(POST_STAGE_HOST_RDY, adapter->csr + MPU_EP_SEMAPHORE_OFFSET); - error = be_POST_stage_poll(adapter, POST_STAGE_ARMFW_RDY); - if (error) - goto err; + if (error || stage != POST_STAGE_ARMFW_RDY) { + dev_err(&adapter->pdev->dev, "POST failed.\n"); + return -1; + } return 0; -err: - printk(KERN_WARNING DRV_NAME ": ERROR, stage=%d\n", stage); - return -1; } static inline void *embedded_payload(struct be_mcc_wrb *wrb) -- cgit v1.2.3-18-g5258 From 005fb4f0330afb2916ddc3f3c4c70e4555d64758 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 31 Jul 2009 09:13:02 +0000 Subject: atl1c: return PCI_ERS_RESULT_DISCONNECT on permanent failure PCI drivers that implement the struct pci_error_handlers' error_detected callback should return PCI_ERS_RESULT_DISCONNECT if the state passed in is pci_channel_io_perm_failure. This patch fixes the issue for atl1c. Signed-off-by: Dean Nelson Signed-off-by: David S. Miller --- drivers/net/atl1c/atl1c_main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index a383122679d..1d601ce7d5b 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -2678,6 +2678,9 @@ static pci_ers_result_t atl1c_io_error_detected(struct pci_dev *pdev, netif_device_detach(netdev); + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + if (netif_running(netdev)) atl1c_down(adapter); -- cgit v1.2.3-18-g5258 From 0d6ab58da0465c42f34d9d4e7d91510278183c80 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 31 Jul 2009 09:13:10 +0000 Subject: atl1e: return PCI_ERS_RESULT_DISCONNECT on permanent failure PCI drivers that implement the struct pci_error_handlers' error_detected callback should return PCI_ERS_RESULT_DISCONNECT if the state passed in is pci_channel_io_perm_failure. This patch fixes the issue for atl1e. Signed-off-by: Dean Nelson Signed-off-by: David S. Miller --- drivers/net/atl1e/atl1e_main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index 9fc6d6d9060..4570749e3d3 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -2497,6 +2497,9 @@ atl1e_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) netif_device_detach(netdev); + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + if (netif_running(netdev)) atl1e_down(adapter); -- cgit v1.2.3-18-g5258 From 2ec3de26d2dc666159b79a8b9394fa00b6f414ae Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 31 Jul 2009 09:13:18 +0000 Subject: bnx2: return PCI_ERS_RESULT_DISCONNECT on permanent failure PCI drivers that implement the struct pci_error_handlers' error_detected callback should return PCI_ERS_RESULT_DISCONNECT if the state passed in is pci_channel_io_perm_failure. This patch fixes the issue for bnx2. Signed-off-by: Dean Nelson Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index cec1b1746ae..756d4b4f0a9 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -8199,6 +8199,11 @@ static pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev, rtnl_lock(); netif_device_detach(dev); + if (state == pci_channel_io_perm_failure) { + rtnl_unlock(); + return PCI_ERS_RESULT_DISCONNECT; + } + if (netif_running(dev)) { bnx2_netif_stop(bp); del_timer_sync(&bp->timer); -- cgit v1.2.3-18-g5258 From 07ce50e434b62c4de05207109ecd3d615b3cce42 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 31 Jul 2009 09:13:25 +0000 Subject: bnx2x: return PCI_ERS_RESULT_DISCONNECT on permanent failure PCI drivers that implement the struct pci_error_handlers' error_detected callback should return PCI_ERS_RESULT_DISCONNECT if the state passed in is pci_channel_io_perm_failure. This patch fixes the issue for bnx2x. Signed-off-by: Dean Nelson Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 2d035d795f0..c92d1a49886 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -11690,6 +11690,11 @@ static pci_ers_result_t bnx2x_io_error_detected(struct pci_dev *pdev, netif_device_detach(dev); + if (state == pci_channel_io_perm_failure) { + rtnl_unlock(); + return PCI_ERS_RESULT_DISCONNECT; + } + if (netif_running(dev)) bnx2x_eeh_nic_unload(bp); -- cgit v1.2.3-18-g5258 From c06c430dedf71a0e9180d673191b9c9368aeaa65 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 31 Jul 2009 09:13:33 +0000 Subject: igbvf: return PCI_ERS_RESULT_DISCONNECT on permanent failure PCI drivers that implement the struct pci_error_handlers' error_detected callback should return PCI_ERS_RESULT_DISCONNECT if the state passed in is pci_channel_io_perm_failure. This patch fixes the issue for igbvf. Signed-off-by: Dean Nelson Signed-off-by: David S. Miller --- drivers/net/igbvf/netdev.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index 926c31b4726..3f03c42ece9 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -2511,6 +2511,9 @@ static pci_ers_result_t igbvf_io_error_detected(struct pci_dev *pdev, netif_device_detach(netdev); + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + if (netif_running(netdev)) igbvf_down(adapter); pci_disable_device(pdev); -- cgit v1.2.3-18-g5258 From d6a1f83b63e6999ee9374330ea2d7924e775aff7 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 31 Jul 2009 09:13:40 +0000 Subject: ixgb: return PCI_ERS_RESULT_DISCONNECT on permanent failure PCI drivers that implement the struct pci_error_handlers' error_detected callback should return PCI_ERS_RESULT_DISCONNECT if the state passed in is pci_channel_io_perm_failure. This patch fixes the issue for ixgb. Signed-off-by: Dean Nelson Signed-off-by: David S. Miller --- drivers/net/ixgb/ixgb_main.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index eb917f16027..fad08ce8a6c 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -2227,6 +2227,11 @@ static pci_ers_result_t ixgb_io_error_detected(struct pci_dev *pdev, struct net_device *netdev = pci_get_drvdata(pdev); struct ixgb_adapter *adapter = netdev_priv(netdev); + netif_device_detach(netdev); + + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + if (netif_running(netdev)) ixgb_down(adapter, true); -- cgit v1.2.3-18-g5258 From fbc663ceeb7a48481a3b0290040528fbfd207282 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 31 Jul 2009 09:13:48 +0000 Subject: qlge: return PCI_ERS_RESULT_DISCONNECT on permanent failure PCI drivers that implement the struct pci_error_handlers' error_detected callback should return PCI_ERS_RESULT_DISCONNECT if the state passed in is pci_channel_io_perm_failure. This patch fixes the issue for qlge. Signed-off-by: Dean Nelson Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 5768af17f16..3a271afdd8f 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -4076,6 +4076,11 @@ static pci_ers_result_t qlge_io_error_detected(struct pci_dev *pdev, struct net_device *ndev = pci_get_drvdata(pdev); struct ql_adapter *qdev = netdev_priv(ndev); + netif_device_detach(ndev); + + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + if (netif_running(ndev)) ql_adapter_down(qdev); -- cgit v1.2.3-18-g5258 From 1e3c8bd63854a620680323681f28e60a44e26f0e Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 31 Jul 2009 09:13:56 +0000 Subject: s2io: return PCI_ERS_RESULT_DISCONNECT on permanent failure PCI drivers that implement the struct pci_error_handlers' error_detected callback should return PCI_ERS_RESULT_DISCONNECT if the state passed in is pci_channel_io_perm_failure. This patch fixes the issue for s2io. Signed-off-by: Dean Nelson Signed-off-by: David S. Miller --- drivers/net/s2io.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index d4df9330c44..bd6d713c861 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -8636,6 +8636,9 @@ static pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev, netif_device_detach(netdev); + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + if (netif_running(netdev)) { /* Bring down the card, while avoiding PCI I/O */ do_s2io_card_down(sp, 0); -- cgit v1.2.3-18-g5258 From e33b992d1504f21a8c2173245aeca4fc2ad632ab Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 31 Jul 2009 09:14:03 +0000 Subject: vxge: return PCI_ERS_RESULT_DISCONNECT on permanent failure PCI drivers that implement the struct pci_error_handlers' error_detected callback should return PCI_ERS_RESULT_DISCONNECT if the state passed in is pci_channel_io_perm_failure. This patch fixes the issue for vxge. Signed-off-by: Dean Nelson Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 7b5402b50d0..335140d2834 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -3956,6 +3956,9 @@ static pci_ers_result_t vxge_io_error_detected(struct pci_dev *pdev, netif_device_detach(netdev); + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + if (netif_running(netdev)) { /* Bring down the card, while avoiding PCI I/O */ do_vxge_close(netdev, 0); -- cgit v1.2.3-18-g5258 From c1dc0b9c0c8979ce4d411caadff5c0d79dee58bc Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 2 Aug 2009 11:28:21 +0200 Subject: debug lockups: Improve lockup detection When debugging a recent lockup bug i found various deficiencies in how our current lockup detection helpers work: - SysRq-L is not very efficient as it uses a workqueue, hence it cannot punch through hard lockups and cannot see through most soft lockups either. - The SysRq-L code depends on the NMI watchdog - which is off by default. - We dont print backtraces from the RCU code's built-in 'RCU state machine is stuck' debug code. This debug code tends to be one of the first (and only) mechanisms that show that a lockup has occured. This patch changes the code so taht we: - Trigger the NMI backtrace code from SysRq-L instead of using a workqueue (which cannot punch through hard lockups) - Trigger print-all-CPU-backtraces from the RCU lockup detection code Also decouple the backtrace printing code from the NMI watchdog: - Dont use variable size cpumasks (it might not be initialized and they are a bit more fragile anyway) - Trigger an NMI immediately via an IPI, instead of waiting for the NMI tick to occur. This is a lot faster and can produce more relevant backtraces. It will also work if the NMI watchdog is disabled. - Dont print the 'dazed and confused' message when we print a backtrace from the NMI - Do a show_regs() plus a dump_stack() to get maximum info out of the dump. Worst-case we get two stacktraces - which is not a big deal. Sometimes, if register content is corrupted, the precise stack walker in show_regs() wont give us a full backtrace - in this case dump_stack() will do it. Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Andrew Morton Cc: Linus Torvalds LKML-Reference: Signed-off-by: Ingo Molnar --- drivers/char/sysrq.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 5d7a02f63e1..165f307f30e 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -222,12 +223,7 @@ static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus); static void sysrq_handle_showallcpus(int key, struct tty_struct *tty) { - struct pt_regs *regs = get_irq_regs(); - if (regs) { - printk(KERN_INFO "CPU%d:\n", smp_processor_id()); - show_regs(regs); - } - schedule_work(&sysrq_showallcpus); + trigger_all_cpu_backtrace(); } static struct sysrq_key_op sysrq_showallcpus_op = { -- cgit v1.2.3-18-g5258 From 9450526ac7bd74edf1ee030841d8078c6db6ca0b Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Thu, 30 Jul 2009 21:23:34 +0000 Subject: cxgb3: fix EDC filename string Fix a cut'n paste error in the AEL2020 twinax EDC file name Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller --- drivers/net/cxgb3/cxgb3_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index ec05149a906..8b3e76c1cf5 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -993,7 +993,7 @@ static int bind_qsets(struct adapter *adap) #define TPSRAM_NAME "cxgb3/t3%c_psram-%d.%d.%d.bin" #define AEL2005_OPT_EDC_NAME "cxgb3/ael2005_opt_edc.bin" #define AEL2005_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin" -#define AEL2020_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin" +#define AEL2020_TWX_EDC_NAME "cxgb3/ael2020_twx_edc.bin" static inline const char *get_edc_fw_name(int edc_idx) { -- cgit v1.2.3-18-g5258 From 88e7b76ef7cf939a0cf23a1902030211b20837fe Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Thu, 30 Jul 2009 21:23:39 +0000 Subject: cxgb3: fix Gen2 pci default settings Modify control register settings to accommodate the bridge's max read requset size. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller --- drivers/net/cxgb3/t3_hw.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index e78d341cbd6..526e144b8b7 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -3465,7 +3465,7 @@ static void config_pcie(struct adapter *adap) {201, 321, 258, 450, 834, 1602} }; - u16 val; + u16 val, devid; unsigned int log2_width, pldsize; unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt; @@ -3473,6 +3473,17 @@ static void config_pcie(struct adapter *adap) adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL, &val); pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5; + + pci_read_config_word(adap->pdev, 0x2, &devid); + if (devid == 0x37) { + pci_write_config_word(adap->pdev, + adap->params.pci.pcie_cap_addr + + PCI_EXP_DEVCTL, + val & ~PCI_EXP_DEVCTL_READRQ & + ~PCI_EXP_DEVCTL_PAYLOAD); + pldsize = 0; + } + pci_read_config_word(adap->pdev, adap->params.pci.pcie_cap_addr + PCI_EXP_LNKCTL, &val); -- cgit v1.2.3-18-g5258 From 39506a552b4b302540e1f9c6c93a122df353e57d Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 1 Aug 2009 09:51:06 +0000 Subject: drivers/net: Use DIV_ROUND_CLOSEST The kernel.h macro DIV_ROUND_CLOSEST performs the computation (x + d/2)/d but is perhaps more readable. The semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @haskernel@ @@ #include @depends on haskernel@ expression x,__divisor; @@ - (((x) + ((__divisor) / 2)) / (__divisor)) + DIV_ROUND_CLOSEST(x,__divisor) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/b44.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 1f7f015442d..07c92f34d8d 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1297,7 +1297,8 @@ static void b44_chip_reset(struct b44 *bp, int reset_kind) switch (sdev->bus->bustype) { case SSB_BUSTYPE_SSB: bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | - (((ssb_clockspeed(sdev->bus) + (B44_MDC_RATIO / 2)) / B44_MDC_RATIO) + (DIV_ROUND_CLOSEST(ssb_clockspeed(sdev->bus), + B44_MDC_RATIO) & MDIO_CTRL_MAXF_MASK))); break; case SSB_BUSTYPE_PCI: -- cgit v1.2.3-18-g5258 From 8b97c7c283c5ba8f9f4dabd418fd7dcfcc8a387e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 1 Aug 2009 22:48:45 +0000 Subject: drivers/atm: Use DIV_ROUND_CLOSEST The kernel.h macro DIV_ROUND_CLOSEST performs the computation (x + d/2)/d but is perhaps more readable. The semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @haskernel@ @@ #include @depends on haskernel@ expression x,__divisor; @@ - (((x) + ((__divisor) / 2)) / (__divisor)) + DIV_ROUND_CLOSEST(x,__divisor) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/atm/horizon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index 6b969f8c684..01ce241dbea 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -641,7 +641,7 @@ static int make_rate (const hrz_dev * dev, u32 c, rounding r, pre = 1; break; case round_nearest: - pre = (br+(c< Date: Tue, 28 Jul 2009 02:37:58 +0000 Subject: smsc95xx: remove EEPROM loaded check The eeprom read & write commands currently check the E2P_CMD_LOADED_ bit is set before allowing any operations. This prevents any reading or writing unless a correctly programmed EEPROM is installed. This patch removes the check, so it is possible to program blank EEPROMS via ethtool. Signed-off-by: Steve Glendinning Signed-off-by: David S. Miller --- drivers/net/usb/smsc95xx.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index fe045896406..09bd6351f64 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -220,11 +220,6 @@ static int smsc95xx_eeprom_confirm_not_busy(struct usbnet *dev) do { smsc95xx_read_reg(dev, E2P_CMD, &val); - if (!(val & E2P_CMD_LOADED_)) { - devwarn(dev, "No EEPROM present"); - return -EIO; - } - if (!(val & E2P_CMD_BUSY_)) return 0; -- cgit v1.2.3-18-g5258 From 47cab6a722d44c71c4f8224017ef548522243cf4 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 3 Aug 2009 09:31:54 +0200 Subject: debug lockups: Improve lockup detection, fix generic arch fallback As Andrew noted, my previous patch ("debug lockups: Improve lockup detection") broke/removed SysRq-L support from architecture that do not provide a __trigger_all_cpu_backtrace implementation. Restore a fallback path and clean up the SysRq-L machinery a bit: - Rename the arch method to arch_trigger_all_cpu_backtrace() - Simplify the define - Document the method a bit - in the hope of more architectures adding support for it. [ The patch touches Sparc code for the rename. ] Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Andrew Morton Cc: Linus Torvalds Cc: "David S. Miller" LKML-Reference: <20090802140809.7ec4bb6b.akpm@linux-foundation.org> Signed-off-by: Ingo Molnar --- drivers/char/sysrq.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 165f307f30e..50eecfe1d72 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -223,7 +223,20 @@ static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus); static void sysrq_handle_showallcpus(int key, struct tty_struct *tty) { - trigger_all_cpu_backtrace(); + /* + * Fall back to the workqueue based printing if the + * backtrace printing did not succeed or the + * architecture has no support for it: + */ + if (!trigger_all_cpu_backtrace()) { + struct pt_regs *regs = get_irq_regs(); + + if (regs) { + printk(KERN_INFO "CPU%d:\n", smp_processor_id()); + show_regs(regs); + } + schedule_work(&sysrq_showallcpus); + } } static struct sysrq_key_op sysrq_showallcpus_op = { -- cgit v1.2.3-18-g5258 From 9851bad7a3ab601b8b5b156119a7d0fd15b47fa3 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 11:53:02 -0700 Subject: ath9k: re-order cancelling of work on mac80211 workqueue ath9k uses the mac80211 workqueue for 4 different types of work: * Led blink work * TX hang monitoring work * internal wiphy schedular work * channel change work done for internal wiphy schedular Since the internal wiphy schedular can end up kicking off some channel channel change work we should first cancel the wiphy schedular work and then the channel change work. The TX hang work can be cancelled second since we're going down anyway. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 75ddb2acb64..49f27648fec 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1252,9 +1252,9 @@ void ath_detach(struct ath_softc *sc) DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n"); ath_deinit_leds(sc); - cancel_work_sync(&sc->chan_work); - cancel_delayed_work_sync(&sc->wiphy_work); cancel_delayed_work_sync(&sc->tx_complete_work); + cancel_delayed_work_sync(&sc->wiphy_work); + cancel_work_sync(&sc->chan_work); for (i = 0; i < sc->num_sec_wiphy; i++) { struct ath_wiphy *aphy = sc->sec_wiphy[i]; -- cgit v1.2.3-18-g5258 From 35c95ab9b5ea3a2bf69d049d5437bb831e9bddf3 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 11:53:03 -0700 Subject: ath9k: move cancel_delayed_work_sync() out of ath_deinit_leds() We do this as we'll be moving the cancel elsewhere later. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 49f27648fec..7437b4295b2 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1056,7 +1056,6 @@ static void ath_unregister_led(struct ath_led *led) static void ath_deinit_leds(struct ath_softc *sc) { - cancel_delayed_work_sync(&sc->ath_led_blink_work); ath_unregister_led(&sc->assoc_led); sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; ath_unregister_led(&sc->tx_led); @@ -1113,6 +1112,7 @@ static void ath_init_leds(struct ath_softc *sc) return; fail: + cancel_delayed_work_sync(&sc->ath_led_blink_work); ath_deinit_leds(sc); } @@ -1251,11 +1251,13 @@ void ath_detach(struct ath_softc *sc) DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n"); - ath_deinit_leds(sc); + cancel_delayed_work_sync(&sc->ath_led_blink_work); cancel_delayed_work_sync(&sc->tx_complete_work); cancel_delayed_work_sync(&sc->wiphy_work); cancel_work_sync(&sc->chan_work); + ath_deinit_leds(sc); + for (i = 0; i < sc->num_sec_wiphy; i++) { struct ath_wiphy *aphy = sc->sec_wiphy[i]; if (aphy == NULL) -- cgit v1.2.3-18-g5258 From c94dbff7996b861fb0ff730bdf6eac4e2b288402 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 11:53:04 -0700 Subject: ath9k: move workqueue cancels to stop callback We should be cancelling our work at the stop callback since we are borrowing the mac80211 workqueue for our work. As it stands mac80211 expects this for suspend purposes. The ath9k specific virtual wiphy stuff need only be cancelled only when the we have no secondary virtual wiphys. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 7437b4295b2..cf44623b5cd 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1251,11 +1251,6 @@ void ath_detach(struct ath_softc *sc) DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n"); - cancel_delayed_work_sync(&sc->ath_led_blink_work); - cancel_delayed_work_sync(&sc->tx_complete_work); - cancel_delayed_work_sync(&sc->wiphy_work); - cancel_work_sync(&sc->chan_work); - ath_deinit_leds(sc); for (i = 0; i < sc->num_sec_wiphy; i++) { @@ -2091,6 +2086,14 @@ static void ath9k_stop(struct ieee80211_hw *hw) aphy->state = ATH_WIPHY_INACTIVE; + cancel_delayed_work_sync(&sc->ath_led_blink_work); + cancel_delayed_work_sync(&sc->tx_complete_work); + + if (!sc->num_sec_wiphy) { + cancel_delayed_work_sync(&sc->wiphy_work); + cancel_work_sync(&sc->chan_work); + } + if (sc->sc_flags & SC_OP_INVALID) { DPRINTF(sc, ATH_DBG_ANY, "Device not present\n"); return; -- cgit v1.2.3-18-g5258 From ebc8ab17d69cbaec6bb345a48a2cb87047643f63 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 11:56:23 -0700 Subject: ar76c50x-usb: cancel promisc work during mac80211 stop We weren't ever cancelling this. Signed-off-by: Luis R. Rodriguez Acked-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/at76c50x-usb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 13303fa3473..bbf5277aeef 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1773,6 +1773,8 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw) at76_dbg(DBG_MAC80211, "%s()", __func__); + cancel_work_sync(&priv->work_set_promisc); + mutex_lock(&priv->mtx); if (!priv->device_unplugged) { -- cgit v1.2.3-18-g5258 From 9ed21d390166ceb89e011d3dbd277475ff2f33c4 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 11:56:24 -0700 Subject: at76c50x-usb: cancel scan work at stop callback This should fix suspend as mac80211 expects all work queued to the mac80211 workqueue to be canceled at driver stop(). Signed-off-by: Luis R. Rodriguez Acked-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/at76c50x-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index bbf5277aeef..f46e2b33b1f 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1773,6 +1773,7 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw) at76_dbg(DBG_MAC80211, "%s()", __func__); + cancel_delayed_work(&priv->dwork_hw_scan); cancel_work_sync(&priv->work_set_promisc); mutex_lock(&priv->mtx); @@ -2298,7 +2299,6 @@ static void at76_delete_device(struct at76_priv *priv) tasklet_kill(&priv->rx_tasklet); if (priv->mac80211_registered) { - cancel_delayed_work(&priv->dwork_hw_scan); flush_workqueue(priv->hw->workqueue); ieee80211_unregister_hw(priv->hw); } -- cgit v1.2.3-18-g5258 From e351cfbf4e6ccd8bf32555748a49dba5bc93fcb0 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 12:51:37 -0700 Subject: ar9170: remove unneeded flush_workqueue() cancel_delayed_work_sync() and cancel_work_sync() are already being used therefore already waiting for all pending work by the driver to have been completed, no need to flush the mac80211 workqueue. Cc: Christian Lamparter Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 85a1452a7c3..099ed3c3ba2 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -1290,14 +1290,13 @@ static void ar9170_op_stop(struct ieee80211_hw *hw) if (IS_STARTED(ar)) ar->state = AR9170_IDLE; - flush_workqueue(ar->hw->workqueue); - cancel_delayed_work_sync(&ar->tx_janitor); #ifdef CONFIG_AR9170_LEDS cancel_delayed_work_sync(&ar->led_work); #endif cancel_work_sync(&ar->filter_config_work); cancel_work_sync(&ar->beacon_work); + mutex_lock(&ar->mutex); if (IS_ACCEPTING_CMD(ar)) { -- cgit v1.2.3-18-g5258 From d17734aee6383ff5e1720b3f01c014c0a9db40d5 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 16:52:06 -0700 Subject: ath: depend on cfg80211 The ath.ko module itself depends on cfg80211 Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index eb0337c4954..6bed009019a 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -1,6 +1,7 @@ config ATH_COMMON tristate "Atheros Wireless Cards" depends on WLAN_80211 + depends on CFG80211 depends on ATH5K || ATH9K || AR9170_USB source "drivers/net/wireless/ath/ath5k/Kconfig" -- cgit v1.2.3-18-g5258 From b820b3bcb02a97091b969faf2b5f19f1218953f9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 16:52:07 -0700 Subject: ath: simplify kconfig dependency and add documentation Make atheros wireless drivers visible when you select "Atheros wirless drivers". Adds links to ath.ko page, and Atheros drivers page on the wiki. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/Kconfig | 18 ++++++++++++++++-- drivers/net/wireless/ath/ar9170/Kconfig | 1 - drivers/net/wireless/ath/ath5k/Kconfig | 1 - drivers/net/wireless/ath/ath9k/Kconfig | 1 - 4 files changed, 16 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 6bed009019a..f27f3a794bb 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -2,9 +2,23 @@ config ATH_COMMON tristate "Atheros Wireless Cards" depends on WLAN_80211 depends on CFG80211 - depends on ATH5K || ATH9K || AR9170_USB + ---help--- + This will enable the support for the Atheros wireless drivers. + ath5k, ath9k and ar9170 drivers share some common code, this option + enables the common ath.ko module which currently shares just common + regulatory EEPROM helpers but will likely be extended later to share + more between modules. + For more information and documentation on this module you can visit: + + http://wireless.kernel.org/en/users/Drivers/ath + + For information on all Atheros wireless drivers visit: + + http://wireless.kernel.org/en/users/Drivers/Atheros + +if ATH_COMMON source "drivers/net/wireless/ath/ath5k/Kconfig" source "drivers/net/wireless/ath/ath9k/Kconfig" source "drivers/net/wireless/ath/ar9170/Kconfig" - +endif diff --git a/drivers/net/wireless/ath/ar9170/Kconfig b/drivers/net/wireless/ath/ar9170/Kconfig index b99e3263ee6..de4281fda12 100644 --- a/drivers/net/wireless/ath/ar9170/Kconfig +++ b/drivers/net/wireless/ath/ar9170/Kconfig @@ -2,7 +2,6 @@ config AR9170_USB tristate "Atheros AR9170 802.11n USB support" depends on USB && MAC80211 && WLAN_80211 && EXPERIMENTAL select FW_LOADER - select ATH_COMMON help This is a driver for the Atheros "otus" 802.11n USB devices. diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index daf0c83527d..9b07eef7c61 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -1,7 +1,6 @@ config ATH5K tristate "Atheros 5xxx wireless cards support" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL - select ATH_COMMON select MAC80211_LEDS select LEDS_CLASS select NEW_LEDS diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 0f4a6d862d3..2cb72f8c32d 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -1,7 +1,6 @@ config ATH9K tristate "Atheros 802.11n wireless cards support" depends on PCI && MAC80211 && WLAN_80211 - select ATH_COMMON select MAC80211_LEDS select LEDS_CLASS select NEW_LEDS -- cgit v1.2.3-18-g5258 From 44b7dd6dde1b80a94e5c0d01ecbc8097f52aa2dc Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 16:52:08 -0700 Subject: ath: use menuconfig to put ath stuff in its own page Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index f27f3a794bb..253b95a264b 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -1,4 +1,4 @@ -config ATH_COMMON +menuconfig ATH_COMMON tristate "Atheros Wireless Cards" depends on WLAN_80211 depends on CFG80211 -- cgit v1.2.3-18-g5258 From 75323fa3dec54abb0bcba8ce6b4994020af210ca Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 16:52:09 -0700 Subject: ath5k: remove EXPERIMENTAL marker Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index 9b07eef7c61..06d006675d7 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -1,6 +1,6 @@ config ATH5K tristate "Atheros 5xxx wireless cards support" - depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL + depends on PCI && MAC80211 && WLAN_80211 select MAC80211_LEDS select LEDS_CLASS select NEW_LEDS -- cgit v1.2.3-18-g5258 From 3e6404528c95e3439f478e1d28353e77f6d9c188 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 16:56:15 -0700 Subject: wireless: use menuconfig for WLAN_PRE80211 and WLAN_80211 This should make it very clear which are pre-802.11 or not Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index ca7a8a31d0b..dda7cc2e1f5 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -5,7 +5,7 @@ menu "Wireless LAN" depends on !S390 -config WLAN_PRE80211 +menuconfig WLAN_PRE80211 bool "Wireless LAN (pre-802.11)" depends on NETDEVICES ---help--- @@ -101,7 +101,7 @@ config PCMCIA_NETWAVE called netwave_cs. If unsure, say N. -config WLAN_80211 +menuconfig WLAN_80211 bool "Wireless LAN (IEEE 802.11)" depends on NETDEVICES ---help--- -- cgit v1.2.3-18-g5258 From 33172899a9d922b04081e12dced3ae474d46d620 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 28 Jul 2009 08:03:42 -0700 Subject: rt2x00: move experimental on kconfig only to rt2800usb These drivers have been around for a while, if there are issues they should be reported. rt2800usb is still a bit flaky though. Signed-off-by: Luis R. Rodriguez Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index f970aa25326..ed1f997e352 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -1,8 +1,8 @@ menuconfig RT2X00 tristate "Ralink driver support" - depends on MAC80211 && WLAN_80211 && EXPERIMENTAL + depends on MAC80211 && WLAN_80211 ---help--- - This will enable the experimental support for the Ralink drivers, + This will enable the support for the Ralink drivers, developed in the rt2x00 project . These drivers make use of the mac80211 stack. @@ -79,14 +79,14 @@ config RT73USB config RT2800USB tristate "Ralink rt2800 (USB) support" - depends on USB + depends on USB && EXPERIMENTAL select RT2X00_LIB_USB select RT2X00_LIB_HT select RT2X00_LIB_FIRMWARE select RT2X00_LIB_CRYPTO select CRC_CCITT ---help--- - This adds support for rt2800 wireless chipset family. + This adds experimental support for rt2800 wireless chipset family. Supported chips: RT2770, RT2870 & RT3070. When compiled as a module, this driver will be called "rt2800usb.ko". -- cgit v1.2.3-18-g5258 From ad2f34b41fd6e2b84c896ccf321d5de0a7c7cd52 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 28 Jul 2009 18:58:54 +0200 Subject: rt2x00: Fix build error when crypto support is disabled When only rt2400pci or rt2500pci is compiled without any of the other rt2x00 modules, then CONFIG_RT2X00_LIB_CRYPTO will not be enabled. However rt2x00mac_set_tim() implemented within #ifdef CONFIG_RT2X00_LIB_CRYPTO statements while the declaration is placed outside the definition. This results in linking errors as reporte by Ken. rt2x00_set_tim() has nothing to do with crypto, and thus should be moved outside of the #ifdef statements. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00mac.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 7de1a2cdcf8..e92c8f99d69 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -435,6 +435,16 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter); +int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + bool set) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + rt2x00lib_beacondone(rt2x00dev); + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_set_tim); + #ifdef CONFIG_RT2X00_LIB_CRYPTO static void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len) { @@ -454,16 +464,6 @@ static void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len) sizeof(crypto->rx_mic)); } -int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, - bool set) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - - rt2x00lib_beacondone(rt2x00dev); - return 0; -} -EXPORT_SYMBOL_GPL(rt2x00mac_set_tim); - int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) -- cgit v1.2.3-18-g5258 From 42e8856092be1db40bd4ae01406d2aaddf4e66fc Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 29 Jul 2009 15:05:21 +0530 Subject: ath9k: Update rate control for 11NA HT40 mode Now the lowest rate in 11na ht40 mode is 13.5Mbps this shortens the range when compared to 11na ht20 mode where the lowest rate is 6.5Mbps. To improve the range, make 6.5Mbps as the lowest rate in 11na ht40 mode, this improves the range by approximately 2dB. 11ng ht40 does not have this issue as it also has basic rates (1, 2, 5.5 and 11). Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index a07efa22551..59ad47c9889 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -44,7 +44,7 @@ static const struct ath_rate_table ar5416_11na_ratetable = { { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 29300, 0x0c, 0x00, 108, 4, 7, 7, 7, 7, 0 }, - { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ + { VALID_2040, VALID_2040, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ 6400, 0x80, 0x00, 0, 0, 8, 24, 8, 24, 3216 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */ @@ -463,8 +463,6 @@ static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw) if (!ignore_cw && WLAN_RC_PHY_HT(phy)) if (WLAN_RC_PHY_40(phy) && !(capflag & WLAN_RC_40_FLAG)) return 0; - if (!WLAN_RC_PHY_40(phy) && (capflag & WLAN_RC_40_FLAG)) - return 0; return 1; } -- cgit v1.2.3-18-g5258 From 3fc0fbf407967fa8def04d019316553c9ca133e2 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 29 Jul 2009 15:05:22 +0530 Subject: ath9k: Maintain monotonicity of PER while going across different phy Monotonicity of packet error rate should be kept when moving from one phy to another (legacy to ht, ht single stream to dual, etc). Current code skips updating per for other phys. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 59ad47c9889..16a271787b8 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1041,9 +1041,6 @@ static void ath_rc_update_ht(struct ath_softc *sc, /* Monotonicity is kept only for rates below the current rate. */ if (ath_rc_priv->per[tx_rate] < last_per) { for (rate = tx_rate - 1; rate >= 0; rate--) { - if (rate_table->info[rate].phy != - rate_table->info[tx_rate].phy) - break; if (ath_rc_priv->per[rate] > ath_rc_priv->per[rate+1]) { -- cgit v1.2.3-18-g5258 From 0b3acfa71a50a1fa1fcee528aa15404ea4ea0877 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 29 Jul 2009 15:05:23 +0530 Subject: ath9k: Remove unused ath9k_hw_intrget() Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 5 ----- drivers/net/wireless/ath/ath9k/hw.h | 1 - 2 files changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 431854ccb65..7a0a6aed632 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3152,11 +3152,6 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) return true; } -enum ath9k_int ath9k_hw_intrget(struct ath_hw *ah) -{ - return ah->mask_reg; -} - enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) { u32 omask = ah->mask_reg; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 2e196df1089..93a89302e79 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -612,7 +612,6 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore); /* Interrupt Handling */ bool ath9k_hw_intrpend(struct ath_hw *ah); bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked); -enum ath9k_int ath9k_hw_intrget(struct ath_hw *ah); enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints); void ath9k_hw_btcoex_enable(struct ath_hw *ah); -- cgit v1.2.3-18-g5258 From ae6f53f25f9803212d1985b5eb5a03111f439c24 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 29 Jul 2009 10:29:03 -0400 Subject: ath5k: update PCU opmode whenever a new interface is added Previously, we would store the operating mode at interface up time, but only update the PCU registers when the next reset happened. The result is that if beacon configuration (ops->bss_info_changed) happens before ops->config, we will program the wrong things into the timer registers. Consequently, beacons won't work in AP mode until after a reset (channel change, scan etc.). This is fragile anyway so just program the opmode as soon as mac80211 gives it to us. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 7db32ce3dbd..55ee976ab6d 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1117,6 +1117,8 @@ ath5k_mode_setup(struct ath5k_softc *sc) struct ath5k_hw *ah = sc->ah; u32 rfilt; + ah->ah_op_mode = sc->opmode; + /* configure rx filter */ rfilt = sc->filter_flags; ath5k_hw_set_rx_filter(ah, rfilt); @@ -2768,6 +2770,7 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, } ath5k_hw_set_lladdr(sc->ah, conf->mac_addr); + ath5k_mode_setup(sc); ret = 0; end: -- cgit v1.2.3-18-g5258 From 18c6951091eca7645005a71b556106cc99a6f4b1 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 29 Jul 2009 10:54:06 -0500 Subject: b43: Work around mac80211 race condition As shown in http://thread.gmane.org/gmane.linux.kernel.wireless.general/36497, mac80211 has a bug that allows a call to the TX routine after the queues have been stopped. This situation will only occur under extreme stress. Although b43 does not crash when this condition occurs, it does generate a WARN_ON and also logs a queue overrun message. This patch recognizes b43 is not at fault and logs a message only when the most verbose debugging mode is enabled. In the unlikely event that the queue is not stopped when the DMA queue becomes full, then a warning is issued. During testing of this patch with one output stream running repeated tcpperf writes and a second running a flood ping, this routine was entered with the DMA ring stopped about once per hour. The condition where the DMA queue is full but the ring has not been stopped has never been seen by me. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43/dma.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 7964cc32b25..41a0e9c2b33 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1334,13 +1334,22 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) spin_lock_irqsave(&ring->lock, flags); B43_WARN_ON(!ring->tx); - /* Check if the queue was stopped in mac80211, - * but we got called nevertheless. - * That would be a mac80211 bug. */ - B43_WARN_ON(ring->stopped); - if (unlikely(free_slots(ring) < TX_SLOTS_PER_FRAME)) { - b43warn(dev->wl, "DMA queue overflow\n"); + if (unlikely(ring->stopped)) { + /* We get here only because of a bug in mac80211. + * Because of a race, one packet may be queued after + * the queue is stopped, thus we got called when we shouldn't. + * For now, just refuse the transmit. */ + if (b43_debug(dev, B43_DBG_DMAVERBOSE)) + b43err(dev->wl, "Packet after queue stopped\n"); + err = -ENOSPC; + goto out_unlock; + } + + if (unlikely(WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME))) { + /* If we get here, we have a real error with the queue + * full, but queues not stopped. */ + b43err(dev->wl, "DMA queue overflow\n"); err = -ENOSPC; goto out_unlock; } -- cgit v1.2.3-18-g5258 From 91b092d73435489d7336f94e927d96224b26c9a8 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 27 Jul 2009 16:52:10 -0700 Subject: ar9170: remove EXPERIMENTAL marker Cc: Christian Lamparter Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ar9170/Kconfig b/drivers/net/wireless/ath/ar9170/Kconfig index de4281fda12..05918f1e685 100644 --- a/drivers/net/wireless/ath/ar9170/Kconfig +++ b/drivers/net/wireless/ath/ar9170/Kconfig @@ -1,12 +1,13 @@ config AR9170_USB tristate "Atheros AR9170 802.11n USB support" - depends on USB && MAC80211 && WLAN_80211 && EXPERIMENTAL + depends on USB && MAC80211 && WLAN_80211 select FW_LOADER help This is a driver for the Atheros "otus" 802.11n USB devices. These devices require additional firmware (2 files). For now, these files can be downloaded from here: + http://wireless.kernel.org/en/users/Drivers/ar9170 If you choose to build a module, it'll be called ar9170usb. -- cgit v1.2.3-18-g5258 From 7e2ce646fc0acc99837f73d39528493e146d1dcc Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Tue, 28 Jul 2009 16:34:26 +0200 Subject: orinoco: enable cfg80211 "set_channel" operation Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/cfg.c | 41 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c index 1a87d3a0967..27f2d334264 100644 --- a/drivers/net/wireless/orinoco/cfg.c +++ b/drivers/net/wireless/orinoco/cfg.c @@ -156,7 +156,48 @@ static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev, return err; } +static int orinoco_set_channel(struct wiphy *wiphy, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + struct orinoco_private *priv = wiphy_priv(wiphy); + int err = 0; + unsigned long flags; + int channel; + + if (!chan) + return -EINVAL; + + if (channel_type != NL80211_CHAN_NO_HT) + return -EINVAL; + + if (chan->band != IEEE80211_BAND_2GHZ) + return -EINVAL; + + channel = ieee80211_freq_to_dsss_chan(chan->center_freq); + + if ((channel < 1) || (channel > NUM_CHANNELS) || + !(priv->channel_mask & (1 << (channel-1)))) + return -EINVAL; + + if (orinoco_lock(priv, &flags) != 0) + return -EBUSY; + + priv->channel = channel; + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { + /* Fast channel change - no commit if successful */ + hermes_t *hw = &priv->hw; + err = hermes_docmd_wait(hw, HERMES_CMD_TEST | + HERMES_TEST_SET_CHANNEL, + channel, NULL); + } + orinoco_unlock(priv, &flags); + + return err; +} + const struct cfg80211_ops orinoco_cfg_ops = { .change_virtual_intf = orinoco_change_vif, + .set_channel = orinoco_set_channel, .scan = orinoco_scan, }; -- cgit v1.2.3-18-g5258 From 8784d2ee92fc835bf18dd5096f00ec9a48dc0590 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 29 Jul 2009 17:32:28 -0400 Subject: ath5k: fix CAB queue operation We need to process tx descriptors for all queues (currently main tx queue and cabq) which may have triggered the TX completion interrupt. Otherwise, the queues can get stuck after sending a few frames. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 55ee976ab6d..3a1c156d275 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2000,9 +2000,12 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) static void ath5k_tasklet_tx(unsigned long data) { + int i; struct ath5k_softc *sc = (void *)data; - ath5k_tx_processq(sc, sc->txq); + for (i=0; i < AR5K_NUM_TX_QUEUES; i++) + if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i))) + ath5k_tx_processq(sc, &sc->txqs[i]); } -- cgit v1.2.3-18-g5258 From 64344d78228f6346a0462ba2d5fc03494aef4e6b Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 29 Jul 2009 14:20:41 -0700 Subject: at76c50x-usb: remove unneeded flush_workqueue() at usb disconnect This driver only uses the mac80211 workqueue and mac80211 requires us to cancel all work at driver stop. Since we now have the cancels in the right places at stop() we really don't need to flush the mac80211 workqueue so remove it. Signed-off-by: Luis R. Rodriguez Acked-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/at76c50x-usb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index f46e2b33b1f..aff09a1cf64 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -2298,10 +2298,8 @@ static void at76_delete_device(struct at76_priv *priv) tasklet_kill(&priv->rx_tasklet); - if (priv->mac80211_registered) { - flush_workqueue(priv->hw->workqueue); + if (priv->mac80211_registered) ieee80211_unregister_hw(priv->hw); - } if (priv->tx_urb) { usb_kill_urb(priv->tx_urb); -- cgit v1.2.3-18-g5258 From 42935ecaf4e784d0815afa9a7e5fe7e141157ca3 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 29 Jul 2009 20:08:07 -0400 Subject: mac80211: redefine usage of the mac80211 workqueue The mac80211 workqueue exists to enable mac80211 and drivers to queue their own work on a single threaded workqueue. mac80211 takes care to flush the workqueue during suspend but we never really had requirements on drivers for how they should use the workqueue in consideration for suspend. We extend mac80211 to document how the mac80211 workqueue should be used, how it should not be used and finally move raw access to the workqueue to mac80211 only. Drivers and mac80211 use helpers to queue work onto the mac80211 workqueue: * ieee80211_queue_work() * ieee80211_queue_delayed_work() These helpers will now warn if mac80211 already completed its suspend cycle and someone is trying to queue work. mac80211 flushes the mac80211 workqueue prior to suspend a few times, but we haven't taken the care to ensure drivers won't add more work after suspend. To help with this we add a warning when someone tries to add work and mac80211 already completed the suspend cycle. Drivers should ensure they cancel any work or delayed work in the mac80211 stop() callback. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/at76c50x-usb.c | 10 +++++----- drivers/net/wireless/ath/ar9170/led.c | 11 +++++++---- drivers/net/wireless/ath/ar9170/main.c | 26 +++++++++++++++----------- drivers/net/wireless/ath/ath9k/main.c | 15 ++++++++------- drivers/net/wireless/ath/ath9k/virtual.c | 17 +++++++++-------- drivers/net/wireless/ath/ath9k/xmit.c | 2 +- drivers/net/wireless/b43/main.c | 8 ++++---- drivers/net/wireless/b43/phy_common.c | 2 +- drivers/net/wireless/b43/pio.c | 2 +- drivers/net/wireless/b43legacy/main.c | 8 ++++---- drivers/net/wireless/p54/led.c | 5 ++--- drivers/net/wireless/p54/main.c | 2 +- drivers/net/wireless/p54/p54spi.c | 4 ++-- drivers/net/wireless/p54/txrx.c | 2 +- drivers/net/wireless/rt2x00/rt2x00dev.c | 2 +- drivers/net/wireless/rt2x00/rt2x00link.c | 8 ++++---- drivers/net/wireless/rt2x00/rt2x00mac.c | 2 +- drivers/net/wireless/rtl818x/rtl8187_dev.c | 2 +- drivers/net/wireless/rtl818x/rtl8187_leds.c | 10 +++++----- drivers/net/wireless/zd1211rw/zd_mac.c | 2 +- 20 files changed, 74 insertions(+), 66 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index aff09a1cf64..7218dbabad3 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1875,8 +1875,8 @@ static void at76_dwork_hw_scan(struct work_struct *work) /* FIXME: add maximum time for scan to complete */ if (ret != CMD_STATUS_COMPLETE) { - queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan, - SCAN_POLL_INTERVAL); + ieee80211_queue_delayed_work(priv->hw, &priv->dwork_hw_scan, + SCAN_POLL_INTERVAL); mutex_unlock(&priv->mtx); return; } @@ -1937,8 +1937,8 @@ static int at76_hw_scan(struct ieee80211_hw *hw, goto exit; } - queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan, - SCAN_POLL_INTERVAL); + ieee80211_queue_delayed_work(priv->hw, &priv->dwork_hw_scan, + SCAN_POLL_INTERVAL); exit: mutex_unlock(&priv->mtx); @@ -2027,7 +2027,7 @@ static void at76_configure_filter(struct ieee80211_hw *hw, } else return; - queue_work(hw->workqueue, &priv->work_set_promisc); + ieee80211_queue_work(hw, &priv->work_set_promisc); } static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, diff --git a/drivers/net/wireless/ath/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c index 63fda6cd210..86c4e79f6bc 100644 --- a/drivers/net/wireless/ath/ar9170/led.c +++ b/drivers/net/wireless/ath/ar9170/led.c @@ -90,9 +90,12 @@ static void ar9170_update_leds(struct work_struct *work) ar9170_set_leds_state(ar, led_val); mutex_unlock(&ar->mutex); - if (rerun) - queue_delayed_work(ar->hw->workqueue, &ar->led_work, - msecs_to_jiffies(blink_delay)); + if (!rerun) + return; + + ieee80211_queue_delayed_work(ar->hw, + &ar->led_work, + msecs_to_jiffies(blink_delay)); } static void ar9170_led_brightness_set(struct led_classdev *led, @@ -110,7 +113,7 @@ static void ar9170_led_brightness_set(struct led_classdev *led, } if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled)) - queue_delayed_work(ar->hw->workqueue, &ar->led_work, HZ/10); + ieee80211_queue_delayed_work(ar->hw, &ar->led_work, HZ/10); } static int ar9170_register_led(struct ar9170 *ar, int i, char *name, diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 099ed3c3ba2..4fc389ae74b 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -595,10 +595,12 @@ static void ar9170_tx_janitor(struct work_struct *work) ar9170_tx_fake_ampdu_status(ar); - if (resched) - queue_delayed_work(ar->hw->workqueue, - &ar->tx_janitor, - msecs_to_jiffies(AR9170_JANITOR_DELAY)); + if (!resched) + return; + + ieee80211_queue_delayed_work(ar->hw, + &ar->tx_janitor, + msecs_to_jiffies(AR9170_JANITOR_DELAY)); } void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) @@ -648,7 +650,7 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) * pre-TBTT event */ if (ar->vif && ar->vif->type == NL80211_IFTYPE_AP) - queue_work(ar->hw->workqueue, &ar->beacon_work); + ieee80211_queue_work(ar->hw, &ar->beacon_work); break; case 0xc2: @@ -1825,10 +1827,12 @@ static void ar9170_tx(struct ar9170 *ar) } } - if (schedule_garbagecollector) - queue_delayed_work(ar->hw->workqueue, - &ar->tx_janitor, - msecs_to_jiffies(AR9170_JANITOR_DELAY)); + if (!schedule_garbagecollector) + return; + + ieee80211_queue_delayed_work(ar->hw, + &ar->tx_janitor, + msecs_to_jiffies(AR9170_JANITOR_DELAY)); } static bool ar9170_tx_ampdu_queue(struct ar9170 *ar, struct sk_buff *skb) @@ -2157,7 +2161,7 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, } if (likely(IS_STARTED(ar))) - queue_work(ar->hw->workqueue, &ar->filter_config_work); + ieee80211_queue_work(ar->hw, &ar->filter_config_work); } static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, @@ -2415,7 +2419,7 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw, } if (IS_STARTED(ar) && ar->filter_changed) - queue_work(ar->hw->workqueue, &ar->filter_config_work); + ieee80211_queue_work(ar->hw, &ar->filter_config_work); } static int ar9170_get_stats(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index cf44623b5cd..292ac2b4189 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -973,10 +973,11 @@ static void ath_led_blink_work(struct work_struct *work) ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0); - queue_delayed_work(sc->hw->workqueue, &sc->ath_led_blink_work, - (sc->sc_flags & SC_OP_LED_ON) ? - msecs_to_jiffies(sc->led_off_duration) : - msecs_to_jiffies(sc->led_on_duration)); + ieee80211_queue_delayed_work(sc->hw, + &sc->ath_led_blink_work, + (sc->sc_flags & SC_OP_LED_ON) ? + msecs_to_jiffies(sc->led_off_duration) : + msecs_to_jiffies(sc->led_on_duration)); sc->led_on_duration = sc->led_on_cnt ? max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) : @@ -1013,8 +1014,8 @@ static void ath_led_brightness(struct led_classdev *led_cdev, case LED_FULL: if (led->led_type == ATH_LED_ASSOC) { sc->sc_flags |= SC_OP_LED_ASSOCIATED; - queue_delayed_work(sc->hw->workqueue, - &sc->ath_led_blink_work, 0); + ieee80211_queue_delayed_work(sc->hw, + &sc->ath_led_blink_work, 0); } else if (led->led_type == ATH_LED_RADIO) { ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); sc->sc_flags |= SC_OP_LED_ON; @@ -1972,7 +1973,7 @@ static int ath9k_start(struct ieee80211_hw *hw) ieee80211_wake_queues(hw); - queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work, 0); + ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); mutex_unlock: mutex_unlock(&sc->mutex); diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index e1d419e02b4..19b88f8177f 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -351,7 +351,7 @@ void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) * Drop from tasklet to work to allow mutex for channel * change. */ - queue_work(aphy->sc->hw->workqueue, + ieee80211_queue_work(aphy->sc->hw, &aphy->sc->chan_work); } } @@ -367,7 +367,7 @@ static void ath9k_mark_paused(struct ath_wiphy *aphy) struct ath_softc *sc = aphy->sc; aphy->state = ATH_WIPHY_PAUSED; if (!__ath9k_wiphy_pausing(sc)) - queue_work(sc->hw->workqueue, &sc->chan_work); + ieee80211_queue_work(sc->hw, &sc->chan_work); } static void ath9k_pause_iter(void *data, u8 *mac, struct ieee80211_vif *vif) @@ -521,7 +521,7 @@ int ath9k_wiphy_select(struct ath_wiphy *aphy) spin_unlock_bh(&sc->wiphy_lock); ath_radio_disable(sc); ath_radio_enable(sc); - queue_work(aphy->sc->hw->workqueue, + ieee80211_queue_work(aphy->sc->hw, &aphy->sc->chan_work); return -EBUSY; /* previous select still in progress */ } @@ -541,7 +541,7 @@ int ath9k_wiphy_select(struct ath_wiphy *aphy) if (now) { /* Ready to request channel change immediately */ - queue_work(aphy->sc->hw->workqueue, &aphy->sc->chan_work); + ieee80211_queue_work(aphy->sc->hw, &aphy->sc->chan_work); } /* @@ -648,8 +648,9 @@ try_again: "change\n"); } - queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work, - sc->wiphy_scheduler_int); + ieee80211_queue_delayed_work(sc->hw, + &sc->wiphy_work, + sc->wiphy_scheduler_int); } void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int) @@ -657,8 +658,8 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int) cancel_delayed_work_sync(&sc->wiphy_work); sc->wiphy_scheduler_int = msecs_to_jiffies(msec_int); if (sc->wiphy_scheduler_int) - queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work, - sc->wiphy_scheduler_int); + ieee80211_queue_delayed_work(sc->hw, &sc->wiphy_work, + sc->wiphy_scheduler_int); } /* caller must hold wiphy_lock */ diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index b7806e2ca0e..87762da0383 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2063,7 +2063,7 @@ static void ath_tx_complete_poll_work(struct work_struct *work) ath_reset(sc, false); } - queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work, + ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT)); } diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 3f4360ad0e4..f985938962e 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1654,7 +1654,7 @@ static void b43_update_templates(struct b43_wl *wl) wl->current_beacon = beacon; wl->beacon0_uploaded = 0; wl->beacon1_uploaded = 0; - queue_work(wl->hw->workqueue, &wl->beacon_update_trigger); + ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger); } static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int) @@ -2914,7 +2914,7 @@ out_requeue: delay = msecs_to_jiffies(50); else delay = round_jiffies_relative(HZ * 15); - queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay); + ieee80211_queue_delayed_work(wl->hw, &dev->periodic_work, delay); out: mutex_unlock(&wl->mutex); } @@ -2925,7 +2925,7 @@ static void b43_periodic_tasks_setup(struct b43_wldev *dev) dev->periodic_state = 0; INIT_DELAYED_WORK(work, b43_periodic_work_handler); - queue_delayed_work(dev->wl->hw->workqueue, work, 0); + ieee80211_queue_delayed_work(dev->wl->hw, work, 0); } /* Check if communication with the device works correctly. */ @@ -4871,7 +4871,7 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason) if (b43_status(dev) < B43_STAT_INITIALIZED) return; b43info(dev->wl, "Controller RESET (%s) ...\n", reason); - queue_work(dev->wl->hw->workqueue, &dev->restart_work); + ieee80211_queue_work(dev->wl->hw, &dev->restart_work); } #ifdef CONFIG_PM diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 6d241622210..f537bfef690 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -352,7 +352,7 @@ void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags) /* We must adjust the transmission power in hardware. * Schedule b43_phy_txpower_adjust_work(). */ - queue_work(dev->wl->hw->workqueue, &dev->wl->txpower_adjust_work); + ieee80211_queue_work(dev->wl->hw, &dev->wl->txpower_adjust_work); } int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset) diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 69138e8c1db..73c047d8de4 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -783,7 +783,7 @@ void b43_pio_rx(struct b43_pio_rxqueue *q) { /* Due to latency issues we must run the RX path in * a workqueue to be able to schedule between packets. */ - queue_work(q->dev->wl->hw->workqueue, &q->rx_work); + ieee80211_queue_work(q->dev->wl->hw, &q->rx_work); } static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q) diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index c4973c1942b..b1435594921 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -1252,7 +1252,7 @@ static void b43legacy_update_templates(struct b43legacy_wl *wl) wl->current_beacon = beacon; wl->beacon0_uploaded = 0; wl->beacon1_uploaded = 0; - queue_work(wl->hw->workqueue, &wl->beacon_update_trigger); + ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger); } static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev, @@ -2300,7 +2300,7 @@ out_requeue: delay = msecs_to_jiffies(50); else delay = round_jiffies_relative(HZ * 15); - queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay); + ieee80211_queue_delayed_work(wl->hw, &dev->periodic_work, delay); out: mutex_unlock(&wl->mutex); } @@ -2311,7 +2311,7 @@ static void b43legacy_periodic_tasks_setup(struct b43legacy_wldev *dev) dev->periodic_state = 0; INIT_DELAYED_WORK(work, b43legacy_periodic_work_handler); - queue_delayed_work(dev->wl->hw->workqueue, work, 0); + ieee80211_queue_delayed_work(dev->wl->hw, work, 0); } /* Validate access to the chip (SHM) */ @@ -3885,7 +3885,7 @@ void b43legacy_controller_restart(struct b43legacy_wldev *dev, if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) return; b43legacyinfo(dev->wl, "Controller RESET (%s) ...\n", reason); - queue_work(dev->wl->hw->workqueue, &dev->restart_work); + ieee80211_queue_work(dev->wl->hw, &dev->restart_work); } #ifdef CONFIG_PM diff --git a/drivers/net/wireless/p54/led.c b/drivers/net/wireless/p54/led.c index c00115b206d..9575ac03363 100644 --- a/drivers/net/wireless/p54/led.c +++ b/drivers/net/wireless/p54/led.c @@ -61,7 +61,7 @@ static void p54_update_leds(struct work_struct *work) wiphy_name(priv->hw->wiphy), err); if (rerun) - queue_delayed_work(priv->hw->workqueue, &priv->led_work, + ieee80211_queue_delayed_work(priv->hw, &priv->led_work, msecs_to_jiffies(blink_delay)); } @@ -78,8 +78,7 @@ static void p54_led_brightness_set(struct led_classdev *led_dev, if ((brightness) && (led->registered)) { led->toggled++; - queue_delayed_work(priv->hw->workqueue, &priv->led_work, - HZ/10); + ieee80211_queue_delayed_work(priv->hw, &priv->led_work, HZ/10); } } diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 955f6d7ec16..a0d0e726bc4 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -180,7 +180,7 @@ static int p54_start(struct ieee80211_hw *dev) goto out; } - queue_delayed_work(dev->workqueue, &priv->work, 0); + ieee80211_queue_delayed_work(dev, &priv->work, 0); priv->softled_state = 0; err = p54_set_leds(priv); diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index eef532987d0..05458d9249c 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -391,7 +391,7 @@ static irqreturn_t p54spi_interrupt(int irq, void *config) struct spi_device *spi = config; struct p54s_priv *priv = dev_get_drvdata(&spi->dev); - queue_work(priv->hw->workqueue, &priv->work); + ieee80211_queue_work(priv->hw, &priv->work); return IRQ_HANDLED; } @@ -479,7 +479,7 @@ static void p54spi_op_tx(struct ieee80211_hw *dev, struct sk_buff *skb) list_add_tail(&di->tx_list, &priv->tx_pending); spin_unlock_irqrestore(&priv->tx_lock, flags); - queue_work(priv->hw->workqueue, &priv->work); + ieee80211_queue_work(priv->hw, &priv->work); } static void p54spi_work(struct work_struct *work) diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index c32a0d2fa1f..704685fab17 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -380,7 +380,7 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb) ieee80211_rx_irqsafe(priv->hw, skb); - queue_delayed_work(priv->hw->workqueue, &priv->work, + ieee80211_queue_delayed_work(priv->hw, &priv->work, msecs_to_jiffies(P54_STATISTICS_UPDATE)); return -1; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 658a63bfb76..b717afbf3f3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -215,7 +215,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) rt2x00lib_beacondone_iter, rt2x00dev); - queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work); + ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work); } EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 79915687e74..917831689cc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -351,8 +351,8 @@ void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev) rt2x00link_reset_tuner(rt2x00dev, false); - queue_delayed_work(rt2x00dev->hw->workqueue, - &link->work, LINK_TUNE_INTERVAL); + ieee80211_queue_delayed_work(rt2x00dev->hw, + &link->work, LINK_TUNE_INTERVAL); } void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev) @@ -461,8 +461,8 @@ static void rt2x00link_tuner(struct work_struct *work) * Increase tuner counter, and reschedule the next link tuner run. */ link->count++; - queue_delayed_work(rt2x00dev->hw->workqueue, - &link->work, LINK_TUNE_INTERVAL); + ieee80211_queue_delayed_work(rt2x00dev->hw, + &link->work, LINK_TUNE_INTERVAL); } void rt2x00link_register(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index e92c8f99d69..81febdfd663 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -431,7 +431,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags)) rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags); else - queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work); + ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->filter_work); } EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter); diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index c9b9dbe584c..53f57dc5222 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -220,7 +220,7 @@ static void rtl8187_tx_cb(struct urb *urb) * reading a register in the device. We are in interrupt mode * here, thus queue the skb and finish on a work queue. */ skb_queue_tail(&priv->b_tx_status.queue, skb); - queue_delayed_work(hw->workqueue, &priv->work, 0); + ieee80211_queue_delayed_work(hw, &priv->work, 0); } } diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.c b/drivers/net/wireless/rtl818x/rtl8187_leds.c index cf9f899fe0e..a6cfb7e7799 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_leds.c +++ b/drivers/net/wireless/rtl818x/rtl8187_leds.c @@ -108,11 +108,11 @@ static void rtl8187_led_brightness_set(struct led_classdev *led_dev, struct rtl8187_priv *priv = hw->priv; if (brightness == LED_OFF) { - queue_delayed_work(hw->workqueue, &priv->led_off, 0); + ieee80211_queue_delayed_work(hw, &priv->led_off, 0); /* The LED is off for 1/20 sec so that it just blinks. */ - queue_delayed_work(hw->workqueue, &priv->led_on, HZ / 20); + ieee80211_queue_delayed_work(hw, &priv->led_on, HZ / 20); } else - queue_delayed_work(hw->workqueue, &priv->led_on, 0); + ieee80211_queue_delayed_work(hw, &priv->led_on, 0); } static int rtl8187_register_led(struct ieee80211_hw *dev, @@ -193,7 +193,7 @@ void rtl8187_leds_init(struct ieee80211_hw *dev, u16 custid) err = rtl8187_register_led(dev, &priv->led_rx, name, ieee80211_get_rx_led_name(dev), ledpin); if (!err) { - queue_delayed_work(dev->workqueue, &priv->led_on, 0); + ieee80211_queue_delayed_work(dev, &priv->led_on, 0); return; } /* registration of RX LED failed - unregister TX */ @@ -209,7 +209,7 @@ void rtl8187_leds_exit(struct ieee80211_hw *dev) struct rtl8187_priv *priv = dev->priv; /* turn the LED off before exiting */ - queue_delayed_work(dev->workqueue, &priv->led_off, 0); + ieee80211_queue_delayed_work(dev, &priv->led_off, 0); cancel_delayed_work_sync(&priv->led_off); cancel_delayed_work_sync(&priv->led_on); rtl8187_unregister_led(&priv->led_rx); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 9600b72495d..54abdd0c004 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -698,7 +698,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) && !mac->pass_ctrl) return 0; - fc = *(__le16 *)buffer; + fc = get_unaligned((__le16*)buffer); need_padding = ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc); skb = dev_alloc_skb(length + (need_padding ? 2 : 0)); -- cgit v1.2.3-18-g5258 From e46ab7f0886143846d8da2ca06c2b0e245f34dc6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Jul 2009 11:58:16 +0200 Subject: iwlwifi: don't export symbols not needed in other modules Even with the split into iwlcore/agn/3945 not all symbols that cross file boundaries are needed in other modules, a few are only used within iwlcore, for example. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 3 --- drivers/net/wireless/iwlwifi/iwl-led.c | 1 - drivers/net/wireless/iwlwifi/iwl-rx.c | 1 - drivers/net/wireless/iwlwifi/iwl-sta.c | 1 - 4 files changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 8570d56b312..1b5180f8d75 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1140,7 +1140,6 @@ void iwl_set_flags_for_band(struct iwl_priv *priv, priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK; } } -EXPORT_SYMBOL(iwl_set_flags_for_band); /* * initialize rxon structure with default values from eeprom @@ -2291,7 +2290,6 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) return iwl_send_cmd(priv, &cmd); } -EXPORT_SYMBOL(iwl_send_card_state); void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) @@ -2335,7 +2333,6 @@ void iwl_clear_isr_stats(struct iwl_priv *priv) { memset(&priv->isr_stats, 0, sizeof(priv->isr_stats)); } -EXPORT_SYMBOL(iwl_clear_isr_stats); int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 7cce8f85bcc..3d61cb43151 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -335,7 +335,6 @@ void iwl_leds_background(struct iwl_priv *priv) priv->last_blink_time = jiffies; priv->last_blink_rate = blink_idx; } -EXPORT_SYMBOL(iwl_leds_background); /* Register all led handler */ int iwl_leds_register(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 5d5f2153f44..e002c8b56c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -406,7 +406,6 @@ void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) rxq->free_count = 0; spin_unlock_irqrestore(&rxq->lock, flags); } -EXPORT_SYMBOL(iwl_rx_queue_reset); int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) { diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 79ea5cc2c89..efcae0d5e19 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -464,7 +464,6 @@ out: spin_unlock_irqrestore(&priv->sta_lock, flags); return ret; } -EXPORT_SYMBOL(iwl_remove_station); /** * iwl_clear_stations_table - Clear the driver's station table -- cgit v1.2.3-18-g5258 From 1487cd5e76337555737cbc55d7d83f41460d198f Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Jul 2009 19:41:20 +0300 Subject: usbnet: allow "minidriver" to prevent urb unlinking on usbnet_stop rndis_wlan devices freeze after running usbnet_stop several times. It appears that firmware freezes in state where it does not respond to any RNDIS commands and device have to be physically unplugged/replugged. This patch lets minidrivers to disable unlink_urbs on usbnet_stop through new info flag. Signed-off-by: Jussi Kivilinna Cc: David Brownell Signed-off-by: John W. Linville --- drivers/net/usb/usbnet.c | 32 ++++++++++++++++++-------------- drivers/net/wireless/rndis_wlan.c | 9 ++++++--- 2 files changed, 24 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 25e435c4904..af1fe469650 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -601,21 +601,25 @@ int usbnet_stop (struct net_device *net) info->description); } - // ensure there are no more active urbs - add_wait_queue (&unlink_wakeup, &wait); - dev->wait = &unlink_wakeup; - temp = unlink_urbs (dev, &dev->txq) + unlink_urbs (dev, &dev->rxq); - - // maybe wait for deletions to finish. - while (!skb_queue_empty(&dev->rxq) - && !skb_queue_empty(&dev->txq) - && !skb_queue_empty(&dev->done)) { - msleep(UNLINK_TIMEOUT_MS); - if (netif_msg_ifdown (dev)) - devdbg (dev, "waited for %d urb completions", temp); + if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) { + /* ensure there are no more active urbs */ + add_wait_queue(&unlink_wakeup, &wait); + dev->wait = &unlink_wakeup; + temp = unlink_urbs(dev, &dev->txq) + + unlink_urbs(dev, &dev->rxq); + + /* maybe wait for deletions to finish. */ + while (!skb_queue_empty(&dev->rxq) + && !skb_queue_empty(&dev->txq) + && !skb_queue_empty(&dev->done)) { + msleep(UNLINK_TIMEOUT_MS); + if (netif_msg_ifdown(dev)) + devdbg(dev, "waited for %d urb completions", + temp); + } + dev->wait = NULL; + remove_wait_queue(&unlink_wakeup, &wait); } - dev->wait = NULL; - remove_wait_queue (&unlink_wakeup, &wait); usb_kill_urb(dev->interrupt); diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 09c0702ae64..76c5ec6bbbc 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2513,7 +2513,8 @@ static int rndis_wlan_stop(struct usbnet *usbdev) static const struct driver_info bcm4320b_info = { .description = "Wireless RNDIS device, BCM4320b based", - .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, + .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT | + FLAG_AVOID_UNLINK_URBS, .bind = rndis_wlan_bind, .unbind = rndis_wlan_unbind, .status = rndis_status, @@ -2527,7 +2528,8 @@ static const struct driver_info bcm4320b_info = { static const struct driver_info bcm4320a_info = { .description = "Wireless RNDIS device, BCM4320a based", - .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, + .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT | + FLAG_AVOID_UNLINK_URBS, .bind = rndis_wlan_bind, .unbind = rndis_wlan_unbind, .status = rndis_status, @@ -2541,7 +2543,8 @@ static const struct driver_info bcm4320a_info = { static const struct driver_info rndis_wlan_info = { .description = "Wireless RNDIS device", - .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, + .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT | + FLAG_AVOID_UNLINK_URBS, .bind = rndis_wlan_bind, .unbind = rndis_wlan_unbind, .status = rndis_status, -- cgit v1.2.3-18-g5258 From 110736de938b5bfdd63c86166e355d3f16115f6a Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Jul 2009 19:41:26 +0300 Subject: rndis_wlan: stop workers on rndis_wlan_stop() and restore on rndis_wlan_reset() Driver doesn't need to poll statistics/link status when stopped. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 76c5ec6bbbc..3c7c620c4f0 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2457,9 +2457,6 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) disassociate(usbdev, 1); netif_carrier_off(usbdev->net); - queue_delayed_work(priv->workqueue, &priv->stats_work, - round_jiffies_relative(STATS_UPDATE_JIFFIES)); - return 0; fail: @@ -2499,15 +2496,33 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) static int rndis_wlan_reset(struct usbnet *usbdev) { + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + devdbg(usbdev, "rndis_wlan_reset"); + + queue_delayed_work(priv->workqueue, &priv->stats_work, + round_jiffies_relative(STATS_UPDATE_JIFFIES)); + return deauthenticate(usbdev); } static int rndis_wlan_stop(struct usbnet *usbdev) { + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + int retval; + devdbg(usbdev, "rndis_wlan_stop"); - return disassociate(usbdev, 0); + + retval = disassociate(usbdev, 0); + + priv->work_pending = 0; + cancel_delayed_work_sync(&priv->stats_work); + cancel_delayed_work_sync(&priv->scan_work); + cancel_work_sync(&priv->work); + flush_workqueue(priv->workqueue); + + return retval; } -- cgit v1.2.3-18-g5258 From 005ba2f17e68b4da6a2c2c01c826294beac50415 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Jul 2009 19:41:31 +0300 Subject: rndis_wlan: clear cfg80211 scan on rndis_wlan_stop() Scanning gets stuck if device is stopped when scan is active. Fix by clearing/aborting cfg80211 scan on rndis_wlan_stop(). Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 3c7c620c4f0..dee05511d59 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1484,6 +1484,9 @@ static void rndis_get_scan_results(struct work_struct *work) devdbg(usbdev, "get_scan_results"); + if (!priv->scan_request) + return; + ret = rndis_check_bssid_list(usbdev); cfg80211_scan_done(priv->scan_request, ret < 0); @@ -2522,6 +2525,11 @@ static int rndis_wlan_stop(struct usbnet *usbdev) cancel_work_sync(&priv->work); flush_workqueue(priv->workqueue); + if (priv->scan_request) { + cfg80211_scan_done(priv->scan_request, true); + priv->scan_request = NULL; + } + return retval; } -- cgit v1.2.3-18-g5258 From 7eaab7086c3a313d76c217f98bc610c523d9bc2c Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Jul 2009 19:41:37 +0300 Subject: rndis_wlan: reset device and restore multicast list on rndis_wlan_reset() Reset device properly with RNDIS_MSG_RESET in rndis_wlan_reset() and restore multicast list afterwards. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index dee05511d59..bfb9861a036 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -594,6 +594,28 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) } +static int rndis_reset(struct usbnet *usbdev) +{ + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + struct rndis_reset *reset; + int ret; + + mutex_lock(&priv->command_lock); + + reset = (void *)priv->command_buffer; + memset(reset, 0, sizeof(*reset)); + reset->msg_type = RNDIS_MSG_RESET; + reset->msg_len = cpu_to_le32(sizeof(*reset)); + ret = rndis_command(usbdev, (void *)reset, CONTROL_BUFFER_SIZE); + + mutex_unlock(&priv->command_lock); + + if (ret < 0) + return ret; + return 0; +} + + /* * Specs say that we can only set config parameters only soon after device * initialization. @@ -2500,9 +2522,17 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) static int rndis_wlan_reset(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + int retval; devdbg(usbdev, "rndis_wlan_reset"); + retval = rndis_reset(usbdev); + if (retval) + devwarn(usbdev, "rndis_reset() failed: %d", retval); + + /* rndis_reset cleared multicast list, so restore here. */ + set_multicast_list(usbdev); + queue_delayed_work(priv->workqueue, &priv->stats_work, round_jiffies_relative(STATS_UPDATE_JIFFIES)); -- cgit v1.2.3-18-g5258 From e5a11a822e1758b05b987e3a5041ef1029aa6cec Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Jul 2009 19:41:42 +0300 Subject: rndis_wlan: set current packet filter to zero on stop Set current packet filter to zero to block receiving data packets from device. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index bfb9861a036..974f7249786 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2530,7 +2530,8 @@ static int rndis_wlan_reset(struct usbnet *usbdev) if (retval) devwarn(usbdev, "rndis_reset() failed: %d", retval); - /* rndis_reset cleared multicast list, so restore here. */ + /* rndis_reset cleared multicast list, so restore here. + (set_multicast_list() also turns on current packet filter) */ set_multicast_list(usbdev); queue_delayed_work(priv->workqueue, &priv->stats_work, @@ -2544,6 +2545,7 @@ static int rndis_wlan_stop(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int retval; + __le32 filter; devdbg(usbdev, "rndis_wlan_stop"); @@ -2560,6 +2562,12 @@ static int rndis_wlan_stop(struct usbnet *usbdev) priv->scan_request = NULL; } + /* Set current packet filter zero to block receiving data packets from + device. */ + filter = 0; + rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &filter, + sizeof(filter)); + return retval; } -- cgit v1.2.3-18-g5258 From 27b7b5c131a1df6701a96e10d1056de8e3b15aa9 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Jul 2009 19:41:47 +0300 Subject: rndis_wlan: add rndis_set/query_oid debugging Add better debugging for failed OID queries. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 86 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 974f7249786..f6dcbb168b7 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -100,7 +100,6 @@ MODULE_PARM_DESC(workaround_interval, #define OID_GEN_RCV_ERROR cpu_to_le32(0x00020104) #define OID_GEN_RCV_NO_BUFFER cpu_to_le32(0x00020105) -#define OID_802_3_PERMANENT_ADDRESS cpu_to_le32(0x01010101) #define OID_802_3_CURRENT_ADDRESS cpu_to_le32(0x01010102) #define OID_802_3_MULTICAST_LIST cpu_to_le32(0x01010103) #define OID_802_3_MAXIMUM_LIST_SIZE cpu_to_le32(0x01010104) @@ -478,6 +477,68 @@ static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv) } +#ifdef DEBUG +static const char *oid_to_string(__le32 oid) +{ + switch (oid) { +#define OID_STR(oid) case oid: return(#oid) + /* from rndis_host.h */ + OID_STR(OID_802_3_PERMANENT_ADDRESS); + OID_STR(OID_GEN_MAXIMUM_FRAME_SIZE); + OID_STR(OID_GEN_CURRENT_PACKET_FILTER); + OID_STR(OID_GEN_PHYSICAL_MEDIUM); + + /* from rndis_wlan.c */ + OID_STR(OID_GEN_LINK_SPEED); + OID_STR(OID_GEN_RNDIS_CONFIG_PARAMETER); + + OID_STR(OID_GEN_XMIT_OK); + OID_STR(OID_GEN_RCV_OK); + OID_STR(OID_GEN_XMIT_ERROR); + OID_STR(OID_GEN_RCV_ERROR); + OID_STR(OID_GEN_RCV_NO_BUFFER); + + OID_STR(OID_802_3_CURRENT_ADDRESS); + OID_STR(OID_802_3_MULTICAST_LIST); + OID_STR(OID_802_3_MAXIMUM_LIST_SIZE); + + OID_STR(OID_802_11_BSSID); + OID_STR(OID_802_11_SSID); + OID_STR(OID_802_11_INFRASTRUCTURE_MODE); + OID_STR(OID_802_11_ADD_WEP); + OID_STR(OID_802_11_REMOVE_WEP); + OID_STR(OID_802_11_DISASSOCIATE); + OID_STR(OID_802_11_AUTHENTICATION_MODE); + OID_STR(OID_802_11_PRIVACY_FILTER); + OID_STR(OID_802_11_BSSID_LIST_SCAN); + OID_STR(OID_802_11_ENCRYPTION_STATUS); + OID_STR(OID_802_11_ADD_KEY); + OID_STR(OID_802_11_REMOVE_KEY); + OID_STR(OID_802_11_ASSOCIATION_INFORMATION); + OID_STR(OID_802_11_PMKID); + OID_STR(OID_802_11_NETWORK_TYPES_SUPPORTED); + OID_STR(OID_802_11_NETWORK_TYPE_IN_USE); + OID_STR(OID_802_11_TX_POWER_LEVEL); + OID_STR(OID_802_11_RSSI); + OID_STR(OID_802_11_RSSI_TRIGGER); + OID_STR(OID_802_11_FRAGMENTATION_THRESHOLD); + OID_STR(OID_802_11_RTS_THRESHOLD); + OID_STR(OID_802_11_SUPPORTED_RATES); + OID_STR(OID_802_11_CONFIGURATION); + OID_STR(OID_802_11_BSSID_LIST); +#undef OID_STR + } + + return "?"; +} +#else +static const char *oid_to_string(__le32 oid) +{ + return "?"; +} +#endif + + /* translate error code */ static int rndis_error_status(__le32 rndis_status) { @@ -533,11 +594,21 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) u.get->oid = oid; ret = rndis_command(dev, u.header, buflen); + if (ret < 0) + devdbg(dev, "rndis_query_oid(%s): rndis_command() failed, %d " + "(%08x)", oid_to_string(oid), ret, + le32_to_cpu(u.get_c->status)); + if (ret == 0) { ret = le32_to_cpu(u.get_c->len); *len = (*len > ret) ? ret : *len; memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len); ret = rndis_error_status(u.get_c->status); + + if (ret < 0) + devdbg(dev, "rndis_query_oid(%s): device returned " + "error, 0x%08x (%d)", oid_to_string(oid), + le32_to_cpu(u.get_c->status), ret); } mutex_unlock(&priv->command_lock); @@ -583,9 +654,20 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) memcpy(u.buf + sizeof(*u.set), data, len); ret = rndis_command(dev, u.header, buflen); - if (ret == 0) + if (ret < 0) + devdbg(dev, "rndis_set_oid(%s): rndis_command() failed, %d " + "(%08x)", oid_to_string(oid), ret, + le32_to_cpu(u.set_c->status)); + + if (ret == 0) { ret = rndis_error_status(u.set_c->status); + if (ret < 0) + devdbg(dev, "rndis_set_oid(%s): device returned error, " + "0x%08x (%d)", oid_to_string(oid), + le32_to_cpu(u.set_c->status), ret); + } + mutex_unlock(&priv->command_lock); if (u.buf != priv->command_buffer) -- cgit v1.2.3-18-g5258 From 2a4901bcbe9c122bd56e1f6c337fcb4ad75fafb7 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Jul 2009 19:41:52 +0300 Subject: rndis_host: allow rndis_wlan to see all indications Allow rndis_wlan to see all indications. Currently rndis_host lets rndis_wlan to know about link state changes only, but there is whole set of other 802.11-specific indications that rndis_wlan should handle properly. So rename link_change() to indication() and convert rndis_wlan to use it. Signed-off-by: Jussi Kivilinna Cc: David Brownell Signed-off-by: John W. Linville --- drivers/net/usb/rndis_host.c | 50 +++++++++++++++++++++++---------------- drivers/net/wireless/rndis_wlan.c | 31 +++++++++++++++++++----- 2 files changed, 54 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index 2232232b798..d032bba9bc4 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -64,6 +64,32 @@ void rndis_status(struct usbnet *dev, struct urb *urb) } EXPORT_SYMBOL_GPL(rndis_status); +/* + * RNDIS indicate messages. + */ +static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg, + int buflen) +{ + struct cdc_state *info = (void *)&dev->data; + struct device *udev = &info->control->dev; + + if (dev->driver_info->indication) { + dev->driver_info->indication(dev, msg, buflen); + } else { + switch (msg->status) { + case RNDIS_STATUS_MEDIA_CONNECT: + dev_info(udev, "rndis media connect\n"); + break; + case RNDIS_STATUS_MEDIA_DISCONNECT: + dev_info(udev, "rndis media disconnect\n"); + break; + default: + dev_info(udev, "rndis indication: 0x%08x\n", + le32_to_cpu(msg->status)); + } + } +} + /* * RPC done RNDIS-style. Caller guarantees: * - message is properly byteswapped @@ -143,27 +169,9 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) request_id, xid); /* then likely retry */ } else switch (buf->msg_type) { - case RNDIS_MSG_INDICATE: { /* fault/event */ - struct rndis_indicate *msg = (void *)buf; - int state = 0; - - switch (msg->status) { - case RNDIS_STATUS_MEDIA_CONNECT: - state = 1; - case RNDIS_STATUS_MEDIA_DISCONNECT: - dev_info(&info->control->dev, - "rndis media %sconnect\n", - !state?"dis":""); - if (dev->driver_info->link_change) - dev->driver_info->link_change( - dev, state); - break; - default: - dev_info(&info->control->dev, - "rndis indication: 0x%08x\n", - le32_to_cpu(msg->status)); - } - } + case RNDIS_MSG_INDICATE: /* fault/event */ + rndis_msg_indicate(dev, (void *)buf, buflen); + break; case RNDIS_MSG_KEEPALIVE: { /* ping */ struct rndis_keepalive_c *msg = (void *)buf; diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index f6dcbb168b7..6b6452b0e8c 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2211,13 +2211,32 @@ static void rndis_wlan_set_multicast_list(struct net_device *dev) queue_work(priv->workqueue, &priv->work); } -static void rndis_wlan_link_change(struct usbnet *usbdev, int state) +static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + struct rndis_indicate *msg = ind; /* queue work to avoid recursive calls into rndis_command */ - set_bit(state ? WORK_LINK_UP : WORK_LINK_DOWN, &priv->work_pending); - queue_work(priv->workqueue, &priv->work); + switch (msg->status) { + case RNDIS_STATUS_MEDIA_CONNECT: + devinfo(usbdev, "media connect"); + + set_bit(WORK_LINK_UP, &priv->work_pending); + queue_work(priv->workqueue, &priv->work); + break; + + case RNDIS_STATUS_MEDIA_DISCONNECT: + devinfo(usbdev, "media disconnect"); + + set_bit(WORK_LINK_DOWN, &priv->work_pending); + queue_work(priv->workqueue, &priv->work); + break; + + default: + devinfo(usbdev, "indication: 0x%08x", + le32_to_cpu(msg->status)); + break; + } } @@ -2666,7 +2685,7 @@ static const struct driver_info bcm4320b_info = { .reset = rndis_wlan_reset, .stop = rndis_wlan_stop, .early_init = bcm4320b_early_init, - .link_change = rndis_wlan_link_change, + .indication = rndis_wlan_indication, }; static const struct driver_info bcm4320a_info = { @@ -2681,7 +2700,7 @@ static const struct driver_info bcm4320a_info = { .reset = rndis_wlan_reset, .stop = rndis_wlan_stop, .early_init = bcm4320a_early_init, - .link_change = rndis_wlan_link_change, + .indication = rndis_wlan_indication, }; static const struct driver_info rndis_wlan_info = { @@ -2696,7 +2715,7 @@ static const struct driver_info rndis_wlan_info = { .reset = rndis_wlan_reset, .stop = rndis_wlan_stop, .early_init = bcm4320a_early_init, - .link_change = rndis_wlan_link_change, + .indication = rndis_wlan_indication, }; /*-------------------------------------------------------------------------*/ -- cgit v1.2.3-18-g5258 From 030645aceb3d9f10b1c3d2231c50f5a8bb3a9667 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Jul 2009 19:41:58 +0300 Subject: rndis_wlan: handle 802.11 indications from device Add handling for 802.11 specific rndis indications. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 233 +++++++++++++++++++++++++++++++++++++- 1 file changed, 232 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 6b6452b0e8c..7a50cfa1884 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -201,6 +201,24 @@ enum ndis_80211_priv_filter { NDIS_80211_PRIV_8021X_WEP }; +enum ndis_80211_status_type { + NDIS_80211_STATUSTYPE_AUTHENTICATION, + NDIS_80211_STATUSTYPE_MEDIASTREAMMODE, + NDIS_80211_STATUSTYPE_PMKID_CANDIDATELIST, + NDIS_80211_STATUSTYPE_RADIOSTATE, +}; + +enum ndis_80211_media_stream_mode { + NDIS_80211_MEDIA_STREAM_OFF, + NDIS_80211_MEDIA_STREAM_ON +}; + +enum ndis_80211_radio_status { + NDIS_80211_RADIO_STATUS_ON, + NDIS_80211_RADIO_STATUS_HARDWARE_OFF, + NDIS_80211_RADIO_STATUS_SOFTWARE_OFF, +}; + enum ndis_80211_addkey_bits { NDIS_80211_ADDKEY_8021X_AUTH = cpu_to_le32(1 << 28), NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ = cpu_to_le32(1 << 29), @@ -213,6 +231,35 @@ enum ndis_80211_addwep_bits { NDIS_80211_ADDWEP_TRANSMIT_KEY = cpu_to_le32(1 << 31) }; +struct ndis_80211_auth_request { + __le32 length; + u8 bssid[6]; + u8 padding[2]; + __le32 flags; +} __attribute__((packed)); + +struct ndis_80211_pmkid_candidate { + u8 bssid[6]; + u8 padding[2]; + __le32 flags; +} __attribute__((packed)); + +struct ndis_80211_pmkid_cand_list { + __le32 version; + __le32 num_candidates; + struct ndis_80211_pmkid_candidate candidate_list[0]; +} __attribute__((packed)); + +struct ndis_80211_status_indication { + __le32 status_type; + union { + enum ndis_80211_media_stream_mode media_stream_mode; + enum ndis_80211_radio_status radio_status; + struct ndis_80211_auth_request auth_request[0]; + struct ndis_80211_pmkid_cand_list cand_list; + } u; +} __attribute__((packed)); + struct ndis_80211_ssid { __le32 length; u8 essid[NDIS_802_11_LENGTH_SSID]; @@ -2211,16 +2258,195 @@ static void rndis_wlan_set_multicast_list(struct net_device *dev) queue_work(priv->workqueue, &priv->work); } + +static void rndis_wlan_auth_indication(struct usbnet *usbdev, + struct ndis_80211_status_indication *indication, + int len) +{ + u8 *buf; + const char *type; + int flags, buflen; + bool pairwise_error, group_error; + struct ndis_80211_auth_request *auth_req; + + /* must have at least one array entry */ + if (len < offsetof(struct ndis_80211_status_indication, u) + + sizeof(struct ndis_80211_auth_request)) { + devinfo(usbdev, "authentication indication: " + "too short message (%i)", len); + return; + } + + buf = (void *)&indication->u.auth_request[0]; + buflen = len - offsetof(struct ndis_80211_status_indication, u); + + while (buflen >= sizeof(*auth_req)) { + auth_req = (void *)buf; + type = "unknown"; + flags = le32_to_cpu(auth_req->flags); + pairwise_error = false; + group_error = false; + + if (flags & 0x1) + type = "reauth request"; + if (flags & 0x2) + type = "key update request"; + if (flags & 0x6) { + pairwise_error = true; + type = "pairwise_error"; + } + if (flags & 0xe) { + group_error = true; + type = "group_error"; + } + + devinfo(usbdev, "authentication indication: %s (0x%08x)", type, + le32_to_cpu(auth_req->flags)); + + if (pairwise_error || group_error) { + union iwreq_data wrqu; + struct iw_michaelmicfailure micfailure; + + memset(&micfailure, 0, sizeof(micfailure)); + if (pairwise_error) + micfailure.flags |= IW_MICFAILURE_PAIRWISE; + if (group_error) + micfailure.flags |= IW_MICFAILURE_GROUP; + + memcpy(micfailure.src_addr.sa_data, auth_req->bssid, + ETH_ALEN); + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = sizeof(micfailure); + wireless_send_event(usbdev->net, IWEVMICHAELMICFAILURE, + &wrqu, (u8 *)&micfailure); + } + + buflen -= le32_to_cpu(auth_req->length); + buf += le32_to_cpu(auth_req->length); + } +} + +static void rndis_wlan_pmkid_cand_list_indication(struct usbnet *usbdev, + struct ndis_80211_status_indication *indication, + int len) +{ + struct ndis_80211_pmkid_cand_list *cand_list; + int list_len, expected_len, i; + + if (len < offsetof(struct ndis_80211_status_indication, u) + + sizeof(struct ndis_80211_pmkid_cand_list)) { + devinfo(usbdev, "pmkid candidate list indication: " + "too short message (%i)", len); + return; + } + + list_len = le32_to_cpu(indication->u.cand_list.num_candidates) * + sizeof(struct ndis_80211_pmkid_candidate); + expected_len = sizeof(struct ndis_80211_pmkid_cand_list) + list_len + + offsetof(struct ndis_80211_status_indication, u); + + if (len < expected_len) { + devinfo(usbdev, "pmkid candidate list indication: " + "list larger than buffer (%i < %i)", + len, expected_len); + return; + } + + cand_list = &indication->u.cand_list; + + devinfo(usbdev, "pmkid candidate list indication: " + "version %i, candidates %i", + le32_to_cpu(cand_list->version), + le32_to_cpu(cand_list->num_candidates)); + + if (le32_to_cpu(cand_list->version) != 1) + return; + + for (i = 0; i < le32_to_cpu(cand_list->num_candidates); i++) { + struct iw_pmkid_cand pcand; + union iwreq_data wrqu; + struct ndis_80211_pmkid_candidate *cand = + &cand_list->candidate_list[i]; + + devdbg(usbdev, "cand[%i]: flags: 0x%08x, bssid: %pM", + i, le32_to_cpu(cand->flags), cand->bssid); + + memset(&pcand, 0, sizeof(pcand)); + if (le32_to_cpu(cand->flags) & 0x01) + pcand.flags |= IW_PMKID_CAND_PREAUTH; + pcand.index = i; + memcpy(pcand.bssid.sa_data, cand->bssid, ETH_ALEN); + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = sizeof(pcand); + wireless_send_event(usbdev->net, IWEVPMKIDCAND, &wrqu, + (u8 *)&pcand); + } +} + +static void rndis_wlan_media_specific_indication(struct usbnet *usbdev, + struct rndis_indicate *msg, int buflen) +{ + struct ndis_80211_status_indication *indication; + int len, offset; + + offset = offsetof(struct rndis_indicate, status) + + le32_to_cpu(msg->offset); + len = le32_to_cpu(msg->length); + + if (len < 8) { + devinfo(usbdev, "media specific indication, " + "ignore too short message (%i < 8)", len); + return; + } + + if (offset + len > buflen) { + devinfo(usbdev, "media specific indication, " + "too large to fit to buffer (%i > %i)", + offset + len, buflen); + return; + } + + indication = (void *)((u8 *)msg + offset); + + switch (le32_to_cpu(indication->status_type)) { + case NDIS_80211_STATUSTYPE_RADIOSTATE: + devinfo(usbdev, "radio state indication: %i", + le32_to_cpu(indication->u.radio_status)); + return; + + case NDIS_80211_STATUSTYPE_MEDIASTREAMMODE: + devinfo(usbdev, "media stream mode indication: %i", + le32_to_cpu(indication->u.media_stream_mode)); + return; + + case NDIS_80211_STATUSTYPE_AUTHENTICATION: + rndis_wlan_auth_indication(usbdev, indication, len); + return; + + case NDIS_80211_STATUSTYPE_PMKID_CANDIDATELIST: + rndis_wlan_pmkid_cand_list_indication(usbdev, indication, len); + return; + + default: + devinfo(usbdev, "media specific indication: " + "unknown status type 0x%08x", + le32_to_cpu(indication->status_type)); + } +} + + static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct rndis_indicate *msg = ind; - /* queue work to avoid recursive calls into rndis_command */ switch (msg->status) { case RNDIS_STATUS_MEDIA_CONNECT: devinfo(usbdev, "media connect"); + /* queue work to avoid recursive calls into rndis_command */ set_bit(WORK_LINK_UP, &priv->work_pending); queue_work(priv->workqueue, &priv->work); break; @@ -2228,10 +2454,15 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) case RNDIS_STATUS_MEDIA_DISCONNECT: devinfo(usbdev, "media disconnect"); + /* queue work to avoid recursive calls into rndis_command */ set_bit(WORK_LINK_DOWN, &priv->work_pending); queue_work(priv->workqueue, &priv->work); break; + case RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION: + rndis_wlan_media_specific_indication(usbdev, msg, buflen); + break; + default: devinfo(usbdev, "indication: 0x%08x", le32_to_cpu(msg->status)); -- cgit v1.2.3-18-g5258 From 9d40934e5e28314731d4b32acd2fdf5fb805a3ed Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Jul 2009 19:42:03 +0300 Subject: rndis_wlan: add missing padding to struct rndis_80211_remove_key OID_802_11_REMOVE_KEY failed with invalid length error, add missing padding to structure fix this. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 7a50cfa1884..3d92b77d959 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -327,6 +327,7 @@ struct ndis_80211_remove_key { __le32 size; __le32 index; u8 bssid[6]; + u8 padding[2]; } __attribute__((packed)); struct ndis_config_param { -- cgit v1.2.3-18-g5258 From b7cfc5b35eed2fe8a5c45793e6e52ef0edddc824 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Jul 2009 19:42:08 +0300 Subject: rndis_wlan: rework key handling Organize key data in private structure better and store WPA keys, so they can be restored as WEP keys. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 188 ++++++++++++++++++++++++++++---------- 1 file changed, 142 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 3d92b77d959..828dc1825bb 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -413,6 +413,15 @@ static const struct ieee80211_rate rndis_rates[] = { { .bitrate = 540 } }; +struct rndis_wlan_encr_key { + int len; + int cipher; + u8 material[32]; + u8 bssid[ETH_ALEN]; + bool pairwise; + bool tx_key; +}; + /* RNDIS device private data */ struct rndis_wlan_private { struct usbnet *usbdev; @@ -456,9 +465,7 @@ struct rndis_wlan_private { /* encryption stuff */ int encr_tx_key_index; - char encr_keys[4][32]; - int encr_key_len[4]; - char encr_key_wpa[4]; + struct rndis_wlan_encr_key encr_keys[4]; int wpa_version; int wpa_keymgmt; int wpa_authalg; @@ -525,6 +532,15 @@ static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv) } +static bool is_wpa_key(struct rndis_wlan_private *priv, int idx) +{ + int cipher = priv->encr_keys[idx].cipher; + + return (cipher == WLAN_CIPHER_SUITE_CCMP || + cipher == WLAN_CIPHER_SUITE_TKIP); +} + + #ifdef DEBUG static const char *oid_to_string(__le32 oid) { @@ -895,8 +911,7 @@ static int freq_to_dsconfig(struct iw_freq *freq, unsigned int *dsconfig) /* * common functions */ -static int -add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index); +static void restore_keys(struct usbnet *usbdev); static int get_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) { @@ -1115,7 +1130,7 @@ static int set_infra_mode(struct usbnet *usbdev, int mode) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; - int ret, i; + int ret; devdbg(usbdev, "set_infra_mode: infra_mode=0x%x", priv->infra_mode); @@ -1130,14 +1145,7 @@ static int set_infra_mode(struct usbnet *usbdev, int mode) /* NDIS drivers clear keys when infrastructure mode is * changed. But Linux tools assume otherwise. So set the * keys */ - if (priv->wpa_keymgmt == 0 || - priv->wpa_keymgmt == IW_AUTH_KEY_MGMT_802_1X) { - for (i = 0; i < 4; i++) { - if (priv->encr_key_len[i] > 0 && !priv->encr_key_wpa[i]) - add_wep_key(usbdev, priv->encr_keys[i], - priv->encr_key_len[i], i); - } - } + restore_keys(usbdev); priv->infra_mode = mode; return 0; @@ -1204,11 +1212,16 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_wep_key ndis_key; - int ret; + int cipher, ret; - if (key_len <= 0 || key_len > 32 || index < 0 || index >= 4) + if ((key_len != 5 || key_len != 13) || index < 0 || index > 3) return -EINVAL; + if (key_len == 5) + cipher = WLAN_CIPHER_SUITE_WEP40; + else + cipher = WLAN_CIPHER_SUITE_WEP104; + memset(&ndis_key, 0, sizeof(ndis_key)); ndis_key.size = cpu_to_le32(sizeof(ndis_key)); @@ -1233,30 +1246,44 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) return ret; } - priv->encr_key_len[index] = key_len; - priv->encr_key_wpa[index] = 0; - memcpy(&priv->encr_keys[index], key, key_len); + priv->encr_keys[index].len = key_len; + priv->encr_keys[index].cipher = cipher; + memcpy(&priv->encr_keys[index].material, key, key_len); + memset(&priv->encr_keys[index].bssid, 0xff, ETH_ALEN); return 0; } static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, - int index, const struct sockaddr *addr, - const u8 *rx_seq, int alg, int flags) + int index, const u8 *addr, const u8 *rx_seq, int cipher, + int flags) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_key ndis_key; + bool is_addr_ok; int ret; - if (index < 0 || index >= 4) + if (index < 0 || index >= 4) { + devdbg(usbdev, "add_wpa_key: index out of range (%i)", index); return -EINVAL; - if (key_len > sizeof(ndis_key.material) || key_len < 0) + } + if (key_len > sizeof(ndis_key.material) || key_len < 0) { + devdbg(usbdev, "add_wpa_key: key length out of range (%i)", + key_len); return -EINVAL; - if ((flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) && !rx_seq) + } + if ((flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) && !rx_seq) { + devdbg(usbdev, "add_wpa_key: recv seq flag without buffer"); return -EINVAL; - if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !addr) + } + is_addr_ok = addr && memcmp(addr, zero_bssid, ETH_ALEN) != 0 && + memcmp(addr, ffff_bssid, ETH_ALEN) != 0; + if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !is_addr_ok) { + devdbg(usbdev, "add_wpa_key: pairwise but bssid invalid (%pM)", + addr); return -EINVAL; + } devdbg(usbdev, "add_wpa_key(%i): flags:%i%i%i", index, !!(flags & NDIS_80211_ADDKEY_TRANSMIT_KEY), @@ -1270,7 +1297,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, ndis_key.length = cpu_to_le32(key_len); ndis_key.index = cpu_to_le32(index) | flags; - if (alg == IW_ENCODE_ALG_TKIP && key_len == 32) { + if (cipher == WLAN_CIPHER_SUITE_TKIP && key_len == 32) { /* wpa_supplicant gives us the Michael MIC RX/TX keys in * different order than NDIS spec, so swap the order here. */ memcpy(ndis_key.material, key, 16); @@ -1284,7 +1311,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) { /* pairwise key */ - memcpy(ndis_key.bssid, addr->sa_data, ETH_ALEN); + memcpy(ndis_key.bssid, addr, ETH_ALEN); } else { /* group key */ if (priv->infra_mode == NDIS_80211_INFRA_ADHOC) @@ -1299,8 +1326,14 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, if (ret != 0) return ret; - priv->encr_key_len[index] = key_len; - priv->encr_key_wpa[index] = 1; + memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index])); + priv->encr_keys[index].len = key_len; + priv->encr_keys[index].cipher = cipher; + memcpy(&priv->encr_keys[index].material, key, key_len); + if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) + memcpy(&priv->encr_keys[index].bssid, ndis_key.bssid, ETH_ALEN); + else + memset(&priv->encr_keys[index].bssid, 0xff, ETH_ALEN); if (flags & NDIS_80211_ADDKEY_TRANSMIT_KEY) priv->encr_tx_key_index = index; @@ -1309,25 +1342,74 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, } +static int restore_key(struct usbnet *usbdev, int key_idx) +{ + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + struct rndis_wlan_encr_key key; + int flags; + + key = priv->encr_keys[key_idx]; + + devdbg(usbdev, "restore_key: %i:%s:%i", key_idx, + is_wpa_key(priv, key_idx) ? "wpa" : "wep", + key.len); + + if (key.len == 0) + return 0; + + if (is_wpa_key(priv, key_idx)) { + flags = 0; + + /*if (priv->encr_tx_key_index == key_idx) + flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY;*/ + + if (memcmp(key.bssid, zero_bssid, ETH_ALEN) != 0 && + memcmp(key.bssid, ffff_bssid, ETH_ALEN) != 0) + flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY; + + return add_wpa_key(usbdev, key.material, key.len, key_idx, + key.bssid, NULL, key.cipher, flags); + } + + return add_wep_key(usbdev, key.material, key.len, key_idx); +} + + +static void restore_keys(struct usbnet *usbdev) +{ + int i; + + for (i = 0; i < 4; i++) + restore_key(usbdev, i); +} + + +static void clear_key(struct rndis_wlan_private *priv, int idx) +{ + memset(&priv->encr_keys[idx], 0, sizeof(priv->encr_keys[idx])); +} + + /* remove_key is for both wep and wpa */ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_remove_key remove_key; __le32 keyindex; + bool is_wpa; int ret; - if (priv->encr_key_len[index] == 0) + if (priv->encr_keys[index].len == 0) return 0; - priv->encr_key_len[index] = 0; - priv->encr_key_wpa[index] = 0; - memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index])); + is_wpa = is_wpa_key(priv, index); - if (priv->wpa_cipher_pair == IW_AUTH_CIPHER_TKIP || - priv->wpa_cipher_pair == IW_AUTH_CIPHER_CCMP || - priv->wpa_cipher_group == IW_AUTH_CIPHER_TKIP || - priv->wpa_cipher_group == IW_AUTH_CIPHER_CCMP) { + devdbg(usbdev, "remove_key: %i:%s:%i", index, is_wpa ? "wpa" : "wep", + priv->encr_keys[index].len); + + clear_key(priv, index); + + if (is_wpa) { remove_key.size = cpu_to_le32(sizeof(remove_key)); remove_key.index = cpu_to_le32(index); if (bssid) { @@ -1871,8 +1953,9 @@ static int rndis_iw_set_encode(struct net_device *dev, { struct usbnet *usbdev = netdev_priv(dev); struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + struct rndis_wlan_encr_key key; int ret, index, key_len; - u8 *key; + u8 *keybuf; index = (wrqu->encoding.flags & IW_ENCODE_INDEX); @@ -1907,17 +1990,18 @@ static int rndis_iw_set_encode(struct net_device *dev, if (wrqu->data.length > 0) { key_len = wrqu->data.length; - key = extra; + keybuf = extra; } else { /* must be set as tx key */ - if (priv->encr_key_len[index] == 0) + if (priv->encr_keys[index].len == 0) return -EINVAL; - key_len = priv->encr_key_len[index]; key = priv->encr_keys[index]; + key_len = key.len; + keybuf = key.material; priv->encr_tx_key_index = index; } - if (add_wep_key(usbdev, key, key_len, index) != 0) + if (add_wep_key(usbdev, keybuf, key_len, index) != 0) return -EINVAL; if (index == priv->encr_tx_key_index) @@ -1934,7 +2018,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; struct usbnet *usbdev = netdev_priv(dev); struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int keyidx, flags; + int keyidx, flags, cipher; keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX; @@ -1944,8 +2028,10 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, else keyidx = priv->encr_tx_key_index; - if (keyidx < 0 || keyidx >= 4) + if (keyidx < 0 || keyidx >= 4) { + devwarn(usbdev, "encryption index out of range (%u)", keyidx); return -EINVAL; + } if (ext->alg == WPA_ALG_WEP) { if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) @@ -1953,10 +2039,19 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, return add_wep_key(usbdev, ext->key, ext->key_len, keyidx); } + cipher = -1; + if (ext->alg == IW_ENCODE_ALG_TKIP) + cipher = WLAN_CIPHER_SUITE_TKIP; + else if (ext->alg == IW_ENCODE_ALG_CCMP) + cipher = WLAN_CIPHER_SUITE_CCMP; + if ((wrqu->encoding.flags & IW_ENCODE_DISABLED) || ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0) return remove_key(usbdev, keyidx, NULL); + if (cipher == -1) + return -EOPNOTSUPP; + flags = 0; if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) flags |= NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ; @@ -1965,8 +2060,9 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY; - return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx, &ext->addr, - ext->rx_seq, ext->alg, flags); + return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx, + (u8 *)&ext->addr.sa_data, ext->rx_seq, cipher, + flags); } -- cgit v1.2.3-18-g5258 From 97cad51e191919b43aabdc85b83241b66c3fcf2c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 30 Jul 2009 21:37:27 -0400 Subject: iwlwifi: remove usage of orig_flags This is a private flag, internal to cfg80211. cfg80211 will set orig_* stuff internally upon wiphy registration, drivers do not need to muck with it. Signed-off-by: Luis R. Rodriguez Acked-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 1b5180f8d75..6797076bd45 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -548,9 +548,6 @@ int iwlcore_init_geos(struct iwl_priv *priv) geo_ch->flags |= IEEE80211_CHAN_DISABLED; } - /* Save flags for reg domain usage */ - geo_ch->orig_flags = geo_ch->flags; - IWL_DEBUG_INFO(priv, "Channel %d Freq=%d[%sGHz] %s flag=0x%X\n", ch->channel, geo_ch->center_freq, is_channel_a_band(ch) ? "5.2" : "2.4", -- cgit v1.2.3-18-g5258 From 88d89526a671ba008f59456161b0c513cdfb5d5a Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Fri, 31 Jul 2009 11:35:19 -0700 Subject: libertas: check valid bits in SPI bus mode reg The SPI driver writes to the bus mode register and performs a sanity check by reading back what we wrote, however only the lower four bits of that register are defined. In some cases, the device side seems to set the higher bits, causing us to fail the sanity check unnecessarily. Check only the lower four bits instead. Thanks to John Goyette from Schick Technologies for pointing out the problem. Signed-off-by: Andrey Yurovsky Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 963c20125fc..446e327180f 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -376,7 +376,7 @@ static int spu_set_bus_mode(struct if_spi_card *card, u16 mode) err = spu_read_u16(card, IF_SPI_SPU_BUS_MODE_REG, &rval); if (err) return err; - if (rval != mode) { + if ((rval & 0xF) != mode) { lbs_pr_err("Can't read bus mode register.\n"); return -EIO; } -- cgit v1.2.3-18-g5258 From f62ae6cd887a184d6923037d588b5b2466aa2a97 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 31 Jul 2009 20:51:41 +0200 Subject: b43: Fix unaligned 32bit SHM-shared access This fixes unaligned 32bit SHM-shared read/write access. The low and high 16 bits were swapped. It also adds a testcase for this to the chipaccess validation. (Thanks to Albert Herranz for tracking down this bug.) Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index f985938962e..a048de5fcc7 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -395,9 +395,8 @@ u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) /* Unaligned access */ b43_shm_control_word(dev, routing, offset >> 2); ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED); - ret <<= 16; b43_shm_control_word(dev, routing, (offset >> 2) + 1); - ret |= b43_read16(dev, B43_MMIO_SHM_DATA); + ret |= ((u32)b43_read16(dev, B43_MMIO_SHM_DATA)) << 16; goto out; } @@ -464,9 +463,10 @@ void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value /* Unaligned access */ b43_shm_control_word(dev, routing, offset >> 2); b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, - (value >> 16) & 0xffff); + value & 0xFFFF); b43_shm_control_word(dev, routing, (offset >> 2) + 1); - b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff); + b43_write16(dev, B43_MMIO_SHM_DATA, + (value >> 16) & 0xFFFF); return; } offset >>= 2; @@ -2931,9 +2931,10 @@ static void b43_periodic_tasks_setup(struct b43_wldev *dev) /* Check if communication with the device works correctly. */ static int b43_validate_chipaccess(struct b43_wldev *dev) { - u32 v, backup; + u32 v, backup0, backup4; - backup = b43_shm_read32(dev, B43_SHM_SHARED, 0); + backup0 = b43_shm_read32(dev, B43_SHM_SHARED, 0); + backup4 = b43_shm_read32(dev, B43_SHM_SHARED, 4); /* Check for read/write and endianness problems. */ b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55); @@ -2943,7 +2944,23 @@ static int b43_validate_chipaccess(struct b43_wldev *dev) if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA) goto error; - b43_shm_write32(dev, B43_SHM_SHARED, 0, backup); + /* Check if unaligned 32bit SHM_SHARED access works properly. + * However, don't bail out on failure, because it's noncritical. */ + b43_shm_write16(dev, B43_SHM_SHARED, 0, 0x1122); + b43_shm_write16(dev, B43_SHM_SHARED, 2, 0x3344); + b43_shm_write16(dev, B43_SHM_SHARED, 4, 0x5566); + b43_shm_write16(dev, B43_SHM_SHARED, 6, 0x7788); + if (b43_shm_read32(dev, B43_SHM_SHARED, 2) != 0x55663344) + b43warn(dev->wl, "Unaligned 32bit SHM read access is broken\n"); + b43_shm_write32(dev, B43_SHM_SHARED, 2, 0xAABBCCDD); + if (b43_shm_read16(dev, B43_SHM_SHARED, 0) != 0x1122 || + b43_shm_read16(dev, B43_SHM_SHARED, 2) != 0xCCDD || + b43_shm_read16(dev, B43_SHM_SHARED, 4) != 0xAABB || + b43_shm_read16(dev, B43_SHM_SHARED, 6) != 0x7788) + b43warn(dev->wl, "Unaligned 32bit SHM write access is broken\n"); + + b43_shm_write32(dev, B43_SHM_SHARED, 0, backup0); + b43_shm_write32(dev, B43_SHM_SHARED, 4, backup4); if ((dev->dev->id.revision >= 3) && (dev->dev->id.revision <= 10)) { /* The 32bit register shadows the two 16bit registers -- cgit v1.2.3-18-g5258 From 92ca8d437fdbb482752534885d86af264897da85 Mon Sep 17 00:00:00 2001 From: gregor kowski Date: Fri, 31 Jul 2009 22:35:49 +0200 Subject: b43: remove wrong probe_resp_plcp write The tkip hw support uncovered a bug in b43_write_probe_resp_template : it is writing at the wrong shm offset, it is in the B43_SHM_SH_TKIPTSCTTAK zone. This patch comments these writes. Signed-off-by: Gregor Kowski Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index a048de5fcc7..925f346ea36 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1524,10 +1524,13 @@ static void b43_write_probe_resp_template(struct b43_wldev *dev, /* Looks like PLCP headers plus packet timings are stored for * all possible basic rates */ + /* FIXME this is the wrong offset : it goes in tkip rx phase1 shm */ +#if 0 b43_write_probe_resp_plcp(dev, 0x31A, size, &b43_b_ratetable[0]); b43_write_probe_resp_plcp(dev, 0x32C, size, &b43_b_ratetable[1]); b43_write_probe_resp_plcp(dev, 0x33E, size, &b43_b_ratetable[2]); b43_write_probe_resp_plcp(dev, 0x350, size, &b43_b_ratetable[3]); +#endif size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6)); b43_write_template_common(dev, probe_resp_data, -- cgit v1.2.3-18-g5258 From 8ce73f3abd064081706cc337c771378fc4431ef3 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Fri, 31 Jul 2009 14:28:06 -0700 Subject: iwlwifi: clear iwl_cmd_meta structure before use Resolve an issue in which out-dated fields in iwl_cmd_meta could be used for later hardware commands. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 6bb9602f347..288b871e974 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -970,6 +970,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) out_cmd = txq->cmd[idx]; out_meta = &txq->meta[idx]; + memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */ out_meta->flags = cmd->flags; if (cmd->flags & CMD_WANT_SKB) out_meta->source = cmd; -- cgit v1.2.3-18-g5258 From 65b7998a9be418482493e9448bb83ff2914ed050 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 31 Jul 2009 14:28:07 -0700 Subject: iwlwifi: Distinguish power amplifier for 6000 series For 6x00 2x2 NIC, two types of Power Amplifier are available. In order for uCode to apply correct tx power, driver needs to program the CSR_GP_DRIVER_REG register and let uCode know the type of PA. If driver do not program CSR_GP_DRIVER_REG register (default to 0), then it is uCode's decision for tx power 2x2 Hybrid card: use both internal and external PA 2x2 IPA(Internal Power Amplifier) card: internal PA only Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 14 ++++++++- drivers/net/wireless/iwlwifi/iwl-5000.c | 8 +----- drivers/net/wireless/iwlwifi/iwl-6000.c | 50 +++++++++++++++++++++++++++++++-- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 ++++-- drivers/net/wireless/iwlwifi/iwl-core.h | 3 ++ drivers/net/wireless/iwlwifi/iwl-csr.h | 10 ++++++- drivers/net/wireless/iwlwifi/iwl-dev.h | 16 ++++++++++- 7 files changed, 94 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 5f7c52053c1..cf3fbc6b98e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -73,6 +73,18 @@ static void iwl1000_set_ct_threshold(struct iwl_priv *priv) priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; } +/* NIC configuration for 1000 series */ +static void iwl1000_nic_config(struct iwl_priv *priv) +{ + iwl5000_nic_config(priv); + + /* Setting digital SVR for 1000 card to 1.32V */ + /* locking is acquired in iwl_set_bits_mask_prph() function */ + iwl_set_bits_mask_prph(priv, APMG_DIGITAL_SVR_REG, + APMG_SVR_DIGITAL_VOLTAGE_1_32, + ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK); +} + static struct iwl_lib_ops iwl1000_lib = { .set_hw_params = iwl5000_hw_set_hw_params, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, @@ -95,7 +107,7 @@ static struct iwl_lib_ops iwl1000_lib = { .init = iwl5000_apm_init, .reset = iwl5000_apm_reset, .stop = iwl5000_apm_stop, - .config = iwl5000_nic_config, + .config = iwl1000_nic_config, .set_pwr_src = iwl_set_pwr_src, }, .eeprom_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index ddd64fef303..87957c05283 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -198,6 +198,7 @@ out: } +/* NIC configuration for 5000 series and up */ void iwl5000_nic_config(struct iwl_priv *priv) { unsigned long flags; @@ -239,18 +240,11 @@ void iwl5000_nic_config(struct iwl_priv *priv) APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); - if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_1000) { - /* Setting digital SVR for 1000 card to 1.32V */ - iwl_set_bits_mask_prph(priv, APMG_DIGITAL_SVR_REG, - APMG_SVR_DIGITAL_VOLTAGE_1_32, - ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK); - } spin_unlock_irqrestore(&priv->lock, flags); } - /* * EEPROM */ diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 59ff73536f3..052a704f236 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -68,6 +68,24 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv) priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; } +/* NIC configuration for 6000 series */ +static void iwl6000_nic_config(struct iwl_priv *priv) +{ + iwl5000_nic_config(priv); + + /* no locking required for register write */ + if (priv->cfg->pa_type == IWL_PA_HYBRID) { + /* 2x2 hybrid phy type */ + iwl_write32(priv, CSR_GP_DRIVER_REG, + CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_HYB); + } else if (priv->cfg->pa_type == IWL_PA_INTERNAL) { + /* 2x2 IPA phy type */ + iwl_write32(priv, CSR_GP_DRIVER_REG, + CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA); + } + /* else do nothing, uCode configured */ +} + static struct iwl_lib_ops iwl6000_lib = { .set_hw_params = iwl5000_hw_set_hw_params, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, @@ -90,7 +108,7 @@ static struct iwl_lib_ops iwl6000_lib = { .init = iwl5000_apm_init, .reset = iwl5000_apm_reset, .stop = iwl5000_apm_stop, - .config = iwl5000_nic_config, + .config = iwl6000_nic_config, .set_pwr_src = iwl_set_pwr_src, }, .eeprom_ops = { @@ -146,9 +164,13 @@ struct iwl_cfg iwl6000_2ag_cfg = { .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, .need_pll_cfg = false, + .pa_type = IWL_PA_SYSTEM, }; -struct iwl_cfg iwl6000_2agn_cfg = { +/* + * "h": Hybrid configuration, use both internal and external Power Amplifier + */ +struct iwl_cfg iwl6000h_2agn_cfg = { .name = "6000 Series 2x2 AGN", .fw_name_pre = IWL6000_FW_PRE, .ucode_api_max = IWL6000_UCODE_API_MAX, @@ -162,6 +184,27 @@ struct iwl_cfg iwl6000_2agn_cfg = { .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .need_pll_cfg = false, + .pa_type = IWL_PA_HYBRID, +}; + +/* + * "i": Internal configuration, use internal Power Amplifier + */ +struct iwl_cfg iwl6000i_2agn_cfg = { + .name = "6000 Series 2x2 AGN", + .fw_name_pre = IWL6000_FW_PRE, + .ucode_api_max = IWL6000_UCODE_API_MAX, + .ucode_api_min = IWL6000_UCODE_API_MIN, + .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .ops = &iwl6000_ops, + .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .mod_params = &iwl50_mod_params, + .valid_tx_ant = ANT_BC, + .valid_rx_ant = ANT_BC, + .need_pll_cfg = false, + .pa_type = IWL_PA_INTERNAL, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -178,6 +221,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .need_pll_cfg = false, + .pa_type = IWL_PA_SYSTEM, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -194,6 +238,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, .need_pll_cfg = false, + .pa_type = IWL_PA_SYSTEM, }; struct iwl_cfg iwl6050_3agn_cfg = { @@ -210,6 +255,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, .need_pll_cfg = false, + .pa_type = IWL_PA_SYSTEM, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 4cb1a1b7348..a54330b2443 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3142,11 +3142,13 @@ static struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x0082, 0x1102, iwl6000_2ag_cfg)}, {IWL_PCI_DEVICE(0x0085, 0x1112, iwl6000_2ag_cfg)}, {IWL_PCI_DEVICE(0x0082, 0x1122, iwl6000_2ag_cfg)}, + {IWL_PCI_DEVICE(0x008D, PCI_ANY_ID, iwl6000h_2agn_cfg)}, + {IWL_PCI_DEVICE(0x008E, PCI_ANY_ID, iwl6000h_2agn_cfg)}, {IWL_PCI_DEVICE(0x422B, PCI_ANY_ID, iwl6000_3agn_cfg)}, - {IWL_PCI_DEVICE(0x422C, PCI_ANY_ID, iwl6000_2agn_cfg)}, + {IWL_PCI_DEVICE(0x422C, PCI_ANY_ID, iwl6000i_2agn_cfg)}, {IWL_PCI_DEVICE(0x4238, PCI_ANY_ID, iwl6000_3agn_cfg)}, - {IWL_PCI_DEVICE(0x4239, PCI_ANY_ID, iwl6000_2agn_cfg)}, - {IWL_PCI_DEVICE(0x0082, PCI_ANY_ID, iwl6000_2agn_cfg)}, + {IWL_PCI_DEVICE(0x4239, PCI_ANY_ID, iwl6000i_2agn_cfg)}, + {IWL_PCI_DEVICE(0x0082, PCI_ANY_ID, iwl6000h_2agn_cfg)}, {IWL_PCI_DEVICE(0x0085, PCI_ANY_ID, iwl6000_3agn_cfg)}, {IWL_PCI_DEVICE(0x0086, PCI_ANY_ID, iwl6050_3agn_cfg)}, {IWL_PCI_DEVICE(0x0087, PCI_ANY_ID, iwl6050_2agn_cfg)}, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index febcf76e1d4..10ddcdda104 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -206,6 +206,7 @@ struct iwl_mod_params { * filename is constructed as fw_name_pre.ucode. * @ucode_api_max: Highest version of uCode API supported by driver. * @ucode_api_min: Lowest version of uCode API supported by driver. + * @pa_type: used by 6000 series only to identify the type of Power Amplifier * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -226,6 +227,7 @@ struct iwl_mod_params { * iwl_hcmd_utils_ops etc. we accommodate different command structures * and flows between hardware versions (4965/5000) as well as their API * versions. + * */ struct iwl_cfg { const char *name; @@ -242,6 +244,7 @@ struct iwl_cfg { u8 valid_rx_ant; bool need_pll_cfg; bool use_isr_legacy; + enum iwl_pa_type pa_type; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index f03dae1b2f3..06437d13e73 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -91,7 +91,8 @@ #define CSR_EEPROM_GP (CSR_BASE+0x030) #define CSR_OTP_GP_REG (CSR_BASE+0x034) #define CSR_GIO_REG (CSR_BASE+0x03C) -#define CSR_GP_UCODE (CSR_BASE+0x044) +#define CSR_GP_UCODE_REG (CSR_BASE+0x048) +#define CSR_GP_DRIVER_REG (CSR_BASE+0x050) #define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) #define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058) #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) @@ -245,6 +246,13 @@ #define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) #define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008) +/* GP Driver */ +#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_MSK (0x00000003) +#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_3x3_HYB (0x00000000) +#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_HYB (0x00000001) +#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA (0x00000002) + + /* GI Chicken Bits */ #define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) #define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0ee3ad24569..335a8f34bc5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -57,7 +57,8 @@ extern struct iwl_cfg iwl5100_bg_cfg; extern struct iwl_cfg iwl5100_abg_cfg; extern struct iwl_cfg iwl5150_agn_cfg; extern struct iwl_cfg iwl6000_2ag_cfg; -extern struct iwl_cfg iwl6000_2agn_cfg; +extern struct iwl_cfg iwl6000h_2agn_cfg; +extern struct iwl_cfg iwl6000i_2agn_cfg; extern struct iwl_cfg iwl6000_3agn_cfg; extern struct iwl_cfg iwl6050_2agn_cfg; extern struct iwl_cfg iwl6050_3agn_cfg; @@ -888,6 +889,19 @@ enum iwl_nvm_type { NVM_DEVICE_TYPE_OTP, }; + +/** + * enum iwl_pa_type - Power Amplifier type + * @IWL_PA_SYSTEM: based on uCode configuration + * @IWL_PA_HYBRID: use both Internal and external PA + * @IWL_PA_INTERNAL: use Internal only + */ +enum iwl_pa_type { + IWL_PA_SYSTEM = 0, + IWL_PA_HYBRID = 1, + IWL_PA_INTERNAL = 2, +}; + /* interrupt statistics */ struct isr_statistics { u32 hw; -- cgit v1.2.3-18-g5258 From a11c4d000b84f7f49ebefc018c24bbfa3c9c0f3b Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 31 Jul 2009 14:28:08 -0700 Subject: iwlwifi: remove deprecated 6000 series adapters Remove the support for deprecated devices. These devices are engineering samples and no longer supported by the uCode. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 16 ---------------- drivers/net/wireless/iwlwifi/iwl-agn.c | 5 ----- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - 3 files changed, 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 052a704f236..4450943d3da 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -150,22 +150,6 @@ static struct iwl_ops iwl6000_ops = { .utils = &iwl6000_hcmd_utils, }; -struct iwl_cfg iwl6000_2ag_cfg = { - .name = "6000 Series 2x2 AG", - .fw_name_pre = IWL6000_FW_PRE, - .ucode_api_max = IWL6000_UCODE_API_MAX, - .ucode_api_min = IWL6000_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G, - .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, - .eeprom_ver = EEPROM_5000_EEPROM_VERSION, - .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, - .mod_params = &iwl50_mod_params, - .valid_tx_ant = ANT_BC, - .valid_rx_ant = ANT_BC, - .need_pll_cfg = false, - .pa_type = IWL_PA_SYSTEM, -}; /* * "h": Hybrid configuration, use both internal and external Power Amplifier diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index a54330b2443..467c8617cb7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3139,17 +3139,12 @@ static struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x423C, PCI_ANY_ID, iwl5150_agn_cfg)}, {IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)}, /* 6000/6050 Series */ - {IWL_PCI_DEVICE(0x0082, 0x1102, iwl6000_2ag_cfg)}, - {IWL_PCI_DEVICE(0x0085, 0x1112, iwl6000_2ag_cfg)}, - {IWL_PCI_DEVICE(0x0082, 0x1122, iwl6000_2ag_cfg)}, {IWL_PCI_DEVICE(0x008D, PCI_ANY_ID, iwl6000h_2agn_cfg)}, {IWL_PCI_DEVICE(0x008E, PCI_ANY_ID, iwl6000h_2agn_cfg)}, {IWL_PCI_DEVICE(0x422B, PCI_ANY_ID, iwl6000_3agn_cfg)}, {IWL_PCI_DEVICE(0x422C, PCI_ANY_ID, iwl6000i_2agn_cfg)}, {IWL_PCI_DEVICE(0x4238, PCI_ANY_ID, iwl6000_3agn_cfg)}, {IWL_PCI_DEVICE(0x4239, PCI_ANY_ID, iwl6000i_2agn_cfg)}, - {IWL_PCI_DEVICE(0x0082, PCI_ANY_ID, iwl6000h_2agn_cfg)}, - {IWL_PCI_DEVICE(0x0085, PCI_ANY_ID, iwl6000_3agn_cfg)}, {IWL_PCI_DEVICE(0x0086, PCI_ANY_ID, iwl6050_3agn_cfg)}, {IWL_PCI_DEVICE(0x0087, PCI_ANY_ID, iwl6050_2agn_cfg)}, {IWL_PCI_DEVICE(0x0088, PCI_ANY_ID, iwl6050_3agn_cfg)}, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 335a8f34bc5..cab6255210d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -56,7 +56,6 @@ extern struct iwl_cfg iwl5350_agn_cfg; extern struct iwl_cfg iwl5100_bg_cfg; extern struct iwl_cfg iwl5100_abg_cfg; extern struct iwl_cfg iwl5150_agn_cfg; -extern struct iwl_cfg iwl6000_2ag_cfg; extern struct iwl_cfg iwl6000h_2agn_cfg; extern struct iwl_cfg iwl6000i_2agn_cfg; extern struct iwl_cfg iwl6000_3agn_cfg; -- cgit v1.2.3-18-g5258 From abdc2d62be335b85091e8f74081336563277a163 Mon Sep 17 00:00:00 2001 From: Jay Sternberg Date: Fri, 31 Jul 2009 14:28:09 -0700 Subject: iwlwifi: remove duplicated version info from sysfs version info in sysfs had been determined to be unnecessary as it is already provided in syslog info. nvm version is added to syslog version info as a debug level message to provide all info that was in the version sysfs data. Signed-off-by: Jay Sternberg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 40 +++++----------------------------- 1 file changed, 6 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 467c8617cb7..db580cbf598 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1291,6 +1291,7 @@ static int iwl_read_ucode(struct iwl_priv *priv) size_t len; u32 api_ver, build; u32 inst_size, data_size, init_size, init_data_size, boot_size; + u16 eeprom_ver; /* Ask kernel firmware_class module to get the boot firmware off disk. * request_firmware() is synchronous, file is in memory on return. */ @@ -1368,6 +1369,11 @@ static int iwl_read_ucode(struct iwl_priv *priv) if (build) IWL_DEBUG_INFO(priv, "Build %u\n", build); + eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); + IWL_DEBUG_INFO(priv, "NVM Type: %s, version: 0x%x\n", + (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) + ? "OTP" : "EEPROM", eeprom_ver); + IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n", priv->ucode_ver); IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n", @@ -2483,39 +2489,6 @@ static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, #endif /* CONFIG_IWLWIFI_DEBUG */ -static ssize_t show_version(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - struct iwl_alive_resp *palive = &priv->card_alive; - ssize_t pos = 0; - u16 eeprom_ver; - - if (palive->is_valid) - pos += sprintf(buf + pos, - "fw version: 0x%01X.0x%01X.0x%01X.0x%01X\n" - "fw type: 0x%01X 0x%01X\n", - palive->ucode_major, palive->ucode_minor, - palive->sw_rev[0], palive->sw_rev[1], - palive->ver_type, palive->ver_subtype); - else - pos += sprintf(buf + pos, "fw not loaded\n"); - - if (priv->eeprom) { - eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); - pos += sprintf(buf + pos, "NVM Type: %s, version: 0x%x\n", - (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) - ? "OTP" : "EEPROM", eeprom_ver); - - } else { - pos += sprintf(buf + pos, "EEPROM not initialzed\n"); - } - - return pos; -} - -static DEVICE_ATTR(version, S_IWUSR | S_IRUGO, show_version, NULL); - static ssize_t show_temperature(struct device *d, struct device_attribute *attr, char *buf) { @@ -2779,7 +2752,6 @@ static struct attribute *iwl_sysfs_entries[] = { #ifdef CONFIG_IWLWIFI_DEBUG &dev_attr_debug_level.attr, #endif - &dev_attr_version.attr, NULL }; -- cgit v1.2.3-18-g5258 From 2c8d51048f6a54aabe2e15278210cb07288e17bb Mon Sep 17 00:00:00 2001 From: Maithili Hinge Date: Fri, 31 Jul 2009 20:02:19 -0700 Subject: libertas: Fix WEP association failure with open source wpa_supplicant 0.5.10 Add code to handle IW_AUTH_PRIVACY_INVOKED and IW_AUTH_RX_UNENCRYPTED_EAPOL cases in lbs_set_auth() function in libertas code. Signed-off-by: Maithili Hinge Signed-off-by: Bing Zhao Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/wext.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index e96451ce470..be837a0d251 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -1728,6 +1728,8 @@ static int lbs_set_auth(struct net_device *dev, } switch (dwrq->flags & IW_AUTH_INDEX) { + case IW_AUTH_PRIVACY_INVOKED: + case IW_AUTH_RX_UNENCRYPTED_EAPOL: case IW_AUTH_TKIP_COUNTERMEASURES: case IW_AUTH_CIPHER_PAIRWISE: case IW_AUTH_CIPHER_GROUP: -- cgit v1.2.3-18-g5258 From 87cdb9894b9367237f25e5a4c381eb8e594e782b Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 1 Aug 2009 21:50:31 +0200 Subject: drivers/net/wireless: Use DIV_ROUND_CLOSEST The kernel.h macro DIV_ROUND_CLOSEST performs the computation (x + d/2)/d but is perhaps more readable. The semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @haskernel@ @@ #include @depends on haskernel@ expression x,__divisor; @@ - (((x) + ((__divisor) / 2)) / (__divisor)) + DIV_ROUND_CLOSEST(x,__divisor) // Signed-off-by: Julia Lawall Signed-off-by: John W. Linville --- drivers/net/wireless/strip.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 73300c226f6..ef2cb20e96a 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -1550,9 +1550,12 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev) if (time_after(jiffies, strip_info->pps_timer + HZ)) { unsigned long t = jiffies - strip_info->pps_timer; - unsigned long rx_pps_count = (strip_info->rx_pps_count * HZ * 8 + t / 2) / t; - unsigned long tx_pps_count = (strip_info->tx_pps_count * HZ * 8 + t / 2) / t; - unsigned long sx_pps_count = (strip_info->sx_pps_count * HZ * 8 + t / 2) / t; + unsigned long rx_pps_count = + DIV_ROUND_CLOSEST(strip_info->rx_pps_count*HZ*8, t); + unsigned long tx_pps_count = + DIV_ROUND_CLOSEST(strip_info->tx_pps_count*HZ*8, t); + unsigned long sx_pps_count = + DIV_ROUND_CLOSEST(strip_info->sx_pps_count*HZ*8, t); strip_info->pps_timer = jiffies; strip_info->rx_pps_count = 0; -- cgit v1.2.3-18-g5258 From c1be5152860218dffea6a47cff5ea31a56c6cff5 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 1 Aug 2009 22:32:48 -0500 Subject: b43legacy: Work around mac80211 race condition As shown in http://thread.gmane.org/gmane.linux.kernel.wireless.general/36497, mac80211 has a bug that allows a call to the TX routine after the queues have been stopped. This situation will only occur under extreme stress. Although b43legacy does not crash when this condition occurs, it does generate a WARN_ON and also logs a queue overrun message. This patch recognizes b43legacy is not at fault and logs a message only when the most verbose debugging mode is enabled. In the unlikely event that the queue is not stopped when the DMA queue becomes full, then a warning is issued. This patch is based on the one used by b43. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/dma.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index 2f90fb9f536..86640341581 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -1366,15 +1366,25 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev, ring = priority_to_txring(dev, skb_get_queue_mapping(skb)); spin_lock_irqsave(&ring->lock, flags); B43legacy_WARN_ON(!ring->tx); - if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { - b43legacywarn(dev->wl, "DMA queue overflow\n"); + + if (unlikely(ring->stopped)) { + /* We get here only because of a bug in mac80211. + * Because of a race, one packet may be queued after + * the queue is stopped, thus we got called when we shouldn't. + * For now, just refuse the transmit. */ + if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE)) + b43legacyerr(dev->wl, "Packet after queue stopped\n"); + err = -ENOSPC; + goto out_unlock; + } + + if (unlikely(WARN_ON(free_slots(ring) < SLOTS_PER_PACKET))) { + /* If we get here, we have a real error with the queue + * full, but queues not stopped. */ + b43legacyerr(dev->wl, "DMA queue overflow\n"); err = -ENOSPC; goto out_unlock; } - /* Check if the queue was stopped in mac80211, - * but we got called nevertheless. - * That would be a mac80211 bug. */ - B43legacy_BUG_ON(ring->stopped); err = dma_tx_fragment(ring, skb); if (unlikely(err == -ENOKEY)) { -- cgit v1.2.3-18-g5258 From 117839bd1251dc654938c529c95c7611ac260351 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Sun, 2 Aug 2009 14:30:02 -0400 Subject: rt61pci: fix module reloading Unloading rt61pci can leave the device in such state that reloading rt61pci would fail to reinitialize it. Bogus data would be read from the EEPROM and the RF version won't be recognized. It appears that unloading rt61pci with power saving enabled would have such effect. To initialize the device properly, SOFT_RESET_CSR should be set to the same value as rt61pci_config_ps() uses to wake up the device. Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index fb95b8cc4fe..e20dd7431f2 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2600,6 +2600,11 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) { int retval; + /* + * Disable power saving. + */ + rt2x00pci_register_write(rt2x00dev, SOFT_RESET_CSR, 0x00000007); + /* * Allocate eeprom data. */ -- cgit v1.2.3-18-g5258 From d8cc8926e9b4dc2ce513ee3325bf16b4ea6d94e8 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Sun, 2 Aug 2009 14:30:15 -0400 Subject: rt2x00: cancel all work on disconnect Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index b717afbf3f3..db54fcc94c8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -892,6 +892,12 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) */ rt2x00lib_disable_radio(rt2x00dev); + /* + * Stop all work. + */ + cancel_work_sync(&rt2x00dev->filter_work); + cancel_work_sync(&rt2x00dev->intf_work); + /* * Uninitialize device. */ -- cgit v1.2.3-18-g5258 From 738f0f4301587ad09b58651390b122205086b484 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Mon, 3 Aug 2009 01:28:12 +0200 Subject: b43: implement baseband init for LP-PHY <= rev1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement baseband init for rev.0 and rev.1 LP PHYs. Convert boardflags_hi values to defines. Implement b43_phy_copy for easier copying between registers, as needed by LP-PHY init. Signed-off-by: Gábor Stefanik Cc: Michael Buesch Cc: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 11 ++++ drivers/net/wireless/b43/phy_common.c | 7 +++ drivers/net/wireless/b43/phy_common.h | 5 ++ drivers/net/wireless/b43/phy_lp.c | 94 ++++++++++++++++++++++++++++++++++- drivers/net/wireless/b43/phy_lp.h | 11 +++- drivers/net/wireless/b43/phy_n.c | 3 +- 6 files changed, 127 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 40448067e4c..b6811cff18b 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -142,6 +142,17 @@ #define B43_BFL_BTCMOD 0x4000 /* BFL_BTCOEXIST is given in alternate GPIOs */ #define B43_BFL_ALTIQ 0x8000 /* alternate I/Q settings */ +/* SPROM boardflags_hi values */ +#define B43_BFH_NOPA 0x0001 /* has no PA */ +#define B43_BFH_RSSIINV 0x0002 /* RSSI uses positive slope (not TSSI) */ +#define B43_BFH_PAREF 0x0004 /* uses the PARef LDO */ +#define B43_BFH_3TSWITCH 0x0008 /* uses a triple throw switch shared + * with bluetooth */ +#define B43_BFH_PHASESHIFT 0x0010 /* can support phase shifter */ +#define B43_BFH_BUCKBOOST 0x0020 /* has buck/booster */ +#define B43_BFH_FEM_BT 0x0040 /* has FEM and switch to share antenna + * with bluetooth */ + /* GPIO register offset, in both ChipCommon and PCI core. */ #define B43_GPIO_CONTROL 0x6c diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index f537bfef690..51686ec9698 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -240,6 +240,13 @@ void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value) dev->phy.ops->phy_write(dev, reg, value); } +void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg) +{ + assert_mac_suspended(dev); + dev->phy.ops->phy_write(dev, destreg, + dev->phy.ops->phy_read(dev, srcreg)); +} + void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask) { b43_phy_write(dev, offset, diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 44cc918e4fc..9f9f23cab72 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -290,6 +290,11 @@ u16 b43_phy_read(struct b43_wldev *dev, u16 reg); */ void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value); +/** + * b43_phy_copy - copy contents of 16bit PHY register to another + */ +void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg); + /** * b43_phy_mask - Mask a PHY register with a mask */ diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index ea0d3a3a6a6..aa1486a1354 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -66,7 +66,99 @@ static void lpphy_table_init(struct b43_wldev *dev) static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) { - B43_WARN_ON(1);//TODO rev < 2 not supported, yet. + struct ssb_bus *bus = dev->dev->bus; + u16 tmp, tmp2; + + if (dev->phy.rev == 1 && + (bus->sprom.boardflags_hi & B43_BFH_FEM_BT)) { + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0x3F00, 0x0900); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x000A); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0B00); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x000A); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0400); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x000A); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0B00); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_5, 0xFFC0, 0x000A); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_5, 0xC0FF, 0x0900); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_6, 0xFFC0, 0x000A); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_6, 0xC0FF, 0x0B00); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_7, 0xFFC0, 0x000A); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_7, 0xC0FF, 0x0900); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xFFC0, 0x000A); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xC0FF, 0x0B00); + } else if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ || + (bus->boardinfo.type == 0x048A) || ((dev->phy.rev == 0) && + (bus->sprom.boardflags_lo & B43_BFL_FEM))) { + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0001); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0400); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0001); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0500); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0002); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0800); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0002); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0A00); + } else if (dev->phy.rev == 1 || + (bus->sprom.boardflags_lo & B43_BFL_FEM)) { + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0004); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0800); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0004); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0C00); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0002); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0100); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0002); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0300); + } else { + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0900); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x000A); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0B00); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0006); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0500); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0006); + b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0700); + } + if (dev->phy.rev == 1) { + b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_5, B43_LPPHY_TR_LOOKUP_1); + b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_6, B43_LPPHY_TR_LOOKUP_2); + b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_7, B43_LPPHY_TR_LOOKUP_3); + b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_8, B43_LPPHY_TR_LOOKUP_4); + } + if ((bus->sprom.boardflags_hi & B43_BFH_FEM_BT) && + (bus->chip_id == 0x5354) && + (bus->chip_package == SSB_CHIPPACK_BCM4712S)) { + b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0006); + b43_phy_write(dev, B43_LPPHY_GPIO_SELECT, 0x0005); + b43_phy_write(dev, B43_LPPHY_GPIO_OUTEN, 0xFFFF); + b43_hf_write(dev, b43_hf_read(dev) | 0x0800ULL << 32); + } + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x8000); + b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0040); + b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0x00FF, 0xA400); + b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xF0FF, 0x0B00); + b43_phy_maskset(dev, B43_LPPHY_SYNCPEAKCNT, 0xFFF8, 0x0007); + b43_phy_maskset(dev, B43_LPPHY_DSSS_CONFIRM_CNT, 0xFFF8, 0x0003); + b43_phy_maskset(dev, B43_LPPHY_DSSS_CONFIRM_CNT, 0xFFC7, 0x0020); + b43_phy_mask(dev, B43_LPPHY_IDLEAFTERPKTRXTO, 0x00FF); + } else { /* 5GHz */ + b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0x7FFF); + b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFBF); + } + if (dev->phy.rev == 1) { + tmp = b43_phy_read(dev, B43_LPPHY_CLIPCTRTHRESH); + tmp2 = (tmp & 0x03E0) >> 5; + tmp2 |= tmp << 5; + b43_phy_write(dev, B43_LPPHY_4C3, tmp2); + tmp = b43_phy_read(dev, B43_LPPHY_OFDMSYNCTHRESH0); + tmp2 = (tmp & 0x1F00) >> 8; + tmp2 |= tmp << 5; + b43_phy_write(dev, B43_LPPHY_4C4, tmp2); + tmp = b43_phy_read(dev, B43_LPPHY_VERYLOWGAINDB); + tmp2 = tmp & 0x00FF; + tmp2 |= tmp << 8; + b43_phy_write(dev, B43_LPPHY_4C5, tmp2); + } } static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h index 18370b4ac38..829b2bba3ee 100644 --- a/drivers/net/wireless/b43/phy_lp.h +++ b/drivers/net/wireless/b43/phy_lp.h @@ -273,12 +273,19 @@ #define B43_LPPHY_AFE_DDFS_POINTER_INIT B43_PHY_OFDM(0xB8) /* AFE DDFS pointer init */ #define B43_LPPHY_AFE_DDFS_INCR_INIT B43_PHY_OFDM(0xB9) /* AFE DDFS incr init */ #define B43_LPPHY_MRCNOISEREDUCTION B43_PHY_OFDM(0xBA) /* mrcNoiseReduction */ -#define B43_LPPHY_TRLOOKUP3 B43_PHY_OFDM(0xBB) /* TRLookup3 */ -#define B43_LPPHY_TRLOOKUP4 B43_PHY_OFDM(0xBC) /* TRLookup4 */ +#define B43_LPPHY_TR_LOOKUP_3 B43_PHY_OFDM(0xBB) /* TR Lookup 3 */ +#define B43_LPPHY_TR_LOOKUP_4 B43_PHY_OFDM(0xBC) /* TR Lookup 4 */ #define B43_LPPHY_RADAR_FIFO_STAT B43_PHY_OFDM(0xBD) /* Radar FIFO Status */ #define B43_LPPHY_GPIO_OUTEN B43_PHY_OFDM(0xBE) /* GPIO Out enable */ #define B43_LPPHY_GPIO_SELECT B43_PHY_OFDM(0xBF) /* GPIO Select */ #define B43_LPPHY_GPIO_OUT B43_PHY_OFDM(0xC0) /* GPIO Out */ +#define B43_LPPHY_4C3 B43_PHY_OFDM(0xC3) /* unknown, used during BB init */ +#define B43_LPPHY_4C4 B43_PHY_OFDM(0xC4) /* unknown, used during BB init */ +#define B43_LPPHY_4C5 B43_PHY_OFDM(0xC5) /* unknown, used during BB init */ +#define B43_LPPHY_TR_LOOKUP_5 B43_PHY_OFDM(0xC7) /* TR Lookup 5 */ +#define B43_LPPHY_TR_LOOKUP_6 B43_PHY_OFDM(0xC8) /* TR Lookup 6 */ +#define B43_LPPHY_TR_LOOKUP_7 B43_PHY_OFDM(0xC9) /* TR Lookup 7 */ +#define B43_LPPHY_TR_LOOKUP_8 B43_PHY_OFDM(0xCA) /* TR Lookup 8 */ diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index be7b5604947..992318a7807 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -137,7 +137,8 @@ static void b43_radio_init2055_post(struct b43_wldev *dev) b43_radio_mask(dev, B2055_MASTER1, 0xFFF3); msleep(1); - if ((sprom->revision != 4) || !(sprom->boardflags_hi & 0x0002)) { + if ((sprom->revision != 4) || + !(sprom->boardflags_hi & B43_BFH_RSSIINV)) { if ((binfo->vendor != PCI_VENDOR_ID_BROADCOM) || (binfo->type != 0x46D) || (binfo->rev < 0x41)) { -- cgit v1.2.3-18-g5258 From 554503f8c9e11cbea92b7cf1e31f7e4d93ad4492 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 3 Aug 2009 14:37:01 +0800 Subject: iwmc3200wifi: fix set_wpa_version and set_auth_type order iwm->umac_profile->sec.flags is set by iwm_set_wpa_version and checked by iwm_set_auth_type. The patch changes the order to make the flag used correctly. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 3f5a08fa401..a6e852f4f92 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -484,6 +484,8 @@ static int iwm_set_auth_type(struct iwm_priv *iwm, static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version) { + IWM_DBG_WEXT(iwm, DBG, "wpa_version: %d\n", wpa_version); + if (!wpa_version) { iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE; return 0; @@ -508,6 +510,9 @@ static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast) return 0; } + IWM_DBG_WEXT(iwm, DBG, "%ccast cipher is 0x%x\n", ucast ? 'u' : 'm', + cipher); + switch (cipher) { case IW_AUTH_CIPHER_NONE: *profile_cipher = UMAC_CIPHER_TYPE_NONE; @@ -584,11 +589,11 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, iwm->umac_profile->bss_num = 0; } - ret = iwm_set_auth_type(iwm, sme->auth_type); + ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions); if (ret < 0) return ret; - ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions); + ret = iwm_set_auth_type(iwm, sme->auth_type); if (ret < 0) return ret; -- cgit v1.2.3-18-g5258 From beda278d987cf7091302cf730c5b226d88e01c5b Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 3 Aug 2009 14:37:02 +0800 Subject: iwmc3200wifi: set WEP key static flag correctly We should only set the static_key flag for open and legacy authentication types. It should not be set for 802.1X and TKIP. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 0d6637005f4..6b3626013fd 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -596,6 +596,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) key_idx = key->hdr.key_idx; if (!remove) { + u8 auth_type = iwm->umac_profile->sec.auth_type; + IWM_DBG_WEXT(iwm, DBG, "key_idx:%d\n", key_idx); IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len); IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n", @@ -618,7 +620,9 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) memcpy(&wep40->key_hdr, key_hdr, sizeof(struct iwm_umac_key_hdr)); memcpy(wep40->key, key_data, key_len); - wep40->static_key = 1; + wep40->static_key = + !!((auth_type != UMAC_AUTH_TYPE_8021X) && + (auth_type != UMAC_AUTH_TYPE_RSNA_PSK)); cmd_size = sizeof(struct iwm_umac_key_wep40); break; @@ -632,7 +636,9 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) memcpy(&wep104->key_hdr, key_hdr, sizeof(struct iwm_umac_key_hdr)); memcpy(wep104->key, key_data, key_len); - wep104->static_key = 1; + wep104->static_key = + !!((auth_type != UMAC_AUTH_TYPE_8021X) && + (auth_type != UMAC_AUTH_TYPE_RSNA_PSK)); cmd_size = sizeof(struct iwm_umac_key_wep104); break; -- cgit v1.2.3-18-g5258 From 847c1e130092240c225a7be08607a7bf4e296fbd Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 3 Aug 2009 14:37:03 +0800 Subject: iwmc3200wifi: avoid setting default key for 802.1X and RSNA UMAC only allows us to set default key for WEP and auth type is not 802.1X or RSNA. This patch fixes iwmc3200wifi for 802.1X with WEP104. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 39 ++++++++++++++++++---------- 1 file changed, 26 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 6b3626013fd..f0c8acdb71a 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -526,19 +526,6 @@ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac) return 0; } -int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx) -{ - struct iwm_umac_tx_key_id tx_key_id; - - tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID; - tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) - - sizeof(struct iwm_umac_wifi_if)); - - tx_key_id.key_idx = key_idx; - - return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1); -} - static int iwm_check_profile(struct iwm_priv *iwm) { if (!iwm->umac_profile_active) @@ -572,6 +559,32 @@ static int iwm_check_profile(struct iwm_priv *iwm) return 0; } +int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx) +{ + struct iwm_umac_tx_key_id tx_key_id; + int ret; + + ret = iwm_check_profile(iwm); + if (ret < 0) + return ret; + + /* UMAC only allows to set default key for WEP and auth type is + * NOT 802.1X or RSNA. */ + if ((iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_40 && + iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_104) || + iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_8021X || + iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_RSNA_PSK) + return 0; + + tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID; + tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) - + sizeof(struct iwm_umac_wifi_if)); + + tx_key_id.key_idx = key_idx; + + return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1); +} + int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) { int ret = 0; -- cgit v1.2.3-18-g5258 From ed459c18517881890193b3414a25dbfe83d2ae7f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:33 -0700 Subject: ath9k: remove usage of AR_SREV_*() wrapper to detect supported hw We will clean this up next to just use a switch. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 7a0a6aed632..e0bc4c58044 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -665,8 +665,10 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, if ((ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCI) && (ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) && (ah->hw_version.macVersion != AR_SREV_VERSION_9160) && - (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && - (!AR_SREV_9285(ah)) && (!AR_SREV_9287(ah))) { + (ah->hw_version.macVersion != AR_SREV_VERSION_9100) && + (ah->hw_version.macVersion != AR_SREV_VERSION_9280) && + (ah->hw_version.macVersion != AR_SREV_VERSION_9285) && + (ah->hw_version.macVersion != AR_SREV_VERSION_9287)) { DPRINTF(sc, ATH_DBG_FATAL, "Mac Chip Rev 0x%02x.%x is not supported by " "this driver\n", ah->hw_version.macVersion, -- cgit v1.2.3-18-g5258 From fbf54660d1b48fba8527aae5c628ba72feee8f83 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:34 -0700 Subject: ath9k: use a switch for revising supported hw mac revisions This makes adding new hw revisions a one line change here. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index e0bc4c58044..8228f41c9c3 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -662,13 +662,16 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, DPRINTF(sc, ATH_DBG_RESET, "serialize_regmode is %d\n", ah->config.serialize_regmode); - if ((ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCI) && - (ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) && - (ah->hw_version.macVersion != AR_SREV_VERSION_9160) && - (ah->hw_version.macVersion != AR_SREV_VERSION_9100) && - (ah->hw_version.macVersion != AR_SREV_VERSION_9280) && - (ah->hw_version.macVersion != AR_SREV_VERSION_9285) && - (ah->hw_version.macVersion != AR_SREV_VERSION_9287)) { + switch (ah->hw_version.macVersion) { + case AR_SREV_VERSION_5416_PCI: + case AR_SREV_VERSION_5416_PCIE: + case AR_SREV_VERSION_9160: + case AR_SREV_VERSION_9100: + case AR_SREV_VERSION_9280: + case AR_SREV_VERSION_9285: + case AR_SREV_VERSION_9287: + break; + default: DPRINTF(sc, ATH_DBG_FATAL, "Mac Chip Rev 0x%02x.%x is not supported by " "this driver\n", ah->hw_version.macVersion, -- cgit v1.2.3-18-g5258 From 7819ac84b689b61340f29af6233fa1d15b76a6ef Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:35 -0700 Subject: ath9k: propagate hw initialization errors We were never propagating hw initialization errors, lets do that now and also use -EOPNOTSUPP when device revision is not supported yet. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 2 +- drivers/net/wireless/ath/ath9k/main.c | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8228f41c9c3..2e09204fc8a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1223,7 +1223,7 @@ struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error) ah = ath9k_hw_do_attach(devid, sc, error); break; default: - *error = -ENXIO; + *error = -EOPNOTSUPP; break; } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 292ac2b4189..ada5fef924c 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1295,7 +1295,6 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, static int ath_init(u16 devid, struct ath_softc *sc) { struct ath_hw *ah = NULL; - int status; int error = 0, i; int csz = 0; @@ -1323,11 +1322,11 @@ static int ath_init(u16 devid, struct ath_softc *sc) /* XXX assert csz is non-zero */ sc->cachelsz = csz << 2; /* convert to bytes */ - ah = ath9k_hw_attach(devid, sc, &status); + ah = ath9k_hw_attach(devid, sc, &error); if (ah == NULL) { DPRINTF(sc, ATH_DBG_FATAL, - "Unable to attach hardware; HAL status %d\n", status); - error = -ENXIO; + "Unable to attach hardware; " + "initialization status: %d\n", error); goto bad; } sc->sc_ah = ah; -- cgit v1.2.3-18-g5258 From 4f3acf81f2a47244f7403353784f528c92e98a6c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:36 -0700 Subject: ath9k: move memory allocation of ath_hw to ath_init() This lets us simplify attach code and arguments passed. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 65 +++++++++++------------------------ drivers/net/wireless/ath/ath9k/hw.h | 2 +- drivers/net/wireless/ath/ath9k/main.c | 35 ++++++++++++------- 3 files changed, 44 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2e09204fc8a..fcefea8461f 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -437,20 +437,9 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah) ah->config.serialize_regmode = SER_REG_MODE_AUTO; } -static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc, - int *status) +static void ath9k_hw_newstate(u16 devid, + struct ath_hw *ah) { - struct ath_hw *ah; - - ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); - if (ah == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, - "Cannot allocate memory for state block\n"); - *status = -ENOMEM; - return NULL; - } - - ah->ah_sc = sc; ah->hw_version.magic = AR5416_MAGIC; ah->regulatory.country_code = CTRY_DEFAULT; ah->hw_version.devid = devid; @@ -479,8 +468,6 @@ static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc, ah->gbeacon_rate = 0; ah->power_mode = ATH9K_PM_UNDEFINED; - - return ah; } static int ath9k_hw_rfattach(struct ath_hw *ah) @@ -623,28 +610,25 @@ static int ath9k_hw_post_attach(struct ath_hw *ah) return 0; } -static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, - int *status) +static int ath9k_hw_do_attach(struct ath_hw *ah, + u16 devid, + struct ath_softc *sc) { - struct ath_hw *ah; - int ecode; + int r; u32 i, j; - ah = ath9k_hw_newstate(devid, sc, status); - if (ah == NULL) - return NULL; - + ath9k_hw_newstate(devid, ah); ath9k_hw_set_defaults(ah); if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { DPRINTF(sc, ATH_DBG_FATAL, "Couldn't reset chip\n"); - ecode = -EIO; + r = -EIO; goto bad; } if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { DPRINTF(sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); - ecode = -EIO; + r = -EIO; goto bad; } @@ -676,7 +660,7 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, "Mac Chip Rev 0x%02x.%x is not supported by " "this driver\n", ah->hw_version.macVersion, ah->hw_version.macRev); - ecode = -EOPNOTSUPP; + r = -EOPNOTSUPP; goto bad; } @@ -878,8 +862,8 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, else ath9k_hw_disablepcie(ah); - ecode = ath9k_hw_post_attach(ah); - if (ecode != 0) + r = ath9k_hw_post_attach(ah); + if (r) goto bad; if (AR_SREV_9287_11(ah)) @@ -939,8 +923,8 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, } } - ecode = ath9k_hw_init_macaddr(ah); - if (ecode != 0) { + r = ath9k_hw_init_macaddr(ah); + if (r) { DPRINTF(sc, ATH_DBG_FATAL, "Failed to initialize MAC address\n"); goto bad; @@ -953,14 +937,10 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, ath9k_init_nfcal_hist_buffer(ah); - return ah; + return 0; bad: - if (ah) - ath9k_hw_detach(ah); - if (status) - *status = ecode; - - return NULL; + ath9k_hw_detach(ah); + return r; } static void ath9k_hw_init_bb(struct ath_hw *ah, @@ -1206,10 +1186,8 @@ void ath9k_hw_detach(struct ath_hw *ah) kfree(ah); } -struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error) +int ath9k_hw_attach(struct ath_hw *ah, u16 devid, struct ath_softc *sc) { - struct ath_hw *ah = NULL; - switch (devid) { case AR5416_DEVID_PCI: case AR5416_DEVID_PCIE: @@ -1220,14 +1198,11 @@ struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error) case AR9285_DEVID_PCIE: case AR5416_DEVID_AR9287_PCI: case AR5416_DEVID_AR9287_PCIE: - ah = ath9k_hw_do_attach(devid, sc, error); - break; + return ath9k_hw_do_attach(ah, devid, sc); default: - *error = -EOPNOTSUPP; break; } - - return ah; + return -EOPNOTSUPP; } /*******/ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 93a89302e79..4a0d5f202a7 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -544,7 +544,7 @@ struct ath_hw { /* Attach, Detach, Reset */ const char *ath9k_hw_probe(u16 vendorid, u16 devid); void ath9k_hw_detach(struct ath_hw *ah); -struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error); +int ath9k_hw_attach(struct ath_hw *ah, u16 devid, struct ath_softc *sc); void ath9k_hw_rfdetach(struct ath_hw *ah); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index ada5fef924c..c2b9974aa09 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1295,7 +1295,7 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, static int ath_init(u16 devid, struct ath_softc *sc) { struct ath_hw *ah = NULL; - int error = 0, i; + int r = 0, i; int csz = 0; /* XXX: hardware will not be ready until ath_open() being called */ @@ -1322,11 +1322,21 @@ static int ath_init(u16 devid, struct ath_softc *sc) /* XXX assert csz is non-zero */ sc->cachelsz = csz << 2; /* convert to bytes */ - ah = ath9k_hw_attach(devid, sc, &error); - if (ah == NULL) { + ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); + if (!ah) { + DPRINTF(sc, ATH_DBG_FATAL, + "Cannot allocate memory for state block\n"); + r = -ENOMEM; + goto bad_no_ah; + } + + ah->ah_sc = sc; + + r = ath9k_hw_attach(ah, devid, sc); + if (r) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to attach hardware; " - "initialization status: %d\n", error); + "initialization status: %d\n", r); goto bad; } sc->sc_ah = ah; @@ -1347,7 +1357,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) for (i = 0; i < sc->keymax; i++) ath9k_hw_keyreset(ah, (u16) i); - if (error) + if (r) goto bad; /* default to MONITOR mode */ @@ -1369,14 +1379,14 @@ static int ath_init(u16 devid, struct ath_softc *sc) if (sc->beacon.beaconq == -1) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to setup a beacon xmit queue\n"); - error = -EIO; + r = -EIO; goto bad2; } sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); if (sc->beacon.cabq == NULL) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to setup CAB xmit queue\n"); - error = -EIO; + r = -EIO; goto bad2; } @@ -1391,26 +1401,26 @@ static int ath_init(u16 devid, struct ath_softc *sc) if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to setup xmit queue for BK traffic\n"); - error = -EIO; + r = -EIO; goto bad2; } if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to setup xmit queue for BE traffic\n"); - error = -EIO; + r = -EIO; goto bad2; } if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to setup xmit queue for VI traffic\n"); - error = -EIO; + r = -EIO; goto bad2; } if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to setup xmit queue for VO traffic\n"); - error = -EIO; + r = -EIO; goto bad2; } @@ -1506,9 +1516,10 @@ bad2: bad: if (ah) ath9k_hw_detach(ah); +bad_no_ah: ath9k_exit_debug(sc); - return error; + return r; } void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) -- cgit v1.2.3-18-g5258 From 8df5d1b77395271dd9b75ed2b9aa9235f7589a0d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:37 -0700 Subject: ath9k: move devid cache setting to ath_init() This lets us trim one argument off of hw initializer routines. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 15 ++++++--------- drivers/net/wireless/ath/ath9k/hw.h | 2 +- drivers/net/wireless/ath/ath9k/main.c | 3 ++- 3 files changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index fcefea8461f..ff2875b233d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -437,16 +437,14 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah) ah->config.serialize_regmode = SER_REG_MODE_AUTO; } -static void ath9k_hw_newstate(u16 devid, - struct ath_hw *ah) +static void ath9k_hw_newstate(struct ath_hw *ah) { ah->hw_version.magic = AR5416_MAGIC; ah->regulatory.country_code = CTRY_DEFAULT; - ah->hw_version.devid = devid; ah->hw_version.subvendorid = 0; ah->ah_flags = 0; - if ((devid == AR5416_AR9100_DEVID)) + if (ah->hw_version.devid == AR5416_AR9100_DEVID) ah->hw_version.macVersion = AR_SREV_VERSION_9100; if (!AR_SREV_9100(ah)) ah->ah_flags = AH_USE_EEPROM; @@ -611,13 +609,12 @@ static int ath9k_hw_post_attach(struct ath_hw *ah) } static int ath9k_hw_do_attach(struct ath_hw *ah, - u16 devid, struct ath_softc *sc) { int r; u32 i, j; - ath9k_hw_newstate(devid, ah); + ath9k_hw_newstate(ah); ath9k_hw_set_defaults(ah); if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { @@ -1186,9 +1183,9 @@ void ath9k_hw_detach(struct ath_hw *ah) kfree(ah); } -int ath9k_hw_attach(struct ath_hw *ah, u16 devid, struct ath_softc *sc) +int ath9k_hw_attach(struct ath_hw *ah, struct ath_softc *sc) { - switch (devid) { + switch (ah->hw_version.devid) { case AR5416_DEVID_PCI: case AR5416_DEVID_PCIE: case AR5416_AR9100_DEVID: @@ -1198,7 +1195,7 @@ int ath9k_hw_attach(struct ath_hw *ah, u16 devid, struct ath_softc *sc) case AR9285_DEVID_PCIE: case AR5416_DEVID_AR9287_PCI: case AR5416_DEVID_AR9287_PCIE: - return ath9k_hw_do_attach(ah, devid, sc); + return ath9k_hw_do_attach(ah, sc); default: break; } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 4a0d5f202a7..c769dd6a835 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -544,7 +544,7 @@ struct ath_hw { /* Attach, Detach, Reset */ const char *ath9k_hw_probe(u16 vendorid, u16 devid); void ath9k_hw_detach(struct ath_hw *ah); -int ath9k_hw_attach(struct ath_hw *ah, u16 devid, struct ath_softc *sc); +int ath9k_hw_attach(struct ath_hw *ah, struct ath_softc *sc); void ath9k_hw_rfdetach(struct ath_hw *ah); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c2b9974aa09..fa2c230c3c2 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1331,8 +1331,9 @@ static int ath_init(u16 devid, struct ath_softc *sc) } ah->ah_sc = sc; + ah->hw_version.devid = devid; - r = ath9k_hw_attach(ah, devid, sc); + r = ath9k_hw_attach(ah, sc); if (r) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to attach hardware; " -- cgit v1.2.3-18-g5258 From e1e2f93ffacab692823209e00a124e802039aa9a Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:38 -0700 Subject: ath9k: move cache setting of softc ah prior to attach We do this in case attach and friends try to get back to ah from the softc somehow. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index fa2c230c3c2..605d3280733 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1332,6 +1332,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) ah->ah_sc = sc; ah->hw_version.devid = devid; + sc->sc_ah = ah; r = ath9k_hw_attach(ah, sc); if (r) { @@ -1340,7 +1341,6 @@ static int ath_init(u16 devid, struct ath_softc *sc) "initialization status: %d\n", r); goto bad; } - sc->sc_ah = ah; /* Get the hardware key cache size. */ sc->keymax = ah->caps.keycache_size; -- cgit v1.2.3-18-g5258 From ee2bb460e28b757f097efb9e5947a6e47e2477e1 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:39 -0700 Subject: ath9k: call hw initializer directly ath9k_hw_attach() was going first through some device id verifier, and then calling some other helper which was doing the real hardware initialization. Lets just do the devid checks within the real worker by calling a helper ath9k_hw_devid_supported(). Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 48 ++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index ff2875b233d..d8ae289a09b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -608,12 +608,35 @@ static int ath9k_hw_post_attach(struct ath_hw *ah) return 0; } -static int ath9k_hw_do_attach(struct ath_hw *ah, - struct ath_softc *sc) +static bool ath9k_hw_devid_supported(u16 devid) +{ + switch (devid) { + case AR5416_DEVID_PCI: + case AR5416_DEVID_PCIE: + case AR5416_AR9100_DEVID: + case AR9160_DEVID_PCI: + case AR9280_DEVID_PCI: + case AR9280_DEVID_PCIE: + case AR9285_DEVID_PCIE: + case AR5416_DEVID_AR9287_PCI: + case AR5416_DEVID_AR9287_PCIE: + return true; + default: + break; + } + return false; +} + +int ath9k_hw_attach(struct ath_hw *ah, struct ath_softc *sc) { int r; u32 i, j; + if (!ath9k_hw_devid_supported(ah->hw_version.devid)) { + r = -EOPNOTSUPP; + goto bad; + } + ath9k_hw_newstate(ah); ath9k_hw_set_defaults(ah); @@ -1183,25 +1206,6 @@ void ath9k_hw_detach(struct ath_hw *ah) kfree(ah); } -int ath9k_hw_attach(struct ath_hw *ah, struct ath_softc *sc) -{ - switch (ah->hw_version.devid) { - case AR5416_DEVID_PCI: - case AR5416_DEVID_PCIE: - case AR5416_AR9100_DEVID: - case AR9160_DEVID_PCI: - case AR9280_DEVID_PCI: - case AR9280_DEVID_PCIE: - case AR9285_DEVID_PCIE: - case AR5416_DEVID_AR9287_PCI: - case AR5416_DEVID_AR9287_PCIE: - return ath9k_hw_do_attach(ah, sc); - default: - break; - } - return -EOPNOTSUPP; -} - /*******/ /* INI */ /*******/ @@ -2898,7 +2902,7 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore) /* * AR9280 2.0 or later chips use SerDes values from the * initvals.h initialized depending on chipset during - * ath9k_hw_do_attach() + * ath9k_hw_attach() */ for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) { REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0), -- cgit v1.2.3-18-g5258 From 07c10c6177bdd199fead127c2a4c43acb415a5be Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:40 -0700 Subject: ath9k: pass only one argument to hw attach The softc is cached and set within the ath_hw struct. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 12 ++++++------ drivers/net/wireless/ath/ath9k/hw.h | 2 +- drivers/net/wireless/ath/ath9k/main.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index d8ae289a09b..301ef04e052 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -627,7 +627,7 @@ static bool ath9k_hw_devid_supported(u16 devid) return false; } -int ath9k_hw_attach(struct ath_hw *ah, struct ath_softc *sc) +int ath9k_hw_attach(struct ath_hw *ah) { int r; u32 i, j; @@ -641,13 +641,13 @@ int ath9k_hw_attach(struct ath_hw *ah, struct ath_softc *sc) ath9k_hw_set_defaults(ah); if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { - DPRINTF(sc, ATH_DBG_FATAL, "Couldn't reset chip\n"); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't reset chip\n"); r = -EIO; goto bad; } if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { - DPRINTF(sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); r = -EIO; goto bad; } @@ -663,7 +663,7 @@ int ath9k_hw_attach(struct ath_hw *ah, struct ath_softc *sc) } } - DPRINTF(sc, ATH_DBG_RESET, "serialize_regmode is %d\n", + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "serialize_regmode is %d\n", ah->config.serialize_regmode); switch (ah->hw_version.macVersion) { @@ -676,7 +676,7 @@ int ath9k_hw_attach(struct ath_hw *ah, struct ath_softc *sc) case AR_SREV_VERSION_9287: break; default: - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Mac Chip Rev 0x%02x.%x is not supported by " "this driver\n", ah->hw_version.macVersion, ah->hw_version.macRev); @@ -945,7 +945,7 @@ int ath9k_hw_attach(struct ath_hw *ah, struct ath_softc *sc) r = ath9k_hw_init_macaddr(ah); if (r) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Failed to initialize MAC address\n"); goto bad; } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index c769dd6a835..35cf9f840eb 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -544,7 +544,7 @@ struct ath_hw { /* Attach, Detach, Reset */ const char *ath9k_hw_probe(u16 vendorid, u16 devid); void ath9k_hw_detach(struct ath_hw *ah); -int ath9k_hw_attach(struct ath_hw *ah, struct ath_softc *sc); +int ath9k_hw_attach(struct ath_hw *ah); void ath9k_hw_rfdetach(struct ath_hw *ah); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 605d3280733..62429508578 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1334,7 +1334,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) ah->hw_version.devid = devid; sc->sc_ah = ah; - r = ath9k_hw_attach(ah, sc); + r = ath9k_hw_attach(ah); if (r) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to attach hardware; " -- cgit v1.2.3-18-g5258 From f9d4a668035b0bf65d1c8d5eba680201112f7c3d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:41 -0700 Subject: ath9k: move hw macrevision checker to helper Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 301ef04e052..4f3d7bf73c5 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -627,6 +627,23 @@ static bool ath9k_hw_devid_supported(u16 devid) return false; } +static bool ath9k_hw_macversion_supported(u32 macversion) +{ + switch (macversion) { + case AR_SREV_VERSION_5416_PCI: + case AR_SREV_VERSION_5416_PCIE: + case AR_SREV_VERSION_9160: + case AR_SREV_VERSION_9100: + case AR_SREV_VERSION_9280: + case AR_SREV_VERSION_9285: + case AR_SREV_VERSION_9287: + return true; + default: + break; + } + return false; +} + int ath9k_hw_attach(struct ath_hw *ah) { int r; @@ -666,16 +683,7 @@ int ath9k_hw_attach(struct ath_hw *ah) DPRINTF(ah->ah_sc, ATH_DBG_RESET, "serialize_regmode is %d\n", ah->config.serialize_regmode); - switch (ah->hw_version.macVersion) { - case AR_SREV_VERSION_5416_PCI: - case AR_SREV_VERSION_5416_PCIE: - case AR_SREV_VERSION_9160: - case AR_SREV_VERSION_9100: - case AR_SREV_VERSION_9280: - case AR_SREV_VERSION_9285: - case AR_SREV_VERSION_9287: - break; - default: + if (!ath9k_hw_macversion_supported(ah->hw_version.macVersion)) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Mac Chip Rev 0x%02x.%x is not supported by " "this driver\n", ah->hw_version.macVersion, -- cgit v1.2.3-18-g5258 From 50aca25b5824f29fa94417abadf82ee7f0c7f816 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:42 -0700 Subject: ath9k: rename ath9k_hw_newstate() to ath9k_hw_init_defaults() This reflects better what we are actually doing there. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 4f3d7bf73c5..6aee57065c7 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -437,7 +437,7 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah) ah->config.serialize_regmode = SER_REG_MODE_AUTO; } -static void ath9k_hw_newstate(struct ath_hw *ah) +static void ath9k_hw_init_defaults(struct ath_hw *ah) { ah->hw_version.magic = AR5416_MAGIC; ah->regulatory.country_code = CTRY_DEFAULT; @@ -654,7 +654,7 @@ int ath9k_hw_attach(struct ath_hw *ah) goto bad; } - ath9k_hw_newstate(ah); + ath9k_hw_init_defaults(ah); ath9k_hw_set_defaults(ah); if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { -- cgit v1.2.3-18-g5258 From b8b0f377c762558b3773e27f73c7bbcd0fa40171 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:43 -0700 Subject: ath9k: rename ath9k_hw_set_defaults() to ath9k_hw_init_config() This reflects better what we are actually doing there. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 6aee57065c7..31ec83dfddd 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -388,7 +388,7 @@ static const char *ath9k_hw_devname(u16 devid) return NULL; } -static void ath9k_hw_set_defaults(struct ath_hw *ah) +static void ath9k_hw_init_config(struct ath_hw *ah) { int i; @@ -655,7 +655,7 @@ int ath9k_hw_attach(struct ath_hw *ah) } ath9k_hw_init_defaults(ah); - ath9k_hw_set_defaults(ah); + ath9k_hw_init_config(ah); if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't reset chip\n"); -- cgit v1.2.3-18-g5258 From 08e0403a1472d9fa3662369a36ccaf24c796a33e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:44 -0700 Subject: ath9k: remove debug message for no memoery on ath_init() We're now propagating the -ENOMEM error so there is no need to keep a debug message there now. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 62429508578..230dedbb2e0 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1324,8 +1324,6 @@ static int ath_init(u16 devid, struct ath_softc *sc) ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); if (!ah) { - DPRINTF(sc, ATH_DBG_FATAL, - "Cannot allocate memory for state block\n"); r = -ENOMEM; goto bad_no_ah; } -- cgit v1.2.3-18-g5258 From aa4058aea24efe7aef736cbfb2d9b07de920ca27 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:45 -0700 Subject: ath9k: break up hw initialization into a few more helpers This makes reading the hardware initialization process easier to understand. The new helpers added are: ath9k_hw_init_cal_settings() ath9k_hw_init_mode_regs() ath9k_hw_init_mode_gain_regs() ath9k_hw_init_11a_eeprom_fix() This patch has no functional changes. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 154 ++++++++++++++++++++---------------- 1 file changed, 87 insertions(+), 67 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 31ec83dfddd..f280eef736b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -644,61 +644,8 @@ static bool ath9k_hw_macversion_supported(u32 macversion) return false; } -int ath9k_hw_attach(struct ath_hw *ah) +static void ath9k_hw_init_cal_settings(struct ath_hw *ah) { - int r; - u32 i, j; - - if (!ath9k_hw_devid_supported(ah->hw_version.devid)) { - r = -EOPNOTSUPP; - goto bad; - } - - ath9k_hw_init_defaults(ah); - ath9k_hw_init_config(ah); - - if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't reset chip\n"); - r = -EIO; - goto bad; - } - - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); - r = -EIO; - goto bad; - } - - if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) { - if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI || - (AR_SREV_9280(ah) && !ah->is_pciexpress)) { - ah->config.serialize_regmode = - SER_REG_MODE_ON; - } else { - ah->config.serialize_regmode = - SER_REG_MODE_OFF; - } - } - - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "serialize_regmode is %d\n", - ah->config.serialize_regmode); - - if (!ath9k_hw_macversion_supported(ah->hw_version.macVersion)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Mac Chip Rev 0x%02x.%x is not supported by " - "this driver\n", ah->hw_version.macVersion, - ah->hw_version.macRev); - r = -EOPNOTSUPP; - goto bad; - } - - if (AR_SREV_9100(ah)) { - ah->iq_caldata.calData = &iq_cal_multi_sample; - ah->supp_cals = IQ_MISMATCH_CAL; - ah->is_pciexpress = false; - } - ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID); - if (AR_SREV_9160_10_OR_LATER(ah)) { if (AR_SREV_9280_10_OR_LATER(ah)) { ah->iq_caldata.calData = &iq_cal_single_sample; @@ -719,10 +666,10 @@ int ath9k_hw_attach(struct ath_hw *ah) } ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; } +} - ah->ani_function = ATH9K_ANI_ALL; - if (AR_SREV_9280_10_OR_LATER(ah)) - ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; +static void ath9k_hw_init_mode_regs(struct ath_hw *ah) +{ if (AR_SREV_9287_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1, ARRAY_SIZE(ar9287Modes_9287_1_1), 6); @@ -884,16 +831,10 @@ int ath9k_hw_attach(struct ath_hw *ah) INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac, ARRAY_SIZE(ar5416Addac), 2); } +} - if (ah->is_pciexpress) - ath9k_hw_configpcipowersave(ah, 0); - else - ath9k_hw_disablepcie(ah); - - r = ath9k_hw_post_attach(ah); - if (r) - goto bad; - +static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah) +{ if (AR_SREV_9287_11(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9287Modes_rx_gain_9287_1_1, @@ -930,8 +871,11 @@ int ath9k_hw_attach(struct ath_hw *ah) } } +} - ath9k_hw_fill_cap_info(ah); +static void ath9k_hw_init_11a_eeprom_fix(struct ath_hw *ah) +{ + u32 i, j; if ((ah->hw_version.devid == AR9280_DEVID_PCI) && test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) { @@ -950,6 +894,82 @@ int ath9k_hw_attach(struct ath_hw *ah) } } } +} + +int ath9k_hw_attach(struct ath_hw *ah) +{ + int r; + + if (!ath9k_hw_devid_supported(ah->hw_version.devid)) { + r = -EOPNOTSUPP; + goto bad; + } + + ath9k_hw_init_defaults(ah); + ath9k_hw_init_config(ah); + + if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't reset chip\n"); + r = -EIO; + goto bad; + } + + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); + r = -EIO; + goto bad; + } + + if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) { + if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI || + (AR_SREV_9280(ah) && !ah->is_pciexpress)) { + ah->config.serialize_regmode = + SER_REG_MODE_ON; + } else { + ah->config.serialize_regmode = + SER_REG_MODE_OFF; + } + } + + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "serialize_regmode is %d\n", + ah->config.serialize_regmode); + + if (!ath9k_hw_macversion_supported(ah->hw_version.macVersion)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Mac Chip Rev 0x%02x.%x is not supported by " + "this driver\n", ah->hw_version.macVersion, + ah->hw_version.macRev); + r = -EOPNOTSUPP; + goto bad; + } + + if (AR_SREV_9100(ah)) { + ah->iq_caldata.calData = &iq_cal_multi_sample; + ah->supp_cals = IQ_MISMATCH_CAL; + ah->is_pciexpress = false; + } + ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID); + + ath9k_hw_init_cal_settings(ah); + + ah->ani_function = ATH9K_ANI_ALL; + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; + + ath9k_hw_init_mode_regs(ah); + + if (ah->is_pciexpress) + ath9k_hw_configpcipowersave(ah, 0); + else + ath9k_hw_disablepcie(ah); + + r = ath9k_hw_post_attach(ah); + if (r) + goto bad; + + ath9k_hw_init_mode_gain_regs(ah); + ath9k_hw_fill_cap_info(ah); + ath9k_hw_init_11a_eeprom_fix(ah); r = ath9k_hw_init_macaddr(ah); if (r) { -- cgit v1.2.3-18-g5258 From f637cfd6bbacbaeab329f9dfc56e9855cc15849d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:46 -0700 Subject: ath9k: describe hw initialization better During initialization ath9k tends to use "attach" to when we initialize hardware due to the fact we used to attach a "HAL". The notion of a HAL is long gone, so lets just be clear on what we are doing. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ani.c | 2 +- drivers/net/wireless/ath/ath9k/ani.h | 2 +- drivers/net/wireless/ath/ath9k/eeprom.c | 2 +- drivers/net/wireless/ath/ath9k/eeprom.h | 2 +- drivers/net/wireless/ath/ath9k/hw.c | 12 ++++++------ drivers/net/wireless/ath/ath9k/hw.h | 4 ++-- drivers/net/wireless/ath/ath9k/main.c | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index aad259b4c19..a613cf46eeb 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -777,7 +777,7 @@ void ath9k_hw_ani_setup(struct ath_hw *ah) } } -void ath9k_hw_ani_attach(struct ath_hw *ah) +void ath9k_hw_ani_init(struct ath_hw *ah) { int i; diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index 08b4e7ed5ff..803669faaad 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -132,7 +132,7 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt, void ath9k_hw_procmibevent(struct ath_hw *ah, const struct ath9k_node_stats *stats); void ath9k_hw_ani_setup(struct ath_hw *ah); -void ath9k_hw_ani_attach(struct ath_hw *ah); +void ath9k_hw_ani_init(struct ath_hw *ah); void ath9k_hw_ani_detach(struct ath_hw *ah); #endif /* ANI_H */ diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 6fb1a8034b3..e8ccec0dea1 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -3978,7 +3978,7 @@ static struct eeprom_ops eep_AR9287_ops = { }; -int ath9k_hw_eeprom_attach(struct ath_hw *ah) +int ath9k_hw_eeprom_init(struct ath_hw *ah) { int status; if (AR_SREV_9287(ah)) { diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 7ddd016a99f..335098d16a7 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -665,6 +665,6 @@ struct eeprom_ops { (((_txchainmask >> 2) & 1) + \ ((_txchainmask >> 1) & 1) + (_txchainmask & 1)) -int ath9k_hw_eeprom_attach(struct ath_hw *ah); +int ath9k_hw_eeprom_init(struct ath_hw *ah); #endif /* EEPROM_H */ diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index f280eef736b..65d2e7d059a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -578,7 +578,7 @@ static void ath9k_hw_init_txgain_ini(struct ath_hw *ah) } } -static int ath9k_hw_post_attach(struct ath_hw *ah) +static int ath9k_hw_post_init(struct ath_hw *ah) { int ecode; @@ -589,7 +589,7 @@ static int ath9k_hw_post_attach(struct ath_hw *ah) if (ecode != 0) return ecode; - ecode = ath9k_hw_eeprom_attach(ah); + ecode = ath9k_hw_eeprom_init(ah); if (ecode != 0) return ecode; @@ -602,7 +602,7 @@ static int ath9k_hw_post_attach(struct ath_hw *ah) if (!AR_SREV_9100(ah)) { ath9k_hw_ani_setup(ah); - ath9k_hw_ani_attach(ah); + ath9k_hw_ani_init(ah); } return 0; @@ -896,7 +896,7 @@ static void ath9k_hw_init_11a_eeprom_fix(struct ath_hw *ah) } } -int ath9k_hw_attach(struct ath_hw *ah) +int ath9k_hw_init(struct ath_hw *ah) { int r; @@ -963,7 +963,7 @@ int ath9k_hw_attach(struct ath_hw *ah) else ath9k_hw_disablepcie(ah); - r = ath9k_hw_post_attach(ah); + r = ath9k_hw_post_init(ah); if (r) goto bad; @@ -2930,7 +2930,7 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore) /* * AR9280 2.0 or later chips use SerDes values from the * initvals.h initialized depending on chipset during - * ath9k_hw_attach() + * ath9k_hw_init() */ for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) { REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0), diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 35cf9f840eb..4c78e8cd039 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -541,10 +541,10 @@ struct ath_hw { struct ar5416IniArray iniModesTxGain; }; -/* Attach, Detach, Reset */ +/* Initialization, Detach, Reset */ const char *ath9k_hw_probe(u16 vendorid, u16 devid); void ath9k_hw_detach(struct ath_hw *ah); -int ath9k_hw_attach(struct ath_hw *ah); +int ath9k_hw_init(struct ath_hw *ah); void ath9k_hw_rfdetach(struct ath_hw *ah); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 230dedbb2e0..751d803e1bc 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1332,10 +1332,10 @@ static int ath_init(u16 devid, struct ath_softc *sc) ah->hw_version.devid = devid; sc->sc_ah = ah; - r = ath9k_hw_attach(ah); + r = ath9k_hw_init(ah); if (r) { DPRINTF(sc, ATH_DBG_FATAL, - "Unable to attach hardware; " + "Unable to initialize hardware; " "initialization status: %d\n", r); goto bad; } -- cgit v1.2.3-18-g5258 From 1e40bcfa91429edb665af9ffefb2658350913d35 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:47 -0700 Subject: ath9k: distinguish between device initialization and ath_softc init We re-label the device driver initialization routines from the ath_softc, the "Software Carrier" fillers. This should make it clearer what each of these do. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ahb.c | 2 +- drivers/net/wireless/ath/ath9k/ath9k.h | 2 +- drivers/net/wireless/ath/ath9k/main.c | 13 ++++++++++--- drivers/net/wireless/ath/ath9k/pci.c | 2 +- 4 files changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 0e65c51ba17..5618fc25d52 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -119,7 +119,7 @@ static int ath_ahb_probe(struct platform_device *pdev) sc->bus_ops = &ath_ahb_bus_ops; sc->irq = irq; - ret = ath_attach(AR5416_AR9100_DEVID, sc); + ret = ath_init_device(AR5416_AR9100_DEVID, sc); if (ret != 0) { dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret); ret = -ENODEV; diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index bda0f302340..7a5a157e15c 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -642,7 +642,7 @@ extern struct ieee80211_ops ath9k_ops; irqreturn_t ath_isr(int irq, void *dev); void ath_cleanup(struct ath_softc *sc); -int ath_attach(u16 devid, struct ath_softc *sc); +int ath_init_device(u16 devid, struct ath_softc *sc); void ath_detach(struct ath_softc *sc); const char *ath_mac_bb_name(u32 mac_bb_version); const char *ath_rf_name(u16 rf_version); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 751d803e1bc..91bffc91bbb 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1292,7 +1292,13 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, return ath_reg_notifier_apply(wiphy, request, reg); } -static int ath_init(u16 devid, struct ath_softc *sc) +/* + * Initialize and fill ath_softc, ath_sofct is the + * "Software Carrier" struct. Historically it has existed + * to allow the separation between hardware specific + * variables (now in ath_hw) and driver specific variables. + */ +static int ath_init_softc(u16 devid, struct ath_softc *sc) { struct ath_hw *ah = NULL; int r = 0, i; @@ -1558,7 +1564,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) &sc->sbands[IEEE80211_BAND_5GHZ]; } -int ath_attach(u16 devid, struct ath_softc *sc) +/* Device driver core initialization */ +int ath_init_device(u16 devid, struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; int error = 0, i; @@ -1566,7 +1573,7 @@ int ath_attach(u16 devid, struct ath_softc *sc) DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); - error = ath_init(devid, sc); + error = ath_init_softc(devid, sc); if (error != 0) return error; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index cd4841be80a..3546504a83c 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -178,7 +178,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) sc->mem = mem; sc->bus_ops = &ath_pci_bus_ops; - if (ath_attach(id->device, sc) != 0) { + if (ath_init_device(id->device, sc) != 0) { ret = -ENODEV; goto bad3; } -- cgit v1.2.3-18-g5258 From 39a21951efc99e040a7d66449f63910e439b97e9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:48 -0700 Subject: ath9k: remove !NULL check before kfree() kfree(NULL) works so remove all those branches which check for it before kfree()'ing on ath9k_hw_rfdetach(). Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/phy.c | 62 +++++++++++++++--------------------- 1 file changed, 26 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index aaa941561c3..06fd057e467 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -266,42 +266,32 @@ ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, void ath9k_hw_rfdetach(struct ath_hw *ah) { - if (ah->analogBank0Data != NULL) { - kfree(ah->analogBank0Data); - ah->analogBank0Data = NULL; - } - if (ah->analogBank1Data != NULL) { - kfree(ah->analogBank1Data); - ah->analogBank1Data = NULL; - } - if (ah->analogBank2Data != NULL) { - kfree(ah->analogBank2Data); - ah->analogBank2Data = NULL; - } - if (ah->analogBank3Data != NULL) { - kfree(ah->analogBank3Data); - ah->analogBank3Data = NULL; - } - if (ah->analogBank6Data != NULL) { - kfree(ah->analogBank6Data); - ah->analogBank6Data = NULL; - } - if (ah->analogBank6TPCData != NULL) { - kfree(ah->analogBank6TPCData); - ah->analogBank6TPCData = NULL; - } - if (ah->analogBank7Data != NULL) { - kfree(ah->analogBank7Data); - ah->analogBank7Data = NULL; - } - if (ah->addac5416_21 != NULL) { - kfree(ah->addac5416_21); - ah->addac5416_21 = NULL; - } - if (ah->bank6Temp != NULL) { - kfree(ah->bank6Temp); - ah->bank6Temp = NULL; - } + kfree(ah->analogBank0Data); + ah->analogBank0Data = NULL; + + kfree(ah->analogBank1Data); + ah->analogBank1Data = NULL; + + kfree(ah->analogBank2Data); + ah->analogBank2Data = NULL; + + kfree(ah->analogBank3Data); + ah->analogBank3Data = NULL; + + kfree(ah->analogBank6Data); + ah->analogBank6Data = NULL; + + kfree(ah->analogBank6TPCData); + ah->analogBank6TPCData = NULL; + + kfree(ah->analogBank7Data); + ah->analogBank7Data = NULL; + + kfree(ah->addac5416_21); + ah->addac5416_21 = NULL; + + kfree(ah->bank6Temp); + ah->bank6Temp = NULL; } bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) -- cgit v1.2.3-18-g5258 From 6b827529058d6d479f31b281a9ec630f7b6841e1 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:49 -0700 Subject: ath9k: use helper macro to kfree and nullify on ath9k_hw_rfdetach() Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/phy.c | 41 +++++++++++++----------------------- 1 file changed, 15 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index 06fd057e467..98b1b56d87c 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -266,32 +266,21 @@ ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, void ath9k_hw_rfdetach(struct ath_hw *ah) { - kfree(ah->analogBank0Data); - ah->analogBank0Data = NULL; - - kfree(ah->analogBank1Data); - ah->analogBank1Data = NULL; - - kfree(ah->analogBank2Data); - ah->analogBank2Data = NULL; - - kfree(ah->analogBank3Data); - ah->analogBank3Data = NULL; - - kfree(ah->analogBank6Data); - ah->analogBank6Data = NULL; - - kfree(ah->analogBank6TPCData); - ah->analogBank6TPCData = NULL; - - kfree(ah->analogBank7Data); - ah->analogBank7Data = NULL; - - kfree(ah->addac5416_21); - ah->addac5416_21 = NULL; - - kfree(ah->bank6Temp); - ah->bank6Temp = NULL; +#define ATH_FREE_BANK(bank) do { \ + kfree(bank); \ + bank = NULL; \ + } while (0); + + ATH_FREE_BANK(ah->analogBank0Data); + ATH_FREE_BANK(ah->analogBank1Data); + ATH_FREE_BANK(ah->analogBank2Data); + ATH_FREE_BANK(ah->analogBank3Data); + ATH_FREE_BANK(ah->analogBank6Data); + ATH_FREE_BANK(ah->analogBank6TPCData); + ATH_FREE_BANK(ah->analogBank7Data); + ATH_FREE_BANK(ah->addac5416_21); + ATH_FREE_BANK(ah->bank6Temp); +#undef ATH_FREE_BANK } bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) -- cgit v1.2.3-18-g5258 From 081b35ab2e98a2f76d0378219e91cd1c90aed55f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:50 -0700 Subject: ath9k: rename ath9k_hw_rfdetach() to ath9k_hw_rf_free() This makes it clear what this does. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 2 +- drivers/net/wireless/ath/ath9k/hw.h | 2 +- drivers/net/wireless/ath/ath9k/phy.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 65d2e7d059a..73dee19e887 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1229,7 +1229,7 @@ void ath9k_hw_detach(struct ath_hw *ah) if (!AR_SREV_9100(ah)) ath9k_hw_ani_detach(ah); - ath9k_hw_rfdetach(ah); + ath9k_hw_rf_free(ah); ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); kfree(ah); } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 4c78e8cd039..4e717cc68cd 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -545,7 +545,7 @@ struct ath_hw { const char *ath9k_hw_probe(u16 vendorid, u16 devid); void ath9k_hw_detach(struct ath_hw *ah); int ath9k_hw_init(struct ath_hw *ah); -void ath9k_hw_rfdetach(struct ath_hw *ah); +void ath9k_hw_rf_free(struct ath_hw *ah); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange); void ath9k_hw_fill_cap_info(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index 98b1b56d87c..59bb3ce1e64 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -264,7 +264,7 @@ ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, } void -ath9k_hw_rfdetach(struct ath_hw *ah) +ath9k_hw_rf_free(struct ath_hw *ah) { #define ATH_FREE_BANK(bank) do { \ kfree(bank); \ -- cgit v1.2.3-18-g5258 From e70c0cfdbf98384d9ce0b7a7332b6e60ec22ad54 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:51 -0700 Subject: ath9k: rename ath9k_hw_ani_detach() to ath9k_hw_ani_disable() Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ani.c | 4 ++-- drivers/net/wireless/ath/ath9k/ani.h | 2 +- drivers/net/wireless/ath/ath9k/hw.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index a613cf46eeb..b7093126dbb 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -822,9 +822,9 @@ void ath9k_hw_ani_init(struct ath_hw *ah) ah->proc_phyerr |= HAL_PROCESS_ANI; } -void ath9k_hw_ani_detach(struct ath_hw *ah) +void ath9k_hw_ani_disable(struct ath_hw *ah) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n"); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disabling ANI\n"); if (ah->has_hw_phycounters) { ath9k_hw_disable_mib_counters(ah); diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index 803669faaad..a36b7bb7c42 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -133,6 +133,6 @@ void ath9k_hw_procmibevent(struct ath_hw *ah, const struct ath9k_node_stats *stats); void ath9k_hw_ani_setup(struct ath_hw *ah); void ath9k_hw_ani_init(struct ath_hw *ah); -void ath9k_hw_ani_detach(struct ath_hw *ah); +void ath9k_hw_ani_disable(struct ath_hw *ah); #endif /* ANI_H */ diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 73dee19e887..6641fbedd6d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1227,7 +1227,7 @@ const char *ath9k_hw_probe(u16 vendorid, u16 devid) void ath9k_hw_detach(struct ath_hw *ah) { if (!AR_SREV_9100(ah)) - ath9k_hw_ani_detach(ah); + ath9k_hw_ani_disable(ah); ath9k_hw_rf_free(ah); ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); -- cgit v1.2.3-18-g5258 From 9db6b6a25fd829a0d29480785ac0770a1e76f9a4 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:52 -0700 Subject: ath9k: set ah to null after freeing Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 6641fbedd6d..633fe8b6f5f 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1232,6 +1232,7 @@ void ath9k_hw_detach(struct ath_hw *ah) ath9k_hw_rf_free(ah); ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); kfree(ah); + ah = NULL; } /*******/ -- cgit v1.2.3-18-g5258 From 3ce1b1a949ae849fb73556867e60977a65ca3141 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:53 -0700 Subject: ath9k: set sc->sc_ah to NULL after freeing it Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 91bffc91bbb..d3d2cb667dc 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1278,6 +1278,7 @@ void ath_detach(struct ath_softc *sc) ath_tx_cleanupq(sc, &sc->tx.txq[i]); ath9k_hw_detach(sc->sc_ah); + sc->sc_ah = NULL; ath9k_exit_debug(sc); } @@ -1521,6 +1522,7 @@ bad2: bad: if (ah) ath9k_hw_detach(ah); + sc->sc_ah = NULL; bad_no_ah: ath9k_exit_debug(sc); @@ -1631,6 +1633,7 @@ error_attach: ath_tx_cleanupq(sc, &sc->tx.txq[i]); ath9k_hw_detach(sc->sc_ah); + sc->sc_ah = NULL; ath9k_exit_debug(sc); return error; -- cgit v1.2.3-18-g5258 From 95fafca26dc317b7ea0667c57576b0b5389f5bef Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:54 -0700 Subject: ath9k: call ath9k_hw_detach() once upon hw init failure If hw initialization fails (ath9k_hw_init()) on ath_init_softc() we bail out and call ath9k_hw_detach(). The call ath9k_hw_detach() is conditional though as ath9k_hw_init() could itself have called ath9k_hw_detach(). Just describing this is itself a brain twister. Avoid this nonsense by removing ath9k_hw_detach() from ath9k_hw_init(). Upon hw initialization failure we expect the callers to take care of the cleanup. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 24 ++++++++---------------- drivers/net/wireless/ath/ath9k/main.c | 3 +-- 2 files changed, 9 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 633fe8b6f5f..08715299f75 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -898,26 +898,22 @@ static void ath9k_hw_init_11a_eeprom_fix(struct ath_hw *ah) int ath9k_hw_init(struct ath_hw *ah) { - int r; + int r = 0; - if (!ath9k_hw_devid_supported(ah->hw_version.devid)) { - r = -EOPNOTSUPP; - goto bad; - } + if (!ath9k_hw_devid_supported(ah->hw_version.devid)) + return -EOPNOTSUPP; ath9k_hw_init_defaults(ah); ath9k_hw_init_config(ah); if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't reset chip\n"); - r = -EIO; - goto bad; + return -EIO; } if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); - r = -EIO; - goto bad; + return -EIO; } if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) { @@ -939,8 +935,7 @@ int ath9k_hw_init(struct ath_hw *ah) "Mac Chip Rev 0x%02x.%x is not supported by " "this driver\n", ah->hw_version.macVersion, ah->hw_version.macRev); - r = -EOPNOTSUPP; - goto bad; + return -EOPNOTSUPP; } if (AR_SREV_9100(ah)) { @@ -965,7 +960,7 @@ int ath9k_hw_init(struct ath_hw *ah) r = ath9k_hw_post_init(ah); if (r) - goto bad; + return r; ath9k_hw_init_mode_gain_regs(ah); ath9k_hw_fill_cap_info(ah); @@ -975,7 +970,7 @@ int ath9k_hw_init(struct ath_hw *ah) if (r) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Failed to initialize MAC address\n"); - goto bad; + return r; } if (AR_SREV_9285(ah)) @@ -986,9 +981,6 @@ int ath9k_hw_init(struct ath_hw *ah) ath9k_init_nfcal_hist_buffer(ah); return 0; -bad: - ath9k_hw_detach(ah); - return r; } static void ath9k_hw_init_bb(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d3d2cb667dc..a5475b7a59d 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1520,8 +1520,7 @@ bad2: if (ATH_TXQ_SETUP(sc, i)) ath_tx_cleanupq(sc, &sc->tx.txq[i]); bad: - if (ah) - ath9k_hw_detach(ah); + ath9k_hw_detach(ah); sc->sc_ah = NULL; bad_no_ah: ath9k_exit_debug(sc); -- cgit v1.2.3-18-g5258 From 2f69ffacb303bba274b126eabd3a3ed011b2d35d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:55 -0700 Subject: ath9k: remove dangling error check on keycache reset on hw init The keycache reset will not fail as right above we ensure to set the sc->keymax to be <= ah->caps.keycache_size. Just remove this dangling check. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a5475b7a59d..7f412dd9b9f 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1363,9 +1363,6 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc) for (i = 0; i < sc->keymax; i++) ath9k_hw_keyreset(ah, (u16) i); - if (r) - goto bad; - /* default to MONITOR mode */ sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR; -- cgit v1.2.3-18-g5258 From 39068d1c2810077377fc2ffcfbe380bfbed696cb Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 12:24:56 -0700 Subject: ath9k: remove spurious check for channel on keycache reset ath9k_hw_keyreset() has a spurious check for ah->curchan.. remove it. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 08715299f75..0d60b357350 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2496,9 +2496,6 @@ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry) } - if (ah->curchan == NULL) - return true; - return true; } -- cgit v1.2.3-18-g5258 From 475f5989d4dc359046521cdfe9869cabf8c9fce9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 17:31:25 -0400 Subject: ath9k: Remove _t postfix for ar9287_eeprom structure We don't use typdefs on ath9k, remove that _t. Cc: Vivek Natarajan Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom.c | 20 ++++++++++---------- drivers/net/wireless/ath/ath9k/eeprom.h | 2 +- drivers/net/wireless/ath/ath9k/hw.h | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index e8ccec0dea1..80ece019216 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -2794,7 +2794,7 @@ static int ath9k_hw_AR9287_get_eeprom_rev(struct ath_hw *ah) static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) { - struct ar9287_eeprom_t *eep = &ah->eeprom.map9287; + struct ar9287_eeprom *eep = &ah->eeprom.map9287; u16 *eep_data; int addr, eep_start_loc = AR9287_EEP_START_LOC; eep_data = (u16 *)eep; @@ -2803,7 +2803,7 @@ static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) "Reading from EEPROM, not flash\n"); } - for (addr = 0; addr < sizeof(struct ar9287_eeprom_t) / sizeof(u16); + for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16); addr++) { if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, @@ -2816,12 +2816,12 @@ static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) } static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) { -#define SIZE_EEPROM_87 (sizeof(struct ar9287_eeprom_t) / sizeof(u16)) +#define SIZE_EEPROM_87 (sizeof(struct ar9287_eeprom) / sizeof(u16)) u32 sum = 0, el, integer; u16 temp, word, magic, magic2, *eepdata; int i, addr; bool need_swap = false; - struct ar9287_eeprom_t *eep = &ah->eeprom.map9287; + struct ar9287_eeprom *eep = &ah->eeprom.map9287; if (!ath9k_hw_use_flash(ah)) { if (!ath9k_hw_nvram_read @@ -2920,7 +2920,7 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah, enum eeprom_param param) { - struct ar9287_eeprom_t *eep = &ah->eeprom.map9287; + struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &eep->modalHeader; struct base_eep_ar9287_header *pBase = &eep->baseEepHeader; u16 ver_minor; @@ -3210,7 +3210,7 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, u16 xpdGainValues[AR9287_NUM_PD_GAINS] = {0, 0, 0, 0}; u32 reg32, regOffset, regChainOffset; int16_t modalIdx, diff = 0; - struct ar9287_eeprom_t *pEepData = &ah->eeprom.map9287; + struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; xpdMask = pEepData->modalHeader.xpdGain; if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= @@ -3380,7 +3380,7 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, struct chan_centers centers; int tx_chainmask; u16 twiceMinEdgePower; - struct ar9287_eeprom_t *pEepData = &ah->eeprom.map9287; + struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; tx_chainmask = ah->txchainmask; ath9k_hw_get_channel_centers(ah, chan, ¢ers); @@ -3613,7 +3613,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, { #define INCREASE_MAXPOW_BY_TWO_CHAIN 6 #define INCREASE_MAXPOW_BY_THREE_CHAIN 10 - struct ar9287_eeprom_t *pEepData = &ah->eeprom.map9287; + struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; int16_t ratesArray[Ar5416RateSize]; int16_t txPowerIndexOffset = 0; @@ -3776,7 +3776,7 @@ static void ath9k_hw_AR9287_set_addac(struct ath_hw *ah, static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, struct ath9k_channel *chan) { - struct ar9287_eeprom_t *eep = &ah->eeprom.map9287; + struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &eep->modalHeader; u16 antWrites[AR9287_ANT_16S]; @@ -3928,7 +3928,7 @@ static u8 ath9k_hw_AR9287_get_num_ant_config(struct ath_hw *ah, static u16 ath9k_hw_AR9287_get_eeprom_antenna_cfg(struct ath_hw *ah, struct ath9k_channel *chan) { - struct ar9287_eeprom_t *eep = &ah->eeprom.map9287; + struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &eep->modalHeader; return pModal->antCtrlCommon & 0xFFFF; } diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 335098d16a7..db77e90ed9a 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -600,7 +600,7 @@ struct ar5416_eeprom_4k { u8 padding; } __packed; -struct ar9287_eeprom_t { +struct ar9287_eeprom { struct base_eep_ar9287_header baseEepHeader; u8 custData[AR9287_DATA_SZ]; struct modal_eep_ar9287_header modalHeader; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 4e717cc68cd..9c23db146a3 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -403,7 +403,7 @@ struct ath_hw { union { struct ar5416_eeprom_def def; struct ar5416_eeprom_4k map4k; - struct ar9287_eeprom_t map9287; + struct ar9287_eeprom map9287; } eeprom; const struct eeprom_ops *eep_ops; enum ath9k_eep_map eep_map; -- cgit v1.2.3-18-g5258 From edb1f9152f1f346381336554674f5d443fc5f473 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 23:14:10 -0400 Subject: ath9k: add ar9271 revision and subrevision ID helpers These will be used later to add support for ar9271. Cc: Stephen Chen Cc: Zhifeng Cai Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/reg.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 8302aeb62e5..37cbf038be4 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -744,6 +744,9 @@ #define AR_SREV_VERSION_9287 0x180 #define AR_SREV_REVISION_9287_10 0 #define AR_SREV_REVISION_9287_11 1 +#define AR_SREV_VERSION_9271 0x140 +#define AR_SREV_REVISION_9271_10 0 +#define AR_SREV_REVISION_9271_11 1 #define AR_SREV_5416(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ @@ -815,6 +818,15 @@ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_11))) +#define AR_SREV_9271(_ah) \ + (((_ah))->hw_version.macVersion == AR_SREV_VERSION_9271) +#define AR_SREV_9271_10(_ah) \ + (AR_SREV_9271(_ah) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9271_10)) +#define AR_SREV_9271_11(_ah) \ + (AR_SREV_9271(_ah) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9271_11)) + #define AR_RADIO_SREV_MAJOR 0xf0 #define AR_RAD5133_SREV_MAJOR 0xc0 #define AR_RAD2133_SREV_MAJOR 0xd0 -- cgit v1.2.3-18-g5258 From 670388c5f56383e1d5b9f4f7fc835a280487754e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 23:14:11 -0400 Subject: ath9k: add initvals and registry definitions for AR9271 Cc: Stephen Chen Cc: Zhifeng Cai Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/initvals.h | 666 ++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/phy.h | 3 + drivers/net/wireless/ath/ath9k/reg.h | 25 ++ 3 files changed, 694 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h index af4a1bafa7e..27a86bb7c4c 100644 --- a/drivers/net/wireless/ath/ath9k/initvals.h +++ b/drivers/net/wireless/ath/ath9k/initvals.h @@ -6365,3 +6365,669 @@ static const u_int32_t ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = { }; +/* AR9271 initialization values automaticaly created: 03/23/09 */ +static const u_int32_t ar9271Modes_9271_1_0[][6] = { + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f }, + { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e }, + { 0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0 }, + { 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 }, + { 0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 }, + { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, + { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, + { 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e }, + { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18 }, + { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, + { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d }, + { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010 }, + { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c }, + { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329 }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000 }, + { 0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 }, + { 0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 }, + { 0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 }, + { 0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 }, + { 0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 }, + { 0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 }, + { 0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 }, + { 0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 }, + { 0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 }, + { 0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 }, + { 0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 }, + { 0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 }, + { 0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 }, + { 0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 }, + { 0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 }, + { 0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 }, + { 0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 }, + { 0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 }, + { 0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 }, + { 0x00009a50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 }, + { 0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 }, + { 0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 }, + { 0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 }, + { 0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 }, + { 0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 }, + { 0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 }, + { 0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000 }, + { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 }, + { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 }, + { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 }, + { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, + { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, + { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, + { 0x00009a88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, + { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 }, + { 0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 }, + { 0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 }, + { 0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 }, + { 0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 }, + { 0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 }, + { 0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 }, + { 0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 }, + { 0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 }, + { 0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 }, + { 0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 }, + { 0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 }, + { 0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 }, + { 0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 }, + { 0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 }, + { 0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 }, + { 0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 }, + { 0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 }, + { 0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 }, + { 0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 }, + { 0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 }, + { 0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 }, + { 0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 }, + { 0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 }, + { 0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 }, + { 0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 }, + { 0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 }, + { 0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 }, + { 0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 }, + { 0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 }, + { 0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 }, + { 0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 }, + { 0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 }, + { 0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 }, + { 0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 }, + { 0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 }, + { 0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 }, + { 0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 }, + { 0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 }, + { 0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 }, + { 0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 }, + { 0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 }, + { 0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 }, + { 0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 }, + { 0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 }, + { 0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 }, + { 0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 }, + { 0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 }, + { 0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 }, + { 0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 }, + { 0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 }, + { 0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 }, + { 0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000 }, + { 0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 }, + { 0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 }, + { 0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 }, + { 0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 }, + { 0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 }, + { 0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 }, + { 0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 }, + { 0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 }, + { 0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 }, + { 0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 }, + { 0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 }, + { 0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 }, + { 0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 }, + { 0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 }, + { 0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 }, + { 0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 }, + { 0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 }, + { 0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 }, + { 0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 }, + { 0x0000aa50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 }, + { 0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 }, + { 0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 }, + { 0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 }, + { 0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 }, + { 0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 }, + { 0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 }, + { 0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000 }, + { 0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 }, + { 0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 }, + { 0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 }, + { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, + { 0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, + { 0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, + { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, + { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 }, + { 0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 }, + { 0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 }, + { 0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 }, + { 0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 }, + { 0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 }, + { 0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 }, + { 0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 }, + { 0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 }, + { 0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 }, + { 0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 }, + { 0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 }, + { 0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 }, + { 0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 }, + { 0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 }, + { 0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 }, + { 0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 }, + { 0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 }, + { 0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 }, + { 0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 }, + { 0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 }, + { 0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 }, + { 0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 }, + { 0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 }, + { 0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 }, + { 0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 }, + { 0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 }, + { 0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 }, + { 0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 }, + { 0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 }, + { 0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 }, + { 0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 }, + { 0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 }, + { 0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 }, + { 0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 }, + { 0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 }, + { 0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 }, + { 0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 }, + { 0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 }, + { 0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 }, + { 0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 }, + { 0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 }, + { 0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 }, + { 0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 }, + { 0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 }, + { 0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 }, + { 0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 }, + { 0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 }, + { 0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 }, + { 0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 }, + { 0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 }, + { 0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 }, + { 0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, + { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 }, + { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 }, + { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 }, + { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a218652, 0x0a218652, 0x0a22a652 }, + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 }, + { 0x0000a310, 0x00000000, 0x00000000, 0x0001e610, 0x0001e610, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x0002d6d0, 0x0002d6d0, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00039758, 0x00039758, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x0003b759, 0x0003b759, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x0003d75a, 0x0003d75a, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0004175c, 0x0004175c, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x0004575e, 0x0004575e, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0004979f, 0x0004979f, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0004d7df, 0x0004d7df, 0x00000000 }, + { 0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000 }, + { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, + { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, + { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, +}; + +static const u_int32_t ar9271Common_9271_1_0[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020045 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00004024, 0x0000001f }, + { 0x00004060, 0x00000000 }, + { 0x00004064, 0x00000000 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x00000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x02000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x00008070, 0x00000000 }, + { 0x000080b0, 0x00000000 }, + { 0x000080b4, 0x00000000 }, + { 0x000080b8, 0x00000000 }, + { 0x000080bc, 0x00000000 }, + { 0x000080c0, 0x2a80001a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008120, 0x08f04814 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0xffffffff }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c0, 0x00000000 }, + { 0x000081d0, 0x0000320a }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008264, 0xa8a00010 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x0000829c, 0x00000000 }, + { 0x00008300, 0x00000040 }, + { 0x00008314, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000001 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00ff0000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x00010380 }, + { 0x00008344, 0x00581043 }, + { 0x00007010, 0x00000030 }, + { 0x00007034, 0x00000002 }, + { 0x00007038, 0x000004c2 }, + { 0x00007800, 0x00140000 }, + { 0x00007804, 0x0e4548d8 }, + { 0x00007808, 0x54214514 }, + { 0x0000780c, 0x02025820 }, + { 0x00007810, 0x71c0d388 }, + { 0x00007814, 0x924934a8 }, + { 0x0000781c, 0x00000000 }, + { 0x00007820, 0x00000c04 }, + { 0x00007824, 0x00d86bff }, + { 0x00007828, 0x66964300 }, + { 0x0000782c, 0x8db6d961 }, + { 0x00007830, 0x8db6d96c }, + { 0x00007834, 0x6140008b }, + { 0x00007838, 0x00000029 }, + { 0x0000783c, 0x72ee0a72 }, + { 0x00007840, 0xbbfffffc }, + { 0x00007844, 0x000c0db6 }, + { 0x00007848, 0x6db61b6f }, + { 0x0000784c, 0x6d9b66db }, + { 0x00007850, 0x6d8c6dba }, + { 0x00007854, 0x00040000 }, + { 0x00007858, 0xdb003012 }, + { 0x0000785c, 0x04924914 }, + { 0x00007860, 0x21084210 }, + { 0x00007864, 0xf7d7ffde }, + { 0x00007868, 0xc2034080 }, + { 0x0000786c, 0x48609eb4 }, + { 0x00007870, 0x10142c00 }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xafe68e30 }, + { 0x00009810, 0xfd14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x0040233c }, + { 0x00009854, 0x00000044 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x00009910, 0x30002310 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x04900000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009940, 0x14750604 }, + { 0x00009948, 0x9280c00a }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5f3ca3de }, + { 0x00009958, 0x0108ecff }, + { 0x00009968, 0x000003ce }, + { 0x00009970, 0x192bb515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x2def0400 }, + { 0x000099b0, 0x03051000 }, + { 0x000099b4, 0x00000820 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099f0, 0x00000000 }, + { 0x0000a1f4, 0x00000000 }, + { 0x0000a1f8, 0x71733d01 }, + { 0x0000a1fc, 0xd0ad5c12 }, + { 0x0000a208, 0x803e68c8 }, + { 0x0000a210, 0x4080a333 }, + { 0x0000a214, 0x00206c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x01834061 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x000003b5 }, + { 0x0000a22c, 0x00000000 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a244, 0x00000000 }, + { 0x0000a248, 0xfffffffc }, + { 0x0000a24c, 0x00000000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0ccb5380 }, + { 0x0000a25c, 0x15151501 }, + { 0x0000a260, 0xdfa90f01 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0ebae9e6 }, + { 0x0000a278, 0x3bdef7bd }, + { 0x0000a27c, 0x050e83bd }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x3bdef7bd }, + { 0x0000a398, 0x000003bd }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x3bdef7bd }, + { 0x0000a3e0, 0x000003bd }, + { 0x0000a3e4, 0x00000000 }, + { 0x0000a3e8, 0x18c43433 }, + { 0x0000a3ec, 0x00f70081 }, + { 0x0000a3f0, 0x01036a2f }, + { 0x0000a3f4, 0x00000000 }, + { 0x0000d270, 0x0d820820 }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, +}; diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index de4fadadbce..27bd93c6e74 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -185,6 +185,9 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, #define AR_PHY_PLL_CTL_44_2133 0xeb #define AR_PHY_PLL_CTL_40_2133 0xea +#define AR_PHY_SPECTRAL_SCAN 0x9912 +#define AR_PHY_SPECTRAL_SCAN_ENABLE 0x1 + #define AR_PHY_RX_DELAY 0x9914 #define AR_PHY_SEARCH_START_DELAY 0x9918 #define AR_PHY_RX_DELAY_DELAY 0x00003FFF diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 37cbf038be4..13fd658b5d3 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1154,12 +1154,32 @@ enum { #define AR9285_AN_RF2G4_DB2_4 0x00003800 #define AR9285_AN_RF2G4_DB2_4_S 11 +/* AR9271 : 0x7828, 0x782c different setting from AR9285 */ +#define AR9271_AN_RF2G3_OB_cck 0x001C0000 +#define AR9271_AN_RF2G3_OB_cck_S 18 +#define AR9271_AN_RF2G3_OB_psk 0x00038000 +#define AR9271_AN_RF2G3_OB_psk_S 15 +#define AR9271_AN_RF2G3_OB_qam 0x00007000 +#define AR9271_AN_RF2G3_OB_qam_S 12 + +#define AR9271_AN_RF2G3_DB_1 0x00E00000 +#define AR9271_AN_RF2G3_DB_1_S 21 + +#define AR9271_AN_RF2G3_CCOMP 0xFFF +#define AR9271_AN_RF2G3_CCOMP_S 0 + +#define AR9271_AN_RF2G4_DB_2 0xE0000000 +#define AR9271_AN_RF2G4_DB_2_S 29 + #define AR9285_AN_RF2G6 0x7834 #define AR9285_AN_RF2G6_CCOMP 0x00007800 #define AR9285_AN_RF2G6_CCOMP_S 11 #define AR9285_AN_RF2G6_OFFS 0x03f00000 #define AR9285_AN_RF2G6_OFFS_S 20 +#define AR9271_AN_RF2G6_OFFS 0x07f00000 +#define AR9271_AN_RF2G6_OFFS_S 20 + #define AR9285_AN_RF2G7 0x7838 #define AR9285_AN_RF2G7_PWDDB 0x00000002 #define AR9285_AN_RF2G7_PWDDB_S 1 @@ -1220,6 +1240,11 @@ enum { #define AR9287_AN_TOP2_XPABIAS_LVL 0xC0000000 #define AR9287_AN_TOP2_XPABIAS_LVL_S 30 +/* AR9271 specific stuff */ +#define AR9271_RESET_POWER_DOWN_CONTROL 0x50044 +#define AR9271_RADIO_RF_RST 0x20 +#define AR9271_GATE_MAC_CTL 0x4000 + #define AR_STA_ID0 0x8000 #define AR_STA_ID1 0x8004 #define AR_STA_ID1_SADH_MASK 0x0000FFFF -- cgit v1.2.3-18-g5258 From d7e7d229c7d1395283e1e1fda8727af60ca6f4ad Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 23:14:12 -0400 Subject: ath9k: add initial hardware support for ar9271 We will finalize this after some driver core changes, for now we leave this unsupported. Cc: Stephen Chen Cc: Zhifeng Cai Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/calib.c | 106 +++++++++++++++++++++++- drivers/net/wireless/ath/ath9k/eeprom.c | 142 ++++++++++++++++++++++++-------- drivers/net/wireless/ath/ath9k/hw.c | 104 +++++++++++++++++++++-- drivers/net/wireless/ath/ath9k/hw.h | 2 + 4 files changed, 314 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index d1bbb02af8d..26d87527acb 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -753,6 +753,98 @@ static void ath9k_olc_temp_compensation(struct ath_hw *ah) } } +static void ath9k_hw_9271_pa_cal(struct ath_hw *ah) +{ + u32 regVal; + unsigned int i; + u32 regList [][2] = { + { 0x786c, 0 }, + { 0x7854, 0 }, + { 0x7820, 0 }, + { 0x7824, 0 }, + { 0x7868, 0 }, + { 0x783c, 0 }, + { 0x7838, 0 } , + { 0x7828, 0 } , + }; + + for (i = 0; i < ARRAY_SIZE(regList); i++) + regList[i][1] = REG_READ(ah, regList[i][0]); + + regVal = REG_READ(ah, 0x7834); + regVal &= (~(0x1)); + REG_WRITE(ah, 0x7834, regVal); + regVal = REG_READ(ah, 0x9808); + regVal |= (0x1 << 27); + REG_WRITE(ah, 0x9808, regVal); + + /* 786c,b23,1, pwddac=1 */ + REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); + /* 7854, b5,1, pdrxtxbb=1 */ + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); + /* 7854, b7,1, pdv2i=1 */ + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); + /* 7854, b8,1, pddacinterface=1 */ + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); + /* 7824,b12,0, offcal=0 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); + /* 7838, b1,0, pwddb=0 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); + /* 7820,b11,0, enpacal=0 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); + /* 7820,b25,1, pdpadrv1=0 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0); + /* 7820,b24,0, pdpadrv2=0 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G1,AR9285_AN_RF2G1_PDPADRV2,0); + /* 7820,b23,0, pdpaout=0 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); + /* 783c,b14-16,7, padrvgn2tab_0=7 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G8,AR9285_AN_RF2G8_PADRVGN2TAB0, 7); + /* + * 7838,b29-31,0, padrvgn1tab_0=0 + * does not matter since we turn it off + */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G7,AR9285_AN_RF2G7_PADRVGN2TAB0, 0); + + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff); + + /* Set: + * localmode=1,bmode=1,bmoderxtx=1,synthon=1, + * txon=1,paon=1,oscon=1,synthon_force=1 + */ + REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); + udelay(30); + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0); + + /* find off_6_1; */ + for (i = 6; i >= 0; i--) { + regVal = REG_READ(ah, 0x7834); + regVal |= (1 << (20 + i)); + REG_WRITE(ah, 0x7834, regVal); + udelay(1); + //regVal = REG_READ(ah, 0x7834); + regVal &= (~(0x1 << (20 + i))); + regVal |= (MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9) + << (20 + i)); + REG_WRITE(ah, 0x7834, regVal); + } + + /* Empirical offset correction */ +#if 0 + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0x20); +#endif + + regVal = REG_READ(ah, 0x7834); + regVal |= 0x1; + REG_WRITE(ah, 0x7834, regVal); + regVal = REG_READ(ah, 0x9808); + regVal &= (~(0x1 << 27)); + REG_WRITE(ah, 0x9808, regVal); + + for (i = 0; i < ARRAY_SIZE(regList); i++) + REG_WRITE(ah, regList[i][0], regList[i][1]); +} + static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah) { @@ -869,14 +961,26 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, } } + /* Do NF cal only at longer intervals */ if (longcal) { - if (AR_SREV_9285_11_OR_LATER(ah)) + /* Do periodic PAOffset Cal */ + if (AR_SREV_9271(ah)) + ath9k_hw_9271_pa_cal(ah); + else if (AR_SREV_9285_11_OR_LATER(ah)) ath9k_hw_9285_pa_cal(ah); if (OLC_FOR_AR9280_20_LATER || OLC_FOR_AR9287_10_LATER) ath9k_olc_temp_compensation(ah); + + /* Get the value from the previous NF cal and update history buffer */ ath9k_hw_getnf(ah, chan); + + /* + * Load the NF from history buffer of the current channel. + * NF is slow time-variant, so it is OK to use a historical value. + */ ath9k_hw_loadnf(ah, ah->curchan); + ath9k_hw_start_nfcal(ah); } diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 80ece019216..9a09cc8e704 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -1237,6 +1237,10 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah, REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); } +/* + * Read EEPROM header info and program the device for correct operation + * given the channel value. + */ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -1313,38 +1317,110 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, } } - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_0, AR9285_AN_RF2G3_OB_0_S, ob[0]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_1, AR9285_AN_RF2G3_OB_1_S, ob[1]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_2, AR9285_AN_RF2G3_OB_2_S, ob[2]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_3, AR9285_AN_RF2G3_OB_3_S, ob[3]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_4, AR9285_AN_RF2G3_OB_4_S, ob[4]); - - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_DB1_0, AR9285_AN_RF2G3_DB1_0_S, db1[0]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_DB1_1, AR9285_AN_RF2G3_DB1_1_S, db1[1]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, - AR9285_AN_RF2G3_DB1_2, AR9285_AN_RF2G3_DB1_2_S, db1[2]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB1_3, AR9285_AN_RF2G4_DB1_3_S, db1[3]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB1_4, AR9285_AN_RF2G4_DB1_4_S, db1[4]); - - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_0, AR9285_AN_RF2G4_DB2_0_S, db2[0]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_1, AR9285_AN_RF2G4_DB2_1_S, db2[1]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_2, AR9285_AN_RF2G4_DB2_2_S, db2[2]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_3, AR9285_AN_RF2G4_DB2_3_S, db2[3]); - ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_4, AR9285_AN_RF2G4_DB2_4_S, db2[4]); + if (AR_SREV_9271(ah)) { + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9271_AN_RF2G3_OB_cck, + AR9271_AN_RF2G3_OB_cck_S, + ob[0]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9271_AN_RF2G3_OB_psk, + AR9271_AN_RF2G3_OB_psk_S, + ob[1]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9271_AN_RF2G3_OB_qam, + AR9271_AN_RF2G3_OB_qam_S, + ob[2]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9271_AN_RF2G3_DB_1, + AR9271_AN_RF2G3_DB_1_S, + db1[0]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9271_AN_RF2G4_DB_2, + AR9271_AN_RF2G4_DB_2_S, + db2[0]); + } else { + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_0, + AR9285_AN_RF2G3_OB_0_S, + ob[0]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_1, + AR9285_AN_RF2G3_OB_1_S, + ob[1]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_2, + AR9285_AN_RF2G3_OB_2_S, + ob[2]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_3, + AR9285_AN_RF2G3_OB_3_S, + ob[3]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_4, + AR9285_AN_RF2G3_OB_4_S, + ob[4]); + + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_0, + AR9285_AN_RF2G3_DB1_0_S, + db1[0]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_1, + AR9285_AN_RF2G3_DB1_1_S, + db1[1]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_2, + AR9285_AN_RF2G3_DB1_2_S, + db1[2]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB1_3, + AR9285_AN_RF2G4_DB1_3_S, + db1[3]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB1_4, + AR9285_AN_RF2G4_DB1_4_S, db1[4]); + + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_0, + AR9285_AN_RF2G4_DB2_0_S, + db2[0]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_1, + AR9285_AN_RF2G4_DB2_1_S, + db2[1]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_2, + AR9285_AN_RF2G4_DB2_2_S, + db2[2]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_3, + AR9285_AN_RF2G4_DB2_3_S, + db2[3]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_4, + AR9285_AN_RF2G4_DB2_4_S, + db2[4]); + } if (AR_SREV_9285_11(ah)) @@ -3984,7 +4060,7 @@ int ath9k_hw_eeprom_init(struct ath_hw *ah) if (AR_SREV_9287(ah)) { ah->eep_map = EEP_MAP_AR9287; ah->eep_ops = &eep_AR9287_ops; - } else if (AR_SREV_9285(ah)) { + } else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) { ah->eep_map = EEP_MAP_4KBITS; ah->eep_ops = &eep_4k_ops; } else { diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 0d60b357350..71a3bcc450a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -638,6 +638,8 @@ static bool ath9k_hw_macversion_supported(u32 macversion) case AR_SREV_VERSION_9285: case AR_SREV_VERSION_9287: return true; + /* Not yet */ + case AR_SREV_VERSION_9271: default: break; } @@ -670,6 +672,14 @@ static void ath9k_hw_init_cal_settings(struct ath_hw *ah) static void ath9k_hw_init_mode_regs(struct ath_hw *ah) { + if (AR_SREV_9271(ah)) { + INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271_1_0, + ARRAY_SIZE(ar9271Modes_9271_1_0), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271_1_0, + ARRAY_SIZE(ar9271Common_9271_1_0), 2); + return; + } + if (AR_SREV_9287_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1, ARRAY_SIZE(ar9287Modes_9287_1_1), 6); @@ -943,6 +953,10 @@ int ath9k_hw_init(struct ath_hw *ah) ah->supp_cals = IQ_MISMATCH_CAL; ah->is_pciexpress = false; } + + if (AR_SREV_9271(ah)) + ah->is_pciexpress = false; + ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID); ath9k_hw_init_cal_settings(ah); @@ -973,7 +987,7 @@ int ath9k_hw_init(struct ath_hw *ah) return r; } - if (AR_SREV_9285(ah)) + if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S); else ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S); @@ -1234,6 +1248,27 @@ void ath9k_hw_detach(struct ath_hw *ah) static void ath9k_hw_override_ini(struct ath_hw *ah, struct ath9k_channel *chan) { + u32 val; + + if (AR_SREV_9271(ah)) { + /* + * Enable spectral scan to solution for issues with stuck + * beacons on AR9271 1.0. The beacon stuck issue is not seeon on + * AR9271 1.1 + */ + if (AR_SREV_9271_10(ah)) { + val = REG_READ(ah, AR_PHY_SPECTRAL_SCAN) | AR_PHY_SPECTRAL_SCAN_ENABLE; + REG_WRITE(ah, AR_PHY_SPECTRAL_SCAN, val); + } + else if (AR_SREV_9271_11(ah)) + /* + * change AR_PHY_RF_CTL3 setting to fix MAC issue + * present on AR9271 1.1 + */ + REG_WRITE(ah, AR_PHY_RF_CTL3, 0x3a020001); + return; + } + /* * Set the RX_ABORT and RX_DIS and clear if off only after * RXE is set for MAC. This prevents frames with corrupted @@ -1245,7 +1280,10 @@ static void ath9k_hw_override_ini(struct ath_hw *ah, if (!AR_SREV_5416_20_OR_LATER(ah) || AR_SREV_9280_10_OR_LATER(ah)) return; - + /* + * Disable BB clock gating + * Necessary to avoid issues on AR5416 2.0 + */ REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); } @@ -1477,23 +1515,48 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah) { u32 regval; + /* + * set AHB_MODE not to do cacheline prefetches + */ regval = REG_READ(ah, AR_AHB_MODE); REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); + /* + * let mac dma reads be in 128 byte chunks + */ regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); + /* + * Restore TX Trigger Level to its pre-reset value. + * The initial value depends on whether aggregation is enabled, and is + * adjusted whenever underruns are detected. + */ REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->tx_trig_level); + /* + * let mac dma writes be in 128 byte chunks + */ regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); + /* + * Setup receive FIFO threshold to hold off TX activities + */ REG_WRITE(ah, AR_RXFIFO_CFG, 0x200); + /* + * reduce the number of usable entries in PCU TXBUF to avoid + * wrap around issues. + */ if (AR_SREV_9285(ah)) { + /* For AR9285 the number of Fifos are reduced to half. + * So set the usable tx buf size also to half to + * avoid data/delimiter underruns + */ REG_WRITE(ah, AR_PCU_TXBUF_CTRL, AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE); - } else { + } else if (!AR_SREV_9271(ah)) { REG_WRITE(ah, AR_PCU_TXBUF_CTRL, AR_PCU_TXBUF_CTRL_USABLE_SIZE); } @@ -2299,11 +2362,26 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_mark_phy_inactive(ah); + if (AR_SREV_9271(ah) && ah->htc_reset_init) { + REG_WRITE(ah, + AR9271_RESET_POWER_DOWN_CONTROL, + AR9271_RADIO_RF_RST); + udelay(50); + } + if (!ath9k_hw_chip_reset(ah, chan)) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Chip reset failed\n"); return -EINVAL; } + if (AR_SREV_9271(ah) && ah->htc_reset_init) { + ah->htc_reset_init = false; + REG_WRITE(ah, + AR9271_RESET_POWER_DOWN_CONTROL, + AR9271_GATE_MAC_CTL); + udelay(50); + } + if (AR_SREV_9280_10_OR_LATER(ah)) REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); @@ -2439,6 +2517,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_WRITE(ah, AR_CFG_LED, saveLedState | AR_CFG_SCLK_32KHZ); + /* + * For big endian systems turn on swapping for descriptors + */ if (AR_SREV_9100(ah)) { u32 mask; mask = REG_READ(ah, AR_CFG); @@ -2453,8 +2534,12 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, "Setting CFG 0x%x\n", REG_READ(ah, AR_CFG)); } } else { + /* Configure AR9271 target WLAN */ + if (AR_SREV_9271(ah)) + REG_WRITE(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB); #ifdef __BIG_ENDIAN - REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); + else + REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); #endif } @@ -2981,7 +3066,7 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore) if (ah->config.pcie_waen) { REG_WRITE(ah, AR_WA, ah->config.pcie_waen); } else { - if (AR_SREV_9285(ah)) + if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT); /* * On AR9280 chips bit 22 of 0x4004 needs to be set to @@ -3445,10 +3530,17 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) } pCap->tx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_TX_MASK); + /* + * For AR9271 we will temporarilly uses the rx chainmax as read from + * the EEPROM. + */ if ((ah->hw_version.devid == AR5416_DEVID_PCI) && - !(eeval & AR5416_OPFLAGS_11A)) + !(eeval & AR5416_OPFLAGS_11A) && + !(AR_SREV_9271(ah))) + /* CB71: GPIO 0 is pulled down to indicate 3 rx chains */ pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7; else + /* Use rx_chainmask from EEPROM. */ pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK); if (!(AR_SREV_9280(ah) && (ah->hw_version.macRev == 0))) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 9c23db146a3..d4aaf4f8db2 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -419,6 +419,8 @@ struct ath_hw { u32 wlanactive_gpio; u32 ah_flags; + bool htc_reset_init; + enum nl80211_iftype opmode; enum ath9k_power_mode power_mode; -- cgit v1.2.3-18-g5258 From e48e3a2f17f189deb086ff221e489e7fd8ec4302 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 24 Jul 2009 20:47:33 -0400 Subject: ath9k: cancel xmit poll work at stop() callback We forgot to cancel this work at the stop() callback. ------------[ cut here ]------------ WARNING: at net/mac80211/util.c:511 ieee80211_queue_delayed_work+0x3a/0x40 [mac80211]() Hardware name: 6460DWU queueing ieee80211 work while going to suspend Modules linked in: <-- snip --> Pid: 5124, comm: phy0 Tainted: G W 2.6.31-rc3-wl #4 Call Trace: [] ? ieee80211_queue_delayed_work+0x3a/0x40 [mac80211] [] warn_slowpath_common+0x78/0xd0 [] warn_slowpath_fmt+0x64/0x70 [] ? thread_return+0x3e/0x635 [] ieee80211_queue_delayed_work+0x3a/0x40 [mac80211] [] ath_tx_complete_poll_work+0xc0/0x100 [ath9k] [] ? ath_tx_complete_poll_work+0x0/0x100 [ath9k] [] worker_thread+0x178/0x260 [] ? autoremove_wake_function+0x0/0x40 [] ? worker_thread+0x0/0x260 [] kthread+0x9e/0xb0 [] child_rip+0xa/0x20 [] ? kthread+0x0/0xb0 [] ? child_rip+0x0/0x20 Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 7f412dd9b9f..a9e43f7a23f 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2117,6 +2117,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) mutex_lock(&sc->mutex); + cancel_delayed_work_sync(&sc->tx_complete_work); + if (ath9k_wiphy_started(sc)) { mutex_unlock(&sc->mutex); return; /* another wiphy still in use */ -- cgit v1.2.3-18-g5258 From 6b4f645a491ac29c7dced415d034eea7736155a6 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 3 Aug 2009 13:51:49 -0700 Subject: ath9k: fix compile warning on ath9k_hw_AR9287_check_eeprom() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC [M] drivers/net/wireless/ath/ath9k/eeprom.o drivers/net/wireless/ath/ath9k/eeprom.c: In function ‘ath9k_hw_AR9287_check_eeprom’: drivers/net/wireless/ath/ath9k/eeprom.c:2866: warning: comparison of distinct pointer types lacks a cast Cc: Vivek Natarajan Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 9a09cc8e704..4cb64a0900b 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -2892,7 +2892,6 @@ static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) } static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) { -#define SIZE_EEPROM_87 (sizeof(struct ar9287_eeprom) / sizeof(u16)) u32 sum = 0, el, integer; u16 temp, word, magic, magic2, *eepdata; int i, addr; @@ -2918,7 +2917,9 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) need_swap = true; eepdata = (u16 *)(&ah->eeprom); - for (addr = 0; addr < SIZE_EEPROM_87; addr++) { + for (addr = 0; + addr < sizeof(struct ar9287_eeprom) / sizeof(u16); + addr++) { temp = swab16(*eepdata); *eepdata = temp; eepdata++; @@ -2938,8 +2939,13 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) else el = ah->eeprom.map9287.baseEepHeader.length; + if (el > sizeof(struct ar9287_eeprom)) + el = sizeof(struct ar9287_eeprom) / sizeof(u16); + else + el = el / sizeof(u16); + eepdata = (u16 *)(&ah->eeprom); - for (i = 0; i < min(el, SIZE_EEPROM_87); i++) + for (i = 0; i < el; i++) sum ^= *eepdata++; if (need_swap) { @@ -2990,7 +2996,6 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) } return 0; -#undef SIZE_EEPROM_87 } static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah, -- cgit v1.2.3-18-g5258 From d570e9ef84e559b09e729f27f5381b6868f6cc5f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 4 Aug 2009 22:07:26 -0700 Subject: Input: tsc2007 - make get_pendown_state platform callback optional In cases when get_pendown_state callback is not available have the driver to fallback on pressure calculation to determine if the pen is up. Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007.c | 172 +++++++++++++++++++----------------- 1 file changed, 93 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index f710af4d0ff..3714d19f102 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -70,7 +70,6 @@ struct tsc2007 { struct input_dev *input; char phys[32]; struct delayed_work work; - struct ts_event tc; struct i2c_client *client; @@ -106,51 +105,96 @@ static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd) return val; } -static void tsc2007_send_event(void *tsc) +static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc) { - struct tsc2007 *ts = tsc; - u32 rt; - u16 x, y, z1, z2; + /* y- still on; turn on only y+ (and ADC) */ + tc->y = tsc2007_xfer(tsc, READ_Y); + + /* turn y- off, x+ on, then leave in lowpower */ + tc->x = tsc2007_xfer(tsc, READ_X); + + /* turn y+ off, x- on; we'll use formula #1 */ + tc->z1 = tsc2007_xfer(tsc, READ_Z1); + tc->z2 = tsc2007_xfer(tsc, READ_Z2); - x = ts->tc.x; - y = ts->tc.y; - z1 = ts->tc.z1; - z2 = ts->tc.z2; + /* Prepare for next touch reading - power down ADC, enable PENIRQ */ + tsc2007_xfer(tsc, PWRDOWN); +} + +static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc) +{ + u32 rt = 0; /* range filtering */ - if (x == MAX_12BIT) - x = 0; + if (tc->x == MAX_12BIT) + tc->x = 0; - if (likely(x && z1)) { + if (likely(tc->x && tc->z1)) { /* compute touch pressure resistance using equation #1 */ - rt = z2; - rt -= z1; - rt *= x; - rt *= ts->x_plate_ohms; - rt /= z1; + rt = tc->z2 - tc->z1; + rt *= tc->x; + rt *= tsc->x_plate_ohms; + rt /= tc->z1; rt = (rt + 2047) >> 12; - } else - rt = 0; - - /* - * Sample found inconsistent by debouncing or pressure is beyond - * the maximum. Don't report it to user space, repeat at least - * once more the measurement - */ - if (rt > MAX_12BIT) { - dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt); - return; } + return rt; +} + +static void tsc2007_send_up_event(struct tsc2007 *tsc) +{ + struct input_dev *input = tsc->input; + + dev_dbg(&tsc->client->dev, "UP\n"); + + input_report_key(input, BTN_TOUCH, 0); + input_report_abs(input, ABS_PRESSURE, 0); + input_sync(input); +} + +static void tsc2007_work(struct work_struct *work) +{ + struct tsc2007 *ts = + container_of(to_delayed_work(work), struct tsc2007, work); + struct ts_event tc; + u32 rt; + /* * NOTE: We can't rely on the pressure to determine the pen down - * state, even this controller has a pressure sensor. The pressure - * value can fluctuate for quite a while after lifting the pen and - * in some cases may not even settle at the expected value. + * state, even though this controller has a pressure sensor. + * The pressure value can fluctuate for quite a while after + * lifting the pen and in some cases may not even settle at the + * expected value. * * The only safe way to check for the pen up condition is in the - * work function by reading the pen signal state (it's a GPIO and IRQ). + * work function by reading the pen signal state (it's a GPIO + * and IRQ). Unfortunately such callback is not always available, + * in that case we have rely on the pressure anyway. */ + if (ts->get_pendown_state) { + if (unlikely(!ts->get_pendown_state())) { + tsc2007_send_up_event(ts); + ts->pendown = false; + goto out; + } + + dev_dbg(&ts->client->dev, "pen is still down\n"); + } + + tsc2007_read_values(ts, &tc); + + rt = tsc2007_calculate_pressure(ts, &tc); + if (rt > MAX_12BIT) { + /* + * Sample found inconsistent by debouncing or pressure is + * beyond the maximum. Don't report it to user space, + * repeat at least once more the measurement. + */ + dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt); + goto out; + + } + if (rt) { struct input_dev *input = ts->input; @@ -161,68 +205,38 @@ static void tsc2007_send_event(void *tsc) ts->pendown = true; } - input_report_abs(input, ABS_X, x); - input_report_abs(input, ABS_Y, y); + input_report_abs(input, ABS_X, tc.x); + input_report_abs(input, ABS_Y, tc.y); input_report_abs(input, ABS_PRESSURE, rt); input_sync(input); dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n", - x, y, rt); - } -} - -static int tsc2007_read_values(struct tsc2007 *tsc) -{ - /* y- still on; turn on only y+ (and ADC) */ - tsc->tc.y = tsc2007_xfer(tsc, READ_Y); - - /* turn y- off, x+ on, then leave in lowpower */ - tsc->tc.x = tsc2007_xfer(tsc, READ_X); - - /* turn y+ off, x- on; we'll use formula #1 */ - tsc->tc.z1 = tsc2007_xfer(tsc, READ_Z1); - tsc->tc.z2 = tsc2007_xfer(tsc, READ_Z2); - - /* Prepare for next touch reading - power down ADC, enable PENIRQ */ - tsc2007_xfer(tsc, PWRDOWN); - - return 0; -} - -static void tsc2007_work(struct work_struct *work) -{ - struct tsc2007 *ts = - container_of(to_delayed_work(work), struct tsc2007, work); - - if (unlikely(!ts->get_pendown_state() && ts->pendown)) { - struct input_dev *input = ts->input; - - dev_dbg(&ts->client->dev, "UP\n"); - - input_report_key(input, BTN_TOUCH, 0); - input_report_abs(input, ABS_PRESSURE, 0); - input_sync(input); + tc.x, tc.y, rt); + } else if (!ts->get_pendown_state && ts->pendown) { + /* + * We don't have callback to check pendown state, so we + * have to assume that since pressure reported is 0 the + * pen was lifted up. + */ + tsc2007_send_up_event(ts); ts->pendown = false; - enable_irq(ts->irq); - } else { - /* pen is still down, continue with the measurement */ - dev_dbg(&ts->client->dev, "pen is still down\n"); - - tsc2007_read_values(ts); - tsc2007_send_event(ts); + } + out: + if (ts->pendown) schedule_delayed_work(&ts->work, msecs_to_jiffies(TS_POLL_PERIOD)); - } + else + enable_irq(ts->irq); } static irqreturn_t tsc2007_irq(int irq, void *handle) { struct tsc2007 *ts = handle; - if (likely(ts->get_pendown_state())) { + if (!ts->get_pendown_state || likely(ts->get_pendown_state())) { disable_irq_nosync(ts->irq); schedule_delayed_work(&ts->work, msecs_to_jiffies(TS_POLL_DELAY)); @@ -255,7 +269,7 @@ static int __devinit tsc2007_probe(struct i2c_client *client, struct input_dev *input_dev; int err; - if (!pdata || !pdata->get_pendown_state) { + if (!pdata) { dev_err(&client->dev, "platform data is required!\n"); return -EINVAL; } -- cgit v1.2.3-18-g5258 From cf5f439b48f82c230dcd81d0061e00664cbb6d39 Mon Sep 17 00:00:00 2001 From: Richard Röjfors Date: Tue, 4 Aug 2009 22:34:10 -0700 Subject: Input: tsc2007 - check if I2C communication works during probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check the result when sending the power down command to the controller. Signed-off-by: Richard Röjfors Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 3714d19f102..7ef0d1420d3 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -319,15 +319,17 @@ static int __devinit tsc2007_probe(struct i2c_client *client, goto err_free_mem; } + /* Prepare for touch readings - power down ADC and enable PENIRQ */ + err = tsc2007_xfer(ts, PWRDOWN); + if (err < 0) + goto err_free_irq; + err = input_register_device(input_dev); if (err) goto err_free_irq; i2c_set_clientdata(client, ts); - /* Prepare for touch readings - power down ADC and enable PENIRQ */ - tsc2007_xfer(ts, PWRDOWN); - return 0; err_free_irq: -- cgit v1.2.3-18-g5258 From c46dd1eb9a4f1b8c1bb597a75199e3d34fb7b43b Mon Sep 17 00:00:00 2001 From: Paul Fox Date: Wed, 5 Aug 2009 00:30:31 -0700 Subject: Input: hgpk - forced recalibration for the OLPC touchpad The OLPC XO laptop incorporates a combination touchpad/tablet device which unfortunately requires frequent recalibration. The driver will force this automatically when various suspicious behaviors are observed, and the user can recalibrate manually (with a special keyboard sequence). There's currently no way, however, for an external program to cause recalibration. We can not use the reconnect capability which is already available in /sys because full reset of the touchpad takes 1.1 - 1.2 secons which is too long. This patch creates a new node in /sys which, when written with '1', will force a touchpad recalibration; no other writes (or reads) of this node are supported. Signed-off-by: Paul Fox Acked-by: Andres Salomon Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/hgpk.c | 55 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c index a1ad2f1a7bb..f5aa035774d 100644 --- a/drivers/input/mouse/hgpk.c +++ b/drivers/input/mouse/hgpk.c @@ -369,12 +369,46 @@ static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data, __PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL, hgpk_show_powered, hgpk_set_powered, 0); +static ssize_t hgpk_trigger_recal_show(struct psmouse *psmouse, + void *data, char *buf) +{ + return -EINVAL; +} + +static ssize_t hgpk_trigger_recal(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + struct hgpk_data *priv = psmouse->private; + unsigned long value; + int err; + + err = strict_strtoul(buf, 10, &value); + if (err || value != 1) + return -EINVAL; + + /* + * We queue work instead of doing recalibration right here + * to avoid adding locking to to hgpk_force_recalibrate() + * since workqueue provides serialization. + */ + psmouse_queue_work(psmouse, &priv->recalib_wq, 0); + return count; +} + +__PSMOUSE_DEFINE_ATTR(recalibrate, S_IWUSR | S_IRUGO, NULL, + hgpk_trigger_recal_show, hgpk_trigger_recal, 0); + static void hgpk_disconnect(struct psmouse *psmouse) { struct hgpk_data *priv = psmouse->private; device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_powered.dattr); + + if (psmouse->model >= HGPK_MODEL_C) + device_remove_file(&psmouse->ps2dev.serio->dev, + &psmouse_attr_recalibrate.dattr); + psmouse_reset(psmouse); kfree(priv); } @@ -423,10 +457,25 @@ static int hgpk_register(struct psmouse *psmouse) err = device_create_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_powered.dattr); - if (err) - hgpk_err(psmouse, "Failed to create sysfs attribute\n"); + if (err) { + hgpk_err(psmouse, "Failed creating 'powered' sysfs node\n"); + return err; + } - return err; + /* C-series touchpads added the recalibrate command */ + if (psmouse->model >= HGPK_MODEL_C) { + err = device_create_file(&psmouse->ps2dev.serio->dev, + &psmouse_attr_recalibrate.dattr); + if (err) { + hgpk_err(psmouse, + "Failed creating 'recalibrate' sysfs node\n"); + device_remove_file(&psmouse->ps2dev.serio->dev, + &psmouse_attr_powered.dattr); + return err; + } + } + + return 0; } int hgpk_init(struct psmouse *psmouse) -- cgit v1.2.3-18-g5258 From dd0d5443da02b091636e967407805f0b7712fd44 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 5 Aug 2009 00:30:26 -0700 Subject: Input: serio - don't use serio->write() directly We have a nice wrapper for that. Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/hil_kbd.c | 40 +++++++++---------- drivers/input/keyboard/lkkbd.c | 62 +++++++++++++++--------------- drivers/input/keyboard/sunkbd.c | 26 +++++++------ drivers/input/mouse/hil_ptr.c | 32 +++++++-------- drivers/input/mouse/vsxxxaa.c | 8 ++-- drivers/input/touchscreen/h3600_ts_input.c | 9 +++-- 6 files changed, 91 insertions(+), 86 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c index 6f356705ee3..f732893a960 100644 --- a/drivers/input/keyboard/hil_kbd.c +++ b/drivers/input/keyboard/hil_kbd.c @@ -280,28 +280,28 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) init_MUTEX_LOCKED(&kbd->sem); /* Get device info. MLC driver supplies devid/status/etc. */ - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_IDD); + serio_write(serio, 0); + serio_write(serio, 0); + serio_write(serio, HIL_PKT_CMD >> 8); + serio_write(serio, HIL_CMD_IDD); down(&kbd->sem); - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_RSC); + serio_write(serio, 0); + serio_write(serio, 0); + serio_write(serio, HIL_PKT_CMD >> 8); + serio_write(serio, HIL_CMD_RSC); down(&kbd->sem); - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_RNM); + serio_write(serio, 0); + serio_write(serio, 0); + serio_write(serio, HIL_PKT_CMD >> 8); + serio_write(serio, HIL_CMD_RNM); down(&kbd->sem); - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_EXD); + serio_write(serio, 0); + serio_write(serio, 0); + serio_write(serio, HIL_PKT_CMD >> 8); + serio_write(serio, HIL_CMD_EXD); down(&kbd->sem); up(&kbd->sem); @@ -350,10 +350,10 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) printk(KERN_INFO "input: %s, ID: %d\n", kbd->dev->name, did); - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_EK1); /* Enable Keyswitch Autorepeat 1 */ + serio_write(serio, 0); + serio_write(serio, 0); + serio_write(serio, HIL_PKT_CMD >> 8); + serio_write(serio, HIL_CMD_EK1); /* Enable Keyswitch Autorepeat 1 */ down(&kbd->sem); up(&kbd->sem); diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index 4730ef35c73..f9847e0fb55 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c @@ -525,12 +525,12 @@ lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code, CHECK_LED (lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK); CHECK_LED (lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT); if (leds_on != 0) { - lk->serio->write (lk->serio, LK_CMD_LED_ON); - lk->serio->write (lk->serio, leds_on); + serio_write (lk->serio, LK_CMD_LED_ON); + serio_write (lk->serio, leds_on); } if (leds_off != 0) { - lk->serio->write (lk->serio, LK_CMD_LED_OFF); - lk->serio->write (lk->serio, leds_off); + serio_write (lk->serio, LK_CMD_LED_OFF); + serio_write (lk->serio, leds_off); } return 0; @@ -539,20 +539,20 @@ lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code, case SND_CLICK: if (value == 0) { DBG ("%s: Deactivating key clicks\n", __func__); - lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK); - lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK); + serio_write (lk->serio, LK_CMD_DISABLE_KEYCLICK); + serio_write (lk->serio, LK_CMD_DISABLE_CTRCLICK); } else { DBG ("%s: Activating key clicks\n", __func__); - lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK); - lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume)); - lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK); - lk->serio->write (lk->serio, volume_to_hw (lk->ctrlclick_volume)); + serio_write (lk->serio, LK_CMD_ENABLE_KEYCLICK); + serio_write (lk->serio, volume_to_hw (lk->keyclick_volume)); + serio_write (lk->serio, LK_CMD_ENABLE_CTRCLICK); + serio_write (lk->serio, volume_to_hw (lk->ctrlclick_volume)); } return 0; case SND_BELL: if (value != 0) - lk->serio->write (lk->serio, LK_CMD_SOUND_BELL); + serio_write (lk->serio, LK_CMD_SOUND_BELL); return 0; } @@ -579,10 +579,10 @@ lkkbd_reinit (struct work_struct *work) unsigned char leds_off = 0; /* Ask for ID */ - lk->serio->write (lk->serio, LK_CMD_REQUEST_ID); + serio_write (lk->serio, LK_CMD_REQUEST_ID); /* Reset parameters */ - lk->serio->write (lk->serio, LK_CMD_SET_DEFAULTS); + serio_write (lk->serio, LK_CMD_SET_DEFAULTS); /* Set LEDs */ CHECK_LED (lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK); @@ -590,12 +590,12 @@ lkkbd_reinit (struct work_struct *work) CHECK_LED (lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK); CHECK_LED (lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT); if (leds_on != 0) { - lk->serio->write (lk->serio, LK_CMD_LED_ON); - lk->serio->write (lk->serio, leds_on); + serio_write (lk->serio, LK_CMD_LED_ON); + serio_write (lk->serio, leds_on); } if (leds_off != 0) { - lk->serio->write (lk->serio, LK_CMD_LED_OFF); - lk->serio->write (lk->serio, leds_off); + serio_write (lk->serio, LK_CMD_LED_OFF); + serio_write (lk->serio, leds_off); } /* @@ -603,31 +603,31 @@ lkkbd_reinit (struct work_struct *work) * only work with a LK401 keyboard and grants access to * LAlt, RAlt, RCompose and RShift. */ - lk->serio->write (lk->serio, LK_CMD_ENABLE_LK401); + serio_write (lk->serio, LK_CMD_ENABLE_LK401); /* Set all keys to UPDOWN mode */ for (division = 1; division <= 14; division++) - lk->serio->write (lk->serio, LK_CMD_SET_MODE (LK_MODE_UPDOWN, + serio_write (lk->serio, LK_CMD_SET_MODE (LK_MODE_UPDOWN, division)); /* Enable bell and set volume */ - lk->serio->write (lk->serio, LK_CMD_ENABLE_BELL); - lk->serio->write (lk->serio, volume_to_hw (lk->bell_volume)); + serio_write (lk->serio, LK_CMD_ENABLE_BELL); + serio_write (lk->serio, volume_to_hw (lk->bell_volume)); /* Enable/disable keyclick (and possibly set volume) */ if (test_bit (SND_CLICK, lk->dev->snd)) { - lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK); - lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume)); - lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK); - lk->serio->write (lk->serio, volume_to_hw (lk->ctrlclick_volume)); + serio_write (lk->serio, LK_CMD_ENABLE_KEYCLICK); + serio_write (lk->serio, volume_to_hw (lk->keyclick_volume)); + serio_write (lk->serio, LK_CMD_ENABLE_CTRCLICK); + serio_write (lk->serio, volume_to_hw (lk->ctrlclick_volume)); } else { - lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK); - lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK); + serio_write (lk->serio, LK_CMD_DISABLE_KEYCLICK); + serio_write (lk->serio, LK_CMD_DISABLE_CTRCLICK); } /* Sound the bell if needed */ if (test_bit (SND_BELL, lk->dev->snd)) - lk->serio->write (lk->serio, LK_CMD_SOUND_BELL); + serio_write (lk->serio, LK_CMD_SOUND_BELL); } /* @@ -684,8 +684,10 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv) input_dev->keycode = lk->keycode; input_dev->keycodesize = sizeof (lk_keycode_t); input_dev->keycodemax = LK_NUM_KEYCODES; + for (i = 0; i < LK_NUM_KEYCODES; i++) - set_bit (lk->keycode[i], input_dev->keybit); + __set_bit (lk->keycode[i], input_dev->keybit); + __clear_bit(KEY_RESERVED, input_dev->keybit); serio_set_drvdata (serio, lk); @@ -697,7 +699,7 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv) if (err) goto fail3; - lk->serio->write (lk->serio, LK_CMD_POWERCYCLE_RESET); + serio_write (lk->serio, LK_CMD_POWERCYCLE_RESET); return 0; diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index 9fce6d1e29b..e7aa935a294 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -150,8 +150,8 @@ static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int c case EV_LED: - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); - sunkbd->serio->write(sunkbd->serio, + serio_write(sunkbd->serio, SUNKBD_CMD_SETLED); + serio_write(sunkbd->serio, (!!test_bit(LED_CAPSL, dev->led) << 3) | (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_COMPOSE, dev->led) << 1) | !!test_bit(LED_NUML, dev->led)); return 0; @@ -161,11 +161,11 @@ static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int c switch (code) { case SND_CLICK: - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value); + serio_write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value); return 0; case SND_BELL: - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value); + serio_write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value); return 0; } @@ -183,7 +183,7 @@ static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int c static int sunkbd_initialize(struct sunkbd *sunkbd) { sunkbd->reset = -2; - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET); + serio_write(sunkbd->serio, SUNKBD_CMD_RESET); wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); if (sunkbd->reset < 0) return -1; @@ -192,7 +192,7 @@ static int sunkbd_initialize(struct sunkbd *sunkbd) if (sunkbd->type == 4) { /* Type 4 keyboard */ sunkbd->layout = -2; - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_LAYOUT); + serio_write(sunkbd->serio, SUNKBD_CMD_LAYOUT); wait_event_interruptible_timeout(sunkbd->wait, sunkbd->layout >= 0, HZ/4); if (sunkbd->layout < 0) return -1; if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) sunkbd->type = 5; @@ -212,12 +212,14 @@ static void sunkbd_reinit(struct work_struct *work) wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); - sunkbd->serio->write(sunkbd->serio, - (!!test_bit(LED_CAPSL, sunkbd->dev->led) << 3) | (!!test_bit(LED_SCROLLL, sunkbd->dev->led) << 2) | - (!!test_bit(LED_COMPOSE, sunkbd->dev->led) << 1) | !!test_bit(LED_NUML, sunkbd->dev->led)); - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev->snd)); - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd)); + serio_write(sunkbd->serio, SUNKBD_CMD_SETLED); + serio_write(sunkbd->serio, + (!!test_bit(LED_CAPSL, sunkbd->dev->led) << 3) | + (!!test_bit(LED_SCROLLL, sunkbd->dev->led) << 2) | + (!!test_bit(LED_COMPOSE, sunkbd->dev->led) << 1) | + !!test_bit(LED_NUML, sunkbd->dev->led)); + serio_write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev->snd)); + serio_write(sunkbd->serio, SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd)); } static void sunkbd_enable(struct sunkbd *sunkbd, int enable) diff --git a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c index 3263ce083bf..cd12c2d8fa0 100644 --- a/drivers/input/mouse/hil_ptr.c +++ b/drivers/input/mouse/hil_ptr.c @@ -273,28 +273,28 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) init_MUTEX_LOCKED(&ptr->sem); /* Get device info. MLC driver supplies devid/status/etc. */ - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_IDD); + serio_write(serio, 0); + serio_write(serio, 0); + serio_write(serio, HIL_PKT_CMD >> 8); + serio_write(serio, HIL_CMD_IDD); down(&ptr->sem); - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_RSC); + serio_write(serio, 0); + serio_write(serio, 0); + serio_write(serio, HIL_PKT_CMD >> 8); + serio_write(serio, HIL_CMD_RSC); down(&ptr->sem); - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_RNM); + serio_write(serio, 0); + serio_write(serio, 0); + serio_write(serio, HIL_PKT_CMD >> 8); + serio_write(serio, HIL_CMD_RNM); down(&ptr->sem); - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_EXD); + serio_write(serio, 0); + serio_write(serio, 0); + serio_write(serio, HIL_PKT_CMD >> 8); + serio_write(serio, HIL_CMD_EXD); down(&ptr->sem); up(&ptr->sem); diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c index 404eedd5ffa..70111443678 100644 --- a/drivers/input/mouse/vsxxxaa.c +++ b/drivers/input/mouse/vsxxxaa.c @@ -384,11 +384,11 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse) printk (KERN_NOTICE "%s on %s: Forceing standard packet format, " "incremental streaming mode and 72 samples/sec\n", mouse->name, mouse->phys); - mouse->serio->write (mouse->serio, 'S'); /* Standard format */ + serio_write (mouse->serio, 'S'); /* Standard format */ mdelay (50); - mouse->serio->write (mouse->serio, 'R'); /* Incremental */ + serio_write (mouse->serio, 'R'); /* Incremental */ mdelay (50); - mouse->serio->write (mouse->serio, 'L'); /* 72 samples/sec */ + serio_write (mouse->serio, 'L'); /* 72 samples/sec */ } static void @@ -532,7 +532,7 @@ vsxxxaa_connect (struct serio *serio, struct serio_driver *drv) * Request selftest. Standard packet format and differential * mode will be requested after the device ID'ed successfully. */ - serio->write (serio, 'T'); /* Test */ + serio_write (serio, 'T'); /* Test */ err = input_register_device (input_dev); if (err) diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index 4d3139e2099..b4d7f63deff 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -148,9 +148,10 @@ unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr) struct h3600_dev *ts = input_get_drvdata(dev); /* Must be in this order */ - ts->serio->write(ts->serio, 1); - ts->serio->write(ts->serio, pwr); - ts->serio->write(ts->serio, brightness); + serio_write(ts->serio, 1); + serio_write(ts->serio, pwr); + serio_write(ts->serio, brightness); + return 0; } @@ -262,7 +263,7 @@ static int h3600ts_event(struct input_dev *dev, unsigned int type, switch (type) { case EV_LED: { - // ts->serio->write(ts->serio, SOME_CMD); + // serio_write(ts->serio, SOME_CMD); return 0; } } -- cgit v1.2.3-18-g5258 From d76c626b922e279c7764ec46fb1b9bbd41538f35 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 4 Aug 2009 10:52:41 +0000 Subject: cpmac: fix wrong MDIO bus identifier This patch fixes the wrong MDIO bus identifier which was set to 0 unconditionaly, suitable for external switches while it is actually 1 for PHYs different than external switches which are autodetected. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/cpmac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index fd5e32cbcb8..c951dd43f29 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -1109,7 +1109,7 @@ static int external_switch; static int __devinit cpmac_probe(struct platform_device *pdev) { int rc, phy_id; - char *mdio_bus_id = "0"; + char mdio_bus_id[BUS_ID_SIZE]; struct resource *mem; struct cpmac_priv *priv; struct net_device *dev; @@ -1127,7 +1127,7 @@ static int __devinit cpmac_probe(struct platform_device *pdev) if (phy_id == PHY_MAX_ADDR) { if (external_switch || dumb_switch) { - mdio_bus_id = 0; /* fixed phys bus */ + strncpy(mdio_bus_id, "0", BUS_ID_SIZE); /* fixed phys bus */ phy_id = pdev->id; } else { dev_err(&pdev->dev, "no PHY present\n"); @@ -1254,7 +1254,7 @@ int __devinit cpmac_init(void) } cpmac_mii->phy_mask = ~(mask | 0x80000000); - snprintf(cpmac_mii->id, MII_BUS_ID_SIZE, "0"); + snprintf(cpmac_mii->id, MII_BUS_ID_SIZE, "1"); res = mdiobus_register(cpmac_mii); if (res) -- cgit v1.2.3-18-g5258 From 76e61eaa55e33ea51205fad633393d1ae10311c5 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 4 Aug 2009 10:52:52 +0000 Subject: cpmac: add support for fixed PHY This patch adds support for fixed PHY connected in MII mode to cpmac. We allow external and dumb_switch module parameters to override the PHY detection process since they are always connected with MDIO bus identifier 0. This lets fixed PHYs to be detected correctly and be connected to the their corresponding MDIO bus identifier. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/cpmac.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index c951dd43f29..7b311c6d14a 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -1117,22 +1117,23 @@ static int __devinit cpmac_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; - for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) { - if (!(pdata->phy_mask & (1 << phy_id))) - continue; - if (!cpmac_mii->phy_map[phy_id]) - continue; - break; + if (external_switch || dumb_switch) { + strncpy(mdio_bus_id, "0", BUS_ID_SIZE); /* fixed phys bus */ + phy_id = pdev->id; + } else { + for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) { + if (!(pdata->phy_mask & (1 << phy_id))) + continue; + if (!cpmac_mii->phy_map[phy_id]) + continue; + strncpy(mdio_bus_id, cpmac_mii->id, BUS_ID_SIZE); + break; + } } if (phy_id == PHY_MAX_ADDR) { - if (external_switch || dumb_switch) { - strncpy(mdio_bus_id, "0", BUS_ID_SIZE); /* fixed phys bus */ - phy_id = pdev->id; - } else { - dev_err(&pdev->dev, "no PHY present\n"); - return -ENODEV; - } + dev_err(&pdev->dev, "no PHY present\n"); + return -ENODEV; } dev = alloc_etherdev_mq(sizeof(*priv), CPMAC_QUEUES); @@ -1166,8 +1167,11 @@ static int __devinit cpmac_probe(struct platform_device *pdev) priv->msg_enable = netif_msg_init(debug_level, 0xff); memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr)); - priv->phy = phy_connect(dev, dev_name(&cpmac_mii->phy_map[phy_id]->dev), - &cpmac_adjust_link, 0, PHY_INTERFACE_MODE_MII); + snprintf(priv->phy_name, BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id); + + priv->phy = phy_connect(dev, priv->phy_name, &cpmac_adjust_link, 0, + PHY_INTERFACE_MODE_MII); + if (IS_ERR(priv->phy)) { if (netif_msg_drv(priv)) printk(KERN_ERR "%s: Could not attach to PHY\n", -- cgit v1.2.3-18-g5258 From e4540aa94f9b3e75528d9091524e7d82a0650f10 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 4 Aug 2009 10:52:57 +0000 Subject: cpmac: wait longer after MDIO reset This patch slows down the MDIO_ALIVE busy waiting to let switches and PHY come up after reset. Previous loop was too quick for IC+175C and ADM6996C/L switches to come up. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/cpmac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 7b311c6d14a..645e6442dc4 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -1245,11 +1245,11 @@ int __devinit cpmac_init(void) cpmac_mii->reset(cpmac_mii); - for (i = 0; i < 300000; i++) + for (i = 0; i < 300; i++) if ((mask = cpmac_read(cpmac_mii->priv, CPMAC_MDIO_ALIVE))) break; else - cpu_relax(); + msleep(10); mask &= 0x7fffffff; if (mask & (mask - 1)) { -- cgit v1.2.3-18-g5258 From 4e43af323a669a977fcb35f1127c57480ebf7265 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 4 Aug 2009 10:53:00 +0000 Subject: cpmac: bump version to 0.5.1 Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/cpmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 645e6442dc4..3e3fab8afb1 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -54,7 +54,7 @@ module_param(dumb_switch, int, 0444); MODULE_PARM_DESC(debug_level, "Number of NETIF_MSG bits to enable"); MODULE_PARM_DESC(dumb_switch, "Assume switch is not connected to MDIO bus"); -#define CPMAC_VERSION "0.5.0" +#define CPMAC_VERSION "0.5.1" /* frame size + 802.1q tag */ #define CPMAC_SKB_SIZE (ETH_FRAME_LEN + 4) #define CPMAC_QUEUES 8 -- cgit v1.2.3-18-g5258 From 839b04c4aba91dd175f60f45712680126fdc88f7 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 4 Aug 2009 11:17:49 +0000 Subject: cpmac: unmark as broken Starting with version 0.5.1, cpmac is no longer broken. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 5f6509a5f64..9948fa23222 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1774,7 +1774,7 @@ config SC92031 config CPMAC tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)" - depends on NET_ETHERNET && EXPERIMENTAL && AR7 && BROKEN + depends on NET_ETHERNET && EXPERIMENTAL && AR7 select PHYLIB help TI AR7 CPMAC Ethernet support -- cgit v1.2.3-18-g5258 From 545eb370087494dcf267e6285fe3aa20e5617c33 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Wed, 5 Aug 2009 07:34:07 +0000 Subject: netxen: fix vlan tso case Fix the calculation of remaining header length in TSO over vlan device case. This was inadvertently missed out in patch 028afe719855a157e32450c ("netxen: add vlan tx acceleration support"). Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 40549a0e9ff..c91e0224581 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1450,7 +1450,7 @@ netxen_tso_check(struct net_device *netdev, skb_copy_from_linear_data_offset(skb, 12, (char *)vh + 16, copy_len - 16); - copied = copy_len; + copied = copy_len - VLAN_HLEN; offset = 0; producer = get_next_index(producer, tx_ring->num_desc); -- cgit v1.2.3-18-g5258 From 06db58c0cd92e157a4ccf2b6836c9f4b931c7cda Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Wed, 5 Aug 2009 07:34:08 +0000 Subject: netxen: remove unnecessary structures Remove unnecessary offsetof calulations on these structures: netxen_board_info, netxen_user_old_info, netxen_new_user_info. The offsets into the flash are fixed, don't need to be calculated. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 167 ++----------------------------------- drivers/net/netxen/netxen_nic_hw.c | 27 +++--- 2 files changed, 18 insertions(+), 176 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index e22d0861589..bb4aa4f5867 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -441,154 +441,6 @@ struct status_desc { #define NETXEN_BRDTYPE_P3_10G_XFP 0x0032 #define NETXEN_BRDTYPE_P3_10G_TP 0x0080 -struct netxen_board_info { - u32 header_version; - - u32 board_mfg; - u32 board_type; - u32 board_num; - u32 chip_id; - u32 chip_minor; - u32 chip_major; - u32 chip_pkg; - u32 chip_lot; - - u32 port_mask; /* available niu ports */ - u32 peg_mask; /* available pegs */ - u32 icache_ok; /* can we run with icache? */ - u32 dcache_ok; /* can we run with dcache? */ - u32 casper_ok; - - u32 mac_addr_lo_0; - u32 mac_addr_lo_1; - u32 mac_addr_lo_2; - u32 mac_addr_lo_3; - - /* MN-related config */ - u32 mn_sync_mode; /* enable/ sync shift cclk/ sync shift mclk */ - u32 mn_sync_shift_cclk; - u32 mn_sync_shift_mclk; - u32 mn_wb_en; - u32 mn_crystal_freq; /* in MHz */ - u32 mn_speed; /* in MHz */ - u32 mn_org; - u32 mn_depth; - u32 mn_ranks_0; /* ranks per slot */ - u32 mn_ranks_1; /* ranks per slot */ - u32 mn_rd_latency_0; - u32 mn_rd_latency_1; - u32 mn_rd_latency_2; - u32 mn_rd_latency_3; - u32 mn_rd_latency_4; - u32 mn_rd_latency_5; - u32 mn_rd_latency_6; - u32 mn_rd_latency_7; - u32 mn_rd_latency_8; - u32 mn_dll_val[18]; - u32 mn_mode_reg; /* MIU DDR Mode Register */ - u32 mn_ext_mode_reg; /* MIU DDR Extended Mode Register */ - u32 mn_timing_0; /* MIU Memory Control Timing Rgister */ - u32 mn_timing_1; /* MIU Extended Memory Ctrl Timing Register */ - u32 mn_timing_2; /* MIU Extended Memory Ctrl Timing2 Register */ - - /* SN-related config */ - u32 sn_sync_mode; /* enable/ sync shift cclk / sync shift mclk */ - u32 sn_pt_mode; /* pass through mode */ - u32 sn_ecc_en; - u32 sn_wb_en; - u32 sn_crystal_freq; - u32 sn_speed; - u32 sn_org; - u32 sn_depth; - u32 sn_dll_tap; - u32 sn_rd_latency; - - u32 mac_addr_hi_0; - u32 mac_addr_hi_1; - u32 mac_addr_hi_2; - u32 mac_addr_hi_3; - - u32 magic; /* indicates flash has been initialized */ - - u32 mn_rdimm; - u32 mn_dll_override; - -}; - -#define FLASH_NUM_PORTS (4) - -struct netxen_flash_mac_addr { - u32 flash_addr[32]; -}; - -struct netxen_user_old_info { - u8 flash_md5[16]; - u8 crbinit_md5[16]; - u8 brdcfg_md5[16]; - /* bootloader */ - u32 bootld_version; - u32 bootld_size; - u8 bootld_md5[16]; - /* image */ - u32 image_version; - u32 image_size; - u8 image_md5[16]; - /* primary image status */ - u32 primary_status; - u32 secondary_present; - - /* MAC address , 4 ports */ - struct netxen_flash_mac_addr mac_addr[FLASH_NUM_PORTS]; -}; -#define FLASH_NUM_MAC_PER_PORT 32 -struct netxen_user_info { - u8 flash_md5[16 * 64]; - /* bootloader */ - u32 bootld_version; - u32 bootld_size; - /* image */ - u32 image_version; - u32 image_size; - /* primary image status */ - u32 primary_status; - u32 secondary_present; - - /* MAC address , 4 ports, 32 address per port */ - u64 mac_addr[FLASH_NUM_PORTS * FLASH_NUM_MAC_PER_PORT]; - u32 sub_sys_id; - u8 serial_num[32]; - - /* Any user defined data */ -}; - -/* - * Flash Layout - new format. - */ -struct netxen_new_user_info { - u8 flash_md5[16 * 64]; - /* bootloader */ - u32 bootld_version; - u32 bootld_size; - /* image */ - u32 image_version; - u32 image_size; - /* primary image status */ - u32 primary_status; - u32 secondary_present; - - /* MAC address , 4 ports, 32 address per port */ - u64 mac_addr[FLASH_NUM_PORTS * FLASH_NUM_MAC_PER_PORT]; - u32 sub_sys_id; - u8 serial_num[32]; - - /* Any user defined data */ -}; - -#define SECONDARY_IMAGE_PRESENT 0xb3b4b5b6 -#define SECONDARY_IMAGE_ABSENT 0xffffffff -#define PRIMARY_IMAGE_GOOD 0x5a5a5a5a -#define PRIMARY_IMAGE_BAD 0xffffffff - /* Flash memory map */ #define NETXEN_CRBINIT_START 0 /* crbinit section */ #define NETXEN_BRDCFG_START 0x4000 /* board config */ @@ -599,28 +451,25 @@ struct netxen_new_user_info { #define NETXEN_PXE_START 0x3E0000 /* PXE boot rom */ #define NETXEN_USER_START 0x3E8000 /* Firmare info */ #define NETXEN_FIXED_START 0x3F0000 /* backup of crbinit */ +#define NETXEN_USER_START_OLD NETXEN_PXE_START /* very old flash */ +#define NX_OLD_MAC_ADDR_OFFSET (NETXEN_USER_START) #define NX_FW_VERSION_OFFSET (NETXEN_USER_START+0x408) #define NX_FW_SIZE_OFFSET (NETXEN_USER_START+0x40c) +#define NX_FW_MAC_ADDR_OFFSET (NETXEN_USER_START+0x418) +#define NX_FW_SERIAL_NUM_OFFSET (NETXEN_USER_START+0x81c) #define NX_BIOS_VERSION_OFFSET (NETXEN_USER_START+0x83c) + +#define NX_HDR_VERSION_OFFSET (NETXEN_BRDCFG_START) +#define NX_BRDTYPE_OFFSET (NETXEN_BRDCFG_START+0x8) #define NX_FW_MAGIC_OFFSET (NETXEN_BRDCFG_START+0x128) + #define NX_FW_MIN_SIZE (0x3fffff) #define NX_P2_MN_ROMIMAGE 0 #define NX_P3_CT_ROMIMAGE 1 #define NX_P3_MN_ROMIMAGE 2 #define NX_FLASH_ROMIMAGE 3 -#define NETXEN_USER_START_OLD NETXEN_PXE_START /* for backward compatibility */ - -#define NETXEN_FLASH_START (NETXEN_CRBINIT_START) -#define NETXEN_INIT_SECTOR (0) -#define NETXEN_PRIMARY_START (NETXEN_BOOTLD_START) -#define NETXEN_FLASH_CRBINIT_SIZE (0x4000) -#define NETXEN_FLASH_BRDCFG_SIZE (sizeof(struct netxen_board_info)) -#define NETXEN_FLASH_USER_SIZE (sizeof(struct netxen_user_info)/sizeof(u32)) -#define NETXEN_FLASH_SECONDARY_SIZE (NETXEN_USER_START-NETXEN_SECONDARY_START) -#define NETXEN_NUM_PRIMARY_SECTORS (0x20) -#define NETXEN_NUM_CONFIG_SECTORS (1) extern char netxen_nic_driver_name[]; /* Number of status descriptors to handle per interrupt */ diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index ddb9deb12b3..673dcf5ea53 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -816,18 +816,15 @@ int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 *mac) __le32 *pmac = (__le32 *) mac; u32 offset; - offset = NETXEN_USER_START + - offsetof(struct netxen_new_user_info, mac_addr) + - adapter->portnum * sizeof(u64); + offset = NX_FW_MAC_ADDR_OFFSET + (adapter->portnum * sizeof(u64)); if (netxen_get_flash_block(adapter, offset, sizeof(u64), pmac) == -1) return -1; if (*mac == cpu_to_le64(~0ULL)) { - offset = NETXEN_USER_START_OLD + - offsetof(struct netxen_user_old_info, mac_addr) + - adapter->portnum * sizeof(u64); + offset = NX_OLD_MAC_ADDR_OFFSET + + (adapter->portnum * sizeof(u64)); if (netxen_get_flash_block(adapter, offset, sizeof(u64), pmac) == -1) @@ -1857,13 +1854,11 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter) int offset, board_type, magic, header_version; struct pci_dev *pdev = adapter->pdev; - offset = NETXEN_BRDCFG_START + - offsetof(struct netxen_board_info, magic); + offset = NX_FW_MAGIC_OFFSET; if (netxen_rom_fast_read(adapter, offset, &magic)) return -EIO; - offset = NETXEN_BRDCFG_START + - offsetof(struct netxen_board_info, header_version); + offset = NX_HDR_VERSION_OFFSET; if (netxen_rom_fast_read(adapter, offset, &header_version)) return -EIO; @@ -1875,8 +1870,7 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter) return -EIO; } - offset = NETXEN_BRDCFG_START + - offsetof(struct netxen_board_info, board_type); + offset = NX_BRDTYPE_OFFSET; if (netxen_rom_fast_read(adapter, offset, &board_type)) return -EIO; @@ -2022,23 +2016,22 @@ void netxen_nic_get_firmware_info(struct netxen_adapter *adapter) u32 fw_major, fw_minor, fw_build; char brd_name[NETXEN_MAX_SHORT_NAME]; char serial_num[32]; - int i, addr, val; + int i, offset, val; int *ptr32; struct pci_dev *pdev = adapter->pdev; adapter->driver_mismatch = 0; ptr32 = (int *)&serial_num; - addr = NETXEN_USER_START + - offsetof(struct netxen_new_user_info, serial_num); + offset = NX_FW_SERIAL_NUM_OFFSET; for (i = 0; i < 8; i++) { - if (netxen_rom_fast_read(adapter, addr, &val) == -1) { + if (netxen_rom_fast_read(adapter, offset, &val) == -1) { dev_err(&pdev->dev, "error reading board info\n"); adapter->driver_mismatch = 1; return; } ptr32[i] = cpu_to_le32(val); - addr += sizeof(u32); + offset += sizeof(u32); } fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR); -- cgit v1.2.3-18-g5258 From c1c00ab8626298ac784ea344bf10e94b5bd9bcb5 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Wed, 5 Aug 2009 07:34:09 +0000 Subject: netxen: add hardware LRO support Add support to handle aggregate packets from firmware. Local TCP flows are automatically identified by firmware based on the dest IP hash added by driver for local IP addresses. The packets are sent down on the jumbo rx ring. Signed-off-by: Narender Kumar Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 21 ++++++ drivers/net/netxen/netxen_nic_ctx.c | 2 + drivers/net/netxen/netxen_nic_init.c | 124 ++++++++++++++++++++++++++++------- 3 files changed, 125 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index bb4aa4f5867..ae81f7022d2 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -365,6 +365,7 @@ struct rcv_desc { #define NETXEN_NIC_RXPKT_DESC 0x04 #define NETXEN_OLD_RXPKT_DESC 0x3f #define NETXEN_NIC_RESPONSE_DESC 0x05 +#define NETXEN_NIC_LRO_DESC 0x12 /* for status field in status_desc */ #define STATUS_NEED_CKSUM (1) @@ -398,6 +399,24 @@ struct rcv_desc { #define netxen_get_sts_opcode(sts_data) \ (((sts_data) >> 58) & 0x03F) +#define netxen_get_lro_sts_refhandle(sts_data) \ + ((sts_data) & 0x0FFFF) +#define netxen_get_lro_sts_length(sts_data) \ + (((sts_data) >> 16) & 0x0FFFF) +#define netxen_get_lro_sts_l2_hdr_offset(sts_data) \ + (((sts_data) >> 32) & 0x0FF) +#define netxen_get_lro_sts_l4_hdr_offset(sts_data) \ + (((sts_data) >> 40) & 0x0FF) +#define netxen_get_lro_sts_timestamp(sts_data) \ + (((sts_data) >> 48) & 0x1) +#define netxen_get_lro_sts_type(sts_data) \ + (((sts_data) >> 49) & 0x7) +#define netxen_get_lro_sts_push_flag(sts_data) \ + (((sts_data) >> 52) & 0x1) +#define netxen_get_lro_sts_seq_number(sts_data) \ + ((sts_data) & 0x0FFFFFFFF) + + struct status_desc { __le64 status_desc_data[2]; } __attribute__ ((aligned(16))); @@ -712,6 +731,7 @@ struct netxen_recv_context { #define NX_CAP0_LSO NX_CAP_BIT(0, 6) #define NX_CAP0_JUMBO_CONTIGUOUS NX_CAP_BIT(0, 7) #define NX_CAP0_LRO_CONTIGUOUS NX_CAP_BIT(0, 8) +#define NX_CAP0_HW_LRO NX_CAP_BIT(0, 10) /* * Context state @@ -969,6 +989,7 @@ typedef struct { #define NX_FW_CAPABILITY_PEXQ (1 << 7) #define NX_FW_CAPABILITY_BDG (1 << 8) #define NX_FW_CAPABILITY_FVLANTX (1 << 9) +#define NX_FW_CAPABILITY_HW_LRO (1 << 10) /* module types */ #define LINKEVENT_MODULE_NOT_PRESENT 1 diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 9e0469643d3..412d65829d2 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -203,6 +203,8 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter) cap = (NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN); cap |= (NX_CAP0_JUMBO_CONTIGUOUS | NX_CAP0_LRO_CONTIGUOUS); + if (adapter->capabilities & NX_FW_CAPABILITY_HW_LRO) + cap |= NX_CAP0_HW_LRO; prq->capabilities[0] = cpu_to_le32(cap); prq->host_int_crb_mode = diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 81253abbfa3..582828756ef 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1242,20 +1242,31 @@ no_skb: static struct netxen_rx_buffer * netxen_process_rcv(struct netxen_adapter *adapter, - int ring, int index, int length, int cksum, int pkt_offset, - struct nx_host_sds_ring *sds_ring) + struct nx_host_sds_ring *sds_ring, + int ring, u64 sts_data0) { struct net_device *netdev = adapter->netdev; struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; struct netxen_rx_buffer *buffer; struct sk_buff *skb; - struct nx_host_rds_ring *rds_ring = &recv_ctx->rds_rings[ring]; + struct nx_host_rds_ring *rds_ring; + int index, length, cksum, pkt_offset; - if (unlikely(index > rds_ring->num_desc)) + if (unlikely(ring >= adapter->max_rds_rings)) + return NULL; + + rds_ring = &recv_ctx->rds_rings[ring]; + + index = netxen_get_sts_refhandle(sts_data0); + if (unlikely(index >= rds_ring->num_desc)) return NULL; buffer = &rds_ring->rx_buf_arr[index]; + length = netxen_get_sts_totallength(sts_data0); + cksum = netxen_get_sts_status(sts_data0); + pkt_offset = netxen_get_sts_pkt_offset(sts_data0); + skb = netxen_process_rxbuf(adapter, rds_ring, index, cksum); if (!skb) return buffer; @@ -1279,6 +1290,78 @@ netxen_process_rcv(struct netxen_adapter *adapter, return buffer; } +#define TCP_HDR_SIZE 20 +#define TCP_TS_OPTION_SIZE 12 +#define TCP_TS_HDR_SIZE (TCP_HDR_SIZE + TCP_TS_OPTION_SIZE) + +static struct netxen_rx_buffer * +netxen_process_lro(struct netxen_adapter *adapter, + struct nx_host_sds_ring *sds_ring, + int ring, u64 sts_data0, u64 sts_data1) +{ + struct net_device *netdev = adapter->netdev; + struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; + struct netxen_rx_buffer *buffer; + struct sk_buff *skb; + struct nx_host_rds_ring *rds_ring; + struct iphdr *iph; + struct tcphdr *th; + bool push, timestamp; + int l2_hdr_offset, l4_hdr_offset; + int index; + u16 lro_length, length, data_offset; + u32 seq_number; + + if (unlikely(ring > adapter->max_rds_rings)) + return NULL; + + rds_ring = &recv_ctx->rds_rings[ring]; + + index = netxen_get_lro_sts_refhandle(sts_data0); + if (unlikely(index > rds_ring->num_desc)) + return NULL; + + buffer = &rds_ring->rx_buf_arr[index]; + + timestamp = netxen_get_lro_sts_timestamp(sts_data0); + lro_length = netxen_get_lro_sts_length(sts_data0); + l2_hdr_offset = netxen_get_lro_sts_l2_hdr_offset(sts_data0); + l4_hdr_offset = netxen_get_lro_sts_l4_hdr_offset(sts_data0); + push = netxen_get_lro_sts_push_flag(sts_data0); + seq_number = netxen_get_lro_sts_seq_number(sts_data1); + + skb = netxen_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK); + if (!skb) + return buffer; + + if (timestamp) + data_offset = l4_hdr_offset + TCP_TS_HDR_SIZE; + else + data_offset = l4_hdr_offset + TCP_HDR_SIZE; + + skb_put(skb, lro_length + data_offset); + + skb->truesize = (skb->len + sizeof(struct sk_buff) + + ((unsigned long)skb->data - (unsigned long)skb->head)); + + skb_pull(skb, l2_hdr_offset); + skb->protocol = eth_type_trans(skb, netdev); + + iph = (struct iphdr *)skb->data; + th = (struct tcphdr *)(skb->data + (iph->ihl << 2)); + + length = (iph->ihl << 2) + (th->doff << 2) + lro_length; + iph->tot_len = htons(length); + iph->check = 0; + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); + th->psh = push; + th->seq = htonl(seq_number); + + netif_receive_skb(skb); + + return buffer; +} + #define netxen_merge_rx_buffers(list, head) \ do { list_splice_tail_init(list, head); } while (0); @@ -1295,28 +1378,33 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max) u32 consumer = sds_ring->consumer; int count = 0; - u64 sts_data; - int opcode, ring, index, length, cksum, pkt_offset, desc_cnt; + u64 sts_data0, sts_data1; + int opcode, ring = 0, desc_cnt; while (count < max) { desc = &sds_ring->desc_head[consumer]; - sts_data = le64_to_cpu(desc->status_desc_data[0]); + sts_data0 = le64_to_cpu(desc->status_desc_data[0]); - if (!(sts_data & STATUS_OWNER_HOST)) + if (!(sts_data0 & STATUS_OWNER_HOST)) break; - desc_cnt = netxen_get_sts_desc_cnt(sts_data); - ring = netxen_get_sts_type(sts_data); + desc_cnt = netxen_get_sts_desc_cnt(sts_data0); - if (ring > RCV_RING_JUMBO) - goto skip; - - opcode = netxen_get_sts_opcode(sts_data); + opcode = netxen_get_sts_opcode(sts_data0); switch (opcode) { case NETXEN_NIC_RXPKT_DESC: case NETXEN_OLD_RXPKT_DESC: case NETXEN_NIC_SYN_OFFLOAD: + ring = netxen_get_sts_type(sts_data0); + rxbuf = netxen_process_rcv(adapter, sds_ring, + ring, sts_data0); + break; + case NETXEN_NIC_LRO_DESC: + ring = netxen_get_lro_sts_type(sts_data0); + sts_data1 = le64_to_cpu(desc->status_desc_data[1]); + rxbuf = netxen_process_lro(adapter, sds_ring, + ring, sts_data0, sts_data1); break; case NETXEN_NIC_RESPONSE_DESC: netxen_handle_fw_message(desc_cnt, consumer, sds_ring); @@ -1326,14 +1414,6 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max) WARN_ON(desc_cnt > 1); - index = netxen_get_sts_refhandle(sts_data); - length = netxen_get_sts_totallength(sts_data); - cksum = netxen_get_sts_status(sts_data); - pkt_offset = netxen_get_sts_pkt_offset(sts_data); - - rxbuf = netxen_process_rcv(adapter, ring, index, - length, cksum, pkt_offset, sds_ring); - if (rxbuf) list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]); -- cgit v1.2.3-18-g5258 From 14074eab8dcaa7f66d8f52612b2dcec51222bb5f Mon Sep 17 00:00:00 2001 From: sarveshwarb Date: Wed, 5 Aug 2009 13:05:24 -0700 Subject: be2net: Patch to perform function reset at initialization This patch is a bug fix to avoid system going into a bad state when driver is loaded in context of kdump kernel. The patch fixes the issue by performing a soft reset of pci function at probe time. Signed-off-by: sarveshwarb Signed-off-by: David S. Miller --- drivers/net/benet/be_cmds.c | 21 +++++++++++++++++++++ drivers/net/benet/be_cmds.h | 2 ++ drivers/net/benet/be_main.c | 4 ++++ 3 files changed, 27 insertions(+) (limited to 'drivers') diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index de107732dcd..2547ee296a7 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -1019,3 +1019,24 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num) spin_unlock(&adapter->mbox_lock); return status; } + +int be_cmd_reset_function(struct be_adapter *adapter) +{ + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); + struct be_cmd_req_hdr *req = embedded_payload(wrb); + int status; + + spin_lock(&adapter->mbox_lock); + + memset(wrb, 0, sizeof(*wrb)); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + + be_cmd_hdr_prepare(req, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_FUNCTION_RESET, sizeof(*req)); + + status = be_mbox_notify(adapter); + + spin_unlock(&adapter->mbox_lock); + return status; +} diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 5c5de3540d2..70618064ae1 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -135,6 +135,7 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_QUERY_FIRMWARE_CONFIG 58 #define OPCODE_COMMON_NTWK_PMAC_ADD 59 #define OPCODE_COMMON_NTWK_PMAC_DEL 60 +#define OPCODE_COMMON_FUNCTION_RESET 61 #define OPCODE_ETH_ACPI_CONFIG 2 #define OPCODE_ETH_PROMISCUOUS 3 @@ -744,4 +745,5 @@ extern int be_cmd_set_flow_control(struct be_adapter *adapter, extern int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc); extern int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num); +extern int be_cmd_reset_function(struct be_adapter *adapter); extern void be_process_mcc(struct be_adapter *adapter); diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index ef82a52f393..d20235b1680 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1873,6 +1873,10 @@ static int __devinit be_probe(struct pci_dev *pdev, if (status) goto free_netdev; + status = be_cmd_reset_function(adapter); + if (status) + goto ctrl_clean; + status = be_stats_init(adapter); if (status) goto ctrl_clean; -- cgit v1.2.3-18-g5258 From 36e89d73e54c8db79d0fd1636cab9236eea7aae9 Mon Sep 17 00:00:00 2001 From: Lucy Liu Date: Wed, 5 Aug 2009 13:06:34 -0700 Subject: ixgbe: allow vlan egress priority mapping in DCB mode The skb priority to vlan-qos egress mapping that can be configured using set_egress_map with vconfig is overriden by the DCB code in the driver. This patch allows this existing mechanism to work and will increase the configuration flexibility of DCB mode on Linux. A hierarchy of configuration is: 1. Modifies the ixgbe_select_queue() routine for DCB mode to return the priority value from the VLAN tag. It will normally be zero, unless the egress priority map has modified it. This will get packets into the correct queue and result in the queue_mapping field being set correctly. 2. Any tc filter which modifies queue_mapping will be honored, as the filters are handled after the vlan egress map is handled. Signed-off-by: Lucy Liu Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 44adc986282..52d7f19de43 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -5126,7 +5126,7 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb) return smp_processor_id(); if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) - return 0; /* All traffic should default to class 0 */ + return (skb->vlan_tci & IXGBE_TX_FLAGS_VLAN_PRIO_MASK) >> 13; return skb_tx_hash(dev, skb); } -- cgit v1.2.3-18-g5258 From 4403b371888d5947ed08200ee6351441a188a5c7 Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Tue, 4 Aug 2009 10:20:44 +0000 Subject: vxge: don't drop frame on tx queue full The vxge driver will drop a packet in its transmit function if the number of TxDs available hits 0. Instead of doing that, simply stop the transmit queue when transmitting a packet with the last available TxD. Signed-off-by: Benjamin LaHaise Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 335140d2834..beee4ab2ed3 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -895,6 +895,12 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev) goto _exit2; } + /* Last TXD? Stop tx queue to avoid dropping packets. TX + * completion will resume the queue. + */ + if (avail == 1) + vxge_stop_tx_queue(fifo); + status = vxge_hw_fifo_txdl_reserve(fifo_hw, &dtr, &dtr_priv); if (unlikely(status != VXGE_HW_OK)) { vxge_debug_tx(VXGE_ERR, -- cgit v1.2.3-18-g5258 From ff67df55f6bde9de5e508bf1f09509c843accd54 Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Tue, 4 Aug 2009 10:21:03 +0000 Subject: vxge: fix pktgen hangs (don't abuse skb->cb[]) This patch fixes a case in the transmit completion code which was resulting in pktgen hanging at the end of a run. The cause is due to the fact that the ->cb[] area of an skb cannot be used in a network driver's transmit path, as that area belongs to the network protocol. Pktgen hangs, as it sends out the same packet multiple times, and vxge's use of this area of the skb for a temporary list can only add the packet to the temporary list once (while it may be on the queue many times). The fix is to remove this abuse of skb->cb[]. Instead, skb pointers are placed into a temporary stack array, and then free outside of the tx lock. This retains the smp optimization of doing dev_kfree_skb() outside of the tx lock. Signed-off-by: Benjamin LaHaise Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-config.h | 7 ++++-- drivers/net/vxge/vxge-main.c | 53 ++++++++++++++++++++++------------------- drivers/net/vxge/vxge-main.h | 3 ++- drivers/net/vxge/vxge-traffic.c | 7 +++--- drivers/net/vxge/vxge-traffic.h | 2 +- 5 files changed, 40 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h index 224acea771e..62779a520ca 100644 --- a/drivers/net/vxge/vxge-config.h +++ b/drivers/net/vxge/vxge-config.h @@ -978,7 +978,9 @@ struct __vxge_hw_fifo { void *txdlh, enum vxge_hw_fifo_tcode t_code, void *userdata, - void **skb_ptr); + struct sk_buff ***skb_ptr, + int nr_skb, + int *more); void (*txdl_term)( void *txdlh, @@ -1779,7 +1781,8 @@ struct vxge_hw_fifo_attr { void *txdlh, enum vxge_hw_fifo_tcode t_code, void *userdata, - void **skb_ptr); + struct sk_buff ***skb_ptr, + int nr_skb, int *more); void (*txdl_term)( void *txdlh, diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index beee4ab2ed3..4b22513bed4 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -87,22 +87,25 @@ static inline int is_vxge_card_up(struct vxgedev *vdev) static inline void VXGE_COMPLETE_VPATH_TX(struct vxge_fifo *fifo) { unsigned long flags = 0; - struct sk_buff *skb_ptr = NULL; - struct sk_buff **temp, *head, *skb; - - if (spin_trylock_irqsave(&fifo->tx_lock, flags)) { - vxge_hw_vpath_poll_tx(fifo->handle, (void **)&skb_ptr); - spin_unlock_irqrestore(&fifo->tx_lock, flags); - } - /* free SKBs */ - head = skb_ptr; - while (head) { - skb = head; - temp = (struct sk_buff **)&skb->cb; - head = *temp; - *temp = NULL; - dev_kfree_skb_irq(skb); - } + struct sk_buff **skb_ptr = NULL; + struct sk_buff **temp; +#define NR_SKB_COMPLETED 128 + struct sk_buff *completed[NR_SKB_COMPLETED]; + int more; + + do { + more = 0; + skb_ptr = completed; + + if (spin_trylock_irqsave(&fifo->tx_lock, flags)) { + vxge_hw_vpath_poll_tx(fifo->handle, &skb_ptr, + NR_SKB_COMPLETED, &more); + spin_unlock_irqrestore(&fifo->tx_lock, flags); + } + /* free SKBs */ + for (temp = completed; temp != skb_ptr; temp++) + dev_kfree_skb_irq(*temp); + } while (more) ; } static inline void VXGE_COMPLETE_ALL_TX(struct vxgedev *vdev) @@ -600,11 +603,10 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, enum vxge_hw_status vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr, enum vxge_hw_fifo_tcode t_code, void *userdata, - void **skb_ptr) + struct sk_buff ***skb_ptr, int nr_skb, int *more) { struct vxge_fifo *fifo = (struct vxge_fifo *)userdata; - struct sk_buff *skb, *head = NULL; - struct sk_buff **temp; + struct sk_buff *skb, **done_skb = *skb_ptr; int pkt_cnt = 0; vxge_debug_entryexit(VXGE_TRACE, @@ -657,9 +659,12 @@ vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr, fifo->stats.tx_frms++; fifo->stats.tx_bytes += skb->len; - temp = (struct sk_buff **)&skb->cb; - *temp = head; - head = skb; + *done_skb++ = skb; + + if (--nr_skb <= 0) { + *more = 1; + break; + } pkt_cnt++; if (pkt_cnt > fifo->indicate_max_pkts) @@ -668,11 +673,9 @@ vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr, } while (vxge_hw_fifo_txdl_next_completed(fifo_hw, &dtr, &t_code) == VXGE_HW_OK); + *skb_ptr = done_skb; vxge_wake_tx_queue(fifo, skb); - if (skb_ptr) - *skb_ptr = (void *) head; - vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...", fifo->ndev->name, __func__, __LINE__); diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index 18d824c3ab9..8b3989bc707 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -428,7 +428,8 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, enum vxge_hw_status vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr, - enum vxge_hw_fifo_tcode t_code, void *userdata, void **skb_ptr); + enum vxge_hw_fifo_tcode t_code, void *userdata, + struct sk_buff ***skb_ptr, int nr_skbs, int *more); int vxge_close(struct net_device *dev); diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c index 370f55cbbad..c249cd25a5d 100644 --- a/drivers/net/vxge/vxge-traffic.c +++ b/drivers/net/vxge/vxge-traffic.c @@ -2508,7 +2508,8 @@ enum vxge_hw_status vxge_hw_vpath_poll_rx(struct __vxge_hw_ring *ring) * See also: vxge_hw_vpath_poll_tx(). */ enum vxge_hw_status vxge_hw_vpath_poll_tx(struct __vxge_hw_fifo *fifo, - void **skb_ptr) + struct sk_buff ***skb_ptr, int nr_skb, + int *more) { enum vxge_hw_fifo_tcode t_code; void *first_txdlh; @@ -2520,8 +2521,8 @@ enum vxge_hw_status vxge_hw_vpath_poll_tx(struct __vxge_hw_fifo *fifo, status = vxge_hw_fifo_txdl_next_completed(fifo, &first_txdlh, &t_code); if (status == VXGE_HW_OK) - if (fifo->callback(fifo, first_txdlh, - t_code, channel->userdata, skb_ptr) != VXGE_HW_OK) + if (fifo->callback(fifo, first_txdlh, t_code, + channel->userdata, skb_ptr, nr_skb, more) != VXGE_HW_OK) status = VXGE_HW_COMPLETIONS_REMAIN; return status; diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h index 8260b91fd79..461742b4442 100644 --- a/drivers/net/vxge/vxge-traffic.h +++ b/drivers/net/vxge/vxge-traffic.h @@ -2326,7 +2326,7 @@ enum vxge_hw_status vxge_hw_vpath_poll_rx( enum vxge_hw_status vxge_hw_vpath_poll_tx( struct __vxge_hw_fifo *fifoh, - void **skb_ptr); + struct sk_buff ***skb_ptr, int nr_skb, int *more); enum vxge_hw_status vxge_hw_vpath_alarm_process( struct __vxge_hw_vpath_handle *vpath_handle, -- cgit v1.2.3-18-g5258 From ff1b974cf30b282f90993ab658e59b73c152c0b8 Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Tue, 4 Aug 2009 10:21:21 +0000 Subject: vxge: improve tx performance by using mmiowb() instead of wmb() wmb() is extremely heavy on x86. The semantics required in the driver are provided by mmiowb(), so use that and improve tx performance on P4 Xeons by 5-10%. Signed-off-by: Benjamin LaHaise Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-traffic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c index c249cd25a5d..0efb769894e 100644 --- a/drivers/net/vxge/vxge-traffic.c +++ b/drivers/net/vxge/vxge-traffic.c @@ -1070,11 +1070,11 @@ static void __vxge_hw_non_offload_db_post(struct __vxge_hw_fifo *fifo, VXGE_HW_NODBW_GET_NO_SNOOP(no_snoop), &fifo->nofl_db->control_0); - wmb(); + mmiowb(); writeq(txdl_ptr, &fifo->nofl_db->txdl_ptr); - wmb(); + mmiowb(); } /** -- cgit v1.2.3-18-g5258 From 3f23e436d241ac1cf50a659228a5a0e1e6572c1a Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Tue, 4 Aug 2009 10:21:39 +0000 Subject: vxge: prefetch RxD descriptors This patch prefetches RxD descriptors which helps to lower the latency of a cache miss in vxge_hw_ring_rxd_next_completed. This lowers the % of CPU time used by vxge_hw_ring_rxd_next_completed() where the descriptor is accessed in profiling netperf on a P4 Xeon from 1.5% to 1.0%. Signed-off-by: Benjamin LaHaise Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-main.c | 1 + drivers/net/vxge/vxge-traffic.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 4b22513bed4..e93651c19f5 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -445,6 +445,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, vxge_hw_ring_replenish(ringh, 0); do { + prefetch((char *)dtr + L1_CACHE_BYTES); rx_priv = vxge_hw_ring_rxd_private_get(dtr); skb = rx_priv->skb; data_size = rx_priv->data_size; diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c index 0efb769894e..fe3ae518c69 100644 --- a/drivers/net/vxge/vxge-traffic.c +++ b/drivers/net/vxge/vxge-traffic.c @@ -731,6 +731,7 @@ vxge_hw_channel_dtr_try_complete(struct __vxge_hw_channel *channel, void **dtrh) vxge_assert(channel->compl_index < channel->length); *dtrh = channel->work_arr[channel->compl_index]; + prefetch(*dtrh); } /* -- cgit v1.2.3-18-g5258 From ea11bbe0c94b045fdefc05476b69a2eef999a9c4 Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Tue, 4 Aug 2009 10:21:57 +0000 Subject: vxge: prefetch skb->data This patch implements prefetching of skb->data from a copy of the pointer in the descriptor (which is already in the L1 cache at this point). This improves netperf rx performance (netperf -L 0,0 -c -H 192.168.254.2 -- -M 131072 -m 131072) by 4.9% on a P4 Xeon host. Signed-off-by: Benjamin LaHaise Signed-off-by: Sreenivasa Honnur Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-main.c | 6 +++++- drivers/net/vxge/vxge-main.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index e93651c19f5..094d15548a2 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -286,6 +286,7 @@ vxge_rx_alloc(void *dtrh, struct vxge_ring *ring, const int skb_size) skb_reserve(skb, VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN); rx_priv->skb = skb; + rx_priv->skb_data = NULL; rx_priv->data_size = skb_size; vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__); @@ -305,7 +306,8 @@ static int vxge_rx_map(void *dtrh, struct vxge_ring *ring) ring->ndev->name, __func__, __LINE__); rx_priv = vxge_hw_ring_rxd_private_get(dtrh); - dma_addr = pci_map_single(ring->pdev, rx_priv->skb->data, + rx_priv->skb_data = rx_priv->skb->data; + dma_addr = pci_map_single(ring->pdev, rx_priv->skb_data, rx_priv->data_size, PCI_DMA_FROMDEVICE); if (dma_addr == 0) { @@ -450,6 +452,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, skb = rx_priv->skb; data_size = rx_priv->data_size; data_dma = rx_priv->data_dma; + prefetch(rx_priv->skb_data); vxge_debug_rx(VXGE_TRACE, "%s: %s:%d skb = 0x%p", @@ -1056,6 +1059,7 @@ vxge_rx_term(void *dtrh, enum vxge_hw_rxd_state state, void *userdata) rx_priv->data_size, PCI_DMA_FROMDEVICE); dev_kfree_skb(rx_priv->skb); + rx_priv->skb_data = NULL; vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...", diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index 8b3989bc707..9c36b3a9a63 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -378,6 +378,7 @@ struct vxgedev { struct vxge_rx_priv { struct sk_buff *skb; + unsigned char *skb_data; dma_addr_t data_dma; dma_addr_t data_size; }; -- cgit v1.2.3-18-g5258 From cc104e52b4f61dbfe1a815f775ffb2fbbb4b785d Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Tue, 4 Aug 2009 10:22:19 +0000 Subject: vxge: Version update Update the driver version number for any bug reports from end users. Signed-off-by: Benjamin LaHaise Signed-off-by: Ramkrishna Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h index 580c6eb077b..8fbce755203 100644 --- a/drivers/net/vxge/vxge-version.h +++ b/drivers/net/vxge/vxge-version.h @@ -17,7 +17,7 @@ #define VXGE_VERSION_MAJOR "2" #define VXGE_VERSION_MINOR "0" -#define VXGE_VERSION_FIX "4" -#define VXGE_VERSION_BUILD "17899" +#define VXGE_VERSION_FIX "5" +#define VXGE_VERSION_BUILD "18053" #define VXGE_VERSION_FOR "k" #endif -- cgit v1.2.3-18-g5258 From 9073e3a32bb249293edc01ecff575bb87380c068 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 5 Aug 2009 20:28:27 -0700 Subject: cxgb3: fix 2 ports 1G regression commit 88045b3cf0f8981129cb489c7b6bc36c21dd33a7 cxgb3: fix mac index mapping Override the mac index computation for the gen2 adapter, as each port is expected to use index 0. introduces a regression on 2 port 1G adapter as its xauicfg vpd value is null. Add a check on the device id. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller --- drivers/net/cxgb3/t3_hw.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 526e144b8b7..032cfe06557 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -3692,8 +3692,12 @@ static void mc7_prep(struct adapter *adapter, struct mc7 *mc7, void mac_prep(struct cmac *mac, struct adapter *adapter, int index) { + u16 devid; + mac->adapter = adapter; - if (!adapter->params.vpd.xauicfg[1]) + pci_read_config_word(adapter->pdev, 0x2, &devid); + + if (devid == 0x37 && !adapter->params.vpd.xauicfg[1]) index = 0; mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index; mac->nucast = 1; -- cgit v1.2.3-18-g5258 From 297713decac17527d3583fcd4d18564568cac759 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Thu, 6 Aug 2009 04:41:45 +0000 Subject: tc35815: Disable StripCRC It seems Rx_StripCRC cause trouble on recovering from the BLEx (Buffer List Exhaust) or FDAEx (Free Descriptor Area Exhaust) condition. Do not use it. Also bump version number up. Reported-by: Ralf Roesch Signed-off-by: Atsushi Nemoto Signed-off-by: David S. Miller --- drivers/net/tc35815.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index 1ce2da172ca..a7581632f81 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -23,9 +23,9 @@ */ #ifdef TC35815_NAPI -#define DRV_VERSION "1.37-NAPI" +#define DRV_VERSION "1.38-NAPI" #else -#define DRV_VERSION "1.37" +#define DRV_VERSION "1.38" #endif static const char *version = "tc35815.c:v" DRV_VERSION "\n"; #define MODNAME "tc35815" @@ -341,8 +341,9 @@ struct BDesc { Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \ Tx_En) /* maybe 0x7b01 */ #endif +/* Do not use Rx_StripCRC -- it causes trouble on BLEx/FDAEx condition */ #define RX_CTL_CMD (Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \ - | Rx_EnCRCErr | Rx_EnAlign | Rx_StripCRC | Rx_RxEn) /* maybe 0x6f11 */ + | Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn) /* maybe 0x6f01 */ #define INT_EN_CMD (Int_NRAbtEn | \ Int_DmParErrEn | Int_DParDEn | Int_DParErrEn | \ Int_SSysErrEn | Int_RMasAbtEn | Int_RTargAbtEn | \ -- cgit v1.2.3-18-g5258 From db30f5ef6e4471fd55671382b8870fdd61e35814 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Thu, 6 Aug 2009 04:41:46 +0000 Subject: tc35815: Improve BLEx / FDAEx handling Clear Int_BLEx / Int_FDAEx after (not before) processing Rx interrupt. This will reduce number of unnecessary interrupts. Also print rx error messages only if netif_msg_rx_err() enabled. Signed-off-by: Atsushi Nemoto Signed-off-by: David S. Miller --- drivers/net/tc35815.c | 60 ++++++++++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index a7581632f81..62965d6665d 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -1541,8 +1541,6 @@ static int tc35815_do_interrupt(struct net_device *dev, u32 status) #endif { struct tc35815_local *lp = netdev_priv(dev); - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; int ret = -1; /* Fatal errors... */ @@ -1552,27 +1550,26 @@ static int tc35815_do_interrupt(struct net_device *dev, u32 status) } /* recoverable errors */ if (status & Int_IntFDAEx) { - /* disable FDAEx int. (until we make rooms...) */ - tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En); - printk(KERN_WARNING - "%s: Free Descriptor Area Exhausted (%#x).\n", - dev->name, status); + if (netif_msg_rx_err(lp)) + dev_warn(&dev->dev, + "Free Descriptor Area Exhausted (%#x).\n", + status); dev->stats.rx_dropped++; ret = 0; } if (status & Int_IntBLEx) { - /* disable BLEx int. (until we make rooms...) */ - tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En); - printk(KERN_WARNING - "%s: Buffer List Exhausted (%#x).\n", - dev->name, status); + if (netif_msg_rx_err(lp)) + dev_warn(&dev->dev, + "Buffer List Exhausted (%#x).\n", + status); dev->stats.rx_dropped++; ret = 0; } if (status & Int_IntExBD) { - printk(KERN_WARNING - "%s: Excessive Buffer Descriptiors (%#x).\n", - dev->name, status); + if (netif_msg_rx_err(lp)) + dev_warn(&dev->dev, + "Excessive Buffer Descriptiors (%#x).\n", + status); dev->stats.rx_length_errors++; ret = 0; } @@ -1631,8 +1628,12 @@ static irqreturn_t tc35815_interrupt(int irq, void *dev_id) spin_lock(&lp->lock); status = tc_readl(&tr->Int_Src); - tc_writel(status, &tr->Int_Src); /* write to clear */ + /* BLEx, FDAEx will be cleared later */ + tc_writel(status & ~(Int_BLEx | Int_FDAEx), + &tr->Int_Src); /* write to clear */ handled = tc35815_do_interrupt(dev, status); + if (status & (Int_BLEx | Int_FDAEx)) + tc_writel(status & (Int_BLEx | Int_FDAEx), &tr->Int_Src); (void)tc_readl(&tr->Int_Src); /* flush */ spin_unlock(&lp->lock); return IRQ_RETVAL(handled >= 0); @@ -1660,8 +1661,6 @@ tc35815_rx(struct net_device *dev) struct tc35815_local *lp = netdev_priv(dev); unsigned int fdctl; int i; - int buf_free_count = 0; - int fd_free_count = 0; #ifdef TC35815_NAPI int received = 0; #endif @@ -1770,8 +1769,9 @@ tc35815_rx(struct net_device *dev) dev->stats.rx_bytes += pkt_len; } else { dev->stats.rx_errors++; - printk(KERN_DEBUG "%s: Rx error (status %x)\n", - dev->name, status & Rx_Stat_Mask); + if (netif_msg_rx_err(lp)) + dev_info(&dev->dev, "Rx error (status %x)\n", + status & Rx_Stat_Mask); /* WORKAROUND: LongErr and CRCErr means Overflow. */ if ((status & Rx_LongErr) && (status & Rx_CRCErr)) { status &= ~(Rx_LongErr|Rx_CRCErr); @@ -1849,7 +1849,6 @@ tc35815_rx(struct net_device *dev) #else lp->fbl_count++; #endif - buf_free_count++; } } @@ -1871,7 +1870,6 @@ tc35815_rx(struct net_device *dev) #endif lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD); lp->rfd_cur++; - fd_free_count++; } if (lp->rfd_cur > lp->rfd_limit) lp->rfd_cur = lp->rfd_base; @@ -1882,17 +1880,6 @@ tc35815_rx(struct net_device *dev) #endif } - /* re-enable BL/FDA Exhaust interrupts. */ - if (fd_free_count) { - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; - u32 en, en_old = tc_readl(&tr->Int_En); - en = en_old | Int_FDAExEn; - if (buf_free_count) - en |= Int_BLExEn; - if (en != en_old) - tc_writel(en, &tr->Int_En); - } #ifdef TC35815_NAPI return received; #endif @@ -1911,9 +1898,14 @@ static int tc35815_poll(struct napi_struct *napi, int budget) spin_lock(&lp->lock); status = tc_readl(&tr->Int_Src); do { - tc_writel(status, &tr->Int_Src); /* write to clear */ + /* BLEx, FDAEx will be cleared later */ + tc_writel(status & ~(Int_BLEx | Int_FDAEx), + &tr->Int_Src); /* write to clear */ handled = tc35815_do_interrupt(dev, status, budget - received); + if (status & (Int_BLEx | Int_FDAEx)) + tc_writel(status & (Int_BLEx | Int_FDAEx), + &tr->Int_Src); if (handled >= 0) { received += handled; if (received >= budget) -- cgit v1.2.3-18-g5258 From c60a5cf7af0a94cf8b09ca22796affa5f5f0669a Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Thu, 6 Aug 2009 04:41:47 +0000 Subject: tc35815: Increase timeout for mdio The current timeout value is too short for very high-load condition which jiffies might jump up in busy-loop. Also add minimum delay before checking completion of MDIO. Signed-off-by: Atsushi Nemoto Signed-off-by: David S. Miller --- drivers/net/tc35815.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index 62965d6665d..f42aaf72cc9 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -594,9 +594,10 @@ static int tc_mdio_read(struct mii_bus *bus, int mii_id, int regnum) struct net_device *dev = bus->priv; struct tc35815_regs __iomem *tr = (struct tc35815_regs __iomem *)dev->base_addr; - unsigned long timeout = jiffies + 10; + unsigned long timeout = jiffies + HZ; tc_writel(MD_CA_Busy | (mii_id << 5) | (regnum & 0x1f), &tr->MD_CA); + udelay(12); /* it takes 32 x 400ns at least */ while (tc_readl(&tr->MD_CA) & MD_CA_Busy) { if (time_after(jiffies, timeout)) return -EIO; @@ -610,11 +611,12 @@ static int tc_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 val) struct net_device *dev = bus->priv; struct tc35815_regs __iomem *tr = (struct tc35815_regs __iomem *)dev->base_addr; - unsigned long timeout = jiffies + 10; + unsigned long timeout = jiffies + HZ; tc_writel(val, &tr->MD_Data); tc_writel(MD_CA_Busy | MD_CA_Wr | (mii_id << 5) | (regnum & 0x1f), &tr->MD_CA); + udelay(12); /* it takes 32 x 400ns at least */ while (tc_readl(&tr->MD_CA) & MD_CA_Busy) { if (time_after(jiffies, timeout)) return -EIO; -- cgit v1.2.3-18-g5258 From 7bb82e834cc9cc95512287a9bf637719557674a0 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Thu, 6 Aug 2009 04:41:48 +0000 Subject: tc35815: Fix rx_missed_errors count The Miss_Cnt register is cleared by reading. Accumulate its value to rx_missed_errors count. Signed-off-by: Atsushi Nemoto Signed-off-by: David S. Miller --- drivers/net/tc35815.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index f42aaf72cc9..411cc0e5f7a 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -2139,7 +2139,7 @@ static struct net_device_stats *tc35815_get_stats(struct net_device *dev) (struct tc35815_regs __iomem *)dev->base_addr; if (netif_running(dev)) /* Update the statistics from the device registers. */ - dev->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt); + dev->stats.rx_missed_errors += tc_readl(&tr->Miss_Cnt); return &dev->stats; } -- cgit v1.2.3-18-g5258 From a48ec346fcb095f6a0e74a57165f9a9a3b23b95a Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Thu, 6 Aug 2009 04:41:49 +0000 Subject: tc35815: Use 0 RxFragSize.MinFrag value for non-packing mode The datasheet say "When not enabling packing, the MinFrag value must remain at 0". Do not set value to RxFragSize register if TC35815_USE_PACKEDBUFFER disabled. This is not a bugfix. No real problem reported on this. Signed-off-by: Atsushi Nemoto Signed-off-by: David S. Miller --- drivers/net/tc35815.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index 411cc0e5f7a..d1298e5b72c 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -2394,8 +2394,6 @@ static void tc35815_chip_init(struct net_device *dev) tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl); #ifdef TC35815_USE_PACKEDBUFFER tc_writel(RxFrag_EnPack | ETH_ZLEN, &tr->RxFragSize); /* Packing */ -#else - tc_writel(ETH_ZLEN, &tr->RxFragSize); #endif tc_writel(0, &tr->TxPollCtr); /* Batch mode */ tc_writel(TX_THRESHOLD, &tr->TxThrsh); -- cgit v1.2.3-18-g5258 From 6cb87823627699b0267234a210d8199b681c70e3 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 5 Aug 2009 08:29:31 +0000 Subject: net: smsc911x: switch to new dev_pm_ops Hibernation is unsupported for now, which meets the actual implementation in the driver. For free/thaw, the chip's D2 state should be entered. Signed-off-by: Daniel Mack Acked-by: Signed-off-by: David S. Miller --- drivers/net/smsc911x.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index 94b6d2658dd..c2667855a00 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -50,6 +50,7 @@ #include #include #include +#include #include "smsc911x.h" #define SMSC_CHIPNAME "smsc911x" @@ -2114,10 +2115,12 @@ out_0: /* This implementation assumes the devices remains powered on its VDDVARIO * pins during suspend. */ -static int smsc911x_suspend(struct platform_device *pdev, pm_message_t state) +/* TODO: implement freeze/thaw callbacks for hibernation.*/ + +static int smsc911x_suspend(struct device *dev) { - struct net_device *dev = platform_get_drvdata(pdev); - struct smsc911x_data *pdata = netdev_priv(dev); + struct net_device *ndev = dev_get_drvdata(dev); + struct smsc911x_data *pdata = netdev_priv(ndev); /* enable wake on LAN, energy detection and the external PME * signal. */ @@ -2128,10 +2131,10 @@ static int smsc911x_suspend(struct platform_device *pdev, pm_message_t state) return 0; } -static int smsc911x_resume(struct platform_device *pdev) +static int smsc911x_resume(struct device *dev) { - struct net_device *dev = platform_get_drvdata(pdev); - struct smsc911x_data *pdata = netdev_priv(dev); + struct net_device *ndev = dev_get_drvdata(dev); + struct smsc911x_data *pdata = netdev_priv(ndev); unsigned int to = 100; /* Note 3.11 from the datasheet: @@ -2149,19 +2152,25 @@ static int smsc911x_resume(struct platform_device *pdev) return (to == 0) ? -EIO : 0; } +static struct dev_pm_ops smsc911x_pm_ops = { + .suspend = smsc911x_suspend, + .resume = smsc911x_resume, +}; + +#define SMSC911X_PM_OPS (&smsc911x_pm_ops) + #else -#define smsc911x_suspend NULL -#define smsc911x_resume NULL +#define SMSC911X_PM_OPS NULL #endif static struct platform_driver smsc911x_driver = { .probe = smsc911x_drv_probe, .remove = __devexit_p(smsc911x_drv_remove), .driver = { - .name = SMSC_CHIPNAME, + .name = SMSC_CHIPNAME, + .owner = THIS_MODULE, + .pm = SMSC911X_PM_OPS, }, - .suspend = smsc911x_suspend, - .resume = smsc911x_resume, }; /* Entry point for loading the module */ -- cgit v1.2.3-18-g5258 From a35ee541a66d11d26da30d3f6046dbddd073334e Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Thu, 6 Aug 2009 19:27:28 -0700 Subject: mlx4_en: Adaptive moderation policy change If the net device is identified as "sender" (number of sent packets is higher then the number of received packets and the incoming packets are small), set the moderation time to its low limit. We do it because the incoming packets are acks, and we don't want to delay them Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/net/mlx4/en_netdev.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 93f4abd990a..c8a24dcca76 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -414,6 +414,7 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) unsigned long avg_pkt_size; unsigned long rx_packets; unsigned long rx_bytes; + unsigned long rx_byte_diff; unsigned long tx_packets; unsigned long tx_pkt_diff; unsigned long rx_pkt_diff; @@ -437,6 +438,8 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) rx_pkt_diff = ((unsigned long) (rx_packets - priv->last_moder_packets)); packets = max(tx_pkt_diff, rx_pkt_diff); + rx_byte_diff = rx_bytes - priv->last_moder_bytes; + rx_byte_diff = rx_byte_diff ? rx_byte_diff : 1; rate = packets * HZ / period; avg_pkt_size = packets ? ((unsigned long) (rx_bytes - priv->last_moder_bytes)) / packets : 0; @@ -447,10 +450,13 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) /* If tx and rx packet rates are not balanced, assume that * traffic is mainly BW bound and apply maximum moderation. * Otherwise, moderate according to packet rate */ - if (2 * tx_pkt_diff > 3 * rx_pkt_diff || - 2 * rx_pkt_diff > 3 * tx_pkt_diff) { + if (2 * tx_pkt_diff > 3 * rx_pkt_diff && + rx_pkt_diff / rx_byte_diff < + MLX4_EN_SMALL_PKT_SIZE) + moder_time = priv->rx_usecs_low; + else if (2 * rx_pkt_diff > 3 * tx_pkt_diff) moder_time = priv->rx_usecs_high; - } else { + else { if (rate < priv->pkt_rate_low) moder_time = priv->rx_usecs_low; else if (rate > priv->pkt_rate_high) -- cgit v1.2.3-18-g5258 From b6b912e0804dc1b3e856da3cc82fbe78b50e968c Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Thu, 6 Aug 2009 19:27:51 -0700 Subject: mlx4_en: Using real number of rings as RSS map size There is no point in using more QPs then actual number of receive rings. If the RSS function for two streams gives the same result modulo number of rings, they will arrive to the same RX ring anyway. Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/net/mlx4/en_main.c | 5 +++-- drivers/net/mlx4/en_netdev.c | 3 --- drivers/net/mlx4/en_rx.c | 38 +++++++++++--------------------------- drivers/net/mlx4/mlx4_en.h | 11 ++--------- 4 files changed, 16 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c index 9ed4a158f89..507e11fce9e 100644 --- a/drivers/net/mlx4/en_main.c +++ b/drivers/net/mlx4/en_main.c @@ -218,8 +218,9 @@ static void *mlx4_en_add(struct mlx4_dev *dev) mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { mlx4_info(mdev, "Using %d tx rings for port:%d\n", mdev->profile.prof[i].tx_ring_num, i); - mdev->profile.prof[i].rx_ring_num = - min_t(int, dev->caps.num_comp_vectors, MAX_RX_RINGS); + mdev->profile.prof[i].rx_ring_num = min_t(int, + roundup_pow_of_two(dev->caps.num_comp_vectors), + MAX_RX_RINGS); mlx4_info(mdev, "Defaulting to %d rx rings for port:%d\n", mdev->profile.prof[i].rx_ring_num, i); } diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index c8a24dcca76..f8bbc5a39e1 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -1011,9 +1011,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, if (err) goto out; - /* Populate Rx default RSS mappings */ - mlx4_en_set_default_rss_map(priv, &priv->rss_map, priv->rx_ring_num * - RSS_FACTOR, priv->rx_ring_num); /* Allocate page for receive rings */ err = mlx4_alloc_hwq_res(mdev->dev, &priv->res, MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE); diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 91bdfdfd431..47b178e2b49 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -835,23 +835,6 @@ void mlx4_en_calc_rx_buf(struct net_device *dev) /* RSS related functions */ -/* Calculate rss size and map each entry in rss table to rx ring */ -void mlx4_en_set_default_rss_map(struct mlx4_en_priv *priv, - struct mlx4_en_rss_map *rss_map, - int num_entries, int num_rings) -{ - int i; - - rss_map->size = roundup_pow_of_two(num_entries); - en_dbg(DRV, priv, "Setting default RSS map of %d entires\n", - rss_map->size); - - for (i = 0; i < rss_map->size; i++) { - rss_map->map[i] = i % num_rings; - en_dbg(DRV, priv, "Entry %d ---> ring %d\n", i, rss_map->map[i]); - } -} - static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn, int srqn, int cqn, enum mlx4_qp_state *state, @@ -902,16 +885,17 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) int good_qps = 0; en_dbg(DRV, priv, "Configuring rss steering\n"); - err = mlx4_qp_reserve_range(mdev->dev, rss_map->size, - rss_map->size, &rss_map->base_qpn); + err = mlx4_qp_reserve_range(mdev->dev, priv->rx_ring_num, + priv->rx_ring_num, + &rss_map->base_qpn); if (err) { - en_err(priv, "Failed reserving %d qps\n", rss_map->size); + en_err(priv, "Failed reserving %d qps\n", priv->rx_ring_num); return err; } - for (i = 0; i < rss_map->size; i++) { - cqn = priv->rx_ring[rss_map->map[i]].cqn; - srqn = priv->rx_ring[rss_map->map[i]].srq.srqn; + for (i = 0; i < priv->rx_ring_num; i++) { + cqn = priv->rx_ring[i].cqn; + srqn = priv->rx_ring[i].srq.srqn; qpn = rss_map->base_qpn + i; err = mlx4_en_config_rss_qp(priv, qpn, srqn, cqn, &rss_map->state[i], @@ -940,7 +924,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) ptr = ((void *) &context) + 0x3c; rss_context = (struct mlx4_en_rss_context *) ptr; - rss_context->base_qpn = cpu_to_be32(ilog2(rss_map->size) << 24 | + rss_context->base_qpn = cpu_to_be32(ilog2(priv->rx_ring_num) << 24 | (rss_map->base_qpn)); rss_context->default_qpn = cpu_to_be32(rss_map->base_qpn); rss_context->hash_fn = rss_xor & 0x3; @@ -967,7 +951,7 @@ rss_err: mlx4_qp_remove(mdev->dev, &rss_map->qps[i]); mlx4_qp_free(mdev->dev, &rss_map->qps[i]); } - mlx4_qp_release_range(mdev->dev, rss_map->base_qpn, rss_map->size); + mlx4_qp_release_range(mdev->dev, rss_map->base_qpn, priv->rx_ring_num); return err; } @@ -983,13 +967,13 @@ void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv) mlx4_qp_free(mdev->dev, &rss_map->indir_qp); mlx4_qp_release_range(mdev->dev, priv->base_qpn, 1); - for (i = 0; i < rss_map->size; i++) { + for (i = 0; i < priv->rx_ring_num; i++) { mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->qps[i]); mlx4_qp_remove(mdev->dev, &rss_map->qps[i]); mlx4_qp_free(mdev->dev, &rss_map->qps[i]); } - mlx4_qp_release_range(mdev->dev, rss_map->base_qpn, rss_map->size); + mlx4_qp_release_range(mdev->dev, rss_map->base_qpn, priv->rx_ring_num); } diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index c7c5e86804f..2d76ff4c564 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -95,8 +95,6 @@ #define MLX4_EN_PAGE_SIZE (1 << MLX4_EN_PAGE_SHIFT) #define MAX_TX_RINGS 16 #define MAX_RX_RINGS 16 -#define MAX_RSS_MAP_SIZE 64 -#define RSS_FACTOR 2 #define TXBB_SIZE 64 #define HEADROOM (2048 / TXBB_SIZE + 1) #define STAMP_STRIDE 64 @@ -377,11 +375,9 @@ struct mlx4_en_dev { struct mlx4_en_rss_map { - int size; int base_qpn; - u16 map[MAX_RSS_MAP_SIZE]; - struct mlx4_qp qps[MAX_RSS_MAP_SIZE]; - enum mlx4_qp_state state[MAX_RSS_MAP_SIZE]; + struct mlx4_qp qps[MAX_RX_RINGS]; + enum mlx4_qp_state state[MAX_RX_RINGS]; struct mlx4_qp indir_qp; enum mlx4_qp_state indir_state; }; @@ -555,9 +551,6 @@ int mlx4_en_map_buffer(struct mlx4_buf *buf); void mlx4_en_unmap_buffer(struct mlx4_buf *buf); void mlx4_en_calc_rx_buf(struct net_device *dev); -void mlx4_en_set_default_rss_map(struct mlx4_en_priv *priv, - struct mlx4_en_rss_map *rss_map, - int num_entries, int num_rings); int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv); void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv); int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring); -- cgit v1.2.3-18-g5258 From 9f519f68cfffba022978634f724944a0b971fec1 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Thu, 6 Aug 2009 19:28:18 -0700 Subject: mlx4_en: Not using Shared Receive Queues We use 1:1 mapping between QPs and SRQs on receive side, so additional indirection level not required. Allocated the receive buffers for the RSS QPs. Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/net/mlx4/en_netdev.c | 3 +- drivers/net/mlx4/en_resources.c | 9 +++-- drivers/net/mlx4/en_rx.c | 77 +++++++++-------------------------------- drivers/net/mlx4/en_tx.c | 4 +-- drivers/net/mlx4/mlx4_en.h | 6 ++-- 5 files changed, 26 insertions(+), 73 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index f8bbc5a39e1..c48b0f4b17b 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -622,8 +622,7 @@ int mlx4_en_start_port(struct net_device *dev) /* Configure ring */ tx_ring = &priv->tx_ring[i]; - err = mlx4_en_activate_tx_ring(priv, tx_ring, cq->mcq.cqn, - priv->rx_ring[0].srq.srqn); + err = mlx4_en_activate_tx_ring(priv, tx_ring, cq->mcq.cqn); if (err) { en_err(priv, "Failed allocating Tx ring\n"); mlx4_en_deactivate_cq(priv, cq); diff --git a/drivers/net/mlx4/en_resources.c b/drivers/net/mlx4/en_resources.c index 65ca706c04b..16256784a94 100644 --- a/drivers/net/mlx4/en_resources.c +++ b/drivers/net/mlx4/en_resources.c @@ -37,7 +37,7 @@ #include "mlx4_en.h" void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, - int is_tx, int rss, int qpn, int cqn, int srqn, + int is_tx, int rss, int qpn, int cqn, struct mlx4_qp_context *context) { struct mlx4_en_dev *mdev = priv->mdev; @@ -46,11 +46,12 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, context->flags = cpu_to_be32(7 << 16 | rss << 13); context->pd = cpu_to_be32(mdev->priv_pdn); context->mtu_msgmax = 0xff; - context->rq_size_stride = 0; + if (!is_tx && !rss) + context->rq_size_stride = ilog2(size) << 3 | (ilog2(stride) - 4); if (is_tx) context->sq_size_stride = ilog2(size) << 3 | (ilog2(stride) - 4); else - context->sq_size_stride = 1; + context->sq_size_stride = ilog2(TXBB_SIZE) - 4; context->usr_page = cpu_to_be32(mdev->priv_uar.index); context->local_qpn = cpu_to_be32(qpn); context->pri_path.ackto = 1 & 0x07; @@ -59,8 +60,6 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, context->cqn_send = cpu_to_be32(cqn); context->cqn_recv = cpu_to_be32(cqn); context->db_rec_addr = cpu_to_be64(priv->res.db.dma << 2); - if (!rss) - context->srqn = cpu_to_be32(MLX4_EN_USE_SRQ | srqn); } diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 47b178e2b49..cd084de322f 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -40,16 +40,6 @@ #include "mlx4_en.h" -static void *get_wqe(struct mlx4_en_rx_ring *ring, int n) -{ - int offset = n << ring->srq.wqe_shift; - return ring->buf + offset; -} - -static void mlx4_en_srq_event(struct mlx4_srq *srq, enum mlx4_event type) -{ - return; -} static int mlx4_en_get_frag_header(struct skb_frag_struct *frags, void **mac_hdr, void **ip_hdr, void **tcpudp_hdr, @@ -154,9 +144,6 @@ static void mlx4_en_init_rx_desc(struct mlx4_en_priv *priv, int possible_frags; int i; - /* Pre-link descriptor */ - rx_desc->next.next_wqe_index = cpu_to_be16((index + 1) & ring->size_mask); - /* Set size and memtype fields */ for (i = 0; i < priv->num_frags; i++) { skb_frags[i].size = priv->frag_info[i].frag_size; @@ -294,9 +281,6 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, int err; int tmp; - /* Sanity check SRQ size before proceeding */ - if (size >= mdev->dev->caps.max_srq_wqes) - return -EINVAL; ring->prod = 0; ring->cons = 0; @@ -304,7 +288,7 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, ring->size_mask = size - 1; ring->stride = stride; ring->log_stride = ffs(ring->stride) - 1; - ring->buf_size = ring->size * ring->stride; + ring->buf_size = ring->size * ring->stride + TXBB_SIZE; tmp = size * roundup_pow_of_two(MLX4_EN_MAX_RX_FRAGS * sizeof(struct skb_frag_struct)); @@ -360,15 +344,12 @@ err_ring: int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) { - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_wqe_srq_next_seg *next; struct mlx4_en_rx_ring *ring; int i; int ring_ind; int err; int stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) + DS_SIZE * priv->num_frags); - int max_gs = (stride - sizeof(struct mlx4_wqe_srq_next_seg)) / DS_SIZE; for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { ring = &priv->rx_ring[ring_ind]; @@ -379,6 +360,9 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) ring->cqn = priv->rx_cq[ring_ind].mcq.cqn; ring->stride = stride; + if (ring->stride <= TXBB_SIZE) + ring->buf += TXBB_SIZE; + ring->log_stride = ffs(ring->stride) - 1; ring->buf_size = ring->size * ring->stride; @@ -405,37 +389,10 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) ring = &priv->rx_ring[ring_ind]; mlx4_en_update_rx_prod_db(ring); - - /* Configure SRQ representing the ring */ - ring->srq.max = ring->actual_size; - ring->srq.max_gs = max_gs; - ring->srq.wqe_shift = ilog2(ring->stride); - - for (i = 0; i < ring->srq.max; ++i) { - next = get_wqe(ring, i); - next->next_wqe_index = - cpu_to_be16((i + 1) & (ring->srq.max - 1)); - } - - err = mlx4_srq_alloc(mdev->dev, mdev->priv_pdn, &ring->wqres.mtt, - ring->wqres.db.dma, &ring->srq); - if (err){ - en_err(priv, "Failed to allocate srq\n"); - ring_ind--; - goto err_srq; - } - ring->srq.event = mlx4_en_srq_event; } return 0; -err_srq: - while (ring_ind >= 0) { - ring = &priv->rx_ring[ring_ind]; - mlx4_srq_free(mdev->dev, &ring->srq); - ring_ind--; - } - err_buffers: for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) mlx4_en_free_rx_buf(priv, &priv->rx_ring[ring_ind]); @@ -456,7 +413,7 @@ void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv, kfree(ring->lro.lro_arr); mlx4_en_unmap_buffer(&ring->wqres.buf); - mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size); + mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size + TXBB_SIZE); vfree(ring->rx_info); ring->rx_info = NULL; } @@ -464,10 +421,9 @@ void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv, void mlx4_en_deactivate_rx_ring(struct mlx4_en_priv *priv, struct mlx4_en_rx_ring *ring) { - struct mlx4_en_dev *mdev = priv->mdev; - - mlx4_srq_free(mdev->dev, &ring->srq); mlx4_en_free_rx_buf(priv, ring); + if (ring->stride <= TXBB_SIZE) + ring->buf -= TXBB_SIZE; mlx4_en_destroy_allocator(priv, ring); } @@ -835,8 +791,8 @@ void mlx4_en_calc_rx_buf(struct net_device *dev) /* RSS related functions */ -static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, - int qpn, int srqn, int cqn, +static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn, + struct mlx4_en_rx_ring *ring, enum mlx4_qp_state *state, struct mlx4_qp *qp) { @@ -858,13 +814,16 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, qp->event = mlx4_en_sqp_event; memset(context, 0, sizeof *context); - mlx4_en_fill_qp_context(priv, 0, 0, 0, 0, qpn, cqn, srqn, context); + mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 0, 0, + qpn, ring->cqn, context); + context->db_rec_addr = cpu_to_be64(ring->wqres.db.dma); - err = mlx4_qp_to_ready(mdev->dev, &priv->res.mtt, context, qp, state); + err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, context, qp, state); if (err) { mlx4_qp_remove(mdev->dev, qp); mlx4_qp_free(mdev->dev, qp); } + mlx4_en_update_rx_prod_db(ring); out: kfree(context); return err; @@ -880,7 +839,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) void *ptr; int rss_xor = mdev->profile.rss_xor; u8 rss_mask = mdev->profile.rss_mask; - int i, srqn, qpn, cqn; + int i, qpn; int err = 0; int good_qps = 0; @@ -894,10 +853,8 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) } for (i = 0; i < priv->rx_ring_num; i++) { - cqn = priv->rx_ring[i].cqn; - srqn = priv->rx_ring[i].srq.srqn; qpn = rss_map->base_qpn + i; - err = mlx4_en_config_rss_qp(priv, qpn, srqn, cqn, + err = mlx4_en_config_rss_qp(priv, qpn, &priv->rx_ring[i], &rss_map->state[i], &rss_map->qps[i]); if (err) @@ -920,7 +877,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) } rss_map->indir_qp.event = mlx4_en_sqp_event; mlx4_en_fill_qp_context(priv, 0, 0, 0, 1, priv->base_qpn, - priv->rx_ring[0].cqn, 0, &context); + priv->rx_ring[0].cqn, &context); ptr = ((void *) &context) + 0x3c; rss_context = (struct mlx4_en_rss_context *) ptr; diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index d5c18c67425..cbc8ab0c6d1 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c @@ -150,7 +150,7 @@ void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, - int cq, int srqn) + int cq) { struct mlx4_en_dev *mdev = priv->mdev; int err; @@ -168,7 +168,7 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, ring->doorbell_qpn = swab32(ring->qp.qpn << 8); mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn, - ring->cqn, srqn, &ring->context); + ring->cqn, &ring->context); err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, &ring->context, &ring->qp, &ring->qp_state); diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index 2d76ff4c564..4513fb4960d 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -274,13 +274,11 @@ struct mlx4_en_tx_ring { }; struct mlx4_en_rx_desc { - struct mlx4_wqe_srq_next_seg next; /* actual number of entries depends on rx ring stride */ struct mlx4_wqe_data_seg data[0]; }; struct mlx4_en_rx_ring { - struct mlx4_srq srq; struct mlx4_hwq_resources wqres; struct mlx4_en_rx_alloc page_alloc[MLX4_EN_MAX_RX_FRAGS]; struct net_lro_mgr lro; @@ -527,7 +525,7 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ri void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring); int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, - int cq, int srqn); + int cq); void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring); @@ -544,7 +542,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, int budget); int mlx4_en_poll_rx_cq(struct napi_struct *napi, int budget); void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, - int is_tx, int rss, int qpn, int cqn, int srqn, + int is_tx, int rss, int qpn, int cqn, struct mlx4_qp_context *context); void mlx4_en_sqp_event(struct mlx4_qp *qp, enum mlx4_event event); int mlx4_en_map_buffer(struct mlx4_buf *buf); -- cgit v1.2.3-18-g5258 From 37d6fb629eb272a91a3c43033f495a66da2392b5 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 27 May 2009 18:23:48 +0200 Subject: i.MX serial: do not use #ifdef CONFIG_ARCH_* Signed-off-by: Sascha Hauer --- drivers/serial/imx.c | 65 ++++++++++++++++++---------------------------------- 1 file changed, 22 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 5d7b58f1fe4..7485afd0df4 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -67,21 +67,8 @@ #define UBIR 0xa4 /* BRM Incremental Register */ #define UBMR 0xa8 /* BRM Modulator Register */ #define UBRC 0xac /* Baud Rate Count Register */ -#if defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX2 -#define ONEMS 0xb0 /* One Millisecond register */ -#define UTS 0xb4 /* UART Test Register */ -#endif -#ifdef CONFIG_ARCH_MX1 -#define BIPR1 0xb0 /* Incremental Preset Register 1 */ -#define BIPR2 0xb4 /* Incremental Preset Register 2 */ -#define BIPR3 0xb8 /* Incremental Preset Register 3 */ -#define BIPR4 0xbc /* Incremental Preset Register 4 */ -#define BMPR1 0xc0 /* BRM Modulator Register 1 */ -#define BMPR2 0xc4 /* BRM Modulator Register 2 */ -#define BMPR3 0xc8 /* BRM Modulator Register 3 */ -#define BMPR4 0xcc /* BRM Modulator Register 4 */ -#define UTS 0xd0 /* UART Test Register */ -#endif +#define MX2_ONEMS 0xb0 /* One Millisecond register */ +#define UTS (cpu_is_mx1() ? 0xd0 : 0xb4) /* UART Test Register */ /* UART Control Register Bit Fields.*/ #define URXD_CHARRDY (1<<15) @@ -101,12 +88,7 @@ #define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */ #define UCR1_SNDBRK (1<<4) /* Send break */ #define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ -#ifdef CONFIG_ARCH_MX1 -#define UCR1_UARTCLKEN (1<<2) /* UART clock enabled */ -#endif -#if defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX2 -#define UCR1_UARTCLKEN (0) /* not present on mx2/mx3 */ -#endif +#define MX1_UCR1_UARTCLKEN (1<<2) /* UART clock enabled, mx1 only */ #define UCR1_DOZE (1<<1) /* Doze */ #define UCR1_UARTEN (1<<0) /* UART enabled */ #define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */ @@ -132,13 +114,9 @@ #define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */ #define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */ #define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */ -#ifdef CONFIG_ARCH_MX1 -#define UCR3_REF25 (1<<3) /* Ref freq 25 MHz, only on mx1 */ -#define UCR3_REF30 (1<<2) /* Ref Freq 30 MHz, only on mx1 */ -#endif -#if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3 -#define UCR3_RXDMUXSEL (1<<2) /* RXD Muxed Input Select, on mx2/mx3 */ -#endif +#define MX1_UCR3_REF25 (1<<3) /* Ref freq 25 MHz, only on mx1 */ +#define MX1_UCR3_REF30 (1<<2) /* Ref Freq 30 MHz, only on mx1 */ +#define MX2_UCR3_RXDMUXSEL (1<<2) /* RXD Muxed Input Select, on mx2/mx3 */ #define UCR3_INVT (1<<1) /* Inverted Infrared transmission */ #define UCR3_BPEN (1<<0) /* Preset registers enable */ #define UCR4_CTSTL_32 (32<<10) /* CTS trigger level (32 chars) */ @@ -186,12 +164,10 @@ #define UTS_SOFTRST (1<<0) /* Software reset */ /* We've been assigned a range on the "Low-density serial ports" major */ -#ifdef CONFIG_ARCH_MXC #define SERIAL_IMX_MAJOR 207 #define MINOR_START 16 #define DEV_NAME "ttymxc" #define MAX_INTERNAL_IRQ MXC_INTERNAL_IRQS -#endif /* * This determines how often we check the modem status signals @@ -706,11 +682,11 @@ static int imx_startup(struct uart_port *port) } } -#if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3 - temp = readl(sport->port.membase + UCR3); - temp |= UCR3_RXDMUXSEL; - writel(temp, sport->port.membase + UCR3); -#endif + if (!cpu_is_mx1()) { + temp = readl(sport->port.membase + UCR3); + temp |= MX2_UCR3_RXDMUXSEL; + writel(temp, sport->port.membase + UCR3); + } if (USE_IRDA(sport)) { temp = readl(sport->port.membase + UCR4); @@ -942,9 +918,9 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, writel(num, sport->port.membase + UBIR); writel(denom, sport->port.membase + UBMR); -#ifdef ONEMS - writel(sport->port.uartclk / div / 1000, sport->port.membase + ONEMS); -#endif + if (!cpu_is_mx1()) + writel(sport->port.uartclk / div / 1000, + sport->port.membase + MX2_ONEMS); writel(old_ucr1, sport->port.membase + UCR1); @@ -1074,17 +1050,20 @@ static void imx_console_write(struct console *co, const char *s, unsigned int count) { struct imx_port *sport = imx_ports[co->index]; - unsigned int old_ucr1, old_ucr2; + unsigned int old_ucr1, old_ucr2, ucr1; /* * First, save UCR1/2 and then disable interrupts */ - old_ucr1 = readl(sport->port.membase + UCR1); + ucr1 = old_ucr1 = readl(sport->port.membase + UCR1); old_ucr2 = readl(sport->port.membase + UCR2); - writel((old_ucr1 | UCR1_UARTCLKEN | UCR1_UARTEN) & - ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN), - sport->port.membase + UCR1); + if (cpu_is_mx1()) + ucr1 |= MX1_UCR1_UARTCLKEN; + ucr1 |= UCR1_UARTEN; + ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN); + + writel(ucr1, sport->port.membase + UCR1); writel(old_ucr2 | UCR2_TXEN, sport->port.membase + UCR2); -- cgit v1.2.3-18-g5258 From f497d0153a6b53b4cfd004de5f10b14bf630d852 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 18 Mar 2009 11:29:31 +0100 Subject: imxfb: calculate bpix value from bits_per_pixel Signed-off-by: Sascha Hauer --- drivers/video/imxfb.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 15a0ee6d8e2..a8c41cb60ff 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -33,6 +33,7 @@ #include #include +#include /* * Complain if VAR is out of range. @@ -530,8 +531,24 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf lcd_clk / pcr); } + switch (var->bits_per_pixel) { + case 32: + pcr |= PCR_BPIX_18; + break; + case 16: + default: + if (cpu_is_mx1()) + pcr |= PCR_BPIX_12; + else + pcr |= PCR_BPIX_16; + break; + case 8: + pcr |= PCR_BPIX_8; + break; + } + /* add sync polarities */ - pcr |= fbi->pcr & ~0x3F; + pcr |= fbi->pcr & ~(0x3f | (7 << 25)); writel(pcr, fbi->regs + LCDC_PCR); writel(fbi->pwmr, fbi->regs + LCDC_PWMR); -- cgit v1.2.3-18-g5258 From d6b515028863a912d051d371b6d71e09f2a9ff19 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 29 Jun 2009 11:41:09 +0200 Subject: imxfb: use resource_size() macro This fixes an off-by-one error. Also, use dev_err instead of printk in probe() function. Signed-off-by: Sascha Hauer --- drivers/video/imxfb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index a8c41cb60ff..330857a8b31 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -661,7 +661,7 @@ static int __init imxfb_probe(struct platform_device *pdev) struct resource *res; int ret; - printk("i.MX Framebuffer driver\n"); + dev_info(&pdev->dev, "i.MX Framebuffer driver\n"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -701,7 +701,7 @@ static int __init imxfb_probe(struct platform_device *pdev) fbi->regs = ioremap(res->start, resource_size(res)); if (fbi->regs == NULL) { - printk(KERN_ERR"Cannot map frame buffer registers\n"); + dev_err(&pdev->dev, "Cannot map frame buffer registers\n"); goto failed_ioremap; } @@ -771,7 +771,7 @@ failed_map: failed_getclock: iounmap(fbi->regs); failed_ioremap: - release_mem_region(res->start, res->end - res->start); + release_mem_region(res->start, resource_size(res)); failed_req: kfree(info->pseudo_palette); failed_init: @@ -802,7 +802,7 @@ static int __devexit imxfb_remove(struct platform_device *pdev) framebuffer_release(info); iounmap(fbi->regs); - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); clk_disable(fbi->clk); clk_put(fbi->clk); -- cgit v1.2.3-18-g5258 From 343684ffb793a3c371579b7bbc16724713ee5ac7 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 19 Mar 2009 08:25:41 +0100 Subject: imxfb: Add support for multiple displays Signed-off-by: Sascha Hauer --- drivers/video/imxfb.c | 191 +++++++++++++++++++++++++++++++------------------- 1 file changed, 120 insertions(+), 71 deletions(-) (limited to 'drivers') diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 330857a8b31..30ae3022f63 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -130,6 +130,10 @@ #define LCDISR_EOF (1<<1) #define LCDISR_BOF (1<<0) +/* Used fb-mode. Can be set on kernel command line, therefore file-static. */ +static const char *fb_mode; + + /* * These are the bitfields for each * display depth that we support. @@ -146,10 +150,6 @@ struct imxfb_info { void __iomem *regs; struct clk *clk; - u_int max_bpp; - u_int max_xres; - u_int max_yres; - /* * These are the addresses we mapped * the framebuffer memory region to. @@ -173,6 +173,9 @@ struct imxfb_info { cmap_static:1, unused:30; + struct imx_fb_videomode *mode; + int num_modes; + void (*lcd_power)(int); void (*backlight_power)(int); }; @@ -299,6 +302,18 @@ static int imxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, return ret; } +static const struct imx_fb_videomode *imxfb_find_mode(struct imxfb_info *fbi) +{ + struct imx_fb_videomode *m; + int i; + + for (i = 0, m = &fbi->mode[0]; i < fbi->num_modes; i++, m++) { + if (!strcmp(m->mode.name, fb_mode)) + return m; + } + return NULL; +} + /* * imxfb_check_var(): * Round up in the following order: bits_per_pixel, xres, @@ -309,35 +324,81 @@ static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct imxfb_info *fbi = info->par; struct imxfb_rgb *rgb; + const struct imx_fb_videomode *imxfb_mode; + unsigned long lcd_clk; + unsigned long long tmp; + u32 pcr = 0; if (var->xres < MIN_XRES) var->xres = MIN_XRES; if (var->yres < MIN_YRES) var->yres = MIN_YRES; - if (var->xres > fbi->max_xres) - var->xres = fbi->max_xres; - if (var->yres > fbi->max_yres) - var->yres = fbi->max_yres; - var->xres_virtual = max(var->xres_virtual, var->xres); - var->yres_virtual = max(var->yres_virtual, var->yres); + + imxfb_mode = imxfb_find_mode(fbi); + if (!imxfb_mode) + return -EINVAL; + + var->xres = imxfb_mode->mode.xres; + var->yres = imxfb_mode->mode.yres; + var->bits_per_pixel = imxfb_mode->bpp; + var->pixclock = imxfb_mode->mode.pixclock; + var->hsync_len = imxfb_mode->mode.hsync_len; + var->left_margin = imxfb_mode->mode.left_margin; + var->right_margin = imxfb_mode->mode.right_margin; + var->vsync_len = imxfb_mode->mode.vsync_len; + var->upper_margin = imxfb_mode->mode.upper_margin; + var->lower_margin = imxfb_mode->mode.lower_margin; + var->sync = imxfb_mode->mode.sync; + var->xres_virtual = max(var->xres_virtual, var->xres); + var->yres_virtual = max(var->yres_virtual, var->yres); pr_debug("var->bits_per_pixel=%d\n", var->bits_per_pixel); + + lcd_clk = clk_get_rate(fbi->clk); + + tmp = var->pixclock * (unsigned long long)lcd_clk; + + do_div(tmp, 1000000); + + if (do_div(tmp, 1000000) > 500000) + tmp++; + + pcr = (unsigned int)tmp; + + if (--pcr > 0x3F) { + pcr = 0x3F; + printk(KERN_WARNING "Must limit pixel clock to %luHz\n", + lcd_clk / pcr); + } + switch (var->bits_per_pixel) { case 32: + pcr |= PCR_BPIX_18; rgb = &def_rgb_18; break; case 16: default: - if (fbi->pcr & PCR_TFT) + if (cpu_is_mx1()) + pcr |= PCR_BPIX_12; + else + pcr |= PCR_BPIX_16; + + if (imxfb_mode->pcr & PCR_TFT) rgb = &def_rgb_16_tft; else rgb = &def_rgb_16_stn; break; case 8: + pcr |= PCR_BPIX_8; rgb = &def_rgb_8; break; } + /* add sync polarities */ + pcr |= imxfb_mode->pcr & ~(0x3f | (7 << 25)); + + fbi->pcr = pcr; + /* * Copy the RGB parameters for this display * from the machine specific parameters. @@ -394,10 +455,6 @@ static void imxfb_enable_controller(struct imxfb_info *fbi) writel(fbi->screen_dma, fbi->regs + LCDC_SSA); - /* physical screen start address */ - writel(VPW_VPW(fbi->max_xres * fbi->max_bpp / 8 / 4), - fbi->regs + LCDC_VPW); - /* panning offset 0 (0 pixel offset) */ writel(0x00000000, fbi->regs + LCDC_POS); @@ -469,8 +526,6 @@ static struct fb_ops imxfb_ops = { static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct imxfb_info *fbi = info->par; - unsigned int pcr, lcd_clk; - unsigned long long tmp; pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n", var->xres, var->hsync_len, @@ -506,6 +561,10 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf info->fix.id, var->lower_margin); #endif + /* physical screen start address */ + writel(VPW_VPW(var->xres * var->bits_per_pixel / 8 / 4), + fbi->regs + LCDC_VPW); + writel(HCR_H_WIDTH(var->hsync_len - 1) | HCR_H_WAIT_1(var->right_margin - 1) | HCR_H_WAIT_2(var->left_margin - 3), @@ -519,38 +578,7 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf writel(SIZE_XMAX(var->xres) | SIZE_YMAX(var->yres), fbi->regs + LCDC_SIZE); - lcd_clk = clk_get_rate(fbi->clk); - tmp = var->pixclock * (unsigned long long)lcd_clk; - do_div(tmp, 1000000); - if (do_div(tmp, 1000000) > 500000) - tmp++; - pcr = (unsigned int)tmp; - if (--pcr > 0x3F) { - pcr = 0x3F; - printk(KERN_WARNING "Must limit pixel clock to %uHz\n", - lcd_clk / pcr); - } - - switch (var->bits_per_pixel) { - case 32: - pcr |= PCR_BPIX_18; - break; - case 16: - default: - if (cpu_is_mx1()) - pcr |= PCR_BPIX_12; - else - pcr |= PCR_BPIX_16; - break; - case 8: - pcr |= PCR_BPIX_8; - break; - } - - /* add sync polarities */ - pcr |= fbi->pcr & ~(0x3f | (7 << 25)); - - writel(pcr, fbi->regs + LCDC_PCR); + writel(fbi->pcr, fbi->regs + LCDC_PCR); writel(fbi->pwmr, fbi->regs + LCDC_PWMR); writel(fbi->lscr1, fbi->regs + LCDC_LSCR1); writel(fbi->dmacr, fbi->regs + LCDC_DMACR); @@ -592,6 +620,8 @@ static int __init imxfb_init_fbinfo(struct platform_device *pdev) struct imx_fb_platform_data *pdata = pdev->dev.platform_data; struct fb_info *info = dev_get_drvdata(&pdev->dev); struct imxfb_info *fbi = info->par; + struct imx_fb_videomode *m; + int i; pr_debug("%s\n",__func__); @@ -620,35 +650,18 @@ static int __init imxfb_init_fbinfo(struct platform_device *pdev) info->fbops = &imxfb_ops; info->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST; - - fbi->max_xres = pdata->xres; - info->var.xres = pdata->xres; - info->var.xres_virtual = pdata->xres; - fbi->max_yres = pdata->yres; - info->var.yres = pdata->yres; - info->var.yres_virtual = pdata->yres; - fbi->max_bpp = pdata->bpp; - info->var.bits_per_pixel = pdata->bpp; - info->var.nonstd = pdata->nonstd; - info->var.pixclock = pdata->pixclock; - info->var.hsync_len = pdata->hsync_len; - info->var.left_margin = pdata->left_margin; - info->var.right_margin = pdata->right_margin; - info->var.vsync_len = pdata->vsync_len; - info->var.upper_margin = pdata->upper_margin; - info->var.lower_margin = pdata->lower_margin; - info->var.sync = pdata->sync; info->var.grayscale = pdata->cmap_greyscale; fbi->cmap_inverse = pdata->cmap_inverse; fbi->cmap_static = pdata->cmap_static; - fbi->pcr = pdata->pcr; fbi->lscr1 = pdata->lscr1; fbi->dmacr = pdata->dmacr; fbi->pwmr = pdata->pwmr; fbi->lcd_power = pdata->lcd_power; fbi->backlight_power = pdata->backlight_power; - info->fix.smem_len = fbi->max_xres * fbi->max_yres * - fbi->max_bpp / 8; + + for (i = 0, m = &pdata->mode[0]; i < pdata->num_modes; i++, m++) + info->fix.smem_len = max_t(size_t, info->fix.smem_len, + m->mode.xres * m->mode.yres * m->bpp / 8); return 0; } @@ -659,7 +672,7 @@ static int __init imxfb_probe(struct platform_device *pdev) struct fb_info *info; struct imx_fb_platform_data *pdata; struct resource *res; - int ret; + int ret, i; dev_info(&pdev->dev, "i.MX Framebuffer driver\n"); @@ -679,6 +692,9 @@ static int __init imxfb_probe(struct platform_device *pdev) fbi = info->par; + if (!fb_mode) + fb_mode = pdata->mode[0].mode.name; + platform_set_drvdata(pdev, info); ret = imxfb_init_fbinfo(pdev); @@ -736,6 +752,13 @@ static int __init imxfb_probe(struct platform_device *pdev) goto failed_platform_init; } + fbi->mode = pdata->mode; + fbi->num_modes = pdata->num_modes; + + INIT_LIST_HEAD(&info->modelist); + for (i = 0; i < pdata->num_modes; i++) + fb_add_videomode(&pdata->mode[i].mode, &info->modelist); + /* * This makes sure that our colour bitfield * descriptors are correctly initialised. @@ -828,8 +851,34 @@ static struct platform_driver imxfb_driver = { }, }; +static int imxfb_setup(void) +{ +#ifndef MODULE + char *opt, *options = NULL; + + if (fb_get_options("imxfb", &options)) + return -ENODEV; + + if (!options || !*options) + return 0; + + while ((opt = strsep(&options, ",")) != NULL) { + if (!*opt) + continue; + else + fb_mode = opt; + } +#endif + return 0; +} + int __init imxfb_init(void) { + int ret = imxfb_setup(); + + if (ret < 0) + return ret; + return platform_driver_probe(&imxfb_driver, imxfb_probe); } -- cgit v1.2.3-18-g5258 From 44cb2db10d05fc263c9fa44347d350d4f7f5890c Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Sat, 8 Aug 2009 02:17:32 +0200 Subject: HID: fix overrun in quirks initialization Check whether index is within bounds before testing the element. declared in drivers/hid/usbhid/hid-core.c:62: static char *quirks_param[MAX_USBHID_BOOT_QUIRKS] = ... Signed-off-by: Roel Kluin Cc: Jiri Kosina Signed-off-by: Andrew Morton Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-quirks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index d8f7423f363..0d9045aa2c4 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -201,7 +201,7 @@ int usbhid_quirks_init(char **quirks_param) u32 quirks; int n = 0, m; - for (; quirks_param[n] && n < MAX_USBHID_BOOT_QUIRKS; n++) { + for (; n < MAX_USBHID_BOOT_QUIRKS && quirks_param[n]; n++) { m = sscanf(quirks_param[n], "0x%hx:0x%hx:0x%x", &idVendor, &idProduct, &quirks); -- cgit v1.2.3-18-g5258 From a809dda0369ae6157f7bcd3e704b857d43704cbd Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 8 Aug 2009 02:26:10 +0200 Subject: HID: fix memory leak on error patch in debug code Error handling code following a kzalloc should free the allocated data. The semantic match that finds the problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; statement S; expression E; identifier f,f1,l; position p1,p2; expression *ptr != NULL; @@ x@p1 = \(kmalloc\|kzalloc\|kcalloc\)(...); ... if (x == NULL) S <... when != x when != if (...) { <+...x...+> } ( x->f1 = E | (x->f1 == NULL || ...) | f(...,x->f1,...) ) ...> ( return \(0\|<+...x...+>\|ptr\); | return@p2 ...; ) @script:python@ p1 << r.p1; p2 << r.p2; @@ print "* file: %s kmalloc %s return %s" % (p1[0].file,p1[0].line,p2[0].line) // Signed-off-by: Julia Lawall Cc: Jiri Kosina Signed-off-by: Andrew Morton Signed-off-by: Jiri Kosina --- drivers/hid/hid-debug.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index a331a1821e8..06e87dc7779 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -909,6 +909,7 @@ static int hid_debug_events_open(struct inode *inode, struct file *file) if (!(list->hid_debug_buf = kzalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_KERNEL))) { err = -ENOMEM; + kfree(list); goto out; } list->hdev = (struct hid_device *) inode->i_private; -- cgit v1.2.3-18-g5258 From 31f7fd795d17b264c3c05e4a976f963012c17c68 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Fri, 31 Jul 2009 10:56:36 -0400 Subject: HID: ignore all recent SoundGraph iMON devices After some inspection of the Windows iMON driver, several additional device IDs were added to the lirc_imon driver. At least a few of these have been seen in the wild, and require manual quirking to keep the usbhid driver from binding to them. Rather than list out every single device, ignore the entire device ID range, 0x0034 - 0x0046. Some of these may not advertise themselves as HID devices, but no harm done to such devices anyway. Does the right thing in brief testing w/my 0x0045 device. Signed-off-by: Jarod Wilson Acked-by: Anssi Hannula Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 10 +++++----- drivers/hid/hid-ids.h | 7 ++----- 2 files changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 6164ed3a414..afb6a3baade 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1627,11 +1627,6 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0003) }, { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) }, { HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD3) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD4) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD5) }, { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY1) }, { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY2) }, { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) }, @@ -1698,6 +1693,11 @@ static bool hid_ignore(struct hid_device *hdev) hdev->product <= USB_DEVICE_ID_LOGITECH_HARMONY_LAST) return true; break; + case USB_VENDOR_ID_SOUNDGRAPH: + if (hdev->product >= USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST && + hdev->product <= USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST) + return true; + break; } if (hdev->type == HID_TYPE_USBMOUSE && diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 3058e472aeb..35752fcc0d0 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -377,11 +377,8 @@ #define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 #define USB_VENDOR_ID_SOUNDGRAPH 0x15c2 -#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD 0x0038 -#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD2 0x0036 -#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD3 0x0034 -#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD4 0x0044 -#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD5 0x0045 +#define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034 +#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST 0x0046 #define USB_VENDOR_ID_SUN 0x0430 #define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab -- cgit v1.2.3-18-g5258 From 4cfae3e80431fd113f0f4a8e1d4fff84aafe045c Mon Sep 17 00:00:00 2001 From: Henning Glawe Date: Sun, 2 Aug 2009 22:18:12 +0200 Subject: HID: ignore Philips IEEE802.15.4 RF Dongle This usb device claims to be of HID class, but is in fact a 802.15.4 lowpan transceiver, therefore the generic HID driver cannot operate this device. A separate driver for this device will be written for this using the new 802.15.4 stack. Signed-off-by: Henning Glawe Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 +++ 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index afb6a3baade..48567d8fe35 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1626,6 +1626,7 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0002) }, { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0003) }, { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) }, + { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) }, { HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) }, { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY1) }, { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY2) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 35752fcc0d0..adbef5d069c 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -360,6 +360,9 @@ #define USB_VENDOR_ID_PETALYNX 0x18b1 #define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037 +#define USB_VENDOR_ID_PHILIPS 0x0471 +#define USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE 0x0617 + #define USB_VENDOR_ID_PLAYDOTCOM 0x0b43 #define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII 0x0003 -- cgit v1.2.3-18-g5258 From 1e5de18278e6862f4198412b5059a03770fa816a Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 19 Jul 2009 00:12:20 +0900 Subject: x86: Introduce GDT_ENTRY_INIT() GDT_ENTRY_INIT is static initializer of desc_struct. We already have similar macro GDT_ENTRY() but it's static initializer for u64 and it cannot be used for desc_struct. Signed-off-by: Akinobu Mita LKML-Reference: <20090718151219.GD11294@localhost.localdomain> Signed-off-by: Ingo Molnar --- drivers/pnp/pnpbios/bioscalls.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c index 45ad3e9cc36..bd035e3d355 100644 --- a/drivers/pnp/pnpbios/bioscalls.c +++ b/drivers/pnp/pnpbios/bioscalls.c @@ -60,7 +60,7 @@ do { \ set_desc_limit(&gdt[(selname) >> 3], (size) - 1); \ } while(0) -static struct desc_struct bad_bios_desc; +static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4092, 0, 0); /* * At some point we want to use this stack frame pointer to unwind @@ -476,9 +476,6 @@ void pnpbios_calls_init(union pnp_bios_install_struct *header) pnp_bios_callpoint.offset = header->fields.pm16offset; pnp_bios_callpoint.segment = PNP_CS16; - bad_bios_desc.a = 0; - bad_bios_desc.b = 0x00409200; - set_desc_base(&bad_bios_desc, (unsigned long)__va(0x40UL << 4)); set_desc_limit(&bad_bios_desc, 4095 - (0x40 << 4)); for_each_possible_cpu(i) { -- cgit v1.2.3-18-g5258 From 67dbe83adca4415e210e436bf961e8a833030d1e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 7 Aug 2009 23:17:39 -0700 Subject: Input: wistron_btns - switch to using dev_pm_ops Also start using 'bool' where it makes sense. Tested-by: Giuseppe Mazzotta Signed-off-by: Dmitry Torokhov --- drivers/input/misc/wistron_btns.c | 66 ++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 26e17a9a22e..bc3116bebfe 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -243,9 +243,9 @@ enum { KE_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH }; #define FE_UNTESTED 0x80 static struct key_entry *keymap; /* = NULL; Current key map */ -static int have_wifi; -static int have_bluetooth; -static int have_leds; +static bool have_wifi; +static bool have_bluetooth; +static int leds_present; /* bitmask of leds present */ static int __init dmi_matched(const struct dmi_system_id *dmi) { @@ -254,11 +254,11 @@ static int __init dmi_matched(const struct dmi_system_id *dmi) keymap = dmi->driver_data; for (key = keymap; key->type != KE_END; key++) { if (key->type == KE_WIFI) - have_wifi = 1; + have_wifi = true; else if (key->type == KE_BLUETOOTH) - have_bluetooth = 1; + have_bluetooth = true; } - have_leds = key->code & (FE_MAIL_LED | FE_WIFI_LED); + leds_present = key->code & (FE_MAIL_LED | FE_WIFI_LED); return 1; } @@ -993,8 +993,8 @@ static int __init select_keymap(void) static struct input_polled_dev *wistron_idev; static unsigned long jiffies_last_press; -static int wifi_enabled; -static int bluetooth_enabled; +static bool wifi_enabled; +static bool bluetooth_enabled; static void report_key(struct input_dev *dev, unsigned int keycode) { @@ -1037,24 +1037,24 @@ static struct led_classdev wistron_wifi_led = { static void __devinit wistron_led_init(struct device *parent) { - if (have_leds & FE_WIFI_LED) { + if (leds_present & FE_WIFI_LED) { u16 wifi = bios_get_default_setting(WIFI); if (wifi & 1) { wistron_wifi_led.brightness = (wifi & 2) ? LED_FULL : LED_OFF; if (led_classdev_register(parent, &wistron_wifi_led)) - have_leds &= ~FE_WIFI_LED; + leds_present &= ~FE_WIFI_LED; else bios_set_state(WIFI, wistron_wifi_led.brightness); } else - have_leds &= ~FE_WIFI_LED; + leds_present &= ~FE_WIFI_LED; } - if (have_leds & FE_MAIL_LED) { + if (leds_present & FE_MAIL_LED) { /* bios_get_default_setting(MAIL) always retuns 0, so just turn the led off */ wistron_mail_led.brightness = LED_OFF; if (led_classdev_register(parent, &wistron_mail_led)) - have_leds &= ~FE_MAIL_LED; + leds_present &= ~FE_MAIL_LED; else bios_set_state(MAIL_LED, wistron_mail_led.brightness); } @@ -1062,28 +1062,28 @@ static void __devinit wistron_led_init(struct device *parent) static void __devexit wistron_led_remove(void) { - if (have_leds & FE_MAIL_LED) + if (leds_present & FE_MAIL_LED) led_classdev_unregister(&wistron_mail_led); - if (have_leds & FE_WIFI_LED) + if (leds_present & FE_WIFI_LED) led_classdev_unregister(&wistron_wifi_led); } static inline void wistron_led_suspend(void) { - if (have_leds & FE_MAIL_LED) + if (leds_present & FE_MAIL_LED) led_classdev_suspend(&wistron_mail_led); - if (have_leds & FE_WIFI_LED) + if (leds_present & FE_WIFI_LED) led_classdev_suspend(&wistron_wifi_led); } static inline void wistron_led_resume(void) { - if (have_leds & FE_MAIL_LED) + if (leds_present & FE_MAIL_LED) led_classdev_resume(&wistron_mail_led); - if (have_leds & FE_WIFI_LED) + if (leds_present & FE_WIFI_LED) led_classdev_resume(&wistron_wifi_led); } @@ -1296,7 +1296,7 @@ static int __devinit wistron_probe(struct platform_device *dev) if (have_wifi) { u16 wifi = bios_get_default_setting(WIFI); if (wifi & 1) - wifi_enabled = (wifi & 2) ? 1 : 0; + wifi_enabled = wifi & 2; else have_wifi = 0; @@ -1307,15 +1307,16 @@ static int __devinit wistron_probe(struct platform_device *dev) if (have_bluetooth) { u16 bt = bios_get_default_setting(BLUETOOTH); if (bt & 1) - bluetooth_enabled = (bt & 2) ? 1 : 0; + bluetooth_enabled = bt & 2; else - have_bluetooth = 0; + have_bluetooth = false; if (have_bluetooth) bios_set_state(BLUETOOTH, bluetooth_enabled); } wistron_led_init(&dev->dev); + err = setup_input_dev(); if (err) { bios_detach(); @@ -1336,7 +1337,7 @@ static int __devexit wistron_remove(struct platform_device *dev) } #ifdef CONFIG_PM -static int wistron_suspend(struct platform_device *dev, pm_message_t state) +static int wistron_suspend(struct device *dev) { if (have_wifi) bios_set_state(WIFI, 0); @@ -1345,10 +1346,11 @@ static int wistron_suspend(struct platform_device *dev, pm_message_t state) bios_set_state(BLUETOOTH, 0); wistron_led_suspend(); + return 0; } -static int wistron_resume(struct platform_device *dev) +static int wistron_resume(struct device *dev) { if (have_wifi) bios_set_state(WIFI, wifi_enabled); @@ -1357,24 +1359,30 @@ static int wistron_resume(struct platform_device *dev) bios_set_state(BLUETOOTH, bluetooth_enabled); wistron_led_resume(); + poll_bios(true); return 0; } -#else -#define wistron_suspend NULL -#define wistron_resume NULL + +static const struct dev_pm_ops wistron_pm_ops = { + .suspend = wistron_suspend, + .resume = wistron_resume, + .poweroff = wistron_suspend, + .restore = wistron_resume, +}; #endif static struct platform_driver wistron_driver = { .driver = { .name = "wistron-bios", .owner = THIS_MODULE, +#if CONFIG_PM + .pm = &wistron_pm_ops, +#endif }, .probe = wistron_probe, .remove = __devexit_p(wistron_remove), - .suspend = wistron_suspend, - .resume = wistron_resume, }; static int __init wb_module_init(void) -- cgit v1.2.3-18-g5258 From 6777f01728d5fc40e02cc0ae43639bf51cc247dd Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 7 Aug 2009 23:17:46 -0700 Subject: Input: hil_kbd - switch to use completion instead of semaphore Stop abusing semaphore for waiting, use completion instead. Also handle errors from input_register_device. Tested-by: Helge Deller Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/hil_kbd.c | 272 ++++++++++++++++++++------------------- 1 file changed, 140 insertions(+), 132 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c index f732893a960..fe57044e9e5 100644 --- a/drivers/input/keyboard/hil_kbd.c +++ b/drivers/input/keyboard/hil_kbd.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include @@ -81,135 +81,128 @@ struct hil_kbd { char exd[HIL_KBD_MAX_LENGTH]; /* EXD record */ char rnm[HIL_KBD_MAX_LENGTH + 1]; /* RNM record + NULL term. */ - /* Something to sleep around with. */ - struct semaphore sem; + struct completion cmd_done; }; -/* Process a complete packet after transfer from the HIL */ -static void hil_kbd_process_record(struct hil_kbd *kbd) +static bool hil_kbd_is_command_response(hil_packet p) { - struct input_dev *dev = kbd->dev; - hil_packet *data = kbd->data; - hil_packet p; - int idx, i, cnt; + if ((p & ~HIL_CMDCT_POL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) + return false; - idx = kbd->idx4/4; - p = data[idx - 1]; + if ((p & ~HIL_CMDCT_RPL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) + return false; + + return true; +} + +static void hil_kbd_handle_command_response(struct hil_kbd *kbd) +{ + hil_packet p; + char *buf; + int i, idx; - if ((p & ~HIL_CMDCT_POL) == - (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) - goto report; - if ((p & ~HIL_CMDCT_RPL) == - (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) - goto report; + idx = kbd->idx4 / 4; + p = kbd->data[idx - 1]; - /* Not a poll response. See if we are loading config records. */ switch (p & HIL_PKT_DATA_MASK) { case HIL_CMD_IDD: - for (i = 0; i < idx; i++) - kbd->idd[i] = kbd->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_KBD_MAX_LENGTH; i++) - kbd->idd[i] = 0; + buf = kbd->idd; break; case HIL_CMD_RSC: - for (i = 0; i < idx; i++) - kbd->rsc[i] = kbd->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_KBD_MAX_LENGTH; i++) - kbd->rsc[i] = 0; + buf = kbd->rsc; break; case HIL_CMD_EXD: - for (i = 0; i < idx; i++) - kbd->exd[i] = kbd->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_KBD_MAX_LENGTH; i++) - kbd->exd[i] = 0; + buf = kbd->exd; break; case HIL_CMD_RNM: - for (i = 0; i < idx; i++) - kbd->rnm[i] = kbd->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_KBD_MAX_LENGTH + 1; i++) - kbd->rnm[i] = '\0'; + kbd->rnm[HIL_KBD_MAX_LENGTH] = 0; + buf = kbd->rnm; break; default: /* These occur when device isn't present */ - if (p == (HIL_ERR_INT | HIL_PKT_CMD)) - break; - /* Anything else we'd like to know about. */ - printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p); - break; + if (p != (HIL_ERR_INT | HIL_PKT_CMD)) { + /* Anything else we'd like to know about. */ + printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p); + } + goto out; } - goto out; - report: - cnt = 1; + for (i = 0; i < idx; i++) + buf[i] = kbd->data[i] & HIL_PKT_DATA_MASK; + for (; i < HIL_KBD_MAX_LENGTH; i++) + buf[i] = 0; + out: + complete(&kbd->cmd_done); +} + +static void hil_kbd_handle_key_events(struct hil_kbd *kbd) +{ + struct input_dev *dev = kbd->dev; + int idx = kbd->idx4 / 4; + int i; + switch (kbd->data[0] & HIL_POL_CHARTYPE_MASK) { case HIL_POL_CHARTYPE_NONE: - break; + return; case HIL_POL_CHARTYPE_ASCII: - while (cnt < idx - 1) - input_report_key(dev, kbd->data[cnt++] & 0x7f, 1); + for (i = 1; i < idx - 1; i++) + input_report_key(dev, kbd->data[i] & 0x7f, 1); break; case HIL_POL_CHARTYPE_RSVD1: case HIL_POL_CHARTYPE_RSVD2: case HIL_POL_CHARTYPE_BINARY: - while (cnt < idx - 1) - input_report_key(dev, kbd->data[cnt++], 1); + for (i = 1; i < idx - 1; i++) + input_report_key(dev, kbd->data[i], 1); break; case HIL_POL_CHARTYPE_SET1: - while (cnt < idx - 1) { - unsigned int key; - int up; - key = kbd->data[cnt++]; - up = key & HIL_KBD_SET1_UPBIT; + for (i = 1; i < idx - 1; i++) { + unsigned int key = kbd->data[i]; + int up = key & HIL_KBD_SET1_UPBIT; + key &= (~HIL_KBD_SET1_UPBIT & 0xff); key = hil_kbd_set1[key >> HIL_KBD_SET1_SHIFT]; - if (key != KEY_RESERVED) - input_report_key(dev, key, !up); + input_report_key(dev, key, !up); } break; case HIL_POL_CHARTYPE_SET2: - while (cnt < idx - 1) { - unsigned int key; - int up; - key = kbd->data[cnt++]; - up = key & HIL_KBD_SET2_UPBIT; + for (i = 1; i < idx - 1; i++) { + unsigned int key = kbd->data[i]; + int up = key & HIL_KBD_SET2_UPBIT; + key &= (~HIL_KBD_SET1_UPBIT & 0xff); key = key >> HIL_KBD_SET2_SHIFT; - if (key != KEY_RESERVED) - input_report_key(dev, key, !up); + input_report_key(dev, key, !up); } break; case HIL_POL_CHARTYPE_SET3: - while (cnt < idx - 1) { - unsigned int key; - int up; - key = kbd->data[cnt++]; - up = key & HIL_KBD_SET3_UPBIT; + for (i = 1; i < idx - 1; i++) { + unsigned int key = kbd->data[i]; + int up = key & HIL_KBD_SET3_UPBIT; + key &= (~HIL_KBD_SET1_UPBIT & 0xff); key = hil_kbd_set3[key >> HIL_KBD_SET3_SHIFT]; - if (key != KEY_RESERVED) - input_report_key(dev, key, !up); + input_report_key(dev, key, !up); } break; } - out: - kbd->idx4 = 0; - up(&kbd->sem); + + input_sync(dev); } static void hil_kbd_process_err(struct hil_kbd *kbd) { printk(KERN_WARNING PREFIX "errored HIL packet\n"); kbd->idx4 = 0; - up(&kbd->sem); + complete(&kbd->cmd_done); /* just in case somebody is waiting */ } static irqreturn_t hil_kbd_interrupt(struct serio *serio, @@ -222,11 +215,12 @@ static irqreturn_t hil_kbd_interrupt(struct serio *serio, kbd = serio_get_drvdata(serio); BUG_ON(kbd == NULL); - if (kbd->idx4 >= (HIL_KBD_MAX_LENGTH * sizeof(hil_packet))) { + if (kbd->idx4 >= HIL_KBD_MAX_LENGTH * sizeof(hil_packet)) { hil_kbd_process_err(kbd); - return IRQ_HANDLED; + goto out; } - idx = kbd->idx4/4; + + idx = kbd->idx4 / 4; if (!(kbd->idx4 % 4)) kbd->data[idx] = 0; packet = kbd->data[idx]; @@ -234,22 +228,25 @@ static irqreturn_t hil_kbd_interrupt(struct serio *serio, kbd->data[idx] = packet; /* Records of N 4-byte hil_packets must terminate with a command. */ - if ((++(kbd->idx4)) % 4) - return IRQ_HANDLED; - if ((packet & 0xffff0000) != HIL_ERR_INT) { - hil_kbd_process_err(kbd); - return IRQ_HANDLED; + if ((++kbd->idx4 % 4) == 0) { + if ((packet & 0xffff0000) != HIL_ERR_INT) { + hil_kbd_process_err(kbd); + } else if (packet & HIL_PKT_CMD) { + if (hil_kbd_is_command_response(packet)) + hil_kbd_handle_command_response(kbd); + else + hil_kbd_handle_key_events(kbd); + kbd->idx4 = 0; + } } - if (packet & HIL_PKT_CMD) - hil_kbd_process_record(kbd); + out: return IRQ_HANDLED; } static void hil_kbd_disconnect(struct serio *serio) { - struct hil_kbd *kbd; + struct hil_kbd *kbd = serio_get_drvdata(serio); - kbd = serio_get_drvdata(serio); BUG_ON(kbd == NULL); serio_close(serio); @@ -259,52 +256,64 @@ static void hil_kbd_disconnect(struct serio *serio) static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) { - struct hil_kbd *kbd; - uint8_t did, *idd; - int i; + struct hil_kbd *kbd; + struct input_dev *input_dev; + uint8_t did, *idd; + int i; + int error; kbd = kzalloc(sizeof(*kbd), GFP_KERNEL); - if (!kbd) - return -ENOMEM; - - kbd->dev = input_allocate_device(); - if (!kbd->dev) + input_dev = input_allocate_device(); + if (!kbd || !input_dev) { + error = -ENOMEM; goto bail0; + } - if (serio_open(serio, drv)) - goto bail1; - - serio_set_drvdata(serio, kbd); kbd->serio = serio; + kbd->dev = input_dev; + + error = serio_open(serio, drv); + if (error) + goto bail0; - init_MUTEX_LOCKED(&kbd->sem); + serio_set_drvdata(serio, kbd); /* Get device info. MLC driver supplies devid/status/etc. */ + init_completion(&kbd->cmd_done); serio_write(serio, 0); serio_write(serio, 0); serio_write(serio, HIL_PKT_CMD >> 8); serio_write(serio, HIL_CMD_IDD); - down(&kbd->sem); + error = wait_for_completion_killable(&kbd->cmd_done); + if (error) + goto bail1; + init_completion(&kbd->cmd_done); serio_write(serio, 0); serio_write(serio, 0); serio_write(serio, HIL_PKT_CMD >> 8); serio_write(serio, HIL_CMD_RSC); - down(&kbd->sem); + error = wait_for_completion_killable(&kbd->cmd_done); + if (error) + goto bail1; + init_completion(&kbd->cmd_done); serio_write(serio, 0); serio_write(serio, 0); serio_write(serio, HIL_PKT_CMD >> 8); serio_write(serio, HIL_CMD_RNM); - down(&kbd->sem); + error = wait_for_completion_killable(&kbd->cmd_done); + if (error) + goto bail1; + init_completion(&kbd->cmd_done); serio_write(serio, 0); serio_write(serio, 0); serio_write(serio, HIL_PKT_CMD >> 8); serio_write(serio, HIL_CMD_EXD); - down(&kbd->sem); - - up(&kbd->sem); + error = wait_for_completion_killable(&kbd->cmd_done); + if (error) + goto bail1; did = kbd->idd[0]; idd = kbd->idd + 1; @@ -317,55 +326,54 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]); break; default: - goto bail2; + goto bail1; } if (HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) { printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n"); - goto bail2; + goto bail1; } - kbd->dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); - kbd->dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) | - BIT_MASK(LED_SCROLLL); - kbd->dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE; - kbd->dev->keycodesize = sizeof(hil_kbd_set1[0]); - kbd->dev->keycode = hil_kbd_set1; - kbd->dev->name = strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME; - kbd->dev->phys = "hpkbd/input0"; /* XXX */ - - kbd->dev->id.bustype = BUS_HIL; - kbd->dev->id.vendor = PCI_VENDOR_ID_HP; - kbd->dev->id.product = 0x0001; /* TODO: get from kbd->rsc */ - kbd->dev->id.version = 0x0100; /* TODO: get from kbd->rsc */ - kbd->dev->dev.parent = &serio->dev; + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); + input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) | + BIT_MASK(LED_SCROLLL); + input_dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE; + input_dev->keycodesize = sizeof(hil_kbd_set1[0]); + input_dev->keycode = hil_kbd_set1; + input_dev->name = strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME; + input_dev->phys = "hpkbd/input0"; /* XXX */ + + input_dev->id.bustype = BUS_HIL; + input_dev->id.vendor = PCI_VENDOR_ID_HP; + input_dev->id.product = 0x0001; /* TODO: get from kbd->rsc */ + input_dev->id.version = 0x0100; /* TODO: get from kbd->rsc */ + input_dev->dev.parent = &serio->dev; for (i = 0; i < 128; i++) { - set_bit(hil_kbd_set1[i], kbd->dev->keybit); - set_bit(hil_kbd_set3[i], kbd->dev->keybit); + __set_bit(hil_kbd_set1[i], input_dev->keybit); + __set_bit(hil_kbd_set3[i], input_dev->keybit); } - clear_bit(0, kbd->dev->keybit); - - input_register_device(kbd->dev); - printk(KERN_INFO "input: %s, ID: %d\n", - kbd->dev->name, did); + __clear_bit(KEY_RESERVED, input_dev->keybit); serio_write(serio, 0); serio_write(serio, 0); serio_write(serio, HIL_PKT_CMD >> 8); serio_write(serio, HIL_CMD_EK1); /* Enable Keyswitch Autorepeat 1 */ - down(&kbd->sem); - up(&kbd->sem); + /* No need to wait for completion */ + + error = input_register_device(kbd->dev); + if (error) + goto bail1; return 0; - bail2: + + bail1: serio_close(serio); serio_set_drvdata(serio, NULL); - bail1: - input_free_device(kbd->dev); bail0: + input_free_device(input_dev); kfree(kbd); - return -EIO; + return error; } static struct serio_device_id hil_kbd_ids[] = { -- cgit v1.2.3-18-g5258 From 1437dc3089911d42180be11c50a0b960250a1d87 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 7 Aug 2009 23:17:47 -0700 Subject: Input: hil_kbd - prepare for merging with hil_ptr Rename functions and variables from [hil_]kbd to [hil_]dev in preparation of merging hil_kbd and hil_ptr. Tested-by: Helge Deller Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/hil_kbd.c | 156 +++++++++++++++++++-------------------- 1 file changed, 78 insertions(+), 78 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c index fe57044e9e5..235a669a0ac 100644 --- a/drivers/input/keyboard/hil_kbd.c +++ b/drivers/input/keyboard/hil_kbd.c @@ -49,7 +49,7 @@ MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS("serio:ty03pr25id00ex*"); -#define HIL_KBD_MAX_LENGTH 16 +#define HIL_PACKET_MAX_LENGTH 16 #define HIL_KBD_SET1_UPBIT 0x01 #define HIL_KBD_SET1_SHIFT 1 @@ -67,24 +67,24 @@ static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] __read_mostly = static const char hil_language[][16] = { HIL_LOCALE_MAP }; -struct hil_kbd { +struct hil_dev { struct input_dev *dev; struct serio *serio; /* Input buffer and index for packets from HIL bus. */ - hil_packet data[HIL_KBD_MAX_LENGTH]; + hil_packet data[HIL_PACKET_MAX_LENGTH]; int idx4; /* four counts per packet */ /* Raw device info records from HIL bus, see hil.h for fields. */ - char idd[HIL_KBD_MAX_LENGTH]; /* DID byte and IDD record */ - char rsc[HIL_KBD_MAX_LENGTH]; /* RSC record */ - char exd[HIL_KBD_MAX_LENGTH]; /* EXD record */ - char rnm[HIL_KBD_MAX_LENGTH + 1]; /* RNM record + NULL term. */ + char idd[HIL_PACKET_MAX_LENGTH]; /* DID byte and IDD record */ + char rsc[HIL_PACKET_MAX_LENGTH]; /* RSC record */ + char exd[HIL_PACKET_MAX_LENGTH]; /* EXD record */ + char rnm[HIL_PACKET_MAX_LENGTH + 1]; /* RNM record + NULL term. */ struct completion cmd_done; }; -static bool hil_kbd_is_command_response(hil_packet p) +static bool hil_dev_is_command_response(hil_packet p) { if ((p & ~HIL_CMDCT_POL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) return false; @@ -95,31 +95,31 @@ static bool hil_kbd_is_command_response(hil_packet p) return true; } -static void hil_kbd_handle_command_response(struct hil_kbd *kbd) +static void hil_dev_handle_command_response(struct hil_dev *dev) { hil_packet p; char *buf; int i, idx; - idx = kbd->idx4 / 4; - p = kbd->data[idx - 1]; + idx = dev->idx4 / 4; + p = dev->data[idx - 1]; switch (p & HIL_PKT_DATA_MASK) { case HIL_CMD_IDD: - buf = kbd->idd; + buf = dev->idd; break; case HIL_CMD_RSC: - buf = kbd->rsc; + buf = dev->rsc; break; case HIL_CMD_EXD: - buf = kbd->exd; + buf = dev->exd; break; case HIL_CMD_RNM: - kbd->rnm[HIL_KBD_MAX_LENGTH] = 0; - buf = kbd->rnm; + dev->rnm[HIL_PACKET_MAX_LENGTH] = 0; + buf = dev->rnm; break; default: @@ -132,14 +132,14 @@ static void hil_kbd_handle_command_response(struct hil_kbd *kbd) } for (i = 0; i < idx; i++) - buf[i] = kbd->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_KBD_MAX_LENGTH; i++) + buf[i] = dev->data[i] & HIL_PKT_DATA_MASK; + for (; i < HIL_PACKET_MAX_LENGTH; i++) buf[i] = 0; out: - complete(&kbd->cmd_done); + complete(&dev->cmd_done); } -static void hil_kbd_handle_key_events(struct hil_kbd *kbd) +static void hil_dev_handle_key_events(struct hil_dev *kbd) { struct input_dev *dev = kbd->dev; int idx = kbd->idx4 / 4; @@ -198,125 +198,125 @@ static void hil_kbd_handle_key_events(struct hil_kbd *kbd) input_sync(dev); } -static void hil_kbd_process_err(struct hil_kbd *kbd) +static void hil_dev_process_err(struct hil_dev *dev) { printk(KERN_WARNING PREFIX "errored HIL packet\n"); - kbd->idx4 = 0; - complete(&kbd->cmd_done); /* just in case somebody is waiting */ + dev->idx4 = 0; + complete(&dev->cmd_done); /* just in case somebody is waiting */ } -static irqreturn_t hil_kbd_interrupt(struct serio *serio, +static irqreturn_t hil_dev_interrupt(struct serio *serio, unsigned char data, unsigned int flags) { - struct hil_kbd *kbd; + struct hil_dev *dev; hil_packet packet; int idx; - kbd = serio_get_drvdata(serio); - BUG_ON(kbd == NULL); + dev = serio_get_drvdata(serio); + BUG_ON(dev == NULL); - if (kbd->idx4 >= HIL_KBD_MAX_LENGTH * sizeof(hil_packet)) { - hil_kbd_process_err(kbd); + if (dev->idx4 >= HIL_PACKET_MAX_LENGTH * sizeof(hil_packet)) { + hil_dev_process_err(dev); goto out; } - idx = kbd->idx4 / 4; - if (!(kbd->idx4 % 4)) - kbd->data[idx] = 0; - packet = kbd->data[idx]; - packet |= ((hil_packet)data) << ((3 - (kbd->idx4 % 4)) * 8); - kbd->data[idx] = packet; + idx = dev->idx4 / 4; + if (!(dev->idx4 % 4)) + dev->data[idx] = 0; + packet = dev->data[idx]; + packet |= ((hil_packet)data) << ((3 - (dev->idx4 % 4)) * 8); + dev->data[idx] = packet; /* Records of N 4-byte hil_packets must terminate with a command. */ - if ((++kbd->idx4 % 4) == 0) { + if ((++dev->idx4 % 4) == 0) { if ((packet & 0xffff0000) != HIL_ERR_INT) { - hil_kbd_process_err(kbd); + hil_dev_process_err(dev); } else if (packet & HIL_PKT_CMD) { - if (hil_kbd_is_command_response(packet)) - hil_kbd_handle_command_response(kbd); + if (hil_dev_is_command_response(packet)) + hil_dev_handle_command_response(dev); else - hil_kbd_handle_key_events(kbd); - kbd->idx4 = 0; + hil_dev_handle_key_events(dev); + dev->idx4 = 0; } } out: return IRQ_HANDLED; } -static void hil_kbd_disconnect(struct serio *serio) +static void hil_dev_disconnect(struct serio *serio) { - struct hil_kbd *kbd = serio_get_drvdata(serio); + struct hil_dev *dev = serio_get_drvdata(serio); - BUG_ON(kbd == NULL); + BUG_ON(dev == NULL); serio_close(serio); - input_unregister_device(kbd->dev); - kfree(kbd); + input_unregister_device(dev->dev); + kfree(dev); } -static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) +static int hil_dev_connect(struct serio *serio, struct serio_driver *drv) { - struct hil_kbd *kbd; + struct hil_dev *dev; struct input_dev *input_dev; uint8_t did, *idd; int i; int error; - kbd = kzalloc(sizeof(*kbd), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); input_dev = input_allocate_device(); - if (!kbd || !input_dev) { + if (!dev || !input_dev) { error = -ENOMEM; goto bail0; } - kbd->serio = serio; - kbd->dev = input_dev; + dev->serio = serio; + dev->dev = input_dev; error = serio_open(serio, drv); if (error) goto bail0; - serio_set_drvdata(serio, kbd); + serio_set_drvdata(serio, dev); /* Get device info. MLC driver supplies devid/status/etc. */ - init_completion(&kbd->cmd_done); + init_completion(&dev->cmd_done); serio_write(serio, 0); serio_write(serio, 0); serio_write(serio, HIL_PKT_CMD >> 8); serio_write(serio, HIL_CMD_IDD); - error = wait_for_completion_killable(&kbd->cmd_done); + error = wait_for_completion_killable(&dev->cmd_done); if (error) goto bail1; - init_completion(&kbd->cmd_done); + init_completion(&dev->cmd_done); serio_write(serio, 0); serio_write(serio, 0); serio_write(serio, HIL_PKT_CMD >> 8); serio_write(serio, HIL_CMD_RSC); - error = wait_for_completion_killable(&kbd->cmd_done); + error = wait_for_completion_killable(&dev->cmd_done); if (error) goto bail1; - init_completion(&kbd->cmd_done); + init_completion(&dev->cmd_done); serio_write(serio, 0); serio_write(serio, 0); serio_write(serio, HIL_PKT_CMD >> 8); serio_write(serio, HIL_CMD_RNM); - error = wait_for_completion_killable(&kbd->cmd_done); + error = wait_for_completion_killable(&dev->cmd_done); if (error) goto bail1; - init_completion(&kbd->cmd_done); + init_completion(&dev->cmd_done); serio_write(serio, 0); serio_write(serio, 0); serio_write(serio, HIL_PKT_CMD >> 8); serio_write(serio, HIL_CMD_EXD); - error = wait_for_completion_killable(&kbd->cmd_done); + error = wait_for_completion_killable(&dev->cmd_done); if (error) goto bail1; - did = kbd->idd[0]; - idd = kbd->idd + 1; + did = dev->idd[0]; + idd = dev->idd + 1; switch (did & HIL_IDD_DID_TYPE_MASK) { case HIL_IDD_DID_TYPE_KB_INTEGRAL: case HIL_IDD_DID_TYPE_KB_ITF: @@ -340,7 +340,7 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) input_dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE; input_dev->keycodesize = sizeof(hil_kbd_set1[0]); input_dev->keycode = hil_kbd_set1; - input_dev->name = strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME; + input_dev->name = strlen(dev->rnm) ? dev->rnm : HIL_GENERIC_NAME; input_dev->phys = "hpkbd/input0"; /* XXX */ input_dev->id.bustype = BUS_HIL; @@ -361,7 +361,7 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) serio_write(serio, HIL_CMD_EK1); /* Enable Keyswitch Autorepeat 1 */ /* No need to wait for completion */ - error = input_register_device(kbd->dev); + error = input_register_device(input_dev); if (error) goto bail1; @@ -372,11 +372,11 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) serio_set_drvdata(serio, NULL); bail0: input_free_device(input_dev); - kfree(kbd); + kfree(dev); return error; } -static struct serio_device_id hil_kbd_ids[] = { +static struct serio_device_id hil_dev_ids[] = { { .type = SERIO_HIL_MLC, .proto = SERIO_HIL, @@ -386,26 +386,26 @@ static struct serio_device_id hil_kbd_ids[] = { { 0 } }; -static struct serio_driver hil_kbd_serio_drv = { +static struct serio_driver hil_serio_drv = { .driver = { .name = "hil_kbd", }, .description = "HP HIL keyboard driver", - .id_table = hil_kbd_ids, - .connect = hil_kbd_connect, - .disconnect = hil_kbd_disconnect, - .interrupt = hil_kbd_interrupt + .id_table = hil_dev_ids, + .connect = hil_dev_connect, + .disconnect = hil_dev_disconnect, + .interrupt = hil_dev_interrupt }; -static int __init hil_kbd_init(void) +static int __init hil_dev_init(void) { - return serio_register_driver(&hil_kbd_serio_drv); + return serio_register_driver(&hil_serio_drv); } -static void __exit hil_kbd_exit(void) +static void __exit hil_dev_exit(void) { - serio_unregister_driver(&hil_kbd_serio_drv); + serio_unregister_driver(&hil_serio_drv); } -module_init(hil_kbd_init); -module_exit(hil_kbd_exit); +module_init(hil_dev_init); +module_exit(hil_dev_exit); -- cgit v1.2.3-18-g5258 From fa71c605c2bb4d816514c2611ad53f48007f1fd3 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 7 Aug 2009 23:17:47 -0700 Subject: Input: combine hil_kbd and hil_ptr drivers hil_kbd and hil_ptr look like twins so it makes sense to combine them into a single driver. [deller@gmx.de: add MODULE_ALIAS() entry for mouse] Tested-by: Helge Deller Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/Kconfig | 5 +- drivers/input/keyboard/hil_kbd.c | 251 +++++++++++++++++++--- drivers/input/mouse/Kconfig | 8 - drivers/input/mouse/Makefile | 1 - drivers/input/mouse/hil_ptr.c | 447 --------------------------------------- 5 files changed, 219 insertions(+), 493 deletions(-) delete mode 100644 drivers/input/mouse/hil_ptr.c (limited to 'drivers') diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index a6b989a9dc0..5239e25e88a 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -187,7 +187,7 @@ config KEYBOARD_HIL_OLD submenu. config KEYBOARD_HIL - tristate "HP HIL keyboard support" + tristate "HP HIL keyboard/pointer support" depends on GSC || HP300 default y select HP_SDC @@ -196,7 +196,8 @@ config KEYBOARD_HIL help The "Human Interface Loop" is a older, 8-channel USB-like controller used in several Hewlett Packard models. - This driver implements support for HIL-keyboards attached + This driver implements support for HIL-keyboards and pointing + devices (mice, tablets, touchscreens) attached to your machine, so normally you should say Y here. config KEYBOARD_HP6XX diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c index 235a669a0ac..c83f4b2ec7d 100644 --- a/drivers/input/keyboard/hil_kbd.c +++ b/drivers/input/keyboard/hil_kbd.c @@ -41,13 +41,13 @@ #include #include -#define PREFIX "HIL KEYB: " -#define HIL_GENERIC_NAME "HIL keyboard" +#define PREFIX "HIL: " MODULE_AUTHOR("Brian S. Julin "); -MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver"); +MODULE_DESCRIPTION("HIL keyboard/mouse driver"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_ALIAS("serio:ty03pr25id00ex*"); +MODULE_ALIAS("serio:ty03pr25id00ex*"); /* HIL keyboard */ +MODULE_ALIAS("serio:ty03pr25id0Fex*"); /* HIL mouse */ #define HIL_PACKET_MAX_LENGTH 16 @@ -82,6 +82,11 @@ struct hil_dev { char rnm[HIL_PACKET_MAX_LENGTH + 1]; /* RNM record + NULL term. */ struct completion cmd_done; + + bool is_pointer; + /* Extra device details needed for pointing devices. */ + unsigned int nbtn, naxes; + unsigned int btnmap[7]; }; static bool hil_dev_is_command_response(hil_packet p) @@ -139,7 +144,7 @@ static void hil_dev_handle_command_response(struct hil_dev *dev) complete(&dev->cmd_done); } -static void hil_dev_handle_key_events(struct hil_dev *kbd) +static void hil_dev_handle_kbd_events(struct hil_dev *kbd) { struct input_dev *dev = kbd->dev; int idx = kbd->idx4 / 4; @@ -198,6 +203,67 @@ static void hil_dev_handle_key_events(struct hil_dev *kbd) input_sync(dev); } +static void hil_dev_handle_ptr_events(struct hil_dev *ptr) +{ + struct input_dev *dev = ptr->dev; + int idx = ptr->idx4 / 4; + hil_packet p = ptr->data[idx - 1]; + int i, cnt, laxis; + bool absdev, ax16; + + if ((p & HIL_CMDCT_POL) != idx - 1) { + printk(KERN_WARNING PREFIX + "Malformed poll packet %x (idx = %i)\n", p, idx); + return; + } + + i = (p & HIL_POL_AXIS_ALT) ? 3 : 0; + laxis = (p & HIL_POL_NUM_AXES_MASK) + i; + + ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */ + absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS; + + for (cnt = 1; i < laxis; i++) { + unsigned int lo, hi, val; + + lo = ptr->data[cnt++] & HIL_PKT_DATA_MASK; + hi = ax16 ? (ptr->data[cnt++] & HIL_PKT_DATA_MASK) : 0; + + if (absdev) { + val = lo + (hi << 8); +#ifdef TABLET_AUTOADJUST + if (val < dev->absmin[ABS_X + i]) + dev->absmin[ABS_X + i] = val; + if (val > dev->absmax[ABS_X + i]) + dev->absmax[ABS_X + i] = val; +#endif + if (i%3) val = dev->absmax[ABS_X + i] - val; + input_report_abs(dev, ABS_X + i, val); + } else { + val = (int) (((int8_t)lo) | ((int8_t)hi << 8)); + if (i % 3) + val *= -1; + input_report_rel(dev, REL_X + i, val); + } + } + + while (cnt < idx - 1) { + unsigned int btn = ptr->data[cnt++]; + int up = btn & 1; + + btn &= 0xfe; + if (btn == 0x8e) + continue; /* TODO: proximity == touch? */ + if (btn > 0x8c || btn < 0x80) + continue; + btn = (btn - 0x80) >> 1; + btn = ptr->btnmap[btn]; + input_report_key(dev, btn, !up); + } + + input_sync(dev); +} + static void hil_dev_process_err(struct hil_dev *dev) { printk(KERN_WARNING PREFIX "errored HIL packet\n"); @@ -234,8 +300,10 @@ static irqreturn_t hil_dev_interrupt(struct serio *serio, } else if (packet & HIL_PKT_CMD) { if (hil_dev_is_command_response(packet)) hil_dev_handle_command_response(dev); + else if (dev->is_pointer) + hil_dev_handle_ptr_events(dev); else - hil_dev_handle_key_events(dev); + hil_dev_handle_kbd_events(dev); dev->idx4 = 0; } } @@ -251,15 +319,130 @@ static void hil_dev_disconnect(struct serio *serio) serio_close(serio); input_unregister_device(dev->dev); + serio_set_drvdata(serio, NULL); kfree(dev); } +static void hil_dev_keyboard_setup(struct hil_dev *kbd) +{ + struct input_dev *input_dev = kbd->dev; + uint8_t did = kbd->idd[0]; + int i; + + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); + input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) | + BIT_MASK(LED_SCROLLL); + + for (i = 0; i < 128; i++) { + __set_bit(hil_kbd_set1[i], input_dev->keybit); + __set_bit(hil_kbd_set3[i], input_dev->keybit); + } + __clear_bit(KEY_RESERVED, input_dev->keybit); + + input_dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE; + input_dev->keycodesize = sizeof(hil_kbd_set1[0]); + input_dev->keycode = hil_kbd_set1; + + input_dev->name = strlen(kbd->rnm) ? kbd->rnm : "HIL keyboard"; + input_dev->phys = "hpkbd/input0"; + + printk(KERN_INFO PREFIX "HIL keyboard found (did = 0x%02x, lang = %s)\n", + did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]); +} + +static void hil_dev_pointer_setup(struct hil_dev *ptr) +{ + struct input_dev *input_dev = ptr->dev; + uint8_t did = ptr->idd[0]; + uint8_t *idd = ptr->idd + 1; + unsigned int naxsets = HIL_IDD_NUM_AXSETS(*idd); + unsigned int i, btntype; + const char *txt; + + ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd); + + switch (did & HIL_IDD_DID_TYPE_MASK) { + case HIL_IDD_DID_TYPE_REL: + input_dev->evbit[0] = BIT_MASK(EV_REL); + + for (i = 0; i < ptr->naxes; i++) + __set_bit(REL_X + i, input_dev->relbit); + + for (i = 3; naxsets > 1 && i < ptr->naxes + 3; i++) + __set_bit(REL_X + i, input_dev->relbit); + + txt = "relative"; + break; + + case HIL_IDD_DID_TYPE_ABS: + input_dev->evbit[0] = BIT_MASK(EV_ABS); + + for (i = 0; i < ptr->naxes; i++) + input_set_abs_params(input_dev, ABS_X + i, + 0, HIL_IDD_AXIS_MAX(idd, i), 0, 0); + + for (i = 3; naxsets > 1 && i < ptr->naxes + 3; i++) + input_set_abs_params(input_dev, ABS_X + i, + 0, HIL_IDD_AXIS_MAX(idd, i - 3), 0, 0); + +#ifdef TABLET_AUTOADJUST + for (i = 0; i < ABS_MAX; i++) { + int diff = input_dev->absmax[ABS_X + i] / 10; + input_dev->absmin[ABS_X + i] += diff; + input_dev->absmax[ABS_X + i] -= diff; + } +#endif + + txt = "absolute"; + break; + + default: + BUG(); + } + + ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd); + if (ptr->nbtn) + input_dev->evbit[0] |= BIT_MASK(EV_KEY); + + btntype = BTN_MISC; + if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET) +#ifdef TABLET_SIMULATES_MOUSE + btntype = BTN_TOUCH; +#else + btntype = BTN_DIGI; +#endif + if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN) + btntype = BTN_TOUCH; + + if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE) + btntype = BTN_MOUSE; + + for (i = 0; i < ptr->nbtn; i++) { + __set_bit(btntype | i, input_dev->keybit); + ptr->btnmap[i] = btntype | i; + } + + if (btntype == BTN_MOUSE) { + /* Swap buttons 2 and 3 */ + ptr->btnmap[1] = BTN_MIDDLE; + ptr->btnmap[2] = BTN_RIGHT; + } + + input_dev->name = strlen(ptr->rnm) ? ptr->rnm : "HIL pointer device"; + + printk(KERN_INFO PREFIX + "HIL pointer device found (did: 0x%02x, axis: %s)\n", + did, txt); + printk(KERN_INFO PREFIX + "HIL pointer has %i buttons and %i sets of %i axes\n", + ptr->nbtn, naxsets, ptr->naxes); +} + static int hil_dev_connect(struct serio *serio, struct serio_driver *drv) { struct hil_dev *dev; struct input_dev *input_dev; uint8_t did, *idd; - int i; int error; dev = kzalloc(sizeof(*dev), GFP_KERNEL); @@ -317,49 +500,47 @@ static int hil_dev_connect(struct serio *serio, struct serio_driver *drv) did = dev->idd[0]; idd = dev->idd + 1; + switch (did & HIL_IDD_DID_TYPE_MASK) { case HIL_IDD_DID_TYPE_KB_INTEGRAL: case HIL_IDD_DID_TYPE_KB_ITF: case HIL_IDD_DID_TYPE_KB_RSVD: case HIL_IDD_DID_TYPE_CHAR: - printk(KERN_INFO PREFIX "HIL keyboard found (did = 0x%02x, lang = %s)\n", - did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]); + if (HIL_IDD_NUM_BUTTONS(idd) || + HIL_IDD_NUM_AXES_PER_SET(*idd)) { + printk(KERN_INFO PREFIX + "combo devices are not supported.\n"); + goto bail1; + } + + dev->is_pointer = false; + hil_dev_keyboard_setup(dev); break; - default: - goto bail1; - } - if (HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) { - printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n"); + case HIL_IDD_DID_TYPE_REL: + case HIL_IDD_DID_TYPE_ABS: + dev->is_pointer = true; + hil_dev_pointer_setup(dev); + break; + + default: goto bail1; } - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); - input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) | - BIT_MASK(LED_SCROLLL); - input_dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE; - input_dev->keycodesize = sizeof(hil_kbd_set1[0]); - input_dev->keycode = hil_kbd_set1; - input_dev->name = strlen(dev->rnm) ? dev->rnm : HIL_GENERIC_NAME; - input_dev->phys = "hpkbd/input0"; /* XXX */ - input_dev->id.bustype = BUS_HIL; input_dev->id.vendor = PCI_VENDOR_ID_HP; input_dev->id.product = 0x0001; /* TODO: get from kbd->rsc */ input_dev->id.version = 0x0100; /* TODO: get from kbd->rsc */ input_dev->dev.parent = &serio->dev; - for (i = 0; i < 128; i++) { - __set_bit(hil_kbd_set1[i], input_dev->keybit); - __set_bit(hil_kbd_set3[i], input_dev->keybit); + if (!dev->is_pointer) { + serio_write(serio, 0); + serio_write(serio, 0); + serio_write(serio, HIL_PKT_CMD >> 8); + /* Enable Keyswitch Autorepeat 1 */ + serio_write(serio, HIL_CMD_EK1); + /* No need to wait for completion */ } - __clear_bit(KEY_RESERVED, input_dev->keybit); - - serio_write(serio, 0); - serio_write(serio, 0); - serio_write(serio, HIL_PKT_CMD >> 8); - serio_write(serio, HIL_CMD_EK1); /* Enable Keyswitch Autorepeat 1 */ - /* No need to wait for completion */ error = input_register_device(input_dev); if (error) @@ -388,9 +569,9 @@ static struct serio_device_id hil_dev_ids[] = { static struct serio_driver hil_serio_drv = { .driver = { - .name = "hil_kbd", + .name = "hil_dev", }, - .description = "HP HIL keyboard driver", + .description = "HP HIL keyboard/mouse/tablet driver", .id_table = hil_dev_ids, .connect = hil_dev_connect, .disconnect = hil_dev_disconnect, diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 8a2c5b14c8d..90bef5d498f 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -262,14 +262,6 @@ config MOUSE_VSXXXAA described in the source file). This driver also works with the digitizer (VSXXX-AB) DEC produced. -config MOUSE_HIL - tristate "HIL pointers (mice etc)." - depends on GSC || HP300 - select HP_SDC - select HIL_MLC - help - Say Y here to support HIL pointers. - config MOUSE_GPIO tristate "GPIO mouse" depends on GENERIC_GPIO diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 010f265ec15..ea58c9a372b 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o -obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o obj-$(CONFIG_MOUSE_INPORT) += inport.o obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o diff --git a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c deleted file mode 100644 index cd12c2d8fa0..00000000000 --- a/drivers/input/mouse/hil_ptr.c +++ /dev/null @@ -1,447 +0,0 @@ -/* - * Generic linux-input device driver for axis-bearing devices - * - * Copyright (c) 2001 Brian S. Julin - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL"). - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * - * References: - * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define PREFIX "HIL PTR: " -#define HIL_GENERIC_NAME "HIL pointer device" - -MODULE_AUTHOR("Brian S. Julin "); -MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver"); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_ALIAS("serio:ty03pr25id0Fex*"); - -#define TABLET_SIMULATES_MOUSE /* allow tablet to be used as mouse */ -#undef TABLET_AUTOADJUST /* auto-adjust valid tablet ranges */ - - -#define HIL_PTR_MAX_LENGTH 16 - -struct hil_ptr { - struct input_dev *dev; - struct serio *serio; - - /* Input buffer and index for packets from HIL bus. */ - hil_packet data[HIL_PTR_MAX_LENGTH]; - int idx4; /* four counts per packet */ - - /* Raw device info records from HIL bus, see hil.h for fields. */ - char idd[HIL_PTR_MAX_LENGTH]; /* DID byte and IDD record */ - char rsc[HIL_PTR_MAX_LENGTH]; /* RSC record */ - char exd[HIL_PTR_MAX_LENGTH]; /* EXD record */ - char rnm[HIL_PTR_MAX_LENGTH + 1]; /* RNM record + NULL term. */ - - /* Extra device details not contained in struct input_dev. */ - unsigned int nbtn, naxes; - unsigned int btnmap[7]; - - /* Something to sleep around with. */ - struct semaphore sem; -}; - -/* Process a complete packet after transfer from the HIL */ -static void hil_ptr_process_record(struct hil_ptr *ptr) -{ - struct input_dev *dev = ptr->dev; - hil_packet *data = ptr->data; - hil_packet p; - int idx, i, cnt, laxis; - int ax16, absdev; - - idx = ptr->idx4/4; - p = data[idx - 1]; - - if ((p & ~HIL_CMDCT_POL) == - (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) - goto report; - if ((p & ~HIL_CMDCT_RPL) == - (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) - goto report; - - /* Not a poll response. See if we are loading config records. */ - switch (p & HIL_PKT_DATA_MASK) { - case HIL_CMD_IDD: - for (i = 0; i < idx; i++) - ptr->idd[i] = ptr->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_PTR_MAX_LENGTH; i++) - ptr->idd[i] = 0; - break; - - case HIL_CMD_RSC: - for (i = 0; i < idx; i++) - ptr->rsc[i] = ptr->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_PTR_MAX_LENGTH; i++) - ptr->rsc[i] = 0; - break; - - case HIL_CMD_EXD: - for (i = 0; i < idx; i++) - ptr->exd[i] = ptr->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_PTR_MAX_LENGTH; i++) - ptr->exd[i] = 0; - break; - - case HIL_CMD_RNM: - for (i = 0; i < idx; i++) - ptr->rnm[i] = ptr->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_PTR_MAX_LENGTH + 1; i++) - ptr->rnm[i] = 0; - break; - - default: - /* These occur when device isn't present */ - if (p == (HIL_ERR_INT | HIL_PKT_CMD)) - break; - /* Anything else we'd like to know about. */ - printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p); - break; - } - goto out; - - report: - if ((p & HIL_CMDCT_POL) != idx - 1) { - printk(KERN_WARNING PREFIX - "Malformed poll packet %x (idx = %i)\n", p, idx); - goto out; - } - - i = (ptr->data[0] & HIL_POL_AXIS_ALT) ? 3 : 0; - laxis = ptr->data[0] & HIL_POL_NUM_AXES_MASK; - laxis += i; - - ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */ - absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS; - - for (cnt = 1; i < laxis; i++) { - unsigned int lo,hi,val; - lo = ptr->data[cnt++] & HIL_PKT_DATA_MASK; - hi = ax16 ? (ptr->data[cnt++] & HIL_PKT_DATA_MASK) : 0; - if (absdev) { - val = lo + (hi<<8); -#ifdef TABLET_AUTOADJUST - if (val < dev->absmin[ABS_X + i]) - dev->absmin[ABS_X + i] = val; - if (val > dev->absmax[ABS_X + i]) - dev->absmax[ABS_X + i] = val; -#endif - if (i%3) val = dev->absmax[ABS_X + i] - val; - input_report_abs(dev, ABS_X + i, val); - } else { - val = (int) (((int8_t)lo) | ((int8_t)hi<<8)); - if (i%3) - val *= -1; - input_report_rel(dev, REL_X + i, val); - } - } - - while (cnt < idx - 1) { - unsigned int btn; - int up; - btn = ptr->data[cnt++]; - up = btn & 1; - btn &= 0xfe; - if (btn == 0x8e) - continue; /* TODO: proximity == touch? */ - else - if ((btn > 0x8c) || (btn < 0x80)) - continue; - btn = (btn - 0x80) >> 1; - btn = ptr->btnmap[btn]; - input_report_key(dev, btn, !up); - } - input_sync(dev); - out: - ptr->idx4 = 0; - up(&ptr->sem); -} - -static void hil_ptr_process_err(struct hil_ptr *ptr) -{ - printk(KERN_WARNING PREFIX "errored HIL packet\n"); - ptr->idx4 = 0; - up(&ptr->sem); -} - -static irqreturn_t hil_ptr_interrupt(struct serio *serio, - unsigned char data, unsigned int flags) -{ - struct hil_ptr *ptr; - hil_packet packet; - int idx; - - ptr = serio_get_drvdata(serio); - BUG_ON(ptr == NULL); - - if (ptr->idx4 >= (HIL_PTR_MAX_LENGTH * sizeof(hil_packet))) { - hil_ptr_process_err(ptr); - return IRQ_HANDLED; - } - idx = ptr->idx4/4; - if (!(ptr->idx4 % 4)) - ptr->data[idx] = 0; - packet = ptr->data[idx]; - packet |= ((hil_packet)data) << ((3 - (ptr->idx4 % 4)) * 8); - ptr->data[idx] = packet; - - /* Records of N 4-byte hil_packets must terminate with a command. */ - if ((++(ptr->idx4)) % 4) - return IRQ_HANDLED; - if ((packet & 0xffff0000) != HIL_ERR_INT) { - hil_ptr_process_err(ptr); - return IRQ_HANDLED; - } - if (packet & HIL_PKT_CMD) - hil_ptr_process_record(ptr); - - return IRQ_HANDLED; -} - -static void hil_ptr_disconnect(struct serio *serio) -{ - struct hil_ptr *ptr; - - ptr = serio_get_drvdata(serio); - BUG_ON(ptr == NULL); - - serio_close(serio); - input_unregister_device(ptr->dev); - kfree(ptr); -} - -static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) -{ - struct hil_ptr *ptr; - const char *txt; - unsigned int i, naxsets, btntype; - uint8_t did, *idd; - int error; - - ptr = kzalloc(sizeof(struct hil_ptr), GFP_KERNEL); - if (!ptr) - return -ENOMEM; - - ptr->dev = input_allocate_device(); - if (!ptr->dev) { - error = -ENOMEM; - goto bail0; - } - - error = serio_open(serio, driver); - if (error) - goto bail1; - - serio_set_drvdata(serio, ptr); - ptr->serio = serio; - - init_MUTEX_LOCKED(&ptr->sem); - - /* Get device info. MLC driver supplies devid/status/etc. */ - serio_write(serio, 0); - serio_write(serio, 0); - serio_write(serio, HIL_PKT_CMD >> 8); - serio_write(serio, HIL_CMD_IDD); - down(&ptr->sem); - - serio_write(serio, 0); - serio_write(serio, 0); - serio_write(serio, HIL_PKT_CMD >> 8); - serio_write(serio, HIL_CMD_RSC); - down(&ptr->sem); - - serio_write(serio, 0); - serio_write(serio, 0); - serio_write(serio, HIL_PKT_CMD >> 8); - serio_write(serio, HIL_CMD_RNM); - down(&ptr->sem); - - serio_write(serio, 0); - serio_write(serio, 0); - serio_write(serio, HIL_PKT_CMD >> 8); - serio_write(serio, HIL_CMD_EXD); - down(&ptr->sem); - - up(&ptr->sem); - - did = ptr->idd[0]; - idd = ptr->idd + 1; - txt = "unknown"; - - if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) { - ptr->dev->evbit[0] = BIT_MASK(EV_REL); - txt = "relative"; - } - - if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_ABS) { - ptr->dev->evbit[0] = BIT_MASK(EV_ABS); - txt = "absolute"; - } - - if (!ptr->dev->evbit[0]) { - error = -ENODEV; - goto bail2; - } - - ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd); - if (ptr->nbtn) - ptr->dev->evbit[0] |= BIT_MASK(EV_KEY); - - naxsets = HIL_IDD_NUM_AXSETS(*idd); - ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd); - - printk(KERN_INFO PREFIX "HIL pointer device found (did: 0x%02x, axis: %s)\n", - did, txt); - printk(KERN_INFO PREFIX "HIL pointer has %i buttons and %i sets of %i axes\n", - ptr->nbtn, naxsets, ptr->naxes); - - btntype = BTN_MISC; - if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET) -#ifdef TABLET_SIMULATES_MOUSE - btntype = BTN_TOUCH; -#else - btntype = BTN_DIGI; -#endif - if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN) - btntype = BTN_TOUCH; - - if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE) - btntype = BTN_MOUSE; - - for (i = 0; i < ptr->nbtn; i++) { - set_bit(btntype | i, ptr->dev->keybit); - ptr->btnmap[i] = btntype | i; - } - - if (btntype == BTN_MOUSE) { - /* Swap buttons 2 and 3 */ - ptr->btnmap[1] = BTN_MIDDLE; - ptr->btnmap[2] = BTN_RIGHT; - } - - if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) { - for (i = 0; i < ptr->naxes; i++) - set_bit(REL_X + i, ptr->dev->relbit); - for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) - set_bit(REL_X + i, ptr->dev->relbit); - } else { - for (i = 0; i < ptr->naxes; i++) { - set_bit(ABS_X + i, ptr->dev->absbit); - ptr->dev->absmin[ABS_X + i] = 0; - ptr->dev->absmax[ABS_X + i] = - HIL_IDD_AXIS_MAX((ptr->idd + 1), i); - } - for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) { - set_bit(ABS_X + i, ptr->dev->absbit); - ptr->dev->absmin[ABS_X + i] = 0; - ptr->dev->absmax[ABS_X + i] = - HIL_IDD_AXIS_MAX((ptr->idd + 1), (i - 3)); - } -#ifdef TABLET_AUTOADJUST - for (i = 0; i < ABS_MAX; i++) { - int diff = ptr->dev->absmax[ABS_X + i] / 10; - ptr->dev->absmin[ABS_X + i] += diff; - ptr->dev->absmax[ABS_X + i] -= diff; - } -#endif - } - - ptr->dev->name = strlen(ptr->rnm) ? ptr->rnm : HIL_GENERIC_NAME; - - ptr->dev->id.bustype = BUS_HIL; - ptr->dev->id.vendor = PCI_VENDOR_ID_HP; - ptr->dev->id.product = 0x0001; /* TODO: get from ptr->rsc */ - ptr->dev->id.version = 0x0100; /* TODO: get from ptr->rsc */ - ptr->dev->dev.parent = &serio->dev; - - error = input_register_device(ptr->dev); - if (error) { - printk(KERN_INFO PREFIX "Unable to register input device\n"); - goto bail2; - } - - printk(KERN_INFO "input: %s (%s), ID: %d\n", - ptr->dev->name, - (btntype == BTN_MOUSE) ? "HIL mouse":"HIL tablet or touchpad", - did); - - return 0; - - bail2: - serio_close(serio); - bail1: - input_free_device(ptr->dev); - bail0: - kfree(ptr); - serio_set_drvdata(serio, NULL); - return error; -} - -static struct serio_device_id hil_ptr_ids[] = { - { - .type = SERIO_HIL_MLC, - .proto = SERIO_HIL, - .id = SERIO_ANY, - .extra = SERIO_ANY, - }, - { 0 } -}; - -static struct serio_driver hil_ptr_serio_driver = { - .driver = { - .name = "hil_ptr", - }, - .description = "HP HIL mouse/tablet driver", - .id_table = hil_ptr_ids, - .connect = hil_ptr_connect, - .disconnect = hil_ptr_disconnect, - .interrupt = hil_ptr_interrupt -}; - -static int __init hil_ptr_init(void) -{ - return serio_register_driver(&hil_ptr_serio_driver); -} - -static void __exit hil_ptr_exit(void) -{ - serio_unregister_driver(&hil_ptr_serio_driver); -} - -module_init(hil_ptr_init); -module_exit(hil_ptr_exit); -- cgit v1.2.3-18-g5258 From 85a7f0ac5370901916a21935e1fafbe397b70f80 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 10 Aug 2009 12:50:03 +1000 Subject: crypto: mv_cesa - Add support for Orion5X crypto engine This adds support for Marvell's Cryptographic Engines and Security Accelerator (CESA) which can be found on a few SoC. Tested with dm-crypt. Acked-by: Nicolas Pitre Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Herbert Xu --- drivers/crypto/Kconfig | 13 + drivers/crypto/Makefile | 1 + drivers/crypto/mv_cesa.c | 606 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/crypto/mv_cesa.h | 119 ++++++++++ 4 files changed, 739 insertions(+) create mode 100644 drivers/crypto/mv_cesa.c create mode 100644 drivers/crypto/mv_cesa.h (limited to 'drivers') diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 1bb4b7fe458..b08403d7d1c 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -157,6 +157,19 @@ config S390_PRNG ANSI X9.17 standard. The PRNG is usable via the char device /dev/prandom. +config CRYPTO_DEV_MV_CESA + tristate "Marvell's Cryptographic Engine" + depends on PLAT_ORION + select CRYPTO_ALGAPI + select CRYPTO_AES + select CRYPTO_BLKCIPHER2 + help + This driver allows you to utilize the Cryptographic Engines and + Security Accelerator (CESA) which can be found on the Marvell Orion + and Kirkwood SoCs, such as QNAP's TS-209. + + Currently the driver supports AES in ECB and CBC mode without DMA. + config CRYPTO_DEV_HIFN_795X tristate "Driver HIFN 795x crypto accelerator chips" select CRYPTO_DES diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 9bf4a2bc884..6ffcb3f7f94 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o +obj-$(CONFIG_CRYPTO_DEV_MV_CESA) += mv_cesa.o obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/ diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c new file mode 100644 index 00000000000..b21ef635f35 --- /dev/null +++ b/drivers/crypto/mv_cesa.c @@ -0,0 +1,606 @@ +/* + * Support for Marvell's crypto engine which can be found on some Orion5X + * boards. + * + * Author: Sebastian Andrzej Siewior < sebastian at breakpoint dot cc > + * License: GPLv2 + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mv_cesa.h" +/* + * STM: + * /---------------------------------------\ + * | | request complete + * \./ | + * IDLE -> new request -> BUSY -> done -> DEQUEUE + * /°\ | + * | | more scatter entries + * \________________/ + */ +enum engine_status { + ENGINE_IDLE, + ENGINE_BUSY, + ENGINE_W_DEQUEUE, +}; + +/** + * struct req_progress - used for every crypt request + * @src_sg_it: sg iterator for src + * @dst_sg_it: sg iterator for dst + * @sg_src_left: bytes left in src to process (scatter list) + * @src_start: offset to add to src start position (scatter list) + * @crypt_len: length of current crypt process + * @sg_dst_left: bytes left dst to process in this scatter list + * @dst_start: offset to add to dst start position (scatter list) + * @total_req_bytes: total number of bytes processed (request). + * + * sg helper are used to iterate over the scatterlist. Since the size of the + * SRAM may be less than the scatter size, this struct struct is used to keep + * track of progress within current scatterlist. + */ +struct req_progress { + struct sg_mapping_iter src_sg_it; + struct sg_mapping_iter dst_sg_it; + + /* src mostly */ + int sg_src_left; + int src_start; + int crypt_len; + /* dst mostly */ + int sg_dst_left; + int dst_start; + int total_req_bytes; +}; + +struct crypto_priv { + void __iomem *reg; + void __iomem *sram; + int irq; + struct task_struct *queue_th; + + /* the lock protects queue and eng_st */ + spinlock_t lock; + struct crypto_queue queue; + enum engine_status eng_st; + struct ablkcipher_request *cur_req; + struct req_progress p; + int max_req_size; + int sram_size; +}; + +static struct crypto_priv *cpg; + +struct mv_ctx { + u8 aes_enc_key[AES_KEY_LEN]; + u32 aes_dec_key[8]; + int key_len; + u32 need_calc_aes_dkey; +}; + +enum crypto_op { + COP_AES_ECB, + COP_AES_CBC, +}; + +struct mv_req_ctx { + enum crypto_op op; + int decrypt; +}; + +static void compute_aes_dec_key(struct mv_ctx *ctx) +{ + struct crypto_aes_ctx gen_aes_key; + int key_pos; + + if (!ctx->need_calc_aes_dkey) + return; + + crypto_aes_expand_key(&gen_aes_key, ctx->aes_enc_key, ctx->key_len); + + key_pos = ctx->key_len + 24; + memcpy(ctx->aes_dec_key, &gen_aes_key.key_enc[key_pos], 4 * 4); + switch (ctx->key_len) { + case AES_KEYSIZE_256: + key_pos -= 2; + /* fall */ + case AES_KEYSIZE_192: + key_pos -= 2; + memcpy(&ctx->aes_dec_key[4], &gen_aes_key.key_enc[key_pos], + 4 * 4); + break; + } + ctx->need_calc_aes_dkey = 0; +} + +static int mv_setkey_aes(struct crypto_ablkcipher *cipher, const u8 *key, + unsigned int len) +{ + struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); + struct mv_ctx *ctx = crypto_tfm_ctx(tfm); + + switch (len) { + case AES_KEYSIZE_128: + case AES_KEYSIZE_192: + case AES_KEYSIZE_256: + break; + default: + crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + ctx->key_len = len; + ctx->need_calc_aes_dkey = 1; + + memcpy(ctx->aes_enc_key, key, AES_KEY_LEN); + return 0; +} + +static void setup_data_in(struct ablkcipher_request *req) +{ + int ret; + void *buf; + + if (!cpg->p.sg_src_left) { + ret = sg_miter_next(&cpg->p.src_sg_it); + BUG_ON(!ret); + cpg->p.sg_src_left = cpg->p.src_sg_it.length; + cpg->p.src_start = 0; + } + + cpg->p.crypt_len = min(cpg->p.sg_src_left, cpg->max_req_size); + + buf = cpg->p.src_sg_it.addr; + buf += cpg->p.src_start; + + memcpy(cpg->sram + SRAM_DATA_IN_START, buf, cpg->p.crypt_len); + + cpg->p.sg_src_left -= cpg->p.crypt_len; + cpg->p.src_start += cpg->p.crypt_len; +} + +static void mv_process_current_q(int first_block) +{ + struct ablkcipher_request *req = cpg->cur_req; + struct mv_ctx *ctx = crypto_tfm_ctx(req->base.tfm); + struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); + struct sec_accel_config op; + + switch (req_ctx->op) { + case COP_AES_ECB: + op.config = CFG_OP_CRYPT_ONLY | CFG_ENCM_AES | CFG_ENC_MODE_ECB; + break; + case COP_AES_CBC: + op.config = CFG_OP_CRYPT_ONLY | CFG_ENCM_AES | CFG_ENC_MODE_CBC; + op.enc_iv = ENC_IV_POINT(SRAM_DATA_IV) | + ENC_IV_BUF_POINT(SRAM_DATA_IV_BUF); + if (first_block) + memcpy(cpg->sram + SRAM_DATA_IV, req->info, 16); + break; + } + if (req_ctx->decrypt) { + op.config |= CFG_DIR_DEC; + memcpy(cpg->sram + SRAM_DATA_KEY_P, ctx->aes_dec_key, + AES_KEY_LEN); + } else { + op.config |= CFG_DIR_ENC; + memcpy(cpg->sram + SRAM_DATA_KEY_P, ctx->aes_enc_key, + AES_KEY_LEN); + } + + switch (ctx->key_len) { + case AES_KEYSIZE_128: + op.config |= CFG_AES_LEN_128; + break; + case AES_KEYSIZE_192: + op.config |= CFG_AES_LEN_192; + break; + case AES_KEYSIZE_256: + op.config |= CFG_AES_LEN_256; + break; + } + op.enc_p = ENC_P_SRC(SRAM_DATA_IN_START) | + ENC_P_DST(SRAM_DATA_OUT_START); + op.enc_key_p = SRAM_DATA_KEY_P; + + setup_data_in(req); + op.enc_len = cpg->p.crypt_len; + memcpy(cpg->sram + SRAM_CONFIG, &op, + sizeof(struct sec_accel_config)); + + writel(SRAM_CONFIG, cpg->reg + SEC_ACCEL_DESC_P0); + /* GO */ + writel(SEC_CMD_EN_SEC_ACCL0, cpg->reg + SEC_ACCEL_CMD); + + /* + * XXX: add timer if the interrupt does not occur for some mystery + * reason + */ +} + +static void mv_crypto_algo_completion(void) +{ + struct ablkcipher_request *req = cpg->cur_req; + struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); + + if (req_ctx->op != COP_AES_CBC) + return ; + + memcpy(req->info, cpg->sram + SRAM_DATA_IV_BUF, 16); +} + +static void dequeue_complete_req(void) +{ + struct ablkcipher_request *req = cpg->cur_req; + void *buf; + int ret; + + cpg->p.total_req_bytes += cpg->p.crypt_len; + do { + int dst_copy; + + if (!cpg->p.sg_dst_left) { + ret = sg_miter_next(&cpg->p.dst_sg_it); + BUG_ON(!ret); + cpg->p.sg_dst_left = cpg->p.dst_sg_it.length; + cpg->p.dst_start = 0; + } + + buf = cpg->p.dst_sg_it.addr; + buf += cpg->p.dst_start; + + dst_copy = min(cpg->p.crypt_len, cpg->p.sg_dst_left); + + memcpy(buf, cpg->sram + SRAM_DATA_OUT_START, dst_copy); + + cpg->p.sg_dst_left -= dst_copy; + cpg->p.crypt_len -= dst_copy; + cpg->p.dst_start += dst_copy; + } while (cpg->p.crypt_len > 0); + + BUG_ON(cpg->eng_st != ENGINE_W_DEQUEUE); + if (cpg->p.total_req_bytes < req->nbytes) { + /* process next scatter list entry */ + cpg->eng_st = ENGINE_BUSY; + mv_process_current_q(0); + } else { + sg_miter_stop(&cpg->p.src_sg_it); + sg_miter_stop(&cpg->p.dst_sg_it); + mv_crypto_algo_completion(); + cpg->eng_st = ENGINE_IDLE; + req->base.complete(&req->base, 0); + } +} + +static int count_sgs(struct scatterlist *sl, unsigned int total_bytes) +{ + int i = 0; + + do { + total_bytes -= sl[i].length; + i++; + + } while (total_bytes > 0); + + return i; +} + +static void mv_enqueue_new_req(struct ablkcipher_request *req) +{ + int num_sgs; + + cpg->cur_req = req; + memset(&cpg->p, 0, sizeof(struct req_progress)); + + num_sgs = count_sgs(req->src, req->nbytes); + sg_miter_start(&cpg->p.src_sg_it, req->src, num_sgs, SG_MITER_FROM_SG); + + num_sgs = count_sgs(req->dst, req->nbytes); + sg_miter_start(&cpg->p.dst_sg_it, req->dst, num_sgs, SG_MITER_TO_SG); + mv_process_current_q(1); +} + +static int queue_manag(void *data) +{ + cpg->eng_st = ENGINE_IDLE; + do { + struct ablkcipher_request *req; + struct crypto_async_request *async_req = NULL; + struct crypto_async_request *backlog; + + __set_current_state(TASK_INTERRUPTIBLE); + + if (cpg->eng_st == ENGINE_W_DEQUEUE) + dequeue_complete_req(); + + spin_lock_irq(&cpg->lock); + if (cpg->eng_st == ENGINE_IDLE) { + backlog = crypto_get_backlog(&cpg->queue); + async_req = crypto_dequeue_request(&cpg->queue); + if (async_req) { + BUG_ON(cpg->eng_st != ENGINE_IDLE); + cpg->eng_st = ENGINE_BUSY; + } + } + spin_unlock_irq(&cpg->lock); + + if (backlog) { + backlog->complete(backlog, -EINPROGRESS); + backlog = NULL; + } + + if (async_req) { + req = container_of(async_req, + struct ablkcipher_request, base); + mv_enqueue_new_req(req); + async_req = NULL; + } + + schedule(); + + } while (!kthread_should_stop()); + return 0; +} + +static int mv_handle_req(struct ablkcipher_request *req) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&cpg->lock, flags); + ret = ablkcipher_enqueue_request(&cpg->queue, req); + spin_unlock_irqrestore(&cpg->lock, flags); + wake_up_process(cpg->queue_th); + return ret; +} + +static int mv_enc_aes_ecb(struct ablkcipher_request *req) +{ + struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); + + req_ctx->op = COP_AES_ECB; + req_ctx->decrypt = 0; + + return mv_handle_req(req); +} + +static int mv_dec_aes_ecb(struct ablkcipher_request *req) +{ + struct mv_ctx *ctx = crypto_tfm_ctx(req->base.tfm); + struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); + + req_ctx->op = COP_AES_ECB; + req_ctx->decrypt = 1; + + compute_aes_dec_key(ctx); + return mv_handle_req(req); +} + +static int mv_enc_aes_cbc(struct ablkcipher_request *req) +{ + struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); + + req_ctx->op = COP_AES_CBC; + req_ctx->decrypt = 0; + + return mv_handle_req(req); +} + +static int mv_dec_aes_cbc(struct ablkcipher_request *req) +{ + struct mv_ctx *ctx = crypto_tfm_ctx(req->base.tfm); + struct mv_req_ctx *req_ctx = ablkcipher_request_ctx(req); + + req_ctx->op = COP_AES_CBC; + req_ctx->decrypt = 1; + + compute_aes_dec_key(ctx); + return mv_handle_req(req); +} + +static int mv_cra_init(struct crypto_tfm *tfm) +{ + tfm->crt_ablkcipher.reqsize = sizeof(struct mv_req_ctx); + return 0; +} + +irqreturn_t crypto_int(int irq, void *priv) +{ + u32 val; + + val = readl(cpg->reg + SEC_ACCEL_INT_STATUS); + if (!(val & SEC_INT_ACCEL0_DONE)) + return IRQ_NONE; + + val &= ~SEC_INT_ACCEL0_DONE; + writel(val, cpg->reg + FPGA_INT_STATUS); + writel(val, cpg->reg + SEC_ACCEL_INT_STATUS); + BUG_ON(cpg->eng_st != ENGINE_BUSY); + cpg->eng_st = ENGINE_W_DEQUEUE; + wake_up_process(cpg->queue_th); + return IRQ_HANDLED; +} + +struct crypto_alg mv_aes_alg_ecb = { + .cra_name = "ecb(aes)", + .cra_driver_name = "mv-ecb-aes", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = 16, + .cra_ctxsize = sizeof(struct mv_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = mv_cra_init, + .cra_u = { + .ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = mv_setkey_aes, + .encrypt = mv_enc_aes_ecb, + .decrypt = mv_dec_aes_ecb, + }, + }, +}; + +struct crypto_alg mv_aes_alg_cbc = { + .cra_name = "cbc(aes)", + .cra_driver_name = "mv-cbc-aes", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct mv_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = mv_cra_init, + .cra_u = { + .ablkcipher = { + .ivsize = AES_BLOCK_SIZE, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = mv_setkey_aes, + .encrypt = mv_enc_aes_cbc, + .decrypt = mv_dec_aes_cbc, + }, + }, +}; + +static int mv_probe(struct platform_device *pdev) +{ + struct crypto_priv *cp; + struct resource *res; + int irq; + int ret; + + if (cpg) { + printk(KERN_ERR "Second crypto dev?\n"); + return -EEXIST; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); + if (!res) + return -ENXIO; + + cp = kzalloc(sizeof(*cp), GFP_KERNEL); + if (!cp) + return -ENOMEM; + + spin_lock_init(&cp->lock); + crypto_init_queue(&cp->queue, 50); + cp->reg = ioremap(res->start, res->end - res->start + 1); + if (!cp->reg) { + ret = -ENOMEM; + goto err; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); + if (!res) { + ret = -ENXIO; + goto err_unmap_reg; + } + cp->sram_size = res->end - res->start + 1; + cp->max_req_size = cp->sram_size - SRAM_CFG_SPACE; + cp->sram = ioremap(res->start, cp->sram_size); + if (!cp->sram) { + ret = -ENOMEM; + goto err_unmap_reg; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0 || irq == NO_IRQ) { + ret = irq; + goto err_unmap_sram; + } + cp->irq = irq; + + platform_set_drvdata(pdev, cp); + cpg = cp; + + cp->queue_th = kthread_run(queue_manag, cp, "mv_crypto"); + if (IS_ERR(cp->queue_th)) { + ret = PTR_ERR(cp->queue_th); + goto err_thread; + } + + ret = request_irq(irq, crypto_int, IRQF_DISABLED, dev_name(&pdev->dev), + cp); + if (ret) + goto err_unmap_sram; + + writel(SEC_INT_ACCEL0_DONE, cpg->reg + SEC_ACCEL_INT_MASK); + writel(SEC_CFG_STOP_DIG_ERR, cpg->reg + SEC_ACCEL_CFG); + + ret = crypto_register_alg(&mv_aes_alg_ecb); + if (ret) + goto err_reg; + + ret = crypto_register_alg(&mv_aes_alg_cbc); + if (ret) + goto err_unreg_ecb; + return 0; +err_unreg_ecb: + crypto_unregister_alg(&mv_aes_alg_ecb); +err_thread: + free_irq(irq, cp); +err_reg: + kthread_stop(cp->queue_th); +err_unmap_sram: + iounmap(cp->sram); +err_unmap_reg: + iounmap(cp->reg); +err: + kfree(cp); + cpg = NULL; + platform_set_drvdata(pdev, NULL); + return ret; +} + +static int mv_remove(struct platform_device *pdev) +{ + struct crypto_priv *cp = platform_get_drvdata(pdev); + + crypto_unregister_alg(&mv_aes_alg_ecb); + crypto_unregister_alg(&mv_aes_alg_cbc); + kthread_stop(cp->queue_th); + free_irq(cp->irq, cp); + memset(cp->sram, 0, cp->sram_size); + iounmap(cp->sram); + iounmap(cp->reg); + kfree(cp); + cpg = NULL; + return 0; +} + +static struct platform_driver marvell_crypto = { + .probe = mv_probe, + .remove = mv_remove, + .driver = { + .owner = THIS_MODULE, + .name = "mv_crypto", + }, +}; +MODULE_ALIAS("platform:mv_crypto"); + +static int __init mv_crypto_init(void) +{ + return platform_driver_register(&marvell_crypto); +} +module_init(mv_crypto_init); + +static void __exit mv_crypto_exit(void) +{ + platform_driver_unregister(&marvell_crypto); +} +module_exit(mv_crypto_exit); + +MODULE_AUTHOR("Sebastian Andrzej Siewior "); +MODULE_DESCRIPTION("Support for Marvell's cryptographic engine"); +MODULE_LICENSE("GPL"); diff --git a/drivers/crypto/mv_cesa.h b/drivers/crypto/mv_cesa.h new file mode 100644 index 00000000000..c3e25d3bb17 --- /dev/null +++ b/drivers/crypto/mv_cesa.h @@ -0,0 +1,119 @@ +#ifndef __MV_CRYPTO_H__ + +#define DIGEST_INITIAL_VAL_A 0xdd00 +#define DES_CMD_REG 0xdd58 + +#define SEC_ACCEL_CMD 0xde00 +#define SEC_CMD_EN_SEC_ACCL0 (1 << 0) +#define SEC_CMD_EN_SEC_ACCL1 (1 << 1) +#define SEC_CMD_DISABLE_SEC (1 << 2) + +#define SEC_ACCEL_DESC_P0 0xde04 +#define SEC_DESC_P0_PTR(x) (x) + +#define SEC_ACCEL_DESC_P1 0xde14 +#define SEC_DESC_P1_PTR(x) (x) + +#define SEC_ACCEL_CFG 0xde08 +#define SEC_CFG_STOP_DIG_ERR (1 << 0) +#define SEC_CFG_CH0_W_IDMA (1 << 7) +#define SEC_CFG_CH1_W_IDMA (1 << 8) +#define SEC_CFG_ACT_CH0_IDMA (1 << 9) +#define SEC_CFG_ACT_CH1_IDMA (1 << 10) + +#define SEC_ACCEL_STATUS 0xde0c +#define SEC_ST_ACT_0 (1 << 0) +#define SEC_ST_ACT_1 (1 << 1) + +/* + * FPGA_INT_STATUS looks like a FPGA leftover and is documented only in Errata + * 4.12. It looks like that it was part of an IRQ-controller in FPGA and + * someone forgot to remove it while switching to the core and moving to + * SEC_ACCEL_INT_STATUS. + */ +#define FPGA_INT_STATUS 0xdd68 +#define SEC_ACCEL_INT_STATUS 0xde20 +#define SEC_INT_AUTH_DONE (1 << 0) +#define SEC_INT_DES_E_DONE (1 << 1) +#define SEC_INT_AES_E_DONE (1 << 2) +#define SEC_INT_AES_D_DONE (1 << 3) +#define SEC_INT_ENC_DONE (1 << 4) +#define SEC_INT_ACCEL0_DONE (1 << 5) +#define SEC_INT_ACCEL1_DONE (1 << 6) +#define SEC_INT_ACC0_IDMA_DONE (1 << 7) +#define SEC_INT_ACC1_IDMA_DONE (1 << 8) + +#define SEC_ACCEL_INT_MASK 0xde24 + +#define AES_KEY_LEN (8 * 4) + +struct sec_accel_config { + + u32 config; +#define CFG_OP_MAC_ONLY 0 +#define CFG_OP_CRYPT_ONLY 1 +#define CFG_OP_MAC_CRYPT 2 +#define CFG_OP_CRYPT_MAC 3 +#define CFG_MACM_MD5 (4 << 4) +#define CFG_MACM_SHA1 (5 << 4) +#define CFG_MACM_HMAC_MD5 (6 << 4) +#define CFG_MACM_HMAC_SHA1 (7 << 4) +#define CFG_ENCM_DES (1 << 8) +#define CFG_ENCM_3DES (2 << 8) +#define CFG_ENCM_AES (3 << 8) +#define CFG_DIR_ENC (0 << 12) +#define CFG_DIR_DEC (1 << 12) +#define CFG_ENC_MODE_ECB (0 << 16) +#define CFG_ENC_MODE_CBC (1 << 16) +#define CFG_3DES_EEE (0 << 20) +#define CFG_3DES_EDE (1 << 20) +#define CFG_AES_LEN_128 (0 << 24) +#define CFG_AES_LEN_192 (1 << 24) +#define CFG_AES_LEN_256 (2 << 24) + + u32 enc_p; +#define ENC_P_SRC(x) (x) +#define ENC_P_DST(x) ((x) << 16) + + u32 enc_len; +#define ENC_LEN(x) (x) + + u32 enc_key_p; +#define ENC_KEY_P(x) (x) + + u32 enc_iv; +#define ENC_IV_POINT(x) ((x) << 0) +#define ENC_IV_BUF_POINT(x) ((x) << 16) + + u32 mac_src_p; +#define MAC_SRC_DATA_P(x) (x) +#define MAC_SRC_TOTAL_LEN(x) ((x) << 16) + + u32 mac_digest; + u32 mac_iv; +}__attribute__ ((packed)); + /* + * /-----------\ 0 + * | ACCEL CFG | 4 * 8 + * |-----------| 0x20 + * | CRYPT KEY | 8 * 4 + * |-----------| 0x40 + * | IV IN | 4 * 4 + * |-----------| 0x40 (inplace) + * | IV BUF | 4 * 4 + * |-----------| 0x50 + * | DATA IN | 16 * x (max ->max_req_size) + * |-----------| 0x50 (inplace operation) + * | DATA OUT | 16 * x (max ->max_req_size) + * \-----------/ SRAM size + */ +#define SRAM_CONFIG 0x00 +#define SRAM_DATA_KEY_P 0x20 +#define SRAM_DATA_IV 0x40 +#define SRAM_DATA_IV_BUF 0x40 +#define SRAM_DATA_IN_START 0x50 +#define SRAM_DATA_OUT_START 0x50 + +#define SRAM_CFG_SPACE 0x50 + +#endif -- cgit v1.2.3-18-g5258 From 4a15235e79f5160a34100b362af2c674d191d0a5 Mon Sep 17 00:00:00 2001 From: Wan ZongShun Date: Sun, 9 Aug 2009 21:22:22 -0700 Subject: Input: add keypad driver for w90p910 Add keypad driver for the 4x4 keypad on an evaluation board based on w90p910. Signed-off-by: Wan ZongShun Reviewed-by: Trilok Soni Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/Kconfig | 10 ++ drivers/input/keyboard/Makefile | 1 + drivers/input/keyboard/w90p910_keypad.c | 305 ++++++++++++++++++++++++++++++++ 3 files changed, 316 insertions(+) create mode 100644 drivers/input/keyboard/w90p910_keypad.c (limited to 'drivers') diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 5239e25e88a..50e407de8a7 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -362,4 +362,14 @@ config KEYBOARD_XTKBD To compile this driver as a module, choose M here: the module will be called xtkbd. +config KEYBOARD_W90P910 + tristate "W90P910 Matrix Keypad support" + depends on ARCH_W90X900 + help + Say Y here to enable the matrix keypad on evaluation board + based on W90P910. + + To compile this driver as a module, choose M here: the + module will be called w90p910_keypad. + endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index b5b5eae9724..15230302920 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o +obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c new file mode 100644 index 00000000000..472c70514af --- /dev/null +++ b/drivers/input/keyboard/w90p910_keypad.c @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2008-2009 Nuvoton technology corporation. + * + * Wan ZongShun + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation;version 2 of the License. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Keypad Interface Control Registers */ +#define KPI_CONF 0x00 +#define KPI_3KCONF 0x04 +#define KPI_LPCONF 0x08 +#define KPI_STATUS 0x0C + +#define IS1KEY (0x01 << 16) +#define INTTR (0x01 << 21) +#define KEY0R (0x0f << 3) +#define KEY0C 0x07 +#define DEBOUNCE_BIT 0x08 +#define KSIZE0 (0x01 << 16) +#define KSIZE1 (0x01 << 17) +#define KPSEL (0x01 << 19) +#define ENKP (0x01 << 18) + +#define KGET_RAW(n) (((n) & KEY0R) >> 3) +#define KGET_COLUMN(n) ((n) & KEY0C) + +#define MAX_MATRIX_KEY_NUM (8 * 8) + +struct w90p910_keypad { + struct w90p910_keypad_platform_data *pdata; + struct clk *clk; + struct input_dev *input_dev; + void __iomem *mmio_base; + int irq; + unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM]; +}; + +static void w90p910_keypad_build_keycode(struct w90p910_keypad *keypad) +{ + struct w90p910_keypad_platform_data *pdata = keypad->pdata; + struct input_dev *input_dev = keypad->input_dev; + unsigned int *key; + int i; + + key = &pdata->matrix_key_map[0]; + for (i = 0; i < pdata->matrix_key_map_size; i++, key++) { + int row = KEY_ROW(*key); + int col = KEY_COL(*key); + int code = KEY_VAL(*key); + + keypad->matrix_keycodes[(row << 3) + col] = code; + __set_bit(code, input_dev->keybit); + } +} + +static inline unsigned int lookup_matrix_keycode( + struct w90p910_keypad *keypad, int row, int col) +{ + return keypad->matrix_keycodes[(row << 3) + col]; +} + +static void w90p910_keypad_scan_matrix(struct w90p910_keypad *keypad, + unsigned int status) +{ + unsigned int row, col, val; + + row = KGET_RAW(status); + col = KGET_COLUMN(status); + + val = lookup_matrix_keycode(keypad, row, col); + + input_report_key(keypad->input_dev, val, 1); + + input_sync(keypad->input_dev); + + input_report_key(keypad->input_dev, val, 0); + + input_sync(keypad->input_dev); +} + +static irqreturn_t w90p910_keypad_irq_handler(int irq, void *dev_id) +{ + struct w90p910_keypad *keypad = dev_id; + unsigned int kstatus, val; + + kstatus = __raw_readl(keypad->mmio_base + KPI_STATUS); + + val = INTTR | IS1KEY; + + if (kstatus & val) + w90p910_keypad_scan_matrix(keypad, kstatus); + + return IRQ_HANDLED; +} + +static int w90p910_keypad_open(struct input_dev *dev) +{ + struct w90p910_keypad *keypad = input_get_drvdata(dev); + struct w90p910_keypad_platform_data *pdata = keypad->pdata; + unsigned int val, config; + + /* Enable unit clock */ + clk_enable(keypad->clk); + + val = __raw_readl(keypad->mmio_base + KPI_CONF); + val |= (KPSEL | ENKP); + val &= ~(KSIZE0 | KSIZE1); + + config = pdata->prescale | (pdata->debounce << DEBOUNCE_BIT); + + val |= config; + + __raw_writel(val, keypad->mmio_base + KPI_CONF); + + return 0; +} + +static void w90p910_keypad_close(struct input_dev *dev) +{ + struct w90p910_keypad *keypad = input_get_drvdata(dev); + + /* Disable clock unit */ + clk_disable(keypad->clk); +} + +static int __devinit w90p910_keypad_probe(struct platform_device *pdev) +{ + struct w90p910_keypad *keypad; + struct input_dev *input_dev; + struct resource *res; + int irq, error; + + keypad = kzalloc(sizeof(struct w90p910_keypad), GFP_KERNEL); + if (keypad == NULL) { + dev_err(&pdev->dev, "failed to allocate driver data\n"); + return -ENOMEM; + } + + keypad->pdata = pdev->dev.platform_data; + if (keypad->pdata == NULL) { + dev_err(&pdev->dev, "no platform data defined\n"); + error = -EINVAL; + goto failed_free; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get keypad irq\n"); + error = -ENXIO; + goto failed_free; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "failed to get I/O memory\n"); + error = -ENXIO; + goto failed_free; + } + + res = request_mem_region(res->start, resource_size(res), pdev->name); + if (res == NULL) { + dev_err(&pdev->dev, "failed to request I/O memory\n"); + error = -EBUSY; + goto failed_free; + } + + keypad->mmio_base = ioremap(res->start, resource_size(res)); + if (keypad->mmio_base == NULL) { + dev_err(&pdev->dev, "failed to remap I/O memory\n"); + error = -ENXIO; + goto failed_free_mem; + } + + keypad->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(keypad->clk)) { + dev_err(&pdev->dev, "failed to get keypad clock\n"); + error = PTR_ERR(keypad->clk); + goto failed_free_io; + } + + /* Create and register the input driver. */ + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&pdev->dev, "failed to allocate input device\n"); + error = -ENOMEM; + goto failed_put_clk; + } + + /* set multi-function pin for w90p910 kpi. */ + mfp_set_groupi(&pdev->dev); + + input_dev->name = pdev->name; + input_dev->id.bustype = BUS_HOST; + input_dev->open = w90p910_keypad_open; + input_dev->close = w90p910_keypad_close; + input_dev->dev.parent = &pdev->dev; + input_dev->keycode = keypad->matrix_keycodes; + input_dev->keycodesize = sizeof(keypad->matrix_keycodes[0]); + input_dev->keycodemax = ARRAY_SIZE(keypad->matrix_keycodes); + + keypad->input_dev = input_dev; + input_set_drvdata(input_dev, keypad); + + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); + w90p910_keypad_build_keycode(keypad); + platform_set_drvdata(pdev, keypad); + + error = request_irq(irq, w90p910_keypad_irq_handler, IRQF_DISABLED, + pdev->name, keypad); + if (error) { + dev_err(&pdev->dev, "failed to request IRQ\n"); + goto failed_free_dev; + } + + keypad->irq = irq; + + /* Register the input device */ + error = input_register_device(input_dev); + if (error) { + dev_err(&pdev->dev, "failed to register input device\n"); + goto failed_free_irq; + } + + return 0; + +failed_free_irq: + free_irq(irq, pdev); + platform_set_drvdata(pdev, NULL); +failed_free_dev: + input_free_device(input_dev); +failed_put_clk: + clk_put(keypad->clk); +failed_free_io: + iounmap(keypad->mmio_base); +failed_free_mem: + release_mem_region(res->start, resource_size(res)); +failed_free: + kfree(keypad); + return error; +} + +static int __devexit w90p910_keypad_remove(struct platform_device *pdev) +{ + struct w90p910_keypad *keypad = platform_get_drvdata(pdev); + struct resource *res; + + free_irq(keypad->irq, pdev); + + clk_put(keypad->clk); + + input_unregister_device(keypad->input_dev); + + iounmap(keypad->mmio_base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + + platform_set_drvdata(pdev, NULL); + kfree(keypad); + return 0; +} + +static struct platform_driver w90p910_keypad_driver = { + .probe = w90p910_keypad_probe, + .remove = __devexit_p(w90p910_keypad_remove), + .driver = { + .name = "w90p910-keypad", + .owner = THIS_MODULE, + }, +}; + +static int __init w90p910_keypad_init(void) +{ + return platform_driver_register(&w90p910_keypad_driver); +} + +static void __exit w90p910_keypad_exit(void) +{ + platform_driver_unregister(&w90p910_keypad_driver); +} + +module_init(w90p910_keypad_init); +module_exit(w90p910_keypad_exit); + +MODULE_AUTHOR("Wan ZongShun "); +MODULE_DESCRIPTION("w90p910 keypad driver!"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:w90p910-keypad"); -- cgit v1.2.3-18-g5258 From 09113aea553cfaf074fd669cd0465daac4cea6e8 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 9 Aug 2009 21:22:22 -0700 Subject: Input: w90p910_keypad - adjust to use definitions from matrix_keypad.h Also have the driver send MSC_SCAN events as most keyboards do to aid in updating keymap from userspace. Tested-by: Wan ZongShun Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/w90p910_keypad.c | 144 ++++++++++++++------------------ 1 file changed, 65 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c index 472c70514af..24096cdfcb6 100644 --- a/drivers/input/keyboard/w90p910_keypad.c +++ b/drivers/input/keyboard/w90p910_keypad.c @@ -41,58 +41,34 @@ #define KGET_RAW(n) (((n) & KEY0R) >> 3) #define KGET_COLUMN(n) ((n) & KEY0C) -#define MAX_MATRIX_KEY_NUM (8 * 8) +#define W90P910_MAX_KEY_NUM (8 * 8) +#define W90P910_ROW_SHIFT 3 struct w90p910_keypad { - struct w90p910_keypad_platform_data *pdata; + const struct w90p910_keypad_platform_data *pdata; struct clk *clk; struct input_dev *input_dev; void __iomem *mmio_base; int irq; - unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM]; + unsigned short keymap[W90P910_MAX_KEY_NUM]; }; -static void w90p910_keypad_build_keycode(struct w90p910_keypad *keypad) -{ - struct w90p910_keypad_platform_data *pdata = keypad->pdata; - struct input_dev *input_dev = keypad->input_dev; - unsigned int *key; - int i; - - key = &pdata->matrix_key_map[0]; - for (i = 0; i < pdata->matrix_key_map_size; i++, key++) { - int row = KEY_ROW(*key); - int col = KEY_COL(*key); - int code = KEY_VAL(*key); - - keypad->matrix_keycodes[(row << 3) + col] = code; - __set_bit(code, input_dev->keybit); - } -} - -static inline unsigned int lookup_matrix_keycode( - struct w90p910_keypad *keypad, int row, int col) -{ - return keypad->matrix_keycodes[(row << 3) + col]; -} - static void w90p910_keypad_scan_matrix(struct w90p910_keypad *keypad, unsigned int status) { - unsigned int row, col, val; - - row = KGET_RAW(status); - col = KGET_COLUMN(status); - - val = lookup_matrix_keycode(keypad, row, col); - - input_report_key(keypad->input_dev, val, 1); - - input_sync(keypad->input_dev); - - input_report_key(keypad->input_dev, val, 0); - - input_sync(keypad->input_dev); + struct input_dev *input_dev = keypad->input_dev; + unsigned int row = KGET_RAW(status); + unsigned int col = KGET_COLUMN(status); + unsigned int code = MATRIX_SCAN_CODE(row, col, W90P910_ROW_SHIFT); + unsigned int key = keypad->keymap[code]; + + input_event(input_dev, EV_MSC, MSC_SCAN, code); + input_report_key(input_dev, key, 1); + input_sync(input_dev); + + input_event(input_dev, EV_MSC, MSC_SCAN, code); + input_report_key(input_dev, key, 0); + input_sync(input_dev); } static irqreturn_t w90p910_keypad_irq_handler(int irq, void *dev_id) @@ -113,7 +89,7 @@ static irqreturn_t w90p910_keypad_irq_handler(int irq, void *dev_id) static int w90p910_keypad_open(struct input_dev *dev) { struct w90p910_keypad *keypad = input_get_drvdata(dev); - struct w90p910_keypad_platform_data *pdata = keypad->pdata; + const struct w90p910_keypad_platform_data *pdata = keypad->pdata; unsigned int val, config; /* Enable unit clock */ @@ -142,31 +118,39 @@ static void w90p910_keypad_close(struct input_dev *dev) static int __devinit w90p910_keypad_probe(struct platform_device *pdev) { + const struct w90p910_keypad_platform_data *pdata = + pdev->dev.platform_data; + const struct matrix_keymap_data *keymap_data = pdata->keymap_data; struct w90p910_keypad *keypad; struct input_dev *input_dev; struct resource *res; - int irq, error; - - keypad = kzalloc(sizeof(struct w90p910_keypad), GFP_KERNEL); - if (keypad == NULL) { - dev_err(&pdev->dev, "failed to allocate driver data\n"); - return -ENOMEM; - } + int irq; + int error; + int i; - keypad->pdata = pdev->dev.platform_data; - if (keypad->pdata == NULL) { + if (!pdata) { dev_err(&pdev->dev, "no platform data defined\n"); - error = -EINVAL; - goto failed_free; + return -EINVAL; } irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "failed to get keypad irq\n"); - error = -ENXIO; + return -ENXIO; + } + + keypad = kzalloc(sizeof(struct w90p910_keypad), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!keypad || !input_dev) { + dev_err(&pdev->dev, "failed to allocate driver data\n"); + error = -ENOMEM; goto failed_free; } + keypad->pdata = pdata; + keypad->input_dev = input_dev; + keypad->irq = irq; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(&pdev->dev, "failed to get I/O memory\n"); @@ -185,7 +169,7 @@ static int __devinit w90p910_keypad_probe(struct platform_device *pdev) if (keypad->mmio_base == NULL) { dev_err(&pdev->dev, "failed to remap I/O memory\n"); error = -ENXIO; - goto failed_free_mem; + goto failed_free_res; } keypad->clk = clk_get(&pdev->dev, NULL); @@ -195,14 +179,6 @@ static int __devinit w90p910_keypad_probe(struct platform_device *pdev) goto failed_free_io; } - /* Create and register the input driver. */ - input_dev = input_allocate_device(); - if (!input_dev) { - dev_err(&pdev->dev, "failed to allocate input device\n"); - error = -ENOMEM; - goto failed_put_clk; - } - /* set multi-function pin for w90p910 kpi. */ mfp_set_groupi(&pdev->dev); @@ -211,26 +187,37 @@ static int __devinit w90p910_keypad_probe(struct platform_device *pdev) input_dev->open = w90p910_keypad_open; input_dev->close = w90p910_keypad_close; input_dev->dev.parent = &pdev->dev; - input_dev->keycode = keypad->matrix_keycodes; - input_dev->keycodesize = sizeof(keypad->matrix_keycodes[0]); - input_dev->keycodemax = ARRAY_SIZE(keypad->matrix_keycodes); - keypad->input_dev = input_dev; + input_dev->keycode = keypad->keymap; + input_dev->keycodesize = sizeof(keypad->keymap[0]); + input_dev->keycodemax = ARRAY_SIZE(keypad->keymap); + input_set_drvdata(input_dev, keypad); input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); - w90p910_keypad_build_keycode(keypad); - platform_set_drvdata(pdev, keypad); + input_set_capability(input_dev, EV_MSC, MSC_SCAN); + + for (i = 0; i < keymap_data->keymap_size; i++) { + unsigned int key = keymap_data->keymap[i]; + unsigned int row = KEY_ROW(key); + unsigned int col = KEY_COL(key); + unsigned short keycode = KEY_VAL(key); + unsigned int scancode = MATRIX_SCAN_CODE(row, col, + W90P910_ROW_SHIFT); + + keypad->keymap[scancode] = keycode; + __set_bit(keycode, input_dev->keybit); + } + __clear_bit(KEY_RESERVED, input_dev->keybit); + - error = request_irq(irq, w90p910_keypad_irq_handler, IRQF_DISABLED, - pdev->name, keypad); + error = request_irq(keypad->irq, w90p910_keypad_irq_handler, + IRQF_DISABLED, pdev->name, keypad); if (error) { dev_err(&pdev->dev, "failed to request IRQ\n"); - goto failed_free_dev; + goto failed_put_clk; } - keypad->irq = irq; - /* Register the input device */ error = input_register_device(input_dev); if (error) { @@ -238,20 +225,19 @@ static int __devinit w90p910_keypad_probe(struct platform_device *pdev) goto failed_free_irq; } + platform_set_drvdata(pdev, keypad); return 0; failed_free_irq: free_irq(irq, pdev); - platform_set_drvdata(pdev, NULL); -failed_free_dev: - input_free_device(input_dev); failed_put_clk: clk_put(keypad->clk); failed_free_io: iounmap(keypad->mmio_base); -failed_free_mem: +failed_free_res: release_mem_region(res->start, resource_size(res)); failed_free: + input_free_device(input_dev); kfree(keypad); return error; } @@ -268,12 +254,12 @@ static int __devexit w90p910_keypad_remove(struct platform_device *pdev) input_unregister_device(keypad->input_dev); iounmap(keypad->mmio_base); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); platform_set_drvdata(pdev, NULL); kfree(keypad); + return 0; } -- cgit v1.2.3-18-g5258 From c7425314c755d5f94da7c978205c85a7c6201212 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 9 Aug 2009 17:03:52 +0900 Subject: x86: Introduce GDT_ENTRY_INIT(), initialize bad_bios_desc statically Fully initialize bad_bios_desc statically instead of doing some fields statically and some dynamically. Suggested-by: "H. Peter Anvin" Signed-off-by: Akinobu Mita LKML-Reference: <20090809080350.GA4765@localhost.localdomain> Signed-off-by: Ingo Molnar --- drivers/pnp/pnpbios/bioscalls.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c index bd035e3d355..fc83783c3a9 100644 --- a/drivers/pnp/pnpbios/bioscalls.c +++ b/drivers/pnp/pnpbios/bioscalls.c @@ -60,7 +60,8 @@ do { \ set_desc_limit(&gdt[(selname) >> 3], (size) - 1); \ } while(0) -static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4092, 0, 0); +static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4092, + (unsigned long)__va(0x400UL), PAGE_SIZE - 0x400 - 1); /* * At some point we want to use this stack frame pointer to unwind @@ -476,8 +477,6 @@ void pnpbios_calls_init(union pnp_bios_install_struct *header) pnp_bios_callpoint.offset = header->fields.pm16offset; pnp_bios_callpoint.segment = PNP_CS16; - set_desc_base(&bad_bios_desc, (unsigned long)__va(0x40UL << 4)); - set_desc_limit(&bad_bios_desc, 4095 - (0x40 << 4)); for_each_possible_cpu(i) { struct desc_struct *gdt = get_cpu_gdt_table(i); if (!gdt) -- cgit v1.2.3-18-g5258 From 25a70e38cd57952b09a013bf070e03705ee4f2ff Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 12 Aug 2009 00:50:09 -0700 Subject: Input: eeti_ts - allow active high irq lines This adds a struct eeti_ts_platform_data which currently holds only one value to specify the interrupt polarity. The driver has a fallback if no platform data is passed in via the i2c_board_info, so no regression is caused. Signed-off-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/eeti_ts.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 3ab92222a52..9029bd3f34e 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -32,6 +32,7 @@ #include #include #include +#include static int flip_x; module_param(flip_x, bool, 0644); @@ -46,7 +47,7 @@ struct eeti_ts_priv { struct input_dev *input; struct work_struct work; struct mutex mutex; - int irq; + int irq, irq_active_high; }; #define EETI_TS_BITDEPTH (11) @@ -58,6 +59,11 @@ struct eeti_ts_priv { #define REPORT_BIT_HAS_PRESSURE (1 << 6) #define REPORT_RES_BITS(v) (((v) >> 1) + EETI_TS_BITDEPTH) +static inline int eeti_ts_irq_active(struct eeti_ts_priv *priv) +{ + return gpio_get_value(irq_to_gpio(priv->irq)) == priv->irq_active_high; +} + static void eeti_ts_read(struct work_struct *work) { char buf[6]; @@ -67,7 +73,7 @@ static void eeti_ts_read(struct work_struct *work) mutex_lock(&priv->mutex); - while (!gpio_get_value(irq_to_gpio(priv->irq)) && --to) + while (eeti_ts_irq_active(priv) && --to) i2c_master_recv(priv->client, buf, sizeof(buf)); if (!to) { @@ -140,8 +146,10 @@ static void eeti_ts_close(struct input_dev *dev) static int __devinit eeti_ts_probe(struct i2c_client *client, const struct i2c_device_id *idp) { + struct eeti_ts_platform_data *pdata; struct eeti_ts_priv *priv; struct input_dev *input; + unsigned int irq_flags; int err = -ENOMEM; /* In contrast to what's described in the datasheet, there seems @@ -180,6 +188,14 @@ static int __devinit eeti_ts_probe(struct i2c_client *client, priv->input = input; priv->irq = client->irq; + pdata = client->dev.platform_data; + + if (pdata) + priv->irq_active_high = pdata->irq_active_high; + + irq_flags = priv->irq_active_high ? + IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING; + INIT_WORK(&priv->work, eeti_ts_read); i2c_set_clientdata(client, priv); input_set_drvdata(input, priv); @@ -188,7 +204,7 @@ static int __devinit eeti_ts_probe(struct i2c_client *client, if (err) goto err1; - err = request_irq(priv->irq, eeti_ts_isr, IRQF_TRIGGER_FALLING, + err = request_irq(priv->irq, eeti_ts_isr, irq_flags, client->name, priv); if (err) { dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); -- cgit v1.2.3-18-g5258 From 07f6642ee9418e962e54cbc07471cfe2e559c568 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Wed, 12 Aug 2009 16:39:16 -0700 Subject: net,pppoe: fixup module init/exit subsequent calls pernet data should allocated first and freed last on module init/exit routines otherwise it's possible to have unserialized calls to packet handling routines. Signed-off-by: Cyrill Gorcunov Signed-off-by: David S. Miller --- drivers/net/pppoe.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 5f2090233d7..7cbf6f9b51d 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -1185,17 +1185,17 @@ static int __init pppoe_init(void) { int err; - err = proto_register(&pppoe_sk_proto, 0); + err = register_pernet_gen_device(&pppoe_net_id, &pppoe_net_ops); if (err) goto out; - err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto); + err = proto_register(&pppoe_sk_proto, 0); if (err) - goto out_unregister_pppoe_proto; + goto out_unregister_net_ops; - err = register_pernet_gen_device(&pppoe_net_id, &pppoe_net_ops); + err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto); if (err) - goto out_unregister_pppox_proto; + goto out_unregister_pppoe_proto; dev_add_pack(&pppoes_ptype); dev_add_pack(&pppoed_ptype); @@ -1203,22 +1203,22 @@ static int __init pppoe_init(void) return 0; -out_unregister_pppox_proto: - unregister_pppox_proto(PX_PROTO_OE); out_unregister_pppoe_proto: proto_unregister(&pppoe_sk_proto); +out_unregister_net_ops: + unregister_pernet_gen_device(pppoe_net_id, &pppoe_net_ops); out: return err; } static void __exit pppoe_exit(void) { - unregister_pppox_proto(PX_PROTO_OE); - dev_remove_pack(&pppoes_ptype); - dev_remove_pack(&pppoed_ptype); unregister_netdevice_notifier(&pppoe_notifier); - unregister_pernet_gen_device(pppoe_net_id, &pppoe_net_ops); + dev_remove_pack(&pppoed_ptype); + dev_remove_pack(&pppoes_ptype); + unregister_pppox_proto(PX_PROTO_OE); proto_unregister(&pppoe_sk_proto); + unregister_pernet_gen_device(pppoe_net_id, &pppoe_net_ops); } module_init(pppoe_init); -- cgit v1.2.3-18-g5258 From e41256f139b9148cfa12d2d057fec39e3d181ff0 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Thu, 13 Aug 2009 11:49:06 +1000 Subject: crypto: talitos - simplify hmac data size calculation don't do request->src vs. assoc pointer math - it's the same as adding assoclen and ivsize (just with more effort). Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index c70775fd3ce..b1a651c6182 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -970,7 +970,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, struct talitos_desc *desc = &edesc->desc; unsigned int cryptlen = areq->cryptlen; unsigned int authsize = ctx->authsize; - unsigned int ivsize; + unsigned int ivsize = crypto_aead_ivsize(aead); int sg_count, ret; int sg_link_tbl_len; @@ -978,11 +978,9 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, map_single_talitos_ptr(dev, &desc->ptr[0], ctx->authkeylen, &ctx->key, 0, DMA_TO_DEVICE); /* hmac data */ - map_single_talitos_ptr(dev, &desc->ptr[1], sg_virt(areq->src) - - sg_virt(areq->assoc), sg_virt(areq->assoc), 0, - DMA_TO_DEVICE); + map_single_talitos_ptr(dev, &desc->ptr[1], areq->assoclen + ivsize, + sg_virt(areq->assoc), 0, DMA_TO_DEVICE); /* cipher iv */ - ivsize = crypto_aead_ivsize(aead); map_single_talitos_ptr(dev, &desc->ptr[2], ivsize, giv ?: areq->iv, 0, DMA_TO_DEVICE); -- cgit v1.2.3-18-g5258 From 4b992628812137e30cda3510510cf3c052345b30 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Thu, 13 Aug 2009 11:50:38 +1000 Subject: crypto: talitos - align locks on cache lines align channel access locks onto separate cache lines (for performance reasons). This is done by placing per-channel variables into their own private struct, and using the cacheline_aligned attribute within that struct. Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 141 +++++++++++++++++++---------------------------- 1 file changed, 58 insertions(+), 83 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index b1a651c6182..5013a2dd47e 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -86,6 +86,25 @@ struct talitos_request { void *context; }; +/* per-channel fifo management */ +struct talitos_channel { + /* request fifo */ + struct talitos_request *fifo; + + /* number of requests pending in channel h/w fifo */ + atomic_t submit_count ____cacheline_aligned; + + /* request submission (head) lock */ + spinlock_t head_lock ____cacheline_aligned; + /* index to next free descriptor request */ + int head; + + /* request release (tail) lock */ + spinlock_t tail_lock ____cacheline_aligned; + /* index to next in-progress/done descriptor request */ + int tail; +}; + struct talitos_private { struct device *dev; struct of_device *ofdev; @@ -101,15 +120,6 @@ struct talitos_private { /* SEC Compatibility info */ unsigned long features; - /* next channel to be assigned next incoming descriptor */ - atomic_t last_chan; - - /* per-channel number of requests pending in channel h/w fifo */ - atomic_t *submit_count; - - /* per-channel request fifo */ - struct talitos_request **fifo; - /* * length of the request fifo * fifo_len is chfifo_len rounded up to next power of 2 @@ -117,15 +127,10 @@ struct talitos_private { */ unsigned int fifo_len; - /* per-channel index to next free descriptor request */ - int *head; - - /* per-channel index to next in-progress/done descriptor request */ - int *tail; + struct talitos_channel *chan; - /* per-channel request submission (head) and release (tail) locks */ - spinlock_t *head_lock; - spinlock_t *tail_lock; + /* next channel to be assigned next incoming descriptor */ + atomic_t last_chan ____cacheline_aligned; /* request callback tasklet */ struct tasklet_struct done_task; @@ -282,16 +287,16 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc, /* emulate SEC's round-robin channel fifo polling scheme */ ch = atomic_inc_return(&priv->last_chan) & (priv->num_channels - 1); - spin_lock_irqsave(&priv->head_lock[ch], flags); + spin_lock_irqsave(&priv->chan[ch].head_lock, flags); - if (!atomic_inc_not_zero(&priv->submit_count[ch])) { + if (!atomic_inc_not_zero(&priv->chan[ch].submit_count)) { /* h/w fifo is full */ - spin_unlock_irqrestore(&priv->head_lock[ch], flags); + spin_unlock_irqrestore(&priv->chan[ch].head_lock, flags); return -EAGAIN; } - head = priv->head[ch]; - request = &priv->fifo[ch][head]; + head = priv->chan[ch].head; + request = &priv->chan[ch].fifo[head]; /* map descriptor and save caller data */ request->dma_desc = dma_map_single(dev, desc, sizeof(*desc), @@ -300,7 +305,7 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc, request->context = context; /* increment fifo head */ - priv->head[ch] = (priv->head[ch] + 1) & (priv->fifo_len - 1); + priv->chan[ch].head = (priv->chan[ch].head + 1) & (priv->fifo_len - 1); smp_wmb(); request->desc = desc; @@ -309,7 +314,7 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc, wmb(); out_be32(priv->reg + TALITOS_FF_LO(ch), request->dma_desc); - spin_unlock_irqrestore(&priv->head_lock[ch], flags); + spin_unlock_irqrestore(&priv->chan[ch].head_lock, flags); return -EINPROGRESS; } @@ -324,11 +329,11 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch) unsigned long flags; int tail, status; - spin_lock_irqsave(&priv->tail_lock[ch], flags); + spin_lock_irqsave(&priv->chan[ch].tail_lock, flags); - tail = priv->tail[ch]; - while (priv->fifo[ch][tail].desc) { - request = &priv->fifo[ch][tail]; + tail = priv->chan[ch].tail; + while (priv->chan[ch].fifo[tail].desc) { + request = &priv->chan[ch].fifo[tail]; /* descriptors with their done bits set don't get the error */ rmb(); @@ -354,22 +359,22 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch) request->desc = NULL; /* increment fifo tail */ - priv->tail[ch] = (tail + 1) & (priv->fifo_len - 1); + priv->chan[ch].tail = (tail + 1) & (priv->fifo_len - 1); - spin_unlock_irqrestore(&priv->tail_lock[ch], flags); + spin_unlock_irqrestore(&priv->chan[ch].tail_lock, flags); - atomic_dec(&priv->submit_count[ch]); + atomic_dec(&priv->chan[ch].submit_count); saved_req.callback(dev, saved_req.desc, saved_req.context, status); /* channel may resume processing in single desc error case */ if (error && !reset_ch && status == error) return; - spin_lock_irqsave(&priv->tail_lock[ch], flags); - tail = priv->tail[ch]; + spin_lock_irqsave(&priv->chan[ch].tail_lock, flags); + tail = priv->chan[ch].tail; } - spin_unlock_irqrestore(&priv->tail_lock[ch], flags); + spin_unlock_irqrestore(&priv->chan[ch].tail_lock, flags); } /* @@ -397,20 +402,20 @@ static void talitos_done(unsigned long data) static struct talitos_desc *current_desc(struct device *dev, int ch) { struct talitos_private *priv = dev_get_drvdata(dev); - int tail = priv->tail[ch]; + int tail = priv->chan[ch].tail; dma_addr_t cur_desc; cur_desc = in_be32(priv->reg + TALITOS_CDPR_LO(ch)); - while (priv->fifo[ch][tail].dma_desc != cur_desc) { + while (priv->chan[ch].fifo[tail].dma_desc != cur_desc) { tail = (tail + 1) & (priv->fifo_len - 1); - if (tail == priv->tail[ch]) { + if (tail == priv->chan[ch].tail) { dev_err(dev, "couldn't locate current descriptor\n"); return NULL; } } - return priv->fifo[ch][tail].desc; + return priv->chan[ch].fifo[tail].desc; } /* @@ -1740,17 +1745,11 @@ static int talitos_remove(struct of_device *ofdev) if (hw_supports(dev, DESC_HDR_SEL0_RNG)) talitos_unregister_rng(dev); - kfree(priv->submit_count); - kfree(priv->tail); - kfree(priv->head); - - if (priv->fifo) - for (i = 0; i < priv->num_channels; i++) - kfree(priv->fifo[i]); + for (i = 0; i < priv->num_channels; i++) + if (priv->chan[i].fifo) + kfree(priv->chan[i].fifo); - kfree(priv->fifo); - kfree(priv->head_lock); - kfree(priv->tail_lock); + kfree(priv->chan); if (priv->irq != NO_IRQ) { free_irq(priv->irq, dev); @@ -1870,58 +1869,34 @@ static int talitos_probe(struct of_device *ofdev, if (of_device_is_compatible(np, "fsl,sec2.1")) priv->features |= TALITOS_FTR_HW_AUTH_CHECK; - priv->head_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels, - GFP_KERNEL); - priv->tail_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels, - GFP_KERNEL); - if (!priv->head_lock || !priv->tail_lock) { - dev_err(dev, "failed to allocate fifo locks\n"); + priv->chan = kzalloc(sizeof(struct talitos_channel) * + priv->num_channels, GFP_KERNEL); + if (!priv->chan) { + dev_err(dev, "failed to allocate channel management space\n"); err = -ENOMEM; goto err_out; } for (i = 0; i < priv->num_channels; i++) { - spin_lock_init(&priv->head_lock[i]); - spin_lock_init(&priv->tail_lock[i]); - } - - priv->fifo = kmalloc(sizeof(struct talitos_request *) * - priv->num_channels, GFP_KERNEL); - if (!priv->fifo) { - dev_err(dev, "failed to allocate request fifo\n"); - err = -ENOMEM; - goto err_out; + spin_lock_init(&priv->chan[i].head_lock); + spin_lock_init(&priv->chan[i].tail_lock); } priv->fifo_len = roundup_pow_of_two(priv->chfifo_len); for (i = 0; i < priv->num_channels; i++) { - priv->fifo[i] = kzalloc(sizeof(struct talitos_request) * - priv->fifo_len, GFP_KERNEL); - if (!priv->fifo[i]) { + priv->chan[i].fifo = kzalloc(sizeof(struct talitos_request) * + priv->fifo_len, GFP_KERNEL); + if (!priv->chan[i].fifo) { dev_err(dev, "failed to allocate request fifo %d\n", i); err = -ENOMEM; goto err_out; } } - priv->submit_count = kmalloc(sizeof(atomic_t) * priv->num_channels, - GFP_KERNEL); - if (!priv->submit_count) { - dev_err(dev, "failed to allocate fifo submit count space\n"); - err = -ENOMEM; - goto err_out; - } for (i = 0; i < priv->num_channels; i++) - atomic_set(&priv->submit_count[i], -(priv->chfifo_len - 1)); - - priv->head = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL); - priv->tail = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL); - if (!priv->head || !priv->tail) { - dev_err(dev, "failed to allocate request index space\n"); - err = -ENOMEM; - goto err_out; - } + atomic_set(&priv->chan[i].submit_count, + -(priv->chfifo_len - 1)); /* reset and initialize the h/w */ err = init_device(dev); -- cgit v1.2.3-18-g5258 From 81eb024c7e63f53b871797f6e2defccfd008dcd4 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Thu, 13 Aug 2009 11:51:51 +1000 Subject: crypto: talitos - add support for 36 bit addressing Enabling extended addressing in the h/w requires we always assign the extended address component (eptr) of the talitos h/w pointer. This is for e500 based platforms with large memories. Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 69 ++++++++++++++++++++++++++++-------------------- drivers/crypto/talitos.h | 1 + 2 files changed, 41 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 5013a2dd47e..c47ffe8a73e 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -146,6 +146,12 @@ struct talitos_private { #define TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT 0x00000001 #define TALITOS_FTR_HW_AUTH_CHECK 0x00000002 +static void to_talitos_ptr(struct talitos_ptr *talitos_ptr, dma_addr_t dma_addr) +{ + talitos_ptr->ptr = cpu_to_be32(lower_32_bits(dma_addr)); + talitos_ptr->eptr = cpu_to_be32(upper_32_bits(dma_addr)); +} + /* * map virtual single (contiguous) pointer to h/w descriptor pointer */ @@ -155,8 +161,10 @@ static void map_single_talitos_ptr(struct device *dev, unsigned char extent, enum dma_data_direction dir) { + dma_addr_t dma_addr = dma_map_single(dev, data, len, dir); + talitos_ptr->len = cpu_to_be16(len); - talitos_ptr->ptr = cpu_to_be32(dma_map_single(dev, data, len, dir)); + to_talitos_ptr(talitos_ptr, dma_addr); talitos_ptr->j_extent = extent; } @@ -187,9 +195,9 @@ static int reset_channel(struct device *dev, int ch) return -EIO; } - /* set done writeback and IRQ */ - setbits32(priv->reg + TALITOS_CCCR_LO(ch), TALITOS_CCCR_LO_CDWE | - TALITOS_CCCR_LO_CDIE); + /* set 36-bit addressing, done writeback enable and done IRQ enable */ + setbits32(priv->reg + TALITOS_CCCR_LO(ch), TALITOS_CCCR_LO_EAE | + TALITOS_CCCR_LO_CDWE | TALITOS_CCCR_LO_CDIE); /* and ICCR writeback, if available */ if (priv->features & TALITOS_FTR_HW_AUTH_CHECK) @@ -312,7 +320,10 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc, /* GO! */ wmb(); - out_be32(priv->reg + TALITOS_FF_LO(ch), request->dma_desc); + out_be32(priv->reg + TALITOS_FF(ch), + cpu_to_be32(upper_32_bits(request->dma_desc))); + out_be32(priv->reg + TALITOS_FF_LO(ch), + cpu_to_be32(lower_32_bits(request->dma_desc))); spin_unlock_irqrestore(&priv->chan[ch].head_lock, flags); @@ -934,7 +945,7 @@ static int sg_to_link_tbl(struct scatterlist *sg, int sg_count, int n_sg = sg_count; while (n_sg--) { - link_tbl_ptr->ptr = cpu_to_be32(sg_dma_address(sg)); + to_talitos_ptr(link_tbl_ptr, sg_dma_address(sg)); link_tbl_ptr->len = cpu_to_be16(sg_dma_len(sg)); link_tbl_ptr->j_extent = 0; link_tbl_ptr++; @@ -1009,7 +1020,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, edesc->src_is_chained); if (sg_count == 1) { - desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->src)); + to_talitos_ptr(&desc->ptr[4], sg_dma_address(areq->src)); } else { sg_link_tbl_len = cryptlen; @@ -1020,14 +1031,14 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, &edesc->link_tbl[0]); if (sg_count > 1) { desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP; - desc->ptr[4].ptr = cpu_to_be32(edesc->dma_link_tbl); + to_talitos_ptr(&desc->ptr[4], edesc->dma_link_tbl); dma_sync_single_for_device(dev, edesc->dma_link_tbl, edesc->dma_len, DMA_BIDIRECTIONAL); } else { /* Only one segment now, so no link tbl needed */ - desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq-> - src)); + to_talitos_ptr(&desc->ptr[4], + sg_dma_address(areq->src)); } } @@ -1042,14 +1053,14 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, edesc->dst_is_chained); if (sg_count == 1) { - desc->ptr[5].ptr = cpu_to_be32(sg_dma_address(areq->dst)); + to_talitos_ptr(&desc->ptr[5], sg_dma_address(areq->dst)); } else { struct talitos_ptr *link_tbl_ptr = &edesc->link_tbl[edesc->src_nents + 1]; - desc->ptr[5].ptr = cpu_to_be32((struct talitos_ptr *) - edesc->dma_link_tbl + - edesc->src_nents + 1); + to_talitos_ptr(&desc->ptr[5], edesc->dma_link_tbl + + (edesc->src_nents + 1) * + sizeof(struct talitos_ptr)); sg_count = sg_to_link_tbl(areq->dst, sg_count, cryptlen, link_tbl_ptr); @@ -1062,11 +1073,9 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, link_tbl_ptr->len = cpu_to_be16(authsize); /* icv data follows link tables */ - link_tbl_ptr->ptr = cpu_to_be32((struct talitos_ptr *) - edesc->dma_link_tbl + - edesc->src_nents + - edesc->dst_nents + 2); - + to_talitos_ptr(link_tbl_ptr, edesc->dma_link_tbl + + (edesc->src_nents + edesc->dst_nents + 2) * + sizeof(struct talitos_ptr)); desc->ptr[5].j_extent |= DESC_PTR_LNKTBL_JUMP; dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl, edesc->dma_len, DMA_BIDIRECTIONAL); @@ -1341,7 +1350,7 @@ static int common_nonsnoop(struct talitos_edesc *edesc, /* first DWORD empty */ desc->ptr[0].len = 0; - desc->ptr[0].ptr = 0; + to_talitos_ptr(&desc->ptr[0], 0); desc->ptr[0].j_extent = 0; /* cipher iv */ @@ -1365,20 +1374,20 @@ static int common_nonsnoop(struct talitos_edesc *edesc, edesc->src_is_chained); if (sg_count == 1) { - desc->ptr[3].ptr = cpu_to_be32(sg_dma_address(areq->src)); + to_talitos_ptr(&desc->ptr[3], sg_dma_address(areq->src)); } else { sg_count = sg_to_link_tbl(areq->src, sg_count, cryptlen, &edesc->link_tbl[0]); if (sg_count > 1) { + to_talitos_ptr(&desc->ptr[3], edesc->dma_link_tbl); desc->ptr[3].j_extent |= DESC_PTR_LNKTBL_JUMP; - desc->ptr[3].ptr = cpu_to_be32(edesc->dma_link_tbl); dma_sync_single_for_device(dev, edesc->dma_link_tbl, edesc->dma_len, DMA_BIDIRECTIONAL); } else { /* Only one segment now, so no link tbl needed */ - desc->ptr[3].ptr = cpu_to_be32(sg_dma_address(areq-> - src)); + to_talitos_ptr(&desc->ptr[3], + sg_dma_address(areq->src)); } } @@ -1393,15 +1402,15 @@ static int common_nonsnoop(struct talitos_edesc *edesc, edesc->dst_is_chained); if (sg_count == 1) { - desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->dst)); + to_talitos_ptr(&desc->ptr[4], sg_dma_address(areq->dst)); } else { struct talitos_ptr *link_tbl_ptr = &edesc->link_tbl[edesc->src_nents + 1]; + to_talitos_ptr(&desc->ptr[4], edesc->dma_link_tbl + + (edesc->src_nents + 1) * + sizeof(struct talitos_ptr)); desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP; - desc->ptr[4].ptr = cpu_to_be32((struct talitos_ptr *) - edesc->dma_link_tbl + - edesc->src_nents + 1); sg_count = sg_to_link_tbl(areq->dst, sg_count, cryptlen, link_tbl_ptr); dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl, @@ -1414,7 +1423,7 @@ static int common_nonsnoop(struct talitos_edesc *edesc, /* last DWORD empty */ desc->ptr[6].len = 0; - desc->ptr[6].ptr = 0; + to_talitos_ptr(&desc->ptr[6], 0); desc->ptr[6].j_extent = 0; ret = talitos_submit(dev, desc, callback, areq); @@ -1898,6 +1907,8 @@ static int talitos_probe(struct of_device *ofdev, atomic_set(&priv->chan[i].submit_count, -(priv->chfifo_len - 1)); + dma_set_mask(dev, DMA_BIT_MASK(36)); + /* reset and initialize the h/w */ err = init_device(dev); if (err) { diff --git a/drivers/crypto/talitos.h b/drivers/crypto/talitos.h index 575981f0cfd..ff5a1450e14 100644 --- a/drivers/crypto/talitos.h +++ b/drivers/crypto/talitos.h @@ -57,6 +57,7 @@ #define TALITOS_CCCR_RESET 0x1 /* channel reset */ #define TALITOS_CCCR_LO(ch) (ch * TALITOS_CH_STRIDE + 0x110c) #define TALITOS_CCCR_LO_IWSE 0x80 /* chan. ICCR writeback enab. */ +#define TALITOS_CCCR_LO_EAE 0x20 /* extended address enable */ #define TALITOS_CCCR_LO_CDWE 0x10 /* chan. done writeback enab. */ #define TALITOS_CCCR_LO_NT 0x4 /* notification type */ #define TALITOS_CCCR_LO_CDIE 0x2 /* channel done IRQ enable */ -- cgit v1.2.3-18-g5258 From 5da63cc4b2258e1c06ee41637492717481025143 Mon Sep 17 00:00:00 2001 From: Rémi Denis-Courmont Date: Thu, 6 Aug 2009 21:56:43 +0000 Subject: f_phonet: lock-less MTU change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the current driver, the MTU is purely indicative, so there is no need to synchronize with the receive path. Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- drivers/usb/gadget/f_phonet.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index d17f1082df9..f4eff7ca0d3 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -261,20 +261,10 @@ out: static int pn_net_mtu(struct net_device *dev, int new_mtu) { - struct phonet_port *port = netdev_priv(dev); - unsigned long flags; - int err = -EBUSY; - if ((new_mtu < PHONET_MIN_MTU) || (new_mtu > PHONET_MAX_MTU)) return -EINVAL; - - spin_lock_irqsave(&port->lock, flags); - if (!netif_carrier_ok(dev)) { - dev->mtu = new_mtu; - err = 0; - } - spin_unlock_irqrestore(&port->lock, flags); - return err; + dev->mtu = new_mtu; + return 0; } static const struct net_device_ops pn_netdev_ops = { -- cgit v1.2.3-18-g5258 From b91cd1440870f7a0649e570498b7b93caf9f781c Mon Sep 17 00:00:00 2001 From: Rémi Denis-Courmont Date: Thu, 6 Aug 2009 21:56:44 +0000 Subject: f_phonet: use page-sized rather than MTU-sized RX buffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of a large (physically) linear buffer, we generate a set of paged sk_buff, so no extra memory copy is involved. This removes high-order allocations and saves quite a bit of memory. Phonet MTU is 65541 bytes, so the two buffers were padded to 128 kilo-bytes each. Now, we create 17 page buffers, almost a 75% memory use reduction. Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- drivers/usb/gadget/f_phonet.c | 77 ++++++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index f4eff7ca0d3..d2de10b9dc4 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -35,6 +35,10 @@ #include "u_phonet.h" #define PN_MEDIA_USB 0x1B +#define MAXPACKET 512 +#if (PAGE_SIZE % MAXPACKET) +#error MAXPACKET must divide PAGE_SIZE! +#endif /*-------------------------------------------------------------------------*/ @@ -45,6 +49,10 @@ struct phonet_port { struct f_phonet { struct usb_function function; + struct { + struct sk_buff *skb; + spinlock_t lock; + } rx; struct net_device *dev; struct usb_ep *in_ep, *out_ep; @@ -52,7 +60,7 @@ struct f_phonet { struct usb_request *out_reqv[0]; }; -static int phonet_rxq_size = 2; +static int phonet_rxq_size = 17; static inline struct f_phonet *func_to_pn(struct usb_function *f) { @@ -138,7 +146,7 @@ pn_hs_sink_desc = { .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), + .wMaxPacketSize = cpu_to_le16(MAXPACKET), }; static struct usb_endpoint_descriptor @@ -298,21 +306,21 @@ static void pn_net_setup(struct net_device *dev) static int pn_rx_submit(struct f_phonet *fp, struct usb_request *req, gfp_t gfp_flags) { - struct sk_buff *skb; - const size_t size = fp->dev->mtu; + struct net_device *dev = fp->dev; + struct page *page; int err; - skb = alloc_skb(size, gfp_flags); - if (!skb) + page = __netdev_alloc_page(dev, gfp_flags); + if (!page) return -ENOMEM; - req->buf = skb->data; - req->length = size; - req->context = skb; + req->buf = page_address(page); + req->length = PAGE_SIZE; + req->context = page; err = usb_ep_queue(fp->out_ep, req, gfp_flags); if (unlikely(err)) - dev_kfree_skb_any(skb); + netdev_free_page(dev, page); return err; } @@ -320,25 +328,37 @@ static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req) { struct f_phonet *fp = ep->driver_data; struct net_device *dev = fp->dev; - struct sk_buff *skb = req->context; + struct page *page = req->context; + struct sk_buff *skb; + unsigned long flags; int status = req->status; switch (status) { case 0: - if (unlikely(!netif_running(dev))) - break; - if (unlikely(req->actual < 1)) + spin_lock_irqsave(&fp->rx.lock, flags); + skb = fp->rx.skb; + if (!skb) + skb = fp->rx.skb = netdev_alloc_skb(dev, 12); + if (req->actual < req->length) /* Last fragment */ + fp->rx.skb = NULL; + spin_unlock_irqrestore(&fp->rx.lock, flags); + + if (unlikely(!skb)) break; - skb_put(skb, req->actual); - skb->protocol = htons(ETH_P_PHONET); - skb_reset_mac_header(skb); - __skb_pull(skb, 1); - skb->dev = dev; - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - - netif_rx(skb); - skb = NULL; + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, 0, + req->actual); + page = NULL; + + if (req->actual < req->length) { /* Last fragment */ + skb->protocol = htons(ETH_P_PHONET); + skb_reset_mac_header(skb); + pskb_pull(skb, 1); + skb->dev = dev; + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + + netif_rx(skb); + } break; /* Do not resubmit in these cases: */ @@ -356,8 +376,8 @@ static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req) break; } - if (skb) - dev_kfree_skb_any(skb); + if (page) + netdev_free_page(dev, page); if (req) pn_rx_submit(fp, req, GFP_ATOMIC); } @@ -375,6 +395,10 @@ static void __pn_reset(struct usb_function *f) usb_ep_disable(fp->out_ep); usb_ep_disable(fp->in_ep); + if (fp->rx.skb) { + dev_kfree_skb_irq(fp->rx.skb); + fp->rx.skb = NULL; + } } static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt) @@ -573,6 +597,7 @@ int __init phonet_bind_config(struct usb_configuration *c) fp->function.set_alt = pn_set_alt; fp->function.get_alt = pn_get_alt; fp->function.disable = pn_disconnect; + spin_lock_init(&fp->rx.lock); err = usb_add_function(c, &fp->function); if (err) -- cgit v1.2.3-18-g5258 From 798c752b815bd80653dc48b6ffb8eb68ede15a66 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 7 Aug 2009 02:58:45 +0000 Subject: fakehard: use START-CONFIRM primitive to report START failure Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: David S. Miller --- drivers/ieee802154/fakehard.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index c94d2c24c35..262536fae90 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c @@ -177,18 +177,14 @@ static int fake_disassoc_req(struct net_device *dev, * * Note: This is in section 7.5.2.3 of the IEEE 802.15.4-2006 * document, with 7.3.8 describing coordinator realignment. - * - * Note: There is currently no way to notify the coordinator userland - * program of whether or not the PAN has started successfully. As - * such, the coordinator program cannot know when the MAC has - * completed starting the network and will simply have to assume - * completeness based on some form of time delay. */ static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, u8 channel, u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, u8 coord_realign) { + /* We don't emulate beacons here at all, so START should fail */ + ieee802154_nl_start_confirm(dev, IEEE802154_INVALID_PARAMETER); return 0; } -- cgit v1.2.3-18-g5258 From 176edd52366d59350717b0bf6865b1d7ece156cc Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 7 Aug 2009 21:53:41 +0000 Subject: drivres/net: Change constant name In this series of tests the constants have the form XRXMAC_STATUS, except in this one case. The values of XRXMAC_STAT_MSK_RXOCTET_CNT_EXP and XRXMAC_STATUS_RXOCTET_CNT_EXP are furthermore the same. Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/niu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/niu.c b/drivers/net/niu.c index d2146d4a10f..3ada7ea2abc 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -4015,7 +4015,7 @@ static void niu_xmac_interrupt(struct niu *np) mp->rx_hist_cnt6 += RXMAC_HIST_CNT6_COUNT; if (val & XRXMAC_STATUS_RXHIST7_CNT_EXP) mp->rx_hist_cnt7 += RXMAC_HIST_CNT7_COUNT; - if (val & XRXMAC_STAT_MSK_RXOCTET_CNT_EXP) + if (val & XRXMAC_STATUS_RXOCTET_CNT_EXP) mp->rx_octets += RXMAC_BT_CNT_COUNT; if (val & XRXMAC_STATUS_CVIOLERR_CNT_EXP) mp->rx_code_violations += RXMAC_CD_VIO_CNT_COUNT; -- cgit v1.2.3-18-g5258 From 582b95c2709cd58913ec2a31b0266ba0aa67b03d Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 7 Aug 2009 20:47:33 +0000 Subject: drivers/net/tokenring: Use status field rather than state field In general in this file, it is the status field, not the state field, that contains values like OPEN and CLOSED. Indeed, in the first error case, it is the field status that is initialized. I have thus assumed that all of the error handling code should be the same, and moved it to the end of the function to emphasize its commonality. Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/tokenring/smctr.c | 36 ++++++++++-------------------------- 1 file changed, 10 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index 6515894c83f..23e012f5bbf 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -3091,11 +3091,7 @@ static int smctr_lobe_media_test(struct net_device *dev) /* Setup the lobe media test. */ smctr_lobe_media_test_cmd(dev); if(smctr_wait_cmd(dev)) - { - smctr_reset_adapter(dev); - tp->status = CLOSED; - return (LOBE_MEDIA_TEST_FAILED); - } + goto err; /* Tx lobe media test frames. */ for(i = 0; i < 1500; ++i) @@ -3103,20 +3099,12 @@ static int smctr_lobe_media_test(struct net_device *dev) if(smctr_send_lobe_media_test(dev)) { if(perror) - { - smctr_reset_adapter(dev); - tp->state = CLOSED; - return (LOBE_MEDIA_TEST_FAILED); - } + goto err; else { perror = 1; if(smctr_lobe_media_test_cmd(dev)) - { - smctr_reset_adapter(dev); - tp->state = CLOSED; - return (LOBE_MEDIA_TEST_FAILED); - } + goto err; } } } @@ -3124,28 +3112,24 @@ static int smctr_lobe_media_test(struct net_device *dev) if(smctr_send_dat(dev)) { if(smctr_send_dat(dev)) - { - smctr_reset_adapter(dev); - tp->state = CLOSED; - return (LOBE_MEDIA_TEST_FAILED); - } + goto err; } /* Check if any frames received during test. */ if((tp->rx_fcb_curr[MAC_QUEUE]->frame_status) || (tp->rx_fcb_curr[NON_MAC_QUEUE]->frame_status)) - { - smctr_reset_adapter(dev); - tp->state = CLOSED; - return (LOBE_MEDIA_TEST_FAILED); - } + goto err; /* Set receive mask to "Promisc" mode. */ tp->receive_mask = saved_rcv_mask; smctr_chg_rx_mask(dev); - return (0); + return 0; +err: + smctr_reset_adapter(dev); + tp->status = CLOSED; + return LOBE_MEDIA_TEST_FAILED; } static int smctr_lobe_media_test_cmd(struct net_device *dev) -- cgit v1.2.3-18-g5258 From ab4c0c77b566bbac25e28c7ae487dc02bdd8f343 Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sun, 9 Aug 2009 02:59:56 +0000 Subject: net: cs89x0: includecheck fix for cs89x0.c fix the following 'make includecheck' warning: drivers/net/cs89x0.c: asm/irq.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Signed-off-by: David S. Miller --- drivers/net/cs89x0.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index ecf88abbf99..839cac5fd8a 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -177,13 +177,10 @@ static unsigned int cs8900_irq_map[] = {1,0,0,0}; #elif defined(CONFIG_MACH_IXDP2351) static unsigned int netcard_portlist[] __used __initdata = {IXDP2351_VIRT_CS8900_BASE, 0}; static unsigned int cs8900_irq_map[] = {IRQ_IXDP2351_CS8900, 0, 0, 0}; -#include #elif defined(CONFIG_ARCH_IXDP2X01) -#include static unsigned int netcard_portlist[] __used __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0}; static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0}; #elif defined(CONFIG_ARCH_PNX010X) -#include #include #define CIRRUS_DEFAULT_BASE IO_ADDRESS(EXT_STATIC2_s0_BASE + 0x200000) /* = Physical address 0x48200000 */ #define CIRRUS_DEFAULT_IRQ VH_INTC_INT_NUM_CASCADED_INTERRUPT_1 /* Event inputs bank 1 - ID 35/bit 3 */ -- cgit v1.2.3-18-g5258 From bdf50d7346588b22fd66367ae2890e2cbf574172 Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sun, 9 Aug 2009 03:05:25 +0000 Subject: net: pcmcia/axnet_cs: includecheck fix axnet_cs.c fix the following 'make includecheck' warning: drivers/net/pcmcia/axnet_cs.c: linux/etherdevice.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Signed-off-by: David S. Miller --- drivers/net/pcmcia/axnet_cs.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index b5cfac7c517..1e87d634d7b 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -893,8 +893,6 @@ static const char version_8390[] = KERN_INFO \ #include #include -#include - #define BUG_83C690 /* These are the operational function interfaces to board-specific -- cgit v1.2.3-18-g5258 From c9145a2df072f75d97592ddac1624baeb7bad195 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 8 Aug 2009 21:43:42 +0000 Subject: drivers/net: Correct use of request_region/request_mem_region request_mem_region should be used with release_mem_region, not request_region. The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @r2@ expression start; @@ request_mem_region(start,...) @b2@ expression r2.start; @@ request_region(start,...) @depends on !b2@ expression r2.start; expression E; @@ - release_region + release_mem_region (start,E) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/jazzsonic.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index ec337b502fd..6e5b3f30527 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -203,7 +203,7 @@ static int __devinit sonic_probe1(struct net_device *dev) return 0; out: - release_region(dev->base_addr, SONIC_MEM_SIZE); + release_mem_region(dev->base_addr, SONIC_MEM_SIZE); return err; } @@ -247,7 +247,7 @@ static int __devinit jazz_sonic_probe(struct platform_device *pdev) return 0; out1: - release_region(dev->base_addr, SONIC_MEM_SIZE); + release_mem_region(dev->base_addr, SONIC_MEM_SIZE); out: free_netdev(dev); @@ -269,7 +269,7 @@ static int __devexit jazz_sonic_device_remove (struct platform_device *pdev) unregister_netdev(dev); dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), lp->descriptors, lp->descriptors_laddr); - release_region (dev->base_addr, SONIC_MEM_SIZE); + release_mem_region(dev->base_addr, SONIC_MEM_SIZE); free_netdev(dev); return 0; -- cgit v1.2.3-18-g5258 From d02342151c51344034fbdeceff8effcb0a77c573 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Fri, 7 Aug 2009 10:44:22 +0000 Subject: myri10ge: improve parity error detection and recovery Improve myri10ge parity error detection and recovery: 1) Don't restore PCI config space to a rebooted NIC until AFTER the host is quiescent. 2) Let myri10ge_close() know the NIC is dead, so it won't waste time waiting for a dead nic to respond to MXGEFW_CMD_ETHERNET_DOWN 3) When the NIC is quiet (link down, or otherwise idle link) use a pci config space read to detect a rebooted NIC. Otherwise we might never notice that a NIC rebooted Signed-off-by: Andrew Gallatin Signed-off-by: Brice Goglin Signed-off-by: David S. Miller --- drivers/net/myri10ge/myri10ge.c | 63 ++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 1a34f7e11d9..75deef35b1e 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -75,7 +75,7 @@ #include "myri10ge_mcp.h" #include "myri10ge_mcp_gen_header.h" -#define MYRI10GE_VERSION_STR "1.5.0-1.418" +#define MYRI10GE_VERSION_STR "1.5.0-1.432" MODULE_DESCRIPTION("Myricom 10G driver (10GbE)"); MODULE_AUTHOR("Maintainer: help@myri.com"); @@ -188,6 +188,7 @@ struct myri10ge_slice_state { dma_addr_t fw_stats_bus; int watchdog_tx_done; int watchdog_tx_req; + int watchdog_rx_done; #ifdef CONFIG_MYRI10GE_DCA int cached_dca_tag; int cpu; @@ -256,6 +257,7 @@ struct myri10ge_priv { u32 link_changes; u32 msg_enable; unsigned int board_number; + int rebooted; }; static char *myri10ge_fw_unaligned = "myri10ge_ethp_z8e.dat"; @@ -2552,17 +2554,22 @@ static int myri10ge_close(struct net_device *dev) netif_carrier_off(dev); netif_tx_stop_all_queues(dev); - old_down_cnt = mgp->down_cnt; - mb(); - status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_DOWN, &cmd, 0); - if (status) - printk(KERN_ERR "myri10ge: %s: Couldn't bring down link\n", - dev->name); - - wait_event_timeout(mgp->down_wq, old_down_cnt != mgp->down_cnt, HZ); - if (old_down_cnt == mgp->down_cnt) - printk(KERN_ERR "myri10ge: %s never got down irq\n", dev->name); + if (mgp->rebooted == 0) { + old_down_cnt = mgp->down_cnt; + mb(); + status = + myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_DOWN, &cmd, 0); + if (status) + printk(KERN_ERR + "myri10ge: %s: Couldn't bring down link\n", + dev->name); + wait_event_timeout(mgp->down_wq, old_down_cnt != mgp->down_cnt, + HZ); + if (old_down_cnt == mgp->down_cnt) + printk(KERN_ERR "myri10ge: %s never got down irq\n", + dev->name); + } netif_tx_disable(dev); myri10ge_free_irq(mgp); for (i = 0; i < mgp->num_slices; i++) @@ -3427,12 +3434,13 @@ static void myri10ge_watchdog(struct work_struct *work) container_of(work, struct myri10ge_priv, watchdog_work); struct myri10ge_tx_buf *tx; u32 reboot; - int status; + int status, rebooted; int i; u16 cmd, vendor; mgp->watchdog_resets++; pci_read_config_word(mgp->pdev, PCI_COMMAND, &cmd); + rebooted = 0; if ((cmd & PCI_COMMAND_MASTER) == 0) { /* Bus master DMA disabled? Check to see * if the card rebooted due to a parity error @@ -3444,9 +3452,12 @@ static void myri10ge_watchdog(struct work_struct *work) myri10ge_reset_recover ? " " : " not"); if (myri10ge_reset_recover == 0) return; - + rtnl_lock(); + mgp->rebooted = 1; + rebooted = 1; + myri10ge_close(mgp->dev); myri10ge_reset_recover--; - + mgp->rebooted = 0; /* * A rebooted nic will come back with config space as * it was after power was applied to PCIe bus. @@ -3494,8 +3505,10 @@ static void myri10ge_watchdog(struct work_struct *work) } } - rtnl_lock(); - myri10ge_close(mgp->dev); + if (!rebooted) { + rtnl_lock(); + myri10ge_close(mgp->dev); + } status = myri10ge_load_firmware(mgp, 1); if (status != 0) printk(KERN_ERR "myri10ge: %s: failed to load firmware\n", @@ -3516,12 +3529,14 @@ static void myri10ge_watchdog_timer(unsigned long arg) { struct myri10ge_priv *mgp; struct myri10ge_slice_state *ss; - int i, reset_needed; + int i, reset_needed, busy_slice_cnt; u32 rx_pause_cnt; + u16 cmd; mgp = (struct myri10ge_priv *)arg; rx_pause_cnt = ntohl(mgp->ss[0].fw_stats->dropped_pause); + busy_slice_cnt = 0; for (i = 0, reset_needed = 0; i < mgp->num_slices && reset_needed == 0; ++i) { @@ -3559,8 +3574,22 @@ static void myri10ge_watchdog_timer(unsigned long arg) reset_needed = 1; } } + if (ss->watchdog_tx_done != ss->tx.done || + ss->watchdog_rx_done != ss->rx_done.cnt) { + busy_slice_cnt++; + } ss->watchdog_tx_done = ss->tx.done; ss->watchdog_tx_req = ss->tx.req; + ss->watchdog_rx_done = ss->rx_done.cnt; + } + /* if we've sent or received no traffic, poll the NIC to + * ensure it is still there. Otherwise, we risk not noticing + * an error in a timely fashion */ + if (busy_slice_cnt == 0) { + pci_read_config_word(mgp->pdev, PCI_COMMAND, &cmd); + if ((cmd & PCI_COMMAND_MASTER) == 0) { + reset_needed = 1; + } } mgp->watchdog_pause = rx_pause_cnt; -- cgit v1.2.3-18-g5258 From f2341641766af3de18502abb6ac9b98e0e4c6bdb Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sun, 9 Aug 2009 03:12:38 +0000 Subject: net: smc911x: includecheck fix for smc911x.h fix the following 'make includecheck' warning: drivers/net/smc911x.h: mach/dma.h is included more than once. Signed-off-by: Jaswinder Singh Rajput Signed-off-by: David S. Miller --- drivers/net/smc911x.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h index 8140f7cb4d8..05adb6a666c 100644 --- a/drivers/net/smc911x.h +++ b/drivers/net/smc911x.h @@ -236,7 +236,6 @@ static inline void SMC_outsl(struct smc911x_local *lp, int reg, * Use a DMA for RX and TX packets. */ #include -#include static dma_addr_t rx_dmabuf, tx_dmabuf; static int rx_dmalen, tx_dmalen; -- cgit v1.2.3-18-g5258 From a8e9179a7de196d37410fd3e9528081f22c70a4e Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 10 Aug 2009 03:42:43 +0000 Subject: be2net: Clear pending tx completions before destroying tx queue Clear pending tx completions in be_close() (ndo.stop method) so that after unregister_netdev() calls be_close(), all tx skbs are freed and there are no more tx completions when txq is destroyed. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/benet/be_main.c | 52 ++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index d20235b1680..acce6a63932 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1018,21 +1018,35 @@ static void be_rx_q_clean(struct be_adapter *adapter) BUG_ON(atomic_read(&rxq->used)); } -static void be_tx_q_clean(struct be_adapter *adapter) +static void be_tx_compl_clean(struct be_adapter *adapter) { - struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list; - struct sk_buff *sent_skb; + struct be_queue_info *tx_cq = &adapter->tx_obj.cq; struct be_queue_info *txq = &adapter->tx_obj.q; - u16 last_index; - bool dummy_wrb; - - while (atomic_read(&txq->used)) { - sent_skb = sent_skbs[txq->tail]; - last_index = txq->tail; - index_adv(&last_index, - wrb_cnt_for_skb(sent_skb, &dummy_wrb) - 1, txq->len); - be_tx_compl_process(adapter, last_index); - } + struct be_eth_tx_compl *txcp; + u16 end_idx, cmpl = 0, timeo = 0; + + /* Wait for a max of 200ms for all the tx-completions to arrive. */ + do { + while ((txcp = be_tx_compl_get(tx_cq))) { + end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl, + wrb_index, txcp); + be_tx_compl_process(adapter, end_idx); + cmpl++; + } + if (cmpl) { + be_cq_notify(adapter, tx_cq->id, false, cmpl); + cmpl = 0; + } + + if (atomic_read(&txq->used) == 0 || ++timeo > 200) + break; + + mdelay(1); + } while (true); + + if (atomic_read(&txq->used)) + dev_err(&adapter->pdev->dev, "%d pending tx-completions\n", + atomic_read(&txq->used)); } static void be_mcc_queues_destroy(struct be_adapter *adapter) @@ -1091,13 +1105,8 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) struct be_queue_info *q; q = &adapter->tx_obj.q; - if (q->created) { + if (q->created) be_cmd_q_destroy(adapter, q, QTYPE_TXQ); - - /* No more tx completions can be rcvd now; clean up if there - * are any pending completions or pending tx requests */ - be_tx_q_clean(adapter); - } be_queue_free(adapter, q); q = &adapter->tx_obj.cq; @@ -1645,6 +1654,11 @@ static int be_close(struct net_device *netdev) napi_disable(&rx_eq->napi); napi_disable(&tx_eq->napi); + /* Wait for all pending tx completions to arrive so that + * all tx skbs are freed. + */ + be_tx_compl_clean(adapter); + return 0; } -- cgit v1.2.3-18-g5258 From cdab23b7017693c00dd69fa28bcdf5b0434b3838 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 10 Aug 2009 03:43:23 +0000 Subject: be2net: fix bad queue traversal in be_rx_q_clean() Using "for(tail != head)" to traverse a queue from tail to head fails in the case of a fully filled queue. Use "for(used != 0)" instead. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/benet/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index acce6a63932..9bbf447ee28 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1010,7 +1010,7 @@ static void be_rx_q_clean(struct be_adapter *adapter) /* Then free posted rx buffer that were not used */ tail = (rxq->head + rxq->len - atomic_read(&rxq->used)) % rxq->len; - for (; tail != rxq->head; index_inc(&tail, rxq->len)) { + for (; atomic_read(&rxq->used) > 0; index_inc(&tail, rxq->len)) { page_info = get_rx_page_info(adapter, tail); put_page(page_info->page); memset(page_info, 0, sizeof(*page_info)); -- cgit v1.2.3-18-g5258 From 859b1e4ec86840b0d0980f82b626d687be682eb9 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 10 Aug 2009 03:43:51 +0000 Subject: be2net: clear & notify residual events before destroying event queues Any events rcvd after interrupts are disabled (in the driver unload path), must be cleared and notified before the event queues are destroyed Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/benet/be_main.c | 85 +++++++++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 9bbf447ee28..2db879c03c6 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -993,6 +993,56 @@ static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index) kfree_skb(sent_skb); } +static inline struct be_eq_entry *event_get(struct be_eq_obj *eq_obj) +{ + struct be_eq_entry *eqe = queue_tail_node(&eq_obj->q); + + if (!eqe->evt) + return NULL; + + eqe->evt = le32_to_cpu(eqe->evt); + queue_tail_inc(&eq_obj->q); + return eqe; +} + +static int event_handle(struct be_adapter *adapter, + struct be_eq_obj *eq_obj) +{ + struct be_eq_entry *eqe; + u16 num = 0; + + while ((eqe = event_get(eq_obj)) != NULL) { + eqe->evt = 0; + num++; + } + + /* Deal with any spurious interrupts that come + * without events + */ + be_eq_notify(adapter, eq_obj->q.id, true, true, num); + if (num) + napi_schedule(&eq_obj->napi); + + return num; +} + +/* Just read and notify events without processing them. + * Used at the time of destroying event queues */ +static void be_eq_clean(struct be_adapter *adapter, + struct be_eq_obj *eq_obj) +{ + struct be_eq_entry *eqe; + u16 num = 0; + + while ((eqe = event_get(eq_obj)) != NULL) { + eqe->evt = 0; + num++; + } + + if (num) + be_eq_notify(adapter, eq_obj->q.id, false, true, num); +} + static void be_rx_q_clean(struct be_adapter *adapter) { struct be_rx_page_info *page_info; @@ -1114,6 +1164,9 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) be_cmd_q_destroy(adapter, q, QTYPE_CQ); be_queue_free(adapter, q); + /* Clear any residual events */ + be_eq_clean(adapter, &adapter->tx_eq); + q = &adapter->tx_eq.q; if (q->created) be_cmd_q_destroy(adapter, q, QTYPE_EQ); @@ -1185,6 +1238,9 @@ static void be_rx_queues_destroy(struct be_adapter *adapter) be_cmd_q_destroy(adapter, q, QTYPE_CQ); be_queue_free(adapter, q); + /* Clear any residual events */ + be_eq_clean(adapter, &adapter->rx_eq); + q = &adapter->rx_eq.q; if (q->created) be_cmd_q_destroy(adapter, q, QTYPE_EQ); @@ -1251,35 +1307,6 @@ rx_eq_free: be_queue_free(adapter, eq); return rc; } -static bool event_get(struct be_eq_obj *eq_obj, u16 *rid) -{ - struct be_eq_entry *entry = queue_tail_node(&eq_obj->q); - u32 evt = entry->evt; - - if (!evt) - return false; - - evt = le32_to_cpu(evt); - *rid = (evt >> EQ_ENTRY_RES_ID_SHIFT) & EQ_ENTRY_RES_ID_MASK; - entry->evt = 0; - queue_tail_inc(&eq_obj->q); - return true; -} - -static int event_handle(struct be_adapter *adapter, struct be_eq_obj *eq_obj) -{ - u16 rid = 0, num = 0; - - while (event_get(eq_obj, &rid)) - num++; - - /* We can see an interrupt and no event */ - be_eq_notify(adapter, eq_obj->q.id, true, true, num); - if (num) - napi_schedule(&eq_obj->napi); - - return num; -} static irqreturn_t be_intx(int irq, void *dev) { -- cgit v1.2.3-18-g5258 From 5edcc537af1a9810726d1b68ba6c59e5d8d36113 Mon Sep 17 00:00:00 2001 From: françois romieu Date: Mon, 10 Aug 2009 19:41:52 +0000 Subject: r8169: fix r8101 quirk dupe Noticed by Vincent Pelletier . Signed-off-by: Francois Romieu Cc: Edward Hsu Signed-off-by: David S. Miller --- drivers/net/r8169.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index b82780d805f..eac882b18db 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -2757,7 +2757,7 @@ static void rtl_hw_start_8168(struct net_device *dev) EnableBist | \ Mac_dbgo_oe | \ Force_half_dup | \ - Force_half_dup | \ + Force_rxflow_en | \ Force_txflow_en | \ Cxpl_dbg_sel | \ ASF | \ -- cgit v1.2.3-18-g5258 From 21d57363201857bd8c5c0ad0ebc795134d632195 Mon Sep 17 00:00:00 2001 From: françois romieu Date: Mon, 10 Aug 2009 19:42:37 +0000 Subject: r8169: differentiate close chipsets in the startup identification message The driver displays the same 0x18000000 xid for RTL_GIGA_MAC_VER_06 and RTL_GIGA_MAC_VER_05 whereas the former ought to be identified as 0x98000000. Signed-off-by: Francois Romieu Cc: Edward Hsu Signed-off-by: David S. Miller --- drivers/net/r8169.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index eac882b18db..6c4b879497d 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -2180,7 +2180,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, dev); if (netif_msg_probe(tp)) { - u32 xid = RTL_R32(TxConfig) & 0x7cf0f8ff; + u32 xid = RTL_R32(TxConfig) & 0x9cf0f8ff; printk(KERN_INFO "%s: %s at 0x%lx, " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " -- cgit v1.2.3-18-g5258 From 8c7006aa94bea415cd7f8c5fa8df9d3f261bd314 Mon Sep 17 00:00:00 2001 From: françois romieu Date: Mon, 10 Aug 2009 19:43:29 +0000 Subject: r8169: phy init for the 8169sce Synced with Realtek's 6.011.00 r8169 driver. Signed-off-by: Francois Romieu Cc: Edward Hsu Signed-off-by: David S. Miller --- drivers/net/r8169.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 6c4b879497d..86722886ae4 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1389,6 +1389,59 @@ static void rtl8169sb_hw_phy_config(void __iomem *ioaddr) rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } +static void rtl8169sce_hw_phy_config(void __iomem *ioaddr) +{ + struct phy_reg phy_reg_init[] = { + { 0x1f, 0x0001 }, + { 0x04, 0x0000 }, + { 0x03, 0x00a1 }, + { 0x02, 0x0008 }, + { 0x01, 0x0120 }, + { 0x00, 0x1000 }, + { 0x04, 0x0800 }, + { 0x04, 0x9000 }, + { 0x03, 0x802f }, + { 0x02, 0x4f02 }, + { 0x01, 0x0409 }, + { 0x00, 0xf099 }, + { 0x04, 0x9800 }, + { 0x04, 0xa000 }, + { 0x03, 0xdf01 }, + { 0x02, 0xdf20 }, + { 0x01, 0xff95 }, + { 0x00, 0xba00 }, + { 0x04, 0xa800 }, + { 0x04, 0xf000 }, + { 0x03, 0xdf01 }, + { 0x02, 0xdf20 }, + { 0x01, 0x101a }, + { 0x00, 0xa0ff }, + { 0x04, 0xf800 }, + { 0x04, 0x0000 }, + { 0x1f, 0x0000 }, + + { 0x1f, 0x0001 }, + { 0x0b, 0x8480 }, + { 0x1f, 0x0000 }, + + { 0x1f, 0x0001 }, + { 0x18, 0x67c7 }, + { 0x04, 0x2000 }, + { 0x03, 0x002f }, + { 0x02, 0x4360 }, + { 0x01, 0x0109 }, + { 0x00, 0x3022 }, + { 0x04, 0x2800 }, + { 0x1f, 0x0000 }, + + { 0x1f, 0x0001 }, + { 0x17, 0x0cc0 }, + { 0x1f, 0x0000 } + }; + + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); +} + static void rtl8168bb_hw_phy_config(void __iomem *ioaddr) { struct phy_reg phy_reg_init[] = { @@ -1628,6 +1681,9 @@ static void rtl_hw_phy_config(struct net_device *dev) case RTL_GIGA_MAC_VER_04: rtl8169sb_hw_phy_config(ioaddr); break; + case RTL_GIGA_MAC_VER_06: + rtl8169sce_hw_phy_config(ioaddr); + break; case RTL_GIGA_MAC_VER_07: case RTL_GIGA_MAC_VER_08: case RTL_GIGA_MAC_VER_09: -- cgit v1.2.3-18-g5258 From 2e955856ff1212bd63dbbf403940c72eca5b4a8f Mon Sep 17 00:00:00 2001 From: françois romieu Date: Mon, 10 Aug 2009 19:44:19 +0000 Subject: r8169: phy init for the 8169scd Synced with Realtek's 6.011.00 r8169 driver. Signed-off-by: Francois Romieu Cc: Edward Hsu Signed-off-by: David S. Miller --- drivers/net/r8169.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 86722886ae4..4470fefbe97 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1389,6 +1389,71 @@ static void rtl8169sb_hw_phy_config(void __iomem *ioaddr) rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } +static void rtl8169scd_hw_phy_config_quirk(struct rtl8169_private *tp, + void __iomem *ioaddr) +{ + struct pci_dev *pdev = tp->pci_dev; + u16 vendor_id, device_id; + + pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &vendor_id); + pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &device_id); + + if ((vendor_id != PCI_VENDOR_ID_GIGABYTE) || (device_id != 0xe000)) + return; + + mdio_write(ioaddr, 0x1f, 0x0001); + mdio_write(ioaddr, 0x10, 0xf01b); + mdio_write(ioaddr, 0x1f, 0x0000); +} + +static void rtl8169scd_hw_phy_config(struct rtl8169_private *tp, + void __iomem *ioaddr) +{ + struct phy_reg phy_reg_init[] = { + { 0x1f, 0x0001 }, + { 0x04, 0x0000 }, + { 0x03, 0x00a1 }, + { 0x02, 0x0008 }, + { 0x01, 0x0120 }, + { 0x00, 0x1000 }, + { 0x04, 0x0800 }, + { 0x04, 0x9000 }, + { 0x03, 0x802f }, + { 0x02, 0x4f02 }, + { 0x01, 0x0409 }, + { 0x00, 0xf099 }, + { 0x04, 0x9800 }, + { 0x04, 0xa000 }, + { 0x03, 0xdf01 }, + { 0x02, 0xdf20 }, + { 0x01, 0xff95 }, + { 0x00, 0xba00 }, + { 0x04, 0xa800 }, + { 0x04, 0xf000 }, + { 0x03, 0xdf01 }, + { 0x02, 0xdf20 }, + { 0x01, 0x101a }, + { 0x00, 0xa0ff }, + { 0x04, 0xf800 }, + { 0x04, 0x0000 }, + { 0x1f, 0x0000 }, + + { 0x1f, 0x0001 }, + { 0x10, 0xf41b }, + { 0x14, 0xfb54 }, + { 0x18, 0xf5c7 }, + { 0x1f, 0x0000 }, + + { 0x1f, 0x0001 }, + { 0x17, 0x0cc0 }, + { 0x1f, 0x0000 } + }; + + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); + + rtl8169scd_hw_phy_config_quirk(tp, ioaddr); +} + static void rtl8169sce_hw_phy_config(void __iomem *ioaddr) { struct phy_reg phy_reg_init[] = { @@ -1681,6 +1746,9 @@ static void rtl_hw_phy_config(struct net_device *dev) case RTL_GIGA_MAC_VER_04: rtl8169sb_hw_phy_config(ioaddr); break; + case RTL_GIGA_MAC_VER_05: + rtl8169scd_hw_phy_config(tp, ioaddr); + break; case RTL_GIGA_MAC_VER_06: rtl8169sce_hw_phy_config(ioaddr); break; -- cgit v1.2.3-18-g5258 From 0b9b571d246d1c2621a5e4e5a0fa5cb95e18365d Mon Sep 17 00:00:00 2001 From: françois romieu Date: Mon, 10 Aug 2009 19:44:56 +0000 Subject: r8169: phy init for the 8169s Synced with Realtek's 6.011.00 r8169 driver. Signed-off-by: Francois Romieu Cc: Edward Hsu Signed-off-by: David S. Miller --- drivers/net/r8169.c | 116 +++++++++++++++++++++++++++------------------------- 1 file changed, 60 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 4470fefbe97..93a87aa7a0e 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1222,17 +1222,6 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { .get_ethtool_stats = rtl8169_get_ethtool_stats, }; -static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg, - int bitnum, int bitval) -{ - int val; - - val = mdio_read(ioaddr, reg); - val = (bitval == 1) ? - val | (bitval << bitnum) : val & ~(0x0001 << bitnum); - mdio_write(ioaddr, reg, val & 0xffff); -} - static void rtl8169_get_mac_version(struct rtl8169_private *tp, void __iomem *ioaddr) { @@ -1328,54 +1317,69 @@ static void rtl_phy_write(void __iomem *ioaddr, struct phy_reg *regs, int len) static void rtl8169s_hw_phy_config(void __iomem *ioaddr) { - struct { - u16 regs[5]; /* Beware of bit-sign propagation */ - } phy_magic[5] = { { - { 0x0000, //w 4 15 12 0 - 0x00a1, //w 3 15 0 00a1 - 0x0008, //w 2 15 0 0008 - 0x1020, //w 1 15 0 1020 - 0x1000 } },{ //w 0 15 0 1000 - { 0x7000, //w 4 15 12 7 - 0xff41, //w 3 15 0 ff41 - 0xde60, //w 2 15 0 de60 - 0x0140, //w 1 15 0 0140 - 0x0077 } },{ //w 0 15 0 0077 - { 0xa000, //w 4 15 12 a - 0xdf01, //w 3 15 0 df01 - 0xdf20, //w 2 15 0 df20 - 0xff95, //w 1 15 0 ff95 - 0xfa00 } },{ //w 0 15 0 fa00 - { 0xb000, //w 4 15 12 b - 0xff41, //w 3 15 0 ff41 - 0xde20, //w 2 15 0 de20 - 0x0140, //w 1 15 0 0140 - 0x00bb } },{ //w 0 15 0 00bb - { 0xf000, //w 4 15 12 f - 0xdf01, //w 3 15 0 df01 - 0xdf20, //w 2 15 0 df20 - 0xff95, //w 1 15 0 ff95 - 0xbf00 } //w 0 15 0 bf00 - } - }, *p = phy_magic; - unsigned int i; + struct phy_reg phy_reg_init[] = { + { 0x1f, 0x0001 }, + { 0x06, 0x006e }, + { 0x08, 0x0708 }, + { 0x15, 0x4000 }, + { 0x18, 0x65c7 }, - mdio_write(ioaddr, 0x1f, 0x0001); //w 31 2 0 1 - mdio_write(ioaddr, 0x15, 0x1000); //w 21 15 0 1000 - mdio_write(ioaddr, 0x18, 0x65c7); //w 24 15 0 65c7 - rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0 + { 0x1f, 0x0001 }, + { 0x03, 0x00a1 }, + { 0x02, 0x0008 }, + { 0x01, 0x0120 }, + { 0x00, 0x1000 }, + { 0x04, 0x0800 }, + { 0x04, 0x0000 }, - for (i = 0; i < ARRAY_SIZE(phy_magic); i++, p++) { - int val, pos = 4; + { 0x03, 0xff41 }, + { 0x02, 0xdf60 }, + { 0x01, 0x0140 }, + { 0x00, 0x0077 }, + { 0x04, 0x7800 }, + { 0x04, 0x7000 }, - val = (mdio_read(ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff); - mdio_write(ioaddr, pos, val); - while (--pos >= 0) - mdio_write(ioaddr, pos, p->regs[4 - pos] & 0xffff); - rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1 - rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0 - } - mdio_write(ioaddr, 0x1f, 0x0000); //w 31 2 0 0 + { 0x03, 0x802f }, + { 0x02, 0x4f02 }, + { 0x01, 0x0409 }, + { 0x00, 0xf0f9 }, + { 0x04, 0x9800 }, + { 0x04, 0x9000 }, + + { 0x03, 0xdf01 }, + { 0x02, 0xdf20 }, + { 0x01, 0xff95 }, + { 0x00, 0xba00 }, + { 0x04, 0xa800 }, + { 0x04, 0xa000 }, + + { 0x03, 0xff41 }, + { 0x02, 0xdf20 }, + { 0x01, 0x0140 }, + { 0x00, 0x00bb }, + { 0x04, 0xb800 }, + { 0x04, 0xb000 }, + + { 0x03, 0xdf41 }, + { 0x02, 0xdc60 }, + { 0x01, 0x6340 }, + { 0x00, 0x007d }, + { 0x04, 0xd800 }, + { 0x04, 0xd000 }, + + { 0x03, 0xdf01 }, + { 0x02, 0xdf20 }, + { 0x01, 0x100a }, + { 0x00, 0xa0ff }, + { 0x04, 0xf800 }, + { 0x04, 0xf000 }, + + { 0x1f, 0x0000 }, + { 0x0b, 0x0000 }, + { 0x00, 0x9200 } + }; + + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } static void rtl8169sb_hw_phy_config(void __iomem *ioaddr) -- cgit v1.2.3-18-g5258 From 85910a8e9f425656bb7202d0fc62800000ffa262 Mon Sep 17 00:00:00 2001 From: françois romieu Date: Mon, 10 Aug 2009 19:45:48 +0000 Subject: r8169: phy init for the 8102e Synced with Realtek's 1.013.00 r8101 driver. Signed-off-by: Francois Romieu Cc: Edward Hsu Signed-off-by: David S. Miller --- drivers/net/r8169.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 93a87aa7a0e..8cd85309c67 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1729,6 +1729,7 @@ static void rtl8102e_hw_phy_config(void __iomem *ioaddr) mdio_write(ioaddr, 0x1f, 0x0000); mdio_patch(ioaddr, 0x11, 1 << 12); mdio_patch(ioaddr, 0x19, 1 << 13); + mdio_patch(ioaddr, 0x10, 1 << 15); rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } -- cgit v1.2.3-18-g5258 From ca00392cb8f5227c67ff52c656d91a764d022ab9 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 22:53:28 -0700 Subject: bnx2x: Using the new FW The new FW improves the packets per second rate. It required a lot of change in the FW which implies many changes in the driver to support it. It is now also possible for the driver to use a separate MSI-X vector for Rx and Tx - this also add some to the complicity of this change. All things said - after this patch, practically all performance matrixes show improvement. Though Vladislav Zolotarov is not signed on this patch, he did most of the job and deserves credit for that. Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x.h | 45 ++- drivers/net/bnx2x_fw_defs.h | 379 +++++++++++++------ drivers/net/bnx2x_hsi.h | 361 +++++++++++++----- drivers/net/bnx2x_main.c | 888 ++++++++++++++++++++++++-------------------- drivers/net/bnx2x_reg.h | 60 +-- 5 files changed, 1074 insertions(+), 659 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 8bd80fca978..16ccba8dda1 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -142,6 +142,9 @@ struct sw_rx_bd { struct sw_tx_bd { struct sk_buff *skb; u16 first_bd; + u8 flags; +/* Set on the first BD descriptor when there is a split BD */ +#define BNX2X_TSO_SPLIT_BD (1<<0) }; struct sw_rx_page { @@ -149,6 +152,11 @@ struct sw_rx_page { DECLARE_PCI_UNMAP_ADDR(mapping) }; +union db_prod { + struct doorbell_set_prod data; + u32 raw; +}; + /* MC hsi */ #define BCM_PAGE_SHIFT 12 @@ -234,15 +242,14 @@ struct bnx2x_fastpath { struct napi_struct napi; + u8 is_rx_queue; + struct host_status_block *status_blk; dma_addr_t status_blk_mapping; - struct eth_tx_db_data *hw_tx_prods; - dma_addr_t tx_prods_mapping; - struct sw_tx_bd *tx_buf_ring; - struct eth_tx_bd *tx_desc_ring; + union eth_tx_bd_types *tx_desc_ring; dma_addr_t tx_desc_mapping; struct sw_rx_bd *rx_buf_ring; /* BDs mappings ring */ @@ -272,6 +279,8 @@ struct bnx2x_fastpath { u8 cl_id; /* eth client id */ u8 sb_id; /* status block number in HW */ + union db_prod tx_db; + u16 tx_pkt_prod; u16 tx_pkt_cons; u16 tx_bd_prod; @@ -309,21 +318,24 @@ struct bnx2x_fastpath { struct xstorm_per_client_stats old_xclient; struct bnx2x_eth_q_stats eth_q_stats; - char name[IFNAMSIZ]; + /* The size is calculated using the following: + sizeof name field from netdev structure + + 4 ('-Xx-' string) + + 4 (for the digits and to make it DWORD aligned) */ +#define FP_NAME_SIZE (sizeof(((struct net_device *)0)->name) + 8) + char name[FP_NAME_SIZE]; struct bnx2x *bp; /* parent */ }; #define bnx2x_fp(bp, nr, var) (bp->fp[nr].var) -#define BNX2X_HAS_WORK(fp) (bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp)) - /* MC hsi */ #define MAX_FETCH_BD 13 /* HW max BDs per packet */ #define RX_COPY_THRESH 92 #define NUM_TX_RINGS 16 -#define TX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_tx_bd)) +#define TX_DESC_CNT (BCM_PAGE_SIZE / sizeof(union eth_tx_bd_types)) #define MAX_TX_DESC_CNT (TX_DESC_CNT - 1) #define NUM_TX_BD (TX_DESC_CNT * NUM_TX_RINGS) #define MAX_TX_BD (NUM_TX_BD - 1) @@ -395,7 +407,7 @@ struct bnx2x_fastpath { #define DPM_TRIGER_TYPE 0x40 #define DOORBELL(bp, cid, val) \ do { \ - writel((u32)val, (bp)->doorbells + (BCM_PAGE_SIZE * cid) + \ + writel((u32)(val), bp->doorbells + (BCM_PAGE_SIZE * (cid)) + \ DPM_TRIGER_TYPE); \ } while (0) @@ -902,8 +914,6 @@ struct bnx2x { u16 rx_quick_cons_trip; u16 rx_ticks_int; u16 rx_ticks; -/* Maximal coalescing timeout in us */ -#define BNX2X_MAX_COALESCE_TOUT (0xf0*12) u32 lin_cnt; @@ -985,19 +995,20 @@ struct bnx2x { }; -#define BNX2X_MAX_QUEUES(bp) (IS_E1HMF(bp) ? (MAX_CONTEXT / E1HVN_MAX) : \ - MAX_CONTEXT) -#define BNX2X_NUM_QUEUES(bp) max(bp->num_rx_queues, bp->num_tx_queues) -#define is_multi(bp) (BNX2X_NUM_QUEUES(bp) > 1) +#define BNX2X_MAX_QUEUES(bp) (IS_E1HMF(bp) ? (MAX_CONTEXT/(2 * E1HVN_MAX)) \ + : (MAX_CONTEXT/2)) +#define BNX2X_NUM_QUEUES(bp) (bp->num_rx_queues + bp->num_tx_queues) +#define is_multi(bp) (BNX2X_NUM_QUEUES(bp) > 2) #define for_each_rx_queue(bp, var) \ for (var = 0; var < bp->num_rx_queues; var++) #define for_each_tx_queue(bp, var) \ - for (var = 0; var < bp->num_tx_queues; var++) + for (var = bp->num_rx_queues; \ + var < BNX2X_NUM_QUEUES(bp); var++) #define for_each_queue(bp, var) \ for (var = 0; var < BNX2X_NUM_QUEUES(bp); var++) #define for_each_nondefault_queue(bp, var) \ - for (var = 1; var < BNX2X_NUM_QUEUES(bp); var++) + for (var = 1; var < bp->num_rx_queues; var++) void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32); diff --git a/drivers/net/bnx2x_fw_defs.h b/drivers/net/bnx2x_fw_defs.h index e2df2380359..931dcace562 100644 --- a/drivers/net/bnx2x_fw_defs.h +++ b/drivers/net/bnx2x_fw_defs.h @@ -12,48 +12,117 @@ (IS_E1H_OFFSET ? 0x7000 : 0x1000) #define CSTORM_ASSERT_LIST_OFFSET(idx) \ (IS_E1H_OFFSET ? (0x7020 + (idx * 0x10)) : (0x1020 + (idx * 0x10))) -#define CSTORM_DEF_SB_HC_DISABLE_OFFSET(function, index) \ - (IS_E1H_OFFSET ? (0x8522 + ((function>>1) * 0x40) + \ - ((function&1) * 0x100) + (index * 0x4)) : (0x1922 + (function * \ +#define CSTORM_DEF_SB_HC_DISABLE_C_OFFSET(function, index) \ + (IS_E1H_OFFSET ? (0x8622 + ((function>>1) * 0x40) + \ + ((function&1) * 0x100) + (index * 0x4)) : (0x3562 + (function * \ 0x40) + (index * 0x4))) -#define CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x8500 + ((function>>1) * 0x40) + \ - ((function&1) * 0x100)) : (0x1900 + (function * 0x40))) -#define CSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x8508 + ((function>>1) * 0x40) + \ - ((function&1) * 0x100)) : (0x1908 + (function * 0x40))) +#define CSTORM_DEF_SB_HC_DISABLE_U_OFFSET(function, index) \ + (IS_E1H_OFFSET ? (0x8822 + ((function>>1) * 0x80) + \ + ((function&1) * 0x200) + (index * 0x4)) : (0x35e2 + (function * \ + 0x80) + (index * 0x4))) +#define CSTORM_DEF_SB_HOST_SB_ADDR_C_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8600 + ((function>>1) * 0x40) + \ + ((function&1) * 0x100)) : (0x3540 + (function * 0x40))) +#define CSTORM_DEF_SB_HOST_SB_ADDR_U_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8800 + ((function>>1) * 0x80) + \ + ((function&1) * 0x200)) : (0x35c0 + (function * 0x80))) +#define CSTORM_DEF_SB_HOST_STATUS_BLOCK_C_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8608 + ((function>>1) * 0x40) + \ + ((function&1) * 0x100)) : (0x3548 + (function * 0x40))) +#define CSTORM_DEF_SB_HOST_STATUS_BLOCK_U_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8808 + ((function>>1) * 0x80) + \ + ((function&1) * 0x200)) : (0x35c8 + (function * 0x80))) #define CSTORM_FUNCTION_MODE_OFFSET \ (IS_E1H_OFFSET ? 0x11e8 : 0xffffffff) -#define CSTORM_HC_BTR_OFFSET(port) \ - (IS_E1H_OFFSET ? (0x8704 + (port * 0xf0)) : (0x1984 + (port * 0xc0))) -#define CSTORM_SB_HC_DISABLE_OFFSET(port, cpu_id, index) \ - (IS_E1H_OFFSET ? (0x801a + (port * 0x280) + (cpu_id * 0x28) + \ - (index * 0x4)) : (0x141a + (port * 0x280) + (cpu_id * 0x28) + \ +#define CSTORM_HC_BTR_C_OFFSET(port) \ + (IS_E1H_OFFSET ? (0x8c04 + (port * 0xf0)) : (0x36c4 + (port * 0xc0))) +#define CSTORM_HC_BTR_U_OFFSET(port) \ + (IS_E1H_OFFSET ? (0x8de4 + (port * 0xf0)) : (0x3844 + (port * 0xc0))) +#define CSTORM_ISCSI_CQ_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6680 + (function * 0x8)) : (0x25a0 + \ + (function * 0x8))) +#define CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x66c0 + (function * 0x8)) : (0x25b0 + \ + (function * 0x8))) +#define CSTORM_ISCSI_EQ_CONS_OFFSET(function, eqIdx) \ + (IS_E1H_OFFSET ? (0x6040 + (function * 0xc0) + (eqIdx * 0x18)) : \ + (0x2410 + (function * 0xc0) + (eqIdx * 0x18))) +#define CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(function, eqIdx) \ + (IS_E1H_OFFSET ? (0x6044 + (function * 0xc0) + (eqIdx * 0x18)) : \ + (0x2414 + (function * 0xc0) + (eqIdx * 0x18))) +#define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(function, eqIdx) \ + (IS_E1H_OFFSET ? (0x604c + (function * 0xc0) + (eqIdx * 0x18)) : \ + (0x241c + (function * 0xc0) + (eqIdx * 0x18))) +#define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_VALID_OFFSET(function, eqIdx) \ + (IS_E1H_OFFSET ? (0x6057 + (function * 0xc0) + (eqIdx * 0x18)) : \ + (0x2427 + (function * 0xc0) + (eqIdx * 0x18))) +#define CSTORM_ISCSI_EQ_PROD_OFFSET(function, eqIdx) \ + (IS_E1H_OFFSET ? (0x6042 + (function * 0xc0) + (eqIdx * 0x18)) : \ + (0x2412 + (function * 0xc0) + (eqIdx * 0x18))) +#define CSTORM_ISCSI_EQ_SB_INDEX_OFFSET(function, eqIdx) \ + (IS_E1H_OFFSET ? (0x6056 + (function * 0xc0) + (eqIdx * 0x18)) : \ + (0x2426 + (function * 0xc0) + (eqIdx * 0x18))) +#define CSTORM_ISCSI_EQ_SB_NUM_OFFSET(function, eqIdx) \ + (IS_E1H_OFFSET ? (0x6054 + (function * 0xc0) + (eqIdx * 0x18)) : \ + (0x2424 + (function * 0xc0) + (eqIdx * 0x18))) +#define CSTORM_ISCSI_HQ_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6640 + (function * 0x8)) : (0x2590 + \ + (function * 0x8))) +#define CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6004 + (function * 0x8)) : (0x2404 + \ + (function * 0x8))) +#define CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6002 + (function * 0x8)) : (0x2402 + \ + (function * 0x8))) +#define CSTORM_ISCSI_PAGE_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6000 + (function * 0x8)) : (0x2400 + \ + (function * 0x8))) +#define CSTORM_SB_HC_DISABLE_C_OFFSET(port, cpu_id, index) \ + (IS_E1H_OFFSET ? (0x811a + (port * 0x280) + (cpu_id * 0x28) + \ + (index * 0x4)) : (0x305a + (port * 0x280) + (cpu_id * 0x28) + \ + (index * 0x4))) +#define CSTORM_SB_HC_DISABLE_U_OFFSET(port, cpu_id, index) \ + (IS_E1H_OFFSET ? (0xb01a + (port * 0x800) + (cpu_id * 0x80) + \ + (index * 0x4)) : (0x401a + (port * 0x800) + (cpu_id * 0x80) + \ (index * 0x4))) -#define CSTORM_SB_HC_TIMEOUT_OFFSET(port, cpu_id, index) \ - (IS_E1H_OFFSET ? (0x8018 + (port * 0x280) + (cpu_id * 0x28) + \ - (index * 0x4)) : (0x1418 + (port * 0x280) + (cpu_id * 0x28) + \ +#define CSTORM_SB_HC_TIMEOUT_C_OFFSET(port, cpu_id, index) \ + (IS_E1H_OFFSET ? (0x8118 + (port * 0x280) + (cpu_id * 0x28) + \ + (index * 0x4)) : (0x3058 + (port * 0x280) + (cpu_id * 0x28) + \ (index * 0x4))) -#define CSTORM_SB_HOST_SB_ADDR_OFFSET(port, cpu_id) \ - (IS_E1H_OFFSET ? (0x8000 + (port * 0x280) + (cpu_id * 0x28)) : \ - (0x1400 + (port * 0x280) + (cpu_id * 0x28))) -#define CSTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, cpu_id) \ - (IS_E1H_OFFSET ? (0x8008 + (port * 0x280) + (cpu_id * 0x28)) : \ - (0x1408 + (port * 0x280) + (cpu_id * 0x28))) +#define CSTORM_SB_HC_TIMEOUT_U_OFFSET(port, cpu_id, index) \ + (IS_E1H_OFFSET ? (0xb018 + (port * 0x800) + (cpu_id * 0x80) + \ + (index * 0x4)) : (0x4018 + (port * 0x800) + (cpu_id * 0x80) + \ + (index * 0x4))) +#define CSTORM_SB_HOST_SB_ADDR_C_OFFSET(port, cpu_id) \ + (IS_E1H_OFFSET ? (0x8100 + (port * 0x280) + (cpu_id * 0x28)) : \ + (0x3040 + (port * 0x280) + (cpu_id * 0x28))) +#define CSTORM_SB_HOST_SB_ADDR_U_OFFSET(port, cpu_id) \ + (IS_E1H_OFFSET ? (0xb000 + (port * 0x800) + (cpu_id * 0x80)) : \ + (0x4000 + (port * 0x800) + (cpu_id * 0x80))) +#define CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, cpu_id) \ + (IS_E1H_OFFSET ? (0x8108 + (port * 0x280) + (cpu_id * 0x28)) : \ + (0x3048 + (port * 0x280) + (cpu_id * 0x28))) +#define CSTORM_SB_HOST_STATUS_BLOCK_U_OFFSET(port, cpu_id) \ + (IS_E1H_OFFSET ? (0xb008 + (port * 0x800) + (cpu_id * 0x80)) : \ + (0x4008 + (port * 0x800) + (cpu_id * 0x80))) +#define CSTORM_SB_STATUS_BLOCK_C_SIZE 0x10 +#define CSTORM_SB_STATUS_BLOCK_U_SIZE 0x60 #define CSTORM_STATS_FLAGS_OFFSET(function) \ (IS_E1H_OFFSET ? (0x1108 + (function * 0x8)) : (0x5108 + \ (function * 0x8))) #define TSTORM_APPROXIMATE_MATCH_MULTICAST_FILTERING_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x31c0 + (function * 0x20)) : 0xffffffff) + (IS_E1H_OFFSET ? (0x3200 + (function * 0x20)) : 0xffffffff) #define TSTORM_ASSERT_LIST_INDEX_OFFSET \ (IS_E1H_OFFSET ? 0xa000 : 0x1000) #define TSTORM_ASSERT_LIST_OFFSET(idx) \ (IS_E1H_OFFSET ? (0xa020 + (idx * 0x10)) : (0x1020 + (idx * 0x10))) #define TSTORM_CLIENT_CONFIG_OFFSET(port, client_id) \ - (IS_E1H_OFFSET ? (0x3350 + (port * 0x190) + (client_id * 0x10)) \ - : (0x9c0 + (port * 0x130) + (client_id * 0x10))) + (IS_E1H_OFFSET ? (0x33a0 + (port * 0x1a0) + (client_id * 0x10)) \ + : (0x9c0 + (port * 0x120) + (client_id * 0x10))) #define TSTORM_COMMON_SAFC_WORKAROUND_ENABLE_OFFSET \ - (IS_E1H_OFFSET ? 0x1ad8 : 0xffffffff) + (IS_E1H_OFFSET ? 0x1ed8 : 0xffffffff) +#define TSTORM_COMMON_SAFC_WORKAROUND_TIMEOUT_10USEC_OFFSET \ + (IS_E1H_OFFSET ? 0x1eda : 0xffffffff) #define TSTORM_DEF_SB_HC_DISABLE_OFFSET(function, index) \ (IS_E1H_OFFSET ? (0xb01a + ((function>>1) * 0x28) + \ ((function&1) * 0xa0) + (index * 0x4)) : (0x141a + (function * \ @@ -65,95 +134,133 @@ (IS_E1H_OFFSET ? (0xb008 + ((function>>1) * 0x28) + \ ((function&1) * 0xa0)) : (0x1408 + (function * 0x28))) #define TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x2b80 + (function * 0x8)) : (0x4b68 + \ + (IS_E1H_OFFSET ? (0x2940 + (function * 0x8)) : (0x4928 + \ (function * 0x8))) #define TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x3000 + (function * 0x38)) : (0x1500 + \ - (function * 0x38))) + (IS_E1H_OFFSET ? (0x3000 + (function * 0x40)) : (0x1500 + \ + (function * 0x40))) #define TSTORM_FUNCTION_MODE_OFFSET \ - (IS_E1H_OFFSET ? 0x1ad0 : 0xffffffff) + (IS_E1H_OFFSET ? 0x1ed0 : 0xffffffff) #define TSTORM_HC_BTR_OFFSET(port) \ (IS_E1H_OFFSET ? (0xb144 + (port * 0x30)) : (0x1454 + (port * 0x18))) #define TSTORM_INDIRECTION_TABLE_OFFSET(function) \ (IS_E1H_OFFSET ? (0x12c8 + (function * 0x80)) : (0x22c8 + \ (function * 0x80))) #define TSTORM_INDIRECTION_TABLE_SIZE 0x80 +#define TSTORM_ISCSI_CONN_BUF_PBL_OFFSET(function, pblEntry) \ + (IS_E1H_OFFSET ? (0x60c0 + (function * 0x40) + (pblEntry * 0x8)) \ + : (0x4c30 + (function * 0x40) + (pblEntry * 0x8))) +#define TSTORM_ISCSI_ERROR_BITMAP_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6340 + (function * 0x8)) : (0x4cd0 + \ + (function * 0x8))) +#define TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6004 + (function * 0x8)) : (0x4c04 + \ + (function * 0x8))) +#define TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6002 + (function * 0x8)) : (0x4c02 + \ + (function * 0x8))) +#define TSTORM_ISCSI_PAGE_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6000 + (function * 0x8)) : (0x4c00 + \ + (function * 0x8))) +#define TSTORM_ISCSI_RQ_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6080 + (function * 0x8)) : (0x4c20 + \ + (function * 0x8))) +#define TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6040 + (function * 0x8)) : (0x4c10 + \ + (function * 0x8))) +#define TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6042 + (function * 0x8)) : (0x4c12 + \ + (function * 0x8))) +#define TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x6044 + (function * 0x8)) : (0x4c14 + \ + (function * 0x8))) #define TSTORM_MAC_FILTER_CONFIG_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x3008 + (function * 0x38)) : (0x1508 + \ - (function * 0x38))) + (IS_E1H_OFFSET ? (0x3008 + (function * 0x40)) : (0x1508 + \ + (function * 0x40))) #define TSTORM_PER_COUNTER_ID_STATS_OFFSET(port, stats_counter_id) \ - (IS_E1H_OFFSET ? (0x2010 + (port * 0x5b0) + (stats_counter_id * \ - 0x50)) : (0x4080 + (port * 0x5b0) + (stats_counter_id * 0x50))) + (IS_E1H_OFFSET ? (0x2010 + (port * 0x490) + (stats_counter_id * \ + 0x40)) : (0x4010 + (port * 0x490) + (stats_counter_id * 0x40))) #define TSTORM_STATS_FLAGS_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x2c00 + (function * 0x8)) : (0x4b88 + \ + (IS_E1H_OFFSET ? (0x29c0 + (function * 0x8)) : (0x4948 + \ (function * 0x8))) -#define TSTORM_TPA_EXIST_OFFSET (IS_E1H_OFFSET ? 0x3680 : 0x1c20) -#define USTORM_AGG_DATA_OFFSET (IS_E1H_OFFSET ? 0xa040 : 0x2c10) -#define USTORM_AGG_DATA_SIZE (IS_E1H_OFFSET ? 0x2440 : 0x1200) +#define TSTORM_TCP_MAX_CWND_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x4004 + (function * 0x8)) : (0x1fb4 + \ + (function * 0x8))) +#define USTORM_AGG_DATA_OFFSET (IS_E1H_OFFSET ? 0xa000 : 0x3000) +#define USTORM_AGG_DATA_SIZE (IS_E1H_OFFSET ? 0x2000 : 0x1000) #define USTORM_ASSERT_LIST_INDEX_OFFSET \ - (IS_E1H_OFFSET ? 0x8960 : 0x1000) + (IS_E1H_OFFSET ? 0x8000 : 0x1000) #define USTORM_ASSERT_LIST_OFFSET(idx) \ - (IS_E1H_OFFSET ? (0x8980 + (idx * 0x10)) : (0x1020 + (idx * 0x10))) + (IS_E1H_OFFSET ? (0x8020 + (idx * 0x10)) : (0x1020 + (idx * 0x10))) #define USTORM_CQE_PAGE_BASE_OFFSET(port, clientId) \ - (IS_E1H_OFFSET ? (0x8018 + (port * 0x4b0) + (clientId * 0x30)) : \ - (0x5330 + (port * 0x260) + (clientId * 0x20))) -#define USTORM_DEF_SB_HC_DISABLE_OFFSET(function, index) \ - (IS_E1H_OFFSET ? (0x9522 + ((function>>1) * 0x40) + \ - ((function&1) * 0x100) + (index * 0x4)) : (0x1922 + (function * \ - 0x40) + (index * 0x4))) -#define USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x9500 + ((function>>1) * 0x40) + \ - ((function&1) * 0x100)) : (0x1900 + (function * 0x40))) -#define USTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x9508 + ((function>>1) * 0x40) + \ - ((function&1) * 0x100)) : (0x1908 + (function * 0x40))) + (IS_E1H_OFFSET ? (0x1010 + (port * 0x680) + (clientId * 0x40)) : \ + (0x4010 + (port * 0x360) + (clientId * 0x30))) +#define USTORM_CQE_PAGE_NEXT_OFFSET(port, clientId) \ + (IS_E1H_OFFSET ? (0x1028 + (port * 0x680) + (clientId * 0x40)) : \ + (0x4028 + (port * 0x360) + (clientId * 0x30))) +#define USTORM_ETH_PAUSE_ENABLED_OFFSET(port) \ + (IS_E1H_OFFSET ? (0x2ad4 + (port * 0x8)) : 0xffffffff) #define USTORM_ETH_RING_PAUSE_DATA_OFFSET(port, clientId) \ - (IS_E1H_OFFSET ? (0x8020 + (port * 0x4b0) + (clientId * 0x30)) : \ + (IS_E1H_OFFSET ? (0x1030 + (port * 0x680) + (clientId * 0x40)) : \ 0xffffffff) #define USTORM_ETH_STATS_QUERY_ADDR_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x2a50 + (function * 0x8)) : (0x1d98 + \ + (IS_E1H_OFFSET ? (0x2a50 + (function * 0x8)) : (0x1dd0 + \ (function * 0x8))) #define USTORM_FUNCTION_MODE_OFFSET \ (IS_E1H_OFFSET ? 0x2448 : 0xffffffff) -#define USTORM_HC_BTR_OFFSET(port) \ - (IS_E1H_OFFSET ? (0x9704 + (port * 0xf0)) : (0x1984 + (port * 0xc0))) +#define USTORM_ISCSI_CQ_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x7044 + (function * 0x8)) : (0x2414 + \ + (function * 0x8))) +#define USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x7046 + (function * 0x8)) : (0x2416 + \ + (function * 0x8))) +#define USTORM_ISCSI_ERROR_BITMAP_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x7688 + (function * 0x8)) : (0x29c8 + \ + (function * 0x8))) +#define USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x7648 + (function * 0x8)) : (0x29b8 + \ + (function * 0x8))) +#define USTORM_ISCSI_NUM_OF_TASKS_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x7004 + (function * 0x8)) : (0x2404 + \ + (function * 0x8))) +#define USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x7002 + (function * 0x8)) : (0x2402 + \ + (function * 0x8))) +#define USTORM_ISCSI_PAGE_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x7000 + (function * 0x8)) : (0x2400 + \ + (function * 0x8))) +#define USTORM_ISCSI_R2TQ_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x7040 + (function * 0x8)) : (0x2410 + \ + (function * 0x8))) +#define USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x7080 + (function * 0x8)) : (0x2420 + \ + (function * 0x8))) +#define USTORM_ISCSI_RQ_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x7084 + (function * 0x8)) : (0x2424 + \ + (function * 0x8))) #define USTORM_MAX_AGG_SIZE_OFFSET(port, clientId) \ - (IS_E1H_OFFSET ? (0x8010 + (port * 0x4b0) + (clientId * 0x30)) : \ - (0x5328 + (port * 0x260) + (clientId * 0x20))) + (IS_E1H_OFFSET ? (0x1018 + (port * 0x680) + (clientId * 0x40)) : \ + (0x4018 + (port * 0x360) + (clientId * 0x30))) #define USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x2408 + (function * 0x8)) : (0x5308 + \ + (IS_E1H_OFFSET ? (0x2408 + (function * 0x8)) : (0x1da8 + \ (function * 0x8))) -#define USTORM_PAUSE_ENABLED_OFFSET(port) \ - (IS_E1H_OFFSET ? (0x2ad4 + (port * 0x8)) : 0xffffffff) #define USTORM_PER_COUNTER_ID_STATS_OFFSET(port, stats_counter_id) \ (IS_E1H_OFFSET ? (0x2450 + (port * 0x2d0) + (stats_counter_id * \ - 0x28)) : (0x4740 + (port * 0x2d0) + (stats_counter_id * 0x28))) + 0x28)) : (0x1500 + (port * 0x2d0) + (stats_counter_id * 0x28))) #define USTORM_RX_PRODS_OFFSET(port, client_id) \ - (IS_E1H_OFFSET ? (0x8000 + (port * 0x4b0) + (client_id * 0x30)) \ - : (0x5318 + (port * 0x260) + (client_id * 0x20))) -#define USTORM_SB_HC_DISABLE_OFFSET(port, cpu_id, index) \ - (IS_E1H_OFFSET ? (0x901a + (port * 0x280) + (cpu_id * 0x28) + \ - (index * 0x4)) : (0x141a + (port * 0x280) + (cpu_id * 0x28) + \ - (index * 0x4))) -#define USTORM_SB_HC_TIMEOUT_OFFSET(port, cpu_id, index) \ - (IS_E1H_OFFSET ? (0x9018 + (port * 0x280) + (cpu_id * 0x28) + \ - (index * 0x4)) : (0x1418 + (port * 0x280) + (cpu_id * 0x28) + \ - (index * 0x4))) -#define USTORM_SB_HOST_SB_ADDR_OFFSET(port, cpu_id) \ - (IS_E1H_OFFSET ? (0x9000 + (port * 0x280) + (cpu_id * 0x28)) : \ - (0x1400 + (port * 0x280) + (cpu_id * 0x28))) -#define USTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, cpu_id) \ - (IS_E1H_OFFSET ? (0x9008 + (port * 0x280) + (cpu_id * 0x28)) : \ - (0x1408 + (port * 0x280) + (cpu_id * 0x28))) + (IS_E1H_OFFSET ? (0x1000 + (port * 0x680) + (client_id * 0x40)) \ + : (0x4000 + (port * 0x360) + (client_id * 0x30))) #define USTORM_STATS_FLAGS_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x29f0 + (function * 0x8)) : (0x1d80 + \ + (IS_E1H_OFFSET ? (0x29f0 + (function * 0x8)) : (0x1db8 + \ (function * 0x8))) +#define USTORM_TPA_BTR_OFFSET (IS_E1H_OFFSET ? 0x3da5 : 0x5095) +#define USTORM_TPA_BTR_SIZE 0x1 #define XSTORM_ASSERT_LIST_INDEX_OFFSET \ (IS_E1H_OFFSET ? 0x9000 : 0x1000) #define XSTORM_ASSERT_LIST_OFFSET(idx) \ (IS_E1H_OFFSET ? (0x9020 + (idx * 0x10)) : (0x1020 + (idx * 0x10))) #define XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) \ - (IS_E1H_OFFSET ? (0x24a8 + (port * 0x50)) : (0x3ba0 + (port * 0x50))) + (IS_E1H_OFFSET ? (0x24a8 + (port * 0x50)) : (0x3a80 + (port * 0x50))) #define XSTORM_DEF_SB_HC_DISABLE_OFFSET(function, index) \ (IS_E1H_OFFSET ? (0xa01a + ((function>>1) * 0x28) + \ ((function&1) * 0xa0) + (index * 0x4)) : (0x141a + (function * \ @@ -165,22 +272,73 @@ (IS_E1H_OFFSET ? (0xa008 + ((function>>1) * 0x28) + \ ((function&1) * 0xa0)) : (0x1408 + (function * 0x28))) #define XSTORM_E1HOV_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x2c10 + (function * 0x2)) : 0xffffffff) + (IS_E1H_OFFSET ? (0x2c10 + (function * 0x8)) : 0xffffffff) #define XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x2418 + (function * 0x8)) : (0x3b70 + \ + (IS_E1H_OFFSET ? (0x2418 + (function * 0x8)) : (0x3a50 + \ (function * 0x8))) #define XSTORM_FAIRNESS_PER_VN_VARS_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x2588 + (function * 0x90)) : (0x3c80 + \ + (IS_E1H_OFFSET ? (0x2588 + (function * 0x90)) : (0x3b60 + \ (function * 0x90))) #define XSTORM_FUNCTION_MODE_OFFSET \ - (IS_E1H_OFFSET ? 0x2c20 : 0xffffffff) + (IS_E1H_OFFSET ? 0x2c50 : 0xffffffff) #define XSTORM_HC_BTR_OFFSET(port) \ (IS_E1H_OFFSET ? (0xa144 + (port * 0x30)) : (0x1454 + (port * 0x18))) +#define XSTORM_ISCSI_HQ_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x80c0 + (function * 0x8)) : (0x1c30 + \ + (function * 0x8))) +#define XSTORM_ISCSI_LOCAL_MAC_ADDR0_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8080 + (function * 0x8)) : (0x1c20 + \ + (function * 0x8))) +#define XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8081 + (function * 0x8)) : (0x1c21 + \ + (function * 0x8))) +#define XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8082 + (function * 0x8)) : (0x1c22 + \ + (function * 0x8))) +#define XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8083 + (function * 0x8)) : (0x1c23 + \ + (function * 0x8))) +#define XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8084 + (function * 0x8)) : (0x1c24 + \ + (function * 0x8))) +#define XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8085 + (function * 0x8)) : (0x1c25 + \ + (function * 0x8))) +#define XSTORM_ISCSI_LOCAL_VLAN_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8086 + (function * 0x8)) : (0x1c26 + \ + (function * 0x8))) +#define XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8004 + (function * 0x8)) : (0x1c04 + \ + (function * 0x8))) +#define XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8002 + (function * 0x8)) : (0x1c02 + \ + (function * 0x8))) +#define XSTORM_ISCSI_PAGE_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8000 + (function * 0x8)) : (0x1c00 + \ + (function * 0x8))) +#define XSTORM_ISCSI_R2TQ_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x80c4 + (function * 0x8)) : (0x1c34 + \ + (function * 0x8))) +#define XSTORM_ISCSI_SQ_SIZE_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x80c2 + (function * 0x8)) : (0x1c32 + \ + (function * 0x8))) +#define XSTORM_ISCSI_TCP_VARS_ADV_WND_SCL_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8043 + (function * 0x8)) : (0x1c13 + \ + (function * 0x8))) +#define XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8042 + (function * 0x8)) : (0x1c12 + \ + (function * 0x8))) +#define XSTORM_ISCSI_TCP_VARS_TOS_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8041 + (function * 0x8)) : (0x1c11 + \ + (function * 0x8))) +#define XSTORM_ISCSI_TCP_VARS_TTL_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x8040 + (function * 0x8)) : (0x1c10 + \ + (function * 0x8))) #define XSTORM_PER_COUNTER_ID_STATS_OFFSET(port, stats_counter_id) \ - (IS_E1H_OFFSET ? (0xc000 + (port * 0x3f0) + (stats_counter_id * \ - 0x38)) : (0x3378 + (port * 0x3f0) + (stats_counter_id * 0x38))) + (IS_E1H_OFFSET ? (0xc000 + (port * 0x360) + (stats_counter_id * \ + 0x30)) : (0x3378 + (port * 0x360) + (stats_counter_id * 0x30))) #define XSTORM_RATE_SHAPING_PER_VN_VARS_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x2548 + (function * 0x90)) : (0x3c40 + \ + (IS_E1H_OFFSET ? (0x2548 + (function * 0x90)) : (0x3b20 + \ (function * 0x90))) #define XSTORM_SPQ_PAGE_BASE_OFFSET(function) \ (IS_E1H_OFFSET ? (0x2000 + (function * 0x10)) : (0x3328 + \ @@ -189,8 +347,15 @@ (IS_E1H_OFFSET ? (0x2008 + (function * 0x10)) : (0x3330 + \ (function * 0x10))) #define XSTORM_STATS_FLAGS_OFFSET(function) \ - (IS_E1H_OFFSET ? (0x23d8 + (function * 0x8)) : (0x3b60 + \ + (IS_E1H_OFFSET ? (0x23d8 + (function * 0x8)) : (0x3a40 + \ (function * 0x8))) +#define XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_ENABLED_OFFSET(port) \ + (IS_E1H_OFFSET ? (0x4000 + (port * 0x8)) : (0x1960 + (port * 0x8))) +#define XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_MAX_COUNT_OFFSET(port) \ + (IS_E1H_OFFSET ? (0x4001 + (port * 0x8)) : (0x1961 + (port * 0x8))) +#define XSTORM_TCP_TX_SWS_TIMER_VAL_OFFSET(function) \ + (IS_E1H_OFFSET ? (0x4060 + ((function>>1) * 0x8) + ((function&1) \ + * 0x4)) : (0x1978 + (function * 0x4))) #define COMMON_ASM_INVALID_ASSERT_OPCODE 0x0 /** @@ -211,6 +376,9 @@ #define TCP_IPV4_HASH_TYPE 2 #define IPV6_HASH_TYPE 3 #define TCP_IPV6_HASH_TYPE 4 +#define VLAN_PRI_HASH_TYPE 5 +#define E1HOV_PRI_HASH_TYPE 6 +#define DSCP_HASH_TYPE 7 /* Ethernet Ring parameters */ @@ -218,30 +386,26 @@ #define FIRST_BD_IN_PKT 0 #define PARSE_BD_INDEX 1 #define NUM_OF_ETH_BDS_IN_PAGE ((PAGE_SIZE)/(STRUCT_SIZE(eth_tx_bd)/8)) - +#define U_ETH_NUM_OF_SGES_TO_FETCH 8 +#define U_ETH_MAX_SGES_FOR_PACKET 3 /* Rx ring params */ -#define U_ETH_LOCAL_BD_RING_SIZE 16 -#define U_ETH_LOCAL_SGE_RING_SIZE 12 +#define U_ETH_LOCAL_BD_RING_SIZE 8 +#define U_ETH_LOCAL_SGE_RING_SIZE 10 #define U_ETH_SGL_SIZE 8 -#define U_ETH_BDS_PER_PAGE_MASK \ - ((PAGE_SIZE/(STRUCT_SIZE(eth_rx_bd)/8))-1) -#define U_ETH_CQE_PER_PAGE_MASK \ - ((PAGE_SIZE/(STRUCT_SIZE(eth_rx_cqe)/8))-1) -#define U_ETH_SGES_PER_PAGE_MASK \ - ((PAGE_SIZE/(STRUCT_SIZE(eth_rx_sge)/8))-1) - #define U_ETH_SGES_PER_PAGE_INVERSE_MASK \ (0xFFFF - ((PAGE_SIZE/((STRUCT_SIZE(eth_rx_sge))/8))-1)) - -#define TU_ETH_CQES_PER_PAGE \ - (PAGE_SIZE/(STRUCT_SIZE(eth_rx_cqe_next_page)/8)) +#define TU_ETH_CQES_PER_PAGE (PAGE_SIZE/(STRUCT_SIZE(eth_rx_cqe)/8)) #define U_ETH_BDS_PER_PAGE (PAGE_SIZE/(STRUCT_SIZE(eth_rx_bd)/8)) #define U_ETH_SGES_PER_PAGE (PAGE_SIZE/(STRUCT_SIZE(eth_rx_sge)/8)) +#define U_ETH_BDS_PER_PAGE_MASK (U_ETH_BDS_PER_PAGE-1) +#define U_ETH_CQE_PER_PAGE_MASK (TU_ETH_CQES_PER_PAGE-1) +#define U_ETH_SGES_PER_PAGE_MASK (U_ETH_SGES_PER_PAGE-1) + #define U_ETH_UNDEFINED_Q 0xFF /* values of command IDs in the ramrod message */ @@ -266,8 +430,8 @@ #define T_ETH_CRC32_HASH_SEED 0x00000000 /* Maximal L2 clients supported */ -#define ETH_MAX_RX_CLIENTS_E1 19 -#define ETH_MAX_RX_CLIENTS_E1H 25 +#define ETH_MAX_RX_CLIENTS_E1 18 +#define ETH_MAX_RX_CLIENTS_E1H 26 /* Maximal aggregation queues supported */ #define ETH_MAX_AGGREGATION_QUEUES_E1 32 @@ -276,6 +440,9 @@ /* ETH RSS modes */ #define ETH_RSS_MODE_DISABLED 0 #define ETH_RSS_MODE_REGULAR 1 +#define ETH_RSS_MODE_VLAN_PRI 2 +#define ETH_RSS_MODE_E1HOV_PRI 3 +#define ETH_RSS_MODE_IP_DSCP 4 /** @@ -332,12 +499,14 @@ #define HC_INDEX_DEF_C_ETH_SLOW_PATH 3 #define HC_INDEX_DEF_C_ETH_RDMA_CQ_CONS 4 #define HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS 5 +#define HC_INDEX_DEF_C_ETH_FCOE_CQ_CONS 6 #define HC_INDEX_DEF_U_ETH_RDMA_RX_CQ_CONS 0 #define HC_INDEX_DEF_U_ETH_ISCSI_RX_CQ_CONS 1 #define HC_INDEX_DEF_U_ETH_RDMA_RX_BD_CONS 2 #define HC_INDEX_DEF_U_ETH_ISCSI_RX_BD_CONS 3 - +#define HC_INDEX_DEF_U_ETH_FCOE_RX_CQ_CONS 4 +#define HC_INDEX_DEF_U_ETH_FCOE_RX_BD_CONS 5 /* used by the driver to get the SB offset */ #define USTORM_ID 0 diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x_hsi.h index 7de83c4a557..da62cc5608d 100644 --- a/drivers/net/bnx2x_hsi.h +++ b/drivers/net/bnx2x_hsi.h @@ -1218,9 +1218,9 @@ struct host_func_stats { }; -#define BCM_5710_FW_MAJOR_VERSION 4 -#define BCM_5710_FW_MINOR_VERSION 8 -#define BCM_5710_FW_REVISION_VERSION 53 +#define BCM_5710_FW_MAJOR_VERSION 5 +#define BCM_5710_FW_MINOR_VERSION 0 +#define BCM_5710_FW_REVISION_VERSION 21 #define BCM_5710_FW_ENGINEERING_VERSION 0 #define BCM_5710_FW_COMPILE_FLAGS 1 @@ -1269,6 +1269,22 @@ struct doorbell { }; +/* + * doorbell message sent to the chip + */ +struct doorbell_set_prod { +#if defined(__BIG_ENDIAN) + u16 prod; + u8 zero_fill1; + struct doorbell_hdr header; +#elif defined(__LITTLE_ENDIAN) + struct doorbell_hdr header; + u8 zero_fill1; + u16 prod; +#endif +}; + + /* * IGU driver acknowledgement register */ @@ -1303,6 +1319,62 @@ struct igu_ack_register { }; +/* + * IGU driver acknowledgement register + */ +struct igu_backward_compatible { + u32 sb_id_and_flags; +#define IGU_BACKWARD_COMPATIBLE_SB_INDEX (0xFFFF<<0) +#define IGU_BACKWARD_COMPATIBLE_SB_INDEX_SHIFT 0 +#define IGU_BACKWARD_COMPATIBLE_SB_SELECT (0x1F<<16) +#define IGU_BACKWARD_COMPATIBLE_SB_SELECT_SHIFT 16 +#define IGU_BACKWARD_COMPATIBLE_SEGMENT_ACCESS (0x7<<21) +#define IGU_BACKWARD_COMPATIBLE_SEGMENT_ACCESS_SHIFT 21 +#define IGU_BACKWARD_COMPATIBLE_BUPDATE (0x1<<24) +#define IGU_BACKWARD_COMPATIBLE_BUPDATE_SHIFT 24 +#define IGU_BACKWARD_COMPATIBLE_ENABLE_INT (0x3<<25) +#define IGU_BACKWARD_COMPATIBLE_ENABLE_INT_SHIFT 25 +#define IGU_BACKWARD_COMPATIBLE_RESERVED_0 (0x1F<<27) +#define IGU_BACKWARD_COMPATIBLE_RESERVED_0_SHIFT 27 + u32 reserved_2; +}; + + +/* + * IGU driver acknowledgement register + */ +struct igu_regular { + u32 sb_id_and_flags; +#define IGU_REGULAR_SB_INDEX (0xFFFFF<<0) +#define IGU_REGULAR_SB_INDEX_SHIFT 0 +#define IGU_REGULAR_RESERVED0 (0x1<<20) +#define IGU_REGULAR_RESERVED0_SHIFT 20 +#define IGU_REGULAR_SEGMENT_ACCESS (0x7<<21) +#define IGU_REGULAR_SEGMENT_ACCESS_SHIFT 21 +#define IGU_REGULAR_BUPDATE (0x1<<24) +#define IGU_REGULAR_BUPDATE_SHIFT 24 +#define IGU_REGULAR_ENABLE_INT (0x3<<25) +#define IGU_REGULAR_ENABLE_INT_SHIFT 25 +#define IGU_REGULAR_RESERVED_1 (0x1<<27) +#define IGU_REGULAR_RESERVED_1_SHIFT 27 +#define IGU_REGULAR_CLEANUP_TYPE (0x3<<28) +#define IGU_REGULAR_CLEANUP_TYPE_SHIFT 28 +#define IGU_REGULAR_CLEANUP_SET (0x1<<30) +#define IGU_REGULAR_CLEANUP_SET_SHIFT 30 +#define IGU_REGULAR_BCLEANUP (0x1<<31) +#define IGU_REGULAR_BCLEANUP_SHIFT 31 + u32 reserved_2; +}; + +/* + * IGU driver acknowledgement register + */ +union igu_consprod_reg { + struct igu_regular regular; + struct igu_backward_compatible backward_compatible; +}; + + /* * Parser parsing flags field */ @@ -1434,12 +1506,10 @@ struct ustorm_eth_st_context_config { #define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_DYNAMIC_HC_SHIFT 1 #define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA (0x1<<2) #define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA_SHIFT 2 -#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_SGE_RING (0x1<<3) -#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_SGE_RING_SHIFT 3 -#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS (0x1<<4) -#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS_SHIFT 4 -#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0 (0x7<<5) -#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0_SHIFT 5 +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS (0x1<<3) +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS_SHIFT 3 +#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0 (0xF<<4) +#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0_SHIFT 4 u8 status_block_id; u8 clientId; u8 sb_index_numbers; @@ -1462,12 +1532,10 @@ struct ustorm_eth_st_context_config { #define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_DYNAMIC_HC_SHIFT 1 #define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA (0x1<<2) #define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA_SHIFT 2 -#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_SGE_RING (0x1<<3) -#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_SGE_RING_SHIFT 3 -#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS (0x1<<4) -#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS_SHIFT 4 -#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0 (0x7<<5) -#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0_SHIFT 5 +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS (0x1<<3) +#define USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS_SHIFT 3 +#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0 (0xF<<4) +#define __USTORM_ETH_ST_CONTEXT_CONFIG_RESERVED0_SHIFT 4 #endif #if defined(__BIG_ENDIAN) u16 bd_buff_size; @@ -1487,11 +1555,36 @@ struct ustorm_eth_st_context_config { u8 __local_bd_prod; u8 __local_sge_prod; #endif - u32 reserved; +#if defined(__BIG_ENDIAN) + u16 __sdm_bd_expected_counter; + u8 cstorm_agg_int; + u8 __expected_bds_on_ram; +#elif defined(__LITTLE_ENDIAN) + u8 __expected_bds_on_ram; + u8 cstorm_agg_int; + u16 __sdm_bd_expected_counter; +#endif +#if defined(__BIG_ENDIAN) + u16 __ring_data_ram_addr; + u16 __hc_cstorm_ram_addr; +#elif defined(__LITTLE_ENDIAN) + u16 __hc_cstorm_ram_addr; + u16 __ring_data_ram_addr; +#endif +#if defined(__BIG_ENDIAN) + u8 reserved1; + u8 max_sges_for_packet; + u16 __bd_ring_ram_addr; +#elif defined(__LITTLE_ENDIAN) + u16 __bd_ring_ram_addr; + u8 max_sges_for_packet; + u8 reserved1; +#endif u32 bd_page_base_lo; u32 bd_page_base_hi; u32 sge_page_base_lo; u32 sge_page_base_hi; + struct regpair reserved2; }; /* @@ -1514,8 +1607,8 @@ struct eth_rx_sge { * Local BDs and SGEs rings (in ETH) */ struct eth_local_rx_rings { - struct eth_rx_bd __local_bd_ring[16]; - struct eth_rx_sge __local_sge_ring[12]; + struct eth_rx_bd __local_bd_ring[8]; + struct eth_rx_sge __local_sge_ring[10]; }; /* @@ -1607,13 +1700,13 @@ struct xstorm_eth_extra_ag_context_section { */ struct xstorm_eth_ag_context { #if defined(__BIG_ENDIAN) - u16 __bd_prod; + u16 agg_val1; u8 __agg_vars1; u8 __state; #elif defined(__LITTLE_ENDIAN) u8 __state; u8 __agg_vars1; - u16 __bd_prod; + u16 agg_val1; #endif #if defined(__BIG_ENDIAN) u8 cdu_reserved; @@ -1626,7 +1719,7 @@ struct xstorm_eth_ag_context { u8 __agg_vars4; u8 cdu_reserved; #endif - u32 __more_packets_to_send; + u32 __bd_prod; #if defined(__BIG_ENDIAN) u16 __agg_vars5; u16 __agg_val4_th; @@ -1892,8 +1985,8 @@ struct eth_tx_bd_flags { #define ETH_TX_BD_FLAGS_VLAN_TAG_SHIFT 0 #define ETH_TX_BD_FLAGS_IP_CSUM (0x1<<1) #define ETH_TX_BD_FLAGS_IP_CSUM_SHIFT 1 -#define ETH_TX_BD_FLAGS_TCP_CSUM (0x1<<2) -#define ETH_TX_BD_FLAGS_TCP_CSUM_SHIFT 2 +#define ETH_TX_BD_FLAGS_L4_CSUM (0x1<<2) +#define ETH_TX_BD_FLAGS_L4_CSUM_SHIFT 2 #define ETH_TX_BD_FLAGS_END_BD (0x1<<3) #define ETH_TX_BD_FLAGS_END_BD_SHIFT 3 #define ETH_TX_BD_FLAGS_START_BD (0x1<<4) @@ -1909,7 +2002,7 @@ struct eth_tx_bd_flags { /* * The eth Tx Buffer Descriptor */ -struct eth_tx_bd { +struct eth_tx_start_bd { __le32 addr_lo; __le32 addr_hi; __le16 nbd; @@ -1917,10 +2010,21 @@ struct eth_tx_bd { __le16 vlan; struct eth_tx_bd_flags bd_flags; u8 general_data; -#define ETH_TX_BD_HDR_NBDS (0x3F<<0) -#define ETH_TX_BD_HDR_NBDS_SHIFT 0 -#define ETH_TX_BD_ETH_ADDR_TYPE (0x3<<6) -#define ETH_TX_BD_ETH_ADDR_TYPE_SHIFT 6 +#define ETH_TX_START_BD_HDR_NBDS (0x3F<<0) +#define ETH_TX_START_BD_HDR_NBDS_SHIFT 0 +#define ETH_TX_START_BD_ETH_ADDR_TYPE (0x3<<6) +#define ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT 6 +}; + +/* + * Tx regular BD structure + */ +struct eth_tx_bd { + u32 addr_lo; + u32 addr_hi; + u16 total_pkt_bytes; + u16 nbytes; + u8 reserved[4]; }; /* @@ -1930,8 +2034,8 @@ struct eth_tx_parse_bd { u8 global_data; #define ETH_TX_PARSE_BD_IP_HDR_START_OFFSET (0xF<<0) #define ETH_TX_PARSE_BD_IP_HDR_START_OFFSET_SHIFT 0 -#define ETH_TX_PARSE_BD_CS_ANY_FLG (0x1<<4) -#define ETH_TX_PARSE_BD_CS_ANY_FLG_SHIFT 4 +#define ETH_TX_PARSE_BD_UDP_CS_FLG (0x1<<4) +#define ETH_TX_PARSE_BD_UDP_CS_FLG_SHIFT 4 #define ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN (0x1<<5) #define ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN_SHIFT 5 #define ETH_TX_PARSE_BD_LLC_SNAP_EN (0x1<<6) @@ -1956,10 +2060,10 @@ struct eth_tx_parse_bd { #define ETH_TX_PARSE_BD_CWR_FLG (0x1<<7) #define ETH_TX_PARSE_BD_CWR_FLG_SHIFT 7 u8 ip_hlen; - s8 cs_offset; + s8 reserved; __le16 total_hlen; - __le16 lso_mss; __le16 tcp_pseudo_csum; + __le16 lso_mss; __le16 ip_id; __le32 tcp_send_seq; }; @@ -1968,15 +2072,16 @@ struct eth_tx_parse_bd { * The last BD in the BD memory will hold a pointer to the next BD memory */ struct eth_tx_next_bd { - u32 addr_lo; - u32 addr_hi; + __le32 addr_lo; + __le32 addr_hi; u8 reserved[8]; }; /* - * union for 3 Bd types + * union for 4 Bd types */ union eth_tx_bd_types { + struct eth_tx_start_bd start_bd; struct eth_tx_bd reg_bd; struct eth_tx_parse_bd parse_bd; struct eth_tx_next_bd next_bd; @@ -2005,11 +2110,35 @@ struct xstorm_eth_st_context { #define XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE_SHIFT 7 u16 tx_bd_cons; #endif - u32 db_data_addr_lo; - u32 db_data_addr_hi; - u32 __pkt_cons; - u32 __gso_next; - u32 is_eth_conn_1b; + u32 __reserved1; + u32 __reserved2; +#if defined(__BIG_ENDIAN) + u8 __ram_cache_index; + u8 __double_buffer_client; + u16 __pkt_cons; +#elif defined(__LITTLE_ENDIAN) + u16 __pkt_cons; + u8 __double_buffer_client; + u8 __ram_cache_index; +#endif +#if defined(__BIG_ENDIAN) + u16 __statistics_address; + u16 __gso_next; +#elif defined(__LITTLE_ENDIAN) + u16 __gso_next; + u16 __statistics_address; +#endif +#if defined(__BIG_ENDIAN) + u8 __local_tx_bd_cons; + u8 safc_group_num; + u8 safc_group_en; + u8 __is_eth_conn; +#elif defined(__LITTLE_ENDIAN) + u8 __is_eth_conn; + u8 safc_group_en; + u8 safc_group_num; + u8 __local_tx_bd_cons; +#endif union eth_tx_bd_types __bds[13]; }; @@ -2074,9 +2203,9 @@ struct eth_tx_doorbell { /* - * ustorm status block + * cstorm default status block, generated by ustorm */ -struct ustorm_def_status_block { +struct cstorm_def_status_block_u { __le16 index_values[HC_USTORM_DEF_SB_NUM_INDICES]; __le16 status_block_index; u8 func; @@ -2085,9 +2214,9 @@ struct ustorm_def_status_block { }; /* - * cstorm status block + * cstorm default status block, generated by cstorm */ -struct cstorm_def_status_block { +struct cstorm_def_status_block_c { __le16 index_values[HC_CSTORM_DEF_SB_NUM_INDICES]; __le16 status_block_index; u8 func; @@ -2122,17 +2251,17 @@ struct tstorm_def_status_block { */ struct host_def_status_block { struct atten_def_status_block atten_status_block; - struct ustorm_def_status_block u_def_status_block; - struct cstorm_def_status_block c_def_status_block; + struct cstorm_def_status_block_u u_def_status_block; + struct cstorm_def_status_block_c c_def_status_block; struct xstorm_def_status_block x_def_status_block; struct tstorm_def_status_block t_def_status_block; }; /* - * ustorm status block + * cstorm status block, generated by ustorm */ -struct ustorm_status_block { +struct cstorm_status_block_u { __le16 index_values[HC_USTORM_SB_NUM_INDICES]; __le16 status_block_index; u8 func; @@ -2141,9 +2270,9 @@ struct ustorm_status_block { }; /* - * cstorm status block + * cstorm status block, generated by cstorm */ -struct cstorm_status_block { +struct cstorm_status_block_c { __le16 index_values[HC_CSTORM_SB_NUM_INDICES]; __le16 status_block_index; u8 func; @@ -2155,8 +2284,8 @@ struct cstorm_status_block { * host status block */ struct host_status_block { - struct ustorm_status_block u_status_block; - struct cstorm_status_block c_status_block; + struct cstorm_status_block_u u_status_block; + struct cstorm_status_block_c c_status_block; }; @@ -2171,15 +2300,6 @@ struct eth_client_setup_ramrod_data { }; -/* - * L2 dynamic host coalescing init parameters - */ -struct eth_dynamic_hc_config { - u32 threshold[3]; - u8 hc_timeout[4]; -}; - - /* * regular eth FP CQE parameters struct */ @@ -2344,12 +2464,10 @@ struct eth_spe { /* - * doorbell data in host memory + * array of 13 bds as appears in the eth xstorm context */ -struct eth_tx_db_data { - __le32 packets_prod; - __le16 bds_prod; - __le16 reserved; +struct eth_tx_bds_array { + union eth_tx_bd_types bds[13]; }; @@ -2377,8 +2495,10 @@ struct tstorm_eth_function_common_config { #define TSTORM_ETH_FUNCTION_COMMON_CONFIG_VLAN_IN_CAM_SHIFT 8 #define TSTORM_ETH_FUNCTION_COMMON_CONFIG_E1HOV_IN_CAM (0x1<<9) #define TSTORM_ETH_FUNCTION_COMMON_CONFIG_E1HOV_IN_CAM_SHIFT 9 -#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0 (0x3F<<10) -#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0_SHIFT 10 +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA (0x1<<10) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA_SHIFT 10 +#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0 (0x1F<<11) +#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0_SHIFT 11 #elif defined(__LITTLE_ENDIAN) u16 config_flags; #define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY (0x1<<0) @@ -2397,20 +2517,49 @@ struct tstorm_eth_function_common_config { #define TSTORM_ETH_FUNCTION_COMMON_CONFIG_VLAN_IN_CAM_SHIFT 8 #define TSTORM_ETH_FUNCTION_COMMON_CONFIG_E1HOV_IN_CAM (0x1<<9) #define TSTORM_ETH_FUNCTION_COMMON_CONFIG_E1HOV_IN_CAM_SHIFT 9 -#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0 (0x3F<<10) -#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0_SHIFT 10 +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA (0x1<<10) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA_SHIFT 10 +#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0 (0x1F<<11) +#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0_SHIFT 11 u8 rss_result_mask; u8 leading_client_id; #endif u16 vlan_id[2]; }; +/* + * RSS idirection table update configuration + */ +struct rss_update_config { +#if defined(__BIG_ENDIAN) + u16 toe_rss_bitmap; + u16 flags; +#define RSS_UPDATE_CONFIG_ETH_UPDATE_ENABLE (0x1<<0) +#define RSS_UPDATE_CONFIG_ETH_UPDATE_ENABLE_SHIFT 0 +#define RSS_UPDATE_CONFIG_TOE_UPDATE_ENABLE (0x1<<1) +#define RSS_UPDATE_CONFIG_TOE_UPDATE_ENABLE_SHIFT 1 +#define __RSS_UPDATE_CONFIG_RESERVED0 (0x3FFF<<2) +#define __RSS_UPDATE_CONFIG_RESERVED0_SHIFT 2 +#elif defined(__LITTLE_ENDIAN) + u16 flags; +#define RSS_UPDATE_CONFIG_ETH_UPDATE_ENABLE (0x1<<0) +#define RSS_UPDATE_CONFIG_ETH_UPDATE_ENABLE_SHIFT 0 +#define RSS_UPDATE_CONFIG_TOE_UPDATE_ENABLE (0x1<<1) +#define RSS_UPDATE_CONFIG_TOE_UPDATE_ENABLE_SHIFT 1 +#define __RSS_UPDATE_CONFIG_RESERVED0 (0x3FFF<<2) +#define __RSS_UPDATE_CONFIG_RESERVED0_SHIFT 2 + u16 toe_rss_bitmap; +#endif + u32 reserved1; +}; + /* * parameters for eth update ramrod */ struct eth_update_ramrod_data { struct tstorm_eth_function_common_config func_config; u8 indirectionTable[128]; + struct rss_update_config rss_config; }; @@ -2455,8 +2604,9 @@ struct tstorm_cam_target_table_entry { #define TSTORM_CAM_TARGET_TABLE_ENTRY_RDMA_MAC_SHIFT 3 #define TSTORM_CAM_TARGET_TABLE_ENTRY_RESERVED0 (0xF<<4) #define TSTORM_CAM_TARGET_TABLE_ENTRY_RESERVED0_SHIFT 4 - u8 client_id; + u8 reserved1; u16 vlan_id; + u32 clients_bit_vector; }; /* @@ -2485,7 +2635,7 @@ struct mac_configuration_entry_e1h { __le16 msb_mac_addr; __le16 vlan_id; __le16 e1hov_id; - u8 client_id; + u8 reserved0; u8 flags; #define MAC_CONFIGURATION_ENTRY_E1H_PORT (0x1<<0) #define MAC_CONFIGURATION_ENTRY_E1H_PORT_SHIFT 0 @@ -2493,8 +2643,9 @@ struct mac_configuration_entry_e1h { #define MAC_CONFIGURATION_ENTRY_E1H_ACTION_TYPE_SHIFT 1 #define MAC_CONFIGURATION_ENTRY_E1H_RDMA_MAC (0x1<<2) #define MAC_CONFIGURATION_ENTRY_E1H_RDMA_MAC_SHIFT 2 -#define MAC_CONFIGURATION_ENTRY_E1H_RESERVED0 (0x1F<<3) -#define MAC_CONFIGURATION_ENTRY_E1H_RESERVED0_SHIFT 3 +#define MAC_CONFIGURATION_ENTRY_E1H_RESERVED1 (0x1F<<3) +#define MAC_CONFIGURATION_ENTRY_E1H_RESERVED1_SHIFT 3 + u32 clients_bit_vector; }; /* @@ -2519,13 +2670,13 @@ struct tstorm_eth_approximate_match_multicast_filtering { */ struct tstorm_eth_client_config { #if defined(__BIG_ENDIAN) - u8 max_sges_for_packet; + u8 reserved0; u8 statistics_counter_id; u16 mtu; #elif defined(__LITTLE_ENDIAN) u16 mtu; u8 statistics_counter_id; - u8 max_sges_for_packet; + u8 reserved0; #endif #if defined(__BIG_ENDIAN) u16 drop_flags; @@ -2537,8 +2688,8 @@ struct tstorm_eth_client_config { #define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0_SHIFT 2 #define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR (0x1<<3) #define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR_SHIFT 3 -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1 (0xFFF<<4) -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1_SHIFT 4 +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED2 (0xFFF<<4) +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED2_SHIFT 4 u16 config_flags; #define TSTORM_ETH_CLIENT_CONFIG_VLAN_REM_ENABLE (0x1<<0) #define TSTORM_ETH_CLIENT_CONFIG_VLAN_REM_ENABLE_SHIFT 0 @@ -2546,10 +2697,8 @@ struct tstorm_eth_client_config { #define TSTORM_ETH_CLIENT_CONFIG_E1HOV_REM_ENABLE_SHIFT 1 #define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE (0x1<<2) #define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE_SHIFT 2 -#define TSTORM_ETH_CLIENT_CONFIG_ENABLE_SGE_RING (0x1<<3) -#define TSTORM_ETH_CLIENT_CONFIG_ENABLE_SGE_RING_SHIFT 3 -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0 (0xFFF<<4) -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0_SHIFT 4 +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1 (0x1FFF<<3) +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1_SHIFT 3 #elif defined(__LITTLE_ENDIAN) u16 config_flags; #define TSTORM_ETH_CLIENT_CONFIG_VLAN_REM_ENABLE (0x1<<0) @@ -2558,10 +2707,8 @@ struct tstorm_eth_client_config { #define TSTORM_ETH_CLIENT_CONFIG_E1HOV_REM_ENABLE_SHIFT 1 #define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE (0x1<<2) #define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE_SHIFT 2 -#define TSTORM_ETH_CLIENT_CONFIG_ENABLE_SGE_RING (0x1<<3) -#define TSTORM_ETH_CLIENT_CONFIG_ENABLE_SGE_RING_SHIFT 3 -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0 (0xFFF<<4) -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0_SHIFT 4 +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1 (0x1FFF<<3) +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1_SHIFT 3 u16 drop_flags; #define TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR (0x1<<0) #define TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR_SHIFT 0 @@ -2571,8 +2718,8 @@ struct tstorm_eth_client_config { #define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0_SHIFT 2 #define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR (0x1<<3) #define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR_SHIFT 3 -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1 (0xFFF<<4) -#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1_SHIFT 4 +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED2 (0xFFF<<4) +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED2_SHIFT 4 #endif }; @@ -2695,7 +2842,6 @@ struct rate_shaping_vars_per_port { u32 rs_threshold; }; - /* * per-port fairness variables */ @@ -2705,7 +2851,6 @@ struct fairness_vars_per_port { u32 fairness_timeout; }; - /* * per-port SAFC variables */ @@ -2722,7 +2867,6 @@ struct safc_struct_per_port { u16 cos_to_pause_mask[NUM_OF_SAFC_BITS]; }; - /* * Per-port congestion management variables */ @@ -2734,12 +2878,24 @@ struct cmng_struct_per_port { }; +/* + * Dynamic host coalescing init parameters + */ +struct dynamic_hc_config { + u32 threshold[3]; + u8 shift_per_protocol[HC_USTORM_SB_NUM_INDICES]; + u8 hc_timeout0[HC_USTORM_SB_NUM_INDICES]; + u8 hc_timeout1[HC_USTORM_SB_NUM_INDICES]; + u8 hc_timeout2[HC_USTORM_SB_NUM_INDICES]; + u8 hc_timeout3[HC_USTORM_SB_NUM_INDICES]; +}; + + /* * Protocol-common statistics collected by the Xstorm (per client) */ struct xstorm_per_client_stats { - struct regpair total_sent_bytes; - __le32 total_sent_pkts; + __le32 reserved0; __le32 unicast_pkts_sent; struct regpair unicast_bytes_sent; struct regpair multicast_bytes_sent; @@ -2747,11 +2903,10 @@ struct xstorm_per_client_stats { __le32 broadcast_pkts_sent; struct regpair broadcast_bytes_sent; __le16 stats_counter; - __le16 reserved0; - __le32 reserved1; + __le16 reserved1; + __le32 reserved2; }; - /* * Common statistics collected by the Xstorm (per port) */ @@ -2759,7 +2914,6 @@ struct xstorm_common_stats { struct xstorm_per_client_stats client_statistics[MAX_X_STAT_COUNTER_ID]; }; - /* * Protocol-common statistics collected by the Tstorm (per port) */ @@ -2770,19 +2924,16 @@ struct tstorm_per_port_stats { __le32 mac_discard; }; - /* * Protocol-common statistics collected by the Tstorm (per client) */ struct tstorm_per_client_stats { - struct regpair total_rcv_bytes; struct regpair rcv_unicast_bytes; struct regpair rcv_broadcast_bytes; struct regpair rcv_multicast_bytes; struct regpair rcv_error_bytes; __le32 checksum_discard; __le32 packets_too_big_discard; - __le32 total_rcv_pkts; __le32 rcv_unicast_pkts; __le32 rcv_broadcast_pkts; __le32 rcv_multicast_pkts; @@ -2790,7 +2941,6 @@ struct tstorm_per_client_stats { __le32 ttl0_discard; __le16 stats_counter; __le16 reserved0; - __le32 reserved1; }; /* @@ -2892,6 +3042,15 @@ struct pram_fw_version { }; +/* + * The send queue element + */ +struct protocol_common_spe { + struct spe_hdr hdr; + struct regpair phy_address; +}; + + /* * a single rate shaping counter. can be used as protocol or vnic counter */ diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 665ed36a0d4..762f37a7d03 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -10,7 +10,7 @@ * Written by: Eliezer Tamir * Based on code from Michael Chan's bnx2 driver * UDP CSUM errata workaround by Arik Gendelman - * Slowpath rework by Vladislav Zolotarov + * Slowpath and fastpath rework by Vladislav Zolotarov * Statistics and Link management by Yitchak Gertner * */ @@ -80,7 +80,18 @@ MODULE_VERSION(DRV_MODULE_VERSION); static int multi_mode = 1; module_param(multi_mode, int, 0); -MODULE_PARM_DESC(multi_mode, " Use per-CPU queues"); +MODULE_PARM_DESC(multi_mode, " Multi queue mode " + "(0 Disable; 1 Enable (default))"); + +static int num_rx_queues; +module_param(num_rx_queues, int, 0); +MODULE_PARM_DESC(num_rx_queues, " Number of Rx queues for multi_mode=1" + " (default is half number of CPUs)"); + +static int num_tx_queues; +module_param(num_tx_queues, int, 0); +MODULE_PARM_DESC(num_tx_queues, " Number of Tx queues for multi_mode=1" + " (default is half number of CPUs)"); static int disable_tpa; module_param(disable_tpa, int, 0); @@ -542,16 +553,15 @@ static void bnx2x_panic_dump(struct bnx2x *bp) /* Tx */ for_each_tx_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; - struct eth_tx_db_data *hw_prods = fp->hw_tx_prods; BNX2X_ERR("fp%d: tx_pkt_prod(%x) tx_pkt_cons(%x)" " tx_bd_prod(%x) tx_bd_cons(%x) *tx_cons_sb(%x)\n", i, fp->tx_pkt_prod, fp->tx_pkt_cons, fp->tx_bd_prod, fp->tx_bd_cons, le16_to_cpu(*fp->tx_cons_sb)); BNX2X_ERR(" fp_c_idx(%x) *sb_c_idx(%x)" - " bd data(%x,%x)\n", le16_to_cpu(fp->fp_c_idx), + " tx_db_prod(%x)\n", le16_to_cpu(fp->fp_c_idx), fp->status_blk->c_status_block.status_block_index, - hw_prods->packets_prod, hw_prods->bds_prod); + fp->tx_db.data.prod); } /* Rings */ @@ -790,16 +800,6 @@ static u16 bnx2x_ack_int(struct bnx2x *bp) * fast path service functions */ -static inline int bnx2x_has_tx_work(struct bnx2x_fastpath *fp) -{ - u16 tx_cons_sb; - - /* Tell compiler that status block fields can change */ - barrier(); - tx_cons_sb = le16_to_cpu(*fp->tx_cons_sb); - return (fp->tx_pkt_cons != tx_cons_sb); -} - static inline int bnx2x_has_tx_work_unload(struct bnx2x_fastpath *fp) { /* Tell compiler that consumer and producer can change */ @@ -814,7 +814,8 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp, u16 idx) { struct sw_tx_bd *tx_buf = &fp->tx_buf_ring[idx]; - struct eth_tx_bd *tx_bd; + struct eth_tx_start_bd *tx_start_bd; + struct eth_tx_bd *tx_data_bd; struct sk_buff *skb = tx_buf->skb; u16 bd_idx = TX_BD(tx_buf->first_bd), new_cons; int nbd; @@ -824,51 +825,46 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp, /* unmap first bd */ DP(BNX2X_MSG_OFF, "free bd_idx %d\n", bd_idx); - tx_bd = &fp->tx_desc_ring[bd_idx]; - pci_unmap_single(bp->pdev, BD_UNMAP_ADDR(tx_bd), - BD_UNMAP_LEN(tx_bd), PCI_DMA_TODEVICE); + tx_start_bd = &fp->tx_desc_ring[bd_idx].start_bd; + pci_unmap_single(bp->pdev, BD_UNMAP_ADDR(tx_start_bd), + BD_UNMAP_LEN(tx_start_bd), PCI_DMA_TODEVICE); - nbd = le16_to_cpu(tx_bd->nbd) - 1; - new_cons = nbd + tx_buf->first_bd; + nbd = le16_to_cpu(tx_start_bd->nbd) - 1; #ifdef BNX2X_STOP_ON_ERROR - if (nbd > (MAX_SKB_FRAGS + 2)) { + if ((nbd - 1) > (MAX_SKB_FRAGS + 2)) { BNX2X_ERR("BAD nbd!\n"); bnx2x_panic(); } #endif + new_cons = nbd + tx_buf->first_bd; - /* Skip a parse bd and the TSO split header bd - since they have no mapping */ - if (nbd) - bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); + /* Get the next bd */ + bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); - if (tx_bd->bd_flags.as_bitfield & (ETH_TX_BD_FLAGS_IP_CSUM | - ETH_TX_BD_FLAGS_TCP_CSUM | - ETH_TX_BD_FLAGS_SW_LSO)) { - if (--nbd) - bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); - tx_bd = &fp->tx_desc_ring[bd_idx]; - /* is this a TSO split header bd? */ - if (tx_bd->bd_flags.as_bitfield & ETH_TX_BD_FLAGS_SW_LSO) { - if (--nbd) - bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); - } + /* Skip a parse bd... */ + --nbd; + bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); + + /* ...and the TSO split header bd since they have no mapping */ + if (tx_buf->flags & BNX2X_TSO_SPLIT_BD) { + --nbd; + bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); } /* now free frags */ while (nbd > 0) { DP(BNX2X_MSG_OFF, "free frag bd_idx %d\n", bd_idx); - tx_bd = &fp->tx_desc_ring[bd_idx]; - pci_unmap_page(bp->pdev, BD_UNMAP_ADDR(tx_bd), - BD_UNMAP_LEN(tx_bd), PCI_DMA_TODEVICE); + tx_data_bd = &fp->tx_desc_ring[bd_idx].reg_bd; + pci_unmap_page(bp->pdev, BD_UNMAP_ADDR(tx_data_bd), + BD_UNMAP_LEN(tx_data_bd), PCI_DMA_TODEVICE); if (--nbd) bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); } /* release skb */ WARN_ON(!skb); - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); tx_buf->first_bd = 0; tx_buf->skb = NULL; @@ -910,7 +906,7 @@ static void bnx2x_tx_int(struct bnx2x_fastpath *fp) return; #endif - txq = netdev_get_tx_queue(bp->dev, fp->index); + txq = netdev_get_tx_queue(bp->dev, fp->index - bp->num_rx_queues); hw_cons = le16_to_cpu(*fp->tx_cons_sb); sw_cons = fp->tx_pkt_cons; @@ -940,8 +936,6 @@ static void bnx2x_tx_int(struct bnx2x_fastpath *fp) /* TBD need a thresh? */ if (unlikely(netif_tx_queue_stopped(txq))) { - __netif_tx_lock(txq, smp_processor_id()); - /* Need to make the tx_bd_cons update visible to start_xmit() * before checking for netif_tx_queue_stopped(). Without the * memory barrier, there is a small possibility that @@ -954,8 +948,6 @@ static void bnx2x_tx_int(struct bnx2x_fastpath *fp) (bp->state == BNX2X_STATE_OPEN) && (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3)) netif_tx_wake_queue(txq); - - __netif_tx_unlock(txq); } } @@ -1023,6 +1015,7 @@ static void bnx2x_sp_event(struct bnx2x_fastpath *fp, break; case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_CLOSING_WAIT4_HALT): + case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_DISABLED): DP(NETIF_MSG_IFDOWN, "got (un)set mac ramrod\n"); break; @@ -1688,7 +1681,6 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie) { struct bnx2x_fastpath *fp = fp_cookie; struct bnx2x *bp = fp->bp; - int index = fp->index; /* Return here if interrupt is disabled */ if (unlikely(atomic_read(&bp->intr_sem) != 0)) { @@ -1697,20 +1689,34 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie) } DP(BNX2X_MSG_FP, "got an MSI-X interrupt on IDX:SB [%d:%d]\n", - index, fp->sb_id); + fp->index, fp->sb_id); bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID, 0, IGU_INT_DISABLE, 0); #ifdef BNX2X_STOP_ON_ERROR if (unlikely(bp->panic)) return IRQ_HANDLED; #endif + /* Handle Rx or Tx according to MSI-X vector */ + if (fp->is_rx_queue) { + prefetch(fp->rx_cons_sb); + prefetch(&fp->status_blk->u_status_block.status_block_index); - prefetch(fp->rx_cons_sb); - prefetch(fp->tx_cons_sb); - prefetch(&fp->status_blk->c_status_block.status_block_index); - prefetch(&fp->status_blk->u_status_block.status_block_index); + napi_schedule(&bnx2x_fp(bp, fp->index, napi)); - napi_schedule(&bnx2x_fp(bp, index, napi)); + } else { + prefetch(fp->tx_cons_sb); + prefetch(&fp->status_blk->c_status_block.status_block_index); + + bnx2x_update_fpsb_idx(fp); + rmb(); + bnx2x_tx_int(fp); + + /* Re-enable interrupts */ + bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID, + le16_to_cpu(fp->fp_u_idx), IGU_INT_NOP, 1); + bnx2x_ack_sb(bp, fp->sb_id, CSTORM_ID, + le16_to_cpu(fp->fp_c_idx), IGU_INT_ENABLE, 1); + } return IRQ_HANDLED; } @@ -1720,6 +1726,7 @@ static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance) struct bnx2x *bp = netdev_priv(dev_instance); u16 status = bnx2x_ack_int(bp); u16 mask; + int i; /* Return here if interrupt is shared and it's not for us */ if (unlikely(status == 0)) { @@ -1739,18 +1746,38 @@ static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance) return IRQ_HANDLED; #endif - mask = 0x2 << bp->fp[0].sb_id; - if (status & mask) { - struct bnx2x_fastpath *fp = &bp->fp[0]; + for (i = 0; i < BNX2X_NUM_QUEUES(bp); i++) { + struct bnx2x_fastpath *fp = &bp->fp[i]; - prefetch(fp->rx_cons_sb); - prefetch(fp->tx_cons_sb); - prefetch(&fp->status_blk->c_status_block.status_block_index); - prefetch(&fp->status_blk->u_status_block.status_block_index); + mask = 0x2 << fp->sb_id; + if (status & mask) { + /* Handle Rx or Tx according to SB id */ + if (fp->is_rx_queue) { + prefetch(fp->rx_cons_sb); + prefetch(&fp->status_blk->u_status_block. + status_block_index); - napi_schedule(&bnx2x_fp(bp, 0, napi)); + napi_schedule(&bnx2x_fp(bp, fp->index, napi)); - status &= ~mask; + } else { + prefetch(fp->tx_cons_sb); + prefetch(&fp->status_blk->c_status_block. + status_block_index); + + bnx2x_update_fpsb_idx(fp); + rmb(); + bnx2x_tx_int(fp); + + /* Re-enable interrupts */ + bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID, + le16_to_cpu(fp->fp_u_idx), + IGU_INT_NOP, 1); + bnx2x_ack_sb(bp, fp->sb_id, CSTORM_ID, + le16_to_cpu(fp->fp_c_idx), + IGU_INT_ENABLE, 1); + } + status &= ~mask; + } } @@ -2298,7 +2325,7 @@ static void bnx2x_link_attn(struct bnx2x *bp) pause_enabled = 1; REG_WR(bp, BAR_USTRORM_INTMEM + - USTORM_PAUSE_ENABLED_OFFSET(port), + USTORM_ETH_PAUSE_ENABLED_OFFSET(port), pause_enabled); } @@ -3756,7 +3783,7 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp) estats->no_buff_discard_hi = 0; estats->no_buff_discard_lo = 0; - for_each_queue(bp, i) { + for_each_rx_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; int cl_id = fp->cl_id; struct tstorm_per_client_stats *tclient = @@ -3795,11 +3822,24 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp) } qstats->total_bytes_received_hi = - qstats->valid_bytes_received_hi = - le32_to_cpu(tclient->total_rcv_bytes.hi); + le32_to_cpu(tclient->rcv_broadcast_bytes.hi); qstats->total_bytes_received_lo = + le32_to_cpu(tclient->rcv_broadcast_bytes.lo); + + ADD_64(qstats->total_bytes_received_hi, + le32_to_cpu(tclient->rcv_multicast_bytes.hi), + qstats->total_bytes_received_lo, + le32_to_cpu(tclient->rcv_multicast_bytes.lo)); + + ADD_64(qstats->total_bytes_received_hi, + le32_to_cpu(tclient->rcv_unicast_bytes.hi), + qstats->total_bytes_received_lo, + le32_to_cpu(tclient->rcv_unicast_bytes.lo)); + + qstats->valid_bytes_received_hi = + qstats->total_bytes_received_hi; qstats->valid_bytes_received_lo = - le32_to_cpu(tclient->total_rcv_bytes.lo); + qstats->total_bytes_received_lo; qstats->error_bytes_received_hi = le32_to_cpu(tclient->rcv_error_bytes.hi); @@ -3832,9 +3872,19 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp) UPDATE_EXTEND_USTAT(bcast_no_buff_pkts, no_buff_discard); qstats->total_bytes_transmitted_hi = - le32_to_cpu(xclient->total_sent_bytes.hi); + le32_to_cpu(xclient->unicast_bytes_sent.hi); qstats->total_bytes_transmitted_lo = - le32_to_cpu(xclient->total_sent_bytes.lo); + le32_to_cpu(xclient->unicast_bytes_sent.lo); + + ADD_64(qstats->total_bytes_transmitted_hi, + le32_to_cpu(xclient->multicast_bytes_sent.hi), + qstats->total_bytes_transmitted_lo, + le32_to_cpu(xclient->multicast_bytes_sent.lo)); + + ADD_64(qstats->total_bytes_transmitted_hi, + le32_to_cpu(xclient->broadcast_bytes_sent.hi), + qstats->total_bytes_transmitted_lo, + le32_to_cpu(xclient->broadcast_bytes_sent.lo)); UPDATE_EXTEND_XSTAT(unicast_pkts_sent, total_unicast_packets_transmitted); @@ -3950,7 +4000,7 @@ static void bnx2x_net_stats_update(struct bnx2x *bp) nstats->tx_bytes = bnx2x_hilo(&estats->total_bytes_transmitted_hi); nstats->rx_dropped = estats->mac_discard; - for_each_queue(bp, i) + for_each_rx_queue(bp, i) nstats->rx_dropped += le32_to_cpu(bp->fp[i].old_tclient.checksum_discard); @@ -4004,7 +4054,7 @@ static void bnx2x_drv_stats_update(struct bnx2x *bp) estats->rx_err_discard_pkt = 0; estats->rx_skb_alloc_failed = 0; estats->hw_csum_err = 0; - for_each_queue(bp, i) { + for_each_rx_queue(bp, i) { struct bnx2x_eth_q_stats *qstats = &bp->fp[i].eth_q_stats; estats->driver_xoff += qstats->driver_xoff; @@ -4034,6 +4084,8 @@ static void bnx2x_stats_update(struct bnx2x *bp) bnx2x_drv_stats_update(bp); if (bp->msglevel & NETIF_MSG_TIMER) { + struct bnx2x_fastpath *fp0_rx = bp->fp; + struct bnx2x_fastpath *fp0_tx = &(bp->fp[bp->num_rx_queues]); struct tstorm_per_client_stats *old_tclient = &bp->fp->old_tclient; struct bnx2x_eth_q_stats *qstats = &bp->fp->eth_q_stats; @@ -4044,13 +4096,13 @@ static void bnx2x_stats_update(struct bnx2x *bp) printk(KERN_DEBUG "%s:\n", bp->dev->name); printk(KERN_DEBUG " tx avail (%4x) tx hc idx (%x)" " tx pkt (%lx)\n", - bnx2x_tx_avail(bp->fp), - le16_to_cpu(*bp->fp->tx_cons_sb), nstats->tx_packets); + bnx2x_tx_avail(fp0_tx), + le16_to_cpu(*fp0_tx->tx_cons_sb), nstats->tx_packets); printk(KERN_DEBUG " rx usage (%4x) rx hc idx (%x)" " rx pkt (%lx)\n", - (u16)(le16_to_cpu(*bp->fp->rx_cons_sb) - - bp->fp->rx_comp_cons), - le16_to_cpu(*bp->fp->rx_cons_sb), nstats->rx_packets); + (u16)(le16_to_cpu(*fp0_rx->rx_cons_sb) - + fp0_rx->rx_comp_cons), + le16_to_cpu(*fp0_rx->rx_cons_sb), nstats->rx_packets); printk(KERN_DEBUG " %s (Xoff events %u) brb drops %u " "brb truncate %u\n", (netif_queue_stopped(bp->dev) ? "Xoff" : "Xon"), @@ -4263,12 +4315,13 @@ static void bnx2x_zero_sb(struct bnx2x *bp, int sb_id) { int port = BP_PORT(bp); - bnx2x_init_fill(bp, USTORM_INTMEM_ADDR + - USTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), 0, - sizeof(struct ustorm_status_block)/4); - bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR + - CSTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), 0, - sizeof(struct cstorm_status_block)/4); + /* "CSTORM" */ + bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY + + CSTORM_SB_HOST_STATUS_BLOCK_U_OFFSET(port, sb_id), 0, + CSTORM_SB_STATUS_BLOCK_U_SIZE / 4); + bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY + + CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, sb_id), 0, + CSTORM_SB_STATUS_BLOCK_C_SIZE / 4); } static void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb, @@ -4284,17 +4337,17 @@ static void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb, u_status_block); sb->u_status_block.status_block_id = sb_id; - REG_WR(bp, BAR_USTRORM_INTMEM + - USTORM_SB_HOST_SB_ADDR_OFFSET(port, sb_id), U64_LO(section)); - REG_WR(bp, BAR_USTRORM_INTMEM + - ((USTORM_SB_HOST_SB_ADDR_OFFSET(port, sb_id)) + 4), + REG_WR(bp, BAR_CSTRORM_INTMEM + + CSTORM_SB_HOST_SB_ADDR_U_OFFSET(port, sb_id), U64_LO(section)); + REG_WR(bp, BAR_CSTRORM_INTMEM + + ((CSTORM_SB_HOST_SB_ADDR_U_OFFSET(port, sb_id)) + 4), U64_HI(section)); - REG_WR8(bp, BAR_USTRORM_INTMEM + FP_USB_FUNC_OFF + - USTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), func); + REG_WR8(bp, BAR_CSTRORM_INTMEM + FP_USB_FUNC_OFF + + CSTORM_SB_HOST_STATUS_BLOCK_U_OFFSET(port, sb_id), func); for (index = 0; index < HC_USTORM_SB_NUM_INDICES; index++) - REG_WR16(bp, BAR_USTRORM_INTMEM + - USTORM_SB_HC_DISABLE_OFFSET(port, sb_id, index), 1); + REG_WR16(bp, BAR_CSTRORM_INTMEM + + CSTORM_SB_HC_DISABLE_U_OFFSET(port, sb_id, index), 1); /* CSTORM */ section = ((u64)mapping) + offsetof(struct host_status_block, @@ -4302,16 +4355,16 @@ static void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb, sb->c_status_block.status_block_id = sb_id; REG_WR(bp, BAR_CSTRORM_INTMEM + - CSTORM_SB_HOST_SB_ADDR_OFFSET(port, sb_id), U64_LO(section)); + CSTORM_SB_HOST_SB_ADDR_C_OFFSET(port, sb_id), U64_LO(section)); REG_WR(bp, BAR_CSTRORM_INTMEM + - ((CSTORM_SB_HOST_SB_ADDR_OFFSET(port, sb_id)) + 4), + ((CSTORM_SB_HOST_SB_ADDR_C_OFFSET(port, sb_id)) + 4), U64_HI(section)); REG_WR8(bp, BAR_CSTRORM_INTMEM + FP_CSB_FUNC_OFF + - CSTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), func); + CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, sb_id), func); for (index = 0; index < HC_CSTORM_SB_NUM_INDICES; index++) REG_WR16(bp, BAR_CSTRORM_INTMEM + - CSTORM_SB_HC_DISABLE_OFFSET(port, sb_id, index), 1); + CSTORM_SB_HC_DISABLE_C_OFFSET(port, sb_id, index), 1); bnx2x_ack_sb(bp, sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0); } @@ -4320,16 +4373,16 @@ static void bnx2x_zero_def_sb(struct bnx2x *bp) { int func = BP_FUNC(bp); - bnx2x_init_fill(bp, TSTORM_INTMEM_ADDR + + bnx2x_init_fill(bp, TSEM_REG_FAST_MEMORY + TSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, sizeof(struct tstorm_def_status_block)/4); - bnx2x_init_fill(bp, USTORM_INTMEM_ADDR + - USTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, - sizeof(struct ustorm_def_status_block)/4); - bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR + - CSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, - sizeof(struct cstorm_def_status_block)/4); - bnx2x_init_fill(bp, XSTORM_INTMEM_ADDR + + bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY + + CSTORM_DEF_SB_HOST_STATUS_BLOCK_U_OFFSET(func), 0, + sizeof(struct cstorm_def_status_block_u)/4); + bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY + + CSTORM_DEF_SB_HOST_STATUS_BLOCK_C_OFFSET(func), 0, + sizeof(struct cstorm_def_status_block_c)/4); + bnx2x_init_fill(bp, XSEM_REG_FAST_MEMORY + XSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, sizeof(struct xstorm_def_status_block)/4); } @@ -4381,17 +4434,17 @@ static void bnx2x_init_def_sb(struct bnx2x *bp, u_def_status_block); def_sb->u_def_status_block.status_block_id = sb_id; - REG_WR(bp, BAR_USTRORM_INTMEM + - USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func), U64_LO(section)); - REG_WR(bp, BAR_USTRORM_INTMEM + - ((USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func)) + 4), + REG_WR(bp, BAR_CSTRORM_INTMEM + + CSTORM_DEF_SB_HOST_SB_ADDR_U_OFFSET(func), U64_LO(section)); + REG_WR(bp, BAR_CSTRORM_INTMEM + + ((CSTORM_DEF_SB_HOST_SB_ADDR_U_OFFSET(func)) + 4), U64_HI(section)); - REG_WR8(bp, BAR_USTRORM_INTMEM + DEF_USB_FUNC_OFF + - USTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), func); + REG_WR8(bp, BAR_CSTRORM_INTMEM + DEF_USB_FUNC_OFF + + CSTORM_DEF_SB_HOST_STATUS_BLOCK_U_OFFSET(func), func); for (index = 0; index < HC_USTORM_DEF_SB_NUM_INDICES; index++) - REG_WR16(bp, BAR_USTRORM_INTMEM + - USTORM_DEF_SB_HC_DISABLE_OFFSET(func, index), 1); + REG_WR16(bp, BAR_CSTRORM_INTMEM + + CSTORM_DEF_SB_HC_DISABLE_U_OFFSET(func, index), 1); /* CSTORM */ section = ((u64)mapping) + offsetof(struct host_def_status_block, @@ -4399,16 +4452,16 @@ static void bnx2x_init_def_sb(struct bnx2x *bp, def_sb->c_def_status_block.status_block_id = sb_id; REG_WR(bp, BAR_CSTRORM_INTMEM + - CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func), U64_LO(section)); + CSTORM_DEF_SB_HOST_SB_ADDR_C_OFFSET(func), U64_LO(section)); REG_WR(bp, BAR_CSTRORM_INTMEM + - ((CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func)) + 4), + ((CSTORM_DEF_SB_HOST_SB_ADDR_C_OFFSET(func)) + 4), U64_HI(section)); REG_WR8(bp, BAR_CSTRORM_INTMEM + DEF_CSB_FUNC_OFF + - CSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), func); + CSTORM_DEF_SB_HOST_STATUS_BLOCK_C_OFFSET(func), func); for (index = 0; index < HC_CSTORM_DEF_SB_NUM_INDICES; index++) REG_WR16(bp, BAR_CSTRORM_INTMEM + - CSTORM_DEF_SB_HC_DISABLE_OFFSET(func, index), 1); + CSTORM_DEF_SB_HC_DISABLE_C_OFFSET(func, index), 1); /* TSTORM */ section = ((u64)mapping) + offsetof(struct host_def_status_block, @@ -4459,23 +4512,23 @@ static void bnx2x_update_coalesce(struct bnx2x *bp) int sb_id = bp->fp[i].sb_id; /* HC_INDEX_U_ETH_RX_CQ_CONS */ - REG_WR8(bp, BAR_USTRORM_INTMEM + - USTORM_SB_HC_TIMEOUT_OFFSET(port, sb_id, - U_SB_ETH_RX_CQ_INDEX), + REG_WR8(bp, BAR_CSTRORM_INTMEM + + CSTORM_SB_HC_TIMEOUT_U_OFFSET(port, sb_id, + U_SB_ETH_RX_CQ_INDEX), bp->rx_ticks/12); - REG_WR16(bp, BAR_USTRORM_INTMEM + - USTORM_SB_HC_DISABLE_OFFSET(port, sb_id, - U_SB_ETH_RX_CQ_INDEX), + REG_WR16(bp, BAR_CSTRORM_INTMEM + + CSTORM_SB_HC_DISABLE_U_OFFSET(port, sb_id, + U_SB_ETH_RX_CQ_INDEX), (bp->rx_ticks/12) ? 0 : 1); /* HC_INDEX_C_ETH_TX_CQ_CONS */ REG_WR8(bp, BAR_CSTRORM_INTMEM + - CSTORM_SB_HC_TIMEOUT_OFFSET(port, sb_id, - C_SB_ETH_TX_CQ_INDEX), + CSTORM_SB_HC_TIMEOUT_C_OFFSET(port, sb_id, + C_SB_ETH_TX_CQ_INDEX), bp->tx_ticks/12); REG_WR16(bp, BAR_CSTRORM_INTMEM + - CSTORM_SB_HC_DISABLE_OFFSET(port, sb_id, - C_SB_ETH_TX_CQ_INDEX), + CSTORM_SB_HC_DISABLE_C_OFFSET(port, sb_id, + C_SB_ETH_TX_CQ_INDEX), (bp->tx_ticks/12) ? 0 : 1); } } @@ -4548,6 +4601,9 @@ static void bnx2x_init_rx_rings(struct bnx2x *bp) fp->rx_cons_sb = BNX2X_RX_SB_INDEX; fp->rx_bd_cons_sb = BNX2X_RX_SB_BD_INDEX; + /* Mark queue as Rx */ + fp->is_rx_queue = 1; + /* "next page" elements initialization */ /* SGE ring */ for (i = 1; i <= NUM_RX_SGE_PAGES; i++) { @@ -4657,17 +4713,21 @@ static void bnx2x_init_tx_ring(struct bnx2x *bp) struct bnx2x_fastpath *fp = &bp->fp[j]; for (i = 1; i <= NUM_TX_RINGS; i++) { - struct eth_tx_bd *tx_bd = - &fp->tx_desc_ring[TX_DESC_CNT * i - 1]; + struct eth_tx_next_bd *tx_next_bd = + &fp->tx_desc_ring[TX_DESC_CNT * i - 1].next_bd; - tx_bd->addr_hi = + tx_next_bd->addr_hi = cpu_to_le32(U64_HI(fp->tx_desc_mapping + BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); - tx_bd->addr_lo = + tx_next_bd->addr_lo = cpu_to_le32(U64_LO(fp->tx_desc_mapping + BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); } + fp->tx_db.data.header.header = DOORBELL_HDR_DB_TYPE; + fp->tx_db.data.zero_fill1 = 0; + fp->tx_db.data.prod = 0; + fp->tx_pkt_prod = 0; fp->tx_pkt_cons = 0; fp->tx_bd_prod = 0; @@ -4703,16 +4763,15 @@ static void bnx2x_init_context(struct bnx2x *bp) { int i; - for_each_queue(bp, i) { + for_each_rx_queue(bp, i) { struct eth_context *context = bnx2x_sp(bp, context[i].eth); struct bnx2x_fastpath *fp = &bp->fp[i]; u8 cl_id = fp->cl_id; - u8 sb_id = fp->sb_id; context->ustorm_st_context.common.sb_index_numbers = BNX2X_RX_SB_INDEX_NUM; context->ustorm_st_context.common.clientId = cl_id; - context->ustorm_st_context.common.status_block_id = sb_id; + context->ustorm_st_context.common.status_block_id = fp->sb_id; context->ustorm_st_context.common.flags = (USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_MC_ALIGNMENT | USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS); @@ -4728,8 +4787,7 @@ static void bnx2x_init_context(struct bnx2x *bp) U64_LO(fp->rx_desc_mapping); if (!fp->disable_tpa) { context->ustorm_st_context.common.flags |= - (USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA | - USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_SGE_RING); + USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA; context->ustorm_st_context.common.sge_buff_size = (u16)min((u32)SGE_PAGE_SIZE*PAGES_PER_SGE, (u32)0xffff); @@ -4737,6 +4795,13 @@ static void bnx2x_init_context(struct bnx2x *bp) U64_HI(fp->rx_sge_mapping); context->ustorm_st_context.common.sge_page_base_lo = U64_LO(fp->rx_sge_mapping); + + context->ustorm_st_context.common.max_sges_for_packet = + SGE_PAGE_ALIGN(bp->dev->mtu) >> SGE_PAGE_SHIFT; + context->ustorm_st_context.common.max_sges_for_packet = + ((context->ustorm_st_context.common. + max_sges_for_packet + PAGES_PER_SGE - 1) & + (~(PAGES_PER_SGE - 1))) >> PAGES_PER_SGE_SHIFT; } context->ustorm_ag_context.cdu_usage = @@ -4744,24 +4809,27 @@ static void bnx2x_init_context(struct bnx2x *bp) CDU_REGION_NUMBER_UCM_AG, ETH_CONNECTION_TYPE); + context->xstorm_ag_context.cdu_reserved = + CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i), + CDU_REGION_NUMBER_XCM_AG, + ETH_CONNECTION_TYPE); + } + + for_each_tx_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + struct eth_context *context = + bnx2x_sp(bp, context[i - bp->num_rx_queues].eth); + + context->cstorm_st_context.sb_index_number = + C_SB_ETH_TX_CQ_INDEX; + context->cstorm_st_context.status_block_id = fp->sb_id; + context->xstorm_st_context.tx_bd_page_base_hi = U64_HI(fp->tx_desc_mapping); context->xstorm_st_context.tx_bd_page_base_lo = U64_LO(fp->tx_desc_mapping); - context->xstorm_st_context.db_data_addr_hi = - U64_HI(fp->tx_prods_mapping); - context->xstorm_st_context.db_data_addr_lo = - U64_LO(fp->tx_prods_mapping); - context->xstorm_st_context.statistics_data = (cl_id | + context->xstorm_st_context.statistics_data = (fp->cl_id | XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE); - context->cstorm_st_context.sb_index_number = - C_SB_ETH_TX_CQ_INDEX; - context->cstorm_st_context.status_block_id = sb_id; - - context->xstorm_ag_context.cdu_reserved = - CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i), - CDU_REGION_NUMBER_XCM_AG, - ETH_CONNECTION_TYPE); } } @@ -4799,18 +4867,6 @@ static void bnx2x_set_client_config(struct bnx2x *bp) } #endif - if (bp->flags & TPA_ENABLE_FLAG) { - tstorm_client.max_sges_for_packet = - SGE_PAGE_ALIGN(tstorm_client.mtu) >> SGE_PAGE_SHIFT; - tstorm_client.max_sges_for_packet = - ((tstorm_client.max_sges_for_packet + - PAGES_PER_SGE - 1) & (~(PAGES_PER_SGE - 1))) >> - PAGES_PER_SGE_SHIFT; - - tstorm_client.config_flags |= - TSTORM_ETH_CLIENT_CONFIG_ENABLE_SGE_RING; - } - for_each_queue(bp, i) { tstorm_client.statistics_counter_id = bp->fp[i].cl_id; @@ -4893,17 +4949,6 @@ static void bnx2x_init_internal_common(struct bnx2x *bp) { int i; - if (bp->flags & TPA_ENABLE_FLAG) { - struct tstorm_eth_tpa_exist tpa = {0}; - - tpa.tpa_exist = 1; - - REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_TPA_EXIST_OFFSET, - ((u32 *)&tpa)[0]); - REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_TPA_EXIST_OFFSET + 4, - ((u32 *)&tpa)[1]); - } - /* Zero this manually as its initialization is currently missing in the initTool */ for (i = 0; i < (USTORM_AGG_DATA_SIZE >> 2); i++) @@ -4915,8 +4960,10 @@ static void bnx2x_init_internal_port(struct bnx2x *bp) { int port = BP_PORT(bp); - REG_WR(bp, BAR_USTRORM_INTMEM + USTORM_HC_BTR_OFFSET(port), BNX2X_BTR); - REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_OFFSET(port), BNX2X_BTR); + REG_WR(bp, + BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_U_OFFSET(port), BNX2X_BTR); + REG_WR(bp, + BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_C_OFFSET(port), BNX2X_BTR); REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_HC_BTR_OFFSET(port), BNX2X_BTR); REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_HC_BTR_OFFSET(port), BNX2X_BTR); } @@ -4976,6 +5023,12 @@ static void bnx2x_init_internal_func(struct bnx2x *bp) tstorm_config.config_flags = MULTI_FLAGS(bp); tstorm_config.rss_result_mask = MULTI_MASK; } + + /* Enable TPA if needed */ + if (bp->flags & TPA_ENABLE_FLAG) + tstorm_config.config_flags |= + TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA; + if (IS_E1HMF(bp)) tstorm_config.config_flags |= TSTORM_ETH_FUNCTION_COMMON_CONFIG_E1HOV_IN_CAM; @@ -5087,6 +5140,14 @@ static void bnx2x_init_internal_func(struct bnx2x *bp) USTORM_CQE_PAGE_BASE_OFFSET(port, fp->cl_id) + 4, U64_HI(fp->rx_comp_mapping)); + /* Next page */ + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_CQE_PAGE_NEXT_OFFSET(port, fp->cl_id), + U64_LO(fp->rx_comp_mapping + BCM_PAGE_SIZE)); + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_CQE_PAGE_NEXT_OFFSET(port, fp->cl_id) + 4, + U64_HI(fp->rx_comp_mapping + BCM_PAGE_SIZE)); + REG_WR16(bp, BAR_USTRORM_INTMEM + USTORM_MAX_AGG_SIZE_OFFSET(port, fp->cl_id), max_agg_size); @@ -5197,6 +5258,9 @@ static void bnx2x_nic_init(struct bnx2x *bp, u32 load_code) fp->index = i; fp->cl_id = BP_L_ID(bp) + i; fp->sb_id = fp->cl_id; + /* Suitable Rx and Tx SBs are served by the same client */ + if (i >= bp->num_rx_queues) + fp->cl_id -= bp->num_rx_queues; DP(NETIF_MSG_IFUP, "queue[%d]: bnx2x_init_sb(%p,%p) cl_id %d sb %d\n", i, bp, fp->status_blk, fp->cl_id, fp->sb_id); @@ -5729,10 +5793,10 @@ static int bnx2x_init_common(struct bnx2x *bp) bnx2x_init_block(bp, USDM_BLOCK, COMMON_STAGE); bnx2x_init_block(bp, XSDM_BLOCK, COMMON_STAGE); - bnx2x_init_fill(bp, TSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp)); - bnx2x_init_fill(bp, USTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp)); - bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp)); - bnx2x_init_fill(bp, XSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp)); + bnx2x_init_fill(bp, TSEM_REG_FAST_MEMORY, 0, STORM_INTMEM_SIZE(bp)); + bnx2x_init_fill(bp, USEM_REG_FAST_MEMORY, 0, STORM_INTMEM_SIZE(bp)); + bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY, 0, STORM_INTMEM_SIZE(bp)); + bnx2x_init_fill(bp, XSEM_REG_FAST_MEMORY, 0, STORM_INTMEM_SIZE(bp)); bnx2x_init_block(bp, TSEM_BLOCK, COMMON_STAGE); bnx2x_init_block(bp, USEM_BLOCK, COMMON_STAGE); @@ -5765,11 +5829,6 @@ static int bnx2x_init_common(struct bnx2x *bp) bnx2x_init_block(bp, CDU_BLOCK, COMMON_STAGE); val = (4 << 24) + (0 << 12) + 1024; REG_WR(bp, CDU_REG_CDU_GLOBAL_PARAMS, val); - if (CHIP_IS_E1(bp)) { - /* !!! fix pxp client crdit until excel update */ - REG_WR(bp, CDU_REG_CDU_DEBUG, 0x264); - REG_WR(bp, CDU_REG_CDU_DEBUG, 0); - } bnx2x_init_block(bp, CFC_BLOCK, COMMON_STAGE); REG_WR(bp, CFC_REG_INIT_REG, 0x7FF); @@ -5782,19 +5841,14 @@ static int bnx2x_init_common(struct bnx2x *bp) bnx2x_init_block(bp, HC_BLOCK, COMMON_STAGE); bnx2x_init_block(bp, MISC_AEU_BLOCK, COMMON_STAGE); - /* PXPCS COMMON comes here */ bnx2x_init_block(bp, PXPCS_BLOCK, COMMON_STAGE); /* Reset PCIE errors for debug */ REG_WR(bp, 0x2814, 0xffffffff); REG_WR(bp, 0x3820, 0xffffffff); - /* EMAC0 COMMON comes here */ bnx2x_init_block(bp, EMAC0_BLOCK, COMMON_STAGE); - /* EMAC1 COMMON comes here */ bnx2x_init_block(bp, EMAC1_BLOCK, COMMON_STAGE); - /* DBU COMMON comes here */ bnx2x_init_block(bp, DBU_BLOCK, COMMON_STAGE); - /* DBG COMMON comes here */ bnx2x_init_block(bp, DBG_BLOCK, COMMON_STAGE); bnx2x_init_block(bp, NIG_BLOCK, COMMON_STAGE); @@ -5875,10 +5929,12 @@ static int bnx2x_init_port(struct bnx2x *bp) REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, 0); - /* Port PXP comes here */ bnx2x_init_block(bp, PXP_BLOCK, init_stage); - /* Port PXP2 comes here */ bnx2x_init_block(bp, PXP2_BLOCK, init_stage); + + bnx2x_init_block(bp, TCM_BLOCK, init_stage); + bnx2x_init_block(bp, UCM_BLOCK, init_stage); + bnx2x_init_block(bp, CCM_BLOCK, init_stage); #ifdef BCM_ISCSI /* Port0 1 * Port1 385 */ @@ -5904,17 +5960,14 @@ static int bnx2x_init_port(struct bnx2x *bp) REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2); REG_WR(bp, PXP2_REG_PSWRQ_SRC0_L2P + func*4, PXP_ONE_ILT(i)); #endif - /* Port CMs come here */ bnx2x_init_block(bp, XCM_BLOCK, init_stage); - /* Port QM comes here */ #ifdef BCM_ISCSI REG_WR(bp, TM_REG_LIN0_SCAN_TIME + func*4, 1024/64*20); REG_WR(bp, TM_REG_LIN0_MAX_ACTIVE_CID + func*4, 31); bnx2x_init_block(bp, TIMERS_BLOCK, init_stage); #endif - /* Port DQ comes here */ bnx2x_init_block(bp, DQ_BLOCK, init_stage); bnx2x_init_block(bp, BRB1_BLOCK, init_stage); @@ -5941,15 +5994,11 @@ static int bnx2x_init_port(struct bnx2x *bp) REG_WR(bp, BRB1_REG_PAUSE_HIGH_THRESHOLD_0 + port*4, high); - /* Port PRS comes here */ bnx2x_init_block(bp, PRS_BLOCK, init_stage); - /* Port TSDM comes here */ + bnx2x_init_block(bp, TSDM_BLOCK, init_stage); - /* Port CSDM comes here */ bnx2x_init_block(bp, CSDM_BLOCK, init_stage); - /* Port USDM comes here */ bnx2x_init_block(bp, USDM_BLOCK, init_stage); - /* Port XSDM comes here */ bnx2x_init_block(bp, XSDM_BLOCK, init_stage); bnx2x_init_block(bp, TSEM_BLOCK, init_stage); @@ -5957,9 +6006,7 @@ static int bnx2x_init_port(struct bnx2x *bp) bnx2x_init_block(bp, CSEM_BLOCK, init_stage); bnx2x_init_block(bp, XSEM_BLOCK, init_stage); - /* Port UPB comes here */ bnx2x_init_block(bp, UPB_BLOCK, init_stage); - /* Port XPB comes here */ bnx2x_init_block(bp, XPB_BLOCK, init_stage); bnx2x_init_block(bp, PBF_BLOCK, init_stage); @@ -5989,11 +6036,8 @@ static int bnx2x_init_port(struct bnx2x *bp) REG_WR_DMAE(bp, SRC_REG_LASTFREE0 + func*4, wb_write, 2); REG_WR(bp, SRC_REG_NUMBER_HASH_BITS0 + func*4, 10); - /* Port SRCH comes here */ #endif - /* Port CDU comes here */ bnx2x_init_block(bp, CDU_BLOCK, init_stage); - /* Port CFC comes here */ bnx2x_init_block(bp, CFC_BLOCK, init_stage); if (CHIP_IS_E1(bp)) { @@ -6010,15 +6054,10 @@ static int bnx2x_init_port(struct bnx2x *bp) REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4, (IS_E1HMF(bp) ? 0xF7 : 0x7)); - /* Port PXPCS comes here */ bnx2x_init_block(bp, PXPCS_BLOCK, init_stage); - /* Port EMAC0 comes here */ bnx2x_init_block(bp, EMAC0_BLOCK, init_stage); - /* Port EMAC1 comes here */ bnx2x_init_block(bp, EMAC1_BLOCK, init_stage); - /* Port DBU comes here */ bnx2x_init_block(bp, DBU_BLOCK, init_stage); - /* Port DBG comes here */ bnx2x_init_block(bp, DBG_BLOCK, init_stage); bnx2x_init_block(bp, NIG_BLOCK, init_stage); @@ -6040,9 +6079,7 @@ static int bnx2x_init_port(struct bnx2x *bp) } } - /* Port MCP comes here */ bnx2x_init_block(bp, MCP_BLOCK, init_stage); - /* Port DMAE comes here */ bnx2x_init_block(bp, DMAE_BLOCK, init_stage); switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) { @@ -6302,8 +6339,7 @@ static void bnx2x_free_mem(struct bnx2x *bp) /* status blocks */ BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk), bnx2x_fp(bp, i, status_blk_mapping), - sizeof(struct host_status_block) + - sizeof(struct eth_tx_db_data)); + sizeof(struct host_status_block)); } /* Rx */ for_each_rx_queue(bp, i) { @@ -6332,7 +6368,7 @@ static void bnx2x_free_mem(struct bnx2x *bp) BNX2X_FREE(bnx2x_fp(bp, i, tx_buf_ring)); BNX2X_PCI_FREE(bnx2x_fp(bp, i, tx_desc_ring), bnx2x_fp(bp, i, tx_desc_mapping), - sizeof(struct eth_tx_bd) * NUM_TX_BD); + sizeof(union eth_tx_bd_types) * NUM_TX_BD); } /* end of fastpath */ @@ -6383,8 +6419,7 @@ static int bnx2x_alloc_mem(struct bnx2x *bp) /* status blocks */ BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, status_blk), &bnx2x_fp(bp, i, status_blk_mapping), - sizeof(struct host_status_block) + - sizeof(struct eth_tx_db_data)); + sizeof(struct host_status_block)); } /* Rx */ for_each_rx_queue(bp, i) { @@ -6411,19 +6446,12 @@ static int bnx2x_alloc_mem(struct bnx2x *bp) /* Tx */ for_each_tx_queue(bp, i) { - bnx2x_fp(bp, i, hw_tx_prods) = - (void *)(bnx2x_fp(bp, i, status_blk) + 1); - - bnx2x_fp(bp, i, tx_prods_mapping) = - bnx2x_fp(bp, i, status_blk_mapping) + - sizeof(struct host_status_block); - /* fastpath tx rings: tx_buf tx_desc */ BNX2X_ALLOC(bnx2x_fp(bp, i, tx_buf_ring), sizeof(struct sw_tx_bd) * NUM_TX_BD); BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, tx_desc_ring), &bnx2x_fp(bp, i, tx_desc_mapping), - sizeof(struct eth_tx_bd) * NUM_TX_BD); + sizeof(union eth_tx_bd_types) * NUM_TX_BD); } /* end of fastpath */ @@ -6600,7 +6628,12 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp) for_each_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; - sprintf(fp->name, "%s.fp%d", bp->dev->name, i); + if (i < bp->num_rx_queues) + sprintf(fp->name, "%s-rx-%d", bp->dev->name, i); + else + sprintf(fp->name, "%s-tx-%d", + bp->dev->name, i - bp->num_rx_queues); + rc = request_irq(bp->msix_table[i + offset].vector, bnx2x_msix_fp_int, 0, fp->name, fp); if (rc) { @@ -6613,16 +6646,11 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp) } i = BNX2X_NUM_QUEUES(bp); - if (is_multi(bp)) - printk(KERN_INFO PFX - "%s: using MSI-X IRQs: sp %d fp %d - %d\n", - bp->dev->name, bp->msix_table[0].vector, - bp->msix_table[offset].vector, - bp->msix_table[offset + i - 1].vector); - else - printk(KERN_INFO PFX "%s: using MSI-X IRQs: sp %d fp %d\n", - bp->dev->name, bp->msix_table[0].vector, - bp->msix_table[offset + i - 1].vector); + printk(KERN_INFO PFX "%s: using MSI-X IRQs: sp %d fp[%d] %d" + " ... fp[%d] %d\n", + bp->dev->name, bp->msix_table[0].vector, + 0, bp->msix_table[offset].vector, + i - 1, bp->msix_table[offset + i - 1].vector); return 0; } @@ -6730,7 +6758,8 @@ static void bnx2x_set_mac_addr_e1(struct bnx2x *bp, int set) config->config_table[0].target_table_entry.flags = 0; else CAM_INVALIDATE(config->config_table[0]); - config->config_table[0].target_table_entry.client_id = 0; + config->config_table[0].target_table_entry.clients_bit_vector = + cpu_to_le32(1 << BP_L_ID(bp)); config->config_table[0].target_table_entry.vlan_id = 0; DP(NETIF_MSG_IFUP, "%s MAC (%04x:%04x:%04x)\n", @@ -6749,7 +6778,8 @@ static void bnx2x_set_mac_addr_e1(struct bnx2x *bp, int set) TSTORM_CAM_TARGET_TABLE_ENTRY_BROADCAST; else CAM_INVALIDATE(config->config_table[1]); - config->config_table[1].target_table_entry.client_id = 0; + config->config_table[1].target_table_entry.clients_bit_vector = + cpu_to_le32(1 << BP_L_ID(bp)); config->config_table[1].target_table_entry.vlan_id = 0; bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0, @@ -6762,11 +6792,6 @@ static void bnx2x_set_mac_addr_e1h(struct bnx2x *bp, int set) struct mac_configuration_cmd_e1h *config = (struct mac_configuration_cmd_e1h *)bnx2x_sp(bp, mac_config); - if (set && (bp->state != BNX2X_STATE_OPEN)) { - DP(NETIF_MSG_IFUP, "state is %x, returning\n", bp->state); - return; - } - /* CAM allocation for E1H * unicasts: by func number * multicast: 20+FUNC*20, 20 each @@ -6783,7 +6808,8 @@ static void bnx2x_set_mac_addr_e1h(struct bnx2x *bp, int set) swab16(*(u16 *)&bp->dev->dev_addr[2]); config->config_table[0].lsb_mac_addr = swab16(*(u16 *)&bp->dev->dev_addr[4]); - config->config_table[0].client_id = BP_L_ID(bp); + config->config_table[0].clients_bit_vector = + cpu_to_le32(1 << BP_L_ID(bp)); config->config_table[0].vlan_id = 0; config->config_table[0].e1hov_id = cpu_to_le16(bp->e1hov); if (set) @@ -6880,49 +6906,94 @@ static int bnx2x_setup_multi(struct bnx2x *bp, int index) static int bnx2x_poll(struct napi_struct *napi, int budget); -static void bnx2x_set_int_mode(struct bnx2x *bp) +static void bnx2x_set_int_mode_msix(struct bnx2x *bp, int *num_rx_queues_out, + int *num_tx_queues_out) +{ + int _num_rx_queues = 0, _num_tx_queues = 0; + + switch (bp->multi_mode) { + case ETH_RSS_MODE_DISABLED: + _num_rx_queues = 1; + _num_tx_queues = 1; + break; + + case ETH_RSS_MODE_REGULAR: + if (num_rx_queues) + _num_rx_queues = min_t(u32, num_rx_queues, + BNX2X_MAX_QUEUES(bp)); + else + _num_rx_queues = min_t(u32, num_online_cpus(), + BNX2X_MAX_QUEUES(bp)); + + if (num_tx_queues) + _num_tx_queues = min_t(u32, num_tx_queues, + BNX2X_MAX_QUEUES(bp)); + else + _num_tx_queues = min_t(u32, num_online_cpus(), + BNX2X_MAX_QUEUES(bp)); + + /* There must be not more Tx queues than Rx queues */ + if (_num_tx_queues > _num_rx_queues) { + BNX2X_ERR("number of tx queues (%d) > " + "number of rx queues (%d)" + " defaulting to %d\n", + _num_tx_queues, _num_rx_queues, + _num_rx_queues); + _num_tx_queues = _num_rx_queues; + } + break; + + + default: + _num_rx_queues = 1; + _num_tx_queues = 1; + break; + } + + *num_rx_queues_out = _num_rx_queues; + *num_tx_queues_out = _num_tx_queues; +} + +static int bnx2x_set_int_mode(struct bnx2x *bp) { - int num_queues; + int rc = 0; switch (int_mode) { case INT_MODE_INTx: case INT_MODE_MSI: - num_queues = 1; - bp->num_rx_queues = num_queues; - bp->num_tx_queues = num_queues; - DP(NETIF_MSG_IFUP, - "set number of queues to %d\n", num_queues); + bp->num_rx_queues = 1; + bp->num_tx_queues = 1; + DP(NETIF_MSG_IFUP, "set number of queues to 1\n"); break; case INT_MODE_MSIX: default: - if (bp->multi_mode == ETH_RSS_MODE_REGULAR) - num_queues = min_t(u32, num_online_cpus(), - BNX2X_MAX_QUEUES(bp)); - else - num_queues = 1; - bp->num_rx_queues = num_queues; - bp->num_tx_queues = num_queues; - DP(NETIF_MSG_IFUP, "set number of rx queues to %d" - " number of tx queues to %d\n", + /* Set interrupt mode according to bp->multi_mode value */ + bnx2x_set_int_mode_msix(bp, &bp->num_rx_queues, + &bp->num_tx_queues); + + DP(NETIF_MSG_IFUP, "set number of queues to: rx %d tx %d\n", bp->num_rx_queues, bp->num_tx_queues); + /* if we can't use MSI-X we only need one fp, * so try to enable MSI-X with the requested number of fp's * and fallback to MSI or legacy INTx with one fp */ - if (bnx2x_enable_msix(bp)) { + rc = bnx2x_enable_msix(bp); + if (rc) { /* failed to enable MSI-X */ - num_queues = 1; - bp->num_rx_queues = num_queues; - bp->num_tx_queues = num_queues; if (bp->multi_mode) BNX2X_ERR("Multi requested but failed to " - "enable MSI-X set number of " - "queues to %d\n", num_queues); + "enable MSI-X (rx %d tx %d), " + "set number of queues to 1\n", + bp->num_rx_queues, bp->num_tx_queues); + bp->num_rx_queues = 1; + bp->num_tx_queues = 1; } break; } bp->dev->real_num_tx_queues = bp->num_tx_queues; + return rc; } static void bnx2x_set_rx_mode(struct net_device *dev); @@ -6931,16 +7002,16 @@ static void bnx2x_set_rx_mode(struct net_device *dev); static int bnx2x_nic_load(struct bnx2x *bp, int load_mode) { u32 load_code; - int i, rc = 0; + int i, rc; + #ifdef BNX2X_STOP_ON_ERROR - DP(NETIF_MSG_IFUP, "enter load_mode %d\n", load_mode); if (unlikely(bp->panic)) return -EPERM; #endif bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD; - bnx2x_set_int_mode(bp); + rc = bnx2x_set_int_mode(bp); if (bnx2x_alloc_mem(bp)) return -ENOMEM; @@ -6953,17 +7024,6 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode) netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi), bnx2x_poll, 128); -#ifdef BNX2X_STOP_ON_ERROR - for_each_rx_queue(bp, i) { - struct bnx2x_fastpath *fp = &bp->fp[i]; - - fp->poll_no_work = 0; - fp->poll_calls = 0; - fp->poll_max_calls = 0; - fp->poll_complete = 0; - fp->poll_exit = 0; - } -#endif bnx2x_napi_enable(bp); if (bp->flags & USING_MSIX_FLAG) { @@ -6973,6 +7033,8 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode) goto load_error1; } } else { + /* Fall to INTx if failed to enable MSI-X due to lack of + memory (in bnx2x_set_int_mode()) */ if ((rc != -ENOMEM) && (int_mode != INT_MODE_INTx)) bnx2x_enable_msi(bp); bnx2x_ack_int(bp); @@ -7065,17 +7127,18 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode) bp->state = BNX2X_STATE_DISABLED; } - if (bp->state == BNX2X_STATE_OPEN) + if (bp->state == BNX2X_STATE_OPEN) { for_each_nondefault_queue(bp, i) { rc = bnx2x_setup_multi(bp, i); if (rc) goto load_error3; } - if (CHIP_IS_E1(bp)) - bnx2x_set_mac_addr_e1(bp, 1); - else - bnx2x_set_mac_addr_e1h(bp, 1); + if (CHIP_IS_E1(bp)) + bnx2x_set_mac_addr_e1(bp, 1); + else + bnx2x_set_mac_addr_e1h(bp, 1); + } if (bp->port.pmf) bnx2x_initial_phy_init(bp, load_mode); @@ -7083,14 +7146,18 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode) /* Start fast path */ switch (load_mode) { case LOAD_NORMAL: - /* Tx queue should be only reenabled */ - netif_tx_wake_all_queues(bp->dev); + if (bp->state == BNX2X_STATE_OPEN) { + /* Tx queue should be only reenabled */ + netif_tx_wake_all_queues(bp->dev); + } /* Initialize the receive filter. */ bnx2x_set_rx_mode(bp->dev); break; case LOAD_OPEN: netif_tx_start_all_queues(bp->dev); + if (bp->state != BNX2X_STATE_OPEN) + netif_tx_disable(bp->dev); /* Initialize the receive filter. */ bnx2x_set_rx_mode(bp->dev); break; @@ -9184,18 +9251,19 @@ static int bnx2x_get_coalesce(struct net_device *dev, return 0; } +#define BNX2X_MAX_COALES_TOUT (0xf0*12) /* Maximal coalescing timeout in us */ static int bnx2x_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal) { struct bnx2x *bp = netdev_priv(dev); bp->rx_ticks = (u16) coal->rx_coalesce_usecs; - if (bp->rx_ticks > BNX2X_MAX_COALESCE_TOUT) - bp->rx_ticks = BNX2X_MAX_COALESCE_TOUT; + if (bp->rx_ticks > BNX2X_MAX_COALES_TOUT) + bp->rx_ticks = BNX2X_MAX_COALES_TOUT; bp->tx_ticks = (u16) coal->tx_coalesce_usecs; - if (bp->tx_ticks > BNX2X_MAX_COALESCE_TOUT) - bp->tx_ticks = BNX2X_MAX_COALESCE_TOUT; + if (bp->tx_ticks > BNX2X_MAX_COALES_TOUT) + bp->tx_ticks = BNX2X_MAX_COALES_TOUT; if (netif_running(dev)) bnx2x_update_coalesce(bp); @@ -9554,12 +9622,14 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up) unsigned int pkt_size, num_pkts, i; struct sk_buff *skb; unsigned char *packet; - struct bnx2x_fastpath *fp = &bp->fp[0]; + struct bnx2x_fastpath *fp_rx = &bp->fp[0]; + struct bnx2x_fastpath *fp_tx = &bp->fp[bp->num_rx_queues]; u16 tx_start_idx, tx_idx; u16 rx_start_idx, rx_idx; - u16 pkt_prod; + u16 pkt_prod, bd_prod; struct sw_tx_bd *tx_buf; - struct eth_tx_bd *tx_bd; + struct eth_tx_start_bd *tx_start_bd; + struct eth_tx_parse_bd *pbd = NULL; dma_addr_t mapping; union eth_rx_cqe *cqe; u8 cqe_fp_flags; @@ -9591,57 +9661,64 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up) } packet = skb_put(skb, pkt_size); memcpy(packet, bp->dev->dev_addr, ETH_ALEN); - memset(packet + ETH_ALEN, 0, (ETH_HLEN - ETH_ALEN)); + memset(packet + ETH_ALEN, 0, ETH_ALEN); + memset(packet + 2*ETH_ALEN, 0x77, (ETH_HLEN - 2*ETH_ALEN)); for (i = ETH_HLEN; i < pkt_size; i++) packet[i] = (unsigned char) (i & 0xff); /* send the loopback packet */ num_pkts = 0; - tx_start_idx = le16_to_cpu(*fp->tx_cons_sb); - rx_start_idx = le16_to_cpu(*fp->rx_cons_sb); + tx_start_idx = le16_to_cpu(*fp_tx->tx_cons_sb); + rx_start_idx = le16_to_cpu(*fp_rx->rx_cons_sb); - pkt_prod = fp->tx_pkt_prod++; - tx_buf = &fp->tx_buf_ring[TX_BD(pkt_prod)]; - tx_buf->first_bd = fp->tx_bd_prod; + pkt_prod = fp_tx->tx_pkt_prod++; + tx_buf = &fp_tx->tx_buf_ring[TX_BD(pkt_prod)]; + tx_buf->first_bd = fp_tx->tx_bd_prod; tx_buf->skb = skb; + tx_buf->flags = 0; - tx_bd = &fp->tx_desc_ring[TX_BD(fp->tx_bd_prod)]; + bd_prod = TX_BD(fp_tx->tx_bd_prod); + tx_start_bd = &fp_tx->tx_desc_ring[bd_prod].start_bd; mapping = pci_map_single(bp->pdev, skb->data, skb_headlen(skb), PCI_DMA_TODEVICE); - tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); - tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); - tx_bd->nbd = cpu_to_le16(1); - tx_bd->nbytes = cpu_to_le16(skb_headlen(skb)); - tx_bd->vlan = cpu_to_le16(pkt_prod); - tx_bd->bd_flags.as_bitfield = (ETH_TX_BD_FLAGS_START_BD | - ETH_TX_BD_FLAGS_END_BD); - tx_bd->general_data = ((UNICAST_ADDRESS << - ETH_TX_BD_ETH_ADDR_TYPE_SHIFT) | 1); + tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + tx_start_bd->nbd = cpu_to_le16(2); /* start + pbd */ + tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb)); + tx_start_bd->vlan = cpu_to_le16(pkt_prod); + tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD; + tx_start_bd->general_data = ((UNICAST_ADDRESS << + ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT) | 1); + + /* turn on parsing and get a BD */ + bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); + pbd = &fp_tx->tx_desc_ring[bd_prod].parse_bd; + + memset(pbd, 0, sizeof(struct eth_tx_parse_bd)); wmb(); - le16_add_cpu(&fp->hw_tx_prods->bds_prod, 1); - mb(); /* FW restriction: must not reorder writing nbd and packets */ - le32_add_cpu(&fp->hw_tx_prods->packets_prod, 1); - DOORBELL(bp, fp->index, 0); + fp_tx->tx_db.data.prod += 2; + barrier(); + DOORBELL(bp, fp_tx->index - bp->num_rx_queues, fp_tx->tx_db.raw); mmiowb(); num_pkts++; - fp->tx_bd_prod++; + fp_tx->tx_bd_prod += 2; /* start + pbd */ bp->dev->trans_start = jiffies; udelay(100); - tx_idx = le16_to_cpu(*fp->tx_cons_sb); + tx_idx = le16_to_cpu(*fp_tx->tx_cons_sb); if (tx_idx != tx_start_idx + num_pkts) goto test_loopback_exit; - rx_idx = le16_to_cpu(*fp->rx_cons_sb); + rx_idx = le16_to_cpu(*fp_rx->rx_cons_sb); if (rx_idx != rx_start_idx + num_pkts) goto test_loopback_exit; - cqe = &fp->rx_comp_ring[RCQ_BD(fp->rx_comp_cons)]; + cqe = &fp_rx->rx_comp_ring[RCQ_BD(fp_rx->rx_comp_cons)]; cqe_fp_flags = cqe->fast_path_cqe.type_error_flags; if (CQE_TYPE(cqe_fp_flags) || (cqe_fp_flags & ETH_RX_ERROR_FALGS)) goto test_loopback_rx_exit; @@ -9650,7 +9727,7 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up) if (len != pkt_size) goto test_loopback_rx_exit; - rx_buf = &fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)]; + rx_buf = &fp_rx->rx_buf_ring[RX_BD(fp_rx->rx_bd_cons)]; skb = rx_buf->skb; skb_reserve(skb, cqe->fast_path_cqe.placement_offset); for (i = ETH_HLEN; i < pkt_size; i++) @@ -9661,14 +9738,14 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up) test_loopback_rx_exit: - fp->rx_bd_cons = NEXT_RX_IDX(fp->rx_bd_cons); - fp->rx_bd_prod = NEXT_RX_IDX(fp->rx_bd_prod); - fp->rx_comp_cons = NEXT_RCQ_IDX(fp->rx_comp_cons); - fp->rx_comp_prod = NEXT_RCQ_IDX(fp->rx_comp_prod); + fp_rx->rx_bd_cons = NEXT_RX_IDX(fp_rx->rx_bd_cons); + fp_rx->rx_bd_prod = NEXT_RX_IDX(fp_rx->rx_bd_prod); + fp_rx->rx_comp_cons = NEXT_RCQ_IDX(fp_rx->rx_comp_cons); + fp_rx->rx_comp_prod = NEXT_RCQ_IDX(fp_rx->rx_comp_prod); /* Update producers */ - bnx2x_update_rx_prod(bp, fp, fp->rx_bd_prod, fp->rx_comp_prod, - fp->rx_sge_prod); + bnx2x_update_rx_prod(bp, fp_rx, fp_rx->rx_bd_prod, fp_rx->rx_comp_prod, + fp_rx->rx_sge_prod); test_loopback_exit: bp->link_params.loopback_mode = LOOPBACK_NONE; @@ -10001,7 +10078,7 @@ static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf) case ETH_SS_STATS: if (is_multi(bp)) { k = 0; - for_each_queue(bp, i) { + for_each_rx_queue(bp, i) { for (j = 0; j < BNX2X_NUM_Q_STATS; j++) sprintf(buf + (k + j)*ETH_GSTRING_LEN, bnx2x_q_stats_arr[j].string, i); @@ -10035,7 +10112,7 @@ static int bnx2x_get_stats_count(struct net_device *dev) int i, num_stats; if (is_multi(bp)) { - num_stats = BNX2X_NUM_Q_STATS * BNX2X_NUM_QUEUES(bp); + num_stats = BNX2X_NUM_Q_STATS * bp->num_rx_queues; if (!IS_E1HMF_MODE_STAT(bp)) num_stats += BNX2X_NUM_STATS; } else { @@ -10060,7 +10137,7 @@ static void bnx2x_get_ethtool_stats(struct net_device *dev, if (is_multi(bp)) { k = 0; - for_each_queue(bp, i) { + for_each_rx_queue(bp, i) { hw_stats = (u32 *)&bp->fp[i].eth_q_stats; for (j = 0; j < BNX2X_NUM_Q_STATS; j++) { if (bnx2x_q_stats_arr[j].size == 0) { @@ -10273,15 +10350,11 @@ static int bnx2x_poll(struct napi_struct *napi, int budget) goto poll_panic; #endif - prefetch(fp->tx_buf_ring[TX_BD(fp->tx_pkt_cons)].skb); prefetch(fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)].skb); prefetch((char *)(fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)].skb) + 256); bnx2x_update_fpsb_idx(fp); - if (bnx2x_has_tx_work(fp)) - bnx2x_tx_int(fp); - if (bnx2x_has_rx_work(fp)) { work_done = bnx2x_rx_int(fp, budget); @@ -10290,11 +10363,11 @@ static int bnx2x_poll(struct napi_struct *napi, int budget) goto poll_again; } - /* BNX2X_HAS_WORK() reads the status block, thus we need to + /* bnx2x_has_rx_work() reads the status block, thus we need to * ensure that status block indices have been actually read - * (bnx2x_update_fpsb_idx) prior to this check (BNX2X_HAS_WORK) + * (bnx2x_update_fpsb_idx) prior to this check (bnx2x_has_rx_work) * so that we won't write the "newer" value of the status block to IGU - * (if there was a DMA right after BNX2X_HAS_WORK and + * (if there was a DMA right after bnx2x_has_rx_work and * if there is no rmb, the memory reading (bnx2x_update_fpsb_idx) * may be postponed to right before bnx2x_ack_sb). In this case * there will never be another interrupt until there is another update @@ -10302,7 +10375,7 @@ static int bnx2x_poll(struct napi_struct *napi, int budget) */ rmb(); - if (!BNX2X_HAS_WORK(fp)) { + if (!bnx2x_has_rx_work(fp)) { #ifdef BNX2X_STOP_ON_ERROR poll_panic: #endif @@ -10327,10 +10400,11 @@ poll_again: */ static noinline u16 bnx2x_tx_split(struct bnx2x *bp, struct bnx2x_fastpath *fp, - struct eth_tx_bd **tx_bd, u16 hlen, + struct sw_tx_bd *tx_buf, + struct eth_tx_start_bd **tx_bd, u16 hlen, u16 bd_prod, int nbd) { - struct eth_tx_bd *h_tx_bd = *tx_bd; + struct eth_tx_start_bd *h_tx_bd = *tx_bd; struct eth_tx_bd *d_tx_bd; dma_addr_t mapping; int old_len = le16_to_cpu(h_tx_bd->nbytes); @@ -10346,7 +10420,7 @@ static noinline u16 bnx2x_tx_split(struct bnx2x *bp, /* now get a new data BD * (after the pbd) and fill it */ bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); - d_tx_bd = &fp->tx_desc_ring[bd_prod]; + d_tx_bd = &fp->tx_desc_ring[bd_prod].reg_bd; mapping = HILO_U64(le32_to_cpu(h_tx_bd->addr_hi), le32_to_cpu(h_tx_bd->addr_lo)) + hlen; @@ -10354,17 +10428,16 @@ static noinline u16 bnx2x_tx_split(struct bnx2x *bp, d_tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); d_tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); d_tx_bd->nbytes = cpu_to_le16(old_len - hlen); - d_tx_bd->vlan = 0; - /* this marks the BD as one that has no individual mapping - * the FW ignores this flag in a BD not marked start - */ - d_tx_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_SW_LSO; + + /* this marks the BD as one that has no individual mapping */ + tx_buf->flags |= BNX2X_TSO_SPLIT_BD; + DP(NETIF_MSG_TX_QUEUED, "TSO split data size is %d (%x:%x)\n", d_tx_bd->nbytes, d_tx_bd->addr_hi, d_tx_bd->addr_lo); - /* update tx_bd for marking the last BD flag */ - *tx_bd = d_tx_bd; + /* update tx_bd */ + *tx_bd = (struct eth_tx_start_bd *)d_tx_bd; return bd_prod; } @@ -10499,18 +10572,19 @@ exit_lbl: static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct bnx2x *bp = netdev_priv(dev); - struct bnx2x_fastpath *fp; + struct bnx2x_fastpath *fp, *fp_stat; struct netdev_queue *txq; struct sw_tx_bd *tx_buf; - struct eth_tx_bd *tx_bd; + struct eth_tx_start_bd *tx_start_bd; + struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL; struct eth_tx_parse_bd *pbd = NULL; u16 pkt_prod, bd_prod; int nbd, fp_index; dma_addr_t mapping; u32 xmit_type = bnx2x_xmit_type(bp, skb); - int vlan_off = (bp->e1hov ? 4 : 0); int i; u8 hlen = 0; + __le16 pkt_size = 0; #ifdef BNX2X_STOP_ON_ERROR if (unlikely(bp->panic)) @@ -10520,10 +10594,11 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) fp_index = skb_get_queue_mapping(skb); txq = netdev_get_tx_queue(dev, fp_index); - fp = &bp->fp[fp_index]; + fp = &bp->fp[fp_index + bp->num_rx_queues]; + fp_stat = &bp->fp[fp_index]; if (unlikely(bnx2x_tx_avail(fp) < (skb_shinfo(skb)->nr_frags + 3))) { - fp->eth_q_stats.driver_xoff++, + fp_stat->eth_q_stats.driver_xoff++; netif_tx_stop_queue(txq); BNX2X_ERR("BUG! Tx ring full when queue awake!\n"); return NETDEV_TX_BUSY; @@ -10552,7 +10627,7 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Please read carefully. First we use one BD which we mark as start, - then for TSO or xsum we have a parsing info BD, + then we have a parsing info BD (used for TSO or xsum), and only then we have the rest of the TSO BDs. (don't forget to mark the last one as last, and to unmap only AFTER you write to the BD ...) @@ -10564,42 +10639,40 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) /* get a tx_buf and first BD */ tx_buf = &fp->tx_buf_ring[TX_BD(pkt_prod)]; - tx_bd = &fp->tx_desc_ring[bd_prod]; + tx_start_bd = &fp->tx_desc_ring[bd_prod].start_bd; - tx_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD; - tx_bd->general_data = (UNICAST_ADDRESS << - ETH_TX_BD_ETH_ADDR_TYPE_SHIFT); + tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD; + tx_start_bd->general_data = (UNICAST_ADDRESS << + ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT); /* header nbd */ - tx_bd->general_data |= (1 << ETH_TX_BD_HDR_NBDS_SHIFT); + tx_start_bd->general_data |= (1 << ETH_TX_START_BD_HDR_NBDS_SHIFT); /* remember the first BD of the packet */ tx_buf->first_bd = fp->tx_bd_prod; tx_buf->skb = skb; + tx_buf->flags = 0; DP(NETIF_MSG_TX_QUEUED, "sending pkt %u @%p next_idx %u bd %u @%p\n", - pkt_prod, tx_buf, fp->tx_pkt_prod, bd_prod, tx_bd); + pkt_prod, tx_buf, fp->tx_pkt_prod, bd_prod, tx_start_bd); #ifdef BCM_VLAN if ((bp->vlgrp != NULL) && vlan_tx_tag_present(skb) && (bp->flags & HW_VLAN_TX_FLAG)) { - tx_bd->vlan = cpu_to_le16(vlan_tx_tag_get(skb)); - tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_VLAN_TAG; - vlan_off += 4; + tx_start_bd->vlan = cpu_to_le16(vlan_tx_tag_get(skb)); + tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_VLAN_TAG; } else #endif - tx_bd->vlan = cpu_to_le16(pkt_prod); + tx_start_bd->vlan = cpu_to_le16(pkt_prod); - if (xmit_type) { - /* turn on parsing and get a BD */ - bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); - pbd = (void *)&fp->tx_desc_ring[bd_prod]; + /* turn on parsing and get a BD */ + bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); + pbd = &fp->tx_desc_ring[bd_prod].parse_bd; - memset(pbd, 0, sizeof(struct eth_tx_parse_bd)); - } + memset(pbd, 0, sizeof(struct eth_tx_parse_bd)); if (xmit_type & XMIT_CSUM) { - hlen = (skb_network_header(skb) - skb->data + vlan_off) / 2; + hlen = (skb_network_header(skb) - skb->data) / 2; /* for now NS flag is not used in Linux */ pbd->global_data = @@ -10612,15 +10685,16 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) hlen += pbd->ip_hlen + tcp_hdrlen(skb) / 2; pbd->total_hlen = cpu_to_le16(hlen); - hlen = hlen*2 - vlan_off; + hlen = hlen*2; - tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_TCP_CSUM; + tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_L4_CSUM; if (xmit_type & XMIT_CSUM_V4) - tx_bd->bd_flags.as_bitfield |= + tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IP_CSUM; else - tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IPV6; + tx_start_bd->bd_flags.as_bitfield |= + ETH_TX_BD_FLAGS_IPV6; if (xmit_type & XMIT_CSUM_TCP) { pbd->tcp_pseudo_csum = swab16(tcp_hdr(skb)->check); @@ -10628,13 +10702,11 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) } else { s8 fix = SKB_CS_OFF(skb); /* signed! */ - pbd->global_data |= ETH_TX_PARSE_BD_CS_ANY_FLG; - pbd->cs_offset = fix / 2; + pbd->global_data |= ETH_TX_PARSE_BD_UDP_CS_FLG; DP(NETIF_MSG_TX_QUEUED, - "hlen %d offset %d fix %d csum before fix %x\n", - le16_to_cpu(pbd->total_hlen), pbd->cs_offset, fix, - SKB_CS(skb)); + "hlen %d fix %d csum before fix %x\n", + le16_to_cpu(pbd->total_hlen), fix, SKB_CS(skb)); /* HW bug: fixup the CSUM */ pbd->tcp_pseudo_csum = @@ -10649,17 +10721,18 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) mapping = pci_map_single(bp->pdev, skb->data, skb_headlen(skb), PCI_DMA_TODEVICE); - tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); - tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); - nbd = skb_shinfo(skb)->nr_frags + ((pbd == NULL) ? 1 : 2); - tx_bd->nbd = cpu_to_le16(nbd); - tx_bd->nbytes = cpu_to_le16(skb_headlen(skb)); + tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + nbd = skb_shinfo(skb)->nr_frags + 2; /* start_bd + pbd + frags */ + tx_start_bd->nbd = cpu_to_le16(nbd); + tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb)); + pkt_size = tx_start_bd->nbytes; DP(NETIF_MSG_TX_QUEUED, "first bd @%p addr (%x:%x) nbd %d" " nbytes %d flags %x vlan %x\n", - tx_bd, tx_bd->addr_hi, tx_bd->addr_lo, le16_to_cpu(tx_bd->nbd), - le16_to_cpu(tx_bd->nbytes), tx_bd->bd_flags.as_bitfield, - le16_to_cpu(tx_bd->vlan)); + tx_start_bd, tx_start_bd->addr_hi, tx_start_bd->addr_lo, + le16_to_cpu(tx_start_bd->nbd), le16_to_cpu(tx_start_bd->nbytes), + tx_start_bd->bd_flags.as_bitfield, le16_to_cpu(tx_start_bd->vlan)); if (xmit_type & XMIT_GSO) { @@ -10668,11 +10741,11 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) skb->len, hlen, skb_headlen(skb), skb_shinfo(skb)->gso_size); - tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_SW_LSO; + tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_SW_LSO; if (unlikely(skb_headlen(skb) > hlen)) - bd_prod = bnx2x_tx_split(bp, fp, &tx_bd, hlen, - bd_prod, ++nbd); + bd_prod = bnx2x_tx_split(bp, fp, tx_buf, &tx_start_bd, + hlen, bd_prod, ++nbd); pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size); pbd->tcp_send_seq = swab32(tcp_hdr(skb)->seq); @@ -10693,33 +10766,31 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) pbd->global_data |= ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN; } + tx_data_bd = (struct eth_tx_bd *)tx_start_bd; for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); - tx_bd = &fp->tx_desc_ring[bd_prod]; + tx_data_bd = &fp->tx_desc_ring[bd_prod].reg_bd; + if (total_pkt_bd == NULL) + total_pkt_bd = &fp->tx_desc_ring[bd_prod].reg_bd; mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset, frag->size, PCI_DMA_TODEVICE); - tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); - tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); - tx_bd->nbytes = cpu_to_le16(frag->size); - tx_bd->vlan = cpu_to_le16(pkt_prod); - tx_bd->bd_flags.as_bitfield = 0; + tx_data_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + tx_data_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + tx_data_bd->nbytes = cpu_to_le16(frag->size); + le16_add_cpu(&pkt_size, frag->size); DP(NETIF_MSG_TX_QUEUED, - "frag %d bd @%p addr (%x:%x) nbytes %d flags %x\n", - i, tx_bd, tx_bd->addr_hi, tx_bd->addr_lo, - le16_to_cpu(tx_bd->nbytes), tx_bd->bd_flags.as_bitfield); + "frag %d bd @%p addr (%x:%x) nbytes %d\n", + i, tx_data_bd, tx_data_bd->addr_hi, tx_data_bd->addr_lo, + le16_to_cpu(tx_data_bd->nbytes)); } - /* now at last mark the BD as the last BD */ - tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_END_BD; - - DP(NETIF_MSG_TX_QUEUED, "last bd @%p flags %x\n", - tx_bd, tx_bd->bd_flags.as_bitfield); + DP(NETIF_MSG_TX_QUEUED, "last bd @%p\n", tx_data_bd); bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); @@ -10729,6 +10800,9 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) if (TX_BD_POFF(bd_prod) < nbd) nbd++; + if (total_pkt_bd != NULL) + total_pkt_bd->total_pkt_bytes = pkt_size; + if (pbd) DP(NETIF_MSG_TX_QUEUED, "PBD @%p ip_data %x ip_hlen %u ip_id %u lso_mss %u" @@ -10748,25 +10822,24 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) */ wmb(); - le16_add_cpu(&fp->hw_tx_prods->bds_prod, nbd); - mb(); /* FW restriction: must not reorder writing nbd and packets */ - le32_add_cpu(&fp->hw_tx_prods->packets_prod, 1); - DOORBELL(bp, fp->index, 0); + fp->tx_db.data.prod += nbd; + barrier(); + DOORBELL(bp, fp->index - bp->num_rx_queues, fp->tx_db.raw); mmiowb(); fp->tx_bd_prod += nbd; if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) { + netif_tx_stop_queue(txq); /* We want bnx2x_tx_int to "see" the updated tx_bd_prod if we put Tx into XOFF state. */ smp_mb(); - netif_tx_stop_queue(txq); - fp->eth_q_stats.driver_xoff++; + fp_stat->eth_q_stats.driver_xoff++; if (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3) netif_tx_wake_queue(txq); } - fp->tx_pkt++; + fp_stat->tx_pkt++; return NETDEV_TX_OK; } @@ -10842,8 +10915,9 @@ static void bnx2x_set_rx_mode(struct net_device *dev) cpu_to_le16(port); config->config_table[i]. target_table_entry.flags = 0; - config->config_table[i]. - target_table_entry.client_id = 0; + config->config_table[i].target_table_entry. + clients_bit_vector = + cpu_to_le32(1 << BP_L_ID(bp)); config->config_table[i]. target_table_entry.vlan_id = 0; diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h index 8e9e7a24f2f..25639e2df52 100644 --- a/drivers/net/bnx2x_reg.h +++ b/drivers/net/bnx2x_reg.h @@ -370,7 +370,6 @@ #define CFC_REG_NUM_LCIDS_LEAVING 0x104018 /* [RW 8] The event id for aggregated interrupt 0 */ #define CSDM_REG_AGG_INT_EVENT_0 0xc2038 -#define CSDM_REG_AGG_INT_EVENT_1 0xc203c #define CSDM_REG_AGG_INT_EVENT_10 0xc2060 #define CSDM_REG_AGG_INT_EVENT_11 0xc2064 #define CSDM_REG_AGG_INT_EVENT_12 0xc2068 @@ -378,37 +377,27 @@ #define CSDM_REG_AGG_INT_EVENT_14 0xc2070 #define CSDM_REG_AGG_INT_EVENT_15 0xc2074 #define CSDM_REG_AGG_INT_EVENT_16 0xc2078 -#define CSDM_REG_AGG_INT_EVENT_17 0xc207c -#define CSDM_REG_AGG_INT_EVENT_18 0xc2080 -#define CSDM_REG_AGG_INT_EVENT_19 0xc2084 #define CSDM_REG_AGG_INT_EVENT_2 0xc2040 -#define CSDM_REG_AGG_INT_EVENT_20 0xc2088 -#define CSDM_REG_AGG_INT_EVENT_21 0xc208c -#define CSDM_REG_AGG_INT_EVENT_22 0xc2090 -#define CSDM_REG_AGG_INT_EVENT_23 0xc2094 -#define CSDM_REG_AGG_INT_EVENT_24 0xc2098 -#define CSDM_REG_AGG_INT_EVENT_25 0xc209c -#define CSDM_REG_AGG_INT_EVENT_26 0xc20a0 -#define CSDM_REG_AGG_INT_EVENT_27 0xc20a4 -#define CSDM_REG_AGG_INT_EVENT_28 0xc20a8 -#define CSDM_REG_AGG_INT_EVENT_29 0xc20ac #define CSDM_REG_AGG_INT_EVENT_3 0xc2044 -#define CSDM_REG_AGG_INT_EVENT_30 0xc20b0 -#define CSDM_REG_AGG_INT_EVENT_31 0xc20b4 #define CSDM_REG_AGG_INT_EVENT_4 0xc2048 -/* [RW 1] The T bit for aggregated interrupt 0 */ -#define CSDM_REG_AGG_INT_T_0 0xc20b8 -#define CSDM_REG_AGG_INT_T_1 0xc20bc -#define CSDM_REG_AGG_INT_T_10 0xc20e0 -#define CSDM_REG_AGG_INT_T_11 0xc20e4 -#define CSDM_REG_AGG_INT_T_12 0xc20e8 -#define CSDM_REG_AGG_INT_T_13 0xc20ec -#define CSDM_REG_AGG_INT_T_14 0xc20f0 -#define CSDM_REG_AGG_INT_T_15 0xc20f4 -#define CSDM_REG_AGG_INT_T_16 0xc20f8 -#define CSDM_REG_AGG_INT_T_17 0xc20fc -#define CSDM_REG_AGG_INT_T_18 0xc2100 -#define CSDM_REG_AGG_INT_T_19 0xc2104 +#define CSDM_REG_AGG_INT_EVENT_5 0xc204c +#define CSDM_REG_AGG_INT_EVENT_6 0xc2050 +#define CSDM_REG_AGG_INT_EVENT_7 0xc2054 +#define CSDM_REG_AGG_INT_EVENT_8 0xc2058 +#define CSDM_REG_AGG_INT_EVENT_9 0xc205c +/* [RW 1] For each aggregated interrupt index whether the mode is normal (0) + or auto-mask-mode (1) */ +#define CSDM_REG_AGG_INT_MODE_10 0xc21e0 +#define CSDM_REG_AGG_INT_MODE_11 0xc21e4 +#define CSDM_REG_AGG_INT_MODE_12 0xc21e8 +#define CSDM_REG_AGG_INT_MODE_13 0xc21ec +#define CSDM_REG_AGG_INT_MODE_14 0xc21f0 +#define CSDM_REG_AGG_INT_MODE_15 0xc21f4 +#define CSDM_REG_AGG_INT_MODE_16 0xc21f8 +#define CSDM_REG_AGG_INT_MODE_6 0xc21d0 +#define CSDM_REG_AGG_INT_MODE_7 0xc21d4 +#define CSDM_REG_AGG_INT_MODE_8 0xc21d8 +#define CSDM_REG_AGG_INT_MODE_9 0xc21dc /* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ #define CSDM_REG_CFC_RSP_START_ADDR 0xc2008 /* [RW 16] The maximum value of the competion counter #0 */ @@ -1421,6 +1410,8 @@ /* [RW 1] e1hmf for WOL. If clr WOL signal o the PXP will be send on bit 0 only. */ #define MISC_REG_E1HMF_MODE 0xa5f8 +/* [RW 32] Debug only: spare RW register reset by core reset */ +#define MISC_REG_GENERIC_CR_0 0xa460 /* [RW 32] GPIO. [31-28] FLOAT port 0; [27-24] FLOAT port 0; When any of these bits is written as a '1'; the corresponding SPIO bit will turn off it's drivers and become an input. This is the reset state of all GPIO @@ -1729,6 +1720,7 @@ /* [RW 3] for port0 enable for llfc ppp and pause. b0 - brb1 enable; b1- tsdm enable; b2- usdm enable */ #define NIG_REG_LLFC_EGRESS_SRC_ENABLE_0 0x16070 +#define NIG_REG_LLFC_EGRESS_SRC_ENABLE_1 0x16074 /* [RW 1] SAFC enable for port0. This register may get 1 only when ~ppp_enable.ppp_enable = 0 and pause_enable.pause_enable =0 for the same port */ @@ -2079,6 +2071,7 @@ #define PXP2_REG_PGL_ADDR_94_F0 0x120540 #define PXP2_REG_PGL_CONTROL0 0x120490 #define PXP2_REG_PGL_CONTROL1 0x120514 +#define PXP2_REG_PGL_DEBUG 0x120520 /* [RW 32] third dword data of expansion rom request. this register is special. reading from it provides a vector outstanding read requests. if a bit is zero it means that a read request on the corresponding tag did @@ -2238,6 +2231,9 @@ /* [RW 8] The maximum number of blocks in Tetris Buffer that can be allocated for vq22 */ #define PXP2_REG_RD_MAX_BLKS_VQ22 0x1203d0 +/* [RW 8] The maximum number of blocks in Tetris Buffer that can be + allocated for vq25 */ +#define PXP2_REG_RD_MAX_BLKS_VQ25 0x1203dc /* [RW 8] The maximum number of blocks in Tetris Buffer that can be allocated for vq6 */ #define PXP2_REG_RD_MAX_BLKS_VQ6 0x120390 @@ -3835,6 +3831,7 @@ #define TM_REG_LIN0_PHY_ADDR 0x164270 /* [RW 1] Linear0 physical address valid. */ #define TM_REG_LIN0_PHY_ADDR_VALID 0x164248 +#define TM_REG_LIN0_SCAN_ON 0x1640d0 /* [RW 24] Linear0 array scan timeout. */ #define TM_REG_LIN0_SCAN_TIME 0x16403c /* [RW 32] Linear1 logic address. */ @@ -4363,6 +4360,7 @@ #define USDM_REG_AGG_INT_EVENT_31 0xc40b4 #define USDM_REG_AGG_INT_EVENT_4 0xc4048 #define USDM_REG_AGG_INT_EVENT_5 0xc404c +#define USDM_REG_AGG_INT_EVENT_6 0xc4050 /* [RW 1] For each aggregated interrupt index whether the mode is normal (0) or auto-mask-mode (1) */ #define USDM_REG_AGG_INT_MODE_0 0xc41b8 @@ -4379,6 +4377,10 @@ #define USDM_REG_AGG_INT_MODE_19 0xc4204 #define USDM_REG_AGG_INT_MODE_4 0xc41c8 #define USDM_REG_AGG_INT_MODE_5 0xc41cc +#define USDM_REG_AGG_INT_MODE_6 0xc41d0 +/* [RW 1] The T bit for aggregated interrupt 5 */ +#define USDM_REG_AGG_INT_T_5 0xc40cc +#define USDM_REG_AGG_INT_T_6 0xc40d0 /* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ #define USDM_REG_CFC_RSP_START_ADDR 0xc4008 /* [RW 16] The maximum value of the competion counter #0 */ -- cgit v1.2.3-18-g5258 From 2691d51d7243560aa0870dadbf5c6b98f647f751 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:22:08 +0000 Subject: bnx2x: Supporting Device Control Channel In multi-function mode, the FW can receive special management control commands to set the Min/Max BW and the the function link state Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x.h | 6 + drivers/net/bnx2x_hsi.h | 34 ++++- drivers/net/bnx2x_main.c | 325 +++++++++++++++++++++++++++++++++-------------- 3 files changed, 268 insertions(+), 97 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 16ccba8dda1..5864ae2faab 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -128,6 +128,11 @@ #define SHMEM_RD(bp, field) REG_RD(bp, SHMEM_ADDR(bp, field)) #define SHMEM_WR(bp, field, val) REG_WR(bp, SHMEM_ADDR(bp, field), val) +#define SHMEM2_ADDR(bp, field) (bp->common.shmem2_base + \ + offsetof(struct shmem2_region, field)) +#define SHMEM2_RD(bp, field) REG_RD(bp, SHMEM2_ADDR(bp, field)) +#define SHMEM2_WR(bp, field, val) REG_WR(bp, SHMEM2_ADDR(bp, field), val) + #define EMAC_RD(bp, reg) REG_RD(bp, emac_base + reg) #define EMAC_WR(bp, reg, val) REG_WR(bp, emac_base + reg, val) @@ -535,6 +540,7 @@ struct bnx2x_common { #define NVRAM_PAGE_SIZE 256 u32 shmem_base; + u32 shmem2_base; u32 hw_config; diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x_hsi.h index da62cc5608d..8e2261fad48 100644 --- a/drivers/net/bnx2x_hsi.h +++ b/drivers/net/bnx2x_hsi.h @@ -658,6 +658,8 @@ struct drv_func_mb { #define DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS 0x20010000 #define DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP 0x20020000 #define DRV_MSG_CODE_UNLOAD_DONE 0x21000000 +#define DRV_MSG_CODE_DCC_OK 0x30000000 +#define DRV_MSG_CODE_DCC_FAILURE 0x31000000 #define DRV_MSG_CODE_DIAG_ENTER_REQ 0x50000000 #define DRV_MSG_CODE_DIAG_EXIT_REQ 0x60000000 #define DRV_MSG_CODE_VALIDATE_KEY 0x70000000 @@ -692,6 +694,7 @@ struct drv_func_mb { #define FW_MSG_CODE_DRV_UNLOAD_PORT 0x20110000 #define FW_MSG_CODE_DRV_UNLOAD_FUNCTION 0x20120000 #define FW_MSG_CODE_DRV_UNLOAD_DONE 0x21100000 +#define FW_MSG_CODE_DCC_DONE 0x30100000 #define FW_MSG_CODE_DIAG_ENTER_DONE 0x50100000 #define FW_MSG_CODE_DIAG_REFUSE 0x50200000 #define FW_MSG_CODE_DIAG_EXIT_DONE 0x60100000 @@ -742,6 +745,14 @@ struct drv_func_mb { u32 drv_status; #define DRV_STATUS_PMF 0x00000001 +#define DRV_STATUS_DCC_EVENT_MASK 0x0000ff00 +#define DRV_STATUS_DCC_DISABLE_ENABLE_PF 0x00000100 +#define DRV_STATUS_DCC_BANDWIDTH_ALLOCATION 0x00000200 +#define DRV_STATUS_DCC_CHANGE_MAC_ADDRESS 0x00000400 +#define DRV_STATUS_DCC_RESERVED1 0x00000800 +#define DRV_STATUS_DCC_SET_PROTOCOL 0x00001000 +#define DRV_STATUS_DCC_SET_PRIORITY 0x00002000 + u32 virt_mac_upper; #define VIRT_MAC_SIGN_MASK 0xffff0000 #define VIRT_MAC_SIGNATURE 0x564d0000 @@ -778,10 +789,9 @@ struct shared_mf_cfg { struct port_mf_cfg { u32 dynamic_cfg; /* device control channel */ -#define PORT_MF_CFG_OUTER_VLAN_TAG_MASK 0x0000ffff -#define PORT_MF_CFG_OUTER_VLAN_TAG_SHIFT 0 -#define PORT_MF_CFG_DYNAMIC_CFG_ENABLED 0x00010000 -#define PORT_MF_CFG_DYNAMIC_CFG_DEFAULT 0x00000000 +#define PORT_MF_CFG_E1HOV_TAG_MASK 0x0000ffff +#define PORT_MF_CFG_E1HOV_TAG_SHIFT 0 +#define PORT_MF_CFG_E1HOV_TAG_DEFAULT PORT_MF_CFG_E1HOV_TAG_MASK u32 reserved[3]; @@ -885,6 +895,22 @@ struct shmem_region { /* SharedMem Offset (size) */ }; /* 0x6dc */ +struct shmem2_region { + + u32 size; + + u32 dcc_support; +#define SHMEM_DCC_SUPPORT_NONE 0x00000000 +#define SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV 0x00000001 +#define SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV 0x00000004 +#define SHMEM_DCC_SUPPORT_CHANGE_MAC_ADDRESS_TLV 0x00000008 +#define SHMEM_DCC_SUPPORT_SET_PROTOCOL_TLV 0x00000040 +#define SHMEM_DCC_SUPPORT_SET_PRIORITY_TLV 0x00000080 +#define SHMEM_DCC_SUPPORT_DEFAULT SHMEM_DCC_SUPPORT_NONE + +}; + + struct emac_stats { u32 rx_stat_ifhcinoctets; u32 rx_stat_ifhcinbadoctets; diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 762f37a7d03..8abce3c182e 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -2104,6 +2104,12 @@ static void bnx2x_calc_fc_adv(struct bnx2x *bp) static void bnx2x_link_report(struct bnx2x *bp) { + if (bp->state == BNX2X_STATE_DISABLED) { + netif_carrier_off(bp->dev); + printk(KERN_ERR PFX "%s NIC Link is Down\n", bp->dev->name); + return; + } + if (bp->link_vars.link_up) { if (bp->state == BNX2X_STATE_OPEN) netif_carrier_on(bp->dev); @@ -2240,6 +2246,46 @@ static void bnx2x_init_port_minmax(struct bnx2x *bp) bp->cmng.fair_vars.fairness_timeout = fair_periodic_timeout_usec / 4; } +/* Calculates the sum of vn_min_rates. + It's needed for further normalizing of the min_rates. + Returns: + sum of vn_min_rates. + or + 0 - if all the min_rates are 0. + In the later case fainess algorithm should be deactivated. + If not all min_rates are zero then those that are zeroes will be set to 1. + */ +static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp) +{ + int all_zero = 1; + int port = BP_PORT(bp); + int vn; + + bp->vn_weight_sum = 0; + for (vn = VN_0; vn < E1HVN_MAX; vn++) { + int func = 2*vn + port; + u32 vn_cfg = SHMEM_RD(bp, mf_cfg.func_mf_config[func].config); + u32 vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >> + FUNC_MF_CFG_MIN_BW_SHIFT) * 100; + + /* Skip hidden vns */ + if (vn_cfg & FUNC_MF_CFG_FUNC_HIDE) + continue; + + /* If min rate is zero - set it to 1 */ + if (!vn_min_rate) + vn_min_rate = DEF_MIN_RATE; + else + all_zero = 0; + + bp->vn_weight_sum += vn_min_rate; + } + + /* ... only if all min rates are zeros - disable fairness */ + if (all_zero) + bp->vn_weight_sum = 0; +} + static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func) { struct rate_shaping_vars_per_vn m_rs_vn; @@ -2383,6 +2429,8 @@ static void bnx2x_link_attn(struct bnx2x *bp) static void bnx2x__link_status_update(struct bnx2x *bp) { + int func = BP_FUNC(bp); + if (bp->state != BNX2X_STATE_OPEN) return; @@ -2393,6 +2441,9 @@ static void bnx2x__link_status_update(struct bnx2x *bp) else bnx2x_stats_handle(bp, STATS_EVENT_STOP); + bp->mf_config = SHMEM_RD(bp, mf_cfg.func_mf_config[func].config); + bnx2x_calc_vn_weight_sum(bp); + /* indicate link status */ bnx2x_link_report(bp); } @@ -2421,6 +2472,152 @@ static void bnx2x_pmf_update(struct bnx2x *bp) * General service functions */ +/* send the MCP a request, block until there is a reply */ +u32 bnx2x_fw_command(struct bnx2x *bp, u32 command) +{ + int func = BP_FUNC(bp); + u32 seq = ++bp->fw_seq; + u32 rc = 0; + u32 cnt = 1; + u8 delay = CHIP_REV_IS_SLOW(bp) ? 100 : 10; + + SHMEM_WR(bp, func_mb[func].drv_mb_header, (command | seq)); + DP(BNX2X_MSG_MCP, "wrote command (%x) to FW MB\n", (command | seq)); + + do { + /* let the FW do it's magic ... */ + msleep(delay); + + rc = SHMEM_RD(bp, func_mb[func].fw_mb_header); + + /* Give the FW up to 2 second (200*10ms) */ + } while ((seq != (rc & FW_MSG_SEQ_NUMBER_MASK)) && (cnt++ < 200)); + + DP(BNX2X_MSG_MCP, "[after %d ms] read (%x) seq is (%x) from FW MB\n", + cnt*delay, rc, seq); + + /* is this a reply to our command? */ + if (seq == (rc & FW_MSG_SEQ_NUMBER_MASK)) + rc &= FW_MSG_CODE_MASK; + else { + /* FW BUG! */ + BNX2X_ERR("FW failed to respond!\n"); + bnx2x_fw_dump(bp); + rc = 0; + } + + return rc; +} + +static void bnx2x_set_storm_rx_mode(struct bnx2x *bp); +static void bnx2x_set_mac_addr_e1h(struct bnx2x *bp, int set); +static void bnx2x_set_rx_mode(struct net_device *dev); + +static void bnx2x_e1h_disable(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int i; + + bp->rx_mode = BNX2X_RX_MODE_NONE; + bnx2x_set_storm_rx_mode(bp); + + netif_tx_disable(bp->dev); + bp->dev->trans_start = jiffies; /* prevent tx timeout */ + + REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 0); + + bnx2x_set_mac_addr_e1h(bp, 0); + + for (i = 0; i < MC_HASH_SIZE; i++) + REG_WR(bp, MC_HASH_OFFSET(bp, i), 0); + + netif_carrier_off(bp->dev); +} + +static void bnx2x_e1h_enable(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + + REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1); + + bnx2x_set_mac_addr_e1h(bp, 1); + + /* Tx queue should be only reenabled */ + netif_tx_wake_all_queues(bp->dev); + + /* Initialize the receive filter. */ + bnx2x_set_rx_mode(bp->dev); +} + +static void bnx2x_update_min_max(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int vn, i; + + /* Init rate shaping and fairness contexts */ + bnx2x_init_port_minmax(bp); + + bnx2x_calc_vn_weight_sum(bp); + + for (vn = VN_0; vn < E1HVN_MAX; vn++) + bnx2x_init_vn_minmax(bp, 2*vn + port); + + if (bp->port.pmf) { + int func; + + /* Set the attention towards other drivers on the same port */ + for (vn = VN_0; vn < E1HVN_MAX; vn++) { + if (vn == BP_E1HVN(bp)) + continue; + + func = ((vn << 1) | port); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 + + (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1); + } + + /* Store it to internal memory */ + for (i = 0; i < sizeof(struct cmng_struct_per_port) / 4; i++) + REG_WR(bp, BAR_XSTRORM_INTMEM + + XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) + i*4, + ((u32 *)(&bp->cmng))[i]); + } +} + +static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event) +{ + int func = BP_FUNC(bp); + + DP(BNX2X_MSG_MCP, "dcc_event 0x%x\n", dcc_event); + bp->mf_config = SHMEM_RD(bp, mf_cfg.func_mf_config[func].config); + + if (dcc_event & DRV_STATUS_DCC_DISABLE_ENABLE_PF) { + + if (bp->mf_config & FUNC_MF_CFG_FUNC_DISABLED) { + DP(NETIF_MSG_IFDOWN, "mf_cfg function disabled\n"); + bp->state = BNX2X_STATE_DISABLED; + + bnx2x_e1h_disable(bp); + } else { + DP(NETIF_MSG_IFUP, "mf_cfg function enabled\n"); + bp->state = BNX2X_STATE_OPEN; + + bnx2x_e1h_enable(bp); + } + dcc_event &= ~DRV_STATUS_DCC_DISABLE_ENABLE_PF; + } + if (dcc_event & DRV_STATUS_DCC_BANDWIDTH_ALLOCATION) { + + bnx2x_update_min_max(bp); + dcc_event &= ~DRV_STATUS_DCC_BANDWIDTH_ALLOCATION; + } + + /* Report results to MCP */ + if (dcc_event) + bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_FAILURE); + else + bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_OK); +} + /* the slow path queue is odd since completions arrive on the fastpath ring */ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid, u32 data_hi, u32 data_lo, int common) @@ -2806,9 +3003,12 @@ static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn) int func = BP_FUNC(bp); REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_12 + func*4, 0); + val = SHMEM_RD(bp, func_mb[func].drv_status); + if (val & DRV_STATUS_DCC_EVENT_MASK) + bnx2x_dcc_event(bp, + (val & DRV_STATUS_DCC_EVENT_MASK)); bnx2x__link_status_update(bp); - if (SHMEM_RD(bp, func_mb[func].drv_status) & - DRV_STATUS_PMF) + if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF)) bnx2x_pmf_update(bp); } else if (attn & BNX2X_MC_ASSERT_BITS) { @@ -4968,47 +5168,6 @@ static void bnx2x_init_internal_port(struct bnx2x *bp) REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_HC_BTR_OFFSET(port), BNX2X_BTR); } -/* Calculates the sum of vn_min_rates. - It's needed for further normalizing of the min_rates. - Returns: - sum of vn_min_rates. - or - 0 - if all the min_rates are 0. - In the later case fainess algorithm should be deactivated. - If not all min_rates are zero then those that are zeroes will be set to 1. - */ -static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp) -{ - int all_zero = 1; - int port = BP_PORT(bp); - int vn; - - bp->vn_weight_sum = 0; - for (vn = VN_0; vn < E1HVN_MAX; vn++) { - int func = 2*vn + port; - u32 vn_cfg = - SHMEM_RD(bp, mf_cfg.func_mf_config[func].config); - u32 vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >> - FUNC_MF_CFG_MIN_BW_SHIFT) * 100; - - /* Skip hidden vns */ - if (vn_cfg & FUNC_MF_CFG_FUNC_HIDE) - continue; - - /* If min rate is zero - set it to 1 */ - if (!vn_min_rate) - vn_min_rate = DEF_MIN_RATE; - else - all_zero = 0; - - bp->vn_weight_sum += vn_min_rate; - } - - /* ... only if all min rates are zeros - disable fairness */ - if (all_zero) - bp->vn_weight_sum = 0; -} - static void bnx2x_init_internal_func(struct bnx2x *bp) { struct tstorm_eth_function_common_config tstorm_config = {0}; @@ -6272,44 +6431,6 @@ init_hw_err: return rc; } -/* send the MCP a request, block until there is a reply */ -u32 bnx2x_fw_command(struct bnx2x *bp, u32 command) -{ - int func = BP_FUNC(bp); - u32 seq = ++bp->fw_seq; - u32 rc = 0; - u32 cnt = 1; - u8 delay = CHIP_REV_IS_SLOW(bp) ? 100 : 10; - - SHMEM_WR(bp, func_mb[func].drv_mb_header, (command | seq)); - DP(BNX2X_MSG_MCP, "wrote command (%x) to FW MB\n", (command | seq)); - - do { - /* let the FW do it's magic ... */ - msleep(delay); - - rc = SHMEM_RD(bp, func_mb[func].fw_mb_header); - - /* Give the FW up to 2 second (200*10ms) */ - } while ((seq != (rc & FW_MSG_SEQ_NUMBER_MASK)) && (cnt++ < 200)); - - DP(BNX2X_MSG_MCP, "[after %d ms] read (%x) seq is (%x) from FW MB\n", - cnt*delay, rc, seq); - - /* is this a reply to our command? */ - if (seq == (rc & FW_MSG_SEQ_NUMBER_MASK)) { - rc &= FW_MSG_CODE_MASK; - - } else { - /* FW BUG! */ - BNX2X_ERR("FW failed to respond!\n"); - bnx2x_fw_dump(bp); - rc = 0; - } - - return rc; -} - static void bnx2x_free_mem(struct bnx2x *bp) { @@ -6996,7 +7117,6 @@ static int bnx2x_set_int_mode(struct bnx2x *bp) return rc; } -static void bnx2x_set_rx_mode(struct net_device *dev); /* must be called with rtnl_lock */ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode) @@ -7103,6 +7223,12 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode) /* Setup NIC internals and enable interrupts */ bnx2x_nic_init(bp, load_code); + if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) && + (bp->common.shmem2_base)) + SHMEM2_WR(bp, dcc_support, + (SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV | + SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV)); + /* Send LOAD_DONE command to MCP */ if (!BP_NOMCP(bp)) { load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE); @@ -7735,8 +7861,10 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp) bp->common.flash_size, bp->common.flash_size); bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR); + bp->common.shmem2_base = REG_RD(bp, MISC_REG_GENERIC_CR_0); bp->link_params.shmem_base = bp->common.shmem_base; - BNX2X_DEV_INFO("shmem offset is 0x%x\n", bp->common.shmem_base); + BNX2X_DEV_INFO("shmem offset 0x%x shmem2 offset 0x%x\n", + bp->common.shmem_base, bp->common.shmem2_base); if (!bp->common.shmem_base || (bp->common.shmem_base < 0xA0000) || @@ -8290,22 +8418,33 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) bp->mf_config = SHMEM_RD(bp, mf_cfg.func_mf_config[func].config); - val = (SHMEM_RD(bp, mf_cfg.func_mf_config[func].e1hov_tag) & + val = (SHMEM_RD(bp, mf_cfg.func_mf_config[FUNC_0].e1hov_tag) & FUNC_MF_CFG_E1HOV_TAG_MASK); - if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) { - - bp->e1hov = val; + if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) bp->e1hmf = 1; - BNX2X_DEV_INFO("MF mode E1HOV for func %d is %d " - "(0x%04x)\n", - func, bp->e1hov, bp->e1hov); - } else { - BNX2X_DEV_INFO("single function mode\n"); - if (BP_E1HVN(bp)) { + BNX2X_DEV_INFO("%s function mode\n", + IS_E1HMF(bp) ? "multi" : "single"); + + if (IS_E1HMF(bp)) { + val = (SHMEM_RD(bp, mf_cfg.func_mf_config[func]. + e1hov_tag) & + FUNC_MF_CFG_E1HOV_TAG_MASK); + if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) { + bp->e1hov = val; + BNX2X_DEV_INFO("E1HOV for func %d is %d " + "(0x%04x)\n", + func, bp->e1hov, bp->e1hov); + } else { BNX2X_ERR("!!! No valid E1HOV for func %d," " aborting\n", func); rc = -EPERM; } + } else { + if (BP_E1HVN(bp)) { + BNX2X_ERR("!!! VN %d in single function mode," + " aborting\n", BP_E1HVN(bp)); + rc = -EPERM; + } } } -- cgit v1.2.3-18-g5258 From 0c593270432035b7b9ba27ee7dd4f32f6feea2e0 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:22:13 +0000 Subject: bnx2x: Advertize flow control normally in MF mode Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 8abce3c182e..a695e7f0647 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -2149,9 +2149,7 @@ static u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode) /* Initialize link parameters structure variables */ /* It is recommended to turn off RX FC for jumbo frames for better performance */ - if (IS_E1HMF(bp)) - bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_BOTH; - else if (bp->dev->mtu > 5000) + if (bp->dev->mtu > 5000) bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_TX; else bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_BOTH; -- cgit v1.2.3-18-g5258 From 2f9044603c8b9ead9eb4d88e360093b44d362b58 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:22:16 +0000 Subject: bnx2x: BCM8481 LED4 instead of LASI The BCM8481 does not generate LASI interrupt for 10M, 100M and 1G link, so we are using LED4 output as the interrupt input to the 57711. This requires some adaptation in the link interrupt routines Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_link.c | 498 +++++++++++++++++++++++++++++++++++++++++------ drivers/net/bnx2x_reg.h | 32 +++ 2 files changed, 468 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index 1f17334c8f0..9e1f19a00ab 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -37,6 +37,10 @@ /* Shortcut definitions */ /***********************************************************/ +#define NIG_LATCH_BC_ENABLE_MI_INT 0 + +#define NIG_STATUS_EMAC0_MI_INT \ + NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_EMAC0_MISC_MI_INT #define NIG_STATUS_XGXS0_LINK10G \ NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G #define NIG_STATUS_XGXS0_LINK_STATUS \ @@ -1589,8 +1593,9 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params, static u8 bnx2x_link_settings_status(struct link_params *params, - struct link_vars *vars, - u32 gp_status) + struct link_vars *vars, + u32 gp_status, + u8 ext_phy_link_up) { struct bnx2x *bp = params->bp; u16 new_line_speed; @@ -1696,6 +1701,16 @@ static u8 bnx2x_link_settings_status(struct link_params *params, Comes to deals with possible FIFO glitch due to clk change when speed is decreased without link down indicator */ if (new_line_speed != vars->line_speed) { + if (XGXS_EXT_PHY_TYPE(params->ext_phy_config) != + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT && + ext_phy_link_up) { + DP(NETIF_MSG_LINK, "Internal link speed %d is" + " different than the external" + " link speed %d\n", new_line_speed, + vars->line_speed); + vars->phy_link_up = 0; + return 0; + } REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); msleep(1); @@ -1709,9 +1724,7 @@ static u8 bnx2x_link_settings_status(struct link_params *params, (XGXS_EXT_PHY_TYPE(params->ext_phy_config) == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) || (XGXS_EXT_PHY_TYPE(params->ext_phy_config) == - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) || - (XGXS_EXT_PHY_TYPE(params->ext_phy_config) == - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481))) { + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726))) { vars->autoneg = AUTO_NEG_ENABLED; if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) { @@ -3182,6 +3195,130 @@ static void bnx2x_set_preemphasis(struct link_params *params) } } + +static void bnx2x_8481_set_led4(struct link_params *params, + u32 ext_phy_type, u8 ext_phy_addr) +{ + struct bnx2x *bp = params->bp; + + /* PHYC_CTL_LED_CTL */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, 0xa482); + + /* Unmask LED4 for 10G link */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_SIGNAL_MASK, (1<<6)); + /* 'Interrupt Mask' */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + 0xFFFB, 0xFFFD); +} +static void bnx2x_8481_set_legacy_led_mode(struct link_params *params, + u32 ext_phy_type, u8 ext_phy_addr) +{ + struct bnx2x *bp = params->bp; + + /* LED1 (10G Link): Disable LED1 when 10/100/1000 link */ + /* LED2 (1G/100/10 Link): Enable LED2 when 10/100/1000 link) */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_SHADOW, + (1<<15) | (0xd << 10) | (0xc<<4) | 0xe); +} + +static void bnx2x_8481_set_10G_led_mode(struct link_params *params, + u32 ext_phy_type, u8 ext_phy_addr) +{ + struct bnx2x *bp = params->bp; + u16 val1; + + /* LED1 (10G Link) */ + /* Enable continuse based on source 7(10G-link) */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, + &val1); + /* Set bit 2 to 0, and bits [1:0] to 10 */ + val1 &= ~((1<<0) | (1<<2)); /* Clear bits 0,2*/ + val1 |= (1<<1); /* Set bit 1 */ + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, + val1); + + /* Unmask LED1 for 10G link */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED1_MASK, + &val1); + /* Set bit 2 to 0, and bits [1:0] to 10 */ + val1 |= (1<<7); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED1_MASK, + val1); + + /* LED2 (1G/100/10G Link) */ + /* Mask LED2 for 10G link */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED2_MASK, + 0); + + /* LED3 (10G/1G/100/10G Activity) */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, + &val1); + /* Enable blink based on source 4(Activity) */ + val1 &= ~((1<<7) | (1<<8)); /* Clear bits 7,8 */ + val1 |= (1<<6); /* Set only bit 6 */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, + val1); + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED3_MASK, + &val1); + val1 |= (1<<4); /* Unmask LED3 for 10G link */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED3_MASK, + val1); +} + + static void bnx2x_init_internal_phy(struct link_params *params, struct link_vars *vars) { @@ -3947,16 +4084,109 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) break; } case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481: - DP(NETIF_MSG_LINK, - "Setting the BCM8481 LASI control\n"); + /* This phy uses the NIG latch mechanism since link + indication arrives through its LED4 and not via + its LASI signal, so we get steady signal + instead of clear on read */ + bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4, + 1 << NIG_LATCH_BC_ENABLE_MI_INT); + + bnx2x_8481_set_led4(params, ext_phy_type, ext_phy_addr); + if (params->req_line_speed == SPEED_AUTO_NEG) { + + u16 autoneg_val, an_1000_val, an_10_100_val; + /* set 1000 speed advertisement */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_1000T_CTRL, + &an_1000_val); - bnx2x_cl45_write(bp, params->port, - ext_phy_type, - ext_phy_addr, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_LASI_CTRL, 0x1); + if (params->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) { + an_1000_val |= (1<<8); + if (params->req_duplex == DUPLEX_FULL) + an_1000_val |= (1<<9); + DP(NETIF_MSG_LINK, "Advertising 1G\n"); + } else + an_1000_val &= ~((1<<8) | (1<<9)); - /* Restart autoneg */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_1000T_CTRL, + an_1000_val); + + /* set 100 speed advertisement */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_AN_ADV, + &an_10_100_val); + + if (params->speed_cap_mask & + (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL | + PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)) { + an_10_100_val |= (1<<7); + if (params->req_duplex == DUPLEX_FULL) + an_10_100_val |= (1<<8); + DP(NETIF_MSG_LINK, + "Advertising 100M\n"); + } else + an_10_100_val &= ~((1<<7) | (1<<8)); + + /* set 10 speed advertisement */ + if (params->speed_cap_mask & + (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL | + PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)) { + an_10_100_val |= (1<<5); + if (params->req_duplex == DUPLEX_FULL) + an_10_100_val |= (1<<6); + DP(NETIF_MSG_LINK, "Advertising 10M\n"); + } + else + an_10_100_val &= ~((1<<5) | (1<<6)); + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_AN_ADV, + an_10_100_val); + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_MII_CTRL, + &autoneg_val); + + /* Disable forced speed */ + autoneg_val &= ~(1<<6|1<<13); + + /* Enable autoneg and restart autoneg + for legacy speeds */ + autoneg_val |= (1<<9|1<<12); + + if (params->req_duplex == DUPLEX_FULL) + autoneg_val |= (1<<8); + else + autoneg_val &= ~(1<<8); + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_MII_CTRL, + autoneg_val); + + if (params->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) { + DP(NETIF_MSG_LINK, "Advertising 10G\n"); + /* Restart autoneg for 10G*/ bnx2x_cl45_read(bp, params->port, ext_phy_type, ext_phy_addr, @@ -3968,6 +4198,76 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) ext_phy_addr, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, val); + } + } else { + /* Force speed */ + u16 autoneg_ctrl, pma_ctrl; + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_MII_CTRL, + &autoneg_ctrl); + + /* Disable autoneg */ + autoneg_ctrl &= ~(1<<12); + + /* Set 1000 force */ + switch (params->req_line_speed) { + case SPEED_10000: + DP(NETIF_MSG_LINK, + "Unable to set 10G force !\n"); + break; + case SPEED_1000: + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, + &pma_ctrl); + autoneg_ctrl &= ~(1<<13); + autoneg_ctrl |= (1<<6); + pma_ctrl &= ~(1<<13); + pma_ctrl |= (1<<6); + DP(NETIF_MSG_LINK, + "Setting 1000M force\n"); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, + pma_ctrl); + break; + case SPEED_100: + autoneg_ctrl |= (1<<13); + autoneg_ctrl &= ~(1<<6); + DP(NETIF_MSG_LINK, + "Setting 100M force\n"); + break; + case SPEED_10: + autoneg_ctrl &= ~(1<<13); + autoneg_ctrl &= ~(1<<6); + DP(NETIF_MSG_LINK, + "Setting 10M force\n"); + break; + } + + /* Duplex mode */ + if (params->req_duplex == DUPLEX_FULL) { + autoneg_ctrl |= (1<<8); + DP(NETIF_MSG_LINK, + "Setting full duplex\n"); + } else + autoneg_ctrl &= ~(1<<8); + + /* Update autoneg ctrl and pma ctrl */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_MII_CTRL, + autoneg_ctrl); + } bnx2x_save_bcm_spirom_ver(bp, params->port, ext_phy_type, @@ -4104,7 +4404,8 @@ static void bnx2x_8727_handle_mod_abs(struct link_params *params) static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, - struct link_vars *vars) + struct link_vars *vars, + u8 is_mi_int) { struct bnx2x *bp = params->bp; u32 ext_phy_type; @@ -4647,48 +4948,77 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, } break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481: - /* Clear LASI interrupt */ - bnx2x_cl45_read(bp, params->port, - ext_phy_type, - ext_phy_addr, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_LASI_STATUS, &val1); - DP(NETIF_MSG_LINK, "8481 LASI status reg = 0x%x\n", - val1); - /* Check 10G-BaseT link status */ - /* Check Global PMD signal ok */ + /* Check PMD signal ok */ bnx2x_cl45_read(bp, params->port, ext_phy_type, - ext_phy_addr, - MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, - &rx_sd); - /* Check PCS block lock */ + ext_phy_addr, + MDIO_AN_DEVAD, + 0xFFFA, + &val1); bnx2x_cl45_read(bp, params->port, ext_phy_type, ext_phy_addr, - MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, - &pcs_status); - DP(NETIF_MSG_LINK, "8481 1.a = 0x%x, 1.20 = 0x%x\n", - rx_sd, pcs_status); - if (rx_sd & pcs_status & 0x1) { + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_PMD_SIGNAL, + &val2); + DP(NETIF_MSG_LINK, "PMD_SIGNAL 1.a811 = 0x%x\n", val2); + + /* Check link 10G */ + if (val2 & (1<<11)) { vars->line_speed = SPEED_10000; ext_phy_link_up = 1; - } else { - - /* Check 1000-BaseT link status */ - bnx2x_cl45_read(bp, params->port, ext_phy_type, - ext_phy_addr, - MDIO_AN_DEVAD, 0xFFE1, - &val1); + bnx2x_8481_set_10G_led_mode(params, + ext_phy_type, + ext_phy_addr); + } else { /* Check Legacy speed link */ + u16 legacy_status, legacy_speed; + + /* Enable expansion register 0x42 + (Operation mode status) */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, + 0xf42); - bnx2x_cl45_read(bp, params->port, ext_phy_type, - ext_phy_addr, - MDIO_AN_DEVAD, 0xFFE1, - &val2); - DP(NETIF_MSG_LINK, "8481 7.FFE1 =" - "0x%x-->0x%x\n", val1, val2); - if (val2 & (1<<2)) { - vars->line_speed = SPEED_1000; - ext_phy_link_up = 1; + /* Get legacy speed operation status */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_EXPANSION_REG_RD_RW, + &legacy_status); + + DP(NETIF_MSG_LINK, "Legacy speed status" + " = 0x%x\n", legacy_status); + ext_phy_link_up = ((legacy_status & (1<<11)) + == (1<<11)); + if (ext_phy_link_up) { + legacy_speed = (legacy_status & (3<<9)); + if (legacy_speed == (0<<9)) + vars->line_speed = SPEED_10; + else if (legacy_speed == (1<<9)) + vars->line_speed = + SPEED_100; + else if (legacy_speed == (2<<9)) + vars->line_speed = + SPEED_1000; + else /* Should not happen */ + vars->line_speed = 0; + + if (legacy_status & (1<<8)) + vars->duplex = DUPLEX_FULL; + else + vars->duplex = DUPLEX_HALF; + + DP(NETIF_MSG_LINK, "Link is up " + "in %dMbps, is_duplex_full" + "= %d\n", + vars->line_speed, + (vars->duplex == DUPLEX_FULL)); + bnx2x_8481_set_legacy_led_mode(params, + ext_phy_type, + ext_phy_addr); } } @@ -4775,12 +5105,47 @@ static void bnx2x_link_int_enable(struct link_params *params) REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68)); } - +static void bnx2x_8481_rearm_latch_signal(struct bnx2x *bp, u8 port, + u8 is_mi_int) +{ + u32 latch_status = 0, is_mi_int_status; + /* Disable the MI INT ( external phy int ) + * by writing 1 to the status register. Link down indication + * is high-active-signal, so in this case we need to write the + * status to clear the XOR + */ + /* Read Latched signals */ + latch_status = REG_RD(bp, + NIG_REG_LATCH_STATUS_0 + port*8); + is_mi_int_status = REG_RD(bp, + NIG_REG_STATUS_INTERRUPT_PORT0 + port*4); + DP(NETIF_MSG_LINK, "original_signal = 0x%x, nig_status = 0x%x," + "latch_status = 0x%x\n", + is_mi_int, is_mi_int_status, latch_status); + /* Handle only those with latched-signal=up.*/ + if (latch_status & 1) { + /* For all latched-signal=up,Write original_signal to status */ + if (is_mi_int) + bnx2x_bits_en(bp, + NIG_REG_STATUS_INTERRUPT_PORT0 + + port*4, + NIG_STATUS_EMAC0_MI_INT); + else + bnx2x_bits_dis(bp, + NIG_REG_STATUS_INTERRUPT_PORT0 + + port*4, + NIG_STATUS_EMAC0_MI_INT); + /* For all latched-signal=up : Re-Arm Latch signals */ + REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8, + (latch_status & 0xfffe) | (latch_status & 1)); + } +} /* * link management */ static void bnx2x_link_int_ack(struct link_params *params, - struct link_vars *vars, u8 is_10g) + struct link_vars *vars, u8 is_10g, + u8 is_mi_int) { struct bnx2x *bp = params->bp; u8 port = params->port; @@ -4791,6 +5156,10 @@ static void bnx2x_link_int_ack(struct link_params *params, (NIG_STATUS_XGXS0_LINK10G | NIG_STATUS_XGXS0_LINK_STATUS | NIG_STATUS_SERDES0_LINK_STATUS)); + if (XGXS_EXT_PHY_TYPE(params->ext_phy_config) + == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481) { + bnx2x_8481_rearm_latch_signal(bp, port, is_mi_int); + } if (vars->phy_link_up) { if (is_10g) { /* Disable the 10G link interrupt @@ -4810,7 +5179,8 @@ static void bnx2x_link_int_ack(struct link_params *params, PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); - DP(NETIF_MSG_LINK, "1G XGXS phy link up\n"); + DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n", + vars->line_speed); bnx2x_bits_en(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, ((1 << ser_lane) << @@ -5270,7 +5640,7 @@ u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars) &gp_status); /* link is up only if both local phy and external phy are up */ if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) && - bnx2x_ext_phy_is_link_up(params, vars)) + bnx2x_ext_phy_is_link_up(params, vars, 1)) return 0; return -ESRCH; @@ -5758,16 +6128,19 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) u8 link_10g; u8 ext_phy_link_up, rc = 0; u32 ext_phy_type; + u8 is_mi_int = 0; DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n", - port, - (vars->phy_flags & PHY_XGXS_FLAG), - REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4)); + port, (vars->phy_flags & PHY_XGXS_FLAG), + REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4)); + is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + + port*0x18) > 0); DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n", - REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4), - REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18), - REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c)); + REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4), + is_mi_int, + REG_RD(bp, + NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c)); DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n", REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68), @@ -5779,7 +6152,7 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* Check external link change only for non-direct */ - ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars); + ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars, is_mi_int); /* Read gp_status */ CL45_RD_OVER_CL22(bp, port, params->phy_addr, @@ -5787,7 +6160,8 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) MDIO_GP_STATUS_TOP_AN_STATUS1, &gp_status); - rc = bnx2x_link_settings_status(params, vars, gp_status); + rc = bnx2x_link_settings_status(params, vars, gp_status, + ext_phy_link_up); if (rc != 0) return rc; @@ -5799,7 +6173,7 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) (vars->line_speed == SPEED_15000) || (vars->line_speed == SPEED_16000)); - bnx2x_link_int_ack(params, vars, link_10g); + bnx2x_link_int_ack(params, vars, link_10g, is_mi_int); /* In case external phy link is up, and internal link is down ( not initialized yet probably after link initialization, it needs diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h index 25639e2df52..9a20da5bf19 100644 --- a/drivers/net/bnx2x_reg.h +++ b/drivers/net/bnx2x_reg.h @@ -1681,6 +1681,24 @@ /* [RW 17] Debug only. RX_EOP_DSCR_lb_FIFO in NIG_RX_EOP. Data packet_length[13:0]; mac_error[14]; trunc_error[15]; parity[16] */ #define NIG_REG_INGRESS_EOP_LB_FIFO 0x104e4 +/* [RW 27] 0 - must be active for Everest A0; 1- for Everest B0 when latch + logic for interrupts must be used. Enable per bit of interrupt of + ~latch_status.latch_status */ +#define NIG_REG_LATCH_BC_0 0x16210 +/* [RW 27] Latch for each interrupt from Unicore.b[0] + status_emac0_misc_mi_int; b[1] status_emac0_misc_mi_complete; + b[2]status_emac0_misc_cfg_change; b[3]status_emac0_misc_link_status; + b[4]status_emac0_misc_link_change; b[5]status_emac0_misc_attn; + b[6]status_serdes0_mac_crs; b[7]status_serdes0_autoneg_complete; + b[8]status_serdes0_fiber_rxact; b[9]status_serdes0_link_status; + b[10]status_serdes0_mr_page_rx; b[11]status_serdes0_cl73_an_complete; + b[12]status_serdes0_cl73_mr_page_rx; b[13]status_serdes0_rx_sigdet; + b[14]status_xgxs0_remotemdioreq; b[15]status_xgxs0_link10g; + b[16]status_xgxs0_autoneg_complete; b[17]status_xgxs0_fiber_rxact; + b[21:18]status_xgxs0_link_status; b[22]status_xgxs0_mr_page_rx; + b[23]status_xgxs0_cl73_an_complete; b[24]status_xgxs0_cl73_mr_page_rx; + b[25]status_xgxs0_rx_sigdet; b[26]status_xgxs0_mac_crs */ +#define NIG_REG_LATCH_STATUS_0 0x18000 /* [RW 1] led 10g for port 0 */ #define NIG_REG_LED_10G_P0 0x10320 /* [RW 1] led 10g for port 1 */ @@ -1871,6 +1889,7 @@ #define NIG_REG_XGXS_LANE_SEL_P0 0x102e8 /* [RW 1] selection for port0 for NIG_MUX block : 0 = SerDes; 1 = XGXS */ #define NIG_REG_XGXS_SERDES0_MODE_SEL 0x102e0 +#define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_EMAC0_MISC_MI_INT (0x1<<0) #define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS (0x1<<9) #define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G (0x1<<15) #define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS (0xf<<18) @@ -5889,6 +5908,13 @@ Theotherbitsarereservedandshouldbezero*/ #define MDIO_PMA_REG_7101_VER1 0xc026 #define MDIO_PMA_REG_7101_VER2 0xc027 +#define MDIO_PMA_REG_8481_PMD_SIGNAL 0xa811 +#define MDIO_PMA_REG_8481_LED1_MASK 0xa82c +#define MDIO_PMA_REG_8481_LED2_MASK 0xa82f +#define MDIO_PMA_REG_8481_LED3_MASK 0xa832 +#define MDIO_PMA_REG_8481_SIGNAL_MASK 0xa835 +#define MDIO_PMA_REG_8481_LINK_SIGNAL 0xa83b + #define MDIO_WIS_DEVAD 0x2 /*bcm*/ @@ -5942,6 +5968,12 @@ Theotherbitsarereservedandshouldbezero*/ #define MDIO_AN_REG_8073_2_5G 0x8329 +#define MDIO_AN_REG_8481_LEGACY_MII_CTRL 0xffe0 +#define MDIO_AN_REG_8481_LEGACY_AN_ADV 0xffe4 +#define MDIO_AN_REG_8481_1000T_CTRL 0xffe9 +#define MDIO_AN_REG_8481_EXPANSION_REG_RD_RW 0xfff5 +#define MDIO_AN_REG_8481_EXPANSION_REG_ACCESS 0xfff7 +#define MDIO_AN_REG_8481_LEGACY_SHADOW 0xfffc #define IGU_FUNC_BASE 0x0400 -- cgit v1.2.3-18-g5258 From b1607af526fd408b244c7b32a0c256c1ef163a17 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:22:54 +0000 Subject: bnx2x: Reading the FW version of the BCM8481 PHY Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_link.c | 118 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index 9e1f19a00ab..c9252498d51 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -2046,6 +2046,111 @@ static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp, u8 port, (u32)(fw_ver1<<16 | fw_ver2)); } + +static void bnx2x_save_8481_spirom_version(struct bnx2x *bp, u8 port, + u8 ext_phy_addr, u32 shmem_base) +{ + u16 val, fw_ver1, fw_ver2, cnt; + /* For the 32 bits registers in 8481, access via MDIO2ARM interface.*/ + /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, MDIO_PMA_DEVAD, + 0xA819, 0x0014); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA81A, + 0xc200); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA81B, + 0x0000); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA81C, + 0x0300); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA817, + 0x0009); + + for (cnt = 0; cnt < 100; cnt++) { + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA818, + &val); + if (val & 1) + break; + udelay(5); + } + if (cnt == 100) { + DP(NETIF_MSG_LINK, "Unable to read 8481 phy fw version(1)\n"); + bnx2x_save_spirom_version(bp, port, + shmem_base, 0); + return; + } + + + /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, MDIO_PMA_DEVAD, + 0xA819, 0x0000); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, MDIO_PMA_DEVAD, + 0xA81A, 0xc200); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, MDIO_PMA_DEVAD, + 0xA817, 0x000A); + for (cnt = 0; cnt < 100; cnt++) { + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA818, + &val); + if (val & 1) + break; + udelay(5); + } + if (cnt == 100) { + DP(NETIF_MSG_LINK, "Unable to read 8481 phy fw version(2)\n"); + bnx2x_save_spirom_version(bp, port, + shmem_base, 0); + return; + } + + /* lower 16 bits of the register SPI_FW_STATUS */ + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA81B, + &fw_ver1); + /* upper 16 bits of register SPI_FW_STATUS */ + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA81C, + &fw_ver2); + + bnx2x_save_spirom_version(bp, port, + shmem_base, (fw_ver2<<16) | fw_ver1); +} + static void bnx2x_bcm8072_external_rom_boot(struct link_params *params) { struct bnx2x *bp = params->bp; @@ -4269,11 +4374,10 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) autoneg_ctrl); } - bnx2x_save_bcm_spirom_ver(bp, params->port, - ext_phy_type, - ext_phy_addr, - params->shmem_base); - + /* Save spirom version */ + bnx2x_save_8481_spirom_version(bp, params->port, + ext_phy_addr, + params->shmem_base); break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE: DP(NETIF_MSG_LINK, @@ -5320,7 +5424,11 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: + status = bnx2x_format_ver(spirom_ver, version, len); + break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481: + spirom_ver = ((spirom_ver & 0xF80) >> 7) << 16 | + (spirom_ver & 0x7F); status = bnx2x_format_ver(spirom_ver, version, len); break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: -- cgit v1.2.3-18-g5258 From 97b41dad385bce97d60b8cdd56342f07f93fc5d2 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:22:59 +0000 Subject: bnx2x: get_ext_phy_fw_version returns NULL if not applicable To avoid confusion, if the PHY does not have a FW (and so, no FW version) make sure that the string is NULL. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_link.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index c9252498d51..aee9fff9619 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -5393,7 +5393,7 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, struct bnx2x *bp; u32 ext_phy_type = 0; u32 spirom_ver = 0; - u8 status = 0 ; + u8 status; if (version == NULL || params == NULL) return -EINVAL; @@ -5403,6 +5403,7 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, offsetof(struct shmem_region, port_mb[params->port].ext_phy_fw_version)); + status = 0; /* reset the returned value to zero */ ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); switch (ext_phy_type) { @@ -5421,7 +5422,6 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: status = bnx2x_format_ver(spirom_ver, version, len); @@ -5432,6 +5432,8 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, status = bnx2x_format_ver(spirom_ver, version, len); break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: + version[0] = '\0'; break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE: -- cgit v1.2.3-18-g5258 From bc7f0a053021491e292fc00810c4f2a8524453dd Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:01 +0000 Subject: bnx2x: BCM8727 FW load The BCM8727 is a dual port PHY. The FW must be loaded in a given order on all designs - including those which swapped the ports (calling port number zero the second port) Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_link.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index aee9fff9619..db4f3c057a1 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -6430,7 +6430,7 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base) static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) { u8 ext_phy_addr[PORT_MAX]; - s8 port; + s8 port, first_port, i; u32 swap_val, swap_override; DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n"); swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); @@ -6439,8 +6439,13 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) bnx2x_hw_reset(bp, 1 ^ (swap_val && swap_override)); msleep(5); + if (swap_val && swap_override) + first_port = PORT_0; + else + first_port = PORT_1; + /* PART1 - Reset both phys */ - for (port = PORT_MAX - 1; port >= PORT_0; port--) { + for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) { /* Extract the ext phy address for the port */ u32 ext_phy_config = REG_RD(bp, shmem_base + offsetof(struct shmem_region, @@ -6470,7 +6475,7 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) msleep(150); /* PART2 - Download firmware to both phys */ - for (port = PORT_MAX - 1; port >= PORT_0; port--) { + for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) { u16 fw_ver1; bnx2x_bcm8727_external_rom_boot(bp, port, @@ -6482,16 +6487,13 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) MDIO_PMA_REG_ROM_VER1, &fw_ver1); if (fw_ver1 == 0 || fw_ver1 == 0x4321) { DP(NETIF_MSG_LINK, - "bnx2x_8073_common_init_phy port %x:" + "bnx2x_8727_common_init_phy port %x:" "Download failed. fw version = 0x%x\n", port, fw_ver1); return -EINVAL; } - } - - return 0; } -- cgit v1.2.3-18-g5258 From 239d686d494f10ecd83a89ddc4e31f9462ca4901 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:04 +0000 Subject: bnx2x: Adding XAUI CL73 autoneg support Adding CL73 support to the built in PHY in the 5771x device. Also supporting fallbacks to CL73 if the link partner does not respond. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_link.c | 197 +++++++++++++++++++++++++++++++++++++++-------- drivers/net/bnx2x_reg.h | 13 ++++ 2 files changed, 180 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index db4f3c057a1..371310db2eb 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -1151,7 +1151,8 @@ static void bnx2x_set_parallel_detection(struct link_params *params, } static void bnx2x_set_autoneg(struct link_params *params, - struct link_vars *vars) + struct link_vars *vars, + u8 enable_cl73) { struct bnx2x *bp = params->bp; u16 reg_val; @@ -1181,7 +1182,9 @@ static void bnx2x_set_autoneg(struct link_params *params, params->phy_addr, MDIO_REG_BANK_SERDES_DIGITAL, MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, ®_val); - reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN; + reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN | + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT); + reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE; if (vars->line_speed == SPEED_AUTO_NEG) reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET; else @@ -1213,8 +1216,51 @@ static void bnx2x_set_autoneg(struct link_params *params, MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL, reg_val); - /* CL73 Autoneg Disabled */ - reg_val = 0; + if (enable_cl73) { + /* Enable Cl73 FSM status bits */ + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_USERB0, + MDIO_CL73_USERB0_CL73_UCTRL, + MDIO_CL73_USERB0_CL73_UCTRL_USTAT1_MUXSEL); + + /* Enable BAM Station Manager*/ + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_USERB0, + MDIO_CL73_USERB0_CL73_BAM_CTRL1, + MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN | + MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN | + MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN); + + /* Merge CL73 and CL37 aneg resolution */ + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_USERB0, + MDIO_CL73_USERB0_CL73_BAM_CTRL3, + ®_val); + + if (params->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) { + /* Set the CL73 AN speed */ + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB1, + MDIO_CL73_IEEEB1_AN_ADV2, + ®_val); + + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB1, + MDIO_CL73_IEEEB1_AN_ADV2, + reg_val | MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4); + + } + /* CL73 Autoneg Enabled */ + reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN; + + } else /* CL73 Autoneg Disabled */ + reg_val = 0; CL45_WR_OVER_CL22(bp, params->port, params->phy_addr, @@ -1297,7 +1343,7 @@ static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params) CL45_WR_OVER_CL22(bp, params->port, params->phy_addr, MDIO_REG_BANK_OVER_1G, - MDIO_OVER_1G_UP3, 0); + MDIO_OVER_1G_UP3, 0x400); } static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc) @@ -1345,28 +1391,46 @@ static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params, MDIO_COMBO_IEEE0_AUTO_NEG_ADV, (u16)ieee_fc); } -static void bnx2x_restart_autoneg(struct link_params *params) +static void bnx2x_restart_autoneg(struct link_params *params, u8 enable_cl73) { struct bnx2x *bp = params->bp; u16 mii_control; + DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n"); /* Enable and restart BAM/CL37 aneg */ - CL45_RD_OVER_CL22(bp, params->port, - params->phy_addr, - MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_MII_CONTROL, - &mii_control); - DP(NETIF_MSG_LINK, - "bnx2x_restart_autoneg mii_control before = 0x%x\n", - mii_control); - CL45_WR_OVER_CL22(bp, params->port, - params->phy_addr, - MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_MII_CONTROL, - (mii_control | - MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | - MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN)); + if (enable_cl73) { + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + &mii_control); + + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + (mii_control | + MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN | + MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN)); + } else { + + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + &mii_control); + DP(NETIF_MSG_LINK, + "bnx2x_restart_autoneg mii_control before = 0x%x\n", + mii_control); + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + (mii_control | + MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | + MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN)); + } } static void bnx2x_initialize_sgmii_process(struct link_params *params, @@ -1438,7 +1502,7 @@ static void bnx2x_initialize_sgmii_process(struct link_params *params, } else { /* AN mode */ /* enable and restart AN */ - bnx2x_restart_autoneg(params); + bnx2x_restart_autoneg(params, 0); } } @@ -1591,7 +1655,73 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params, DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl); } - +static void bnx2x_check_fallback_to_cl37(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u16 rx_status, ustat_val, cl37_fsm_recieved; + DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n"); + /* Step 1: Make sure signal is detected */ + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_RX0, + MDIO_RX0_RX_STATUS, + &rx_status); + if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) != + (MDIO_RX0_RX_STATUS_SIGDET)) { + DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73." + "rx_status(0x80b0) = 0x%x\n", rx_status); + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN); + return; + } + /* Step 2: Check CL73 state machine */ + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_USERB0, + MDIO_CL73_USERB0_CL73_USTAT1, + &ustat_val); + if ((ustat_val & + (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK | + MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) != + (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK | + MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) { + DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. " + "ustat_val(0x8371) = 0x%x\n", ustat_val); + return; + } + /* Step 3: Check CL37 Message Pages received to indicate LP + supports only CL37 */ + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_REMOTE_PHY, + MDIO_REMOTE_PHY_MISC_RX_STATUS, + &cl37_fsm_recieved); + if ((cl37_fsm_recieved & + (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG | + MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) != + (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG | + MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) { + DP(NETIF_MSG_LINK, "No CL37 FSM were received. " + "misc_rx_status(0x8330) = 0x%x\n", + cl37_fsm_recieved); + return; + } + /* The combined cl37/cl73 fsm state information indicating that we are + connected to a device which does not support cl73, but does support + cl37 BAM. In this case we disable cl73 and restart cl37 auto-neg */ + /* Disable CL73 */ + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + 0); + /* Restart CL37 autoneg */ + bnx2x_restart_autoneg(params, 0); + DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n"); +} static u8 bnx2x_link_settings_status(struct link_params *params, struct link_vars *vars, u32 gp_status, @@ -1755,6 +1885,13 @@ static u8 bnx2x_link_settings_status(struct link_params *params, vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; vars->autoneg = AUTO_NEG_DISABLED; vars->mac_type = MAC_TYPE_NONE; + + if ((params->req_line_speed == SPEED_AUTO_NEG) && + ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT))) { + /* Check signal is detected */ + bnx2x_check_fallback_to_cl37(params); + } } DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x \n", @@ -3425,7 +3562,8 @@ static void bnx2x_8481_set_10G_led_mode(struct link_params *params, static void bnx2x_init_internal_phy(struct link_params *params, - struct link_vars *vars) + struct link_vars *vars, + u8 enable_cl73) { struct bnx2x *bp = params->bp; if (!(vars->phy_flags & PHY_SGMII_FLAG)) { @@ -3440,7 +3578,7 @@ static void bnx2x_init_internal_phy(struct link_params *params, DP(NETIF_MSG_LINK, "not SGMII, no AN\n"); /* disable autoneg */ - bnx2x_set_autoneg(params, vars); + bnx2x_set_autoneg(params, vars, 0); /* program speed and duplex */ bnx2x_program_serdes(params, vars); @@ -3456,10 +3594,10 @@ static void bnx2x_init_internal_phy(struct link_params *params, vars->ieee_fc); /* enable autoneg */ - bnx2x_set_autoneg(params, vars); + bnx2x_set_autoneg(params, vars, enable_cl73); /* enable and restart AN */ - bnx2x_restart_autoneg(params); + bnx2x_restart_autoneg(params, enable_cl73); } } else { /* SGMII mode */ @@ -5815,11 +5953,10 @@ static u8 bnx2x_link_initialize(struct link_params *params, if (non_ext_phy || (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) || (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) || - (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481) || (params->loopback_mode == LOOPBACK_EXT_PHY)) { if (params->req_line_speed == SPEED_AUTO_NEG) bnx2x_set_parallel_detection(params, vars->phy_flags); - bnx2x_init_internal_phy(params, vars); + bnx2x_init_internal_phy(params, vars, non_ext_phy); } if (!non_ext_phy) @@ -6296,7 +6433,7 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) && (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) && (ext_phy_link_up && !vars->phy_link_up)) - bnx2x_init_internal_phy(params, vars); + bnx2x_init_internal_phy(params, vars, 0); /* link is up only if both local phy and external phy are up */ vars->link_up = (ext_phy_link_up && vars->phy_link_up); diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h index 9a20da5bf19..999838629be 100644 --- a/drivers/net/bnx2x_reg.h +++ b/drivers/net/bnx2x_reg.h @@ -5596,6 +5596,9 @@ #define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KR 0x0080 #define MDIO_REG_BANK_RX0 0x80b0 +#define MDIO_RX0_RX_STATUS 0x10 +#define MDIO_RX0_RX_STATUS_SIGDET 0x8000 +#define MDIO_RX0_RX_STATUS_RX_SEQ_DONE 0x1000 #define MDIO_RX0_RX_EQ_BOOST 0x1c #define MDIO_RX0_RX_EQ_BOOST_EQUALIZER_CTRL_MASK 0x7 #define MDIO_RX0_RX_EQ_BOOST_OFFSET_CTRL 0x10 @@ -5789,12 +5792,22 @@ #define MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT 7 #define MDIO_OVER_1G_LP_UP3 0x1E +#define MDIO_REG_BANK_REMOTE_PHY 0x8330 +#define MDIO_REMOTE_PHY_MISC_RX_STATUS 0x10 +#define MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG 0x0010 +#define MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG 0x0600 + #define MDIO_REG_BANK_BAM_NEXT_PAGE 0x8350 #define MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL 0x10 #define MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE 0x0001 #define MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN 0x0002 #define MDIO_REG_BANK_CL73_USERB0 0x8370 +#define MDIO_CL73_USERB0_CL73_UCTRL 0x10 +#define MDIO_CL73_USERB0_CL73_UCTRL_USTAT1_MUXSEL 0x0002 +#define MDIO_CL73_USERB0_CL73_USTAT1 0x11 +#define MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK 0x0100 +#define MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37 0x0400 #define MDIO_CL73_USERB0_CL73_BAM_CTRL1 0x12 #define MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN 0x8000 #define MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN 0x4000 -- cgit v1.2.3-18-g5258 From 01cd452846c98609dd3efbee0deea050e6706f02 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:08 +0000 Subject: bnx2x: MDC/MDIO CL45 IOCTLs As suggested by Ben Hutchings , using the MDC/MDIO IOCTL Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/Kconfig | 1 + drivers/net/bnx2x.h | 3 ++ drivers/net/bnx2x_main.c | 121 ++++++++++++++++++++++++++++++++--------------- 3 files changed, 88 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 9948fa23222..29935a9fb1a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2722,6 +2722,7 @@ config BNX2X select FW_LOADER select ZLIB_INFLATE select LIBCRC32C + select MDIO help This driver supports Broadcom NetXtremeII 10 gigabit Ethernet cards. To compile this driver as a module, choose M here: the module diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 5864ae2faab..903c89d8518 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -30,6 +30,8 @@ #define BNX2X_NEW_NAPI + +#include #include "bnx2x_reg.h" #include "bnx2x_fw_defs.h" #include "bnx2x_hsi.h" @@ -895,6 +897,7 @@ struct bnx2x { struct link_params link_params; struct link_vars link_vars; + struct mdio_if_info mdio; struct bnx2x_common common; struct bnx2x_port port; diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index a695e7f0647..145866764d4 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -8331,6 +8331,7 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) u32 val, val2; u32 config; u16 i; + u32 ext_phy_type; bp->link_params.bp = bp; bp->link_params.port = port; @@ -8390,6 +8391,21 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) bnx2x_link_settings_requested(bp); + /* + * If connected directly, work with the internal PHY, otherwise, work + * with the external PHY + */ + ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config); + if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) + bp->mdio.prtad = bp->link_params.phy_addr; + + else if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) && + (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) + bp->mdio.prtad = + (bp->link_params.ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT; + val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper); val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower); bp->dev->dev_addr[0] = (u8)(val2 >> 8 & 0xff); @@ -8614,7 +8630,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) } else cmd->port = PORT_TP; - cmd->phy_address = bp->port.phy_addr; + cmd->phy_address = bp->mdio.prtad; cmd->transceiver = XCVR_INTERNAL; if (bp->link_params.req_line_speed == SPEED_AUTO_NEG) @@ -11149,54 +11165,77 @@ static int bnx2x_change_mac_addr(struct net_device *dev, void *p) } /* called with rtnl_lock */ -static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +static int bnx2x_mdio_read(struct net_device *netdev, int prtad, + int devad, u16 addr) { - struct mii_ioctl_data *data = if_mii(ifr); - struct bnx2x *bp = netdev_priv(dev); - int port = BP_PORT(bp); - int err; + struct bnx2x *bp = netdev_priv(netdev); + u16 value; + int rc; + u32 phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config); - switch (cmd) { - case SIOCGMIIPHY: - data->phy_id = bp->port.phy_addr; + DP(NETIF_MSG_LINK, "mdio_read: prtad 0x%x, devad 0x%x, addr 0x%x\n", + prtad, devad, addr); - /* fallthrough */ + if (prtad != bp->mdio.prtad) { + DP(NETIF_MSG_LINK, "prtad missmatch (cmd:0x%x != bp:0x%x)\n", + prtad, bp->mdio.prtad); + return -EINVAL; + } + + /* The HW expects different devad if CL22 is used */ + devad = (devad == MDIO_DEVAD_NONE) ? DEFAULT_PHY_DEV_ADDR : devad; - case SIOCGMIIREG: { - u16 mii_regval; + bnx2x_acquire_phy_lock(bp); + rc = bnx2x_cl45_read(bp, BP_PORT(bp), phy_type, prtad, + devad, addr, &value); + bnx2x_release_phy_lock(bp); + DP(NETIF_MSG_LINK, "mdio_read_val 0x%x rc = 0x%x\n", value, rc); - if (!netif_running(dev)) - return -EAGAIN; + if (!rc) + rc = value; + return rc; +} - mutex_lock(&bp->port.phy_mutex); - err = bnx2x_cl45_read(bp, port, 0, bp->port.phy_addr, - DEFAULT_PHY_DEV_ADDR, - (data->reg_num & 0x1f), &mii_regval); - data->val_out = mii_regval; - mutex_unlock(&bp->port.phy_mutex); - return err; +/* called with rtnl_lock */ +static int bnx2x_mdio_write(struct net_device *netdev, int prtad, int devad, + u16 addr, u16 value) +{ + struct bnx2x *bp = netdev_priv(netdev); + u32 ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config); + int rc; + + DP(NETIF_MSG_LINK, "mdio_write: prtad 0x%x, devad 0x%x, addr 0x%x," + " value 0x%x\n", prtad, devad, addr, value); + + if (prtad != bp->mdio.prtad) { + DP(NETIF_MSG_LINK, "prtad missmatch (cmd:0x%x != bp:0x%x)\n", + prtad, bp->mdio.prtad); + return -EINVAL; } - case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; + /* The HW expects different devad if CL22 is used */ + devad = (devad == MDIO_DEVAD_NONE) ? DEFAULT_PHY_DEV_ADDR : devad; - if (!netif_running(dev)) - return -EAGAIN; + bnx2x_acquire_phy_lock(bp); + rc = bnx2x_cl45_write(bp, BP_PORT(bp), ext_phy_type, prtad, + devad, addr, value); + bnx2x_release_phy_lock(bp); + return rc; +} - mutex_lock(&bp->port.phy_mutex); - err = bnx2x_cl45_write(bp, port, 0, bp->port.phy_addr, - DEFAULT_PHY_DEV_ADDR, - (data->reg_num & 0x1f), data->val_in); - mutex_unlock(&bp->port.phy_mutex); - return err; +/* called with rtnl_lock */ +static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct bnx2x *bp = netdev_priv(dev); + struct mii_ioctl_data *mdio = if_mii(ifr); - default: - /* do nothing */ - break; - } + DP(NETIF_MSG_LINK, "ioctl: phy id 0x%x, reg 0x%x, val_in 0x%x\n", + mdio->phy_id, mdio->reg_num, mdio->val_in); - return -EOPNOTSUPP; + if (!netif_running(dev)) + return -EAGAIN; + + return mdio_mii_ioctl(&bp->mdio, mdio, cmd); } /* called with rtnl_lock */ @@ -11420,6 +11459,14 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev, dev->vlan_features |= NETIF_F_TSO6; #endif + /* get_port_hwinfo() will set prtad and mmds properly */ + bp->mdio.prtad = MDIO_PRTAD_NONE; + bp->mdio.mmds = 0; + bp->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; + bp->mdio.dev = dev; + bp->mdio.mdio_read = bnx2x_mdio_read; + bp->mdio.mdio_write = bnx2x_mdio_write; + return 0; err_out_unmap: -- cgit v1.2.3-18-g5258 From f57a60256d02daba1316c98da472f02cd98a58d3 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:11 +0000 Subject: bnx2x: Supporting PHY FW upgrade There are 3 operations that the driver needs to support to allow applications to access the PHY FW (on top of the MDC/MDIO access). Since those are essentially nvram access commands, adding them to the ethtool -E interface. Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_link.c | 21 ++++++-------- drivers/net/bnx2x_link.h | 4 +++ drivers/net/bnx2x_main.c | 72 ++++++++++++++++++++++++++++++++++++------------ 3 files changed, 67 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index 371310db2eb..98e3e8fc0ef 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -1996,7 +1996,7 @@ static u8 bnx2x_emac_program(struct link_params *params, /*****************************************************************************/ /* External Phy section */ /*****************************************************************************/ -static void bnx2x_hw_reset(struct bnx2x *bp, u8 port) +void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port) { bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, MISC_REGISTERS_GPIO_OUTPUT_LOW, port); @@ -2035,7 +2035,7 @@ static void bnx2x_ext_phy_reset(struct link_params *params, params->port); /* HW reset */ - bnx2x_hw_reset(bp, params->port); + bnx2x_ext_phy_hw_reset(bp, params->port); bnx2x_cl45_write(bp, params->port, ext_phy_type, @@ -2106,8 +2106,7 @@ static void bnx2x_ext_phy_reset(struct link_params *params, params->port); /* HW reset */ - bnx2x_hw_reset(bp, params->port); - + bnx2x_ext_phy_hw_reset(bp, params->port); break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481: @@ -2118,7 +2117,7 @@ static void bnx2x_ext_phy_reset(struct link_params *params, params->port); /* HW reset */ - bnx2x_hw_reset(bp, params->port); + bnx2x_ext_phy_hw_reset(bp, params->port); bnx2x_cl45_write(bp, params->port, ext_phy_type, @@ -2146,7 +2145,7 @@ static void bnx2x_ext_phy_reset(struct link_params *params, case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482: DP(NETIF_MSG_LINK, "SerDes 5482\n"); - bnx2x_hw_reset(bp, params->port); + bnx2x_ext_phy_hw_reset(bp, params->port); break; default: @@ -6573,7 +6572,7 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); - bnx2x_hw_reset(bp, 1 ^ (swap_val && swap_override)); + bnx2x_ext_phy_hw_reset(bp, 1 ^ (swap_val && swap_override)); msleep(5); if (swap_val && swap_override) @@ -6647,7 +6646,7 @@ static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base) (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT))); REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val); - bnx2x_hw_reset(bp, 1); + bnx2x_ext_phy_hw_reset(bp, 1); msleep(5); for (port = 0; port < PORT_MAX; port++) { /* Extract the ext phy address for the port */ @@ -6714,9 +6713,7 @@ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base) return rc; } - - -static void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr) +void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr) { u16 val, cnt; @@ -7032,7 +7029,7 @@ static u8 bnx2x_sfx7101_flash_download(struct bnx2x *bp, u8 port, for (cnt = 0; cnt < 100; cnt++) msleep(5); - bnx2x_hw_reset(bp, port); + bnx2x_ext_phy_hw_reset(bp, port); for (cnt = 0; cnt < 100; cnt++) msleep(5); diff --git a/drivers/net/bnx2x_link.h b/drivers/net/bnx2x_link.h index d25ef45d793..9805d210c02 100644 --- a/drivers/net/bnx2x_link.h +++ b/drivers/net/bnx2x_link.h @@ -187,6 +187,10 @@ u8 bnx2x_test_link(struct link_params *input, struct link_vars *vars); /* One-time initialization for external phy after power up */ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base); +/* Reset the external PHY using GPIO */ +void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port); + +void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr); u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr, u8 byte_cnt, u8 *o_buf); diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 145866764d4..7853977b8de 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -9353,7 +9353,8 @@ static int bnx2x_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *eebuf) { struct bnx2x *bp = netdev_priv(dev); - int rc; + int port = BP_PORT(bp); + int rc = 0; if (!netif_running(dev)) return -EAGAIN; @@ -9365,27 +9366,62 @@ static int bnx2x_set_eeprom(struct net_device *dev, /* parameters already validated in ethtool_set_eeprom */ - /* If the magic number is PHY (0x00504859) upgrade the PHY FW */ - if (eeprom->magic == 0x00504859) - if (bp->port.pmf) { + /* PHY eeprom can be accessed only by the PMF */ + if ((eeprom->magic >= 0x50485900) && (eeprom->magic <= 0x504859FF) && + !bp->port.pmf) + return -EINVAL; + + if (eeprom->magic == 0x50485950) { + /* 'PHYP' (0x50485950): prepare phy for FW upgrade */ + bnx2x_stats_handle(bp, STATS_EVENT_STOP); + bnx2x_acquire_phy_lock(bp); + rc |= bnx2x_link_reset(&bp->link_params, + &bp->link_vars, 0); + if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, + MISC_REGISTERS_GPIO_HIGH, port); + bnx2x_release_phy_lock(bp); + bnx2x_link_report(bp); + + } else if (eeprom->magic == 0x50485952) { + /* 'PHYR' (0x50485952): re-init link after FW upgrade */ + if ((bp->state == BNX2X_STATE_OPEN) || + (bp->state == BNX2X_STATE_DISABLED)) { bnx2x_acquire_phy_lock(bp); - rc = bnx2x_flash_download(bp, BP_PORT(bp), - bp->link_params.ext_phy_config, - (bp->state != BNX2X_STATE_CLOSED), - eebuf, eeprom->len); - if ((bp->state == BNX2X_STATE_OPEN) || - (bp->state == BNX2X_STATE_DISABLED)) { - rc |= bnx2x_link_reset(&bp->link_params, - &bp->link_vars, 1); - rc |= bnx2x_phy_init(&bp->link_params, - &bp->link_vars); - } + rc |= bnx2x_link_reset(&bp->link_params, + &bp->link_vars, 1); + + rc |= bnx2x_phy_init(&bp->link_params, + &bp->link_vars); bnx2x_release_phy_lock(bp); + bnx2x_calc_fc_adv(bp); + } + } else if (eeprom->magic == 0x53985943) { + /* 'PHYC' (0x53985943): PHY FW upgrade completed */ + if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) { + u8 ext_phy_addr = + (bp->link_params.ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT; + + /* DSP Remove Download Mode */ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, + MISC_REGISTERS_GPIO_LOW, port); - } else /* Only the PMF can access the PHY */ - return -EINVAL; - else + bnx2x_acquire_phy_lock(bp); + + bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr); + + /* wait 0.5 sec to allow it to run */ + msleep(500); + bnx2x_ext_phy_hw_reset(bp, port); + msleep(500); + bnx2x_release_phy_lock(bp); + } + } else rc = bnx2x_nvram_write(bp, eeprom->offset, eebuf, eeprom->len); return rc; -- cgit v1.2.3-18-g5258 From cdea52128f6099e8f84459823c45790a78264022 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:14 +0000 Subject: bnx2x: Removing old PHY FW upgrade code This code should not have resided in the driver. Now that we have a new interface, this logic can reside in the application that whishes to upgrade the PHY FW Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_link.c | 427 ----------------------------------------------- drivers/net/bnx2x_link.h | 2 - 2 files changed, 429 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index 98e3e8fc0ef..dc3b69e1fd1 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -5471,59 +5471,6 @@ static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len) return 0; } - -static void bnx2x_turn_on_ef(struct bnx2x *bp, u8 port, u8 ext_phy_addr, - u32 ext_phy_type) -{ - u32 cnt = 0; - u16 ctrl = 0; - /* Enable EMAC0 in to enable MDIO */ - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, - (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port)); - msleep(5); - - /* take ext phy out of reset */ - bnx2x_set_gpio(bp, - MISC_REGISTERS_GPIO_2, - MISC_REGISTERS_GPIO_HIGH, - port); - - bnx2x_set_gpio(bp, - MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_HIGH, - port); - - /* wait for 5ms */ - msleep(5); - - for (cnt = 0; cnt < 1000; cnt++) { - msleep(1); - bnx2x_cl45_read(bp, port, - ext_phy_type, - ext_phy_addr, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_CTRL, - &ctrl); - if (!(ctrl & (1<<15))) { - DP(NETIF_MSG_LINK, "Reset completed\n\n"); - break; - } - } -} - -static void bnx2x_turn_off_sf(struct bnx2x *bp, u8 port) -{ - /* put sf to reset */ - bnx2x_set_gpio(bp, - MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_LOW, - port); - bnx2x_set_gpio(bp, - MISC_REGISTERS_GPIO_2, - MISC_REGISTERS_GPIO_LOW, - port); -} - u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, u8 *version, u16 len) { @@ -6743,377 +6690,3 @@ void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr) break; } } -#define RESERVED_SIZE 256 -/* max application is 160K bytes - data at end of RAM */ -#define MAX_APP_SIZE (160*1024 - RESERVED_SIZE) - -/* Header is 14 bytes */ -#define HEADER_SIZE 14 -#define DATA_OFFSET HEADER_SIZE - -#define SPI_START_TRANSFER(bp, port, ext_phy_addr) \ - bnx2x_cl45_write(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, \ - ext_phy_addr, \ - MDIO_PCS_DEVAD, \ - MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 1) - -/* Programs an image to DSP's flash via the SPI port*/ -static u8 bnx2x_sfx7101_flash_download(struct bnx2x *bp, u8 port, - u8 ext_phy_addr, - char data[], u32 size) -{ - const u16 num_trans = size/4; /* 4 bytes can be sent at a time */ - /* Doesn't include last trans!*/ - const u16 last_trans_size = size%4; /* Num bytes on last trans */ - u16 trans_cnt, byte_cnt; - u32 data_index; - u16 tmp; - u16 code_started = 0; - u16 image_revision1, image_revision2; - u16 cnt; - - DP(NETIF_MSG_LINK, "bnx2x_sfx7101_flash_download file_size=%d\n", size); - /* Going to flash*/ - if ((size-HEADER_SIZE) > MAX_APP_SIZE) { - /* This very often will be the case, because the image is built - with 160Kbytes size whereas the total image size must actually - be 160Kbytes-RESERVED_SIZE */ - DP(NETIF_MSG_LINK, "Warning, file size was %d bytes " - "truncated to %d bytes\n", size, MAX_APP_SIZE); - size = MAX_APP_SIZE+HEADER_SIZE; - } - DP(NETIF_MSG_LINK, "File version is %c%c\n", data[0x14e], data[0x14f]); - DP(NETIF_MSG_LINK, " %c%c\n", data[0x150], data[0x151]); - /* Put the DSP in download mode by setting FLASH_CFG[2] to 1 - and issuing a reset.*/ - - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, - MISC_REGISTERS_GPIO_HIGH, port); - - bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr); - - /* wait 0.5 sec */ - for (cnt = 0; cnt < 100; cnt++) - msleep(5); - - /* Make sure we can access the DSP - And it's in the correct mode (waiting for download) */ - - bnx2x_cl45_read(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_DSP_ACCESS, &tmp); - - if (tmp != 0x000A) { - DP(NETIF_MSG_LINK, "DSP is not in waiting on download mode. " - "Expected 0x000A, read 0x%04X\n", tmp); - DP(NETIF_MSG_LINK, "Download failed\n"); - return -EINVAL; - } - - /* Mux the SPI interface away from the internal processor */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_MUX, 1); - - /* Reset the SPI port */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0); - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_CTRL_ADDR, - (1<>16)); - /* Bits 15-8 of address */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - (data_index>>8)); - - /* Bits 7-0 of address */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - ((u16)data_index)); - - byte_cnt = 0; - while (byte_cnt < 4 && data_index < size) { - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - data[data_index++]); - byte_cnt++; - } - - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR, - byte_cnt+4); - - SPI_START_TRANSFER(bp, port, ext_phy_addr); - msleep(5); /* Wait 5 ms minimum between transs */ - - /* Let the user know something's going on.*/ - /* a pacifier ever 4K */ - if ((data_index % 1023) == 0) - DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size); - } - - DP(NETIF_MSG_LINK, "\n"); - /* Transfer the last block if there is data remaining */ - if (last_trans_size) { - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD); - - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR, - 1); - - SPI_START_TRANSFER(bp, port, ext_phy_addr); - - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD); - - /* Bits 23-16 of address */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - (data_index>>16)); - /* Bits 15-8 of address */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - (data_index>>8)); - - /* Bits 7-0 of address */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - ((u16)data_index)); - - byte_cnt = 0; - while (byte_cnt < last_trans_size && data_index < size) { - /* Bits 7-0 of address */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - data[data_index++]); - byte_cnt++; - } - - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR, - byte_cnt+4); - - SPI_START_TRANSFER(bp, port, ext_phy_addr); - } - - /* DSP Remove Download Mode */ - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, - MISC_REGISTERS_GPIO_LOW, port); - - bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr); - - /* wait 0.5 sec to allow it to run */ - for (cnt = 0; cnt < 100; cnt++) - msleep(5); - - bnx2x_ext_phy_hw_reset(bp, port); - - for (cnt = 0; cnt < 100; cnt++) - msleep(5); - - /* Check that the code is started. In case the download - checksum failed, the code won't be started. */ - bnx2x_cl45_read(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_DSP_ACCESS, - &tmp); - - code_started = (tmp & (1<<4)); - if (!code_started) { - DP(NETIF_MSG_LINK, "Download failed. Please check file.\n"); - return -EINVAL; - } - - /* Verify that the file revision is now equal to the image - revision within the DSP */ - bnx2x_cl45_read(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_7101_VER1, - &image_revision1); - - bnx2x_cl45_read(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_7101_VER2, - &image_revision2); - - if (data[0x14e] != (image_revision2&0xFF) || - data[0x14f] != ((image_revision2&0xFF00)>>8) || - data[0x150] != (image_revision1&0xFF) || - data[0x151] != ((image_revision1&0xFF00)>>8)) { - DP(NETIF_MSG_LINK, "Download failed.\n"); - return -EINVAL; - } - DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size); - return 0; -} - -u8 bnx2x_flash_download(struct bnx2x *bp, u8 port, u32 ext_phy_config, - u8 driver_loaded, char data[], u32 size) -{ - u8 rc = 0; - u32 ext_phy_type; - u8 ext_phy_addr; - ext_phy_addr = ((ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); - - ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config); - - switch (ext_phy_type) { - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: - DP(NETIF_MSG_LINK, - "Flash download not supported for this ext phy\n"); - rc = -EINVAL; - break; - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: - /* Take ext phy out of reset */ - if (!driver_loaded) - bnx2x_turn_on_ef(bp, port, ext_phy_addr, ext_phy_type); - rc = bnx2x_sfx7101_flash_download(bp, port, ext_phy_addr, - data, size); - if (!driver_loaded) - bnx2x_turn_off_sf(bp, port); - break; - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN: - default: - DP(NETIF_MSG_LINK, "Invalid ext phy type\n"); - rc = -EINVAL; - break; - } - return rc; -} - diff --git a/drivers/net/bnx2x_link.h b/drivers/net/bnx2x_link.h index 9805d210c02..6d26d6c524b 100644 --- a/drivers/net/bnx2x_link.h +++ b/drivers/net/bnx2x_link.h @@ -174,8 +174,6 @@ u8 bnx2x_set_led(struct bnx2x *bp, u8 port, u8 mode, u32 speed, u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port, u32 led_idx, u32 value); -u8 bnx2x_flash_download(struct bnx2x *bp, u8 port, u32 ext_phy_config, - u8 driver_loaded, char data[], u32 size); /* bnx2x_handle_module_detect_int should be called upon module detection interrupt */ void bnx2x_handle_module_detect_int(struct link_params *params); -- cgit v1.2.3-18-g5258 From 6fe49bb978de3de0ba7ff9d6b2d55a15518db2a3 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:17 +0000 Subject: bnx2x: Reporting host statistics to management FW This is required for NCSI statistics Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x.h | 1 + drivers/net/bnx2x_main.c | 228 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 176 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 903c89d8518..1d0b72716f7 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -777,6 +777,7 @@ struct bnx2x_slowpath { struct nig_stats nig_stats; struct host_port_stats port_stats; struct host_func_stats func_stats; + struct host_func_stats func_stats_base; u32 wb_comp; u32 wb_data[4]; diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 7853977b8de..88f30d25409 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -3365,53 +3365,6 @@ static void bnx2x_storm_stats_post(struct bnx2x *bp) } } -static void bnx2x_stats_init(struct bnx2x *bp) -{ - int port = BP_PORT(bp); - int i; - - bp->stats_pending = 0; - bp->executer_idx = 0; - bp->stats_counter = 0; - - /* port stats */ - if (!BP_NOMCP(bp)) - bp->port.port_stx = SHMEM_RD(bp, port_mb[port].port_stx); - else - bp->port.port_stx = 0; - DP(BNX2X_MSG_STATS, "port_stx 0x%x\n", bp->port.port_stx); - - memset(&(bp->port.old_nig_stats), 0, sizeof(struct nig_stats)); - bp->port.old_nig_stats.brb_discard = - REG_RD(bp, NIG_REG_STAT0_BRB_DISCARD + port*0x38); - bp->port.old_nig_stats.brb_truncate = - REG_RD(bp, NIG_REG_STAT0_BRB_TRUNCATE + port*0x38); - REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT0 + port*0x50, - &(bp->port.old_nig_stats.egress_mac_pkt0_lo), 2); - REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT1 + port*0x50, - &(bp->port.old_nig_stats.egress_mac_pkt1_lo), 2); - - /* function stats */ - for_each_queue(bp, i) { - struct bnx2x_fastpath *fp = &bp->fp[i]; - - memset(&fp->old_tclient, 0, - sizeof(struct tstorm_per_client_stats)); - memset(&fp->old_uclient, 0, - sizeof(struct ustorm_per_client_stats)); - memset(&fp->old_xclient, 0, - sizeof(struct xstorm_per_client_stats)); - memset(&fp->eth_q_stats, 0, sizeof(struct bnx2x_eth_q_stats)); - } - - memset(&bp->dev->stats, 0, sizeof(struct net_device_stats)); - memset(&bp->eth_stats, 0, sizeof(struct bnx2x_eth_stats)); - - bp->stats_state = STATS_STATE_DISABLED; - if (IS_E1HMF(bp) && bp->port.pmf && bp->port.port_stx) - bnx2x_stats_handle(bp, STATS_EVENT_PMF); -} - static void bnx2x_hw_stats_post(struct bnx2x *bp) { struct dmae_command *dmae = &bp->stats_dmae; @@ -3972,7 +3925,8 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp) struct bnx2x_eth_stats *estats = &bp->eth_stats; int i; - memset(&(fstats->total_bytes_received_hi), 0, + memcpy(&(fstats->total_bytes_received_hi), + &(bnx2x_sp(bp, func_stats_base)->total_bytes_received_hi), sizeof(struct host_func_stats) - 2*sizeof(u32)); estats->error_bytes_received_hi = 0; estats->error_bytes_received_lo = 0; @@ -4451,6 +4405,173 @@ static void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event) state, event, bp->stats_state); } +static void bnx2x_port_stats_base_init(struct bnx2x *bp) +{ + struct dmae_command *dmae; + u32 *stats_comp = bnx2x_sp(bp, stats_comp); + + /* sanity */ + if (!bp->port.pmf || !bp->port.port_stx) { + BNX2X_ERR("BUG!\n"); + return; + } + + bp->executer_idx = 0; + + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC | + DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN + DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else + DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | + (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT)); + dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats)); + dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats)); + dmae->dst_addr_lo = bp->port.port_stx >> 2; + dmae->dst_addr_hi = 0; + dmae->len = sizeof(struct host_port_stats) >> 2; + dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_val = DMAE_COMP_VAL; + + *stats_comp = 0; + bnx2x_hw_stats_post(bp); + bnx2x_stats_comp(bp); +} + +static void bnx2x_func_stats_base_init(struct bnx2x *bp) +{ + int vn, vn_max = IS_E1HMF(bp) ? E1HVN_MAX : E1VN_MAX; + int port = BP_PORT(bp); + int func; + u32 func_stx; + + /* sanity */ + if (!bp->port.pmf || !bp->func_stx) { + BNX2X_ERR("BUG!\n"); + return; + } + + /* save our func_stx */ + func_stx = bp->func_stx; + + for (vn = VN_0; vn < vn_max; vn++) { + func = 2*vn + port; + + bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param); + bnx2x_func_stats_init(bp); + bnx2x_hw_stats_post(bp); + bnx2x_stats_comp(bp); + } + + /* restore our func_stx */ + bp->func_stx = func_stx; +} + +static void bnx2x_func_stats_base_update(struct bnx2x *bp) +{ + struct dmae_command *dmae = &bp->stats_dmae; + u32 *stats_comp = bnx2x_sp(bp, stats_comp); + + /* sanity */ + if (!bp->func_stx) { + BNX2X_ERR("BUG!\n"); + return; + } + + bp->executer_idx = 0; + memset(dmae, 0, sizeof(struct dmae_command)); + + dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI | + DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN + DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else + DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | + (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT)); + dmae->src_addr_lo = bp->func_stx >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats_base)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats_base)); + dmae->len = sizeof(struct host_func_stats) >> 2; + dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_val = DMAE_COMP_VAL; + + *stats_comp = 0; + bnx2x_hw_stats_post(bp); + bnx2x_stats_comp(bp); +} + +static void bnx2x_stats_init(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int func = BP_FUNC(bp); + int i; + + bp->stats_pending = 0; + bp->executer_idx = 0; + bp->stats_counter = 0; + + /* port and func stats for management */ + if (!BP_NOMCP(bp)) { + bp->port.port_stx = SHMEM_RD(bp, port_mb[port].port_stx); + bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param); + + } else { + bp->port.port_stx = 0; + bp->func_stx = 0; + } + DP(BNX2X_MSG_STATS, "port_stx 0x%x func_stx 0x%x\n", + bp->port.port_stx, bp->func_stx); + + /* port stats */ + memset(&(bp->port.old_nig_stats), 0, sizeof(struct nig_stats)); + bp->port.old_nig_stats.brb_discard = + REG_RD(bp, NIG_REG_STAT0_BRB_DISCARD + port*0x38); + bp->port.old_nig_stats.brb_truncate = + REG_RD(bp, NIG_REG_STAT0_BRB_TRUNCATE + port*0x38); + REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT0 + port*0x50, + &(bp->port.old_nig_stats.egress_mac_pkt0_lo), 2); + REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT1 + port*0x50, + &(bp->port.old_nig_stats.egress_mac_pkt1_lo), 2); + + /* function stats */ + for_each_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + + memset(&fp->old_tclient, 0, + sizeof(struct tstorm_per_client_stats)); + memset(&fp->old_uclient, 0, + sizeof(struct ustorm_per_client_stats)); + memset(&fp->old_xclient, 0, + sizeof(struct xstorm_per_client_stats)); + memset(&fp->eth_q_stats, 0, sizeof(struct bnx2x_eth_q_stats)); + } + + memset(&bp->dev->stats, 0, sizeof(struct net_device_stats)); + memset(&bp->eth_stats, 0, sizeof(struct bnx2x_eth_stats)); + + bp->stats_state = STATS_STATE_DISABLED; + + if (bp->port.pmf) { + if (bp->port.port_stx) + bnx2x_port_stats_base_init(bp); + + if (bp->func_stx) + bnx2x_func_stats_base_init(bp); + + } else if (bp->func_stx) + bnx2x_func_stats_base_update(bp); +} + static void bnx2x_timer(unsigned long data) { struct bnx2x *bp = (struct bnx2x *) data; @@ -4933,6 +5054,10 @@ static void bnx2x_init_tx_ring(struct bnx2x *bp) fp->tx_cons_sb = BNX2X_TX_SB_INDEX; fp->tx_pkt = 0; } + + /* clean tx statistics */ + for_each_rx_queue(bp, i) + bnx2x_fp(bp, i, tx_pkt) = 0; } static void bnx2x_init_sp_ring(struct bnx2x *bp) @@ -6412,11 +6537,8 @@ static int bnx2x_init_hw(struct bnx2x *bp, u32 load_code) bp->fw_drv_pulse_wr_seq = (SHMEM_RD(bp, func_mb[func].drv_pulse_mb) & DRV_PULSE_SEQ_MASK); - bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param); - DP(BNX2X_MSG_MCP, "drv_pulse 0x%x func_stx 0x%x\n", - bp->fw_drv_pulse_wr_seq, bp->func_stx); - } else - bp->func_stx = 0; + DP(BNX2X_MSG_MCP, "drv_pulse 0x%x\n", bp->fw_drv_pulse_wr_seq); + } /* this needs to be done before gunzip end */ bnx2x_zero_def_sb(bp); -- cgit v1.2.3-18-g5258 From 619e7a66b515f5f6b1cbe6f378f6a4ca3a65ac52 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:20 +0000 Subject: bnx2x: Prefetch the page containing the BD descriptor Signed-off-by: Vladislav Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 88f30d25409..bdc2e71f491 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -1498,6 +1498,13 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) bd_prod = RX_BD(bd_prod); bd_cons = RX_BD(bd_cons); + /* Prefetch the page containing the BD descriptor + at producer's index. It will be needed when new skb is + allocated */ + prefetch((void *)(PAGE_ALIGN((unsigned long) + (&fp->rx_desc_ring[bd_prod])) - + PAGE_SIZE + 1)); + cqe = &fp->rx_comp_ring[comp_ring_cons]; cqe_fp_flags = cqe->fast_path_cqe.type_error_flags; -- cgit v1.2.3-18-g5258 From a119a069349b6ad32807ff1b09e417cf23514020 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:23 +0000 Subject: bnx2x: Adding Likely directive Signed-off-by: Vladislav Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index bdc2e71f491..039fdd4becf 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -1613,7 +1613,8 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) skb = new_skb; - } else if (bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0) { + } else + if (likely(bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0)) { pci_unmap_single(bp->pdev, pci_unmap_addr(rx_buf, mapping), bp->rx_buf_size, -- cgit v1.2.3-18-g5258 From a18f5128828cd1af8091602f5233b00422e74c9a Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:26 +0000 Subject: bnx2x: Configurable pause scheme When a given ring is running out of space, the FW can send pause towards the network. When working with multi-queues, when one queue is getting out of space it can block all other queues. The preferred scheme is to send pause frames only when running out of the shared internal chip buffers and if a given queue cannot place a packet on the host, it will drop it. Since some users might want to work in drop-less mode, allowing changing the behavior as a module parameter. Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x.h | 2 ++ drivers/net/bnx2x_main.c | 14 ++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 1d0b72716f7..004f4a8e164 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -967,6 +967,8 @@ struct bnx2x { dma_addr_t qm_mapping; #endif + int dropless_fc; + int dmae_ready; /* used to synchronize dmae accesses */ struct mutex dmae_mutex; diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 039fdd4becf..0ebbc779480 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -101,6 +101,10 @@ static int int_mode; module_param(int_mode, int, 0); MODULE_PARM_DESC(int_mode, " Force interrupt mode (1 INT#x; 2 MSI)"); +static int dropless_fc; +module_param(dropless_fc, int, 0); +MODULE_PARM_DESC(dropless_fc, " Pause on exhausted host ring"); + static int poll; module_param(poll, int, 0); MODULE_PARM_DESC(poll, " Use polling (for debug)"); @@ -2369,7 +2373,7 @@ static void bnx2x_link_attn(struct bnx2x *bp) if (bp->link_vars.link_up) { /* dropless flow control */ - if (CHIP_IS_E1H(bp)) { + if (CHIP_IS_E1H(bp) && bp->dropless_fc) { int port = BP_PORT(bp); u32 pause_enabled = 0; @@ -6359,9 +6363,6 @@ static int bnx2x_init_port(struct bnx2x *bp) REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK_MF + port*4, (IS_E1HMF(bp) ? 0x1 : 0x2)); - /* support pause requests from USDM, TSDM and BRB */ - REG_WR(bp, NIG_REG_LLFC_EGRESS_SRC_ENABLE_0 + port*4, 0x7); - { REG_WR(bp, NIG_REG_LLFC_ENABLE_0 + port*4, 0); REG_WR(bp, NIG_REG_LLFC_OUT_EN_0 + port*4, 0); @@ -8677,6 +8678,11 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp) bp->dev->features |= NETIF_F_LRO; } + if (CHIP_IS_E1(bp)) + bp->dropless_fc = 0; + else + bp->dropless_fc = dropless_fc; + bp->mrrs = mrrs; bp->tx_ring_size = MAX_TX_AVAIL; -- cgit v1.2.3-18-g5258 From df4770de03d2eec3f66b0ac4d2248d471a1ccc0b Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:28 +0000 Subject: bnx2x: Calling pci_set_drvdata earlier In case of error, bnx2x_init_dev calls pci_set_drvdata(pdev, NULL) Signed-off-by: Yitchak Gertner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 0ebbc779480..8e77e933ac1 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -11885,14 +11885,14 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, bp = netdev_priv(dev); bp->msglevel = debug; + pci_set_drvdata(pdev, dev); + rc = bnx2x_init_dev(pdev, dev); if (rc < 0) { free_netdev(dev); return rc; } - pci_set_drvdata(pdev, dev); - rc = bnx2x_init_bp(bp); if (rc) goto init_one_exit; -- cgit v1.2.3-18-g5258 From e3553b29c6f395c6692afccc2ed5eff9c3d1daef Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:31 +0000 Subject: bnx2x: Stop loading if error condition detected Signed-off-by: Benjamin Li Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x.h | 1 + drivers/net/bnx2x_main.c | 8 ++++++++ 2 files changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 004f4a8e164..633acca4a98 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -89,6 +89,7 @@ } while (0) #else #define bnx2x_panic() do { \ + bp->panic = 1; \ BNX2X_ERR("driver assert\n"); \ bnx2x_panic_dump(bp); \ } while (0) diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 8e77e933ac1..c289670a55a 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -7109,6 +7109,9 @@ static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx, } msleep(1); + + if (bp->panic) + return -EIO; } /* timeout! */ @@ -7373,7 +7376,12 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode) rc = bnx2x_setup_leading(bp); if (rc) { BNX2X_ERR("Setup leading failed!\n"); +#ifndef BNX2X_STOP_ON_ERROR goto load_error3; +#else + bp->panic = 1; + return -EBUSY; +#endif } if (CHIP_IS_E1H(bp)) -- cgit v1.2.3-18-g5258 From 37f9ce6231cafb2973e09f7f72ad62bc6348d1b3 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:34 +0000 Subject: bnx2x: Combine get_pcie_width and get_pcie_speed The functions bnx2x_get_pcie_width() and bnx2x_get_pcie_speed() were combined into bnx2x_get_pcie_width_speed() so that there is only 1 PCI read to PCICFG_OFFSET + PCICFG_LINK_CONTROL rather then 2 reads. Signed-off-by: Benjamin Li Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index c289670a55a..807c1565ef8 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -11671,31 +11671,26 @@ err_out: return rc; } -static int __devinit bnx2x_get_pcie_width(struct bnx2x *bp) +static void __devinit bnx2x_get_pcie_width_speed(struct bnx2x *bp, + int *width, int *speed) { u32 val = REG_RD(bp, PCICFG_OFFSET + PCICFG_LINK_CONTROL); - val = (val & PCICFG_LINK_WIDTH) >> PCICFG_LINK_WIDTH_SHIFT; - return val; -} - -/* return value of 1=2.5GHz 2=5GHz */ -static int __devinit bnx2x_get_pcie_speed(struct bnx2x *bp) -{ - u32 val = REG_RD(bp, PCICFG_OFFSET + PCICFG_LINK_CONTROL); + *width = (val & PCICFG_LINK_WIDTH) >> PCICFG_LINK_WIDTH_SHIFT; - val = (val & PCICFG_LINK_SPEED) >> PCICFG_LINK_SPEED_SHIFT; - return val; + /* return value of 1=2.5GHz 2=5GHz */ + *speed = (val & PCICFG_LINK_SPEED) >> PCICFG_LINK_SPEED_SHIFT; } + static int __devinit bnx2x_check_firmware(struct bnx2x *bp) { + const struct firmware *firmware = bp->firmware; struct bnx2x_fw_file_hdr *fw_hdr; struct bnx2x_fw_file_section *sections; - u16 *ops_offsets; u32 offset, len, num_ops; + u16 *ops_offsets; int i; - const struct firmware *firmware = bp->firmware; - const u8 * fw_ver; + const u8 *fw_ver; if (firmware->size < sizeof(struct bnx2x_fw_file_hdr)) return -EINVAL; @@ -11709,7 +11704,8 @@ static int __devinit bnx2x_check_firmware(struct bnx2x *bp) offset = be32_to_cpu(sections[i].offset); len = be32_to_cpu(sections[i].len); if (offset + len > firmware->size) { - printk(KERN_ERR PFX "Section %d length is out of bounds\n", i); + printk(KERN_ERR PFX "Section %d length is out of " + "bounds\n", i); return -EINVAL; } } @@ -11721,7 +11717,8 @@ static int __devinit bnx2x_check_firmware(struct bnx2x *bp) for (i = 0; i < be32_to_cpu(fw_hdr->init_ops_offsets.len) / 2; i++) { if (be16_to_cpu(ops_offsets[i]) > num_ops) { - printk(KERN_ERR PFX "Section offset %d is out of bounds\n", i); + printk(KERN_ERR PFX "Section offset %d is out of " + "bounds\n", i); return -EINVAL; } } @@ -11878,6 +11875,7 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, static int version_printed; struct net_device *dev = NULL; struct bnx2x *bp; + int pcie_width, pcie_speed; int rc; if (version_printed++ == 0) @@ -11918,11 +11916,11 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, goto init_one_exit; } + bnx2x_get_pcie_width_speed(bp, &pcie_width, &pcie_speed); printk(KERN_INFO "%s: %s (%c%d) PCI-E x%d %s found at mem %lx," " IRQ %d, ", dev->name, board_info[ent->driver_data].name, (CHIP_REV(bp) >> 12) + 'A', (CHIP_METAL(bp) >> 4), - bnx2x_get_pcie_width(bp), - (bnx2x_get_pcie_speed(bp) == 2) ? "5GHz (Gen2)" : "2.5GHz", + pcie_width, (pcie_speed == 2) ? "5GHz (Gen2)" : "2.5GHz", dev->base_addr, bp->pdev->irq); printk(KERN_CONT "node addr %pM\n", dev->dev_addr); -- cgit v1.2.3-18-g5258 From 938cf5416d59769ec2e7ce4eb7967cb3b61242a3 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:37 +0000 Subject: bnx2x: Move printing of version from probe to the init Move printing of version from probe to the init function Rather then checking if this is the first module probe call to print the version of the driver only once, the statement is moved to the init function of the module where init is only called once Signed-off-by: Benjamin Li Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 807c1565ef8..f1bd0a32cc3 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -11872,15 +11872,11 @@ request_firmware_exit: static int __devinit bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - static int version_printed; struct net_device *dev = NULL; struct bnx2x *bp; int pcie_width, pcie_speed; int rc; - if (version_printed++ == 0) - printk(KERN_INFO "%s", version); - /* dev zeroed in init_etherdev */ dev = alloc_etherdev_mq(sizeof(*bp), MAX_CONTEXT); if (!dev) { @@ -12218,6 +12214,8 @@ static int __init bnx2x_init(void) { int ret; + printk(KERN_INFO "%s", version); + bnx2x_wq = create_singlethread_workqueue("bnx2x"); if (bnx2x_wq == NULL) { printk(KERN_ERR PFX "Cannot create workqueue\n"); -- cgit v1.2.3-18-g5258 From 0d28e49a2616b927bca5fde0f16dfdfd2a501107 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:40 +0000 Subject: bnx2x: Updating regdump_len at drvinfo Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 69 +++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index f1bd0a32cc3..276d8467b8c 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -8947,50 +8947,15 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return 0; } -#define PHY_FW_VER_LEN 10 - -static void bnx2x_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - struct bnx2x *bp = netdev_priv(dev); - u8 phy_fw_ver[PHY_FW_VER_LEN]; - - strcpy(info->driver, DRV_MODULE_NAME); - strcpy(info->version, DRV_MODULE_VERSION); - - phy_fw_ver[0] = '\0'; - if (bp->port.pmf) { - bnx2x_acquire_phy_lock(bp); - bnx2x_get_ext_phy_fw_version(&bp->link_params, - (bp->state != BNX2X_STATE_CLOSED), - phy_fw_ver, PHY_FW_VER_LEN); - bnx2x_release_phy_lock(bp); - } - - snprintf(info->fw_version, 32, "BC:%d.%d.%d%s%s", - (bp->common.bc_ver & 0xff0000) >> 16, - (bp->common.bc_ver & 0xff00) >> 8, - (bp->common.bc_ver & 0xff), - ((phy_fw_ver[0] != '\0') ? " PHY:" : ""), phy_fw_ver); - strcpy(info->bus_info, pci_name(bp->pdev)); - info->n_stats = BNX2X_NUM_STATS; - info->testinfo_len = BNX2X_NUM_TESTS; - info->eedump_len = bp->common.flash_size; - info->regdump_len = 0; -} - #define IS_E1_ONLINE(info) (((info) & RI_E1_ONLINE) == RI_E1_ONLINE) #define IS_E1H_ONLINE(info) (((info) & RI_E1H_ONLINE) == RI_E1H_ONLINE) static int bnx2x_get_regs_len(struct net_device *dev) { - static u32 regdump_len; struct bnx2x *bp = netdev_priv(dev); + int regdump_len = 0; int i; - if (regdump_len) - return regdump_len; - if (CHIP_IS_E1(bp)) { for (i = 0; i < REGS_COUNT; i++) if (IS_E1_ONLINE(reg_addrs[i].info)) @@ -9057,6 +9022,38 @@ static void bnx2x_get_regs(struct net_device *dev, } } +#define PHY_FW_VER_LEN 10 + +static void bnx2x_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct bnx2x *bp = netdev_priv(dev); + u8 phy_fw_ver[PHY_FW_VER_LEN]; + + strcpy(info->driver, DRV_MODULE_NAME); + strcpy(info->version, DRV_MODULE_VERSION); + + phy_fw_ver[0] = '\0'; + if (bp->port.pmf) { + bnx2x_acquire_phy_lock(bp); + bnx2x_get_ext_phy_fw_version(&bp->link_params, + (bp->state != BNX2X_STATE_CLOSED), + phy_fw_ver, PHY_FW_VER_LEN); + bnx2x_release_phy_lock(bp); + } + + snprintf(info->fw_version, 32, "BC:%d.%d.%d%s%s", + (bp->common.bc_ver & 0xff0000) >> 16, + (bp->common.bc_ver & 0xff00) >> 8, + (bp->common.bc_ver & 0xff), + ((phy_fw_ver[0] != '\0') ? " PHY:" : ""), phy_fw_ver); + strcpy(info->bus_info, pci_name(bp->pdev)); + info->n_stats = BNX2X_NUM_STATS; + info->testinfo_len = BNX2X_NUM_TESTS; + info->eedump_len = bp->common.flash_size; + info->regdump_len = bnx2x_get_regs_len(dev); +} + static void bnx2x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct bnx2x *bp = netdev_priv(dev); -- cgit v1.2.3-18-g5258 From 5ff7b6d4c129a430e355b2f88162a36d9e058f88 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:44 +0000 Subject: bnx2x: Remove the init_dmae field from bp Moved the dmae_command from the heap to the stack. This will save 56 bytes per bnx2x structure. As a side benefit, we can also reduce the time the dmae_mutex is held. This is because do we not need to hold this mutex when setting up the dmae command. The memory where is dmae command is stored is not a shared resource and doesn not need to be protected. Signed-off-by: Benjamin Li Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x.h | 1 - drivers/net/bnx2x_main.c | 94 ++++++++++++++++++++++++------------------------ 2 files changed, 47 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 633acca4a98..a231780061c 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -973,7 +973,6 @@ struct bnx2x { int dmae_ready; /* used to synchronize dmae accesses */ struct mutex dmae_mutex; - struct dmae_command init_dmae; /* used to synchronize stats collecting */ int stats_state; diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 276d8467b8c..59aacd84d7e 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -203,7 +203,7 @@ static void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae, void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr, u32 len32) { - struct dmae_command *dmae = &bp->init_dmae; + struct dmae_command dmae; u32 *wb_comp = bnx2x_sp(bp, wb_comp); int cnt = 200; @@ -216,43 +216,43 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr, return; } - mutex_lock(&bp->dmae_mutex); - - memset(dmae, 0, sizeof(struct dmae_command)); + memset(&dmae, 0, sizeof(struct dmae_command)); - dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC | - DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | - DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | + dmae.opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC | + DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | #ifdef __BIG_ENDIAN - DMAE_CMD_ENDIANITY_B_DW_SWAP | + DMAE_CMD_ENDIANITY_B_DW_SWAP | #else - DMAE_CMD_ENDIANITY_DW_SWAP | + DMAE_CMD_ENDIANITY_DW_SWAP | #endif - (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | - (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT)); - dmae->src_addr_lo = U64_LO(dma_addr); - dmae->src_addr_hi = U64_HI(dma_addr); - dmae->dst_addr_lo = dst_addr >> 2; - dmae->dst_addr_hi = 0; - dmae->len = len32; - dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp)); - dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp)); - dmae->comp_val = DMAE_COMP_VAL; + (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | + (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT)); + dmae.src_addr_lo = U64_LO(dma_addr); + dmae.src_addr_hi = U64_HI(dma_addr); + dmae.dst_addr_lo = dst_addr >> 2; + dmae.dst_addr_hi = 0; + dmae.len = len32; + dmae.comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp)); + dmae.comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp)); + dmae.comp_val = DMAE_COMP_VAL; DP(BNX2X_MSG_OFF, "DMAE: opcode 0x%08x\n" DP_LEVEL "src_addr [%x:%08x] len [%d *4] " "dst_addr [%x:%08x (%08x)]\n" DP_LEVEL "comp_addr [%x:%08x] comp_val 0x%08x\n", - dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo, - dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo, dst_addr, - dmae->comp_addr_hi, dmae->comp_addr_lo, dmae->comp_val); + dmae.opcode, dmae.src_addr_hi, dmae.src_addr_lo, + dmae.len, dmae.dst_addr_hi, dmae.dst_addr_lo, dst_addr, + dmae.comp_addr_hi, dmae.comp_addr_lo, dmae.comp_val); DP(BNX2X_MSG_OFF, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n", bp->slowpath->wb_data[0], bp->slowpath->wb_data[1], bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]); + mutex_lock(&bp->dmae_mutex); + *wb_comp = 0; - bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp)); + bnx2x_post_dmae(bp, &dmae, INIT_DMAE_C(bp)); udelay(5); @@ -276,7 +276,7 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr, void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32) { - struct dmae_command *dmae = &bp->init_dmae; + struct dmae_command dmae; u32 *wb_comp = bnx2x_sp(bp, wb_comp); int cnt = 200; @@ -291,41 +291,41 @@ void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32) return; } - mutex_lock(&bp->dmae_mutex); - - memset(bnx2x_sp(bp, wb_data[0]), 0, sizeof(u32) * 4); - memset(dmae, 0, sizeof(struct dmae_command)); + memset(&dmae, 0, sizeof(struct dmae_command)); - dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI | - DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | - DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | + dmae.opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI | + DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | #ifdef __BIG_ENDIAN - DMAE_CMD_ENDIANITY_B_DW_SWAP | + DMAE_CMD_ENDIANITY_B_DW_SWAP | #else - DMAE_CMD_ENDIANITY_DW_SWAP | + DMAE_CMD_ENDIANITY_DW_SWAP | #endif - (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | - (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT)); - dmae->src_addr_lo = src_addr >> 2; - dmae->src_addr_hi = 0; - dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_data)); - dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_data)); - dmae->len = len32; - dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp)); - dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp)); - dmae->comp_val = DMAE_COMP_VAL; + (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | + (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT)); + dmae.src_addr_lo = src_addr >> 2; + dmae.src_addr_hi = 0; + dmae.dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_data)); + dmae.dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_data)); + dmae.len = len32; + dmae.comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp)); + dmae.comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp)); + dmae.comp_val = DMAE_COMP_VAL; DP(BNX2X_MSG_OFF, "DMAE: opcode 0x%08x\n" DP_LEVEL "src_addr [%x:%08x] len [%d *4] " "dst_addr [%x:%08x (%08x)]\n" DP_LEVEL "comp_addr [%x:%08x] comp_val 0x%08x\n", - dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo, - dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo, src_addr, - dmae->comp_addr_hi, dmae->comp_addr_lo, dmae->comp_val); + dmae.opcode, dmae.src_addr_hi, dmae.src_addr_lo, + dmae.len, dmae.dst_addr_hi, dmae.dst_addr_lo, src_addr, + dmae.comp_addr_hi, dmae.comp_addr_lo, dmae.comp_val); + mutex_lock(&bp->dmae_mutex); + + memset(bnx2x_sp(bp, wb_data[0]), 0, sizeof(u32) * 4); *wb_comp = 0; - bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp)); + bnx2x_post_dmae(bp, &dmae, INIT_DMAE_C(bp)); udelay(5); -- cgit v1.2.3-18-g5258 From 54016b260e873d0d4d30cf1fdbd0cdcf0e26251b Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:48 +0000 Subject: bnx2x: Check unzip return code Without this check, when running out of memory, we will see PSOD's in bnx2x_init_fill() when doing a memset(). This is because at that time, bp->gunzip_buf is not pointing to a valid allocated space. Signed-off-by: Benjamin Li Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 59aacd84d7e..edd7b137b76 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -6512,7 +6512,9 @@ static int bnx2x_init_hw(struct bnx2x *bp, u32 load_code) bp->dmae_ready = 0; mutex_init(&bp->dmae_mutex); - bnx2x_gunzip_init(bp); + rc = bnx2x_gunzip_init(bp); + if (rc) + return rc; switch (load_code) { case FW_MSG_CODE_DRV_LOAD_COMMON: -- cgit v1.2.3-18-g5258 From 6f65497b567ef9a518d930ef30fe6b8f27051688 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:51 +0000 Subject: bnx2x: Keep only one HW path active Disable bmac access while working with emac and keep the single lane SerDes in reset while working with 4 lanes XGXS Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_link.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index dc3b69e1fd1..b81a05737d4 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -397,7 +397,8 @@ static u8 bnx2x_emac_enable(struct link_params *params, /* enable access for bmac registers */ REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1); - } + } else + REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0); vars->mac_type = MAC_TYPE_EMAC; return 0; @@ -1021,8 +1022,8 @@ static u8 bnx2x_reset_unicore(struct link_params *params) MDIO_COMBO_IEEE0_MII_CONTROL, (mii_control | MDIO_COMBO_IEEO_MII_CONTROL_RESET)); - - bnx2x_set_serdes_access(params); + if (params->switch_cfg == SWITCH_CFG_1G) + bnx2x_set_serdes_access(params); /* wait for the reset to self clear */ for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) { -- cgit v1.2.3-18-g5258 From 57937203aa077520a7e1665bfb7071b3cbb3f5a9 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:53 +0000 Subject: bnx2x: Remove SGMII configuration when not required Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_link.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index b81a05737d4..c163c42bc1f 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -1276,14 +1276,14 @@ static void bnx2x_program_serdes(struct link_params *params, struct bnx2x *bp = params->bp; u16 reg_val; - /* program duplex, disable autoneg */ - + /* program duplex, disable autoneg and sgmii*/ CL45_RD_OVER_CL22(bp, params->port, params->phy_addr, MDIO_REG_BANK_COMBO_IEEE0, MDIO_COMBO_IEEE0_MII_CONTROL, ®_val); reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX | - MDIO_COMBO_IEEO_MII_CONTROL_AN_EN); + MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | + MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK); if (params->req_duplex == DUPLEX_FULL) reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX; CL45_WR_OVER_CL22(bp, params->port, @@ -5271,6 +5271,13 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, ext_phy_link_up = 0; break; } + /* Set SGMII mode for external phy */ + if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) { + if (vars->line_speed < SPEED_1000) + vars->phy_flags |= PHY_SGMII_FLAG; + else + vars->phy_flags &= ~PHY_SGMII_FLAG; + } } else { /* SerDes */ ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config); -- cgit v1.2.3-18-g5258 From 8924665a7d77bb79ee895b98864e3201507f6ef2 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:56 +0000 Subject: bnx2x: Missing smp_wmb for statistics state machine Signed-off-by: Vladislav Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index edd7b137b76..1e8e7e1efbd 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -4412,6 +4412,9 @@ static void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event) bnx2x_stats_stm[state][event].action(bp); bp->stats_state = bnx2x_stats_stm[state][event].next_state; + /* Make sure the state has been "changed" */ + smp_wmb(); + if ((event != STATS_EVENT_UPDATE) || (bp->msglevel & NETIF_MSG_TIMER)) DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n", state, event, bp->stats_state); -- cgit v1.2.3-18-g5258 From 1ef70b9c12407f0bf332ba775a8aa8f8035d0a24 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:59 +0000 Subject: bnx2x: Re-arrange the link structures for better alignment Change ieee_fc to u16 instead of u32 and re-arrange the link parameters structures Signed-off-by: Yitchak Gertner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_link.c | 6 +++--- drivers/net/bnx2x_link.h | 31 +++++++++++++++++++------------ 2 files changed, 22 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index c163c42bc1f..74f4d1085a3 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -1347,7 +1347,7 @@ static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params) MDIO_OVER_1G_UP3, 0x400); } -static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc) +static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u16 *ieee_fc) { *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX; /* resolve pause mode and advertisement @@ -1381,7 +1381,7 @@ static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc) } static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params, - u32 ieee_fc) + u16 ieee_fc) { struct bnx2x *bp = params->bp; /* for AN, we are always publishing full duplex */ @@ -1389,7 +1389,7 @@ static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params, CL45_WR_OVER_CL22(bp, params->port, params->phy_addr, MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_AUTO_NEG_ADV, (u16)ieee_fc); + MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc); } static void bnx2x_restart_autoneg(struct link_params *params, u8 enable_cl73) diff --git a/drivers/net/bnx2x_link.h b/drivers/net/bnx2x_link.h index 6d26d6c524b..e0d7eef1ced 100644 --- a/drivers/net/bnx2x_link.h +++ b/drivers/net/bnx2x_link.h @@ -81,6 +81,11 @@ struct link_params { #define SWITCH_CFG_AUTO_DETECT PORT_FEATURE_CON_SWITCH_AUTO_DETECT u16 hw_led_mode; /* part of the hw_config read from the shmem */ + + /* phy_addr populated by the phy_init function */ + u8 phy_addr; + /*u8 reserved1;*/ + u32 lane_config; u32 ext_phy_config; #define XGXS_EXT_PHY_TYPE(ext_phy_config) (ext_phy_config & \ @@ -90,39 +95,41 @@ struct link_params { /* Phy register parameter */ u32 chip_id; - /* phy_addr populated by the CLC */ - u8 phy_addr; u16 xgxs_config_rx[4]; /* preemphasis values for the rx side */ - u16 xgxs_config_tx[4]; /* preemphasis values for the tx side */ + u32 feature_config_flags; #define FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED (1<<0) #define FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY (1<<2) #define FEATURE_CONFIG_BCM8727_NOC (1<<3) + /* Device pointer passed to all callback functions */ struct bnx2x *bp; }; /* Output parameters */ struct link_vars { + u8 phy_flags; + + u8 mac_type; +#define MAC_TYPE_NONE 0 +#define MAC_TYPE_EMAC 1 +#define MAC_TYPE_BMAC 2 + u8 phy_link_up; /* internal phy link indication */ u8 link_up; + + u16 line_speed; u16 duplex; + u16 flow_ctrl; - u32 ieee_fc; - u8 mac_type; + u16 ieee_fc; -#define MAC_TYPE_NONE 0 -#define MAC_TYPE_EMAC 1 -#define MAC_TYPE_BMAC 2 - u16 line_speed; u32 autoneg; #define AUTO_NEG_DISABLED 0x0 #define AUTO_NEG_ENABLED 0x1 #define AUTO_NEG_COMPLETE 0x2 -#define AUTO_NEG_PARALLEL_DETECTION_USED 0x3 - - u8 phy_flags; +#define AUTO_NEG_PARALLEL_DETECTION_USED 0x3 /* The same definitions as the shmem parameter */ u32 link_status; -- cgit v1.2.3-18-g5258 From 659bc5c4f2e84e69e1b10b36c16cd52ff7eb317a Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:24:02 +0000 Subject: bnx2x: Using macro for phy address Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_link.c | 108 +++++++++++++---------------------------------- drivers/net/bnx2x_link.h | 12 ++++-- drivers/net/bnx2x_main.c | 8 +--- 3 files changed, 39 insertions(+), 89 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index 74f4d1085a3..c2b001031e7 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -1547,10 +1547,7 @@ static u8 bnx2x_ext_phy_resove_fc(struct link_params *params, u8 ret = 0; u32 ext_phy_type; u8 port = params->port; - ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); - + ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* read twice */ @@ -2011,9 +2008,8 @@ static void bnx2x_ext_phy_reset(struct link_params *params, { struct bnx2x *bp = params->bp; u32 ext_phy_type; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); + DP(NETIF_MSG_LINK, "Port %x: bnx2x_ext_phy_reset\n", params->port); ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* The PHY reset is controled by GPIO 1 @@ -2292,9 +2288,7 @@ static void bnx2x_bcm8072_external_rom_boot(struct link_params *params) { struct bnx2x *bp = params->bp; u8 port = params->port; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* Need to wait 200ms after reset */ @@ -2342,9 +2336,7 @@ static u8 bnx2x_8073_is_snr_needed(struct link_params *params) /* This is only required for 8073A1, version 102 only */ struct bnx2x *bp = params->bp; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u16 val; /* Read 8073 HW revision*/ @@ -2375,9 +2367,7 @@ static u8 bnx2x_8073_is_snr_needed(struct link_params *params) static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params) { struct bnx2x *bp = params->bp; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u16 val, cnt, cnt1 ; bnx2x_cl45_read(bp, params->port, @@ -2519,9 +2509,7 @@ static void bnx2x_bcm8726_external_rom_boot(struct link_params *params) { struct bnx2x *bp = params->bp; u8 port = params->port; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* Need to wait 100ms after reset */ @@ -2607,9 +2595,7 @@ static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params, u16 val = 0; u16 i; u8 port = params->port; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); if (byte_cnt > 16) { DP(NETIF_MSG_LINK, "Reading from eeprom is" @@ -2691,9 +2677,7 @@ static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params, struct bnx2x *bp = params->bp; u16 val, i; u8 port = params->port; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); if (byte_cnt > 16) { @@ -2946,9 +2930,7 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params, { struct bnx2x *bp = params->bp; u8 port = params->port; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u16 cur_limiting_mode; bnx2x_cl45_read(bp, port, @@ -3014,9 +2996,7 @@ static u8 bnx2x_bcm8727_set_limiting_mode(struct link_params *params, u8 port = params->port; u16 phy_identifier; u16 rom_ver2_val; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, @@ -3120,9 +3100,7 @@ static u8 bnx2x_sfp_module_detection(struct link_params *params) struct bnx2x *bp = params->bp; u16 edc_mode; u8 rc = 0; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); u32 val = REG_RD(bp, params->shmem_base + offsetof(struct shmem_region, dev_info. @@ -3212,9 +3190,8 @@ void bnx2x_handle_module_detect_int(struct link_params *params) else DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n"); } else { - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); + u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); u32 val = REG_RD(bp, params->shmem_base + @@ -3238,9 +3215,7 @@ static void bnx2x_bcm807x_force_10G(struct link_params *params) { struct bnx2x *bp = params->bp; u8 port = params->port; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* Force KR or KX */ @@ -3266,9 +3241,7 @@ static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params) struct bnx2x *bp = params->bp; u8 port = params->port; u16 val; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); bnx2x_cl45_read(bp, params->port, @@ -3333,9 +3306,7 @@ static void bnx2x_8073_set_pause_cl37(struct link_params *params, struct bnx2x *bp = params->bp; u16 cl37_val; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); bnx2x_cl45_read(bp, params->port, @@ -3378,9 +3349,7 @@ static void bnx2x_ext_phy_set_pause(struct link_params *params, { struct bnx2x *bp = params->bp; u16 val; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* read modify write pause advertizing */ @@ -3617,9 +3586,7 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) u16 val = 0; u8 rc = 0; if (vars->phy_flags & PHY_XGXS_FLAG) { - ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* Make sure that the soft reset is off (expect for the 8072: @@ -4555,9 +4522,7 @@ static void bnx2x_8727_handle_mod_abs(struct link_params *params) { struct bnx2x *bp = params->bp; u16 mod_abs, rx_alarm_status; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 val = REG_RD(bp, params->shmem_base + offsetof(struct shmem_region, dev_info. port_feature_config[params->port]. @@ -4657,10 +4622,7 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, u8 ext_phy_link_up = 0; u8 port = params->port; if (vars->phy_flags & PHY_XGXS_FLAG) { - ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); - + ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); switch (ext_phy_type) { case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: @@ -5608,10 +5570,8 @@ static void bnx2x_ext_phy_loopback(struct link_params *params) if (params->switch_cfg == SWITCH_CFG_10G) { ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); /* CL37 Autoneg Enabled */ - ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); switch (ext_phy_type) { case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN: @@ -6180,9 +6140,8 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, { /* Disable Transmitter */ - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = + XGXS_EXT_PHY_ADDR(params->ext_phy_config); if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) bnx2x_sfp_set_transmitter(bp, port, @@ -6200,9 +6159,8 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: { - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = + XGXS_EXT_PHY_ADDR(params->ext_phy_config); /* Set soft reset */ bnx2x_8726_reset_phy(bp, params->port, ext_phy_addr); break; @@ -6420,10 +6378,7 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base) NIG_MASK_SERDES0_LINK_STATUS | NIG_MASK_MI_INT)); - ext_phy_addr[port] = - ((ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + ext_phy_addr[port] = XGXS_EXT_PHY_ADDR(ext_phy_config); /* Need to take the phy out of low power mode in order to write to access its registers */ @@ -6549,9 +6504,7 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) NIG_MASK_SERDES0_LINK_STATUS | NIG_MASK_MI_INT)); - ext_phy_addr[port] = ((ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + ext_phy_addr[port] = XGXS_EXT_PHY_ADDR(ext_phy_config); /* Reset the phy */ bnx2x_cl45_write(bp, port, @@ -6609,10 +6562,7 @@ static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base) offsetof(struct shmem_region, dev_info.port_hw_config[port].external_phy_config)); - ext_phy_addr = - ((ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + ext_phy_addr = XGXS_EXT_PHY_ADDR(ext_phy_config); DP(NETIF_MSG_LINK, "8726_common_init : ext_phy_addr = 0x%x\n", ext_phy_addr); diff --git a/drivers/net/bnx2x_link.h b/drivers/net/bnx2x_link.h index e0d7eef1ced..f3e252264e1 100644 --- a/drivers/net/bnx2x_link.h +++ b/drivers/net/bnx2x_link.h @@ -88,10 +88,14 @@ struct link_params { u32 lane_config; u32 ext_phy_config; -#define XGXS_EXT_PHY_TYPE(ext_phy_config) (ext_phy_config & \ - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK) -#define SERDES_EXT_PHY_TYPE(ext_phy_config) (ext_phy_config & \ - PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) +#define XGXS_EXT_PHY_TYPE(ext_phy_config) \ + ((ext_phy_config) & PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK) +#define XGXS_EXT_PHY_ADDR(ext_phy_config) \ + (((ext_phy_config) & PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> \ + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT) +#define SERDES_EXT_PHY_TYPE(ext_phy_config) \ + ((ext_phy_config) & PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) + /* Phy register parameter */ u32 chip_id; diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 1e8e7e1efbd..d22c6b7f7da 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -8546,9 +8546,7 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) else if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) && (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) bp->mdio.prtad = - (bp->link_params.ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT; + XGXS_EXT_PHY_ADDR(bp->link_params.ext_phy_config); val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper); val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower); @@ -9549,9 +9547,7 @@ static int bnx2x_set_eeprom(struct net_device *dev, if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) { u8 ext_phy_addr = - (bp->link_params.ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT; + XGXS_EXT_PHY_ADDR(bp->link_params.ext_phy_config); /* DSP Remove Download Mode */ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, -- cgit v1.2.3-18-g5258 From 0fc5d0094de11bb005c35f03fb1d3b52b0bd85e3 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:24:05 +0000 Subject: bnx2x: Adding explicit casting Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index d22c6b7f7da..6b6aa89f752 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -2927,7 +2927,7 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) REG_WR(bp, reg_offset, val); BNX2X_ERR("FATAL HW block attention set0 0x%x\n", - (attn & HW_INTERRUT_ASSERT_SET_0)); + (u32)(attn & HW_INTERRUT_ASSERT_SET_0)); bnx2x_panic(); } } @@ -2958,7 +2958,7 @@ static inline void bnx2x_attn_int_deasserted1(struct bnx2x *bp, u32 attn) REG_WR(bp, reg_offset, val); BNX2X_ERR("FATAL HW block attention set1 0x%x\n", - (attn & HW_INTERRUT_ASSERT_SET_1)); + (u32)(attn & HW_INTERRUT_ASSERT_SET_1)); bnx2x_panic(); } } @@ -2998,7 +2998,7 @@ static inline void bnx2x_attn_int_deasserted2(struct bnx2x *bp, u32 attn) REG_WR(bp, reg_offset, val); BNX2X_ERR("FATAL HW block attention set2 0x%x\n", - (attn & HW_INTERRUT_ASSERT_SET_2)); + (u32)(attn & HW_INTERRUT_ASSERT_SET_2)); bnx2x_panic(); } } -- cgit v1.2.3-18-g5258 From e4ed7113372a04df9b7aa985ce3860207dbb1141 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:24:10 +0000 Subject: bnx2x: Using PCI_DEVICE macro Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 6b6aa89f752..b084e8b531a 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -138,12 +138,9 @@ static struct { static const struct pci_device_id bnx2x_pci_tbl[] = { - { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57710, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM57710 }, - { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57711, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM57711 }, - { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57711E, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM57711E }, + { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57710), BCM57710 }, + { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711), BCM57711 }, + { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711E), BCM57711E }, { 0 } }; -- cgit v1.2.3-18-g5258 From 573f203574581faaf80ca4fc079d33452327fc3b Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:24:14 +0000 Subject: bnx2x: Re-factor the initialization code Moving the code to a more logical place and beautifying it. No real change in behavior. Signed-off-by: Vladislav Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x.h | 28 ++- drivers/net/bnx2x_init.h | 320 ++++++--------------------------- drivers/net/bnx2x_init_ops.h | 419 ++++++++++++++++++++++++------------------- drivers/net/bnx2x_main.c | 79 +++++--- drivers/net/bnx2x_reg.h | 113 ++++++++++++ 5 files changed, 495 insertions(+), 464 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index a231780061c..97bc5e046f4 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -116,16 +116,22 @@ #define REG_RD_DMAE(bp, offset, valp, len32) \ do { \ bnx2x_read_dmae(bp, offset, len32);\ - memcpy(valp, bnx2x_sp(bp, wb_data[0]), len32 * 4); \ + memcpy(valp, bnx2x_sp(bp, wb_data[0]), (len32) * 4); \ } while (0) #define REG_WR_DMAE(bp, offset, valp, len32) \ do { \ - memcpy(bnx2x_sp(bp, wb_data[0]), valp, len32 * 4); \ + memcpy(bnx2x_sp(bp, wb_data[0]), valp, (len32) * 4); \ bnx2x_write_dmae(bp, bnx2x_sp_mapping(bp, wb_data), \ offset, len32); \ } while (0) +#define VIRT_WR_DMAE_LEN(bp, data, addr, len32) \ + do { \ + memcpy(GUNZIP_BUF(bp), data, (len32) * 4); \ + bnx2x_write_big_buf_wb(bp, addr, len32); \ + } while (0) + #define SHMEM_ADDR(bp, field) (bp->common.shmem_base + \ offsetof(struct shmem_region, field)) #define SHMEM_RD(bp, field) REG_RD(bp, SHMEM_ADDR(bp, field)) @@ -988,6 +994,9 @@ struct bnx2x { dma_addr_t gunzip_mapping; int gunzip_outlen; #define FW_BUF_SIZE 0x8000 +#define GUNZIP_BUF(bp) (bp->gunzip_buf) +#define GUNZIP_PHYS(bp) (bp->gunzip_mapping) +#define GUNZIP_OUTLEN(bp) (bp->gunzip_outlen) struct raw_op *init_ops; /* Init blocks offsets inside init_ops */ @@ -1003,6 +1012,18 @@ struct bnx2x { const u8 *xsem_pram_data; const u8 *csem_int_table_data; const u8 *csem_pram_data; +#define INIT_OPS(bp) (bp->init_ops) +#define INIT_OPS_OFFSETS(bp) (bp->init_ops_offsets) +#define INIT_DATA(bp) (bp->init_data) +#define INIT_TSEM_INT_TABLE_DATA(bp) (bp->tsem_int_table_data) +#define INIT_TSEM_PRAM_DATA(bp) (bp->tsem_pram_data) +#define INIT_USEM_INT_TABLE_DATA(bp) (bp->usem_int_table_data) +#define INIT_USEM_PRAM_DATA(bp) (bp->usem_pram_data) +#define INIT_XSEM_INT_TABLE_DATA(bp) (bp->xsem_int_table_data) +#define INIT_XSEM_PRAM_DATA(bp) (bp->xsem_pram_data) +#define INIT_CSEM_INT_TABLE_DATA(bp) (bp->csem_int_table_data) +#define INIT_CSEM_PRAM_DATA(bp) (bp->csem_pram_data) + const struct firmware *firmware; }; @@ -1030,6 +1051,9 @@ int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port); int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port); int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port); u32 bnx2x_fw_command(struct bnx2x *bp, u32 command); +void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val); +void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr, + u32 addr, u32 len); static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, int wait) diff --git a/drivers/net/bnx2x_init.h b/drivers/net/bnx2x_init.h index 3ba4d888068..65b26cbfe3e 100644 --- a/drivers/net/bnx2x_init.h +++ b/drivers/net/bnx2x_init.h @@ -15,24 +15,11 @@ #ifndef BNX2X_INIT_H #define BNX2X_INIT_H -#define COMMON 0x1 -#define PORT0 0x2 -#define PORT1 0x4 - -#define INIT_EMULATION 0x1 -#define INIT_FPGA 0x2 -#define INIT_ASIC 0x4 -#define INIT_HARDWARE 0x7 - -#define TSTORM_INTMEM_ADDR TSEM_REG_FAST_MEMORY -#define CSTORM_INTMEM_ADDR CSEM_REG_FAST_MEMORY -#define XSTORM_INTMEM_ADDR XSEM_REG_FAST_MEMORY -#define USTORM_INTMEM_ADDR USEM_REG_FAST_MEMORY /* RAM0 size in bytes */ #define STORM_INTMEM_SIZE_E1 0x5800 #define STORM_INTMEM_SIZE_E1H 0x10000 -#define STORM_INTMEM_SIZE(bp) ((CHIP_IS_E1H(bp) ? STORM_INTMEM_SIZE_E1H : \ - STORM_INTMEM_SIZE_E1) / 4) +#define STORM_INTMEM_SIZE(bp) ((CHIP_IS_E1(bp) ? STORM_INTMEM_SIZE_E1 : \ + STORM_INTMEM_SIZE_E1H) / 4) /* Init operation types and structures */ @@ -53,65 +40,68 @@ #define OP_WR_ASIC 0xc /* write single register on ASIC */ /* Init stages */ -#define COMMON_STAGE 0 -#define PORT0_STAGE 1 -#define PORT1_STAGE 2 -/* Never reorder FUNCx stages !!! */ -#define FUNC0_STAGE 3 -#define FUNC1_STAGE 4 -#define FUNC2_STAGE 5 -#define FUNC3_STAGE 6 -#define FUNC4_STAGE 7 -#define FUNC5_STAGE 8 -#define FUNC6_STAGE 9 -#define FUNC7_STAGE 10 -#define STAGE_IDX_MAX 11 - -#define STAGE_START 0 -#define STAGE_END 1 +/* Never reorder stages !!! */ +#define COMMON_STAGE 0 +#define PORT0_STAGE 1 +#define PORT1_STAGE 2 +#define FUNC0_STAGE 3 +#define FUNC1_STAGE 4 +#define FUNC2_STAGE 5 +#define FUNC3_STAGE 6 +#define FUNC4_STAGE 7 +#define FUNC5_STAGE 8 +#define FUNC6_STAGE 9 +#define FUNC7_STAGE 10 +#define STAGE_IDX_MAX 11 + +#define STAGE_START 0 +#define STAGE_END 1 /* Indices of blocks */ -#define PRS_BLOCK 0 -#define SRCH_BLOCK 1 -#define TSDM_BLOCK 2 -#define TCM_BLOCK 3 -#define BRB1_BLOCK 4 -#define TSEM_BLOCK 5 -#define PXPCS_BLOCK 6 -#define EMAC0_BLOCK 7 -#define EMAC1_BLOCK 8 -#define DBU_BLOCK 9 -#define MISC_BLOCK 10 -#define DBG_BLOCK 11 -#define NIG_BLOCK 12 -#define MCP_BLOCK 13 -#define UPB_BLOCK 14 -#define CSDM_BLOCK 15 -#define USDM_BLOCK 16 -#define CCM_BLOCK 17 -#define UCM_BLOCK 18 -#define USEM_BLOCK 19 -#define CSEM_BLOCK 20 -#define XPB_BLOCK 21 -#define DQ_BLOCK 22 -#define TIMERS_BLOCK 23 -#define XSDM_BLOCK 24 -#define QM_BLOCK 25 -#define PBF_BLOCK 26 -#define XCM_BLOCK 27 -#define XSEM_BLOCK 28 -#define CDU_BLOCK 29 -#define DMAE_BLOCK 30 -#define PXP_BLOCK 31 -#define CFC_BLOCK 32 -#define HC_BLOCK 33 -#define PXP2_BLOCK 34 -#define MISC_AEU_BLOCK 35 +#define PRS_BLOCK 0 +#define SRCH_BLOCK 1 +#define TSDM_BLOCK 2 +#define TCM_BLOCK 3 +#define BRB1_BLOCK 4 +#define TSEM_BLOCK 5 +#define PXPCS_BLOCK 6 +#define EMAC0_BLOCK 7 +#define EMAC1_BLOCK 8 +#define DBU_BLOCK 9 +#define MISC_BLOCK 10 +#define DBG_BLOCK 11 +#define NIG_BLOCK 12 +#define MCP_BLOCK 13 +#define UPB_BLOCK 14 +#define CSDM_BLOCK 15 +#define USDM_BLOCK 16 +#define CCM_BLOCK 17 +#define UCM_BLOCK 18 +#define USEM_BLOCK 19 +#define CSEM_BLOCK 20 +#define XPB_BLOCK 21 +#define DQ_BLOCK 22 +#define TIMERS_BLOCK 23 +#define XSDM_BLOCK 24 +#define QM_BLOCK 25 +#define PBF_BLOCK 26 +#define XCM_BLOCK 27 +#define XSEM_BLOCK 28 +#define CDU_BLOCK 29 +#define DMAE_BLOCK 30 +#define PXP_BLOCK 31 +#define CFC_BLOCK 32 +#define HC_BLOCK 33 +#define PXP2_BLOCK 34 +#define MISC_AEU_BLOCK 35 +#define PGLUE_B_BLOCK 36 +#define IGU_BLOCK 37 + /* Returns the index of start or end of a specific block stage in ops array*/ #define BLOCK_OPS_IDX(block, stage, end) \ - (2*(((block)*STAGE_IDX_MAX) + (stage)) + (end)) + (2*(((block)*STAGE_IDX_MAX) + (stage)) + (end)) struct raw_op { @@ -158,199 +148,5 @@ union init_op { struct raw_op raw; }; -/**************************************************************************** -* PXP -****************************************************************************/ -/* - * This code configures the PCI read/write arbiter - * which implements a weighted round robin - * between the virtual queues in the chip. - * - * The values were derived for each PCI max payload and max request size. - * since max payload and max request size are only known at run time, - * this is done as a separate init stage. - */ - -#define NUM_WR_Q 13 -#define NUM_RD_Q 29 -#define MAX_RD_ORD 3 -#define MAX_WR_ORD 2 - -/* configuration for one arbiter queue */ -struct arb_line { - int l; - int add; - int ubound; -}; - -/* derived configuration for each read queue for each max request size */ -static const struct arb_line read_arb_data[NUM_RD_Q][MAX_RD_ORD + 1] = { -/* 1 */ { {8, 64, 25}, {16, 64, 25}, {32, 64, 25}, {64, 64, 41} }, - { {4, 8, 4}, {4, 8, 4}, {4, 8, 4}, {4, 8, 4} }, - { {4, 3, 3}, {4, 3, 3}, {4, 3, 3}, {4, 3, 3} }, - { {8, 3, 6}, {16, 3, 11}, {16, 3, 11}, {16, 3, 11} }, - { {8, 64, 25}, {16, 64, 25}, {32, 64, 25}, {64, 64, 41} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {64, 3, 41} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {64, 3, 41} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {64, 3, 41} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {64, 3, 41} }, -/* 10 */{ {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, -/* 20 */{ {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, - { {8, 64, 25}, {16, 64, 41}, {32, 64, 81}, {64, 64, 120} } -}; - -/* derived configuration for each write queue for each max request size */ -static const struct arb_line write_arb_data[NUM_WR_Q][MAX_WR_ORD + 1] = { -/* 1 */ { {4, 6, 3}, {4, 6, 3}, {4, 6, 3} }, - { {4, 2, 3}, {4, 2, 3}, {4, 2, 3} }, - { {8, 2, 6}, {16, 2, 11}, {16, 2, 11} }, - { {8, 2, 6}, {16, 2, 11}, {32, 2, 21} }, - { {8, 2, 6}, {16, 2, 11}, {32, 2, 21} }, - { {8, 2, 6}, {16, 2, 11}, {32, 2, 21} }, - { {8, 64, 25}, {16, 64, 25}, {32, 64, 25} }, - { {8, 2, 6}, {16, 2, 11}, {16, 2, 11} }, - { {8, 2, 6}, {16, 2, 11}, {16, 2, 11} }, -/* 10 */{ {8, 9, 6}, {16, 9, 11}, {32, 9, 21} }, - { {8, 47, 19}, {16, 47, 19}, {32, 47, 21} }, - { {8, 9, 6}, {16, 9, 11}, {16, 9, 11} }, - { {8, 64, 25}, {16, 64, 41}, {32, 64, 81} } -}; - -/* register addresses for read queues */ -static const struct arb_line read_arb_addr[NUM_RD_Q-1] = { -/* 1 */ {PXP2_REG_RQ_BW_RD_L0, PXP2_REG_RQ_BW_RD_ADD0, - PXP2_REG_RQ_BW_RD_UBOUND0}, - {PXP2_REG_PSWRQ_BW_L1, PXP2_REG_PSWRQ_BW_ADD1, - PXP2_REG_PSWRQ_BW_UB1}, - {PXP2_REG_PSWRQ_BW_L2, PXP2_REG_PSWRQ_BW_ADD2, - PXP2_REG_PSWRQ_BW_UB2}, - {PXP2_REG_PSWRQ_BW_L3, PXP2_REG_PSWRQ_BW_ADD3, - PXP2_REG_PSWRQ_BW_UB3}, - {PXP2_REG_RQ_BW_RD_L4, PXP2_REG_RQ_BW_RD_ADD4, - PXP2_REG_RQ_BW_RD_UBOUND4}, - {PXP2_REG_RQ_BW_RD_L5, PXP2_REG_RQ_BW_RD_ADD5, - PXP2_REG_RQ_BW_RD_UBOUND5}, - {PXP2_REG_PSWRQ_BW_L6, PXP2_REG_PSWRQ_BW_ADD6, - PXP2_REG_PSWRQ_BW_UB6}, - {PXP2_REG_PSWRQ_BW_L7, PXP2_REG_PSWRQ_BW_ADD7, - PXP2_REG_PSWRQ_BW_UB7}, - {PXP2_REG_PSWRQ_BW_L8, PXP2_REG_PSWRQ_BW_ADD8, - PXP2_REG_PSWRQ_BW_UB8}, -/* 10 */{PXP2_REG_PSWRQ_BW_L9, PXP2_REG_PSWRQ_BW_ADD9, - PXP2_REG_PSWRQ_BW_UB9}, - {PXP2_REG_PSWRQ_BW_L10, PXP2_REG_PSWRQ_BW_ADD10, - PXP2_REG_PSWRQ_BW_UB10}, - {PXP2_REG_PSWRQ_BW_L11, PXP2_REG_PSWRQ_BW_ADD11, - PXP2_REG_PSWRQ_BW_UB11}, - {PXP2_REG_RQ_BW_RD_L12, PXP2_REG_RQ_BW_RD_ADD12, - PXP2_REG_RQ_BW_RD_UBOUND12}, - {PXP2_REG_RQ_BW_RD_L13, PXP2_REG_RQ_BW_RD_ADD13, - PXP2_REG_RQ_BW_RD_UBOUND13}, - {PXP2_REG_RQ_BW_RD_L14, PXP2_REG_RQ_BW_RD_ADD14, - PXP2_REG_RQ_BW_RD_UBOUND14}, - {PXP2_REG_RQ_BW_RD_L15, PXP2_REG_RQ_BW_RD_ADD15, - PXP2_REG_RQ_BW_RD_UBOUND15}, - {PXP2_REG_RQ_BW_RD_L16, PXP2_REG_RQ_BW_RD_ADD16, - PXP2_REG_RQ_BW_RD_UBOUND16}, - {PXP2_REG_RQ_BW_RD_L17, PXP2_REG_RQ_BW_RD_ADD17, - PXP2_REG_RQ_BW_RD_UBOUND17}, - {PXP2_REG_RQ_BW_RD_L18, PXP2_REG_RQ_BW_RD_ADD18, - PXP2_REG_RQ_BW_RD_UBOUND18}, -/* 20 */{PXP2_REG_RQ_BW_RD_L19, PXP2_REG_RQ_BW_RD_ADD19, - PXP2_REG_RQ_BW_RD_UBOUND19}, - {PXP2_REG_RQ_BW_RD_L20, PXP2_REG_RQ_BW_RD_ADD20, - PXP2_REG_RQ_BW_RD_UBOUND20}, - {PXP2_REG_RQ_BW_RD_L22, PXP2_REG_RQ_BW_RD_ADD22, - PXP2_REG_RQ_BW_RD_UBOUND22}, - {PXP2_REG_RQ_BW_RD_L23, PXP2_REG_RQ_BW_RD_ADD23, - PXP2_REG_RQ_BW_RD_UBOUND23}, - {PXP2_REG_RQ_BW_RD_L24, PXP2_REG_RQ_BW_RD_ADD24, - PXP2_REG_RQ_BW_RD_UBOUND24}, - {PXP2_REG_RQ_BW_RD_L25, PXP2_REG_RQ_BW_RD_ADD25, - PXP2_REG_RQ_BW_RD_UBOUND25}, - {PXP2_REG_RQ_BW_RD_L26, PXP2_REG_RQ_BW_RD_ADD26, - PXP2_REG_RQ_BW_RD_UBOUND26}, - {PXP2_REG_RQ_BW_RD_L27, PXP2_REG_RQ_BW_RD_ADD27, - PXP2_REG_RQ_BW_RD_UBOUND27}, - {PXP2_REG_PSWRQ_BW_L28, PXP2_REG_PSWRQ_BW_ADD28, - PXP2_REG_PSWRQ_BW_UB28} -}; - -/* register addresses for write queues */ -static const struct arb_line write_arb_addr[NUM_WR_Q-1] = { -/* 1 */ {PXP2_REG_PSWRQ_BW_L1, PXP2_REG_PSWRQ_BW_ADD1, - PXP2_REG_PSWRQ_BW_UB1}, - {PXP2_REG_PSWRQ_BW_L2, PXP2_REG_PSWRQ_BW_ADD2, - PXP2_REG_PSWRQ_BW_UB2}, - {PXP2_REG_PSWRQ_BW_L3, PXP2_REG_PSWRQ_BW_ADD3, - PXP2_REG_PSWRQ_BW_UB3}, - {PXP2_REG_PSWRQ_BW_L6, PXP2_REG_PSWRQ_BW_ADD6, - PXP2_REG_PSWRQ_BW_UB6}, - {PXP2_REG_PSWRQ_BW_L7, PXP2_REG_PSWRQ_BW_ADD7, - PXP2_REG_PSWRQ_BW_UB7}, - {PXP2_REG_PSWRQ_BW_L8, PXP2_REG_PSWRQ_BW_ADD8, - PXP2_REG_PSWRQ_BW_UB8}, - {PXP2_REG_PSWRQ_BW_L9, PXP2_REG_PSWRQ_BW_ADD9, - PXP2_REG_PSWRQ_BW_UB9}, - {PXP2_REG_PSWRQ_BW_L10, PXP2_REG_PSWRQ_BW_ADD10, - PXP2_REG_PSWRQ_BW_UB10}, - {PXP2_REG_PSWRQ_BW_L11, PXP2_REG_PSWRQ_BW_ADD11, - PXP2_REG_PSWRQ_BW_UB11}, -/* 10 */{PXP2_REG_PSWRQ_BW_L28, PXP2_REG_PSWRQ_BW_ADD28, - PXP2_REG_PSWRQ_BW_UB28}, - {PXP2_REG_RQ_BW_WR_L29, PXP2_REG_RQ_BW_WR_ADD29, - PXP2_REG_RQ_BW_WR_UBOUND29}, - {PXP2_REG_RQ_BW_WR_L30, PXP2_REG_RQ_BW_WR_ADD30, - PXP2_REG_RQ_BW_WR_UBOUND30} -}; - - -/**************************************************************************** -* CDU -****************************************************************************/ - -#define CDU_REGION_NUMBER_XCM_AG 2 -#define CDU_REGION_NUMBER_UCM_AG 4 - -/** - * String-to-compress [31:8] = CID (all 24 bits) - * String-to-compress [7:4] = Region - * String-to-compress [3:0] = Type - */ -#define CDU_VALID_DATA(_cid, _region, _type) \ - (((_cid) << 8) | (((_region) & 0xf) << 4) | (((_type) & 0xf))) -#define CDU_CRC8(_cid, _region, _type) \ - calc_crc8(CDU_VALID_DATA(_cid, _region, _type), 0xff) -#define CDU_RSRVD_VALUE_TYPE_A(_cid, _region, _type) \ - (0x80 | (CDU_CRC8(_cid, _region, _type) & 0x7f)) -#define CDU_RSRVD_VALUE_TYPE_B(_crc, _type) \ - (0x80 | ((_type) & 0xf << 3) | (CDU_CRC8(_cid, _region, _type) & 0x7)) -#define CDU_RSRVD_INVALIDATE_CONTEXT_VALUE(_val) ((_val) & ~0x80) - - -/* registers addresses are not in order - so these arrays help simplify the code */ -static const int cm_blocks[9] = { - MISC_BLOCK, TCM_BLOCK, UCM_BLOCK, CCM_BLOCK, XCM_BLOCK, - TSEM_BLOCK, USEM_BLOCK, CSEM_BLOCK, XSEM_BLOCK -}; - #endif /* BNX2X_INIT_H */ diff --git a/drivers/net/bnx2x_init_ops.h b/drivers/net/bnx2x_init_ops.h index 32552b9366c..38b970a14fd 100644 --- a/drivers/net/bnx2x_init_ops.h +++ b/drivers/net/bnx2x_init_ops.h @@ -11,85 +11,68 @@ * Maintained by: Eilon Greenstein * Written by: Vladislav Zolotarov */ + #ifndef BNX2X_INIT_OPS_H #define BNX2X_INIT_OPS_H -static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val); static int bnx2x_gunzip(struct bnx2x *bp, const u8 *zbuf, int len); + static void bnx2x_init_str_wr(struct bnx2x *bp, u32 addr, const u32 *data, u32 len) { - int i; + u32 i; - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) REG_WR(bp, addr + i*4, data[i]); - if (!(i % 10000)) { - touch_softlockup_watchdog(); - cpu_relax(); - } - } } static void bnx2x_init_ind_wr(struct bnx2x *bp, u32 addr, const u32 *data, - u16 len) + u32 len) { - int i; + u32 i; - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) REG_WR_IND(bp, addr + i*4, data[i]); - if (!(i % 10000)) { - touch_softlockup_watchdog(); - cpu_relax(); - } - } } static void bnx2x_write_big_buf(struct bnx2x *bp, u32 addr, u32 len) { - int offset = 0; - - if (bp->dmae_ready) { - while (len > DMAE_LEN32_WR_MAX) { - bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, - addr + offset, DMAE_LEN32_WR_MAX); - offset += DMAE_LEN32_WR_MAX * 4; - len -= DMAE_LEN32_WR_MAX; - } - bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, - addr + offset, len); - } else - bnx2x_init_str_wr(bp, addr, bp->gunzip_buf, len); + if (bp->dmae_ready) + bnx2x_write_dmae_phys_len(bp, GUNZIP_PHYS(bp), addr, len); + else + bnx2x_init_str_wr(bp, addr, GUNZIP_BUF(bp), len); } static void bnx2x_init_fill(struct bnx2x *bp, u32 addr, int fill, u32 len) { - u32 buf_len = (((len * 4) > FW_BUF_SIZE) ? FW_BUF_SIZE : (len * 4)); - u32 buf_len32 = buf_len / 4; - int i; + u32 buf_len = (((len*4) > FW_BUF_SIZE) ? FW_BUF_SIZE : (len*4)); + u32 buf_len32 = buf_len/4; + u32 i; - memset(bp->gunzip_buf, fill, buf_len); + memset(GUNZIP_BUF(bp), (u8)fill, buf_len); for (i = 0; i < len; i += buf_len32) { u32 cur_len = min(buf_len32, len - i); - bnx2x_write_big_buf(bp, addr + i * 4, cur_len); + bnx2x_write_big_buf(bp, addr + i*4, cur_len); } } static void bnx2x_init_wr_64(struct bnx2x *bp, u32 addr, const u32 *data, u32 len64) { - u32 buf_len32 = FW_BUF_SIZE / 4; - u32 len = len64 * 2; + u32 buf_len32 = FW_BUF_SIZE/4; + u32 len = len64*2; u64 data64 = 0; - int i; + u32 i; /* 64 bit value is in a blob: first low DWORD, then high DWORD */ data64 = HILO_U64((*(data + 1)), (*data)); + len64 = min((u32)(FW_BUF_SIZE/8), len64); for (i = 0; i < len64; i++) { - u64 *pdata = ((u64 *)(bp->gunzip_buf)) + i; + u64 *pdata = ((u64 *)(GUNZIP_BUF(bp))) + i; *pdata = data64; } @@ -97,7 +80,7 @@ static void bnx2x_init_wr_64(struct bnx2x *bp, u32 addr, const u32 *data, for (i = 0; i < len; i += buf_len32) { u32 cur_len = min(buf_len32, len - i); - bnx2x_write_big_buf(bp, addr + i * 4, cur_len); + bnx2x_write_big_buf(bp, addr + i*4, cur_len); } } @@ -118,97 +101,81 @@ static void bnx2x_init_wr_64(struct bnx2x *bp, u32 addr, const u32 *data, static const u8 *bnx2x_sel_blob(struct bnx2x *bp, u32 addr, const u8 *data) { IF_IS_INT_TABLE_ADDR(TSEM_REG_INT_TABLE, addr) - data = bp->tsem_int_table_data; - else IF_IS_INT_TABLE_ADDR(CSEM_REG_INT_TABLE, addr) - data = bp->csem_int_table_data; - else IF_IS_INT_TABLE_ADDR(USEM_REG_INT_TABLE, addr) - data = bp->usem_int_table_data; - else IF_IS_INT_TABLE_ADDR(XSEM_REG_INT_TABLE, addr) - data = bp->xsem_int_table_data; - else IF_IS_PRAM_ADDR(TSEM_REG_PRAM, addr) - data = bp->tsem_pram_data; - else IF_IS_PRAM_ADDR(CSEM_REG_PRAM, addr) - data = bp->csem_pram_data; - else IF_IS_PRAM_ADDR(USEM_REG_PRAM, addr) - data = bp->usem_pram_data; - else IF_IS_PRAM_ADDR(XSEM_REG_PRAM, addr) - data = bp->xsem_pram_data; + data = INIT_TSEM_INT_TABLE_DATA(bp); + else + IF_IS_INT_TABLE_ADDR(CSEM_REG_INT_TABLE, addr) + data = INIT_CSEM_INT_TABLE_DATA(bp); + else + IF_IS_INT_TABLE_ADDR(USEM_REG_INT_TABLE, addr) + data = INIT_USEM_INT_TABLE_DATA(bp); + else + IF_IS_INT_TABLE_ADDR(XSEM_REG_INT_TABLE, addr) + data = INIT_XSEM_INT_TABLE_DATA(bp); + else + IF_IS_PRAM_ADDR(TSEM_REG_PRAM, addr) + data = INIT_TSEM_PRAM_DATA(bp); + else + IF_IS_PRAM_ADDR(CSEM_REG_PRAM, addr) + data = INIT_CSEM_PRAM_DATA(bp); + else + IF_IS_PRAM_ADDR(USEM_REG_PRAM, addr) + data = INIT_USEM_PRAM_DATA(bp); + else + IF_IS_PRAM_ADDR(XSEM_REG_PRAM, addr) + data = INIT_XSEM_PRAM_DATA(bp); return data; } static void bnx2x_write_big_buf_wb(struct bnx2x *bp, u32 addr, u32 len) { - int offset = 0; - - if (bp->dmae_ready) { - while (len > DMAE_LEN32_WR_MAX) { - bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, - addr + offset, DMAE_LEN32_WR_MAX); - offset += DMAE_LEN32_WR_MAX * 4; - len -= DMAE_LEN32_WR_MAX; - } - bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, - addr + offset, len); - } else - bnx2x_init_ind_wr(bp, addr, bp->gunzip_buf, len); + if (bp->dmae_ready) + bnx2x_write_dmae_phys_len(bp, GUNZIP_PHYS(bp), addr, len); + else + bnx2x_init_ind_wr(bp, addr, GUNZIP_BUF(bp), len); } static void bnx2x_init_wr_wb(struct bnx2x *bp, u32 addr, const u32 *data, u32 len) { - /* This is needed for NO_ZIP mode, currently supported - in little endian mode only */ - data = (const u32*)bnx2x_sel_blob(bp, addr, (const u8*)data); + data = (const u32 *)bnx2x_sel_blob(bp, addr, (const u8 *)data); - if ((len * 4) > FW_BUF_SIZE) { - BNX2X_ERR("LARGE DMAE OPERATION ! " - "addr 0x%x len 0x%x\n", addr, len*4); - return; - } - memcpy(bp->gunzip_buf, data, len * 4); - - bnx2x_write_big_buf_wb(bp, addr, len); + if (bp->dmae_ready) + VIRT_WR_DMAE_LEN(bp, data, addr, len); + else + bnx2x_init_ind_wr(bp, addr, data, len); } -static void bnx2x_init_wr_zp(struct bnx2x *bp, u32 addr, - u32 len, u32 blob_off) +static void bnx2x_init_wr_zp(struct bnx2x *bp, u32 addr, u32 len, u32 blob_off) { - int rc, i; - const u8 *data = NULL; + const u8 *data = NULL; + int rc; + u32 i; - data = bnx2x_sel_blob(bp, addr, data) + 4*blob_off; - - if (data == NULL) { - panic("Blob not found for addr 0x%x\n", addr); - return; - } + data = bnx2x_sel_blob(bp, addr, data) + blob_off*4; rc = bnx2x_gunzip(bp, data, len); - if (rc) { - BNX2X_ERR("gunzip failed ! addr 0x%x rc %d\n", addr, rc); - BNX2X_ERR("blob_offset=0x%x\n", blob_off); + if (rc) return; - } /* gunzip_outlen is in dwords */ - len = bp->gunzip_outlen; + len = GUNZIP_OUTLEN(bp); for (i = 0; i < len; i++) - ((u32 *)bp->gunzip_buf)[i] = - cpu_to_le32(((u32 *)bp->gunzip_buf)[i]); + ((u32 *)GUNZIP_BUF(bp))[i] = + cpu_to_le32(((u32 *)GUNZIP_BUF(bp))[i]); bnx2x_write_big_buf_wb(bp, addr, len); } static void bnx2x_init_block(struct bnx2x *bp, u32 block, u32 stage) { - int hw_wr, i; u16 op_start = - bp->init_ops_offsets[BLOCK_OPS_IDX(block,stage,STAGE_START)]; + INIT_OPS_OFFSETS(bp)[BLOCK_OPS_IDX(block, stage, STAGE_START)]; u16 op_end = - bp->init_ops_offsets[BLOCK_OPS_IDX(block,stage,STAGE_END)]; + INIT_OPS_OFFSETS(bp)[BLOCK_OPS_IDX(block, stage, STAGE_END)]; union init_op *op; - u32 op_type, addr, len; + int hw_wr; + u32 i, op_type, addr, len; const u32 *data, *data_base; /* If empty block */ @@ -222,11 +189,11 @@ static void bnx2x_init_block(struct bnx2x *bp, u32 block, u32 stage) else hw_wr = OP_WR_ASIC; - data_base = bp->init_data; + data_base = INIT_DATA(bp); for (i = op_start; i < op_end; i++) { - op = (union init_op *)&(bp->init_ops[i]); + op = (union init_op *)&(INIT_OPS(bp)[i]); op_type = op->str_wr.op; addr = op->str_wr.offset; @@ -234,7 +201,7 @@ static void bnx2x_init_block(struct bnx2x *bp, u32 block, u32 stage) data = data_base + op->str_wr.data_off; /* HW/EMUL specific */ - if (unlikely((op_type > OP_WB) && (op_type == hw_wr))) + if ((op_type > OP_WB) && (op_type == hw_wr)) op_type = OP_WR; switch (op_type) { @@ -265,35 +232,179 @@ static void bnx2x_init_block(struct bnx2x *bp, u32 block, u32 stage) break; default: /* happens whenever an op is of a diff HW */ -#if 0 - DP(NETIF_MSG_HW, "skipping init operation " - "index %d[%d:%d]: type %d addr 0x%x " - "len %d(0x%x)\n", - i, op_start, op_end, op_type, addr, len, len); -#endif break; } } } -/* PXP */ -static void bnx2x_init_pxp(struct bnx2x *bp) + +/**************************************************************************** +* PXP Arbiter +****************************************************************************/ +/* + * This code configures the PCI read/write arbiter + * which implements a weighted round robin + * between the virtual queues in the chip. + * + * The values were derived for each PCI max payload and max request size. + * since max payload and max request size are only known at run time, + * this is done as a separate init stage. + */ + +#define NUM_WR_Q 13 +#define NUM_RD_Q 29 +#define MAX_RD_ORD 3 +#define MAX_WR_ORD 2 + +/* configuration for one arbiter queue */ +struct arb_line { + int l; + int add; + int ubound; +}; + +/* derived configuration for each read queue for each max request size */ +static const struct arb_line read_arb_data[NUM_RD_Q][MAX_RD_ORD + 1] = { +/* 1 */ { {8, 64, 25}, {16, 64, 25}, {32, 64, 25}, {64, 64, 41} }, + { {4, 8, 4}, {4, 8, 4}, {4, 8, 4}, {4, 8, 4} }, + { {4, 3, 3}, {4, 3, 3}, {4, 3, 3}, {4, 3, 3} }, + { {8, 3, 6}, {16, 3, 11}, {16, 3, 11}, {16, 3, 11} }, + { {8, 64, 25}, {16, 64, 25}, {32, 64, 25}, {64, 64, 41} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {64, 3, 41} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {64, 3, 41} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {64, 3, 41} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {64, 3, 41} }, +/* 10 */{ {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 64, 6}, {16, 64, 11}, {32, 64, 21}, {32, 64, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, +/* 20 */{ {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 64, 25}, {16, 64, 41}, {32, 64, 81}, {64, 64, 120} } +}; + +/* derived configuration for each write queue for each max request size */ +static const struct arb_line write_arb_data[NUM_WR_Q][MAX_WR_ORD + 1] = { +/* 1 */ { {4, 6, 3}, {4, 6, 3}, {4, 6, 3} }, + { {4, 2, 3}, {4, 2, 3}, {4, 2, 3} }, + { {8, 2, 6}, {16, 2, 11}, {16, 2, 11} }, + { {8, 2, 6}, {16, 2, 11}, {32, 2, 21} }, + { {8, 2, 6}, {16, 2, 11}, {32, 2, 21} }, + { {8, 2, 6}, {16, 2, 11}, {32, 2, 21} }, + { {8, 64, 25}, {16, 64, 25}, {32, 64, 25} }, + { {8, 2, 6}, {16, 2, 11}, {16, 2, 11} }, + { {8, 2, 6}, {16, 2, 11}, {16, 2, 11} }, +/* 10 */{ {8, 9, 6}, {16, 9, 11}, {32, 9, 21} }, + { {8, 47, 19}, {16, 47, 19}, {32, 47, 21} }, + { {8, 9, 6}, {16, 9, 11}, {16, 9, 11} }, + { {8, 64, 25}, {16, 64, 41}, {32, 64, 81} } +}; + +/* register addresses for read queues */ +static const struct arb_line read_arb_addr[NUM_RD_Q-1] = { +/* 1 */ {PXP2_REG_RQ_BW_RD_L0, PXP2_REG_RQ_BW_RD_ADD0, + PXP2_REG_RQ_BW_RD_UBOUND0}, + {PXP2_REG_PSWRQ_BW_L1, PXP2_REG_PSWRQ_BW_ADD1, + PXP2_REG_PSWRQ_BW_UB1}, + {PXP2_REG_PSWRQ_BW_L2, PXP2_REG_PSWRQ_BW_ADD2, + PXP2_REG_PSWRQ_BW_UB2}, + {PXP2_REG_PSWRQ_BW_L3, PXP2_REG_PSWRQ_BW_ADD3, + PXP2_REG_PSWRQ_BW_UB3}, + {PXP2_REG_RQ_BW_RD_L4, PXP2_REG_RQ_BW_RD_ADD4, + PXP2_REG_RQ_BW_RD_UBOUND4}, + {PXP2_REG_RQ_BW_RD_L5, PXP2_REG_RQ_BW_RD_ADD5, + PXP2_REG_RQ_BW_RD_UBOUND5}, + {PXP2_REG_PSWRQ_BW_L6, PXP2_REG_PSWRQ_BW_ADD6, + PXP2_REG_PSWRQ_BW_UB6}, + {PXP2_REG_PSWRQ_BW_L7, PXP2_REG_PSWRQ_BW_ADD7, + PXP2_REG_PSWRQ_BW_UB7}, + {PXP2_REG_PSWRQ_BW_L8, PXP2_REG_PSWRQ_BW_ADD8, + PXP2_REG_PSWRQ_BW_UB8}, +/* 10 */{PXP2_REG_PSWRQ_BW_L9, PXP2_REG_PSWRQ_BW_ADD9, + PXP2_REG_PSWRQ_BW_UB9}, + {PXP2_REG_PSWRQ_BW_L10, PXP2_REG_PSWRQ_BW_ADD10, + PXP2_REG_PSWRQ_BW_UB10}, + {PXP2_REG_PSWRQ_BW_L11, PXP2_REG_PSWRQ_BW_ADD11, + PXP2_REG_PSWRQ_BW_UB11}, + {PXP2_REG_RQ_BW_RD_L12, PXP2_REG_RQ_BW_RD_ADD12, + PXP2_REG_RQ_BW_RD_UBOUND12}, + {PXP2_REG_RQ_BW_RD_L13, PXP2_REG_RQ_BW_RD_ADD13, + PXP2_REG_RQ_BW_RD_UBOUND13}, + {PXP2_REG_RQ_BW_RD_L14, PXP2_REG_RQ_BW_RD_ADD14, + PXP2_REG_RQ_BW_RD_UBOUND14}, + {PXP2_REG_RQ_BW_RD_L15, PXP2_REG_RQ_BW_RD_ADD15, + PXP2_REG_RQ_BW_RD_UBOUND15}, + {PXP2_REG_RQ_BW_RD_L16, PXP2_REG_RQ_BW_RD_ADD16, + PXP2_REG_RQ_BW_RD_UBOUND16}, + {PXP2_REG_RQ_BW_RD_L17, PXP2_REG_RQ_BW_RD_ADD17, + PXP2_REG_RQ_BW_RD_UBOUND17}, + {PXP2_REG_RQ_BW_RD_L18, PXP2_REG_RQ_BW_RD_ADD18, + PXP2_REG_RQ_BW_RD_UBOUND18}, +/* 20 */{PXP2_REG_RQ_BW_RD_L19, PXP2_REG_RQ_BW_RD_ADD19, + PXP2_REG_RQ_BW_RD_UBOUND19}, + {PXP2_REG_RQ_BW_RD_L20, PXP2_REG_RQ_BW_RD_ADD20, + PXP2_REG_RQ_BW_RD_UBOUND20}, + {PXP2_REG_RQ_BW_RD_L22, PXP2_REG_RQ_BW_RD_ADD22, + PXP2_REG_RQ_BW_RD_UBOUND22}, + {PXP2_REG_RQ_BW_RD_L23, PXP2_REG_RQ_BW_RD_ADD23, + PXP2_REG_RQ_BW_RD_UBOUND23}, + {PXP2_REG_RQ_BW_RD_L24, PXP2_REG_RQ_BW_RD_ADD24, + PXP2_REG_RQ_BW_RD_UBOUND24}, + {PXP2_REG_RQ_BW_RD_L25, PXP2_REG_RQ_BW_RD_ADD25, + PXP2_REG_RQ_BW_RD_UBOUND25}, + {PXP2_REG_RQ_BW_RD_L26, PXP2_REG_RQ_BW_RD_ADD26, + PXP2_REG_RQ_BW_RD_UBOUND26}, + {PXP2_REG_RQ_BW_RD_L27, PXP2_REG_RQ_BW_RD_ADD27, + PXP2_REG_RQ_BW_RD_UBOUND27}, + {PXP2_REG_PSWRQ_BW_L28, PXP2_REG_PSWRQ_BW_ADD28, + PXP2_REG_PSWRQ_BW_UB28} +}; + +/* register addresses for write queues */ +static const struct arb_line write_arb_addr[NUM_WR_Q-1] = { +/* 1 */ {PXP2_REG_PSWRQ_BW_L1, PXP2_REG_PSWRQ_BW_ADD1, + PXP2_REG_PSWRQ_BW_UB1}, + {PXP2_REG_PSWRQ_BW_L2, PXP2_REG_PSWRQ_BW_ADD2, + PXP2_REG_PSWRQ_BW_UB2}, + {PXP2_REG_PSWRQ_BW_L3, PXP2_REG_PSWRQ_BW_ADD3, + PXP2_REG_PSWRQ_BW_UB3}, + {PXP2_REG_PSWRQ_BW_L6, PXP2_REG_PSWRQ_BW_ADD6, + PXP2_REG_PSWRQ_BW_UB6}, + {PXP2_REG_PSWRQ_BW_L7, PXP2_REG_PSWRQ_BW_ADD7, + PXP2_REG_PSWRQ_BW_UB7}, + {PXP2_REG_PSWRQ_BW_L8, PXP2_REG_PSWRQ_BW_ADD8, + PXP2_REG_PSWRQ_BW_UB8}, + {PXP2_REG_PSWRQ_BW_L9, PXP2_REG_PSWRQ_BW_ADD9, + PXP2_REG_PSWRQ_BW_UB9}, + {PXP2_REG_PSWRQ_BW_L10, PXP2_REG_PSWRQ_BW_ADD10, + PXP2_REG_PSWRQ_BW_UB10}, + {PXP2_REG_PSWRQ_BW_L11, PXP2_REG_PSWRQ_BW_ADD11, + PXP2_REG_PSWRQ_BW_UB11}, +/* 10 */{PXP2_REG_PSWRQ_BW_L28, PXP2_REG_PSWRQ_BW_ADD28, + PXP2_REG_PSWRQ_BW_UB28}, + {PXP2_REG_RQ_BW_WR_L29, PXP2_REG_RQ_BW_WR_ADD29, + PXP2_REG_RQ_BW_WR_UBOUND29}, + {PXP2_REG_RQ_BW_WR_L30, PXP2_REG_RQ_BW_WR_ADD30, + PXP2_REG_RQ_BW_WR_UBOUND30} +}; + +static void bnx2x_init_pxp_arb(struct bnx2x *bp, int r_order, int w_order) { - u16 devctl; - int r_order, w_order; u32 val, i; - pci_read_config_word(bp->pdev, - bp->pcie_cap + PCI_EXP_DEVCTL, &devctl); - DP(NETIF_MSG_HW, "read 0x%x from devctl\n", devctl); - w_order = ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5); - if (bp->mrrs == -1) - r_order = ((devctl & PCI_EXP_DEVCTL_READRQ) >> 12); - else { - DP(NETIF_MSG_HW, "force read order to %d\n", bp->mrrs); - r_order = bp->mrrs; - } - if (r_order > MAX_RD_ORD) { DP(NETIF_MSG_HW, "read order of %d order adjusted to %d\n", r_order, MAX_RD_ORD); @@ -367,6 +478,11 @@ static void bnx2x_init_pxp(struct bnx2x *bp) REG_WR(bp, PXP2_REG_WR_USDMDP_TH, (0x18 << w_order)); if (CHIP_IS_E1H(bp)) { + /* MPS w_order optimal TH presently TH + * 128 0 0 2 + * 256 1 1 3 + * >=512 2 2 3 + */ val = ((w_order == 0) ? 2 : 3); REG_WR(bp, PXP2_REG_WR_HC_MPS, val); REG_WR(bp, PXP2_REG_WR_USDM_MPS, val); @@ -382,61 +498,4 @@ static void bnx2x_init_pxp(struct bnx2x *bp) } } -/***************************************************************************** - * Description: - * Calculates crc 8 on a word value: polynomial 0-1-2-8 - * Code was translated from Verilog. - ****************************************************************************/ -static u8 calc_crc8(u32 data, u8 crc) -{ - u8 D[32]; - u8 NewCRC[8]; - u8 C[8]; - u8 crc_res; - u8 i; - - /* split the data into 31 bits */ - for (i = 0; i < 32; i++) { - D[i] = data & 1; - data = data >> 1; - } - - /* split the crc into 8 bits */ - for (i = 0; i < 8; i++) { - C[i] = crc & 1; - crc = crc >> 1; - } - - NewCRC[0] = D[31] ^ D[30] ^ D[28] ^ D[23] ^ D[21] ^ D[19] ^ D[18] ^ - D[16] ^ D[14] ^ D[12] ^ D[8] ^ D[7] ^ D[6] ^ D[0] ^ C[4] ^ - C[6] ^ C[7]; - NewCRC[1] = D[30] ^ D[29] ^ D[28] ^ D[24] ^ D[23] ^ D[22] ^ D[21] ^ - D[20] ^ D[18] ^ D[17] ^ D[16] ^ D[15] ^ D[14] ^ D[13] ^ - D[12] ^ D[9] ^ D[6] ^ D[1] ^ D[0] ^ C[0] ^ C[4] ^ C[5] ^ C[6]; - NewCRC[2] = D[29] ^ D[28] ^ D[25] ^ D[24] ^ D[22] ^ D[17] ^ D[15] ^ - D[13] ^ D[12] ^ D[10] ^ D[8] ^ D[6] ^ D[2] ^ D[1] ^ D[0] ^ - C[0] ^ C[1] ^ C[4] ^ C[5]; - NewCRC[3] = D[30] ^ D[29] ^ D[26] ^ D[25] ^ D[23] ^ D[18] ^ D[16] ^ - D[14] ^ D[13] ^ D[11] ^ D[9] ^ D[7] ^ D[3] ^ D[2] ^ D[1] ^ - C[1] ^ C[2] ^ C[5] ^ C[6]; - NewCRC[4] = D[31] ^ D[30] ^ D[27] ^ D[26] ^ D[24] ^ D[19] ^ D[17] ^ - D[15] ^ D[14] ^ D[12] ^ D[10] ^ D[8] ^ D[4] ^ D[3] ^ D[2] ^ - C[0] ^ C[2] ^ C[3] ^ C[6] ^ C[7]; - NewCRC[5] = D[31] ^ D[28] ^ D[27] ^ D[25] ^ D[20] ^ D[18] ^ D[16] ^ - D[15] ^ D[13] ^ D[11] ^ D[9] ^ D[5] ^ D[4] ^ D[3] ^ C[1] ^ - C[3] ^ C[4] ^ C[7]; - NewCRC[6] = D[29] ^ D[28] ^ D[26] ^ D[21] ^ D[19] ^ D[17] ^ D[16] ^ - D[14] ^ D[12] ^ D[10] ^ D[6] ^ D[5] ^ D[4] ^ C[2] ^ C[4] ^ - C[5]; - NewCRC[7] = D[30] ^ D[29] ^ D[27] ^ D[22] ^ D[20] ^ D[18] ^ D[17] ^ - D[15] ^ D[13] ^ D[11] ^ D[7] ^ D[6] ^ D[5] ^ C[3] ^ C[5] ^ - C[6]; - - crc_res = 0; - for (i = 0; i < 8; i++) - crc_res |= (NewCRC[i] << i); - - return crc_res; -} - #endif /* BNX2X_INIT_OPS_H */ diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index b084e8b531a..8b6bb999d8e 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -153,7 +153,7 @@ MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl); /* used only at init * locking is done by mcp */ -static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val) +void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val) { pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr); pci_write_config_dword(bp->pdev, PCICFG_GRC_DATA, val); @@ -346,6 +346,21 @@ void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32) mutex_unlock(&bp->dmae_mutex); } +void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr, + u32 addr, u32 len) +{ + int offset = 0; + + while (len > DMAE_LEN32_WR_MAX) { + bnx2x_write_dmae(bp, phys_addr + offset, + addr + offset, DMAE_LEN32_WR_MAX); + offset += DMAE_LEN32_WR_MAX * 4; + len -= DMAE_LEN32_WR_MAX; + } + + bnx2x_write_dmae(bp, phys_addr + offset, addr + offset, len); +} + /* used only for slowpath so not inlined */ static void bnx2x_wb_wr(struct bnx2x *bp, int reg, u32 val_hi, u32 val_lo) { @@ -5917,6 +5932,24 @@ static void bnx2x_reset_common(struct bnx2x *bp) REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, 0x1403); } +static void bnx2x_init_pxp(struct bnx2x *bp) +{ + u16 devctl; + int r_order, w_order; + + pci_read_config_word(bp->pdev, + bp->pcie_cap + PCI_EXP_DEVCTL, &devctl); + DP(NETIF_MSG_HW, "read 0x%x from devctl\n", devctl); + w_order = ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5); + if (bp->mrrs == -1) + r_order = ((devctl & PCI_EXP_DEVCTL_READRQ) >> 12); + else { + DP(NETIF_MSG_HW, "force read order to %d\n", bp->mrrs); + r_order = bp->mrrs; + } + + bnx2x_init_pxp_arb(bp, r_order, w_order); +} static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp) { @@ -6479,9 +6512,15 @@ static int bnx2x_init_func(struct bnx2x *bp) if (CHIP_IS_E1H(bp)) { - for (i = 0; i < 9; i++) - bnx2x_init_block(bp, - cm_blocks[i], FUNC0_STAGE + func); + bnx2x_init_block(bp, MISC_BLOCK, FUNC0_STAGE + func); + bnx2x_init_block(bp, TCM_BLOCK, FUNC0_STAGE + func); + bnx2x_init_block(bp, UCM_BLOCK, FUNC0_STAGE + func); + bnx2x_init_block(bp, CCM_BLOCK, FUNC0_STAGE + func); + bnx2x_init_block(bp, XCM_BLOCK, FUNC0_STAGE + func); + bnx2x_init_block(bp, TSEM_BLOCK, FUNC0_STAGE + func); + bnx2x_init_block(bp, USEM_BLOCK, FUNC0_STAGE + func); + bnx2x_init_block(bp, CSEM_BLOCK, FUNC0_STAGE + func); + bnx2x_init_block(bp, XSEM_BLOCK, FUNC0_STAGE + func); REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1); REG_WR(bp, NIG_REG_LLH0_FUNC_VLAN_ID + port*8, bp->e1hov); @@ -11834,22 +11873,22 @@ static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev) BNX2X_ALLOC_AND_SET(init_ops_offsets, init_offsets_alloc_err, be16_to_cpu_n); /* STORMs firmware */ - bp->tsem_int_table_data = bp->firmware->data + - be32_to_cpu(fw_hdr->tsem_int_table_data.offset); - bp->tsem_pram_data = bp->firmware->data + - be32_to_cpu(fw_hdr->tsem_pram_data.offset); - bp->usem_int_table_data = bp->firmware->data + - be32_to_cpu(fw_hdr->usem_int_table_data.offset); - bp->usem_pram_data = bp->firmware->data + - be32_to_cpu(fw_hdr->usem_pram_data.offset); - bp->xsem_int_table_data = bp->firmware->data + - be32_to_cpu(fw_hdr->xsem_int_table_data.offset); - bp->xsem_pram_data = bp->firmware->data + - be32_to_cpu(fw_hdr->xsem_pram_data.offset); - bp->csem_int_table_data = bp->firmware->data + - be32_to_cpu(fw_hdr->csem_int_table_data.offset); - bp->csem_pram_data = bp->firmware->data + - be32_to_cpu(fw_hdr->csem_pram_data.offset); + INIT_TSEM_INT_TABLE_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->tsem_int_table_data.offset); + INIT_TSEM_PRAM_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->tsem_pram_data.offset); + INIT_USEM_INT_TABLE_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->usem_int_table_data.offset); + INIT_USEM_PRAM_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->usem_pram_data.offset); + INIT_XSEM_INT_TABLE_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->xsem_int_table_data.offset); + INIT_XSEM_PRAM_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->xsem_pram_data.offset); + INIT_CSEM_INT_TABLE_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->csem_int_table_data.offset); + INIT_CSEM_PRAM_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->csem_pram_data.offset); return 0; init_offsets_alloc_err: diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h index 999838629be..1e6f5aa4eb5 100644 --- a/drivers/net/bnx2x_reg.h +++ b/drivers/net/bnx2x_reg.h @@ -6019,3 +6019,116 @@ Theotherbitsarereservedandshouldbezero*/ #define COMMAND_REG_SIMD_NOMASK 0x1c +#define IGU_MEM_BASE 0x0000 + +#define IGU_MEM_MSIX_BASE 0x0000 +#define IGU_MEM_MSIX_UPPER 0x007f +#define IGU_MEM_MSIX_RESERVED_UPPER 0x01ff + +#define IGU_MEM_PBA_MSIX_BASE 0x0200 +#define IGU_MEM_PBA_MSIX_UPPER 0x0200 + +#define IGU_CMD_BACKWARD_COMP_PROD_UPD 0x0201 +#define IGU_MEM_PBA_MSIX_RESERVED_UPPER 0x03ff + +#define IGU_CMD_INT_ACK_BASE 0x0400 +#define IGU_CMD_INT_ACK_UPPER\ + (IGU_CMD_INT_ACK_BASE + MAX_SB_PER_PORT * NUM_OF_PORTS_PER_PATH - 1) +#define IGU_CMD_INT_ACK_RESERVED_UPPER 0x04ff + +#define IGU_CMD_E2_PROD_UPD_BASE 0x0500 +#define IGU_CMD_E2_PROD_UPD_UPPER\ + (IGU_CMD_E2_PROD_UPD_BASE + MAX_SB_PER_PORT * NUM_OF_PORTS_PER_PATH - 1) +#define IGU_CMD_E2_PROD_UPD_RESERVED_UPPER 0x059f + +#define IGU_CMD_ATTN_BIT_UPD_UPPER 0x05a0 +#define IGU_CMD_ATTN_BIT_SET_UPPER 0x05a1 +#define IGU_CMD_ATTN_BIT_CLR_UPPER 0x05a2 + +#define IGU_REG_SISR_MDPC_WMASK_UPPER 0x05a3 +#define IGU_REG_SISR_MDPC_WMASK_LSB_UPPER 0x05a4 +#define IGU_REG_SISR_MDPC_WMASK_MSB_UPPER 0x05a5 +#define IGU_REG_SISR_MDPC_WOMASK_UPPER 0x05a6 + +#define IGU_REG_RESERVED_UPPER 0x05ff + + +#define CDU_REGION_NUMBER_XCM_AG 2 +#define CDU_REGION_NUMBER_UCM_AG 4 + + +/** + * String-to-compress [31:8] = CID (all 24 bits) + * String-to-compress [7:4] = Region + * String-to-compress [3:0] = Type + */ +#define CDU_VALID_DATA(_cid, _region, _type)\ + (((_cid) << 8) | (((_region)&0xf)<<4) | (((_type)&0xf))) +#define CDU_CRC8(_cid, _region, _type)\ + (calc_crc8(CDU_VALID_DATA(_cid, _region, _type), 0xff)) +#define CDU_RSRVD_VALUE_TYPE_A(_cid, _region, _type)\ + (0x80 | ((CDU_CRC8(_cid, _region, _type)) & 0x7f)) +#define CDU_RSRVD_VALUE_TYPE_B(_crc, _type)\ + (0x80 | ((_type)&0xf << 3) | ((CDU_CRC8(_cid, _region, _type)) & 0x7)) +#define CDU_RSRVD_INVALIDATE_CONTEXT_VALUE(_val) ((_val) & ~0x80) + +/****************************************************************************** + * Description: + * Calculates crc 8 on a word value: polynomial 0-1-2-8 + * Code was translated from Verilog. + * Return: + *****************************************************************************/ +static inline u8 calc_crc8(u32 data, u8 crc) +{ + u8 D[32]; + u8 NewCRC[8]; + u8 C[8]; + u8 crc_res; + u8 i; + + /* split the data into 31 bits */ + for (i = 0; i < 32; i++) { + D[i] = (u8)(data & 1); + data = data >> 1; + } + + /* split the crc into 8 bits */ + for (i = 0; i < 8; i++) { + C[i] = crc & 1; + crc = crc >> 1; + } + + NewCRC[0] = D[31] ^ D[30] ^ D[28] ^ D[23] ^ D[21] ^ D[19] ^ D[18] ^ + D[16] ^ D[14] ^ D[12] ^ D[8] ^ D[7] ^ D[6] ^ D[0] ^ C[4] ^ + C[6] ^ C[7]; + NewCRC[1] = D[30] ^ D[29] ^ D[28] ^ D[24] ^ D[23] ^ D[22] ^ D[21] ^ + D[20] ^ D[18] ^ D[17] ^ D[16] ^ D[15] ^ D[14] ^ D[13] ^ + D[12] ^ D[9] ^ D[6] ^ D[1] ^ D[0] ^ C[0] ^ C[4] ^ C[5] ^ + C[6]; + NewCRC[2] = D[29] ^ D[28] ^ D[25] ^ D[24] ^ D[22] ^ D[17] ^ D[15] ^ + D[13] ^ D[12] ^ D[10] ^ D[8] ^ D[6] ^ D[2] ^ D[1] ^ D[0] ^ + C[0] ^ C[1] ^ C[4] ^ C[5]; + NewCRC[3] = D[30] ^ D[29] ^ D[26] ^ D[25] ^ D[23] ^ D[18] ^ D[16] ^ + D[14] ^ D[13] ^ D[11] ^ D[9] ^ D[7] ^ D[3] ^ D[2] ^ D[1] ^ + C[1] ^ C[2] ^ C[5] ^ C[6]; + NewCRC[4] = D[31] ^ D[30] ^ D[27] ^ D[26] ^ D[24] ^ D[19] ^ D[17] ^ + D[15] ^ D[14] ^ D[12] ^ D[10] ^ D[8] ^ D[4] ^ D[3] ^ D[2] ^ + C[0] ^ C[2] ^ C[3] ^ C[6] ^ C[7]; + NewCRC[5] = D[31] ^ D[28] ^ D[27] ^ D[25] ^ D[20] ^ D[18] ^ D[16] ^ + D[15] ^ D[13] ^ D[11] ^ D[9] ^ D[5] ^ D[4] ^ D[3] ^ C[1] ^ + C[3] ^ C[4] ^ C[7]; + NewCRC[6] = D[29] ^ D[28] ^ D[26] ^ D[21] ^ D[19] ^ D[17] ^ D[16] ^ + D[14] ^ D[12] ^ D[10] ^ D[6] ^ D[5] ^ D[4] ^ C[2] ^ C[4] ^ + C[5]; + NewCRC[7] = D[30] ^ D[29] ^ D[27] ^ D[22] ^ D[20] ^ D[18] ^ D[17] ^ + D[15] ^ D[13] ^ D[11] ^ D[7] ^ D[6] ^ D[5] ^ C[3] ^ C[5] ^ + C[6]; + + crc_res = 0; + for (i = 0; i < 8; i++) + crc_res |= (NewCRC[i] << i); + + return crc_res; +} + + -- cgit v1.2.3-18-g5258 From 45a4864d80264f6708528dcaa2c5c0b3933a8d7f Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:24:18 +0000 Subject: bnx2x: Beautify bnx2x_dump.h Signed-off-by: Yitchak Gertner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_dump.h | 890 ++++++++++++++++++++++++----------------------- 1 file changed, 449 insertions(+), 441 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_dump.h b/drivers/net/bnx2x_dump.h index 78c6b0353ad..3bb9a91bb3f 100644 --- a/drivers/net/bnx2x_dump.h +++ b/drivers/net/bnx2x_dump.h @@ -13,31 +13,35 @@ * The signature is time stamp, diag version and grc_dump version */ +#ifndef BNX2X_DUMP_H +#define BNX2X_DUMP_H + + struct dump_sign { u32 time_stamp; u32 diag_ver; u32 grc_dump_ver; }; -#define TSTORM_WAITP_ADDR 0x1b8a80 -#define CSTORM_WAITP_ADDR 0x238a80 -#define XSTORM_WAITP_ADDR 0x2b8a80 -#define USTORM_WAITP_ADDR 0x338a80 -#define TSTORM_CAM_MODE 0x1b1440 +#define TSTORM_WAITP_ADDR 0x1b8a80 +#define CSTORM_WAITP_ADDR 0x238a80 +#define XSTORM_WAITP_ADDR 0x2b8a80 +#define USTORM_WAITP_ADDR 0x338a80 +#define TSTORM_CAM_MODE 0x1b1440 -#define RI_E1 0x1 -#define RI_E1H 0x2 -#define RI_ONLINE 0x100 +#define RI_E1 0x1 +#define RI_E1H 0x2 +#define RI_ONLINE 0x100 -#define RI_E1_OFFLINE (RI_E1) -#define RI_E1_ONLINE (RI_E1 | RI_ONLINE) -#define RI_E1H_OFFLINE (RI_E1H) -#define RI_E1H_ONLINE (RI_E1H | RI_ONLINE) -#define RI_ALL_OFFLINE (RI_E1 | RI_E1H) -#define RI_ALL_ONLINE (RI_E1 | RI_E1H | RI_ONLINE) +#define RI_E1_OFFLINE (RI_E1) +#define RI_E1_ONLINE (RI_E1 | RI_ONLINE) +#define RI_E1H_OFFLINE (RI_E1H) +#define RI_E1H_ONLINE (RI_E1H | RI_ONLINE) +#define RI_ALL_OFFLINE (RI_E1 | RI_E1H) +#define RI_ALL_ONLINE (RI_E1 | RI_E1H | RI_ONLINE) -#define MAX_TIMER_PENDING 200 -#define TIMER_SCAN_DONT_CARE 0xFF +#define MAX_TIMER_PENDING 200 +#define TIMER_SCAN_DONT_CARE 0xFF struct dump_hdr { @@ -67,443 +71,444 @@ struct wreg_addr { }; -#define REGS_COUNT 558 +#define REGS_COUNT 558 static const struct reg_addr reg_addrs[REGS_COUNT] = { - { 0x2000, 341, RI_ALL_ONLINE}, { 0x2800, 103, RI_ALL_ONLINE}, - { 0x3000, 287, RI_ALL_ONLINE}, { 0x3800, 331, RI_ALL_ONLINE}, - { 0x8800, 6, RI_E1_ONLINE}, { 0xa000, 223, RI_ALL_ONLINE}, - { 0xa388, 1, RI_ALL_ONLINE}, { 0xa398, 1, RI_ALL_ONLINE}, - { 0xa39c, 7, RI_E1H_ONLINE}, { 0xa3c0, 3, RI_E1H_ONLINE}, - { 0xa3d0, 1, RI_E1H_ONLINE}, { 0xa3d8, 1, RI_E1H_ONLINE}, - { 0xa3e0, 1, RI_E1H_ONLINE}, { 0xa3e8, 1, RI_E1H_ONLINE}, - { 0xa3f0, 1, RI_E1H_ONLINE}, { 0xa3f8, 1, RI_E1H_ONLINE}, - { 0xa400, 69, RI_ALL_ONLINE}, { 0xa518, 1, RI_ALL_ONLINE}, - { 0xa520, 1, RI_ALL_ONLINE}, { 0xa528, 1, RI_ALL_ONLINE}, - { 0xa530, 1, RI_ALL_ONLINE}, { 0xa538, 1, RI_ALL_ONLINE}, - { 0xa540, 1, RI_ALL_ONLINE}, { 0xa548, 1, RI_ALL_ONLINE}, - { 0xa550, 1, RI_ALL_ONLINE}, { 0xa558, 1, RI_ALL_ONLINE}, - { 0xa560, 1, RI_ALL_ONLINE}, { 0xa568, 1, RI_ALL_ONLINE}, - { 0xa570, 1, RI_ALL_ONLINE}, { 0xa580, 1, RI_ALL_ONLINE}, - { 0xa590, 1, RI_ALL_ONLINE}, { 0xa5a0, 1, RI_ALL_ONLINE}, - { 0xa5c0, 1, RI_ALL_ONLINE}, { 0xa5e0, 1, RI_E1H_ONLINE}, - { 0xa5e8, 1, RI_E1H_ONLINE}, { 0xa5f0, 1, RI_E1H_ONLINE}, - { 0xa5f8, 10, RI_E1H_ONLINE}, { 0x10000, 236, RI_ALL_ONLINE}, - { 0x103bc, 1, RI_ALL_ONLINE}, { 0x103cc, 1, RI_ALL_ONLINE}, - { 0x103dc, 1, RI_ALL_ONLINE}, { 0x10400, 57, RI_ALL_ONLINE}, - { 0x104e8, 2, RI_ALL_ONLINE}, { 0x104f4, 2, RI_ALL_ONLINE}, - { 0x10500, 146, RI_ALL_ONLINE}, { 0x10750, 2, RI_ALL_ONLINE}, - { 0x10760, 2, RI_ALL_ONLINE}, { 0x10770, 2, RI_ALL_ONLINE}, - { 0x10780, 2, RI_ALL_ONLINE}, { 0x10790, 2, RI_ALL_ONLINE}, - { 0x107a0, 2, RI_ALL_ONLINE}, { 0x107b0, 2, RI_ALL_ONLINE}, - { 0x107c0, 2, RI_ALL_ONLINE}, { 0x107d0, 2, RI_ALL_ONLINE}, - { 0x107e0, 2, RI_ALL_ONLINE}, { 0x10880, 2, RI_ALL_ONLINE}, - { 0x10900, 2, RI_ALL_ONLINE}, { 0x12000, 1, RI_ALL_ONLINE}, - { 0x14000, 1, RI_ALL_ONLINE}, { 0x16000, 26, RI_E1H_ONLINE}, - { 0x16070, 18, RI_E1H_ONLINE}, { 0x160c0, 27, RI_E1H_ONLINE}, - { 0x16140, 1, RI_E1H_ONLINE}, { 0x16160, 1, RI_E1H_ONLINE}, - { 0x16180, 2, RI_E1H_ONLINE}, { 0x161c0, 2, RI_E1H_ONLINE}, - { 0x16204, 5, RI_E1H_ONLINE}, { 0x18000, 1, RI_E1H_ONLINE}, - { 0x18008, 1, RI_E1H_ONLINE}, { 0x20000, 24, RI_ALL_ONLINE}, - { 0x20060, 8, RI_ALL_ONLINE}, { 0x20080, 138, RI_ALL_ONLINE}, - { 0x202b4, 1, RI_ALL_ONLINE}, { 0x202c4, 1, RI_ALL_ONLINE}, - { 0x20400, 2, RI_ALL_ONLINE}, { 0x2040c, 8, RI_ALL_ONLINE}, - { 0x2042c, 18, RI_E1H_ONLINE}, { 0x20480, 1, RI_ALL_ONLINE}, - { 0x20500, 1, RI_ALL_ONLINE}, { 0x20600, 1, RI_ALL_ONLINE}, - { 0x28000, 1, RI_ALL_ONLINE}, { 0x28004, 8191, RI_ALL_OFFLINE}, - { 0x30000, 1, RI_ALL_ONLINE}, { 0x30004, 16383, RI_ALL_OFFLINE}, - { 0x40000, 98, RI_ALL_ONLINE}, { 0x40194, 1, RI_ALL_ONLINE}, - { 0x401a4, 1, RI_ALL_ONLINE}, { 0x401a8, 11, RI_E1H_ONLINE}, - { 0x40200, 4, RI_ALL_ONLINE}, { 0x40400, 43, RI_ALL_ONLINE}, - { 0x404b8, 1, RI_ALL_ONLINE}, { 0x404c8, 1, RI_ALL_ONLINE}, - { 0x404cc, 3, RI_E1H_ONLINE}, { 0x40500, 2, RI_ALL_ONLINE}, - { 0x40510, 2, RI_ALL_ONLINE}, { 0x40520, 2, RI_ALL_ONLINE}, - { 0x40530, 2, RI_ALL_ONLINE}, { 0x40540, 2, RI_ALL_ONLINE}, - { 0x42000, 164, RI_ALL_ONLINE}, { 0x4229c, 1, RI_ALL_ONLINE}, - { 0x422ac, 1, RI_ALL_ONLINE}, { 0x422bc, 1, RI_ALL_ONLINE}, - { 0x422d4, 5, RI_E1H_ONLINE}, { 0x42400, 49, RI_ALL_ONLINE}, - { 0x424c8, 38, RI_ALL_ONLINE}, { 0x42568, 2, RI_ALL_ONLINE}, - { 0x42800, 1, RI_ALL_ONLINE}, { 0x50000, 20, RI_ALL_ONLINE}, - { 0x50050, 8, RI_ALL_ONLINE}, { 0x50070, 88, RI_ALL_ONLINE}, - { 0x501dc, 1, RI_ALL_ONLINE}, { 0x501ec, 1, RI_ALL_ONLINE}, - { 0x501f0, 4, RI_E1H_ONLINE}, { 0x50200, 2, RI_ALL_ONLINE}, - { 0x5020c, 7, RI_ALL_ONLINE}, { 0x50228, 6, RI_E1H_ONLINE}, - { 0x50240, 1, RI_ALL_ONLINE}, { 0x50280, 1, RI_ALL_ONLINE}, - { 0x52000, 1, RI_ALL_ONLINE}, { 0x54000, 1, RI_ALL_ONLINE}, - { 0x54004, 3327, RI_ALL_OFFLINE}, { 0x58000, 1, RI_ALL_ONLINE}, - { 0x58004, 8191, RI_ALL_OFFLINE}, { 0x60000, 71, RI_ALL_ONLINE}, - { 0x60128, 1, RI_ALL_ONLINE}, { 0x60138, 1, RI_ALL_ONLINE}, - { 0x6013c, 24, RI_E1H_ONLINE}, { 0x60200, 1, RI_ALL_ONLINE}, - { 0x61000, 1, RI_ALL_ONLINE}, { 0x61004, 511, RI_ALL_OFFLINE}, - { 0x70000, 8, RI_ALL_ONLINE}, { 0x70020, 21496, RI_ALL_OFFLINE}, - { 0x85000, 3, RI_ALL_ONLINE}, { 0x8500c, 4, RI_ALL_OFFLINE}, - { 0x8501c, 7, RI_ALL_ONLINE}, { 0x85038, 4, RI_ALL_OFFLINE}, - { 0x85048, 1, RI_ALL_ONLINE}, { 0x8504c, 109, RI_ALL_OFFLINE}, - { 0x85200, 32, RI_ALL_ONLINE}, { 0x85280, 11104, RI_ALL_OFFLINE}, - { 0xa0000, 16384, RI_ALL_ONLINE}, { 0xb0000, 16384, RI_E1H_ONLINE}, - { 0xc1000, 7, RI_ALL_ONLINE}, { 0xc1028, 1, RI_ALL_ONLINE}, - { 0xc1038, 1, RI_ALL_ONLINE}, { 0xc1800, 2, RI_ALL_ONLINE}, - { 0xc2000, 164, RI_ALL_ONLINE}, { 0xc229c, 1, RI_ALL_ONLINE}, - { 0xc22ac, 1, RI_ALL_ONLINE}, { 0xc22bc, 1, RI_ALL_ONLINE}, - { 0xc2400, 49, RI_ALL_ONLINE}, { 0xc24c8, 38, RI_ALL_ONLINE}, - { 0xc2568, 2, RI_ALL_ONLINE}, { 0xc2600, 1, RI_ALL_ONLINE}, - { 0xc4000, 165, RI_ALL_ONLINE}, { 0xc42a0, 1, RI_ALL_ONLINE}, - { 0xc42b0, 1, RI_ALL_ONLINE}, { 0xc42c0, 1, RI_ALL_ONLINE}, - { 0xc42e0, 7, RI_E1H_ONLINE}, { 0xc4400, 51, RI_ALL_ONLINE}, - { 0xc44d0, 38, RI_ALL_ONLINE}, { 0xc4570, 2, RI_ALL_ONLINE}, - { 0xc4600, 1, RI_ALL_ONLINE}, { 0xd0000, 19, RI_ALL_ONLINE}, - { 0xd004c, 8, RI_ALL_ONLINE}, { 0xd006c, 91, RI_ALL_ONLINE}, - { 0xd01e4, 1, RI_ALL_ONLINE}, { 0xd01f4, 1, RI_ALL_ONLINE}, - { 0xd0200, 2, RI_ALL_ONLINE}, { 0xd020c, 7, RI_ALL_ONLINE}, - { 0xd0228, 18, RI_E1H_ONLINE}, { 0xd0280, 1, RI_ALL_ONLINE}, - { 0xd0300, 1, RI_ALL_ONLINE}, { 0xd0400, 1, RI_ALL_ONLINE}, - { 0xd4000, 1, RI_ALL_ONLINE}, { 0xd4004, 2559, RI_ALL_OFFLINE}, - { 0xd8000, 1, RI_ALL_ONLINE}, { 0xd8004, 8191, RI_ALL_OFFLINE}, - { 0xe0000, 21, RI_ALL_ONLINE}, { 0xe0054, 8, RI_ALL_ONLINE}, - { 0xe0074, 85, RI_ALL_ONLINE}, { 0xe01d4, 1, RI_ALL_ONLINE}, - { 0xe01e4, 1, RI_ALL_ONLINE}, { 0xe0200, 2, RI_ALL_ONLINE}, - { 0xe020c, 8, RI_ALL_ONLINE}, { 0xe022c, 18, RI_E1H_ONLINE}, - { 0xe0280, 1, RI_ALL_ONLINE}, { 0xe0300, 1, RI_ALL_ONLINE}, - { 0xe1000, 1, RI_ALL_ONLINE}, { 0xe2000, 1, RI_ALL_ONLINE}, - { 0xe2004, 2047, RI_ALL_OFFLINE}, { 0xf0000, 1, RI_ALL_ONLINE}, - { 0xf0004, 16383, RI_ALL_OFFLINE}, { 0x101000, 12, RI_ALL_ONLINE}, - { 0x10103c, 1, RI_ALL_ONLINE}, { 0x10104c, 1, RI_ALL_ONLINE}, - { 0x101050, 1, RI_E1H_ONLINE}, { 0x101100, 1, RI_ALL_ONLINE}, - { 0x101800, 8, RI_ALL_ONLINE}, { 0x102000, 18, RI_ALL_ONLINE}, - { 0x102054, 1, RI_ALL_ONLINE}, { 0x102064, 1, RI_ALL_ONLINE}, - { 0x102080, 17, RI_ALL_ONLINE}, { 0x1020c8, 8, RI_E1H_ONLINE}, - { 0x102400, 1, RI_ALL_ONLINE}, { 0x103000, 26, RI_ALL_ONLINE}, - { 0x103074, 1, RI_ALL_ONLINE}, { 0x103084, 1, RI_ALL_ONLINE}, - { 0x103094, 1, RI_ALL_ONLINE}, { 0x103098, 5, RI_E1H_ONLINE}, - { 0x103800, 8, RI_ALL_ONLINE}, { 0x104000, 63, RI_ALL_ONLINE}, - { 0x104108, 1, RI_ALL_ONLINE}, { 0x104118, 1, RI_ALL_ONLINE}, - { 0x104200, 17, RI_ALL_ONLINE}, { 0x104400, 64, RI_ALL_ONLINE}, - { 0x104500, 192, RI_ALL_OFFLINE}, { 0x104800, 64, RI_ALL_ONLINE}, - { 0x104900, 192, RI_ALL_OFFLINE}, { 0x105000, 7, RI_ALL_ONLINE}, - { 0x10501c, 1, RI_ALL_OFFLINE}, { 0x105020, 3, RI_ALL_ONLINE}, - { 0x10502c, 1, RI_ALL_OFFLINE}, { 0x105030, 3, RI_ALL_ONLINE}, - { 0x10503c, 1, RI_ALL_OFFLINE}, { 0x105040, 3, RI_ALL_ONLINE}, - { 0x10504c, 1, RI_ALL_OFFLINE}, { 0x105050, 3, RI_ALL_ONLINE}, - { 0x10505c, 1, RI_ALL_OFFLINE}, { 0x105060, 3, RI_ALL_ONLINE}, - { 0x10506c, 1, RI_ALL_OFFLINE}, { 0x105070, 3, RI_ALL_ONLINE}, - { 0x10507c, 1, RI_ALL_OFFLINE}, { 0x105080, 3, RI_ALL_ONLINE}, - { 0x10508c, 1, RI_ALL_OFFLINE}, { 0x105090, 3, RI_ALL_ONLINE}, - { 0x10509c, 1, RI_ALL_OFFLINE}, { 0x1050a0, 3, RI_ALL_ONLINE}, - { 0x1050ac, 1, RI_ALL_OFFLINE}, { 0x1050b0, 3, RI_ALL_ONLINE}, - { 0x1050bc, 1, RI_ALL_OFFLINE}, { 0x1050c0, 3, RI_ALL_ONLINE}, - { 0x1050cc, 1, RI_ALL_OFFLINE}, { 0x1050d0, 3, RI_ALL_ONLINE}, - { 0x1050dc, 1, RI_ALL_OFFLINE}, { 0x1050e0, 3, RI_ALL_ONLINE}, - { 0x1050ec, 1, RI_ALL_OFFLINE}, { 0x1050f0, 3, RI_ALL_ONLINE}, - { 0x1050fc, 1, RI_ALL_OFFLINE}, { 0x105100, 3, RI_ALL_ONLINE}, - { 0x10510c, 1, RI_ALL_OFFLINE}, { 0x105110, 3, RI_ALL_ONLINE}, - { 0x10511c, 1, RI_ALL_OFFLINE}, { 0x105120, 3, RI_ALL_ONLINE}, - { 0x10512c, 1, RI_ALL_OFFLINE}, { 0x105130, 3, RI_ALL_ONLINE}, - { 0x10513c, 1, RI_ALL_OFFLINE}, { 0x105140, 3, RI_ALL_ONLINE}, - { 0x10514c, 1, RI_ALL_OFFLINE}, { 0x105150, 3, RI_ALL_ONLINE}, - { 0x10515c, 1, RI_ALL_OFFLINE}, { 0x105160, 3, RI_ALL_ONLINE}, - { 0x10516c, 1, RI_ALL_OFFLINE}, { 0x105170, 3, RI_ALL_ONLINE}, - { 0x10517c, 1, RI_ALL_OFFLINE}, { 0x105180, 3, RI_ALL_ONLINE}, - { 0x10518c, 1, RI_ALL_OFFLINE}, { 0x105190, 3, RI_ALL_ONLINE}, - { 0x10519c, 1, RI_ALL_OFFLINE}, { 0x1051a0, 3, RI_ALL_ONLINE}, - { 0x1051ac, 1, RI_ALL_OFFLINE}, { 0x1051b0, 3, RI_ALL_ONLINE}, - { 0x1051bc, 1, RI_ALL_OFFLINE}, { 0x1051c0, 3, RI_ALL_ONLINE}, - { 0x1051cc, 1, RI_ALL_OFFLINE}, { 0x1051d0, 3, RI_ALL_ONLINE}, - { 0x1051dc, 1, RI_ALL_OFFLINE}, { 0x1051e0, 3, RI_ALL_ONLINE}, - { 0x1051ec, 1, RI_ALL_OFFLINE}, { 0x1051f0, 3, RI_ALL_ONLINE}, - { 0x1051fc, 1, RI_ALL_OFFLINE}, { 0x105200, 3, RI_ALL_ONLINE}, - { 0x10520c, 1, RI_ALL_OFFLINE}, { 0x105210, 3, RI_ALL_ONLINE}, - { 0x10521c, 1, RI_ALL_OFFLINE}, { 0x105220, 3, RI_ALL_ONLINE}, - { 0x10522c, 1, RI_ALL_OFFLINE}, { 0x105230, 3, RI_ALL_ONLINE}, - { 0x10523c, 1, RI_ALL_OFFLINE}, { 0x105240, 3, RI_ALL_ONLINE}, - { 0x10524c, 1, RI_ALL_OFFLINE}, { 0x105250, 3, RI_ALL_ONLINE}, - { 0x10525c, 1, RI_ALL_OFFLINE}, { 0x105260, 3, RI_ALL_ONLINE}, - { 0x10526c, 1, RI_ALL_OFFLINE}, { 0x105270, 3, RI_ALL_ONLINE}, - { 0x10527c, 1, RI_ALL_OFFLINE}, { 0x105280, 3, RI_ALL_ONLINE}, - { 0x10528c, 1, RI_ALL_OFFLINE}, { 0x105290, 3, RI_ALL_ONLINE}, - { 0x10529c, 1, RI_ALL_OFFLINE}, { 0x1052a0, 3, RI_ALL_ONLINE}, - { 0x1052ac, 1, RI_ALL_OFFLINE}, { 0x1052b0, 3, RI_ALL_ONLINE}, - { 0x1052bc, 1, RI_ALL_OFFLINE}, { 0x1052c0, 3, RI_ALL_ONLINE}, - { 0x1052cc, 1, RI_ALL_OFFLINE}, { 0x1052d0, 3, RI_ALL_ONLINE}, - { 0x1052dc, 1, RI_ALL_OFFLINE}, { 0x1052e0, 3, RI_ALL_ONLINE}, - { 0x1052ec, 1, RI_ALL_OFFLINE}, { 0x1052f0, 3, RI_ALL_ONLINE}, - { 0x1052fc, 1, RI_ALL_OFFLINE}, { 0x105300, 3, RI_ALL_ONLINE}, - { 0x10530c, 1, RI_ALL_OFFLINE}, { 0x105310, 3, RI_ALL_ONLINE}, - { 0x10531c, 1, RI_ALL_OFFLINE}, { 0x105320, 3, RI_ALL_ONLINE}, - { 0x10532c, 1, RI_ALL_OFFLINE}, { 0x105330, 3, RI_ALL_ONLINE}, - { 0x10533c, 1, RI_ALL_OFFLINE}, { 0x105340, 3, RI_ALL_ONLINE}, - { 0x10534c, 1, RI_ALL_OFFLINE}, { 0x105350, 3, RI_ALL_ONLINE}, - { 0x10535c, 1, RI_ALL_OFFLINE}, { 0x105360, 3, RI_ALL_ONLINE}, - { 0x10536c, 1, RI_ALL_OFFLINE}, { 0x105370, 3, RI_ALL_ONLINE}, - { 0x10537c, 1, RI_ALL_OFFLINE}, { 0x105380, 3, RI_ALL_ONLINE}, - { 0x10538c, 1, RI_ALL_OFFLINE}, { 0x105390, 3, RI_ALL_ONLINE}, - { 0x10539c, 1, RI_ALL_OFFLINE}, { 0x1053a0, 3, RI_ALL_ONLINE}, - { 0x1053ac, 1, RI_ALL_OFFLINE}, { 0x1053b0, 3, RI_ALL_ONLINE}, - { 0x1053bc, 1, RI_ALL_OFFLINE}, { 0x1053c0, 3, RI_ALL_ONLINE}, - { 0x1053cc, 1, RI_ALL_OFFLINE}, { 0x1053d0, 3, RI_ALL_ONLINE}, - { 0x1053dc, 1, RI_ALL_OFFLINE}, { 0x1053e0, 3, RI_ALL_ONLINE}, - { 0x1053ec, 1, RI_ALL_OFFLINE}, { 0x1053f0, 3, RI_ALL_ONLINE}, - { 0x1053fc, 769, RI_ALL_OFFLINE}, { 0x108000, 33, RI_ALL_ONLINE}, - { 0x108090, 1, RI_ALL_ONLINE}, { 0x1080a0, 1, RI_ALL_ONLINE}, - { 0x1080ac, 5, RI_E1H_ONLINE}, { 0x108100, 5, RI_ALL_ONLINE}, - { 0x108120, 5, RI_ALL_ONLINE}, { 0x108200, 74, RI_ALL_ONLINE}, - { 0x108400, 74, RI_ALL_ONLINE}, { 0x108800, 152, RI_ALL_ONLINE}, - { 0x109000, 1, RI_ALL_ONLINE}, { 0x120000, 347, RI_ALL_ONLINE}, - { 0x120578, 1, RI_ALL_ONLINE}, { 0x120588, 1, RI_ALL_ONLINE}, - { 0x120598, 1, RI_ALL_ONLINE}, { 0x12059c, 23, RI_E1H_ONLINE}, - { 0x120614, 1, RI_E1H_ONLINE}, { 0x12061c, 30, RI_E1H_ONLINE}, - { 0x12080c, 65, RI_ALL_ONLINE}, { 0x120a00, 2, RI_ALL_ONLINE}, - { 0x122000, 2, RI_ALL_ONLINE}, { 0x128000, 2, RI_E1H_ONLINE}, - { 0x140000, 114, RI_ALL_ONLINE}, { 0x1401d4, 1, RI_ALL_ONLINE}, - { 0x1401e4, 1, RI_ALL_ONLINE}, { 0x140200, 6, RI_ALL_ONLINE}, - { 0x144000, 4, RI_ALL_ONLINE}, { 0x148000, 4, RI_ALL_ONLINE}, - { 0x14c000, 4, RI_ALL_ONLINE}, { 0x150000, 4, RI_ALL_ONLINE}, - { 0x154000, 4, RI_ALL_ONLINE}, { 0x158000, 4, RI_ALL_ONLINE}, - { 0x15c000, 7, RI_E1H_ONLINE}, { 0x161000, 7, RI_ALL_ONLINE}, - { 0x161028, 1, RI_ALL_ONLINE}, { 0x161038, 1, RI_ALL_ONLINE}, - { 0x161800, 2, RI_ALL_ONLINE}, { 0x164000, 60, RI_ALL_ONLINE}, - { 0x1640fc, 1, RI_ALL_ONLINE}, { 0x16410c, 1, RI_ALL_ONLINE}, - { 0x164110, 2, RI_E1H_ONLINE}, { 0x164200, 1, RI_ALL_ONLINE}, - { 0x164208, 1, RI_ALL_ONLINE}, { 0x164210, 1, RI_ALL_ONLINE}, - { 0x164218, 1, RI_ALL_ONLINE}, { 0x164220, 1, RI_ALL_ONLINE}, - { 0x164228, 1, RI_ALL_ONLINE}, { 0x164230, 1, RI_ALL_ONLINE}, - { 0x164238, 1, RI_ALL_ONLINE}, { 0x164240, 1, RI_ALL_ONLINE}, - { 0x164248, 1, RI_ALL_ONLINE}, { 0x164250, 1, RI_ALL_ONLINE}, - { 0x164258, 1, RI_ALL_ONLINE}, { 0x164260, 1, RI_ALL_ONLINE}, - { 0x164270, 2, RI_ALL_ONLINE}, { 0x164280, 2, RI_ALL_ONLINE}, - { 0x164800, 2, RI_ALL_ONLINE}, { 0x165000, 2, RI_ALL_ONLINE}, - { 0x166000, 164, RI_ALL_ONLINE}, { 0x16629c, 1, RI_ALL_ONLINE}, - { 0x1662ac, 1, RI_ALL_ONLINE}, { 0x1662bc, 1, RI_ALL_ONLINE}, - { 0x166400, 49, RI_ALL_ONLINE}, { 0x1664c8, 38, RI_ALL_ONLINE}, - { 0x166568, 2, RI_ALL_ONLINE}, { 0x166800, 1, RI_ALL_ONLINE}, - { 0x168000, 270, RI_ALL_ONLINE}, { 0x168444, 1, RI_ALL_ONLINE}, - { 0x168454, 1, RI_ALL_ONLINE}, { 0x168800, 19, RI_ALL_ONLINE}, - { 0x168900, 1, RI_ALL_ONLINE}, { 0x168a00, 128, RI_ALL_ONLINE}, - { 0x16a000, 1, RI_ALL_ONLINE}, { 0x16a004, 1535, RI_ALL_OFFLINE}, - { 0x16c000, 1, RI_ALL_ONLINE}, { 0x16c004, 1535, RI_ALL_OFFLINE}, - { 0x16e000, 16, RI_E1H_ONLINE}, { 0x16e100, 1, RI_E1H_ONLINE}, - { 0x16e200, 2, RI_E1H_ONLINE}, { 0x16e400, 183, RI_E1H_ONLINE}, - { 0x170000, 93, RI_ALL_ONLINE}, { 0x170180, 1, RI_ALL_ONLINE}, - { 0x170190, 1, RI_ALL_ONLINE}, { 0x170200, 4, RI_ALL_ONLINE}, - { 0x170214, 1, RI_ALL_ONLINE}, { 0x178000, 1, RI_ALL_ONLINE}, - { 0x180000, 61, RI_ALL_ONLINE}, { 0x180100, 1, RI_ALL_ONLINE}, - { 0x180110, 1, RI_ALL_ONLINE}, { 0x180120, 1, RI_ALL_ONLINE}, - { 0x180130, 1, RI_ALL_ONLINE}, { 0x18013c, 2, RI_E1H_ONLINE}, - { 0x180200, 58, RI_ALL_ONLINE}, { 0x180340, 4, RI_ALL_ONLINE}, - { 0x180400, 1, RI_ALL_ONLINE}, { 0x180404, 255, RI_ALL_OFFLINE}, - { 0x181000, 4, RI_ALL_ONLINE}, { 0x181010, 1020, RI_ALL_OFFLINE}, - { 0x1a0000, 1, RI_ALL_ONLINE}, { 0x1a0004, 1023, RI_ALL_OFFLINE}, - { 0x1a1000, 1, RI_ALL_ONLINE}, { 0x1a1004, 4607, RI_ALL_OFFLINE}, - { 0x1a5800, 2560, RI_E1H_OFFLINE}, { 0x1a8000, 64, RI_ALL_OFFLINE}, - { 0x1a8100, 1984, RI_E1H_OFFLINE}, { 0x1aa000, 1, RI_E1H_ONLINE}, - { 0x1aa004, 6655, RI_E1H_OFFLINE}, { 0x1b1800, 128, RI_ALL_OFFLINE}, - { 0x1b1c00, 128, RI_ALL_OFFLINE}, { 0x1b2000, 1, RI_ALL_OFFLINE}, - { 0x1b2400, 64, RI_E1H_OFFLINE}, { 0x1b8200, 1, RI_ALL_ONLINE}, - { 0x1b8240, 1, RI_ALL_ONLINE}, { 0x1b8280, 1, RI_ALL_ONLINE}, - { 0x1b82c0, 1, RI_ALL_ONLINE}, { 0x1b8a00, 1, RI_ALL_ONLINE}, - { 0x1b8a80, 1, RI_ALL_ONLINE}, { 0x1c0000, 2, RI_ALL_ONLINE}, - { 0x200000, 65, RI_ALL_ONLINE}, { 0x200110, 1, RI_ALL_ONLINE}, - { 0x200120, 1, RI_ALL_ONLINE}, { 0x200130, 1, RI_ALL_ONLINE}, - { 0x200140, 1, RI_ALL_ONLINE}, { 0x20014c, 2, RI_E1H_ONLINE}, - { 0x200200, 58, RI_ALL_ONLINE}, { 0x200340, 4, RI_ALL_ONLINE}, - { 0x200400, 1, RI_ALL_ONLINE}, { 0x200404, 255, RI_ALL_OFFLINE}, - { 0x202000, 4, RI_ALL_ONLINE}, { 0x202010, 2044, RI_ALL_OFFLINE}, - { 0x220000, 1, RI_ALL_ONLINE}, { 0x220004, 1023, RI_ALL_OFFLINE}, - { 0x221000, 1, RI_ALL_ONLINE}, { 0x221004, 4607, RI_ALL_OFFLINE}, - { 0x225800, 1536, RI_E1H_OFFLINE}, { 0x227000, 1, RI_E1H_ONLINE}, - { 0x227004, 1023, RI_E1H_OFFLINE}, { 0x228000, 64, RI_ALL_OFFLINE}, - { 0x228100, 8640, RI_E1H_OFFLINE}, { 0x231800, 128, RI_ALL_OFFLINE}, - { 0x231c00, 128, RI_ALL_OFFLINE}, { 0x232000, 1, RI_ALL_OFFLINE}, - { 0x232400, 64, RI_E1H_OFFLINE}, { 0x238200, 1, RI_ALL_ONLINE}, - { 0x238240, 1, RI_ALL_ONLINE}, { 0x238280, 1, RI_ALL_ONLINE}, - { 0x2382c0, 1, RI_ALL_ONLINE}, { 0x238a00, 1, RI_ALL_ONLINE}, - { 0x238a80, 1, RI_ALL_ONLINE}, { 0x240000, 2, RI_ALL_ONLINE}, - { 0x280000, 65, RI_ALL_ONLINE}, { 0x280110, 1, RI_ALL_ONLINE}, - { 0x280120, 1, RI_ALL_ONLINE}, { 0x280130, 1, RI_ALL_ONLINE}, - { 0x280140, 1, RI_ALL_ONLINE}, { 0x28014c, 2, RI_E1H_ONLINE}, - { 0x280200, 58, RI_ALL_ONLINE}, { 0x280340, 4, RI_ALL_ONLINE}, - { 0x280400, 1, RI_ALL_ONLINE}, { 0x280404, 255, RI_ALL_OFFLINE}, - { 0x282000, 4, RI_ALL_ONLINE}, { 0x282010, 2044, RI_ALL_OFFLINE}, - { 0x2a0000, 1, RI_ALL_ONLINE}, { 0x2a0004, 1023, RI_ALL_OFFLINE}, - { 0x2a1000, 1, RI_ALL_ONLINE}, { 0x2a1004, 4607, RI_ALL_OFFLINE}, - { 0x2a5800, 2560, RI_E1H_OFFLINE}, { 0x2a8000, 64, RI_ALL_OFFLINE}, - { 0x2a8100, 960, RI_E1H_OFFLINE}, { 0x2a9000, 1, RI_E1H_ONLINE}, - { 0x2a9004, 7679, RI_E1H_OFFLINE}, { 0x2b1800, 128, RI_ALL_OFFLINE}, - { 0x2b1c00, 128, RI_ALL_OFFLINE}, { 0x2b2000, 1, RI_ALL_OFFLINE}, - { 0x2b2400, 64, RI_E1H_OFFLINE}, { 0x2b8200, 1, RI_ALL_ONLINE}, - { 0x2b8240, 1, RI_ALL_ONLINE}, { 0x2b8280, 1, RI_ALL_ONLINE}, - { 0x2b82c0, 1, RI_ALL_ONLINE}, { 0x2b8a00, 1, RI_ALL_ONLINE}, - { 0x2b8a80, 1, RI_ALL_ONLINE}, { 0x2c0000, 2, RI_ALL_ONLINE}, - { 0x300000, 65, RI_ALL_ONLINE}, { 0x300110, 1, RI_ALL_ONLINE}, - { 0x300120, 1, RI_ALL_ONLINE}, { 0x300130, 1, RI_ALL_ONLINE}, - { 0x300140, 1, RI_ALL_ONLINE}, { 0x30014c, 2, RI_E1H_ONLINE}, - { 0x300200, 58, RI_ALL_ONLINE}, { 0x300340, 4, RI_ALL_ONLINE}, - { 0x300400, 1, RI_ALL_ONLINE}, { 0x300404, 255, RI_ALL_OFFLINE}, - { 0x302000, 4, RI_ALL_ONLINE}, { 0x302010, 2044, RI_ALL_OFFLINE}, - { 0x320000, 1, RI_ALL_ONLINE}, { 0x320004, 1023, RI_ALL_OFFLINE}, - { 0x321000, 1, RI_ALL_ONLINE}, { 0x321004, 4607, RI_ALL_OFFLINE}, - { 0x325800, 2560, RI_E1H_OFFLINE}, { 0x328000, 64, RI_ALL_OFFLINE}, - { 0x328100, 536, RI_E1H_OFFLINE}, { 0x328960, 1, RI_E1H_ONLINE}, - { 0x328964, 8103, RI_E1H_OFFLINE}, { 0x331800, 128, RI_ALL_OFFLINE}, - { 0x331c00, 128, RI_ALL_OFFLINE}, { 0x332000, 1, RI_ALL_OFFLINE}, - { 0x332400, 64, RI_E1H_OFFLINE}, { 0x338200, 1, RI_ALL_ONLINE}, - { 0x338240, 1, RI_ALL_ONLINE}, { 0x338280, 1, RI_ALL_ONLINE}, - { 0x3382c0, 1, RI_ALL_ONLINE}, { 0x338a00, 1, RI_ALL_ONLINE}, - { 0x338a80, 1, RI_ALL_ONLINE}, { 0x340000, 2, RI_ALL_ONLINE} + { 0x2000, 341, RI_ALL_ONLINE }, { 0x2800, 103, RI_ALL_ONLINE }, + { 0x3000, 287, RI_ALL_ONLINE }, { 0x3800, 331, RI_ALL_ONLINE }, + { 0x8800, 6, RI_E1_ONLINE }, { 0xa000, 223, RI_ALL_ONLINE }, + { 0xa388, 1, RI_ALL_ONLINE }, { 0xa398, 1, RI_ALL_ONLINE }, + { 0xa39c, 7, RI_E1H_ONLINE }, { 0xa3c0, 3, RI_E1H_ONLINE }, + { 0xa3d0, 1, RI_E1H_ONLINE }, { 0xa3d8, 1, RI_E1H_ONLINE }, + { 0xa3e0, 1, RI_E1H_ONLINE }, { 0xa3e8, 1, RI_E1H_ONLINE }, + { 0xa3f0, 1, RI_E1H_ONLINE }, { 0xa3f8, 1, RI_E1H_ONLINE }, + { 0xa400, 69, RI_ALL_ONLINE }, { 0xa518, 1, RI_ALL_ONLINE }, + { 0xa520, 1, RI_ALL_ONLINE }, { 0xa528, 1, RI_ALL_ONLINE }, + { 0xa530, 1, RI_ALL_ONLINE }, { 0xa538, 1, RI_ALL_ONLINE }, + { 0xa540, 1, RI_ALL_ONLINE }, { 0xa548, 1, RI_ALL_ONLINE }, + { 0xa550, 1, RI_ALL_ONLINE }, { 0xa558, 1, RI_ALL_ONLINE }, + { 0xa560, 1, RI_ALL_ONLINE }, { 0xa568, 1, RI_ALL_ONLINE }, + { 0xa570, 1, RI_ALL_ONLINE }, { 0xa580, 1, RI_ALL_ONLINE }, + { 0xa590, 1, RI_ALL_ONLINE }, { 0xa5a0, 1, RI_ALL_ONLINE }, + { 0xa5c0, 1, RI_ALL_ONLINE }, { 0xa5e0, 1, RI_E1H_ONLINE }, + { 0xa5e8, 1, RI_E1H_ONLINE }, { 0xa5f0, 1, RI_E1H_ONLINE }, + { 0xa5f8, 10, RI_E1H_ONLINE }, { 0x10000, 236, RI_ALL_ONLINE }, + { 0x103bc, 1, RI_ALL_ONLINE }, { 0x103cc, 1, RI_ALL_ONLINE }, + { 0x103dc, 1, RI_ALL_ONLINE }, { 0x10400, 57, RI_ALL_ONLINE }, + { 0x104e8, 2, RI_ALL_ONLINE }, { 0x104f4, 2, RI_ALL_ONLINE }, + { 0x10500, 146, RI_ALL_ONLINE }, { 0x10750, 2, RI_ALL_ONLINE }, + { 0x10760, 2, RI_ALL_ONLINE }, { 0x10770, 2, RI_ALL_ONLINE }, + { 0x10780, 2, RI_ALL_ONLINE }, { 0x10790, 2, RI_ALL_ONLINE }, + { 0x107a0, 2, RI_ALL_ONLINE }, { 0x107b0, 2, RI_ALL_ONLINE }, + { 0x107c0, 2, RI_ALL_ONLINE }, { 0x107d0, 2, RI_ALL_ONLINE }, + { 0x107e0, 2, RI_ALL_ONLINE }, { 0x10880, 2, RI_ALL_ONLINE }, + { 0x10900, 2, RI_ALL_ONLINE }, { 0x12000, 1, RI_ALL_ONLINE }, + { 0x14000, 1, RI_ALL_ONLINE }, { 0x16000, 26, RI_E1H_ONLINE }, + { 0x16070, 18, RI_E1H_ONLINE }, { 0x160c0, 27, RI_E1H_ONLINE }, + { 0x16140, 1, RI_E1H_ONLINE }, { 0x16160, 1, RI_E1H_ONLINE }, + { 0x16180, 2, RI_E1H_ONLINE }, { 0x161c0, 2, RI_E1H_ONLINE }, + { 0x16204, 5, RI_E1H_ONLINE }, { 0x18000, 1, RI_E1H_ONLINE }, + { 0x18008, 1, RI_E1H_ONLINE }, { 0x20000, 24, RI_ALL_ONLINE }, + { 0x20060, 8, RI_ALL_ONLINE }, { 0x20080, 138, RI_ALL_ONLINE }, + { 0x202b4, 1, RI_ALL_ONLINE }, { 0x202c4, 1, RI_ALL_ONLINE }, + { 0x20400, 2, RI_ALL_ONLINE }, { 0x2040c, 8, RI_ALL_ONLINE }, + { 0x2042c, 18, RI_E1H_ONLINE }, { 0x20480, 1, RI_ALL_ONLINE }, + { 0x20500, 1, RI_ALL_ONLINE }, { 0x20600, 1, RI_ALL_ONLINE }, + { 0x28000, 1, RI_ALL_ONLINE }, { 0x28004, 8191, RI_ALL_OFFLINE }, + { 0x30000, 1, RI_ALL_ONLINE }, { 0x30004, 16383, RI_ALL_OFFLINE }, + { 0x40000, 98, RI_ALL_ONLINE }, { 0x40194, 1, RI_ALL_ONLINE }, + { 0x401a4, 1, RI_ALL_ONLINE }, { 0x401a8, 11, RI_E1H_ONLINE }, + { 0x40200, 4, RI_ALL_ONLINE }, { 0x40400, 43, RI_ALL_ONLINE }, + { 0x404b8, 1, RI_ALL_ONLINE }, { 0x404c8, 1, RI_ALL_ONLINE }, + { 0x404cc, 3, RI_E1H_ONLINE }, { 0x40500, 2, RI_ALL_ONLINE }, + { 0x40510, 2, RI_ALL_ONLINE }, { 0x40520, 2, RI_ALL_ONLINE }, + { 0x40530, 2, RI_ALL_ONLINE }, { 0x40540, 2, RI_ALL_ONLINE }, + { 0x42000, 164, RI_ALL_ONLINE }, { 0x4229c, 1, RI_ALL_ONLINE }, + { 0x422ac, 1, RI_ALL_ONLINE }, { 0x422bc, 1, RI_ALL_ONLINE }, + { 0x422d4, 5, RI_E1H_ONLINE }, { 0x42400, 49, RI_ALL_ONLINE }, + { 0x424c8, 38, RI_ALL_ONLINE }, { 0x42568, 2, RI_ALL_ONLINE }, + { 0x42800, 1, RI_ALL_ONLINE }, { 0x50000, 20, RI_ALL_ONLINE }, + { 0x50050, 8, RI_ALL_ONLINE }, { 0x50070, 88, RI_ALL_ONLINE }, + { 0x501dc, 1, RI_ALL_ONLINE }, { 0x501ec, 1, RI_ALL_ONLINE }, + { 0x501f0, 4, RI_E1H_ONLINE }, { 0x50200, 2, RI_ALL_ONLINE }, + { 0x5020c, 7, RI_ALL_ONLINE }, { 0x50228, 6, RI_E1H_ONLINE }, + { 0x50240, 1, RI_ALL_ONLINE }, { 0x50280, 1, RI_ALL_ONLINE }, + { 0x52000, 1, RI_ALL_ONLINE }, { 0x54000, 1, RI_ALL_ONLINE }, + { 0x54004, 3327, RI_ALL_OFFLINE }, { 0x58000, 1, RI_ALL_ONLINE }, + { 0x58004, 8191, RI_ALL_OFFLINE }, { 0x60000, 71, RI_ALL_ONLINE }, + { 0x60128, 1, RI_ALL_ONLINE }, { 0x60138, 1, RI_ALL_ONLINE }, + { 0x6013c, 24, RI_E1H_ONLINE }, { 0x60200, 1, RI_ALL_ONLINE }, + { 0x61000, 1, RI_ALL_ONLINE }, { 0x61004, 511, RI_ALL_OFFLINE }, + { 0x70000, 8, RI_ALL_ONLINE }, { 0x70020, 21496, RI_ALL_OFFLINE }, + { 0x85000, 3, RI_ALL_ONLINE }, { 0x8500c, 4, RI_ALL_OFFLINE }, + { 0x8501c, 7, RI_ALL_ONLINE }, { 0x85038, 4, RI_ALL_OFFLINE }, + { 0x85048, 1, RI_ALL_ONLINE }, { 0x8504c, 109, RI_ALL_OFFLINE }, + { 0x85200, 32, RI_ALL_ONLINE }, { 0x85280, 11104, RI_ALL_OFFLINE }, + { 0xa0000, 16384, RI_ALL_ONLINE }, { 0xb0000, 16384, RI_E1H_ONLINE }, + { 0xc1000, 7, RI_ALL_ONLINE }, { 0xc1028, 1, RI_ALL_ONLINE }, + { 0xc1038, 1, RI_ALL_ONLINE }, { 0xc1800, 2, RI_ALL_ONLINE }, + { 0xc2000, 164, RI_ALL_ONLINE }, { 0xc229c, 1, RI_ALL_ONLINE }, + { 0xc22ac, 1, RI_ALL_ONLINE }, { 0xc22bc, 1, RI_ALL_ONLINE }, + { 0xc2400, 49, RI_ALL_ONLINE }, { 0xc24c8, 38, RI_ALL_ONLINE }, + { 0xc2568, 2, RI_ALL_ONLINE }, { 0xc2600, 1, RI_ALL_ONLINE }, + { 0xc4000, 165, RI_ALL_ONLINE }, { 0xc42a0, 1, RI_ALL_ONLINE }, + { 0xc42b0, 1, RI_ALL_ONLINE }, { 0xc42c0, 1, RI_ALL_ONLINE }, + { 0xc42e0, 7, RI_E1H_ONLINE }, { 0xc4400, 51, RI_ALL_ONLINE }, + { 0xc44d0, 38, RI_ALL_ONLINE }, { 0xc4570, 2, RI_ALL_ONLINE }, + { 0xc4600, 1, RI_ALL_ONLINE }, { 0xd0000, 19, RI_ALL_ONLINE }, + { 0xd004c, 8, RI_ALL_ONLINE }, { 0xd006c, 91, RI_ALL_ONLINE }, + { 0xd01e4, 1, RI_ALL_ONLINE }, { 0xd01f4, 1, RI_ALL_ONLINE }, + { 0xd0200, 2, RI_ALL_ONLINE }, { 0xd020c, 7, RI_ALL_ONLINE }, + { 0xd0228, 18, RI_E1H_ONLINE }, { 0xd0280, 1, RI_ALL_ONLINE }, + { 0xd0300, 1, RI_ALL_ONLINE }, { 0xd0400, 1, RI_ALL_ONLINE }, + { 0xd4000, 1, RI_ALL_ONLINE }, { 0xd4004, 2559, RI_ALL_OFFLINE }, + { 0xd8000, 1, RI_ALL_ONLINE }, { 0xd8004, 8191, RI_ALL_OFFLINE }, + { 0xe0000, 21, RI_ALL_ONLINE }, { 0xe0054, 8, RI_ALL_ONLINE }, + { 0xe0074, 85, RI_ALL_ONLINE }, { 0xe01d4, 1, RI_ALL_ONLINE }, + { 0xe01e4, 1, RI_ALL_ONLINE }, { 0xe0200, 2, RI_ALL_ONLINE }, + { 0xe020c, 8, RI_ALL_ONLINE }, { 0xe022c, 18, RI_E1H_ONLINE }, + { 0xe0280, 1, RI_ALL_ONLINE }, { 0xe0300, 1, RI_ALL_ONLINE }, + { 0xe1000, 1, RI_ALL_ONLINE }, { 0xe2000, 1, RI_ALL_ONLINE }, + { 0xe2004, 2047, RI_ALL_OFFLINE }, { 0xf0000, 1, RI_ALL_ONLINE }, + { 0xf0004, 16383, RI_ALL_OFFLINE }, { 0x101000, 12, RI_ALL_ONLINE }, + { 0x10103c, 1, RI_ALL_ONLINE }, { 0x10104c, 1, RI_ALL_ONLINE }, + { 0x101050, 1, RI_E1H_ONLINE }, { 0x101100, 1, RI_ALL_ONLINE }, + { 0x101800, 8, RI_ALL_ONLINE }, { 0x102000, 18, RI_ALL_ONLINE }, + { 0x102054, 1, RI_ALL_ONLINE }, { 0x102064, 1, RI_ALL_ONLINE }, + { 0x102080, 17, RI_ALL_ONLINE }, { 0x1020c8, 8, RI_E1H_ONLINE }, + { 0x102400, 1, RI_ALL_ONLINE }, { 0x103000, 26, RI_ALL_ONLINE }, + { 0x103074, 1, RI_ALL_ONLINE }, { 0x103084, 1, RI_ALL_ONLINE }, + { 0x103094, 1, RI_ALL_ONLINE }, { 0x103098, 5, RI_E1H_ONLINE }, + { 0x103800, 8, RI_ALL_ONLINE }, { 0x104000, 63, RI_ALL_ONLINE }, + { 0x104108, 1, RI_ALL_ONLINE }, { 0x104118, 1, RI_ALL_ONLINE }, + { 0x104200, 17, RI_ALL_ONLINE }, { 0x104400, 64, RI_ALL_ONLINE }, + { 0x104500, 192, RI_ALL_OFFLINE }, { 0x104800, 64, RI_ALL_ONLINE }, + { 0x104900, 192, RI_ALL_OFFLINE }, { 0x105000, 7, RI_ALL_ONLINE }, + { 0x10501c, 1, RI_ALL_OFFLINE }, { 0x105020, 3, RI_ALL_ONLINE }, + { 0x10502c, 1, RI_ALL_OFFLINE }, { 0x105030, 3, RI_ALL_ONLINE }, + { 0x10503c, 1, RI_ALL_OFFLINE }, { 0x105040, 3, RI_ALL_ONLINE }, + { 0x10504c, 1, RI_ALL_OFFLINE }, { 0x105050, 3, RI_ALL_ONLINE }, + { 0x10505c, 1, RI_ALL_OFFLINE }, { 0x105060, 3, RI_ALL_ONLINE }, + { 0x10506c, 1, RI_ALL_OFFLINE }, { 0x105070, 3, RI_ALL_ONLINE }, + { 0x10507c, 1, RI_ALL_OFFLINE }, { 0x105080, 3, RI_ALL_ONLINE }, + { 0x10508c, 1, RI_ALL_OFFLINE }, { 0x105090, 3, RI_ALL_ONLINE }, + { 0x10509c, 1, RI_ALL_OFFLINE }, { 0x1050a0, 3, RI_ALL_ONLINE }, + { 0x1050ac, 1, RI_ALL_OFFLINE }, { 0x1050b0, 3, RI_ALL_ONLINE }, + { 0x1050bc, 1, RI_ALL_OFFLINE }, { 0x1050c0, 3, RI_ALL_ONLINE }, + { 0x1050cc, 1, RI_ALL_OFFLINE }, { 0x1050d0, 3, RI_ALL_ONLINE }, + { 0x1050dc, 1, RI_ALL_OFFLINE }, { 0x1050e0, 3, RI_ALL_ONLINE }, + { 0x1050ec, 1, RI_ALL_OFFLINE }, { 0x1050f0, 3, RI_ALL_ONLINE }, + { 0x1050fc, 1, RI_ALL_OFFLINE }, { 0x105100, 3, RI_ALL_ONLINE }, + { 0x10510c, 1, RI_ALL_OFFLINE }, { 0x105110, 3, RI_ALL_ONLINE }, + { 0x10511c, 1, RI_ALL_OFFLINE }, { 0x105120, 3, RI_ALL_ONLINE }, + { 0x10512c, 1, RI_ALL_OFFLINE }, { 0x105130, 3, RI_ALL_ONLINE }, + { 0x10513c, 1, RI_ALL_OFFLINE }, { 0x105140, 3, RI_ALL_ONLINE }, + { 0x10514c, 1, RI_ALL_OFFLINE }, { 0x105150, 3, RI_ALL_ONLINE }, + { 0x10515c, 1, RI_ALL_OFFLINE }, { 0x105160, 3, RI_ALL_ONLINE }, + { 0x10516c, 1, RI_ALL_OFFLINE }, { 0x105170, 3, RI_ALL_ONLINE }, + { 0x10517c, 1, RI_ALL_OFFLINE }, { 0x105180, 3, RI_ALL_ONLINE }, + { 0x10518c, 1, RI_ALL_OFFLINE }, { 0x105190, 3, RI_ALL_ONLINE }, + { 0x10519c, 1, RI_ALL_OFFLINE }, { 0x1051a0, 3, RI_ALL_ONLINE }, + { 0x1051ac, 1, RI_ALL_OFFLINE }, { 0x1051b0, 3, RI_ALL_ONLINE }, + { 0x1051bc, 1, RI_ALL_OFFLINE }, { 0x1051c0, 3, RI_ALL_ONLINE }, + { 0x1051cc, 1, RI_ALL_OFFLINE }, { 0x1051d0, 3, RI_ALL_ONLINE }, + { 0x1051dc, 1, RI_ALL_OFFLINE }, { 0x1051e0, 3, RI_ALL_ONLINE }, + { 0x1051ec, 1, RI_ALL_OFFLINE }, { 0x1051f0, 3, RI_ALL_ONLINE }, + { 0x1051fc, 1, RI_ALL_OFFLINE }, { 0x105200, 3, RI_ALL_ONLINE }, + { 0x10520c, 1, RI_ALL_OFFLINE }, { 0x105210, 3, RI_ALL_ONLINE }, + { 0x10521c, 1, RI_ALL_OFFLINE }, { 0x105220, 3, RI_ALL_ONLINE }, + { 0x10522c, 1, RI_ALL_OFFLINE }, { 0x105230, 3, RI_ALL_ONLINE }, + { 0x10523c, 1, RI_ALL_OFFLINE }, { 0x105240, 3, RI_ALL_ONLINE }, + { 0x10524c, 1, RI_ALL_OFFLINE }, { 0x105250, 3, RI_ALL_ONLINE }, + { 0x10525c, 1, RI_ALL_OFFLINE }, { 0x105260, 3, RI_ALL_ONLINE }, + { 0x10526c, 1, RI_ALL_OFFLINE }, { 0x105270, 3, RI_ALL_ONLINE }, + { 0x10527c, 1, RI_ALL_OFFLINE }, { 0x105280, 3, RI_ALL_ONLINE }, + { 0x10528c, 1, RI_ALL_OFFLINE }, { 0x105290, 3, RI_ALL_ONLINE }, + { 0x10529c, 1, RI_ALL_OFFLINE }, { 0x1052a0, 3, RI_ALL_ONLINE }, + { 0x1052ac, 1, RI_ALL_OFFLINE }, { 0x1052b0, 3, RI_ALL_ONLINE }, + { 0x1052bc, 1, RI_ALL_OFFLINE }, { 0x1052c0, 3, RI_ALL_ONLINE }, + { 0x1052cc, 1, RI_ALL_OFFLINE }, { 0x1052d0, 3, RI_ALL_ONLINE }, + { 0x1052dc, 1, RI_ALL_OFFLINE }, { 0x1052e0, 3, RI_ALL_ONLINE }, + { 0x1052ec, 1, RI_ALL_OFFLINE }, { 0x1052f0, 3, RI_ALL_ONLINE }, + { 0x1052fc, 1, RI_ALL_OFFLINE }, { 0x105300, 3, RI_ALL_ONLINE }, + { 0x10530c, 1, RI_ALL_OFFLINE }, { 0x105310, 3, RI_ALL_ONLINE }, + { 0x10531c, 1, RI_ALL_OFFLINE }, { 0x105320, 3, RI_ALL_ONLINE }, + { 0x10532c, 1, RI_ALL_OFFLINE }, { 0x105330, 3, RI_ALL_ONLINE }, + { 0x10533c, 1, RI_ALL_OFFLINE }, { 0x105340, 3, RI_ALL_ONLINE }, + { 0x10534c, 1, RI_ALL_OFFLINE }, { 0x105350, 3, RI_ALL_ONLINE }, + { 0x10535c, 1, RI_ALL_OFFLINE }, { 0x105360, 3, RI_ALL_ONLINE }, + { 0x10536c, 1, RI_ALL_OFFLINE }, { 0x105370, 3, RI_ALL_ONLINE }, + { 0x10537c, 1, RI_ALL_OFFLINE }, { 0x105380, 3, RI_ALL_ONLINE }, + { 0x10538c, 1, RI_ALL_OFFLINE }, { 0x105390, 3, RI_ALL_ONLINE }, + { 0x10539c, 1, RI_ALL_OFFLINE }, { 0x1053a0, 3, RI_ALL_ONLINE }, + { 0x1053ac, 1, RI_ALL_OFFLINE }, { 0x1053b0, 3, RI_ALL_ONLINE }, + { 0x1053bc, 1, RI_ALL_OFFLINE }, { 0x1053c0, 3, RI_ALL_ONLINE }, + { 0x1053cc, 1, RI_ALL_OFFLINE }, { 0x1053d0, 3, RI_ALL_ONLINE }, + { 0x1053dc, 1, RI_ALL_OFFLINE }, { 0x1053e0, 3, RI_ALL_ONLINE }, + { 0x1053ec, 1, RI_ALL_OFFLINE }, { 0x1053f0, 3, RI_ALL_ONLINE }, + { 0x1053fc, 769, RI_ALL_OFFLINE }, { 0x108000, 33, RI_ALL_ONLINE }, + { 0x108090, 1, RI_ALL_ONLINE }, { 0x1080a0, 1, RI_ALL_ONLINE }, + { 0x1080ac, 5, RI_E1H_ONLINE }, { 0x108100, 5, RI_ALL_ONLINE }, + { 0x108120, 5, RI_ALL_ONLINE }, { 0x108200, 74, RI_ALL_ONLINE }, + { 0x108400, 74, RI_ALL_ONLINE }, { 0x108800, 152, RI_ALL_ONLINE }, + { 0x109000, 1, RI_ALL_ONLINE }, { 0x120000, 347, RI_ALL_ONLINE }, + { 0x120578, 1, RI_ALL_ONLINE }, { 0x120588, 1, RI_ALL_ONLINE }, + { 0x120598, 1, RI_ALL_ONLINE }, { 0x12059c, 23, RI_E1H_ONLINE }, + { 0x120614, 1, RI_E1H_ONLINE }, { 0x12061c, 30, RI_E1H_ONLINE }, + { 0x12080c, 65, RI_ALL_ONLINE }, { 0x120a00, 2, RI_ALL_ONLINE }, + { 0x122000, 2, RI_ALL_ONLINE }, { 0x128000, 2, RI_E1H_ONLINE }, + { 0x140000, 114, RI_ALL_ONLINE }, { 0x1401d4, 1, RI_ALL_ONLINE }, + { 0x1401e4, 1, RI_ALL_ONLINE }, { 0x140200, 6, RI_ALL_ONLINE }, + { 0x144000, 4, RI_ALL_ONLINE }, { 0x148000, 4, RI_ALL_ONLINE }, + { 0x14c000, 4, RI_ALL_ONLINE }, { 0x150000, 4, RI_ALL_ONLINE }, + { 0x154000, 4, RI_ALL_ONLINE }, { 0x158000, 4, RI_ALL_ONLINE }, + { 0x15c000, 7, RI_E1H_ONLINE }, { 0x161000, 7, RI_ALL_ONLINE }, + { 0x161028, 1, RI_ALL_ONLINE }, { 0x161038, 1, RI_ALL_ONLINE }, + { 0x161800, 2, RI_ALL_ONLINE }, { 0x164000, 60, RI_ALL_ONLINE }, + { 0x1640fc, 1, RI_ALL_ONLINE }, { 0x16410c, 1, RI_ALL_ONLINE }, + { 0x164110, 2, RI_E1H_ONLINE }, { 0x164200, 1, RI_ALL_ONLINE }, + { 0x164208, 1, RI_ALL_ONLINE }, { 0x164210, 1, RI_ALL_ONLINE }, + { 0x164218, 1, RI_ALL_ONLINE }, { 0x164220, 1, RI_ALL_ONLINE }, + { 0x164228, 1, RI_ALL_ONLINE }, { 0x164230, 1, RI_ALL_ONLINE }, + { 0x164238, 1, RI_ALL_ONLINE }, { 0x164240, 1, RI_ALL_ONLINE }, + { 0x164248, 1, RI_ALL_ONLINE }, { 0x164250, 1, RI_ALL_ONLINE }, + { 0x164258, 1, RI_ALL_ONLINE }, { 0x164260, 1, RI_ALL_ONLINE }, + { 0x164270, 2, RI_ALL_ONLINE }, { 0x164280, 2, RI_ALL_ONLINE }, + { 0x164800, 2, RI_ALL_ONLINE }, { 0x165000, 2, RI_ALL_ONLINE }, + { 0x166000, 164, RI_ALL_ONLINE }, { 0x16629c, 1, RI_ALL_ONLINE }, + { 0x1662ac, 1, RI_ALL_ONLINE }, { 0x1662bc, 1, RI_ALL_ONLINE }, + { 0x166400, 49, RI_ALL_ONLINE }, { 0x1664c8, 38, RI_ALL_ONLINE }, + { 0x166568, 2, RI_ALL_ONLINE }, { 0x166800, 1, RI_ALL_ONLINE }, + { 0x168000, 270, RI_ALL_ONLINE }, { 0x168444, 1, RI_ALL_ONLINE }, + { 0x168454, 1, RI_ALL_ONLINE }, { 0x168800, 19, RI_ALL_ONLINE }, + { 0x168900, 1, RI_ALL_ONLINE }, { 0x168a00, 128, RI_ALL_ONLINE }, + { 0x16a000, 1, RI_ALL_ONLINE }, { 0x16a004, 1535, RI_ALL_OFFLINE }, + { 0x16c000, 1, RI_ALL_ONLINE }, { 0x16c004, 1535, RI_ALL_OFFLINE }, + { 0x16e000, 16, RI_E1H_ONLINE }, { 0x16e100, 1, RI_E1H_ONLINE }, + { 0x16e200, 2, RI_E1H_ONLINE }, { 0x16e400, 183, RI_E1H_ONLINE }, + { 0x170000, 93, RI_ALL_ONLINE }, { 0x170180, 1, RI_ALL_ONLINE }, + { 0x170190, 1, RI_ALL_ONLINE }, { 0x170200, 4, RI_ALL_ONLINE }, + { 0x170214, 1, RI_ALL_ONLINE }, { 0x178000, 1, RI_ALL_ONLINE }, + { 0x180000, 61, RI_ALL_ONLINE }, { 0x180100, 1, RI_ALL_ONLINE }, + { 0x180110, 1, RI_ALL_ONLINE }, { 0x180120, 1, RI_ALL_ONLINE }, + { 0x180130, 1, RI_ALL_ONLINE }, { 0x18013c, 2, RI_E1H_ONLINE }, + { 0x180200, 58, RI_ALL_ONLINE }, { 0x180340, 4, RI_ALL_ONLINE }, + { 0x180400, 1, RI_ALL_ONLINE }, { 0x180404, 255, RI_ALL_OFFLINE }, + { 0x181000, 4, RI_ALL_ONLINE }, { 0x181010, 1020, RI_ALL_OFFLINE }, + { 0x1a0000, 1, RI_ALL_ONLINE }, { 0x1a0004, 1023, RI_ALL_OFFLINE }, + { 0x1a1000, 1, RI_ALL_ONLINE }, { 0x1a1004, 4607, RI_ALL_OFFLINE }, + { 0x1a5800, 2560, RI_E1H_OFFLINE }, { 0x1a8000, 64, RI_ALL_OFFLINE }, + { 0x1a8100, 1984, RI_E1H_OFFLINE }, { 0x1aa000, 1, RI_E1H_ONLINE }, + { 0x1aa004, 6655, RI_E1H_OFFLINE }, { 0x1b1800, 128, RI_ALL_OFFLINE }, + { 0x1b1c00, 128, RI_ALL_OFFLINE }, { 0x1b2000, 1, RI_ALL_OFFLINE }, + { 0x1b2400, 64, RI_E1H_OFFLINE }, { 0x1b8200, 1, RI_ALL_ONLINE }, + { 0x1b8240, 1, RI_ALL_ONLINE }, { 0x1b8280, 1, RI_ALL_ONLINE }, + { 0x1b82c0, 1, RI_ALL_ONLINE }, { 0x1b8a00, 1, RI_ALL_ONLINE }, + { 0x1b8a80, 1, RI_ALL_ONLINE }, { 0x1c0000, 2, RI_ALL_ONLINE }, + { 0x200000, 65, RI_ALL_ONLINE }, { 0x200110, 1, RI_ALL_ONLINE }, + { 0x200120, 1, RI_ALL_ONLINE }, { 0x200130, 1, RI_ALL_ONLINE }, + { 0x200140, 1, RI_ALL_ONLINE }, { 0x20014c, 2, RI_E1H_ONLINE }, + { 0x200200, 58, RI_ALL_ONLINE }, { 0x200340, 4, RI_ALL_ONLINE }, + { 0x200400, 1, RI_ALL_ONLINE }, { 0x200404, 255, RI_ALL_OFFLINE }, + { 0x202000, 4, RI_ALL_ONLINE }, { 0x202010, 2044, RI_ALL_OFFLINE }, + { 0x220000, 1, RI_ALL_ONLINE }, { 0x220004, 1023, RI_ALL_OFFLINE }, + { 0x221000, 1, RI_ALL_ONLINE }, { 0x221004, 4607, RI_ALL_OFFLINE }, + { 0x225800, 1536, RI_E1H_OFFLINE }, { 0x227000, 1, RI_E1H_ONLINE }, + { 0x227004, 1023, RI_E1H_OFFLINE }, { 0x228000, 64, RI_ALL_OFFLINE }, + { 0x228100, 8640, RI_E1H_OFFLINE }, { 0x231800, 128, RI_ALL_OFFLINE }, + { 0x231c00, 128, RI_ALL_OFFLINE }, { 0x232000, 1, RI_ALL_OFFLINE }, + { 0x232400, 64, RI_E1H_OFFLINE }, { 0x238200, 1, RI_ALL_ONLINE }, + { 0x238240, 1, RI_ALL_ONLINE }, { 0x238280, 1, RI_ALL_ONLINE }, + { 0x2382c0, 1, RI_ALL_ONLINE }, { 0x238a00, 1, RI_ALL_ONLINE }, + { 0x238a80, 1, RI_ALL_ONLINE }, { 0x240000, 2, RI_ALL_ONLINE }, + { 0x280000, 65, RI_ALL_ONLINE }, { 0x280110, 1, RI_ALL_ONLINE }, + { 0x280120, 1, RI_ALL_ONLINE }, { 0x280130, 1, RI_ALL_ONLINE }, + { 0x280140, 1, RI_ALL_ONLINE }, { 0x28014c, 2, RI_E1H_ONLINE }, + { 0x280200, 58, RI_ALL_ONLINE }, { 0x280340, 4, RI_ALL_ONLINE }, + { 0x280400, 1, RI_ALL_ONLINE }, { 0x280404, 255, RI_ALL_OFFLINE }, + { 0x282000, 4, RI_ALL_ONLINE }, { 0x282010, 2044, RI_ALL_OFFLINE }, + { 0x2a0000, 1, RI_ALL_ONLINE }, { 0x2a0004, 1023, RI_ALL_OFFLINE }, + { 0x2a1000, 1, RI_ALL_ONLINE }, { 0x2a1004, 4607, RI_ALL_OFFLINE }, + { 0x2a5800, 2560, RI_E1H_OFFLINE }, { 0x2a8000, 64, RI_ALL_OFFLINE }, + { 0x2a8100, 960, RI_E1H_OFFLINE }, { 0x2a9000, 1, RI_E1H_ONLINE }, + { 0x2a9004, 7679, RI_E1H_OFFLINE }, { 0x2b1800, 128, RI_ALL_OFFLINE }, + { 0x2b1c00, 128, RI_ALL_OFFLINE }, { 0x2b2000, 1, RI_ALL_OFFLINE }, + { 0x2b2400, 64, RI_E1H_OFFLINE }, { 0x2b8200, 1, RI_ALL_ONLINE }, + { 0x2b8240, 1, RI_ALL_ONLINE }, { 0x2b8280, 1, RI_ALL_ONLINE }, + { 0x2b82c0, 1, RI_ALL_ONLINE }, { 0x2b8a00, 1, RI_ALL_ONLINE }, + { 0x2b8a80, 1, RI_ALL_ONLINE }, { 0x2c0000, 2, RI_ALL_ONLINE }, + { 0x300000, 65, RI_ALL_ONLINE }, { 0x300110, 1, RI_ALL_ONLINE }, + { 0x300120, 1, RI_ALL_ONLINE }, { 0x300130, 1, RI_ALL_ONLINE }, + { 0x300140, 1, RI_ALL_ONLINE }, { 0x30014c, 2, RI_E1H_ONLINE }, + { 0x300200, 58, RI_ALL_ONLINE }, { 0x300340, 4, RI_ALL_ONLINE }, + { 0x300400, 1, RI_ALL_ONLINE }, { 0x300404, 255, RI_ALL_OFFLINE }, + { 0x302000, 4, RI_ALL_ONLINE }, { 0x302010, 2044, RI_ALL_OFFLINE }, + { 0x320000, 1, RI_ALL_ONLINE }, { 0x320004, 1023, RI_ALL_OFFLINE }, + { 0x321000, 1, RI_ALL_ONLINE }, { 0x321004, 4607, RI_ALL_OFFLINE }, + { 0x325800, 2560, RI_E1H_OFFLINE }, { 0x328000, 64, RI_ALL_OFFLINE }, + { 0x328100, 536, RI_E1H_OFFLINE }, { 0x328960, 1, RI_E1H_ONLINE }, + { 0x328964, 8103, RI_E1H_OFFLINE }, { 0x331800, 128, RI_ALL_OFFLINE }, + { 0x331c00, 128, RI_ALL_OFFLINE }, { 0x332000, 1, RI_ALL_OFFLINE }, + { 0x332400, 64, RI_E1H_OFFLINE }, { 0x338200, 1, RI_ALL_ONLINE }, + { 0x338240, 1, RI_ALL_ONLINE }, { 0x338280, 1, RI_ALL_ONLINE }, + { 0x3382c0, 1, RI_ALL_ONLINE }, { 0x338a00, 1, RI_ALL_ONLINE }, + { 0x338a80, 1, RI_ALL_ONLINE }, { 0x340000, 2, RI_ALL_ONLINE } }; -#define IDLEREGS_COUNT 277 -static const struct reg_addr idle_addrs[IDLEREGS_COUNT] = { - { 0x2114, 1, RI_ALL_ONLINE}, { 0x2120, 1, RI_ALL_ONLINE}, - { 0x212c, 4, RI_ALL_ONLINE}, { 0x2814, 1, RI_ALL_ONLINE}, - { 0x281c, 2, RI_ALL_ONLINE}, { 0xa38c, 1, RI_ALL_ONLINE}, - { 0xa408, 1, RI_ALL_ONLINE}, { 0xa42c, 12, RI_ALL_ONLINE}, - { 0xa600, 5, RI_E1H_ONLINE}, { 0xa618, 1, RI_E1H_ONLINE}, - { 0xc09c, 1, RI_ALL_ONLINE}, { 0x103b0, 1, RI_ALL_ONLINE}, - { 0x103c0, 1, RI_ALL_ONLINE}, { 0x103d0, 1, RI_E1H_ONLINE}, - { 0x2021c, 11, RI_ALL_ONLINE}, { 0x202a8, 1, RI_ALL_ONLINE}, - { 0x202b8, 1, RI_ALL_ONLINE}, { 0x20404, 1, RI_ALL_ONLINE}, - { 0x2040c, 2, RI_ALL_ONLINE}, { 0x2041c, 2, RI_ALL_ONLINE}, - { 0x40154, 14, RI_ALL_ONLINE}, { 0x40198, 1, RI_ALL_ONLINE}, - { 0x404ac, 1, RI_ALL_ONLINE}, { 0x404bc, 1, RI_ALL_ONLINE}, - { 0x42290, 1, RI_ALL_ONLINE}, { 0x422a0, 1, RI_ALL_ONLINE}, - { 0x422b0, 1, RI_ALL_ONLINE}, { 0x42548, 1, RI_ALL_ONLINE}, - { 0x42550, 1, RI_ALL_ONLINE}, { 0x42558, 1, RI_ALL_ONLINE}, - { 0x50160, 8, RI_ALL_ONLINE}, { 0x501d0, 1, RI_ALL_ONLINE}, - { 0x501e0, 1, RI_ALL_ONLINE}, { 0x50204, 1, RI_ALL_ONLINE}, - { 0x5020c, 2, RI_ALL_ONLINE}, { 0x5021c, 1, RI_ALL_ONLINE}, - { 0x60090, 1, RI_ALL_ONLINE}, { 0x6011c, 1, RI_ALL_ONLINE}, - { 0x6012c, 1, RI_ALL_ONLINE}, { 0xc101c, 1, RI_ALL_ONLINE}, - { 0xc102c, 1, RI_ALL_ONLINE}, { 0xc2290, 1, RI_ALL_ONLINE}, - { 0xc22a0, 1, RI_ALL_ONLINE}, { 0xc22b0, 1, RI_ALL_ONLINE}, - { 0xc2548, 1, RI_ALL_ONLINE}, { 0xc2550, 1, RI_ALL_ONLINE}, - { 0xc2558, 1, RI_ALL_ONLINE}, { 0xc4294, 1, RI_ALL_ONLINE}, - { 0xc42a4, 1, RI_ALL_ONLINE}, { 0xc42b4, 1, RI_ALL_ONLINE}, - { 0xc4550, 1, RI_ALL_ONLINE}, { 0xc4558, 1, RI_ALL_ONLINE}, - { 0xc4560, 1, RI_ALL_ONLINE}, { 0xd016c, 8, RI_ALL_ONLINE}, - { 0xd01d8, 1, RI_ALL_ONLINE}, { 0xd01e8, 1, RI_ALL_ONLINE}, - { 0xd0204, 1, RI_ALL_ONLINE}, { 0xd020c, 3, RI_ALL_ONLINE}, - { 0xe0154, 8, RI_ALL_ONLINE}, { 0xe01c8, 1, RI_ALL_ONLINE}, - { 0xe01d8, 1, RI_ALL_ONLINE}, { 0xe0204, 1, RI_ALL_ONLINE}, - { 0xe020c, 2, RI_ALL_ONLINE}, { 0xe021c, 2, RI_ALL_ONLINE}, - { 0x101014, 1, RI_ALL_ONLINE}, { 0x101030, 1, RI_ALL_ONLINE}, - { 0x101040, 1, RI_ALL_ONLINE}, { 0x102058, 1, RI_ALL_ONLINE}, - { 0x102080, 16, RI_ALL_ONLINE}, { 0x103004, 2, RI_ALL_ONLINE}, - { 0x103068, 1, RI_ALL_ONLINE}, { 0x103078, 1, RI_ALL_ONLINE}, - { 0x103088, 1, RI_ALL_ONLINE}, { 0x10309c, 2, RI_E1H_ONLINE}, - { 0x104004, 1, RI_ALL_ONLINE}, { 0x104018, 1, RI_ALL_ONLINE}, - { 0x104020, 1, RI_ALL_ONLINE}, { 0x10403c, 1, RI_ALL_ONLINE}, - { 0x1040fc, 1, RI_ALL_ONLINE}, { 0x10410c, 1, RI_ALL_ONLINE}, - { 0x104400, 64, RI_ALL_ONLINE}, { 0x104800, 64, RI_ALL_ONLINE}, - { 0x105000, 3, RI_ALL_ONLINE}, { 0x105010, 3, RI_ALL_ONLINE}, - { 0x105020, 3, RI_ALL_ONLINE}, { 0x105030, 3, RI_ALL_ONLINE}, - { 0x105040, 3, RI_ALL_ONLINE}, { 0x105050, 3, RI_ALL_ONLINE}, - { 0x105060, 3, RI_ALL_ONLINE}, { 0x105070, 3, RI_ALL_ONLINE}, - { 0x105080, 3, RI_ALL_ONLINE}, { 0x105090, 3, RI_ALL_ONLINE}, - { 0x1050a0, 3, RI_ALL_ONLINE}, { 0x1050b0, 3, RI_ALL_ONLINE}, - { 0x1050c0, 3, RI_ALL_ONLINE}, { 0x1050d0, 3, RI_ALL_ONLINE}, - { 0x1050e0, 3, RI_ALL_ONLINE}, { 0x1050f0, 3, RI_ALL_ONLINE}, - { 0x105100, 3, RI_ALL_ONLINE}, { 0x105110, 3, RI_ALL_ONLINE}, - { 0x105120, 3, RI_ALL_ONLINE}, { 0x105130, 3, RI_ALL_ONLINE}, - { 0x105140, 3, RI_ALL_ONLINE}, { 0x105150, 3, RI_ALL_ONLINE}, - { 0x105160, 3, RI_ALL_ONLINE}, { 0x105170, 3, RI_ALL_ONLINE}, - { 0x105180, 3, RI_ALL_ONLINE}, { 0x105190, 3, RI_ALL_ONLINE}, - { 0x1051a0, 3, RI_ALL_ONLINE}, { 0x1051b0, 3, RI_ALL_ONLINE}, - { 0x1051c0, 3, RI_ALL_ONLINE}, { 0x1051d0, 3, RI_ALL_ONLINE}, - { 0x1051e0, 3, RI_ALL_ONLINE}, { 0x1051f0, 3, RI_ALL_ONLINE}, - { 0x105200, 3, RI_ALL_ONLINE}, { 0x105210, 3, RI_ALL_ONLINE}, - { 0x105220, 3, RI_ALL_ONLINE}, { 0x105230, 3, RI_ALL_ONLINE}, - { 0x105240, 3, RI_ALL_ONLINE}, { 0x105250, 3, RI_ALL_ONLINE}, - { 0x105260, 3, RI_ALL_ONLINE}, { 0x105270, 3, RI_ALL_ONLINE}, - { 0x105280, 3, RI_ALL_ONLINE}, { 0x105290, 3, RI_ALL_ONLINE}, - { 0x1052a0, 3, RI_ALL_ONLINE}, { 0x1052b0, 3, RI_ALL_ONLINE}, - { 0x1052c0, 3, RI_ALL_ONLINE}, { 0x1052d0, 3, RI_ALL_ONLINE}, - { 0x1052e0, 3, RI_ALL_ONLINE}, { 0x1052f0, 3, RI_ALL_ONLINE}, - { 0x105300, 3, RI_ALL_ONLINE}, { 0x105310, 3, RI_ALL_ONLINE}, - { 0x105320, 3, RI_ALL_ONLINE}, { 0x105330, 3, RI_ALL_ONLINE}, - { 0x105340, 3, RI_ALL_ONLINE}, { 0x105350, 3, RI_ALL_ONLINE}, - { 0x105360, 3, RI_ALL_ONLINE}, { 0x105370, 3, RI_ALL_ONLINE}, - { 0x105380, 3, RI_ALL_ONLINE}, { 0x105390, 3, RI_ALL_ONLINE}, - { 0x1053a0, 3, RI_ALL_ONLINE}, { 0x1053b0, 3, RI_ALL_ONLINE}, - { 0x1053c0, 3, RI_ALL_ONLINE}, { 0x1053d0, 3, RI_ALL_ONLINE}, - { 0x1053e0, 3, RI_ALL_ONLINE}, { 0x1053f0, 3, RI_ALL_ONLINE}, - { 0x108094, 1, RI_ALL_ONLINE}, { 0x1201b0, 2, RI_ALL_ONLINE}, - { 0x12032c, 1, RI_ALL_ONLINE}, { 0x12036c, 3, RI_ALL_ONLINE}, - { 0x120408, 2, RI_ALL_ONLINE}, { 0x120414, 15, RI_ALL_ONLINE}, - { 0x120478, 2, RI_ALL_ONLINE}, { 0x12052c, 1, RI_ALL_ONLINE}, - { 0x120564, 3, RI_ALL_ONLINE}, { 0x12057c, 1, RI_ALL_ONLINE}, - { 0x12058c, 1, RI_ALL_ONLINE}, { 0x120608, 1, RI_E1H_ONLINE}, - { 0x120808, 1, RI_E1_ONLINE}, { 0x12080c, 2, RI_ALL_ONLINE}, - { 0x120818, 1, RI_ALL_ONLINE}, { 0x120820, 1, RI_ALL_ONLINE}, - { 0x120828, 1, RI_ALL_ONLINE}, { 0x120830, 1, RI_ALL_ONLINE}, - { 0x120838, 1, RI_ALL_ONLINE}, { 0x120840, 1, RI_ALL_ONLINE}, - { 0x120848, 1, RI_ALL_ONLINE}, { 0x120850, 1, RI_ALL_ONLINE}, - { 0x120858, 1, RI_ALL_ONLINE}, { 0x120860, 1, RI_ALL_ONLINE}, - { 0x120868, 1, RI_ALL_ONLINE}, { 0x120870, 1, RI_ALL_ONLINE}, - { 0x120878, 1, RI_ALL_ONLINE}, { 0x120880, 1, RI_ALL_ONLINE}, - { 0x120888, 1, RI_ALL_ONLINE}, { 0x120890, 1, RI_ALL_ONLINE}, - { 0x120898, 1, RI_ALL_ONLINE}, { 0x1208a0, 1, RI_ALL_ONLINE}, - { 0x1208a8, 1, RI_ALL_ONLINE}, { 0x1208b0, 1, RI_ALL_ONLINE}, - { 0x1208b8, 1, RI_ALL_ONLINE}, { 0x1208c0, 1, RI_ALL_ONLINE}, - { 0x1208c8, 1, RI_ALL_ONLINE}, { 0x1208d0, 1, RI_ALL_ONLINE}, - { 0x1208d8, 1, RI_ALL_ONLINE}, { 0x1208e0, 1, RI_ALL_ONLINE}, - { 0x1208e8, 1, RI_ALL_ONLINE}, { 0x1208f0, 1, RI_ALL_ONLINE}, - { 0x1208f8, 1, RI_ALL_ONLINE}, { 0x120900, 1, RI_ALL_ONLINE}, - { 0x120908, 1, RI_ALL_ONLINE}, { 0x14005c, 2, RI_ALL_ONLINE}, - { 0x1400d0, 2, RI_ALL_ONLINE}, { 0x1400e0, 1, RI_ALL_ONLINE}, - { 0x1401c8, 1, RI_ALL_ONLINE}, { 0x140200, 6, RI_ALL_ONLINE}, - { 0x16101c, 1, RI_ALL_ONLINE}, { 0x16102c, 1, RI_ALL_ONLINE}, - { 0x164014, 2, RI_ALL_ONLINE}, { 0x1640f0, 1, RI_ALL_ONLINE}, - { 0x166290, 1, RI_ALL_ONLINE}, { 0x1662a0, 1, RI_ALL_ONLINE}, - { 0x1662b0, 1, RI_ALL_ONLINE}, { 0x166548, 1, RI_ALL_ONLINE}, - { 0x166550, 1, RI_ALL_ONLINE}, { 0x166558, 1, RI_ALL_ONLINE}, - { 0x168000, 1, RI_ALL_ONLINE}, { 0x168008, 1, RI_ALL_ONLINE}, - { 0x168010, 1, RI_ALL_ONLINE}, { 0x168018, 1, RI_ALL_ONLINE}, - { 0x168028, 2, RI_ALL_ONLINE}, { 0x168058, 4, RI_ALL_ONLINE}, - { 0x168070, 1, RI_ALL_ONLINE}, { 0x168238, 1, RI_ALL_ONLINE}, - { 0x1682d0, 2, RI_ALL_ONLINE}, { 0x1682e0, 1, RI_ALL_ONLINE}, - { 0x168300, 67, RI_ALL_ONLINE}, { 0x168410, 2, RI_ALL_ONLINE}, - { 0x168438, 1, RI_ALL_ONLINE}, { 0x168448, 1, RI_ALL_ONLINE}, - { 0x168a00, 128, RI_ALL_ONLINE}, { 0x16e200, 128, RI_E1H_ONLINE}, - { 0x16e404, 2, RI_E1H_ONLINE}, { 0x16e584, 70, RI_E1H_ONLINE}, - { 0x1700a4, 1, RI_ALL_ONLINE}, { 0x1700ac, 2, RI_ALL_ONLINE}, - { 0x1700c0, 1, RI_ALL_ONLINE}, { 0x170174, 1, RI_ALL_ONLINE}, - { 0x170184, 1, RI_ALL_ONLINE}, { 0x1800f4, 1, RI_ALL_ONLINE}, - { 0x180104, 1, RI_ALL_ONLINE}, { 0x180114, 1, RI_ALL_ONLINE}, - { 0x180124, 1, RI_ALL_ONLINE}, { 0x18026c, 1, RI_ALL_ONLINE}, - { 0x1802a0, 1, RI_ALL_ONLINE}, { 0x1a1000, 1, RI_ALL_ONLINE}, - { 0x1aa000, 1, RI_E1H_ONLINE}, { 0x1b8000, 1, RI_ALL_ONLINE}, - { 0x1b8040, 1, RI_ALL_ONLINE}, { 0x1b8080, 1, RI_ALL_ONLINE}, - { 0x1b80c0, 1, RI_ALL_ONLINE}, { 0x200104, 1, RI_ALL_ONLINE}, - { 0x200114, 1, RI_ALL_ONLINE}, { 0x200124, 1, RI_ALL_ONLINE}, - { 0x200134, 1, RI_ALL_ONLINE}, { 0x20026c, 1, RI_ALL_ONLINE}, - { 0x2002a0, 1, RI_ALL_ONLINE}, { 0x221000, 1, RI_ALL_ONLINE}, - { 0x227000, 1, RI_E1H_ONLINE}, { 0x238000, 1, RI_ALL_ONLINE}, - { 0x238040, 1, RI_ALL_ONLINE}, { 0x238080, 1, RI_ALL_ONLINE}, - { 0x2380c0, 1, RI_ALL_ONLINE}, { 0x280104, 1, RI_ALL_ONLINE}, - { 0x280114, 1, RI_ALL_ONLINE}, { 0x280124, 1, RI_ALL_ONLINE}, - { 0x280134, 1, RI_ALL_ONLINE}, { 0x28026c, 1, RI_ALL_ONLINE}, - { 0x2802a0, 1, RI_ALL_ONLINE}, { 0x2a1000, 1, RI_ALL_ONLINE}, - { 0x2a9000, 1, RI_E1H_ONLINE}, { 0x2b8000, 1, RI_ALL_ONLINE}, - { 0x2b8040, 1, RI_ALL_ONLINE}, { 0x2b8080, 1, RI_ALL_ONLINE}, - { 0x2b80c0, 1, RI_ALL_ONLINE}, { 0x300104, 1, RI_ALL_ONLINE}, - { 0x300114, 1, RI_ALL_ONLINE}, { 0x300124, 1, RI_ALL_ONLINE}, - { 0x300134, 1, RI_ALL_ONLINE}, { 0x30026c, 1, RI_ALL_ONLINE}, - { 0x3002a0, 1, RI_ALL_ONLINE}, { 0x321000, 1, RI_ALL_ONLINE}, - { 0x328960, 1, RI_E1H_ONLINE}, { 0x338000, 1, RI_ALL_ONLINE}, - { 0x338040, 1, RI_ALL_ONLINE}, { 0x338080, 1, RI_ALL_ONLINE}, - { 0x3380c0, 1, RI_ALL_ONLINE} +#define IDLE_REGS_COUNT 277 +static const struct reg_addr idle_addrs[IDLE_REGS_COUNT] = { + { 0x2114, 1, RI_ALL_ONLINE }, { 0x2120, 1, RI_ALL_ONLINE }, + { 0x212c, 4, RI_ALL_ONLINE }, { 0x2814, 1, RI_ALL_ONLINE }, + { 0x281c, 2, RI_ALL_ONLINE }, { 0xa38c, 1, RI_ALL_ONLINE }, + { 0xa408, 1, RI_ALL_ONLINE }, { 0xa42c, 12, RI_ALL_ONLINE }, + { 0xa600, 5, RI_E1H_ONLINE }, { 0xa618, 1, RI_E1H_ONLINE }, + { 0xc09c, 1, RI_ALL_ONLINE }, { 0x103b0, 1, RI_ALL_ONLINE }, + { 0x103c0, 1, RI_ALL_ONLINE }, { 0x103d0, 1, RI_E1H_ONLINE }, + { 0x2021c, 11, RI_ALL_ONLINE }, { 0x202a8, 1, RI_ALL_ONLINE }, + { 0x202b8, 1, RI_ALL_ONLINE }, { 0x20404, 1, RI_ALL_ONLINE }, + { 0x2040c, 2, RI_ALL_ONLINE }, { 0x2041c, 2, RI_ALL_ONLINE }, + { 0x40154, 14, RI_ALL_ONLINE }, { 0x40198, 1, RI_ALL_ONLINE }, + { 0x404ac, 1, RI_ALL_ONLINE }, { 0x404bc, 1, RI_ALL_ONLINE }, + { 0x42290, 1, RI_ALL_ONLINE }, { 0x422a0, 1, RI_ALL_ONLINE }, + { 0x422b0, 1, RI_ALL_ONLINE }, { 0x42548, 1, RI_ALL_ONLINE }, + { 0x42550, 1, RI_ALL_ONLINE }, { 0x42558, 1, RI_ALL_ONLINE }, + { 0x50160, 8, RI_ALL_ONLINE }, { 0x501d0, 1, RI_ALL_ONLINE }, + { 0x501e0, 1, RI_ALL_ONLINE }, { 0x50204, 1, RI_ALL_ONLINE }, + { 0x5020c, 2, RI_ALL_ONLINE }, { 0x5021c, 1, RI_ALL_ONLINE }, + { 0x60090, 1, RI_ALL_ONLINE }, { 0x6011c, 1, RI_ALL_ONLINE }, + { 0x6012c, 1, RI_ALL_ONLINE }, { 0xc101c, 1, RI_ALL_ONLINE }, + { 0xc102c, 1, RI_ALL_ONLINE }, { 0xc2290, 1, RI_ALL_ONLINE }, + { 0xc22a0, 1, RI_ALL_ONLINE }, { 0xc22b0, 1, RI_ALL_ONLINE }, + { 0xc2548, 1, RI_ALL_ONLINE }, { 0xc2550, 1, RI_ALL_ONLINE }, + { 0xc2558, 1, RI_ALL_ONLINE }, { 0xc4294, 1, RI_ALL_ONLINE }, + { 0xc42a4, 1, RI_ALL_ONLINE }, { 0xc42b4, 1, RI_ALL_ONLINE }, + { 0xc4550, 1, RI_ALL_ONLINE }, { 0xc4558, 1, RI_ALL_ONLINE }, + { 0xc4560, 1, RI_ALL_ONLINE }, { 0xd016c, 8, RI_ALL_ONLINE }, + { 0xd01d8, 1, RI_ALL_ONLINE }, { 0xd01e8, 1, RI_ALL_ONLINE }, + { 0xd0204, 1, RI_ALL_ONLINE }, { 0xd020c, 3, RI_ALL_ONLINE }, + { 0xe0154, 8, RI_ALL_ONLINE }, { 0xe01c8, 1, RI_ALL_ONLINE }, + { 0xe01d8, 1, RI_ALL_ONLINE }, { 0xe0204, 1, RI_ALL_ONLINE }, + { 0xe020c, 2, RI_ALL_ONLINE }, { 0xe021c, 2, RI_ALL_ONLINE }, + { 0x101014, 1, RI_ALL_ONLINE }, { 0x101030, 1, RI_ALL_ONLINE }, + { 0x101040, 1, RI_ALL_ONLINE }, { 0x102058, 1, RI_ALL_ONLINE }, + { 0x102080, 16, RI_ALL_ONLINE }, { 0x103004, 2, RI_ALL_ONLINE }, + { 0x103068, 1, RI_ALL_ONLINE }, { 0x103078, 1, RI_ALL_ONLINE }, + { 0x103088, 1, RI_ALL_ONLINE }, { 0x10309c, 2, RI_E1H_ONLINE }, + { 0x104004, 1, RI_ALL_ONLINE }, { 0x104018, 1, RI_ALL_ONLINE }, + { 0x104020, 1, RI_ALL_ONLINE }, { 0x10403c, 1, RI_ALL_ONLINE }, + { 0x1040fc, 1, RI_ALL_ONLINE }, { 0x10410c, 1, RI_ALL_ONLINE }, + { 0x104400, 64, RI_ALL_ONLINE }, { 0x104800, 64, RI_ALL_ONLINE }, + { 0x105000, 3, RI_ALL_ONLINE }, { 0x105010, 3, RI_ALL_ONLINE }, + { 0x105020, 3, RI_ALL_ONLINE }, { 0x105030, 3, RI_ALL_ONLINE }, + { 0x105040, 3, RI_ALL_ONLINE }, { 0x105050, 3, RI_ALL_ONLINE }, + { 0x105060, 3, RI_ALL_ONLINE }, { 0x105070, 3, RI_ALL_ONLINE }, + { 0x105080, 3, RI_ALL_ONLINE }, { 0x105090, 3, RI_ALL_ONLINE }, + { 0x1050a0, 3, RI_ALL_ONLINE }, { 0x1050b0, 3, RI_ALL_ONLINE }, + { 0x1050c0, 3, RI_ALL_ONLINE }, { 0x1050d0, 3, RI_ALL_ONLINE }, + { 0x1050e0, 3, RI_ALL_ONLINE }, { 0x1050f0, 3, RI_ALL_ONLINE }, + { 0x105100, 3, RI_ALL_ONLINE }, { 0x105110, 3, RI_ALL_ONLINE }, + { 0x105120, 3, RI_ALL_ONLINE }, { 0x105130, 3, RI_ALL_ONLINE }, + { 0x105140, 3, RI_ALL_ONLINE }, { 0x105150, 3, RI_ALL_ONLINE }, + { 0x105160, 3, RI_ALL_ONLINE }, { 0x105170, 3, RI_ALL_ONLINE }, + { 0x105180, 3, RI_ALL_ONLINE }, { 0x105190, 3, RI_ALL_ONLINE }, + { 0x1051a0, 3, RI_ALL_ONLINE }, { 0x1051b0, 3, RI_ALL_ONLINE }, + { 0x1051c0, 3, RI_ALL_ONLINE }, { 0x1051d0, 3, RI_ALL_ONLINE }, + { 0x1051e0, 3, RI_ALL_ONLINE }, { 0x1051f0, 3, RI_ALL_ONLINE }, + { 0x105200, 3, RI_ALL_ONLINE }, { 0x105210, 3, RI_ALL_ONLINE }, + { 0x105220, 3, RI_ALL_ONLINE }, { 0x105230, 3, RI_ALL_ONLINE }, + { 0x105240, 3, RI_ALL_ONLINE }, { 0x105250, 3, RI_ALL_ONLINE }, + { 0x105260, 3, RI_ALL_ONLINE }, { 0x105270, 3, RI_ALL_ONLINE }, + { 0x105280, 3, RI_ALL_ONLINE }, { 0x105290, 3, RI_ALL_ONLINE }, + { 0x1052a0, 3, RI_ALL_ONLINE }, { 0x1052b0, 3, RI_ALL_ONLINE }, + { 0x1052c0, 3, RI_ALL_ONLINE }, { 0x1052d0, 3, RI_ALL_ONLINE }, + { 0x1052e0, 3, RI_ALL_ONLINE }, { 0x1052f0, 3, RI_ALL_ONLINE }, + { 0x105300, 3, RI_ALL_ONLINE }, { 0x105310, 3, RI_ALL_ONLINE }, + { 0x105320, 3, RI_ALL_ONLINE }, { 0x105330, 3, RI_ALL_ONLINE }, + { 0x105340, 3, RI_ALL_ONLINE }, { 0x105350, 3, RI_ALL_ONLINE }, + { 0x105360, 3, RI_ALL_ONLINE }, { 0x105370, 3, RI_ALL_ONLINE }, + { 0x105380, 3, RI_ALL_ONLINE }, { 0x105390, 3, RI_ALL_ONLINE }, + { 0x1053a0, 3, RI_ALL_ONLINE }, { 0x1053b0, 3, RI_ALL_ONLINE }, + { 0x1053c0, 3, RI_ALL_ONLINE }, { 0x1053d0, 3, RI_ALL_ONLINE }, + { 0x1053e0, 3, RI_ALL_ONLINE }, { 0x1053f0, 3, RI_ALL_ONLINE }, + { 0x108094, 1, RI_ALL_ONLINE }, { 0x1201b0, 2, RI_ALL_ONLINE }, + { 0x12032c, 1, RI_ALL_ONLINE }, { 0x12036c, 3, RI_ALL_ONLINE }, + { 0x120408, 2, RI_ALL_ONLINE }, { 0x120414, 15, RI_ALL_ONLINE }, + { 0x120478, 2, RI_ALL_ONLINE }, { 0x12052c, 1, RI_ALL_ONLINE }, + { 0x120564, 3, RI_ALL_ONLINE }, { 0x12057c, 1, RI_ALL_ONLINE }, + { 0x12058c, 1, RI_ALL_ONLINE }, { 0x120608, 1, RI_E1H_ONLINE }, + { 0x120808, 1, RI_E1_ONLINE }, { 0x12080c, 2, RI_ALL_ONLINE }, + { 0x120818, 1, RI_ALL_ONLINE }, { 0x120820, 1, RI_ALL_ONLINE }, + { 0x120828, 1, RI_ALL_ONLINE }, { 0x120830, 1, RI_ALL_ONLINE }, + { 0x120838, 1, RI_ALL_ONLINE }, { 0x120840, 1, RI_ALL_ONLINE }, + { 0x120848, 1, RI_ALL_ONLINE }, { 0x120850, 1, RI_ALL_ONLINE }, + { 0x120858, 1, RI_ALL_ONLINE }, { 0x120860, 1, RI_ALL_ONLINE }, + { 0x120868, 1, RI_ALL_ONLINE }, { 0x120870, 1, RI_ALL_ONLINE }, + { 0x120878, 1, RI_ALL_ONLINE }, { 0x120880, 1, RI_ALL_ONLINE }, + { 0x120888, 1, RI_ALL_ONLINE }, { 0x120890, 1, RI_ALL_ONLINE }, + { 0x120898, 1, RI_ALL_ONLINE }, { 0x1208a0, 1, RI_ALL_ONLINE }, + { 0x1208a8, 1, RI_ALL_ONLINE }, { 0x1208b0, 1, RI_ALL_ONLINE }, + { 0x1208b8, 1, RI_ALL_ONLINE }, { 0x1208c0, 1, RI_ALL_ONLINE }, + { 0x1208c8, 1, RI_ALL_ONLINE }, { 0x1208d0, 1, RI_ALL_ONLINE }, + { 0x1208d8, 1, RI_ALL_ONLINE }, { 0x1208e0, 1, RI_ALL_ONLINE }, + { 0x1208e8, 1, RI_ALL_ONLINE }, { 0x1208f0, 1, RI_ALL_ONLINE }, + { 0x1208f8, 1, RI_ALL_ONLINE }, { 0x120900, 1, RI_ALL_ONLINE }, + { 0x120908, 1, RI_ALL_ONLINE }, { 0x14005c, 2, RI_ALL_ONLINE }, + { 0x1400d0, 2, RI_ALL_ONLINE }, { 0x1400e0, 1, RI_ALL_ONLINE }, + { 0x1401c8, 1, RI_ALL_ONLINE }, { 0x140200, 6, RI_ALL_ONLINE }, + { 0x16101c, 1, RI_ALL_ONLINE }, { 0x16102c, 1, RI_ALL_ONLINE }, + { 0x164014, 2, RI_ALL_ONLINE }, { 0x1640f0, 1, RI_ALL_ONLINE }, + { 0x166290, 1, RI_ALL_ONLINE }, { 0x1662a0, 1, RI_ALL_ONLINE }, + { 0x1662b0, 1, RI_ALL_ONLINE }, { 0x166548, 1, RI_ALL_ONLINE }, + { 0x166550, 1, RI_ALL_ONLINE }, { 0x166558, 1, RI_ALL_ONLINE }, + { 0x168000, 1, RI_ALL_ONLINE }, { 0x168008, 1, RI_ALL_ONLINE }, + { 0x168010, 1, RI_ALL_ONLINE }, { 0x168018, 1, RI_ALL_ONLINE }, + { 0x168028, 2, RI_ALL_ONLINE }, { 0x168058, 4, RI_ALL_ONLINE }, + { 0x168070, 1, RI_ALL_ONLINE }, { 0x168238, 1, RI_ALL_ONLINE }, + { 0x1682d0, 2, RI_ALL_ONLINE }, { 0x1682e0, 1, RI_ALL_ONLINE }, + { 0x168300, 67, RI_ALL_ONLINE }, { 0x168410, 2, RI_ALL_ONLINE }, + { 0x168438, 1, RI_ALL_ONLINE }, { 0x168448, 1, RI_ALL_ONLINE }, + { 0x168a00, 128, RI_ALL_ONLINE }, { 0x16e200, 128, RI_E1H_ONLINE }, + { 0x16e404, 2, RI_E1H_ONLINE }, { 0x16e584, 70, RI_E1H_ONLINE }, + { 0x1700a4, 1, RI_ALL_ONLINE }, { 0x1700ac, 2, RI_ALL_ONLINE }, + { 0x1700c0, 1, RI_ALL_ONLINE }, { 0x170174, 1, RI_ALL_ONLINE }, + { 0x170184, 1, RI_ALL_ONLINE }, { 0x1800f4, 1, RI_ALL_ONLINE }, + { 0x180104, 1, RI_ALL_ONLINE }, { 0x180114, 1, RI_ALL_ONLINE }, + { 0x180124, 1, RI_ALL_ONLINE }, { 0x18026c, 1, RI_ALL_ONLINE }, + { 0x1802a0, 1, RI_ALL_ONLINE }, { 0x1a1000, 1, RI_ALL_ONLINE }, + { 0x1aa000, 1, RI_E1H_ONLINE }, { 0x1b8000, 1, RI_ALL_ONLINE }, + { 0x1b8040, 1, RI_ALL_ONLINE }, { 0x1b8080, 1, RI_ALL_ONLINE }, + { 0x1b80c0, 1, RI_ALL_ONLINE }, { 0x200104, 1, RI_ALL_ONLINE }, + { 0x200114, 1, RI_ALL_ONLINE }, { 0x200124, 1, RI_ALL_ONLINE }, + { 0x200134, 1, RI_ALL_ONLINE }, { 0x20026c, 1, RI_ALL_ONLINE }, + { 0x2002a0, 1, RI_ALL_ONLINE }, { 0x221000, 1, RI_ALL_ONLINE }, + { 0x227000, 1, RI_E1H_ONLINE }, { 0x238000, 1, RI_ALL_ONLINE }, + { 0x238040, 1, RI_ALL_ONLINE }, { 0x238080, 1, RI_ALL_ONLINE }, + { 0x2380c0, 1, RI_ALL_ONLINE }, { 0x280104, 1, RI_ALL_ONLINE }, + { 0x280114, 1, RI_ALL_ONLINE }, { 0x280124, 1, RI_ALL_ONLINE }, + { 0x280134, 1, RI_ALL_ONLINE }, { 0x28026c, 1, RI_ALL_ONLINE }, + { 0x2802a0, 1, RI_ALL_ONLINE }, { 0x2a1000, 1, RI_ALL_ONLINE }, + { 0x2a9000, 1, RI_E1H_ONLINE }, { 0x2b8000, 1, RI_ALL_ONLINE }, + { 0x2b8040, 1, RI_ALL_ONLINE }, { 0x2b8080, 1, RI_ALL_ONLINE }, + { 0x2b80c0, 1, RI_ALL_ONLINE }, { 0x300104, 1, RI_ALL_ONLINE }, + { 0x300114, 1, RI_ALL_ONLINE }, { 0x300124, 1, RI_ALL_ONLINE }, + { 0x300134, 1, RI_ALL_ONLINE }, { 0x30026c, 1, RI_ALL_ONLINE }, + { 0x3002a0, 1, RI_ALL_ONLINE }, { 0x321000, 1, RI_ALL_ONLINE }, + { 0x328960, 1, RI_E1H_ONLINE }, { 0x338000, 1, RI_ALL_ONLINE }, + { 0x338040, 1, RI_ALL_ONLINE }, { 0x338080, 1, RI_ALL_ONLINE }, + { 0x3380c0, 1, RI_ALL_ONLINE } }; +#define WREGS_COUNT_E1 1 static const u32 read_reg_e1_0[] = { 0x1b1000 }; -#define WREGS_COUNT_E1 1 static const struct wreg_addr wreg_addrs_e1[WREGS_COUNT_E1] = { { 0x1b0c00, 192, 1, read_reg_e1_0, RI_E1_OFFLINE } }; + +#define WREGS_COUNT_E1H 1 static const u32 read_reg_e1h_0[] = { 0x1b1040, 0x1b1000 }; -#define WREGS_COUNT_E1H 1 static const struct wreg_addr wreg_addrs_e1h[WREGS_COUNT_E1H] = { { 0x1b0c00, 256, 2, read_reg_e1h_0, RI_E1H_OFFLINE } }; @@ -512,15 +517,18 @@ static const struct wreg_addr wreg_addrs_e1h[WREGS_COUNT_E1H] = { static const struct dump_sign dump_sign_all = { 0x49aa93ee, 0x40835, 0x22 }; -#define TIMER_REGS_COUNT_E1 2 +#define TIMER_REGS_COUNT_E1 2 static const u32 timer_status_regs_e1[TIMER_REGS_COUNT_E1] = { 0x164014, 0x164018 }; static const u32 timer_scan_regs_e1[TIMER_REGS_COUNT_E1] = { 0x1640d0, 0x1640d4 }; -#define TIMER_REGS_COUNT_E1H 2 + +#define TIMER_REGS_COUNT_E1H 2 static const u32 timer_status_regs_e1h[TIMER_REGS_COUNT_E1H] = { 0x164014, 0x164018 }; static const u32 timer_scan_regs_e1h[TIMER_REGS_COUNT_E1H] = { 0x1640d0, 0x1640d4 }; + +#endif /* BNX2X_DUMP_H */ -- cgit v1.2.3-18-g5258 From 9c63de6293775b537614550fd61075a33ada9469 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:24:25 +0000 Subject: bnx2x: Removing unused definitions Signed-off-by: Vladislav Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_reg.h | 811 ------------------------------------------------ 1 file changed, 811 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h index 1e6f5aa4eb5..95ebf3fb3e8 100644 --- a/drivers/net/bnx2x_reg.h +++ b/drivers/net/bnx2x_reg.h @@ -190,12 +190,6 @@ _(0..15) stands for the connection type (one of 16). */ #define CCM_REG_N_SM_CTX_LD_0 0xd004c #define CCM_REG_N_SM_CTX_LD_1 0xd0050 -#define CCM_REG_N_SM_CTX_LD_10 0xd0074 -#define CCM_REG_N_SM_CTX_LD_11 0xd0078 -#define CCM_REG_N_SM_CTX_LD_12 0xd007c -#define CCM_REG_N_SM_CTX_LD_13 0xd0080 -#define CCM_REG_N_SM_CTX_LD_14 0xd0084 -#define CCM_REG_N_SM_CTX_LD_15 0xd0088 #define CCM_REG_N_SM_CTX_LD_2 0xd0054 #define CCM_REG_N_SM_CTX_LD_3 0xd0058 #define CCM_REG_N_SM_CTX_LD_4 0xd005c @@ -622,24 +616,6 @@ #define DMAE_REG_GO_C1 0x102084 /* [RW 1] Command 10 go. */ #define DMAE_REG_GO_C10 0x102088 -#define DMAE_REG_GO_C10_SIZE 1 -/* [RW 1] Command 11 go. */ -#define DMAE_REG_GO_C11 0x10208c -#define DMAE_REG_GO_C11_SIZE 1 -/* [RW 1] Command 12 go. */ -#define DMAE_REG_GO_C12 0x102090 -#define DMAE_REG_GO_C12_SIZE 1 -/* [RW 1] Command 13 go. */ -#define DMAE_REG_GO_C13 0x102094 -#define DMAE_REG_GO_C13_SIZE 1 -/* [RW 1] Command 14 go. */ -#define DMAE_REG_GO_C14 0x102098 -#define DMAE_REG_GO_C14_SIZE 1 -/* [RW 1] Command 15 go. */ -#define DMAE_REG_GO_C15 0x10209c -#define DMAE_REG_GO_C15_SIZE 1 -/* [RW 1] Command 10 go. */ -#define DMAE_REG_GO_C10 0x102088 /* [RW 1] Command 11 go. */ #define DMAE_REG_GO_C11 0x10208c /* [RW 1] Command 12 go. */ @@ -789,7 +765,6 @@ #define MCP_REG_MCPR_NVM_READ 0x86410 #define MCP_REG_MCPR_NVM_SW_ARB 0x86420 #define MCP_REG_MCPR_NVM_WRITE 0x86408 -#define MCP_REG_MCPR_NVM_WRITE1 0x86428 #define MCP_REG_MCPR_SCRATCH 0xa0000 /* [R 32] read first 32 bit after inversion of function 0. mapped as follows: [0] NIG attention for function0; [1] NIG attention for @@ -1175,19 +1150,7 @@ #define MISC_REG_AEU_GENERAL_ATTN_10 0xa028 #define MISC_REG_AEU_GENERAL_ATTN_11 0xa02c #define MISC_REG_AEU_GENERAL_ATTN_12 0xa030 -#define MISC_REG_AEU_GENERAL_ATTN_13 0xa034 -#define MISC_REG_AEU_GENERAL_ATTN_14 0xa038 -#define MISC_REG_AEU_GENERAL_ATTN_15 0xa03c -#define MISC_REG_AEU_GENERAL_ATTN_16 0xa040 -#define MISC_REG_AEU_GENERAL_ATTN_17 0xa044 -#define MISC_REG_AEU_GENERAL_ATTN_18 0xa048 -#define MISC_REG_AEU_GENERAL_ATTN_19 0xa04c -#define MISC_REG_AEU_GENERAL_ATTN_10 0xa028 -#define MISC_REG_AEU_GENERAL_ATTN_11 0xa02c -#define MISC_REG_AEU_GENERAL_ATTN_12 0xa030 #define MISC_REG_AEU_GENERAL_ATTN_2 0xa008 -#define MISC_REG_AEU_GENERAL_ATTN_20 0xa050 -#define MISC_REG_AEU_GENERAL_ATTN_21 0xa054 #define MISC_REG_AEU_GENERAL_ATTN_3 0xa00c #define MISC_REG_AEU_GENERAL_ATTN_4 0xa010 #define MISC_REG_AEU_GENERAL_ATTN_5 0xa014 @@ -1263,78 +1226,6 @@ starts at 0x0 for the A0 tape-out and increments by one for each all-layer tape-out. */ #define MISC_REG_CHIP_REV 0xa40c -/* [RW 32] The following driver registers(1...16) represent 16 drivers and - 32 clients. Each client can be controlled by one driver only. One in each - bit represent that this driver control the appropriate client (Ex: bit 5 - is set means this driver control client number 5). addr1 = set; addr0 = - clear; read from both addresses will give the same result = status. write - to address 1 will set a request to control all the clients that their - appropriate bit (in the write command) is set. if the client is free (the - appropriate bit in all the other drivers is clear) one will be written to - that driver register; if the client isn't free the bit will remain zero. - if the appropriate bit is set (the driver request to gain control on a - client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW - interrupt will be asserted). write to address 0 will set a request to - free all the clients that their appropriate bit (in the write command) is - set. if the appropriate bit is clear (the driver request to free a client - it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will - be asserted). */ -#define MISC_REG_DRIVER_CONTROL_10 0xa3e0 -#define MISC_REG_DRIVER_CONTROL_10_SIZE 2 -/* [RW 32] The following driver registers(1...16) represent 16 drivers and - 32 clients. Each client can be controlled by one driver only. One in each - bit represent that this driver control the appropriate client (Ex: bit 5 - is set means this driver control client number 5). addr1 = set; addr0 = - clear; read from both addresses will give the same result = status. write - to address 1 will set a request to control all the clients that their - appropriate bit (in the write command) is set. if the client is free (the - appropriate bit in all the other drivers is clear) one will be written to - that driver register; if the client isn't free the bit will remain zero. - if the appropriate bit is set (the driver request to gain control on a - client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW - interrupt will be asserted). write to address 0 will set a request to - free all the clients that their appropriate bit (in the write command) is - set. if the appropriate bit is clear (the driver request to free a client - it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will - be asserted). */ -#define MISC_REG_DRIVER_CONTROL_11 0xa3e8 -#define MISC_REG_DRIVER_CONTROL_11_SIZE 2 -/* [RW 32] The following driver registers(1...16) represent 16 drivers and - 32 clients. Each client can be controlled by one driver only. One in each - bit represent that this driver control the appropriate client (Ex: bit 5 - is set means this driver control client number 5). addr1 = set; addr0 = - clear; read from both addresses will give the same result = status. write - to address 1 will set a request to control all the clients that their - appropriate bit (in the write command) is set. if the client is free (the - appropriate bit in all the other drivers is clear) one will be written to - that driver register; if the client isn't free the bit will remain zero. - if the appropriate bit is set (the driver request to gain control on a - client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW - interrupt will be asserted). write to address 0 will set a request to - free all the clients that their appropriate bit (in the write command) is - set. if the appropriate bit is clear (the driver request to free a client - it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will - be asserted). */ -#define MISC_REG_DRIVER_CONTROL_12 0xa3f0 -#define MISC_REG_DRIVER_CONTROL_12_SIZE 2 -/* [RW 32] The following driver registers(1...16) represent 16 drivers and - 32 clients. Each client can be controlled by one driver only. One in each - bit represent that this driver control the appropriate client (Ex: bit 5 - is set means this driver control client number 5). addr1 = set; addr0 = - clear; read from both addresses will give the same result = status. write - to address 1 will set a request to control all the clients that their - appropriate bit (in the write command) is set. if the client is free (the - appropriate bit in all the other drivers is clear) one will be written to - that driver register; if the client isn't free the bit will remain zero. - if the appropriate bit is set (the driver request to gain control on a - client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW - interrupt will be asserted). write to address 0 will set a request to - free all the clients that their appropriate bit (in the write command) is - set. if the appropriate bit is clear (the driver request to free a client - it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will - be asserted). */ -#define MISC_REG_DRIVER_CONTROL_13 0xa3f8 -#define MISC_REG_DRIVER_CONTROL_13_SIZE 2 /* [RW 32] The following driver registers(1...16) represent 16 drivers and 32 clients. Each client can be controlled by one driver only. One in each bit represent that this driver control the appropriate client (Ex: bit 5 @@ -1352,60 +1243,6 @@ it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will be asserted). */ #define MISC_REG_DRIVER_CONTROL_1 0xa510 -#define MISC_REG_DRIVER_CONTROL_14 0xa5e0 -#define MISC_REG_DRIVER_CONTROL_14_SIZE 2 -/* [RW 32] The following driver registers(1...16) represent 16 drivers and - 32 clients. Each client can be controlled by one driver only. One in each - bit represent that this driver control the appropriate client (Ex: bit 5 - is set means this driver control client number 5). addr1 = set; addr0 = - clear; read from both addresses will give the same result = status. write - to address 1 will set a request to control all the clients that their - appropriate bit (in the write command) is set. if the client is free (the - appropriate bit in all the other drivers is clear) one will be written to - that driver register; if the client isn't free the bit will remain zero. - if the appropriate bit is set (the driver request to gain control on a - client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW - interrupt will be asserted). write to address 0 will set a request to - free all the clients that their appropriate bit (in the write command) is - set. if the appropriate bit is clear (the driver request to free a client - it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will - be asserted). */ -#define MISC_REG_DRIVER_CONTROL_15 0xa5e8 -#define MISC_REG_DRIVER_CONTROL_15_SIZE 2 -/* [RW 32] The following driver registers(1...16) represent 16 drivers and - 32 clients. Each client can be controlled by one driver only. One in each - bit represent that this driver control the appropriate client (Ex: bit 5 - is set means this driver control client number 5). addr1 = set; addr0 = - clear; read from both addresses will give the same result = status. write - to address 1 will set a request to control all the clients that their - appropriate bit (in the write command) is set. if the client is free (the - appropriate bit in all the other drivers is clear) one will be written to - that driver register; if the client isn't free the bit will remain zero. - if the appropriate bit is set (the driver request to gain control on a - client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW - interrupt will be asserted). write to address 0 will set a request to - free all the clients that their appropriate bit (in the write command) is - set. if the appropriate bit is clear (the driver request to free a client - it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will - be asserted). */ -#define MISC_REG_DRIVER_CONTROL_16 0xa5f0 -#define MISC_REG_DRIVER_CONTROL_16_SIZE 2 -/* [RW 32] The following driver registers(1...16) represent 16 drivers and - 32 clients. Each client can be controlled by one driver only. One in each - bit represent that this driver control the appropriate client (Ex: bit 5 - is set means this driver control client number 5). addr1 = set; addr0 = - clear; read from both addresses will give the same result = status. write - to address 1 will set a request to control all the clients that their - appropriate bit (in the write command) is set. if the client is free (the - appropriate bit in all the other drivers is clear) one will be written to - that driver register; if the client isn't free the bit will remain zero. - if the appropriate bit is set (the driver request to gain control on a - client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW - interrupt will be asserted). write to address 0 will set a request to - free all the clients that their appropriate bit (in the write command) is - set. if the appropriate bit is clear (the driver request to free a client - it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will - be asserted). */ #define MISC_REG_DRIVER_CONTROL_7 0xa3c8 /* [RW 1] e1hmf for WOL. If clr WOL signal o the PXP will be send on bit 0 only. */ @@ -1650,8 +1487,6 @@ /* [RW 1] MAC configuration for packets of port0. If 1 - all packet outputs to emac for port0; other way to bmac for port0 */ #define NIG_REG_EGRESS_EMAC0_PORT 0x10058 -/* [RW 32] TX_MNG_FIFO in NIG_TX_PORT0; data[31:0] written in FIFO order. */ -#define NIG_REG_EGRESS_MNG0_FIFO 0x1045c /* [RW 1] Input enable for TX PBF user packet port0 IF */ #define NIG_REG_EGRESS_PBF0_IN_EN 0x100cc /* [RW 1] Input enable for TX PBF user packet port1 IF */ @@ -2161,11 +1996,8 @@ #define PXP2_REG_PSWRQ_BW_ADD1 0x1201c0 #define PXP2_REG_PSWRQ_BW_ADD10 0x1201e4 #define PXP2_REG_PSWRQ_BW_ADD11 0x1201e8 -#define PXP2_REG_PSWRQ_BW_ADD10 0x1201e4 -#define PXP2_REG_PSWRQ_BW_ADD11 0x1201e8 #define PXP2_REG_PSWRQ_BW_ADD2 0x1201c4 #define PXP2_REG_PSWRQ_BW_ADD28 0x120228 -#define PXP2_REG_PSWRQ_BW_ADD28 0x120228 #define PXP2_REG_PSWRQ_BW_ADD3 0x1201c8 #define PXP2_REG_PSWRQ_BW_ADD6 0x1201d4 #define PXP2_REG_PSWRQ_BW_ADD7 0x1201d8 @@ -2175,11 +2007,8 @@ #define PXP2_REG_PSWRQ_BW_L1 0x1202b0 #define PXP2_REG_PSWRQ_BW_L10 0x1202d4 #define PXP2_REG_PSWRQ_BW_L11 0x1202d8 -#define PXP2_REG_PSWRQ_BW_L10 0x1202d4 -#define PXP2_REG_PSWRQ_BW_L11 0x1202d8 #define PXP2_REG_PSWRQ_BW_L2 0x1202b4 #define PXP2_REG_PSWRQ_BW_L28 0x120318 -#define PXP2_REG_PSWRQ_BW_L28 0x120318 #define PXP2_REG_PSWRQ_BW_L3 0x1202b8 #define PXP2_REG_PSWRQ_BW_L6 0x1202c4 #define PXP2_REG_PSWRQ_BW_L7 0x1202c8 @@ -2189,11 +2018,8 @@ #define PXP2_REG_PSWRQ_BW_UB1 0x120238 #define PXP2_REG_PSWRQ_BW_UB10 0x12025c #define PXP2_REG_PSWRQ_BW_UB11 0x120260 -#define PXP2_REG_PSWRQ_BW_UB10 0x12025c -#define PXP2_REG_PSWRQ_BW_UB11 0x120260 #define PXP2_REG_PSWRQ_BW_UB2 0x12023c #define PXP2_REG_PSWRQ_BW_UB28 0x1202a0 -#define PXP2_REG_PSWRQ_BW_UB28 0x1202a0 #define PXP2_REG_PSWRQ_BW_UB3 0x120240 #define PXP2_REG_PSWRQ_BW_UB6 0x12024c #define PXP2_REG_PSWRQ_BW_UB7 0x120250 @@ -2784,16 +2610,6 @@ #define QM_REG_QVOQIDX_107 0x16e4b8 #define QM_REG_QVOQIDX_108 0x16e4bc #define QM_REG_QVOQIDX_109 0x16e4c0 -#define QM_REG_QVOQIDX_100 0x16e49c -#define QM_REG_QVOQIDX_101 0x16e4a0 -#define QM_REG_QVOQIDX_102 0x16e4a4 -#define QM_REG_QVOQIDX_103 0x16e4a8 -#define QM_REG_QVOQIDX_104 0x16e4ac -#define QM_REG_QVOQIDX_105 0x16e4b0 -#define QM_REG_QVOQIDX_106 0x16e4b4 -#define QM_REG_QVOQIDX_107 0x16e4b8 -#define QM_REG_QVOQIDX_108 0x16e4bc -#define QM_REG_QVOQIDX_109 0x16e4c0 #define QM_REG_QVOQIDX_11 0x168120 #define QM_REG_QVOQIDX_110 0x16e4c4 #define QM_REG_QVOQIDX_111 0x16e4c8 @@ -2805,16 +2621,6 @@ #define QM_REG_QVOQIDX_117 0x16e4e0 #define QM_REG_QVOQIDX_118 0x16e4e4 #define QM_REG_QVOQIDX_119 0x16e4e8 -#define QM_REG_QVOQIDX_110 0x16e4c4 -#define QM_REG_QVOQIDX_111 0x16e4c8 -#define QM_REG_QVOQIDX_112 0x16e4cc -#define QM_REG_QVOQIDX_113 0x16e4d0 -#define QM_REG_QVOQIDX_114 0x16e4d4 -#define QM_REG_QVOQIDX_115 0x16e4d8 -#define QM_REG_QVOQIDX_116 0x16e4dc -#define QM_REG_QVOQIDX_117 0x16e4e0 -#define QM_REG_QVOQIDX_118 0x16e4e4 -#define QM_REG_QVOQIDX_119 0x16e4e8 #define QM_REG_QVOQIDX_12 0x168124 #define QM_REG_QVOQIDX_120 0x16e4ec #define QM_REG_QVOQIDX_121 0x16e4f0 @@ -2824,14 +2630,6 @@ #define QM_REG_QVOQIDX_125 0x16e500 #define QM_REG_QVOQIDX_126 0x16e504 #define QM_REG_QVOQIDX_127 0x16e508 -#define QM_REG_QVOQIDX_120 0x16e4ec -#define QM_REG_QVOQIDX_121 0x16e4f0 -#define QM_REG_QVOQIDX_122 0x16e4f4 -#define QM_REG_QVOQIDX_123 0x16e4f8 -#define QM_REG_QVOQIDX_124 0x16e4fc -#define QM_REG_QVOQIDX_125 0x16e500 -#define QM_REG_QVOQIDX_126 0x16e504 -#define QM_REG_QVOQIDX_127 0x16e508 #define QM_REG_QVOQIDX_13 0x168128 #define QM_REG_QVOQIDX_14 0x16812c #define QM_REG_QVOQIDX_15 0x168130 @@ -2877,16 +2675,6 @@ #define QM_REG_QVOQIDX_57 0x1681d8 #define QM_REG_QVOQIDX_58 0x1681dc #define QM_REG_QVOQIDX_59 0x1681e0 -#define QM_REG_QVOQIDX_50 0x1681bc -#define QM_REG_QVOQIDX_51 0x1681c0 -#define QM_REG_QVOQIDX_52 0x1681c4 -#define QM_REG_QVOQIDX_53 0x1681c8 -#define QM_REG_QVOQIDX_54 0x1681cc -#define QM_REG_QVOQIDX_55 0x1681d0 -#define QM_REG_QVOQIDX_56 0x1681d4 -#define QM_REG_QVOQIDX_57 0x1681d8 -#define QM_REG_QVOQIDX_58 0x1681dc -#define QM_REG_QVOQIDX_59 0x1681e0 #define QM_REG_QVOQIDX_6 0x16810c #define QM_REG_QVOQIDX_60 0x1681e4 #define QM_REG_QVOQIDX_61 0x1681e8 @@ -2894,16 +2682,6 @@ #define QM_REG_QVOQIDX_63 0x1681f0 #define QM_REG_QVOQIDX_64 0x16e40c #define QM_REG_QVOQIDX_65 0x16e410 -#define QM_REG_QVOQIDX_66 0x16e414 -#define QM_REG_QVOQIDX_67 0x16e418 -#define QM_REG_QVOQIDX_68 0x16e41c -#define QM_REG_QVOQIDX_69 0x16e420 -#define QM_REG_QVOQIDX_60 0x1681e4 -#define QM_REG_QVOQIDX_61 0x1681e8 -#define QM_REG_QVOQIDX_62 0x1681ec -#define QM_REG_QVOQIDX_63 0x1681f0 -#define QM_REG_QVOQIDX_64 0x16e40c -#define QM_REG_QVOQIDX_65 0x16e410 #define QM_REG_QVOQIDX_69 0x16e420 #define QM_REG_QVOQIDX_7 0x168110 #define QM_REG_QVOQIDX_70 0x16e424 @@ -2916,29 +2694,9 @@ #define QM_REG_QVOQIDX_77 0x16e440 #define QM_REG_QVOQIDX_78 0x16e444 #define QM_REG_QVOQIDX_79 0x16e448 -#define QM_REG_QVOQIDX_70 0x16e424 -#define QM_REG_QVOQIDX_71 0x16e428 -#define QM_REG_QVOQIDX_72 0x16e42c -#define QM_REG_QVOQIDX_73 0x16e430 -#define QM_REG_QVOQIDX_74 0x16e434 -#define QM_REG_QVOQIDX_75 0x16e438 -#define QM_REG_QVOQIDX_76 0x16e43c -#define QM_REG_QVOQIDX_77 0x16e440 -#define QM_REG_QVOQIDX_78 0x16e444 -#define QM_REG_QVOQIDX_79 0x16e448 #define QM_REG_QVOQIDX_8 0x168114 #define QM_REG_QVOQIDX_80 0x16e44c #define QM_REG_QVOQIDX_81 0x16e450 -#define QM_REG_QVOQIDX_82 0x16e454 -#define QM_REG_QVOQIDX_83 0x16e458 -#define QM_REG_QVOQIDX_84 0x16e45c -#define QM_REG_QVOQIDX_85 0x16e460 -#define QM_REG_QVOQIDX_86 0x16e464 -#define QM_REG_QVOQIDX_87 0x16e468 -#define QM_REG_QVOQIDX_88 0x16e46c -#define QM_REG_QVOQIDX_89 0x16e470 -#define QM_REG_QVOQIDX_80 0x16e44c -#define QM_REG_QVOQIDX_81 0x16e450 #define QM_REG_QVOQIDX_85 0x16e460 #define QM_REG_QVOQIDX_86 0x16e464 #define QM_REG_QVOQIDX_87 0x16e468 @@ -2955,23 +2713,11 @@ #define QM_REG_QVOQIDX_97 0x16e490 #define QM_REG_QVOQIDX_98 0x16e494 #define QM_REG_QVOQIDX_99 0x16e498 -#define QM_REG_QVOQIDX_90 0x16e474 -#define QM_REG_QVOQIDX_91 0x16e478 -#define QM_REG_QVOQIDX_92 0x16e47c -#define QM_REG_QVOQIDX_93 0x16e480 -#define QM_REG_QVOQIDX_94 0x16e484 -#define QM_REG_QVOQIDX_95 0x16e488 -#define QM_REG_QVOQIDX_96 0x16e48c -#define QM_REG_QVOQIDX_97 0x16e490 -#define QM_REG_QVOQIDX_98 0x16e494 -#define QM_REG_QVOQIDX_99 0x16e498 /* [RW 1] Initialization bit command */ #define QM_REG_SOFT_RESET 0x168428 /* [RW 8] The credit cost per every task in the QM. A value per each VOQ */ #define QM_REG_TASKCRDCOST_0 0x16809c #define QM_REG_TASKCRDCOST_1 0x1680a0 -#define QM_REG_TASKCRDCOST_10 0x1680c4 -#define QM_REG_TASKCRDCOST_11 0x1680c8 #define QM_REG_TASKCRDCOST_2 0x1680a4 #define QM_REG_TASKCRDCOST_4 0x1680ac #define QM_REG_TASKCRDCOST_5 0x1680b0 @@ -2984,24 +2730,18 @@ /* [R 16] The credit value for each VOQ */ #define QM_REG_VOQCREDIT_0 0x1682d0 #define QM_REG_VOQCREDIT_1 0x1682d4 -#define QM_REG_VOQCREDIT_10 0x1682f8 -#define QM_REG_VOQCREDIT_11 0x1682fc #define QM_REG_VOQCREDIT_4 0x1682e0 /* [RW 16] The credit value that if above the QM is considered almost full */ #define QM_REG_VOQCREDITAFULLTHR 0x168090 /* [RW 16] The init and maximum credit for each VoQ */ #define QM_REG_VOQINITCREDIT_0 0x168060 #define QM_REG_VOQINITCREDIT_1 0x168064 -#define QM_REG_VOQINITCREDIT_10 0x168088 -#define QM_REG_VOQINITCREDIT_11 0x16808c #define QM_REG_VOQINITCREDIT_2 0x168068 #define QM_REG_VOQINITCREDIT_4 0x168070 #define QM_REG_VOQINITCREDIT_5 0x168074 /* [RW 1] The port of which VOQ belongs */ #define QM_REG_VOQPORT_0 0x1682a0 #define QM_REG_VOQPORT_1 0x1682a4 -#define QM_REG_VOQPORT_10 0x1682c8 -#define QM_REG_VOQPORT_11 0x1682cc #define QM_REG_VOQPORT_2 0x1682a8 /* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ #define QM_REG_VOQQMASK_0_LSB 0x168240 @@ -3099,36 +2839,6 @@ #define QM_REG_WRRWEIGHTS_0 0x16880c #define QM_REG_WRRWEIGHTS_1 0x168810 #define QM_REG_WRRWEIGHTS_10 0x168814 -#define QM_REG_WRRWEIGHTS_10_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_11 0x168818 -#define QM_REG_WRRWEIGHTS_11_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_12 0x16881c -#define QM_REG_WRRWEIGHTS_12_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_13 0x168820 -#define QM_REG_WRRWEIGHTS_13_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_14 0x168824 -#define QM_REG_WRRWEIGHTS_14_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_15 0x168828 -#define QM_REG_WRRWEIGHTS_15_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_16 0x16e000 -#define QM_REG_WRRWEIGHTS_16_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_17 0x16e004 -#define QM_REG_WRRWEIGHTS_17_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_18 0x16e008 -#define QM_REG_WRRWEIGHTS_18_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_19 0x16e00c -#define QM_REG_WRRWEIGHTS_19_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_10 0x168814 #define QM_REG_WRRWEIGHTS_11 0x168818 #define QM_REG_WRRWEIGHTS_12 0x16881c #define QM_REG_WRRWEIGHTS_13 0x168820 @@ -3140,36 +2850,6 @@ #define QM_REG_WRRWEIGHTS_19 0x16e00c #define QM_REG_WRRWEIGHTS_2 0x16882c #define QM_REG_WRRWEIGHTS_20 0x16e010 -#define QM_REG_WRRWEIGHTS_20_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_21 0x16e014 -#define QM_REG_WRRWEIGHTS_21_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_22 0x16e018 -#define QM_REG_WRRWEIGHTS_22_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_23 0x16e01c -#define QM_REG_WRRWEIGHTS_23_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_24 0x16e020 -#define QM_REG_WRRWEIGHTS_24_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_25 0x16e024 -#define QM_REG_WRRWEIGHTS_25_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_26 0x16e028 -#define QM_REG_WRRWEIGHTS_26_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_27 0x16e02c -#define QM_REG_WRRWEIGHTS_27_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_28 0x16e030 -#define QM_REG_WRRWEIGHTS_28_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_29 0x16e034 -#define QM_REG_WRRWEIGHTS_29_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_20 0x16e010 #define QM_REG_WRRWEIGHTS_21 0x16e014 #define QM_REG_WRRWEIGHTS_22 0x16e018 #define QM_REG_WRRWEIGHTS_23 0x16e01c @@ -3181,12 +2861,6 @@ #define QM_REG_WRRWEIGHTS_29 0x16e034 #define QM_REG_WRRWEIGHTS_3 0x168830 #define QM_REG_WRRWEIGHTS_30 0x16e038 -#define QM_REG_WRRWEIGHTS_30_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_31 0x16e03c -#define QM_REG_WRRWEIGHTS_31_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_30 0x16e038 #define QM_REG_WRRWEIGHTS_31 0x16e03c #define QM_REG_WRRWEIGHTS_4 0x168834 #define QM_REG_WRRWEIGHTS_5 0x168838 @@ -3196,362 +2870,6 @@ #define QM_REG_WRRWEIGHTS_9 0x168848 /* [R 6] Keep the fill level of the fifo from write client 1 */ #define QM_REG_XQM_WRC_FIFOLVL 0x168000 -#define BRB1_BRB1_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define BRB1_BRB1_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define BRB1_BRB1_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define BRB1_BRB1_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define BRB1_BRB1_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define BRB1_BRB1_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define BRB1_BRB1_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define BRB1_BRB1_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define CCM_CCM_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define CCM_CCM_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define CCM_CCM_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define CCM_CCM_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define CCM_CCM_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define CCM_CCM_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define CCM_CCM_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define CCM_CCM_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define CDU_CDU_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define CDU_CDU_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define CDU_CDU_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define CDU_CDU_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define CDU_CDU_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define CDU_CDU_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define CDU_CDU_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define CDU_CDU_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define CFC_CFC_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define CFC_CFC_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define CFC_CFC_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define CFC_CFC_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define CFC_CFC_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define CFC_CFC_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define CFC_CFC_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define CFC_CFC_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define CSDM_CSDM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define CSDM_CSDM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define CSDM_CSDM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define CSDM_CSDM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define CSDM_CSDM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define CSDM_CSDM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define CSDM_CSDM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define CSDM_CSDM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define CSEM_CSEM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define CSEM_CSEM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define CSEM_CSEM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define CSEM_CSEM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define CSEM_CSEM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define CSEM_CSEM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define CSEM_CSEM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define CSEM_CSEM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define DBG_DBG_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define DBG_DBG_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define DBG_DBG_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define DBG_DBG_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define DBG_DBG_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define DBG_DBG_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define DBG_DBG_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define DBG_DBG_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define DMAE_DMAE_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define DMAE_DMAE_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define DMAE_DMAE_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define DMAE_DMAE_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define DMAE_DMAE_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define DMAE_DMAE_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define DMAE_DMAE_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define DMAE_DMAE_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define DORQ_DORQ_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define DORQ_DORQ_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define DORQ_DORQ_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define DORQ_DORQ_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define DORQ_DORQ_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define DORQ_DORQ_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define DORQ_DORQ_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define DORQ_DORQ_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define HC_HC_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define HC_HC_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define HC_HC_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define HC_HC_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define HC_HC_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define HC_HC_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define HC_HC_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define HC_HC_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define MISC_MISC_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define MISC_MISC_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define MISC_MISC_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define MISC_MISC_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define MISC_MISC_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define MISC_MISC_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define MISC_MISC_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define MISC_MISC_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define NIG_NIG_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define NIG_NIG_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define NIG_NIG_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define NIG_NIG_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define NIG_NIG_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define NIG_NIG_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define NIG_NIG_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define NIG_NIG_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define PBF_PBF_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define PBF_PBF_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define PBF_PBF_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define PBF_PBF_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define PBF_PBF_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define PBF_PBF_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define PBF_PBF_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define PBF_PBF_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define PB_PB_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define PB_PB_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define PB_PB_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define PB_PB_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define PB_PB_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define PB_PB_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define PB_PB_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define PB_PB_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define PRS_PRS_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define PRS_PRS_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define PRS_PRS_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define PRS_PRS_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define PRS_PRS_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define PRS_PRS_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define PRS_PRS_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define PRS_PRS_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define PXP2_PXP2_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define PXP2_PXP2_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define PXP2_PXP2_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define PXP2_PXP2_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define PXP2_PXP2_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define PXP2_PXP2_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define PXP2_PXP2_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define PXP2_PXP2_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define PXP_PXP_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define PXP_PXP_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define PXP_PXP_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define PXP_PXP_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define PXP_PXP_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define PXP_PXP_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define PXP_PXP_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define PXP_PXP_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define QM_QM_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define QM_QM_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define QM_QM_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define QM_QM_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define QM_QM_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define QM_QM_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define QM_QM_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define QM_QM_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define SEM_FAST_SEM_FAST_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define SEM_FAST_SEM_FAST_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define SEM_FAST_SEM_FAST_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define SEM_FAST_SEM_FAST_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define SEM_FAST_SEM_FAST_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define SEM_FAST_SEM_FAST_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define SEM_FAST_SEM_FAST_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define SEM_FAST_SEM_FAST_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define SRC_SRC_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define SRC_SRC_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define SRC_SRC_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define SRC_SRC_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define SRC_SRC_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define SRC_SRC_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define SRC_SRC_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define SRC_SRC_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define TCM_TCM_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define TCM_TCM_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define TCM_TCM_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define TCM_TCM_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define TCM_TCM_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define TCM_TCM_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define TCM_TCM_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define TCM_TCM_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define TM_TM_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define TM_TM_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define TM_TM_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define TM_TM_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define TM_TM_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define TM_TM_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define TM_TM_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define TM_TM_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define TSDM_TSDM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define TSDM_TSDM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define TSDM_TSDM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define TSDM_TSDM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define TSDM_TSDM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define TSDM_TSDM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define TSDM_TSDM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define TSDM_TSDM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define TSEM_TSEM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define TSEM_TSEM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define TSEM_TSEM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define TSEM_TSEM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define TSEM_TSEM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define TSEM_TSEM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define TSEM_TSEM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define TSEM_TSEM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define UCM_UCM_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define UCM_UCM_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define UCM_UCM_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define UCM_UCM_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define UCM_UCM_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define UCM_UCM_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define UCM_UCM_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define UCM_UCM_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define USDM_USDM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define USDM_USDM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define USDM_USDM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define USDM_USDM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define USDM_USDM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define USDM_USDM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define USDM_USDM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define USDM_USDM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define USEM_USEM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define USEM_USEM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define USEM_USEM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define USEM_USEM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define USEM_USEM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define USEM_USEM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define USEM_USEM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define USEM_USEM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define XCM_XCM_INT_STS_REG_ADDRESS_ERROR (0x1<<0) -#define XCM_XCM_INT_STS_REG_ADDRESS_ERROR_SIZE 0 -#define XCM_XCM_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) -#define XCM_XCM_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 -#define XCM_XCM_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) -#define XCM_XCM_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 -#define XCM_XCM_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) -#define XCM_XCM_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 -#define XSDM_XSDM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define XSDM_XSDM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define XSDM_XSDM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define XSDM_XSDM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define XSDM_XSDM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define XSDM_XSDM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define XSDM_XSDM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define XSDM_XSDM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define XSEM_XSEM_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) -#define XSEM_XSEM_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 -#define XSEM_XSEM_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) -#define XSEM_XSEM_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 -#define XSEM_XSEM_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) -#define XSEM_XSEM_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 -#define XSEM_XSEM_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) -#define XSEM_XSEM_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 -#define CFC_DEBUG1_REG_WRITE_AC (0x1<<4) -#define CFC_DEBUG1_REG_WRITE_AC_SIZE 4 -/* [R 1] debug only: This bit indicates whether indicates that external - buffer was wrapped (oldest data was thrown); Relevant only when - ~dbg_registers_debug_target=2 (PCI) & ~dbg_registers_full_mode=1 (wrap); */ -#define DBG_REG_WRAP_ON_EXT_BUFFER 0xc124 -#define DBG_REG_WRAP_ON_EXT_BUFFER_SIZE 1 -/* [R 1] debug only: This bit indicates whether the internal buffer was - wrapped (oldest data was thrown) Relevant only when - ~dbg_registers_debug_target=0 (internal buffer) */ -#define DBG_REG_WRAP_ON_INT_BUFFER 0xc128 -#define DBG_REG_WRAP_ON_INT_BUFFER_SIZE 1 -#define QM_QM_PRTY_STS_REG_WRBUFF (0x1<<8) -#define QM_QM_PRTY_STS_REG_WRBUFF_SIZE 8 -#define QM_QM_PRTY_STS_CLR_REG_WRBUFF (0x1<<8) -#define QM_QM_PRTY_STS_CLR_REG_WRBUFF_SIZE 8 -#define QM_QM_PRTY_STS_WR_REG_WRBUFF (0x1<<8) -#define QM_QM_PRTY_STS_WR_REG_WRBUFF_SIZE 8 -#define QM_QM_PRTY_MASK_REG_WRBUFF (0x1<<8) -#define QM_QM_PRTY_MASK_REG_WRBUFF_SIZE 8 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_0 0x16880c -#define QM_REG_WRRWEIGHTS_0_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_1 0x168810 -#define QM_REG_WRRWEIGHTS_1_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_10 0x168814 -#define QM_REG_WRRWEIGHTS_10_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_11 0x168818 -#define QM_REG_WRRWEIGHTS_11_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_12 0x16881c -#define QM_REG_WRRWEIGHTS_12_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_13 0x168820 -#define QM_REG_WRRWEIGHTS_13_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_14 0x168824 -#define QM_REG_WRRWEIGHTS_14_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_15 0x168828 -#define QM_REG_WRRWEIGHTS_15_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_2 0x16882c -#define QM_REG_WRRWEIGHTS_2_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_3 0x168830 -#define QM_REG_WRRWEIGHTS_3_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_4 0x168834 -#define QM_REG_WRRWEIGHTS_4_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_5 0x168838 -#define QM_REG_WRRWEIGHTS_5_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_6 0x16883c -#define QM_REG_WRRWEIGHTS_6_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_7 0x168840 -#define QM_REG_WRRWEIGHTS_7_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_8 0x168844 -#define QM_REG_WRRWEIGHTS_8_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_9 0x168848 -#define QM_REG_WRRWEIGHTS_9_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_16 0x16e000 -#define QM_REG_WRRWEIGHTS_16_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_17 0x16e004 -#define QM_REG_WRRWEIGHTS_17_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_18 0x16e008 -#define QM_REG_WRRWEIGHTS_18_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_19 0x16e00c -#define QM_REG_WRRWEIGHTS_19_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_20 0x16e010 -#define QM_REG_WRRWEIGHTS_20_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_21 0x16e014 -#define QM_REG_WRRWEIGHTS_21_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_22 0x16e018 -#define QM_REG_WRRWEIGHTS_22_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_23 0x16e01c -#define QM_REG_WRRWEIGHTS_23_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_24 0x16e020 -#define QM_REG_WRRWEIGHTS_24_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_25 0x16e024 -#define QM_REG_WRRWEIGHTS_25_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_26 0x16e028 -#define QM_REG_WRRWEIGHTS_26_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_27 0x16e02c -#define QM_REG_WRRWEIGHTS_27_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_28 0x16e030 -#define QM_REG_WRRWEIGHTS_28_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_29 0x16e034 -#define QM_REG_WRRWEIGHTS_29_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_30 0x16e038 -#define QM_REG_WRRWEIGHTS_30_SIZE 1 -/* [RW 32] Wrr weights */ -#define QM_REG_WRRWEIGHTS_31 0x16e03c -#define QM_REG_WRRWEIGHTS_31_SIZE 1 #define SRC_REG_COUNTFREE0 0x40500 /* [RW 1] If clr the searcher is compatible to E1 A0 - support only two ports. If set the searcher support 8 functions. */ @@ -3651,12 +2969,6 @@ type (one of 16). */ #define TCM_REG_N_SM_CTX_LD_0 0x50050 #define TCM_REG_N_SM_CTX_LD_1 0x50054 -#define TCM_REG_N_SM_CTX_LD_10 0x50078 -#define TCM_REG_N_SM_CTX_LD_11 0x5007c -#define TCM_REG_N_SM_CTX_LD_12 0x50080 -#define TCM_REG_N_SM_CTX_LD_13 0x50084 -#define TCM_REG_N_SM_CTX_LD_14 0x50088 -#define TCM_REG_N_SM_CTX_LD_15 0x5008c #define TCM_REG_N_SM_CTX_LD_2 0x50058 #define TCM_REG_N_SM_CTX_LD_3 0x5005c #define TCM_REG_N_SM_CTX_LD_4 0x50060 @@ -3863,8 +3175,6 @@ #define TM_REG_LIN_SETCLR_FIFO_ALFULL_THR 0x164070 /* [RW 2] Load value for pci arbiter credit cnt. */ #define TM_REG_PCIARB_CRDCNT_VAL 0x164260 -/* [RW 1] Timer software reset - active high. */ -#define TM_REG_TIMER_SOFT_RST 0x164004 /* [RW 20] The amount of hardware cycles for each timer tick. */ #define TM_REG_TIMER_TICK_SIZE 0x16401c /* [RW 8] Timers Context region. */ @@ -3876,44 +3186,12 @@ /* [RW 8] The event id for aggregated interrupt 0 */ #define TSDM_REG_AGG_INT_EVENT_0 0x42038 #define TSDM_REG_AGG_INT_EVENT_1 0x4203c -#define TSDM_REG_AGG_INT_EVENT_10 0x42060 -#define TSDM_REG_AGG_INT_EVENT_11 0x42064 -#define TSDM_REG_AGG_INT_EVENT_12 0x42068 -#define TSDM_REG_AGG_INT_EVENT_13 0x4206c -#define TSDM_REG_AGG_INT_EVENT_14 0x42070 -#define TSDM_REG_AGG_INT_EVENT_15 0x42074 -#define TSDM_REG_AGG_INT_EVENT_16 0x42078 -#define TSDM_REG_AGG_INT_EVENT_17 0x4207c -#define TSDM_REG_AGG_INT_EVENT_18 0x42080 -#define TSDM_REG_AGG_INT_EVENT_19 0x42084 #define TSDM_REG_AGG_INT_EVENT_2 0x42040 -#define TSDM_REG_AGG_INT_EVENT_20 0x42088 -#define TSDM_REG_AGG_INT_EVENT_21 0x4208c -#define TSDM_REG_AGG_INT_EVENT_22 0x42090 -#define TSDM_REG_AGG_INT_EVENT_23 0x42094 -#define TSDM_REG_AGG_INT_EVENT_24 0x42098 -#define TSDM_REG_AGG_INT_EVENT_25 0x4209c -#define TSDM_REG_AGG_INT_EVENT_26 0x420a0 -#define TSDM_REG_AGG_INT_EVENT_27 0x420a4 -#define TSDM_REG_AGG_INT_EVENT_28 0x420a8 -#define TSDM_REG_AGG_INT_EVENT_29 0x420ac #define TSDM_REG_AGG_INT_EVENT_3 0x42044 -#define TSDM_REG_AGG_INT_EVENT_30 0x420b0 -#define TSDM_REG_AGG_INT_EVENT_31 0x420b4 #define TSDM_REG_AGG_INT_EVENT_4 0x42048 /* [RW 1] The T bit for aggregated interrupt 0 */ #define TSDM_REG_AGG_INT_T_0 0x420b8 #define TSDM_REG_AGG_INT_T_1 0x420bc -#define TSDM_REG_AGG_INT_T_10 0x420e0 -#define TSDM_REG_AGG_INT_T_11 0x420e4 -#define TSDM_REG_AGG_INT_T_12 0x420e8 -#define TSDM_REG_AGG_INT_T_13 0x420ec -#define TSDM_REG_AGG_INT_T_14 0x420f0 -#define TSDM_REG_AGG_INT_T_15 0x420f4 -#define TSDM_REG_AGG_INT_T_16 0x420f8 -#define TSDM_REG_AGG_INT_T_17 0x420fc -#define TSDM_REG_AGG_INT_T_18 0x42100 -#define TSDM_REG_AGG_INT_T_19 0x42104 /* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ #define TSDM_REG_CFC_RSP_START_ADDR 0x42008 /* [RW 16] The maximum value of the competion counter #0 */ @@ -4198,12 +3476,6 @@ connection type (one of 16). */ #define UCM_REG_N_SM_CTX_LD_0 0xe0054 #define UCM_REG_N_SM_CTX_LD_1 0xe0058 -#define UCM_REG_N_SM_CTX_LD_10 0xe007c -#define UCM_REG_N_SM_CTX_LD_11 0xe0080 -#define UCM_REG_N_SM_CTX_LD_12 0xe0084 -#define UCM_REG_N_SM_CTX_LD_13 0xe0088 -#define UCM_REG_N_SM_CTX_LD_14 0xe008c -#define UCM_REG_N_SM_CTX_LD_15 0xe0090 #define UCM_REG_N_SM_CTX_LD_2 0xe005c #define UCM_REG_N_SM_CTX_LD_3 0xe0060 #define UCM_REG_N_SM_CTX_LD_4 0xe0064 @@ -4353,30 +3625,7 @@ /* [RW 8] The event id for aggregated interrupt 0 */ #define USDM_REG_AGG_INT_EVENT_0 0xc4038 #define USDM_REG_AGG_INT_EVENT_1 0xc403c -#define USDM_REG_AGG_INT_EVENT_10 0xc4060 -#define USDM_REG_AGG_INT_EVENT_11 0xc4064 -#define USDM_REG_AGG_INT_EVENT_12 0xc4068 -#define USDM_REG_AGG_INT_EVENT_13 0xc406c -#define USDM_REG_AGG_INT_EVENT_14 0xc4070 -#define USDM_REG_AGG_INT_EVENT_15 0xc4074 -#define USDM_REG_AGG_INT_EVENT_16 0xc4078 -#define USDM_REG_AGG_INT_EVENT_17 0xc407c -#define USDM_REG_AGG_INT_EVENT_18 0xc4080 -#define USDM_REG_AGG_INT_EVENT_19 0xc4084 #define USDM_REG_AGG_INT_EVENT_2 0xc4040 -#define USDM_REG_AGG_INT_EVENT_20 0xc4088 -#define USDM_REG_AGG_INT_EVENT_21 0xc408c -#define USDM_REG_AGG_INT_EVENT_22 0xc4090 -#define USDM_REG_AGG_INT_EVENT_23 0xc4094 -#define USDM_REG_AGG_INT_EVENT_24 0xc4098 -#define USDM_REG_AGG_INT_EVENT_25 0xc409c -#define USDM_REG_AGG_INT_EVENT_26 0xc40a0 -#define USDM_REG_AGG_INT_EVENT_27 0xc40a4 -#define USDM_REG_AGG_INT_EVENT_28 0xc40a8 -#define USDM_REG_AGG_INT_EVENT_29 0xc40ac -#define USDM_REG_AGG_INT_EVENT_3 0xc4044 -#define USDM_REG_AGG_INT_EVENT_30 0xc40b0 -#define USDM_REG_AGG_INT_EVENT_31 0xc40b4 #define USDM_REG_AGG_INT_EVENT_4 0xc4048 #define USDM_REG_AGG_INT_EVENT_5 0xc404c #define USDM_REG_AGG_INT_EVENT_6 0xc4050 @@ -4384,16 +3633,6 @@ or auto-mask-mode (1) */ #define USDM_REG_AGG_INT_MODE_0 0xc41b8 #define USDM_REG_AGG_INT_MODE_1 0xc41bc -#define USDM_REG_AGG_INT_MODE_10 0xc41e0 -#define USDM_REG_AGG_INT_MODE_11 0xc41e4 -#define USDM_REG_AGG_INT_MODE_12 0xc41e8 -#define USDM_REG_AGG_INT_MODE_13 0xc41ec -#define USDM_REG_AGG_INT_MODE_14 0xc41f0 -#define USDM_REG_AGG_INT_MODE_15 0xc41f4 -#define USDM_REG_AGG_INT_MODE_16 0xc41f8 -#define USDM_REG_AGG_INT_MODE_17 0xc41fc -#define USDM_REG_AGG_INT_MODE_18 0xc4200 -#define USDM_REG_AGG_INT_MODE_19 0xc4204 #define USDM_REG_AGG_INT_MODE_4 0xc41c8 #define USDM_REG_AGG_INT_MODE_5 0xc41cc #define USDM_REG_AGG_INT_MODE_6 0xc41d0 @@ -4703,10 +3942,6 @@ /* [RC 1] Set at message length mismatch (relative to last indication) at the nig1 interface. */ #define XCM_REG_NIG1_LENGTH_MIS 0x2023c -/* [RW 3] The weight of the input nig1 in the WRR mechanism. 0 stands for - weight 8 (the most prioritised); 1 stands for weight 1(least - prioritised); 2 stands for weight 2; tc. */ -#define XCM_REG_NIG1_WEIGHT 0x200d8 /* [RW 5] The number of double REG-pairs; loaded from the STORM context and sent to STORM; for a specific connection type. The double REG-pairs are used in order to align to STORM context row size of 128 bits. The offset @@ -4714,12 +3949,6 @@ connection type (one of 16). */ #define XCM_REG_N_SM_CTX_LD_0 0x20060 #define XCM_REG_N_SM_CTX_LD_1 0x20064 -#define XCM_REG_N_SM_CTX_LD_10 0x20088 -#define XCM_REG_N_SM_CTX_LD_11 0x2008c -#define XCM_REG_N_SM_CTX_LD_12 0x20090 -#define XCM_REG_N_SM_CTX_LD_13 0x20094 -#define XCM_REG_N_SM_CTX_LD_14 0x20098 -#define XCM_REG_N_SM_CTX_LD_15 0x2009c #define XCM_REG_N_SM_CTX_LD_2 0x20068 #define XCM_REG_N_SM_CTX_LD_3 0x2006c #define XCM_REG_N_SM_CTX_LD_4 0x20070 @@ -4896,30 +4125,8 @@ #define XSDM_REG_AGG_INT_EVENT_12 0x166068 #define XSDM_REG_AGG_INT_EVENT_13 0x16606c #define XSDM_REG_AGG_INT_EVENT_14 0x166070 -#define XSDM_REG_AGG_INT_EVENT_15 0x166074 -#define XSDM_REG_AGG_INT_EVENT_16 0x166078 -#define XSDM_REG_AGG_INT_EVENT_17 0x16607c -#define XSDM_REG_AGG_INT_EVENT_18 0x166080 -#define XSDM_REG_AGG_INT_EVENT_19 0x166084 -#define XSDM_REG_AGG_INT_EVENT_10 0x166060 -#define XSDM_REG_AGG_INT_EVENT_11 0x166064 -#define XSDM_REG_AGG_INT_EVENT_12 0x166068 -#define XSDM_REG_AGG_INT_EVENT_13 0x16606c -#define XSDM_REG_AGG_INT_EVENT_14 0x166070 #define XSDM_REG_AGG_INT_EVENT_2 0x166040 -#define XSDM_REG_AGG_INT_EVENT_20 0x166088 -#define XSDM_REG_AGG_INT_EVENT_21 0x16608c -#define XSDM_REG_AGG_INT_EVENT_22 0x166090 -#define XSDM_REG_AGG_INT_EVENT_23 0x166094 -#define XSDM_REG_AGG_INT_EVENT_24 0x166098 -#define XSDM_REG_AGG_INT_EVENT_25 0x16609c -#define XSDM_REG_AGG_INT_EVENT_26 0x1660a0 -#define XSDM_REG_AGG_INT_EVENT_27 0x1660a4 -#define XSDM_REG_AGG_INT_EVENT_28 0x1660a8 -#define XSDM_REG_AGG_INT_EVENT_29 0x1660ac #define XSDM_REG_AGG_INT_EVENT_3 0x166044 -#define XSDM_REG_AGG_INT_EVENT_30 0x1660b0 -#define XSDM_REG_AGG_INT_EVENT_31 0x1660b4 #define XSDM_REG_AGG_INT_EVENT_4 0x166048 #define XSDM_REG_AGG_INT_EVENT_5 0x16604c #define XSDM_REG_AGG_INT_EVENT_6 0x166050 @@ -4930,16 +4137,6 @@ or auto-mask-mode (1) */ #define XSDM_REG_AGG_INT_MODE_0 0x1661b8 #define XSDM_REG_AGG_INT_MODE_1 0x1661bc -#define XSDM_REG_AGG_INT_MODE_10 0x1661e0 -#define XSDM_REG_AGG_INT_MODE_11 0x1661e4 -#define XSDM_REG_AGG_INT_MODE_12 0x1661e8 -#define XSDM_REG_AGG_INT_MODE_13 0x1661ec -#define XSDM_REG_AGG_INT_MODE_14 0x1661f0 -#define XSDM_REG_AGG_INT_MODE_15 0x1661f4 -#define XSDM_REG_AGG_INT_MODE_16 0x1661f8 -#define XSDM_REG_AGG_INT_MODE_17 0x1661fc -#define XSDM_REG_AGG_INT_MODE_18 0x166200 -#define XSDM_REG_AGG_INT_MODE_19 0x166204 /* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ #define XSDM_REG_CFC_RSP_START_ADDR 0x166008 /* [RW 16] The maximum value of the competion counter #0 */ @@ -5147,10 +4344,6 @@ #define MCPR_NVM_COMMAND_FIRST (1L<<7) #define MCPR_NVM_COMMAND_LAST (1L<<8) #define MCPR_NVM_COMMAND_WR (1L<<5) -#define MCPR_NVM_COMMAND_WREN (1L<<16) -#define MCPR_NVM_COMMAND_WREN_BITSHIFT 16 -#define MCPR_NVM_COMMAND_WRDI (1L<<17) -#define MCPR_NVM_COMMAND_WRDI_BITSHIFT 17 #define MCPR_NVM_SW_ARB_ARB_ARB1 (1L<<9) #define MCPR_NVM_SW_ARB_ARB_REQ_CLR1 (1L<<5) #define MCPR_NVM_SW_ARB_ARB_REQ_SET1 (1L<<1) @@ -5251,10 +4444,6 @@ #define MISC_REGISTERS_SPIO_7 7 #define MISC_REGISTERS_SPIO_CLR_POS 16 #define MISC_REGISTERS_SPIO_FLOAT (0xffL<<24) -#define GRC_MISC_REGISTERS_SPIO_FLOAT7 0x80000000 -#define GRC_MISC_REGISTERS_SPIO_FLOAT6 0x40000000 -#define GRC_MISC_REGISTERS_SPIO_FLOAT5 0x20000000 -#define GRC_MISC_REGISTERS_SPIO_FLOAT4 0x10000000 #define MISC_REGISTERS_SPIO_FLOAT_POS 24 #define MISC_REGISTERS_SPIO_INPUT_HI_Z 2 #define MISC_REGISTERS_SPIO_INT_OLD_SET_POS 16 -- cgit v1.2.3-18-g5258 From ab6ad5a4875e99dffe957a411fe890402a91f67f Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:24:29 +0000 Subject: bnx2x: Whitespaces and comments Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x.h | 38 ++++++++-------- drivers/net/bnx2x_link.c | 115 ++++++++++++++++++++++++----------------------- drivers/net/bnx2x_main.c | 80 +++++++++++++++++---------------- drivers/net/bnx2x_reg.h | 3 +- 4 files changed, 121 insertions(+), 115 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 97bc5e046f4..bbf842284eb 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -314,9 +314,11 @@ struct bnx2x_fastpath { __le16 *rx_cons_sb; __le16 *rx_bd_cons_sb; + unsigned long tx_pkt, rx_pkt, rx_calls; + /* TPA related */ struct sw_rx_bd tpa_pool[ETH_MAX_AGGREGATION_QUEUES_E1H]; u8 tpa_state[ETH_MAX_AGGREGATION_QUEUES_E1H]; @@ -998,20 +1000,20 @@ struct bnx2x { #define GUNZIP_PHYS(bp) (bp->gunzip_mapping) #define GUNZIP_OUTLEN(bp) (bp->gunzip_outlen) - struct raw_op *init_ops; + struct raw_op *init_ops; /* Init blocks offsets inside init_ops */ - u16 *init_ops_offsets; + u16 *init_ops_offsets; /* Data blob - has 32 bit granularity */ - u32 *init_data; + u32 *init_data; /* Zipped PRAM blobs - raw data */ - const u8 *tsem_int_table_data; - const u8 *tsem_pram_data; - const u8 *usem_int_table_data; - const u8 *usem_pram_data; - const u8 *xsem_int_table_data; - const u8 *xsem_pram_data; - const u8 *csem_int_table_data; - const u8 *csem_pram_data; + const u8 *tsem_int_table_data; + const u8 *tsem_pram_data; + const u8 *usem_int_table_data; + const u8 *usem_pram_data; + const u8 *xsem_int_table_data; + const u8 *xsem_pram_data; + const u8 *csem_int_table_data; + const u8 *csem_pram_data; #define INIT_OPS(bp) (bp->init_ops) #define INIT_OPS_OFFSETS(bp) (bp->init_ops_offsets) #define INIT_DATA(bp) (bp->init_data) @@ -1024,7 +1026,7 @@ struct bnx2x { #define INIT_CSEM_INT_TABLE_DATA(bp) (bp->csem_int_table_data) #define INIT_CSEM_PRAM_DATA(bp) (bp->csem_pram_data) - const struct firmware *firmware; + const struct firmware *firmware; }; @@ -1111,9 +1113,9 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, #define DMAE_COMP_VAL 0xe0d0d0ae #define MAX_DMAE_C_PER_PORT 8 -#define INIT_DMAE_C(bp) (BP_PORT(bp)*MAX_DMAE_C_PER_PORT + \ +#define INIT_DMAE_C(bp) (BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \ BP_E1HVN(bp)) -#define PMF_DMAE_C(bp) (BP_PORT(bp)*MAX_DMAE_C_PER_PORT + \ +#define PMF_DMAE_C(bp) (BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \ E1HVN_MAX) @@ -1138,7 +1140,8 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, /* must be used on a CID before placing it on a HW ring */ -#define HW_CID(bp, x) ((BP_PORT(bp) << 23) | (BP_E1HVN(bp) << 17) | x) +#define HW_CID(bp, x) ((BP_PORT(bp) << 23) | \ + (BP_E1HVN(bp) << 17) | (x)) #define SP_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_spe)) #define MAX_SP_DESC_CNT (SP_DESC_CNT - 1) @@ -1226,8 +1229,8 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, AEU_INPUTS_ATTN_BITS_QM_PARITY_ERROR | \ AEU_INPUTS_ATTN_BITS_XSDM_PARITY_ERROR | \ AEU_INPUTS_ATTN_BITS_XSEMI_PARITY_ERROR | \ - AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR |\ - AEU_INPUTS_ATTN_BITS_VAUX_PCI_CORE_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_VAUX_PCI_CORE_PARITY_ERROR |\ AEU_INPUTS_ATTN_BITS_DEBUG_PARITY_ERROR | \ AEU_INPUTS_ATTN_BITS_USDM_PARITY_ERROR | \ AEU_INPUTS_ATTN_BITS_USEMI_PARITY_ERROR | \ @@ -1255,7 +1258,6 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY | \ (bp->multi_mode << \ TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_MODE_SHIFT)) - #define MULTI_MASK 0x7f diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index c2b001031e7..e32d3370862 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -182,6 +182,7 @@ static void bnx2x_set_serdes_access(struct link_params *params) { struct bnx2x *bp = params->bp; u32 emac_base = (params->port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + /* Set Clause 22 */ REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + params->port*0x10, 1); REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000); @@ -194,6 +195,7 @@ static void bnx2x_set_serdes_access(struct link_params *params) static void bnx2x_set_phy_mdio(struct link_params *params, u8 phy_flags) { struct bnx2x *bp = params->bp; + if (phy_flags & PHY_XGXS_FLAG) { REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST + params->port*0x18, 0); @@ -465,7 +467,6 @@ static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars, REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, wb_data, 2); - /* set rx mtu */ wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; wb_data[1] = 0; @@ -684,6 +685,7 @@ void bnx2x_link_status_update(struct link_params *params, static void bnx2x_update_mng(struct link_params *params, u32 link_status) { struct bnx2x *bp = params->bp; + REG_WR(bp, params->shmem_base + offsetof(struct shmem_region, port_mb[params->port].link_status), @@ -780,7 +782,6 @@ static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl, DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", line_speed); return -EINVAL; - break; } } REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd); @@ -800,6 +801,7 @@ static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl, static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port) { u32 emac_base; + switch (ext_phy_type) { case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: @@ -905,7 +907,7 @@ u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type, val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL | EMAC_MDIO_MODE_CLOCK_CNT)); val |= (EMAC_MDIO_MODE_CLAUSE_45 | - (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT)); + (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT)); REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val); REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); udelay(40); @@ -1535,14 +1537,14 @@ static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result) } } -static u8 bnx2x_ext_phy_resove_fc(struct link_params *params, +static u8 bnx2x_ext_phy_resolve_fc(struct link_params *params, struct link_vars *vars) { struct bnx2x *bp = params->bp; u8 ext_phy_addr; - u16 ld_pause; /* local */ - u16 lp_pause; /* link partner */ - u16 an_complete; /* AN complete */ + u16 ld_pause; /* local */ + u16 lp_pause; /* link partner */ + u16 an_complete; /* AN complete */ u16 pause_result; u8 ret = 0; u32 ext_phy_type; @@ -1642,7 +1644,7 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params, DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result); bnx2x_pause_resolve(vars, pause_result); } else if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) && - (bnx2x_ext_phy_resove_fc(params, vars))) { + (bnx2x_ext_phy_resolve_fc(params, vars))) { return; } else { if (params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) @@ -1784,7 +1786,7 @@ static u8 bnx2x_link_settings_status(struct link_params *params, "link speed unsupported gp_status 0x%x\n", gp_status); return -EINVAL; - break; + case GP_STATUS_10G_KX4: case GP_STATUS_10G_HIG: case GP_STATUS_10G_CX4: @@ -1821,8 +1823,7 @@ static u8 bnx2x_link_settings_status(struct link_params *params, DP(NETIF_MSG_LINK, "link speed unsupported gp_status 0x%x\n", gp_status); - return -EINVAL; - break; + return -EINVAL; } /* Upon link speed change set the NIG into drain mode. @@ -2061,16 +2062,17 @@ static void bnx2x_ext_phy_reset(struct link_params *params, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15); - break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: + DP(NETIF_MSG_LINK, "XGXS 8072\n"); + /* Unset Low Power Mode and SW reset */ /* Restore normal power mode*/ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); - DP(NETIF_MSG_LINK, "XGXS 8072\n"); bnx2x_cl45_write(bp, params->port, ext_phy_type, ext_phy_addr, @@ -2078,8 +2080,9 @@ static void bnx2x_ext_phy_reset(struct link_params *params, MDIO_PMA_REG_CTRL, 1<<15); break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: - { + DP(NETIF_MSG_LINK, "XGXS 8073\n"); /* Restore normal power mode*/ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, @@ -2089,9 +2092,6 @@ static void bnx2x_ext_phy_reset(struct link_params *params, bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); - - DP(NETIF_MSG_LINK, "XGXS 8073\n"); - } break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: @@ -2107,7 +2107,6 @@ static void bnx2x_ext_phy_reset(struct link_params *params, break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481: - /* Restore normal power mode*/ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, MISC_REGISTERS_GPIO_OUTPUT_HIGH, @@ -2146,20 +2145,18 @@ static void bnx2x_ext_phy_reset(struct link_params *params, break; default: - DP(NETIF_MSG_LINK, - "BAD SerDes ext_phy_config 0x%x\n", + DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n", params->ext_phy_config); break; } } } - static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port, u32 shmem_base, u32 spirom_ver) { - DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x\n", - (u16)(spirom_ver>>16), (u16)spirom_ver); + DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n", + (u16)(spirom_ver>>16), (u16)spirom_ver, port); REG_WR(bp, shmem_base + offsetof(struct shmem_region, port_mb[port].ext_phy_fw_version), @@ -2171,6 +2168,7 @@ static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp, u8 port, u32 shmem_base) { u16 fw_ver1, fw_ver2; + bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &fw_ver1); bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, @@ -2423,7 +2421,6 @@ static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params) } DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n"); return -EINVAL; - } static void bnx2x_bcm8073_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port, @@ -2565,6 +2562,7 @@ static void bnx2x_sfp_set_transmitter(struct bnx2x *bp, u8 port, u8 tx_en) { u16 val; + DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n", tx_en, port); /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/ @@ -2597,6 +2595,7 @@ static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params, u8 port = params->port; u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + if (byte_cnt > 16) { DP(NETIF_MSG_LINK, "Reading from eeprom is" " is limited to 0xf\n"); @@ -2808,6 +2807,7 @@ static u8 bnx2x_get_edc_mode(struct link_params *params, case SFP_EEPROM_CON_TYPE_VAL_COPPER: { u8 copper_module_type; + /* Check if its active cable( includes SFP+ module) of passive cable*/ if (bnx2x_read_sfp_module_eeprom(params, @@ -2842,7 +2842,6 @@ static u8 bnx2x_get_edc_mode(struct link_params *params, DP(NETIF_MSG_LINK, "Optic module detected\n"); check_limiting_mode = 1; break; - default: DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n", val); @@ -3169,6 +3168,7 @@ void bnx2x_handle_module_detect_int(struct link_params *params) struct bnx2x *bp = params->bp; u32 gpio_val; u8 port = params->port; + /* Set valid module led off */ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, MISC_REGISTERS_GPIO_HIGH, @@ -3236,6 +3236,7 @@ static void bnx2x_bcm807x_force_10G(struct link_params *params) MDIO_AN_REG_CTRL, 0x0000); } + static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params) { struct bnx2x *bp = params->bp; @@ -3303,7 +3304,6 @@ static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params) static void bnx2x_8073_set_pause_cl37(struct link_params *params, struct link_vars *vars) { - struct bnx2x *bp = params->bp; u16 cl37_val; u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); @@ -3535,6 +3535,7 @@ static void bnx2x_init_internal_phy(struct link_params *params, u8 enable_cl73) { struct bnx2x *bp = params->bp; + if (!(vars->phy_flags & PHY_SGMII_FLAG)) { if ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) && @@ -3585,6 +3586,7 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) u16 ctrl = 0; u16 val = 0; u8 rc = 0; + if (vars->phy_flags & PHY_XGXS_FLAG) { ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); @@ -3881,14 +3883,12 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) bnx2x_8073_set_pause_cl37(params, vars); if (ext_phy_type == - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072){ + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) bnx2x_bcm8072_external_rom_boot(params); - } else { - + else /* In case of 8073 with long xaui lines, don't set the 8073 xaui low power*/ bnx2x_bcm8073_set_xaui_low_power_mode(params); - } bnx2x_cl45_read(bp, params->port, ext_phy_type, @@ -3953,10 +3953,8 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) ext_phy_addr, MDIO_AN_DEVAD, MDIO_AN_REG_ADV, val); - if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) { - bnx2x_cl45_read(bp, params->port, ext_phy_type, ext_phy_addr, @@ -4290,7 +4288,6 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) bnx2x_save_spirom_version(params->bp, params->port, params->shmem_base, (u32)(fw_ver1<<16 | fw_ver2)); - break; } case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481: @@ -4621,6 +4618,7 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, u16 rx_sd, pcs_status; u8 ext_phy_link_up = 0; u8 port = params->port; + if (vars->phy_flags & PHY_XGXS_FLAG) { ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); @@ -4729,7 +4727,6 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, break; } } - if (val2 & (1<<1)) vars->line_speed = SPEED_1000; else @@ -4786,8 +4783,9 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, if ((val1 & (1<<8)) == 0) { DP(NETIF_MSG_LINK, "8727 Power fault" - " has been detected on port" - " %d\n", params->port); + " has been detected on " + "port %d\n", + params->port); printk(KERN_ERR PFX "Error: Power" " fault on %s Port %d has" " been detected and the" @@ -4894,6 +4892,7 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, { u16 link_status = 0; u16 an1000_status = 0; + if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) { bnx2x_cl45_read(bp, params->port, @@ -4909,7 +4908,6 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, DP(NETIF_MSG_LINK, "870x LASI status 0x%x->0x%x\n", val1, val2); - } else { /* In 8073, port1 is directed through emac0 and * port0 is directed through emac1 @@ -5039,8 +5037,6 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH, 0x0333); - - } bnx2x_cl45_read(bp, params->port, ext_phy_type, @@ -5225,7 +5221,6 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, ext_phy_addr); } } - break; default: DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n", @@ -5272,6 +5267,7 @@ static void bnx2x_link_int_enable(struct link_params *params) u32 ext_phy_type; u32 mask; struct bnx2x *bp = params->bp; + /* setting the status to report on link up for either XGXS or SerDes */ @@ -5303,10 +5299,10 @@ static void bnx2x_link_int_enable(struct link_params *params) bnx2x_bits_en(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, mask); - DP(NETIF_MSG_LINK, "port %x, is_xgxs=%x, int_status 0x%x\n", port, + + DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port, (params->switch_cfg == SWITCH_CFG_10G), REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4)); - DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n", REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4), REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18), @@ -5738,6 +5734,7 @@ u8 bnx2x_set_led(struct bnx2x *bp, u8 port, u8 mode, u32 speed, u8 rc = 0; u32 tmp; u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode); DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n", speed, hw_led_mode); @@ -5816,6 +5813,7 @@ static u8 bnx2x_link_initialize(struct link_params *params, u8 rc = 0; u8 non_ext_phy; u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + /* Activate the external PHY */ bnx2x_ext_phy_reset(params, vars); @@ -5889,11 +5887,11 @@ static u8 bnx2x_link_initialize(struct link_params *params, u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) { struct bnx2x *bp = params->bp; - u32 val; - DP(NETIF_MSG_LINK, "Phy Initialization started \n"); - DP(NETIF_MSG_LINK, "req_speed = %d, req_flowctrl=%d\n", - params->req_line_speed, params->req_flow_ctrl); + + DP(NETIF_MSG_LINK, "Phy Initialization started\n"); + DP(NETIF_MSG_LINK, "req_speed %d, req_flowctrl %d\n", + params->req_line_speed, params->req_flow_ctrl); vars->link_status = 0; vars->phy_link_up = 0; vars->link_up = 0; @@ -5907,7 +5905,6 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) else vars->phy_flags = PHY_XGXS_FLAG; - /* disable attentions */ bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4, (NIG_MASK_XGXS0_LINK_STATUS | @@ -5918,6 +5915,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) bnx2x_emac_init(params, vars); if (CHIP_REV_IS_FPGA(bp)) { + vars->link_up = 1; vars->line_speed = SPEED_10000; vars->duplex = DUPLEX_FULL; @@ -5926,7 +5924,8 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) /* enable on E1.5 FPGA */ if (CHIP_IS_E1H(bp)) { vars->flow_ctrl |= - (BNX2X_FLOW_CTRL_TX | BNX2X_FLOW_CTRL_RX); + (BNX2X_FLOW_CTRL_TX | + BNX2X_FLOW_CTRL_RX); vars->link_status |= (LINK_STATUS_TX_FLOW_CONTROL_ENABLED | LINK_STATUS_RX_FLOW_CONTROL_ENABLED); @@ -5935,8 +5934,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) bnx2x_emac_enable(params, vars, 0); bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed); /* disable drain */ - REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE - + params->port*4, 0); + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); /* update shared memory */ bnx2x_update_mng(params, vars->link_status); @@ -5966,6 +5964,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) } else if (params->loopback_mode == LOOPBACK_BMAC) { + vars->link_up = 1; vars->line_speed = SPEED_10000; vars->duplex = DUPLEX_FULL; @@ -5980,7 +5979,9 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); + } else if (params->loopback_mode == LOOPBACK_EMAC) { + vars->link_up = 1; vars->line_speed = SPEED_1000; vars->duplex = DUPLEX_FULL; @@ -5996,8 +5997,10 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) vars->duplex); REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); + } else if ((params->loopback_mode == LOOPBACK_XGXS_10) || - (params->loopback_mode == LOOPBACK_EXT_PHY)) { + (params->loopback_mode == LOOPBACK_EXT_PHY)) { + vars->link_up = 1; vars->line_speed = SPEED_10000; vars->duplex = DUPLEX_FULL; @@ -6034,7 +6037,6 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) } else /* No loopback */ { - bnx2x_phy_deassert(params, vars->phy_flags); switch (params->switch_cfg) { case SWITCH_CFG_1G: @@ -6042,8 +6044,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) if ((params->ext_phy_config & PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) == PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482) { - vars->phy_flags |= - PHY_SGMII_FLAG; + vars->phy_flags |= PHY_SGMII_FLAG; } val = REG_RD(bp, @@ -6064,7 +6065,6 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) default: DP(NETIF_MSG_LINK, "Invalid switch_cfg\n"); return -EINVAL; - break; } DP(NETIF_MSG_LINK, "Phy address = 0x%x\n", params->phy_addr); @@ -6089,7 +6089,6 @@ static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr) u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, u8 reset_ext_phy) { - struct bnx2x *bp = params->bp; u32 ext_phy_config = params->ext_phy_config; u16 hw_led_mode = params->hw_led_mode; @@ -6102,7 +6101,6 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, config)); /* disable attentions */ - vars->link_status = 0; bnx2x_update_mng(params, vars->link_status); bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, @@ -6198,6 +6196,7 @@ static u8 bnx2x_update_link_down(struct link_params *params, { struct bnx2x *bp = params->bp; u8 port = params->port; + DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port); bnx2x_set_led(bp, port, LED_MODE_OFF, 0, params->hw_led_mode, @@ -6234,6 +6233,7 @@ static u8 bnx2x_update_link_up(struct link_params *params, struct bnx2x *bp = params->bp; u8 port = params->port; u8 rc = 0; + vars->link_status |= LINK_STATUS_LINK_UP; if (link_10g) { bnx2x_bmac_enable(params, vars, 0); @@ -6547,6 +6547,7 @@ static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base) u8 ext_phy_addr; u32 val; s8 port; + /* Use port1 because of the static port-swap */ /* Enable the module detection interrupt */ val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN); diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 8b6bb999d8e..466c447c5fe 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -63,8 +63,8 @@ #include #include "bnx2x_fw_file_hdr.h" /* FW files */ -#define FW_FILE_PREFIX_E1 "bnx2x-e1-" -#define FW_FILE_PREFIX_E1H "bnx2x-e1h-" +#define FW_FILE_PREFIX_E1 "bnx2x-e1-" +#define FW_FILE_PREFIX_E1H "bnx2x-e1h-" /* Time in jiffies before concluding the transmitter is hung */ #define TX_TIMEOUT (5*HZ) @@ -723,7 +723,6 @@ static void bnx2x_int_disable(struct bnx2x *bp) REG_WR(bp, addr, val); if (REG_RD(bp, addr) != val) BNX2X_ERR("BUG! proper val not read from IGU!\n"); - } static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw) @@ -1660,6 +1659,7 @@ reuse_rx: } skb_record_rx_queue(skb, fp->index); + #ifdef BCM_VLAN if ((bp->vlgrp != NULL) && (bp->flags & HW_VLAN_RX_FLAG) && (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) & @@ -2418,14 +2418,12 @@ static void bnx2x_link_attn(struct bnx2x *bp) int func; int vn; + /* Set the attention towards other drivers on the same port */ for (vn = VN_0; vn < E1HVN_MAX; vn++) { if (vn == BP_E1HVN(bp)) continue; func = ((vn << 1) | port); - - /* Set the attention towards other drivers - on the same port */ REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 + (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1); } @@ -2880,6 +2878,7 @@ static inline void bnx2x_fan_failure(struct bnx2x *bp) " damage. Please contact Dell Support for assistance\n", bp->dev->name); } + static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) { int port = BP_PORT(bp); @@ -7660,9 +7659,11 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode) bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT; + /* Set "drop all" */ bp->rx_mode = BNX2X_RX_MODE_NONE; bnx2x_set_storm_rx_mode(bp); + /* Disable HW interrupts, NAPI and Tx */ bnx2x_netif_stop(bp, 1); del_timer_sync(&bp->timer); @@ -9158,8 +9159,7 @@ static int bnx2x_nway_reset(struct net_device *dev) return 0; } -static u32 -bnx2x_get_link(struct net_device *dev) +static u32 bnx2x_get_link(struct net_device *dev) { struct bnx2x *bp = netdev_priv(dev); @@ -10169,7 +10169,7 @@ static int bnx2x_test_nvram(struct bnx2x *bp) __be32 buf[0x350 / 4]; u8 *data = (u8 *)buf; int i, rc; - u32 magic, csum; + u32 magic, crc; rc = bnx2x_nvram_read(bp, 0, data, 4); if (rc) { @@ -10194,10 +10194,10 @@ static int bnx2x_test_nvram(struct bnx2x *bp) goto test_nvram_exit; } - csum = ether_crc_le(nvram_tbl[i].size, data); - if (csum != CRC32_RESIDUAL) { + crc = ether_crc_le(nvram_tbl[i].size, data); + if (crc != CRC32_RESIDUAL) { DP(NETIF_MSG_PROBE, - "nvram_tbl[%d] csum value (0x%08x)\n", i, csum); + "nvram_tbl[%d] crc value (0x%08x)\n", i, crc); rc = -ENODEV; goto test_nvram_exit; } @@ -11771,17 +11771,17 @@ static int __devinit bnx2x_check_firmware(struct bnx2x *bp) BCM_5710_FW_MINOR_VERSION, BCM_5710_FW_REVISION_VERSION, BCM_5710_FW_ENGINEERING_VERSION); - return -EINVAL; + return -EINVAL; } return 0; } -static void inline be32_to_cpu_n(const u8 *_source, u8 *_target, u32 n) +static inline void be32_to_cpu_n(const u8 *_source, u8 *_target, u32 n) { + const __be32 *source = (const __be32 *)_source; + u32 *target = (u32 *)_target; u32 i; - const __be32 *source = (const __be32*)_source; - u32 *target = (u32*)_target; for (i = 0; i < n/4; i++) target[i] = be32_to_cpu(source[i]); @@ -11791,66 +11791,67 @@ static void inline be32_to_cpu_n(const u8 *_source, u8 *_target, u32 n) Ops array is stored in the following format: {op(8bit), offset(24bit, big endian), data(32bit, big endian)} */ -static void inline bnx2x_prep_ops(const u8 *_source, u8 *_target, u32 n) +static inline void bnx2x_prep_ops(const u8 *_source, u8 *_target, u32 n) { + const __be32 *source = (const __be32 *)_source; + struct raw_op *target = (struct raw_op *)_target; u32 i, j, tmp; - const __be32 *source = (const __be32*)_source; - struct raw_op *target = (struct raw_op*)_target; - for (i = 0, j = 0; i < n/8; i++, j+=2) { + for (i = 0, j = 0; i < n/8; i++, j += 2) { tmp = be32_to_cpu(source[j]); target[i].op = (tmp >> 24) & 0xff; target[i].offset = tmp & 0xffffff; target[i].raw_data = be32_to_cpu(source[j+1]); } } -static void inline be16_to_cpu_n(const u8 *_source, u8 *_target, u32 n) + +static inline void be16_to_cpu_n(const u8 *_source, u8 *_target, u32 n) { + const __be16 *source = (const __be16 *)_source; + u16 *target = (u16 *)_target; u32 i; - u16 *target = (u16*)_target; - const __be16 *source = (const __be16*)_source; for (i = 0; i < n/2; i++) target[i] = be16_to_cpu(source[i]); } #define BNX2X_ALLOC_AND_SET(arr, lbl, func) \ - do { \ - u32 len = be32_to_cpu(fw_hdr->arr.len); \ - bp->arr = kmalloc(len, GFP_KERNEL); \ + do { \ + u32 len = be32_to_cpu(fw_hdr->arr.len); \ + bp->arr = kmalloc(len, GFP_KERNEL); \ if (!bp->arr) { \ - printk(KERN_ERR PFX "Failed to allocate %d bytes for "#arr"\n", len); \ + printk(KERN_ERR PFX "Failed to allocate %d bytes " \ + "for "#arr"\n", len); \ goto lbl; \ } \ - func(bp->firmware->data + \ - be32_to_cpu(fw_hdr->arr.offset), \ - (u8*)bp->arr, len); \ + func(bp->firmware->data + be32_to_cpu(fw_hdr->arr.offset), \ + (u8 *)bp->arr, len); \ } while (0) - static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev) { char fw_file_name[40] = {0}; - int rc, offset; struct bnx2x_fw_file_hdr *fw_hdr; + int rc, offset; /* Create a FW file name */ if (CHIP_IS_E1(bp)) - offset = sprintf(fw_file_name, FW_FILE_PREFIX_E1); + offset = sprintf(fw_file_name, FW_FILE_PREFIX_E1); else offset = sprintf(fw_file_name, FW_FILE_PREFIX_E1H); sprintf(fw_file_name + offset, "%d.%d.%d.%d.fw", BCM_5710_FW_MAJOR_VERSION, - BCM_5710_FW_MINOR_VERSION, - BCM_5710_FW_REVISION_VERSION, - BCM_5710_FW_ENGINEERING_VERSION); + BCM_5710_FW_MINOR_VERSION, + BCM_5710_FW_REVISION_VERSION, + BCM_5710_FW_ENGINEERING_VERSION); printk(KERN_INFO PFX "Loading %s\n", fw_file_name); rc = request_firmware(&bp->firmware, fw_file_name, dev); if (rc) { - printk(KERN_ERR PFX "Can't load firmware file %s\n", fw_file_name); + printk(KERN_ERR PFX "Can't load firmware file %s\n", + fw_file_name); goto request_firmware_exit; } @@ -11870,7 +11871,8 @@ static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev) BNX2X_ALLOC_AND_SET(init_ops, init_ops_alloc_err, bnx2x_prep_ops); /* Offsets */ - BNX2X_ALLOC_AND_SET(init_ops_offsets, init_offsets_alloc_err, be16_to_cpu_n); + BNX2X_ALLOC_AND_SET(init_ops_offsets, init_offsets_alloc_err, + be16_to_cpu_n); /* STORMs firmware */ INIT_TSEM_INT_TABLE_DATA(bp) = bp->firmware->data + @@ -11891,6 +11893,7 @@ static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev) be32_to_cpu(fw_hdr->csem_pram_data.offset); return 0; + init_offsets_alloc_err: kfree(bp->init_ops); init_ops_alloc_err: @@ -11902,7 +11905,6 @@ request_firmware_exit: } - static int __devinit bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h index 95ebf3fb3e8..0695be14cf9 100644 --- a/drivers/net/bnx2x_reg.h +++ b/drivers/net/bnx2x_reg.h @@ -4561,7 +4561,8 @@ #define LATCHED_ATTN_SCPAD_PARITY_MCP 33 #define GENERAL_ATTEN_WORD(atten_name) ((94 + atten_name) / 32) -#define GENERAL_ATTEN_OFFSET(atten_name) (1 << ((94 + atten_name) % 32)) +#define GENERAL_ATTEN_OFFSET(atten_name)\ + (1UL << ((94 + atten_name) % 32)) /* * This file defines GRC base address for every block. * This file is included by chipsim, asm microcode and cpp microcode. -- cgit v1.2.3-18-g5258 From c458bc50e31631f7e9333ea6f1832fc54d4e2c1e Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:24:31 +0000 Subject: bnx2x: update version to 1.52.1 Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 466c447c5fe..b318d16a4d9 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -56,8 +56,8 @@ #include "bnx2x_init_ops.h" #include "bnx2x_dump.h" -#define DRV_MODULE_VERSION "1.48.114-1" -#define DRV_MODULE_RELDATE "2009/07/29" +#define DRV_MODULE_VERSION "1.52.1" +#define DRV_MODULE_RELDATE "2009/08/12" #define BNX2X_BC_VER 0x040200 #include -- cgit v1.2.3-18-g5258 From 9b0365f1954b0b54a896171b4438ed42ad7ef02f Mon Sep 17 00:00:00 2001 From: Sarveshwar Bandi Date: Wed, 12 Aug 2009 21:01:29 +0000 Subject: be2net:Creating/destroying queues regardless of netif_running() in suspend/resume path Signed-off-by: sarveshwarb Signed-off-by: David S. Miller --- drivers/net/benet/be_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 2db879c03c6..45507d88e6a 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1972,9 +1972,9 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state) if (netif_running(netdev)) { rtnl_lock(); be_close(netdev); - be_clear(adapter); rtnl_unlock(); } + be_clear(adapter); pci_save_state(pdev); pci_disable_device(pdev); @@ -1997,9 +1997,9 @@ static int be_resume(struct pci_dev *pdev) pci_set_power_state(pdev, 0); pci_restore_state(pdev); + be_setup(adapter); if (netif_running(netdev)) { rtnl_lock(); - be_setup(adapter); be_open(netdev); rtnl_unlock(); } -- cgit v1.2.3-18-g5258 From 8dd07086a1f8048428d33a1917b6209978750cb1 Mon Sep 17 00:00:00 2001 From: roel kluin Date: Mon, 10 Aug 2009 01:29:52 +0000 Subject: lmc: Read outside array bounds If dev_alloc_skb() fails on the first iteration of the allocation loop, then we end up writing before the start of the array. Signed-off-by: Roel Kluin Signed-off-by: David S. Miller --- drivers/net/wan/lmc/lmc_main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index d1492ae5d30..6e6b08c3a1e 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -1897,11 +1897,12 @@ static void lmc_softreset (lmc_softc_t * const sc) /*fold00*/ /* * Sets end of ring */ - sc->lmc_rxring[i - 1].length |= 0x02000000; /* Set end of buffers flag */ - sc->lmc_rxring[i - 1].buffer2 = virt_to_bus (&sc->lmc_rxring[0]); /* Point back to the start */ + if (i != 0) { + sc->lmc_rxring[i - 1].length |= 0x02000000; /* Set end of buffers flag */ + sc->lmc_rxring[i - 1].buffer2 = virt_to_bus(&sc->lmc_rxring[0]); /* Point back to the start */ + } LMC_CSR_WRITE (sc, csr_rxlist, virt_to_bus (sc->lmc_rxring)); /* write base address */ - /* Initialize the transmit rings and buffers */ for (i = 0; i < LMC_TXDESCS; i++) { -- cgit v1.2.3-18-g5258 From f16aea4d201018a124f3c1efd7f247fd3b11e4e1 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 12 Aug 2009 12:22:46 +0000 Subject: korina: fix printk formatting, add final info line The macro DRV_NAME contains "korina", the field dev->name points to the actual interface name. So messages were formerly prefixed with 'korinaeth2:' (on my system). Signed-off-by: Phil Sutter Signed-off-by: David S. Miller --- drivers/net/korina.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/korina.c b/drivers/net/korina.c index b4cf602c32b..6df9d253cc0 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c @@ -338,7 +338,7 @@ static irqreturn_t korina_rx_dma_interrupt(int irq, void *dev_id) napi_schedule(&lp->napi); if (dmas & DMA_STAT_ERR) - printk(KERN_ERR DRV_NAME "%s: DMA error\n", dev->name); + printk(KERN_ERR "%s: DMA error\n", dev->name); retval = IRQ_HANDLED; } else @@ -555,7 +555,7 @@ static void korina_tx(struct net_device *dev) dev->stats.tx_dropped++; /* Should never happen */ - printk(KERN_ERR DRV_NAME "%s: split tx ignored\n", + printk(KERN_ERR "%s: split tx ignored\n", dev->name); } else if (devcs & ETH_TX_TOK) { dev->stats.tx_packets++; @@ -641,7 +641,7 @@ korina_tx_dma_interrupt(int irq, void *dev_id) dev->trans_start = jiffies; } if (dmas & DMA_STAT_ERR) - printk(KERN_ERR DRV_NAME "%s: DMA error\n", dev->name); + printk(KERN_ERR "%s: DMA error\n", dev->name); retval = IRQ_HANDLED; } else @@ -917,8 +917,7 @@ static int korina_restart(struct net_device *dev) ret = korina_init(dev); if (ret < 0) { - printk(KERN_ERR DRV_NAME "%s: cannot restart device\n", - dev->name); + printk(KERN_ERR "%s: cannot restart device\n", dev->name); return ret; } korina_multicast_list(dev); @@ -1005,7 +1004,7 @@ static int korina_open(struct net_device *dev) /* Initialize */ ret = korina_init(dev); if (ret < 0) { - printk(KERN_ERR DRV_NAME "%s: cannot open device\n", dev->name); + printk(KERN_ERR "%s: cannot open device\n", dev->name); goto out; } @@ -1015,14 +1014,14 @@ static int korina_open(struct net_device *dev) ret = request_irq(lp->rx_irq, &korina_rx_dma_interrupt, IRQF_DISABLED, "Korina ethernet Rx", dev); if (ret < 0) { - printk(KERN_ERR DRV_NAME "%s: unable to get Rx DMA IRQ %d\n", + printk(KERN_ERR "%s: unable to get Rx DMA IRQ %d\n", dev->name, lp->rx_irq); goto err_release; } ret = request_irq(lp->tx_irq, &korina_tx_dma_interrupt, IRQF_DISABLED, "Korina ethernet Tx", dev); if (ret < 0) { - printk(KERN_ERR DRV_NAME "%s: unable to get Tx DMA IRQ %d\n", + printk(KERN_ERR "%s: unable to get Tx DMA IRQ %d\n", dev->name, lp->tx_irq); goto err_free_rx_irq; } @@ -1031,7 +1030,7 @@ static int korina_open(struct net_device *dev) ret = request_irq(lp->ovr_irq, &korina_ovr_interrupt, IRQF_DISABLED, "Ethernet Overflow", dev); if (ret < 0) { - printk(KERN_ERR DRV_NAME"%s: unable to get OVR IRQ %d\n", + printk(KERN_ERR "%s: unable to get OVR IRQ %d\n", dev->name, lp->ovr_irq); goto err_free_tx_irq; } @@ -1040,7 +1039,7 @@ static int korina_open(struct net_device *dev) ret = request_irq(lp->und_irq, &korina_und_interrupt, IRQF_DISABLED, "Ethernet Underflow", dev); if (ret < 0) { - printk(KERN_ERR DRV_NAME "%s: unable to get UND IRQ %d\n", + printk(KERN_ERR "%s: unable to get UND IRQ %d\n", dev->name, lp->und_irq); goto err_free_ovr_irq; } @@ -1137,7 +1136,7 @@ static int korina_probe(struct platform_device *pdev) dev->base_addr = r->start; lp->eth_regs = ioremap_nocache(r->start, r->end - r->start); if (!lp->eth_regs) { - printk(KERN_ERR DRV_NAME "cannot remap registers\n"); + printk(KERN_ERR DRV_NAME ": cannot remap registers\n"); rc = -ENXIO; goto probe_err_out; } @@ -1145,7 +1144,7 @@ static int korina_probe(struct platform_device *pdev) r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "korina_dma_rx"); lp->rx_dma_regs = ioremap_nocache(r->start, r->end - r->start); if (!lp->rx_dma_regs) { - printk(KERN_ERR DRV_NAME "cannot remap Rx DMA registers\n"); + printk(KERN_ERR DRV_NAME ": cannot remap Rx DMA registers\n"); rc = -ENXIO; goto probe_err_dma_rx; } @@ -1153,14 +1152,14 @@ static int korina_probe(struct platform_device *pdev) r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "korina_dma_tx"); lp->tx_dma_regs = ioremap_nocache(r->start, r->end - r->start); if (!lp->tx_dma_regs) { - printk(KERN_ERR DRV_NAME "cannot remap Tx DMA registers\n"); + printk(KERN_ERR DRV_NAME ": cannot remap Tx DMA registers\n"); rc = -ENXIO; goto probe_err_dma_tx; } lp->td_ring = kmalloc(TD_RING_SIZE + RD_RING_SIZE, GFP_KERNEL); if (!lp->td_ring) { - printk(KERN_ERR DRV_NAME "cannot allocate descriptors\n"); + printk(KERN_ERR DRV_NAME ": cannot allocate descriptors\n"); rc = -ENXIO; goto probe_err_td_ring; } @@ -1193,10 +1192,13 @@ static int korina_probe(struct platform_device *pdev) rc = register_netdev(dev); if (rc < 0) { printk(KERN_ERR DRV_NAME - ": cannot register net device %d\n", rc); + ": cannot register net device: %d\n", rc); goto probe_err_register; } setup_timer(&lp->media_check_timer, korina_poll_media, (unsigned long) dev); + + printk(KERN_INFO "%s: " DRV_NAME "-" DRV_VERSION " " DRV_RELDATE "\n", + dev->name); out: return rc; -- cgit v1.2.3-18-g5258 From 7010837a44813711b66d9e82e90f9641464e515d Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 12 Aug 2009 12:52:32 +0000 Subject: korina: add error-handling to korina_alloc_ring This also avoids a potential buffer overflow in case the very first receive descriptor fails to allocate, as an index of -1 would be used afterwards. Kudos to Roel Kluin for pointing this out and providing an initial patch. Signed-off-by: Phil Sutter Signed-off-by: David S. Miller --- drivers/net/korina.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/korina.c b/drivers/net/korina.c index 6df9d253cc0..51ca54c8ec5 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c @@ -750,7 +750,7 @@ static struct ethtool_ops netdev_ethtool_ops = { .get_link = netdev_get_link, }; -static void korina_alloc_ring(struct net_device *dev) +static int korina_alloc_ring(struct net_device *dev) { struct korina_private *lp = netdev_priv(dev); struct sk_buff *skb; @@ -771,7 +771,7 @@ static void korina_alloc_ring(struct net_device *dev) for (i = 0; i < KORINA_NUM_RDS; i++) { skb = dev_alloc_skb(KORINA_RBSIZE + 2); if (!skb) - break; + return -ENOMEM; skb_reserve(skb, 2); lp->rx_skb[i] = skb; lp->rd_ring[i].control = DMA_DESC_IOD | @@ -790,6 +790,8 @@ static void korina_alloc_ring(struct net_device *dev) lp->rx_chain_head = 0; lp->rx_chain_tail = 0; lp->rx_chain_status = desc_empty; + + return 0; } static void korina_free_ring(struct net_device *dev) @@ -832,7 +834,11 @@ static int korina_init(struct net_device *dev) writel(ETH_INT_FC_EN, &lp->eth_regs->ethintfc); /* Allocate rings */ - korina_alloc_ring(dev); + if (korina_alloc_ring(dev)) { + printk(KERN_ERR "%s: descriptor allocation failed\n", dev->name); + korina_free_ring(dev); + return -ENOMEM; + } writel(0, &lp->rx_dma_regs->dmas); /* Start Rx DMA */ -- cgit v1.2.3-18-g5258 From 1e5053b7635c6a985a7cd8108e538883d961de2a Mon Sep 17 00:00:00 2001 From: Wan ZongShun Date: Sun, 9 Aug 2009 03:06:19 +0000 Subject: Add support for w90p910 mac driver I fixed up my mac driver, which relatives to previous mac driver actually in the tree. Signed-off-by: Wan ZongShun Signed-off-by: David S. Miller --- drivers/net/arm/w90p910_ether.c | 206 ++++++++++++++++++++++------------------ 1 file changed, 112 insertions(+), 94 deletions(-) (limited to 'drivers') diff --git a/drivers/net/arm/w90p910_ether.c b/drivers/net/arm/w90p910_ether.c index 616fb7985a3..890716f6c01 100644 --- a/drivers/net/arm/w90p910_ether.c +++ b/drivers/net/arm/w90p910_ether.c @@ -143,16 +143,17 @@ struct recv_pdesc { struct tran_pdesc { struct w90p910_txbd desclist[TX_DESC_SIZE]; - char tran_buf[RX_DESC_SIZE][MAX_TBUFF_SZ]; + char tran_buf[TX_DESC_SIZE][MAX_TBUFF_SZ]; }; struct w90p910_ether { struct recv_pdesc *rdesc; - struct recv_pdesc *rdesc_phys; struct tran_pdesc *tdesc; - struct tran_pdesc *tdesc_phys; + dma_addr_t rdesc_phys; + dma_addr_t tdesc_phys; struct net_device_stats stats; struct platform_device *pdev; + struct resource *res; struct sk_buff *skb; struct clk *clk; struct clk *rmiiclk; @@ -169,7 +170,6 @@ struct w90p910_ether { unsigned int start_tx_ptr; unsigned int start_rx_ptr; unsigned int linkflag; - spinlock_t lock; }; static void update_linkspeed_register(struct net_device *dev, @@ -275,59 +275,75 @@ static void w90p910_write_cam(struct net_device *dev, __raw_writel(msw, ether->reg + REG_CAMM_BASE + x * CAM_ENTRY_SIZE); } -static void w90p910_init_desc(struct net_device *dev) +static int w90p910_init_desc(struct net_device *dev) { struct w90p910_ether *ether; - struct w90p910_txbd *tdesc, *tdesc_phys; - struct w90p910_rxbd *rdesc, *rdesc_phys; - unsigned int i, j; + struct w90p910_txbd *tdesc; + struct w90p910_rxbd *rdesc; + struct platform_device *pdev; + unsigned int i; ether = netdev_priv(dev); + pdev = ether->pdev; ether->tdesc = (struct tran_pdesc *) - dma_alloc_coherent(NULL, sizeof(struct tran_pdesc), - (dma_addr_t *) ðer->tdesc_phys, GFP_KERNEL); + dma_alloc_coherent(&pdev->dev, sizeof(struct tran_pdesc), + ðer->tdesc_phys, GFP_KERNEL); + + if (!ether->tdesc) { + dev_err(&pdev->dev, "Failed to allocate memory for tx desc\n"); + return -ENOMEM; + } ether->rdesc = (struct recv_pdesc *) - dma_alloc_coherent(NULL, sizeof(struct recv_pdesc), - (dma_addr_t *) ðer->rdesc_phys, GFP_KERNEL); + dma_alloc_coherent(&pdev->dev, sizeof(struct recv_pdesc), + ðer->rdesc_phys, GFP_KERNEL); + + if (!ether->rdesc) { + dev_err(&pdev->dev, "Failed to allocate memory for rx desc\n"); + dma_free_coherent(&pdev->dev, sizeof(struct tran_pdesc), + ether->tdesc, ether->tdesc_phys); + return -ENOMEM; + } for (i = 0; i < TX_DESC_SIZE; i++) { - tdesc = &(ether->tdesc->desclist[i]); + unsigned int offset; - j = ((i + 1) / TX_DESC_SIZE); + tdesc = &(ether->tdesc->desclist[i]); - if (j != 0) { - tdesc_phys = &(ether->tdesc_phys->desclist[0]); - ether->start_tx_ptr = (unsigned int)tdesc_phys; - tdesc->next = (unsigned int)ether->start_tx_ptr; - } else { - tdesc_phys = &(ether->tdesc_phys->desclist[i+1]); - tdesc->next = (unsigned int)tdesc_phys; - } + if (i == TX_DESC_SIZE - 1) + offset = offsetof(struct tran_pdesc, desclist[0]); + else + offset = offsetof(struct tran_pdesc, desclist[i + 1]); - tdesc->buffer = (unsigned int)ether->tdesc_phys->tran_buf[i]; + tdesc->next = ether->tdesc_phys + offset; + tdesc->buffer = ether->tdesc_phys + + offsetof(struct tran_pdesc, tran_buf[i]); tdesc->sl = 0; tdesc->mode = 0; } + ether->start_tx_ptr = ether->tdesc_phys; + for (i = 0; i < RX_DESC_SIZE; i++) { - rdesc = &(ether->rdesc->desclist[i]); + unsigned int offset; - j = ((i + 1) / RX_DESC_SIZE); + rdesc = &(ether->rdesc->desclist[i]); - if (j != 0) { - rdesc_phys = &(ether->rdesc_phys->desclist[0]); - ether->start_rx_ptr = (unsigned int)rdesc_phys; - rdesc->next = (unsigned int)ether->start_rx_ptr; - } else { - rdesc_phys = &(ether->rdesc_phys->desclist[i+1]); - rdesc->next = (unsigned int)rdesc_phys; - } + if (i == RX_DESC_SIZE - 1) + offset = offsetof(struct recv_pdesc, desclist[0]); + else + offset = offsetof(struct recv_pdesc, desclist[i + 1]); + rdesc->next = ether->rdesc_phys + offset; rdesc->sl = RX_OWEN_DMA; - rdesc->buffer = (unsigned int)ether->rdesc_phys->recv_buf[i]; + rdesc->buffer = ether->rdesc_phys + + offsetof(struct recv_pdesc, recv_buf[i]); } + + ether->start_rx_ptr = ether->rdesc_phys; + + return 0; } static void w90p910_set_fifo_threshold(struct net_device *dev) @@ -456,8 +472,6 @@ static void w90p910_reset_mac(struct net_device *dev) { struct w90p910_ether *ether = netdev_priv(dev); - spin_lock(ðer->lock); - w90p910_enable_tx(dev, 0); w90p910_enable_rx(dev, 0); w90p910_set_fifo_threshold(dev); @@ -486,8 +500,6 @@ static void w90p910_reset_mac(struct net_device *dev) if (netif_queue_stopped(dev)) netif_wake_queue(dev); - - spin_unlock(ðer->lock); } static void w90p910_mdio_write(struct net_device *dev, @@ -541,7 +553,7 @@ static int w90p910_mdio_read(struct net_device *dev, int phy_id, int reg) return data; } -static int set_mac_address(struct net_device *dev, void *addr) +static int w90p910_set_mac_address(struct net_device *dev, void *addr) { struct sockaddr *address = addr; @@ -557,11 +569,14 @@ static int set_mac_address(struct net_device *dev, void *addr) static int w90p910_ether_close(struct net_device *dev) { struct w90p910_ether *ether = netdev_priv(dev); + struct platform_device *pdev; - dma_free_writecombine(NULL, sizeof(struct w90p910_rxbd), - ether->rdesc, (dma_addr_t)ether->rdesc_phys); - dma_free_writecombine(NULL, sizeof(struct w90p910_txbd), - ether->tdesc, (dma_addr_t)ether->tdesc_phys); + pdev = ether->pdev; + + dma_free_coherent(&pdev->dev, sizeof(struct recv_pdesc), + ether->rdesc, ether->rdesc_phys); + dma_free_coherent(&pdev->dev, sizeof(struct tran_pdesc), + ether->tdesc, ether->tdesc_phys); netif_stop_queue(dev); @@ -597,6 +612,7 @@ static int w90p910_send_frame(struct net_device *dev, txbd = ðer->tdesc->desclist[ether->cur_tx]; buffer = ether->tdesc->tran_buf[ether->cur_tx]; + if (length > 1514) { dev_err(&pdev->dev, "send data %d bytes, check it\n", length); length = 1514; @@ -612,7 +628,9 @@ static int w90p910_send_frame(struct net_device *dev, w90p910_trigger_tx(dev); - ether->cur_tx = (ether->cur_tx+1) % TX_DESC_SIZE; + if (++ether->cur_tx >= TX_DESC_SIZE) + ether->cur_tx = 0; + txbd = ðer->tdesc->desclist[ether->cur_tx]; dev->trans_start = jiffies; @@ -632,7 +650,7 @@ static int w90p910_ether_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb_irq(skb); return 0; } - return -1; + return -EAGAIN; } static irqreturn_t w90p910_tx_interrupt(int irq, void *dev_id) @@ -640,27 +658,25 @@ static irqreturn_t w90p910_tx_interrupt(int irq, void *dev_id) struct w90p910_ether *ether; struct w90p910_txbd *txbd; struct platform_device *pdev; - struct tran_pdesc *tran_pdesc; struct net_device *dev; unsigned int cur_entry, entry, status; - dev = (struct net_device *)dev_id; + dev = dev_id; ether = netdev_priv(dev); pdev = ether->pdev; - spin_lock(ðer->lock); - w90p910_get_and_clear_int(dev, &status); cur_entry = __raw_readl(ether->reg + REG_CTXDSA); - tran_pdesc = ether->tdesc_phys; - entry = (unsigned int)(&tran_pdesc->desclist[ether->finish_tx]); + entry = ether->tdesc_phys + + offsetof(struct tran_pdesc, desclist[ether->finish_tx]); while (entry != cur_entry) { txbd = ðer->tdesc->desclist[ether->finish_tx]; - ether->finish_tx = (ether->finish_tx + 1) % TX_DESC_SIZE; + if (++ether->finish_tx >= TX_DESC_SIZE) + ether->finish_tx = 0; if (txbd->sl & TXDS_TXCP) { ether->stats.tx_packets++; @@ -675,20 +691,19 @@ static irqreturn_t w90p910_tx_interrupt(int irq, void *dev_id) if (netif_queue_stopped(dev)) netif_wake_queue(dev); - entry = (unsigned int)(&tran_pdesc->desclist[ether->finish_tx]); + entry = ether->tdesc_phys + + offsetof(struct tran_pdesc, desclist[ether->finish_tx]); } if (status & MISTA_EXDEF) { dev_err(&pdev->dev, "emc defer exceed interrupt\n"); } else if (status & MISTA_TXBERR) { - dev_err(&pdev->dev, "emc bus error interrupt\n"); - w90p910_reset_mac(dev); - } else if (status & MISTA_TDU) { - if (netif_queue_stopped(dev)) - netif_wake_queue(dev); - } - - spin_unlock(ðer->lock); + dev_err(&pdev->dev, "emc bus error interrupt\n"); + w90p910_reset_mac(dev); + } else if (status & MISTA_TDU) { + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + } return IRQ_HANDLED; } @@ -698,20 +713,20 @@ static void netdev_rx(struct net_device *dev) struct w90p910_ether *ether; struct w90p910_rxbd *rxbd; struct platform_device *pdev; - struct recv_pdesc *rdesc_phys; struct sk_buff *skb; unsigned char *data; unsigned int length, status, val, entry; ether = netdev_priv(dev); pdev = ether->pdev; - rdesc_phys = ether->rdesc_phys; rxbd = ðer->rdesc->desclist[ether->cur_rx]; do { val = __raw_readl(ether->reg + REG_CRXDSA); - entry = (unsigned int)&rdesc_phys->desclist[ether->cur_rx]; + + entry = ether->rdesc_phys + + offsetof(struct recv_pdesc, desclist[ether->cur_rx]); if (val == entry) break; @@ -743,22 +758,23 @@ static void netdev_rx(struct net_device *dev) dev_err(&pdev->dev, "rx runt err\n"); ether->stats.rx_length_errors++; } else if (status & RXDS_CRCE) { - dev_err(&pdev->dev, "rx crc err\n"); - ether->stats.rx_crc_errors++; - } - - if (status & RXDS_ALIE) { + dev_err(&pdev->dev, "rx crc err\n"); + ether->stats.rx_crc_errors++; + } else if (status & RXDS_ALIE) { dev_err(&pdev->dev, "rx aligment err\n"); ether->stats.rx_frame_errors++; } else if (status & RXDS_PTLE) { - dev_err(&pdev->dev, "rx longer err\n"); - ether->stats.rx_over_errors++; - } + dev_err(&pdev->dev, "rx longer err\n"); + ether->stats.rx_over_errors++; } + } rxbd->sl = RX_OWEN_DMA; rxbd->reserved = 0x0; - ether->cur_rx = (ether->cur_rx+1) % RX_DESC_SIZE; + + if (++ether->cur_rx >= RX_DESC_SIZE) + ether->cur_rx = 0; + rxbd = ðer->rdesc->desclist[ether->cur_rx]; dev->last_rx = jiffies; @@ -772,28 +788,23 @@ static irqreturn_t w90p910_rx_interrupt(int irq, void *dev_id) struct platform_device *pdev; unsigned int status; - dev = (struct net_device *)dev_id; + dev = dev_id; ether = netdev_priv(dev); pdev = ether->pdev; - spin_lock(ðer->lock); - w90p910_get_and_clear_int(dev, &status); if (status & MISTA_RDU) { netdev_rx(dev); - w90p910_trigger_rx(dev); - spin_unlock(ðer->lock); return IRQ_HANDLED; } else if (status & MISTA_RXBERR) { - dev_err(&pdev->dev, "emc rx bus error\n"); - w90p910_reset_mac(dev); - } + dev_err(&pdev->dev, "emc rx bus error\n"); + w90p910_reset_mac(dev); + } netdev_rx(dev); - spin_unlock(ðer->lock); return IRQ_HANDLED; } @@ -826,6 +837,7 @@ static int w90p910_ether_open(struct net_device *dev) if (request_irq(ether->rxirq, w90p910_rx_interrupt, 0x0, pdev->name, dev)) { dev_err(&pdev->dev, "register irq rx failed\n"); + free_irq(ether->txirq, dev); return -EAGAIN; } @@ -908,7 +920,7 @@ static const struct net_device_ops w90p910_ether_netdev_ops = { .ndo_start_xmit = w90p910_ether_start_xmit, .ndo_get_stats = w90p910_ether_stats, .ndo_set_multicast_list = w90p910_ether_set_multicast_list, - .ndo_set_mac_address = set_mac_address, + .ndo_set_mac_address = w90p910_set_mac_address, .ndo_do_ioctl = w90p910_ether_ioctl, .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = eth_change_mtu, @@ -949,8 +961,6 @@ static int w90p910_ether_setup(struct net_device *dev) get_mac_address(dev); - spin_lock_init(ðer->lock); - ether->cur_tx = 0x0; ether->cur_rx = 0x0; ether->finish_tx = 0x0; @@ -972,30 +982,29 @@ static int __devinit w90p910_ether_probe(struct platform_device *pdev) { struct w90p910_ether *ether; struct net_device *dev; - struct resource *res; int error; dev = alloc_etherdev(sizeof(struct w90p910_ether)); if (!dev) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { + ether = netdev_priv(dev); + + ether->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (ether->res == NULL) { dev_err(&pdev->dev, "failed to get I/O memory\n"); error = -ENXIO; goto failed_free; } - res = request_mem_region(res->start, resource_size(res), pdev->name); - if (res == NULL) { + if (!request_mem_region(ether->res->start, + resource_size(ether->res), pdev->name)) { dev_err(&pdev->dev, "failed to request I/O memory\n"); error = -EBUSY; goto failed_free; } - ether = netdev_priv(dev); - - ether->reg = ioremap(res->start, resource_size(res)); + ether->reg = ioremap(ether->res->start, resource_size(ether->res)); if (ether->reg == NULL) { dev_err(&pdev->dev, "failed to remap I/O memory\n"); error = -ENXIO; @@ -1056,7 +1065,7 @@ failed_free_txirq: failed_free_io: iounmap(ether->reg); failed_free_mem: - release_mem_region(res->start, resource_size(res)); + release_mem_region(ether->res->start, resource_size(ether->res)); failed_free: free_netdev(dev); return error; @@ -1068,10 +1077,19 @@ static int __devexit w90p910_ether_remove(struct platform_device *pdev) struct w90p910_ether *ether = netdev_priv(dev); unregister_netdev(dev); + clk_put(ether->rmiiclk); clk_put(ether->clk); + + iounmap(ether->reg); + release_mem_region(ether->res->start, resource_size(ether->res)); + + free_irq(ether->txirq, dev); + free_irq(ether->rxirq, dev); + del_timer_sync(ðer->check_timer); platform_set_drvdata(pdev, NULL); + free_netdev(dev); return 0; } -- cgit v1.2.3-18-g5258 From e5e2a8fd8358d1b3a2c51c3248edee72e4194703 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 13 Aug 2009 04:11:52 +0000 Subject: bonding: wipe out printk's I did not introduce new lines over 80 chars. I even eliminated some of them. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/bonding/bond_3ad.c | 96 +++++++++++++++++++++------------------- drivers/net/bonding/bond_alb.c | 26 ++++++----- drivers/net/bonding/bond_ipv6.c | 4 +- drivers/net/bonding/bond_main.c | 6 +-- drivers/net/bonding/bond_sysfs.c | 63 +++++++++++++------------- 5 files changed, 102 insertions(+), 93 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index be799d2a8a8..cea5cfe23b7 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -1124,7 +1124,7 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) // detect loopback situation if (!MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->actor_system))) { // INFO_RECEIVED_LOOPBACK_FRAMES - printk(KERN_ERR DRV_NAME ": %s: An illegal loopback occurred on " + pr_err(DRV_NAME ": %s: An illegal loopback occurred on " "adapter (%s). Check the configuration to verify that all " "Adapters are connected to 802.3ad compliant switch ports\n", port->slave->dev->master->name, port->slave->dev->name); @@ -1306,11 +1306,13 @@ static void ad_port_selection_logic(struct port *port) } } if (!curr_port) { // meaning: the port was related to an aggregator but was not on the aggregator port list - printk(KERN_WARNING DRV_NAME ": %s: Warning: Port %d (on %s) was " - "related to aggregator %d but was not on its port list\n", - port->slave->dev->master->name, - port->actor_port_number, port->slave->dev->name, - port->aggregator->aggregator_identifier); + pr_warning(DRV_NAME ": %s: Warning: Port %d (on %s) " + "was related to aggregator %d but was not " + "on its port list\n", + port->slave->dev->master->name, + port->actor_port_number, + port->slave->dev->name, + port->aggregator->aggregator_identifier); } } // search on all aggregators for a suitable aggregator for this port @@ -1379,7 +1381,8 @@ static void ad_port_selection_logic(struct port *port) pr_debug("Port %d joined LAG %d(new LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); } else { - printk(KERN_ERR DRV_NAME ": %s: Port %d (on %s) did not find a suitable aggregator\n", + pr_err(DRV_NAME ": %s: Port %d (on %s) did not find " + "a suitable aggregator\n", port->slave->dev->master->name, port->actor_port_number, port->slave->dev->name); } @@ -1456,10 +1459,10 @@ static struct aggregator *ad_agg_selection_test(struct aggregator *best, break; default: - printk(KERN_WARNING DRV_NAME - ": %s: Impossible agg select mode %d\n", - curr->slave->dev->master->name, - __get_agg_selection_mode(curr->lag_ports)); + pr_warning(DRV_NAME + ": %s: Impossible agg select mode %d\n", + curr->slave->dev->master->name, + __get_agg_selection_mode(curr->lag_ports)); break; } @@ -1562,7 +1565,7 @@ static void ad_agg_selection_logic(struct aggregator *agg) // check if any partner replys if (best->is_individual) { - printk(KERN_WARNING DRV_NAME ": %s: Warning: No 802.3ad" + pr_warning(DRV_NAME ": %s: Warning: No 802.3ad" " response from the link partner for any" " adapters in the bond\n", best->slave->dev->master->name); @@ -1885,7 +1888,8 @@ int bond_3ad_bind_slave(struct slave *slave) struct aggregator *aggregator; if (bond == NULL) { - printk(KERN_ERR DRV_NAME ": %s: The slave %s is not attached to its bond\n", + pr_err(DRV_NAME ": %s: The slave %s is not attached to " + "its bond\n", slave->dev->master->name, slave->dev->name); return -1; } @@ -1961,9 +1965,9 @@ void bond_3ad_unbind_slave(struct slave *slave) // if slave is null, the whole port is not initialized if (!port->slave) { - printk(KERN_WARNING DRV_NAME ": Warning: %s: Trying to " - "unbind an uninitialized port on %s\n", - slave->dev->master->name, slave->dev->name); + pr_warning(DRV_NAME ": Warning: %s: Trying to " + "unbind an uninitialized port on %s\n", + slave->dev->master->name, slave->dev->name); return; } @@ -1994,8 +1998,8 @@ void bond_3ad_unbind_slave(struct slave *slave) pr_debug("Some port(s) related to LAG %d - replaceing with LAG %d\n", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier); if ((new_aggregator->lag_ports == port) && new_aggregator->is_active) { - printk(KERN_INFO DRV_NAME ": %s: Removing an active aggregator\n", - aggregator->slave->dev->master->name); + pr_info(DRV_NAME ": %s: Removing an active aggregator\n", + aggregator->slave->dev->master->name); // select new active aggregator select_new_active_agg = 1; } @@ -2025,17 +2029,17 @@ void bond_3ad_unbind_slave(struct slave *slave) ad_agg_selection_logic(__get_first_agg(port)); } } else { - printk(KERN_WARNING DRV_NAME ": %s: Warning: unbinding aggregator, " - "and could not find a new aggregator for its ports\n", - slave->dev->master->name); + pr_warning(DRV_NAME ": %s: Warning: unbinding aggregator, " + "and could not find a new aggregator for its ports\n", + slave->dev->master->name); } } else { // in case that the only port related to this aggregator is the one we want to remove select_new_active_agg = aggregator->is_active; // clear the aggregator ad_clear_agg(aggregator); if (select_new_active_agg) { - printk(KERN_INFO DRV_NAME ": %s: Removing an active aggregator\n", - slave->dev->master->name); + pr_info(DRV_NAME ": %s: Removing an active aggregator\n", + slave->dev->master->name); // select new active aggregator ad_agg_selection_logic(__get_first_agg(port)); } @@ -2061,8 +2065,8 @@ void bond_3ad_unbind_slave(struct slave *slave) // clear the aggregator ad_clear_agg(temp_aggregator); if (select_new_active_agg) { - printk(KERN_INFO DRV_NAME ": %s: Removing an active aggregator\n", - slave->dev->master->name); + pr_info(DRV_NAME ": %s: Removing an active aggregator\n", + slave->dev->master->name); // select new active aggregator ad_agg_selection_logic(__get_first_agg(port)); } @@ -2110,8 +2114,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work) // select the active aggregator for the bond if ((port = __get_first_port(bond))) { if (!port->slave) { - printk(KERN_WARNING DRV_NAME ": %s: Warning: bond's first port is " - "uninitialized\n", bond->dev->name); + pr_warning(DRV_NAME ": %s: Warning: bond's first port is " + "uninitialized\n", bond->dev->name); goto re_arm; } @@ -2124,8 +2128,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work) // for each port run the state machines for (port = __get_first_port(bond); port; port = __get_next_port(port)) { if (!port->slave) { - printk(KERN_WARNING DRV_NAME ": %s: Warning: Found an uninitialized " - "port\n", bond->dev->name); + pr_warning(DRV_NAME ": %s: Warning: Found an uninitialized " + "port\n", bond->dev->name); goto re_arm; } @@ -2166,8 +2170,9 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u port = &(SLAVE_AD_INFO(slave).port); if (!port->slave) { - printk(KERN_WARNING DRV_NAME ": %s: Warning: port of slave %s is " - "uninitialized\n", slave->dev->name, slave->dev->master->name); + pr_warning(DRV_NAME ": %s: Warning: port of slave %s " + "is uninitialized\n", + slave->dev->name, slave->dev->master->name); return; } @@ -2212,9 +2217,9 @@ void bond_3ad_adapter_speed_changed(struct slave *slave) // if slave is null, the whole port is not initialized if (!port->slave) { - printk(KERN_WARNING DRV_NAME ": Warning: %s: speed " - "changed for uninitialized port on %s\n", - slave->dev->master->name, slave->dev->name); + pr_warning(DRV_NAME ": Warning: %s: speed " + "changed for uninitialized port on %s\n", + slave->dev->master->name, slave->dev->name); return; } @@ -2240,9 +2245,9 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave) // if slave is null, the whole port is not initialized if (!port->slave) { - printk(KERN_WARNING DRV_NAME ": %s: Warning: duplex changed " - "for uninitialized port on %s\n", - slave->dev->master->name, slave->dev->name); + pr_warning(DRV_NAME ": %s: Warning: duplex changed " + "for uninitialized port on %s\n", + slave->dev->master->name, slave->dev->name); return; } @@ -2269,9 +2274,9 @@ void bond_3ad_handle_link_change(struct slave *slave, char link) // if slave is null, the whole port is not initialized if (!port->slave) { - printk(KERN_WARNING DRV_NAME ": Warning: %s: link status changed for " - "uninitialized port on %s\n", - slave->dev->master->name, slave->dev->name); + pr_warning(DRV_NAME ": Warning: %s: link status changed for " + "uninitialized port on %s\n", + slave->dev->master->name, slave->dev->name); return; } @@ -2375,8 +2380,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) } if (bond_3ad_get_active_agg_info(bond, &ad_info)) { - printk(KERN_DEBUG DRV_NAME ": %s: Error: " - "bond_3ad_get_active_agg_info failed\n", dev->name); + pr_debug(DRV_NAME ": %s: Error: " + "bond_3ad_get_active_agg_info failed\n", dev->name); goto out; } @@ -2385,9 +2390,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) if (slaves_in_agg == 0) { /*the aggregator is empty*/ - printk(KERN_DEBUG DRV_NAME ": %s: Error: active " - "aggregator is empty\n", - dev->name); + pr_debug(DRV_NAME ": %s: Error: active aggregator is empty\n", + dev->name); goto out; } @@ -2405,7 +2409,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) } if (slave_agg_no >= 0) { - printk(KERN_ERR DRV_NAME ": %s: Error: Couldn't find a slave to tx on " + pr_err(DRV_NAME ": %s: Error: Couldn't find a slave to tx on " "for aggregator ID %d\n", dev->name, agg_id); goto out; } diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index bf45d200292..2108706d2f0 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -194,7 +194,7 @@ static int tlb_initialize(struct bonding *bond) new_hashtbl = kzalloc(size, GFP_KERNEL); if (!new_hashtbl) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: Failed to allocate TLB hash table\n", bond->dev->name); return -1; @@ -510,7 +510,7 @@ static void rlb_update_client(struct rlb_client_info *client_info) client_info->slave->dev->dev_addr, client_info->mac_dst); if (!skb) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: failed to create an ARP packet\n", client_info->slave->dev->master->name); continue; @@ -521,7 +521,7 @@ static void rlb_update_client(struct rlb_client_info *client_info) if (client_info->tag) { skb = vlan_put_tag(skb, client_info->vlan_id); if (!skb) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: failed to insert VLAN tag\n", client_info->slave->dev->master->name); continue; @@ -605,7 +605,7 @@ static void rlb_req_update_subnet_clients(struct bonding *bond, __be32 src_ip) client_info = &(bond_info->rx_hashtbl[hash_index]); if (!client_info->slave) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: found a client with no channel in " "the client's hash table\n", bond->dev->name); @@ -802,7 +802,7 @@ static int rlb_initialize(struct bonding *bond) new_hashtbl = kmalloc(size, GFP_KERNEL); if (!new_hashtbl) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: Failed to allocate RLB hash table\n", bond->dev->name); return -1; @@ -924,7 +924,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) skb = vlan_put_tag(skb, vlan->vlan_id); if (!skb) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: failed to insert VLAN tag\n", bond->dev->name); continue; @@ -954,7 +954,7 @@ static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw) memcpy(s_addr.sa_data, addr, dev->addr_len); s_addr.sa_family = dev->type; if (dev_set_mac_address(dev, &s_addr)) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: dev_set_mac_address of dev %s failed! ALB " "mode requires that the base driver support setting " "the hw address also when the network device's " @@ -1170,13 +1170,15 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr, bond->alb_info.rlb_enabled); - printk(KERN_WARNING DRV_NAME - ": %s: Warning: the hw address of slave %s is in use by " - "the bond; giving it the hw address of %s\n", - bond->dev->name, slave->dev->name, free_mac_slave->dev->name); + pr_warning(DRV_NAME + ": %s: Warning: the hw address of slave %s is " + "in use by the bond; giving it the hw address " + "of %s\n", + bond->dev->name, slave->dev->name, + free_mac_slave->dev->name); } else if (has_bond_addr) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: the hw address of slave %s is in use by the " "bond; couldn't find a slave with a free hw address to " "give it (this should not have happened)\n", diff --git a/drivers/net/bonding/bond_ipv6.c b/drivers/net/bonding/bond_ipv6.c index 0d73bf5ac5a..83921abae12 100644 --- a/drivers/net/bonding/bond_ipv6.c +++ b/drivers/net/bonding/bond_ipv6.c @@ -79,14 +79,14 @@ static void bond_na_send(struct net_device *slave_dev, ND_OPT_TARGET_LL_ADDR); if (!skb) { - printk(KERN_ERR DRV_NAME ": NA packet allocation failed\n"); + pr_err(DRV_NAME ": NA packet allocation failed\n"); return; } if (vlan_id) { skb = vlan_put_tag(skb, vlan_id); if (!skb) { - printk(KERN_ERR DRV_NAME ": failed to insert VLAN tag\n"); + pr_err(DRV_NAME ": failed to insert VLAN tag\n"); return; } } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 3bf0cc61e92..4798d30c954 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4837,7 +4837,7 @@ static int bond_check_params(struct bond_params *params) } if (bond_mode == BOND_MODE_ALB) { - printk(KERN_NOTICE DRV_NAME + pr_notice(DRV_NAME ": In ALB mode you might experience client " "disconnections upon reconnection of a link if the " "bonding module updelay parameter (%d msec) is " @@ -4961,9 +4961,9 @@ static int bond_check_params(struct bond_params *params) arp_ip_count); for (i = 0; i < arp_ip_count; i++) - printk(" %s", arp_ip_target[i]); + pr_info(" %s", arp_ip_target[i]); - printk("\n"); + pr_info("\n"); } else if (max_bonds) { /* miimon and arp_interval not set, we need one so things diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 55bf34f59bb..6044e12ff9f 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -218,9 +218,8 @@ static ssize_t bonding_store_slaves(struct device *d, /* Quick sanity check -- is the bond interface up? */ if (!(bond->dev->flags & IFF_UP)) { - printk(KERN_WARNING DRV_NAME - ": %s: doing slave updates when interface is down.\n", - bond->dev->name); + pr_warning(DRV_NAME ": %s: doing slave updates when " + "interface is down.\n", bond->dev->name); } /* Note: We can't hold bond->lock here, as bond_create grabs it. */ @@ -778,12 +777,14 @@ static ssize_t bonding_store_downdelay(struct device *d, goto out; } else { if ((new_value % bond->params.miimon) != 0) { - printk(KERN_WARNING DRV_NAME - ": %s: Warning: down delay (%d) is not a multiple " - "of miimon (%d), delay rounded to %d ms\n", - bond->dev->name, new_value, bond->params.miimon, - (new_value / bond->params.miimon) * - bond->params.miimon); + pr_warning(DRV_NAME + ": %s: Warning: down delay (%d) is not a " + "multiple of miimon (%d), delay rounded " + "to %d ms\n", + bond->dev->name, new_value, + bond->params.miimon, + (new_value / bond->params.miimon) * + bond->params.miimon); } bond->params.downdelay = new_value / bond->params.miimon; pr_info(DRV_NAME ": %s: Setting down delay to %d.\n", @@ -838,12 +839,14 @@ static ssize_t bonding_store_updelay(struct device *d, goto out; } else { if ((new_value % bond->params.miimon) != 0) { - printk(KERN_WARNING DRV_NAME - ": %s: Warning: up delay (%d) is not a multiple " - "of miimon (%d), updelay rounded to %d ms\n", - bond->dev->name, new_value, bond->params.miimon, - (new_value / bond->params.miimon) * - bond->params.miimon); + pr_warning(DRV_NAME + ": %s: Warning: up delay (%d) is not a " + "multiple of miimon (%d), updelay rounded " + "to %d ms\n", + bond->dev->name, new_value, + bond->params.miimon, + (new_value / bond->params.miimon) * + bond->params.miimon); } bond->params.updelay = new_value / bond->params.miimon; pr_info(DRV_NAME ": %s: Setting up delay to %d.\n", @@ -1299,9 +1302,9 @@ static ssize_t bonding_store_active_slave(struct device *d, new_active = slave; if (new_active == old_active) { /* do nothing */ - printk(KERN_INFO DRV_NAME - ": %s: %s is already the current active slave.\n", - bond->dev->name, slave->dev->name); + pr_info(DRV_NAME + ": %s: %s is already the current active slave.\n", + bond->dev->name, slave->dev->name); goto out; } else { @@ -1309,17 +1312,17 @@ static ssize_t bonding_store_active_slave(struct device *d, (old_active) && (new_active->link == BOND_LINK_UP) && IS_UP(new_active->dev)) { - printk(KERN_INFO DRV_NAME - ": %s: Setting %s as active slave.\n", - bond->dev->name, slave->dev->name); - bond_change_active_slave(bond, new_active); + pr_info(DRV_NAME + ": %s: Setting %s as active slave.\n", + bond->dev->name, slave->dev->name); + bond_change_active_slave(bond, new_active); } else { - printk(KERN_INFO DRV_NAME - ": %s: Could not set %s as active slave; " - "either %s is down or the link is down.\n", - bond->dev->name, slave->dev->name, - slave->dev->name); + pr_info(DRV_NAME + ": %s: Could not set %s as active slave; " + "either %s is down or the link is down.\n", + bond->dev->name, slave->dev->name, + slave->dev->name); } goto out; } @@ -1537,8 +1540,8 @@ int bond_create_sysfs(void) /* Is someone being kinky and naming a device bonding_master? */ if (__dev_get_by_name(&init_net, class_attr_bonding_masters.attr.name)) - printk(KERN_ERR - "network device named %s already exists in sysfs", + pr_err("network device named %s already " + "exists in sysfs", class_attr_bonding_masters.attr.name); ret = 0; } @@ -1566,7 +1569,7 @@ int bond_create_sysfs_entry(struct bonding *bond) err = sysfs_create_group(&(dev->dev.kobj), &bonding_group); if (err) - printk(KERN_EMERG "eek! didn't create group!\n"); + pr_emerg("eek! didn't create group!\n"); return err; } -- cgit v1.2.3-18-g5258 From a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565c Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Thu, 13 Aug 2009 09:44:51 -0400 Subject: Networking: use CAP_NET_ADMIN when deciding to call request_module The networking code checks CAP_SYS_MODULE before using request_module() to try to load a kernel module. While this seems reasonable it's actually weakening system security since we have to allow CAP_SYS_MODULE for things like /sbin/ip and bluetoothd which need to be able to trigger module loads. CAP_SYS_MODULE actually grants those binaries the ability to directly load any code into the kernel. We should instead be protecting modprobe and the modules on disk, rather than granting random programs the ability to load code directly into the kernel. Instead we are going to gate those networking checks on CAP_NET_ADMIN which still limits them to root but which does not grant those processes the ability to load arbitrary code into the kernel. Signed-off-by: Eric Paris Acked-by: Serge Hallyn Acked-by: Paul Moore Acked-by: David S. Miller Signed-off-by: James Morris --- drivers/staging/comedi/comedi_fops.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 9d7c99394ec..640f65c6ef8 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -1752,12 +1752,12 @@ static int comedi_open(struct inode *inode, struct file *file) mutex_lock(&dev->mutex); if (dev->attached) goto ok; - if (!capable(CAP_SYS_MODULE) && dev->in_request_module) { + if (!capable(CAP_NET_ADMIN) && dev->in_request_module) { DPRINTK("in request module\n"); mutex_unlock(&dev->mutex); return -ENODEV; } - if (capable(CAP_SYS_MODULE) && dev->in_request_module) + if (capable(CAP_NET_ADMIN) && dev->in_request_module) goto ok; dev->in_request_module = 1; @@ -1770,8 +1770,8 @@ static int comedi_open(struct inode *inode, struct file *file) dev->in_request_module = 0; - if (!dev->attached && !capable(CAP_SYS_MODULE)) { - DPRINTK("not attached and not CAP_SYS_MODULE\n"); + if (!dev->attached && !capable(CAP_NET_ADMIN)) { + DPRINTK("not attached and not CAP_NET_ADMIN\n"); mutex_unlock(&dev->mutex); return -ENODEV; } -- cgit v1.2.3-18-g5258 From e30eb4ab45211c2f27b6bb9b29124ac431e01ce9 Mon Sep 17 00:00:00 2001 From: Joerg Albert Date: Wed, 5 Aug 2009 01:52:07 +0200 Subject: ath5k: fix missing output in monitor mode after ifconfig up Let ath5k_chan_set() always call ath5k_reset(). This fixes the bug that we don't get any packets in monitor mode after: ifconfig wlan0 down iwconfig wlan0 mode monitor channel 1 ifconfig wlan0 up but they arrive after iwconfig wlan0 channel 2 Signed-off-by: Joerg Albert Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 3a1c156d275..5d5028538ac 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1071,10 +1071,9 @@ ath5k_setup_bands(struct ieee80211_hw *hw) } /* - * Set/change channels. If the channel is really being changed, - * it's done by reseting the chip. To accomplish this we must - * first cleanup any pending DMA, then restart stuff after a la - * ath5k_init. + * Set/change channels. We always reset the chip. + * To accomplish this we must first cleanup any pending DMA, + * then restart stuff after a la ath5k_init. * * Called with sc->lock. */ @@ -1084,19 +1083,13 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "(%u MHz) -> (%u MHz)\n", sc->curchan->center_freq, chan->center_freq); - if (chan->center_freq != sc->curchan->center_freq || - chan->hw_value != sc->curchan->hw_value) { - - /* - * To switch channels clear any pending DMA operations; - * wait long enough for the RX fifo to drain, reset the - * hardware at the new frequency, and then re-enable - * the relevant bits of the h/w. - */ - return ath5k_reset(sc, chan); - } - - return 0; + /* + * To switch channels clear any pending DMA operations; + * wait long enough for the RX fifo to drain, reset the + * hardware at the new frequency, and then re-enable + * the relevant bits of the h/w. + */ + return ath5k_reset(sc, chan); } static void @@ -2811,9 +2804,11 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&sc->lock); - ret = ath5k_chan_set(sc, conf->channel); - if (ret < 0) - goto unlock; + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + ret = ath5k_chan_set(sc, conf->channel); + if (ret < 0) + goto unlock; + } if ((changed & IEEE80211_CONF_CHANGE_POWER) && (sc->power_level != conf->power_level)) { -- cgit v1.2.3-18-g5258 From 63b08b8d97a2a5ff23436cd52e8cd70c1de0319c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 4 Aug 2009 10:05:30 -0700 Subject: ath9k: use new FIF_PSPOLL configure filter We used to set pspoll filter on ath9k on AP mode but we no longer need this mode specific check as mac80211 now does the check for us and informs us when we should enable pspoll through FIF_PSPOLL. Cc: Igor Perminov Cc: Jouni Malinen Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 61edfab20ff..6b07cedf5b7 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -448,8 +448,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) else rfilt |= ATH9K_RX_FILTER_BEACON; - /* If in HOSTAP mode, want to enable reception of PSPOLL frames */ - if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) + if (sc->rx.rxfilter & FIF_PSPOLL) rfilt |= ATH9K_RX_FILTER_PSPOLL; if (sc->sec_wiphy) { -- cgit v1.2.3-18-g5258 From 14b46c8a87f835f4327afa32fad2a523a8fe584d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 4 Aug 2009 14:04:17 -0700 Subject: zd1211rw: make it clear we don't use leds.h LED stuff zd1211rw uses its own LED stuff so let rename its LED stuff as such. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_chip.c | 6 +++--- drivers/net/wireless/zd1211rw/zd_chip.h | 6 +++--- drivers/net/wireless/zd1211rw/zd_mac.c | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 2c813d87092..5e110a2328a 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -1278,11 +1278,11 @@ int zd_chip_control_leds(struct zd_chip *chip, enum led_status status) other_led = chip->link_led == LED1 ? LED2 : LED1; switch (status) { - case LED_OFF: + case ZD_LED_OFF: ioreqs[0].value = FW_LINK_OFF; ioreqs[1].value = v[1] & ~(LED1|LED2); break; - case LED_SCANNING: + case ZD_LED_SCANNING: ioreqs[0].value = FW_LINK_OFF; ioreqs[1].value = v[1] & ~other_led; if (get_seconds() % 3 == 0) { @@ -1291,7 +1291,7 @@ int zd_chip_control_leds(struct zd_chip *chip, enum led_status status) ioreqs[1].value |= chip->link_led; } break; - case LED_ASSOCIATED: + case ZD_LED_ASSOCIATED: ioreqs[0].value = FW_LINK_TX; ioreqs[1].value = v[1] & ~other_led; ioreqs[1].value |= chip->link_led; diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index ee42751d5cb..678c139a840 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -897,9 +897,9 @@ int zd_chip_lock_phy_regs(struct zd_chip *chip); int zd_chip_unlock_phy_regs(struct zd_chip *chip); enum led_status { - LED_OFF = 0, - LED_SCANNING = 1, - LED_ASSOCIATED = 2, + ZD_LED_OFF = 0, + ZD_LED_SCANNING = 1, + ZD_LED_ASSOCIATED = 2, }; int zd_chip_control_leds(struct zd_chip *chip, enum led_status status); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 54abdd0c004..55b7fbdc85d 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -1013,7 +1013,7 @@ static void link_led_handler(struct work_struct *work) spin_unlock_irq(&mac->lock); r = zd_chip_control_leds(chip, - is_associated ? LED_ASSOCIATED : LED_SCANNING); + is_associated ? ZD_LED_ASSOCIATED : ZD_LED_SCANNING); if (r) dev_dbg_f(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r); @@ -1038,5 +1038,5 @@ static void housekeeping_disable(struct zd_mac *mac) dev_dbg_f(zd_mac_dev(mac), "\n"); cancel_rearming_delayed_workqueue(zd_workqueue, &mac->housekeeping.link_led_work); - zd_chip_control_leds(&mac->chip, LED_OFF); + zd_chip_control_leds(&mac->chip, ZD_LED_OFF); } -- cgit v1.2.3-18-g5258 From c10e47f458653a68b1d3956237b7bf2e1ab1e8da Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Tue, 4 Aug 2009 23:57:32 +0200 Subject: b43: Add LP 2063 radio init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add B2063 radio init code and tables for LP-PHY. Rename structures common between B2062 and B2063 to B206X. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 13 +- drivers/net/wireless/b43/tables_lpphy.c | 428 ++++++++++++++++++++++++++++---- drivers/net/wireless/b43/tables_lpphy.h | 1 + 3 files changed, 386 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index aa1486a1354..184fdaf3221 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -333,7 +333,17 @@ static void lpphy_2062_init(struct b43_wldev *dev) /* Initialize the 2063 radio. */ static void lpphy_2063_init(struct b43_wldev *dev) { - //TODO + b2063_upload_init_table(dev); + b43_radio_write(dev, B2063_LOGEN_SP5, 0); + b43_radio_set(dev, B2063_COMM8, 0x38); + b43_radio_write(dev, B2063_REG_SP1, 0x56); + b43_radio_mask(dev, B2063_RX_BB_CTL2, ~0x2); + b43_radio_write(dev, B2063_PA_SP7, 0); + b43_radio_write(dev, B2063_TX_RF_SP6, 0x20); + b43_radio_write(dev, B2063_TX_RF_SP9, 0x40); + b43_radio_write(dev, B2063_PA_SP3, 0xa0); + b43_radio_write(dev, B2063_PA_SP4, 0xa0); + b43_radio_write(dev, B2063_PA_SP2, 0x18); } static void lpphy_sync_stx(struct b43_wldev *dev) @@ -533,6 +543,7 @@ static void lpphy_tx_pctl_init(struct b43_wldev *dev) static int b43_lpphy_op_init(struct b43_wldev *dev) { /* TODO: band SPROM */ + /* TODO: tables init */ lpphy_baseband_init(dev); lpphy_radio_init(dev); //TODO calibrate RC diff --git a/drivers/net/wireless/b43/tables_lpphy.c b/drivers/net/wireless/b43/tables_lpphy.c index 4ea734dce21..cadfe81fd09 100644 --- a/drivers/net/wireless/b43/tables_lpphy.c +++ b/drivers/net/wireless/b43/tables_lpphy.c @@ -28,22 +28,22 @@ #include "phy_lp.h" -/* Entry of the 2062 radio init table */ -struct b2062_init_tab_entry { +/* Entry of the 2062/2063 radio init table */ +struct b206x_init_tab_entry { u16 offset; u16 value_a; u16 value_g; u8 flags; }; -#define B2062_FLAG_A 0x01 /* Flag: Init in A mode */ -#define B2062_FLAG_G 0x02 /* Flag: Init in G mode */ +#define B206X_FLAG_A 0x01 /* Flag: Init in A mode */ +#define B206X_FLAG_G 0x02 /* Flag: Init in G mode */ -static const struct b2062_init_tab_entry b2062_init_tab[] = { +static const struct b206x_init_tab_entry b2062_init_tab[] = { /* { .offset = B2062_N_COMM1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = 0x0001, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_COMM2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_COMM3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_N_COMM4, .value_a = 0x0001, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_N_COMM4, .value_a = 0x0001, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_N_COMM5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_COMM6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_COMM7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ @@ -56,42 +56,42 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { /* { .offset = B2062_N_COMM14, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_COMM15, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_PDN_CTL0, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_N_PDN_CTL1, .value_a = 0x0000, .value_g = 0x00CA, .flags = B2062_FLAG_G, }, + { .offset = B2062_N_PDN_CTL1, .value_a = 0x0000, .value_g = 0x00CA, .flags = B206X_FLAG_G, }, /* { .offset = B2062_N_PDN_CTL2, .value_a = 0x0018, .value_g = 0x0018, .flags = 0, }, */ - { .offset = B2062_N_PDN_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_N_PDN_CTL4, .value_a = 0x0015, .value_g = 0x002A, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_N_PDN_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_N_PDN_CTL4, .value_a = 0x0015, .value_g = 0x002A, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_N_GEN_CTL0, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_IQ_CALIB, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ - { .offset = B2062_N_LGENC, .value_a = 0x00DB, .value_g = 0x00FF, .flags = B2062_FLAG_A, }, + { .offset = B2062_N_LGENC, .value_a = 0x00DB, .value_g = 0x00FF, .flags = B206X_FLAG_A, }, /* { .offset = B2062_N_LGENA_LPF, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ /* { .offset = B2062_N_LGENA_BIAS0, .value_a = 0x0041, .value_g = 0x0041, .flags = 0, }, */ /* { .offset = B2062_N_LGNEA_BIAS1, .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */ /* { .offset = B2062_N_LGENA_CTL0, .value_a = 0x0032, .value_g = 0x0032, .flags = 0, }, */ /* { .offset = B2062_N_LGENA_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_LGENA_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_N_LGENA_TUNE0, .value_a = 0x00DD, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_N_LGENA_TUNE0, .value_a = 0x00DD, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_N_LGENA_TUNE1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_N_LGENA_TUNE2, .value_a = 0x00DD, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_N_LGENA_TUNE3, .value_a = 0x0077, .value_g = 0x00B5, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_N_LGENA_CTL3, .value_a = 0x0000, .value_g = 0x00FF, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_N_LGENA_TUNE2, .value_a = 0x00DD, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_N_LGENA_TUNE3, .value_a = 0x0077, .value_g = 0x00B5, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_N_LGENA_CTL3, .value_a = 0x0000, .value_g = 0x00FF, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_N_LGENA_CTL4, .value_a = 0x001F, .value_g = 0x001F, .flags = 0, }, */ /* { .offset = B2062_N_LGENA_CTL5, .value_a = 0x0032, .value_g = 0x0032, .flags = 0, }, */ /* { .offset = B2062_N_LGENA_CTL6, .value_a = 0x0032, .value_g = 0x0032, .flags = 0, }, */ - { .offset = B2062_N_LGENA_CTL7, .value_a = 0x0033, .value_g = 0x0033, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_N_LGENA_CTL7, .value_a = 0x0033, .value_g = 0x0033, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_N_RXA_CTL0, .value_a = 0x0009, .value_g = 0x0009, .flags = 0, }, */ - { .offset = B2062_N_RXA_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = B2062_FLAG_G, }, + { .offset = B2062_N_RXA_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, /* { .offset = B2062_N_RXA_CTL2, .value_a = 0x0018, .value_g = 0x0018, .flags = 0, }, */ /* { .offset = B2062_N_RXA_CTL3, .value_a = 0x0027, .value_g = 0x0027, .flags = 0, }, */ /* { .offset = B2062_N_RXA_CTL4, .value_a = 0x0028, .value_g = 0x0028, .flags = 0, }, */ /* { .offset = B2062_N_RXA_CTL5, .value_a = 0x0007, .value_g = 0x0007, .flags = 0, }, */ /* { .offset = B2062_N_RXA_CTL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_RXA_CTL7, .value_a = 0x0008, .value_g = 0x0008, .flags = 0, }, */ - { .offset = B2062_N_RXBB_CTL0, .value_a = 0x0082, .value_g = 0x0080, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_N_RXBB_CTL0, .value_a = 0x0082, .value_g = 0x0080, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_N_RXBB_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_RXBB_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_RXBB_GAIN0, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_N_RXBB_GAIN1, .value_a = 0x0004, .value_g = 0x0004, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_N_RXBB_GAIN2, .value_a = 0x0000, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_N_RXBB_GAIN1, .value_a = 0x0004, .value_g = 0x0004, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_N_RXBB_GAIN2, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_N_RXBB_GAIN3, .value_a = 0x0011, .value_g = 0x0011, .flags = 0, }, */ /* { .offset = B2062_N_RXBB_RSSI0, .value_a = 0x0043, .value_g = 0x0043, .flags = 0, }, */ /* { .offset = B2062_N_RXBB_RSSI1, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ @@ -112,8 +112,8 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { /* { .offset = B2062_N_TX_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_TX_CTL2, .value_a = 0x0084, .value_g = 0x0084, .flags = 0, }, */ /* { .offset = B2062_N_TX_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_N_TX_CTL4, .value_a = 0x0003, .value_g = 0x0003, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_N_TX_CTL5, .value_a = 0x0002, .value_g = 0x0002, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_N_TX_CTL4, .value_a = 0x0003, .value_g = 0x0003, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_N_TX_CTL5, .value_a = 0x0002, .value_g = 0x0002, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_N_TX_CTL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_TX_CTL7, .value_a = 0x0058, .value_g = 0x0058, .flags = 0, }, */ /* { .offset = B2062_N_TX_CTL8, .value_a = 0x0082, .value_g = 0x0082, .flags = 0, }, */ @@ -121,7 +121,7 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { /* { .offset = B2062_N_TX_CTL_A, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_N_TX_GC2G, .value_a = 0x00FF, .value_g = 0x00FF, .flags = 0, }, */ /* { .offset = B2062_N_TX_GC5G, .value_a = 0x00FF, .value_g = 0x00FF, .flags = 0, }, */ - { .offset = B2062_N_TX_TUNE, .value_a = 0x0088, .value_g = 0x001B, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_N_TX_TUNE, .value_a = 0x0088, .value_g = 0x001B, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_N_TX_PAD, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ /* { .offset = B2062_N_TX_PGA, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ /* { .offset = B2062_N_TX_PADAUX, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ @@ -150,7 +150,7 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { /* { .offset = B2062_S_RADIO_ID_CODE, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_COMM2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_COMM3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_S_COMM4, .value_a = 0x0001, .value_g = 0x0000, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_COMM4, .value_a = 0x0001, .value_g = 0x0000, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_COMM5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_COMM6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_COMM7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ @@ -162,24 +162,24 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { /* { .offset = B2062_S_COMM13, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_COMM14, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_COMM15, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_S_PDS_CTL0, .value_a = 0x00FF, .value_g = 0x00FF, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_PDS_CTL0, .value_a = 0x00FF, .value_g = 0x00FF, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_PDS_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_PDS_CTL2, .value_a = 0x008E, .value_g = 0x008E, .flags = 0, }, */ /* { .offset = B2062_S_PDS_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_BG_CTL0, .value_a = 0x0006, .value_g = 0x0006, .flags = 0, }, */ /* { .offset = B2062_S_BG_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_BG_CTL2, .value_a = 0x0011, .value_g = 0x0011, .flags = 0, }, */ - { .offset = B2062_S_LGENG_CTL0, .value_a = 0x00F8, .value_g = 0x00D8, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_LGENG_CTL1, .value_a = 0x003C, .value_g = 0x0024, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_LGENG_CTL0, .value_a = 0x00F8, .value_g = 0x00D8, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_LGENG_CTL1, .value_a = 0x003C, .value_g = 0x0024, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_LGENG_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_LGENG_CTL3, .value_a = 0x0041, .value_g = 0x0041, .flags = 0, }, */ /* { .offset = B2062_S_LGENG_CTL4, .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */ /* { .offset = B2062_S_LGENG_CTL5, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ /* { .offset = B2062_S_LGENG_CTL6, .value_a = 0x0022, .value_g = 0x0022, .flags = 0, }, */ /* { .offset = B2062_S_LGENG_CTL7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_S_LGENG_CTL8, .value_a = 0x0088, .value_g = 0x0080, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_LGENG_CTL8, .value_a = 0x0088, .value_g = 0x0080, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_LGENG_CTL9, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ - { .offset = B2062_S_LGENG_CTL10, .value_a = 0x0088, .value_g = 0x0080, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_LGENG_CTL10, .value_a = 0x0088, .value_g = 0x0080, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_LGENG_CTL11, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_REFPLL_CTL0, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_REFPLL_CTL1, .value_a = 0x0007, .value_g = 0x0007, .flags = 0, }, */ @@ -198,41 +198,41 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { /* { .offset = B2062_S_REFPLL_CTL14, .value_a = 0x0075, .value_g = 0x0075, .flags = 0, }, */ /* { .offset = B2062_S_REFPLL_CTL15, .value_a = 0x00B4, .value_g = 0x00B4, .flags = 0, }, */ /* { .offset = B2062_S_REFPLL_CTL16, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_S_RFPLL_CTL0, .value_a = 0x0098, .value_g = 0x0098, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL1, .value_a = 0x0010, .value_g = 0x0010, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL0, .value_a = 0x0098, .value_g = 0x0098, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL1, .value_a = 0x0010, .value_g = 0x0010, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_RFPLL_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_RFPLL_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_RFPLL_CTL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_S_RFPLL_CTL5, .value_a = 0x0043, .value_g = 0x0043, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL6, .value_a = 0x0047, .value_g = 0x0047, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL7, .value_a = 0x000C, .value_g = 0x000C, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL8, .value_a = 0x0011, .value_g = 0x0011, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL9, .value_a = 0x0011, .value_g = 0x0011, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL10, .value_a = 0x000E, .value_g = 0x000E, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL11, .value_a = 0x0008, .value_g = 0x0008, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL12, .value_a = 0x0033, .value_g = 0x0033, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL13, .value_a = 0x000A, .value_g = 0x000A, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL14, .value_a = 0x0006, .value_g = 0x0006, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL5, .value_a = 0x0043, .value_g = 0x0043, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL6, .value_a = 0x0047, .value_g = 0x0047, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL7, .value_a = 0x000C, .value_g = 0x000C, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL8, .value_a = 0x0011, .value_g = 0x0011, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL9, .value_a = 0x0011, .value_g = 0x0011, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL10, .value_a = 0x000E, .value_g = 0x000E, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL11, .value_a = 0x0008, .value_g = 0x0008, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL12, .value_a = 0x0033, .value_g = 0x0033, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL13, .value_a = 0x000A, .value_g = 0x000A, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL14, .value_a = 0x0006, .value_g = 0x0006, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_RFPLL_CTL15, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_RFPLL_CTL16, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_RFPLL_CTL17, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_S_RFPLL_CTL18, .value_a = 0x003E, .value_g = 0x003E, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL19, .value_a = 0x0013, .value_g = 0x0013, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL18, .value_a = 0x003E, .value_g = 0x003E, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL19, .value_a = 0x0013, .value_g = 0x0013, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_RFPLL_CTL20, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_S_RFPLL_CTL21, .value_a = 0x0062, .value_g = 0x0062, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL22, .value_a = 0x0007, .value_g = 0x0007, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL23, .value_a = 0x0016, .value_g = 0x0016, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL24, .value_a = 0x005C, .value_g = 0x005C, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL25, .value_a = 0x0095, .value_g = 0x0095, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL21, .value_a = 0x0062, .value_g = 0x0062, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL22, .value_a = 0x0007, .value_g = 0x0007, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL23, .value_a = 0x0016, .value_g = 0x0016, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL24, .value_a = 0x005C, .value_g = 0x005C, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL25, .value_a = 0x0095, .value_g = 0x0095, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_RFPLL_CTL26, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_RFPLL_CTL27, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_RFPLL_CTL28, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_RFPLL_CTL29, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_S_RFPLL_CTL30, .value_a = 0x00A0, .value_g = 0x00A0, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL31, .value_a = 0x0004, .value_g = 0x0004, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL30, .value_a = 0x00A0, .value_g = 0x00A0, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL31, .value_a = 0x0004, .value_g = 0x0004, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_RFPLL_CTL32, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ - { .offset = B2062_S_RFPLL_CTL33, .value_a = 0x00CC, .value_g = 0x00CC, .flags = B2062_FLAG_A | B2062_FLAG_G, }, - { .offset = B2062_S_RFPLL_CTL34, .value_a = 0x0007, .value_g = 0x0007, .flags = B2062_FLAG_A | B2062_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL33, .value_a = 0x00CC, .value_g = 0x00CC, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2062_S_RFPLL_CTL34, .value_a = 0x0007, .value_g = 0x0007, .flags = B206X_FLAG_A | B206X_FLAG_G, }, /* { .offset = B2062_S_RXG_CNT0, .value_a = 0x0010, .value_g = 0x0010, .flags = 0, }, */ /* { .offset = B2062_S_RXG_CNT1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_RXG_CNT2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ @@ -241,7 +241,7 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { /* { .offset = B2062_S_RXG_CNT5, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ /* { .offset = B2062_S_RXG_CNT6, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ /* { .offset = B2062_S_RXG_CNT7, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ - { .offset = B2062_S_RXG_CNT8, .value_a = 0x000F, .value_g = 0x000F, .flags = B2062_FLAG_A, }, + { .offset = B2062_S_RXG_CNT8, .value_a = 0x000F, .value_g = 0x000F, .flags = B206X_FLAG_A, }, /* { .offset = B2062_S_RXG_CNT9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ /* { .offset = B2062_S_RXG_CNT10, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ /* { .offset = B2062_S_RXG_CNT11, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ @@ -253,19 +253,337 @@ static const struct b2062_init_tab_entry b2062_init_tab[] = { /* { .offset = B2062_S_RXG_CNT17, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ }; +static const struct b206x_init_tab_entry b2063_init_tab[] = { + { .offset = B2063_COMM1, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, + /* { .offset = B2063_COMM2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_COMM3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_COMM4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_COMM5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_COMM6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_COMM7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_COMM8, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_COMM9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_COMM10, .value_a = 0x0001, .value_g = 0x0000, .flags = B206X_FLAG_A, }, + /* { .offset = B2063_COMM11, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_COMM12, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_COMM13, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_COMM14, .value_a = 0x0006, .value_g = 0x0006, .flags = 0, }, */ + /* { .offset = B2063_COMM15, .value_a = 0x000f, .value_g = 0x000f, .flags = 0, }, */ + { .offset = B2063_COMM16, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, + { .offset = B2063_COMM17, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, + { .offset = B2063_COMM18, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, + { .offset = B2063_COMM19, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, + { .offset = B2063_COMM20, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, + { .offset = B2063_COMM21, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, + { .offset = B2063_COMM22, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, + { .offset = B2063_COMM23, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, + { .offset = B2063_COMM24, .value_a = 0x0000, .value_g = 0x0000, .flags = B206X_FLAG_G, }, + /* { .offset = B2063_PWR_SWITCH_CTL, .value_a = 0x007f, .value_g = 0x007f, .flags = 0, }, */ + /* { .offset = B2063_PLL_SP1, .value_a = 0x003f, .value_g = 0x003f, .flags = 0, }, */ + /* { .offset = B2063_PLL_SP2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_LOGEN_SP1, .value_a = 0x00e8, .value_g = 0x00d4, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2063_LOGEN_SP2, .value_a = 0x00a7, .value_g = 0x0053, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_LOGEN_SP3, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ + { .offset = B2063_LOGEN_SP4, .value_a = 0x00f0, .value_g = 0x000f, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_LOGEN_SP5, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ + { .offset = B2063_G_RX_SP1, .value_a = 0x001f, .value_g = 0x005e, .flags = B206X_FLAG_G, }, + { .offset = B2063_G_RX_SP2, .value_a = 0x007f, .value_g = 0x007e, .flags = B206X_FLAG_G, }, + { .offset = B2063_G_RX_SP3, .value_a = 0x0030, .value_g = 0x00f0, .flags = B206X_FLAG_G, }, + /* { .offset = B2063_G_RX_SP4, .value_a = 0x0035, .value_g = 0x0035, .flags = 0, }, */ + /* { .offset = B2063_G_RX_SP5, .value_a = 0x003f, .value_g = 0x003f, .flags = 0, }, */ + /* { .offset = B2063_G_RX_SP6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_G_RX_SP7, .value_a = 0x007f, .value_g = 0x007f, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_G_RX_SP8, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_SP9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_G_RX_SP10, .value_a = 0x000c, .value_g = 0x000c, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_G_RX_SP11, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_A_RX_SP1, .value_a = 0x003c, .value_g = 0x003f, .flags = B206X_FLAG_A, }, + { .offset = B2063_A_RX_SP2, .value_a = 0x00fc, .value_g = 0x00fe, .flags = B206X_FLAG_A, }, + /* { .offset = B2063_A_RX_SP3, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ + /* { .offset = B2063_A_RX_SP4, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ + /* { .offset = B2063_A_RX_SP5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_SP6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_A_RX_SP7, .value_a = 0x0008, .value_g = 0x0008, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_RX_BB_SP1, .value_a = 0x000f, .value_g = 0x000f, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_SP2, .value_a = 0x0022, .value_g = 0x0022, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_SP3, .value_a = 0x00a8, .value_g = 0x00a8, .flags = 0, }, */ + { .offset = B2063_RX_BB_SP4, .value_a = 0x0060, .value_g = 0x0060, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_RX_BB_SP5, .value_a = 0x0011, .value_g = 0x0011, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_SP6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_SP7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_RX_BB_SP8, .value_a = 0x0030, .value_g = 0x0030, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_TX_RF_SP1, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP2, .value_a = 0x0003, .value_g = 0x0003, .flags = 0, }, */ + { .offset = B2063_TX_RF_SP3, .value_a = 0x000c, .value_g = 0x000b, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2063_TX_RF_SP4, .value_a = 0x0010, .value_g = 0x000f, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_TX_RF_SP5, .value_a = 0x000f, .value_g = 0x000f, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP6, .value_a = 0x0080, .value_g = 0x0080, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP7, .value_a = 0x0068, .value_g = 0x0068, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP8, .value_a = 0x0068, .value_g = 0x0068, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP9, .value_a = 0x0080, .value_g = 0x0080, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP10, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP11, .value_a = 0x0003, .value_g = 0x0003, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP12, .value_a = 0x0038, .value_g = 0x0038, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP13, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP14, .value_a = 0x0038, .value_g = 0x0038, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP15, .value_a = 0x00c0, .value_g = 0x00c0, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP16, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_SP17, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ + { .offset = B2063_PA_SP1, .value_a = 0x003d, .value_g = 0x00fd, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_PA_SP2, .value_a = 0x000c, .value_g = 0x000c, .flags = 0, }, */ + /* { .offset = B2063_PA_SP3, .value_a = 0x0096, .value_g = 0x0096, .flags = 0, }, */ + /* { .offset = B2063_PA_SP4, .value_a = 0x005a, .value_g = 0x005a, .flags = 0, }, */ + /* { .offset = B2063_PA_SP5, .value_a = 0x007f, .value_g = 0x007f, .flags = 0, }, */ + /* { .offset = B2063_PA_SP6, .value_a = 0x007f, .value_g = 0x007f, .flags = 0, }, */ + /* { .offset = B2063_PA_SP7, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ + { .offset = B2063_TX_BB_SP1, .value_a = 0x0002, .value_g = 0x0002, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_TX_BB_SP2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_TX_BB_SP3, .value_a = 0x0030, .value_g = 0x0030, .flags = 0, }, */ + /* { .offset = B2063_REG_SP1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_BANDGAP_CTL1, .value_a = 0x0056, .value_g = 0x0056, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_BANDGAP_CTL2, .value_a = 0x0006, .value_g = 0x0006, .flags = 0, }, */ + /* { .offset = B2063_LPO_CTL1, .value_a = 0x000e, .value_g = 0x000e, .flags = 0, }, */ + /* { .offset = B2063_RC_CALIB_CTL1, .value_a = 0x007e, .value_g = 0x007e, .flags = 0, }, */ + /* { .offset = B2063_RC_CALIB_CTL2, .value_a = 0x0015, .value_g = 0x0015, .flags = 0, }, */ + /* { .offset = B2063_RC_CALIB_CTL3, .value_a = 0x000f, .value_g = 0x000f, .flags = 0, }, */ + /* { .offset = B2063_RC_CALIB_CTL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_RC_CALIB_CTL5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_RC_CALIB_CTL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_RC_CALIB_CTL7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_RC_CALIB_CTL8, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_RC_CALIB_CTL9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_RC_CALIB_CTL10, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_CALNRST, .value_a = 0x0004, .value_g = 0x0004, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_IN_PLL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_IN_PLL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_CP1, .value_a = 0x00cf, .value_g = 0x00cf, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_CP2, .value_a = 0x0059, .value_g = 0x0059, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_CP3, .value_a = 0x0007, .value_g = 0x0007, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_CP4, .value_a = 0x0042, .value_g = 0x0042, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_LF1, .value_a = 0x00db, .value_g = 0x00db, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_LF2, .value_a = 0x0094, .value_g = 0x0094, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_LF3, .value_a = 0x0028, .value_g = 0x0028, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_LF4, .value_a = 0x0063, .value_g = 0x0063, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_SG1, .value_a = 0x0007, .value_g = 0x0007, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_SG2, .value_a = 0x00d3, .value_g = 0x00d3, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_SG3, .value_a = 0x00b1, .value_g = 0x00b1, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_SG4, .value_a = 0x003b, .value_g = 0x003b, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_SG5, .value_a = 0x0006, .value_g = 0x0006, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_VCO1, .value_a = 0x0058, .value_g = 0x0058, .flags = 0, }, */ + { .offset = B2063_PLL_JTAG_PLL_VCO2, .value_a = 0x00f7, .value_g = 0x00f7, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB3, .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB5, .value_a = 0x0009, .value_g = 0x0009, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB6, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB7, .value_a = 0x0016, .value_g = 0x0016, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB8, .value_a = 0x006b, .value_g = 0x006b, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_VCO_CALIB10, .value_a = 0x00b3, .value_g = 0x00b3, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_XTAL_12, .value_a = 0x0004, .value_g = 0x0004, .flags = 0, }, */ + /* { .offset = B2063_PLL_JTAG_PLL_XTAL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_ACL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_ACL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_ACL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_ACL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_ACL5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_INPUTS, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_WAITCNT, .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_OVR1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_OVR2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_OVAL1, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_OVAL2, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_OVAL3, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_OVAL4, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_OVAL5, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_OVAL6, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_OVAL7, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CALVLD1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CALVLD2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CVAL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CVAL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CVAL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CVAL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CVAL5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CVAL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LO_CALIB_CVAL7, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_CALIB_EN, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_PEAKDET1, .value_a = 0x00ff, .value_g = 0x00ff, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_RCCR1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_VCOBUF1, .value_a = 0x0060, .value_g = 0x0060, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_MIXER1, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_MIXER2, .value_a = 0x000c, .value_g = 0x000c, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_BUF1, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_BUF2, .value_a = 0x000c, .value_g = 0x000c, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_DIV1, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_DIV2, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_DIV3, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_CBUFRX1, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_CBUFRX2, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_CBUFTX1, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_CBUFTX2, .value_a = 0x0066, .value_g = 0x0066, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_IDAC1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_SPARE1, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_SPARE2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_LOGEN_SPARE3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_1ST1, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ + /* { .offset = B2063_G_RX_1ST2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_1ST3, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ + /* { .offset = B2063_G_RX_2ND1, .value_a = 0x0030, .value_g = 0x0030, .flags = 0, }, */ + /* { .offset = B2063_G_RX_2ND2, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ + /* { .offset = B2063_G_RX_2ND3, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ + /* { .offset = B2063_G_RX_2ND4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_2ND5, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ + /* { .offset = B2063_G_RX_2ND6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_2ND7, .value_a = 0x0035, .value_g = 0x0035, .flags = 0, }, */ + /* { .offset = B2063_G_RX_2ND8, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_PS1, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ + /* { .offset = B2063_G_RX_PS2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_PS3, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ + /* { .offset = B2063_G_RX_PS4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_PS5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_MIX1, .value_a = 0x0044, .value_g = 0x0044, .flags = 0, }, */ + /* { .offset = B2063_G_RX_MIX2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_G_RX_MIX3, .value_a = 0x0071, .value_g = 0x0071, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2063_G_RX_MIX4, .value_a = 0x0071, .value_g = 0x0071, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_G_RX_MIX5, .value_a = 0x0003, .value_g = 0x0003, .flags = 0, }, */ + /* { .offset = B2063_G_RX_MIX6, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ + /* { .offset = B2063_G_RX_MIX7, .value_a = 0x0044, .value_g = 0x0044, .flags = 0, }, */ + /* { .offset = B2063_G_RX_MIX8, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ + /* { .offset = B2063_G_RX_PDET1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_SPARES1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_SPARES2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_G_RX_SPARES3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_1ST1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_A_RX_1ST2, .value_a = 0x00f0, .value_g = 0x0030, .flags = B206X_FLAG_A, }, + /* { .offset = B2063_A_RX_1ST3, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ + /* { .offset = B2063_A_RX_1ST4, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ + /* { .offset = B2063_A_RX_1ST5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_2ND1, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ + /* { .offset = B2063_A_RX_2ND2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_2ND3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_2ND4, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ + /* { .offset = B2063_A_RX_2ND5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_2ND6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_2ND7, .value_a = 0x0005, .value_g = 0x0005, .flags = 0, }, */ + /* { .offset = B2063_A_RX_PS1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_PS2, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ + /* { .offset = B2063_A_RX_PS3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_PS4, .value_a = 0x0033, .value_g = 0x0033, .flags = 0, }, */ + /* { .offset = B2063_A_RX_PS5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_A_RX_PS6, .value_a = 0x0077, .value_g = 0x0077, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_A_RX_MIX1, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ + /* { .offset = B2063_A_RX_MIX2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_MIX3, .value_a = 0x0044, .value_g = 0x0044, .flags = 0, }, */ + { .offset = B2063_A_RX_MIX4, .value_a = 0x0003, .value_g = 0x0003, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2063_A_RX_MIX5, .value_a = 0x000f, .value_g = 0x000f, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + { .offset = B2063_A_RX_MIX6, .value_a = 0x000f, .value_g = 0x000f, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_A_RX_MIX7, .value_a = 0x0044, .value_g = 0x0044, .flags = 0, }, */ + /* { .offset = B2063_A_RX_MIX8, .value_a = 0x0001, .value_g = 0x0001, .flags = 0, }, */ + /* { .offset = B2063_A_RX_PWRDET1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_SPARE1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_SPARE2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_A_RX_SPARE3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_RX_TIA_CTL1, .value_a = 0x0077, .value_g = 0x0077, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_RX_TIA_CTL2, .value_a = 0x0058, .value_g = 0x0058, .flags = 0, }, */ + { .offset = B2063_RX_TIA_CTL3, .value_a = 0x0077, .value_g = 0x0077, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_RX_TIA_CTL4, .value_a = 0x0058, .value_g = 0x0058, .flags = 0, }, */ + /* { .offset = B2063_RX_TIA_CTL5, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_RX_TIA_CTL6, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_CTL1, .value_a = 0x0074, .value_g = 0x0074, .flags = 0, }, */ + { .offset = B2063_RX_BB_CTL2, .value_a = 0x0004, .value_g = 0x0004, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_RX_BB_CTL3, .value_a = 0x00a2, .value_g = 0x00a2, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_CTL4, .value_a = 0x00aa, .value_g = 0x00aa, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_CTL5, .value_a = 0x0024, .value_g = 0x0024, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_CTL6, .value_a = 0x00a9, .value_g = 0x00a9, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_CTL7, .value_a = 0x0028, .value_g = 0x0028, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_CTL8, .value_a = 0x0010, .value_g = 0x0010, .flags = 0, }, */ + /* { .offset = B2063_RX_BB_CTL9, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL1, .value_a = 0x0080, .value_g = 0x0080, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_IDAC_LO_RF_I, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_IDAC_LO_RF_Q, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_IDAC_LO_BB_I, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_IDAC_LO_BB_Q, .value_a = 0x0088, .value_g = 0x0088, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL2, .value_a = 0x0080, .value_g = 0x0080, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL3, .value_a = 0x0038, .value_g = 0x0038, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL4, .value_a = 0x00b8, .value_g = 0x00b8, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL5, .value_a = 0x0080, .value_g = 0x0080, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL6, .value_a = 0x0038, .value_g = 0x0038, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL7, .value_a = 0x0078, .value_g = 0x0078, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL8, .value_a = 0x00c0, .value_g = 0x00c0, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL9, .value_a = 0x0003, .value_g = 0x0003, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL10, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL14, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_TX_RF_CTL15, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_PA_CTL1, .value_a = 0x0000, .value_g = 0x0004, .flags = B206X_FLAG_A, }, + /* { .offset = B2063_PA_CTL2, .value_a = 0x000c, .value_g = 0x000c, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL3, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL4, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL5, .value_a = 0x0096, .value_g = 0x0096, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL6, .value_a = 0x0077, .value_g = 0x0077, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL7, .value_a = 0x005a, .value_g = 0x005a, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL8, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL9, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL10, .value_a = 0x0021, .value_g = 0x0021, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL11, .value_a = 0x0070, .value_g = 0x0070, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL12, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_PA_CTL13, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_TX_BB_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_TX_BB_CTL2, .value_a = 0x00b3, .value_g = 0x00b3, .flags = 0, }, */ + /* { .offset = B2063_TX_BB_CTL3, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ + /* { .offset = B2063_TX_BB_CTL4, .value_a = 0x000b, .value_g = 0x000b, .flags = 0, }, */ + /* { .offset = B2063_GPIO_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + { .offset = B2063_VREG_CTL1, .value_a = 0x0003, .value_g = 0x0003, .flags = B206X_FLAG_A | B206X_FLAG_G, }, + /* { .offset = B2063_AMUX_CTL1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_IQ_CALIB_GVAR, .value_a = 0x00b3, .value_g = 0x00b3, .flags = 0, }, */ + /* { .offset = B2063_IQ_CALIB_CTL1, .value_a = 0x0055, .value_g = 0x0055, .flags = 0, }, */ + /* { .offset = B2063_IQ_CALIB_CTL2, .value_a = 0x0030, .value_g = 0x0030, .flags = 0, }, */ + /* { .offset = B2063_TEMPSENSE_CTL1, .value_a = 0x0046, .value_g = 0x0046, .flags = 0, }, */ + /* { .offset = B2063_TEMPSENSE_CTL2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_TX_RX_LOOPBACK1, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_TX_RX_LOOPBACK2, .value_a = 0x0000, .value_g = 0x0000, .flags = 0, }, */ + /* { .offset = B2063_EXT_TSSI_CTL1, .value_a = 0x0021, .value_g = 0x0021, .flags = 0, }, */ + /* { .offset = B2063_EXT_TSSI_CTL2, .value_a = 0x0023, .value_g = 0x0023, .flags = 0, }, */ + /* { .offset = B2063_AFE_CTL , .value_a = 0x0002, .value_g = 0x0002, .flags = 0, }, */ +}; + void b2062_upload_init_table(struct b43_wldev *dev) { - const struct b2062_init_tab_entry *e; + const struct b206x_init_tab_entry *e; unsigned int i; for (i = 0; i < ARRAY_SIZE(b2062_init_tab); i++) { e = &b2062_init_tab[i]; if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { - if (!(e->flags & B2062_FLAG_G)) + if (!(e->flags & B206X_FLAG_G)) + continue; + b43_radio_write(dev, e->offset, e->value_g); + } else { + if (!(e->flags & B206X_FLAG_A)) + continue; + b43_radio_write(dev, e->offset, e->value_a); + } + } +} + +void b2063_upload_init_table(struct b43_wldev *dev) +{ + const struct b206x_init_tab_entry *e; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(b2063_init_tab); i++) { + e = &b2063_init_tab[i]; + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + if (!(e->flags & B206X_FLAG_G)) continue; b43_radio_write(dev, e->offset, e->value_g); } else { - if (!(e->flags & B2062_FLAG_A)) + if (!(e->flags & B206X_FLAG_A)) continue; b43_radio_write(dev, e->offset, e->value_a); } diff --git a/drivers/net/wireless/b43/tables_lpphy.h b/drivers/net/wireless/b43/tables_lpphy.h index 0b8d02895a5..52ce32ff43a 100644 --- a/drivers/net/wireless/b43/tables_lpphy.h +++ b/drivers/net/wireless/b43/tables_lpphy.h @@ -26,6 +26,7 @@ void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset, unsigned int nr_elements, const void *data); void b2062_upload_init_table(struct b43_wldev *dev); +void b2063_upload_init_table(struct b43_wldev *dev); #endif /* B43_TABLES_LPPHY_H_ */ -- cgit v1.2.3-18-g5258 From 7c81e98a60cc525e21a6d86cb4357a626f530699 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Wed, 5 Aug 2009 00:25:42 +0200 Subject: b43: Typo fixes & minor cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make use of HostFlags defines in the LP-PHY code. Fix fallout from the IEEE80211_IF_TYPE to NL80211_IFTYPE change. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 2 +- drivers/net/wireless/b43/phy_lp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index b6811cff18b..d57ee9bd429 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -639,7 +639,7 @@ struct b43_wl { u8 mac_addr[ETH_ALEN]; /* Current BSSID */ u8 bssid[ETH_ALEN]; - /* Interface type. (IEEE80211_IF_TYPE_XXX) */ + /* Interface type. (NL80211_IFTYPE_XXX) */ int if_type; /* Is the card operating in AP, STA or IBSS mode? */ bool operating; diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 184fdaf3221..ed3a5288613 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -130,7 +130,7 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0006); b43_phy_write(dev, B43_LPPHY_GPIO_SELECT, 0x0005); b43_phy_write(dev, B43_LPPHY_GPIO_OUTEN, 0xFFFF); - b43_hf_write(dev, b43_hf_read(dev) | 0x0800ULL << 32); + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_PR45960W); } if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x8000); -- cgit v1.2.3-18-g5258 From c45fa8c50c2149eec260a55c84e76339a2a761dd Mon Sep 17 00:00:00 2001 From: gregor kowski Date: Wed, 5 Aug 2009 00:44:23 +0200 Subject: b43: remove wrong probe_resp_plcp write The tkip hw support uncovered a bug in b43_write_probe_resp_template : it is writing at the wrong shm offset, it is in the B43_SHM_SH_TKIPTSCTTAK zone. Remove b43_write_probe_resp_template, b43_write_probe_resp_plcp and b43_write_probe_resp_plcp because the probe response offload is currently not supported by mac80211. Signed-off-by: Gregor Kowski Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 114 ---------------------------------------- 1 file changed, 114 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 925f346ea36..997dd55b63f 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1429,116 +1429,6 @@ static void b43_write_beacon_template(struct b43_wldev *dev, b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset); } -static void b43_write_probe_resp_plcp(struct b43_wldev *dev, - u16 shm_offset, u16 size, - struct ieee80211_rate *rate) -{ - struct b43_plcp_hdr4 plcp; - u32 tmp; - __le16 dur; - - plcp.data = 0; - b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value); - dur = ieee80211_generic_frame_duration(dev->wl->hw, - dev->wl->vif, size, - rate); - /* Write PLCP in two parts and timing for packet transfer */ - tmp = le32_to_cpu(plcp.data); - b43_shm_write16(dev, B43_SHM_SHARED, shm_offset, tmp & 0xFFFF); - b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 2, tmp >> 16); - b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 6, le16_to_cpu(dur)); -} - -/* Instead of using custom probe response template, this function - * just patches custom beacon template by: - * 1) Changing packet type - * 2) Patching duration field - * 3) Stripping TIM - */ -static const u8 *b43_generate_probe_resp(struct b43_wldev *dev, - u16 *dest_size, - struct ieee80211_rate *rate) -{ - const u8 *src_data; - u8 *dest_data; - u16 src_size, elem_size, src_pos, dest_pos; - __le16 dur; - struct ieee80211_hdr *hdr; - size_t ie_start; - - src_size = dev->wl->current_beacon->len; - src_data = (const u8 *)dev->wl->current_beacon->data; - - /* Get the start offset of the variable IEs in the packet. */ - ie_start = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - B43_WARN_ON(ie_start != offsetof(struct ieee80211_mgmt, u.beacon.variable)); - - if (B43_WARN_ON(src_size < ie_start)) - return NULL; - - dest_data = kmalloc(src_size, GFP_ATOMIC); - if (unlikely(!dest_data)) - return NULL; - - /* Copy the static data and all Information Elements, except the TIM. */ - memcpy(dest_data, src_data, ie_start); - src_pos = ie_start; - dest_pos = ie_start; - for ( ; src_pos < src_size - 2; src_pos += elem_size) { - elem_size = src_data[src_pos + 1] + 2; - if (src_data[src_pos] == 5) { - /* This is the TIM. */ - continue; - } - memcpy(dest_data + dest_pos, src_data + src_pos, - elem_size); - dest_pos += elem_size; - } - *dest_size = dest_pos; - hdr = (struct ieee80211_hdr *)dest_data; - - /* Set the frame control. */ - hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_PROBE_RESP); - dur = ieee80211_generic_frame_duration(dev->wl->hw, - dev->wl->vif, *dest_size, - rate); - hdr->duration_id = dur; - - return dest_data; -} - -static void b43_write_probe_resp_template(struct b43_wldev *dev, - u16 ram_offset, - u16 shm_size_offset, - struct ieee80211_rate *rate) -{ - const u8 *probe_resp_data; - u16 size; - - size = dev->wl->current_beacon->len; - probe_resp_data = b43_generate_probe_resp(dev, &size, rate); - if (unlikely(!probe_resp_data)) - return; - - /* Looks like PLCP headers plus packet timings are stored for - * all possible basic rates - */ - /* FIXME this is the wrong offset : it goes in tkip rx phase1 shm */ -#if 0 - b43_write_probe_resp_plcp(dev, 0x31A, size, &b43_b_ratetable[0]); - b43_write_probe_resp_plcp(dev, 0x32C, size, &b43_b_ratetable[1]); - b43_write_probe_resp_plcp(dev, 0x33E, size, &b43_b_ratetable[2]); - b43_write_probe_resp_plcp(dev, 0x350, size, &b43_b_ratetable[3]); -#endif - - size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6)); - b43_write_template_common(dev, probe_resp_data, - size, ram_offset, shm_size_offset, - rate->hw_value); - kfree(probe_resp_data); -} - static void b43_upload_beacon0(struct b43_wldev *dev) { struct b43_wl *wl = dev->wl; @@ -1546,10 +1436,6 @@ static void b43_upload_beacon0(struct b43_wldev *dev) if (wl->beacon0_uploaded) return; b43_write_beacon_template(dev, 0x68, 0x18); - /* FIXME: Probe resp upload doesn't really belong here, - * but we don't use that feature anyway. */ - b43_write_probe_resp_template(dev, 0x268, 0x4A, - &__b43_ratetable[3]); wl->beacon0_uploaded = 1; } -- cgit v1.2.3-18-g5258 From bedaf80866f5d438b47d05e02fb1852065fe5d8e Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Wed, 5 Aug 2009 01:28:20 +0200 Subject: b43: Fix fallout from the IEEE80211_IF_TYPE to NL80211_IFTYPE change. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update a comment that still says IEEE80211_IF_TYPE instead of NL80211_IFTYPE. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index d57ee9bd429..102094a2359 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -845,7 +845,7 @@ static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev) return ssb_get_drvdata(ssb_dev); } -/* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */ +/* Is the device operating in a specified mode (NL80211_IFTYPE_XXX). */ static inline int b43_is_mode(struct b43_wl *wl, int type) { return (wl->operating && wl->if_type == type); -- cgit v1.2.3-18-g5258 From bb7e43c061ad1e52a4738d5b45595ec9e1638b6a Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Wed, 5 Aug 2009 21:23:27 +0100 Subject: orinoco: prefer_port3 can be a single bit This is a boolean value set based on firmware capabilities, so move the variable to the capabilities section and reduce the structure size. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/orinoco.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index 5f4f5c9eef7..2a4eef1b96c 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -107,10 +107,10 @@ struct orinoco_private { unsigned int do_fw_download:1; unsigned int broken_disableport:1; unsigned int broken_monitor:1; + unsigned int prefer_port3:1; /* Configuration paramaters */ enum nl80211_iftype iw_mode; - int prefer_port3; u16 encode_alg, wep_restrict, tx_key; struct orinoco_key keys[ORINOCO_MAX_KEYS]; int bitratemode; -- cgit v1.2.3-18-g5258 From 5c9f41e285ad60013f0962746192769f899757be Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Wed, 5 Aug 2009 21:23:28 +0100 Subject: orinoco: use local types for auth alg and sequence length This helps in the refactorring required to convert the driver to cfg80211. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/hw.c | 12 ++++++------ drivers/net/wireless/orinoco/main.c | 6 +++--- drivers/net/wireless/orinoco/orinoco.h | 10 +++++++++- drivers/net/wireless/orinoco/wext.c | 30 +++++++++++++++--------------- 4 files changed, 33 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index fa508af1a35..d069fe8b603 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -642,7 +642,7 @@ int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc) { hermes_t *hw = &priv->hw; int err = 0; - u8 tsc_arr[4][IW_ENCODE_SEQ_MAX_SIZE]; + u8 tsc_arr[4][ORINOCO_SEQ_LEN]; if ((key < 0) || (key > 4)) return -EINVAL; @@ -840,14 +840,14 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) if (priv->wpa_enabled) enc_flag = 2; - else if (priv->encode_alg == IW_ENCODE_ALG_WEP) + else if (priv->encode_alg == ORINOCO_ALG_WEP) enc_flag = 1; else enc_flag = 0; switch (priv->firmware_type) { case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ - if (priv->encode_alg == IW_ENCODE_ALG_WEP) { + if (priv->encode_alg == ORINOCO_ALG_WEP) { /* Enable the shared-key authentication. */ err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFAUTHENTICATION_AGERE, @@ -872,7 +872,7 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ - if (priv->encode_alg == IW_ENCODE_ALG_WEP) { + if (priv->encode_alg == ORINOCO_ALG_WEP) { if (priv->wep_restrict || (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)) master_wep_flag = HERMES_WEP_PRIVACY_INVOKED | @@ -913,11 +913,11 @@ int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, { struct { __le16 idx; - u8 rsc[IW_ENCODE_SEQ_MAX_SIZE]; + u8 rsc[ORINOCO_SEQ_LEN]; u8 key[TKIP_KEYLEN]; u8 tx_mic[MIC_KEYLEN]; u8 rx_mic[MIC_KEYLEN]; - u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; + u8 tsc[ORINOCO_SEQ_LEN]; } __attribute__ ((packed)) buf; hermes_t *hw = &priv->hw; int ret; diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index e8c550a61f3..931f7deddb5 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -380,7 +380,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX; - if (priv->encode_alg == IW_ENCODE_ALG_TKIP) + if (priv->encode_alg == ORINOCO_ALG_TKIP) tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) | HERMES_TXCTRL_MIC; @@ -462,7 +462,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) } /* Calculate Michael MIC */ - if (priv->encode_alg == IW_ENCODE_ALG_TKIP) { + if (priv->encode_alg == ORINOCO_ALG_TKIP) { u8 mic_buf[MICHAEL_MIC_LEN + 1]; u8 *mic; size_t offset; @@ -2040,7 +2040,7 @@ int orinoco_init(struct orinoco_private *priv) priv->channel = 0; /* use firmware default */ priv->promiscuous = 0; - priv->encode_alg = IW_ENCODE_ALG_NONE; + priv->encode_alg = ORINOCO_ALG_NONE; priv->tx_key = 0; priv->wpa_enabled = 0; priv->tkip_cm_active = 0; diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index 2a4eef1b96c..badfc566524 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -25,6 +25,7 @@ #define MAX_SCAN_LEN 4096 +#define ORINOCO_SEQ_LEN 8 #define ORINOCO_MAX_KEY_SIZE 14 #define ORINOCO_MAX_KEYS 4 @@ -42,6 +43,12 @@ struct orinoco_tkip_key { u8 rx_mic[MIC_KEYLEN]; }; +enum orinoco_alg { + ORINOCO_ALG_NONE, + ORINOCO_ALG_WEP, + ORINOCO_ALG_TKIP +}; + typedef enum { FIRMWARE_TYPE_AGERE, FIRMWARE_TYPE_INTERSIL, @@ -111,7 +118,8 @@ struct orinoco_private { /* Configuration paramaters */ enum nl80211_iftype iw_mode; - u16 encode_alg, wep_restrict, tx_key; + enum orinoco_alg encode_alg; + u16 wep_restrict, tx_key; struct orinoco_key keys[ORINOCO_MAX_KEYS]; int bitratemode; char nick[IW_ESSID_MAX_SIZE+1]; diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index b6ff3dbb7dd..33d81b4823a 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -180,7 +180,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct orinoco_private *priv = ndev_priv(dev); int index = (erq->flags & IW_ENCODE_INDEX) - 1; int setindex = priv->tx_key; - int encode_alg = priv->encode_alg; + enum orinoco_alg encode_alg = priv->encode_alg; int restricted = priv->wep_restrict; u16 xlen = 0; int err = -EINPROGRESS; /* Call commit handler */ @@ -202,7 +202,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, return -EBUSY; /* Clear any TKIP key we have */ - if ((priv->has_wpa) && (priv->encode_alg == IW_ENCODE_ALG_TKIP)) + if ((priv->has_wpa) && (priv->encode_alg == ORINOCO_ALG_TKIP)) (void) orinoco_clear_tkip_key(priv, setindex); if (erq->length > 0) { @@ -212,15 +212,13 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, /* Adjust key length to a supported value */ if (erq->length > SMALL_KEY_SIZE) xlen = LARGE_KEY_SIZE; - else if (erq->length > 0) + else /* (erq->length > 0) */ xlen = SMALL_KEY_SIZE; - else - xlen = 0; /* Switch on WEP if off */ - if ((encode_alg != IW_ENCODE_ALG_WEP) && (xlen > 0)) { + if (encode_alg != ORINOCO_ALG_WEP) { setindex = index; - encode_alg = IW_ENCODE_ALG_WEP; + encode_alg = ORINOCO_ALG_WEP; } } else { /* Important note : if the user do "iwconfig eth0 enc off", @@ -242,7 +240,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, } if (erq->flags & IW_ENCODE_DISABLED) - encode_alg = IW_ENCODE_ALG_NONE; + encode_alg = ORINOCO_ALG_NONE; if (erq->flags & IW_ENCODE_OPEN) restricted = 0; if (erq->flags & IW_ENCODE_RESTRICTED) @@ -825,7 +823,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, /* Set the requested key first */ switch (alg) { case IW_ENCODE_ALG_NONE: - priv->encode_alg = alg; + priv->encode_alg = ORINOCO_ALG_NONE; priv->keys[idx].len = 0; break; @@ -837,7 +835,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, else goto out; - priv->encode_alg = alg; + priv->encode_alg = ORINOCO_ALG_WEP; priv->keys[idx].len = cpu_to_le16(key_len); key_len = min(ext->key_len, key_len); @@ -854,7 +852,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, (ext->key_len > sizeof(priv->tkip_key[0]))) goto out; - priv->encode_alg = alg; + priv->encode_alg = ORINOCO_ALG_TKIP; memset(&priv->tkip_key[idx], 0, sizeof(priv->tkip_key[idx])); memcpy(&priv->tkip_key[idx], ext->key, ext->key_len); @@ -914,19 +912,21 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev, encoding->flags = idx + 1; memset(ext, 0, sizeof(*ext)); - ext->alg = priv->encode_alg; switch (priv->encode_alg) { - case IW_ENCODE_ALG_NONE: + case ORINOCO_ALG_NONE: + ext->alg = IW_ENCODE_ALG_NONE; ext->key_len = 0; encoding->flags |= IW_ENCODE_DISABLED; break; - case IW_ENCODE_ALG_WEP: + case ORINOCO_ALG_WEP: + ext->alg = IW_ENCODE_ALG_WEP; ext->key_len = min_t(u16, le16_to_cpu(priv->keys[idx].len), max_key_len); memcpy(ext->key, priv->keys[idx].data, ext->key_len); encoding->flags |= IW_ENCODE_ENABLED; break; - case IW_ENCODE_ALG_TKIP: + case ORINOCO_ALG_TKIP: + ext->alg = IW_ENCODE_ALG_TKIP; ext->key_len = min_t(u16, sizeof(struct orinoco_tkip_key), max_key_len); memcpy(ext->key, &priv->tkip_key[idx], ext->key_len); -- cgit v1.2.3-18-g5258 From 16e158480d542f3909b5aca8b125af986ae128c1 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Wed, 5 Aug 2009 21:23:29 +0100 Subject: orinoco: pass orinoco_set_tkip_key the sequence lengths When we store the keys for cfg80211, the sequence lengths will also be stored. So avoid assuming the sequence lengths at this level. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/hw.c | 30 ++++++++++++++++++------------ drivers/net/wireless/orinoco/hw.h | 3 ++- drivers/net/wireless/orinoco/wext.c | 2 +- 3 files changed, 21 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index d069fe8b603..35516a9e2a3 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -905,11 +905,12 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) } /* key must be 32 bytes, including the tx and rx MIC keys. - * rsc must be 8 bytes - * tsc must be 8 bytes or NULL + * rsc must be NULL or up to 8 bytes + * tsc must be NULL or up to 8 bytes */ int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, - int set_tx, u8 *key, u8 *rsc, u8 *tsc) + int set_tx, u8 *key, u8 *rsc, size_t rsc_len, + u8 *tsc, size_t tsc_len) { struct { __le16 idx; @@ -934,17 +935,22 @@ int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, memcpy(buf.key, key, sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic)); - if (rsc == NULL) - memset(buf.rsc, 0, sizeof(buf.rsc)); - else - memcpy(buf.rsc, rsc, sizeof(buf.rsc)); + if (rsc_len > sizeof(buf.rsc)) + rsc_len = sizeof(buf.rsc); + + if (tsc_len > sizeof(buf.tsc)) + tsc_len = sizeof(buf.tsc); + + memset(buf.rsc, 0, sizeof(buf.rsc)); + memset(buf.tsc, 0, sizeof(buf.tsc)); + + if (rsc != NULL) + memcpy(buf.rsc, rsc, rsc_len); - if (tsc == NULL) { - memset(buf.tsc, 0, sizeof(buf.tsc)); + if (tsc != NULL) + memcpy(buf.tsc, tsc, tsc_len); + else buf.tsc[4] = 0x10; - } else { - memcpy(buf.tsc, tsc, sizeof(buf.tsc)); - } /* Wait upto 100ms for tx queue to empty */ for (k = 100; k > 0; k--) { diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index 27b427649d1..33a31fa7c62 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h @@ -38,7 +38,8 @@ int __orinoco_hw_set_wap(struct orinoco_private *priv); int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv); int __orinoco_hw_setup_enc(struct orinoco_private *priv); int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, - int set_tx, u8 *key, u8 *rsc, u8 *tsc); + int set_tx, u8 *key, u8 *rsc, size_t rsc_len, + u8 *tsc, size_t tsc_len); int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx); int __orinoco_hw_set_multicast_list(struct orinoco_private *priv, struct dev_addr_list *mc_list, diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 33d81b4823a..7e18bb40493 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -863,7 +863,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, err = __orinoco_hw_set_tkip_key(priv, idx, ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, (u8 *) &priv->tkip_key[idx], - tkip_iv, NULL); + tkip_iv, ORINOCO_SEQ_LEN, NULL, 0); if (err) printk(KERN_ERR "%s: Error %d setting TKIP key" "\n", dev->name, err); -- cgit v1.2.3-18-g5258 From 07542d08ee573b6d8281f38430117b52fccaf50a Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Wed, 5 Aug 2009 21:23:30 +0100 Subject: orinoco: move disassociation to hw.c This allows the disassociation to be called via cfg80211. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/hw.c | 24 ++++++++++++++++++++++++ drivers/net/wireless/orinoco/hw.h | 2 ++ drivers/net/wireless/orinoco/wext.c | 17 ++++------------- 3 files changed, 30 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 35516a9e2a3..3e9021c4778 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -1248,3 +1248,27 @@ int orinoco_hw_trigger_scan(struct orinoco_private *priv, return err; } + +/* Disassociate from node with BSSID addr */ +int orinoco_hw_disassociate(struct orinoco_private *priv, + u8 *addr, u16 reason_code) +{ + hermes_t *hw = &priv->hw; + int err; + + struct { + u8 addr[ETH_ALEN]; + __le16 reason_code; + } __attribute__ ((packed)) buf; + + /* Currently only supported by WPA enabled Agere fw */ + if (!priv->has_wpa) + return -EOPNOTSUPP; + + memcpy(buf.addr, addr, ETH_ALEN); + buf.reason_code = cpu_to_le16(reason_code); + err = HERMES_WRITE_RECORD(hw, USER_BAP, + HERMES_RID_CNFDISASSOCIATE, + &buf); + return err; +} diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index 33a31fa7c62..b096786a93d 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h @@ -51,5 +51,7 @@ int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates, s32 *rates, int max); int orinoco_hw_trigger_scan(struct orinoco_private *priv, const struct cfg80211_ssid *ssid); +int orinoco_hw_disassociate(struct orinoco_private *priv, + u8 *addr, u16 reason_code); #endif /* _ORINOCO_HW_H_ */ diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 7e18bb40493..f324bf919bc 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -1136,7 +1136,6 @@ static int orinoco_ioctl_set_mlme(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct orinoco_private *priv = ndev_priv(dev); - hermes_t *hw = &priv->hw; struct iw_mlme *mlme = (struct iw_mlme *)extra; unsigned long flags; int ret = 0; @@ -1150,19 +1149,11 @@ static int orinoco_ioctl_set_mlme(struct net_device *dev, break; case IW_MLME_DISASSOC: - { - struct { - u8 addr[ETH_ALEN]; - __le16 reason_code; - } __attribute__ ((packed)) buf; - - memcpy(buf.addr, mlme->addr.sa_data, ETH_ALEN); - buf.reason_code = cpu_to_le16(mlme->reason_code); - ret = HERMES_WRITE_RECORD(hw, USER_BAP, - HERMES_RID_CNFDISASSOCIATE, - &buf); + + ret = orinoco_hw_disassociate(priv, mlme->addr.sa_data, + mlme->reason_code); break; - } + default: ret = -EOPNOTSUPP; } -- cgit v1.2.3-18-g5258 From 2b2603515e26466685895e93cae59bc061389f11 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Wed, 5 Aug 2009 21:23:31 +0100 Subject: orinoco: add function to retrieve current bssid We will need this from the cfg80211 disassociate call. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/hw.c | 12 ++++++++++++ drivers/net/wireless/orinoco/hw.h | 2 ++ drivers/net/wireless/orinoco/wext.c | 4 +--- 3 files changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 3e9021c4778..5b126542692 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -1272,3 +1272,15 @@ int orinoco_hw_disassociate(struct orinoco_private *priv, &buf); return err; } + +int orinoco_hw_get_current_bssid(struct orinoco_private *priv, + u8 *addr) +{ + hermes_t *hw = &priv->hw; + int err; + + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, + ETH_ALEN, NULL, addr); + + return err; +} diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index b096786a93d..8df6e8752be 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h @@ -53,5 +53,7 @@ int orinoco_hw_trigger_scan(struct orinoco_private *priv, const struct cfg80211_ssid *ssid); int orinoco_hw_disassociate(struct orinoco_private *priv, u8 *addr, u16 reason_code); +int orinoco_hw_get_current_bssid(struct orinoco_private *priv, + u8 *addr); #endif /* _ORINOCO_HW_H_ */ diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index f324bf919bc..f68bbe383e0 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -156,7 +156,6 @@ static int orinoco_ioctl_getwap(struct net_device *dev, { struct orinoco_private *priv = ndev_priv(dev); - hermes_t *hw = &priv->hw; int err = 0; unsigned long flags; @@ -164,8 +163,7 @@ static int orinoco_ioctl_getwap(struct net_device *dev, return -EBUSY; ap_addr->sa_family = ARPHRD_ETHER; - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, - ETH_ALEN, NULL, ap_addr->sa_data); + err = orinoco_hw_get_current_bssid(priv, ap_addr->sa_data); orinoco_unlock(priv, &flags); -- cgit v1.2.3-18-g5258 From 4af198fb7a99b07980b1bd52df550ba3f24688df Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Wed, 5 Aug 2009 21:23:32 +0100 Subject: orinoco: consolidate storage of WEP and TKIP keys When TKIP support was added, we stored the keys separately to avoid issues when both TKIP and WEP keys are sent to the driver. We need to consolidate the storage to convert to cfg80211, so do this first and try iron out the issues. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/hw.c | 42 +++++++++--- drivers/net/wireless/orinoco/main.c | 33 ++++++--- drivers/net/wireless/orinoco/orinoco.h | 4 +- drivers/net/wireless/orinoco/wext.c | 122 ++++++++++++++++++++++----------- 4 files changed, 139 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 5b126542692..40d8dfa7eac 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -768,12 +768,29 @@ int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) { hermes_t *hw = &priv->hw; int err = 0; + int i; switch (priv->firmware_type) { case FIRMWARE_TYPE_AGERE: + { + struct orinoco_key keys[ORINOCO_MAX_KEYS]; + + memset(&keys, 0, sizeof(keys)); + for (i = 0; i < ORINOCO_MAX_KEYS; i++) { + int len = min(priv->keys[i].key_len, + ORINOCO_MAX_KEY_SIZE); + memcpy(&keys[i].data, priv->keys[i].key, len); + if (len > SMALL_KEY_SIZE) + keys[i].len = cpu_to_le16(LARGE_KEY_SIZE); + else if (len > 0) + keys[i].len = cpu_to_le16(SMALL_KEY_SIZE); + else + keys[i].len = cpu_to_le16(0); + } + err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFWEPKEYS_AGERE, - &priv->keys); + &keys); if (err) return err; err = hermes_write_wordrec(hw, USER_BAP, @@ -782,28 +799,38 @@ int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) if (err) return err; break; + } case FIRMWARE_TYPE_INTERSIL: case FIRMWARE_TYPE_SYMBOL: { int keylen; - int i; /* Force uniform key length to work around * firmware bugs */ - keylen = le16_to_cpu(priv->keys[priv->tx_key].len); + keylen = priv->keys[priv->tx_key].key_len; if (keylen > LARGE_KEY_SIZE) { printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", priv->ndev->name, priv->tx_key, keylen); return -E2BIG; - } + } else if (keylen > SMALL_KEY_SIZE) + keylen = LARGE_KEY_SIZE; + else if (keylen > 0) + keylen = SMALL_KEY_SIZE; + else + keylen = 0; /* Write all 4 keys */ for (i = 0; i < ORINOCO_MAX_KEYS; i++) { + u8 key[LARGE_KEY_SIZE] = { 0 }; + + memcpy(key, priv->keys[i].key, + priv->keys[i].key_len); + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDEFAULTKEY0 + i, HERMES_BYTES_TO_RECLEN(keylen), - priv->keys[i].data); + key); if (err) return err; } @@ -829,8 +856,8 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) int auth_flag; int enc_flag; - /* Setup WEP keys for WEP and WPA */ - if (priv->encode_alg) + /* Setup WEP keys */ + if (priv->encode_alg == ORINOCO_ALG_WEP) __orinoco_hw_setup_wepkeys(priv); if (priv->wep_restrict) @@ -976,7 +1003,6 @@ int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx) hermes_t *hw = &priv->hw; int err; - memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx])); err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE, key_idx); diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 931f7deddb5..2c7dc65cd2b 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -341,12 +341,14 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) { struct orinoco_private *priv = ndev_priv(dev); struct net_device_stats *stats = &priv->stats; + struct orinoco_tkip_key *key; hermes_t *hw = &priv->hw; int err = 0; u16 txfid = priv->txfid; struct ethhdr *eh; int tx_control; unsigned long flags; + int do_mic; if (!netif_running(dev)) { printk(KERN_ERR "%s: Tx on stopped device!\n", @@ -378,9 +380,14 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->len < ETH_HLEN) goto drop; + key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key; + + do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) && + (key != NULL)); + tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX; - if (priv->encode_alg == ORINOCO_ALG_TKIP) + if (do_mic) tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) | HERMES_TXCTRL_MIC; @@ -462,7 +469,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) } /* Calculate Michael MIC */ - if (priv->encode_alg == ORINOCO_ALG_TKIP) { + if (do_mic) { u8 mic_buf[MICHAEL_MIC_LEN + 1]; u8 *mic; size_t offset; @@ -480,8 +487,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) len = MICHAEL_MIC_LEN; } - orinoco_mic(priv->tx_tfm_mic, - priv->tkip_key[priv->tx_key].tx_mic, + orinoco_mic(priv->tx_tfm_mic, key->tx_mic, eh->h_dest, eh->h_source, 0 /* priority */, skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic); @@ -926,6 +932,7 @@ static void orinoco_rx(struct net_device *dev, /* Calculate and check MIC */ if (status & HERMES_RXSTAT_MIC) { + struct orinoco_tkip_key *key; int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >> HERMES_MIC_KEY_ID_SHIFT); u8 mic[MICHAEL_MIC_LEN]; @@ -939,14 +946,18 @@ static void orinoco_rx(struct net_device *dev, skb_trim(skb, skb->len - MICHAEL_MIC_LEN); length -= MICHAEL_MIC_LEN; - orinoco_mic(priv->rx_tfm_mic, - priv->tkip_key[key_id].rx_mic, - desc->addr1, - src, + key = (struct orinoco_tkip_key *) priv->keys[key_id].key; + + if (!key) { + printk(KERN_WARNING "%s: Received encrypted frame from " + "%pM using key %i, but key is not installed\n", + dev->name, src, key_id); + goto drop; + } + + orinoco_mic(priv->rx_tfm_mic, key->rx_mic, desc->addr1, src, 0, /* priority or QoS? */ - skb->data, - skb->len, - &mic[0]); + skb->data, skb->len, &mic[0]); if (memcmp(mic, rxmic, MICHAEL_MIC_LEN)) { diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index badfc566524..9ac6f1dda4b 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -120,7 +120,8 @@ struct orinoco_private { enum nl80211_iftype iw_mode; enum orinoco_alg encode_alg; u16 wep_restrict, tx_key; - struct orinoco_key keys[ORINOCO_MAX_KEYS]; + struct key_params keys[ORINOCO_MAX_KEYS]; + int bitratemode; char nick[IW_ESSID_MAX_SIZE+1]; char desired_essid[IW_ESSID_MAX_SIZE+1]; @@ -150,7 +151,6 @@ struct orinoco_private { u8 *wpa_ie; int wpa_ie_len; - struct orinoco_tkip_key tkip_key[ORINOCO_MAX_KEYS]; struct crypto_hash *rx_tfm_mic; struct crypto_hash *tx_tfm_mic; diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index f68bbe383e0..3e56f7643df 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -22,6 +22,67 @@ #define MAX_RID_LEN 1024 +/* Helper routine to record keys + * Do not call from interrupt context */ +static int orinoco_set_key(struct orinoco_private *priv, int index, + enum orinoco_alg alg, const u8 *key, int key_len, + const u8 *seq, int seq_len) +{ + kzfree(priv->keys[index].key); + kzfree(priv->keys[index].seq); + + if (key_len) { + priv->keys[index].key = kzalloc(key_len, GFP_KERNEL); + if (!priv->keys[index].key) + goto nomem; + } else + priv->keys[index].key = NULL; + + if (seq_len) { + priv->keys[index].seq = kzalloc(seq_len, GFP_KERNEL); + if (!priv->keys[index].seq) + goto free_key; + } else + priv->keys[index].seq = NULL; + + priv->keys[index].key_len = key_len; + priv->keys[index].seq_len = seq_len; + + if (key_len) + memcpy(priv->keys[index].key, key, key_len); + if (seq_len) + memcpy(priv->keys[index].seq, seq, seq_len); + + switch (alg) { + case ORINOCO_ALG_TKIP: + priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP; + break; + + case ORINOCO_ALG_WEP: + priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ? + WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40; + break; + + case ORINOCO_ALG_NONE: + default: + priv->keys[index].cipher = 0; + break; + } + + return 0; + +free_key: + kfree(priv->keys[index].key); + priv->keys[index].key = NULL; + +nomem: + priv->keys[index].key_len = 0; + priv->keys[index].seq_len = 0; + priv->keys[index].cipher = 0; + + return -ENOMEM; +} + static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) { struct orinoco_private *priv = ndev_priv(dev); @@ -180,7 +241,6 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, int setindex = priv->tx_key; enum orinoco_alg encode_alg = priv->encode_alg; int restricted = priv->wep_restrict; - u16 xlen = 0; int err = -EINPROGRESS; /* Call commit handler */ unsigned long flags; @@ -207,12 +267,6 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) index = priv->tx_key; - /* Adjust key length to a supported value */ - if (erq->length > SMALL_KEY_SIZE) - xlen = LARGE_KEY_SIZE; - else /* (erq->length > 0) */ - xlen = SMALL_KEY_SIZE; - /* Switch on WEP if off */ if (encode_alg != ORINOCO_ALG_WEP) { setindex = index; @@ -229,7 +283,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, } } else { /* Set the index : Check that the key is valid */ - if (priv->keys[index].len == 0) { + if (priv->keys[index].key_len == 0) { err = -EINVAL; goto out; } @@ -245,10 +299,8 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, restricted = 1; if (erq->pointer && erq->length > 0) { - priv->keys[index].len = cpu_to_le16(xlen); - memset(priv->keys[index].data, 0, - sizeof(priv->keys[index].data)); - memcpy(priv->keys[index].data, keybuf, erq->length); + err = orinoco_set_key(priv, index, ORINOCO_ALG_WEP, keybuf, + erq->length, NULL, 0); } priv->tx_key = setindex; @@ -277,7 +329,6 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, { struct orinoco_private *priv = ndev_priv(dev); int index = (erq->flags & IW_ENCODE_INDEX) - 1; - u16 xlen = 0; unsigned long flags; if (!priv->has_wep) @@ -299,11 +350,9 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, else erq->flags |= IW_ENCODE_OPEN; - xlen = le16_to_cpu(priv->keys[index].len); + erq->length = priv->keys[index].key_len; - erq->length = xlen; - - memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE); + memcpy(keybuf, priv->keys[index].key, erq->length); orinoco_unlock(priv, &flags); return 0; @@ -789,7 +838,6 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, int idx, alg = ext->alg, set_key = 1; unsigned long flags; int err = -EINVAL; - u16 key_len; if (orinoco_lock(priv, &flags) != 0) return -EBUSY; @@ -822,24 +870,17 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, switch (alg) { case IW_ENCODE_ALG_NONE: priv->encode_alg = ORINOCO_ALG_NONE; - priv->keys[idx].len = 0; + err = orinoco_set_key(priv, idx, ORINOCO_ALG_NONE, + NULL, 0, NULL, 0); break; case IW_ENCODE_ALG_WEP: - if (ext->key_len > SMALL_KEY_SIZE) - key_len = LARGE_KEY_SIZE; - else if (ext->key_len > 0) - key_len = SMALL_KEY_SIZE; - else + if (ext->key_len <= 0) goto out; priv->encode_alg = ORINOCO_ALG_WEP; - priv->keys[idx].len = cpu_to_le16(key_len); - - key_len = min(ext->key_len, key_len); - - memset(priv->keys[idx].data, 0, ORINOCO_MAX_KEY_SIZE); - memcpy(priv->keys[idx].data, ext->key, key_len); + err = orinoco_set_key(priv, idx, ORINOCO_ALG_WEP, + ext->key, ext->key_len, NULL, 0); break; case IW_ENCODE_ALG_TKIP: @@ -847,20 +888,21 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, u8 *tkip_iv = NULL; if (!priv->has_wpa || - (ext->key_len > sizeof(priv->tkip_key[0]))) + (ext->key_len > sizeof(struct orinoco_tkip_key))) goto out; priv->encode_alg = ORINOCO_ALG_TKIP; - memset(&priv->tkip_key[idx], 0, - sizeof(priv->tkip_key[idx])); - memcpy(&priv->tkip_key[idx], ext->key, ext->key_len); if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) tkip_iv = &ext->rx_seq[0]; + err = orinoco_set_key(priv, idx, ORINOCO_ALG_TKIP, + ext->key, ext->key_len, tkip_iv, + ORINOCO_SEQ_LEN); + err = __orinoco_hw_set_tkip_key(priv, idx, ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, - (u8 *) &priv->tkip_key[idx], + priv->keys[idx].key, tkip_iv, ORINOCO_SEQ_LEN, NULL, 0); if (err) printk(KERN_ERR "%s: Error %d setting TKIP key" @@ -918,16 +960,14 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev, break; case ORINOCO_ALG_WEP: ext->alg = IW_ENCODE_ALG_WEP; - ext->key_len = min_t(u16, le16_to_cpu(priv->keys[idx].len), - max_key_len); - memcpy(ext->key, priv->keys[idx].data, ext->key_len); + ext->key_len = min(priv->keys[idx].key_len, max_key_len); + memcpy(ext->key, priv->keys[idx].key, ext->key_len); encoding->flags |= IW_ENCODE_ENABLED; break; case ORINOCO_ALG_TKIP: ext->alg = IW_ENCODE_ALG_TKIP; - ext->key_len = min_t(u16, sizeof(struct orinoco_tkip_key), - max_key_len); - memcpy(ext->key, &priv->tkip_key[idx], ext->key_len); + ext->key_len = min(priv->keys[idx].key_len, max_key_len); + memcpy(ext->key, priv->keys[idx].key, ext->key_len); encoding->flags |= IW_ENCODE_ENABLED; break; } -- cgit v1.2.3-18-g5258 From f5fc0f86b02afef1119b523623b4cde41475bc8c Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 6 Aug 2009 16:25:28 +0300 Subject: wl1271: add wl1271 driver files This driver supports the wl1271 chipset from Texas Instruments based on the WiLink(tm) 6.0 mobile platform. Support for wl1273 should be relatively easy to add. This chipset is designed for embedded devices, with good powersaving capabilities. The wl1271 chipset is the successor of wl1251 and supports the 802.11b/g/n standards, but currently this driver supports only b/g. More information about this chipset can be found here: http://focus.ti.com/general/docs/wtbu/wtbuproductcontent.tsp?templateId=6123&navigationId=12762&contentId=29993 Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 407 ++++++++ drivers/net/wireless/wl12xx/wl1271_acx.c | 961 ++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_acx.h | 1221 ++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_boot.c | 540 ++++++++++ drivers/net/wireless/wl12xx/wl1271_boot.h | 72 ++ drivers/net/wireless/wl12xx/wl1271_cmd.c | 813 +++++++++++++++ drivers/net/wireless/wl12xx/wl1271_cmd.h | 464 +++++++++ drivers/net/wireless/wl12xx/wl1271_debugfs.c | 518 ++++++++++ drivers/net/wireless/wl12xx/wl1271_debugfs.h | 33 + drivers/net/wireless/wl12xx/wl1271_event.c | 125 +++ drivers/net/wireless/wl12xx/wl1271_event.h | 110 ++ drivers/net/wireless/wl12xx/wl1271_init.c | 397 ++++++++ drivers/net/wireless/wl12xx/wl1271_init.h | 115 +++ drivers/net/wireless/wl12xx/wl1271_main.c | 1396 ++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_ps.c | 142 +++ drivers/net/wireless/wl12xx/wl1271_ps.h | 35 + drivers/net/wireless/wl12xx/wl1271_reg.h | 758 ++++++++++++++ drivers/net/wireless/wl12xx/wl1271_rx.c | 200 ++++ drivers/net/wireless/wl12xx/wl1271_rx.h | 121 +++ drivers/net/wireless/wl12xx/wl1271_spi.c | 382 +++++++ drivers/net/wireless/wl12xx/wl1271_spi.h | 113 +++ drivers/net/wireless/wl12xx/wl1271_tx.c | 378 +++++++ drivers/net/wireless/wl12xx/wl1271_tx.h | 130 +++ 23 files changed, 9431 insertions(+) create mode 100644 drivers/net/wireless/wl12xx/wl1271.h create mode 100644 drivers/net/wireless/wl12xx/wl1271_acx.c create mode 100644 drivers/net/wireless/wl12xx/wl1271_acx.h create mode 100644 drivers/net/wireless/wl12xx/wl1271_boot.c create mode 100644 drivers/net/wireless/wl12xx/wl1271_boot.h create mode 100644 drivers/net/wireless/wl12xx/wl1271_cmd.c create mode 100644 drivers/net/wireless/wl12xx/wl1271_cmd.h create mode 100644 drivers/net/wireless/wl12xx/wl1271_debugfs.c create mode 100644 drivers/net/wireless/wl12xx/wl1271_debugfs.h create mode 100644 drivers/net/wireless/wl12xx/wl1271_event.c create mode 100644 drivers/net/wireless/wl12xx/wl1271_event.h create mode 100644 drivers/net/wireless/wl12xx/wl1271_init.c create mode 100644 drivers/net/wireless/wl12xx/wl1271_init.h create mode 100644 drivers/net/wireless/wl12xx/wl1271_main.c create mode 100644 drivers/net/wireless/wl12xx/wl1271_ps.c create mode 100644 drivers/net/wireless/wl12xx/wl1271_ps.h create mode 100644 drivers/net/wireless/wl12xx/wl1271_reg.h create mode 100644 drivers/net/wireless/wl12xx/wl1271_rx.c create mode 100644 drivers/net/wireless/wl12xx/wl1271_rx.h create mode 100644 drivers/net/wireless/wl12xx/wl1271_spi.c create mode 100644 drivers/net/wireless/wl12xx/wl1271_spi.h create mode 100644 drivers/net/wireless/wl12xx/wl1271_tx.c create mode 100644 drivers/net/wireless/wl12xx/wl1271_tx.h (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h new file mode 100644 index 00000000000..55818f94017 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -0,0 +1,407 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1271_H__ +#define __WL1271_H__ + +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "wl1271" +#define DRIVER_PREFIX DRIVER_NAME ": " + +enum { + DEBUG_NONE = 0, + DEBUG_IRQ = BIT(0), + DEBUG_SPI = BIT(1), + DEBUG_BOOT = BIT(2), + DEBUG_MAILBOX = BIT(3), + DEBUG_NETLINK = BIT(4), + DEBUG_EVENT = BIT(5), + DEBUG_TX = BIT(6), + DEBUG_RX = BIT(7), + DEBUG_SCAN = BIT(8), + DEBUG_CRYPT = BIT(9), + DEBUG_PSM = BIT(10), + DEBUG_MAC80211 = BIT(11), + DEBUG_CMD = BIT(12), + DEBUG_ACX = BIT(13), + DEBUG_ALL = ~0, +}; + +#define DEBUG_LEVEL (DEBUG_NONE) + +#define DEBUG_DUMP_LIMIT 1024 + +#define wl1271_error(fmt, arg...) \ + printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) + +#define wl1271_warning(fmt, arg...) \ + printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) + +#define wl1271_notice(fmt, arg...) \ + printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) + +#define wl1271_info(fmt, arg...) \ + printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) + +#define wl1271_debug(level, fmt, arg...) \ + do { \ + if (level & DEBUG_LEVEL) \ + printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ + } while (0) + +#define wl1271_dump(level, prefix, buf, len) \ + do { \ + if (level & DEBUG_LEVEL) \ + print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, \ + min_t(size_t, len, DEBUG_DUMP_LIMIT), \ + 0); \ + } while (0) + +#define wl1271_dump_ascii(level, prefix, buf, len) \ + do { \ + if (level & DEBUG_LEVEL) \ + print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, \ + min_t(size_t, len, DEBUG_DUMP_LIMIT), \ + true); \ + } while (0) + +#define WL1271_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ + CFG_BSSID_FILTER_EN) + +#define WL1271_DEFAULT_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \ + CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \ + CFG_RX_CTL_EN | CFG_RX_BCN_EN | \ + CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) + +#define WL1271_FW_NAME "wl1271-fw.bin" +#define WL1271_NVS_NAME "wl1271-nvs.bin" + +#define WL1271_BUSY_WORD_LEN 8 + +#define WL1271_ELP_HW_STATE_ASLEEP 0 +#define WL1271_ELP_HW_STATE_IRQ 1 + +enum wl1271_state { + WL1271_STATE_OFF, + WL1271_STATE_ON, + WL1271_STATE_PLT, +}; + +enum wl1271_partition_type { + PART_DOWN, + PART_WORK, + PART_DRPW, + + PART_TABLE_LEN +}; + +struct wl1271_partition { + u32 size; + u32 start; +}; + +struct wl1271_partition_set { + struct wl1271_partition mem; + struct wl1271_partition reg; +}; + +struct wl1271; + +/* FIXME: I'm not sure about this structure name */ +struct wl1271_chip { + u32 id; + char fw_ver[21]; +}; + +struct wl1271_stats { + struct acx_statistics *fw_stats; + unsigned long fw_stats_update; + + unsigned int retry_count; + unsigned int excessive_retries; +}; + +struct wl1271_debugfs { + struct dentry *rootdir; + struct dentry *fw_statistics; + + struct dentry *tx_internal_desc_overflow; + + struct dentry *rx_out_of_mem; + struct dentry *rx_hdr_overflow; + struct dentry *rx_hw_stuck; + struct dentry *rx_dropped; + struct dentry *rx_fcs_err; + struct dentry *rx_xfr_hint_trig; + struct dentry *rx_path_reset; + struct dentry *rx_reset_counter; + + struct dentry *dma_rx_requested; + struct dentry *dma_rx_errors; + struct dentry *dma_tx_requested; + struct dentry *dma_tx_errors; + + struct dentry *isr_cmd_cmplt; + struct dentry *isr_fiqs; + struct dentry *isr_rx_headers; + struct dentry *isr_rx_mem_overflow; + struct dentry *isr_rx_rdys; + struct dentry *isr_irqs; + struct dentry *isr_tx_procs; + struct dentry *isr_decrypt_done; + struct dentry *isr_dma0_done; + struct dentry *isr_dma1_done; + struct dentry *isr_tx_exch_complete; + struct dentry *isr_commands; + struct dentry *isr_rx_procs; + struct dentry *isr_hw_pm_mode_changes; + struct dentry *isr_host_acknowledges; + struct dentry *isr_pci_pm; + struct dentry *isr_wakeups; + struct dentry *isr_low_rssi; + + struct dentry *wep_addr_key_count; + struct dentry *wep_default_key_count; + /* skipping wep.reserved */ + struct dentry *wep_key_not_found; + struct dentry *wep_decrypt_fail; + struct dentry *wep_packets; + struct dentry *wep_interrupt; + + struct dentry *pwr_ps_enter; + struct dentry *pwr_elp_enter; + struct dentry *pwr_missing_bcns; + struct dentry *pwr_wake_on_host; + struct dentry *pwr_wake_on_timer_exp; + struct dentry *pwr_tx_with_ps; + struct dentry *pwr_tx_without_ps; + struct dentry *pwr_rcvd_beacons; + struct dentry *pwr_power_save_off; + struct dentry *pwr_enable_ps; + struct dentry *pwr_disable_ps; + struct dentry *pwr_fix_tsf_ps; + /* skipping cont_miss_bcns_spread for now */ + struct dentry *pwr_rcvd_awake_beacons; + + struct dentry *mic_rx_pkts; + struct dentry *mic_calc_failure; + + struct dentry *aes_encrypt_fail; + struct dentry *aes_decrypt_fail; + struct dentry *aes_encrypt_packets; + struct dentry *aes_decrypt_packets; + struct dentry *aes_encrypt_interrupt; + struct dentry *aes_decrypt_interrupt; + + struct dentry *event_heart_beat; + struct dentry *event_calibration; + struct dentry *event_rx_mismatch; + struct dentry *event_rx_mem_empty; + struct dentry *event_rx_pool; + struct dentry *event_oom_late; + struct dentry *event_phy_transmit_error; + struct dentry *event_tx_stuck; + + struct dentry *ps_pspoll_timeouts; + struct dentry *ps_upsd_timeouts; + struct dentry *ps_upsd_max_sptime; + struct dentry *ps_upsd_max_apturn; + struct dentry *ps_pspoll_max_apturn; + struct dentry *ps_pspoll_utilization; + struct dentry *ps_upsd_utilization; + + struct dentry *rxpipe_rx_prep_beacon_drop; + struct dentry *rxpipe_descr_host_int_trig_rx_data; + struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data; + struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data; + struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data; + + struct dentry *tx_queue_len; + + struct dentry *retry_count; + struct dentry *excessive_retries; +}; + +#define NUM_TX_QUEUES 4 +#define NUM_RX_PKT_DESC 8 + +/* FW status registers */ +struct wl1271_fw_status { + u32 intr; + u8 fw_rx_counter; + u8 drv_rx_counter; + u8 reserved; + u8 tx_results_counter; + u32 rx_pkt_descs[NUM_RX_PKT_DESC]; + u32 tx_released_blks[NUM_TX_QUEUES]; + u32 fw_localtime; + u32 padding[2]; +} __attribute__ ((packed)); + +struct wl1271_rx_mem_pool_addr { + u32 addr; + u32 addr_extra; +}; + +struct wl1271 { + struct ieee80211_hw *hw; + bool mac80211_registered; + + struct spi_device *spi; + + void (*set_power)(bool enable); + int irq; + + spinlock_t wl_lock; + + enum wl1271_state state; + struct mutex mutex; + + int physical_mem_addr; + int physical_reg_addr; + int virtual_mem_addr; + int virtual_reg_addr; + + struct wl1271_chip chip; + + int cmd_box_addr; + int event_box_addr; + + u8 *fw; + size_t fw_len; + u8 *nvs; + size_t nvs_len; + + u8 bssid[ETH_ALEN]; + u8 mac_addr[ETH_ALEN]; + u8 bss_type; + u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 ssid_len; + u8 listen_int; + int channel; + + struct wl1271_acx_mem_map *target_mem_map; + + /* Accounting for allocated / available TX blocks on HW */ + u32 tx_blocks_freed[NUM_TX_QUEUES]; + u32 tx_blocks_available; + u8 tx_results_count; + + /* Transmitted TX packets counter for chipset interface */ + int tx_packets_count; + + /* Time-offset between host and chipset clocks */ + int time_offset; + + /* Session counter for the chipset */ + int session_counter; + + /* Frames scheduled for transmission, not handled yet */ + struct sk_buff_head tx_queue; + bool tx_queue_stopped; + + struct work_struct tx_work; + struct work_struct filter_work; + + /* Pending TX frames */ + struct sk_buff *tx_frames[16]; + + /* FW Rx counter */ + u32 rx_counter; + + /* Rx memory pool address */ + struct wl1271_rx_mem_pool_addr rx_mem_pool_addr; + + /* The target interrupt mask */ + struct work_struct irq_work; + + /* The mbox event mask */ + u32 event_mask; + + /* Mailbox pointers */ + u32 mbox_ptr[2]; + + /* Are we currently scanning */ + bool scanning; + + /* Our association ID */ + u16 aid; + + /* Default key (for WEP) */ + u32 default_key; + + unsigned int rx_config; + unsigned int rx_filter; + + /* is firmware in elp mode */ + bool elp; + + struct completion *elp_compl; + + /* we can be in psm, but not in elp, we have to differentiate */ + bool psm; + + /* PSM mode requested */ + bool psm_requested; + + /* in dBm */ + int power_level; + + struct wl1271_stats stats; + struct wl1271_debugfs debugfs; + + u32 buffer_32; + u32 buffer_cmd; + u8 buffer_busyword[WL1271_BUSY_WORD_LEN]; + struct wl1271_rx_descriptor *rx_descriptor; + + struct wl1271_fw_status *fw_status; + struct wl1271_tx_hw_res_if *tx_res_if; +}; + +int wl1271_plt_start(struct wl1271 *wl); +int wl1271_plt_stop(struct wl1271 *wl); + +#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ + +#define SESSION_COUNTER_MAX 7 /* maximum value for the session counter */ + +#define WL1271_DEFAULT_POWER_LEVEL 0 + +#define WL1271_TX_QUEUE_MAX_LENGTH 20 + +/* WL1271 needs a 200ms sleep after power on */ +#define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */ + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c new file mode 100644 index 00000000000..f622a409261 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -0,0 +1,961 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl1271_acx.h" + +#include +#include +#include +#include + +#include "wl1271.h" +#include "wl12xx_80211.h" +#include "wl1271_reg.h" +#include "wl1271_spi.h" +#include "wl1271_ps.h" + +int wl1271_acx_wake_up_conditions(struct wl1271 *wl, u8 wake_up_event, + u8 listen_interval) +{ + struct acx_wake_up_condition *wake_up; + int ret; + + wl1271_debug(DEBUG_ACX, "acx wake up conditions"); + + wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); + if (!wake_up) { + ret = -ENOMEM; + goto out; + } + + wake_up->wake_up_event = wake_up_event; + wake_up->listen_interval = listen_interval; + + ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, + wake_up, sizeof(*wake_up)); + if (ret < 0) { + wl1271_warning("could not set wake up conditions: %d", ret); + goto out; + } + +out: + kfree(wake_up); + return ret; +} + +int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth) +{ + struct acx_sleep_auth *auth; + int ret; + + wl1271_debug(DEBUG_ACX, "acx sleep auth"); + + auth = kzalloc(sizeof(*auth), GFP_KERNEL); + if (!auth) { + ret = -ENOMEM; + goto out; + } + + auth->sleep_auth = sleep_auth; + + ret = wl1271_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); + if (ret < 0) + return ret; + +out: + kfree(auth); + return ret; +} + +int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len) +{ + struct acx_revision *rev; + int ret; + + wl1271_debug(DEBUG_ACX, "acx fw rev"); + + rev = kzalloc(sizeof(*rev), GFP_KERNEL); + if (!rev) { + ret = -ENOMEM; + goto out; + } + + ret = wl1271_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); + if (ret < 0) { + wl1271_warning("ACX_FW_REV interrogate failed"); + goto out; + } + + /* be careful with the buffer sizes */ + strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); + + /* + * if the firmware version string is exactly + * sizeof(rev->fw_version) long or fw_len is less than + * sizeof(rev->fw_version) it won't be null terminated + */ + buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; + +out: + kfree(rev); + return ret; +} + +int wl1271_acx_tx_power(struct wl1271 *wl, int power) +{ + struct acx_current_tx_power *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); + + if (power < 0 || power > 25) + return -EINVAL; + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->current_tx_power = power * 10; + + ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("configure of tx power failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_feature_cfg(struct wl1271 *wl) +{ + struct acx_feature_config *feature; + int ret; + + wl1271_debug(DEBUG_ACX, "acx feature cfg"); + + feature = kzalloc(sizeof(*feature), GFP_KERNEL); + if (!feature) { + ret = -ENOMEM; + goto out; + } + + /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ + feature->data_flow_options = 0; + feature->options = 0; + + ret = wl1271_cmd_configure(wl, ACX_FEATURE_CFG, + feature, sizeof(*feature)); + if (ret < 0) { + wl1271_error("Couldnt set HW encryption"); + goto out; + } + +out: + kfree(feature); + return ret; +} + +int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map, + size_t len) +{ + int ret; + + wl1271_debug(DEBUG_ACX, "acx mem map"); + + ret = wl1271_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); + if (ret < 0) + return ret; + + return 0; +} + +int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl, u32 life_time) +{ + struct acx_rx_msdu_lifetime *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx rx msdu life time"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->lifetime = life_time; + ret = wl1271_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("failed to set rx msdu life time: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter) +{ + struct acx_rx_config *rx_config; + int ret; + + wl1271_debug(DEBUG_ACX, "acx rx config"); + + rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); + if (!rx_config) { + ret = -ENOMEM; + goto out; + } + + rx_config->config_options = config; + rx_config->filter_options = filter; + + ret = wl1271_cmd_configure(wl, ACX_RX_CFG, + rx_config, sizeof(*rx_config)); + if (ret < 0) { + wl1271_warning("failed to set rx config: %d", ret); + goto out; + } + +out: + kfree(rx_config); + return ret; +} + +int wl1271_acx_pd_threshold(struct wl1271 *wl) +{ + struct acx_packet_detection *pd; + int ret; + + wl1271_debug(DEBUG_ACX, "acx data pd threshold"); + + pd = kzalloc(sizeof(*pd), GFP_KERNEL); + if (!pd) { + ret = -ENOMEM; + goto out; + } + + /* FIXME: threshold value not set */ + + ret = wl1271_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); + if (ret < 0) { + wl1271_warning("failed to set pd threshold: %d", ret); + goto out; + } + +out: + kfree(pd); + return 0; +} + +int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time) +{ + struct acx_slot *slot; + int ret; + + wl1271_debug(DEBUG_ACX, "acx slot"); + + slot = kzalloc(sizeof(*slot), GFP_KERNEL); + if (!slot) { + ret = -ENOMEM; + goto out; + } + + slot->wone_index = STATION_WONE_INDEX; + slot->slot_time = slot_time; + + ret = wl1271_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); + if (ret < 0) { + wl1271_warning("failed to set slot time: %d", ret); + goto out; + } + +out: + kfree(slot); + return ret; +} + +int wl1271_acx_group_address_tbl(struct wl1271 *wl) +{ + struct acx_dot11_grp_addr_tbl *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx group address tbl"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* MAC filtering */ + acx->enabled = 0; + acx->num_groups = 0; + memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); + + ret = wl1271_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("failed to set group addr table: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_service_period_timeout(struct wl1271 *wl) +{ + struct acx_rx_timeout *rx_timeout; + int ret; + + rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); + if (!rx_timeout) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_ACX, "acx service period timeout"); + + rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; + rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF; + + ret = wl1271_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, + rx_timeout, sizeof(*rx_timeout)); + if (ret < 0) { + wl1271_warning("failed to set service period timeout: %d", + ret); + goto out; + } + +out: + kfree(rx_timeout); + return ret; +} + +int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold) +{ + struct acx_rts_threshold *rts; + int ret; + + wl1271_debug(DEBUG_ACX, "acx rts threshold"); + + rts = kzalloc(sizeof(*rts), GFP_KERNEL); + if (!rts) { + ret = -ENOMEM; + goto out; + } + + rts->threshold = rts_threshold; + + ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); + if (ret < 0) { + wl1271_warning("failed to set rts threshold: %d", ret); + goto out; + } + +out: + kfree(rts); + return ret; +} + +int wl1271_acx_beacon_filter_opt(struct wl1271 *wl) +{ + struct acx_beacon_filter_option *beacon_filter; + int ret; + + wl1271_debug(DEBUG_ACX, "acx beacon filter opt"); + + beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); + if (!beacon_filter) { + ret = -ENOMEM; + goto out; + } + + beacon_filter->enable = 0; + beacon_filter->max_num_beacons = 0; + + ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_OPT, + beacon_filter, sizeof(*beacon_filter)); + if (ret < 0) { + wl1271_warning("failed to set beacon filter opt: %d", ret); + goto out; + } + +out: + kfree(beacon_filter); + return ret; +} + +int wl1271_acx_beacon_filter_table(struct wl1271 *wl) +{ + struct acx_beacon_filter_ie_table *ie_table; + int ret; + + wl1271_debug(DEBUG_ACX, "acx beacon filter table"); + + ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); + if (!ie_table) { + ret = -ENOMEM; + goto out; + } + + ie_table->num_ie = 0; + memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE); + + ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, + ie_table, sizeof(*ie_table)); + if (ret < 0) { + wl1271_warning("failed to set beacon filter table: %d", ret); + goto out; + } + +out: + kfree(ie_table); + return ret; +} + +int wl1271_acx_sg_enable(struct wl1271 *wl) +{ + struct acx_bt_wlan_coex *pta; + int ret; + + wl1271_debug(DEBUG_ACX, "acx sg enable"); + + pta = kzalloc(sizeof(*pta), GFP_KERNEL); + if (!pta) { + ret = -ENOMEM; + goto out; + } + + pta->enable = SG_ENABLE; + + ret = wl1271_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); + if (ret < 0) { + wl1271_warning("failed to set softgemini enable: %d", ret); + goto out; + } + +out: + kfree(pta); + return ret; +} + +int wl1271_acx_sg_cfg(struct wl1271 *wl) +{ + struct acx_bt_wlan_coex_param *param; + int ret; + + wl1271_debug(DEBUG_ACX, "acx sg cfg"); + + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) { + ret = -ENOMEM; + goto out; + } + + /* BT-WLAN coext parameters */ + param->min_rate = RATE_INDEX_24MBPS; + param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; + param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; + param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; + param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; + param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; + param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; + param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; + param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; + param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; + param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; + param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; + param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; + param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; + param->antenna_type = PTA_ANTENNA_TYPE_DEF; + param->signal_type = PTA_SIGNALING_TYPE_DEF; + param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; + param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; + param->max_cts = PTA_MAX_NUM_CTS_DEF; + param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; + param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; + param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; + param->wlan_elp_hp = PTA_ELP_HP_DEF; + param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; + param->ack_mode_dual_ant = PTA_ACK_MODE_DEF; + param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF; + param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; + param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; + + ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); + if (ret < 0) { + wl1271_warning("failed to set sg config: %d", ret); + goto out; + } + +out: + kfree(param); + return ret; +} + +int wl1271_acx_cca_threshold(struct wl1271 *wl) +{ + struct acx_energy_detection *detection; + int ret; + + wl1271_debug(DEBUG_ACX, "acx cca threshold"); + + detection = kzalloc(sizeof(*detection), GFP_KERNEL); + if (!detection) { + ret = -ENOMEM; + goto out; + } + + detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; + detection->tx_energy_detection = 0; + + ret = wl1271_cmd_configure(wl, ACX_CCA_THRESHOLD, + detection, sizeof(*detection)); + if (ret < 0) { + wl1271_warning("failed to set cca threshold: %d", ret); + return ret; + } + +out: + kfree(detection); + return ret; +} + +int wl1271_acx_bcn_dtim_options(struct wl1271 *wl) +{ + struct acx_beacon_broadcast *bb; + int ret; + + wl1271_debug(DEBUG_ACX, "acx bcn dtim options"); + + bb = kzalloc(sizeof(*bb), GFP_KERNEL); + if (!bb) { + ret = -ENOMEM; + goto out; + } + + bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; + bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; + bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; + bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; + + ret = wl1271_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); + if (ret < 0) { + wl1271_warning("failed to set rx config: %d", ret); + goto out; + } + +out: + kfree(bb); + return ret; +} + +int wl1271_acx_aid(struct wl1271 *wl, u16 aid) +{ + struct acx_aid *acx_aid; + int ret; + + wl1271_debug(DEBUG_ACX, "acx aid"); + + acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); + if (!acx_aid) { + ret = -ENOMEM; + goto out; + } + + acx_aid->aid = aid; + + ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); + if (ret < 0) { + wl1271_warning("failed to set aid: %d", ret); + goto out; + } + +out: + kfree(acx_aid); + return ret; +} + +int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask) +{ + struct acx_event_mask *mask; + int ret; + + wl1271_debug(DEBUG_ACX, "acx event mbox mask"); + + mask = kzalloc(sizeof(*mask), GFP_KERNEL); + if (!mask) { + ret = -ENOMEM; + goto out; + } + + /* high event mask is unused */ + mask->high_event_mask = 0xffffffff; + + mask->event_mask = event_mask; + + ret = wl1271_cmd_configure(wl, ACX_EVENT_MBOX_MASK, + mask, sizeof(*mask)); + if (ret < 0) { + wl1271_warning("failed to set acx_event_mbox_mask: %d", ret); + goto out; + } + +out: + kfree(mask); + return ret; +} + +int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble) +{ + struct acx_preamble *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx_set_preamble"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->preamble = preamble; + + ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of preamble failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_cts_protect(struct wl1271 *wl, + enum acx_ctsprotect_type ctsprotect) +{ + struct acx_ctsprotect *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx_set_ctsprotect"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->ctsprotect = ctsprotect; + + ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of ctsprotect failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) +{ + int ret; + + wl1271_debug(DEBUG_ACX, "acx statistics"); + + ret = wl1271_cmd_interrogate(wl, ACX_STATISTICS, stats, + sizeof(*stats)); + if (ret < 0) { + wl1271_warning("acx statistics failed: %d", ret); + return -ENOMEM; + } + + return 0; +} + +int wl1271_acx_rate_policies(struct wl1271 *wl) +{ + struct acx_rate_policy *acx; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx rate policies"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* configure one default (one-size-fits-all) rate class */ + acx->rate_class_cnt = 1; + acx->rate_class[0].enabled_rates = ACX_RATE_MASK_ALL; + acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT; + acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT; + acx->rate_class[0].aflags = 0; + + ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of rate policies failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_ac_cfg(struct wl1271 *wl) +{ + struct acx_ac_cfg *acx; + int i, ret = 0; + + wl1271_debug(DEBUG_ACX, "acx access category config"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* + * FIXME: Configure each AC with appropriate values (most suitable + * values will probably be different for each AC. + */ + for (i = 0; i < WL1271_ACX_AC_COUNT; i++) { + acx->ac = i; + + /* + * FIXME: The following default values originate from + * the TI reference driver. What do they mean? + */ + acx->cw_min = 15; + acx->cw_max = 63; + acx->aifsn = 3; + acx->reserved = 0; + acx->tx_op_limit = 0; + + ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of access category " + "config: %d", ret); + goto out; + } + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_tid_cfg(struct wl1271 *wl) +{ + struct acx_tid_config *acx; + int i, ret = 0; + + wl1271_debug(DEBUG_ACX, "acx tid config"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* FIXME: configure each TID with a different AC reference */ + for (i = 0; i < WL1271_ACX_TID_COUNT; i++) { + acx->queue_id = i; + acx->tsid = WL1271_ACX_AC_BE; + acx->ps_scheme = WL1271_ACX_PS_SCHEME_LEGACY; + acx->ack_policy = WL1271_ACX_ACK_POLICY_LEGACY; + + ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of tid config failed: %d", ret); + goto out; + } + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_frag_threshold(struct wl1271 *wl) +{ + struct acx_frag_threshold *acx; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx frag threshold"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; + ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of frag threshold failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_tx_config_options(struct wl1271 *wl) +{ + struct acx_tx_config_options *acx; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx tx config options"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->tx_compl_timeout = WL1271_ACX_TX_COMPL_TIMEOUT; + acx->tx_compl_threshold = WL1271_ACX_TX_COMPL_THRESHOLD; + ret = wl1271_cmd_configure(wl, ACX_TX_CONFIG_OPT, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of tx options failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_mem_cfg(struct wl1271 *wl) +{ + struct wl1271_acx_config_memory *mem_conf; + int ret; + + wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); + + mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); + if (!mem_conf) { + ret = -ENOMEM; + goto out; + } + + /* memory config */ + mem_conf->num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); + mem_conf->rx_mem_block_num = ACX_RX_MEM_BLOCKS; + mem_conf->tx_min_mem_block_num = ACX_TX_MIN_MEM_BLOCKS; + mem_conf->num_ssid_profiles = ACX_NUM_SSID_PROFILES; + mem_conf->total_tx_descriptors = ACX_TX_DESCRIPTORS; + + ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, + sizeof(*mem_conf)); + if (ret < 0) { + wl1271_warning("wl1271 mem config failed: %d", ret); + goto out; + } + +out: + kfree(mem_conf); + return ret; +} + +int wl1271_acx_init_mem_config(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_mem_cfg(wl); + if (ret < 0) + return ret; + + wl->target_mem_map = kzalloc(sizeof(struct wl1271_acx_mem_map), + GFP_KERNEL); + if (!wl->target_mem_map) { + wl1271_error("couldn't allocate target memory map"); + return -ENOMEM; + } + + /* we now ask for the firmware built memory map */ + ret = wl1271_acx_mem_map(wl, (void *)wl->target_mem_map, + sizeof(struct wl1271_acx_mem_map)); + if (ret < 0) { + wl1271_error("couldn't retrieve firmware memory map"); + kfree(wl->target_mem_map); + wl->target_mem_map = NULL; + return ret; + } + + /* initialize TX block book keeping */ + wl->tx_blocks_available = wl->target_mem_map->num_tx_mem_blocks; + wl1271_debug(DEBUG_TX, "available tx blocks: %d", + wl->tx_blocks_available); + + return 0; +} + +int wl1271_acx_init_rx_interrupt(struct wl1271 *wl) +{ + struct wl1271_acx_rx_config_opt *rx_conf; + int ret; + + wl1271_debug(DEBUG_ACX, "wl1271 rx interrupt config"); + + rx_conf = kzalloc(sizeof(*rx_conf), GFP_KERNEL); + if (!rx_conf) { + ret = -ENOMEM; + goto out; + } + + rx_conf->threshold = WL1271_RX_INTR_THRESHOLD_DEF; + rx_conf->timeout = WL1271_RX_INTR_TIMEOUT_DEF; + rx_conf->mblk_threshold = USHORT_MAX; /* Disabled */ + rx_conf->queue_type = RX_QUEUE_TYPE_RX_LOW_PRIORITY; + + ret = wl1271_cmd_configure(wl, ACX_RX_CONFIG_OPT, rx_conf, + sizeof(*rx_conf)); + if (ret < 0) { + wl1271_warning("wl1271 rx config opt failed: %d", ret); + goto out; + } + +out: + kfree(rx_conf); + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h new file mode 100644 index 00000000000..9068daaf0dd --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -0,0 +1,1221 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1271_ACX_H__ +#define __WL1271_ACX_H__ + +#include "wl1271.h" +#include "wl1271_cmd.h" + +/************************************************************************* + + Host Interrupt Register (WiLink -> Host) + +**************************************************************************/ +/* HW Initiated interrupt Watchdog timer expiration */ +#define WL1271_ACX_INTR_WATCHDOG BIT(0) +/* Init sequence is done (masked interrupt, detection through polling only ) */ +#define WL1271_ACX_INTR_INIT_COMPLETE BIT(1) +/* Event was entered to Event MBOX #A*/ +#define WL1271_ACX_INTR_EVENT_A BIT(2) +/* Event was entered to Event MBOX #B*/ +#define WL1271_ACX_INTR_EVENT_B BIT(3) +/* Command processing completion*/ +#define WL1271_ACX_INTR_CMD_COMPLETE BIT(4) +/* Signaling the host on HW wakeup */ +#define WL1271_ACX_INTR_HW_AVAILABLE BIT(5) +/* The MISC bit is used for aggregation of RX, TxComplete and TX rate update */ +#define WL1271_ACX_INTR_DATA BIT(6) +/* Trace meassge on MBOX #A */ +#define WL1271_ACX_INTR_TRACE_A BIT(7) +/* Trace meassge on MBOX #B */ +#define WL1271_ACX_INTR_TRACE_B BIT(8) + +#define WL1271_ACX_INTR_ALL 0xFFFFFFFF +#define WL1271_ACX_ALL_EVENTS_VECTOR (WL1271_ACX_INTR_WATCHDOG | \ + WL1271_ACX_INTR_INIT_COMPLETE | \ + WL1271_ACX_INTR_EVENT_A | \ + WL1271_ACX_INTR_EVENT_B | \ + WL1271_ACX_INTR_CMD_COMPLETE | \ + WL1271_ACX_INTR_HW_AVAILABLE | \ + WL1271_ACX_INTR_DATA) + +#define WL1271_INTR_MASK (WL1271_ACX_INTR_EVENT_A | \ + WL1271_ACX_INTR_EVENT_B | \ + WL1271_ACX_INTR_DATA) + +/* Target's information element */ +struct acx_header { + struct wl1271_cmd_header cmd; + + /* acx (or information element) header */ + u16 id; + + /* payload length (not including headers */ + u16 len; +}; + +struct acx_error_counter { + struct acx_header header; + + /* The number of PLCP errors since the last time this */ + /* information element was interrogated. This field is */ + /* automatically cleared when it is interrogated.*/ + u32 PLCP_error; + + /* The number of FCS errors since the last time this */ + /* information element was interrogated. This field is */ + /* automatically cleared when it is interrogated.*/ + u32 FCS_error; + + /* The number of MPDUs without PLCP header errors received*/ + /* since the last time this information element was interrogated. */ + /* This field is automatically cleared when it is interrogated.*/ + u32 valid_frame; + + /* the number of missed sequence numbers in the squentially */ + /* values of frames seq numbers */ + u32 seq_num_miss; +} __attribute__ ((packed)); + +struct acx_revision { + struct acx_header header; + + /* + * The WiLink firmware version, an ASCII string x.x.x.x, + * that uniquely identifies the current firmware. + * The left most digit is incremented each time a + * significant change is made to the firmware, such as + * code redesign or new platform support. + * The second digit is incremented when major enhancements + * are added or major fixes are made. + * The third digit is incremented for each GA release. + * The fourth digit is incremented for each build. + * The first two digits identify a firmware release version, + * in other words, a unique set of features. + * The first three digits identify a GA release. + */ + char fw_version[20]; + + /* + * This 4 byte field specifies the WiLink hardware version. + * bits 0 - 15: Reserved. + * bits 16 - 23: Version ID - The WiLink version ID + * (1 = first spin, 2 = second spin, and so on). + * bits 24 - 31: Chip ID - The WiLink chip ID. + */ + u32 hw_version; +} __attribute__ ((packed)); + +enum wl1271_psm_mode { + /* Active mode */ + WL1271_PSM_CAM = 0, + + /* Power save mode */ + WL1271_PSM_PS = 1, + + /* Extreme low power */ + WL1271_PSM_ELP = 2, +}; + +struct acx_sleep_auth { + struct acx_header header; + + /* The sleep level authorization of the device. */ + /* 0 - Always active*/ + /* 1 - Power down mode: light / fast sleep*/ + /* 2 - ELP mode: Deep / Max sleep*/ + u8 sleep_auth; + u8 padding[3]; +} __attribute__ ((packed)); + +enum { + HOSTIF_PCI_MASTER_HOST_INDIRECT, + HOSTIF_PCI_MASTER_HOST_DIRECT, + HOSTIF_SLAVE, + HOSTIF_PKT_RING, + HOSTIF_DONTCARE = 0xFF +}; + +#define DEFAULT_UCAST_PRIORITY 0 +#define DEFAULT_RX_Q_PRIORITY 0 +#define DEFAULT_NUM_STATIONS 1 +#define DEFAULT_RXQ_PRIORITY 0 /* low 0 .. 15 high */ +#define DEFAULT_RXQ_TYPE 0x07 /* All frames, Data/Ctrl/Mgmt */ +#define TRACE_BUFFER_MAX_SIZE 256 + +#define DP_RX_PACKET_RING_CHUNK_SIZE 1600 +#define DP_TX_PACKET_RING_CHUNK_SIZE 1600 +#define DP_RX_PACKET_RING_CHUNK_NUM 2 +#define DP_TX_PACKET_RING_CHUNK_NUM 2 +#define DP_TX_COMPLETE_TIME_OUT 20 +#define FW_TX_CMPLT_BLOCK_SIZE 16 + +#define TX_MSDU_LIFETIME_MIN 0 +#define TX_MSDU_LIFETIME_MAX 3000 +#define TX_MSDU_LIFETIME_DEF 512 +#define RX_MSDU_LIFETIME_MIN 0 +#define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF +#define RX_MSDU_LIFETIME_DEF 512000 + +struct acx_rx_msdu_lifetime { + struct acx_header header; + + /* + * The maximum amount of time, in TU, before the + * firmware discards the MSDU. + */ + u32 lifetime; +} __attribute__ ((packed)); + +/* + * RX Config Options Table + * Bit Definition + * === ========== + * 31:14 Reserved + * 13 Copy RX Status - when set, write three receive status words + * to top of rx'd MPDUs. + * When cleared, do not write three status words (added rev 1.5) + * 12 Reserved + * 11 RX Complete upon FCS error - when set, give rx complete + * interrupt for FCS errors, after the rx filtering, e.g. unicast + * frames not to us with FCS error will not generate an interrupt. + * 10 SSID Filter Enable - When set, the WiLink discards all beacon, + * probe request, and probe response frames with an SSID that does + * not match the SSID specified by the host in the START/JOIN + * command. + * When clear, the WiLink receives frames with any SSID. + * 9 Broadcast Filter Enable - When set, the WiLink discards all + * broadcast frames. When clear, the WiLink receives all received + * broadcast frames. + * 8:6 Reserved + * 5 BSSID Filter Enable - When set, the WiLink discards any frames + * with a BSSID that does not match the BSSID specified by the + * host. + * When clear, the WiLink receives frames from any BSSID. + * 4 MAC Addr Filter - When set, the WiLink discards any frames + * with a destination address that does not match the MAC address + * of the adaptor. + * When clear, the WiLink receives frames destined to any MAC + * address. + * 3 Promiscuous - When set, the WiLink receives all valid frames + * (i.e., all frames that pass the FCS check). + * When clear, only frames that pass the other filters specified + * are received. + * 2 FCS - When set, the WiLink includes the FCS with the received + * frame. + * When cleared, the FCS is discarded. + * 1 PLCP header - When set, write all data from baseband to frame + * buffer including PHY header. + * 0 Reserved - Always equal to 0. + * + * RX Filter Options Table + * Bit Definition + * === ========== + * 31:12 Reserved - Always equal to 0. + * 11 Association - When set, the WiLink receives all association + * related frames (association request/response, reassocation + * request/response, and disassociation). When clear, these frames + * are discarded. + * 10 Auth/De auth - When set, the WiLink receives all authentication + * and de-authentication frames. When clear, these frames are + * discarded. + * 9 Beacon - When set, the WiLink receives all beacon frames. + * When clear, these frames are discarded. + * 8 Contention Free - When set, the WiLink receives all contention + * free frames. + * When clear, these frames are discarded. + * 7 Control - When set, the WiLink receives all control frames. + * When clear, these frames are discarded. + * 6 Data - When set, the WiLink receives all data frames. + * When clear, these frames are discarded. + * 5 FCS Error - When set, the WiLink receives frames that have FCS + * errors. + * When clear, these frames are discarded. + * 4 Management - When set, the WiLink receives all management + * frames. + * When clear, these frames are discarded. + * 3 Probe Request - When set, the WiLink receives all probe request + * frames. + * When clear, these frames are discarded. + * 2 Probe Response - When set, the WiLink receives all probe + * response frames. + * When clear, these frames are discarded. + * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK + * frames. + * When clear, these frames are discarded. + * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames + * that have reserved frame types and sub types as defined by the + * 802.11 specification. + * When clear, these frames are discarded. + */ +struct acx_rx_config { + struct acx_header header; + + u32 config_options; + u32 filter_options; +} __attribute__ ((packed)); + +struct acx_packet_detection { + struct acx_header header; + + u32 threshold; +} __attribute__ ((packed)); + + +enum acx_slot_type { + SLOT_TIME_LONG = 0, + SLOT_TIME_SHORT = 1, + DEFAULT_SLOT_TIME = SLOT_TIME_SHORT, + MAX_SLOT_TIMES = 0xFF +}; + +#define STATION_WONE_INDEX 0 + +struct acx_slot { + struct acx_header header; + + u8 wone_index; /* Reserved */ + u8 slot_time; + u8 reserved[6]; +} __attribute__ ((packed)); + + +#define ADDRESS_GROUP_MAX (8) +#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) + +struct acx_dot11_grp_addr_tbl { + struct acx_header header; + + u8 enabled; + u8 num_groups; + u8 pad[2]; + u8 mac_table[ADDRESS_GROUP_MAX_LEN]; +} __attribute__ ((packed)); + + +#define RX_TIMEOUT_PS_POLL_MIN 0 +#define RX_TIMEOUT_PS_POLL_MAX (200000) +#define RX_TIMEOUT_PS_POLL_DEF (15) +#define RX_TIMEOUT_UPSD_MIN 0 +#define RX_TIMEOUT_UPSD_MAX (200000) +#define RX_TIMEOUT_UPSD_DEF (15) + +struct acx_rx_timeout { + struct acx_header header; + + /* + * The longest time the STA will wait to receive + * traffic from the AP after a PS-poll has been + * transmitted. + */ + u16 ps_poll_timeout; + + /* + * The longest time the STA will wait to receive + * traffic from the AP after a frame has been sent + * from an UPSD enabled queue. + */ + u16 upsd_timeout; +} __attribute__ ((packed)); + +#define RTS_THRESHOLD_MIN 0 +#define RTS_THRESHOLD_MAX 4096 +#define RTS_THRESHOLD_DEF 2347 + +struct acx_rts_threshold { + struct acx_header header; + + u16 threshold; + u8 pad[2]; +} __attribute__ ((packed)); + +struct acx_beacon_filter_option { + struct acx_header header; + + u8 enable; + + /* + * The number of beacons without the unicast TIM + * bit set that the firmware buffers before + * signaling the host about ready frames. + * When set to 0 and the filter is enabled, beacons + * without the unicast TIM bit set are dropped. + */ + u8 max_num_beacons; + u8 pad[2]; +} __attribute__ ((packed)); + +/* + * ACXBeaconFilterEntry (not 221) + * Byte Offset Size (Bytes) Definition + * =========== ============ ========== + * 0 1 IE identifier + * 1 1 Treatment bit mask + * + * ACXBeaconFilterEntry (221) + * Byte Offset Size (Bytes) Definition + * =========== ============ ========== + * 0 1 IE identifier + * 1 1 Treatment bit mask + * 2 3 OUI + * 5 1 Type + * 6 2 Version + * + * + * Treatment bit mask - The information element handling: + * bit 0 - The information element is compared and transferred + * in case of change. + * bit 1 - The information element is transferred to the host + * with each appearance or disappearance. + * Note that both bits can be set at the same time. + */ +#define BEACON_FILTER_TABLE_MAX_IE_NUM (32) +#define BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM (6) +#define BEACON_FILTER_TABLE_IE_ENTRY_SIZE (2) +#define BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE (6) +#define BEACON_FILTER_TABLE_MAX_SIZE ((BEACON_FILTER_TABLE_MAX_IE_NUM * \ + BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \ + (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ + BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) + +struct acx_beacon_filter_ie_table { + struct acx_header header; + + u8 num_ie; + u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; + u8 pad[3]; +} __attribute__ ((packed)); + +enum { + SG_ENABLE = 0, + SG_DISABLE, + SG_SENSE_NO_ACTIVITY, + SG_SENSE_ACTIVE +}; + +struct acx_bt_wlan_coex { + struct acx_header header; + + /* + * 0 -> PTA enabled + * 1 -> PTA disabled + * 2 -> sense no active mode, i.e. + * an interrupt is sent upon + * BT activity. + * 3 -> PTA is switched on in response + * to the interrupt sending. + */ + u8 enable; + u8 pad[3]; +} __attribute__ ((packed)); + +#define PTA_ANTENNA_TYPE_DEF (0) +#define PTA_BT_HP_MAXTIME_DEF (2000) +#define PTA_WLAN_HP_MAX_TIME_DEF (5000) +#define PTA_SENSE_DISABLE_TIMER_DEF (1350) +#define PTA_PROTECTIVE_RX_TIME_DEF (1500) +#define PTA_PROTECTIVE_TX_TIME_DEF (1500) +#define PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF (3000) +#define PTA_SIGNALING_TYPE_DEF (1) +#define PTA_AFH_LEVERAGE_ON_DEF (0) +#define PTA_NUMBER_QUIET_CYCLE_DEF (0) +#define PTA_MAX_NUM_CTS_DEF (3) +#define PTA_NUMBER_OF_WLAN_PACKETS_DEF (2) +#define PTA_NUMBER_OF_BT_PACKETS_DEF (2) +#define PTA_PROTECTIVE_RX_TIME_FAST_DEF (1500) +#define PTA_PROTECTIVE_TX_TIME_FAST_DEF (3000) +#define PTA_CYCLE_TIME_FAST_DEF (8700) +#define PTA_RX_FOR_AVALANCHE_DEF (5) +#define PTA_ELP_HP_DEF (0) +#define PTA_ANTI_STARVE_PERIOD_DEF (500) +#define PTA_ANTI_STARVE_NUM_CYCLE_DEF (4) +#define PTA_ALLOW_PA_SD_DEF (1) +#define PTA_TIME_BEFORE_BEACON_DEF (6300) +#define PTA_HPDM_MAX_TIME_DEF (1600) +#define PTA_TIME_OUT_NEXT_WLAN_DEF (2550) +#define PTA_AUTO_MODE_NO_CTS_DEF (0) +#define PTA_BT_HP_RESPECTED_DEF (3) +#define PTA_WLAN_RX_MIN_RATE_DEF (24) +#define PTA_ACK_MODE_DEF (1) + +struct acx_bt_wlan_coex_param { + struct acx_header header; + + /* + * The minimum rate of a received WLAN packet in the STA, + * during protective mode, of which a new BT-HP request + * during this Rx will always be respected and gain the antenna. + */ + u32 min_rate; + + /* Max time the BT HP will be respected. */ + u16 bt_hp_max_time; + + /* Max time the WLAN HP will be respected. */ + u16 wlan_hp_max_time; + + /* + * The time between the last BT activity + * and the moment when the sense mode returns + * to SENSE_INACTIVE. + */ + u16 sense_disable_timer; + + /* Time before the next BT HP instance */ + u16 rx_time_bt_hp; + u16 tx_time_bt_hp; + + /* range: 10-20000 default: 1500 */ + u16 rx_time_bt_hp_fast; + u16 tx_time_bt_hp_fast; + + /* range: 2000-65535 default: 8700 */ + u16 wlan_cycle_fast; + + /* range: 0 - 15000 (Msec) default: 1000 */ + u16 bt_anti_starvation_period; + + /* range 400-10000(Usec) default: 3000 */ + u16 next_bt_lp_packet; + + /* Deafult: worst case for BT DH5 traffic */ + u16 wake_up_beacon; + + /* range: 0-50000(Usec) default: 1050 */ + u16 hp_dm_max_guard_time; + + /* + * This is to prevent both BT & WLAN antenna + * starvation. + * Range: 100-50000(Usec) default:2550 + */ + u16 next_wlan_packet; + + /* 0 -> shared antenna */ + u8 antenna_type; + + /* + * 0 -> TI legacy + * 1 -> Palau + */ + u8 signal_type; + + /* + * BT AFH status + * 0 -> no AFH + * 1 -> from dedicated GPIO + * 2 -> AFH on (from host) + */ + u8 afh_leverage_on; + + /* + * The number of cycles during which no + * TX will be sent after 1 cycle of RX + * transaction in protective mode + */ + u8 quiet_cycle_num; + + /* + * The maximum number of CTSs that will + * be sent for receiving RX packet in + * protective mode + */ + u8 max_cts; + + /* + * The number of WLAN packets + * transferred in common mode before + * switching to BT. + */ + u8 wlan_packets_num; + + /* + * The number of BT packets + * transferred in common mode before + * switching to WLAN. + */ + u8 bt_packets_num; + + /* range: 1-255 default: 5 */ + u8 missed_rx_avalanche; + + /* range: 0-1 default: 1 */ + u8 wlan_elp_hp; + + /* range: 0 - 15 default: 4 */ + u8 bt_anti_starvation_cycles; + + u8 ack_mode_dual_ant; + + /* + * Allow PA_SD assertion/de-assertion + * during enabled BT activity. + */ + u8 pa_sd_enable; + + /* + * Enable/Disable PTA in auto mode: + * Support Both Active & P.S modes + */ + u8 pta_auto_mode_enable; + + /* range: 0 - 20 default: 1 */ + u8 bt_hp_respected_num; +} __attribute__ ((packed)); + +#define CCA_THRSH_ENABLE_ENERGY_D 0x140A +#define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF + +struct acx_energy_detection { + struct acx_header header; + + /* The RX Clear Channel Assessment threshold in the PHY */ + u16 rx_cca_threshold; + u8 tx_energy_detection; + u8 pad; +} __attribute__ ((packed)); + +#define BCN_RX_TIMEOUT_DEF_VALUE 10000 +#define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000 +#define RX_BROADCAST_IN_PS_DEF_VALUE 1 +#define CONSECUTIVE_PS_POLL_FAILURE_DEF 4 + +struct acx_beacon_broadcast { + struct acx_header header; + + u16 beacon_rx_timeout; + u16 broadcast_timeout; + + /* Enables receiving of broadcast packets in PS mode */ + u8 rx_broadcast_in_ps; + + /* Consecutive PS Poll failures before updating the host */ + u8 ps_poll_threshold; + u8 pad[2]; +} __attribute__ ((packed)); + +struct acx_event_mask { + struct acx_header header; + + u32 event_mask; + u32 high_event_mask; /* Unused */ +} __attribute__ ((packed)); + +#define CFG_RX_FCS BIT(2) +#define CFG_RX_ALL_GOOD BIT(3) +#define CFG_UNI_FILTER_EN BIT(4) +#define CFG_BSSID_FILTER_EN BIT(5) +#define CFG_MC_FILTER_EN BIT(6) +#define CFG_MC_ADDR0_EN BIT(7) +#define CFG_MC_ADDR1_EN BIT(8) +#define CFG_BC_REJECT_EN BIT(9) +#define CFG_SSID_FILTER_EN BIT(10) +#define CFG_RX_INT_FCS_ERROR BIT(11) +#define CFG_RX_INT_ENCRYPTED BIT(12) +#define CFG_RX_WR_RX_STATUS BIT(13) +#define CFG_RX_FILTER_NULTI BIT(14) +#define CFG_RX_RESERVE BIT(15) +#define CFG_RX_TIMESTAMP_TSF BIT(16) + +#define CFG_RX_RSV_EN BIT(0) +#define CFG_RX_RCTS_ACK BIT(1) +#define CFG_RX_PRSP_EN BIT(2) +#define CFG_RX_PREQ_EN BIT(3) +#define CFG_RX_MGMT_EN BIT(4) +#define CFG_RX_FCS_ERROR BIT(5) +#define CFG_RX_DATA_EN BIT(6) +#define CFG_RX_CTL_EN BIT(7) +#define CFG_RX_CF_EN BIT(8) +#define CFG_RX_BCN_EN BIT(9) +#define CFG_RX_AUTH_EN BIT(10) +#define CFG_RX_ASSOC_EN BIT(11) + +#define SCAN_PASSIVE BIT(0) +#define SCAN_5GHZ_BAND BIT(1) +#define SCAN_TRIGGERED BIT(2) +#define SCAN_PRIORITY_HIGH BIT(3) + +struct acx_feature_config { + struct acx_header header; + + u32 options; + u32 data_flow_options; +} __attribute__ ((packed)); + +struct acx_current_tx_power { + struct acx_header header; + + u8 current_tx_power; + u8 padding[3]; +} __attribute__ ((packed)); + +enum acx_wake_up_event { + WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/ + WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/ + WAKE_UP_EVENT_N_DTIM_BITMAP = 0x04, /* Wake on every Nth DTIM */ + WAKE_UP_EVENT_N_BEACONS_BITMAP = 0x08, /* Wake on every Nth Beacon */ + WAKE_UP_EVENT_BITS_MASK = 0x0F +}; + +struct acx_wake_up_condition { + struct acx_header header; + + u8 wake_up_event; /* Only one bit can be set */ + u8 listen_interval; + u8 pad[2]; +} __attribute__ ((packed)); + +struct acx_aid { + struct acx_header header; + + /* + * To be set when associated with an AP. + */ + u16 aid; + u8 pad[2]; +} __attribute__ ((packed)); + +enum acx_preamble_type { + ACX_PREAMBLE_LONG = 0, + ACX_PREAMBLE_SHORT = 1 +}; + +struct acx_preamble { + struct acx_header header; + + /* + * When set, the WiLink transmits the frames with a short preamble and + * when cleared, the WiLink transmits the frames with a long preamble. + */ + u8 preamble; + u8 padding[3]; +} __attribute__ ((packed)); + +enum acx_ctsprotect_type { + CTSPROTECT_DISABLE = 0, + CTSPROTECT_ENABLE = 1 +}; + +struct acx_ctsprotect { + struct acx_header header; + u8 ctsprotect; + u8 padding[3]; +} __attribute__ ((packed)); + +struct acx_tx_statistics { + u32 internal_desc_overflow; +} __attribute__ ((packed)); + +struct acx_rx_statistics { + u32 out_of_mem; + u32 hdr_overflow; + u32 hw_stuck; + u32 dropped; + u32 fcs_err; + u32 xfr_hint_trig; + u32 path_reset; + u32 reset_counter; +} __attribute__ ((packed)); + +struct acx_dma_statistics { + u32 rx_requested; + u32 rx_errors; + u32 tx_requested; + u32 tx_errors; +} __attribute__ ((packed)); + +struct acx_isr_statistics { + /* host command complete */ + u32 cmd_cmplt; + + /* fiqisr() */ + u32 fiqs; + + /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ + u32 rx_headers; + + /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ + u32 rx_completes; + + /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ + u32 rx_mem_overflow; + + /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ + u32 rx_rdys; + + /* irqisr() */ + u32 irqs; + + /* (INT_STS_ND & INT_TRIG_TX_PROC) */ + u32 tx_procs; + + /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ + u32 decrypt_done; + + /* (INT_STS_ND & INT_TRIG_DMA0) */ + u32 dma0_done; + + /* (INT_STS_ND & INT_TRIG_DMA1) */ + u32 dma1_done; + + /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ + u32 tx_exch_complete; + + /* (INT_STS_ND & INT_TRIG_COMMAND) */ + u32 commands; + + /* (INT_STS_ND & INT_TRIG_RX_PROC) */ + u32 rx_procs; + + /* (INT_STS_ND & INT_TRIG_PM_802) */ + u32 hw_pm_mode_changes; + + /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ + u32 host_acknowledges; + + /* (INT_STS_ND & INT_TRIG_PM_PCI) */ + u32 pci_pm; + + /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ + u32 wakeups; + + /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ + u32 low_rssi; +} __attribute__ ((packed)); + +struct acx_wep_statistics { + /* WEP address keys configured */ + u32 addr_key_count; + + /* default keys configured */ + u32 default_key_count; + + u32 reserved; + + /* number of times that WEP key not found on lookup */ + u32 key_not_found; + + /* number of times that WEP key decryption failed */ + u32 decrypt_fail; + + /* WEP packets decrypted */ + u32 packets; + + /* WEP decrypt interrupts */ + u32 interrupt; +} __attribute__ ((packed)); + +#define ACX_MISSED_BEACONS_SPREAD 10 + +struct acx_pwr_statistics { + /* the amount of enters into power save mode (both PD & ELP) */ + u32 ps_enter; + + /* the amount of enters into ELP mode */ + u32 elp_enter; + + /* the amount of missing beacon interrupts to the host */ + u32 missing_bcns; + + /* the amount of wake on host-access times */ + u32 wake_on_host; + + /* the amount of wake on timer-expire */ + u32 wake_on_timer_exp; + + /* the number of packets that were transmitted with PS bit set */ + u32 tx_with_ps; + + /* the number of packets that were transmitted with PS bit clear */ + u32 tx_without_ps; + + /* the number of received beacons */ + u32 rcvd_beacons; + + /* the number of entering into PowerOn (power save off) */ + u32 power_save_off; + + /* the number of entries into power save mode */ + u16 enable_ps; + + /* + * the number of exits from power save, not including failed PS + * transitions + */ + u16 disable_ps; + + /* + * the number of times the TSF counter was adjusted because + * of drift + */ + u32 fix_tsf_ps; + + /* Gives statistics about the spread continuous missed beacons. + * The 16 LSB are dedicated for the PS mode. + * The 16 MSB are dedicated for the PS mode. + * cont_miss_bcns_spread[0] - single missed beacon. + * cont_miss_bcns_spread[1] - two continuous missed beacons. + * cont_miss_bcns_spread[2] - three continuous missed beacons. + * ... + * cont_miss_bcns_spread[9] - ten and more continuous missed beacons. + */ + u32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; + + /* the number of beacons in awake mode */ + u32 rcvd_awake_beacons; +} __attribute__ ((packed)); + +struct acx_mic_statistics { + u32 rx_pkts; + u32 calc_failure; +} __attribute__ ((packed)); + +struct acx_aes_statistics { + u32 encrypt_fail; + u32 decrypt_fail; + u32 encrypt_packets; + u32 decrypt_packets; + u32 encrypt_interrupt; + u32 decrypt_interrupt; +} __attribute__ ((packed)); + +struct acx_event_statistics { + u32 heart_beat; + u32 calibration; + u32 rx_mismatch; + u32 rx_mem_empty; + u32 rx_pool; + u32 oom_late; + u32 phy_transmit_error; + u32 tx_stuck; +} __attribute__ ((packed)); + +struct acx_ps_statistics { + u32 pspoll_timeouts; + u32 upsd_timeouts; + u32 upsd_max_sptime; + u32 upsd_max_apturn; + u32 pspoll_max_apturn; + u32 pspoll_utilization; + u32 upsd_utilization; +} __attribute__ ((packed)); + +struct acx_rxpipe_statistics { + u32 rx_prep_beacon_drop; + u32 descr_host_int_trig_rx_data; + u32 beacon_buffer_thres_host_int_trig_rx_data; + u32 missed_beacon_host_int_trig_rx_data; + u32 tx_xfr_host_int_trig_rx_data; +} __attribute__ ((packed)); + +struct acx_statistics { + struct acx_header header; + + struct acx_tx_statistics tx; + struct acx_rx_statistics rx; + struct acx_dma_statistics dma; + struct acx_isr_statistics isr; + struct acx_wep_statistics wep; + struct acx_pwr_statistics pwr; + struct acx_aes_statistics aes; + struct acx_mic_statistics mic; + struct acx_event_statistics event; + struct acx_ps_statistics ps; + struct acx_rxpipe_statistics rxpipe; +} __attribute__ ((packed)); + +#define ACX_MAX_RATE_CLASSES 8 +#define ACX_RATE_MASK_UNSPECIFIED 0 +#define ACX_RATE_MASK_ALL 0x1eff +#define ACX_RATE_RETRY_LIMIT 10 + +struct acx_rate_class { + u32 enabled_rates; + u8 short_retry_limit; + u8 long_retry_limit; + u8 aflags; + u8 reserved; +}; + +struct acx_rate_policy { + struct acx_header header; + + u32 rate_class_cnt; + struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES]; +} __attribute__ ((packed)); + +#define WL1271_ACX_AC_COUNT 4 + +struct acx_ac_cfg { + struct acx_header header; + u8 ac; + u8 cw_min; + u16 cw_max; + u8 aifsn; + u8 reserved; + u16 tx_op_limit; +} __attribute__ ((packed)); + +enum wl1271_acx_ac { + WL1271_ACX_AC_BE = 0, + WL1271_ACX_AC_BK = 1, + WL1271_ACX_AC_VI = 2, + WL1271_ACX_AC_VO = 3, + WL1271_ACX_AC_CTS2SELF = 4, + WL1271_ACX_AC_ANY_TID = 0x1F, + WL1271_ACX_AC_INVALID = 0xFF, +}; + +enum wl1271_acx_ps_scheme { + WL1271_ACX_PS_SCHEME_LEGACY = 0, + WL1271_ACX_PS_SCHEME_UPSD_TRIGGER = 1, + WL1271_ACX_PS_SCHEME_LEGACY_PSPOLL = 2, + WL1271_ACX_PS_SCHEME_SAPSD = 3, +}; + +enum wl1271_acx_ack_policy { + WL1271_ACX_ACK_POLICY_LEGACY = 0, + WL1271_ACX_ACK_POLICY_NO_ACK = 1, + WL1271_ACX_ACK_POLICY_BLOCK = 2, +}; + +#define WL1271_ACX_TID_COUNT 7 + +struct acx_tid_config { + struct acx_header header; + u8 queue_id; + u8 channel_type; + u8 tsid; + u8 ps_scheme; + u8 ack_policy; + u8 padding[3]; + u32 apsd_conf[2]; +} __attribute__ ((packed)); + +struct acx_frag_threshold { + struct acx_header header; + u16 frag_threshold; + u8 padding[2]; +} __attribute__ ((packed)); + +#define WL1271_ACX_TX_COMPL_TIMEOUT 5 +#define WL1271_ACX_TX_COMPL_THRESHOLD 5 + +struct acx_tx_config_options { + struct acx_header header; + u16 tx_compl_timeout; /* msec */ + u16 tx_compl_threshold; /* number of packets */ +} __attribute__ ((packed)); + +#define ACX_RX_MEM_BLOCKS 64 +#define ACX_TX_MIN_MEM_BLOCKS 64 +#define ACX_TX_DESCRIPTORS 32 +#define ACX_NUM_SSID_PROFILES 1 + +struct wl1271_acx_config_memory { + struct acx_header header; + + u8 rx_mem_block_num; + u8 tx_min_mem_block_num; + u8 num_stations; + u8 num_ssid_profiles; + u32 total_tx_descriptors; +} __attribute__ ((packed)); + +struct wl1271_acx_mem_map { + struct acx_header header; + + void *code_start; + void *code_end; + + void *wep_defkey_start; + void *wep_defkey_end; + + void *sta_table_start; + void *sta_table_end; + + void *packet_template_start; + void *packet_template_end; + + /* Address of the TX result interface (control block) */ + u32 tx_result; + u32 tx_result_queue_start; + + void *queue_memory_start; + void *queue_memory_end; + + u32 packet_memory_pool_start; + u32 packet_memory_pool_end; + + void *debug_buffer1_start; + void *debug_buffer1_end; + + void *debug_buffer2_start; + void *debug_buffer2_end; + + /* Number of blocks FW allocated for TX packets */ + u32 num_tx_mem_blocks; + + /* Number of blocks FW allocated for RX packets */ + u32 num_rx_mem_blocks; + + /* the following 4 fields are valid in SLAVE mode only */ + u8 *tx_cbuf; + u8 *rx_cbuf; + void *rx_ctrl; + void *tx_ctrl; +} __attribute__ ((packed)); + +enum wl1271_acx_rx_queue_type { + RX_QUEUE_TYPE_RX_LOW_PRIORITY, /* All except the high priority */ + RX_QUEUE_TYPE_RX_HIGH_PRIORITY, /* Management and voice packets */ + RX_QUEUE_TYPE_NUM, + RX_QUEUE_TYPE_MAX = USHORT_MAX +}; + +#define WL1271_RX_INTR_THRESHOLD_DEF 0 /* no pacing, send interrupt on + * every event */ +#define WL1271_RX_INTR_THRESHOLD_MIN 0 +#define WL1271_RX_INTR_THRESHOLD_MAX 15 + +#define WL1271_RX_INTR_TIMEOUT_DEF 5 +#define WL1271_RX_INTR_TIMEOUT_MIN 1 +#define WL1271_RX_INTR_TIMEOUT_MAX 100 + +struct wl1271_acx_rx_config_opt { + struct acx_header header; + + u16 mblk_threshold; + u16 threshold; + u16 timeout; + u8 queue_type; + u8 reserved; +} __attribute__ ((packed)); + +enum { + ACX_WAKE_UP_CONDITIONS = 0x0002, + ACX_MEM_CFG = 0x0003, + ACX_SLOT = 0x0004, + ACX_AC_CFG = 0x0007, + ACX_MEM_MAP = 0x0008, + ACX_AID = 0x000A, + /* ACX_FW_REV is missing in the ref driver, but seems to work */ + ACX_FW_REV = 0x000D, + ACX_MEDIUM_USAGE = 0x000F, + ACX_RX_CFG = 0x0010, + ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */ + ACX_STATISTICS = 0x0013, /* Debug API */ + ACX_PWR_CONSUMPTION_STATISTICS = 0x0014, + ACX_FEATURE_CFG = 0x0015, + ACX_TID_CFG = 0x001A, + ACX_PS_RX_STREAMING = 0x001B, + ACX_BEACON_FILTER_OPT = 0x001F, + ACX_NOISE_HIST = 0x0021, + ACX_HDK_VERSION = 0x0022, /* ??? */ + ACX_PD_THRESHOLD = 0x0023, + ACX_TX_CONFIG_OPT = 0x0024, + ACX_CCA_THRESHOLD = 0x0025, + ACX_EVENT_MBOX_MASK = 0x0026, + ACX_CONN_MONIT_PARAMS = 0x002D, + ACX_CONS_TX_FAILURE = 0x002F, + ACX_BCN_DTIM_OPTIONS = 0x0031, + ACX_SG_ENABLE = 0x0032, + ACX_SG_CFG = 0x0033, + ACX_BEACON_FILTER_TABLE = 0x0038, + ACX_ARP_IP_FILTER = 0x0039, + ACX_ROAMING_STATISTICS_TBL = 0x003B, + ACX_RATE_POLICY = 0x003D, + ACX_CTS_PROTECTION = 0x003E, + ACX_SLEEP_AUTH = 0x003F, + ACX_PREAMBLE_TYPE = 0x0040, + ACX_ERROR_CNT = 0x0041, + ACX_IBSS_FILTER = 0x0044, + ACX_SERVICE_PERIOD_TIMEOUT = 0x0045, + ACX_TSF_INFO = 0x0046, + ACX_CONFIG_PS_WMM = 0x0049, + ACX_ENABLE_RX_DATA_FILTER = 0x004A, + ACX_SET_RX_DATA_FILTER = 0x004B, + ACX_GET_DATA_FILTER_STATISTICS = 0x004C, + ACX_RX_CONFIG_OPT = 0x004E, + ACX_FRAG_CFG = 0x004F, + ACX_BET_ENABLE = 0x0050, + ACX_RSSI_SNR_TRIGGER = 0x0051, + ACX_RSSI_SNR_WEIGHTS = 0x0051, + ACX_KEEP_ALIVE_MODE = 0x0052, + ACX_SET_KEEP_ALIVE_CONFIG = 0x0054, + ACX_BA_SESSION_RESPONDER_POLICY = 0x0055, + ACX_BA_SESSION_INITIATOR_POLICY = 0x0056, + ACX_PEER_HT_CAP = 0x0057, + ACX_HT_BSS_OPERATION = 0x0058, + ACX_COEX_ACTIVITY = 0x0059, + DOT11_RX_MSDU_LIFE_TIME = 0x1004, + DOT11_CUR_TX_PWR = 0x100D, + DOT11_RX_DOT11_MODE = 0x1012, + DOT11_RTS_THRESHOLD = 0x1013, + DOT11_GROUP_ADDRESS_TBL = 0x1014, + + MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, + + MAX_IE = 0xFFFF +}; + + +int wl1271_acx_wake_up_conditions(struct wl1271 *wl, u8 wake_up_event, + u8 listen_interval); +int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth); +int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len); +int wl1271_acx_tx_power(struct wl1271 *wl, int power); +int wl1271_acx_feature_cfg(struct wl1271 *wl); +int wl1271_acx_mem_map(struct wl1271 *wl, + struct acx_header *mem_map, size_t len); +int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl, u32 life_time); +int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter); +int wl1271_acx_pd_threshold(struct wl1271 *wl); +int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time); +int wl1271_acx_group_address_tbl(struct wl1271 *wl); +int wl1271_acx_service_period_timeout(struct wl1271 *wl); +int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold); +int wl1271_acx_beacon_filter_opt(struct wl1271 *wl); +int wl1271_acx_beacon_filter_table(struct wl1271 *wl); +int wl1271_acx_sg_enable(struct wl1271 *wl); +int wl1271_acx_sg_cfg(struct wl1271 *wl); +int wl1271_acx_cca_threshold(struct wl1271 *wl); +int wl1271_acx_bcn_dtim_options(struct wl1271 *wl); +int wl1271_acx_aid(struct wl1271 *wl, u16 aid); +int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask); +int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble); +int wl1271_acx_cts_protect(struct wl1271 *wl, + enum acx_ctsprotect_type ctsprotect); +int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats); +int wl1271_acx_rate_policies(struct wl1271 *wl); +int wl1271_acx_ac_cfg(struct wl1271 *wl); +int wl1271_acx_tid_cfg(struct wl1271 *wl); +int wl1271_acx_frag_threshold(struct wl1271 *wl); +int wl1271_acx_tx_config_options(struct wl1271 *wl); +int wl1271_acx_mem_cfg(struct wl1271 *wl); +int wl1271_acx_init_mem_config(struct wl1271 *wl); +int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); + +#endif /* __WL1271_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c new file mode 100644 index 00000000000..4c22f25fd8f --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -0,0 +1,540 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include + +#include "wl1271_acx.h" +#include "wl1271_reg.h" +#include "wl1271_boot.h" +#include "wl1271_spi.h" +#include "wl1271_event.h" + +static struct wl1271_partition_set part_table[PART_TABLE_LEN] = { + [PART_DOWN] = { + .mem = { + .start = 0x00000000, + .size = 0x000177c0 + }, + .reg = { + .start = REGISTERS_BASE, + .size = 0x00008800 + }, + }, + + [PART_WORK] = { + .mem = { + .start = 0x00040000, + .size = 0x00014fc0 + }, + .reg = { + .start = REGISTERS_BASE, + .size = 0x0000b000 + }, + }, + + [PART_DRPW] = { + .mem = { + .start = 0x00040000, + .size = 0x00014fc0 + }, + .reg = { + .start = DRPW_BASE, + .size = 0x00006000 + } + } +}; + +static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) +{ + u32 cpu_ctrl; + + /* 10.5.0 run the firmware (I) */ + cpu_ctrl = wl1271_reg_read32(wl, ACX_REG_ECPU_CONTROL); + + /* 10.5.1 run the firmware (II) */ + cpu_ctrl |= flag; + wl1271_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); +} + +static void wl1271_boot_fw_version(struct wl1271 *wl) +{ + struct wl1271_static_data static_data; + + wl1271_spi_mem_read(wl, wl->cmd_box_addr, + &static_data, sizeof(static_data)); + + strncpy(wl->chip.fw_ver, static_data.fw_version, + sizeof(wl->chip.fw_ver)); + + /* make sure the string is NULL-terminated */ + wl->chip.fw_ver[sizeof(wl->chip.fw_ver) - 1] = '\0'; +} + +static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, + size_t fw_data_len, u32 dest) +{ + int addr, chunk_num, partition_limit; + u8 *p; + + /* whal_FwCtrl_LoadFwImageSm() */ + + wl1271_debug(DEBUG_BOOT, "starting firmware upload"); + + wl1271_debug(DEBUG_BOOT, "fw_data_len %d chunk_size %d", fw_data_len, + CHUNK_SIZE); + + + if ((fw_data_len % 4) != 0) { + wl1271_error("firmware length not multiple of four"); + return -EIO; + } + + wl1271_set_partition(wl, dest, + part_table[PART_DOWN].mem.size, + part_table[PART_DOWN].reg.start, + part_table[PART_DOWN].reg.size); + + /* 10.1 set partition limit and chunk num */ + chunk_num = 0; + partition_limit = part_table[PART_DOWN].mem.size; + + while (chunk_num < fw_data_len / CHUNK_SIZE) { + /* 10.2 update partition, if needed */ + addr = dest + (chunk_num + 2) * CHUNK_SIZE; + if (addr > partition_limit) { + addr = dest + chunk_num * CHUNK_SIZE; + partition_limit = chunk_num * CHUNK_SIZE + + part_table[PART_DOWN].mem.size; + + /* FIXME: Over 80 chars! */ + wl1271_set_partition(wl, + addr, + part_table[PART_DOWN].mem.size, + part_table[PART_DOWN].reg.start, + part_table[PART_DOWN].reg.size); + } + + /* 10.3 upload the chunk */ + addr = dest + chunk_num * CHUNK_SIZE; + p = buf + chunk_num * CHUNK_SIZE; + wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", + p, addr); + wl1271_spi_mem_write(wl, addr, p, CHUNK_SIZE); + + chunk_num++; + } + + /* 10.4 upload the last chunk */ + addr = dest + chunk_num * CHUNK_SIZE; + p = buf + chunk_num * CHUNK_SIZE; + wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%d B) 0x%p to 0x%x", + fw_data_len % CHUNK_SIZE, p, addr); + wl1271_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); + + return 0; +} + +static int wl1271_boot_upload_firmware(struct wl1271 *wl) +{ + u32 chunks, addr, len; + u8 *fw; + + fw = wl->fw; + chunks = be32_to_cpup((u32 *) fw); + fw += sizeof(u32); + + wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks); + + while (chunks--) { + addr = be32_to_cpup((u32 *) fw); + fw += sizeof(u32); + len = be32_to_cpup((u32 *) fw); + fw += sizeof(u32); + + if (len > 300000) { + wl1271_info("firmware chunk too long: %u", len); + return -EINVAL; + } + wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u", + chunks, addr, len); + wl1271_boot_upload_firmware_chunk(wl, fw, len, addr); + fw += len; + } + + return 0; +} + +static int wl1271_boot_upload_nvs(struct wl1271 *wl) +{ + size_t nvs_len, burst_len; + int i; + u32 dest_addr, val; + u8 *nvs_ptr, *nvs, *nvs_aligned; + + nvs = wl->nvs; + if (nvs == NULL) + return -ENODEV; + + nvs_ptr = nvs; + + nvs_len = wl->nvs_len; + + /* Update the device MAC address into the nvs */ + nvs[11] = wl->mac_addr[0]; + nvs[10] = wl->mac_addr[1]; + nvs[6] = wl->mac_addr[2]; + nvs[5] = wl->mac_addr[3]; + nvs[4] = wl->mac_addr[4]; + nvs[3] = wl->mac_addr[5]; + + /* + * Layout before the actual NVS tables: + * 1 byte : burst length. + * 2 bytes: destination address. + * n bytes: data to burst copy. + * + * This is ended by a 0 length, then the NVS tables. + */ + + /* FIXME: Do we need to check here whether the LSB is 1? */ + while (nvs_ptr[0]) { + burst_len = nvs_ptr[0]; + dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); + + /* FIXME: Due to our new wl1271_translate_reg_addr function, + we need to add the REGISTER_BASE to the destination */ + dest_addr += REGISTERS_BASE; + + /* We move our pointer to the data */ + nvs_ptr += 3; + + for (i = 0; i < burst_len; i++) { + val = (nvs_ptr[0] | (nvs_ptr[1] << 8) + | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); + + wl1271_debug(DEBUG_BOOT, + "nvs burst write 0x%x: 0x%x", + dest_addr, val); + wl1271_reg_write32(wl, dest_addr, val); + + nvs_ptr += 4; + dest_addr += 4; + } + } + + /* + * We've reached the first zero length, the first NVS table + * is 7 bytes further. + */ + nvs_ptr += 7; + nvs_len -= nvs_ptr - nvs; + nvs_len = ALIGN(nvs_len, 4); + + /* FIXME: The driver sets the partition here, but this is not needed, + since it sets to the same one as currently in use */ + /* Now we must set the partition correctly */ + wl1271_set_partition(wl, + part_table[PART_WORK].mem.start, + part_table[PART_WORK].mem.size, + part_table[PART_WORK].reg.start, + part_table[PART_WORK].reg.size); + + /* Copy the NVS tables to a new block to ensure alignment */ + nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); + + /* And finally we upload the NVS tables */ + /* FIXME: In wl1271, we upload everything at once. + No endianness handling needed here?! The ref driver doesn't do + anything about it at this point */ + wl1271_spi_mem_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len); + + kfree(nvs_aligned); + return 0; +} + +static void wl1271_boot_enable_interrupts(struct wl1271 *wl) +{ + enable_irq(wl->irq); + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(WL1271_INTR_MASK)); + wl1271_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); +} + +static int wl1271_boot_soft_reset(struct wl1271 *wl) +{ + unsigned long timeout; + u32 boot_data; + + /* perform soft reset */ + wl1271_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); + + /* SOFT_RESET is self clearing */ + timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); + while (1) { + boot_data = wl1271_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); + wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); + if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) + break; + + if (time_after(jiffies, timeout)) { + /* 1.2 check pWhalBus->uSelfClearTime if the + * timeout was reached */ + wl1271_error("soft reset timeout"); + return -1; + } + + udelay(SOFT_RESET_STALL_TIME); + } + + /* disable Rx/Tx */ + wl1271_reg_write32(wl, ENABLE, 0x0); + + /* disable auto calibration on start*/ + wl1271_reg_write32(wl, SPARE_A2, 0xffff); + + return 0; +} + +static int wl1271_boot_run_firmware(struct wl1271 *wl) +{ + int loop, ret; + u32 chip_id, interrupt; + + wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); + + chip_id = wl1271_reg_read32(wl, CHIP_ID_B); + + wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); + + if (chip_id != wl->chip.id) { + wl1271_error("chip id doesn't match after firmware boot"); + return -EIO; + } + + /* wait for init to complete */ + loop = 0; + while (loop++ < INIT_LOOP) { + udelay(INIT_LOOP_DELAY); + interrupt = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + + if (interrupt == 0xffffffff) { + wl1271_error("error reading hardware complete " + "init indication"); + return -EIO; + } + /* check that ACX_INTR_INIT_COMPLETE is enabled */ + else if (interrupt & WL1271_ACX_INTR_INIT_COMPLETE) { + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK, + WL1271_ACX_INTR_INIT_COMPLETE); + break; + } + } + + if (loop >= INIT_LOOP) { + wl1271_error("timeout waiting for the hardware to " + "complete initialization"); + return -EIO; + } + + /* get hardware config command mail box */ + wl->cmd_box_addr = wl1271_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); + + /* get hardware config event mail box */ + wl->event_box_addr = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR); + + /* set the working partition to its "running" mode offset */ + wl1271_set_partition(wl, + part_table[PART_WORK].mem.start, + part_table[PART_WORK].mem.size, + part_table[PART_WORK].reg.start, + part_table[PART_WORK].reg.size); + + wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", + wl->cmd_box_addr, wl->event_box_addr); + + wl1271_boot_fw_version(wl); + + /* + * in case of full asynchronous mode the firmware event must be + * ready to receive event from the command mailbox + */ + + /* enable gpio interrupts */ + wl1271_boot_enable_interrupts(wl); + + /* unmask all mbox events */ + wl->event_mask = 0xffffffff; + + ret = wl1271_event_unmask(wl); + if (ret < 0) { + wl1271_error("EVENT mask setting failed"); + return ret; + } + + wl1271_event_mbox_config(wl); + + /* firmware startup completed */ + return 0; +} + +static int wl1271_boot_write_irq_polarity(struct wl1271 *wl) +{ + u32 polarity, status, i; + + wl1271_reg_write32(wl, OCP_POR_CTR, OCP_REG_POLARITY); + wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_READ); + + /* Wait until the command is complete (ie. bit 18 is set) */ + for (i = 0; i < OCP_CMD_LOOP; i++) { + polarity = wl1271_reg_read32(wl, OCP_DATA_READ); + if (polarity & OCP_READY_MASK) + break; + } + if (i == OCP_CMD_LOOP) { + wl1271_error("OCP command timeout!"); + return -EIO; + } + + status = polarity & OCP_STATUS_MASK; + if (status != OCP_STATUS_OK) { + wl1271_error("OCP command failed (%d)", status); + return -EIO; + } + + /* We use HIGH polarity, so unset the LOW bit */ + polarity &= ~POLARITY_LOW; + + wl1271_reg_write32(wl, OCP_POR_CTR, OCP_REG_POLARITY); + wl1271_reg_write32(wl, OCP_DATA_WRITE, polarity); + wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_WRITE); + + return 0; +} + +int wl1271_boot(struct wl1271 *wl) +{ + int ret = 0; + u32 tmp, clk, pause; + + if (REF_CLOCK == 0 || REF_CLOCK == 2) + /* ref clk: 19.2/38.4 */ + clk = 0x3; + else if (REF_CLOCK == 1 || REF_CLOCK == 3) + /* ref clk: 26/52 */ + clk = 0x5; + + wl1271_reg_write32(wl, PLL_PARAMETERS, clk); + + pause = wl1271_reg_read32(wl, PLL_PARAMETERS); + + wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); + + pause &= ~(WU_COUNTER_PAUSE_VAL); /* FIXME: This should probably be + * WU_COUNTER_PAUSE_VAL instead of + * 0x3ff (magic number ). How does + * this work?! */ + pause |= WU_COUNTER_PAUSE_VAL; + wl1271_reg_write32(wl, WU_COUNTER_PAUSE, pause); + + /* Continue the ELP wake up sequence */ + wl1271_reg_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); + udelay(500); + + wl1271_set_partition(wl, + part_table[PART_DRPW].mem.start, + part_table[PART_DRPW].mem.size, + part_table[PART_DRPW].reg.start, + part_table[PART_DRPW].reg.size); + + /* Read-modify-write DRPW_SCRATCH_START register (see next state) + to be used by DRPw FW. The RTRIM value will be added by the FW + before taking DRPw out of reset */ + + wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START); + clk = wl1271_reg_read32(wl, DRPW_SCRATCH_START); + + wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); + + /* 2 */ + clk |= (REF_CLOCK << 1) << 4; + wl1271_reg_write32(wl, DRPW_SCRATCH_START, clk); + + wl1271_set_partition(wl, + part_table[PART_WORK].mem.start, + part_table[PART_WORK].mem.size, + part_table[PART_WORK].reg.start, + part_table[PART_WORK].reg.size); + + /* Disable interrupts */ + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); + + ret = wl1271_boot_soft_reset(wl); + if (ret < 0) + goto out; + + /* 2. start processing NVS file */ + ret = wl1271_boot_upload_nvs(wl); + if (ret < 0) + goto out; + + /* write firmware's last address (ie. it's length) to + * ACX_EEPROMLESS_IND_REG */ + wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG"); + + wl1271_reg_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG); + + tmp = wl1271_reg_read32(wl, CHIP_ID_B); + + wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); + + /* 6. read the EEPROM parameters */ + tmp = wl1271_reg_read32(wl, SCR_PAD2); + + ret = wl1271_boot_write_irq_polarity(wl); + if (ret < 0) + goto out; + + /* FIXME: Need to check whether this is really what we want */ + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, + WL1271_ACX_ALL_EVENTS_VECTOR); + + /* WL1271: The reference driver skips steps 7 to 10 (jumps directly + * to upload_fw) */ + + ret = wl1271_boot_upload_firmware(wl); + if (ret < 0) + goto out; + + /* 10.5 start firmware */ + ret = wl1271_boot_run_firmware(wl); + if (ret < 0) + goto out; + + /* set the wl1271 default filters */ + wl->rx_config = WL1271_DEFAULT_RX_CONFIG; + wl->rx_filter = WL1271_DEFAULT_RX_FILTER; + + wl1271_event_mbox_config(wl); + +out: + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.h b/drivers/net/wireless/wl12xx/wl1271_boot.h new file mode 100644 index 00000000000..b0d8fb46a43 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_boot.h @@ -0,0 +1,72 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __BOOT_H__ +#define __BOOT_H__ + +#include "wl1271.h" + +int wl1271_boot(struct wl1271 *wl); + +#define WL1271_NO_SUBBANDS 8 +#define WL1271_NO_POWER_LEVELS 4 +#define WL1271_FW_VERSION_MAX_LEN 20 + +struct wl1271_static_data { + u8 mac_address[ETH_ALEN]; + u8 padding[2]; + u8 fw_version[WL1271_FW_VERSION_MAX_LEN]; + u32 hw_version; + u8 tx_power_table[WL1271_NO_SUBBANDS][WL1271_NO_POWER_LEVELS]; +}; + +/* number of times we try to read the INIT interrupt */ +#define INIT_LOOP 20000 + +/* delay between retries */ +#define INIT_LOOP_DELAY 50 + +#define REF_CLOCK 2 +#define WU_COUNTER_PAUSE_VAL 0x3FF +#define WELP_ARM_COMMAND_VAL 0x4 + +#define OCP_CMD_LOOP 32 + +#define OCP_CMD_WRITE 0x1 +#define OCP_CMD_READ 0x2 + +#define OCP_READY_MASK BIT(18) +#define OCP_STATUS_MASK (BIT(16) | BIT(17)) + +#define OCP_STATUS_NO_RESP 0x00000 +#define OCP_STATUS_OK 0x10000 +#define OCP_STATUS_REQ_FAILED 0x20000 +#define OCP_STATUS_RESP_ERROR 0x30000 + +#define OCP_REG_POLARITY 0x30032 + +#define CMD_MBOX_ADDRESS 0x407B4 + +#define POLARITY_LOW BIT(1) + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c new file mode 100644 index 00000000000..2a4351ff54d --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -0,0 +1,813 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include + +#include "wl1271.h" +#include "wl1271_reg.h" +#include "wl1271_spi.h" +#include "wl1271_acx.h" +#include "wl12xx_80211.h" +#include "wl1271_cmd.h" + +/* + * send command to firmware + * + * @wl: wl struct + * @id: command id + * @buf: buffer containing the command, must work with dma + * @len: length of the buffer + */ +int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len) +{ + struct wl1271_cmd_header *cmd; + unsigned long timeout; + u32 intr; + int ret = 0; + + cmd = buf; + cmd->id = id; + cmd->status = 0; + + WARN_ON(len % 4 != 0); + + wl1271_spi_mem_write(wl, wl->cmd_box_addr, buf, len); + + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); + + timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); + + intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { + if (time_after(jiffies, timeout)) { + wl1271_error("command complete timeout"); + ret = -ETIMEDOUT; + goto out; + } + + msleep(1); + + intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + } + + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK, + WL1271_ACX_INTR_CMD_COMPLETE); + +out: + return ret; +} + +int wl1271_cmd_cal_channel_tune(struct wl1271 *wl) +{ + struct wl1271_cmd_cal_channel_tune *cmd; + int ret = 0; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->test.id = TEST_CMD_CHANNEL_TUNE; + + cmd->band = WL1271_CHANNEL_TUNE_BAND_2_4; + /* set up any channel, 7 is in the middle of the range */ + cmd->channel = 7; + + ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0); + if (ret < 0) + wl1271_warning("TEST_CMD_CHANNEL_TUNE failed"); + + kfree(cmd); + return ret; +} + +int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl) +{ + struct wl1271_cmd_cal_update_ref_point *cmd; + int ret = 0; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->test.id = TEST_CMD_UPDATE_PD_REFERENCE_POINT; + + /* FIXME: still waiting for the correct values */ + cmd->ref_power = 0; + cmd->ref_detector = 0; + + cmd->sub_band = WL1271_PD_REFERENCE_POINT_BAND_B_G; + + ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0); + if (ret < 0) + wl1271_warning("TEST_CMD_UPDATE_PD_REFERENCE_POINT failed"); + + kfree(cmd); + return ret; +} + +int wl1271_cmd_cal_p2g(struct wl1271 *wl) +{ + struct wl1271_cmd_cal_p2g *cmd; + int ret = 0; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->test.id = TEST_CMD_P2G_CAL; + + cmd->sub_band_mask = WL1271_CAL_P2G_BAND_B_G; + + ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0); + if (ret < 0) + wl1271_warning("TEST_CMD_P2G_CAL failed"); + + kfree(cmd); + return ret; +} + +int wl1271_cmd_cal(struct wl1271 *wl) +{ + /* + * FIXME: we must make sure that we're not sleeping when calibration + * is done + */ + int ret; + + wl1271_notice("performing tx calibration"); + + ret = wl1271_cmd_cal_channel_tune(wl); + if (ret < 0) + return ret; + + ret = wl1271_cmd_cal_update_ref_point(wl); + if (ret < 0) + return ret; + + ret = wl1271_cmd_cal_p2g(wl); + if (ret < 0) + return ret; + + return ret; +} + +int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval, + u16 beacon_interval, u8 wait) +{ + static bool do_cal = true; + unsigned long timeout; + struct wl1271_cmd_join *join; + int ret, i; + u8 *bssid; + + /* FIXME: remove when we get calibration from the factory */ + if (do_cal) { + ret = wl1271_cmd_cal(wl); + if (ret < 0) + wl1271_warning("couldn't calibrate"); + else + do_cal = false; + } + + + join = kzalloc(sizeof(*join), GFP_KERNEL); + if (!join) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_CMD, "cmd join"); + + /* Reverse order BSSID */ + bssid = (u8 *) &join->bssid_lsb; + for (i = 0; i < ETH_ALEN; i++) + bssid[i] = wl->bssid[ETH_ALEN - i - 1]; + + join->rx_config_options = wl->rx_config; + join->rx_filter_options = wl->rx_filter; + + join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | + RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; + + join->beacon_interval = beacon_interval; + join->dtim_interval = dtim_interval; + join->bss_type = bss_type; + join->channel = wl->channel; + join->ssid_len = wl->ssid_len; + memcpy(join->ssid, wl->ssid, wl->ssid_len); + join->ctrl = WL1271_JOIN_CMD_CTRL_TX_FLUSH; + + /* increment the session counter */ + wl->session_counter++; + if (wl->session_counter >= SESSION_COUNTER_MAX) + wl->session_counter = 0; + + join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET; + + + ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); + if (ret < 0) { + wl1271_error("failed to initiate cmd join"); + goto out_free; + } + + timeout = msecs_to_jiffies(JOIN_TIMEOUT); + + /* + * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to + * simplify locking we just sleep instead, for now + */ + if (wait) + msleep(10); + +out_free: + kfree(join); + +out: + return ret; +} + +/** + * send test command to firmware + * + * @wl: wl struct + * @buf: buffer containing the command, with all headers, must work with dma + * @len: length of the buffer + * @answer: is answer needed + */ +int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) +{ + int ret; + + wl1271_debug(DEBUG_CMD, "cmd test"); + + ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len); + + if (ret < 0) { + wl1271_warning("TEST command failed"); + return ret; + } + + if (answer) { + struct wl1271_command *cmd_answer; + + /* + * The test command got in, we can read the answer. + * The answer would be a wl1271_command, where the + * parameter array contains the actual answer. + */ + wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); + + cmd_answer = buf; + + if (cmd_answer->header.status != CMD_STATUS_SUCCESS) + wl1271_error("TEST command answer error: %d", + cmd_answer->header.status); + } + + return 0; +} + +/** + * read acx from firmware + * + * @wl: wl struct + * @id: acx id + * @buf: buffer for the response, including all headers, must work with dma + * @len: lenght of buf + */ +int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) +{ + struct acx_header *acx = buf; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd interrogate"); + + acx->id = id; + + /* payload length, does not include any headers */ + acx->len = len - sizeof(*acx); + + ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_error("INTERROGATE command failed"); + goto out; + } + + /* the interrogate command got in, we can read the answer */ + wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, len); + + acx = buf; + if (acx->cmd.status != CMD_STATUS_SUCCESS) + wl1271_error("INTERROGATE command error: %d", + acx->cmd.status); + +out: + return ret; +} + +/** + * write acx value to firmware + * + * @wl: wl struct + * @id: acx id + * @buf: buffer containing acx, including all headers, must work with dma + * @len: length of buf + */ +int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) +{ + struct acx_header *acx = buf; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd configure"); + + acx->id = id; + + /* payload length, does not include any headers */ + acx->len = len - sizeof(*acx); + + ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len); + if (ret < 0) { + wl1271_warning("CONFIGURE command NOK"); + return ret; + } + + return 0; +} + +int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable) +{ + struct cmd_enabledisable_path *cmd; + int ret; + u16 cmd_rx, cmd_tx; + + wl1271_debug(DEBUG_CMD, "cmd data path"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->channel = channel; + + if (enable) { + cmd_rx = CMD_ENABLE_RX; + cmd_tx = CMD_ENABLE_TX; + } else { + cmd_rx = CMD_DISABLE_RX; + cmd_tx = CMD_DISABLE_TX; + } + + ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1271_error("rx %s cmd for channel %d failed", + enable ? "start" : "stop", channel); + goto out; + } + + wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d", + enable ? "start" : "stop", channel); + + ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1271_error("tx %s cmd for channel %d failed", + enable ? "start" : "stop", channel); + return ret; + } + + wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d", + enable ? "start" : "stop", channel); + +out: + kfree(cmd); + return ret; +} + +int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode) +{ + struct wl1271_cmd_ps_params *ps_params = NULL; + int ret = 0; + + /* FIXME: this should be in ps.c */ + ret = wl1271_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, + wl->listen_int); + if (ret < 0) { + wl1271_error("couldn't set wake up conditions"); + goto out; + } + + wl1271_debug(DEBUG_CMD, "cmd set ps mode"); + + ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); + if (!ps_params) { + ret = -ENOMEM; + goto out; + } + + ps_params->ps_mode = ps_mode; + ps_params->send_null_data = 1; + ps_params->retries = 5; + ps_params->hang_over_period = 128; + ps_params->null_data_rate = 1; /* 1 Mbps */ + + ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, + sizeof(*ps_params)); + if (ret < 0) { + wl1271_error("cmd set_ps_mode failed"); + goto out; + } + +out: + kfree(ps_params); + return ret; +} + +int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, + size_t len) +{ + struct cmd_read_write_memory *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd read memory"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + WARN_ON(len > MAX_READ_SIZE); + len = min_t(size_t, len, MAX_READ_SIZE); + + cmd->addr = addr; + cmd->size = len; + + ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1271_error("read memory command failed: %d", ret); + goto out; + } + + /* the read command got in, we can now read the answer */ + wl1271_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); + + if (cmd->header.status != CMD_STATUS_SUCCESS) + wl1271_error("error in read command result: %d", + cmd->header.status); + + memcpy(answer, cmd->value, len); + +out: + kfree(cmd); + return ret; +} + +int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, + u8 active_scan, u8 high_prio, u8 num_channels, + u8 probe_requests) +{ + + struct wl1271_cmd_trigger_scan_to *trigger = NULL; + struct wl1271_cmd_scan *params = NULL; + int i, ret; + u16 scan_options = 0; + + if (wl->scanning) + return -EINVAL; + + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; + + params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); + params->params.rx_filter_options = + cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); + + if (!active_scan) + scan_options |= WL1271_SCAN_OPT_PASSIVE; + if (high_prio) + scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH; + params->params.scan_options = scan_options; + + params->params.num_channels = num_channels; + params->params.num_probe_requests = probe_requests; + params->params.tx_rate = cpu_to_le32(RATE_MASK_2MBPS); + params->params.tid_trigger = 0; + params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; + + for (i = 0; i < num_channels; i++) { + params->channels[i].min_duration = + cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION); + params->channels[i].max_duration = + cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION); + memset(¶ms->channels[i].bssid_lsb, 0xff, 4); + memset(¶ms->channels[i].bssid_msb, 0xff, 2); + params->channels[i].early_termination = 0; + params->channels[i].tx_power_att = WL1271_SCAN_CURRENT_TX_PWR; + params->channels[i].channel = i + 1; + } + + if (len && ssid) { + params->params.ssid_len = len; + memcpy(params->params.ssid, ssid, len); + } + + ret = wl1271_cmd_build_probe_req(wl, ssid, len); + if (ret < 0) { + wl1271_error("PROBE request template failed"); + goto out; + } + + trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); + if (!trigger) { + ret = -ENOMEM; + goto out; + } + + /* disable the timeout */ + trigger->timeout = 0; + + ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, + sizeof(*trigger)); + if (ret < 0) { + wl1271_error("trigger scan to failed for hw scan"); + goto out; + } + + wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); + + wl->scanning = true; + + ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); + if (ret < 0) { + wl1271_error("SCAN failed"); + goto out; + } + + wl1271_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); + + if (params->header.status != CMD_STATUS_SUCCESS) { + wl1271_error("Scan command error: %d", + params->header.status); + wl->scanning = false; + ret = -EIO; + goto out; + } + +out: + kfree(params); + return ret; +} + +int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, + void *buf, size_t buf_len) +{ + struct wl1271_cmd_template_set *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id); + + WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE); + buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->len = cpu_to_le16(buf_len); + cmd->template_type = template_id; + cmd->enabled_rates = ACX_RATE_MASK_UNSPECIFIED; + cmd->short_retry_limit = ACX_RATE_RETRY_LIMIT; + cmd->long_retry_limit = ACX_RATE_RETRY_LIMIT; + + if (buf) + memcpy(cmd->template_data, buf, buf_len); + + ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1271_warning("cmd set_template failed: %d", ret); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +static int wl1271_build_basic_rates(char *rates) +{ + u8 index = 0; + + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; + + return index; +} + +static int wl1271_build_extended_rates(char *rates) +{ + u8 index = 0; + + rates[index++] = IEEE80211_OFDM_RATE_6MB; + rates[index++] = IEEE80211_OFDM_RATE_9MB; + rates[index++] = IEEE80211_OFDM_RATE_12MB; + rates[index++] = IEEE80211_OFDM_RATE_18MB; + rates[index++] = IEEE80211_OFDM_RATE_24MB; + rates[index++] = IEEE80211_OFDM_RATE_36MB; + rates[index++] = IEEE80211_OFDM_RATE_48MB; + rates[index++] = IEEE80211_OFDM_RATE_54MB; + + return index; +} + +int wl1271_cmd_build_null_data(struct wl1271 *wl) +{ + struct wl12xx_null_data_template template; + + if (!is_zero_ether_addr(wl->bssid)) { + memcpy(template.header.da, wl->bssid, ETH_ALEN); + memcpy(template.header.bssid, wl->bssid, ETH_ALEN); + } else { + memset(template.header.da, 0xff, ETH_ALEN); + memset(template.header.bssid, 0xff, ETH_ALEN); + } + + memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); + template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_NULLFUNC); + + return wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, &template, + sizeof(template)); + +} + +int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid) +{ + struct wl12xx_ps_poll_template template; + + memcpy(template.bssid, wl->bssid, ETH_ALEN); + memcpy(template.ta, wl->mac_addr, ETH_ALEN); + template.aid = aid; + template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); + + return wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, &template, + sizeof(template)); + +} + +int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len) +{ + struct wl12xx_probe_req_template template; + struct wl12xx_ie_rates *rates; + char *ptr; + u16 size; + + ptr = (char *)&template; + size = sizeof(struct ieee80211_header); + + memset(template.header.da, 0xff, ETH_ALEN); + memset(template.header.bssid, 0xff, ETH_ALEN); + memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); + template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); + + /* IEs */ + /* SSID */ + template.ssid.header.id = WLAN_EID_SSID; + template.ssid.header.len = ssid_len; + if (ssid_len && ssid) + memcpy(template.ssid.ssid, ssid, ssid_len); + size += sizeof(struct wl12xx_ie_header) + ssid_len; + ptr += size; + + /* Basic Rates */ + rates = (struct wl12xx_ie_rates *)ptr; + rates->header.id = WLAN_EID_SUPP_RATES; + rates->header.len = wl1271_build_basic_rates(rates->rates); + size += sizeof(struct wl12xx_ie_header) + rates->header.len; + ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; + + /* Extended rates */ + rates = (struct wl12xx_ie_rates *)ptr; + rates->header.id = WLAN_EID_EXT_SUPP_RATES; + rates->header.len = wl1271_build_extended_rates(rates->rates); + size += sizeof(struct wl12xx_ie_header) + rates->header.len; + + wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); + + return wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, + &template, size); +} + +int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) +{ + struct wl1271_cmd_set_keys *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->id = id; + cmd->key_action = KEY_SET_ID; + cmd->key_type = KEY_WEP; + + ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1271_warning("cmd set_default_wep_key failed: %d", ret); + goto out; + } + +out: + kfree(cmd); + + return ret; +} + +int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, + u8 key_size, const u8 *key, const u8 *addr) +{ + struct wl1271_cmd_set_keys *cmd; + int ret = 0; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + if (key_type != KEY_WEP) + memcpy(cmd->addr, addr, ETH_ALEN); + + cmd->key_action = action; + cmd->key_size = key_size; + cmd->key_type = key_type; + + /* we have only one SSID profile */ + cmd->ssid_profile = 0; + + cmd->id = id; + + /* FIXME: this is from wl1251, needs to be checked */ + if (key_type == KEY_TKIP) { + /* + * We get the key in the following form: + * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) + * but the target is expecting: + * TKIP - RX MIC - TX MIC + */ + memcpy(cmd->key, key, 16); + memcpy(cmd->key + 16, key + 24, 8); + memcpy(cmd->key + 24, key + 16, 8); + + } else { + memcpy(cmd->key, key, key_size); + } + + wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd)); + + ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1271_warning("could not set keys"); + goto out; + } + +out: + kfree(cmd); + + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h new file mode 100644 index 00000000000..951a8447a51 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -0,0 +1,464 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1271_CMD_H__ +#define __WL1271_CMD_H__ + +#include "wl1271.h" + +struct acx_header; + +int wl1271_cmd_send(struct wl1271 *wl, u16 type, void *buf, size_t buf_len); +int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval, + u16 beacon_interval, u8 wait); +int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); +int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); +int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); +int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable); +int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode); +int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, + size_t len); +int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, + u8 active_scan, u8 high_prio, u8 num_channels, + u8 probe_requests); +int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, + void *buf, size_t buf_len); +int wl1271_cmd_build_null_data(struct wl1271 *wl); +int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid); +int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len); +int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id); +int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, + u8 key_size, const u8 *key, const u8 *addr); + +enum wl1271_commands { + CMD_INTERROGATE = 1, /*use this to read information elements*/ + CMD_CONFIGURE = 2, /*use this to write information elements*/ + CMD_ENABLE_RX = 3, + CMD_ENABLE_TX = 4, + CMD_DISABLE_RX = 5, + CMD_DISABLE_TX = 6, + CMD_SCAN = 8, + CMD_STOP_SCAN = 9, + CMD_START_JOIN = 11, + CMD_SET_KEYS = 12, + CMD_READ_MEMORY = 13, + CMD_WRITE_MEMORY = 14, + CMD_SET_TEMPLATE = 19, + CMD_TEST = 23, + CMD_NOISE_HIST = 28, + CMD_LNA_CONTROL = 32, + CMD_SET_BCN_MODE = 33, + CMD_MEASUREMENT = 34, + CMD_STOP_MEASUREMENT = 35, + CMD_DISCONNECT = 36, + CMD_SET_PS_MODE = 37, + CMD_CHANNEL_SWITCH = 38, + CMD_STOP_CHANNEL_SWICTH = 39, + CMD_AP_DISCOVERY = 40, + CMD_STOP_AP_DISCOVERY = 41, + CMD_SPS_SCAN = 42, + CMD_STOP_SPS_SCAN = 43, + CMD_HEALTH_CHECK = 45, + CMD_DEBUG = 46, + CMD_TRIGGER_SCAN_TO = 47, + CMD_CONNECTION_SCAN_CFG = 48, + CMD_CONNECTION_SCAN_SSID_CFG = 49, + CMD_START_PERIODIC_SCAN = 50, + CMD_STOP_PERIODIC_SCAN = 51, + CMD_SET_STA_STATE = 52, + + NUM_COMMANDS, + MAX_COMMAND_ID = 0xFFFF, +}; + +#define MAX_CMD_PARAMS 572 + +enum cmd_templ { + CMD_TEMPL_NULL_DATA = 0, + CMD_TEMPL_BEACON, + CMD_TEMPL_CFG_PROBE_REQ_2_4, + CMD_TEMPL_CFG_PROBE_REQ_5, + CMD_TEMPL_PROBE_RESPONSE, + CMD_TEMPL_QOS_NULL_DATA, + CMD_TEMPL_PS_POLL, + CMD_TEMPL_KLV, + CMD_TEMPL_DISCONNECT, + CMD_TEMPL_PROBE_REQ_2_4, /* for firmware internal use only */ + CMD_TEMPL_PROBE_REQ_5, /* for firmware internal use only */ + CMD_TEMPL_BAR, /* for firmware internal use only */ + CMD_TEMPL_CTS, /* + * For CTS-to-self (FastCTS) mechanism + * for BT/WLAN coexistence (SoftGemini). */ + CMD_TEMPL_MAX = 0xff +}; + +/* unit ms */ +#define WL1271_COMMAND_TIMEOUT 2000 +#define WL1271_CMD_TEMPL_MAX_SIZE 252 + +struct wl1271_cmd_header { + u16 id; + u16 status; + /* payload */ + u8 data[0]; +} __attribute__ ((packed)); + +#define WL1271_CMD_MAX_PARAMS 572 + +struct wl1271_command { + struct wl1271_cmd_header header; + u8 parameters[WL1271_CMD_MAX_PARAMS]; +} __attribute__ ((packed)); + +enum { + CMD_MAILBOX_IDLE = 0, + CMD_STATUS_SUCCESS = 1, + CMD_STATUS_UNKNOWN_CMD = 2, + CMD_STATUS_UNKNOWN_IE = 3, + CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11, + CMD_STATUS_RX_BUSY = 13, + CMD_STATUS_INVALID_PARAM = 14, + CMD_STATUS_TEMPLATE_TOO_LARGE = 15, + CMD_STATUS_OUT_OF_MEMORY = 16, + CMD_STATUS_STA_TABLE_FULL = 17, + CMD_STATUS_RADIO_ERROR = 18, + CMD_STATUS_WRONG_NESTING = 19, + CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ + CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ + MAX_COMMAND_STATUS = 0xff +}; + + +/* + * CMD_READ_MEMORY + * + * The host issues this command to read the WiLink device memory/registers. + * + * Note: The Base Band address has special handling (16 bits registers and + * addresses). For more information, see the hardware specification. + */ +/* + * CMD_WRITE_MEMORY + * + * The host issues this command to write the WiLink device memory/registers. + * + * The Base Band address has special handling (16 bits registers and + * addresses). For more information, see the hardware specification. + */ +#define MAX_READ_SIZE 256 + +struct cmd_read_write_memory { + struct wl1271_cmd_header header; + + /* The address of the memory to read from or write to.*/ + u32 addr; + + /* The amount of data in bytes to read from or write to the WiLink + * device.*/ + u32 size; + + /* The actual value read from or written to the Wilink. The source + of this field is the Host in WRITE command or the Wilink in READ + command. */ + u8 value[MAX_READ_SIZE]; +}; + +#define CMDMBOX_HEADER_LEN 4 +#define CMDMBOX_INFO_ELEM_HEADER_LEN 4 + +enum { + BSS_TYPE_IBSS = 0, + BSS_TYPE_STA_BSS = 2, + BSS_TYPE_AP_BSS = 3, + MAX_BSS_TYPE = 0xFF +}; + +#define WL1271_JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ +#define WL1271_JOIN_CMD_TX_SESSION_OFFSET 1 + +struct wl1271_cmd_join { + struct wl1271_cmd_header header; + + u32 bssid_lsb; + u16 bssid_msb; + u16 beacon_interval; /* in TBTTs */ + u32 rx_config_options; + u32 rx_filter_options; + + /* + * The target uses this field to determine the rate at + * which to transmit control frame responses (such as + * ACK or CTS frames). + */ + u32 basic_rate_set; + u8 dtim_interval; + /* + * bits 0-2: This bitwise field specifies the type + * of BSS to start or join (BSS_TYPE_*). + * bit 4: Band - The radio band in which to join + * or start. + * 0 - 2.4GHz band + * 1 - 5GHz band + * bits 3, 5-7: Reserved + */ + u8 bss_type; + u8 channel; + u8 ssid_len; + u8 ssid[IW_ESSID_MAX_SIZE]; + u8 ctrl; /* JOIN_CMD_CTRL_* */ + u8 reserved[3]; +} __attribute__ ((packed)); + +struct cmd_enabledisable_path { + struct wl1271_cmd_header header; + + u8 channel; + u8 padding[3]; +} __attribute__ ((packed)); + +struct wl1271_cmd_template_set { + struct wl1271_cmd_header header; + + u16 len; + u8 template_type; + u8 index; /* relevant only for KLV_TEMPLATE type */ + u32 enabled_rates; + u8 short_retry_limit; + u8 long_retry_limit; + u8 aflags; + u8 reserved; + u8 template_data[WL1271_CMD_TEMPL_MAX_SIZE]; +} __attribute__ ((packed)); + +#define TIM_ELE_ID 5 +#define PARTIAL_VBM_MAX 251 + +struct wl1271_tim { + u8 identity; + u8 length; + u8 dtim_count; + u8 dtim_period; + u8 bitmap_ctrl; + u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ +} __attribute__ ((packed)); + +enum wl1271_cmd_ps_mode { + STATION_ACTIVE_MODE, + STATION_POWER_SAVE_MODE +}; + +struct wl1271_cmd_ps_params { + struct wl1271_cmd_header header; + + u8 ps_mode; /* STATION_* */ + u8 send_null_data; /* Do we have to send NULL data packet ? */ + u8 retries; /* Number of retires for the initial NULL data packet */ + + /* + * TUs during which the target stays awake after switching + * to power save mode. + */ + u8 hang_over_period; + u32 null_data_rate; +} __attribute__ ((packed)); + +/* HW encryption keys */ +#define NUM_ACCESS_CATEGORIES_COPY 4 +#define MAX_KEY_SIZE 32 + +/* When set, disable HW encryption */ +#define DF_ENCRYPTION_DISABLE 0x01 +/* When set, disable HW decryption */ +#define DF_SNIFF_MODE_ENABLE 0x80 + +enum wl1271_cmd_key_action { + KEY_ADD_OR_REPLACE = 1, + KEY_REMOVE = 2, + KEY_SET_ID = 3, + MAX_KEY_ACTION = 0xffff, +}; + +enum wl1271_cmd_key_type { + KEY_NONE = 0, + KEY_WEP = 1, + KEY_TKIP = 2, + KEY_AES = 3, + KEY_GEM = 4 +}; + +/* FIXME: Add description for key-types */ + +struct wl1271_cmd_set_keys { + struct wl1271_cmd_header header; + + /* Ignored for default WEP key */ + u8 addr[ETH_ALEN]; + + /* key_action_e */ + u16 key_action; + + u16 reserved_1; + + /* key size in bytes */ + u8 key_size; + + /* key_type_e */ + u8 key_type; + u8 ssid_profile; + + /* + * TKIP, AES: frame's key id field. + * For WEP default key: key id; + */ + u8 id; + u8 reserved_2[6]; + u8 key[MAX_KEY_SIZE]; + u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; + u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; +} __attribute__ ((packed)); + + +#define WL1271_SCAN_MAX_CHANNELS 24 +#define WL1271_SCAN_DEFAULT_TAG 1 +#define WL1271_SCAN_CURRENT_TX_PWR 0 +#define WL1271_SCAN_OPT_ACTIVE 0 +#define WL1271_SCAN_OPT_PASSIVE 1 +#define WL1271_SCAN_OPT_PRIORITY_HIGH 4 +#define WL1271_SCAN_CHAN_MIN_DURATION 30000 /* TU */ +#define WL1271_SCAN_CHAN_MAX_DURATION 60000 /* TU */ + +struct basic_scan_params { + u32 rx_config_options; + u32 rx_filter_options; + /* Scan option flags (WL1271_SCAN_OPT_*) */ + u16 scan_options; + /* Number of scan channels in the list (maximum 30) */ + u8 num_channels; + /* This field indicates the number of probe requests to send + per channel for an active scan */ + u8 num_probe_requests; + /* Rate bit field for sending the probes */ + u32 tx_rate; + u8 tid_trigger; + u8 ssid_len; + /* in order to align */ + u8 padding1[2]; + u8 ssid[IW_ESSID_MAX_SIZE]; + /* Band to scan */ + u8 band; + u8 use_ssid_list; + u8 scan_tag; + u8 padding2; +} __attribute__ ((packed)); + +struct basic_scan_channel_params { + /* Duration in TU to wait for frames on a channel for active scan */ + u32 min_duration; + u32 max_duration; + u32 bssid_lsb; + u16 bssid_msb; + u8 early_termination; + u8 tx_power_att; + u8 channel; + /* FW internal use only! */ + u8 dfs_candidate; + u8 activity_detected; + u8 pad; +} __attribute__ ((packed)); + +struct wl1271_cmd_scan { + struct wl1271_cmd_header header; + + struct basic_scan_params params; + struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS]; +} __attribute__ ((packed)); + +struct wl1271_cmd_trigger_scan_to { + struct wl1271_cmd_header header; + + u32 timeout; +}; + +struct wl1271_cmd_test_header { + u8 id; + u8 padding[3]; +}; + +enum wl1271_channel_tune_bands { + WL1271_CHANNEL_TUNE_BAND_2_4, + WL1271_CHANNEL_TUNE_BAND_5, + WL1271_CHANNEL_TUNE_BAND_4_9 +}; + +#define WL1271_PD_REFERENCE_POINT_BAND_B_G 0 + +#define TEST_CMD_P2G_CAL 0x02 +#define TEST_CMD_CHANNEL_TUNE 0x0d +#define TEST_CMD_UPDATE_PD_REFERENCE_POINT 0x1d + +struct wl1271_cmd_cal_channel_tune { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + u8 band; + u8 channel; + + u16 radio_status; +} __attribute__ ((packed)); + +struct wl1271_cmd_cal_update_ref_point { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + s32 ref_power; + s32 ref_detector; + u8 sub_band; + u8 padding[3]; +} __attribute__ ((packed)); + +#define MAX_TLV_LENGTH 400 +#define MAX_NVS_VERSION_LENGTH 12 + +#define WL1271_CAL_P2G_BAND_B_G BIT(0) + +struct wl1271_cmd_cal_p2g { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + u16 len; + u8 buf[MAX_TLV_LENGTH]; + u8 type; + u8 padding; + + s16 radio_status; + u8 nvs_version[MAX_NVS_VERSION_LENGTH]; + + u8 sub_band_mask; + u8 padding2; +} __attribute__ ((packed)); + +#endif /* __WL1271_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1271_debugfs.c b/drivers/net/wireless/wl12xx/wl1271_debugfs.c new file mode 100644 index 00000000000..c1805e5f896 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_debugfs.c @@ -0,0 +1,518 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl1271_debugfs.h" + +#include + +#include "wl1271.h" +#include "wl1271_acx.h" +#include "wl1271_ps.h" + +/* ms */ +#define WL1271_DEBUGFS_STATS_LIFETIME 1000 + +/* debugfs macros idea from mac80211 */ + +#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ +static ssize_t name## _read(struct file *file, char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + struct wl1271 *wl = file->private_data; \ + char buf[buflen]; \ + int res; \ + \ + res = scnprintf(buf, buflen, fmt "\n", ##value); \ + return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ +} \ + \ +static const struct file_operations name## _ops = { \ + .read = name## _read, \ + .open = wl1271_open_file_generic, \ +}; + +#define DEBUGFS_ADD(name, parent) \ + wl->debugfs.name = debugfs_create_file(#name, 0400, parent, \ + wl, &name## _ops); \ + if (IS_ERR(wl->debugfs.name)) { \ + ret = PTR_ERR(wl->debugfs.name); \ + wl->debugfs.name = NULL; \ + goto out; \ + } + +#define DEBUGFS_DEL(name) \ + do { \ + debugfs_remove(wl->debugfs.name); \ + wl->debugfs.name = NULL; \ + } while (0) + +#define DEBUGFS_FWSTATS_FILE(sub, name, buflen, fmt) \ +static ssize_t sub## _ ##name## _read(struct file *file, \ + char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + struct wl1271 *wl = file->private_data; \ + char buf[buflen]; \ + int res; \ + \ + wl1271_debugfs_update_stats(wl); \ + \ + res = scnprintf(buf, buflen, fmt "\n", \ + wl->stats.fw_stats->sub.name); \ + return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ +} \ + \ +static const struct file_operations sub## _ ##name## _ops = { \ + .read = sub## _ ##name## _read, \ + .open = wl1271_open_file_generic, \ +}; + +#define DEBUGFS_FWSTATS_ADD(sub, name) \ + DEBUGFS_ADD(sub## _ ##name, wl->debugfs.fw_statistics) + +#define DEBUGFS_FWSTATS_DEL(sub, name) \ + DEBUGFS_DEL(sub## _ ##name) + +static void wl1271_debugfs_update_stats(struct wl1271 *wl) +{ + int ret; + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + if (wl->state == WL1271_STATE_ON && + time_after(jiffies, wl->stats.fw_stats_update + + msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) { + wl1271_acx_statistics(wl, wl->stats.fw_stats); + wl->stats.fw_stats_update = jiffies; + } + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +static int wl1271_open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, hw_stuck, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, dropped, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, fcs_err, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, path_reset, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, reset_counter, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(dma, rx_requested, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, rx_errors, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, tx_requested, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, tx_errors, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, fiqs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_headers, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_rdys, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, irqs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, tx_procs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, decrypt_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, dma0_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, dma1_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, commands, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_procs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, pci_pm, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, wakeups, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, low_rssi, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(wep, addr_key_count, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, default_key_count, 20, "%u"); +/* skipping wep.reserved */ +DEBUGFS_FWSTATS_FILE(wep, key_not_found, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, interrupt, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(pwr, ps_enter, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, elp_enter, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, power_save_off, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, enable_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, disable_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, 20, "%u"); +/* skipping cont_miss_bcns_spread for now */ +DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(mic, rx_pkts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(mic, calc_failure, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(event, heart_beat, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, calibration, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_mismatch, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_pool, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, oom_late, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, tx_stuck, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, + 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, 20, "%u"); + +DEBUGFS_READONLY_FILE(retry_count, 20, "%u", wl->stats.retry_count); +DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u", + wl->stats.excessive_retries); + +static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + u32 queue_len; + char buf[20]; + int res; + + queue_len = skb_queue_len(&wl->tx_queue); + + res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); + return simple_read_from_buffer(userbuf, count, ppos, buf, res); +} + +static const struct file_operations tx_queue_len_ops = { + .read = tx_queue_len_read, + .open = wl1271_open_file_generic, +}; + +static void wl1271_debugfs_delete_files(struct wl1271 *wl) +{ + DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); + + DEBUGFS_FWSTATS_DEL(rx, out_of_mem); + DEBUGFS_FWSTATS_DEL(rx, hdr_overflow); + DEBUGFS_FWSTATS_DEL(rx, hw_stuck); + DEBUGFS_FWSTATS_DEL(rx, dropped); + DEBUGFS_FWSTATS_DEL(rx, fcs_err); + DEBUGFS_FWSTATS_DEL(rx, xfr_hint_trig); + DEBUGFS_FWSTATS_DEL(rx, path_reset); + DEBUGFS_FWSTATS_DEL(rx, reset_counter); + + DEBUGFS_FWSTATS_DEL(dma, rx_requested); + DEBUGFS_FWSTATS_DEL(dma, rx_errors); + DEBUGFS_FWSTATS_DEL(dma, tx_requested); + DEBUGFS_FWSTATS_DEL(dma, tx_errors); + + DEBUGFS_FWSTATS_DEL(isr, cmd_cmplt); + DEBUGFS_FWSTATS_DEL(isr, fiqs); + DEBUGFS_FWSTATS_DEL(isr, rx_headers); + DEBUGFS_FWSTATS_DEL(isr, rx_mem_overflow); + DEBUGFS_FWSTATS_DEL(isr, rx_rdys); + DEBUGFS_FWSTATS_DEL(isr, irqs); + DEBUGFS_FWSTATS_DEL(isr, tx_procs); + DEBUGFS_FWSTATS_DEL(isr, decrypt_done); + DEBUGFS_FWSTATS_DEL(isr, dma0_done); + DEBUGFS_FWSTATS_DEL(isr, dma1_done); + DEBUGFS_FWSTATS_DEL(isr, tx_exch_complete); + DEBUGFS_FWSTATS_DEL(isr, commands); + DEBUGFS_FWSTATS_DEL(isr, rx_procs); + DEBUGFS_FWSTATS_DEL(isr, hw_pm_mode_changes); + DEBUGFS_FWSTATS_DEL(isr, host_acknowledges); + DEBUGFS_FWSTATS_DEL(isr, pci_pm); + DEBUGFS_FWSTATS_DEL(isr, wakeups); + DEBUGFS_FWSTATS_DEL(isr, low_rssi); + + DEBUGFS_FWSTATS_DEL(wep, addr_key_count); + DEBUGFS_FWSTATS_DEL(wep, default_key_count); + /* skipping wep.reserved */ + DEBUGFS_FWSTATS_DEL(wep, key_not_found); + DEBUGFS_FWSTATS_DEL(wep, decrypt_fail); + DEBUGFS_FWSTATS_DEL(wep, packets); + DEBUGFS_FWSTATS_DEL(wep, interrupt); + + DEBUGFS_FWSTATS_DEL(pwr, ps_enter); + DEBUGFS_FWSTATS_DEL(pwr, elp_enter); + DEBUGFS_FWSTATS_DEL(pwr, missing_bcns); + DEBUGFS_FWSTATS_DEL(pwr, wake_on_host); + DEBUGFS_FWSTATS_DEL(pwr, wake_on_timer_exp); + DEBUGFS_FWSTATS_DEL(pwr, tx_with_ps); + DEBUGFS_FWSTATS_DEL(pwr, tx_without_ps); + DEBUGFS_FWSTATS_DEL(pwr, rcvd_beacons); + DEBUGFS_FWSTATS_DEL(pwr, power_save_off); + DEBUGFS_FWSTATS_DEL(pwr, enable_ps); + DEBUGFS_FWSTATS_DEL(pwr, disable_ps); + DEBUGFS_FWSTATS_DEL(pwr, fix_tsf_ps); + /* skipping cont_miss_bcns_spread for now */ + DEBUGFS_FWSTATS_DEL(pwr, rcvd_awake_beacons); + + DEBUGFS_FWSTATS_DEL(mic, rx_pkts); + DEBUGFS_FWSTATS_DEL(mic, calc_failure); + + DEBUGFS_FWSTATS_DEL(aes, encrypt_fail); + DEBUGFS_FWSTATS_DEL(aes, decrypt_fail); + DEBUGFS_FWSTATS_DEL(aes, encrypt_packets); + DEBUGFS_FWSTATS_DEL(aes, decrypt_packets); + DEBUGFS_FWSTATS_DEL(aes, encrypt_interrupt); + DEBUGFS_FWSTATS_DEL(aes, decrypt_interrupt); + + DEBUGFS_FWSTATS_DEL(event, heart_beat); + DEBUGFS_FWSTATS_DEL(event, calibration); + DEBUGFS_FWSTATS_DEL(event, rx_mismatch); + DEBUGFS_FWSTATS_DEL(event, rx_mem_empty); + DEBUGFS_FWSTATS_DEL(event, rx_pool); + DEBUGFS_FWSTATS_DEL(event, oom_late); + DEBUGFS_FWSTATS_DEL(event, phy_transmit_error); + DEBUGFS_FWSTATS_DEL(event, tx_stuck); + + DEBUGFS_FWSTATS_DEL(ps, pspoll_timeouts); + DEBUGFS_FWSTATS_DEL(ps, upsd_timeouts); + DEBUGFS_FWSTATS_DEL(ps, upsd_max_sptime); + DEBUGFS_FWSTATS_DEL(ps, upsd_max_apturn); + DEBUGFS_FWSTATS_DEL(ps, pspoll_max_apturn); + DEBUGFS_FWSTATS_DEL(ps, pspoll_utilization); + DEBUGFS_FWSTATS_DEL(ps, upsd_utilization); + + DEBUGFS_FWSTATS_DEL(rxpipe, rx_prep_beacon_drop); + DEBUGFS_FWSTATS_DEL(rxpipe, descr_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, missed_beacon_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data); + + DEBUGFS_DEL(tx_queue_len); + DEBUGFS_DEL(retry_count); + DEBUGFS_DEL(excessive_retries); +} + +static int wl1271_debugfs_add_files(struct wl1271 *wl) +{ + int ret = 0; + + DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow); + + DEBUGFS_FWSTATS_ADD(rx, out_of_mem); + DEBUGFS_FWSTATS_ADD(rx, hdr_overflow); + DEBUGFS_FWSTATS_ADD(rx, hw_stuck); + DEBUGFS_FWSTATS_ADD(rx, dropped); + DEBUGFS_FWSTATS_ADD(rx, fcs_err); + DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig); + DEBUGFS_FWSTATS_ADD(rx, path_reset); + DEBUGFS_FWSTATS_ADD(rx, reset_counter); + + DEBUGFS_FWSTATS_ADD(dma, rx_requested); + DEBUGFS_FWSTATS_ADD(dma, rx_errors); + DEBUGFS_FWSTATS_ADD(dma, tx_requested); + DEBUGFS_FWSTATS_ADD(dma, tx_errors); + + DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt); + DEBUGFS_FWSTATS_ADD(isr, fiqs); + DEBUGFS_FWSTATS_ADD(isr, rx_headers); + DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow); + DEBUGFS_FWSTATS_ADD(isr, rx_rdys); + DEBUGFS_FWSTATS_ADD(isr, irqs); + DEBUGFS_FWSTATS_ADD(isr, tx_procs); + DEBUGFS_FWSTATS_ADD(isr, decrypt_done); + DEBUGFS_FWSTATS_ADD(isr, dma0_done); + DEBUGFS_FWSTATS_ADD(isr, dma1_done); + DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete); + DEBUGFS_FWSTATS_ADD(isr, commands); + DEBUGFS_FWSTATS_ADD(isr, rx_procs); + DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes); + DEBUGFS_FWSTATS_ADD(isr, host_acknowledges); + DEBUGFS_FWSTATS_ADD(isr, pci_pm); + DEBUGFS_FWSTATS_ADD(isr, wakeups); + DEBUGFS_FWSTATS_ADD(isr, low_rssi); + + DEBUGFS_FWSTATS_ADD(wep, addr_key_count); + DEBUGFS_FWSTATS_ADD(wep, default_key_count); + /* skipping wep.reserved */ + DEBUGFS_FWSTATS_ADD(wep, key_not_found); + DEBUGFS_FWSTATS_ADD(wep, decrypt_fail); + DEBUGFS_FWSTATS_ADD(wep, packets); + DEBUGFS_FWSTATS_ADD(wep, interrupt); + + DEBUGFS_FWSTATS_ADD(pwr, ps_enter); + DEBUGFS_FWSTATS_ADD(pwr, elp_enter); + DEBUGFS_FWSTATS_ADD(pwr, missing_bcns); + DEBUGFS_FWSTATS_ADD(pwr, wake_on_host); + DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp); + DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps); + DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps); + DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons); + DEBUGFS_FWSTATS_ADD(pwr, power_save_off); + DEBUGFS_FWSTATS_ADD(pwr, enable_ps); + DEBUGFS_FWSTATS_ADD(pwr, disable_ps); + DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps); + /* skipping cont_miss_bcns_spread for now */ + DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons); + + DEBUGFS_FWSTATS_ADD(mic, rx_pkts); + DEBUGFS_FWSTATS_ADD(mic, calc_failure); + + DEBUGFS_FWSTATS_ADD(aes, encrypt_fail); + DEBUGFS_FWSTATS_ADD(aes, decrypt_fail); + DEBUGFS_FWSTATS_ADD(aes, encrypt_packets); + DEBUGFS_FWSTATS_ADD(aes, decrypt_packets); + DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt); + DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt); + + DEBUGFS_FWSTATS_ADD(event, heart_beat); + DEBUGFS_FWSTATS_ADD(event, calibration); + DEBUGFS_FWSTATS_ADD(event, rx_mismatch); + DEBUGFS_FWSTATS_ADD(event, rx_mem_empty); + DEBUGFS_FWSTATS_ADD(event, rx_pool); + DEBUGFS_FWSTATS_ADD(event, oom_late); + DEBUGFS_FWSTATS_ADD(event, phy_transmit_error); + DEBUGFS_FWSTATS_ADD(event, tx_stuck); + + DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts); + DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts); + DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime); + DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn); + DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn); + DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization); + DEBUGFS_FWSTATS_ADD(ps, upsd_utilization); + + DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop); + DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); + + DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir); + DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); + DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); + +out: + if (ret < 0) + wl1271_debugfs_delete_files(wl); + + return ret; +} + +void wl1271_debugfs_reset(struct wl1271 *wl) +{ + memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); + wl->stats.retry_count = 0; + wl->stats.excessive_retries = 0; +} + +int wl1271_debugfs_init(struct wl1271 *wl) +{ + int ret; + + wl->debugfs.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); + + if (IS_ERR(wl->debugfs.rootdir)) { + ret = PTR_ERR(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + goto err; + } + + wl->debugfs.fw_statistics = debugfs_create_dir("fw-statistics", + wl->debugfs.rootdir); + + if (IS_ERR(wl->debugfs.fw_statistics)) { + ret = PTR_ERR(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + goto err_root; + } + + wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats), + GFP_KERNEL); + + if (!wl->stats.fw_stats) { + ret = -ENOMEM; + goto err_fw; + } + + wl->stats.fw_stats_update = jiffies; + + ret = wl1271_debugfs_add_files(wl); + + if (ret < 0) + goto err_file; + + return 0; + +err_file: + kfree(wl->stats.fw_stats); + wl->stats.fw_stats = NULL; + +err_fw: + debugfs_remove(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + +err_root: + debugfs_remove(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + +err: + return ret; +} + +void wl1271_debugfs_exit(struct wl1271 *wl) +{ + wl1271_debugfs_delete_files(wl); + + kfree(wl->stats.fw_stats); + wl->stats.fw_stats = NULL; + + debugfs_remove(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + + debugfs_remove(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + +} diff --git a/drivers/net/wireless/wl12xx/wl1271_debugfs.h b/drivers/net/wireless/wl12xx/wl1271_debugfs.h new file mode 100644 index 00000000000..00a45b2669a --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_debugfs.h @@ -0,0 +1,33 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef WL1271_DEBUGFS_H +#define WL1271_DEBUGFS_H + +#include "wl1271.h" + +int wl1271_debugfs_init(struct wl1271 *wl); +void wl1271_debugfs_exit(struct wl1271 *wl); +void wl1271_debugfs_reset(struct wl1271 *wl); + +#endif /* WL1271_DEBUGFS_H */ diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c new file mode 100644 index 00000000000..f3afd4a6ff3 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -0,0 +1,125 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl1271.h" +#include "wl1271_reg.h" +#include "wl1271_spi.h" +#include "wl1271_event.h" +#include "wl1271_ps.h" + +static int wl1271_event_scan_complete(struct wl1271 *wl, + struct event_mailbox *mbox) +{ + wl1271_debug(DEBUG_EVENT, "status: 0x%x", + mbox->scheduled_scan_status); + + if (wl->scanning) { + mutex_unlock(&wl->mutex); + ieee80211_scan_completed(wl->hw, false); + mutex_lock(&wl->mutex); + wl->scanning = false; + } + + return 0; +} + +static void wl1271_event_mbox_dump(struct event_mailbox *mbox) +{ + wl1271_debug(DEBUG_EVENT, "MBOX DUMP:"); + wl1271_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); + wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); +} + +static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) +{ + int ret; + u32 vector; + + wl1271_event_mbox_dump(mbox); + + vector = mbox->events_vector & ~(mbox->events_mask); + wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector); + + if (vector & SCAN_COMPLETE_EVENT_ID) { + ret = wl1271_event_scan_complete(wl, mbox); + if (ret < 0) + return ret; + } + + if (vector & BSS_LOSE_EVENT_ID) { + wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); + + if (wl->psm_requested && wl->psm) { + ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + return ret; + } + } + + return 0; +} + +int wl1271_event_unmask(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_event_mbox_mask(wl, ~(wl->event_mask)); + if (ret < 0) + return ret; + + return 0; +} + +void wl1271_event_mbox_config(struct wl1271 *wl) +{ + wl->mbox_ptr[0] = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR); + wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); + + wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", + wl->mbox_ptr[0], wl->mbox_ptr[1]); +} + +int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) +{ + struct event_mailbox mbox; + int ret; + + wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); + + if (mbox_num > 1) + return -EINVAL; + + /* first we read the mbox descriptor */ + wl1271_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, + sizeof(struct event_mailbox)); + + /* process the descriptor */ + ret = wl1271_event_process(wl, &mbox); + if (ret < 0) + return ret; + + /* then we let the firmware know it can go on...*/ + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); + + return 0; +} diff --git a/drivers/net/wireless/wl12xx/wl1271_event.h b/drivers/net/wireless/wl12xx/wl1271_event.h new file mode 100644 index 00000000000..2cdce7c34bf --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_event.h @@ -0,0 +1,110 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1271_EVENT_H__ +#define __WL1271_EVENT_H__ + +/* + * Mbox events + * + * The event mechanism is based on a pair of event buffers (buffers A and + * B) at fixed locations in the target's memory. The host processes one + * buffer while the other buffer continues to collect events. If the host + * is not processing events, an interrupt is issued to signal that a buffer + * is ready. Once the host is done with processing events from one buffer, + * it signals the target (with an ACK interrupt) that the event buffer is + * free. + */ + +enum { + MEASUREMENT_START_EVENT_ID = BIT(8), + MEASUREMENT_COMPLETE_EVENT_ID = BIT(9), + SCAN_COMPLETE_EVENT_ID = BIT(10), + SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(11), + AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12), + PS_REPORT_EVENT_ID = BIT(13), + PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14), + DISCONNECT_EVENT_COMPLETE_ID = BIT(15), + JOIN_EVENT_COMPLETE_ID = BIT(16), + CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), + BSS_LOSE_EVENT_ID = BIT(18), + REGAINED_BSS_EVENT_ID = BIT(19), + ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20), + SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), + SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), + SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), + PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25), + DBG_EVENT_ID = BIT(26), + HEALTH_CHECK_REPLY_EVENT_ID = BIT(27), + PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28), + PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29), + BA_SESSION_TEAR_DOWN_EVENT_ID = BIT(30), + EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, +}; + +struct event_debug_report { + u8 debug_event_id; + u8 num_params; + u16 pad; + u32 report_1; + u32 report_2; + u32 report_3; +} __attribute__ ((packed)); + +#define NUM_OF_RSSI_SNR_TRIGGERS 8 + +struct event_mailbox { + u32 events_vector; + u32 events_mask; + u32 reserved_1; + u32 reserved_2; + + u8 dbg_event_id; + u8 num_relevant_params; + u16 reserved_3; + u32 event_report_p1; + u32 event_report_p2; + u32 event_report_p3; + + u8 number_of_scan_results; + u8 scan_tag; + u8 reserved_4[2]; + u32 compl_scheduled_scan_status; + + u16 scheduled_scan_attended_channels; + u8 soft_gemini_sense_info; + u8 soft_gemini_protective_info; + s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS]; + u8 channel_switch_status; + u8 scheduled_scan_status; + u8 ps_status; + + u8 reserved_5[29]; +} __attribute__ ((packed)); + +int wl1271_event_unmask(struct wl1271 *wl); +void wl1271_event_mbox_config(struct wl1271 *wl); +int wl1271_event_handle(struct wl1271 *wl, u8 mbox); + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c new file mode 100644 index 00000000000..490df217605 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -0,0 +1,397 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "wl1271_init.h" +#include "wl12xx_80211.h" +#include "wl1271_acx.h" +#include "wl1271_cmd.h" +#include "wl1271_reg.h" + +static int wl1271_init_hwenc_config(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_feature_cfg(wl); + if (ret < 0) { + wl1271_warning("couldn't set feature config"); + return ret; + } + + ret = wl1271_cmd_set_default_wep_key(wl, wl->default_key); + if (ret < 0) { + wl1271_warning("couldn't set default key"); + return ret; + } + + return 0; +} + +static int wl1271_init_templates_config(struct wl1271 *wl) +{ + int ret; + + /* send empty templates for fw memory reservation */ + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, + sizeof(struct wl12xx_probe_req_template)); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL, + sizeof(struct wl12xx_null_data_template)); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, NULL, + sizeof(struct wl12xx_ps_poll_template)); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL, + sizeof + (struct wl12xx_qos_null_data_template)); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL, + sizeof + (struct wl12xx_probe_resp_template)); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL, + sizeof + (struct wl12xx_beacon_template)); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter) +{ + int ret; + + ret = wl1271_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); + if (ret < 0) + return ret; + + ret = wl1271_acx_rx_config(wl, config, filter); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_init_phy_config(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_pd_threshold(wl); + if (ret < 0) + return ret; + + ret = wl1271_acx_slot(wl, DEFAULT_SLOT_TIME); + if (ret < 0) + return ret; + + ret = wl1271_acx_group_address_tbl(wl); + if (ret < 0) + return ret; + + ret = wl1271_acx_service_period_timeout(wl); + if (ret < 0) + return ret; + + ret = wl1271_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_init_beacon_filter(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_beacon_filter_opt(wl); + if (ret < 0) + return ret; + + ret = wl1271_acx_beacon_filter_table(wl); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_init_pta(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_sg_enable(wl); + if (ret < 0) + return ret; + + ret = wl1271_acx_sg_cfg(wl); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_init_energy_detection(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_cca_threshold(wl); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_init_beacon_broadcast(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_bcn_dtim_options(wl); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_init_general_parms(struct wl1271 *wl) +{ + struct wl1271_general_parms *gen_parms; + int ret; + + gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); + if (!gen_parms) + return -ENOMEM; + + gen_parms->id = TEST_CMD_INI_FILE_GENERAL_PARAM; + + gen_parms->ref_clk = REF_CLK_38_4_E; + /* FIXME: magic numbers */ + gen_parms->settling_time = 5; + gen_parms->clk_valid_on_wakeup = 0; + gen_parms->dc2dcmode = 0; + gen_parms->single_dual_band = 0; + gen_parms->tx_bip_fem_autodetect = 1; + gen_parms->tx_bip_fem_manufacturer = 1; + gen_parms->settings = 1; + + ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0); + if (ret < 0) { + wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); + return ret; + } + + kfree(gen_parms); + return 0; +} + +static int wl1271_init_radio_parms(struct wl1271 *wl) +{ + /* + * FIXME: All these magic numbers should be moved to some place where + * they can be configured (separate file?) + */ + + struct wl1271_radio_parms *radio_parms; + int ret; + u8 compensation[] = { 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8, 0xfc, 0x00, + 0x08, 0x10, 0xf0, 0xf8, 0x00, 0x0a, 0x14 }; + + u8 tx_rate_limits_normal[] = { 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 }; + u8 tx_rate_limits_degraded[] = { 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 }; + + u8 tx_channel_limits_11b[] = { 0x22, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x22, 0x50, + 0x22, 0x50 }; + + u8 tx_channel_limits_ofdm[] = { 0x20, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x20, 0x50, + 0x20, 0x50 }; + + u8 tx_pdv_rate_offsets[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + u8 tx_ibias[] = { 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 }; + + radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); + if (!radio_parms) + return -ENOMEM; + + radio_parms->id = TEST_CMD_INI_FILE_RADIO_PARAM; + + /* Static radio parameters */ + radio_parms->rx_trace_loss = 10; + radio_parms->tx_trace_loss = 10; + memcpy(radio_parms->rx_rssi_and_proc_compens, compensation, + sizeof(compensation)); + + /* We don't set the 5GHz -- N/A */ + + /* Dynamic radio parameters */ + radio_parms->tx_ref_pd_voltage = cpu_to_le16(0x24e); + radio_parms->tx_ref_power = 0x78; + radio_parms->tx_offset_db = 0x0; + + memcpy(radio_parms->tx_rate_limits_normal, tx_rate_limits_normal, + sizeof(tx_rate_limits_normal)); + memcpy(radio_parms->tx_rate_limits_degraded, tx_rate_limits_degraded, + sizeof(tx_rate_limits_degraded)); + + memcpy(radio_parms->tx_channel_limits_11b, tx_channel_limits_11b, + sizeof(tx_channel_limits_11b)); + memcpy(radio_parms->tx_channel_limits_ofdm, tx_channel_limits_ofdm, + sizeof(tx_channel_limits_ofdm)); + memcpy(radio_parms->tx_pdv_rate_offsets, tx_pdv_rate_offsets, + sizeof(tx_pdv_rate_offsets)); + memcpy(radio_parms->tx_ibias, tx_ibias, + sizeof(tx_ibias)); + + radio_parms->rx_fem_insertion_loss = 0x14; + + ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); + if (ret < 0) + wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); + + kfree(radio_parms); + return ret; +} + +int wl1271_hw_init(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_init_general_parms(wl); + if (ret < 0) + return ret; + + ret = wl1271_init_radio_parms(wl); + if (ret < 0) + return ret; + + /* Template settings */ + ret = wl1271_init_templates_config(wl); + if (ret < 0) + return ret; + + /* Default memory configuration */ + ret = wl1271_acx_init_mem_config(wl); + if (ret < 0) + return ret; + + /* RX config */ + ret = wl1271_init_rx_config(wl, + RX_CFG_PROMISCUOUS | RX_CFG_TSF, + RX_FILTER_OPTION_DEF); + /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, + RX_FILTER_OPTION_FILTER_ALL); */ + if (ret < 0) + goto out_free_memmap; + + /* PHY layer config */ + ret = wl1271_init_phy_config(wl); + if (ret < 0) + goto out_free_memmap; + + /* Beacon filtering */ + ret = wl1271_init_beacon_filter(wl); + if (ret < 0) + goto out_free_memmap; + + /* Configure TX patch complete interrupt behavior */ + ret = wl1271_acx_tx_config_options(wl); + if (ret < 0) + goto out_free_memmap; + + /* RX complete interrupt pacing */ + ret = wl1271_acx_init_rx_interrupt(wl); + if (ret < 0) + goto out_free_memmap; + + /* Bluetooth WLAN coexistence */ + ret = wl1271_init_pta(wl); + if (ret < 0) + goto out_free_memmap; + + /* Energy detection */ + ret = wl1271_init_energy_detection(wl); + if (ret < 0) + goto out_free_memmap; + + /* Beacons and boradcast settings */ + ret = wl1271_init_beacon_broadcast(wl); + if (ret < 0) + goto out_free_memmap; + + /* Default fragmentation threshold */ + ret = wl1271_acx_frag_threshold(wl); + if (ret < 0) + goto out_free_memmap; + + /* Default TID configuration */ + ret = wl1271_acx_tid_cfg(wl); + if (ret < 0) + goto out_free_memmap; + + /* Default AC configuration */ + ret = wl1271_acx_ac_cfg(wl); + if (ret < 0) + goto out_free_memmap; + + /* Configure TX rate classes */ + ret = wl1271_acx_rate_policies(wl); + if (ret < 0) + goto out_free_memmap; + + /* Enable data path */ + ret = wl1271_cmd_data_path(wl, wl->channel, 1); + if (ret < 0) + goto out_free_memmap; + + /* Configure for ELP power saving */ + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); + if (ret < 0) + goto out_free_memmap; + + /* Configure HW encryption */ + ret = wl1271_init_hwenc_config(wl); + if (ret < 0) + goto out_free_memmap; + + return 0; + + out_free_memmap: + kfree(wl->target_mem_map); + + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1271_init.h b/drivers/net/wireless/wl12xx/wl1271_init.h new file mode 100644 index 00000000000..bd8ff0fa227 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_init.h @@ -0,0 +1,115 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1271_INIT_H__ +#define __WL1271_INIT_H__ + +#include "wl1271.h" + +int wl1271_hw_init_power_auth(struct wl1271 *wl); +int wl1271_hw_init(struct wl1271 *wl); + +/* These are not really a TEST_CMD, but the ref driver uses them as such */ +#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19 +#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E + +struct wl1271_general_parms { + u8 id; + u8 padding[3]; + + u8 ref_clk; + u8 settling_time; + u8 clk_valid_on_wakeup; + u8 dc2dcmode; + u8 single_dual_band; + + u8 tx_bip_fem_autodetect; + u8 tx_bip_fem_manufacturer; + u8 settings; +} __attribute__ ((packed)); + +enum ref_clk_enum { + REF_CLK_19_2_E, + REF_CLK_26_E, + REF_CLK_38_4_E, + REF_CLK_52_E +}; + +#define RSSI_AND_PROCESS_COMPENSATION_SIZE 15 +#define NUMBER_OF_SUB_BANDS_5 7 +#define NUMBER_OF_RATE_GROUPS 6 +#define NUMBER_OF_CHANNELS_2_4 14 +#define NUMBER_OF_CHANNELS_5 35 + +struct wl1271_radio_parms { + u8 id; + u8 padding[3]; + + /* Static radio parameters */ + /* 2.4GHz */ + u8 rx_trace_loss; + u8 tx_trace_loss; + s8 rx_rssi_and_proc_compens[RSSI_AND_PROCESS_COMPENSATION_SIZE]; + + /* 5GHz */ + u8 rx_trace_loss_5[NUMBER_OF_SUB_BANDS_5]; + u8 tx_trace_loss_5[NUMBER_OF_SUB_BANDS_5]; + s8 rx_rssi_and_proc_compens_5[RSSI_AND_PROCESS_COMPENSATION_SIZE]; + + /* Dynamic radio parameters */ + /* 2.4GHz */ + s16 tx_ref_pd_voltage; + s8 tx_ref_power; + s8 tx_offset_db; + + s8 tx_rate_limits_normal[NUMBER_OF_RATE_GROUPS]; + s8 tx_rate_limits_degraded[NUMBER_OF_RATE_GROUPS]; + + s8 tx_channel_limits_11b[NUMBER_OF_CHANNELS_2_4]; + s8 tx_channel_limits_ofdm[NUMBER_OF_CHANNELS_2_4]; + s8 tx_pdv_rate_offsets[NUMBER_OF_RATE_GROUPS]; + + u8 tx_ibias[NUMBER_OF_RATE_GROUPS]; + u8 rx_fem_insertion_loss; + + u8 padding2; + + /* 5GHz */ + s16 tx_ref_pd_voltage_5[NUMBER_OF_SUB_BANDS_5]; + s8 tx_ref_power_5[NUMBER_OF_SUB_BANDS_5]; + s8 tx_offset_db_5[NUMBER_OF_SUB_BANDS_5]; + + s8 tx_rate_limits_normal_5[NUMBER_OF_RATE_GROUPS]; + s8 tx_rate_limits_degraded_5[NUMBER_OF_RATE_GROUPS]; + + s8 tx_channel_limits_ofdm_5[NUMBER_OF_CHANNELS_5]; + s8 tx_pdv_rate_offsets_5[NUMBER_OF_RATE_GROUPS]; + + /* FIXME: this is inconsistent with the types for 2.4GHz */ + s8 tx_ibias_5[NUMBER_OF_RATE_GROUPS]; + s8 rx_fem_insertion_loss_5[NUMBER_OF_SUB_BANDS_5]; + + u8 padding3[2]; +} __attribute__ ((packed)); + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c new file mode 100644 index 00000000000..3bb45ced99a --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -0,0 +1,1396 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wl1271.h" +#include "wl12xx_80211.h" +#include "wl1271_reg.h" +#include "wl1271_spi.h" +#include "wl1271_event.h" +#include "wl1271_tx.h" +#include "wl1271_rx.h" +#include "wl1271_ps.h" +#include "wl1271_init.h" +#include "wl1271_debugfs.h" +#include "wl1271_cmd.h" +#include "wl1271_boot.h" + +static int wl1271_plt_init(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_init_mem_config(wl); + if (ret < 0) + return ret; + + ret = wl1271_cmd_data_path(wl, wl->channel, 1); + if (ret < 0) + return ret; + + return 0; +} + +static void wl1271_disable_interrupts(struct wl1271 *wl) +{ + disable_irq(wl->irq); +} + +static void wl1271_power_off(struct wl1271 *wl) +{ + wl->set_power(false); +} + +static void wl1271_power_on(struct wl1271 *wl) +{ + wl->set_power(true); +} + +static void wl1271_fw_status(struct wl1271 *wl, struct wl1271_fw_status *status) +{ + u32 total = 0; + int i; + + /* + * FIXME: Reading the FW status directly from the registers seems to + * be the right thing to do, but it doesn't work. And in the + * reference driver, there is a workaround called + * USE_SDIO_24M_WORKAROUND, which reads the status from memory + * instead, so we do the same here. + */ + + wl1271_spi_mem_read(wl, STATUS_MEM_ADDRESS, status, sizeof(*status)); + + wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " + "drv_rx_counter = %d, tx_results_counter = %d)", + status->intr, + status->fw_rx_counter, + status->drv_rx_counter, + status->tx_results_counter); + + /* update number of available TX blocks */ + for (i = 0; i < NUM_TX_QUEUES; i++) { + u32 cnt = status->tx_released_blks[i] - wl->tx_blocks_freed[i]; + wl->tx_blocks_freed[i] = status->tx_released_blks[i]; + wl->tx_blocks_available += cnt; + total += cnt; + } + + /* if more blocks are available now, schedule some tx work */ + if (total && !skb_queue_empty(&wl->tx_queue)) + schedule_work(&wl->tx_work); + + /* update the host-chipset time offset */ + wl->time_offset = jiffies_to_usecs(jiffies) - status->fw_localtime; +} + +#define WL1271_IRQ_MAX_LOOPS 10 +static void wl1271_irq_work(struct work_struct *work) +{ + u32 intr, ctr = WL1271_IRQ_MAX_LOOPS; + int ret; + struct wl1271 *wl = + container_of(work, struct wl1271, irq_work); + + mutex_lock(&wl->mutex); + + wl1271_debug(DEBUG_IRQ, "IRQ work"); + + if (wl->state == WL1271_STATE_OFF) + goto out; + + ret = wl1271_ps_elp_wakeup(wl, true); + if (ret < 0) + goto out; + + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); + + intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); + if (!intr) { + wl1271_debug(DEBUG_IRQ, "Zero interrupt received."); + goto out_sleep; + } + + intr &= WL1271_INTR_MASK; + + do { + wl1271_fw_status(wl, wl->fw_status); + + + if (intr & (WL1271_ACX_INTR_EVENT_A | + WL1271_ACX_INTR_EVENT_B)) { + wl1271_debug(DEBUG_IRQ, + "WL1271_ACX_INTR_EVENT (0x%x)", intr); + if (intr & WL1271_ACX_INTR_EVENT_A) + wl1271_event_handle(wl, 0); + else + wl1271_event_handle(wl, 1); + } + + if (intr & WL1271_ACX_INTR_INIT_COMPLETE) + wl1271_debug(DEBUG_IRQ, + "WL1271_ACX_INTR_INIT_COMPLETE"); + + if (intr & WL1271_ACX_INTR_HW_AVAILABLE) + wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE"); + + if (intr & WL1271_ACX_INTR_DATA) { + u8 tx_res_cnt = wl->fw_status->tx_results_counter - + wl->tx_results_count; + + wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); + + /* check for tx results */ + if (tx_res_cnt) + wl1271_tx_complete(wl, tx_res_cnt); + + wl1271_rx(wl, wl->fw_status); + } + + intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); + intr &= WL1271_INTR_MASK; + } while (intr && --ctr); + +out_sleep: + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(WL1271_INTR_MASK)); + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +static irqreturn_t wl1271_irq(int irq, void *cookie) +{ + struct wl1271 *wl; + unsigned long flags; + + wl1271_debug(DEBUG_IRQ, "IRQ"); + + wl = cookie; + + /* complete the ELP completion */ + spin_lock_irqsave(&wl->wl_lock, flags); + if (wl->elp_compl) { + complete(wl->elp_compl); + wl->elp_compl = NULL; + } + + schedule_work(&wl->irq_work); + spin_unlock_irqrestore(&wl->wl_lock, flags); + + return IRQ_HANDLED; +} + +static int wl1271_fetch_firmware(struct wl1271 *wl) +{ + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev); + + if (ret < 0) { + wl1271_error("could not get firmware: %d", ret); + return ret; + } + + if (fw->size % 4) { + wl1271_error("firmware size is not multiple of 32 bits: %zu", + fw->size); + ret = -EILSEQ; + goto out; + } + + wl->fw_len = fw->size; + wl->fw = kmalloc(wl->fw_len, GFP_KERNEL); + + if (!wl->fw) { + wl1271_error("could not allocate memory for the firmware"); + ret = -ENOMEM; + goto out; + } + + memcpy(wl->fw, fw->data, wl->fw_len); + + ret = 0; + +out: + release_firmware(fw); + + return ret; +} + +static int wl1271_fetch_nvs(struct wl1271 *wl) +{ + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev); + + if (ret < 0) { + wl1271_error("could not get nvs file: %d", ret); + return ret; + } + + if (fw->size % 4) { + wl1271_error("nvs size is not multiple of 32 bits: %zu", + fw->size); + ret = -EILSEQ; + goto out; + } + + wl->nvs_len = fw->size; + wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL); + + if (!wl->nvs) { + wl1271_error("could not allocate memory for the nvs file"); + ret = -ENOMEM; + goto out; + } + + memcpy(wl->nvs, fw->data, wl->nvs_len); + + ret = 0; + +out: + release_firmware(fw); + + return ret; +} + +static void wl1271_fw_wakeup(struct wl1271 *wl) +{ + u32 elp_reg; + + elp_reg = ELPCTRL_WAKE_UP; + wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); +} + +static int wl1271_setup(struct wl1271 *wl) +{ + wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL); + if (!wl->fw_status) + return -ENOMEM; + + wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL); + if (!wl->tx_res_if) { + kfree(wl->fw_status); + return -ENOMEM; + } + + INIT_WORK(&wl->irq_work, wl1271_irq_work); + INIT_WORK(&wl->tx_work, wl1271_tx_work); + return 0; +} + +static int wl1271_chip_wakeup(struct wl1271 *wl) +{ + int ret = 0; + + wl1271_power_on(wl); + msleep(WL1271_POWER_ON_SLEEP); + wl1271_spi_reset(wl); + wl1271_spi_init(wl); + + /* We don't need a real memory partition here, because we only want + * to use the registers at this point. */ + wl1271_set_partition(wl, + 0x00000000, + 0x00000000, + REGISTERS_BASE, + REGISTERS_DOWN_SIZE); + + /* ELP module wake up */ + wl1271_fw_wakeup(wl); + + /* whal_FwCtrl_BootSm() */ + + /* 0. read chip id from CHIP_ID */ + wl->chip.id = wl1271_reg_read32(wl, CHIP_ID_B); + + /* 1. check if chip id is valid */ + + switch (wl->chip.id) { + case CHIP_ID_1271_PG10: + wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete", + wl->chip.id); + + ret = wl1271_setup(wl); + if (ret < 0) + goto out; + break; + case CHIP_ID_1271_PG20: + wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", + wl->chip.id); + + ret = wl1271_setup(wl); + if (ret < 0) + goto out; + break; + default: + wl1271_error("unsupported chip id: 0x%x", wl->chip.id); + ret = -ENODEV; + goto out; + } + + if (wl->fw == NULL) { + ret = wl1271_fetch_firmware(wl); + if (ret < 0) + goto out; + } + + /* No NVS from netlink, try to get it from the filesystem */ + if (wl->nvs == NULL) { + ret = wl1271_fetch_nvs(wl); + if (ret < 0) + goto out; + } + +out: + return ret; +} + +static void wl1271_filter_work(struct work_struct *work) +{ + struct wl1271 *wl = + container_of(work, struct wl1271, filter_work); + int ret; + + mutex_lock(&wl->mutex); + + if (wl->state == WL1271_STATE_OFF) + goto out; + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + /* FIXME: replace the magic numbers with proper definitions */ + ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0); + if (ret < 0) + goto out_sleep; + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +int wl1271_plt_start(struct wl1271 *wl) +{ + int ret; + + mutex_lock(&wl->mutex); + + wl1271_notice("power up"); + + if (wl->state != WL1271_STATE_OFF) { + wl1271_error("cannot go into PLT state because not " + "in off state: %d", wl->state); + ret = -EBUSY; + goto out; + } + + wl->state = WL1271_STATE_PLT; + + ret = wl1271_chip_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1271_boot(wl); + if (ret < 0) + goto out; + + wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); + + ret = wl1271_plt_init(wl); + if (ret < 0) + goto out; + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +int wl1271_plt_stop(struct wl1271 *wl) +{ + int ret = 0; + + mutex_lock(&wl->mutex); + + wl1271_notice("power down"); + + if (wl->state != WL1271_STATE_PLT) { + wl1271_error("cannot power down because not in PLT " + "state: %d", wl->state); + ret = -EBUSY; + goto out; + } + + wl1271_disable_interrupts(wl); + wl1271_power_off(wl); + + wl->state = WL1271_STATE_OFF; + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + + +static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct wl1271 *wl = hw->priv; + + skb_queue_tail(&wl->tx_queue, skb); + + /* + * The chip specific setup must run before the first TX packet - + * before that, the tx_work will not be initialized! + */ + + schedule_work(&wl->tx_work); + + /* + * The workqueue is slow to process the tx_queue and we need stop + * the queue here, otherwise the queue will get too long. + */ + if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) { + ieee80211_stop_queues(wl->hw); + + /* + * FIXME: this is racy, the variable is not properly + * protected. Maybe fix this by removing the stupid + * variable altogether and checking the real queue state? + */ + wl->tx_queue_stopped = true; + } + + return NETDEV_TX_OK; +} + +static int wl1271_op_start(struct ieee80211_hw *hw) +{ + struct wl1271 *wl = hw->priv; + int ret = 0; + + wl1271_debug(DEBUG_MAC80211, "mac80211 start"); + + mutex_lock(&wl->mutex); + + if (wl->state != WL1271_STATE_OFF) { + wl1271_error("cannot start because not in off state: %d", + wl->state); + ret = -EBUSY; + goto out; + } + + ret = wl1271_chip_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1271_boot(wl); + if (ret < 0) + goto out; + + ret = wl1271_hw_init(wl); + if (ret < 0) + goto out; + + wl->state = WL1271_STATE_ON; + + wl1271_info("firmware booted (%s)", wl->chip.fw_ver); + +out: + if (ret < 0) + wl1271_power_off(wl); + + mutex_unlock(&wl->mutex); + + return ret; +} + +static void wl1271_op_stop(struct ieee80211_hw *hw) +{ + struct wl1271 *wl = hw->priv; + int i; + + wl1271_info("down"); + + wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); + + mutex_lock(&wl->mutex); + + WARN_ON(wl->state != WL1271_STATE_ON); + + if (wl->scanning) { + mutex_unlock(&wl->mutex); + ieee80211_scan_completed(wl->hw, true); + mutex_lock(&wl->mutex); + wl->scanning = false; + } + + wl->state = WL1271_STATE_OFF; + + wl1271_disable_interrupts(wl); + + mutex_unlock(&wl->mutex); + + cancel_work_sync(&wl->irq_work); + cancel_work_sync(&wl->tx_work); + cancel_work_sync(&wl->filter_work); + + mutex_lock(&wl->mutex); + + /* let's notify MAC80211 about the remaining pending TX frames */ + wl1271_tx_flush(wl); + wl1271_power_off(wl); + + memset(wl->bssid, 0, ETH_ALEN); + memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1); + wl->ssid_len = 0; + wl->listen_int = 1; + wl->bss_type = MAX_BSS_TYPE; + + wl->rx_counter = 0; + wl->elp = false; + wl->psm = 0; + wl->tx_queue_stopped = false; + wl->power_level = WL1271_DEFAULT_POWER_LEVEL; + wl->tx_blocks_available = 0; + wl->tx_results_count = 0; + wl->tx_packets_count = 0; + wl->time_offset = 0; + wl->session_counter = 0; + for (i = 0; i < NUM_TX_QUEUES; i++) + wl->tx_blocks_freed[i] = 0; + + wl1271_debugfs_reset(wl); + mutex_unlock(&wl->mutex); +} + +static int wl1271_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct wl1271 *wl = hw->priv; + DECLARE_MAC_BUF(mac); + int ret = 0; + + wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", + conf->type, print_mac(mac, conf->mac_addr)); + + mutex_lock(&wl->mutex); + + switch (conf->type) { + case NL80211_IFTYPE_STATION: + wl->bss_type = BSS_TYPE_STA_BSS; + break; + case NL80211_IFTYPE_ADHOC: + wl->bss_type = BSS_TYPE_IBSS; + break; + default: + ret = -EOPNOTSUPP; + goto out; + } + + /* FIXME: what if conf->mac_addr changes? */ + +out: + mutex_unlock(&wl->mutex); + return ret; +} + +static void wl1271_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); +} + +#if 0 +static int wl1271_op_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) +{ + struct wl1271 *wl = hw->priv; + struct sk_buff *beacon; + DECLARE_MAC_BUF(mac); + int ret; + + wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %s", + print_mac(mac, conf->bssid)); + wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid, + conf->ssid_len); + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + memcpy(wl->bssid, conf->bssid, ETH_ALEN); + + ret = wl1271_cmd_build_null_data(wl); + if (ret < 0) + goto out_sleep; + + wl->ssid_len = conf->ssid_len; + if (wl->ssid_len) + memcpy(wl->ssid, conf->ssid, wl->ssid_len); + + if (wl->bss_type != BSS_TYPE_IBSS) { + /* FIXME: replace the magic numbers with proper definitions */ + ret = wl1271_cmd_join(wl, wl->bss_type, 5, 100, 1); + if (ret < 0) + goto out_sleep; + } + + if (conf->changed & IEEE80211_IFCC_BEACON) { + beacon = ieee80211_beacon_get(hw, vif); + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, + beacon->data, beacon->len); + + if (ret < 0) { + dev_kfree_skb(beacon); + goto out_sleep; + } + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, + beacon->data, beacon->len); + + dev_kfree_skb(beacon); + + if (ret < 0) + goto out_sleep; + + /* FIXME: replace the magic numbers with proper definitions */ + ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0); + + if (ret < 0) + goto out_sleep; + } + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} +#endif + +static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) +{ + struct wl1271 *wl = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + int channel, ret = 0; + + channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + + wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", + channel, + conf->flags & IEEE80211_CONF_PS ? "on" : "off", + conf->power_level); + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + if (channel != wl->channel) { + u8 old_channel = wl->channel; + wl->channel = channel; + + /* FIXME: use beacon interval provided by mac80211 */ + ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0); + if (ret < 0) { + wl->channel = old_channel; + goto out_sleep; + } + } + + ret = wl1271_cmd_build_null_data(wl); + if (ret < 0) + goto out_sleep; + + if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { + wl1271_info("psm enabled"); + + wl->psm_requested = true; + + /* + * We enter PSM only if we're already associated. + * If we're not, we'll enter it when joining an SSID, + * through the bss_info_changed() hook. + */ + ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + } else if (!(conf->flags & IEEE80211_CONF_PS) && + wl->psm_requested) { + wl1271_info("psm disabled"); + + wl->psm_requested = false; + + if (wl->psm) + ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE); + } + + if (conf->power_level != wl->power_level) { + ret = wl1271_acx_tx_power(wl, conf->power_level); + if (ret < 0) + goto out; + + wl->power_level = conf->power_level; + } + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ + FIF_ALLMULTI | \ + FIF_FCSFAIL | \ + FIF_BCN_PRBRESP_PROMISC | \ + FIF_CONTROL | \ + FIF_OTHER_BSS) + +static void wl1271_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, + unsigned int *total, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct wl1271 *wl = hw->priv; + + wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter"); + + *total &= WL1271_SUPPORTED_FILTERS; + changed &= WL1271_SUPPORTED_FILTERS; + + if (changed == 0) + return; + + /* FIXME: wl->rx_config and wl->rx_filter are not protected */ + wl->rx_config = WL1271_DEFAULT_RX_CONFIG; + wl->rx_filter = WL1271_DEFAULT_RX_FILTER; + + /* + * FIXME: workqueues need to be properly cancelled on stop(), for + * now let's just disable changing the filter settings. They will + * be updated any on config(). + */ + /* schedule_work(&wl->filter_work); */ +} + +static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key_conf) +{ + struct wl1271 *wl = hw->priv; + const u8 *addr; + int ret; + u8 key_type; + + static const u8 bcast_addr[ETH_ALEN] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + wl1271_debug(DEBUG_MAC80211, "mac80211 set key"); + + addr = sta ? sta->addr : bcast_addr; + + wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); + wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); + wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", + key_conf->alg, key_conf->keyidx, + key_conf->keylen, key_conf->flags); + wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen); + + if (is_zero_ether_addr(addr)) { + /* We dont support TX only encryption */ + ret = -EOPNOTSUPP; + goto out; + } + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out_unlock; + + switch (key_conf->alg) { + case ALG_WEP: + key_type = KEY_WEP; + + key_conf->hw_key_idx = key_conf->keyidx; + break; + case ALG_TKIP: + key_type = KEY_TKIP; + + key_conf->hw_key_idx = key_conf->keyidx; + break; + case ALG_CCMP: + key_type = KEY_AES; + + key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + break; + default: + wl1271_error("Unknown key algo 0x%x", key_conf->alg); + + ret = -EOPNOTSUPP; + goto out_sleep; + } + + switch (cmd) { + case SET_KEY: + ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE, + key_conf->keyidx, key_type, + key_conf->keylen, key_conf->key, + addr); + if (ret < 0) { + wl1271_error("Could not add or replace key"); + goto out_sleep; + } + break; + + case DISABLE_KEY: + ret = wl1271_cmd_set_key(wl, KEY_REMOVE, + key_conf->keyidx, key_type, + key_conf->keylen, key_conf->key, + addr); + if (ret < 0) { + wl1271_error("Could not remove key"); + goto out_sleep; + } + break; + + default: + wl1271_error("Unsupported key cmd 0x%x", cmd); + ret = -EOPNOTSUPP; + goto out_sleep; + + break; + } + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out_unlock: + mutex_unlock(&wl->mutex); + +out: + return ret; +} + +static int wl1271_op_hw_scan(struct ieee80211_hw *hw, + struct cfg80211_scan_request *req) +{ + struct wl1271 *wl = hw->priv; + int ret; + u8 *ssid = NULL; + size_t ssid_len = 0; + + wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan"); + + if (req->n_ssids) { + ssid = req->ssids[0].ssid; + ssid_len = req->ssids[0].ssid_len; + } + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + ret = wl1271_cmd_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct wl1271 *wl = hw->priv; + int ret; + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + ret = wl1271_acx_rts_threshold(wl, (u16) value); + if (ret < 0) + wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret); + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + enum wl1271_cmd_ps_mode mode; + struct wl1271 *wl = hw->priv; + int ret; + + wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed"); + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + if (changed & BSS_CHANGED_ASSOC) { + if (bss_conf->assoc) { + wl->aid = bss_conf->aid; + + ret = wl1271_cmd_build_ps_poll(wl, wl->aid); + if (ret < 0) + goto out_sleep; + + ret = wl1271_acx_aid(wl, wl->aid); + if (ret < 0) + goto out_sleep; + + /* If we want to go in PSM but we're not there yet */ + if (wl->psm_requested && !wl->psm) { + mode = STATION_POWER_SAVE_MODE; + ret = wl1271_ps_set_mode(wl, mode); + if (ret < 0) + goto out_sleep; + } + } + } + if (changed & BSS_CHANGED_ERP_SLOT) { + if (bss_conf->use_short_slot) + ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT); + else + ret = wl1271_acx_slot(wl, SLOT_TIME_LONG); + if (ret < 0) { + wl1271_warning("Set slot time failed %d", ret); + goto out_sleep; + } + } + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + if (bss_conf->use_short_preamble) + wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); + else + wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG); + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + if (bss_conf->use_cts_prot) + ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE); + else + ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE); + if (ret < 0) { + wl1271_warning("Set ctsprotect failed %d", ret); + goto out_sleep; + } + } + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_rate wl1271_rates[] = { + { .bitrate = 10, + .hw_value = 0x1, + .hw_value_short = 0x1, }, + { .bitrate = 20, + .hw_value = 0x2, + .hw_value_short = 0x2, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, + .hw_value = 0x4, + .hw_value_short = 0x4, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, + .hw_value = 0x20, + .hw_value_short = 0x20, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, + .hw_value = 0x8, + .hw_value_short = 0x8, }, + { .bitrate = 90, + .hw_value = 0x10, + .hw_value_short = 0x10, }, + { .bitrate = 120, + .hw_value = 0x40, + .hw_value_short = 0x40, }, + { .bitrate = 180, + .hw_value = 0x80, + .hw_value_short = 0x80, }, + { .bitrate = 240, + .hw_value = 0x200, + .hw_value_short = 0x200, }, + { .bitrate = 360, + .hw_value = 0x400, + .hw_value_short = 0x400, }, + { .bitrate = 480, + .hw_value = 0x800, + .hw_value_short = 0x800, }, + { .bitrate = 540, + .hw_value = 0x1000, + .hw_value_short = 0x1000, }, +}; + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_channel wl1271_channels[] = { + { .hw_value = 1, .center_freq = 2412}, + { .hw_value = 2, .center_freq = 2417}, + { .hw_value = 3, .center_freq = 2422}, + { .hw_value = 4, .center_freq = 2427}, + { .hw_value = 5, .center_freq = 2432}, + { .hw_value = 6, .center_freq = 2437}, + { .hw_value = 7, .center_freq = 2442}, + { .hw_value = 8, .center_freq = 2447}, + { .hw_value = 9, .center_freq = 2452}, + { .hw_value = 10, .center_freq = 2457}, + { .hw_value = 11, .center_freq = 2462}, + { .hw_value = 12, .center_freq = 2467}, + { .hw_value = 13, .center_freq = 2472}, +}; + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_supported_band wl1271_band_2ghz = { + .channels = wl1271_channels, + .n_channels = ARRAY_SIZE(wl1271_channels), + .bitrates = wl1271_rates, + .n_bitrates = ARRAY_SIZE(wl1271_rates), +}; + +static const struct ieee80211_ops wl1271_ops = { + .start = wl1271_op_start, + .stop = wl1271_op_stop, + .add_interface = wl1271_op_add_interface, + .remove_interface = wl1271_op_remove_interface, + .config = wl1271_op_config, +/* .config_interface = wl1271_op_config_interface, */ + .configure_filter = wl1271_op_configure_filter, + .tx = wl1271_op_tx, + .set_key = wl1271_op_set_key, + .hw_scan = wl1271_op_hw_scan, + .bss_info_changed = wl1271_op_bss_info_changed, + .set_rts_threshold = wl1271_op_set_rts_threshold, +}; + +static int wl1271_register_hw(struct wl1271 *wl) +{ + int ret; + + if (wl->mac80211_registered) + return 0; + + SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); + + ret = ieee80211_register_hw(wl->hw); + if (ret < 0) { + wl1271_error("unable to register mac80211 hw: %d", ret); + return ret; + } + + wl->mac80211_registered = true; + + wl1271_notice("loaded"); + + return 0; +} + +static int wl1271_init_ieee80211(struct wl1271 *wl) +{ + /* + * The tx descriptor buffer and the TKIP space. + * + * FIXME: add correct 1271 descriptor size + */ + wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE; + + /* unit us */ + /* FIXME: find a proper value */ + wl->hw->channel_change_time = 10000; + + wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; + + wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + wl->hw->wiphy->max_scan_ssids = 1; + wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz; + + SET_IEEE80211_DEV(wl->hw, &wl->spi->dev); + + return 0; +} + +static void wl1271_device_release(struct device *dev) +{ + +} + +static struct platform_device wl1271_device = { + .name = "wl1271", + .id = -1, + + /* device model insists to have a release function */ + .dev = { + .release = wl1271_device_release, + }, +}; + +#define WL1271_DEFAULT_CHANNEL 0 +static int __devinit wl1271_probe(struct spi_device *spi) +{ + struct wl12xx_platform_data *pdata; + struct ieee80211_hw *hw; + struct wl1271 *wl; + int ret, i; + static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; + + pdata = spi->dev.platform_data; + if (!pdata) { + wl1271_error("no platform data"); + return -ENODEV; + } + + hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); + if (!hw) { + wl1271_error("could not alloc ieee80211_hw"); + return -ENOMEM; + } + + wl = hw->priv; + memset(wl, 0, sizeof(*wl)); + + wl->hw = hw; + dev_set_drvdata(&spi->dev, wl); + wl->spi = spi; + + skb_queue_head_init(&wl->tx_queue); + + INIT_WORK(&wl->filter_work, wl1271_filter_work); + wl->channel = WL1271_DEFAULT_CHANNEL; + wl->scanning = false; + wl->default_key = 0; + wl->listen_int = 1; + wl->rx_counter = 0; + wl->rx_config = WL1271_DEFAULT_RX_CONFIG; + wl->rx_filter = WL1271_DEFAULT_RX_FILTER; + wl->elp = false; + wl->psm = 0; + wl->psm_requested = false; + wl->tx_queue_stopped = false; + wl->power_level = WL1271_DEFAULT_POWER_LEVEL; + + /* We use the default power on sleep time until we know which chip + * we're using */ + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + wl->tx_frames[i] = NULL; + + spin_lock_init(&wl->wl_lock); + + /* + * In case our MAC address is not correctly set, + * we use a random but Nokia MAC. + */ + memcpy(wl->mac_addr, nokia_oui, 3); + get_random_bytes(wl->mac_addr + 3, 3); + + wl->state = WL1271_STATE_OFF; + mutex_init(&wl->mutex); + + wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); + if (!wl->rx_descriptor) { + wl1271_error("could not allocate memory for rx descriptor"); + ret = -ENOMEM; + goto out_free; + } + + /* This is the only SPI value that we need to set here, the rest + * comes from the board-peripherals file */ + spi->bits_per_word = 32; + + ret = spi_setup(spi); + if (ret < 0) { + wl1271_error("spi_setup failed"); + goto out_free; + } + + wl->set_power = pdata->set_power; + if (!wl->set_power) { + wl1271_error("set power function missing in platform data"); + ret = -ENODEV; + goto out_free; + } + + wl->irq = spi->irq; + if (wl->irq < 0) { + wl1271_error("irq missing in platform data"); + ret = -ENODEV; + goto out_free; + } + + ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl); + if (ret < 0) { + wl1271_error("request_irq() failed: %d", ret); + goto out_free; + } + + set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); + + disable_irq(wl->irq); + + ret = platform_device_register(&wl1271_device); + if (ret) { + wl1271_error("couldn't register platform device"); + goto out_irq; + } + dev_set_drvdata(&wl1271_device.dev, wl); + + ret = wl1271_init_ieee80211(wl); + if (ret) + goto out_platform; + + ret = wl1271_register_hw(wl); + if (ret) + goto out_platform; + + wl1271_debugfs_init(wl); + + wl1271_notice("initialized"); + + return 0; + + out_platform: + platform_device_unregister(&wl1271_device); + + out_irq: + free_irq(wl->irq, wl); + + out_free: + kfree(wl->rx_descriptor); + wl->rx_descriptor = NULL; + + ieee80211_free_hw(hw); + + return ret; +} + +static int __devexit wl1271_remove(struct spi_device *spi) +{ + struct wl1271 *wl = dev_get_drvdata(&spi->dev); + + ieee80211_unregister_hw(wl->hw); + + wl1271_debugfs_exit(wl); + platform_device_unregister(&wl1271_device); + free_irq(wl->irq, wl); + kfree(wl->target_mem_map); + kfree(wl->fw); + wl->fw = NULL; + kfree(wl->nvs); + wl->nvs = NULL; + + kfree(wl->rx_descriptor); + wl->rx_descriptor = NULL; + + kfree(wl->fw_status); + kfree(wl->tx_res_if); + + ieee80211_free_hw(wl->hw); + + return 0; +} + + +static struct spi_driver wl1271_spi_driver = { + .driver = { + .name = "wl1271", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = wl1271_probe, + .remove = __devexit_p(wl1271_remove), +}; + +static int __init wl1271_init(void) +{ + int ret; + + ret = spi_register_driver(&wl1271_spi_driver); + if (ret < 0) { + wl1271_error("failed to register spi driver: %d", ret); + goto out; + } + +out: + return ret; +} + +static void __exit wl1271_exit(void) +{ + spi_unregister_driver(&wl1271_spi_driver); + + wl1271_notice("unloaded"); +} + +module_init(wl1271_init); +module_exit(wl1271_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Luciano Coelho "); diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c new file mode 100644 index 00000000000..1dc74b0c773 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_ps.c @@ -0,0 +1,142 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl1271_reg.h" +#include "wl1271_ps.h" +#include "wl1271_spi.h" + +#define WL1271_WAKEUP_TIMEOUT 500 + +/* Routines to toggle sleep mode while in ELP */ +void wl1271_ps_elp_sleep(struct wl1271 *wl) +{ + /* + * FIXME: due to a problem in the firmware (causing a firmware + * crash), ELP entry is prevented below. Remove the "true" to + * re-enable ELP entry. + */ + if (true || wl->elp || !wl->psm) + return; + + /* + * Go to ELP unless there is work already pending - pending work + * will immediately wakeup the chipset anyway. + */ + if (!work_pending(&wl->irq_work) && !work_pending(&wl->tx_work)) { + wl1271_debug(DEBUG_PSM, "chip to elp"); + wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); + wl->elp = true; + } +} + +int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) +{ + DECLARE_COMPLETION_ONSTACK(compl); + unsigned long flags; + int ret; + u32 start_time = jiffies; + bool pending = false; + + if (!wl->elp) + return 0; + + wl1271_debug(DEBUG_PSM, "waking up chip from elp"); + + /* + * The spinlock is required here to synchronize both the work and + * the completion variable in one entity. + */ + spin_lock_irqsave(&wl->wl_lock, flags); + if (work_pending(&wl->irq_work) || chip_awake) + pending = true; + else + wl->elp_compl = &compl; + spin_unlock_irqrestore(&wl->wl_lock, flags); + + wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); + + if (!pending) { + ret = wait_for_completion_timeout( + &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); + if (ret == 0) { + wl1271_error("ELP wakeup timeout!"); + ret = -ETIMEDOUT; + goto err; + } else if (ret < 0) { + wl1271_error("ELP wakeup completion error."); + goto err; + } + } + + wl->elp = false; + + wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", + jiffies_to_msecs(jiffies - start_time)); + goto out; + +err: + spin_lock_irqsave(&wl->wl_lock, flags); + wl->elp_compl = NULL; + spin_unlock_irqrestore(&wl->wl_lock, flags); + return ret; + +out: + return 0; +} + +int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode) +{ + int ret; + + switch (mode) { + case STATION_POWER_SAVE_MODE: + wl1271_debug(DEBUG_PSM, "entering psm"); + ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); + if (ret < 0) + return ret; + + wl1271_ps_elp_sleep(wl); + if (ret < 0) + return ret; + + wl->psm = 1; + break; + case STATION_ACTIVE_MODE: + default: + wl1271_debug(DEBUG_PSM, "leaving psm"); + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + return ret; + + ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + return ret; + + wl->psm = 0; + break; + } + + return ret; +} + + diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.h b/drivers/net/wireless/wl12xx/wl1271_ps.h new file mode 100644 index 00000000000..de2bd3c7dc9 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_ps.h @@ -0,0 +1,35 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1271_PS_H__ +#define __WL1271_PS_H__ + +#include "wl1271.h" +#include "wl1271_acx.h" + +int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode); +void wl1271_ps_elp_sleep(struct wl1271 *wl); +int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake); + + +#endif /* __WL1271_PS_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1271_reg.h b/drivers/net/wireless/wl12xx/wl1271_reg.h new file mode 100644 index 00000000000..f8ed4a4fc69 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_reg.h @@ -0,0 +1,758 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __REG_H__ +#define __REG_H__ + +#include + +#define REGISTERS_BASE 0x00300000 +#define DRPW_BASE 0x00310000 + +#define REGISTERS_DOWN_SIZE 0x00008800 +#define REGISTERS_WORK_SIZE 0x0000b000 + +#define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC +#define STATUS_MEM_ADDRESS 0x40400 + +/* ELP register commands */ +#define ELPCTRL_WAKE_UP 0x1 +#define ELPCTRL_WAKE_UP_WLAN_READY 0x5 +#define ELPCTRL_SLEEP 0x0 +/* ELP WLAN_READY bit */ +#define ELPCTRL_WLAN_READY 0x2 + +/*=============================================== + Host Software Reset - 32bit RW + ------------------------------------------ + [31:1] Reserved + 0 SOFT_RESET Soft Reset - When this bit is set, + it holds the Wlan hardware in a soft reset state. + This reset disables all MAC and baseband processor + clocks except the CardBus/PCI interface clock. + It also initializes all MAC state machines except + the host interface. It does not reload the + contents of the EEPROM. When this bit is cleared + (not self-clearing), the Wlan hardware + exits the software reset state. +===============================================*/ +#define ACX_REG_SLV_SOFT_RESET (REGISTERS_BASE + 0x0000) + +#define WL1271_SLV_REG_DATA (REGISTERS_BASE + 0x0008) +#define WL1271_SLV_REG_ADATA (REGISTERS_BASE + 0x000c) +#define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018) +/* + * Interrupt registers. + * 64 bit interrupt sources registers ws ced. + * sme interupts were removed and new ones were added. + * Order was changed. + */ +#define FIQ_MASK (REGISTERS_BASE + 0x0400) +#define FIQ_MASK_L (REGISTERS_BASE + 0x0400) +#define FIQ_MASK_H (REGISTERS_BASE + 0x0404) +#define FIQ_MASK_SET (REGISTERS_BASE + 0x0408) +#define FIQ_MASK_SET_L (REGISTERS_BASE + 0x0408) +#define FIQ_MASK_SET_H (REGISTERS_BASE + 0x040C) +#define FIQ_MASK_CLR (REGISTERS_BASE + 0x0410) +#define FIQ_MASK_CLR_L (REGISTERS_BASE + 0x0410) +#define FIQ_MASK_CLR_H (REGISTERS_BASE + 0x0414) +#define IRQ_MASK (REGISTERS_BASE + 0x0418) +#define IRQ_MASK_L (REGISTERS_BASE + 0x0418) +#define IRQ_MASK_H (REGISTERS_BASE + 0x041C) +#define IRQ_MASK_SET (REGISTERS_BASE + 0x0420) +#define IRQ_MASK_SET_L (REGISTERS_BASE + 0x0420) +#define IRQ_MASK_SET_H (REGISTERS_BASE + 0x0424) +#define IRQ_MASK_CLR (REGISTERS_BASE + 0x0428) +#define IRQ_MASK_CLR_L (REGISTERS_BASE + 0x0428) +#define IRQ_MASK_CLR_H (REGISTERS_BASE + 0x042C) +#define ECPU_MASK (REGISTERS_BASE + 0x0448) +#define FIQ_STS_L (REGISTERS_BASE + 0x044C) +#define FIQ_STS_H (REGISTERS_BASE + 0x0450) +#define IRQ_STS_L (REGISTERS_BASE + 0x0454) +#define IRQ_STS_H (REGISTERS_BASE + 0x0458) +#define INT_STS_ND (REGISTERS_BASE + 0x0464) +#define INT_STS_RAW_L (REGISTERS_BASE + 0x0464) +#define INT_STS_RAW_H (REGISTERS_BASE + 0x0468) +#define INT_STS_CLR (REGISTERS_BASE + 0x04B4) +#define INT_STS_CLR_L (REGISTERS_BASE + 0x04B4) +#define INT_STS_CLR_H (REGISTERS_BASE + 0x04B8) +#define INT_ACK (REGISTERS_BASE + 0x046C) +#define INT_ACK_L (REGISTERS_BASE + 0x046C) +#define INT_ACK_H (REGISTERS_BASE + 0x0470) +#define INT_TRIG (REGISTERS_BASE + 0x0474) +#define INT_TRIG_L (REGISTERS_BASE + 0x0474) +#define INT_TRIG_H (REGISTERS_BASE + 0x0478) +#define HOST_STS_L (REGISTERS_BASE + 0x045C) +#define HOST_STS_H (REGISTERS_BASE + 0x0460) +#define HOST_MASK (REGISTERS_BASE + 0x0430) +#define HOST_MASK_L (REGISTERS_BASE + 0x0430) +#define HOST_MASK_H (REGISTERS_BASE + 0x0434) +#define HOST_MASK_SET (REGISTERS_BASE + 0x0438) +#define HOST_MASK_SET_L (REGISTERS_BASE + 0x0438) +#define HOST_MASK_SET_H (REGISTERS_BASE + 0x043C) +#define HOST_MASK_CLR (REGISTERS_BASE + 0x0440) +#define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440) +#define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444) + +#define ACX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474) +#define ACX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478) + +/* Host Interrupts*/ +#define HINT_MASK (REGISTERS_BASE + 0x0494) +#define HINT_MASK_SET (REGISTERS_BASE + 0x0498) +#define HINT_MASK_CLR (REGISTERS_BASE + 0x049C) +#define HINT_STS_ND_MASKED (REGISTERS_BASE + 0x04A0) +/*1150 spec calls this HINT_STS_RAW*/ +#define HINT_STS_ND (REGISTERS_BASE + 0x04B0) +#define HINT_STS_CLR (REGISTERS_BASE + 0x04A4) +#define HINT_ACK (REGISTERS_BASE + 0x04A8) +#define HINT_TRIG (REGISTERS_BASE + 0x04AC) + +/*============================================= + Host Interrupt Mask Register - 32bit (RW) + ------------------------------------------ + Setting a bit in this register masks the + corresponding interrupt to the host. + 0 - RX0 - Rx first dubble buffer Data Interrupt + 1 - TXD - Tx Data Interrupt + 2 - TXXFR - Tx Transfer Interrupt + 3 - RX1 - Rx second dubble buffer Data Interrupt + 4 - RXXFR - Rx Transfer Interrupt + 5 - EVENT_A - Event Mailbox interrupt + 6 - EVENT_B - Event Mailbox interrupt + 7 - WNONHST - Wake On Host Interrupt + 8 - TRACE_A - Debug Trace interrupt + 9 - TRACE_B - Debug Trace interrupt + 10 - CDCMP - Command Complete Interrupt + 11 - + 12 - + 13 - + 14 - ICOMP - Initialization Complete Interrupt + 16 - SG SE - Soft Gemini - Sense enable interrupt + 17 - SG SD - Soft Gemini - Sense disable interrupt + 18 - - + 19 - - + 20 - - + 21- - + Default: 0x0001 +*==============================================*/ +#define ACX_REG_INTERRUPT_MASK (REGISTERS_BASE + 0x04DC) + +/*============================================= + Host Interrupt Mask Set 16bit, (Write only) + ------------------------------------------ + Setting a bit in this register sets + the corresponding bin in ACX_HINT_MASK register + without effecting the mask + state of other bits (0 = no effect). +==============================================*/ +#define ACX_REG_HINT_MASK_SET (REGISTERS_BASE + 0x04E0) + +/*============================================= + Host Interrupt Mask Clear 16bit,(Write only) + ------------------------------------------ + Setting a bit in this register clears + the corresponding bin in ACX_HINT_MASK register + without effecting the mask + state of other bits (0 = no effect). +=============================================*/ +#define ACX_REG_HINT_MASK_CLR (REGISTERS_BASE + 0x04E4) + +/*============================================= + Host Interrupt Status Nondestructive Read + 16bit,(Read only) + ------------------------------------------ + The host can read this register to determine + which interrupts are active. + Reading this register doesn't + effect its content. +=============================================*/ +#define ACX_REG_INTERRUPT_NO_CLEAR (REGISTERS_BASE + 0x04E8) + +/*============================================= + Host Interrupt Status Clear on Read Register + 16bit,(Read only) + ------------------------------------------ + The host can read this register to determine + which interrupts are active. + Reading this register clears it, + thus making all interrupts inactive. +==============================================*/ +#define ACX_REG_INTERRUPT_CLEAR (REGISTERS_BASE + 0x04F8) + +/*============================================= + Host Interrupt Acknowledge Register + 16bit,(Write only) + ------------------------------------------ + The host can set individual bits in this + register to clear (acknowledge) the corresp. + interrupt status bits in the HINT_STS_CLR and + HINT_STS_ND registers, thus making the + assotiated interrupt inactive. (0-no effect) +==============================================*/ +#define ACX_REG_INTERRUPT_ACK (REGISTERS_BASE + 0x04F0) + +#define RX_DRIVER_DUMMY_WRITE_ADDRESS (REGISTERS_BASE + 0x0534) +#define RX_DRIVER_COUNTER_ADDRESS (REGISTERS_BASE + 0x0538) + +/* Device Configuration registers*/ +#define SOR_CFG (REGISTERS_BASE + 0x0800) + +/* Embedded ARM CPU Control */ + +/*=============================================== + Halt eCPU - 32bit RW + ------------------------------------------ + 0 HALT_ECPU Halt Embedded CPU - This bit is the + compliment of bit 1 (MDATA2) in the SOR_CFG register. + During a hardware reset, this bit holds + the inverse of MDATA2. + When downloading firmware from the host, + set this bit (pull down MDATA2). + The host clears this bit after downloading the firmware into + zero-wait-state SSRAM. + When loading firmware from Flash, clear this bit (pull up MDATA2) + so that the eCPU can run the bootloader code in Flash + HALT_ECPU eCPU State + -------------------- + 1 halt eCPU + 0 enable eCPU + ===============================================*/ +#define ACX_REG_ECPU_CONTROL (REGISTERS_BASE + 0x0804) + +#define HI_CFG (REGISTERS_BASE + 0x0808) + +/*=============================================== + EEPROM Burst Read Start - 32bit RW + ------------------------------------------ + [31:1] Reserved + 0 ACX_EE_START - EEPROM Burst Read Start 0 + Setting this bit starts a burst read from + the external EEPROM. + If this bit is set (after reset) before an EEPROM read/write, + the burst read starts at EEPROM address 0. + Otherwise, it starts at the address + following the address of the previous access. + TheWlan hardware hardware clears this bit automatically. + + Default: 0x00000000 +*================================================*/ +#define ACX_REG_EE_START (REGISTERS_BASE + 0x080C) + +#define OCP_POR_CTR (REGISTERS_BASE + 0x09B4) +#define OCP_DATA_WRITE (REGISTERS_BASE + 0x09B8) +#define OCP_DATA_READ (REGISTERS_BASE + 0x09BC) +#define OCP_CMD (REGISTERS_BASE + 0x09C0) + +#define WL1271_HOST_WR_ACCESS (REGISTERS_BASE + 0x09F8) + +#define CHIP_ID_B (REGISTERS_BASE + 0x5674) + +#define CHIP_ID_1271_PG10 (0x4030101) +#define CHIP_ID_1271_PG20 (0x4030111) + +#define ENABLE (REGISTERS_BASE + 0x5450) + +/* Power Management registers */ +#define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) +#define ELP_CMD (REGISTERS_BASE + 0x5808) +#define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) +#define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) +#define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) + +#define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) + +/* Scratch Pad registers*/ +#define SCR_PAD0 (REGISTERS_BASE + 0x5608) +#define SCR_PAD1 (REGISTERS_BASE + 0x560C) +#define SCR_PAD2 (REGISTERS_BASE + 0x5610) +#define SCR_PAD3 (REGISTERS_BASE + 0x5614) +#define SCR_PAD4 (REGISTERS_BASE + 0x5618) +#define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) +#define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) +#define SCR_PAD5 (REGISTERS_BASE + 0x5624) +#define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) +#define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) +#define SCR_PAD6 (REGISTERS_BASE + 0x5630) +#define SCR_PAD7 (REGISTERS_BASE + 0x5634) +#define SCR_PAD8 (REGISTERS_BASE + 0x5638) +#define SCR_PAD9 (REGISTERS_BASE + 0x563C) + +/* Spare registers*/ +#define SPARE_A1 (REGISTERS_BASE + 0x0994) +#define SPARE_A2 (REGISTERS_BASE + 0x0998) +#define SPARE_A3 (REGISTERS_BASE + 0x099C) +#define SPARE_A4 (REGISTERS_BASE + 0x09A0) +#define SPARE_A5 (REGISTERS_BASE + 0x09A4) +#define SPARE_A6 (REGISTERS_BASE + 0x09A8) +#define SPARE_A7 (REGISTERS_BASE + 0x09AC) +#define SPARE_A8 (REGISTERS_BASE + 0x09B0) +#define SPARE_B1 (REGISTERS_BASE + 0x5420) +#define SPARE_B2 (REGISTERS_BASE + 0x5424) +#define SPARE_B3 (REGISTERS_BASE + 0x5428) +#define SPARE_B4 (REGISTERS_BASE + 0x542C) +#define SPARE_B5 (REGISTERS_BASE + 0x5430) +#define SPARE_B6 (REGISTERS_BASE + 0x5434) +#define SPARE_B7 (REGISTERS_BASE + 0x5438) +#define SPARE_B8 (REGISTERS_BASE + 0x543C) + +#define PLL_PARAMETERS (REGISTERS_BASE + 0x6040) +#define WU_COUNTER_PAUSE (REGISTERS_BASE + 0x6008) +#define WELP_ARM_COMMAND (REGISTERS_BASE + 0x6100) +#define DRPW_SCRATCH_START (DRPW_BASE + 0x002C) + + +#define ACX_SLV_SOFT_RESET_BIT BIT(1) +#define ACX_REG_EEPROM_START_BIT BIT(1) + +/* Command/Information Mailbox Pointers */ + +/*=============================================== + Command Mailbox Pointer - 32bit RW + ------------------------------------------ + This register holds the start address of + the command mailbox located in the Wlan hardware memory. + The host must read this pointer after a reset to + find the location of the command mailbox. + The Wlan hardware initializes the command mailbox + pointer with the default address of the command mailbox. + The command mailbox pointer is not valid until after + the host receives the Init Complete interrupt from + the Wlan hardware. + ===============================================*/ +#define REG_COMMAND_MAILBOX_PTR (SCR_PAD0) + +/*=============================================== + Information Mailbox Pointer - 32bit RW + ------------------------------------------ + This register holds the start address of + the information mailbox located in the Wlan hardware memory. + The host must read this pointer after a reset to find + the location of the information mailbox. + The Wlan hardware initializes the information mailbox pointer + with the default address of the information mailbox. + The information mailbox pointer is not valid + until after the host receives the Init Complete interrupt from + the Wlan hardware. + ===============================================*/ +#define REG_EVENT_MAILBOX_PTR (SCR_PAD1) + + +/* Misc */ + +#define REG_ENABLE_TX_RX (ENABLE) +/* + * Rx configuration (filter) information element + * --------------------------------------------- + */ +#define REG_RX_CONFIG (RX_CFG) +#define REG_RX_FILTER (RX_FILTER_CFG) + + +#define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002 + +/* promiscuous - receives all valid frames */ +#define RX_CFG_PROMISCUOUS 0x0008 + +/* receives frames from any BSSID */ +#define RX_CFG_BSSID 0x0020 + +/* receives frames destined to any MAC address */ +#define RX_CFG_MAC 0x0010 + +#define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010 +#define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000 +#define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020 +#define RX_CFG_ENABLE_ANY_BSSID 0x0000 + +/* discards all broadcast frames */ +#define RX_CFG_DISABLE_BCAST 0x0200 + +#define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400 +#define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800 +#define RX_CFG_COPY_RX_STATUS 0x2000 +#define RX_CFG_TSF 0x10000 + +#define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ + RX_CFG_ENABLE_ONLY_MY_BSSID) + +#define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ + | RX_CFG_ENABLE_ANY_BSSID) + +#define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ + RX_CFG_ENABLE_ANY_BSSID) + +#define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ + | RX_CFG_ENABLE_ONLY_MY_BSSID) + +#define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \ + | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \ + | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF) + +#define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC) + +#define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \ + RX_CFG_ENABLE_ONLY_MY_DEST_MAC) + +#define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \ + RX_CFG_ENABLE_ONLY_MY_DEST_MAC) + +#define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ + | CFG_RX_CTL_EN | CFG_RX_BCN_EN\ + | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) + +#define RX_FILTER_OPTION_FILTER_ALL 0 + +#define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\ + | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN) + +#define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ + | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\ + | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\ + | CFG_RX_PRSP_EN) + + +/*=============================================== + Phy regs + ===============================================*/ +#define ACX_PHY_ADDR_REG SBB_ADDR +#define ACX_PHY_DATA_REG SBB_DATA +#define ACX_PHY_CTRL_REG SBB_CTL +#define ACX_PHY_REG_WR_MASK 0x00000001ul +#define ACX_PHY_REG_RD_MASK 0x00000002ul + + +/*=============================================== + EEPROM Read/Write Request 32bit RW + ------------------------------------------ + 1 EE_READ - EEPROM Read Request 1 - Setting this bit + loads a single byte of data into the EE_DATA + register from the EEPROM location specified in + the EE_ADDR register. + The Wlan hardware hardware clears this bit automatically. + EE_DATA is valid when this bit is cleared. + + 0 EE_WRITE - EEPROM Write Request - Setting this bit + writes a single byte of data from the EE_DATA register into the + EEPROM location specified in the EE_ADDR register. + The Wlan hardware hardware clears this bit automatically. +*===============================================*/ +#define ACX_EE_CTL_REG EE_CTL +#define EE_WRITE 0x00000001ul +#define EE_READ 0x00000002ul + +/*=============================================== + EEPROM Address - 32bit RW + ------------------------------------------ + This register specifies the address + within the EEPROM from/to which to read/write data. + ===============================================*/ +#define ACX_EE_ADDR_REG EE_ADDR + +/*=============================================== + EEPROM Data - 32bit RW + ------------------------------------------ + This register either holds the read 8 bits of + data from the EEPROM or the write data + to be written to the EEPROM. + ===============================================*/ +#define ACX_EE_DATA_REG EE_DATA + +/*=============================================== + EEPROM Base Address - 32bit RW + ------------------------------------------ + This register holds the upper nine bits + [23:15] of the 24-bit Wlan hardware memory + address for burst reads from EEPROM accesses. + The EEPROM provides the lower 15 bits of this address. + The MSB of the address from the EEPROM is ignored. + ===============================================*/ +#define ACX_EE_CFG EE_CFG + +/*=============================================== + GPIO Output Values -32bit, RW + ------------------------------------------ + [31:16] Reserved + [15: 0] Specify the output values (at the output driver inputs) for + GPIO[15:0], respectively. + ===============================================*/ +#define ACX_GPIO_OUT_REG GPIO_OUT +#define ACX_MAX_GPIO_LINES 15 + +/*=============================================== + Contention window -32bit, RW + ------------------------------------------ + [31:26] Reserved + [25:16] Max (0x3ff) + [15:07] Reserved + [06:00] Current contention window value - default is 0x1F + ===============================================*/ +#define ACX_CONT_WIND_CFG_REG CONT_WIND_CFG +#define ACX_CONT_WIND_MIN_MASK 0x0000007f +#define ACX_CONT_WIND_MAX 0x03ff0000 + +/* + * Indirect slave register/memory registers + * ---------------------------------------- + */ +#define HW_SLAVE_REG_ADDR_REG 0x00000004 +#define HW_SLAVE_REG_DATA_REG 0x00000008 +#define HW_SLAVE_REG_CTRL_REG 0x0000000c + +#define SLAVE_AUTO_INC 0x00010000 +#define SLAVE_NO_AUTO_INC 0x00000000 +#define SLAVE_HOST_LITTLE_ENDIAN 0x00000000 + +#define HW_SLAVE_MEM_ADDR_REG SLV_MEM_ADDR +#define HW_SLAVE_MEM_DATA_REG SLV_MEM_DATA +#define HW_SLAVE_MEM_CTRL_REG SLV_MEM_CTL +#define HW_SLAVE_MEM_ENDIAN_REG SLV_END_CTL + +#define HW_FUNC_EVENT_INT_EN 0x8000 +#define HW_FUNC_EVENT_MASK_REG 0x00000034 + +#define ACX_MAC_TIMESTAMP_REG (MAC_TIMESTAMP) + +/*=============================================== + HI_CFG Interface Configuration Register Values + ------------------------------------------ + ===============================================*/ +#define HI_CFG_UART_ENABLE 0x00000004 +#define HI_CFG_RST232_ENABLE 0x00000008 +#define HI_CFG_CLOCK_REQ_SELECT 0x00000010 +#define HI_CFG_HOST_INT_ENABLE 0x00000020 +#define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040 +#define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080 +#define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100 +#define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 +#define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 + +/* + * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile + * for platforms using active high interrupt level + */ +#ifdef USE_ACTIVE_HIGH +#define HI_CFG_DEF_VAL \ + (HI_CFG_UART_ENABLE | \ + HI_CFG_RST232_ENABLE | \ + HI_CFG_CLOCK_REQ_SELECT | \ + HI_CFG_HOST_INT_ENABLE) +#else +#define HI_CFG_DEF_VAL \ + (HI_CFG_UART_ENABLE | \ + HI_CFG_RST232_ENABLE | \ + HI_CFG_CLOCK_REQ_SELECT | \ + HI_CFG_HOST_INT_ENABLE) + +#endif + +#define REF_FREQ_19_2 0 +#define REF_FREQ_26_0 1 +#define REF_FREQ_38_4 2 +#define REF_FREQ_40_0 3 +#define REF_FREQ_33_6 4 +#define REF_FREQ_NUM 5 + +#define LUT_PARAM_INTEGER_DIVIDER 0 +#define LUT_PARAM_FRACTIONAL_DIVIDER 1 +#define LUT_PARAM_ATTN_BB 2 +#define LUT_PARAM_ALPHA_BB 3 +#define LUT_PARAM_STOP_TIME_BB 4 +#define LUT_PARAM_BB_PLL_LOOP_FILTER 5 +#define LUT_PARAM_NUM 6 + +#define ACX_EEPROMLESS_IND_REG (SCR_PAD4) +#define USE_EEPROM 0 +#define SOFT_RESET_MAX_TIME 1000000 +#define SOFT_RESET_STALL_TIME 1000 +#define NVS_DATA_BUNDARY_ALIGNMENT 4 + + +/* Firmware image load chunk size */ +#define CHUNK_SIZE 512 + +/* Firmware image header size */ +#define FW_HDR_SIZE 8 + +#define ECPU_CONTROL_HALT 0x00000101 + + +/****************************************************************************** + + CHANNELS, BAND & REG DOMAINS definitions + +******************************************************************************/ + + +enum { + RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */ + RADIO_BAND_5GHZ = 1, /* 5 Ghz band */ + RADIO_BAND_JAPAN_4_9_GHZ = 2, + DEFAULT_BAND = RADIO_BAND_2_4GHZ, + INVALID_BAND = 0xFE, + MAX_RADIO_BANDS = 0xFF +}; + +enum { + NO_RATE = 0, + RATE_1MBPS = 0x0A, + RATE_2MBPS = 0x14, + RATE_5_5MBPS = 0x37, + RATE_6MBPS = 0x0B, + RATE_9MBPS = 0x0F, + RATE_11MBPS = 0x6E, + RATE_12MBPS = 0x0A, + RATE_18MBPS = 0x0E, + RATE_22MBPS = 0xDC, + RATE_24MBPS = 0x09, + RATE_36MBPS = 0x0D, + RATE_48MBPS = 0x08, + RATE_54MBPS = 0x0C +}; + +enum { + RATE_INDEX_1MBPS = 0, + RATE_INDEX_2MBPS = 1, + RATE_INDEX_5_5MBPS = 2, + RATE_INDEX_6MBPS = 3, + RATE_INDEX_9MBPS = 4, + RATE_INDEX_11MBPS = 5, + RATE_INDEX_12MBPS = 6, + RATE_INDEX_18MBPS = 7, + RATE_INDEX_22MBPS = 8, + RATE_INDEX_24MBPS = 9, + RATE_INDEX_36MBPS = 10, + RATE_INDEX_48MBPS = 11, + RATE_INDEX_54MBPS = 12, + RATE_INDEX_MAX = RATE_INDEX_54MBPS, + MAX_RATE_INDEX, + INVALID_RATE_INDEX = MAX_RATE_INDEX, + RATE_INDEX_ENUM_MAX_SIZE = 0x7FFFFFFF +}; + +enum { + RATE_MASK_1MBPS = 0x1, + RATE_MASK_2MBPS = 0x2, + RATE_MASK_5_5MBPS = 0x4, + RATE_MASK_11MBPS = 0x20, +}; + +#define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ +#define OFDM_RATE_BIT BIT(6) +#define PBCC_RATE_BIT BIT(7) + +enum { + CCK_LONG = 0, + CCK_SHORT = SHORT_PREAMBLE_BIT, + PBCC_LONG = PBCC_RATE_BIT, + PBCC_SHORT = PBCC_RATE_BIT | SHORT_PREAMBLE_BIT, + OFDM = OFDM_RATE_BIT +}; + +/****************************************************************************** + +Transmit-Descriptor RATE-SET field definitions... + +Define a new "Rate-Set" for TX path that incorporates the +Rate & Modulation info into a single 16-bit field. + +TxdRateSet_t: +b15 - Indicates Preamble type (1=SHORT, 0=LONG). + Notes: + Must be LONG (0) for 1Mbps rate. + Does not apply (set to 0) for RevG-OFDM rates. +b14 - Indicates PBCC encoding (1=PBCC, 0=not). + Notes: + Does not apply (set to 0) for rates 1 and 2 Mbps. + Does not apply (set to 0) for RevG-OFDM rates. +b13 - Unused (set to 0). +b12-b0 - Supported Rate indicator bits as defined below. + +******************************************************************************/ + + +#define TNETW1251_CHIP_ID_PG1_0 0x07010101 +#define TNETW1251_CHIP_ID_PG1_1 0x07020101 +#define TNETW1251_CHIP_ID_PG1_2 0x07030101 + +/************************************************************************* + + Interrupt Trigger Register (Host -> WiLink) + +**************************************************************************/ + +/* Hardware to Embedded CPU Interrupts - first 32-bit register set */ + +/* + * Host Command Interrupt. Setting this bit masks + * the interrupt that the host issues to inform + * the FW that it has sent a command + * to the Wlan hardware Command Mailbox. + */ +#define INTR_TRIG_CMD BIT(0) + +/* + * Host Event Acknowlegde Interrupt. The host + * sets this bit to acknowledge that it received + * the unsolicited information from the event + * mailbox. + */ +#define INTR_TRIG_EVENT_ACK BIT(1) + +/* + * The host sets this bit to inform the Wlan + * FW that a TX packet is in the XFER + * Buffer #0. + */ +#define INTR_TRIG_TX_PROC0 BIT(2) + +/* + * The host sets this bit to inform the FW + * that it read a packet from RX XFER + * Buffer #0. + */ +#define INTR_TRIG_RX_PROC0 BIT(3) + +#define INTR_TRIG_DEBUG_ACK BIT(4) + +#define INTR_TRIG_STATE_CHANGED BIT(5) + + +/* Hardware to Embedded CPU Interrupts - second 32-bit register set */ + +/* + * The host sets this bit to inform the FW + * that it read a packet from RX XFER + * Buffer #1. + */ +#define INTR_TRIG_RX_PROC1 BIT(17) + +/* + * The host sets this bit to inform the Wlan + * hardware that a TX packet is in the XFER + * Buffer #1. + */ +#define INTR_TRIG_TX_PROC1 BIT(18) + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c new file mode 100644 index 00000000000..ad8b6904c5e --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c @@ -0,0 +1,200 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl1271.h" +#include "wl1271_acx.h" +#include "wl1271_reg.h" +#include "wl1271_rx.h" +#include "wl1271_spi.h" + +static u8 wl1271_rx_get_mem_block(struct wl1271_fw_status *status, + u32 drv_rx_counter) +{ + return status->rx_pkt_descs[drv_rx_counter] & RX_MEM_BLOCK_MASK; +} + +static u32 wl1271_rx_get_buf_size(struct wl1271_fw_status *status, + u32 drv_rx_counter) +{ + return (status->rx_pkt_descs[drv_rx_counter] & RX_BUF_SIZE_MASK) >> + RX_BUF_SIZE_SHIFT_DIV; +} + +/* The values of this table must match the wl1271_rates[] array */ +static u8 wl1271_rx_rate_to_idx[] = { + /* MCS rates are used only with 11n */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS7 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS6 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS5 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS4 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS3 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS2 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS1 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS0 */ + + 11, /* WL1271_RATE_54 */ + 10, /* WL1271_RATE_48 */ + 9, /* WL1271_RATE_36 */ + 8, /* WL1271_RATE_24 */ + + /* TI-specific rate */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_22 */ + + 7, /* WL1271_RATE_18 */ + 6, /* WL1271_RATE_12 */ + 3, /* WL1271_RATE_11 */ + 5, /* WL1271_RATE_9 */ + 4, /* WL1271_RATE_6 */ + 2, /* WL1271_RATE_5_5 */ + 1, /* WL1271_RATE_2 */ + 0 /* WL1271_RATE_1 */ +}; + +static void wl1271_rx_status(struct wl1271 *wl, + struct wl1271_rx_descriptor *desc, + struct ieee80211_rx_status *status, + u8 beacon) +{ + memset(status, 0, sizeof(struct ieee80211_rx_status)); + + if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) + status->band = IEEE80211_BAND_2GHZ; + else + wl1271_warning("unsupported band 0x%x", + desc->flags & WL1271_RX_DESC_BAND_MASK); + + /* + * FIXME: Add mactime handling. For IBSS (ad-hoc) we need to get the + * timestamp from the beacon (acx_tsf_info). In BSS mode (infra) we + * only need the mactime for monitor mode. For now the mactime is + * not valid, so RX_FLAG_TSFT should not be set + */ + status->signal = desc->rssi; + + /* FIXME: Should this be optimized? */ + status->qual = (desc->rssi - WL1271_RX_MIN_RSSI) * 100 / + (WL1271_RX_MAX_RSSI - WL1271_RX_MIN_RSSI); + status->qual = min(status->qual, 100); + status->qual = max(status->qual, 0); + + /* + * FIXME: In wl1251, the SNR should be divided by two. In wl1271 we + * need to divide by two for now, but TI has been discussing about + * changing it. This needs to be rechecked. + */ + status->noise = desc->rssi - (desc->snr >> 1); + + status->freq = ieee80211_channel_to_frequency(desc->channel); + + if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { + status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; + + if (likely(!(desc->flags & WL1271_RX_DESC_DECRYPT_FAIL))) + status->flag |= RX_FLAG_DECRYPTED; + + if (unlikely(desc->flags & WL1271_RX_DESC_MIC_FAIL)) + status->flag |= RX_FLAG_MMIC_ERROR; + } + + status->rate_idx = wl1271_rx_rate_to_idx[desc->rate]; + + if (status->rate_idx == WL1271_RX_RATE_UNSUPPORTED) + wl1271_warning("unsupported rate"); +} + +static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length) +{ + struct ieee80211_rx_status rx_status; + struct wl1271_rx_descriptor *desc; + struct sk_buff *skb; + u16 *fc; + u8 *buf; + u8 beacon = 0; + + skb = dev_alloc_skb(length); + if (!skb) { + wl1271_error("Couldn't allocate RX frame"); + return; + } + + buf = skb_put(skb, length); + wl1271_spi_reg_read(wl, WL1271_SLV_MEM_DATA, buf, length, true); + + /* the data read starts with the descriptor */ + desc = (struct wl1271_rx_descriptor *) buf; + + /* now we pull the descriptor out of the buffer */ + skb_pull(skb, sizeof(*desc)); + + fc = (u16 *)skb->data; + if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) + beacon = 1; + + wl1271_rx_status(wl, desc, &rx_status, beacon); + + wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, + beacon ? "beacon" : ""); + + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); + ieee80211_rx(wl->hw, skb); +} + +void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) +{ + struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; + u32 buf_size; + u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK; + u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; + u32 mem_block; + + while (drv_rx_counter != fw_rx_counter) { + mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter); + buf_size = wl1271_rx_get_buf_size(status, drv_rx_counter); + + if (buf_size == 0) { + wl1271_warning("received empty data"); + break; + } + + wl->rx_mem_pool_addr.addr = + (mem_block << 8) + wl_mem_map->packet_memory_pool_start; + wl->rx_mem_pool_addr.addr_extra = + wl->rx_mem_pool_addr.addr + 4; + + /* Choose the block we want to read */ + wl1271_spi_reg_write(wl, WL1271_SLV_REG_DATA, + &wl->rx_mem_pool_addr, + sizeof(wl->rx_mem_pool_addr), false); + + wl1271_rx_handle_data(wl, buf_size); + + wl->rx_counter++; + drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; + } + + wl1271_reg_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); + + /* This is a workaround for some problems in the chip */ + wl1271_reg_write32(wl, RX_DRIVER_DUMMY_WRITE_ADDRESS, 0x1); + +} diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.h b/drivers/net/wireless/wl12xx/wl1271_rx.h new file mode 100644 index 00000000000..d1ca60e43a2 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_rx.h @@ -0,0 +1,121 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1271_RX_H__ +#define __WL1271_RX_H__ + +#include + +#define WL1271_RX_MAX_RSSI -30 +#define WL1271_RX_MIN_RSSI -95 + +#define WL1271_RX_ALIGN_TO 4 +#define WL1271_RX_ALIGN(len) (((len) + WL1271_RX_ALIGN_TO - 1) & \ + ~(WL1271_RX_ALIGN_TO - 1)) + +#define SHORT_PREAMBLE_BIT BIT(0) +#define OFDM_RATE_BIT BIT(6) +#define PBCC_RATE_BIT BIT(7) + +#define PLCP_HEADER_LENGTH 8 +#define RX_DESC_PACKETID_SHIFT 11 +#define RX_MAX_PACKET_ID 3 + +#define NUM_RX_PKT_DESC_MOD_MASK 7 +#define WL1271_RX_RATE_UNSUPPORTED 0xFF + +#define RX_DESC_VALID_FCS 0x0001 +#define RX_DESC_MATCH_RXADDR1 0x0002 +#define RX_DESC_MCAST 0x0004 +#define RX_DESC_STAINTIM 0x0008 +#define RX_DESC_VIRTUAL_BM 0x0010 +#define RX_DESC_BCAST 0x0020 +#define RX_DESC_MATCH_SSID 0x0040 +#define RX_DESC_MATCH_BSSID 0x0080 +#define RX_DESC_ENCRYPTION_MASK 0x0300 +#define RX_DESC_MEASURMENT 0x0400 +#define RX_DESC_SEQNUM_MASK 0x1800 +#define RX_DESC_MIC_FAIL 0x2000 +#define RX_DESC_DECRYPT_FAIL 0x4000 + +/* + * RX Descriptor flags: + * + * Bits 0-1 - band + * Bit 2 - STBC + * Bit 3 - A-MPDU + * Bit 4 - HT + * Bits 5-7 - encryption + */ +#define WL1271_RX_DESC_BAND_MASK 0x03 +#define WL1271_RX_DESC_ENCRYPT_MASK 0xE0 + +#define WL1271_RX_DESC_BAND_BG 0x00 +#define WL1271_RX_DESC_BAND_J 0x01 +#define WL1271_RX_DESC_BAND_A 0x02 + +#define WL1271_RX_DESC_STBC BIT(2) +#define WL1271_RX_DESC_A_MPDU BIT(3) +#define WL1271_RX_DESC_HT BIT(4) + +#define WL1271_RX_DESC_ENCRYPT_WEP 0x20 +#define WL1271_RX_DESC_ENCRYPT_TKIP 0x40 +#define WL1271_RX_DESC_ENCRYPT_AES 0x60 +#define WL1271_RX_DESC_ENCRYPT_GEM 0x80 + +/* + * RX Descriptor status + * + * Bits 0-2 - status + * Bits 3-7 - reserved + */ +#define WL1271_RX_DESC_STATUS_MASK 0x07 + +#define WL1271_RX_DESC_SUCCESS 0x00 +#define WL1271_RX_DESC_DECRYPT_FAIL 0x01 +#define WL1271_RX_DESC_MIC_FAIL 0x02 +#define WL1271_RX_DESC_DRIVER_RX_Q_FAIL 0x03 + +#define RX_MEM_BLOCK_MASK 0xFF +#define RX_BUF_SIZE_MASK 0xFFF00 +#define RX_BUF_SIZE_SHIFT_DIV 6 + +struct wl1271_rx_descriptor { + u16 length; + u8 status; + u8 flags; + u8 rate; + u8 channel; + s8 rssi; + u8 snr; + u32 timestamp; + u8 packet_class; + u8 process_id; + u8 pad_len; + u8 reserved; +} __attribute__ ((packed)); + +void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status); + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c new file mode 100644 index 00000000000..4a12880c16a --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_spi.c @@ -0,0 +1,382 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include + +#include "wl1271.h" +#include "wl12xx_80211.h" +#include "wl1271_spi.h" + +static int wl1271_translate_reg_addr(struct wl1271 *wl, int addr) +{ + return addr - wl->physical_reg_addr + wl->virtual_reg_addr; +} + +static int wl1271_translate_mem_addr(struct wl1271 *wl, int addr) +{ + return addr - wl->physical_mem_addr + wl->virtual_mem_addr; +} + + +void wl1271_spi_reset(struct wl1271 *wl) +{ + u8 *cmd; + struct spi_transfer t; + struct spi_message m; + + cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); + if (!cmd) { + wl1271_error("could not allocate cmd for spi reset"); + return; + } + + memset(&t, 0, sizeof(t)); + spi_message_init(&m); + + memset(cmd, 0xff, WSPI_INIT_CMD_LEN); + + t.tx_buf = cmd; + t.len = WSPI_INIT_CMD_LEN; + spi_message_add_tail(&t, &m); + + spi_sync(wl->spi, &m); + + wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); +} + +void wl1271_spi_init(struct wl1271 *wl) +{ + u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; + struct spi_transfer t; + struct spi_message m; + + cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); + if (!cmd) { + wl1271_error("could not allocate cmd for spi init"); + return; + } + + memset(crc, 0, sizeof(crc)); + memset(&t, 0, sizeof(t)); + spi_message_init(&m); + + /* + * Set WSPI_INIT_COMMAND + * the data is being send from the MSB to LSB + */ + cmd[2] = 0xff; + cmd[3] = 0xff; + cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; + cmd[0] = 0; + cmd[7] = 0; + cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3; + cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; + + if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) + cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY; + else + cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY; + + cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS + | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; + + crc[0] = cmd[1]; + crc[1] = cmd[0]; + crc[2] = cmd[7]; + crc[3] = cmd[6]; + crc[4] = cmd[5]; + + cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; + cmd[4] |= WSPI_INIT_CMD_END; + + t.tx_buf = cmd; + t.len = WSPI_INIT_CMD_LEN; + spi_message_add_tail(&t, &m); + + spi_sync(wl->spi, &m); + + wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); +} + +/* Set the SPI partitions to access the chip addresses + * + * There are two VIRTUAL (SPI) partitions (the memory partition and the + * registers partition), which are mapped to two different areas of the + * PHYSICAL (hardware) memory. This function also makes other checks to + * ensure that the partitions are not overlapping. In the diagram below, the + * memory partition comes before the register partition, but the opposite is + * also supported. + * + * PHYSICAL address + * space + * + * | | + * ...+----+--> mem_start + * VIRTUAL address ... | | + * space ... | | [PART_0] + * ... | | + * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size + * | | ... | | + * |MEM | ... | | + * | | ... | | + * part_size <--+----+... | | {unused area) + * | | ... | | + * |REG | ... | | + * part_size | | ... | | + * + <--+----+... ...+----+--> reg_start + * reg_size ... | | + * ... | | [PART_1] + * ... | | + * ...+----+--> reg_start + reg_size + * | | + * + */ +int wl1271_set_partition(struct wl1271 *wl, + u32 mem_start, u32 mem_size, + u32 reg_start, u32 reg_size) +{ + struct wl1271_partition *partition; + struct spi_transfer t; + struct spi_message m; + size_t len, cmd_len; + u32 *cmd; + int addr; + + cmd_len = sizeof(u32) + 2 * sizeof(struct wl1271_partition); + cmd = kzalloc(cmd_len, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + spi_message_init(&m); + memset(&t, 0, sizeof(t)); + + partition = (struct wl1271_partition *) (cmd + 1); + addr = HW_ACCESS_PART0_SIZE_ADDR; + len = 2 * sizeof(struct wl1271_partition); + + *cmd |= WSPI_CMD_WRITE; + *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; + + wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + + /* Make sure that the two partitions together don't exceed the + * address range */ + if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { + wl1271_debug(DEBUG_SPI, "Total size exceeds maximum virtual" + " address range. Truncating partition[0]."); + mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; + wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } + + if ((mem_start < reg_start) && + ((mem_start + mem_size) > reg_start)) { + /* Guarantee that the memory partition doesn't overlap the + * registers partition */ + wl1271_debug(DEBUG_SPI, "End of partition[0] is " + "overlapping partition[1]. Adjusted."); + mem_size = reg_start - mem_start; + wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } else if ((reg_start < mem_start) && + ((reg_start + reg_size) > mem_start)) { + /* Guarantee that the register partition doesn't overlap the + * memory partition */ + wl1271_debug(DEBUG_SPI, "End of partition[1] is" + " overlapping partition[0]. Adjusted."); + reg_size = mem_start - reg_start; + wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } + + partition[0].start = mem_start; + partition[0].size = mem_size; + partition[1].start = reg_start; + partition[1].size = reg_size; + + wl->physical_mem_addr = mem_start; + wl->physical_reg_addr = reg_start; + + wl->virtual_mem_addr = 0; + wl->virtual_reg_addr = mem_size; + + t.tx_buf = cmd; + t.len = cmd_len; + spi_message_add_tail(&t, &m); + + spi_sync(wl->spi, &m); + + kfree(cmd); + + return 0; +} + +void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed) +{ + struct spi_transfer t[3]; + struct spi_message m; + u8 *busy_buf; + u32 *cmd; + + cmd = &wl->buffer_cmd; + busy_buf = wl->buffer_busyword; + + *cmd = 0; + *cmd |= WSPI_CMD_READ; + *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; + + if (fixed) + *cmd |= WSPI_CMD_FIXED; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = cmd; + t[0].len = 4; + spi_message_add_tail(&t[0], &m); + + /* Busy and non busy words read */ + t[1].rx_buf = busy_buf; + t[1].len = WL1271_BUSY_WORD_LEN; + spi_message_add_tail(&t[1], &m); + + t[2].rx_buf = buf; + t[2].len = len; + spi_message_add_tail(&t[2], &m); + + spi_sync(wl->spi, &m); + + /* FIXME: check busy words */ + + wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); + wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); +} + +void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed) +{ + struct spi_transfer t[2]; + struct spi_message m; + u32 *cmd; + + cmd = &wl->buffer_cmd; + + *cmd = 0; + *cmd |= WSPI_CMD_WRITE; + *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; + + if (fixed) + *cmd |= WSPI_CMD_FIXED; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = cmd; + t[0].len = sizeof(*cmd); + spi_message_add_tail(&t[0], &m); + + t[1].tx_buf = buf; + t[1].len = len; + spi_message_add_tail(&t[1], &m); + + spi_sync(wl->spi, &m); + + wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); + wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); +} + +void wl1271_spi_mem_read(struct wl1271 *wl, int addr, void *buf, + size_t len) +{ + int physical; + + physical = wl1271_translate_mem_addr(wl, addr); + + wl1271_spi_read(wl, physical, buf, len, false); +} + +void wl1271_spi_mem_write(struct wl1271 *wl, int addr, void *buf, + size_t len) +{ + int physical; + + physical = wl1271_translate_mem_addr(wl, addr); + + wl1271_spi_write(wl, physical, buf, len, false); +} + +void wl1271_spi_reg_read(struct wl1271 *wl, int addr, void *buf, size_t len, + bool fixed) +{ + int physical; + + physical = wl1271_translate_reg_addr(wl, addr); + + wl1271_spi_read(wl, physical, buf, len, fixed); +} + +void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len, + bool fixed) +{ + int physical; + + physical = wl1271_translate_reg_addr(wl, addr); + + wl1271_spi_write(wl, physical, buf, len, fixed); +} + +u32 wl1271_mem_read32(struct wl1271 *wl, int addr) +{ + return wl1271_read32(wl, wl1271_translate_mem_addr(wl, addr)); +} + +void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val) +{ + wl1271_write32(wl, wl1271_translate_mem_addr(wl, addr), val); +} + +u32 wl1271_reg_read32(struct wl1271 *wl, int addr) +{ + return wl1271_read32(wl, wl1271_translate_reg_addr(wl, addr)); +} + +void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val) +{ + wl1271_write32(wl, wl1271_translate_reg_addr(wl, addr), val); +} diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.h b/drivers/net/wireless/wl12xx/wl1271_spi.h new file mode 100644 index 00000000000..2c996845864 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_spi.h @@ -0,0 +1,113 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1271_SPI_H__ +#define __WL1271_SPI_H__ + +#include "wl1271_reg.h" + +#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 + +#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 +#define HW_ACCESS_PART0_START_ADDR 0x1FFC4 +#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 +#define HW_ACCESS_PART1_START_ADDR 0x1FFCC + +#define HW_ACCESS_REGISTER_SIZE 4 + +#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 + +#define WSPI_CMD_READ 0x40000000 +#define WSPI_CMD_WRITE 0x00000000 +#define WSPI_CMD_FIXED 0x20000000 +#define WSPI_CMD_BYTE_LENGTH 0x1FFE0000 +#define WSPI_CMD_BYTE_LENGTH_OFFSET 17 +#define WSPI_CMD_BYTE_ADDR 0x0001FFFF + +#define WSPI_INIT_CMD_CRC_LEN 5 + +#define WSPI_INIT_CMD_START 0x00 +#define WSPI_INIT_CMD_TX 0x40 +/* the extra bypass bit is sampled by the TNET as '1' */ +#define WSPI_INIT_CMD_BYPASS_BIT 0x80 +#define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07 +#define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80 +#define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00 +#define WSPI_INIT_CMD_IOD 0x40 +#define WSPI_INIT_CMD_IP 0x20 +#define WSPI_INIT_CMD_CS 0x10 +#define WSPI_INIT_CMD_WS 0x08 +#define WSPI_INIT_CMD_WSPI 0x01 +#define WSPI_INIT_CMD_END 0x01 + +#define WSPI_INIT_CMD_LEN 8 + +#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ + ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32)) +#define HW_ACCESS_WSPI_INIT_CMD_MASK 0 + + +/* Raw target IO, address is not translated */ +void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed); +void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed); + +/* Memory target IO, address is tranlated to partition 0 */ +void wl1271_spi_mem_read(struct wl1271 *wl, int addr, void *buf, size_t len); +void wl1271_spi_mem_write(struct wl1271 *wl, int addr, void *buf, size_t len); +u32 wl1271_mem_read32(struct wl1271 *wl, int addr); +void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val); + +/* Registers IO */ +void wl1271_spi_reg_read(struct wl1271 *wl, int addr, void *buf, size_t len, + bool fixed); +void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len, + bool fixed); +u32 wl1271_reg_read32(struct wl1271 *wl, int addr); +void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val); + +/* INIT and RESET words */ +void wl1271_spi_reset(struct wl1271 *wl); +void wl1271_spi_init(struct wl1271 *wl); +int wl1271_set_partition(struct wl1271 *wl, + u32 part_start, u32 part_size, + u32 reg_start, u32 reg_size); + +static inline u32 wl1271_read32(struct wl1271 *wl, int addr) +{ + wl1271_spi_read(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); + + return wl->buffer_32; +} + +static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val) +{ + wl->buffer_32 = val; + wl1271_spi_write(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); +} + +#endif /* __WL1271_SPI_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c new file mode 100644 index 00000000000..ff221258b94 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -0,0 +1,378 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "wl1271.h" +#include "wl1271_spi.h" +#include "wl1271_reg.h" +#include "wl1271_ps.h" +#include "wl1271_tx.h" + +static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb) +{ + int i; + + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + if (wl->tx_frames[i] == NULL) { + wl->tx_frames[i] = skb; + return i; + } + + return -EBUSY; +} + +static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra) +{ + struct wl1271_tx_hw_descr *desc; + u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; + u32 total_blocks, excluded; + int id, ret = -EBUSY; + + /* allocate free identifier for the packet */ + id = wl1271_tx_id(wl, skb); + if (id < 0) + return id; + + /* approximate the number of blocks required for this packet + in the firmware */ + /* FIXME: try to figure out what is done here and make it cleaner */ + total_blocks = (skb->len) >> TX_HW_BLOCK_SHIFT_DIV; + excluded = (total_blocks << 2) + (skb->len & 0xff) + 34; + total_blocks += (excluded > 252) ? 2 : 1; + total_blocks += TX_HW_BLOCK_SPARE; + + if (total_blocks <= wl->tx_blocks_available) { + desc = (struct wl1271_tx_hw_descr *)skb_push( + skb, total_len - skb->len); + + desc->extra_mem_blocks = TX_HW_BLOCK_SPARE; + desc->total_mem_blocks = total_blocks; + desc->id = id; + + wl->tx_blocks_available -= total_blocks; + + ret = 0; + + wl1271_debug(DEBUG_TX, + "tx_allocate: size: %d, blocks: %d, id: %d", + total_len, total_blocks, id); + } else + wl->tx_frames[id] = NULL; + + return ret; +} + +static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, + u32 extra, struct ieee80211_tx_info *control) +{ + struct wl1271_tx_hw_descr *desc; + int pad; + + desc = (struct wl1271_tx_hw_descr *) skb->data; + + /* configure packet life time */ + desc->start_time = jiffies_to_usecs(jiffies) - wl->time_offset; + desc->life_time = TX_HW_MGMT_PKT_LIFETIME_TU; + + /* configure the tx attributes */ + desc->tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; + /* FIXME: do we know the packet priority? can we identify mgmt + packets, and use max prio for them at least? */ + desc->tid = 0; + desc->aid = TX_HW_DEFAULT_AID; + desc->reserved = 0; + + /* align the length (and store in terms of words) */ + pad = WL1271_TX_ALIGN(skb->len); + desc->length = pad >> 2; + + /* calculate number of padding bytes */ + pad = pad - skb->len; + desc->tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; + + wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad); + return 0; +} + +static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb, + struct ieee80211_tx_info *control) +{ + + struct wl1271_tx_hw_descr *desc; + int len; + + /* FIXME: This is a workaround for getting non-aligned packets. + This happens at least with EAPOL packets from the user space. + Our DMA requires packets to be aligned on a 4-byte boundary. + */ + if (unlikely((long)skb->data & 0x03)) { + int offset = (4 - (long)skb->data) & 0x03; + wl1271_debug(DEBUG_TX, "skb offset %d", offset); + + /* check whether the current skb can be used */ + if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { + unsigned char *src = skb->data; + + /* align the buffer on a 4-byte boundary */ + skb_reserve(skb, offset); + memmove(skb->data, src, skb->len); + } else { + wl1271_info("No handler, fixme!"); + return -EINVAL; + } + } + + len = WL1271_TX_ALIGN(skb->len); + + /* perform a fixed address block write with the packet */ + wl1271_spi_reg_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true); + + /* write packet new counter into the write access register */ + wl->tx_packets_count++; + wl1271_reg_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); + + desc = (struct wl1271_tx_hw_descr *) skb->data; + wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)", + desc->id, skb, len, desc->length); + + return 0; +} + +/* caller must hold wl->mutex */ +static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) +{ + struct ieee80211_tx_info *info; + u32 extra = 0; + int ret = 0; + u8 idx; + + if (!skb) + return -EINVAL; + + info = IEEE80211_SKB_CB(skb); + + if (info->control.hw_key && + info->control.hw_key->alg == ALG_TKIP) + extra = WL1271_TKIP_IV_SPACE; + + if (info->control.hw_key) { + idx = info->control.hw_key->hw_key_idx; + + /* FIXME: do we have to do this if we're not using WEP? */ + if (unlikely(wl->default_key != idx)) { + ret = wl1271_cmd_set_default_wep_key(wl, idx); + if (ret < 0) + return ret; + } + } + + ret = wl1271_tx_allocate(wl, skb, extra); + if (ret < 0) + return ret; + + ret = wl1271_tx_fill_hdr(wl, skb, extra, info); + if (ret < 0) + return ret; + + ret = wl1271_tx_send_packet(wl, skb, info); + if (ret < 0) + return ret; + + return ret; +} + +void wl1271_tx_work(struct work_struct *work) +{ + struct wl1271 *wl = container_of(work, struct wl1271, tx_work); + struct sk_buff *skb; + bool woken_up = false; + int ret; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + while ((skb = skb_dequeue(&wl->tx_queue))) { + if (!woken_up) { + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + woken_up = true; + } + + ret = wl1271_tx_frame(wl, skb); + if (ret == -EBUSY) { + /* firmware buffer is full, stop queues */ + wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, " + "stop queues"); + ieee80211_stop_queues(wl->hw); + wl->tx_queue_stopped = true; + skb_queue_head(&wl->tx_queue, skb); + goto out; + } else if (ret < 0) { + dev_kfree_skb(skb); + goto out; + } else if (wl->tx_queue_stopped) { + /* firmware buffer has space, restart queues */ + wl1271_debug(DEBUG_TX, + "complete_packet: waking queues"); + ieee80211_wake_queues(wl->hw); + wl->tx_queue_stopped = false; + } + } + +out: + if (woken_up) + wl1271_ps_elp_sleep(wl); + + mutex_unlock(&wl->mutex); +} + +static void wl1271_tx_complete_packet(struct wl1271 *wl, + struct wl1271_tx_hw_res_descr *result) +{ + + struct ieee80211_tx_info *info; + struct sk_buff *skb; + u32 header_len; + int id = result->id; + + /* check for id legality */ + if (id >= TX_HW_RESULT_QUEUE_LEN || wl->tx_frames[id] == NULL) { + wl1271_warning("TX result illegal id: %d", id); + return; + } + + skb = wl->tx_frames[id]; + info = IEEE80211_SKB_CB(skb); + + /* update packet status */ + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { + if (result->status == TX_SUCCESS) + info->flags |= IEEE80211_TX_STAT_ACK; + if (result->status & TX_RETRY_EXCEEDED) { + /* FIXME */ + /* info->status.excessive_retries = 1; */ + wl->stats.excessive_retries++; + } + } + + /* FIXME */ + /* info->status.retry_count = result->ack_failures; */ + wl->stats.retry_count += result->ack_failures; + + /* get header len */ + if (info->control.hw_key && + info->control.hw_key->alg == ALG_TKIP) + header_len = WL1271_TKIP_IV_SPACE + + sizeof(struct wl1271_tx_hw_descr); + else + header_len = sizeof(struct wl1271_tx_hw_descr); + + wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" + " status 0x%x", + result->id, skb, result->ack_failures, + result->rate_class_index, result->status); + + /* remove private header from packet */ + skb_pull(skb, header_len); + + /* return the packet to the stack */ + ieee80211_tx_status(wl->hw, skb); + wl->tx_frames[result->id] = NULL; +} + +/* Called upon reception of a TX complete interrupt */ +void wl1271_tx_complete(struct wl1271 *wl, u32 count) +{ + struct wl1271_acx_mem_map *memmap = + (struct wl1271_acx_mem_map *)wl->target_mem_map; + u32 i; + + wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); + + /* read the tx results from the chipset */ + wl1271_spi_mem_read(wl, memmap->tx_result, + wl->tx_res_if, sizeof(*wl->tx_res_if)); + + /* verify that the result buffer is not getting overrun */ + if (count > TX_HW_RESULT_QUEUE_LEN) { + wl1271_warning("TX result overflow from chipset: %d", count); + count = TX_HW_RESULT_QUEUE_LEN; + } + + /* process the results */ + for (i = 0; i < count; i++) { + struct wl1271_tx_hw_res_descr *result; + u8 offset = wl->tx_results_count & TX_HW_RESULT_QUEUE_LEN_MASK; + + /* process the packet */ + result = &(wl->tx_res_if->tx_results_queue[offset]); + wl1271_tx_complete_packet(wl, result); + + wl->tx_results_count++; + } + + /* write host counter to chipset (to ack) */ + wl1271_mem_write32(wl, memmap->tx_result + + offsetof(struct wl1271_tx_hw_res_if, + tx_result_host_counter), + wl->tx_res_if->tx_result_fw_counter); +} + +/* caller must hold wl->mutex */ +void wl1271_tx_flush(struct wl1271 *wl) +{ + int i; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + + /* TX failure */ +/* control->flags = 0; FIXME */ + + while ((skb = skb_dequeue(&wl->tx_queue))) { + info = IEEE80211_SKB_CB(skb); + + wl1271_debug(DEBUG_TX, "flushing skb 0x%p", skb); + + if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) + continue; + + ieee80211_tx_status(wl->hw, skb); + } + + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + if (wl->tx_frames[i] != NULL) { + skb = wl->tx_frames[i]; + info = IEEE80211_SKB_CB(skb); + + if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) + continue; + + ieee80211_tx_status(wl->hw, skb); + wl->tx_frames[i] = NULL; + } +} diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h new file mode 100644 index 00000000000..4a614067ddb --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_tx.h @@ -0,0 +1,130 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1271_TX_H__ +#define __WL1271_TX_H__ + +#define TX_HW_BLOCK_SPARE 2 +#define TX_HW_BLOCK_SHIFT_DIV 8 + +#define TX_HW_MGMT_PKT_LIFETIME_TU 2000 +/* The chipset reference driver states, that the "aid" value 1 + * is for infra-BSS, but is still always used */ +#define TX_HW_DEFAULT_AID 1 + +#define TX_HW_ATTR_SAVE_RETRIES BIT(0) +#define TX_HW_ATTR_HEADER_PAD BIT(1) +#define TX_HW_ATTR_SESSION_COUNTER (BIT(2) | BIT(3) | BIT(4)) +#define TX_HW_ATTR_RATE_POLICY (BIT(5) | BIT(6) | BIT(7) | \ + BIT(8) | BIT(9)) +#define TX_HW_ATTR_LAST_WORD_PAD (BIT(10) | BIT(11)) +#define TX_HW_ATTR_TX_CMPLT_REQ BIT(12) + +#define TX_HW_ATTR_OFST_SAVE_RETRIES 0 +#define TX_HW_ATTR_OFST_HEADER_PAD 1 +#define TX_HW_ATTR_OFST_SESSION_COUNTER 2 +#define TX_HW_ATTR_OFST_RATE_POLICY 5 +#define TX_HW_ATTR_OFST_LAST_WORD_PAD 10 +#define TX_HW_ATTR_OFST_TX_CMPLT_REQ 12 + +#define TX_HW_RESULT_QUEUE_LEN 16 +#define TX_HW_RESULT_QUEUE_LEN_MASK 0xf + +#define WL1271_TX_ALIGN_TO 4 +#define WL1271_TX_ALIGN(len) (((len) + WL1271_TX_ALIGN_TO - 1) & \ + ~(WL1271_TX_ALIGN_TO - 1)) +#define WL1271_TKIP_IV_SPACE 4 + +struct wl1271_tx_hw_descr { + /* Length of packet in words, including descriptor+header+data */ + u16 length; + /* Number of extra memory blocks to allocate for this packet in + addition to the number of blocks derived from the packet length */ + u8 extra_mem_blocks; + /* Total number of memory blocks allocated by the host for this packet. + Must be equal or greater than the actual blocks number allocated by + HW!! */ + u8 total_mem_blocks; + /* Device time (in us) when the packet arrived to the driver */ + u32 start_time; + /* Max delay in TUs until transmission. The last device time the + packet can be transmitted is: startTime+(1024*LifeTime) */ + u16 life_time; + /* Bitwise fields - see TX_ATTR... definitions above. */ + u16 tx_attr; + /* Packet identifier used also in the Tx-Result. */ + u8 id; + /* The packet TID value (as User-Priority) */ + u8 tid; + /* Identifier of the remote STA in IBSS, 1 in infra-BSS */ + u8 aid; + u8 reserved; +} __attribute__ ((packed)); + +enum wl1271_tx_hw_res_status { + TX_SUCCESS = 0, + TX_HW_ERROR = 1, + TX_DISABLED = 2, + TX_RETRY_EXCEEDED = 3, + TX_TIMEOUT = 4, + TX_KEY_NOT_FOUND = 5, + TX_PEER_NOT_FOUND = 6, + TX_SESSION_MISMATCH = 7 +}; + +struct wl1271_tx_hw_res_descr { + /* Packet Identifier - same value used in the Tx descriptor.*/ + u8 id; + /* The status of the transmission, indicating success or one of + several possible reasons for failure. */ + u8 status; + /* Total air access duration including all retrys and overheads.*/ + u16 medium_usage; + /* The time passed from host xfer to Tx-complete.*/ + u32 fw_handling_time; + /* Total media delay + (from 1st EDCA AIFS counter until TX Complete). */ + u32 medium_delay; + /* LS-byte of last TKIP seq-num (saved per AC for recovery). */ + u8 lsb_security_sequence_number; + /* Retry count - number of transmissions without successful ACK.*/ + u8 ack_failures; + /* The rate that succeeded getting ACK + (Valid only if status=SUCCESS). */ + u8 rate_class_index; + /* for 4-byte alignment. */ + u8 spare; +} __attribute__ ((packed)); + +struct wl1271_tx_hw_res_if { + u32 tx_result_fw_counter; + u32 tx_result_host_counter; + struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN]; +} __attribute__ ((packed)); + +void wl1271_tx_work(struct work_struct *work); +void wl1271_tx_complete(struct wl1271 *wl, u32 count); +void wl1271_tx_flush(struct wl1271 *wl); + +#endif -- cgit v1.2.3-18-g5258 From 30d742d5468c954969766bb0e809f218abc73af7 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 6 Aug 2009 16:25:29 +0300 Subject: wl1271: add wl1271 to Kconfig and the Makefile This patch adds support for the wl1271 driver in the Kconfig and in the Makefile. Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/Kconfig | 12 ++++++++++++ drivers/net/wireless/wl12xx/Makefile | 6 ++++++ 2 files changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 82a0f97975d..af31eabad18 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -16,3 +16,15 @@ config WL1251 If you choose to build a module, it'll be called wl1251. Say N if unsure. + +config WL1271 + tristate "TI wl1271 support" + depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS + select FW_LOADER + select CRC7 + ---help--- + This module adds support for wireless adapters based on the + TI wl1271 chipset. + + If you choose to build a module, it'll be called wl1271. Say N if + unsure. diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index d5595a841f5..ecb88333365 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -3,3 +3,9 @@ wl1251-objs = wl1251_main.o wl1251_spi.o wl1251_event.o \ wl1251_acx.o wl1251_boot.o wl1251_init.o \ wl1251_ops.o wl1251_debugfs.o obj-$(CONFIG_WL1251) += wl1251.o + +wl1271-objs = wl1271_main.o wl1271_spi.o wl1271_cmd.o \ + wl1271_event.o wl1271_tx.o wl1271_rx.o \ + wl1271_ps.o wl1271_acx.o wl1271_boot.o \ + wl1271_init.o wl1271_debugfs.o +obj-$(CONFIG_WL1271) += wl1271.o -- cgit v1.2.3-18-g5258 From 87b5bee86d281383ac2e5cae20ec47afa8fa374a Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:01 +0530 Subject: ath9k: Remove unneeded assignment of protocol field Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 6b07cedf5b7..f6a8b1c384e 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -788,7 +788,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) DMA_FROM_DEVICE); skb_put(skb, ds->ds_rxstat.rs_datalen); - skb->protocol = cpu_to_be16(ETH_P_CONTROL); /* see if any padding is done by the hw and remove it */ hdr = (struct ieee80211_hdr *)skb->data; -- cgit v1.2.3-18-g5258 From 54e4cec69e70ba30aec68650fb95b3a7e1e6dc18 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:09 +0530 Subject: ath9k: Cleanup function return types Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom.c | 5 +---- drivers/net/wireless/ath/ath9k/hw.c | 4 +--- drivers/net/wireless/ath/ath9k/hw.h | 2 +- drivers/net/wireless/ath/ath9k/mac.c | 17 ++++------------- drivers/net/wireless/ath/ath9k/mac.h | 8 ++++---- 5 files changed, 11 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 4cb64a0900b..86b13d1b290 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -35,7 +35,6 @@ static void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) { - if (fbin == AR5416_BCHAN_UNUSED) return fbin; @@ -95,7 +94,7 @@ static inline bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) return sc->bus_ops->eeprom_read(ah, off, data); } -static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, +static inline void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, u8 *pVpdList, u16 numIntercepts, u8 *pRetVpdList) { @@ -120,8 +119,6 @@ static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, pRetVpdList[i] = (u8) k; currPwr += 2; } - - return true; } static void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 71a3bcc450a..6514dc7a7be 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -4019,14 +4019,12 @@ void ath9k_hw_reset_tsf(struct ath_hw *ah) ath9k_ps_restore(ah->ah_sc); } -bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting) +void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting) { if (setting) ah->misc_mode |= AR_PCU_TX_ADD_TSF; else ah->misc_mode &= ~AR_PCU_TX_ADD_TSF; - - return true; } bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index d4aaf4f8db2..e83e900e275 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -601,7 +601,7 @@ void ath9k_hw_write_associd(struct ath_softc *sc); u64 ath9k_hw_gettsf64(struct ath_hw *ah); void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); void ath9k_hw_reset_tsf(struct ath_hw *ah); -bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); +void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us); void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode); void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 6f923e31872..800bfab9463 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -40,20 +40,15 @@ u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q) return REG_READ(ah, AR_QTXDP(q)); } -bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp) +void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp) { REG_WRITE(ah, AR_QTXDP(q), txdp); - - return true; } -bool ath9k_hw_txstart(struct ath_hw *ah, u32 q) +void ath9k_hw_txstart(struct ath_hw *ah, u32 q) { DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Enable TXE on queue: %u\n", q); - REG_WRITE(ah, AR_Q_TXE, 1 << q); - - return true; } u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q) @@ -178,7 +173,7 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) #undef ATH9K_TIME_QUANTUM } -bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, +void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 segLen, bool firstSeg, bool lastSeg, const struct ath_desc *ds0) { @@ -202,8 +197,6 @@ bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, ads->ds_txstatus4 = ads->ds_txstatus5 = 0; ads->ds_txstatus6 = ads->ds_txstatus7 = 0; ads->ds_txstatus8 = ads->ds_txstatus9 = 0; - - return true; } void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds) @@ -888,7 +881,7 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, return 0; } -bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, +void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 size, u32 flags) { struct ar5416_desc *ads = AR5416DESC(ds); @@ -901,8 +894,6 @@ bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, ads->ds_rxstatus8 &= ~AR_RxDone; if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) memset(&(ads->u), 0, sizeof(ads->u)); - - return true; } bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set) diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 1176bce8b76..7b3982295a4 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -628,12 +628,12 @@ struct ath9k_channel; struct ath_rate_table; u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q); -bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp); -bool ath9k_hw_txstart(struct ath_hw *ah, u32 q); +void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp); +void ath9k_hw_txstart(struct ath_hw *ah, u32 q); u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q); bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel); bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q); -bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, +void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 segLen, bool firstSeg, bool lastSeg, const struct ath_desc *ds0); void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds); @@ -668,7 +668,7 @@ bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q); bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q); int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, u32 pa, struct ath_desc *nds, u64 tsf); -bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, +void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 size, u32 flags); bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set); void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp); -- cgit v1.2.3-18-g5258 From c16c9d0657268daaf8a03e7895fb5c5f005285db Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:11 +0530 Subject: ath9k: Try to fix whitespace damage Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom.c | 251 +++++++++++++++----------------- drivers/net/wireless/ath/ath9k/eeprom.h | 193 ++++++++++++------------ 2 files changed, 215 insertions(+), 229 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 86b13d1b290..4303a4d8828 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -2854,7 +2854,6 @@ static struct eeprom_ops eep_def_ops = { .get_spur_channel = ath9k_hw_def_get_spur_channel }; - static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah) { return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF; @@ -2871,22 +2870,24 @@ static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) u16 *eep_data; int addr, eep_start_loc = AR9287_EEP_START_LOC; eep_data = (u16 *)eep; + if (!ath9k_hw_use_flash(ah)) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Reading from EEPROM, not flash\n"); + "Reading from EEPROM, not flash\n"); } for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16); addr++) { if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Unable to read eeprom region \n"); + "Unable to read eeprom region \n"); return false; } eep_data++; } return true; } + static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) { u32 sum = 0, el, integer; @@ -2996,7 +2997,7 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) } static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah, - enum eeprom_param param) + enum eeprom_param param) { struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &eep->modalHeader; @@ -3059,6 +3060,7 @@ static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah, { #define TMP_VAL_VPD_TABLE \ ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); + int i, j, k; int16_t ss; u16 idxL = 0, idxR = 0, numPiers; @@ -3079,6 +3081,7 @@ static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah, [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; ath9k_hw_get_channel_centers(ah, chan, ¢ers); + for (numPiers = 0; numPiers < availPiers; numPiers++) { if (bChans[numPiers] == AR9287_BCHAN_UNUSED) break; @@ -3205,16 +3208,18 @@ static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah, } static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah, - struct ath9k_channel *chan, - struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop, - u8 *pCalChans, u16 availPiers, - int8_t *pPwr) + struct ath9k_channel *chan, + struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop, + u8 *pCalChans, u16 availPiers, + int8_t *pPwr) { u8 pcdac, i = 0; u16 idxL = 0, idxR = 0, numPiers; bool match; struct chan_centers centers; + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + for (numPiers = 0; numPiers < availPiers; numPiers++) { if (pCalChans[numPiers] == AR9287_BCHAN_UNUSED) break; @@ -3272,9 +3277,9 @@ static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah, } } - static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, - struct ath9k_channel *chan, int16_t *pTxPowerIndexOffset) + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset) { struct cal_data_per_freq_ar9287 *pRawDataset; struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop; @@ -3430,7 +3435,6 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, *pTxPowerIndexOffset = 0; } - static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl, u16 AntennaReduction, u16 twiceMaxRegulatoryPower, @@ -3440,8 +3444,8 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - static const u16 tpScaleReductionTable[5] = { 0, 3, 6, 9, - AR5416_MAX_RATE_POWER }; + static const u16 tpScaleReductionTable[5] = + { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; int i; int16_t twiceLargestAntenna; struct cal_ctl_data_ar9287 *rep; @@ -3452,8 +3456,9 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {0, {0, 0, 0, 0} }; u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; - u16 ctlModesFor11g[] = {CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, - CTL_11G_EXT, CTL_2GHT40}; + u16 ctlModesFor11g[] = + {CTL_11B, CTL_11G, CTL_2GHT20, + CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40}; u16 numCtlModes = 0, *pCtlMode = NULL, ctlMode, freq; struct chan_centers centers; int tx_chainmask; @@ -3464,7 +3469,7 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, ath9k_hw_get_channel_centers(ah, chan, ¢ers); twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0], - pEepData->modalHeader.antennaGainCh[1]); + pEepData->modalHeader.antennaGainCh[1]); twiceLargestAntenna = (int16_t)min((AntennaReduction) - twiceLargestAntenna, 0); @@ -3489,42 +3494,41 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, scaledPower = max((u16)0, scaledPower); if (IS_CHAN_2GHZ(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11g) - - SUB_NUM_CTL_MODES_AT_2G_40; + numCtlModes = + ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; pCtlMode = ctlModesFor11g; ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR9287_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCck, 4, false); + pEepData->calTargetPowerCck, + AR9287_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCck, 4, false); ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR9287_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdm, 4, false); + pEepData->calTargetPower2G, + AR9287_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT20, - AR9287_NUM_2G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); + pEepData->calTargetPower2GHT20, + AR9287_NUM_2G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); if (IS_CHAN_HT40(chan)) { numCtlModes = ARRAY_SIZE(ctlModesFor11g); ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT40, - AR9287_NUM_2G_40_TARGET_POWERS, - &targetPowerHt40, 8, true); + pEepData->calTargetPower2GHT40, + AR9287_NUM_2G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR9287_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCckExt, 4, true); + pEepData->calTargetPowerCck, + AR9287_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCckExt, 4, true); ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR9287_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdmExt, 4, true); + pEepData->calTargetPower2G, + AR9287_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); } } for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { - bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || (pCtlMode[ctlMode] == CTL_2GHT40); if (isHt40CtlMode) @@ -3534,14 +3538,15 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, else freq = centers.ctl_center; - if (ah->eep_ops->get_eeprom_ver(ah) == 14 && - ah->eep_ops->get_eeprom_rev(ah) <= 2) + ah->eep_ops->get_eeprom_rev(ah) <= 2) twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d," "EXT_ADDITIVE %d\n", ctlMode, numCtlModes, isHt40CtlMode, (pCtlMode[ctlMode] & EXT_ADDITIVE)); + for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, @@ -3552,12 +3557,12 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, pEepData->ctlIndex[i], chan->channel); if ((((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - pEepData->ctlIndex[i]) || + (pCtlMode[ctlMode] & CTL_MODE_M)) == + pEepData->ctlIndex[i]) || (((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - ((pEepData->ctlIndex[i] & - CTL_MODE_M) | SD_NO_CTL))) { + (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & + CTL_MODE_M) | SD_NO_CTL))) { rep = &(pEepData->ctlData[i]); twiceMinEdgePower = ath9k_hw_get_max_edge_power( @@ -3592,7 +3597,6 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, scaledPower, minCtlPower); - switch (pCtlMode[ctlMode]) { case CTL_11B: @@ -3650,9 +3654,13 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, } } - ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = - ratesArray[rate18mb] = ratesArray[rate24mb] = - targetPowerOfdm.tPow2x[0]; + ratesArray[rate6mb] = + ratesArray[rate9mb] = + ratesArray[rate12mb] = + ratesArray[rate18mb] = + ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; @@ -3663,7 +3671,7 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, if (IS_CHAN_2GHZ(chan)) { ratesArray[rate1l] = targetPowerCck.tPow2x[0]; - ratesArray[rate2s] = ratesArray[rate2l] = + ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; @@ -3680,35 +3688,38 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, if (IS_CHAN_2GHZ(chan)) ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; } + #undef REDUCE_SCALED_POWER_BY_TWO_CHAIN #undef REDUCE_SCALED_POWER_BY_THREE_CHAIN } static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, - struct ath9k_channel *chan, u16 cfgCtl, - u8 twiceAntennaReduction, u8 twiceMaxRegulatoryPower, - u8 powerLimit) + struct ath9k_channel *chan, u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) { #define INCREASE_MAXPOW_BY_TWO_CHAIN 6 #define INCREASE_MAXPOW_BY_THREE_CHAIN 10 + struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; int16_t ratesArray[Ar5416RateSize]; int16_t txPowerIndexOffset = 0; u8 ht40PowerIncForPdadc = 2; int i; + memset(ratesArray, 0, sizeof(ratesArray)); if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= - AR9287_EEP_MINOR_VER_2) + AR9287_EEP_MINOR_VER_2) ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; ath9k_hw_set_AR9287_power_per_rate_table(ah, chan, - &ratesArray[0], cfgCtl, - twiceAntennaReduction, - twiceMaxRegulatoryPower, - powerLimit); - + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit); ath9k_hw_set_AR9287_power_cal_table(ah, chan, &txPowerIndexOffset); @@ -3723,99 +3734,85 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; } - REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, - ATH9K_POW_SM(ratesArray[rate18mb], 24) - | ATH9K_POW_SM(ratesArray[rate12mb], 16) - | ATH9K_POW_SM(ratesArray[rate9mb], 8) - | ATH9K_POW_SM(ratesArray[rate6mb], 0) - ); + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) + | ATH9K_POW_SM(ratesArray[rate9mb], 8) + | ATH9K_POW_SM(ratesArray[rate6mb], 0)); REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, - ATH9K_POW_SM(ratesArray[rate54mb], 24) - | ATH9K_POW_SM(ratesArray[rate48mb], 16) - | ATH9K_POW_SM(ratesArray[rate36mb], 8) - | ATH9K_POW_SM(ratesArray[rate24mb], 0) - ); + ATH9K_POW_SM(ratesArray[rate54mb], 24) + | ATH9K_POW_SM(ratesArray[rate48mb], 16) + | ATH9K_POW_SM(ratesArray[rate36mb], 8) + | ATH9K_POW_SM(ratesArray[rate24mb], 0)); if (IS_CHAN_2GHZ(chan)) { REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, - ATH9K_POW_SM(ratesArray[rate2s], 24) - | ATH9K_POW_SM(ratesArray[rate2l], 16) - | ATH9K_POW_SM(ratesArray[rateXr], 8) - | ATH9K_POW_SM(ratesArray[rate1l], 0) - ); + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0)); REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, - ATH9K_POW_SM(ratesArray[rate11s], 24) - | ATH9K_POW_SM(ratesArray[rate11l], 16) - | ATH9K_POW_SM(ratesArray[rate5_5s], 8) - | ATH9K_POW_SM(ratesArray[rate5_5l], 0) - ); + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); } REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, - ATH9K_POW_SM(ratesArray[rateHt20_3], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_0], 0) - ); + ATH9K_POW_SM(ratesArray[rateHt20_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, - ATH9K_POW_SM(ratesArray[rateHt20_7], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_4], 0) - ); + ATH9K_POW_SM(ratesArray[rateHt20_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); if (IS_CHAN_HT40(chan)) { if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, ATH9K_POW_SM(ratesArray[rateHt40_3], 24) - | ATH9K_POW_SM(ratesArray[rateHt40_2], 16) - | ATH9K_POW_SM(ratesArray[rateHt40_1], 8) - | ATH9K_POW_SM(ratesArray[rateHt40_0], 0) - ); + | ATH9K_POW_SM(ratesArray[rateHt40_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0], 0)); REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, ATH9K_POW_SM(ratesArray[rateHt40_7], 24) - | ATH9K_POW_SM(ratesArray[rateHt40_6], 16) - | ATH9K_POW_SM(ratesArray[rateHt40_5], 8) - | ATH9K_POW_SM(ratesArray[rateHt40_4], 0) - ); + | ATH9K_POW_SM(ratesArray[rateHt40_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4], 0)); } else { REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, ATH9K_POW_SM(ratesArray[rateHt40_3] + ht40PowerIncForPdadc, 24) | ATH9K_POW_SM(ratesArray[rateHt40_2] + - ht40PowerIncForPdadc, 16) + ht40PowerIncForPdadc, 16) | ATH9K_POW_SM(ratesArray[rateHt40_1] + - ht40PowerIncForPdadc, 8) + ht40PowerIncForPdadc, 8) | ATH9K_POW_SM(ratesArray[rateHt40_0] + - ht40PowerIncForPdadc, 0) - ); + ht40PowerIncForPdadc, 0)); REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, ATH9K_POW_SM(ratesArray[rateHt40_7] + ht40PowerIncForPdadc, 24) | ATH9K_POW_SM(ratesArray[rateHt40_6] + - ht40PowerIncForPdadc, 16) + ht40PowerIncForPdadc, 16) | ATH9K_POW_SM(ratesArray[rateHt40_5] + - ht40PowerIncForPdadc, 8) + ht40PowerIncForPdadc, 8) | ATH9K_POW_SM(ratesArray[rateHt40_4] + - ht40PowerIncForPdadc, 0) - ); - + ht40PowerIncForPdadc, 0)); } REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, - ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) - | ATH9K_POW_SM(ratesArray[rateExtCck], 16) - | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) - | ATH9K_POW_SM(ratesArray[rateDupCck], 0) - ); + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(ratesArray[rateExtCck], 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); } - if (IS_CHAN_2GHZ(chan)) i = rate1l; else @@ -3840,7 +3837,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, break; default: DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Invalid chainmask configuration\n"); + "Invalid chainmask configuration\n"); break; } } @@ -3848,7 +3845,6 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, static void ath9k_hw_AR9287_set_addac(struct ath_hw *ah, struct ath9k_channel *chan) { - return; } static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, @@ -3856,7 +3852,6 @@ static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, { struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &eep->modalHeader; - u16 antWrites[AR9287_ANT_16S]; u32 regChainOffset; u8 txRxAttenLocal; @@ -3886,7 +3881,6 @@ static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3); } - REG_WRITE(ah, AR_PHY_SWITCH_COM, ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); @@ -3899,11 +3893,11 @@ static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | - SM(pModal->iqCalICh[i], - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | - SM(pModal->iqCalQCh[i], - AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); txRxAttenLocal = pModal->txRxAttenCh[i]; @@ -3995,23 +3989,20 @@ static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, } static u8 ath9k_hw_AR9287_get_num_ant_config(struct ath_hw *ah, - enum ieee80211_band freq_band) + enum ieee80211_band freq_band) { return 1; } - - - static u16 ath9k_hw_AR9287_get_eeprom_antenna_cfg(struct ath_hw *ah, - struct ath9k_channel *chan) + struct ath9k_channel *chan) { struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &eep->modalHeader; + return pModal->antCtrlCommon & 0xFFFF; } - static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) { @@ -4020,8 +4011,8 @@ static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah, u16 spur_val = AR_NO_SPUR; DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur idx %d is2Ghz. %d val %x\n", - i, is2GHz, ah->config.spurchans[i][is2GHz]); + "Getting spur idx %d is2Ghz. %d val %x\n", + i, is2GHz, ah->config.spurchans[i][is2GHz]); switch (ah->config.spurmode) { case SPUR_DISABLE: @@ -4055,10 +4046,10 @@ static struct eeprom_ops eep_AR9287_ops = { .get_spur_channel = ath9k_hw_AR9287_get_spur_channel }; - int ath9k_hw_eeprom_init(struct ath_hw *ah) { int status; + if (AR_SREV_9287(ah)) { ah->eep_map = EEP_MAP_AR9287; ah->eep_ops = &eep_AR9287_ops; diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index db77e90ed9a..a6447096fd1 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -385,106 +385,103 @@ struct calDataPerFreqOpLoop { } __packed; struct modal_eep_4k_header { - u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS]; - u32 antCtrlCommon; - u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS]; - u8 switchSettling; - u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS]; - u8 rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS]; - u8 adcDesiredSize; - u8 pgaDesiredSize; - u8 xlnaGainCh[AR5416_EEP4K_MAX_CHAINS]; - u8 txEndToXpaOff; - u8 txEndToRxOn; - u8 txFrameToXpaOn; - u8 thresh62; - u8 noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS]; - u8 xpdGain; - u8 xpd; - u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS]; - u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS]; - u8 pdGainOverlap; - u8 ob_01; - u8 db1_01; - u8 xpaBiasLvl; - u8 txFrameToDataStart; - u8 txFrameToPaOn; - u8 ht40PowerIncForPdadc; - u8 bswAtten[AR5416_EEP4K_MAX_CHAINS]; - u8 bswMargin[AR5416_EEP4K_MAX_CHAINS]; - u8 swSettleHt40; - u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS]; - u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS]; - u8 db2_01; - u8 version; - u16 ob_234; - u16 db1_234; - u16 db2_234; - u8 futureModal[4]; - + u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS]; + u32 antCtrlCommon; + u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS]; + u8 switchSettling; + u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS]; + u8 rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS]; + u8 adcDesiredSize; + u8 pgaDesiredSize; + u8 xlnaGainCh[AR5416_EEP4K_MAX_CHAINS]; + u8 txEndToXpaOff; + u8 txEndToRxOn; + u8 txFrameToXpaOn; + u8 thresh62; + u8 noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS]; + u8 xpdGain; + u8 xpd; + u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS]; + u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS]; + u8 pdGainOverlap; + u8 ob_01; + u8 db1_01; + u8 xpaBiasLvl; + u8 txFrameToDataStart; + u8 txFrameToPaOn; + u8 ht40PowerIncForPdadc; + u8 bswAtten[AR5416_EEP4K_MAX_CHAINS]; + u8 bswMargin[AR5416_EEP4K_MAX_CHAINS]; + u8 swSettleHt40; + u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS]; + u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS]; + u8 db2_01; + u8 version; + u16 ob_234; + u16 db1_234; + u16 db2_234; + u8 futureModal[4]; struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; } __packed; struct base_eep_ar9287_header { - u16 length; - u16 checksum; - u16 version; - u8 opCapFlags; - u8 eepMisc; - u16 regDmn[2]; - u8 macAddr[6]; - u8 rxMask; - u8 txMask; - u16 rfSilent; - u16 blueToothOptions; - u16 deviceCap; - u32 binBuildNumber; - u8 deviceType; - u8 openLoopPwrCntl; - int8_t pwrTableOffset; - int8_t tempSensSlope; - int8_t tempSensSlopePalOn; - u8 futureBase[29]; + u16 length; + u16 checksum; + u16 version; + u8 opCapFlags; + u8 eepMisc; + u16 regDmn[2]; + u8 macAddr[6]; + u8 rxMask; + u8 txMask; + u16 rfSilent; + u16 blueToothOptions; + u16 deviceCap; + u32 binBuildNumber; + u8 deviceType; + u8 openLoopPwrCntl; + int8_t pwrTableOffset; + int8_t tempSensSlope; + int8_t tempSensSlopePalOn; + u8 futureBase[29]; } __packed; struct modal_eep_ar9287_header { - u32 antCtrlChain[AR9287_MAX_CHAINS]; - u32 antCtrlCommon; - int8_t antennaGainCh[AR9287_MAX_CHAINS]; - u8 switchSettling; - u8 txRxAttenCh[AR9287_MAX_CHAINS]; - u8 rxTxMarginCh[AR9287_MAX_CHAINS]; - int8_t adcDesiredSize; - u8 txEndToXpaOff; - u8 txEndToRxOn; - u8 txFrameToXpaOn; - u8 thresh62; - int8_t noiseFloorThreshCh[AR9287_MAX_CHAINS]; - u8 xpdGain; - u8 xpd; - int8_t iqCalICh[AR9287_MAX_CHAINS]; - int8_t iqCalQCh[AR9287_MAX_CHAINS]; - u8 pdGainOverlap; - u8 xpaBiasLvl; - u8 txFrameToDataStart; - u8 txFrameToPaOn; - u8 ht40PowerIncForPdadc; - u8 bswAtten[AR9287_MAX_CHAINS]; - u8 bswMargin[AR9287_MAX_CHAINS]; - u8 swSettleHt40; - u8 version; - u8 db1; - u8 db2; - u8 ob_cck; - u8 ob_psk; - u8 ob_qam; - u8 ob_pal_off; - u8 futureModal[30]; - struct spur_chan spurChans[AR9287_EEPROM_MODAL_SPURS]; + u32 antCtrlChain[AR9287_MAX_CHAINS]; + u32 antCtrlCommon; + int8_t antennaGainCh[AR9287_MAX_CHAINS]; + u8 switchSettling; + u8 txRxAttenCh[AR9287_MAX_CHAINS]; + u8 rxTxMarginCh[AR9287_MAX_CHAINS]; + int8_t adcDesiredSize; + u8 txEndToXpaOff; + u8 txEndToRxOn; + u8 txFrameToXpaOn; + u8 thresh62; + int8_t noiseFloorThreshCh[AR9287_MAX_CHAINS]; + u8 xpdGain; + u8 xpd; + int8_t iqCalICh[AR9287_MAX_CHAINS]; + int8_t iqCalQCh[AR9287_MAX_CHAINS]; + u8 pdGainOverlap; + u8 xpaBiasLvl; + u8 txFrameToDataStart; + u8 txFrameToPaOn; + u8 ht40PowerIncForPdadc; + u8 bswAtten[AR9287_MAX_CHAINS]; + u8 bswMargin[AR9287_MAX_CHAINS]; + u8 swSettleHt40; + u8 version; + u8 db1; + u8 db2; + u8 ob_cck; + u8 ob_psk; + u8 ob_qam; + u8 ob_pal_off; + u8 futureModal[30]; + struct spur_chan spurChans[AR9287_EEPROM_MODAL_SPURS]; } __packed; - - struct cal_data_per_freq { u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; u8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; @@ -525,7 +522,6 @@ struct cal_data_op_loop_ar9287 { u8 empty[2][5]; } __packed; - struct cal_data_per_freq_ar9287 { u8 pwrPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS]; u8 vpdPdg[AR9287_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS]; @@ -601,26 +597,25 @@ struct ar5416_eeprom_4k { } __packed; struct ar9287_eeprom { - struct base_eep_ar9287_header baseEepHeader; + struct base_eep_ar9287_header baseEepHeader; u8 custData[AR9287_DATA_SZ]; struct modal_eep_ar9287_header modalHeader; u8 calFreqPier2G[AR9287_NUM_2G_CAL_PIERS]; union cal_data_per_freq_ar9287_u - calPierData2G[AR9287_MAX_CHAINS][AR9287_NUM_2G_CAL_PIERS]; + calPierData2G[AR9287_MAX_CHAINS][AR9287_NUM_2G_CAL_PIERS]; struct cal_target_power_leg - calTargetPowerCck[AR9287_NUM_2G_CCK_TARGET_POWERS]; + calTargetPowerCck[AR9287_NUM_2G_CCK_TARGET_POWERS]; struct cal_target_power_leg - calTargetPower2G[AR9287_NUM_2G_20_TARGET_POWERS]; + calTargetPower2G[AR9287_NUM_2G_20_TARGET_POWERS]; struct cal_target_power_ht - calTargetPower2GHT20[AR9287_NUM_2G_20_TARGET_POWERS]; + calTargetPower2GHT20[AR9287_NUM_2G_20_TARGET_POWERS]; struct cal_target_power_ht - calTargetPower2GHT40[AR9287_NUM_2G_40_TARGET_POWERS]; + calTargetPower2GHT40[AR9287_NUM_2G_40_TARGET_POWERS]; u8 ctlIndex[AR9287_NUM_CTLS]; struct cal_ctl_data_ar9287 ctlData[AR9287_NUM_CTLS]; u8 padding; } __packed; - enum reg_ext_bitmap { REG_EXT_JAPAN_MIDBAND = 1, REG_EXT_FCC_DFS_HT40 = 2, -- cgit v1.2.3-18-g5258 From 6780ccf5652a04493f72fafd9af0d9964ee977ad Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:13 +0530 Subject: ath9k: Remove a few DEBUG mesages We have never used these at all. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom.c | 126 ++++++-------------------------- 1 file changed, 23 insertions(+), 103 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 4303a4d8828..79310225d3a 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -236,9 +236,6 @@ static void ath9k_olc_get_pdadcs(struct ath_hw *ah, pPDADCValues[i] = 0xFF; } - - - static void ath9k_hw_get_target_powers(struct ath_hw *ah, struct ath9k_channel *chan, struct cal_target_power_ht *powInfo, @@ -905,20 +902,8 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, ah->eep_ops->get_eeprom_rev(ah) <= 2) twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " - "EXT_ADDITIVE %d\n", - ctlMode, numCtlModes, isHt40CtlMode, - (pCtlMode[ctlMode] & EXT_ADDITIVE)); - for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " - "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " - "chan %d\n", - i, cfgCtl, pCtlMode[ctlMode], - pEepData->ctlIndex[i], chan->channel); if ((((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == @@ -936,13 +921,6 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, IS_CHAN_2GHZ(chan), AR5416_EEP4K_NUM_BAND_EDGES); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - " MATCH-EE_IDX %d: ch %d is2 %d " - "2xMinEdge %d chainmask %d chains %d\n", - i, freq, IS_CHAN_2GHZ(chan), - twiceMinEdgePower, tx_chainmask, - ar5416_get_ntxchains - (tx_chainmask)); if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { twiceMaxEdgePower = min(twiceMaxEdgePower, @@ -956,12 +934,6 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - " SEL-Min ctlMode %d pCtlMode %d " - "2xMaxEdge %d sP %d minCtlPwr %d\n", - ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, - scaledPower, minCtlPower); - switch (pCtlMode[ctlMode]) { case CTL_11B: for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); @@ -2491,20 +2463,7 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, ah->eep_ops->get_eeprom_rev(ah) <= 2) twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " - "EXT_ADDITIVE %d\n", - ctlMode, numCtlModes, isHt40CtlMode, - (pCtlMode[ctlMode] & EXT_ADDITIVE)); - for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " - "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " - "chan %d\n", - i, cfgCtl, pCtlMode[ctlMode], - pEepData->ctlIndex[i], chan->channel); - if ((((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == pEepData->ctlIndex[i]) || @@ -2517,13 +2476,6 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1], IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - " MATCH-EE_IDX %d: ch %d is2 %d " - "2xMinEdge %d chainmask %d chains %d\n", - i, freq, IS_CHAN_2GHZ(chan), - twiceMinEdgePower, tx_chainmask, - ar5416_get_ntxchains - (tx_chainmask)); if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { twiceMaxEdgePower = min(twiceMaxEdgePower, twiceMinEdgePower); @@ -2536,12 +2488,6 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, minCtlPower = min(twiceMaxEdgePower, scaledPower); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - " SEL-Min ctlMode %d pCtlMode %d " - "2xMaxEdge %d sP %d minCtlPwr %d\n", - ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, - scaledPower, minCtlPower); - switch (pCtlMode[ctlMode]) { case CTL_11B: for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { @@ -2898,17 +2844,15 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) if (!ath9k_hw_use_flash(ah)) { if (!ath9k_hw_nvram_read - (ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { + (ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Reading Magic # failed\n"); + "Reading Magic # failed\n"); return false; } DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "Read Magic = 0x%04X\n", magic); if (magic != AR5416_EEPROM_MAGIC) { - - magic2 = swab16(magic); if (magic2 == AR5416_EEPROM_MAGIC) { @@ -2924,13 +2868,14 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) } } else { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Invalid EEPROM Magic. " - "endianness mismatch.\n"); - return -EINVAL; } + "Invalid EEPROM Magic. " + "endianness mismatch.\n"); + return -EINVAL; + } } } DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ? - "True" : "False"); + "True" : "False"); if (need_swap) el = swab16(ah->eeprom.map9287.baseEepHeader.length); @@ -3360,19 +3305,19 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, if (i == 0) { if (!ath9k_hw_AR9287_get_eeprom( - ah, EEP_OL_PWRCTRL)) { + ah, EEP_OL_PWRCTRL)) { REG_WRITE(ah, AR_PHY_TPCRG5 + - regChainOffset, - SM(pdGainOverlap_t2, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | - SM(gainBoundaries[0], + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | + SM(gainBoundaries[0], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) - | SM(gainBoundaries[1], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) - | SM(gainBoundaries[2], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) - | SM(gainBoundaries[3], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + | SM(gainBoundaries[1], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) + | SM(gainBoundaries[2], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) + | SM(gainBoundaries[3], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); } } @@ -3394,6 +3339,7 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, pdadcValues[ AR9287_NUM_PDADC_VALUES-diff]; } + if (!ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; @@ -3412,6 +3358,7 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, "PDADC (%d,%4x): %4.4x %8.8x\n", i, regChainOffset, regOffset, reg32); + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "PDADC: Chain %d | " "PDADC %3d Value %3d | " @@ -3542,20 +3489,7 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, ah->eep_ops->get_eeprom_rev(ah) <= 2) twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d," - "EXT_ADDITIVE %d\n", ctlMode, numCtlModes, - isHt40CtlMode, (pCtlMode[ctlMode] & EXT_ADDITIVE)); - - for (i = 0; (i < AR9287_NUM_CTLS) - && pEepData->ctlIndex[i]; i++) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "LOOP-Ctlidx %d: cfgCtl 0x%2.2x" - "pCtlMode 0x%2.2x ctlIndex 0x%2.2x" - "chan %d chanctl=xxxx\n", - i, cfgCtl, pCtlMode[ctlMode], - pEepData->ctlIndex[i], chan->channel); - + for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { if ((((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == pEepData->ctlIndex[i]) || @@ -3571,13 +3505,6 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, tx_chainmask) - 1], IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "MATCH-EE_IDX %d: ch %d is2 %d" - "2xMinEdge %d chainmask %d chains %d\n", - i, freq, IS_CHAN_2GHZ(chan), - twiceMinEdgePower, tx_chainmask, - ar5416_get_ntxchains(tx_chainmask)); - if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) twiceMaxEdgePower = min( twiceMaxEdgePower, @@ -3591,14 +3518,7 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d" - "sP %d minCtlPwr %d\n", - ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, - scaledPower, minCtlPower); - switch (pCtlMode[ctlMode]) { - case CTL_11B: for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); @@ -3670,7 +3590,7 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; if (IS_CHAN_2GHZ(chan)) { - ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; ratesArray[rate5_5s] = ratesArray[rate5_5l] = @@ -3686,7 +3606,7 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; if (IS_CHAN_2GHZ(chan)) - ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; + ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; } #undef REDUCE_SCALED_POWER_BY_TWO_CHAIN -- cgit v1.2.3-18-g5258 From b5aec950eeb433d4850c1e5fcf14b666048e647d Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:15 +0530 Subject: ath9k: Split eeprom.c into manageable pieces Add eeprom_def.c, eeprom_4k.c and eeprom_9287.c This improves maintainability. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/Makefile | 3 + drivers/net/wireless/ath/ath9k/eeprom.c | 3776 +------------------------- drivers/net/wireless/ath/ath9k/eeprom.h | 31 +- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 1181 ++++++++ drivers/net/wireless/ath/ath9k/eeprom_9287.c | 1183 ++++++++ drivers/net/wireless/ath/ath9k/eeprom_def.c | 1385 ++++++++++ 6 files changed, 3814 insertions(+), 3745 deletions(-) create mode 100644 drivers/net/wireless/ath/ath9k/eeprom_4k.c create mode 100644 drivers/net/wireless/ath/ath9k/eeprom_9287.c create mode 100644 drivers/net/wireless/ath/ath9k/eeprom_def.c (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 783bc39eb2f..28443e05ec1 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -1,5 +1,8 @@ ath9k-y += hw.o \ eeprom.o \ + eeprom_def.o \ + eeprom_4k.o \ + eeprom_9287.o \ mac.o \ calib.o \ ani.o \ diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 79310225d3a..958948bc73f 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -16,9 +16,16 @@ #include "ath9k.h" -static void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, - u32 reg, u32 mask, - u32 shift, u32 val) +static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) +{ + if (fbin == AR5416_BCHAN_UNUSED) + return fbin; + + return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); +} + +void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask, + u32 shift, u32 val) { u32 regVal; @@ -33,18 +40,8 @@ static void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, return; } -static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) -{ - if (fbin == AR5416_BCHAN_UNUSED) - return fbin; - - return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); -} - -static inline int16_t ath9k_hw_interpolate(u16 target, - u16 srcLeft, u16 srcRight, - int16_t targetLeft, - int16_t targetRight) +int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight, + int16_t targetLeft, int16_t targetRight) { int16_t rv; @@ -58,9 +55,8 @@ static inline int16_t ath9k_hw_interpolate(u16 target, return rv; } -static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, - u16 listSize, u16 *indexL, - u16 *indexR) +bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize, + u16 *indexL, u16 *indexR) { u16 i; @@ -87,16 +83,16 @@ static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, return false; } -static inline bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) +bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) { struct ath_softc *sc = ah->ah_sc; return sc->bus_ops->eeprom_read(ah, off, data); } -static inline void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, - u8 *pVpdList, u16 numIntercepts, - u8 *pRetVpdList) +void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, + u8 *pVpdList, u16 numIntercepts, + u8 *pRetVpdList) { u16 i, k; u8 currPwr = pwrMin; @@ -121,12 +117,12 @@ static inline void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, } } -static void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, - struct ath9k_channel *chan, - struct cal_target_power_leg *powInfo, - u16 numChannels, - struct cal_target_power_leg *pNewPower, - u16 numRates, bool isExtTarget) +void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_target_power_leg *powInfo, + u16 numChannels, + struct cal_target_power_leg *pNewPower, + u16 numRates, bool isExtTarget) { struct chan_centers centers; u16 clo, chi; @@ -176,72 +172,12 @@ static void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, } } -static void ath9k_get_txgain_index(struct ath_hw *ah, - struct ath9k_channel *chan, - struct calDataPerFreqOpLoop *rawDatasetOpLoop, - u8 *calChans, u16 availPiers, u8 *pwr, u8 *pcdacIdx) -{ - u8 pcdac, i = 0; - u16 idxL = 0, idxR = 0, numPiers; - bool match; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - for (numPiers = 0; numPiers < availPiers; numPiers++) - if (calChans[numPiers] == AR5416_BCHAN_UNUSED) - break; - - match = ath9k_hw_get_lower_upper_index( - (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), - calChans, numPiers, &idxL, &idxR); - if (match) { - pcdac = rawDatasetOpLoop[idxL].pcdac[0][0]; - *pwr = rawDatasetOpLoop[idxL].pwrPdg[0][0]; - } else { - pcdac = rawDatasetOpLoop[idxR].pcdac[0][0]; - *pwr = (rawDatasetOpLoop[idxL].pwrPdg[0][0] + - rawDatasetOpLoop[idxR].pwrPdg[0][0])/2; - } - - while (pcdac > ah->originalGain[i] && - i < (AR9280_TX_GAIN_TABLE_SIZE - 1)) - i++; - - *pcdacIdx = i; - return; -} - -static void ath9k_olc_get_pdadcs(struct ath_hw *ah, - u32 initTxGain, - int txPower, - u8 *pPDADCValues) -{ - u32 i; - u32 offset; - - REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_0, - AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); - REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_1, - AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); - - REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL7, - AR_PHY_TX_PWRCTRL_INIT_TX_GAIN, initTxGain); - - offset = txPower; - for (i = 0; i < AR5416_NUM_PDADC_VALUES; i++) - if (i < offset) - pPDADCValues[i] = 0x0; - else - pPDADCValues[i] = 0xFF; -} - -static void ath9k_hw_get_target_powers(struct ath_hw *ah, - struct ath9k_channel *chan, - struct cal_target_power_ht *powInfo, - u16 numChannels, - struct cal_target_power_ht *pNewPower, - u16 numRates, bool isHt40Target) +void ath9k_hw_get_target_powers(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_target_power_ht *powInfo, + u16 numChannels, + struct cal_target_power_ht *pNewPower, + u16 numRates, bool isHt40Target) { struct chan_centers centers; u16 clo, chi; @@ -291,9 +227,8 @@ static void ath9k_hw_get_target_powers(struct ath_hw *ah, } } -static u16 ath9k_hw_get_max_edge_power(u16 freq, - struct cal_ctl_edges *pRdEdgesPower, - bool is2GHz, int num_band_edges) +u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower, + bool is2GHz, int num_band_edges) { u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; int i; @@ -319,3653 +254,6 @@ static u16 ath9k_hw_get_max_edge_power(u16 freq, return twiceMaxEdgePower; } -/****************************************/ -/* EEPROM Operations for 4K sized cards */ -/****************************************/ - -static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah) -{ - return ((ah->eeprom.map4k.baseEepHeader.version >> 12) & 0xF); -} - -static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah) -{ - return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF); -} - -static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) -{ -#define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) - u16 *eep_data = (u16 *)&ah->eeprom.map4k; - int addr, eep_start_loc = 0; - - eep_start_loc = 64; - - if (!ath9k_hw_use_flash(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Reading from EEPROM, not flash\n"); - } - - for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { - if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Unable to read eeprom region \n"); - return false; - } - eep_data++; - } - - return true; -#undef SIZE_EEPROM_4K -} - -static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) -{ -#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) - struct ar5416_eeprom_4k *eep = - (struct ar5416_eeprom_4k *) &ah->eeprom.map4k; - u16 *eepdata, temp, magic, magic2; - u32 sum = 0, el; - bool need_swap = false; - int i, addr; - - - if (!ath9k_hw_use_flash(ah)) { - if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, - &magic)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Reading Magic # failed\n"); - return false; - } - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Read Magic = 0x%04X\n", magic); - - if (magic != AR5416_EEPROM_MAGIC) { - magic2 = swab16(magic); - - if (magic2 == AR5416_EEPROM_MAGIC) { - need_swap = true; - eepdata = (u16 *) (&ah->eeprom); - - for (addr = 0; addr < EEPROM_4K_SIZE; addr++) { - temp = swab16(*eepdata); - *eepdata = temp; - eepdata++; - } - } else { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Invalid EEPROM Magic. " - "endianness mismatch.\n"); - return -EINVAL; - } - } - } - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", - need_swap ? "True" : "False"); - - if (need_swap) - el = swab16(ah->eeprom.map4k.baseEepHeader.length); - else - el = ah->eeprom.map4k.baseEepHeader.length; - - if (el > sizeof(struct ar5416_eeprom_4k)) - el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16); - else - el = el / sizeof(u16); - - eepdata = (u16 *)(&ah->eeprom); - - for (i = 0; i < el; i++) - sum ^= *eepdata++; - - if (need_swap) { - u32 integer; - u16 word; - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "EEPROM Endianness is not native.. Changing\n"); - - word = swab16(eep->baseEepHeader.length); - eep->baseEepHeader.length = word; - - word = swab16(eep->baseEepHeader.checksum); - eep->baseEepHeader.checksum = word; - - word = swab16(eep->baseEepHeader.version); - eep->baseEepHeader.version = word; - - word = swab16(eep->baseEepHeader.regDmn[0]); - eep->baseEepHeader.regDmn[0] = word; - - word = swab16(eep->baseEepHeader.regDmn[1]); - eep->baseEepHeader.regDmn[1] = word; - - word = swab16(eep->baseEepHeader.rfSilent); - eep->baseEepHeader.rfSilent = word; - - word = swab16(eep->baseEepHeader.blueToothOptions); - eep->baseEepHeader.blueToothOptions = word; - - word = swab16(eep->baseEepHeader.deviceCap); - eep->baseEepHeader.deviceCap = word; - - integer = swab32(eep->modalHeader.antCtrlCommon); - eep->modalHeader.antCtrlCommon = integer; - - for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { - integer = swab32(eep->modalHeader.antCtrlChain[i]); - eep->modalHeader.antCtrlChain[i] = integer; - } - - for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { - word = swab16(eep->modalHeader.spurChans[i].spurChan); - eep->modalHeader.spurChans[i].spurChan = word; - } - } - - if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || - ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ah->eep_ops->get_eeprom_ver(ah)); - return -EINVAL; - } - - return 0; -#undef EEPROM_4K_SIZE -} - -static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, - enum eeprom_param param) -{ - struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; - struct modal_eep_4k_header *pModal = &eep->modalHeader; - struct base_eep_header_4k *pBase = &eep->baseEepHeader; - - switch (param) { - case EEP_NFTHRESH_2: - return pModal->noiseFloorThreshCh[0]; - case AR_EEPROM_MAC(0): - return pBase->macAddr[0] << 8 | pBase->macAddr[1]; - case AR_EEPROM_MAC(1): - return pBase->macAddr[2] << 8 | pBase->macAddr[3]; - case AR_EEPROM_MAC(2): - return pBase->macAddr[4] << 8 | pBase->macAddr[5]; - case EEP_REG_0: - return pBase->regDmn[0]; - case EEP_REG_1: - return pBase->regDmn[1]; - case EEP_OP_CAP: - return pBase->deviceCap; - case EEP_OP_MODE: - return pBase->opCapFlags; - case EEP_RF_SILENT: - return pBase->rfSilent; - case EEP_OB_2: - return pModal->ob_01; - case EEP_DB_2: - return pModal->db1_01; - case EEP_MINOR_REV: - return pBase->version & AR5416_EEP_VER_MINOR_MASK; - case EEP_TX_MASK: - return pBase->txMask; - case EEP_RX_MASK: - return pBase->rxMask; - case EEP_FRAC_N_5G: - return 0; - default: - return 0; - } -} - -static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah, - struct ath9k_channel *chan, - struct cal_data_per_freq_4k *pRawDataSet, - u8 *bChans, u16 availPiers, - u16 tPdGainOverlap, int16_t *pMinCalPower, - u16 *pPdGainBoundaries, u8 *pPDADCValues, - u16 numXpdGains) -{ -#define TMP_VAL_VPD_TABLE \ - ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); - int i, j, k; - int16_t ss; - u16 idxL = 0, idxR = 0, numPiers; - static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - - u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; - u8 minPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; - u8 maxPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; - int16_t vpdStep; - int16_t tmpVal; - u16 sizeCurrVpdTable, maxIndex, tgtIndex; - bool match; - int16_t minDelta = 0; - struct chan_centers centers; -#define PD_GAIN_BOUNDARY_DEFAULT 58; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - for (numPiers = 0; numPiers < availPiers; numPiers++) { - if (bChans[numPiers] == AR5416_BCHAN_UNUSED) - break; - } - - match = ath9k_hw_get_lower_upper_index( - (u8)FREQ2FBIN(centers.synth_center, - IS_CHAN_2GHZ(chan)), bChans, numPiers, - &idxL, &idxR); - - if (match) { - for (i = 0; i < numXpdGains; i++) { - minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; - maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pRawDataSet[idxL].pwrPdg[i], - pRawDataSet[idxL].vpdPdg[i], - AR5416_EEP4K_PD_GAIN_ICEPTS, - vpdTableI[i]); - } - } else { - for (i = 0; i < numXpdGains; i++) { - pVpdL = pRawDataSet[idxL].vpdPdg[i]; - pPwrL = pRawDataSet[idxL].pwrPdg[i]; - pVpdR = pRawDataSet[idxR].vpdPdg[i]; - pPwrR = pRawDataSet[idxR].pwrPdg[i]; - - minPwrT4[i] = max(pPwrL[0], pPwrR[0]); - - maxPwrT4[i] = - min(pPwrL[AR5416_EEP4K_PD_GAIN_ICEPTS - 1], - pPwrR[AR5416_EEP4K_PD_GAIN_ICEPTS - 1]); - - - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrL, pVpdL, - AR5416_EEP4K_PD_GAIN_ICEPTS, - vpdTableL[i]); - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrR, pVpdR, - AR5416_EEP4K_PD_GAIN_ICEPTS, - vpdTableR[i]); - - for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { - vpdTableI[i][j] = - (u8)(ath9k_hw_interpolate((u16) - FREQ2FBIN(centers. - synth_center, - IS_CHAN_2GHZ - (chan)), - bChans[idxL], bChans[idxR], - vpdTableL[i][j], vpdTableR[i][j])); - } - } - } - - *pMinCalPower = (int16_t)(minPwrT4[0] / 2); - - k = 0; - - for (i = 0; i < numXpdGains; i++) { - if (i == (numXpdGains - 1)) - pPdGainBoundaries[i] = - (u16)(maxPwrT4[i] / 2); - else - pPdGainBoundaries[i] = - (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); - - pPdGainBoundaries[i] = - min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); - - if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { - minDelta = pPdGainBoundaries[0] - 23; - pPdGainBoundaries[0] = 23; - } else { - minDelta = 0; - } - - if (i == 0) { - if (AR_SREV_9280_10_OR_LATER(ah)) - ss = (int16_t)(0 - (minPwrT4[i] / 2)); - else - ss = 0; - } else { - ss = (int16_t)((pPdGainBoundaries[i - 1] - - (minPwrT4[i] / 2)) - - tPdGainOverlap + 1 + minDelta); - } - vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); - vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); - - while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); - pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); - ss++; - } - - sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); - tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - - (minPwrT4[i] / 2)); - maxIndex = (tgtIndex < sizeCurrVpdTable) ? - tgtIndex : sizeCurrVpdTable; - - while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) - pPDADCValues[k++] = vpdTableI[i][ss++]; - - vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - - vpdTableI[i][sizeCurrVpdTable - 2]); - vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); - - if (tgtIndex >= maxIndex) { - while ((ss <= tgtIndex) && - (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t) TMP_VAL_VPD_TABLE; - pPDADCValues[k++] = (u8)((tmpVal > 255) ? - 255 : tmpVal); - ss++; - } - } - } - - while (i < AR5416_EEP4K_PD_GAINS_IN_MASK) { - pPdGainBoundaries[i] = PD_GAIN_BOUNDARY_DEFAULT; - i++; - } - - while (k < AR5416_NUM_PDADC_VALUES) { - pPDADCValues[k] = pPDADCValues[k - 1]; - k++; - } - - return; -#undef TMP_VAL_VPD_TABLE -} - -static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, - struct ath9k_channel *chan, - int16_t *pTxPowerIndexOffset) -{ - struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; - struct cal_data_per_freq_4k *pRawDataset; - u8 *pCalBChans = NULL; - u16 pdGainOverlap_t2; - static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; - u16 gainBoundaries[AR5416_EEP4K_PD_GAINS_IN_MASK]; - u16 numPiers, i, j; - int16_t tMinCalPower; - u16 numXpdGain, xpdMask; - u16 xpdGainValues[AR5416_EEP4K_NUM_PD_GAINS] = { 0, 0 }; - u32 reg32, regOffset, regChainOffset; - - xpdMask = pEepData->modalHeader.xpdGain; - - if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - pdGainOverlap_t2 = - pEepData->modalHeader.pdGainOverlap; - } else { - pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), - AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); - } - - pCalBChans = pEepData->calFreqPier2G; - numPiers = AR5416_EEP4K_NUM_2G_CAL_PIERS; - - numXpdGain = 0; - - for (i = 1; i <= AR5416_EEP4K_PD_GAINS_IN_MASK; i++) { - if ((xpdMask >> (AR5416_EEP4K_PD_GAINS_IN_MASK - i)) & 1) { - if (numXpdGain >= AR5416_EEP4K_NUM_PD_GAINS) - break; - xpdGainValues[numXpdGain] = - (u16)(AR5416_EEP4K_PD_GAINS_IN_MASK - i); - numXpdGain++; - } - } - - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, - (numXpdGain - 1) & 0x3); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, - xpdGainValues[0]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, - xpdGainValues[1]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0); - - for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { - if (AR_SREV_5416_20_OR_LATER(ah) && - (ah->rxchainmask == 5 || ah->txchainmask == 5) && - (i != 0)) { - regChainOffset = (i == 1) ? 0x2000 : 0x1000; - } else - regChainOffset = i * 0x1000; - - if (pEepData->baseEepHeader.txMask & (1 << i)) { - pRawDataset = pEepData->calPierData2G[i]; - - ath9k_hw_get_4k_gain_boundaries_pdadcs(ah, chan, - pRawDataset, pCalBChans, - numPiers, pdGainOverlap_t2, - &tMinCalPower, gainBoundaries, - pdadcValues, numXpdGain); - - if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { - REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset, - SM(pdGainOverlap_t2, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP) - | SM(gainBoundaries[0], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) - | SM(gainBoundaries[1], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) - | SM(gainBoundaries[2], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) - | SM(gainBoundaries[3], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); - } - - regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; - for (j = 0; j < 32; j++) { - reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | - ((pdadcValues[4 * j + 1] & 0xFF) << 8) | - ((pdadcValues[4 * j + 2] & 0xFF) << 16)| - ((pdadcValues[4 * j + 3] & 0xFF) << 24); - REG_WRITE(ah, regOffset, reg32); - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "PDADC (%d,%4x): %4.4x %8.8x\n", - i, regChainOffset, regOffset, - reg32); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "PDADC: Chain %d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d |\n", - i, 4 * j, pdadcValues[4 * j], - 4 * j + 1, pdadcValues[4 * j + 1], - 4 * j + 2, pdadcValues[4 * j + 2], - 4 * j + 3, - pdadcValues[4 * j + 3]); - - regOffset += 4; - } - } - } - - *pTxPowerIndexOffset = 0; -} - -static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, - struct ath9k_channel *chan, - int16_t *ratesArray, - u16 cfgCtl, - u16 AntennaReduction, - u16 twiceMaxRegulatoryPower, - u16 powerLimit) -{ - struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; - u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - static const u16 tpScaleReductionTable[5] = - { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; - - int i; - int16_t twiceLargestAntenna; - struct cal_ctl_data_4k *rep; - struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { - 0, { 0, 0, 0, 0} - }; - struct cal_target_power_leg targetPowerOfdmExt = { - 0, { 0, 0, 0, 0} }, targetPowerCckExt = { - 0, { 0, 0, 0, 0 } - }; - struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { - 0, {0, 0, 0, 0} - }; - u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; - u16 ctlModesFor11g[] = - { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, - CTL_2GHT40 - }; - u16 numCtlModes, *pCtlMode, ctlMode, freq; - struct chan_centers centers; - int tx_chainmask; - u16 twiceMinEdgePower; - - tx_chainmask = ah->txchainmask; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0]; - - twiceLargestAntenna = (int16_t)min(AntennaReduction - - twiceLargestAntenna, 0); - - maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - - if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { - maxRegAllowedPower -= - (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); - } - - scaledPower = min(powerLimit, maxRegAllowedPower); - scaledPower = max((u16)0, scaledPower); - - numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; - pCtlMode = ctlModesFor11g; - - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR5416_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCck, 4, false); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdm, 4, false); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT20, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); - - if (IS_CHAN_HT40(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11g); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT40, - AR5416_NUM_2G_40_TARGET_POWERS, - &targetPowerHt40, 8, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR5416_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCckExt, 4, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdmExt, 4, true); - } - - for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { - bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || - (pCtlMode[ctlMode] == CTL_2GHT40); - if (isHt40CtlMode) - freq = centers.synth_center; - else if (pCtlMode[ctlMode] & EXT_ADDITIVE) - freq = centers.ext_center; - else - freq = centers.ctl_center; - - if (ah->eep_ops->get_eeprom_ver(ah) == 14 && - ah->eep_ops->get_eeprom_rev(ah) <= 2) - twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - - for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) && - pEepData->ctlIndex[i]; i++) { - - if ((((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - pEepData->ctlIndex[i]) || - (((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - ((pEepData->ctlIndex[i] & CTL_MODE_M) | - SD_NO_CTL))) { - rep = &(pEepData->ctlData[i]); - - twiceMinEdgePower = - ath9k_hw_get_max_edge_power(freq, - rep->ctlEdges[ar5416_get_ntxchains - (tx_chainmask) - 1], - IS_CHAN_2GHZ(chan), - AR5416_EEP4K_NUM_BAND_EDGES); - - if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { - twiceMaxEdgePower = - min(twiceMaxEdgePower, - twiceMinEdgePower); - } else { - twiceMaxEdgePower = twiceMinEdgePower; - break; - } - } - } - - minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); - - switch (pCtlMode[ctlMode]) { - case CTL_11B: - for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); - i++) { - targetPowerCck.tPow2x[i] = - min((u16)targetPowerCck.tPow2x[i], - minCtlPower); - } - break; - case CTL_11G: - for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); - i++) { - targetPowerOfdm.tPow2x[i] = - min((u16)targetPowerOfdm.tPow2x[i], - minCtlPower); - } - break; - case CTL_2GHT20: - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); - i++) { - targetPowerHt20.tPow2x[i] = - min((u16)targetPowerHt20.tPow2x[i], - minCtlPower); - } - break; - case CTL_11B_EXT: - targetPowerCckExt.tPow2x[0] = min((u16) - targetPowerCckExt.tPow2x[0], - minCtlPower); - break; - case CTL_11G_EXT: - targetPowerOfdmExt.tPow2x[0] = min((u16) - targetPowerOfdmExt.tPow2x[0], - minCtlPower); - break; - case CTL_2GHT40: - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); - i++) { - targetPowerHt40.tPow2x[i] = - min((u16)targetPowerHt40.tPow2x[i], - minCtlPower); - } - break; - default: - break; - } - } - - ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = - ratesArray[rate18mb] = ratesArray[rate24mb] = - targetPowerOfdm.tPow2x[0]; - ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; - ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; - ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; - ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; - - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) - ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; - - ratesArray[rate1l] = targetPowerCck.tPow2x[0]; - ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; - ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; - ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3]; - - if (IS_CHAN_HT40(chan)) { - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { - ratesArray[rateHt40_0 + i] = - targetPowerHt40.tPow2x[i]; - } - ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; - ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; - ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; - ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; - } -} - -static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, - struct ath9k_channel *chan, - u16 cfgCtl, - u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) -{ - struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; - struct modal_eep_4k_header *pModal = &pEepData->modalHeader; - int16_t ratesArray[Ar5416RateSize]; - int16_t txPowerIndexOffset = 0; - u8 ht40PowerIncForPdadc = 2; - int i; - - memset(ratesArray, 0, sizeof(ratesArray)); - - if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; - } - - ath9k_hw_set_4k_power_per_rate_table(ah, chan, - &ratesArray[0], cfgCtl, - twiceAntennaReduction, - twiceMaxRegulatoryPower, - powerLimit); - - ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset); - - for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { - ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); - if (ratesArray[i] > AR5416_MAX_RATE_POWER) - ratesArray[i] = AR5416_MAX_RATE_POWER; - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - for (i = 0; i < Ar5416RateSize; i++) - ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, - ATH9K_POW_SM(ratesArray[rate18mb], 24) - | ATH9K_POW_SM(ratesArray[rate12mb], 16) - | ATH9K_POW_SM(ratesArray[rate9mb], 8) - | ATH9K_POW_SM(ratesArray[rate6mb], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, - ATH9K_POW_SM(ratesArray[rate54mb], 24) - | ATH9K_POW_SM(ratesArray[rate48mb], 16) - | ATH9K_POW_SM(ratesArray[rate36mb], 8) - | ATH9K_POW_SM(ratesArray[rate24mb], 0)); - - if (IS_CHAN_2GHZ(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, - ATH9K_POW_SM(ratesArray[rate2s], 24) - | ATH9K_POW_SM(ratesArray[rate2l], 16) - | ATH9K_POW_SM(ratesArray[rateXr], 8) - | ATH9K_POW_SM(ratesArray[rate1l], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, - ATH9K_POW_SM(ratesArray[rate11s], 24) - | ATH9K_POW_SM(ratesArray[rate11l], 16) - | ATH9K_POW_SM(ratesArray[rate5_5s], 8) - | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, - ATH9K_POW_SM(ratesArray[rateHt20_3], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, - ATH9K_POW_SM(ratesArray[rateHt20_7], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); - - if (IS_CHAN_HT40(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, - ATH9K_POW_SM(ratesArray[rateHt40_3] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_2] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_1] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_0] + - ht40PowerIncForPdadc, 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, - ATH9K_POW_SM(ratesArray[rateHt40_7] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_6] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_5] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_4] + - ht40PowerIncForPdadc, 0)); - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, - ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) - | ATH9K_POW_SM(ratesArray[rateExtCck], 16) - | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) - | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); - } - - i = rate6mb; - - if (IS_CHAN_HT40(chan)) - i = rateHt40_0; - else if (IS_CHAN_HT20(chan)) - i = rateHt20_0; - - if (AR_SREV_9280_10_OR_LATER(ah)) - ah->regulatory.max_power_level = - ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; - else - ah->regulatory.max_power_level = ratesArray[i]; - -} - -static void ath9k_hw_4k_set_addac(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct modal_eep_4k_header *pModal; - struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; - u8 biaslevel; - - if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) - return; - - if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) - return; - - pModal = &eep->modalHeader; - - if (pModal->xpaBiasLvl != 0xff) { - biaslevel = pModal->xpaBiasLvl; - INI_RA(&ah->iniAddac, 7, 1) = - (INI_RA(&ah->iniAddac, 7, 1) & (~0x18)) | biaslevel << 3; - } -} - -static void ath9k_hw_4k_set_gain(struct ath_hw *ah, - struct modal_eep_4k_header *pModal, - struct ar5416_eeprom_4k *eep, - u8 txRxAttenLocal, int regChainOffset) -{ - REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, - pModal->antCtrlChain[0]); - - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, - (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & - ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | - SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | - SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); - - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_3) { - txRxAttenLocal = pModal->txRxAttenCh[0]; - - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, - pModal->xatten2Margin[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); - - /* Set the block 1 value to block 0 value */ - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, - AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, - pModal->bswMargin[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, - AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, - AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, - pModal->xatten2Margin[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, - AR_PHY_GAIN_2GHZ_XATTEN2_DB, - pModal->xatten2Db[0]); - } - - REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, - AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); - REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, - AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); - - REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, - AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); - REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, - AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); - - if (AR_SREV_9285_11(ah)) - REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); -} - -/* - * Read EEPROM header info and program the device for correct operation - * given the channel value. - */ -static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct modal_eep_4k_header *pModal; - struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; - u8 txRxAttenLocal; - u8 ob[5], db1[5], db2[5]; - u8 ant_div_control1, ant_div_control2; - u32 regVal; - - pModal = &eep->modalHeader; - txRxAttenLocal = 23; - - REG_WRITE(ah, AR_PHY_SWITCH_COM, - ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); - - /* Single chain for 4K EEPROM*/ - ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0); - - /* Initialize Ant Diversity settings from EEPROM */ - if (pModal->version >= 3) { - ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf); - ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf); - regVal = REG_READ(ah, 0x99ac); - regVal &= (~(0x7f000000)); - regVal |= ((ant_div_control1 & 0x1) << 24); - regVal |= (((ant_div_control1 >> 1) & 0x1) << 29); - regVal |= (((ant_div_control1 >> 2) & 0x1) << 30); - regVal |= ((ant_div_control2 & 0x3) << 25); - regVal |= (((ant_div_control2 >> 2) & 0x3) << 27); - REG_WRITE(ah, 0x99ac, regVal); - regVal = REG_READ(ah, 0x99ac); - regVal = REG_READ(ah, 0xa208); - regVal &= (~(0x1 << 13)); - regVal |= (((ant_div_control1 >> 3) & 0x1) << 13); - REG_WRITE(ah, 0xa208, regVal); - regVal = REG_READ(ah, 0xa208); - } - - if (pModal->version >= 2) { - ob[0] = (pModal->ob_01 & 0xf); - ob[1] = (pModal->ob_01 >> 4) & 0xf; - ob[2] = (pModal->ob_234 & 0xf); - ob[3] = ((pModal->ob_234 >> 4) & 0xf); - ob[4] = ((pModal->ob_234 >> 8) & 0xf); - - db1[0] = (pModal->db1_01 & 0xf); - db1[1] = ((pModal->db1_01 >> 4) & 0xf); - db1[2] = (pModal->db1_234 & 0xf); - db1[3] = ((pModal->db1_234 >> 4) & 0xf); - db1[4] = ((pModal->db1_234 >> 8) & 0xf); - - db2[0] = (pModal->db2_01 & 0xf); - db2[1] = ((pModal->db2_01 >> 4) & 0xf); - db2[2] = (pModal->db2_234 & 0xf); - db2[3] = ((pModal->db2_234 >> 4) & 0xf); - db2[4] = ((pModal->db2_234 >> 8) & 0xf); - - } else if (pModal->version == 1) { - ob[0] = (pModal->ob_01 & 0xf); - ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf; - db1[0] = (pModal->db1_01 & 0xf); - db1[1] = db1[2] = db1[3] = - db1[4] = ((pModal->db1_01 >> 4) & 0xf); - db2[0] = (pModal->db2_01 & 0xf); - db2[1] = db2[2] = db2[3] = - db2[4] = ((pModal->db2_01 >> 4) & 0xf); - } else { - int i; - for (i = 0; i < 5; i++) { - ob[i] = pModal->ob_01; - db1[i] = pModal->db1_01; - db2[i] = pModal->db1_01; - } - } - - if (AR_SREV_9271(ah)) { - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9271_AN_RF2G3_OB_cck, - AR9271_AN_RF2G3_OB_cck_S, - ob[0]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9271_AN_RF2G3_OB_psk, - AR9271_AN_RF2G3_OB_psk_S, - ob[1]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9271_AN_RF2G3_OB_qam, - AR9271_AN_RF2G3_OB_qam_S, - ob[2]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9271_AN_RF2G3_DB_1, - AR9271_AN_RF2G3_DB_1_S, - db1[0]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G4, - AR9271_AN_RF2G4_DB_2, - AR9271_AN_RF2G4_DB_2_S, - db2[0]); - } else { - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_0, - AR9285_AN_RF2G3_OB_0_S, - ob[0]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_1, - AR9285_AN_RF2G3_OB_1_S, - ob[1]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_2, - AR9285_AN_RF2G3_OB_2_S, - ob[2]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_3, - AR9285_AN_RF2G3_OB_3_S, - ob[3]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9285_AN_RF2G3_OB_4, - AR9285_AN_RF2G3_OB_4_S, - ob[4]); - - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9285_AN_RF2G3_DB1_0, - AR9285_AN_RF2G3_DB1_0_S, - db1[0]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9285_AN_RF2G3_DB1_1, - AR9285_AN_RF2G3_DB1_1_S, - db1[1]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G3, - AR9285_AN_RF2G3_DB1_2, - AR9285_AN_RF2G3_DB1_2_S, - db1[2]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB1_3, - AR9285_AN_RF2G4_DB1_3_S, - db1[3]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB1_4, - AR9285_AN_RF2G4_DB1_4_S, db1[4]); - - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_0, - AR9285_AN_RF2G4_DB2_0_S, - db2[0]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_1, - AR9285_AN_RF2G4_DB2_1_S, - db2[1]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_2, - AR9285_AN_RF2G4_DB2_2_S, - db2[2]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_3, - AR9285_AN_RF2G4_DB2_3_S, - db2[3]); - ath9k_hw_analog_shift_rmw(ah, - AR9285_AN_RF2G4, - AR9285_AN_RF2G4_DB2_4, - AR9285_AN_RF2G4_DB2_4_S, - db2[4]); - } - - - if (AR_SREV_9285_11(ah)) - REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); - - REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, - pModal->switchSettling); - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, - pModal->adcDesiredSize); - - REG_WRITE(ah, AR_PHY_RF_CTL4, - SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | - SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | - SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | - SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); - - REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, - pModal->txEndToRxOn); - REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, - pModal->thresh62); - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, - pModal->thresh62); - - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START, - pModal->txFrameToDataStart); - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, - pModal->txFrameToPaOn); - } - - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_3) { - if (IS_CHAN_HT40(chan)) - REG_RMW_FIELD(ah, AR_PHY_SETTLING, - AR_PHY_SETTLING_SWITCH, - pModal->swSettleHt40); - } -} - -static u16 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; - struct modal_eep_4k_header *pModal = &eep->modalHeader; - - return pModal->antCtrlCommon & 0xFFFF; -} - -static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah, - enum ieee80211_band freq_band) -{ - return 1; -} - -static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) -{ -#define EEP_MAP4K_SPURCHAN \ - (ah->eeprom.map4k.modalHeader.spurChans[i].spurChan) - - u16 spur_val = AR_NO_SPUR; - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur idx %d is2Ghz. %d val %x\n", - i, is2GHz, ah->config.spurchans[i][is2GHz]); - - switch (ah->config.spurmode) { - case SPUR_DISABLE: - break; - case SPUR_ENABLE_IOCTL: - spur_val = ah->config.spurchans[i][is2GHz]; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur val from new loc. %d\n", spur_val); - break; - case SPUR_ENABLE_EEPROM: - spur_val = EEP_MAP4K_SPURCHAN; - break; - } - - return spur_val; - -#undef EEP_MAP4K_SPURCHAN -} - -static struct eeprom_ops eep_4k_ops = { - .check_eeprom = ath9k_hw_4k_check_eeprom, - .get_eeprom = ath9k_hw_4k_get_eeprom, - .fill_eeprom = ath9k_hw_4k_fill_eeprom, - .get_eeprom_ver = ath9k_hw_4k_get_eeprom_ver, - .get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev, - .get_num_ant_config = ath9k_hw_4k_get_num_ant_config, - .get_eeprom_antenna_cfg = ath9k_hw_4k_get_eeprom_antenna_cfg, - .set_board_values = ath9k_hw_4k_set_board_values, - .set_addac = ath9k_hw_4k_set_addac, - .set_txpower = ath9k_hw_4k_set_txpower, - .get_spur_channel = ath9k_hw_4k_get_spur_channel -}; - -/************************************************/ -/* EEPROM Operations for non-4K (Default) cards */ -/************************************************/ - -static int ath9k_hw_def_get_eeprom_ver(struct ath_hw *ah) -{ - return ((ah->eeprom.def.baseEepHeader.version >> 12) & 0xF); -} - -static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah) -{ - return ((ah->eeprom.def.baseEepHeader.version) & 0xFFF); -} - -static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) -{ -#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16)) - u16 *eep_data = (u16 *)&ah->eeprom.def; - int addr, ar5416_eep_start_loc = 0x100; - - for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { - if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, - eep_data)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Unable to read eeprom region\n"); - return false; - } - eep_data++; - } - return true; -#undef SIZE_EEPROM_DEF -} - -static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) -{ - struct ar5416_eeprom_def *eep = - (struct ar5416_eeprom_def *) &ah->eeprom.def; - u16 *eepdata, temp, magic, magic2; - u32 sum = 0, el; - bool need_swap = false; - int i, addr, size; - - if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Reading Magic # failed\n"); - return false; - } - - if (!ath9k_hw_use_flash(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Read Magic = 0x%04X\n", magic); - - if (magic != AR5416_EEPROM_MAGIC) { - magic2 = swab16(magic); - - if (magic2 == AR5416_EEPROM_MAGIC) { - size = sizeof(struct ar5416_eeprom_def); - need_swap = true; - eepdata = (u16 *) (&ah->eeprom); - - for (addr = 0; addr < size / sizeof(u16); addr++) { - temp = swab16(*eepdata); - *eepdata = temp; - eepdata++; - } - } else { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Invalid EEPROM Magic. " - "Endianness mismatch.\n"); - return -EINVAL; - } - } - } - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", - need_swap ? "True" : "False"); - - if (need_swap) - el = swab16(ah->eeprom.def.baseEepHeader.length); - else - el = ah->eeprom.def.baseEepHeader.length; - - if (el > sizeof(struct ar5416_eeprom_def)) - el = sizeof(struct ar5416_eeprom_def) / sizeof(u16); - else - el = el / sizeof(u16); - - eepdata = (u16 *)(&ah->eeprom); - - for (i = 0; i < el; i++) - sum ^= *eepdata++; - - if (need_swap) { - u32 integer, j; - u16 word; - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "EEPROM Endianness is not native.. Changing.\n"); - - word = swab16(eep->baseEepHeader.length); - eep->baseEepHeader.length = word; - - word = swab16(eep->baseEepHeader.checksum); - eep->baseEepHeader.checksum = word; - - word = swab16(eep->baseEepHeader.version); - eep->baseEepHeader.version = word; - - word = swab16(eep->baseEepHeader.regDmn[0]); - eep->baseEepHeader.regDmn[0] = word; - - word = swab16(eep->baseEepHeader.regDmn[1]); - eep->baseEepHeader.regDmn[1] = word; - - word = swab16(eep->baseEepHeader.rfSilent); - eep->baseEepHeader.rfSilent = word; - - word = swab16(eep->baseEepHeader.blueToothOptions); - eep->baseEepHeader.blueToothOptions = word; - - word = swab16(eep->baseEepHeader.deviceCap); - eep->baseEepHeader.deviceCap = word; - - for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) { - struct modal_eep_header *pModal = - &eep->modalHeader[j]; - integer = swab32(pModal->antCtrlCommon); - pModal->antCtrlCommon = integer; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - integer = swab32(pModal->antCtrlChain[i]); - pModal->antCtrlChain[i] = integer; - } - - for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { - word = swab16(pModal->spurChans[i].spurChan); - pModal->spurChans[i].spurChan = word; - } - } - } - - if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || - ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ah->eep_ops->get_eeprom_ver(ah)); - return -EINVAL; - } - - return 0; -} - -static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, - enum eeprom_param param) -{ - struct ar5416_eeprom_def *eep = &ah->eeprom.def; - struct modal_eep_header *pModal = eep->modalHeader; - struct base_eep_header *pBase = &eep->baseEepHeader; - - switch (param) { - case EEP_NFTHRESH_5: - return pModal[0].noiseFloorThreshCh[0]; - case EEP_NFTHRESH_2: - return pModal[1].noiseFloorThreshCh[0]; - case AR_EEPROM_MAC(0): - return pBase->macAddr[0] << 8 | pBase->macAddr[1]; - case AR_EEPROM_MAC(1): - return pBase->macAddr[2] << 8 | pBase->macAddr[3]; - case AR_EEPROM_MAC(2): - return pBase->macAddr[4] << 8 | pBase->macAddr[5]; - case EEP_REG_0: - return pBase->regDmn[0]; - case EEP_REG_1: - return pBase->regDmn[1]; - case EEP_OP_CAP: - return pBase->deviceCap; - case EEP_OP_MODE: - return pBase->opCapFlags; - case EEP_RF_SILENT: - return pBase->rfSilent; - case EEP_OB_5: - return pModal[0].ob; - case EEP_DB_5: - return pModal[0].db; - case EEP_OB_2: - return pModal[1].ob; - case EEP_DB_2: - return pModal[1].db; - case EEP_MINOR_REV: - return AR5416_VER_MASK; - case EEP_TX_MASK: - return pBase->txMask; - case EEP_RX_MASK: - return pBase->rxMask; - case EEP_RXGAIN_TYPE: - return pBase->rxGainType; - case EEP_TXGAIN_TYPE: - return pBase->txGainType; - case EEP_OL_PWRCTRL: - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) - return pBase->openLoopPwrCntl ? true : false; - else - return false; - case EEP_RC_CHAIN_MASK: - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) - return pBase->rcChainMask; - else - return 0; - case EEP_DAC_HPWR_5G: - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) - return pBase->dacHiPwrMode_5G; - else - return 0; - case EEP_FRAC_N_5G: - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_22) - return pBase->frac_n_5g; - else - return 0; - default: - return 0; - } -} - -static void ath9k_hw_def_set_gain(struct ath_hw *ah, - struct modal_eep_header *pModal, - struct ar5416_eeprom_def *eep, - u8 txRxAttenLocal, int regChainOffset, int i) -{ - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { - txRxAttenLocal = pModal->txRxAttenCh[i]; - - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, - pModal->bswMargin[i]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_DB, - pModal->bswAtten[i]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, - pModal->xatten2Margin[i]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_DB, - pModal->xatten2Db[i]); - } else { - REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & - ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) - | SM(pModal-> bswMargin[i], - AR_PHY_GAIN_2GHZ_BSW_MARGIN)); - REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & - ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) - | SM(pModal->bswAtten[i], - AR_PHY_GAIN_2GHZ_BSW_ATTEN)); - } - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_RMW_FIELD(ah, - AR_PHY_RXGAIN + regChainOffset, - AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); - REG_RMW_FIELD(ah, - AR_PHY_RXGAIN + regChainOffset, - AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[i]); - } else { - REG_WRITE(ah, - AR_PHY_RXGAIN + regChainOffset, - (REG_READ(ah, AR_PHY_RXGAIN + regChainOffset) & - ~AR_PHY_RXGAIN_TXRX_ATTEN) - | SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN)); - REG_WRITE(ah, - AR_PHY_GAIN_2GHZ + regChainOffset, - (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & - ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | - SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); - } -} - -static void ath9k_hw_def_set_board_values(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct modal_eep_header *pModal; - struct ar5416_eeprom_def *eep = &ah->eeprom.def; - int i, regChainOffset; - u8 txRxAttenLocal; - - pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); - txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; - - REG_WRITE(ah, AR_PHY_SWITCH_COM, - ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (AR_SREV_9280(ah)) { - if (i >= 2) - break; - } - - if (AR_SREV_5416_20_OR_LATER(ah) && - (ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0)) - regChainOffset = (i == 1) ? 0x2000 : 0x1000; - else - regChainOffset = i * 0x1000; - - REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, - pModal->antCtrlChain[i]); - - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, - (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & - ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | - SM(pModal->iqCalICh[i], - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | - SM(pModal->iqCalQCh[i], - AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); - - if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) - ath9k_hw_def_set_gain(ah, pModal, eep, txRxAttenLocal, - regChainOffset, i); - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - if (IS_CHAN_2GHZ(chan)) { - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, - AR_AN_RF2G1_CH0_OB, - AR_AN_RF2G1_CH0_OB_S, - pModal->ob); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, - AR_AN_RF2G1_CH0_DB, - AR_AN_RF2G1_CH0_DB_S, - pModal->db); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, - AR_AN_RF2G1_CH1_OB, - AR_AN_RF2G1_CH1_OB_S, - pModal->ob_ch1); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, - AR_AN_RF2G1_CH1_DB, - AR_AN_RF2G1_CH1_DB_S, - pModal->db_ch1); - } else { - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, - AR_AN_RF5G1_CH0_OB5, - AR_AN_RF5G1_CH0_OB5_S, - pModal->ob); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, - AR_AN_RF5G1_CH0_DB5, - AR_AN_RF5G1_CH0_DB5_S, - pModal->db); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, - AR_AN_RF5G1_CH1_OB5, - AR_AN_RF5G1_CH1_OB5_S, - pModal->ob_ch1); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, - AR_AN_RF5G1_CH1_DB5, - AR_AN_RF5G1_CH1_DB5_S, - pModal->db_ch1); - } - ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, - AR_AN_TOP2_XPABIAS_LVL, - AR_AN_TOP2_XPABIAS_LVL_S, - pModal->xpaBiasLvl); - ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, - AR_AN_TOP2_LOCALBIAS, - AR_AN_TOP2_LOCALBIAS_S, - pModal->local_bias); - REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG, - pModal->force_xpaon); - } - - REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, - pModal->switchSettling); - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, - pModal->adcDesiredSize); - - if (!AR_SREV_9280_10_OR_LATER(ah)) - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, - AR_PHY_DESIRED_SZ_PGA, - pModal->pgaDesiredSize); - - REG_WRITE(ah, AR_PHY_RF_CTL4, - SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) - | SM(pModal->txEndToXpaOff, - AR_PHY_RF_CTL4_TX_END_XPAB_OFF) - | SM(pModal->txFrameToXpaOn, - AR_PHY_RF_CTL4_FRAME_XPAA_ON) - | SM(pModal->txFrameToXpaOn, - AR_PHY_RF_CTL4_FRAME_XPAB_ON)); - - REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, - pModal->txEndToRxOn); - - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, - pModal->thresh62); - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, - AR_PHY_EXT_CCA0_THRESH62, - pModal->thresh62); - } else { - REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62, - pModal->thresh62); - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, - AR_PHY_EXT_CCA_THRESH62, - pModal->thresh62); - } - - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) { - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, - AR_PHY_TX_END_DATA_START, - pModal->txFrameToDataStart); - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, - pModal->txFrameToPaOn); - } - - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { - if (IS_CHAN_HT40(chan)) - REG_RMW_FIELD(ah, AR_PHY_SETTLING, - AR_PHY_SETTLING_SWITCH, - pModal->swSettleHt40); - } - - if (AR_SREV_9280_20_OR_LATER(ah) && - AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) - REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL, - AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK, - pModal->miscBits); - - - if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) { - if (IS_CHAN_2GHZ(chan)) - REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, - eep->baseEepHeader.dacLpMode); - else if (eep->baseEepHeader.dacHiPwrMode_5G) - REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, 0); - else - REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, - eep->baseEepHeader.dacLpMode); - - REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP, - pModal->miscBits >> 2); - - REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL9, - AR_PHY_TX_DESIRED_SCALE_CCK, - eep->baseEepHeader.desiredScaleCCK); - } -} - -static void ath9k_hw_def_set_addac(struct ath_hw *ah, - struct ath9k_channel *chan) -{ -#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt]) - struct modal_eep_header *pModal; - struct ar5416_eeprom_def *eep = &ah->eeprom.def; - u8 biaslevel; - - if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) - return; - - if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) - return; - - pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); - - if (pModal->xpaBiasLvl != 0xff) { - biaslevel = pModal->xpaBiasLvl; - } else { - u16 resetFreqBin, freqBin, freqCount = 0; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - resetFreqBin = FREQ2FBIN(centers.synth_center, - IS_CHAN_2GHZ(chan)); - freqBin = XPA_LVL_FREQ(0) & 0xff; - biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14); - - freqCount++; - - while (freqCount < 3) { - if (XPA_LVL_FREQ(freqCount) == 0x0) - break; - - freqBin = XPA_LVL_FREQ(freqCount) & 0xff; - if (resetFreqBin >= freqBin) - biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14); - else - break; - freqCount++; - } - } - - if (IS_CHAN_2GHZ(chan)) { - INI_RA(&ah->iniAddac, 7, 1) = (INI_RA(&ah->iniAddac, - 7, 1) & (~0x18)) | biaslevel << 3; - } else { - INI_RA(&ah->iniAddac, 6, 1) = (INI_RA(&ah->iniAddac, - 6, 1) & (~0xc0)) | biaslevel << 6; - } -#undef XPA_LVL_FREQ -} - -static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah, - struct ath9k_channel *chan, - struct cal_data_per_freq *pRawDataSet, - u8 *bChans, u16 availPiers, - u16 tPdGainOverlap, int16_t *pMinCalPower, - u16 *pPdGainBoundaries, u8 *pPDADCValues, - u16 numXpdGains) -{ - int i, j, k; - int16_t ss; - u16 idxL = 0, idxR = 0, numPiers; - static u8 vpdTableL[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableR[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableI[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - - u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; - u8 minPwrT4[AR5416_NUM_PD_GAINS]; - u8 maxPwrT4[AR5416_NUM_PD_GAINS]; - int16_t vpdStep; - int16_t tmpVal; - u16 sizeCurrVpdTable, maxIndex, tgtIndex; - bool match; - int16_t minDelta = 0; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - for (numPiers = 0; numPiers < availPiers; numPiers++) { - if (bChans[numPiers] == AR5416_BCHAN_UNUSED) - break; - } - - match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center, - IS_CHAN_2GHZ(chan)), - bChans, numPiers, &idxL, &idxR); - - if (match) { - for (i = 0; i < numXpdGains; i++) { - minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; - maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pRawDataSet[idxL].pwrPdg[i], - pRawDataSet[idxL].vpdPdg[i], - AR5416_PD_GAIN_ICEPTS, - vpdTableI[i]); - } - } else { - for (i = 0; i < numXpdGains; i++) { - pVpdL = pRawDataSet[idxL].vpdPdg[i]; - pPwrL = pRawDataSet[idxL].pwrPdg[i]; - pVpdR = pRawDataSet[idxR].vpdPdg[i]; - pPwrR = pRawDataSet[idxR].pwrPdg[i]; - - minPwrT4[i] = max(pPwrL[0], pPwrR[0]); - - maxPwrT4[i] = - min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], - pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); - - - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrL, pVpdL, - AR5416_PD_GAIN_ICEPTS, - vpdTableL[i]); - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrR, pVpdR, - AR5416_PD_GAIN_ICEPTS, - vpdTableR[i]); - - for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { - vpdTableI[i][j] = - (u8)(ath9k_hw_interpolate((u16) - FREQ2FBIN(centers. - synth_center, - IS_CHAN_2GHZ - (chan)), - bChans[idxL], bChans[idxR], - vpdTableL[i][j], vpdTableR[i][j])); - } - } - } - - *pMinCalPower = (int16_t)(minPwrT4[0] / 2); - - k = 0; - - for (i = 0; i < numXpdGains; i++) { - if (i == (numXpdGains - 1)) - pPdGainBoundaries[i] = - (u16)(maxPwrT4[i] / 2); - else - pPdGainBoundaries[i] = - (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); - - pPdGainBoundaries[i] = - min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); - - if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { - minDelta = pPdGainBoundaries[0] - 23; - pPdGainBoundaries[0] = 23; - } else { - minDelta = 0; - } - - if (i == 0) { - if (AR_SREV_9280_10_OR_LATER(ah)) - ss = (int16_t)(0 - (minPwrT4[i] / 2)); - else - ss = 0; - } else { - ss = (int16_t)((pPdGainBoundaries[i - 1] - - (minPwrT4[i] / 2)) - - tPdGainOverlap + 1 + minDelta); - } - vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); - vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); - - while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); - pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); - ss++; - } - - sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); - tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - - (minPwrT4[i] / 2)); - maxIndex = (tgtIndex < sizeCurrVpdTable) ? - tgtIndex : sizeCurrVpdTable; - - while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - pPDADCValues[k++] = vpdTableI[i][ss++]; - } - - vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - - vpdTableI[i][sizeCurrVpdTable - 2]); - vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); - - if (tgtIndex > maxIndex) { - while ((ss <= tgtIndex) && - (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + - (ss - maxIndex + 1) * vpdStep)); - pPDADCValues[k++] = (u8)((tmpVal > 255) ? - 255 : tmpVal); - ss++; - } - } - } - - while (i < AR5416_PD_GAINS_IN_MASK) { - pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; - i++; - } - - while (k < AR5416_NUM_PDADC_VALUES) { - pPDADCValues[k] = pPDADCValues[k - 1]; - k++; - } - - return; -} - -static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, - struct ath9k_channel *chan, - int16_t *pTxPowerIndexOffset) -{ -#define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x) -#define SM_PDGAIN_B(x, y) \ - SM((gainBoundaries[x]), AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##y) - - struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; - struct cal_data_per_freq *pRawDataset; - u8 *pCalBChans = NULL; - u16 pdGainOverlap_t2; - static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; - u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; - u16 numPiers, i, j; - int16_t tMinCalPower; - u16 numXpdGain, xpdMask; - u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; - u32 reg32, regOffset, regChainOffset; - int16_t modalIdx; - - modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; - xpdMask = pEepData->modalHeader[modalIdx].xpdGain; - - if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - pdGainOverlap_t2 = - pEepData->modalHeader[modalIdx].pdGainOverlap; - } else { - pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), - AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); - } - - if (IS_CHAN_2GHZ(chan)) { - pCalBChans = pEepData->calFreqPier2G; - numPiers = AR5416_NUM_2G_CAL_PIERS; - } else { - pCalBChans = pEepData->calFreqPier5G; - numPiers = AR5416_NUM_5G_CAL_PIERS; - } - - if (OLC_FOR_AR9280_20_LATER && IS_CHAN_2GHZ(chan)) { - pRawDataset = pEepData->calPierData2G[0]; - ah->initPDADC = ((struct calDataPerFreqOpLoop *) - pRawDataset)->vpdPdg[0][0]; - } - - numXpdGain = 0; - - for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { - if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { - if (numXpdGain >= AR5416_NUM_PD_GAINS) - break; - xpdGainValues[numXpdGain] = - (u16)(AR5416_PD_GAINS_IN_MASK - i); - numXpdGain++; - } - } - - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, - (numXpdGain - 1) & 0x3); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, - xpdGainValues[0]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, - xpdGainValues[1]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, - xpdGainValues[2]); - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (AR_SREV_5416_20_OR_LATER(ah) && - (ah->rxchainmask == 5 || ah->txchainmask == 5) && - (i != 0)) { - regChainOffset = (i == 1) ? 0x2000 : 0x1000; - } else - regChainOffset = i * 0x1000; - - if (pEepData->baseEepHeader.txMask & (1 << i)) { - if (IS_CHAN_2GHZ(chan)) - pRawDataset = pEepData->calPierData2G[i]; - else - pRawDataset = pEepData->calPierData5G[i]; - - - if (OLC_FOR_AR9280_20_LATER) { - u8 pcdacIdx; - u8 txPower; - - ath9k_get_txgain_index(ah, chan, - (struct calDataPerFreqOpLoop *)pRawDataset, - pCalBChans, numPiers, &txPower, &pcdacIdx); - ath9k_olc_get_pdadcs(ah, pcdacIdx, - txPower/2, pdadcValues); - } else { - ath9k_hw_get_def_gain_boundaries_pdadcs(ah, - chan, pRawDataset, - pCalBChans, numPiers, - pdGainOverlap_t2, - &tMinCalPower, - gainBoundaries, - pdadcValues, - numXpdGain); - } - - if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { - if (OLC_FOR_AR9280_20_LATER) { - REG_WRITE(ah, - AR_PHY_TPCRG5 + regChainOffset, - SM(0x6, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | - SM_PD_GAIN(1) | SM_PD_GAIN(2) | - SM_PD_GAIN(3) | SM_PD_GAIN(4)); - } else { - REG_WRITE(ah, - AR_PHY_TPCRG5 + regChainOffset, - SM(pdGainOverlap_t2, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP)| - SM_PDGAIN_B(0, 1) | - SM_PDGAIN_B(1, 2) | - SM_PDGAIN_B(2, 3) | - SM_PDGAIN_B(3, 4)); - } - } - - regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; - for (j = 0; j < 32; j++) { - reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | - ((pdadcValues[4 * j + 1] & 0xFF) << 8) | - ((pdadcValues[4 * j + 2] & 0xFF) << 16)| - ((pdadcValues[4 * j + 3] & 0xFF) << 24); - REG_WRITE(ah, regOffset, reg32); - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "PDADC (%d,%4x): %4.4x %8.8x\n", - i, regChainOffset, regOffset, - reg32); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "PDADC: Chain %d | PDADC %3d " - "Value %3d | PDADC %3d Value %3d | " - "PDADC %3d Value %3d | PDADC %3d " - "Value %3d |\n", - i, 4 * j, pdadcValues[4 * j], - 4 * j + 1, pdadcValues[4 * j + 1], - 4 * j + 2, pdadcValues[4 * j + 2], - 4 * j + 3, - pdadcValues[4 * j + 3]); - - regOffset += 4; - } - } - } - - *pTxPowerIndexOffset = 0; -#undef SM_PD_GAIN -#undef SM_PDGAIN_B -} - -static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, - struct ath9k_channel *chan, - int16_t *ratesArray, - u16 cfgCtl, - u16 AntennaReduction, - u16 twiceMaxRegulatoryPower, - u16 powerLimit) -{ -#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ -#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ - - struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; - u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - static const u16 tpScaleReductionTable[5] = - { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; - - int i; - int16_t twiceLargestAntenna; - struct cal_ctl_data *rep; - struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { - 0, { 0, 0, 0, 0} - }; - struct cal_target_power_leg targetPowerOfdmExt = { - 0, { 0, 0, 0, 0} }, targetPowerCckExt = { - 0, { 0, 0, 0, 0 } - }; - struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { - 0, {0, 0, 0, 0} - }; - u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; - u16 ctlModesFor11a[] = - { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; - u16 ctlModesFor11g[] = - { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, - CTL_2GHT40 - }; - u16 numCtlModes, *pCtlMode, ctlMode, freq; - struct chan_centers centers; - int tx_chainmask; - u16 twiceMinEdgePower; - - tx_chainmask = ah->txchainmask; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - twiceLargestAntenna = max( - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[0], - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[1]); - - twiceLargestAntenna = max((u8)twiceLargestAntenna, - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); - - twiceLargestAntenna = (int16_t)min(AntennaReduction - - twiceLargestAntenna, 0); - - maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - - if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { - maxRegAllowedPower -= - (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); - } - - scaledPower = min(powerLimit, maxRegAllowedPower); - - switch (ar5416_get_ntxchains(tx_chainmask)) { - case 1: - break; - case 2: - scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; - break; - case 3: - scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; - break; - } - - scaledPower = max((u16)0, scaledPower); - - if (IS_CHAN_2GHZ(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11g) - - SUB_NUM_CTL_MODES_AT_2G_40; - pCtlMode = ctlModesFor11g; - - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR5416_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCck, 4, false); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdm, 4, false); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT20, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); - - if (IS_CHAN_HT40(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11g); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT40, - AR5416_NUM_2G_40_TARGET_POWERS, - &targetPowerHt40, 8, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR5416_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCckExt, 4, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdmExt, 4, true); - } - } else { - numCtlModes = ARRAY_SIZE(ctlModesFor11a) - - SUB_NUM_CTL_MODES_AT_5G_40; - pCtlMode = ctlModesFor11a; - - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower5G, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerOfdm, 4, false); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower5GHT20, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); - - if (IS_CHAN_HT40(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11a); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower5GHT40, - AR5416_NUM_5G_40_TARGET_POWERS, - &targetPowerHt40, 8, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower5G, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerOfdmExt, 4, true); - } - } - - for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { - bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || - (pCtlMode[ctlMode] == CTL_2GHT40); - if (isHt40CtlMode) - freq = centers.synth_center; - else if (pCtlMode[ctlMode] & EXT_ADDITIVE) - freq = centers.ext_center; - else - freq = centers.ctl_center; - - if (ah->eep_ops->get_eeprom_ver(ah) == 14 && - ah->eep_ops->get_eeprom_rev(ah) <= 2) - twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - - for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { - if ((((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - pEepData->ctlIndex[i]) || - (((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { - rep = &(pEepData->ctlData[i]); - - twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq, - rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1], - IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); - - if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { - twiceMaxEdgePower = min(twiceMaxEdgePower, - twiceMinEdgePower); - } else { - twiceMaxEdgePower = twiceMinEdgePower; - break; - } - } - } - - minCtlPower = min(twiceMaxEdgePower, scaledPower); - - switch (pCtlMode[ctlMode]) { - case CTL_11B: - for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { - targetPowerCck.tPow2x[i] = - min((u16)targetPowerCck.tPow2x[i], - minCtlPower); - } - break; - case CTL_11A: - case CTL_11G: - for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { - targetPowerOfdm.tPow2x[i] = - min((u16)targetPowerOfdm.tPow2x[i], - minCtlPower); - } - break; - case CTL_5GHT20: - case CTL_2GHT20: - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { - targetPowerHt20.tPow2x[i] = - min((u16)targetPowerHt20.tPow2x[i], - minCtlPower); - } - break; - case CTL_11B_EXT: - targetPowerCckExt.tPow2x[0] = min((u16) - targetPowerCckExt.tPow2x[0], - minCtlPower); - break; - case CTL_11A_EXT: - case CTL_11G_EXT: - targetPowerOfdmExt.tPow2x[0] = min((u16) - targetPowerOfdmExt.tPow2x[0], - minCtlPower); - break; - case CTL_5GHT40: - case CTL_2GHT40: - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { - targetPowerHt40.tPow2x[i] = - min((u16)targetPowerHt40.tPow2x[i], - minCtlPower); - } - break; - default: - break; - } - } - - ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = - ratesArray[rate18mb] = ratesArray[rate24mb] = - targetPowerOfdm.tPow2x[0]; - ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; - ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; - ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; - ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; - - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) - ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; - - if (IS_CHAN_2GHZ(chan)) { - ratesArray[rate1l] = targetPowerCck.tPow2x[0]; - ratesArray[rate2s] = ratesArray[rate2l] = - targetPowerCck.tPow2x[1]; - ratesArray[rate5_5s] = ratesArray[rate5_5l] = - targetPowerCck.tPow2x[2]; - ratesArray[rate11s] = ratesArray[rate11l] = - targetPowerCck.tPow2x[3]; - } - if (IS_CHAN_HT40(chan)) { - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { - ratesArray[rateHt40_0 + i] = - targetPowerHt40.tPow2x[i]; - } - ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; - ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; - ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; - if (IS_CHAN_2GHZ(chan)) { - ratesArray[rateExtCck] = - targetPowerCckExt.tPow2x[0]; - } - } -} - -static void ath9k_hw_def_set_txpower(struct ath_hw *ah, - struct ath9k_channel *chan, - u16 cfgCtl, - u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) -{ -#define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta) - struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; - struct modal_eep_header *pModal = - &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); - int16_t ratesArray[Ar5416RateSize]; - int16_t txPowerIndexOffset = 0; - u8 ht40PowerIncForPdadc = 2; - int i, cck_ofdm_delta = 0; - - memset(ratesArray, 0, sizeof(ratesArray)); - - if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; - } - - ath9k_hw_set_def_power_per_rate_table(ah, chan, - &ratesArray[0], cfgCtl, - twiceAntennaReduction, - twiceMaxRegulatoryPower, - powerLimit); - - ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset); - - for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { - ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); - if (ratesArray[i] > AR5416_MAX_RATE_POWER) - ratesArray[i] = AR5416_MAX_RATE_POWER; - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - for (i = 0; i < Ar5416RateSize; i++) - ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, - ATH9K_POW_SM(ratesArray[rate18mb], 24) - | ATH9K_POW_SM(ratesArray[rate12mb], 16) - | ATH9K_POW_SM(ratesArray[rate9mb], 8) - | ATH9K_POW_SM(ratesArray[rate6mb], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, - ATH9K_POW_SM(ratesArray[rate54mb], 24) - | ATH9K_POW_SM(ratesArray[rate48mb], 16) - | ATH9K_POW_SM(ratesArray[rate36mb], 8) - | ATH9K_POW_SM(ratesArray[rate24mb], 0)); - - if (IS_CHAN_2GHZ(chan)) { - if (OLC_FOR_AR9280_20_LATER) { - cck_ofdm_delta = 2; - REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, - ATH9K_POW_SM(RT_AR_DELTA(rate2s), 24) - | ATH9K_POW_SM(RT_AR_DELTA(rate2l), 16) - | ATH9K_POW_SM(ratesArray[rateXr], 8) - | ATH9K_POW_SM(RT_AR_DELTA(rate1l), 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, - ATH9K_POW_SM(RT_AR_DELTA(rate11s), 24) - | ATH9K_POW_SM(RT_AR_DELTA(rate11l), 16) - | ATH9K_POW_SM(RT_AR_DELTA(rate5_5s), 8) - | ATH9K_POW_SM(RT_AR_DELTA(rate5_5l), 0)); - } else { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, - ATH9K_POW_SM(ratesArray[rate2s], 24) - | ATH9K_POW_SM(ratesArray[rate2l], 16) - | ATH9K_POW_SM(ratesArray[rateXr], 8) - | ATH9K_POW_SM(ratesArray[rate1l], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, - ATH9K_POW_SM(ratesArray[rate11s], 24) - | ATH9K_POW_SM(ratesArray[rate11l], 16) - | ATH9K_POW_SM(ratesArray[rate5_5s], 8) - | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); - } - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, - ATH9K_POW_SM(ratesArray[rateHt20_3], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, - ATH9K_POW_SM(ratesArray[rateHt20_7], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); - - if (IS_CHAN_HT40(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, - ATH9K_POW_SM(ratesArray[rateHt40_3] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_2] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_1] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_0] + - ht40PowerIncForPdadc, 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, - ATH9K_POW_SM(ratesArray[rateHt40_7] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_6] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_5] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_4] + - ht40PowerIncForPdadc, 0)); - if (OLC_FOR_AR9280_20_LATER) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, - ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) - | ATH9K_POW_SM(RT_AR_DELTA(rateExtCck), 16) - | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) - | ATH9K_POW_SM(RT_AR_DELTA(rateDupCck), 0)); - } else { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, - ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) - | ATH9K_POW_SM(ratesArray[rateExtCck], 16) - | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) - | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); - } - } - - REG_WRITE(ah, AR_PHY_POWER_TX_SUB, - ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) - | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); - - i = rate6mb; - - if (IS_CHAN_HT40(chan)) - i = rateHt40_0; - else if (IS_CHAN_HT20(chan)) - i = rateHt20_0; - - if (AR_SREV_9280_10_OR_LATER(ah)) - ah->regulatory.max_power_level = - ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; - else - ah->regulatory.max_power_level = ratesArray[i]; - - switch(ar5416_get_ntxchains(ah->txchainmask)) { - case 1: - break; - case 2: - ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; - break; - case 3: - ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Invalid chainmask configuration\n"); - break; - } -} - -static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah, - enum ieee80211_band freq_band) -{ - struct ar5416_eeprom_def *eep = &ah->eeprom.def; - struct modal_eep_header *pModal = - &(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]); - struct base_eep_header *pBase = &eep->baseEepHeader; - u8 num_ant_config; - - num_ant_config = 1; - - if (pBase->version >= 0x0E0D) - if (pModal->useAnt1) - num_ant_config += 1; - - return num_ant_config; -} - -static u16 ath9k_hw_def_get_eeprom_antenna_cfg(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct ar5416_eeprom_def *eep = &ah->eeprom.def; - struct modal_eep_header *pModal = - &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); - - return pModal->antCtrlCommon & 0xFFFF; -} - -static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) -{ -#define EEP_DEF_SPURCHAN \ - (ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan) - - u16 spur_val = AR_NO_SPUR; - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur idx %d is2Ghz. %d val %x\n", - i, is2GHz, ah->config.spurchans[i][is2GHz]); - - switch (ah->config.spurmode) { - case SPUR_DISABLE: - break; - case SPUR_ENABLE_IOCTL: - spur_val = ah->config.spurchans[i][is2GHz]; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur val from new loc. %d\n", spur_val); - break; - case SPUR_ENABLE_EEPROM: - spur_val = EEP_DEF_SPURCHAN; - break; - } - - return spur_val; - -#undef EEP_DEF_SPURCHAN -} - -static struct eeprom_ops eep_def_ops = { - .check_eeprom = ath9k_hw_def_check_eeprom, - .get_eeprom = ath9k_hw_def_get_eeprom, - .fill_eeprom = ath9k_hw_def_fill_eeprom, - .get_eeprom_ver = ath9k_hw_def_get_eeprom_ver, - .get_eeprom_rev = ath9k_hw_def_get_eeprom_rev, - .get_num_ant_config = ath9k_hw_def_get_num_ant_config, - .get_eeprom_antenna_cfg = ath9k_hw_def_get_eeprom_antenna_cfg, - .set_board_values = ath9k_hw_def_set_board_values, - .set_addac = ath9k_hw_def_set_addac, - .set_txpower = ath9k_hw_def_set_txpower, - .get_spur_channel = ath9k_hw_def_get_spur_channel -}; - -static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah) -{ - return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF; -} - -static int ath9k_hw_AR9287_get_eeprom_rev(struct ath_hw *ah) -{ - return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF; -} - -static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) -{ - struct ar9287_eeprom *eep = &ah->eeprom.map9287; - u16 *eep_data; - int addr, eep_start_loc = AR9287_EEP_START_LOC; - eep_data = (u16 *)eep; - - if (!ath9k_hw_use_flash(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Reading from EEPROM, not flash\n"); - } - - for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16); - addr++) { - if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Unable to read eeprom region \n"); - return false; - } - eep_data++; - } - return true; -} - -static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) -{ - u32 sum = 0, el, integer; - u16 temp, word, magic, magic2, *eepdata; - int i, addr; - bool need_swap = false; - struct ar9287_eeprom *eep = &ah->eeprom.map9287; - - if (!ath9k_hw_use_flash(ah)) { - if (!ath9k_hw_nvram_read - (ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Reading Magic # failed\n"); - return false; - } - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Read Magic = 0x%04X\n", magic); - if (magic != AR5416_EEPROM_MAGIC) { - magic2 = swab16(magic); - - if (magic2 == AR5416_EEPROM_MAGIC) { - need_swap = true; - eepdata = (u16 *)(&ah->eeprom); - - for (addr = 0; - addr < sizeof(struct ar9287_eeprom) / sizeof(u16); - addr++) { - temp = swab16(*eepdata); - *eepdata = temp; - eepdata++; - } - } else { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Invalid EEPROM Magic. " - "endianness mismatch.\n"); - return -EINVAL; - } - } - } - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ? - "True" : "False"); - - if (need_swap) - el = swab16(ah->eeprom.map9287.baseEepHeader.length); - else - el = ah->eeprom.map9287.baseEepHeader.length; - - if (el > sizeof(struct ar9287_eeprom)) - el = sizeof(struct ar9287_eeprom) / sizeof(u16); - else - el = el / sizeof(u16); - - eepdata = (u16 *)(&ah->eeprom); - for (i = 0; i < el; i++) - sum ^= *eepdata++; - - if (need_swap) { - word = swab16(eep->baseEepHeader.length); - eep->baseEepHeader.length = word; - - word = swab16(eep->baseEepHeader.checksum); - eep->baseEepHeader.checksum = word; - - word = swab16(eep->baseEepHeader.version); - eep->baseEepHeader.version = word; - - word = swab16(eep->baseEepHeader.regDmn[0]); - eep->baseEepHeader.regDmn[0] = word; - - word = swab16(eep->baseEepHeader.regDmn[1]); - eep->baseEepHeader.regDmn[1] = word; - - word = swab16(eep->baseEepHeader.rfSilent); - eep->baseEepHeader.rfSilent = word; - - word = swab16(eep->baseEepHeader.blueToothOptions); - eep->baseEepHeader.blueToothOptions = word; - - word = swab16(eep->baseEepHeader.deviceCap); - eep->baseEepHeader.deviceCap = word; - - integer = swab32(eep->modalHeader.antCtrlCommon); - eep->modalHeader.antCtrlCommon = integer; - - for (i = 0; i < AR9287_MAX_CHAINS; i++) { - integer = swab32(eep->modalHeader.antCtrlChain[i]); - eep->modalHeader.antCtrlChain[i] = integer; - } - - for (i = 0; i < AR9287_EEPROM_MODAL_SPURS; i++) { - word = swab16(eep->modalHeader.spurChans[i].spurChan); - eep->modalHeader.spurChans[i].spurChan = word; - } - } - - if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER - || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ah->eep_ops->get_eeprom_ver(ah)); - return -EINVAL; - } - - return 0; -} - -static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah, - enum eeprom_param param) -{ - struct ar9287_eeprom *eep = &ah->eeprom.map9287; - struct modal_eep_ar9287_header *pModal = &eep->modalHeader; - struct base_eep_ar9287_header *pBase = &eep->baseEepHeader; - u16 ver_minor; - - ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK; - switch (param) { - case EEP_NFTHRESH_2: - return pModal->noiseFloorThreshCh[0]; - case AR_EEPROM_MAC(0): - return pBase->macAddr[0] << 8 | pBase->macAddr[1]; - case AR_EEPROM_MAC(1): - return pBase->macAddr[2] << 8 | pBase->macAddr[3]; - case AR_EEPROM_MAC(2): - return pBase->macAddr[4] << 8 | pBase->macAddr[5]; - case EEP_REG_0: - return pBase->regDmn[0]; - case EEP_REG_1: - return pBase->regDmn[1]; - case EEP_OP_CAP: - return pBase->deviceCap; - case EEP_OP_MODE: - return pBase->opCapFlags; - case EEP_RF_SILENT: - return pBase->rfSilent; - case EEP_MINOR_REV: - return ver_minor; - case EEP_TX_MASK: - return pBase->txMask; - case EEP_RX_MASK: - return pBase->rxMask; - case EEP_DEV_TYPE: - return pBase->deviceType; - case EEP_OL_PWRCTRL: - return pBase->openLoopPwrCntl; - case EEP_TEMPSENSE_SLOPE: - if (ver_minor >= AR9287_EEP_MINOR_VER_2) - return pBase->tempSensSlope; - else - return 0; - case EEP_TEMPSENSE_SLOPE_PAL_ON: - if (ver_minor >= AR9287_EEP_MINOR_VER_3) - return pBase->tempSensSlopePalOn; - else - return 0; - default: - return 0; - } -} - - -static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah, - struct ath9k_channel *chan, - struct cal_data_per_freq_ar9287 *pRawDataSet, - u8 *bChans, u16 availPiers, - u16 tPdGainOverlap, int16_t *pMinCalPower, - u16 *pPdGainBoundaries, u8 *pPDADCValues, - u16 numXpdGains) -{ -#define TMP_VAL_VPD_TABLE \ - ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); - - int i, j, k; - int16_t ss; - u16 idxL = 0, idxR = 0, numPiers; - u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; - u8 minPwrT4[AR9287_NUM_PD_GAINS]; - u8 maxPwrT4[AR9287_NUM_PD_GAINS]; - int16_t vpdStep; - int16_t tmpVal; - u16 sizeCurrVpdTable, maxIndex, tgtIndex; - bool match; - int16_t minDelta = 0; - struct chan_centers centers; - static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - for (numPiers = 0; numPiers < availPiers; numPiers++) { - if (bChans[numPiers] == AR9287_BCHAN_UNUSED) - break; - } - - match = ath9k_hw_get_lower_upper_index( - (u8)FREQ2FBIN(centers.synth_center, - IS_CHAN_2GHZ(chan)), bChans, numPiers, - &idxL, &idxR); - - if (match) { - for (i = 0; i < numXpdGains; i++) { - minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; - maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pRawDataSet[idxL].pwrPdg[i], - pRawDataSet[idxL].vpdPdg[i], - AR9287_PD_GAIN_ICEPTS, vpdTableI[i]); - } - } else { - for (i = 0; i < numXpdGains; i++) { - pVpdL = pRawDataSet[idxL].vpdPdg[i]; - pPwrL = pRawDataSet[idxL].pwrPdg[i]; - pVpdR = pRawDataSet[idxR].vpdPdg[i]; - pPwrR = pRawDataSet[idxR].pwrPdg[i]; - - minPwrT4[i] = max(pPwrL[0], pPwrR[0]); - - maxPwrT4[i] = - min(pPwrL[AR9287_PD_GAIN_ICEPTS - 1], - pPwrR[AR9287_PD_GAIN_ICEPTS - 1]); - - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrL, pVpdL, - AR9287_PD_GAIN_ICEPTS, - vpdTableL[i]); - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrR, pVpdR, - AR9287_PD_GAIN_ICEPTS, - vpdTableR[i]); - - for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { - vpdTableI[i][j] = - (u8)(ath9k_hw_interpolate((u16) - FREQ2FBIN(centers. synth_center, - IS_CHAN_2GHZ(chan)), - bChans[idxL], bChans[idxR], - vpdTableL[i][j], vpdTableR[i][j])); - } - } - } - *pMinCalPower = (int16_t)(minPwrT4[0] / 2); - - k = 0; - for (i = 0; i < numXpdGains; i++) { - if (i == (numXpdGains - 1)) - pPdGainBoundaries[i] = (u16)(maxPwrT4[i] / 2); - else - pPdGainBoundaries[i] = (u16)((maxPwrT4[i] + - minPwrT4[i+1]) / 4); - - pPdGainBoundaries[i] = min((u16)AR5416_MAX_RATE_POWER, - pPdGainBoundaries[i]); - - - if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { - minDelta = pPdGainBoundaries[0] - 23; - pPdGainBoundaries[0] = 23; - } else - minDelta = 0; - - if (i == 0) { - if (AR_SREV_9280_10_OR_LATER(ah)) - ss = (int16_t)(0 - (minPwrT4[i] / 2)); - else - ss = 0; - } else - ss = (int16_t)((pPdGainBoundaries[i-1] - - (minPwrT4[i] / 2)) - - tPdGainOverlap + 1 + minDelta); - - vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); - vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); - while ((ss < 0) && (k < (AR9287_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); - pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); - ss++; - } - - sizeCurrVpdTable = (u8)((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); - tgtIndex = (u8)(pPdGainBoundaries[i] + - tPdGainOverlap - (minPwrT4[i] / 2)); - maxIndex = (tgtIndex < sizeCurrVpdTable) ? - tgtIndex : sizeCurrVpdTable; - - while ((ss < maxIndex) && (k < (AR9287_NUM_PDADC_VALUES - 1))) - pPDADCValues[k++] = vpdTableI[i][ss++]; - - vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - - vpdTableI[i][sizeCurrVpdTable - 2]); - vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); - if (tgtIndex > maxIndex) { - while ((ss <= tgtIndex) && - (k < (AR9287_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t) TMP_VAL_VPD_TABLE; - pPDADCValues[k++] = (u8)((tmpVal > 255) ? - 255 : tmpVal); - ss++; - } - } - } - - while (i < AR9287_PD_GAINS_IN_MASK) { - pPdGainBoundaries[i] = pPdGainBoundaries[i-1]; - i++; - } - - while (k < AR9287_NUM_PDADC_VALUES) { - pPDADCValues[k] = pPDADCValues[k-1]; - k++; - } - -#undef TMP_VAL_VPD_TABLE -} - -static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah, - struct ath9k_channel *chan, - struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop, - u8 *pCalChans, u16 availPiers, - int8_t *pPwr) -{ - u8 pcdac, i = 0; - u16 idxL = 0, idxR = 0, numPiers; - bool match; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - for (numPiers = 0; numPiers < availPiers; numPiers++) { - if (pCalChans[numPiers] == AR9287_BCHAN_UNUSED) - break; - } - - match = ath9k_hw_get_lower_upper_index( - (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), - pCalChans, numPiers, - &idxL, &idxR); - - if (match) { - pcdac = pRawDatasetOpLoop[idxL].pcdac[0][0]; - *pPwr = pRawDatasetOpLoop[idxL].pwrPdg[0][0]; - } else { - pcdac = pRawDatasetOpLoop[idxR].pcdac[0][0]; - *pPwr = (pRawDatasetOpLoop[idxL].pwrPdg[0][0] + - pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; - } - - while ((pcdac > ah->originalGain[i]) && - (i < (AR9280_TX_GAIN_TABLE_SIZE - 1))) - i++; -} - -static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah, - int32_t txPower, u16 chain) -{ - u32 tmpVal; - u32 a; - - tmpVal = REG_READ(ah, 0xa270); - tmpVal = tmpVal & 0xFCFFFFFF; - tmpVal = tmpVal | (0x3 << 24); - REG_WRITE(ah, 0xa270, tmpVal); - - tmpVal = REG_READ(ah, 0xb270); - tmpVal = tmpVal & 0xFCFFFFFF; - tmpVal = tmpVal | (0x3 << 24); - REG_WRITE(ah, 0xb270, tmpVal); - - if (chain == 0) { - tmpVal = REG_READ(ah, 0xa398); - tmpVal = tmpVal & 0xff00ffff; - a = (txPower)&0xff; - tmpVal = tmpVal | (a << 16); - REG_WRITE(ah, 0xa398, tmpVal); - } - - if (chain == 1) { - tmpVal = REG_READ(ah, 0xb398); - tmpVal = tmpVal & 0xff00ffff; - a = (txPower)&0xff; - tmpVal = tmpVal | (a << 16); - REG_WRITE(ah, 0xb398, tmpVal); - } -} - -static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, - struct ath9k_channel *chan, - int16_t *pTxPowerIndexOffset) -{ - struct cal_data_per_freq_ar9287 *pRawDataset; - struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop; - u8 *pCalBChans = NULL; - u16 pdGainOverlap_t2; - u8 pdadcValues[AR9287_NUM_PDADC_VALUES]; - u16 gainBoundaries[AR9287_PD_GAINS_IN_MASK]; - u16 numPiers = 0, i, j; - int16_t tMinCalPower; - u16 numXpdGain, xpdMask; - u16 xpdGainValues[AR9287_NUM_PD_GAINS] = {0, 0, 0, 0}; - u32 reg32, regOffset, regChainOffset; - int16_t modalIdx, diff = 0; - struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; - modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; - xpdMask = pEepData->modalHeader.xpdGain; - if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= - AR9287_EEP_MINOR_VER_2) - pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap; - else - pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), - AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); - - if (IS_CHAN_2GHZ(chan)) { - pCalBChans = pEepData->calFreqPier2G; - numPiers = AR9287_NUM_2G_CAL_PIERS; - if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { - pRawDatasetOpenLoop = - (struct cal_data_op_loop_ar9287 *) - pEepData->calPierData2G[0]; - ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0]; - } - } - - numXpdGain = 0; - for (i = 1; i <= AR9287_PD_GAINS_IN_MASK; i++) { - if ((xpdMask >> (AR9287_PD_GAINS_IN_MASK - i)) & 1) { - if (numXpdGain >= AR9287_NUM_PD_GAINS) - break; - xpdGainValues[numXpdGain] = - (u16)(AR9287_PD_GAINS_IN_MASK-i); - numXpdGain++; - } - } - - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, - (numXpdGain - 1) & 0x3); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, - xpdGainValues[0]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, - xpdGainValues[1]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, - xpdGainValues[2]); - - for (i = 0; i < AR9287_MAX_CHAINS; i++) { - regChainOffset = i * 0x1000; - if (pEepData->baseEepHeader.txMask & (1 << i)) { - pRawDatasetOpenLoop = (struct cal_data_op_loop_ar9287 *) - pEepData->calPierData2G[i]; - if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { - int8_t txPower; - ar9287_eeprom_get_tx_gain_index(ah, chan, - pRawDatasetOpenLoop, - pCalBChans, numPiers, - &txPower); - ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i); - } else { - pRawDataset = - (struct cal_data_per_freq_ar9287 *) - pEepData->calPierData2G[i]; - ath9k_hw_get_AR9287_gain_boundaries_pdadcs( - ah, chan, pRawDataset, - pCalBChans, numPiers, - pdGainOverlap_t2, - &tMinCalPower, gainBoundaries, - pdadcValues, numXpdGain); - } - - if (i == 0) { - if (!ath9k_hw_AR9287_get_eeprom( - ah, EEP_OL_PWRCTRL)) { - REG_WRITE(ah, AR_PHY_TPCRG5 + - regChainOffset, - SM(pdGainOverlap_t2, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | - SM(gainBoundaries[0], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) - | SM(gainBoundaries[1], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) - | SM(gainBoundaries[2], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) - | SM(gainBoundaries[3], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); - } - } - - if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB != - pEepData->baseEepHeader.pwrTableOffset) { - diff = (u16) - (pEepData->baseEepHeader.pwrTableOffset - - (int32_t)AR9287_PWR_TABLE_OFFSET_DB); - diff *= 2; - - for (j = 0; - j < ((u16)AR9287_NUM_PDADC_VALUES-diff); - j++) - pdadcValues[j] = pdadcValues[j+diff]; - - for (j = (u16)(AR9287_NUM_PDADC_VALUES-diff); - j < AR9287_NUM_PDADC_VALUES; j++) - pdadcValues[j] = - pdadcValues[ - AR9287_NUM_PDADC_VALUES-diff]; - } - - if (!ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { - regOffset = AR_PHY_BASE + (672 << 2) + - regChainOffset; - for (j = 0; j < 32; j++) { - reg32 = ((pdadcValues[4*j + 0] - & 0xFF) << 0) | - ((pdadcValues[4*j + 1] - & 0xFF) << 8) | - ((pdadcValues[4*j + 2] - & 0xFF) << 16) | - ((pdadcValues[4*j + 3] - & 0xFF) << 24) ; - REG_WRITE(ah, regOffset, reg32); - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "PDADC (%d,%4x): %4.4x %8.8x\n", - i, regChainOffset, regOffset, - reg32); - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "PDADC: Chain %d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d |\n", - i, 4 * j, pdadcValues[4 * j], - 4 * j + 1, - pdadcValues[4 * j + 1], - 4 * j + 2, - pdadcValues[4 * j + 2], - 4 * j + 3, - pdadcValues[4 * j + 3]); - - regOffset += 4; - } - } - } - } - - *pTxPowerIndexOffset = 0; -} - -static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, - struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl, - u16 AntennaReduction, u16 twiceMaxRegulatoryPower, - u16 powerLimit) -{ -#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 -#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 - - u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - static const u16 tpScaleReductionTable[5] = - { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; - int i; - int16_t twiceLargestAntenna; - struct cal_ctl_data_ar9287 *rep; - struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} }, - targetPowerCck = {0, {0, 0, 0, 0} }; - struct cal_target_power_leg targetPowerOfdmExt = {0, {0, 0, 0, 0} }, - targetPowerCckExt = {0, {0, 0, 0, 0} }; - struct cal_target_power_ht targetPowerHt20, - targetPowerHt40 = {0, {0, 0, 0, 0} }; - u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; - u16 ctlModesFor11g[] = - {CTL_11B, CTL_11G, CTL_2GHT20, - CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40}; - u16 numCtlModes = 0, *pCtlMode = NULL, ctlMode, freq; - struct chan_centers centers; - int tx_chainmask; - u16 twiceMinEdgePower; - struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; - tx_chainmask = ah->txchainmask; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0], - pEepData->modalHeader.antennaGainCh[1]); - - twiceLargestAntenna = (int16_t)min((AntennaReduction) - - twiceLargestAntenna, 0); - - maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) - maxRegAllowedPower -= - (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); - - scaledPower = min(powerLimit, maxRegAllowedPower); - - switch (ar5416_get_ntxchains(tx_chainmask)) { - case 1: - break; - case 2: - scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; - break; - case 3: - scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; - break; - } - scaledPower = max((u16)0, scaledPower); - - if (IS_CHAN_2GHZ(chan)) { - numCtlModes = - ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; - pCtlMode = ctlModesFor11g; - - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR9287_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCck, 4, false); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR9287_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdm, 4, false); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT20, - AR9287_NUM_2G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); - - if (IS_CHAN_HT40(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11g); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT40, - AR9287_NUM_2G_40_TARGET_POWERS, - &targetPowerHt40, 8, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPowerCck, - AR9287_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCckExt, 4, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData->calTargetPower2G, - AR9287_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdmExt, 4, true); - } - } - - for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { - bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || - (pCtlMode[ctlMode] == CTL_2GHT40); - if (isHt40CtlMode) - freq = centers.synth_center; - else if (pCtlMode[ctlMode] & EXT_ADDITIVE) - freq = centers.ext_center; - else - freq = centers.ctl_center; - - if (ah->eep_ops->get_eeprom_ver(ah) == 14 && - ah->eep_ops->get_eeprom_rev(ah) <= 2) - twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - - for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { - if ((((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - pEepData->ctlIndex[i]) || - (((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - ((pEepData->ctlIndex[i] & - CTL_MODE_M) | SD_NO_CTL))) { - - rep = &(pEepData->ctlData[i]); - twiceMinEdgePower = ath9k_hw_get_max_edge_power( - freq, - rep->ctlEdges[ar5416_get_ntxchains( - tx_chainmask) - 1], - IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); - - if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) - twiceMaxEdgePower = min( - twiceMaxEdgePower, - twiceMinEdgePower); - else { - twiceMaxEdgePower = twiceMinEdgePower; - break; - } - } - } - - minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); - - switch (pCtlMode[ctlMode]) { - case CTL_11B: - for (i = 0; - i < ARRAY_SIZE(targetPowerCck.tPow2x); - i++) { - targetPowerCck.tPow2x[i] = (u8)min( - (u16)targetPowerCck.tPow2x[i], - minCtlPower); - } - break; - case CTL_11A: - case CTL_11G: - for (i = 0; - i < ARRAY_SIZE(targetPowerOfdm.tPow2x); - i++) { - targetPowerOfdm.tPow2x[i] = (u8)min( - (u16)targetPowerOfdm.tPow2x[i], - minCtlPower); - } - break; - case CTL_5GHT20: - case CTL_2GHT20: - for (i = 0; - i < ARRAY_SIZE(targetPowerHt20.tPow2x); - i++) { - targetPowerHt20.tPow2x[i] = (u8)min( - (u16)targetPowerHt20.tPow2x[i], - minCtlPower); - } - break; - case CTL_11B_EXT: - targetPowerCckExt.tPow2x[0] = (u8)min( - (u16)targetPowerCckExt.tPow2x[0], - minCtlPower); - break; - case CTL_11A_EXT: - case CTL_11G_EXT: - targetPowerOfdmExt.tPow2x[0] = (u8)min( - (u16)targetPowerOfdmExt.tPow2x[0], - minCtlPower); - break; - case CTL_5GHT40: - case CTL_2GHT40: - for (i = 0; - i < ARRAY_SIZE(targetPowerHt40.tPow2x); - i++) { - targetPowerHt40.tPow2x[i] = (u8)min( - (u16)targetPowerHt40.tPow2x[i], - minCtlPower); - } - break; - default: - break; - } - } - - ratesArray[rate6mb] = - ratesArray[rate9mb] = - ratesArray[rate12mb] = - ratesArray[rate18mb] = - ratesArray[rate24mb] = - targetPowerOfdm.tPow2x[0]; - - ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; - ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; - ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; - ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; - - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) - ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; - - if (IS_CHAN_2GHZ(chan)) { - ratesArray[rate1l] = targetPowerCck.tPow2x[0]; - ratesArray[rate2s] = ratesArray[rate2l] = - targetPowerCck.tPow2x[1]; - ratesArray[rate5_5s] = ratesArray[rate5_5l] = - targetPowerCck.tPow2x[2]; - ratesArray[rate11s] = ratesArray[rate11l] = - targetPowerCck.tPow2x[3]; - } - if (IS_CHAN_HT40(chan)) { - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) - ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i]; - - ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; - ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; - ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; - if (IS_CHAN_2GHZ(chan)) - ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; - } - -#undef REDUCE_SCALED_POWER_BY_TWO_CHAIN -#undef REDUCE_SCALED_POWER_BY_THREE_CHAIN -} - -static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, - struct ath9k_channel *chan, u16 cfgCtl, - u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) -{ -#define INCREASE_MAXPOW_BY_TWO_CHAIN 6 -#define INCREASE_MAXPOW_BY_THREE_CHAIN 10 - - struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; - struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; - int16_t ratesArray[Ar5416RateSize]; - int16_t txPowerIndexOffset = 0; - u8 ht40PowerIncForPdadc = 2; - int i; - - memset(ratesArray, 0, sizeof(ratesArray)); - - if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= - AR9287_EEP_MINOR_VER_2) - ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; - - ath9k_hw_set_AR9287_power_per_rate_table(ah, chan, - &ratesArray[0], cfgCtl, - twiceAntennaReduction, - twiceMaxRegulatoryPower, - powerLimit); - - ath9k_hw_set_AR9287_power_cal_table(ah, chan, &txPowerIndexOffset); - - for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { - ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); - if (ratesArray[i] > AR9287_MAX_RATE_POWER) - ratesArray[i] = AR9287_MAX_RATE_POWER; - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - for (i = 0; i < Ar5416RateSize; i++) - ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, - ATH9K_POW_SM(ratesArray[rate18mb], 24) - | ATH9K_POW_SM(ratesArray[rate12mb], 16) - | ATH9K_POW_SM(ratesArray[rate9mb], 8) - | ATH9K_POW_SM(ratesArray[rate6mb], 0)); - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, - ATH9K_POW_SM(ratesArray[rate54mb], 24) - | ATH9K_POW_SM(ratesArray[rate48mb], 16) - | ATH9K_POW_SM(ratesArray[rate36mb], 8) - | ATH9K_POW_SM(ratesArray[rate24mb], 0)); - - if (IS_CHAN_2GHZ(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, - ATH9K_POW_SM(ratesArray[rate2s], 24) - | ATH9K_POW_SM(ratesArray[rate2l], 16) - | ATH9K_POW_SM(ratesArray[rateXr], 8) - | ATH9K_POW_SM(ratesArray[rate1l], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, - ATH9K_POW_SM(ratesArray[rate11s], 24) - | ATH9K_POW_SM(ratesArray[rate11l], 16) - | ATH9K_POW_SM(ratesArray[rate5_5s], 8) - | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, - ATH9K_POW_SM(ratesArray[rateHt20_3], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, - ATH9K_POW_SM(ratesArray[rateHt20_7], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); - - if (IS_CHAN_HT40(chan)) { - if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, - ATH9K_POW_SM(ratesArray[rateHt40_3], 24) - | ATH9K_POW_SM(ratesArray[rateHt40_2], 16) - | ATH9K_POW_SM(ratesArray[rateHt40_1], 8) - | ATH9K_POW_SM(ratesArray[rateHt40_0], 0)); - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, - ATH9K_POW_SM(ratesArray[rateHt40_7], 24) - | ATH9K_POW_SM(ratesArray[rateHt40_6], 16) - | ATH9K_POW_SM(ratesArray[rateHt40_5], 8) - | ATH9K_POW_SM(ratesArray[rateHt40_4], 0)); - } else { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, - ATH9K_POW_SM(ratesArray[rateHt40_3] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_2] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_1] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_0] + - ht40PowerIncForPdadc, 0)); - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, - ATH9K_POW_SM(ratesArray[rateHt40_7] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_6] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_5] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_4] + - ht40PowerIncForPdadc, 0)); - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, - ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) - | ATH9K_POW_SM(ratesArray[rateExtCck], 16) - | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) - | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); - } - - if (IS_CHAN_2GHZ(chan)) - i = rate1l; - else - i = rate6mb; - - if (AR_SREV_9280_10_OR_LATER(ah)) - ah->regulatory.max_power_level = - ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2; - else - ah->regulatory.max_power_level = ratesArray[i]; - - switch (ar5416_get_ntxchains(ah->txchainmask)) { - case 1: - break; - case 2: - ah->regulatory.max_power_level += - INCREASE_MAXPOW_BY_TWO_CHAIN; - break; - case 3: - ah->regulatory.max_power_level += - INCREASE_MAXPOW_BY_THREE_CHAIN; - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Invalid chainmask configuration\n"); - break; - } -} - -static void ath9k_hw_AR9287_set_addac(struct ath_hw *ah, - struct ath9k_channel *chan) -{ -} - -static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct ar9287_eeprom *eep = &ah->eeprom.map9287; - struct modal_eep_ar9287_header *pModal = &eep->modalHeader; - u16 antWrites[AR9287_ANT_16S]; - u32 regChainOffset; - u8 txRxAttenLocal; - int i, j, offset_num; - - pModal = &eep->modalHeader; - - antWrites[0] = (u16)((pModal->antCtrlCommon >> 28) & 0xF); - antWrites[1] = (u16)((pModal->antCtrlCommon >> 24) & 0xF); - antWrites[2] = (u16)((pModal->antCtrlCommon >> 20) & 0xF); - antWrites[3] = (u16)((pModal->antCtrlCommon >> 16) & 0xF); - antWrites[4] = (u16)((pModal->antCtrlCommon >> 12) & 0xF); - antWrites[5] = (u16)((pModal->antCtrlCommon >> 8) & 0xF); - antWrites[6] = (u16)((pModal->antCtrlCommon >> 4) & 0xF); - antWrites[7] = (u16)(pModal->antCtrlCommon & 0xF); - - offset_num = 8; - - for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) { - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 28) & 0xf); - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 10) & 0x3); - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 8) & 0x3); - antWrites[j++] = 0; - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 6) & 0x3); - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 4) & 0x3); - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 2) & 0x3); - antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3); - } - - REG_WRITE(ah, AR_PHY_SWITCH_COM, - ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); - - for (i = 0; i < AR9287_MAX_CHAINS; i++) { - regChainOffset = i * 0x1000; - - REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, - pModal->antCtrlChain[i]); - - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, - (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) - & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | - SM(pModal->iqCalICh[i], - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | - SM(pModal->iqCalQCh[i], - AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); - - txRxAttenLocal = pModal->txRxAttenCh[i]; - - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, - pModal->bswMargin[i]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_DB, - pModal->bswAtten[i]); - REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, - AR9280_PHY_RXGAIN_TXRX_ATTEN, - txRxAttenLocal); - REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, - AR9280_PHY_RXGAIN_TXRX_MARGIN, - pModal->rxTxMarginCh[i]); - } - - - if (IS_CHAN_HT40(chan)) - REG_RMW_FIELD(ah, AR_PHY_SETTLING, - AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); - else - REG_RMW_FIELD(ah, AR_PHY_SETTLING, - AR_PHY_SETTLING_SWITCH, pModal->switchSettling); - - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, - AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize); - - REG_WRITE(ah, AR_PHY_RF_CTL4, - SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) - | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) - | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) - | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); - - REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, - AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); - - REG_RMW_FIELD(ah, AR_PHY_CCA, - AR9280_PHY_CCA_THRESH62, pModal->thresh62); - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, - AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62); - - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB1, - AR9287_AN_RF2G3_DB1_S, pModal->db1); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB2, - AR9287_AN_RF2G3_DB2_S, pModal->db2); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, - AR9287_AN_RF2G3_OB_CCK, - AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, - AR9287_AN_RF2G3_OB_PSK, - AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, - AR9287_AN_RF2G3_OB_QAM, - AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, - AR9287_AN_RF2G3_OB_PAL_OFF, - AR9287_AN_RF2G3_OB_PAL_OFF_S, - pModal->ob_pal_off); - - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, - AR9287_AN_RF2G3_DB1, AR9287_AN_RF2G3_DB1_S, - pModal->db1); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, AR9287_AN_RF2G3_DB2, - AR9287_AN_RF2G3_DB2_S, pModal->db2); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, - AR9287_AN_RF2G3_OB_CCK, - AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, - AR9287_AN_RF2G3_OB_PSK, - AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, - AR9287_AN_RF2G3_OB_QAM, - AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, - AR9287_AN_RF2G3_OB_PAL_OFF, - AR9287_AN_RF2G3_OB_PAL_OFF_S, - pModal->ob_pal_off); - - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, - AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart); - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, - AR_PHY_TX_END_PA_ON, pModal->txFrameToPaOn); - - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TOP2, - AR9287_AN_TOP2_XPABIAS_LVL, - AR9287_AN_TOP2_XPABIAS_LVL_S, - pModal->xpaBiasLvl); -} - -static u8 ath9k_hw_AR9287_get_num_ant_config(struct ath_hw *ah, - enum ieee80211_band freq_band) -{ - return 1; -} - -static u16 ath9k_hw_AR9287_get_eeprom_antenna_cfg(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct ar9287_eeprom *eep = &ah->eeprom.map9287; - struct modal_eep_ar9287_header *pModal = &eep->modalHeader; - - return pModal->antCtrlCommon & 0xFFFF; -} - -static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah, - u16 i, bool is2GHz) -{ -#define EEP_MAP9287_SPURCHAN \ - (ah->eeprom.map9287.modalHeader.spurChans[i].spurChan) - u16 spur_val = AR_NO_SPUR; - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur idx %d is2Ghz. %d val %x\n", - i, is2GHz, ah->config.spurchans[i][is2GHz]); - - switch (ah->config.spurmode) { - case SPUR_DISABLE: - break; - case SPUR_ENABLE_IOCTL: - spur_val = ah->config.spurchans[i][is2GHz]; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur val from new loc. %d\n", spur_val); - break; - case SPUR_ENABLE_EEPROM: - spur_val = EEP_MAP9287_SPURCHAN; - break; - } - - return spur_val; - -#undef EEP_MAP9287_SPURCHAN -} - -static struct eeprom_ops eep_AR9287_ops = { - .check_eeprom = ath9k_hw_AR9287_check_eeprom, - .get_eeprom = ath9k_hw_AR9287_get_eeprom, - .fill_eeprom = ath9k_hw_AR9287_fill_eeprom, - .get_eeprom_ver = ath9k_hw_AR9287_get_eeprom_ver, - .get_eeprom_rev = ath9k_hw_AR9287_get_eeprom_rev, - .get_num_ant_config = ath9k_hw_AR9287_get_num_ant_config, - .get_eeprom_antenna_cfg = ath9k_hw_AR9287_get_eeprom_antenna_cfg, - .set_board_values = ath9k_hw_AR9287_set_board_values, - .set_addac = ath9k_hw_AR9287_set_addac, - .set_txpower = ath9k_hw_AR9287_set_txpower, - .get_spur_channel = ath9k_hw_AR9287_get_spur_channel -}; - int ath9k_hw_eeprom_init(struct ath_hw *ah) { int status; diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index a6447096fd1..7d825b6d9c8 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -656,10 +656,39 @@ struct eeprom_ops { u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz); }; +void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask, + u32 shift, u32 val); +int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight, + int16_t targetLeft, + int16_t targetRight); +bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize, + u16 *indexL, u16 *indexR); +bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data); +void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, + u8 *pVpdList, u16 numIntercepts, + u8 *pRetVpdList); +void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_target_power_leg *powInfo, + u16 numChannels, + struct cal_target_power_leg *pNewPower, + u16 numRates, bool isExtTarget); +void ath9k_hw_get_target_powers(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_target_power_ht *powInfo, + u16 numChannels, + struct cal_target_power_ht *pNewPower, + u16 numRates, bool isHt40Target); +u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower, + bool is2GHz, int num_band_edges); +int ath9k_hw_eeprom_init(struct ath_hw *ah); + #define ar5416_get_ntxchains(_txchainmask) \ (((_txchainmask >> 2) & 1) + \ ((_txchainmask >> 1) & 1) + (_txchainmask & 1)) -int ath9k_hw_eeprom_init(struct ath_hw *ah); +extern const struct eeprom_ops eep_def_ops; +extern const struct eeprom_ops eep_4k_ops; +extern const struct eeprom_ops eep_AR9287_ops; #endif /* EEPROM_H */ diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c new file mode 100644 index 00000000000..111f4d72092 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -0,0 +1,1181 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah) +{ + return ((ah->eeprom.map4k.baseEepHeader.version >> 12) & 0xF); +} + +static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah) +{ + return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF); +} + +static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) +{ +#define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) + u16 *eep_data = (u16 *)&ah->eeprom.map4k; + int addr, eep_start_loc = 0; + + eep_start_loc = 64; + + if (!ath9k_hw_use_flash(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); + } + + for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { + if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Unable to read eeprom region \n"); + return false; + } + eep_data++; + } + + return true; +#undef SIZE_EEPROM_4K +} + +static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) +{ +#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) + struct ar5416_eeprom_4k *eep = + (struct ar5416_eeprom_4k *) &ah->eeprom.map4k; + u16 *eepdata, temp, magic, magic2; + u32 sum = 0, el; + bool need_swap = false; + int i, addr; + + + if (!ath9k_hw_use_flash(ah)) { + if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, + &magic)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Reading Magic # failed\n"); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); + + if (magic != AR5416_EEPROM_MAGIC) { + magic2 = swab16(magic); + + if (magic2 == AR5416_EEPROM_MAGIC) { + need_swap = true; + eepdata = (u16 *) (&ah->eeprom); + + for (addr = 0; addr < EEPROM_4K_SIZE; addr++) { + temp = swab16(*eepdata); + *eepdata = temp; + eepdata++; + } + } else { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Invalid EEPROM Magic. " + "endianness mismatch.\n"); + return -EINVAL; + } + } + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", + need_swap ? "True" : "False"); + + if (need_swap) + el = swab16(ah->eeprom.map4k.baseEepHeader.length); + else + el = ah->eeprom.map4k.baseEepHeader.length; + + if (el > sizeof(struct ar5416_eeprom_4k)) + el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16); + else + el = el / sizeof(u16); + + eepdata = (u16 *)(&ah->eeprom); + + for (i = 0; i < el; i++) + sum ^= *eepdata++; + + if (need_swap) { + u32 integer; + u16 word; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "EEPROM Endianness is not native.. Changing\n"); + + word = swab16(eep->baseEepHeader.length); + eep->baseEepHeader.length = word; + + word = swab16(eep->baseEepHeader.checksum); + eep->baseEepHeader.checksum = word; + + word = swab16(eep->baseEepHeader.version); + eep->baseEepHeader.version = word; + + word = swab16(eep->baseEepHeader.regDmn[0]); + eep->baseEepHeader.regDmn[0] = word; + + word = swab16(eep->baseEepHeader.regDmn[1]); + eep->baseEepHeader.regDmn[1] = word; + + word = swab16(eep->baseEepHeader.rfSilent); + eep->baseEepHeader.rfSilent = word; + + word = swab16(eep->baseEepHeader.blueToothOptions); + eep->baseEepHeader.blueToothOptions = word; + + word = swab16(eep->baseEepHeader.deviceCap); + eep->baseEepHeader.deviceCap = word; + + integer = swab32(eep->modalHeader.antCtrlCommon); + eep->modalHeader.antCtrlCommon = integer; + + for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { + integer = swab32(eep->modalHeader.antCtrlChain[i]); + eep->modalHeader.antCtrlChain[i] = integer; + } + + for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { + word = swab16(eep->modalHeader.spurChans[i].spurChan); + eep->modalHeader.spurChans[i].spurChan = word; + } + } + + if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || + ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Bad EEPROM checksum 0x%x or revision 0x%04x\n", + sum, ah->eep_ops->get_eeprom_ver(ah)); + return -EINVAL; + } + + return 0; +#undef EEPROM_4K_SIZE +} + +static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, + enum eeprom_param param) +{ + struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; + struct modal_eep_4k_header *pModal = &eep->modalHeader; + struct base_eep_header_4k *pBase = &eep->baseEepHeader; + + switch (param) { + case EEP_NFTHRESH_2: + return pModal->noiseFloorThreshCh[0]; + case AR_EEPROM_MAC(0): + return pBase->macAddr[0] << 8 | pBase->macAddr[1]; + case AR_EEPROM_MAC(1): + return pBase->macAddr[2] << 8 | pBase->macAddr[3]; + case AR_EEPROM_MAC(2): + return pBase->macAddr[4] << 8 | pBase->macAddr[5]; + case EEP_REG_0: + return pBase->regDmn[0]; + case EEP_REG_1: + return pBase->regDmn[1]; + case EEP_OP_CAP: + return pBase->deviceCap; + case EEP_OP_MODE: + return pBase->opCapFlags; + case EEP_RF_SILENT: + return pBase->rfSilent; + case EEP_OB_2: + return pModal->ob_01; + case EEP_DB_2: + return pModal->db1_01; + case EEP_MINOR_REV: + return pBase->version & AR5416_EEP_VER_MINOR_MASK; + case EEP_TX_MASK: + return pBase->txMask; + case EEP_RX_MASK: + return pBase->rxMask; + case EEP_FRAC_N_5G: + return 0; + default: + return 0; + } +} + +static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_data_per_freq_4k *pRawDataSet, + u8 *bChans, u16 availPiers, + u16 tPdGainOverlap, int16_t *pMinCalPower, + u16 *pPdGainBoundaries, u8 *pPDADCValues, + u16 numXpdGains) +{ +#define TMP_VAL_VPD_TABLE \ + ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); + int i, j, k; + int16_t ss; + u16 idxL = 0, idxR = 0, numPiers; + static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; + u8 minPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; + u8 maxPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; + int16_t vpdStep; + int16_t tmpVal; + u16 sizeCurrVpdTable, maxIndex, tgtIndex; + bool match; + int16_t minDelta = 0; + struct chan_centers centers; +#define PD_GAIN_BOUNDARY_DEFAULT 58; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (bChans[numPiers] == AR5416_BCHAN_UNUSED) + break; + } + + match = ath9k_hw_get_lower_upper_index( + (u8)FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)), bChans, numPiers, + &idxL, &idxR); + + if (match) { + for (i = 0; i < numXpdGains; i++) { + minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; + maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pRawDataSet[idxL].pwrPdg[i], + pRawDataSet[idxL].vpdPdg[i], + AR5416_EEP4K_PD_GAIN_ICEPTS, + vpdTableI[i]); + } + } else { + for (i = 0; i < numXpdGains; i++) { + pVpdL = pRawDataSet[idxL].vpdPdg[i]; + pPwrL = pRawDataSet[idxL].pwrPdg[i]; + pVpdR = pRawDataSet[idxR].vpdPdg[i]; + pPwrR = pRawDataSet[idxR].pwrPdg[i]; + + minPwrT4[i] = max(pPwrL[0], pPwrR[0]); + + maxPwrT4[i] = + min(pPwrL[AR5416_EEP4K_PD_GAIN_ICEPTS - 1], + pPwrR[AR5416_EEP4K_PD_GAIN_ICEPTS - 1]); + + + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrL, pVpdL, + AR5416_EEP4K_PD_GAIN_ICEPTS, + vpdTableL[i]); + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrR, pVpdR, + AR5416_EEP4K_PD_GAIN_ICEPTS, + vpdTableR[i]); + + for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { + vpdTableI[i][j] = + (u8)(ath9k_hw_interpolate((u16) + FREQ2FBIN(centers. + synth_center, + IS_CHAN_2GHZ + (chan)), + bChans[idxL], bChans[idxR], + vpdTableL[i][j], vpdTableR[i][j])); + } + } + } + + *pMinCalPower = (int16_t)(minPwrT4[0] / 2); + + k = 0; + + for (i = 0; i < numXpdGains; i++) { + if (i == (numXpdGains - 1)) + pPdGainBoundaries[i] = + (u16)(maxPwrT4[i] / 2); + else + pPdGainBoundaries[i] = + (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); + + pPdGainBoundaries[i] = + min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); + + if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { + minDelta = pPdGainBoundaries[0] - 23; + pPdGainBoundaries[0] = 23; + } else { + minDelta = 0; + } + + if (i == 0) { + if (AR_SREV_9280_10_OR_LATER(ah)) + ss = (int16_t)(0 - (minPwrT4[i] / 2)); + else + ss = 0; + } else { + ss = (int16_t)((pPdGainBoundaries[i - 1] - + (minPwrT4[i] / 2)) - + tPdGainOverlap + 1 + minDelta); + } + vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); + pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); + tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - + (minPwrT4[i] / 2)); + maxIndex = (tgtIndex < sizeCurrVpdTable) ? + tgtIndex : sizeCurrVpdTable; + + while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) + pPDADCValues[k++] = vpdTableI[i][ss++]; + + vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - + vpdTableI[i][sizeCurrVpdTable - 2]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + if (tgtIndex >= maxIndex) { + while ((ss <= tgtIndex) && + (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t) TMP_VAL_VPD_TABLE; + pPDADCValues[k++] = (u8)((tmpVal > 255) ? + 255 : tmpVal); + ss++; + } + } + } + + while (i < AR5416_EEP4K_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = PD_GAIN_BOUNDARY_DEFAULT; + i++; + } + + while (k < AR5416_NUM_PDADC_VALUES) { + pPDADCValues[k] = pPDADCValues[k - 1]; + k++; + } + + return; +#undef TMP_VAL_VPD_TABLE +} + +static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset) +{ + struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; + struct cal_data_per_freq_4k *pRawDataset; + u8 *pCalBChans = NULL; + u16 pdGainOverlap_t2; + static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; + u16 gainBoundaries[AR5416_EEP4K_PD_GAINS_IN_MASK]; + u16 numPiers, i, j; + int16_t tMinCalPower; + u16 numXpdGain, xpdMask; + u16 xpdGainValues[AR5416_EEP4K_NUM_PD_GAINS] = { 0, 0 }; + u32 reg32, regOffset, regChainOffset; + + xpdMask = pEepData->modalHeader.xpdGain; + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + pdGainOverlap_t2 = + pEepData->modalHeader.pdGainOverlap; + } else { + pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); + } + + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR5416_EEP4K_NUM_2G_CAL_PIERS; + + numXpdGain = 0; + + for (i = 1; i <= AR5416_EEP4K_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR5416_EEP4K_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR5416_EEP4K_NUM_PD_GAINS) + break; + xpdGainValues[numXpdGain] = + (u16)(AR5416_EEP4K_PD_GAINS_IN_MASK - i); + numXpdGain++; + } + } + + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (numXpdGain - 1) & 0x3); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, + xpdGainValues[0]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, + xpdGainValues[1]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0); + + for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { + if (AR_SREV_5416_20_OR_LATER(ah) && + (ah->rxchainmask == 5 || ah->txchainmask == 5) && + (i != 0)) { + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + } else + regChainOffset = i * 0x1000; + + if (pEepData->baseEepHeader.txMask & (1 << i)) { + pRawDataset = pEepData->calPierData2G[i]; + + ath9k_hw_get_4k_gain_boundaries_pdadcs(ah, chan, + pRawDataset, pCalBChans, + numPiers, pdGainOverlap_t2, + &tMinCalPower, gainBoundaries, + pdadcValues, numXpdGain); + + if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { + REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) + | SM(gainBoundaries[0], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) + | SM(gainBoundaries[1], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) + | SM(gainBoundaries[2], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) + | SM(gainBoundaries[3], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + } + + regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; + for (j = 0; j < 32; j++) { + reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | + ((pdadcValues[4 * j + 1] & 0xFF) << 8) | + ((pdadcValues[4 * j + 2] & 0xFF) << 16)| + ((pdadcValues[4 * j + 3] & 0xFF) << 24); + REG_WRITE(ah, regOffset, reg32); + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PDADC (%d,%4x): %4.4x %8.8x\n", + i, regChainOffset, regOffset, + reg32); + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PDADC: Chain %d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, pdadcValues[4 * j + 1], + 4 * j + 2, pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); + + regOffset += 4; + } + } + } + + *pTxPowerIndexOffset = 0; +} + +static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, + struct ath9k_channel *chan, + int16_t *ratesArray, + u16 cfgCtl, + u16 AntennaReduction, + u16 twiceMaxRegulatoryPower, + u16 powerLimit) +{ + struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + static const u16 tpScaleReductionTable[5] = + { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; + + int i; + int16_t twiceLargestAntenna; + struct cal_ctl_data_4k *rep; + struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { + 0, { 0, 0, 0, 0} + }; + struct cal_target_power_leg targetPowerOfdmExt = { + 0, { 0, 0, 0, 0} }, targetPowerCckExt = { + 0, { 0, 0, 0, 0 } + }; + struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { + 0, {0, 0, 0, 0} + }; + u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 ctlModesFor11g[] = + { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, + CTL_2GHT40 + }; + u16 numCtlModes, *pCtlMode, ctlMode, freq; + struct chan_centers centers; + int tx_chainmask; + u16 twiceMinEdgePower; + + tx_chainmask = ah->txchainmask; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0]; + + twiceLargestAntenna = (int16_t)min(AntennaReduction - + twiceLargestAntenna, 0); + + maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; + + if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { + maxRegAllowedPower -= + (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); + } + + scaledPower = min(powerLimit, maxRegAllowedPower); + scaledPower = max((u16)0, scaledPower); + + numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; + pCtlMode = ctlModesFor11g; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCck, 4, false); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT20, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT40, + AR5416_NUM_2G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCckExt, 4, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + + for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { + bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || + (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) + freq = centers.synth_center; + else if (pCtlMode[ctlMode] & EXT_ADDITIVE) + freq = centers.ext_center; + else + freq = centers.ctl_center; + + if (ah->eep_ops->get_eeprom_ver(ah) == 14 && + ah->eep_ops->get_eeprom_rev(ah) <= 2) + twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + + for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) && + pEepData->ctlIndex[i]; i++) { + if ((((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + pEepData->ctlIndex[i]) || + (((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & CTL_MODE_M) | + SD_NO_CTL))) { + rep = &(pEepData->ctlData[i]); + + twiceMinEdgePower = + ath9k_hw_get_max_edge_power(freq, + rep->ctlEdges[ar5416_get_ntxchains + (tx_chainmask) - 1], + IS_CHAN_2GHZ(chan), + AR5416_EEP4K_NUM_BAND_EDGES); + + if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { + twiceMaxEdgePower = + min(twiceMaxEdgePower, + twiceMinEdgePower); + } else { + twiceMaxEdgePower = twiceMinEdgePower; + break; + } + } + } + + minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); + + switch (pCtlMode[ctlMode]) { + case CTL_11B: + for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); + i++) { + targetPowerCck.tPow2x[i] = + min((u16)targetPowerCck.tPow2x[i], + minCtlPower); + } + break; + case CTL_11G: + for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); + i++) { + targetPowerOfdm.tPow2x[i] = + min((u16)targetPowerOfdm.tPow2x[i], + minCtlPower); + } + break; + case CTL_2GHT20: + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); + i++) { + targetPowerHt20.tPow2x[i] = + min((u16)targetPowerHt20.tPow2x[i], + minCtlPower); + } + break; + case CTL_11B_EXT: + targetPowerCckExt.tPow2x[0] = min((u16) + targetPowerCckExt.tPow2x[0], + minCtlPower); + break; + case CTL_11G_EXT: + targetPowerOfdmExt.tPow2x[0] = min((u16) + targetPowerOfdmExt.tPow2x[0], + minCtlPower); + break; + case CTL_2GHT40: + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); + i++) { + targetPowerHt40.tPow2x[i] = + min((u16)targetPowerHt40.tPow2x[i], + minCtlPower); + } + break; + default: + break; + } + } + + ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = + ratesArray[rate18mb] = ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; + ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; + ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; + ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; + + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) + ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; + + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; + ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; + ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3]; + + if (IS_CHAN_HT40(chan)) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { + ratesArray[rateHt40_0 + i] = + targetPowerHt40.tPow2x[i]; + } + ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; + ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; + ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; + ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; + } +} + +static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ + struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; + struct modal_eep_4k_header *pModal = &pEepData->modalHeader; + int16_t ratesArray[Ar5416RateSize]; + int16_t txPowerIndexOffset = 0; + u8 ht40PowerIncForPdadc = 2; + int i; + + memset(ratesArray, 0, sizeof(ratesArray)); + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; + } + + ath9k_hw_set_4k_power_per_rate_table(ah, chan, + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit); + + ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset); + + for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { + ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); + if (ratesArray[i] > AR5416_MAX_RATE_POWER) + ratesArray[i] = AR5416_MAX_RATE_POWER; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + for (i = 0; i < Ar5416RateSize; i++) + ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) + | ATH9K_POW_SM(ratesArray[rate9mb], 8) + | ATH9K_POW_SM(ratesArray[rate6mb], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + ATH9K_POW_SM(ratesArray[rate54mb], 24) + | ATH9K_POW_SM(ratesArray[rate48mb], 16) + | ATH9K_POW_SM(ratesArray[rate36mb], 8) + | ATH9K_POW_SM(ratesArray[rate24mb], 0)); + + if (IS_CHAN_2GHZ(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, + ATH9K_POW_SM(ratesArray[rateHt20_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, + ATH9K_POW_SM(ratesArray[rateHt20_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); + + if (IS_CHAN_HT40(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0] + + ht40PowerIncForPdadc, 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4] + + ht40PowerIncForPdadc, 0)); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(ratesArray[rateExtCck], 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); + } + + i = rate6mb; + + if (IS_CHAN_HT40(chan)) + i = rateHt40_0; + else if (IS_CHAN_HT20(chan)) + i = rateHt20_0; + + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->regulatory.max_power_level = + ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; + else + ah->regulatory.max_power_level = ratesArray[i]; + +} + +static void ath9k_hw_4k_set_addac(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct modal_eep_4k_header *pModal; + struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; + u8 biaslevel; + + if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) + return; + + if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) + return; + + pModal = &eep->modalHeader; + + if (pModal->xpaBiasLvl != 0xff) { + biaslevel = pModal->xpaBiasLvl; + INI_RA(&ah->iniAddac, 7, 1) = + (INI_RA(&ah->iniAddac, 7, 1) & (~0x18)) | biaslevel << 3; + } +} + +static void ath9k_hw_4k_set_gain(struct ath_hw *ah, + struct modal_eep_4k_header *pModal, + struct ar5416_eeprom_4k *eep, + u8 txRxAttenLocal, int regChainOffset) +{ + REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, + pModal->antCtrlChain[0]); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, + (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & + ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_3) { + txRxAttenLocal = pModal->txRxAttenCh[0]; + + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, + pModal->xatten2Margin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); + + /* Set the block 1 value to block 0 value */ + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, + pModal->bswMargin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, + AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, + pModal->xatten2Margin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, + AR_PHY_GAIN_2GHZ_XATTEN2_DB, + pModal->xatten2Db[0]); + } + + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); + + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, + AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, + AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); + + if (AR_SREV_9285_11(ah)) + REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); +} + +/* + * Read EEPROM header info and program the device for correct operation + * given the channel value. + */ +static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct modal_eep_4k_header *pModal; + struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; + u8 txRxAttenLocal; + u8 ob[5], db1[5], db2[5]; + u8 ant_div_control1, ant_div_control2; + u32 regVal; + + pModal = &eep->modalHeader; + txRxAttenLocal = 23; + + REG_WRITE(ah, AR_PHY_SWITCH_COM, + ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); + + /* Single chain for 4K EEPROM*/ + ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0); + + /* Initialize Ant Diversity settings from EEPROM */ + if (pModal->version >= 3) { + ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf); + ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf); + regVal = REG_READ(ah, 0x99ac); + regVal &= (~(0x7f000000)); + regVal |= ((ant_div_control1 & 0x1) << 24); + regVal |= (((ant_div_control1 >> 1) & 0x1) << 29); + regVal |= (((ant_div_control1 >> 2) & 0x1) << 30); + regVal |= ((ant_div_control2 & 0x3) << 25); + regVal |= (((ant_div_control2 >> 2) & 0x3) << 27); + REG_WRITE(ah, 0x99ac, regVal); + regVal = REG_READ(ah, 0x99ac); + regVal = REG_READ(ah, 0xa208); + regVal &= (~(0x1 << 13)); + regVal |= (((ant_div_control1 >> 3) & 0x1) << 13); + REG_WRITE(ah, 0xa208, regVal); + regVal = REG_READ(ah, 0xa208); + } + + if (pModal->version >= 2) { + ob[0] = (pModal->ob_01 & 0xf); + ob[1] = (pModal->ob_01 >> 4) & 0xf; + ob[2] = (pModal->ob_234 & 0xf); + ob[3] = ((pModal->ob_234 >> 4) & 0xf); + ob[4] = ((pModal->ob_234 >> 8) & 0xf); + + db1[0] = (pModal->db1_01 & 0xf); + db1[1] = ((pModal->db1_01 >> 4) & 0xf); + db1[2] = (pModal->db1_234 & 0xf); + db1[3] = ((pModal->db1_234 >> 4) & 0xf); + db1[4] = ((pModal->db1_234 >> 8) & 0xf); + + db2[0] = (pModal->db2_01 & 0xf); + db2[1] = ((pModal->db2_01 >> 4) & 0xf); + db2[2] = (pModal->db2_234 & 0xf); + db2[3] = ((pModal->db2_234 >> 4) & 0xf); + db2[4] = ((pModal->db2_234 >> 8) & 0xf); + + } else if (pModal->version == 1) { + ob[0] = (pModal->ob_01 & 0xf); + ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf; + db1[0] = (pModal->db1_01 & 0xf); + db1[1] = db1[2] = db1[3] = + db1[4] = ((pModal->db1_01 >> 4) & 0xf); + db2[0] = (pModal->db2_01 & 0xf); + db2[1] = db2[2] = db2[3] = + db2[4] = ((pModal->db2_01 >> 4) & 0xf); + } else { + int i; + for (i = 0; i < 5; i++) { + ob[i] = pModal->ob_01; + db1[i] = pModal->db1_01; + db2[i] = pModal->db1_01; + } + } + + if (AR_SREV_9271(ah)) { + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9271_AN_RF2G3_OB_cck, + AR9271_AN_RF2G3_OB_cck_S, + ob[0]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9271_AN_RF2G3_OB_psk, + AR9271_AN_RF2G3_OB_psk_S, + ob[1]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9271_AN_RF2G3_OB_qam, + AR9271_AN_RF2G3_OB_qam_S, + ob[2]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9271_AN_RF2G3_DB_1, + AR9271_AN_RF2G3_DB_1_S, + db1[0]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9271_AN_RF2G4_DB_2, + AR9271_AN_RF2G4_DB_2_S, + db2[0]); + } else { + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_0, + AR9285_AN_RF2G3_OB_0_S, + ob[0]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_1, + AR9285_AN_RF2G3_OB_1_S, + ob[1]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_2, + AR9285_AN_RF2G3_OB_2_S, + ob[2]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_3, + AR9285_AN_RF2G3_OB_3_S, + ob[3]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_4, + AR9285_AN_RF2G3_OB_4_S, + ob[4]); + + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_0, + AR9285_AN_RF2G3_DB1_0_S, + db1[0]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_1, + AR9285_AN_RF2G3_DB1_1_S, + db1[1]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_2, + AR9285_AN_RF2G3_DB1_2_S, + db1[2]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB1_3, + AR9285_AN_RF2G4_DB1_3_S, + db1[3]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB1_4, + AR9285_AN_RF2G4_DB1_4_S, db1[4]); + + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_0, + AR9285_AN_RF2G4_DB2_0_S, + db2[0]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_1, + AR9285_AN_RF2G4_DB2_1_S, + db2[1]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_2, + AR9285_AN_RF2G4_DB2_2_S, + db2[2]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_3, + AR9285_AN_RF2G4_DB2_3_S, + db2[3]); + ath9k_hw_analog_shift_rmw(ah, + AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_4, + AR9285_AN_RF2G4_DB2_4_S, + db2[4]); + } + + + if (AR_SREV_9285_11(ah)) + REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); + + REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, + pModal->switchSettling); + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, + pModal->adcDesiredSize); + + REG_WRITE(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | + SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | + SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, + pModal->txEndToRxOn); + REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, + pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, + pModal->thresh62); + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START, + pModal->txFrameToDataStart); + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, + pModal->txFrameToPaOn); + } + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_3) { + if (IS_CHAN_HT40(chan)) + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, + pModal->swSettleHt40); + } +} + +static u16 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; + struct modal_eep_4k_header *pModal = &eep->modalHeader; + + return pModal->antCtrlCommon & 0xFFFF; +} + +static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah, + enum ieee80211_band freq_band) +{ + return 1; +} + +static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) +{ +#define EEP_MAP4K_SPURCHAN \ + (ah->eeprom.map4k.modalHeader.spurChans[i].spurChan) + + u16 spur_val = AR_NO_SPUR; + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur idx %d is2Ghz. %d val %x\n", + i, is2GHz, ah->config.spurchans[i][is2GHz]); + + switch (ah->config.spurmode) { + case SPUR_DISABLE: + break; + case SPUR_ENABLE_IOCTL: + spur_val = ah->config.spurchans[i][is2GHz]; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur val from new loc. %d\n", spur_val); + break; + case SPUR_ENABLE_EEPROM: + spur_val = EEP_MAP4K_SPURCHAN; + break; + } + + return spur_val; + +#undef EEP_MAP4K_SPURCHAN +} + +const struct eeprom_ops eep_4k_ops = { + .check_eeprom = ath9k_hw_4k_check_eeprom, + .get_eeprom = ath9k_hw_4k_get_eeprom, + .fill_eeprom = ath9k_hw_4k_fill_eeprom, + .get_eeprom_ver = ath9k_hw_4k_get_eeprom_ver, + .get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev, + .get_num_ant_config = ath9k_hw_4k_get_num_ant_config, + .get_eeprom_antenna_cfg = ath9k_hw_4k_get_eeprom_antenna_cfg, + .set_board_values = ath9k_hw_4k_set_board_values, + .set_addac = ath9k_hw_4k_set_addac, + .set_txpower = ath9k_hw_4k_set_txpower, + .get_spur_channel = ath9k_hw_4k_get_spur_channel +}; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c new file mode 100644 index 00000000000..aeb7f484b6e --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -0,0 +1,1183 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah) +{ + return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF; +} + +static int ath9k_hw_AR9287_get_eeprom_rev(struct ath_hw *ah) +{ + return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF; +} + +static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) +{ + struct ar9287_eeprom *eep = &ah->eeprom.map9287; + u16 *eep_data; + int addr, eep_start_loc = AR9287_EEP_START_LOC; + eep_data = (u16 *)eep; + + if (!ath9k_hw_use_flash(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); + } + + for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16); + addr++) { + if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Unable to read eeprom region \n"); + return false; + } + eep_data++; + } + return true; +} + +static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) +{ + u32 sum = 0, el, integer; + u16 temp, word, magic, magic2, *eepdata; + int i, addr; + bool need_swap = false; + struct ar9287_eeprom *eep = &ah->eeprom.map9287; + + if (!ath9k_hw_use_flash(ah)) { + if (!ath9k_hw_nvram_read + (ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Reading Magic # failed\n"); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); + if (magic != AR5416_EEPROM_MAGIC) { + magic2 = swab16(magic); + + if (magic2 == AR5416_EEPROM_MAGIC) { + need_swap = true; + eepdata = (u16 *)(&ah->eeprom); + + for (addr = 0; + addr < sizeof(struct ar9287_eeprom) / sizeof(u16); + addr++) { + temp = swab16(*eepdata); + *eepdata = temp; + eepdata++; + } + } else { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Invalid EEPROM Magic. " + "endianness mismatch.\n"); + return -EINVAL; + } + } + } + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ? + "True" : "False"); + + if (need_swap) + el = swab16(ah->eeprom.map9287.baseEepHeader.length); + else + el = ah->eeprom.map9287.baseEepHeader.length; + + if (el > sizeof(struct ar9287_eeprom)) + el = sizeof(struct ar9287_eeprom) / sizeof(u16); + else + el = el / sizeof(u16); + + eepdata = (u16 *)(&ah->eeprom); + for (i = 0; i < el; i++) + sum ^= *eepdata++; + + if (need_swap) { + word = swab16(eep->baseEepHeader.length); + eep->baseEepHeader.length = word; + + word = swab16(eep->baseEepHeader.checksum); + eep->baseEepHeader.checksum = word; + + word = swab16(eep->baseEepHeader.version); + eep->baseEepHeader.version = word; + + word = swab16(eep->baseEepHeader.regDmn[0]); + eep->baseEepHeader.regDmn[0] = word; + + word = swab16(eep->baseEepHeader.regDmn[1]); + eep->baseEepHeader.regDmn[1] = word; + + word = swab16(eep->baseEepHeader.rfSilent); + eep->baseEepHeader.rfSilent = word; + + word = swab16(eep->baseEepHeader.blueToothOptions); + eep->baseEepHeader.blueToothOptions = word; + + word = swab16(eep->baseEepHeader.deviceCap); + eep->baseEepHeader.deviceCap = word; + + integer = swab32(eep->modalHeader.antCtrlCommon); + eep->modalHeader.antCtrlCommon = integer; + + for (i = 0; i < AR9287_MAX_CHAINS; i++) { + integer = swab32(eep->modalHeader.antCtrlChain[i]); + eep->modalHeader.antCtrlChain[i] = integer; + } + + for (i = 0; i < AR9287_EEPROM_MODAL_SPURS; i++) { + word = swab16(eep->modalHeader.spurChans[i].spurChan); + eep->modalHeader.spurChans[i].spurChan = word; + } + } + + if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER + || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Bad EEPROM checksum 0x%x or revision 0x%04x\n", + sum, ah->eep_ops->get_eeprom_ver(ah)); + return -EINVAL; + } + + return 0; +} + +static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah, + enum eeprom_param param) +{ + struct ar9287_eeprom *eep = &ah->eeprom.map9287; + struct modal_eep_ar9287_header *pModal = &eep->modalHeader; + struct base_eep_ar9287_header *pBase = &eep->baseEepHeader; + u16 ver_minor; + + ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK; + switch (param) { + case EEP_NFTHRESH_2: + return pModal->noiseFloorThreshCh[0]; + case AR_EEPROM_MAC(0): + return pBase->macAddr[0] << 8 | pBase->macAddr[1]; + case AR_EEPROM_MAC(1): + return pBase->macAddr[2] << 8 | pBase->macAddr[3]; + case AR_EEPROM_MAC(2): + return pBase->macAddr[4] << 8 | pBase->macAddr[5]; + case EEP_REG_0: + return pBase->regDmn[0]; + case EEP_REG_1: + return pBase->regDmn[1]; + case EEP_OP_CAP: + return pBase->deviceCap; + case EEP_OP_MODE: + return pBase->opCapFlags; + case EEP_RF_SILENT: + return pBase->rfSilent; + case EEP_MINOR_REV: + return ver_minor; + case EEP_TX_MASK: + return pBase->txMask; + case EEP_RX_MASK: + return pBase->rxMask; + case EEP_DEV_TYPE: + return pBase->deviceType; + case EEP_OL_PWRCTRL: + return pBase->openLoopPwrCntl; + case EEP_TEMPSENSE_SLOPE: + if (ver_minor >= AR9287_EEP_MINOR_VER_2) + return pBase->tempSensSlope; + else + return 0; + case EEP_TEMPSENSE_SLOPE_PAL_ON: + if (ver_minor >= AR9287_EEP_MINOR_VER_3) + return pBase->tempSensSlopePalOn; + else + return 0; + default: + return 0; + } +} + + +static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_data_per_freq_ar9287 *pRawDataSet, + u8 *bChans, u16 availPiers, + u16 tPdGainOverlap, int16_t *pMinCalPower, + u16 *pPdGainBoundaries, u8 *pPDADCValues, + u16 numXpdGains) +{ +#define TMP_VAL_VPD_TABLE \ + ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); + + int i, j, k; + int16_t ss; + u16 idxL = 0, idxR = 0, numPiers; + u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; + u8 minPwrT4[AR9287_NUM_PD_GAINS]; + u8 maxPwrT4[AR9287_NUM_PD_GAINS]; + int16_t vpdStep; + int16_t tmpVal; + u16 sizeCurrVpdTable, maxIndex, tgtIndex; + bool match; + int16_t minDelta = 0; + struct chan_centers centers; + static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (bChans[numPiers] == AR9287_BCHAN_UNUSED) + break; + } + + match = ath9k_hw_get_lower_upper_index( + (u8)FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)), bChans, numPiers, + &idxL, &idxR); + + if (match) { + for (i = 0; i < numXpdGains; i++) { + minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; + maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pRawDataSet[idxL].pwrPdg[i], + pRawDataSet[idxL].vpdPdg[i], + AR9287_PD_GAIN_ICEPTS, vpdTableI[i]); + } + } else { + for (i = 0; i < numXpdGains; i++) { + pVpdL = pRawDataSet[idxL].vpdPdg[i]; + pPwrL = pRawDataSet[idxL].pwrPdg[i]; + pVpdR = pRawDataSet[idxR].vpdPdg[i]; + pPwrR = pRawDataSet[idxR].pwrPdg[i]; + + minPwrT4[i] = max(pPwrL[0], pPwrR[0]); + + maxPwrT4[i] = + min(pPwrL[AR9287_PD_GAIN_ICEPTS - 1], + pPwrR[AR9287_PD_GAIN_ICEPTS - 1]); + + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrL, pVpdL, + AR9287_PD_GAIN_ICEPTS, + vpdTableL[i]); + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrR, pVpdR, + AR9287_PD_GAIN_ICEPTS, + vpdTableR[i]); + + for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { + vpdTableI[i][j] = + (u8)(ath9k_hw_interpolate((u16) + FREQ2FBIN(centers. synth_center, + IS_CHAN_2GHZ(chan)), + bChans[idxL], bChans[idxR], + vpdTableL[i][j], vpdTableR[i][j])); + } + } + } + *pMinCalPower = (int16_t)(minPwrT4[0] / 2); + + k = 0; + for (i = 0; i < numXpdGains; i++) { + if (i == (numXpdGains - 1)) + pPdGainBoundaries[i] = (u16)(maxPwrT4[i] / 2); + else + pPdGainBoundaries[i] = (u16)((maxPwrT4[i] + + minPwrT4[i+1]) / 4); + + pPdGainBoundaries[i] = min((u16)AR5416_MAX_RATE_POWER, + pPdGainBoundaries[i]); + + + if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { + minDelta = pPdGainBoundaries[0] - 23; + pPdGainBoundaries[0] = 23; + } else + minDelta = 0; + + if (i == 0) { + if (AR_SREV_9280_10_OR_LATER(ah)) + ss = (int16_t)(0 - (minPwrT4[i] / 2)); + else + ss = 0; + } else + ss = (int16_t)((pPdGainBoundaries[i-1] - + (minPwrT4[i] / 2)) - + tPdGainOverlap + 1 + minDelta); + + vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + while ((ss < 0) && (k < (AR9287_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); + pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = (u8)((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); + tgtIndex = (u8)(pPdGainBoundaries[i] + + tPdGainOverlap - (minPwrT4[i] / 2)); + maxIndex = (tgtIndex < sizeCurrVpdTable) ? + tgtIndex : sizeCurrVpdTable; + + while ((ss < maxIndex) && (k < (AR9287_NUM_PDADC_VALUES - 1))) + pPDADCValues[k++] = vpdTableI[i][ss++]; + + vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - + vpdTableI[i][sizeCurrVpdTable - 2]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + if (tgtIndex > maxIndex) { + while ((ss <= tgtIndex) && + (k < (AR9287_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t) TMP_VAL_VPD_TABLE; + pPDADCValues[k++] = (u8)((tmpVal > 255) ? + 255 : tmpVal); + ss++; + } + } + } + + while (i < AR9287_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = pPdGainBoundaries[i-1]; + i++; + } + + while (k < AR9287_NUM_PDADC_VALUES) { + pPDADCValues[k] = pPDADCValues[k-1]; + k++; + } + +#undef TMP_VAL_VPD_TABLE +} + +static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop, + u8 *pCalChans, u16 availPiers, + int8_t *pPwr) +{ + u8 pcdac, i = 0; + u16 idxL = 0, idxR = 0, numPiers; + bool match; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (pCalChans[numPiers] == AR9287_BCHAN_UNUSED) + break; + } + + match = ath9k_hw_get_lower_upper_index( + (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), + pCalChans, numPiers, + &idxL, &idxR); + + if (match) { + pcdac = pRawDatasetOpLoop[idxL].pcdac[0][0]; + *pPwr = pRawDatasetOpLoop[idxL].pwrPdg[0][0]; + } else { + pcdac = pRawDatasetOpLoop[idxR].pcdac[0][0]; + *pPwr = (pRawDatasetOpLoop[idxL].pwrPdg[0][0] + + pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; + } + + while ((pcdac > ah->originalGain[i]) && + (i < (AR9280_TX_GAIN_TABLE_SIZE - 1))) + i++; +} + +static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah, + int32_t txPower, u16 chain) +{ + u32 tmpVal; + u32 a; + + tmpVal = REG_READ(ah, 0xa270); + tmpVal = tmpVal & 0xFCFFFFFF; + tmpVal = tmpVal | (0x3 << 24); + REG_WRITE(ah, 0xa270, tmpVal); + + tmpVal = REG_READ(ah, 0xb270); + tmpVal = tmpVal & 0xFCFFFFFF; + tmpVal = tmpVal | (0x3 << 24); + REG_WRITE(ah, 0xb270, tmpVal); + + if (chain == 0) { + tmpVal = REG_READ(ah, 0xa398); + tmpVal = tmpVal & 0xff00ffff; + a = (txPower)&0xff; + tmpVal = tmpVal | (a << 16); + REG_WRITE(ah, 0xa398, tmpVal); + } + + if (chain == 1) { + tmpVal = REG_READ(ah, 0xb398); + tmpVal = tmpVal & 0xff00ffff; + a = (txPower)&0xff; + tmpVal = tmpVal | (a << 16); + REG_WRITE(ah, 0xb398, tmpVal); + } +} + +static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset) +{ + struct cal_data_per_freq_ar9287 *pRawDataset; + struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop; + u8 *pCalBChans = NULL; + u16 pdGainOverlap_t2; + u8 pdadcValues[AR9287_NUM_PDADC_VALUES]; + u16 gainBoundaries[AR9287_PD_GAINS_IN_MASK]; + u16 numPiers = 0, i, j; + int16_t tMinCalPower; + u16 numXpdGain, xpdMask; + u16 xpdGainValues[AR9287_NUM_PD_GAINS] = {0, 0, 0, 0}; + u32 reg32, regOffset, regChainOffset; + int16_t modalIdx, diff = 0; + struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; + modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; + xpdMask = pEepData->modalHeader.xpdGain; + if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= + AR9287_EEP_MINOR_VER_2) + pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap; + else + pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); + + if (IS_CHAN_2GHZ(chan)) { + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR9287_NUM_2G_CAL_PIERS; + if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { + pRawDatasetOpenLoop = + (struct cal_data_op_loop_ar9287 *) + pEepData->calPierData2G[0]; + ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0]; + } + } + + numXpdGain = 0; + for (i = 1; i <= AR9287_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR9287_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR9287_NUM_PD_GAINS) + break; + xpdGainValues[numXpdGain] = + (u16)(AR9287_PD_GAINS_IN_MASK-i); + numXpdGain++; + } + } + + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (numXpdGain - 1) & 0x3); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, + xpdGainValues[0]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, + xpdGainValues[1]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, + xpdGainValues[2]); + + for (i = 0; i < AR9287_MAX_CHAINS; i++) { + regChainOffset = i * 0x1000; + if (pEepData->baseEepHeader.txMask & (1 << i)) { + pRawDatasetOpenLoop = (struct cal_data_op_loop_ar9287 *) + pEepData->calPierData2G[i]; + if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { + int8_t txPower; + ar9287_eeprom_get_tx_gain_index(ah, chan, + pRawDatasetOpenLoop, + pCalBChans, numPiers, + &txPower); + ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i); + } else { + pRawDataset = + (struct cal_data_per_freq_ar9287 *) + pEepData->calPierData2G[i]; + ath9k_hw_get_AR9287_gain_boundaries_pdadcs( + ah, chan, pRawDataset, + pCalBChans, numPiers, + pdGainOverlap_t2, + &tMinCalPower, gainBoundaries, + pdadcValues, numXpdGain); + } + + if (i == 0) { + if (!ath9k_hw_AR9287_get_eeprom( + ah, EEP_OL_PWRCTRL)) { + REG_WRITE(ah, AR_PHY_TPCRG5 + + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | + SM(gainBoundaries[0], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) + | SM(gainBoundaries[1], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) + | SM(gainBoundaries[2], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) + | SM(gainBoundaries[3], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + } + } + + if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB != + pEepData->baseEepHeader.pwrTableOffset) { + diff = (u16) + (pEepData->baseEepHeader.pwrTableOffset + - (int32_t)AR9287_PWR_TABLE_OFFSET_DB); + diff *= 2; + + for (j = 0; + j < ((u16)AR9287_NUM_PDADC_VALUES-diff); + j++) + pdadcValues[j] = pdadcValues[j+diff]; + + for (j = (u16)(AR9287_NUM_PDADC_VALUES-diff); + j < AR9287_NUM_PDADC_VALUES; j++) + pdadcValues[j] = + pdadcValues[ + AR9287_NUM_PDADC_VALUES-diff]; + } + + if (!ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { + regOffset = AR_PHY_BASE + (672 << 2) + + regChainOffset; + for (j = 0; j < 32; j++) { + reg32 = ((pdadcValues[4*j + 0] + & 0xFF) << 0) | + ((pdadcValues[4*j + 1] + & 0xFF) << 8) | + ((pdadcValues[4*j + 2] + & 0xFF) << 16) | + ((pdadcValues[4*j + 3] + & 0xFF) << 24) ; + REG_WRITE(ah, regOffset, reg32); + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PDADC (%d,%4x): %4.4x %8.8x\n", + i, regChainOffset, regOffset, + reg32); + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PDADC: Chain %d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, + pdadcValues[4 * j + 1], + 4 * j + 2, + pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); + + regOffset += 4; + } + } + } + } + + *pTxPowerIndexOffset = 0; +} + +static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, + struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl, + u16 AntennaReduction, u16 twiceMaxRegulatoryPower, + u16 powerLimit) +{ +#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 +#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 + + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + static const u16 tpScaleReductionTable[5] = + { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; + int i; + int16_t twiceLargestAntenna; + struct cal_ctl_data_ar9287 *rep; + struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} }, + targetPowerCck = {0, {0, 0, 0, 0} }; + struct cal_target_power_leg targetPowerOfdmExt = {0, {0, 0, 0, 0} }, + targetPowerCckExt = {0, {0, 0, 0, 0} }; + struct cal_target_power_ht targetPowerHt20, + targetPowerHt40 = {0, {0, 0, 0, 0} }; + u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 ctlModesFor11g[] = + {CTL_11B, CTL_11G, CTL_2GHT20, + CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40}; + u16 numCtlModes = 0, *pCtlMode = NULL, ctlMode, freq; + struct chan_centers centers; + int tx_chainmask; + u16 twiceMinEdgePower; + struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; + tx_chainmask = ah->txchainmask; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0], + pEepData->modalHeader.antennaGainCh[1]); + + twiceLargestAntenna = (int16_t)min((AntennaReduction) - + twiceLargestAntenna, 0); + + maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; + if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) + maxRegAllowedPower -= + (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); + + scaledPower = min(powerLimit, maxRegAllowedPower); + + switch (ar5416_get_ntxchains(tx_chainmask)) { + case 1: + break; + case 2: + scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; + break; + case 3: + scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; + break; + } + scaledPower = max((u16)0, scaledPower); + + if (IS_CHAN_2GHZ(chan)) { + numCtlModes = + ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; + pCtlMode = ctlModesFor11g; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR9287_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCck, 4, false); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR9287_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT20, + AR9287_NUM_2G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT40, + AR9287_NUM_2G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR9287_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCckExt, 4, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR9287_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + } + + for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { + bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || + (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) + freq = centers.synth_center; + else if (pCtlMode[ctlMode] & EXT_ADDITIVE) + freq = centers.ext_center; + else + freq = centers.ctl_center; + + if (ah->eep_ops->get_eeprom_ver(ah) == 14 && + ah->eep_ops->get_eeprom_rev(ah) <= 2) + twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + + for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { + if ((((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + pEepData->ctlIndex[i]) || + (((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & + CTL_MODE_M) | SD_NO_CTL))) { + + rep = &(pEepData->ctlData[i]); + twiceMinEdgePower = ath9k_hw_get_max_edge_power( + freq, + rep->ctlEdges[ar5416_get_ntxchains( + tx_chainmask) - 1], + IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); + + if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) + twiceMaxEdgePower = min( + twiceMaxEdgePower, + twiceMinEdgePower); + else { + twiceMaxEdgePower = twiceMinEdgePower; + break; + } + } + } + + minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); + + switch (pCtlMode[ctlMode]) { + case CTL_11B: + for (i = 0; + i < ARRAY_SIZE(targetPowerCck.tPow2x); + i++) { + targetPowerCck.tPow2x[i] = (u8)min( + (u16)targetPowerCck.tPow2x[i], + minCtlPower); + } + break; + case CTL_11A: + case CTL_11G: + for (i = 0; + i < ARRAY_SIZE(targetPowerOfdm.tPow2x); + i++) { + targetPowerOfdm.tPow2x[i] = (u8)min( + (u16)targetPowerOfdm.tPow2x[i], + minCtlPower); + } + break; + case CTL_5GHT20: + case CTL_2GHT20: + for (i = 0; + i < ARRAY_SIZE(targetPowerHt20.tPow2x); + i++) { + targetPowerHt20.tPow2x[i] = (u8)min( + (u16)targetPowerHt20.tPow2x[i], + minCtlPower); + } + break; + case CTL_11B_EXT: + targetPowerCckExt.tPow2x[0] = (u8)min( + (u16)targetPowerCckExt.tPow2x[0], + minCtlPower); + break; + case CTL_11A_EXT: + case CTL_11G_EXT: + targetPowerOfdmExt.tPow2x[0] = (u8)min( + (u16)targetPowerOfdmExt.tPow2x[0], + minCtlPower); + break; + case CTL_5GHT40: + case CTL_2GHT40: + for (i = 0; + i < ARRAY_SIZE(targetPowerHt40.tPow2x); + i++) { + targetPowerHt40.tPow2x[i] = (u8)min( + (u16)targetPowerHt40.tPow2x[i], + minCtlPower); + } + break; + default: + break; + } + } + + ratesArray[rate6mb] = + ratesArray[rate9mb] = + ratesArray[rate12mb] = + ratesArray[rate18mb] = + ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; + ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; + ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; + ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; + + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) + ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; + + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate2s] = ratesArray[rate2l] = + targetPowerCck.tPow2x[1]; + ratesArray[rate5_5s] = ratesArray[rate5_5l] = + targetPowerCck.tPow2x[2]; + ratesArray[rate11s] = ratesArray[rate11l] = + targetPowerCck.tPow2x[3]; + } + if (IS_CHAN_HT40(chan)) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) + ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i]; + + ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; + ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; + ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; + if (IS_CHAN_2GHZ(chan)) + ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; + } + +#undef REDUCE_SCALED_POWER_BY_TWO_CHAIN +#undef REDUCE_SCALED_POWER_BY_THREE_CHAIN +} + +static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, + struct ath9k_channel *chan, u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ +#define INCREASE_MAXPOW_BY_TWO_CHAIN 6 +#define INCREASE_MAXPOW_BY_THREE_CHAIN 10 + + struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; + struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; + int16_t ratesArray[Ar5416RateSize]; + int16_t txPowerIndexOffset = 0; + u8 ht40PowerIncForPdadc = 2; + int i; + + memset(ratesArray, 0, sizeof(ratesArray)); + + if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= + AR9287_EEP_MINOR_VER_2) + ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; + + ath9k_hw_set_AR9287_power_per_rate_table(ah, chan, + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit); + + ath9k_hw_set_AR9287_power_cal_table(ah, chan, &txPowerIndexOffset); + + for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { + ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); + if (ratesArray[i] > AR9287_MAX_RATE_POWER) + ratesArray[i] = AR9287_MAX_RATE_POWER; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + for (i = 0; i < Ar5416RateSize; i++) + ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) + | ATH9K_POW_SM(ratesArray[rate9mb], 8) + | ATH9K_POW_SM(ratesArray[rate6mb], 0)); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + ATH9K_POW_SM(ratesArray[rate54mb], 24) + | ATH9K_POW_SM(ratesArray[rate48mb], 16) + | ATH9K_POW_SM(ratesArray[rate36mb], 8) + | ATH9K_POW_SM(ratesArray[rate24mb], 0)); + + if (IS_CHAN_2GHZ(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, + ATH9K_POW_SM(ratesArray[rateHt20_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, + ATH9K_POW_SM(ratesArray[rateHt20_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); + + if (IS_CHAN_HT40(chan)) { + if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0], 0)); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4], 0)); + } else { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0] + + ht40PowerIncForPdadc, 0)); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4] + + ht40PowerIncForPdadc, 0)); + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(ratesArray[rateExtCck], 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); + } + + if (IS_CHAN_2GHZ(chan)) + i = rate1l; + else + i = rate6mb; + + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->regulatory.max_power_level = + ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2; + else + ah->regulatory.max_power_level = ratesArray[i]; + + switch (ar5416_get_ntxchains(ah->txchainmask)) { + case 1: + break; + case 2: + ah->regulatory.max_power_level += + INCREASE_MAXPOW_BY_TWO_CHAIN; + break; + case 3: + ah->regulatory.max_power_level += + INCREASE_MAXPOW_BY_THREE_CHAIN; + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Invalid chainmask configuration\n"); + break; + } +} + +static void ath9k_hw_AR9287_set_addac(struct ath_hw *ah, + struct ath9k_channel *chan) +{ +} + +static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct ar9287_eeprom *eep = &ah->eeprom.map9287; + struct modal_eep_ar9287_header *pModal = &eep->modalHeader; + u16 antWrites[AR9287_ANT_16S]; + u32 regChainOffset; + u8 txRxAttenLocal; + int i, j, offset_num; + + pModal = &eep->modalHeader; + + antWrites[0] = (u16)((pModal->antCtrlCommon >> 28) & 0xF); + antWrites[1] = (u16)((pModal->antCtrlCommon >> 24) & 0xF); + antWrites[2] = (u16)((pModal->antCtrlCommon >> 20) & 0xF); + antWrites[3] = (u16)((pModal->antCtrlCommon >> 16) & 0xF); + antWrites[4] = (u16)((pModal->antCtrlCommon >> 12) & 0xF); + antWrites[5] = (u16)((pModal->antCtrlCommon >> 8) & 0xF); + antWrites[6] = (u16)((pModal->antCtrlCommon >> 4) & 0xF); + antWrites[7] = (u16)(pModal->antCtrlCommon & 0xF); + + offset_num = 8; + + for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) { + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 28) & 0xf); + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 10) & 0x3); + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 8) & 0x3); + antWrites[j++] = 0; + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 6) & 0x3); + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 4) & 0x3); + antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 2) & 0x3); + antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3); + } + + REG_WRITE(ah, AR_PHY_SWITCH_COM, + ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); + + for (i = 0; i < AR9287_MAX_CHAINS; i++) { + regChainOffset = i * 0x1000; + + REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, + pModal->antCtrlChain[i]); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, + (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) + & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + + txRxAttenLocal = pModal->txRxAttenCh[i]; + + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, + pModal->bswMargin[i]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, + pModal->bswAtten[i]); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_ATTEN, + txRxAttenLocal); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_MARGIN, + pModal->rxTxMarginCh[i]); + } + + + if (IS_CHAN_HT40(chan)) + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); + else + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, pModal->switchSettling); + + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, + AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize); + + REG_WRITE(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) + | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) + | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) + | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, + AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); + + REG_RMW_FIELD(ah, AR_PHY_CCA, + AR9280_PHY_CCA_THRESH62, pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, + AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62); + + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB1, + AR9287_AN_RF2G3_DB1_S, pModal->db1); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB2, + AR9287_AN_RF2G3_DB2_S, pModal->db2); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, + AR9287_AN_RF2G3_OB_CCK, + AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, + AR9287_AN_RF2G3_OB_PSK, + AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, + AR9287_AN_RF2G3_OB_QAM, + AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, + AR9287_AN_RF2G3_OB_PAL_OFF, + AR9287_AN_RF2G3_OB_PAL_OFF_S, + pModal->ob_pal_off); + + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, + AR9287_AN_RF2G3_DB1, AR9287_AN_RF2G3_DB1_S, + pModal->db1); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, AR9287_AN_RF2G3_DB2, + AR9287_AN_RF2G3_DB2_S, pModal->db2); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, + AR9287_AN_RF2G3_OB_CCK, + AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, + AR9287_AN_RF2G3_OB_PSK, + AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, + AR9287_AN_RF2G3_OB_QAM, + AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, + AR9287_AN_RF2G3_OB_PAL_OFF, + AR9287_AN_RF2G3_OB_PAL_OFF_S, + pModal->ob_pal_off); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, + AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart); + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, + AR_PHY_TX_END_PA_ON, pModal->txFrameToPaOn); + + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TOP2, + AR9287_AN_TOP2_XPABIAS_LVL, + AR9287_AN_TOP2_XPABIAS_LVL_S, + pModal->xpaBiasLvl); +} + +static u8 ath9k_hw_AR9287_get_num_ant_config(struct ath_hw *ah, + enum ieee80211_band freq_band) +{ + return 1; +} + +static u16 ath9k_hw_AR9287_get_eeprom_antenna_cfg(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct ar9287_eeprom *eep = &ah->eeprom.map9287; + struct modal_eep_ar9287_header *pModal = &eep->modalHeader; + + return pModal->antCtrlCommon & 0xFFFF; +} + +static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah, + u16 i, bool is2GHz) +{ +#define EEP_MAP9287_SPURCHAN \ + (ah->eeprom.map9287.modalHeader.spurChans[i].spurChan) + u16 spur_val = AR_NO_SPUR; + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur idx %d is2Ghz. %d val %x\n", + i, is2GHz, ah->config.spurchans[i][is2GHz]); + + switch (ah->config.spurmode) { + case SPUR_DISABLE: + break; + case SPUR_ENABLE_IOCTL: + spur_val = ah->config.spurchans[i][is2GHz]; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur val from new loc. %d\n", spur_val); + break; + case SPUR_ENABLE_EEPROM: + spur_val = EEP_MAP9287_SPURCHAN; + break; + } + + return spur_val; + +#undef EEP_MAP9287_SPURCHAN +} + +const struct eeprom_ops eep_AR9287_ops = { + .check_eeprom = ath9k_hw_AR9287_check_eeprom, + .get_eeprom = ath9k_hw_AR9287_get_eeprom, + .fill_eeprom = ath9k_hw_AR9287_fill_eeprom, + .get_eeprom_ver = ath9k_hw_AR9287_get_eeprom_ver, + .get_eeprom_rev = ath9k_hw_AR9287_get_eeprom_rev, + .get_num_ant_config = ath9k_hw_AR9287_get_num_ant_config, + .get_eeprom_antenna_cfg = ath9k_hw_AR9287_get_eeprom_antenna_cfg, + .set_board_values = ath9k_hw_AR9287_set_board_values, + .set_addac = ath9k_hw_AR9287_set_addac, + .set_txpower = ath9k_hw_AR9287_set_txpower, + .get_spur_channel = ath9k_hw_AR9287_get_spur_channel +}; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c new file mode 100644 index 00000000000..5211ad94c8f --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -0,0 +1,1385 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +static void ath9k_get_txgain_index(struct ath_hw *ah, + struct ath9k_channel *chan, + struct calDataPerFreqOpLoop *rawDatasetOpLoop, + u8 *calChans, u16 availPiers, u8 *pwr, u8 *pcdacIdx) +{ + u8 pcdac, i = 0; + u16 idxL = 0, idxR = 0, numPiers; + bool match; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + for (numPiers = 0; numPiers < availPiers; numPiers++) + if (calChans[numPiers] == AR5416_BCHAN_UNUSED) + break; + + match = ath9k_hw_get_lower_upper_index( + (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), + calChans, numPiers, &idxL, &idxR); + if (match) { + pcdac = rawDatasetOpLoop[idxL].pcdac[0][0]; + *pwr = rawDatasetOpLoop[idxL].pwrPdg[0][0]; + } else { + pcdac = rawDatasetOpLoop[idxR].pcdac[0][0]; + *pwr = (rawDatasetOpLoop[idxL].pwrPdg[0][0] + + rawDatasetOpLoop[idxR].pwrPdg[0][0])/2; + } + + while (pcdac > ah->originalGain[i] && + i < (AR9280_TX_GAIN_TABLE_SIZE - 1)) + i++; + + *pcdacIdx = i; + return; +} + +static void ath9k_olc_get_pdadcs(struct ath_hw *ah, + u32 initTxGain, + int txPower, + u8 *pPDADCValues) +{ + u32 i; + u32 offset; + + REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_0, + AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); + REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_1, + AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); + + REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL7, + AR_PHY_TX_PWRCTRL_INIT_TX_GAIN, initTxGain); + + offset = txPower; + for (i = 0; i < AR5416_NUM_PDADC_VALUES; i++) + if (i < offset) + pPDADCValues[i] = 0x0; + else + pPDADCValues[i] = 0xFF; +} + +static int ath9k_hw_def_get_eeprom_ver(struct ath_hw *ah) +{ + return ((ah->eeprom.def.baseEepHeader.version >> 12) & 0xF); +} + +static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah) +{ + return ((ah->eeprom.def.baseEepHeader.version) & 0xFFF); +} + +static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) +{ +#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16)) + u16 *eep_data = (u16 *)&ah->eeprom.def; + int addr, ar5416_eep_start_loc = 0x100; + + for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { + if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, + eep_data)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Unable to read eeprom region\n"); + return false; + } + eep_data++; + } + return true; +#undef SIZE_EEPROM_DEF +} + +static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) +{ + struct ar5416_eeprom_def *eep = + (struct ar5416_eeprom_def *) &ah->eeprom.def; + u16 *eepdata, temp, magic, magic2; + u32 sum = 0, el; + bool need_swap = false; + int i, addr, size; + + if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Reading Magic # failed\n"); + return false; + } + + if (!ath9k_hw_use_flash(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); + + if (magic != AR5416_EEPROM_MAGIC) { + magic2 = swab16(magic); + + if (magic2 == AR5416_EEPROM_MAGIC) { + size = sizeof(struct ar5416_eeprom_def); + need_swap = true; + eepdata = (u16 *) (&ah->eeprom); + + for (addr = 0; addr < size / sizeof(u16); addr++) { + temp = swab16(*eepdata); + *eepdata = temp; + eepdata++; + } + } else { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Invalid EEPROM Magic. " + "Endianness mismatch.\n"); + return -EINVAL; + } + } + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", + need_swap ? "True" : "False"); + + if (need_swap) + el = swab16(ah->eeprom.def.baseEepHeader.length); + else + el = ah->eeprom.def.baseEepHeader.length; + + if (el > sizeof(struct ar5416_eeprom_def)) + el = sizeof(struct ar5416_eeprom_def) / sizeof(u16); + else + el = el / sizeof(u16); + + eepdata = (u16 *)(&ah->eeprom); + + for (i = 0; i < el; i++) + sum ^= *eepdata++; + + if (need_swap) { + u32 integer, j; + u16 word; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "EEPROM Endianness is not native.. Changing.\n"); + + word = swab16(eep->baseEepHeader.length); + eep->baseEepHeader.length = word; + + word = swab16(eep->baseEepHeader.checksum); + eep->baseEepHeader.checksum = word; + + word = swab16(eep->baseEepHeader.version); + eep->baseEepHeader.version = word; + + word = swab16(eep->baseEepHeader.regDmn[0]); + eep->baseEepHeader.regDmn[0] = word; + + word = swab16(eep->baseEepHeader.regDmn[1]); + eep->baseEepHeader.regDmn[1] = word; + + word = swab16(eep->baseEepHeader.rfSilent); + eep->baseEepHeader.rfSilent = word; + + word = swab16(eep->baseEepHeader.blueToothOptions); + eep->baseEepHeader.blueToothOptions = word; + + word = swab16(eep->baseEepHeader.deviceCap); + eep->baseEepHeader.deviceCap = word; + + for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) { + struct modal_eep_header *pModal = + &eep->modalHeader[j]; + integer = swab32(pModal->antCtrlCommon); + pModal->antCtrlCommon = integer; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + integer = swab32(pModal->antCtrlChain[i]); + pModal->antCtrlChain[i] = integer; + } + + for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { + word = swab16(pModal->spurChans[i].spurChan); + pModal->spurChans[i].spurChan = word; + } + } + } + + if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || + ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Bad EEPROM checksum 0x%x or revision 0x%04x\n", + sum, ah->eep_ops->get_eeprom_ver(ah)); + return -EINVAL; + } + + return 0; +} + +static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, + enum eeprom_param param) +{ + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + struct modal_eep_header *pModal = eep->modalHeader; + struct base_eep_header *pBase = &eep->baseEepHeader; + + switch (param) { + case EEP_NFTHRESH_5: + return pModal[0].noiseFloorThreshCh[0]; + case EEP_NFTHRESH_2: + return pModal[1].noiseFloorThreshCh[0]; + case AR_EEPROM_MAC(0): + return pBase->macAddr[0] << 8 | pBase->macAddr[1]; + case AR_EEPROM_MAC(1): + return pBase->macAddr[2] << 8 | pBase->macAddr[3]; + case AR_EEPROM_MAC(2): + return pBase->macAddr[4] << 8 | pBase->macAddr[5]; + case EEP_REG_0: + return pBase->regDmn[0]; + case EEP_REG_1: + return pBase->regDmn[1]; + case EEP_OP_CAP: + return pBase->deviceCap; + case EEP_OP_MODE: + return pBase->opCapFlags; + case EEP_RF_SILENT: + return pBase->rfSilent; + case EEP_OB_5: + return pModal[0].ob; + case EEP_DB_5: + return pModal[0].db; + case EEP_OB_2: + return pModal[1].ob; + case EEP_DB_2: + return pModal[1].db; + case EEP_MINOR_REV: + return AR5416_VER_MASK; + case EEP_TX_MASK: + return pBase->txMask; + case EEP_RX_MASK: + return pBase->rxMask; + case EEP_RXGAIN_TYPE: + return pBase->rxGainType; + case EEP_TXGAIN_TYPE: + return pBase->txGainType; + case EEP_OL_PWRCTRL: + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) + return pBase->openLoopPwrCntl ? true : false; + else + return false; + case EEP_RC_CHAIN_MASK: + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) + return pBase->rcChainMask; + else + return 0; + case EEP_DAC_HPWR_5G: + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) + return pBase->dacHiPwrMode_5G; + else + return 0; + case EEP_FRAC_N_5G: + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_22) + return pBase->frac_n_5g; + else + return 0; + default: + return 0; + } +} + +static void ath9k_hw_def_set_gain(struct ath_hw *ah, + struct modal_eep_header *pModal, + struct ar5416_eeprom_def *eep, + u8 txRxAttenLocal, int regChainOffset, int i) +{ + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { + txRxAttenLocal = pModal->txRxAttenCh[i]; + + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, + pModal->bswMargin[i]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, + pModal->bswAtten[i]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, + pModal->xatten2Margin[i]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_DB, + pModal->xatten2Db[i]); + } else { + REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) + | SM(pModal-> bswMargin[i], + AR_PHY_GAIN_2GHZ_BSW_MARGIN)); + REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) + | SM(pModal->bswAtten[i], + AR_PHY_GAIN_2GHZ_BSW_ATTEN)); + } + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_RMW_FIELD(ah, + AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); + REG_RMW_FIELD(ah, + AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[i]); + } else { + REG_WRITE(ah, + AR_PHY_RXGAIN + regChainOffset, + (REG_READ(ah, AR_PHY_RXGAIN + regChainOffset) & + ~AR_PHY_RXGAIN_TXRX_ATTEN) + | SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN)); + REG_WRITE(ah, + AR_PHY_GAIN_2GHZ + regChainOffset, + (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | + SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); + } +} + +static void ath9k_hw_def_set_board_values(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct modal_eep_header *pModal; + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + int i, regChainOffset; + u8 txRxAttenLocal; + + pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; + + REG_WRITE(ah, AR_PHY_SWITCH_COM, + ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (AR_SREV_9280(ah)) { + if (i >= 2) + break; + } + + if (AR_SREV_5416_20_OR_LATER(ah) && + (ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0)) + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + else + regChainOffset = i * 0x1000; + + REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, + pModal->antCtrlChain[i]); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, + (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & + ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + + if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) + ath9k_hw_def_set_gain(ah, pModal, eep, txRxAttenLocal, + regChainOffset, i); + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + if (IS_CHAN_2GHZ(chan)) { + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, + AR_AN_RF2G1_CH0_OB, + AR_AN_RF2G1_CH0_OB_S, + pModal->ob); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, + AR_AN_RF2G1_CH0_DB, + AR_AN_RF2G1_CH0_DB_S, + pModal->db); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, + AR_AN_RF2G1_CH1_OB, + AR_AN_RF2G1_CH1_OB_S, + pModal->ob_ch1); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, + AR_AN_RF2G1_CH1_DB, + AR_AN_RF2G1_CH1_DB_S, + pModal->db_ch1); + } else { + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, + AR_AN_RF5G1_CH0_OB5, + AR_AN_RF5G1_CH0_OB5_S, + pModal->ob); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, + AR_AN_RF5G1_CH0_DB5, + AR_AN_RF5G1_CH0_DB5_S, + pModal->db); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, + AR_AN_RF5G1_CH1_OB5, + AR_AN_RF5G1_CH1_OB5_S, + pModal->ob_ch1); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, + AR_AN_RF5G1_CH1_DB5, + AR_AN_RF5G1_CH1_DB5_S, + pModal->db_ch1); + } + ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, + AR_AN_TOP2_XPABIAS_LVL, + AR_AN_TOP2_XPABIAS_LVL_S, + pModal->xpaBiasLvl); + ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, + AR_AN_TOP2_LOCALBIAS, + AR_AN_TOP2_LOCALBIAS_S, + pModal->local_bias); + REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG, + pModal->force_xpaon); + } + + REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, + pModal->switchSettling); + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, + pModal->adcDesiredSize); + + if (!AR_SREV_9280_10_OR_LATER(ah)) + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, + AR_PHY_DESIRED_SZ_PGA, + pModal->pgaDesiredSize); + + REG_WRITE(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) + | SM(pModal->txEndToXpaOff, + AR_PHY_RF_CTL4_TX_END_XPAB_OFF) + | SM(pModal->txFrameToXpaOn, + AR_PHY_RF_CTL4_FRAME_XPAA_ON) + | SM(pModal->txFrameToXpaOn, + AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, + pModal->txEndToRxOn); + + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, + pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, + AR_PHY_EXT_CCA0_THRESH62, + pModal->thresh62); + } else { + REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62, + pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, + AR_PHY_EXT_CCA_THRESH62, + pModal->thresh62); + } + + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) { + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, + AR_PHY_TX_END_DATA_START, + pModal->txFrameToDataStart); + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, + pModal->txFrameToPaOn); + } + + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { + if (IS_CHAN_HT40(chan)) + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, + pModal->swSettleHt40); + } + + if (AR_SREV_9280_20_OR_LATER(ah) && + AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) + REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL, + AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK, + pModal->miscBits); + + + if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) { + if (IS_CHAN_2GHZ(chan)) + REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, + eep->baseEepHeader.dacLpMode); + else if (eep->baseEepHeader.dacHiPwrMode_5G) + REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, 0); + else + REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, + eep->baseEepHeader.dacLpMode); + + REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP, + pModal->miscBits >> 2); + + REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL9, + AR_PHY_TX_DESIRED_SCALE_CCK, + eep->baseEepHeader.desiredScaleCCK); + } +} + +static void ath9k_hw_def_set_addac(struct ath_hw *ah, + struct ath9k_channel *chan) +{ +#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt]) + struct modal_eep_header *pModal; + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + u8 biaslevel; + + if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) + return; + + if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) + return; + + pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + + if (pModal->xpaBiasLvl != 0xff) { + biaslevel = pModal->xpaBiasLvl; + } else { + u16 resetFreqBin, freqBin, freqCount = 0; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + resetFreqBin = FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)); + freqBin = XPA_LVL_FREQ(0) & 0xff; + biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14); + + freqCount++; + + while (freqCount < 3) { + if (XPA_LVL_FREQ(freqCount) == 0x0) + break; + + freqBin = XPA_LVL_FREQ(freqCount) & 0xff; + if (resetFreqBin >= freqBin) + biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14); + else + break; + freqCount++; + } + } + + if (IS_CHAN_2GHZ(chan)) { + INI_RA(&ah->iniAddac, 7, 1) = (INI_RA(&ah->iniAddac, + 7, 1) & (~0x18)) | biaslevel << 3; + } else { + INI_RA(&ah->iniAddac, 6, 1) = (INI_RA(&ah->iniAddac, + 6, 1) & (~0xc0)) | biaslevel << 6; + } +#undef XPA_LVL_FREQ +} + +static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah, + struct ath9k_channel *chan, + struct cal_data_per_freq *pRawDataSet, + u8 *bChans, u16 availPiers, + u16 tPdGainOverlap, int16_t *pMinCalPower, + u16 *pPdGainBoundaries, u8 *pPDADCValues, + u16 numXpdGains) +{ + int i, j, k; + int16_t ss; + u16 idxL = 0, idxR = 0, numPiers; + static u8 vpdTableL[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableR[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableI[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; + u8 minPwrT4[AR5416_NUM_PD_GAINS]; + u8 maxPwrT4[AR5416_NUM_PD_GAINS]; + int16_t vpdStep; + int16_t tmpVal; + u16 sizeCurrVpdTable, maxIndex, tgtIndex; + bool match; + int16_t minDelta = 0; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (bChans[numPiers] == AR5416_BCHAN_UNUSED) + break; + } + + match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)), + bChans, numPiers, &idxL, &idxR); + + if (match) { + for (i = 0; i < numXpdGains; i++) { + minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; + maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pRawDataSet[idxL].pwrPdg[i], + pRawDataSet[idxL].vpdPdg[i], + AR5416_PD_GAIN_ICEPTS, + vpdTableI[i]); + } + } else { + for (i = 0; i < numXpdGains; i++) { + pVpdL = pRawDataSet[idxL].vpdPdg[i]; + pPwrL = pRawDataSet[idxL].pwrPdg[i]; + pVpdR = pRawDataSet[idxR].vpdPdg[i]; + pPwrR = pRawDataSet[idxR].pwrPdg[i]; + + minPwrT4[i] = max(pPwrL[0], pPwrR[0]); + + maxPwrT4[i] = + min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], + pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); + + + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrL, pVpdL, + AR5416_PD_GAIN_ICEPTS, + vpdTableL[i]); + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrR, pVpdR, + AR5416_PD_GAIN_ICEPTS, + vpdTableR[i]); + + for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { + vpdTableI[i][j] = + (u8)(ath9k_hw_interpolate((u16) + FREQ2FBIN(centers. + synth_center, + IS_CHAN_2GHZ + (chan)), + bChans[idxL], bChans[idxR], + vpdTableL[i][j], vpdTableR[i][j])); + } + } + } + + *pMinCalPower = (int16_t)(minPwrT4[0] / 2); + + k = 0; + + for (i = 0; i < numXpdGains; i++) { + if (i == (numXpdGains - 1)) + pPdGainBoundaries[i] = + (u16)(maxPwrT4[i] / 2); + else + pPdGainBoundaries[i] = + (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); + + pPdGainBoundaries[i] = + min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); + + if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { + minDelta = pPdGainBoundaries[0] - 23; + pPdGainBoundaries[0] = 23; + } else { + minDelta = 0; + } + + if (i == 0) { + if (AR_SREV_9280_10_OR_LATER(ah)) + ss = (int16_t)(0 - (minPwrT4[i] / 2)); + else + ss = 0; + } else { + ss = (int16_t)((pPdGainBoundaries[i - 1] - + (minPwrT4[i] / 2)) - + tPdGainOverlap + 1 + minDelta); + } + vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); + pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); + tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - + (minPwrT4[i] / 2)); + maxIndex = (tgtIndex < sizeCurrVpdTable) ? + tgtIndex : sizeCurrVpdTable; + + while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + pPDADCValues[k++] = vpdTableI[i][ss++]; + } + + vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - + vpdTableI[i][sizeCurrVpdTable - 2]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + if (tgtIndex > maxIndex) { + while ((ss <= tgtIndex) && + (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + + (ss - maxIndex + 1) * vpdStep)); + pPDADCValues[k++] = (u8)((tmpVal > 255) ? + 255 : tmpVal); + ss++; + } + } + } + + while (i < AR5416_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; + i++; + } + + while (k < AR5416_NUM_PDADC_VALUES) { + pPDADCValues[k] = pPDADCValues[k - 1]; + k++; + } + + return; +} + +static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset) +{ +#define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x) +#define SM_PDGAIN_B(x, y) \ + SM((gainBoundaries[x]), AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##y) + + struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; + struct cal_data_per_freq *pRawDataset; + u8 *pCalBChans = NULL; + u16 pdGainOverlap_t2; + static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; + u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; + u16 numPiers, i, j; + int16_t tMinCalPower; + u16 numXpdGain, xpdMask; + u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; + u32 reg32, regOffset, regChainOffset; + int16_t modalIdx; + + modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; + xpdMask = pEepData->modalHeader[modalIdx].xpdGain; + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + pdGainOverlap_t2 = + pEepData->modalHeader[modalIdx].pdGainOverlap; + } else { + pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); + } + + if (IS_CHAN_2GHZ(chan)) { + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR5416_NUM_2G_CAL_PIERS; + } else { + pCalBChans = pEepData->calFreqPier5G; + numPiers = AR5416_NUM_5G_CAL_PIERS; + } + + if (OLC_FOR_AR9280_20_LATER && IS_CHAN_2GHZ(chan)) { + pRawDataset = pEepData->calPierData2G[0]; + ah->initPDADC = ((struct calDataPerFreqOpLoop *) + pRawDataset)->vpdPdg[0][0]; + } + + numXpdGain = 0; + + for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR5416_NUM_PD_GAINS) + break; + xpdGainValues[numXpdGain] = + (u16)(AR5416_PD_GAINS_IN_MASK - i); + numXpdGain++; + } + } + + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (numXpdGain - 1) & 0x3); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, + xpdGainValues[0]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, + xpdGainValues[1]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, + xpdGainValues[2]); + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (AR_SREV_5416_20_OR_LATER(ah) && + (ah->rxchainmask == 5 || ah->txchainmask == 5) && + (i != 0)) { + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + } else + regChainOffset = i * 0x1000; + + if (pEepData->baseEepHeader.txMask & (1 << i)) { + if (IS_CHAN_2GHZ(chan)) + pRawDataset = pEepData->calPierData2G[i]; + else + pRawDataset = pEepData->calPierData5G[i]; + + + if (OLC_FOR_AR9280_20_LATER) { + u8 pcdacIdx; + u8 txPower; + + ath9k_get_txgain_index(ah, chan, + (struct calDataPerFreqOpLoop *)pRawDataset, + pCalBChans, numPiers, &txPower, &pcdacIdx); + ath9k_olc_get_pdadcs(ah, pcdacIdx, + txPower/2, pdadcValues); + } else { + ath9k_hw_get_def_gain_boundaries_pdadcs(ah, + chan, pRawDataset, + pCalBChans, numPiers, + pdGainOverlap_t2, + &tMinCalPower, + gainBoundaries, + pdadcValues, + numXpdGain); + } + + if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { + if (OLC_FOR_AR9280_20_LATER) { + REG_WRITE(ah, + AR_PHY_TPCRG5 + regChainOffset, + SM(0x6, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | + SM_PD_GAIN(1) | SM_PD_GAIN(2) | + SM_PD_GAIN(3) | SM_PD_GAIN(4)); + } else { + REG_WRITE(ah, + AR_PHY_TPCRG5 + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)| + SM_PDGAIN_B(0, 1) | + SM_PDGAIN_B(1, 2) | + SM_PDGAIN_B(2, 3) | + SM_PDGAIN_B(3, 4)); + } + } + + regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; + for (j = 0; j < 32; j++) { + reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | + ((pdadcValues[4 * j + 1] & 0xFF) << 8) | + ((pdadcValues[4 * j + 2] & 0xFF) << 16)| + ((pdadcValues[4 * j + 3] & 0xFF) << 24); + REG_WRITE(ah, regOffset, reg32); + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PDADC (%d,%4x): %4.4x %8.8x\n", + i, regChainOffset, regOffset, + reg32); + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "PDADC: Chain %d | PDADC %3d " + "Value %3d | PDADC %3d Value %3d | " + "PDADC %3d Value %3d | PDADC %3d " + "Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, pdadcValues[4 * j + 1], + 4 * j + 2, pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); + + regOffset += 4; + } + } + } + + *pTxPowerIndexOffset = 0; +#undef SM_PD_GAIN +#undef SM_PDGAIN_B +} + +static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, + struct ath9k_channel *chan, + int16_t *ratesArray, + u16 cfgCtl, + u16 AntennaReduction, + u16 twiceMaxRegulatoryPower, + u16 powerLimit) +{ +#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ +#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ + + struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + static const u16 tpScaleReductionTable[5] = + { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; + + int i; + int16_t twiceLargestAntenna; + struct cal_ctl_data *rep; + struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { + 0, { 0, 0, 0, 0} + }; + struct cal_target_power_leg targetPowerOfdmExt = { + 0, { 0, 0, 0, 0} }, targetPowerCckExt = { + 0, { 0, 0, 0, 0 } + }; + struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { + 0, {0, 0, 0, 0} + }; + u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 ctlModesFor11a[] = + { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; + u16 ctlModesFor11g[] = + { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, + CTL_2GHT40 + }; + u16 numCtlModes, *pCtlMode, ctlMode, freq; + struct chan_centers centers; + int tx_chainmask; + u16 twiceMinEdgePower; + + tx_chainmask = ah->txchainmask; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + twiceLargestAntenna = max( + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[0], + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[1]); + + twiceLargestAntenna = max((u8)twiceLargestAntenna, + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); + + twiceLargestAntenna = (int16_t)min(AntennaReduction - + twiceLargestAntenna, 0); + + maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; + + if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { + maxRegAllowedPower -= + (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); + } + + scaledPower = min(powerLimit, maxRegAllowedPower); + + switch (ar5416_get_ntxchains(tx_chainmask)) { + case 1: + break; + case 2: + scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; + break; + case 3: + scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; + break; + } + + scaledPower = max((u16)0, scaledPower); + + if (IS_CHAN_2GHZ(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g) - + SUB_NUM_CTL_MODES_AT_2G_40; + pCtlMode = ctlModesFor11g; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCck, 4, false); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT20, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT40, + AR5416_NUM_2G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCckExt, 4, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + } else { + numCtlModes = ARRAY_SIZE(ctlModesFor11a) - + SUB_NUM_CTL_MODES_AT_5G_40; + pCtlMode = ctlModesFor11a; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower5G, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower5GHT20, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11a); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower5GHT40, + AR5416_NUM_5G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower5G, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + } + + for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { + bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || + (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) + freq = centers.synth_center; + else if (pCtlMode[ctlMode] & EXT_ADDITIVE) + freq = centers.ext_center; + else + freq = centers.ctl_center; + + if (ah->eep_ops->get_eeprom_ver(ah) == 14 && + ah->eep_ops->get_eeprom_rev(ah) <= 2) + twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + + for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { + if ((((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + pEepData->ctlIndex[i]) || + (((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { + rep = &(pEepData->ctlData[i]); + + twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq, + rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1], + IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); + + if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { + twiceMaxEdgePower = min(twiceMaxEdgePower, + twiceMinEdgePower); + } else { + twiceMaxEdgePower = twiceMinEdgePower; + break; + } + } + } + + minCtlPower = min(twiceMaxEdgePower, scaledPower); + + switch (pCtlMode[ctlMode]) { + case CTL_11B: + for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { + targetPowerCck.tPow2x[i] = + min((u16)targetPowerCck.tPow2x[i], + minCtlPower); + } + break; + case CTL_11A: + case CTL_11G: + for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { + targetPowerOfdm.tPow2x[i] = + min((u16)targetPowerOfdm.tPow2x[i], + minCtlPower); + } + break; + case CTL_5GHT20: + case CTL_2GHT20: + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { + targetPowerHt20.tPow2x[i] = + min((u16)targetPowerHt20.tPow2x[i], + minCtlPower); + } + break; + case CTL_11B_EXT: + targetPowerCckExt.tPow2x[0] = min((u16) + targetPowerCckExt.tPow2x[0], + minCtlPower); + break; + case CTL_11A_EXT: + case CTL_11G_EXT: + targetPowerOfdmExt.tPow2x[0] = min((u16) + targetPowerOfdmExt.tPow2x[0], + minCtlPower); + break; + case CTL_5GHT40: + case CTL_2GHT40: + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { + targetPowerHt40.tPow2x[i] = + min((u16)targetPowerHt40.tPow2x[i], + minCtlPower); + } + break; + default: + break; + } + } + + ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = + ratesArray[rate18mb] = ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; + ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; + ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; + ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; + + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) + ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; + + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate2s] = ratesArray[rate2l] = + targetPowerCck.tPow2x[1]; + ratesArray[rate5_5s] = ratesArray[rate5_5l] = + targetPowerCck.tPow2x[2]; + ratesArray[rate11s] = ratesArray[rate11l] = + targetPowerCck.tPow2x[3]; + } + if (IS_CHAN_HT40(chan)) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { + ratesArray[rateHt40_0 + i] = + targetPowerHt40.tPow2x[i]; + } + ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; + ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; + ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rateExtCck] = + targetPowerCckExt.tPow2x[0]; + } + } +} + +static void ath9k_hw_def_set_txpower(struct ath_hw *ah, + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ +#define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta) + struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; + struct modal_eep_header *pModal = + &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); + int16_t ratesArray[Ar5416RateSize]; + int16_t txPowerIndexOffset = 0; + u8 ht40PowerIncForPdadc = 2; + int i, cck_ofdm_delta = 0; + + memset(ratesArray, 0, sizeof(ratesArray)); + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; + } + + ath9k_hw_set_def_power_per_rate_table(ah, chan, + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit); + + ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset); + + for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { + ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); + if (ratesArray[i] > AR5416_MAX_RATE_POWER) + ratesArray[i] = AR5416_MAX_RATE_POWER; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + for (i = 0; i < Ar5416RateSize; i++) + ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) + | ATH9K_POW_SM(ratesArray[rate9mb], 8) + | ATH9K_POW_SM(ratesArray[rate6mb], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + ATH9K_POW_SM(ratesArray[rate54mb], 24) + | ATH9K_POW_SM(ratesArray[rate48mb], 16) + | ATH9K_POW_SM(ratesArray[rate36mb], 8) + | ATH9K_POW_SM(ratesArray[rate24mb], 0)); + + if (IS_CHAN_2GHZ(chan)) { + if (OLC_FOR_AR9280_20_LATER) { + cck_ofdm_delta = 2; + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(RT_AR_DELTA(rate2s), 24) + | ATH9K_POW_SM(RT_AR_DELTA(rate2l), 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(RT_AR_DELTA(rate1l), 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(RT_AR_DELTA(rate11s), 24) + | ATH9K_POW_SM(RT_AR_DELTA(rate11l), 16) + | ATH9K_POW_SM(RT_AR_DELTA(rate5_5s), 8) + | ATH9K_POW_SM(RT_AR_DELTA(rate5_5l), 0)); + } else { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); + } + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, + ATH9K_POW_SM(ratesArray[rateHt20_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, + ATH9K_POW_SM(ratesArray[rateHt20_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); + + if (IS_CHAN_HT40(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0] + + ht40PowerIncForPdadc, 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4] + + ht40PowerIncForPdadc, 0)); + if (OLC_FOR_AR9280_20_LATER) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(RT_AR_DELTA(rateExtCck), 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(RT_AR_DELTA(rateDupCck), 0)); + } else { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(ratesArray[rateExtCck], 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); + } + } + + REG_WRITE(ah, AR_PHY_POWER_TX_SUB, + ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) + | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); + + i = rate6mb; + + if (IS_CHAN_HT40(chan)) + i = rateHt40_0; + else if (IS_CHAN_HT20(chan)) + i = rateHt20_0; + + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->regulatory.max_power_level = + ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; + else + ah->regulatory.max_power_level = ratesArray[i]; + + switch(ar5416_get_ntxchains(ah->txchainmask)) { + case 1: + break; + case 2: + ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; + break; + case 3: + ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Invalid chainmask configuration\n"); + break; + } +} + +static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah, + enum ieee80211_band freq_band) +{ + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + struct modal_eep_header *pModal = + &(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]); + struct base_eep_header *pBase = &eep->baseEepHeader; + u8 num_ant_config; + + num_ant_config = 1; + + if (pBase->version >= 0x0E0D) + if (pModal->useAnt1) + num_ant_config += 1; + + return num_ant_config; +} + +static u16 ath9k_hw_def_get_eeprom_antenna_cfg(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + struct modal_eep_header *pModal = + &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + + return pModal->antCtrlCommon & 0xFFFF; +} + +static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) +{ +#define EEP_DEF_SPURCHAN \ + (ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan) + + u16 spur_val = AR_NO_SPUR; + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur idx %d is2Ghz. %d val %x\n", + i, is2GHz, ah->config.spurchans[i][is2GHz]); + + switch (ah->config.spurmode) { + case SPUR_DISABLE: + break; + case SPUR_ENABLE_IOCTL: + spur_val = ah->config.spurchans[i][is2GHz]; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur val from new loc. %d\n", spur_val); + break; + case SPUR_ENABLE_EEPROM: + spur_val = EEP_DEF_SPURCHAN; + break; + } + + return spur_val; + +#undef EEP_DEF_SPURCHAN +} + +const struct eeprom_ops eep_def_ops = { + .check_eeprom = ath9k_hw_def_check_eeprom, + .get_eeprom = ath9k_hw_def_get_eeprom, + .fill_eeprom = ath9k_hw_def_fill_eeprom, + .get_eeprom_ver = ath9k_hw_def_get_eeprom_ver, + .get_eeprom_rev = ath9k_hw_def_get_eeprom_rev, + .get_num_ant_config = ath9k_hw_def_get_num_ant_config, + .get_eeprom_antenna_cfg = ath9k_hw_def_get_eeprom_antenna_cfg, + .set_board_values = ath9k_hw_def_set_board_values, + .set_addac = ath9k_hw_def_set_addac, + .set_txpower = ath9k_hw_def_set_txpower, + .get_spur_channel = ath9k_hw_def_get_spur_channel +}; -- cgit v1.2.3-18-g5258 From a37414a220990614de376a155e23dfed471efbdc Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:19 +0530 Subject: ath9k: Cleanup ath9k_hw_4k_set_gain() interface regChainOffset is always zero, remove it. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 111f4d72092..aafc6d33da7 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -844,13 +844,13 @@ static void ath9k_hw_4k_set_addac(struct ath_hw *ah, static void ath9k_hw_4k_set_gain(struct ath_hw *ah, struct modal_eep_4k_header *pModal, struct ar5416_eeprom_4k *eep, - u8 txRxAttenLocal, int regChainOffset) + u8 txRxAttenLocal) { - REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, + REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0, pModal->antCtrlChain[0]); - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, - (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), + (REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | @@ -860,14 +860,14 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah, AR5416_EEP_MINOR_VER_3) { txRxAttenLocal = pModal->txRxAttenCh[0]; - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, pModal->xatten2Margin[0]); - REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); /* Set the block 1 value to block 0 value */ @@ -884,9 +884,9 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah, pModal->xatten2Db[0]); } - REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + REG_RMW_FIELD(ah, AR_PHY_RXGAIN, AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); - REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + REG_RMW_FIELD(ah, AR_PHY_RXGAIN, AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, @@ -919,7 +919,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); /* Single chain for 4K EEPROM*/ - ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0); + ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal); /* Initialize Ant Diversity settings from EEPROM */ if (pModal->version >= 3) { -- cgit v1.2.3-18-g5258 From 066edc80ebd9e429d593dcfe97b3ed01c9823847 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:21 +0530 Subject: ath9k: Add macros for Antenna Diversity A subsequent patch would use these for configuring antennae on AR9285. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/phy.h | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index 27bd93c6e74..5317e0503f6 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -312,7 +312,25 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, #define AR_PHY_NEW_ADC_DC_GAIN_CORR(_i) (0x99b4 + ((_i) << 12)) #define AR_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000 #define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000 -#define AR_PHY_MULTICHAIN_GAIN_CTL 0x99ac + +#define AR_PHY_MULTICHAIN_GAIN_CTL 0x99ac +#define AR_PHY_9285_ANT_DIV_CTL_ALL 0x7f000000 +#define AR_PHY_9285_ANT_DIV_CTL 0x01000000 +#define AR_PHY_9285_ANT_DIV_CTL_S 24 +#define AR_PHY_9285_ANT_DIV_ALT_LNACONF 0x06000000 +#define AR_PHY_9285_ANT_DIV_ALT_LNACONF_S 25 +#define AR_PHY_9285_ANT_DIV_MAIN_LNACONF 0x18000000 +#define AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S 27 +#define AR_PHY_9285_ANT_DIV_ALT_GAINTB 0x20000000 +#define AR_PHY_9285_ANT_DIV_ALT_GAINTB_S 29 +#define AR_PHY_9285_ANT_DIV_MAIN_GAINTB 0x40000000 +#define AR_PHY_9285_ANT_DIV_MAIN_GAINTB_S 30 +#define AR_PHY_9285_ANT_DIV_LNA1 2 +#define AR_PHY_9285_ANT_DIV_LNA2 1 +#define AR_PHY_9285_ANT_DIV_LNA1_PLUS_LNA2 3 +#define AR_PHY_9285_ANT_DIV_LNA1_MINUS_LNA2 0 +#define AR_PHY_9285_ANT_DIV_GAINTB_0 0 +#define AR_PHY_9285_ANT_DIV_GAINTB_1 1 #define AR_PHY_EXT_CCA0 0x99b8 #define AR_PHY_EXT_CCA0_THRESH62 0x000000FF -- cgit v1.2.3-18-g5258 From 7f63845f2a5f54c64968a4221561c619468b8a54 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:23 +0530 Subject: ath9k: Clean antenna configuration for 4K EEPROM chips This patch revamps the antenna configuration mechanism for 4K chips. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom.h | 33 +++++++-- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 103 ++++++++++++++++------------- drivers/net/wireless/ath/ath9k/phy.h | 1 + 3 files changed, 84 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 7d825b6d9c8..4fe33f7eee9 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -404,8 +404,13 @@ struct modal_eep_4k_header { u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS]; u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS]; u8 pdGainOverlap; - u8 ob_01; - u8 db1_01; +#ifdef __BIG_ENDIAN_BITFIELD + u8 ob_1:4, ob_0:4; + u8 db1_1:4, db1_0:4; +#else + u8 ob_0:4, ob_1:4; + u8 db1_0:4, db1_1:4; +#endif u8 xpaBiasLvl; u8 txFrameToDataStart; u8 txFrameToPaOn; @@ -415,11 +420,27 @@ struct modal_eep_4k_header { u8 swSettleHt40; u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS]; u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS]; - u8 db2_01; +#ifdef __BIG_ENDIAN_BITFIELD + u8 db2_1:4, db2_0:4; +#else + u8 db2_0:4, db2_1:4; +#endif u8 version; - u16 ob_234; - u16 db1_234; - u16 db2_234; +#ifdef __BIG_ENDIAN_BITFIELD + u8 ob_3:4, ob_2:4; + u8 antdiv_ctl1:4, ob_4:4; + u8 db1_3:4, db1_2:4; + u8 antdiv_ctl2:4, db1_4:4; + u8 db2_2:4, db2_3:4; + u8 reserved:4, db2_4:4; +#else + u8 ob_2:4, ob_3:4; + u8 ob_4:4, antdiv_ctl1:4; + u8 db1_2:4, db1_3:4; + u8 db1_4:4, antdiv_ctl2:4; + u8 db2_2:4, db2_3:4; + u8 db2_4:4, reserved:4; +#endif u8 futureModal[4]; struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; } __packed; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index aafc6d33da7..c9636159b8f 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -197,9 +197,9 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, case EEP_RF_SILENT: return pBase->rfSilent; case EEP_OB_2: - return pModal->ob_01; + return pModal->ob_0; case EEP_DB_2: - return pModal->db1_01; + return pModal->db1_1; case EEP_MINOR_REV: return pBase->version & AR5416_EEP_VER_MINOR_MASK; case EEP_TX_MASK: @@ -923,58 +923,67 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, /* Initialize Ant Diversity settings from EEPROM */ if (pModal->version >= 3) { - ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf); - ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf); - regVal = REG_READ(ah, 0x99ac); - regVal &= (~(0x7f000000)); - regVal |= ((ant_div_control1 & 0x1) << 24); - regVal |= (((ant_div_control1 >> 1) & 0x1) << 29); - regVal |= (((ant_div_control1 >> 2) & 0x1) << 30); - regVal |= ((ant_div_control2 & 0x3) << 25); - regVal |= (((ant_div_control2 >> 2) & 0x3) << 27); - REG_WRITE(ah, 0x99ac, regVal); - regVal = REG_READ(ah, 0x99ac); - regVal = REG_READ(ah, 0xa208); - regVal &= (~(0x1 << 13)); - regVal |= (((ant_div_control1 >> 3) & 0x1) << 13); - REG_WRITE(ah, 0xa208, regVal); - regVal = REG_READ(ah, 0xa208); + ant_div_control1 = pModal->antdiv_ctl1; + ant_div_control2 = pModal->antdiv_ctl2; + + regVal = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL); + regVal &= (~(AR_PHY_9285_ANT_DIV_CTL_ALL)); + + regVal |= SM(ant_div_control1, + AR_PHY_9285_ANT_DIV_CTL); + regVal |= SM(ant_div_control2, + AR_PHY_9285_ANT_DIV_ALT_LNACONF); + regVal |= SM((ant_div_control2 >> 2), + AR_PHY_9285_ANT_DIV_MAIN_LNACONF); + regVal |= SM((ant_div_control1 >> 1), + AR_PHY_9285_ANT_DIV_ALT_GAINTB); + regVal |= SM((ant_div_control1 >> 2), + AR_PHY_9285_ANT_DIV_MAIN_GAINTB); + + + REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal); + regVal = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL); + regVal = REG_READ(ah, AR_PHY_CCK_DETECT); + regVal &= (~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); + regVal |= SM((ant_div_control1 >> 3), + AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); + + REG_WRITE(ah, AR_PHY_CCK_DETECT, regVal); + regVal = REG_READ(ah, AR_PHY_CCK_DETECT); } if (pModal->version >= 2) { - ob[0] = (pModal->ob_01 & 0xf); - ob[1] = (pModal->ob_01 >> 4) & 0xf; - ob[2] = (pModal->ob_234 & 0xf); - ob[3] = ((pModal->ob_234 >> 4) & 0xf); - ob[4] = ((pModal->ob_234 >> 8) & 0xf); - - db1[0] = (pModal->db1_01 & 0xf); - db1[1] = ((pModal->db1_01 >> 4) & 0xf); - db1[2] = (pModal->db1_234 & 0xf); - db1[3] = ((pModal->db1_234 >> 4) & 0xf); - db1[4] = ((pModal->db1_234 >> 8) & 0xf); - - db2[0] = (pModal->db2_01 & 0xf); - db2[1] = ((pModal->db2_01 >> 4) & 0xf); - db2[2] = (pModal->db2_234 & 0xf); - db2[3] = ((pModal->db2_234 >> 4) & 0xf); - db2[4] = ((pModal->db2_234 >> 8) & 0xf); - + ob[0] = pModal->ob_0; + ob[1] = pModal->ob_1; + ob[2] = pModal->ob_2; + ob[3] = pModal->ob_3; + ob[4] = pModal->ob_4; + + db1[0] = pModal->db1_0; + db1[1] = pModal->db1_1; + db1[2] = pModal->db1_2; + db1[3] = pModal->db1_3; + db1[4] = pModal->db1_4; + + db2[0] = pModal->db2_0; + db2[1] = pModal->db2_1; + db2[2] = pModal->db2_2; + db2[3] = pModal->db2_3; + db2[4] = pModal->db2_4; } else if (pModal->version == 1) { - ob[0] = (pModal->ob_01 & 0xf); - ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf; - db1[0] = (pModal->db1_01 & 0xf); - db1[1] = db1[2] = db1[3] = - db1[4] = ((pModal->db1_01 >> 4) & 0xf); - db2[0] = (pModal->db2_01 & 0xf); - db2[1] = db2[2] = db2[3] = - db2[4] = ((pModal->db2_01 >> 4) & 0xf); + ob[0] = pModal->ob_0; + ob[1] = ob[2] = ob[3] = ob[4] = pModal->ob_1; + db1[0] = pModal->db1_0; + db1[1] = db1[2] = db1[3] = db1[4] = pModal->db1_1; + db2[0] = pModal->db2_0; + db2[1] = db2[2] = db2[3] = db2[4] = pModal->db2_1; } else { int i; + for (i = 0; i < 5; i++) { - ob[i] = pModal->ob_01; - db1[i] = pModal->db1_01; - db2[i] = pModal->db1_01; + ob[i] = pModal->ob_0; + db1[i] = pModal->db1_0; + db2[i] = pModal->db1_0; } } diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index 5317e0503f6..e83cd4ab87f 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -419,6 +419,7 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, #define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME 0x00001FC0 #define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME_S 6 #define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV 0x2000 +#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV_S 13 #define AR_PHY_GAIN_2GHZ 0xA20C #define AR_PHY_GAIN_2GHZ_RXTX_MARGIN 0x00FC0000 -- cgit v1.2.3-18-g5258 From bf466fb67c8e0559ba1875232b03ee8dee32ae09 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:30 +0530 Subject: ath9k: Cleanup TX power calculation for 4K chips Write CCK power-per-rate array always and report correct TX power to regulatory. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 72 +++++++++++++++--------------- 1 file changed, 35 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index c9636159b8f..29878e0789b 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -703,11 +703,11 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, } static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, - struct ath9k_channel *chan, - u16 cfgCtl, - u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) { struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; struct modal_eep_4k_header *pModal = &pEepData->modalHeader; @@ -724,10 +724,10 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, } ath9k_hw_set_4k_power_per_rate_table(ah, chan, - &ratesArray[0], cfgCtl, - twiceAntennaReduction, - twiceMaxRegulatoryPower, - powerLimit); + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit); ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset); @@ -737,11 +737,23 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, ratesArray[i] = AR5416_MAX_RATE_POWER; } + + /* Update regulatory */ + + i = rate6mb; + if (IS_CHAN_HT40(chan)) + i = rateHt40_0; + else if (IS_CHAN_HT20(chan)) + i = rateHt20_0; + + ah->regulatory.max_power_level = ratesArray[i]; + if (AR_SREV_9280_10_OR_LATER(ah)) { for (i = 0; i < Ar5416RateSize; i++) ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; } + /* OFDM power per rate */ REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, ATH9K_POW_SM(ratesArray[rate18mb], 24) | ATH9K_POW_SM(ratesArray[rate12mb], 16) @@ -753,19 +765,19 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, | ATH9K_POW_SM(ratesArray[rate36mb], 8) | ATH9K_POW_SM(ratesArray[rate24mb], 0)); - if (IS_CHAN_2GHZ(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, - ATH9K_POW_SM(ratesArray[rate2s], 24) - | ATH9K_POW_SM(ratesArray[rate2l], 16) - | ATH9K_POW_SM(ratesArray[rateXr], 8) - | ATH9K_POW_SM(ratesArray[rate1l], 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, - ATH9K_POW_SM(ratesArray[rate11s], 24) - | ATH9K_POW_SM(ratesArray[rate11l], 16) - | ATH9K_POW_SM(ratesArray[rate5_5s], 8) - | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); - } - + /* CCK power per rate */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); + + /* HT20 power per rate */ REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, ATH9K_POW_SM(ratesArray[rateHt20_3], 24) | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) @@ -777,6 +789,7 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); + /* HT40 power per rate */ if (IS_CHAN_HT40(chan)) { REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, ATH9K_POW_SM(ratesArray[rateHt40_3] + @@ -796,27 +809,12 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, ht40PowerIncForPdadc, 8) | ATH9K_POW_SM(ratesArray[rateHt40_4] + ht40PowerIncForPdadc, 0)); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | ATH9K_POW_SM(ratesArray[rateExtCck], 16) | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); } - - i = rate6mb; - - if (IS_CHAN_HT40(chan)) - i = rateHt40_0; - else if (IS_CHAN_HT20(chan)) - i = rateHt20_0; - - if (AR_SREV_9280_10_OR_LATER(ah)) - ah->regulatory.max_power_level = - ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; - else - ah->regulatory.max_power_level = ratesArray[i]; - } static void ath9k_hw_4k_set_addac(struct ath_hw *ah, -- cgit v1.2.3-18-g5258 From 180d674bab10ce10747f7bc7214462da185431bd Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:33 +0530 Subject: ath9k: Remove local chainmask variable The chainmask can be obtained directly from ath_hw. Also, use a helper macro for comparing CTLs - this improves readability. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 86 +++++++++++++++--------------- 1 file changed, 42 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 29878e0789b..d34dd23e806 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -502,14 +502,23 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, u16 twiceMaxRegulatoryPower, u16 powerLimit) { - struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; - u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - static const u16 tpScaleReductionTable[5] = - { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; +#define CMP_TEST_GRP \ + (((cfgCtl & ~CTL_MODE_M)| (pCtlMode[ctlMode] & CTL_MODE_M)) == \ + pEepData->ctlIndex[i]) \ + || (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \ + ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL)) int i; int16_t twiceLargestAntenna; + u16 twiceMinEdgePower; + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 numCtlModes, *pCtlMode, ctlMode, freq; + struct chan_centers centers; struct cal_ctl_data_4k *rep; + struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; + static const u16 tpScaleReductionTable[5] = + { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { 0, { 0, 0, 0, 0} }; @@ -520,27 +529,18 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { 0, {0, 0, 0, 0} }; - u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; u16 ctlModesFor11g[] = { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40 }; - u16 numCtlModes, *pCtlMode, ctlMode, freq; - struct chan_centers centers; - int tx_chainmask; - u16 twiceMinEdgePower; - - tx_chainmask = ah->txchainmask; ath9k_hw_get_channel_centers(ah, chan, ¢ers); twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0]; - twiceLargestAntenna = (int16_t)min(AntennaReduction - twiceLargestAntenna, 0); maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { maxRegAllowedPower -= (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); @@ -584,6 +584,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) freq = centers.synth_center; else if (pCtlMode[ctlMode] & EXT_ADDITIVE) @@ -596,22 +597,17 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, twiceMaxEdgePower = AR5416_MAX_RATE_POWER; for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) && - pEepData->ctlIndex[i]; i++) { - if ((((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - pEepData->ctlIndex[i]) || - (((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - ((pEepData->ctlIndex[i] & CTL_MODE_M) | - SD_NO_CTL))) { + pEepData->ctlIndex[i]; i++) { + + if (CMP_TEST_GRP) { rep = &(pEepData->ctlData[i]); - twiceMinEdgePower = - ath9k_hw_get_max_edge_power(freq, - rep->ctlEdges[ar5416_get_ntxchains - (tx_chainmask) - 1], - IS_CHAN_2GHZ(chan), - AR5416_EEP4K_NUM_BAND_EDGES); + twiceMinEdgePower = ath9k_hw_get_max_edge_power( + freq, + rep->ctlEdges[ + ar5416_get_ntxchains(ah->txchainmask) - 1], + IS_CHAN_2GHZ(chan), + AR5416_EEP4K_NUM_BAND_EDGES); if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { twiceMaxEdgePower = @@ -628,42 +624,38 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, switch (pCtlMode[ctlMode]) { case CTL_11B: - for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); - i++) { + for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { targetPowerCck.tPow2x[i] = min((u16)targetPowerCck.tPow2x[i], minCtlPower); } break; case CTL_11G: - for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); - i++) { + for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { targetPowerOfdm.tPow2x[i] = min((u16)targetPowerOfdm.tPow2x[i], minCtlPower); } break; case CTL_2GHT20: - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); - i++) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { targetPowerHt20.tPow2x[i] = min((u16)targetPowerHt20.tPow2x[i], minCtlPower); } break; case CTL_11B_EXT: - targetPowerCckExt.tPow2x[0] = min((u16) - targetPowerCckExt.tPow2x[0], - minCtlPower); + targetPowerCckExt.tPow2x[0] = + min((u16)targetPowerCckExt.tPow2x[0], + minCtlPower); break; case CTL_11G_EXT: - targetPowerOfdmExt.tPow2x[0] = min((u16) - targetPowerOfdmExt.tPow2x[0], - minCtlPower); + targetPowerOfdmExt.tPow2x[0] = + min((u16)targetPowerOfdmExt.tPow2x[0], + minCtlPower); break; case CTL_2GHT40: - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); - i++) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { targetPowerHt40.tPow2x[i] = min((u16)targetPowerHt40.tPow2x[i], minCtlPower); @@ -674,9 +666,13 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, } } - ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = - ratesArray[rate18mb] = ratesArray[rate24mb] = - targetPowerOfdm.tPow2x[0]; + ratesArray[rate6mb] = + ratesArray[rate9mb] = + ratesArray[rate12mb] = + ratesArray[rate18mb] = + ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; @@ -700,6 +696,8 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; } + +#undef CMP_TEST_GRP } static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, -- cgit v1.2.3-18-g5258 From 5e32b1ed7e81558b09bf0a6bf9e73c34db3c337c Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 7 Aug 2009 09:45:36 +0530 Subject: ath9k: Update beacon RSSI ANI uses the beacon RSSI for its operation. Update this properly. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index f6a8b1c384e..1a08c694fe5 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -252,6 +252,10 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, else if (ds->ds_rxstat.rs_rssi > 127) ds->ds_rxstat.rs_rssi = 127; + /* Update Beacon RSSI, this is used by ANI. */ + if (ieee80211_is_beacon(fc)) + sc->nodestats.ns_avgbrssi = ds->ds_rxstat.rs_rssi; + rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); rx_status->band = hw->conf.channel->band; rx_status->freq = hw->conf.channel->center_freq; -- cgit v1.2.3-18-g5258 From b8010790c480f495520fd458197f86d758f0c83a Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:32:48 +0300 Subject: wl1251: remove fixed address support from spi commands The fixed addresses are not used in wl1251, only in wl1271. So it can be safely removed. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_spi.c | 26 ++++++++------------------ drivers/net/wireless/wl12xx/wl1251_spi.h | 18 ++++++------------ 2 files changed, 14 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index c5da79dbc49..c2b813f5184 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -255,8 +255,7 @@ int wl1251_set_partition(struct wl1251 *wl, return 0; } -void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, - size_t len, bool fixed) +void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, size_t len) { struct spi_transfer t[3]; struct spi_message m; @@ -271,9 +270,6 @@ void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; *cmd |= addr & WSPI_CMD_BYTE_ADDR; - if (fixed) - *cmd |= WSPI_CMD_FIXED; - spi_message_init(&m); memset(t, 0, sizeof(t)); @@ -298,8 +294,7 @@ void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); } -void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, - size_t len, bool fixed) +void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, size_t len) { struct spi_transfer t[2]; struct spi_message m; @@ -312,9 +307,6 @@ void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; *cmd |= addr & WSPI_CMD_BYTE_ADDR; - if (fixed) - *cmd |= WSPI_CMD_FIXED; - spi_message_init(&m); memset(t, 0, sizeof(t)); @@ -339,7 +331,7 @@ void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf, physical = wl1251_translate_mem_addr(wl, addr); - wl1251_spi_read(wl, physical, buf, len, false); + wl1251_spi_read(wl, physical, buf, len); } void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf, @@ -349,27 +341,25 @@ void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf, physical = wl1251_translate_mem_addr(wl, addr); - wl1251_spi_write(wl, physical, buf, len, false); + wl1251_spi_write(wl, physical, buf, len); } -void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len, - bool fixed) +void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len) { int physical; physical = wl1251_translate_reg_addr(wl, addr); - wl1251_spi_read(wl, physical, buf, len, fixed); + wl1251_spi_read(wl, physical, buf, len); } -void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len, - bool fixed) +void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len) { int physical; physical = wl1251_translate_reg_addr(wl, addr); - wl1251_spi_write(wl, physical, buf, len, fixed); + wl1251_spi_write(wl, physical, buf, len); } u32 wl1251_mem_read32(struct wl1251 *wl, int addr) diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h index 6e8daf4e108..70763528db2 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.h +++ b/drivers/net/wireless/wl12xx/wl1251_spi.h @@ -71,10 +71,8 @@ /* Raw target IO, address is not translated */ -void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, - size_t len, bool fixed); -void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, - size_t len, bool fixed); +void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, size_t len); +void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, size_t len); /* Memory target IO, address is tranlated to partition 0 */ void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len); @@ -83,10 +81,8 @@ u32 wl1251_mem_read32(struct wl1251 *wl, int addr); void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val); /* Registers IO */ -void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len, - bool fixed); -void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len, - bool fixed); +void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len); +void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len); u32 wl1251_reg_read32(struct wl1251 *wl, int addr); void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val); @@ -99,8 +95,7 @@ int wl1251_set_partition(struct wl1251 *wl, static inline u32 wl1251_read32(struct wl1251 *wl, int addr) { - wl1251_spi_read(wl, addr, &wl->buffer_32, - sizeof(wl->buffer_32), false); + wl1251_spi_read(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32)); return wl->buffer_32; } @@ -108,8 +103,7 @@ static inline u32 wl1251_read32(struct wl1251 *wl, int addr) static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) { wl->buffer_32 = val; - wl1251_spi_write(wl, addr, &wl->buffer_32, - sizeof(wl->buffer_32), false); + wl1251_spi_write(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32)); } #endif /* __WL1251_SPI_H__ */ -- cgit v1.2.3-18-g5258 From 0764de64c8628f653c7e8493017d6bd8d43f4e3b Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 7 Aug 2009 13:32:56 +0300 Subject: wl1251: separate bus i/o code into io.c In order to eventually support wl1251 spi and sdio interfaces, move the register and memory transfer functions to a common file. Also rename wl1251_spi_mem_{read,write} to indicate its common usage. We still use spi_read internally until SDIO interface is introduced so nothing functional should change here. Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/Makefile | 2 +- drivers/net/wireless/wl12xx/wl1251_acx.c | 2 +- drivers/net/wireless/wl12xx/wl1251_boot.c | 2 +- drivers/net/wireless/wl12xx/wl1251_cmd.c | 10 ++-- drivers/net/wireless/wl12xx/wl1251_event.c | 4 +- drivers/net/wireless/wl12xx/wl1251_io.c | 86 ++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1251_io.h | 54 +++++++++++++++++++ drivers/net/wireless/wl12xx/wl1251_main.c | 3 +- drivers/net/wireless/wl12xx/wl1251_ops.c | 6 +-- drivers/net/wireless/wl12xx/wl1251_ps.c | 3 +- drivers/net/wireless/wl12xx/wl1251_rx.c | 7 +-- drivers/net/wireless/wl12xx/wl1251_spi.c | 81 ---------------------------- drivers/net/wireless/wl12xx/wl1251_spi.h | 30 ----------- drivers/net/wireless/wl12xx/wl1251_tx.c | 61 ++++++++++----------- 14 files changed, 192 insertions(+), 159 deletions(-) create mode 100644 drivers/net/wireless/wl12xx/wl1251_io.c create mode 100644 drivers/net/wireless/wl12xx/wl1251_io.h (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index ecb88333365..a1a15cef735 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,7 +1,7 @@ wl1251-objs = wl1251_main.o wl1251_spi.o wl1251_event.o \ wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \ wl1251_acx.o wl1251_boot.o wl1251_init.o \ - wl1251_ops.o wl1251_debugfs.o + wl1251_ops.o wl1251_debugfs.o wl1251_io.o obj-$(CONFIG_WL1251) += wl1251.o wl1271-objs = wl1271_main.o wl1271_spi.o wl1271_cmd.o \ diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index a46c92a2952..2e3171a61b7 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -6,7 +6,7 @@ #include "wl1251.h" #include "reg.h" -#include "wl1251_spi.h" +#include "wl1251_cmd.h" #include "wl1251_ps.h" int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index d8a155dc2fa..5702398de16 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -25,7 +25,7 @@ #include "reg.h" #include "wl1251_boot.h" -#include "wl1251_spi.h" +#include "wl1251_io.h" #include "wl1251_event.h" static void wl1251_boot_enable_interrupts(struct wl1251 *wl) diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index dc04d1fc2ee..2c30c705908 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -6,7 +6,7 @@ #include "wl1251.h" #include "reg.h" -#include "wl1251_spi.h" +#include "wl1251_io.h" #include "wl1251_ps.h" #include "wl1251_acx.h" @@ -31,7 +31,7 @@ int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len) WARN_ON(len % 4 != 0); - wl1251_spi_mem_write(wl, wl->cmd_box_addr, buf, len); + wl1251_mem_write(wl, wl->cmd_box_addr, buf, len); wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); @@ -86,7 +86,7 @@ int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer) * The answer would be a wl1251_command, where the * parameter array contains the actual answer. */ - wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); + wl1251_mem_read(wl, wl->cmd_box_addr, buf, buf_len); cmd_answer = buf; @@ -125,7 +125,7 @@ int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len) } /* the interrogate command got in, we can read the answer */ - wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, len); + wl1251_mem_read(wl, wl->cmd_box_addr, buf, len); acx = buf; if (acx->cmd.status != CMD_STATUS_SUCCESS) @@ -379,7 +379,7 @@ int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, } /* the read command got in, we can now read the answer */ - wl1251_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); + wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); if (cmd->header.status != CMD_STATUS_SUCCESS) wl1251_error("error in read command result: %d", diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl12xx/wl1251_event.c index 1a0a0bc1a31..1b4f8d2850c 100644 --- a/drivers/net/wireless/wl12xx/wl1251_event.c +++ b/drivers/net/wireless/wl12xx/wl1251_event.c @@ -24,7 +24,7 @@ #include "wl1251.h" #include "reg.h" -#include "wl1251_spi.h" +#include "wl1251_io.h" #include "wl1251_event.h" #include "wl1251_ps.h" @@ -112,7 +112,7 @@ int wl1251_event_handle(struct wl1251 *wl, u8 mbox_num) return -EINVAL; /* first we read the mbox descriptor */ - wl1251_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, + wl1251_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, sizeof(struct event_mailbox)); /* process the descriptor */ diff --git a/drivers/net/wireless/wl12xx/wl1251_io.c b/drivers/net/wireless/wl12xx/wl1251_io.c new file mode 100644 index 00000000000..1fa26749af3 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_io.c @@ -0,0 +1,86 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl1251.h" +#include "reg.h" +#include "wl1251_io.h" + +static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) +{ + /* If the address is lower than REGISTERS_BASE, it means that this is + * a chip-specific register address, so look it up in the registers + * table */ + if (addr < REGISTERS_BASE) { + /* Make sure we don't go over the table */ + if (addr >= ACX_REG_TABLE_LEN) { + wl1251_error("address out of range (%d)", addr); + return -EINVAL; + } + addr = wl->chip.acx_reg_table[addr]; + } + + return addr - wl->physical_reg_addr + wl->virtual_reg_addr; +} + +static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr) +{ + return addr - wl->physical_mem_addr + wl->virtual_mem_addr; +} + +void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len) +{ + int physical; + + physical = wl1251_translate_mem_addr(wl, addr); + + wl1251_spi_read(wl, physical, buf, len); +} + +void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len) +{ + int physical; + + physical = wl1251_translate_mem_addr(wl, addr); + + wl1251_spi_write(wl, physical, buf, len); +} + +u32 wl1251_mem_read32(struct wl1251 *wl, int addr) +{ + return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr)); +} + +void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val) +{ + wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val); +} + +u32 wl1251_reg_read32(struct wl1251 *wl, int addr) +{ + return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr)); +} + +void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val) +{ + wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val); +} diff --git a/drivers/net/wireless/wl12xx/wl1251_io.h b/drivers/net/wireless/wl12xx/wl1251_io.h new file mode 100644 index 00000000000..e2bb9546fa6 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_io.h @@ -0,0 +1,54 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ +#ifndef __WL1251_IO_H__ +#define __WL1251_IO_H__ + +#include "wl1251.h" +#include "wl1251_spi.h" + +/* Raw target IO, address is not translated */ +void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, size_t len); +void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, size_t len); + +static inline u32 wl1251_read32(struct wl1251 *wl, int addr) +{ + u32 response; + + wl1251_spi_read(wl, addr, &response, sizeof(u32)); + + return response; +} + +static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) +{ + wl1251_spi_write(wl, addr, &val, sizeof(u32)); +} + +/* Memory target IO, address is translated to partition 0 */ +void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len); +void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len); +u32 wl1251_mem_read32(struct wl1251 *wl, int addr); +void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val); +/* Registers IO */ +u32 wl1251_reg_read32(struct wl1251 *wl, int addr); +void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val); + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index da4c688c46a..a858e4dc20e 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -35,6 +35,7 @@ #include "wl12xx_80211.h" #include "reg.h" #include "wl1251_ops.h" +#include "wl1251_io.h" #include "wl1251_spi.h" #include "wl1251_event.h" #include "wl1251_tx.h" @@ -877,7 +878,7 @@ static int wl1251_hw_scan(struct wl1251 *wl, u8 *ssid, size_t len, if (ret < 0) wl1251_error("SCAN failed"); - wl1251_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); + wl1251_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); if (params->header.status != CMD_STATUS_SUCCESS) { wl1251_error("TEST command answer error: %d", diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.c b/drivers/net/wireless/wl12xx/wl1251_ops.c index e7b9aab3682..506123f1c8f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ops.c +++ b/drivers/net/wireless/wl12xx/wl1251_ops.c @@ -26,7 +26,7 @@ #include "wl1251_ops.h" #include "reg.h" -#include "wl1251_spi.h" +#include "wl1251_io.h" #include "wl1251_boot.h" #include "wl1251_event.h" #include "wl1251_acx.h" @@ -130,7 +130,7 @@ static int wl1251_upload_firmware(struct wl1251 *wl) p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", p, addr); - wl1251_spi_mem_write(wl, addr, p, CHUNK_SIZE); + wl1251_mem_write(wl, addr, p, CHUNK_SIZE); chunk_num++; } @@ -140,7 +140,7 @@ static int wl1251_upload_firmware(struct wl1251 *wl) p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", fw_data_len % CHUNK_SIZE, p, addr); - wl1251_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); + wl1251_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); return 0; } diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c index 68ff7f1900e..05816778f3d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.c +++ b/drivers/net/wireless/wl12xx/wl1251_ps.c @@ -23,7 +23,8 @@ #include "reg.h" #include "wl1251_ps.h" -#include "wl1251_spi.h" +#include "wl1251_cmd.h" +#include "wl1251_io.h" #define WL1251_WAKEUP_TIMEOUT 2000 diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c index 0dbb483a097..af8187909c9 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.c +++ b/drivers/net/wireless/wl12xx/wl1251_rx.c @@ -27,8 +27,9 @@ #include "wl1251.h" #include "reg.h" -#include "wl1251_spi.h" +#include "wl1251_io.h" #include "wl1251_rx.h" +#include "wl1251_cmd.h" #include "wl1251_acx.h" static void wl1251_rx_header(struct wl1251 *wl, @@ -40,7 +41,7 @@ static void wl1251_rx_header(struct wl1251 *wl, if (wl->rx_current_buffer) rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; - wl1251_spi_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); + wl1251_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); } static void wl1251_rx_status(struct wl1251 *wl, @@ -136,7 +137,7 @@ static void wl1251_rx_body(struct wl1251 *wl, } rx_buffer = skb_put(skb, length); - wl1251_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); + wl1251_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); /* The actual lenght doesn't include the target's alignment */ skb->len = desc->length - PLCP_HEADER_LENGTH; diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index c2b813f5184..031a3bac95e 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -29,29 +29,6 @@ #include "reg.h" #include "wl1251_spi.h" -static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) -{ - /* If the address is lower than REGISTERS_BASE, it means that this is - * a chip-specific register address, so look it up in the registers - * table */ - if (addr < REGISTERS_BASE) { - /* Make sure we don't go over the table */ - if (addr >= ACX_REG_TABLE_LEN) { - wl1251_error("address out of range (%d)", addr); - return -EINVAL; - } - addr = wl->chip.acx_reg_table[addr]; - } - - return addr - wl->physical_reg_addr + wl->virtual_reg_addr; -} - -static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr) -{ - return addr - wl->physical_mem_addr + wl->virtual_mem_addr; -} - - void wl1251_spi_reset(struct wl1251 *wl) { u8 *cmd; @@ -323,61 +300,3 @@ void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, size_t len) wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); } - -void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf, - size_t len) -{ - int physical; - - physical = wl1251_translate_mem_addr(wl, addr); - - wl1251_spi_read(wl, physical, buf, len); -} - -void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf, - size_t len) -{ - int physical; - - physical = wl1251_translate_mem_addr(wl, addr); - - wl1251_spi_write(wl, physical, buf, len); -} - -void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len) -{ - int physical; - - physical = wl1251_translate_reg_addr(wl, addr); - - wl1251_spi_read(wl, physical, buf, len); -} - -void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len) -{ - int physical; - - physical = wl1251_translate_reg_addr(wl, addr); - - wl1251_spi_write(wl, physical, buf, len); -} - -u32 wl1251_mem_read32(struct wl1251 *wl, int addr) -{ - return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr)); -} - -void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val) -{ - wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val); -} - -u32 wl1251_reg_read32(struct wl1251 *wl, int addr) -{ - return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr)); -} - -void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val) -{ - wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val); -} diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h index 70763528db2..ca9a85118ec 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.h +++ b/drivers/net/wireless/wl12xx/wl1251_spi.h @@ -69,23 +69,6 @@ ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32)) #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 - -/* Raw target IO, address is not translated */ -void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, size_t len); -void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, size_t len); - -/* Memory target IO, address is tranlated to partition 0 */ -void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len); -void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len); -u32 wl1251_mem_read32(struct wl1251 *wl, int addr); -void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val); - -/* Registers IO */ -void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len); -void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len); -u32 wl1251_reg_read32(struct wl1251 *wl, int addr); -void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val); - /* INIT and RESET words */ void wl1251_spi_reset(struct wl1251 *wl); void wl1251_spi_init(struct wl1251 *wl); @@ -93,17 +76,4 @@ int wl1251_set_partition(struct wl1251 *wl, u32 part_start, u32 part_size, u32 reg_start, u32 reg_size); -static inline u32 wl1251_read32(struct wl1251 *wl, int addr) -{ - wl1251_spi_read(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32)); - - return wl->buffer_32; -} - -static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) -{ - wl->buffer_32 = val; - wl1251_spi_write(wl, addr, &wl->buffer_32, sizeof(wl->buffer_32)); -} - #endif /* __WL1251_SPI_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c index 2652a222383..7ddc9a34630 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c @@ -30,6 +30,7 @@ #include "wl1251_spi.h" #include "wl1251_tx.h" #include "wl1251_ps.h" +#include "wl1251_io.h" static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count) { @@ -235,7 +236,7 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb, else addr = wl->data_path->tx_packet_ring_addr; - wl1251_spi_mem_write(wl, addr, skb->data, len); + wl1251_mem_write(wl, addr, skb->data, len); wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x", tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate); @@ -451,7 +452,7 @@ void wl1251_tx_complete(struct wl1251 *wl) return; /* First we read the result */ - wl1251_spi_mem_read(wl, wl->data_path->tx_complete_addr, + wl1251_mem_read(wl, wl->data_path->tx_complete_addr, result, sizeof(result)); result_index = wl->next_tx_complete; @@ -482,41 +483,41 @@ void wl1251_tx_complete(struct wl1251 *wl) */ if (result_index > wl->next_tx_complete) { /* Only 1 write is needed */ - wl1251_spi_mem_write(wl, - wl->data_path->tx_complete_addr + - (wl->next_tx_complete * - sizeof(struct tx_result)), - &result[wl->next_tx_complete], - num_complete * - sizeof(struct tx_result)); + wl1251_mem_write(wl, + wl->data_path->tx_complete_addr + + (wl->next_tx_complete * + sizeof(struct tx_result)), + &result[wl->next_tx_complete], + num_complete * + sizeof(struct tx_result)); } else if (result_index < wl->next_tx_complete) { /* 2 writes are needed */ - wl1251_spi_mem_write(wl, - wl->data_path->tx_complete_addr + - (wl->next_tx_complete * - sizeof(struct tx_result)), - &result[wl->next_tx_complete], - (FW_TX_CMPLT_BLOCK_SIZE - - wl->next_tx_complete) * - sizeof(struct tx_result)); - - wl1251_spi_mem_write(wl, - wl->data_path->tx_complete_addr, - result, - (num_complete - - FW_TX_CMPLT_BLOCK_SIZE + - wl->next_tx_complete) * - sizeof(struct tx_result)); + wl1251_mem_write(wl, + wl->data_path->tx_complete_addr + + (wl->next_tx_complete * + sizeof(struct tx_result)), + &result[wl->next_tx_complete], + (FW_TX_CMPLT_BLOCK_SIZE - + wl->next_tx_complete) * + sizeof(struct tx_result)); + + wl1251_mem_write(wl, + wl->data_path->tx_complete_addr, + result, + (num_complete - + FW_TX_CMPLT_BLOCK_SIZE + + wl->next_tx_complete) * + sizeof(struct tx_result)); } else { /* We have to write the whole array */ - wl1251_spi_mem_write(wl, - wl->data_path->tx_complete_addr, - result, - FW_TX_CMPLT_BLOCK_SIZE * - sizeof(struct tx_result)); + wl1251_mem_write(wl, + wl->data_path->tx_complete_addr, + result, + FW_TX_CMPLT_BLOCK_SIZE * + sizeof(struct tx_result)); } } -- cgit v1.2.3-18-g5258 From 6c766f413c81d5a11588552934fa093eab6ae06e Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 7 Aug 2009 13:33:04 +0300 Subject: wl1251: use wiphy_dev instead of wl->spi->dev Remove a dependency on the bus-specific struct device by using wiphy_dev when requesting firmware. Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index a858e4dc20e..953cdb4fd38 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -75,9 +75,10 @@ static irqreturn_t wl1251_irq(int irq, void *cookie) static int wl1251_fetch_firmware(struct wl1251 *wl) { const struct firmware *fw; + struct device *dev = wiphy_dev(wl->hw->wiphy); int ret; - ret = request_firmware(&fw, wl->chip.fw_filename, &wl->spi->dev); + ret = request_firmware(&fw, wl->chip.fw_filename, dev); if (ret < 0) { wl1251_error("could not get firmware: %d", ret); @@ -113,9 +114,10 @@ out: static int wl1251_fetch_nvs(struct wl1251 *wl) { const struct firmware *fw; + struct device *dev = wiphy_dev(wl->hw->wiphy); int ret; - ret = request_firmware(&fw, wl->chip.nvs_filename, &wl->spi->dev); + ret = request_firmware(&fw, wl->chip.nvs_filename, dev); if (ret < 0) { wl1251_error("could not get nvs file: %d", ret); -- cgit v1.2.3-18-g5258 From 08d9f57251841e4870cfd286e867ffcbef81d9a4 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 7 Aug 2009 13:33:11 +0300 Subject: wl1251: introduce wl1251_if_operations struct Introduce an ops struct with read, write, and reset functions to abstract away the details of the wl1251 bus interface. Doing this will allow SDIO to coexist with SPI by supplying its own I/O routines. Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251.h | 7 +++++++ drivers/net/wireless/wl12xx/wl1251_boot.c | 1 + drivers/net/wireless/wl12xx/wl1251_io.c | 4 ++-- drivers/net/wireless/wl12xx/wl1251_io.h | 9 ++------- drivers/net/wireless/wl12xx/wl1251_main.c | 6 ++++-- drivers/net/wireless/wl12xx/wl1251_ops.c | 1 + drivers/net/wireless/wl12xx/wl1251_spi.c | 23 +++++++++++++++++++---- drivers/net/wireless/wl12xx/wl1251_spi.h | 3 --- 8 files changed, 36 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index 665aca02bea..284bb508c87 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -281,11 +281,18 @@ struct wl1251_debugfs { struct dentry *excessive_retries; }; +struct wl1251_if_operations { + void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len); + void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len); + void (*reset)(struct wl1251 *wl); +}; + struct wl1251 { struct ieee80211_hw *hw; bool mac80211_registered; struct spi_device *spi; + struct wl1251_if_operations *if_ops; void (*set_power)(bool enable); int irq; diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index 5702398de16..5c6f32757ac 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -26,6 +26,7 @@ #include "reg.h" #include "wl1251_boot.h" #include "wl1251_io.h" +#include "wl1251_spi.h" #include "wl1251_event.h" static void wl1251_boot_enable_interrupts(struct wl1251 *wl) diff --git a/drivers/net/wireless/wl12xx/wl1251_io.c b/drivers/net/wireless/wl12xx/wl1251_io.c index 1fa26749af3..bc957858b9f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_io.c +++ b/drivers/net/wireless/wl12xx/wl1251_io.c @@ -53,7 +53,7 @@ void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len) physical = wl1251_translate_mem_addr(wl, addr); - wl1251_spi_read(wl, physical, buf, len); + wl->if_ops->read(wl, physical, buf, len); } void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len) @@ -62,7 +62,7 @@ void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len) physical = wl1251_translate_mem_addr(wl, addr); - wl1251_spi_write(wl, physical, buf, len); + wl->if_ops->write(wl, physical, buf, len); } u32 wl1251_mem_read32(struct wl1251 *wl, int addr) diff --git a/drivers/net/wireless/wl12xx/wl1251_io.h b/drivers/net/wireless/wl12xx/wl1251_io.h index e2bb9546fa6..1fa2ab18a9e 100644 --- a/drivers/net/wireless/wl12xx/wl1251_io.h +++ b/drivers/net/wireless/wl12xx/wl1251_io.h @@ -22,24 +22,19 @@ #define __WL1251_IO_H__ #include "wl1251.h" -#include "wl1251_spi.h" - -/* Raw target IO, address is not translated */ -void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, size_t len); -void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, size_t len); static inline u32 wl1251_read32(struct wl1251 *wl, int addr) { u32 response; - wl1251_spi_read(wl, addr, &response, sizeof(u32)); + wl->if_ops->read(wl, addr, &response, sizeof(u32)); return response; } static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) { - wl1251_spi_write(wl, addr, &val, sizeof(u32)); + wl->if_ops->write(wl, addr, &val, sizeof(u32)); } /* Memory target IO, address is translated to partition 0 */ diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 953cdb4fd38..0f30d0a62aa 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -168,8 +168,7 @@ static int wl1251_chip_wakeup(struct wl1251 *wl) wl1251_power_on(wl); msleep(wl->chip.power_on_sleep); - wl1251_spi_reset(wl); - wl1251_spi_init(wl); + wl->if_ops->reset(wl); /* We don't need a real memory partition here, because we only want * to use the registers at this point. */ @@ -1192,6 +1191,8 @@ static int wl1251_init_ieee80211(struct wl1251 *wl) return 0; } +extern struct wl1251_if_operations wl1251_spi_ops; + #define WL1251_DEFAULT_CHANNEL 1 static int __devinit wl1251_probe(struct spi_device *spi) { @@ -1219,6 +1220,7 @@ static int __devinit wl1251_probe(struct spi_device *spi) wl->hw = hw; dev_set_drvdata(&spi->dev, wl); wl->spi = spi; + wl->if_ops = &wl1251_spi_ops; wl->data_in_count = 0; diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.c b/drivers/net/wireless/wl12xx/wl1251_ops.c index 506123f1c8f..758280af10d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ops.c +++ b/drivers/net/wireless/wl12xx/wl1251_ops.c @@ -27,6 +27,7 @@ #include "wl1251_ops.h" #include "reg.h" #include "wl1251_io.h" +#include "wl1251_spi.h" #include "wl1251_boot.h" #include "wl1251_event.h" #include "wl1251_acx.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index 031a3bac95e..61a0852b4ee 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -29,7 +29,7 @@ #include "reg.h" #include "wl1251_spi.h" -void wl1251_spi_reset(struct wl1251 *wl) +static void wl1251_spi_reset(struct wl1251 *wl) { u8 *cmd; struct spi_transfer t; @@ -55,7 +55,7 @@ void wl1251_spi_reset(struct wl1251 *wl) wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); } -void wl1251_spi_init(struct wl1251 *wl) +static void wl1251_spi_init(struct wl1251 *wl) { u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; struct spi_transfer t; @@ -109,6 +109,13 @@ void wl1251_spi_init(struct wl1251 *wl) wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); } +static void wl1251_spi_reset_wake(struct wl1251 *wl) +{ + wl1251_spi_reset(wl); + wl1251_spi_init(wl); +} + + /* Set the SPI partitions to access the chip addresses * * There are two VIRTUAL (SPI) partitions (the memory partition and the @@ -232,7 +239,8 @@ int wl1251_set_partition(struct wl1251 *wl, return 0; } -void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, size_t len) +static void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, + size_t len) { struct spi_transfer t[3]; struct spi_message m; @@ -271,7 +279,8 @@ void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, size_t len) wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); } -void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, size_t len) +static void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, + size_t len) { struct spi_transfer t[2]; struct spi_message m; @@ -300,3 +309,9 @@ void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, size_t len) wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); } + +const struct wl1251_if_operations wl1251_spi_ops = { + .read = wl1251_spi_read, + .write = wl1251_spi_write, + .reset = wl1251_spi_reset_wake, +}; diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h index ca9a85118ec..7c6da21cb00 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.h +++ b/drivers/net/wireless/wl12xx/wl1251_spi.h @@ -69,9 +69,6 @@ ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32)) #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 -/* INIT and RESET words */ -void wl1251_spi_reset(struct wl1251 *wl); -void wl1251_spi_init(struct wl1251 *wl); int wl1251_set_partition(struct wl1251 *wl, u32 part_start, u32 part_size, u32 reg_start, u32 reg_size); -- cgit v1.2.3-18-g5258 From 0d77e141331b25adf190ce30d69fe5744a69c5bd Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 7 Aug 2009 13:33:18 +0300 Subject: wl1251: make wl1251_set_partition bus agnostic The same partition setting code can be used for both SPI and SDIO modes, if we remove the spi-specific commands and use the more generic buffer write routines. Do that and move it to io.c since it deals with register/memory address offsets. Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_io.c | 95 +++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1251_io.h | 15 ++++ drivers/net/wireless/wl12xx/wl1251_spi.c | 124 ------------------------------- drivers/net/wireless/wl12xx/wl1251_spi.h | 15 ---- 4 files changed, 110 insertions(+), 139 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_io.c b/drivers/net/wireless/wl12xx/wl1251_io.c index bc957858b9f..db2cfbfb1e4 100644 --- a/drivers/net/wireless/wl12xx/wl1251_io.c +++ b/drivers/net/wireless/wl12xx/wl1251_io.c @@ -84,3 +84,98 @@ void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val) { wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val); } + +/* Set the partitions to access the chip addresses. + * + * There are two VIRTUAL partitions (the memory partition and the + * registers partition), which are mapped to two different areas of the + * PHYSICAL (hardware) memory. This function also makes other checks to + * ensure that the partitions are not overlapping. In the diagram below, the + * memory partition comes before the register partition, but the opposite is + * also supported. + * + * PHYSICAL address + * space + * + * | | + * ...+----+--> mem_start + * VIRTUAL address ... | | + * space ... | | [PART_0] + * ... | | + * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size + * | | ... | | + * |MEM | ... | | + * | | ... | | + * part_size <--+----+... | | {unused area) + * | | ... | | + * |REG | ... | | + * part_size | | ... | | + * + <--+----+... ...+----+--> reg_start + * reg_size ... | | + * ... | | [PART_1] + * ... | | + * ...+----+--> reg_start + reg_size + * | | + * + */ +void wl1251_set_partition(struct wl1251 *wl, + u32 mem_start, u32 mem_size, + u32 reg_start, u32 reg_size) +{ + struct wl1251_partition partition[2]; + + wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + + /* Make sure that the two partitions together don't exceed the + * address range */ + if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { + wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual" + " address range. Truncating partition[0]."); + mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; + wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } + + if ((mem_start < reg_start) && + ((mem_start + mem_size) > reg_start)) { + /* Guarantee that the memory partition doesn't overlap the + * registers partition */ + wl1251_debug(DEBUG_SPI, "End of partition[0] is " + "overlapping partition[1]. Adjusted."); + mem_size = reg_start - mem_start; + wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } else if ((reg_start < mem_start) && + ((reg_start + reg_size) > mem_start)) { + /* Guarantee that the register partition doesn't overlap the + * memory partition */ + wl1251_debug(DEBUG_SPI, "End of partition[1] is" + " overlapping partition[0]. Adjusted."); + reg_size = mem_start - reg_start; + wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } + + partition[0].start = mem_start; + partition[0].size = mem_size; + partition[1].start = reg_start; + partition[1].size = reg_size; + + wl->physical_mem_addr = mem_start; + wl->physical_reg_addr = reg_start; + + wl->virtual_mem_addr = 0; + wl->virtual_reg_addr = mem_size; + + wl->if_ops->write(wl, HW_ACCESS_PART0_SIZE_ADDR, partition, + sizeof(partition)); +} diff --git a/drivers/net/wireless/wl12xx/wl1251_io.h b/drivers/net/wireless/wl12xx/wl1251_io.h index 1fa2ab18a9e..b89d2ac62ef 100644 --- a/drivers/net/wireless/wl12xx/wl1251_io.h +++ b/drivers/net/wireless/wl12xx/wl1251_io.h @@ -23,6 +23,17 @@ #include "wl1251.h" +#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 + +#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 +#define HW_ACCESS_PART0_START_ADDR 0x1FFC4 +#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 +#define HW_ACCESS_PART1_START_ADDR 0x1FFCC + +#define HW_ACCESS_REGISTER_SIZE 4 + +#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 + static inline u32 wl1251_read32(struct wl1251 *wl, int addr) { u32 response; @@ -46,4 +57,8 @@ void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val); u32 wl1251_reg_read32(struct wl1251 *wl, int addr); void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val); +void wl1251_set_partition(struct wl1251 *wl, + u32 part_start, u32 part_size, + u32 reg_start, u32 reg_size); + #endif diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index 61a0852b4ee..ceb237b4e57 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -115,130 +115,6 @@ static void wl1251_spi_reset_wake(struct wl1251 *wl) wl1251_spi_init(wl); } - -/* Set the SPI partitions to access the chip addresses - * - * There are two VIRTUAL (SPI) partitions (the memory partition and the - * registers partition), which are mapped to two different areas of the - * PHYSICAL (hardware) memory. This function also makes other checks to - * ensure that the partitions are not overlapping. In the diagram below, the - * memory partition comes before the register partition, but the opposite is - * also supported. - * - * PHYSICAL address - * space - * - * | | - * ...+----+--> mem_start - * VIRTUAL address ... | | - * space ... | | [PART_0] - * ... | | - * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size - * | | ... | | - * |MEM | ... | | - * | | ... | | - * part_size <--+----+... | | {unused area) - * | | ... | | - * |REG | ... | | - * part_size | | ... | | - * + <--+----+... ...+----+--> reg_start - * reg_size ... | | - * ... | | [PART_1] - * ... | | - * ...+----+--> reg_start + reg_size - * | | - * - */ -int wl1251_set_partition(struct wl1251 *wl, - u32 mem_start, u32 mem_size, - u32 reg_start, u32 reg_size) -{ - struct wl1251_partition *partition; - struct spi_transfer t; - struct spi_message m; - size_t len, cmd_len; - u32 *cmd; - int addr; - - cmd_len = sizeof(u32) + 2 * sizeof(struct wl1251_partition); - cmd = kzalloc(cmd_len, GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - spi_message_init(&m); - memset(&t, 0, sizeof(t)); - - partition = (struct wl1251_partition *) (cmd + 1); - addr = HW_ACCESS_PART0_SIZE_ADDR; - len = 2 * sizeof(struct wl1251_partition); - - *cmd |= WSPI_CMD_WRITE; - *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - *cmd |= addr & WSPI_CMD_BYTE_ADDR; - - wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - - /* Make sure that the two partitions together don't exceed the - * address range */ - if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { - wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual" - " address range. Truncating partition[0]."); - mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; - wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } - - if ((mem_start < reg_start) && - ((mem_start + mem_size) > reg_start)) { - /* Guarantee that the memory partition doesn't overlap the - * registers partition */ - wl1251_debug(DEBUG_SPI, "End of partition[0] is " - "overlapping partition[1]. Adjusted."); - mem_size = reg_start - mem_start; - wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } else if ((reg_start < mem_start) && - ((reg_start + reg_size) > mem_start)) { - /* Guarantee that the register partition doesn't overlap the - * memory partition */ - wl1251_debug(DEBUG_SPI, "End of partition[1] is" - " overlapping partition[0]. Adjusted."); - reg_size = mem_start - reg_start; - wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } - - partition[0].start = mem_start; - partition[0].size = mem_size; - partition[1].start = reg_start; - partition[1].size = reg_size; - - wl->physical_mem_addr = mem_start; - wl->physical_reg_addr = reg_start; - - wl->virtual_mem_addr = 0; - wl->virtual_reg_addr = mem_size; - - t.tx_buf = cmd; - t.len = cmd_len; - spi_message_add_tail(&t, &m); - - spi_sync(wl->spi, &m); - - kfree(cmd); - - return 0; -} - static void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, size_t len) { diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h index 7c6da21cb00..cb0c228dbc6 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.h +++ b/drivers/net/wireless/wl12xx/wl1251_spi.h @@ -29,17 +29,6 @@ #include "wl1251_acx.h" #include "reg.h" -#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 - -#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 -#define HW_ACCESS_PART0_START_ADDR 0x1FFC4 -#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 -#define HW_ACCESS_PART1_START_ADDR 0x1FFCC - -#define HW_ACCESS_REGISTER_SIZE 4 - -#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 - #define WSPI_CMD_READ 0x40000000 #define WSPI_CMD_WRITE 0x00000000 #define WSPI_CMD_FIXED 0x20000000 @@ -69,8 +58,4 @@ ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32)) #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 -int wl1251_set_partition(struct wl1251 *wl, - u32 part_start, u32 part_size, - u32 reg_start, u32 reg_size); - #endif /* __WL1251_SPI_H__ */ -- cgit v1.2.3-18-g5258 From 8e639c0673a9b676bb7c6bd4e50f9003bdda423e Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 7 Aug 2009 13:33:26 +0300 Subject: wl1251: move module probe methods into spi.c This change moves all of the spi specific code from main.c into spi.c. The module initialization code also moves, but common code for initializing mac80211 etc. stays in main.c, as this will eventually form a common library module also used by wl1251_sdio. Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251.h | 7 +- drivers/net/wireless/wl12xx/wl1251_acx.c | 1 - drivers/net/wireless/wl12xx/wl1251_cmd.c | 1 - drivers/net/wireless/wl12xx/wl1251_main.c | 148 +++++------------------------- drivers/net/wireless/wl12xx/wl1251_spi.c | 125 ++++++++++++++++++++++++- drivers/net/wireless/wl12xx/wl1251_tx.c | 1 - 6 files changed, 151 insertions(+), 132 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index 284bb508c87..df4c06d4167 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -292,7 +292,7 @@ struct wl1251 { bool mac80211_registered; struct spi_device *spi; - struct wl1251_if_operations *if_ops; + const struct wl1251_if_operations *if_ops; void (*set_power)(bool enable); int irq; @@ -404,6 +404,11 @@ struct wl1251 { int wl1251_plt_start(struct wl1251 *wl); int wl1251_plt_stop(struct wl1251 *wl); +irqreturn_t wl1251_irq(int irq, void *cookie); +struct ieee80211_hw *wl1251_alloc_hw(void); +int wl1251_free_hw(struct wl1251 *wl); +int wl1251_init_ieee80211(struct wl1251 *wl); + #define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ #define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index 2e3171a61b7..91fe16c8d5b 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -2,7 +2,6 @@ #include #include -#include #include "wl1251.h" #include "reg.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index 2c30c705908..dfbf6811976 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -2,7 +2,6 @@ #include #include -#include #include "wl1251.h" #include "reg.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 0f30d0a62aa..74544e11f69 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -26,17 +26,15 @@ #include #include #include -#include #include #include -#include #include "wl1251.h" #include "wl12xx_80211.h" #include "reg.h" #include "wl1251_ops.h" #include "wl1251_io.h" -#include "wl1251_spi.h" +#include "wl1251_cmd.h" #include "wl1251_event.h" #include "wl1251_tx.h" #include "wl1251_rx.h" @@ -59,7 +57,7 @@ static void wl1251_power_on(struct wl1251 *wl) wl->set_power(true); } -static irqreturn_t wl1251_irq(int irq, void *cookie) +irqreturn_t wl1251_irq(int irq, void *cookie) { struct wl1251 *wl; @@ -1169,8 +1167,10 @@ static int wl1251_register_hw(struct wl1251 *wl) return 0; } -static int wl1251_init_ieee80211(struct wl1251 *wl) +int wl1251_init_ieee80211(struct wl1251 *wl) { + int ret; + /* The tx descriptor buffer and the TKIP space */ wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) + WL1251_TKIP_IV_SPACE; @@ -1186,41 +1186,37 @@ static int wl1251_init_ieee80211(struct wl1251 *wl) wl->hw->wiphy->max_scan_ssids = 1; wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; - SET_IEEE80211_DEV(wl->hw, &wl->spi->dev); + ret = wl1251_register_hw(wl); + if (ret) + goto out; - return 0; -} + wl1251_debugfs_init(wl); + wl1251_notice("initialized"); -extern struct wl1251_if_operations wl1251_spi_ops; + ret = 0; + +out: + return ret; +} #define WL1251_DEFAULT_CHANNEL 1 -static int __devinit wl1251_probe(struct spi_device *spi) +struct ieee80211_hw *wl1251_alloc_hw(void) { - struct wl12xx_platform_data *pdata; struct ieee80211_hw *hw; struct wl1251 *wl; - int ret, i; + int i; static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; - pdata = spi->dev.platform_data; - if (!pdata) { - wl1251_error("no platform data"); - return -ENODEV; - } - hw = ieee80211_alloc_hw(sizeof(*wl), &wl1251_ops); if (!hw) { wl1251_error("could not alloc ieee80211_hw"); - return -ENOMEM; + return ERR_PTR(-ENOMEM); } wl = hw->priv; memset(wl, 0, sizeof(*wl)); wl->hw = hw; - dev_set_drvdata(&spi->dev, wl); - wl->spi = spi; - wl->if_ops = &wl1251_spi_ops; wl->data_in_count = 0; @@ -1268,74 +1264,15 @@ static int __devinit wl1251_probe(struct spi_device *spi) wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); if (!wl->rx_descriptor) { wl1251_error("could not allocate memory for rx descriptor"); - ret = -ENOMEM; - goto out_free; + ieee80211_free_hw(hw); + return ERR_PTR(-ENOMEM); } - /* This is the only SPI value that we need to set here, the rest - * comes from the board-peripherals file */ - spi->bits_per_word = 32; - - ret = spi_setup(spi); - if (ret < 0) { - wl1251_error("spi_setup failed"); - goto out_free; - } - - wl->set_power = pdata->set_power; - if (!wl->set_power) { - wl1251_error("set power function missing in platform data"); - ret = -ENODEV; - goto out_free; - } - - wl->irq = spi->irq; - if (wl->irq < 0) { - wl1251_error("irq missing in platform data"); - ret = -ENODEV; - goto out_free; - } - - ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); - if (ret < 0) { - wl1251_error("request_irq() failed: %d", ret); - goto out_free; - } - - set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); - - disable_irq(wl->irq); - - ret = wl1251_init_ieee80211(wl); - if (ret) - goto out_irq; - - ret = wl1251_register_hw(wl); - if (ret) - goto out_irq; - - wl1251_debugfs_init(wl); - - wl1251_notice("initialized"); - - return 0; - - out_irq: - free_irq(wl->irq, wl); - - out_free: - kfree(wl->rx_descriptor); - wl->rx_descriptor = NULL; - - ieee80211_free_hw(hw); - - return ret; + return hw; } -static int __devexit wl1251_remove(struct spi_device *spi) +int wl1251_free_hw(struct wl1251 *wl) { - struct wl1251 *wl = dev_get_drvdata(&spi->dev); - ieee80211_unregister_hw(wl->hw); wl1251_debugfs_exit(wl); @@ -1355,44 +1292,3 @@ static int __devexit wl1251_remove(struct spi_device *spi) return 0; } - - -static struct spi_driver wl1251_spi_driver = { - .driver = { - /* FIXME: use wl12xx name to not break the user space */ - .name = "wl12xx", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - }, - - .probe = wl1251_probe, - .remove = __devexit_p(wl1251_remove), -}; - -static int __init wl1251_init(void) -{ - int ret; - - ret = spi_register_driver(&wl1251_spi_driver); - if (ret < 0) { - wl1251_error("failed to register spi driver: %d", ret); - goto out; - } - -out: - return ret; -} - -static void __exit wl1251_exit(void) -{ - spi_unregister_driver(&wl1251_spi_driver); - - wl1251_notice("unloaded"); -} - -module_init(wl1251_init); -module_exit(wl1251_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kalle Valo , " - "Luciano Coelho "); diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index ceb237b4e57..13e7a726dea 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -21,9 +21,11 @@ * */ +#include #include #include #include +#include #include "wl1251.h" #include "reg.h" @@ -55,7 +57,7 @@ static void wl1251_spi_reset(struct wl1251 *wl) wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); } -static void wl1251_spi_init(struct wl1251 *wl) +static void wl1251_spi_wake(struct wl1251 *wl) { u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; struct spi_transfer t; @@ -112,7 +114,7 @@ static void wl1251_spi_init(struct wl1251 *wl) static void wl1251_spi_reset_wake(struct wl1251 *wl) { wl1251_spi_reset(wl); - wl1251_spi_init(wl); + wl1251_spi_wake(wl); } static void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, @@ -191,3 +193,122 @@ const struct wl1251_if_operations wl1251_spi_ops = { .write = wl1251_spi_write, .reset = wl1251_spi_reset_wake, }; + +static int __devinit wl1251_spi_probe(struct spi_device *spi) +{ + struct wl12xx_platform_data *pdata; + struct ieee80211_hw *hw; + struct wl1251 *wl; + int ret; + + pdata = spi->dev.platform_data; + if (!pdata) { + wl1251_error("no platform data"); + return -ENODEV; + } + + hw = wl1251_alloc_hw(); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + wl = hw->priv; + + SET_IEEE80211_DEV(hw, &spi->dev); + dev_set_drvdata(&spi->dev, wl); + wl->spi = spi; + wl->if_ops = &wl1251_spi_ops; + + /* This is the only SPI value that we need to set here, the rest + * comes from the board-peripherals file */ + spi->bits_per_word = 32; + + ret = spi_setup(spi); + if (ret < 0) { + wl1251_error("spi_setup failed"); + goto out_free; + } + + wl->set_power = pdata->set_power; + if (!wl->set_power) { + wl1251_error("set power function missing in platform data"); + return -ENODEV; + } + + wl->irq = spi->irq; + if (wl->irq < 0) { + wl1251_error("irq missing in platform data"); + return -ENODEV; + } + + ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); + if (ret < 0) { + wl1251_error("request_irq() failed: %d", ret); + goto out_free; + } + + set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); + + disable_irq(wl->irq); + + ret = wl1251_init_ieee80211(wl); + if (ret) + goto out_irq; + + return 0; + + out_irq: + free_irq(wl->irq, wl); + + out_free: + ieee80211_free_hw(hw); + + return ret; +} + +static int __devexit wl1251_spi_remove(struct spi_device *spi) +{ + struct wl1251 *wl = dev_get_drvdata(&spi->dev); + + wl1251_free_hw(wl); + + return 0; +} + +static struct spi_driver wl1251_spi_driver = { + .driver = { + .name = "wl12xx", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = wl1251_spi_probe, + .remove = __devexit_p(wl1251_spi_remove), +}; + +static int __init wl1251_spi_init(void) +{ + int ret; + + ret = spi_register_driver(&wl1251_spi_driver); + if (ret < 0) { + wl1251_error("failed to register spi driver: %d", ret); + goto out; + } + +out: + return ret; +} + +static void __exit wl1251_spi_exit(void) +{ + spi_unregister_driver(&wl1251_spi_driver); + + wl1251_notice("unloaded"); +} + +module_init(wl1251_spi_init); +module_exit(wl1251_spi_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kalle Valo "); +MODULE_AUTHOR("Luciano Coelho "); diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c index 7ddc9a34630..f20bab61fd6 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c @@ -27,7 +27,6 @@ #include "wl1251.h" #include "reg.h" -#include "wl1251_spi.h" #include "wl1251_tx.h" #include "wl1251_ps.h" #include "wl1251_io.h" -- cgit v1.2.3-18-g5258 From af8c78ebbf2a15ecf9b2b6b7b051b0d4c3ba1163 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 7 Aug 2009 13:33:34 +0300 Subject: wl1251: split spi interface into separate module This creates a module called wl1251_spi.ko which contains just the SPI-specific code. The core remains in the module wl1251.ko. Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/Kconfig | 17 ++++++++++++++--- drivers/net/wireless/wl12xx/Makefile | 4 +++- drivers/net/wireless/wl12xx/wl1251.h | 2 +- drivers/net/wireless/wl12xx/wl1251_main.c | 9 +++++++++ drivers/net/wireless/wl12xx/wl1251_spi.c | 17 +++++++++++------ 5 files changed, 38 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index af31eabad18..f8cb8b864ad 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -7,15 +7,26 @@ menuconfig WL12XX config WL1251 tristate "TI wl1251 support" - depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS + depends on WL12XX && GENERIC_HARDIRQS select FW_LOADER select CRC7 ---help--- This module adds support for wireless adapters based on TI wl1251 chipset. - If you choose to build a module, it'll be called wl1251. Say N if - unsure. + If you choose to build a module, it'll be called wl1251. Say + N if unsure. + +config WL1251_SPI + tristate "TI wl1251 SPI support" + depends on WL1251 && SPI_MASTER + ---help--- + This module adds support for the SPI interface of adapters using + TI wl1251 chipset. Select this if your platform is using + the SPI bus. + + If you choose to build a module, it'll be called wl1251_spi. + Say N if unsure. config WL1271 tristate "TI wl1271 support" diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index a1a15cef735..ea0477f1d1d 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,8 +1,10 @@ -wl1251-objs = wl1251_main.o wl1251_spi.o wl1251_event.o \ +wl1251-objs = wl1251_main.o wl1251_event.o \ wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \ wl1251_acx.o wl1251_boot.o wl1251_init.o \ wl1251_ops.o wl1251_debugfs.o wl1251_io.o + obj-$(CONFIG_WL1251) += wl1251.o +obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o wl1271-objs = wl1271_main.o wl1271_spi.o wl1271_cmd.o \ wl1271_event.o wl1271_tx.o wl1271_rx.o \ diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index df4c06d4167..ebe2c70559c 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -291,7 +291,7 @@ struct wl1251 { struct ieee80211_hw *hw; bool mac80211_registered; - struct spi_device *spi; + void *if_priv; const struct wl1251_if_operations *if_ops; void (*set_power)(bool enable); diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 74544e11f69..abe157a174c 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -69,6 +69,7 @@ irqreturn_t wl1251_irq(int irq, void *cookie) return IRQ_HANDLED; } +EXPORT_SYMBOL_GPL(wl1251_irq); static int wl1251_fetch_firmware(struct wl1251 *wl) { @@ -1198,6 +1199,7 @@ int wl1251_init_ieee80211(struct wl1251 *wl) out: return ret; } +EXPORT_SYMBOL_GPL(wl1251_init_ieee80211); #define WL1251_DEFAULT_CHANNEL 1 struct ieee80211_hw *wl1251_alloc_hw(void) @@ -1270,6 +1272,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void) return hw; } +EXPORT_SYMBOL_GPL(wl1251_alloc_hw); int wl1251_free_hw(struct wl1251 *wl) { @@ -1292,3 +1295,9 @@ int wl1251_free_hw(struct wl1251 *wl) return 0; } +EXPORT_SYMBOL_GPL(wl1251_free_hw); + +MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kalle Valo "); +MODULE_AUTHOR("Luciano Coelho "); diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index 13e7a726dea..5967317ef02 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -31,6 +31,11 @@ #include "reg.h" #include "wl1251_spi.h" +static struct spi_device *wl_to_spi(struct wl1251 *wl) +{ + return wl->if_priv; +} + static void wl1251_spi_reset(struct wl1251 *wl) { u8 *cmd; @@ -52,7 +57,7 @@ static void wl1251_spi_reset(struct wl1251 *wl) t.len = WSPI_INIT_CMD_LEN; spi_message_add_tail(&t, &m); - spi_sync(wl->spi, &m); + spi_sync(wl_to_spi(wl), &m); wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); } @@ -106,7 +111,7 @@ static void wl1251_spi_wake(struct wl1251 *wl) t.len = WSPI_INIT_CMD_LEN; spi_message_add_tail(&t, &m); - spi_sync(wl->spi, &m); + spi_sync(wl_to_spi(wl), &m); wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); } @@ -149,7 +154,7 @@ static void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, t[2].len = len; spi_message_add_tail(&t[2], &m); - spi_sync(wl->spi, &m); + spi_sync(wl_to_spi(wl), &m); /* FIXME: check busy words */ @@ -182,13 +187,13 @@ static void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, t[1].len = len; spi_message_add_tail(&t[1], &m); - spi_sync(wl->spi, &m); + spi_sync(wl_to_spi(wl), &m); wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); } -const struct wl1251_if_operations wl1251_spi_ops = { +static const struct wl1251_if_operations wl1251_spi_ops = { .read = wl1251_spi_read, .write = wl1251_spi_write, .reset = wl1251_spi_reset_wake, @@ -215,7 +220,7 @@ static int __devinit wl1251_spi_probe(struct spi_device *spi) SET_IEEE80211_DEV(hw, &spi->dev); dev_set_drvdata(&spi->dev, wl); - wl->spi = spi; + wl->if_priv = spi; wl->if_ops = &wl1251_spi_ops; /* This is the only SPI value that we need to set here, the rest -- cgit v1.2.3-18-g5258 From 3ec410d747fa1da035183c43775a64c0e285e399 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 7 Aug 2009 13:33:42 +0300 Subject: wl1251: add sdio support This adds the wl1251_sdio module, enabling the SDIO interface for wl1251, as used by the Google G1 phone and others. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/Kconfig | 11 ++ drivers/net/wireless/wl12xx/Makefile | 1 + drivers/net/wireless/wl12xx/wl1251_sdio.c | 188 ++++++++++++++++++++++++++++++ 3 files changed, 200 insertions(+) create mode 100644 drivers/net/wireless/wl12xx/wl1251_sdio.c (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index f8cb8b864ad..7b14d5bc63d 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -28,6 +28,17 @@ config WL1251_SPI If you choose to build a module, it'll be called wl1251_spi. Say N if unsure. +config WL1251_SDIO + tristate "TI wl1251 SDIO support" + depends on WL1251 && MMC + ---help--- + This module adds support for the SDIO interface of adapters using + TI wl1251 chipset. Select this if your platform is using + the SDIO bus. + + If you choose to build a module, it'll be called + wl1251_sdio. Say N if unsure. + config WL1271 tristate "TI wl1271 support" depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index ea0477f1d1d..207e85274bc 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -5,6 +5,7 @@ wl1251-objs = wl1251_main.o wl1251_event.o \ obj-$(CONFIG_WL1251) += wl1251.o obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o +obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o wl1271-objs = wl1271_main.o wl1271_spi.o wl1271_cmd.o \ wl1271_event.o wl1271_tx.o wl1271_rx.o \ diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c new file mode 100644 index 00000000000..f1d9e76e048 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c @@ -0,0 +1,188 @@ +/* + * wl12xx SDIO routines + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * Copyright (C) 2005 Texas Instruments Incorporated + * Copyright (C) 2008 Google Inc + * Copyright (C) 2009 Bob Copeland (me@bobcopeland.com) + */ +#include +#include +#include +#include +#include +#include +#include + +#include "wl1251.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "wl1251_ps.h" +#include "wl1251_io.h" +#include "wl1251_tx.h" +#include "wl1251_debugfs.h" + +#ifndef SDIO_VENDOR_ID_TI +#define SDIO_VENDOR_ID_TI 0x104c +#endif + +#ifndef SDIO_DEVICE_ID_TI_WL1251 +#define SDIO_DEVICE_ID_TI_WL1251 0x9066 +#endif + +static struct sdio_func *wl_to_func(struct wl1251 *wl) +{ + return wl->if_priv; +} + +static void wl1251_sdio_interrupt(struct sdio_func *func) +{ + wl1251_irq(0, sdio_get_drvdata(func)); +} + +static const struct sdio_device_id wl1251_devices[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1251) }, + {} +}; +MODULE_DEVICE_TABLE(sdio, wl1251_devices); + + +void wl1251_sdio_read(struct wl1251 *wl, int addr, void *buf, size_t len) +{ + int ret; + struct sdio_func *func = wl_to_func(wl); + + sdio_claim_host(func); + ret = sdio_memcpy_fromio(func, buf, addr, len); + if (ret) + wl1251_error("sdio read failed (%d)", ret); + sdio_release_host(func); +} + +void wl1251_sdio_write(struct wl1251 *wl, int addr, void *buf, size_t len) +{ + int ret; + struct sdio_func *func = wl_to_func(wl); + + sdio_claim_host(func); + ret = sdio_memcpy_toio(func, addr, buf, len); + if (ret) + wl1251_error("sdio write failed (%d)", ret); + sdio_release_host(func); +} + +void wl1251_sdio_reset(struct wl1251 *wl) +{ +} + +void wl1251_sdio_set_power(bool enable) +{ +} + +struct wl1251_if_operations wl1251_sdio_ops = { + .read = wl1251_sdio_read, + .write = wl1251_sdio_write, + .reset = wl1251_sdio_reset, +}; + +int wl1251_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) +{ + int ret; + struct wl1251 *wl; + struct ieee80211_hw *hw; + + hw = wl1251_alloc_hw(); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + wl = hw->priv; + + sdio_claim_host(func); + ret = sdio_enable_func(func); + if (ret) + goto release; + + sdio_set_block_size(func, 512); + + SET_IEEE80211_DEV(hw, &func->dev); + wl->if_priv = func; + wl->if_ops = &wl1251_sdio_ops; + wl->set_power = wl1251_sdio_set_power; + + sdio_release_host(func); + ret = wl1251_init_ieee80211(wl); + sdio_claim_host(func); + if (ret) + goto disable; + + ret = sdio_claim_irq(func, wl1251_sdio_interrupt); + if (ret) + goto no_irq; + + sdio_release_host(func); + sdio_set_drvdata(func, wl); + return ret; + +no_irq: + wl1251_free_hw(wl); +disable: + sdio_disable_func(func); +release: + sdio_release_host(func); + return ret; +} + +static void __devexit wl1251_sdio_remove(struct sdio_func *func) +{ + struct wl1251 *wl = sdio_get_drvdata(func); + + wl1251_free_hw(wl); + + sdio_claim_host(func); + sdio_release_irq(func); + sdio_disable_func(func); + sdio_release_host(func); +} + +static struct sdio_driver wl1251_sdio_driver = { + .name = "wl1251_sdio", + .id_table = wl1251_devices, + .probe = wl1251_sdio_probe, + .remove = __devexit_p(wl1251_sdio_remove), +}; + +static int __init wl1251_sdio_init(void) +{ + int err; + + err = sdio_register_driver(&wl1251_sdio_driver); + if (err) + wl1251_error("failed to register sdio driver: %d", err); + return err; +} + +static void __exit wl1251_sdio_exit(void) +{ + sdio_unregister_driver(&wl1251_sdio_driver); + wl1251_notice("unloaded"); +} + +module_init(wl1251_sdio_init); +module_exit(wl1251_sdio_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kalle Valo "); +MODULE_AUTHOR("Luciano Coelho "); -- cgit v1.2.3-18-g5258 From b5ed9c1b6f8fcb2d2315f12599fd5808f7933f16 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 7 Aug 2009 13:33:49 +0300 Subject: wl1251: make irq handling interface specific In SDIO, the host driver requests the IRQ and invokes a callback to the card driver. This differs from SPI, so the relevant code needs to be interface-specific. This patch pushes the irq code down into _spi.c and _sdio.c, and adds enable/disable callbacks. This fixes the following warning: [ 566.343887] ------------[ cut here ]------------ [ 566.349105] WARNING: at kernel/irq/manage.c:222 __enable_irq+0x3c/0x6c() [ 566.356735] Unbalanced enable for IRQ 0 [ 566.361099] Modules linked in: msm_wifi wl12xx_sdio wl12xx mac80211 cfg80211 rfkill_backport lib80211_crypt_ccmp lib80211_crypt_wep lib80211_crypt_tkip lib80211 [ 566.381240] [] (dump_stack+0x0/0x14) from [] (warn_slowpath+0x70/0x8c) [ 566.391860] [] (warn_slowpath+0x0/0x8c) from [] (__enable_irq+0x3c/0x6c) [ 566.402572] r3:00000000 r2:c02cad13 [ 566.407516] r7:00001002 r6:00000000 r5:c0310be4 r4:c0310be4 [ 566.415786] [] (__enable_irq+0x0/0x6c) from [] (enable_irq+0x38/0x64) [ 566.425826] r5:c0310be4 r4:a0000013 [ 566.430709] [] (enable_irq+0x0/0x64) from [] (wl12xx_boot_run_firmware+0xfc/0x170 [wl12xx]) [ 566.442947] r7:00001002 r6:c440a9fc r5:00000072 r4:c440a9e0 [ 566.450851] [] (wl12xx_boot_run_firmware+0x0/0x170 [wl12xx]) from [] (wl1251_boot+0xd4/0x108 [wl12xx]) [ 566.464492] r5:00000000 r4:c440a9e0 [ 566.469466] [] (wl1251_boot+0x0/0x108 [wl12xx]) from [] (wl12xx_op_start+0x54/0xb8 [wl12xx]) [ 566.482162] r5:00000000 r4:c440a9e0 [ 566.487472] [] (wl12xx_op_start+0x0/0xb8 [wl12xx]) from [] (ieee80211_open+0x2dc/0x720 [mac80211]) [ 566.500594] r7:00001002 r6:c4950800 r5:c440a220 r4:00000000 [ 566.508865] [] (ieee80211_open+0x0/0x720 [mac80211]) from [] (dev_open+0x9c/0xfc) [ 566.520705] [] (dev_open+0x0/0xfc) from [] (dev_change_flags+0x98/0x170) [ 566.531417] r5:00000041 r4:c4950800 [ 566.536330] [] (dev_change_flags+0x0/0x170) from [] (devinet_ioctl+0x3a8/0x784) [ 566.547683] r7:c128e380 r6:00000001 r5:00008914 r4:00000000 [ 566.555587] [] (devinet_ioctl+0x0/0x784) from [] (inet_ioctl+0xdc/0x114) [ 566.566299] [] (inet_ioctl+0x0/0x114) from [] (sock_ioctl+0x1f0/0x248) [ 566.576827] r5:00008914 r4:c572c1a0 [ 566.581771] [] (sock_ioctl+0x0/0x248) from [] (vfs_ioctl+0x34/0x94) [ 566.592086] r7:c572c1a0 r6:bee497e8 r5:00008914 r4:c572c1a0 [ 566.599990] [] (vfs_ioctl+0x0/0x94) from [] (do_vfs_ioctl+0x52c/0x584) [ 566.610549] r7:c572c1a0 r6:00008914 r5:c572c1a0 r4:c3201228 [ 566.618453] [] (do_vfs_ioctl+0x0/0x584) from [] (sys_ioctl+0x40/0x64) [ 566.628890] [] (sys_ioctl+0x0/0x64) from [] (ret_fast_syscall+0x0/0x2c) [ 566.639541] r7:00000036 r6:00000000 r5:00000004 r4:001a11f3 [ 566.647445] ---[ end trace 15c26ef7dd5e7b03 ]--- Signed-off-by: Bob Copeland Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251.h | 5 ++++- drivers/net/wireless/wl12xx/wl1251_boot.c | 7 +----- drivers/net/wireless/wl12xx/wl1251_main.c | 24 ++++++--------------- drivers/net/wireless/wl12xx/wl1251_sdio.c | 36 +++++++++++++++++++++++-------- drivers/net/wireless/wl12xx/wl1251_spi.c | 26 ++++++++++++++++++++++ 5 files changed, 65 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index ebe2c70559c..13f0589beec 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -285,6 +285,8 @@ struct wl1251_if_operations { void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len); void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len); void (*reset)(struct wl1251 *wl); + void (*enable_irq)(struct wl1251 *wl); + void (*disable_irq)(struct wl1251 *wl); }; struct wl1251 { @@ -404,10 +406,11 @@ struct wl1251 { int wl1251_plt_start(struct wl1251 *wl); int wl1251_plt_stop(struct wl1251 *wl); -irqreturn_t wl1251_irq(int irq, void *cookie); struct ieee80211_hw *wl1251_alloc_hw(void); int wl1251_free_hw(struct wl1251 *wl); int wl1251_init_ieee80211(struct wl1251 *wl); +void wl1251_enable_interrupts(struct wl1251 *wl); +void wl1251_disable_interrupts(struct wl1251 *wl); #define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ #define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index 5c6f32757ac..8b50d44d824 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -29,11 +29,6 @@ #include "wl1251_spi.h" #include "wl1251_event.h" -static void wl1251_boot_enable_interrupts(struct wl1251 *wl) -{ - enable_irq(wl->irq); -} - void wl1251_boot_target_enable_interrupts(struct wl1251 *wl) { wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); @@ -278,7 +273,7 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) */ /* enable gpio interrupts */ - wl1251_boot_enable_interrupts(wl); + wl1251_enable_interrupts(wl); wl->chip.op_target_enable_interrupts(wl); diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index abe157a174c..4c1aad33fb5 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -42,9 +42,14 @@ #include "wl1251_init.h" #include "wl1251_debugfs.h" -static void wl1251_disable_interrupts(struct wl1251 *wl) +void wl1251_enable_interrupts(struct wl1251 *wl) { - disable_irq(wl->irq); + wl->if_ops->enable_irq(wl); +} + +void wl1251_disable_interrupts(struct wl1251 *wl) +{ + wl->if_ops->disable_irq(wl); } static void wl1251_power_off(struct wl1251 *wl) @@ -57,20 +62,6 @@ static void wl1251_power_on(struct wl1251 *wl) wl->set_power(true); } -irqreturn_t wl1251_irq(int irq, void *cookie) -{ - struct wl1251 *wl; - - wl1251_debug(DEBUG_IRQ, "IRQ"); - - wl = cookie; - - schedule_work(&wl->irq_work); - - return IRQ_HANDLED; -} -EXPORT_SYMBOL_GPL(wl1251_irq); - static int wl1251_fetch_firmware(struct wl1251 *wl) { const struct firmware *fw; @@ -1280,7 +1271,6 @@ int wl1251_free_hw(struct wl1251 *wl) wl1251_debugfs_exit(wl); - free_irq(wl->irq, wl); kfree(wl->target_mem_map); kfree(wl->data_path); kfree(wl->fw); diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c index f1d9e76e048..f7e451fed8b 100644 --- a/drivers/net/wireless/wl12xx/wl1251_sdio.c +++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c @@ -50,7 +50,12 @@ static struct sdio_func *wl_to_func(struct wl1251 *wl) static void wl1251_sdio_interrupt(struct sdio_func *func) { - wl1251_irq(0, sdio_get_drvdata(func)); + struct wl1251 *wl = sdio_get_drvdata(func); + + wl1251_debug(DEBUG_IRQ, "IRQ"); + + /* FIXME should be synchronous for sdio */ + schedule_work(&wl->irq_work); } static const struct sdio_device_id wl1251_devices[] = { @@ -88,6 +93,24 @@ void wl1251_sdio_reset(struct wl1251 *wl) { } +static void wl1251_sdio_enable_irq(struct wl1251 *wl) +{ + struct sdio_func *func = wl_to_func(wl); + + sdio_claim_host(func); + sdio_claim_irq(func, wl1251_sdio_interrupt); + sdio_release_host(func); +} + +static void wl1251_sdio_disable_irq(struct wl1251 *wl) +{ + struct sdio_func *func = wl_to_func(wl); + + sdio_claim_host(func); + sdio_release_irq(func); + sdio_release_host(func); +} + void wl1251_sdio_set_power(bool enable) { } @@ -96,6 +119,8 @@ struct wl1251_if_operations wl1251_sdio_ops = { .read = wl1251_sdio_read, .write = wl1251_sdio_write, .reset = wl1251_sdio_reset, + .enable_irq = wl1251_sdio_enable_irq, + .disable_irq = wl1251_sdio_disable_irq, }; int wl1251_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) @@ -124,21 +149,14 @@ int wl1251_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) sdio_release_host(func); ret = wl1251_init_ieee80211(wl); - sdio_claim_host(func); if (ret) goto disable; - ret = sdio_claim_irq(func, wl1251_sdio_interrupt); - if (ret) - goto no_irq; - - sdio_release_host(func); sdio_set_drvdata(func, wl); return ret; -no_irq: - wl1251_free_hw(wl); disable: + sdio_claim_host(func); sdio_disable_func(func); release: sdio_release_host(func); diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index 5967317ef02..7d1031b7a08 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -31,6 +31,19 @@ #include "reg.h" #include "wl1251_spi.h" +static irqreturn_t wl1251_irq(int irq, void *cookie) +{ + struct wl1251 *wl; + + wl1251_debug(DEBUG_IRQ, "IRQ"); + + wl = cookie; + + schedule_work(&wl->irq_work); + + return IRQ_HANDLED; +} + static struct spi_device *wl_to_spi(struct wl1251 *wl) { return wl->if_priv; @@ -193,10 +206,22 @@ static void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); } +static void wl1251_spi_enable_irq(struct wl1251 *wl) +{ + return enable_irq(wl->irq); +} + +static void wl1251_spi_disable_irq(struct wl1251 *wl) +{ + return disable_irq(wl->irq); +} + static const struct wl1251_if_operations wl1251_spi_ops = { .read = wl1251_spi_read, .write = wl1251_spi_write, .reset = wl1251_spi_reset_wake, + .enable_irq = wl1251_spi_enable_irq, + .disable_irq = wl1251_spi_disable_irq, }; static int __devinit wl1251_spi_probe(struct spi_device *spi) @@ -274,6 +299,7 @@ static int __devexit wl1251_spi_remove(struct spi_device *spi) { struct wl1251 *wl = dev_get_drvdata(&spi->dev); + free_irq(wl->irq, wl); wl1251_free_hw(wl); return 0; -- cgit v1.2.3-18-g5258 From 0e71bb084adc4986b9a4be3581897f0ee703cbd5 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:33:57 +0300 Subject: wl1251: remove wl1251_ops Now wl1271 is splitted to separate files, no need to use wl1251_ops anymore. So remove struct wl1251_chip and wl1251_ops.c. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/Makefile | 2 +- drivers/net/wireless/wl12xx/wl1251.h | 55 +++---- drivers/net/wireless/wl12xx/wl1251_acx.c | 79 +++++++++ drivers/net/wireless/wl12xx/wl1251_acx.h | 146 +++++++++++++++++ drivers/net/wireless/wl12xx/wl1251_boot.c | 256 ++++++++++++++++++++++++++++-- drivers/net/wireless/wl12xx/wl1251_boot.h | 1 + drivers/net/wireless/wl12xx/wl1251_cmd.c | 4 +- drivers/net/wireless/wl12xx/wl1251_init.c | 213 +++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1251_init.h | 2 + drivers/net/wireless/wl12xx/wl1251_io.c | 17 +- drivers/net/wireless/wl12xx/wl1251_main.c | 141 +++++++++++++--- drivers/net/wireless/wl12xx/wl1251_ops.h | 165 ------------------- 12 files changed, 842 insertions(+), 239 deletions(-) delete mode 100644 drivers/net/wireless/wl12xx/wl1251_ops.h (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index 207e85274bc..62e37ad01cc 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,7 +1,7 @@ wl1251-objs = wl1251_main.o wl1251_event.o \ wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \ wl1251_acx.o wl1251_boot.o wl1251_init.o \ - wl1251_ops.o wl1251_debugfs.o wl1251_io.o + wl1251_debugfs.o wl1251_io.o obj-$(CONFIG_WL1251) += wl1251.o obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index 13f0589beec..44c5001beed 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -143,35 +143,6 @@ struct wl1251_partition_set { struct wl1251; -/* FIXME: I'm not sure about this structure name */ -struct wl1251_chip { - u32 id; - - const char *fw_filename; - const char *nvs_filename; - - char fw_ver[21]; - - unsigned int power_on_sleep; - int intr_cmd_complete; - int intr_init_complete; - - int (*op_upload_fw)(struct wl1251 *wl); - int (*op_upload_nvs)(struct wl1251 *wl); - int (*op_boot)(struct wl1251 *wl); - void (*op_set_ecpu_ctrl)(struct wl1251 *wl, u32 flag); - void (*op_target_enable_interrupts)(struct wl1251 *wl); - int (*op_hw_init)(struct wl1251 *wl); - int (*op_plt_init)(struct wl1251 *wl); - void (*op_tx_flush)(struct wl1251 *wl); - void (*op_fw_version)(struct wl1251 *wl); - int (*op_cmd_join)(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, - u16 beacon_interval, u8 wait); - - struct wl1251_partition_set *p_table; - enum wl12xx_acx_int_reg *acx_reg_table; -}; - struct wl1251_stats { struct acx_statistics *fw_stats; unsigned long fw_stats_update; @@ -307,8 +278,6 @@ struct wl1251 { int virtual_mem_addr; int virtual_reg_addr; - struct wl1251_chip chip; - int cmd_box_addr; int event_box_addr; struct boot_attr boot_attr; @@ -401,6 +370,9 @@ struct wl1251 { u32 buffer_cmd; u8 buffer_busyword[WL1251_BUSY_WORD_LEN]; struct wl1251_rx_descriptor *rx_descriptor; + + u32 chip_id; + char fw_ver[21]; }; int wl1251_plt_start(struct wl1251 *wl); @@ -420,16 +392,25 @@ void wl1251_disable_interrupts(struct wl1251 *wl); #define WL1251_TX_QUEUE_MAX_LENGTH 20 -/* Different chips need different sleep times after power on. WL1271 needs - * 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we - * know the chip ID, we change the sleep value in the wl1251 chip structure, - * so in subsequent power ons, we don't waste more time then needed. */ -#define WL1251_DEFAULT_POWER_ON_SLEEP 200 - #define CHIP_ID_1251_PG10 (0x7010101) #define CHIP_ID_1251_PG11 (0x7020101) #define CHIP_ID_1251_PG12 (0x7030101) #define CHIP_ID_1271_PG10 (0x4030101) #define CHIP_ID_1271_PG20 (0x4030111) +#define WL1251_FW_NAME "wl1251-fw.bin" +#define WL1251_NVS_NAME "wl1251-nvs.bin" + +#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ + +#define WL1251_PART_DOWN_MEM_START 0x0 +#define WL1251_PART_DOWN_MEM_SIZE 0x16800 +#define WL1251_PART_DOWN_REG_START REGISTERS_BASE +#define WL1251_PART_DOWN_REG_SIZE REGISTERS_DOWN_SIZE + +#define WL1251_PART_WORK_MEM_START 0x28000 +#define WL1251_PART_WORK_MEM_SIZE 0x14000 +#define WL1251_PART_WORK_REG_START REGISTERS_BASE +#define WL1251_PART_WORK_REG_SIZE REGISTERS_WORK_SIZE + #endif diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index 91fe16c8d5b..0a225c62c97 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -837,3 +837,82 @@ int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats) return 0; } + +int wl1251_acx_rate_policies(struct wl1251 *wl) +{ + struct acx_rate_policy *acx; + int ret = 0; + + wl1251_debug(DEBUG_ACX, "acx rate policies"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* configure one default (one-size-fits-all) rate class */ + acx->rate_class_cnt = 1; + acx->rate_class[0].enabled_rates = ACX_RATE_MASK_UNSPECIFIED; + acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT; + acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT; + acx->rate_class[0].aflags = 0; + + ret = wl1251_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); + if (ret < 0) { + wl1251_warning("Setting of rate policies failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1251_acx_mem_cfg(struct wl1251 *wl) +{ + struct wl1251_acx_config_memory *mem_conf; + int ret, i; + + wl1251_debug(DEBUG_ACX, "acx mem cfg"); + + mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); + if (!mem_conf) { + ret = -ENOMEM; + goto out; + } + + /* memory config */ + mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); + mem_conf->mem_config.rx_mem_block_num = 35; + mem_conf->mem_config.tx_min_mem_block_num = 64; + mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; + mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; + mem_conf->mem_config.num_ssid_profiles = 1; + mem_conf->mem_config.debug_buffer_size = + cpu_to_le16(TRACE_BUFFER_MAX_SIZE); + + /* RX queue config */ + mem_conf->rx_queue_config.dma_address = 0; + mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; + mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; + mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; + + /* TX queue config */ + for (i = 0; i < MAX_TX_QUEUES; i++) { + mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; + mem_conf->tx_queue_config[i].attributes = i; + } + + ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf, + sizeof(*mem_conf)); + if (ret < 0) { + wl1251_warning("wl1251 mem config failed: %d", ret); + goto out; + } + +out: + kfree(mem_conf); + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h index 2e7b1933a8f..cafb9145950 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.h +++ b/drivers/net/wireless/wl12xx/wl1251_acx.h @@ -1031,6 +1031,150 @@ struct acx_statistics { struct acx_rxpipe_statistics rxpipe; } __attribute__ ((packed)); +#define ACX_MAX_RATE_CLASSES 8 +#define ACX_RATE_MASK_UNSPECIFIED 0 +#define ACX_RATE_RETRY_LIMIT 10 + +struct acx_rate_class { + u32 enabled_rates; + u8 short_retry_limit; + u8 long_retry_limit; + u8 aflags; + u8 reserved; +}; + +struct acx_rate_policy { + struct acx_header header; + + u32 rate_class_cnt; + struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES]; +} __attribute__ ((packed)); + +struct wl1251_acx_memory { + __le16 num_stations; /* number of STAs to be supported. */ + u16 reserved_1; + + /* + * Nmber of memory buffers for the RX mem pool. + * The actual number may be less if there are + * not enough blocks left for the minimum num + * of TX ones. + */ + u8 rx_mem_block_num; + u8 reserved_2; + u8 num_tx_queues; /* From 1 to 16 */ + u8 host_if_options; /* HOST_IF* */ + u8 tx_min_mem_block_num; + u8 num_ssid_profiles; + __le16 debug_buffer_size; +} __attribute__ ((packed)); + + +#define ACX_RX_DESC_MIN 1 +#define ACX_RX_DESC_MAX 127 +#define ACX_RX_DESC_DEF 32 +struct wl1251_acx_rx_queue_config { + u8 num_descs; + u8 pad; + u8 type; + u8 priority; + __le32 dma_address; +} __attribute__ ((packed)); + +#define ACX_TX_DESC_MIN 1 +#define ACX_TX_DESC_MAX 127 +#define ACX_TX_DESC_DEF 16 +struct wl1251_acx_tx_queue_config { + u8 num_descs; + u8 pad[2]; + u8 attributes; +} __attribute__ ((packed)); + +#define MAX_TX_QUEUE_CONFIGS 5 +#define MAX_TX_QUEUES 4 +struct wl1251_acx_config_memory { + struct acx_header header; + + struct wl1251_acx_memory mem_config; + struct wl1251_acx_rx_queue_config rx_queue_config; + struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS]; +} __attribute__ ((packed)); + +struct wl1251_acx_mem_map { + struct acx_header header; + + void *code_start; + void *code_end; + + void *wep_defkey_start; + void *wep_defkey_end; + + void *sta_table_start; + void *sta_table_end; + + void *packet_template_start; + void *packet_template_end; + + void *queue_memory_start; + void *queue_memory_end; + + void *packet_memory_pool_start; + void *packet_memory_pool_end; + + void *debug_buffer1_start; + void *debug_buffer1_end; + + void *debug_buffer2_start; + void *debug_buffer2_end; + + /* Number of blocks FW allocated for TX packets */ + u32 num_tx_mem_blocks; + + /* Number of blocks FW allocated for RX packets */ + u32 num_rx_mem_blocks; +} __attribute__ ((packed)); + +/************************************************************************* + + Host Interrupt Register (WiLink -> Host) + +**************************************************************************/ + +/* RX packet is ready in Xfer buffer #0 */ +#define WL1251_ACX_INTR_RX0_DATA BIT(0) + +/* TX result(s) are in the TX complete buffer */ +#define WL1251_ACX_INTR_TX_RESULT BIT(1) + +/* OBSOLETE */ +#define WL1251_ACX_INTR_TX_XFR BIT(2) + +/* RX packet is ready in Xfer buffer #1 */ +#define WL1251_ACX_INTR_RX1_DATA BIT(3) + +/* Event was entered to Event MBOX #A */ +#define WL1251_ACX_INTR_EVENT_A BIT(4) + +/* Event was entered to Event MBOX #B */ +#define WL1251_ACX_INTR_EVENT_B BIT(5) + +/* OBSOLETE */ +#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) + +/* Trace meassge on MBOX #A */ +#define WL1251_ACX_INTR_TRACE_A BIT(7) + +/* Trace meassge on MBOX #B */ +#define WL1251_ACX_INTR_TRACE_B BIT(8) + +/* Command processing completion */ +#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9) + +/* Init sequence is done */ +#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14) + +#define WL1251_ACX_INTR_ALL 0xFFFFFFFF + enum { ACX_WAKE_UP_CONDITIONS = 0x0002, ACX_MEM_CFG = 0x0003, @@ -1142,5 +1286,7 @@ int wl1251_acx_cts_protect(struct wl1251 *wl, enum acx_ctsprotect_type ctsprotect); int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats); int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime); +int wl1251_acx_rate_policies(struct wl1251 *wl); +int wl1251_acx_mem_cfg(struct wl1251 *wl); #endif /* __WL1251_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index 8b50d44d824..88e9cb0947d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -28,6 +28,7 @@ #include "wl1251_io.h" #include "wl1251_spi.h" #include "wl1251_event.h" +#include "wl1251_acx.h" void wl1251_boot_target_enable_interrupts(struct wl1251 *wl) { @@ -208,18 +209,30 @@ int wl1251_boot_init_seq(struct wl1251 *wl) return 0; } +static void wl1251_boot_set_ecpu_ctrl(struct wl1251 *wl, u32 flag) +{ + u32 cpu_ctrl; + + /* 10.5.0 run the firmware (I) */ + cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); + + /* 10.5.1 run the firmware (II) */ + cpu_ctrl &= ~flag; + wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); +} + int wl1251_boot_run_firmware(struct wl1251 *wl) { int loop, ret; u32 chip_id, interrupt; - wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); + wl1251_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); chip_id = wl1251_reg_read32(wl, CHIP_ID_B); wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); - if (chip_id != wl->chip.id) { + if (chip_id != wl->chip_id) { wl1251_error("chip id doesn't match after firmware boot"); return -EIO; } @@ -236,9 +249,9 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) return -EIO; } /* check that ACX_INTR_INIT_COMPLETE is enabled */ - else if (interrupt & wl->chip.intr_init_complete) { + else if (interrupt & WL1251_ACX_INTR_INIT_COMPLETE) { wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, - wl->chip.intr_init_complete); + WL1251_ACX_INTR_INIT_COMPLETE); break; } } @@ -256,16 +269,15 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); /* set the working partition to its "running" mode offset */ - wl1251_set_partition(wl, - wl->chip.p_table[PART_WORK].mem.start, - wl->chip.p_table[PART_WORK].mem.size, - wl->chip.p_table[PART_WORK].reg.start, - wl->chip.p_table[PART_WORK].reg.size); + wl1251_set_partition(wl, WL1251_PART_WORK_MEM_START, + WL1251_PART_WORK_MEM_SIZE, + WL1251_PART_WORK_REG_START, + WL1251_PART_WORK_REG_SIZE); wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", wl->cmd_box_addr, wl->event_box_addr); - wl->chip.op_fw_version(wl); + wl1251_acx_fw_version(wl, wl->fw_ver, sizeof(wl->fw_ver)); /* * in case of full asynchronous mode the firmware event must be @@ -275,7 +287,14 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) /* enable gpio interrupts */ wl1251_enable_interrupts(wl); - wl->chip.op_target_enable_interrupts(wl); + /* Enable target's interrupts */ + wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | + WL1251_ACX_INTR_RX1_DATA | + WL1251_ACX_INTR_TX_RESULT | + WL1251_ACX_INTR_EVENT_A | + WL1251_ACX_INTR_EVENT_B | + WL1251_ACX_INTR_INIT_COMPLETE; + wl1251_boot_target_enable_interrupts(wl); /* unmask all mbox events */ wl->event_mask = 0xffffffff; @@ -291,3 +310,218 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) /* firmware startup completed */ return 0; } + +static int wl1251_boot_upload_firmware(struct wl1251 *wl) +{ + int addr, chunk_num, partition_limit; + size_t fw_data_len; + u8 *p; + + /* whal_FwCtrl_LoadFwImageSm() */ + + wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", + wl1251_reg_read32(wl, CHIP_ID_B)); + + /* 10.0 check firmware length and set partition */ + fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | + (wl->fw[6] << 8) | (wl->fw[7]); + + wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, + CHUNK_SIZE); + + if ((fw_data_len % 4) != 0) { + wl1251_error("firmware length not multiple of four"); + return -EIO; + } + + wl1251_set_partition(wl, WL1251_PART_DOWN_MEM_START, + WL1251_PART_DOWN_MEM_SIZE, + WL1251_PART_DOWN_REG_START, + WL1251_PART_DOWN_REG_SIZE); + + /* 10.1 set partition limit and chunk num */ + chunk_num = 0; + partition_limit = WL1251_PART_DOWN_MEM_SIZE; + + while (chunk_num < fw_data_len / CHUNK_SIZE) { + /* 10.2 update partition, if needed */ + addr = WL1251_PART_DOWN_MEM_START + + (chunk_num + 2) * CHUNK_SIZE; + if (addr > partition_limit) { + addr = WL1251_PART_DOWN_MEM_START + + chunk_num * CHUNK_SIZE; + partition_limit = chunk_num * CHUNK_SIZE + + WL1251_PART_DOWN_MEM_SIZE; + wl1251_set_partition(wl, + addr, + WL1251_PART_DOWN_MEM_SIZE, + WL1251_PART_DOWN_REG_START, + WL1251_PART_DOWN_REG_SIZE); + } + + /* 10.3 upload the chunk */ + addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE; + p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; + wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", + p, addr); + wl1251_mem_write(wl, addr, p, CHUNK_SIZE); + + chunk_num++; + } + + /* 10.4 upload the last chunk */ + addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE; + p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; + wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", + fw_data_len % CHUNK_SIZE, p, addr); + wl1251_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); + + return 0; +} + +static int wl1251_boot_upload_nvs(struct wl1251 *wl) +{ + size_t nvs_len, nvs_bytes_written, burst_len; + int nvs_start, i; + u32 dest_addr, val; + u8 *nvs_ptr, *nvs; + + nvs = wl->nvs; + if (nvs == NULL) + return -ENODEV; + + nvs_ptr = nvs; + + nvs_len = wl->nvs_len; + nvs_start = wl->fw_len; + + /* + * Layout before the actual NVS tables: + * 1 byte : burst length. + * 2 bytes: destination address. + * n bytes: data to burst copy. + * + * This is ended by a 0 length, then the NVS tables. + */ + + while (nvs_ptr[0]) { + burst_len = nvs_ptr[0]; + dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); + + /* We move our pointer to the data */ + nvs_ptr += 3; + + for (i = 0; i < burst_len; i++) { + val = (nvs_ptr[0] | (nvs_ptr[1] << 8) + | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); + + wl1251_debug(DEBUG_BOOT, + "nvs burst write 0x%x: 0x%x", + dest_addr, val); + wl1251_mem_write32(wl, dest_addr, val); + + nvs_ptr += 4; + dest_addr += 4; + } + } + + /* + * We've reached the first zero length, the first NVS table + * is 7 bytes further. + */ + nvs_ptr += 7; + nvs_len -= nvs_ptr - nvs; + nvs_len = ALIGN(nvs_len, 4); + + /* Now we must set the partition correctly */ + wl1251_set_partition(wl, nvs_start, + WL1251_PART_DOWN_MEM_SIZE, + WL1251_PART_DOWN_REG_START, + WL1251_PART_DOWN_REG_SIZE); + + /* And finally we upload the NVS tables */ + nvs_bytes_written = 0; + while (nvs_bytes_written < nvs_len) { + val = (nvs_ptr[0] | (nvs_ptr[1] << 8) + | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); + + val = cpu_to_le32(val); + + wl1251_debug(DEBUG_BOOT, + "nvs write table 0x%x: 0x%x", + nvs_start, val); + wl1251_mem_write32(wl, nvs_start, val); + + nvs_ptr += 4; + nvs_bytes_written += 4; + nvs_start += 4; + } + + return 0; +} + +int wl1251_boot(struct wl1251 *wl) +{ + int ret = 0, minor_minor_e2_ver; + u32 tmp, boot_data; + + ret = wl1251_boot_soft_reset(wl); + if (ret < 0) + goto out; + + /* 2. start processing NVS file */ + ret = wl1251_boot_upload_nvs(wl); + if (ret < 0) + goto out; + + /* write firmware's last address (ie. it's length) to + * ACX_EEPROMLESS_IND_REG */ + wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); + + /* 6. read the EEPROM parameters */ + tmp = wl1251_reg_read32(wl, SCR_PAD2); + + /* 7. read bootdata */ + wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; + wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; + tmp = wl1251_reg_read32(wl, SCR_PAD3); + + /* 8. check bootdata and call restart sequence */ + wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; + minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; + + wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " + "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", + wl->boot_attr.radio_type, wl->boot_attr.major, + wl->boot_attr.minor, minor_minor_e2_ver); + + ret = wl1251_boot_init_seq(wl); + if (ret < 0) + goto out; + + /* 9. NVS processing done */ + boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); + + wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); + + /* 10. check that ECPU_CONTROL_HALT bits are set in + * pWhalBus->uBootData and start uploading firmware + */ + if ((boot_data & ECPU_CONTROL_HALT) == 0) { + wl1251_error("boot failed, ECPU_CONTROL_HALT not set"); + ret = -EIO; + goto out; + } + + ret = wl1251_boot_upload_firmware(wl); + if (ret < 0) + goto out; + + /* 10.5 start firmware */ + ret = wl1251_boot_run_firmware(wl); + if (ret < 0) + goto out; + +out: + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.h b/drivers/net/wireless/wl12xx/wl1251_boot.h index 798362d71e3..90063697e8f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.h +++ b/drivers/net/wireless/wl12xx/wl1251_boot.h @@ -30,6 +30,7 @@ int wl1251_boot_soft_reset(struct wl1251 *wl); int wl1251_boot_init_seq(struct wl1251 *wl); int wl1251_boot_run_firmware(struct wl1251 *wl); void wl1251_boot_target_enable_interrupts(struct wl1251 *wl); +int wl1251_boot(struct wl1251 *wl); /* number of times we try to read the INIT interrupt */ #define INIT_LOOP 20000 diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index dfbf6811976..53f5da65bcb 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -37,7 +37,7 @@ int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len) timeout = jiffies + msecs_to_jiffies(WL1251_COMMAND_TIMEOUT); intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); - while (!(intr & wl->chip.intr_cmd_complete)) { + while (!(intr & WL1251_ACX_INTR_CMD_COMPLETE)) { if (time_after(jiffies, timeout)) { wl1251_error("command complete timeout"); ret = -ETIMEDOUT; @@ -50,7 +50,7 @@ int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len) } wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, - wl->chip.intr_cmd_complete); + WL1251_ACX_INTR_CMD_COMPLETE); out: return ret; diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c index df6c60f0fd6..1c587eceacc 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.c +++ b/drivers/net/wireless/wl12xx/wl1251_init.c @@ -28,6 +28,7 @@ #include "wl12xx_80211.h" #include "wl1251_acx.h" #include "wl1251_cmd.h" +#include "reg.h" int wl1251_hw_init_hwenc_config(struct wl1251 *wl) { @@ -198,3 +199,215 @@ int wl1251_hw_init_power_auth(struct wl1251 *wl) { return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); } + +int wl1251_hw_init_mem_config(struct wl1251 *wl) +{ + int ret; + + ret = wl1251_acx_mem_cfg(wl); + if (ret < 0) + return ret; + + wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), + GFP_KERNEL); + if (!wl->target_mem_map) { + wl1251_error("couldn't allocate target memory map"); + return -ENOMEM; + } + + /* we now ask for the firmware built memory map */ + ret = wl1251_acx_mem_map(wl, wl->target_mem_map, + sizeof(struct wl1251_acx_mem_map)); + if (ret < 0) { + wl1251_error("couldn't retrieve firmware memory map"); + kfree(wl->target_mem_map); + wl->target_mem_map = NULL; + return ret; + } + + return 0; +} + +static int wl1251_hw_init_txq_fill(u8 qid, + struct acx_tx_queue_qos_config *config, + u32 num_blocks) +{ + config->qid = qid; + + switch (qid) { + case QOS_AC_BE: + config->high_threshold = + (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_BE_DEF * num_blocks) / 100; + break; + case QOS_AC_BK: + config->high_threshold = + (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_BK_DEF * num_blocks) / 100; + break; + case QOS_AC_VI: + config->high_threshold = + (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_VI_DEF * num_blocks) / 100; + break; + case QOS_AC_VO: + config->high_threshold = + (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_VO_DEF * num_blocks) / 100; + break; + default: + wl1251_error("Invalid TX queue id: %d", qid); + return -EINVAL; + } + + return 0; +} + +static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl) +{ + struct acx_tx_queue_qos_config *config; + struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; + int ret, i; + + wl1251_debug(DEBUG_ACX, "acx tx queue config"); + + config = kzalloc(sizeof(*config), GFP_KERNEL); + if (!config) { + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < MAX_NUM_OF_AC; i++) { + ret = wl1251_hw_init_txq_fill(i, config, + wl_mem_map->num_tx_mem_blocks); + if (ret < 0) + goto out; + + ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG, + config, sizeof(*config)); + if (ret < 0) + goto out; + } + +out: + kfree(config); + return ret; +} + +static int wl1251_hw_init_data_path_config(struct wl1251 *wl) +{ + int ret; + + /* asking for the data path parameters */ + wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), + GFP_KERNEL); + if (!wl->data_path) { + wl1251_error("Couldnt allocate data path parameters"); + return -ENOMEM; + } + + ret = wl1251_acx_data_path_params(wl, wl->data_path); + if (ret < 0) { + kfree(wl->data_path); + wl->data_path = NULL; + return ret; + } + + return 0; +} + + +int wl1251_hw_init(struct wl1251 *wl) +{ + struct wl1251_acx_mem_map *wl_mem_map; + int ret; + + ret = wl1251_hw_init_hwenc_config(wl); + if (ret < 0) + return ret; + + /* Template settings */ + ret = wl1251_hw_init_templates_config(wl); + if (ret < 0) + return ret; + + /* Default memory configuration */ + ret = wl1251_hw_init_mem_config(wl); + if (ret < 0) + return ret; + + /* Default data path configuration */ + ret = wl1251_hw_init_data_path_config(wl); + if (ret < 0) + goto out_free_memmap; + + /* RX config */ + ret = wl1251_hw_init_rx_config(wl, + RX_CFG_PROMISCUOUS | RX_CFG_TSF, + RX_FILTER_OPTION_DEF); + /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, + RX_FILTER_OPTION_FILTER_ALL); */ + if (ret < 0) + goto out_free_data_path; + + /* TX queues config */ + ret = wl1251_hw_init_tx_queue_config(wl); + if (ret < 0) + goto out_free_data_path; + + /* PHY layer config */ + ret = wl1251_hw_init_phy_config(wl); + if (ret < 0) + goto out_free_data_path; + + /* Beacon filtering */ + ret = wl1251_hw_init_beacon_filter(wl); + if (ret < 0) + goto out_free_data_path; + + /* Bluetooth WLAN coexistence */ + ret = wl1251_hw_init_pta(wl); + if (ret < 0) + goto out_free_data_path; + + /* Energy detection */ + ret = wl1251_hw_init_energy_detection(wl); + if (ret < 0) + goto out_free_data_path; + + /* Beacons and boradcast settings */ + ret = wl1251_hw_init_beacon_broadcast(wl); + if (ret < 0) + goto out_free_data_path; + + /* Enable data path */ + ret = wl1251_cmd_data_path(wl, wl->channel, 1); + if (ret < 0) + goto out_free_data_path; + + /* Default power state */ + ret = wl1251_hw_init_power_auth(wl); + if (ret < 0) + goto out_free_data_path; + + wl_mem_map = wl->target_mem_map; + wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", + wl_mem_map->num_tx_mem_blocks, + wl->data_path->tx_control_addr, + wl_mem_map->num_rx_mem_blocks, + wl->data_path->rx_control_addr); + + return 0; + + out_free_data_path: + kfree(wl->data_path); + + out_free_memmap: + kfree(wl->target_mem_map); + + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl12xx/wl1251_init.h index 8596188e834..b3b25ec885e 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.h +++ b/drivers/net/wireless/wl12xx/wl1251_init.h @@ -35,5 +35,7 @@ int wl1251_hw_init_pta(struct wl1251 *wl); int wl1251_hw_init_energy_detection(struct wl1251 *wl); int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl); int wl1251_hw_init_power_auth(struct wl1251 *wl); +int wl1251_hw_init_mem_config(struct wl1251 *wl); +int wl1251_hw_init(struct wl1251 *wl); #endif diff --git a/drivers/net/wireless/wl12xx/wl1251_io.c b/drivers/net/wireless/wl12xx/wl1251_io.c index db2cfbfb1e4..04e486c275c 100644 --- a/drivers/net/wireless/wl12xx/wl1251_io.c +++ b/drivers/net/wireless/wl12xx/wl1251_io.c @@ -25,6 +25,21 @@ #include "reg.h" #include "wl1251_io.h" +/* FIXME: this is static data nowadays and the table can be removed */ +static enum wl12xx_acx_int_reg wl1251_io_reg_table[ACX_REG_TABLE_LEN] = { + [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), + [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), + [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), + [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), + [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), + [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), + [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), + [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), + [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), + [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), + [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) +}; + static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) { /* If the address is lower than REGISTERS_BASE, it means that this is @@ -36,7 +51,7 @@ static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) wl1251_error("address out of range (%d)", addr); return -EINVAL; } - addr = wl->chip.acx_reg_table[addr]; + addr = wl1251_io_reg_table[addr]; } return addr - wl->physical_reg_addr + wl->virtual_reg_addr; diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 4c1aad33fb5..8c88fe279ec 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -32,7 +32,6 @@ #include "wl1251.h" #include "wl12xx_80211.h" #include "reg.h" -#include "wl1251_ops.h" #include "wl1251_io.h" #include "wl1251_cmd.h" #include "wl1251_event.h" @@ -41,6 +40,7 @@ #include "wl1251_ps.h" #include "wl1251_init.h" #include "wl1251_debugfs.h" +#include "wl1251_boot.h" void wl1251_enable_interrupts(struct wl1251 *wl) { @@ -68,7 +68,7 @@ static int wl1251_fetch_firmware(struct wl1251 *wl) struct device *dev = wiphy_dev(wl->hw->wiphy); int ret; - ret = request_firmware(&fw, wl->chip.fw_filename, dev); + ret = request_firmware(&fw, WL1251_FW_NAME, dev); if (ret < 0) { wl1251_error("could not get firmware: %d", ret); @@ -107,7 +107,7 @@ static int wl1251_fetch_nvs(struct wl1251 *wl) struct device *dev = wiphy_dev(wl->hw->wiphy); int ret; - ret = request_firmware(&fw, wl->chip.nvs_filename, dev); + ret = request_firmware(&fw, WL1251_NVS_NAME, dev); if (ret < 0) { wl1251_error("could not get nvs file: %d", ret); @@ -157,7 +157,7 @@ static int wl1251_chip_wakeup(struct wl1251 *wl) int ret = 0; wl1251_power_on(wl); - msleep(wl->chip.power_on_sleep); + msleep(WL1251_POWER_ON_SLEEP); wl->if_ops->reset(wl); /* We don't need a real memory partition here, because we only want @@ -174,22 +174,19 @@ static int wl1251_chip_wakeup(struct wl1251 *wl) /* whal_FwCtrl_BootSm() */ /* 0. read chip id from CHIP_ID */ - wl->chip.id = wl1251_reg_read32(wl, CHIP_ID_B); + wl->chip_id = wl1251_reg_read32(wl, CHIP_ID_B); /* 1. check if chip id is valid */ - switch (wl->chip.id) { + switch (wl->chip_id) { case CHIP_ID_1251_PG12: wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", - wl->chip.id); - - wl1251_setup(wl); - + wl->chip_id); break; case CHIP_ID_1251_PG10: case CHIP_ID_1251_PG11: default: - wl1251_error("unsupported chip id: 0x%x", wl->chip.id); + wl1251_error("unsupported chip id: 0x%x", wl->chip_id); ret = -ENODEV; goto out; } @@ -211,6 +208,107 @@ out: return ret; } +static void wl1251_irq_work(struct work_struct *work) +{ + u32 intr; + struct wl1251 *wl = + container_of(work, struct wl1251, irq_work); + int ret; + + mutex_lock(&wl->mutex); + + wl1251_debug(DEBUG_IRQ, "IRQ work"); + + if (wl->state == WL1251_STATE_OFF) + goto out; + + ret = wl1251_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); + + intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); + wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); + + if (wl->data_path) { + wl->rx_counter = + wl1251_mem_read32(wl, wl->data_path->rx_control_addr); + + /* We handle a frmware bug here */ + switch ((wl->rx_counter - wl->rx_handled) & 0xf) { + case 0: + wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync"); + intr &= ~WL1251_ACX_INTR_RX0_DATA; + intr &= ~WL1251_ACX_INTR_RX1_DATA; + break; + case 1: + wl1251_debug(DEBUG_IRQ, "RX: FW +1"); + intr |= WL1251_ACX_INTR_RX0_DATA; + intr &= ~WL1251_ACX_INTR_RX1_DATA; + break; + case 2: + wl1251_debug(DEBUG_IRQ, "RX: FW +2"); + intr |= WL1251_ACX_INTR_RX0_DATA; + intr |= WL1251_ACX_INTR_RX1_DATA; + break; + default: + wl1251_warning("RX: FW and host out of sync: %d", + wl->rx_counter - wl->rx_handled); + break; + } + + wl->rx_handled = wl->rx_counter; + + + wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); + } + + intr &= wl->intr_mask; + + if (intr == 0) { + wl1251_debug(DEBUG_IRQ, "INTR is 0"); + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, + ~(wl->intr_mask)); + + goto out_sleep; + } + + if (intr & WL1251_ACX_INTR_RX0_DATA) { + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); + wl1251_rx(wl); + } + + if (intr & WL1251_ACX_INTR_RX1_DATA) { + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); + wl1251_rx(wl); + } + + if (intr & WL1251_ACX_INTR_TX_RESULT) { + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); + wl1251_tx_complete(wl); + } + + if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); + if (intr & WL1251_ACX_INTR_EVENT_A) + wl1251_event_handle(wl, 0); + else + wl1251_event_handle(wl, 1); + } + + if (intr & WL1251_ACX_INTR_INIT_COMPLETE) + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); + + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); + +out_sleep: + wl1251_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + static void wl1251_filter_work(struct work_struct *work) { struct wl1251 *wl = @@ -227,7 +325,7 @@ static void wl1251_filter_work(struct work_struct *work) goto out; /* FIXME: replace the magic numbers with proper definitions */ - ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); + ret = wl1251_cmd_join(wl, wl->bss_type, 1, 100, 0); if (ret < 0) goto out_sleep; @@ -289,11 +387,11 @@ static int wl1251_op_start(struct ieee80211_hw *hw) if (ret < 0) goto out; - ret = wl->chip.op_boot(wl); + ret = wl1251_boot(wl); if (ret < 0) goto out; - ret = wl->chip.op_hw_init(wl); + ret = wl1251_hw_init(wl); if (ret < 0) goto out; @@ -303,7 +401,7 @@ static int wl1251_op_start(struct ieee80211_hw *hw) wl->state = WL1251_STATE_ON; - wl1251_info("firmware booted (%s)", wl->chip.fw_ver); + wl1251_info("firmware booted (%s)", wl->fw_ver); out: if (ret < 0) @@ -346,7 +444,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) mutex_lock(&wl->mutex); /* let's notify MAC80211 about the remaining pending TX frames */ - wl->chip.op_tx_flush(wl); + wl1251_tx_flush(wl); wl1251_power_off(wl); memset(wl->bssid, 0, ETH_ALEN); @@ -467,7 +565,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) if (channel != wl->channel) { /* FIXME: use beacon interval provided by mac80211 */ - ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); + ret = wl1251_cmd_join(wl, wl->bss_type, 1, 100, 0); if (ret < 0) goto out_sleep; @@ -1041,7 +1139,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out; - ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0); + ret = wl1251_cmd_join(wl, wl->bss_type, 1, 100, 0); if (ret < 0) goto out; @@ -1232,15 +1330,14 @@ struct ieee80211_hw *wl1251_alloc_hw(void) wl->tx_queue_stopped = false; wl->power_level = WL1251_DEFAULT_POWER_LEVEL; - /* We use the default power on sleep time until we know which chip - * we're using */ - wl->chip.power_on_sleep = WL1251_DEFAULT_POWER_ON_SLEEP; - for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) wl->tx_frames[i] = NULL; wl->next_tx_complete = 0; + INIT_WORK(&wl->irq_work, wl1251_irq_work); + INIT_WORK(&wl->tx_work, wl1251_tx_work); + /* * In case our MAC address is not correctly set, * we use a random but Nokia MAC. diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.h b/drivers/net/wireless/wl12xx/wl1251_ops.h deleted file mode 100644 index 68183c472e4..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_ops.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_OPS_H__ -#define __WL1251_OPS_H__ - -#include - -#include "wl1251.h" -#include "wl1251_acx.h" - -#define WL1251_FW_NAME "wl1251-fw.bin" -#define WL1251_NVS_NAME "wl1251-nvs.bin" - -#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ - -void wl1251_setup(struct wl1251 *wl); - - -struct wl1251_acx_memory { - __le16 num_stations; /* number of STAs to be supported. */ - u16 reserved_1; - - /* - * Nmber of memory buffers for the RX mem pool. - * The actual number may be less if there are - * not enough blocks left for the minimum num - * of TX ones. - */ - u8 rx_mem_block_num; - u8 reserved_2; - u8 num_tx_queues; /* From 1 to 16 */ - u8 host_if_options; /* HOST_IF* */ - u8 tx_min_mem_block_num; - u8 num_ssid_profiles; - __le16 debug_buffer_size; -} __attribute__ ((packed)); - - -#define ACX_RX_DESC_MIN 1 -#define ACX_RX_DESC_MAX 127 -#define ACX_RX_DESC_DEF 32 -struct wl1251_acx_rx_queue_config { - u8 num_descs; - u8 pad; - u8 type; - u8 priority; - __le32 dma_address; -} __attribute__ ((packed)); - -#define ACX_TX_DESC_MIN 1 -#define ACX_TX_DESC_MAX 127 -#define ACX_TX_DESC_DEF 16 -struct wl1251_acx_tx_queue_config { - u8 num_descs; - u8 pad[2]; - u8 attributes; -} __attribute__ ((packed)); - -#define MAX_TX_QUEUE_CONFIGS 5 -#define MAX_TX_QUEUES 4 -struct wl1251_acx_config_memory { - struct acx_header header; - - struct wl1251_acx_memory mem_config; - struct wl1251_acx_rx_queue_config rx_queue_config; - struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS]; -} __attribute__ ((packed)); - -struct wl1251_acx_mem_map { - struct acx_header header; - - void *code_start; - void *code_end; - - void *wep_defkey_start; - void *wep_defkey_end; - - void *sta_table_start; - void *sta_table_end; - - void *packet_template_start; - void *packet_template_end; - - void *queue_memory_start; - void *queue_memory_end; - - void *packet_memory_pool_start; - void *packet_memory_pool_end; - - void *debug_buffer1_start; - void *debug_buffer1_end; - - void *debug_buffer2_start; - void *debug_buffer2_end; - - /* Number of blocks FW allocated for TX packets */ - u32 num_tx_mem_blocks; - - /* Number of blocks FW allocated for RX packets */ - u32 num_rx_mem_blocks; -} __attribute__ ((packed)); - -/************************************************************************* - - Host Interrupt Register (WiLink -> Host) - -**************************************************************************/ - -/* RX packet is ready in Xfer buffer #0 */ -#define WL1251_ACX_INTR_RX0_DATA BIT(0) - -/* TX result(s) are in the TX complete buffer */ -#define WL1251_ACX_INTR_TX_RESULT BIT(1) - -/* OBSOLETE */ -#define WL1251_ACX_INTR_TX_XFR BIT(2) - -/* RX packet is ready in Xfer buffer #1 */ -#define WL1251_ACX_INTR_RX1_DATA BIT(3) - -/* Event was entered to Event MBOX #A */ -#define WL1251_ACX_INTR_EVENT_A BIT(4) - -/* Event was entered to Event MBOX #B */ -#define WL1251_ACX_INTR_EVENT_B BIT(5) - -/* OBSOLETE */ -#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) - -/* Trace meassge on MBOX #A */ -#define WL1251_ACX_INTR_TRACE_A BIT(7) - -/* Trace meassge on MBOX #B */ -#define WL1251_ACX_INTR_TRACE_B BIT(8) - -/* Command processing completion */ -#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9) - -/* Init sequence is done */ -#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14) - -#define WL1251_ACX_INTR_ALL 0xFFFFFFFF - -#endif -- cgit v1.2.3-18-g5258 From 46e947b9c382f67f84cffec3bf068d6d23695058 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:34:05 +0300 Subject: wl1251: reorder wl1251_cmd_join() arguments It's more common to have beacon interval before dtim period. Also use bool instead of u8. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_cmd.c | 4 ++-- drivers/net/wireless/wl12xx/wl1251_cmd.h | 4 ++-- drivers/net/wireless/wl12xx/wl1251_main.c | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index 53f5da65bcb..50daa9bda4a 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -251,8 +251,8 @@ out: return ret; } -int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, - u16 beacon_interval, u8 wait) +int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, + u8 dtim_interval, bool wait) { unsigned long timeout; struct cmd_join *join; diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h index 64f228dd9a9..f9177d6941d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h @@ -36,8 +36,8 @@ int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len); int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, void *bitmap, u16 bitmap_len, u8 bitmap_control); int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable); -int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval, - u16 beacon_interval, u8 wait); +int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, + u8 dtim_interval, bool wait); int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode); int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, size_t len); diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 8c88fe279ec..47b82faac69 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -325,7 +325,7 @@ static void wl1251_filter_work(struct work_struct *work) goto out; /* FIXME: replace the magic numbers with proper definitions */ - ret = wl1251_cmd_join(wl, wl->bss_type, 1, 100, 0); + ret = wl1251_cmd_join(wl, wl->bss_type, 100, 1, false); if (ret < 0) goto out_sleep; @@ -565,7 +565,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) if (channel != wl->channel) { /* FIXME: use beacon interval provided by mac80211 */ - ret = wl1251_cmd_join(wl, wl->bss_type, 1, 100, 0); + ret = wl1251_cmd_join(wl, wl->bss_type, 100, 1, false); if (ret < 0) goto out_sleep; @@ -1113,7 +1113,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, goto out; if (wl->bss_type != BSS_TYPE_IBSS) { - ret = wl1251_cmd_join(wl, wl->bss_type, 5, 100, 1); + ret = wl1251_cmd_join(wl, wl->bss_type, 100, 5, true); if (ret < 0) goto out_sleep; wl1251_warning("Set ctsprotect failed %d", ret); @@ -1139,7 +1139,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out; - ret = wl1251_cmd_join(wl, wl->bss_type, 1, 100, 0); + ret = wl1251_cmd_join(wl, wl->bss_type, 100, 1, false); if (ret < 0) goto out; -- cgit v1.2.3-18-g5258 From e2fd4611d50a1cd13a370f84b672a5f29472ee09 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:34:12 +0300 Subject: wl1251: use beacon interval and dtim period provided by mac80211 wl1251 was using hardcoded beacon intervals and dtim periods, use the ones provided by mac80211 instead. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251.h | 6 ++++++ drivers/net/wireless/wl12xx/wl1251_cmd.c | 5 ++++- drivers/net/wireless/wl12xx/wl1251_main.c | 26 ++++++++++++++++++++------ 3 files changed, 30 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index 44c5001beed..86d2abea4e1 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -360,6 +360,9 @@ struct wl1251 { /* PSM mode requested */ bool psm_requested; + u16 beacon_int; + u8 dtim_period; + /* in dBm */ int power_level; @@ -392,6 +395,9 @@ void wl1251_disable_interrupts(struct wl1251 *wl); #define WL1251_TX_QUEUE_MAX_LENGTH 20 +#define WL1251_DEFAULT_BEACON_INT 100 +#define WL1251_DEFAULT_DTIM_PERIOD 1 + #define CHIP_ID_1251_PG10 (0x7010101) #define CHIP_ID_1251_PG11 (0x7020101) #define CHIP_ID_1251_PG12 (0x7030101) diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index 50daa9bda4a..9cd46ce88e5 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -273,7 +273,10 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, if (ret < 0) goto out; - wl1251_debug(DEBUG_CMD, "cmd join"); + wl1251_debug(DEBUG_CMD, "cmd join%s %d %d%s", + bss_type == BSS_TYPE_IBSS ? " ibss" : "", + beacon_interval, dtim_interval, + wait ? " wait" : ""); /* Reverse order BSSID */ bssid = (u8 *) &join->bssid_lsb; diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 47b82faac69..70142334541 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -324,8 +324,8 @@ static void wl1251_filter_work(struct work_struct *work) if (ret < 0) goto out; - /* FIXME: replace the magic numbers with proper definitions */ - ret = wl1251_cmd_join(wl, wl->bss_type, 100, 1, false); + ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, + wl->dtim_period, false); if (ret < 0) goto out_sleep; @@ -564,8 +564,8 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) goto out; if (channel != wl->channel) { - /* FIXME: use beacon interval provided by mac80211 */ - ret = wl1251_cmd_join(wl, wl->bss_type, 100, 1, false); + ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, + wl->dtim_period, false); if (ret < 0) goto out_sleep; @@ -1057,6 +1057,11 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { + wl->beacon_int = bss_conf->beacon_int; + wl->dtim_period = bss_conf->dtim_period; + + /* FIXME: call join */ + wl->aid = bss_conf->aid; ret = wl1251_build_ps_poll(wl, wl->aid); @@ -1074,6 +1079,10 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out_sleep; } + } else { + /* use defaults when not associated */ + wl->beacon_int = WL1251_DEFAULT_BEACON_INT; + wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; } } if (changed & BSS_CHANGED_ERP_SLOT) { @@ -1113,7 +1122,9 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, goto out; if (wl->bss_type != BSS_TYPE_IBSS) { - ret = wl1251_cmd_join(wl, wl->bss_type, 100, 5, true); + ret = wl1251_cmd_join(wl, wl->bss_type, + wl->beacon_int, + wl->dtim_period, true); if (ret < 0) goto out_sleep; wl1251_warning("Set ctsprotect failed %d", ret); @@ -1139,7 +1150,8 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out; - ret = wl1251_cmd_join(wl, wl->bss_type, 100, 1, false); + ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, + wl->dtim_period, false); if (ret < 0) goto out; @@ -1329,6 +1341,8 @@ struct ieee80211_hw *wl1251_alloc_hw(void) wl->psm_requested = false; wl->tx_queue_stopped = false; wl->power_level = WL1251_DEFAULT_POWER_LEVEL; + wl->beacon_int = WL1251_DEFAULT_BEACON_INT; + wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) wl->tx_frames[i] = NULL; -- cgit v1.2.3-18-g5258 From 7a33732fd9f2181bfe639691ead3def7a1e87c7d Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:34:19 +0300 Subject: wl1251: remove wait parameter from wl1251_cmd_join() We should wait everytime for the join command to finish, not waiting for it might create problems. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_cmd.c | 10 ++++------ drivers/net/wireless/wl12xx/wl1251_cmd.h | 2 +- drivers/net/wireless/wl12xx/wl1251_main.c | 8 ++++---- 3 files changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index 9cd46ce88e5..e276cb5f5be 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -252,7 +252,7 @@ out: } int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, - u8 dtim_interval, bool wait) + u8 dtim_interval) { unsigned long timeout; struct cmd_join *join; @@ -273,10 +273,9 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, if (ret < 0) goto out; - wl1251_debug(DEBUG_CMD, "cmd join%s %d %d%s", + wl1251_debug(DEBUG_CMD, "cmd join%s %d %d", bss_type == BSS_TYPE_IBSS ? " ibss" : "", - beacon_interval, dtim_interval, - wait ? " wait" : ""); + beacon_interval, dtim_interval); /* Reverse order BSSID */ bssid = (u8 *) &join->bssid_lsb; @@ -307,8 +306,7 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to * simplify locking we just sleep instead, for now */ - if (wait) - msleep(10); + msleep(10); out: kfree(join); diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h index f9177d6941d..ffeabf28d34 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h @@ -37,7 +37,7 @@ int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, void *bitmap, u16 bitmap_len, u8 bitmap_control); int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable); int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, - u8 dtim_interval, bool wait); + u8 dtim_interval); int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode); int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, size_t len); diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 70142334541..d03169266b2 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -325,7 +325,7 @@ static void wl1251_filter_work(struct work_struct *work) goto out; ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, - wl->dtim_period, false); + wl->dtim_period); if (ret < 0) goto out_sleep; @@ -565,7 +565,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) if (channel != wl->channel) { ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, - wl->dtim_period, false); + wl->dtim_period); if (ret < 0) goto out_sleep; @@ -1124,7 +1124,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (wl->bss_type != BSS_TYPE_IBSS) { ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, - wl->dtim_period, true); + wl->dtim_period); if (ret < 0) goto out_sleep; wl1251_warning("Set ctsprotect failed %d", ret); @@ -1151,7 +1151,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, goto out; ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, - wl->dtim_period, false); + wl->dtim_period); if (ret < 0) goto out; -- cgit v1.2.3-18-g5258 From 9780279c60c32cb5f14531aa34ae991bb714c90c Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:34:27 +0300 Subject: wl1251: initialise default channel to zero Because wl->channel was initialised to one, the first join command in wl1251_op_config() always failed. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251.h | 2 ++ drivers/net/wireless/wl12xx/wl1251_main.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index 86d2abea4e1..998e4b6252b 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -398,6 +398,8 @@ void wl1251_disable_interrupts(struct wl1251 *wl); #define WL1251_DEFAULT_BEACON_INT 100 #define WL1251_DEFAULT_DTIM_PERIOD 1 +#define WL1251_DEFAULT_CHANNEL 0 + #define CHIP_ID_1251_PG10 (0x7010101) #define CHIP_ID_1251_PG11 (0x7020101) #define CHIP_ID_1251_PG12 (0x7030101) diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index d03169266b2..2514c94294d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -461,6 +461,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) wl->psm = 0; wl->tx_queue_stopped = false; wl->power_level = WL1251_DEFAULT_POWER_LEVEL; + wl->channel = WL1251_DEFAULT_CHANNEL; wl1251_debugfs_reset(wl); @@ -1302,7 +1303,6 @@ out: } EXPORT_SYMBOL_GPL(wl1251_init_ieee80211); -#define WL1251_DEFAULT_CHANNEL 1 struct ieee80211_hw *wl1251_alloc_hw(void) { struct ieee80211_hw *hw; -- cgit v1.2.3-18-g5258 From c88f87540fa4b90a0b8696dae8bce801ecc142d3 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:34:34 +0300 Subject: wl1251: add channel to wl1251_cmd_join() parameters Because join channel tunes to a channel, better to make it more obvious by adding a parameter for it. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_cmd.c | 10 +++++----- drivers/net/wireless/wl12xx/wl1251_cmd.h | 4 ++-- drivers/net/wireless/wl12xx/wl1251_main.c | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index e276cb5f5be..4e796db1624 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -251,8 +251,8 @@ out: return ret; } -int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, - u8 dtim_interval) +int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, + u16 beacon_interval, u8 dtim_interval) { unsigned long timeout; struct cmd_join *join; @@ -273,9 +273,9 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, if (ret < 0) goto out; - wl1251_debug(DEBUG_CMD, "cmd join%s %d %d", + wl1251_debug(DEBUG_CMD, "cmd join%s ch %d %d/%d", bss_type == BSS_TYPE_IBSS ? " ibss" : "", - beacon_interval, dtim_interval); + channel, beacon_interval, dtim_interval); /* Reverse order BSSID */ bssid = (u8 *) &join->bssid_lsb; @@ -291,7 +291,7 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, join->beacon_interval = beacon_interval; join->dtim_interval = dtim_interval; join->bss_type = bss_type; - join->channel = wl->channel; + join->channel = channel; join->ctrl = JOIN_CMD_CTRL_TX_FLUSH; ret = wl1251_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h index ffeabf28d34..dff798ad0ef 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h @@ -36,8 +36,8 @@ int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len); int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, void *bitmap, u16 bitmap_len, u8 bitmap_control); int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable); -int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u16 beacon_interval, - u8 dtim_interval); +int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, + u16 beacon_interval, u8 dtim_interval); int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode); int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, size_t len); diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 2514c94294d..5e9045985e5 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -324,7 +324,7 @@ static void wl1251_filter_work(struct work_struct *work) if (ret < 0) goto out; - ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, + ret = wl1251_cmd_join(wl, wl->bss_type, wl->channel, wl->beacon_int, wl->dtim_period); if (ret < 0) goto out_sleep; @@ -565,8 +565,8 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) goto out; if (channel != wl->channel) { - ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, - wl->dtim_period); + ret = wl1251_cmd_join(wl, wl->bss_type, wl->channel, + wl->beacon_int, wl->dtim_period); if (ret < 0) goto out_sleep; @@ -1123,7 +1123,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, goto out; if (wl->bss_type != BSS_TYPE_IBSS) { - ret = wl1251_cmd_join(wl, wl->bss_type, + ret = wl1251_cmd_join(wl, wl->bss_type, wl->channel, wl->beacon_int, wl->dtim_period); if (ret < 0) @@ -1152,7 +1152,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, goto out; ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, - wl->dtim_period); + wl->channel, wl->dtim_period); if (ret < 0) goto out; -- cgit v1.2.3-18-g5258 From ae46ae17d1d8b953eb5859764737c065e4e3c86b Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:34:42 +0300 Subject: wl1251: create wl1251_join() Better to use wl1251_cmd_join() only for sending the command and move the logic to wl1251_join(). Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_cmd.c | 17 ------------ drivers/net/wireless/wl12xx/wl1251_main.c | 45 ++++++++++++++++++++++++------- 2 files changed, 36 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index 4e796db1624..d7800a39f7d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -254,7 +254,6 @@ out: int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, u16 beacon_interval, u8 dtim_interval) { - unsigned long timeout; struct cmd_join *join; int ret, i; u8 *bssid; @@ -265,14 +264,6 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, goto out; } - /* FIXME: this should be in main.c */ - ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, - DEFAULT_HW_GEN_MODULATION_TYPE, - wl->tx_mgmt_frm_rate, - wl->tx_mgmt_frm_mod); - if (ret < 0) - goto out; - wl1251_debug(DEBUG_CMD, "cmd join%s ch %d %d/%d", bss_type == BSS_TYPE_IBSS ? " ibss" : "", channel, beacon_interval, dtim_interval); @@ -300,14 +291,6 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, goto out; } - timeout = msecs_to_jiffies(JOIN_TIMEOUT); - - /* - * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to - * simplify locking we just sleep instead, for now - */ - msleep(10); - out: kfree(join); return ret; diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 5e9045985e5..e575b7869fb 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -309,6 +309,34 @@ out: mutex_unlock(&wl->mutex); } +static int wl1251_join(struct wl1251 *wl, u8 bss_type, u8 channel, + u16 beacon_interval, u8 dtim_period) +{ + int ret; + + ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, + DEFAULT_HW_GEN_MODULATION_TYPE, + wl->tx_mgmt_frm_rate, + wl->tx_mgmt_frm_mod); + if (ret < 0) + goto out; + + + ret = wl1251_cmd_join(wl, bss_type, channel, beacon_interval, + dtim_period); + if (ret < 0) + goto out; + + /* + * FIXME: we should wait for JOIN_EVENT_COMPLETE_ID but to simplify + * locking we just sleep instead, for now + */ + msleep(10); + +out: + return ret; +} + static void wl1251_filter_work(struct work_struct *work) { struct wl1251 *wl = @@ -324,8 +352,8 @@ static void wl1251_filter_work(struct work_struct *work) if (ret < 0) goto out; - ret = wl1251_cmd_join(wl, wl->bss_type, wl->channel, wl->beacon_int, - wl->dtim_period); + ret = wl1251_join(wl, wl->bss_type, wl->channel, wl->beacon_int, + wl->dtim_period); if (ret < 0) goto out_sleep; @@ -565,8 +593,8 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) goto out; if (channel != wl->channel) { - ret = wl1251_cmd_join(wl, wl->bss_type, wl->channel, - wl->beacon_int, wl->dtim_period); + ret = wl1251_join(wl, wl->bss_type, wl->channel, + wl->beacon_int, wl->dtim_period); if (ret < 0) goto out_sleep; @@ -1123,9 +1151,8 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, goto out; if (wl->bss_type != BSS_TYPE_IBSS) { - ret = wl1251_cmd_join(wl, wl->bss_type, wl->channel, - wl->beacon_int, - wl->dtim_period); + ret = wl1251_join(wl, wl->bss_type, wl->channel, + wl->beacon_int, wl->dtim_period); if (ret < 0) goto out_sleep; wl1251_warning("Set ctsprotect failed %d", ret); @@ -1151,8 +1178,8 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out; - ret = wl1251_cmd_join(wl, wl->bss_type, wl->beacon_int, - wl->channel, wl->dtim_period); + ret = wl1251_join(wl, wl->bss_type, wl->beacon_int, + wl->channel, wl->dtim_period); if (ret < 0) goto out; -- cgit v1.2.3-18-g5258 From fe9a98460b6c8dac47d0e34bcb04850193d41565 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:34:49 +0300 Subject: wl1251: fix channel setting in wl1251_op_config() There is a bug in wl1251_op_config(). It was calling join with previous channel. Fix it by setting assigning wl->channel before calling join command. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index e575b7869fb..568b640aaa5 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -593,12 +593,12 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) goto out; if (channel != wl->channel) { + wl->channel = channel; + ret = wl1251_join(wl, wl->bss_type, wl->channel, wl->beacon_int, wl->dtim_period); if (ret < 0) goto out_sleep; - - wl->channel = channel; } ret = wl1251_build_null_data(wl); -- cgit v1.2.3-18-g5258 From 4a8189227fc4718a767ffca74d13a7d552e42189 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:34:56 +0300 Subject: wl1251: move wl1251_acx_wake_up_conditions() to wl1251_ps_set_mode() It should not be hidden inside wl1251_cmd_ps_mode(). Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_cmd.c | 8 -------- drivers/net/wireless/wl12xx/wl1251_ps.c | 13 +++++++++++++ 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index d7800a39f7d..74ea1fdf9bd 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -301,14 +301,6 @@ int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode) struct wl1251_cmd_ps_params *ps_params = NULL; int ret = 0; - /* FIXME: this should be in ps.c */ - ret = wl1251_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, - wl->listen_int); - if (ret < 0) { - wl1251_error("couldn't set wake up conditions"); - goto out; - } - wl1251_debug(DEBUG_CMD, "cmd set ps mode"); ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c index 05816778f3d..36acde0b3bd 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.c +++ b/drivers/net/wireless/wl12xx/wl1251_ps.c @@ -118,6 +118,13 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) switch (mode) { case STATION_POWER_SAVE_MODE: wl1251_debug(DEBUG_PSM, "entering psm"); + + ret = wl1251_acx_wake_up_conditions(wl, + WAKE_UP_EVENT_DTIM_BITMAP, + wl->listen_int); + if (ret < 0) + return ret; + ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); if (ret < 0) return ret; @@ -135,6 +142,12 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) if (ret < 0) return ret; + ret = wl1251_acx_wake_up_conditions(wl, + WAKE_UP_EVENT_DTIM_BITMAP, + wl->listen_int); + if (ret < 0) + return ret; + ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE); if (ret < 0) return ret; -- cgit v1.2.3-18-g5258 From 16e711f9ed16e32126270652d79225836a7062cb Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:35:04 +0300 Subject: wl1251: use workqueue provided by mac80211 wl1251 should use workqueue created by mac80211 to not block the events workqueue too long. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 2 +- drivers/net/wireless/wl12xx/wl1251_sdio.c | 2 +- drivers/net/wireless/wl12xx/wl1251_spi.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 568b640aaa5..c5f2d9dbd1a 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -375,7 +375,7 @@ static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * before that, the tx_work will not be initialized! */ - schedule_work(&wl->tx_work); + ieee80211_queue_work(wl->hw, &wl->tx_work); /* * The workqueue is slow to process the tx_queue and we need stop diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c index f7e451fed8b..20668e244c6 100644 --- a/drivers/net/wireless/wl12xx/wl1251_sdio.c +++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c @@ -55,7 +55,7 @@ static void wl1251_sdio_interrupt(struct sdio_func *func) wl1251_debug(DEBUG_IRQ, "IRQ"); /* FIXME should be synchronous for sdio */ - schedule_work(&wl->irq_work); + ieee80211_queue_work(wl->hw, &wl->irq_work); } static const struct sdio_device_id wl1251_devices[] = { diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index 7d1031b7a08..e088334536a 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -39,7 +39,7 @@ static irqreturn_t wl1251_irq(int irq, void *cookie) wl = cookie; - schedule_work(&wl->irq_work); + ieee80211_queue_work(wl->hw, &wl->irq_work); return IRQ_HANDLED; } -- cgit v1.2.3-18-g5258 From 29d904c452d466fbf51b2fde10f405b5c8f14c74 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:35:11 +0300 Subject: wl1251: rename reg.h to wl1251_reg.h Now that wl1271 doesn't use reg.h anymore, it can be renamed to wl1251_reg.h. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/reg.h | 744 ----------------------------- drivers/net/wireless/wl12xx/wl1251_acx.c | 2 +- drivers/net/wireless/wl12xx/wl1251_boot.c | 2 +- drivers/net/wireless/wl12xx/wl1251_cmd.c | 2 +- drivers/net/wireless/wl12xx/wl1251_event.c | 2 +- drivers/net/wireless/wl12xx/wl1251_init.c | 2 +- drivers/net/wireless/wl12xx/wl1251_io.c | 2 +- drivers/net/wireless/wl12xx/wl1251_main.c | 2 +- drivers/net/wireless/wl12xx/wl1251_ps.c | 2 +- drivers/net/wireless/wl12xx/wl1251_reg.h | 744 +++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1251_rx.c | 2 +- drivers/net/wireless/wl12xx/wl1251_sdio.c | 2 +- drivers/net/wireless/wl12xx/wl1251_spi.c | 2 +- drivers/net/wireless/wl12xx/wl1251_spi.h | 2 +- drivers/net/wireless/wl12xx/wl1251_tx.c | 2 +- 15 files changed, 757 insertions(+), 757 deletions(-) delete mode 100644 drivers/net/wireless/wl12xx/reg.h create mode 100644 drivers/net/wireless/wl12xx/wl1251_reg.h (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h deleted file mode 100644 index 2de47cc32b8..00000000000 --- a/drivers/net/wireless/wl12xx/reg.h +++ /dev/null @@ -1,744 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (c) 1998-2007 Texas Instruments Incorporated - * Copyright (C) 2008 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __REG_H__ -#define __REG_H__ - -#include - -#define REGISTERS_BASE 0x00300000 -#define DRPW_BASE 0x00310000 - -#define REGISTERS_DOWN_SIZE 0x00008800 -#define REGISTERS_WORK_SIZE 0x0000b000 - -#define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC - -/* ELP register commands */ -#define ELPCTRL_WAKE_UP 0x1 -#define ELPCTRL_WAKE_UP_WLAN_READY 0x5 -#define ELPCTRL_SLEEP 0x0 -/* ELP WLAN_READY bit */ -#define ELPCTRL_WLAN_READY 0x2 - -/* - * Interrupt registers. - * 64 bit interrupt sources registers ws ced. - * sme interupts were removed and new ones were added. - * Order was changed. - */ -#define FIQ_MASK (REGISTERS_BASE + 0x0400) -#define FIQ_MASK_L (REGISTERS_BASE + 0x0400) -#define FIQ_MASK_H (REGISTERS_BASE + 0x0404) -#define FIQ_MASK_SET (REGISTERS_BASE + 0x0408) -#define FIQ_MASK_SET_L (REGISTERS_BASE + 0x0408) -#define FIQ_MASK_SET_H (REGISTERS_BASE + 0x040C) -#define FIQ_MASK_CLR (REGISTERS_BASE + 0x0410) -#define FIQ_MASK_CLR_L (REGISTERS_BASE + 0x0410) -#define FIQ_MASK_CLR_H (REGISTERS_BASE + 0x0414) -#define IRQ_MASK (REGISTERS_BASE + 0x0418) -#define IRQ_MASK_L (REGISTERS_BASE + 0x0418) -#define IRQ_MASK_H (REGISTERS_BASE + 0x041C) -#define IRQ_MASK_SET (REGISTERS_BASE + 0x0420) -#define IRQ_MASK_SET_L (REGISTERS_BASE + 0x0420) -#define IRQ_MASK_SET_H (REGISTERS_BASE + 0x0424) -#define IRQ_MASK_CLR (REGISTERS_BASE + 0x0428) -#define IRQ_MASK_CLR_L (REGISTERS_BASE + 0x0428) -#define IRQ_MASK_CLR_H (REGISTERS_BASE + 0x042C) -#define ECPU_MASK (REGISTERS_BASE + 0x0448) -#define FIQ_STS_L (REGISTERS_BASE + 0x044C) -#define FIQ_STS_H (REGISTERS_BASE + 0x0450) -#define IRQ_STS_L (REGISTERS_BASE + 0x0454) -#define IRQ_STS_H (REGISTERS_BASE + 0x0458) -#define INT_STS_ND (REGISTERS_BASE + 0x0464) -#define INT_STS_RAW_L (REGISTERS_BASE + 0x0464) -#define INT_STS_RAW_H (REGISTERS_BASE + 0x0468) -#define INT_STS_CLR (REGISTERS_BASE + 0x04B4) -#define INT_STS_CLR_L (REGISTERS_BASE + 0x04B4) -#define INT_STS_CLR_H (REGISTERS_BASE + 0x04B8) -#define INT_ACK (REGISTERS_BASE + 0x046C) -#define INT_ACK_L (REGISTERS_BASE + 0x046C) -#define INT_ACK_H (REGISTERS_BASE + 0x0470) -#define INT_TRIG (REGISTERS_BASE + 0x0474) -#define INT_TRIG_L (REGISTERS_BASE + 0x0474) -#define INT_TRIG_H (REGISTERS_BASE + 0x0478) -#define HOST_STS_L (REGISTERS_BASE + 0x045C) -#define HOST_STS_H (REGISTERS_BASE + 0x0460) -#define HOST_MASK (REGISTERS_BASE + 0x0430) -#define HOST_MASK_L (REGISTERS_BASE + 0x0430) -#define HOST_MASK_H (REGISTERS_BASE + 0x0434) -#define HOST_MASK_SET (REGISTERS_BASE + 0x0438) -#define HOST_MASK_SET_L (REGISTERS_BASE + 0x0438) -#define HOST_MASK_SET_H (REGISTERS_BASE + 0x043C) -#define HOST_MASK_CLR (REGISTERS_BASE + 0x0440) -#define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440) -#define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444) - -/* Host Interrupts*/ -#define HINT_MASK (REGISTERS_BASE + 0x0494) -#define HINT_MASK_SET (REGISTERS_BASE + 0x0498) -#define HINT_MASK_CLR (REGISTERS_BASE + 0x049C) -#define HINT_STS_ND_MASKED (REGISTERS_BASE + 0x04A0) -/*1150 spec calls this HINT_STS_RAW*/ -#define HINT_STS_ND (REGISTERS_BASE + 0x04B0) -#define HINT_STS_CLR (REGISTERS_BASE + 0x04A4) -#define HINT_ACK (REGISTERS_BASE + 0x04A8) -#define HINT_TRIG (REGISTERS_BASE + 0x04AC) - -/* Device Configuration registers*/ -#define SOR_CFG (REGISTERS_BASE + 0x0800) -#define ECPU_CTRL (REGISTERS_BASE + 0x0804) -#define HI_CFG (REGISTERS_BASE + 0x0808) -#define EE_START (REGISTERS_BASE + 0x080C) - -#define CHIP_ID_B (REGISTERS_BASE + 0x5674) - -#define CHIP_ID_1251_PG10 (0x7010101) -#define CHIP_ID_1251_PG11 (0x7020101) -#define CHIP_ID_1251_PG12 (0x7030101) - -#define ENABLE (REGISTERS_BASE + 0x5450) - -/* Power Management registers */ -#define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) -#define ELP_CMD (REGISTERS_BASE + 0x5808) -#define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) -#define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) -#define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) - -#define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) - -/* Scratch Pad registers*/ -#define SCR_PAD0 (REGISTERS_BASE + 0x5608) -#define SCR_PAD1 (REGISTERS_BASE + 0x560C) -#define SCR_PAD2 (REGISTERS_BASE + 0x5610) -#define SCR_PAD3 (REGISTERS_BASE + 0x5614) -#define SCR_PAD4 (REGISTERS_BASE + 0x5618) -#define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) -#define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) -#define SCR_PAD5 (REGISTERS_BASE + 0x5624) -#define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) -#define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) -#define SCR_PAD6 (REGISTERS_BASE + 0x5630) -#define SCR_PAD7 (REGISTERS_BASE + 0x5634) -#define SCR_PAD8 (REGISTERS_BASE + 0x5638) -#define SCR_PAD9 (REGISTERS_BASE + 0x563C) - -/* Spare registers*/ -#define SPARE_A1 (REGISTERS_BASE + 0x0994) -#define SPARE_A2 (REGISTERS_BASE + 0x0998) -#define SPARE_A3 (REGISTERS_BASE + 0x099C) -#define SPARE_A4 (REGISTERS_BASE + 0x09A0) -#define SPARE_A5 (REGISTERS_BASE + 0x09A4) -#define SPARE_A6 (REGISTERS_BASE + 0x09A8) -#define SPARE_A7 (REGISTERS_BASE + 0x09AC) -#define SPARE_A8 (REGISTERS_BASE + 0x09B0) -#define SPARE_B1 (REGISTERS_BASE + 0x5420) -#define SPARE_B2 (REGISTERS_BASE + 0x5424) -#define SPARE_B3 (REGISTERS_BASE + 0x5428) -#define SPARE_B4 (REGISTERS_BASE + 0x542C) -#define SPARE_B5 (REGISTERS_BASE + 0x5430) -#define SPARE_B6 (REGISTERS_BASE + 0x5434) -#define SPARE_B7 (REGISTERS_BASE + 0x5438) -#define SPARE_B8 (REGISTERS_BASE + 0x543C) - -enum wl12xx_acx_int_reg { - ACX_REG_INTERRUPT_TRIG, - ACX_REG_INTERRUPT_TRIG_H, - -/*============================================= - Host Interrupt Mask Register - 32bit (RW) - ------------------------------------------ - Setting a bit in this register masks the - corresponding interrupt to the host. - 0 - RX0 - Rx first dubble buffer Data Interrupt - 1 - TXD - Tx Data Interrupt - 2 - TXXFR - Tx Transfer Interrupt - 3 - RX1 - Rx second dubble buffer Data Interrupt - 4 - RXXFR - Rx Transfer Interrupt - 5 - EVENT_A - Event Mailbox interrupt - 6 - EVENT_B - Event Mailbox interrupt - 7 - WNONHST - Wake On Host Interrupt - 8 - TRACE_A - Debug Trace interrupt - 9 - TRACE_B - Debug Trace interrupt - 10 - CDCMP - Command Complete Interrupt - 11 - - 12 - - 13 - - 14 - ICOMP - Initialization Complete Interrupt - 16 - SG SE - Soft Gemini - Sense enable interrupt - 17 - SG SD - Soft Gemini - Sense disable interrupt - 18 - - - 19 - - - 20 - - - 21- - - Default: 0x0001 -*==============================================*/ - ACX_REG_INTERRUPT_MASK, - -/*============================================= - Host Interrupt Mask Set 16bit, (Write only) - ------------------------------------------ - Setting a bit in this register sets - the corresponding bin in ACX_HINT_MASK register - without effecting the mask - state of other bits (0 = no effect). -==============================================*/ - ACX_REG_HINT_MASK_SET, - -/*============================================= - Host Interrupt Mask Clear 16bit,(Write only) - ------------------------------------------ - Setting a bit in this register clears - the corresponding bin in ACX_HINT_MASK register - without effecting the mask - state of other bits (0 = no effect). -=============================================*/ - ACX_REG_HINT_MASK_CLR, - -/*============================================= - Host Interrupt Status Nondestructive Read - 16bit,(Read only) - ------------------------------------------ - The host can read this register to determine - which interrupts are active. - Reading this register doesn't - effect its content. -=============================================*/ - ACX_REG_INTERRUPT_NO_CLEAR, - -/*============================================= - Host Interrupt Status Clear on Read Register - 16bit,(Read only) - ------------------------------------------ - The host can read this register to determine - which interrupts are active. - Reading this register clears it, - thus making all interrupts inactive. -==============================================*/ - ACX_REG_INTERRUPT_CLEAR, - -/*============================================= - Host Interrupt Acknowledge Register - 16bit,(Write only) - ------------------------------------------ - The host can set individual bits in this - register to clear (acknowledge) the corresp. - interrupt status bits in the HINT_STS_CLR and - HINT_STS_ND registers, thus making the - assotiated interrupt inactive. (0-no effect) -==============================================*/ - ACX_REG_INTERRUPT_ACK, - -/*=============================================== - Host Software Reset - 32bit RW - ------------------------------------------ - [31:1] Reserved - 0 SOFT_RESET Soft Reset - When this bit is set, - it holds the Wlan hardware in a soft reset state. - This reset disables all MAC and baseband processor - clocks except the CardBus/PCI interface clock. - It also initializes all MAC state machines except - the host interface. It does not reload the - contents of the EEPROM. When this bit is cleared - (not self-clearing), the Wlan hardware - exits the software reset state. -===============================================*/ - ACX_REG_SLV_SOFT_RESET, - -/*=============================================== - EEPROM Burst Read Start - 32bit RW - ------------------------------------------ - [31:1] Reserved - 0 ACX_EE_START - EEPROM Burst Read Start 0 - Setting this bit starts a burst read from - the external EEPROM. - If this bit is set (after reset) before an EEPROM read/write, - the burst read starts at EEPROM address 0. - Otherwise, it starts at the address - following the address of the previous access. - TheWlan hardware hardware clears this bit automatically. - - Default: 0x00000000 -*================================================*/ - ACX_REG_EE_START, - -/* Embedded ARM CPU Control */ - -/*=============================================== - Halt eCPU - 32bit RW - ------------------------------------------ - 0 HALT_ECPU Halt Embedded CPU - This bit is the - compliment of bit 1 (MDATA2) in the SOR_CFG register. - During a hardware reset, this bit holds - the inverse of MDATA2. - When downloading firmware from the host, - set this bit (pull down MDATA2). - The host clears this bit after downloading the firmware into - zero-wait-state SSRAM. - When loading firmware from Flash, clear this bit (pull up MDATA2) - so that the eCPU can run the bootloader code in Flash - HALT_ECPU eCPU State - -------------------- - 1 halt eCPU - 0 enable eCPU - ===============================================*/ - ACX_REG_ECPU_CONTROL, - - ACX_REG_TABLE_LEN -}; - -#define ACX_SLV_SOFT_RESET_BIT BIT(1) -#define ACX_REG_EEPROM_START_BIT BIT(1) - -/* Command/Information Mailbox Pointers */ - -/*=============================================== - Command Mailbox Pointer - 32bit RW - ------------------------------------------ - This register holds the start address of - the command mailbox located in the Wlan hardware memory. - The host must read this pointer after a reset to - find the location of the command mailbox. - The Wlan hardware initializes the command mailbox - pointer with the default address of the command mailbox. - The command mailbox pointer is not valid until after - the host receives the Init Complete interrupt from - the Wlan hardware. - ===============================================*/ -#define REG_COMMAND_MAILBOX_PTR (SCR_PAD0) - -/*=============================================== - Information Mailbox Pointer - 32bit RW - ------------------------------------------ - This register holds the start address of - the information mailbox located in the Wlan hardware memory. - The host must read this pointer after a reset to find - the location of the information mailbox. - The Wlan hardware initializes the information mailbox pointer - with the default address of the information mailbox. - The information mailbox pointer is not valid - until after the host receives the Init Complete interrupt from - the Wlan hardware. - ===============================================*/ -#define REG_EVENT_MAILBOX_PTR (SCR_PAD1) - - -/* Misc */ - -#define REG_ENABLE_TX_RX (ENABLE) -/* - * Rx configuration (filter) information element - * --------------------------------------------- - */ -#define REG_RX_CONFIG (RX_CFG) -#define REG_RX_FILTER (RX_FILTER_CFG) - - -#define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002 - -/* promiscuous - receives all valid frames */ -#define RX_CFG_PROMISCUOUS 0x0008 - -/* receives frames from any BSSID */ -#define RX_CFG_BSSID 0x0020 - -/* receives frames destined to any MAC address */ -#define RX_CFG_MAC 0x0010 - -#define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010 -#define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000 -#define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020 -#define RX_CFG_ENABLE_ANY_BSSID 0x0000 - -/* discards all broadcast frames */ -#define RX_CFG_DISABLE_BCAST 0x0200 - -#define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400 -#define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800 -#define RX_CFG_COPY_RX_STATUS 0x2000 -#define RX_CFG_TSF 0x10000 - -#define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ - RX_CFG_ENABLE_ONLY_MY_BSSID) - -#define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ - | RX_CFG_ENABLE_ANY_BSSID) - -#define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ - RX_CFG_ENABLE_ANY_BSSID) - -#define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ - | RX_CFG_ENABLE_ONLY_MY_BSSID) - -#define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \ - | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \ - | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF) - -#define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC) - -#define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \ - RX_CFG_ENABLE_ONLY_MY_DEST_MAC) - -#define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \ - RX_CFG_ENABLE_ONLY_MY_DEST_MAC) - -#define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ - | CFG_RX_CTL_EN | CFG_RX_BCN_EN\ - | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) - -#define RX_FILTER_OPTION_FILTER_ALL 0 - -#define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\ - | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN) - -#define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ - | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\ - | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\ - | CFG_RX_PRSP_EN) - - -/*=============================================== - Phy regs - ===============================================*/ -#define ACX_PHY_ADDR_REG SBB_ADDR -#define ACX_PHY_DATA_REG SBB_DATA -#define ACX_PHY_CTRL_REG SBB_CTL -#define ACX_PHY_REG_WR_MASK 0x00000001ul -#define ACX_PHY_REG_RD_MASK 0x00000002ul - - -/*=============================================== - EEPROM Read/Write Request 32bit RW - ------------------------------------------ - 1 EE_READ - EEPROM Read Request 1 - Setting this bit - loads a single byte of data into the EE_DATA - register from the EEPROM location specified in - the EE_ADDR register. - The Wlan hardware hardware clears this bit automatically. - EE_DATA is valid when this bit is cleared. - - 0 EE_WRITE - EEPROM Write Request - Setting this bit - writes a single byte of data from the EE_DATA register into the - EEPROM location specified in the EE_ADDR register. - The Wlan hardware hardware clears this bit automatically. -*===============================================*/ -#define ACX_EE_CTL_REG EE_CTL -#define EE_WRITE 0x00000001ul -#define EE_READ 0x00000002ul - -/*=============================================== - EEPROM Address - 32bit RW - ------------------------------------------ - This register specifies the address - within the EEPROM from/to which to read/write data. - ===============================================*/ -#define ACX_EE_ADDR_REG EE_ADDR - -/*=============================================== - EEPROM Data - 32bit RW - ------------------------------------------ - This register either holds the read 8 bits of - data from the EEPROM or the write data - to be written to the EEPROM. - ===============================================*/ -#define ACX_EE_DATA_REG EE_DATA - -/*=============================================== - EEPROM Base Address - 32bit RW - ------------------------------------------ - This register holds the upper nine bits - [23:15] of the 24-bit Wlan hardware memory - address for burst reads from EEPROM accesses. - The EEPROM provides the lower 15 bits of this address. - The MSB of the address from the EEPROM is ignored. - ===============================================*/ -#define ACX_EE_CFG EE_CFG - -/*=============================================== - GPIO Output Values -32bit, RW - ------------------------------------------ - [31:16] Reserved - [15: 0] Specify the output values (at the output driver inputs) for - GPIO[15:0], respectively. - ===============================================*/ -#define ACX_GPIO_OUT_REG GPIO_OUT -#define ACX_MAX_GPIO_LINES 15 - -/*=============================================== - Contention window -32bit, RW - ------------------------------------------ - [31:26] Reserved - [25:16] Max (0x3ff) - [15:07] Reserved - [06:00] Current contention window value - default is 0x1F - ===============================================*/ -#define ACX_CONT_WIND_CFG_REG CONT_WIND_CFG -#define ACX_CONT_WIND_MIN_MASK 0x0000007f -#define ACX_CONT_WIND_MAX 0x03ff0000 - -/* - * Indirect slave register/memory registers - * ---------------------------------------- - */ -#define HW_SLAVE_REG_ADDR_REG 0x00000004 -#define HW_SLAVE_REG_DATA_REG 0x00000008 -#define HW_SLAVE_REG_CTRL_REG 0x0000000c - -#define SLAVE_AUTO_INC 0x00010000 -#define SLAVE_NO_AUTO_INC 0x00000000 -#define SLAVE_HOST_LITTLE_ENDIAN 0x00000000 - -#define HW_SLAVE_MEM_ADDR_REG SLV_MEM_ADDR -#define HW_SLAVE_MEM_DATA_REG SLV_MEM_DATA -#define HW_SLAVE_MEM_CTRL_REG SLV_MEM_CTL -#define HW_SLAVE_MEM_ENDIAN_REG SLV_END_CTL - -#define HW_FUNC_EVENT_INT_EN 0x8000 -#define HW_FUNC_EVENT_MASK_REG 0x00000034 - -#define ACX_MAC_TIMESTAMP_REG (MAC_TIMESTAMP) - -/*=============================================== - HI_CFG Interface Configuration Register Values - ------------------------------------------ - ===============================================*/ -#define HI_CFG_UART_ENABLE 0x00000004 -#define HI_CFG_RST232_ENABLE 0x00000008 -#define HI_CFG_CLOCK_REQ_SELECT 0x00000010 -#define HI_CFG_HOST_INT_ENABLE 0x00000020 -#define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040 -#define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080 -#define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100 -#define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 -#define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 - -/* - * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile - * for platforms using active high interrupt level - */ -#ifdef USE_ACTIVE_HIGH -#define HI_CFG_DEF_VAL \ - (HI_CFG_UART_ENABLE | \ - HI_CFG_RST232_ENABLE | \ - HI_CFG_CLOCK_REQ_SELECT | \ - HI_CFG_HOST_INT_ENABLE) -#else -#define HI_CFG_DEF_VAL \ - (HI_CFG_UART_ENABLE | \ - HI_CFG_RST232_ENABLE | \ - HI_CFG_CLOCK_REQ_SELECT | \ - HI_CFG_HOST_INT_ENABLE) - -#endif - -#define REF_FREQ_19_2 0 -#define REF_FREQ_26_0 1 -#define REF_FREQ_38_4 2 -#define REF_FREQ_40_0 3 -#define REF_FREQ_33_6 4 -#define REF_FREQ_NUM 5 - -#define LUT_PARAM_INTEGER_DIVIDER 0 -#define LUT_PARAM_FRACTIONAL_DIVIDER 1 -#define LUT_PARAM_ATTN_BB 2 -#define LUT_PARAM_ALPHA_BB 3 -#define LUT_PARAM_STOP_TIME_BB 4 -#define LUT_PARAM_BB_PLL_LOOP_FILTER 5 -#define LUT_PARAM_NUM 6 - -#define ACX_EEPROMLESS_IND_REG (SCR_PAD4) -#define USE_EEPROM 0 -#define SOFT_RESET_MAX_TIME 1000000 -#define SOFT_RESET_STALL_TIME 1000 -#define NVS_DATA_BUNDARY_ALIGNMENT 4 - - -/* Firmware image load chunk size */ -#define CHUNK_SIZE 512 - -/* Firmware image header size */ -#define FW_HDR_SIZE 8 - -#define ECPU_CONTROL_HALT 0x00000101 - - -/****************************************************************************** - - CHANNELS, BAND & REG DOMAINS definitions - -******************************************************************************/ - - -enum { - RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */ - RADIO_BAND_5GHZ = 1, /* 5 Ghz band */ - RADIO_BAND_JAPAN_4_9_GHZ = 2, - DEFAULT_BAND = RADIO_BAND_2_4GHZ, - INVALID_BAND = 0xFE, - MAX_RADIO_BANDS = 0xFF -}; - -enum { - NO_RATE = 0, - RATE_1MBPS = 0x0A, - RATE_2MBPS = 0x14, - RATE_5_5MBPS = 0x37, - RATE_6MBPS = 0x0B, - RATE_9MBPS = 0x0F, - RATE_11MBPS = 0x6E, - RATE_12MBPS = 0x0A, - RATE_18MBPS = 0x0E, - RATE_22MBPS = 0xDC, - RATE_24MBPS = 0x09, - RATE_36MBPS = 0x0D, - RATE_48MBPS = 0x08, - RATE_54MBPS = 0x0C -}; - -enum { - RATE_INDEX_1MBPS = 0, - RATE_INDEX_2MBPS = 1, - RATE_INDEX_5_5MBPS = 2, - RATE_INDEX_6MBPS = 3, - RATE_INDEX_9MBPS = 4, - RATE_INDEX_11MBPS = 5, - RATE_INDEX_12MBPS = 6, - RATE_INDEX_18MBPS = 7, - RATE_INDEX_22MBPS = 8, - RATE_INDEX_24MBPS = 9, - RATE_INDEX_36MBPS = 10, - RATE_INDEX_48MBPS = 11, - RATE_INDEX_54MBPS = 12, - RATE_INDEX_MAX = RATE_INDEX_54MBPS, - MAX_RATE_INDEX, - INVALID_RATE_INDEX = MAX_RATE_INDEX, - RATE_INDEX_ENUM_MAX_SIZE = 0x7FFFFFFF -}; - -enum { - RATE_MASK_1MBPS = 0x1, - RATE_MASK_2MBPS = 0x2, - RATE_MASK_5_5MBPS = 0x4, - RATE_MASK_11MBPS = 0x20, -}; - -#define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ -#define OFDM_RATE_BIT BIT(6) -#define PBCC_RATE_BIT BIT(7) - -enum { - CCK_LONG = 0, - CCK_SHORT = SHORT_PREAMBLE_BIT, - PBCC_LONG = PBCC_RATE_BIT, - PBCC_SHORT = PBCC_RATE_BIT | SHORT_PREAMBLE_BIT, - OFDM = OFDM_RATE_BIT -}; - -/****************************************************************************** - -Transmit-Descriptor RATE-SET field definitions... - -Define a new "Rate-Set" for TX path that incorporates the -Rate & Modulation info into a single 16-bit field. - -TxdRateSet_t: -b15 - Indicates Preamble type (1=SHORT, 0=LONG). - Notes: - Must be LONG (0) for 1Mbps rate. - Does not apply (set to 0) for RevG-OFDM rates. -b14 - Indicates PBCC encoding (1=PBCC, 0=not). - Notes: - Does not apply (set to 0) for rates 1 and 2 Mbps. - Does not apply (set to 0) for RevG-OFDM rates. -b13 - Unused (set to 0). -b12-b0 - Supported Rate indicator bits as defined below. - -******************************************************************************/ - - -#define TNETW1251_CHIP_ID_PG1_0 0x07010101 -#define TNETW1251_CHIP_ID_PG1_1 0x07020101 -#define TNETW1251_CHIP_ID_PG1_2 0x07030101 - -/************************************************************************* - - Interrupt Trigger Register (Host -> WiLink) - -**************************************************************************/ - -/* Hardware to Embedded CPU Interrupts - first 32-bit register set */ - -/* - * Host Command Interrupt. Setting this bit masks - * the interrupt that the host issues to inform - * the FW that it has sent a command - * to the Wlan hardware Command Mailbox. - */ -#define INTR_TRIG_CMD BIT(0) - -/* - * Host Event Acknowlegde Interrupt. The host - * sets this bit to acknowledge that it received - * the unsolicited information from the event - * mailbox. - */ -#define INTR_TRIG_EVENT_ACK BIT(1) - -/* - * The host sets this bit to inform the Wlan - * FW that a TX packet is in the XFER - * Buffer #0. - */ -#define INTR_TRIG_TX_PROC0 BIT(2) - -/* - * The host sets this bit to inform the FW - * that it read a packet from RX XFER - * Buffer #0. - */ -#define INTR_TRIG_RX_PROC0 BIT(3) - -#define INTR_TRIG_DEBUG_ACK BIT(4) - -#define INTR_TRIG_STATE_CHANGED BIT(5) - - -/* Hardware to Embedded CPU Interrupts - second 32-bit register set */ - -/* - * The host sets this bit to inform the FW - * that it read a packet from RX XFER - * Buffer #1. - */ -#define INTR_TRIG_RX_PROC1 BIT(17) - -/* - * The host sets this bit to inform the Wlan - * hardware that a TX packet is in the XFER - * Buffer #1. - */ -#define INTR_TRIG_TX_PROC1 BIT(18) - -#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index 0a225c62c97..10b26c4532c 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -4,7 +4,7 @@ #include #include "wl1251.h" -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_cmd.h" #include "wl1251_ps.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index 88e9cb0947d..592c3b5cc8f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -23,7 +23,7 @@ #include -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_boot.h" #include "wl1251_io.h" #include "wl1251_spi.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index 74ea1fdf9bd..6cd024b50a7 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -4,7 +4,7 @@ #include #include "wl1251.h" -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_io.h" #include "wl1251_ps.h" #include "wl1251_acx.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl12xx/wl1251_event.c index 1b4f8d2850c..7bd1b6aa699 100644 --- a/drivers/net/wireless/wl12xx/wl1251_event.c +++ b/drivers/net/wireless/wl12xx/wl1251_event.c @@ -23,7 +23,7 @@ */ #include "wl1251.h" -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_io.h" #include "wl1251_event.h" #include "wl1251_ps.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c index 1c587eceacc..b2ee4f468fc 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.c +++ b/drivers/net/wireless/wl12xx/wl1251_init.c @@ -28,7 +28,7 @@ #include "wl12xx_80211.h" #include "wl1251_acx.h" #include "wl1251_cmd.h" -#include "reg.h" +#include "wl1251_reg.h" int wl1251_hw_init_hwenc_config(struct wl1251 *wl) { diff --git a/drivers/net/wireless/wl12xx/wl1251_io.c b/drivers/net/wireless/wl12xx/wl1251_io.c index 04e486c275c..f1c232e0887 100644 --- a/drivers/net/wireless/wl12xx/wl1251_io.c +++ b/drivers/net/wireless/wl12xx/wl1251_io.c @@ -22,7 +22,7 @@ */ #include "wl1251.h" -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_io.h" /* FIXME: this is static data nowadays and the table can be removed */ diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index c5f2d9dbd1a..3fe8b65e186 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -31,7 +31,7 @@ #include "wl1251.h" #include "wl12xx_80211.h" -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_io.h" #include "wl1251_cmd.h" #include "wl1251_event.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c index 36acde0b3bd..c53e28727ed 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.c +++ b/drivers/net/wireless/wl12xx/wl1251_ps.c @@ -21,7 +21,7 @@ * */ -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_ps.h" #include "wl1251_cmd.h" #include "wl1251_io.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_reg.h b/drivers/net/wireless/wl12xx/wl1251_reg.h new file mode 100644 index 00000000000..2de47cc32b8 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251_reg.h @@ -0,0 +1,744 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __REG_H__ +#define __REG_H__ + +#include + +#define REGISTERS_BASE 0x00300000 +#define DRPW_BASE 0x00310000 + +#define REGISTERS_DOWN_SIZE 0x00008800 +#define REGISTERS_WORK_SIZE 0x0000b000 + +#define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC + +/* ELP register commands */ +#define ELPCTRL_WAKE_UP 0x1 +#define ELPCTRL_WAKE_UP_WLAN_READY 0x5 +#define ELPCTRL_SLEEP 0x0 +/* ELP WLAN_READY bit */ +#define ELPCTRL_WLAN_READY 0x2 + +/* + * Interrupt registers. + * 64 bit interrupt sources registers ws ced. + * sme interupts were removed and new ones were added. + * Order was changed. + */ +#define FIQ_MASK (REGISTERS_BASE + 0x0400) +#define FIQ_MASK_L (REGISTERS_BASE + 0x0400) +#define FIQ_MASK_H (REGISTERS_BASE + 0x0404) +#define FIQ_MASK_SET (REGISTERS_BASE + 0x0408) +#define FIQ_MASK_SET_L (REGISTERS_BASE + 0x0408) +#define FIQ_MASK_SET_H (REGISTERS_BASE + 0x040C) +#define FIQ_MASK_CLR (REGISTERS_BASE + 0x0410) +#define FIQ_MASK_CLR_L (REGISTERS_BASE + 0x0410) +#define FIQ_MASK_CLR_H (REGISTERS_BASE + 0x0414) +#define IRQ_MASK (REGISTERS_BASE + 0x0418) +#define IRQ_MASK_L (REGISTERS_BASE + 0x0418) +#define IRQ_MASK_H (REGISTERS_BASE + 0x041C) +#define IRQ_MASK_SET (REGISTERS_BASE + 0x0420) +#define IRQ_MASK_SET_L (REGISTERS_BASE + 0x0420) +#define IRQ_MASK_SET_H (REGISTERS_BASE + 0x0424) +#define IRQ_MASK_CLR (REGISTERS_BASE + 0x0428) +#define IRQ_MASK_CLR_L (REGISTERS_BASE + 0x0428) +#define IRQ_MASK_CLR_H (REGISTERS_BASE + 0x042C) +#define ECPU_MASK (REGISTERS_BASE + 0x0448) +#define FIQ_STS_L (REGISTERS_BASE + 0x044C) +#define FIQ_STS_H (REGISTERS_BASE + 0x0450) +#define IRQ_STS_L (REGISTERS_BASE + 0x0454) +#define IRQ_STS_H (REGISTERS_BASE + 0x0458) +#define INT_STS_ND (REGISTERS_BASE + 0x0464) +#define INT_STS_RAW_L (REGISTERS_BASE + 0x0464) +#define INT_STS_RAW_H (REGISTERS_BASE + 0x0468) +#define INT_STS_CLR (REGISTERS_BASE + 0x04B4) +#define INT_STS_CLR_L (REGISTERS_BASE + 0x04B4) +#define INT_STS_CLR_H (REGISTERS_BASE + 0x04B8) +#define INT_ACK (REGISTERS_BASE + 0x046C) +#define INT_ACK_L (REGISTERS_BASE + 0x046C) +#define INT_ACK_H (REGISTERS_BASE + 0x0470) +#define INT_TRIG (REGISTERS_BASE + 0x0474) +#define INT_TRIG_L (REGISTERS_BASE + 0x0474) +#define INT_TRIG_H (REGISTERS_BASE + 0x0478) +#define HOST_STS_L (REGISTERS_BASE + 0x045C) +#define HOST_STS_H (REGISTERS_BASE + 0x0460) +#define HOST_MASK (REGISTERS_BASE + 0x0430) +#define HOST_MASK_L (REGISTERS_BASE + 0x0430) +#define HOST_MASK_H (REGISTERS_BASE + 0x0434) +#define HOST_MASK_SET (REGISTERS_BASE + 0x0438) +#define HOST_MASK_SET_L (REGISTERS_BASE + 0x0438) +#define HOST_MASK_SET_H (REGISTERS_BASE + 0x043C) +#define HOST_MASK_CLR (REGISTERS_BASE + 0x0440) +#define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440) +#define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444) + +/* Host Interrupts*/ +#define HINT_MASK (REGISTERS_BASE + 0x0494) +#define HINT_MASK_SET (REGISTERS_BASE + 0x0498) +#define HINT_MASK_CLR (REGISTERS_BASE + 0x049C) +#define HINT_STS_ND_MASKED (REGISTERS_BASE + 0x04A0) +/*1150 spec calls this HINT_STS_RAW*/ +#define HINT_STS_ND (REGISTERS_BASE + 0x04B0) +#define HINT_STS_CLR (REGISTERS_BASE + 0x04A4) +#define HINT_ACK (REGISTERS_BASE + 0x04A8) +#define HINT_TRIG (REGISTERS_BASE + 0x04AC) + +/* Device Configuration registers*/ +#define SOR_CFG (REGISTERS_BASE + 0x0800) +#define ECPU_CTRL (REGISTERS_BASE + 0x0804) +#define HI_CFG (REGISTERS_BASE + 0x0808) +#define EE_START (REGISTERS_BASE + 0x080C) + +#define CHIP_ID_B (REGISTERS_BASE + 0x5674) + +#define CHIP_ID_1251_PG10 (0x7010101) +#define CHIP_ID_1251_PG11 (0x7020101) +#define CHIP_ID_1251_PG12 (0x7030101) + +#define ENABLE (REGISTERS_BASE + 0x5450) + +/* Power Management registers */ +#define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) +#define ELP_CMD (REGISTERS_BASE + 0x5808) +#define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) +#define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) +#define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) + +#define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) + +/* Scratch Pad registers*/ +#define SCR_PAD0 (REGISTERS_BASE + 0x5608) +#define SCR_PAD1 (REGISTERS_BASE + 0x560C) +#define SCR_PAD2 (REGISTERS_BASE + 0x5610) +#define SCR_PAD3 (REGISTERS_BASE + 0x5614) +#define SCR_PAD4 (REGISTERS_BASE + 0x5618) +#define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) +#define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) +#define SCR_PAD5 (REGISTERS_BASE + 0x5624) +#define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) +#define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) +#define SCR_PAD6 (REGISTERS_BASE + 0x5630) +#define SCR_PAD7 (REGISTERS_BASE + 0x5634) +#define SCR_PAD8 (REGISTERS_BASE + 0x5638) +#define SCR_PAD9 (REGISTERS_BASE + 0x563C) + +/* Spare registers*/ +#define SPARE_A1 (REGISTERS_BASE + 0x0994) +#define SPARE_A2 (REGISTERS_BASE + 0x0998) +#define SPARE_A3 (REGISTERS_BASE + 0x099C) +#define SPARE_A4 (REGISTERS_BASE + 0x09A0) +#define SPARE_A5 (REGISTERS_BASE + 0x09A4) +#define SPARE_A6 (REGISTERS_BASE + 0x09A8) +#define SPARE_A7 (REGISTERS_BASE + 0x09AC) +#define SPARE_A8 (REGISTERS_BASE + 0x09B0) +#define SPARE_B1 (REGISTERS_BASE + 0x5420) +#define SPARE_B2 (REGISTERS_BASE + 0x5424) +#define SPARE_B3 (REGISTERS_BASE + 0x5428) +#define SPARE_B4 (REGISTERS_BASE + 0x542C) +#define SPARE_B5 (REGISTERS_BASE + 0x5430) +#define SPARE_B6 (REGISTERS_BASE + 0x5434) +#define SPARE_B7 (REGISTERS_BASE + 0x5438) +#define SPARE_B8 (REGISTERS_BASE + 0x543C) + +enum wl12xx_acx_int_reg { + ACX_REG_INTERRUPT_TRIG, + ACX_REG_INTERRUPT_TRIG_H, + +/*============================================= + Host Interrupt Mask Register - 32bit (RW) + ------------------------------------------ + Setting a bit in this register masks the + corresponding interrupt to the host. + 0 - RX0 - Rx first dubble buffer Data Interrupt + 1 - TXD - Tx Data Interrupt + 2 - TXXFR - Tx Transfer Interrupt + 3 - RX1 - Rx second dubble buffer Data Interrupt + 4 - RXXFR - Rx Transfer Interrupt + 5 - EVENT_A - Event Mailbox interrupt + 6 - EVENT_B - Event Mailbox interrupt + 7 - WNONHST - Wake On Host Interrupt + 8 - TRACE_A - Debug Trace interrupt + 9 - TRACE_B - Debug Trace interrupt + 10 - CDCMP - Command Complete Interrupt + 11 - + 12 - + 13 - + 14 - ICOMP - Initialization Complete Interrupt + 16 - SG SE - Soft Gemini - Sense enable interrupt + 17 - SG SD - Soft Gemini - Sense disable interrupt + 18 - - + 19 - - + 20 - - + 21- - + Default: 0x0001 +*==============================================*/ + ACX_REG_INTERRUPT_MASK, + +/*============================================= + Host Interrupt Mask Set 16bit, (Write only) + ------------------------------------------ + Setting a bit in this register sets + the corresponding bin in ACX_HINT_MASK register + without effecting the mask + state of other bits (0 = no effect). +==============================================*/ + ACX_REG_HINT_MASK_SET, + +/*============================================= + Host Interrupt Mask Clear 16bit,(Write only) + ------------------------------------------ + Setting a bit in this register clears + the corresponding bin in ACX_HINT_MASK register + without effecting the mask + state of other bits (0 = no effect). +=============================================*/ + ACX_REG_HINT_MASK_CLR, + +/*============================================= + Host Interrupt Status Nondestructive Read + 16bit,(Read only) + ------------------------------------------ + The host can read this register to determine + which interrupts are active. + Reading this register doesn't + effect its content. +=============================================*/ + ACX_REG_INTERRUPT_NO_CLEAR, + +/*============================================= + Host Interrupt Status Clear on Read Register + 16bit,(Read only) + ------------------------------------------ + The host can read this register to determine + which interrupts are active. + Reading this register clears it, + thus making all interrupts inactive. +==============================================*/ + ACX_REG_INTERRUPT_CLEAR, + +/*============================================= + Host Interrupt Acknowledge Register + 16bit,(Write only) + ------------------------------------------ + The host can set individual bits in this + register to clear (acknowledge) the corresp. + interrupt status bits in the HINT_STS_CLR and + HINT_STS_ND registers, thus making the + assotiated interrupt inactive. (0-no effect) +==============================================*/ + ACX_REG_INTERRUPT_ACK, + +/*=============================================== + Host Software Reset - 32bit RW + ------------------------------------------ + [31:1] Reserved + 0 SOFT_RESET Soft Reset - When this bit is set, + it holds the Wlan hardware in a soft reset state. + This reset disables all MAC and baseband processor + clocks except the CardBus/PCI interface clock. + It also initializes all MAC state machines except + the host interface. It does not reload the + contents of the EEPROM. When this bit is cleared + (not self-clearing), the Wlan hardware + exits the software reset state. +===============================================*/ + ACX_REG_SLV_SOFT_RESET, + +/*=============================================== + EEPROM Burst Read Start - 32bit RW + ------------------------------------------ + [31:1] Reserved + 0 ACX_EE_START - EEPROM Burst Read Start 0 + Setting this bit starts a burst read from + the external EEPROM. + If this bit is set (after reset) before an EEPROM read/write, + the burst read starts at EEPROM address 0. + Otherwise, it starts at the address + following the address of the previous access. + TheWlan hardware hardware clears this bit automatically. + + Default: 0x00000000 +*================================================*/ + ACX_REG_EE_START, + +/* Embedded ARM CPU Control */ + +/*=============================================== + Halt eCPU - 32bit RW + ------------------------------------------ + 0 HALT_ECPU Halt Embedded CPU - This bit is the + compliment of bit 1 (MDATA2) in the SOR_CFG register. + During a hardware reset, this bit holds + the inverse of MDATA2. + When downloading firmware from the host, + set this bit (pull down MDATA2). + The host clears this bit after downloading the firmware into + zero-wait-state SSRAM. + When loading firmware from Flash, clear this bit (pull up MDATA2) + so that the eCPU can run the bootloader code in Flash + HALT_ECPU eCPU State + -------------------- + 1 halt eCPU + 0 enable eCPU + ===============================================*/ + ACX_REG_ECPU_CONTROL, + + ACX_REG_TABLE_LEN +}; + +#define ACX_SLV_SOFT_RESET_BIT BIT(1) +#define ACX_REG_EEPROM_START_BIT BIT(1) + +/* Command/Information Mailbox Pointers */ + +/*=============================================== + Command Mailbox Pointer - 32bit RW + ------------------------------------------ + This register holds the start address of + the command mailbox located in the Wlan hardware memory. + The host must read this pointer after a reset to + find the location of the command mailbox. + The Wlan hardware initializes the command mailbox + pointer with the default address of the command mailbox. + The command mailbox pointer is not valid until after + the host receives the Init Complete interrupt from + the Wlan hardware. + ===============================================*/ +#define REG_COMMAND_MAILBOX_PTR (SCR_PAD0) + +/*=============================================== + Information Mailbox Pointer - 32bit RW + ------------------------------------------ + This register holds the start address of + the information mailbox located in the Wlan hardware memory. + The host must read this pointer after a reset to find + the location of the information mailbox. + The Wlan hardware initializes the information mailbox pointer + with the default address of the information mailbox. + The information mailbox pointer is not valid + until after the host receives the Init Complete interrupt from + the Wlan hardware. + ===============================================*/ +#define REG_EVENT_MAILBOX_PTR (SCR_PAD1) + + +/* Misc */ + +#define REG_ENABLE_TX_RX (ENABLE) +/* + * Rx configuration (filter) information element + * --------------------------------------------- + */ +#define REG_RX_CONFIG (RX_CFG) +#define REG_RX_FILTER (RX_FILTER_CFG) + + +#define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002 + +/* promiscuous - receives all valid frames */ +#define RX_CFG_PROMISCUOUS 0x0008 + +/* receives frames from any BSSID */ +#define RX_CFG_BSSID 0x0020 + +/* receives frames destined to any MAC address */ +#define RX_CFG_MAC 0x0010 + +#define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010 +#define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000 +#define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020 +#define RX_CFG_ENABLE_ANY_BSSID 0x0000 + +/* discards all broadcast frames */ +#define RX_CFG_DISABLE_BCAST 0x0200 + +#define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400 +#define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800 +#define RX_CFG_COPY_RX_STATUS 0x2000 +#define RX_CFG_TSF 0x10000 + +#define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ + RX_CFG_ENABLE_ONLY_MY_BSSID) + +#define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ + | RX_CFG_ENABLE_ANY_BSSID) + +#define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ + RX_CFG_ENABLE_ANY_BSSID) + +#define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ + | RX_CFG_ENABLE_ONLY_MY_BSSID) + +#define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \ + | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \ + | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF) + +#define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC) + +#define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \ + RX_CFG_ENABLE_ONLY_MY_DEST_MAC) + +#define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \ + RX_CFG_ENABLE_ONLY_MY_DEST_MAC) + +#define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ + | CFG_RX_CTL_EN | CFG_RX_BCN_EN\ + | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) + +#define RX_FILTER_OPTION_FILTER_ALL 0 + +#define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\ + | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN) + +#define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ + | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\ + | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\ + | CFG_RX_PRSP_EN) + + +/*=============================================== + Phy regs + ===============================================*/ +#define ACX_PHY_ADDR_REG SBB_ADDR +#define ACX_PHY_DATA_REG SBB_DATA +#define ACX_PHY_CTRL_REG SBB_CTL +#define ACX_PHY_REG_WR_MASK 0x00000001ul +#define ACX_PHY_REG_RD_MASK 0x00000002ul + + +/*=============================================== + EEPROM Read/Write Request 32bit RW + ------------------------------------------ + 1 EE_READ - EEPROM Read Request 1 - Setting this bit + loads a single byte of data into the EE_DATA + register from the EEPROM location specified in + the EE_ADDR register. + The Wlan hardware hardware clears this bit automatically. + EE_DATA is valid when this bit is cleared. + + 0 EE_WRITE - EEPROM Write Request - Setting this bit + writes a single byte of data from the EE_DATA register into the + EEPROM location specified in the EE_ADDR register. + The Wlan hardware hardware clears this bit automatically. +*===============================================*/ +#define ACX_EE_CTL_REG EE_CTL +#define EE_WRITE 0x00000001ul +#define EE_READ 0x00000002ul + +/*=============================================== + EEPROM Address - 32bit RW + ------------------------------------------ + This register specifies the address + within the EEPROM from/to which to read/write data. + ===============================================*/ +#define ACX_EE_ADDR_REG EE_ADDR + +/*=============================================== + EEPROM Data - 32bit RW + ------------------------------------------ + This register either holds the read 8 bits of + data from the EEPROM or the write data + to be written to the EEPROM. + ===============================================*/ +#define ACX_EE_DATA_REG EE_DATA + +/*=============================================== + EEPROM Base Address - 32bit RW + ------------------------------------------ + This register holds the upper nine bits + [23:15] of the 24-bit Wlan hardware memory + address for burst reads from EEPROM accesses. + The EEPROM provides the lower 15 bits of this address. + The MSB of the address from the EEPROM is ignored. + ===============================================*/ +#define ACX_EE_CFG EE_CFG + +/*=============================================== + GPIO Output Values -32bit, RW + ------------------------------------------ + [31:16] Reserved + [15: 0] Specify the output values (at the output driver inputs) for + GPIO[15:0], respectively. + ===============================================*/ +#define ACX_GPIO_OUT_REG GPIO_OUT +#define ACX_MAX_GPIO_LINES 15 + +/*=============================================== + Contention window -32bit, RW + ------------------------------------------ + [31:26] Reserved + [25:16] Max (0x3ff) + [15:07] Reserved + [06:00] Current contention window value - default is 0x1F + ===============================================*/ +#define ACX_CONT_WIND_CFG_REG CONT_WIND_CFG +#define ACX_CONT_WIND_MIN_MASK 0x0000007f +#define ACX_CONT_WIND_MAX 0x03ff0000 + +/* + * Indirect slave register/memory registers + * ---------------------------------------- + */ +#define HW_SLAVE_REG_ADDR_REG 0x00000004 +#define HW_SLAVE_REG_DATA_REG 0x00000008 +#define HW_SLAVE_REG_CTRL_REG 0x0000000c + +#define SLAVE_AUTO_INC 0x00010000 +#define SLAVE_NO_AUTO_INC 0x00000000 +#define SLAVE_HOST_LITTLE_ENDIAN 0x00000000 + +#define HW_SLAVE_MEM_ADDR_REG SLV_MEM_ADDR +#define HW_SLAVE_MEM_DATA_REG SLV_MEM_DATA +#define HW_SLAVE_MEM_CTRL_REG SLV_MEM_CTL +#define HW_SLAVE_MEM_ENDIAN_REG SLV_END_CTL + +#define HW_FUNC_EVENT_INT_EN 0x8000 +#define HW_FUNC_EVENT_MASK_REG 0x00000034 + +#define ACX_MAC_TIMESTAMP_REG (MAC_TIMESTAMP) + +/*=============================================== + HI_CFG Interface Configuration Register Values + ------------------------------------------ + ===============================================*/ +#define HI_CFG_UART_ENABLE 0x00000004 +#define HI_CFG_RST232_ENABLE 0x00000008 +#define HI_CFG_CLOCK_REQ_SELECT 0x00000010 +#define HI_CFG_HOST_INT_ENABLE 0x00000020 +#define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040 +#define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080 +#define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100 +#define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 +#define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 + +/* + * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile + * for platforms using active high interrupt level + */ +#ifdef USE_ACTIVE_HIGH +#define HI_CFG_DEF_VAL \ + (HI_CFG_UART_ENABLE | \ + HI_CFG_RST232_ENABLE | \ + HI_CFG_CLOCK_REQ_SELECT | \ + HI_CFG_HOST_INT_ENABLE) +#else +#define HI_CFG_DEF_VAL \ + (HI_CFG_UART_ENABLE | \ + HI_CFG_RST232_ENABLE | \ + HI_CFG_CLOCK_REQ_SELECT | \ + HI_CFG_HOST_INT_ENABLE) + +#endif + +#define REF_FREQ_19_2 0 +#define REF_FREQ_26_0 1 +#define REF_FREQ_38_4 2 +#define REF_FREQ_40_0 3 +#define REF_FREQ_33_6 4 +#define REF_FREQ_NUM 5 + +#define LUT_PARAM_INTEGER_DIVIDER 0 +#define LUT_PARAM_FRACTIONAL_DIVIDER 1 +#define LUT_PARAM_ATTN_BB 2 +#define LUT_PARAM_ALPHA_BB 3 +#define LUT_PARAM_STOP_TIME_BB 4 +#define LUT_PARAM_BB_PLL_LOOP_FILTER 5 +#define LUT_PARAM_NUM 6 + +#define ACX_EEPROMLESS_IND_REG (SCR_PAD4) +#define USE_EEPROM 0 +#define SOFT_RESET_MAX_TIME 1000000 +#define SOFT_RESET_STALL_TIME 1000 +#define NVS_DATA_BUNDARY_ALIGNMENT 4 + + +/* Firmware image load chunk size */ +#define CHUNK_SIZE 512 + +/* Firmware image header size */ +#define FW_HDR_SIZE 8 + +#define ECPU_CONTROL_HALT 0x00000101 + + +/****************************************************************************** + + CHANNELS, BAND & REG DOMAINS definitions + +******************************************************************************/ + + +enum { + RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */ + RADIO_BAND_5GHZ = 1, /* 5 Ghz band */ + RADIO_BAND_JAPAN_4_9_GHZ = 2, + DEFAULT_BAND = RADIO_BAND_2_4GHZ, + INVALID_BAND = 0xFE, + MAX_RADIO_BANDS = 0xFF +}; + +enum { + NO_RATE = 0, + RATE_1MBPS = 0x0A, + RATE_2MBPS = 0x14, + RATE_5_5MBPS = 0x37, + RATE_6MBPS = 0x0B, + RATE_9MBPS = 0x0F, + RATE_11MBPS = 0x6E, + RATE_12MBPS = 0x0A, + RATE_18MBPS = 0x0E, + RATE_22MBPS = 0xDC, + RATE_24MBPS = 0x09, + RATE_36MBPS = 0x0D, + RATE_48MBPS = 0x08, + RATE_54MBPS = 0x0C +}; + +enum { + RATE_INDEX_1MBPS = 0, + RATE_INDEX_2MBPS = 1, + RATE_INDEX_5_5MBPS = 2, + RATE_INDEX_6MBPS = 3, + RATE_INDEX_9MBPS = 4, + RATE_INDEX_11MBPS = 5, + RATE_INDEX_12MBPS = 6, + RATE_INDEX_18MBPS = 7, + RATE_INDEX_22MBPS = 8, + RATE_INDEX_24MBPS = 9, + RATE_INDEX_36MBPS = 10, + RATE_INDEX_48MBPS = 11, + RATE_INDEX_54MBPS = 12, + RATE_INDEX_MAX = RATE_INDEX_54MBPS, + MAX_RATE_INDEX, + INVALID_RATE_INDEX = MAX_RATE_INDEX, + RATE_INDEX_ENUM_MAX_SIZE = 0x7FFFFFFF +}; + +enum { + RATE_MASK_1MBPS = 0x1, + RATE_MASK_2MBPS = 0x2, + RATE_MASK_5_5MBPS = 0x4, + RATE_MASK_11MBPS = 0x20, +}; + +#define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ +#define OFDM_RATE_BIT BIT(6) +#define PBCC_RATE_BIT BIT(7) + +enum { + CCK_LONG = 0, + CCK_SHORT = SHORT_PREAMBLE_BIT, + PBCC_LONG = PBCC_RATE_BIT, + PBCC_SHORT = PBCC_RATE_BIT | SHORT_PREAMBLE_BIT, + OFDM = OFDM_RATE_BIT +}; + +/****************************************************************************** + +Transmit-Descriptor RATE-SET field definitions... + +Define a new "Rate-Set" for TX path that incorporates the +Rate & Modulation info into a single 16-bit field. + +TxdRateSet_t: +b15 - Indicates Preamble type (1=SHORT, 0=LONG). + Notes: + Must be LONG (0) for 1Mbps rate. + Does not apply (set to 0) for RevG-OFDM rates. +b14 - Indicates PBCC encoding (1=PBCC, 0=not). + Notes: + Does not apply (set to 0) for rates 1 and 2 Mbps. + Does not apply (set to 0) for RevG-OFDM rates. +b13 - Unused (set to 0). +b12-b0 - Supported Rate indicator bits as defined below. + +******************************************************************************/ + + +#define TNETW1251_CHIP_ID_PG1_0 0x07010101 +#define TNETW1251_CHIP_ID_PG1_1 0x07020101 +#define TNETW1251_CHIP_ID_PG1_2 0x07030101 + +/************************************************************************* + + Interrupt Trigger Register (Host -> WiLink) + +**************************************************************************/ + +/* Hardware to Embedded CPU Interrupts - first 32-bit register set */ + +/* + * Host Command Interrupt. Setting this bit masks + * the interrupt that the host issues to inform + * the FW that it has sent a command + * to the Wlan hardware Command Mailbox. + */ +#define INTR_TRIG_CMD BIT(0) + +/* + * Host Event Acknowlegde Interrupt. The host + * sets this bit to acknowledge that it received + * the unsolicited information from the event + * mailbox. + */ +#define INTR_TRIG_EVENT_ACK BIT(1) + +/* + * The host sets this bit to inform the Wlan + * FW that a TX packet is in the XFER + * Buffer #0. + */ +#define INTR_TRIG_TX_PROC0 BIT(2) + +/* + * The host sets this bit to inform the FW + * that it read a packet from RX XFER + * Buffer #0. + */ +#define INTR_TRIG_RX_PROC0 BIT(3) + +#define INTR_TRIG_DEBUG_ACK BIT(4) + +#define INTR_TRIG_STATE_CHANGED BIT(5) + + +/* Hardware to Embedded CPU Interrupts - second 32-bit register set */ + +/* + * The host sets this bit to inform the FW + * that it read a packet from RX XFER + * Buffer #1. + */ +#define INTR_TRIG_RX_PROC1 BIT(17) + +/* + * The host sets this bit to inform the Wlan + * hardware that a TX packet is in the XFER + * Buffer #1. + */ +#define INTR_TRIG_TX_PROC1 BIT(18) + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c index af8187909c9..17c54b59ef8 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.c +++ b/drivers/net/wireless/wl12xx/wl1251_rx.c @@ -26,7 +26,7 @@ #include #include "wl1251.h" -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_io.h" #include "wl1251_rx.h" #include "wl1251_cmd.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c index 20668e244c6..9577ed610de 100644 --- a/drivers/net/wireless/wl12xx/wl1251_sdio.c +++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c @@ -29,7 +29,7 @@ #include "wl1251.h" #include "wl12xx_80211.h" -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_ps.h" #include "wl1251_io.h" #include "wl1251_tx.h" diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index e088334536a..612d5655e28 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -28,7 +28,7 @@ #include #include "wl1251.h" -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_spi.h" static irqreturn_t wl1251_irq(int irq, void *cookie) diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h index cb0c228dbc6..2e273a97e7f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.h +++ b/drivers/net/wireless/wl12xx/wl1251_spi.h @@ -27,7 +27,7 @@ #include "wl1251_cmd.h" #include "wl1251_acx.h" -#include "reg.h" +#include "wl1251_reg.h" #define WSPI_CMD_READ 0x40000000 #define WSPI_CMD_WRITE 0x00000000 diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c index f20bab61fd6..f8597061584 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.c +++ b/drivers/net/wireless/wl12xx/wl1251_tx.c @@ -26,7 +26,7 @@ #include #include "wl1251.h" -#include "reg.h" +#include "wl1251_reg.h" #include "wl1251_tx.h" #include "wl1251_ps.h" #include "wl1251_io.h" -- cgit v1.2.3-18-g5258 From b1b0a2b8b51fa3f0cd349f947a38ab4c6ab192c6 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:35:19 +0300 Subject: wl1251: remove Luciano as maintainer Luciano is maintaining wl1271 part. Signed-off-by: Kalle Valo Acked-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 3 +-- drivers/net/wireless/wl12xx/wl1251_sdio.c | 3 +-- drivers/net/wireless/wl12xx/wl1251_spi.c | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 3fe8b65e186..7148934e464 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -1427,5 +1427,4 @@ EXPORT_SYMBOL_GPL(wl1251_free_hw); MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core"); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kalle Valo "); -MODULE_AUTHOR("Luciano Coelho "); +MODULE_AUTHOR("Kalle Valo "); diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c index 9577ed610de..9423f22bdce 100644 --- a/drivers/net/wireless/wl12xx/wl1251_sdio.c +++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c @@ -202,5 +202,4 @@ module_init(wl1251_sdio_init); module_exit(wl1251_sdio_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kalle Valo "); -MODULE_AUTHOR("Luciano Coelho "); +MODULE_AUTHOR("Kalle Valo "); diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index 612d5655e28..14eff2b3d4c 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -341,5 +341,4 @@ module_init(wl1251_spi_init); module_exit(wl1251_spi_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kalle Valo "); -MODULE_AUTHOR("Luciano Coelho "); +MODULE_AUTHOR("Kalle Valo "); -- cgit v1.2.3-18-g5258 From 2789da9e58cc8db4e74359491a425712b5fcfdb6 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:35:26 +0300 Subject: wl1251: add hw scan completed debug message The logs currently don't show when hw scan has completed, fix that. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_event.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl12xx/wl1251_event.c index 7bd1b6aa699..00076c4a8a2 100644 --- a/drivers/net/wireless/wl12xx/wl1251_event.c +++ b/drivers/net/wireless/wl12xx/wl1251_event.c @@ -39,6 +39,7 @@ static int wl1251_event_scan_complete(struct wl1251 *wl, mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw, false); mutex_lock(&wl->mutex); + wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed"); wl->scanning = false; } -- cgit v1.2.3-18-g5258 From f26b32ed4bd5780855a79bb17fb1a431fa867dad Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 7 Aug 2009 13:35:33 +0300 Subject: wl1251: hack to disable filters for fixing association Commit 9cef8737 "mac80211: fix managed mode BSSID handling" broke association in wl1251, most probably because the driver configured the bssid filter incorrectly. Workaround this by disabling filter altogether. This needs to be fixed properly soon. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_cmd.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index 6cd024b50a7..770f260726b 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -276,6 +276,15 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, join->rx_config_options = wl->rx_config; join->rx_filter_options = wl->rx_filter; + /* + * FIXME: disable temporarily all filters because after commit + * 9cef8737 "mac80211: fix managed mode BSSID handling" broke + * association. The filter logic needs to be implemented properly + * and once that is done, this hack can be removed. + */ + join->rx_config_options = 0; + join->rx_filter_options = WL1251_DEFAULT_RX_FILTER; + join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; -- cgit v1.2.3-18-g5258 From 66d2d089c394c7e31020947d682523f77a93244b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 6 Aug 2009 10:36:50 +0200 Subject: b43: Fix hardware key index handling This fixes the hardware encryption keys index and array size handling. Thanks to Gregor Kowski for reporting this issue. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 7 ++- drivers/net/wireless/b43/main.c | 96 ++++++++++++++++++++--------------------- drivers/net/wireless/b43/xmit.c | 4 +- 3 files changed, 53 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 102094a2359..a1b3b731935 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -493,6 +493,10 @@ enum { /* Max size of a security key */ #define B43_SEC_KEYSIZE 16 +/* Max number of group keys */ +#define B43_NR_GROUP_KEYS 4 +/* Max number of pairwise keys */ +#define B43_NR_PAIRWISE_KEYS 50 /* Security algorithms. */ enum { B43_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */ @@ -819,8 +823,7 @@ struct b43_wldev { /* encryption/decryption */ u16 ktp; /* Key table pointer */ - u8 max_nr_keys; - struct b43_key key[58]; + struct b43_key key[B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS]; /* Firmware data */ struct b43_firmware fw; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 997dd55b63f..950beefbeae 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -796,18 +796,19 @@ static void key_write(struct b43_wldev *dev, static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr) { u32 addrtmp[2] = { 0, 0, }; - u8 per_sta_keys_start = 8; + u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2; if (b43_new_kidx_api(dev)) - per_sta_keys_start = 4; + pairwise_keys_start = B43_NR_GROUP_KEYS; - B43_WARN_ON(index < per_sta_keys_start); - /* We have two default TX keys and possibly two default RX keys. + B43_WARN_ON(index < pairwise_keys_start); + /* We have four default TX keys and possibly four default RX keys. * Physical mac 0 is mapped to physical key 4 or 8, depending * on the firmware version. * So we must adjust the index here. */ - index -= per_sta_keys_start; + index -= pairwise_keys_start; + B43_WARN_ON(index >= B43_NR_PAIRWISE_KEYS); if (addr) { addrtmp[0] = addr[0]; @@ -818,27 +819,11 @@ static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr) addrtmp[1] |= ((u32) (addr[5]) << 8); } - if (dev->dev->id.revision >= 5) { - /* Receive match transmitter address mechanism */ - b43_shm_write32(dev, B43_SHM_RCMTA, - (index * 2) + 0, addrtmp[0]); - b43_shm_write16(dev, B43_SHM_RCMTA, - (index * 2) + 1, addrtmp[1]); - } else { - /* RXE (Receive Engine) and - * PSM (Programmable State Machine) mechanism - */ - if (index < 8) { - /* TODO write to RCM 16, 19, 22 and 25 */ - } else { - b43_shm_write32(dev, B43_SHM_SHARED, - B43_SHM_SH_PSM + (index * 6) + 0, - addrtmp[0]); - b43_shm_write16(dev, B43_SHM_SHARED, - B43_SHM_SH_PSM + (index * 6) + 4, - addrtmp[1]); - } - } + /* Receive match transmitter address (RCMTA) mechanism */ + b43_shm_write32(dev, B43_SHM_RCMTA, + (index * 2) + 0, addrtmp[0]); + b43_shm_write16(dev, B43_SHM_RCMTA, + (index * 2) + 1, addrtmp[1]); } static void do_key_write(struct b43_wldev *dev, @@ -846,20 +831,20 @@ static void do_key_write(struct b43_wldev *dev, const u8 *key, size_t key_len, const u8 *mac_addr) { u8 buf[B43_SEC_KEYSIZE] = { 0, }; - u8 per_sta_keys_start = 8; + u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2; if (b43_new_kidx_api(dev)) - per_sta_keys_start = 4; + pairwise_keys_start = B43_NR_GROUP_KEYS; - B43_WARN_ON(index >= dev->max_nr_keys); + B43_WARN_ON(index >= ARRAY_SIZE(dev->key)); B43_WARN_ON(key_len > B43_SEC_KEYSIZE); - if (index >= per_sta_keys_start) + if (index >= pairwise_keys_start) keymac_write(dev, index, NULL); /* First zero out mac. */ if (key) memcpy(buf, key, key_len); key_write(dev, index, algorithm, buf); - if (index >= per_sta_keys_start) + if (index >= pairwise_keys_start) keymac_write(dev, index, mac_addr); dev->key[index].algorithm = algorithm; @@ -872,21 +857,24 @@ static int b43_key_write(struct b43_wldev *dev, struct ieee80211_key_conf *keyconf) { int i; - int sta_keys_start; + int pairwise_keys_start; if (key_len > B43_SEC_KEYSIZE) return -EINVAL; - for (i = 0; i < dev->max_nr_keys; i++) { + for (i = 0; i < ARRAY_SIZE(dev->key); i++) { /* Check that we don't already have this key. */ B43_WARN_ON(dev->key[i].keyconf == keyconf); } if (index < 0) { /* Pairwise key. Get an empty slot for the key. */ if (b43_new_kidx_api(dev)) - sta_keys_start = 4; + pairwise_keys_start = B43_NR_GROUP_KEYS; else - sta_keys_start = 8; - for (i = sta_keys_start; i < dev->max_nr_keys; i++) { + pairwise_keys_start = B43_NR_GROUP_KEYS * 2; + for (i = pairwise_keys_start; + i < pairwise_keys_start + B43_NR_PAIRWISE_KEYS; + i++) { + B43_WARN_ON(i >= ARRAY_SIZE(dev->key)); if (!dev->key[i].keyconf) { /* found empty */ index = i; @@ -914,7 +902,7 @@ static int b43_key_write(struct b43_wldev *dev, static int b43_key_clear(struct b43_wldev *dev, int index) { - if (B43_WARN_ON((index < 0) || (index >= dev->max_nr_keys))) + if (B43_WARN_ON((index < 0) || (index >= ARRAY_SIZE(dev->key)))) return -EINVAL; do_key_write(dev, index, B43_SEC_ALGO_NONE, NULL, B43_SEC_KEYSIZE, NULL); @@ -929,15 +917,19 @@ static int b43_key_clear(struct b43_wldev *dev, int index) static void b43_clear_keys(struct b43_wldev *dev) { - int i; + int i, count; - for (i = 0; i < dev->max_nr_keys; i++) + if (b43_new_kidx_api(dev)) + count = B43_NR_GROUP_KEYS + B43_NR_PAIRWISE_KEYS; + else + count = B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS; + for (i = 0; i < count; i++) b43_key_clear(dev, i); } static void b43_dump_keymemory(struct b43_wldev *dev) { - unsigned int i, index, offset; + unsigned int i, index, count, offset, pairwise_keys_start; u8 mac[ETH_ALEN]; u16 algo; u32 rcmta0; @@ -951,7 +943,14 @@ static void b43_dump_keymemory(struct b43_wldev *dev) hf = b43_hf_read(dev); b43dbg(dev->wl, "Hardware key memory dump: USEDEFKEYS=%u\n", !!(hf & B43_HF_USEDEFKEYS)); - for (index = 0; index < dev->max_nr_keys; index++) { + if (b43_new_kidx_api(dev)) { + pairwise_keys_start = B43_NR_GROUP_KEYS; + count = B43_NR_GROUP_KEYS + B43_NR_PAIRWISE_KEYS; + } else { + pairwise_keys_start = B43_NR_GROUP_KEYS * 2; + count = B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS; + } + for (index = 0; index < count; index++) { key = &(dev->key[index]); printk(KERN_DEBUG "Key slot %02u: %s", index, (key->keyconf == NULL) ? " " : "*"); @@ -965,11 +964,11 @@ static void b43_dump_keymemory(struct b43_wldev *dev) B43_SHM_SH_KEYIDXBLOCK + (index * 2)); printk(" Algo: %04X/%02X", algo, key->algorithm); - if (index >= 4) { + if (index >= pairwise_keys_start) { rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA, - ((index - 4) * 2) + 0); + ((index - pairwise_keys_start) * 2) + 0); rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA, - ((index - 4) * 2) + 1); + ((index - pairwise_keys_start) * 2) + 1); *((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0); *((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1); printk(" MAC: %pM", mac); @@ -2876,17 +2875,14 @@ error: static void b43_security_init(struct b43_wldev *dev) { - dev->max_nr_keys = (dev->dev->id.revision >= 5) ? 58 : 20; - B43_WARN_ON(dev->max_nr_keys > ARRAY_SIZE(dev->key)); dev->ktp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_KTP); /* KTP is a word address, but we address SHM bytewise. * So multiply by two. */ dev->ktp *= 2; - if (dev->dev->id.revision >= 5) { - /* Number of RCMTA address slots */ - b43_write16(dev, B43_MMIO_RCMTA_COUNT, dev->max_nr_keys - 8); - } + /* Number of RCMTA address slots */ + b43_write16(dev, B43_MMIO_RCMTA_COUNT, B43_NR_PAIRWISE_KEYS); + /* Clear the key memory. */ b43_clear_keys(dev); } diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 5b85e7d7359..5280ebc8c6e 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -237,7 +237,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, int wlhdr_len; size_t iv_len; - B43_WARN_ON(key_idx >= dev->max_nr_keys); + B43_WARN_ON(key_idx >= ARRAY_SIZE(dev->key)); key = &(dev->key[key_idx]); if (unlikely(!key->keyconf)) { @@ -578,7 +578,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) * key index, but the ucode passed it slightly different. */ keyidx = b43_kidx_to_raw(dev, keyidx); - B43_WARN_ON(keyidx >= dev->max_nr_keys); + B43_WARN_ON(keyidx >= ARRAY_SIZE(dev->key)); if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) { wlhdr_len = ieee80211_hdrlen(fctl); -- cgit v1.2.3-18-g5258 From 718126a75e5fd4c6df6ee0567f00c7345b2370f4 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 7 Aug 2009 19:38:51 +0200 Subject: p54: Write outside array bounds This patch fixes a coding error which allowed the to upper-layer to corrupt limited portions of the phy data. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index a0d0e726bc4..b99ee9b472b 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -317,7 +317,7 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, int ret; mutex_lock(&priv->conf_mutex); - if ((params) && !(queue > 4)) { + if (queue < dev->queues) { P54_SET_QUEUE(priv->qos_params[queue], params->aifs, params->cw_min, params->cw_max, params->txop); ret = p54_set_edcf(priv); -- cgit v1.2.3-18-g5258 From 6208f8b22cb24e446f24eb9f4aa9f4c3a9a1d52e Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 7 Aug 2009 19:39:05 +0200 Subject: p54: implement rfkill MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch implements a basic rfkill support for p54 hardware and removes a rfkill related WARNING: fwio.c: In function ‘p54_setup_mac’: fwio.c:323: warning: ‘radio_enabled’ is deprecated. by abandoning radio_enable in flavour for IEEE80211_CONF_CHANGE_IDLE. Tested-by: Larry Finger Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/fwio.c | 5 +++-- drivers/net/wireless/p54/main.c | 5 +++++ drivers/net/wireless/p54/txrx.c | 6 ++++++ 3 files changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index 21f19018fab..e7b9e9cb39f 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c @@ -320,7 +320,7 @@ int p54_setup_mac(struct p54_common *priv) return -ENOMEM; setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup)); - if (priv->hw->conf.radio_enabled) { + if (!(priv->hw->conf.flags & IEEE80211_CONF_IDLE)) { switch (priv->mode) { case NL80211_IFTYPE_STATION: mode = P54_FILTER_TYPE_STATION; @@ -348,8 +348,9 @@ int p54_setup_mac(struct p54_common *priv) (priv->filter_flags & FIF_OTHER_BSS)) && (mode != P54_FILTER_TYPE_PROMISCUOUS)) mode |= P54_FILTER_TYPE_TRANSPARENT; - } else + } else { mode = P54_FILTER_TYPE_HIBERNATE; + } setup->mac_mode = cpu_to_le16(mode); memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN); diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index b99ee9b472b..4a741df9c08 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -288,6 +288,11 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed) if (ret) goto out; } + if (changed & IEEE80211_CONF_CHANGE_IDLE) { + ret = p54_setup_mac(priv); + if (ret) + goto out; + } out: mutex_unlock(&priv->conf_mutex); diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 704685fab17..6fc0b6148c8 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -552,6 +552,12 @@ static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb) break; case P54_TRAP_TIMER: break; + case P54_TRAP_FAA_RADIO_OFF: + wiphy_rfkill_set_hw_state(priv->hw->wiphy, true); + break; + case P54_TRAP_FAA_RADIO_ON: + wiphy_rfkill_set_hw_state(priv->hw->wiphy, false); + break; default: printk(KERN_INFO "%s: received event:%x freq:%d\n", wiphy_name(priv->hw->wiphy), event, freq); -- cgit v1.2.3-18-g5258 From 3d816c77ecb05d3a3e974a205e53392e5353553e Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 7 Aug 2009 15:41:37 -0700 Subject: iwlwifi: re-introduce per device debugging Commit "iwlwifi: make debug level more user friendly" cleaned up the debug level handling. In doing so it created a single global debug level for all devices. Some setups do consits of more that one iwlwifi device and in these setups there is a requirement that debug levels should be unique per device. We now re-introduce the per device debugging while maintaining the cleanup effort of the previous patch. The maintain the global debug level and now introduce a per-device debug level that will be used if it (the per-device debug level) is set. The per-device debug level can be controlled via the debug_level sysfs file while the global debug level is controlled by the debug module parameter. Signed-off-by: Reinette Chatre Acked-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-4965.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-agn.c | 22 +++++++++++----------- drivers/net/wireless/iwlwifi/iwl-core.c | 8 ++++---- drivers/net/wireless/iwlwifi/iwl-debug.h | 11 ++++++----- drivers/net/wireless/iwlwifi/iwl-dev.h | 21 +++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-rx.c | 6 +++--- drivers/net/wireless/iwlwifi/iwl-sta.c | 2 +- drivers/net/wireless/iwlwifi/iwl-tx.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 21 +++++++++++---------- 10 files changed, 63 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index e1b0ef3c56a..7ad02074725 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -502,14 +502,14 @@ static void _iwl3945_dbg_report_frame(struct iwl_priv *priv, } } if (print_dump) - iwl_print_hex_dump(IWL_DL_RX, data, length); + iwl_print_hex_dump(priv, IWL_DL_RX, data, length); } static void iwl3945_dbg_report_frame(struct iwl_priv *priv, struct iwl_rx_packet *pkt, struct ieee80211_hdr *header, int group100) { - if (iwl_debug_level & IWL_DL_RX) + if (iwl_get_debug_level(priv) & IWL_DL_RX) _iwl3945_dbg_report_frame(priv, pkt, header, group100); } diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 670214823cb..62436a90ba8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -46,7 +46,7 @@ #include "iwl-sta.h" static int iwl4965_send_tx_power(struct iwl_priv *priv); -static int iwl4965_hw_get_temperature(const struct iwl_priv *priv); +static int iwl4965_hw_get_temperature(struct iwl_priv *priv); /* Highest firmware API version supported */ #define IWL4965_UCODE_API_MAX 2 @@ -1680,7 +1680,7 @@ static s32 sign_extend(u32 oper, int index) * * A return of <0 indicates bogus data in the statistics */ -static int iwl4965_hw_get_temperature(const struct iwl_priv *priv) +static int iwl4965_hw_get_temperature(struct iwl_priv *priv) { s32 temperature; s32 vt; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index db580cbf598..24c1ae6b816 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -896,7 +896,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & IWL_DL_ISR) { + if (iwl_get_debug_level(priv) & IWL_DL_ISR) { /* just for debug */ inta_mask = iwl_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", @@ -931,7 +931,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) } #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ if (inta & CSR_INT_BIT_SCD) { IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " @@ -1045,7 +1045,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) iwl_enable_interrupts(priv); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { inta = iwl_read32(priv, CSR_INT); inta_mask = iwl_read32(priv, CSR_INT_MASK); inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); @@ -1076,7 +1076,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) inta = priv->inta; #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & IWL_DL_ISR) { + if (iwl_get_debug_level(priv) & IWL_DL_ISR) { /* just for debug */ inta_mask = iwl_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ", @@ -1104,7 +1104,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) } #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ if (inta & CSR_INT_BIT_SCD) { IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " @@ -2455,15 +2455,15 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw, * * See the level definitions in iwl for details. * - * FIXME This file can be deprecated as the module parameter is - * writable and users can thus also change the debug level - * using the /sys/module/iwl3945/parameters/debug file. + * The debug_level being managed using sysfs below is a per device debug + * level that is used instead of the global debug level if it (the per + * device debug level) is set. */ - static ssize_t show_debug_level(struct device *d, struct device_attribute *attr, char *buf) { - return sprintf(buf, "0x%08X\n", iwl_debug_level); + struct iwl_priv *priv = dev_get_drvdata(d); + return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv)); } static ssize_t store_debug_level(struct device *d, struct device_attribute *attr, @@ -2477,7 +2477,7 @@ static ssize_t store_debug_level(struct device *d, if (ret) IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf); else - iwl_debug_level = val; + priv->debug_level = val; return strnlen(buf, count); } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 2ffbd27d01d..30f1953208e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1278,7 +1278,7 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv) struct iwl_rxon_cmd *rxon = &priv->staging_rxon; IWL_DEBUG_RADIO(priv, "RX CONFIG:\n"); - iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); + iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n", @@ -1508,7 +1508,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv) clear_bit(STATUS_HCMD_ACTIVE, &priv->status); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & IWL_DL_FW_ERRORS) { + if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) { iwl_dump_nic_error_log(priv); iwl_dump_nic_event_log(priv); iwl_print_rx_config_cmd(priv); @@ -1985,7 +1985,7 @@ static irqreturn_t iwl_isr(int irq, void *data) } #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, " "fh 0x%08x\n", inta, inta_mask, inta_fh); @@ -2310,7 +2310,7 @@ void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " "notification for %s:\n", le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); - iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); + iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); } EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif); diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index fbe177608bc..09af046927a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -46,7 +46,7 @@ do { \ #ifdef CONFIG_IWLWIFI_DEBUG #define IWL_DEBUG(__priv, level, fmt, args...) \ do { \ - if (iwl_debug_level & (level)) \ + if (iwl_get_debug_level(__priv) & (level)) \ dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \ "%c %s " fmt, in_interrupt() ? 'I' : 'U', \ __func__ , ## args); \ @@ -54,15 +54,15 @@ do { \ #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) \ do { \ - if ((iwl_debug_level & (level)) && net_ratelimit()) \ + if ((iwl_get_debug_level(__priv) & (level)) && net_ratelimit()) \ dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \ "%c %s " fmt, in_interrupt() ? 'I' : 'U', \ __func__ , ## args); \ } while (0) -#define iwl_print_hex_dump(level, p, len) \ +#define iwl_print_hex_dump(priv, level, p, len) \ do { \ - if (iwl_debug_level & level) \ + if (iwl_get_debug_level(priv) & level) \ print_hex_dump(KERN_DEBUG, "iwl data: ", \ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ } while (0) @@ -106,7 +106,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv); #else #define IWL_DEBUG(__priv, level, fmt, args...) #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) -static inline void iwl_print_hex_dump(int level, void *p, u32 len) +static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, + void *p, u32 len) {} #endif /* CONFIG_IWLWIFI_DEBUG */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index cab6255210d..1bf3e4ccc5d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1175,6 +1175,8 @@ struct iwl_priv { #ifdef CONFIG_IWLWIFI_DEBUG /* debugging info */ + u32 debug_level; /* per device debugging will override global + iwl_debug_level if set */ u32 framecnt_to_us; atomic_t restrict_refcnt; bool disable_ht40; @@ -1211,8 +1213,27 @@ static inline void iwl_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id) #ifdef CONFIG_IWLWIFI_DEBUG const char *iwl_get_tx_fail_reason(u32 status); +/* + * iwl_get_debug_level: Return active debug level for device + * + * Using sysfs it is possible to set per device debug level. This debug + * level will be used if set, otherwise the global debug level which can be + * set via module parameter is used. + */ +static inline u32 iwl_get_debug_level(struct iwl_priv *priv) +{ + if (priv->debug_level) + return priv->debug_level; + else + return iwl_debug_level; +} #else static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; } + +static inline u32 iwl_get_debug_level(struct iwl_priv *priv) +{ + return iwl_debug_level; +} #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index e002c8b56c4..98f014276e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -645,7 +645,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, u32 tsf_low; int rssi; - if (likely(!(iwl_debug_level & IWL_DL_RX))) + if (likely(!(iwl_get_debug_level(priv) & IWL_DL_RX))) return; /* MAC header */ @@ -741,7 +741,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, } } if (print_dump) - iwl_print_hex_dump(IWL_DL_RX, header, length); + iwl_print_hex_dump(priv, IWL_DL_RX, header, length); } #endif @@ -1060,7 +1060,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, /* Set "1" to report good data frames in groups of 100 */ #ifdef CONFIG_IWLWIFI_DEBUG - if (unlikely(iwl_debug_level & IWL_DL_RX)) + if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX)) iwl_dbg_report_frame(priv, rx_start, len, header, 1); #endif IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index efcae0d5e19..def12545d9a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1088,7 +1088,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) IWL_DEBUG_DROP(priv, "Station %pM not in station map. " "Defaulting to broadcast...\n", hdr->addr1); - iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); + iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_params.bcast_sta_id; default: diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 288b871e974..0cac06c43f9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -884,8 +884,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n", le16_to_cpu(out_cmd->hdr.sequence)); IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags)); - iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); - iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); + iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); + iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); /* Set up entry for this TFD in Tx byte-count array */ if (info->flags & IEEE80211_TX_CTL_AMPDU) diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index ea051b739ba..0babce250ea 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -614,8 +614,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n", le16_to_cpu(out_cmd->hdr.sequence)); IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx->tx_flags)); - iwl_print_hex_dump(IWL_DL_TX, tx, sizeof(*tx)); - iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx->hdr, + iwl_print_hex_dump(priv, IWL_DL_TX, tx, sizeof(*tx)); + iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx->hdr, ieee80211_hdrlen(fc)); /* @@ -1646,7 +1646,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & IWL_DL_ISR) { + if (iwl_get_debug_level(priv) & IWL_DL_ISR) { /* just for debug */ inta_mask = iwl_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", @@ -1681,7 +1681,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) } #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ if (inta & CSR_INT_BIT_SCD) { IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " @@ -1760,7 +1760,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) iwl_enable_interrupts(priv); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { inta = iwl_read32(priv, CSR_INT); inta_mask = iwl_read32(priv, CSR_INT_MASK); inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); @@ -3311,14 +3311,15 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, * * See the level definitions in iwl for details. * - * FIXME This file can be deprecated as the module parameter is - * writable and users can thus also change the debug level - * using the /sys/module/iwl3945/parameters/debug file. + * The debug_level being managed using sysfs below is a per device debug + * level that is used instead of the global debug level if it (the per + * device debug level) is set. */ static ssize_t show_debug_level(struct device *d, struct device_attribute *attr, char *buf) { - return sprintf(buf, "0x%08X\n", iwl_debug_level); + struct iwl_priv *priv = dev_get_drvdata(d); + return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv)); } static ssize_t store_debug_level(struct device *d, struct device_attribute *attr, @@ -3332,7 +3333,7 @@ static ssize_t store_debug_level(struct device *d, if (ret) IWL_INFO(priv, "%s is not in hex or decimal form.\n", buf); else - iwl_debug_level = val; + priv->debug_level = val; return strnlen(buf, count); } -- cgit v1.2.3-18-g5258 From 7aafef1c6e2e24f9a10dc2972bf0ee70624ccc47 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 7 Aug 2009 15:41:38 -0700 Subject: iwlwifi: name changed from "fat" to "ht40" Rename "fat" to "ht40" The term "fat channel" is deprecated in favor of "HT40" Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 4 +- drivers/net/wireless/iwlwifi/iwl-3945-hw.h | 2 +- drivers/net/wireless/iwlwifi/iwl-3945.c | 4 +- drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 6 +-- drivers/net/wireless/iwlwifi/iwl-4965.c | 42 +++++++++--------- drivers/net/wireless/iwlwifi/iwl-5000.c | 10 ++--- drivers/net/wireless/iwlwifi/iwl-6000.c | 4 +- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 67 +++++++++++++++-------------- drivers/net/wireless/iwlwifi/iwl-commands.h | 22 +++++----- drivers/net/wireless/iwlwifi/iwl-core.c | 24 +++++------ drivers/net/wireless/iwlwifi/iwl-core.h | 2 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 22 +++++----- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 54 +++++++++++------------ drivers/net/wireless/iwlwifi/iwl-eeprom.h | 34 +++++++-------- drivers/net/wireless/iwlwifi/iwl-power.c | 2 +- drivers/net/wireless/iwlwifi/iwl-rx.c | 4 +- drivers/net/wireless/iwlwifi/iwl-sta.c | 6 +-- 17 files changed, 155 insertions(+), 154 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index cf3fbc6b98e..191718a0c54 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -117,8 +117,8 @@ static struct iwl_lib_ops iwl1000_lib = { EEPROM_5000_REG_BAND_3_CHANNELS, EEPROM_5000_REG_BAND_4_CHANNELS, EEPROM_5000_REG_BAND_5_CHANNELS, - EEPROM_5000_REG_BAND_24_FAT_CHANNELS, - EEPROM_5000_REG_BAND_52_FAT_CHANNELS + EEPROM_5000_REG_BAND_24_HT40_CHANNELS, + EEPROM_5000_REG_BAND_52_HT40_CHANNELS }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index b569c6f38e5..16772780c5b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -176,7 +176,7 @@ struct iwl3945_eeprom { * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory * txpower (MSB). * - * Entries immediately below are for 20 MHz channel width. FAT (40 MHz) + * Entries immediately below are for 20 MHz channel width. HT40 (40 MHz) * channels (only for 4965, not supported by 3945) appear later in the EEPROM. * * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 7ad02074725..9e33507661d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2851,8 +2851,8 @@ static struct iwl_lib_ops iwl3945_lib = { EEPROM_REGULATORY_BAND_3_CHANNELS, EEPROM_REGULATORY_BAND_4_CHANNELS, EEPROM_REGULATORY_BAND_5_CHANNELS, - EEPROM_REGULATORY_BAND_NO_FAT, - EEPROM_REGULATORY_BAND_NO_FAT, + EEPROM_REGULATORY_BAND_NO_HT40, + EEPROM_REGULATORY_BAND_NO_HT40, }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwl3945_eeprom_acquire_semaphore, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index a71a489096f..b34322a3245 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -188,7 +188,7 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr) * * 1) Regulatory information (max txpower and channel usage flags) is provided * separately for each channel that can possibly supported by 4965. - * 40 MHz wide (.11n fat) channels are listed separately from 20 MHz + * 40 MHz wide (.11n HT40) channels are listed separately from 20 MHz * (legacy) channels. * * See struct iwl4965_eeprom_channel for format, and struct iwl4965_eeprom @@ -251,8 +251,8 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr) * no reduction (such as with regulatory txpower limits) is required. * * Saturation and Backoff values apply equally to 20 Mhz (legacy) channel - * widths and 40 Mhz (.11n fat) channel widths; there is no separate - * factory measurement for fat channels. + * widths and 40 Mhz (.11n HT40) channel widths; there is no separate + * factory measurement for ht40 channels. * * The result of this step is the final target txpower. The rest of * the steps figure out the proper settings for the device to achieve diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 62436a90ba8..f02023eea41 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -317,7 +317,7 @@ restart: queue_work(priv->workqueue, &priv->restart); } -static bool is_fat_channel(__le32 rxon_flags) +static bool is_ht40_channel(__le32 rxon_flags) { int chan_mod = le32_to_cpu(rxon_flags & RXON_FLG_CHANNEL_MODE_MSK) >> RXON_FLG_CHANNEL_MODE_POS; @@ -806,7 +806,7 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWL49_RTC_INST_SIZE; priv->hw_params.max_bsm_size = BSM_SRAM_SIZE; - priv->hw_params.fat_channel = BIT(IEEE80211_BAND_5GHZ); + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -1266,7 +1266,7 @@ static const struct gain_entry gain_table[2][108] = { }; static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, - u8 is_fat, u8 ctrl_chan_high, + u8 is_ht40, u8 ctrl_chan_high, struct iwl4965_tx_power_db *tx_power_tbl) { u8 saturation_power; @@ -1298,8 +1298,8 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, user_target_power = 2 * priv->tx_power_user_lmt; /* Get current (RXON) channel, band, width */ - IWL_DEBUG_TXPOWER(priv, "chan %d band %d is_fat %d\n", channel, band, - is_fat); + IWL_DEBUG_TXPOWER(priv, "chan %d band %d is_ht40 %d\n", channel, band, + is_ht40); ch_info = iwl_get_channel_info(priv, priv->band, channel); @@ -1318,7 +1318,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, IWL_DEBUG_TXPOWER(priv, "channel %d belongs to txatten group %d\n", channel, txatten_grp); - if (is_fat) { + if (is_ht40) { if (ctrl_chan_high) channel -= 2; else @@ -1342,8 +1342,8 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, /* regulatory txpower limits ... reg_limit values are in half-dBm, * max_power_avg values are in dBm, convert * 2 */ - if (is_fat) - reg_limit = ch_info->fat_max_power_avg * 2; + if (is_ht40) + reg_limit = ch_info->ht40_max_power_avg * 2; else reg_limit = ch_info->max_power_avg * 2; @@ -1509,7 +1509,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, /** * iwl4965_send_tx_power - Configure the TXPOWER level user limit * - * Uses the active RXON for channel, band, and characteristics (fat, high) + * Uses the active RXON for channel, band, and characteristics (ht40, high) * The power limit is taken from priv->tx_power_user_lmt. */ static int iwl4965_send_tx_power(struct iwl_priv *priv) @@ -1517,7 +1517,7 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv) struct iwl4965_txpowertable_cmd cmd = { 0 }; int ret; u8 band = 0; - bool is_fat = false; + bool is_ht40 = false; u8 ctrl_chan_high = 0; if (test_bit(STATUS_SCANNING, &priv->status)) { @@ -1530,9 +1530,9 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv) band = priv->band == IEEE80211_BAND_2GHZ; - is_fat = is_fat_channel(priv->active_rxon.flags); + is_ht40 = is_ht40_channel(priv->active_rxon.flags); - if (is_fat && + if (is_ht40 && (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) ctrl_chan_high = 1; @@ -1541,7 +1541,7 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv) ret = iwl4965_fill_txpower_tbl(priv, band, le16_to_cpu(priv->active_rxon.channel), - is_fat, ctrl_chan_high, &cmd.tx_power); + is_ht40, ctrl_chan_high, &cmd.tx_power); if (ret) goto out; @@ -1595,7 +1595,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) { int rc; u8 band = 0; - bool is_fat = false; + bool is_ht40 = false; u8 ctrl_chan_high = 0; struct iwl4965_channel_switch_cmd cmd = { 0 }; const struct iwl_channel_info *ch_info; @@ -1604,9 +1604,9 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) ch_info = iwl_get_channel_info(priv, priv->band, channel); - is_fat = is_fat_channel(priv->staging_rxon.flags); + is_ht40 = is_ht40_channel(priv->staging_rxon.flags); - if (is_fat && + if (is_ht40 && (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) ctrl_chan_high = 1; @@ -1621,7 +1621,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) else cmd.expect_beacon = 1; - rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_fat, + rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_ht40, ctrl_chan_high, &cmd.tx_power); if (rc) { IWL_DEBUG_11H(priv, "error:%d fill txpower_tbl\n", rc); @@ -1688,8 +1688,8 @@ static int iwl4965_hw_get_temperature(struct iwl_priv *priv) u32 R4; if (test_bit(STATUS_TEMPERATURE, &priv->status) && - (priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK)) { - IWL_DEBUG_TEMP(priv, "Running FAT temperature calibration\n"); + (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)) { + IWL_DEBUG_TEMP(priv, "Running HT40 temperature calibration\n"); R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]); R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]); R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]); @@ -2330,8 +2330,8 @@ static struct iwl_lib_ops iwl4965_lib = { EEPROM_REGULATORY_BAND_3_CHANNELS, EEPROM_REGULATORY_BAND_4_CHANNELS, EEPROM_REGULATORY_BAND_5_CHANNELS, - EEPROM_4965_REGULATORY_BAND_24_FAT_CHANNELS, - EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS + EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS, + EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 87957c05283..755c184b3ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -845,7 +845,7 @@ int iwl5000_hw_set_hw_params(struct iwl_priv *priv) } priv->hw_params.max_bsm_size = 0; - priv->hw_params.fat_channel = BIT(IEEE80211_BAND_2GHZ) | + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -1547,8 +1547,8 @@ struct iwl_lib_ops iwl5000_lib = { EEPROM_5000_REG_BAND_3_CHANNELS, EEPROM_5000_REG_BAND_4_CHANNELS, EEPROM_5000_REG_BAND_5_CHANNELS, - EEPROM_5000_REG_BAND_24_FAT_CHANNELS, - EEPROM_5000_REG_BAND_52_FAT_CHANNELS + EEPROM_5000_REG_BAND_24_HT40_CHANNELS, + EEPROM_5000_REG_BAND_52_HT40_CHANNELS }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, @@ -1597,8 +1597,8 @@ static struct iwl_lib_ops iwl5150_lib = { EEPROM_5000_REG_BAND_3_CHANNELS, EEPROM_5000_REG_BAND_4_CHANNELS, EEPROM_5000_REG_BAND_5_CHANNELS, - EEPROM_5000_REG_BAND_24_FAT_CHANNELS, - EEPROM_5000_REG_BAND_52_FAT_CHANNELS + EEPROM_5000_REG_BAND_24_HT40_CHANNELS, + EEPROM_5000_REG_BAND_52_HT40_CHANNELS }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 4450943d3da..c3ec6c20cc9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -118,8 +118,8 @@ static struct iwl_lib_ops iwl6000_lib = { EEPROM_5000_REG_BAND_3_CHANNELS, EEPROM_5000_REG_BAND_4_CHANNELS, EEPROM_5000_REG_BAND_5_CHANNELS, - EEPROM_5000_REG_BAND_24_FAT_CHANNELS, - EEPROM_5000_REG_BAND_52_FAT_CHANNELS + EEPROM_5000_REG_BAND_24_HT40_CHANNELS, + EEPROM_5000_REG_BAND_52_HT40_CHANNELS }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 52a4810274e..0c3ed23ed77 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -97,7 +97,7 @@ struct iwl_scale_tbl_info { enum iwl_table_type lq_type; u8 ant_type; u8 is_SGI; /* 1 = short guard interval */ - u8 is_fat; /* 1 = 40 MHz channel width */ + u8 is_ht40; /* 1 = 40 MHz channel width */ u8 is_dup; /* 1 = duplicated data streams */ u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ u8 max_search; /* maximun number of tables we can search */ @@ -539,11 +539,11 @@ static u32 rate_n_flags_from_tbl(struct iwl_priv *priv, RATE_MCS_ANT_ABC_MSK); if (is_Ht(tbl->lq_type)) { - if (tbl->is_fat) { + if (tbl->is_ht40) { if (tbl->is_dup) rate_n_flags |= RATE_MCS_DUP_MSK; else - rate_n_flags |= RATE_MCS_FAT_MSK; + rate_n_flags |= RATE_MCS_HT40_MSK; } if (tbl->is_SGI) rate_n_flags |= RATE_MCS_SGI_MSK; @@ -579,7 +579,7 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, return -EINVAL; } tbl->is_SGI = 0; /* default legacy setup */ - tbl->is_fat = 0; + tbl->is_ht40 = 0; tbl->is_dup = 0; tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS); tbl->lq_type = LQ_NONE; @@ -598,9 +598,9 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, if (rate_n_flags & RATE_MCS_SGI_MSK) tbl->is_SGI = 1; - if ((rate_n_flags & RATE_MCS_FAT_MSK) || + if ((rate_n_flags & RATE_MCS_HT40_MSK) || (rate_n_flags & RATE_MCS_DUP_MSK)) - tbl->is_fat = 1; + tbl->is_ht40 = 1; if (rate_n_flags & RATE_MCS_DUP_MSK) tbl->is_dup = 1; @@ -776,7 +776,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, if (num_of_ant(tbl->ant_type) > 1) tbl->ant_type = ANT_A;/*FIXME:RS*/ - tbl->is_fat = 0; + tbl->is_ht40 = 0; tbl->is_SGI = 0; tbl->max_search = IWL_MAX_SEARCH; } @@ -880,7 +880,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, if ((info->status.rates[0].idx < 0) || (tbl_type.is_SGI != !!(info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) || - (tbl_type.is_fat != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || + (tbl_type.is_ht40 != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || (tbl_type.is_dup != !!(info->status.rates[0].flags & IEEE80211_TX_RC_DUP_DATA)) || (tbl_type.ant_type != info->antenna_sel_tx) || (!!(tx_rate & RATE_MCS_HT_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) || @@ -1049,7 +1049,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, else tbl->expected_tpt = expected_tpt_A; } else if (is_siso(tbl->lq_type)) { - if (tbl->is_fat && !lq_sta->is_dup) + if (tbl->is_ht40 && !lq_sta->is_dup) if (tbl->is_SGI) tbl->expected_tpt = expected_tpt_siso40MHzSGI; else @@ -1059,7 +1059,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, else tbl->expected_tpt = expected_tpt_siso20MHz; } else if (is_mimo2(tbl->lq_type)) { - if (tbl->is_fat && !lq_sta->is_dup) + if (tbl->is_ht40 && !lq_sta->is_dup) if (tbl->is_SGI) tbl->expected_tpt = expected_tpt_mimo2_40MHzSGI; else @@ -1069,7 +1069,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, else tbl->expected_tpt = expected_tpt_mimo2_20MHz; } else if (is_mimo3(tbl->lq_type)) { - if (tbl->is_fat && !lq_sta->is_dup) + if (tbl->is_ht40 && !lq_sta->is_dup) if (tbl->is_SGI) tbl->expected_tpt = expected_tpt_mimo3_40MHzSGI; else @@ -1217,13 +1217,13 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, tbl->max_search = IWL_MAX_SEARCH; rate_mask = lq_sta->active_mimo2_rate; - if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) - tbl->is_fat = 1; + if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap)) + tbl->is_ht40 = 1; else - tbl->is_fat = 0; + tbl->is_ht40 = 0; /* FIXME: - don't toggle SGI here - if (tbl->is_fat) { + if (tbl->is_ht40) { if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) tbl->is_SGI = 1; else @@ -1283,13 +1283,13 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; rate_mask = lq_sta->active_mimo3_rate; - if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) - tbl->is_fat = 1; + if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap)) + tbl->is_ht40 = 1; else - tbl->is_fat = 0; + tbl->is_ht40 = 0; /* FIXME: - don't toggle SGI here - if (tbl->is_fat) { + if (tbl->is_ht40) { if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) tbl->is_SGI = 1; else @@ -1342,13 +1342,13 @@ static int rs_switch_to_siso(struct iwl_priv *priv, tbl->max_search = IWL_MAX_SEARCH; rate_mask = lq_sta->active_siso_rate; - if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) - tbl->is_fat = 1; + if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap)) + tbl->is_ht40 = 1; else - tbl->is_fat = 0; + tbl->is_ht40 = 0; /* FIXME: - don't toggle SGI here - if (tbl->is_fat) { + if (tbl->is_ht40) { if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) tbl->is_SGI = 1; else @@ -1586,11 +1586,11 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, goto out; break; case IWL_SISO_SWITCH_GI: - if (!tbl->is_fat && + if (!tbl->is_ht40 && !(priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ)) break; - if (tbl->is_fat && + if (tbl->is_ht40 && !(priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ)) break; @@ -1726,11 +1726,11 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, break; case IWL_MIMO2_SWITCH_GI: - if (!tbl->is_fat && + if (!tbl->is_ht40 && !(priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ)) break; - if (tbl->is_fat && + if (tbl->is_ht40 && !(priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ)) break; @@ -1890,11 +1890,11 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, break; case IWL_MIMO3_SWITCH_GI: - if (!tbl->is_fat && + if (!tbl->is_ht40 && !(priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ)) break; - if (tbl->is_fat && + if (tbl->is_ht40 && !(priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ)) break; @@ -2576,7 +2576,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI; if (lq_sta->last_rate_n_flags & RATE_MCS_DUP_MSK) info->control.rates[0].flags |= IEEE80211_TX_RC_DUP_DATA; - if (lq_sta->last_rate_n_flags & RATE_MCS_FAT_MSK) + if (lq_sta->last_rate_n_flags & RATE_MCS_HT40_MSK) info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; if (lq_sta->last_rate_n_flags & RATE_MCS_GF_MSK) info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD; @@ -2963,7 +2963,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, (is_siso(tbl->lq_type)) ? "SISO" : ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3")); desc += sprintf(buff+desc, " %s", - (tbl->is_fat) ? "40MHz" : "20MHz"); + (tbl->is_ht40) ? "40MHz" : "20MHz"); desc += sprintf(buff+desc, " %s %s\n", (tbl->is_SGI) ? "SGI" : "", (lq_sta->is_green) ? "GF enabled" : ""); } @@ -3028,12 +3028,13 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, return -ENOMEM; for (i = 0; i < LQ_SIZE; i++) { - desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d GF=%d\n" + desc += sprintf(buff+desc, + "%s type=%d SGI=%d HT40=%d DUP=%d GF=%d\n" "rate=0x%X\n", lq_sta->active_tbl == i ? "*" : "x", lq_sta->lq_info[i].lq_type, lq_sta->lq_info[i].is_SGI, - lq_sta->lq_info[i].is_fat, + lq_sta->lq_info[i].is_ht40, lq_sta->lq_info[i].is_dup, lq_sta->is_green, lq_sta->lq_info[i].current_rate); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 39ede5727fe..6188c54113b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -283,7 +283,7 @@ struct iwl3945_power_per_rate { * 1) Dual stream (MIMO) * 2) Triple stream (MIMO) * - * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps FAT duplicate data + * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps HT40 duplicate data * * Legacy OFDM rate format for bits 7:0 (bit 8 must be "0", bit 9 "0"): * 3-0: 0xD) 6 Mbps @@ -320,11 +320,11 @@ struct iwl3945_power_per_rate { #define RATE_MCS_GF_POS 10 #define RATE_MCS_GF_MSK 0x400 -/* Bit 11: (1) Use 40Mhz FAT chnl width, (0) use 20 MHz legacy chnl width */ -#define RATE_MCS_FAT_POS 11 -#define RATE_MCS_FAT_MSK 0x800 +/* Bit 11: (1) Use 40Mhz HT40 chnl width, (0) use 20 MHz legacy chnl width */ +#define RATE_MCS_HT40_POS 11 +#define RATE_MCS_HT40_MSK 0x800 -/* Bit 12: (1) Duplicate data on both 20MHz chnls. FAT (bit 11) must be set. */ +/* Bit 12: (1) Duplicate data on both 20MHz chnls. HT40 (bit 11) must be set. */ #define RATE_MCS_DUP_POS 12 #define RATE_MCS_DUP_MSK 0x1000 @@ -459,7 +459,7 @@ struct iwl_init_alive_resp { /* calibration values from "initialize" uCode */ __le32 voltage; /* signed, higher value is lower voltage */ - __le32 therm_r1[2]; /* signed, 1st for normal, 2nd for FAT channel*/ + __le32 therm_r1[2]; /* signed, 1st for normal, 2nd for HT40 */ __le32 therm_r2[2]; /* signed */ __le32 therm_r3[2]; /* signed */ __le32 therm_r4[2]; /* signed */ @@ -610,7 +610,7 @@ enum { #define RXON_FLG_HT_OPERATING_MODE_POS (23) #define RXON_FLG_HT_PROT_MSK cpu_to_le32(0x1 << 23) -#define RXON_FLG_FAT_PROT_MSK cpu_to_le32(0x2 << 23) +#define RXON_FLG_HT40_PROT_MSK cpu_to_le32(0x2 << 23) #define RXON_FLG_CHANNEL_MODE_POS (25) #define RXON_FLG_CHANNEL_MODE_MSK cpu_to_le32(0x3 << 25) @@ -891,7 +891,7 @@ struct iwl_qosparam_cmd { #define STA_FLG_AGG_MPDU_8US_MSK cpu_to_le32(1 << 18) #define STA_FLG_MAX_AGG_SIZE_POS (19) #define STA_FLG_MAX_AGG_SIZE_MSK cpu_to_le32(3 << 19) -#define STA_FLG_FAT_EN_MSK cpu_to_le32(1 << 21) +#define STA_FLG_HT40_EN_MSK cpu_to_le32(1 << 21) #define STA_FLG_MIMO_DIS_MSK cpu_to_le32(1 << 22) #define STA_FLG_AGG_MPDU_DENSITY_POS (23) #define STA_FLG_AGG_MPDU_DENSITY_MSK cpu_to_le32(7 << 23) @@ -1984,10 +1984,10 @@ struct iwl_link_qual_agg_params { * a) Use this same initial rate for first 3 entries. * b) Find next lower available rate using same mode (SISO or MIMO), * use for next 3 entries. If no lower rate available, switch to - * legacy mode (no FAT channel, no MIMO, no short guard interval). + * legacy mode (no HT40 channel, no MIMO, no short guard interval). * c) If using MIMO, set command's mimo_delimiter to number of entries * using MIMO (3 or 6). - * d) After trying 2 HT rates, switch to legacy mode (no FAT channel, + * d) After trying 2 HT rates, switch to legacy mode (no HT40 channel, * no MIMO, no short guard interval), at the next lower bit rate * (e.g. if second HT bit rate was 54, try 48 legacy), and follow * legacy procedure for remaining table entries. @@ -3017,7 +3017,7 @@ struct iwl_statistics_cmd { * one channel that has just been scanned. */ #define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2) -#define STATISTICS_REPLY_FLG_FAT_MODE_MSK cpu_to_le32(0x8) +#define STATISTICS_REPLY_FLG_HT40_MODE_MSK cpu_to_le32(0x8) struct iwl3945_notif_statistics { __le32 flag; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 30f1953208e..5315d347a00 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -105,7 +105,7 @@ void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, r->flags |= IEEE80211_TX_RC_MCS; if (rate_n_flags & RATE_MCS_GF_MSK) r->flags |= IEEE80211_TX_RC_GREEN_FIELD; - if (rate_n_flags & RATE_MCS_FAT_MSK) + if (rate_n_flags & RATE_MCS_HT40_MSK) r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; if (rate_n_flags & RATE_MCS_DUP_MSK) r->flags |= IEEE80211_TX_RC_DUP_DATA; @@ -400,7 +400,7 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, (WLAN_HT_CAP_SM_PS_DISABLED << 2)); max_bit_rate = MAX_BIT_RATE_20_MHZ; - if (priv->hw_params.fat_channel & BIT(band)) { + if (priv->hw_params.ht40_channel & BIT(band)) { ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; ht_info->cap |= IEEE80211_HT_CAP_SGI_40; ht_info->mcs.rx_mask[4] = 0x01; @@ -540,7 +540,7 @@ int iwlcore_init_geos(struct iwl_priv *priv) if (ch->flags & EEPROM_CHANNEL_RADAR) geo_ch->flags |= IEEE80211_CHAN_RADAR; - geo_ch->flags |= ch->fat_extension_channel; + geo_ch->flags |= ch->ht40_extension_channel; if (ch->max_power_avg > priv->tx_power_channel_lmt) priv->tx_power_channel_lmt = ch->max_power_avg; @@ -604,16 +604,16 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv, return 0; if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) - return !(ch_info->fat_extension_channel & + return !(ch_info->ht40_extension_channel & IEEE80211_CHAN_NO_HT40PLUS); else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) - return !(ch_info->fat_extension_channel & + return !(ch_info->ht40_extension_channel & IEEE80211_CHAN_NO_HT40MINUS); return 0; } -u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, +u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv, struct ieee80211_sta_ht_cap *sta_ht_inf) { struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; @@ -637,7 +637,7 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, le16_to_cpu(priv->staging_rxon.channel), iwl_ht_conf->extension_chan_offset); } -EXPORT_SYMBOL(iwl_is_fat_tx_allowed); +EXPORT_SYMBOL(iwl_is_ht40_tx_allowed); static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val) { @@ -866,7 +866,7 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) if (!ht_info->is_ht) { rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | - RXON_FLG_FAT_PROT_MSK | + RXON_FLG_HT40_PROT_MSK | RXON_FLG_HT_PROT_MSK); return; } @@ -877,12 +877,12 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) rxon->flags |= cpu_to_le32(ht_info->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS); /* Set up channel bandwidth: - * 20 MHz only, 20/40 mixed or pure 40 if fat ok */ + * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */ /* clear the HT channel mode before set the mode */ rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); - if (iwl_is_fat_tx_allowed(priv, NULL)) { - /* pure 40 fat */ + if (iwl_is_ht40_tx_allowed(priv, NULL)) { + /* pure ht40 */ if (ht_info->ht_protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) { rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40; /* Note: control channel is opposite of extension channel */ @@ -2428,7 +2428,7 @@ static void iwl_ht_conf(struct iwl_priv *priv, else if (conf_is_ht40_plus(&priv->hw->conf)) iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - /* If no above or below channel supplied disable FAT channel */ + /* If no above or below channel supplied disable HT40 channel */ if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) iwl_conf->supported_chan_width = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 10ddcdda104..dd66148a789 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -264,7 +264,7 @@ int iwl_full_rxon_required(struct iwl_priv *priv); void iwl_set_rxon_chain(struct iwl_priv *priv); int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch); void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info); -u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, +u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv, struct ieee80211_sta_ht_cap *sta_ht_inf); void iwl_set_flags_for_band(struct iwl_priv *priv, enum ieee80211_band band); void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1bf3e4ccc5d..624656a2bba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -277,8 +277,8 @@ struct iwl_channel_info { struct iwl4965_channel_tgd_info tgd; struct iwl4965_channel_tgh_info tgh; struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */ - struct iwl_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for - * FAT channel */ + struct iwl_eeprom_channel ht40_eeprom; /* EEPROM regulatory limit for + * HT40 channel */ u8 channel; /* channel number */ u8 flags; /* flags copied from EEPROM */ @@ -291,13 +291,13 @@ struct iwl_channel_info { u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */ enum ieee80211_band band; - /* FAT channel info */ - s8 fat_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ - s8 fat_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */ - s8 fat_min_power; /* always 0 */ - s8 fat_scan_power; /* (dBm) eeprom, direct scans, any rate */ - u8 fat_flags; /* flags copied from EEPROM */ - u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */ + /* HT40 channel info */ + s8 ht40_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ + s8 ht40_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */ + s8 ht40_min_power; /* always 0 */ + s8 ht40_scan_power; /* (dBm) eeprom, direct scans, any rate */ + u8 ht40_flags; /* flags copied from EEPROM */ + u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */ /* Radio/DSP gain settings for each "normal" data Tx rate. * These include, in addition to RF and DSP gain, a few fields for @@ -649,7 +649,7 @@ struct iwl_sensitivity_ranges { * @rx_wrt_ptr_reg: FH{39}_RSCSR_CHNL0_WPTR * @max_stations: * @bcast_sta_id: - * @fat_channel: is 40MHz width possible in band 2.4 + * @ht40_channel: is 40MHz width possible in band 2.4 * BIT(IEEE80211_BAND_5GHZ) BIT(IEEE80211_BAND_5GHZ) * @sw_crypto: 0 for hw, 1 for sw * @max_xxx_size: for ucode uses @@ -673,7 +673,7 @@ struct iwl_hw_params { u32 max_pkt_size; u8 max_stations; u8 bcast_sta_id; - u8 fat_channel; + u8 ht40_channel; u8 max_beacon_itrvl; /* in 1024 ms */ u32 max_inst_size; u32 max_data_size; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 51eed722666..78c4a324a3b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -127,11 +127,11 @@ static const u8 iwl_eeprom_band_5[] = { /* 5725-5825MHz */ 145, 149, 153, 157, 161, 165 }; -static const u8 iwl_eeprom_band_6[] = { /* 2.4 FAT channel */ +static const u8 iwl_eeprom_band_6[] = { /* 2.4 ht40 channel */ 1, 2, 3, 4, 5, 6, 7 }; -static const u8 iwl_eeprom_band_7[] = { /* 5.2 FAT channel */ +static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */ 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157 }; @@ -462,13 +462,13 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_5; break; - case 6: /* 2.4GHz FAT channels */ + case 6: /* 2.4GHz ht40 channels */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6); *eeprom_ch_info = (struct iwl_eeprom_channel *) iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_6; break; - case 7: /* 5 GHz FAT channels */ + case 7: /* 5 GHz ht40 channels */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7); *eeprom_ch_info = (struct iwl_eeprom_channel *) iwl_eeprom_query_addr(priv, offset); @@ -484,14 +484,14 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, ? # x " " : "") /** - * iwl_set_fat_chan_info - Copy fat channel info into driver's priv. + * iwl_set_ht40_chan_info - Copy ht40 channel info into driver's priv. * * Does not set up a command, or touch hardware. */ -static int iwl_set_fat_chan_info(struct iwl_priv *priv, +static int iwl_set_ht40_chan_info(struct iwl_priv *priv, enum ieee80211_band band, u16 channel, const struct iwl_eeprom_channel *eeprom_ch, - u8 fat_extension_channel) + u8 ht40_extension_channel) { struct iwl_channel_info *ch_info; @@ -501,7 +501,7 @@ static int iwl_set_fat_chan_info(struct iwl_priv *priv, if (!is_channel_valid(ch_info)) return -1; - IWL_DEBUG_INFO(priv, "FAT Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm):" + IWL_DEBUG_INFO(priv, "HT40 Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm):" " Ad-Hoc %ssupported\n", ch_info->channel, is_channel_a_band(ch_info) ? @@ -517,13 +517,13 @@ static int iwl_set_fat_chan_info(struct iwl_priv *priv, && !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ? "" : "not "); - ch_info->fat_eeprom = *eeprom_ch; - ch_info->fat_max_power_avg = eeprom_ch->max_power_avg; - ch_info->fat_curr_txpow = eeprom_ch->max_power_avg; - ch_info->fat_min_power = 0; - ch_info->fat_scan_power = eeprom_ch->max_power_avg; - ch_info->fat_flags = eeprom_ch->flags; - ch_info->fat_extension_channel = fat_extension_channel; + ch_info->ht40_eeprom = *eeprom_ch; + ch_info->ht40_max_power_avg = eeprom_ch->max_power_avg; + ch_info->ht40_curr_txpow = eeprom_ch->max_power_avg; + ch_info->ht40_min_power = 0; + ch_info->ht40_scan_power = eeprom_ch->max_power_avg; + ch_info->ht40_flags = eeprom_ch->flags; + ch_info->ht40_extension_channel = ht40_extension_channel; return 0; } @@ -589,9 +589,9 @@ int iwl_init_channel_map(struct iwl_priv *priv) /* Copy the run-time flags so they are there even on * invalid channels */ ch_info->flags = eeprom_ch_info[ch].flags; - /* First write that fat is not enabled, and then enable + /* First write that ht40 is not enabled, and then enable * one by one */ - ch_info->fat_extension_channel = + ch_info->ht40_extension_channel = (IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS); @@ -642,17 +642,17 @@ int iwl_init_channel_map(struct iwl_priv *priv) } } - /* Check if we do have FAT channels */ + /* Check if we do have HT40 channels */ if (priv->cfg->ops->lib->eeprom_ops.regulatory_bands[5] == - EEPROM_REGULATORY_BAND_NO_FAT && + EEPROM_REGULATORY_BAND_NO_HT40 && priv->cfg->ops->lib->eeprom_ops.regulatory_bands[6] == - EEPROM_REGULATORY_BAND_NO_FAT) + EEPROM_REGULATORY_BAND_NO_HT40) return 0; - /* Two additional EEPROM bands for 2.4 and 5 GHz FAT channels */ + /* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */ for (band = 6; band <= 7; band++) { enum ieee80211_band ieeeband; - u8 fat_extension_chan; + u8 ht40_extension_chan; iwl_init_band_reference(priv, band, &eeprom_ch_count, &eeprom_ch_info, &eeprom_ch_index); @@ -669,19 +669,19 @@ int iwl_init_channel_map(struct iwl_priv *priv) (eeprom_ch_index[ch] == 6) || (eeprom_ch_index[ch] == 7))) /* both are allowed: above and below */ - fat_extension_chan = 0; + ht40_extension_chan = 0; else - fat_extension_chan = + ht40_extension_chan = IEEE80211_CHAN_NO_HT40MINUS; /* Set up driver's info for lower half */ - iwl_set_fat_chan_info(priv, ieeeband, + iwl_set_ht40_chan_info(priv, ieeeband, eeprom_ch_index[ch], &(eeprom_ch_info[ch]), - fat_extension_chan); + ht40_extension_chan); /* Set up driver's info for upper half */ - iwl_set_fat_chan_info(priv, ieeeband, + iwl_set_ht40_chan_info(priv, ieeeband, (eeprom_ch_index[ch] + 4), &(eeprom_ch_info[ch]), IEEE80211_CHAN_NO_HT40PLUS); diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 195b4ef12c2..05d4fc4451d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -88,10 +88,10 @@ struct iwl_priv; * requirement for establishing a new network for legal operation on channels * requiring RADAR detection or restricting ACTIVE scanning. * - * NOTE: "WIDE" flag does not indicate anything about "FAT" 40 MHz channels. - * It only indicates that 20 MHz channel use is supported; FAT channel + * NOTE: "WIDE" flag does not indicate anything about "HT40" 40 MHz channels. + * It only indicates that 20 MHz channel use is supported; HT40 channel * usage is indicated by a separate set of regulatory flags for each - * FAT channel pair. + * HT40 channel pair. * * NOTE: Using a channel inappropriately will result in a uCode error! */ @@ -112,7 +112,7 @@ enum { #define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) /* *regulatory* channel data format in eeprom, one for each channel. - * There are separate entries for FAT (40 MHz) vs. normal (20 MHz) channels. */ + * There are separate entries for HT40 (40 MHz) vs. normal (20 MHz) channels. */ struct iwl_eeprom_channel { u8 flags; /* EEPROM_CHANNEL_* flags copied from EEPROM */ s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ @@ -170,9 +170,9 @@ struct iwl_eeprom_channel { | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */ #define EEPROM_5000_REG_BAND_5_CHANNELS ((0x74)\ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 12 bytes */ -#define EEPROM_5000_REG_BAND_24_FAT_CHANNELS ((0x82)\ +#define EEPROM_5000_REG_BAND_24_HT40_CHANNELS ((0x82)\ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 14 bytes */ -#define EEPROM_5000_REG_BAND_52_FAT_CHANNELS ((0x92)\ +#define EEPROM_5000_REG_BAND_52_HT40_CHANNELS ((0x92)\ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */ /* 5050 Specific */ @@ -313,7 +313,7 @@ struct iwl_eeprom_calib_info { * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory * txpower (MSB). * - * Entries immediately below are for 20 MHz channel width. FAT (40 MHz) + * Entries immediately below are for 20 MHz channel width. HT40 (40 MHz) * channels (only for 4965, not supported by 3945) appear later in the EEPROM. * * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 @@ -352,29 +352,29 @@ struct iwl_eeprom_calib_info { #define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ /* - * 2.4 GHz FAT channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) + * 2.4 GHz HT40 channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) * * The channel listed is the center of the lower 20 MHz half of the channel. * The overall center frequency is actually 2 channels (10 MHz) above that, - * and the upper half of each FAT channel is centered 4 channels (20 MHz) away - * from the lower half; e.g. the upper half of FAT channel 1 is channel 5, - * and the overall FAT channel width centers on channel 3. + * and the upper half of each HT40 channel is centered 4 channels (20 MHz) away + * from the lower half; e.g. the upper half of HT40 channel 1 is channel 5, + * and the overall HT40 channel width centers on channel 3. * * NOTE: The RXON command uses 20 MHz channel numbers to specify the * control channel to which to tune. RXON also specifies whether the - * control channel is the upper or lower half of a FAT channel. + * control channel is the upper or lower half of a HT40 channel. * - * NOTE: 4965 does not support FAT channels on 2.4 GHz. + * NOTE: 4965 does not support HT40 channels on 2.4 GHz. */ -#define EEPROM_4965_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0) /* 14 bytes */ +#define EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS (2*0xA0) /* 14 bytes */ /* - * 5.2 GHz FAT channels 36 (40), 44 (48), 52 (56), 60 (64), + * 5.2 GHz HT40 channels 36 (40), 44 (48), 52 (56), 60 (64), * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161) */ -#define EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8) /* 22 bytes */ +#define EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS (2*0xA8) /* 22 bytes */ -#define EEPROM_REGULATORY_BAND_NO_FAT (0) +#define EEPROM_REGULATORY_BAND_NO_HT40 (0) struct iwl_eeprom_ops { const u32 regulatory_bands[7]; diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 00937b3ee8e..594b5c2540b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -583,7 +583,7 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) /* disable HT */ rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | - RXON_FLG_FAT_PROT_MSK | + RXON_FLG_HT40_PROT_MSK | RXON_FLG_HT_PROT_MSK); else { /* check HT capability and set diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 98f014276e6..9e63f9d149e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -544,8 +544,8 @@ void iwl_rx_statistics(struct iwl_priv *priv, change = ((priv->statistics.general.temperature != pkt->u.stats.general.temperature) || ((priv->statistics.flag & - STATISTICS_REPLY_FLG_FAT_MODE_MSK) != - (pkt->u.stats.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK))); + STATISTICS_REPLY_FLG_HT40_MODE_MSK) != + (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK))); memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index def12545d9a..c6633fec821 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -214,10 +214,10 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, sta_flags |= cpu_to_le32( (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); - if (iwl_is_fat_tx_allowed(priv, sta_ht_inf)) - sta_flags |= STA_FLG_FAT_EN_MSK; + if (iwl_is_ht40_tx_allowed(priv, sta_ht_inf)) + sta_flags |= STA_FLG_HT40_EN_MSK; else - sta_flags &= ~STA_FLG_FAT_EN_MSK; + sta_flags &= ~STA_FLG_HT40_EN_MSK; priv->stations[index].sta.station_flags = sta_flags; done: -- cgit v1.2.3-18-g5258 From 20594eb0daa67f7a0cc19d74a1bafceb1bb09f4a Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 7 Aug 2009 15:41:39 -0700 Subject: iwlwifi: new debugging feature for dumping data traffic The traffic buffer will only beallocated and used if either bit 23 (IWL_DX_TX) or bit 24 (IWL_DL_RX) of "debug" is set; example: "debug=0x800000" - log tx data traffic "debug=0x1000000" - log rx data traffic "debug=0x1800000" - log both tx and rx traffic The traffic log will store the beginning portion (64 bytes) of the latest 256 of tx and rx packets in the round-robbin buffer for debugging, user can examine the log through debugfs file. How to display the current logged tx/rx traffic and txfifo and rxfifo read/write point: "cat traffic_log" in /sys/kernel/debug/ieee80211/phy0/iwlagn/debug directory By echo "0" to traffic_log file will empty the traffic log buffer and reset both tx and rx taffic log index to 0. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 1 + drivers/net/wireless/iwlwifi/iwl-agn.c | 11 ++- drivers/net/wireless/iwlwifi/iwl-core.c | 100 +++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 28 ++++++++ drivers/net/wireless/iwlwifi/iwl-debug.h | 4 ++ drivers/net/wireless/iwlwifi/iwl-debugfs.c | 102 ++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-dev.h | 6 ++ drivers/net/wireless/iwlwifi/iwl-rx.c | 1 + drivers/net/wireless/iwlwifi/iwl-tx.c | 1 + drivers/net/wireless/iwlwifi/iwl3945-base.c | 13 +++- 10 files changed, 262 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 9e33507661d..bfd509f7af2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -679,6 +679,7 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv, /* Set "1" to report good data frames in groups of 100 */ iwl3945_dbg_report_frame(priv, pkt, header, 1); + iwl_dbg_log_rx_data_frame(priv, le16_to_cpu(rx_hdr->len), header); if (network_packet) { priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 24c1ae6b816..c9a1aacb243 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2476,9 +2476,12 @@ static ssize_t store_debug_level(struct device *d, ret = strict_strtoul(buf, 0, &val); if (ret) IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf); - else + else { priv->debug_level = val; - + if (iwl_alloc_traffic_mem(priv)) + IWL_ERR(priv, + "Not enough memory to generate traffic log\n"); + } return strnlen(buf, count); } @@ -2819,6 +2822,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) #ifdef CONFIG_IWLWIFI_DEBUG atomic_set(&priv->restrict_refcnt, 0); #endif + if (iwl_alloc_traffic_mem(priv)) + IWL_ERR(priv, "Not enough memory to generate traffic log\n"); /************************** * 2. Initializing PCI bus @@ -3003,6 +3008,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_disable_device(pdev); out_ieee80211_free_hw: ieee80211_free_hw(priv->hw); + iwl_free_traffic_mem(priv); out: return err; } @@ -3061,6 +3067,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) * until now... */ destroy_workqueue(priv->workqueue); priv->workqueue = NULL; + iwl_free_traffic_mem(priv); free_irq(priv->pci_dev->irq, priv); pci_disable_msi(priv->pci_dev); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 5315d347a00..1ae2ce3512c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2953,6 +2953,106 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw) } EXPORT_SYMBOL(iwl_mac_reset_tsf); +#ifdef CONFIG_IWLWIFI_DEBUGFS + +#define IWL_TRAFFIC_DUMP_SIZE (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES) + +void iwl_reset_traffic_log(struct iwl_priv *priv) +{ + priv->tx_traffic_idx = 0; + priv->rx_traffic_idx = 0; + if (priv->tx_traffic) + memset(priv->tx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE); + if (priv->rx_traffic) + memset(priv->rx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE); +} + +int iwl_alloc_traffic_mem(struct iwl_priv *priv) +{ + u32 traffic_size = IWL_TRAFFIC_DUMP_SIZE; + + if (iwl_debug_level & IWL_DL_TX) { + if (!priv->tx_traffic) { + priv->tx_traffic = + kzalloc(traffic_size, GFP_KERNEL); + if (!priv->tx_traffic) + return -ENOMEM; + } + } + if (iwl_debug_level & IWL_DL_RX) { + if (!priv->rx_traffic) { + priv->rx_traffic = + kzalloc(traffic_size, GFP_KERNEL); + if (!priv->rx_traffic) + return -ENOMEM; + } + } + iwl_reset_traffic_log(priv); + return 0; +} +EXPORT_SYMBOL(iwl_alloc_traffic_mem); + +void iwl_free_traffic_mem(struct iwl_priv *priv) +{ + kfree(priv->tx_traffic); + priv->tx_traffic = NULL; + + kfree(priv->rx_traffic); + priv->rx_traffic = NULL; +} +EXPORT_SYMBOL(iwl_free_traffic_mem); + +void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, + u16 length, struct ieee80211_hdr *header) +{ + __le16 fc; + u16 len; + + if (likely(!(iwl_debug_level & IWL_DL_TX))) + return; + + if (!priv->tx_traffic) + return; + + fc = header->frame_control; + if (ieee80211_is_data(fc)) { + len = (length > IWL_TRAFFIC_ENTRY_SIZE) + ? IWL_TRAFFIC_ENTRY_SIZE : length; + memcpy((priv->tx_traffic + + (priv->tx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)), + header, len); + priv->tx_traffic_idx = + (priv->tx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES; + } +} +EXPORT_SYMBOL(iwl_dbg_log_tx_data_frame); + +void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, + u16 length, struct ieee80211_hdr *header) +{ + __le16 fc; + u16 len; + + if (likely(!(iwl_debug_level & IWL_DL_RX))) + return; + + if (!priv->rx_traffic) + return; + + fc = header->frame_control; + if (ieee80211_is_data(fc)) { + len = (length > IWL_TRAFFIC_ENTRY_SIZE) + ? IWL_TRAFFIC_ENTRY_SIZE : length; + memcpy((priv->rx_traffic + + (priv->rx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)), + header, len); + priv->rx_traffic_idx = + (priv->rx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES; + } +} +EXPORT_SYMBOL(iwl_dbg_log_rx_data_frame); +#endif + #ifdef CONFIG_PM int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index dd66148a789..40a9167cacc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -300,7 +300,35 @@ void iwl_config_ap(struct iwl_priv *priv); int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats); void iwl_mac_reset_tsf(struct ieee80211_hw *hw); +#ifdef CONFIG_IWLWIFI_DEBUGFS +int iwl_alloc_traffic_mem(struct iwl_priv *priv); +void iwl_free_traffic_mem(struct iwl_priv *priv); +void iwl_reset_traffic_log(struct iwl_priv *priv); +void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, + u16 length, struct ieee80211_hdr *header); +void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, + u16 length, struct ieee80211_hdr *header); +#else +static inline int iwl_alloc_traffic_mem(struct iwl_priv *priv) +{ + return 0; +} +static inline void iwl_free_traffic_mem(struct iwl_priv *priv) +{ +} +static inline void iwl_reset_traffic_log(struct iwl_priv *priv) +{ +} +static inline void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, + u16 length, struct ieee80211_hdr *header) +{ +} +static inline void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, + u16 length, struct ieee80211_hdr *header) +{ +} +#endif /***************************************************** * RX handlers. * **************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 09af046927a..335ff5c4396 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -72,6 +72,7 @@ struct iwl_debugfs { const char *name; struct dentry *dir_drv; struct dentry *dir_data; + struct dentry *dir_debug; struct dentry *dir_rf; struct dir_data_files { struct dentry *file_sram; @@ -95,6 +96,9 @@ struct iwl_debugfs { struct dentry *file_disable_chain_noise; struct dentry *file_disable_tx_power; } dbgfs_rf_files; + struct dir_debug_files { + struct dentry *file_traffic_log; + } dbgfs_debug_files; u32 sram_offset; u32 sram_len; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 6748a3fb966..031538c4206 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -712,6 +712,104 @@ DEBUGFS_READ_FILE_OPS(led); DEBUGFS_READ_FILE_OPS(thermal_throttling); DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40); +static ssize_t iwl_dbgfs_traffic_log_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + int pos = 0, ofs = 0; + int cnt = 0, entry; + struct iwl_tx_queue *txq; + struct iwl_queue *q; + struct iwl_rx_queue *rxq = &priv->rxq; + char *buf; + int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) + + (IWL_MAX_NUM_QUEUES * 32 * 8) + 400; + const u8 *ptr; + ssize_t ret; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate buffer\n"); + return -ENOMEM; + } + pos += scnprintf(buf + pos, bufsz - pos, "Tx Queue\n"); + for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) { + txq = &priv->txq[cnt]; + q = &txq->q; + pos += scnprintf(buf + pos, bufsz - pos, + "q[%d]: read_ptr: %u, write_ptr: %u\n", + cnt, q->read_ptr, q->write_ptr); + } + if (priv->tx_traffic && (iwl_debug_level & IWL_DL_TX)) { + ptr = priv->tx_traffic; + pos += scnprintf(buf + pos, bufsz - pos, + "Tx Traffic idx: %u\n", priv->tx_traffic_idx); + for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) { + for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16; + entry++, ofs += 16) { + pos += scnprintf(buf + pos, bufsz - pos, + "0x%.4x ", ofs); + hex_dump_to_buffer(ptr + ofs, 16, 16, 2, + buf + pos, bufsz - pos, 0); + pos += strlen(buf); + if (bufsz - pos > 0) + buf[pos++] = '\n'; + } + } + } + + pos += scnprintf(buf + pos, bufsz - pos, "Rx Queue\n"); + pos += scnprintf(buf + pos, bufsz - pos, + "read: %u, write: %u\n", + rxq->read, rxq->write); + + if (priv->rx_traffic && (iwl_debug_level & IWL_DL_RX)) { + ptr = priv->rx_traffic; + pos += scnprintf(buf + pos, bufsz - pos, + "Rx Traffic idx: %u\n", priv->rx_traffic_idx); + for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) { + for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16; + entry++, ofs += 16) { + pos += scnprintf(buf + pos, bufsz - pos, + "0x%.4x ", ofs); + hex_dump_to_buffer(ptr + ofs, 16, 16, 2, + buf + pos, bufsz - pos, 0); + pos += strlen(buf); + if (bufsz - pos > 0) + buf[pos++] = '\n'; + } + } + } + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_traffic_log_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[8]; + int buf_size; + int traffic_log; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%d", &traffic_log) != 1) + return -EFAULT; + if (traffic_log == 0) + iwl_reset_traffic_log(priv); + + return count; +} + +DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); + /* * Create the debugfs files and directories * @@ -738,6 +836,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv); + DEBUGFS_ADD_DIR(debug, dbgfs->dir_drv); DEBUGFS_ADD_FILE(nvm, data); DEBUGFS_ADD_FILE(sram, data); DEBUGFS_ADD_FILE(log_event, data); @@ -753,6 +852,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) #endif DEBUGFS_ADD_FILE(thermal_throttling, data); DEBUGFS_ADD_FILE(disable_ht40, data); + DEBUGFS_ADD_FILE(traffic_log, debug); DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); @@ -794,6 +894,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_ht40); DEBUGFS_REMOVE(priv->dbgfs->dir_data); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_traffic_log); + DEBUGFS_REMOVE(priv->dbgfs->dir_debug); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) || diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 624656a2bba..899b75f28a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -877,6 +877,8 @@ struct iwl_chain_noise_data { #define EEPROM_SEM_TIMEOUT 10 /* milliseconds */ #define EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */ +#define IWL_TRAFFIC_ENTRIES (256) +#define IWL_TRAFFIC_ENTRY_SIZE (64) enum { MEASUREMENT_READY = (1 << 0), @@ -1182,6 +1184,10 @@ struct iwl_priv { bool disable_ht40; #ifdef CONFIG_IWLWIFI_DEBUGFS /* debugfs */ + u16 tx_traffic_idx; + u16 rx_traffic_idx; + u8 *tx_traffic; + u8 *rx_traffic; struct iwl_debugfs *dbgfs; #endif /* CONFIG_IWLWIFI_DEBUGFS */ #endif /* CONFIG_IWLWIFI_DEBUG */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 9e63f9d149e..55860037f98 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -1063,6 +1063,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX)) iwl_dbg_report_frame(priv, rx_start, len, header, 1); #endif + iwl_dbg_log_rx_data_frame(priv, len, header); IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n", rx_status.signal, rx_status.noise, rx_status.qual, (unsigned long long)rx_status.mactime); diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 0cac06c43f9..c85e54cb31d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -808,6 +808,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* TODO need this for burst mode later on */ iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id); + iwl_dbg_log_tx_data_frame(priv, len, hdr); /* set is_hcca to 0; it probably will never be implemented */ iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 0babce250ea..4f5a3d035b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -598,7 +598,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) len = (u16)skb->len; tx->len = cpu_to_le16(len); - + iwl_dbg_log_tx_data_frame(priv, len, hdr); tx->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; tx->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; @@ -3332,9 +3332,12 @@ static ssize_t store_debug_level(struct device *d, ret = strict_strtoul(buf, 0, &val); if (ret) IWL_INFO(priv, "%s is not in hex or decimal form.\n", buf); - else + else { priv->debug_level = val; - + if (iwl_alloc_traffic_mem(priv)) + IWL_ERR(priv, + "Not enough memory to generate traffic log\n"); + } return strnlen(buf, count); } @@ -3976,6 +3979,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e #ifdef CONFIG_IWLWIFI_DEBUG atomic_set(&priv->restrict_refcnt, 0); #endif + if (iwl_alloc_traffic_mem(priv)) + IWL_ERR(priv, "Not enough memory to generate traffic log\n"); /*************************** * 2. Initializing PCI bus @@ -4138,6 +4143,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_disable_device(pdev); out_ieee80211_free_hw: ieee80211_free_hw(priv->hw); + iwl_free_traffic_mem(priv); out: return err; } @@ -4193,6 +4199,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) * until now... */ destroy_workqueue(priv->workqueue); priv->workqueue = NULL; + iwl_free_traffic_mem(priv); free_irq(pdev->irq, priv); pci_disable_msi(pdev); -- cgit v1.2.3-18-g5258 From 22fdf3c9e19dce6d66bcfdbed547a5aa52b89933 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 7 Aug 2009 15:41:40 -0700 Subject: iwlwifi: Traffic type and counter for debugFs Break down the traffic type and counter for both Tx and Rx. Enhance the tx_statistics and rx_statistics debugfs function and move to /sys/kernel/debug/ieee80211/phy0/iwlagn/debug directory to help better debugging both driver and uCode related problems. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 2 + drivers/net/wireless/iwlwifi/iwl-core.c | 158 ++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 9 +- drivers/net/wireless/iwlwifi/iwl-debug.h | 4 +- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 129 ++++++++++++++++++----- drivers/net/wireless/iwlwifi/iwl-dev.h | 48 ++++++++- drivers/net/wireless/iwlwifi/iwl-hcmd.c | 2 - drivers/net/wireless/iwlwifi/iwl-led.c | 3 +- drivers/net/wireless/iwlwifi/iwl-rx.c | 10 +- drivers/net/wireless/iwlwifi/iwl-tx.c | 11 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 1 + 11 files changed, 324 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index bfd509f7af2..ae7f1632ccb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -577,6 +577,8 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, if (ieee80211_is_data(hdr->frame_control)) priv->rxtxpackets += len; #endif + iwl_update_stats(priv, false, hdr->frame_control, len); + memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); ieee80211_rx_irqsafe(priv->hw, rxb->skb); rxb->skb = NULL; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 1ae2ce3512c..202bc3985a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -3051,6 +3051,164 @@ void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, } } EXPORT_SYMBOL(iwl_dbg_log_rx_data_frame); + +const char *get_mgmt_string(int cmd) +{ + switch (cmd) { + IWL_CMD(MANAGEMENT_ASSOC_REQ); + IWL_CMD(MANAGEMENT_ASSOC_RESP); + IWL_CMD(MANAGEMENT_REASSOC_REQ); + IWL_CMD(MANAGEMENT_REASSOC_RESP); + IWL_CMD(MANAGEMENT_PROBE_REQ); + IWL_CMD(MANAGEMENT_PROBE_RESP); + IWL_CMD(MANAGEMENT_BEACON); + IWL_CMD(MANAGEMENT_ATIM); + IWL_CMD(MANAGEMENT_DISASSOC); + IWL_CMD(MANAGEMENT_AUTH); + IWL_CMD(MANAGEMENT_DEAUTH); + IWL_CMD(MANAGEMENT_ACTION); + default: + return "UNKNOWN"; + + } +} + +const char *get_ctrl_string(int cmd) +{ + switch (cmd) { + IWL_CMD(CONTROL_BACK_REQ); + IWL_CMD(CONTROL_BACK); + IWL_CMD(CONTROL_PSPOLL); + IWL_CMD(CONTROL_RTS); + IWL_CMD(CONTROL_CTS); + IWL_CMD(CONTROL_ACK); + IWL_CMD(CONTROL_CFEND); + IWL_CMD(CONTROL_CFENDACK); + default: + return "UNKNOWN"; + + } +} + +void iwl_clear_tx_stats(struct iwl_priv *priv) +{ + memset(&priv->tx_stats, 0, sizeof(struct traffic_stats)); + +} + +void iwl_clear_rx_stats(struct iwl_priv *priv) +{ + memset(&priv->rx_stats, 0, sizeof(struct traffic_stats)); +} + +/* + * if CONFIG_IWLWIFI_DEBUGFS defined, iwl_update_stats function will + * record all the MGMT, CTRL and DATA pkt for both TX and Rx pass. + * Use debugFs to display the rx/rx_statistics + * if CONFIG_IWLWIFI_DEBUGFS not being defined, then no MGMT and CTRL + * information will be recorded, but DATA pkt still will be recorded + * for the reason of iwl_led.c need to control the led blinking based on + * number of tx and rx data. + * + */ +void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) +{ + struct traffic_stats *stats; + + if (is_tx) + stats = &priv->tx_stats; + else + stats = &priv->rx_stats; + + if (ieee80211_is_mgmt(fc)) { + switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { + case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): + stats->mgmt[MANAGEMENT_ASSOC_REQ]++; + break; + case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP): + stats->mgmt[MANAGEMENT_ASSOC_RESP]++; + break; + case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): + stats->mgmt[MANAGEMENT_REASSOC_REQ]++; + break; + case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP): + stats->mgmt[MANAGEMENT_REASSOC_RESP]++; + break; + case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ): + stats->mgmt[MANAGEMENT_PROBE_REQ]++; + break; + case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP): + stats->mgmt[MANAGEMENT_PROBE_RESP]++; + break; + case cpu_to_le16(IEEE80211_STYPE_BEACON): + stats->mgmt[MANAGEMENT_BEACON]++; + break; + case cpu_to_le16(IEEE80211_STYPE_ATIM): + stats->mgmt[MANAGEMENT_ATIM]++; + break; + case cpu_to_le16(IEEE80211_STYPE_DISASSOC): + stats->mgmt[MANAGEMENT_DISASSOC]++; + break; + case cpu_to_le16(IEEE80211_STYPE_AUTH): + stats->mgmt[MANAGEMENT_AUTH]++; + break; + case cpu_to_le16(IEEE80211_STYPE_DEAUTH): + stats->mgmt[MANAGEMENT_DEAUTH]++; + break; + case cpu_to_le16(IEEE80211_STYPE_ACTION): + stats->mgmt[MANAGEMENT_ACTION]++; + break; + } + } else if (ieee80211_is_ctl(fc)) { + switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { + case cpu_to_le16(IEEE80211_STYPE_BACK_REQ): + stats->ctrl[CONTROL_BACK_REQ]++; + break; + case cpu_to_le16(IEEE80211_STYPE_BACK): + stats->ctrl[CONTROL_BACK]++; + break; + case cpu_to_le16(IEEE80211_STYPE_PSPOLL): + stats->ctrl[CONTROL_PSPOLL]++; + break; + case cpu_to_le16(IEEE80211_STYPE_RTS): + stats->ctrl[CONTROL_RTS]++; + break; + case cpu_to_le16(IEEE80211_STYPE_CTS): + stats->ctrl[CONTROL_CTS]++; + break; + case cpu_to_le16(IEEE80211_STYPE_ACK): + stats->ctrl[CONTROL_ACK]++; + break; + case cpu_to_le16(IEEE80211_STYPE_CFEND): + stats->ctrl[CONTROL_CFEND]++; + break; + case cpu_to_le16(IEEE80211_STYPE_CFENDACK): + stats->ctrl[CONTROL_CFENDACK]++; + break; + } + } else { + /* data */ + stats->data_cnt++; + stats->data_bytes += len; + } +} +EXPORT_SYMBOL(iwl_update_stats); + +#else +void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) +{ + struct traffic_stats *stats; + + if (is_tx) + stats = &priv->tx_stats; + else + stats = &priv->rx_stats; + + if (ieee80211_is_data(fc)) { + /* data */ + stats->data_bytes += len; + } +} #endif #ifdef CONFIG_PM diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 40a9167cacc..fc096b929ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -83,6 +83,8 @@ struct iwl_cmd; #define IWL_SKU_A 0x2 #define IWL_SKU_N 0x8 +#define IWL_CMD(x) case x: return #x + struct iwl_hcmd_ops { int (*rxon_assoc)(struct iwl_priv *priv); int (*commit_rxon)(struct iwl_priv *priv); @@ -308,7 +310,10 @@ void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, u16 length, struct ieee80211_hdr *header); void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, u16 length, struct ieee80211_hdr *header); - +const char *get_mgmt_string(int cmd); +const char *get_ctrl_string(int cmd); +void iwl_clear_tx_stats(struct iwl_priv *priv); +void iwl_clear_rx_stats(struct iwl_priv *priv); #else static inline int iwl_alloc_traffic_mem(struct iwl_priv *priv) { @@ -329,6 +334,8 @@ static inline void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, { } #endif +void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, + u16 len); /***************************************************** * RX handlers. * **************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 335ff5c4396..4ac06ad69ed 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -78,8 +78,6 @@ struct iwl_debugfs { struct dentry *file_sram; struct dentry *file_nvm; struct dentry *file_stations; - struct dentry *file_rx_statistics; - struct dentry *file_tx_statistics; struct dentry *file_log_event; struct dentry *file_channels; struct dentry *file_status; @@ -97,6 +95,8 @@ struct iwl_debugfs { struct dentry *file_disable_tx_power; } dbgfs_rf_files; struct dir_debug_files { + struct dentry *file_rx_statistics; + struct dentry *file_tx_statistics; struct dentry *file_traffic_log; } dbgfs_debug_files; u32 sram_offset; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 031538c4206..a0e5063cd8c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -126,18 +126,58 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file, size_t count, loff_t *ppos) { struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - char buf[256]; + char *buf; int pos = 0; - const size_t bufsz = sizeof(buf); - pos += scnprintf(buf + pos, bufsz - pos, "mgmt: %u\n", - priv->tx_stats[0].cnt); - pos += scnprintf(buf + pos, bufsz - pos, "ctrl: %u\n", - priv->tx_stats[1].cnt); - pos += scnprintf(buf + pos, bufsz - pos, "data: %u\n", - priv->tx_stats[2].cnt); + int cnt; + ssize_t ret; + const size_t bufsz = 100 + sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX); + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + pos += scnprintf(buf + pos, bufsz - pos, "Management:\n"); + for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, + "\t%s\t\t: %u\n", + get_mgmt_string(cnt), + priv->tx_stats.mgmt[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "Control\n"); + for (cnt = 0; cnt < CONTROL_MAX; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, + "\t%s\t\t: %u\n", + get_ctrl_string(cnt), + priv->tx_stats.ctrl[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "Data:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n", + priv->tx_stats.data_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n", + priv->tx_stats.data_bytes); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_tx_statistics_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + u32 clear_flag; + char buf[8]; + int buf_size; - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%x", &clear_flag) != 1) + return -EFAULT; + if (clear_flag == 1) + iwl_clear_tx_stats(priv); + + return count; } static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, @@ -145,18 +185,59 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, size_t count, loff_t *ppos) { struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - char buf[256]; + char *buf; int pos = 0; - const size_t bufsz = sizeof(buf); + int cnt; + ssize_t ret; + const size_t bufsz = 100 + + sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX); + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; - pos += scnprintf(buf + pos, bufsz - pos, "mgmt: %u\n", - priv->rx_stats[0].cnt); - pos += scnprintf(buf + pos, bufsz - pos, "ctrl: %u\n", - priv->rx_stats[1].cnt); - pos += scnprintf(buf + pos, bufsz - pos, "data: %u\n", - priv->rx_stats[2].cnt); + pos += scnprintf(buf + pos, bufsz - pos, "Management:\n"); + for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, + "\t%s\t\t: %u\n", + get_mgmt_string(cnt), + priv->rx_stats.mgmt[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "Control:\n"); + for (cnt = 0; cnt < CONTROL_MAX; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, + "\t%s\t\t: %u\n", + get_ctrl_string(cnt), + priv->rx_stats.ctrl[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "Data:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n", + priv->rx_stats.data_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n", + priv->rx_stats.data_bytes); - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_rx_statistics_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + u32 clear_flag; + char buf[8]; + int buf_size; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%x", &clear_flag) != 1) + return -EFAULT; + if (clear_flag == 1) + iwl_clear_rx_stats(priv); + return count; } #define BYTE1_MASK 0x000000ff; @@ -700,8 +781,6 @@ DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_WRITE_FILE_OPS(log_event); DEBUGFS_READ_FILE_OPS(nvm); DEBUGFS_READ_FILE_OPS(stations); -DEBUGFS_READ_FILE_OPS(rx_statistics); -DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_FILE_OPS(channels); DEBUGFS_READ_FILE_OPS(status); DEBUGFS_READ_WRITE_FILE_OPS(interrupt); @@ -808,6 +887,8 @@ static ssize_t iwl_dbgfs_traffic_log_write(struct file *file, return count; } +DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics); +DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); /* @@ -841,8 +922,6 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(sram, data); DEBUGFS_ADD_FILE(log_event, data); DEBUGFS_ADD_FILE(stations, data); - DEBUGFS_ADD_FILE(rx_statistics, data); - DEBUGFS_ADD_FILE(tx_statistics, data); DEBUGFS_ADD_FILE(channels, data); DEBUGFS_ADD_FILE(status, data); DEBUGFS_ADD_FILE(interrupt, data); @@ -852,6 +931,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) #endif DEBUGFS_ADD_FILE(thermal_throttling, data); DEBUGFS_ADD_FILE(disable_ht40, data); + DEBUGFS_ADD_FILE(rx_statistics, debug); + DEBUGFS_ADD_FILE(tx_statistics, debug); DEBUGFS_ADD_FILE(traffic_log, debug); DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, @@ -879,8 +960,6 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) return; DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_nvm); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); @@ -894,6 +973,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_ht40); DEBUGFS_REMOVE(priv->dbgfs->dir_data); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_statistics); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_traffic_log); DEBUGFS_REMOVE(priv->dbgfs->dir_debug); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 899b75f28a2..dcf9d576323 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -919,6 +919,48 @@ struct isr_statistics { u32 unhandled; }; +#ifdef CONFIG_IWLWIFI_DEBUGFS +/* management statistics */ +enum iwl_mgmt_stats { + MANAGEMENT_ASSOC_REQ = 0, + MANAGEMENT_ASSOC_RESP, + MANAGEMENT_REASSOC_REQ, + MANAGEMENT_REASSOC_RESP, + MANAGEMENT_PROBE_REQ, + MANAGEMENT_PROBE_RESP, + MANAGEMENT_BEACON, + MANAGEMENT_ATIM, + MANAGEMENT_DISASSOC, + MANAGEMENT_AUTH, + MANAGEMENT_DEAUTH, + MANAGEMENT_ACTION, + MANAGEMENT_MAX, +}; +/* control statistics */ +enum iwl_ctrl_stats { + CONTROL_BACK_REQ = 0, + CONTROL_BACK, + CONTROL_PSPOLL, + CONTROL_RTS, + CONTROL_CTS, + CONTROL_ACK, + CONTROL_CFEND, + CONTROL_CFENDACK, + CONTROL_MAX, +}; + +struct traffic_stats { + u32 mgmt[MANAGEMENT_MAX]; + u32 ctrl[CONTROL_MAX]; + u32 data_cnt; + u64 data_bytes; +}; +#else +struct traffic_stats { + u64 data_bytes; +}; +#endif + #define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */ struct iwl_priv { @@ -1064,10 +1106,8 @@ struct iwl_priv { int last_rx_noise; /* From beacon statistics */ /* counts mgmt, ctl, and data packets */ - struct traffic_stats { - u32 cnt; - u64 bytes; - } tx_stats[3], rx_stats[3]; + struct traffic_stats tx_stats; + struct traffic_stats rx_stats; /* counts interrupts */ struct isr_statistics isr_stats; diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index b82ad15d518..532c8d6cd8d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -36,8 +36,6 @@ #include "iwl-core.h" -#define IWL_CMD(x) case x: return #x - const char *get_cmd_string(u8 cmd) { switch (cmd) { diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 3d61cb43151..f420c99e724 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -272,7 +272,8 @@ static int iwl_get_blink_rate(struct iwl_priv *priv) /* count both tx and rx traffic to be able to * handle traffic in either direction */ - u64 current_tpt = priv->tx_stats[2].bytes + priv->rx_stats[2].bytes; + u64 current_tpt = priv->tx_stats.data_bytes + + priv->rx_stats.data_bytes; s64 tpt = current_tpt - priv->led_tpt; if (tpt < 0) /* wraparound */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 55860037f98..43b2fce4cbf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -745,14 +745,6 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, } #endif -static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len) -{ - /* 0 - mgmt, 1 - cnt, 2 - data */ - int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; - priv->rx_stats[idx].cnt++; - priv->rx_stats[idx].bytes += len; -} - /* * returns non-zero if packet should be dropped */ @@ -930,7 +922,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; - iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len); + iwl_update_stats(priv, false, hdr->frame_control, len); memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); ieee80211_rx_irqsafe(priv->hw, rxb->skb); priv->alloc_rxb_skb--; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index c85e54cb31d..9b76bd41f21 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -668,14 +668,6 @@ static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv, } } -static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len) -{ - /* 0 - mgmt, 1 - cnt, 2 - data */ - int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; - priv->tx_stats[idx].cnt++; - priv->tx_stats[idx].bytes += len; -} - /* * start REPLY_TX command process */ @@ -813,8 +805,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* set is_hcca to 0; it probably will never be implemented */ iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0); - iwl_update_tx_stats(priv, le16_to_cpu(fc), len); - + iwl_update_stats(priv, true, fc, len); /* * Use the first empty entry in this queue's command buffer array * to contain the Tx command and MAC header concatenated together diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 4f5a3d035b0..e5fa672e839 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -599,6 +599,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) tx->len = cpu_to_le16(len); iwl_dbg_log_tx_data_frame(priv, len, hdr); + iwl_update_stats(priv, true, fc, len); tx->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; tx->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; -- cgit v1.2.3-18-g5258 From 141b03e07a54af68fc099459bf780a182b240b45 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 7 Aug 2009 15:41:41 -0700 Subject: iwlwifi: tx/rx queue pointer information Adding debugfs function to show current TxFifo/RxFifo read/write pointer, plus the current tx queue status (wake/stop) for both real and virtual queue. This is part of debug feature set to help debugging driver/uCode. use tx_queue and rx_queue in /sys/kernel/debug/ieee80211/phy0/iwlagn/debug directory to show the current read/write pointer for both TxFifo and RxFifo queue Signed-off-by: Wey-Yi Guy Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debug.h | 2 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 69 ++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 4ac06ad69ed..cad5e27fe8b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -98,6 +98,8 @@ struct iwl_debugfs { struct dentry *file_rx_statistics; struct dentry *file_tx_statistics; struct dentry *file_traffic_log; + struct dentry *file_rx_queue; + struct dentry *file_tx_queue; } dbgfs_debug_files; u32 sram_offset; u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index a0e5063cd8c..d4109cbb4f3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -887,9 +887,74 @@ static ssize_t iwl_dbgfs_traffic_log_write(struct file *file, return count; } +static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_tx_queue *txq; + struct iwl_queue *q; + char *buf; + int pos = 0; + int cnt; + int ret; + const size_t bufsz = sizeof(char) * 60 * IWL_MAX_NUM_QUEUES; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) { + txq = &priv->txq[cnt]; + q = &txq->q; + pos += scnprintf(buf + pos, bufsz - pos, + "hwq %.2d: read=%u write=%u stop=%d" + " swq_id=%#.2x (ac %d/hwq %d)\n", + cnt, q->read_ptr, q->write_ptr, + !!test_bit(cnt, priv->queue_stopped), + txq->swq_id, + txq->swq_id & 0x80 ? txq->swq_id & 3 : + txq->swq_id, + txq->swq_id & 0x80 ? (txq->swq_id >> 2) & + 0x1f : txq->swq_id); + if (cnt >= 4) + continue; + /* for the ACs, display the stop count too */ + pos += scnprintf(buf + pos, bufsz - pos, + " stop-count: %d\n", + atomic_read(&priv->queue_stop_count[cnt])); + } + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_rx_queue *rxq = &priv->rxq; + char buf[256]; + int pos = 0; + const size_t bufsz = sizeof(buf); + + pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n", + rxq->read); + pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n", + rxq->write); + pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n", + rxq->free_count); + pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n", + le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF); + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); +DEBUGFS_READ_FILE_OPS(rx_queue); +DEBUGFS_READ_FILE_OPS(tx_queue); /* * Create the debugfs files and directories @@ -934,6 +999,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(rx_statistics, debug); DEBUGFS_ADD_FILE(tx_statistics, debug); DEBUGFS_ADD_FILE(traffic_log, debug); + DEBUGFS_ADD_FILE(rx_queue, debug); + DEBUGFS_ADD_FILE(tx_queue, debug); DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); @@ -976,6 +1043,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_traffic_log); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_queue); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue); DEBUGFS_REMOVE(priv->dbgfs->dir_debug); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); -- cgit v1.2.3-18-g5258 From e8fe59aecb9020b06305be4f8c67d73cbf49cbd2 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 7 Aug 2009 15:41:42 -0700 Subject: iwlwifi: uCode statistics notification counter Display statistics notification information The information break down into uCode_tx_stats uCode_rx_stats uCode_general_stats and can be found in /sys/kernel/debug/ieee80211/phy0/iwlagn/debug directory The statistic information display in debugFs is based on the last statistics notification from uCode; it might not reflect the current uCode activity. Using "watch" command to monitor the uCode activity should give up-to-date statistics provided by uCode. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debug.h | 3 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 412 +++++++++++++++++++++++++++++ 2 files changed, 415 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index cad5e27fe8b..18b8cf79213 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -100,6 +100,9 @@ struct iwl_debugfs { struct dentry *file_traffic_log; struct dentry *file_rx_queue; struct dentry *file_tx_queue; + struct dentry *file_ucode_rx_stats; + struct dentry *file_ucode_tx_stats; + struct dentry *file_ucode_general_stats; } dbgfs_debug_files; u32 sram_offset; u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index d4109cbb4f3..20e4edb36ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -950,11 +950,410 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +#define UCODE_STATISTICS_CLEAR_MSK (0x1 << 0) +#define UCODE_STATISTICS_FREQUENCY_MSK (0x1 << 1) +#define UCODE_STATISTICS_NARROW_BAND_MSK (0x1 << 2) + +static int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf, + int bufsz) +{ + int p = 0; + + p += scnprintf(buf + p, bufsz - p, + "Statistics Flag(0x%X):\n", + le32_to_cpu(priv->statistics.flag)); + if (le32_to_cpu(priv->statistics.flag) & UCODE_STATISTICS_CLEAR_MSK) + p += scnprintf(buf + p, bufsz - p, + "\tStatistics have been cleared\n"); + p += scnprintf(buf + p, bufsz - p, + "\tOperational Frequency: %s\n", + (le32_to_cpu(priv->statistics.flag) & + UCODE_STATISTICS_FREQUENCY_MSK) + ? "2.4 GHz" : "5.2 GHz"); + p += scnprintf(buf + p, bufsz - p, + "\tTGj Narrow Band: %s\n", + (le32_to_cpu(priv->statistics.flag) & + UCODE_STATISTICS_NARROW_BAND_MSK) + ? "enabled" : "disabled"); + return p; +} + + +static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char *buf; + int bufsz = sizeof(struct statistics_rx_phy) * 20 + + sizeof(struct statistics_rx_non_phy) * 20 + + sizeof(struct statistics_rx_ht_phy) * 20 + 400; + ssize_t ret; + struct statistics_rx_phy *ofdm; + struct statistics_rx_phy *cck; + struct statistics_rx_non_phy *general; + struct statistics_rx_ht_phy *ht; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + ret = iwl_send_statistics_request(priv, 0); + mutex_unlock(&priv->mutex); + + if (ret) { + IWL_ERR(priv, + "Error sending statistics request: %zd\n", ret); + return -EAGAIN; + } + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + ofdm = &priv->statistics.rx.ofdm; + cck = &priv->statistics.rx.cck; + general = &priv->statistics.rx.general; + ht = &priv->statistics.rx.ofdm_ht; + pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt: %u\n", + le32_to_cpu(ofdm->ina_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt: %u\n", + le32_to_cpu(ofdm->fina_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n", + le32_to_cpu(ofdm->plcp_err)); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n", + le32_to_cpu(ofdm->crc32_err)); + pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n", + le32_to_cpu(ofdm->overrun_err)); + pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n", + le32_to_cpu(ofdm->early_overrun_err)); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n", + le32_to_cpu(ofdm->crc32_good)); + pos += scnprintf(buf + pos, bufsz - pos, "false_alarm_cnt: %u\n", + le32_to_cpu(ofdm->false_alarm_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "fina_sync_err_cnt: %u\n", + le32_to_cpu(ofdm->fina_sync_err_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "sfd_timeout: %u\n", + le32_to_cpu(ofdm->sfd_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, "fina_timeout: %u\n", + le32_to_cpu(ofdm->fina_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, "unresponded_rts: %u\n", + le32_to_cpu(ofdm->unresponded_rts)); + pos += scnprintf(buf + pos, bufsz - pos, + "rxe_frame_limit_overrun: %u\n", + le32_to_cpu(ofdm->rxe_frame_limit_overrun)); + pos += scnprintf(buf + pos, bufsz - pos, "sent_ack_cnt: %u\n", + le32_to_cpu(ofdm->sent_ack_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "sent_cts_cnt: %u\n", + le32_to_cpu(ofdm->sent_cts_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "sent_ba_rsp_cnt: %u\n", + le32_to_cpu(ofdm->sent_ba_rsp_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "dsp_self_kill: %u\n", + le32_to_cpu(ofdm->dsp_self_kill)); + pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n", + le32_to_cpu(ofdm->mh_format_err)); + pos += scnprintf(buf + pos, bufsz - pos, "re_acq_main_rssi_sum: %u\n", + le32_to_cpu(ofdm->re_acq_main_rssi_sum)); + + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - CCK:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt: %u\n", + le32_to_cpu(cck->ina_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt: %u\n", + le32_to_cpu(cck->fina_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n", + le32_to_cpu(cck->plcp_err)); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n", + le32_to_cpu(cck->crc32_err)); + pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n", + le32_to_cpu(cck->overrun_err)); + pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n", + le32_to_cpu(cck->early_overrun_err)); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n", + le32_to_cpu(cck->crc32_good)); + pos += scnprintf(buf + pos, bufsz - pos, "false_alarm_cnt: %u\n", + le32_to_cpu(cck->false_alarm_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "fina_sync_err_cnt: %u\n", + le32_to_cpu(cck->fina_sync_err_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "sfd_timeout: %u\n", + le32_to_cpu(cck->sfd_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, "fina_timeout: %u\n", + le32_to_cpu(cck->fina_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, "unresponded_rts: %u\n", + le32_to_cpu(cck->unresponded_rts)); + pos += scnprintf(buf + pos, bufsz - pos, + "rxe_frame_limit_overrun: %u\n", + le32_to_cpu(cck->rxe_frame_limit_overrun)); + pos += scnprintf(buf + pos, bufsz - pos, "sent_ack_cnt: %u\n", + le32_to_cpu(cck->sent_ack_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "sent_cts_cnt: %u\n", + le32_to_cpu(cck->sent_cts_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "sent_ba_rsp_cnt: %u\n", + le32_to_cpu(cck->sent_ba_rsp_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "dsp_self_kill: %u\n", + le32_to_cpu(cck->dsp_self_kill)); + pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n", + le32_to_cpu(cck->mh_format_err)); + pos += scnprintf(buf + pos, bufsz - pos, "re_acq_main_rssi_sum: %u\n", + le32_to_cpu(cck->re_acq_main_rssi_sum)); + + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - GENERAL:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "bogus_cts: %u\n", + le32_to_cpu(general->bogus_cts)); + pos += scnprintf(buf + pos, bufsz - pos, "bogus_ack: %u\n", + le32_to_cpu(general->bogus_ack)); + pos += scnprintf(buf + pos, bufsz - pos, "non_bssid_frames: %u\n", + le32_to_cpu(general->non_bssid_frames)); + pos += scnprintf(buf + pos, bufsz - pos, "filtered_frames: %u\n", + le32_to_cpu(general->filtered_frames)); + pos += scnprintf(buf + pos, bufsz - pos, "non_channel_beacons: %u\n", + le32_to_cpu(general->non_channel_beacons)); + pos += scnprintf(buf + pos, bufsz - pos, "channel_beacons: %u\n", + le32_to_cpu(general->channel_beacons)); + pos += scnprintf(buf + pos, bufsz - pos, "num_missed_bcon: %u\n", + le32_to_cpu(general->num_missed_bcon)); + pos += scnprintf(buf + pos, bufsz - pos, + "adc_rx_saturation_time: %u\n", + le32_to_cpu(general->adc_rx_saturation_time)); + pos += scnprintf(buf + pos, bufsz - pos, + "ina_detection_search_time: %u\n", + le32_to_cpu(general->ina_detection_search_time)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_a: %u\n", + le32_to_cpu(general->beacon_silence_rssi_a)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_b: %u\n", + le32_to_cpu(general->beacon_silence_rssi_b)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_c: %u\n", + le32_to_cpu(general->beacon_silence_rssi_c)); + pos += scnprintf(buf + pos, bufsz - pos, + "interference_data_flag: %u\n", + le32_to_cpu(general->interference_data_flag)); + pos += scnprintf(buf + pos, bufsz - pos, "channel_load: %u\n", + le32_to_cpu(general->channel_load)); + pos += scnprintf(buf + pos, bufsz - pos, "dsp_false_alarms: %u\n", + le32_to_cpu(general->dsp_false_alarms)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_a: %u\n", + le32_to_cpu(general->beacon_rssi_a)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_b: %u\n", + le32_to_cpu(general->beacon_rssi_b)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_c: %u\n", + le32_to_cpu(general->beacon_rssi_c)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_a: %u\n", + le32_to_cpu(general->beacon_energy_a)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_b: %u\n", + le32_to_cpu(general->beacon_energy_b)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_c: %u\n", + le32_to_cpu(general->beacon_energy_c)); + + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM_HT:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n", + le32_to_cpu(ht->plcp_err)); + pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n", + le32_to_cpu(ht->overrun_err)); + pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n", + le32_to_cpu(ht->early_overrun_err)); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n", + le32_to_cpu(ht->crc32_good)); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n", + le32_to_cpu(ht->crc32_err)); + pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n", + le32_to_cpu(ht->mh_format_err)); + pos += scnprintf(buf + pos, bufsz - pos, "agg_crc32_good: %u\n", + le32_to_cpu(ht->agg_crc32_good)); + pos += scnprintf(buf + pos, bufsz - pos, "agg_mpdu_cnt: %u\n", + le32_to_cpu(ht->agg_mpdu_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt: %u\n", + le32_to_cpu(ht->agg_cnt)); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char *buf; + int bufsz = (sizeof(struct statistics_tx) * 24) + 250; + ssize_t ret; + struct statistics_tx *tx; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + ret = iwl_send_statistics_request(priv, 0); + mutex_unlock(&priv->mutex); + + if (ret) { + IWL_ERR(priv, + "Error sending statistics request: %zd\n", ret); + return -EAGAIN; + } + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + tx = &priv->statistics.tx; + pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Tx:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "preamble: %u\n", + le32_to_cpu(tx->preamble_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "rx_detected_cnt: %u\n", + le32_to_cpu(tx->rx_detected_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "bt_prio_defer_cnt: %u\n", + le32_to_cpu(tx->bt_prio_defer_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "bt_prio_kill_cnt: %u\n", + le32_to_cpu(tx->bt_prio_kill_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "few_bytes_cnt: %u\n", + le32_to_cpu(tx->few_bytes_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "cts_timeout: %u\n", + le32_to_cpu(tx->cts_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, "ack_timeout: %u\n", + le32_to_cpu(tx->ack_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, "expected_ack_cnt: %u\n", + le32_to_cpu(tx->expected_ack_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "actual_ack_cnt: %u\n", + le32_to_cpu(tx->actual_ack_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "dump_msdu_cnt: %u\n", + le32_to_cpu(tx->dump_msdu_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, + "burst_abort_next_frame_mismatch_cnt: %u\n", + le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, + "burst_abort_missing_next_frame_cnt: %u\n", + le32_to_cpu(tx->burst_abort_missing_next_frame_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "cts_timeout_collision: %u\n", + le32_to_cpu(tx->cts_timeout_collision)); + pos += scnprintf(buf + pos, bufsz - pos, + "ack_or_ba_timeout_collision: %u\n", + le32_to_cpu(tx->ack_or_ba_timeout_collision)); + pos += scnprintf(buf + pos, bufsz - pos, "agg ba_timeout: %u\n", + le32_to_cpu(tx->agg.ba_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, + "agg ba_reschedule_frames: %u\n", + le32_to_cpu(tx->agg.ba_reschedule_frames)); + pos += scnprintf(buf + pos, bufsz - pos, + "agg scd_query_agg_frame_cnt: %u\n", + le32_to_cpu(tx->agg.scd_query_agg_frame_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "agg scd_query_no_agg: %u\n", + le32_to_cpu(tx->agg.scd_query_no_agg)); + pos += scnprintf(buf + pos, bufsz - pos, "agg scd_query_agg: %u\n", + le32_to_cpu(tx->agg.scd_query_agg)); + pos += scnprintf(buf + pos, bufsz - pos, + "agg scd_query_mismatch: %u\n", + le32_to_cpu(tx->agg.scd_query_mismatch)); + pos += scnprintf(buf + pos, bufsz - pos, "agg frame_not_ready: %u\n", + le32_to_cpu(tx->agg.frame_not_ready)); + pos += scnprintf(buf + pos, bufsz - pos, "agg underrun: %u\n", + le32_to_cpu(tx->agg.underrun)); + pos += scnprintf(buf + pos, bufsz - pos, "agg bt_prio_kill: %u\n", + le32_to_cpu(tx->agg.bt_prio_kill)); + pos += scnprintf(buf + pos, bufsz - pos, "agg rx_ba_rsp_cnt: %u\n", + le32_to_cpu(tx->agg.rx_ba_rsp_cnt)); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char *buf; + int bufsz = sizeof(struct statistics_general) * 4 + 250; + ssize_t ret; + struct statistics_general *general; + struct statistics_dbg *dbg; + struct statistics_div *div; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + ret = iwl_send_statistics_request(priv, 0); + mutex_unlock(&priv->mutex); + + if (ret) { + IWL_ERR(priv, + "Error sending statistics request: %zd\n", ret); + return -EAGAIN; + } + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + general = &priv->statistics.general; + dbg = &priv->statistics.general.dbg; + div = &priv->statistics.general.div; + pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_General:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "temperature: %u\n", + le32_to_cpu(general->temperature)); + pos += scnprintf(buf + pos, bufsz - pos, "temperature_m: %u\n", + le32_to_cpu(general->temperature_m)); + pos += scnprintf(buf + pos, bufsz - pos, "burst_check: %u\n", + le32_to_cpu(dbg->burst_check)); + pos += scnprintf(buf + pos, bufsz - pos, "burst_count: %u\n", + le32_to_cpu(dbg->burst_count)); + pos += scnprintf(buf + pos, bufsz - pos, "sleep_time: %u\n", + le32_to_cpu(general->sleep_time)); + pos += scnprintf(buf + pos, bufsz - pos, "slots_out: %u\n", + le32_to_cpu(general->slots_out)); + pos += scnprintf(buf + pos, bufsz - pos, "slots_idle: %u\n", + le32_to_cpu(general->slots_idle)); + pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp: %u\n", + le32_to_cpu(general->ttl_timestamp)); + pos += scnprintf(buf + pos, bufsz - pos, "tx_on_a: %u\n", + le32_to_cpu(div->tx_on_a)); + pos += scnprintf(buf + pos, bufsz - pos, "tx_on_b: %u\n", + le32_to_cpu(div->tx_on_b)); + pos += scnprintf(buf + pos, bufsz - pos, "exec_time: %u\n", + le32_to_cpu(div->exec_time)); + pos += scnprintf(buf + pos, bufsz - pos, "probe_time: %u\n", + le32_to_cpu(div->probe_time)); + pos += scnprintf(buf + pos, bufsz - pos, "rx_enable_counter: %u\n", + le32_to_cpu(general->rx_enable_counter)); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); DEBUGFS_READ_FILE_OPS(rx_queue); DEBUGFS_READ_FILE_OPS(tx_queue); +DEBUGFS_READ_FILE_OPS(ucode_rx_stats); +DEBUGFS_READ_FILE_OPS(ucode_tx_stats); +DEBUGFS_READ_FILE_OPS(ucode_general_stats); /* * Create the debugfs files and directories @@ -1001,6 +1400,11 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(traffic_log, debug); DEBUGFS_ADD_FILE(rx_queue, debug); DEBUGFS_ADD_FILE(tx_queue, debug); + if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { + DEBUGFS_ADD_FILE(ucode_rx_stats, debug); + DEBUGFS_ADD_FILE(ucode_tx_stats, debug); + DEBUGFS_ADD_FILE(ucode_general_stats, debug); + } DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); @@ -1045,6 +1449,14 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_traffic_log); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_queue); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue); + if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_ucode_rx_stats); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_ucode_tx_stats); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_ucode_general_stats); + } DEBUGFS_REMOVE(priv->dbgfs->dir_debug); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); -- cgit v1.2.3-18-g5258 From 5225935b53ce1eafb222c644230d03ad6011d357 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 7 Aug 2009 15:41:43 -0700 Subject: iwlwifi: Display sensitivity and chain noise information Display sensitivity and chain noise data to help understand the current environment and RF condition. The data is feeded by statistics notification and Beacon from uCode; then used by sensitivity calibration and chain noise calibration to determine how DSP should react to the environment changes Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debug.h | 2 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 149 ++++++++++++++++++++++++++++- 2 files changed, 150 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 18b8cf79213..82befb7ce99 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -103,6 +103,8 @@ struct iwl_debugfs { struct dentry *file_ucode_rx_stats; struct dentry *file_ucode_tx_stats; struct dentry *file_ucode_general_stats; + struct dentry *file_sensitivity; + struct dentry *file_chain_noise; } dbgfs_debug_files; u32 sram_offset; u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 20e4edb36ec..1ad4ff6bfff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -38,7 +38,7 @@ #include "iwl-debug.h" #include "iwl-core.h" #include "iwl-io.h" - +#include "iwl-calib.h" /* create and remove of files */ #define DEBUGFS_ADD_DIR(name, parent) do { \ @@ -1346,6 +1346,145 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, return ret; } +static ssize_t iwl_dbgfs_sensitivity_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + int cnt = 0; + char *buf; + int bufsz = sizeof(struct iwl_sensitivity_data) * 4 + 100; + ssize_t ret; + struct iwl_sensitivity_data *data; + + data = &priv->sensitivity_data; + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm:\t\t\t %u\n", + data->auto_corr_ofdm); + pos += scnprintf(buf + pos, bufsz - pos, + "auto_corr_ofdm_mrc:\t\t %u\n", + data->auto_corr_ofdm_mrc); + pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_x1:\t\t %u\n", + data->auto_corr_ofdm_x1); + pos += scnprintf(buf + pos, bufsz - pos, + "auto_corr_ofdm_mrc_x1:\t\t %u\n", + data->auto_corr_ofdm_mrc_x1); + pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck:\t\t\t %u\n", + data->auto_corr_cck); + pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck_mrc:\t\t %u\n", + data->auto_corr_cck_mrc); + pos += scnprintf(buf + pos, bufsz - pos, + "last_bad_plcp_cnt_ofdm:\t\t %u\n", + data->last_bad_plcp_cnt_ofdm); + pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_ofdm:\t\t %u\n", + data->last_fa_cnt_ofdm); + pos += scnprintf(buf + pos, bufsz - pos, + "last_bad_plcp_cnt_cck:\t\t %u\n", + data->last_bad_plcp_cnt_cck); + pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_cck:\t\t %u\n", + data->last_fa_cnt_cck); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_curr_state:\t\t\t %u\n", + data->nrg_curr_state); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_prev_state:\t\t\t %u\n", + data->nrg_prev_state); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_value:\t\t\t"); + for (cnt = 0; cnt < 10; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, " %u", + data->nrg_value[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "\n"); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_rssi:\t\t"); + for (cnt = 0; cnt < NRG_NUM_PREV_STAT_L; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, " %u", + data->nrg_silence_rssi[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "\n"); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_ref:\t\t %u\n", + data->nrg_silence_ref); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_energy_idx:\t\t\t %u\n", + data->nrg_energy_idx); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_idx:\t\t %u\n", + data->nrg_silence_idx); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_cck:\t\t\t %u\n", + data->nrg_th_cck); + pos += scnprintf(buf + pos, bufsz - pos, + "nrg_auto_corr_silence_diff:\t %u\n", + data->nrg_auto_corr_silence_diff); + pos += scnprintf(buf + pos, bufsz - pos, "num_in_cck_no_fa:\t\t %u\n", + data->num_in_cck_no_fa); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_ofdm:\t\t\t %u\n", + data->nrg_th_ofdm); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + + +static ssize_t iwl_dbgfs_chain_noise_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + int cnt = 0; + char *buf; + int bufsz = sizeof(struct iwl_chain_noise_data) * 4 + 100; + ssize_t ret; + struct iwl_chain_noise_data *data; + + data = &priv->chain_noise_data; + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + pos += scnprintf(buf + pos, bufsz - pos, "active_chains:\t\t\t %u\n", + data->active_chains); + pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_a:\t\t\t %u\n", + data->chain_noise_a); + pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_b:\t\t\t %u\n", + data->chain_noise_b); + pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_c:\t\t\t %u\n", + data->chain_noise_c); + pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_a:\t\t\t %u\n", + data->chain_signal_a); + pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_b:\t\t\t %u\n", + data->chain_signal_b); + pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_c:\t\t\t %u\n", + data->chain_signal_c); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_count:\t\t\t %u\n", + data->beacon_count); + + pos += scnprintf(buf + pos, bufsz - pos, "disconn_array:\t\t\t"); + for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, " %u", + data->disconn_array[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "\n"); + pos += scnprintf(buf + pos, bufsz - pos, "delta_gain_code:\t\t"); + for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, " %u", + data->delta_gain_code[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "\n"); + pos += scnprintf(buf + pos, bufsz - pos, "radio_write:\t\t\t %u\n", + data->radio_write); + pos += scnprintf(buf + pos, bufsz - pos, "state:\t\t\t\t %u\n", + data->state); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); @@ -1354,6 +1493,8 @@ DEBUGFS_READ_FILE_OPS(tx_queue); DEBUGFS_READ_FILE_OPS(ucode_rx_stats); DEBUGFS_READ_FILE_OPS(ucode_tx_stats); DEBUGFS_READ_FILE_OPS(ucode_general_stats); +DEBUGFS_READ_FILE_OPS(sensitivity); +DEBUGFS_READ_FILE_OPS(chain_noise); /* * Create the debugfs files and directories @@ -1404,6 +1545,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(ucode_rx_stats, debug); DEBUGFS_ADD_FILE(ucode_tx_stats, debug); DEBUGFS_ADD_FILE(ucode_general_stats, debug); + DEBUGFS_ADD_FILE(sensitivity, debug); + DEBUGFS_ADD_FILE(chain_noise, debug); } DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, @@ -1456,6 +1599,10 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) file_ucode_tx_stats); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. file_ucode_general_stats); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_sensitivity); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_chain_noise); } DEBUGFS_REMOVE(priv->dbgfs->dir_debug); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); -- cgit v1.2.3-18-g5258 From c03ea16285bf142172f9816b8a1f5c43bb4b4405 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 7 Aug 2009 15:41:44 -0700 Subject: iwlwifi: revert uCode Alive notification with timeout commit "iwlwifi: uCode Alive notification with timeout" introduced a more reliable mechanism for ucode loading. Unfortunately we hit a problem with it frequently enough to make a 4965 unusable. The problem can be seen in debug log below. What this code attempts is to set runtime ucode up to load, start a timer to wait for the alive response from runtime ucode, and if it times out it tries again. As can be seen below we receive the alive response and wake the waiting task _before_ the tasks starts waiting. The task thus times out as the alive response is not received while it is waiting for it and it restarts the device. This starts the cycle all over again. [29739.000819] ieee80211 phy0: U iwl_mac_start enter [29739.005751] ieee80211 phy0: U iwl_prepare_card_hw iwl_prepare_card_hw enter [29739.012798] ieee80211 phy0: U iwl_set_hw_ready hardware ready [29739.057200] ieee80211 phy0: U iwl4965_load_bsm Begin load bsm [29739.063366] ieee80211 phy0: U iwl4965_verify_bsm Begin verify bsm [29739.072485] ieee80211 phy0: U iwl4965_verify_bsm BSM bootstrap uCode image OK [29739.079671] ieee80211 phy0: U iwl4965_load_bsm BSM write complete, poll 0 iterations [29739.257019] ieee80211 phy0: I iwl_rx_reply_alive Alive ucode status 0x00000001 revision 0x1 0x9 [29739.260964] ieee80211 phy0: I iwl_rx_reply_alive Initialization Alive received. [29739.260964] ieee80211 phy0: U __iwl_up iwlagn is coming up [29739.278571] ieee80211 phy0: U iwl_mac_start Start UP work done. [29739.284509] ieee80211 phy0: U iwlcore_verify_inst_sparse ucode inst image size is 788 [29739.292432] ieee80211 phy0: U iwlcore_verify_inst_sparse ucode inst image size is 10312 [29739.302004] ieee80211 phy0: U iwl_verify_ucode Initialize uCode is good in inst SRAM [29739.309746] ieee80211 phy0: U iwl4965_hw_get_temperature Running temperature calibration [29739.317833] ieee80211 phy0: U iwl4965_hw_get_temperature Calib values R[1-3]: -36 13522 -13496 R4: -2726 [29739.327337] ieee80211 phy0: U iwl4965_hw_get_temperature Calibrated temperature: 310K, 37C [29739.335598] ieee80211 phy0: U iwl4965_init_alive_start Initialization Alive received. [29739.343477] ieee80211 phy0: U iwl4965_set_ucode_ptrs Runtime uCode pointers are set. [29739.351283] ieee80211 phy0: I iwl_rx_reply_alive Alive ucode status 0x00000001 revision 0x1 0x0 [29739.355210] ieee80211 phy0: I iwl_rx_reply_alive Runtime Alive received. [29739.366731] iwlagn 0000:03:00.0: Runtime uCode already alive? Waiting for alive anyway [29743.284110] iwlagn 0000:03:00.0: START_ALIVE timeout after 4000ms. [29743.290337] ieee80211 phy0: U iwl_mac_add_interface enter: type 2 [29744.364089] iwlagn 0000:03:00.0: Runtime timeout after 5000ms [29744.370882] ieee80211 phy0: U iwl_alive_start Runtime Alive received. [29744.377347] ieee80211 phy0: U iwlcore_verify_inst_sparse ucode inst image size is 788 [29744.385287] ieee80211 phy0: U iwlcore_verify_inst_sparse ucode inst image size is 10312 [29744.393397] ieee80211 phy0: U iwlcore_verify_inst_sparse ucode inst image size is 94720 [29744.415835] ieee80211 phy0: U iwl_verify_ucode Runtime uCode is good in inst SRAM Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 26 +---------------- drivers/net/wireless/iwlwifi/iwl-agn.c | 50 --------------------------------- drivers/net/wireless/iwlwifi/iwl-core.c | 39 ++++++------------------- drivers/net/wireless/iwlwifi/iwl-core.h | 2 -- drivers/net/wireless/iwlwifi/iwl-dev.h | 2 -- 5 files changed, 10 insertions(+), 109 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index f02023eea41..e427a8937ed 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -146,7 +146,7 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "Begin load bsm\n"); - priv->ucode_type = UCODE_INIT; + priv->ucode_type = UCODE_RT; /* make sure bootstrap program is no larger than BSM's SRAM size */ if (len > IWL49_MAX_BSM_SIZE) @@ -256,8 +256,6 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) */ static void iwl4965_init_alive_start(struct iwl_priv *priv) { - int ret; - /* Check alive response for "valid" sign from uCode */ if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { /* We had an error bringing up the hardware, so take it @@ -289,28 +287,6 @@ static void iwl4965_init_alive_start(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "Couldn't set up uCode pointers.\n"); goto restart; } - priv->ucode_type = UCODE_RT; - if (test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) { - IWL_WARN(priv, "Runtime uCode already alive? " - "Waiting for alive anyway\n"); - clear_bit(STATUS_RT_UCODE_ALIVE, &priv->status); - } - ret = wait_event_interruptible_timeout( - priv->wait_command_queue, - test_bit(STATUS_RT_UCODE_ALIVE, &priv->status), - UCODE_ALIVE_TIMEOUT); - if (!ret) { - /* FIXME: if STATUS_RT_UCODE_ALIVE timeout - * go back to restart the download Init uCode again - * this might cause to trap in the restart loop - */ - priv->ucode_type = UCODE_NONE; - if (!test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) { - IWL_ERR(priv, "Runtime timeout after %dms\n", - jiffies_to_msecs(UCODE_ALIVE_TIMEOUT)); - goto restart; - } - } return; restart: diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c9a1aacb243..319df4ab7f1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -533,16 +533,12 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv, if (palive->ver_subtype == INITIALIZE_SUBTYPE) { IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); - set_bit(STATUS_INIT_UCODE_ALIVE, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); memcpy(&priv->card_alive_init, &pkt->u.alive_frame, sizeof(struct iwl_init_alive_resp)); pwork = &priv->init_alive_start; } else { IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); - set_bit(STATUS_RT_UCODE_ALIVE, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); memcpy(&priv->card_alive, &pkt->u.alive_frame, sizeof(struct iwl_alive_resp)); pwork = &priv->alive_start; @@ -1784,7 +1780,6 @@ static int __iwl_up(struct iwl_priv *priv) { int i; int ret; - unsigned long status; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { IWL_WARN(priv, "Exit pending; will not bring the NIC up\n"); @@ -1862,51 +1857,6 @@ static int __iwl_up(struct iwl_priv *priv) /* start card; "initialize" will load runtime ucode */ iwl_nic_start(priv); - /* Just finish download Init or Runtime uCode image to device - * now we wait here for uCode send REPLY_ALIVE notification - * to indicate uCode is ready. - * 1) For Init uCode image, all iwlagn devices should wait here - * on STATUS_INIT_UCODE_ALIVE status bit; if timeout before - * receive the REPLY_ALIVE notification, go back and try to - * download the Init uCode image again. - * 2) For Runtime uCode image, all iwlagn devices except 4965 - * wait here on STATUS_RT_UCODE_ALIVE status bit; if - * timeout before receive the REPLY_ALIVE notification, go back - * and download the Runtime uCode image again. - * 3) For 4965 Runtime uCode, it will not go through this path, - * need to wait for STATUS_RT_UCODE_ALIVE status bit in - * iwl4965_init_alive_start() function; if timeout, need to - * restart and download Init uCode image. - */ - if (priv->ucode_type == UCODE_INIT) - status = STATUS_INIT_UCODE_ALIVE; - else - status = STATUS_RT_UCODE_ALIVE; - if (test_bit(status, &priv->status)) { - IWL_WARN(priv, - "%s uCode already alive? " - "Waiting for alive anyway\n", - (status == STATUS_INIT_UCODE_ALIVE) - ? "INIT" : "Runtime"); - clear_bit(status, &priv->status); - } - ret = wait_event_interruptible_timeout( - priv->wait_command_queue, - test_bit(status, &priv->status), - UCODE_ALIVE_TIMEOUT); - if (!ret) { - if (!test_bit(status, &priv->status)) { - priv->ucode_type = - (status == STATUS_INIT_UCODE_ALIVE) - ? UCODE_NONE : UCODE_INIT; - IWL_ERR(priv, - "%s timeout after %dms\n", - (status == STATUS_INIT_UCODE_ALIVE) - ? "INIT" : "Runtime", - jiffies_to_msecs(UCODE_ALIVE_TIMEOUT)); - continue; - } - } IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n"); return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 202bc3985a4..79170a9037a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1343,17 +1343,10 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv) u32 desc, time, count, base, data1; u32 blink1, blink2, ilink1, ilink2; - switch (priv->ucode_type) { - case UCODE_RT: - base = le32_to_cpu(priv->card_alive.error_event_table_ptr); - break; - case UCODE_INIT: + if (priv->ucode_type == UCODE_INIT) base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); - break; - default: - IWL_ERR(priv, "uCode image not available\n"); - return; - } + else + base = le32_to_cpu(priv->card_alive.error_event_table_ptr); if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base); @@ -1405,17 +1398,10 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, if (num_events == 0) return; - switch (priv->ucode_type) { - case UCODE_RT: - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - break; - case UCODE_INIT: + if (priv->ucode_type == UCODE_INIT) base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); - break; - default: - IWL_ERR(priv, "uCode image not available\n"); - return; - } + else + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); if (mode == 0) event_size = 2 * sizeof(u32); @@ -1452,17 +1438,10 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) u32 next_entry; /* index of next entry to be written by uCode */ u32 size; /* # entries that we'll print */ - switch (priv->ucode_type) { - case UCODE_RT: - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - break; - case UCODE_INIT: + if (priv->ucode_type == UCODE_INIT) base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); - break; - default: - IWL_ERR(priv, "uCode image not available\n"); - return; - } + else + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index fc096b929ee..ea8748dd675 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -547,8 +547,6 @@ void iwlcore_free_geos(struct iwl_priv *priv); #define STATUS_POWER_PMI 16 #define STATUS_FW_ERROR 17 #define STATUS_MODE_PENDING 18 -#define STATUS_INIT_UCODE_ALIVE 19 -#define STATUS_RT_UCODE_ALIVE 20 static inline int iwl_is_ready(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index dcf9d576323..61f952330a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -823,8 +823,6 @@ struct iwl_calib_result { size_t buf_len; }; -#define UCODE_ALIVE_TIMEOUT (5 * HZ) - enum ucode_type { UCODE_NONE = 0, UCODE_INIT, -- cgit v1.2.3-18-g5258 From a28027cd7f169edc399fe4b76d3a33b0203049a1 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 7 Aug 2009 15:41:45 -0700 Subject: iwlwifi: fix thermal throttling locking problem Move all the thermal throttling functions to background task to make sure do not change power and rx chain in interrupt handler. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 ++ drivers/net/wireless/iwlwifi/iwl-power.c | 57 +++++++++++++++++++++++++++++--- 2 files changed, 56 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 61f952330a8..35d07a81325 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1197,6 +1197,9 @@ struct iwl_priv { struct work_struct report_work; struct work_struct request_scan; struct work_struct beacon_update; + struct work_struct tt_work; + struct work_struct ct_enter; + struct work_struct ct_exit; struct tasklet_struct irq_tasklet; diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 594b5c2540b..9c05af77f9e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -481,6 +481,7 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) tt->tt_power_mode = IWL_POWER_INDEX_5; break; } + mutex_lock(&priv->mutex); if (iwl_power_update_mode(priv, true)) { /* TT state not updated * try again during next temperature read @@ -499,6 +500,7 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) IWL_DEBUG_POWER(priv, "Power Index change to %u\n", tt->tt_power_mode); } + mutex_unlock(&priv->mutex); } } @@ -609,6 +611,7 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) * in case get disabled before */ iwl_set_rxon_ht(priv, &priv->current_ht_config); } + mutex_lock(&priv->mutex); if (iwl_power_update_mode(priv, true)) { /* TT state not updated * try again during next temperature read @@ -631,6 +634,7 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) iwl_perform_ct_kill_task(priv, false); } } + mutex_unlock(&priv->mutex); } } @@ -644,13 +648,17 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) * for advance mode * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state */ -void iwl_tt_enter_ct_kill(struct iwl_priv *priv) +static void iwl_bg_ct_enter(struct work_struct *work) { + struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter); struct iwl_tt_mgmt *tt = &priv->power_data.tt; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; + if (!iwl_is_ready(priv)) + return; + if (tt->state != IWL_TI_CT_KILL) { IWL_ERR(priv, "Device reached critical temperature " "- ucode going to sleep!\n"); @@ -662,20 +670,23 @@ void iwl_tt_enter_ct_kill(struct iwl_priv *priv) CT_KILL_THRESHOLD + 1); } } -EXPORT_SYMBOL(iwl_tt_enter_ct_kill); /* Card State Notification indicated out of critical temperature * since Card State Notification will not provide any temperature reading * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state */ -void iwl_tt_exit_ct_kill(struct iwl_priv *priv) +static void iwl_bg_ct_exit(struct work_struct *work) { + struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit); struct iwl_tt_mgmt *tt = &priv->power_data.tt; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; + if (!iwl_is_ready(priv)) + return; + /* stop ct_kill_exit_tm timer */ del_timer_sync(&priv->power_data.ct_kill_exit_tm); @@ -690,10 +701,30 @@ void iwl_tt_exit_ct_kill(struct iwl_priv *priv) iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD); } } + +void iwl_tt_enter_ct_kill(struct iwl_priv *priv) +{ + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + IWL_DEBUG_POWER(priv, "Queueing critical temperature enter.\n"); + queue_work(priv->workqueue, &priv->ct_enter); +} +EXPORT_SYMBOL(iwl_tt_enter_ct_kill); + +void iwl_tt_exit_ct_kill(struct iwl_priv *priv) +{ + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + IWL_DEBUG_POWER(priv, "Queueing critical temperature exit.\n"); + queue_work(priv->workqueue, &priv->ct_exit); +} EXPORT_SYMBOL(iwl_tt_exit_ct_kill); -void iwl_tt_handler(struct iwl_priv *priv) +static void iwl_bg_tt_work(struct work_struct *work) { + struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work); s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */ if (test_bit(STATUS_EXIT_PENDING, &priv->status)) @@ -707,6 +738,15 @@ void iwl_tt_handler(struct iwl_priv *priv) else iwl_advance_tt_handler(priv, temp); } + +void iwl_tt_handler(struct iwl_priv *priv) +{ + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + IWL_DEBUG_POWER(priv, "Queueing thermal throttling work.\n"); + queue_work(priv->workqueue, &priv->tt_work); +} EXPORT_SYMBOL(iwl_tt_handler); /* Thermal throttling initialization @@ -731,6 +771,12 @@ void iwl_tt_initialize(struct iwl_priv *priv) init_timer(&priv->power_data.ct_kill_exit_tm); priv->power_data.ct_kill_exit_tm.data = (unsigned long)priv; priv->power_data.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; + + /* setup deferred ct kill work */ + INIT_WORK(&priv->tt_work, iwl_bg_tt_work); + INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter); + INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit); + switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_6x00: case CSR_HW_REV_TYPE_6x50: @@ -782,6 +828,9 @@ void iwl_tt_exit(struct iwl_priv *priv) /* stop ct_kill_exit_tm timer if activated */ del_timer_sync(&priv->power_data.ct_kill_exit_tm); + cancel_work_sync(&priv->tt_work); + cancel_work_sync(&priv->ct_enter); + cancel_work_sync(&priv->ct_exit); if (priv->power_data.adv_tt) { /* free advance thermal throttling memory */ -- cgit v1.2.3-18-g5258 From ee9f29894fc3819c1bd639fc3a886326bb809266 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 7 Aug 2009 15:41:46 -0700 Subject: iwlwifi: fix legacy thermal throttling power index For legacy thermal throttling, set the new Thermal Throttling state and change power index when thermal throttling manager detects temperature changed. The current implementation sets the state to the previous Thermal Throttling state, which causes system to enter wrong power index. The worse case, it will trying to set the lower power index when device reach critical temperature, it will cuase issue for both system and the device. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-power.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 9c05af77f9e..bd97a0da1cd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -425,7 +425,7 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv, static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) { struct iwl_tt_mgmt *tt = &priv->power_data.tt; - enum iwl_tt_state new_state; + enum iwl_tt_state old_state; struct iwl_power_mgr *setting = &priv->power_data; #ifdef CONFIG_IWLWIFI_DEBUG @@ -438,26 +438,27 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) (temp - tt->tt_previous_temp)); } #endif + old_state = tt->state; /* in Celsius */ if (temp >= IWL_MINIMAL_POWER_THRESHOLD) - new_state = IWL_TI_CT_KILL; + tt->state = IWL_TI_CT_KILL; else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2) - new_state = IWL_TI_2; + tt->state = IWL_TI_2; else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1) - new_state = IWL_TI_1; + tt->state = IWL_TI_1; else - new_state = IWL_TI_0; + tt->state = IWL_TI_0; #ifdef CONFIG_IWLWIFI_DEBUG tt->tt_previous_temp = temp; #endif - if (tt->state != new_state) { - if (tt->state == IWL_TI_0) { + if (tt->state != old_state) { + if (old_state == IWL_TI_0) { tt->sys_power_mode = setting->power_mode; IWL_DEBUG_POWER(priv, "current power mode: %u\n", setting->power_mode); } - switch (new_state) { + switch (tt->state) { case IWL_TI_0: /* when system ready to go back to IWL_TI_0 state * using system power mode instead of TT power mode @@ -486,15 +487,15 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) /* TT state not updated * try again during next temperature read */ + tt->state = old_state; IWL_ERR(priv, "Cannot update power mode, " "TT state not updated\n"); } else { - if (new_state == IWL_TI_CT_KILL) + if (tt->state == IWL_TI_CT_KILL) iwl_perform_ct_kill_task(priv, true); - else if (tt->state == IWL_TI_CT_KILL && - new_state != IWL_TI_CT_KILL) + else if (old_state == IWL_TI_CT_KILL && + tt->state != IWL_TI_CT_KILL) iwl_perform_ct_kill_task(priv, false); - tt->state = new_state; IWL_DEBUG_POWER(priv, "Temperature state changed %u\n", tt->state); IWL_DEBUG_POWER(priv, "Power Index change to %u\n", -- cgit v1.2.3-18-g5258 From 3a780d25428a0a391a8ba6c888cf4e89ac3fdbb1 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 7 Aug 2009 15:41:47 -0700 Subject: iwlwifi: handle the case when set power fail Modify the power update function, when driver fail to set the power, it should not continue move forward and try to change the rx chain configuration. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-power.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index bd97a0da1cd..9e8916d15ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -282,18 +282,21 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) cmd.flags |= IWL_POWER_FAST_PD; ret = iwl_set_power(priv, &cmd); - - if (final_mode == IWL_POWER_MODE_CAM) - clear_bit(STATUS_POWER_PMI, &priv->status); - - if (priv->cfg->ops->lib->update_chain_flags && update_chains) - priv->cfg->ops->lib->update_chain_flags(priv); - else - IWL_DEBUG_POWER(priv, "Cannot update the power, chain noise " + if (!ret) { + if (final_mode == IWL_POWER_MODE_CAM) + clear_bit(STATUS_POWER_PMI, &priv->status); + + if (priv->cfg->ops->lib->update_chain_flags && + update_chains) + priv->cfg->ops->lib->update_chain_flags(priv); + else + IWL_DEBUG_POWER(priv, + "Cannot update the power, chain noise " "calibration running: %d\n", priv->chain_noise_data.state); - if (!ret) setting->power_mode = final_mode; + } else + IWL_ERR(priv, "set power fail, ret = %d", ret); } return ret; -- cgit v1.2.3-18-g5258 From 3ad3b92a5517c043ef30e4b95c4c39a35bbc36be Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 7 Aug 2009 15:41:48 -0700 Subject: iwlwifi: refactor some thermal throttle code Some of the thermal throttle data structures and code are really very intermingled with the sleep (power) control code. They really do belong together in a way since the thermal throttle code uses powersaving to achieve its goal, but it's making it hard to work on the powersave code. Split this up to make that easier. I've also changed the antenna defines to an enum and used the same enum for RX and TX. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 14 +++--- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 7 ++- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 + drivers/net/wireless/iwlwifi/iwl-power.c | 78 +++++++++++++++--------------- drivers/net/wireless/iwlwifi/iwl-power.h | 50 +++++++++---------- 6 files changed, 76 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 0c3ed23ed77..21331552ff2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1401,7 +1401,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, if (!iwl_ht_enabled(priv)) /* stay in Legacy */ tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; - else if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE && + else if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE && tbl->action > IWL_LEGACY_SWITCH_SISO) tbl->action = IWL_LEGACY_SWITCH_SISO; for (; ;) { @@ -1535,7 +1535,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, u8 update_search_tbl_counter = 0; int ret; - if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE && + if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE && tbl->action > IWL_SISO_SWITCH_ANTENNA2) { /* stay in SISO */ tbl->action = IWL_SISO_SWITCH_ANTENNA1; @@ -1674,7 +1674,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, u8 update_search_tbl_counter = 0; int ret; - if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) && + if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) && (tbl->action < IWL_MIMO2_SWITCH_SISO_A || tbl->action > IWL_MIMO2_SWITCH_SISO_C)) { /* switch in SISO */ @@ -1816,7 +1816,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, int ret; u8 update_search_tbl_counter = 0; - if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) && + if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) && (tbl->action < IWL_MIMO3_SWITCH_SISO_A || tbl->action > IWL_MIMO3_SWITCH_SISO_C)) { /* switch in SISO */ @@ -2202,7 +2202,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, /* If we are searching for better modulation mode, check success. */ if (lq_sta->search_better_tbl && - (iwl_tx_ant_restriction(priv) == IWL_TX_MULTI)) { + (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI)) { /* If good success, continue using the "search" mode; * no need to send new link quality command, since we're * continuing to use the setup that we've been trying. */ @@ -2332,7 +2332,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, scale_action = 0; if (!iwl_ht_enabled(priv) && !is_legacy(tbl->lq_type)) scale_action = -1; - if (iwl_tx_ant_restriction(priv) != IWL_TX_MULTI && + if (iwl_tx_ant_restriction(priv) != IWL_ANT_OK_MULTI && (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) scale_action = -1; switch (scale_action) { @@ -2368,7 +2368,7 @@ lq_update: rate = rs_update_rate_tbl(priv, lq_sta, tbl, index, is_green); - if (iwl_tx_ant_restriction(priv) == IWL_TX_MULTI) { + if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI) { /* Should we stay with this modulation mode, * or search for a new one? */ rs_stay_in_table(lq_sta); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 79170a9037a..22961e906cb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2214,7 +2214,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); spin_unlock_irqrestore(&priv->lock, flags); - priv->power_data.ct_kill_toggle = false; + priv->thermal_throttle.ct_kill_toggle = false; switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_1000: diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 1ad4ff6bfff..7b578d41101 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -704,7 +704,7 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file, size_t count, loff_t *ppos) { struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; struct iwl_tt_restriction *restriction; char buf[100]; int pos = 0; @@ -713,12 +713,11 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file, pos += scnprintf(buf + pos, bufsz - pos, "Thermal Throttling Mode: %s\n", - (priv->power_data.adv_tt) - ? "Advance" : "Legacy"); + tt->advanced_tt ? "Advance" : "Legacy"); pos += scnprintf(buf + pos, bufsz - pos, "Thermal Throttling State: %d\n", tt->state); - if (priv->power_data.adv_tt) { + if (tt->advanced_tt) { restriction = tt->restriction + tt->state; pos += scnprintf(buf + pos, bufsz - pos, "Tx mode: %d\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 35d07a81325..1aa2ae6d075 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1111,6 +1111,7 @@ struct iwl_priv { struct isr_statistics isr_stats; struct iwl_power_mgr power_data; + struct iwl_tt_mgmt thermal_throttle; struct iwl_notif_statistics statistics; unsigned long last_statistics_time; diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 9e8916d15ec..27ad59d8643 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -132,10 +132,10 @@ static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = { /* Advance Thermal Throttling default restriction table */ static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = { - {IWL_TX_MULTI, true, IWL_RX_MULTI}, - {IWL_TX_SINGLE, true, IWL_RX_MULTI}, - {IWL_TX_SINGLE, false, IWL_RX_SINGLE}, - {IWL_TX_NONE, false, IWL_RX_NONE} + {IWL_ANT_OK_MULTI, IWL_ANT_OK_MULTI, true }, + {IWL_ANT_OK_SINGLE, IWL_ANT_OK_MULTI, true }, + {IWL_ANT_OK_SINGLE, IWL_ANT_OK_SINGLE, false }, + {IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false } }; /* set card power command */ @@ -251,7 +251,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) { struct iwl_power_mgr *setting = &(priv->power_data); int ret = 0; - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; u16 uninitialized_var(final_mode); bool update_chains; @@ -317,35 +317,35 @@ EXPORT_SYMBOL(iwl_power_set_user_mode); bool iwl_ht_enabled(struct iwl_priv *priv) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; struct iwl_tt_restriction *restriction; - if (!priv->power_data.adv_tt) + if (!priv->thermal_throttle.advanced_tt) return true; restriction = tt->restriction + tt->state; return restriction->is_ht; } EXPORT_SYMBOL(iwl_ht_enabled); -u8 iwl_tx_ant_restriction(struct iwl_priv *priv) +enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; struct iwl_tt_restriction *restriction; - if (!priv->power_data.adv_tt) - return IWL_TX_MULTI; + if (!priv->thermal_throttle.advanced_tt) + return IWL_ANT_OK_MULTI; restriction = tt->restriction + tt->state; return restriction->tx_stream; } EXPORT_SYMBOL(iwl_tx_ant_restriction); -u8 iwl_rx_ant_restriction(struct iwl_priv *priv) +enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; struct iwl_tt_restriction *restriction; - if (!priv->power_data.adv_tt) - return IWL_RX_MULTI; + if (!priv->thermal_throttle.advanced_tt) + return IWL_ANT_OK_MULTI; restriction = tt->restriction + tt->state; return restriction->rx_stream; } @@ -364,21 +364,21 @@ EXPORT_SYMBOL(iwl_rx_ant_restriction); static void iwl_tt_check_exit_ct_kill(unsigned long data) { struct iwl_priv *priv = (struct iwl_priv *)data; - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; unsigned long flags; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; if (tt->state == IWL_TI_CT_KILL) { - if (priv->power_data.ct_kill_toggle) { + if (priv->thermal_throttle.ct_kill_toggle) { iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); - priv->power_data.ct_kill_toggle = false; + priv->thermal_throttle.ct_kill_toggle = false; } else { iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); - priv->power_data.ct_kill_toggle = true; + priv->thermal_throttle.ct_kill_toggle = true; } iwl_read32(priv, CSR_UCODE_DRV_GP1); spin_lock_irqsave(&priv->reg_lock, flags); @@ -389,7 +389,7 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data) /* Reschedule the ct_kill timer to occur in * CT_KILL_EXIT_DURATION seconds to ensure we get a * thermal update */ - mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies + + mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies + CT_KILL_EXIT_DURATION * HZ); } } @@ -403,7 +403,7 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv, ieee80211_stop_queues(priv->hw); IWL_DEBUG_POWER(priv, "Schedule 5 seconds CT_KILL Timer\n"); - mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies + + mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies + CT_KILL_EXIT_DURATION * HZ); } else { IWL_DEBUG_POWER(priv, "Wake all queues\n"); @@ -427,7 +427,7 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv, */ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; enum iwl_tt_state old_state; struct iwl_power_mgr *setting = &priv->power_data; @@ -531,7 +531,7 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) */ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; int i; bool changed = false; enum iwl_tt_state old_state; @@ -655,7 +655,7 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) static void iwl_bg_ct_enter(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter); - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -666,7 +666,7 @@ static void iwl_bg_ct_enter(struct work_struct *work) if (tt->state != IWL_TI_CT_KILL) { IWL_ERR(priv, "Device reached critical temperature " "- ucode going to sleep!\n"); - if (!priv->power_data.adv_tt) + if (!priv->thermal_throttle.advanced_tt) iwl_legacy_tt_handler(priv, IWL_MINIMAL_POWER_THRESHOLD); else @@ -683,7 +683,7 @@ static void iwl_bg_ct_enter(struct work_struct *work) static void iwl_bg_ct_exit(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit); - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -692,13 +692,13 @@ static void iwl_bg_ct_exit(struct work_struct *work) return; /* stop ct_kill_exit_tm timer */ - del_timer_sync(&priv->power_data.ct_kill_exit_tm); + del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm); if (tt->state == IWL_TI_CT_KILL) { IWL_ERR(priv, "Device temperature below critical" "- ucode awake!\n"); - if (!priv->power_data.adv_tt) + if (!priv->thermal_throttle.advanced_tt) iwl_legacy_tt_handler(priv, IWL_REDUCED_PERFORMANCE_THRESHOLD_2); else @@ -737,7 +737,7 @@ static void iwl_bg_tt_work(struct work_struct *work) if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) temp = KELVIN_TO_CELSIUS(priv->temperature); - if (!priv->power_data.adv_tt) + if (!priv->thermal_throttle.advanced_tt) iwl_legacy_tt_handler(priv, temp); else iwl_advance_tt_handler(priv, temp); @@ -760,7 +760,7 @@ EXPORT_SYMBOL(iwl_tt_handler); */ void iwl_tt_initialize(struct iwl_priv *priv) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; struct iwl_power_mgr *setting = &priv->power_data; int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1); struct iwl_tt_trans *transaction; @@ -772,9 +772,9 @@ void iwl_tt_initialize(struct iwl_priv *priv) tt->state = IWL_TI_0; tt->sys_power_mode = setting->power_mode; tt->tt_power_mode = tt->sys_power_mode; - init_timer(&priv->power_data.ct_kill_exit_tm); - priv->power_data.ct_kill_exit_tm.data = (unsigned long)priv; - priv->power_data.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; + init_timer(&priv->thermal_throttle.ct_kill_exit_tm); + priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv; + priv->thermal_throttle.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; /* setup deferred ct kill work */ INIT_WORK(&priv->tt_work, iwl_bg_tt_work); @@ -792,7 +792,7 @@ void iwl_tt_initialize(struct iwl_priv *priv) GFP_KERNEL); if (!tt->restriction || !tt->transaction) { IWL_ERR(priv, "Fallback to Legacy Throttling\n"); - priv->power_data.adv_tt = false; + priv->thermal_throttle.advanced_tt = false; kfree(tt->restriction); tt->restriction = NULL; kfree(tt->transaction); @@ -814,12 +814,12 @@ void iwl_tt_initialize(struct iwl_priv *priv) IWL_TI_STATE_MAX; memcpy(tt->restriction, &restriction_range[0], size); - priv->power_data.adv_tt = true; + priv->thermal_throttle.advanced_tt = true; } break; default: IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n"); - priv->power_data.adv_tt = false; + priv->thermal_throttle.advanced_tt = false; break; } } @@ -828,15 +828,15 @@ EXPORT_SYMBOL(iwl_tt_initialize); /* cleanup thermal throttling management related memory and timer */ void iwl_tt_exit(struct iwl_priv *priv) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; /* stop ct_kill_exit_tm timer if activated */ - del_timer_sync(&priv->power_data.ct_kill_exit_tm); + del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm); cancel_work_sync(&priv->tt_work); cancel_work_sync(&priv->ct_enter); cancel_work_sync(&priv->ct_exit); - if (priv->power_data.adv_tt) { + if (priv->thermal_throttle.advanced_tt) { /* free advance thermal throttling memory */ kfree(tt->restriction); tt->restriction = NULL; diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 3d49b7a45b7..15e3eabd2e8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -37,13 +37,11 @@ struct iwl_priv; #define IWL_ABSOLUTE_MAX 0xFFFFFFFF #define IWL_TT_INCREASE_MARGIN 5 -/* Tx/Rx restrictions */ -#define IWL_TX_MULTI 0x02 -#define IWL_TX_SINGLE 0x01 -#define IWL_TX_NONE 0x00 -#define IWL_RX_MULTI 0x02 -#define IWL_RX_SINGLE 0x01 -#define IWL_RX_NONE 0x00 +enum iwl_antenna_ok { + IWL_ANT_OK_NONE, + IWL_ANT_OK_SINGLE, + IWL_ANT_OK_MULTI, +}; /* Thermal Throttling State Machine states */ enum iwl_tt_state { @@ -55,27 +53,30 @@ enum iwl_tt_state { }; /** - * struct iwl_tt_restriction - Thermal Throttling restriction table used - * by advance thermal throttling management - * based on the current thermal throttling state, determine - * number of tx/rx streams; and the status of HT operation + * struct iwl_tt_restriction - Thermal Throttling restriction table * @tx_stream: number of tx stream allowed * @is_ht: ht enable/disable * @rx_stream: number of rx stream allowed + * + * This table is used by advance thermal throttling management + * based on the current thermal throttling state, and determines + * the number of tx/rx streams and the status of HT operation. */ struct iwl_tt_restriction { - u8 tx_stream; + enum iwl_antenna_ok tx_stream; + enum iwl_antenna_ok rx_stream; bool is_ht; - u8 rx_stream; }; /** - * struct iwl_tt_trans - Thermal Throttling transaction table; used by - * advance thermal throttling algorithm to determine next - * thermal state to go based on the current temperature + * struct iwl_tt_trans - Thermal Throttling transaction table * @next_state: next thermal throttling mode * @tt_low: low temperature threshold to change state * @tt_high: high temperature threshold to change state + * + * This is used by the advanced thermal throttling algorithm + * to determine the next thermal state to go based on the + * current temperature. */ struct iwl_tt_trans { enum iwl_tt_state next_state; @@ -85,6 +86,7 @@ struct iwl_tt_trans { /** * struct iwl_tt_mgnt - Thermal Throttling Management structure + * @advanced_tt: advanced thermal throttle required * @state: current Thermal Throttling state * @tt_power_mode: Thermal Throttling power mode index * being used to set power level when @@ -99,16 +101,21 @@ struct iwl_tt_trans { * should be used in tt state; and can HT be enabled or not * @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling * state transaction + * @ct_kill_toggle: used to toggle the CSR bit when checking uCode temperature + * @ct_kill_exit_tm: timer to exit thermal kill */ struct iwl_tt_mgmt { enum iwl_tt_state state; + bool advanced_tt; u8 tt_power_mode; u8 sys_power_mode; + bool ct_kill_toggle; #ifdef CONFIG_IWLWIFI_DEBUG s32 tt_previous_temp; #endif struct iwl_tt_restriction *restriction; struct iwl_tt_trans *transaction; + struct timer_list ct_kill_exit_tm; }; enum { @@ -137,20 +144,13 @@ struct iwl_power_mgr { u8 power_mode; u8 user_power_setting; /* set by user through sysfs */ u8 power_disabled; /* set by mac80211's CONF_PS */ - struct iwl_tt_mgmt tt; /* Thermal Throttling Management */ - bool adv_tt; /* false: legacy mode */ - /* true: advance mode */ - bool ct_kill_toggle; /* use to toggle the CSR bit when - * checking uCode temperature - */ - struct timer_list ct_kill_exit_tm; }; int iwl_power_update_mode(struct iwl_priv *priv, bool force); int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); bool iwl_ht_enabled(struct iwl_priv *priv); -u8 iwl_tx_ant_restriction(struct iwl_priv *priv); -u8 iwl_rx_ant_restriction(struct iwl_priv *priv); +enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv); +enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv); void iwl_tt_enter_ct_kill(struct iwl_priv *priv); void iwl_tt_exit_ct_kill(struct iwl_priv *priv); void iwl_tt_handler(struct iwl_priv *priv); -- cgit v1.2.3-18-g5258 From 450ccb36b4d8a18c34643335d3305ec1a781e717 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 7 Aug 2009 15:41:49 -0700 Subject: iwlwifi: fix missing EXPORT_SYMBOL When compiling without CONFIG_IWLWIFI_DEBUGFS there is a missing iwl_update_stats symbol. This is fixed by making this function an inline in the case when CONFIG_IWLWIFI_DEBUGFS is not set due to the hot path in which it is used. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 16 ---------------- drivers/net/wireless/iwlwifi/iwl-core.h | 19 +++++++++++++++++-- 2 files changed, 17 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 22961e906cb..44d01a2f294 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -3172,22 +3172,6 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) } } EXPORT_SYMBOL(iwl_update_stats); - -#else -void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) -{ - struct traffic_stats *stats; - - if (is_tx) - stats = &priv->tx_stats; - else - stats = &priv->rx_stats; - - if (ieee80211_is_data(fc)) { - /* data */ - stats->data_bytes += len; - } -} #endif #ifdef CONFIG_PM diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index ea8748dd675..32750f4f1ce 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -314,6 +314,8 @@ const char *get_mgmt_string(int cmd); const char *get_ctrl_string(int cmd); void iwl_clear_tx_stats(struct iwl_priv *priv); void iwl_clear_rx_stats(struct iwl_priv *priv); +void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, + u16 len); #else static inline int iwl_alloc_traffic_mem(struct iwl_priv *priv) { @@ -333,9 +335,22 @@ static inline void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, u16 length, struct ieee80211_hdr *header) { } +static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx, + __le16 fc, u16 len) +{ + struct traffic_stats *stats; + + if (is_tx) + stats = &priv->tx_stats; + else + stats = &priv->rx_stats; + + if (ieee80211_is_data(fc)) { + /* data */ + stats->data_bytes += len; + } +} #endif -void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, - u16 len); /***************************************************** * RX handlers. * **************************************************/ -- cgit v1.2.3-18-g5258 From d91b1ba37744bc7fb7524516be855c9fa81142e2 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 7 Aug 2009 15:41:50 -0700 Subject: iwlwifi: display correct critical temperature infomation Do not send CT KILL config command twice and correct critical temperature informatiom in dmesg Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 44d01a2f294..36c6e16285d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2227,6 +2227,15 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, sizeof(adv_cmd), &adv_cmd); + if (ret) + IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n"); + else + IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD " + "succeeded, " + "critical temperature enter is %d," + "exit is %d\n", + priv->hw_params.ct_kill_threshold, + priv->hw_params.ct_kill_exit_threshold); break; default: cmd.critical_temperature_R = @@ -2234,16 +2243,15 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, sizeof(cmd), &cmd); + if (ret) + IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n"); + else + IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD " + "succeeded, " + "critical temperature is %d\n", + priv->hw_params.ct_kill_threshold); break; } - ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, - sizeof(cmd), &cmd); - if (ret) - IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n"); - else - IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD succeeded, " - "critical temperature is %d\n", - cmd.critical_temperature_R); } EXPORT_SYMBOL(iwl_rf_kill_ct_config); -- cgit v1.2.3-18-g5258 From e312c24cf8229f9b6e76dbfd5d99eefe21f4ac0a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 7 Aug 2009 15:41:51 -0700 Subject: iwlwifi: automatically adjust sleep level Depending on required latency requested by pm_qos (via mac80211) we can automatically adjust the sleep state. Also, mac80211 has a user-visible dynamic sleep feature where we are supposed to stay awake after sending/receiving frames to better receive response frames to our packets, this can be integrated into the sleep command. Currently, and this patch doesn't change that yet, we default to using sleep level 1 if PS is enabled. With a module parameter to iwlcore, automatic adjustment to changing network latency requirements can be enabled -- this isn't yet the default due to requiring more testing. The goal is to enable automatic adjustment and then go into the deepest possible sleep state possible depending on the networking latency requirements. This patch does, however, enable IEEE80211_HW_SUPPORTS_DYNAMIC_PS to avoid the double-timer (one in software and one in the device) when transmitting -- the exact timeout may be ignored but that is not of big concern. Note also that we keep the hard-coded power indices around for thermal throttling -- the specification of that calls for using the specified power levels. Those can also be selected in debugfs to allow easier testing of such parameters. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 46 +--- drivers/net/wireless/iwlwifi/iwl-calib.c | 2 +- drivers/net/wireless/iwlwifi/iwl-commands.h | 7 + drivers/net/wireless/iwlwifi/iwl-core.c | 15 +- drivers/net/wireless/iwlwifi/iwl-debug.h | 2 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 83 ++++++++ drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - drivers/net/wireless/iwlwifi/iwl-power.c | 317 +++++++++++++--------------- drivers/net/wireless/iwlwifi/iwl-power.h | 30 +-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 66 +----- 10 files changed, 256 insertions(+), 313 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 319df4ab7f1..2232b1794e7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1606,7 +1606,7 @@ static void iwl_alive_start(struct iwl_priv *priv) set_bit(STATUS_READY, &priv->status); wake_up_interruptible(&priv->wait_command_queue); - iwl_power_update_mode(priv, 1); + iwl_power_update_mode(priv, true); /* reassociate for ADHOC mode */ if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) { @@ -2075,7 +2075,7 @@ void iwl_post_associate(struct iwl_priv *priv) * If chain noise has already been run, then we need to enable * power management here */ if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE) - iwl_power_update_mode(priv, 0); + iwl_power_update_mode(priv, false); /* Enable Rx differential gain and sensitivity calibrations */ iwl_chain_noise_reset(priv); @@ -2565,47 +2565,6 @@ static ssize_t store_filter_flags(struct device *d, static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, store_filter_flags); -static ssize_t store_power_level(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - int ret; - unsigned long mode; - - - mutex_lock(&priv->mutex); - - ret = strict_strtoul(buf, 10, &mode); - if (ret) - goto out; - - ret = iwl_power_set_user_mode(priv, mode); - if (ret) { - IWL_DEBUG_MAC80211(priv, "failed setting power mode.\n"); - goto out; - } - ret = count; - - out: - mutex_unlock(&priv->mutex); - return ret; -} - -static ssize_t show_power_level(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - int level = priv->power_data.power_mode; - char *p = buf; - - p += sprintf(p, "%d\n", level); - return p - buf + 1; -} - -static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, - store_power_level); - static ssize_t show_statistics(struct device *d, struct device_attribute *attr, char *buf) @@ -2698,7 +2657,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) static struct attribute *iwl_sysfs_entries[] = { &dev_attr_flags.attr, &dev_attr_filter_flags.attr, - &dev_attr_power_level.attr, &dev_attr_statistics.attr, &dev_attr_temperature.attr, &dev_attr_tx_power.attr, diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 13180d6ee2f..c4b565a2de9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -852,7 +852,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, priv->cfg->ops->lib->update_chain_flags(priv); data->state = IWL_CHAIN_NOISE_DONE; - iwl_power_update_mode(priv, 0); + iwl_power_update_mode(priv, false); } EXPORT_SYMBOL(iwl_chain_noise_calibration); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 6188c54113b..68d7719071f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2313,15 +2313,22 @@ struct iwl_spectrum_notification { * PM allow: * bit 0 - '0' Driver not allow power management * '1' Driver allow PM (use rest of parameters) + * * uCode send sleep notifications: * bit 1 - '0' Don't send sleep notification * '1' send sleep notification (SEND_PM_NOTIFICATION) + * * Sleep over DTIM * bit 2 - '0' PM have to walk up every DTIM * '1' PM could sleep over DTIM till listen Interval. + * * PCI power managed * bit 3 - '0' (PCI_CFG_LINK_CTRL & 0x1) * '1' !(PCI_CFG_LINK_CTRL & 0x1) + * + * Fast PD + * bit 4 - '1' Put radio to sleep when receiving frame for others + * * Force sleep Modes * bit 31/30- '00' use both mac/xtal sleeps * '01' force Mac sleep diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 36c6e16285d..af735128333 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1568,7 +1568,8 @@ int iwl_setup_mac(struct iwl_priv *priv) IEEE80211_HW_NOISE_DBM | IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_SPECTRUM_MGMT | - IEEE80211_HW_SUPPORTS_PS; + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_SUPPORTS_DYNAMIC_PS; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); @@ -1663,8 +1664,6 @@ int iwl_init_drv(struct iwl_priv *priv) priv->qos_data.qos_cap.val = 0; priv->rates_mask = IWL_RATES_MASK; - /* If power management is turned on, default to CAM mode */ - priv->power_mode = IWL_POWER_MODE_CAM; priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MAX; ret = iwl_init_channel_map(priv); @@ -2551,7 +2550,6 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, if (bss_conf->assoc) { priv->assoc_id = bss_conf->aid; priv->beacon_int = bss_conf->beacon_int; - priv->power_data.dtim_period = bss_conf->dtim_period; priv->timestamp = bss_conf->timestamp; priv->assoc_capability = bss_conf->assoc_capability; @@ -2801,13 +2799,10 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) iwl_set_rate(priv); } - if (changed & IEEE80211_CONF_CHANGE_PS && - priv->iw_mode == NL80211_IFTYPE_STATION) { - priv->power_data.power_disabled = - !(conf->flags & IEEE80211_CONF_PS); - ret = iwl_power_update_mode(priv, 0); + if (changed & IEEE80211_CONF_CHANGE_PS) { + ret = iwl_power_update_mode(priv, false); if (ret) - IWL_DEBUG_MAC80211(priv, "Error setting power level\n"); + IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n"); } if (changed & IEEE80211_CONF_CHANGE_POWER) { diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 82befb7ce99..723f38a023c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -88,6 +88,8 @@ struct iwl_debugfs { struct dentry *file_led; #endif struct dentry *file_disable_ht40; + struct dentry *file_sleep_level_override; + struct dentry *file_current_sleep_command; } dbgfs_data_files; struct dir_rf_files { struct dentry *file_disable_sensitivity; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 7b578d41101..f68fb4711da 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -776,6 +776,83 @@ static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file, return ret; } +static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[8]; + int buf_size; + int value; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + + if (sscanf(buf, "%d", &value) != 1) + return -EINVAL; + + /* + * Our users expect 0 to be "CAM", but 0 isn't actually + * valid here. However, let's not confuse them and present + * IWL_POWER_INDEX_1 as "1", not "0". + */ + if (value > 0) + value -= 1; + + if (value != -1 && (value < 0 || value >= IWL_POWER_NUM)) + return -EINVAL; + + priv->power_data.debug_sleep_level_override = value; + + iwl_power_update_mode(priv, false); + + return count; +} + +static ssize_t iwl_dbgfs_sleep_level_override_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + char buf[10]; + int pos, value; + const size_t bufsz = sizeof(buf); + + /* see the write function */ + value = priv->power_data.debug_sleep_level_override; + if (value >= 0) + value += 1; + + pos = scnprintf(buf, bufsz, "%d\n", value); + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + char buf[200]; + int pos = 0, i; + const size_t bufsz = sizeof(buf); + struct iwl_powertable_cmd *cmd = &priv->power_data.sleep_cmd; + + pos += scnprintf(buf + pos, bufsz - pos, + "flags: %#.2x\n", le16_to_cpu(cmd->flags)); + pos += scnprintf(buf + pos, bufsz - pos, + "RX/TX timeout: %d/%d usec\n", + le32_to_cpu(cmd->rx_data_timeout), + le32_to_cpu(cmd->tx_data_timeout)); + for (i = 0; i < IWL_POWER_VEC_SIZE; i++) + pos += scnprintf(buf + pos, bufsz - pos, + "sleep_interval[%d]: %d\n", i, + le32_to_cpu(cmd->sleep_interval[i])); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_WRITE_FILE_OPS(log_event); DEBUGFS_READ_FILE_OPS(nvm); @@ -789,6 +866,8 @@ DEBUGFS_READ_FILE_OPS(led); #endif DEBUGFS_READ_FILE_OPS(thermal_throttling); DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40); +DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override); +DEBUGFS_READ_FILE_OPS(current_sleep_command); static ssize_t iwl_dbgfs_traffic_log_read(struct file *file, char __user *user_buf, @@ -1533,6 +1612,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) #ifdef CONFIG_IWLWIFI_LEDS DEBUGFS_ADD_FILE(led, data); #endif + DEBUGFS_ADD_FILE(sleep_level_override, data); + DEBUGFS_ADD_FILE(current_sleep_command, data); DEBUGFS_ADD_FILE(thermal_throttling, data); DEBUGFS_ADD_FILE(disable_ht40, data); DEBUGFS_ADD_FILE(rx_statistics, debug); @@ -1572,6 +1653,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) if (!priv->dbgfs) return; + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sleep_level_override); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_current_sleep_command); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_nvm); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1aa2ae6d075..b96c3c9e92a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1119,7 +1119,6 @@ struct iwl_priv { /* context information */ u16 rates_mask; - u32 power_mode; u8 bssid[ETH_ALEN]; u16 rts_threshold; u8 mac_addr[ETH_ALEN]; diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 27ad59d8643..0b16841f45f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -42,20 +42,35 @@ #include "iwl-power.h" /* - * Setting power level allow the card to go to sleep when not busy. + * Setting power level allows the card to go to sleep when not busy. * - * The power level is set to INDEX_1 (the least deep state) by - * default, and will, in the future, be the deepest state unless - * otherwise required by pm_qos network latency requirements. - * - * Using INDEX_1 without pm_qos is ok because mac80211 will disable - * PS when even checking every beacon for the TIM bit would exceed - * the required latency. + * We calculate a sleep command based on the required latency, which + * we get from mac80211. In order to handle thermal throttling, we can + * also use pre-defined power levels. */ -#define IWL_POWER_RANGE_0_MAX (2) -#define IWL_POWER_RANGE_1_MAX (10) +/* + * For now, keep using power level 1 instead of automatically + * adjusting ... + */ +bool no_sleep_autoadjust = true; +module_param(no_sleep_autoadjust, bool, S_IRUGO); +MODULE_PARM_DESC(no_sleep_autoadjust, + "don't automatically adjust sleep level " + "according to maximum network latency"); +/* + * This defines the old power levels. They are still used by default + * (level 1) and for thermal throttle (levels 3 through 5) + */ + +struct iwl_power_vec_entry { + struct iwl_powertable_cmd cmd; + u8 no_dtim; +}; + +#define IWL_DTIM_RANGE_0_MAX 2 +#define IWL_DTIM_RANGE_1_MAX 10 #define NOSLP cpu_to_le16(0), 0, 0 #define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 @@ -67,9 +82,8 @@ cpu_to_le32(X3), \ cpu_to_le32(X4)} /* default power management (not Tx power) table values */ -/* for DTIM period 0 through IWL_POWER_RANGE_0_MAX */ +/* for DTIM period 0 through IWL_DTIM_RANGE_0_MAX */ static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { - {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0}, @@ -78,9 +92,8 @@ static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { }; -/* for DTIM period IWL_POWER_RANGE_0_MAX + 1 through IWL_POWER_RANGE_1_MAX */ +/* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */ static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { - {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0}, {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0}, @@ -88,9 +101,8 @@ static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2} }; -/* for DTIM period > IWL_POWER_RANGE_1_MAX */ +/* for DTIM period > IWL_DTIM_RANGE_1_MAX */ static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { - {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, @@ -98,6 +110,56 @@ static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} }; +static void iwl_static_sleep_cmd(struct iwl_priv *priv, + struct iwl_powertable_cmd *cmd, + enum iwl_power_level lvl, int period) +{ + const struct iwl_power_vec_entry *table; + int max_sleep, i; + bool skip; + + table = range_2; + if (period < IWL_DTIM_RANGE_1_MAX) + table = range_1; + if (period < IWL_DTIM_RANGE_0_MAX) + table = range_0; + + BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM); + + *cmd = table[lvl].cmd; + + if (period == 0) { + skip = false; + period = 1; + } else { + skip = !!table[lvl].no_dtim; + } + + if (skip) { + __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; + max_sleep = le32_to_cpu(slp_itrvl); + if (max_sleep == 0xFF) + max_sleep = period * (skip + 1); + else if (max_sleep > period) + max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; + cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; + } else { + max_sleep = period; + cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; + } + + for (i = 0; i < IWL_POWER_VEC_SIZE; i++) + if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) + cmd->sleep_interval[i] = cpu_to_le32(max_sleep); + + if (priv->power_data.pci_pm) + cmd->flags |= IWL_POWER_PCI_PM_MSK; + else + cmd->flags &= ~IWL_POWER_PCI_PM_MSK; + + IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1); +} + /* default Thermal Throttling transaction table * Current state | Throttling Down | Throttling Up *============================================================================= @@ -138,98 +200,44 @@ static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = { {IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false } }; -/* set card power command */ -static int iwl_set_power(struct iwl_priv *priv, void *cmd) -{ - return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, - sizeof(struct iwl_powertable_cmd), cmd); -} -/* initialize to default */ -static void iwl_power_init_handle(struct iwl_priv *priv) +static void iwl_power_sleep_cam_cmd(struct iwl_priv *priv, + struct iwl_powertable_cmd *cmd) { - struct iwl_power_mgr *pow_data; - int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_NUM; - struct iwl_powertable_cmd *cmd; - int i; - u16 lctl; - - IWL_DEBUG_POWER(priv, "Initialize power \n"); - - pow_data = &priv->power_data; - - memset(pow_data, 0, sizeof(*pow_data)); - - memcpy(&pow_data->pwr_range_0[0], &range_0[0], size); - memcpy(&pow_data->pwr_range_1[0], &range_1[0], size); - memcpy(&pow_data->pwr_range_2[0], &range_2[0], size); - - lctl = iwl_pcie_link_ctl(priv); + memset(cmd, 0, sizeof(*cmd)); - IWL_DEBUG_POWER(priv, "adjust power command flags\n"); + if (priv->power_data.pci_pm) + cmd->flags |= IWL_POWER_PCI_PM_MSK; - for (i = 0; i < IWL_POWER_NUM; i++) { - cmd = &pow_data->pwr_range_0[i].cmd; - - if (lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN) - cmd->flags &= ~IWL_POWER_PCI_PM_MSK; - else - cmd->flags |= IWL_POWER_PCI_PM_MSK; - } + IWL_DEBUG_POWER(priv, "Sleep command for CAM\n"); } -/* adjust power command according to DTIM period and power level*/ -static int iwl_update_power_cmd(struct iwl_priv *priv, - struct iwl_powertable_cmd *cmd, u16 mode) +static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv, + struct iwl_powertable_cmd *cmd, + int dynps_ms, int wakeup_period) { - struct iwl_power_vec_entry *range; - struct iwl_power_mgr *pow_data; int i; - u32 max_sleep = 0; - u8 period; - bool skip; - if (mode > IWL_POWER_INDEX_5) { - IWL_DEBUG_POWER(priv, "Error invalid power mode \n"); - return -EINVAL; - } + memset(cmd, 0, sizeof(*cmd)); - pow_data = &priv->power_data; + cmd->flags = IWL_POWER_DRIVER_ALLOW_SLEEP_MSK | + IWL_POWER_FAST_PD; /* no use seeing frames for others */ - if (pow_data->dtim_period <= IWL_POWER_RANGE_0_MAX) - range = &pow_data->pwr_range_0[0]; - else if (pow_data->dtim_period <= IWL_POWER_RANGE_1_MAX) - range = &pow_data->pwr_range_1[0]; - else - range = &pow_data->pwr_range_2[0]; + if (priv->power_data.pci_pm) + cmd->flags |= IWL_POWER_PCI_PM_MSK; - period = pow_data->dtim_period; - memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd)); - - if (period == 0) { - period = 1; - skip = false; - } else { - skip = !!range[mode].no_dtim; - } - - if (skip) { - __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; - max_sleep = le32_to_cpu(slp_itrvl); - if (max_sleep == 0xFF) - max_sleep = period * (skip + 1); - else if (max_sleep > period) - max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; - cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; - } else { - max_sleep = period; - cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; - } + cmd->rx_data_timeout = cpu_to_le32(1000 * dynps_ms); + cmd->tx_data_timeout = cpu_to_le32(1000 * dynps_ms); for (i = 0; i < IWL_POWER_VEC_SIZE; i++) - if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) - cmd->sleep_interval[i] = cpu_to_le32(max_sleep); + cmd->sleep_interval[i] = cpu_to_le32(wakeup_period); + + IWL_DEBUG_POWER(priv, "Automatic sleep command\n"); +} +static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd) +{ + IWL_DEBUG_POWER(priv, "Sending power/sleep command\n"); IWL_DEBUG_POWER(priv, "Flags value = 0x%08X\n", cmd->flags); IWL_DEBUG_POWER(priv, "Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout)); IWL_DEBUG_POWER(priv, "Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout)); @@ -240,50 +248,54 @@ static int iwl_update_power_cmd(struct iwl_priv *priv, le32_to_cpu(cmd->sleep_interval[3]), le32_to_cpu(cmd->sleep_interval[4])); - return 0; + return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, + sizeof(struct iwl_powertable_cmd), cmd); } -/* - * compute the final power mode index - */ int iwl_power_update_mode(struct iwl_priv *priv, bool force) { - struct iwl_power_mgr *setting = &(priv->power_data); int ret = 0; struct iwl_tt_mgmt *tt = &priv->thermal_throttle; - u16 uninitialized_var(final_mode); + bool enabled = (priv->iw_mode == NL80211_IFTYPE_STATION) && + (priv->hw->conf.flags & IEEE80211_CONF_PS); bool update_chains; + struct iwl_powertable_cmd cmd; + int dtimper; /* Don't update the RX chain when chain noise calibration is running */ update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; - final_mode = priv->power_data.user_power_setting; - - if (setting->power_disabled) - final_mode = IWL_POWER_MODE_CAM; + if (priv->vif) + dtimper = priv->vif->bss_conf.dtim_period; + else + dtimper = 1; + + /* TT power setting overwrites everything */ + if (tt->state >= IWL_TI_1) + iwl_static_sleep_cmd(priv, &cmd, tt->tt_power_mode, dtimper); + else if (!enabled) + iwl_power_sleep_cam_cmd(priv, &cmd); + else if (priv->power_data.debug_sleep_level_override >= 0) + iwl_static_sleep_cmd(priv, &cmd, + priv->power_data.debug_sleep_level_override, + dtimper); + else if (no_sleep_autoadjust) + iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_1, dtimper); + else + iwl_power_fill_sleep_cmd(priv, &cmd, + priv->hw->conf.dynamic_ps_timeout, + priv->hw->conf.max_sleep_period); - if (tt->state >= IWL_TI_1) { - /* TT power setting overwrite user & system power setting */ - final_mode = tt->tt_power_mode; - } if (iwl_is_ready_rf(priv) && - ((setting->power_mode != final_mode) || force)) { - struct iwl_powertable_cmd cmd; - - if (final_mode != IWL_POWER_MODE_CAM) + (memcmp(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd)) || force)) { + if (cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK) set_bit(STATUS_POWER_PMI, &priv->status); - iwl_update_power_cmd(priv, &cmd, final_mode); - cmd.keep_alive_beacons = 0; - - if (final_mode == IWL_POWER_INDEX_5) - cmd.flags |= IWL_POWER_FAST_PD; - ret = iwl_set_power(priv, &cmd); if (!ret) { - if (final_mode == IWL_POWER_MODE_CAM) + if (!(cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)) clear_bit(STATUS_POWER_PMI, &priv->status); if (priv->cfg->ops->lib->update_chain_flags && @@ -294,7 +306,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) "Cannot update the power, chain noise " "calibration running: %d\n", priv->chain_noise_data.state); - setting->power_mode = final_mode; + memcpy(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd)); } else IWL_ERR(priv, "set power fail, ret = %d", ret); } @@ -303,18 +315,6 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) } EXPORT_SYMBOL(iwl_power_update_mode); -/* set user_power_setting */ -int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) -{ - if (mode >= IWL_POWER_NUM) - return -EINVAL; - - priv->power_data.user_power_setting = mode; - - return iwl_power_update_mode(priv, 0); -} -EXPORT_SYMBOL(iwl_power_set_user_mode); - bool iwl_ht_enabled(struct iwl_priv *priv) { struct iwl_tt_mgmt *tt = &priv->thermal_throttle; @@ -349,7 +349,6 @@ enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv) restriction = tt->restriction + tt->state; return restriction->rx_stream; } -EXPORT_SYMBOL(iwl_rx_ant_restriction); #define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */ @@ -429,7 +428,6 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) { struct iwl_tt_mgmt *tt = &priv->thermal_throttle; enum iwl_tt_state old_state; - struct iwl_power_mgr *setting = &priv->power_data; #ifdef CONFIG_IWLWIFI_DEBUG if ((tt->tt_previous_temp) && @@ -456,24 +454,13 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) tt->tt_previous_temp = temp; #endif if (tt->state != old_state) { - if (old_state == IWL_TI_0) { - tt->sys_power_mode = setting->power_mode; - IWL_DEBUG_POWER(priv, "current power mode: %u\n", - setting->power_mode); - } switch (tt->state) { case IWL_TI_0: - /* when system ready to go back to IWL_TI_0 state - * using system power mode instead of TT power mode - * revert back to the orginal power mode which was saved - * before enter Thermal Throttling state - * update priv->power_data.user_power_setting to the - * required power mode to make sure - * iwl_power_update_mode() will update power correctly. + /* + * When the system is ready to go back to IWL_TI_0 + * we only have to call iwl_power_update_mode() to + * do so. */ - priv->power_data.user_power_setting = - tt->sys_power_mode; - tt->tt_power_mode = tt->sys_power_mode; break; case IWL_TI_1: tt->tt_power_mode = IWL_POWER_INDEX_3; @@ -576,13 +563,8 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) } if (changed) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; - struct iwl_power_mgr *setting = &priv->power_data; if (tt->state >= IWL_TI_1) { - /* if switching from IWL_TI_0 to other TT state - * save previous power setting in tt->sys_power_mode */ - if (old_state == IWL_TI_0) - tt->sys_power_mode = setting->power_mode; /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */ tt->tt_power_mode = IWL_POWER_INDEX_5; if (!iwl_ht_enabled(priv)) @@ -599,17 +581,11 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) } } else { - /* restore system power setting */ - /* the previous power mode was saved in - * tt->sys_power_mode when system move into - * Thermal Throttling state - * set power_data.user_power_setting to the previous - * system power mode to make sure power will get - * updated correctly + /* + * restore system power setting -- it will be + * recalculated automatically. */ - priv->power_data.user_power_setting = - tt->sys_power_mode; - tt->tt_power_mode = tt->sys_power_mode; + /* check HT capability and set * according to the system HT capability * in case get disabled before */ @@ -761,7 +737,6 @@ EXPORT_SYMBOL(iwl_tt_handler); void iwl_tt_initialize(struct iwl_priv *priv) { struct iwl_tt_mgmt *tt = &priv->thermal_throttle; - struct iwl_power_mgr *setting = &priv->power_data; int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1); struct iwl_tt_trans *transaction; @@ -770,8 +745,6 @@ void iwl_tt_initialize(struct iwl_priv *priv) memset(tt, 0, sizeof(struct iwl_tt_mgmt)); tt->state = IWL_TI_0; - tt->sys_power_mode = setting->power_mode; - tt->tt_power_mode = tt->sys_power_mode; init_timer(&priv->thermal_throttle.ct_kill_exit_tm); priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv; priv->thermal_throttle.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; @@ -849,9 +822,13 @@ EXPORT_SYMBOL(iwl_tt_exit); /* initialize to default */ void iwl_power_initialize(struct iwl_priv *priv) { - iwl_power_init_handle(priv); - priv->power_data.user_power_setting = IWL_POWER_INDEX_1; - /* default to disabled until mac80211 says otherwise */ - priv->power_data.power_disabled = 1; + u16 lctl = iwl_pcie_link_ctl(priv); + + priv->power_data.pci_pm = !(lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN); + + priv->power_data.debug_sleep_level_override = -1; + + memset(&priv->power_data.sleep_cmd, 0, + sizeof(priv->power_data.sleep_cmd)); } EXPORT_SYMBOL(iwl_power_initialize); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 15e3eabd2e8..df6f6a49712 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -28,11 +28,8 @@ #ifndef __iwl_power_setting_h__ #define __iwl_power_setting_h__ -#include #include "iwl-commands.h" -struct iwl_priv; - #define IWL_ABSOLUTE_ZERO 0 #define IWL_ABSOLUTE_MAX 0xFFFFFFFF #define IWL_TT_INCREASE_MARGIN 5 @@ -93,8 +90,6 @@ struct iwl_tt_trans { * when thermal throttling state != IWL_TI_0 * the tt_power_mode should set to different * power mode based on the current tt state - * @sys_power_mode: previous system power mode - * before transition into TT state * @tt_previous_temperature: last measured temperature * @iwl_tt_restriction: ptr to restriction tbl, used by advance * thermal throttling to determine how many tx/rx streams @@ -108,7 +103,6 @@ struct iwl_tt_mgmt { enum iwl_tt_state state; bool advanced_tt; u8 tt_power_mode; - u8 sys_power_mode; bool ct_kill_toggle; #ifdef CONFIG_IWLWIFI_DEBUG s32 tt_previous_temp; @@ -118,8 +112,7 @@ struct iwl_tt_mgmt { struct timer_list ct_kill_exit_tm; }; -enum { - IWL_POWER_MODE_CAM, /* Continuously Aware Mode, always on */ +enum iwl_power_level { IWL_POWER_INDEX_1, IWL_POWER_INDEX_2, IWL_POWER_INDEX_3, @@ -128,26 +121,13 @@ enum { IWL_POWER_NUM }; -/* Power management (not Tx power) structures */ - -struct iwl_power_vec_entry { - struct iwl_powertable_cmd cmd; - u8 no_dtim; -}; - struct iwl_power_mgr { - struct iwl_power_vec_entry pwr_range_0[IWL_POWER_NUM]; - struct iwl_power_vec_entry pwr_range_1[IWL_POWER_NUM]; - struct iwl_power_vec_entry pwr_range_2[IWL_POWER_NUM]; - u32 dtim_period; - /* final power level that used to calculate final power command */ - u8 power_mode; - u8 user_power_setting; /* set by user through sysfs */ - u8 power_disabled; /* set by mac80211's CONF_PS */ + struct iwl_powertable_cmd sleep_cmd; + int debug_sleep_level_override; + bool pci_pm; }; int iwl_power_update_mode(struct iwl_priv *priv, bool force); -int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); bool iwl_ht_enabled(struct iwl_priv *priv); enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv); enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv); @@ -158,4 +138,6 @@ void iwl_tt_initialize(struct iwl_priv *priv); void iwl_tt_exit(struct iwl_priv *priv); void iwl_power_initialize(struct iwl_priv *priv); +extern bool no_sleep_autoadjust; + #endif /* __iwl_power_setting_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index e5fa672e839..e617411d0c5 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3554,65 +3554,6 @@ static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate, store_retry_rate); -static ssize_t store_power_level(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - int ret; - unsigned long mode; - - - mutex_lock(&priv->mutex); - - ret = strict_strtoul(buf, 10, &mode); - if (ret) - goto out; - - ret = iwl_power_set_user_mode(priv, mode); - if (ret) { - IWL_DEBUG_MAC80211(priv, "failed setting power mode.\n"); - goto out; - } - ret = count; - - out: - mutex_unlock(&priv->mutex); - return ret; -} - -static ssize_t show_power_level(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - int level = priv->power_data.power_mode; - char *p = buf; - - p += sprintf(p, "%d\n", level); - return p - buf + 1; -} - -static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, - show_power_level, store_power_level); - -#define MAX_WX_STRING 80 - -/* Values are in microsecond */ -static const s32 timeout_duration[] = { - 350000, - 250000, - 75000, - 37000, - 25000, -}; -static const s32 period_duration[] = { - 400000, - 700000, - 1000000, - 1000000, - 1000000 -}; - static ssize_t show_channels(struct device *d, struct device_attribute *attr, char *buf) { @@ -3789,7 +3730,6 @@ static struct attribute *iwl3945_sysfs_entries[] = { #ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT &dev_attr_measurement.attr, #endif - &dev_attr_power_level.attr, &dev_attr_retry_rate.attr, &dev_attr_statistics.attr, &dev_attr_status.attr, @@ -3854,8 +3794,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv) priv->qos_data.qos_cap.val = 0; priv->rates_mask = IWL_RATES_MASK; - /* If power management is turned on, default to CAM mode */ - priv->power_mode = IWL_POWER_MODE_CAM; priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER; if (eeprom->version < EEPROM_3945_EEPROM_VERSION) { @@ -3902,7 +3840,9 @@ static int iwl3945_setup_mac(struct iwl_priv *priv) /* Tell mac80211 our characteristics */ hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM | - IEEE80211_HW_SPECTRUM_MGMT; + IEEE80211_HW_SPECTRUM_MGMT | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_SUPPORTS_DYNAMIC_PS; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | -- cgit v1.2.3-18-g5258 From 4d30d309a3be84dfb01743ceb4652405204a80a0 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 8 Aug 2009 15:22:26 +0200 Subject: drivers/net/wireless/ath/ath5k: Change constant name Elsewhere, the tqi_type field is compared to constants having a name beginning with AR5K_TX_QUEUE, rather than AR5K_TX_QUEUE_ID. I have thus converted AR5K_TX_QUEUE_ID_CAB to AR5K_TX_QUEUE_CAB. This does, however, change the value, so perhaps something else was wanted. Signed-off-by: Julia Lawall Acked-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/qcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 6d5aaf00d8b..eeebb9aef20 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -362,7 +362,7 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) } if (tq->tqi_ready_time && - (tq->tqi_type != AR5K_TX_QUEUE_ID_CAB)) + (tq->tqi_type != AR5K_TX_QUEUE_CAB)) ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time, AR5K_QCU_RDYTIMECFG_INTVAL) | AR5K_QCU_RDYTIMECFG_ENABLE, -- cgit v1.2.3-18-g5258 From bdfa500b8b8ca87dfe7a311f569fe8b39746c299 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 8 Aug 2009 23:53:04 +0200 Subject: rt2x00: Remove usage of deprecated radio_enabled & IEEE80211_CONF_CHANGE_RADIO_ENABLED In the config() callback function the fields radio_enabled and the change flag IEEE80211_CONF_CHANGE_RADIO_ENABLED have been deprecated. This removes the usage of those fields by improving antenna change detection in the antenna configuration function. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00config.c | 22 ++++++++---- drivers/net/wireless/rt2x00/rt2x00dev.c | 7 ++++ drivers/net/wireless/rt2x00/rt2x00link.c | 12 ++++--- drivers/net/wireless/rt2x00/rt2x00mac.c | 54 +++++++++++------------------- 4 files changed, 50 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 3845316ccd3..3501788ab49 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -124,8 +124,9 @@ enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant, } void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup ant) + struct antenna_setup config) { + struct link_ant *ant = &rt2x00dev->link.ant; struct antenna_setup *def = &rt2x00dev->default_ant; struct antenna_setup *active = &rt2x00dev->link.ant.active; @@ -134,14 +135,23 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, * ANTENNA_SW_DIVERSITY state to the driver. * If that happens, fallback to hardware defaults, * or our own default. + * If diversity handling is active for a particular antenna, + * we shouldn't overwrite that antenna. * The calls to rt2x00lib_config_antenna_check() * might have caused that we restore back to the already * active setting. If that has happened we can quit. */ - ant.rx = rt2x00lib_config_antenna_check(ant.rx, def->rx); - ant.tx = rt2x00lib_config_antenna_check(ant.tx, def->tx); + if (!(ant->flags & ANTENNA_RX_DIVERSITY)) + config.rx = rt2x00lib_config_antenna_check(config.rx, def->rx); + else + config.rx = active->rx; - if (ant.rx == active->rx && ant.tx == active->tx) + if (!(ant->flags & ANTENNA_TX_DIVERSITY)) + config.tx = rt2x00lib_config_antenna_check(config.tx, def->tx); + else + config.tx = active->tx; + + if (config.rx == active->rx && config.tx == active->tx) return; /* @@ -156,11 +166,11 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, * The latter is required since we need to recalibrate the * noise-sensitivity ratio for the new setup. */ - rt2x00dev->ops->lib->config_ant(rt2x00dev, &ant); + rt2x00dev->ops->lib->config_ant(rt2x00dev, &config); rt2x00link_reset_tuner(rt2x00dev, true); - memcpy(active, &ant, sizeof(ant)); + memcpy(active, &config, sizeof(config)); if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index db54fcc94c8..e0348cc22d1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -785,6 +785,13 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) rt2x00dev->intf_sta_count = 0; rt2x00dev->intf_associated = 0; + /* Enable the radio */ + retval = rt2x00lib_enable_radio(rt2x00dev); + if (retval) { + rt2x00queue_uninitialize(rt2x00dev); + return retval; + } + set_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags); return 0; diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 917831689cc..fe951dc9bac 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -219,6 +219,7 @@ static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev) static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) { struct link_ant *ant = &rt2x00dev->link.ant; + unsigned int flags = ant->flags; /* * Determine if software diversity is enabled for @@ -226,13 +227,13 @@ static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) * Always perform this check since within the link * tuner interval the configuration might have changed. */ - ant->flags &= ~ANTENNA_RX_DIVERSITY; - ant->flags &= ~ANTENNA_TX_DIVERSITY; + flags &= ~ANTENNA_RX_DIVERSITY; + flags &= ~ANTENNA_TX_DIVERSITY; if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) - ant->flags |= ANTENNA_RX_DIVERSITY; + flags |= ANTENNA_RX_DIVERSITY; if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) - ant->flags |= ANTENNA_TX_DIVERSITY; + flags |= ANTENNA_TX_DIVERSITY; if (!(ant->flags & ANTENNA_RX_DIVERSITY) && !(ant->flags & ANTENNA_TX_DIVERSITY)) { @@ -240,6 +241,9 @@ static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) return; } + /* Update flags */ + ant->flags = flags; + /* * If we have only sampled the data over the last period * we should now harvest the data. Otherwise just evaluate diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 81febdfd663..4164fce0598 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -338,7 +338,6 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) { struct rt2x00_dev *rt2x00dev = hw->priv; struct ieee80211_conf *conf = &hw->conf; - int status; /* * mac80211 might be calling this function while we are trying @@ -348,44 +347,29 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) return 0; /* - * Only change device state when the radio is enabled. It does not - * matter what parameters we have configured when the radio is disabled - * because we won't be able to send or receive anyway. Also note that - * some configuration parameters (e.g. channel and antenna values) can - * only be set when the radio is enabled. + * Some configuration parameters (e.g. channel and antenna values) can + * only be set when the radio is enabled, but do require the RX to + * be off. */ - if (conf->radio_enabled) { - /* For programming the values, we have to turn RX off */ - rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); - /* Enable the radio */ - status = rt2x00lib_enable_radio(rt2x00dev); - if (unlikely(status)) - return status; + /* + * When we've just turned on the radio, we want to reprogram + * everything to ensure a consistent state + */ + rt2x00lib_config(rt2x00dev, conf, changed); - /* - * When we've just turned on the radio, we want to reprogram - * everything to ensure a consistent state - */ - rt2x00lib_config(rt2x00dev, conf, changed); + /* + * After the radio has been enabled we need to configure + * the antenna to the default settings. rt2x00lib_config_antenna() + * should determine if any action should be taken based on + * checking if diversity has been enabled or no antenna changes + * have been made since the last configuration change. + */ + rt2x00lib_config_antenna(rt2x00dev, rt2x00dev->default_ant); - /* - * The radio was enabled, configure the antenna to the - * default settings, the link tuner will later start - * continue configuring the antenna based on the software - * diversity. But for non-diversity configurations, we need - * to have configured the correct state now. - */ - if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) - rt2x00lib_config_antenna(rt2x00dev, - rt2x00dev->default_ant); - - /* Turn RX back on */ - rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); - } else { - /* Disable the radio */ - rt2x00lib_disable_radio(rt2x00dev); - } + /* Turn RX back on */ + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); return 0; } -- cgit v1.2.3-18-g5258 From 267e898755d7fc6249e26208e7ce97f415fd8c31 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 8 Aug 2009 23:53:26 +0200 Subject: rt2x00: Use IEEE80211_TX_CTL_MORE_FRAMES flag Check the IEEE80211_TX_CTL_MORE_FRAMES flag to help determining if the DMA queue should be kicked. At the moment this is combined with the ieee80211_has_morefrags() but we might remove that later. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00queue.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 44e5b3279ca..65435c9fe4b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -324,7 +324,8 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, /* * Check if more fragments are pending */ - if (ieee80211_has_morefrags(hdr->frame_control)) { + if (ieee80211_has_morefrags(hdr->frame_control) || + (tx_info->flags & IEEE80211_TX_CTL_MORE_FRAMES)) { __set_bit(ENTRY_TXD_BURST, &txdesc->flags); __set_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags); } -- cgit v1.2.3-18-g5258 From 93354cbbcbfca920495377158c0f61c36be79e13 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 8 Aug 2009 23:53:47 +0200 Subject: rt2x00: Align ieee80211 header to 4-byte boundary for PCI devices Some hardware require the ieee80211 header to be aligned to a 4-byte boundary before mapping it to the DMA. Otherwise some frames (like beacons) will not be send out correctly by the device. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00queue.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 65435c9fe4b..e67e339d9df 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -453,9 +453,21 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) rt2x00crypto_tx_remove_iv(skb, &txdesc); } + /* + * When DMA allocation is required we should guarentee to the + * driver that the DMA is aligned to a 4-byte boundary. + * Aligning the header to this boundary can be done by calling + * rt2x00queue_payload_align with the header length of 0. + * However some drivers require L2 padding to pad the payload + * rather then the header. This could be a requirement for + * PCI and USB devices, while header alignment only is valid + * for PCI devices. + */ if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags)) rt2x00queue_payload_align(entry->skb, true, txdesc.header_length); + else if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) + rt2x00queue_payload_align(entry->skb, false, 0); /* * It could be possible that the queue was corrupted and this -- cgit v1.2.3-18-g5258 From 193df183b15cda78f6b2373f576e243327ea0d8f Mon Sep 17 00:00:00 2001 From: Lars Ericsson Date: Sat, 8 Aug 2009 23:54:24 +0200 Subject: rt2x00: Fix quality houskeeping for software diversity Antanna quality statistics is not handled correctly, which leads to software diversity being shutdown completly. The main problem is that during antenna diversity statistics can be reset resulting in loosing the signal strength just before evaluation. rssi history is not updated correctly leading to incorrect comparison material for basing antenna switching on. Signed-off-by: Lars Ericsson Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 11 ++--- drivers/net/wireless/rt2x00/rt2x00link.c | 77 ++++++++++++++------------------ 2 files changed, 38 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index cbec91ef6f7..704e94474b1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -245,14 +245,11 @@ struct link_ant { struct antenna_setup active; /* - * RSSI information for the different antennas. - * These statistics are used to determine when - * to switch antenna when using software diversity. - * - * rssi[0] -> Antenna A RSSI - * rssi[1] -> Antenna B RSSI + * RSSI history information for the antenna. + * Used to determine when to switch antenna + * when using software diversity. */ - int rssi_history[2]; + int rssi_history; /* * Current RSSI average of the currently active antenna. diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index fe951dc9bac..dd68f3a57b6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -103,39 +103,21 @@ static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev) return DEFAULT_RSSI; } -static int rt2x00link_antenna_get_rssi_history(struct rt2x00_dev *rt2x00dev, - enum antenna antenna) +static int rt2x00link_antenna_get_rssi_history(struct rt2x00_dev *rt2x00dev) { struct link_ant *ant = &rt2x00dev->link.ant; - if (ant->rssi_history[antenna - ANTENNA_A]) - return ant->rssi_history[antenna - ANTENNA_A]; + if (ant->rssi_history) + return ant->rssi_history; return DEFAULT_RSSI; } -/* Small wrapper for rt2x00link_antenna_get_rssi_history() */ -#define rt2x00link_antenna_get_rssi_rx_history(__dev) \ - rt2x00link_antenna_get_rssi_history((__dev), \ - (__dev)->link.ant.active.rx) -#define rt2x00link_antenna_get_rssi_tx_history(__dev) \ - rt2x00link_antenna_get_rssi_history((__dev), \ - (__dev)->link.ant.active.tx) static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev, - enum antenna antenna, int rssi) { struct link_ant *ant = &rt2x00dev->link.ant; - ant->rssi_history[ant->active.rx - ANTENNA_A] = rssi; + ant->rssi_history = rssi; } -/* Small wrapper for rt2x00link_antenna_get_rssi_history() */ -#define rt2x00link_antenna_update_rssi_rx_history(__dev, __rssi) \ - rt2x00link_antenna_update_rssi_history((__dev), \ - (__dev)->link.ant.active.rx, \ - (__rssi)) -#define rt2x00link_antenna_update_rssi_tx_history(__dev, __rssi) \ - rt2x00link_antenna_update_rssi_history((__dev), \ - (__dev)->link.ant.active.tx, \ - (__rssi)) static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev) { @@ -146,8 +128,10 @@ static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev) { struct link_ant *ant = &rt2x00dev->link.ant; struct antenna_setup new_ant; - int sample_a = rt2x00link_antenna_get_rssi_history(rt2x00dev, ANTENNA_A); - int sample_b = rt2x00link_antenna_get_rssi_history(rt2x00dev, ANTENNA_B); + int other_antenna; + + int sample_current = rt2x00link_antenna_get_link_rssi(rt2x00dev); + int sample_other = rt2x00link_antenna_get_rssi_history(rt2x00dev); memcpy(&new_ant, &ant->active, sizeof(new_ant)); @@ -161,17 +145,22 @@ static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev) * from both antennas. It now is time to determine * which antenna demonstrated the best performance. * When we are already on the antenna with the best - * performance, then there really is nothing for us - * left to do. + * performance, just create a good starting point + * for the history and we are done. */ - if (sample_a == sample_b) + if (sample_current >= sample_other) { + rt2x00link_antenna_update_rssi_history(rt2x00dev, + sample_current); return; + } + + other_antenna = (ant->active.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; if (ant->flags & ANTENNA_RX_DIVERSITY) - new_ant.rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; + new_ant.rx = other_antenna; if (ant->flags & ANTENNA_TX_DIVERSITY) - new_ant.tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; + new_ant.tx = other_antenna; rt2x00lib_config_antenna(rt2x00dev, new_ant); } @@ -190,8 +179,8 @@ static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev) * after that update the history with the current value. */ rssi_curr = rt2x00link_antenna_get_link_rssi(rt2x00dev); - rssi_old = rt2x00link_antenna_get_rssi_rx_history(rt2x00dev); - rt2x00link_antenna_update_rssi_rx_history(rt2x00dev, rssi_curr); + rssi_old = rt2x00link_antenna_get_rssi_history(rt2x00dev); + rt2x00link_antenna_update_rssi_history(rt2x00dev, rssi_curr); /* * Legacy driver indicates that we should swap antenna's @@ -216,7 +205,7 @@ static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev) rt2x00lib_config_antenna(rt2x00dev, new_ant); } -static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) +static bool rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) { struct link_ant *ant = &rt2x00dev->link.ant; unsigned int flags = ant->flags; @@ -238,7 +227,7 @@ static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) if (!(ant->flags & ANTENNA_RX_DIVERSITY) && !(ant->flags & ANTENNA_TX_DIVERSITY)) { ant->flags = 0; - return; + return true; } /* Update flags */ @@ -250,10 +239,15 @@ static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) * the data. The latter should only be performed once * every 2 seconds. */ - if (ant->flags & ANTENNA_MODE_SAMPLE) + if (ant->flags & ANTENNA_MODE_SAMPLE) { rt2x00lib_antenna_diversity_sample(rt2x00dev); - else if (rt2x00dev->link.count & 1) + return true; + } else if (rt2x00dev->link.count & 1) { rt2x00lib_antenna_diversity_eval(rt2x00dev); + return true; + } + + return false; } void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, @@ -451,15 +445,12 @@ static void rt2x00link_tuner(struct work_struct *work) rt2x00leds_led_quality(rt2x00dev, link->avg_rssi); /* - * Evaluate antenna setup, make this the last step since this could - * possibly reset some statistics. - */ - rt2x00lib_antenna_diversity(rt2x00dev); - - /* - * Reset the quality counters which recounted during each period. + * Evaluate antenna setup, make this the last step when + * rt2x00lib_antenna_diversity made changes the quality + * statistics will be reset. */ - rt2x00link_reset_qual(rt2x00dev); + if (rt2x00lib_antenna_diversity(rt2x00dev)) + rt2x00link_reset_qual(rt2x00dev); /* * Increase tuner counter, and reschedule the next link tuner run. -- cgit v1.2.3-18-g5258 From 66679a65efffffb62dc2650960b3aff758d575f9 Mon Sep 17 00:00:00 2001 From: Lars Ericsson Date: Sat, 8 Aug 2009 23:54:51 +0200 Subject: rt2x00: Fix rounding errors in RSSI average calculation Small changes in signal level was not detected up by the MOVING_AVERAGE() due to a rounding error, using 'int' type. rt2x00lib_antenna_diversity_eval: rssi: -62 -62 -62 -62 -62 -62 -62 -62 -62 -62 -62 -62 -62 -62 -62 rssi_avg: -57 -57 -57 -57 -57 -57 -57 -57 -57 -57 -57 -57 -57 -57 -57 The signal level reported back could be significantly (5dBm) different from the actual value. A level +3dBm is the same as double the AP output power. Signed-off-by: Lars Ericsson Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 15 +++++++- drivers/net/wireless/rt2x00/rt2x00link.c | 65 +++++++++++++++++++------------- 2 files changed, 52 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 704e94474b1..e6e73be31e3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -133,6 +133,17 @@ #define SHORT_EIFS ( SIFS + SHORT_DIFS + \ GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) ) +/* + * Structure for average calculation + * The avg field contains the actual average value, + * but avg_weight is internally used during calculations + * to prevent rounding errors. + */ +struct avg_val { + int avg; + int avg_weight; +}; + /* * Chipset identification * The chipset on the device is composed of a RT and RF chip. @@ -256,7 +267,7 @@ struct link_ant { * Similar to the avg_rssi in the link_qual structure * this value is updated by using the walking average. */ - int rssi_ant; + struct avg_val rssi_ant; }; /* @@ -285,7 +296,7 @@ struct link { /* * Currently active average RSSI value */ - int avg_rssi; + struct avg_val avg_rssi; /* * Currently precalculated percentages of successful diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index dd68f3a57b6..c64db0ba7f4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -46,7 +46,15 @@ #define DEFAULT_PERCENTAGE 50 /* - * Small helper macro to work with moving/walking averages. + * Small helper macro for percentage calculation + * This is a very simple macro with the only catch that it will + * produce a default value in case no total value was provided. + */ +#define PERCENTAGE(__value, __total) \ + ( (__total) ? (((__value) * 100) / (__total)) : (DEFAULT_PERCENTAGE) ) + +/* + * Helper struct and macro to work with moving/walking averages. * When adding a value to the average value the following calculation * is needed: * @@ -60,18 +68,28 @@ * for a few minutes but when the device is moved away from the AP * the average will not decrease fast enough to compensate. * The walking average compensates this and will move towards - * the new values correctly allowing a effective link tuning. + * the new values correctly allowing a effective link tuning, + * the speed of the average moving towards other values depends + * on the value for the number of samples. The higher the number + * of samples, the slower the average will move. + * We use two variables to keep track of the average value to + * compensate for the rounding errors. This can be a significant + * error (>5dBm) if the factor is too low. */ -#define MOVING_AVERAGE(__avg, __val, __samples) \ - ( (((__avg) * ((__samples) - 1)) + (__val)) / (__samples) ) - -/* - * Small helper macro for percentage calculation - * This is a very simple macro with the only catch that it will - * produce a default value in case no total value was provided. - */ -#define PERCENTAGE(__value, __total) \ - ( (__total) ? (((__value) * 100) / (__total)) : (DEFAULT_PERCENTAGE) ) +#define AVG_SAMPLES 8 +#define AVG_FACTOR 1000 +#define MOVING_AVERAGE(__avg, __val) \ +({ \ + struct avg_val __new; \ + __new.avg_weight = \ + (__avg).avg_weight ? \ + ((((__avg).avg_weight * ((AVG_SAMPLES) - 1)) + \ + ((__val) * (AVG_FACTOR))) / \ + (AVG_SAMPLES) ) : \ + ((__val) * (AVG_FACTOR)); \ + __new.avg = __new.avg_weight / (AVG_FACTOR); \ + __new; \ +}) /* * For calculating the Signal quality we have determined @@ -98,8 +116,8 @@ static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev) { struct link_ant *ant = &rt2x00dev->link.ant; - if (ant->rssi_ant && rt2x00dev->link.qual.rx_success) - return ant->rssi_ant; + if (ant->rssi_ant.avg && rt2x00dev->link.qual.rx_success) + return ant->rssi_ant.avg; return DEFAULT_RSSI; } @@ -121,7 +139,8 @@ static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev, static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev) { - rt2x00dev->link.ant.rssi_ant = 0; + rt2x00dev->link.ant.rssi_ant.avg = 0; + rt2x00dev->link.ant.rssi_ant.avg_weight = 0; } static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev) @@ -258,8 +277,6 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, struct link_qual *qual = &rt2x00dev->link.qual; struct link_ant *ant = &rt2x00dev->link.ant; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - int avg_rssi = rxdesc->rssi; - int ant_rssi = rxdesc->rssi; /* * Frame was received successfully since non-succesfull @@ -279,16 +296,12 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, /* * Update global RSSI */ - if (link->avg_rssi) - avg_rssi = MOVING_AVERAGE(link->avg_rssi, rxdesc->rssi, 8); - link->avg_rssi = avg_rssi; + link->avg_rssi = MOVING_AVERAGE(link->avg_rssi, rxdesc->rssi); /* * Update antenna RSSI */ - if (ant->rssi_ant) - ant_rssi = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi, 8); - ant->rssi_ant = ant_rssi; + ant->rssi_ant = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi); } static void rt2x00link_precalculate_signal(struct rt2x00_dev *rt2x00dev) @@ -421,10 +434,10 @@ static void rt2x00link_tuner(struct work_struct *work) * collect the RSSI data we could use this. Otherwise we * must fallback to the default RSSI value. */ - if (!link->avg_rssi || !qual->rx_success) + if (!link->avg_rssi.avg || !qual->rx_success) qual->rssi = DEFAULT_RSSI; else - qual->rssi = link->avg_rssi; + qual->rssi = link->avg_rssi.avg; /* * Only perform the link tuning when Link tuning @@ -442,7 +455,7 @@ static void rt2x00link_tuner(struct work_struct *work) /* * Send a signal to the led to update the led signal strength. */ - rt2x00leds_led_quality(rt2x00dev, link->avg_rssi); + rt2x00leds_led_quality(rt2x00dev, qual->rssi); /* * Evaluate antenna setup, make this the last step when -- cgit v1.2.3-18-g5258 From 17512dc3b7fc9ff1a60d3748ce87c323df507c3d Mon Sep 17 00:00:00 2001 From: Igor Perminov Date: Sat, 8 Aug 2009 23:55:18 +0200 Subject: rt2x00: Fix for race condition while update beacon The patch "Implement set_tim callback for all drivers" can cause kernel oops in rt73usb_write_beacon. The oops is caused by one of the following race conditions: * In case of two near calls to set_tim: rt2x00lib_beacondone_iter is cleaning the beacon skb, whereas rt73usb_write_beacon is still using it. * In case of two near updates of beacon: first as the result of set_tim and second as the result of a call from an application (e.g. hostapd). This patch fixes the race condition by rearranging the update logic and guarding rt2x00_intf->beacon->skb with a mutex. Signed-off-by: Igor Perminov Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 5 +++++ drivers/net/wireless/rt2x00/rt2x00dev.c | 7 ------- drivers/net/wireless/rt2x00/rt2x00mac.c | 1 + drivers/net/wireless/rt2x00/rt2x00queue.c | 15 ++++++++++++++- 4 files changed, 20 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index e6e73be31e3..7c74c4efcb0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -333,6 +333,11 @@ struct rt2x00_intf { */ u8 bssid[ETH_ALEN]; + /* + * beacon->skb must be protected with the mutex. + */ + struct mutex beacon_skb_mutex; + /* * Entry in the beacon queue which belongs to * this interface. Each interface has its own diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index e0348cc22d1..b6676c6722f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -186,7 +186,6 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work) static void rt2x00lib_beacondone_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { - struct rt2x00_dev *rt2x00dev = data; struct rt2x00_intf *intf = vif_to_intf(vif); if (vif->type != NL80211_IFTYPE_AP && @@ -195,12 +194,6 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac, vif->type != NL80211_IFTYPE_WDS) return; - /* - * Clean up the beacon skb. - */ - rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb); - intf->beacon->skb = NULL; - spin_lock(&intf->lock); intf->delayed_flags |= DELAYED_UPDATE_BEACON; spin_unlock(&intf->lock); diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 4164fce0598..74451f9672d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -274,6 +274,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, spin_lock_init(&intf->lock); spin_lock_init(&intf->seqlock); + mutex_init(&intf->beacon_skb_mutex); intf->beacon = entry; if (conf->type == NL80211_IFTYPE_AP) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index e67e339d9df..06af823efd8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -503,14 +503,25 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, if (unlikely(!intf->beacon)) return -ENOBUFS; + mutex_lock(&intf->beacon_skb_mutex); + + /* + * Clean up the beacon skb. + */ + rt2x00queue_free_skb(rt2x00dev, intf->beacon->skb); + intf->beacon->skb = NULL; + if (!enable_beacon) { rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, QID_BEACON); + mutex_unlock(&intf->beacon_skb_mutex); return 0; } intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif); - if (!intf->beacon->skb) + if (!intf->beacon->skb) { + mutex_unlock(&intf->beacon_skb_mutex); return -ENOMEM; + } /* * Copy all TX descriptor information into txdesc, @@ -548,6 +559,8 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, rt2x00dev->ops->lib->write_beacon(intf->beacon); rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON); + mutex_unlock(&intf->beacon_skb_mutex); + return 0; } -- cgit v1.2.3-18-g5258 From 1afcfd54fdf913017c07fa1ee497141a7958991d Mon Sep 17 00:00:00 2001 From: Igor Perminov Date: Sat, 8 Aug 2009 23:55:55 +0200 Subject: rt2x00: FIF_PSPOLL filter flag support This patch implements FIF_PSPOLL filter flag support in rt2x00 drivers, which has been introduced in mac80211 (see http://marc.info/?l=linux-wireless&m=124897986330807&w=2). Signed-off-by: Igor Perminov Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 9 ++++++++- drivers/net/wireless/rt2x00/rt2x00.h | 2 ++ drivers/net/wireless/rt2x00/rt2x00mac.c | 17 +++++++++++++++++ drivers/net/wireless/rt2x00/rt61pci.c | 8 +++++++- drivers/net/wireless/rt2x00/rt73usb.c | 8 +++++++- 5 files changed, 41 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 9efb4171050..2de0389d823 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -518,7 +518,7 @@ static void rt2800usb_config_filter(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, RX_FILTER_CFG_DROP_RTS, !(filter_flags & FIF_CONTROL)); rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PSPOLL, - !(filter_flags & FIF_CONTROL)); + !(filter_flags & FIF_PSPOLL)); rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BA, 1); rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, 0); rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CNTL, @@ -2623,6 +2623,13 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) if (retval) return retval; + /* + * This device has multiple filters for control frames + * and has a separate filter for PS Poll frames. + */ + __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); + __set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags); + /* * This device requires firmware. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 7c74c4efcb0..5bc100db28d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -624,6 +624,8 @@ enum rt2x00_flags { */ CONFIG_SUPPORT_HW_BUTTON, CONFIG_SUPPORT_HW_CRYPTO, + DRIVER_SUPPORT_CONTROL_FILTERS, + DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, /* * Driver configuration diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 74451f9672d..cb7b6d45933 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -392,6 +392,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, FIF_FCSFAIL | FIF_PLCPFAIL | FIF_CONTROL | + FIF_PSPOLL | FIF_OTHER_BSS | FIF_PROMISC_IN_BSS; @@ -406,6 +407,22 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, *total_flags & FIF_PROMISC_IN_BSS) *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; + /* + * If the device has a single filter for all control frames, + * FIF_CONTROL and FIF_PSPOLL flags imply each other. + * And if the device has more than one filter for control frames + * of different types, but has no a separate filter for PS Poll frames, + * FIF_CONTROL flag implies FIF_PSPOLL. + */ + if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags)) { + if (*total_flags & FIF_CONTROL || *total_flags & FIF_PSPOLL) + *total_flags |= FIF_CONTROL | FIF_PSPOLL; + } + if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags)) { + if (*total_flags & FIF_CONTROL) + *total_flags |= FIF_PSPOLL; + } + /* * Check if there is any work left for us. */ diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index e20dd7431f2..3447997fc71 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -530,7 +530,7 @@ static void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, !(filter_flags & FIF_PLCPFAIL)); rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, - !(filter_flags & FIF_CONTROL)); + !(filter_flags & (FIF_CONTROL | FIF_PSPOLL))); rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, !(filter_flags & FIF_PROMISC_IN_BSS)); rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, @@ -2623,6 +2623,12 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) if (retval) return retval; + /* + * This device has multiple filters for control frames, + * but has no a separate filter for PS Poll frames. + */ + __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); + /* * This device requires firmware and DMA mapped skbs. */ diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 4f9b1772e1a..4b9955b1c70 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -493,7 +493,7 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, !(filter_flags & FIF_PLCPFAIL)); rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, - !(filter_flags & FIF_CONTROL)); + !(filter_flags & (FIF_CONTROL | FIF_PSPOLL))); rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, !(filter_flags & FIF_PROMISC_IN_BSS)); rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, @@ -2143,6 +2143,12 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) if (retval) return retval; + /* + * This device has multiple filters for control frames, + * but has no a separate filter for PS Poll frames. + */ + __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); + /* * This device requires firmware. */ -- cgit v1.2.3-18-g5258 From af6a3fc7e728eb4cd14653c8cfc1ee81432cfd5d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sat, 8 Aug 2009 21:55:16 -0400 Subject: ath9k: Fix regression on receiving PS poll frames In the the patch: ath9k: use new FIF_PSPOLL configure filter I forgot to add the new FIF_PSPOLL to the supported mask. Without this we mask out the FIF_PSPOLL flag therefore we'd ignore it from mac80211. Cc: Jouni Malinen Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a9e43f7a23f..efe2e856397 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2380,6 +2380,7 @@ skip_chan_change: (FIF_PROMISC_IN_BSS | \ FIF_ALLMULTI | \ FIF_CONTROL | \ + FIF_PSPOLL | \ FIF_OTHER_BSS | \ FIF_BCN_PRBRESP_PROMISC | \ FIF_FCSFAIL) -- cgit v1.2.3-18-g5258 From 3ecee182d68621d1f9a813f15153883ca221dd0b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 9 Aug 2009 17:57:30 +0200 Subject: rtl818x: Add some documentation to the TX desc flags Add some TX desc flags docs. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl818x.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtl818x/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h index 34a5555cc19..562222e6cf1 100644 --- a/drivers/net/wireless/rtl818x/rtl818x.h +++ b/drivers/net/wireless/rtl818x/rtl818x.h @@ -194,8 +194,18 @@ struct rtl818x_rf_ops { void (*conf_erp)(struct ieee80211_hw *, struct ieee80211_bss_conf *); }; -/* Tx/Rx flags are common between RTL818X chips */ - +/** + * enum rtl818x_tx_desc_flags - Tx/Rx flags are common between RTL818X chips + * + * @RTL818X_TX_DESC_FLAG_NO_ENC: Disable hardware based encryption. + * @RTL818X_TX_DESC_FLAG_TX_OK: TX frame was ACKed. + * @RTL818X_TX_DESC_FLAG_SPLCP: Use short preamble. + * @RTL818X_TX_DESC_FLAG_MOREFRAG: More fragments follow. + * @RTL818X_TX_DESC_FLAG_CTS: Use CTS-to-self protection. + * @RTL818X_TX_DESC_FLAG_RTS: Use RTS/CTS protection. + * @RTL818X_TX_DESC_FLAG_LS: Last segment of the frame. + * @RTL818X_TX_DESC_FLAG_FS: First segment of the frame. + */ enum rtl818x_tx_desc_flags { RTL818X_TX_DESC_FLAG_NO_ENC = (1 << 15), RTL818X_TX_DESC_FLAG_TX_OK = (1 << 15), -- cgit v1.2.3-18-g5258 From 3281d95d0535909e28ff16c38a678102e10f0312 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Sun, 9 Aug 2009 20:15:09 +0200 Subject: b43: LP-PHY: Implement STX synchronization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The v2+ radio init (B2063) is now complete, modulo BCM4325 support. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 57 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index ed3a5288613..e68644d9502 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -346,9 +346,60 @@ static void lpphy_2063_init(struct b43_wldev *dev) b43_radio_write(dev, B2063_PA_SP2, 0x18); } +struct lpphy_stx_table_entry { + u16 phy_offset; + u16 phy_shift; + u16 rf_addr; + u16 rf_shift; + u16 mask; +}; + +static const struct lpphy_stx_table_entry lpphy_stx_table[] = { + { .phy_offset = 2, .phy_shift = 6, .rf_addr = 0x3d, .rf_shift = 3, .mask = 0x01, }, + { .phy_offset = 1, .phy_shift = 12, .rf_addr = 0x4c, .rf_shift = 1, .mask = 0x01, }, + { .phy_offset = 1, .phy_shift = 8, .rf_addr = 0x50, .rf_shift = 0, .mask = 0x7f, }, + { .phy_offset = 0, .phy_shift = 8, .rf_addr = 0x44, .rf_shift = 0, .mask = 0xff, }, + { .phy_offset = 1, .phy_shift = 0, .rf_addr = 0x4a, .rf_shift = 0, .mask = 0xff, }, + { .phy_offset = 0, .phy_shift = 4, .rf_addr = 0x4d, .rf_shift = 0, .mask = 0xff, }, + { .phy_offset = 1, .phy_shift = 4, .rf_addr = 0x4e, .rf_shift = 0, .mask = 0xff, }, + { .phy_offset = 0, .phy_shift = 12, .rf_addr = 0x4f, .rf_shift = 0, .mask = 0x0f, }, + { .phy_offset = 1, .phy_shift = 0, .rf_addr = 0x4f, .rf_shift = 4, .mask = 0x0f, }, + { .phy_offset = 3, .phy_shift = 0, .rf_addr = 0x49, .rf_shift = 0, .mask = 0x0f, }, + { .phy_offset = 4, .phy_shift = 3, .rf_addr = 0x46, .rf_shift = 4, .mask = 0x07, }, + { .phy_offset = 3, .phy_shift = 15, .rf_addr = 0x46, .rf_shift = 0, .mask = 0x01, }, + { .phy_offset = 4, .phy_shift = 0, .rf_addr = 0x46, .rf_shift = 1, .mask = 0x07, }, + { .phy_offset = 3, .phy_shift = 8, .rf_addr = 0x48, .rf_shift = 4, .mask = 0x07, }, + { .phy_offset = 3, .phy_shift = 11, .rf_addr = 0x48, .rf_shift = 0, .mask = 0x0f, }, + { .phy_offset = 3, .phy_shift = 4, .rf_addr = 0x49, .rf_shift = 4, .mask = 0x0f, }, + { .phy_offset = 2, .phy_shift = 15, .rf_addr = 0x45, .rf_shift = 0, .mask = 0x01, }, + { .phy_offset = 5, .phy_shift = 13, .rf_addr = 0x52, .rf_shift = 4, .mask = 0x07, }, + { .phy_offset = 6, .phy_shift = 0, .rf_addr = 0x52, .rf_shift = 7, .mask = 0x01, }, + { .phy_offset = 5, .phy_shift = 3, .rf_addr = 0x41, .rf_shift = 5, .mask = 0x07, }, + { .phy_offset = 5, .phy_shift = 6, .rf_addr = 0x41, .rf_shift = 0, .mask = 0x0f, }, + { .phy_offset = 5, .phy_shift = 10, .rf_addr = 0x42, .rf_shift = 5, .mask = 0x07, }, + { .phy_offset = 4, .phy_shift = 15, .rf_addr = 0x42, .rf_shift = 0, .mask = 0x01, }, + { .phy_offset = 5, .phy_shift = 0, .rf_addr = 0x42, .rf_shift = 1, .mask = 0x07, }, + { .phy_offset = 4, .phy_shift = 11, .rf_addr = 0x43, .rf_shift = 4, .mask = 0x0f, }, + { .phy_offset = 4, .phy_shift = 7, .rf_addr = 0x43, .rf_shift = 0, .mask = 0x0f, }, + { .phy_offset = 4, .phy_shift = 6, .rf_addr = 0x45, .rf_shift = 1, .mask = 0x01, }, + { .phy_offset = 2, .phy_shift = 7, .rf_addr = 0x40, .rf_shift = 4, .mask = 0x0f, }, + { .phy_offset = 2, .phy_shift = 11, .rf_addr = 0x40, .rf_shift = 0, .mask = 0x0f, }, +}; + static void lpphy_sync_stx(struct b43_wldev *dev) { - //TODO + const struct lpphy_stx_table_entry *e; + unsigned int i; + u16 tmp; + + for (i = 0; i < ARRAY_SIZE(lpphy_stx_table); i++) { + e = &lpphy_stx_table[i]; + tmp = b43_radio_read(dev, e->rf_addr); + tmp >>= e->rf_shift; + tmp <<= e->phy_shift; + b43_phy_maskset(dev, B43_PHY_OFDM(0xF2 + e->phy_offset), + e->mask << e->phy_shift, tmp); + } } static void lpphy_radio_init(struct b43_wldev *dev) @@ -366,7 +417,9 @@ static void lpphy_radio_init(struct b43_wldev *dev) lpphy_sync_stx(dev); b43_phy_write(dev, B43_PHY_OFDM(0xF0), 0x5F80); b43_phy_write(dev, B43_PHY_OFDM(0xF1), 0); - //TODO Do something on the backplane + if (dev->dev->bus->chip_id == 0x4325) { + // TODO SSB PMU recalibration + } } } -- cgit v1.2.3-18-g5258 From d6756d0dc220c3d12e2c4c06ca97d1dbcb5edf4e Mon Sep 17 00:00:00 2001 From: Igor Perminov Date: Mon, 10 Aug 2009 00:58:54 +0200 Subject: rt2x00: Fix beacon de-synchronization while update beacon When beacon is being updated to refresh TIM (AP mode), beacon frames are de-synchronizing (i.e. two neighbor beacon frames - before and after update - are being transmitted with a wrong time interval). That is because xxx_write_beacon should disable beacon generation only while beacon data are being uploaded to the device, but it should not disable the beacon clock. Signed-off-by: Igor Perminov Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 2 -- drivers/net/wireless/rt2x00/rt2500pci.c | 2 -- drivers/net/wireless/rt2x00/rt2500usb.c | 15 ++++++++------- drivers/net/wireless/rt2x00/rt2800usb.c | 2 -- drivers/net/wireless/rt2x00/rt61pci.c | 2 -- drivers/net/wireless/rt2x00/rt73usb.c | 2 -- 6 files changed, 8 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 30185ad28d9..164df9347a2 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1069,8 +1069,6 @@ static void rt2400pci_write_beacon(struct queue_entry *entry) * otherwise we might be sending out invalid data. */ rt2x00pci_register_read(rt2x00dev, CSR14, ®); - rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); - rt2x00_set_field32(®, CSR14_TBCN, 0); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); rt2x00pci_register_write(rt2x00dev, CSR14, reg); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 3b3171578b1..4186582f277 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1227,8 +1227,6 @@ static void rt2500pci_write_beacon(struct queue_entry *entry) * otherwise we might be sending out invalid data. */ rt2x00pci_register_read(rt2x00dev, CSR14, ®); - rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); - rt2x00_set_field32(®, CSR14_TBCN, 0); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); rt2x00pci_register_write(rt2x00dev, CSR14, reg); diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index de48c5c68ef..09a589432da 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1238,8 +1238,6 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) * otherwise we might be sending out invalid data. */ rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); - rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 0); - rt2x00_set_field16(®, TXRX_CSR19_TBCN, 0); rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); @@ -1287,7 +1285,7 @@ static int rt2500usb_get_tx_data_len(struct queue_entry *entry) static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, const enum data_queue_qid queue) { - u16 reg; + u16 reg, reg0; if (queue != QID_BEACON) { rt2x00usb_kick_tx_queue(rt2x00dev, queue); @@ -1298,16 +1296,19 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, if (!rt2x00_get_field16(reg, TXRX_CSR19_BEACON_GEN)) { rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1); + reg0 = reg; rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 1); /* * Beacon generation will fail initially. - * To prevent this we need to register the TXRX_CSR19 - * register several times. + * To prevent this we need to change the TXRX_CSR19 + * register several times (reg0 is the same as reg + * except for TXRX_CSR19_BEACON_GEN, which is 0 in reg0 + * and 1 in reg). */ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); - rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0); rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); - rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0); rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); } } diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 2de0389d823..3856f06fdca 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -2050,8 +2050,6 @@ static void rt2800usb_write_beacon(struct queue_entry *entry) * otherwise we might be sending out invalid data. */ rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); - rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); - rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 3447997fc71..f4b4b86da4d 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1855,8 +1855,6 @@ static void rt61pci_write_beacon(struct queue_entry *entry) * otherwise we might be sending out invalid data. */ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); - rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 4b9955b1c70..4d94b65943f 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1527,8 +1527,6 @@ static void rt73usb_write_beacon(struct queue_entry *entry) * otherwise we might be sending out invalid data. */ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); - rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); -- cgit v1.2.3-18-g5258 From c38e7a9348f725be0ea2493454db9e6d44fb7e0c Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Mon, 10 Aug 2009 03:26:55 +0300 Subject: ath5k: Check EEPROM before tweaking SERDES * Read PCI-E infos offset from EEPROM and if it points to serdes section (0x40), enable serdes programming (further tweaking of serdes values during attach). This follows Legacy and Sam's HAL sources. Signed-off-by: Nick Kossifidis Acked-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/attach.c | 56 ++++++++++++++++++++------------- drivers/net/wireless/ath/ath5k/eeprom.c | 10 ++++++ drivers/net/wireless/ath/ath5k/eeprom.h | 4 +++ 3 files changed, 48 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 9a84d9410b2..626306592cf 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -252,28 +252,6 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) goto err_free; } - /* - * Write PCI-E power save settings - */ - if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) { - ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES); - ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES); - /* Shut off RX when elecidle is asserted */ - ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES); - ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES); - /* TODO: EEPROM work */ - ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES); - /* Shut off PLL and CLKREQ active in L1 */ - ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES); - /* Preserce other settings */ - ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES); - ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES); - ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES); - /* Reset SERDES to load new settings */ - ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET); - mdelay(1); - } - /* * POST */ @@ -295,6 +273,40 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) goto err_free; } + /* + * Write PCI-E power save settings + */ + if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) { + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + + ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES); + ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES); + + /* Shut off RX when elecidle is asserted */ + ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES); + ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES); + + /* If serdes programing is enabled, increase PCI-E + * tx power for systems with long trace from host + * to minicard connector. */ + if (ee->ee_serdes) + ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES); + else + ath5k_hw_reg_write(ah, 0xf6800579, AR5K_PCIE_SERDES); + + /* Shut off PLL and CLKREQ active in L1 */ + ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES); + + /* Preserve other settings */ + ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES); + ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES); + ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES); + + /* Reset SERDES to load new settings */ + ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET); + mdelay(1); + } + /* Get misc capabilities */ ret = ath5k_hw_set_capabilities(ah); if (ret) { diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index c56b494d417..8af477dd6fc 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -167,6 +167,16 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah) ee->ee_rfkill_pin = (u8) AR5K_REG_MS(val, AR5K_EEPROM_RFKILL_GPIO_SEL); ee->ee_rfkill_pol = val & AR5K_EEPROM_RFKILL_POLARITY ? true : false; + /* Check if PCIE_OFFSET points to PCIE_SERDES_SECTION + * and enable serdes programming if needed. + * + * XXX: Serdes values seem to be fixed so + * no need to read them here, we write them + * during ath5k_hw_attach */ + AR5K_EEPROM_READ(AR5K_EEPROM_PCIE_OFFSET, val); + ee->ee_serdes = (val == AR5K_EEPROM_PCIE_SERDES_SECTION) ? + true : false; + return 0; } diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h index 64be73a5eda..0123f3521a0 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.h +++ b/drivers/net/wireless/ath/ath5k/eeprom.h @@ -19,6 +19,9 @@ /* * Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE) */ +#define AR5K_EEPROM_PCIE_OFFSET 0x02 /* Contains offset to PCI-E infos */ +#define AR5K_EEPROM_PCIE_SERDES_SECTION 0x40 /* PCIE_OFFSET points here when + * SERDES infos are present */ #define AR5K_EEPROM_MAGIC 0x003d /* EEPROM Magic number */ #define AR5K_EEPROM_MAGIC_VALUE 0x5aa5 /* Default - found on EEPROM */ #define AR5K_EEPROM_MAGIC_5212 0x0000145c /* 5212 */ @@ -391,6 +394,7 @@ struct ath5k_eeprom_info { u8 ee_rfkill_pin; bool ee_rfkill_pol; bool ee_is_hb63; + bool ee_serdes; u16 ee_misc0; u16 ee_misc1; u16 ee_misc2; -- cgit v1.2.3-18-g5258 From d1cb0bdac180a4afdd3c001acb2618d2a62d9abe Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Mon, 10 Aug 2009 03:27:59 +0300 Subject: ath5k: Linear PCDAC code fixes * Set correct xpd curve indices for high/low gain curves during rfbuffer setup on RF5112B with both calibration curves available. * Don't return zero min power when we have the same pcdac value twice because it breaks interpolation. Instead return the right x barrier as we do when we have equal power levels for 2 different pcdac values. Signed-off-by: Nick Kossifidis Acked-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/phy.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 2075ba99396..6afba98f6ad 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -740,13 +740,22 @@ int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, AR5K_RF_XPD_GAIN, true); } else { - /* TODO: Set high and low gain bits */ - ath5k_hw_rfb_op(ah, rf_regs, - ee->ee_x_gain[ee_mode], + u8 *pdg_curve_to_idx = ee->ee_pdc_to_idx[ee_mode]; + if (ee->ee_pd_gains[ee_mode] > 1) { + ath5k_hw_rfb_op(ah, rf_regs, + pdg_curve_to_idx[0], AR5K_RF_PD_GAIN_LO, true); - ath5k_hw_rfb_op(ah, rf_regs, - ee->ee_x_gain[ee_mode], + ath5k_hw_rfb_op(ah, rf_regs, + pdg_curve_to_idx[1], AR5K_RF_PD_GAIN_HI, true); + } else { + ath5k_hw_rfb_op(ah, rf_regs, + pdg_curve_to_idx[0], + AR5K_RF_PD_GAIN_LO, true); + ath5k_hw_rfb_op(ah, rf_regs, + pdg_curve_to_idx[0], + AR5K_RF_PD_GAIN_HI, true); + } /* Lower synth voltage on Rev 2 */ ath5k_hw_rfb_op(ah, rf_regs, 2, @@ -1896,8 +1905,9 @@ ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR, s16 min_pwrL, min_pwrR; s16 pwr_i; - if (WARN_ON(stepL[0] == stepL[1] || stepR[0] == stepR[1])) - return 0; + /* Some vendors write the same pcdac value twice !!! */ + if (stepL[0] == stepL[1] || stepR[0] == stepR[1]) + return max(pwrL[0], pwrR[0]); if (pwrL[0] == pwrL[1]) min_pwrL = pwrL[0]; -- cgit v1.2.3-18-g5258 From edd7fc7003f31da48d06e215a93ea966a22c2a03 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Mon, 10 Aug 2009 03:29:02 +0300 Subject: ath5k: Wakeup fixes * Don't put chip to full sleep because there are problems during wakeup. Instead hold MAC/Baseband on warm reset state via a new function ath5k_hw_on_hold. * Minor cleanups Signed-off-by: Nick Kossifidis Tested-by: Ben Greear Tested-by: Johannes Stezenbach Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 1 + drivers/net/wireless/ath/ath5k/attach.c | 2 +- drivers/net/wireless/ath/ath5k/base.c | 44 ++++----- drivers/net/wireless/ath/ath5k/reset.c | 155 +++++++++++++++++++++++--------- 4 files changed, 140 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 91375113916..1047a6cb1d9 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1157,6 +1157,7 @@ extern void ath5k_unregister_leds(struct ath5k_softc *sc); /* Reset Functions */ extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial); +extern int ath5k_hw_on_hold(struct ath5k_hw *ah); extern int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel); /* Power management functions */ extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration); diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 626306592cf..238eeb7e166 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -145,7 +145,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) goto err_free; /* Bring device out of sleep and reset it's units */ - ret = ath5k_hw_nic_wakeup(ah, CHANNEL_B, true); + ret = ath5k_hw_nic_wakeup(ah, 0, true); if (ret) goto err_free; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 5d5028538ac..0370cba8356 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2446,27 +2446,29 @@ ath5k_stop_hw(struct ath5k_softc *sc) ret = ath5k_stop_locked(sc); if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) { /* - * Set the chip in full sleep mode. Note that we are - * careful to do this only when bringing the interface - * completely to a stop. When the chip is in this state - * it must be carefully woken up or references to - * registers in the PCI clock domain may freeze the bus - * (and system). This varies by chip and is mostly an - * issue with newer parts that go to sleep more quickly. - */ - if (sc->ah->ah_mac_srev >= 0x78) { - /* - * XXX - * don't put newer MAC revisions > 7.8 to sleep because - * of the above mentioned problems - */ - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mac version > 7.8, " - "not putting device to sleep\n"); - } else { - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, - "putting device to full sleep\n"); - ath5k_hw_set_power(sc->ah, AR5K_PM_FULL_SLEEP, true, 0); - } + * Don't set the card in full sleep mode! + * + * a) When the device is in this state it must be carefully + * woken up or references to registers in the PCI clock + * domain may freeze the bus (and system). This varies + * by chip and is mostly an issue with newer parts + * (madwifi sources mentioned srev >= 0x78) that go to + * sleep more quickly. + * + * b) On older chips full sleep results a weird behaviour + * during wakeup. I tested various cards with srev < 0x78 + * and they don't wake up after module reload, a second + * module reload is needed to bring the card up again. + * + * Until we figure out what's going on don't enable + * full chip reset on any chip (this is what Legacy HAL + * and Sam's HAL do anyway). Instead Perform a full reset + * on the device (same as initial state after attach) and + * leave it idle (keep MAC/BB on warm reset) */ + ret = ath5k_hw_on_hold(sc->ah); + + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, + "putting device to sleep\n"); } ath5k_txbuf_free(sc, sc->bbuf); diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 86733fdb477..34e13c70084 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -258,29 +258,35 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, if (!set_chip) goto commit; - /* Preserve sleep duration */ data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL); + + /* If card is down we 'll get 0xffff... so we + * need to clean this up before we write the register + */ if (data & 0xffc00000) data = 0; else - data = data & 0xfffcffff; + /* Preserve sleep duration etc */ + data = data & ~AR5K_SLEEP_CTL_SLE; - ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL); + ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE, + AR5K_SLEEP_CTL); udelay(15); - for (i = 50; i > 0; i--) { + for (i = 200; i > 0; i--) { /* Check if the chip did wake up */ if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) & AR5K_PCICFG_SPWR_DN) == 0) break; /* Wait a bit and retry */ - udelay(200); - ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL); + udelay(50); + ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE, + AR5K_SLEEP_CTL); } /* Fail if the chip didn't wake up */ - if (i <= 0) + if (i == 0) return -EIO; break; @@ -295,6 +301,64 @@ commit: return 0; } +/* + * Put device on hold + * + * Put MAC and Baseband on warm reset and + * keep that state (don't clean sleep control + * register). After this MAC and Baseband are + * disabled and a full reset is needed to come + * back. This way we save as much power as possible + * without puting the card on full sleep. + */ +int ath5k_hw_on_hold(struct ath5k_hw *ah) +{ + struct pci_dev *pdev = ah->ah_sc->pdev; + u32 bus_flags; + int ret; + + /* Make sure device is awake */ + ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); + if (ret) { + ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n"); + return ret; + } + + /* + * Put chipset on warm reset... + * + * Note: puting PCI core on warm reset on PCI-E cards + * results card to hang and always return 0xffff... so + * we ingore that flag for PCI-E cards. On PCI cards + * this flag gets cleared after 64 PCI clocks. + */ + bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI; + + if (ah->ah_version == AR5K_AR5210) { + ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | + AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA | + AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI); + mdelay(2); + } else { + ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | + AR5K_RESET_CTL_BASEBAND | bus_flags); + } + + if (ret) { + ATH5K_ERR(ah->ah_sc, "failed to put device on warm reset\n"); + return -EIO; + } + + /* ...wakeup again!*/ + ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); + if (ret) { + ATH5K_ERR(ah->ah_sc, "failed to put device on hold\n"); + return ret; + } + + return ret; +} + /* * Bring up MAC + PHY Chips and program PLL * TODO: Half/Quarter rate support @@ -318,6 +382,50 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) return ret; } + /* + * Put chipset on warm reset... + * + * Note: puting PCI core on warm reset on PCI-E cards + * results card to hang and always return 0xffff... so + * we ingore that flag for PCI-E cards. On PCI cards + * this flag gets cleared after 64 PCI clocks. + */ + bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI; + + if (ah->ah_version == AR5K_AR5210) { + ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | + AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA | + AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI); + mdelay(2); + } else { + ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | + AR5K_RESET_CTL_BASEBAND | bus_flags); + } + + if (ret) { + ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n"); + return -EIO; + } + + /* ...wakeup again!...*/ + ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); + if (ret) { + ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n"); + return ret; + } + + /* ...clear reset control register and pull device out of + * warm reset */ + if (ath5k_hw_nic_reset(ah, 0)) { + ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n"); + return -EIO; + } + + /* On initialization skip PLL programming since we don't have + * a channel / mode set yet */ + if (initial) + return 0; + if (ah->ah_version != AR5K_AR5210) { /* * Get channel mode flags @@ -383,39 +491,6 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) AR5K_PHY_TURBO); } - /* reseting PCI on PCI-E cards results card to hang - * and always return 0xffff... so we ingore that flag - * for PCI-E cards */ - bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI; - - /* Reset chipset */ - if (ah->ah_version == AR5K_AR5210) { - ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | - AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA | - AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI); - mdelay(2); - } else { - ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU | - AR5K_RESET_CTL_BASEBAND | bus_flags); - } - if (ret) { - ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n"); - return -EIO; - } - - /* ...wakeup again!*/ - ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); - if (ret) { - ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n"); - return ret; - } - - /* ...final warm reset */ - if (ath5k_hw_nic_reset(ah, 0)) { - ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n"); - return -EIO; - } - if (ah->ah_version != AR5K_AR5210) { /* ...update PLL if needed */ -- cgit v1.2.3-18-g5258 From b55a5de114dcdc03f2f18c3bd98bbabb13ee53ef Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Mon, 10 Aug 2009 03:30:32 +0300 Subject: ath5k: Preserve pcicfg bits during attach * During attach preserve pcicfg bits when enabling pci core sw retry fix. Signed-off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/attach.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 238eeb7e166..65d438b59f6 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -261,7 +261,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) /* Enable pci core retry fix on Hainan (5213A) and later chips */ if (srev >= AR5K_SREV_AR5213A) - ath5k_hw_reg_write(ah, AR5K_PCICFG_RETRY_FIX, AR5K_PCICFG); + AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_RETRY_FIX); /* * Get card capabilities, calibration values etc -- cgit v1.2.3-18-g5258 From 6e220662bf9a2ba284e88a8c8867340c9f6da27e Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Mon, 10 Aug 2009 03:31:31 +0300 Subject: ath5k: Use SWI to trigger calibration * Get rid of calibration timer, instead use a software interrupt to schedule the calibration tasklet. a) We don't need a timer for this, there is no need for accuracy even with round_jiffies i think this is a waste of resources. Also we don't need to run calibration if we are idle (no interrupts). b) When we add ANI support we 'll just extend the poll function and calibration tasklet and handle all periodic phy calibration on one place (much cleaner). c) Having calibration on a tasklet is better since during calibration we can't transmit or receive (antennas are detached to measure noise floor), previously calibration could run in parallel with tx/rx and interfere (packet loss). v2: kill tasklet on stop_hw, stop/wake queues v3: use time_is_before_eq_jiffies to compare timestamp with current time Signed-off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 16 +++++++++++++++ drivers/net/wireless/ath/ath5k/base.c | 36 ++++++++++++++++++++++++---------- drivers/net/wireless/ath/ath5k/base.h | 3 ++- drivers/net/wireless/ath/ath5k/phy.c | 23 ++++++++++++++++++++++ 4 files changed, 67 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 1047a6cb1d9..c09402eea7f 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -919,6 +919,12 @@ enum ath5k_int { AR5K_INT_NOCARD = 0xffffffff }; +/* Software interrupts used for calibration */ +enum ath5k_software_interrupt { + AR5K_SWI_FULL_CALIBRATION = 0x01, + AR5K_SWI_SHORT_CALIBRATION = 0x02, +}; + /* * Power management */ @@ -1123,6 +1129,15 @@ struct ath5k_hw { /* noise floor from last periodic calibration */ s32 ah_noise_floor; + /* Calibration timestamp */ + unsigned long ah_cal_tstamp; + + /* Calibration interval (secs) */ + u8 ah_cal_intval; + + /* Software interrupt mask */ + u8 ah_swi_mask; + /* * Function pointers */ @@ -1276,6 +1291,7 @@ extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *chann /* PHY calibration */ extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel); extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq); +extern void ath5k_hw_calibration_poll(struct ath5k_hw *ah); /* Spur mitigation */ bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, struct ieee80211_channel *channel); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 0370cba8356..acbcfc2a9f7 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -59,7 +59,7 @@ #include "reg.h" #include "debug.h" -static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ +static u8 ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); @@ -376,7 +376,7 @@ static int ath5k_stop_hw(struct ath5k_softc *sc); static irqreturn_t ath5k_intr(int irq, void *dev_id); static void ath5k_tasklet_reset(unsigned long data); -static void ath5k_calibrate(unsigned long data); +static void ath5k_tasklet_calibrate(unsigned long data); /* * Module init/exit functions @@ -799,8 +799,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc); tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc); tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); + tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc); tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc); - setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc); ret = ath5k_eeprom_read_mac(ah, mac); if (ret) { @@ -2364,7 +2364,7 @@ ath5k_init(struct ath5k_softc *sc) sc->curband = &sc->sbands[sc->curchan->band]; sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | - AR5K_INT_FATAL | AR5K_INT_GLOBAL; + AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_SWI; ret = ath5k_reset(sc, NULL); if (ret) goto done; @@ -2381,8 +2381,8 @@ ath5k_init(struct ath5k_softc *sc) /* Set ack to be sent at low bit-rates */ ath5k_hw_set_ack_bitrate_high(ah, false); - mod_timer(&sc->calib_tim, round_jiffies(jiffies + - msecs_to_jiffies(ath5k_calinterval * 1000))); + /* Set PHY calibration inteval */ + ah->ah_cal_intval = ath5k_calinterval; ret = 0; done: @@ -2475,10 +2475,10 @@ ath5k_stop_hw(struct ath5k_softc *sc) mmiowb(); mutex_unlock(&sc->lock); - del_timer_sync(&sc->calib_tim); tasklet_kill(&sc->rxtq); tasklet_kill(&sc->txtq); tasklet_kill(&sc->restq); + tasklet_kill(&sc->calib); tasklet_kill(&sc->beacontq); ath5k_rfkill_hw_stop(sc->ah); @@ -2534,6 +2534,9 @@ ath5k_intr(int irq, void *dev_id) if (status & AR5K_INT_BMISS) { /* TODO */ } + if (status & AR5K_INT_SWI) { + tasklet_schedule(&sc->calib); + } if (status & AR5K_INT_MIB) { /* * These stats are also used for ANI i think @@ -2550,6 +2553,8 @@ ath5k_intr(int irq, void *dev_id) if (unlikely(!counter)) ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); + ath5k_hw_calibration_poll(ah); + return IRQ_HANDLED; } @@ -2566,11 +2571,19 @@ ath5k_tasklet_reset(unsigned long data) * for temperature/environment changes. */ static void -ath5k_calibrate(unsigned long data) +ath5k_tasklet_calibrate(unsigned long data) { struct ath5k_softc *sc = (void *)data; struct ath5k_hw *ah = sc->ah; + /* Only full calibration for now */ + if (ah->ah_swi_mask != AR5K_SWI_FULL_CALIBRATION) + return; + + /* Stop queues so that calibration + * doesn't interfere with tx */ + ieee80211_stop_queues(sc->hw); + ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n", ieee80211_frequency_to_channel(sc->curchan->center_freq), sc->curchan->hw_value); @@ -2588,8 +2601,11 @@ ath5k_calibrate(unsigned long data) ieee80211_frequency_to_channel( sc->curchan->center_freq)); - mod_timer(&sc->calib_tim, round_jiffies(jiffies + - msecs_to_jiffies(ath5k_calinterval * 1000))); + ah->ah_swi_mask = 0; + + /* Wake queues */ + ieee80211_wake_queues(sc->hw); + } diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 778e422946a..667bd9dc190 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -177,6 +177,8 @@ struct ath5k_softc { struct ath5k_rfkill rf_kill; + struct tasklet_struct calib; /* calibration tasklet */ + spinlock_t block; /* protects beacon */ struct tasklet_struct beacontq; /* beacon intr tasklet */ struct ath5k_buf *bbuf; /* beacon buffer */ @@ -187,7 +189,6 @@ struct ath5k_softc { unsigned int nexttbtt; /* next beacon time in TU */ struct ath5k_txq *cabq; /* content after beacon */ - struct timer_list calib_tim; /* calibration timer */ int power_level; /* Requested tx power in dbm */ bool assoc; /* assocate state */ bool enable_beacon; /* true if beacons are on */ diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 6afba98f6ad..298fcf01522 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1104,6 +1104,29 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) PHY calibration \*****************/ +void +ath5k_hw_calibration_poll(struct ath5k_hw *ah) +{ + /* Calibration interval in jiffies */ + unsigned long cal_intval; + + cal_intval = msecs_to_jiffies(ah->ah_cal_intval * 1000); + + /* Initialize timestamp if needed */ + if (!ah->ah_cal_tstamp) + ah->ah_cal_tstamp = jiffies; + + /* For now we always do full calibration + * Mark software interrupt mask and fire software + * interrupt (bit gets auto-cleared) */ + if (time_is_before_eq_jiffies(ah->ah_cal_tstamp + cal_intval)) { + ah->ah_cal_tstamp = jiffies; + ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION; + AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); + } + +} + /** * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration * -- cgit v1.2.3-18-g5258 From c65d6fbf91517a0a955de7ce029940bc63ea8203 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Mon, 10 Aug 2009 20:39:47 +0200 Subject: b43: Implement LP-PHY baseband table initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement LP-PHY baseband table init for all revisions. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 41 +- drivers/net/wireless/b43/tables_lpphy.c | 1716 +++++++++++++++++++++++++++++++ drivers/net/wireless/b43/tables_lpphy.h | 3 + 3 files changed, 1756 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index e68644d9502..79039c3f60c 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -59,9 +59,43 @@ static void b43_lpphy_op_free(struct b43_wldev *dev) dev->phy.lp = NULL; } +static void lpphy_adjust_gain_table(struct b43_wldev *dev) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + u32 freq = dev->wl->hw->conf.channel->center_freq; + u16 temp[3]; + u16 isolation; + + B43_WARN_ON(dev->phy.rev >= 2); + + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + isolation = lpphy->tx_isolation_med_band; + else if (freq <= 5320) + isolation = lpphy->tx_isolation_low_band; + else if (freq <= 5700) + isolation = lpphy->tx_isolation_med_band; + else + isolation = lpphy->tx_isolation_hi_band; + + temp[0] = ((isolation - 26) / 12) << 12; + temp[1] = temp[0] + 0x1000; + temp[2] = temp[0] + 0x2000; + + b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), 3, temp); + b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), 3, temp); +} + static void lpphy_table_init(struct b43_wldev *dev) { - //TODO + if (dev->phy.rev < 2) + lpphy_rev0_1_table_init(dev); + else + lpphy_rev2plus_table_init(dev); + + lpphy_init_tx_gain_table(dev); + + if (dev->phy.rev < 2) + lpphy_adjust_gain_table(dev); } static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) @@ -596,13 +630,13 @@ static void lpphy_tx_pctl_init(struct b43_wldev *dev) static int b43_lpphy_op_init(struct b43_wldev *dev) { /* TODO: band SPROM */ - /* TODO: tables init */ lpphy_baseband_init(dev); lpphy_radio_init(dev); //TODO calibrate RC //TODO set channel lpphy_tx_pctl_init(dev); - //TODO full calib + lpphy_calibration(dev); + //TODO ACI init return 0; } @@ -680,7 +714,6 @@ static enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev, return B43_TXPWR_RES_DONE; } - const struct b43_phy_operations b43_phyops_lp = { .allocate = b43_lpphy_op_allocate, .free = b43_lpphy_op_free, diff --git a/drivers/net/wireless/b43/tables_lpphy.c b/drivers/net/wireless/b43/tables_lpphy.c index cadfe81fd09..b056811a170 100644 --- a/drivers/net/wireless/b43/tables_lpphy.c +++ b/drivers/net/wireless/b43/tables_lpphy.c @@ -710,3 +710,1719 @@ void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset, offset++; } } + +static const u8 lpphy_min_sig_sq_table[] = { + 0xde, 0xdc, 0xda, 0xd8, 0xd6, 0xd4, 0xd2, 0xcf, 0xcd, + 0xca, 0xc7, 0xc4, 0xc1, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0x00, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xc1, 0xc4, 0xc7, 0xca, 0xcd, + 0xcf, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, +}; + +static const u16 lpphy_rev01_noise_scale_table[] = { + 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, + 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa400, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, + 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0x00a4, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4c00, 0x2d36, + 0x0000, 0x0000, 0x4c00, 0x2d36, +}; + +static const u16 lpphy_rev2plus_noise_scale_table[] = { + 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, + 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, + 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x0000, + 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, + 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, + 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, + 0x00a4, +}; + +static const u16 lpphy_crs_gain_nft_table[] = { + 0x0366, 0x036a, 0x036f, 0x0364, 0x0367, 0x036d, 0x0374, 0x037f, 0x036f, + 0x037b, 0x038a, 0x0378, 0x0367, 0x036d, 0x0375, 0x0381, 0x0374, 0x0381, + 0x0392, 0x03a9, 0x03c4, 0x03e1, 0x0001, 0x001f, 0x0040, 0x005e, 0x007f, + 0x009e, 0x00bd, 0x00dd, 0x00fd, 0x011d, 0x013d, +}; + +static const u16 lpphy_rev01_filter_control_table[] = { + 0xa0fc, 0x10fc, 0x10db, 0x20b7, 0xff93, 0x10bf, 0x109b, 0x2077, 0xff53, + 0x0127, +}; + +static const u32 lpphy_rev2plus_filter_control_table[] = { + 0x000141fc, 0x000021fc, 0x000021b7, 0x0000416f, 0x0001ff27, 0x0000217f, + 0x00002137, 0x000040ef, 0x0001fea7, 0x0000024f, +}; + +static const u32 lpphy_rev01_ps_control_table[] = { + 0x00010000, 0x000000a0, 0x00040000, 0x00000048, 0x08080101, 0x00000080, + 0x08080101, 0x00000040, 0x08080101, 0x000000c0, 0x08a81501, 0x000000c0, + 0x0fe8fd01, 0x000000c0, 0x08300105, 0x000000c0, 0x08080201, 0x000000c0, + 0x08280205, 0x000000c0, 0xe80802fe, 0x000000c7, 0x28080206, 0x000000c0, + 0x08080202, 0x000000c0, 0x0ba87602, 0x000000c0, 0x1068013d, 0x000000c0, + 0x10280105, 0x000000c0, 0x08880102, 0x000000c0, 0x08280106, 0x000000c0, + 0xe80801fd, 0x000000c7, 0xa8080115, 0x000000c0, +}; + +static const u32 lpphy_rev2plus_ps_control_table[] = { + 0x00e38e08, 0x00e08e38, 0x00000000, 0x00000000, 0x00000000, 0x00002080, + 0x00006180, 0x00003002, 0x00000040, 0x00002042, 0x00180047, 0x00080043, + 0x00000041, 0x000020c1, 0x00046006, 0x00042002, 0x00040000, 0x00002003, + 0x00180006, 0x00080002, +}; + +static const u8 lpphy_pll_fraction_table[] = { + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +}; + +static const u16 lpphy_iq_local_table[] = { + 0x0200, 0x0300, 0x0400, 0x0600, 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, + 0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0200, 0x0300, 0x0400, 0x0600, + 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, + 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, +}; + +static const u16 lpphy_ofdm_cck_gain_table[] = { + 0x5000, 0x6000, 0x7000, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001, 0x5001, + 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055, 0x2065, 0x2075, + 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d, 0x135d, 0x055d, 0x155d, + 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d, 0x755d, +}; + +static const u16 lpphy_gain_delta_table[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const u32 lpphy_tx_power_control_table[] = { + 0x00000050, 0x0000004f, 0x0000004e, 0x0000004d, 0x0000004c, 0x0000004b, + 0x0000004a, 0x00000049, 0x00000048, 0x00000047, 0x00000046, 0x00000045, + 0x00000044, 0x00000043, 0x00000042, 0x00000041, 0x00000040, 0x0000003f, + 0x0000003e, 0x0000003d, 0x0000003c, 0x0000003b, 0x0000003a, 0x00000039, + 0x00000038, 0x00000037, 0x00000036, 0x00000035, 0x00000034, 0x00000033, + 0x00000032, 0x00000031, 0x00000030, 0x0000002f, 0x0000002e, 0x0000002d, + 0x0000002c, 0x0000002b, 0x0000002a, 0x00000029, 0x00000028, 0x00000027, + 0x00000026, 0x00000025, 0x00000024, 0x00000023, 0x00000022, 0x00000021, + 0x00000020, 0x0000001f, 0x0000001e, 0x0000001d, 0x0000001c, 0x0000001b, + 0x0000001a, 0x00000019, 0x00000018, 0x00000017, 0x00000016, 0x00000015, + 0x00000014, 0x00000013, 0x00000012, 0x00000011, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x000075a0, 0x000075a0, 0x000075a1, 0x000075a1, 0x000075a2, 0x000075a2, + 0x000075a3, 0x000075a3, 0x000074b0, 0x000074b0, 0x000074b1, 0x000074b1, + 0x000074b2, 0x000074b2, 0x000074b3, 0x000074b3, 0x00006d20, 0x00006d20, + 0x00006d21, 0x00006d21, 0x00006d22, 0x00006d22, 0x00006d23, 0x00006d23, + 0x00004660, 0x00004660, 0x00004661, 0x00004661, 0x00004662, 0x00004662, + 0x00004663, 0x00004663, 0x00003e60, 0x00003e60, 0x00003e61, 0x00003e61, + 0x00003e62, 0x00003e62, 0x00003e63, 0x00003e63, 0x00003660, 0x00003660, + 0x00003661, 0x00003661, 0x00003662, 0x00003662, 0x00003663, 0x00003663, + 0x00002e60, 0x00002e60, 0x00002e61, 0x00002e61, 0x00002e62, 0x00002e62, + 0x00002e63, 0x00002e63, 0x00002660, 0x00002660, 0x00002661, 0x00002661, + 0x00002662, 0x00002662, 0x00002663, 0x00002663, 0x000025e0, 0x000025e0, + 0x000025e1, 0x000025e1, 0x000025e2, 0x000025e2, 0x000025e3, 0x000025e3, + 0x00001de0, 0x00001de0, 0x00001de1, 0x00001de1, 0x00001de2, 0x00001de2, + 0x00001de3, 0x00001de3, 0x00001d60, 0x00001d60, 0x00001d61, 0x00001d61, + 0x00001d62, 0x00001d62, 0x00001d63, 0x00001d63, 0x00001560, 0x00001560, + 0x00001561, 0x00001561, 0x00001562, 0x00001562, 0x00001563, 0x00001563, + 0x00000d60, 0x00000d60, 0x00000d61, 0x00000d61, 0x00000d62, 0x00000d62, + 0x00000d63, 0x00000d63, 0x00000ce0, 0x00000ce0, 0x00000ce1, 0x00000ce1, + 0x00000ce2, 0x00000ce2, 0x00000ce3, 0x00000ce3, 0x00000e10, 0x00000e10, + 0x00000e11, 0x00000e11, 0x00000e12, 0x00000e12, 0x00000e13, 0x00000e13, + 0x00000bf0, 0x00000bf0, 0x00000bf1, 0x00000bf1, 0x00000bf2, 0x00000bf2, + 0x00000bf3, 0x00000bf3, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000, + 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x000000ff, 0x000002fc, + 0x0000fa08, 0x00000305, 0x00000206, 0x00000304, 0x0000fb04, 0x0000fcff, + 0x000005fb, 0x0000fd01, 0x00000401, 0x00000006, 0x0000ff03, 0x000007fc, + 0x0000fc08, 0x00000203, 0x0000fffb, 0x00000600, 0x0000fa01, 0x0000fc03, + 0x0000fe06, 0x0000fe00, 0x00000102, 0x000007fd, 0x000004fb, 0x000006ff, + 0x000004fd, 0x0000fdfa, 0x000007fb, 0x0000fdfa, 0x0000fa06, 0x00000500, + 0x0000f902, 0x000007fa, 0x0000fafa, 0x00000500, 0x000007fa, 0x00000700, + 0x00000305, 0x000004ff, 0x00000801, 0x00000503, 0x000005f9, 0x00000404, + 0x0000fb08, 0x000005fd, 0x00000501, 0x00000405, 0x0000fb03, 0x000007fc, + 0x00000403, 0x00000303, 0x00000402, 0x0000faff, 0x0000fe05, 0x000005fd, + 0x0000fe01, 0x000007fa, 0x00000202, 0x00000504, 0x00000102, 0x000008fe, + 0x0000fa04, 0x0000fafc, 0x0000fe08, 0x000000f9, 0x000002fa, 0x000003fe, + 0x00000304, 0x000004f9, 0x00000100, 0x0000fd06, 0x000008fc, 0x00000701, + 0x00000504, 0x0000fdfe, 0x0000fdfc, 0x000003fe, 0x00000704, 0x000002fc, + 0x000004f9, 0x0000fdfd, 0x0000fa07, 0x00000205, 0x000003fd, 0x000005fb, + 0x000004f9, 0x00000804, 0x0000fc06, 0x0000fcf9, 0x00000100, 0x0000fe05, + 0x00000408, 0x0000fb02, 0x00000304, 0x000006fe, 0x000004fa, 0x00000305, + 0x000008fc, 0x00000102, 0x000001fd, 0x000004fc, 0x0000fe03, 0x00000701, + 0x000001fb, 0x000001f9, 0x00000206, 0x000006fd, 0x00000508, 0x00000700, + 0x00000304, 0x000005fe, 0x000005ff, 0x0000fa04, 0x00000303, 0x0000fefb, + 0x000007f9, 0x0000fefc, 0x000004fd, 0x000005fc, 0x0000fffd, 0x0000fc08, + 0x0000fbf9, 0x0000fd07, 0x000008fb, 0x0000fe02, 0x000006fb, 0x00000702, +}; + +static const u32 lpphy_gain_idx_table[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x10000001, 0x00000000, 0x20000082, 0x00000000, 0x40000104, 0x00000000, + 0x60004207, 0x00000001, 0x7000838a, 0x00000001, 0xd021050d, 0x00000001, + 0xe041c683, 0x00000001, 0x50828805, 0x00000000, 0x80e34288, 0x00000000, + 0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000, 0x12064711, 0x00000001, + 0xb0a18612, 0x00000010, 0xe1024794, 0x00000010, 0x11630915, 0x00000011, + 0x31c3ca1b, 0x00000011, 0xc1848a9c, 0x00000018, 0xf1e50da0, 0x00000018, + 0x22468e21, 0x00000019, 0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019, + 0xb36811a6, 0x00000019, 0xf3e89227, 0x00000019, 0x0408d329, 0x0000001a, + 0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a, 0x54aa152c, 0x0000001a, + 0x64ca55ad, 0x0000001a, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x10000001, 0x00000000, 0x20000082, 0x00000000, + 0x40000104, 0x00000000, 0x60004207, 0x00000001, 0x7000838a, 0x00000001, + 0xd021050d, 0x00000001, 0xe041c683, 0x00000001, 0x50828805, 0x00000000, + 0x80e34288, 0x00000000, 0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000, + 0x12064711, 0x00000001, 0xb0a18612, 0x00000010, 0xe1024794, 0x00000010, + 0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011, 0xc1848a9c, 0x00000018, + 0xf1e50da0, 0x00000018, 0x22468e21, 0x00000019, 0x4286d023, 0x00000019, + 0xa347d0a4, 0x00000019, 0xb36811a6, 0x00000019, 0xf3e89227, 0x00000019, + 0x0408d329, 0x0000001a, 0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a, + 0x54aa152c, 0x0000001a, 0x64ca55ad, 0x0000001a, +}; + +static const u16 lpphy_aux_gain_idx_table[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0001, 0x0002, 0x0004, 0x0016, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0016, +}; + +static const u32 lpphy_gain_value_table[] = { + 0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb, 0x00000004, + 0x00000008, 0x0000000d, 0x00000001, 0x00000004, 0x00000007, 0x0000000a, + 0x0000000d, 0x00000010, 0x00000012, 0x00000015, 0x00000000, 0x00000006, + 0x0000000c, 0x00000000, 0x00000000, 0x00000000, 0x00000012, 0x00000000, + 0x00000000, 0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0000001e, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000003, 0x00000006, 0x00000009, 0x0000000c, 0x0000000f, + 0x00000012, 0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000009, 0x000000f1, + 0x00000000, 0x00000000, +}; + +static const u16 lpphy_gain_table[] = { + 0x0000, 0x0400, 0x0800, 0x0802, 0x0804, 0x0806, 0x0807, 0x0808, 0x080a, + 0x080b, 0x080c, 0x080e, 0x080f, 0x0810, 0x0812, 0x0813, 0x0814, 0x0816, + 0x0817, 0x081a, 0x081b, 0x081f, 0x0820, 0x0824, 0x0830, 0x0834, 0x0837, + 0x083b, 0x083f, 0x0840, 0x0844, 0x0857, 0x085b, 0x085f, 0x08d7, 0x08db, + 0x08df, 0x0957, 0x095b, 0x095f, 0x0b57, 0x0b5b, 0x0b5f, 0x0f5f, 0x135f, + 0x175f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const u32 lpphy_a0_gain_idx_table[] = { + 0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060, 0x00511065, + 0x004c806b, 0x0047d072, 0x00444078, 0x00400080, 0x003ca087, 0x0039408f, + 0x0035e098, 0x0032e0a1, 0x003030aa, 0x002d80b4, 0x002ae0bf, 0x002880ca, + 0x002640d6, 0x002410e3, 0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, + 0x001b012f, 0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193, + 0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a, 0x000e523a, + 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd, 0x000ac2f8, 0x000a2325, + 0x00099355, 0x00091387, 0x000883bd, 0x000813f5, 0x0007a432, 0x00073471, + 0x0006c4b5, 0x000664fc, 0x00061547, 0x0005b598, 0x000565ec, 0x00051646, + 0x0004d6a5, 0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd, + 0x00036963, 0x000339f2, 0x00030a89, 0x0002db28, +}; + +static const u16 lpphy_a0_aux_gain_idx_table[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0002, 0x0014, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0002, 0x0014, +}; + +static const u32 lpphy_a0_gain_value_table[] = { + 0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb, 0x00000004, + 0x00000008, 0x0000000d, 0x00000001, 0x00000004, 0x00000007, 0x0000000a, + 0x0000000d, 0x00000010, 0x00000012, 0x00000015, 0x00000000, 0x00000006, + 0x0000000c, 0x00000000, 0x00000000, 0x00000000, 0x00000012, 0x00000000, + 0x00000000, 0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0000001e, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000003, 0x00000006, 0x00000009, 0x0000000c, 0x0000000f, + 0x00000012, 0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000f, 0x000000f7, + 0x00000000, 0x00000000, +}; + +static const u16 lpphy_a0_gain_table[] = { + 0x0000, 0x0002, 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b, 0x000c, + 0x000e, 0x000f, 0x0010, 0x0012, 0x0013, 0x0014, 0x0016, 0x0017, 0x001a, + 0x001b, 0x001f, 0x0020, 0x0024, 0x0030, 0x0034, 0x0037, 0x003b, 0x003f, + 0x0040, 0x0044, 0x0057, 0x005b, 0x005f, 0x00d7, 0x00db, 0x00df, 0x0157, + 0x015b, 0x015f, 0x0357, 0x035b, 0x035f, 0x075f, 0x0b5f, 0x0f5f, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const u16 lpphy_sw_control_table[] = { + 0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028, 0x0128, + 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028, 0x0009, 0x0009, + 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0018, 0x0018, 0x0018, + 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0128, 0x0128, 0x0009, 0x0009, + 0x0028, 0x0028, 0x0028, 0x0028, 0x0128, 0x0128, 0x0009, 0x0009, 0x0028, + 0x0028, 0x0028, 0x0028, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, + 0x0009, 0x0009, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, + 0x0018, +}; + +static const u8 lpphy_hf_table[] = { + 0x4b, 0x36, 0x24, 0x18, 0x49, 0x34, 0x23, 0x17, 0x48, + 0x33, 0x23, 0x17, 0x48, 0x33, 0x23, 0x17, +}; + +static const u32 lpphy_papd_eps_table[] = { + 0x00000000, 0x00013ffc, 0x0001dff3, 0x0001bff0, 0x00023fe9, 0x00021fdf, + 0x00028fdf, 0x00033fd2, 0x00039fcb, 0x00043fc7, 0x0004efc2, 0x00055fb5, + 0x0005cfb0, 0x00063fa8, 0x00068fa3, 0x00071f98, 0x0007ef92, 0x00084f8b, + 0x0008df82, 0x00097f77, 0x0009df69, 0x000a3f62, 0x000adf57, 0x000b6f4c, + 0x000bff41, 0x000c9f39, 0x000cff30, 0x000dbf27, 0x000e4f1e, 0x000edf16, + 0x000f7f13, 0x00102f11, 0x00110f10, 0x0011df11, 0x0012ef15, 0x00143f1c, + 0x00158f27, 0x00172f35, 0x00193f47, 0x001baf5f, 0x001e6f7e, 0x0021cfa4, + 0x0025bfd2, 0x002a2008, 0x002fb047, 0x00360090, 0x003d40e0, 0x0045c135, + 0x004fb189, 0x005ae1d7, 0x0067221d, 0x0075025a, 0x007ff291, 0x007ff2bf, + 0x007ff2e3, 0x007ff2ff, 0x007ff315, 0x007ff329, 0x007ff33f, 0x007ff356, + 0x007ff36e, 0x007ff39c, 0x007ff441, 0x007ff506, +}; + +static const u32 lpphy_papd_mult_table[] = { + 0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060, 0x00511065, + 0x004c806b, 0x0047d072, 0x00444078, 0x00400080, 0x003ca087, 0x0039408f, + 0x0035e098, 0x0032e0a1, 0x003030aa, 0x002d80b4, 0x002ae0bf, 0x002880ca, + 0x002640d6, 0x002410e3, 0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, + 0x001b012f, 0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193, + 0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a, 0x000e523a, + 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd, 0x000ac2f8, 0x000a2325, + 0x00099355, 0x00091387, 0x000883bd, 0x000813f5, 0x0007a432, 0x00073471, + 0x0006c4b5, 0x000664fc, 0x00061547, 0x0005b598, 0x000565ec, 0x00051646, + 0x0004d6a5, 0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd, + 0x00036963, 0x000339f2, 0x00030a89, 0x0002db28, +}; + +struct lpphy_tx_gain_table_entry { + u8 gm, pga, pad, dac, bb_mult; +}; + +static struct lpphy_tx_gain_table_entry lpphy_rev0_nopa_tx_gain_table[] = { + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 152, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 147, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 143, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 139, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 135, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 131, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 128, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 124, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 121, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 117, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 114, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 111, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 107, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 104, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 101, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 99, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 96, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 93, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 90, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 88, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 85, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 83, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 81, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 78, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 76, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 74, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 56, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 73, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 73, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 71, }, +}; + +static struct lpphy_tx_gain_table_entry lpphy_rev0_2ghz_tx_gain_table[] = { + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 73, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 71, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 69, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 67, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 73, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 71, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 69, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 67, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 71, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 69, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 67, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 58, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 67, }, + { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 58, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 57, }, + { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 83, }, + { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 81, }, + { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 78, }, + { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 76, }, + { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 74, }, + { .gm = 4, .pga = 4, .pad = 2, .dac = 0, .bb_mult = 72, }, +}; + +static struct lpphy_tx_gain_table_entry lpphy_rev0_5ghz_tx_gain_table[] = { + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 99, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 96, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 93, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 90, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 88, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 85, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 83, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 81, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 78, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 76, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 74, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 55, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 56, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 55, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 56, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 73, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 56, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 60, }, +}; + +static struct lpphy_tx_gain_table_entry lpphy_rev1_nopa_tx_gain_table[] = { + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 152, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 147, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 143, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 139, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 135, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 131, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 128, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 124, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 121, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 117, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 114, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 111, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 107, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 104, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 101, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 99, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 96, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 93, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 90, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 88, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 85, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 83, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 81, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 78, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 76, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 74, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 56, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 73, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 73, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 71, }, +}; + +static struct lpphy_tx_gain_table_entry lpphy_rev1_2ghz_tx_gain_table[] = { + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 85, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 81, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 78, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 76, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 74, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 73, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 71, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 69, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 67, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 73, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 71, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 69, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 67, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 71, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 69, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 67, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 58, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 67, }, + { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 65, }, + { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 63, }, + { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 61, }, + { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 58, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 62, }, +}; + +static struct lpphy_tx_gain_table_entry lpphy_rev1_5ghz_tx_gain_table[] = { + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 99, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 96, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 93, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 90, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 88, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 85, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 83, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 81, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 78, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 76, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 74, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 55, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 56, }, + { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 55, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 56, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 72, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 73, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 71, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 56, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 14, .pad = 9, .dac = 0, .bb_mult = 58, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 13, .pad = 9, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 60, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 13, .pad = 8, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 12, .pad = 8, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 12, .pad = 7, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 70, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 68, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 66, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 61, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 59, }, + { .gm = 7, .pga = 11, .pad = 7, .dac = 0, .bb_mult = 57, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 69, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 67, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 65, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 63, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 62, }, + { .gm = 7, .pga = 11, .pad = 6, .dac = 0, .bb_mult = 60, }, +}; + +static struct lpphy_tx_gain_table_entry lpphy_rev2_nopa_tx_gain_table[] = { + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 152, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 147, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 143, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 139, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 135, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 131, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 128, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 124, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 121, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 117, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 114, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 111, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 107, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 104, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 101, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 99, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 96, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 93, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 90, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 88, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 85, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 83, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 81, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 78, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 76, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 74, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 72, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 70, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 68, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 66, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 197, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 192, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 186, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 181, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 176, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 171, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 166, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 161, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 157, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 152, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 148, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 144, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 140, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 136, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 132, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 128, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 124, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 121, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 117, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 114, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 111, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 108, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 105, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 102, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 99, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 96, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 93, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 91, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 88, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 86, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 83, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 81, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 79, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 76, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 74, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 72, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 70, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 68, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 66, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 64, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 248, .pad = 64, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 248, .pad = 62, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 241, .pad = 62, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 241, .pad = 60, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 234, .pad = 60, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 234, .pad = 59, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 227, .pad = 59, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 227, .pad = 57, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 221, .pad = 57, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 221, .pad = 55, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 215, .pad = 55, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 215, .pad = 54, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 208, .pad = 54, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 208, .pad = 52, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 203, .pad = 52, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 203, .pad = 51, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 197, .pad = 51, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 197, .pad = 49, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 191, .pad = 49, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 191, .pad = 48, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 186, .pad = 48, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 186, .pad = 47, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 181, .pad = 47, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 181, .pad = 45, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 175, .pad = 45, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 175, .pad = 44, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 170, .pad = 44, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 170, .pad = 43, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 166, .pad = 43, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 166, .pad = 42, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 161, .pad = 42, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 161, .pad = 40, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 156, .pad = 40, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 156, .pad = 39, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 152, .pad = 39, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 152, .pad = 38, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 148, .pad = 38, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 148, .pad = 37, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 143, .pad = 37, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 143, .pad = 36, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 139, .pad = 36, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 139, .pad = 35, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 135, .pad = 35, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 135, .pad = 34, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 132, .pad = 34, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 132, .pad = 33, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 128, .pad = 33, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 128, .pad = 32, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 124, .pad = 32, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 124, .pad = 31, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 121, .pad = 31, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 121, .pad = 30, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 117, .pad = 30, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 117, .pad = 29, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 114, .pad = 29, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 114, .pad = 29, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 111, .pad = 29, .dac = 0, .bb_mult = 64, }, +}; + +static struct lpphy_tx_gain_table_entry lpphy_rev2_2ghz_tx_gain_table[] = { + { .gm = 7, .pga = 99, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 96, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 93, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 90, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 88, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 85, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 83, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 81, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 78, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 76, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 74, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 72, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 70, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 68, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 66, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 64, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 64, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 62, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 62, .pad = 248, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 60, .pad = 248, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 60, .pad = 241, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 59, .pad = 241, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 59, .pad = 234, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 57, .pad = 234, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 57, .pad = 227, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 55, .pad = 227, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 55, .pad = 221, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 54, .pad = 221, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 54, .pad = 215, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 52, .pad = 215, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 52, .pad = 208, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 51, .pad = 208, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 51, .pad = 203, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 49, .pad = 203, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 49, .pad = 197, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 48, .pad = 197, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 48, .pad = 191, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 47, .pad = 191, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 47, .pad = 186, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 45, .pad = 186, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 45, .pad = 181, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 44, .pad = 181, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 44, .pad = 175, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 43, .pad = 175, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 43, .pad = 170, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 42, .pad = 170, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 42, .pad = 166, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 40, .pad = 166, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 40, .pad = 161, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 39, .pad = 161, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 39, .pad = 156, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 38, .pad = 156, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 38, .pad = 152, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 37, .pad = 152, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 37, .pad = 148, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 36, .pad = 148, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 36, .pad = 143, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 35, .pad = 143, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 35, .pad = 139, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 34, .pad = 139, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 34, .pad = 135, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 33, .pad = 135, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 33, .pad = 132, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 32, .pad = 132, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 32, .pad = 128, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 31, .pad = 128, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 31, .pad = 124, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 30, .pad = 124, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 30, .pad = 121, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 29, .pad = 121, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 29, .pad = 117, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 29, .pad = 117, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 29, .pad = 114, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 28, .pad = 114, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 28, .pad = 111, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 27, .pad = 111, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 27, .pad = 108, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 26, .pad = 108, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 26, .pad = 104, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 25, .pad = 104, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 25, .pad = 102, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 25, .pad = 102, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 25, .pad = 99, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 24, .pad = 99, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 24, .pad = 96, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 23, .pad = 96, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 23, .pad = 93, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 23, .pad = 93, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 23, .pad = 90, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 22, .pad = 90, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 22, .pad = 88, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 21, .pad = 88, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 21, .pad = 85, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 21, .pad = 85, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 21, .pad = 83, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 20, .pad = 83, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 20, .pad = 81, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 20, .pad = 81, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 20, .pad = 78, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 19, .pad = 78, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 19, .pad = 76, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 19, .pad = 76, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 19, .pad = 74, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 18, .pad = 74, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 18, .pad = 72, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 18, .pad = 72, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 18, .pad = 70, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 17, .pad = 70, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 17, .pad = 68, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 17, .pad = 68, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 17, .pad = 66, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 16, .pad = 66, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 16, .pad = 64, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 16, .pad = 64, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 16, .pad = 62, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 62, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 60, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 60, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 15, .pad = 59, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 14, .pad = 59, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 14, .pad = 57, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 14, .pad = 57, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 14, .pad = 55, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 14, .pad = 55, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 14, .pad = 54, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 54, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 52, .dac = 0, .bb_mult = 64, }, + { .gm = 7, .pga = 13, .pad = 52, .dac = 0, .bb_mult = 64, }, +}; + +static struct lpphy_tx_gain_table_entry lpphy_rev2_5ghz_tx_gain_table[] = { + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 152, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 147, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 143, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 139, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 135, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 131, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 128, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 124, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 121, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 117, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 114, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 111, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 107, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 104, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 101, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 99, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 96, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 93, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 90, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 88, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 85, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 83, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 81, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 78, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 76, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 74, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 72, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 70, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 68, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 66, }, + { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 248, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 241, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 234, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 227, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 221, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 215, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 208, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 203, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 197, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 191, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 186, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 181, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 175, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 170, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 166, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 161, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 156, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 152, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 148, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 143, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 139, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 135, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 132, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 128, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 124, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 121, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 117, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 114, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 111, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 108, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 104, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 102, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 99, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 96, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 93, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 90, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 88, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 85, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 83, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 81, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 78, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 76, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 74, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 72, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 70, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 68, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 66, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 64, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 64, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 62, .pad = 255, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 62, .pad = 248, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 60, .pad = 248, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 60, .pad = 241, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 59, .pad = 241, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 59, .pad = 234, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 57, .pad = 234, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 57, .pad = 227, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 55, .pad = 227, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 55, .pad = 221, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 54, .pad = 221, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 54, .pad = 215, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 52, .pad = 215, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 52, .pad = 208, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 51, .pad = 208, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 51, .pad = 203, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 49, .pad = 203, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 49, .pad = 197, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 48, .pad = 197, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 48, .pad = 191, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 47, .pad = 191, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 47, .pad = 186, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 45, .pad = 186, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 45, .pad = 181, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 44, .pad = 181, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 44, .pad = 175, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 43, .pad = 175, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 43, .pad = 170, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 42, .pad = 170, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 42, .pad = 166, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 40, .pad = 166, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 40, .pad = 161, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 39, .pad = 161, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 39, .pad = 156, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 38, .pad = 156, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 38, .pad = 152, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 37, .pad = 152, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 37, .pad = 148, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 36, .pad = 148, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 36, .pad = 143, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 35, .pad = 143, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 35, .pad = 139, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 34, .pad = 139, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 34, .pad = 135, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 33, .pad = 135, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 33, .pad = 132, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 32, .pad = 132, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 32, .pad = 128, .dac = 0, .bb_mult = 64, }, +}; + +void lpphy_rev0_1_table_init(struct b43_wldev *dev) +{ + B43_WARN_ON(dev->phy.rev >= 2); + + b43_lptab_write_bulk(dev, B43_LPTAB8(2, 0), + ARRAY_SIZE(lpphy_min_sig_sq_table), lpphy_min_sig_sq_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(1, 0), + ARRAY_SIZE(lpphy_rev01_noise_scale_table), lpphy_rev01_noise_scale_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(14, 0), + ARRAY_SIZE(lpphy_crs_gain_nft_table), lpphy_crs_gain_nft_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(8, 0), + ARRAY_SIZE(lpphy_rev01_filter_control_table), lpphy_rev01_filter_control_table); + b43_lptab_write_bulk(dev, B43_LPTAB32(9, 0), + ARRAY_SIZE(lpphy_rev01_ps_control_table), lpphy_rev01_ps_control_table); + b43_lptab_write_bulk(dev, B43_LPTAB8(6, 0), + ARRAY_SIZE(lpphy_pll_fraction_table), lpphy_pll_fraction_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(0, 0), + ARRAY_SIZE(lpphy_iq_local_table), lpphy_iq_local_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), + ARRAY_SIZE(lpphy_ofdm_cck_gain_table), lpphy_ofdm_cck_gain_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), + ARRAY_SIZE(lpphy_ofdm_cck_gain_table), lpphy_ofdm_cck_gain_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(15, 0), + ARRAY_SIZE(lpphy_gain_delta_table), lpphy_gain_delta_table); + b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0), + ARRAY_SIZE(lpphy_tx_power_control_table), lpphy_tx_power_control_table); +} + +void lpphy_rev2plus_table_init(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + int i; + + B43_WARN_ON(dev->phy.rev < 2); + + /* + * FIXME This code follows the specs, but it looks wrong: + * In each pass, it writes 4 bytes to an offset in table ID 7, + * then increments the offset by 1 for the next pass. This results + * in the first 3 bytes of each pass except the first one getting + * written to a location that has already been zeroed in the previous + * pass. + * This is what the vendor driver does, but it still looks suspicious. + * + * This should probably suffice: + * + * for (i = 0; i < 704; i+=4) + * b43_lptab_write(dev, B43_LPTAB32(7, i), 0) + * + * This should be tested once the code is functional. + */ + for (i = 0; i < 704; i++) + b43_lptab_write(dev, B43_LPTAB32(7, i), 0); + + b43_lptab_write_bulk(dev, B43_LPTAB8(2, 0), + ARRAY_SIZE(lpphy_min_sig_sq_table), lpphy_min_sig_sq_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(1, 0), + ARRAY_SIZE(lpphy_rev2plus_noise_scale_table), lpphy_rev2plus_noise_scale_table); + b43_lptab_write_bulk(dev, B43_LPTAB32(11, 0), + ARRAY_SIZE(lpphy_rev2plus_filter_control_table), lpphy_rev2plus_filter_control_table); + b43_lptab_write_bulk(dev, B43_LPTAB32(12, 0), + ARRAY_SIZE(lpphy_rev2plus_ps_control_table), lpphy_rev2plus_ps_control_table); + b43_lptab_write_bulk(dev, B43_LPTAB32(13, 0), + ARRAY_SIZE(lpphy_gain_idx_table), lpphy_gain_idx_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(14, 0), + ARRAY_SIZE(lpphy_aux_gain_idx_table), lpphy_aux_gain_idx_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(15, 0), + ARRAY_SIZE(lpphy_sw_control_table), lpphy_sw_control_table); + b43_lptab_write_bulk(dev, B43_LPTAB8(16, 0), + ARRAY_SIZE(lpphy_hf_table), lpphy_hf_table); + b43_lptab_write_bulk(dev, B43_LPTAB32(17, 0), + ARRAY_SIZE(lpphy_gain_value_table), lpphy_gain_value_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(18, 0), + ARRAY_SIZE(lpphy_gain_table), lpphy_gain_table); + b43_lptab_write_bulk(dev, B43_LPTAB8(6, 0), + ARRAY_SIZE(lpphy_pll_fraction_table), lpphy_pll_fraction_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(0, 0), + ARRAY_SIZE(lpphy_iq_local_table), lpphy_iq_local_table); + b43_lptab_write_bulk(dev, B43_LPTAB32(9, 0), + ARRAY_SIZE(lpphy_papd_eps_table), lpphy_papd_eps_table); + b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0), + ARRAY_SIZE(lpphy_papd_mult_table), lpphy_papd_mult_table); + + if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) { + b43_lptab_write_bulk(dev, B43_LPTAB32(13, 0), + ARRAY_SIZE(lpphy_a0_gain_idx_table), lpphy_a0_gain_idx_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(14, 0), + ARRAY_SIZE(lpphy_a0_aux_gain_idx_table), lpphy_a0_aux_gain_idx_table); + b43_lptab_write_bulk(dev, B43_LPTAB32(17, 0), + ARRAY_SIZE(lpphy_a0_gain_value_table), lpphy_a0_gain_value_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(18, 0), + ARRAY_SIZE(lpphy_a0_gain_table), lpphy_a0_gain_table); + } +} + + +static void lpphy_rev0_1_write_gain_table(struct b43_wldev *dev, + struct lpphy_tx_gain_table_entry *table) +{ + int i; + u32 tmp; + + B43_WARN_ON(dev->phy.rev >= 2); + + for (i = 0; i < 128; i++) { + tmp = table[i].pad << 11; + tmp |= table[i].pga << 7; + tmp |= table[i].gm << 4; + tmp |= table[i].dac; + b43_lptab_write(dev, B43_LPTAB32(10, 0xC0 + i), tmp); + tmp = table[i].bb_mult << 20; + b43_lptab_write(dev, B43_LPTAB32(10, 0x140 + i), tmp); + } +} + +static void lpphy_rev2plus_write_gain_table(struct b43_wldev *dev, + struct lpphy_tx_gain_table_entry *table) +{ + int i; + u32 tmp; + + B43_WARN_ON(dev->phy.rev < 2); + + for (i = 0; i < 128; i++) { + tmp = table[i].pad << 16; + tmp |= table[i].pga << 8; + tmp |= table[i].gm; + tmp |= 0x7f000000; + b43_lptab_write(dev, B43_LPTAB32(7, 0xC0 + i), tmp); + tmp = table[i].bb_mult << 20; + tmp |= table[i].dac << 28; + b43_lptab_write(dev, B43_LPTAB32(7, 0x140 + i), tmp); + } +} + +void lpphy_init_tx_gain_table(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + + switch (dev->phy.rev) { + case 0: + if ((bus->sprom.boardflags_hi & B43_BFH_NOPA) || + (bus->sprom.boardflags_lo & B43_BFL_HGPA)) + lpphy_rev0_1_write_gain_table(dev, + lpphy_rev0_nopa_tx_gain_table); + else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + lpphy_rev0_1_write_gain_table(dev, + lpphy_rev0_2ghz_tx_gain_table); + else + lpphy_rev0_1_write_gain_table(dev, + lpphy_rev0_5ghz_tx_gain_table); + break; + case 1: + if ((bus->sprom.boardflags_hi & B43_BFH_NOPA) || + (bus->sprom.boardflags_lo & B43_BFL_HGPA)) + lpphy_rev0_1_write_gain_table(dev, + lpphy_rev1_nopa_tx_gain_table); + else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + lpphy_rev0_1_write_gain_table(dev, + lpphy_rev1_2ghz_tx_gain_table); + else + lpphy_rev0_1_write_gain_table(dev, + lpphy_rev1_5ghz_tx_gain_table); + break; + default: + if (bus->sprom.boardflags_hi & B43_BFH_NOPA) + lpphy_rev2plus_write_gain_table(dev, + lpphy_rev2_nopa_tx_gain_table); + else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + lpphy_rev2plus_write_gain_table(dev, + lpphy_rev2_2ghz_tx_gain_table); + else + lpphy_rev2plus_write_gain_table(dev, + lpphy_rev2_5ghz_tx_gain_table); + } +} diff --git a/drivers/net/wireless/b43/tables_lpphy.h b/drivers/net/wireless/b43/tables_lpphy.h index 52ce32ff43a..b5024b6edab 100644 --- a/drivers/net/wireless/b43/tables_lpphy.h +++ b/drivers/net/wireless/b43/tables_lpphy.h @@ -28,5 +28,8 @@ void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset, void b2062_upload_init_table(struct b43_wldev *dev); void b2063_upload_init_table(struct b43_wldev *dev); +void lpphy_rev0_1_table_init(struct b43_wldev *dev); +void lpphy_rev2plus_table_init(struct b43_wldev *dev); +void lpphy_init_tx_gain_table(struct b43_wldev *dev); #endif /* B43_TABLES_LPPHY_H_ */ -- cgit v1.2.3-18-g5258 From a3e14f3d2a55fa1268f64ec8a839b6dfa4ff9ea2 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Mon, 10 Aug 2009 20:57:06 +0200 Subject: b43: Update LP-PHY rev2+ baseband init to match the specs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rev2+ BB init spec has changed behind us, and thus the code is no longer up to date. Update the code to match the current specs. Also implement save/restore dig filt state, as required by the new specification. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 73 ++++++++++++++++++++++++++++++++++++--- drivers/net/wireless/b43/phy_lp.h | 3 ++ 2 files changed, 72 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 79039c3f60c..6b1989490ae 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -195,6 +195,56 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) } } +static void lpphy_save_dig_flt_state(struct b43_wldev *dev) +{ + static const u16 addr[] = { + B43_PHY_OFDM(0xC1), + B43_PHY_OFDM(0xC2), + B43_PHY_OFDM(0xC3), + B43_PHY_OFDM(0xC4), + B43_PHY_OFDM(0xC5), + B43_PHY_OFDM(0xC6), + B43_PHY_OFDM(0xC7), + B43_PHY_OFDM(0xC8), + B43_PHY_OFDM(0xCF), + }; + + static const u16 coefs[] = { + 0xDE5E, 0xE832, 0xE331, 0x4D26, + 0x0026, 0x1420, 0x0020, 0xFE08, + 0x0008, + }; + + struct b43_phy_lp *lpphy = dev->phy.lp; + int i; + + for (i = 0; i < ARRAY_SIZE(addr); i++) { + lpphy->dig_flt_state[i] = b43_phy_read(dev, addr[i]); + b43_phy_write(dev, addr[i], coefs[i]); + } +} + +static void lpphy_restore_dig_flt_state(struct b43_wldev *dev) +{ + static const u16 addr[] = { + B43_PHY_OFDM(0xC1), + B43_PHY_OFDM(0xC2), + B43_PHY_OFDM(0xC3), + B43_PHY_OFDM(0xC4), + B43_PHY_OFDM(0xC5), + B43_PHY_OFDM(0xC6), + B43_PHY_OFDM(0xC7), + B43_PHY_OFDM(0xC8), + B43_PHY_OFDM(0xCF), + }; + + struct b43_phy_lp *lpphy = dev->phy.lp; + int i; + + for (i = 0; i < ARRAY_SIZE(addr); i++) + b43_phy_write(dev, addr[i], lpphy->dig_flt_state[i]); +} + static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) { struct ssb_bus *bus = dev->dev->bus; @@ -209,7 +259,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_OFDM(0xF9), 0); b43_phy_write(dev, B43_LPPHY_TR_LOOKUP_1, 0); b43_phy_set(dev, B43_LPPHY_ADC_COMPENSATION_CTL, 0x10); - b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0x78); + b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0xB4); b43_phy_maskset(dev, B43_LPPHY_DCOFFSETTRANSIENT, 0xF8FF, 0x200); b43_phy_maskset(dev, B43_LPPHY_DCOFFSETTRANSIENT, 0xFF00, 0x7F); b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFF0F, 0x40); @@ -217,7 +267,12 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x4000); b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x2000); b43_phy_set(dev, B43_PHY_OFDM(0x10A), 0x1); - b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x10); + if (bus->boardinfo.rev >= 0x18) { + b43_lptab_write(dev, B43_LPTAB32(17, 65), 0xEC); + b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x14); + } else { + b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x10); + } b43_phy_maskset(dev, B43_PHY_OFDM(0xDF), 0xFF00, 0xF4); b43_phy_maskset(dev, B43_PHY_OFDM(0xDF), 0x00FF, 0xF100); b43_phy_write(dev, B43_LPPHY_CLIPTHRESH, 0x48); @@ -247,8 +302,10 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x12); b43_phy_maskset(dev, B43_LPPHY_GAINMISMATCH, 0x0FFF, 0x9000); - b43_lptab_write(dev, B43_LPTAB16(0x08, 0x14), 0); - b43_lptab_write(dev, B43_LPTAB16(0x08, 0x12), 0x40); + if ((bus->chip_id == 0x4325) && (bus->chip_rev == 1)) { + b43_lptab_write(dev, B43_LPTAB16(0x08, 0x14), 0); + b43_lptab_write(dev, B43_LPTAB16(0x08, 0x12), 0x40); + } if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x40); @@ -268,6 +325,14 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0x2000 | ((u16)lpphy->rssi_gs << 10) | ((u16)lpphy->rssi_vc << 4) | lpphy->rssi_vf); + + if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) { + b43_phy_set(dev, B43_LPPHY_AFE_ADC_CTL_0, 0x1C); + b43_phy_maskset(dev, B43_LPPHY_AFE_CTL, 0x00FF, 0x8800); + b43_phy_maskset(dev, B43_LPPHY_AFE_ADC_CTL_1, 0xFC3C, 0x0400); + } + + lpphy_save_dig_flt_state(dev); } static void lpphy_baseband_init(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h index 829b2bba3ee..13d89eacaf5 100644 --- a/drivers/net/wireless/b43/phy_lp.h +++ b/drivers/net/wireless/b43/phy_lp.h @@ -865,6 +865,9 @@ struct b43_phy_lp { /* Transmit iqlocal best coeffs */ bool tx_iqloc_best_coeffs_valid; u8 tx_iqloc_best_coeffs[11]; + + /* Used for "Save/Restore Dig Filt State" */ + u16 dig_flt_state[9]; }; -- cgit v1.2.3-18-g5258 From f679056b2fdd4e9b7c8eb42ba447cd9646236305 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Mon, 10 Aug 2009 21:23:08 +0200 Subject: ssb: Implement the remaining rev.8 SPROM vars needed for LP-PHY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also add a "SPEX32" macro for extracting 32-bit SPROM variables. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/ssb/pci.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 40ea4176224..593fc618a2e 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -169,8 +169,14 @@ err_pci: /* Get the word-offset for a SSB_SPROM_XXX define. */ #define SPOFF(offset) (((offset) - SSB_SPROM_BASE) / sizeof(u16)) /* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */ -#define SPEX(_outvar, _offset, _mask, _shift) \ +#define SPEX16(_outvar, _offset, _mask, _shift) \ out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift)) +#define SPEX32(_outvar, _offset, _mask, _shift) \ + out->_outvar = ((((u32)in[SPOFF((_offset)+2)] << 16 | \ + in[SPOFF(_offset)]) & (_mask)) >> (_shift)) +#define SPEX(_outvar, _offset, _mask, _shift) \ + SPEX16(_outvar, _offset, _mask, _shift) + static inline u8 ssb_crc8(u8 crc, u8 data) { @@ -480,6 +486,8 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) SPEX(country_code, SSB_SPROM8_CCODE, 0xFFFF, 0); SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0); SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0); + SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0); + SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, 0xFFFF, 0); SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A, SSB_SPROM8_ANTAVAIL_A_SHIFT); SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG, @@ -490,12 +498,55 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0); SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A, SSB_SPROM8_ITSSI_A_SHIFT); + SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0); + SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK, + SSB_SPROM8_MAXP_AL_SHIFT); SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0); SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1, SSB_SPROM8_GPIOA_P1_SHIFT); SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0); SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3, SSB_SPROM8_GPIOB_P3_SHIFT); + SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0); + SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G, + SSB_SPROM8_TRI5G_SHIFT); + SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0); + SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH, + SSB_SPROM8_TRI5GH_SHIFT); + SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, 0); + SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G, + SSB_SPROM8_RXPO5G_SHIFT); + SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0); + SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G, + SSB_SPROM8_RSSISMC2G_SHIFT); + SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G, + SSB_SPROM8_RSSISAV2G_SHIFT); + SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G, + SSB_SPROM8_BXA2G_SHIFT); + SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0); + SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G, + SSB_SPROM8_RSSISMC5G_SHIFT); + SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G, + SSB_SPROM8_RSSISAV5G_SHIFT); + SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G, + SSB_SPROM8_BXA5G_SHIFT); + SPEX(pa0b0, SSB_SPROM8_PA0B0, 0xFFFF, 0); + SPEX(pa0b1, SSB_SPROM8_PA0B1, 0xFFFF, 0); + SPEX(pa0b2, SSB_SPROM8_PA0B2, 0xFFFF, 0); + SPEX(pa1b0, SSB_SPROM8_PA1B0, 0xFFFF, 0); + SPEX(pa1b1, SSB_SPROM8_PA1B1, 0xFFFF, 0); + SPEX(pa1b2, SSB_SPROM8_PA1B2, 0xFFFF, 0); + SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, 0xFFFF, 0); + SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, 0xFFFF, 0); + SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, 0xFFFF, 0); + SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, 0xFFFF, 0); + SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, 0xFFFF, 0); + SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, 0xFFFF, 0); + SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, 0xFFFF, 0); + SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, 0xFFFFFFFF, 0); + SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, 0xFFFFFFFF, 0); + SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, 0xFFFFFFFF, 0); + SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0); /* Extract the antenna gain values. */ SPEX(antenna_gain.ghz24.a0, SSB_SPROM8_AGAIN01, -- cgit v1.2.3-18-g5258 From d44517f235c5baa943fc8cac7e56bd291ffc077e Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Tue, 11 Aug 2009 00:54:26 +0200 Subject: b43: Fix a typo in the sync_stx routine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I completely missed the "one's complement" instruction from the specs. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 6b1989490ae..95e15e6692a 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -497,7 +497,7 @@ static void lpphy_sync_stx(struct b43_wldev *dev) tmp >>= e->rf_shift; tmp <<= e->phy_shift; b43_phy_maskset(dev, B43_PHY_OFDM(0xF2 + e->phy_offset), - e->mask << e->phy_shift, tmp); + ~(e->mask << e->phy_shift), tmp); } } -- cgit v1.2.3-18-g5258 From 73d0a13c8583cd9a84c1333cf9b45d1d894e52b3 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 11 Aug 2009 11:58:27 +0300 Subject: wl1271: fix compiler warnings on 64 bit archs There were a few warnings when compiling the wl1271 driver on 64 bit architectures. This was due to size mismatch of integers. This commit fixes the following warnings: drivers/net/wireless/wl12xx/wl1271_main.c: In function 'wl1271_irq_work': drivers/net/wireless/wl12xx/wl1271_main.c:184: warning: large integer implicitly truncated to unsigned type drivers/net/wireless/wl12xx/wl1271_boot.c: In function 'wl1271_boot_upload_firmware_chunk': drivers/net/wireless/wl12xx/wl1271_boot.c:103: warning: format '%d' expects type 'int', but argument 2 has type 'size_t' drivers/net/wireless/wl12xx/wl1271_boot.c:150: warning: format '%d' expects type 'int', but argument 2 has type 'size_t' drivers/net/wireless/wl12xx/wl1271_boot.c: In function 'wl1271_boot_enable_interrupts': drivers/net/wireless/wl12xx/wl1271_boot.c:278: warning: large integer implicitly truncated to unsigned type Reported-by: Stephen Rothwell Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_boot.c | 9 +++++---- drivers/net/wireless/wl12xx/wl1271_main.c | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index 4c22f25fd8f..8228ef474a7 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -100,8 +100,8 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, wl1271_debug(DEBUG_BOOT, "starting firmware upload"); - wl1271_debug(DEBUG_BOOT, "fw_data_len %d chunk_size %d", fw_data_len, - CHUNK_SIZE); + wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d", + fw_data_len, CHUNK_SIZE); if ((fw_data_len % 4) != 0) { @@ -147,7 +147,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, /* 10.4 upload the last chunk */ addr = dest + chunk_num * CHUNK_SIZE; p = buf + chunk_num * CHUNK_SIZE; - wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%d B) 0x%p to 0x%x", + wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x", fw_data_len % CHUNK_SIZE, p, addr); wl1271_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); @@ -275,7 +275,8 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) static void wl1271_boot_enable_interrupts(struct wl1271 *wl) { enable_irq(wl->irq); - wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(WL1271_INTR_MASK)); + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, + WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); wl1271_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); } diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 3bb45ced99a..4102d590b79 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -181,7 +181,8 @@ static void wl1271_irq_work(struct work_struct *work) } while (intr && --ctr); out_sleep: - wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(WL1271_INTR_MASK)); + wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, + WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); wl1271_ps_elp_sleep(wl); out: -- cgit v1.2.3-18-g5258 From c00552c60840c32456ca9e45de758ac03e3d3c4f Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 11 Aug 2009 16:09:34 +0200 Subject: libertas: name the network device wlan%d Devices created by the libertas driver are currently called eth%d. Which is wrong, because the device does not at all have anything to do with Ethernet. And it is also confusing when used on devices with more than one network device. Fix this by calling it wlan%d. Signed-off-by: Daniel Mack Cc: Roel Kluin Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 89575e44801..8df1cfd5f93 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1176,7 +1176,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) /* Allocate an Ethernet device and register it */ dev = alloc_etherdev(sizeof(struct lbs_private)); if (!dev) { - lbs_pr_err("init ethX device failed\n"); + lbs_pr_err("init wlanX device failed\n"); goto done; } priv = netdev_priv(dev); @@ -1204,6 +1204,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) SET_NETDEV_DEV(dev, dmdev); priv->rtap_net_dev = NULL; + strcpy(dev->name, "wlan%d"); lbs_deb_thread("Starting main thread...\n"); init_waitqueue_head(&priv->waitq); -- cgit v1.2.3-18-g5258 From 84ec167d327b42414285f22eb037a5bdee486ded Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Tue, 11 Aug 2009 21:47:00 +0200 Subject: b43: LP-PHY: Implement reading band SPROM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some of the new variables in b43_phy_lp appear to be dead code in the vendor driver; they will be removed if they remain unused when LP-PHY implementation is finished. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 85 ++++++++++++++++++++++++++++++++++++++- drivers/net/wireless/b43/phy_lp.h | 16 ++++++++ 2 files changed, 100 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 95e15e6692a..2bec791041f 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -59,6 +59,89 @@ static void b43_lpphy_op_free(struct b43_wldev *dev) dev->phy.lp = NULL; } +static void lpphy_read_band_sprom(struct b43_wldev *dev) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + struct ssb_bus *bus = dev->dev->bus; + u16 cckpo, maxpwr; + u32 ofdmpo; + int i; + + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + lpphy->tx_isolation_med_band = bus->sprom.tri2g; + lpphy->bx_arch = bus->sprom.bxa2g; + lpphy->rx_pwr_offset = bus->sprom.rxpo2g; + lpphy->rssi_vf = bus->sprom.rssismf2g; + lpphy->rssi_vc = bus->sprom.rssismc2g; + lpphy->rssi_gs = bus->sprom.rssisav2g; + lpphy->txpa[0] = bus->sprom.pa0b0; + lpphy->txpa[1] = bus->sprom.pa0b1; + lpphy->txpa[2] = bus->sprom.pa0b2; + maxpwr = bus->sprom.maxpwr_bg; + lpphy->max_tx_pwr_med_band = maxpwr; + cckpo = bus->sprom.cck2gpo; + ofdmpo = bus->sprom.ofdm2gpo; + if (cckpo) { + for (i = 0; i < 4; i++) { + lpphy->tx_max_rate[i] = + maxpwr - (ofdmpo & 0xF) * 2; + ofdmpo >>= 4; + } + ofdmpo = bus->sprom.ofdm2gpo; + for (i = 4; i < 15; i++) { + lpphy->tx_max_rate[i] = + maxpwr - (ofdmpo & 0xF) * 2; + ofdmpo >>= 4; + } + } else { + ofdmpo &= 0xFF; + for (i = 0; i < 4; i++) + lpphy->tx_max_rate[i] = maxpwr; + for (i = 4; i < 15; i++) + lpphy->tx_max_rate[i] = maxpwr - ofdmpo; + } + } else { /* 5GHz */ + lpphy->tx_isolation_low_band = bus->sprom.tri5gl; + lpphy->tx_isolation_med_band = bus->sprom.tri5g; + lpphy->tx_isolation_hi_band = bus->sprom.tri5gh; + lpphy->bx_arch = bus->sprom.bxa5g; + lpphy->rx_pwr_offset = bus->sprom.rxpo5g; + lpphy->rssi_vf = bus->sprom.rssismf5g; + lpphy->rssi_vc = bus->sprom.rssismc5g; + lpphy->rssi_gs = bus->sprom.rssisav5g; + lpphy->txpa[0] = bus->sprom.pa1b0; + lpphy->txpa[1] = bus->sprom.pa1b1; + lpphy->txpa[2] = bus->sprom.pa1b2; + lpphy->txpal[0] = bus->sprom.pa1lob0; + lpphy->txpal[1] = bus->sprom.pa1lob1; + lpphy->txpal[2] = bus->sprom.pa1lob2; + lpphy->txpah[0] = bus->sprom.pa1hib0; + lpphy->txpah[1] = bus->sprom.pa1hib1; + lpphy->txpah[2] = bus->sprom.pa1hib2; + maxpwr = bus->sprom.maxpwr_al; + ofdmpo = bus->sprom.ofdm5glpo; + lpphy->max_tx_pwr_low_band = maxpwr; + for (i = 4; i < 12; i++) { + lpphy->tx_max_ratel[i] = maxpwr - (ofdmpo & 0xF) * 2; + ofdmpo >>= 4; + } + maxpwr = bus->sprom.maxpwr_a; + ofdmpo = bus->sprom.ofdm5gpo; + lpphy->max_tx_pwr_med_band = maxpwr; + for (i = 4; i < 12; i++) { + lpphy->tx_max_rate[i] = maxpwr - (ofdmpo & 0xF) * 2; + ofdmpo >>= 4; + } + maxpwr = bus->sprom.maxpwr_ah; + ofdmpo = bus->sprom.ofdm5ghpo; + lpphy->max_tx_pwr_hi_band = maxpwr; + for (i = 4; i < 12; i++) { + lpphy->tx_max_rateh[i] = maxpwr - (ofdmpo & 0xF) * 2; + ofdmpo >>= 4; + } + } +} + static void lpphy_adjust_gain_table(struct b43_wldev *dev) { struct b43_phy_lp *lpphy = dev->phy.lp; @@ -694,7 +777,7 @@ static void lpphy_tx_pctl_init(struct b43_wldev *dev) static int b43_lpphy_op_init(struct b43_wldev *dev) { - /* TODO: band SPROM */ + lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs? lpphy_baseband_init(dev); lpphy_radio_init(dev); //TODO calibrate RC diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h index 13d89eacaf5..0461d5b3144 100644 --- a/drivers/net/wireless/b43/phy_lp.h +++ b/drivers/net/wireless/b43/phy_lp.h @@ -831,6 +831,22 @@ struct b43_phy_lp { /* Transmit isolation high band */ u8 tx_isolation_hi_band; /* FIXME initial value? */ + /* Max transmit power medium band */ + u16 max_tx_pwr_med_band; + /* Max transmit power low band */ + u16 max_tx_pwr_low_band; + /* Max transmit power high band */ + u16 max_tx_pwr_hi_band; + + /* FIXME What are these used for? */ + /* FIXME Is 15 the correct array size? */ + u16 tx_max_rate[15]; + u16 tx_max_ratel[15]; + u16 tx_max_rateh[15]; + + /* Transmit power arrays */ + s16 txpa[3], txpal[3], txpah[3]; + /* Receive power offset */ u8 rx_pwr_offset; /* FIXME initial value? */ -- cgit v1.2.3-18-g5258 From d4de9532fd0b50d486259ace17650a58bbb751c2 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Tue, 11 Aug 2009 21:53:06 +0200 Subject: b43: Implement RC calibration for rev.2+ LP PHYs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 86 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 2bec791041f..296e209a8c1 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -605,6 +605,90 @@ static void lpphy_radio_init(struct b43_wldev *dev) } } +static void lpphy_set_rc_cap(struct b43_wldev *dev) +{ + u8 rc_cap = dev->phy.lp->rc_cap; + + b43_radio_write(dev, B2062_N_RXBB_CALIB2, max_t(u8, rc_cap-4, 0x80)); + b43_radio_write(dev, B2062_N_TX_CTL_A, ((rc_cap & 0x1F) >> 1) | 0x80); + b43_radio_write(dev, B2062_S_RXG_CNT16, ((rc_cap & 0x1F) >> 2) | 0x80); +} + +static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) +{ + //TODO and SPEC FIXME +} + +static void lpphy_rev2plus_rc_calib(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000; + u8 tmp = b43_radio_read(dev, B2063_RX_BB_SP8) & 0xFF; + int i; + + b43_radio_write(dev, B2063_RX_BB_SP8, 0x0); + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); + b43_radio_mask(dev, B2063_PLL_SP1, 0xF7); + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C); + b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x15); + b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x70); + b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x52); + b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1); + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7D); + + for (i = 0; i < 10000; i++) { + if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2) + break; + msleep(1); + } + + if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)) + b43_radio_write(dev, B2063_RX_BB_SP8, tmp); + + tmp = b43_radio_read(dev, B2063_TX_BB_SP3) & 0xFF; + + b43_radio_write(dev, B2063_TX_BB_SP3, 0x0); + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C); + b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x55); + b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x76); + + if (crystal_freq == 24000000) { + b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0xFC); + b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x0); + } else { + b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x13); + b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1); + } + + b43_radio_write(dev, B2063_PA_SP7, 0x7D); + + for (i = 0; i < 10000; i++) { + if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2) + break; + msleep(1); + } + + if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)) + b43_radio_write(dev, B2063_TX_BB_SP3, tmp); + + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); +} + +static void lpphy_calibrate_rc(struct b43_wldev *dev) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + + if (dev->phy.rev >= 2) { + lpphy_rev2plus_rc_calib(dev); + } else if (!lpphy->rc_cap) { + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + lpphy_rev0_1_rc_calib(dev); + } else { + lpphy_set_rc_cap(dev); + } +} + /* Read the TX power control mode from hardware. */ static void lpphy_read_tx_pctl_mode_from_hardware(struct b43_wldev *dev) { @@ -780,7 +864,7 @@ static int b43_lpphy_op_init(struct b43_wldev *dev) lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs? lpphy_baseband_init(dev); lpphy_radio_init(dev); - //TODO calibrate RC + lpphy_calibrate_rc(dev); //TODO set channel lpphy_tx_pctl_init(dev); lpphy_calibration(dev); -- cgit v1.2.3-18-g5258 From 7834ddbcc7a097443761b0722e8c9fb8511b95b1 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 11 Aug 2009 22:57:16 +0300 Subject: usbnet: add rx queue pausing Add rx queue pausing to usbnet. This is needed by rndis_wlan so that it can control rx queue and prevent received packets from being send forward before rndis_wlan receives and handles 'media connect'-indication. Without this establishing WPA connections is hard and fail often. [v2] - removed unneeded use of skb_clone Cc: David Brownell Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/usb/usbnet.c | 44 ++++++++++++++++++++++++++++++++++++++- drivers/net/wireless/rndis_wlan.c | 13 +++++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index af1fe469650..7d471fca274 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -233,6 +233,11 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) { int status; + if (test_bit(EVENT_RX_PAUSED, &dev->flags)) { + skb_queue_tail(&dev->rxq_pause, skb); + return; + } + skb->protocol = eth_type_trans (skb, dev->net); dev->net->stats.rx_packets++; dev->net->stats.rx_bytes += skb->len; @@ -525,6 +530,41 @@ static void intr_complete (struct urb *urb) deverr(dev, "intr resubmit --> %d", status); } +/*-------------------------------------------------------------------------*/ +void usbnet_pause_rx(struct usbnet *dev) +{ + set_bit(EVENT_RX_PAUSED, &dev->flags); + + if (netif_msg_rx_status(dev)) + devdbg(dev, "paused rx queue enabled"); +} +EXPORT_SYMBOL_GPL(usbnet_pause_rx); + +void usbnet_resume_rx(struct usbnet *dev) +{ + struct sk_buff *skb; + int num = 0; + + clear_bit(EVENT_RX_PAUSED, &dev->flags); + + while ((skb = skb_dequeue(&dev->rxq_pause)) != NULL) { + usbnet_skb_return(dev, skb); + num++; + } + + tasklet_schedule(&dev->bh); + + if (netif_msg_rx_status(dev)) + devdbg(dev, "paused rx queue disabled, %d skbs requeued", num); +} +EXPORT_SYMBOL_GPL(usbnet_resume_rx); + +void usbnet_purge_paused_rxq(struct usbnet *dev) +{ + skb_queue_purge(&dev->rxq_pause); +} +EXPORT_SYMBOL_GPL(usbnet_purge_paused_rxq); + /*-------------------------------------------------------------------------*/ // unlink pending rx/tx; completion handlers do all other cleanup @@ -623,6 +663,8 @@ int usbnet_stop (struct net_device *net) usb_kill_urb(dev->interrupt); + usbnet_purge_paused_rxq(dev); + /* deferred work (task, timer, softirq) must also stop. * can't flush_scheduled_work() until we drop rtnl (later), * else workers could deadlock; so make workers a NOP. @@ -1113,7 +1155,6 @@ static void usbnet_bh (unsigned long param) } - /*------------------------------------------------------------------------- * * USB Device Driver support @@ -1210,6 +1251,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) skb_queue_head_init (&dev->rxq); skb_queue_head_init (&dev->txq); skb_queue_head_init (&dev->done); + skb_queue_head_init(&dev->rxq_pause); dev->bh.func = usbnet_bh; dev->bh.data = (unsigned long) dev; INIT_WORK (&dev->kevent, kevent); diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 828dc1825bb..d42692dfbc6 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1764,8 +1764,15 @@ static int rndis_iw_set_essid(struct net_device *dev, if (!wrqu->essid.flags || length == 0) return disassociate(usbdev, 1); - else + else { + /* Pause and purge rx queue, so we don't pass packets before + * 'media connect'-indication. + */ + usbnet_pause_rx(usbdev); + usbnet_purge_paused_rxq(usbdev); + return set_essid(usbdev, &ssid); + } } @@ -2328,6 +2335,8 @@ get_bssid: memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN); wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL); } + + usbnet_resume_rx(usbdev); } if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) { @@ -2541,6 +2550,8 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) switch (msg->status) { case RNDIS_STATUS_MEDIA_CONNECT: + usbnet_pause_rx(usbdev); + devinfo(usbdev, "media connect"); /* queue work to avoid recursive calls into rndis_command */ -- cgit v1.2.3-18-g5258 From 47583154767886a97a82452c8aca63bf0336337a Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Tue, 11 Aug 2009 22:24:22 +0200 Subject: b43: LP-PHY: Refactor TX gain table I/O MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make it possible to write individual gain table entries. Allow gain table entries to be written outside gain table init. Add version-agnostic helpers for writing gain tables. Use the new TX gain table helpers during table init. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/tables_lpphy.c | 85 ++++++++++++++++++--------------- drivers/net/wireless/b43/tables_lpphy.h | 9 ++++ 2 files changed, 55 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/tables_lpphy.c b/drivers/net/wireless/b43/tables_lpphy.c index b056811a170..2721310acb2 100644 --- a/drivers/net/wireless/b43/tables_lpphy.c +++ b/drivers/net/wireless/b43/tables_lpphy.c @@ -1058,10 +1058,6 @@ static const u32 lpphy_papd_mult_table[] = { 0x00036963, 0x000339f2, 0x00030a89, 0x0002db28, }; -struct lpphy_tx_gain_table_entry { - u8 gm, pga, pad, dac, bb_mult; -}; - static struct lpphy_tx_gain_table_entry lpphy_rev0_nopa_tx_gain_table[] = { { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 152, }, { .gm = 7, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 147, }, @@ -2345,44 +2341,55 @@ void lpphy_rev2plus_table_init(struct b43_wldev *dev) } } - -static void lpphy_rev0_1_write_gain_table(struct b43_wldev *dev, - struct lpphy_tx_gain_table_entry *table) +static void lpphy_rev0_1_write_gain_table(struct b43_wldev *dev, int offset, + struct lpphy_tx_gain_table_entry data) { - int i; u32 tmp; B43_WARN_ON(dev->phy.rev >= 2); - for (i = 0; i < 128; i++) { - tmp = table[i].pad << 11; - tmp |= table[i].pga << 7; - tmp |= table[i].gm << 4; - tmp |= table[i].dac; - b43_lptab_write(dev, B43_LPTAB32(10, 0xC0 + i), tmp); - tmp = table[i].bb_mult << 20; - b43_lptab_write(dev, B43_LPTAB32(10, 0x140 + i), tmp); - } + tmp = data.pad << 11; + tmp |= data.pga << 7; + tmp |= data.gm << 4; + tmp |= data.dac; + b43_lptab_write(dev, B43_LPTAB32(10, 0xC0 + offset), tmp); + tmp = data.bb_mult << 20; + b43_lptab_write(dev, B43_LPTAB32(10, 0x140 + offset), tmp); } -static void lpphy_rev2plus_write_gain_table(struct b43_wldev *dev, - struct lpphy_tx_gain_table_entry *table) +static void lpphy_rev2plus_write_gain_table(struct b43_wldev *dev, int offset, + struct lpphy_tx_gain_table_entry data) { - int i; u32 tmp; B43_WARN_ON(dev->phy.rev < 2); - for (i = 0; i < 128; i++) { - tmp = table[i].pad << 16; - tmp |= table[i].pga << 8; - tmp |= table[i].gm; - tmp |= 0x7f000000; - b43_lptab_write(dev, B43_LPTAB32(7, 0xC0 + i), tmp); - tmp = table[i].bb_mult << 20; - tmp |= table[i].dac << 28; - b43_lptab_write(dev, B43_LPTAB32(7, 0x140 + i), tmp); - } + tmp = data.pad << 16; + tmp |= data.pga << 8; + tmp |= data.gm; + tmp |= 0x7f000000; + b43_lptab_write(dev, B43_LPTAB32(7, 0xC0 + offset), tmp); + tmp = data.bb_mult << 20; + tmp |= data.dac << 28; + b43_lptab_write(dev, B43_LPTAB32(7, 0x140 + offset), tmp); +} + +void lpphy_write_gain_table(struct b43_wldev *dev, int offset, + struct lpphy_tx_gain_table_entry data) +{ + if (dev->phy.rev >= 2) + lpphy_rev2plus_write_gain_table(dev, offset, data); + else + lpphy_rev0_1_write_gain_table(dev, offset, data); +} + +void lpphy_write_gain_table_bulk(struct b43_wldev *dev, int offset, int count, + struct lpphy_tx_gain_table_entry *table) +{ + int i; + + for (i = offset; i < count; i++) + lpphy_write_gain_table(dev, i, table[i]); } void lpphy_init_tx_gain_table(struct b43_wldev *dev) @@ -2393,36 +2400,36 @@ void lpphy_init_tx_gain_table(struct b43_wldev *dev) case 0: if ((bus->sprom.boardflags_hi & B43_BFH_NOPA) || (bus->sprom.boardflags_lo & B43_BFL_HGPA)) - lpphy_rev0_1_write_gain_table(dev, + lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev0_nopa_tx_gain_table); else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - lpphy_rev0_1_write_gain_table(dev, + lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev0_2ghz_tx_gain_table); else - lpphy_rev0_1_write_gain_table(dev, + lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev0_5ghz_tx_gain_table); break; case 1: if ((bus->sprom.boardflags_hi & B43_BFH_NOPA) || (bus->sprom.boardflags_lo & B43_BFL_HGPA)) - lpphy_rev0_1_write_gain_table(dev, + lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev1_nopa_tx_gain_table); else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - lpphy_rev0_1_write_gain_table(dev, + lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev1_2ghz_tx_gain_table); else - lpphy_rev0_1_write_gain_table(dev, + lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev1_5ghz_tx_gain_table); break; default: if (bus->sprom.boardflags_hi & B43_BFH_NOPA) - lpphy_rev2plus_write_gain_table(dev, + lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev2_nopa_tx_gain_table); else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - lpphy_rev2plus_write_gain_table(dev, + lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev2_2ghz_tx_gain_table); else - lpphy_rev2plus_write_gain_table(dev, + lpphy_write_gain_table_bulk(dev, 0, 128, lpphy_rev2_5ghz_tx_gain_table); } } diff --git a/drivers/net/wireless/b43/tables_lpphy.h b/drivers/net/wireless/b43/tables_lpphy.h index b5024b6edab..84f1d265f65 100644 --- a/drivers/net/wireless/b43/tables_lpphy.h +++ b/drivers/net/wireless/b43/tables_lpphy.h @@ -28,6 +28,15 @@ void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset, void b2062_upload_init_table(struct b43_wldev *dev); void b2063_upload_init_table(struct b43_wldev *dev); +struct lpphy_tx_gain_table_entry { + u8 gm, pga, pad, dac, bb_mult; +}; + +void lpphy_write_gain_table(struct b43_wldev *dev, int offset, + struct lpphy_tx_gain_table_entry data); +void lpphy_write_gain_table_bulk(struct b43_wldev *dev, int offset, int count, + struct lpphy_tx_gain_table_entry *table); + void lpphy_rev0_1_table_init(struct b43_wldev *dev); void lpphy_rev2plus_table_init(struct b43_wldev *dev); void lpphy_init_tx_gain_table(struct b43_wldev *dev); -- cgit v1.2.3-18-g5258 From aae79e648d93bc9d6b3581ab4eb88e2ac44f5c46 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 12 Aug 2009 14:07:27 +0300 Subject: iwl3945: fix compilation error in iwl3945_pass_packet_to_mac80211() Commit "iwlwifi: Traffic type and counter for debugFs" broke iwl3945 in a case when CONFIG_IWLWIFI_LEDS is disabled: drivers/net/wireless/iwlwifi/iwl-3945.c:580: error: 'hdr' undeclared (first use in this function) Fix it by removing the ifdef check for hdr variable. Signed-off-by: Kalle Valo Acked-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index ae7f1632ccb..ba5ef832d77 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -544,9 +544,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, struct ieee80211_rx_status *stats) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; -#ifdef CONFIG_IWLWIFI_LEDS struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); -#endif struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); short len = le16_to_cpu(rx_hdr->len); -- cgit v1.2.3-18-g5258 From 11aa6e2398f54712b1e1bdeb9d8bf3b452c5a5d5 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 12 Aug 2009 14:42:51 +0300 Subject: wl1251: remove wl1251_ops.c Commit "wl1251: remove wl1251_ops" originally removed file wl1251_ops.c, but while I rebased the patch the removal got lost. Now remote the file for real. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_ops.c | 729 ------------------------------- 1 file changed, 729 deletions(-) delete mode 100644 drivers/net/wireless/wl12xx/wl1251_ops.c (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.c b/drivers/net/wireless/wl12xx/wl1251_ops.c deleted file mode 100644 index 758280af10d..00000000000 --- a/drivers/net/wireless/wl12xx/wl1251_ops.c +++ /dev/null @@ -1,729 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include - -#include "wl1251_ops.h" -#include "reg.h" -#include "wl1251_io.h" -#include "wl1251_spi.h" -#include "wl1251_boot.h" -#include "wl1251_event.h" -#include "wl1251_acx.h" -#include "wl1251_tx.h" -#include "wl1251_rx.h" -#include "wl1251_ps.h" -#include "wl1251_init.h" - -static struct wl1251_partition_set wl1251_part_table[PART_TABLE_LEN] = { - [PART_DOWN] = { - .mem = { - .start = 0x00000000, - .size = 0x00016800 - }, - .reg = { - .start = REGISTERS_BASE, - .size = REGISTERS_DOWN_SIZE - }, - }, - - [PART_WORK] = { - .mem = { - .start = 0x00028000, - .size = 0x00014000 - }, - .reg = { - .start = REGISTERS_BASE, - .size = REGISTERS_WORK_SIZE - }, - }, - - /* WL1251 doesn't use the DRPW partition, so we don't set it here */ -}; - -static enum wl12xx_acx_int_reg wl1251_acx_reg_table[ACX_REG_TABLE_LEN] = { - [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), - [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), - [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), - [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), - [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), - [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), - [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), - [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), - [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), - [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), - [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) -}; - -static int wl1251_upload_firmware(struct wl1251 *wl) -{ - struct wl1251_partition_set *p_table = wl->chip.p_table; - int addr, chunk_num, partition_limit; - size_t fw_data_len; - u8 *p; - - /* whal_FwCtrl_LoadFwImageSm() */ - - wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", - wl1251_reg_read32(wl, CHIP_ID_B)); - - /* 10.0 check firmware length and set partition */ - fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | - (wl->fw[6] << 8) | (wl->fw[7]); - - wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, - CHUNK_SIZE); - - if ((fw_data_len % 4) != 0) { - wl1251_error("firmware length not multiple of four"); - return -EIO; - } - - wl1251_set_partition(wl, - p_table[PART_DOWN].mem.start, - p_table[PART_DOWN].mem.size, - p_table[PART_DOWN].reg.start, - p_table[PART_DOWN].reg.size); - - /* 10.1 set partition limit and chunk num */ - chunk_num = 0; - partition_limit = p_table[PART_DOWN].mem.size; - - while (chunk_num < fw_data_len / CHUNK_SIZE) { - /* 10.2 update partition, if needed */ - addr = p_table[PART_DOWN].mem.start + - (chunk_num + 2) * CHUNK_SIZE; - if (addr > partition_limit) { - addr = p_table[PART_DOWN].mem.start + - chunk_num * CHUNK_SIZE; - partition_limit = chunk_num * CHUNK_SIZE + - p_table[PART_DOWN].mem.size; - wl1251_set_partition(wl, - addr, - p_table[PART_DOWN].mem.size, - p_table[PART_DOWN].reg.start, - p_table[PART_DOWN].reg.size); - } - - /* 10.3 upload the chunk */ - addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; - p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; - wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", - p, addr); - wl1251_mem_write(wl, addr, p, CHUNK_SIZE); - - chunk_num++; - } - - /* 10.4 upload the last chunk */ - addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; - p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; - wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", - fw_data_len % CHUNK_SIZE, p, addr); - wl1251_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); - - return 0; -} - -static int wl1251_upload_nvs(struct wl1251 *wl) -{ - size_t nvs_len, nvs_bytes_written, burst_len; - int nvs_start, i; - u32 dest_addr, val; - u8 *nvs_ptr, *nvs; - - nvs = wl->nvs; - if (nvs == NULL) - return -ENODEV; - - nvs_ptr = nvs; - - nvs_len = wl->nvs_len; - nvs_start = wl->fw_len; - - /* - * Layout before the actual NVS tables: - * 1 byte : burst length. - * 2 bytes: destination address. - * n bytes: data to burst copy. - * - * This is ended by a 0 length, then the NVS tables. - */ - - while (nvs_ptr[0]) { - burst_len = nvs_ptr[0]; - dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); - - /* We move our pointer to the data */ - nvs_ptr += 3; - - for (i = 0; i < burst_len; i++) { - val = (nvs_ptr[0] | (nvs_ptr[1] << 8) - | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); - - wl1251_debug(DEBUG_BOOT, - "nvs burst write 0x%x: 0x%x", - dest_addr, val); - wl1251_mem_write32(wl, dest_addr, val); - - nvs_ptr += 4; - dest_addr += 4; - } - } - - /* - * We've reached the first zero length, the first NVS table - * is 7 bytes further. - */ - nvs_ptr += 7; - nvs_len -= nvs_ptr - nvs; - nvs_len = ALIGN(nvs_len, 4); - - /* Now we must set the partition correctly */ - wl1251_set_partition(wl, nvs_start, - wl->chip.p_table[PART_DOWN].mem.size, - wl->chip.p_table[PART_DOWN].reg.start, - wl->chip.p_table[PART_DOWN].reg.size); - - /* And finally we upload the NVS tables */ - nvs_bytes_written = 0; - while (nvs_bytes_written < nvs_len) { - val = (nvs_ptr[0] | (nvs_ptr[1] << 8) - | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); - - val = cpu_to_le32(val); - - wl1251_debug(DEBUG_BOOT, - "nvs write table 0x%x: 0x%x", - nvs_start, val); - wl1251_mem_write32(wl, nvs_start, val); - - nvs_ptr += 4; - nvs_bytes_written += 4; - nvs_start += 4; - } - - return 0; -} - -static int wl1251_boot(struct wl1251 *wl) -{ - int ret = 0, minor_minor_e2_ver; - u32 tmp, boot_data; - - ret = wl1251_boot_soft_reset(wl); - if (ret < 0) - goto out; - - /* 2. start processing NVS file */ - ret = wl->chip.op_upload_nvs(wl); - if (ret < 0) - goto out; - - /* write firmware's last address (ie. it's length) to - * ACX_EEPROMLESS_IND_REG */ - wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); - - /* 6. read the EEPROM parameters */ - tmp = wl1251_reg_read32(wl, SCR_PAD2); - - /* 7. read bootdata */ - wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; - wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; - tmp = wl1251_reg_read32(wl, SCR_PAD3); - - /* 8. check bootdata and call restart sequence */ - wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; - minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; - - wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " - "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", - wl->boot_attr.radio_type, wl->boot_attr.major, - wl->boot_attr.minor, minor_minor_e2_ver); - - ret = wl1251_boot_init_seq(wl); - if (ret < 0) - goto out; - - /* 9. NVS processing done */ - boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); - - wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); - - /* 10. check that ECPU_CONTROL_HALT bits are set in - * pWhalBus->uBootData and start uploading firmware - */ - if ((boot_data & ECPU_CONTROL_HALT) == 0) { - wl1251_error("boot failed, ECPU_CONTROL_HALT not set"); - ret = -EIO; - goto out; - } - - ret = wl->chip.op_upload_fw(wl); - if (ret < 0) - goto out; - - /* 10.5 start firmware */ - ret = wl1251_boot_run_firmware(wl); - if (ret < 0) - goto out; - -out: - return ret; -} - -static int wl1251_mem_cfg(struct wl1251 *wl) -{ - struct wl1251_acx_config_memory *mem_conf; - int ret, i; - - wl1251_debug(DEBUG_ACX, "wl1251 mem cfg"); - - mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); - if (!mem_conf) { - ret = -ENOMEM; - goto out; - } - - /* memory config */ - mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); - mem_conf->mem_config.rx_mem_block_num = 35; - mem_conf->mem_config.tx_min_mem_block_num = 64; - mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; - mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; - mem_conf->mem_config.num_ssid_profiles = 1; - mem_conf->mem_config.debug_buffer_size = - cpu_to_le16(TRACE_BUFFER_MAX_SIZE); - - /* RX queue config */ - mem_conf->rx_queue_config.dma_address = 0; - mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; - mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; - mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; - - /* TX queue config */ - for (i = 0; i < MAX_TX_QUEUES; i++) { - mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; - mem_conf->tx_queue_config[i].attributes = i; - } - - ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf, - sizeof(*mem_conf)); - if (ret < 0) { - wl1251_warning("wl1251 mem config failed: %d", ret); - goto out; - } - -out: - kfree(mem_conf); - return ret; -} - -static int wl1251_hw_init_mem_config(struct wl1251 *wl) -{ - int ret; - - ret = wl1251_mem_cfg(wl); - if (ret < 0) - return ret; - - wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), - GFP_KERNEL); - if (!wl->target_mem_map) { - wl1251_error("couldn't allocate target memory map"); - return -ENOMEM; - } - - /* we now ask for the firmware built memory map */ - ret = wl1251_acx_mem_map(wl, wl->target_mem_map, - sizeof(struct wl1251_acx_mem_map)); - if (ret < 0) { - wl1251_error("couldn't retrieve firmware memory map"); - kfree(wl->target_mem_map); - wl->target_mem_map = NULL; - return ret; - } - - return 0; -} - -static void wl1251_set_ecpu_ctrl(struct wl1251 *wl, u32 flag) -{ - u32 cpu_ctrl; - - /* 10.5.0 run the firmware (I) */ - cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); - - /* 10.5.1 run the firmware (II) */ - cpu_ctrl &= ~flag; - wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); -} - -static void wl1251_target_enable_interrupts(struct wl1251 *wl) -{ - /* Enable target's interrupts */ - wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | - WL1251_ACX_INTR_RX1_DATA | - WL1251_ACX_INTR_TX_RESULT | - WL1251_ACX_INTR_EVENT_A | - WL1251_ACX_INTR_EVENT_B | - WL1251_ACX_INTR_INIT_COMPLETE; - wl1251_boot_target_enable_interrupts(wl); -} - -static void wl1251_fw_version(struct wl1251 *wl) -{ - wl1251_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver)); -} - -static void wl1251_irq_work(struct work_struct *work) -{ - u32 intr; - struct wl1251 *wl = - container_of(work, struct wl1251, irq_work); - int ret; - - mutex_lock(&wl->mutex); - - wl1251_debug(DEBUG_IRQ, "IRQ work"); - - if (wl->state == WL1251_STATE_OFF) - goto out; - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); - - intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); - wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); - - if (wl->data_path) { - wl->rx_counter = - wl1251_mem_read32(wl, wl->data_path->rx_control_addr); - - /* We handle a firmware bug here */ - switch ((wl->rx_counter - wl->rx_handled) & 0xf) { - case 0: - wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync"); - intr &= ~WL1251_ACX_INTR_RX0_DATA; - intr &= ~WL1251_ACX_INTR_RX1_DATA; - break; - case 1: - wl1251_debug(DEBUG_IRQ, "RX: FW +1"); - intr |= WL1251_ACX_INTR_RX0_DATA; - intr &= ~WL1251_ACX_INTR_RX1_DATA; - break; - case 2: - wl1251_debug(DEBUG_IRQ, "RX: FW +2"); - intr |= WL1251_ACX_INTR_RX0_DATA; - intr |= WL1251_ACX_INTR_RX1_DATA; - break; - default: - wl1251_warning("RX: FW and host out of sync: %d", - wl->rx_counter - wl->rx_handled); - break; - } - - wl->rx_handled = wl->rx_counter; - - - wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); - } - - intr &= wl->intr_mask; - - if (intr == 0) { - wl1251_debug(DEBUG_IRQ, "INTR is 0"); - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, - ~(wl->intr_mask)); - - goto out_sleep; - } - - if (intr & WL1251_ACX_INTR_RX0_DATA) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); - wl1251_rx(wl); - } - - if (intr & WL1251_ACX_INTR_RX1_DATA) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); - wl1251_rx(wl); - } - - if (intr & WL1251_ACX_INTR_TX_RESULT) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); - wl1251_tx_complete(wl); - } - - if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); - if (intr & WL1251_ACX_INTR_EVENT_A) - wl1251_event_handle(wl, 0); - else - wl1251_event_handle(wl, 1); - } - - if (intr & WL1251_ACX_INTR_INIT_COMPLETE) - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); - - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); - -out_sleep: - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - -static int wl1251_hw_init_txq_fill(u8 qid, - struct acx_tx_queue_qos_config *config, - u32 num_blocks) -{ - config->qid = qid; - - switch (qid) { - case QOS_AC_BE: - config->high_threshold = - (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_BE_DEF * num_blocks) / 100; - break; - case QOS_AC_BK: - config->high_threshold = - (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_BK_DEF * num_blocks) / 100; - break; - case QOS_AC_VI: - config->high_threshold = - (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_VI_DEF * num_blocks) / 100; - break; - case QOS_AC_VO: - config->high_threshold = - (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; - config->low_threshold = - (QOS_TX_LOW_VO_DEF * num_blocks) / 100; - break; - default: - wl1251_error("Invalid TX queue id: %d", qid); - return -EINVAL; - } - - return 0; -} - -static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl) -{ - struct acx_tx_queue_qos_config *config; - struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; - int ret, i; - - wl1251_debug(DEBUG_ACX, "acx tx queue config"); - - config = kzalloc(sizeof(*config), GFP_KERNEL); - if (!config) { - ret = -ENOMEM; - goto out; - } - - for (i = 0; i < MAX_NUM_OF_AC; i++) { - ret = wl1251_hw_init_txq_fill(i, config, - wl_mem_map->num_tx_mem_blocks); - if (ret < 0) - goto out; - - ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG, - config, sizeof(*config)); - if (ret < 0) - goto out; - } - -out: - kfree(config); - return ret; -} - -static int wl1251_hw_init_data_path_config(struct wl1251 *wl) -{ - int ret; - - /* asking for the data path parameters */ - wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), - GFP_KERNEL); - if (!wl->data_path) { - wl1251_error("Couldn't allocate data path parameters"); - return -ENOMEM; - } - - ret = wl1251_acx_data_path_params(wl, wl->data_path); - if (ret < 0) { - kfree(wl->data_path); - wl->data_path = NULL; - return ret; - } - - return 0; -} - -static int wl1251_hw_init(struct wl1251 *wl) -{ - struct wl1251_acx_mem_map *wl_mem_map; - int ret; - - ret = wl1251_hw_init_hwenc_config(wl); - if (ret < 0) - return ret; - - /* Template settings */ - ret = wl1251_hw_init_templates_config(wl); - if (ret < 0) - return ret; - - /* Default memory configuration */ - ret = wl1251_hw_init_mem_config(wl); - if (ret < 0) - return ret; - - /* Default data path configuration */ - ret = wl1251_hw_init_data_path_config(wl); - if (ret < 0) - goto out_free_memmap; - - /* RX config */ - ret = wl1251_hw_init_rx_config(wl, - RX_CFG_PROMISCUOUS | RX_CFG_TSF, - RX_FILTER_OPTION_DEF); - /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, - RX_FILTER_OPTION_FILTER_ALL); */ - if (ret < 0) - goto out_free_data_path; - - /* TX queues config */ - ret = wl1251_hw_init_tx_queue_config(wl); - if (ret < 0) - goto out_free_data_path; - - /* PHY layer config */ - ret = wl1251_hw_init_phy_config(wl); - if (ret < 0) - goto out_free_data_path; - - /* Beacon filtering */ - ret = wl1251_hw_init_beacon_filter(wl); - if (ret < 0) - goto out_free_data_path; - - /* Bluetooth WLAN coexistence */ - ret = wl1251_hw_init_pta(wl); - if (ret < 0) - goto out_free_data_path; - - /* Energy detection */ - ret = wl1251_hw_init_energy_detection(wl); - if (ret < 0) - goto out_free_data_path; - - /* Beacons and boradcast settings */ - ret = wl1251_hw_init_beacon_broadcast(wl); - if (ret < 0) - goto out_free_data_path; - - /* Enable data path */ - ret = wl1251_cmd_data_path(wl, wl->channel, 1); - if (ret < 0) - goto out_free_data_path; - - /* Default power state */ - ret = wl1251_hw_init_power_auth(wl); - if (ret < 0) - goto out_free_data_path; - - wl_mem_map = wl->target_mem_map; - wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", - wl_mem_map->num_tx_mem_blocks, - wl->data_path->tx_control_addr, - wl_mem_map->num_rx_mem_blocks, - wl->data_path->rx_control_addr); - - return 0; - - out_free_data_path: - kfree(wl->data_path); - - out_free_memmap: - kfree(wl->target_mem_map); - - return ret; -} - -static int wl1251_plt_init(struct wl1251 *wl) -{ - int ret; - - ret = wl1251_hw_init_mem_config(wl); - if (ret < 0) - return ret; - - ret = wl1251_cmd_data_path(wl, wl->channel, 1); - if (ret < 0) - return ret; - - return 0; -} - -void wl1251_setup(struct wl1251 *wl) -{ - /* FIXME: Is it better to use strncpy here or is this ok? */ - wl->chip.fw_filename = WL1251_FW_NAME; - wl->chip.nvs_filename = WL1251_NVS_NAME; - - /* Now we know what chip we're using, so adjust the power on sleep - * time accordingly */ - wl->chip.power_on_sleep = WL1251_POWER_ON_SLEEP; - - wl->chip.intr_cmd_complete = WL1251_ACX_INTR_CMD_COMPLETE; - wl->chip.intr_init_complete = WL1251_ACX_INTR_INIT_COMPLETE; - - wl->chip.op_upload_nvs = wl1251_upload_nvs; - wl->chip.op_upload_fw = wl1251_upload_firmware; - wl->chip.op_boot = wl1251_boot; - wl->chip.op_set_ecpu_ctrl = wl1251_set_ecpu_ctrl; - wl->chip.op_target_enable_interrupts = wl1251_target_enable_interrupts; - wl->chip.op_hw_init = wl1251_hw_init; - wl->chip.op_plt_init = wl1251_plt_init; - wl->chip.op_fw_version = wl1251_fw_version; - wl->chip.op_tx_flush = wl1251_tx_flush; - wl->chip.op_cmd_join = wl1251_cmd_join; - - wl->chip.p_table = wl1251_part_table; - wl->chip.acx_reg_table = wl1251_acx_reg_table; - - INIT_WORK(&wl->irq_work, wl1251_irq_work); - INIT_WORK(&wl->tx_work, wl1251_tx_work); - -} -- cgit v1.2.3-18-g5258 From 5ef5da0ff2fc4f04c856f4ce9a757e318a02ad06 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 12 Aug 2009 14:42:59 +0300 Subject: wl1251: remove unused definitions from wl1251_reg.h Luis reported that IRQ_MASK conflicts with include/pcmcia/cs.h on compat-wireless. Remove that and a bunch of other unused defines from wl1251_reg.h. Reported-by: Luis R. Rodriguez Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_reg.h | 100 ------------------------------- 1 file changed, 100 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_reg.h b/drivers/net/wireless/wl12xx/wl1251_reg.h index 2de47cc32b8..bdd561001dc 100644 --- a/drivers/net/wireless/wl12xx/wl1251_reg.h +++ b/drivers/net/wireless/wl12xx/wl1251_reg.h @@ -42,70 +42,6 @@ /* ELP WLAN_READY bit */ #define ELPCTRL_WLAN_READY 0x2 -/* - * Interrupt registers. - * 64 bit interrupt sources registers ws ced. - * sme interupts were removed and new ones were added. - * Order was changed. - */ -#define FIQ_MASK (REGISTERS_BASE + 0x0400) -#define FIQ_MASK_L (REGISTERS_BASE + 0x0400) -#define FIQ_MASK_H (REGISTERS_BASE + 0x0404) -#define FIQ_MASK_SET (REGISTERS_BASE + 0x0408) -#define FIQ_MASK_SET_L (REGISTERS_BASE + 0x0408) -#define FIQ_MASK_SET_H (REGISTERS_BASE + 0x040C) -#define FIQ_MASK_CLR (REGISTERS_BASE + 0x0410) -#define FIQ_MASK_CLR_L (REGISTERS_BASE + 0x0410) -#define FIQ_MASK_CLR_H (REGISTERS_BASE + 0x0414) -#define IRQ_MASK (REGISTERS_BASE + 0x0418) -#define IRQ_MASK_L (REGISTERS_BASE + 0x0418) -#define IRQ_MASK_H (REGISTERS_BASE + 0x041C) -#define IRQ_MASK_SET (REGISTERS_BASE + 0x0420) -#define IRQ_MASK_SET_L (REGISTERS_BASE + 0x0420) -#define IRQ_MASK_SET_H (REGISTERS_BASE + 0x0424) -#define IRQ_MASK_CLR (REGISTERS_BASE + 0x0428) -#define IRQ_MASK_CLR_L (REGISTERS_BASE + 0x0428) -#define IRQ_MASK_CLR_H (REGISTERS_BASE + 0x042C) -#define ECPU_MASK (REGISTERS_BASE + 0x0448) -#define FIQ_STS_L (REGISTERS_BASE + 0x044C) -#define FIQ_STS_H (REGISTERS_BASE + 0x0450) -#define IRQ_STS_L (REGISTERS_BASE + 0x0454) -#define IRQ_STS_H (REGISTERS_BASE + 0x0458) -#define INT_STS_ND (REGISTERS_BASE + 0x0464) -#define INT_STS_RAW_L (REGISTERS_BASE + 0x0464) -#define INT_STS_RAW_H (REGISTERS_BASE + 0x0468) -#define INT_STS_CLR (REGISTERS_BASE + 0x04B4) -#define INT_STS_CLR_L (REGISTERS_BASE + 0x04B4) -#define INT_STS_CLR_H (REGISTERS_BASE + 0x04B8) -#define INT_ACK (REGISTERS_BASE + 0x046C) -#define INT_ACK_L (REGISTERS_BASE + 0x046C) -#define INT_ACK_H (REGISTERS_BASE + 0x0470) -#define INT_TRIG (REGISTERS_BASE + 0x0474) -#define INT_TRIG_L (REGISTERS_BASE + 0x0474) -#define INT_TRIG_H (REGISTERS_BASE + 0x0478) -#define HOST_STS_L (REGISTERS_BASE + 0x045C) -#define HOST_STS_H (REGISTERS_BASE + 0x0460) -#define HOST_MASK (REGISTERS_BASE + 0x0430) -#define HOST_MASK_L (REGISTERS_BASE + 0x0430) -#define HOST_MASK_H (REGISTERS_BASE + 0x0434) -#define HOST_MASK_SET (REGISTERS_BASE + 0x0438) -#define HOST_MASK_SET_L (REGISTERS_BASE + 0x0438) -#define HOST_MASK_SET_H (REGISTERS_BASE + 0x043C) -#define HOST_MASK_CLR (REGISTERS_BASE + 0x0440) -#define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440) -#define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444) - -/* Host Interrupts*/ -#define HINT_MASK (REGISTERS_BASE + 0x0494) -#define HINT_MASK_SET (REGISTERS_BASE + 0x0498) -#define HINT_MASK_CLR (REGISTERS_BASE + 0x049C) -#define HINT_STS_ND_MASKED (REGISTERS_BASE + 0x04A0) -/*1150 spec calls this HINT_STS_RAW*/ -#define HINT_STS_ND (REGISTERS_BASE + 0x04B0) -#define HINT_STS_CLR (REGISTERS_BASE + 0x04A4) -#define HINT_ACK (REGISTERS_BASE + 0x04A8) -#define HINT_TRIG (REGISTERS_BASE + 0x04AC) - /* Device Configuration registers*/ #define SOR_CFG (REGISTERS_BASE + 0x0800) #define ECPU_CTRL (REGISTERS_BASE + 0x0804) @@ -419,16 +355,6 @@ enum wl12xx_acx_int_reg { | CFG_RX_PRSP_EN) -/*=============================================== - Phy regs - ===============================================*/ -#define ACX_PHY_ADDR_REG SBB_ADDR -#define ACX_PHY_DATA_REG SBB_DATA -#define ACX_PHY_CTRL_REG SBB_CTL -#define ACX_PHY_REG_WR_MASK 0x00000001ul -#define ACX_PHY_REG_RD_MASK 0x00000002ul - - /*=============================================== EEPROM Read/Write Request 32bit RW ------------------------------------------ @@ -498,28 +424,6 @@ enum wl12xx_acx_int_reg { #define ACX_CONT_WIND_MIN_MASK 0x0000007f #define ACX_CONT_WIND_MAX 0x03ff0000 -/* - * Indirect slave register/memory registers - * ---------------------------------------- - */ -#define HW_SLAVE_REG_ADDR_REG 0x00000004 -#define HW_SLAVE_REG_DATA_REG 0x00000008 -#define HW_SLAVE_REG_CTRL_REG 0x0000000c - -#define SLAVE_AUTO_INC 0x00010000 -#define SLAVE_NO_AUTO_INC 0x00000000 -#define SLAVE_HOST_LITTLE_ENDIAN 0x00000000 - -#define HW_SLAVE_MEM_ADDR_REG SLV_MEM_ADDR -#define HW_SLAVE_MEM_DATA_REG SLV_MEM_DATA -#define HW_SLAVE_MEM_CTRL_REG SLV_MEM_CTL -#define HW_SLAVE_MEM_ENDIAN_REG SLV_END_CTL - -#define HW_FUNC_EVENT_INT_EN 0x8000 -#define HW_FUNC_EVENT_MASK_REG 0x00000034 - -#define ACX_MAC_TIMESTAMP_REG (MAC_TIMESTAMP) - /*=============================================== HI_CFG Interface Configuration Register Values ------------------------------------------ @@ -678,10 +582,6 @@ b12-b0 - Supported Rate indicator bits as defined below. ******************************************************************************/ -#define TNETW1251_CHIP_ID_PG1_0 0x07010101 -#define TNETW1251_CHIP_ID_PG1_1 0x07020101 -#define TNETW1251_CHIP_ID_PG1_2 0x07030101 - /************************************************************************* Interrupt Trigger Register (Host -> WiLink) -- cgit v1.2.3-18-g5258 From d15dd3e5d74186a3b0a4db271b440bbdc0f6da36 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 12 Aug 2009 09:56:59 -0700 Subject: ath: add common ath_rxbuf_alloc() and make ath9k use it Turns out ath5k and ath9k can share the same helper to allocates RX skbs. We allocate skbs aligned to the cache line size. This requirement seems to have come from AR5210; when this was not done it seems sometimes we'd get bogus data. I'm also told it may have been a performance enhancement consideration. In the end I can't be sure we can remove this on new hardware so just keep this and start sharing it through ath.ko. Make ath9k start using this, ath5k is next. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/Kconfig | 4 +--- drivers/net/wireless/ath/ath.h | 30 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/ath9k.h | 4 +++- drivers/net/wireless/ath/ath9k/main.c | 2 +- drivers/net/wireless/ath/ath9k/recv.c | 40 ++++------------------------------ drivers/net/wireless/ath/main.c | 36 ++++++++++++++++++++++++++++++ 6 files changed, 75 insertions(+), 41 deletions(-) create mode 100644 drivers/net/wireless/ath/ath.h (limited to 'drivers') diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 253b95a264b..11ded150b93 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -5,9 +5,7 @@ menuconfig ATH_COMMON ---help--- This will enable the support for the Atheros wireless drivers. ath5k, ath9k and ar9170 drivers share some common code, this option - enables the common ath.ko module which currently shares just common - regulatory EEPROM helpers but will likely be extended later to share - more between modules. + enables the common ath.ko module which shares common helpers. For more information and documentation on this module you can visit: diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h new file mode 100644 index 00000000000..e284cd3ac6d --- /dev/null +++ b/drivers/net/wireless/ath/ath.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef ATH_H +#define ATH_H + +#include + +struct ath_common { + u16 cachelsz; +}; + +struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, + u32 len, + gfp_t gfp_mask); + +#endif /* ATH_H */ diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 7a5a157e15c..2fd663c01b8 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -25,6 +25,7 @@ #include "hw.h" #include "rc.h" #include "debug.h" +#include "../ath.h" struct ath_node; @@ -532,6 +533,8 @@ struct ath_softc { struct ieee80211_hw *hw; struct device *dev; + struct ath_common common; + spinlock_t wiphy_lock; /* spinlock to protect ath_wiphy data */ struct ath_wiphy *pri_wiphy; struct ath_wiphy **sec_wiphy; /* secondary wiphys (virtual radios); may @@ -564,7 +567,6 @@ struct ath_softc { u32 sc_flags; /* SC_OP_* */ u16 curtxpow; u16 curaid; - u16 cachelsz; u8 nbcnvifs; u16 nvifs; u8 tx_chainmask; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index efe2e856397..b29d0ff7451 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1327,7 +1327,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc) */ ath_read_cachesize(sc, &csz); /* XXX assert csz is non-zero */ - sc->cachelsz = csz << 2; /* convert to bytes */ + sc->common.cachelsz = csz << 2; /* convert to bytes */ ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); if (!ah) { diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 1a08c694fe5..61dbdd22744 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -100,38 +100,6 @@ static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp) return (tsf & ~0x7fff) | rstamp; } -static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len, gfp_t gfp_mask) -{ - struct sk_buff *skb; - u32 off; - - /* - * Cache-line-align. This is important (for the - * 5210 at least) as not doing so causes bogus data - * in rx'd frames. - */ - - /* Note: the kernel can allocate a value greater than - * what we ask it to give us. We really only need 4 KB as that - * is this hardware supports and in fact we need at least 3849 - * as that is the MAX AMSDU size this hardware supports. - * Unfortunately this means we may get 8 KB here from the - * kernel... and that is actually what is observed on some - * systems :( */ - skb = __dev_alloc_skb(len + sc->cachelsz - 1, gfp_mask); - if (skb != NULL) { - off = ((unsigned long) skb->data) % sc->cachelsz; - if (off != 0) - skb_reserve(skb, sc->cachelsz - off); - } else { - DPRINTF(sc, ATH_DBG_FATAL, - "skbuff alloc of size %u failed\n", len); - return NULL; - } - - return skb; -} - /* * For Decrypt or Demic errors, we only mark packet status here and always push * up the frame up to let mac80211 handle the actual error case, be it no @@ -336,10 +304,10 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) spin_lock_init(&sc->rx.rxbuflock); sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN, - min(sc->cachelsz, (u16)64)); + min(sc->common.cachelsz, (u16)64)); DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", - sc->cachelsz, sc->rx.bufsize); + sc->common.cachelsz, sc->rx.bufsize); /* Initialize rx descriptors */ @@ -352,7 +320,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) } list_for_each_entry(bf, &sc->rx.rxbuf, list) { - skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_KERNEL); + skb = ath_rxbuf_alloc(&sc->common, sc->rx.bufsize, GFP_KERNEL); if (skb == NULL) { error = -ENOMEM; goto err; @@ -777,7 +745,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) /* Ensure we always have an skb to requeue once we are done * processing the current buffer's skb */ - requeue_skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_ATOMIC); + requeue_skb = ath_rxbuf_alloc(&sc->common, sc->rx.bufsize, GFP_ATOMIC); /* If there is no memory we ignore the current RX'd frame, * tell hardware it can give us a new frame using the old diff --git a/drivers/net/wireless/ath/main.c b/drivers/net/wireless/ath/main.c index 9949b11cb15..487193f1de1 100644 --- a/drivers/net/wireless/ath/main.c +++ b/drivers/net/wireless/ath/main.c @@ -17,6 +17,42 @@ #include #include +#include "ath.h" + MODULE_AUTHOR("Atheros Communications"); MODULE_DESCRIPTION("Shared library for Atheros wireless LAN cards."); MODULE_LICENSE("Dual BSD/GPL"); + +struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, + u32 len, + gfp_t gfp_mask) +{ + struct sk_buff *skb; + u32 off; + + /* + * Cache-line-align. This is important (for the + * 5210 at least) as not doing so causes bogus data + * in rx'd frames. + */ + + /* Note: the kernel can allocate a value greater than + * what we ask it to give us. We really only need 4 KB as that + * is this hardware supports and in fact we need at least 3849 + * as that is the MAX AMSDU size this hardware supports. + * Unfortunately this means we may get 8 KB here from the + * kernel... and that is actually what is observed on some + * systems :( */ + skb = __dev_alloc_skb(len + common->cachelsz - 1, gfp_mask); + if (skb != NULL) { + off = ((unsigned long) skb->data) % common->cachelsz; + if (off != 0) + skb_reserve(skb, common->cachelsz - off); + } else { + printk(KERN_ERR "skbuff alloc of size %u failed\n", len); + return NULL; + } + + return skb; +} +EXPORT_SYMBOL(ath_rxbuf_alloc); -- cgit v1.2.3-18-g5258 From aeb63cfd4ccc813c204a0d81ad6c5a90c33d8f61 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 12 Aug 2009 09:57:00 -0700 Subject: ath5k: use common ath.ko ath_rxbuf_alloc() Now that its shared we can remove ath5k's own implementation. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 21 +++++++-------------- drivers/net/wireless/ath/ath5k/base.h | 3 ++- 2 files changed, 9 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index acbcfc2a9f7..63c2b5714d2 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -544,7 +544,7 @@ ath5k_pci_probe(struct pci_dev *pdev, __set_bit(ATH_STAT_INVALID, sc->status); sc->iobase = mem; /* So we can unmap it on detach */ - sc->cachelsz = csz * sizeof(u32); /* convert to bytes */ + sc->common.cachelsz = csz * sizeof(u32); /* convert to bytes */ sc->opmode = NL80211_IFTYPE_STATION; sc->bintval = 1000; mutex_init(&sc->lock); @@ -1151,27 +1151,20 @@ static struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr) { struct sk_buff *skb; - unsigned int off; /* * Allocate buffer with headroom_needed space for the * fake physical layer header at the start. */ - skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1); + skb = ath_rxbuf_alloc(&sc->common, + sc->rxbufsize + sc->common.cachelsz - 1, + GFP_ATOMIC); if (!skb) { ATH5K_ERR(sc, "can't alloc skbuff of size %u\n", - sc->rxbufsize + sc->cachelsz - 1); + sc->rxbufsize + sc->common.cachelsz - 1); return NULL; } - /* - * Cache-line-align. This is important (for the - * 5210 at least) as not doing so causes bogus data - * in rx'd frames. - */ - off = ((unsigned long)skb->data) % sc->cachelsz; - if (off != 0) - skb_reserve(skb, sc->cachelsz - off); *skb_addr = pci_map_single(sc->pdev, skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE); @@ -1613,10 +1606,10 @@ ath5k_rx_start(struct ath5k_softc *sc) struct ath5k_buf *bf; int ret; - sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->cachelsz); + sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->common.cachelsz); ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n", - sc->cachelsz, sc->rxbufsize); + sc->common.cachelsz, sc->rxbufsize); spin_lock_bh(&sc->rxbuflock); sc->rxlink = NULL; diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 667bd9dc190..25a72a85aaa 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -50,6 +50,7 @@ #include "ath5k.h" #include "debug.h" +#include "../ath.h" #define ATH_RXBUF 40 /* number of RX buffers */ #define ATH_TXBUF 200 /* number of TX buffers */ @@ -112,6 +113,7 @@ struct ath5k_rfkill { * associated with an instance of a device */ struct ath5k_softc { struct pci_dev *pdev; /* for dma mapping */ + struct ath_common common; void __iomem *iobase; /* address of the device */ struct mutex lock; /* dev-level lock */ struct ieee80211_tx_queue_stats tx_stats[AR5K_NUM_TX_QUEUES]; @@ -134,7 +136,6 @@ struct ath5k_softc { struct ath5k_desc *desc; /* TX/RX descriptors */ dma_addr_t desc_daddr; /* DMA (physical) address */ size_t desc_len; /* size of TX/RX descriptors */ - u16 cachelsz; /* cache line size */ DECLARE_BITMAP(status, 5); #define ATH_STAT_INVALID 0 /* disable hardware accesses */ -- cgit v1.2.3-18-g5258 From 13311b00117ed1bf903cf8870432504631a7ce77 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 12 Aug 2009 09:57:01 -0700 Subject: ath5k: use bit shift operators for cache line size This matches ath9k, providing consistency when reading both drivers. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 63c2b5714d2..2b3cf39dd4b 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -471,7 +471,7 @@ ath5k_pci_probe(struct pci_dev *pdev, * DMA to work so force a reasonable value here if it * comes up zero. */ - csz = L1_CACHE_BYTES / sizeof(u32); + csz = L1_CACHE_BYTES >> 2; pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); } /* @@ -544,7 +544,7 @@ ath5k_pci_probe(struct pci_dev *pdev, __set_bit(ATH_STAT_INVALID, sc->status); sc->iobase = mem; /* So we can unmap it on detach */ - sc->common.cachelsz = csz * sizeof(u32); /* convert to bytes */ + sc->common.cachelsz = csz << 2; /* convert to bytes */ sc->opmode = NL80211_IFTYPE_STATION; sc->bintval = 1000; mutex_init(&sc->lock); -- cgit v1.2.3-18-g5258 From 2a219eb26793fc4c47b3ad7b84bded7b66f6e2c4 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 12 Aug 2009 14:45:16 -0700 Subject: ath9k: update kconfig to indicate support for AR9002 family ath9k supports the AR9002 family of chipsets. This includes the AR9285 and the miniPCI AR9223 and AR9220 (which themselves have AR9280+AR5133). We now refer people to the wiki page as it seems this is not as popular as we would have hoped. Reported-by: JD Cc: Dakota Lee Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/Kconfig | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 2cb72f8c32d..ef5f59c4dd8 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -6,7 +6,13 @@ config ATH9K select NEW_LEDS ---help--- This module adds support for wireless adapters based on - Atheros IEEE 802.11n AR5008 and AR9001 family of chipsets. + Atheros IEEE 802.11n AR5008, AR9001 and AR9002 family + of chipsets. For a specific list of supported external + cards, laptops that already ship with these cards and + APs that come with these cards refer to to ath9k wiki + products page: + + http://wireless.kernel.org/en/users/Drivers/ath9k/products If you choose to build a module, it'll be called ath9k. -- cgit v1.2.3-18-g5258 From 1aa8e84736fb1a584c679f2893245826583a0526 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 13 Aug 2009 09:34:25 +0530 Subject: ath9k: Remove has_hw_phycounters PHY counters are available in all chipsets supported by ath9k. Remove the check. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ani.c | 195 +++++++++++++++------------------- drivers/net/wireless/ath/ath9k/ani.h | 1 - drivers/net/wireless/ath/ath9k/hw.h | 1 - drivers/net/wireless/ath/ath9k/main.c | 3 +- 4 files changed, 88 insertions(+), 112 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index b7093126dbb..f264097a2f4 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -236,36 +236,35 @@ static void ath9k_ani_restart(struct ath_hw *ah) return; aniState = ah->curani; - aniState->listenTime = 0; - if (ah->has_hw_phycounters) { - if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { - aniState->ofdmPhyErrBase = 0; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "OFDM Trigger is too high for hw counters\n"); - } else { - aniState->ofdmPhyErrBase = - AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; - } - if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { - aniState->cckPhyErrBase = 0; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "CCK Trigger is too high for hw counters\n"); - } else { - aniState->cckPhyErrBase = - AR_PHY_COUNTMAX - aniState->cckTrigHigh; - } + + if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { + aniState->ofdmPhyErrBase = 0; DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Writing ofdmbase=%u cckbase=%u\n", - aniState->ofdmPhyErrBase, - aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); - - ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); + "OFDM Trigger is too high for hw counters\n"); + } else { + aniState->ofdmPhyErrBase = + AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; + } + if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { + aniState->cckPhyErrBase = 0; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "CCK Trigger is too high for hw counters\n"); + } else { + aniState->cckPhyErrBase = + AR_PHY_COUNTMAX - aniState->cckTrigHigh; } + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Writing ofdmbase=%u cckbase=%u\n", + aniState->ofdmPhyErrBase, + aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); + + ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); + aniState->ofdmPhyErrCount = 0; aniState->cckPhyErrCount = 0; } @@ -530,18 +529,12 @@ void ath9k_ani_reset(struct ath_hw *ah) if (aniState->firstepLevel != 0) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel); - if (ah->has_hw_phycounters) { - ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & - ~ATH9K_RX_FILTER_PHYERR); - ath9k_ani_restart(ah); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); - } else { - ath9k_ani_restart(ah); - ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | - ATH9K_RX_FILTER_PHYERR); - } + ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & + ~ATH9K_RX_FILTER_PHYERR); + ath9k_ani_restart(ah); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); } void ath9k_hw_ani_monitor(struct ath_hw *ah, @@ -550,6 +543,8 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, { struct ar5416AniState *aniState; int32_t listenTime; + u32 phyCnt1, phyCnt2; + u32 ofdmPhyErrCnt, cckPhyErrCnt; if (!DO_ANI(ah)) return; @@ -566,50 +561,45 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, aniState->listenTime += listenTime; - if (ah->has_hw_phycounters) { - u32 phyCnt1, phyCnt2; - u32 ofdmPhyErrCnt, cckPhyErrCnt; + ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); - ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); - - phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); - phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); - - if (phyCnt1 < aniState->ofdmPhyErrBase || - phyCnt2 < aniState->cckPhyErrBase) { - if (phyCnt1 < aniState->ofdmPhyErrBase) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "phyCnt1 0x%x, resetting " - "counter value to 0x%x\n", - phyCnt1, aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_1, - aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, - AR_PHY_ERR_OFDM_TIMING); - } - if (phyCnt2 < aniState->cckPhyErrBase) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "phyCnt2 0x%x, resetting " - "counter value to 0x%x\n", - phyCnt2, aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, - aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, - AR_PHY_ERR_CCK_TIMING); - } - return; + phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); + phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); + + if (phyCnt1 < aniState->ofdmPhyErrBase || + phyCnt2 < aniState->cckPhyErrBase) { + if (phyCnt1 < aniState->ofdmPhyErrBase) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "phyCnt1 0x%x, resetting " + "counter value to 0x%x\n", + phyCnt1, aniState->ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_1, + aniState->ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, + AR_PHY_ERR_OFDM_TIMING); + } + if (phyCnt2 < aniState->cckPhyErrBase) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "phyCnt2 0x%x, resetting " + "counter value to 0x%x\n", + phyCnt2, aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_2, + aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, + AR_PHY_ERR_CCK_TIMING); } + return; + } - ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; - ah->stats.ast_ani_ofdmerrs += - ofdmPhyErrCnt - aniState->ofdmPhyErrCount; - aniState->ofdmPhyErrCount = ofdmPhyErrCnt; + ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; + ah->stats.ast_ani_ofdmerrs += + ofdmPhyErrCnt - aniState->ofdmPhyErrCount; + aniState->ofdmPhyErrCount = ofdmPhyErrCnt; - cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; - ah->stats.ast_ani_cckerrs += - cckPhyErrCnt - aniState->cckPhyErrCount; - aniState->cckPhyErrCount = cckPhyErrCnt; - } + cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; + ah->stats.ast_ani_cckerrs += + cckPhyErrCnt - aniState->cckPhyErrCount; + aniState->cckPhyErrCount = cckPhyErrCnt; if (aniState->listenTime > 5 * ah->aniperiod) { if (aniState->ofdmPhyErrCount <= aniState->listenTime * @@ -632,11 +622,6 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, } } -bool ath9k_hw_phycounters(struct ath_hw *ah) -{ - return ah->has_hw_phycounters ? true : false; -} - void ath9k_enable_mib_counters(struct ath_hw *ah) { DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n"); @@ -781,9 +766,7 @@ void ath9k_hw_ani_init(struct ath_hw *ah) { int i; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n"); - - ah->has_hw_phycounters = 1; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Initialize ANI\n"); memset(ah->ani, 0, sizeof(ah->ani)); for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { @@ -799,24 +782,22 @@ void ath9k_hw_ani_init(struct ath_hw *ah) ATH9K_ANI_CCK_WEAK_SIG_THR; ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL; - if (ah->has_hw_phycounters) { - ah->ani[i].ofdmPhyErrBase = - AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH; - ah->ani[i].cckPhyErrBase = - AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; - } - } - if (ah->has_hw_phycounters) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Setting OfdmErrBase = 0x%08x\n", - ah->ani[0].ofdmPhyErrBase); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", - ah->ani[0].cckPhyErrBase); - - REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase); - ath9k_enable_mib_counters(ah); + ah->ani[i].ofdmPhyErrBase = + AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH; + ah->ani[i].cckPhyErrBase = + AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; } + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Setting OfdmErrBase = 0x%08x\n", + ah->ani[0].ofdmPhyErrBase); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", + ah->ani[0].cckPhyErrBase); + + REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase); + ath9k_enable_mib_counters(ah); + ah->aniperiod = ATH9K_ANI_PERIOD; if (ah->config.enable_ani) ah->proc_phyerr |= HAL_PROCESS_ANI; @@ -826,9 +807,7 @@ void ath9k_hw_ani_disable(struct ath_hw *ah) { DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disabling ANI\n"); - if (ah->has_hw_phycounters) { - ath9k_hw_disable_mib_counters(ah); - REG_WRITE(ah, AR_PHY_ERR_1, 0); - REG_WRITE(ah, AR_PHY_ERR_2, 0); - } + ath9k_hw_disable_mib_counters(ah); + REG_WRITE(ah, AR_PHY_ERR_1, 0); + REG_WRITE(ah, AR_PHY_ERR_2, 0); } diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index a36b7bb7c42..119924511f8 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -124,7 +124,6 @@ void ath9k_ani_reset(struct ath_hw *ah); void ath9k_hw_ani_monitor(struct ath_hw *ah, const struct ath9k_node_stats *stats, struct ath9k_channel *chan); -bool ath9k_hw_phycounters(struct ath_hw *ah); void ath9k_enable_mib_counters(struct ath_hw *ah); void ath9k_hw_disable_mib_counters(struct ath_hw *ah); u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt, diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index e83e900e275..0e65873cc27 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -507,7 +507,6 @@ struct ath_hw { /* ANI */ u32 proc_phyerr; - bool has_hw_phycounters; u32 aniperiod; struct ar5416AniState *curani; struct ar5416AniState ani[255]; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b29d0ff7451..3eb6dc0c8e2 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2214,8 +2214,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, if ((conf->type == NL80211_IFTYPE_STATION) || (conf->type == NL80211_IFTYPE_ADHOC) || (conf->type == NL80211_IFTYPE_MESH_POINT)) { - if (ath9k_hw_phycounters(sc->sc_ah)) - sc->imask |= ATH9K_INT_MIB; + sc->imask |= ATH9K_INT_MIB; sc->imask |= ATH9K_INT_TSFOOR; } -- cgit v1.2.3-18-g5258 From 1cf6873a191388ff7d06bbd70f68bbffe1d70019 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 13 Aug 2009 09:34:32 +0530 Subject: ath9k: Remove duplicate variables diversity_control and antenna_switch_swap are already present in ath9k_ops_config. Remove duplicate occurrences in ath_hw. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 7 ++----- drivers/net/wireless/ath/ath9k/hw.h | 16 +++++++--------- drivers/net/wireless/ath/ath9k/phy.c | 12 +++++------- 3 files changed, 14 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 6514dc7a7be..9f1b34d9861 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -407,7 +407,7 @@ static void ath9k_hw_init_config(struct ath_hw *ah) ah->config.cck_trig_high = 200; ah->config.cck_trig_low = 100; ah->config.enable_ani = 1; - ah->config.diversity_control = 0; + ah->config.diversity_control = ATH9K_ANT_VARIABLE; ah->config.antenna_switch_swap = 0; for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { @@ -452,9 +452,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ah->regulatory.power_limit = MAX_RATE_POWER; ah->regulatory.tp_scale = ATH9K_TP_SCALE_MAX; ah->atim_window = 0; - ah->diversity_control = ah->config.diversity_control; - ah->antenna_switch_swap = - ah->config.antenna_switch_swap; ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE; ah->beacon_interval = 100; ah->enable_32kHz_clock = DONT_USE_32KHZ; @@ -3891,7 +3888,7 @@ bool ath9k_hw_setantennaswitch(struct ath_hw *ah, break; } } else { - ah->diversity_control = settings; + ah->config.diversity_control = settings; } return true; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 0e65873cc27..0336981a70e 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -127,6 +127,12 @@ enum wireless_mode { ATH9K_MODE_MAX, }; +enum ath9k_ant_setting { + ATH9K_ANT_VARIABLE = 0, + ATH9K_ANT_FIXED_A, + ATH9K_ANT_FIXED_B +}; + enum ath9k_hw_caps { ATH9K_HW_CAP_MIC_AESCCM = BIT(0), ATH9K_HW_CAP_MIC_CKIP = BIT(1), @@ -191,7 +197,7 @@ struct ath9k_ops_config { u32 cck_trig_high; u32 cck_trig_low; u32 enable_ani; - u16 diversity_control; + enum ath9k_ant_setting diversity_control; u16 antenna_switch_swap; int serialize_regmode; bool intr_mitigation; @@ -330,12 +336,6 @@ enum ath9k_power_mode { ATH9K_PM_UNDEFINED }; -enum ath9k_ant_setting { - ATH9K_ANT_VARIABLE = 0, - ATH9K_ANT_FIXED_A, - ATH9K_ANT_FIXED_B -}; - enum ath9k_tp_scale { ATH9K_TP_SCALE_MAX = 0, ATH9K_TP_SCALE_50, @@ -437,8 +437,6 @@ struct ath_hw { u32 txurn_interrupt_mask; bool chip_fullsleep; u32 atim_window; - u16 antenna_switch_swap; - enum ath9k_ant_setting diversity_control; /* Calibration */ enum ath9k_cal_types supp_cals; diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index 59bb3ce1e64..63bf9a307c6 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -353,18 +353,16 @@ ath9k_hw_decrease_chain_power(struct ath_hw *ah, struct ath9k_channel *chan) u32 bank6SelMask; u32 *bank6Temp = ah->bank6Temp; - switch (ah->diversity_control) { + switch (ah->config.diversity_control) { case ATH9K_ANT_FIXED_A: bank6SelMask = - (ah-> - antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_0 : - REDUCE_CHAIN_1; + (ah->config.antenna_switch_swap & ANTSWAP_AB) ? + REDUCE_CHAIN_0 : REDUCE_CHAIN_1; break; case ATH9K_ANT_FIXED_B: bank6SelMask = - (ah-> - antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_1 : - REDUCE_CHAIN_0; + (ah->config.antenna_switch_swap & ANTSWAP_AB) ? + REDUCE_CHAIN_1 : REDUCE_CHAIN_0; break; case ATH9K_ANT_VARIABLE: return; -- cgit v1.2.3-18-g5258 From 523c36fc9cf75ccf605d9acf68ae9eb857de3f58 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 13 Aug 2009 09:34:35 +0530 Subject: ath9k: Fix bug in PCI resume This patch fixes a bug where the device was enabled before restoring the PCI state. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 3546504a83c..616bdff2b6a 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -253,10 +253,12 @@ static int ath_pci_resume(struct pci_dev *pdev) u32 val; int err; + pci_restore_state(pdev); + err = pci_enable_device(pdev); if (err) return err; - pci_restore_state(pdev); + /* * Suspend/Resume resets the PCI configuration space, so we have to * re-disable the RETRY_TIMEOUT register (0x41) to keep -- cgit v1.2.3-18-g5258 From eff563cf10e2f24e3b025d352c3aa174cf0111b3 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 13 Aug 2009 09:34:37 +0530 Subject: ath9k: Set HW state properly This patch fixes a bug in ath9k_stop() where the HW was not put into FULL_SLEEP state. Not doing so will cause issues in suspend-resume and the HW will not respond to chip resets. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3eb6dc0c8e2..fa4c6e74f97 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2140,6 +2140,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) /* disable HAL and put h/w to sleep */ ath9k_hw_disable(sc->sc_ah); ath9k_hw_configpcipowersave(sc->sc_ah, 1); + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); sc->sc_flags |= SC_OP_INVALID; -- cgit v1.2.3-18-g5258 From 560ad81b6c90e0fddc4d6c280f16ddf18d47eeb1 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Thu, 13 Aug 2009 14:19:02 +0200 Subject: b43: Implement RC calibration for rev.0/1 LP-PHYs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also implement get/set BB mult, get/set TX gain, set RX gain, disable/restore CRS, run/stop DDFS, RX IQ est and QDIV roundup in the process. Signed-off-by: Gábor Stefanik Acked-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 507 ++++++++++++++++++++++++++++++++++---- 1 file changed, 460 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 296e209a8c1..cfb8337d385 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -605,6 +605,8 @@ static void lpphy_radio_init(struct b43_wldev *dev) } } +struct lpphy_iq_est { u32 iq_prod, i_pwr, q_pwr; }; + static void lpphy_set_rc_cap(struct b43_wldev *dev) { u8 rc_cap = dev->phy.lp->rc_cap; @@ -614,79 +616,326 @@ static void lpphy_set_rc_cap(struct b43_wldev *dev) b43_radio_write(dev, B2062_S_RXG_CNT16, ((rc_cap & 0x1F) >> 2) | 0x80); } -static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) +static u8 lpphy_get_bb_mult(struct b43_wldev *dev) { - //TODO and SPEC FIXME + return (b43_lptab_read(dev, B43_LPTAB16(0, 87)) & 0xFF00) >> 8; } -static void lpphy_rev2plus_rc_calib(struct b43_wldev *dev) +static void lpphy_set_bb_mult(struct b43_wldev *dev, u8 bb_mult) { - struct ssb_bus *bus = dev->dev->bus; - u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000; - u8 tmp = b43_radio_read(dev, B2063_RX_BB_SP8) & 0xFF; - int i; + b43_lptab_write(dev, B43_LPTAB16(0, 87), (u16)bb_mult << 8); +} - b43_radio_write(dev, B2063_RX_BB_SP8, 0x0); - b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); - b43_radio_mask(dev, B2063_PLL_SP1, 0xF7); - b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C); - b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x15); - b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x70); - b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x52); - b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1); - b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7D); +static void lpphy_disable_crs(struct b43_wldev *dev) +{ + b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x80); + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x1); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFB); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x4); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFF7); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x10); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFDF); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x20); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFBF); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x7); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x38); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFF3F); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x100); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFDFF); + b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL0, 0); + b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL1, 1); + b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL2, 0x20); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFBFF); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xF7FF); + b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, 0); + b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, 0x45AF); + b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0x3FF); +} - for (i = 0; i < 10000; i++) { - if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2) - break; - msleep(1); +static void lpphy_restore_crs(struct b43_wldev *dev) +{ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x60); + else + b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x20); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFF80); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFC00); +} + +struct lpphy_tx_gains { u16 gm, pga, pad, dac; }; + +static struct lpphy_tx_gains lpphy_get_tx_gains(struct b43_wldev *dev) +{ + struct lpphy_tx_gains gains; + u16 tmp; + + gains.dac = (b43_phy_read(dev, B43_LPPHY_AFE_DAC_CTL) & 0x380) >> 7; + if (dev->phy.rev < 2) { + tmp = b43_phy_read(dev, + B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL) & 0x7FF; + gains.gm = tmp & 0x0007; + gains.pga = (tmp & 0x0078) >> 3; + gains.pad = (tmp & 0x780) >> 7; + } else { + tmp = b43_phy_read(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL); + gains.pad = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0xFF; + gains.gm = tmp & 0xFF; + gains.pga = (tmp >> 8) & 0xFF; } - if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)) - b43_radio_write(dev, B2063_RX_BB_SP8, tmp); + return gains; +} - tmp = b43_radio_read(dev, B2063_TX_BB_SP3) & 0xFF; +static void lpphy_set_dac_gain(struct b43_wldev *dev, u16 dac) +{ + u16 ctl = b43_phy_read(dev, B43_LPPHY_AFE_DAC_CTL) & 0xC7F; + ctl |= dac << 7; + b43_phy_maskset(dev, B43_LPPHY_AFE_DAC_CTL, 0xF000, ctl); +} - b43_radio_write(dev, B2063_TX_BB_SP3, 0x0); - b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); - b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C); - b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x55); - b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x76); +static void lpphy_set_tx_gains(struct b43_wldev *dev, + struct lpphy_tx_gains gains) +{ + u16 rf_gain, pa_gain; - if (crystal_freq == 24000000) { - b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0xFC); - b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x0); + if (dev->phy.rev < 2) { + rf_gain = (gains.pad << 7) | (gains.pga << 3) | gains.gm; + b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, + 0xF800, rf_gain); } else { - b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x13); - b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1); + pa_gain = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x7F00; + b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, + (gains.pga << 8) | gains.gm); + b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, + 0x8000, gains.pad | pa_gain); + b43_phy_write(dev, B43_PHY_OFDM(0xFC), + (gains.pga << 8) | gains.gm); + b43_phy_maskset(dev, B43_PHY_OFDM(0xFD), + 0x8000, gains.pad | pa_gain); } + lpphy_set_dac_gain(dev, gains.dac); + if (dev->phy.rev < 2) { + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF, 1 << 8); + } else { + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F, 1 << 7); + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF, 1 << 14); + } + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFBF, 1 << 4); +} - b43_radio_write(dev, B2063_PA_SP7, 0x7D); +static void lpphy_rev0_1_set_rx_gain(struct b43_wldev *dev, u32 gain) +{ + u16 trsw = gain & 0x1; + u16 lna = (gain & 0xFFFC) | ((gain & 0xC) >> 2); + u16 ext_lna = (gain & 2) >> 1; + + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFE, trsw); + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, + 0xFBFF, ext_lna << 10); + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, + 0xF7FF, ext_lna << 11); + b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, lna); +} - for (i = 0; i < 10000; i++) { - if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2) +static void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain) +{ + u16 low_gain = gain & 0xFFFF; + u16 high_gain = (gain >> 16) & 0xF; + u16 ext_lna = (gain >> 21) & 0x1; + u16 trsw = ~(gain >> 20) & 0x1; + u16 tmp; + + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFE, trsw); + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, + 0xFDFF, ext_lna << 9); + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, + 0xFBFF, ext_lna << 10); + b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, low_gain); + b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFF0, high_gain); + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + tmp = (gain >> 2) & 0x3; + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, + 0xE7FF, tmp<<11); + b43_phy_maskset(dev, B43_PHY_OFDM(0xE6), 0xFFE7, tmp << 3); + } +} + +static void lpphy_enable_rx_gain_override(struct b43_wldev *dev) +{ + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFEF); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFBF); + if (dev->phy.rev >= 2) { + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF); + if (b43_current_band(dev->wl) != IEEE80211_BAND_2GHZ) + return; + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFF7); + } else { + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF); + } +} + +static void lpphy_disable_rx_gain_override(struct b43_wldev *dev) +{ + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40); + if (dev->phy.rev >= 2) { + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100); + if (b43_current_band(dev->wl) != IEEE80211_BAND_2GHZ) + return; + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x8); + } else { + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x200); + } +} + +static void lpphy_set_rx_gain(struct b43_wldev *dev, u32 gain) +{ + if (dev->phy.rev < 2) + lpphy_rev0_1_set_rx_gain(dev, gain); + else + lpphy_rev2plus_set_rx_gain(dev, gain); + lpphy_enable_rx_gain_override(dev); +} + +static void lpphy_set_rx_gain_by_index(struct b43_wldev *dev, u16 idx) +{ + u32 gain = b43_lptab_read(dev, B43_LPTAB16(12, idx)); + lpphy_set_rx_gain(dev, gain); +} + +static void lpphy_stop_ddfs(struct b43_wldev *dev) +{ + b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFD); + b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0xFFDF); +} + +static void lpphy_run_ddfs(struct b43_wldev *dev, int i_on, int q_on, + int incr1, int incr2, int scale_idx) +{ + lpphy_stop_ddfs(dev); + b43_phy_mask(dev, B43_LPPHY_AFE_DDFS_POINTER_INIT, 0xFF80); + b43_phy_mask(dev, B43_LPPHY_AFE_DDFS_POINTER_INIT, 0x80FF); + b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS_INCR_INIT, 0xFF80, incr1); + b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS_INCR_INIT, 0x80FF, incr2 << 8); + b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFF7, i_on << 3); + b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFEF, q_on << 4); + b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFF9F, scale_idx << 5); + b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFB); + b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x2); + b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x20); +} + +static bool lpphy_rx_iq_est(struct b43_wldev *dev, u16 samples, u8 time, + struct lpphy_iq_est *iq_est) +{ + int i; + + b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFF7); + b43_phy_write(dev, B43_LPPHY_IQ_NUM_SMPLS_ADDR, samples); + b43_phy_maskset(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFF00, time); + b43_phy_mask(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFEFF); + b43_phy_set(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFDFF); + + for (i = 0; i < 500; i++) { + if (!(b43_phy_read(dev, + B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) break; msleep(1); } - if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)) - b43_radio_write(dev, B2063_TX_BB_SP3, tmp); + if ((b43_phy_read(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) { + b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x8); + return false; + } - b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); + iq_est->iq_prod = b43_phy_read(dev, B43_LPPHY_IQ_ACC_HI_ADDR); + iq_est->iq_prod <<= 16; + iq_est->iq_prod |= b43_phy_read(dev, B43_LPPHY_IQ_ACC_LO_ADDR); + + iq_est->i_pwr = b43_phy_read(dev, B43_LPPHY_IQ_I_PWR_ACC_HI_ADDR); + iq_est->i_pwr <<= 16; + iq_est->i_pwr |= b43_phy_read(dev, B43_LPPHY_IQ_I_PWR_ACC_LO_ADDR); + + iq_est->q_pwr = b43_phy_read(dev, B43_LPPHY_IQ_Q_PWR_ACC_HI_ADDR); + iq_est->q_pwr <<= 16; + iq_est->q_pwr |= b43_phy_read(dev, B43_LPPHY_IQ_Q_PWR_ACC_LO_ADDR); + + b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x8); + return true; } -static void lpphy_calibrate_rc(struct b43_wldev *dev) +static int lpphy_loopback(struct b43_wldev *dev) { - struct b43_phy_lp *lpphy = dev->phy.lp; + struct lpphy_iq_est iq_est; + int i, index = -1; + u32 tmp; + + memset(&iq_est, 0, sizeof(iq_est)); + + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x3); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3); + b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x800); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x8); + b43_radio_write(dev, B2062_N_TX_CTL_A, 0x80); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x80); + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x80); + for (i = 0; i < 32; i++) { + lpphy_set_rx_gain_by_index(dev, i); + lpphy_run_ddfs(dev, 1, 1, 5, 5, 0); + if (!(lpphy_rx_iq_est(dev, 1000, 32, &iq_est))) + continue; + tmp = (iq_est.i_pwr + iq_est.q_pwr) / 1000; + if ((tmp > 4000) && (tmp < 10000)) { + index = i; + break; + } + } + lpphy_stop_ddfs(dev); + return index; +} - if (dev->phy.rev >= 2) { - lpphy_rev2plus_rc_calib(dev); - } else if (!lpphy->rc_cap) { - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - lpphy_rev0_1_rc_calib(dev); +static u32 lpphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision) +{ + u32 quotient, remainder, rbit, roundup, tmp; + + if (divisor == 0) { + quotient = 0; + remainder = 0; } else { - lpphy_set_rc_cap(dev); + quotient = dividend / divisor; + remainder = dividend % divisor; } + + rbit = divisor & 0x1; + roundup = (divisor >> 1) + rbit; + precision--; + + while (precision != 0xFF) { + tmp = remainder - roundup; + quotient <<= 1; + remainder <<= 1; + if (remainder >= roundup) { + remainder = (tmp << 1) + rbit; + quotient--; + } + precision--; + } + + if (remainder >= roundup) + quotient++; + + return quotient; } /* Read the TX power control mode from hardware. */ @@ -773,6 +1022,170 @@ static void lpphy_set_tx_power_control(struct b43_wldev *dev, lpphy_write_tx_pctl_mode_to_hardware(dev); } +static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + struct lpphy_iq_est iq_est; + struct lpphy_tx_gains tx_gains; + static const u32 ideal_pwr_table[22] = { + 0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64, + 0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35, + 0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088, + 0x0004c, 0x0002c, 0x0001a, 0xc0006, + }; + bool old_txg_ovr; + u8 old_bbmult; + u16 old_rf_ovr, old_rf_ovrval, old_afe_ovr, old_afe_ovrval, + old_rf2_ovr, old_rf2_ovrval, old_phy_ctl, old_txpctl; + u32 normal_pwr, ideal_pwr, mean_sq_pwr, tmp = 0, mean_sq_pwr_min = 0; + int loopback, i, j, inner_sum; + + memset(&iq_est, 0, sizeof(iq_est)); + + b43_switch_channel(dev, 7); + old_txg_ovr = (b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) >> 6) & 1; + old_bbmult = lpphy_get_bb_mult(dev); + if (old_txg_ovr) + tx_gains = lpphy_get_tx_gains(dev); + old_rf_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_0); + old_rf_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_VAL_0); + old_afe_ovr = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR); + old_afe_ovrval = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVRVAL); + old_rf2_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2); + old_rf2_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2_VAL); + old_phy_ctl = b43_phy_read(dev, B43_LPPHY_LP_PHY_CTL); + old_txpctl = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_CMD) & + B43_LPPHY_TX_PWR_CTL_CMD_MODE; + + lpphy_set_tx_power_control(dev, B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF); + lpphy_disable_crs(dev); + loopback = lpphy_loopback(dev); + if (loopback == -1) + goto finish; + lpphy_set_rx_gain_by_index(dev, loopback); + b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFFBF, 0x40); + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFFF8, 0x1); + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFFC7, 0x8); + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFF3F, 0xC0); + for (i = 128; i <= 159; i++) { + b43_radio_write(dev, B2062_N_RXBB_CALIB2, i); + inner_sum = 0; + for (j = 5; j <= 25; j++) { + lpphy_run_ddfs(dev, 1, 1, j, j, 0); + if (!(lpphy_rx_iq_est(dev, 1000, 32, &iq_est))) + goto finish; + mean_sq_pwr = iq_est.i_pwr + iq_est.q_pwr; + if (j == 5) + tmp = mean_sq_pwr; + ideal_pwr = ((ideal_pwr_table[j-5] >> 3) + 1) >> 1; + normal_pwr = lpphy_qdiv_roundup(mean_sq_pwr, tmp, 12); + mean_sq_pwr = ideal_pwr - normal_pwr; + mean_sq_pwr *= mean_sq_pwr; + inner_sum += mean_sq_pwr; + if ((i = 128) || (inner_sum < mean_sq_pwr_min)) { + lpphy->rc_cap = i; + mean_sq_pwr_min = inner_sum; + } + } + } + lpphy_stop_ddfs(dev); + +finish: + lpphy_restore_crs(dev); + b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, old_rf_ovrval); + b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, old_rf_ovr); + b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVRVAL, old_afe_ovrval); + b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, old_afe_ovr); + b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, old_rf2_ovrval); + b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, old_rf2_ovr); + b43_phy_write(dev, B43_LPPHY_LP_PHY_CTL, old_phy_ctl); + + lpphy_set_bb_mult(dev, old_bbmult); + if (old_txg_ovr) { + /* + * SPEC FIXME: The specs say "get_tx_gains" here, which is + * illogical. According to lwfinger, vendor driver v4.150.10.5 + * has a Set here, while v4.174.64.19 has a Get - regression in + * the vendor driver? This should be tested this once the code + * is testable. + */ + lpphy_set_tx_gains(dev, tx_gains); + } + lpphy_set_tx_power_control(dev, old_txpctl); + if (lpphy->rc_cap) + lpphy_set_rc_cap(dev); +} + +static void lpphy_rev2plus_rc_calib(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000; + u8 tmp = b43_radio_read(dev, B2063_RX_BB_SP8) & 0xFF; + int i; + + b43_radio_write(dev, B2063_RX_BB_SP8, 0x0); + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); + b43_radio_mask(dev, B2063_PLL_SP1, 0xF7); + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C); + b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x15); + b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x70); + b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x52); + b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1); + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7D); + + for (i = 0; i < 10000; i++) { + if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2) + break; + msleep(1); + } + + if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)) + b43_radio_write(dev, B2063_RX_BB_SP8, tmp); + + tmp = b43_radio_read(dev, B2063_TX_BB_SP3) & 0xFF; + + b43_radio_write(dev, B2063_TX_BB_SP3, 0x0); + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C); + b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x55); + b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x76); + + if (crystal_freq == 24000000) { + b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0xFC); + b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x0); + } else { + b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x13); + b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1); + } + + b43_radio_write(dev, B2063_PA_SP7, 0x7D); + + for (i = 0; i < 10000; i++) { + if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2) + break; + msleep(1); + } + + if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)) + b43_radio_write(dev, B2063_TX_BB_SP3, tmp); + + b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E); +} + +static void lpphy_calibrate_rc(struct b43_wldev *dev) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + + if (dev->phy.rev >= 2) { + lpphy_rev2plus_rc_calib(dev); + } else if (!lpphy->rc_cap) { + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + lpphy_rev0_1_rc_calib(dev); + } else { + lpphy_set_rc_cap(dev); + } +} + static void lpphy_set_tx_power_by_index(struct b43_wldev *dev, u8 index) { struct b43_phy_lp *lpphy = dev->phy.lp; -- cgit v1.2.3-18-g5258 From c9a2bfd1f08973115c2fc3da9372e0e81ac42a19 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 14 Aug 2009 13:09:32 -0700 Subject: pcmcia: add CNF-CDROM-ID for ide Fixes this report: http://article.gmane.org/gmane.linux.kernel.pcmcia.devel/2228/ Reported-by: John McGrath Signed-off-by: Wolfram Sang Signed-off-by: David S. Miller --- drivers/ide/ide-cs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c index 527908ff298..063b933d864 100644 --- a/drivers/ide/ide-cs.c +++ b/drivers/ide/ide-cs.c @@ -408,6 +408,7 @@ static struct pcmcia_device_id ide_ids[] = { PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9), PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591), PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728), + PCMCIA_DEVICE_PROD_ID12("CNF ", "CD-ROM", 0x46d7db81, 0x66536591), PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591), PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4), PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde), -- cgit v1.2.3-18-g5258 From 9b289c3374d2891aac6c12de58e49a16cfbcb6b1 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Fri, 14 Aug 2009 05:15:12 +0000 Subject: sky2: Avoid rewinding sky2->tx_prod Keep sky2->tx_prod consistent since int might be examined by an softirq poll or restart. Signed-off-by: Mike McCormack Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 1415a837509..a52b8631783 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -989,11 +989,11 @@ static void sky2_prefetch_init(struct sky2_hw *hw, u32 qaddr, sky2_read32(hw, Y2_QADDR(qaddr, PREF_UNIT_CTRL)); } -static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2) +static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2, u16 *slot) { - struct sky2_tx_le *le = sky2->tx_le + sky2->tx_prod; + struct sky2_tx_le *le = sky2->tx_le + *slot; - sky2->tx_prod = RING_NEXT(sky2->tx_prod, TX_RING_SIZE); + *slot = RING_NEXT(*slot, TX_RING_SIZE); le->ctrl = 0; return le; } @@ -1006,7 +1006,7 @@ static void tx_init(struct sky2_port *sky2) sky2->tx_tcpsum = 0; sky2->tx_last_mss = 0; - le = get_tx_le(sky2); + le = get_tx_le(sky2, &sky2->tx_prod); le->addr = 0; le->opcode = OP_ADDR64 | HW_OWNER; } @@ -1572,7 +1572,8 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) struct sky2_hw *hw = sky2->hw; struct sky2_tx_le *le = NULL; struct tx_ring_info *re; - unsigned i, len, first_slot; + unsigned i, len; + u16 slot; dma_addr_t mapping; u16 mss; u8 ctrl; @@ -1586,14 +1587,14 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) if (pci_dma_mapping_error(hw->pdev, mapping)) goto mapping_error; - first_slot = sky2->tx_prod; + slot = sky2->tx_prod; if (unlikely(netif_msg_tx_queued(sky2))) printk(KERN_DEBUG "%s: tx queued, slot %u, len %d\n", - dev->name, first_slot, skb->len); + dev->name, slot, skb->len); /* Send high bits if needed */ if (sizeof(dma_addr_t) > sizeof(u32)) { - le = get_tx_le(sky2); + le = get_tx_le(sky2, &slot); le->addr = cpu_to_le32(upper_32_bits(mapping)); le->opcode = OP_ADDR64 | HW_OWNER; } @@ -1606,7 +1607,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) mss += ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb); if (mss != sky2->tx_last_mss) { - le = get_tx_le(sky2); + le = get_tx_le(sky2, &slot); le->addr = cpu_to_le32(mss); if (hw->flags & SKY2_HW_NEW_LE) @@ -1622,7 +1623,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) /* Add VLAN tag, can piggyback on LRGLEN or ADDR64 */ if (sky2->vlgrp && vlan_tx_tag_present(skb)) { if (!le) { - le = get_tx_le(sky2); + le = get_tx_le(sky2, &slot); le->addr = 0; le->opcode = OP_VLAN|HW_OWNER; } else @@ -1651,7 +1652,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) if (tcpsum != sky2->tx_tcpsum) { sky2->tx_tcpsum = tcpsum; - le = get_tx_le(sky2); + le = get_tx_le(sky2, &slot); le->addr = cpu_to_le32(tcpsum); le->length = 0; /* initial checksum value */ le->ctrl = 1; /* one packet */ @@ -1660,7 +1661,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) } } - le = get_tx_le(sky2); + le = get_tx_le(sky2, &slot); le->addr = cpu_to_le32((u32) mapping); le->length = cpu_to_le16(len); le->ctrl = ctrl; @@ -1681,13 +1682,13 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) goto mapping_unwind; if (sizeof(dma_addr_t) > sizeof(u32)) { - le = get_tx_le(sky2); + le = get_tx_le(sky2, &slot); le->addr = cpu_to_le32(upper_32_bits(mapping)); le->ctrl = 0; le->opcode = OP_ADDR64 | HW_OWNER; } - le = get_tx_le(sky2); + le = get_tx_le(sky2, &slot); le->addr = cpu_to_le32((u32) mapping); le->length = cpu_to_le16(frag->size); le->ctrl = ctrl; @@ -1701,6 +1702,8 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) le->ctrl |= EOP; + sky2->tx_prod = slot; + if (tx_avail(sky2) <= MAX_SKB_TX_LE) netif_stop_queue(dev); @@ -1709,7 +1712,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; mapping_unwind: - for (i = first_slot; i != sky2->tx_prod; i = RING_NEXT(i, TX_RING_SIZE)) { + for (i = sky2->tx_prod; i != slot; i = RING_NEXT(i, TX_RING_SIZE)) { le = sky2->tx_le + i; re = sky2->tx_ring + i; @@ -1729,7 +1732,6 @@ mapping_unwind: } } - sky2->tx_prod = first_slot; mapping_error: if (net_ratelimit()) dev_warn(&hw->pdev->dev, "%s: tx mapping error\n", dev->name); -- cgit v1.2.3-18-g5258 From a510996bea68eec2feb7818e9a440bd840613a25 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Fri, 14 Aug 2009 05:15:13 +0000 Subject: sky2: Move tx reset functionality to sky2_tx_reset() This is pure refactoring. Signed-off-by: Mike McCormack Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index a52b8631783..768ed47da9b 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1811,6 +1811,31 @@ static void sky2_tx_clean(struct net_device *dev) netif_tx_unlock_bh(dev); } +static void sky2_tx_reset(struct sky2_port* sky2) +{ + unsigned port = sky2->port; + struct sky2_hw *hw = sky2->hw; + + /* Disable Force Sync bit and Enable Alloc bit */ + sky2_write8(hw, SK_REG(port, TXA_CTRL), + TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC); + + /* Stop Interval Timer and Limit Counter of Tx Arbiter */ + sky2_write32(hw, SK_REG(port, TXA_ITI_INI), 0L); + sky2_write32(hw, SK_REG(port, TXA_LIM_INI), 0L); + + /* Reset the PCI FIFO of the async Tx queue */ + sky2_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), + BMU_RST_SET | BMU_FIFO_RST); + + /* Reset the Tx prefetch units */ + sky2_write32(hw, Y2_QADDR(txqaddr[port], PREF_UNIT_CTRL), + PREF_UNIT_RST_SET); + + sky2_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL), RB_RST_SET); + sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET); +} + /* Network shutdown */ static int sky2_down(struct net_device *dev) { @@ -1852,26 +1877,9 @@ static int sky2_down(struct net_device *dev) && port == 0 && hw->dev[1] && netif_running(hw->dev[1]))) sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_SET); - /* Disable Force Sync bit and Enable Alloc bit */ - sky2_write8(hw, SK_REG(port, TXA_CTRL), - TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC); - - /* Stop Interval Timer and Limit Counter of Tx Arbiter */ - sky2_write32(hw, SK_REG(port, TXA_ITI_INI), 0L); - sky2_write32(hw, SK_REG(port, TXA_LIM_INI), 0L); - - /* Reset the PCI FIFO of the async Tx queue */ - sky2_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), - BMU_RST_SET | BMU_FIFO_RST); - - /* Reset the Tx prefetch units */ - sky2_write32(hw, Y2_QADDR(txqaddr[port], PREF_UNIT_CTRL), - PREF_UNIT_RST_SET); - - sky2_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL), RB_RST_SET); + sky2_tx_reset(sky2); sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); - sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET); /* Force any delayed status interrrupt and NAPI */ sky2_write32(hw, STAT_LEV_TIMER_CNT, 0); -- cgit v1.2.3-18-g5258 From 264bb4fab1a0952b4eef4df5b9e90bc050a2d1e6 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Fri, 14 Aug 2009 05:15:14 +0000 Subject: sky2: Reset tx train after interrupts disabled. Reseting the tx chain too soon results in invalid tx queue positions being delivered in the status queue. This also makes sure there's no overlap between the cleanup done by sky2_tx_clean() and sky2_tx_done(). Signed-off-by: Mike McCormack Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 768ed47da9b..b75b48e8397 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1811,11 +1811,8 @@ static void sky2_tx_clean(struct net_device *dev) netif_tx_unlock_bh(dev); } -static void sky2_tx_reset(struct sky2_port* sky2) +static void sky2_tx_reset(struct sky2_hw *hw, unsigned port) { - unsigned port = sky2->port; - struct sky2_hw *hw = sky2->hw; - /* Disable Force Sync bit and Enable Alloc bit */ sky2_write8(hw, SK_REG(port, TXA_CTRL), TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC); @@ -1877,8 +1874,6 @@ static int sky2_down(struct net_device *dev) && port == 0 && hw->dev[1] && netif_running(hw->dev[1]))) sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_SET); - sky2_tx_reset(sky2); - sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); /* Force any delayed status interrrupt and NAPI */ @@ -1903,6 +1898,8 @@ static int sky2_down(struct net_device *dev) /* turn off LED's */ sky2_write16(hw, B0_Y2LED, LED_STAT_OFF); + sky2_tx_reset(hw, port); + sky2_tx_clean(dev); sky2_rx_clean(sky2); -- cgit v1.2.3-18-g5258 From 0da6d7b331f391d3c0ce52fb5289f7edeb94e280 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Aug 2009 05:15:15 +0000 Subject: sky2: hold spinlock around phy_power_down Avoid any possible problems with accessing PHY registers on shutdown. This is a purely theoretical issue and is not related to any of the outstanding bug reports. Since receiver and transmitter are already shutdown and phy interrupts for this device are already disabled, there should already be enough protection. Suggested by Mike McCormack. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index b75b48e8397..1d3ee03fa64 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1893,7 +1893,9 @@ static int sky2_down(struct net_device *dev) synchronize_irq(hw->pdev->irq); napi_synchronize(&hw->napi); + spin_lock_bh(&sky2->phy_lock); sky2_phy_power_down(hw, port); + spin_unlock_bh(&sky2->phy_lock); /* turn off LED's */ sky2_write16(hw, B0_Y2LED, LED_STAT_OFF); -- cgit v1.2.3-18-g5258 From 19720737187aaee006afb20e63be5e9eddc505a8 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Aug 2009 05:15:16 +0000 Subject: sky2: hold RTNL when doing suspend/shutdown operations The suspend and shutdown code plays with shared state. Use consistent locking, for extra protection. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 1d3ee03fa64..3ae4b42fe4d 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -4643,6 +4643,7 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) del_timer_sync(&hw->watchdog_timer); cancel_work_sync(&hw->restart_work); + rtnl_lock(); for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; struct sky2_port *sky2 = netdev_priv(dev); @@ -4660,6 +4661,7 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) sky2_write32(hw, B0_IMSK, 0); napi_disable(&hw->napi); sky2_power_aux(hw); + rtnl_unlock(); pci_save_state(pdev); pci_enable_wake(pdev, pci_choose_state(pdev, state), wol); @@ -4729,6 +4731,7 @@ static void sky2_shutdown(struct pci_dev *pdev) if (!hw) return; + rtnl_lock(); del_timer_sync(&hw->watchdog_timer); for (i = 0; i < hw->ports; i++) { @@ -4743,6 +4746,7 @@ static void sky2_shutdown(struct pci_dev *pdev) if (wol) sky2_power_aux(hw); + rtnl_unlock(); pci_enable_wake(pdev, PCI_D3hot, wol); pci_enable_wake(pdev, PCI_D3cold, wol); -- cgit v1.2.3-18-g5258 From af18d8b89930aecc742982634adaf97dfb43ed3b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Aug 2009 15:31:25 -0700 Subject: sky2: cleanup restart operations This unifies the places that bounce the device (suspend/resume and restart). And makes the operations have the same semantics as normal dev_open/dev_stop. This also avoids setting the multicast addresses twice when device is brought up. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 95 +++++++++++++++++++++++++++--------------------------- 1 file changed, 48 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 3ae4b42fe4d..301f8a6f8c0 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1500,13 +1500,12 @@ static int sky2_up(struct net_device *dev) sky2_write32(hw, B0_IMSK, imask); sky2_read32(hw, B0_IMSK); - sky2_set_multicast(dev); - /* wake queue incase we are restarting */ netif_wake_queue(dev); if (netif_msg_ifup(sky2)) printk(KERN_INFO PFX "%s: enabling interface\n", dev->name); + return 0; err_out: @@ -3087,18 +3086,46 @@ static void sky2_reset(struct sky2_hw *hw) sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START); } +/* Take device down (offline). + * Equivalent to doing dev_stop() but this does not + * inform upper layers of the transistion. + */ +static void sky2_detach(struct net_device *dev) +{ + if (netif_running(dev)) { + netif_device_detach(dev); /* stop txq */ + sky2_down(dev); + } +} + +/* Bring device back after doing sky2_detach */ +static int sky2_reattach(struct net_device *dev) +{ + int err = 0; + + if (netif_running(dev)) { + err = sky2_up(dev); + if (err) { + printk(KERN_INFO PFX "%s: could not restart %d\n", + dev->name, err); + dev_close(dev); + } else { + netif_device_attach(dev); + sky2_set_multicast(dev); + } + } + + return err; +} + static void sky2_restart(struct work_struct *work) { struct sky2_hw *hw = container_of(work, struct sky2_hw, restart_work); - struct net_device *dev; - int i, err; + int i; rtnl_lock(); - for (i = 0; i < hw->ports; i++) { - dev = hw->dev[i]; - if (netif_running(dev)) - sky2_down(dev); - } + for (i = 0; i < hw->ports; i++) + sky2_detach(hw->dev[i]); napi_disable(&hw->napi); sky2_write32(hw, B0_IMSK, 0); @@ -3106,17 +3133,8 @@ static void sky2_restart(struct work_struct *work) sky2_write32(hw, B0_IMSK, Y2_IS_BASE); napi_enable(&hw->napi); - for (i = 0; i < hw->ports; i++) { - dev = hw->dev[i]; - if (netif_running(dev)) { - err = sky2_up(dev); - if (err) { - printk(KERN_INFO PFX "%s: could not restart %d\n", - dev->name, err); - dev_close(dev); - } - } - } + for (i = 0; i < hw->ports; i++) + sky2_reattach(hw->dev[i]); rtnl_unlock(); } @@ -3705,7 +3723,6 @@ static int sky2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) { struct sky2_port *sky2 = netdev_priv(dev); - int err = 0; if (ering->rx_pending > RX_MAX_PENDING || ering->rx_pending < 8 || @@ -3713,19 +3730,12 @@ static int sky2_set_ringparam(struct net_device *dev, ering->tx_pending > TX_RING_SIZE - 1) return -EINVAL; - if (netif_running(dev)) - sky2_down(dev); + sky2_detach(dev); sky2->rx_pending = ering->rx_pending; sky2->tx_pending = ering->tx_pending; - if (netif_running(dev)) { - err = sky2_up(dev); - if (err) - dev_close(dev); - } - - return err; + return sky2_reattach(dev); } static int sky2_get_regs_len(struct net_device *dev) @@ -4648,9 +4658,7 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) struct net_device *dev = hw->dev[i]; struct sky2_port *sky2 = netdev_priv(dev); - netif_device_detach(dev); - if (netif_running(dev)) - sky2_down(dev); + sky2_detach(dev); if (sky2->wol) sky2_wol_init(sky2); @@ -4698,25 +4706,18 @@ static int sky2_resume(struct pci_dev *pdev) sky2_write32(hw, B0_IMSK, Y2_IS_BASE); napi_enable(&hw->napi); + rtnl_lock(); for (i = 0; i < hw->ports; i++) { - struct net_device *dev = hw->dev[i]; - - netif_device_attach(dev); - if (netif_running(dev)) { - err = sky2_up(dev); - if (err) { - printk(KERN_ERR PFX "%s: could not up: %d\n", - dev->name, err); - rtnl_lock(); - dev_close(dev); - rtnl_unlock(); - goto out; - } - } + err = sky2_reattach(hw->dev[i]); + if (err) + goto out; } + rtnl_unlock(); return 0; out: + rtnl_unlock(); + dev_err(&pdev->dev, "resume failed (%d)\n", err); pci_disable_device(pdev); return err; -- cgit v1.2.3-18-g5258 From 481cea4a4d72aabe76dbb86b1a64f4e8931eca25 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Aug 2009 15:33:19 -0700 Subject: sky2: lock less transmit completion Transmit completion can safely run lockless against transmit start. In the normal case, completion is done from NAPI and only looks at elements that are at the tail of the ring. When doing shutdown or reset, the transmiter should be completely block by NAPI disable and blocking of transmit queue. Based on earlier work by Mike McCormack. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 301f8a6f8c0..4944fcc6b07 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1741,8 +1741,12 @@ mapping_error: /* * Free ring elements from starting at tx_cons until "done" * - * NB: the hardware will tell us about partial completion of multi-part + * NB: + * 1. The hardware will tell us about partial completion of multi-part * buffers so make sure not to free skb to early. + * 2. This may run in parallel start_xmit because the it only + * looks at the tail of the queue of FIFO (tx_cons), not + * the head (tx_prod) */ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) { @@ -1800,16 +1804,6 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) netif_wake_queue(dev); } -/* Cleanup all untransmitted buffers, assume transmitter not running */ -static void sky2_tx_clean(struct net_device *dev) -{ - struct sky2_port *sky2 = netdev_priv(dev); - - netif_tx_lock_bh(dev); - sky2_tx_complete(sky2, sky2->tx_prod); - netif_tx_unlock_bh(dev); -} - static void sky2_tx_reset(struct sky2_hw *hw, unsigned port) { /* Disable Force Sync bit and Enable Alloc bit */ @@ -1901,7 +1895,9 @@ static int sky2_down(struct net_device *dev) sky2_tx_reset(hw, port); - sky2_tx_clean(dev); + /* Free any pending frames stuck in HW queue */ + sky2_tx_complete(sky2, sky2->tx_prod); + sky2_rx_clean(sky2); pci_free_consistent(hw->pdev, RX_LE_BYTES, @@ -2378,11 +2374,8 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last) { struct sky2_port *sky2 = netdev_priv(dev); - if (likely(netif_running(dev) && !sky2->restarting)) { - netif_tx_lock(dev); + if (likely(netif_running(dev) && !sky2->restarting)) sky2_tx_complete(sky2, last); - netif_tx_unlock(dev); - } } static inline void sky2_skb_rx(const struct sky2_port *sky2, -- cgit v1.2.3-18-g5258 From 0ea065e52eb6a0f029b5fa5ed2f142be1b66a153 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Aug 2009 15:36:41 -0700 Subject: sky2: fix pause negotiation The sky2 driver combines auto speed negotiation with automatic negotiation of pause parameters; but the ethtool interface expects them to be split. This patch allows autonegotiation to be used for speed, but manually disable flow control. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 73 +++++++++++++++++++++++++++++++++++------------------- drivers/net/sky2.h | 16 ++++++------ 2 files changed, 56 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 4944fcc6b07..6788a91d68d 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -321,7 +321,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) struct sky2_port *sky2 = netdev_priv(hw->dev[port]); u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg; - if (sky2->autoneg == AUTONEG_ENABLE && + if ( (sky2->flags & SKY2_FLAG_AUTO_SPEED) && !(hw->flags & SKY2_HW_NEWER_PHY)) { u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL); @@ -363,7 +363,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO); /* downshift on PHY 88E1112 and 88E1149 is changed */ - if (sky2->autoneg == AUTONEG_ENABLE + if ( (sky2->flags & SKY2_FLAG_AUTO_SPEED) && (hw->flags & SKY2_HW_NEWER_PHY)) { /* set downshift counter to 3x and enable downshift */ ctrl &= ~PHY_M_PC_DSC_MSK; @@ -408,7 +408,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) adv = PHY_AN_CSMA; reg = 0; - if (sky2->autoneg == AUTONEG_ENABLE) { + if (sky2->flags & SKY2_FLAG_AUTO_SPEED) { if (sky2_is_copper(hw)) { if (sky2->advertising & ADVERTISED_1000baseT_Full) ct1000 |= PHY_M_1000C_AFD; @@ -423,14 +423,11 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) if (sky2->advertising & ADVERTISED_10baseT_Half) adv |= PHY_M_AN_10_HD; - adv |= copper_fc_adv[sky2->flow_mode]; } else { /* special defines for FIBER (88E1040S only) */ if (sky2->advertising & ADVERTISED_1000baseT_Full) adv |= PHY_M_AN_1000X_AFD; if (sky2->advertising & ADVERTISED_1000baseT_Half) adv |= PHY_M_AN_1000X_AHD; - - adv |= fiber_fc_adv[sky2->flow_mode]; } /* Restart Auto-negotiation */ @@ -439,8 +436,8 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) /* forced speed/duplex settings */ ct1000 = PHY_M_1000C_MSE; - /* Disable auto update for duplex flow control and speed */ - reg |= GM_GPCR_AU_ALL_DIS; + /* Disable auto update for duplex flow control and duplex */ + reg |= GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_SPD_DIS; switch (sky2->speed) { case SPEED_1000: @@ -458,8 +455,15 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) ctrl |= PHY_CT_DUP_MD; } else if (sky2->speed < SPEED_1000) sky2->flow_mode = FC_NONE; + } - + if (sky2->flags & SKY2_FLAG_AUTO_PAUSE) { + if (sky2_is_copper(hw)) + adv |= copper_fc_adv[sky2->flow_mode]; + else + adv |= fiber_fc_adv[sky2->flow_mode]; + } else { + reg |= GM_GPCR_AU_FCT_DIS; reg |= gm_fc_disable[sky2->flow_mode]; /* Forward pause packets to GMAC? */ @@ -594,7 +598,8 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) /* no effect on Yukon-XL */ gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); - if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) { + if ( !(sky2->flags & SKY2_FLAG_AUTO_SPEED) + || sky2->speed == SPEED_100) { /* turn on 100 Mbps LED (LED_LINK100) */ ledover |= PHY_M_LED_MO_100(MO_LED_ON); } @@ -605,7 +610,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) } /* Enable phy interrupt on auto-negotiation complete (or link up) */ - if (sky2->autoneg == AUTONEG_ENABLE) + if (sky2->flags & SKY2_FLAG_AUTO_SPEED) gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL); else gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK); @@ -661,7 +666,9 @@ static void sky2_phy_power_down(struct sky2_hw *hw, unsigned port) /* setup General Purpose Control Register */ gma_write16(hw, port, GM_GP_CTRL, - GM_GPCR_FL_PASS | GM_GPCR_SPEED_100 | GM_GPCR_AU_ALL_DIS); + GM_GPCR_FL_PASS | GM_GPCR_SPEED_100 | + GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_FCT_DIS | + GM_GPCR_AU_SPD_DIS); if (hw->chip_id != CHIP_ID_YUKON_EC) { if (hw->chip_id == CHIP_ID_YUKON_EC_U) { @@ -1117,7 +1124,8 @@ static void rx_set_checksum(struct sky2_port *sky2) sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), - sky2->rx_csum ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); + (sky2->flags & SKY2_FLAG_RX_CHECKSUM) + ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); } /* @@ -2087,7 +2095,7 @@ static void sky2_phy_intr(struct sky2_hw *hw, unsigned port) printk(KERN_INFO PFX "%s: phy interrupt status 0x%x 0x%x\n", sky2->netdev->name, istatus, phystat); - if (sky2->autoneg == AUTONEG_ENABLE && (istatus & PHY_M_IS_AN_COMPL)) { + if (istatus & PHY_M_IS_AN_COMPL) { if (sky2_autoneg_done(sky2, phystat) == 0) sky2_link_up(sky2); goto out; @@ -2453,7 +2461,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) /* This chip reports checksum status differently */ if (hw->flags & SKY2_HW_NEW_LE) { - if (sky2->rx_csum && + if ((sky2->flags & SKY2_FLAG_RX_CHECKSUM) && (le->css & (CSS_ISIPV4 | CSS_ISIPV6)) && (le->css & CSS_TCPUDPCSOK)) skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -2480,7 +2488,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) /* fall through */ #endif case OP_RXCHKS: - if (!sky2->rx_csum) + if (!(sky2->flags & SKY2_FLAG_RX_CHECKSUM)) break; /* If this happens then driver assuming wrong format */ @@ -2505,7 +2513,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) printk(KERN_NOTICE PFX "%s: hardware receive " "checksum problem (status = %#x)\n", dev->name, status); - sky2->rx_csum = 0; + sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM; + sky2_write32(sky2->hw, Q_ADDR(rxqaddr[port], Q_CSR), BMU_DIS_RX_CHKSUM); @@ -3206,7 +3215,8 @@ static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) } ecmd->advertising = sky2->advertising; - ecmd->autoneg = sky2->autoneg; + ecmd->autoneg = (sky2->flags & SKY2_FLAG_AUTO_SPEED) + ? AUTONEG_ENABLE : AUTONEG_DISABLE; ecmd->duplex = sky2->duplex; return 0; } @@ -3218,6 +3228,7 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) u32 supported = sky2_supported_modes(hw); if (ecmd->autoneg == AUTONEG_ENABLE) { + sky2->flags |= SKY2_FLAG_AUTO_SPEED; ecmd->advertising = supported; sky2->duplex = -1; sky2->speed = -1; @@ -3259,9 +3270,9 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) sky2->speed = ecmd->speed; sky2->duplex = ecmd->duplex; + sky2->flags &= ~SKY2_FLAG_AUTO_SPEED; } - sky2->autoneg = ecmd->autoneg; sky2->advertising = ecmd->advertising; if (netif_running(dev)) { @@ -3331,14 +3342,17 @@ static u32 sky2_get_rx_csum(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); - return sky2->rx_csum; + return !!(sky2->flags & SKY2_FLAG_RX_CHECKSUM); } static int sky2_set_rx_csum(struct net_device *dev, u32 data) { struct sky2_port *sky2 = netdev_priv(dev); - sky2->rx_csum = data; + if (data) + sky2->flags |= SKY2_FLAG_RX_CHECKSUM; + else + sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM; sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), data ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); @@ -3356,7 +3370,7 @@ static int sky2_nway_reset(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); - if (!netif_running(dev) || sky2->autoneg != AUTONEG_ENABLE) + if (!netif_running(dev) || !(sky2->flags & SKY2_FLAG_AUTO_SPEED)) return -EINVAL; sky2_phy_reinit(sky2); @@ -3596,7 +3610,8 @@ static void sky2_get_pauseparam(struct net_device *dev, ecmd->tx_pause = ecmd->rx_pause = 1; } - ecmd->autoneg = sky2->autoneg; + ecmd->autoneg = (sky2->flags & SKY2_FLAG_AUTO_PAUSE) + ? AUTONEG_ENABLE : AUTONEG_DISABLE; } static int sky2_set_pauseparam(struct net_device *dev, @@ -3604,7 +3619,11 @@ static int sky2_set_pauseparam(struct net_device *dev, { struct sky2_port *sky2 = netdev_priv(dev); - sky2->autoneg = ecmd->autoneg; + if (ecmd->autoneg == AUTONEG_ENABLE) + sky2->flags |= SKY2_FLAG_AUTO_PAUSE; + else + sky2->flags &= ~SKY2_FLAG_AUTO_PAUSE; + sky2->flow_mode = sky2_flow(ecmd->rx_pause, ecmd->tx_pause); if (netif_running(dev)) @@ -4294,13 +4313,15 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, sky2->msg_enable = netif_msg_init(debug, default_msg); /* Auto speed and flow control */ - sky2->autoneg = AUTONEG_ENABLE; + sky2->flags = SKY2_FLAG_AUTO_SPEED | SKY2_FLAG_AUTO_PAUSE; + if (hw->chip_id != CHIP_ID_YUKON_XL) + sky2->flags |= SKY2_FLAG_RX_CHECKSUM; + sky2->flow_mode = FC_BOTH; sky2->duplex = -1; sky2->speed = -1; sky2->advertising = sky2_supported_modes(hw); - sky2->rx_csum = (hw->chip_id != CHIP_ID_YUKON_XL); sky2->wol = wol; spin_lock_init(&sky2->phy_lock); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 4486b066b43..c9548d6d567 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1583,7 +1583,6 @@ enum { }; #define GM_GPCR_SPEED_1000 (GM_GPCR_GIGS_ENA | GM_GPCR_SPEED_100) -#define GM_GPCR_AU_ALL_DIS (GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_FCT_DIS|GM_GPCR_AU_SPD_DIS) /* GM_TX_CTRL 16 bit r/w Transmit Control Register */ enum { @@ -2042,15 +2041,18 @@ struct sky2_port { u8 fifo_lev; } check; - dma_addr_t rx_le_map; dma_addr_t tx_le_map; + u16 advertising; /* ADVERTISED_ bits */ - u16 speed; /* SPEED_1000, SPEED_100, ... */ - u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */ - u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */ - u8 rx_csum; - u8 wol; + u16 speed; /* SPEED_1000, SPEED_100, ... */ + u8 wol; /* WAKE_ bits */ + u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */ + u16 flags; +#define SKY2_FLAG_RX_CHECKSUM 0x0001 +#define SKY2_FLAG_AUTO_SPEED 0x0002 +#define SKY2_FLAG_AUTO_PAUSE 0x0004 + u8 restarting; enum flow_control flow_mode; enum flow_control flow_status; -- cgit v1.2.3-18-g5258 From deeb16dc24b68cbdca72dc717ae82178a6644801 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Aug 2009 05:15:20 +0000 Subject: sky2: version 1.24 Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 6788a91d68d..bac187000e1 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -50,7 +50,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.23" +#define DRV_VERSION "1.24" #define PFX DRV_NAME " " /* -- cgit v1.2.3-18-g5258 From 36a82236314b5ebd6e3e1eb8bb7b850c83e53c3a Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Fri, 14 Aug 2009 12:41:28 +0000 Subject: ixgbe: updates vlan feature flags to enable FCoE offloads on vlan interface Updates netdev->vlan_features for NETIF_F_FCOE_CRC and NETIF_F_FSO, so that FCoE CRC and GSO offloads will get used for FCoE over ixgbe based vlan interface. Signed-off-by: Vasu Dev Signed-off-by: Yi Zou Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_dcb_nl.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index 1c726573290..116f12cc2c7 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -148,7 +148,10 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) IXGBE_FCRETA_SIZE; netdev->features |= NETIF_F_FCOE_CRC; netdev->features |= NETIF_F_FSO; + netdev->vlan_features |= NETIF_F_FCOE_CRC; + netdev->vlan_features |= NETIF_F_FSO; netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1; + netdev_features_change(netdev); } #endif /* IXGBE_FCOE */ ixgbe_init_interrupt_scheme(adapter); @@ -177,7 +180,10 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) adapter->ring_feature[RING_F_FCOE].indices = 0; netdev->features &= ~NETIF_F_FCOE_CRC; netdev->features &= ~NETIF_F_FSO; + netdev->vlan_features &= ~NETIF_F_FCOE_CRC; + netdev->vlan_features &= ~NETIF_F_FSO; netdev->fcoe_ddp_xid = 0; + netdev_features_change(netdev); } #endif /* IXGBE_FCOE */ ixgbe_init_interrupt_scheme(adapter); -- cgit v1.2.3-18-g5258 From f34c5c828439cedbc222030d7e45af69f947384d Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Fri, 14 Aug 2009 12:42:17 +0000 Subject: ixgbe: Add support for NETIF_F_FCOE_MTU to 82599 devices Enable netdev feature flag bit NETIF_F_FCOE_MTU for 82599 devices and enable jumbo frame correspondingly when NETIF_F_FCOE_MTU is set. Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_dcb_nl.c | 4 ++++ drivers/net/ixgbe/ixgbe_main.c | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index 116f12cc2c7..34bca45fbd1 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -148,8 +148,10 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) IXGBE_FCRETA_SIZE; netdev->features |= NETIF_F_FCOE_CRC; netdev->features |= NETIF_F_FSO; + netdev->features |= NETIF_F_FCOE_MTU; netdev->vlan_features |= NETIF_F_FCOE_CRC; netdev->vlan_features |= NETIF_F_FSO; + netdev->vlan_features |= NETIF_F_FCOE_MTU; netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1; netdev_features_change(netdev); } @@ -180,8 +182,10 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) adapter->ring_feature[RING_F_FCOE].indices = 0; netdev->features &= ~NETIF_F_FCOE_CRC; netdev->features &= ~NETIF_F_FSO; + netdev->features &= ~NETIF_F_FCOE_MTU; netdev->vlan_features &= ~NETIF_F_FCOE_CRC; netdev->vlan_features &= ~NETIF_F_FSO; + netdev->vlan_features &= ~NETIF_F_FCOE_MTU; netdev->fcoe_ddp_xid = 0; netdev_features_change(netdev); } diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 8a8518dd694..d69d277886e 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2026,7 +2026,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) else hlreg0 |= IXGBE_HLREG0_JUMBOEN; #ifdef IXGBE_FCOE - if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) + if (netdev->features & NETIF_F_FCOE_MTU) hlreg0 |= IXGBE_HLREG0_JUMBOEN; #endif IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0); @@ -2057,7 +2057,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) rx_ring->flags |= IXGBE_RING_RX_PS_ENABLED; #ifdef IXGBE_FCOE - if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { + if (netdev->features & NETIF_F_FCOE_MTU) { struct ixgbe_ring_feature *f; f = &adapter->ring_feature[RING_F_FCOE]; if ((i >= f->mask) && (i < f->mask + f->indices)) { @@ -2609,7 +2609,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) #ifdef IXGBE_FCOE /* adjust max frame to be able to do baby jumbo for FCoE */ - if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) && + if ((netdev->features & NETIF_F_FCOE_MTU) && (max_frame < IXGBE_FCOE_JUMBO_FRAME_SIZE)) max_frame = IXGBE_FCOE_JUMBO_FRAME_SIZE; -- cgit v1.2.3-18-g5258 From 49d4b8ba97034469b941d00d5ca1e3b897394e35 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 14 Aug 2009 13:33:17 +0000 Subject: sky2: remove restarting workaround flag The whole restarting flag was introduced by Mike McCormack and was a temporary duct tape patch around issues with transmits inflight during restart. The problems it was covering are now fixed and the code should have been reverted. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 14 +------------- drivers/net/sky2.h | 1 - 2 files changed, 1 insertion(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index bac187000e1..8a763f86661 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1496,8 +1496,6 @@ static int sky2_up(struct net_device *dev) sky2_set_vlan_mode(hw, port, sky2->vlgrp != NULL); #endif - sky2->restarting = 0; - err = sky2_rx_start(sky2); if (err) goto err_out; @@ -1508,9 +1506,6 @@ static int sky2_up(struct net_device *dev) sky2_write32(hw, B0_IMSK, imask); sky2_read32(hw, B0_IMSK); - /* wake queue incase we are restarting */ - netif_wake_queue(dev); - if (netif_msg_ifup(sky2)) printk(KERN_INFO PFX "%s: enabling interface\n", dev->name); @@ -1545,8 +1540,6 @@ static inline int tx_dist(unsigned tail, unsigned head) /* Number of list elements available for next tx */ static inline int tx_avail(const struct sky2_port *sky2) { - if (unlikely(sky2->restarting)) - return 0; return sky2->tx_pending - tx_dist(sky2->tx_cons, sky2->tx_prod); } @@ -1850,10 +1843,6 @@ static int sky2_down(struct net_device *dev) if (netif_msg_ifdown(sky2)) printk(KERN_INFO PFX "%s: disabling interface\n", dev->name); - /* explicitly shut off tx incase we're restarting */ - sky2->restarting = 1; - netif_tx_disable(dev); - /* Force flow control off */ sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); @@ -2382,7 +2371,7 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last) { struct sky2_port *sky2 = netdev_priv(dev); - if (likely(netif_running(dev) && !sky2->restarting)) + if (netif_running(dev)) sky2_tx_complete(sky2, last); } @@ -4327,7 +4316,6 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, spin_lock_init(&sky2->phy_lock); sky2->tx_pending = TX_DEF_PENDING; sky2->rx_pending = RX_DEF_PENDING; - sky2->restarting = 0; hw->dev[port] = dev; diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index c9548d6d567..65b94c366fb 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2053,7 +2053,6 @@ struct sky2_port { #define SKY2_FLAG_AUTO_SPEED 0x0002 #define SKY2_FLAG_AUTO_PAUSE 0x0004 - u8 restarting; enum flow_control flow_mode; enum flow_control flow_status; -- cgit v1.2.3-18-g5258 From 433a915fc6456ee3a4b740fe4d92caa78164fdce Mon Sep 17 00:00:00 2001 From: Byungho Min Date: Tue, 23 Jun 2009 21:40:09 +0900 Subject: ARM: S5PC100: UART and Serial Serial driver of S5PC100 is the same as S3C6400, so S5PC100 shares the serial driver with S3C6400. Uart driver is copied from plat-s3c64xx to plat-s5pc1xx, as I do not use plat-s3c64xx directory. Signed-off-by: Byungho Min [ben-linux@fluff.org: title fixup] Signed-off-by: Ben Dooks --- drivers/serial/Kconfig | 9 ++++++++- drivers/serial/Makefile | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 037c1e0b7c4..cdd552d33a7 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -459,7 +459,7 @@ config SERIAL_SAMSUNG_UARTS int depends on ARM && PLAT_S3C default 2 if ARCH_S3C2400 - default 4 if ARCH_S3C64XX || CPU_S3C2443 + default 4 if ARCH_S5PC1XX || ARCH_S3C64XX || CPU_S3C2443 default 3 help Select the number of available UART ports for the Samsung S3C @@ -533,6 +533,13 @@ config SERIAL_S3C6400 Serial port support for the Samsung S3C6400 and S3C6410 SoCs +config SERIAL_S5PC100 + tristate "Samsung S5PC100 Serial port support" + depends on SERIAL_SAMSUNG && CPU_S5PC100 + default y + help + Serial port support for the Samsung S5PC100 SoCs + config SERIAL_MAX3100 tristate "MAX3100 support" depends on SPI diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index d5a29981c6c..97f6fcc8b43 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o obj-$(CONFIG_SERIAL_S3C24A0) += s3c24a0.o obj-$(CONFIG_SERIAL_S3C6400) += s3c6400.o +obj-$(CONFIG_SERIAL_S5PC100) += s3c6400.o obj-$(CONFIG_SERIAL_MAX3100) += max3100.o obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o obj-$(CONFIG_SERIAL_MUX) += mux.o -- cgit v1.2.3-18-g5258 From a65027e4d80ece5a5a3bd4fc4808a83208430929 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 17 Aug 2009 00:58:04 +0000 Subject: be2net: Set mac addr in hw regardless of netif_running() be_mac_addr_set() currently is broken when netif_running() is false. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/benet/be_main.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 45507d88e6a..362346045ed 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -117,23 +117,18 @@ void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped) iowrite32(val, adapter->db + DB_CQ_OFFSET); } - static int be_mac_addr_set(struct net_device *netdev, void *p) { struct be_adapter *adapter = netdev_priv(netdev); struct sockaddr *addr = p; int status = 0; - if (netif_running(netdev)) { - status = be_cmd_pmac_del(adapter, adapter->if_handle, - adapter->pmac_id); - if (status) - return status; - - status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data, - adapter->if_handle, &adapter->pmac_id); - } + status = be_cmd_pmac_del(adapter, adapter->if_handle, adapter->pmac_id); + if (status) + return status; + status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data, + adapter->if_handle, &adapter->pmac_id); if (!status) memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); -- cgit v1.2.3-18-g5258 From b628bde2b5390776efc30837798d016ec1aa3ebe Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 17 Aug 2009 00:58:26 +0000 Subject: be2net: refactor be_msix_(un)register() code. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/benet/be_main.c | 58 +++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 362346045ed..010175f4b8f 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1303,6 +1303,12 @@ rx_eq_free: return rc; } +/* There are 8 evt ids per func. Retruns the evt id's bit number */ +static inline int be_evt_bit_get(struct be_adapter *adapter, u32 eq_id) +{ + return eq_id - 8 * be_pci_func(adapter); +} + static irqreturn_t be_intx(int irq, void *dev) { struct be_adapter *adapter = dev; @@ -1476,31 +1482,44 @@ static void be_msix_enable(struct be_adapter *adapter) static inline int be_msix_vec_get(struct be_adapter *adapter, u32 eq_id) { - return adapter->msix_entries[eq_id - 8 * be_pci_func(adapter)].vector; + return adapter->msix_entries[ + be_evt_bit_get(adapter, eq_id)].vector; } -static int be_msix_register(struct be_adapter *adapter) +static int be_request_irq(struct be_adapter *adapter, + struct be_eq_obj *eq_obj, + void *handler, char *desc) { struct net_device *netdev = adapter->netdev; - struct be_eq_obj *tx_eq = &adapter->tx_eq; - struct be_eq_obj *rx_eq = &adapter->rx_eq; - int status, vec; + int vec; + + sprintf(eq_obj->desc, "%s-%s", netdev->name, desc); + vec = be_msix_vec_get(adapter, eq_obj->q.id); + return request_irq(vec, handler, 0, eq_obj->desc, adapter); +} + +static void be_free_irq(struct be_adapter *adapter, struct be_eq_obj *eq_obj) +{ + int vec = be_msix_vec_get(adapter, eq_obj->q.id); + free_irq(vec, adapter); +} - sprintf(tx_eq->desc, "%s-tx", netdev->name); - vec = be_msix_vec_get(adapter, tx_eq->q.id); - status = request_irq(vec, be_msix_tx_mcc, 0, tx_eq->desc, adapter); +static int be_msix_register(struct be_adapter *adapter) +{ + int status; + + status = be_request_irq(adapter, &adapter->tx_eq, be_msix_tx_mcc, "tx"); if (status) goto err; - sprintf(rx_eq->desc, "%s-rx", netdev->name); - vec = be_msix_vec_get(adapter, rx_eq->q.id); - status = request_irq(vec, be_msix_rx, 0, rx_eq->desc, adapter); - if (status) { /* Free TX IRQ */ - vec = be_msix_vec_get(adapter, tx_eq->q.id); - free_irq(vec, adapter); - goto err; - } + status = be_request_irq(adapter, &adapter->rx_eq, be_msix_rx, "rx"); + if (status) + goto free_tx_irq; + return 0; + +free_tx_irq: + be_free_irq(adapter, &adapter->tx_eq); err: dev_warn(&adapter->pdev->dev, "MSIX Request IRQ failed - err %d\n", status); @@ -1537,7 +1556,6 @@ done: static void be_irq_unregister(struct be_adapter *adapter) { struct net_device *netdev = adapter->netdev; - int vec; if (!adapter->isr_registered) return; @@ -1549,10 +1567,8 @@ static void be_irq_unregister(struct be_adapter *adapter) } /* MSIx */ - vec = be_msix_vec_get(adapter, adapter->tx_eq.q.id); - free_irq(vec, adapter); - vec = be_msix_vec_get(adapter, adapter->rx_eq.q.id); - free_irq(vec, adapter); + be_free_irq(adapter, &adapter->tx_eq); + be_free_irq(adapter, &adapter->rx_eq); done: adapter->isr_registered = false; return; -- cgit v1.2.3-18-g5258 From 1a8887d81ac4bbee6153b4bc9b9f9e099fb5f07e Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 17 Aug 2009 00:58:41 +0000 Subject: be2net: destroy mcc queue before tx queues As mcc queue uses the tx event queue. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/benet/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 010175f4b8f..7b9efee890f 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1655,12 +1655,12 @@ do_none: static int be_clear(struct be_adapter *adapter) { + be_mcc_queues_destroy(adapter); be_rx_queues_destroy(adapter); be_tx_queues_destroy(adapter); be_cmd_if_destroy(adapter, adapter->if_handle); - be_mcc_queues_destroy(adapter); return 0; } -- cgit v1.2.3-18-g5258 From 52cfc61bf95262d55bc00063d7597e5e008fa22e Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Mon, 17 Aug 2009 15:37:18 -0700 Subject: HID: local function should be static __usbhid_submit_report() is a local function wrapped by the exported symbol usbhid_submit_report(). As such, it should be static. Signed-off-by: H Hartley Sweeten Cc: Jiri Kosina Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 9238bcffaf0..25f38a5af26 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -489,7 +489,8 @@ static void hid_ctrl(struct urb *urb) wake_up(&usbhid->wait); } -void __usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) +static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *report, + unsigned char dir) { int head; struct usbhid_device *usbhid = hid->driver_data; -- cgit v1.2.3-18-g5258 From d6e74b6b7eda3584a403eebae27f9591a1d9c9ff Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 18 Aug 2009 15:17:05 +0000 Subject: sky2: use upper/lower 32 bits Use the existing macros to show where DMA address is being broken apart. This is cosmetic only. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 8a763f86661..fb841c815b5 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -984,12 +984,12 @@ static void sky2_qset(struct sky2_hw *hw, u16 q) * hardware and driver list elements */ static void sky2_prefetch_init(struct sky2_hw *hw, u32 qaddr, - u64 addr, u32 last) + dma_addr_t addr, u32 last) { sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_CTRL), PREF_UNIT_RST_SET); sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_CTRL), PREF_UNIT_RST_CLR); - sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_ADDR_HI), addr >> 32); - sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_ADDR_LO), (u32) addr); + sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_ADDR_HI), upper_32_bits(addr)); + sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_ADDR_LO), lower_32_bits(addr)); sky2_write16(hw, Y2_QADDR(qaddr, PREF_UNIT_LAST_IDX), last); sky2_write32(hw, Y2_QADDR(qaddr, PREF_UNIT_CTRL), PREF_UNIT_OP_ON); @@ -1057,7 +1057,7 @@ static void sky2_rx_add(struct sky2_port *sky2, u8 op, } le = sky2_next_rx(sky2); - le->addr = cpu_to_le32((u32) map); + le->addr = cpu_to_le32(lower_32_bits(map)); le->length = cpu_to_le16(len); le->opcode = op | HW_OWNER; } @@ -1662,7 +1662,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) } le = get_tx_le(sky2, &slot); - le->addr = cpu_to_le32((u32) mapping); + le->addr = cpu_to_le32(lower_32_bits(mapping)); le->length = cpu_to_le16(len); le->ctrl = ctrl; le->opcode = mss ? (OP_LARGESEND | HW_OWNER) : (OP_PACKET | HW_OWNER); @@ -1689,7 +1689,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) } le = get_tx_le(sky2, &slot); - le->addr = cpu_to_le32((u32) mapping); + le->addr = cpu_to_le32(lower_32_bits(mapping)); le->length = cpu_to_le16(frag->size); le->ctrl = ctrl; le->opcode = OP_BUFFER | HW_OWNER; -- cgit v1.2.3-18-g5258 From 5dce95e5687a5a335202b03d133c1b4411ef7ce3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 18 Aug 2009 15:17:06 +0000 Subject: sky2: transmit ring 64 bit conservation This patch saves elements on transmit ring by only updating the upper 64 bit address when it changes. With many workloads skb's are located in same region, so it saves space. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 17 +++++++++++------ drivers/net/sky2.h | 1 + 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index fb841c815b5..88041e57887 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1016,6 +1016,7 @@ static void tx_init(struct sky2_port *sky2) le = get_tx_le(sky2, &sky2->tx_prod); le->addr = 0; le->opcode = OP_ADDR64 | HW_OWNER; + sky2->tx_last_upper = 0; } static inline struct tx_ring_info *tx_le_re(struct sky2_port *sky2, @@ -1573,8 +1574,9 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) struct sky2_tx_le *le = NULL; struct tx_ring_info *re; unsigned i, len; - u16 slot; dma_addr_t mapping; + u32 upper; + u16 slot; u16 mss; u8 ctrl; @@ -1593,9 +1595,11 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) dev->name, slot, skb->len); /* Send high bits if needed */ - if (sizeof(dma_addr_t) > sizeof(u32)) { + upper = upper_32_bits(mapping); + if (upper != sky2->tx_last_upper) { le = get_tx_le(sky2, &slot); - le->addr = cpu_to_le32(upper_32_bits(mapping)); + le->addr = cpu_to_le32(upper); + sky2->tx_last_upper = upper; le->opcode = OP_ADDR64 | HW_OWNER; } @@ -1681,10 +1685,11 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) if (pci_dma_mapping_error(hw->pdev, mapping)) goto mapping_unwind; - if (sizeof(dma_addr_t) > sizeof(u32)) { + upper = upper_32_bits(mapping); + if (upper != sky2->tx_last_upper) { le = get_tx_le(sky2, &slot); - le->addr = cpu_to_le32(upper_32_bits(mapping)); - le->ctrl = 0; + le->addr = cpu_to_le32(upper); + sky2->tx_last_upper = upper; le->opcode = OP_ADDR64 | HW_OWNER; } diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 65b94c366fb..feb3204134e 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2017,6 +2017,7 @@ struct sky2_port { u16 tx_pending; u16 tx_last_mss; + u32 tx_last_upper; u32 tx_tcpsum; struct rx_ring_info *rx_ring ____cacheline_aligned_in_smp; -- cgit v1.2.3-18-g5258 From c119731d6606ae25d787740d60706e2732454637 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 18 Aug 2009 15:17:07 +0000 Subject: sky2: simplify list element error The code for list element error (which should only happen on hardware errors) should be cleaner and safer. Gets rid of unused ring_size argument, which makes next patch easier. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 88041e57887..58d35214d12 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2661,19 +2661,15 @@ static void sky2_mac_intr(struct sky2_hw *hw, unsigned port) } /* This should never happen it is a bug. */ -static void sky2_le_error(struct sky2_hw *hw, unsigned port, - u16 q, unsigned ring_size) +static void sky2_le_error(struct sky2_hw *hw, unsigned port, u16 q) { struct net_device *dev = hw->dev[port]; - struct sky2_port *sky2 = netdev_priv(dev); - unsigned idx; - const u64 *le = (q == Q_R1 || q == Q_R2) - ? (u64 *) sky2->rx_le : (u64 *) sky2->tx_le; + u16 idx = sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_GET_IDX)); - idx = sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_GET_IDX)); - printk(KERN_ERR PFX "%s: descriptor error q=%#x get=%u [%llx] put=%u\n", - dev->name, (unsigned) q, idx, (unsigned long long) le[idx], - (unsigned) sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX))); + dev_err(&hw->pdev->dev, PFX + "%s: descriptor error q=%#x get=%u put=%u\n", + dev->name, (unsigned) q, (unsigned) idx, + (unsigned) sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX))); sky2_write32(hw, Q_ADDR(q, Q_CSR), BMU_CLR_IRQ_CHK); } @@ -2759,16 +2755,16 @@ static void sky2_err_intr(struct sky2_hw *hw, u32 status) sky2_mac_intr(hw, 1); if (status & Y2_IS_CHK_RX1) - sky2_le_error(hw, 0, Q_R1, RX_LE_SIZE); + sky2_le_error(hw, 0, Q_R1); if (status & Y2_IS_CHK_RX2) - sky2_le_error(hw, 1, Q_R2, RX_LE_SIZE); + sky2_le_error(hw, 1, Q_R2); if (status & Y2_IS_CHK_TXA1) - sky2_le_error(hw, 0, Q_XA1, TX_RING_SIZE); + sky2_le_error(hw, 0, Q_XA1); if (status & Y2_IS_CHK_TXA2) - sky2_le_error(hw, 1, Q_XA2, TX_RING_SIZE); + sky2_le_error(hw, 1, Q_XA2); } static int sky2_poll(struct napi_struct *napi, int work_limit) -- cgit v1.2.3-18-g5258 From ee5f68fea27b53b16c265b1f9ed8aa3bc9024c96 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 18 Aug 2009 15:17:08 +0000 Subject: sky2: dynamic size transmit ring Allocate and size transmit ring based on parameters. Saves excess space and allows configuring larger rings for testing. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 50 +++++++++++++++++++++++++++----------------------- drivers/net/sky2.h | 1 + 2 files changed, 28 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 58d35214d12..7c1880d8b31 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -64,10 +64,12 @@ #define RX_MAX_PENDING (RX_LE_SIZE/6 - 2) #define RX_DEF_PENDING RX_MAX_PENDING -#define TX_RING_SIZE 512 -#define TX_DEF_PENDING 128 -#define MAX_SKB_TX_LE (4 + (sizeof(dma_addr_t)/sizeof(u32))*MAX_SKB_FRAGS) +/* This is the worst case number of transmit list elements for a single skb: + VLAN + TSO + CKSUM + Data + skb_frags * DMA */ +#define MAX_SKB_TX_LE (4 + (sizeof(dma_addr_t)/sizeof(u32))*MAX_SKB_FRAGS) #define TX_MIN_PENDING (MAX_SKB_TX_LE+1) +#define TX_MAX_PENDING 4096 +#define TX_DEF_PENDING 127 #define STATUS_RING_SIZE 2048 /* 2 ports * (TX + 2*RX) */ #define STATUS_LE_BYTES (STATUS_RING_SIZE*sizeof(struct sky2_status_le)) @@ -1000,7 +1002,7 @@ static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2, u16 *slot) { struct sky2_tx_le *le = sky2->tx_le + *slot; - *slot = RING_NEXT(*slot, TX_RING_SIZE); + *slot = RING_NEXT(*slot, sky2->tx_ring_size); le->ctrl = 0; return le; } @@ -1433,13 +1435,13 @@ static int sky2_up(struct net_device *dev) /* must be power of 2 */ sky2->tx_le = pci_alloc_consistent(hw->pdev, - TX_RING_SIZE * + sky2->tx_ring_size * sizeof(struct sky2_tx_le), &sky2->tx_le_map); if (!sky2->tx_le) goto err_out; - sky2->tx_ring = kcalloc(TX_RING_SIZE, sizeof(struct tx_ring_info), + sky2->tx_ring = kcalloc(sky2->tx_ring_size, sizeof(struct tx_ring_info), GFP_KERNEL); if (!sky2->tx_ring) goto err_out; @@ -1491,7 +1493,7 @@ static int sky2_up(struct net_device *dev) sky2_write16(hw, Q_ADDR(txqaddr[port], Q_AL), ECU_TXFF_LEV); sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map, - TX_RING_SIZE - 1); + sky2->tx_ring_size - 1); #ifdef SKY2_VLAN_TAG_USED sky2_set_vlan_mode(hw, port, sky2->vlgrp != NULL); @@ -1520,7 +1522,7 @@ err_out: } if (sky2->tx_le) { pci_free_consistent(hw->pdev, - TX_RING_SIZE * sizeof(struct sky2_tx_le), + sky2->tx_ring_size * sizeof(struct sky2_tx_le), sky2->tx_le, sky2->tx_le_map); sky2->tx_le = NULL; } @@ -1533,15 +1535,15 @@ err_out: } /* Modular subtraction in ring */ -static inline int tx_dist(unsigned tail, unsigned head) +static inline int tx_inuse(const struct sky2_port *sky2) { - return (head - tail) & (TX_RING_SIZE - 1); + return (sky2->tx_prod - sky2->tx_cons) & (sky2->tx_ring_size - 1); } /* Number of list elements available for next tx */ static inline int tx_avail(const struct sky2_port *sky2) { - return sky2->tx_pending - tx_dist(sky2->tx_cons, sky2->tx_prod); + return sky2->tx_pending - tx_inuse(sky2); } /* Estimate of number of transmit list elements required */ @@ -1717,7 +1719,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; mapping_unwind: - for (i = sky2->tx_prod; i != slot; i = RING_NEXT(i, TX_RING_SIZE)) { + for (i = sky2->tx_prod; i != slot; i = RING_NEXT(i, sky2->tx_ring_size)) { le = sky2->tx_le + i; re = sky2->tx_ring + i; @@ -1760,10 +1762,10 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) struct pci_dev *pdev = sky2->hw->pdev; unsigned idx; - BUG_ON(done >= TX_RING_SIZE); + BUG_ON(done >= sky2->tx_ring_size); for (idx = sky2->tx_cons; idx != done; - idx = RING_NEXT(idx, TX_RING_SIZE)) { + idx = RING_NEXT(idx, sky2->tx_ring_size)) { struct sky2_tx_le *le = sky2->tx_le + idx; struct tx_ring_info *re = sky2->tx_ring + idx; @@ -1799,7 +1801,7 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) else dev_kfree_skb_any(skb); - sky2->tx_next = RING_NEXT(idx, TX_RING_SIZE); + sky2->tx_next = RING_NEXT(idx, sky2->tx_ring_size); } } @@ -1907,7 +1909,7 @@ static int sky2_down(struct net_device *dev) kfree(sky2->rx_ring); pci_free_consistent(hw->pdev, - TX_RING_SIZE * sizeof(struct sky2_tx_le), + sky2->tx_ring_size * sizeof(struct sky2_tx_le), sky2->tx_le, sky2->tx_le_map); kfree(sky2->tx_ring); @@ -2517,7 +2519,6 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) case OP_TXINDEXLE: /* TX index reports status for both ports */ - BUILD_BUG_ON(TX_RING_SIZE > 0x1000); sky2_tx_done(hw->dev[0], status & 0xfff); if (hw->dev[1]) sky2_tx_done(hw->dev[1], @@ -3669,7 +3670,7 @@ static int sky2_set_coalesce(struct net_device *dev, ecmd->rx_coalesce_usecs_irq > tmax) return -EINVAL; - if (ecmd->tx_max_coalesced_frames >= TX_RING_SIZE-1) + if (ecmd->tx_max_coalesced_frames >= sky2->tx_ring_size-1) return -EINVAL; if (ecmd->rx_max_coalesced_frames > RX_MAX_PENDING) return -EINVAL; @@ -3713,7 +3714,7 @@ static void sky2_get_ringparam(struct net_device *dev, ering->rx_max_pending = RX_MAX_PENDING; ering->rx_mini_max_pending = 0; ering->rx_jumbo_max_pending = 0; - ering->tx_max_pending = TX_RING_SIZE - 1; + ering->tx_max_pending = TX_MAX_PENDING; ering->rx_pending = sky2->rx_pending; ering->rx_mini_pending = 0; @@ -3728,14 +3729,15 @@ static int sky2_set_ringparam(struct net_device *dev, if (ering->rx_pending > RX_MAX_PENDING || ering->rx_pending < 8 || - ering->tx_pending < MAX_SKB_TX_LE || - ering->tx_pending > TX_RING_SIZE - 1) + ering->tx_pending < TX_MIN_PENDING || + ering->tx_pending > TX_MAX_PENDING) return -EINVAL; sky2_detach(dev); sky2->rx_pending = ering->rx_pending; sky2->tx_pending = ering->tx_pending; + sky2->tx_ring_size = roundup_pow_of_two(sky2->tx_pending+1); return sky2_reattach(dev); } @@ -4105,8 +4107,8 @@ static int sky2_debug_show(struct seq_file *seq, void *v) /* Dump contents of tx ring */ sop = 1; - for (idx = sky2->tx_next; idx != sky2->tx_prod && idx < TX_RING_SIZE; - idx = RING_NEXT(idx, TX_RING_SIZE)) { + for (idx = sky2->tx_next; idx != sky2->tx_prod && idx < sky2->tx_ring_size; + idx = RING_NEXT(idx, sky2->tx_ring_size)) { const struct sky2_tx_le *le = sky2->tx_le + idx; u32 a = le32_to_cpu(le->addr); @@ -4315,7 +4317,9 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, sky2->wol = wol; spin_lock_init(&sky2->phy_lock); + sky2->tx_pending = TX_DEF_PENDING; + sky2->tx_ring_size = roundup_pow_of_two(TX_DEF_PENDING+1); sky2->rx_pending = RX_DEF_PENDING; hw->dev[port] = dev; diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index feb3204134e..2c262f763f9 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2011,6 +2011,7 @@ struct sky2_port { struct tx_ring_info *tx_ring; struct sky2_tx_le *tx_le; + u16 tx_ring_size; u16 tx_cons; /* next le to check */ u16 tx_prod; /* next le to use */ u16 tx_next; /* debug only */ -- cgit v1.2.3-18-g5258 From 6b84dacadbdc3dab6a5b313d20d5a93b0d998641 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 18 Aug 2009 15:17:09 +0000 Subject: sky2: optimize transmit completion Don't reference the list element in hardware transmit ring on transmit completion. The list element is updated by hardware, therefore it causes a cache miss. Do book keeping in software structure. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 80 +++++++++++++++++++++--------------------------------- drivers/net/sky2.h | 3 ++ 2 files changed, 34 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 7c1880d8b31..a3e40d70c07 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1001,8 +1001,11 @@ static void sky2_prefetch_init(struct sky2_hw *hw, u32 qaddr, static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2, u16 *slot) { struct sky2_tx_le *le = sky2->tx_le + *slot; + struct tx_ring_info *re = sky2->tx_ring + *slot; *slot = RING_NEXT(*slot, sky2->tx_ring_size); + re->flags = 0; + re->skb = NULL; le->ctrl = 0; return le; } @@ -1021,12 +1024,6 @@ static void tx_init(struct sky2_port *sky2) sky2->tx_last_upper = 0; } -static inline struct tx_ring_info *tx_le_re(struct sky2_port *sky2, - struct sky2_tx_le *le) -{ - return sky2->tx_ring + (le - sky2->tx_le); -} - /* Update chip's next pointer */ static inline void sky2_put_idx(struct sky2_hw *hw, unsigned q, u16 idx) { @@ -1563,6 +1560,19 @@ static unsigned tx_le_req(const struct sk_buff *skb) return count; } +static void sky2_tx_unmap(struct pci_dev *pdev, + const struct tx_ring_info *re) +{ + if (re->flags & TX_MAP_SINGLE) + pci_unmap_single(pdev, pci_unmap_addr(re, mapaddr), + pci_unmap_len(re, maplen), + PCI_DMA_TODEVICE); + else if (re->flags & TX_MAP_PAGE) + pci_unmap_page(pdev, pci_unmap_addr(re, mapaddr), + pci_unmap_len(re, maplen), + PCI_DMA_TODEVICE); +} + /* * Put one packet in ring for transmit. * A single packet can generate multiple list elements, and @@ -1667,16 +1677,17 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) } } + re = sky2->tx_ring + slot; + re->flags = TX_MAP_SINGLE; + pci_unmap_addr_set(re, mapaddr, mapping); + pci_unmap_len_set(re, maplen, len); + le = get_tx_le(sky2, &slot); le->addr = cpu_to_le32(lower_32_bits(mapping)); le->length = cpu_to_le16(len); le->ctrl = ctrl; le->opcode = mss ? (OP_LARGESEND | HW_OWNER) : (OP_PACKET | HW_OWNER); - re = tx_le_re(sky2, le); - re->skb = skb; - pci_unmap_addr_set(re, mapaddr, mapping); - pci_unmap_len_set(re, maplen, len); for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; @@ -1695,18 +1706,19 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) le->opcode = OP_ADDR64 | HW_OWNER; } + re = sky2->tx_ring + slot; + re->flags = TX_MAP_PAGE; + pci_unmap_addr_set(re, mapaddr, mapping); + pci_unmap_len_set(re, maplen, frag->size); + le = get_tx_le(sky2, &slot); le->addr = cpu_to_le32(lower_32_bits(mapping)); le->length = cpu_to_le16(frag->size); le->ctrl = ctrl; le->opcode = OP_BUFFER | HW_OWNER; - - re = tx_le_re(sky2, le); - re->skb = skb; - pci_unmap_addr_set(re, mapaddr, mapping); - pci_unmap_len_set(re, maplen, frag->size); } + re->skb = skb; le->ctrl |= EOP; sky2->tx_prod = slot; @@ -1720,23 +1732,9 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) mapping_unwind: for (i = sky2->tx_prod; i != slot; i = RING_NEXT(i, sky2->tx_ring_size)) { - le = sky2->tx_le + i; re = sky2->tx_ring + i; - switch(le->opcode & ~HW_OWNER) { - case OP_LARGESEND: - case OP_PACKET: - pci_unmap_single(hw->pdev, - pci_unmap_addr(re, mapaddr), - pci_unmap_len(re, maplen), - PCI_DMA_TODEVICE); - break; - case OP_BUFFER: - pci_unmap_page(hw->pdev, pci_unmap_addr(re, mapaddr), - pci_unmap_len(re, maplen), - PCI_DMA_TODEVICE); - break; - } + sky2_tx_unmap(hw->pdev, re); } mapping_error: @@ -1759,34 +1757,18 @@ mapping_error: static void sky2_tx_complete(struct sky2_port *sky2, u16 done) { struct net_device *dev = sky2->netdev; - struct pci_dev *pdev = sky2->hw->pdev; unsigned idx; BUG_ON(done >= sky2->tx_ring_size); for (idx = sky2->tx_cons; idx != done; idx = RING_NEXT(idx, sky2->tx_ring_size)) { - struct sky2_tx_le *le = sky2->tx_le + idx; struct tx_ring_info *re = sky2->tx_ring + idx; + struct sk_buff *skb = re->skb; - switch(le->opcode & ~HW_OWNER) { - case OP_LARGESEND: - case OP_PACKET: - pci_unmap_single(pdev, - pci_unmap_addr(re, mapaddr), - pci_unmap_len(re, maplen), - PCI_DMA_TODEVICE); - break; - case OP_BUFFER: - pci_unmap_page(pdev, pci_unmap_addr(re, mapaddr), - pci_unmap_len(re, maplen), - PCI_DMA_TODEVICE); - break; - } - - if (le->ctrl & EOP) { - struct sk_buff *skb = re->skb; + sky2_tx_unmap(sky2->hw->pdev, re); + if (skb) { if (unlikely(netif_msg_tx_done(sky2))) printk(KERN_DEBUG "%s: tx done %u\n", dev->name, idx); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 2c262f763f9..9d07a466aec 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1984,6 +1984,9 @@ struct sky2_status_le { struct tx_ring_info { struct sk_buff *skb; + unsigned long flags; +#define TX_MAP_SINGLE 0x0001 +#define TX_MAP_PAGE 000002 DECLARE_PCI_UNMAP_ADDR(mapaddr); DECLARE_PCI_UNMAP_LEN(maplen); }; -- cgit v1.2.3-18-g5258 From 724b694225e711f95e6265afdbc304c9e7eb3721 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 18 Aug 2009 15:17:10 +0000 Subject: sky2: no recycling Recycling turns out to be a bad idea! For most use cases, the packet can not be reused: TCP packets are cloned. Even for the ideal case of forwarding, it hurts performance because of CPU ping/pong. On a multi-core system forwarding of 64 byte packets is worse much worse: recycling = 24% forwarded vs no recycling = 42% forwarded Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 16 +++------------- drivers/net/sky2.h | 1 - 2 files changed, 3 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index a3e40d70c07..1b79d3311e6 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1177,7 +1177,6 @@ static void sky2_rx_clean(struct sky2_port *sky2) re->skb = NULL; } } - skb_queue_purge(&sky2->rx_recycle); } /* Basic MII support */ @@ -1269,10 +1268,8 @@ static struct sk_buff *sky2_rx_alloc(struct sky2_port *sky2) struct sk_buff *skb; int i; - skb = __skb_dequeue(&sky2->rx_recycle); - if (!skb) - skb = netdev_alloc_skb(sky2->netdev, sky2->rx_data_size - + sky2_rx_pad(sky2->hw)); + skb = netdev_alloc_skb(sky2->netdev, + sky2->rx_data_size + sky2_rx_pad(sky2->hw)); if (!skb) goto nomem; @@ -1364,8 +1361,6 @@ static int sky2_rx_start(struct sky2_port *sky2) sky2->rx_data_size = size; - skb_queue_head_init(&sky2->rx_recycle); - /* Fill Rx ring */ for (i = 0; i < sky2->rx_pending; i++) { re = sky2->rx_ring + i; @@ -1776,12 +1771,7 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; - if (skb_queue_len(&sky2->rx_recycle) < sky2->rx_pending - && skb_recycle_check(skb, sky2->rx_data_size - + sky2_rx_pad(sky2->hw))) - __skb_queue_head(&sky2->rx_recycle, skb); - else - dev_kfree_skb_any(skb); + dev_kfree_skb_any(skb); sky2->tx_next = RING_NEXT(idx, sky2->tx_ring_size); } diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 9d07a466aec..73c95471246 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2032,7 +2032,6 @@ struct sky2_port { u16 rx_pending; u16 rx_data_size; u16 rx_nfrags; - struct sk_buff_head rx_recycle; #ifdef SKY2_VLAN_TAG_USED u16 rx_tag; -- cgit v1.2.3-18-g5258 From 0c3f450b8b345dafa79f1cc69eda702e0293b0cc Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 18 Aug 2009 15:17:11 +0000 Subject: sky2: version 1.25 Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 1b79d3311e6..dd630cf18b4 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -50,7 +50,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.24" +#define DRV_VERSION "1.25" #define PFX DRV_NAME " " /* -- cgit v1.2.3-18-g5258 From 81f9510381ee43205564063f2e8650672b11d453 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Wed, 19 Aug 2009 18:56:57 +0400 Subject: fakehard: add binding to wpan-phy device Make fakehard create and maintain wpan-phy node, thus representing it's phy in the sysfs. Signed-off-by: Dmitry Eremin-Solenikov --- drivers/ieee802154/fakehard.c | 52 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index 262536fae90..22a93bc764c 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c @@ -30,6 +30,12 @@ #include #include #include +#include + +struct wpan_phy *net_to_phy(struct net_device *dev) +{ + return container_of(dev->dev.parent, struct wpan_phy, dev); +} /** * fake_get_pan_id - Retrieve the PAN ID of the device. @@ -115,6 +121,12 @@ static u8 fake_get_bsn(struct net_device *dev) static int fake_assoc_req(struct net_device *dev, struct ieee802154_addr *addr, u8 channel, u8 cap) { + struct wpan_phy *phy = net_to_phy(dev); + + mutex_lock(&phy->pib_lock); + phy->current_channel = channel; + mutex_unlock(&phy->pib_lock); + /* We simply emulate it here */ return ieee802154_nl_assoc_confirm(dev, fake_get_short_addr(dev), IEEE802154_SUCCESS); @@ -183,6 +195,12 @@ static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, u8 coord_realign) { + struct wpan_phy *phy = net_to_phy(dev); + + mutex_lock(&phy->pib_lock); + phy->current_channel = channel; + mutex_unlock(&phy->pib_lock); + /* We don't emulate beacons here at all, so START should fail */ ieee802154_nl_start_confirm(dev, IEEE802154_INVALID_PARAMETER); return 0; @@ -290,6 +308,14 @@ static const struct net_device_ops fake_ops = { .ndo_set_mac_address = ieee802154_fake_mac_addr, }; +static void ieee802154_fake_destruct(struct net_device *dev) +{ + struct wpan_phy *phy = net_to_phy(dev); + + wpan_phy_unregister(phy); + free_netdev(dev); + wpan_phy_free(phy); +} static void ieee802154_fake_setup(struct net_device *dev) { @@ -302,22 +328,34 @@ static void ieee802154_fake_setup(struct net_device *dev) dev->type = ARPHRD_IEEE802154; dev->flags = IFF_NOARP | IFF_BROADCAST; dev->watchdog_timeo = 0; + dev->destructor = ieee802154_fake_destruct; } static int __devinit ieee802154fake_probe(struct platform_device *pdev) { - struct net_device *dev = - alloc_netdev(0, "hardwpan%d", ieee802154_fake_setup); + struct net_device *dev; + struct wpan_phy *phy = wpan_phy_alloc(0); int err; - if (!dev) + if (!phy) + return -ENOMEM; + + dev = alloc_netdev(0, "hardwpan%d", ieee802154_fake_setup); + if (!dev) { + wpan_phy_free(phy); return -ENOMEM; + } + + phy->dev.platform_data = dev; memcpy(dev->dev_addr, "\xba\xbe\xca\xfe\xde\xad\xbe\xef", dev->addr_len); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); + phy->channels_supported = (1 << 27) - 1; + phy->transmit_power = 0xbf; + dev->netdev_ops = &fake_ops; dev->ml_priv = &fake_mlme; @@ -331,15 +369,18 @@ static int __devinit ieee802154fake_probe(struct platform_device *pdev) goto out; } - SET_NETDEV_DEV(dev, &pdev->dev); + SET_NETDEV_DEV(dev, &phy->dev); platform_set_drvdata(pdev, dev); + err = wpan_phy_register(&pdev->dev, phy); + if (err) + goto out; + err = register_netdev(dev); if (err < 0) goto out; - dev_info(&pdev->dev, "Added ieee802154 HardMAC hardware\n"); return 0; @@ -352,7 +393,6 @@ static int __devexit ieee802154fake_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); unregister_netdev(dev); - free_netdev(dev); return 0; } -- cgit v1.2.3-18-g5258 From 16eea493da563b5a3356a77c6d8776dffc29d3b6 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Wed, 19 Aug 2009 19:32:24 +0400 Subject: ieee802154: add support for channel pages from IEEE 802.15.4-2006 IEEE 802.15.4-2006 adds new concept: channel pages, which can contain several channels. Add support for channel pages in the API and in the fakehard driver. Signed-off-by: Dmitry Eremin-Solenikov --- drivers/ieee802154/fakehard.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index 22a93bc764c..c1c9697f9fd 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c @@ -119,12 +119,13 @@ static u8 fake_get_bsn(struct net_device *dev) * 802.15.4-2006 document. */ static int fake_assoc_req(struct net_device *dev, - struct ieee802154_addr *addr, u8 channel, u8 cap) + struct ieee802154_addr *addr, u8 channel, u8 page, u8 cap) { struct wpan_phy *phy = net_to_phy(dev); mutex_lock(&phy->pib_lock); phy->current_channel = channel; + phy->current_page = page; mutex_unlock(&phy->pib_lock); /* We simply emulate it here */ @@ -191,7 +192,7 @@ static int fake_disassoc_req(struct net_device *dev, * document, with 7.3.8 describing coordinator realignment. */ static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, - u8 channel, + u8 channel, u8 page, u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, u8 coord_realign) { @@ -199,6 +200,7 @@ static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, mutex_lock(&phy->pib_lock); phy->current_channel = channel; + phy->current_page = page; mutex_unlock(&phy->pib_lock); /* We don't emulate beacons here at all, so START should fail */ @@ -222,11 +224,11 @@ static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, * Note: This is in section 7.5.2.1 of the IEEE 802.15.4-2006 document. */ static int fake_scan_req(struct net_device *dev, u8 type, u32 channels, - u8 duration) + u8 page, u8 duration) { u8 edl[27] = {}; return ieee802154_nl_scan_confirm(dev, IEEE802154_SUCCESS, type, - channels, + channels, page, type == IEEE802154_MAC_SCAN_ED ? edl : NULL); } -- cgit v1.2.3-18-g5258 From 886f9fe68310168358f55028a03553ae154dfeb6 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 19 Aug 2009 13:55:55 -0700 Subject: ppp_generic: Help GCC see that 'flen' is always initialized. It's too stupid to see that we always set flen to something before we use it in ppp_mp_explode(): drivers/net/ppp_generic.c: In function 'ppp_push': drivers/net/ppp_generic.c:1314: warning: 'flen' may be used uninitialized in this function drivers/net/ppp_generic.c:1314: note: 'flen' was declared here This started warning after commit a53a8b56827cc429c6d9f861ad558beeb5f6103f ("ppp: fix lost fragments in ppp_mp_explode() (resubmit)") So just put an explicit unconditional initialization there to hush it up. Signed-off-by: David S. Miller --- drivers/net/ppp_generic.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 7dd0868f983..35be2e8f0c9 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -1431,6 +1431,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) *otherwise divide it according to the speed *of the channel we are going to transmit on */ + flen = len; if (nfree > 0) { if (pch->speed == 0) { flen = totlen/nfree ; -- cgit v1.2.3-18-g5258 From 3b72094409ab673d096b3852f4636be540780faf Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 18 Aug 2009 11:45:02 -0700 Subject: Input: psmouse - allow defining read-only attributes Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse.h | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 54ed267894b..e3562daeb2e 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -116,9 +116,7 @@ ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *at ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); -#define __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, _protect) \ -static ssize_t _show(struct psmouse *, void *data, char *); \ -static ssize_t _set(struct psmouse *, void *data, const char *, size_t); \ +#define __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, _set, _protect) \ static struct psmouse_attribute psmouse_attr_##_name = { \ .dattr = { \ .attr = { \ @@ -134,7 +132,20 @@ static struct psmouse_attribute psmouse_attr_##_name = { \ .protect = _protect, \ } -#define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set) \ - __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, 1) +#define __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, _protect) \ + static ssize_t _show(struct psmouse *, void *, char *); \ + static ssize_t _set(struct psmouse *, void *, const char *, size_t); \ + __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, _set, _protect) + +#define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set) \ + __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, 1) + +#define PSMOUSE_DEFINE_RO_ATTR(_name, _mode, _data, _show) \ + static ssize_t _show(struct psmouse *, void *, char *); \ + __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, NULL, 1) + +#define PSMOUSE_DEFINE_WO_ATTR(_name, _mode, _data, _set) \ + static ssize_t _set(struct psmouse *, void *, const char *, size_t); \ + __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, NULL, _set, 1) #endif /* _PSMOUSE_H */ -- cgit v1.2.3-18-g5258 From fc69f4a6af49ee69475dc4217924d9edf77760e0 Mon Sep 17 00:00:00 2001 From: Tai-hwa Liang Date: Sun, 10 May 2009 18:15:39 -0700 Subject: Input: add new driver for Sentelic Finger Sensing Pad This is the driver for Sentelic Finger Sensing Pad which can be found on MSI WIND Netbook. Signed-off-by: Tai-hwa Liang Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/Kconfig | 8 + drivers/input/mouse/Makefile | 1 + drivers/input/mouse/psmouse-base.c | 26 +- drivers/input/mouse/psmouse.h | 1 + drivers/input/mouse/sentelic.c | 867 +++++++++++++++++++++++++++++++++++++ drivers/input/mouse/sentelic.h | 98 +++++ drivers/input/serio/libps2.c | 15 +- 7 files changed, 1012 insertions(+), 4 deletions(-) create mode 100644 drivers/input/mouse/sentelic.c create mode 100644 drivers/input/mouse/sentelic.h (limited to 'drivers') diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 90bef5d498f..3feeb3af8ab 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -107,6 +107,14 @@ config MOUSE_PS2_ELANTECH entries. For further information, see . +config MOUSE_PS2_SENTELIC + bool "Sentelic Finger Sensing Pad PS/2 protocol extension" + depends on MOUSE_PS2 + help + Say Y here if you have a laptop (such as MSI WIND Netbook) + with Sentelic Finger Sensing Pad touchpad. + + If unsure, say N. config MOUSE_PS2_TOUCHKIT bool "eGalax TouchKit PS/2 protocol extension" diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index ea58c9a372b..570c84a4a65 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -27,5 +27,6 @@ psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o psmouse-$(CONFIG_MOUSE_PS2_OLPC) += hgpk.o psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o +psmouse-$(CONFIG_MOUSE_PS2_SENTELIC) += sentelic.o psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index b407b355dce..df318887ca0 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -30,6 +30,7 @@ #include "trackpoint.h" #include "touchkit_ps2.h" #include "elantech.h" +#include "sentelic.h" #define DRIVER_DESC "PS/2 mouse driver" @@ -666,6 +667,20 @@ static int psmouse_extensions(struct psmouse *psmouse, max_proto = PSMOUSE_IMEX; } +/* + * Try Finger Sensing Pad + */ + if (max_proto > PSMOUSE_IMEX) { + if (fsp_detect(psmouse, set_properties) == 0) { + if (!set_properties || fsp_init(psmouse) == 0) + return PSMOUSE_FSP; +/* + * Init failed, try basic relative protocols + */ + max_proto = PSMOUSE_IMEX; + } + } + if (max_proto > PSMOUSE_IMEX) { if (genius_detect(psmouse, set_properties) == 0) return PSMOUSE_GENPS; @@ -813,7 +828,16 @@ static const struct psmouse_protocol psmouse_protocols[] = { .detect = elantech_detect, .init = elantech_init, }, - #endif +#endif +#ifdef CONFIG_MOUSE_PS2_SENTELIC + { + .type = PSMOUSE_FSP, + .name = "FSPPS/2", + .alias = "fsp", + .detect = fsp_detect, + .init = fsp_init, + }, +#endif { .type = PSMOUSE_CORTRON, .name = "CortronPS/2", diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index e3562daeb2e..cca1744c2a0 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -91,6 +91,7 @@ enum psmouse_type { PSMOUSE_CORTRON, PSMOUSE_HGPK, PSMOUSE_ELANTECH, + PSMOUSE_FSP, PSMOUSE_AUTO /* This one should always be last */ }; diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c new file mode 100644 index 00000000000..97b1e72855a --- /dev/null +++ b/drivers/input/mouse/sentelic.c @@ -0,0 +1,867 @@ +/*- + * Finger Sensing Pad PS/2 mouse driver. + * + * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd. + * Copyright (C) 2005-2009 Tai-hwa Liang, Sentelic Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "psmouse.h" +#include "sentelic.h" + +/* + * Timeout for FSP PS/2 command only (in milliseconds). + */ +#define FSP_CMD_TIMEOUT 200 +#define FSP_CMD_TIMEOUT2 30 + +/** Driver version. */ +static const char fsp_drv_ver[] = "1.0.0-K"; + +/* + * Make sure that the value being sent to FSP will not conflict with + * possible sample rate values. + */ +static unsigned char fsp_test_swap_cmd(unsigned char reg_val) +{ + switch (reg_val) { + case 10: case 20: case 40: case 60: case 80: case 100: case 200: + /* + * The requested value being sent to FSP matched to possible + * sample rates, swap the given value such that the hardware + * wouldn't get confused. + */ + return (reg_val >> 4) | (reg_val << 4); + default: + return reg_val; /* swap isn't necessary */ + } +} + +/* + * Make sure that the value being sent to FSP will not conflict with certain + * commands. + */ +static unsigned char fsp_test_invert_cmd(unsigned char reg_val) +{ + switch (reg_val) { + case 0xe9: case 0xee: case 0xf2: case 0xff: + /* + * The requested value being sent to FSP matched to certain + * commands, inverse the given value such that the hardware + * wouldn't get confused. + */ + return ~reg_val; + default: + return reg_val; /* inversion isn't necessary */ + } +} + +static int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char param[3]; + unsigned char addr; + int rc = -1; + + /* + * We need to shut off the device and switch it into command + * mode so we don't confuse our protocol handler. We don't need + * to do that for writes because sysfs set helper does this for + * us. + */ + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE); + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + mutex_lock(&ps2dev->cmd_mutex); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + goto out; + + /* should return 0xfe(request for resending) */ + ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2); + /* should return 0xfc(failed) */ + ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + goto out; + + if ((addr = fsp_test_invert_cmd(reg_addr)) != reg_addr) { + ps2_sendbyte(ps2dev, 0x68, FSP_CMD_TIMEOUT2); + } else if ((addr = fsp_test_swap_cmd(reg_addr)) != reg_addr) { + /* swapping is required */ + ps2_sendbyte(ps2dev, 0xcc, FSP_CMD_TIMEOUT2); + /* expect 0xfe */ + } else { + /* swapping isn't necessary */ + ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2); + /* expect 0xfe */ + } + /* should return 0xfc(failed) */ + ps2_sendbyte(ps2dev, addr, FSP_CMD_TIMEOUT); + + if (__ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) < 0) + goto out; + + *reg_val = param[2]; + rc = 0; + + out: + mutex_unlock(&ps2dev->cmd_mutex); + ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); + dev_dbg(&ps2dev->serio->dev, "READ REG: 0x%02x is 0x%02x (rc = %d)\n", + reg_addr, *reg_val, rc); + return rc; +} + +static int fsp_reg_write(struct psmouse *psmouse, int reg_addr, int reg_val) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char v; + int rc = -1; + + mutex_lock(&ps2dev->cmd_mutex); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + goto out; + + if ((v = fsp_test_invert_cmd(reg_addr)) != reg_addr) { + /* inversion is required */ + ps2_sendbyte(ps2dev, 0x74, FSP_CMD_TIMEOUT2); + } else { + if ((v = fsp_test_swap_cmd(reg_addr)) != reg_addr) { + /* swapping is required */ + ps2_sendbyte(ps2dev, 0x77, FSP_CMD_TIMEOUT2); + } else { + /* swapping isn't necessary */ + ps2_sendbyte(ps2dev, 0x55, FSP_CMD_TIMEOUT2); + } + } + /* write the register address in correct order */ + ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + return -1; + + if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) { + /* inversion is required */ + ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2); + } else if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) { + /* swapping is required */ + ps2_sendbyte(ps2dev, 0x44, FSP_CMD_TIMEOUT2); + } else { + /* swapping isn't necessary */ + ps2_sendbyte(ps2dev, 0x33, FSP_CMD_TIMEOUT2); + } + + /* write the register value in correct order */ + ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2); + rc = 0; + + out: + mutex_unlock(&ps2dev->cmd_mutex); + dev_dbg(&ps2dev->serio->dev, "WRITE REG: 0x%02x to 0x%02x (rc = %d)\n", + reg_addr, reg_val, rc); + return rc; +} + +/* Enable register clock gating for writing certain registers */ +static int fsp_reg_write_enable(struct psmouse *psmouse, bool enable) +{ + int v, nv; + + if (fsp_reg_read(psmouse, FSP_REG_SYSCTL1, &v) == -1) + return -1; + + if (enable) + nv = v | FSP_BIT_EN_REG_CLK; + else + nv = v & ~FSP_BIT_EN_REG_CLK; + + /* only write if necessary */ + if (nv != v) + if (fsp_reg_write(psmouse, FSP_REG_SYSCTL1, nv) == -1) + return -1; + + return 0; +} + +static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char param[3]; + int rc = -1; + + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE); + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + mutex_lock(&ps2dev->cmd_mutex); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + goto out; + + ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2); + ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + goto out; + + ps2_sendbyte(ps2dev, 0x83, FSP_CMD_TIMEOUT2); + ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); + + /* get the returned result */ + if (__ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) + goto out; + + *reg_val = param[2]; + rc = 0; + + out: + mutex_unlock(&ps2dev->cmd_mutex); + ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); + dev_dbg(&ps2dev->serio->dev, "READ PAGE REG: 0x%02x (rc = %d)\n", + *reg_val, rc); + return rc; +} + +static int fsp_page_reg_write(struct psmouse *psmouse, int reg_val) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char v; + int rc = -1; + + mutex_lock(&ps2dev->cmd_mutex); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + goto out; + + ps2_sendbyte(ps2dev, 0x38, FSP_CMD_TIMEOUT2); + ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + return -1; + + if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) { + ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2); + } else if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) { + /* swapping is required */ + ps2_sendbyte(ps2dev, 0x44, FSP_CMD_TIMEOUT2); + } else { + /* swapping isn't necessary */ + ps2_sendbyte(ps2dev, 0x33, FSP_CMD_TIMEOUT2); + } + + ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2); + rc = 0; + + out: + mutex_unlock(&ps2dev->cmd_mutex); + dev_dbg(&ps2dev->serio->dev, "WRITE PAGE REG: to 0x%02x (rc = %d)\n", + reg_val, rc); + return rc; +} + +static int fsp_get_version(struct psmouse *psmouse, int *version) +{ + if (fsp_reg_read(psmouse, FSP_REG_VERSION, version)) + return -EIO; + + return 0; +} + +static int fsp_get_revision(struct psmouse *psmouse, int *rev) +{ + if (fsp_reg_read(psmouse, FSP_REG_REVISION, rev)) + return -EIO; + + return 0; +} + +static int fsp_get_buttons(struct psmouse *psmouse, int *btn) +{ + static const int buttons[] = { + 0x16, /* Left/Middle/Right/Forward/Backward & Scroll Up/Down */ + 0x06, /* Left/Middle/Right & Scroll Up/Down/Right/Left */ + 0x04, /* Left/Middle/Right & Scroll Up/Down */ + 0x02, /* Left/Middle/Right */ + }; + int val; + + if (fsp_reg_read(psmouse, FSP_REG_TMOD_STATUS1, &val) == -1) + return -EIO; + + *btn = buttons[(val & 0x30) >> 4]; + return 0; +} + +/* Enable on-pad command tag output */ +static int fsp_opc_tag_enable(struct psmouse *psmouse, bool enable) +{ + int v, nv; + int res = 0; + + if (fsp_reg_read(psmouse, FSP_REG_OPC_QDOWN, &v) == -1) { + dev_err(&psmouse->ps2dev.serio->dev, "Unable get OPC state.\n"); + return -EIO; + } + + if (enable) + nv = v | FSP_BIT_EN_OPC_TAG; + else + nv = v & ~FSP_BIT_EN_OPC_TAG; + + /* only write if necessary */ + if (nv != v) { + fsp_reg_write_enable(psmouse, true); + res = fsp_reg_write(psmouse, FSP_REG_OPC_QDOWN, nv); + fsp_reg_write_enable(psmouse, false); + } + + if (res != 0) { + dev_err(&psmouse->ps2dev.serio->dev, + "Unable to enable OPC tag.\n"); + res = -EIO; + } + + return res; +} + +static int fsp_onpad_vscr(struct psmouse *psmouse, bool enable) +{ + struct fsp_data *pad = psmouse->private; + int val; + + if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val)) + return -EIO; + + pad->vscroll = enable; + + if (enable) + val |= (FSP_BIT_FIX_VSCR | FSP_BIT_ONPAD_ENABLE); + else + val &= ~FSP_BIT_FIX_VSCR; + + if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val)) + return -EIO; + + return 0; +} + +static int fsp_onpad_hscr(struct psmouse *psmouse, bool enable) +{ + struct fsp_data *pad = psmouse->private; + int val, v2; + + if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val)) + return -EIO; + + if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &v2)) + return -EIO; + + pad->hscroll = enable; + + if (enable) { + val |= (FSP_BIT_FIX_HSCR | FSP_BIT_ONPAD_ENABLE); + v2 |= FSP_BIT_EN_MSID6; + } else { + val &= ~FSP_BIT_FIX_HSCR; + v2 &= ~(FSP_BIT_EN_MSID6 | FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8); + } + + if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val)) + return -EIO; + + /* reconfigure horizontal scrolling packet output */ + if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, v2)) + return -EIO; + + return 0; +} + +/* + * Write device specific initial parameters. + * + * ex: 0xab 0xcd - write oxcd into register 0xab + */ +static ssize_t fsp_attr_set_setreg(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + unsigned long reg, val; + char *rest; + ssize_t retval; + + reg = simple_strtoul(buf, &rest, 16); + if (rest == buf || *rest != ' ' || reg > 0xff) + return -EINVAL; + + if (strict_strtoul(rest + 1, 16, &val) || val > 0xff) + return -EINVAL; + + if (fsp_reg_write_enable(psmouse, true)) + return -EIO; + + retval = fsp_reg_write(psmouse, reg, val) < 0 ? -EIO : count; + + fsp_reg_write_enable(psmouse, false); + + return count; +} + +PSMOUSE_DEFINE_WO_ATTR(setreg, S_IWUSR, NULL, fsp_attr_set_setreg); + +static ssize_t fsp_attr_show_getreg(struct psmouse *psmouse, + void *data, char *buf) +{ + struct fsp_data *pad = psmouse->private; + + return sprintf(buf, "%02x%02x\n", pad->last_reg, pad->last_val); +} + +/* + * Read a register from device. + * + * ex: 0xab -- read content from register 0xab + */ +static ssize_t fsp_attr_set_getreg(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + struct fsp_data *pad = psmouse->private; + unsigned long reg; + int val; + + if (strict_strtoul(buf, 16, ®) || reg > 0xff) + return -EINVAL; + + if (fsp_reg_read(psmouse, reg, &val)) + return -EIO; + + pad->last_reg = reg; + pad->last_val = val; + + return count; +} + +PSMOUSE_DEFINE_ATTR(getreg, S_IWUSR | S_IRUGO, NULL, + fsp_attr_show_getreg, fsp_attr_set_getreg); + +static ssize_t fsp_attr_show_pagereg(struct psmouse *psmouse, + void *data, char *buf) +{ + int val = 0; + + if (fsp_page_reg_read(psmouse, &val)) + return -EIO; + + return sprintf(buf, "%02x\n", val); +} + +static ssize_t fsp_attr_set_pagereg(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + unsigned long val; + + if (strict_strtoul(buf, 16, &val) || val > 0xff) + return -EINVAL; + + if (fsp_page_reg_write(psmouse, val)) + return -EIO; + + return count; +} + +PSMOUSE_DEFINE_ATTR(page, S_IWUSR | S_IRUGO, NULL, + fsp_attr_show_pagereg, fsp_attr_set_pagereg); + +static ssize_t fsp_attr_show_vscroll(struct psmouse *psmouse, + void *data, char *buf) +{ + struct fsp_data *pad = psmouse->private; + + return sprintf(buf, "%d\n", pad->vscroll); +} + +static ssize_t fsp_attr_set_vscroll(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + unsigned long val; + + if (strict_strtoul(buf, 10, &val) || val > 1) + return -EINVAL; + + fsp_onpad_vscr(psmouse, val); + + return count; +} + +PSMOUSE_DEFINE_ATTR(vscroll, S_IWUSR | S_IRUGO, NULL, + fsp_attr_show_vscroll, fsp_attr_set_vscroll); + +static ssize_t fsp_attr_show_hscroll(struct psmouse *psmouse, + void *data, char *buf) +{ + struct fsp_data *pad = psmouse->private; + + return sprintf(buf, "%d\n", pad->hscroll); +} + +static ssize_t fsp_attr_set_hscroll(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + unsigned long val; + + if (strict_strtoul(buf, 10, &val) || val > 1) + return -EINVAL; + + fsp_onpad_hscr(psmouse, val); + + return count; +} + +PSMOUSE_DEFINE_ATTR(hscroll, S_IWUSR | S_IRUGO, NULL, + fsp_attr_show_hscroll, fsp_attr_set_hscroll); + +static ssize_t fsp_attr_show_flags(struct psmouse *psmouse, + void *data, char *buf) +{ + struct fsp_data *pad = psmouse->private; + + return sprintf(buf, "%c\n", + pad->flags & FSPDRV_FLAG_EN_OPC ? 'C' : 'c'); +} + +static ssize_t fsp_attr_set_flags(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + struct fsp_data *pad = psmouse->private; + size_t i; + + for (i = 0; i < count; i++) { + switch (buf[i]) { + case 'C': + pad->flags |= FSPDRV_FLAG_EN_OPC; + break; + case 'c': + pad->flags &= ~FSPDRV_FLAG_EN_OPC; + break; + default: + return -EINVAL; + } + } + return count; +} + +PSMOUSE_DEFINE_ATTR(flags, S_IWUSR | S_IRUGO, NULL, + fsp_attr_show_flags, fsp_attr_set_flags); + +static ssize_t fsp_attr_show_ver(struct psmouse *psmouse, + void *data, char *buf) +{ + return sprintf(buf, "Sentelic FSP kernel module %s\n", fsp_drv_ver); +} + +PSMOUSE_DEFINE_RO_ATTR(ver, S_IRUGO, NULL, fsp_attr_show_ver); + +static struct attribute *fsp_attributes[] = { + &psmouse_attr_setreg.dattr.attr, + &psmouse_attr_getreg.dattr.attr, + &psmouse_attr_page.dattr.attr, + &psmouse_attr_vscroll.dattr.attr, + &psmouse_attr_hscroll.dattr.attr, + &psmouse_attr_flags.dattr.attr, + &psmouse_attr_ver.dattr.attr, + NULL +}; + +static struct attribute_group fsp_attribute_group = { + .attrs = fsp_attributes, +}; + +#ifdef FSP_DEBUG +static void fsp_packet_debug(unsigned char packet[]) +{ + static unsigned int ps2_packet_cnt; + static unsigned int ps2_last_second; + unsigned int jiffies_msec; + + ps2_packet_cnt++; + jiffies_msec = jiffies_to_msecs(jiffies); + printk(KERN_DEBUG "%08dms PS/2 packets: %02x, %02x, %02x, %02x\n", + jiffies_msec, packet[0], packet[1], packet[2], packet[3]); + + if (jiffies_msec - ps2_last_second > 1000) { + printk(KERN_DEBUG "PS/2 packets/sec = %d\n", ps2_packet_cnt); + ps2_packet_cnt = 0; + ps2_last_second = jiffies_msec; + } +} +#else +static void fsp_packet_debug(unsigned char packet[]) +{ +} +#endif + +static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse) +{ + struct input_dev *dev = psmouse->dev; + struct fsp_data *ad = psmouse->private; + unsigned char *packet = psmouse->packet; + unsigned char button_status = 0, lscroll = 0, rscroll = 0; + int rel_x, rel_y; + + if (psmouse->pktcnt < 4) + return PSMOUSE_GOOD_DATA; + + /* + * Full packet accumulated, process it + */ + + switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) { + case FSP_PKT_TYPE_ABS: + dev_warn(&psmouse->ps2dev.serio->dev, + "Unexpected absolute mode packet, ignored.\n"); + break; + + case FSP_PKT_TYPE_NORMAL_OPC: + /* on-pad click, filter it if necessary */ + if ((ad->flags & FSPDRV_FLAG_EN_OPC) != FSPDRV_FLAG_EN_OPC) + packet[0] &= ~BIT(0); + /* fall through */ + + case FSP_PKT_TYPE_NORMAL: + /* normal packet */ + /* special packet data translation from on-pad packets */ + if (packet[3] != 0) { + if (packet[3] & BIT(0)) + button_status |= 0x01; /* wheel down */ + if (packet[3] & BIT(1)) + button_status |= 0x0f; /* wheel up */ + if (packet[3] & BIT(2)) + button_status |= BIT(5);/* horizontal left */ + if (packet[3] & BIT(3)) + button_status |= BIT(4);/* horizontal right */ + /* push back to packet queue */ + if (button_status != 0) + packet[3] = button_status; + rscroll = (packet[3] >> 4) & 1; + lscroll = (packet[3] >> 5) & 1; + } + /* + * Processing wheel up/down and extra button events + */ + input_report_rel(dev, REL_WHEEL, + (int)(packet[3] & 8) - (int)(packet[3] & 7)); + input_report_rel(dev, REL_HWHEEL, lscroll - rscroll); + input_report_key(dev, BTN_BACK, lscroll); + input_report_key(dev, BTN_FORWARD, rscroll); + + /* + * Standard PS/2 Mouse + */ + input_report_key(dev, BTN_LEFT, packet[0] & 1); + input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1); + input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1); + + rel_x = packet[1] ? (int)packet[1] - (int)((packet[0] << 4) & 0x100) : 0; + rel_y = packet[2] ? (int)((packet[0] << 3) & 0x100) - (int)packet[2] : 0; + + input_report_rel(dev, REL_X, rel_x); + input_report_rel(dev, REL_Y, rel_y); + break; + } + + input_sync(dev); + + fsp_packet_debug(packet); + + return PSMOUSE_FULL_PACKET; +} + +static int fsp_activate_protocol(struct psmouse *psmouse) +{ + struct fsp_data *pad = psmouse->private; + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char param[2]; + int val; + + /* + * Standard procedure to enter FSP Intellimouse mode + * (scrolling wheel, 4th and 5th buttons) + */ + param[0] = 200; + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); + param[0] = 200; + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); + param[0] = 80; + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); + + ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); + if (param[0] != 0x04) { + dev_err(&psmouse->ps2dev.serio->dev, + "Unable to enable 4 bytes packet format.\n"); + return -EIO; + } + + if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &val)) { + dev_err(&psmouse->ps2dev.serio->dev, + "Unable to read SYSCTL5 register.\n"); + return -EIO; + } + + val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 | FSP_BIT_EN_AUTO_MSID8); + /* Ensure we are not in absolute mode */ + val &= ~FSP_BIT_EN_PKT_G0; + if (pad->buttons == 0x06) { + /* Left/Middle/Right & Scroll Up/Down/Right/Left */ + val |= FSP_BIT_EN_MSID6; + } + + if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, val)) { + dev_err(&psmouse->ps2dev.serio->dev, + "Unable to set up required mode bits.\n"); + return -EIO; + } + + /* + * Enable OPC tags such that driver can tell the difference between + * on-pad and real button click + */ + if (fsp_opc_tag_enable(psmouse, true)) + dev_warn(&psmouse->ps2dev.serio->dev, + "Failed to enable OPC tag mode.\n"); + + /* Enable on-pad vertical and horizontal scrolling */ + fsp_onpad_vscr(psmouse, true); + fsp_onpad_hscr(psmouse, true); + + return 0; +} + +int fsp_detect(struct psmouse *psmouse, int set_properties) +{ + int id; + + if (fsp_reg_read(psmouse, FSP_REG_DEVICE_ID, &id)) + return -EIO; + + if (id != 0x01) + return -ENODEV; + + if (set_properties) { + psmouse->vendor = "Sentelic"; + psmouse->name = "FingerSensingPad"; + } + + return 0; +} + +static void fsp_reset(struct psmouse *psmouse) +{ + fsp_opc_tag_enable(psmouse, false); + fsp_onpad_vscr(psmouse, false); + fsp_onpad_hscr(psmouse, false); +} + +static void fsp_disconnect(struct psmouse *psmouse) +{ + sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, + &fsp_attribute_group); + + fsp_reset(psmouse); + kfree(psmouse->private); +} + +static int fsp_reconnect(struct psmouse *psmouse) +{ + int version; + + if (fsp_detect(psmouse, 0)) + return -ENODEV; + + if (fsp_get_version(psmouse, &version)) + return -ENODEV; + + if (fsp_activate_protocol(psmouse)) + return -EIO; + + return 0; +} + +int fsp_init(struct psmouse *psmouse) +{ + struct fsp_data *priv; + int ver, rev, buttons; + int error; + + if (fsp_get_version(psmouse, &ver) || + fsp_get_revision(psmouse, &rev) || + fsp_get_buttons(psmouse, &buttons)) { + return -ENODEV; + } + + printk(KERN_INFO + "Finger Sensing Pad, hw: %d.%d.%d, sw: %s, buttons: %d\n", + ver >> 4, ver & 0x0F, rev, fsp_drv_ver, buttons & 7); + + psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->ver = ver; + priv->rev = rev; + priv->buttons = buttons; + + /* enable on-pad click by default */ + priv->flags |= FSPDRV_FLAG_EN_OPC; + + /* Set up various supported input event bits */ + __set_bit(BTN_BACK, psmouse->dev->keybit); + __set_bit(BTN_FORWARD, psmouse->dev->keybit); + __set_bit(REL_WHEEL, psmouse->dev->relbit); + __set_bit(REL_HWHEEL, psmouse->dev->relbit); + + psmouse->protocol_handler = fsp_process_byte; + psmouse->disconnect = fsp_disconnect; + psmouse->reconnect = fsp_reconnect; + psmouse->cleanup = fsp_reset; + psmouse->pktsize = 4; + + /* set default packet output based on number of buttons we found */ + error = fsp_activate_protocol(psmouse); + if (error) + goto err_out; + + error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj, + &fsp_attribute_group); + if (error) { + dev_err(&psmouse->ps2dev.serio->dev, + "Failed to create sysfs attributes (%d)", error); + goto err_out; + } + + return 0; + + err_out: + kfree(psmouse->private); + psmouse->private = NULL; + return error; +} diff --git a/drivers/input/mouse/sentelic.h b/drivers/input/mouse/sentelic.h new file mode 100644 index 00000000000..083559c7282 --- /dev/null +++ b/drivers/input/mouse/sentelic.h @@ -0,0 +1,98 @@ +/*- + * Finger Sensing Pad PS/2 mouse driver. + * + * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd. + * Copyright (C) 2005-2009 Tai-hwa Liang, Sentelic Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __SENTELIC_H +#define __SENTELIC_H + +/* Finger-sensing Pad information registers */ +#define FSP_REG_DEVICE_ID 0x00 +#define FSP_REG_VERSION 0x01 +#define FSP_REG_REVISION 0x04 +#define FSP_REG_TMOD_STATUS1 0x0B +#define FSP_BIT_NO_ROTATION BIT(3) +#define FSP_REG_PAGE_CTRL 0x0F + +/* Finger-sensing Pad control registers */ +#define FSP_REG_SYSCTL1 0x10 +#define FSP_BIT_EN_REG_CLK BIT(5) +#define FSP_REG_OPC_QDOWN 0x31 +#define FSP_BIT_EN_OPC_TAG BIT(7) +#define FSP_REG_OPTZ_XLO 0x34 +#define FSP_REG_OPTZ_XHI 0x35 +#define FSP_REG_OPTZ_YLO 0x36 +#define FSP_REG_OPTZ_YHI 0x37 +#define FSP_REG_SYSCTL5 0x40 +#define FSP_BIT_90_DEGREE BIT(0) +#define FSP_BIT_EN_MSID6 BIT(1) +#define FSP_BIT_EN_MSID7 BIT(2) +#define FSP_BIT_EN_MSID8 BIT(3) +#define FSP_BIT_EN_AUTO_MSID8 BIT(5) +#define FSP_BIT_EN_PKT_G0 BIT(6) + +#define FSP_REG_ONPAD_CTL 0x43 +#define FSP_BIT_ONPAD_ENABLE BIT(0) +#define FSP_BIT_ONPAD_FBBB BIT(1) +#define FSP_BIT_FIX_VSCR BIT(3) +#define FSP_BIT_FIX_HSCR BIT(5) +#define FSP_BIT_DRAG_LOCK BIT(6) + +/* Finger-sensing Pad packet formating related definitions */ + +/* absolute packet type */ +#define FSP_PKT_TYPE_NORMAL (0x00) +#define FSP_PKT_TYPE_ABS (0x01) +#define FSP_PKT_TYPE_NOTIFY (0x02) +#define FSP_PKT_TYPE_NORMAL_OPC (0x03) +#define FSP_PKT_TYPE_SHIFT (6) + +#ifdef __KERNEL__ + +struct fsp_data { + unsigned char ver; /* hardware version */ + unsigned char rev; /* hardware revison */ + unsigned char buttons; /* Number of buttons */ + unsigned int flags; +#define FSPDRV_FLAG_EN_OPC (0x001) /* enable on-pad clicking */ + + bool vscroll; /* Vertical scroll zone enabled */ + bool hscroll; /* Horizontal scroll zone enabled */ + + unsigned char last_reg; /* Last register we requested read from */ + unsigned char last_val; +}; + +#ifdef CONFIG_MOUSE_PS2_SENTELIC +extern int fsp_detect(struct psmouse *psmouse, int set_properties); +extern int fsp_init(struct psmouse *psmouse); +#else +inline int fsp_detect(struct psmouse *psmouse, int set_properties) +{ + return -ENOSYS; +} +inline int fsp_init(struct psmouse *psmouse) +{ + return -ENOSYS; +} +#endif + +#endif /* __KERNEL__ */ + +#endif /* !__SENTELIC_H */ diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index be5bbbb8ae4..3a95b508bf2 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -161,7 +161,7 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout) * ps2_command() can only be called from a process context */ -int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) +int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) { int timeout; int send = (command >> 12) & 0xf; @@ -179,8 +179,6 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) return -1; } - mutex_lock(&ps2dev->cmd_mutex); - serio_pause_rx(ps2dev->serio); ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0; ps2dev->cmdcnt = receive; @@ -231,7 +229,18 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) ps2dev->flags = 0; serio_continue_rx(ps2dev->serio); + return rc; +} +EXPORT_SYMBOL(__ps2_command); + +int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) +{ + int rc; + + mutex_lock(&ps2dev->cmd_mutex); + rc = __ps2_command(ps2dev, param, command); mutex_unlock(&ps2dev->cmd_mutex); + return rc; } EXPORT_SYMBOL(ps2_command); -- cgit v1.2.3-18-g5258 From bb81b2ddfa194b6d12761a350b5b5985cecae0a9 Mon Sep 17 00:00:00 2001 From: John Linn Date: Thu, 20 Aug 2009 02:52:16 -0700 Subject: net: add Xilinx emac lite device driver This patch adds support for the Xilinx Ethernet Lite device. The soft logic core from Xilinx is typically used on Virtex and Spartan designs attached to either a PowerPC or a Microblaze processor. Signed-off-by: Sadanand M Signed-off-by: John Linn Signed-off-by: David S. Miller --- drivers/net/Kconfig | 6 + drivers/net/Makefile | 1 + drivers/net/xilinx_emaclite.c | 1041 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1048 insertions(+) create mode 100755 drivers/net/xilinx_emaclite.c (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 29935a9fb1a..bbe77a06584 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1926,6 +1926,12 @@ config ATL2 To compile this driver as a module, choose M here. The module will be called atl2. +config XILINX_EMACLITE + tristate "Xilinx 10/100 Ethernet Lite support" + depends on PPC32 || MICROBLAZE + help + This driver supports the 10/100 Ethernet Lite from Xilinx. + source "drivers/net/fs_enet/Kconfig" endif # NET_ETHERNET diff --git a/drivers/net/Makefile b/drivers/net/Makefile index ead8cab3cfe..99ae6d7fe6a 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -142,6 +142,7 @@ obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o ll_temac-objs := ll_temac_main.o ll_temac_mdio.o obj-$(CONFIG_XILINX_LL_TEMAC) += ll_temac.o +obj-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o obj-$(CONFIG_QLA3XXX) += qla3xxx.o obj-$(CONFIG_QLGE) += qlge/ diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c new file mode 100755 index 00000000000..7e05b40ae36 --- /dev/null +++ b/drivers/net/xilinx_emaclite.c @@ -0,0 +1,1041 @@ +/* + * Xilinx EmacLite Linux driver for the Xilinx Ethernet MAC Lite device. + * + * This is a new flat driver which is based on the original emac_lite + * driver from John Williams . + * + * 2007-2009 (c) Xilinx, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRIVER_NAME "xilinx_emaclite" + +/* Register offsets for the EmacLite Core */ +#define XEL_TXBUFF_OFFSET 0x0 /* Transmit Buffer */ +#define XEL_GIER_OFFSET 0x07F8 /* GIE Register */ +#define XEL_TSR_OFFSET 0x07FC /* Tx status */ +#define XEL_TPLR_OFFSET 0x07F4 /* Tx packet length */ + +#define XEL_RXBUFF_OFFSET 0x1000 /* Receive Buffer */ +#define XEL_RPLR_OFFSET 0x100C /* Rx packet length */ +#define XEL_RSR_OFFSET 0x17FC /* Rx status */ + +#define XEL_BUFFER_OFFSET 0x0800 /* Next Tx/Rx buffer's offset */ + +/* Global Interrupt Enable Register (GIER) Bit Masks */ +#define XEL_GIER_GIE_MASK 0x80000000 /* Global Enable */ + +/* Transmit Status Register (TSR) Bit Masks */ +#define XEL_TSR_XMIT_BUSY_MASK 0x00000001 /* Tx complete */ +#define XEL_TSR_PROGRAM_MASK 0x00000002 /* Program the MAC address */ +#define XEL_TSR_XMIT_IE_MASK 0x00000008 /* Tx interrupt enable bit */ +#define XEL_TSR_XMIT_ACTIVE_MASK 0x80000000 /* Buffer is active, SW bit + * only. This is not documented + * in the HW spec */ + +/* Define for programming the MAC address into the EmacLite */ +#define XEL_TSR_PROG_MAC_ADDR (XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_PROGRAM_MASK) + +/* Receive Status Register (RSR) */ +#define XEL_RSR_RECV_DONE_MASK 0x00000001 /* Rx complete */ +#define XEL_RSR_RECV_IE_MASK 0x00000008 /* Rx interrupt enable bit */ + +/* Transmit Packet Length Register (TPLR) */ +#define XEL_TPLR_LENGTH_MASK 0x0000FFFF /* Tx packet length */ + +/* Receive Packet Length Register (RPLR) */ +#define XEL_RPLR_LENGTH_MASK 0x0000FFFF /* Rx packet length */ + +#define XEL_HEADER_OFFSET 12 /* Offset to length field */ +#define XEL_HEADER_SHIFT 16 /* Shift value for length */ + +/* General Ethernet Definitions */ +#define XEL_ARP_PACKET_SIZE 28 /* Max ARP packet size */ +#define XEL_HEADER_IP_LENGTH_OFFSET 16 /* IP Length Offset */ + + + +#define TX_TIMEOUT (60*HZ) /* Tx timeout is 60 seconds. */ +#define ALIGNMENT 4 + +/* BUFFER_ALIGN(adr) calculates the number of bytes to the next alignment. */ +#define BUFFER_ALIGN(adr) ((ALIGNMENT - ((u32) adr)) % ALIGNMENT) + +/** + * struct net_local - Our private per device data + * @ndev: instance of the network device + * @tx_ping_pong: indicates whether Tx Pong buffer is configured in HW + * @rx_ping_pong: indicates whether Rx Pong buffer is configured in HW + * @next_tx_buf_to_use: next Tx buffer to write to + * @next_rx_buf_to_use: next Rx buffer to read from + * @base_addr: base address of the Emaclite device + * @reset_lock: lock used for synchronization + * @deferred_skb: holds an skb (for transmission at a later time) when the + * Tx buffer is not free + */ +struct net_local { + + struct net_device *ndev; + + bool tx_ping_pong; + bool rx_ping_pong; + u32 next_tx_buf_to_use; + u32 next_rx_buf_to_use; + void __iomem *base_addr; + + spinlock_t reset_lock; + struct sk_buff *deferred_skb; +}; + + +/*************************/ +/* EmacLite driver calls */ +/*************************/ + +/** + * xemaclite_enable_interrupts - Enable the interrupts for the EmacLite device + * @drvdata: Pointer to the Emaclite device private data + * + * This function enables the Tx and Rx interrupts for the Emaclite device along + * with the Global Interrupt Enable. + */ +static void xemaclite_enable_interrupts(struct net_local *drvdata) +{ + u32 reg_data; + + /* Enable the Tx interrupts for the first Buffer */ + reg_data = in_be32(drvdata->base_addr + XEL_TSR_OFFSET); + out_be32(drvdata->base_addr + XEL_TSR_OFFSET, + reg_data | XEL_TSR_XMIT_IE_MASK); + + /* Enable the Tx interrupts for the second Buffer if + * configured in HW */ + if (drvdata->tx_ping_pong != 0) { + reg_data = in_be32(drvdata->base_addr + + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET); + out_be32(drvdata->base_addr + XEL_BUFFER_OFFSET + + XEL_TSR_OFFSET, + reg_data | XEL_TSR_XMIT_IE_MASK); + } + + /* Enable the Rx interrupts for the first buffer */ + reg_data = in_be32(drvdata->base_addr + XEL_RSR_OFFSET); + out_be32(drvdata->base_addr + XEL_RSR_OFFSET, + reg_data | XEL_RSR_RECV_IE_MASK); + + /* Enable the Rx interrupts for the second Buffer if + * configured in HW */ + if (drvdata->rx_ping_pong != 0) { + reg_data = in_be32(drvdata->base_addr + XEL_BUFFER_OFFSET + + XEL_RSR_OFFSET); + out_be32(drvdata->base_addr + XEL_BUFFER_OFFSET + + XEL_RSR_OFFSET, + reg_data | XEL_RSR_RECV_IE_MASK); + } + + /* Enable the Global Interrupt Enable */ + out_be32(drvdata->base_addr + XEL_GIER_OFFSET, XEL_GIER_GIE_MASK); +} + +/** + * xemaclite_disable_interrupts - Disable the interrupts for the EmacLite device + * @drvdata: Pointer to the Emaclite device private data + * + * This function disables the Tx and Rx interrupts for the Emaclite device, + * along with the Global Interrupt Enable. + */ +static void xemaclite_disable_interrupts(struct net_local *drvdata) +{ + u32 reg_data; + + /* Disable the Global Interrupt Enable */ + out_be32(drvdata->base_addr + XEL_GIER_OFFSET, XEL_GIER_GIE_MASK); + + /* Disable the Tx interrupts for the first buffer */ + reg_data = in_be32(drvdata->base_addr + XEL_TSR_OFFSET); + out_be32(drvdata->base_addr + XEL_TSR_OFFSET, + reg_data & (~XEL_TSR_XMIT_IE_MASK)); + + /* Disable the Tx interrupts for the second Buffer + * if configured in HW */ + if (drvdata->tx_ping_pong != 0) { + reg_data = in_be32(drvdata->base_addr + XEL_BUFFER_OFFSET + + XEL_TSR_OFFSET); + out_be32(drvdata->base_addr + XEL_BUFFER_OFFSET + + XEL_TSR_OFFSET, + reg_data & (~XEL_TSR_XMIT_IE_MASK)); + } + + /* Disable the Rx interrupts for the first buffer */ + reg_data = in_be32(drvdata->base_addr + XEL_RSR_OFFSET); + out_be32(drvdata->base_addr + XEL_RSR_OFFSET, + reg_data & (~XEL_RSR_RECV_IE_MASK)); + + /* Disable the Rx interrupts for the second buffer + * if configured in HW */ + if (drvdata->rx_ping_pong != 0) { + + reg_data = in_be32(drvdata->base_addr + XEL_BUFFER_OFFSET + + XEL_RSR_OFFSET); + out_be32(drvdata->base_addr + XEL_BUFFER_OFFSET + + XEL_RSR_OFFSET, + reg_data & (~XEL_RSR_RECV_IE_MASK)); + } +} + +/** + * xemaclite_aligned_write - Write from 16-bit aligned to 32-bit aligned address + * @src_ptr: Void pointer to the 16-bit aligned source address + * @dest_ptr: Pointer to the 32-bit aligned destination address + * @length: Number bytes to write from source to destination + * + * This function writes data from a 16-bit aligned buffer to a 32-bit aligned + * address in the EmacLite device. + */ +static void xemaclite_aligned_write(void *src_ptr, u32 *dest_ptr, + unsigned length) +{ + u32 align_buffer; + u32 *to_u32_ptr; + u16 *from_u16_ptr, *to_u16_ptr; + + to_u32_ptr = dest_ptr; + from_u16_ptr = (u16 *) src_ptr; + align_buffer = 0; + + for (; length > 3; length -= 4) { + to_u16_ptr = (u16 *) ((void *) &align_buffer); + *to_u16_ptr++ = *from_u16_ptr++; + *to_u16_ptr++ = *from_u16_ptr++; + + /* Output a word */ + *to_u32_ptr++ = align_buffer; + } + if (length) { + u8 *from_u8_ptr, *to_u8_ptr; + + /* Set up to output the remaining data */ + align_buffer = 0; + to_u8_ptr = (u8 *) &align_buffer; + from_u8_ptr = (u8 *) from_u16_ptr; + + /* Output the remaining data */ + for (; length > 0; length--) + *to_u8_ptr++ = *from_u8_ptr++; + + *to_u32_ptr = align_buffer; + } +} + +/** + * xemaclite_aligned_read - Read from 32-bit aligned to 16-bit aligned buffer + * @src_ptr: Pointer to the 32-bit aligned source address + * @dest_ptr: Pointer to the 16-bit aligned destination address + * @length: Number bytes to read from source to destination + * + * This function reads data from a 32-bit aligned address in the EmacLite device + * to a 16-bit aligned buffer. + */ +static void xemaclite_aligned_read(u32 *src_ptr, u8 *dest_ptr, + unsigned length) +{ + u16 *to_u16_ptr, *from_u16_ptr; + u32 *from_u32_ptr; + u32 align_buffer; + + from_u32_ptr = src_ptr; + to_u16_ptr = (u16 *) dest_ptr; + + for (; length > 3; length -= 4) { + /* Copy each word into the temporary buffer */ + align_buffer = *from_u32_ptr++; + from_u16_ptr = (u16 *)&align_buffer; + + /* Read data from source */ + *to_u16_ptr++ = *from_u16_ptr++; + *to_u16_ptr++ = *from_u16_ptr++; + } + + if (length) { + u8 *to_u8_ptr, *from_u8_ptr; + + /* Set up to read the remaining data */ + to_u8_ptr = (u8 *) to_u16_ptr; + align_buffer = *from_u32_ptr++; + from_u8_ptr = (u8 *) &align_buffer; + + /* Read the remaining data */ + for (; length > 0; length--) + *to_u8_ptr = *from_u8_ptr; + } +} + +/** + * xemaclite_send_data - Send an Ethernet frame + * @drvdata: Pointer to the Emaclite device private data + * @data: Pointer to the data to be sent + * @byte_count: Total frame size, including header + * + * This function checks if the Tx buffer of the Emaclite device is free to send + * data. If so, it fills the Tx buffer with data for transmission. Otherwise, it + * returns an error. + * + * Return: 0 upon success or -1 if the buffer(s) are full. + * + * Note: The maximum Tx packet size can not be more than Ethernet header + * (14 Bytes) + Maximum MTU (1500 bytes). This is excluding FCS. + */ +static int xemaclite_send_data(struct net_local *drvdata, u8 *data, + unsigned int byte_count) +{ + u32 reg_data; + void __iomem *addr; + + /* Determine the expected Tx buffer address */ + addr = drvdata->base_addr + drvdata->next_tx_buf_to_use; + + /* If the length is too large, truncate it */ + if (byte_count > ETH_FRAME_LEN) + byte_count = ETH_FRAME_LEN; + + /* Check if the expected buffer is available */ + reg_data = in_be32(addr + XEL_TSR_OFFSET); + if ((reg_data & (XEL_TSR_XMIT_BUSY_MASK | + XEL_TSR_XMIT_ACTIVE_MASK)) == 0) { + + /* Switch to next buffer if configured */ + if (drvdata->tx_ping_pong != 0) + drvdata->next_tx_buf_to_use ^= XEL_BUFFER_OFFSET; + } else if (drvdata->tx_ping_pong != 0) { + /* If the expected buffer is full, try the other buffer, + * if it is configured in HW */ + + addr = (void __iomem __force *)((u32 __force)addr ^ + XEL_BUFFER_OFFSET); + reg_data = in_be32(addr + XEL_TSR_OFFSET); + + if ((reg_data & (XEL_TSR_XMIT_BUSY_MASK | + XEL_TSR_XMIT_ACTIVE_MASK)) != 0) + return -1; /* Buffers were full, return failure */ + } else + return -1; /* Buffer was full, return failure */ + + /* Write the frame to the buffer */ + xemaclite_aligned_write(data, (u32 __force *) addr, byte_count); + + out_be32(addr + XEL_TPLR_OFFSET, (byte_count & XEL_TPLR_LENGTH_MASK)); + + /* Update the Tx Status Register to indicate that there is a + * frame to send. Set the XEL_TSR_XMIT_ACTIVE_MASK flag which + * is used by the interrupt handler to check whether a frame + * has been transmitted */ + reg_data = in_be32(addr + XEL_TSR_OFFSET); + reg_data |= (XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_XMIT_ACTIVE_MASK); + out_be32(addr + XEL_TSR_OFFSET, reg_data); + + return 0; +} + +/** + * xemaclite_recv_data - Receive a frame + * @drvdata: Pointer to the Emaclite device private data + * @data: Address where the data is to be received + * + * This function is intended to be called from the interrupt context or + * with a wrapper which waits for the receive frame to be available. + * + * Return: Total number of bytes received + */ +static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data) +{ + void __iomem *addr; + u16 length, proto_type; + u32 reg_data; + + /* Determine the expected buffer address */ + addr = (drvdata->base_addr + drvdata->next_rx_buf_to_use); + + /* Verify which buffer has valid data */ + reg_data = in_be32(addr + XEL_RSR_OFFSET); + + if ((reg_data & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) { + if (drvdata->rx_ping_pong != 0) + drvdata->next_rx_buf_to_use ^= XEL_BUFFER_OFFSET; + } else { + /* The instance is out of sync, try other buffer if other + * buffer is configured, return 0 otherwise. If the instance is + * out of sync, do not update the 'next_rx_buf_to_use' since it + * will correct on subsequent calls */ + if (drvdata->rx_ping_pong != 0) + addr = (void __iomem __force *)((u32 __force)addr ^ + XEL_BUFFER_OFFSET); + else + return 0; /* No data was available */ + + /* Verify that buffer has valid data */ + reg_data = in_be32(addr + XEL_RSR_OFFSET); + if ((reg_data & XEL_RSR_RECV_DONE_MASK) != + XEL_RSR_RECV_DONE_MASK) + return 0; /* No data was available */ + } + + /* Get the protocol type of the ethernet frame that arrived */ + proto_type = ((in_be32(addr + XEL_HEADER_OFFSET + + XEL_RXBUFF_OFFSET) >> XEL_HEADER_SHIFT) & + XEL_RPLR_LENGTH_MASK); + + /* Check if received ethernet frame is a raw ethernet frame + * or an IP packet or an ARP packet */ + if (proto_type > (ETH_FRAME_LEN + ETH_FCS_LEN)) { + + if (proto_type == ETH_P_IP) { + length = ((in_be32(addr + + XEL_HEADER_IP_LENGTH_OFFSET + + XEL_RXBUFF_OFFSET) >> + XEL_HEADER_SHIFT) & + XEL_RPLR_LENGTH_MASK); + length += ETH_HLEN + ETH_FCS_LEN; + + } else if (proto_type == ETH_P_ARP) + length = XEL_ARP_PACKET_SIZE + ETH_HLEN + ETH_FCS_LEN; + else + /* Field contains type other than IP or ARP, use max + * frame size and let user parse it */ + length = ETH_FRAME_LEN + ETH_FCS_LEN; + } else + /* Use the length in the frame, plus the header and trailer */ + length = proto_type + ETH_HLEN + ETH_FCS_LEN; + + /* Read from the EmacLite device */ + xemaclite_aligned_read((u32 __force *) (addr + XEL_RXBUFF_OFFSET), + data, length); + + /* Acknowledge the frame */ + reg_data = in_be32(addr + XEL_RSR_OFFSET); + reg_data &= ~XEL_RSR_RECV_DONE_MASK; + out_be32(addr + XEL_RSR_OFFSET, reg_data); + + return length; +} + +/** + * xemaclite_set_mac_address - Set the MAC address for this device + * @drvdata: Pointer to the Emaclite device private data + * @address_ptr:Pointer to the MAC address (MAC address is a 48-bit value) + * + * Tx must be idle and Rx should be idle for deterministic results. + * It is recommended that this function should be called after the + * initialization and before transmission of any packets from the device. + * The MAC address can be programmed using any of the two transmit + * buffers (if configured). + */ +static void xemaclite_set_mac_address(struct net_local *drvdata, + u8 *address_ptr) +{ + void __iomem *addr; + u32 reg_data; + + /* Determine the expected Tx buffer address */ + addr = drvdata->base_addr + drvdata->next_tx_buf_to_use; + + xemaclite_aligned_write(address_ptr, (u32 __force *) addr, ETH_ALEN); + + out_be32(addr + XEL_TPLR_OFFSET, ETH_ALEN); + + /* Update the MAC address in the EmacLite */ + reg_data = in_be32(addr + XEL_TSR_OFFSET); + out_be32(addr + XEL_TSR_OFFSET, reg_data | XEL_TSR_PROG_MAC_ADDR); + + /* Wait for EmacLite to finish with the MAC address update */ + while ((in_be32(addr + XEL_TSR_OFFSET) & + XEL_TSR_PROG_MAC_ADDR) != 0) + ; +} + +/** + * xemaclite_tx_timeout - Callback for Tx Timeout + * @dev: Pointer to the network device + * + * This function is called when Tx time out occurs for Emaclite device. + */ +static void xemaclite_tx_timeout(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + unsigned long flags; + + dev_err(&lp->ndev->dev, "Exceeded transmit timeout of %lu ms\n", + TX_TIMEOUT * 1000UL / HZ); + + dev->stats.tx_errors++; + + /* Reset the device */ + spin_lock_irqsave(&lp->reset_lock, flags); + + /* Shouldn't really be necessary, but shouldn't hurt */ + netif_stop_queue(dev); + + xemaclite_disable_interrupts(lp); + xemaclite_enable_interrupts(lp); + + if (lp->deferred_skb) { + dev_kfree_skb(lp->deferred_skb); + lp->deferred_skb = NULL; + dev->stats.tx_errors++; + } + + /* To exclude tx timeout */ + dev->trans_start = 0xffffffff - TX_TIMEOUT - TX_TIMEOUT; + + /* We're all ready to go. Start the queue */ + netif_wake_queue(dev); + spin_unlock_irqrestore(&lp->reset_lock, flags); +} + +/**********************/ +/* Interrupt Handlers */ +/**********************/ + +/** + * xemaclite_tx_handler - Interrupt handler for frames sent + * @dev: Pointer to the network device + * + * This function updates the number of packets transmitted and handles the + * deferred skb, if there is one. + */ +static void xemaclite_tx_handler(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + + dev->stats.tx_packets++; + if (lp->deferred_skb) { + if (xemaclite_send_data(lp, + (u8 *) lp->deferred_skb->data, + lp->deferred_skb->len) != 0) + return; + else { + dev->stats.tx_bytes += lp->deferred_skb->len; + dev_kfree_skb_irq(lp->deferred_skb); + lp->deferred_skb = NULL; + dev->trans_start = jiffies; + netif_wake_queue(dev); + } + } +} + +/** + * xemaclite_rx_handler- Interrupt handler for frames received + * @dev: Pointer to the network device + * + * This function allocates memory for a socket buffer, fills it with data + * received and hands it over to the TCP/IP stack. + */ +static void xemaclite_rx_handler(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + struct sk_buff *skb; + unsigned int align; + u32 len; + + len = ETH_FRAME_LEN + ETH_FCS_LEN; + skb = dev_alloc_skb(len + ALIGNMENT); + if (!skb) { + /* Couldn't get memory. */ + dev->stats.rx_dropped++; + dev_err(&lp->ndev->dev, "Could not allocate receive buffer\n"); + return; + } + + /* + * A new skb should have the data halfword aligned, but this code is + * here just in case that isn't true. Calculate how many + * bytes we should reserve to get the data to start on a word + * boundary */ + align = BUFFER_ALIGN(skb->data); + if (align) + skb_reserve(skb, align); + + skb_reserve(skb, 2); + + len = xemaclite_recv_data(lp, (u8 *) skb->data); + + if (!len) { + dev->stats.rx_errors++; + dev_kfree_skb_irq(skb); + return; + } + + skb_put(skb, len); /* Tell the skb how much data we got */ + skb->dev = dev; /* Fill out required meta-data */ + + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_NONE; + + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; + dev->last_rx = jiffies; + + netif_rx(skb); /* Send the packet upstream */ +} + +/** + * xemaclite_interrupt - Interrupt handler for this driver + * @irq: Irq of the Emaclite device + * @dev_id: Void pointer to the network device instance used as callback + * reference + * + * This function handles the Tx and Rx interrupts of the EmacLite device. + */ +static irqreturn_t xemaclite_interrupt(int irq, void *dev_id) +{ + bool tx_complete = 0; + struct net_device *dev = dev_id; + struct net_local *lp = (struct net_local *) netdev_priv(dev); + void __iomem *base_addr = lp->base_addr; + u32 tx_status; + + /* Check if there is Rx Data available */ + if ((in_be32(base_addr + XEL_RSR_OFFSET) & XEL_RSR_RECV_DONE_MASK) || + (in_be32(base_addr + XEL_BUFFER_OFFSET + XEL_RSR_OFFSET) + & XEL_RSR_RECV_DONE_MASK)) + + xemaclite_rx_handler(dev); + + /* Check if the Transmission for the first buffer is completed */ + tx_status = in_be32(base_addr + XEL_TSR_OFFSET); + if (((tx_status & XEL_TSR_XMIT_BUSY_MASK) == 0) && + (tx_status & XEL_TSR_XMIT_ACTIVE_MASK) != 0) { + + tx_status &= ~XEL_TSR_XMIT_ACTIVE_MASK; + out_be32(base_addr + XEL_TSR_OFFSET, tx_status); + + tx_complete = 1; + } + + /* Check if the Transmission for the second buffer is completed */ + tx_status = in_be32(base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET); + if (((tx_status & XEL_TSR_XMIT_BUSY_MASK) == 0) && + (tx_status & XEL_TSR_XMIT_ACTIVE_MASK) != 0) { + + tx_status &= ~XEL_TSR_XMIT_ACTIVE_MASK; + out_be32(base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET, + tx_status); + + tx_complete = 1; + } + + /* If there was a Tx interrupt, call the Tx Handler */ + if (tx_complete != 0) + xemaclite_tx_handler(dev); + + return IRQ_HANDLED; +} + +/** + * xemaclite_open - Open the network device + * @dev: Pointer to the network device + * + * This function sets the MAC address, requests an IRQ and enables interrupts + * for the Emaclite device and starts the Tx queue. + */ +static int xemaclite_open(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + int retval; + + /* Just to be safe, stop the device first */ + xemaclite_disable_interrupts(lp); + + /* Set the MAC address each time opened */ + xemaclite_set_mac_address(lp, dev->dev_addr); + + /* Grab the IRQ */ + retval = request_irq(dev->irq, &xemaclite_interrupt, 0, dev->name, dev); + if (retval) { + dev_err(&lp->ndev->dev, "Could not allocate interrupt %d\n", + dev->irq); + return retval; + } + + /* Enable Interrupts */ + xemaclite_enable_interrupts(lp); + + /* We're ready to go */ + netif_start_queue(dev); + + return 0; +} + +/** + * xemaclite_close - Close the network device + * @dev: Pointer to the network device + * + * This function stops the Tx queue, disables interrupts and frees the IRQ for + * the Emaclite device. + */ +static int xemaclite_close(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + + netif_stop_queue(dev); + xemaclite_disable_interrupts(lp); + free_irq(dev->irq, dev); + + return 0; +} + +/** + * xemaclite_get_stats - Get the stats for the net_device + * @dev: Pointer to the network device + * + * This function returns the address of the 'net_device_stats' structure for the + * given network device. This structure holds usage statistics for the network + * device. + * + * Return: Pointer to the net_device_stats structure. + */ +static struct net_device_stats *xemaclite_get_stats(struct net_device *dev) +{ + return &dev->stats; +} + +/** + * xemaclite_send - Transmit a frame + * @orig_skb: Pointer to the socket buffer to be transmitted + * @dev: Pointer to the network device + * + * This function checks if the Tx buffer of the Emaclite device is free to send + * data. If so, it fills the Tx buffer with data from socket buffer data, + * updates the stats and frees the socket buffer. The Tx completion is signaled + * by an interrupt. If the Tx buffer isn't free, then the socket buffer is + * deferred and the Tx queue is stopped so that the deferred socket buffer can + * be transmitted when the Emaclite device is free to transmit data. + * + * Return: 0, always. + */ +static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + struct sk_buff *new_skb; + unsigned int len; + unsigned long flags; + + len = orig_skb->len; + + new_skb = orig_skb; + + spin_lock_irqsave(&lp->reset_lock, flags); + if (xemaclite_send_data(lp, (u8 *) new_skb->data, len) != 0) { + /* If the Emaclite Tx buffer is busy, stop the Tx queue and + * defer the skb for transmission at a later point when the + * current transmission is complete */ + netif_stop_queue(dev); + lp->deferred_skb = new_skb; + spin_unlock_irqrestore(&lp->reset_lock, flags); + return 0; + } + spin_unlock_irqrestore(&lp->reset_lock, flags); + + dev->stats.tx_bytes += len; + dev_kfree_skb(new_skb); + dev->trans_start = jiffies; + + return 0; +} + +/** + * xemaclite_ioctl - Perform IO Control operations on the network device + * @dev: Pointer to the network device + * @rq: Pointer to the interface request structure + * @cmd: IOCTL command + * + * The only IOCTL operation supported by this function is setting the MAC + * address. An error is reported if any other operations are requested. + * + * Return: 0 to indicate success, or a negative error for failure. + */ +static int xemaclite_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct net_local *lp = (struct net_local *) netdev_priv(dev); + struct hw_addr_data *hw_addr = (struct hw_addr_data *) &rq->ifr_hwaddr; + + switch (cmd) { + case SIOCETHTOOL: + return -EIO; + + case SIOCSIFHWADDR: + dev_err(&lp->ndev->dev, "SIOCSIFHWADDR\n"); + + /* Copy MAC address in from user space */ + copy_from_user((void __force *) dev->dev_addr, + (void __user __force *) hw_addr, + IFHWADDRLEN); + xemaclite_set_mac_address(lp, dev->dev_addr); + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +/** + * xemaclite_remove_ndev - Free the network device + * @ndev: Pointer to the network device to be freed + * + * This function un maps the IO region of the Emaclite device and frees the net + * device. + */ +static void xemaclite_remove_ndev(struct net_device *ndev) +{ + if (ndev) { + struct net_local *lp = (struct net_local *) netdev_priv(ndev); + + if (lp->base_addr) + iounmap((void __iomem __force *) (lp->base_addr)); + free_netdev(ndev); + } +} + +/** + * get_bool - Get a parameter from the OF device + * @ofdev: Pointer to OF device structure + * @s: Property to be retrieved + * + * This function looks for a property in the device node and returns the value + * of the property if its found or 0 if the property is not found. + * + * Return: Value of the parameter if the parameter is found, or 0 otherwise + */ +static bool get_bool(struct of_device *ofdev, const char *s) +{ + u32 *p = (u32 *)of_get_property(ofdev->node, s, NULL); + + if (p) { + return (bool)*p; + } else { + dev_warn(&ofdev->dev, "Parameter %s not found," + "defaulting to false\n", s); + return 0; + } +} + +static struct net_device_ops xemaclite_netdev_ops; + +/** + * xemaclite_of_probe - Probe method for the Emaclite device. + * @ofdev: Pointer to OF device structure + * @match: Pointer to the structure used for matching a device + * + * This function probes for the Emaclite device in the device tree. + * It initializes the driver data structure and the hardware, sets the MAC + * address and registers the network device. + * + * Return: 0, if the driver is bound to the Emaclite device, or + * a negative error if there is failure. + */ +static int __devinit xemaclite_of_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct resource r_irq; /* Interrupt resources */ + struct resource r_mem; /* IO mem resources */ + struct net_device *ndev = NULL; + struct net_local *lp = NULL; + struct device *dev = &ofdev->dev; + const void *mac_address; + + int rc = 0; + + dev_info(dev, "Device Tree Probing\n"); + + /* Get iospace for the device */ + rc = of_address_to_resource(ofdev->node, 0, &r_mem); + if (rc) { + dev_err(dev, "invalid address\n"); + return rc; + } + + /* Get IRQ for the device */ + rc = of_irq_to_resource(ofdev->node, 0, &r_irq); + if (rc == NO_IRQ) { + dev_err(dev, "no IRQ found\n"); + return rc; + } + + /* Create an ethernet device instance */ + ndev = alloc_etherdev(sizeof(struct net_local)); + if (!ndev) { + dev_err(dev, "Could not allocate network device\n"); + return -ENOMEM; + } + + dev_set_drvdata(dev, ndev); + + ndev->irq = r_irq.start; + ndev->mem_start = r_mem.start; + ndev->mem_end = r_mem.end; + + lp = netdev_priv(ndev); + lp->ndev = ndev; + + if (!request_mem_region(ndev->mem_start, + ndev->mem_end - ndev->mem_start + 1, + DRIVER_NAME)) { + dev_err(dev, "Couldn't lock memory region at %p\n", + (void *)ndev->mem_start); + rc = -EBUSY; + goto error2; + } + + /* Get the virtual base address for the device */ + lp->base_addr = ioremap(r_mem.start, r_mem.end - r_mem.start + 1); + if (NULL == lp->base_addr) { + dev_err(dev, "EmacLite: Could not allocate iomem\n"); + rc = -EIO; + goto error1; + } + + spin_lock_init(&lp->reset_lock); + lp->next_tx_buf_to_use = 0x0; + lp->next_rx_buf_to_use = 0x0; + lp->tx_ping_pong = get_bool(ofdev, "xlnx,tx-ping-pong"); + lp->rx_ping_pong = get_bool(ofdev, "xlnx,rx-ping-pong"); + mac_address = of_get_mac_address(ofdev->node); + + if (mac_address) + /* Set the MAC address. */ + memcpy(ndev->dev_addr, mac_address, 6); + else + dev_warn(dev, "No MAC address found\n"); + + /* Clear the Tx CSR's in case this is a restart */ + out_be32(lp->base_addr + XEL_TSR_OFFSET, 0); + out_be32(lp->base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET, 0); + + /* Set the MAC address in the EmacLite device */ + xemaclite_set_mac_address(lp, ndev->dev_addr); + + dev_info(dev, + "MAC address is now %2x:%2x:%2x:%2x:%2x:%2x\n", + ndev->dev_addr[0], ndev->dev_addr[1], + ndev->dev_addr[2], ndev->dev_addr[3], + ndev->dev_addr[4], ndev->dev_addr[5]); + + ndev->netdev_ops = &xemaclite_netdev_ops; + ndev->flags &= ~IFF_MULTICAST; + ndev->watchdog_timeo = TX_TIMEOUT; + + /* Finally, register the device */ + rc = register_netdev(ndev); + if (rc) { + dev_err(dev, + "Cannot register network device, aborting\n"); + goto error1; + } + + dev_info(dev, + "Xilinx EmacLite at 0x%08X mapped to 0x%08X, irq=%d\n", + (unsigned int __force)ndev->mem_start, + (unsigned int __force)lp->base_addr, ndev->irq); + return 0; + +error1: + release_mem_region(ndev->mem_start, r_mem.end - r_mem.start + 1); + +error2: + xemaclite_remove_ndev(ndev); + return rc; +} + +/** + * xemaclite_of_remove - Unbind the driver from the Emaclite device. + * @of_dev: Pointer to OF device structure + * + * This function is called if a device is physically removed from the system or + * if the driver module is being unloaded. It frees any resources allocated to + * the device. + * + * Return: 0, always. + */ +static int __devexit xemaclite_of_remove(struct of_device *of_dev) +{ + struct device *dev = &of_dev->dev; + struct net_device *ndev = dev_get_drvdata(dev); + + unregister_netdev(ndev); + + release_mem_region(ndev->mem_start, ndev->mem_end-ndev->mem_start + 1); + + xemaclite_remove_ndev(ndev); + + dev_set_drvdata(dev, NULL); + + return 0; +} + +static struct net_device_ops xemaclite_netdev_ops = { + .ndo_open = xemaclite_open, + .ndo_stop = xemaclite_close, + .ndo_start_xmit = xemaclite_send, + .ndo_do_ioctl = xemaclite_ioctl, + .ndo_tx_timeout = xemaclite_tx_timeout, + .ndo_get_stats = xemaclite_get_stats, +}; + +/* Match table for OF platform binding */ +static struct of_device_id xemaclite_of_match[] __devinitdata = { + { .compatible = "xlnx,opb-ethernetlite-1.01.a", }, + { .compatible = "xlnx,opb-ethernetlite-1.01.b", }, + { .compatible = "xlnx,xps-ethernetlite-1.00.a", }, + { .compatible = "xlnx,xps-ethernetlite-2.00.a", }, + { .compatible = "xlnx,xps-ethernetlite-2.01.a", }, + { /* end of list */ }, +}; +MODULE_DEVICE_TABLE(of, xemaclite_of_match); + +static struct of_platform_driver xemaclite_of_driver = { + .name = DRIVER_NAME, + .match_table = xemaclite_of_match, + .probe = xemaclite_of_probe, + .remove = __devexit_p(xemaclite_of_remove), +}; + +/** + * xgpiopss_init - Initial driver registration call + * + * Return: 0 upon success, or a negative error upon failure. + */ +static int __init xemaclite_init(void) +{ + /* No kernel boot options used, we just need to register the driver */ + return of_register_platform_driver(&xemaclite_of_driver); +} + +/** + * xemaclite_cleanup - Driver un-registration call + */ +static void __exit xemaclite_cleanup(void) +{ + of_unregister_platform_driver(&xemaclite_of_driver); +} + +module_init(xemaclite_init); +module_exit(xemaclite_cleanup); + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION("Xilinx Ethernet MAC Lite driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-18-g5258 From affbb8c6e690be2196258e65f3cc92d55b18d9fa Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 20 Aug 2009 12:04:14 +0200 Subject: HID: support larger reports than 64 bytes in hiddev hiddev userspace driver uses a rignbuffer to store the parsed usages that should be returned through read(). This buffer is 64 bytes long, which is sufficient for queueing single USB 1.0 low-speed report, which is of maximum size 48 bytes. There are however USB HID devices which are full-speed USB devices, and therefore they are free to produce reports 64 bytes long. This is correctly handled by HID core, but read() on hiddev node gets stuck forever, because the ring buffer loops infinitely (as it is exactly 64 bytes long as well), never advancing the buffer pointer. Plus, the core driver is ready to handle highspeed devices, so we should be able to handle reports from such devices in the hiddev driver as well, which means we need larger ringbuffer. Reported-by: Michael Zeisel Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hiddev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 215b2addddb..4d1dc0cf140 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -44,7 +44,7 @@ #define HIDDEV_MINOR_BASE 96 #define HIDDEV_MINORS 16 #endif -#define HIDDEV_BUFFER_SIZE 64 +#define HIDDEV_BUFFER_SIZE 2048 struct hiddev { int exist; -- cgit v1.2.3-18-g5258 From 2f19c287fecb958eb68b1c2199b4dd6e00ba4276 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Thu, 13 Aug 2009 16:51:51 +0200 Subject: b43: Update dummy transmission to match V4 specs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The V4 dummy transmission has two extra bools in its prototype, so update all callers with the 2 bools. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/lo.c | 2 +- drivers/net/wireless/b43/main.c | 42 ++++++++++++++++++++++++---------------- drivers/net/wireless/b43/main.h | 2 +- drivers/net/wireless/b43/phy_g.c | 6 +++--- drivers/net/wireless/b43/wa.c | 2 +- 5 files changed, 31 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c index 22d0fbd83a6..976104f634a 100644 --- a/drivers/net/wireless/b43/lo.c +++ b/drivers/net/wireless/b43/lo.c @@ -477,7 +477,7 @@ static void lo_measure_setup(struct b43_wldev *dev, } else b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x0802); if (phy->rev >= 2) - b43_dummy_transmission(dev); + b43_dummy_transmission(dev, false, true); b43_gphy_channel_switch(dev, 6, 0); b43_radio_read16(dev, 0x51); /* dummy read */ if (phy->type == B43_PHYTYPE_G) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 950beefbeae..f6d039e303f 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -691,9 +691,9 @@ static void b43_synchronize_irq(struct b43_wldev *dev) } /* DummyTransmission function, as documented on - * http://bcm-specs.sipsolutions.net/DummyTransmission + * http://bcm-v4.sipsolutions.net/802.11/DummyTransmission */ -void b43_dummy_transmission(struct b43_wldev *dev) +void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) { struct b43_wl *wl = dev->wl; struct b43_phy *phy = &dev->phy; @@ -707,19 +707,12 @@ void b43_dummy_transmission(struct b43_wldev *dev) 0x00000000, }; - switch (phy->type) { - case B43_PHYTYPE_A: + if (ofdm) { max_loop = 0x1E; buffer[0] = 0x000201CC; - break; - case B43_PHYTYPE_B: - case B43_PHYTYPE_G: + } else { max_loop = 0xFA; buffer[0] = 0x000B846E; - break; - default: - B43_WARN_ON(1); - return; } spin_lock_irq(&wl->irq_lock); @@ -728,20 +721,35 @@ void b43_dummy_transmission(struct b43_wldev *dev) for (i = 0; i < 5; i++) b43_ram_write(dev, i * 4, buffer[i]); - /* Commit writes */ - b43_read32(dev, B43_MMIO_MACCTL); - b43_write16(dev, 0x0568, 0x0000); - b43_write16(dev, 0x07C0, 0x0000); - value = ((phy->type == B43_PHYTYPE_A) ? 1 : 0); + if (dev->dev->id.revision < 11) + b43_write16(dev, 0x07C0, 0x0000); + else + b43_write16(dev, 0x07C0, 0x0100); + value = (ofdm ? 0x41 : 0x40); b43_write16(dev, 0x050C, value); + if ((phy->type == B43_PHYTYPE_N) || (phy->type == B43_PHYTYPE_LP)) + b43_write16(dev, 0x0514, 0x1A02); b43_write16(dev, 0x0508, 0x0000); b43_write16(dev, 0x050A, 0x0000); b43_write16(dev, 0x054C, 0x0000); b43_write16(dev, 0x056A, 0x0014); b43_write16(dev, 0x0568, 0x0826); b43_write16(dev, 0x0500, 0x0000); - b43_write16(dev, 0x0502, 0x0030); + if (!pa_on && (phy->type == B43_PHYTYPE_N)) { + //SPEC TODO + } + + switch (phy->type) { + case B43_PHYTYPE_N: + b43_write16(dev, 0x0502, 0x00D0); + break; + case B43_PHYTYPE_LP: + b43_write16(dev, 0x0502, 0x0050); + break; + default: + b43_write16(dev, 0x0502, 0x0030); + } if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) b43_radio_write16(dev, 0x0051, 0x0017); diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 950fb1b0546..0406e06781d 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -123,7 +123,7 @@ void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value u64 b43_hf_read(struct b43_wldev *dev); void b43_hf_write(struct b43_wldev *dev, u64 value); -void b43_dummy_transmission(struct b43_wldev *dev); +void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on); void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags); diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 5300232449f..e47131216a6 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -333,7 +333,7 @@ static void b43_set_all_gains(struct b43_wldev *dev, b43_phy_maskset(dev, 0x04A1, 0xBFBF, tmp); b43_phy_maskset(dev, 0x04A2, 0xBFBF, tmp); } - b43_dummy_transmission(dev); + b43_dummy_transmission(dev, false, true); } static void b43_set_original_gains(struct b43_wldev *dev) @@ -365,7 +365,7 @@ static void b43_set_original_gains(struct b43_wldev *dev) b43_phy_maskset(dev, 0x04A0, 0xBFBF, 0x4040); b43_phy_maskset(dev, 0x04A1, 0xBFBF, 0x4040); b43_phy_maskset(dev, 0x04A2, 0xBFBF, 0x4000); - b43_dummy_transmission(dev); + b43_dummy_transmission(dev, false, true); } /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ @@ -1964,7 +1964,7 @@ static void b43_phy_init_pctl(struct b43_wldev *dev) } b43_set_txpower_g(dev, &bbatt, &rfatt, 0); } - b43_dummy_transmission(dev); + b43_dummy_transmission(dev, false, true); gphy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI); if (B43_DEBUG) { /* Current-Idle-TSSI sanity check. */ diff --git a/drivers/net/wireless/b43/wa.c b/drivers/net/wireless/b43/wa.c index e1e20f69f6d..73e97fa4ddf 100644 --- a/drivers/net/wireless/b43/wa.c +++ b/drivers/net/wireless/b43/wa.c @@ -37,7 +37,7 @@ static void b43_wa_papd(struct b43_wldev *dev) backup = b43_ofdmtab_read16(dev, B43_OFDMTAB_PWRDYN2, 0); b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, 7); b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_APHY, 0, 0); - b43_dummy_transmission(dev); + b43_dummy_transmission(dev, true, true); b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, backup); } -- cgit v1.2.3-18-g5258 From 7021f62a46d4866fecd7b31cbc359d742876bb61 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Thu, 13 Aug 2009 17:27:31 +0200 Subject: b43: LP-PHY: Initialize TX power control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HW TX power control init still needs work. The SW init is complete according to the specs. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 105 +++++++++++++++++++++++++++++++++++--- drivers/net/wireless/b43/phy_lp.h | 5 ++ 2 files changed, 103 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index cfb8337d385..996b7eccfaf 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1257,18 +1257,109 @@ static void lpphy_calibration(struct b43_wldev *dev) b43_mac_enable(dev); } +static void lpphy_set_tssi_mux(struct b43_wldev *dev, enum tssi_mux_mode mode) +{ + if (mode != TSSI_MUX_EXT) { + b43_radio_set(dev, B2063_PA_SP1, 0x2); + b43_phy_set(dev, B43_PHY_OFDM(0xF3), 0x1000); + b43_radio_write(dev, B2063_PA_CTL10, 0x51); + if (mode == TSSI_MUX_POSTPA) { + b43_radio_mask(dev, B2063_PA_SP1, 0xFFFE); + b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFC7); + } else { + b43_radio_maskset(dev, B2063_PA_SP1, 0xFFFE, 0x1); + b43_phy_maskset(dev, B43_LPPHY_AFE_CTL_OVRVAL, + 0xFFC7, 0x20); + } + } else { + B43_WARN_ON(1); + } +} + +static void lpphy_tx_pctl_init_hw(struct b43_wldev *dev) +{ + u16 tmp; + int i; + + //SPEC TODO Call LP PHY Clear TX Power offsets + for (i = 0; i < 64; i++) { + if (dev->phy.rev >= 2) + b43_lptab_write(dev, B43_LPTAB32(7, i + 1), i); + else + b43_lptab_write(dev, B43_LPTAB32(10, i + 1), i); + } + + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0xFF00, 0xFF); + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0x8FFF, 0x5000); + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, 0xFFC0, 0x1F); + if (dev->phy.rev < 2) { + b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0xEFFF); + b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xDFFF, 0x2000); + } else { + b43_phy_mask(dev, B43_PHY_OFDM(0x103), 0xFFFE); + b43_phy_maskset(dev, B43_PHY_OFDM(0x103), 0xFFFB, 0x4); + b43_phy_maskset(dev, B43_PHY_OFDM(0x103), 0xFFEF, 0x10); + b43_radio_maskset(dev, B2063_IQ_CALIB_CTL2, 0xF3, 0x1); + lpphy_set_tssi_mux(dev, TSSI_MUX_POSTPA); + } + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, 0x7FFF, 0x8000); + b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xFF); + b43_phy_write(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xA); + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD, + (u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE, + B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF); + b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0xF8FF); + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD, + (u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE, + B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW); + + if (dev->phy.rev < 2) { + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_0, 0xEFFF, 0x1000); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xEFFF); + } else { + lpphy_set_tx_power_by_index(dev, 0x7F); + } + + b43_dummy_transmission(dev, true, true); + + tmp = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_STAT); + if (tmp & 0x8000) { + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, + 0xFFC0, (tmp & 0xFF) - 32); + } + + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xEFFF); + + // (SPEC?) TODO Set "Target TX frequency" variable to 0 + // SPEC FIXME "Set BB Multiplier to 0xE000" impossible - bb_mult is u8! +} + +static void lpphy_tx_pctl_init_sw(struct b43_wldev *dev) +{ + struct lpphy_tx_gains gains; + + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + gains.gm = 4; + gains.pad = 12; + gains.pga = 12; + gains.dac = 0; + } else { + gains.gm = 7; + gains.pad = 14; + gains.pga = 15; + gains.dac = 0; + } + lpphy_set_tx_gains(dev, gains); + lpphy_set_bb_mult(dev, 150); +} + /* Initialize TX power control */ static void lpphy_tx_pctl_init(struct b43_wldev *dev) { if (0/*FIXME HWPCTL capable */) { - //TODO + lpphy_tx_pctl_init_hw(dev); } else { /* This device is only software TX power control capable. */ - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { - //TODO - } else { - //TODO - } - //TODO set BB multiplier to 0x0096 + lpphy_tx_pctl_init_sw(dev); } } diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h index 0461d5b3144..4eab760ac61 100644 --- a/drivers/net/wireless/b43/phy_lp.h +++ b/drivers/net/wireless/b43/phy_lp.h @@ -886,6 +886,11 @@ struct b43_phy_lp { u16 dig_flt_state[9]; }; +enum tssi_mux_mode { + TSSI_MUX_PREPA, + TSSI_MUX_POSTPA, + TSSI_MUX_EXT, +}; struct b43_phy_operations; extern const struct b43_phy_operations b43_phyops_lp; -- cgit v1.2.3-18-g5258 From e6a6cf4c42e0dc3541a63b5f0f88299f982d6704 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Thu, 13 Aug 2009 13:30:50 -0700 Subject: iwlwifi: prevent read outside array bounds With EDCA and HCCA we have 16 potential tid values. This is accommodated by mac80211, but iwlwifi only supports EDCA. With this implementation it is thus possible for mac80211 to request a tid that will cause iwlwifi to read outside array bounds. A similar problem exists if traffic is received in an unsupported category. We add error checking to catch these situations. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 3 +++ drivers/net/wireless/iwlwifi/iwl-tx.c | 5 +++++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 ++ 3 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 21331552ff2..1bd7cd4dd80 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -332,6 +332,9 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data, } else return MAX_TID_COUNT; + if (unlikely(tid >= TID_MAX_LOAD_COUNT)) + return MAX_TID_COUNT; + tl = &lq_data->load[tid]; curr_time -= curr_time % TID_ROUND_VALUE; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 9b76bd41f21..7686fc72eb8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -745,6 +745,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + if (unlikely(tid >= MAX_TID_COUNT)) + goto drop_unlock; seq_number = priv->stations[sta_id].tid[tid].seq_number; seq_number &= IEEE80211_SCTL_SEQ; hdr->seq_ctrl = hdr->seq_ctrl & @@ -1238,6 +1240,9 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid) return -EINVAL; } + if (unlikely(tid >= MAX_TID_COUNT)) + return -EINVAL; + if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) tx_fifo_id = default_tid_to_tx_fifo[tid]; else diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index e617411d0c5..f339c5bd1fd 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -544,6 +544,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + if (unlikely(tid >= MAX_TID_COUNT)) + goto drop; seq_number = priv->stations[sta_id].tid[tid].seq_number & IEEE80211_SCTL_SEQ; hdr->seq_ctrl = cpu_to_le16(seq_number) | -- cgit v1.2.3-18-g5258 From be2527654fab254beda8612cbd6bc927dc98fbee Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Thu, 13 Aug 2009 13:30:51 -0700 Subject: iwlwifi: remove unused HT configuration entry tx_chan_width The tx_chan_width entry is never used, supported_chan_width is used instead. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 1 - drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index af735128333..479b7e165b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2423,7 +2423,6 @@ static void iwl_ht_conf(struct iwl_priv *priv, memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); - iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0; iwl_conf->ht_protection = bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; iwl_conf->non_GF_STA_present = diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index b96c3c9e92a..c34f9d73306 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -515,7 +515,6 @@ struct iwl_ht_info { struct ieee80211_mcs_info mcs; /* BSS related data */ u8 extension_chan_offset; - u8 tx_chan_width; u8 ht_protection; u8 non_GF_STA_present; }; -- cgit v1.2.3-18-g5258 From 7869b0eaed0447a989d8672eed27a358aa5dde0c Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Thu, 13 Aug 2009 13:30:52 -0700 Subject: iwlwifi: include HT configuration when adding stations through rs_rate_init Driver's first notification of a new station from mac80211 can be through rate selection API. This patch fixes a bug where, in this code path, the HT capabilities of the new station were ignored. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 1bd7cd4dd80..551c4ba3f17 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2522,6 +2522,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_supported_band *sband = txrc->sband; struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct ieee80211_conf *conf = &priv->hw->conf; + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_lq_sta *lq_sta = priv_sta; @@ -2554,7 +2555,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", hdr->addr1); sta_id = iwl_add_station(priv, hdr->addr1, - false, CMD_ASYNC, NULL); + false, CMD_ASYNC, ht_cap); } if ((sta_id != IWL_INVALID_STATION)) { lq_sta->lq.sta_id = sta_id; @@ -2623,6 +2624,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, int i, j; struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct ieee80211_conf *conf = &priv->hw->conf; + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; struct iwl_lq_sta *lq_sta = priv_sta; u16 mask_bit = 0; int count; @@ -2651,7 +2653,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr); sta_id = iwl_add_station(priv, sta->addr, false, - CMD_ASYNC, NULL); + CMD_ASYNC, ht_cap); } if ((sta_id != IWL_INVALID_STATION)) { lq_sta->lq.sta_id = sta_id; @@ -2672,19 +2674,19 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), * supp_rates[] does not; shift to convert format, force 9 MBits off. */ - lq_sta->active_siso_rate = sta->ht_cap.mcs.rx_mask[0] << 1; - lq_sta->active_siso_rate |= sta->ht_cap.mcs.rx_mask[0] & 0x1; + lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1; + lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1; lq_sta->active_siso_rate &= ~((u16)0x2); lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; /* Same here */ - lq_sta->active_mimo2_rate = sta->ht_cap.mcs.rx_mask[1] << 1; - lq_sta->active_mimo2_rate |= sta->ht_cap.mcs.rx_mask[1] & 0x1; + lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1; + lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1; lq_sta->active_mimo2_rate &= ~((u16)0x2); lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; - lq_sta->active_mimo3_rate = sta->ht_cap.mcs.rx_mask[2] << 1; - lq_sta->active_mimo3_rate |= sta->ht_cap.mcs.rx_mask[2] & 0x1; + lq_sta->active_mimo3_rate = ht_cap->mcs.rx_mask[2] << 1; + lq_sta->active_mimo3_rate |= ht_cap->mcs.rx_mask[2] & 0x1; lq_sta->active_mimo3_rate &= ~((u16)0x2); lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE; -- cgit v1.2.3-18-g5258 From 3b24716fc978db9c27c4a069e5201460479340a4 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 13 Aug 2009 13:30:53 -0700 Subject: iwlwifi: cleanup HT40 extension channels setup The patch cleans up the HT40 extension channels setup for EEPROM band 6 and 7 to make it more readable. Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 37 ++++++++++--------------------- 1 file changed, 12 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 78c4a324a3b..ded63320a46 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -484,14 +484,14 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, ? # x " " : "") /** - * iwl_set_ht40_chan_info - Copy ht40 channel info into driver's priv. + * iwl_mod_ht40_chan_info - Copy ht40 channel info into driver's priv. * * Does not set up a command, or touch hardware. */ -static int iwl_set_ht40_chan_info(struct iwl_priv *priv, +static int iwl_mod_ht40_chan_info(struct iwl_priv *priv, enum ieee80211_band band, u16 channel, const struct iwl_eeprom_channel *eeprom_ch, - u8 ht40_extension_channel) + u8 clear_ht40_extension_channel) { struct iwl_channel_info *ch_info; @@ -523,7 +523,7 @@ static int iwl_set_ht40_chan_info(struct iwl_priv *priv, ch_info->ht40_min_power = 0; ch_info->ht40_scan_power = eeprom_ch->max_power_avg; ch_info->ht40_flags = eeprom_ch->flags; - ch_info->ht40_extension_channel = ht40_extension_channel; + ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel; return 0; } @@ -592,8 +592,7 @@ int iwl_init_channel_map(struct iwl_priv *priv) /* First write that ht40 is not enabled, and then enable * one by one */ ch_info->ht40_extension_channel = - (IEEE80211_CHAN_NO_HT40PLUS | - IEEE80211_CHAN_NO_HT40MINUS); + IEEE80211_CHAN_NO_HT40; if (!(is_channel_valid(ch_info))) { IWL_DEBUG_INFO(priv, "Ch. %d Flags %x [%sGHz] - " @@ -652,7 +651,6 @@ int iwl_init_channel_map(struct iwl_priv *priv) /* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */ for (band = 6; band <= 7; band++) { enum ieee80211_band ieeeband; - u8 ht40_extension_chan; iwl_init_band_reference(priv, band, &eeprom_ch_count, &eeprom_ch_info, &eeprom_ch_index); @@ -663,28 +661,17 @@ int iwl_init_channel_map(struct iwl_priv *priv) /* Loop through each band adding each of the channels */ for (ch = 0; ch < eeprom_ch_count; ch++) { - - if ((band == 6) && - ((eeprom_ch_index[ch] == 5) || - (eeprom_ch_index[ch] == 6) || - (eeprom_ch_index[ch] == 7))) - /* both are allowed: above and below */ - ht40_extension_chan = 0; - else - ht40_extension_chan = - IEEE80211_CHAN_NO_HT40MINUS; - /* Set up driver's info for lower half */ - iwl_set_ht40_chan_info(priv, ieeeband, + iwl_mod_ht40_chan_info(priv, ieeeband, eeprom_ch_index[ch], - &(eeprom_ch_info[ch]), - ht40_extension_chan); + &eeprom_ch_info[ch], + IEEE80211_CHAN_NO_HT40PLUS); /* Set up driver's info for upper half */ - iwl_set_ht40_chan_info(priv, ieeeband, - (eeprom_ch_index[ch] + 4), - &(eeprom_ch_info[ch]), - IEEE80211_CHAN_NO_HT40PLUS); + iwl_mod_ht40_chan_info(priv, ieeeband, + eeprom_ch_index[ch] + 4, + &eeprom_ch_info[ch], + IEEE80211_CHAN_NO_HT40MINUS); } } -- cgit v1.2.3-18-g5258 From 415e49936b4b29b34c2fb561eeab867d41fc43a6 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 13 Aug 2009 13:30:54 -0700 Subject: iwlwifi: traverse linklist to find the valid OTP block For devices using OTP memory, EEPROM image can start from any one of the OTP blocks. If shadow RAM is disabled, we need to traverse link list to find the last valid block, then start the EEPROM image reading. If OTP is not full, the valid block is the block _before_ the last block on the link list; the last block on the link list is the empty block ready for next OTP refresh/update. If OTP is full, then the last block is the valid block to be used for configure the device. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 4 +- drivers/net/wireless/iwlwifi/iwl-6000.c | 20 +++- drivers/net/wireless/iwlwifi/iwl-core.h | 4 + drivers/net/wireless/iwlwifi/iwl-dev.h | 11 ++ drivers/net/wireless/iwlwifi/iwl-eeprom.c | 185 ++++++++++++++++++++++++------ drivers/net/wireless/iwlwifi/iwl-eeprom.h | 10 +- 6 files changed, 191 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 191718a0c54..9bb6a287eae 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -149,12 +149,14 @@ struct iwl_cfg iwl1000_bgn_cfg = { .ucode_api_min = IWL1000_UCODE_API_MIN, .sku = IWL_SKU_G|IWL_SKU_N, .ops = &iwl1000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, .need_pll_cfg = true, + .max_ll_items = OTP_MAX_LL_ITEMS_1000, + .shadow_ram_support = false, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index c3ec6c20cc9..0b731fd5ad1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -161,7 +161,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .ucode_api_min = IWL6000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, @@ -169,6 +169,8 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .valid_rx_ant = ANT_AB, .need_pll_cfg = false, .pa_type = IWL_PA_HYBRID, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, }; /* @@ -181,7 +183,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .ucode_api_min = IWL6000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, @@ -189,6 +191,8 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .valid_rx_ant = ANT_BC, .need_pll_cfg = false, .pa_type = IWL_PA_INTERNAL, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -198,7 +202,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, @@ -206,6 +210,8 @@ struct iwl_cfg iwl6050_2agn_cfg = { .valid_rx_ant = ANT_AB, .need_pll_cfg = false, .pa_type = IWL_PA_SYSTEM, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -215,7 +221,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .ucode_api_min = IWL6000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, @@ -223,6 +229,8 @@ struct iwl_cfg iwl6000_3agn_cfg = { .valid_rx_ant = ANT_ABC, .need_pll_cfg = false, .pa_type = IWL_PA_SYSTEM, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, }; struct iwl_cfg iwl6050_3agn_cfg = { @@ -232,7 +240,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, @@ -240,6 +248,8 @@ struct iwl_cfg iwl6050_3agn_cfg = { .valid_rx_ant = ANT_ABC, .need_pll_cfg = false, .pa_type = IWL_PA_SYSTEM, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 32750f4f1ce..509683487e0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -209,6 +209,8 @@ struct iwl_mod_params { * @ucode_api_max: Highest version of uCode API supported by driver. * @ucode_api_min: Lowest version of uCode API supported by driver. * @pa_type: used by 6000 series only to identify the type of Power Amplifier + * @max_ll_items: max number of OTP blocks + * @shadow_ram_support: shadow support for OTP memory * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -247,6 +249,8 @@ struct iwl_cfg { bool need_pll_cfg; bool use_isr_legacy; enum iwl_pa_type pa_type; + const u16 max_ll_items; + const bool shadow_ram_support; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index c34f9d73306..0b19a6f93c8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -887,6 +887,17 @@ enum iwl_nvm_type { NVM_DEVICE_TYPE_OTP, }; +/* + * Two types of OTP memory access modes + * IWL_OTP_ACCESS_ABSOLUTE - absolute address mode, + * based on physical memory addressing + * IWL_OTP_ACCESS_RELATIVE - relative address mode, + * based on logical memory addressing + */ +enum iwl_access_mode { + IWL_OTP_ACCESS_ABSOLUTE, + IWL_OTP_ACCESS_RELATIVE, +}; /** * enum iwl_pa_type - Power Amplifier type diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index ded63320a46..01b95e89009 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -152,6 +152,19 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv) } EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); +static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode) +{ + u32 otpgp; + + otpgp = iwl_read32(priv, CSR_OTP_GP_REG); + if (mode == IWL_OTP_ACCESS_ABSOLUTE) + iwl_clear_bit(priv, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_OTP_ACCESS_MODE); + else + iwl_set_bit(priv, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_OTP_ACCESS_MODE); +} + static int iwlcore_get_nvm_type(struct iwl_priv *priv) { u32 otpgp; @@ -252,6 +265,124 @@ static int iwl_init_otp_access(struct iwl_priv *priv) return ret; } +static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data) +{ + int ret = 0; + u32 r; + u32 otpgp; + + _iwl_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); + if (ret < 0) { + IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); + return ret; + } + r = _iwl_read_direct32(priv, CSR_EEPROM_REG); + /* check for ECC errors: */ + otpgp = iwl_read32(priv, CSR_OTP_GP_REG); + if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { + /* stop in this case */ + /* set the uncorrectable OTP ECC bit for acknowledgement */ + iwl_set_bit(priv, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); + IWL_ERR(priv, "Uncorrectable OTP ECC error, abort OTP read\n"); + return -EINVAL; + } + if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { + /* continue in this case */ + /* set the correctable OTP ECC bit for acknowledgement */ + iwl_set_bit(priv, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); + IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); + } + *eeprom_data = le16_to_cpu((__force __le16)(r >> 16)); + return 0; +} + +/* + * iwl_is_otp_empty: check for empty OTP + */ +static bool iwl_is_otp_empty(struct iwl_priv *priv) +{ + u16 next_link_addr = 0, link_value; + bool is_empty = false; + + /* locate the beginning of OTP link list */ + if (!iwl_read_otp_word(priv, next_link_addr, &link_value)) { + if (!link_value) { + IWL_ERR(priv, "OTP is empty\n"); + is_empty = true; + } + } else { + IWL_ERR(priv, "Unable to read first block of OTP list.\n"); + is_empty = true; + } + + return is_empty; +} + + +/* + * iwl_find_otp_image: find EEPROM image in OTP + * finding the OTP block that contains the EEPROM image. + * the last valid block on the link list (the block _before_ the last block) + * is the block we should read and used to configure the device. + * If all the available OTP blocks are full, the last block will be the block + * we should read and used to configure the device. + * only perform this operation if shadow RAM is disabled + */ +static int iwl_find_otp_image(struct iwl_priv *priv, + u16 *validblockaddr) +{ + u16 next_link_addr = 0, link_value = 0, valid_addr; + int ret = 0; + int usedblocks = 0; + + /* set addressing mode to absolute to traverse the link list */ + iwl_set_otp_access(priv, IWL_OTP_ACCESS_ABSOLUTE); + + /* checking for empty OTP or error */ + if (iwl_is_otp_empty(priv)) + return -EINVAL; + + /* + * start traverse link list + * until reach the max number of OTP blocks + * different devices have different number of OTP blocks + */ + do { + /* save current valid block address + * check for more block on the link list + */ + valid_addr = next_link_addr; + next_link_addr = link_value; + IWL_DEBUG_INFO(priv, "OTP blocks %d addr 0x%x\n", + usedblocks, next_link_addr); + if (iwl_read_otp_word(priv, next_link_addr, &link_value)) + return -EINVAL; + if (!link_value) { + /* + * reach the end of link list, + * set address point to the starting address + * of the image + */ + goto done; + } + /* more in the link list, continue */ + usedblocks++; + } while (usedblocks < priv->cfg->max_ll_items); + /* OTP full, use last block */ + IWL_DEBUG_INFO(priv, "OTP is full, use last block\n"); +done: + *validblockaddr = valid_addr; + /* skip first 2 bytes (link list pointer) */ + *validblockaddr += 2; + return ret; +} + /** * iwl_eeprom_init - read EEPROM contents * @@ -266,15 +397,14 @@ int iwl_eeprom_init(struct iwl_priv *priv) int sz; int ret; u16 addr; - u32 otpgp; + u16 validblockaddr = 0; + u16 cache_addr = 0; priv->nvm_device_type = iwlcore_get_nvm_type(priv); if (priv->nvm_device_type == -ENOENT) return -ENOENT; /* allocate eeprom */ - if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) - priv->cfg->eeprom_size = - OTP_BLOCK_SIZE * OTP_LOWER_BLOCKS_TOTAL; + IWL_DEBUG_INFO(priv, "NVM size = %d\n", priv->cfg->eeprom_size); sz = priv->cfg->eeprom_size; priv->eeprom = kzalloc(sz, GFP_KERNEL); if (!priv->eeprom) { @@ -302,46 +432,31 @@ int iwl_eeprom_init(struct iwl_priv *priv) if (ret) { IWL_ERR(priv, "Failed to initialize OTP access.\n"); ret = -ENOENT; - goto err; + goto done; } _iwl_write32(priv, CSR_EEPROM_GP, iwl_read32(priv, CSR_EEPROM_GP) & ~CSR_EEPROM_GP_IF_OWNER_MSK); - /* clear */ - _iwl_write32(priv, CSR_OTP_GP_REG, - iwl_read32(priv, CSR_OTP_GP_REG) | + + iwl_set_bit(priv, CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); - - for (addr = 0; addr < sz; addr += sizeof(u16)) { - u32 r; - - _iwl_write32(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - - ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_READ_VALID_MSK, - IWL_EEPROM_ACCESS_TIMEOUT); - if (ret < 0) { - IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); + /* traversing the linked list if no shadow ram supported */ + if (!priv->cfg->shadow_ram_support) { + if (iwl_find_otp_image(priv, &validblockaddr)) { + ret = -ENOENT; goto done; } - r = _iwl_read_direct32(priv, CSR_EEPROM_REG); - /* check for ECC errors: */ - otpgp = iwl_read32(priv, CSR_OTP_GP_REG); - if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { - /* stop in this case */ - IWL_ERR(priv, "Uncorrectable OTP ECC error, Abort OTP read\n"); + } + for (addr = validblockaddr; addr < validblockaddr + sz; + addr += sizeof(u16)) { + u16 eeprom_data; + + ret = iwl_read_otp_word(priv, addr, &eeprom_data); + if (ret) goto done; - } - if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { - /* continue in this case */ - _iwl_write32(priv, CSR_OTP_GP_REG, - iwl_read32(priv, CSR_OTP_GP_REG) | - CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); - IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); - } - e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); + e[cache_addr / 2] = eeprom_data; + cache_addr += sizeof(u16); } } else { /* eeprom is an array of 16bit values */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 05d4fc4451d..ca7920a8f52 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -180,8 +180,14 @@ struct iwl_eeprom_channel { #define EEPROM_5050_EEPROM_VERSION (0x21E) /* OTP */ -#define OTP_LOWER_BLOCKS_TOTAL (3) -#define OTP_BLOCK_SIZE (0x400) +/* lower blocks contain EEPROM image and calibration data */ +#define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */ +/* high blocks contain PAPD data */ +#define OTP_HIGH_IMAGE_SIZE_6x00 (6 * 512 * sizeof(u16)) /* 6 KB */ +#define OTP_HIGH_IMAGE_SIZE_1000 (0x200 * sizeof(u16)) /* 1024 bytes */ +#define OTP_MAX_LL_ITEMS_1000 (3) /* OTP blocks for 1000 */ +#define OTP_MAX_LL_ITEMS_6x00 (4) /* OTP blocks for 6x00 */ +#define OTP_MAX_LL_ITEMS_6x50 (7) /* OTP blocks for 6x50 */ /* 2.4 GHz */ extern const u8 iwl_eeprom_band_1[14]; -- cgit v1.2.3-18-g5258 From 367ca28da433ed9639468be851e1f33468e3485e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 13 Aug 2009 13:30:55 -0700 Subject: iwlwifi: remove unused members of iwl_ht_info Some members of iwl_ht_info are unused, and one of them is write-only, so we can remove these three: max_amsdu_size, ampdu_factor and mpdu_density. Signed-off-by: Johannes Berg Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 2 -- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 --- 2 files changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 479b7e165b0..08345b97cb4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2397,8 +2397,6 @@ static void iwl_ht_conf(struct iwl_priv *priv, iwl_conf->sgf |= HT_SHORT_GI_40MHZ; iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); - iwl_conf->max_amsdu_size = - !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); iwl_conf->supported_chan_width = !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0b19a6f93c8..db745343d36 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -509,9 +509,6 @@ struct iwl_ht_info { u8 sm_ps; u8 is_green_field; u8 sgf; /* HT_SHORT_GI_* short guard interval */ - u8 max_amsdu_size; - u8 ampdu_factor; - u8 mpdu_density; struct ieee80211_mcs_info mcs; /* BSS related data */ u8 extension_chan_offset; -- cgit v1.2.3-18-g5258 From 9f30e04e041cf9943940f71fd76094dd5a237018 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Thu, 13 Aug 2009 13:30:56 -0700 Subject: iwlwifi: refactor packet reception code This patch fixes a number of issues in iwl_rx_reply_rx and iwl_pass_packet_to_mac80211. These issues stem from the complexities of managing two different types of packet commands for different hardware. - Unify code handling rx_phy_res in SKB or cached to eliminate redundancy and remove potential NULL pointer accesses - Replace magic number with proper constant - Optimize functions by moving early exit conditions before computation - Comment code and improve some variable names - Remove redundant computation in iwl_pass_packet_to_mac80211 by passing in the correct, already-computed arguments. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 1 + drivers/net/wireless/iwlwifi/iwl-rx.c | 204 +++++++++++----------------- 2 files changed, 78 insertions(+), 127 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 68d7719071f..9398ad7e42b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1156,6 +1156,7 @@ struct iwl_wep_cmd { #define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK cpu_to_le16(1 << 2) #define RX_RES_PHY_FLAGS_NARROW_BAND_MSK cpu_to_le16(1 << 3) #define RX_RES_PHY_FLAGS_ANTENNA_MSK cpu_to_le16(0xf0) +#define RX_RES_PHY_FLAGS_ANTENNA_POS 4 #define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) #define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 43b2fce4cbf..092d3276175 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -853,61 +853,12 @@ static u32 iwl_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) } static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, - int include_phy, - struct iwl_rx_mem_buffer *rxb, - struct ieee80211_rx_status *stats) + struct ieee80211_hdr *hdr, + u16 len, + u32 ampdu_status, + struct iwl_rx_mem_buffer *rxb, + struct ieee80211_rx_status *stats) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl_rx_phy_res *rx_start = (include_phy) ? - (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) : NULL; - struct ieee80211_hdr *hdr; - u16 len; - __le32 *rx_end; - unsigned int skblen; - u32 ampdu_status; - u32 ampdu_status_legacy; - - if (!include_phy && priv->last_phy_res[0]) - rx_start = (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; - - if (!rx_start) { - IWL_ERR(priv, "MPDU frame without a PHY data\n"); - return; - } - if (include_phy) { - hdr = (struct ieee80211_hdr *)((u8 *) &rx_start[1] + - rx_start->cfg_phy_cnt); - - len = le16_to_cpu(rx_start->byte_count); - - rx_end = (__le32 *)((u8 *) &pkt->u.raw[0] + - sizeof(struct iwl_rx_phy_res) + - rx_start->cfg_phy_cnt + len); - - } else { - struct iwl4965_rx_mpdu_res_start *amsdu = - (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; - - hdr = (struct ieee80211_hdr *)(pkt->u.raw + - sizeof(struct iwl4965_rx_mpdu_res_start)); - len = le16_to_cpu(amsdu->byte_count); - rx_start->byte_count = amsdu->byte_count; - rx_end = (__le32 *) (((u8 *) hdr) + len); - } - - ampdu_status = le32_to_cpu(*rx_end); - skblen = ((u8 *) rx_end - (u8 *) &pkt->u.raw[0]) + sizeof(u32); - - if (!include_phy) { - /* New status scheme, need to translate */ - ampdu_status_legacy = ampdu_status; - ampdu_status = iwl_translate_rx_status(priv, ampdu_status); - } - - /* start from MAC */ - skb_reserve(rxb->skb, (void *)hdr - (void *)pkt); - skb_put(rxb->skb, len); /* end where data ends */ - /* We only process data packets if the interface is open */ if (unlikely(!priv->is_open)) { IWL_DEBUG_DROP_LIMIT(priv, @@ -915,13 +866,15 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, return; } - hdr = (struct ieee80211_hdr *)rxb->skb->data; - - /* in case of HW accelerated crypto and bad decryption, drop */ + /* In case of HW accelerated crypto and bad decryption, drop */ if (!priv->cfg->mod_params->sw_crypto && iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; + /* Resize SKB from mac header to end of packet */ + skb_reserve(rxb->skb, (void *)hdr - (void *)rxb->skb->data); + skb_put(rxb->skb, len); + iwl_update_stats(priv, false, hdr->frame_control, len); memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); ieee80211_rx_irqsafe(priv->hw, rxb->skb); @@ -955,25 +908,66 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, struct ieee80211_hdr *header; struct ieee80211_rx_status rx_status; struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - /* Use phy data (Rx signal strength, etc.) contained within - * this rx packet for legacy frames, - * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ - int include_phy = (pkt->hdr.cmd == REPLY_RX); - struct iwl_rx_phy_res *rx_start = (include_phy) ? - (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) : - (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; - __le32 *rx_end; - unsigned int len = 0; + struct iwl_rx_phy_res *phy_res; + __le32 rx_pkt_status; + struct iwl4965_rx_mpdu_res_start *amsdu; + u32 len; + u32 ampdu_status; u16 fc; - u8 network_packet; - rx_status.mactime = le64_to_cpu(rx_start->timestamp); + /** + * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently. + * REPLY_RX: physical layer info is in this buffer + * REPLY_RX_MPDU_CMD: physical layer info was sent in separate + * command and cached in priv->last_phy_res + * + * Here we set up local variables depending on which command is + * received. + */ + if (pkt->hdr.cmd == REPLY_RX) { + phy_res = (struct iwl_rx_phy_res *)pkt->u.raw; + header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*phy_res) + + phy_res->cfg_phy_cnt); + + len = le16_to_cpu(phy_res->byte_count); + rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*phy_res) + + phy_res->cfg_phy_cnt + len); + ampdu_status = le32_to_cpu(rx_pkt_status); + } else { + if (!priv->last_phy_res[0]) { + IWL_ERR(priv, "MPDU frame without cached PHY data\n"); + return; + } + phy_res = (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; + amsdu = (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; + header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu)); + len = le16_to_cpu(amsdu->byte_count); + rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len); + ampdu_status = iwl_translate_rx_status(priv, + le32_to_cpu(rx_pkt_status)); + } + + if ((unlikely(phy_res->cfg_phy_cnt > 20))) { + IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n", + phy_res->cfg_phy_cnt); + return; + } + + if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) || + !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { + IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", + le32_to_cpu(rx_pkt_status)); + return; + } + + /* rx_status carries information about the packet to mac80211 */ + rx_status.mactime = le64_to_cpu(phy_res->timestamp); rx_status.freq = - ieee80211_channel_to_frequency(le16_to_cpu(rx_start->channel)); - rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? + ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel)); + rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; rx_status.rate_idx = - iwl_hwrate_to_plcp_idx(le32_to_cpu(rx_start->rate_n_flags)); + iwl_hwrate_to_plcp_idx(le32_to_cpu(phy_res->rate_n_flags)); if (rx_status.band == IEEE80211_BAND_5GHZ) rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; @@ -983,54 +977,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, * this W/A doesn't propagate it to the mac80211 */ /*rx_status.flag |= RX_FLAG_TSFT;*/ - if ((unlikely(rx_start->cfg_phy_cnt > 20))) { - IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n", - rx_start->cfg_phy_cnt); - return; - } - - if (!include_phy) { - if (priv->last_phy_res[0]) - rx_start = (struct iwl_rx_phy_res *) - &priv->last_phy_res[1]; - else - rx_start = NULL; - } - - if (!rx_start) { - IWL_ERR(priv, "MPDU frame without a PHY data\n"); - return; - } - - if (include_phy) { - header = (struct ieee80211_hdr *)((u8 *) &rx_start[1] - + rx_start->cfg_phy_cnt); - - len = le16_to_cpu(rx_start->byte_count); - rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt + - sizeof(struct iwl_rx_phy_res) + len); - } else { - struct iwl4965_rx_mpdu_res_start *amsdu = - (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; - - header = (void *)(pkt->u.raw + - sizeof(struct iwl4965_rx_mpdu_res_start)); - len = le16_to_cpu(amsdu->byte_count); - rx_end = (__le32 *) (pkt->u.raw + - sizeof(struct iwl4965_rx_mpdu_res_start) + len); - } - - if (!(*rx_end & RX_RES_STATUS_NO_CRC32_ERROR) || - !(*rx_end & RX_RES_STATUS_NO_RXE_OVERFLOW)) { - IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", - le32_to_cpu(*rx_end)); - return; - } - - priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); + priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp); /* Find max signal strength (dBm) among 3 antenna/receiver chains */ - rx_status.signal = iwl_calc_rssi(priv, rx_start); + rx_status.signal = iwl_calc_rssi(priv, phy_res); /* Meaningful noise values are available only from beacon statistics, * which are gathered only when associated, and indicate noise @@ -1050,10 +1000,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, if (!iwl_is_associated(priv)) priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; - /* Set "1" to report good data frames in groups of 100 */ #ifdef CONFIG_IWLWIFI_DEBUG + /* Set "1" to report good data frames in groups of 100 */ if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX)) - iwl_dbg_report_frame(priv, rx_start, len, header, 1); + iwl_dbg_report_frame(priv, phy_res, len, header, 1); #endif iwl_dbg_log_rx_data_frame(priv, len, header); IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n", @@ -1073,18 +1023,18 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, * new 802.11n radiotap field "RX chains" that is defined * as a bitmask. */ - rx_status.antenna = le16_to_cpu(rx_start->phy_flags & - RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; + rx_status.antenna = + le16_to_cpu(phy_res->phy_flags & RX_RES_PHY_FLAGS_ANTENNA_MSK) + >> RX_RES_PHY_FLAGS_ANTENNA_POS; /* set the preamble flag if appropriate */ - if (rx_start->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) + if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) rx_status.flag |= RX_FLAG_SHORTPRE; - network_packet = iwl_is_network_packet(priv, header); - if (network_packet) { + if (iwl_is_network_packet(priv, header)) { priv->last_rx_rssi = rx_status.signal; priv->last_beacon_time = priv->ucode_beacon_time; - priv->last_tsf = le64_to_cpu(rx_start->timestamp); + priv->last_tsf = le64_to_cpu(phy_res->timestamp); } fc = le16_to_cpu(header->frame_control); @@ -1096,8 +1046,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, header->addr2); /* fall through */ default: - iwl_pass_packet_to_mac80211(priv, include_phy, rxb, - &rx_status); + iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status, + rxb, &rx_status); break; } -- cgit v1.2.3-18-g5258 From 28bd723bbaddba4e145d25117649bb6da5fafad7 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Thu, 13 Aug 2009 13:30:57 -0700 Subject: iwlwifi: configure HT40 channels in iwl_mac_config As indicated by note in iwl_ht_conf, some HT parameters are set on association (e.g., channel width) and some vary over time (HT protection mode) and per station (e.g., short GI support). The global parameters should be set in iwl_mac_config and the local/varying parameters in iwl_ht_conf. This patch moves the channel width configuration from iwl_ht_conf to iwl_mac_config, and defers further cleanup of the local/global conflation for a later patch. This fixes a bug in using HT40 channels in some modes. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 46 ++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 08345b97cb4..104fd95dfad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2398,25 +2398,6 @@ static void iwl_ht_conf(struct iwl_priv *priv, iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); - iwl_conf->supported_chan_width = - !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); - - /* - * XXX: The HT configuration needs to be moved into iwl_mac_config() - * to be done there correctly. - */ - - iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; - if (conf_is_ht40_minus(&priv->hw->conf)) - iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; - else if (conf_is_ht40_plus(&priv->hw->conf)) - iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - - /* If no above or below channel supplied disable HT40 channel */ - if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && - iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) - iwl_conf->supported_chan_width = 0; - iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); @@ -2733,6 +2714,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) struct iwl_priv *priv = hw->priv; const struct iwl_channel_info *ch_info; struct ieee80211_conf *conf = &hw->conf; + struct iwl_ht_info *ht_conf = &priv->current_ht_config; unsigned long flags = 0; int ret = 0; u16 ch; @@ -2774,10 +2756,32 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) goto set_ch_out; } - priv->current_ht_config.is_ht = conf_is_ht(conf); - spin_lock_irqsave(&priv->lock, flags); + /* Configure HT40 channels */ + ht_conf->is_ht = conf_is_ht(conf); + if (ht_conf->is_ht) { + if (conf_is_ht40_minus(conf)) { + ht_conf->extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_BELOW; + ht_conf->supported_chan_width = + IWL_CHANNEL_WIDTH_40MHZ; + } else if (conf_is_ht40_plus(conf)) { + ht_conf->extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + ht_conf->supported_chan_width = + IWL_CHANNEL_WIDTH_40MHZ; + } else { + ht_conf->extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_NONE; + ht_conf->supported_chan_width = + IWL_CHANNEL_WIDTH_20MHZ; + } + } else + ht_conf->supported_chan_width = IWL_CHANNEL_WIDTH_20MHZ; + /* Default to no protection. Protection mode will later be set + * from BSS config in iwl_ht_conf */ + ht_conf->ht_protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE; /* if we are switching from ht to 2.4 clear flags * from any ht related info since 2.4 does not -- cgit v1.2.3-18-g5258 From 28e6f48953f44f7eb615383efe6e7f17624a11bb Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Thu, 13 Aug 2009 13:30:58 -0700 Subject: iwlwifi: check short GI support per-station rather than globally Short guard interval support is a local per-station parameter not a global per-NIC parameter. (mac80211 will correctly remove SGI support from station capabilities if the BSS does not permit it). This patch removes the short GI support bitfield from the global iwl_ht_info struct and properly uses per-station HT capabilities during rate selection. Signed-off-by: Daniel C Halperin Acked-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 69 +++++++------------------------ drivers/net/wireless/iwlwifi/iwl-core.c | 5 --- drivers/net/wireless/iwlwifi/iwl-dev.h | 4 -- 3 files changed, 15 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 551c4ba3f17..3b1bbc394a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1225,18 +1225,6 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, else tbl->is_ht40 = 0; - /* FIXME: - don't toggle SGI here - if (tbl->is_ht40) { - if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - */ - rs_set_expected_tpt_table(lq_sta, tbl); rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index); @@ -1291,18 +1279,6 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, else tbl->is_ht40 = 0; - /* FIXME: - don't toggle SGI here - if (tbl->is_ht40) { - if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - */ - rs_set_expected_tpt_table(lq_sta, tbl); rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index); @@ -1350,18 +1326,6 @@ static int rs_switch_to_siso(struct iwl_priv *priv, else tbl->is_ht40 = 0; - /* FIXME: - don't toggle SGI here - if (tbl->is_ht40) { - if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - */ - if (is_green) tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/ @@ -1530,6 +1494,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, struct iwl_scale_tbl_info *search_tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); struct iwl_rate_scale_data *window = &(tbl->win[index]); + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; @@ -1589,13 +1554,11 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, goto out; break; case IWL_SISO_SWITCH_GI: - if (!tbl->is_ht40 && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_20MHZ)) + if (!tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_20)) break; - if (tbl->is_ht40 && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_40MHZ)) + if (tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_40)) break; IWL_DEBUG_RATE(priv, "LQ: SISO toggle SGI/NGI\n"); @@ -1669,6 +1632,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, struct iwl_scale_tbl_info *search_tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); struct iwl_rate_scale_data *window = &(tbl->win[index]); + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; @@ -1729,13 +1693,11 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, break; case IWL_MIMO2_SWITCH_GI: - if (!tbl->is_ht40 && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_20MHZ)) + if (!tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_20)) break; - if (tbl->is_ht40 && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_40MHZ)) + if (tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_40)) break; IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle SGI/NGI\n"); @@ -1811,6 +1773,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, struct iwl_scale_tbl_info *search_tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); struct iwl_rate_scale_data *window = &(tbl->win[index]); + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; @@ -1893,13 +1856,11 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, break; case IWL_MIMO3_SWITCH_GI: - if (!tbl->is_ht40 && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_20MHZ)) + if (!tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_20)) break; - if (tbl->is_ht40 && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_40MHZ)) + if (tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_40)) break; IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle SGI/NGI\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 104fd95dfad..b845cf30e1b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2391,11 +2391,6 @@ static void iwl_ht_conf(struct iwl_priv *priv, } ht_conf = &sta->ht_cap; - if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) - iwl_conf->sgf |= HT_SHORT_GI_20MHZ; - if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) - iwl_conf->sgf |= HT_SHORT_GI_40MHZ; - iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index db745343d36..e6a1c6ff44d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -508,7 +508,6 @@ struct iwl_ht_info { u8 supported_chan_width; u8 sm_ps; u8 is_green_field; - u8 sgf; /* HT_SHORT_GI_* short guard interval */ struct ieee80211_mcs_info mcs; /* BSS related data */ u8 extension_chan_offset; @@ -728,9 +727,6 @@ struct iwl_dma_ptr { size_t size; }; -#define HT_SHORT_GI_20MHZ (1 << 0) -#define HT_SHORT_GI_40MHZ (1 << 1) - #define IWL_CHANNEL_WIDTH_20MHZ 0 #define IWL_CHANNEL_WIDTH_40MHZ 1 -- cgit v1.2.3-18-g5258 From b261793da587160d12ce6d63db60493342ddce20 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Thu, 13 Aug 2009 13:30:59 -0700 Subject: iwlwifi: use station HT capabilities and BSS operating mode for Green-field Green-field mode should be configured in the HT station table. This patch uses both the per-station GF support flag as well as the current BSS HT operation mode (non-GF stations present flag). Added the "ht_greenfield_support" field to struct iwl_cfg to replace the device-specific check in rs_use_green(). That check has been moved to iwlcore_init_ht_hw_capab(). Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 1 + drivers/net/wireless/iwlwifi/iwl-3945.c | 6 ++++-- drivers/net/wireless/iwlwifi/iwl-4965.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-5000.c | 6 ++++++ drivers/net/wireless/iwlwifi/iwl-6000.c | 5 +++++ drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 26 +++++++++++--------------- drivers/net/wireless/iwlwifi/iwl-core.c | 5 ++--- drivers/net/wireless/iwlwifi/iwl-core.h | 1 + drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - 9 files changed, 32 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 9bb6a287eae..a95caa01414 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -158,5 +158,6 @@ struct iwl_cfg iwl1000_bgn_cfg = { .need_pll_cfg = true, .max_ll_items = OTP_MAX_LL_ITEMS_1000, .shadow_ram_support = false, + .ht_greenfield_support = true, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index ba5ef832d77..b5a4d2ecdd2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2889,7 +2889,8 @@ static struct iwl_cfg iwl3945_bg_cfg = { .eeprom_ver = EEPROM_3945_EEPROM_VERSION, .ops = &iwl3945_ops, .mod_params = &iwl3945_mod_params, - .use_isr_legacy = true + .use_isr_legacy = true, + .ht_greenfield_support = false, }; static struct iwl_cfg iwl3945_abg_cfg = { @@ -2902,7 +2903,8 @@ static struct iwl_cfg iwl3945_abg_cfg = { .eeprom_ver = EEPROM_3945_EEPROM_VERSION, .ops = &iwl3945_ops, .mod_params = &iwl3945_mod_params, - .use_isr_legacy = true + .use_isr_legacy = true, + .ht_greenfield_support = false, }; struct pci_device_id iwl3945_hw_card_ids[] = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index e427a8937ed..6a13bfbc9d9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2344,7 +2344,8 @@ struct iwl_cfg iwl4965_agn_cfg = { .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION, .ops = &iwl4965_ops, .mod_params = &iwl4965_mod_params, - .use_isr_legacy = true + .use_isr_legacy = true, + .ht_greenfield_support = false, }; /* Module firmware */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 755c184b3ec..e1e862eb5ac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1652,6 +1652,7 @@ struct iwl_cfg iwl5300_agn_cfg = { .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, .need_pll_cfg = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl5100_bg_cfg = { @@ -1668,6 +1669,7 @@ struct iwl_cfg iwl5100_bg_cfg = { .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, .need_pll_cfg = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl5100_abg_cfg = { @@ -1684,6 +1686,7 @@ struct iwl_cfg iwl5100_abg_cfg = { .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, .need_pll_cfg = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl5100_agn_cfg = { @@ -1700,6 +1703,7 @@ struct iwl_cfg iwl5100_agn_cfg = { .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, .need_pll_cfg = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl5350_agn_cfg = { @@ -1716,6 +1720,7 @@ struct iwl_cfg iwl5350_agn_cfg = { .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, .need_pll_cfg = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl5150_agn_cfg = { @@ -1732,6 +1737,7 @@ struct iwl_cfg iwl5150_agn_cfg = { .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, .need_pll_cfg = true, + .ht_greenfield_support = true, }; MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 0b731fd5ad1..383177db7de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -171,6 +171,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .pa_type = IWL_PA_HYBRID, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, + .ht_greenfield_support = true, }; /* @@ -193,6 +194,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .pa_type = IWL_PA_INTERNAL, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -212,6 +214,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -231,6 +234,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl6050_3agn_cfg = { @@ -250,6 +254,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, + .ht_greenfield_support = true, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 3b1bbc394a4..fee110de5c6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -657,19 +657,15 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, return 1; } -/* in 4965 we don't use greenfield at all */ -static inline u8 rs_use_green(struct iwl_priv *priv, - struct ieee80211_conf *conf) +/** + * Green-field mode is valid if the station supports it and + * there are no non-GF stations present in the BSS. + */ +static inline u8 rs_use_green(struct ieee80211_sta *sta, + struct iwl_ht_info *ht_conf) { - u8 is_green; - - if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) - is_green = 0; - else - is_green = (conf_is_ht(conf) && - priv->current_ht_config.is_green_field && - !priv->current_ht_config.non_GF_STA_present); - return is_green; + return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && + !(ht_conf->non_GF_STA_present); } /** @@ -2072,7 +2068,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, if (is_legacy(tbl->lq_type)) lq_sta->is_green = 0; else - lq_sta->is_green = rs_use_green(priv, conf); + lq_sta->is_green = rs_use_green(sta, &priv->current_ht_config); is_green = lq_sta->is_green; /* current tx rate */ @@ -2430,7 +2426,7 @@ static void rs_initialize_lq(struct iwl_priv *priv, int rate_idx; int i; u32 rate; - u8 use_green = rs_use_green(priv, conf); + u8 use_green = rs_use_green(sta, &priv->current_ht_config); u8 active_tbl = 0; u8 valid_tx_ant; @@ -2627,7 +2623,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->is_dup = 0; lq_sta->max_rate_idx = -1; lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX; - lq_sta->is_green = rs_use_green(priv, conf); + lq_sta->is_green = rs_use_green(sta, &priv->current_ht_config); lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000); lq_sta->active_rate_basic = priv->active_rate_basic; lq_sta->band = priv->band; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index b845cf30e1b..62aa87b4358 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -394,7 +394,8 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, ht_info->ht_supported = true; - ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; + if (priv->cfg->ht_greenfield_support) + ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; ht_info->cap |= IEEE80211_HT_CAP_SGI_20; ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & (WLAN_HT_CAP_SM_PS_DISABLED << 2)); @@ -2391,8 +2392,6 @@ static void iwl_ht_conf(struct iwl_priv *priv, } ht_conf = &sta->ht_cap; - iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); - iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 509683487e0..4ca025a34da 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -251,6 +251,7 @@ struct iwl_cfg { enum iwl_pa_type pa_type; const u16 max_ll_items; const bool shadow_ram_support; + const bool ht_greenfield_support; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index e6a1c6ff44d..0178734499f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -507,7 +507,6 @@ struct iwl_ht_info { u8 is_ht; u8 supported_chan_width; u8 sm_ps; - u8 is_green_field; struct ieee80211_mcs_info mcs; /* BSS related data */ u8 extension_chan_offset; -- cgit v1.2.3-18-g5258 From 15993e08ac027b64b6f3400d32754966b4cac7b0 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 13 Aug 2009 13:31:00 -0700 Subject: iwlwifi: add thermal throttling support to 5150 Adding legacy thermal throttling management support to 5150 NIC Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index e1e862eb5ac..720d234c973 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1411,6 +1411,7 @@ static void iwl5150_temperature(struct iwl_priv *priv) vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset; /* now vt hold the temperature in Kelvin */ priv->temperature = KELVIN_TO_CELSIUS(vt); + iwl_tt_handler(priv); } /* Calc max signal level (dBm) among 3 possible receivers */ -- cgit v1.2.3-18-g5258 From 396887a2b2ad1ef5e5526fec34dec582baf39b81 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Thu, 13 Aug 2009 13:31:01 -0700 Subject: iwlwifi: fix erroneous use of iwl_rx_packet.len as a length The field called 'len' in struct iwl_rx_packet is in fact not just a length field but also includes some flags from the flow handler. In several places throughout the driver, this causes incorrect values to be interpreted as lengths when the field is improperly masked. In most situations the improper use is for debugging output, and simply results in an erroneous message, such as: [551933.070224] ieee80211 phy0: I iwl_rx_statistics Statistics notification received (480 vs -1367342620). which should read '(480 vs 484)'. In at least one case this could case bad things to happen: void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " "notification for %s:\n", le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len) ); } EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif); Given the rampant misuse of this field without proper masking throughout the driver (every use but one), this patch renames the field from 'len' to 'len_n_flags' to reduce confusion. It also adds the proper masking when this field is used as a length value. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 5 +++-- drivers/net/wireless/iwlwifi/iwl-5000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-commands.h | 2 +- drivers/net/wireless/iwlwifi/iwl-core.c | 7 ++++--- drivers/net/wireless/iwlwifi/iwl-rx.c | 3 ++- 5 files changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index b5a4d2ecdd2..e9a685d8e3a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -349,12 +349,13 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv, * *****************************************************************************/ -void iwl3945_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +void iwl3945_hw_rx_statistics(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (void *)rxb->skb->data; IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", (int)sizeof(struct iwl3945_notif_statistics), - le32_to_cpu(pkt->len)); + le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); memcpy(&priv->statistics_39, pkt->u.raw, sizeof(priv->statistics_39)); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 720d234c973..1d539e3b8db 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -494,7 +494,7 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv, { struct iwl_rx_packet *pkt = (void *)rxb->skb->data; struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw; - int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK; + int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; int index; /* reduce the size of the length field itself */ diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 9398ad7e42b..f4303843ff9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -3482,7 +3482,7 @@ struct iwl_wimax_coex_cmd { *****************************************************************************/ struct iwl_rx_packet { - __le32 len; + __le32 len_n_flags; struct iwl_cmd_header hdr; union { struct iwl3945_rx_frame rx_frame; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 62aa87b4358..f4c2431017e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2294,10 +2294,11 @@ void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " - "notification for %s:\n", - le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); - iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); + "notification for %s:\n", len, + get_cmd_string(pkt->hdr.cmd)); + iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, len); } EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif); diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 092d3276175..353d9a2ddbc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -539,7 +539,8 @@ void iwl_rx_statistics(struct iwl_priv *priv, struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", - (int)sizeof(priv->statistics), pkt->len); + (int)sizeof(priv->statistics), + le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); change = ((priv->statistics.general.temperature != pkt->u.stats.general.temperature) || -- cgit v1.2.3-18-g5258 From b23da49e6db341f4721476394dd8b95e0be2d179 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 13 Aug 2009 13:31:02 -0700 Subject: iwlwifi: disable PS by default Unfortunately, PS currently affects RX performance significantly enough to warrant disabling it by default, but give the user the choice to enable it again with iwconfig. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index f4c2431017e..c0efa6623c0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1580,6 +1580,12 @@ int iwl_setup_mac(struct iwl_priv *priv) /* Firmware does not support this */ hw->wiphy->disable_beacon_hints = true; + /* + * For now, disable PS by default because it affects + * RX performance significantly. + */ + hw->wiphy->ps_default = false; + hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; /* we create the 802.11 header and a zero-length SSID element */ hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2; -- cgit v1.2.3-18-g5258 From 6f632d57f35303118685b88c139f3da73df077e2 Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Thu, 13 Aug 2009 17:34:40 -0700 Subject: libertas: don't use dynamic-sized array sparse complains about a bad constant expression due to the use of a dynamic-sized array in get_common_rates(). Allocate and free the array instead. Signed-off-by: Andrey Yurovsky Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 385b50f4b10..81f86ef2699 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -45,9 +45,14 @@ static int get_common_rates(struct lbs_private *priv, u8 *card_rates = lbs_bg_rates; size_t num_card_rates = sizeof(lbs_bg_rates); int ret = 0, i, j; - u8 tmp[30]; + u8 *tmp; size_t tmp_size = 0; + tmp = kzalloc((ARRAY_SIZE(lbs_bg_rates) - 1) * (*rates_size - 1), + GFP_KERNEL); + if (!tmp) + return -1; + /* For each rate in card_rates that exists in rate1, copy to tmp */ for (i = 0; card_rates[i] && (i < num_card_rates); i++) { for (j = 0; rates[j] && (j < *rates_size); j++) { @@ -77,6 +82,7 @@ done: memset(rates, 0, *rates_size); *rates_size = min_t(int, tmp_size, *rates_size); memcpy(rates, tmp, *rates_size); + kfree(tmp); return ret; } -- cgit v1.2.3-18-g5258 From 588f8377c5470fab611c14ead768f7f9af87da94 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Thu, 13 Aug 2009 22:46:30 +0200 Subject: b43: LP-PHY: Implement channel switching for rev2+/B2063 radio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rev.2+/B2063 will now hopefully show some signs of life, though it won't work at full performance, as calibration is still missing. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 424 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 402 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 996b7eccfaf..86da8281d92 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -29,6 +29,25 @@ #include "tables_lpphy.h" +static inline u16 channel2freq_lp(u8 channel) +{ + if (channel < 14) + return (2407 + 5 * channel); + else if (channel == 14) + return 2484; + else if (channel < 184) + return (5000 + 5 * channel); + else + return (4000 + 5 * channel); +} + +static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev) +{ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + return 1; + return 36; +} + static int b43_lpphy_op_allocate(struct b43_wldev *dev) { struct b43_phy_lp *lpphy; @@ -142,10 +161,9 @@ static void lpphy_read_band_sprom(struct b43_wldev *dev) } } -static void lpphy_adjust_gain_table(struct b43_wldev *dev) +static void lpphy_adjust_gain_table(struct b43_wldev *dev, u32 freq) { struct b43_phy_lp *lpphy = dev->phy.lp; - u32 freq = dev->wl->hw->conf.channel->center_freq; u16 temp[3]; u16 isolation; @@ -170,6 +188,8 @@ static void lpphy_adjust_gain_table(struct b43_wldev *dev) static void lpphy_table_init(struct b43_wldev *dev) { + u32 freq = channel2freq_lp(b43_lpphy_op_get_default_chan(dev)); + if (dev->phy.rev < 2) lpphy_rev0_1_table_init(dev); else @@ -178,7 +198,7 @@ static void lpphy_table_init(struct b43_wldev *dev) lpphy_init_tx_gain_table(dev); if (dev->phy.rev < 2) - lpphy_adjust_gain_table(dev); + lpphy_adjust_gain_table(dev, freq); } static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) @@ -1363,20 +1383,6 @@ static void lpphy_tx_pctl_init(struct b43_wldev *dev) } } -static int b43_lpphy_op_init(struct b43_wldev *dev) -{ - lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs? - lpphy_baseband_init(dev); - lpphy_radio_init(dev); - lpphy_calibrate_rc(dev); - //TODO set channel - lpphy_tx_pctl_init(dev); - lpphy_calibration(dev); - //TODO ACI init - - return 0; -} - static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg) { b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); @@ -1419,18 +1425,392 @@ static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev, //TODO } +struct b206x_channel { + u8 channel; + u16 freq; + u8 data[12]; +}; + +static const struct b206x_channel b2063_chantbl[] = { + { .channel = 1, .freq = 2412, .data[0] = 0x6F, .data[1] = 0x3C, + .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 2, .freq = 2417, .data[0] = 0x6F, .data[1] = 0x3C, + .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 3, .freq = 2422, .data[0] = 0x6F, .data[1] = 0x3C, + .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 4, .freq = 2427, .data[0] = 0x6F, .data[1] = 0x2C, + .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 5, .freq = 2432, .data[0] = 0x6F, .data[1] = 0x2C, + .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 6, .freq = 2437, .data[0] = 0x6F, .data[1] = 0x2C, + .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 7, .freq = 2442, .data[0] = 0x6F, .data[1] = 0x2C, + .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 8, .freq = 2447, .data[0] = 0x6F, .data[1] = 0x2C, + .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 9, .freq = 2452, .data[0] = 0x6F, .data[1] = 0x1C, + .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 10, .freq = 2457, .data[0] = 0x6F, .data[1] = 0x1C, + .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 11, .freq = 2462, .data[0] = 0x6E, .data[1] = 0x1C, + .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 12, .freq = 2467, .data[0] = 0x6E, .data[1] = 0x1C, + .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 13, .freq = 2472, .data[0] = 0x6E, .data[1] = 0x1C, + .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 14, .freq = 2484, .data[0] = 0x6E, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, + .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x80, .data[11] = 0x70, }, + { .channel = 34, .freq = 5170, .data[0] = 0x6A, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x02, .data[5] = 0x05, + .data[6] = 0x0D, .data[7] = 0x0D, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 36, .freq = 5180, .data[0] = 0x6A, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x05, + .data[6] = 0x0D, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 38, .freq = 5190, .data[0] = 0x6A, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04, + .data[6] = 0x0C, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x80, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 40, .freq = 5200, .data[0] = 0x69, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04, + .data[6] = 0x0C, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x70, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 42, .freq = 5210, .data[0] = 0x69, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04, + .data[6] = 0x0B, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x70, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 44, .freq = 5220, .data[0] = 0x69, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x04, + .data[6] = 0x0B, .data[7] = 0x0B, .data[8] = 0x77, .data[9] = 0x60, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 46, .freq = 5230, .data[0] = 0x69, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x03, + .data[6] = 0x0A, .data[7] = 0x0B, .data[8] = 0x77, .data[9] = 0x60, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 48, .freq = 5240, .data[0] = 0x69, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x03, + .data[6] = 0x0A, .data[7] = 0x0A, .data[8] = 0x77, .data[9] = 0x60, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 52, .freq = 5260, .data[0] = 0x68, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x02, + .data[6] = 0x09, .data[7] = 0x09, .data[8] = 0x77, .data[9] = 0x60, + .data[10] = 0x20, .data[11] = 0x00, }, + { .channel = 56, .freq = 5280, .data[0] = 0x68, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x01, + .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50, + .data[10] = 0x10, .data[11] = 0x00, }, + { .channel = 60, .freq = 5300, .data[0] = 0x68, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x01, + .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50, + .data[10] = 0x10, .data[11] = 0x00, }, + { .channel = 64, .freq = 5320, .data[0] = 0x67, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50, + .data[10] = 0x10, .data[11] = 0x00, }, + { .channel = 100, .freq = 5500, .data[0] = 0x64, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x02, .data[7] = 0x01, .data[8] = 0x77, .data[9] = 0x20, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 104, .freq = 5520, .data[0] = 0x64, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x01, .data[7] = 0x01, .data[8] = 0x77, .data[9] = 0x20, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 108, .freq = 5540, .data[0] = 0x63, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x01, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 112, .freq = 5560, .data[0] = 0x63, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 116, .freq = 5580, .data[0] = 0x62, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 120, .freq = 5600, .data[0] = 0x62, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 124, .freq = 5620, .data[0] = 0x62, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 128, .freq = 5640, .data[0] = 0x61, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 132, .freq = 5660, .data[0] = 0x61, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 136, .freq = 5680, .data[0] = 0x61, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 140, .freq = 5700, .data[0] = 0x60, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 149, .freq = 5745, .data[0] = 0x60, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 153, .freq = 5765, .data[0] = 0x60, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 157, .freq = 5785, .data[0] = 0x60, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 161, .freq = 5805, .data[0] = 0x60, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 165, .freq = 5825, .data[0] = 0x60, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00, + .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00, + .data[10] = 0x00, .data[11] = 0x00, }, + { .channel = 184, .freq = 4920, .data[0] = 0x6E, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x09, .data[5] = 0x0E, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xC0, + .data[10] = 0x50, .data[11] = 0x00, }, + { .channel = 188, .freq = 4940, .data[0] = 0x6E, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x09, .data[5] = 0x0D, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xB0, + .data[10] = 0x50, .data[11] = 0x00, }, + { .channel = 192, .freq = 4960, .data[0] = 0x6E, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0C, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xB0, + .data[10] = 0x50, .data[11] = 0x00, }, + { .channel = 196, .freq = 4980, .data[0] = 0x6D, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0C, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0, + .data[10] = 0x40, .data[11] = 0x00, }, + { .channel = 200, .freq = 5000, .data[0] = 0x6D, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0B, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0, + .data[10] = 0x40, .data[11] = 0x00, }, + { .channel = 204, .freq = 5020, .data[0] = 0x6D, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0A, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0, + .data[10] = 0x40, .data[11] = 0x00, }, + { .channel = 208, .freq = 5040, .data[0] = 0x6C, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x07, .data[5] = 0x09, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90, + .data[10] = 0x40, .data[11] = 0x00, }, + { .channel = 212, .freq = 5060, .data[0] = 0x6C, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x06, .data[5] = 0x08, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90, + .data[10] = 0x40, .data[11] = 0x00, }, + { .channel = 216, .freq = 5080, .data[0] = 0x6C, .data[1] = 0x0C, + .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x05, .data[5] = 0x08, + .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90, + .data[10] = 0x40, .data[11] = 0x00, }, +}; + +static void lpphy_b2062_tune(struct b43_wldev *dev, + unsigned int channel) +{ + //TODO +} + +static void lpphy_b2063_vco_calib(struct b43_wldev *dev) +{ + u16 tmp; + + b43_phy_mask(dev, B2063_PLL_SP1, ~0x40); + tmp = b43_phy_read(dev, B2063_PLL_JTAG_CALNRST) & 0xF8; + b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp); + udelay(1); + b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x4); + udelay(1); + b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x6); + udelay(1); + b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x7); + udelay(300); + b43_phy_set(dev, B2063_PLL_SP1, 0x40); +} + +static void lpphy_b2063_tune(struct b43_wldev *dev, + unsigned int channel) +{ + struct ssb_bus *bus = dev->dev->bus; + + static const struct b206x_channel *chandata = NULL; + u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000; + u32 freqref, vco_freq, val1, val2, val3, timeout, timeoutref, count; + u16 old_comm15, scale; + u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; + int i, div = (crystal_freq <= 26000000 ? 1 : 2); + + for (i = 0; i < ARRAY_SIZE(b2063_chantbl); i++) { + if (b2063_chantbl[i].channel == channel) { + chandata = &b2063_chantbl[i]; + break; + } + } + + if (B43_WARN_ON(!chandata)) + return; + + b43_radio_write(dev, B2063_LOGEN_VCOBUF1, chandata->data[0]); + b43_radio_write(dev, B2063_LOGEN_MIXER2, chandata->data[1]); + b43_radio_write(dev, B2063_LOGEN_BUF2, chandata->data[2]); + b43_radio_write(dev, B2063_LOGEN_RCCR1, chandata->data[3]); + b43_radio_write(dev, B2063_A_RX_1ST3, chandata->data[4]); + b43_radio_write(dev, B2063_A_RX_2ND1, chandata->data[5]); + b43_radio_write(dev, B2063_A_RX_2ND4, chandata->data[6]); + b43_radio_write(dev, B2063_A_RX_2ND7, chandata->data[7]); + b43_radio_write(dev, B2063_A_RX_PS6, chandata->data[8]); + b43_radio_write(dev, B2063_TX_RF_CTL2, chandata->data[9]); + b43_radio_write(dev, B2063_TX_RF_CTL5, chandata->data[10]); + b43_radio_write(dev, B2063_PA_CTL11, chandata->data[11]); + + old_comm15 = b43_radio_read(dev, B2063_COMM15); + b43_radio_set(dev, B2063_COMM15, 0x1E); + + if (chandata->freq > 4000) /* spec says 2484, but 4000 is safer */ + vco_freq = chandata->freq << 1; + else + vco_freq = chandata->freq << 2; + + freqref = crystal_freq * 3; + val1 = lpphy_qdiv_roundup(crystal_freq, 1000000, 16); + val2 = lpphy_qdiv_roundup(crystal_freq, 1000000 * div, 16); + val3 = lpphy_qdiv_roundup(vco_freq, 3, 16); + timeout = ((((8 * crystal_freq) / (div * 5000000)) + 1) >> 1) - 1; + b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB3, 0x2); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB6, + 0xFFF8, timeout >> 2); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB7, + 0xFF9F,timeout << 5); + + timeoutref = ((((8 * crystal_freq) / (div * (timeout + 1))) + + 999999) / 1000000) + 1; + b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB5, timeoutref); + + count = lpphy_qdiv_roundup(val3, val2 + 16, 16); + count *= (timeout + 1) * (timeoutref + 1); + count--; + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB7, + 0xF0, count >> 8); + b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB8, count & 0xFF); + + tmp1 = ((val3 * 62500) / freqref) << 4; + tmp2 = ((val3 * 62500) % freqref) << 4; + while (tmp2 >= freqref) { + tmp1++; + tmp2 -= freqref; + } + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG1, 0xFFE0, tmp1 >> 4); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG2, 0xFE0F, tmp1 << 4); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG2, 0xFFF0, tmp1 >> 16); + b43_radio_write(dev, B2063_PLL_JTAG_PLL_SG3, (tmp2 >> 8) & 0xFF); + b43_radio_write(dev, B2063_PLL_JTAG_PLL_SG4, tmp2 & 0xFF); + + b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF1, 0xB9); + b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF2, 0x88); + b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF3, 0x28); + b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF4, 0x63); + + tmp3 = ((41 * (val3 - 3000)) /1200) + 27; + tmp4 = lpphy_qdiv_roundup(132000 * tmp1, 8451, 16); + + if ((tmp4 + tmp3 - 1) / tmp3 > 60) { + scale = 1; + tmp5 = ((tmp4 + tmp3) / (tmp3 << 1)) - 8; + } else { + scale = 0; + tmp5 = ((tmp4 + (tmp3 >> 1)) / tmp3) - 8; + } + b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFC0, tmp5); + b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFBF, scale << 6); + + tmp6 = lpphy_qdiv_roundup(100 * val1, val3, 16); + tmp6 *= (tmp5 * 8) * (scale + 1); + if (tmp6 > 150) + tmp6 = 0; + + b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFE0, tmp6); + b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFDF, scale << 5); + + b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFFFB, 0x4); + if (crystal_freq > 26000000) + b43_phy_set(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0x2); + else + b43_phy_mask(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFD); + + if (val1 == 45) + b43_phy_set(dev, B2063_PLL_JTAG_PLL_VCO1, 0x2); + else + b43_phy_mask(dev, B2063_PLL_JTAG_PLL_VCO1, 0xFD); + + b43_phy_set(dev, B2063_PLL_SP2, 0x3); + udelay(1); + b43_phy_mask(dev, B2063_PLL_SP2, 0xFFFC); + lpphy_b2063_vco_calib(dev); + b43_radio_write(dev, B2063_COMM15, old_comm15); +} + static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, unsigned int new_channel) { - //TODO + b43_write16(dev, B43_MMIO_CHANNEL, new_channel); + + if (dev->phy.radio_ver == 0x2063) { + lpphy_b2063_tune(dev, new_channel); + } else { + lpphy_b2062_tune(dev, new_channel); + //TODO Japan filter + } + + lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel)); + return 0; } -static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev) +static int b43_lpphy_op_init(struct b43_wldev *dev) { - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - return 1; - return 36; + lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs? + lpphy_baseband_init(dev); + lpphy_radio_init(dev); + lpphy_calibrate_rc(dev); + b43_lpphy_op_switch_channel(dev, b43_lpphy_op_get_default_chan(dev)); + lpphy_tx_pctl_init(dev); + lpphy_calibration(dev); + //TODO ACI init + + return 0; } static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) -- cgit v1.2.3-18-g5258 From 1e711bee566e26f03e51d5a754e7c8a57e489f9f Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Fri, 14 Aug 2009 00:15:17 +0200 Subject: b43: LP-PHY: Implement channel switching for rev0/1/B2062 radio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -Move pdiv from lpphy_2062_init to struct b43_phy_lp. -Add channel table for the B2062 radio. -Add code for tuning the B2062 radio to channel. -Add error handling to op_switch_channel, and use it for both radios. Rev0/1/B2062 will now hopefully show some signs of life, though it won't work at full performance, as calibration is still missing. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 297 ++++++++++++++++++++++++++++++++++++-- drivers/net/wireless/b43/phy_lp.h | 2 + 2 files changed, 284 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 86da8281d92..e010268b987 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -455,8 +455,9 @@ struct b2062_freqdata { /* Initialize the 2062 radio. */ static void lpphy_2062_init(struct b43_wldev *dev) { + struct b43_phy_lp *lpphy = dev->phy.lp; struct ssb_bus *bus = dev->dev->bus; - u32 crystalfreq, pdiv, tmp, ref; + u32 crystalfreq, tmp, ref; unsigned int i; const struct b2062_freqdata *fd = NULL; @@ -496,22 +497,24 @@ static void lpphy_2062_init(struct b43_wldev *dev) B43_WARN_ON(crystalfreq == 0); if (crystalfreq >= 30000000) { - pdiv = 1; + lpphy->pdiv = 1; b43_radio_mask(dev, B2062_S_RFPLL_CTL1, 0xFFFB); } else { - pdiv = 2; + lpphy->pdiv = 2; b43_radio_set(dev, B2062_S_RFPLL_CTL1, 0x4); } - tmp = (800000000 * pdiv + crystalfreq) / (32000000 * pdiv); + tmp = (800000000 * lpphy->pdiv + crystalfreq) / + (32000000 * lpphy->pdiv); tmp = (tmp - 1) & 0xFF; b43_radio_write(dev, B2062_S_RFPLL_CTL18, tmp); - tmp = (2 * crystalfreq + 1000000 * pdiv) / (2000000 * pdiv); + tmp = (2 * crystalfreq + 1000000 * lpphy->pdiv) / + (2000000 * lpphy->pdiv); tmp = ((tmp & 0xFF) - 1) & 0xFFFF; b43_radio_write(dev, B2062_S_RFPLL_CTL19, tmp); - ref = (1000 * pdiv + 2 * crystalfreq) / (2000 * pdiv); + ref = (1000 * lpphy->pdiv + 2 * crystalfreq) / (2000 * lpphy->pdiv); ref &= 0xFFFF; for (i = 0; i < ARRAY_SIZE(freqdata_tab); i++) { if (ref < freqdata_tab[i].freq) { @@ -1431,6 +1434,162 @@ struct b206x_channel { u8 data[12]; }; +static const struct b206x_channel b2062_chantbl[] = { + { .channel = 1, .freq = 2412, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 2, .freq = 2417, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 3, .freq = 2422, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 4, .freq = 2427, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 5, .freq = 2432, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 6, .freq = 2437, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 7, .freq = 2442, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 8, .freq = 2447, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 9, .freq = 2452, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 10, .freq = 2457, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 11, .freq = 2462, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 12, .freq = 2467, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 13, .freq = 2472, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 14, .freq = 2484, .data[0] = 0xFF, .data[1] = 0xFF, + .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32, + .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, }, + { .channel = 34, .freq = 5170, .data[0] = 0x00, .data[1] = 0x22, + .data[2] = 0x20, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 38, .freq = 5190, .data[0] = 0x00, .data[1] = 0x11, + .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 42, .freq = 5210, .data[0] = 0x00, .data[1] = 0x11, + .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 46, .freq = 5230, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 36, .freq = 5180, .data[0] = 0x00, .data[1] = 0x11, + .data[2] = 0x20, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 40, .freq = 5200, .data[0] = 0x00, .data[1] = 0x11, + .data[2] = 0x10, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 44, .freq = 5220, .data[0] = 0x00, .data[1] = 0x11, + .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 48, .freq = 5240, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 52, .freq = 5260, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 56, .freq = 5280, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 60, .freq = 5300, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x63, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 64, .freq = 5320, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x62, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 100, .freq = 5500, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x30, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 104, .freq = 5520, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 108, .freq = 5540, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 112, .freq = 5560, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 116, .freq = 5580, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x10, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 120, .freq = 5600, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 124, .freq = 5620, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 128, .freq = 5640, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 132, .freq = 5660, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 136, .freq = 5680, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 140, .freq = 5700, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 149, .freq = 5745, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 153, .freq = 5765, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 157, .freq = 5785, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 161, .freq = 5805, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 165, .freq = 5825, .data[0] = 0x00, .data[1] = 0x00, + .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 184, .freq = 4920, .data[0] = 0x55, .data[1] = 0x77, + .data[2] = 0x90, .data[3] = 0xF7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 188, .freq = 4940, .data[0] = 0x44, .data[1] = 0x77, + .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 192, .freq = 4960, .data[0] = 0x44, .data[1] = 0x66, + .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 196, .freq = 4980, .data[0] = 0x33, .data[1] = 0x66, + .data[2] = 0x70, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 200, .freq = 5000, .data[0] = 0x22, .data[1] = 0x55, + .data[2] = 0x60, .data[3] = 0xD7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 204, .freq = 5020, .data[0] = 0x22, .data[1] = 0x55, + .data[2] = 0x60, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 208, .freq = 5040, .data[0] = 0x22, .data[1] = 0x44, + .data[2] = 0x50, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, }, + { .channel = 212, .freq = 5060, .data[0] = 0x11, .data[1] = 0x44, + .data[2] = 0x50, .data[3] = 0xA5, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, + { .channel = 216, .freq = 5080, .data[0] = 0x00, .data[1] = 0x44, + .data[2] = 0x40, .data[3] = 0xB6, .data[4] = 0x3C, .data[5] = 0x77, + .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, }, +}; + static const struct b206x_channel b2063_chantbl[] = { { .channel = 1, .freq = 2412, .data[0] = 0x6F, .data[1] = 0x3C, .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, @@ -1638,10 +1797,110 @@ static const struct b206x_channel b2063_chantbl[] = { .data[10] = 0x40, .data[11] = 0x00, }, }; -static void lpphy_b2062_tune(struct b43_wldev *dev, - unsigned int channel) +static void lpphy_b2062_reset_pll_bias(struct b43_wldev *dev) { - //TODO + struct ssb_bus *bus = dev->dev->bus; + + b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0xFF); + udelay(20); + if (bus->chip_id == 0x5354) { + b43_radio_write(dev, B2062_N_COMM1, 4); + b43_radio_write(dev, B2062_S_RFPLL_CTL2, 4); + } else { + b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0); + } + udelay(5); +} + +static void lpphy_b2062_vco_calib(struct b43_wldev *dev) +{ + b43_phy_write(dev, B2062_S_RFPLL_CTL21, 0x42); + b43_phy_write(dev, B2062_S_RFPLL_CTL21, 0x62); + udelay(200); +} + +static int lpphy_b2062_tune(struct b43_wldev *dev, + unsigned int channel) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + struct ssb_bus *bus = dev->dev->bus; + static const struct b206x_channel *chandata = NULL; + u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000; + u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9; + int i, err = 0; + + for (i = 0; i < ARRAY_SIZE(b2063_chantbl); i++) { + if (b2063_chantbl[i].channel == channel) { + chandata = &b2063_chantbl[i]; + break; + } + } + + if (B43_WARN_ON(!chandata)) + return -EINVAL; + + b43_radio_set(dev, B2062_S_RFPLL_CTL14, 0x04); + b43_radio_write(dev, B2062_N_LGENA_TUNE0, chandata->data[0]); + b43_radio_write(dev, B2062_N_LGENA_TUNE2, chandata->data[1]); + b43_radio_write(dev, B2062_N_LGENA_TUNE3, chandata->data[2]); + b43_radio_write(dev, B2062_N_TX_TUNE, chandata->data[3]); + b43_radio_write(dev, B2062_S_LGENG_CTL1, chandata->data[4]); + b43_radio_write(dev, B2062_N_LGENA_CTL5, chandata->data[5]); + b43_radio_write(dev, B2062_N_LGENA_CTL6, chandata->data[6]); + b43_radio_write(dev, B2062_N_TX_PGA, chandata->data[7]); + b43_radio_write(dev, B2062_N_TX_PAD, chandata->data[8]); + + tmp1 = crystal_freq / 1000; + tmp2 = lpphy->pdiv * 1000; + b43_radio_write(dev, B2062_S_RFPLL_CTL33, 0xCC); + b43_radio_write(dev, B2062_S_RFPLL_CTL34, 0x07); + lpphy_b2062_reset_pll_bias(dev); + tmp3 = tmp2 * channel2freq_lp(channel); + if (channel2freq_lp(channel) < 4000) + tmp3 *= 2; + tmp4 = 48 * tmp1; + tmp6 = tmp3 / tmp4; + tmp7 = tmp3 % tmp4; + b43_radio_write(dev, B2062_S_RFPLL_CTL26, tmp6); + tmp5 = tmp7 * 0x100; + tmp6 = tmp5 / tmp4; + tmp7 = tmp5 % tmp4; + b43_radio_write(dev, B2062_S_RFPLL_CTL28, tmp6); + tmp5 = tmp7 * 0x100; + tmp6 = tmp5 / tmp4; + tmp7 = tmp5 % tmp4; + b43_radio_write(dev, B2062_S_RFPLL_CTL29, tmp6 + ((2 * tmp7) / tmp4)); + tmp8 = b43_phy_read(dev, B2062_S_RFPLL_CTL19); + tmp9 = ((2 * tmp3 * (tmp8 + 1)) + (3 * tmp1)) / (6 * tmp1); + b43_radio_write(dev, B2062_S_RFPLL_CTL23, tmp9 >> 8); + b43_radio_write(dev, B2062_S_RFPLL_CTL24, tmp9 & 0xFF); + + lpphy_b2062_vco_calib(dev); + if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10) { + b43_radio_write(dev, B2062_S_RFPLL_CTL33, 0xFC); + b43_radio_write(dev, B2062_S_RFPLL_CTL34, 0); + lpphy_b2062_reset_pll_bias(dev); + lpphy_b2062_vco_calib(dev); + if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10) + err = -EINVAL; + } + + b43_radio_mask(dev, B2062_S_RFPLL_CTL14, ~0x04); + return err; +} + +static void lpphy_japan_filter(struct b43_wldev *dev, int channel) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + u16 tmp = (channel == 14); //SPEC FIXME check japanwidefilter! + + if (dev->phy.rev < 2) { //SPEC FIXME Isn't this rev0/1-specific? + b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFCFF, tmp << 9); + if ((dev->phy.rev == 1) && (lpphy->rc_cap)) + lpphy_set_rc_cap(dev); + } else { + b43_radio_write(dev, B2063_TX_BB_SP3, 0x3F); + } } static void lpphy_b2063_vco_calib(struct b43_wldev *dev) @@ -1661,8 +1920,8 @@ static void lpphy_b2063_vco_calib(struct b43_wldev *dev) b43_phy_set(dev, B2063_PLL_SP1, 0x40); } -static void lpphy_b2063_tune(struct b43_wldev *dev, - unsigned int channel) +static int lpphy_b2063_tune(struct b43_wldev *dev, + unsigned int channel) { struct ssb_bus *bus = dev->dev->bus; @@ -1681,7 +1940,7 @@ static void lpphy_b2063_tune(struct b43_wldev *dev, } if (B43_WARN_ON(!chandata)) - return; + return -EINVAL; b43_radio_write(dev, B2063_LOGEN_VCOBUF1, chandata->data[0]); b43_radio_write(dev, B2063_LOGEN_MIXER2, chandata->data[1]); @@ -1780,18 +2039,26 @@ static void lpphy_b2063_tune(struct b43_wldev *dev, b43_phy_mask(dev, B2063_PLL_SP2, 0xFFFC); lpphy_b2063_vco_calib(dev); b43_radio_write(dev, B2063_COMM15, old_comm15); + + return 0; } static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, unsigned int new_channel) { + int err; + b43_write16(dev, B43_MMIO_CHANNEL, new_channel); if (dev->phy.radio_ver == 0x2063) { - lpphy_b2063_tune(dev, new_channel); + err = lpphy_b2063_tune(dev, new_channel); + if (err) + return err; } else { - lpphy_b2062_tune(dev, new_channel); - //TODO Japan filter + err = lpphy_b2062_tune(dev, new_channel); + if (err) + return err; + lpphy_japan_filter(dev, new_channel); } lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel)); diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h index 4eab760ac61..99cb0386e34 100644 --- a/drivers/net/wireless/b43/phy_lp.h +++ b/drivers/net/wireless/b43/phy_lp.h @@ -884,6 +884,8 @@ struct b43_phy_lp { /* Used for "Save/Restore Dig Filt State" */ u16 dig_flt_state[9]; + + unsigned int pdiv; }; enum tssi_mux_mode { -- cgit v1.2.3-18-g5258 From db91f2e4d410bf3011b3649b9257e5b3c60b25ff Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Fri, 14 Aug 2009 11:27:16 +0530 Subject: ath9k: Add open loop power control support for AR9287. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/calib.c | 44 +++++++++++++++++++++++----------- drivers/net/wireless/ath/ath9k/hw.c | 20 ++++++++++++---- drivers/net/wireless/ath/ath9k/phy.h | 7 ++++++ 3 files changed, 52 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 26d87527acb..20f74b5b570 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -729,26 +729,42 @@ s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) static void ath9k_olc_temp_compensation(struct ath_hw *ah) { u32 rddata, i; - int delta, currPDADC, regval; + int delta, currPDADC, regval, slope; rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4); - currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); - if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G)) - delta = (currPDADC - ah->initPDADC + 4) / 8; - else - delta = (currPDADC - ah->initPDADC + 5) / 10; - if (delta != ah->PDADCdelta) { - ah->PDADCdelta = delta; - for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) { - regval = ah->originalGain[i] - delta; - if (regval < 0) - regval = 0; + if (OLC_FOR_AR9287_10_LATER) { + if (ah->initPDADC == 0 || currPDADC == 0) { + return; + } else { + slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE); + if (slope == 0) + delta = 0; + else + delta = ((currPDADC - ah->initPDADC)*4) / slope; + REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11, + AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); + REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11, + AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); + } + } else { + if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G)) + delta = (currPDADC - ah->initPDADC + 4) / 8; + else + delta = (currPDADC - ah->initPDADC + 5) / 10; + + if (delta != ah->PDADCdelta) { + ah->PDADCdelta = delta; + for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) { + regval = ah->originalGain[i] - delta; + if (regval < 0) + regval = 0; - REG_RMW_FIELD(ah, AR_PHY_TX_GAIN_TBL1 + i * 4, - AR_PHY_TX_GAIN, regval); + REG_RMW_FIELD(ah, AR_PHY_TX_GAIN_TBL1 + i * 4, + AR_PHY_TX_GAIN, regval); + } } } } diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 9f1b34d9861..125e689f7c5 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1332,11 +1332,21 @@ static void ath9k_olc_init(struct ath_hw *ah) { u32 i; - for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++) - ah->originalGain[i] = - MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4), - AR_PHY_TX_GAIN); - ah->PDADCdelta = 0; + if (OLC_FOR_AR9287_10_LATER) { + REG_SET_BIT(ah, AR_PHY_TX_PWRCTRL9, + AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TXPC0, + AR9287_AN_TXPC0_TXPCMODE, + AR9287_AN_TXPC0_TXPCMODE_S, + AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE); + udelay(100); + } else { + for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++) + ah->originalGain[i] = + MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4), + AR_PHY_TX_GAIN); + ah->PDADCdelta = 0; + } } static u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index e83cd4ab87f..dfda6f44464 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -490,11 +490,18 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, #define AR_PHY_TX_PWRCTRL9 0xa27C #define AR_PHY_TX_DESIRED_SCALE_CCK 0x00007C00 #define AR_PHY_TX_DESIRED_SCALE_CCK_S 10 +#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL 0x80000000 +#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL_S 31 #define AR_PHY_TX_GAIN_TBL1 0xa300 #define AR_PHY_TX_GAIN 0x0007F000 #define AR_PHY_TX_GAIN_S 12 +#define AR_PHY_CH0_TX_PWRCTRL11 0xa398 +#define AR_PHY_CH1_TX_PWRCTRL11 0xb398 +#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP 0x0000FC00 +#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP_S 10 + #define AR_PHY_VIT_MASK2_M_46_61 0xa3a0 #define AR_PHY_MASK2_M_31_45 0xa3a4 #define AR_PHY_MASK2_M_16_30 0xa3a8 -- cgit v1.2.3-18-g5258 From d340b1f0e5e374fc902a020cb6ef9ebd7fb9f368 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Fri, 14 Aug 2009 11:29:27 +0530 Subject: ath9k: Set AR_WA for AR9287 as it improves consistency in throughput. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 125e689f7c5..9a139dcc69b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3073,7 +3073,7 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore) if (ah->config.pcie_waen) { REG_WRITE(ah, AR_WA, ah->config.pcie_waen); } else { - if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) + if (AR_SREV_9285(ah) || AR_SREV_9271(ah) || AR_SREV_9287(ah)) REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT); /* * On AR9280 chips bit 22 of 0x4004 needs to be set to -- cgit v1.2.3-18-g5258 From 08fc5c1ba026de0904aeeba9785f95f6603d58f7 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Fri, 14 Aug 2009 11:30:52 +0530 Subject: ath9k: Enable LEDs for AR9287 chipsets. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 3 ++- drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/main.c | 27 ++++++++++++++++----------- drivers/net/wireless/ath/ath9k/pci.c | 6 +++--- 4 files changed, 22 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 2fd663c01b8..2c9f6628a8e 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -454,7 +454,8 @@ struct ath_ani { /* LED Control */ /********************/ -#define ATH_LED_PIN 1 +#define ATH_LED_PIN_DEF 1 +#define ATH_LED_PIN_9287 8 #define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */ #define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 0336981a70e..de31a1595f1 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -522,6 +522,7 @@ struct ath_hw { u32 originalGain[22]; int initPDADC; int PDADCdelta; + u8 led_pin; struct ar5416IniArray iniModes; struct ar5416IniArray iniCommon; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index fa4c6e74f97..3e09b9ac165 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -968,9 +968,9 @@ static void ath_led_blink_work(struct work_struct *work) if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) || (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); else - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0); ieee80211_queue_delayed_work(sc->hw, @@ -1002,7 +1002,7 @@ static void ath_led_brightness(struct led_classdev *led_cdev, case LED_OFF: if (led->led_type == ATH_LED_ASSOC || led->led_type == ATH_LED_RADIO) { - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, (led->led_type == ATH_LED_RADIO)); sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; if (led->led_type == ATH_LED_RADIO) @@ -1017,7 +1017,7 @@ static void ath_led_brightness(struct led_classdev *led_cdev, ieee80211_queue_delayed_work(sc->hw, &sc->ath_led_blink_work, 0); } else if (led->led_type == ATH_LED_RADIO) { - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); sc->sc_flags |= SC_OP_LED_ON; } else { sc->led_on_cnt++; @@ -1062,7 +1062,7 @@ static void ath_deinit_leds(struct ath_softc *sc) ath_unregister_led(&sc->tx_led); ath_unregister_led(&sc->rx_led); ath_unregister_led(&sc->radio_led); - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); } static void ath_init_leds(struct ath_softc *sc) @@ -1070,11 +1070,16 @@ static void ath_init_leds(struct ath_softc *sc) char *trigger; int ret; + if (AR_SREV_9287(sc->sc_ah)) + sc->sc_ah->led_pin = ATH_LED_PIN_9287; + else + sc->sc_ah->led_pin = ATH_LED_PIN_DEF; + /* Configure gpio 1 for output */ - ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, + ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); /* LED off, active low */ - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work); @@ -1153,9 +1158,9 @@ void ath_radio_enable(struct ath_softc *sc) ath9k_hw_set_interrupts(ah, sc->imask); /* Enable LED */ - ath9k_hw_cfg_output(ah, ATH_LED_PIN, + ath9k_hw_cfg_output(ah, ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - ath9k_hw_set_gpio(ah, ATH_LED_PIN, 0); + ath9k_hw_set_gpio(ah, ah->led_pin, 0); ieee80211_wake_queues(sc->hw); ath9k_ps_restore(sc); @@ -1171,8 +1176,8 @@ void ath_radio_disable(struct ath_softc *sc) ieee80211_stop_queues(sc->hw); /* Disable LED */ - ath9k_hw_set_gpio(ah, ATH_LED_PIN, 1); - ath9k_hw_cfg_gpio_input(ah, ATH_LED_PIN); + ath9k_hw_set_gpio(ah, ah->led_pin, 1); + ath9k_hw_cfg_gpio_input(ah, ah->led_pin); /* Disable interrupts */ ath9k_hw_set_interrupts(ah, 0); diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 616bdff2b6a..685a8cebb46 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -236,7 +236,7 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); pci_save_state(pdev); pci_disable_device(pdev); @@ -269,9 +269,9 @@ static int ath_pci_resume(struct pci_dev *pdev) pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); /* Enable LED */ - ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, + ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); return 0; } -- cgit v1.2.3-18-g5258 From d4fe5afa006bf308962877c4768c4e60d37a3da2 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Fri, 14 Aug 2009 11:32:04 +0530 Subject: ath9k: Fix ref power interpolation logic for AR9287 chipsets. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom_9287.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index aeb7f484b6e..959097927ee 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -374,7 +374,6 @@ static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah, u8 *pCalChans, u16 availPiers, int8_t *pPwr) { - u8 pcdac, i = 0; u16 idxL = 0, idxR = 0, numPiers; bool match; struct chan_centers centers; @@ -392,17 +391,12 @@ static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah, &idxL, &idxR); if (match) { - pcdac = pRawDatasetOpLoop[idxL].pcdac[0][0]; - *pPwr = pRawDatasetOpLoop[idxL].pwrPdg[0][0]; + *pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0]; } else { - pcdac = pRawDatasetOpLoop[idxR].pcdac[0][0]; - *pPwr = (pRawDatasetOpLoop[idxL].pwrPdg[0][0] + - pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; + *pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] + + (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; } - while ((pcdac > ah->originalGain[i]) && - (i < (AR9280_TX_GAIN_TABLE_SIZE - 1))) - i++; } static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah, -- cgit v1.2.3-18-g5258 From 326bebbcb51d3ce9761f616b8b9a35827fd9c697 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Fri, 14 Aug 2009 11:33:36 +0530 Subject: ath9k: Updates for AR9287_12 version of chipset. Enable AsyncFIFO and AGGWEP for AR9287_12 and later revisions only. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 6 +++--- drivers/net/wireless/ath/ath9k/reg.h | 9 ++++++++- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 9a139dcc69b..df62113d89d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2392,7 +2392,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (AR_SREV_9280_10_OR_LATER(ah)) REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); - if (AR_SREV_9287_10_OR_LATER(ah)) { + if (AR_SREV_9287_12_OR_LATER(ah)) { /* Enable ASYNC FIFO */ REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3, AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL); @@ -2478,7 +2478,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_init_user_settings(ah); - if (AR_SREV_9287_10_OR_LATER(ah)) { + if (AR_SREV_9287_12_OR_LATER(ah)) { REG_WRITE(ah, AR_D_GBL_IFS_SIFS, AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR); REG_WRITE(ah, AR_D_GBL_IFS_SLOT, @@ -2494,7 +2494,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN, AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL); } - if (AR_SREV_9287_10_OR_LATER(ah)) { + if (AR_SREV_9287_12_OR_LATER(ah)) { REG_SET_BIT(ah, AR_PCU_MISC_MODE2, AR_PCU_MISC_MODE2_ENABLE_AGGWEP); } diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 13fd658b5d3..c9e1ac92d0e 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -744,6 +744,7 @@ #define AR_SREV_VERSION_9287 0x180 #define AR_SREV_REVISION_9287_10 0 #define AR_SREV_REVISION_9287_11 1 +#define AR_SREV_REVISION_9287_12 2 #define AR_SREV_VERSION_9271 0x140 #define AR_SREV_REVISION_9271_10 0 #define AR_SREV_REVISION_9271_11 1 @@ -817,7 +818,13 @@ (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_11))) - +#define AR_SREV_9287_12(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_12)) +#define AR_SREV_9287_12_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \ + ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_12))) #define AR_SREV_9271(_ah) \ (((_ah))->hw_version.macVersion == AR_SREV_VERSION_9271) #define AR_SREV_9271_10(_ah) \ -- cgit v1.2.3-18-g5258 From c46aaba74f37448f0a1a3e911230834b7ebe514f Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 14 Aug 2009 13:23:05 +0200 Subject: p54: disable PS by default Johannes kindly pointed out that I completely missed a hunk in his patch: "[PATCH] cfg80211: allow driver to override PS default". The driver must explicitly set ps_default to false, as the setting is pre-filled with the kconfig default. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 4a741df9c08..77203e346cd 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -575,6 +575,12 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 + sizeof(struct p54_tx_data); + /* + * For now, disable PS by default because it affects + * link stability significantly. + */ + dev->wiphy->ps_default = false; + mutex_init(&priv->conf_mutex); mutex_init(&priv->eeprom_mutex); init_completion(&priv->eeprom_comp); -- cgit v1.2.3-18-g5258 From f0ea6ce14ae2a72a353ddf8ab370c09ba403d897 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Fri, 14 Aug 2009 14:11:53 +0200 Subject: ssb: Fix typo in the rev8 SPROM extraction routine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No comment. :-) Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/ssb/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 593fc618a2e..f853d5600ca 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -480,7 +480,7 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) /* extract the MAC address */ for (i = 0; i < 3; i++) { - v = in[SPOFF(SSB_SPROM1_IL0MAC) + i]; + v = in[SPOFF(SSB_SPROM8_IL0MAC) + i]; *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); } SPEX(country_code, SSB_SPROM8_CCODE, 0xFFFF, 0); -- cgit v1.2.3-18-g5258 From 759b973bb2d24adecaa526957435eabb00f02725 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Fri, 14 Aug 2009 14:39:53 +0200 Subject: b43: Add LP-PHY firmware loading support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for loading LP-PHY firmware to b43_try_request_fw. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index f6d039e303f..2a75bebd329 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1955,8 +1955,12 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) filename = "ucode5"; else if ((rev >= 11) && (rev <= 12)) filename = "ucode11"; - else if (rev >= 13) + else if (rev == 13) filename = "ucode13"; + else if (rev == 14) + filename = "ucode14"; + else if (rev >= 15) + filename = "ucode15"; else goto err_no_ucode; err = b43_do_request_fw(ctx, filename, &fw->ucode); @@ -2004,6 +2008,16 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) else goto err_no_initvals; break; + case B43_PHYTYPE_LP: + if (rev == 13) + filename = "lp0initvals13"; + else if (rev == 14) + filename = "lp0initvals14"; + else if (rev >= 15) + filename = "lp0initvals15"; + else + goto err_no_initvals; + break; default: goto err_no_initvals; } @@ -2038,6 +2052,16 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) else goto err_no_initvals; break; + case B43_PHYTYPE_LP: + if (rev == 13) + filename = "lp0bsinitvals13"; + else if (rev == 14) + filename = "lp0bsinitvals14"; + else if (rev >= 15) + filename = "lp0bsinitvals15"; + else + goto err_no_initvals; + break; default: goto err_no_initvals; } -- cgit v1.2.3-18-g5258 From 9d86a2d531c722feb0046e5a0b81809efb10422a Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Fri, 14 Aug 2009 14:54:46 +0200 Subject: b43: Make LP-PHY testable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -Enable rate memory init for LP-PHY (same as G and N-PHY). -Mark rev.2 LP-PHYs with the B2063 radio as supported. -Allow using the 5GHz band on LP-PHYs. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 2a75bebd329..99b41ce6848 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2589,6 +2589,7 @@ static void b43_rate_memory_init(struct b43_wldev *dev) case B43_PHYTYPE_A: case B43_PHYTYPE_G: case B43_PHYTYPE_N: + case B43_PHYTYPE_LP: b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1); b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1); b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1); @@ -3817,7 +3818,7 @@ static int b43_phy_versioning(struct b43_wldev *dev) #endif #ifdef CONFIG_B43_PHY_LP case B43_PHYTYPE_LP: - if (phy_rev > 1) + if (phy_rev > 2) unsupported = 1; break; #endif @@ -3874,7 +3875,7 @@ static int b43_phy_versioning(struct b43_wldev *dev) unsupported = 1; break; case B43_PHYTYPE_LP: - if (radio_ver != 0x2062) + if (radio_ver != 0x2062 && radio_ver != 0x2063) unsupported = 1; break; default: @@ -4512,9 +4513,10 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) case B43_PHYTYPE_A: have_5ghz_phy = 1; break; + case B43_PHYTYPE_LP: //FIXME not always! + have_5ghz_phy = 1; case B43_PHYTYPE_G: case B43_PHYTYPE_N: - case B43_PHYTYPE_LP: have_2ghz_phy = 1; break; default: @@ -4529,7 +4531,8 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) } if (1 /* disable A-PHY */) { /* FIXME: For now we disable the A-PHY on multi-PHY devices. */ - if (dev->phy.type != B43_PHYTYPE_N) { + if (dev->phy.type != B43_PHYTYPE_N && + dev->phy.type != B43_PHYTYPE_LP) { have_2ghz_phy = 1; have_5ghz_phy = 0; } -- cgit v1.2.3-18-g5258 From 0c61bb9a410de6ef36b4a473ced34f983a87db35 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Fri, 14 Aug 2009 21:11:59 +0200 Subject: b43: LP-PHY: Don't adjust gain table for rev2+ when setting channel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rev2+ never needs to have gain tables adjusted according to the spec. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index e010268b987..ce81920d26d 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -2059,10 +2059,9 @@ static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, if (err) return err; lpphy_japan_filter(dev, new_channel); + lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel)); } - lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel)); - return 0; } -- cgit v1.2.3-18-g5258 From 16373f652523705aa07bf78b4f388d96feb8f9d3 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Fri, 14 Aug 2009 22:10:34 +0200 Subject: b43: LP-PHY: Update TX gain override for a spec typo fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index ce81920d26d..18d517cc292 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -747,7 +747,7 @@ static void lpphy_set_tx_gains(struct b43_wldev *dev, b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F, 1 << 7); b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF, 1 << 14); } - b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFBF, 1 << 4); + b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFBF, 1 << 6); } static void lpphy_rev0_1_set_rx_gain(struct b43_wldev *dev, u32 gain) -- cgit v1.2.3-18-g5258 From 1245684c631844d52079fb3fa1fcb57cc1213e5c Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Fri, 14 Aug 2009 23:00:32 +0200 Subject: b43: LP-PHY: Fix another TX power control abuse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should fix the remaining WARN_ON. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 18d517cc292..038a59d63a4 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1059,7 +1059,8 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) bool old_txg_ovr; u8 old_bbmult; u16 old_rf_ovr, old_rf_ovrval, old_afe_ovr, old_afe_ovrval, - old_rf2_ovr, old_rf2_ovrval, old_phy_ctl, old_txpctl; + old_rf2_ovr, old_rf2_ovrval, old_phy_ctl; + enum b43_lpphy_txpctl_mode old_txpctl; u32 normal_pwr, ideal_pwr, mean_sq_pwr, tmp = 0, mean_sq_pwr_min = 0; int loopback, i, j, inner_sum; @@ -1077,8 +1078,8 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) old_rf2_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2); old_rf2_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2_VAL); old_phy_ctl = b43_phy_read(dev, B43_LPPHY_LP_PHY_CTL); - old_txpctl = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_CMD) & - B43_LPPHY_TX_PWR_CTL_CMD_MODE; + lpphy_read_tx_pctl_mode_from_hardware(dev); + old_txpctl = lpphy->txpctl_mode; lpphy_set_tx_power_control(dev, B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF); lpphy_disable_crs(dev); -- cgit v1.2.3-18-g5258 From 826ee70664c658a022d999f7eb4d3cd9448895dd Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Sat, 15 Aug 2009 00:52:02 +0200 Subject: b43: Handle B43_PHYTYPE_LP in RX path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't drop all packets received from an LP-PHY with WARN_ON. Also update a comment with LP-specific information. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/wa.c | 2 +- drivers/net/wireless/b43/xmit.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/wa.c b/drivers/net/wireless/b43/wa.c index 73e97fa4ddf..97c79161c20 100644 --- a/drivers/net/wireless/b43/wa.c +++ b/drivers/net/wireless/b43/wa.c @@ -628,7 +628,7 @@ void b43_wa_all(struct b43_wldev *dev) B43_WARN_ON(1); } b43_wa_boards_g(dev); - } else { /* No N PHY support so far */ + } else { /* No N PHY support so far, LP PHY is in phy_lp.c */ B43_WARN_ON(1); } diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 5280ebc8c6e..be1c53ecdb0 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -655,6 +655,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) status.freq = chanid + 2400; break; case B43_PHYTYPE_N: + case B43_PHYTYPE_LP: /* chanid is the SHM channel cookie. Which is the plain * channel number in b43. */ if (chanstat & B43_RX_CHAN_5GHZ) { -- cgit v1.2.3-18-g5258 From 96909e97716de1d86e6e24d6aabce09980372771 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Sun, 16 Aug 2009 01:15:49 +0200 Subject: b43: LP-PHY: Update baseband init for recent spec changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The spec had some nasty typos, and a large part of the rev0/1 BB init procedure was also missing. Fix these. Also make the init-time channel switch debuggable. (The change from -EINVAL to -EIO is simply to make it possible to distinguish the PLL charge pump error from a channel-not-found error.) Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 73 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 038a59d63a4..85af82a7f94 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -204,8 +204,62 @@ static void lpphy_table_init(struct b43_wldev *dev) static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) { struct ssb_bus *bus = dev->dev->bus; + struct b43_phy_lp *lpphy = dev->phy.lp; u16 tmp, tmp2; + b43_phy_mask(dev, B43_LPPHY_AFE_DAC_CTL, 0xF7FF); + b43_phy_write(dev, B43_LPPHY_AFE_CTL, 0); + b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, 0); + b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, 0); + b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0); + b43_phy_set(dev, B43_LPPHY_AFE_DAC_CTL, 0x0004); + b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0x0078); + b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x5800); + b43_phy_write(dev, B43_LPPHY_ADC_COMPENSATION_CTL, 0x0016); + b43_phy_maskset(dev, B43_LPPHY_AFE_ADC_CTL_0, 0xFFF8, 0x0004); + b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0x00FF, 0x5400); + b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2400); + b43_phy_maskset(dev, B43_LPPHY_LOWGAINDB, 0x00FF, 0x2100); + b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0x0006); + b43_phy_mask(dev, B43_LPPHY_RX_RADIO_CTL, 0xFFFE); + b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x0005); + b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC10, 0x0180); + b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x3800); + b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFFF0, 0x0005); + b43_phy_maskset(dev, B43_LPPHY_GAIN_MISMATCH_LIMIT, 0xFFC0, 0x001A); + b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0xFF00, 0x00B3); + b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0x00FF, 0xAD00); + b43_phy_maskset(dev, B43_LPPHY_INPUT_PWRDB, + 0xFF00, lpphy->rx_pwr_offset); + if ((bus->sprom.boardflags_lo & B43_BFL_FEM) && + ((b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) || + (bus->sprom.boardflags_hi & B43_BFH_PAREF))) { + /* TODO: + * Set the LDO voltage to 0x0028 - FIXME: What is this? + * Call sb_pmu_set_ldo_voltage with 4 and the LDO voltage + * as arguments + * Call sb_pmu_paref_ldo_enable with argument TRUE + */ + if (dev->phy.rev == 0) { + b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT, + 0xFFCF, 0x0010); + } + b43_lptab_write(dev, B43_LPTAB16(11, 7), 60); + } else { + //TODO: Call ssb_pmu_paref_ldo_enable with argument FALSE + b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT, + 0xFFCF, 0x0020); + b43_lptab_write(dev, B43_LPTAB16(11, 7), 100); + } + tmp = lpphy->rssi_vf | lpphy->rssi_vc << 4 | 0xA000; + b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_0, tmp); + if (bus->sprom.boardflags_hi & B43_BFH_RSSIINV) + b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x0AAA); + else + b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x02AA); + b43_lptab_write(dev, B43_LPTAB16(11, 1), 24); + b43_phy_maskset(dev, B43_LPPHY_RX_RADIO_CTL, + 0xFFF9, (lpphy->bx_arch << 1)); if (dev->phy.rev == 1 && (bus->sprom.boardflags_hi & B43_BFH_FEM_BT)) { b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A); @@ -255,7 +309,7 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0006); b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0700); } - if (dev->phy.rev == 1) { + if (dev->phy.rev == 1 && (bus->sprom.boardflags_hi & B43_BFH_PAREF)) { b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_5, B43_LPPHY_TR_LOOKUP_1); b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_6, B43_LPPHY_TR_LOOKUP_2); b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_7, B43_LPPHY_TR_LOOKUP_3); @@ -267,6 +321,7 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0006); b43_phy_write(dev, B43_LPPHY_GPIO_SELECT, 0x0005); b43_phy_write(dev, B43_LPPHY_GPIO_OUTEN, 0xFFFF); + //FIXME the Broadcom driver caches & delays this HF write! b43_hf_write(dev, b43_hf_read(dev) | B43_HF_PR45960W); } if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { @@ -384,7 +439,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_PWR_THRESH1, 0xFFF0, 0x9); b43_phy_mask(dev, B43_LPPHY_GAINDIRECTMISMATCH, ~0xF); b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0x00FF, 0x5500); - b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xF81F, 0xA0); + b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC1F, 0xA0); b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xE0FF, 0x300); b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2A00); if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) { @@ -405,7 +460,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x12); b43_phy_maskset(dev, B43_LPPHY_GAINMISMATCH, 0x0FFF, 0x9000); - if ((bus->chip_id == 0x4325) && (bus->chip_rev == 1)) { + if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) { b43_lptab_write(dev, B43_LPTAB16(0x08, 0x14), 0); b43_lptab_write(dev, B43_LPTAB16(0x08, 0x12), 0x40); } @@ -416,6 +471,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_SYNCPEAKCNT, 0xFFF8, 0x6); b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0x00FF, 0x9D00); b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0xFF00, 0xA1); + b43_phy_mask(dev, B43_LPPHY_IDLEAFTERPKTRXTO, 0x00FF); } else /* 5GHz */ b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x40); @@ -1883,7 +1939,7 @@ static int lpphy_b2062_tune(struct b43_wldev *dev, lpphy_b2062_reset_pll_bias(dev); lpphy_b2062_vco_calib(dev); if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10) - err = -EINVAL; + err = -EIO; } b43_radio_mask(dev, B2062_S_RFPLL_CTL14, ~0x04); @@ -2068,11 +2124,18 @@ static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, static int b43_lpphy_op_init(struct b43_wldev *dev) { + int err; + lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs? lpphy_baseband_init(dev); lpphy_radio_init(dev); lpphy_calibrate_rc(dev); - b43_lpphy_op_switch_channel(dev, b43_lpphy_op_get_default_chan(dev)); + err = b43_lpphy_op_switch_channel(dev, + b43_lpphy_op_get_default_chan(dev)); + if (err) { + b43dbg(dev->wl, "Switch to init channel failed, error = %d.\n", + err); + } lpphy_tx_pctl_init(dev); lpphy_calibration(dev); //TODO ACI init -- cgit v1.2.3-18-g5258 From 055114a38804947554065194d50ded4bc7d7c4c6 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Sun, 16 Aug 2009 15:32:40 +0200 Subject: b43: LP-PHY: Fix a spec error in the B2062 channel switch routine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The channel switch routine had a whole instruction missing. Add it. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 85af82a7f94..cb6c18d2cdb 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1922,6 +1922,10 @@ static int lpphy_b2062_tune(struct b43_wldev *dev, tmp5 = tmp7 * 0x100; tmp6 = tmp5 / tmp4; tmp7 = tmp5 % tmp4; + b43_radio_write(dev, B2062_S_RFPLL_CTL27, tmp6); + tmp5 = tmp7 * 0x100; + tmp6 = tmp5 / tmp4; + tmp7 = tmp5 % tmp4; b43_radio_write(dev, B2062_S_RFPLL_CTL28, tmp6); tmp5 = tmp7 * 0x100; tmp6 = tmp5 / tmp4; -- cgit v1.2.3-18-g5258 From 5269102ec9c1584ccfab71affd1d7600d59f9096 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Sun, 16 Aug 2009 18:05:09 +0200 Subject: b43: LP-PHY: Update code for spec fixes, and fix a few typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A few typos have been discovered in both the specs and the code. This patch fixes them. Also use lpphy_op_switch_channel consistently, and make all users of it print its return value for easier debugging. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 53 ++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index cb6c18d2cdb..4d14102821c 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -552,7 +552,7 @@ static void lpphy_2062_init(struct b43_wldev *dev) B43_WARN_ON(!(bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU)); B43_WARN_ON(crystalfreq == 0); - if (crystalfreq >= 30000000) { + if (crystalfreq <= 30000000) { lpphy->pdiv = 1; b43_radio_mask(dev, B2062_S_RFPLL_CTL1, 0xFFFB); } else { @@ -560,14 +560,16 @@ static void lpphy_2062_init(struct b43_wldev *dev) b43_radio_set(dev, B2062_S_RFPLL_CTL1, 0x4); } - tmp = (800000000 * lpphy->pdiv + crystalfreq) / - (32000000 * lpphy->pdiv); - tmp = (tmp - 1) & 0xFF; + tmp = (((800000000 * lpphy->pdiv + crystalfreq) / + (2 * crystalfreq)) - 8) & 0xFF; + b43_radio_write(dev, B2062_S_RFPLL_CTL7, tmp); + + tmp = (((100 * crystalfreq + 16000000 * lpphy->pdiv) / + (32000000 * lpphy->pdiv)) - 1) & 0xFF; b43_radio_write(dev, B2062_S_RFPLL_CTL18, tmp); - tmp = (2 * crystalfreq + 1000000 * lpphy->pdiv) / - (2000000 * lpphy->pdiv); - tmp = ((tmp & 0xFF) - 1) & 0xFFFF; + tmp = (((2 * crystalfreq + 1000000 * lpphy->pdiv) / + (2000000 * lpphy->pdiv)) - 1) & 0xFF; b43_radio_write(dev, B2062_S_RFPLL_CTL19, tmp); ref = (1000 * lpphy->pdiv + 2 * crystalfreq) / (2000 * lpphy->pdiv); @@ -671,7 +673,7 @@ static void lpphy_radio_init(struct b43_wldev *dev) b43_phy_mask(dev, B43_LPPHY_FOURWIRE_CTL, 0xFFFD); udelay(1); - if (dev->phy.rev < 2) { + if (dev->phy.radio_ver == 0x2062) { lpphy_2062_init(dev); } else { lpphy_2063_init(dev); @@ -688,11 +690,18 @@ struct lpphy_iq_est { u32 iq_prod, i_pwr, q_pwr; }; static void lpphy_set_rc_cap(struct b43_wldev *dev) { - u8 rc_cap = dev->phy.lp->rc_cap; + struct b43_phy_lp *lpphy = dev->phy.lp; + + u8 rc_cap = (lpphy->rc_cap & 0x1F) >> 1; - b43_radio_write(dev, B2062_N_RXBB_CALIB2, max_t(u8, rc_cap-4, 0x80)); - b43_radio_write(dev, B2062_N_TX_CTL_A, ((rc_cap & 0x1F) >> 1) | 0x80); - b43_radio_write(dev, B2062_S_RXG_CNT16, ((rc_cap & 0x1F) >> 2) | 0x80); + if (dev->phy.rev == 1) //FIXME check channel 14! + rc_cap = max_t(u8, rc_cap + 5, 15); + + b43_radio_write(dev, B2062_N_RXBB_CALIB2, + max_t(u8, lpphy->rc_cap - 4, 0x80)); + b43_radio_write(dev, B2062_N_TX_CTL_A, rc_cap | 0x80); + b43_radio_write(dev, B2062_S_RXG_CNT16, + ((lpphy->rc_cap & 0x1F) >> 2) | 0x80); } static u8 lpphy_get_bb_mult(struct b43_wldev *dev) @@ -1101,6 +1110,9 @@ static void lpphy_set_tx_power_control(struct b43_wldev *dev, lpphy_write_tx_pctl_mode_to_hardware(dev); } +static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, + unsigned int new_channel); + static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) { struct b43_phy_lp *lpphy = dev->phy.lp; @@ -1118,11 +1130,16 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) old_rf2_ovr, old_rf2_ovrval, old_phy_ctl; enum b43_lpphy_txpctl_mode old_txpctl; u32 normal_pwr, ideal_pwr, mean_sq_pwr, tmp = 0, mean_sq_pwr_min = 0; - int loopback, i, j, inner_sum; + int loopback, i, j, inner_sum, err; memset(&iq_est, 0, sizeof(iq_est)); - b43_switch_channel(dev, 7); + err = b43_lpphy_op_switch_channel(dev, 7); + if (err) { + b43dbg(dev->wl, + "RC calib: Failed to switch to channel 7, error = %d", + err); + } old_txg_ovr = (b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) >> 6) & 1; old_bbmult = lpphy_get_bb_mult(dev); if (old_txg_ovr) @@ -1881,14 +1898,14 @@ static int lpphy_b2062_tune(struct b43_wldev *dev, { struct b43_phy_lp *lpphy = dev->phy.lp; struct ssb_bus *bus = dev->dev->bus; - static const struct b206x_channel *chandata = NULL; + const struct b206x_channel *chandata = NULL; u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000; u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9; int i, err = 0; - for (i = 0; i < ARRAY_SIZE(b2063_chantbl); i++) { - if (b2063_chantbl[i].channel == channel) { - chandata = &b2063_chantbl[i]; + for (i = 0; i < ARRAY_SIZE(b2062_chantbl); i++) { + if (b2062_chantbl[i].channel == channel) { + chandata = &b2062_chantbl[i]; break; } } -- cgit v1.2.3-18-g5258 From ed07c4b3af341bad3fa29558f08b166220014ca7 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Sun, 16 Aug 2009 18:40:09 +0200 Subject: b43: LP-PHY: Fix a bug in the B2062 channel tune path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I missed the "+16" part of the instruction in the specs. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 4d14102821c..4553e407395 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1950,7 +1950,7 @@ static int lpphy_b2062_tune(struct b43_wldev *dev, b43_radio_write(dev, B2062_S_RFPLL_CTL29, tmp6 + ((2 * tmp7) / tmp4)); tmp8 = b43_phy_read(dev, B2062_S_RFPLL_CTL19); tmp9 = ((2 * tmp3 * (tmp8 + 1)) + (3 * tmp1)) / (6 * tmp1); - b43_radio_write(dev, B2062_S_RFPLL_CTL23, tmp9 >> 8); + b43_radio_write(dev, B2062_S_RFPLL_CTL23, (tmp9 >> 8) + 16); b43_radio_write(dev, B2062_S_RFPLL_CTL24, tmp9 & 0xFF); lpphy_b2062_vco_calib(dev); -- cgit v1.2.3-18-g5258 From 7e4d8529921004014bef21a2031b6c3478339a2a Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Sun, 16 Aug 2009 20:08:13 +0200 Subject: b43: LP-PHY: Update B2062 radio init with recent spec changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The spec for initializing the B2062 radio have changed recently, update the code to match the changes. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 4553e407395..faca56f908e 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -537,10 +537,15 @@ static void lpphy_2062_init(struct b43_wldev *dev) b43_radio_write(dev, B2062_N_TX_CTL3, 0); b43_radio_write(dev, B2062_N_TX_CTL4, 0); b43_radio_write(dev, B2062_N_TX_CTL5, 0); + b43_radio_write(dev, B2062_N_TX_CTL6, 0); b43_radio_write(dev, B2062_N_PDN_CTL0, 0x40); b43_radio_write(dev, B2062_N_PDN_CTL0, 0); b43_radio_write(dev, B2062_N_CALIB_TS, 0x10); b43_radio_write(dev, B2062_N_CALIB_TS, 0); + if (dev->phy.rev > 0) { + b43_radio_write(dev, B2062_S_BG_CTL1, + (b43_radio_read(dev, B2062_N_COMM2) >> 1) | 0x80); + } if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) b43_radio_set(dev, B2062_N_TSSI_CTL0, 0x1); else -- cgit v1.2.3-18-g5258 From 86b2892a22a433e56e39e33bf353adc6cc4eabb2 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Sun, 16 Aug 2009 20:22:41 +0200 Subject: b43: LP-PHY: Remove BROKEN from B43_PHY_LP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Larry has reported success getting scan data with an LP-PHY device, so it's probably time to release LP-PHY support for testing. Also disable 802.11a support for now, as 802.11a currently causes the driver to panic on startup (NULL pointer dereference). Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/Kconfig | 14 +++++++------- drivers/net/wireless/b43/main.c | 2 ++ 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 67f564e3722..237b1aadf9b 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -80,16 +80,16 @@ config B43_NPHY SAY N. config B43_PHY_LP - bool "IEEE 802.11g LP-PHY support (BROKEN)" - depends on B43 && EXPERIMENTAL && BROKEN + bool "Support for low-power (LP-PHY) devices (EXPERIMENTAL)" + depends on B43 && EXPERIMENTAL ---help--- Support for the LP-PHY. - The LP-PHY is an IEEE 802.11g based PHY built into some notebooks - and embedded devices. - - THIS IS BROKEN AND DOES NOT WORK YET. + The LP-PHY is a low-power PHY built into some notebooks + and embedded devices. It supports 802.11a/g + (802.11a support is optional, and currently disabled). - SAY N. + This is heavily experimental, and probably will not work for you. + Say N unless you want to help debug the driver. # This config option automatically enables b43 LEDS support, # if it's possible. diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 99b41ce6848..c5bece09042 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4514,7 +4514,9 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) have_5ghz_phy = 1; break; case B43_PHYTYPE_LP: //FIXME not always! +#if 0 //FIXME enabling 5GHz causes a NULL pointer dereference have_5ghz_phy = 1; +#endif case B43_PHYTYPE_G: case B43_PHYTYPE_N: have_2ghz_phy = 1; -- cgit v1.2.3-18-g5258 From 3ac64beecd27400d12cc7afb4108eef26c499f6a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Aug 2009 16:16:53 +0200 Subject: mac80211: allow configure_filter callback to sleep Over time, a whole bunch of drivers have come up with their own scheme to delay the configure_filter operation to a workqueue. To be able to simplify things, allow configure_filter to sleep, and add a new prepare_multicast callback that drivers that need the multicast address list implement. This new callback must be atomic, but most drivers either don't care or just calculate a hash which can be done atomically and then uploaded to the hardware non-atomically. A cursory look suggests that at76c50x-usb, ar9170, mwl8k (which is actually very broken now), rt2x00, wl1251, wl1271 and zd1211 should make use of this new capability. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 42 +++++++++++++------- drivers/net/wireless/at76c50x-usb.c | 7 ++-- drivers/net/wireless/ath/ar9170/main.c | 43 +++++++++++--------- drivers/net/wireless/ath/ath5k/base.c | 64 ++++++++++++++++++------------ drivers/net/wireless/ath/ath9k/main.c | 3 +- drivers/net/wireless/b43/main.c | 2 +- drivers/net/wireless/b43legacy/main.c | 4 +- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.h | 3 +- drivers/net/wireless/libertas_tf/main.c | 37 +++++++++++------ drivers/net/wireless/mac80211_hwsim.c | 4 +- drivers/net/wireless/mwl8k.c | 34 ++++++++++++---- drivers/net/wireless/p54/main.c | 2 +- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 2 +- drivers/net/wireless/rtl818x/rtl8180_dev.c | 11 ++++- drivers/net/wireless/rtl818x/rtl8187_dev.c | 11 ++++- drivers/net/wireless/wl12xx/wl1251_main.c | 4 +- drivers/net/wireless/wl12xx/wl1271_main.c | 4 +- drivers/net/wireless/zd1211rw/zd_mac.c | 44 +++++++++++++------- 20 files changed, 205 insertions(+), 120 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 5695911bc60..b80f514877d 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1328,16 +1328,39 @@ static void adm8211_bss_info_changed(struct ieee80211_hw *dev, } } +static u64 adm8211_prepare_multicast(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mclist) +{ + unsigned int bit_nr, i; + u32 mc_filter[2]; + + mc_filter[1] = mc_filter[0] = 0; + + for (i = 0; i < mc_count; i++) { + if (!mclist) + break; + bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; + + bit_nr &= 0x3F; + mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); + mclist = mclist->next; + } + + return mc_filter[0] | ((u64)(mc_filter[1]) << 32); +} + static void adm8211_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_mc_list *mclist) + u64 multicast) { static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; struct adm8211_priv *priv = dev->priv; - unsigned int bit_nr, new_flags; + unsigned int new_flags; u32 mc_filter[2]; - int i; + + mc_filter[0] = multicast; + mc_filter[1] = multicast >> 32; new_flags = 0; @@ -1346,23 +1369,13 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev, priv->nar |= ADM8211_NAR_PR; priv->nar &= ~ADM8211_NAR_MM; mc_filter[1] = mc_filter[0] = ~0; - } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) { + } else if (*total_flags & FIF_ALLMULTI || multicast == ~(0ULL)) { new_flags |= FIF_ALLMULTI; priv->nar &= ~ADM8211_NAR_PR; priv->nar |= ADM8211_NAR_MM; mc_filter[1] = mc_filter[0] = ~0; } else { priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR); - mc_filter[1] = mc_filter[0] = 0; - for (i = 0; i < mc_count; i++) { - if (!mclist) - break; - bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; - - bit_nr &= 0x3F; - mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); - mclist = mclist->next; - } } ADM8211_IDLE_RX(); @@ -1757,6 +1770,7 @@ static const struct ieee80211_ops adm8211_ops = { .remove_interface = adm8211_remove_interface, .config = adm8211_config, .bss_info_changed = adm8211_bss_info_changed, + .prepare_multicast = adm8211_prepare_multicast, .configure_filter = adm8211_configure_filter, .get_stats = adm8211_get_stats, .get_tx_stats = adm8211_get_tx_stats, diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 7218dbabad3..a6e19545ac6 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1997,15 +1997,14 @@ static void at76_bss_info_changed(struct ieee80211_hw *hw, /* must be atomic */ static void at76_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, - unsigned int *total_flags, int mc_count, - struct dev_addr_list *mc_list) + unsigned int *total_flags, u64 multicast) { struct at76_priv *priv = hw->priv; int flags; at76_dbg(DBG_MAC80211, "%s(): changed_flags=0x%08x " - "total_flags=0x%08x mc_count=%d", - __func__, changed_flags, *total_flags, mc_count); + "total_flags=0x%08x", + __func__, changed_flags, *total_flags); flags = changed_flags & AT76_SUPPORTED_FILTERS; *total_flags = AT76_SUPPORTED_FILTERS; diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index ea8c9419336..6a9462e4fd8 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -2100,10 +2100,29 @@ unlock: mutex_unlock(&ar->mutex); } +static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, + struct dev_addr_list *mclist) +{ + u64 mchash; + int i; + + /* always get broadcast frames */ + mchash = 1ULL << (0xff >> 2); + + for (i = 0; i < mc_count; i++) { + if (WARN_ON(!mclist)) + break; + mchash |= 1ULL << (mclist->dmi_addr[5] >> 2); + mclist = mclist->next; + } + + return mchash; +} + static void ar9170_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, - int mc_count, struct dev_mc_list *mclist) + u64 multicast) { struct ar9170 *ar = hw->priv; @@ -2116,24 +2135,11 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, * then checking the error flags, later. */ - if (changed_flags & FIF_ALLMULTI) { - if (*new_flags & FIF_ALLMULTI) { - ar->want_mc_hash = ~0ULL; - } else { - u64 mchash; - int i; - - /* always get broadcast frames */ - mchash = 1ULL << (0xff >> 2); + if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI) + multicast = ~0ULL; - for (i = 0; i < mc_count; i++) { - if (WARN_ON(!mclist)) - break; - mchash |= 1ULL << (mclist->dmi_addr[5] >> 2); - mclist = mclist->next; - } - ar->want_mc_hash = mchash; - } + if (multicast != ar->want_mc_hash) { + ar->want_mc_hash = multicast; set_bit(AR9170_FILTER_CHANGED_MULTICAST, &ar->filter_changed); } @@ -2543,6 +2549,7 @@ static const struct ieee80211_ops ar9170_ops = { .add_interface = ar9170_op_add_interface, .remove_interface = ar9170_op_remove_interface, .config = ar9170_op_config, + .prepare_multicast = ar9170_op_prepare_multicast, .configure_filter = ar9170_op_configure_filter, .conf_tx = ar9170_conf_tx, .bss_info_changed = ar9170_op_bss_info_changed, diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 2b3cf39dd4b..3951b5b1342 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -229,10 +229,12 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, static void ath5k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); static int ath5k_config(struct ieee80211_hw *hw, u32 changed); +static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mc_list); static void ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, - int mc_count, struct dev_mc_list *mclist); + u64 multicast); static int ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -260,6 +262,7 @@ static const struct ieee80211_ops ath5k_hw_ops = { .add_interface = ath5k_add_interface, .remove_interface = ath5k_remove_interface, .config = ath5k_config, + .prepare_multicast = ath5k_prepare_multicast, .configure_filter = ath5k_configure_filter, .set_key = ath5k_set_key, .get_stats = ath5k_get_stats, @@ -2853,6 +2856,37 @@ unlock: return ret; } +static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mclist) +{ + u32 mfilt[2], val; + int i; + u8 pos; + + mfilt[0] = 0; + mfilt[1] = 1; + + for (i = 0; i < mc_count; i++) { + if (!mclist) + break; + /* calculate XOR of eight 6-bit values */ + val = get_unaligned_le32(mclist->dmi_addr + 0); + pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; + val = get_unaligned_le32(mclist->dmi_addr + 3); + pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; + pos &= 0x3f; + mfilt[pos / 32] |= (1 << (pos % 32)); + /* XXX: we might be able to just do this instead, + * but not sure, needs testing, if we do use this we'd + * neet to inform below to not reset the mcast */ + /* ath5k_hw_set_mcast_filterindex(ah, + * mclist->dmi_addr[5]); */ + mclist = mclist->next; + } + + return ((u64)(mfilt[1]) << 32) | mfilt[0]; +} + #define SUPPORTED_FIF_FLAGS \ FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \ FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \ @@ -2878,16 +2912,14 @@ unlock: static void ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, - int mc_count, struct dev_mc_list *mclist) + u64 multicast) { struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; - u32 mfilt[2], val, rfilt; - u8 pos; - int i; + u32 mfilt[2], rfilt; - mfilt[0] = 0; - mfilt[1] = 0; + mfilt[0] = multicast; + mfilt[1] = multicast >> 32; /* Only deal with supported flags */ changed_flags &= SUPPORTED_FIF_FLAGS; @@ -2913,24 +2945,6 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, if (*new_flags & FIF_ALLMULTI) { mfilt[0] = ~0; mfilt[1] = ~0; - } else { - for (i = 0; i < mc_count; i++) { - if (!mclist) - break; - /* calculate XOR of eight 6-bit values */ - val = get_unaligned_le32(mclist->dmi_addr + 0); - pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; - val = get_unaligned_le32(mclist->dmi_addr + 3); - pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; - pos &= 0x3f; - mfilt[pos / 32] |= (1 << (pos % 32)); - /* XXX: we might be able to just do this instead, - * but not sure, needs testing, if we do use this we'd - * neet to inform below to not reset the mcast */ - /* ath5k_hw_set_mcast_filterindex(ah, - * mclist->dmi_addr[5]); */ - mclist = mclist->next; - } } /* This is the best we can do */ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3e09b9ac165..2f9c149fd48 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2394,8 +2394,7 @@ skip_chan_change: static void ath9k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, - struct dev_mc_list *mclist) + u64 multicast) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index c5bece09042..78ddbc7f836 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3679,7 +3679,7 @@ out_unlock: static void b43_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, unsigned int *fflags, - int mc_count, struct dev_addr_list *mc_list) + u64 multicast) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index b1435594921..b166a6f9f05 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2836,9 +2836,7 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, static void b43legacy_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, - unsigned int *fflags, - int mc_count, - struct dev_addr_list *mc_list) + unsigned int *fflags,u64 multicast) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c0efa6623c0..f1f6dabd8fb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1514,7 +1514,7 @@ EXPORT_SYMBOL(iwl_irq_handle_error); void iwl_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_addr_list *mc_list) + u64 multicast) { struct iwl_priv *priv = hw->priv; __le32 *filter_flags = &priv->staging_rxon.filter_flags; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 4ca025a34da..62d90364b61 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -282,8 +282,7 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv, void iwl_irq_handle_error(struct iwl_priv *priv); void iwl_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, struct dev_addr_list *mc_list); + unsigned int *total_flags, u64 multicast); int iwl_hw_nic_init(struct iwl_priv *priv); int iwl_setup_mac(struct iwl_priv *priv); int iwl_set_hw_params(struct iwl_priv *priv); diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index 4872345a2f6..019431d2f8a 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -366,15 +366,35 @@ static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed) return 0; } +static u64 lbtf_op_prepare_multicast(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mclist) +{ + struct lbtf_private *priv = hw->priv; + int i; + + if (!mc_count || mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE) + return mc_count; + + priv->nr_of_multicastmacaddr = mc_count; + for (i = 0; i < mc_count; i++) { + if (!mclist) + break; + memcpy(&priv->multicastlist[i], mclist->da_addr, + ETH_ALEN); + mclist = mclist->next; + } + + return mc_count; +} + #define SUPPORTED_FIF_FLAGS (FIF_PROMISC_IN_BSS | FIF_ALLMULTI) static void lbtf_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, - int mc_count, struct dev_mc_list *mclist) + u64 multicast) { struct lbtf_private *priv = hw->priv; int old_mac_control = priv->mac_control; - int i; changed_flags &= SUPPORTED_FIF_FLAGS; *new_flags &= SUPPORTED_FIF_FLAGS; @@ -386,20 +406,12 @@ static void lbtf_op_configure_filter(struct ieee80211_hw *hw, else priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE; if (*new_flags & (FIF_ALLMULTI) || - mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE) { + multicast > MRVDRV_MAX_MULTICAST_LIST_SIZE) { priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE; priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE; - } else if (mc_count) { + } else if (multicast) { priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE; priv->mac_control &= ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE; - priv->nr_of_multicastmacaddr = mc_count; - for (i = 0; i < mc_count; i++) { - if (!mclist) - break; - memcpy(&priv->multicastlist[i], mclist->da_addr, - ETH_ALEN); - mclist = mclist->next; - } lbtf_cmd_set_mac_multicast_addr(priv); } else { priv->mac_control &= ~(CMD_ACT_MAC_MULTICAST_ENABLE | @@ -461,6 +473,7 @@ static const struct ieee80211_ops lbtf_ops = { .add_interface = lbtf_op_add_interface, .remove_interface = lbtf_op_remove_interface, .config = lbtf_op_config, + .prepare_multicast = lbtf_op_prepare_multicast, .configure_filter = lbtf_op_configure_filter, .bss_info_changed = lbtf_op_bss_info_changed, }; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 930f5c7da4a..6f6cd43592c 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -582,9 +582,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, - struct dev_addr_list *mc_list) + unsigned int *total_flags,u64 multicast) { struct mac80211_hwsim_data *data = hw->priv; diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 8a6d3afe412..f84387083e7 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3251,31 +3251,50 @@ mwl8k_configure_filter_exit: return rc; } +static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mclist) +{ + struct mwl8k_configure_filter_worker *worker; + + worker = kzalloc(sizeof(*worker), GFP_ATOMIC); + + if (!worker) + return 0; + + /* + * XXX: This is _HORRIBLY_ broken!! + * + * No locking, the mclist pointer might be invalid as soon as this + * function returns, something in the list might be invalidated + * once we get to the worker, etc... + */ + worker->mc_count = mc_count; + worker->mclist = mclist; + + return (u64)worker; +} + static void mwl8k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, - struct dev_addr_list *mclist) + u64 multicast) { - struct mwl8k_configure_filter_worker *worker; + struct mwl8k_configure_filter_worker *worker = (void *)multicast; struct mwl8k_priv *priv = hw->priv; /* Clear unsupported feature flags */ *total_flags &= MWL8K_SUPPORTED_IF_FLAGS; - if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS) && !mc_count) + if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS)) return; - worker = kzalloc(sizeof(*worker), GFP_ATOMIC); if (worker == NULL) return; worker->header.options = MWL8K_WQ_QUEUE_ONLY | MWL8K_WQ_TX_WAIT_EMPTY; worker->changed_flags = changed_flags; worker->total_flags = total_flags; - worker->mc_count = mc_count; - worker->mclist = mclist; mwl8k_queue_work(hw, &worker->header, priv->config_wq, mwl8k_configure_filter_wt); @@ -3441,6 +3460,7 @@ static const struct ieee80211_ops mwl8k_ops = { .remove_interface = mwl8k_remove_interface, .config = mwl8k_config, .bss_info_changed = mwl8k_bss_info_changed, + .prepare_multicast = mwl8k_prepare_multicast, .configure_filter = mwl8k_configure_filter, .set_rts_threshold = mwl8k_set_rts_threshold, .conf_tx = mwl8k_conf_tx, diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 77203e346cd..4d486bf9f72 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -302,7 +302,7 @@ out: static void p54_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_mc_list *mclist) + u64 multicast) { struct p54_common *priv = dev->priv; diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 99e89596cef..39d7d9baafd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -978,7 +978,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed); void rt2x00mac_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_addr_list *mc_list); + u64 multicast); int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set); #ifdef CONFIG_RT2X00_LIB_CRYPTO diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index cb7b6d45933..602f1269971 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -379,7 +379,7 @@ EXPORT_SYMBOL_GPL(rt2x00mac_config); void rt2x00mac_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_addr_list *mc_list) + u64 multicast) { struct rt2x00_dev *rt2x00dev = hw->priv; diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index 09f46abc730..16429c49139 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -728,10 +728,16 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev, priv->rf->conf_erp(dev, info); } +static u64 rtl8180_prepare_multicast(struct ieee80211_hw *dev, int mc_count, + struct dev_addr_list *mc_list) +{ + return mc_count; +} + static void rtl8180_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_addr_list *mclist) + u64 multicast) { struct rtl8180_priv *priv = dev->priv; @@ -741,7 +747,7 @@ static void rtl8180_configure_filter(struct ieee80211_hw *dev, priv->rx_conf ^= RTL818X_RX_CONF_CTRL; if (changed_flags & FIF_OTHER_BSS) priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; - if (*total_flags & FIF_ALLMULTI || mc_count > 0) + if (*total_flags & FIF_ALLMULTI || multicast > 0) priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; else priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST; @@ -768,6 +774,7 @@ static const struct ieee80211_ops rtl8180_ops = { .remove_interface = rtl8180_remove_interface, .config = rtl8180_config, .bss_info_changed = rtl8180_bss_info_changed, + .prepare_multicast = rtl8180_prepare_multicast, .configure_filter = rtl8180_configure_filter, }; diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 53f57dc5222..90f38357393 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -1192,10 +1192,16 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, info->use_short_preamble); } +static u64 rtl8187_prepare_multicast(struct ieee80211_hw *dev, + int mc_count, struct dev_addr_list *mc_list) +{ + return mc_count; +} + static void rtl8187_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_addr_list *mclist) + u64 multicast) { struct rtl8187_priv *priv = dev->priv; @@ -1205,7 +1211,7 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev, priv->rx_conf ^= RTL818X_RX_CONF_CTRL; if (changed_flags & FIF_OTHER_BSS) priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; - if (*total_flags & FIF_ALLMULTI || mc_count > 0) + if (*total_flags & FIF_ALLMULTI || multicast > 0) priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; else priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST; @@ -1268,6 +1274,7 @@ static const struct ieee80211_ops rtl8187_ops = { .remove_interface = rtl8187_remove_interface, .config = rtl8187_config, .bss_info_changed = rtl8187_bss_info_changed, + .prepare_multicast = rtl8187_prepare_multicast, .configure_filter = rtl8187_configure_filter, .conf_tx = rtl8187_conf_tx }; diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 7148934e464..5809ef5b18f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -652,9 +652,7 @@ out: static void wl1251_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, - unsigned int *total, - int mc_count, - struct dev_addr_list *mc_list) + unsigned int *total,u64 multicast) { struct wl1251 *wl = hw->priv; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 4102d590b79..754be817930 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -793,9 +793,7 @@ out: static void wl1271_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, - unsigned int *total, - int mc_count, - struct dev_addr_list *mc_list) + unsigned int *total,u64 multicast) { struct wl1271 *wl = hw->priv; diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 55b7fbdc85d..6d666359a42 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -796,18 +796,40 @@ static void set_rx_filter_handler(struct work_struct *work) dev_err(zd_mac_dev(mac), "set_rx_filter_handler error %d\n", r); } +static u64 zd_op_prepare_multicast(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mclist) +{ + struct zd_mac *mac = zd_hw_mac(hw); + struct zd_mc_hash hash; + int i; + + zd_mc_clear(&hash); + + for (i = 0; i < mc_count; i++) { + if (!mclist) + break; + dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n", mclist->dmi_addr); + zd_mc_add_addr(&hash, mclist->dmi_addr); + mclist = mclist->next; + } + + return hash.low | ((u64)hash.high << 32); +} + #define SUPPORTED_FIF_FLAGS \ (FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \ FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC) static void zd_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, - int mc_count, struct dev_mc_list *mclist) + u64 multicast) { - struct zd_mc_hash hash; + struct zd_mc_hash hash = { + .low = multicast, + .high = multicast >> 32, + }; struct zd_mac *mac = zd_hw_mac(hw); unsigned long flags; - int i; /* Only deal with supported flags */ changed_flags &= SUPPORTED_FIF_FLAGS; @@ -819,25 +841,16 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw, if (!changed_flags) return; - if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) { + if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) zd_mc_add_all(&hash); - } else { - zd_mc_clear(&hash); - for (i = 0; i < mc_count; i++) { - if (!mclist) - break; - dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n", - mclist->dmi_addr); - zd_mc_add_addr(&hash, mclist->dmi_addr); - mclist = mclist->next; - } - } spin_lock_irqsave(&mac->lock, flags); mac->pass_failed_fcs = !!(*new_flags & FIF_FCSFAIL); mac->pass_ctrl = !!(*new_flags & FIF_CONTROL); mac->multicast_hash = hash; spin_unlock_irqrestore(&mac->lock, flags); + + /* XXX: these can be called here now, can sleep now! */ queue_work(zd_workqueue, &mac->set_multicast_hash_work); if (changed_flags & FIF_CONTROL) @@ -940,6 +953,7 @@ static const struct ieee80211_ops zd_ops = { .add_interface = zd_op_add_interface, .remove_interface = zd_op_remove_interface, .config = zd_op_config, + .prepare_multicast = zd_op_prepare_multicast, .configure_filter = zd_op_configure_filter, .bss_info_changed = zd_op_bss_info_changed, .get_tsf = zd_op_get_tsf, -- cgit v1.2.3-18-g5258 From f424afa17899408cbd267a4c4534ca6fc9d8f71c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Aug 2009 16:18:07 +0200 Subject: mac80211: remove deprecated API All but two drivers have now stopped using the two deprecated members radio_enabled and beacon_int, so it's about time to remove them for good. Signed-off-by: Johannes Berg Acked-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/at76c50x-usb.c | 5 ++--- drivers/net/wireless/mwl8k.c | 7 ------- 2 files changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index a6e19545ac6..8e1a55dec35 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1950,9 +1950,8 @@ static int at76_config(struct ieee80211_hw *hw, u32 changed) { struct at76_priv *priv = hw->priv; - at76_dbg(DBG_MAC80211, "%s(): channel %d radio %d", - __func__, hw->conf.channel->hw_value, - hw->conf.radio_enabled); + at76_dbg(DBG_MAC80211, "%s(): channel %d", + __func__, hw->conf.channel->hw_value); at76_dbg_dump(DBG_MAC80211, priv->bssid, ETH_ALEN, "bssid:"); mutex_lock(&priv->mtx); diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index f84387083e7..c32e93c8c41 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3031,13 +3031,6 @@ static int mwl8k_config_wt(struct work_struct *wt) struct mwl8k_priv *priv = hw->priv; int rc = 0; - if (!conf->radio_enabled) { - mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_DISABLE); - priv->current_channel = NULL; - rc = 0; - goto mwl8k_config_exit; - } - if (mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_ENABLE)) { rc = -EINVAL; goto mwl8k_config_exit; -- cgit v1.2.3-18-g5258 From 1de6f73c34fb9a74454a5b519cefd635b5e8ceb6 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 17 Aug 2009 11:18:14 -0400 Subject: wl1251: correct definitions for 0th bit defines ACX_SLV_SOFT_RESET_BIT and ACX_REG_EEPROM_START_BIT are both defined as "1" in the vendor driver code, but they were defined to be BIT(1) ("2") here. The SOFT_RESET typo ensures that wl1251_boot_soft_reset() doesn't; as a result the device hangs when trying to reprogram the PLL registers while running. Signed-off-by: Bob Copeland Acked-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_reg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_reg.h b/drivers/net/wireless/wl12xx/wl1251_reg.h index bdd561001dc..06e1bd94a73 100644 --- a/drivers/net/wireless/wl12xx/wl1251_reg.h +++ b/drivers/net/wireless/wl12xx/wl1251_reg.h @@ -245,8 +245,8 @@ enum wl12xx_acx_int_reg { ACX_REG_TABLE_LEN }; -#define ACX_SLV_SOFT_RESET_BIT BIT(1) -#define ACX_REG_EEPROM_START_BIT BIT(1) +#define ACX_SLV_SOFT_RESET_BIT BIT(0) +#define ACX_REG_EEPROM_START_BIT BIT(0) /* Command/Information Mailbox Pointers */ -- cgit v1.2.3-18-g5258 From 12d4bba0fd7ac50ca20d9ac1247a0de851850bb0 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Fri, 14 Aug 2009 20:29:47 +0200 Subject: b43: LP-PHY: Fix reading old mode in the set TX power control routine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check the mode the hardware is in, not the mode we used the last time. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index faca56f908e..ca52fd5f38c 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1085,9 +1085,9 @@ static void lpphy_set_tx_power_control(struct b43_wldev *dev, struct b43_phy_lp *lpphy = dev->phy.lp; enum b43_lpphy_txpctl_mode oldmode; - oldmode = lpphy->txpctl_mode; lpphy_read_tx_pctl_mode_from_hardware(dev); - if (lpphy->txpctl_mode == mode) + oldmode = lpphy->txpctl_mode; + if (oldmode == mode) return; lpphy->txpctl_mode = mode; -- cgit v1.2.3-18-g5258 From 5f1c07d924d3e670044911487aca057bb39b4e7e Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Fri, 14 Aug 2009 21:19:58 +0200 Subject: b43: LP-PHY: Fix setting TX power control mode during RC calibration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Call set_tx_power_control with a LPPHY_TXPCTL rather than an LPPHY_TX_PWR_CTL_CMD_MODE. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index ca52fd5f38c..94023838568 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1159,7 +1159,7 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) lpphy_read_tx_pctl_mode_from_hardware(dev); old_txpctl = lpphy->txpctl_mode; - lpphy_set_tx_power_control(dev, B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF); + lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF); lpphy_disable_crs(dev); loopback = lpphy_loopback(dev); if (loopback == -1) -- cgit v1.2.3-18-g5258 From 73077c85458739169cdaf893a375b8bb3939d35a Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 17 Aug 2009 18:53:24 +0200 Subject: rt2x00: Fix RFKILL polling The rfkill_poll callback function in the drivers check a bit to see if the RFKILL key has been pressed. However when the bit is set it means the radio is active and the device can be used. The wiphy_rfkill_set_hw_state() function expects the inversed, so '1' must be send when the radio must be disabled. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 602f1269971..3011aea4fea 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -704,8 +704,8 @@ EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx); void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; - bool blocked = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev); + bool active = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev); - wiphy_rfkill_set_hw_state(hw->wiphy, blocked); + wiphy_rfkill_set_hw_state(hw->wiphy, !active); } EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll); -- cgit v1.2.3-18-g5258 From 1738c9e42a9bb3705a3b03dde854f3db269e7bdd Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 17 Aug 2009 18:53:57 +0200 Subject: rt2x00: Fix for rt2800usb for SHARED_KEY_TABLE initializations Fixed comments about SHARED_KEY_TABLE_BASE and SHARED_KEY_MODE_BASE. Fixed initialization loop for SHARED_KEY_MODE_ENTRY. Based on a patch for rt2800pci from Benoit. Signed-off-by: Benoit PAPILLAULT Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 8 ++++---- drivers/net/wireless/rt2x00/rt2800usb.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 3856f06fdca..c82474ebba3 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1463,6 +1463,10 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) /* * ASIC will keep garbage value after boot, clear encryption keys. */ + for (i = 0; i < 4; i++) + rt2x00usb_register_write(rt2x00dev, + SHARED_KEY_MODE_ENTRY(i), 0); + for (i = 0; i < 256; i++) { u32 wcid[2] = { 0xffffffff, 0x00ffffff }; rt2x00usb_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i), @@ -1472,10 +1476,6 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00usb_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0); } - for (i = 0; i < 16; i++) - rt2x00usb_register_write(rt2x00dev, - SHARED_KEY_MODE_ENTRY(i), 0); - /* * Clear all beacons * For the Beacon base registers we only need to clear diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 2d9dc378336..a79a6d90eea 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -1300,8 +1300,8 @@ * PAIRWISE_KEY_TABLE_BASE: 32-byte * 256 entry * MAC_IVEIV_TABLE_BASE: 8-byte * 256-entry * MAC_WCID_ATTRIBUTE_BASE: 4-byte * 256-entry - * SHARED_KEY_TABLE_BASE: 32-byte * 16-entry - * SHARED_KEY_MODE_BASE: 4-byte * 16-entry + * SHARED_KEY_TABLE_BASE: 32 bytes * 32-entry + * SHARED_KEY_MODE_BASE: 4 bits * 32-entry */ #define MAC_WCID_BASE 0x1800 #define PAIRWISE_KEY_TABLE_BASE 0x4000 -- cgit v1.2.3-18-g5258 From 05a32730f16e7b91e9fd2d11f26db152e5c9a68d Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 17 Aug 2009 18:54:47 +0200 Subject: rt2x00: Add new RF chip defines Add new defines for RF chipsets which can be found by the driver. We don't have to check for these chips specifically yet, but it is better to have the defines in now. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index a79a6d90eea..4d9991c9a51 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -36,6 +36,9 @@ * RF2750 2.4G/5G 1T2R * RF3020 2.4G 1T1R * RF2020 2.4G B/G + * RF3021 2.4G 1T2R + * RF3022 2.4G 2T2R + * RF3052 2.4G 2T2R */ #define RF2820 0x0001 #define RF2850 0x0002 @@ -43,6 +46,9 @@ #define RF2750 0x0004 #define RF3020 0x0005 #define RF2020 0x0006 +#define RF3021 0x0007 +#define RF3022 0x0008 +#define RF3052 0x0009 /* * RT2870 version -- cgit v1.2.3-18-g5258 From 0fefe0fda4376eff97be965a41714da38fe4a36d Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 17 Aug 2009 18:54:50 +0200 Subject: rt2x00: Set SKBDESC_L2_PADDED in RX path When the RX descriptor indicates the frame was L2 padded, the SKBDESC_L2_PADDED flag should be set to make sure the L2 padding is removed before it is send to mac80211. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index c82474ebba3..6de2edab51e 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -2163,8 +2163,10 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(rxd0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; - if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD)) + if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD)) { rxdesc->dev_flags |= RXDONE_L2PAD; + skbdesc->flags |= SKBDESC_L2_PADDED; + } if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI)) rxdesc->flags |= RX_FLAG_SHORT_GI; -- cgit v1.2.3-18-g5258 From 534aff0288f49a2366b7e6fbb67ff035dea814d3 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 17 Aug 2009 18:55:15 +0200 Subject: rt2x00: wireless CLI ID and packet ID must not be 0 In the TX descriptor the Packet ID must not be 0, so add 1 to the ID. The wireless CLI ID is not allowed to be 0 either, but also must be initialized with the wcid value rather then keyid. Based on a patch for rt2800pci from Benoit Signed-off-by: Benoit PAPILLAULT Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 6de2edab51e..3633e5878ee 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1995,11 +1995,11 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size); rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID, test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ? - txdesc->key_idx : 0xff); + (skbdesc->entry->entry_idx + 1) : 0xff); rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT, skb->len - txdesc->l2pad); rt2x00_set_field32(&word, TXWI_W1_PACKETID, - skbdesc->entry->entry_idx); + skbdesc->entry->queue->qid + 1); rt2x00_desc_write(txwi, 1, word); /* -- cgit v1.2.3-18-g5258 From cd80b684a08655e7dcc7a1c96d4b7e7ffa753017 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 17 Aug 2009 18:55:40 +0200 Subject: rt2x00: Fix MCS register intialization According to the original Ralink driver, LG_FBK_CFG0_OFDMMCS2FBK should be initialized to 9 rather then 3. Based on a patch for rt2800pci from Benoit Signed-off-by: Benoit PAPILLAULT Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 3633e5878ee..45e02f16d75 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1520,7 +1520,7 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00usb_register_read(rt2x00dev, LG_FBK_CFG0, ®); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS0FBK, 8); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS1FBK, 8); - rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS2FBK, 3); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS2FBK, 9); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS3FBK, 10); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS4FBK, 11); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS5FBK, 12); -- cgit v1.2.3-18-g5258 From 92ed48e5230e8f5906dda0cc31715b3b7e3fe303 Mon Sep 17 00:00:00 2001 From: Benoit PAPILLAULT Date: Mon, 17 Aug 2009 18:56:10 +0200 Subject: rt2x00: Add support for retry rates rt2800pci can handle different retry rates, it will always step 1 rate down after a failed transmission so creating the retry rate list for mac80211 is quite simple. Signed-off-by: Benoit PAPILLAULT Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 22 +++++++++++++++++----- drivers/net/wireless/rt2x00/rt2x00queue.h | 2 ++ 2 files changed, 19 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index b6676c6722f..9ab70e435b5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -220,7 +220,8 @@ void rt2x00lib_txdone(struct queue_entry *entry, struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); unsigned int header_length = ieee80211_get_hdrlen_from_skb(entry->skb); - u8 rate_idx, rate_flags; + u8 rate_idx, rate_flags, retry_rates; + unsigned int i; /* * Unmap the skb. @@ -259,16 +260,27 @@ void rt2x00lib_txdone(struct queue_entry *entry, rate_idx = skbdesc->tx_rate_idx; rate_flags = skbdesc->tx_rate_flags; + retry_rates = test_bit(TXDONE_FALLBACK, &txdesc->flags) ? + (txdesc->retry + 1) : 1; /* * Initialize TX status */ memset(&tx_info->status, 0, sizeof(tx_info->status)); tx_info->status.ack_signal = 0; - tx_info->status.rates[0].idx = rate_idx; - tx_info->status.rates[0].flags = rate_flags; - tx_info->status.rates[0].count = txdesc->retry + 1; - tx_info->status.rates[1].idx = -1; /* terminate */ + + /* + * Frame was send with retries, hardware tried + * different rates to send out the frame, at each + * retry it lowered the rate 1 step. + */ + for (i = 0; i < retry_rates && i < IEEE80211_TX_MAX_RATES; i++) { + tx_info->status.rates[i].idx = rate_idx - i; + tx_info->status.rates[i].flags = rate_flags; + tx_info->status.rates[i].count = 1; + } + if (i < (IEEE80211_TX_MAX_RATES -1)) + tx_info->status.rates[i].idx = -1; /* terminate */ if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (test_bit(TXDONE_SUCCESS, &txdesc->flags) || diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 47d175a1379..a5591fb2b19 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -214,6 +214,7 @@ struct rxdone_entry_desc { * * @TXDONE_UNKNOWN: Hardware could not determine success of transmission. * @TXDONE_SUCCESS: Frame was successfully send + * @TXDONE_FALLBACK: Frame was successfully send using a fallback rate. * @TXDONE_FAILURE: Frame was not successfully send * @TXDONE_EXCESSIVE_RETRY: In addition to &TXDONE_FAILURE, the * frame transmission failed due to excessive retries. @@ -221,6 +222,7 @@ struct rxdone_entry_desc { enum txdone_entry_desc_flags { TXDONE_UNKNOWN, TXDONE_SUCCESS, + TXDONE_FALLBACK, TXDONE_FAILURE, TXDONE_EXCESSIVE_RETRY, }; -- cgit v1.2.3-18-g5258 From bcd64e0c20eafe6a3976c248833d5d8bcccdf0d9 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 17 Aug 2009 23:33:56 -0400 Subject: wl1251: halt the embedded CPU before loading firmware After initial power-up, the embedded cpu is usually halted. However, if we down the interface and only do a soft reset before bringing the interface back up, it will still be running and the firmware loading code will bail out. This change halts the CPU before loading the firmware, enabling a second call to wl1251_boot() to succeed without a hard reset. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_boot.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index 592c3b5cc8f..452d748e42c 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -465,6 +465,9 @@ int wl1251_boot(struct wl1251 *wl) int ret = 0, minor_minor_e2_ver; u32 tmp, boot_data; + /* halt embedded ARM CPU while loading firmware */ + wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, ECPU_CONTROL_HALT); + ret = wl1251_boot_soft_reset(wl); if (ret < 0) goto out; -- cgit v1.2.3-18-g5258 From 4c48381786159ba3f3d8a33d967aeb049341a220 Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 18 Aug 2009 10:51:52 +0530 Subject: ath9k: Fix TX poll cancelling In ath9k_stop(), tx_complete_work was being cancelled twice. This patch fixes it. Also, locking sc->mutex should be done at the beginning. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 2f9c149fd48..fddda206def 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2105,6 +2105,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + mutex_lock(&sc->mutex); + aphy->state = ATH_WIPHY_INACTIVE; cancel_delayed_work_sync(&sc->ath_led_blink_work); @@ -2117,13 +2119,10 @@ static void ath9k_stop(struct ieee80211_hw *hw) if (sc->sc_flags & SC_OP_INVALID) { DPRINTF(sc, ATH_DBG_ANY, "Device not present\n"); + mutex_unlock(&sc->mutex); return; } - mutex_lock(&sc->mutex); - - cancel_delayed_work_sync(&sc->tx_complete_work); - if (ath9k_wiphy_started(sc)) { mutex_unlock(&sc->mutex); return; /* another wiphy still in use */ -- cgit v1.2.3-18-g5258 From 608b88cb34b0e70a538ee1fc334cc833ef691836 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 17 Aug 2009 18:07:23 -0700 Subject: ath: move regulatory info into shared common structure This moves the shared regulatory structure into the common structure. We will use this ongoing for common data. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/ar9170.h | 2 +- drivers/net/wireless/ath/ar9170/main.c | 14 ++++---- drivers/net/wireless/ath/ath.h | 18 ++++++++++ drivers/net/wireless/ath/ath5k/ath5k.h | 3 -- drivers/net/wireless/ath/ath5k/base.c | 14 ++++---- drivers/net/wireless/ath/ath5k/base.h | 13 +++++++ drivers/net/wireless/ath/ath5k/phy.c | 3 +- drivers/net/wireless/ath/ath9k/ath9k.h | 10 ++++++ drivers/net/wireless/ath/ath9k/eeprom_4k.c | 8 +++-- drivers/net/wireless/ath/ath9k/eeprom_9287.c | 16 ++++----- drivers/net/wireless/ath/ath9k/eeprom_def.c | 14 ++++---- drivers/net/wireless/ath/ath9k/hw.c | 53 ++++++++++++++++------------ drivers/net/wireless/ath/ath9k/hw.h | 1 - drivers/net/wireless/ath/ath9k/main.c | 6 ++-- drivers/net/wireless/ath/regd.h | 20 ++--------- 15 files changed, 116 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index e6c3ee3e058..95f8256c202 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -157,6 +157,7 @@ struct ar9170_sta_tid { struct ar9170 { struct ieee80211_hw *hw; + struct ath_common common; struct mutex mutex; enum ar9170_device_state state; unsigned long bad_hw_nagger; @@ -222,7 +223,6 @@ struct ar9170 { /* EEPROM */ struct ar9170_eeprom eeprom; - struct ath_regulatory regulatory; /* tx queues - as seen by hw - */ struct sk_buff_head tx_pending[__AR9170_NUM_TXQ]; diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 6a9462e4fd8..d30f33d4d41 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -2641,6 +2641,7 @@ static int ar9170_read_eeprom(struct ar9170 *ar) { #define RW 8 /* number of words to read at once */ #define RB (sizeof(u32) * RW) + struct ath_regulatory *regulatory = &ar->common.regulatory; u8 *eeprom = (void *)&ar->eeprom; u8 *addr = ar->eeprom.mac_address; __le32 offsets[RW]; @@ -2707,8 +2708,8 @@ static int ar9170_read_eeprom(struct ar9170 *ar) else ar->hw->channel_change_time = 80 * 1000; - ar->regulatory.current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]); - ar->regulatory.current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]); + regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]); + regulatory->current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]); /* second part of wiphy init */ SET_IEEE80211_PERM_ADDR(ar->hw, addr); @@ -2722,11 +2723,12 @@ static int ar9170_reg_notifier(struct wiphy *wiphy, struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ar9170 *ar = hw->priv; - return ath_reg_notifier_apply(wiphy, request, &ar->regulatory); + return ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory); } int ar9170_register(struct ar9170 *ar, struct device *pdev) { + struct ath_regulatory *regulatory = &ar->common.regulatory; int err; /* try to read EEPROM, init MAC addr */ @@ -2734,7 +2736,7 @@ int ar9170_register(struct ar9170 *ar, struct device *pdev) if (err) goto err_out; - err = ath_regd_init(&ar->regulatory, ar->hw->wiphy, + err = ath_regd_init(regulatory, ar->hw->wiphy, ar9170_reg_notifier); if (err) goto err_out; @@ -2743,8 +2745,8 @@ int ar9170_register(struct ar9170 *ar, struct device *pdev) if (err) goto err_out; - if (!ath_is_world_regd(&ar->regulatory)) - regulatory_hint(ar->hw->wiphy, ar->regulatory.alpha2); + if (!ath_is_world_regd(regulatory)) + regulatory_hint(ar->hw->wiphy, regulatory->alpha2); err = ar9170_init_leds(ar); if (err) diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index e284cd3ac6d..a63e90cbf9e 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -19,8 +19,26 @@ #include +struct reg_dmn_pair_mapping { + u16 regDmnEnum; + u16 reg_5ghz_ctl; + u16 reg_2ghz_ctl; +}; + +struct ath_regulatory { + char alpha2[2]; + u16 country_code; + u16 max_power_level; + u32 tp_scale; + u16 current_rd; + u16 current_rd_ext; + int16_t power_limit; + struct reg_dmn_pair_mapping *regpair; +}; + struct ath_common { u16 cachelsz; + struct ath_regulatory regulatory; }; struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index c09402eea7f..862762cea54 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -27,8 +27,6 @@ #include #include -#include "../regd.h" - /* RX/TX descriptor hw structs * TODO: Driver part should only see sw structs */ #include "desc.h" @@ -1077,7 +1075,6 @@ struct ath5k_hw { int ah_gpio_npins; - struct ath_regulatory ah_regulatory; struct ath5k_capabilities ah_capabilities; struct ath5k_txq_info ah_txq[AR5K_NUM_TX_QUEUES]; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 3951b5b1342..5056410d788 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -718,9 +718,9 @@ static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *re { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath5k_softc *sc = hw->priv; - struct ath_regulatory *reg = &sc->ah->ah_regulatory; + struct ath_regulatory *regulatory = &sc->common.regulatory; - return ath_reg_notifier_apply(wiphy, request, reg); + return ath_reg_notifier_apply(wiphy, request, regulatory); } static int @@ -728,6 +728,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) { struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; + struct ath_regulatory *regulatory = &sc->common.regulatory; u8 mac[ETH_ALEN] = {}; int ret; @@ -817,9 +818,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) memset(sc->bssidmask, 0xff, ETH_ALEN); ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); - ah->ah_regulatory.current_rd = - ah->ah_capabilities.cap_eeprom.ee_regdomain; - ret = ath_regd_init(&ah->ah_regulatory, hw->wiphy, ath5k_reg_notifier); + regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain; + ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier); if (ret) { ATH5K_ERR(sc, "can't initialize regulatory system\n"); goto err_queues; @@ -831,8 +831,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) goto err_queues; } - if (!ath_is_world_regd(&sc->ah->ah_regulatory)) - regulatory_hint(hw->wiphy, sc->ah->ah_regulatory.alpha2); + if (!ath_is_world_regd(regulatory)) + regulatory_hint(hw->wiphy, regulatory->alpha2); ath5k_init_leds(sc); diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 25a72a85aaa..a28c42f32c9 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -50,6 +50,8 @@ #include "ath5k.h" #include "debug.h" + +#include "../regd.h" #include "../ath.h" #define ATH_RXBUF 40 /* number of RX buffers */ @@ -200,4 +202,15 @@ struct ath5k_softc { #define ath5k_hw_hasveol(_ah) \ (ath5k_hw_get_capability(_ah, AR5K_CAP_VEOL, 0, NULL) == 0) +static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah) +{ + return &ah->ah_sc->common; +} + +static inline struct ath_regulatory *ath5k_hw_regulatory(struct ath5k_hw *ah) +{ + return &(ath5k_hw_common(ah)->regulatory); + +} + #endif diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 298fcf01522..1a039f2bd73 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -2198,6 +2198,7 @@ static void ath5k_get_max_ctl_power(struct ath5k_hw *ah, struct ieee80211_channel *channel) { + struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah); struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; struct ath5k_edge_power *rep = ee->ee_ctl_pwr; u8 *ctl_val = ee->ee_ctl; @@ -2208,7 +2209,7 @@ ath5k_get_max_ctl_power(struct ath5k_hw *ah, u8 ctl_idx = 0xFF; u32 target = channel->center_freq; - ctl_mode = ath_regd_get_band_ctl(&ah->ah_regulatory, channel->band); + ctl_mode = ath_regd_get_band_ctl(regulatory, channel->band); switch (channel->hw_value & CHANNEL_MODES) { case CHANNEL_A: diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 2c9f6628a8e..0e444a62904 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -631,6 +631,16 @@ int ath_get_hal_qnum(u16 queue, struct ath_softc *sc); int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); int ath_cabq_update(struct ath_softc *); +static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah) +{ + return &ah->ah_sc->common; +} + +static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah) +{ + return &(ath9k_hw_common(ah)->regulatory); +} + static inline void ath_read_cachesize(struct ath_softc *sc, int *csz) { sc->bus_ops->read_cachesize(sc, csz); diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index d34dd23e806..b8eca7be5f3 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -508,6 +508,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, || (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \ ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL)) + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); int i; int16_t twiceLargestAntenna; u16 twiceMinEdgePower; @@ -541,9 +542,9 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, twiceLargestAntenna, 0); maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { + if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) { maxRegAllowedPower -= - (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); + (tpScaleReductionTable[(regulatory->tp_scale)] * 2); } scaledPower = min(powerLimit, maxRegAllowedPower); @@ -707,6 +708,7 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, u8 twiceMaxRegulatoryPower, u8 powerLimit) { + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; struct modal_eep_4k_header *pModal = &pEepData->modalHeader; int16_t ratesArray[Ar5416RateSize]; @@ -744,7 +746,7 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, else if (IS_CHAN_HT20(chan)) i = rateHt20_0; - ah->regulatory.max_power_level = ratesArray[i]; + regulatory->max_power_level = ratesArray[i]; if (AR_SREV_9280_10_OR_LATER(ah)) { for (i = 0; i < Ar5416RateSize; i++) diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 959097927ee..c20c21a79b2 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -599,7 +599,7 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, { #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 - + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; static const u16 tpScaleReductionTable[5] = { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; @@ -632,9 +632,9 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah, twiceLargestAntenna, 0); maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) + if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) maxRegAllowedPower -= - (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); + (tpScaleReductionTable[(regulatory->tp_scale)] * 2); scaledPower = min(powerLimit, maxRegAllowedPower); @@ -831,7 +831,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, { #define INCREASE_MAXPOW_BY_TWO_CHAIN 6 #define INCREASE_MAXPOW_BY_THREE_CHAIN 10 - + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; int16_t ratesArray[Ar5416RateSize]; @@ -949,20 +949,20 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, i = rate6mb; if (AR_SREV_9280_10_OR_LATER(ah)) - ah->regulatory.max_power_level = + regulatory->max_power_level = ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2; else - ah->regulatory.max_power_level = ratesArray[i]; + regulatory->max_power_level = ratesArray[i]; switch (ar5416_get_ntxchains(ah->txchainmask)) { case 1: break; case 2: - ah->regulatory.max_power_level += + regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; break; case 3: - ah->regulatory.max_power_level += + regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; break; default: diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 5211ad94c8f..ae7fb5dcb26 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -904,6 +904,7 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; static const u16 tpScaleReductionTable[5] = @@ -953,9 +954,9 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - if (ah->regulatory.tp_scale != ATH9K_TP_SCALE_MAX) { + if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) { maxRegAllowedPower -= - (tpScaleReductionTable[(ah->regulatory.tp_scale)] * 2); + (tpScaleReductionTable[(regulatory->tp_scale)] * 2); } scaledPower = min(powerLimit, maxRegAllowedPower); @@ -1163,6 +1164,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, u8 powerLimit) { #define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta) + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; struct modal_eep_header *pModal = &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); @@ -1292,19 +1294,19 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, i = rateHt20_0; if (AR_SREV_9280_10_OR_LATER(ah)) - ah->regulatory.max_power_level = + regulatory->max_power_level = ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; else - ah->regulatory.max_power_level = ratesArray[i]; + regulatory->max_power_level = ratesArray[i]; switch(ar5416_get_ntxchains(ah->txchainmask)) { case 1: break; case 2: - ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; + regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; break; case 3: - ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; + regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; break; default: DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index df62113d89d..4f3d5ea3481 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -439,8 +439,13 @@ static void ath9k_hw_init_config(struct ath_hw *ah) static void ath9k_hw_init_defaults(struct ath_hw *ah) { + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); + + regulatory->country_code = CTRY_DEFAULT; + regulatory->power_limit = MAX_RATE_POWER; + regulatory->tp_scale = ATH9K_TP_SCALE_MAX; + ah->hw_version.magic = AR5416_MAGIC; - ah->regulatory.country_code = CTRY_DEFAULT; ah->hw_version.subvendorid = 0; ah->ah_flags = 0; @@ -449,8 +454,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) if (!AR_SREV_9100(ah)) ah->ah_flags = AH_USE_EEPROM; - ah->regulatory.power_limit = MAX_RATE_POWER; - ah->regulatory.tp_scale = ATH9K_TP_SCALE_MAX; ah->atim_window = 0; ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE; ah->beacon_interval = 100; @@ -1368,6 +1371,7 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode) { + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); int i, regWrites = 0; struct ieee80211_channel *channel = chan->chan; u32 modesIndex, freqIndex; @@ -1474,11 +1478,11 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, ath9k_olc_init(ah); ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(&ah->regulatory, chan), + ath9k_regd_get_ctl(regulatory, chan), channel->max_antenna_gain * 2, channel->max_power * 2, min((u32) MAX_RATE_POWER, - (u32) ah->regulatory.power_limit)); + (u32) regulatory->power_limit)); if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, @@ -1796,6 +1800,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode) { + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ieee80211_channel *channel = chan->chan; u32 synthDelay, qnum; @@ -1828,11 +1833,11 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, } ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(&ah->regulatory, chan), + ath9k_regd_get_ctl(regulatory, chan), channel->max_antenna_gain * 2, channel->max_power * 2, min((u32) MAX_RATE_POWER, - (u32) ah->regulatory.power_limit)); + (u32) regulatory->power_limit)); synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; if (IS_CHAN_B(chan)) @@ -3480,27 +3485,29 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, void ath9k_hw_fill_cap_info(struct ath_hw *ah) { struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); + u16 capField = 0, eeval; eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0); - ah->regulatory.current_rd = eeval; + regulatory->current_rd = eeval; eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_1); if (AR_SREV_9285_10_OR_LATER(ah)) eeval |= AR9285_RDEXT_DEFAULT; - ah->regulatory.current_rd_ext = eeval; + regulatory->current_rd_ext = eeval; capField = ah->eep_ops->get_eeprom(ah, EEP_OP_CAP); if (ah->opmode != NL80211_IFTYPE_AP && ah->hw_version.subvendorid == AR_SUBVENDOR_ID_NEW_A) { - if (ah->regulatory.current_rd == 0x64 || - ah->regulatory.current_rd == 0x65) - ah->regulatory.current_rd += 5; - else if (ah->regulatory.current_rd == 0x41) - ah->regulatory.current_rd = 0x43; + if (regulatory->current_rd == 0x64 || + regulatory->current_rd == 0x65) + regulatory->current_rd += 5; + else if (regulatory->current_rd == 0x41) + regulatory->current_rd = 0x43; DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "regdomain mapped to 0x%x\n", ah->regulatory.current_rd); + "regdomain mapped to 0x%x\n", regulatory->current_rd); } eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE); @@ -3635,7 +3642,7 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) else pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; - if (ah->regulatory.current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) { + if (regulatory->current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) { pCap->reg_cap = AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN | @@ -3664,6 +3671,7 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, u32 capability, u32 *result) { + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); switch (type) { case ATH9K_CAP_CIPHER: switch (capability) { @@ -3712,13 +3720,13 @@ bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, case 0: return 0; case 1: - *result = ah->regulatory.power_limit; + *result = regulatory->power_limit; return 0; case 2: - *result = ah->regulatory.max_power_level; + *result = regulatory->max_power_level; return 0; case 3: - *result = ah->regulatory.tp_scale; + *result = regulatory->tp_scale; return 0; } return false; @@ -3956,17 +3964,18 @@ bool ath9k_hw_disable(struct ath_hw *ah) void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit) { + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ath9k_channel *chan = ah->curchan; struct ieee80211_channel *channel = chan->chan; - ah->regulatory.power_limit = min(limit, (u32) MAX_RATE_POWER); + regulatory->power_limit = min(limit, (u32) MAX_RATE_POWER); ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(&ah->regulatory, chan), + ath9k_regd_get_ctl(regulatory, chan), channel->max_antenna_gain * 2, channel->max_power * 2, min((u32) MAX_RATE_POWER, - (u32) ah->regulatory.power_limit)); + (u32) regulatory->power_limit)); } void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index de31a1595f1..24b30631d93 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -396,7 +396,6 @@ struct ath_hw { struct ath9k_hw_version hw_version; struct ath9k_ops_config config; struct ath9k_hw_capabilities caps; - struct ath_regulatory regulatory; struct ath9k_channel channels[38]; struct ath9k_channel *curchan; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index fddda206def..de197117fdc 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1293,7 +1293,7 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - struct ath_regulatory *reg = &sc->sc_ah->regulatory; + struct ath_regulatory *reg = &sc->common.regulatory; return ath_reg_notifier_apply(wiphy, request, reg); } @@ -1586,12 +1586,12 @@ int ath_init_device(u16 devid, struct ath_softc *sc) ath_set_hw_capab(sc, hw); - error = ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy, + error = ath_regd_init(&sc->common.regulatory, sc->hw->wiphy, ath9k_reg_notifier); if (error) return error; - reg = &sc->sc_ah->regulatory; + reg = &sc->common.regulatory; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 07291ccb23f..4d3c53674e5 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -18,9 +18,10 @@ #define REGD_H #include - #include +#include "ath.h" + #define NO_CTL 0xff #define SD_NO_CTL 0xE0 #define NO_CTL 0xff @@ -47,29 +48,12 @@ #define CHANNEL_HALF_BW 10 #define CHANNEL_QUARTER_BW 5 -struct reg_dmn_pair_mapping { - u16 regDmnEnum; - u16 reg_5ghz_ctl; - u16 reg_2ghz_ctl; -}; - struct country_code_to_enum_rd { u16 countryCode; u16 regDmnEnum; const char *isoName; }; -struct ath_regulatory { - char alpha2[2]; - u16 country_code; - u16 max_power_level; - u32 tp_scale; - u16 current_rd; - u16 current_rd_ext; - int16_t power_limit; - struct reg_dmn_pair_mapping *regpair; -}; - enum CountryCode { CTRY_ALBANIA = 8, CTRY_ALGERIA = 12, -- cgit v1.2.3-18-g5258 From e5539bcbf64fdb16af73b5c8caff9255307490b5 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 18 Aug 2009 10:50:34 -0400 Subject: wl1271: remove print_mac usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC [M] drivers/net/wireless/wl12xx/wl1271_main.o drivers/net/wireless/wl12xx/wl1271_main.c: In function ‘wl1271_op_add_interface’: drivers/net/wireless/wl12xx/wl1271_main.c:611: warning: ‘print_mac’ is deprecated (declared at include/linux/if_ether.h:142) Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 754be817930..d9169b47ac4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -605,11 +605,10 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct wl1271 *wl = hw->priv; - DECLARE_MAC_BUF(mac); int ret = 0; - wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", - conf->type, print_mac(mac, conf->mac_addr)); + wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", + conf->type, conf->mac_addr); mutex_lock(&wl->mutex); -- cgit v1.2.3-18-g5258 From 21f8a73f829797eb7ebc12202b4c68e10e751ddb Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Tue, 18 Aug 2009 10:25:05 -0700 Subject: ipw2x00: fix sparse warnings This fixes: CHECK drivers/net/wireless/ipw2x00/ipw2100.c drivers/net/wireless/ipw2x00/ipw2100.c:7888:22: warning: symbol 'mode' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2100.c:188:12: originally declared here drivers/net/wireless/ipw2x00/ipw2100.c:7952:18: warning: symbol 'mode' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2100.c:188:12: originally declared here drivers/net/wireless/ipw2x00/ipw2100.c:8000:18: warning: symbol 'mode' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2100.c:188:12: originally declared here drivers/net/wireless/ipw2x00/ipw2100.c:8268:27: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2100.c:8268:27: originally declared here drivers/net/wireless/ipw2x00/ipw2100.c:8268:27: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2100.c:8268:27: originally declared here drivers/net/wireless/ipw2x00/ipw2100.c:8268:27: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2100.c:8268:27: originally declared here CC [M] drivers/net/wireless/ipw2x00/ipw2100.o CHECK drivers/net/wireless/ipw2x00/ipw2200.c drivers/net/wireless/ipw2x00/ipw2200.c:847:13: warning: symbol 'led' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:92:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:891:13: warning: symbol 'led' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:92:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:935:13: warning: symbol 'led' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:92:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:980:13: warning: symbol 'led' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:92:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:1016:13: warning: symbol 'led' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:92:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:1051:13: warning: symbol 'led' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:92:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:1823:13: warning: symbol 'channel' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:86:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min1' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: warning: symbol '_min2' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:4268:19: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:6228:28: warning: symbol 'channel' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:86:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:6369:20: warning: symbol 'channel' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:86:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:6857:12: warning: symbol 'mode' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:87:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:7964:13: warning: symbol 'channel' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:86:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:8720:12: warning: symbol 'channel' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:86:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:9662:13: warning: symbol 'mode' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:87:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:9720:13: warning: symbol 'mode' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:87:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:9826:13: warning: symbol 'mode' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:87:12: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:10318:21: warning: symbol 'remaining_bytes' shadows an earlier one drivers/net/wireless/ipw2x00/ipw2200.c:10184:13: originally declared here drivers/net/wireless/ipw2x00/ipw2200.c:8338:45: warning: cast to restricted __le16 drivers/net/wireless/ipw2x00/ipw2200.c:4414:21: warning: incorrect type in assignment (different base types) drivers/net/wireless/ipw2x00/ipw2200.c:4414:21: expected restricted __le16 [usertype] size drivers/net/wireless/ipw2x00/ipw2200.c:4414:21: got unsigned short [unsigned] [usertype] drivers/net/wireless/ipw2x00/ipw2200.c:6105:33: warning: incorrect type in initializer (different base types) drivers/net/wireless/ipw2x00/ipw2200.c:6105:33: expected restricted __le16 [usertype] tx_rates drivers/net/wireless/ipw2x00/ipw2200.c:6105:33: got unsigned short [unsigned] [usertype] rates_mask drivers/net/wireless/ipw2x00/ipw2200.c:6124:29: warning: bad assignment (>>=) to restricted __le16 drivers/net/wireless/ipw2x00/ipw2200.c:6130:31: warning: restricted __le16 degrades to integer drivers/net/wireless/ipw2x00/ipw2200.c:6140:23: warning: restricted __le16 degrades to integer drivers/net/wireless/ipw2x00/ipw2200.c:6149:54: warning: restricted __le16 degrades to integer drivers/net/wireless/ipw2x00/ipw2200.c:6151:37: warning: invalid assignment: &= drivers/net/wireless/ipw2x00/ipw2200.c:6151:37: left side has type restricted __le16 drivers/net/wireless/ipw2x00/ipw2200.c:6151:37: right side has type int drivers/net/wireless/ipw2x00/ipw2200.c:6154:54: warning: restricted __le16 degrades to integer drivers/net/wireless/ipw2x00/ipw2200.c:6156:37: warning: invalid assignment: &= drivers/net/wireless/ipw2x00/ipw2200.c:6156:37: left side has type restricted __le16 drivers/net/wireless/ipw2x00/ipw2200.c:6156:37: right side has type int drivers/net/wireless/ipw2x00/ipw2200.c:6159:55: warning: restricted __le16 degrades to integer drivers/net/wireless/ipw2x00/ipw2200.c:6161:37: warning: invalid assignment: &= drivers/net/wireless/ipw2x00/ipw2200.c:6161:37: left side has type restricted __le16 drivers/net/wireless/ipw2x00/ipw2200.c:6161:37: right side has type int drivers/net/wireless/ipw2x00/ipw2200.c:6164:29: warning: invalid assignment: |= drivers/net/wireless/ipw2x00/ipw2200.c:6164:29: left side has type restricted __le16 drivers/net/wireless/ipw2x00/ipw2200.c:6164:29: right side has type unsigned short drivers/net/wireless/ipw2x00/ipw2200.c:7853:29: warning: incorrect type in assignment (different base types) drivers/net/wireless/ipw2x00/ipw2200.c:7853:29: expected signed char [signed] [usertype] [explicitly-signed] rt_dbmnoise drivers/net/wireless/ipw2x00/ipw2200.c:7853:29: got restricted __le16 [usertype] noise drivers/net/wireless/ipw2x00/ipw2200.c:7967:25: warning: incorrect type in initializer (different base types) drivers/net/wireless/ipw2x00/ipw2200.c:7967:25: expected signed char [signed] [usertype] [explicitly-signed] noise drivers/net/wireless/ipw2x00/ipw2200.c:7967:25: got restricted __le16 [usertype] noise Signed-off-by: Reinette Chatre Cc: Zhu Yi Acked-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2100.c | 14 ++++--- drivers/net/wireless/ipw2x00/ipw2200.c | 73 +++++++++++++++++----------------- 2 files changed, 44 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 742432388ca..dee50ed0897 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -185,7 +185,7 @@ MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); static int debug = 0; -static int mode = 0; +static int network_mode = 0; static int channel = 0; static int associate = 0; static int disable = 0; @@ -195,7 +195,7 @@ static struct ipw2100_fw ipw2100_firmware; #include module_param(debug, int, 0444); -module_param(mode, int, 0444); +module_param_named(mode, network_mode, int, 0444); module_param(channel, int, 0444); module_param(associate, int, 0444); module_param(disable, int, 0444); @@ -2844,7 +2844,7 @@ static int __ipw2100_tx_process(struct ipw2100_priv *priv) #ifdef CONFIG_IPW2100_DEBUG { - int i = txq->oldest; + i = txq->oldest; IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i, &txq->drv[i], (u32) (txq->nic + i * sizeof(struct ipw2100_bd)), @@ -6076,7 +6076,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, priv->ieee->ieee802_1x = 1; /* Set module parameters */ - switch (mode) { + switch (network_mode) { case 1: priv->ieee->iw_mode = IW_MODE_ADHOC; break; @@ -8179,10 +8179,11 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev) int rssi_qual; int tx_qual; int beacon_qual; + int quality; struct ipw2100_priv *priv = ieee80211_priv(dev); struct iw_statistics *wstats; - u32 rssi, quality, tx_retries, missed_beacons, tx_failures; + u32 rssi, tx_retries, missed_beacons, tx_failures; u32 ord_len = sizeof(u32); if (!priv) @@ -8265,7 +8266,8 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev) beacon_qual = (20 - missed_beacons) * (PERFECT - VERY_GOOD) / 20 + VERY_GOOD; - quality = min(beacon_qual, min(tx_qual, rssi_qual)); + quality = min(tx_qual, rssi_qual); + quality = min(beacon_qual, quality); #ifdef CONFIG_IPW2100_DEBUG if (beacon_qual == quality) diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 07f171c4d30..8e18d534835 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -83,13 +83,13 @@ MODULE_LICENSE("GPL"); static int cmdlog = 0; static int debug = 0; -static int channel = 0; -static int mode = 0; +static int default_channel = 0; +static int network_mode = 0; static u32 ipw_debug_level; static int associate; static int auto_create = 1; -static int led = 0; +static int led_support = 0; static int disable = 0; static int bt_coexist = 0; static int hwcrypto = 0; @@ -4265,9 +4265,10 @@ static void ipw_gather_stats(struct ipw_priv *priv) IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n", signal_quality, rssi); - quality = min(beacon_quality, - min(rate_quality, - min(tx_quality, min(rx_quality, signal_quality)))); + quality = min(rx_quality, signal_quality); + quality = min(tx_quality, quality); + quality = min(rate_quality, quality); + quality = min(beacon_quality, quality); if (quality == beacon_quality) IPW_DEBUG_STATS("Quality (%d%%): Clamped to missed beacons.\n", quality); @@ -4411,7 +4412,6 @@ static void ipw_rx_notification(struct ipw_priv *priv, { DECLARE_SSID_BUF(ssid); u16 size = le16_to_cpu(notif->size); - notif->size = le16_to_cpu(notif->size); IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, size); @@ -6101,11 +6101,10 @@ static void ipw_debug_config(struct ipw_priv *priv) static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode) { /* TODO: Verify that this works... */ - struct ipw_fixed_rate fr = { - .tx_rates = priv->rates_mask - }; + struct ipw_fixed_rate fr; u32 reg; u16 mask = 0; + u16 new_tx_rates = priv->rates_mask; /* Identify 'current FW band' and match it with the fixed * Tx rates */ @@ -6117,54 +6116,56 @@ static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode) /* Invalid fixed rate mask */ IPW_DEBUG_WX ("invalid fixed rate mask in ipw_set_fixed_rate\n"); - fr.tx_rates = 0; + new_tx_rates = 0; break; } - fr.tx_rates >>= IEEE80211_OFDM_SHIFT_MASK_A; + new_tx_rates >>= IEEE80211_OFDM_SHIFT_MASK_A; break; default: /* 2.4Ghz or Mixed */ /* IEEE_B */ if (mode == IEEE_B) { - if (fr.tx_rates & ~IEEE80211_CCK_RATES_MASK) { + if (new_tx_rates & ~IEEE80211_CCK_RATES_MASK) { /* Invalid fixed rate mask */ IPW_DEBUG_WX ("invalid fixed rate mask in ipw_set_fixed_rate\n"); - fr.tx_rates = 0; + new_tx_rates = 0; } break; } /* IEEE_G */ - if (fr.tx_rates & ~(IEEE80211_CCK_RATES_MASK | + if (new_tx_rates & ~(IEEE80211_CCK_RATES_MASK | IEEE80211_OFDM_RATES_MASK)) { /* Invalid fixed rate mask */ IPW_DEBUG_WX ("invalid fixed rate mask in ipw_set_fixed_rate\n"); - fr.tx_rates = 0; + new_tx_rates = 0; break; } - if (IEEE80211_OFDM_RATE_6MB_MASK & fr.tx_rates) { + if (IEEE80211_OFDM_RATE_6MB_MASK & new_tx_rates) { mask |= (IEEE80211_OFDM_RATE_6MB_MASK >> 1); - fr.tx_rates &= ~IEEE80211_OFDM_RATE_6MB_MASK; + new_tx_rates &= ~IEEE80211_OFDM_RATE_6MB_MASK; } - if (IEEE80211_OFDM_RATE_9MB_MASK & fr.tx_rates) { + if (IEEE80211_OFDM_RATE_9MB_MASK & new_tx_rates) { mask |= (IEEE80211_OFDM_RATE_9MB_MASK >> 1); - fr.tx_rates &= ~IEEE80211_OFDM_RATE_9MB_MASK; + new_tx_rates &= ~IEEE80211_OFDM_RATE_9MB_MASK; } - if (IEEE80211_OFDM_RATE_12MB_MASK & fr.tx_rates) { + if (IEEE80211_OFDM_RATE_12MB_MASK & new_tx_rates) { mask |= (IEEE80211_OFDM_RATE_12MB_MASK >> 1); - fr.tx_rates &= ~IEEE80211_OFDM_RATE_12MB_MASK; + new_tx_rates &= ~IEEE80211_OFDM_RATE_12MB_MASK; } - fr.tx_rates |= mask; + new_tx_rates |= mask; break; } + fr.tx_rates = cpu_to_le16(new_tx_rates); + reg = ipw_read32(priv, IPW_MEM_FIXED_OVERRIDE); ipw_write_reg32(priv, reg, *(u32 *) & fr); } @@ -7850,7 +7851,7 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, /* Convert signal to DBM */ ipw_rt->rt_dbmsignal = antsignal; - ipw_rt->rt_dbmnoise = frame->noise; + ipw_rt->rt_dbmnoise = (s8) le16_to_cpu(frame->noise); /* Convert the channel data and set the flags */ ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(received_channel)); @@ -7964,7 +7965,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, u16 channel = frame->received_channel; u8 phy_flags = frame->antennaAndPhy; s8 signal = frame->rssi_dbm - IPW_RSSI_TO_DBM; - s8 noise = frame->noise; + s8 noise = (s8) le16_to_cpu(frame->noise); u8 rate = frame->rate; short len = le16_to_cpu(pkt->u.frame.length); struct sk_buff *skb; @@ -8335,7 +8336,7 @@ static void ipw_rx(struct ipw_priv *priv) .rssi = pkt->u.frame.rssi_dbm - IPW_RSSI_TO_DBM, .signal = - le16_to_cpu(pkt->u.frame.rssi_dbm) - + pkt->u.frame.rssi_dbm - IPW_RSSI_TO_DBM + 0x100, .noise = le16_to_cpu(pkt->u.frame.noise), @@ -8517,7 +8518,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) /* We default to disabling the LED code as right now it causes * too many systems to lock up... */ - if (!led) + if (!led_support) priv->config |= CFG_NO_LED; if (associate) @@ -8539,10 +8540,10 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) IPW_DEBUG_INFO("Radio disabled.\n"); } - if (channel != 0) { + if (default_channel != 0) { priv->config |= CFG_STATIC_CHANNEL; - priv->channel = channel; - IPW_DEBUG_INFO("Bind to static channel %d\n", channel); + priv->channel = default_channel; + IPW_DEBUG_INFO("Bind to static channel %d\n", default_channel); /* TODO: Validate that provided channel is in range */ } #ifdef CONFIG_IPW2200_QOS @@ -8550,7 +8551,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) burst_duration_CCK, burst_duration_OFDM); #endif /* CONFIG_IPW2200_QOS */ - switch (mode) { + switch (network_mode) { case 1: priv->ieee->iw_mode = IW_MODE_ADHOC; priv->net_dev->type = ARPHRD_ETHER; @@ -10181,7 +10182,6 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, #endif struct clx2_queue *q = &txq->q; u8 id, hdr_len, unicast; - u16 remaining_bytes; int fc; if (!(priv->status & STATUS_ASSOCIATED)) @@ -10220,7 +10220,6 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, tfd->u.data.cmd_id = DINO_CMD_TX; tfd->u.data.len = cpu_to_le16(txb->payload_size); - remaining_bytes = txb->payload_size; if (priv->assoc_request.ieee_mode == IPW_B_MODE) tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_CCK; @@ -11946,13 +11945,13 @@ MODULE_PARM_DESC(associate, "auto associate when scanning (default off)"); module_param(auto_create, int, 0444); MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)"); -module_param(led, int, 0444); +module_param_named(led, led_support, int, 0444); MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)"); module_param(debug, int, 0444); MODULE_PARM_DESC(debug, "debug output mask"); -module_param(channel, int, 0444); +module_param_named(channel, default_channel, int, 0444); MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])"); #ifdef CONFIG_IPW2200_PROMISCUOUS @@ -11978,10 +11977,10 @@ MODULE_PARM_DESC(burst_duration_OFDM, "set OFDM burst value"); #endif /* CONFIG_IPW2200_QOS */ #ifdef CONFIG_IPW2200_MONITOR -module_param(mode, int, 0444); +module_param_named(mode, network_mode, int, 0444); MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)"); #else -module_param(mode, int, 0444); +module_param_named(mode, network_mode, int, 0444); MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)"); #endif -- cgit v1.2.3-18-g5258 From afa620429ac6a636246f85d97cf205d6533e7fcb Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 18 Aug 2009 19:54:23 +0200 Subject: rt2x00: configure_filter() callback is allowed to sleep The configure_filter() callback function no longer needs to be atomic. Remove the scheduled work structure and call into the driver configure_filter() directly. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 1 - drivers/net/wireless/rt2x00/rt2x00dev.c | 10 ---------- drivers/net/wireless/rt2x00/rt2x00mac.c | 5 +---- 3 files changed, 1 insertion(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 39d7d9baafd..ad70946c3b5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -826,7 +826,6 @@ struct rt2x00_dev { * due to RTNL locking requirements. */ struct work_struct intf_work; - struct work_struct filter_work; /* * Data queue arrays for RX, TX and Beacon. diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 9ab70e435b5..16b560a661e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -118,14 +118,6 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state) rt2x00link_start_tuner(rt2x00dev); } -static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) -{ - struct rt2x00_dev *rt2x00dev = - container_of(work, struct rt2x00_dev, filter_work); - - rt2x00dev->ops->lib->config_filter(rt2x00dev, rt2x00dev->packet_filter); -} - static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { @@ -859,7 +851,6 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) * Initialize configuration work. */ INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); - INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled); /* * Allocate queue array. @@ -907,7 +898,6 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) /* * Stop all work. */ - cancel_work_sync(&rt2x00dev->filter_work); cancel_work_sync(&rt2x00dev->intf_work); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 3011aea4fea..967d3b55c89 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -430,10 +430,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, return; rt2x00dev->packet_filter = *total_flags; - if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags)) - rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags); - else - ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->filter_work); + rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags); } EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter); -- cgit v1.2.3-18-g5258 From d904dc17495581254442b7fd054e267f2605c8ec Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 18 Aug 2009 20:33:12 +0200 Subject: rt2x00: bss_info_changed() callback is allowed to sleep The bss_info_changed() callback function no longer needs to be atomic. Remove the scheduled work structure and call into the driver directly. Additionaly this makes the DRIVER_REQUIRE_SCHEDULED flag redundant so it can be removed. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500usb.c | 1 - drivers/net/wireless/rt2x00/rt2800usb.c | 1 - drivers/net/wireless/rt2x00/rt2x00.h | 3 --- drivers/net/wireless/rt2x00/rt2x00dev.c | 8 -------- drivers/net/wireless/rt2x00/rt2x00mac.c | 14 +++----------- drivers/net/wireless/rt2x00/rt73usb.c | 1 - 6 files changed, 3 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 09a589432da..b04f59bab3b 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1874,7 +1874,6 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) */ __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); if (!modparam_nohwcrypt) { __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_COPY_IV, &rt2x00dev->flags); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 45e02f16d75..639dc6cc04b 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -2634,7 +2634,6 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) * This device requires firmware. */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags); if (!modparam_nohwcrypt) __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index ad70946c3b5..555a777db6d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -350,8 +350,6 @@ struct rt2x00_intf { */ unsigned int delayed_flags; #define DELAYED_UPDATE_BEACON 0x00000001 -#define DELAYED_CONFIG_ERP 0x00000002 -#define DELAYED_LED_ASSOC 0x00000004 /* * Software sequence counter, this is only required @@ -614,7 +612,6 @@ enum rt2x00_flags { DRIVER_REQUIRE_FIRMWARE, DRIVER_REQUIRE_BEACON_GUARD, DRIVER_REQUIRE_ATIM_QUEUE, - DRIVER_REQUIRE_SCHEDULED, DRIVER_REQUIRE_DMA, DRIVER_REQUIRE_COPY_IV, DRIVER_REQUIRE_L2PAD, diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 16b560a661e..3f8c70ebe9a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -123,7 +123,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, { struct rt2x00_dev *rt2x00dev = data; struct rt2x00_intf *intf = vif_to_intf(vif); - struct ieee80211_bss_conf conf; int delayed_flags; /* @@ -133,7 +132,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, */ spin_lock(&intf->lock); - memcpy(&conf, &vif->bss_conf, sizeof(conf)); delayed_flags = intf->delayed_flags; intf->delayed_flags = 0; @@ -150,12 +148,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, if (delayed_flags & DELAYED_UPDATE_BEACON) rt2x00queue_update_beacon(rt2x00dev, vif, true); - - if (delayed_flags & DELAYED_CONFIG_ERP) - rt2x00lib_config_erp(rt2x00dev, intf, &conf); - - if (delayed_flags & DELAYED_LED_ASSOC) - rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated); } static void rt2x00lib_intf_scheduled(struct work_struct *work) diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 967d3b55c89..a91f316cd45 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -636,23 +636,15 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, else rt2x00dev->intf_associated--; - if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags)) - rt2x00leds_led_assoc(rt2x00dev, - !!rt2x00dev->intf_associated); - else - delayed |= DELAYED_LED_ASSOC; + rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated); } /* * When the erp information has changed, we should perform * additional configuration steps. For all other changes we are done. */ - if (changes & ~(BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) { - if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags)) - rt2x00lib_config_erp(rt2x00dev, intf, bss_conf); - else - delayed |= DELAYED_CONFIG_ERP; - } + if (changes & ~(BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) + rt2x00lib_config_erp(rt2x00dev, intf, bss_conf); spin_lock(&intf->lock); if (delayed) { diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 4d94b65943f..90e11726305 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2151,7 +2151,6 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) * This device requires firmware. */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); if (!modparam_nohwcrypt) __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); -- cgit v1.2.3-18-g5258 From 5791ce18aa660df7d1dafebf6bd89d5aa05bd742 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Tue, 18 Aug 2009 22:08:31 +0200 Subject: b43: LP-PHY: Two small spec updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The specs are beginning to support rev3 LP-PHYs - implement one of the changes needed for rev3 support. Also, in the new MIPS driver, the "Japan TX filter" was renamed to "analog TX filter init" - however, calling it "init" is confusing, so name it "set analog filter", with a comment for easier future identification. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 94023838568..37ba1777667 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -609,9 +609,14 @@ static void lpphy_2063_init(struct b43_wldev *dev) b43_radio_write(dev, B2063_PA_SP7, 0); b43_radio_write(dev, B2063_TX_RF_SP6, 0x20); b43_radio_write(dev, B2063_TX_RF_SP9, 0x40); - b43_radio_write(dev, B2063_PA_SP3, 0xa0); - b43_radio_write(dev, B2063_PA_SP4, 0xa0); - b43_radio_write(dev, B2063_PA_SP2, 0x18); + if (dev->phy.rev == 2) { + b43_radio_write(dev, B2063_PA_SP3, 0xa0); + b43_radio_write(dev, B2063_PA_SP4, 0xa0); + b43_radio_write(dev, B2063_PA_SP2, 0x18); + } else { + b43_radio_write(dev, B2063_PA_SP3, 0x20); + b43_radio_write(dev, B2063_PA_SP2, 0x20); + } } struct lpphy_stx_table_entry { @@ -1972,7 +1977,9 @@ static int lpphy_b2062_tune(struct b43_wldev *dev, return err; } -static void lpphy_japan_filter(struct b43_wldev *dev, int channel) + +/* This was previously called lpphy_japan_filter */ +static void lpphy_set_analog_filter(struct b43_wldev *dev, int channel) { struct b43_phy_lp *lpphy = dev->phy.lp; u16 tmp = (channel == 14); //SPEC FIXME check japanwidefilter! @@ -2141,7 +2148,7 @@ static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, err = lpphy_b2062_tune(dev, new_channel); if (err) return err; - lpphy_japan_filter(dev, new_channel); + lpphy_set_analog_filter(dev, new_channel); lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel)); } -- cgit v1.2.3-18-g5258 From eeef41854deae30ea304544f18684df70ae3f87b Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 19 Aug 2009 12:43:47 +0200 Subject: ar9170: refactor configure_filter Thanks to "mac80211: allow configure_filter callback to sleep", we no longer have to defer the work to the workqueue. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/ar9170.h | 14 ++---- drivers/net/wireless/ath/ar9170/mac.c | 22 +++------- drivers/net/wireless/ath/ar9170/main.c | 75 +++++++------------------------- 3 files changed, 27 insertions(+), 84 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index 95f8256c202..ce407248d7d 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -185,10 +185,8 @@ struct ar9170 { bool disable_offload; /* filter settings */ - struct work_struct filter_config_work; - u64 cur_mc_hash, want_mc_hash; - u32 cur_filter, want_filter; - unsigned long filter_changed; + u64 cur_mc_hash; + u32 cur_filter; unsigned int filter_state; bool sniffer_enabled; @@ -261,10 +259,6 @@ struct ar9170_tx_info { #define IS_STARTED(a) (((struct ar9170 *)a)->state >= AR9170_STARTED) #define IS_ACCEPTING_CMD(a) (((struct ar9170 *)a)->state >= AR9170_IDLE) -#define AR9170_FILTER_CHANGED_MODE BIT(0) -#define AR9170_FILTER_CHANGED_MULTICAST BIT(1) -#define AR9170_FILTER_CHANGED_FRAMEFILTER BIT(2) - /* exported interface */ void *ar9170_alloc(size_t priv_size); int ar9170_register(struct ar9170 *ar, struct device *pdev); @@ -278,8 +272,8 @@ int ar9170_nag_limiter(struct ar9170 *ar); int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb); int ar9170_init_mac(struct ar9170 *ar); int ar9170_set_qos(struct ar9170 *ar); -int ar9170_update_multicast(struct ar9170 *ar); -int ar9170_update_frame_filter(struct ar9170 *ar); +int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hast); +int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter); int ar9170_set_operating_mode(struct ar9170 *ar); int ar9170_set_beacon_timers(struct ar9170 *ar); int ar9170_set_dyn_sifs_ack(struct ar9170 *ar); diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c index d9f1f46de18..60049366e86 100644 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ b/drivers/net/wireless/ath/ar9170/mac.c @@ -238,39 +238,31 @@ static int ar9170_set_mac_reg(struct ar9170 *ar, const u32 reg, const u8 *mac) return ar9170_regwrite_result(); } -int ar9170_update_multicast(struct ar9170 *ar) +int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hash) { int err; ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, - ar->want_mc_hash >> 32); - ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, - ar->want_mc_hash); - + ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, mc_hash >> 32); + ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, mc_hash); ar9170_regwrite_finish(); err = ar9170_regwrite_result(); - if (err) return err; - ar->cur_mc_hash = ar->want_mc_hash; - + ar->cur_mc_hash = mc_hash; return 0; } -int ar9170_update_frame_filter(struct ar9170 *ar) +int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter) { int err; - err = ar9170_write_reg(ar, AR9170_MAC_REG_FRAMETYPE_FILTER, - ar->want_filter); - + err = ar9170_write_reg(ar, AR9170_MAC_REG_FRAMETYPE_FILTER, filter); if (err) return err; - ar->cur_filter = ar->want_filter; - + ar->cur_filter = filter; return 0; } diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index d30f33d4d41..658b32312ca 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -1232,8 +1232,6 @@ static int ar9170_op_start(struct ieee80211_hw *hw) mutex_lock(&ar->mutex); - ar->filter_changed = 0; - /* reinitialize queues statistics */ memset(&ar->tx_stats, 0, sizeof(ar->tx_stats)); for (i = 0; i < __AR9170_NUM_TXQ; i++) @@ -1296,7 +1294,6 @@ static void ar9170_op_stop(struct ieee80211_hw *hw) #ifdef CONFIG_AR9170_LEDS cancel_delayed_work_sync(&ar->led_work); #endif - cancel_work_sync(&ar->filter_config_work); cancel_work_sync(&ar->beacon_work); mutex_lock(&ar->mutex); @@ -1973,8 +1970,7 @@ static int ar9170_op_add_interface(struct ieee80211_hw *hw, } ar->cur_filter = 0; - ar->want_filter = AR9170_MAC_REG_FTF_DEFAULTS; - err = ar9170_update_frame_filter(ar); + err = ar9170_update_frame_filter(ar, AR9170_MAC_REG_FTF_DEFAULTS); if (err) goto unlock; @@ -1992,8 +1988,7 @@ static void ar9170_op_remove_interface(struct ieee80211_hw *hw, mutex_lock(&ar->mutex); ar->vif = NULL; - ar->want_filter = 0; - ar9170_update_frame_filter(ar); + ar9170_update_frame_filter(ar, 0); ar9170_set_beacon_timers(ar); dev_kfree_skb(ar->beacon); ar->beacon = NULL; @@ -2065,41 +2060,6 @@ out: return err; } -static void ar9170_set_filters(struct work_struct *work) -{ - struct ar9170 *ar = container_of(work, struct ar9170, - filter_config_work); - int err; - - if (unlikely(!IS_STARTED(ar))) - return ; - - mutex_lock(&ar->mutex); - if (test_and_clear_bit(AR9170_FILTER_CHANGED_MODE, - &ar->filter_changed)) { - err = ar9170_set_operating_mode(ar); - if (err) - goto unlock; - } - - if (test_and_clear_bit(AR9170_FILTER_CHANGED_MULTICAST, - &ar->filter_changed)) { - err = ar9170_update_multicast(ar); - if (err) - goto unlock; - } - - if (test_and_clear_bit(AR9170_FILTER_CHANGED_FRAMEFILTER, - &ar->filter_changed)) { - err = ar9170_update_frame_filter(ar); - if (err) - goto unlock; - } - -unlock: - mutex_unlock(&ar->mutex); -} - static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, struct dev_addr_list *mclist) { @@ -2126,6 +2086,11 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, { struct ar9170 *ar = hw->priv; + if (unlikely(!IS_ACCEPTING_CMD(ar))) + return ; + + mutex_lock(&ar->mutex); + /* mask supported flags */ *new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC | FIF_PROMISC_IN_BSS | FIF_FCSFAIL | FIF_PLCPFAIL; @@ -2136,12 +2101,10 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, */ if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI) - multicast = ~0ULL; + multicast = ~0ULL; - if (multicast != ar->want_mc_hash) { - ar->want_mc_hash = multicast; - set_bit(AR9170_FILTER_CHANGED_MULTICAST, &ar->filter_changed); - } + if (multicast != ar->cur_mc_hash) + ar9170_update_multicast(ar, multicast); if (changed_flags & FIF_CONTROL) { u32 filter = AR9170_MAC_REG_FTF_PSPOLL | @@ -2152,24 +2115,22 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, AR9170_MAC_REG_FTF_CFE_ACK; if (*new_flags & FIF_CONTROL) - ar->want_filter = ar->cur_filter | filter; + filter |= ar->cur_filter; else - ar->want_filter = ar->cur_filter & ~filter; + filter &= (~ar->cur_filter); - set_bit(AR9170_FILTER_CHANGED_FRAMEFILTER, - &ar->filter_changed); + ar9170_update_frame_filter(ar, filter); } if (changed_flags & FIF_PROMISC_IN_BSS) { ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0; - set_bit(AR9170_FILTER_CHANGED_MODE, - &ar->filter_changed); + ar9170_set_operating_mode(ar); } - if (likely(IS_STARTED(ar))) - ieee80211_queue_work(ar->hw, &ar->filter_config_work); + mutex_unlock(&ar->mutex); } + static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -2423,9 +2384,6 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw, default: break; } - - if (IS_STARTED(ar) && ar->filter_changed) - ieee80211_queue_work(ar->hw, &ar->filter_config_work); } static int ar9170_get_stats(struct ieee80211_hw *hw, @@ -2596,7 +2554,6 @@ void *ar9170_alloc(size_t priv_size) skb_queue_head_init(&ar->tx_pending[i]); } ar9170_rx_reset_rx_mpdu(ar); - INIT_WORK(&ar->filter_config_work, ar9170_set_filters); INIT_WORK(&ar->beacon_work, ar9170_new_beacon); INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor); INIT_LIST_HEAD(&ar->tx_ampdu_list); -- cgit v1.2.3-18-g5258 From 30fab9e0aecf15ca79bb194bb603203f5e1fde66 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Wed, 19 Aug 2009 00:44:43 +0100 Subject: orinoco: remove spare whitespace Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/wext.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 3e56f7643df..7698fdd6a3a 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -1291,7 +1291,7 @@ static int orinoco_ioctl_setibssport(struct net_device *dev, if (orinoco_lock(priv, &flags) != 0) return -EBUSY; - priv->ibss_port = val ; + priv->ibss_port = val; /* Actually update the mode we are using */ set_port_type(priv); -- cgit v1.2.3-18-g5258 From 5904d2067680e9bb73a4816fa6b9eec49355c9c8 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Tue, 18 Aug 2009 19:18:13 +0200 Subject: b43: LP-PHY: Implement spec updates and remove resolved FIXMEs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Larry has started re-checking all current routines against a new version of the Broadcom MIPS driver. This patch implements the first round of changes he documented on the specs wiki. Also remove a few FIXMEs regarding missing initial values for variables with dynamic initial values where reading the values has been implemented. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 98 ++++++++++++++++++++------------- drivers/net/wireless/b43/phy_lp.h | 18 +++--- drivers/net/wireless/b43/tables_lpphy.c | 12 +++- 3 files changed, 82 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 37ba1777667..2d3a5d812c4 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -724,9 +724,39 @@ static void lpphy_set_bb_mult(struct b43_wldev *dev, u8 bb_mult) b43_lptab_write(dev, B43_LPTAB16(0, 87), (u16)bb_mult << 8); } -static void lpphy_disable_crs(struct b43_wldev *dev) +static void lpphy_set_deaf(struct b43_wldev *dev, bool user) { + struct b43_phy_lp *lpphy = dev->phy.lp; + + if (user) + lpphy->crs_usr_disable = 1; + else + lpphy->crs_sys_disable = 1; b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x80); +} + +static void lpphy_clear_deaf(struct b43_wldev *dev, bool user) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + + if (user) + lpphy->crs_usr_disable = 0; + else + lpphy->crs_sys_disable = 0; + + if (!lpphy->crs_usr_disable && !lpphy->crs_sys_disable) { + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, + 0xFF1F, 0x60); + else + b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, + 0xFF1F, 0x20); + } +} + +static void lpphy_disable_crs(struct b43_wldev *dev, bool user) +{ + lpphy_set_deaf(dev, user); b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x1); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3); b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFB); @@ -754,12 +784,9 @@ static void lpphy_disable_crs(struct b43_wldev *dev) b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0x3FF); } -static void lpphy_restore_crs(struct b43_wldev *dev) +static void lpphy_restore_crs(struct b43_wldev *dev, bool user) { - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x60); - else - b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x20); + lpphy_clear_deaf(dev, user); b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFF80); b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFC00); } @@ -805,10 +832,11 @@ static void lpphy_set_tx_gains(struct b43_wldev *dev, b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, 0xF800, rf_gain); } else { - pa_gain = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x7F00; + pa_gain = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x1FC0; + pa_gain <<= 2; b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, (gains.pga << 8) | gains.gm); - b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, + b43_phy_maskset(dev, B43_PHY_OFDM(0xFB), 0x8000, gains.pad | pa_gain); b43_phy_write(dev, B43_PHY_OFDM(0xFC), (gains.pga << 8) | gains.gm); @@ -822,7 +850,7 @@ static void lpphy_set_tx_gains(struct b43_wldev *dev, b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F, 1 << 7); b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF, 1 << 14); } - b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFBF, 1 << 6); + b43_phy_maskset(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFBF, 1 << 6); } static void lpphy_rev0_1_set_rx_gain(struct b43_wldev *dev, u32 gain) @@ -862,33 +890,33 @@ static void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain) } } -static void lpphy_enable_rx_gain_override(struct b43_wldev *dev) +static void lpphy_disable_rx_gain_override(struct b43_wldev *dev) { b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE); b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFEF); b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFBF); if (dev->phy.rev >= 2) { b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF); - if (b43_current_band(dev->wl) != IEEE80211_BAND_2GHZ) - return; - b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF); - b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFF7); + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF); + b43_phy_mask(dev, B43_PHY_OFDM(0xE5), 0xFFF7); + } } else { b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF); } } -static void lpphy_disable_rx_gain_override(struct b43_wldev *dev) +static void lpphy_enable_rx_gain_override(struct b43_wldev *dev) { b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40); if (dev->phy.rev >= 2) { b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100); - if (b43_current_band(dev->wl) != IEEE80211_BAND_2GHZ) - return; - b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400); - b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x8); + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400); + b43_phy_set(dev, B43_PHY_OFDM(0xE5), 0x8); + } } else { b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x200); } @@ -1007,26 +1035,22 @@ static u32 lpphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision) { u32 quotient, remainder, rbit, roundup, tmp; - if (divisor == 0) { - quotient = 0; - remainder = 0; - } else { - quotient = dividend / divisor; - remainder = dividend % divisor; - } + if (divisor == 0) + return 0; + + quotient = dividend / divisor; + remainder = dividend % divisor; rbit = divisor & 0x1; roundup = (divisor >> 1) + rbit; - precision--; - while (precision != 0xFF) { + while (precision != 0) { tmp = remainder - roundup; quotient <<= 1; - remainder <<= 1; - if (remainder >= roundup) { + if (remainder >= roundup) remainder = (tmp << 1) + rbit; - quotient--; - } + else + remainder <<= 1; precision--; } @@ -1128,11 +1152,11 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) struct b43_phy_lp *lpphy = dev->phy.lp; struct lpphy_iq_est iq_est; struct lpphy_tx_gains tx_gains; - static const u32 ideal_pwr_table[22] = { + static const u32 ideal_pwr_table[21] = { 0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64, 0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35, 0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088, - 0x0004c, 0x0002c, 0x0001a, 0xc0006, + 0x0004c, 0x0002c, 0x0001a, }; bool old_txg_ovr; u8 old_bbmult; @@ -1150,7 +1174,7 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) "RC calib: Failed to switch to channel 7, error = %d", err); } - old_txg_ovr = (b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) >> 6) & 1; + old_txg_ovr = !!(b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40); old_bbmult = lpphy_get_bb_mult(dev); if (old_txg_ovr) tx_gains = lpphy_get_tx_gains(dev); @@ -1165,7 +1189,7 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) old_txpctl = lpphy->txpctl_mode; lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF); - lpphy_disable_crs(dev); + lpphy_disable_crs(dev, true); loopback = lpphy_loopback(dev); if (loopback == -1) goto finish; @@ -1198,7 +1222,7 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) lpphy_stop_ddfs(dev); finish: - lpphy_restore_crs(dev); + lpphy_restore_crs(dev, true); b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, old_rf_ovrval); b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, old_rf_ovr); b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVRVAL, old_afe_ovrval); diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h index 99cb0386e34..e158d1f66c0 100644 --- a/drivers/net/wireless/b43/phy_lp.h +++ b/drivers/net/wireless/b43/phy_lp.h @@ -825,11 +825,11 @@ struct b43_phy_lp { enum b43_lpphy_txpctl_mode txpctl_mode; /* Transmit isolation medium band */ - u8 tx_isolation_med_band; /* FIXME initial value? */ + u8 tx_isolation_med_band; /* Transmit isolation low band */ - u8 tx_isolation_low_band; /* FIXME initial value? */ + u8 tx_isolation_low_band; /* Transmit isolation high band */ - u8 tx_isolation_hi_band; /* FIXME initial value? */ + u8 tx_isolation_hi_band; /* Max transmit power medium band */ u16 max_tx_pwr_med_band; @@ -848,7 +848,7 @@ struct b43_phy_lp { s16 txpa[3], txpal[3], txpah[3]; /* Receive power offset */ - u8 rx_pwr_offset; /* FIXME initial value? */ + u8 rx_pwr_offset; /* TSSI transmit count */ u16 tssi_tx_count; @@ -864,16 +864,16 @@ struct b43_phy_lp { s8 tx_pwr_idx_over; /* FIXME initial value? */ /* RSSI vf */ - u8 rssi_vf; /* FIXME initial value? */ + u8 rssi_vf; /* RSSI vc */ - u8 rssi_vc; /* FIXME initial value? */ + u8 rssi_vc; /* RSSI gs */ - u8 rssi_gs; /* FIXME initial value? */ + u8 rssi_gs; /* RC cap */ u8 rc_cap; /* FIXME initial value? */ /* BX arch */ - u8 bx_arch; /* FIXME initial value? */ + u8 bx_arch; /* Full calibration channel */ u8 full_calib_chan; /* FIXME initial value? */ @@ -885,6 +885,8 @@ struct b43_phy_lp { /* Used for "Save/Restore Dig Filt State" */ u16 dig_flt_state[9]; + bool crs_usr_disable, crs_sys_disable; + unsigned int pdiv; }; diff --git a/drivers/net/wireless/b43/tables_lpphy.c b/drivers/net/wireless/b43/tables_lpphy.c index 2721310acb2..60d472f285a 100644 --- a/drivers/net/wireless/b43/tables_lpphy.c +++ b/drivers/net/wireless/b43/tables_lpphy.c @@ -2367,7 +2367,17 @@ static void lpphy_rev2plus_write_gain_table(struct b43_wldev *dev, int offset, tmp = data.pad << 16; tmp |= data.pga << 8; tmp |= data.gm; - tmp |= 0x7f000000; + if (dev->phy.rev >= 3) { + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) + tmp |= 0x10 << 24; + else + tmp |= 0x70 << 24; + } else { + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) + tmp |= 0x14 << 24; + else + tmp |= 0x7F << 24; + } b43_lptab_write(dev, B43_LPTAB32(7, 0xC0 + offset), tmp); tmp = data.bb_mult << 20; tmp |= data.dac << 28; -- cgit v1.2.3-18-g5258 From 035d0243ebbdbd5f8f07d6ce378c9a9b36415bc9 Mon Sep 17 00:00:00 2001 From: gregor kowski Date: Wed, 19 Aug 2009 22:35:45 +0200 Subject: b43: add hardware tkip This add hardware tkip for b43. Signed-off-by: Gregor Kowski Acked-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/dma.c | 2 +- drivers/net/wireless/b43/main.c | 122 +++++++++++++++++++++++++++++++++++++++- drivers/net/wireless/b43/pio.c | 4 +- drivers/net/wireless/b43/xmit.c | 28 +++++++-- drivers/net/wireless/b43/xmit.h | 3 +- 5 files changed, 147 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 41a0e9c2b33..289aaf6dfe7 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1188,7 +1188,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, header = &(ring->txhdr_cache[(slot / TX_SLOTS_PER_FRAME) * hdrsize]); cookie = generate_cookie(ring, slot); err = b43_generate_txhdr(ring->dev, header, - skb->data, skb->len, info, cookie); + skb, info, cookie); if (unlikely(err)) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 78ddbc7f836..f5bdf1cae1d 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -80,6 +80,10 @@ static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); +static int modparam_hwtkip; +module_param_named(hwtkip, modparam_hwtkip, int, 0444); +MODULE_PARM_DESC(hwtkip, "Enable hardware tkip."); + static int modparam_qos = 1; module_param_named(qos, modparam_qos, int, 0444); MODULE_PARM_DESC(qos, "Enable QOS support (default on)"); @@ -834,6 +838,85 @@ static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr) (index * 2) + 1, addrtmp[1]); } +/* The ucode will use phase1 key with TEK key to decrypt rx packets. + * When a packet is received, the iv32 is checked. + * - if it doesn't the packet is returned without modification (and software + * decryption can be done). That's what happen when iv16 wrap. + * - if it does, the rc4 key is computed, and decryption is tried. + * Either it will success and B43_RX_MAC_DEC is returned, + * either it fails and B43_RX_MAC_DEC|B43_RX_MAC_DECERR is returned + * and the packet is not usable (it got modified by the ucode). + * So in order to never have B43_RX_MAC_DECERR, we should provide + * a iv32 and phase1key that match. Because we drop packets in case of + * B43_RX_MAC_DECERR, if we have a correct iv32 but a wrong phase1key, all + * packets will be lost without higher layer knowing (ie no resync possible + * until next wrap). + * + * NOTE : this should support 50 key like RCMTA because + * (B43_SHM_SH_KEYIDXBLOCK - B43_SHM_SH_TKIPTSCTTAK)/14 = 50 + */ +static void rx_tkip_phase1_write(struct b43_wldev *dev, u8 index, u32 iv32, + u16 *phase1key) +{ + unsigned int i; + u32 offset; + u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2; + + if (!modparam_hwtkip) + return; + + if (b43_new_kidx_api(dev)) + pairwise_keys_start = B43_NR_GROUP_KEYS; + + B43_WARN_ON(index < pairwise_keys_start); + /* We have four default TX keys and possibly four default RX keys. + * Physical mac 0 is mapped to physical key 4 or 8, depending + * on the firmware version. + * So we must adjust the index here. + */ + index -= pairwise_keys_start; + B43_WARN_ON(index >= B43_NR_PAIRWISE_KEYS); + + if (b43_debug(dev, B43_DBG_KEYS)) { + b43dbg(dev->wl, "rx_tkip_phase1_write : idx 0x%x, iv32 0x%x\n", + index, iv32); + } + /* Write the key to the RX tkip shared mem */ + offset = B43_SHM_SH_TKIPTSCTTAK + index * (10 + 4); + for (i = 0; i < 10; i += 2) { + b43_shm_write16(dev, B43_SHM_SHARED, offset + i, + phase1key ? phase1key[i / 2] : 0); + } + b43_shm_write16(dev, B43_SHM_SHARED, offset + i, iv32); + b43_shm_write16(dev, B43_SHM_SHARED, offset + i + 2, iv32 >> 16); +} + +static void b43_op_update_tkip_key(struct ieee80211_hw *hw, + struct ieee80211_key_conf *keyconf, const u8 *addr, + u32 iv32, u16 *phase1key) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev; + int index = keyconf->hw_key_idx; + + if (B43_WARN_ON(!modparam_hwtkip)) + return; + + mutex_lock(&wl->mutex); + + dev = wl->current_dev; + if (!dev || b43_status(dev) < B43_STAT_INITIALIZED) + goto out_unlock; + + keymac_write(dev, index, NULL); /* First zero out mac to avoid race */ + + rx_tkip_phase1_write(dev, index, iv32, phase1key); + keymac_write(dev, index, addr); + +out_unlock: + mutex_unlock(&wl->mutex); +} + static void do_key_write(struct b43_wldev *dev, u8 index, u8 algorithm, const u8 *key, size_t key_len, const u8 *mac_addr) @@ -849,6 +932,19 @@ static void do_key_write(struct b43_wldev *dev, if (index >= pairwise_keys_start) keymac_write(dev, index, NULL); /* First zero out mac. */ + if (algorithm == B43_SEC_ALGO_TKIP) { + /* + * We should provide an initial iv32, phase1key pair. + * We could start with iv32=0 and compute the corresponding + * phase1key, but this means calling ieee80211_get_tkip_key + * with a fake skb (or export other tkip function). + * Because we are lazy we hope iv32 won't start with + * 0xffffffff and let's b43_op_update_tkip_key provide a + * correct pair. + */ + rx_tkip_phase1_write(dev, index, 0xffffffff, (u16*)buf); + } else if (index >= pairwise_keys_start) /* clear it */ + rx_tkip_phase1_write(dev, index, 0, NULL); if (key) memcpy(buf, key, key_len); key_write(dev, index, algorithm, buf); @@ -867,6 +963,15 @@ static int b43_key_write(struct b43_wldev *dev, int i; int pairwise_keys_start; + /* For ALG_TKIP the key is encoded as a 256-bit (32 byte) data block: + * - Temporal Encryption Key (128 bits) + * - Temporal Authenticator Tx MIC Key (64 bits) + * - Temporal Authenticator Rx MIC Key (64 bits) + * + * Hardware only store TEK + */ + if (algorithm == B43_SEC_ALGO_TKIP && key_len == 32) + key_len = 16; if (key_len > B43_SEC_KEYSIZE) return -EINVAL; for (i = 0; i < ARRAY_SIZE(dev->key); i++) { @@ -973,6 +1078,14 @@ static void b43_dump_keymemory(struct b43_wldev *dev) printk(" Algo: %04X/%02X", algo, key->algorithm); if (index >= pairwise_keys_start) { + if (key->algorithm == B43_SEC_ALGO_TKIP) { + printk(" TKIP: "); + offset = B43_SHM_SH_TKIPTSCTTAK + (index - 4) * (10 + 4); + for (i = 0; i < 14; i += 2) { + u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i); + printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF)); + } + } rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA, ((index - pairwise_keys_start) * 2) + 0); rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA, @@ -3620,8 +3733,10 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, switch (cmd) { case SET_KEY: - if (algorithm == B43_SEC_ALGO_TKIP) { - /* FIXME: No TKIP hardware encryption for now. */ + if (algorithm == B43_SEC_ALGO_TKIP && + (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE) || + !modparam_hwtkip)) { + /* We support only pairwise key */ err = -EOPNOTSUPP; goto out_unlock; } @@ -3651,6 +3766,8 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, b43_hf_read(dev) & ~B43_HF_USEDEFKEYS); } key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + if (algorithm == B43_SEC_ALGO_TKIP) + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; break; case DISABLE_KEY: { err = b43_key_clear(dev, key->hw_key_idx); @@ -4378,6 +4495,7 @@ static const struct ieee80211_ops b43_hw_ops = { .bss_info_changed = b43_op_bss_info_changed, .configure_filter = b43_op_configure_filter, .set_key = b43_op_set_key, + .update_tkip_key = b43_op_update_tkip_key, .get_stats = b43_op_get_stats, .get_tx_stats = b43_op_get_tx_stats, .get_tsf = b43_op_get_tsf, diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 73c047d8de4..3fd653c78b1 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -461,8 +461,8 @@ static int pio_tx_frame(struct b43_pio_txqueue *q, cookie = generate_cookie(q, pack); hdrlen = b43_txhdr_size(q->dev); - err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb->data, - skb->len, info, cookie); + err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb, + info, cookie); if (err) return err; diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index be1c53ecdb0..e7075d2c775 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -180,11 +180,12 @@ static u8 b43_calc_fallback_rate(u8 bitrate) /* Generate a TX data header. */ int b43_generate_txhdr(struct b43_wldev *dev, u8 *_txhdr, - const unsigned char *fragment_data, - unsigned int fragment_len, + struct sk_buff *skb_frag, struct ieee80211_tx_info *info, u16 cookie) { + const unsigned char *fragment_data = skb_frag->data; + unsigned int fragment_len = skb_frag->len; struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr; const struct b43_phy *phy = &dev->phy; const struct ieee80211_hdr *wlhdr = @@ -258,9 +259,26 @@ int b43_generate_txhdr(struct b43_wldev *dev, mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) & B43_TXH_MAC_KEYALG; wlhdr_len = ieee80211_hdrlen(fctl); - iv_len = min((size_t) info->control.hw_key->iv_len, - ARRAY_SIZE(txhdr->iv)); - memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); + if (key->algorithm == B43_SEC_ALGO_TKIP) { + u16 phase1key[5]; + int i; + /* we give the phase1key and iv16 here, the key is stored in + * shm. With that the hardware can do phase 2 and encryption. + */ + ieee80211_get_tkip_key(info->control.hw_key, skb_frag, + IEEE80211_TKIP_P1_KEY, (u8*)phase1key); + /* phase1key is in host endian */ + for (i = 0; i < 5; i++) + phase1key[i] = cpu_to_le16(phase1key[i]); + + memcpy(txhdr->iv, phase1key, 10); + /* iv16 */ + memcpy(txhdr->iv + 10, ((u8 *) wlhdr) + wlhdr_len, 3); + } else { + iv_len = min((size_t) info->control.hw_key->iv_len, + ARRAY_SIZE(txhdr->iv)); + memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); + } } if (b43_is_old_txhdr_format(dev)) { b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp), diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index 4fb2a190f7a..3530de87187 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h @@ -176,8 +176,7 @@ size_t b43_txhdr_size(struct b43_wldev *dev) int b43_generate_txhdr(struct b43_wldev *dev, u8 * txhdr, - const unsigned char *fragment_data, - unsigned int fragment_len, + struct sk_buff *skb_frag, struct ieee80211_tx_info *txctl, u16 cookie); /* Transmit Status */ -- cgit v1.2.3-18-g5258 From ff36041652fcb9f5c17bdbeb081414f69521f1af Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 20 Aug 2009 13:41:14 +0530 Subject: ath9k: Fix bug in retrieving average beacon rssi Currently the beacon rssi that LPF gives is divided and rounded up by ATH_RSSI_EP_MULTIPLIER twice. This will leave the incorrect rssi in ANI. Having correct rssi in ANI fixes the connection stability at < 30dB rssi range. This patch removes the unncessary computation of average rssi over already valid average rssi. Also removes the redundant macros to find average rssi. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ani.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index 119924511f8..6273fd056c2 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -18,15 +18,10 @@ #define ANI_H #define HAL_PROCESS_ANI 0x00000001 -#define ATH9K_RSSI_EP_MULTIPLIER (1<<7) #define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI)) -#define HAL_EP_RND(x, mul) \ - ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) -#define BEACON_RSSI(ahp) \ - HAL_EP_RND(ahp->stats.ast_nodestats.ns_avgbrssi, \ - ATH9K_RSSI_EP_MULTIPLIER) +#define BEACON_RSSI(ahp) (ahp->stats.ast_nodestats.ns_avgbrssi) #define ATH9K_ANI_OFDM_TRIG_HIGH 500 #define ATH9K_ANI_OFDM_TRIG_LOW 200 -- cgit v1.2.3-18-g5258 From 22e66a4c15b063aee5d03991c4b9629a3b0c4556 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 19 Aug 2009 16:23:40 +0530 Subject: ath9k: Nuke struct ath9k_node_stats Other than ns_avgbrssi (Average beacon rssi) no data of ath9k_node_stats is being used anywhere. Nuke this structure and move its only useful member to ar5416Anistate. Also cleanup this redundant data in ath_softc. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ani.c | 6 +----- drivers/net/wireless/ath/ath9k/ani.h | 15 +++------------ drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/main.c | 9 +++------ drivers/net/wireless/ath/ath9k/recv.c | 2 +- 5 files changed, 8 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index f264097a2f4..a7cbb07988c 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -538,7 +538,6 @@ void ath9k_ani_reset(struct ath_hw *ah) } void ath9k_hw_ani_monitor(struct ath_hw *ah, - const struct ath9k_node_stats *stats, struct ath9k_channel *chan) { struct ar5416AniState *aniState; @@ -550,7 +549,6 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, return; aniState = ah->curani; - ah->stats.ast_nodestats = *stats; listenTime = ath9k_hw_ani_get_listen_time(ah); if (listenTime < 0) { @@ -693,8 +691,7 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, * any of the MIB counters overflow/trigger so don't assume we're * here because a PHY error counter triggered. */ -void ath9k_hw_procmibevent(struct ath_hw *ah, - const struct ath9k_node_stats *stats) +void ath9k_hw_procmibevent(struct ath_hw *ah) { u32 phyCnt1, phyCnt2; @@ -706,7 +703,6 @@ void ath9k_hw_procmibevent(struct ath_hw *ah, /* Clear the mib counters and save them in the stats */ ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); - ah->stats.ast_nodestats = *stats; if (!DO_ANI(ah)) return; diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index 6273fd056c2..4e1ab94a515 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -21,7 +21,7 @@ #define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI)) -#define BEACON_RSSI(ahp) (ahp->stats.ast_nodestats.ns_avgbrssi) +#define BEACON_RSSI(ahp) (ahp->stats.avgbrssi) #define ATH9K_ANI_OFDM_TRIG_HIGH 500 #define ATH9K_ANI_OFDM_TRIG_LOW 200 @@ -60,13 +60,6 @@ struct ath9k_mib_stats { u32 beacons; }; -struct ath9k_node_stats { - u32 ns_avgbrssi; - u32 ns_avgrssi; - u32 ns_avgtxrssi; - u32 ns_avgtxrate; -}; - struct ar5416AniState { struct ath9k_channel *c; u8 noiseImmunityLevel; @@ -110,21 +103,19 @@ struct ar5416Stats { u32 ast_ani_reset; u32 ast_ani_lzero; u32 ast_ani_lneg; + u32 avgbrssi; struct ath9k_mib_stats ast_mibstats; - struct ath9k_node_stats ast_nodestats; }; #define ah_mibStats stats.ast_mibstats void ath9k_ani_reset(struct ath_hw *ah); void ath9k_hw_ani_monitor(struct ath_hw *ah, - const struct ath9k_node_stats *stats, struct ath9k_channel *chan); void ath9k_enable_mib_counters(struct ath_hw *ah); void ath9k_hw_disable_mib_counters(struct ath_hw *ah); u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt, u32 *rxf_pcnt, u32 *txf_pcnt); -void ath9k_hw_procmibevent(struct ath_hw *ah, - const struct ath9k_node_stats *stats); +void ath9k_hw_procmibevent(struct ath_hw *ah); void ath9k_hw_ani_setup(struct ath_hw *ah); void ath9k_hw_ani_init(struct ath_hw *ah); void ath9k_hw_ani_disable(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 0e444a62904..7705da1103f 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -603,7 +603,6 @@ struct ath_softc { int beacon_interval; struct ath_ani ani; - struct ath9k_node_stats nodestats; #ifdef CONFIG_ATH9K_DEBUG struct ath9k_debug debug; #endif diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index de197117fdc..9b9b4e8ee1e 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -384,7 +384,7 @@ static void ath_ani_calibrate(unsigned long data) if (longcal || shortcal || aniflag) { /* Call ANI routine if necessary */ if (aniflag) - ath9k_hw_ani_monitor(ah, &sc->nodestats, ah->curchan); + ath9k_hw_ani_monitor(ah, ah->curchan); /* Perform calibration if necessary */ if (longcal || shortcal) { @@ -589,7 +589,7 @@ irqreturn_t ath_isr(int irq, void *dev) * it will clear whatever condition caused * the interrupt. */ - ath9k_hw_procmibevent(ah, &sc->nodestats); + ath9k_hw_procmibevent(ah); ath9k_hw_set_interrupts(ah, sc->imask); } @@ -940,10 +940,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, ath_beacon_config(sc, vif); /* Reset rssi stats */ - sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; - sc->nodestats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; - sc->nodestats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; - sc->nodestats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; + sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; ath_start_ani(sc); } else { diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 61dbdd22744..7b62c220d5f 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -222,7 +222,7 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, /* Update Beacon RSSI, this is used by ANI. */ if (ieee80211_is_beacon(fc)) - sc->nodestats.ns_avgbrssi = ds->ds_rxstat.rs_rssi; + sc->sc_ah->stats.avgbrssi = ds->ds_rxstat.rs_rssi; rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); rx_status->band = hw->conf.channel->band; -- cgit v1.2.3-18-g5258 From c23b5a699471ea2ef9d146eae80e64836cfbf001 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 13:49:55 +0200 Subject: mwl8k: remove various unused struct members and defines Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 73 +++++--------------------------------------- 1 file changed, 8 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index c32e93c8c41..91b7062711e 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -58,7 +58,6 @@ MODULE_DEVICE_TABLE(pci, mwl8k_table); #define MWL8K_HIU_H2A_INTERRUPT_STATUS_MASK 0x00000c28 #define MWL8K_H2A_INT_DUMMY (1 << 20) #define MWL8K_H2A_INT_RESET (1 << 15) -#define MWL8K_H2A_INT_PS (1 << 2) #define MWL8K_H2A_INT_DOORBELL (1 << 1) #define MWL8K_H2A_INT_PPA_READY (1 << 0) @@ -161,10 +160,8 @@ struct mwl8k_priv { /* lock held over TX and TX reap */ spinlock_t tx_lock; - u32 int_mask; struct ieee80211_vif *vif; - struct list_head vif_list; struct ieee80211_channel *current_channel; @@ -173,10 +170,8 @@ struct mwl8k_priv { dma_addr_t cookie_dma; u16 num_mcaddrs; - u16 region_code; u8 hw_rev; __le32 fw_rev; - u32 wep_enabled; /* * Running count of TX packets in flight, to avoid @@ -226,8 +221,6 @@ struct mwl8k_priv { /* Per interface specific private data */ struct mwl8k_vif { - struct list_head node; - /* backpointer to parent config block */ struct mwl8k_priv *priv; @@ -247,18 +240,11 @@ struct mwl8k_vif { /* number of supported legacy rates */ u8 legacy_nrates; - /* Number of supported MCS rates. Work in progress */ - u8 mcs_nrates; - /* Index into station database.Returned by update_sta_db call */ u8 peer_id; /* Non AMPDU sequence number assigned by driver */ u16 seqno; - - /* Note:There is no channel info, - * refer to the master channel info in priv - */ }; #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) @@ -681,11 +667,9 @@ struct ewc_ht_info { /* Peer Entry flags - used to define the type of the peer node */ #define MWL8K_PEER_TYPE_ACCESSPOINT 2 -#define MWL8K_PEER_TYPE_ADHOC_STATION 4 #define MWL8K_IEEE_LEGACY_DATA_RATES 12 #define MWL8K_MCS_BITMAP_SIZE 16 -#define pad_size 16 struct peer_capability_info { /* Peer type - AP vs. STA. */ @@ -707,7 +691,7 @@ struct peer_capability_info { /* HT rate table. Intersection of our rates and peer rates. */ __u8 ht_rates[MWL8K_MCS_BITMAP_SIZE]; - __u8 pad[pad_size]; + __u8 pad[16]; /* If set, interoperability mode, no proprietary extensions. */ __u8 interop; @@ -717,15 +701,6 @@ struct peer_capability_info { } __attribute__((packed)); /* Inline functions to manipulate QoS field in data descriptor. */ -static inline u16 mwl8k_qos_setbit_tid(u16 qos, u8 tid) -{ - u16 val_mask = 0x000f; - u16 qos_mask = ~val_mask; - - /* TID bits 0-3 */ - return (qos & qos_mask) | (tid & val_mask); -} - static inline u16 mwl8k_qos_setbit_eosp(u16 qos) { u16 val_mask = 1 << 4; @@ -826,9 +801,7 @@ static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb) /* * Packet reception. */ -#define MWL8K_RX_CTRL_KEY_INDEX_MASK 0x30 #define MWL8K_RX_CTRL_OWNED_BY_HOST 0x02 -#define MWL8K_RX_CTRL_AMPDU 0x01 struct mwl8k_rx_desc { __le16 pkt_len; @@ -1073,8 +1046,6 @@ enum { /* Transmit packet ACK policy */ #define MWL8K_TXD_ACK_POLICY_NORMAL 0 -#define MWL8K_TXD_ACK_POLICY_NONE 1 -#define MWL8K_TXD_ACK_POLICY_NO_EXPLICIT 2 #define MWL8K_TXD_ACK_POLICY_BLOCKACK 3 #define GET_TXQ(_ac) (\ @@ -1083,20 +1054,11 @@ enum { ((_ac) == WME_AC_BK) ? MWL8K_WME_AC_BK : \ MWL8K_WME_AC_BE) -#define MWL8K_TXD_STATUS_IDLE 0x00000000 -#define MWL8K_TXD_STATUS_USED 0x00000001 #define MWL8K_TXD_STATUS_OK 0x00000001 #define MWL8K_TXD_STATUS_OK_RETRY 0x00000002 #define MWL8K_TXD_STATUS_OK_MORE_RETRY 0x00000004 #define MWL8K_TXD_STATUS_MULTICAST_TX 0x00000008 -#define MWL8K_TXD_STATUS_BROADCAST_TX 0x00000010 -#define MWL8K_TXD_STATUS_FAILED_LINK_ERROR 0x00000020 -#define MWL8K_TXD_STATUS_FAILED_EXCEED_LIMIT 0x00000040 -#define MWL8K_TXD_STATUS_FAILED_AGING 0x00000080 -#define MWL8K_TXD_STATUS_HOST_CMD 0x40000000 #define MWL8K_TXD_STATUS_FW_OWNED 0x80000000 -#define MWL8K_TXD_SOFTSTALE 0x80 -#define MWL8K_TXD_SOFTSTALE_MGMT_RETRY 0x01 struct mwl8k_tx_desc { __le32 status; @@ -1279,12 +1241,10 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) return 0; } -#define MWL8K_TXD_OK (MWL8K_TXD_STATUS_OK | \ - MWL8K_TXD_STATUS_OK_RETRY | \ - MWL8K_TXD_STATUS_OK_MORE_RETRY) -#define MWL8K_TXD_SUCCESS(stat) ((stat) & MWL8K_TXD_OK) -#define MWL8K_TXD_FAIL_RETRY(stat) \ - ((stat) & (MWL8K_TXD_STATUS_FAILED_EXCEED_LIMIT)) +#define MWL8K_TXD_SUCCESS(status) \ + ((status) & (MWL8K_TXD_STATUS_OK | \ + MWL8K_TXD_STATUS_OK_RETRY | \ + MWL8K_TXD_STATUS_OK_MORE_RETRY)) static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) { @@ -1671,7 +1631,6 @@ static int mwl8k_cmd_get_hw_spec(struct ieee80211_hw *hw) priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); priv->fw_rev = le32_to_cpu(cmd->fw_rev); priv->hw_rev = cmd->hw_rev; - priv->region_code = le16_to_cpu(cmd->region_code); } kfree(cmd); @@ -2150,7 +2109,6 @@ struct mwl8k_cmd_set_edca_params { __u8 txq; } __attribute__((packed)); -#define MWL8K_GET_EDCA_ALL 0 #define MWL8K_SET_EDCA_CW 0x01 #define MWL8K_SET_EDCA_TXOP 0x02 #define MWL8K_SET_EDCA_AIFS 0x04 @@ -2323,18 +2281,12 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw, /* * CMD_SET_AID. */ -#define IEEE80211_OPMODE_DISABLED 0x00 -#define IEEE80211_OPMODE_NON_MEMBER_PROT_MODE 0x01 -#define IEEE80211_OPMODE_ONE_20MHZ_STA_PROT_MODE 0x02 -#define IEEE80211_OPMODE_HTMIXED_PROT_MODE 0x03 - #define MWL8K_RATE_INDEX_MAX_ARRAY 14 #define MWL8K_FRAME_PROT_DISABLED 0x00 #define MWL8K_FRAME_PROT_11G 0x07 #define MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY 0x02 #define MWL8K_FRAME_PROT_11N_HT_ALL 0x06 -#define MWL8K_FRAME_PROT_MASK 0x07 struct mwl8k_cmd_update_set_aid { struct mwl8k_cmd_pkt header; @@ -2439,10 +2391,6 @@ static int mwl8k_update_rateset(struct ieee80211_hw *hw, */ #define MWL8K_RATE_TABLE_SIZE 8 #define MWL8K_UCAST_RATE 0 -#define MWL8K_MCAST_RATE 1 -#define MWL8K_BCAST_RATE 2 - -#define MWL8K_USE_FIXED_RATE 0x0001 #define MWL8K_USE_AUTO_RATE 0x0002 struct mwl8k_rate_entry { @@ -2535,7 +2483,6 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); - status &= priv->int_mask; if (!status) return IRQ_NONE; @@ -2873,7 +2820,7 @@ static int mwl8k_start(struct ieee80211_hw *hw) } /* Enable interrupts */ - iowrite32(priv->int_mask, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); + iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); worker = kzalloc(sizeof(*worker), GFP_KERNEL); if (worker == NULL) { @@ -3532,7 +3479,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, priv->hostcmd_wait = NULL; priv->tx_wait = NULL; priv->inconfig = false; - priv->wep_enabled = 0; priv->wmm_mode = false; priv->pending_tx_pkts = 0; strncpy(priv->name, MWL8K_NAME, sizeof(priv->name)); @@ -3614,8 +3560,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, } iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); - priv->int_mask = 0; - iowrite32(priv->int_mask, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); + iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); @@ -3652,9 +3597,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, * commands use interrupts and avoids polling. Disable * interrupts when done. */ - priv->int_mask |= MWL8K_A2H_EVENTS; - - iowrite32(priv->int_mask, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); + iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); /* Get config data, mac addrs etc */ rc = mwl8k_cmd_get_hw_spec(hw); -- cgit v1.2.3-18-g5258 From d89173f25228b8795af2d4b53e985cc44c729332 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 09:54:27 +0200 Subject: mwl8k: s/IEEE80211_ADDR_LEN/ETH_ALEN/g Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 47 +++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 91b7062711e..e8febab6135 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -38,8 +38,6 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_table) = { }; MODULE_DEVICE_TABLE(pci, mwl8k_table); -#define IEEE80211_ADDR_LEN ETH_ALEN - /* Register definitions */ #define MWL8K_HIU_GEN_PTR 0x00000c10 #define MWL8K_MODE_STA 0x0000005a @@ -199,7 +197,7 @@ struct mwl8k_priv { /* XXX need to convert this to handle multiple interfaces */ bool capture_beacon; - u8 capture_bssid[IEEE80211_ADDR_LEN]; + u8 capture_bssid[ETH_ALEN]; struct sk_buff *beacon_skb; /* @@ -228,8 +226,8 @@ struct mwl8k_vif { struct ieee80211_bss_conf bss_info; /* BSSID of AP or IBSS */ - u8 bssid[IEEE80211_ADDR_LEN]; - u8 mac_addr[IEEE80211_ADDR_LEN]; + u8 bssid[ETH_ALEN]; + u8 mac_addr[ETH_ALEN]; /* * Subset of supported legacy rates. @@ -785,7 +783,7 @@ static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb) memmove(&tr->wh, wh, hdrlen); /* Clear addr4 */ - memset(tr->wh.addr4, 0, IEEE80211_ADDR_LEN); + memset(tr->wh.addr4, 0, ETH_ALEN); /* * Firmware length is the length of the fully formed "802.11 @@ -952,7 +950,7 @@ static inline void mwl8k_save_beacon(struct mwl8k_priv *priv, struct sk_buff *skb) { priv->capture_beacon = false; - memset(priv->capture_bssid, 0, IEEE80211_ADDR_LEN); + memset(priv->capture_bssid, 0, ETH_ALEN); /* * Use GFP_ATOMIC as rxq_process is called from @@ -1067,7 +1065,7 @@ struct mwl8k_tx_desc { __le16 qos_control; __le32 pkt_phys_addr; __le16 pkt_len; - __u8 dest_MAC_addr[IEEE80211_ADDR_LEN]; + __u8 dest_MAC_addr[ETH_ALEN]; __le32 next_tx_desc_phys_addr; __le32 reserved; __le16 rate_info; @@ -1587,7 +1585,7 @@ struct mwl8k_cmd_get_hw_spec { __u8 hw_rev; __u8 host_interface; __le16 num_mcaddrs; - __u8 perm_addr[IEEE80211_ADDR_LEN]; + __u8 perm_addr[ETH_ALEN]; __le16 region_code; __le32 fw_rev; __le32 ps_cookie; @@ -1644,7 +1642,7 @@ struct mwl8k_cmd_mac_multicast_adr { struct mwl8k_cmd_pkt header; __le16 action; __le16 numaddr; - __u8 addr[1][IEEE80211_ADDR_LEN]; + __u8 addr[1][ETH_ALEN]; }; #define MWL8K_ENABLE_RX_MULTICAST 0x000F @@ -1655,7 +1653,7 @@ static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, struct mwl8k_cmd_mac_multicast_adr *cmd; int index = 0; int rc; - int size = sizeof(*cmd) + ((mc_count - 1) * IEEE80211_ADDR_LEN); + int size = sizeof(*cmd) + ((mc_count - 1) * ETH_ALEN); cmd = kzalloc(size, GFP_KERNEL); if (cmd == NULL) return -ENOMEM; @@ -1665,11 +1663,11 @@ static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST); cmd->numaddr = cpu_to_le16(mc_count); while ((index < mc_count) && mclist) { - if (mclist->da_addrlen != IEEE80211_ADDR_LEN) { + if (mclist->da_addrlen != ETH_ALEN) { rc = -EINVAL; goto mwl8k_cmd_mac_multicast_adr_exit; } - memcpy(cmd->addr[index], mclist->da_addr, IEEE80211_ADDR_LEN); + memcpy(cmd->addr[index], mclist->da_addr, ETH_ALEN); index++; mclist = mclist->next; } @@ -1848,11 +1846,11 @@ static int mwl8k_cmd_set_pre_scan(struct ieee80211_hw *hw) struct mwl8k_cmd_set_post_scan { struct mwl8k_cmd_pkt header; __le32 isibss; - __u8 bssid[IEEE80211_ADDR_LEN]; + __u8 bssid[ETH_ALEN]; } __attribute__((packed)); static int -mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 mac[IEEE80211_ADDR_LEN]) +mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 mac[ETH_ALEN]) { struct mwl8k_cmd_set_post_scan *cmd; int rc; @@ -1864,7 +1862,7 @@ mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 mac[IEEE80211_ADDR_LEN]) cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_POST_SCAN); cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->isibss = 0; - memcpy(cmd->bssid, mac, IEEE80211_ADDR_LEN); + memcpy(cmd->bssid, mac, ETH_ALEN); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2216,7 +2214,7 @@ struct mwl8k_cmd_update_sta_db { __le32 action; /* Peer MAC address */ - __u8 peer_addr[IEEE80211_ADDR_LEN]; + __u8 peer_addr[ETH_ALEN]; __le32 reserved; @@ -2244,7 +2242,7 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw, cmd->action = cpu_to_le32(action); peer_info = &cmd->peer_info; - memcpy(cmd->peer_addr, mv_vif->bssid, IEEE80211_ADDR_LEN); + memcpy(cmd->peer_addr, mv_vif->bssid, ETH_ALEN); switch (action) { case MWL8K_STA_DB_ADD_ENTRY: @@ -2293,7 +2291,7 @@ struct mwl8k_cmd_update_set_aid { __le16 aid; /* AP's MAC address (BSSID) */ - __u8 bssid[IEEE80211_ADDR_LEN]; + __u8 bssid[ETH_ALEN]; __le16 protection_mode; __u8 supp_rates[MWL8K_RATE_INDEX_MAX_ARRAY]; } __attribute__((packed)); @@ -2317,7 +2315,7 @@ static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw, cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->aid = cpu_to_le16(info->aid); - memcpy(cmd->bssid, mv_vif->bssid, IEEE80211_ADDR_LEN); + memcpy(cmd->bssid, mv_vif->bssid, ETH_ALEN); prot_mode = MWL8K_FRAME_PROT_DISABLED; @@ -2934,7 +2932,7 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); /* Save the mac address */ - memcpy(mwl8k_vif->mac_addr, conf->mac_addr, IEEE80211_ADDR_LEN); + memcpy(mwl8k_vif->mac_addr, conf->mac_addr, ETH_ALEN); /* Back pointer to parent config block */ mwl8k_vif->priv = priv; @@ -3091,14 +3089,13 @@ static int mwl8k_bss_info_changed_wt(struct work_struct *wt) * Finalize the join. Tell rx handler to process * next beacon from our BSSID. */ - memcpy(priv->capture_bssid, - mwl8k_vif->bssid, IEEE80211_ADDR_LEN); + memcpy(priv->capture_bssid, mwl8k_vif->bssid, ETH_ALEN); priv->capture_beacon = true; } else { mwl8k_cmd_update_sta_db(hw, vif, MWL8K_STA_DB_DEL_ENTRY); memset(&mwl8k_vif->bss_info, 0, sizeof(struct ieee80211_bss_conf)); - memset(mwl8k_vif->bssid, 0, IEEE80211_ADDR_LEN); + memset(mwl8k_vif->bssid, 0, ETH_ALEN); } mwl8k_bss_info_changed_exit: @@ -3117,7 +3114,7 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, int rc; if (changed & BSS_CHANGED_BSSID) - memcpy(mv_vif->bssid, info->bssid, IEEE80211_ADDR_LEN); + memcpy(mv_vif->bssid, info->bssid, ETH_ALEN); if ((changed & BSS_CHANGED_ASSOC) == 0) return; -- cgit v1.2.3-18-g5258 From ff45fc60ad583f45ecf10a41f7dbecf78519bcc1 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 11:50:36 +0200 Subject: mwl8k: sort firmware command list by opcode, and trim unused commands Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index e8febab6135..682b82071a0 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -307,25 +307,23 @@ static const struct ieee80211_rate mwl8k_rates[] = { #define MWL8K_CMD_GET_HW_SPEC 0x0003 #define MWL8K_CMD_MAC_MULTICAST_ADR 0x0010 #define MWL8K_CMD_GET_STAT 0x0014 -#define MWL8K_CMD_RADIO_CONTROL 0x001C -#define MWL8K_CMD_RF_TX_POWER 0x001E +#define MWL8K_CMD_RADIO_CONTROL 0x001c +#define MWL8K_CMD_RF_TX_POWER 0x001e #define MWL8K_CMD_SET_PRE_SCAN 0x0107 #define MWL8K_CMD_SET_POST_SCAN 0x0108 -#define MWL8K_CMD_SET_RF_CHANNEL 0x010A +#define MWL8K_CMD_SET_RF_CHANNEL 0x010a +#define MWL8K_CMD_SET_AID 0x010d +#define MWL8K_CMD_SET_RATE 0x0110 +#define MWL8K_CMD_SET_FINALIZE_JOIN 0x0111 +#define MWL8K_CMD_RTS_THRESHOLD 0x0113 #define MWL8K_CMD_SET_SLOT 0x0114 +#define MWL8K_CMD_SET_EDCA_PARAMS 0x0115 +#define MWL8K_CMD_SET_WMM_MODE 0x0123 #define MWL8K_CMD_MIMO_CONFIG 0x0125 +#define MWL8K_CMD_USE_FIXED_RATE 0x0126 #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 -#define MWL8K_CMD_SET_WMM_MODE 0x0123 -#define MWL8K_CMD_SET_EDCA_PARAMS 0x0115 -#define MWL8K_CMD_SET_FINALIZE_JOIN 0x0111 -#define MWL8K_CMD_UPDATE_STADB 0x1123 #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 -#define MWL8K_CMD_SET_LINKADAPT_MODE 0x0129 -#define MWL8K_CMD_SET_AID 0x010d -#define MWL8K_CMD_SET_RATE 0x0110 -#define MWL8K_CMD_USE_FIXED_RATE 0x0126 -#define MWL8K_CMD_RTS_THRESHOLD 0x0113 -#define MWL8K_CMD_ENCRYPTION 0x1122 +#define MWL8K_CMD_UPDATE_STADB 0x1123 static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) { @@ -343,20 +341,18 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) MWL8K_CMDNAME(SET_PRE_SCAN); MWL8K_CMDNAME(SET_POST_SCAN); MWL8K_CMDNAME(SET_RF_CHANNEL); + MWL8K_CMDNAME(SET_AID); + MWL8K_CMDNAME(SET_RATE); + MWL8K_CMDNAME(SET_FINALIZE_JOIN); + MWL8K_CMDNAME(RTS_THRESHOLD); MWL8K_CMDNAME(SET_SLOT); + MWL8K_CMDNAME(SET_EDCA_PARAMS); + MWL8K_CMDNAME(SET_WMM_MODE); MWL8K_CMDNAME(MIMO_CONFIG); + MWL8K_CMDNAME(USE_FIXED_RATE); MWL8K_CMDNAME(ENABLE_SNIFFER); - MWL8K_CMDNAME(SET_WMM_MODE); - MWL8K_CMDNAME(SET_EDCA_PARAMS); - MWL8K_CMDNAME(SET_FINALIZE_JOIN); - MWL8K_CMDNAME(UPDATE_STADB); MWL8K_CMDNAME(SET_RATEADAPT_MODE); - MWL8K_CMDNAME(SET_LINKADAPT_MODE); - MWL8K_CMDNAME(SET_AID); - MWL8K_CMDNAME(SET_RATE); - MWL8K_CMDNAME(USE_FIXED_RATE); - MWL8K_CMDNAME(RTS_THRESHOLD); - MWL8K_CMDNAME(ENCRYPTION); + MWL8K_CMDNAME(UPDATE_STADB); default: snprintf(buf, bufsize, "0x%x", cmd); } -- cgit v1.2.3-18-g5258 From ce9e2e1b8433c8795459a259ee87bc4e424e7c50 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 14:00:45 +0200 Subject: mwl8k: various coding style cleanups Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 130 +++++++++++++++++++------------------------ 1 file changed, 57 insertions(+), 73 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 682b82071a0..a2eeba17d37 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1,5 +1,6 @@ /* - * drivers/net/wireless/mwl8k.c driver for Marvell TOPDOG 802.11 Wireless cards + * drivers/net/wireless/mwl8k.c + * Driver for Marvell TOPDOG 802.11 Wireless cards * * Copyright (C) 2008 Marvell Semiconductor Inc. * @@ -40,12 +41,12 @@ MODULE_DEVICE_TABLE(pci, mwl8k_table); /* Register definitions */ #define MWL8K_HIU_GEN_PTR 0x00000c10 -#define MWL8K_MODE_STA 0x0000005a -#define MWL8K_MODE_AP 0x000000a5 +#define MWL8K_MODE_STA 0x0000005a +#define MWL8K_MODE_AP 0x000000a5 #define MWL8K_HIU_INT_CODE 0x00000c14 -#define MWL8K_FWSTA_READY 0xf0f1f2f4 -#define MWL8K_FWAP_READY 0xf1f2f4a5 -#define MWL8K_INT_CODE_CMD_FINISHED 0x00000005 +#define MWL8K_FWSTA_READY 0xf0f1f2f4 +#define MWL8K_FWAP_READY 0xf1f2f4a5 +#define MWL8K_INT_CODE_CMD_FINISHED 0x00000005 #define MWL8K_HIU_SCRATCH 0x00000c40 /* Host->device communications */ @@ -54,10 +55,10 @@ MODULE_DEVICE_TABLE(pci, mwl8k_table); #define MWL8K_HIU_H2A_INTERRUPT_MASK 0x00000c20 #define MWL8K_HIU_H2A_INTERRUPT_CLEAR_SEL 0x00000c24 #define MWL8K_HIU_H2A_INTERRUPT_STATUS_MASK 0x00000c28 -#define MWL8K_H2A_INT_DUMMY (1 << 20) -#define MWL8K_H2A_INT_RESET (1 << 15) -#define MWL8K_H2A_INT_DOORBELL (1 << 1) -#define MWL8K_H2A_INT_PPA_READY (1 << 0) +#define MWL8K_H2A_INT_DUMMY (1 << 20) +#define MWL8K_H2A_INT_RESET (1 << 15) +#define MWL8K_H2A_INT_DOORBELL (1 << 1) +#define MWL8K_H2A_INT_PPA_READY (1 << 0) /* Device->host communications */ #define MWL8K_HIU_A2H_INTERRUPT_EVENTS 0x00000c2c @@ -65,16 +66,16 @@ MODULE_DEVICE_TABLE(pci, mwl8k_table); #define MWL8K_HIU_A2H_INTERRUPT_MASK 0x00000c34 #define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL 0x00000c38 #define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK 0x00000c3c -#define MWL8K_A2H_INT_DUMMY (1 << 20) -#define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11) -#define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10) -#define MWL8K_A2H_INT_RADAR_DETECT (1 << 7) -#define MWL8K_A2H_INT_RADIO_ON (1 << 6) -#define MWL8K_A2H_INT_RADIO_OFF (1 << 5) -#define MWL8K_A2H_INT_MAC_EVENT (1 << 3) -#define MWL8K_A2H_INT_OPC_DONE (1 << 2) -#define MWL8K_A2H_INT_RX_READY (1 << 1) -#define MWL8K_A2H_INT_TX_DONE (1 << 0) +#define MWL8K_A2H_INT_DUMMY (1 << 20) +#define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11) +#define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10) +#define MWL8K_A2H_INT_RADAR_DETECT (1 << 7) +#define MWL8K_A2H_INT_RADIO_ON (1 << 6) +#define MWL8K_A2H_INT_RADIO_OFF (1 << 5) +#define MWL8K_A2H_INT_MAC_EVENT (1 << 3) +#define MWL8K_A2H_INT_OPC_DONE (1 << 2) +#define MWL8K_A2H_INT_RX_READY (1 << 1) +#define MWL8K_A2H_INT_TX_DONE (1 << 0) #define MWL8K_A2H_EVENTS (MWL8K_A2H_INT_DUMMY | \ MWL8K_A2H_INT_CHNL_SWITCHED | \ @@ -331,7 +332,7 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) snprintf(buf, bufsize, "%s", #x);\ return buf;\ } while (0) - switch (cmd & (~0x8000)) { + switch (cmd & ~0x8000) { MWL8K_CMDNAME(CODE_DNLD); MWL8K_CMDNAME(GET_HW_SPEC); MWL8K_CMDNAME(MAC_MULTICAST_ADR); @@ -1078,8 +1079,7 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index) int size; int i; - memset(&txq->tx_stats, 0, - sizeof(struct ieee80211_tx_queue_stats)); + memset(&txq->tx_stats, 0, sizeof(struct ieee80211_tx_queue_stats)); txq->tx_stats.limit = MWL8K_TX_DESCS; txq->tx_head = 0; txq->tx_tail = 0; @@ -1181,10 +1181,10 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv, static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) { - u32 count = 0; - unsigned long timeout = 0; struct mwl8k_priv *priv = hw->priv; DECLARE_COMPLETION_ONSTACK(cmd_wait); + u32 count; + unsigned long timeout; might_sleep(); @@ -1219,7 +1219,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) __func__, __LINE__, delay_ms, count, newcount); mwl8k_scan_tx_ring(priv, txinfo, 4); - for (index = 0 ; index < 4; index++) + for (index = 0; index < 4; index++) printk(KERN_ERR "TXQ:%u L:%u H:%u T:%u FW:%u DRV:%u U:%u\n", index, @@ -1229,6 +1229,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) txinfo[index].fw_owned, txinfo[index].drv_owned, txinfo[index].unused); + return -ETIMEDOUT; } @@ -1251,7 +1252,7 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) int rc; struct mwl8k_tx_desc *tx_desc; unsigned long addr; - size_t size; + int size; struct sk_buff *skb; struct ieee80211_tx_info *info; u32 status; @@ -1275,7 +1276,7 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) priv->pending_tx_pkts--; addr = le32_to_cpu(tx_desc->pkt_phys_addr); - size = (u32)(le16_to_cpu(tx_desc->pkt_len)); + size = le16_to_cpu(tx_desc->pkt_len); skb = txq->tx_skb[tx].skb; txq->tx_skb[tx].skb = NULL; @@ -1312,12 +1313,8 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) info = IEEE80211_SKB_CB(skb); ieee80211_tx_info_clear_status(info); - - /* Convert firmware status stuff into tx_status */ - if (MWL8K_TXD_SUCCESS(status)) { - /* Transmit OK */ + if (MWL8K_TXD_SUCCESS(status)) info->flags |= IEEE80211_TX_STAT_ACK; - } ieee80211_tx_status_irqsafe(hw, skb); @@ -1522,7 +1519,6 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) dma_addr_t dma_addr; unsigned int dma_size; int rc; - u16 __iomem *result; unsigned long timeout = 0; u8 buf[32]; @@ -1551,7 +1547,6 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) pci_unmap_single(priv->pdev, dma_addr, dma_size, PCI_DMA_BIDIRECTIONAL); - result = &cmd->result; if (!timeout) { spin_lock_irq(&priv->fw_lock); priv->hostcmd_wait = NULL; @@ -1562,12 +1557,12 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) MWL8K_CMD_TIMEOUT_MS); rc = -ETIMEDOUT; } else { - rc = *result ? -EINVAL : 0; + rc = cmd->result ? -EINVAL : 0; if (rc) printk(KERN_ERR "%s: Command %s error 0x%x\n", priv->name, mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), - *result); + cmd->result); } return rc; @@ -1638,10 +1633,11 @@ struct mwl8k_cmd_mac_multicast_adr { struct mwl8k_cmd_pkt header; __le16 action; __le16 numaddr; - __u8 addr[1][ETH_ALEN]; + __u8 addr[0][ETH_ALEN]; }; #define MWL8K_ENABLE_RX_MULTICAST 0x000F + static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int mc_count, struct dev_addr_list *mclist) @@ -1649,7 +1645,8 @@ static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, struct mwl8k_cmd_mac_multicast_adr *cmd; int index = 0; int rc; - int size = sizeof(*cmd) + ((mc_count - 1) * ETH_ALEN); + int size = sizeof(*cmd) + mc_count * ETH_ALEN; + cmd = kzalloc(size, GFP_KERNEL); if (cmd == NULL) return -ENOMEM; @@ -1658,13 +1655,13 @@ static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, cmd->header.length = cpu_to_le16(size); cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST); cmd->numaddr = cpu_to_le16(mc_count); - while ((index < mc_count) && mclist) { + + while (index < mc_count && mclist) { if (mclist->da_addrlen != ETH_ALEN) { rc = -EINVAL; goto mwl8k_cmd_mac_multicast_adr_exit; } - memcpy(cmd->addr[index], mclist->da_addr, ETH_ALEN); - index++; + memcpy(cmd->addr[index++], mclist->da_addr, ETH_ALEN); mclist = mclist->next; } @@ -1846,7 +1843,7 @@ struct mwl8k_cmd_set_post_scan { } __attribute__((packed)); static int -mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 mac[ETH_ALEN]) +mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 *mac) { struct mwl8k_cmd_set_post_scan *cmd; int rc; @@ -1980,7 +1977,7 @@ static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable) cmd->header.code = cpu_to_le16(MWL8K_CMD_ENABLE_SNIFFER); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = enable ? cpu_to_le32((u32)MWL8K_CMD_SET) : 0; + cmd->action = cpu_to_le32(!!enable); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -1989,7 +1986,7 @@ static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable) } /* - * CMD_SET_RATE_ADAPT_MODE. + * CMD_SET_RATEADAPT_MODE. */ struct mwl8k_cmd_set_rate_adapt_mode { struct mwl8k_cmd_pkt header; @@ -2117,22 +2114,18 @@ mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, __u8 aifs, __u16 txop) { struct mwl8k_cmd_set_edca_params *cmd; - u32 log_cw_min, log_cw_max; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; - log_cw_min = ilog2(cw_min+1); - log_cw_max = ilog2(cw_max+1); cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_EDCA_PARAMS); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL); cmd->txop = cpu_to_le16(txop); - cmd->log_cw_max = (u8)log_cw_max; - cmd->log_cw_min = (u8)log_cw_min; + cmd->log_cw_max = (u8)ilog2(cw_max + 1); + cmd->log_cw_min = (u8)ilog2(cw_min + 1); cmd->aifs = aifs; cmd->txq = qnum; @@ -2173,11 +2166,7 @@ static int mwl8k_finalize_join(struct ieee80211_hw *hw, void *frame, cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_FINALIZE_JOIN); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - - if (dtim) - cmd->sleep_interval = cpu_to_le32(dtim); - else - cmd->sleep_interval = cpu_to_le32(1); + cmd->sleep_interval = cpu_to_le32(dtim ? dtim : 1); hdrlen = ieee80211_hdrlen(payload->frame_control); @@ -2189,8 +2178,8 @@ static int mwl8k_finalize_join(struct ieee80211_hw *hw, void *frame, "sent to firmware. Sz=%u MAX=%u\n", __func__, payload_len, MWL8K_FJ_BEACON_MAXLEN); - payload_len = payload_len > MWL8K_FJ_BEACON_MAXLEN ? - MWL8K_FJ_BEACON_MAXLEN : payload_len; + if (payload_len > MWL8K_FJ_BEACON_MAXLEN) + payload_len = MWL8K_FJ_BEACON_MAXLEN; if (payload && payload_len) memcpy(cmd->beacon_data, &payload->u.beacon, payload_len); @@ -2250,7 +2239,7 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw, peer_info->amsdu_enabled = 0; rates = peer_info->legacy_rates; - for (count = 0 ; count < mv_vif->legacy_nrates; count++) + for (count = 0; count < mv_vif->legacy_nrates; count++) rates[count] = bitrates[count].hw_value; rc = mwl8k_post_cmd(hw, &cmd->header); @@ -2313,8 +2302,6 @@ static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw, memcpy(cmd->bssid, mv_vif->bssid, ETH_ALEN); - prot_mode = MWL8K_FRAME_PROT_DISABLED; - if (info->use_cts_prot) { prot_mode = MWL8K_FRAME_PROT_11G; } else { @@ -2331,7 +2318,6 @@ static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw, break; } } - cmd->protection_mode = cpu_to_le16(prot_mode); for (count = 0; count < mv_vif->legacy_nrates; count++) @@ -2934,7 +2920,7 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, mwl8k_vif->priv = priv; /* Setup initial PHY parameters */ - memcpy(mwl8k_vif->legacy_rates , + memcpy(mwl8k_vif->legacy_rates, priv->rates, sizeof(mwl8k_vif->legacy_rates)); mwl8k_vif->legacy_nrates = ARRAY_SIZE(priv->rates); @@ -3171,8 +3157,9 @@ static int mwl8k_configure_filter_wt(struct work_struct *wt) if (rc) goto mwl8k_configure_filter_exit; if (mc_count) { - mc_count = mc_count < priv->num_mcaddrs ? - mc_count : priv->num_mcaddrs; + if (mc_count > priv->num_mcaddrs) + mc_count = priv->num_mcaddrs; + rc = mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist); if (rc) printk(KERN_ERR @@ -3411,12 +3398,9 @@ static void mwl8k_tx_reclaim_handler(unsigned long data) for (i = 0; i < MWL8K_TX_QUEUES; i++) mwl8k_txq_reclaim(hw, i, 0); - if (priv->tx_wait != NULL) { - int count = mwl8k_txq_busy(priv); - if (count == 0) { - complete(priv->tx_wait); - priv->tx_wait = NULL; - } + if (priv->tx_wait != NULL && mwl8k_txq_busy(priv) == 0) { + complete(priv->tx_wait); + priv->tx_wait = NULL; } spin_unlock_bh(&priv->tx_lock); } @@ -3426,7 +3410,7 @@ static void mwl8k_finalize_join_worker(struct work_struct *work) struct mwl8k_priv *priv = container_of(work, struct mwl8k_priv, finalize_join_worker); struct sk_buff *skb = priv->beacon_skb; - u8 dtim = (MWL8K_VIF(priv->vif))->bss_info.dtim_period; + u8 dtim = MWL8K_VIF(priv->vif)->bss_info.dtim_period; mwl8k_finalize_join(priv->hw, skb->data, skb->len, dtim); dev_kfree_skb(skb); @@ -3513,7 +3497,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_MONITOR); /* Set rssi and noise values to dBm */ - hw->flags |= (IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM); + hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; hw->vif_data_size = sizeof(struct mwl8k_vif); priv->vif = NULL; -- cgit v1.2.3-18-g5258 From c46563b714b09d44eec4d1fd8a0f53e79ddaa3aa Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 12:14:58 +0200 Subject: mwl8k: remove MWL8K_RADIO_* defines Instead of passing a flag bitmask to mwl8k_cmd_802_11_radio_control, pass the 'enable' and 'force' arguments as separate parameters, and introduce wrappers for the common cases of enabling and disabling without forcing. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 50 +++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index a2eeba17d37..78183c8b5f0 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -186,9 +186,10 @@ struct mwl8k_priv { struct ieee80211_channel channels[14]; struct ieee80211_rate rates[12]; + bool radio_on; + /* RF preamble: Short, Long or Auto */ u8 radio_preamble; - u8 radio_state; /* WMM MODE 1 for enabled; 0 for disabled */ bool wmm_mode; @@ -278,9 +279,6 @@ static const struct ieee80211_rate mwl8k_rates[] = { }; /* Radio settings */ -#define MWL8K_RADIO_FORCE 0x2 -#define MWL8K_RADIO_ENABLE 0x1 -#define MWL8K_RADIO_DISABLE 0x0 #define MWL8K_RADIO_AUTO_PREAMBLE 0x0005 #define MWL8K_RADIO_SHORT_PREAMBLE 0x0003 #define MWL8K_RADIO_LONG_PREAMBLE 0x0001 @@ -1195,7 +1193,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) count = mwl8k_txq_busy(priv); if (count) { priv->tx_wait = &cmd_wait; - if (priv->radio_state) + if (priv->radio_on) mwl8k_tx_start(priv); } spin_unlock_bh(&priv->tx_lock); @@ -1318,7 +1316,7 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) ieee80211_tx_status_irqsafe(hw, skb); - wake = !priv->inconfig && priv->radio_state; + wake = !priv->inconfig && priv->radio_on; } if (wake) @@ -1726,18 +1724,16 @@ struct mwl8k_cmd_802_11_radio_control { __le16 radio_on; } __attribute__((packed)); -static int mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, int enable) +static int +mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, bool enable, bool force) { struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_802_11_radio_control *cmd; int rc; - if (((enable & MWL8K_RADIO_ENABLE) == priv->radio_state) && - !(enable & MWL8K_RADIO_FORCE)) + if (enable == priv->radio_on && !force) return 0; - enable &= MWL8K_RADIO_ENABLE; - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (cmd == NULL) return -ENOMEM; @@ -1752,11 +1748,21 @@ static int mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, int enable) kfree(cmd); if (!rc) - priv->radio_state = enable; + priv->radio_on = enable; return rc; } +static int mwl8k_cmd_802_11_radio_disable(struct ieee80211_hw *hw) +{ + return mwl8k_cmd_802_11_radio_control(hw, 0, 0); +} + +static int mwl8k_cmd_802_11_radio_enable(struct ieee80211_hw *hw) +{ + return mwl8k_cmd_802_11_radio_control(hw, 1, 0); +} + static int mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble) { @@ -1770,8 +1776,7 @@ mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble) MWL8K_RADIO_SHORT_PREAMBLE : MWL8K_RADIO_LONG_PREAMBLE); - return mwl8k_cmd_802_11_radio_control(hw, - MWL8K_RADIO_ENABLE | MWL8K_RADIO_FORCE); + return mwl8k_cmd_802_11_radio_control(hw, 1, 1); } /* @@ -2483,7 +2488,7 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) if (status & MWL8K_A2H_INT_QUEUE_EMPTY) { if (!priv->inconfig && - priv->radio_state && + priv->radio_on && mwl8k_txq_busy(priv)) mwl8k_tx_start(priv); } @@ -2661,7 +2666,7 @@ static void mwl8k_config_thread(struct work_struct *wt) spin_lock_irq(&priv->tx_lock); priv->inconfig = false; - if (priv->pending_tx_pkts && priv->radio_state) + if (priv->pending_tx_pkts && priv->radio_on) mwl8k_tx_start(priv); spin_unlock_irq(&priv->tx_lock); ieee80211_wake_queues(hw); @@ -2745,7 +2750,7 @@ static int mwl8k_start_wt(struct work_struct *wt) } /* Turn on radio */ - if (mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_ENABLE)) { + if (mwl8k_cmd_802_11_radio_enable(hw)) { rc = -EIO; goto mwl8k_start_exit; } @@ -2839,11 +2844,8 @@ static int mwl8k_stop_wt(struct work_struct *wt) { struct mwl8k_stop_worker *worker = (struct mwl8k_stop_worker *)wt; struct ieee80211_hw *hw = worker->header.hw; - int rc; - - rc = mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_DISABLE); - return rc; + return mwl8k_cmd_802_11_radio_disable(hw); } static void mwl8k_stop(struct ieee80211_hw *hw) @@ -2958,7 +2960,7 @@ static int mwl8k_config_wt(struct work_struct *wt) struct mwl8k_priv *priv = hw->priv; int rc = 0; - if (mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_ENABLE)) { + if (mwl8k_cmd_802_11_radio_enable(hw)) { rc = -EINVAL; goto mwl8k_config_exit; } @@ -3503,7 +3505,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, /* Set default radio state and preamble */ priv->radio_preamble = MWL8K_RADIO_DEFAULT_PREAMBLE; - priv->radio_state = MWL8K_RADIO_DISABLE; + priv->radio_on = 0; /* Finalize join worker */ INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); @@ -3584,7 +3586,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, } /* Turn radio off */ - rc = mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_DISABLE); + rc = mwl8k_cmd_802_11_radio_disable(hw); if (rc) { printk(KERN_ERR "%s: Cannot disable\n", priv->name); goto err_stop_firmware; -- cgit v1.2.3-18-g5258 From 68ce38845c23443b15e374fb7362916c1231278e Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 12:26:57 +0200 Subject: mwl8k: remove MWL8K_RADIO_*_PREAMBLE defines Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 78183c8b5f0..22500bf59d1 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -187,9 +187,7 @@ struct mwl8k_priv { struct ieee80211_rate rates[12]; bool radio_on; - - /* RF preamble: Short, Long or Auto */ - u8 radio_preamble; + bool radio_short_preamble; /* WMM MODE 1 for enabled; 0 for disabled */ bool wmm_mode; @@ -278,17 +276,10 @@ static const struct ieee80211_rate mwl8k_rates[] = { { .bitrate = 540, .hw_value = 108, }, }; -/* Radio settings */ -#define MWL8K_RADIO_AUTO_PREAMBLE 0x0005 -#define MWL8K_RADIO_SHORT_PREAMBLE 0x0003 -#define MWL8K_RADIO_LONG_PREAMBLE 0x0001 - /* WMM */ #define MWL8K_WMM_ENABLE 1 #define MWL8K_WMM_DISABLE 0 -#define MWL8K_RADIO_DEFAULT_PREAMBLE MWL8K_RADIO_LONG_PREAMBLE - /* Slot time */ /* Short Slot: 9us slot time */ @@ -1741,7 +1732,7 @@ mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, bool enable, bool force) cmd->header.code = cpu_to_le16(MWL8K_CMD_RADIO_CONTROL); cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->action = cpu_to_le16(MWL8K_CMD_SET); - cmd->control = cpu_to_le16(priv->radio_preamble); + cmd->control = cpu_to_le16(priv->radio_short_preamble ? 3 : 1); cmd->radio_on = cpu_to_le16(enable ? 0x0001 : 0x0000); rc = mwl8k_post_cmd(hw, &cmd->header); @@ -1772,9 +1763,7 @@ mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble) return -EINVAL; priv = hw->priv; - priv->radio_preamble = (short_preamble ? - MWL8K_RADIO_SHORT_PREAMBLE : - MWL8K_RADIO_LONG_PREAMBLE); + priv->radio_short_preamble = short_preamble; return mwl8k_cmd_802_11_radio_control(hw, 1, 1); } @@ -3051,8 +3040,7 @@ static int mwl8k_bss_info_changed_wt(struct work_struct *wt) goto mwl8k_bss_info_changed_exit; /* Set radio preamble */ - if (mwl8k_set_radio_preamble(hw, - info->use_short_preamble)) + if (mwl8k_set_radio_preamble(hw, info->use_short_preamble)) goto mwl8k_bss_info_changed_exit; /* Set slot time */ @@ -3504,8 +3492,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, priv->vif = NULL; /* Set default radio state and preamble */ - priv->radio_preamble = MWL8K_RADIO_DEFAULT_PREAMBLE; priv->radio_on = 0; + priv->radio_short_preamble = 0; /* Finalize join worker */ INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); -- cgit v1.2.3-18-g5258 From 0439b1f55646ea944b0d58337f5065b79a1c1be0 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 12:34:02 +0200 Subject: mwl8k: remove MWL8K_WMM_* defines Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 22500bf59d1..33d7ab517b3 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -188,9 +188,7 @@ struct mwl8k_priv { bool radio_on; bool radio_short_preamble; - - /* WMM MODE 1 for enabled; 0 for disabled */ - bool wmm_mode; + bool wmm_enabled; /* Set if PHY config is in progress */ bool inconfig; @@ -276,10 +274,6 @@ static const struct ieee80211_rate mwl8k_rates[] = { { .bitrate = 540, .hw_value = 108, }, }; -/* WMM */ -#define MWL8K_WMM_ENABLE 1 -#define MWL8K_WMM_DISABLE 0 - /* Slot time */ /* Short Slot: 9us slot time */ @@ -2028,13 +2022,13 @@ static int mwl8k_set_wmm(struct ieee80211_hw *hw, bool enable) cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_WMM_MODE); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = enable ? cpu_to_le16(MWL8K_CMD_SET) : 0; + cmd->action = cpu_to_le16(!!enable); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); if (!rc) - priv->wmm_mode = enable; + priv->wmm_enabled = enable; return rc; } @@ -2762,7 +2756,7 @@ static int mwl8k_start_wt(struct work_struct *wt) } /* Disable WMM. WMM gets enabled when stack sends WMM parms */ - if (mwl8k_set_wmm(hw, MWL8K_WMM_DISABLE)) { + if (mwl8k_set_wmm(hw, 0)) { rc = -EIO; goto mwl8k_start_exit; } @@ -3272,10 +3266,11 @@ static int mwl8k_conf_tx_wt(struct work_struct *wt) struct mwl8k_priv *priv = hw->priv; int rc = 0; - if (priv->wmm_mode == MWL8K_WMM_DISABLE) - if (mwl8k_set_wmm(hw, MWL8K_WMM_ENABLE)) { + if (!priv->wmm_enabled) { + if (mwl8k_set_wmm(hw, 1)) { rc = -EINVAL; goto mwl8k_conf_tx_exit; + } } if (mwl8k_set_edca_params(hw, GET_TXQ(queue), params->cw_min, @@ -3446,7 +3441,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, priv->hostcmd_wait = NULL; priv->tx_wait = NULL; priv->inconfig = false; - priv->wmm_mode = false; + priv->wmm_enabled = false; priv->pending_tx_pkts = 0; strncpy(priv->name, MWL8K_NAME, sizeof(priv->name)); -- cgit v1.2.3-18-g5258 From 5539bb51295f2c9300a6e467a29bb62bcfe9f4bc Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 16:06:53 +0200 Subject: mwl8k: remove MWL8K_*_SLOTTIME defines Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 33d7ab517b3..a40434b5572 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -274,14 +274,6 @@ static const struct ieee80211_rate mwl8k_rates[] = { { .bitrate = 540, .hw_value = 108, }, }; -/* Slot time */ - -/* Short Slot: 9us slot time */ -#define MWL8K_SHORT_SLOTTIME 1 - -/* Long slot: 20us slot time */ -#define MWL8K_LONG_SLOTTIME 0 - /* Set or get info from Firmware */ #define MWL8K_CMD_SET 0x0001 #define MWL8K_CMD_GET 0x0000 @@ -1895,7 +1887,7 @@ struct mwl8k_cmd_set_slot { __u8 short_slot; } __attribute__((packed)); -static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, int slot_time) +static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time) { struct mwl8k_cmd_set_slot *cmd; int rc; @@ -1907,7 +1899,7 @@ static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, int slot_time) cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT); cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->action = cpu_to_le16(MWL8K_CMD_SET); - cmd->short_slot = slot_time == MWL8K_SHORT_SLOTTIME ? 1 : 0; + cmd->short_slot = short_slot_time; rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -3038,8 +3030,7 @@ static int mwl8k_bss_info_changed_wt(struct work_struct *wt) goto mwl8k_bss_info_changed_exit; /* Set slot time */ - if (mwl8k_cmd_set_slot(hw, info->use_short_slot ? - MWL8K_SHORT_SLOTTIME : MWL8K_LONG_SLOTTIME)) + if (mwl8k_cmd_set_slot(hw, info->use_short_slot)) goto mwl8k_bss_info_changed_exit; /* Update peer rate info */ -- cgit v1.2.3-18-g5258 From e81cd2d664fe5b75a0db9bb24b43c0dfbde32319 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 18 Aug 2009 03:55:42 +0200 Subject: mwl8k: fix mwl8k_configure_filter() parameter lifetime issue mwl8k_configure_filter() passes pointers to total_flags and the multicast address list to a workqueue function, while there is no guarantee that those pointers will still be valid by the time the workqueue function runs. Solve this by passing total_flags by value, and by passing an already built multicast address setup command packet to the workqueue function so that we don't have to look at the multicast address list itself outside of mwl8k_configure_filter(). Also, since ->configure_filter() can sleep now, wait synchronously for the worker to finish. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 107 ++++++++++++++++--------------------------- 1 file changed, 39 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index a40434b5572..a961b698c69 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1613,38 +1613,39 @@ struct mwl8k_cmd_mac_multicast_adr { #define MWL8K_ENABLE_RX_MULTICAST 0x000F -static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, - int mc_count, - struct dev_addr_list *mclist) +static struct mwl8k_cmd_pkt * +__mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mclist) { + struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_mac_multicast_adr *cmd; - int index = 0; - int rc; - int size = sizeof(*cmd) + mc_count * ETH_ALEN; + int size; + int i; + + if (mc_count > priv->num_mcaddrs) + mc_count = priv->num_mcaddrs; + + size = sizeof(*cmd) + mc_count * ETH_ALEN; - cmd = kzalloc(size, GFP_KERNEL); + cmd = kzalloc(size, GFP_ATOMIC); if (cmd == NULL) - return -ENOMEM; + return NULL; cmd->header.code = cpu_to_le16(MWL8K_CMD_MAC_MULTICAST_ADR); cmd->header.length = cpu_to_le16(size); cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST); cmd->numaddr = cpu_to_le16(mc_count); - while (index < mc_count && mclist) { + for (i = 0; i < mc_count && mclist; i++) { if (mclist->da_addrlen != ETH_ALEN) { - rc = -EINVAL; - goto mwl8k_cmd_mac_multicast_adr_exit; + kfree(cmd); + return NULL; } - memcpy(cmd->addr[index++], mclist->da_addr, ETH_ALEN); + memcpy(cmd->addr[i], mclist->da_addr, ETH_ALEN); mclist = mclist->next; } - rc = mwl8k_post_cmd(hw, &cmd->header); - -mwl8k_cmd_mac_multicast_adr_exit: - kfree(cmd); - return rc; + return &cmd->header; } /* @@ -3091,12 +3092,21 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, printk(KERN_ERR "%s() timed out\n", __func__); } +static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, + int mc_count, struct dev_addr_list *mclist) +{ + struct mwl8k_cmd_pkt *cmd; + + cmd = __mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist); + + return (unsigned long)cmd; +} + struct mwl8k_configure_filter_worker { struct mwl8k_work_struct header; unsigned int changed_flags; - unsigned int *total_flags; - int mc_count; - struct dev_addr_list *mclist; + unsigned int total_flags; + struct mwl8k_cmd_pkt *multicast_adr_cmd; }; #define MWL8K_SUPPORTED_IF_FLAGS FIF_BCN_PRBRESP_PROMISC @@ -3105,18 +3115,12 @@ static int mwl8k_configure_filter_wt(struct work_struct *wt) { struct mwl8k_configure_filter_worker *worker = (struct mwl8k_configure_filter_worker *)wt; - struct ieee80211_hw *hw = worker->header.hw; - unsigned int changed_flags = worker->changed_flags; - unsigned int *total_flags = worker->total_flags; - int mc_count = worker->mc_count; - struct dev_addr_list *mclist = worker->mclist; - struct mwl8k_priv *priv = hw->priv; int rc = 0; - if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { - if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + if (worker->changed_flags & FIF_BCN_PRBRESP_PROMISC) { + if (worker->total_flags & FIF_BCN_PRBRESP_PROMISC) rc = mwl8k_cmd_set_pre_scan(hw); else { u8 *bssid; @@ -3129,54 +3133,20 @@ static int mwl8k_configure_filter_wt(struct work_struct *wt) } } - if (rc) - goto mwl8k_configure_filter_exit; - if (mc_count) { - if (mc_count > priv->num_mcaddrs) - mc_count = priv->num_mcaddrs; - - rc = mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist); - if (rc) - printk(KERN_ERR - "%s()Error setting multicast addresses\n", - __func__); - } + if (!rc && worker->multicast_adr_cmd != NULL) + rc = mwl8k_post_cmd(hw, worker->multicast_adr_cmd); + kfree(worker->multicast_adr_cmd); -mwl8k_configure_filter_exit: return rc; } -static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, - int mc_count, struct dev_addr_list *mclist) -{ - struct mwl8k_configure_filter_worker *worker; - - worker = kzalloc(sizeof(*worker), GFP_ATOMIC); - - if (!worker) - return 0; - - /* - * XXX: This is _HORRIBLY_ broken!! - * - * No locking, the mclist pointer might be invalid as soon as this - * function returns, something in the list might be invalidated - * once we get to the worker, etc... - */ - worker->mc_count = mc_count; - worker->mclist = mclist; - - return (u64)worker; -} - static void mwl8k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, u64 multicast) { - - struct mwl8k_configure_filter_worker *worker = (void *)multicast; struct mwl8k_priv *priv = hw->priv; + struct mwl8k_configure_filter_worker *worker; /* Clear unsupported feature flags */ *total_flags &= MWL8K_SUPPORTED_IF_FLAGS; @@ -3184,12 +3154,13 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS)) return; + worker = kzalloc(sizeof(*worker), GFP_ATOMIC); if (worker == NULL) return; - worker->header.options = MWL8K_WQ_QUEUE_ONLY | MWL8K_WQ_TX_WAIT_EMPTY; worker->changed_flags = changed_flags; - worker->total_flags = total_flags; + worker->total_flags = *total_flags; + worker->multicast_adr_cmd = (void *)(unsigned long)multicast; mwl8k_queue_work(hw, &worker->header, priv->config_wq, mwl8k_configure_filter_wt); -- cgit v1.2.3-18-g5258 From 240e86efd60e6bc232a072273a7f7794bcb035e0 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 14:15:44 +0200 Subject: mwl8k: ->add_interface() is not called for monitor interfaces There is no need to check for NL80211_IFTYPE_MONITOR in ->add_interface(), as this function is never called for monitor interfaces. Also, there is no need to advertise this bit in our wiphy's ->interface_modes. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index a961b698c69..301d2a20d42 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2883,8 +2883,7 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, /* * We only support managed interfaces for now. */ - if (conf->type != NL80211_IFTYPE_STATION && - conf->type != NL80211_IFTYPE_MONITOR) + if (conf->type != NL80211_IFTYPE_STATION) return -EINVAL; /* Clean out driver private area */ @@ -3440,8 +3439,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, hw->queues = MWL8K_TX_QUEUES; - hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_MONITOR); + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); /* Set rssi and noise values to dBm */ hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; -- cgit v1.2.3-18-g5258 From 76266b2ad38c33fb2c1475cfeb35ed070adaba2b Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 11:07:09 +0200 Subject: mwl8k: dma header manipulations can't fail Adding and removing the DMA header that the mwl8k hardware requires on tx and provides on rx can never fail, since we are guaranteed to have enough headroom on the tx path to expand the packet, and we only ever shrink the packet on the rx path. (And on both paths we are guaranteed to be the only user of the skb we are handling.) This allows removing all of the skb clone handling in the tx and tx reclaim paths, and eliminates error checks in both the tx and rx paths, simplifying the code a bit more. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 83 +++++++------------------------------------- 1 file changed, 13 insertions(+), 70 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 301d2a20d42..5aa80420c0d 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -111,17 +111,6 @@ struct mwl8k_rx_queue { struct sk_buff **rx_skb; }; -struct mwl8k_skb { - /* - * The DMA engine requires a modification to the payload. - * If the skbuff is shared/cloned, it needs to be unshared. - * This method is used to ensure the stack always gets back - * the skbuff it sent for transmission. - */ - struct sk_buff *clone; - struct sk_buff *skb; -}; - struct mwl8k_tx_queue { /* hw transmits here */ int tx_head; @@ -132,7 +121,7 @@ struct mwl8k_tx_queue { struct ieee80211_tx_queue_stats tx_stats; struct mwl8k_tx_desc *tx_desc_area; dma_addr_t tx_desc_dma; - struct mwl8k_skb *tx_skb; + struct sk_buff **tx_skb; }; /* Pointers to the firmware data and meta information about it. */ @@ -714,12 +703,11 @@ struct mwl8k_dma_data { } __attribute__((packed)); /* Routines to add/remove DMA header from skb. */ -static inline int mwl8k_remove_dma_header(struct sk_buff *skb) +static inline void mwl8k_remove_dma_header(struct sk_buff *skb) { - struct mwl8k_dma_data *tr = (struct mwl8k_dma_data *)(skb->data); + struct mwl8k_dma_data *tr = (struct mwl8k_dma_data *)skb->data; void *dst, *src = &tr->wh; - __le16 fc = tr->wh.frame_control; - int hdrlen = ieee80211_hdrlen(fc); + int hdrlen = ieee80211_hdrlen(tr->wh.frame_control); u16 space = sizeof(struct mwl8k_dma_data) - hdrlen; dst = (void *)tr + space; @@ -727,11 +715,9 @@ static inline int mwl8k_remove_dma_header(struct sk_buff *skb) memmove(dst, src, hdrlen); skb_pull(skb, space); } - - return 0; } -static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb) +static inline void mwl8k_add_dma_header(struct sk_buff *skb) { struct ieee80211_hdr *wh; u32 hdrlen, pktlen; @@ -763,8 +749,6 @@ static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb) * This includes all crypto material including the MIC. */ tr->fwlen = cpu_to_le16(pktlen - hdrlen); - - return skb; } @@ -967,10 +951,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE); skb_put(skb, le16_to_cpu(rx_desc->pkt_len)); - if (mwl8k_remove_dma_header(skb)) { - dev_kfree_skb(skb); - continue; - } + mwl8k_remove_dma_header(skb); wh = (struct ieee80211_hdr *)skb->data; @@ -1224,7 +1205,6 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) while (txq->tx_stats.len > 0) { int tx; - int rc; struct mwl8k_tx_desc *tx_desc; unsigned long addr; int size; @@ -1232,7 +1212,6 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) struct ieee80211_tx_info *info; u32 status; - rc = 0; tx = txq->tx_head; tx_desc = txq->tx_desc_area + tx; @@ -1252,40 +1231,18 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) addr = le32_to_cpu(tx_desc->pkt_phys_addr); size = le16_to_cpu(tx_desc->pkt_len); - skb = txq->tx_skb[tx].skb; - txq->tx_skb[tx].skb = NULL; + skb = txq->tx_skb[tx]; + txq->tx_skb[tx] = NULL; BUG_ON(skb == NULL); pci_unmap_single(priv->pdev, addr, size, PCI_DMA_TODEVICE); - rc = mwl8k_remove_dma_header(skb); + mwl8k_remove_dma_header(skb); /* Mark descriptor as unused */ tx_desc->pkt_phys_addr = 0; tx_desc->pkt_len = 0; - if (txq->tx_skb[tx].clone) { - /* Replace with original skb - * before returning to stack - * as buffer has been cloned - */ - dev_kfree_skb(skb); - skb = txq->tx_skb[tx].clone; - txq->tx_skb[tx].clone = NULL; - } - - if (rc) { - /* Something has gone wrong here. - * Failed to remove DMA header. - * Print error message and drop packet. - */ - printk(KERN_ERR "%s: Error removing DMA header from " - "tx skb 0x%p.\n", priv->name, skb); - - dev_kfree_skb(skb); - continue; - } - info = IEEE80211_SKB_CB(skb); ieee80211_tx_info_clear_status(info); if (MWL8K_TXD_SUCCESS(status)) @@ -1327,7 +1284,6 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) struct mwl8k_tx_desc *tx; struct mwl8k_dma_data *tr; struct mwl8k_vif *mwl8k_vif; - struct sk_buff *org_skb = skb; dma_addr_t dma; u16 qos = 0; bool qosframe = false, ampduframe = false; @@ -1338,21 +1294,12 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) txq = priv->txq + index; tx = txq->tx_desc_area + txq->tx_tail; - BUG_ON(txq->tx_skb[txq->tx_tail].skb != NULL); + BUG_ON(txq->tx_skb[txq->tx_tail] != NULL); /* - * Append HW DMA header to start of packet. Drop packet if - * there is not enough space or a failure to unshare/unclone - * the skb. + * Append HW DMA header to start of packet. */ - skb = mwl8k_add_dma_header(skb); - - if (skb == NULL) { - printk(KERN_DEBUG "%s: failed to prepend HW DMA " - "header, dropping TX frame.\n", priv->name); - dev_kfree_skb(org_skb); - return NETDEV_TX_OK; - } + mwl8k_add_dma_header(skb); tx_info = IEEE80211_SKB_CB(skb); mwl8k_vif = MWL8K_VIF(tx_info->control.vif); @@ -1380,8 +1327,6 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) printk(KERN_DEBUG "%s: failed to dma map skb, " "dropping TX frame.\n", priv->name); - if (org_skb != NULL) - dev_kfree_skb(org_skb); if (skb != NULL) dev_kfree_skb(skb); return NETDEV_TX_OK; @@ -1437,9 +1382,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) tx->pkt_phys_addr = cpu_to_le32(dma); tx->pkt_len = cpu_to_le16(skb->len); - txq->tx_skb[txq->tx_tail].skb = skb; - txq->tx_skb[txq->tx_tail].clone = - skb == org_skb ? NULL : org_skb; + txq->tx_skb[txq->tx_tail] = skb; spin_lock_bh(&priv->tx_lock); -- cgit v1.2.3-18-g5258 From d4b7057052236e81ab0788cc8df306dc02b0e7be Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 16 Jul 2009 12:44:45 +0200 Subject: mwl8k: don't touch 'command done' interrupt during firmware load Since firmware load commands don't generate 'command done' interrupts like normal commands do, polling for command done interrupts just unnecessarily slows down the firmware load process. Removing this bit of code speeds up loading a typical firmware image from 840 msec to 180 msec. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 5aa80420c0d..cc0aa80ca87 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -411,7 +411,6 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length) { void __iomem *regs = priv->regs; dma_addr_t dma_addr; - int rc; int loops; dma_addr = pci_map_single(priv->pdev, data, length, PCI_DMA_TODEVICE); @@ -425,7 +424,6 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length) iowrite32(MWL8K_H2A_INT_DUMMY, regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); - rc = -ETIMEDOUT; loops = 1000; do { u32 int_code; @@ -433,7 +431,6 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length) int_code = ioread32(regs + MWL8K_HIU_INT_CODE); if (int_code == MWL8K_INT_CODE_CMD_FINISHED) { iowrite32(0, regs + MWL8K_HIU_INT_CODE); - rc = 0; break; } @@ -442,26 +439,7 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length) pci_unmap_single(priv->pdev, dma_addr, length, PCI_DMA_TODEVICE); - /* - * Clear 'command done' interrupt bit. - */ - loops = 1000; - do { - u32 status; - - status = ioread32(priv->regs + - MWL8K_HIU_A2H_INTERRUPT_STATUS); - if (status & MWL8K_A2H_INT_OPC_DONE) { - iowrite32(~MWL8K_A2H_INT_OPC_DONE, - priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); - ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); - break; - } - - udelay(1); - } while (--loops); - - return rc; + return loops ? 0 : -ETIMEDOUT; } static int mwl8k_load_fw_image(struct mwl8k_priv *priv, -- cgit v1.2.3-18-g5258 From c3f967d301a76b7053d16817c34191964c457566 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 18 Aug 2009 04:15:22 +0200 Subject: mwl8k: don't hardcode the number of transmit queues Use MWL8K_TX_QUEUES instead of a hardcoded "4" in a couple of places. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index cc0aa80ca87..0281e70cec8 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1080,17 +1080,17 @@ struct mwl8k_txq_info { }; static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv, - struct mwl8k_txq_info txinfo[], - u32 num_queues) + struct mwl8k_txq_info *txinfo) { int count, desc, status; struct mwl8k_tx_queue *txq; struct mwl8k_tx_desc *tx_desc; int ndescs = 0; - memset(txinfo, 0, num_queues * sizeof(struct mwl8k_txq_info)); + memset(txinfo, 0, MWL8K_TX_QUEUES * sizeof(struct mwl8k_txq_info)); + spin_lock_bh(&priv->tx_lock); - for (count = 0; count < num_queues; count++) { + for (count = 0; count < MWL8K_TX_QUEUES; count++) { txq = priv->txq + count; txinfo[count].len = txq->tx_stats.len; txinfo[count].head = txq->tx_head; @@ -1135,7 +1135,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) spin_unlock_bh(&priv->tx_lock); if (count) { - struct mwl8k_txq_info txinfo[4]; + struct mwl8k_txq_info txinfo[MWL8K_TX_QUEUES]; int index; int newcount; @@ -1152,8 +1152,8 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) printk(KERN_ERR "%s(%u) TIMEDOUT:%ums Pend:%u-->%u\n", __func__, __LINE__, delay_ms, count, newcount); - mwl8k_scan_tx_ring(priv, txinfo, 4); - for (index = 0; index < 4; index++) + mwl8k_scan_tx_ring(priv, txinfo); + for (index = 0; index < MWL8K_TX_QUEUES; index++) printk(KERN_ERR "TXQ:%u L:%u H:%u T:%u FW:%u DRV:%u U:%u\n", index, -- cgit v1.2.3-18-g5258 From 361c55cfaddaa36f0997c5a96948ba5888bfb992 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 18 Aug 2009 04:19:00 +0200 Subject: mwl8k: no need to hold ->tx_lock while setting the hardware interrupt mask Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 0281e70cec8..177d92f0b87 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2768,9 +2768,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw) printk(KERN_ERR "%s() timed out\n", __func__); /* Disable interrupts */ - spin_lock_irq(&priv->tx_lock); iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - spin_unlock_irq(&priv->tx_lock); free_irq(priv->pdev->irq, hw); /* Stop finalize join worker */ @@ -3457,9 +3455,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, } /* Disable interrupts */ - spin_lock_irq(&priv->tx_lock); iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - spin_unlock_irq(&priv->tx_lock); free_irq(priv->pdev->irq, hw); rc = ieee80211_register_hw(hw); @@ -3483,9 +3479,7 @@ err_stop_firmware: mwl8k_release_firmware(priv); err_free_irq: - spin_lock_irq(&priv->tx_lock); iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - spin_unlock_irq(&priv->tx_lock); free_irq(priv->pdev->irq, hw); err_free_queues: -- cgit v1.2.3-18-g5258 From 7595d67a06466cc00e3aae1b86544278b57481ee Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 17 Aug 2009 23:59:40 +0200 Subject: mwl8k: implement idle mode Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 177d92f0b87..65eefe83502 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2854,6 +2854,12 @@ static int mwl8k_config_wt(struct work_struct *wt) struct mwl8k_priv *priv = hw->priv; int rc = 0; + if (conf->flags & IEEE80211_CONF_IDLE) { + mwl8k_cmd_802_11_radio_disable(hw); + priv->current_channel = NULL; + goto mwl8k_config_exit; + } + if (mwl8k_cmd_802_11_radio_enable(hw)) { rc = -EINVAL; goto mwl8k_config_exit; -- cgit v1.2.3-18-g5258 From 23b339062f247e0be84eaabb15e17b403c4388b6 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 17 Jul 2009 05:21:04 +0200 Subject: mwl8k: mwl8k_txq_xmit() rework Various mwl8k_txq_xmit changes: - Extract the QoS field before adding the DMA header. - Only write to tx->status once, and only after all the other descriptor fields have been set. - Do all tx state manipulation under the tx spinlock. - Remove the priv->inconfig check, as all transmit queues will be frozen during config cycles, so we won't ever be asked to transmit if a config cycle is running. - Remove some more dead code. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 145 ++++++++++++++++--------------------------- 1 file changed, 52 insertions(+), 93 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 65eefe83502..88ba52e13af 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1257,46 +1257,60 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) { struct mwl8k_priv *priv = hw->priv; struct ieee80211_tx_info *tx_info; + struct mwl8k_vif *mwl8k_vif; struct ieee80211_hdr *wh; struct mwl8k_tx_queue *txq; struct mwl8k_tx_desc *tx; - struct mwl8k_dma_data *tr; - struct mwl8k_vif *mwl8k_vif; dma_addr_t dma; - u16 qos = 0; - bool qosframe = false, ampduframe = false; - bool mcframe = false, eapolframe = false; - bool amsduframe = false; - __le16 fc; + u32 txstatus; + u8 txdatarate; + u16 qos; - txq = priv->txq + index; - tx = txq->tx_desc_area + txq->tx_tail; - - BUG_ON(txq->tx_skb[txq->tx_tail] != NULL); + wh = (struct ieee80211_hdr *)skb->data; + if (ieee80211_is_data_qos(wh->frame_control)) + qos = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(wh))); + else + qos = 0; - /* - * Append HW DMA header to start of packet. - */ mwl8k_add_dma_header(skb); + wh = &((struct mwl8k_dma_data *)skb->data)->wh; tx_info = IEEE80211_SKB_CB(skb); mwl8k_vif = MWL8K_VIF(tx_info->control.vif); - tr = (struct mwl8k_dma_data *)skb->data; - wh = &tr->wh; - fc = wh->frame_control; - qosframe = ieee80211_is_data_qos(fc); - mcframe = is_multicast_ether_addr(wh->addr1); - ampduframe = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU); if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { u16 seqno = mwl8k_vif->seqno; + wh->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); wh->seq_ctrl |= cpu_to_le16(seqno << 4); mwl8k_vif->seqno = seqno++ % 4096; } - if (qosframe) - qos = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(wh))); + /* Setup firmware control bit fields for each frame type. */ + txstatus = 0; + txdatarate = 0; + if (ieee80211_is_mgmt(wh->frame_control) || + ieee80211_is_ctl(wh->frame_control)) { + txdatarate = 0; + qos = mwl8k_qos_setbit_eosp(qos); + /* Set Queue size to unspecified */ + qos = mwl8k_qos_setbit_qlen(qos, 0xff); + } else if (ieee80211_is_data(wh->frame_control)) { + txdatarate = 1; + if (is_multicast_ether_addr(wh->addr1)) + txstatus |= MWL8K_TXD_STATUS_MULTICAST_TX; + + /* Send pkt in an aggregate if AMPDU frame. */ + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) + qos = mwl8k_qos_setbit_ack(qos, + MWL8K_TXD_ACK_POLICY_BLOCKACK); + else + qos = mwl8k_qos_setbit_ack(qos, + MWL8K_TXD_ACK_POLICY_NORMAL); + + if (qos & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) + qos = mwl8k_qos_setbit_amsdu(qos); + } dma = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); @@ -1304,95 +1318,40 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) if (pci_dma_mapping_error(priv->pdev, dma)) { printk(KERN_DEBUG "%s: failed to dma map skb, " "dropping TX frame.\n", priv->name); - - if (skb != NULL) - dev_kfree_skb(skb); + dev_kfree_skb(skb); return NETDEV_TX_OK; } - /* Set desc header, cpu bit order. */ - tx->status = 0; - tx->data_rate = 0; - tx->tx_priority = index; - tx->qos_control = 0; - tx->rate_info = 0; - tx->peer_id = mwl8k_vif->peer_id; - - amsduframe = !!(qos & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT); - - /* Setup firmware control bit fields for each frame type. */ - if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) { - tx->data_rate = 0; - qos = mwl8k_qos_setbit_eosp(qos); - /* Set Queue size to unspecified */ - qos = mwl8k_qos_setbit_qlen(qos, 0xff); - } else if (ieee80211_is_data(fc)) { - tx->data_rate = 1; - if (mcframe) - tx->status |= MWL8K_TXD_STATUS_MULTICAST_TX; + spin_lock_bh(&priv->tx_lock); - /* - * Tell firmware to not send EAPOL pkts in an - * aggregate. Verify against mac80211 tx path. If - * stack turns off AMPDU for an EAPOL frame this - * check will be removed. - */ - if (eapolframe) { - qos = mwl8k_qos_setbit_ack(qos, - MWL8K_TXD_ACK_POLICY_NORMAL); - } else { - /* Send pkt in an aggregate if AMPDU frame. */ - if (ampduframe) - qos = mwl8k_qos_setbit_ack(qos, - MWL8K_TXD_ACK_POLICY_BLOCKACK); - else - qos = mwl8k_qos_setbit_ack(qos, - MWL8K_TXD_ACK_POLICY_NORMAL); + txq = priv->txq + index; - if (amsduframe) - qos = mwl8k_qos_setbit_amsdu(qos); - } - } + BUG_ON(txq->tx_skb[txq->tx_tail] != NULL); + txq->tx_skb[txq->tx_tail] = skb; - /* Convert to little endian */ + tx = txq->tx_desc_area + txq->tx_tail; + tx->data_rate = txdatarate; + tx->tx_priority = index; tx->qos_control = cpu_to_le16(qos); - tx->status = cpu_to_le32(tx->status); tx->pkt_phys_addr = cpu_to_le32(dma); tx->pkt_len = cpu_to_le16(skb->len); - - txq->tx_skb[txq->tx_tail] = skb; - - spin_lock_bh(&priv->tx_lock); - - tx->status = cpu_to_le32(MWL8K_TXD_STATUS_OK | - MWL8K_TXD_STATUS_FW_OWNED); + tx->rate_info = 0; + tx->peer_id = mwl8k_vif->peer_id; wmb(); + tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); + + txq->tx_stats.count++; txq->tx_stats.len++; priv->pending_tx_pkts++; - txq->tx_stats.count++; - txq->tx_tail++; + txq->tx_tail++; if (txq->tx_tail == MWL8K_TX_DESCS) txq->tx_tail = 0; + if (txq->tx_head == txq->tx_tail) ieee80211_stop_queue(hw, index); - if (priv->inconfig) { - /* - * Silently queue packet when we are in the middle of - * a config cycle. Notify firmware only if we are - * waiting for TXQs to empty. If a packet is sent - * before .config() is complete, perhaps it is better - * to drop the packet, as the channel is being changed - * and the packet will end up on the wrong channel. - */ - printk(KERN_ERR "%s(): WARNING TX activity while " - "in config\n", __func__); - - if (priv->tx_wait != NULL) - mwl8k_tx_start(priv); - } else - mwl8k_tx_start(priv); + mwl8k_tx_start(priv); spin_unlock_bh(&priv->tx_lock); -- cgit v1.2.3-18-g5258 From 950d5b0191dc3e71017f336017f75f6189f39f08 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 17 Jul 2009 01:48:41 +0200 Subject: mwl8k: mwl8k_queue_work() cleanup Delete most of the mwl8k_work_struct fields and options, since most of them are unused or never changed from their defaults: - We always use priv->config_wq, so delete the wqueue argument from mwl8k_queue_work(). - MWL8K_WQ_SPIN and MWL8K_WQ_POST_REQUEST are never used, as all callers sleep for request completion, so sleep unconditionally. - MWL8K_WQ_FREE_WORKSTRUCT is never used. - MWL8K_WQ_TX_WAIT_EMPTY is always set, so assume it unconditionally. - timeout_ms/txwait_attempts/tx_timeout_ms are never changed from their defaults, so just hardcode these in the workqueue worker. - step is never used. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 204 +++++++------------------------------------ 1 file changed, 33 insertions(+), 171 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 88ba52e13af..7bbdca41831 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1113,7 +1113,7 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv, return ndescs; } -static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) +static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) { struct mwl8k_priv *priv = hw->priv; DECLARE_COMPLETION_ONSTACK(cmd_wait); @@ -1140,7 +1140,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) int newcount; timeout = wait_for_completion_timeout(&cmd_wait, - msecs_to_jiffies(delay_ms)); + msecs_to_jiffies(1000)); if (timeout) return 0; @@ -1149,8 +1149,8 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms) newcount = mwl8k_txq_busy(priv); spin_unlock_bh(&priv->tx_lock); - printk(KERN_ERR "%s(%u) TIMEDOUT:%ums Pend:%u-->%u\n", - __func__, __LINE__, delay_ms, count, newcount); + printk(KERN_ERR "%s(%u) TIMEDOUT:1000ms Pend:%u-->%u\n", + __func__, __LINE__, count, newcount); mwl8k_scan_tx_ring(priv, txinfo); for (index = 0; index < MWL8K_TX_QUEUES; index++) @@ -2389,84 +2389,15 @@ struct mwl8k_work_struct { /* Result code. */ int rc; - - /* - * Optional field. Refer to explanation of MWL8K_WQ_XXX_XXX - * flags for explanation. Defaults to MWL8K_WQ_DEFAULT_OPTIONS. - */ - u32 options; - - /* Optional field. Defaults to MWL8K_CONFIG_TIMEOUT_MS. */ - unsigned long timeout_ms; - - /* Optional field. Defaults to MWL8K_WQ_TXWAIT_ATTEMPTS. */ - u32 txwait_attempts; - - /* Optional field. Defaults to MWL8K_TXWAIT_MS. */ - u32 tx_timeout_ms; - u32 step; }; -/* Flags controlling behavior of config queue requests */ - -/* Caller spins while waiting for completion. */ -#define MWL8K_WQ_SPIN 0x00000001 - -/* Wait for TX queues to empty before proceeding with configuration. */ -#define MWL8K_WQ_TX_WAIT_EMPTY 0x00000002 - -/* Queue request and return immediately. */ -#define MWL8K_WQ_POST_REQUEST 0x00000004 - -/* - * Caller sleeps and waits for task complete notification. - * Do not use in atomic context. - */ -#define MWL8K_WQ_SLEEP 0x00000008 - -/* Free work struct when task is done. */ -#define MWL8K_WQ_FREE_WORKSTRUCT 0x00000010 - -/* - * Config request is queued and returns to caller imediately. Use - * this in atomic context. Work struct is freed by mwl8k_queue_work() - * when this flag is set. - */ -#define MWL8K_WQ_QUEUE_ONLY (MWL8K_WQ_POST_REQUEST | \ - MWL8K_WQ_FREE_WORKSTRUCT) - -/* Default work queue behavior is to sleep and wait for tx completion. */ -#define MWL8K_WQ_DEFAULT_OPTIONS (MWL8K_WQ_SLEEP | MWL8K_WQ_TX_WAIT_EMPTY) - -/* - * Default config request timeout. Add adjustments to make sure the - * config thread waits long enough for both tx wait and cmd wait before - * timing out. - */ - -/* Time to wait for all TXQs to drain. TX Doorbell is pressed each time. */ -#define MWL8K_TXWAIT_TIMEOUT_MS 1000 - -/* Default number of TX wait attempts. */ -#define MWL8K_WQ_TXWAIT_ATTEMPTS 4 - -/* Total time to wait for TXQ to drain. */ -#define MWL8K_TXWAIT_MS (MWL8K_TXWAIT_TIMEOUT_MS * \ - MWL8K_WQ_TXWAIT_ATTEMPTS) - -/* Scheduling slop. */ -#define MWL8K_OS_SCHEDULE_OVERHEAD_MS 200 - -#define MWL8K_CONFIG_TIMEOUT_MS (MWL8K_CMD_TIMEOUT_MS + \ - MWL8K_TXWAIT_MS + \ - MWL8K_OS_SCHEDULE_OVERHEAD_MS) - static void mwl8k_config_thread(struct work_struct *wt) { struct mwl8k_work_struct *worker = (struct mwl8k_work_struct *)wt; struct ieee80211_hw *hw = worker->hw; struct mwl8k_priv *priv = hw->priv; int rc = 0; + int iter; spin_lock_irq(&priv->tx_lock); priv->inconfig = true; @@ -2479,44 +2410,16 @@ static void mwl8k_config_thread(struct work_struct *wt) * reconfiguration. This avoids interrupting any in-flight * DMA transfers to the hardware. */ - if (worker->options & MWL8K_WQ_TX_WAIT_EMPTY) { - u32 timeout; - u32 time_remaining; - u32 iter; - u32 tx_wait_attempts = worker->txwait_attempts; - - time_remaining = worker->tx_timeout_ms; - if (!tx_wait_attempts) - tx_wait_attempts = 1; - - timeout = worker->tx_timeout_ms/tx_wait_attempts; - if (!timeout) - timeout = 1; - - iter = tx_wait_attempts; - do { - int wait_time; - - if (time_remaining > timeout) { - time_remaining -= timeout; - wait_time = timeout; - } else - wait_time = time_remaining; - - if (!wait_time) - wait_time = 1; - - rc = mwl8k_tx_wait_empty(hw, wait_time); - if (rc) - printk(KERN_ERR "%s() txwait timeout=%ums " - "Retry:%u/%u\n", __func__, timeout, - tx_wait_attempts - iter + 1, - tx_wait_attempts); + iter = 4; + do { + rc = mwl8k_tx_wait_empty(hw); + if (rc) + printk(KERN_ERR "%s() txwait timeout=1000ms " + "Retry:%u/%u\n", __func__, 4 - iter + 1, 4); + } while (rc && --iter); - } while (rc && --iter); + rc = iter ? 0 : -ETIMEDOUT; - rc = iter ? 0 : -ETIMEDOUT; - } if (!rc) rc = worker->wfunc(wt); @@ -2525,65 +2428,39 @@ static void mwl8k_config_thread(struct work_struct *wt) if (priv->pending_tx_pkts && priv->radio_on) mwl8k_tx_start(priv); spin_unlock_irq(&priv->tx_lock); + ieee80211_wake_queues(hw); worker->rc = rc; - if (worker->options & MWL8K_WQ_SLEEP) - complete(worker->cmd_wait); - - if (worker->options & MWL8K_WQ_FREE_WORKSTRUCT) - kfree(wt); + complete(worker->cmd_wait); } static int mwl8k_queue_work(struct ieee80211_hw *hw, struct mwl8k_work_struct *worker, - struct workqueue_struct *wqueue, int (*wfunc)(struct work_struct *w)) { + struct mwl8k_priv *priv = hw->priv; unsigned long timeout = 0; int rc = 0; DECLARE_COMPLETION_ONSTACK(cmd_wait); - if (!worker->timeout_ms) - worker->timeout_ms = MWL8K_CONFIG_TIMEOUT_MS; - - if (!worker->options) - worker->options = MWL8K_WQ_DEFAULT_OPTIONS; - - if (!worker->txwait_attempts) - worker->txwait_attempts = MWL8K_WQ_TXWAIT_ATTEMPTS; - - if (!worker->tx_timeout_ms) - worker->tx_timeout_ms = MWL8K_TXWAIT_MS; - worker->hw = hw; worker->cmd_wait = &cmd_wait; worker->rc = 1; worker->wfunc = wfunc; INIT_WORK(&worker->wt, mwl8k_config_thread); - queue_work(wqueue, &worker->wt); + queue_work(priv->config_wq, &worker->wt); - if (worker->options & MWL8K_WQ_POST_REQUEST) { - rc = 0; - } else { - if (worker->options & MWL8K_WQ_SPIN) { - timeout = worker->timeout_ms; - while (timeout && (worker->rc > 0)) { - mdelay(1); - timeout--; - } - } else if (worker->options & MWL8K_WQ_SLEEP) - timeout = wait_for_completion_timeout(&cmd_wait, - msecs_to_jiffies(worker->timeout_ms)); + timeout = wait_for_completion_timeout(&cmd_wait, + msecs_to_jiffies(10000)); - if (timeout) - rc = worker->rc; - else { - cancel_work_sync(&worker->wt); - rc = -ETIMEDOUT; - } + if (timeout) + rc = worker->rc; + else { + cancel_work_sync(&worker->wt); + rc = -ETIMEDOUT; } return rc; @@ -2669,8 +2546,7 @@ static int mwl8k_start(struct ieee80211_hw *hw) goto mwl8k_start_disable_irq; } - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, mwl8k_start_wt); + rc = mwl8k_queue_work(hw, &worker->header, mwl8k_start_wt); kfree(worker); if (!rc) return rc; @@ -2720,8 +2596,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw) if (worker == NULL) return; - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, mwl8k_stop_wt); + rc = mwl8k_queue_work(hw, &worker->header, mwl8k_stop_wt); kfree(worker); if (rc == -ETIMEDOUT) printk(KERN_ERR "%s() timed out\n", __func__); @@ -2849,15 +2724,14 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) { int rc = 0; struct mwl8k_config_worker *worker; - struct mwl8k_priv *priv = hw->priv; worker = kzalloc(sizeof(*worker), GFP_KERNEL); if (worker == NULL) return -ENOMEM; worker->changed = changed; - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, mwl8k_config_wt); + + rc = mwl8k_queue_work(hw, &worker->header, mwl8k_config_wt); if (rc == -ETIMEDOUT) { printk(KERN_ERR "%s() timed out.\n", __func__); rc = -EINVAL; @@ -2950,7 +2824,6 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, u32 changed) { struct mwl8k_bss_info_changed_worker *worker; - struct mwl8k_priv *priv = hw->priv; struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); int rc; @@ -2967,9 +2840,7 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, worker->vif = vif; worker->info = info; worker->changed = changed; - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, - mwl8k_bss_info_changed_wt); + rc = mwl8k_queue_work(hw, &worker->header, mwl8k_bss_info_changed_wt); kfree(worker); if (rc == -ETIMEDOUT) printk(KERN_ERR "%s() timed out\n", __func__); @@ -3028,7 +2899,6 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, unsigned int *total_flags, u64 multicast) { - struct mwl8k_priv *priv = hw->priv; struct mwl8k_configure_filter_worker *worker; /* Clear unsupported feature flags */ @@ -3045,8 +2915,7 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, worker->total_flags = *total_flags; worker->multicast_adr_cmd = (void *)(unsigned long)multicast; - mwl8k_queue_work(hw, &worker->header, priv->config_wq, - mwl8k_configure_filter_wt); + mwl8k_queue_work(hw, &worker->header, mwl8k_configure_filter_wt); } struct mwl8k_set_rts_threshold_worker { @@ -3072,7 +2941,6 @@ static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { int rc; struct mwl8k_set_rts_threshold_worker *worker; - struct mwl8k_priv *priv = hw->priv; worker = kzalloc(sizeof(*worker), GFP_KERNEL); if (worker == NULL) @@ -3080,9 +2948,7 @@ static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) worker->value = value; - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, - mwl8k_set_rts_threshold_wt); + rc = mwl8k_queue_work(hw, &worker->header, mwl8k_set_rts_threshold_wt); kfree(worker); if (rc == -ETIMEDOUT) { @@ -3130,7 +2996,6 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, { int rc; struct mwl8k_conf_tx_worker *worker; - struct mwl8k_priv *priv = hw->priv; worker = kzalloc(sizeof(*worker), GFP_KERNEL); if (worker == NULL) @@ -3138,8 +3003,7 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, worker->queue = queue; worker->params = params; - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, mwl8k_conf_tx_wt); + rc = mwl8k_queue_work(hw, &worker->header, mwl8k_conf_tx_wt); kfree(worker); if (rc == -ETIMEDOUT) { printk(KERN_ERR "%s() timed out\n", __func__); @@ -3183,15 +3047,13 @@ static int mwl8k_get_stats(struct ieee80211_hw *hw, { int rc; struct mwl8k_get_stats_worker *worker; - struct mwl8k_priv *priv = hw->priv; worker = kzalloc(sizeof(*worker), GFP_KERNEL); if (worker == NULL) return -ENOMEM; worker->stats = stats; - rc = mwl8k_queue_work(hw, &worker->header, - priv->config_wq, mwl8k_get_stats_wt); + rc = mwl8k_queue_work(hw, &worker->header, mwl8k_get_stats_wt); kfree(worker); if (rc == -ETIMEDOUT) { -- cgit v1.2.3-18-g5258 From 618952a7b19b796fce98364fb26551cbe3e16a75 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 18 Aug 2009 03:18:01 +0200 Subject: mwl8k: fix firmware command serialisation The current mwl8k_priv->fw_lock spinlock doesn't actually protect against multiple commands being submitted at once, as it is not kept held over the entire firmware command submission. And since waiting for command completion sleeps, we can't use a spinlock anyway. To fix mwl8k firmware command serialisation properly, we have the following requirements: - Some commands require that the packet transmit path is idle when the command is issued. (For simplicity, we'll just quiesce the transmit path for every command.) - There are certain sequences of commands that need to be issued to the hardware sequentially, with no other intervening commands. This leads to an implementation of a "firmware lock" as a mutex that can be taken recursively, and which is taken by both the low-level command submission function (mwl8k_post_cmd) as well as any users of that function that require issuing of an atomic sequence of commands, and quiesces the transmit path whenever it's taken. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 154 +++++++++++++++++++++++++------------------ 1 file changed, 89 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 7bbdca41831..93b92680d07 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -139,13 +139,18 @@ struct mwl8k_priv { struct pci_dev *pdev; u8 name[16]; - /* firmware access lock */ - spinlock_t fw_lock; /* firmware files and meta data */ struct mwl8k_firmware fw; u32 part_num; + /* firmware access */ + struct mutex fw_mutex; + struct task_struct *fw_mutex_owner; + int fw_mutex_depth; + struct completion *tx_wait; + struct completion *hostcmd_wait; + /* lock held over TX and TX reap */ spinlock_t tx_lock; @@ -179,9 +184,6 @@ struct mwl8k_priv { bool radio_short_preamble; bool wmm_enabled; - /* Set if PHY config is in progress */ - bool inconfig; - /* XXX need to convert this to handle multiple interfaces */ bool capture_beacon; u8 capture_bssid[ETH_ALEN]; @@ -200,8 +202,6 @@ struct mwl8k_priv { /* Work thread to serialize configuration requests */ struct workqueue_struct *config_wq; - struct completion *hostcmd_wait; - struct completion *tx_wait; }; /* Per interface specific private data */ @@ -1113,6 +1113,9 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv, return ndescs; } +/* + * Must be called with hw->fw_mutex held and tx queues stopped. + */ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) { struct mwl8k_priv *priv = hw->priv; @@ -1122,9 +1125,6 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) might_sleep(); - if (priv->tx_wait != NULL) - printk(KERN_ERR "WARNING Previous TXWaitEmpty instance\n"); - spin_lock_bh(&priv->tx_lock); count = mwl8k_txq_busy(priv); if (count) { @@ -1140,7 +1140,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) int newcount; timeout = wait_for_completion_timeout(&cmd_wait, - msecs_to_jiffies(1000)); + msecs_to_jiffies(5000)); if (timeout) return 0; @@ -1149,7 +1149,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) newcount = mwl8k_txq_busy(priv); spin_unlock_bh(&priv->tx_lock); - printk(KERN_ERR "%s(%u) TIMEDOUT:1000ms Pend:%u-->%u\n", + printk(KERN_ERR "%s(%u) TIMEDOUT:5000ms Pend:%u-->%u\n", __func__, __LINE__, count, newcount); mwl8k_scan_tx_ring(priv, txinfo); @@ -1228,10 +1228,10 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) ieee80211_tx_status_irqsafe(hw, skb); - wake = !priv->inconfig && priv->radio_on; + wake = 1; } - if (wake) + if (wake && priv->radio_on && !mutex_is_locked(&priv->fw_mutex)) ieee80211_wake_queue(hw, index); } @@ -1359,6 +1359,60 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) } +/* + * Firmware access. + * + * We have the following requirements for issuing firmware commands: + * - Some commands require that the packet transmit path is idle when + * the command is issued. (For simplicity, we'll just quiesce the + * transmit path for every command.) + * - There are certain sequences of commands that need to be issued to + * the hardware sequentially, with no other intervening commands. + * + * This leads to an implementation of a "firmware lock" as a mutex that + * can be taken recursively, and which is taken by both the low-level + * command submission function (mwl8k_post_cmd) as well as any users of + * that function that require issuing of an atomic sequence of commands, + * and quiesces the transmit path whenever it's taken. + */ +static int mwl8k_fw_lock(struct ieee80211_hw *hw) +{ + struct mwl8k_priv *priv = hw->priv; + + if (priv->fw_mutex_owner != current) { + int rc; + + mutex_lock(&priv->fw_mutex); + ieee80211_stop_queues(hw); + + rc = mwl8k_tx_wait_empty(hw); + if (rc) { + ieee80211_wake_queues(hw); + mutex_unlock(&priv->fw_mutex); + + return rc; + } + + priv->fw_mutex_owner = current; + } + + priv->fw_mutex_depth++; + + return 0; +} + +static void mwl8k_fw_unlock(struct ieee80211_hw *hw) +{ + struct mwl8k_priv *priv = hw->priv; + + if (!--priv->fw_mutex_depth) { + ieee80211_wake_queues(hw); + priv->fw_mutex_owner = NULL; + mutex_unlock(&priv->fw_mutex); + } +} + + /* * Command processing. */ @@ -1384,28 +1438,28 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) if (pci_dma_mapping_error(priv->pdev, dma_addr)) return -ENOMEM; - if (priv->hostcmd_wait != NULL) - printk(KERN_ERR "WARNING host command in progress\n"); + rc = mwl8k_fw_lock(hw); + if (rc) + return rc; - spin_lock_irq(&priv->fw_lock); priv->hostcmd_wait = &cmd_wait; iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR); iowrite32(MWL8K_H2A_INT_DOORBELL, regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); iowrite32(MWL8K_H2A_INT_DUMMY, regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); - spin_unlock_irq(&priv->fw_lock); timeout = wait_for_completion_timeout(&cmd_wait, msecs_to_jiffies(MWL8K_CMD_TIMEOUT_MS)); + priv->hostcmd_wait = NULL; + + mwl8k_fw_unlock(hw); + pci_unmap_single(priv->pdev, dma_addr, dma_size, PCI_DMA_BIDIRECTIONAL); if (!timeout) { - spin_lock_irq(&priv->fw_lock); - priv->hostcmd_wait = NULL; - spin_unlock_irq(&priv->fw_lock); printk(KERN_ERR "%s: Command %s timeout after %u ms\n", priv->name, mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), @@ -2336,17 +2390,14 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) } if (status & MWL8K_A2H_INT_OPC_DONE) { - if (priv->hostcmd_wait != NULL) { + if (priv->hostcmd_wait != NULL) complete(priv->hostcmd_wait); - priv->hostcmd_wait = NULL; - } } if (status & MWL8K_A2H_INT_QUEUE_EMPTY) { - if (!priv->inconfig && - priv->radio_on && - mwl8k_txq_busy(priv)) - mwl8k_tx_start(priv); + if (!mutex_is_locked(&priv->fw_mutex) && + priv->radio_on && mwl8k_txq_busy(priv)) + mwl8k_tx_start(priv); } return IRQ_HANDLED; @@ -2395,41 +2446,13 @@ static void mwl8k_config_thread(struct work_struct *wt) { struct mwl8k_work_struct *worker = (struct mwl8k_work_struct *)wt; struct ieee80211_hw *hw = worker->hw; - struct mwl8k_priv *priv = hw->priv; int rc = 0; - int iter; - spin_lock_irq(&priv->tx_lock); - priv->inconfig = true; - spin_unlock_irq(&priv->tx_lock); - - ieee80211_stop_queues(hw); - - /* - * Wait for host queues to drain before doing PHY - * reconfiguration. This avoids interrupting any in-flight - * DMA transfers to the hardware. - */ - iter = 4; - do { - rc = mwl8k_tx_wait_empty(hw); - if (rc) - printk(KERN_ERR "%s() txwait timeout=1000ms " - "Retry:%u/%u\n", __func__, 4 - iter + 1, 4); - } while (rc && --iter); - - rc = iter ? 0 : -ETIMEDOUT; - - if (!rc) + rc = mwl8k_fw_lock(hw); + if (!rc) { rc = worker->wfunc(wt); - - spin_lock_irq(&priv->tx_lock); - priv->inconfig = false; - if (priv->pending_tx_pkts && priv->radio_on) - mwl8k_tx_start(priv); - spin_unlock_irq(&priv->tx_lock); - - ieee80211_wake_queues(hw); + mwl8k_fw_unlock(hw); + } worker->rc = rc; complete(worker->cmd_wait); @@ -3145,15 +3168,10 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, priv = hw->priv; priv->hw = hw; priv->pdev = pdev; - priv->hostcmd_wait = NULL; - priv->tx_wait = NULL; - priv->inconfig = false; priv->wmm_enabled = false; priv->pending_tx_pkts = 0; strncpy(priv->name, MWL8K_NAME, sizeof(priv->name)); - spin_lock_init(&priv->fw_lock); - SET_IEEE80211_DEV(hw, &pdev->dev); pci_set_drvdata(pdev, hw); @@ -3219,6 +3237,12 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, goto err_iounmap; rxq_refill(hw, 0, INT_MAX); + mutex_init(&priv->fw_mutex); + priv->fw_mutex_owner = NULL; + priv->fw_mutex_depth = 0; + priv->tx_wait = NULL; + priv->hostcmd_wait = NULL; + spin_lock_init(&priv->tx_lock); for (i = 0; i < MWL8K_TX_QUEUES; i++) { -- cgit v1.2.3-18-g5258 From 2ec610cb6d57032cdab89781e37ed3e442c73367 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 17 Jul 2009 07:11:37 +0200 Subject: mwl8k: get rid of mwl8k_start() workqueue use Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 105 +++++++++++-------------------------------- 1 file changed, 27 insertions(+), 78 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 93b92680d07..7b7007da873 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2489,104 +2489,53 @@ static int mwl8k_queue_work(struct ieee80211_hw *hw, return rc; } -struct mwl8k_start_worker { - struct mwl8k_work_struct header; -}; - -static int mwl8k_start_wt(struct work_struct *wt) -{ - struct mwl8k_start_worker *worker = (struct mwl8k_start_worker *)wt; - struct ieee80211_hw *hw = worker->header.hw; - struct mwl8k_priv *priv = hw->priv; - int rc = 0; - - if (priv->vif != NULL) { - rc = -EIO; - goto mwl8k_start_exit; - } - - /* Turn on radio */ - if (mwl8k_cmd_802_11_radio_enable(hw)) { - rc = -EIO; - goto mwl8k_start_exit; - } - - /* Purge TX/RX HW queues */ - if (mwl8k_cmd_set_pre_scan(hw)) { - rc = -EIO; - goto mwl8k_start_exit; - } - - if (mwl8k_cmd_set_post_scan(hw, "\x00\x00\x00\x00\x00\x00")) { - rc = -EIO; - goto mwl8k_start_exit; - } - - /* Enable firmware rate adaptation */ - if (mwl8k_cmd_setrateadaptmode(hw, 0)) { - rc = -EIO; - goto mwl8k_start_exit; - } - - /* Disable WMM. WMM gets enabled when stack sends WMM parms */ - if (mwl8k_set_wmm(hw, 0)) { - rc = -EIO; - goto mwl8k_start_exit; - } - - /* Disable sniffer mode */ - if (mwl8k_enable_sniffer(hw, 0)) - rc = -EIO; - -mwl8k_start_exit: - return rc; -} - static int mwl8k_start(struct ieee80211_hw *hw) { - struct mwl8k_start_worker *worker; struct mwl8k_priv *priv = hw->priv; int rc; - /* Enable tx reclaim tasklet */ - tasklet_enable(&priv->tx_reclaim_task); - rc = request_irq(priv->pdev->irq, &mwl8k_interrupt, IRQF_SHARED, MWL8K_NAME, hw); if (rc) { printk(KERN_ERR "%s: failed to register IRQ handler\n", priv->name); - rc = -EIO; - goto mwl8k_start_disable_tasklet; + return -EIO; } + /* Enable tx reclaim tasklet */ + tasklet_enable(&priv->tx_reclaim_task); + /* Enable interrupts */ iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) { - rc = -ENOMEM; - goto mwl8k_start_disable_irq; - } + rc = mwl8k_fw_lock(hw); + if (!rc) { + rc = mwl8k_cmd_802_11_radio_enable(hw); - rc = mwl8k_queue_work(hw, &worker->header, mwl8k_start_wt); - kfree(worker); - if (!rc) - return rc; + if (!rc) + rc = mwl8k_cmd_set_pre_scan(hw); - if (rc == -ETIMEDOUT) - printk(KERN_ERR "%s() timed out\n", __func__); + if (!rc) + rc = mwl8k_cmd_set_post_scan(hw, + "\x00\x00\x00\x00\x00\x00"); - rc = -EIO; + if (!rc) + rc = mwl8k_cmd_setrateadaptmode(hw, 0); -mwl8k_start_disable_irq: - spin_lock_irq(&priv->tx_lock); - iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - spin_unlock_irq(&priv->tx_lock); - free_irq(priv->pdev->irq, hw); + if (!rc) + rc = mwl8k_set_wmm(hw, 0); -mwl8k_start_disable_tasklet: - tasklet_disable(&priv->tx_reclaim_task); + if (!rc) + rc = mwl8k_enable_sniffer(hw, 0); + + mwl8k_fw_unlock(hw); + } + + if (rc) { + iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); + free_irq(priv->pdev->irq, hw); + tasklet_disable(&priv->tx_reclaim_task); + } return rc; } -- cgit v1.2.3-18-g5258 From d3cea0b85a31a98630c6fcf7373d486db9612a10 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 17 Jul 2009 07:15:49 +0200 Subject: mwl8k: get rid of mwl8k_stop() workqueue use Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 7b7007da873..b88b1e001f0 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2540,39 +2540,15 @@ static int mwl8k_start(struct ieee80211_hw *hw) return rc; } -struct mwl8k_stop_worker { - struct mwl8k_work_struct header; -}; - -static int mwl8k_stop_wt(struct work_struct *wt) -{ - struct mwl8k_stop_worker *worker = (struct mwl8k_stop_worker *)wt; - struct ieee80211_hw *hw = worker->header.hw; - - return mwl8k_cmd_802_11_radio_disable(hw); -} - static void mwl8k_stop(struct ieee80211_hw *hw) { - int rc; - struct mwl8k_stop_worker *worker; struct mwl8k_priv *priv = hw->priv; int i; - if (priv->vif != NULL) - return; + mwl8k_cmd_802_11_radio_disable(hw); ieee80211_stop_queues(hw); - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) - return; - - rc = mwl8k_queue_work(hw, &worker->header, mwl8k_stop_wt); - kfree(worker); - if (rc == -ETIMEDOUT) - printk(KERN_ERR "%s() timed out\n", __func__); - /* Disable interrupts */ iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); free_irq(priv->pdev->irq, hw); -- cgit v1.2.3-18-g5258 From ee03a93241eb954d669fb795b4e5c0eec92eef22 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 17 Jul 2009 07:19:37 +0200 Subject: mwl8k: get rid of mwl8k_config() workqueue use Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 72 ++++++++++++-------------------------------- 1 file changed, 20 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index b88b1e001f0..77e280a00a5 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2622,77 +2622,45 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw, priv->vif = NULL; } -struct mwl8k_config_worker { - struct mwl8k_work_struct header; - u32 changed; -}; - -static int mwl8k_config_wt(struct work_struct *wt) +static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) { - struct mwl8k_config_worker *worker = - (struct mwl8k_config_worker *)wt; - struct ieee80211_hw *hw = worker->header.hw; struct ieee80211_conf *conf = &hw->conf; struct mwl8k_priv *priv = hw->priv; - int rc = 0; + int rc; if (conf->flags & IEEE80211_CONF_IDLE) { mwl8k_cmd_802_11_radio_disable(hw); priv->current_channel = NULL; - goto mwl8k_config_exit; + return 0; } - if (mwl8k_cmd_802_11_radio_enable(hw)) { - rc = -EINVAL; - goto mwl8k_config_exit; - } + rc = mwl8k_fw_lock(hw); + if (rc) + return rc; - priv->current_channel = conf->channel; + rc = mwl8k_cmd_802_11_radio_enable(hw); + if (rc) + goto out; - if (mwl8k_cmd_set_rf_channel(hw, conf->channel)) { - rc = -EINVAL; - goto mwl8k_config_exit; - } + rc = mwl8k_cmd_set_rf_channel(hw, conf->channel); + if (rc) + goto out; + + priv->current_channel = conf->channel; if (conf->power_level > 18) conf->power_level = 18; - if (mwl8k_cmd_802_11_rf_tx_power(hw, conf->power_level)) { - rc = -EINVAL; - goto mwl8k_config_exit; - } + rc = mwl8k_cmd_802_11_rf_tx_power(hw, conf->power_level); + if (rc) + goto out; if (mwl8k_cmd_mimo_config(hw, 0x7, 0x7)) rc = -EINVAL; -mwl8k_config_exit: - return rc; -} - -static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) -{ - int rc = 0; - struct mwl8k_config_worker *worker; - - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) - return -ENOMEM; - - worker->changed = changed; - - rc = mwl8k_queue_work(hw, &worker->header, mwl8k_config_wt); - if (rc == -ETIMEDOUT) { - printk(KERN_ERR "%s() timed out.\n", __func__); - rc = -EINVAL; - } - - kfree(worker); +out: + mwl8k_fw_unlock(hw); - /* - * mac80211 will crash on anything other than -EINVAL on - * error. Looks like wireless extensions which calls mac80211 - * may be the actual culprit... - */ - return rc ? -EINVAL : 0; + return rc; } struct mwl8k_bss_info_changed_worker { -- cgit v1.2.3-18-g5258 From 3a980d0a505161b99fc936827cb28ec8eb853284 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 17 Jul 2009 07:21:46 +0200 Subject: mwl8k: get rid of mwl8k_bss_info_changed() workqueue use Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 101 ++++++++++++++++--------------------------- 1 file changed, 38 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 77e280a00a5..d5a46a917cf 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2663,58 +2663,62 @@ out: return rc; } -struct mwl8k_bss_info_changed_worker { - struct mwl8k_work_struct header; - struct ieee80211_vif *vif; - struct ieee80211_bss_conf *info; - u32 changed; -}; - -static int mwl8k_bss_info_changed_wt(struct work_struct *wt) +static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) { - struct mwl8k_bss_info_changed_worker *worker = - (struct mwl8k_bss_info_changed_worker *)wt; - struct ieee80211_hw *hw = worker->header.hw; - struct ieee80211_vif *vif = worker->vif; - struct ieee80211_bss_conf *info = worker->info; - u32 changed; - int rc; - struct mwl8k_priv *priv = hw->priv; struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); + int rc; + + if (changed & BSS_CHANGED_BSSID) + memcpy(mwl8k_vif->bssid, info->bssid, ETH_ALEN); + + if ((changed & BSS_CHANGED_ASSOC) == 0) + return; - changed = worker->changed; priv->capture_beacon = false; + rc = mwl8k_fw_lock(hw); + if (!rc) + return; + if (info->assoc) { memcpy(&mwl8k_vif->bss_info, info, sizeof(struct ieee80211_bss_conf)); /* Install rates */ - if (mwl8k_update_rateset(hw, vif)) - goto mwl8k_bss_info_changed_exit; + rc = mwl8k_update_rateset(hw, vif); + if (rc) + goto out; /* Turn on rate adaptation */ - if (mwl8k_cmd_use_fixed_rate(hw, MWL8K_USE_AUTO_RATE, - MWL8K_UCAST_RATE, NULL)) - goto mwl8k_bss_info_changed_exit; + rc = mwl8k_cmd_use_fixed_rate(hw, MWL8K_USE_AUTO_RATE, + MWL8K_UCAST_RATE, NULL); + if (rc) + goto out; /* Set radio preamble */ - if (mwl8k_set_radio_preamble(hw, info->use_short_preamble)) - goto mwl8k_bss_info_changed_exit; + rc = mwl8k_set_radio_preamble(hw, info->use_short_preamble); + if (rc) + goto out; /* Set slot time */ - if (mwl8k_cmd_set_slot(hw, info->use_short_slot)) - goto mwl8k_bss_info_changed_exit; + rc = mwl8k_cmd_set_slot(hw, info->use_short_slot); + if (rc) + goto out; /* Update peer rate info */ - if (mwl8k_cmd_update_sta_db(hw, vif, - MWL8K_STA_DB_MODIFY_ENTRY)) - goto mwl8k_bss_info_changed_exit; + rc = mwl8k_cmd_update_sta_db(hw, vif, + MWL8K_STA_DB_MODIFY_ENTRY); + if (rc) + goto out; /* Set AID */ - if (mwl8k_cmd_set_aid(hw, vif)) - goto mwl8k_bss_info_changed_exit; + rc = mwl8k_cmd_set_aid(hw, vif); + if (rc) + goto out; /* * Finalize the join. Tell rx handler to process @@ -2723,43 +2727,14 @@ static int mwl8k_bss_info_changed_wt(struct work_struct *wt) memcpy(priv->capture_bssid, mwl8k_vif->bssid, ETH_ALEN); priv->capture_beacon = true; } else { - mwl8k_cmd_update_sta_db(hw, vif, MWL8K_STA_DB_DEL_ENTRY); + rc = mwl8k_cmd_update_sta_db(hw, vif, MWL8K_STA_DB_DEL_ENTRY); memset(&mwl8k_vif->bss_info, 0, sizeof(struct ieee80211_bss_conf)); memset(mwl8k_vif->bssid, 0, ETH_ALEN); } -mwl8k_bss_info_changed_exit: - rc = 0; - return rc; -} - -static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, - u32 changed) -{ - struct mwl8k_bss_info_changed_worker *worker; - struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); - int rc; - - if (changed & BSS_CHANGED_BSSID) - memcpy(mv_vif->bssid, info->bssid, ETH_ALEN); - - if ((changed & BSS_CHANGED_ASSOC) == 0) - return; - - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) - return; - - worker->vif = vif; - worker->info = info; - worker->changed = changed; - rc = mwl8k_queue_work(hw, &worker->header, mwl8k_bss_info_changed_wt); - kfree(worker); - if (rc == -ETIMEDOUT) - printk(KERN_ERR "%s() timed out\n", __func__); +out: + mwl8k_fw_unlock(hw); } static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, -- cgit v1.2.3-18-g5258 From 733d3067d3fb168fbbd008cb0ebf5ad2027030f3 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 17 Jul 2009 07:24:15 +0200 Subject: mwl8k: get rid of mwl8k_set_rts_threshold() workqueue use Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 42 +++--------------------------------------- 1 file changed, 3 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index d5a46a917cf..3129c577388 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1970,7 +1970,7 @@ struct mwl8k_cmd_rts_threshold { } __attribute__((packed)); static int mwl8k_rts_threshold(struct ieee80211_hw *hw, - u16 action, u16 *threshold) + u16 action, u16 threshold) { struct mwl8k_cmd_rts_threshold *cmd; int rc; @@ -1982,7 +1982,7 @@ static int mwl8k_rts_threshold(struct ieee80211_hw *hw, cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD); cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->action = cpu_to_le16(action); - cmd->threshold = cpu_to_le16(*threshold); + cmd->threshold = cpu_to_le16(threshold); rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -2809,45 +2809,9 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, mwl8k_queue_work(hw, &worker->header, mwl8k_configure_filter_wt); } -struct mwl8k_set_rts_threshold_worker { - struct mwl8k_work_struct header; - u32 value; -}; - -static int mwl8k_set_rts_threshold_wt(struct work_struct *wt) -{ - struct mwl8k_set_rts_threshold_worker *worker = - (struct mwl8k_set_rts_threshold_worker *)wt; - - struct ieee80211_hw *hw = worker->header.hw; - u16 threshold = (u16)(worker->value); - int rc; - - rc = mwl8k_rts_threshold(hw, MWL8K_CMD_SET, &threshold); - - return rc; -} - static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { - int rc; - struct mwl8k_set_rts_threshold_worker *worker; - - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) - return -ENOMEM; - - worker->value = value; - - rc = mwl8k_queue_work(hw, &worker->header, mwl8k_set_rts_threshold_wt); - kfree(worker); - - if (rc == -ETIMEDOUT) { - printk(KERN_ERR "%s() timed out\n", __func__); - rc = -EINVAL; - } - - return rc; + return mwl8k_rts_threshold(hw, MWL8K_CMD_SET, value); } struct mwl8k_conf_tx_worker { -- cgit v1.2.3-18-g5258 From 3e4f542cfbf5a60f2295b2de9a31bdd14beb7b4a Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 17 Jul 2009 07:25:59 +0200 Subject: mwl8k: get rid of mwl8k_conf_tx() workqueue use Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 57 +++++++++++--------------------------------- 1 file changed, 14 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 3129c577388..5ce2d362e07 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2814,56 +2814,27 @@ static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return mwl8k_rts_threshold(hw, MWL8K_CMD_SET, value); } -struct mwl8k_conf_tx_worker { - struct mwl8k_work_struct header; - u16 queue; - const struct ieee80211_tx_queue_params *params; -}; - -static int mwl8k_conf_tx_wt(struct work_struct *wt) -{ - struct mwl8k_conf_tx_worker *worker = - (struct mwl8k_conf_tx_worker *)wt; - - struct ieee80211_hw *hw = worker->header.hw; - u16 queue = worker->queue; - const struct ieee80211_tx_queue_params *params = worker->params; - - struct mwl8k_priv *priv = hw->priv; - int rc = 0; - - if (!priv->wmm_enabled) { - if (mwl8k_set_wmm(hw, 1)) { - rc = -EINVAL; - goto mwl8k_conf_tx_exit; - } - } - - if (mwl8k_set_edca_params(hw, GET_TXQ(queue), params->cw_min, - params->cw_max, params->aifs, params->txop)) - rc = -EINVAL; -mwl8k_conf_tx_exit: - return rc; -} - static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { + struct mwl8k_priv *priv = hw->priv; int rc; - struct mwl8k_conf_tx_worker *worker; - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) - return -ENOMEM; + rc = mwl8k_fw_lock(hw); + if (!rc) { + if (!priv->wmm_enabled) + rc = mwl8k_set_wmm(hw, 1); - worker->queue = queue; - worker->params = params; - rc = mwl8k_queue_work(hw, &worker->header, mwl8k_conf_tx_wt); - kfree(worker); - if (rc == -ETIMEDOUT) { - printk(KERN_ERR "%s() timed out\n", __func__); - rc = -EINVAL; + if (!rc) + rc = mwl8k_set_edca_params(hw, queue, + params->cw_min, + params->cw_max, + params->aifs, + params->txop); + + mwl8k_fw_unlock(hw); } + return rc; } -- cgit v1.2.3-18-g5258 From 954ef509cc7d795ccd69fa2e01539297e9a003a0 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 17 Jul 2009 07:26:27 +0200 Subject: mwl8k: get rid of mwl8k_get_stats() workqueue use Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 5ce2d362e07..29712bd95af 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2852,42 +2852,14 @@ static int mwl8k_get_tx_stats(struct ieee80211_hw *hw, sizeof(struct ieee80211_tx_queue_stats)); } spin_unlock_bh(&priv->tx_lock); - return 0; -} - -struct mwl8k_get_stats_worker { - struct mwl8k_work_struct header; - struct ieee80211_low_level_stats *stats; -}; -static int mwl8k_get_stats_wt(struct work_struct *wt) -{ - struct mwl8k_get_stats_worker *worker = - (struct mwl8k_get_stats_worker *)wt; - - return mwl8k_cmd_802_11_get_stat(worker->header.hw, worker->stats); + return 0; } static int mwl8k_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { - int rc; - struct mwl8k_get_stats_worker *worker; - - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (worker == NULL) - return -ENOMEM; - - worker->stats = stats; - rc = mwl8k_queue_work(hw, &worker->header, mwl8k_get_stats_wt); - - kfree(worker); - if (rc == -ETIMEDOUT) { - printk(KERN_ERR "%s() timed out\n", __func__); - rc = -EINVAL; - } - - return rc; + return mwl8k_cmd_802_11_get_stat(hw, stats); } static const struct ieee80211_ops mwl8k_ops = { -- cgit v1.2.3-18-g5258 From e6935ea10485f34b82d16f8dff9aa2bdf32ab4bf Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 18 Aug 2009 04:06:20 +0200 Subject: mwl8k: get rid of mwl8k_configure_filter() workqueue use Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 65 ++++++++++++++------------------------------ 1 file changed, 20 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 29712bd95af..43e5dd19b66 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2747,26 +2747,23 @@ static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, return (unsigned long)cmd; } -struct mwl8k_configure_filter_worker { - struct mwl8k_work_struct header; - unsigned int changed_flags; - unsigned int total_flags; +static void mwl8k_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) +{ + struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_pkt *multicast_adr_cmd; -}; -#define MWL8K_SUPPORTED_IF_FLAGS FIF_BCN_PRBRESP_PROMISC + /* Clear unsupported feature flags */ + *total_flags &= FIF_BCN_PRBRESP_PROMISC; -static int mwl8k_configure_filter_wt(struct work_struct *wt) -{ - struct mwl8k_configure_filter_worker *worker = - (struct mwl8k_configure_filter_worker *)wt; - struct ieee80211_hw *hw = worker->header.hw; - struct mwl8k_priv *priv = hw->priv; - int rc = 0; + if (mwl8k_fw_lock(hw)) + return; - if (worker->changed_flags & FIF_BCN_PRBRESP_PROMISC) { - if (worker->total_flags & FIF_BCN_PRBRESP_PROMISC) - rc = mwl8k_cmd_set_pre_scan(hw); + if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + mwl8k_cmd_set_pre_scan(hw); else { u8 *bssid; @@ -2774,39 +2771,17 @@ static int mwl8k_configure_filter_wt(struct work_struct *wt) if (priv->vif != NULL) bssid = MWL8K_VIF(priv->vif)->bssid; - rc = mwl8k_cmd_set_post_scan(hw, bssid); + mwl8k_cmd_set_post_scan(hw, bssid); } } - if (!rc && worker->multicast_adr_cmd != NULL) - rc = mwl8k_post_cmd(hw, worker->multicast_adr_cmd); - kfree(worker->multicast_adr_cmd); - - return rc; -} - -static void mwl8k_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast) -{ - struct mwl8k_configure_filter_worker *worker; - - /* Clear unsupported feature flags */ - *total_flags &= MWL8K_SUPPORTED_IF_FLAGS; - - if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS)) - return; - - worker = kzalloc(sizeof(*worker), GFP_ATOMIC); - if (worker == NULL) - return; - - worker->changed_flags = changed_flags; - worker->total_flags = *total_flags; - worker->multicast_adr_cmd = (void *)(unsigned long)multicast; + multicast_adr_cmd = (void *)(unsigned long)multicast; + if (multicast_adr_cmd != NULL) { + mwl8k_post_cmd(hw, multicast_adr_cmd); + kfree(multicast_adr_cmd); + } - mwl8k_queue_work(hw, &worker->header, mwl8k_configure_filter_wt); + mwl8k_fw_unlock(hw); } static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) -- cgit v1.2.3-18-g5258 From ab565790cb5ca3d00db0af9c2a8eb95e16054c29 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 18 Aug 2009 04:08:01 +0200 Subject: mwl8k: remove mwl8k_queue_work() Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 64 -------------------------------------------- 1 file changed, 64 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 43e5dd19b66..a634b565018 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2425,70 +2425,6 @@ static int mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return rc; } -struct mwl8k_work_struct { - /* Initialized by mwl8k_queue_work(). */ - struct work_struct wt; - - /* Required field passed in to mwl8k_queue_work(). */ - struct ieee80211_hw *hw; - - /* Required field passed in to mwl8k_queue_work(). */ - int (*wfunc)(struct work_struct *w); - - /* Initialized by mwl8k_queue_work(). */ - struct completion *cmd_wait; - - /* Result code. */ - int rc; -}; - -static void mwl8k_config_thread(struct work_struct *wt) -{ - struct mwl8k_work_struct *worker = (struct mwl8k_work_struct *)wt; - struct ieee80211_hw *hw = worker->hw; - int rc = 0; - - rc = mwl8k_fw_lock(hw); - if (!rc) { - rc = worker->wfunc(wt); - mwl8k_fw_unlock(hw); - } - - worker->rc = rc; - complete(worker->cmd_wait); -} - -static int mwl8k_queue_work(struct ieee80211_hw *hw, - struct mwl8k_work_struct *worker, - int (*wfunc)(struct work_struct *w)) -{ - struct mwl8k_priv *priv = hw->priv; - unsigned long timeout = 0; - int rc = 0; - - DECLARE_COMPLETION_ONSTACK(cmd_wait); - - worker->hw = hw; - worker->cmd_wait = &cmd_wait; - worker->rc = 1; - worker->wfunc = wfunc; - - INIT_WORK(&worker->wt, mwl8k_config_thread); - queue_work(priv->config_wq, &worker->wt); - - timeout = wait_for_completion_timeout(&cmd_wait, - msecs_to_jiffies(10000)); - - if (timeout) - rc = worker->rc; - else { - cancel_work_sync(&worker->wt); - rc = -ETIMEDOUT; - } - - return rc; -} - static int mwl8k_start(struct ieee80211_hw *hw) { struct mwl8k_priv *priv = hw->priv; -- cgit v1.2.3-18-g5258 From a145d575833ff47330125364cb49304db7308825 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 18 Aug 2009 04:34:26 +0200 Subject: mwl8k: update copyright and version number Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index a634b565018..41a708ce873 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2,7 +2,7 @@ * drivers/net/wireless/mwl8k.c * Driver for Marvell TOPDOG 802.11 Wireless cards * - * Copyright (C) 2008 Marvell Semiconductor Inc. + * Copyright (C) 2008-2009 Marvell Semiconductor Inc. * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any @@ -25,7 +25,7 @@ #define MWL8K_DESC "Marvell TOPDOG(R) 802.11 Wireless Network Driver" #define MWL8K_NAME KBUILD_MODNAME -#define MWL8K_VERSION "0.9.1" +#define MWL8K_VERSION "0.10" MODULE_DESCRIPTION(MWL8K_DESC); MODULE_VERSION(MWL8K_VERSION); -- cgit v1.2.3-18-g5258 From fb962e1e1772df163358832476e6091d1660ba9f Mon Sep 17 00:00:00 2001 From: Wan ZongShun Date: Thu, 20 Aug 2009 21:41:03 -0700 Subject: Input: w90p910_keypad - rename driver name to match platform Signed-off-by: Wan ZongShun Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/w90p910_keypad.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c index 24096cdfcb6..b8598ae124e 100644 --- a/drivers/input/keyboard/w90p910_keypad.c +++ b/drivers/input/keyboard/w90p910_keypad.c @@ -267,7 +267,7 @@ static struct platform_driver w90p910_keypad_driver = { .probe = w90p910_keypad_probe, .remove = __devexit_p(w90p910_keypad_remove), .driver = { - .name = "w90p910-keypad", + .name = "nuc900-keypad", .owner = THIS_MODULE, }, }; @@ -286,6 +286,6 @@ module_init(w90p910_keypad_init); module_exit(w90p910_keypad_exit); MODULE_AUTHOR("Wan ZongShun "); -MODULE_DESCRIPTION("w90p910 keypad driver!"); +MODULE_DESCRIPTION("w90p910 keypad driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:w90p910-keypad"); +MODULE_ALIAS("platform:nuc900-keypad"); -- cgit v1.2.3-18-g5258 From 805423e84e900e56c834aadee61a020b0d5092c3 Mon Sep 17 00:00:00 2001 From: Corbin Simpson Date: Thu, 20 Aug 2009 21:41:04 -0700 Subject: Input: xpad - add USB ID for the drumkit controller from Rock Band Signed-off-by: Corbin Simpson Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index f155ad8cdae..2388cf578a6 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -144,6 +144,7 @@ static const struct xpad_device { { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, + { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_UNKNOWN } }; @@ -208,6 +209,7 @@ static struct usb_device_id xpad_table [] = { XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */ + XPAD_XBOX360_VENDOR(0x1bad), /* Rock Band Drums */ { } }; -- cgit v1.2.3-18-g5258 From 290ba200815fdecb4d40dc942499c4ea6d0c4624 Mon Sep 17 00:00:00 2001 From: Vikram Kandukuri Date: Thu, 2 Jul 2009 14:31:59 +0530 Subject: Bluetooth: Improve USB driver throughput by increasing the frame size This patch increases the receive buffer size to HCI_MAX_FRAME_SIZE which improves the RX throughput considerably. Tested against BRM/Atheros/CSR USB Dongles with PAN profile using iperf and chariot. This gave significant (around 40%) increase in performance (increased from 0.8 to 1.5 Mb/s in Sheld room) Signed-off-by: Vikram Kandukuri Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index e70c57ee422..124db8cd144 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -301,7 +301,7 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags) struct urb *urb; unsigned char *buf; unsigned int pipe; - int err, size; + int err, size = HCI_MAX_FRAME_SIZE; BT_DBG("%s", hdev->name); @@ -312,8 +312,6 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags) if (!urb) return -ENOMEM; - size = le16_to_cpu(data->bulk_rx_ep->wMaxPacketSize); - buf = kmalloc(size, mem_flags); if (!buf) { usb_free_urb(urb); -- cgit v1.2.3-18-g5258 From 132ff4e5fa8dfb71a7d99902f88043113947e972 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Tue, 2 Jun 2009 14:29:35 -0700 Subject: Bluetooth: Add btmrvl driver for Marvell Bluetooth devices This driver provides basic definitions and library functions to support Marvell Bluetooth enabled devices, such as 88W8688 WLAN/BT combo chip. This patch incorporates a lot of comments given by Nicolas Pitre . Many thanks to Nicolas Pitre. Signed-off-by: Rahul Tank Signed-off-by: Bing Zhao Signed-off-by: Marcel Holtmann --- drivers/bluetooth/Kconfig | 12 + drivers/bluetooth/Makefile | 3 + drivers/bluetooth/btmrvl_drv.h | 138 ++++++++ drivers/bluetooth/btmrvl_main.c | 714 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 867 insertions(+) create mode 100644 drivers/bluetooth/btmrvl_drv.h create mode 100644 drivers/bluetooth/btmrvl_main.c (limited to 'drivers') diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 1164837bb78..b049a79fcc0 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -170,5 +170,17 @@ config BT_HCIVHCI Say Y here to compile support for virtual HCI devices into the kernel or say M to compile it as module (hci_vhci). +config BT_MRVL + tristate "Marvell Bluetooth driver support" + select FW_LOADER + help + The core driver to support Marvell Bluetooth devices. + + This driver is required if you want to support + Marvell Bluetooth devices, such as 8688. + + Say Y here to compile Marvell Bluetooth driver + into the kernel or say M to compile it as module. + endmenu diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 16930f93d1c..3eff1231812 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -15,6 +15,9 @@ obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o obj-$(CONFIG_BT_HCIBTUSB) += btusb.o obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o +btmrvl-objs := btmrvl_main.o +obj-$(CONFIG_BT_MRVL) += btmrvl.o + hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h new file mode 100644 index 00000000000..9ad71f48110 --- /dev/null +++ b/drivers/bluetooth/btmrvl_drv.h @@ -0,0 +1,138 @@ +/* + * Marvell Bluetooth driver: global definitions & declarations + * + * Copyright (C) 2009, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +#ifndef _BTMRVL_DRV_H_ +#define _BTMRVL_DRV_H_ + +#include +#include +#include + +#define BTM_HEADER_LEN 4 +#define BTM_DEV_NAME_LEN 32 +#define BTM_UPLD_SIZE 2312 + +/* Time to wait until Host Sleep state change in millisecond */ +#define WAIT_UNTIL_HS_STATE_CHANGED 5000 +/* Time to wait for command response in millisecond */ +#define WAIT_UNTIL_CMD_RESP 5000 + +struct btmrvl_thread { + struct task_struct *task; + wait_queue_head_t wait_q; + void *priv; +}; + +struct btmrvl_device { + char name[BTM_DEV_NAME_LEN]; + void *card; + struct hci_dev *hcidev; + + u8 tx_dnld_rdy; + + u8 psmode; + u8 pscmd; + u8 hsmode; + u8 hscmd; + + /* Low byte is gap, high byte is GPIO */ + u16 gpio_gap; + + u8 hscfgcmd; + u8 sendcmdflag; +}; + +struct btmrvl_adapter { + u32 int_count; + struct sk_buff_head tx_queue; + u8 psmode; + u8 ps_state; + u8 hs_state; + u8 wakeup_tries; + wait_queue_head_t cmd_wait_q; + u8 cmd_complete; +}; + +struct btmrvl_private { + struct btmrvl_device btmrvl_dev; + struct btmrvl_adapter *adapter; + struct btmrvl_thread main_thread; + int (*hw_host_to_card) (struct btmrvl_private *priv, + u8 *payload, u16 nb); + int (*hw_wakeup_firmware) (struct btmrvl_private *priv); + spinlock_t driver_lock; /* spinlock used by driver */ +}; + +#define MRVL_VENDOR_PKT 0xFE + +/* Bluetooth commands */ +#define BT_CMD_AUTO_SLEEP_MODE 0x23 +#define BT_CMD_HOST_SLEEP_CONFIG 0x59 +#define BT_CMD_HOST_SLEEP_ENABLE 0x5A +#define BT_CMD_MODULE_CFG_REQ 0x5B + +/* Sub-commands: Module Bringup/Shutdown Request */ +#define MODULE_BRINGUP_REQ 0xF1 +#define MODULE_SHUTDOWN_REQ 0xF2 + +#define BT_EVENT_POWER_STATE 0x20 + +/* Bluetooth Power States */ +#define BT_PS_ENABLE 0x02 +#define BT_PS_DISABLE 0x03 +#define BT_PS_SLEEP 0x01 + +#define OGF 0x3F + +/* Host Sleep states */ +#define HS_ACTIVATED 0x01 +#define HS_DEACTIVATED 0x00 + +/* Power Save modes */ +#define PS_SLEEP 0x01 +#define PS_AWAKE 0x00 + +struct btmrvl_cmd { + __le16 ocf_ogf; + u8 length; + u8 data[4]; +} __attribute__ ((packed)); + +struct btmrvl_event { + u8 ec; /* event counter */ + u8 length; + u8 data[4]; +} __attribute__ ((packed)); + +/* Prototype of global function */ + +struct btmrvl_private *btmrvl_add_card(void *card); +int btmrvl_remove_card(struct btmrvl_private *priv); + +void btmrvl_interrupt(struct btmrvl_private *priv); + +void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb); +int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb); + +int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd); +int btmrvl_prepare_command(struct btmrvl_private *priv); + +#endif /* _BTMRVL_DRV_H_ */ diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c new file mode 100644 index 00000000000..11c2f2cecf1 --- /dev/null +++ b/drivers/bluetooth/btmrvl_main.c @@ -0,0 +1,714 @@ +/** + * Marvell Bluetooth driver + * + * Copyright (C) 2009, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + **/ + +#include +#include + +#include "btmrvl_drv.h" + +#define VERSION "1.0" + +/* + * This function is called by interface specific interrupt handler. + * It updates Power Save & Host Sleep states, and wakes up the main + * thread. + */ +void btmrvl_interrupt(struct btmrvl_private *priv) +{ + BT_DBG("Enter"); + + priv->adapter->ps_state = PS_AWAKE; + + priv->adapter->wakeup_tries = 0; + + priv->adapter->int_count++; + + wake_up_interruptible(&priv->main_thread.wait_q); + + BT_DBG("Leave"); +} +EXPORT_SYMBOL_GPL(btmrvl_interrupt); + +void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) +{ + struct hci_event_hdr *hdr = (struct hci_event_hdr *)skb->data; + struct hci_ev_cmd_complete *ec; + u16 opcode, ocf; + + BT_DBG("Enter"); + + if (hdr->evt == HCI_EV_CMD_COMPLETE) { + ec = (struct hci_ev_cmd_complete *)(skb->data + + HCI_EVENT_HDR_SIZE); + opcode = __le16_to_cpu(ec->opcode); + ocf = hci_opcode_ocf(opcode); + if ((ocf == BT_CMD_MODULE_CFG_REQ) && + (priv->btmrvl_dev.sendcmdflag)) { + priv->btmrvl_dev.sendcmdflag = false; + priv->adapter->cmd_complete = true; + wake_up_interruptible(&priv->adapter->cmd_wait_q); + } + } + + BT_DBG("Leave"); +} +EXPORT_SYMBOL_GPL(btmrvl_check_evtpkt); + +int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) +{ + struct btmrvl_adapter *adapter = priv->adapter; + u8 ret = 0; + struct btmrvl_event *event; + + BT_DBG("Enter"); + + event = (struct btmrvl_event *) skb->data; + if (event->ec != 0xff) { + BT_DBG("Not Marvell Event=%x", event->ec); + ret = -EINVAL; + goto exit; + } + + switch (event->data[0]) { + case BT_CMD_AUTO_SLEEP_MODE: + if (!event->data[2]) { + if (event->data[1] == BT_PS_ENABLE) + adapter->psmode = 1; + else + adapter->psmode = 0; + BT_DBG("PS Mode:%s", + (adapter->psmode) ? "Enable" : "Disable"); + } else { + BT_DBG("PS Mode command failed"); + } + break; + + case BT_CMD_HOST_SLEEP_CONFIG: + if (!event->data[3]) + BT_DBG("gpio=%x, gap=%x", event->data[1], + event->data[2]); + else + BT_DBG("HSCFG command failed"); + break; + + case BT_CMD_HOST_SLEEP_ENABLE: + if (!event->data[1]) { + adapter->hs_state = HS_ACTIVATED; + if (adapter->psmode) + adapter->ps_state = PS_SLEEP; + wake_up_interruptible(&adapter->cmd_wait_q); + BT_DBG("HS ACTIVATED!"); + } else { + BT_DBG("HS Enable failed"); + } + break; + + case BT_CMD_MODULE_CFG_REQ: + if ((priv->btmrvl_dev.sendcmdflag) && + (event->data[1] == MODULE_BRINGUP_REQ)) { + BT_DBG("EVENT:%s", (event->data[2]) ? + "Bring-up failed" : "Bring-up succeed"); + } else if ((priv->btmrvl_dev.sendcmdflag) && + (event->data[1] == MODULE_SHUTDOWN_REQ)) { + BT_DBG("EVENT:%s", (event->data[2]) ? + "Shutdown failed" : "Shutdown succeed"); + } else { + BT_DBG("BT_CMD_MODULE_CFG_REQ resp for APP"); + ret = -EINVAL; + } + break; + + case BT_EVENT_POWER_STATE: + if (event->data[1] == BT_PS_SLEEP) + adapter->ps_state = PS_SLEEP; + BT_DBG("EVENT:%s", + (adapter->ps_state) ? "PS_SLEEP" : "PS_AWAKE"); + break; + + default: + BT_DBG("Unknown Event=%d", event->data[0]); + ret = -EINVAL; + break; + } + +exit: + if (!ret) + kfree_skb(skb); + + BT_DBG("Leave"); + + return ret; +} +EXPORT_SYMBOL_GPL(btmrvl_process_event); + +int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) +{ + struct sk_buff *skb = NULL; + u8 ret = 0; + struct btmrvl_cmd *cmd; + + BT_DBG("Enter"); + + skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); + if (skb == NULL) { + BT_ERR("No free skb"); + ret = -ENOMEM; + goto exit; + } + + cmd = (struct btmrvl_cmd *) skb->tail; + cmd->ocf_ogf = cpu_to_le16((OGF << 10) | BT_CMD_MODULE_CFG_REQ); + cmd->length = 1; + cmd->data[0] = subcmd; + + bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; + + skb_put(skb, sizeof(*cmd)); + skb->dev = (void *)priv->btmrvl_dev.hcidev; + skb_queue_head(&priv->adapter->tx_queue, skb); + + priv->btmrvl_dev.sendcmdflag = true; + + priv->adapter->cmd_complete = false; + + BT_DBG("Queue module cfg Command"); + + wake_up_interruptible(&priv->main_thread.wait_q); + + if (!wait_event_interruptible_timeout( + priv->adapter->cmd_wait_q, + priv->adapter->cmd_complete, + msecs_to_jiffies(WAIT_UNTIL_CMD_RESP))) { + ret = -ETIMEDOUT; + BT_ERR("module_cfg_cmd(%x): timeout: %d", + subcmd, priv->btmrvl_dev.sendcmdflag); + } + + BT_DBG("module cfg Command done"); + +exit: + BT_DBG("Leave"); + + return ret; +} +EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd); + +static int btmrvl_enable_hs(struct btmrvl_private *priv) +{ + struct sk_buff *skb = NULL; + u8 ret = 0; + struct btmrvl_cmd *cmd; + + BT_DBG("Enter"); + + skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); + if (skb == NULL) { + BT_ERR("No free skb"); + ret = -ENOMEM; + goto exit; + } + + cmd = (struct btmrvl_cmd *) skb->tail; + cmd->ocf_ogf = cpu_to_le16((OGF << 10) | BT_CMD_HOST_SLEEP_ENABLE); + cmd->length = 0; + + bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; + + skb_put(skb, sizeof(*cmd)); + skb->dev = (void *)priv->btmrvl_dev.hcidev; + skb_queue_head(&priv->adapter->tx_queue, skb); + + BT_DBG("Queue hs enable Command"); + + wake_up_interruptible(&priv->main_thread.wait_q); + + if (!wait_event_interruptible_timeout( + priv->adapter->cmd_wait_q, + priv->adapter->hs_state, + msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED))) { + ret = -ETIMEDOUT; + BT_ERR("timeout: %d, %d,%d", + priv->adapter->hs_state, + priv->adapter->ps_state, + priv->adapter->wakeup_tries); + } + +exit: + BT_DBG("Leave"); + + return ret; +} + +int btmrvl_prepare_command(struct btmrvl_private *priv) +{ + struct sk_buff *skb = NULL; + u8 ret = 0; + struct btmrvl_cmd *cmd; + + BT_DBG("Enter"); + + if (priv->btmrvl_dev.hscfgcmd) { + priv->btmrvl_dev.hscfgcmd = 0; + + skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); + if (skb == NULL) { + BT_ERR("No free skb"); + ret = -ENOMEM; + goto exit; + } + + cmd = (struct btmrvl_cmd *) skb->tail; + cmd->ocf_ogf = cpu_to_le16((OGF << 10) | + BT_CMD_HOST_SLEEP_CONFIG); + cmd->length = 2; + cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8; + cmd->data[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff); + + bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; + + skb_put(skb, sizeof(*cmd)); + skb->dev = (void *)priv->btmrvl_dev.hcidev; + skb_queue_head(&priv->adapter->tx_queue, skb); + + BT_DBG("Queue HSCFG Command, gpio=0x%x, gap=0x%x", + cmd->data[0], cmd->data[1]); + } + + if (priv->btmrvl_dev.pscmd) { + priv->btmrvl_dev.pscmd = 0; + + skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); + if (skb == NULL) { + BT_ERR("No free skb"); + ret = -ENOMEM; + goto exit; + } + + cmd = (struct btmrvl_cmd *) skb->tail; + cmd->ocf_ogf = cpu_to_le16((OGF << 10) | + BT_CMD_AUTO_SLEEP_MODE); + cmd->length = 1; + + if (priv->btmrvl_dev.psmode) + cmd->data[0] = BT_PS_ENABLE; + else + cmd->data[0] = BT_PS_DISABLE; + + bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; + + skb_put(skb, sizeof(*cmd)); + skb->dev = (void *)priv->btmrvl_dev.hcidev; + skb_queue_head(&priv->adapter->tx_queue, skb); + + BT_DBG("Queue PSMODE Command:%d", cmd->data[0]); + } + + if (priv->btmrvl_dev.hscmd) { + priv->btmrvl_dev.hscmd = 0; + + if (priv->btmrvl_dev.hsmode) { + ret = btmrvl_enable_hs(priv); + } else { + ret = priv->hw_wakeup_firmware(priv); + priv->adapter->hs_state = HS_DEACTIVATED; + } + } + +exit: + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb) +{ + u8 ret = 0; + + BT_DBG("Enter"); + + if (!skb || !skb->data) { + BT_DBG("Leave"); + return -EINVAL; + } + + if (!skb->len || ((skb->len + BTM_HEADER_LEN) > BTM_UPLD_SIZE)) { + BT_ERR("Tx Error: Bad skb length %d : %d", + skb->len, BTM_UPLD_SIZE); + BT_DBG("Leave"); + return -EINVAL; + } + + if (skb_headroom(skb) < BTM_HEADER_LEN) { + struct sk_buff *tmp = skb; + + skb = skb_realloc_headroom(skb, BTM_HEADER_LEN); + if (!skb) { + BT_ERR("Tx Error: realloc_headroom failed %d", + BTM_HEADER_LEN); + skb = tmp; + BT_DBG("Leave"); + return -EINVAL; + } + + kfree_skb(tmp); + } + + skb_push(skb, BTM_HEADER_LEN); + + /* header type: byte[3] + * HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor + * header length: byte[2][1][0] + */ + + skb->data[0] = (skb->len & 0x0000ff); + skb->data[1] = (skb->len & 0x00ff00) >> 8; + skb->data[2] = (skb->len & 0xff0000) >> 16; + skb->data[3] = bt_cb(skb)->pkt_type; + + if (priv->hw_host_to_card) + ret = priv->hw_host_to_card(priv, skb->data, skb->len); + + BT_DBG("Leave"); + + return ret; +} + +static void btmrvl_init_adapter(struct btmrvl_private *priv) +{ + BT_DBG("Enter"); + + skb_queue_head_init(&priv->adapter->tx_queue); + + priv->adapter->ps_state = PS_AWAKE; + + init_waitqueue_head(&priv->adapter->cmd_wait_q); + + BT_DBG("Leave"); +} + +static void btmrvl_free_adapter(struct btmrvl_private *priv) +{ + BT_DBG("Enter"); + + skb_queue_purge(&priv->adapter->tx_queue); + + kfree(priv->adapter); + + priv->adapter = NULL; + + BT_DBG("Leave"); +} + +static int +btmrvl_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) +{ + BT_DBG("Enter"); + + BT_DBG("Leave"); + + return -ENOIOCTLCMD; +} + +static void btmrvl_destruct(struct hci_dev *hdev) +{ + BT_DBG("Enter"); + + BT_DBG("Leave"); +} + +static int btmrvl_send_frame(struct sk_buff *skb) +{ + struct hci_dev *hdev = (struct hci_dev *)skb->dev; + struct btmrvl_private *priv = NULL; + + BT_DBG("Enter: type=%d, len=%d", skb->pkt_type, skb->len); + + if (!hdev || !hdev->driver_data) { + BT_ERR("Frame for unknown HCI device"); + BT_DBG("Leave"); + return -ENODEV; + } + + priv = (struct btmrvl_private *)hdev->driver_data; + if (!test_bit(HCI_RUNNING, &hdev->flags)) { + BT_ERR("Failed testing HCI_RUNING, flags=%lx", hdev->flags); + print_hex_dump_bytes("data: ", DUMP_PREFIX_OFFSET, + skb->data, skb->len); + BT_DBG("Leave"); + return -EBUSY; + } + + switch (bt_cb(skb)->pkt_type) { + case HCI_COMMAND_PKT: + hdev->stat.cmd_tx++; + break; + + case HCI_ACLDATA_PKT: + hdev->stat.acl_tx++; + break; + + case HCI_SCODATA_PKT: + hdev->stat.sco_tx++; + break; + } + + skb_queue_tail(&priv->adapter->tx_queue, skb); + + wake_up_interruptible(&priv->main_thread.wait_q); + + BT_DBG("Leave"); + + return 0; +} + +static int btmrvl_flush(struct hci_dev *hdev) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) hdev->driver_data; + + BT_DBG("Enter"); + + skb_queue_purge(&priv->adapter->tx_queue); + + BT_DBG("Leave"); + + return 0; +} + +static int btmrvl_close(struct hci_dev *hdev) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) hdev->driver_data; + + BT_DBG("Enter"); + + if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) { + BT_DBG("Leave"); + return 0; + } + + skb_queue_purge(&priv->adapter->tx_queue); + + BT_DBG("Leave"); + + return 0; +} + +static int btmrvl_open(struct hci_dev *hdev) +{ + BT_DBG("Enter"); + + set_bit(HCI_RUNNING, &hdev->flags); + + BT_DBG("Leave"); + + return 0; +} + +/* + * This function handles the event generated by firmware, rx data + * received from firmware, and tx data sent from kernel. + */ +static int btmrvl_service_main_thread(void *data) +{ + struct btmrvl_thread *thread = data; + struct btmrvl_private *priv = thread->priv; + struct btmrvl_adapter *adapter = priv->adapter; + wait_queue_t wait; + struct sk_buff *skb; + ulong flags; + + BT_DBG("Enter"); + + init_waitqueue_entry(&wait, current); + + current->flags |= PF_NOFREEZE; + + for (;;) { + add_wait_queue(&thread->wait_q, &wait); + + set_current_state(TASK_INTERRUPTIBLE); + + if (adapter->wakeup_tries || + ((!adapter->int_count) && + (!priv->btmrvl_dev.tx_dnld_rdy || + skb_queue_empty(&adapter->tx_queue)))) { + BT_DBG("main_thread is sleeping..."); + schedule(); + } + + set_current_state(TASK_RUNNING); + + remove_wait_queue(&thread->wait_q, &wait); + + BT_DBG("main_thread woke up"); + + if (kthread_should_stop()) { + BT_DBG("main_thread: break from main thread"); + break; + } + + spin_lock_irqsave(&priv->driver_lock, flags); + if (adapter->int_count) { + adapter->int_count = 0; + } else if ((adapter->ps_state == PS_SLEEP) && + !skb_queue_empty(&adapter->tx_queue)) { + spin_unlock_irqrestore(&priv->driver_lock, flags); + adapter->wakeup_tries++; + priv->hw_wakeup_firmware(priv); + continue; + } + spin_unlock_irqrestore(&priv->driver_lock, flags); + + if (adapter->ps_state == PS_SLEEP) + continue; + + if (!priv->btmrvl_dev.tx_dnld_rdy) + continue; + + skb = skb_dequeue(&adapter->tx_queue); + if (skb) { + if (btmrvl_tx_pkt(priv, skb)) + priv->btmrvl_dev.hcidev->stat.err_tx++; + else + priv->btmrvl_dev.hcidev->stat.byte_tx + += skb->len; + + kfree_skb(skb); + } + } + + BT_DBG("Leave"); + + return 0; +} + +struct btmrvl_private *btmrvl_add_card(void *card) +{ + struct hci_dev *hdev = NULL; + struct btmrvl_private *priv = NULL; + int ret; + + BT_DBG("Enter"); + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + BT_ERR("Can not allocate priv"); + goto err_priv; + } + + priv->adapter = kzalloc(sizeof(*priv->adapter), GFP_KERNEL); + if (!priv->adapter) { + BT_ERR("Allocate buffer for btmrvl_adapter failed!"); + goto err_adapter; + } + + btmrvl_init_adapter(priv); + + hdev = hci_alloc_dev(); + if (!hdev) { + BT_ERR("Can not allocate HCI device"); + goto err_hdev; + } + + BT_DBG("Starting kthread..."); + priv->main_thread.priv = priv; + spin_lock_init(&priv->driver_lock); + + init_waitqueue_head(&priv->main_thread.wait_q); + priv->main_thread.task = kthread_run(btmrvl_service_main_thread, + &priv->main_thread, "btmrvl_main_service"); + + priv->btmrvl_dev.hcidev = hdev; + priv->btmrvl_dev.card = card; + + hdev->driver_data = priv; + + priv->btmrvl_dev.tx_dnld_rdy = true; + + hdev->type = HCI_SDIO; + hdev->open = btmrvl_open; + hdev->close = btmrvl_close; + hdev->flush = btmrvl_flush; + hdev->send = btmrvl_send_frame; + hdev->destruct = btmrvl_destruct; + hdev->ioctl = btmrvl_ioctl; + hdev->owner = THIS_MODULE; + + ret = hci_register_dev(hdev); + if (ret < 0) { + BT_ERR("Can not register HCI device"); + goto err_hci_register_dev; + } + + BT_DBG("Leave"); + return priv; + +err_hci_register_dev: + /* Stop the thread servicing the interrupts */ + kthread_stop(priv->main_thread.task); + + hci_free_dev(hdev); + +err_hdev: + btmrvl_free_adapter(priv); + +err_adapter: + kfree(priv); + +err_priv: + BT_DBG("Leave"); + + return NULL; +} +EXPORT_SYMBOL_GPL(btmrvl_add_card); + +int btmrvl_remove_card(struct btmrvl_private *priv) +{ + struct hci_dev *hdev; + + BT_DBG("Enter"); + + hdev = priv->btmrvl_dev.hcidev; + + wake_up_interruptible(&priv->adapter->cmd_wait_q); + + kthread_stop(priv->main_thread.task); + + hci_unregister_dev(hdev); + + hci_free_dev(hdev); + + priv->btmrvl_dev.hcidev = NULL; + + btmrvl_free_adapter(priv); + + kfree(priv); + + BT_DBG("Leave"); + + return 0; +} +EXPORT_SYMBOL_GPL(btmrvl_remove_card); + +MODULE_AUTHOR("Marvell International Ltd."); +MODULE_DESCRIPTION("Marvell Bluetooth Driver v" VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-18-g5258 From 789221ecc870117b77e354d488d5d29f15410de8 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Tue, 2 Jun 2009 14:29:36 -0700 Subject: Bluetooth: Add Marvell BT-over-SDIO driver This driver supports Marvell Bluetooth enabled devices with SDIO interface. Currently only SD8688 chip is supported. The helper/firmware images of SD8688 can be downloaded from this tree: git://git.infradead.org/users/dwmw2/linux-firmware.git This patch incorporates a lot of comments given by Nicolas Pitre . Many thanks to Nicolas Pitre. Signed-off-by: Rahul Tank Signed-off-by: Bing Zhao Signed-off-by: Marcel Holtmann --- drivers/bluetooth/Kconfig | 13 + drivers/bluetooth/Makefile | 1 + drivers/bluetooth/btmrvl_sdio.c | 1128 +++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/btmrvl_sdio.h | 113 ++++ 4 files changed, 1255 insertions(+) create mode 100644 drivers/bluetooth/btmrvl_sdio.c create mode 100644 drivers/bluetooth/btmrvl_sdio.h (limited to 'drivers') diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index b049a79fcc0..8c89bd4abbf 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -182,5 +182,18 @@ config BT_MRVL Say Y here to compile Marvell Bluetooth driver into the kernel or say M to compile it as module. +config BT_MRVL_SDIO + tristate "Marvell BT-over-SDIO driver" + depends on BT_MRVL && MMC + help + The driver for Marvell Bluetooth chipsets with SDIO interface. + + This driver is required if you want to use Marvell Bluetooth + devices with SDIO interface. Currently only SD8688 chipset is + supported. + + Say Y here to compile support for Marvell BT-over-SDIO driver + into the kernel or say M to compile it as module. + endmenu diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 3eff1231812..2dc12e7d015 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o btmrvl-objs := btmrvl_main.o obj-$(CONFIG_BT_MRVL) += btmrvl.o +obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c new file mode 100644 index 00000000000..8f13e7bea0b --- /dev/null +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -0,0 +1,1128 @@ +/** + * Marvell BT-over-SDIO driver: SDIO interface related functions. + * + * Copyright (C) 2009, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + **/ + +#include + +#include +#include + +#include +#include + +#include "btmrvl_drv.h" +#include "btmrvl_sdio.h" + +#define VERSION "1.0" + +#ifndef SDIO_DEVICE_ID_MARVELL_8688BT +#define SDIO_DEVICE_ID_MARVELL_8688BT 0x9105 +#endif + +/* The btmrvl_sdio_remove() callback function is called + * when user removes this module from kernel space or ejects + * the card from the slot. The driver handles these 2 cases + * differently. + * If the user is removing the module, a MODULE_SHUTDOWN_REQ + * command is sent to firmware and interrupt will be disabled. + * If the card is removed, there is no need to send command + * or disable interrupt. + * + * The variable 'user_rmmod' is used to distinguish these two + * scenarios. This flag is initialized as FALSE in case the card + * is removed, and will be set to TRUE for module removal when + * module_exit function is called. + */ +static u8 user_rmmod; + +static const struct sdio_device_id btmrvl_sdio_ids[] = { + {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8688BT)}, + {0, 0, 0, 0} +}; + +MODULE_DEVICE_TABLE(sdio, btmrvl_sdio_ids); + +static struct btmrvl_sdio_device btmrvl_sdio_devices[] = { + { + .dev_id = SDIO_DEVICE_ID_MARVELL_8688BT, + .helper = "sd8688_helper.bin", + .firmware = "sd8688.bin", + }, +}; + +static int btmrvl_sdio_get_rx_unit(struct btmrvl_sdio_card *card) +{ + u8 reg; + int ret; + + BT_DBG("Enter"); + + reg = sdio_readb(card->func, CARD_RX_UNIT_REG, &ret); + if (!ret) + card->rx_unit = reg; + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_read_fw_status(struct btmrvl_sdio_card *card, u16 *dat) +{ + int ret; + u8 fws0, fws1; + + BT_DBG("Enter"); + + *dat = 0; + + fws0 = sdio_readb(card->func, CARD_FW_STATUS0_REG, &ret); + + if (!ret) + fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret); + + if (ret) { + BT_DBG("Leave"); + return -EIO; + } + + *dat = (((u16) fws1) << 8) | fws0; + + BT_DBG("Leave"); + + return 0; +} + +static int btmrvl_sdio_read_rx_len(struct btmrvl_sdio_card *card, u16 *dat) +{ + int ret; + u8 reg; + + BT_DBG("Enter"); + + reg = sdio_readb(card->func, CARD_RX_LEN_REG, &ret); + if (!ret) + *dat = (u16) reg << card->rx_unit; + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_enable_host_int_mask(struct btmrvl_sdio_card *card, + u8 mask) +{ + int ret; + + BT_DBG("Enter"); + + sdio_writeb(card->func, mask, HOST_INT_MASK_REG, &ret); + if (ret) { + BT_ERR("Unable to enable the host interrupt!"); + ret = -EIO; + } + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_disable_host_int_mask(struct btmrvl_sdio_card *card, + u8 mask) +{ + int ret; + u8 host_int_mask; + + BT_DBG("Enter"); + + host_int_mask = sdio_readb(card->func, HOST_INT_MASK_REG, &ret); + if (ret) { + ret = -EIO; + goto done; + } + + host_int_mask &= ~mask; + + sdio_writeb(card->func, host_int_mask, HOST_INT_MASK_REG, &ret); + if (ret < 0) { + BT_ERR("Unable to disable the host interrupt!"); + ret = -EIO; + goto done; + } + + ret = 0; + +done: + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_poll_card_status(struct btmrvl_sdio_card *card, u8 bits) +{ + unsigned int tries; + int ret; + u8 status; + + BT_DBG("Enter"); + + for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) { + status = sdio_readb(card->func, CARD_STATUS_REG, &ret); + if (ret) + goto failed; + if ((status & bits) == bits) + goto done; + + udelay(1); + } + + ret = -ETIMEDOUT; + +failed: + BT_ERR("FAILED! ret=%d", ret); + +done: + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_verify_fw_download(struct btmrvl_sdio_card *card, + int pollnum) +{ + int ret = -ETIMEDOUT; + u16 firmwarestat; + unsigned int tries; + + BT_DBG("Enter"); + + /* Wait for firmware to become ready */ + for (tries = 0; tries < pollnum; tries++) { + if (btmrvl_sdio_read_fw_status(card, &firmwarestat) < 0) + continue; + + if (firmwarestat == FIRMWARE_READY) { + ret = 0; + break; + } else { + msleep(10); + } + } + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card) +{ + const struct firmware *fw_helper = NULL; + const u8 *helper = NULL; + int ret; + void *tmphlprbuf = NULL; + int tmphlprbufsz, hlprblknow, helperlen; + u8 *helperbuf; + u32 tx_len; + + BT_DBG("Enter"); + + ret = request_firmware(&fw_helper, card->helper, + &card->func->dev); + if ((ret < 0) || !fw_helper) { + BT_ERR("request_firmware(helper) failed, error code = %d", + ret); + ret = -ENOENT; + goto done; + } + + helper = fw_helper->data; + helperlen = fw_helper->size; + + BT_DBG("Downloading helper image (%d bytes), block size %d bytes", + helperlen, SDIO_BLOCK_SIZE); + + tmphlprbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN); + + tmphlprbuf = kmalloc(tmphlprbufsz, GFP_KERNEL); + if (!tmphlprbuf) { + BT_ERR("Unable to allocate buffer for helper." + " Terminating download"); + ret = -ENOMEM; + goto done; + } + + memset(tmphlprbuf, 0, tmphlprbufsz); + + helperbuf = (u8 *) ALIGN_ADDR(tmphlprbuf, BTSDIO_DMA_ALIGN); + + /* Perform helper data transfer */ + tx_len = (FIRMWARE_TRANSFER_NBLOCK * SDIO_BLOCK_SIZE) + - SDIO_HEADER_LEN; + hlprblknow = 0; + + do { + ret = btmrvl_sdio_poll_card_status(card, + CARD_IO_READY | DN_LD_CARD_RDY); + if (ret < 0) { + BT_ERR("Helper download poll status timeout @ %d", + hlprblknow); + goto done; + } + + /* Check if there is more data? */ + if (hlprblknow >= helperlen) + break; + + if (helperlen - hlprblknow < tx_len) + tx_len = helperlen - hlprblknow; + + /* Little-endian */ + helperbuf[0] = ((tx_len & 0x000000ff) >> 0); + helperbuf[1] = ((tx_len & 0x0000ff00) >> 8); + helperbuf[2] = ((tx_len & 0x00ff0000) >> 16); + helperbuf[3] = ((tx_len & 0xff000000) >> 24); + + memcpy(&helperbuf[SDIO_HEADER_LEN], &helper[hlprblknow], + tx_len); + + /* Now send the data */ + ret = sdio_writesb(card->func, card->ioport, + helperbuf, + FIRMWARE_TRANSFER_NBLOCK * + SDIO_BLOCK_SIZE); + if (ret < 0) { + BT_ERR("IO error during helper download @ %d", + hlprblknow); + goto done; + } + + hlprblknow += tx_len; + } while (true); + + BT_DBG("Transferring helper image EOF block"); + + memset(helperbuf, 0x0, SDIO_BLOCK_SIZE); + + ret = sdio_writesb(card->func, card->ioport, helperbuf, + SDIO_BLOCK_SIZE); + if (ret < 0) { + BT_ERR("IO error in writing helper image EOF block"); + goto done; + } + + ret = 0; + +done: + kfree(tmphlprbuf); + if (fw_helper) + release_firmware(fw_helper); + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) +{ + const struct firmware *fw_firmware = NULL; + const u8 *firmware = NULL; + int firmwarelen, tmpfwbufsz, ret; + unsigned int tries, offset; + u8 base0, base1; + void *tmpfwbuf = NULL; + u8 *fwbuf; + u16 len; + int txlen = 0, tx_blocks = 0, count = 0; + + BT_DBG("Enter"); + + ret = request_firmware(&fw_firmware, card->firmware, + &card->func->dev); + if ((ret < 0) || !fw_firmware) { + BT_ERR("request_firmware(firmware) failed, error code = %d", + ret); + ret = -ENOENT; + goto done; + } + + firmware = fw_firmware->data; + firmwarelen = fw_firmware->size; + + BT_DBG("Downloading FW image (%d bytes)", firmwarelen); + + tmpfwbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN); + tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL); + if (!tmpfwbuf) { + BT_ERR("Unable to allocate buffer for firmware." + " Terminating download"); + ret = -ENOMEM; + goto done; + } + + memset(tmpfwbuf, 0, tmpfwbufsz); + + /* Ensure aligned firmware buffer */ + fwbuf = (u8 *) ALIGN_ADDR(tmpfwbuf, BTSDIO_DMA_ALIGN); + + /* Perform firmware data transfer */ + offset = 0; + do { + ret = btmrvl_sdio_poll_card_status(card, + CARD_IO_READY | DN_LD_CARD_RDY); + if (ret < 0) { + BT_ERR("FW download with helper poll status" + " timeout @ %d", offset); + goto done; + } + + /* Check if there is more data ? */ + if (offset >= firmwarelen) + break; + + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { + base0 = sdio_readb(card->func, + SQ_READ_BASE_ADDRESS_A0_REG, &ret); + if (ret) { + BT_ERR("BASE0 register read failed:" + " base0 = 0x%04X(%d)." + " Terminating download", + base0, base0); + ret = -EIO; + goto done; + } + base1 = sdio_readb(card->func, + SQ_READ_BASE_ADDRESS_A1_REG, &ret); + if (ret) { + BT_ERR("BASE1 register read failed:" + " base1 = 0x%04X(%d)." + " Terminating download", + base1, base1); + ret = -EIO; + goto done; + } + + len = (((u16) base1) << 8) | base0; + if (len) + break; + + udelay(10); + } + + if (!len) + break; + else if (len > BTM_UPLD_SIZE) { + BT_ERR("FW download failure @%d, invalid length %d", + offset, len); + ret = -EINVAL; + goto done; + } + + txlen = len; + + if (len & BIT(0)) { + count++; + if (count > MAX_WRITE_IOMEM_RETRY) { + BT_ERR("FW download failure @%d, " + "over max retry count", offset); + ret = -EIO; + goto done; + } + BT_ERR("FW CRC error indicated by the helper: " + "len = 0x%04X, txlen = %d", len, txlen); + len &= ~BIT(0); + /* Set txlen to 0 so as to resend from same offset */ + txlen = 0; + } else { + count = 0; + + /* Last block ? */ + if (firmwarelen - offset < txlen) + txlen = firmwarelen - offset; + + tx_blocks = + (txlen + SDIO_BLOCK_SIZE - 1) / SDIO_BLOCK_SIZE; + + memcpy(fwbuf, &firmware[offset], txlen); + } + + ret = sdio_writesb(card->func, card->ioport, fwbuf, + tx_blocks * SDIO_BLOCK_SIZE); + + if (ret < 0) { + BT_ERR("FW download, writesb(%d) failed @%d", + count, offset); + sdio_writeb(card->func, HOST_CMD53_FIN, CONFIG_REG, + &ret); + if (ret) + BT_ERR("writeb failed (CFG)"); + } + + offset += txlen; + } while (true); + + BT_DBG("FW download over, size %d bytes", offset); + + ret = 0; + +done: + kfree(tmpfwbuf); + + if (fw_firmware) + release_firmware(fw_firmware); + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) +{ + u16 buf_len = 0; + int ret, buf_block_len, blksz; + struct sk_buff *skb = NULL; + u32 type; + u8 *payload = NULL; + struct hci_dev *hdev = priv->btmrvl_dev.hcidev; + struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; + + BT_DBG("Enter"); + + if (!card || !card->func) { + BT_ERR("card or function is NULL!"); + ret = -EINVAL; + goto exit; + } + + /* Read the length of data to be transferred */ + ret = btmrvl_sdio_read_rx_len(card, &buf_len); + if (ret < 0) { + BT_ERR("read rx_len failed"); + ret = -EIO; + goto exit; + } + + blksz = SDIO_BLOCK_SIZE; + buf_block_len = (buf_len + blksz - 1) / blksz; + + if (buf_len <= SDIO_HEADER_LEN + || (buf_block_len * blksz) > ALLOC_BUF_SIZE) { + BT_ERR("invalid packet length: %d", buf_len); + ret = -EINVAL; + goto exit; + } + + /* Allocate buffer */ + skb = bt_skb_alloc(buf_block_len * blksz + BTSDIO_DMA_ALIGN, + GFP_ATOMIC); + if (skb == NULL) { + BT_ERR("No free skb"); + goto exit; + } + + if ((u32) skb->data & (BTSDIO_DMA_ALIGN - 1)) { + skb_put(skb, (u32) skb->data & (BTSDIO_DMA_ALIGN - 1)); + skb_pull(skb, (u32) skb->data & (BTSDIO_DMA_ALIGN - 1)); + } + + payload = skb->tail; + + ret = sdio_readsb(card->func, payload, card->ioport, + buf_block_len * blksz); + if (ret < 0) { + BT_ERR("readsb failed: %d", ret); + ret = -EIO; + goto exit; + } + + /* This is SDIO specific header length: byte[2][1][0], type: byte[3] + * (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor) + */ + + buf_len = payload[0]; + buf_len |= (u16) payload[1] << 8; + type = payload[3]; + + switch (type) { + case HCI_ACLDATA_PKT: + case HCI_SCODATA_PKT: + case HCI_EVENT_PKT: + bt_cb(skb)->pkt_type = type; + skb->dev = (void *)hdev; + skb_put(skb, buf_len); + skb_pull(skb, SDIO_HEADER_LEN); + + if (type == HCI_EVENT_PKT) + btmrvl_check_evtpkt(priv, skb); + + hci_recv_frame(skb); + hdev->stat.byte_rx += buf_len; + break; + + case MRVL_VENDOR_PKT: + bt_cb(skb)->pkt_type = HCI_VENDOR_PKT; + skb->dev = (void *)hdev; + skb_put(skb, buf_len); + skb_pull(skb, SDIO_HEADER_LEN); + + if (btmrvl_process_event(priv, skb)) + hci_recv_frame(skb); + + hdev->stat.byte_rx += buf_len; + break; + + default: + BT_ERR("Unknow packet type:%d", type); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, payload, + blksz * buf_block_len); + + kfree_skb(skb); + skb = NULL; + break; + } + +exit: + if (ret) { + hdev->stat.err_rx++; + if (skb) + kfree_skb(skb); + } + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_get_int_status(struct btmrvl_private *priv, u8 * ireg) +{ + int ret; + u8 sdio_ireg = 0; + struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; + + BT_DBG("Enter"); + + *ireg = 0; + + sdio_ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret); + if (ret) { + BT_ERR("sdio_readb: read int status register failed"); + ret = -EIO; + goto done; + } + + if (sdio_ireg != 0) { + /* + * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS + * Clear the interrupt status register and re-enable the + * interrupt. + */ + BT_DBG("sdio_ireg = 0x%x", sdio_ireg); + + sdio_writeb(card->func, ~(sdio_ireg) & (DN_LD_HOST_INT_STATUS | + UP_LD_HOST_INT_STATUS), + HOST_INTSTATUS_REG, &ret); + if (ret) { + BT_ERR("sdio_writeb: clear int status register " + "failed"); + ret = -EIO; + goto done; + } + } + + if (sdio_ireg & DN_LD_HOST_INT_STATUS) { + if (priv->btmrvl_dev.tx_dnld_rdy) + BT_DBG("tx_done already received: " + " int_status=0x%x", sdio_ireg); + else + priv->btmrvl_dev.tx_dnld_rdy = true; + } + + if (sdio_ireg & UP_LD_HOST_INT_STATUS) + btmrvl_sdio_card_to_host(priv); + + *ireg = sdio_ireg; + + ret = 0; + +done: + BT_DBG("Leave"); + + return ret; +} + +static void btmrvl_sdio_interrupt(struct sdio_func *func) +{ + struct btmrvl_private *priv; + struct hci_dev *hcidev; + struct btmrvl_sdio_card *card; + u8 ireg = 0; + + BT_DBG("Enter"); + + card = sdio_get_drvdata(func); + if (card && card->priv) { + priv = card->priv; + hcidev = priv->btmrvl_dev.hcidev; + + if (btmrvl_sdio_get_int_status(priv, &ireg)) + BT_ERR("reading HOST_INT_STATUS_REG failed"); + else + BT_DBG("HOST_INT_STATUS_REG %#x", ireg); + + btmrvl_interrupt(priv); + } + + BT_DBG("Leave"); +} + +static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) +{ + int ret = 0, i; + u8 reg; + struct sdio_func *func; + + BT_DBG("Enter"); + + if (!card || !card->func) { + BT_ERR("Error: card or function is NULL!"); + ret = -EINVAL; + goto failed; + } + + func = card->func; + + for (i = 0; i < ARRAY_SIZE(btmrvl_sdio_devices); i++) { + if (func->device == btmrvl_sdio_devices[i].dev_id) + break; + } + + if (i == ARRAY_SIZE(btmrvl_sdio_devices)) { + BT_ERR("Error: unknown device id 0x%x", func->device); + ret = -EINVAL; + goto failed; + } + + card->helper = btmrvl_sdio_devices[i].helper; + card->firmware = btmrvl_sdio_devices[i].firmware; + + sdio_claim_host(func); + + ret = sdio_enable_func(func); + if (ret) { + BT_ERR("sdio_enable_func() failed: ret=%d", ret); + ret = -EIO; + goto release_host; + } + + ret = sdio_claim_irq(func, btmrvl_sdio_interrupt); + if (ret) { + BT_ERR("sdio_claim_irq failed: ret=%d", ret); + ret = -EIO; + goto disable_func; + } + + ret = sdio_set_block_size(card->func, SDIO_BLOCK_SIZE); + if (ret) { + BT_ERR("cannot set SDIO block size"); + ret = -EIO; + goto release_irq; + } + + reg = sdio_readb(func, IO_PORT_0_REG, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + + card->ioport = reg; + + reg = sdio_readb(func, IO_PORT_1_REG, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + + card->ioport |= (reg << 8); + + reg = sdio_readb(func, IO_PORT_2_REG, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + + card->ioport |= (reg << 16); + + BT_DBG("SDIO FUNC%d IO port: 0x%x", func->num, card->ioport); + + sdio_set_drvdata(func, card); + + sdio_release_host(func); + + BT_DBG("Leave"); + return 0; + +release_irq: + sdio_release_irq(func); + +disable_func: + sdio_disable_func(func); + +release_host: + sdio_release_host(func); + +failed: + BT_DBG("Leave"); + return ret; +} + +static int btmrvl_sdio_unregister_dev(struct btmrvl_sdio_card *card) +{ + BT_DBG("Enter"); + + if (card && card->func) { + sdio_claim_host(card->func); + sdio_release_irq(card->func); + sdio_disable_func(card->func); + sdio_release_host(card->func); + sdio_set_drvdata(card->func, NULL); + } + + BT_DBG("Leave"); + + return 0; +} + +static int btmrvl_sdio_enable_host_int(struct btmrvl_sdio_card *card) +{ + int ret; + + BT_DBG("Enter"); + + if (!card || !card->func) { + BT_DBG("Leave"); + return -EINVAL; + } + + sdio_claim_host(card->func); + + ret = btmrvl_sdio_enable_host_int_mask(card, HIM_ENABLE); + + btmrvl_sdio_get_rx_unit(card); + + sdio_release_host(card->func); + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_disable_host_int(struct btmrvl_sdio_card *card) +{ + int ret; + + BT_DBG("Enter"); + + if (!card || !card->func) { + BT_DBG("Leave"); + return -EINVAL; + } + + sdio_claim_host(card->func); + + ret = btmrvl_sdio_disable_host_int_mask(card, HIM_DISABLE); + + sdio_release_host(card->func); + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv, + u8 *payload, u16 nb) +{ + struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; + int ret = 0; + int buf_block_len; + int blksz; + int i = 0; + u8 *buf = NULL; + void *tmpbuf = NULL; + int tmpbufsz; + + BT_DBG("Enter"); + + if (!card || !card->func) { + BT_ERR("card or function is NULL!"); + BT_DBG("Leave"); + return -EINVAL; + } + + buf = payload; + if ((u32) payload & (BTSDIO_DMA_ALIGN - 1)) { + tmpbufsz = ALIGN_SZ(nb, BTSDIO_DMA_ALIGN); + tmpbuf = kmalloc(tmpbufsz, GFP_KERNEL); + memset(tmpbuf, 0, tmpbufsz); + buf = (u8 *) ALIGN_ADDR(tmpbuf, BTSDIO_DMA_ALIGN); + memcpy(buf, payload, nb); + } + + blksz = SDIO_BLOCK_SIZE; + buf_block_len = (nb + blksz - 1) / blksz; + + sdio_claim_host(card->func); + + do { + /* Transfer data to card */ + ret = sdio_writesb(card->func, card->ioport, buf, + buf_block_len * blksz); + if (ret < 0) { + i++; + BT_ERR("i=%d writesb failed: %d", i, ret); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, + payload, nb); + ret = -EIO; + if (i > MAX_WRITE_IOMEM_RETRY) + goto exit; + } + } while (ret); + + priv->btmrvl_dev.tx_dnld_rdy = false; + +exit: + sdio_release_host(card->func); + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card) +{ + int ret = 0; + + BT_DBG("Enter"); + + if (!card || !card->func) { + BT_ERR("card or function is NULL!"); + BT_DBG("Leave"); + return -EINVAL; + } + sdio_claim_host(card->func); + + if (!btmrvl_sdio_verify_fw_download(card, 1)) { + BT_DBG("Firmware already downloaded!"); + goto done; + } + + ret = btmrvl_sdio_download_helper(card); + if (ret) { + BT_ERR("Failed to download helper!"); + ret = -EIO; + goto done; + } + + if (btmrvl_sdio_download_fw_w_helper(card)) { + BT_ERR("Failed to download firmware!"); + ret = -EIO; + goto done; + } + + if (btmrvl_sdio_verify_fw_download(card, MAX_POLL_TRIES)) { + BT_ERR("FW failed to be active in time!"); + ret = -ETIMEDOUT; + goto done; + } + +done: + sdio_release_host(card->func); + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv) +{ + struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; + int ret = 0; + + BT_DBG("Enter"); + + if (!card || !card->func) { + BT_ERR("card or function is NULL!"); + BT_DBG("Leave"); + return -EINVAL; + } + + sdio_claim_host(card->func); + + sdio_writeb(card->func, HOST_POWER_UP, CONFIG_REG, &ret); + + sdio_release_host(card->func); + + BT_DBG("wake up firmware"); + + BT_DBG("Leave"); + + return ret; +} + +static int btmrvl_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + int ret = 0; + struct btmrvl_private *priv = NULL; + struct btmrvl_sdio_card *card = NULL; + + BT_DBG("Enter"); + + BT_INFO("vendor=0x%x, device=0x%x, class=%d, fn=%d", + id->vendor, id->device, id->class, func->num); + + card = kzalloc(sizeof(*card), GFP_KERNEL); + if (!card) { + ret = -ENOMEM; + goto done; + } + + card->func = func; + + if (btmrvl_sdio_register_dev(card) < 0) { + BT_ERR("Failed to register BT device!"); + ret = -ENODEV; + goto free_card; + } + + /* Disable the interrupts on the card */ + btmrvl_sdio_disable_host_int(card); + + if (btmrvl_sdio_download_fw(card)) { + BT_ERR("Downloading firmware failed!"); + ret = -ENODEV; + goto unreg_dev; + } + + msleep(100); + + btmrvl_sdio_enable_host_int(card); + + priv = btmrvl_add_card(card); + if (!priv) { + BT_ERR("Initializing card failed!"); + ret = -ENODEV; + goto disable_host_int; + } + + card->priv = priv; + + /* Initialize the interface specific function pointers */ + priv->hw_host_to_card = btmrvl_sdio_host_to_card; + priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw; + + strncpy(priv->btmrvl_dev.name, "btmrvl_sdio0", + sizeof(priv->btmrvl_dev.name)); + + btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ); + + BT_DBG("Leave"); + + return 0; + +disable_host_int: + btmrvl_sdio_disable_host_int(card); +unreg_dev: + btmrvl_sdio_unregister_dev(card); +free_card: + kfree(card); +done: + BT_DBG("Leave"); + + return ret; +} + +static void btmrvl_sdio_remove(struct sdio_func *func) +{ + struct btmrvl_sdio_card *card; + + BT_DBG("Enter"); + + if (func) { + card = sdio_get_drvdata(func); + if (card) { + /* Send SHUTDOWN command & disable interrupt + * if user removes the module. + */ + if (user_rmmod) { + btmrvl_send_module_cfg_cmd(card->priv, + MODULE_SHUTDOWN_REQ); + btmrvl_sdio_disable_host_int(card); + } + BT_DBG("unregester dev"); + btmrvl_sdio_unregister_dev(card); + btmrvl_remove_card(card->priv); + kfree(card); + } + } + + BT_DBG("Leave"); +} + +static struct sdio_driver bt_mrvl_sdio = { + .name = "btmrvl_sdio", + .id_table = btmrvl_sdio_ids, + .probe = btmrvl_sdio_probe, + .remove = btmrvl_sdio_remove, +}; + +static int btmrvl_sdio_init_module(void) +{ + BT_DBG("Enter"); + + if (sdio_register_driver(&bt_mrvl_sdio) != 0) { + BT_ERR("SDIO Driver Registration Failed"); + BT_DBG("Leave"); + return -ENODEV; + } + + /* Clear the flag in case user removes the card. */ + user_rmmod = 0; + + BT_DBG("Leave"); + + return 0; +} + +static void btmrvl_sdio_exit_module(void) +{ + BT_DBG("Enter"); + + /* Set the flag as user is removing this module. */ + user_rmmod = 1; + + sdio_unregister_driver(&bt_mrvl_sdio); + + BT_DBG("Leave"); +} + +module_init(btmrvl_sdio_init_module); +module_exit(btmrvl_sdio_exit_module); + +MODULE_AUTHOR("Marvell International Ltd."); +MODULE_DESCRIPTION("Marvell BT-over-SDIO Driver v" VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h new file mode 100644 index 00000000000..08bef333ded --- /dev/null +++ b/drivers/bluetooth/btmrvl_sdio.h @@ -0,0 +1,113 @@ +/** + * Marvell BT-over-SDIO driver: SDIO interface related definitions + * + * Copyright (C) 2009, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + **/ + +#ifndef _BTMRVL_SDIO_H_ +#define _BTMRVL_SDIO_H_ + +#define SDIO_HEADER_LEN 4 + +/* SD block size can not bigger than 64 due to buf size limit in firmware */ +/* define SD block size for data Tx/Rx */ +#define SDIO_BLOCK_SIZE 64 + +/* Number of blocks for firmware transfer */ +#define FIRMWARE_TRANSFER_NBLOCK 2 + +/* This is for firmware specific length */ +#define FW_EXTRA_LEN 36 + +#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024) + +#define MRVDRV_BT_RX_PACKET_BUFFER_SIZE \ + (HCI_MAX_FRAME_SIZE + FW_EXTRA_LEN) + +#define ALLOC_BUF_SIZE (((max_t (int, MRVDRV_BT_RX_PACKET_BUFFER_SIZE, \ + MRVDRV_SIZE_OF_CMD_BUFFER) + SDIO_HEADER_LEN \ + + SDIO_BLOCK_SIZE - 1) / SDIO_BLOCK_SIZE) \ + * SDIO_BLOCK_SIZE) + +/* The number of times to try when polling for status */ +#define MAX_POLL_TRIES 100 + +/* Max retry number of CMD53 write */ +#define MAX_WRITE_IOMEM_RETRY 2 + +/* Host Control Registers */ +#define IO_PORT_0_REG 0x00 +#define IO_PORT_1_REG 0x01 +#define IO_PORT_2_REG 0x02 + +#define CONFIG_REG 0x03 +#define HOST_POWER_UP BIT(1) +#define HOST_CMD53_FIN BIT(2) + +#define HOST_INT_MASK_REG 0x04 +#define HIM_DISABLE 0xff +#define HIM_ENABLE (BIT(0) | BIT(1)) + +#define HOST_INTSTATUS_REG 0x05 +#define UP_LD_HOST_INT_STATUS BIT(0) +#define DN_LD_HOST_INT_STATUS BIT(1) + +/* Card Control Registers */ +#define SQ_READ_BASE_ADDRESS_A0_REG 0x10 +#define SQ_READ_BASE_ADDRESS_A1_REG 0x11 + +#define CARD_STATUS_REG 0x20 +#define DN_LD_CARD_RDY BIT(0) +#define CARD_IO_READY BIT(3) + +#define CARD_FW_STATUS0_REG 0x40 +#define CARD_FW_STATUS1_REG 0x41 +#define FIRMWARE_READY 0xfedc + +#define CARD_RX_LEN_REG 0x42 +#define CARD_RX_UNIT_REG 0x43 + + +struct btmrvl_sdio_card { + struct sdio_func *func; + u32 ioport; + const char *helper; + const char *firmware; + u8 rx_unit; + struct btmrvl_private *priv; +}; + +struct btmrvl_sdio_device { + unsigned short dev_id; + const char *helper; + const char *firmware; +}; + + +/* Platform specific DMA alignment */ +#define BTSDIO_DMA_ALIGN 8 + +/* Macros for Data Alignment : size */ +#define ALIGN_SZ(p, a) \ + (((p) + ((a) - 1)) & ~((a) - 1)) + +/* Macros for Data Alignment : address */ +#define ALIGN_ADDR(p, a) \ + ((((u32)(p)) + (((u32)(a)) - 1)) & ~(((u32)(a)) - 1)) + +#endif /* _BTMRVL_SDIO_H_ */ -- cgit v1.2.3-18-g5258 From fb784f0508d5aa39a23e72879a8dfb517c6f6e7f Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Tue, 2 Jun 2009 14:29:37 -0700 Subject: Bluetooth: Add debugfs support to btmrvl driver /debug/btmrvl/config/ /debug/btmrvl/status/ See Documentation/btmrvl.txt for details. This patch incorporates a lot of comments given by Nicolas Pitre . Many thanks to Nicolas Pitre. Signed-off-by: Rahul Tank Signed-off-by: Bing Zhao Signed-off-by: Marcel Holtmann --- drivers/bluetooth/Kconfig | 1 + drivers/bluetooth/Makefile | 2 +- drivers/bluetooth/btmrvl_debugfs.c | 469 +++++++++++++++++++++++++++++++++++++ drivers/bluetooth/btmrvl_drv.h | 8 + drivers/bluetooth/btmrvl_main.c | 8 + 5 files changed, 487 insertions(+), 1 deletion(-) create mode 100644 drivers/bluetooth/btmrvl_debugfs.c (limited to 'drivers') diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 8c89bd4abbf..5f04014b62a 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -173,6 +173,7 @@ config BT_HCIVHCI config BT_MRVL tristate "Marvell Bluetooth driver support" select FW_LOADER + select DEBUG_FS help The core driver to support Marvell Bluetooth devices. diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 2dc12e7d015..75f70e0e3e5 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o obj-$(CONFIG_BT_HCIBTUSB) += btusb.o obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o -btmrvl-objs := btmrvl_main.o +btmrvl-objs := btmrvl_main.o btmrvl_debugfs.o obj-$(CONFIG_BT_MRVL) += btmrvl.o obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c new file mode 100644 index 00000000000..747bb0c723c --- /dev/null +++ b/drivers/bluetooth/btmrvl_debugfs.c @@ -0,0 +1,469 @@ +/** + * Marvell Bluetooth driver: debugfs related functions + * + * Copyright (C) 2009, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + **/ + +#include + +#include +#include + +#include "btmrvl_drv.h" + +struct btmrvl_debugfs_data { + struct dentry *root_dir, *config_dir, *status_dir; + + /* config */ + struct dentry *drvdbg; + struct dentry *psmode; + struct dentry *pscmd; + struct dentry *hsmode; + struct dentry *hscmd; + struct dentry *gpiogap; + struct dentry *hscfgcmd; + + /* status */ + struct dentry *curpsmode; + struct dentry *hsstate; + struct dentry *psstate; + struct dentry *txdnldready; +}; + +static int btmrvl_open_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t btmrvl_hscfgcmd_write(struct file *file, + const char __user *ubuf, + size_t count, + loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + + long result, ret; + char buf[16]; + + memset(buf, 0, sizeof(buf)); + + if (copy_from_user(&buf, ubuf, + min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + ret = strict_strtol(buf, 10, &result); + + priv->btmrvl_dev.hscfgcmd = result; + + if (priv->btmrvl_dev.hscfgcmd) { + btmrvl_prepare_command(priv); + wake_up_interruptible(&priv->main_thread.wait_q); + } + + return count; +} + +static ssize_t btmrvl_hscfgcmd_read(struct file *file, char __user * userbuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + int ret; + char buf[16]; + + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", + priv->btmrvl_dev.hscfgcmd); + + return simple_read_from_buffer(userbuf, count, ppos, buf, ret); +} + +static const struct file_operations btmrvl_hscfgcmd_fops = { + .read = btmrvl_hscfgcmd_read, + .write = btmrvl_hscfgcmd_write, + .open = btmrvl_open_generic, +}; + +static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + long result, ret; + char buf[16]; + + memset(buf, 0, sizeof(buf)); + + if (copy_from_user(&buf, ubuf, + min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + ret = strict_strtol(buf, 10, &result); + + priv->btmrvl_dev.psmode = result; + + return count; +} + +static ssize_t btmrvl_psmode_read(struct file *file, char __user * userbuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + int ret; + char buf[16]; + + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", + priv->btmrvl_dev.psmode); + + return simple_read_from_buffer(userbuf, count, ppos, buf, ret); +} + +static const struct file_operations btmrvl_psmode_fops = { + .read = btmrvl_psmode_read, + .write = btmrvl_psmode_write, + .open = btmrvl_open_generic, +}; + +static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + long result, ret; + char buf[16]; + + memset(buf, 0, sizeof(buf)); + + if (copy_from_user(&buf, ubuf, + min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + ret = strict_strtol(buf, 10, &result); + + priv->btmrvl_dev.pscmd = result; + + if (priv->btmrvl_dev.pscmd) { + btmrvl_prepare_command(priv); + wake_up_interruptible(&priv->main_thread.wait_q); + } + + return count; + +} + +static ssize_t btmrvl_pscmd_read(struct file *file, char __user * userbuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + int ret; + char buf[16]; + + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.pscmd); + + return simple_read_from_buffer(userbuf, count, ppos, buf, ret); +} + +static const struct file_operations btmrvl_pscmd_fops = { + .read = btmrvl_pscmd_read, + .write = btmrvl_pscmd_write, + .open = btmrvl_open_generic, +}; + +static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + long result, ret; + char buf[16]; + + memset(buf, 0, sizeof(buf)); + + if (copy_from_user(&buf, ubuf, + min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + ret = strict_strtol(buf, 16, &result); + + priv->btmrvl_dev.gpio_gap = result; + + return count; +} + +static ssize_t btmrvl_gpiogap_read(struct file *file, char __user * userbuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + int ret; + char buf[16]; + + ret = snprintf(buf, sizeof(buf) - 1, "0x%x\n", + priv->btmrvl_dev.gpio_gap); + + return simple_read_from_buffer(userbuf, count, ppos, buf, ret); +} + +static const struct file_operations btmrvl_gpiogap_fops = { + .read = btmrvl_gpiogap_read, + .write = btmrvl_gpiogap_write, + .open = btmrvl_open_generic, +}; + +static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + long result, ret; + char buf[16]; + + memset(buf, 0, sizeof(buf)); + + if (copy_from_user(&buf, ubuf, + min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + ret = strict_strtol(buf, 10, &result); + + priv->btmrvl_dev.hscmd = result; + if (priv->btmrvl_dev.hscmd) { + btmrvl_prepare_command(priv); + wake_up_interruptible(&priv->main_thread.wait_q); + } + + return count; +} + +static ssize_t btmrvl_hscmd_read(struct file *file, char __user * userbuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + int ret; + char buf[16]; + + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hscmd); + + return simple_read_from_buffer(userbuf, count, ppos, buf, ret); +} + +static const struct file_operations btmrvl_hscmd_fops = { + .read = btmrvl_hscmd_read, + .write = btmrvl_hscmd_write, + .open = btmrvl_open_generic, +}; + +static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + long result, ret; + char buf[16]; + + memset(buf, 0, sizeof(buf)); + + if (copy_from_user(&buf, ubuf, + min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + ret = strict_strtol(buf, 10, &result); + + priv->btmrvl_dev.hsmode = result; + + return count; +} + +static ssize_t btmrvl_hsmode_read(struct file *file, char __user * userbuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + int ret; + char buf[16]; + + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", + priv->btmrvl_dev.hsmode); + + return simple_read_from_buffer(userbuf, count, ppos, buf, ret); +} + +static const struct file_operations btmrvl_hsmode_fops = { + .read = btmrvl_hsmode_read, + .write = btmrvl_hsmode_write, + .open = btmrvl_open_generic, +}; + +static ssize_t btmrvl_curpsmode_read(struct file *file, char __user * userbuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + int ret; + char buf[16]; + + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->psmode); + + return simple_read_from_buffer(userbuf, count, ppos, buf, ret); +} + +static const struct file_operations btmrvl_curpsmode_fops = { + .read = btmrvl_curpsmode_read, + .open = btmrvl_open_generic, +}; + +static ssize_t btmrvl_psstate_read(struct file *file, char __user * userbuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + int ret; + char buf[16]; + + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", + priv->adapter->ps_state); + + return simple_read_from_buffer(userbuf, count, ppos, buf, ret); +} + +static const struct file_operations btmrvl_psstate_fops = { + .read = btmrvl_psstate_read, + .open = btmrvl_open_generic, +}; + +static ssize_t btmrvl_hsstate_read(struct file *file, char __user * userbuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + int ret; + char buf[16]; + + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", + priv->adapter->hs_state); + + return simple_read_from_buffer(userbuf, count, ppos, buf, ret); +} + +static const struct file_operations btmrvl_hsstate_fops = { + .read = btmrvl_hsstate_read, + .open = btmrvl_open_generic, +}; + +static ssize_t btmrvl_txdnldready_read(struct file *file, char __user * userbuf, + size_t count, loff_t *ppos) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) file->private_data; + int ret; + char buf[16]; + + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", + priv->btmrvl_dev.tx_dnld_rdy); + + return simple_read_from_buffer(userbuf, count, ppos, buf, ret); +} + +static const struct file_operations btmrvl_txdnldready_fops = { + .read = btmrvl_txdnldready_read, + .open = btmrvl_open_generic, +}; + +void btmrvl_debugfs_init(struct hci_dev *hdev) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) hdev->driver_data; + struct btmrvl_debugfs_data *dbg; + + dbg = kzalloc(sizeof(*dbg), GFP_KERNEL); + priv->debugfs_data = dbg; + + if (!dbg) { + BT_ERR("Can not allocate memory for btmrvl_debugfs_data."); + return; + } + + dbg->root_dir = debugfs_create_dir("btmrvl", NULL); + + dbg->config_dir = debugfs_create_dir("config", dbg->root_dir); + + dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir, + hdev->driver_data, + &btmrvl_psmode_fops); + dbg->pscmd = + debugfs_create_file("pscmd", 0644, dbg->config_dir, + hdev->driver_data, &btmrvl_pscmd_fops); + dbg->gpiogap = + debugfs_create_file("gpiogap", 0644, dbg->config_dir, + hdev->driver_data, &btmrvl_gpiogap_fops); + dbg->hsmode = + debugfs_create_file("hsmode", 0644, dbg->config_dir, + hdev->driver_data, &btmrvl_hsmode_fops); + dbg->hscmd = + debugfs_create_file("hscmd", 0644, dbg->config_dir, + hdev->driver_data, &btmrvl_hscmd_fops); + dbg->hscfgcmd = + debugfs_create_file("hscfgcmd", 0644, dbg->config_dir, + hdev->driver_data, &btmrvl_hscfgcmd_fops); + + dbg->status_dir = debugfs_create_dir("status", dbg->root_dir); + dbg->curpsmode = debugfs_create_file("curpsmode", 0444, + dbg->status_dir, + hdev->driver_data, + &btmrvl_curpsmode_fops); + dbg->psstate = + debugfs_create_file("psstate", 0444, dbg->status_dir, + hdev->driver_data, &btmrvl_psstate_fops); + dbg->hsstate = + debugfs_create_file("hsstate", 0444, dbg->status_dir, + hdev->driver_data, &btmrvl_hsstate_fops); + dbg->txdnldready = + debugfs_create_file("txdnldready", 0444, dbg->status_dir, + hdev->driver_data, &btmrvl_txdnldready_fops); +} + +void btmrvl_debugfs_remove(struct hci_dev *hdev) +{ + struct btmrvl_private *priv = + (struct btmrvl_private *) hdev->driver_data; + struct btmrvl_debugfs_data *dbg = priv->debugfs_data; + + if (!dbg) + return; + + debugfs_remove(dbg->psmode); + debugfs_remove(dbg->pscmd); + debugfs_remove(dbg->gpiogap); + debugfs_remove(dbg->hsmode); + debugfs_remove(dbg->hscmd); + debugfs_remove(dbg->hscfgcmd); + debugfs_remove(dbg->config_dir); + + debugfs_remove(dbg->curpsmode); + debugfs_remove(dbg->psstate); + debugfs_remove(dbg->hsstate); + debugfs_remove(dbg->txdnldready); + debugfs_remove(dbg->status_dir); + + debugfs_remove(dbg->root_dir); + + kfree(dbg); +} diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index 9ad71f48110..7a12f6883bf 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -79,6 +79,9 @@ struct btmrvl_private { u8 *payload, u16 nb); int (*hw_wakeup_firmware) (struct btmrvl_private *priv); spinlock_t driver_lock; /* spinlock used by driver */ +#ifdef CONFIG_DEBUG_FS + void *debugfs_data; +#endif }; #define MRVL_VENDOR_PKT 0xFE @@ -135,4 +138,9 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb); int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd); int btmrvl_prepare_command(struct btmrvl_private *priv); +#ifdef CONFIG_DEBUG_FS +void btmrvl_debugfs_init(struct hci_dev *hdev); +void btmrvl_debugfs_remove(struct hci_dev *hdev); +#endif + #endif /* _BTMRVL_DRV_H_ */ diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 11c2f2cecf1..b4f44454666 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -658,6 +658,10 @@ struct btmrvl_private *btmrvl_add_card(void *card) goto err_hci_register_dev; } +#ifdef CONFIG_DEBUG_FS + btmrvl_debugfs_init(hdev); +#endif + BT_DBG("Leave"); return priv; @@ -692,6 +696,10 @@ int btmrvl_remove_card(struct btmrvl_private *priv) kthread_stop(priv->main_thread.task); +#ifdef CONFIG_DEBUG_FS + btmrvl_debugfs_remove(hdev); +#endif + hci_unregister_dev(hdev); hci_free_dev(hdev); -- cgit v1.2.3-18-g5258 From e7a25f9839fd392ec2c96e7e2b3734501d761a24 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 9 Jun 2009 13:42:54 +0200 Subject: Bluetooth: Fix Kconfig for Marvell Bluetooth driver The Marvell driver selects DEBUG_FS and FW_LOADER for its core driver and that is pointless. Don't select DEBUG_FS since it is either enabled or not and it is not for the driver to enable it. Also FW_LOADER is only used within the SDIO driver and so just have that one select the FW_LOADER option. Signed-off-by: Marcel Holtmann --- drivers/bluetooth/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 5f04014b62a..652367aa654 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -172,8 +172,6 @@ config BT_HCIVHCI config BT_MRVL tristate "Marvell Bluetooth driver support" - select FW_LOADER - select DEBUG_FS help The core driver to support Marvell Bluetooth devices. @@ -186,6 +184,7 @@ config BT_MRVL config BT_MRVL_SDIO tristate "Marvell BT-over-SDIO driver" depends on BT_MRVL && MMC + select FW_LOADER help The driver for Marvell Bluetooth chipsets with SDIO interface. -- cgit v1.2.3-18-g5258 From 08b0b0ce8c609b0e2284b134f0614e211374a038 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 9 Jun 2009 15:44:03 +0200 Subject: Bluetooth: Fix compilation of Marvell driver without debugfs The Makefile entry for the Marvell driver is broken when it comes to handling the optional DEBUG_FS correctly. That must have been the reason why they were using select in Kconfig in the first place. Fix this and make it really optional. Signed-off-by: Marcel Holtmann --- drivers/bluetooth/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 75f70e0e3e5..b3f57d2d4eb 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -15,10 +15,12 @@ obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o obj-$(CONFIG_BT_HCIBTUSB) += btusb.o obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o -btmrvl-objs := btmrvl_main.o btmrvl_debugfs.o obj-$(CONFIG_BT_MRVL) += btmrvl.o obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o +btmrvl-y := btmrvl_main.o +btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o + hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o -- cgit v1.2.3-18-g5258 From 944fe798c6a48336e82bbc0d4e280587325a4d95 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 9 Jun 2009 15:46:07 +0200 Subject: Bluetooth: Remove pointless ifdef protection for Marvell header files Both header files of the Marvell Bluetooth driver are private anyway and if the driver happens to include them twice or they create a circular dependency then the driver needs fixing. So just remove both pointless ifdefs. Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_drv.h | 5 ----- drivers/bluetooth/btmrvl_sdio.h | 5 ----- 2 files changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index 7a12f6883bf..5da3be40770 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -19,9 +19,6 @@ * */ -#ifndef _BTMRVL_DRV_H_ -#define _BTMRVL_DRV_H_ - #include #include #include @@ -142,5 +139,3 @@ int btmrvl_prepare_command(struct btmrvl_private *priv); void btmrvl_debugfs_init(struct hci_dev *hdev); void btmrvl_debugfs_remove(struct hci_dev *hdev); #endif - -#endif /* _BTMRVL_DRV_H_ */ diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h index 08bef333ded..6beb340685e 100644 --- a/drivers/bluetooth/btmrvl_sdio.h +++ b/drivers/bluetooth/btmrvl_sdio.h @@ -19,9 +19,6 @@ * **/ -#ifndef _BTMRVL_SDIO_H_ -#define _BTMRVL_SDIO_H_ - #define SDIO_HEADER_LEN 4 /* SD block size can not bigger than 64 due to buf size limit in firmware */ @@ -109,5 +106,3 @@ struct btmrvl_sdio_device { /* Macros for Data Alignment : address */ #define ALIGN_ADDR(p, a) \ ((((u32)(p)) + (((u32)(a)) - 1)) & ~(((u32)(a)) - 1)) - -#endif /* _BTMRVL_SDIO_H_ */ -- cgit v1.2.3-18-g5258 From 542399037d0cb2b2e96dfb8ced35b07dfb1c3706 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 9 Jun 2009 15:48:35 +0200 Subject: Bluetooth: Remove pointless casts from Marvell debugfs support The Marvell Bluetooth driver has debugfs support and they are casting like there is no tomorrow. Remove all of them and magically the code becomes more readable. Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_debugfs.c | 249 ++++++++++++++++--------------------- 1 file changed, 106 insertions(+), 143 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c index 747bb0c723c..4617bd12f63 100644 --- a/drivers/bluetooth/btmrvl_debugfs.c +++ b/drivers/bluetooth/btmrvl_debugfs.c @@ -51,20 +51,15 @@ static int btmrvl_open_generic(struct inode *inode, struct file *file) } static ssize_t btmrvl_hscfgcmd_write(struct file *file, - const char __user *ubuf, - size_t count, - loff_t *ppos) + const char __user *ubuf, size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - - long result, ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + long result, ret; memset(buf, 0, sizeof(buf)); - if (copy_from_user(&buf, ubuf, - min_t(size_t, sizeof(buf) - 1, count))) + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 10, &result); @@ -79,38 +74,35 @@ static ssize_t btmrvl_hscfgcmd_write(struct file *file, return count; } -static ssize_t btmrvl_hscfgcmd_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) +static ssize_t btmrvl_hscfgcmd_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - int ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", - priv->btmrvl_dev.hscfgcmd); + priv->btmrvl_dev.hscfgcmd); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_hscfgcmd_fops = { - .read = btmrvl_hscfgcmd_read, - .write = btmrvl_hscfgcmd_write, - .open = btmrvl_open_generic, + .read = btmrvl_hscfgcmd_read, + .write = btmrvl_hscfgcmd_write, + .open = btmrvl_open_generic, }; static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - long result, ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + long result, ret; memset(buf, 0, sizeof(buf)); - if (copy_from_user(&buf, ubuf, - min_t(size_t, sizeof(buf) - 1, count))) + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 10, &result); @@ -120,38 +112,35 @@ static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf, return count; } -static ssize_t btmrvl_psmode_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) +static ssize_t btmrvl_psmode_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - int ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", - priv->btmrvl_dev.psmode); + priv->btmrvl_dev.psmode); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_psmode_fops = { - .read = btmrvl_psmode_read, - .write = btmrvl_psmode_write, - .open = btmrvl_open_generic, + .read = btmrvl_psmode_read, + .write = btmrvl_psmode_write, + .open = btmrvl_open_generic, }; static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - long result, ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + long result, ret; memset(buf, 0, sizeof(buf)); - if (copy_from_user(&buf, ubuf, - min_t(size_t, sizeof(buf) - 1, count))) + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 10, &result); @@ -167,13 +156,12 @@ static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf, } -static ssize_t btmrvl_pscmd_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) +static ssize_t btmrvl_pscmd_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - int ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.pscmd); @@ -187,17 +175,15 @@ static const struct file_operations btmrvl_pscmd_fops = { }; static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - long result, ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + long result, ret; memset(buf, 0, sizeof(buf)); - if (copy_from_user(&buf, ubuf, - min_t(size_t, sizeof(buf) - 1, count))) + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 16, &result); @@ -207,38 +193,35 @@ static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf, return count; } -static ssize_t btmrvl_gpiogap_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) +static ssize_t btmrvl_gpiogap_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - int ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + int ret; ret = snprintf(buf, sizeof(buf) - 1, "0x%x\n", - priv->btmrvl_dev.gpio_gap); + priv->btmrvl_dev.gpio_gap); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_gpiogap_fops = { - .read = btmrvl_gpiogap_read, - .write = btmrvl_gpiogap_write, - .open = btmrvl_open_generic, + .read = btmrvl_gpiogap_read, + .write = btmrvl_gpiogap_write, + .open = btmrvl_open_generic, }; static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - long result, ret; + struct btmrvl_private *priv = (struct btmrvl_private *) file->private_data; char buf[16]; + long result, ret; memset(buf, 0, sizeof(buf)); - if (copy_from_user(&buf, ubuf, - min_t(size_t, sizeof(buf) - 1, count))) + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 10, &result); @@ -252,13 +235,12 @@ static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf, return count; } -static ssize_t btmrvl_hscmd_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) +static ssize_t btmrvl_hscmd_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - int ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hscmd); @@ -266,23 +248,21 @@ static ssize_t btmrvl_hscmd_read(struct file *file, char __user * userbuf, } static const struct file_operations btmrvl_hscmd_fops = { - .read = btmrvl_hscmd_read, - .write = btmrvl_hscmd_write, - .open = btmrvl_open_generic, + .read = btmrvl_hscmd_read, + .write = btmrvl_hscmd_write, + .open = btmrvl_open_generic, }; static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - long result, ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + long result, ret; memset(buf, 0, sizeof(buf)); - if (copy_from_user(&buf, ubuf, - min_t(size_t, sizeof(buf) - 1, count))) + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 10, &result); @@ -293,32 +273,29 @@ static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf, } static ssize_t btmrvl_hsmode_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - int ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + int ret; - ret = snprintf(buf, sizeof(buf) - 1, "%d\n", - priv->btmrvl_dev.hsmode); + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hsmode); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_hsmode_fops = { - .read = btmrvl_hsmode_read, - .write = btmrvl_hsmode_write, - .open = btmrvl_open_generic, + .read = btmrvl_hsmode_read, + .write = btmrvl_hsmode_write, + .open = btmrvl_open_generic, }; -static ssize_t btmrvl_curpsmode_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) +static ssize_t btmrvl_curpsmode_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - int ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->psmode); @@ -326,71 +303,65 @@ static ssize_t btmrvl_curpsmode_read(struct file *file, char __user * userbuf, } static const struct file_operations btmrvl_curpsmode_fops = { - .read = btmrvl_curpsmode_read, - .open = btmrvl_open_generic, + .read = btmrvl_curpsmode_read, + .open = btmrvl_open_generic, }; static ssize_t btmrvl_psstate_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - int ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + int ret; - ret = snprintf(buf, sizeof(buf) - 1, "%d\n", - priv->adapter->ps_state); + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->ps_state); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_psstate_fops = { - .read = btmrvl_psstate_read, - .open = btmrvl_open_generic, + .read = btmrvl_psstate_read, + .open = btmrvl_open_generic, }; -static ssize_t btmrvl_hsstate_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) +static ssize_t btmrvl_hsstate_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - int ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + int ret; - ret = snprintf(buf, sizeof(buf) - 1, "%d\n", - priv->adapter->hs_state); + ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->hs_state); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_hsstate_fops = { - .read = btmrvl_hsstate_read, - .open = btmrvl_open_generic, + .read = btmrvl_hsstate_read, + .open = btmrvl_open_generic, }; -static ssize_t btmrvl_txdnldready_read(struct file *file, char __user * userbuf, - size_t count, loff_t *ppos) +static ssize_t btmrvl_txdnldready_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) { - struct btmrvl_private *priv = - (struct btmrvl_private *) file->private_data; - int ret; + struct btmrvl_private *priv = file->private_data; char buf[16]; + int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", - priv->btmrvl_dev.tx_dnld_rdy); + priv->btmrvl_dev.tx_dnld_rdy); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_txdnldready_fops = { - .read = btmrvl_txdnldready_read, - .open = btmrvl_open_generic, + .read = btmrvl_txdnldready_read, + .open = btmrvl_open_generic, }; void btmrvl_debugfs_init(struct hci_dev *hdev) { - struct btmrvl_private *priv = - (struct btmrvl_private *) hdev->driver_data; + struct btmrvl_private *priv = hdev->driver_data; struct btmrvl_debugfs_data *dbg; dbg = kzalloc(sizeof(*dbg), GFP_KERNEL); @@ -406,22 +377,16 @@ void btmrvl_debugfs_init(struct hci_dev *hdev) dbg->config_dir = debugfs_create_dir("config", dbg->root_dir); dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir, - hdev->driver_data, - &btmrvl_psmode_fops); - dbg->pscmd = - debugfs_create_file("pscmd", 0644, dbg->config_dir, + hdev->driver_data, &btmrvl_psmode_fops); + dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_pscmd_fops); - dbg->gpiogap = - debugfs_create_file("gpiogap", 0644, dbg->config_dir, + dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_gpiogap_fops); - dbg->hsmode = - debugfs_create_file("hsmode", 0644, dbg->config_dir, + dbg->hsmode = debugfs_create_file("hsmode", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_hsmode_fops); - dbg->hscmd = - debugfs_create_file("hscmd", 0644, dbg->config_dir, + dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_hscmd_fops); - dbg->hscfgcmd = - debugfs_create_file("hscfgcmd", 0644, dbg->config_dir, + dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_hscfgcmd_fops); dbg->status_dir = debugfs_create_dir("status", dbg->root_dir); @@ -429,21 +394,19 @@ void btmrvl_debugfs_init(struct hci_dev *hdev) dbg->status_dir, hdev->driver_data, &btmrvl_curpsmode_fops); - dbg->psstate = - debugfs_create_file("psstate", 0444, dbg->status_dir, + dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir, hdev->driver_data, &btmrvl_psstate_fops); - dbg->hsstate = - debugfs_create_file("hsstate", 0444, dbg->status_dir, + dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir, hdev->driver_data, &btmrvl_hsstate_fops); - dbg->txdnldready = - debugfs_create_file("txdnldready", 0444, dbg->status_dir, - hdev->driver_data, &btmrvl_txdnldready_fops); + dbg->txdnldready = debugfs_create_file("txdnldready", 0444, + dbg->status_dir, + hdev->driver_data, + &btmrvl_txdnldready_fops); } void btmrvl_debugfs_remove(struct hci_dev *hdev) { - struct btmrvl_private *priv = - (struct btmrvl_private *) hdev->driver_data; + struct btmrvl_private *priv = hdev->driver_data; struct btmrvl_debugfs_data *dbg = priv->debugfs_data; if (!dbg) -- cgit v1.2.3-18-g5258 From 4271e08d8b799171af18d7864908ec444282efe5 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 9 Jun 2009 16:00:22 +0200 Subject: Bluetooth: Some coding style cleanup for Marvell core driver The Marvell core Bluetooth driver has various weird casting and unneeded braces in its code that makes it hard to read. Remove all of these to make the code a little bit simpler. Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_main.c | 97 +++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index b4f44454666..db4fdb1538e 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -48,19 +48,18 @@ EXPORT_SYMBOL_GPL(btmrvl_interrupt); void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) { - struct hci_event_hdr *hdr = (struct hci_event_hdr *)skb->data; + struct hci_event_hdr *hdr = (void *) skb->data; struct hci_ev_cmd_complete *ec; u16 opcode, ocf; BT_DBG("Enter"); if (hdr->evt == HCI_EV_CMD_COMPLETE) { - ec = (struct hci_ev_cmd_complete *)(skb->data + - HCI_EVENT_HDR_SIZE); + ec = (void *) (skb->data + HCI_EVENT_HDR_SIZE); opcode = __le16_to_cpu(ec->opcode); ocf = hci_opcode_ocf(opcode); - if ((ocf == BT_CMD_MODULE_CFG_REQ) && - (priv->btmrvl_dev.sendcmdflag)) { + if (ocf == BT_CMD_MODULE_CFG_REQ && + priv->btmrvl_dev.sendcmdflag) { priv->btmrvl_dev.sendcmdflag = false; priv->adapter->cmd_complete = true; wake_up_interruptible(&priv->adapter->cmd_wait_q); @@ -74,8 +73,8 @@ EXPORT_SYMBOL_GPL(btmrvl_check_evtpkt); int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) { struct btmrvl_adapter *adapter = priv->adapter; - u8 ret = 0; struct btmrvl_event *event; + u8 ret = 0; BT_DBG("Enter"); @@ -103,7 +102,7 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) case BT_CMD_HOST_SLEEP_CONFIG: if (!event->data[3]) BT_DBG("gpio=%x, gap=%x", event->data[1], - event->data[2]); + event->data[2]); else BT_DBG("HSCFG command failed"); break; @@ -121,12 +120,12 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) break; case BT_CMD_MODULE_CFG_REQ: - if ((priv->btmrvl_dev.sendcmdflag) && - (event->data[1] == MODULE_BRINGUP_REQ)) { + if (priv->btmrvl_dev.sendcmdflag && + event->data[1] == MODULE_BRINGUP_REQ) { BT_DBG("EVENT:%s", (event->data[2]) ? "Bring-up failed" : "Bring-up succeed"); - } else if ((priv->btmrvl_dev.sendcmdflag) && - (event->data[1] == MODULE_SHUTDOWN_REQ)) { + } else if (priv->btmrvl_dev.sendcmdflag && + event->data[1] == MODULE_SHUTDOWN_REQ) { BT_DBG("EVENT:%s", (event->data[2]) ? "Shutdown failed" : "Shutdown succeed"); } else { @@ -160,9 +159,9 @@ EXPORT_SYMBOL_GPL(btmrvl_process_event); int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) { - struct sk_buff *skb = NULL; - u8 ret = 0; + struct sk_buff *skb; struct btmrvl_cmd *cmd; + u8 ret = 0; BT_DBG("Enter"); @@ -181,7 +180,7 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; skb_put(skb, sizeof(*cmd)); - skb->dev = (void *)priv->btmrvl_dev.hcidev; + skb->dev = (void *) priv->btmrvl_dev.hcidev; skb_queue_head(&priv->adapter->tx_queue, skb); priv->btmrvl_dev.sendcmdflag = true; @@ -192,13 +191,12 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) wake_up_interruptible(&priv->main_thread.wait_q); - if (!wait_event_interruptible_timeout( - priv->adapter->cmd_wait_q, - priv->adapter->cmd_complete, - msecs_to_jiffies(WAIT_UNTIL_CMD_RESP))) { + if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q, + priv->adapter->cmd_complete, + msecs_to_jiffies(WAIT_UNTIL_CMD_RESP))) { ret = -ETIMEDOUT; BT_ERR("module_cfg_cmd(%x): timeout: %d", - subcmd, priv->btmrvl_dev.sendcmdflag); + subcmd, priv->btmrvl_dev.sendcmdflag); } BT_DBG("module cfg Command done"); @@ -212,9 +210,9 @@ EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd); static int btmrvl_enable_hs(struct btmrvl_private *priv) { - struct sk_buff *skb = NULL; - u8 ret = 0; + struct sk_buff *skb; struct btmrvl_cmd *cmd; + u8 ret = 0; BT_DBG("Enter"); @@ -232,22 +230,20 @@ static int btmrvl_enable_hs(struct btmrvl_private *priv) bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; skb_put(skb, sizeof(*cmd)); - skb->dev = (void *)priv->btmrvl_dev.hcidev; + skb->dev = (void *) priv->btmrvl_dev.hcidev; skb_queue_head(&priv->adapter->tx_queue, skb); BT_DBG("Queue hs enable Command"); wake_up_interruptible(&priv->main_thread.wait_q); - if (!wait_event_interruptible_timeout( - priv->adapter->cmd_wait_q, + if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q, priv->adapter->hs_state, msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED))) { ret = -ETIMEDOUT; - BT_ERR("timeout: %d, %d,%d", - priv->adapter->hs_state, - priv->adapter->ps_state, - priv->adapter->wakeup_tries); + BT_ERR("timeout: %d, %d,%d", priv->adapter->hs_state, + priv->adapter->ps_state, + priv->adapter->wakeup_tries); } exit: @@ -259,8 +255,8 @@ exit: int btmrvl_prepare_command(struct btmrvl_private *priv) { struct sk_buff *skb = NULL; - u8 ret = 0; struct btmrvl_cmd *cmd; + u8 ret = 0; BT_DBG("Enter"); @@ -284,11 +280,11 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; skb_put(skb, sizeof(*cmd)); - skb->dev = (void *)priv->btmrvl_dev.hcidev; + skb->dev = (void *) priv->btmrvl_dev.hcidev; skb_queue_head(&priv->adapter->tx_queue, skb); BT_DBG("Queue HSCFG Command, gpio=0x%x, gap=0x%x", - cmd->data[0], cmd->data[1]); + cmd->data[0], cmd->data[1]); } if (priv->btmrvl_dev.pscmd) { @@ -314,7 +310,7 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; skb_put(skb, sizeof(*cmd)); - skb->dev = (void *)priv->btmrvl_dev.hcidev; + skb->dev = (void *) priv->btmrvl_dev.hcidev; skb_queue_head(&priv->adapter->tx_queue, skb); BT_DBG("Queue PSMODE Command:%d", cmd->data[0]); @@ -350,7 +346,7 @@ static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb) if (!skb->len || ((skb->len + BTM_HEADER_LEN) > BTM_UPLD_SIZE)) { BT_ERR("Tx Error: Bad skb length %d : %d", - skb->len, BTM_UPLD_SIZE); + skb->len, BTM_UPLD_SIZE); BT_DBG("Leave"); return -EINVAL; } @@ -416,8 +412,8 @@ static void btmrvl_free_adapter(struct btmrvl_private *priv) BT_DBG("Leave"); } -static int -btmrvl_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) +static int btmrvl_ioctl(struct hci_dev *hdev, + unsigned int cmd, unsigned long arg) { BT_DBG("Enter"); @@ -435,7 +431,7 @@ static void btmrvl_destruct(struct hci_dev *hdev) static int btmrvl_send_frame(struct sk_buff *skb) { - struct hci_dev *hdev = (struct hci_dev *)skb->dev; + struct hci_dev *hdev = (struct hci_dev *) skb->dev; struct btmrvl_private *priv = NULL; BT_DBG("Enter: type=%d, len=%d", skb->pkt_type, skb->len); @@ -446,11 +442,11 @@ static int btmrvl_send_frame(struct sk_buff *skb) return -ENODEV; } - priv = (struct btmrvl_private *)hdev->driver_data; + priv = (struct btmrvl_private *) hdev->driver_data; if (!test_bit(HCI_RUNNING, &hdev->flags)) { BT_ERR("Failed testing HCI_RUNING, flags=%lx", hdev->flags); print_hex_dump_bytes("data: ", DUMP_PREFIX_OFFSET, - skb->data, skb->len); + skb->data, skb->len); BT_DBG("Leave"); return -EBUSY; } @@ -480,8 +476,7 @@ static int btmrvl_send_frame(struct sk_buff *skb) static int btmrvl_flush(struct hci_dev *hdev) { - struct btmrvl_private *priv = - (struct btmrvl_private *) hdev->driver_data; + struct btmrvl_private *priv = hdev->driver_data; BT_DBG("Enter"); @@ -494,8 +489,7 @@ static int btmrvl_flush(struct hci_dev *hdev) static int btmrvl_close(struct hci_dev *hdev) { - struct btmrvl_private *priv = - (struct btmrvl_private *) hdev->driver_data; + struct btmrvl_private *priv = hdev->driver_data; BT_DBG("Enter"); @@ -547,9 +541,9 @@ static int btmrvl_service_main_thread(void *data) set_current_state(TASK_INTERRUPTIBLE); if (adapter->wakeup_tries || - ((!adapter->int_count) && - (!priv->btmrvl_dev.tx_dnld_rdy || - skb_queue_empty(&adapter->tx_queue)))) { + ((!adapter->int_count) && + (!priv->btmrvl_dev.tx_dnld_rdy || + skb_queue_empty(&adapter->tx_queue)))) { BT_DBG("main_thread is sleeping..."); schedule(); } @@ -568,8 +562,8 @@ static int btmrvl_service_main_thread(void *data) spin_lock_irqsave(&priv->driver_lock, flags); if (adapter->int_count) { adapter->int_count = 0; - } else if ((adapter->ps_state == PS_SLEEP) && - !skb_queue_empty(&adapter->tx_queue)) { + } else if (adapter->ps_state == PS_SLEEP && + !skb_queue_empty(&adapter->tx_queue)) { spin_unlock_irqrestore(&priv->driver_lock, flags); adapter->wakeup_tries++; priv->hw_wakeup_firmware(priv); @@ -588,8 +582,7 @@ static int btmrvl_service_main_thread(void *data) if (btmrvl_tx_pkt(priv, skb)) priv->btmrvl_dev.hcidev->stat.err_tx++; else - priv->btmrvl_dev.hcidev->stat.byte_tx - += skb->len; + priv->btmrvl_dev.hcidev->stat.byte_tx += skb->len; kfree_skb(skb); } @@ -603,7 +596,7 @@ static int btmrvl_service_main_thread(void *data) struct btmrvl_private *btmrvl_add_card(void *card) { struct hci_dev *hdev = NULL; - struct btmrvl_private *priv = NULL; + struct btmrvl_private *priv; int ret; BT_DBG("Enter"); @@ -634,7 +627,7 @@ struct btmrvl_private *btmrvl_add_card(void *card) init_waitqueue_head(&priv->main_thread.wait_q); priv->main_thread.task = kthread_run(btmrvl_service_main_thread, - &priv->main_thread, "btmrvl_main_service"); + &priv->main_thread, "btmrvl_main_service"); priv->btmrvl_dev.hcidev = hdev; priv->btmrvl_dev.card = card; @@ -717,6 +710,6 @@ int btmrvl_remove_card(struct btmrvl_private *priv) EXPORT_SYMBOL_GPL(btmrvl_remove_card); MODULE_AUTHOR("Marvell International Ltd."); -MODULE_DESCRIPTION("Marvell Bluetooth Driver v" VERSION); +MODULE_DESCRIPTION("Marvell Bluetooth Driver ver" VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-18-g5258 From dcf47f3bc798888f9ea40b9f626d669dc62086bf Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 9 Jun 2009 16:21:58 +0200 Subject: Bluetooth: Fix complicated assignment of firmware for Marvell devices The Marvell Bluetooth SDIO driver has a really complicated concept on how firmware names are assigned to specific device ids. Fix that by doing a proper structure and assign it to the module device table. And while at it fix various coding style weirdness that is still present in this driver. Signed-off-by: Marcel Holtman --- drivers/bluetooth/btmrvl_sdio.c | 90 +++++++++++++++++------------------------ drivers/bluetooth/btmrvl_sdio.h | 1 - 2 files changed, 38 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 8f13e7bea0b..867ebe4b8e9 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -31,10 +31,6 @@ #define VERSION "1.0" -#ifndef SDIO_DEVICE_ID_MARVELL_8688BT -#define SDIO_DEVICE_ID_MARVELL_8688BT 0x9105 -#endif - /* The btmrvl_sdio_remove() callback function is called * when user removes this module from kernel space or ejects * the card from the slot. The driver handles these 2 cases @@ -51,21 +47,21 @@ */ static u8 user_rmmod; -static const struct sdio_device_id btmrvl_sdio_ids[] = { - {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8688BT)}, - {0, 0, 0, 0} +static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = { + .helper = "sd8688_helper.bin", + .firmware = "sd8688.bin", }; -MODULE_DEVICE_TABLE(sdio, btmrvl_sdio_ids); +static const struct sdio_device_id btmrvl_sdio_ids[] = { + /* Marvell SD8688 Bluetooth device */ + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105), + .driver_data = (unsigned long) &btmrvl_sdio_sd6888 }, -static struct btmrvl_sdio_device btmrvl_sdio_devices[] = { - { - .dev_id = SDIO_DEVICE_ID_MARVELL_8688BT, - .helper = "sd8688_helper.bin", - .firmware = "sd8688.bin", - }, + { } /* Terminating entry */ }; +MODULE_DEVICE_TABLE(sdio, btmrvl_sdio_ids); + static int btmrvl_sdio_get_rx_unit(struct btmrvl_sdio_card *card) { u8 reg; @@ -125,7 +121,7 @@ static int btmrvl_sdio_read_rx_len(struct btmrvl_sdio_card *card, u16 *dat) } static int btmrvl_sdio_enable_host_int_mask(struct btmrvl_sdio_card *card, - u8 mask) + u8 mask) { int ret; @@ -143,7 +139,7 @@ static int btmrvl_sdio_enable_host_int_mask(struct btmrvl_sdio_card *card, } static int btmrvl_sdio_disable_host_int_mask(struct btmrvl_sdio_card *card, - u8 mask) + u8 mask) { int ret; u8 host_int_mask; @@ -203,7 +199,7 @@ done: } static int btmrvl_sdio_verify_fw_download(struct btmrvl_sdio_card *card, - int pollnum) + int pollnum) { int ret = -ETIMEDOUT; u16 firmwarestat; @@ -242,10 +238,10 @@ static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card) BT_DBG("Enter"); ret = request_firmware(&fw_helper, card->helper, - &card->func->dev); + &card->func->dev); if ((ret < 0) || !fw_helper) { BT_ERR("request_firmware(helper) failed, error code = %d", - ret); + ret); ret = -ENOENT; goto done; } @@ -254,7 +250,7 @@ static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card) helperlen = fw_helper->size; BT_DBG("Downloading helper image (%d bytes), block size %d bytes", - helperlen, SDIO_BLOCK_SIZE); + helperlen, SDIO_BLOCK_SIZE); tmphlprbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN); @@ -301,10 +297,8 @@ static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card) tx_len); /* Now send the data */ - ret = sdio_writesb(card->func, card->ioport, - helperbuf, - FIRMWARE_TRANSFER_NBLOCK * - SDIO_BLOCK_SIZE); + ret = sdio_writesb(card->func, card->ioport, helperbuf, + FIRMWARE_TRANSFER_NBLOCK * SDIO_BLOCK_SIZE); if (ret < 0) { BT_ERR("IO error during helper download @ %d", hlprblknow); @@ -319,7 +313,7 @@ static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card) memset(helperbuf, 0x0, SDIO_BLOCK_SIZE); ret = sdio_writesb(card->func, card->ioport, helperbuf, - SDIO_BLOCK_SIZE); + SDIO_BLOCK_SIZE); if (ret < 0) { BT_ERR("IO error in writing helper image EOF block"); goto done; @@ -352,10 +346,10 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) BT_DBG("Enter"); ret = request_firmware(&fw_firmware, card->firmware, - &card->func->dev); + &card->func->dev); if ((ret < 0) || !fw_firmware) { BT_ERR("request_firmware(firmware) failed, error code = %d", - ret); + ret); ret = -ENOENT; goto done; } @@ -383,10 +377,10 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) offset = 0; do { ret = btmrvl_sdio_poll_card_status(card, - CARD_IO_READY | DN_LD_CARD_RDY); + CARD_IO_READY | DN_LD_CARD_RDY); if (ret < 0) { BT_ERR("FW download with helper poll status" - " timeout @ %d", offset); + " timeout @ %d", offset); goto done; } @@ -427,7 +421,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) break; else if (len > BTM_UPLD_SIZE) { BT_ERR("FW download failure @%d, invalid length %d", - offset, len); + offset, len); ret = -EINVAL; goto done; } @@ -465,9 +459,9 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) if (ret < 0) { BT_ERR("FW download, writesb(%d) failed @%d", - count, offset); + count, offset); sdio_writeb(card->func, HOST_CMD53_FIN, CONFIG_REG, - &ret); + &ret); if (ret) BT_ERR("writeb failed (CFG)"); } @@ -520,7 +514,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) buf_block_len = (buf_len + blksz - 1) / blksz; if (buf_len <= SDIO_HEADER_LEN - || (buf_block_len * blksz) > ALLOC_BUF_SIZE) { + || (buf_block_len * blksz) > ALLOC_BUF_SIZE) { BT_ERR("invalid packet length: %d", buf_len); ret = -EINVAL; goto exit; @@ -528,7 +522,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) /* Allocate buffer */ skb = bt_skb_alloc(buf_block_len * blksz + BTSDIO_DMA_ALIGN, - GFP_ATOMIC); + GFP_ATOMIC); if (skb == NULL) { BT_ERR("No free skb"); goto exit; @@ -588,7 +582,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) default: BT_ERR("Unknow packet type:%d", type); print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, payload, - blksz * buf_block_len); + blksz * buf_block_len); kfree_skb(skb); skb = NULL; @@ -691,9 +685,9 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func) static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) { - int ret = 0, i; - u8 reg; struct sdio_func *func; + u8 reg; + int ret = 0; BT_DBG("Enter"); @@ -705,20 +699,6 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) func = card->func; - for (i = 0; i < ARRAY_SIZE(btmrvl_sdio_devices); i++) { - if (func->device == btmrvl_sdio_devices[i].dev_id) - break; - } - - if (i == ARRAY_SIZE(btmrvl_sdio_devices)) { - BT_ERR("Error: unknown device id 0x%x", func->device); - ret = -EINVAL; - goto failed; - } - - card->helper = btmrvl_sdio_devices[i].helper; - card->firmware = btmrvl_sdio_devices[i].firmware; - sdio_claim_host(func); ret = sdio_enable_func(func); @@ -983,7 +963,7 @@ static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv) } static int btmrvl_sdio_probe(struct sdio_func *func, - const struct sdio_device_id *id) + const struct sdio_device_id *id) { int ret = 0; struct btmrvl_private *priv = NULL; @@ -1002,6 +982,12 @@ static int btmrvl_sdio_probe(struct sdio_func *func, card->func = func; + if (id->driver_data) { + struct btmrvl_sdio_device *data = (void *) id->driver_data; + card->helper = data->helper; + card->firmware = data->firmware; + } + if (btmrvl_sdio_register_dev(card) < 0) { BT_ERR("Failed to register BT device!"); ret = -ENODEV; diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h index 6beb340685e..2dd284e0df1 100644 --- a/drivers/bluetooth/btmrvl_sdio.h +++ b/drivers/bluetooth/btmrvl_sdio.h @@ -90,7 +90,6 @@ struct btmrvl_sdio_card { }; struct btmrvl_sdio_device { - unsigned short dev_id; const char *helper; const char *firmware; }; -- cgit v1.2.3-18-g5258 From 9666fb356da78a5ec28403197d72e8cd6aa16424 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 9 Jun 2009 21:45:04 +0200 Subject: Bluetooth: Fix module description strings for Marvell driver Make the module description entries for the core and also the Marvell SDIO driver match common practive inside the Bluetooth subsystem. Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_main.c | 2 +- drivers/bluetooth/btmrvl_sdio.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index db4fdb1538e..61168ec3bd2 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -710,6 +710,6 @@ int btmrvl_remove_card(struct btmrvl_private *priv) EXPORT_SYMBOL_GPL(btmrvl_remove_card); MODULE_AUTHOR("Marvell International Ltd."); -MODULE_DESCRIPTION("Marvell Bluetooth Driver ver" VERSION); +MODULE_DESCRIPTION("Marvell Bluetooth driver ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL v2"); diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 867ebe4b8e9..0dea23e99ec 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -1109,6 +1109,6 @@ module_init(btmrvl_sdio_init_module); module_exit(btmrvl_sdio_exit_module); MODULE_AUTHOR("Marvell International Ltd."); -MODULE_DESCRIPTION("Marvell BT-over-SDIO Driver v" VERSION); +MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-18-g5258 From 60dee5ccd789ee8a380eee802b6cb24c52123428 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 10 Jun 2009 12:05:52 +0200 Subject: Bluetooth: Remove private device name of Marvell SDIO driver For some reason the btmrvl_device struct has a name field that the SDIO fills in, but then never ever uses again. That is totally pointless and so just remove it. Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_drv.h | 2 -- drivers/bluetooth/btmrvl_sdio.c | 3 --- 2 files changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index 5da3be40770..411c7a77082 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -24,7 +24,6 @@ #include #define BTM_HEADER_LEN 4 -#define BTM_DEV_NAME_LEN 32 #define BTM_UPLD_SIZE 2312 /* Time to wait until Host Sleep state change in millisecond */ @@ -39,7 +38,6 @@ struct btmrvl_thread { }; struct btmrvl_device { - char name[BTM_DEV_NAME_LEN]; void *card; struct hci_dev *hcidev; diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 0dea23e99ec..7638f62e8a0 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -1020,9 +1020,6 @@ static int btmrvl_sdio_probe(struct sdio_func *func, priv->hw_host_to_card = btmrvl_sdio_host_to_card; priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw; - strncpy(priv->btmrvl_dev.name, "btmrvl_sdio0", - sizeof(priv->btmrvl_dev.name)); - btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ); BT_DBG("Leave"); -- cgit v1.2.3-18-g5258 From 91d697302b291205171840bfe84c1563e171acb2 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 10 Jun 2009 12:18:50 +0200 Subject: Bluetooth: Fix Marvell driver to use skb_put and hci_opcode_pack The Marvell driver has some weird quirks on how to construct proper SKBs with Bluetooth HCI commands. Fix it to use skb_put properly and also use hci_opcode_pack instead of self-crafted macro. Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_main.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 61168ec3bd2..f5a3dc5c067 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -172,14 +172,13 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) goto exit; } - cmd = (struct btmrvl_cmd *) skb->tail; - cmd->ocf_ogf = cpu_to_le16((OGF << 10) | BT_CMD_MODULE_CFG_REQ); + cmd = skb_put(skb, sizeof(*cmd)); + cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_MODULE_CFG_REQ)); cmd->length = 1; cmd->data[0] = subcmd; bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; - skb_put(skb, sizeof(*cmd)); skb->dev = (void *) priv->btmrvl_dev.hcidev; skb_queue_head(&priv->adapter->tx_queue, skb); @@ -223,13 +222,12 @@ static int btmrvl_enable_hs(struct btmrvl_private *priv) goto exit; } - cmd = (struct btmrvl_cmd *) skb->tail; - cmd->ocf_ogf = cpu_to_le16((OGF << 10) | BT_CMD_HOST_SLEEP_ENABLE); + cmd = skb_put(skb, sizeof(*cmd)); + cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_ENABLE)); cmd->length = 0; bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; - skb_put(skb, sizeof(*cmd)); skb->dev = (void *) priv->btmrvl_dev.hcidev; skb_queue_head(&priv->adapter->tx_queue, skb); @@ -270,16 +268,14 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) goto exit; } - cmd = (struct btmrvl_cmd *) skb->tail; - cmd->ocf_ogf = cpu_to_le16((OGF << 10) | - BT_CMD_HOST_SLEEP_CONFIG); + cmd = skb_put(skb, sizeof(*cmd)); + cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_CONFIG)); cmd->length = 2; cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8; cmd->data[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff); bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; - skb_put(skb, sizeof(*cmd)); skb->dev = (void *) priv->btmrvl_dev.hcidev; skb_queue_head(&priv->adapter->tx_queue, skb); @@ -297,9 +293,8 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) goto exit; } - cmd = (struct btmrvl_cmd *) skb->tail; - cmd->ocf_ogf = cpu_to_le16((OGF << 10) | - BT_CMD_AUTO_SLEEP_MODE); + cmd = skb_put(skb, sizeof(*cmd)); + cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_AUTO_SLEEP_MODE)); cmd->length = 1; if (priv->btmrvl_dev.psmode) @@ -309,7 +304,6 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; - skb_put(skb, sizeof(*cmd)); skb->dev = (void *) priv->btmrvl_dev.hcidev; skb_queue_head(&priv->adapter->tx_queue, skb); -- cgit v1.2.3-18-g5258 From e0721f99ba33d13a88746732be2d74ca805abf55 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 13 Jun 2009 07:27:19 +0200 Subject: Bluetooth: Fix last few compiler warning within Marvell core driver After fixing the driver to use skb_put properly for their HCI commands only a few compiler warnings are left. Add proper casting for them. Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index f5a3dc5c067..bbc4446c4b4 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -172,7 +172,7 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) goto exit; } - cmd = skb_put(skb, sizeof(*cmd)); + cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_MODULE_CFG_REQ)); cmd->length = 1; cmd->data[0] = subcmd; @@ -222,7 +222,7 @@ static int btmrvl_enable_hs(struct btmrvl_private *priv) goto exit; } - cmd = skb_put(skb, sizeof(*cmd)); + cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_ENABLE)); cmd->length = 0; @@ -268,7 +268,7 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) goto exit; } - cmd = skb_put(skb, sizeof(*cmd)); + cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_CONFIG)); cmd->length = 2; cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8; @@ -293,7 +293,7 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) goto exit; } - cmd = skb_put(skb, sizeof(*cmd)); + cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_AUTO_SLEEP_MODE)); cmd->length = 1; -- cgit v1.2.3-18-g5258 From 9374253ffe609f2d70dd5ae280182cb6f08fef08 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 13 Jun 2009 07:40:18 +0200 Subject: Bluetooth: Remove Enter/Leave debug statements from Marvell driver The Marvell Bluetooth driver is full of Enter/Leave debug statements and all of them are really pointless and only clutter the code. Seems to be some left-overs when they ported the driver from Windows. For the Linux driver lets remove these. Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_main.c | 107 ++++--------------------------- drivers/bluetooth/btmrvl_sdio.c | 135 ++++------------------------------------ 2 files changed, 23 insertions(+), 219 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index bbc4446c4b4..e605563b4ea 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -32,8 +32,6 @@ */ void btmrvl_interrupt(struct btmrvl_private *priv) { - BT_DBG("Enter"); - priv->adapter->ps_state = PS_AWAKE; priv->adapter->wakeup_tries = 0; @@ -41,8 +39,6 @@ void btmrvl_interrupt(struct btmrvl_private *priv) priv->adapter->int_count++; wake_up_interruptible(&priv->main_thread.wait_q); - - BT_DBG("Leave"); } EXPORT_SYMBOL_GPL(btmrvl_interrupt); @@ -52,8 +48,6 @@ void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) struct hci_ev_cmd_complete *ec; u16 opcode, ocf; - BT_DBG("Enter"); - if (hdr->evt == HCI_EV_CMD_COMPLETE) { ec = (void *) (skb->data + HCI_EVENT_HDR_SIZE); opcode = __le16_to_cpu(ec->opcode); @@ -65,8 +59,6 @@ void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) wake_up_interruptible(&priv->adapter->cmd_wait_q); } } - - BT_DBG("Leave"); } EXPORT_SYMBOL_GPL(btmrvl_check_evtpkt); @@ -76,8 +68,6 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) struct btmrvl_event *event; u8 ret = 0; - BT_DBG("Enter"); - event = (struct btmrvl_event *) skb->data; if (event->ec != 0xff) { BT_DBG("Not Marvell Event=%x", event->ec); @@ -151,8 +141,6 @@ exit: if (!ret) kfree_skb(skb); - BT_DBG("Leave"); - return ret; } EXPORT_SYMBOL_GPL(btmrvl_process_event); @@ -161,15 +149,12 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) { struct sk_buff *skb; struct btmrvl_cmd *cmd; - u8 ret = 0; - - BT_DBG("Enter"); + int ret = 0; skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); if (skb == NULL) { BT_ERR("No free skb"); - ret = -ENOMEM; - goto exit; + return -ENOMEM; } cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); @@ -200,9 +185,6 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) BT_DBG("module cfg Command done"); -exit: - BT_DBG("Leave"); - return ret; } EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd); @@ -211,15 +193,12 @@ static int btmrvl_enable_hs(struct btmrvl_private *priv) { struct sk_buff *skb; struct btmrvl_cmd *cmd; - u8 ret = 0; - - BT_DBG("Enter"); + int ret = 0; skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); if (skb == NULL) { BT_ERR("No free skb"); - ret = -ENOMEM; - goto exit; + return -ENOMEM; } cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); @@ -244,9 +223,6 @@ static int btmrvl_enable_hs(struct btmrvl_private *priv) priv->adapter->wakeup_tries); } -exit: - BT_DBG("Leave"); - return ret; } @@ -254,9 +230,7 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) { struct sk_buff *skb = NULL; struct btmrvl_cmd *cmd; - u8 ret = 0; - - BT_DBG("Enter"); + int ret = 0; if (priv->btmrvl_dev.hscfgcmd) { priv->btmrvl_dev.hscfgcmd = 0; @@ -264,8 +238,7 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); if (skb == NULL) { BT_ERR("No free skb"); - ret = -ENOMEM; - goto exit; + return -ENOMEM; } cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); @@ -289,8 +262,7 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); if (skb == NULL) { BT_ERR("No free skb"); - ret = -ENOMEM; - goto exit; + return -ENOMEM; } cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); @@ -321,27 +293,19 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) } } -exit: - BT_DBG("Leave"); - return ret; } static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb) { - u8 ret = 0; + int ret = 0; - BT_DBG("Enter"); - - if (!skb || !skb->data) { - BT_DBG("Leave"); + if (!skb || !skb->data) return -EINVAL; - } if (!skb->len || ((skb->len + BTM_HEADER_LEN) > BTM_UPLD_SIZE)) { BT_ERR("Tx Error: Bad skb length %d : %d", skb->len, BTM_UPLD_SIZE); - BT_DBG("Leave"); return -EINVAL; } @@ -353,7 +317,6 @@ static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb) BT_ERR("Tx Error: realloc_headroom failed %d", BTM_HEADER_LEN); skb = tmp; - BT_DBG("Leave"); return -EINVAL; } @@ -375,52 +338,35 @@ static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb) if (priv->hw_host_to_card) ret = priv->hw_host_to_card(priv, skb->data, skb->len); - BT_DBG("Leave"); - return ret; } static void btmrvl_init_adapter(struct btmrvl_private *priv) { - BT_DBG("Enter"); - skb_queue_head_init(&priv->adapter->tx_queue); priv->adapter->ps_state = PS_AWAKE; init_waitqueue_head(&priv->adapter->cmd_wait_q); - - BT_DBG("Leave"); } static void btmrvl_free_adapter(struct btmrvl_private *priv) { - BT_DBG("Enter"); - skb_queue_purge(&priv->adapter->tx_queue); kfree(priv->adapter); priv->adapter = NULL; - - BT_DBG("Leave"); } static int btmrvl_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) { - BT_DBG("Enter"); - - BT_DBG("Leave"); - return -ENOIOCTLCMD; } static void btmrvl_destruct(struct hci_dev *hdev) { - BT_DBG("Enter"); - - BT_DBG("Leave"); } static int btmrvl_send_frame(struct sk_buff *skb) @@ -428,11 +374,10 @@ static int btmrvl_send_frame(struct sk_buff *skb) struct hci_dev *hdev = (struct hci_dev *) skb->dev; struct btmrvl_private *priv = NULL; - BT_DBG("Enter: type=%d, len=%d", skb->pkt_type, skb->len); + BT_DBG("type=%d, len=%d", skb->pkt_type, skb->len); if (!hdev || !hdev->driver_data) { BT_ERR("Frame for unknown HCI device"); - BT_DBG("Leave"); return -ENODEV; } @@ -441,7 +386,6 @@ static int btmrvl_send_frame(struct sk_buff *skb) BT_ERR("Failed testing HCI_RUNING, flags=%lx", hdev->flags); print_hex_dump_bytes("data: ", DUMP_PREFIX_OFFSET, skb->data, skb->len); - BT_DBG("Leave"); return -EBUSY; } @@ -463,8 +407,6 @@ static int btmrvl_send_frame(struct sk_buff *skb) wake_up_interruptible(&priv->main_thread.wait_q); - BT_DBG("Leave"); - return 0; } @@ -472,12 +414,8 @@ static int btmrvl_flush(struct hci_dev *hdev) { struct btmrvl_private *priv = hdev->driver_data; - BT_DBG("Enter"); - skb_queue_purge(&priv->adapter->tx_queue); - BT_DBG("Leave"); - return 0; } @@ -485,28 +423,18 @@ static int btmrvl_close(struct hci_dev *hdev) { struct btmrvl_private *priv = hdev->driver_data; - BT_DBG("Enter"); - - if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) { - BT_DBG("Leave"); + if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) return 0; - } skb_queue_purge(&priv->adapter->tx_queue); - BT_DBG("Leave"); - return 0; } static int btmrvl_open(struct hci_dev *hdev) { - BT_DBG("Enter"); - set_bit(HCI_RUNNING, &hdev->flags); - BT_DBG("Leave"); - return 0; } @@ -523,8 +451,6 @@ static int btmrvl_service_main_thread(void *data) struct sk_buff *skb; ulong flags; - BT_DBG("Enter"); - init_waitqueue_entry(&wait, current); current->flags |= PF_NOFREEZE; @@ -582,8 +508,6 @@ static int btmrvl_service_main_thread(void *data) } } - BT_DBG("Leave"); - return 0; } @@ -593,8 +517,6 @@ struct btmrvl_private *btmrvl_add_card(void *card) struct btmrvl_private *priv; int ret; - BT_DBG("Enter"); - priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { BT_ERR("Can not allocate priv"); @@ -649,7 +571,6 @@ struct btmrvl_private *btmrvl_add_card(void *card) btmrvl_debugfs_init(hdev); #endif - BT_DBG("Leave"); return priv; err_hci_register_dev: @@ -665,8 +586,6 @@ err_adapter: kfree(priv); err_priv: - BT_DBG("Leave"); - return NULL; } EXPORT_SYMBOL_GPL(btmrvl_add_card); @@ -675,8 +594,6 @@ int btmrvl_remove_card(struct btmrvl_private *priv) { struct hci_dev *hdev; - BT_DBG("Enter"); - hdev = priv->btmrvl_dev.hcidev; wake_up_interruptible(&priv->adapter->cmd_wait_q); @@ -697,8 +614,6 @@ int btmrvl_remove_card(struct btmrvl_private *priv) kfree(priv); - BT_DBG("Leave"); - return 0; } EXPORT_SYMBOL_GPL(btmrvl_remove_card); diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 7638f62e8a0..224af53e0fa 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -67,23 +67,17 @@ static int btmrvl_sdio_get_rx_unit(struct btmrvl_sdio_card *card) u8 reg; int ret; - BT_DBG("Enter"); - reg = sdio_readb(card->func, CARD_RX_UNIT_REG, &ret); if (!ret) card->rx_unit = reg; - BT_DBG("Leave"); - return ret; } static int btmrvl_sdio_read_fw_status(struct btmrvl_sdio_card *card, u16 *dat) { - int ret; u8 fws0, fws1; - - BT_DBG("Enter"); + int ret; *dat = 0; @@ -92,31 +86,23 @@ static int btmrvl_sdio_read_fw_status(struct btmrvl_sdio_card *card, u16 *dat) if (!ret) fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret); - if (ret) { - BT_DBG("Leave"); + if (ret) return -EIO; - } *dat = (((u16) fws1) << 8) | fws0; - BT_DBG("Leave"); - return 0; } static int btmrvl_sdio_read_rx_len(struct btmrvl_sdio_card *card, u16 *dat) { - int ret; u8 reg; - - BT_DBG("Enter"); + int ret; reg = sdio_readb(card->func, CARD_RX_LEN_REG, &ret); if (!ret) *dat = (u16) reg << card->rx_unit; - BT_DBG("Leave"); - return ret; } @@ -125,64 +111,48 @@ static int btmrvl_sdio_enable_host_int_mask(struct btmrvl_sdio_card *card, { int ret; - BT_DBG("Enter"); - sdio_writeb(card->func, mask, HOST_INT_MASK_REG, &ret); if (ret) { BT_ERR("Unable to enable the host interrupt!"); ret = -EIO; } - BT_DBG("Leave"); - return ret; } static int btmrvl_sdio_disable_host_int_mask(struct btmrvl_sdio_card *card, u8 mask) { - int ret; u8 host_int_mask; - - BT_DBG("Enter"); + int ret; host_int_mask = sdio_readb(card->func, HOST_INT_MASK_REG, &ret); - if (ret) { - ret = -EIO; - goto done; - } + if (ret) + return -EIO; host_int_mask &= ~mask; sdio_writeb(card->func, host_int_mask, HOST_INT_MASK_REG, &ret); if (ret < 0) { BT_ERR("Unable to disable the host interrupt!"); - ret = -EIO; - goto done; + return -EIO; } - ret = 0; - -done: - BT_DBG("Leave"); - - return ret; + return 0; } static int btmrvl_sdio_poll_card_status(struct btmrvl_sdio_card *card, u8 bits) { unsigned int tries; - int ret; u8 status; - - BT_DBG("Enter"); + int ret; for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) { status = sdio_readb(card->func, CARD_STATUS_REG, &ret); if (ret) goto failed; if ((status & bits) == bits) - goto done; + return ret; udelay(1); } @@ -192,9 +162,6 @@ static int btmrvl_sdio_poll_card_status(struct btmrvl_sdio_card *card, u8 bits) failed: BT_ERR("FAILED! ret=%d", ret); -done: - BT_DBG("Leave"); - return ret; } @@ -205,8 +172,6 @@ static int btmrvl_sdio_verify_fw_download(struct btmrvl_sdio_card *card, u16 firmwarestat; unsigned int tries; - BT_DBG("Enter"); - /* Wait for firmware to become ready */ for (tries = 0; tries < pollnum; tries++) { if (btmrvl_sdio_read_fw_status(card, &firmwarestat) < 0) @@ -220,8 +185,6 @@ static int btmrvl_sdio_verify_fw_download(struct btmrvl_sdio_card *card, } } - BT_DBG("Leave"); - return ret; } @@ -235,8 +198,6 @@ static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card) u8 *helperbuf; u32 tx_len; - BT_DBG("Enter"); - ret = request_firmware(&fw_helper, card->helper, &card->func->dev); if ((ret < 0) || !fw_helper) { @@ -326,8 +287,6 @@ done: if (fw_helper) release_firmware(fw_helper); - BT_DBG("Leave"); - return ret; } @@ -343,8 +302,6 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) u16 len; int txlen = 0, tx_blocks = 0, count = 0; - BT_DBG("Enter"); - ret = request_firmware(&fw_firmware, card->firmware, &card->func->dev); if ((ret < 0) || !fw_firmware) { @@ -479,8 +436,6 @@ done: if (fw_firmware) release_firmware(fw_firmware); - BT_DBG("Leave"); - return ret; } @@ -494,8 +449,6 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) struct hci_dev *hdev = priv->btmrvl_dev.hcidev; struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; - BT_DBG("Enter"); - if (!card || !card->func) { BT_ERR("card or function is NULL!"); ret = -EINVAL; @@ -596,8 +549,6 @@ exit: kfree_skb(skb); } - BT_DBG("Leave"); - return ret; } @@ -607,8 +558,6 @@ static int btmrvl_sdio_get_int_status(struct btmrvl_private *priv, u8 * ireg) u8 sdio_ireg = 0; struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; - BT_DBG("Enter"); - *ireg = 0; sdio_ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret); @@ -653,8 +602,6 @@ static int btmrvl_sdio_get_int_status(struct btmrvl_private *priv, u8 * ireg) ret = 0; done: - BT_DBG("Leave"); - return ret; } @@ -665,8 +612,6 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func) struct btmrvl_sdio_card *card; u8 ireg = 0; - BT_DBG("Enter"); - card = sdio_get_drvdata(func); if (card && card->priv) { priv = card->priv; @@ -679,8 +624,6 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func) btmrvl_interrupt(priv); } - - BT_DBG("Leave"); } static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) @@ -689,8 +632,6 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) u8 reg; int ret = 0; - BT_DBG("Enter"); - if (!card || !card->func) { BT_ERR("Error: card or function is NULL!"); ret = -EINVAL; @@ -752,7 +693,6 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) sdio_release_host(func); - BT_DBG("Leave"); return 0; release_irq: @@ -765,14 +705,11 @@ release_host: sdio_release_host(func); failed: - BT_DBG("Leave"); return ret; } static int btmrvl_sdio_unregister_dev(struct btmrvl_sdio_card *card) { - BT_DBG("Enter"); - if (card && card->func) { sdio_claim_host(card->func); sdio_release_irq(card->func); @@ -781,8 +718,6 @@ static int btmrvl_sdio_unregister_dev(struct btmrvl_sdio_card *card) sdio_set_drvdata(card->func, NULL); } - BT_DBG("Leave"); - return 0; } @@ -790,12 +725,8 @@ static int btmrvl_sdio_enable_host_int(struct btmrvl_sdio_card *card) { int ret; - BT_DBG("Enter"); - - if (!card || !card->func) { - BT_DBG("Leave"); + if (!card || !card->func) return -EINVAL; - } sdio_claim_host(card->func); @@ -805,8 +736,6 @@ static int btmrvl_sdio_enable_host_int(struct btmrvl_sdio_card *card) sdio_release_host(card->func); - BT_DBG("Leave"); - return ret; } @@ -814,12 +743,8 @@ static int btmrvl_sdio_disable_host_int(struct btmrvl_sdio_card *card) { int ret; - BT_DBG("Enter"); - - if (!card || !card->func) { - BT_DBG("Leave"); + if (!card || !card->func) return -EINVAL; - } sdio_claim_host(card->func); @@ -827,8 +752,6 @@ static int btmrvl_sdio_disable_host_int(struct btmrvl_sdio_card *card) sdio_release_host(card->func); - BT_DBG("Leave"); - return ret; } @@ -844,11 +767,8 @@ static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv, void *tmpbuf = NULL; int tmpbufsz; - BT_DBG("Enter"); - if (!card || !card->func) { BT_ERR("card or function is NULL!"); - BT_DBG("Leave"); return -EINVAL; } @@ -886,8 +806,6 @@ static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv, exit: sdio_release_host(card->func); - BT_DBG("Leave"); - return ret; } @@ -895,11 +813,8 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card) { int ret = 0; - BT_DBG("Enter"); - if (!card || !card->func) { BT_ERR("card or function is NULL!"); - BT_DBG("Leave"); return -EINVAL; } sdio_claim_host(card->func); @@ -931,8 +846,6 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card) done: sdio_release_host(card->func); - BT_DBG("Leave"); - return ret; } @@ -941,11 +854,8 @@ static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv) struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; int ret = 0; - BT_DBG("Enter"); - if (!card || !card->func) { BT_ERR("card or function is NULL!"); - BT_DBG("Leave"); return -EINVAL; } @@ -957,8 +867,6 @@ static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv) BT_DBG("wake up firmware"); - BT_DBG("Leave"); - return ret; } @@ -969,8 +877,6 @@ static int btmrvl_sdio_probe(struct sdio_func *func, struct btmrvl_private *priv = NULL; struct btmrvl_sdio_card *card = NULL; - BT_DBG("Enter"); - BT_INFO("vendor=0x%x, device=0x%x, class=%d, fn=%d", id->vendor, id->device, id->class, func->num); @@ -1022,8 +928,6 @@ static int btmrvl_sdio_probe(struct sdio_func *func, btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ); - BT_DBG("Leave"); - return 0; disable_host_int: @@ -1033,8 +937,6 @@ unreg_dev: free_card: kfree(card); done: - BT_DBG("Leave"); - return ret; } @@ -1042,8 +944,6 @@ static void btmrvl_sdio_remove(struct sdio_func *func) { struct btmrvl_sdio_card *card; - BT_DBG("Enter"); - if (func) { card = sdio_get_drvdata(func); if (card) { @@ -1061,8 +961,6 @@ static void btmrvl_sdio_remove(struct sdio_func *func) kfree(card); } } - - BT_DBG("Leave"); } static struct sdio_driver bt_mrvl_sdio = { @@ -1074,32 +972,23 @@ static struct sdio_driver bt_mrvl_sdio = { static int btmrvl_sdio_init_module(void) { - BT_DBG("Enter"); - if (sdio_register_driver(&bt_mrvl_sdio) != 0) { BT_ERR("SDIO Driver Registration Failed"); - BT_DBG("Leave"); return -ENODEV; } /* Clear the flag in case user removes the card. */ user_rmmod = 0; - BT_DBG("Leave"); - return 0; } static void btmrvl_sdio_exit_module(void) { - BT_DBG("Enter"); - /* Set the flag as user is removing this module. */ user_rmmod = 1; sdio_unregister_driver(&bt_mrvl_sdio); - - BT_DBG("Leave"); } module_init(btmrvl_sdio_init_module); -- cgit v1.2.3-18-g5258 From 3318b2362bf0528be77123c480249663557dfbfc Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Wed, 8 Jul 2009 11:44:14 -0700 Subject: Bluetooth: Fix incorrect alignment in Marvell BT-over-SDIO driver The driver uses "u32" for alignment check and calculation which works only on 32-bit system. It will crash the 64-bit system. Replace "u32" with "unsigned long" to fix this issue. Signed-off-by: Bing Zhao Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_sdio.c | 12 +++++++----- drivers/bluetooth/btmrvl_sdio.h | 3 ++- 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 224af53e0fa..1cfa8b4ace5 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -481,12 +481,14 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) goto exit; } - if ((u32) skb->data & (BTSDIO_DMA_ALIGN - 1)) { - skb_put(skb, (u32) skb->data & (BTSDIO_DMA_ALIGN - 1)); - skb_pull(skb, (u32) skb->data & (BTSDIO_DMA_ALIGN - 1)); + if ((unsigned long) skb->data & (BTSDIO_DMA_ALIGN - 1)) { + skb_put(skb, (unsigned long) skb->data & + (BTSDIO_DMA_ALIGN - 1)); + skb_pull(skb, (unsigned long) skb->data & + (BTSDIO_DMA_ALIGN - 1)); } - payload = skb->tail; + payload = skb->data; ret = sdio_readsb(card->func, payload, card->ioport, buf_block_len * blksz); @@ -773,7 +775,7 @@ static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv, } buf = payload; - if ((u32) payload & (BTSDIO_DMA_ALIGN - 1)) { + if ((unsigned long) payload & (BTSDIO_DMA_ALIGN - 1)) { tmpbufsz = ALIGN_SZ(nb, BTSDIO_DMA_ALIGN); tmpbuf = kmalloc(tmpbufsz, GFP_KERNEL); memset(tmpbuf, 0, tmpbufsz); diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h index 2dd284e0df1..27329f107e5 100644 --- a/drivers/bluetooth/btmrvl_sdio.h +++ b/drivers/bluetooth/btmrvl_sdio.h @@ -104,4 +104,5 @@ struct btmrvl_sdio_device { /* Macros for Data Alignment : address */ #define ALIGN_ADDR(p, a) \ - ((((u32)(p)) + (((u32)(a)) - 1)) & ~(((u32)(a)) - 1)) + ((((unsigned long)(p)) + (((unsigned long)(a)) - 1)) & \ + ~(((unsigned long)(a)) - 1)) -- cgit v1.2.3-18-g5258 From 5959809ded86e267c1a95fb44738a224c30d3434 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 6 Aug 2009 22:05:18 +0200 Subject: Bluetooth: Add missing kmalloc NULL tests to Marvell driver Check that the result of kmalloc is not NULL before dereferencing it. The patch also replaces kmalloc + memset by kzalloc. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression *x; identifier f; constant char *C; @@ x = \(kmalloc\|kcalloc\|kzalloc\)(...); ... when != x == NULL when != x != NULL when != (x || ...) ( kfree(x) | f(...,C,...,x,...) | *f(...,x,...) | *x->f ) // Signed-off-by: Julia Lawall Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_sdio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 1cfa8b4ace5..5b33b85790f 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -777,8 +777,9 @@ static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv, buf = payload; if ((unsigned long) payload & (BTSDIO_DMA_ALIGN - 1)) { tmpbufsz = ALIGN_SZ(nb, BTSDIO_DMA_ALIGN); - tmpbuf = kmalloc(tmpbufsz, GFP_KERNEL); - memset(tmpbuf, 0, tmpbufsz); + tmpbuf = kzalloc(tmpbufsz, GFP_KERNEL); + if (!tmpbuf) + return -ENOMEM; buf = (u8 *) ALIGN_ADDR(tmpbuf, BTSDIO_DMA_ALIGN); memcpy(buf, payload, nb); } -- cgit v1.2.3-18-g5258 From 5e928f77a09a07f9dd595bb8a489965d69a83458 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 18 Aug 2009 23:38:32 +0200 Subject: PM: Introduce core framework for run-time PM of I/O devices (rev. 17) Introduce a core framework for run-time power management of I/O devices. Add device run-time PM fields to 'struct dev_pm_info' and device run-time PM callbacks to 'struct dev_pm_ops'. Introduce a run-time PM workqueue and define some device run-time PM helper functions at the core level. Document all these things. Special thanks to Alan Stern for his help with the design and multiple detailed reviews of the pereceding versions of this patch and to Magnus Damm for testing feedback. Signed-off-by: Rafael J. Wysocki Acked-by: Magnus Damm --- drivers/base/dd.c | 11 + drivers/base/power/Makefile | 1 + drivers/base/power/main.c | 22 +- drivers/base/power/power.h | 31 +- drivers/base/power/runtime.c | 1011 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1068 insertions(+), 8 deletions(-) create mode 100644 drivers/base/power/runtime.c (limited to 'drivers') diff --git a/drivers/base/dd.c b/drivers/base/dd.c index f0106875f01..7b34b3a48f6 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "base.h" #include "power/power.h" @@ -202,7 +203,10 @@ int driver_probe_device(struct device_driver *drv, struct device *dev) pr_debug("bus: '%s': %s: matched device %s with driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name); + pm_runtime_get_noresume(dev); + pm_runtime_barrier(dev); ret = really_probe(dev, drv); + pm_runtime_put_sync(dev); return ret; } @@ -245,7 +249,9 @@ int device_attach(struct device *dev) ret = 0; } } else { + pm_runtime_get_noresume(dev); ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); + pm_runtime_put_sync(dev); } up(&dev->sem); return ret; @@ -306,6 +312,9 @@ static void __device_release_driver(struct device *dev) drv = dev->driver; if (drv) { + pm_runtime_get_noresume(dev); + pm_runtime_barrier(dev); + driver_sysfs_remove(dev); if (dev->bus) @@ -324,6 +333,8 @@ static void __device_release_driver(struct device *dev) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_UNBOUND_DRIVER, dev); + + pm_runtime_put_sync(dev); } } diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 911208b8925..3ce3519e8f3 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM_SLEEP) += main.o +obj-$(CONFIG_PM_RUNTIME) += runtime.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 1b1a786b7de..86990011277 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,16 @@ static DEFINE_MUTEX(dpm_list_mtx); */ static bool transition_started; +/** + * device_pm_init - Initialize the PM-related part of a device object + * @dev: Device object being initialized. + */ +void device_pm_init(struct device *dev) +{ + dev->power.status = DPM_ON; + pm_runtime_init(dev); +} + /** * device_pm_lock - lock the list of active devices used by the PM core */ @@ -105,6 +116,7 @@ void device_pm_remove(struct device *dev) mutex_lock(&dpm_list_mtx); list_del_init(&dev->power.entry); mutex_unlock(&dpm_list_mtx); + pm_runtime_remove(dev); } /** @@ -512,6 +524,7 @@ static void dpm_complete(pm_message_t state) mutex_unlock(&dpm_list_mtx); device_complete(dev, state); + pm_runtime_put_noidle(dev); mutex_lock(&dpm_list_mtx); } @@ -757,7 +770,14 @@ static int dpm_prepare(pm_message_t state) dev->power.status = DPM_PREPARING; mutex_unlock(&dpm_list_mtx); - error = device_prepare(dev, state); + pm_runtime_get_noresume(dev); + if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) { + /* Wake-up requested during system sleep transition. */ + pm_runtime_put_noidle(dev); + error = -EBUSY; + } else { + error = device_prepare(dev, state); + } mutex_lock(&dpm_list_mtx); if (error) { diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index c7cb4fc3735..b8fa1aa5225 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -1,7 +1,14 @@ -static inline void device_pm_init(struct device *dev) -{ - dev->power.status = DPM_ON; -} +#ifdef CONFIG_PM_RUNTIME + +extern void pm_runtime_init(struct device *dev); +extern void pm_runtime_remove(struct device *dev); + +#else /* !CONFIG_PM_RUNTIME */ + +static inline void pm_runtime_init(struct device *dev) {} +static inline void pm_runtime_remove(struct device *dev) {} + +#endif /* !CONFIG_PM_RUNTIME */ #ifdef CONFIG_PM_SLEEP @@ -16,23 +23,33 @@ static inline struct device *to_device(struct list_head *entry) return container_of(entry, struct device, power.entry); } +extern void device_pm_init(struct device *dev); extern void device_pm_add(struct device *); extern void device_pm_remove(struct device *); extern void device_pm_move_before(struct device *, struct device *); extern void device_pm_move_after(struct device *, struct device *); extern void device_pm_move_last(struct device *); -#else /* CONFIG_PM_SLEEP */ +#else /* !CONFIG_PM_SLEEP */ + +static inline void device_pm_init(struct device *dev) +{ + pm_runtime_init(dev); +} + +static inline void device_pm_remove(struct device *dev) +{ + pm_runtime_remove(dev); +} static inline void device_pm_add(struct device *dev) {} -static inline void device_pm_remove(struct device *dev) {} static inline void device_pm_move_before(struct device *deva, struct device *devb) {} static inline void device_pm_move_after(struct device *deva, struct device *devb) {} static inline void device_pm_move_last(struct device *dev) {} -#endif +#endif /* !CONFIG_PM_SLEEP */ #ifdef CONFIG_PM diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c new file mode 100644 index 00000000000..38556f6cc22 --- /dev/null +++ b/drivers/base/power/runtime.c @@ -0,0 +1,1011 @@ +/* + * drivers/base/power/runtime.c - Helper functions for device run-time PM + * + * Copyright (c) 2009 Rafael J. Wysocki , Novell Inc. + * + * This file is released under the GPLv2. + */ + +#include +#include +#include + +static int __pm_runtime_resume(struct device *dev, bool from_wq); +static int __pm_request_idle(struct device *dev); +static int __pm_request_resume(struct device *dev); + +/** + * pm_runtime_deactivate_timer - Deactivate given device's suspend timer. + * @dev: Device to handle. + */ +static void pm_runtime_deactivate_timer(struct device *dev) +{ + if (dev->power.timer_expires > 0) { + del_timer(&dev->power.suspend_timer); + dev->power.timer_expires = 0; + } +} + +/** + * pm_runtime_cancel_pending - Deactivate suspend timer and cancel requests. + * @dev: Device to handle. + */ +static void pm_runtime_cancel_pending(struct device *dev) +{ + pm_runtime_deactivate_timer(dev); + /* + * In case there's a request pending, make sure its work function will + * return without doing anything. + */ + dev->power.request = RPM_REQ_NONE; +} + +/** + * __pm_runtime_idle - Notify device bus type if the device can be suspended. + * @dev: Device to notify the bus type about. + * + * This function must be called under dev->power.lock with interrupts disabled. + */ +static int __pm_runtime_idle(struct device *dev) + __releases(&dev->power.lock) __acquires(&dev->power.lock) +{ + int retval = 0; + + dev_dbg(dev, "__pm_runtime_idle()!\n"); + + if (dev->power.runtime_error) + retval = -EINVAL; + else if (dev->power.idle_notification) + retval = -EINPROGRESS; + else if (atomic_read(&dev->power.usage_count) > 0 + || dev->power.disable_depth > 0 + || dev->power.runtime_status != RPM_ACTIVE) + retval = -EAGAIN; + else if (!pm_children_suspended(dev)) + retval = -EBUSY; + if (retval) + goto out; + + if (dev->power.request_pending) { + /* + * If an idle notification request is pending, cancel it. Any + * other pending request takes precedence over us. + */ + if (dev->power.request == RPM_REQ_IDLE) { + dev->power.request = RPM_REQ_NONE; + } else if (dev->power.request != RPM_REQ_NONE) { + retval = -EAGAIN; + goto out; + } + } + + dev->power.idle_notification = true; + + if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle) { + spin_unlock_irq(&dev->power.lock); + + dev->bus->pm->runtime_idle(dev); + + spin_lock_irq(&dev->power.lock); + } + + dev->power.idle_notification = false; + wake_up_all(&dev->power.wait_queue); + + out: + dev_dbg(dev, "__pm_runtime_idle() returns %d!\n", retval); + + return retval; +} + +/** + * pm_runtime_idle - Notify device bus type if the device can be suspended. + * @dev: Device to notify the bus type about. + */ +int pm_runtime_idle(struct device *dev) +{ + int retval; + + spin_lock_irq(&dev->power.lock); + retval = __pm_runtime_idle(dev); + spin_unlock_irq(&dev->power.lock); + + return retval; +} +EXPORT_SYMBOL_GPL(pm_runtime_idle); + +/** + * __pm_runtime_suspend - Carry out run-time suspend of given device. + * @dev: Device to suspend. + * @from_wq: If set, the function has been called via pm_wq. + * + * Check if the device can be suspended and run the ->runtime_suspend() callback + * provided by its bus type. If another suspend has been started earlier, wait + * for it to finish. If an idle notification or suspend request is pending or + * scheduled, cancel it. + * + * This function must be called under dev->power.lock with interrupts disabled. + */ +int __pm_runtime_suspend(struct device *dev, bool from_wq) + __releases(&dev->power.lock) __acquires(&dev->power.lock) +{ + struct device *parent = NULL; + bool notify = false; + int retval = 0; + + dev_dbg(dev, "__pm_runtime_suspend()%s!\n", + from_wq ? " from workqueue" : ""); + + repeat: + if (dev->power.runtime_error) { + retval = -EINVAL; + goto out; + } + + /* Pending resume requests take precedence over us. */ + if (dev->power.request_pending + && dev->power.request == RPM_REQ_RESUME) { + retval = -EAGAIN; + goto out; + } + + /* Other scheduled or pending requests need to be canceled. */ + pm_runtime_cancel_pending(dev); + + if (dev->power.runtime_status == RPM_SUSPENDED) + retval = 1; + else if (dev->power.runtime_status == RPM_RESUMING + || dev->power.disable_depth > 0 + || atomic_read(&dev->power.usage_count) > 0) + retval = -EAGAIN; + else if (!pm_children_suspended(dev)) + retval = -EBUSY; + if (retval) + goto out; + + if (dev->power.runtime_status == RPM_SUSPENDING) { + DEFINE_WAIT(wait); + + if (from_wq) { + retval = -EINPROGRESS; + goto out; + } + + /* Wait for the other suspend running in parallel with us. */ + for (;;) { + prepare_to_wait(&dev->power.wait_queue, &wait, + TASK_UNINTERRUPTIBLE); + if (dev->power.runtime_status != RPM_SUSPENDING) + break; + + spin_unlock_irq(&dev->power.lock); + + schedule(); + + spin_lock_irq(&dev->power.lock); + } + finish_wait(&dev->power.wait_queue, &wait); + goto repeat; + } + + dev->power.runtime_status = RPM_SUSPENDING; + + if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) { + spin_unlock_irq(&dev->power.lock); + + retval = dev->bus->pm->runtime_suspend(dev); + + spin_lock_irq(&dev->power.lock); + dev->power.runtime_error = retval; + } else { + retval = -ENOSYS; + } + + if (retval) { + dev->power.runtime_status = RPM_ACTIVE; + pm_runtime_cancel_pending(dev); + dev->power.deferred_resume = false; + + if (retval == -EAGAIN || retval == -EBUSY) { + notify = true; + dev->power.runtime_error = 0; + } + } else { + dev->power.runtime_status = RPM_SUSPENDED; + + if (dev->parent) { + parent = dev->parent; + atomic_add_unless(&parent->power.child_count, -1, 0); + } + } + wake_up_all(&dev->power.wait_queue); + + if (dev->power.deferred_resume) { + dev->power.deferred_resume = false; + __pm_runtime_resume(dev, false); + retval = -EAGAIN; + goto out; + } + + if (notify) + __pm_runtime_idle(dev); + + if (parent && !parent->power.ignore_children) { + spin_unlock_irq(&dev->power.lock); + + pm_request_idle(parent); + + spin_lock_irq(&dev->power.lock); + } + + out: + dev_dbg(dev, "__pm_runtime_suspend() returns %d!\n", retval); + + return retval; +} + +/** + * pm_runtime_suspend - Carry out run-time suspend of given device. + * @dev: Device to suspend. + */ +int pm_runtime_suspend(struct device *dev) +{ + int retval; + + spin_lock_irq(&dev->power.lock); + retval = __pm_runtime_suspend(dev, false); + spin_unlock_irq(&dev->power.lock); + + return retval; +} +EXPORT_SYMBOL_GPL(pm_runtime_suspend); + +/** + * __pm_runtime_resume - Carry out run-time resume of given device. + * @dev: Device to resume. + * @from_wq: If set, the function has been called via pm_wq. + * + * Check if the device can be woken up and run the ->runtime_resume() callback + * provided by its bus type. If another resume has been started earlier, wait + * for it to finish. If there's a suspend running in parallel with this + * function, wait for it to finish and resume the device. Cancel any scheduled + * or pending requests. + * + * This function must be called under dev->power.lock with interrupts disabled. + */ +int __pm_runtime_resume(struct device *dev, bool from_wq) + __releases(&dev->power.lock) __acquires(&dev->power.lock) +{ + struct device *parent = NULL; + int retval = 0; + + dev_dbg(dev, "__pm_runtime_resume()%s!\n", + from_wq ? " from workqueue" : ""); + + repeat: + if (dev->power.runtime_error) { + retval = -EINVAL; + goto out; + } + + pm_runtime_cancel_pending(dev); + + if (dev->power.runtime_status == RPM_ACTIVE) + retval = 1; + else if (dev->power.disable_depth > 0) + retval = -EAGAIN; + if (retval) + goto out; + + if (dev->power.runtime_status == RPM_RESUMING + || dev->power.runtime_status == RPM_SUSPENDING) { + DEFINE_WAIT(wait); + + if (from_wq) { + if (dev->power.runtime_status == RPM_SUSPENDING) + dev->power.deferred_resume = true; + retval = -EINPROGRESS; + goto out; + } + + /* Wait for the operation carried out in parallel with us. */ + for (;;) { + prepare_to_wait(&dev->power.wait_queue, &wait, + TASK_UNINTERRUPTIBLE); + if (dev->power.runtime_status != RPM_RESUMING + && dev->power.runtime_status != RPM_SUSPENDING) + break; + + spin_unlock_irq(&dev->power.lock); + + schedule(); + + spin_lock_irq(&dev->power.lock); + } + finish_wait(&dev->power.wait_queue, &wait); + goto repeat; + } + + if (!parent && dev->parent) { + /* + * Increment the parent's resume counter and resume it if + * necessary. + */ + parent = dev->parent; + spin_unlock_irq(&dev->power.lock); + + pm_runtime_get_noresume(parent); + + spin_lock_irq(&parent->power.lock); + /* + * We can resume if the parent's run-time PM is disabled or it + * is set to ignore children. + */ + if (!parent->power.disable_depth + && !parent->power.ignore_children) { + __pm_runtime_resume(parent, false); + if (parent->power.runtime_status != RPM_ACTIVE) + retval = -EBUSY; + } + spin_unlock_irq(&parent->power.lock); + + spin_lock_irq(&dev->power.lock); + if (retval) + goto out; + goto repeat; + } + + dev->power.runtime_status = RPM_RESUMING; + + if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) { + spin_unlock_irq(&dev->power.lock); + + retval = dev->bus->pm->runtime_resume(dev); + + spin_lock_irq(&dev->power.lock); + dev->power.runtime_error = retval; + } else { + retval = -ENOSYS; + } + + if (retval) { + dev->power.runtime_status = RPM_SUSPENDED; + pm_runtime_cancel_pending(dev); + } else { + dev->power.runtime_status = RPM_ACTIVE; + if (parent) + atomic_inc(&parent->power.child_count); + } + wake_up_all(&dev->power.wait_queue); + + if (!retval) + __pm_request_idle(dev); + + out: + if (parent) { + spin_unlock_irq(&dev->power.lock); + + pm_runtime_put(parent); + + spin_lock_irq(&dev->power.lock); + } + + dev_dbg(dev, "__pm_runtime_resume() returns %d!\n", retval); + + return retval; +} + +/** + * pm_runtime_resume - Carry out run-time resume of given device. + * @dev: Device to suspend. + */ +int pm_runtime_resume(struct device *dev) +{ + int retval; + + spin_lock_irq(&dev->power.lock); + retval = __pm_runtime_resume(dev, false); + spin_unlock_irq(&dev->power.lock); + + return retval; +} +EXPORT_SYMBOL_GPL(pm_runtime_resume); + +/** + * pm_runtime_work - Universal run-time PM work function. + * @work: Work structure used for scheduling the execution of this function. + * + * Use @work to get the device object the work is to be done for, determine what + * is to be done and execute the appropriate run-time PM function. + */ +static void pm_runtime_work(struct work_struct *work) +{ + struct device *dev = container_of(work, struct device, power.work); + enum rpm_request req; + + spin_lock_irq(&dev->power.lock); + + if (!dev->power.request_pending) + goto out; + + req = dev->power.request; + dev->power.request = RPM_REQ_NONE; + dev->power.request_pending = false; + + switch (req) { + case RPM_REQ_NONE: + break; + case RPM_REQ_IDLE: + __pm_runtime_idle(dev); + break; + case RPM_REQ_SUSPEND: + __pm_runtime_suspend(dev, true); + break; + case RPM_REQ_RESUME: + __pm_runtime_resume(dev, true); + break; + } + + out: + spin_unlock_irq(&dev->power.lock); +} + +/** + * __pm_request_idle - Submit an idle notification request for given device. + * @dev: Device to handle. + * + * Check if the device's run-time PM status is correct for suspending the device + * and queue up a request to run __pm_runtime_idle() for it. + * + * This function must be called under dev->power.lock with interrupts disabled. + */ +static int __pm_request_idle(struct device *dev) +{ + int retval = 0; + + if (dev->power.runtime_error) + retval = -EINVAL; + else if (atomic_read(&dev->power.usage_count) > 0 + || dev->power.disable_depth > 0 + || dev->power.runtime_status == RPM_SUSPENDED + || dev->power.runtime_status == RPM_SUSPENDING) + retval = -EAGAIN; + else if (!pm_children_suspended(dev)) + retval = -EBUSY; + if (retval) + return retval; + + if (dev->power.request_pending) { + /* Any requests other then RPM_REQ_IDLE take precedence. */ + if (dev->power.request == RPM_REQ_NONE) + dev->power.request = RPM_REQ_IDLE; + else if (dev->power.request != RPM_REQ_IDLE) + retval = -EAGAIN; + return retval; + } + + dev->power.request = RPM_REQ_IDLE; + dev->power.request_pending = true; + queue_work(pm_wq, &dev->power.work); + + return retval; +} + +/** + * pm_request_idle - Submit an idle notification request for given device. + * @dev: Device to handle. + */ +int pm_request_idle(struct device *dev) +{ + unsigned long flags; + int retval; + + spin_lock_irqsave(&dev->power.lock, flags); + retval = __pm_request_idle(dev); + spin_unlock_irqrestore(&dev->power.lock, flags); + + return retval; +} +EXPORT_SYMBOL_GPL(pm_request_idle); + +/** + * __pm_request_suspend - Submit a suspend request for given device. + * @dev: Device to suspend. + * + * This function must be called under dev->power.lock with interrupts disabled. + */ +static int __pm_request_suspend(struct device *dev) +{ + int retval = 0; + + if (dev->power.runtime_error) + return -EINVAL; + + if (dev->power.runtime_status == RPM_SUSPENDED) + retval = 1; + else if (atomic_read(&dev->power.usage_count) > 0 + || dev->power.disable_depth > 0) + retval = -EAGAIN; + else if (dev->power.runtime_status == RPM_SUSPENDING) + retval = -EINPROGRESS; + else if (!pm_children_suspended(dev)) + retval = -EBUSY; + if (retval < 0) + return retval; + + pm_runtime_deactivate_timer(dev); + + if (dev->power.request_pending) { + /* + * Pending resume requests take precedence over us, but we can + * overtake any other pending request. + */ + if (dev->power.request == RPM_REQ_RESUME) + retval = -EAGAIN; + else if (dev->power.request != RPM_REQ_SUSPEND) + dev->power.request = retval ? + RPM_REQ_NONE : RPM_REQ_SUSPEND; + return retval; + } else if (retval) { + return retval; + } + + dev->power.request = RPM_REQ_SUSPEND; + dev->power.request_pending = true; + queue_work(pm_wq, &dev->power.work); + + return 0; +} + +/** + * pm_suspend_timer_fn - Timer function for pm_schedule_suspend(). + * @data: Device pointer passed by pm_schedule_suspend(). + * + * Check if the time is right and execute __pm_request_suspend() in that case. + */ +static void pm_suspend_timer_fn(unsigned long data) +{ + struct device *dev = (struct device *)data; + unsigned long flags; + unsigned long expires; + + spin_lock_irqsave(&dev->power.lock, flags); + + expires = dev->power.timer_expires; + /* If 'expire' is after 'jiffies' we've been called too early. */ + if (expires > 0 && !time_after(expires, jiffies)) { + dev->power.timer_expires = 0; + __pm_request_suspend(dev); + } + + spin_unlock_irqrestore(&dev->power.lock, flags); +} + +/** + * pm_schedule_suspend - Set up a timer to submit a suspend request in future. + * @dev: Device to suspend. + * @delay: Time to wait before submitting a suspend request, in milliseconds. + */ +int pm_schedule_suspend(struct device *dev, unsigned int delay) +{ + unsigned long flags; + int retval = 0; + + spin_lock_irqsave(&dev->power.lock, flags); + + if (dev->power.runtime_error) { + retval = -EINVAL; + goto out; + } + + if (!delay) { + retval = __pm_request_suspend(dev); + goto out; + } + + pm_runtime_deactivate_timer(dev); + + if (dev->power.request_pending) { + /* + * Pending resume requests take precedence over us, but any + * other pending requests have to be canceled. + */ + if (dev->power.request == RPM_REQ_RESUME) { + retval = -EAGAIN; + goto out; + } + dev->power.request = RPM_REQ_NONE; + } + + if (dev->power.runtime_status == RPM_SUSPENDED) + retval = 1; + else if (dev->power.runtime_status == RPM_SUSPENDING) + retval = -EINPROGRESS; + else if (atomic_read(&dev->power.usage_count) > 0 + || dev->power.disable_depth > 0) + retval = -EAGAIN; + else if (!pm_children_suspended(dev)) + retval = -EBUSY; + if (retval) + goto out; + + dev->power.timer_expires = jiffies + msecs_to_jiffies(delay); + mod_timer(&dev->power.suspend_timer, dev->power.timer_expires); + + out: + spin_unlock_irqrestore(&dev->power.lock, flags); + + return retval; +} +EXPORT_SYMBOL_GPL(pm_schedule_suspend); + +/** + * pm_request_resume - Submit a resume request for given device. + * @dev: Device to resume. + * + * This function must be called under dev->power.lock with interrupts disabled. + */ +static int __pm_request_resume(struct device *dev) +{ + int retval = 0; + + if (dev->power.runtime_error) + return -EINVAL; + + if (dev->power.runtime_status == RPM_ACTIVE) + retval = 1; + else if (dev->power.runtime_status == RPM_RESUMING) + retval = -EINPROGRESS; + else if (dev->power.disable_depth > 0) + retval = -EAGAIN; + if (retval < 0) + return retval; + + pm_runtime_deactivate_timer(dev); + + if (dev->power.request_pending) { + /* If non-resume request is pending, we can overtake it. */ + dev->power.request = retval ? RPM_REQ_NONE : RPM_REQ_RESUME; + return retval; + } else if (retval) { + return retval; + } + + dev->power.request = RPM_REQ_RESUME; + dev->power.request_pending = true; + queue_work(pm_wq, &dev->power.work); + + return retval; +} + +/** + * pm_request_resume - Submit a resume request for given device. + * @dev: Device to resume. + */ +int pm_request_resume(struct device *dev) +{ + unsigned long flags; + int retval; + + spin_lock_irqsave(&dev->power.lock, flags); + retval = __pm_request_resume(dev); + spin_unlock_irqrestore(&dev->power.lock, flags); + + return retval; +} +EXPORT_SYMBOL_GPL(pm_request_resume); + +/** + * __pm_runtime_get - Reference count a device and wake it up, if necessary. + * @dev: Device to handle. + * @sync: If set and the device is suspended, resume it synchronously. + * + * Increment the usage count of the device and if it was zero previously, + * resume it or submit a resume request for it, depending on the value of @sync. + */ +int __pm_runtime_get(struct device *dev, bool sync) +{ + int retval = 1; + + if (atomic_add_return(1, &dev->power.usage_count) == 1) + retval = sync ? pm_runtime_resume(dev) : pm_request_resume(dev); + + return retval; +} +EXPORT_SYMBOL_GPL(__pm_runtime_get); + +/** + * __pm_runtime_put - Decrement the device's usage counter and notify its bus. + * @dev: Device to handle. + * @sync: If the device's bus type is to be notified, do that synchronously. + * + * Decrement the usage count of the device and if it reaches zero, carry out a + * synchronous idle notification or submit an idle notification request for it, + * depending on the value of @sync. + */ +int __pm_runtime_put(struct device *dev, bool sync) +{ + int retval = 0; + + if (atomic_dec_and_test(&dev->power.usage_count)) + retval = sync ? pm_runtime_idle(dev) : pm_request_idle(dev); + + return retval; +} +EXPORT_SYMBOL_GPL(__pm_runtime_put); + +/** + * __pm_runtime_set_status - Set run-time PM status of a device. + * @dev: Device to handle. + * @status: New run-time PM status of the device. + * + * If run-time PM of the device is disabled or its power.runtime_error field is + * different from zero, the status may be changed either to RPM_ACTIVE, or to + * RPM_SUSPENDED, as long as that reflects the actual state of the device. + * However, if the device has a parent and the parent is not active, and the + * parent's power.ignore_children flag is unset, the device's status cannot be + * set to RPM_ACTIVE, so -EBUSY is returned in that case. + * + * If successful, __pm_runtime_set_status() clears the power.runtime_error field + * and the device parent's counter of unsuspended children is modified to + * reflect the new status. If the new status is RPM_SUSPENDED, an idle + * notification request for the parent is submitted. + */ +int __pm_runtime_set_status(struct device *dev, unsigned int status) +{ + struct device *parent = dev->parent; + unsigned long flags; + bool notify_parent = false; + int error = 0; + + if (status != RPM_ACTIVE && status != RPM_SUSPENDED) + return -EINVAL; + + spin_lock_irqsave(&dev->power.lock, flags); + + if (!dev->power.runtime_error && !dev->power.disable_depth) { + error = -EAGAIN; + goto out; + } + + if (dev->power.runtime_status == status) + goto out_set; + + if (status == RPM_SUSPENDED) { + /* It always is possible to set the status to 'suspended'. */ + if (parent) { + atomic_add_unless(&parent->power.child_count, -1, 0); + notify_parent = !parent->power.ignore_children; + } + goto out_set; + } + + if (parent) { + spin_lock_irq(&parent->power.lock); + + /* + * It is invalid to put an active child under a parent that is + * not active, has run-time PM enabled and the + * 'power.ignore_children' flag unset. + */ + if (!parent->power.disable_depth + && !parent->power.ignore_children + && parent->power.runtime_status != RPM_ACTIVE) { + error = -EBUSY; + } else { + if (dev->power.runtime_status == RPM_SUSPENDED) + atomic_inc(&parent->power.child_count); + } + + spin_unlock_irq(&parent->power.lock); + + if (error) + goto out; + } + + out_set: + dev->power.runtime_status = status; + dev->power.runtime_error = 0; + out: + spin_unlock_irqrestore(&dev->power.lock, flags); + + if (notify_parent) + pm_request_idle(parent); + + return error; +} +EXPORT_SYMBOL_GPL(__pm_runtime_set_status); + +/** + * __pm_runtime_barrier - Cancel pending requests and wait for completions. + * @dev: Device to handle. + * + * Flush all pending requests for the device from pm_wq and wait for all + * run-time PM operations involving the device in progress to complete. + * + * Should be called under dev->power.lock with interrupts disabled. + */ +static void __pm_runtime_barrier(struct device *dev) +{ + pm_runtime_deactivate_timer(dev); + + if (dev->power.request_pending) { + dev->power.request = RPM_REQ_NONE; + spin_unlock_irq(&dev->power.lock); + + cancel_work_sync(&dev->power.work); + + spin_lock_irq(&dev->power.lock); + dev->power.request_pending = false; + } + + if (dev->power.runtime_status == RPM_SUSPENDING + || dev->power.runtime_status == RPM_RESUMING + || dev->power.idle_notification) { + DEFINE_WAIT(wait); + + /* Suspend, wake-up or idle notification in progress. */ + for (;;) { + prepare_to_wait(&dev->power.wait_queue, &wait, + TASK_UNINTERRUPTIBLE); + if (dev->power.runtime_status != RPM_SUSPENDING + && dev->power.runtime_status != RPM_RESUMING + && !dev->power.idle_notification) + break; + spin_unlock_irq(&dev->power.lock); + + schedule(); + + spin_lock_irq(&dev->power.lock); + } + finish_wait(&dev->power.wait_queue, &wait); + } +} + +/** + * pm_runtime_barrier - Flush pending requests and wait for completions. + * @dev: Device to handle. + * + * Prevent the device from being suspended by incrementing its usage counter and + * if there's a pending resume request for the device, wake the device up. + * Next, make sure that all pending requests for the device have been flushed + * from pm_wq and wait for all run-time PM operations involving the device in + * progress to complete. + * + * Return value: + * 1, if there was a resume request pending and the device had to be woken up, + * 0, otherwise + */ +int pm_runtime_barrier(struct device *dev) +{ + int retval = 0; + + pm_runtime_get_noresume(dev); + spin_lock_irq(&dev->power.lock); + + if (dev->power.request_pending + && dev->power.request == RPM_REQ_RESUME) { + __pm_runtime_resume(dev, false); + retval = 1; + } + + __pm_runtime_barrier(dev); + + spin_unlock_irq(&dev->power.lock); + pm_runtime_put_noidle(dev); + + return retval; +} +EXPORT_SYMBOL_GPL(pm_runtime_barrier); + +/** + * __pm_runtime_disable - Disable run-time PM of a device. + * @dev: Device to handle. + * @check_resume: If set, check if there's a resume request for the device. + * + * Increment power.disable_depth for the device and if was zero previously, + * cancel all pending run-time PM requests for the device and wait for all + * operations in progress to complete. The device can be either active or + * suspended after its run-time PM has been disabled. + * + * If @check_resume is set and there's a resume request pending when + * __pm_runtime_disable() is called and power.disable_depth is zero, the + * function will wake up the device before disabling its run-time PM. + */ +void __pm_runtime_disable(struct device *dev, bool check_resume) +{ + spin_lock_irq(&dev->power.lock); + + if (dev->power.disable_depth > 0) { + dev->power.disable_depth++; + goto out; + } + + /* + * Wake up the device if there's a resume request pending, because that + * means there probably is some I/O to process and disabling run-time PM + * shouldn't prevent the device from processing the I/O. + */ + if (check_resume && dev->power.request_pending + && dev->power.request == RPM_REQ_RESUME) { + /* + * Prevent suspends and idle notifications from being carried + * out after we have woken up the device. + */ + pm_runtime_get_noresume(dev); + + __pm_runtime_resume(dev, false); + + pm_runtime_put_noidle(dev); + } + + if (!dev->power.disable_depth++) + __pm_runtime_barrier(dev); + + out: + spin_unlock_irq(&dev->power.lock); +} +EXPORT_SYMBOL_GPL(__pm_runtime_disable); + +/** + * pm_runtime_enable - Enable run-time PM of a device. + * @dev: Device to handle. + */ +void pm_runtime_enable(struct device *dev) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->power.lock, flags); + + if (dev->power.disable_depth > 0) + dev->power.disable_depth--; + else + dev_warn(dev, "Unbalanced %s!\n", __func__); + + spin_unlock_irqrestore(&dev->power.lock, flags); +} +EXPORT_SYMBOL_GPL(pm_runtime_enable); + +/** + * pm_runtime_init - Initialize run-time PM fields in given device object. + * @dev: Device object to initialize. + */ +void pm_runtime_init(struct device *dev) +{ + spin_lock_init(&dev->power.lock); + + dev->power.runtime_status = RPM_SUSPENDED; + dev->power.idle_notification = false; + + dev->power.disable_depth = 1; + atomic_set(&dev->power.usage_count, 0); + + dev->power.runtime_error = 0; + + atomic_set(&dev->power.child_count, 0); + pm_suspend_ignore_children(dev, false); + + dev->power.request_pending = false; + dev->power.request = RPM_REQ_NONE; + dev->power.deferred_resume = false; + INIT_WORK(&dev->power.work, pm_runtime_work); + + dev->power.timer_expires = 0; + setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn, + (unsigned long)dev); + + init_waitqueue_head(&dev->power.wait_queue); +} + +/** + * pm_runtime_remove - Prepare for removing a device from device hierarchy. + * @dev: Device object being removed from device hierarchy. + */ +void pm_runtime_remove(struct device *dev) +{ + __pm_runtime_disable(dev, false); + + /* Change the status back to 'suspended' to match the initial status. */ + if (dev->power.runtime_status == RPM_ACTIVE) + pm_runtime_set_suspended(dev); +} -- cgit v1.2.3-18-g5258 From 9d7302299ee96ca954fe4ab8ca640333b6e19ad0 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 20 Aug 2009 20:25:32 +0200 Subject: PM: Run-time PM platform device bus support This patch adds default Runtime PM callbacks to the dev_pm_ops belonging to the platform bus. The callbacks are weak symbols that architecture specific code can override. Allows Runtime PM even though CONFIG_PM_SLEEP=n. Signed-off-by: Magnus Damm Acked-by: Greg Kroah-Hartman Signed-off-by: Rafael J. Wysocki --- drivers/base/platform.c | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index d28c289e4a3..0f7d434ce98 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "base.h" @@ -656,6 +657,13 @@ static void platform_pm_complete(struct device *dev) drv->pm->complete(dev); } +#else /* !CONFIG_PM_SLEEP */ + +#define platform_pm_prepare NULL +#define platform_pm_complete NULL + +#endif /* !CONFIG_PM_SLEEP */ + #ifdef CONFIG_SUSPEND static int platform_pm_suspend(struct device *dev) @@ -886,6 +894,31 @@ static int platform_pm_restore_noirq(struct device *dev) #endif /* !CONFIG_HIBERNATION */ +#ifdef CONFIG_PM_RUNTIME + +int __weak platform_pm_runtime_suspend(struct device *dev) +{ + return -ENOSYS; +}; + +int __weak platform_pm_runtime_resume(struct device *dev) +{ + return -ENOSYS; +}; + +int __weak platform_pm_runtime_idle(struct device *dev) +{ + return -ENOSYS; +}; + +#else /* !CONFIG_PM_RUNTIME */ + +#define platform_pm_runtime_suspend NULL +#define platform_pm_runtime_resume NULL +#define platform_pm_runtime_idle NULL + +#endif /* !CONFIG_PM_RUNTIME */ + static const struct dev_pm_ops platform_dev_pm_ops = { .prepare = platform_pm_prepare, .complete = platform_pm_complete, @@ -901,22 +934,17 @@ static const struct dev_pm_ops platform_dev_pm_ops = { .thaw_noirq = platform_pm_thaw_noirq, .poweroff_noirq = platform_pm_poweroff_noirq, .restore_noirq = platform_pm_restore_noirq, + .runtime_suspend = platform_pm_runtime_suspend, + .runtime_resume = platform_pm_runtime_resume, + .runtime_idle = platform_pm_runtime_idle, }; -#define PLATFORM_PM_OPS_PTR (&platform_dev_pm_ops) - -#else /* !CONFIG_PM_SLEEP */ - -#define PLATFORM_PM_OPS_PTR NULL - -#endif /* !CONFIG_PM_SLEEP */ - struct bus_type platform_bus_type = { .name = "platform", .dev_attrs = platform_dev_attrs, .match = platform_match, .uevent = platform_uevent, - .pm = PLATFORM_PM_OPS_PTR, + .pm = &platform_dev_pm_ops, }; EXPORT_SYMBOL_GPL(platform_bus_type); -- cgit v1.2.3-18-g5258 From b4567ca6304a9b31cb2eae62f812e9eb9badcb60 Mon Sep 17 00:00:00 2001 From: Douglas Gilbert Date: Thu, 25 Jun 2009 15:43:02 -0400 Subject: [SCSI] update scsi/constants.c It has been 3 years since this file was sync-ed with www.t10.org . Information taken from the last bunch of drafts released in May 2009. More asc/ascq codes are coming for thin provisioning; when approved and allocated another patch could add them prior to this patch going live. Changelog: - add some new command names and rename two commands - sync asc/ascq table with www.t10.org/lists/asc-num.txt - correct bug in scsi_extd_sense_format() [second for loop] Signed-off-by: Douglas Gilbert Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/constants.c | 95 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 75 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index e79e18101f8..63abb06c4ed 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -4,8 +4,7 @@ * Additions for SCSI 2 and Linux 2.2.x by D. Gilbert (990422) * Additions for SCSI 3+ (SPC-3 T10/1416-D Rev 07 3 May 2002) * by D. Gilbert and aeb (20020609) - * Additions for SPC-3 T10/1416-D Rev 21 22 Sept 2004, D. Gilbert 20041025 - * Update to SPC-4 T10/1713-D Rev 5a, 14 June 2006, D. Gilbert 20060702 + * Update to SPC-4 T10/1713-D Rev 20, 22 May 2009, D. Gilbert 20090624 */ #include @@ -56,9 +55,9 @@ static const char * cdb_byte0_names[] = { "Read Buffer", /* 3d-3f */ "Update Block", "Read Long(10)", "Write Long(10)", /* 40-41 */ "Change Definition", "Write Same(10)", -/* 42-48 */ "Read sub-channel", "Read TOC/PMA/ATIP", "Read density support", - "Play audio(10)", "Get configuration", "Play audio msf", - "Play audio track/index", +/* 42-48 */ "Unmap/Read sub-channel", "Read TOC/PMA/ATIP", + "Read density support", "Play audio(10)", "Get configuration", + "Play audio msf", "Play audio track/index", /* 49-4f */ "Play track relative(10)", "Get event status notification", "Pause/resume", "Log Select", "Log Sense", "Stop play/scan", NULL, @@ -71,12 +70,13 @@ static const char * cdb_byte0_names[] = { /* 60-67 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 68-6f */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 70-77 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -/* 78-7f */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Variable length", +/* 78-7f */ NULL, NULL, NULL, NULL, NULL, NULL, "Extended CDB", + "Variable length", /* 80-84 */ "Xdwrite(16)", "Rebuild(16)", "Regenerate(16)", "Extended copy", "Receive copy results", /* 85-89 */ "ATA command pass through(16)", "Access control in", "Access control out", "Read(16)", "Memory Export Out(16)", -/* 8a-8f */ "Write(16)", NULL, "Read attributes", "Write attributes", +/* 8a-8f */ "Write(16)", "ORWrite", "Read attributes", "Write attributes", "Write and verify(16)", "Verify(16)", /* 90-94 */ "Pre-fetch(16)", "Synchronize cache(16)", "Lock/unlock cache(16)", "Write same(16)", NULL, @@ -107,22 +107,24 @@ struct value_name_pair { }; static const struct value_name_pair maint_in_arr[] = { - {0x5, "Report device identifier"}, + {0x5, "Report identifying information"}, {0xa, "Report target port groups"}, {0xb, "Report aliases"}, {0xc, "Report supported operation codes"}, {0xd, "Report supported task management functions"}, {0xe, "Report priority"}, {0xf, "Report timestamp"}, + {0x10, "Management protocol in"}, }; #define MAINT_IN_SZ ARRAY_SIZE(maint_in_arr) static const struct value_name_pair maint_out_arr[] = { - {0x6, "Set device identifier"}, + {0x6, "Set identifying information"}, {0xa, "Set target port groups"}, {0xb, "Change aliases"}, {0xe, "Set priority"}, - {0xe, "Set timestamp"}, + {0xf, "Set timestamp"}, + {0x10, "Management protocol out"}, }; #define MAINT_OUT_SZ ARRAY_SIZE(maint_out_arr) @@ -412,6 +414,7 @@ static const struct error_info additional[] = {0x0004, "Beginning-of-partition/medium detected"}, {0x0005, "End-of-data detected"}, {0x0006, "I/O process terminated"}, + {0x0007, "Programmable early warning detected"}, {0x0011, "Audio play operation in progress"}, {0x0012, "Audio play operation paused"}, {0x0013, "Audio play operation successfully completed"}, @@ -425,6 +428,7 @@ static const struct error_info additional[] = {0x001B, "Set capacity operation in progress"}, {0x001C, "Verify operation in progress"}, {0x001D, "ATA pass through information available"}, + {0x001E, "Conflicting SA creation request"}, {0x0100, "No index/sector signal"}, @@ -449,9 +453,12 @@ static const struct error_info additional[] = {0x040B, "Logical unit not accessible, target port in standby state"}, {0x040C, "Logical unit not accessible, target port in unavailable " "state"}, + {0x040D, "Logical unit not ready, structure check required"}, {0x0410, "Logical unit not ready, auxiliary memory not accessible"}, {0x0411, "Logical unit not ready, notify (enable spinup) required"}, {0x0412, "Logical unit not ready, offline"}, + {0x0413, "Logical unit not ready, SA creation in progress"}, + {0x0414, "Logical unit not ready, space allocation in progress"}, {0x0500, "Logical unit does not respond to selection"}, @@ -479,6 +486,9 @@ static const struct error_info additional[] = {0x0B03, "Warning - background self-test failed"}, {0x0B04, "Warning - background pre-scan detected medium error"}, {0x0B05, "Warning - background medium scan detected medium error"}, + {0x0B06, "Warning - non-volatile cache now volatile"}, + {0x0B07, "Warning - degraded power to non-volatile cache"}, + {0x0B08, "Warning - power loss expected"}, {0x0C00, "Write error"}, {0x0C01, "Write error - recovered with auto reallocation"}, @@ -593,6 +603,7 @@ static const struct error_info additional[] = {0x1C02, "Grown defect list not found"}, {0x1D00, "Miscompare during verify operation"}, + {0x1D01, "Miscompare verify of unmapped LBA"}, {0x1E00, "Recovered id with ECC correction"}, @@ -626,6 +637,7 @@ static const struct error_info additional[] = {0x2405, "Security working key frozen"}, {0x2406, "Nonce not unique"}, {0x2407, "Nonce timestamp out of range"}, + {0x2408, "Invalid XCDB"}, {0x2500, "Logical unit not supported"}, @@ -656,10 +668,12 @@ static const struct error_info additional[] = {0x2704, "Persistent write protect"}, {0x2705, "Permanent write protect"}, {0x2706, "Conditional write protect"}, + {0x2707, "Space allocation failed write protect"}, {0x2800, "Not ready to ready change, medium may have changed"}, {0x2801, "Import or export element accessed"}, {0x2802, "Format-layer may have changed"}, + {0x2803, "Import/export element accessed, medium changed"}, {0x2900, "Power on, reset, or bus device reset occurred"}, {0x2901, "Power on occurred"}, @@ -680,11 +694,16 @@ static const struct error_info additional[] = {0x2A07, "Implicit asymmetric access state transition failed"}, {0x2A08, "Priority changed"}, {0x2A09, "Capacity data has changed"}, + {0x2A0A, "Error history I_T nexus cleared"}, + {0x2A0B, "Error history snapshot released"}, + {0x2A0C, "Error recovery attributes have changed"}, + {0x2A0D, "Data encryption capabilities changed"}, {0x2A10, "Timestamp changed"}, {0x2A11, "Data encryption parameters changed by another i_t nexus"}, {0x2A12, "Data encryption parameters changed by vendor specific " "event"}, {0x2A13, "Data encryption key instance counter has changed"}, + {0x2A14, "SA creation capabilities data has changed"}, {0x2B00, "Copy cannot execute since host cannot disconnect"}, @@ -723,6 +742,8 @@ static const struct error_info additional[] = {0x300C, "WORM medium - overwrite attempted"}, {0x300D, "WORM medium - integrity check"}, {0x3010, "Medium not formatted"}, + {0x3011, "Incompatible volume type"}, + {0x3012, "Incompatible volume qualifier"}, {0x3100, "Medium format corrupted"}, {0x3101, "Format command failed"}, @@ -782,6 +803,10 @@ static const struct error_info additional[] = {0x3B15, "Medium magazine unlocked"}, {0x3B16, "Mechanical positioning or changer error"}, {0x3B17, "Read past end of user object"}, + {0x3B18, "Element disabled"}, + {0x3B19, "Element enabled"}, + {0x3B1A, "Data transfer device removed"}, + {0x3B1B, "Data transfer device inserted"}, {0x3D00, "Invalid bits in identify message"}, @@ -882,6 +907,8 @@ static const struct error_info additional[] = {0x5506, "Auxiliary memory out of space"}, {0x5507, "Quota error"}, {0x5508, "Maximum number of supplemental decryption keys exceeded"}, + {0x5509, "Medium auxiliary memory not accessible"}, + {0x550A, "Data currently unavailable"}, {0x5700, "Unable to recover table-of-contents"}, @@ -993,6 +1020,12 @@ static const struct error_info additional[] = {0x5E02, "Standby condition activated by timer"}, {0x5E03, "Idle condition activated by command"}, {0x5E04, "Standby condition activated by command"}, + {0x5E05, "Idle_b condition activated by timer"}, + {0x5E06, "Idle_b condition activated by command"}, + {0x5E07, "Idle_c condition activated by timer"}, + {0x5E08, "Idle_c condition activated by command"}, + {0x5E09, "Standby_y condition activated by timer"}, + {0x5E0A, "Standby_y condition activated by command"}, {0x5E41, "Power state change to active"}, {0x5E42, "Power state change to idle"}, {0x5E43, "Power state change to standby"}, @@ -1091,7 +1124,28 @@ static const struct error_info additional[] = {0x7403, "Incorrect data encryption key"}, {0x7404, "Cryptographic integrity validation failed"}, {0x7405, "Error decrypting data"}, + {0x7406, "Unknown signature verification key"}, + {0x7407, "Encryption parameters not useable"}, + {0x7408, "Digital signature validation failure"}, + {0x7409, "Encryption mode mismatch on read"}, + {0x740A, "Encrypted block not raw read enabled"}, + {0x740B, "Incorrect Encryption parameters"}, + {0x740C, "Unable to decrypt parameter list"}, + {0x740D, "Encryption algorithm disabled"}, + {0x7410, "SA creation parameter value invalid"}, + {0x7411, "SA creation parameter value rejected"}, + {0x7412, "Invalid SA usage"}, + {0x7421, "Data Encryption configuration prevented"}, + {0x7430, "SA creation parameter not supported"}, + {0x7440, "Authentication failed"}, + {0x7461, "External data encryption key manager access error"}, + {0x7462, "External data encryption key manager error"}, + {0x7463, "External data encryption key not found"}, + {0x7464, "External data encryption request not authorized"}, + {0x746E, "External data encryption control timeout"}, + {0x746F, "External data encryption control error"}, {0x7471, "Logical unit access not authorized"}, + {0x7479, "Security conflict in translated device"}, {0, NULL} }; @@ -1103,12 +1157,12 @@ struct error_info2 { static const struct error_info2 additional2[] = { - {0x40,0x00,0x7f,"Ram failure (%x)"}, - {0x40,0x80,0xff,"Diagnostic failure on component (%x)"}, - {0x41,0x00,0xff,"Data path failure (%x)"}, - {0x42,0x00,0xff,"Power-on or self-test failure (%x)"}, - {0x4D,0x00,0xff,"Tagged overlapped commands (queue tag %x)"}, - {0x70,0x00,0xff,"Decompression exception short algorithm id of %x"}, + {0x40, 0x00, 0x7f, "Ram failure (%x)"}, + {0x40, 0x80, 0xff, "Diagnostic failure on component (%x)"}, + {0x41, 0x00, 0xff, "Data path failure (%x)"}, + {0x42, 0x00, 0xff, "Power-on or self-test failure (%x)"}, + {0x4D, 0x00, 0xff, "Tagged overlapped commands (task tag %x)"}, + {0x70, 0x00, 0xff, "Decompression exception short algorithm id of %x"}, {0, 0, 0, NULL} }; @@ -1157,14 +1211,15 @@ scsi_extd_sense_format(unsigned char asc, unsigned char ascq) { int i; unsigned short code = ((asc << 8) | ascq); - for (i=0; additional[i].text; i++) + for (i = 0; additional[i].text; i++) if (additional[i].code12 == code) return additional[i].text; - for (i=0; additional2[i].fmt; i++) + for (i = 0; additional2[i].fmt; i++) { if (additional2[i].code1 == asc && - additional2[i].code2_min >= ascq && - additional2[i].code2_max <= ascq) + ascq >= additional2[i].code2_min && + ascq <= additional2[i].code2_max) return additional2[i].fmt; + } #endif return NULL; } -- cgit v1.2.3-18-g5258 From 6c10db72c94818573552fd71c89540da325efdfb Mon Sep 17 00:00:00 2001 From: Chandra Seetharaman Date: Fri, 26 Jun 2009 19:30:06 -0700 Subject: [SCSI] scsi_dh: Reference count scsi_dh_attach Problem reported: http://marc.info/?l=dm-devel&m=124585978305866&w=2 scsi_dh does not do a refernce count for attach/detach, and this affects the way it is supposed to work with multipath when a device is not in the dev_list of the hardware handler. This patch adds a reference count that counts each attach. Signed-off-by: Chandra Seetharaman Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/device_handler/scsi_dh.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index a518f2eff19..53a7385e1b4 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c @@ -153,12 +153,24 @@ static int scsi_dh_handler_attach(struct scsi_device *sdev, if (sdev->scsi_dh_data) { if (sdev->scsi_dh_data->scsi_dh != scsi_dh) err = -EBUSY; - } else if (scsi_dh->attach) + else + kref_get(&sdev->scsi_dh_data->kref); + } else if (scsi_dh->attach) { err = scsi_dh->attach(sdev); - + if (!err) { + kref_init(&sdev->scsi_dh_data->kref); + sdev->scsi_dh_data->sdev = sdev; + } + } return err; } +static void __detach_handler (struct kref *kref) +{ + struct scsi_dh_data *scsi_dh_data = container_of(kref, struct scsi_dh_data, kref); + scsi_dh_data->scsi_dh->detach(scsi_dh_data->sdev); +} + /* * scsi_dh_handler_detach - Detach a device handler from a device * @sdev - SCSI device the device handler should be detached from @@ -180,7 +192,7 @@ static void scsi_dh_handler_detach(struct scsi_device *sdev, scsi_dh = sdev->scsi_dh_data->scsi_dh; if (scsi_dh && scsi_dh->detach) - scsi_dh->detach(sdev); + kref_put(&sdev->scsi_dh_data->kref, __detach_handler); } /* @@ -474,7 +486,6 @@ int scsi_dh_attach(struct request_queue *q, const char *name) if (!err) { err = scsi_dh_handler_attach(sdev, scsi_dh); - put_device(&sdev->sdev_gendev); } return err; @@ -505,10 +516,8 @@ void scsi_dh_detach(struct request_queue *q) return; if (sdev->scsi_dh_data) { - /* if sdev is not on internal list, detach */ scsi_dh = sdev->scsi_dh_data->scsi_dh; - if (!device_handler_match(scsi_dh, sdev)) - scsi_dh_handler_detach(sdev, scsi_dh); + scsi_dh_handler_detach(sdev, scsi_dh); } put_device(&sdev->sdev_gendev); } -- cgit v1.2.3-18-g5258 From 002b1eb2c03ccec36bf6e7b719cccedf57d83402 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Sat, 23 May 2009 11:45:07 -0400 Subject: [SCSI] Print failed commands When a request fails we print the sense data but not the actual command that failed. Add a printout of the operation + CDB for failed commands. Signed-off-by: Martin K. Petersen Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index f3c40898fc7..662024d8694 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -896,6 +896,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) scsi_print_result(cmd); if (driver_byte(result) & DRIVER_SENSE) scsi_print_sense("", cmd); + scsi_print_command(cmd); } blk_end_request_all(req, -EIO); scsi_next_command(cmd); -- cgit v1.2.3-18-g5258 From 1ed0f6a3ef94996341f3c5a2d4034ba1a2532b0a Mon Sep 17 00:00:00 2001 From: Anil Veerabhadrappa Date: Tue, 23 Jun 2009 13:56:29 -0700 Subject: [SCSI] bnx2i: remove global variable bnx2i_reg_devices Removed bnx2i_reg_devices as this counter is not really used in a meaningful way Signed-off-by: Michael Chan Signed-off-by: Anil Veerabhadrappa Reviewed-by: Mike Christie Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/bnx2i/bnx2i_init.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c index ae4b2d588fd..269192d7437 100644 --- a/drivers/scsi/bnx2i/bnx2i_init.c +++ b/drivers/scsi/bnx2i/bnx2i_init.c @@ -15,7 +15,6 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list); static u32 adapter_count; -static int bnx2i_reg_device; #define DRV_MODULE_NAME "bnx2i" #define DRV_MODULE_VERSION "2.0.1d" @@ -193,10 +192,6 @@ void bnx2i_register_device(struct bnx2i_hba *hba) hba->cnic->register_device(hba->cnic, CNIC_ULP_ISCSI, hba); - spin_lock(&hba->lock); - bnx2i_reg_device++; - spin_unlock(&hba->lock); - set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); } @@ -234,10 +229,6 @@ static void bnx2i_unreg_one_device(struct bnx2i_hba *hba) hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI); - spin_lock(&hba->lock); - bnx2i_reg_device--; - spin_unlock(&hba->lock); - /* ep_disconnect could come before NETDEV_DOWN, driver won't * see NETDEV_DOWN as it already unregistered itself. */ @@ -276,16 +267,12 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic) int rc; read_lock(&bnx2i_dev_lock); - if (bnx2i_reg_device && - !test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { + if (!test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba); if (rc) /* duplicate registration */ printk(KERN_ERR "bnx2i- dev reg failed\n"); - spin_lock(&hba->lock); - bnx2i_reg_device++; hba->age++; - spin_unlock(&hba->lock); set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); } @@ -350,10 +337,6 @@ void bnx2i_ulp_exit(struct cnic_dev *dev) if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI); clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); - - spin_lock(&hba->lock); - bnx2i_reg_device--; - spin_unlock(&hba->lock); } write_unlock(&bnx2i_dev_lock); @@ -421,7 +404,6 @@ static void __exit bnx2i_mod_exit(void) if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI); clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); - bnx2i_reg_device--; } write_unlock(&bnx2i_dev_lock); -- cgit v1.2.3-18-g5258 From 4e85f15166a6a9da8317ddb8600b604b27e58aa3 Mon Sep 17 00:00:00 2001 From: Anil Veerabhadrappa Date: Tue, 23 Jun 2009 14:04:23 -0700 Subject: [SCSI] bnx2i: bug fixes in bnx2i_init_one to handle error conditions Fixed bnx2i_init_one() to properly handle return code of cnic->register_device() and propagate it back to the caller. No need to check for BNX2I_CNIC_REGISTERED, because unless the adapter is added to adapter_list it will not be registered in ep_connect context Signed-off-by: Michael Chan Signed-off-by: Anil Veerabhadrappa Reviewed-by: Mike Christie Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/bnx2i/bnx2i_init.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c index 269192d7437..2aeeeee3372 100644 --- a/drivers/scsi/bnx2i/bnx2i_init.c +++ b/drivers/scsi/bnx2i/bnx2i_init.c @@ -267,22 +267,29 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic) int rc; read_lock(&bnx2i_dev_lock); - if (!test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { - rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba); - if (rc) /* duplicate registration */ - printk(KERN_ERR "bnx2i- dev reg failed\n"); - + rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba); + if (!rc) { hba->age++; - set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); - } + } else if (rc == -EBUSY) /* duplicate registration */ + printk(KERN_ALERT "bnx2i, duplicate registration" + "hba=%p, cnic=%p\n", hba, cnic); + else if (rc == -EAGAIN) + printk(KERN_ERR "bnx2i, driver not registered\n"); + else if (rc == -EINVAL) + printk(KERN_ERR "bnx2i, invalid type %d\n", CNIC_ULP_ISCSI); + else + printk(KERN_ERR "bnx2i dev reg, unknown error, %d\n", rc); read_unlock(&bnx2i_dev_lock); - write_lock(&bnx2i_dev_lock); - list_add_tail(&hba->link, &adapter_list); - adapter_count++; - write_unlock(&bnx2i_dev_lock); - return 0; + if (!rc) { + write_lock(&bnx2i_dev_lock); + list_add_tail(&hba->link, &adapter_list); + adapter_count++; + write_unlock(&bnx2i_dev_lock); + } + + return rc; } -- cgit v1.2.3-18-g5258 From 3be924fb1d7be90c3ae6aa30ca42e9aa5d75efaf Mon Sep 17 00:00:00 2001 From: Anil Veerabhadrappa Date: Tue, 23 Jun 2009 14:07:40 -0700 Subject: [SCSI] bnx2i: convert bnx2i_dev_lock to mutex convert bnx2i_dev_lock to type mutex from rwlock_t because cnic->register_device() can sleep for various reasons including memory allocation, waiting for ISCSI_INIT completion and while acquiring mutex lock, cnic_lock. Signed-off-by: Michael Chan Signed-off-by: Anil Veerabhadrappa Reviewed-by: Mike Christie Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/bnx2i/bnx2i_init.c | 54 +++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c index 2aeeeee3372..fd78540ffc9 100644 --- a/drivers/scsi/bnx2i/bnx2i_init.c +++ b/drivers/scsi/bnx2i/bnx2i_init.c @@ -17,8 +17,8 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list); static u32 adapter_count; #define DRV_MODULE_NAME "bnx2i" -#define DRV_MODULE_VERSION "2.0.1d" -#define DRV_MODULE_RELDATE "Mar 25, 2009" +#define DRV_MODULE_VERSION "2.0.1e" +#define DRV_MODULE_RELDATE "June 22, 2009" static char version[] __devinitdata = "Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \ @@ -30,7 +30,7 @@ MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709 iSCSI Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_MODULE_VERSION); -static DEFINE_RWLOCK(bnx2i_dev_lock); +static DEFINE_MUTEX(bnx2i_dev_lock); unsigned int event_coal_div = 1; module_param(event_coal_div, int, 0664); @@ -99,14 +99,14 @@ struct bnx2i_hba *get_adapter_list_head(void) if (!adapter_count) goto hba_not_found; - read_lock(&bnx2i_dev_lock); + mutex_lock(&bnx2i_dev_lock); list_for_each_entry(tmp_hba, &adapter_list, link) { if (tmp_hba->cnic && tmp_hba->cnic->cm_select_dev) { hba = tmp_hba; break; } } - read_unlock(&bnx2i_dev_lock); + mutex_unlock(&bnx2i_dev_lock); hba_not_found: return hba; } @@ -121,14 +121,14 @@ struct bnx2i_hba *bnx2i_find_hba_for_cnic(struct cnic_dev *cnic) { struct bnx2i_hba *hba, *temp; - read_lock(&bnx2i_dev_lock); + mutex_lock(&bnx2i_dev_lock); list_for_each_entry_safe(hba, temp, &adapter_list, link) { if (hba->cnic == cnic) { - read_unlock(&bnx2i_dev_lock); + mutex_unlock(&bnx2i_dev_lock); return hba; } } - read_unlock(&bnx2i_dev_lock); + mutex_unlock(&bnx2i_dev_lock); return NULL; } @@ -206,10 +206,10 @@ void bnx2i_reg_dev_all(void) { struct bnx2i_hba *hba, *temp; - read_lock(&bnx2i_dev_lock); + mutex_lock(&bnx2i_dev_lock); list_for_each_entry_safe(hba, temp, &adapter_list, link) bnx2i_register_device(hba); - read_unlock(&bnx2i_dev_lock); + mutex_unlock(&bnx2i_dev_lock); } @@ -246,10 +246,10 @@ void bnx2i_unreg_dev_all(void) { struct bnx2i_hba *hba, *temp; - read_lock(&bnx2i_dev_lock); + mutex_lock(&bnx2i_dev_lock); list_for_each_entry_safe(hba, temp, &adapter_list, link) bnx2i_unreg_one_device(hba); - read_unlock(&bnx2i_dev_lock); + mutex_unlock(&bnx2i_dev_lock); } @@ -258,19 +258,21 @@ void bnx2i_unreg_dev_all(void) * @hba: bnx2i adapter instance * @cnic: cnic device handle * - * Global resource lock and host adapter lock is held during critical sections - * below. This routine is called from cnic_register_driver() context and - * work horse thread which does majority of device specific initialization + * Global resource lock is held during critical sections below. This routine is + * called from either cnic_register_driver() or device hot plug context and + * and does majority of device specific initialization */ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic) { int rc; - read_lock(&bnx2i_dev_lock); + mutex_lock(&bnx2i_dev_lock); rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba); if (!rc) { hba->age++; set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); + list_add_tail(&hba->link, &adapter_list); + adapter_count++; } else if (rc == -EBUSY) /* duplicate registration */ printk(KERN_ALERT "bnx2i, duplicate registration" "hba=%p, cnic=%p\n", hba, cnic); @@ -280,14 +282,8 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic) printk(KERN_ERR "bnx2i, invalid type %d\n", CNIC_ULP_ISCSI); else printk(KERN_ERR "bnx2i dev reg, unknown error, %d\n", rc); - read_unlock(&bnx2i_dev_lock); - if (!rc) { - write_lock(&bnx2i_dev_lock); - list_add_tail(&hba->link, &adapter_list); - adapter_count++; - write_unlock(&bnx2i_dev_lock); - } + mutex_unlock(&bnx2i_dev_lock); return rc; } @@ -337,7 +333,7 @@ void bnx2i_ulp_exit(struct cnic_dev *dev) "found, dev 0x%p\n", dev); return; } - write_lock(&bnx2i_dev_lock); + mutex_lock(&bnx2i_dev_lock); list_del_init(&hba->link); adapter_count--; @@ -345,7 +341,7 @@ void bnx2i_ulp_exit(struct cnic_dev *dev) hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI); clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); } - write_unlock(&bnx2i_dev_lock); + mutex_unlock(&bnx2i_dev_lock); bnx2i_free_hba(hba); } @@ -367,6 +363,8 @@ static int __init bnx2i_mod_init(void) if (!is_power_of_2(sq_size)) sq_size = roundup_pow_of_two(sq_size); + mutex_init(&bnx2i_dev_lock); + bnx2i_scsi_xport_template = iscsi_register_transport(&bnx2i_iscsi_transport); if (!bnx2i_scsi_xport_template) { @@ -402,7 +400,7 @@ static void __exit bnx2i_mod_exit(void) { struct bnx2i_hba *hba; - write_lock(&bnx2i_dev_lock); + mutex_lock(&bnx2i_dev_lock); while (!list_empty(&adapter_list)) { hba = list_entry(adapter_list.next, struct bnx2i_hba, link); list_del(&hba->link); @@ -413,11 +411,9 @@ static void __exit bnx2i_mod_exit(void) clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); } - write_unlock(&bnx2i_dev_lock); bnx2i_free_hba(hba); - write_lock(&bnx2i_dev_lock); } - write_unlock(&bnx2i_dev_lock); + mutex_unlock(&bnx2i_dev_lock); iscsi_unregister_transport(&bnx2i_iscsi_transport); cnic_unregister_driver(CNIC_ULP_ISCSI); -- cgit v1.2.3-18-g5258 From fe5d20c818a8c5fe83d9f2223a051fb5bc50d180 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 4 Jul 2009 13:10:41 -0700 Subject: [SCSI] scsi_transport_fc: fix kernel-doc param name Change function parameter name in kernel-doc to match the function's actual parameter name, to fix 2 kernel-doc warnings. Signed-off-by: Randy Dunlap Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_fc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 292c02f810d..751f239e01e 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -3432,7 +3432,7 @@ fc_bsg_jobdone(struct fc_bsg_job *job) /** * fc_bsg_softirq_done - softirq done routine for destroying the bsg requests - * @req: BSG request that holds the job to be destroyed + * @rq: BSG request that holds the job to be destroyed */ static void fc_bsg_softirq_done(struct request *rq) { -- cgit v1.2.3-18-g5258 From fac3cc458fc2f8272bcc1ff1903474ff41715723 Mon Sep 17 00:00:00 2001 From: Anil Veerabhadrappa Date: Wed, 8 Jul 2009 18:21:01 -0700 Subject: [SCSI] bnx2i: register given device with cnic if shost != NULL in ep_connect() When using iface, bnx2i was unable to offload further connections after all active sessions are logged out. bnx2i will unregister the device from cnic when the last connection is torn down. Next call to ep_connect() will fail because the device is not registered. This issue is not seen if shost == NULL is passed to ep_connect() call because in that case bnx2i will registers all known devices with cnic before doing a route look-up. When shost != NULL, bnx2i knows the device on which to offload the connection and has to register this device before attempting to offload the connection Signed-off-by: Anil Veerabhadrappa Reviewed-by: Michael Chan Reviewed-by Mike Christie Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/bnx2i/bnx2i_init.c | 7 +++++-- drivers/scsi/bnx2i/bnx2i_iscsi.c | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c index fd78540ffc9..0c4210d48ee 100644 --- a/drivers/scsi/bnx2i/bnx2i_init.c +++ b/drivers/scsi/bnx2i/bnx2i_init.c @@ -185,14 +185,17 @@ void bnx2i_stop(void *handle) */ void bnx2i_register_device(struct bnx2i_hba *hba) { + int rc; + if (test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state) || test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { return; } - hba->cnic->register_device(hba->cnic, CNIC_ULP_ISCSI, hba); + rc = hba->cnic->register_device(hba->cnic, CNIC_ULP_ISCSI, hba); - set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); + if (!rc) + set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); } diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index f7412196f2f..98148f3f3c6 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -1653,15 +1653,18 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, struct iscsi_endpoint *ep; int rc = 0; - if (shost) + if (shost) { /* driver is given scsi host to work with */ hba = iscsi_host_priv(shost); - else + /* Register the device with cnic if not already done so */ + bnx2i_register_device(hba); + } else /* * check if the given destination can be reached through * a iscsi capable NetXtreme2 device */ hba = bnx2i_check_route(dst_addr); + if (!hba) { rc = -ENOMEM; goto check_busy; -- cgit v1.2.3-18-g5258 From 0fd30f77693f4fef32d30d4801cd21dcd487c2f0 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 13 Jul 2009 16:27:46 -0400 Subject: [SCSI] qla2xxx: Fix __LITTLE_ENDIAN definition warnings On ppc64, gcc 4.4 spews lots of.. drivers/scsi/qla2xxx/qla_def.h:1485:7: warning: "__LITTLE_ENDIAN" is not defined Signed-off-by: Dave Jones Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 00aa48d975a..9fde8bfe760 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1482,7 +1482,7 @@ typedef union { uint8_t domain; uint8_t area; uint8_t al_pa; -#elif __LITTLE_ENDIAN +#elif defined(__LITTLE_ENDIAN) uint8_t al_pa; uint8_t area; uint8_t domain; -- cgit v1.2.3-18-g5258 From e34ccdfe0e08a6acb8c5e649fef1e94e6cd637f9 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 13 Jul 2009 23:25:54 +0200 Subject: [SCSI] lpfc: don't dereference NULL When kzalloc fails in lpfc_hba_alloc, don't dereference the NULL by lpfc_printf_log. Use dev_err instead. Signed-off-by: Jiri Slaby Acked-By: James Smart Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_init.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index fc67cc65c63..2452dc9c901 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -4130,8 +4130,7 @@ lpfc_hba_alloc(struct pci_dev *pdev) /* Allocate memory for HBA structure */ phba = kzalloc(sizeof(struct lpfc_hba), GFP_KERNEL); if (!phba) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1417 Failed to allocate hba struct.\n"); + dev_err(&pdev->dev, "failed to allocate hba struct\n"); return NULL; } -- cgit v1.2.3-18-g5258 From 66d6faec2f874cf6bf9bd4900966584ea9feae3d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Jul 2009 17:21:14 +0200 Subject: [SCSI] fcoe: convert to %pM print_mac is being deprecated, and %pM makes for smaller code anyway. Signed-off-by: Johannes Berg Acked-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/fcoe/libfcoe.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index f544340d318..d6ed3f8255a 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -1104,7 +1104,6 @@ static void fcoe_ctlr_timeout(unsigned long arg) struct fcoe_fcf *sel; struct fcoe_fcf *fcf; unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD); - DECLARE_MAC_BUF(buf); u8 send_ctlr_ka; u8 send_port_ka; @@ -1128,9 +1127,8 @@ static void fcoe_ctlr_timeout(unsigned long arg) fcf = sel; /* the old FCF may have been freed */ if (sel) { printk(KERN_INFO "libfcoe: host%d: FIP selected " - "Fibre-Channel Forwarder MAC %s\n", - fip->lp->host->host_no, - print_mac(buf, sel->fcf_mac)); + "Fibre-Channel Forwarder MAC %pM\n", + fip->lp->host->host_no, sel->fcf_mac); memcpy(fip->dest_addr, sel->fcf_mac, ETH_ALEN); fip->port_ka_time = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD); -- cgit v1.2.3-18-g5258 From 8fa38513ddc1076f3e26c651f3567b084c273ba2 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sun, 19 Jul 2009 10:01:03 -0400 Subject: [SCSI] lpfc 8.3.4: Various SLI4 fixes Various SLI4 fixes - Fix switch name not used in the FCF record for FCoE HBAs - Enabled HBA UE error polling error-condition action code - Rewrite lpfc_sli4_scmd_to_wqidx_distr() to handle counter rollover cleanly - Modify resume_rpi mailbox data structure to match current SLI4 spec - Do not issue mailbox command in MBX_POLL mode when LPFC_HBA_ERROR is set - Wait for HBA POST completion before checking Online and UE registers - Fix accumulated total length not being filled in on unsolicited IOCBs - Use PCI config space register to determine SLI rev of HBA - Turn on starting ELS tmo function timer during device initialization Signed-off-by: James Smart Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 2 + drivers/scsi/lpfc/lpfc_hbadisc.c | 66 ++++++++++++++++++++++++++--- drivers/scsi/lpfc/lpfc_hw4.h | 74 +++++++++++++++++++++++++++------ drivers/scsi/lpfc/lpfc_init.c | 48 ++++++++++----------- drivers/scsi/lpfc/lpfc_mbox.c | 8 ++-- drivers/scsi/lpfc/lpfc_sli.c | 90 ++++++++++++++++++---------------------- drivers/scsi/lpfc/lpfc_sli4.h | 1 + 7 files changed, 190 insertions(+), 99 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 1877d981183..8917bb2c5fc 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -616,6 +616,8 @@ struct lpfc_hba { uint32_t hbq_count; /* Count of configured HBQs */ struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies */ + uint32_t fcp_qidx; /* next work queue to post work to */ + unsigned long pci_bar0_map; /* Physical address for PCI BAR0 */ unsigned long pci_bar1_map; /* Physical address for PCI BAR1 */ unsigned long pci_bar2_map; /* Physical address for PCI BAR2 */ diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index ed46b24a338..625b2ef3050 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1053,6 +1053,39 @@ lpfc_fab_name_match(uint8_t *fab_name, struct fcf_record *new_fcf_record) return 0; } +/** + * lpfc_sw_name_match - Check if the fcf switch name match. + * @fab_name: pointer to fabric name. + * @new_fcf_record: pointer to fcf record. + * + * This routine compare the fcf record's switch name with provided + * switch name. If the switch name are identical this function + * returns 1 else return 0. + **/ +static uint32_t +lpfc_sw_name_match(uint8_t *sw_name, struct fcf_record *new_fcf_record) +{ + if ((sw_name[0] == + bf_get(lpfc_fcf_record_switch_name_0, new_fcf_record)) && + (sw_name[1] == + bf_get(lpfc_fcf_record_switch_name_1, new_fcf_record)) && + (sw_name[2] == + bf_get(lpfc_fcf_record_switch_name_2, new_fcf_record)) && + (sw_name[3] == + bf_get(lpfc_fcf_record_switch_name_3, new_fcf_record)) && + (sw_name[4] == + bf_get(lpfc_fcf_record_switch_name_4, new_fcf_record)) && + (sw_name[5] == + bf_get(lpfc_fcf_record_switch_name_5, new_fcf_record)) && + (sw_name[6] == + bf_get(lpfc_fcf_record_switch_name_6, new_fcf_record)) && + (sw_name[7] == + bf_get(lpfc_fcf_record_switch_name_7, new_fcf_record))) + return 1; + else + return 0; +} + /** * lpfc_mac_addr_match - Check if the fcf mac address match. * @phba: pointer to lpfc hba data structure. @@ -1123,6 +1156,22 @@ lpfc_copy_fcf_record(struct lpfc_hba *phba, struct fcf_record *new_fcf_record) bf_get(lpfc_fcf_record_mac_5, new_fcf_record); phba->fcf.fcf_indx = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record); phba->fcf.priority = new_fcf_record->fip_priority; + phba->fcf.switch_name[0] = + bf_get(lpfc_fcf_record_switch_name_0, new_fcf_record); + phba->fcf.switch_name[1] = + bf_get(lpfc_fcf_record_switch_name_1, new_fcf_record); + phba->fcf.switch_name[2] = + bf_get(lpfc_fcf_record_switch_name_2, new_fcf_record); + phba->fcf.switch_name[3] = + bf_get(lpfc_fcf_record_switch_name_3, new_fcf_record); + phba->fcf.switch_name[4] = + bf_get(lpfc_fcf_record_switch_name_4, new_fcf_record); + phba->fcf.switch_name[5] = + bf_get(lpfc_fcf_record_switch_name_5, new_fcf_record); + phba->fcf.switch_name[6] = + bf_get(lpfc_fcf_record_switch_name_6, new_fcf_record); + phba->fcf.switch_name[7] = + bf_get(lpfc_fcf_record_switch_name_7, new_fcf_record); } /** @@ -1239,9 +1288,12 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba, if ((conn_entry->conn_rec.flags & FCFCNCT_FBNM_VALID) && !lpfc_fab_name_match(conn_entry->conn_rec.fabric_name, - new_fcf_record)) + new_fcf_record)) + continue; + if ((conn_entry->conn_rec.flags & FCFCNCT_SWNM_VALID) && + !lpfc_sw_name_match(conn_entry->conn_rec.switch_name, + new_fcf_record)) continue; - if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID) { /* * If the vlan bit map does not have the bit set for the @@ -1424,7 +1476,9 @@ lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) spin_lock_irqsave(&phba->hbalock, flags); if (phba->fcf.fcf_flag & FCF_IN_USE) { if (lpfc_fab_name_match(phba->fcf.fabric_name, - new_fcf_record) && + new_fcf_record) && + lpfc_sw_name_match(phba->fcf.switch_name, + new_fcf_record) && lpfc_mac_addr_match(phba, new_fcf_record)) { phba->fcf.fcf_flag |= FCF_AVAILABLE; spin_unlock_irqrestore(&phba->hbalock, flags); @@ -1464,9 +1518,9 @@ lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) * If there is a record with lower priority value for * the current FCF, use that record. */ - if (lpfc_fab_name_match(phba->fcf.fabric_name, new_fcf_record) - && (new_fcf_record->fip_priority < - phba->fcf.priority)) { + if (lpfc_fab_name_match(phba->fcf.fabric_name, + new_fcf_record) && + (new_fcf_record->fip_priority < phba->fcf.priority)) { /* Use this FCF record */ lpfc_copy_fcf_record(phba, new_fcf_record); phba->fcf.addr_mode = addr_mode; diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 2995d128f07..3689eee0453 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -52,6 +52,31 @@ struct dma_address { uint32_t addr_hi; }; +#define LPFC_SLIREV_CONF_WORD 0x58 +struct lpfc_sli_intf { + uint32_t word0; +#define lpfc_sli_intf_iftype_MASK 0x00000007 +#define lpfc_sli_intf_iftype_SHIFT 0 +#define lpfc_sli_intf_iftype_WORD word0 +#define lpfc_sli_intf_rev_MASK 0x0000000f +#define lpfc_sli_intf_rev_SHIFT 4 +#define lpfc_sli_intf_rev_WORD word0 +#define LPFC_SLIREV_CONF_SLI4 4 +#define lpfc_sli_intf_family_MASK 0x000000ff +#define lpfc_sli_intf_family_SHIFT 8 +#define lpfc_sli_intf_family_WORD word0 +#define lpfc_sli_intf_feat1_MASK 0x000000ff +#define lpfc_sli_intf_feat1_SHIFT 16 +#define lpfc_sli_intf_feat1_WORD word0 +#define lpfc_sli_intf_feat2_MASK 0x0000001f +#define lpfc_sli_intf_feat2_SHIFT 24 +#define lpfc_sli_intf_feat2_WORD word0 +#define lpfc_sli_intf_valid_MASK 0x00000007 +#define lpfc_sli_intf_valid_SHIFT 29 +#define lpfc_sli_intf_valid_WORD word0 +#define LPFC_SLI_INTF_VALID 6 +}; + #define LPFC_SLI4_BAR0 1 #define LPFC_SLI4_BAR1 2 #define LPFC_SLI4_BAR2 4 @@ -1181,6 +1206,32 @@ struct fcf_record { #define lpfc_fcf_record_fcf_state_MASK 0x0000FFFF #define lpfc_fcf_record_fcf_state_WORD word8 uint8_t vlan_bitmap[512]; + uint32_t word137; +#define lpfc_fcf_record_switch_name_0_SHIFT 0 +#define lpfc_fcf_record_switch_name_0_MASK 0x000000FF +#define lpfc_fcf_record_switch_name_0_WORD word137 +#define lpfc_fcf_record_switch_name_1_SHIFT 8 +#define lpfc_fcf_record_switch_name_1_MASK 0x000000FF +#define lpfc_fcf_record_switch_name_1_WORD word137 +#define lpfc_fcf_record_switch_name_2_SHIFT 16 +#define lpfc_fcf_record_switch_name_2_MASK 0x000000FF +#define lpfc_fcf_record_switch_name_2_WORD word137 +#define lpfc_fcf_record_switch_name_3_SHIFT 24 +#define lpfc_fcf_record_switch_name_3_MASK 0x000000FF +#define lpfc_fcf_record_switch_name_3_WORD word137 + uint32_t word138; +#define lpfc_fcf_record_switch_name_4_SHIFT 0 +#define lpfc_fcf_record_switch_name_4_MASK 0x000000FF +#define lpfc_fcf_record_switch_name_4_WORD word138 +#define lpfc_fcf_record_switch_name_5_SHIFT 8 +#define lpfc_fcf_record_switch_name_5_MASK 0x000000FF +#define lpfc_fcf_record_switch_name_5_WORD word138 +#define lpfc_fcf_record_switch_name_6_SHIFT 16 +#define lpfc_fcf_record_switch_name_6_MASK 0x000000FF +#define lpfc_fcf_record_switch_name_6_WORD word138 +#define lpfc_fcf_record_switch_name_7_SHIFT 24 +#define lpfc_fcf_record_switch_name_7_MASK 0x000000FF +#define lpfc_fcf_record_switch_name_7_WORD word138 }; struct lpfc_mbx_read_fcf_tbl { @@ -1385,20 +1436,17 @@ struct lpfc_mbx_unreg_vfi { struct lpfc_mbx_resume_rpi { uint32_t word1; -#define lpfc_resume_rpi_rpi_SHIFT 0 -#define lpfc_resume_rpi_rpi_MASK 0x0000FFFF -#define lpfc_resume_rpi_rpi_WORD word1 +#define lpfc_resume_rpi_index_SHIFT 0 +#define lpfc_resume_rpi_index_MASK 0x0000FFFF +#define lpfc_resume_rpi_index_WORD word1 +#define lpfc_resume_rpi_ii_SHIFT 30 +#define lpfc_resume_rpi_ii_MASK 0x00000003 +#define lpfc_resume_rpi_ii_WORD word1 +#define RESUME_INDEX_RPI 0 +#define RESUME_INDEX_VPI 1 +#define RESUME_INDEX_VFI 2 +#define RESUME_INDEX_FCFI 3 uint32_t event_tag; - uint32_t word3_rsvd; - uint32_t word4_rsvd; - uint32_t word5_rsvd; - uint32_t word6; -#define lpfc_resume_rpi_vpi_SHIFT 0 -#define lpfc_resume_rpi_vpi_MASK 0x0000FFFF -#define lpfc_resume_rpi_vpi_WORD word6 -#define lpfc_resume_rpi_vfi_SHIFT 16 -#define lpfc_resume_rpi_vfi_MASK 0x0000FFFF -#define lpfc_resume_rpi_vfi_WORD word6 }; #define REG_FCF_INVALID_QID 0xFFFF diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 2452dc9c901..f8271a587aa 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -4488,23 +4488,6 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba) if (!phba->sli4_hba.STAregaddr) return -ENODEV; - /* With uncoverable error, log the error message and return error */ - onlnreg0 = readl(phba->sli4_hba.ONLINE0regaddr); - onlnreg1 = readl(phba->sli4_hba.ONLINE1regaddr); - if ((onlnreg0 != LPFC_ONLINE_NERR) || (onlnreg1 != LPFC_ONLINE_NERR)) { - uerrlo_reg.word0 = readl(phba->sli4_hba.UERRLOregaddr); - uerrhi_reg.word0 = readl(phba->sli4_hba.UERRHIregaddr); - if (uerrlo_reg.word0 || uerrhi_reg.word0) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1422 HBA Unrecoverable error: " - "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, " - "online0_reg=0x%x, online1_reg=0x%x\n", - uerrlo_reg.word0, uerrhi_reg.word0, - onlnreg0, onlnreg1); - } - return -ENODEV; - } - /* Wait up to 30 seconds for the SLI Port POST done and ready */ for (i = 0; i < 3000; i++) { sta_reg.word0 = readl(phba->sli4_hba.STAregaddr); @@ -4544,6 +4527,23 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba) bf_get(lpfc_scratchpad_featurelevel1, &scratchpad), bf_get(lpfc_scratchpad_featurelevel2, &scratchpad)); + /* With uncoverable error, log the error message and return error */ + onlnreg0 = readl(phba->sli4_hba.ONLINE0regaddr); + onlnreg1 = readl(phba->sli4_hba.ONLINE1regaddr); + if ((onlnreg0 != LPFC_ONLINE_NERR) || (onlnreg1 != LPFC_ONLINE_NERR)) { + uerrlo_reg.word0 = readl(phba->sli4_hba.UERRLOregaddr); + uerrhi_reg.word0 = readl(phba->sli4_hba.UERRHIregaddr); + if (uerrlo_reg.word0 || uerrhi_reg.word0) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1422 HBA Unrecoverable error: " + "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, " + "online0_reg=0x%x, online1_reg=0x%x\n", + uerrlo_reg.word0, uerrhi_reg.word0, + onlnreg0, onlnreg1); + } + return -ENODEV; + } + return port_error; } @@ -7635,19 +7635,17 @@ static int __devinit lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) { int rc; - uint16_t dev_id; + struct lpfc_sli_intf intf; - if (pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id)) + if (pci_read_config_dword(pdev, LPFC_SLIREV_CONF_WORD, &intf.word0)) return -ENODEV; - switch (dev_id) { - case PCI_DEVICE_ID_TIGERSHARK: + if ((bf_get(lpfc_sli_intf_valid, &intf) == LPFC_SLI_INTF_VALID) && + (bf_get(lpfc_sli_intf_rev, &intf) == LPFC_SLIREV_CONF_SLI4)) rc = lpfc_pci_probe_one_s4(pdev, pid); - break; - default: + else rc = lpfc_pci_probe_one_s3(pdev, pid); - break; - } + return rc; } diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 3423571dd1b..42b4f384169 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1938,9 +1938,7 @@ lpfc_resume_rpi(struct lpfcMboxq *mbox, struct lpfc_nodelist *ndlp) memset(mbox, 0, sizeof(*mbox)); resume_rpi = &mbox->u.mqe.un.resume_rpi; bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_RESUME_RPI); - bf_set(lpfc_resume_rpi_rpi, resume_rpi, ndlp->nlp_rpi); - bf_set(lpfc_resume_rpi_vpi, resume_rpi, - ndlp->vport->vpi + ndlp->vport->phba->vpi_base); - bf_set(lpfc_resume_rpi_vfi, resume_rpi, - ndlp->vport->vfi + ndlp->vport->phba->vfi_base); + bf_set(lpfc_resume_rpi_index, resume_rpi, ndlp->nlp_rpi); + bf_set(lpfc_resume_rpi_ii, resume_rpi, RESUME_INDEX_RPI); + resume_rpi->event_tag = ndlp->phba->fc_eventTag; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index acc43b061ba..04f527ca8f5 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -4522,12 +4522,8 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) lpfc_sli4_rb_setup(phba); /* Start the ELS watchdog timer */ - /* - * The driver for SLI4 is not yet ready to process timeouts - * or interrupts. Once it is, the comment bars can be removed. - */ - /* mod_timer(&vport->els_tmofunc, - * jiffies + HZ * (phba->fc_ratov*2)); */ + mod_timer(&vport->els_tmofunc, + jiffies + HZ * (phba->fc_ratov * 2)); /* Start heart beat timer */ mod_timer(&phba->hb_tmofunc, @@ -5279,6 +5275,18 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, unsigned long iflags; int rc; + rc = lpfc_mbox_dev_check(phba); + if (unlikely(rc)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "(%d):2544 Mailbox command x%x (x%x) " + "cannot issue Data: x%x x%x\n", + mboxq->vport ? mboxq->vport->vpi : 0, + mboxq->u.mb.mbxCommand, + lpfc_sli4_mbox_opcode_get(phba, mboxq), + psli->sli_flag, flag); + goto out_not_finished; + } + /* Detect polling mode and jump to a handler */ if (!phba->sli4_hba.intr_enable) { if (flag == MBX_POLL) @@ -5338,17 +5346,6 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, psli->sli_flag, flag); goto out_not_finished; } - rc = lpfc_mbox_dev_check(phba); - if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "(%d):2544 Mailbox command x%x (x%x) " - "cannot issue Data: x%x x%x\n", - mboxq->vport ? mboxq->vport->vpi : 0, - mboxq->u.mb.mbxCommand, - lpfc_sli4_mbox_opcode_get(phba, mboxq), - psli->sli_flag, flag); - goto out_not_finished; - } /* Put the mailbox command to the driver internal FIFO */ psli->slistat.mbox_busy++; @@ -5817,19 +5814,21 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, /** * lpfc_sli4_scmd_to_wqidx_distr - scsi command to SLI4 WQ index distribution * @phba: Pointer to HBA context object. - * @piocb: Pointer to command iocb. * * This routine performs a round robin SCSI command to SLI4 FCP WQ index - * distribution. + * distribution. This is called by __lpfc_sli_issue_iocb_s4() with the hbalock + * held. * * Return: index into SLI4 fast-path FCP queue index. **/ static uint32_t -lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba, struct lpfc_iocbq *piocb) +lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba) { - static uint32_t fcp_qidx; + ++phba->fcp_qidx; + if (phba->fcp_qidx >= phba->cfg_fcp_wq_count) + phba->fcp_qidx = 0; - return fcp_qidx++ % phba->cfg_fcp_wq_count; + return phba->fcp_qidx; } /** @@ -6156,7 +6155,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, return IOCB_ERROR; if (piocb->iocb_flag & LPFC_IO_FCP) { - fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba, piocb); + fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba); if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[fcp_wqidx], &wqe)) return IOCB_ERROR; } else { @@ -7678,12 +7677,6 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba) "online0_reg=0x%x, online1_reg=0x%x\n", uerr_sta_lo, uerr_sta_hi, onlnreg0, onlnreg1); - /* TEMP: as the driver error recover logic is not - * fully developed, we just log the error message - * and the device error attention action is now - * temporarily disabled. - */ - return 0; phba->work_status[0] = uerr_sta_lo; phba->work_status[1] = uerr_sta_hi; /* Set the driver HA work bitmap */ @@ -9499,8 +9492,7 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax) eq->host_index = 0; eq->hba_index = 0; - if (rc != MBX_TIMEOUT) - mempool_free(mbox, phba->mbox_mem_pool); + mempool_free(mbox, phba->mbox_mem_pool); return status; } @@ -9604,10 +9596,9 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, cq->queue_id = bf_get(lpfc_mbx_cq_create_q_id, &cq_create->u.response); cq->host_index = 0; cq->hba_index = 0; -out: - if (rc != MBX_TIMEOUT) - mempool_free(mbox, phba->mbox_mem_pool); +out: + mempool_free(mbox, phba->mbox_mem_pool); return status; } @@ -9712,8 +9703,7 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq, /* link the mq onto the parent cq child list */ list_add_tail(&mq->list, &cq->child_list); out: - if (rc != MBX_TIMEOUT) - mempool_free(mbox, phba->mbox_mem_pool); + mempool_free(mbox, phba->mbox_mem_pool); return status; } @@ -9795,8 +9785,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, /* link the wq onto the parent cq child list */ list_add_tail(&wq->list, &cq->child_list); out: - if (rc != MBX_TIMEOUT) - mempool_free(mbox, phba->mbox_mem_pool); + mempool_free(mbox, phba->mbox_mem_pool); return status; } @@ -9970,8 +9959,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, list_add_tail(&drq->list, &cq->child_list); out: - if (rc != MBX_TIMEOUT) - mempool_free(mbox, phba->mbox_mem_pool); + mempool_free(mbox, phba->mbox_mem_pool); return status; } @@ -10026,8 +10014,7 @@ lpfc_eq_destroy(struct lpfc_hba *phba, struct lpfc_queue *eq) /* Remove eq from any list */ list_del_init(&eq->list); - if (rc != MBX_TIMEOUT) - mempool_free(mbox, eq->phba->mbox_mem_pool); + mempool_free(mbox, eq->phba->mbox_mem_pool); return status; } @@ -10080,8 +10067,7 @@ lpfc_cq_destroy(struct lpfc_hba *phba, struct lpfc_queue *cq) } /* Remove cq from any list */ list_del_init(&cq->list); - if (rc != MBX_TIMEOUT) - mempool_free(mbox, cq->phba->mbox_mem_pool); + mempool_free(mbox, cq->phba->mbox_mem_pool); return status; } @@ -10134,8 +10120,7 @@ lpfc_mq_destroy(struct lpfc_hba *phba, struct lpfc_queue *mq) } /* Remove mq from any list */ list_del_init(&mq->list); - if (rc != MBX_TIMEOUT) - mempool_free(mbox, mq->phba->mbox_mem_pool); + mempool_free(mbox, mq->phba->mbox_mem_pool); return status; } @@ -10187,8 +10172,7 @@ lpfc_wq_destroy(struct lpfc_hba *phba, struct lpfc_queue *wq) } /* Remove wq from any list */ list_del_init(&wq->list); - if (rc != MBX_TIMEOUT) - mempool_free(mbox, wq->phba->mbox_mem_pool); + mempool_free(mbox, wq->phba->mbox_mem_pool); return status; } @@ -10258,8 +10242,7 @@ lpfc_rq_destroy(struct lpfc_hba *phba, struct lpfc_queue *hrq, } list_del_init(&hrq->list); list_del_init(&drq->list); - if (rc != MBX_TIMEOUT) - mempool_free(mbox, hrq->phba->mbox_mem_pool); + mempool_free(mbox, hrq->phba->mbox_mem_pool); return status; } @@ -10933,6 +10916,7 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) first_iocbq = lpfc_sli_get_iocbq(vport->phba); if (first_iocbq) { /* Initialize the first IOCB. */ + first_iocbq->iocb.unsli3.rcvsli3.acc_len = 0; first_iocbq->iocb.ulpStatus = IOSTAT_SUCCESS; first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX; first_iocbq->iocb.ulpContext = be16_to_cpu(fc_hdr->fh_ox_id); @@ -10945,6 +10929,8 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) first_iocbq->iocb.un.cont64[0].tus.f.bdeSize = LPFC_DATA_BUF_SIZE; first_iocbq->iocb.un.rcvels.remoteID = sid; + first_iocbq->iocb.unsli3.rcvsli3.acc_len += + bf_get(lpfc_rcqe_length, &seq_dmabuf->rcqe); } iocbq = first_iocbq; /* @@ -10961,6 +10947,8 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) iocbq->iocb.ulpBdeCount++; iocbq->iocb.unsli3.rcvsli3.bde2.tus.f.bdeSize = LPFC_DATA_BUF_SIZE; + first_iocbq->iocb.unsli3.rcvsli3.acc_len += + bf_get(lpfc_rcqe_length, &seq_dmabuf->rcqe); } else { iocbq = lpfc_sli_get_iocbq(vport->phba); if (!iocbq) { @@ -10978,6 +10966,8 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) iocbq->iocb.ulpBdeCount = 1; iocbq->iocb.un.cont64[0].tus.f.bdeSize = LPFC_DATA_BUF_SIZE; + first_iocbq->iocb.unsli3.rcvsli3.acc_len += + bf_get(lpfc_rcqe_length, &seq_dmabuf->rcqe); iocbq->iocb.un.rcvels.remoteID = sid; list_add_tail(&iocbq->list, &first_iocbq->list); } diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 3b276b47d18..b6f3e04f384 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -132,6 +132,7 @@ struct lpfc_sli4_link { struct lpfc_fcf { uint8_t fabric_name[8]; + uint8_t switch_name[8]; uint8_t mac_addr[6]; uint16_t fcf_indx; uint16_t fcfi; -- cgit v1.2.3-18-g5258 From a0c87cbdb52467a16343b31251f2722643db603c Mon Sep 17 00:00:00 2001 From: James Smart Date: Sun, 19 Jul 2009 10:01:10 -0400 Subject: [SCSI] lpfc 8.3.4: Consistently Implement persistent port disable Consistently implement persistent port disable. Ability was to be managed in the adapter via firmware via flash settings. However, not all firmware images supported it. Uniformly support it everywhere. Signed-off-by: James Smart Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 1 + drivers/scsi/lpfc/lpfc_attr.c | 7 +- drivers/scsi/lpfc/lpfc_crtn.h | 5 +- drivers/scsi/lpfc/lpfc_hw.h | 4 +- drivers/scsi/lpfc/lpfc_init.c | 59 +++++++++++----- drivers/scsi/lpfc/lpfc_mbox.c | 36 +++++++--- drivers/scsi/lpfc/lpfc_sli.c | 158 +++++++++++++++++++++++++++++++++++++++++- drivers/scsi/lpfc/lpfc_sli4.h | 4 ++ 8 files changed, 242 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 8917bb2c5fc..7b63fe53004 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -525,6 +525,7 @@ struct lpfc_hba { #define FCP_XRI_ABORT_EVENT 0x20 #define ELS_XRI_ABORT_EVENT 0x40 #define ASYNC_EVENT 0x80 +#define LINK_DISABLED 0x100 /* Link disabled by user */ struct lpfc_dmabuf slim2p; MAILBOX_t *mbox; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index fc07be5fbce..7a629511338 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -394,7 +394,12 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr, case LPFC_INIT_MBX_CMDS: case LPFC_LINK_DOWN: case LPFC_HBA_ERROR: - len += snprintf(buf + len, PAGE_SIZE-len, "Link Down\n"); + if (phba->hba_flag & LINK_DISABLED) + len += snprintf(buf + len, PAGE_SIZE-len, + "Link Down - User disabled\n"); + else + len += snprintf(buf + len, PAGE_SIZE-len, + "Link Down\n"); break; case LPFC_LINK_UP: case LPFC_CLEAR_LA: diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index d2a922997c0..84e53bb1daa 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -21,7 +21,9 @@ typedef int (*node_filter)(struct lpfc_nodelist *, void *); struct fc_rport; -void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); +void lpfc_down_link(struct lpfc_hba *, LPFC_MBOXQ_t *); +void lpfc_sli_read_link_ste(struct lpfc_hba *); +void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t, uint16_t); void lpfc_dump_wakeup_param(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_dump_static_vport(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); int lpfc_dump_fcoe_param(struct lpfc_hba *, struct lpfcMboxq *); @@ -234,6 +236,7 @@ void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); int lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t, struct lpfc_iocbq *, uint32_t); void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t); +void lpfc_sli_bemem_bcopy(void *, void *, uint32_t); void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *); void lpfc_sli_flush_fcp_rings(struct lpfc_hba *); int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *, diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 8a3a026667e..ccb26724dc5 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -2496,8 +2496,8 @@ typedef struct { #define DMP_VPORT_REGION_SIZE 0x200 #define DMP_MBOX_OFFSET_WORD 0x5 -#define DMP_REGION_FCOEPARAM 0x17 /* fcoe param region */ -#define DMP_FCOEPARAM_RGN_SIZE 0x400 +#define DMP_REGION_23 0x17 /* fcoe param and port state region */ +#define DMP_RGN23_SIZE 0x400 #define WAKE_UP_PARMS_REGION_ID 4 #define WAKE_UP_PARMS_WORD_SIZE 15 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index f8271a587aa..900b5628ceb 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -211,7 +211,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba) goto out_free_mbox; do { - lpfc_dump_mem(phba, pmb, offset); + lpfc_dump_mem(phba, pmb, offset, DMP_REGION_VPD); rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); if (rc != MBX_SUCCESS) { @@ -425,6 +425,9 @@ lpfc_config_port_post(struct lpfc_hba *phba) return -EIO; } + /* Check if the port is disabled */ + lpfc_sli_read_link_ste(phba); + /* Reset the DFT_HBA_Q_DEPTH to the max xri */ if (phba->cfg_hba_queue_depth > (mb->un.varRdConfig.max_xri+1)) phba->cfg_hba_queue_depth = @@ -524,27 +527,49 @@ lpfc_config_port_post(struct lpfc_hba *phba) /* Set up error attention (ERATT) polling timer */ mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL); - lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed); - pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - lpfc_set_loopback_flag(phba); - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); - if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + /* Check if the port is disabled */ + lpfc_sli_read_serdes_param(phba); + + if (phba->hba_flag & LINK_DISABLED) { + lpfc_printf_log(phba, + KERN_ERR, LOG_INIT, + "2598 Adapter Link is disabled.\n"); + lpfc_down_link(phba, pmb); + pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); + if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) { + lpfc_printf_log(phba, + KERN_ERR, LOG_INIT, + "2599 Adapter failed to issue DOWN_LINK" + " mbox command rc 0x%x\n", rc); + + mempool_free(pmb, phba->mbox_mem_pool); + return -EIO; + } + } else { + lpfc_init_link(phba, pmb, phba->cfg_topology, + phba->cfg_link_speed); + pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + lpfc_set_loopback_flag(phba); + rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); + if (rc != MBX_SUCCESS) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0454 Adapter failed to init, mbxCmd x%x " "INIT_LINK, mbxStatus x%x\n", mb->mbxCommand, mb->mbxStatus); - /* Clear all interrupt enable conditions */ - writel(0, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - /* Clear all pending interrupts */ - writel(0xffffffff, phba->HAregaddr); - readl(phba->HAregaddr); /* flush */ + /* Clear all interrupt enable conditions */ + writel(0, phba->HCregaddr); + readl(phba->HCregaddr); /* flush */ + /* Clear all pending interrupts */ + writel(0xffffffff, phba->HAregaddr); + readl(phba->HAregaddr); /* flush */ - phba->link_state = LPFC_HBA_ERROR; - if (rc != MBX_BUSY) - mempool_free(pmb, phba->mbox_mem_pool); - return -EIO; + phba->link_state = LPFC_HBA_ERROR; + if (rc != MBX_BUSY) + mempool_free(pmb, phba->mbox_mem_pool); + return -EIO; + } } /* MBOX buffer will be freed in mbox compl */ pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 42b4f384169..245945f2f3a 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -79,21 +79,37 @@ lpfc_dump_static_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, } /** - * lpfc_dump_mem - Prepare a mailbox command for retrieving HBA's VPD memory + * lpfc_down_link - Bring down HBAs link. * @phba: pointer to lpfc hba data structure. * @pmb: pointer to the driver internal queue element for mailbox command. - * @offset: offset for dumping VPD memory mailbox command. + * + * This routine prepares a mailbox command to bring down HBA link. + **/ +void +lpfc_down_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) +{ + MAILBOX_t *mb; + memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); + mb = &pmb->u.mb; + mb->mbxCommand = MBX_DOWN_LINK; + mb->mbxOwner = OWN_HOST; +} + +/** + * lpfc_dump_mem - Prepare a mailbox command for reading a region. + * @phba: pointer to lpfc hba data structure. + * @pmb: pointer to the driver internal queue element for mailbox command. + * @offset: offset into the region. + * @region_id: config region id. * * The dump mailbox command provides a method for the device driver to obtain * various types of information from the HBA device. * - * This routine prepares the mailbox command for dumping HBA Vital Product - * Data (VPD) memory. This mailbox command is to be used for retrieving a - * portion (DMP_RSP_SIZE bytes) of a HBA's VPD from the HBA at an address - * offset specified by the offset parameter. + * This routine prepares the mailbox command for dumping HBA's config region. **/ void -lpfc_dump_mem(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint16_t offset) +lpfc_dump_mem(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, uint16_t offset, + uint16_t region_id) { MAILBOX_t *mb; void *ctx; @@ -107,7 +123,7 @@ lpfc_dump_mem(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint16_t offset) mb->un.varDmp.cv = 1; mb->un.varDmp.type = DMP_NV_PARAMS; mb->un.varDmp.entry_index = offset; - mb->un.varDmp.region_id = DMP_REGION_VPD; + mb->un.varDmp.region_id = region_id; mb->un.varDmp.word_cnt = (DMP_RSP_SIZE / sizeof (uint32_t)); mb->un.varDmp.co = 0; mb->un.varDmp.resp_offset = 0; @@ -1864,8 +1880,8 @@ lpfc_dump_fcoe_param(struct lpfc_hba *phba, mb->mbxCommand = MBX_DUMP_MEMORY; mb->un.varDmp.type = DMP_NV_PARAMS; - mb->un.varDmp.region_id = DMP_REGION_FCOEPARAM; - mb->un.varDmp.sli4_length = DMP_FCOEPARAM_RGN_SIZE; + mb->un.varDmp.region_id = DMP_REGION_23; + mb->un.varDmp.sli4_length = DMP_RGN23_SIZE; mb->un.varWords[3] = putPaddrLow(mp->phys); mb->un.varWords[4] = putPaddrHigh(mp->phys); return 0; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 04f527ca8f5..a3f85454368 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -4139,7 +4139,7 @@ lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba, return -EIO; } data_length = mqe->un.mb_words[5]; - if (data_length > DMP_FCOEPARAM_RGN_SIZE) { + if (data_length > DMP_RGN23_SIZE) { lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); return -EIO; @@ -6788,6 +6788,33 @@ lpfc_sli_pcimem_bcopy(void *srcp, void *destp, uint32_t cnt) } +/** + * lpfc_sli_bemem_bcopy - SLI memory copy function + * @srcp: Source memory pointer. + * @destp: Destination memory pointer. + * @cnt: Number of words required to be copied. + * + * This function is used for copying data between a data structure + * with big endian representation to local endianness. + * This function can be called with or without lock. + **/ +void +lpfc_sli_bemem_bcopy(void *srcp, void *destp, uint32_t cnt) +{ + uint32_t *src = srcp; + uint32_t *dest = destp; + uint32_t ldata; + int i; + + for (i = 0; i < (int)cnt; i += sizeof(uint32_t)) { + ldata = *src; + ldata = be32_to_cpu(ldata); + *dest = ldata; + src++; + dest++; + } +} + /** * lpfc_sli_ringpostbuf_put - Function to add a buffer to postbufq * @phba: Pointer to HBA context object. @@ -11564,3 +11591,132 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index) error = 0; return error; } + +/** + * lpfc_sli_read_link_ste - Read region 23 to decide if link is disabled. + * @phba: pointer to lpfc hba data structure. + * + * This function read region 23 and parse TLV for port status to + * decide if the user disaled the port. If the TLV indicates the + * port is disabled, the hba_flag is set accordingly. + **/ +void +lpfc_sli_read_link_ste(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *pmb = NULL; + MAILBOX_t *mb; + uint8_t *rgn23_data = NULL; + uint32_t offset = 0, data_size, sub_tlv_len, tlv_offset; + int rc; + + pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!pmb) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2600 lpfc_sli_read_serdes_param failed to" + " allocate mailbox memory\n"); + goto out; + } + mb = &pmb->u.mb; + + /* Get adapter Region 23 data */ + rgn23_data = kzalloc(DMP_RGN23_SIZE, GFP_KERNEL); + if (!rgn23_data) + goto out; + + do { + lpfc_dump_mem(phba, pmb, offset, DMP_REGION_23); + rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); + + if (rc != MBX_SUCCESS) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2601 lpfc_sli_read_link_ste failed to" + " read config region 23 rc 0x%x Status 0x%x\n", + rc, mb->mbxStatus); + mb->un.varDmp.word_cnt = 0; + } + /* + * dump mem may return a zero when finished or we got a + * mailbox error, either way we are done. + */ + if (mb->un.varDmp.word_cnt == 0) + break; + if (mb->un.varDmp.word_cnt > DMP_RGN23_SIZE - offset) + mb->un.varDmp.word_cnt = DMP_RGN23_SIZE - offset; + + lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET, + rgn23_data + offset, + mb->un.varDmp.word_cnt); + offset += mb->un.varDmp.word_cnt; + } while (mb->un.varDmp.word_cnt && offset < DMP_RGN23_SIZE); + + data_size = offset; + offset = 0; + + if (!data_size) + goto out; + + /* Check the region signature first */ + if (memcmp(&rgn23_data[offset], LPFC_REGION23_SIGNATURE, 4)) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2619 Config region 23 has bad signature\n"); + goto out; + } + offset += 4; + + /* Check the data structure version */ + if (rgn23_data[offset] != LPFC_REGION23_VERSION) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2620 Config region 23 has bad version\n"); + goto out; + } + offset += 4; + + /* Parse TLV entries in the region */ + while (offset < data_size) { + if (rgn23_data[offset] == LPFC_REGION23_LAST_REC) + break; + /* + * If the TLV is not driver specific TLV or driver id is + * not linux driver id, skip the record. + */ + if ((rgn23_data[offset] != DRIVER_SPECIFIC_TYPE) || + (rgn23_data[offset + 2] != LINUX_DRIVER_ID) || + (rgn23_data[offset + 3] != 0)) { + offset += rgn23_data[offset + 1] * 4 + 4; + continue; + } + + /* Driver found a driver specific TLV in the config region */ + sub_tlv_len = rgn23_data[offset + 1] * 4; + offset += 4; + tlv_offset = 0; + + /* + * Search for configured port state sub-TLV. + */ + while ((offset < data_size) && + (tlv_offset < sub_tlv_len)) { + if (rgn23_data[offset] == LPFC_REGION23_LAST_REC) { + offset += 4; + tlv_offset += 4; + break; + } + if (rgn23_data[offset] != PORT_STE_TYPE) { + offset += rgn23_data[offset + 1] * 4 + 4; + tlv_offset += rgn23_data[offset + 1] * 4 + 4; + continue; + } + + /* This HBA contains PORT_STE configured */ + if (!rgn23_data[offset + 2]) + phba->hba_flag |= LINK_DISABLED; + + goto out; + } + } +out: + if (pmb) + mempool_free(pmb, phba->mbox_mem_pool); + kfree(rgn23_data); + return; +} diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index b6f3e04f384..b5f4ba1a5c2 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -151,6 +151,10 @@ struct lpfc_fcf { #define LPFC_REGION23_SIGNATURE "RG23" #define LPFC_REGION23_VERSION 1 #define LPFC_REGION23_LAST_REC 0xff +#define DRIVER_SPECIFIC_TYPE 0xA2 +#define LINUX_DRIVER_ID 0x20 +#define PORT_STE_TYPE 0x1 + struct lpfc_fip_param_hdr { uint8_t type; #define FCOE_PARAM_TYPE 0xA0 -- cgit v1.2.3-18-g5258 From 8568a4d2495ebcf5da38a2141c7633399143b1a5 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sun, 19 Jul 2009 10:01:16 -0400 Subject: [SCSI] lpfc 8.3.4: Various SLI3 fixes Various SLI3 fixes - Fix for firmware dump failure - Fix inband remote management Signed-off-by: James Smart Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 1 + drivers/scsi/lpfc/lpfc_init.c | 3 --- drivers/scsi/lpfc/lpfc_mem.c | 41 +++++++++++++++++++++++++++++------------ drivers/scsi/lpfc/lpfc_sli.c | 2 +- 4 files changed, 31 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 7b63fe53004..8b69a110a30 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -685,6 +685,7 @@ struct lpfc_hba { struct pci_pool *lpfc_mbuf_pool; struct pci_pool *lpfc_hrb_pool; /* header receive buffer pool */ struct pci_pool *lpfc_drb_pool; /* data receive buffer pool */ + struct pci_pool *lpfc_hbq_pool; /* SLI3 hbq buffer pool */ struct lpfc_dma_pool lpfc_mbuf_safety_pool; mempool_t *mbox_mem_pool; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 900b5628ceb..dc561e3c8b9 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -527,9 +527,6 @@ lpfc_config_port_post(struct lpfc_hba *phba) /* Set up error attention (ERATT) polling timer */ mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL); - /* Check if the port is disabled */ - lpfc_sli_read_serdes_param(phba); - if (phba->hba_flag & LINK_DISABLED) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index e198c917c13..a1b6db6016d 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -110,17 +110,28 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align) sizeof(struct lpfc_nodelist)); if (!phba->nlp_mem_pool) goto fail_free_mbox_pool; - phba->lpfc_hrb_pool = pci_pool_create("lpfc_hrb_pool", + + if (phba->sli_rev == LPFC_SLI_REV4) { + phba->lpfc_hrb_pool = pci_pool_create("lpfc_hrb_pool", phba->pcidev, LPFC_HDR_BUF_SIZE, align, 0); - if (!phba->lpfc_hrb_pool) - goto fail_free_nlp_mem_pool; - phba->lpfc_drb_pool = pci_pool_create("lpfc_drb_pool", + if (!phba->lpfc_hrb_pool) + goto fail_free_nlp_mem_pool; + + phba->lpfc_drb_pool = pci_pool_create("lpfc_drb_pool", phba->pcidev, LPFC_DATA_BUF_SIZE, align, 0); - if (!phba->lpfc_drb_pool) - goto fail_free_hbq_pool; - + if (!phba->lpfc_drb_pool) + goto fail_free_hrb_pool; + phba->lpfc_hbq_pool = NULL; + } else { + phba->lpfc_hbq_pool = pci_pool_create("lpfc_hbq_pool", + phba->pcidev, LPFC_BPL_SIZE, align, 0); + if (!phba->lpfc_hbq_pool) + goto fail_free_nlp_mem_pool; + phba->lpfc_hrb_pool = NULL; + phba->lpfc_drb_pool = NULL; + } /* vpi zero is reserved for the physical port so add 1 to max */ longs = ((phba->max_vpi + 1) + BITS_PER_LONG - 1) / BITS_PER_LONG; phba->vpi_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL); @@ -132,7 +143,7 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align) fail_free_dbq_pool: pci_pool_destroy(phba->lpfc_drb_pool); phba->lpfc_drb_pool = NULL; - fail_free_hbq_pool: + fail_free_hrb_pool: pci_pool_destroy(phba->lpfc_hrb_pool); phba->lpfc_hrb_pool = NULL; fail_free_nlp_mem_pool: @@ -176,11 +187,17 @@ lpfc_mem_free(struct lpfc_hba *phba) /* Free HBQ pools */ lpfc_sli_hbqbuf_free_all(phba); - pci_pool_destroy(phba->lpfc_drb_pool); + if (phba->lpfc_drb_pool) + pci_pool_destroy(phba->lpfc_drb_pool); phba->lpfc_drb_pool = NULL; - pci_pool_destroy(phba->lpfc_hrb_pool); + if (phba->lpfc_hrb_pool) + pci_pool_destroy(phba->lpfc_hrb_pool); phba->lpfc_hrb_pool = NULL; + if (phba->lpfc_hbq_pool) + pci_pool_destroy(phba->lpfc_hbq_pool); + phba->lpfc_hbq_pool = NULL; + /* Free NLP memory pool */ mempool_destroy(phba->nlp_mem_pool); phba->nlp_mem_pool = NULL; @@ -380,7 +397,7 @@ lpfc_els_hbq_alloc(struct lpfc_hba *phba) if (!hbqbp) return NULL; - hbqbp->dbuf.virt = pci_pool_alloc(phba->lpfc_hrb_pool, GFP_KERNEL, + hbqbp->dbuf.virt = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_KERNEL, &hbqbp->dbuf.phys); if (!hbqbp->dbuf.virt) { kfree(hbqbp); @@ -405,7 +422,7 @@ lpfc_els_hbq_alloc(struct lpfc_hba *phba) void lpfc_els_hbq_free(struct lpfc_hba *phba, struct hbq_dmabuf *hbqbp) { - pci_pool_free(phba->lpfc_hrb_pool, hbqbp->dbuf.virt, hbqbp->dbuf.phys); + pci_pool_free(phba->lpfc_hbq_pool, hbqbp->dbuf.virt, hbqbp->dbuf.phys); kfree(hbqbp); return; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index a3f85454368..174a1b0d005 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -4702,13 +4702,13 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, spin_lock_irqsave(&phba->hbalock, drvr_flag); if (!pmbox) { + phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; /* processing mbox queue from intr_handler */ if (unlikely(psli->sli_flag & LPFC_SLI_ASYNC_MBX_BLK)) { spin_unlock_irqrestore(&phba->hbalock, drvr_flag); return MBX_SUCCESS; } processing_queue = 1; - phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; pmbox = lpfc_mbox_get(phba); if (!pmbox) { spin_unlock_irqrestore(&phba->hbalock, drvr_flag); -- cgit v1.2.3-18-g5258 From 32b9793fe6ff09a85f36b8bd7d6ff214653a7497 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sun, 19 Jul 2009 10:01:21 -0400 Subject: [SCSI] lpfc 8.3.4: Fix a pair of FCoE issues Fix a pair of FCoE issues - Fix Region 23 FCoE Parameters not being read correctly - Fix race condition when there are FCoE events during FCF table read Signed-off-by: James Smart Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 3 ++ drivers/scsi/lpfc/lpfc_crtn.h | 1 + drivers/scsi/lpfc/lpfc_hbadisc.c | 77 +++++++++++++++++++++++++++++++++++++++- drivers/scsi/lpfc/lpfc_init.c | 9 +++-- drivers/scsi/lpfc/lpfc_sli.c | 7 +++- 5 files changed, 92 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 8b69a110a30..d982ac78009 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -526,6 +526,7 @@ struct lpfc_hba { #define ELS_XRI_ABORT_EVENT 0x40 #define ASYNC_EVENT 0x80 #define LINK_DISABLED 0x100 /* Link disabled by user */ +#define FCF_DISC_INPROGRESS 0x200 /* FCF discovery in progress */ struct lpfc_dmabuf slim2p; MAILBOX_t *mbox; @@ -767,6 +768,8 @@ struct lpfc_hba { /* Maximum number of events that can be outstanding at any time*/ #define LPFC_MAX_EVT_COUNT 512 atomic_t fast_event_count; + uint32_t fcoe_eventtag; + uint32_t fcoe_eventtag_at_fcf_scan; struct lpfc_fcf fcf; uint8_t fc_map[3]; uint8_t valid_vlan; diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 84e53bb1daa..d52aa331055 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -189,6 +189,7 @@ void lpfc_unreg_vfi(struct lpfcMboxq *, uint16_t); void lpfc_reg_fcfi(struct lpfc_hba *, struct lpfcMboxq *); void lpfc_unreg_fcfi(struct lpfcMboxq *, uint16_t); void lpfc_resume_rpi(struct lpfcMboxq *, struct lpfc_nodelist *); +int lpfc_check_pending_fcoe_event(struct lpfc_hba *, uint8_t); void lpfc_config_hbq(struct lpfc_hba *, uint32_t, struct lpfc_hbq_init *, uint32_t , LPFC_MBOXQ_t *); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 625b2ef3050..cc4b6ba9e4d 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -61,6 +61,7 @@ static uint8_t lpfcAlpaArray[] = { static void lpfc_disc_timeout_handler(struct lpfc_vport *); static void lpfc_disc_flush_list(struct lpfc_vport *vport); +static void lpfc_unregister_fcfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_terminate_rport_io(struct fc_rport *rport) @@ -1009,9 +1010,15 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) spin_lock_irqsave(&phba->hbalock, flags); phba->fcf.fcf_flag |= FCF_REGISTERED; spin_unlock_irqrestore(&phba->hbalock, flags); + /* If there is a pending FCoE event, restart FCF table scan. */ + if (lpfc_check_pending_fcoe_event(phba, 1)) { + mempool_free(mboxq, phba->mbox_mem_pool); + return; + } if (vport->port_state != LPFC_FLOGI) { spin_lock_irqsave(&phba->hbalock, flags); phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE); + phba->hba_flag &= ~FCF_DISC_INPROGRESS; spin_unlock_irqrestore(&phba->hbalock, flags); lpfc_initial_flogi(vport); } @@ -1199,6 +1206,7 @@ lpfc_register_fcf(struct lpfc_hba *phba) /* The FCF is already registered, start discovery */ if (phba->fcf.fcf_flag & FCF_REGISTERED) { phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE); + phba->hba_flag &= ~FCF_DISC_INPROGRESS; spin_unlock_irqrestore(&phba->hbalock, flags); if (phba->pport->port_state != LPFC_FLOGI) lpfc_initial_flogi(phba->pport); @@ -1387,6 +1395,60 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba, return 0; } +/** + * lpfc_check_pending_fcoe_event - Check if there is pending fcoe event. + * @phba: pointer to lpfc hba data structure. + * @unreg_fcf: Unregister FCF if FCF table need to be re-scaned. + * + * This function check if there is any fcoe event pending while driver + * scan FCF entries. If there is any pending event, it will restart the + * FCF saning and return 1 else return 0. + */ +int +lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf) +{ + LPFC_MBOXQ_t *mbox; + int rc; + /* + * If the Link is up and no FCoE events while in the + * FCF discovery, no need to restart FCF discovery. + */ + if ((phba->link_state >= LPFC_LINK_UP) && + (phba->fcoe_eventtag == phba->fcoe_eventtag_at_fcf_scan)) + return 0; + + spin_lock_irq(&phba->hbalock); + phba->fcf.fcf_flag &= ~FCF_AVAILABLE; + spin_unlock_irq(&phba->hbalock); + + if (phba->link_state >= LPFC_LINK_UP) + lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST); + + if (unreg_fcf) { + spin_lock_irq(&phba->hbalock); + phba->fcf.fcf_flag &= ~FCF_REGISTERED; + spin_unlock_irq(&phba->hbalock); + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) { + lpfc_printf_log(phba, KERN_ERR, + LOG_DISCOVERY|LOG_MBOX, + "2610 UNREG_FCFI mbox allocation failed\n"); + return 1; + } + lpfc_unreg_fcfi(mbox, phba->fcf.fcfi); + mbox->vport = phba->pport; + mbox->mbox_cmpl = lpfc_unregister_fcfi_cmpl; + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + "2611 UNREG_FCFI issue mbox failed\n"); + mempool_free(mbox, phba->mbox_mem_pool); + } + } + + return 1; +} + /** * lpfc_mbx_cmpl_read_fcf_record - Completion handler for read_fcf mbox. * @phba: pointer to lpfc hba data structure. @@ -1419,6 +1481,12 @@ lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) unsigned long flags; uint16_t vlan_id; + /* If there is pending FCoE event restart FCF table scan */ + if (lpfc_check_pending_fcoe_event(phba, 0)) { + lpfc_sli4_mbox_cmd_free(phba, mboxq); + return; + } + /* Get the first SGE entry from the non-embedded DMA memory. This * routine only uses a single SGE. */ @@ -1823,6 +1891,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) goto out; } } else { + vport->port_state = LPFC_VPORT_UNKNOWN; /* * Add the driver's default FCF record at FCF index 0 now. This * is phase 1 implementation that support FCF index 0 and driver @@ -1858,6 +1927,12 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) * The driver is expected to do FIP/FCF. Call the port * and get the FCF Table. */ + spin_lock_irq(&phba->hbalock); + if (phba->hba_flag & FCF_DISC_INPROGRESS) { + spin_unlock_irq(&phba->hbalock); + return; + } + spin_unlock_irq(&phba->hbalock); rc = lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST); if (rc) @@ -4414,7 +4489,7 @@ lpfc_read_fcoe_param(struct lpfc_hba *phba, fcoe_param_hdr = (struct lpfc_fip_param_hdr *) buff; fcoe_param = (struct lpfc_fcoe_params *) - buff + sizeof(struct lpfc_fip_param_hdr); + (buff + sizeof(struct lpfc_fip_param_hdr)); if ((fcoe_param_hdr->parm_version != FIPP_VERSION) || (fcoe_param_hdr->length != FCOE_PARAM_LENGTH)) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index dc561e3c8b9..a7f32ed256b 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -2829,6 +2829,7 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba, att_type = lpfc_sli4_parse_latt_type(phba, acqe_link); if (att_type != AT_LINK_DOWN && att_type != AT_LINK_UP) return; + phba->fcoe_eventtag = acqe_link->event_tag; pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, @@ -2916,6 +2917,7 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, uint8_t event_type = bf_get(lpfc_acqe_fcoe_event_type, acqe_fcoe); int rc; + phba->fcoe_eventtag = acqe_fcoe->event_tag; switch (event_type) { case LPFC_FCOE_EVENT_TYPE_NEW_FCF: lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, @@ -2923,11 +2925,12 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, acqe_fcoe->fcf_index, acqe_fcoe->event_tag); /* - * If the current FCF is in discovered state, - * do nothing. + * If the current FCF is in discovered state, or + * FCF discovery is in progress do nothing. */ spin_lock_irq(&phba->hbalock); - if (phba->fcf.fcf_flag & FCF_DISCOVERED) { + if ((phba->fcf.fcf_flag & FCF_DISCOVERED) || + (phba->hba_flag & FCF_DISC_INPROGRESS)) { spin_unlock_irq(&phba->hbalock); break; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 174a1b0d005..a0f973e7acb 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -11536,6 +11536,7 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index) uint32_t alloc_len, req_len; struct lpfc_mbx_read_fcf_tbl *read_fcf; + phba->fcoe_eventtag_at_fcf_scan = phba->fcoe_eventtag; mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -11587,8 +11588,12 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index) if (rc == MBX_NOT_FINISHED) { lpfc_sli4_mbox_cmd_free(phba, mboxq); error = -EIO; - } else + } else { + spin_lock_irq(&phba->hbalock); + phba->hba_flag |= FCF_DISC_INPROGRESS; + spin_unlock_irq(&phba->hbalock); error = 0; + } return error; } -- cgit v1.2.3-18-g5258 From 1c6834a7e85715a4ac07c1cac25a1950040decb0 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sun, 19 Jul 2009 10:01:26 -0400 Subject: [SCSI] lpfc 8.3.4: NPIV vport fixes NPIV vport fixes - Fixed static vport creation on SLI4 HBAs - Fixed vport create sending init_vpi before REG_VFI - Fix unable to create vports on SLI4 HBA's Port2 Signed-off-by: James Smart Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 1 + drivers/scsi/lpfc/lpfc_crtn.h | 4 +- drivers/scsi/lpfc/lpfc_hbadisc.c | 114 ++++++++++++++++++++++++++++++++------- drivers/scsi/lpfc/lpfc_init.c | 5 ++ drivers/scsi/lpfc/lpfc_mbox.c | 47 ++++++++++++---- drivers/scsi/lpfc/lpfc_sli.c | 2 +- drivers/scsi/lpfc/lpfc_vport.c | 51 ++++++++++-------- 7 files changed, 168 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index d982ac78009..8cca3619c74 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -312,6 +312,7 @@ struct lpfc_vport { #define FC_BYPASSED_MODE 0x20000 /* NPort is in bypassed mode */ #define FC_VPORT_NEEDS_REG_VPI 0x80000 /* Needs to have its vpi registered */ #define FC_RSCN_DEFERRED 0x100000 /* A deferred RSCN being processed */ +#define FC_VPORT_NEEDS_INIT_VPI 0x200000 /* Need to INIT_VPI before FDISC */ uint32_t ct_flags; #define FC_CT_RFF_ID 0x1 /* RFF_ID accepted by switch */ diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index d52aa331055..48943d34414 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -25,7 +25,7 @@ void lpfc_down_link(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_sli_read_link_ste(struct lpfc_hba *); void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t, uint16_t); void lpfc_dump_wakeup_param(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_dump_static_vport(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); +int lpfc_dump_static_vport(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); int lpfc_dump_fcoe_param(struct lpfc_hba *, struct lpfcMboxq *); void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); @@ -184,7 +184,7 @@ int lpfc_mbox_dev_check(struct lpfc_hba *); int lpfc_mbox_tmo_val(struct lpfc_hba *, int); void lpfc_init_vfi(struct lpfcMboxq *, struct lpfc_vport *); void lpfc_reg_vfi(struct lpfcMboxq *, struct lpfc_vport *, dma_addr_t); -void lpfc_init_vpi(struct lpfcMboxq *, uint16_t); +void lpfc_init_vpi(struct lpfc_hba *, struct lpfcMboxq *, uint16_t); void lpfc_unreg_vfi(struct lpfcMboxq *, uint16_t); void lpfc_reg_fcfi(struct lpfc_hba *, struct lpfcMboxq *); void lpfc_unreg_fcfi(struct lpfcMboxq *, uint16_t); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index cc4b6ba9e4d..491c53fd1ca 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1633,6 +1633,39 @@ out: return; } +/** + * lpfc_init_vpi_cmpl - Completion handler for init_vpi mbox command. + * @phba: pointer to lpfc hba data structure. + * @mboxq: pointer to mailbox data structure. + * + * This function handles completion of init vpi mailbox command. + */ +static void +lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) +{ + struct lpfc_vport *vport = mboxq->vport; + if (mboxq->u.mb.mbxStatus) { + lpfc_printf_vlog(vport, KERN_ERR, + LOG_MBOX, + "2609 Init VPI mailbox failed 0x%x\n", + mboxq->u.mb.mbxStatus); + mempool_free(mboxq, phba->mbox_mem_pool); + lpfc_vport_set_state(vport, FC_VPORT_FAILED); + return; + } + vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI; + + if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) + lpfc_initial_fdisc(vport); + else { + lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP); + lpfc_printf_vlog(vport, KERN_ERR, + LOG_ELS, + "2606 No NPIV Fabric support\n"); + } + return; +} + /** * lpfc_start_fdiscs - send fdiscs for each vports on this port. * @phba: pointer to lpfc hba data structure. @@ -1645,6 +1678,8 @@ lpfc_start_fdiscs(struct lpfc_hba *phba) { struct lpfc_vport **vports; int i; + LPFC_MBOXQ_t *mboxq; + int rc; vports = lpfc_create_vport_work_array(phba); if (vports != NULL) { @@ -1662,6 +1697,29 @@ lpfc_start_fdiscs(struct lpfc_hba *phba) FC_VPORT_LINKDOWN); continue; } + if (vports[i]->fc_flag & FC_VPORT_NEEDS_INIT_VPI) { + mboxq = mempool_alloc(phba->mbox_mem_pool, + GFP_KERNEL); + if (!mboxq) { + lpfc_printf_vlog(vports[i], KERN_ERR, + LOG_MBOX, "2607 Failed to allocate " + "init_vpi mailbox\n"); + continue; + } + lpfc_init_vpi(phba, mboxq, vports[i]->vpi); + mboxq->vport = vports[i]; + mboxq->mbox_cmpl = lpfc_init_vpi_cmpl; + rc = lpfc_sli_issue_mbox(phba, mboxq, + MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + lpfc_printf_vlog(vports[i], KERN_ERR, + LOG_MBOX, "2608 Failed to issue " + "init_vpi mailbox\n"); + mempool_free(mboxq, + phba->mbox_mem_pool); + } + continue; + } if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) lpfc_initial_fdisc(vports[i]); else { @@ -2242,13 +2300,15 @@ lpfc_create_static_vport(struct lpfc_hba *phba) LPFC_MBOXQ_t *pmb = NULL; MAILBOX_t *mb; struct static_vport_info *vport_info; - int rc, i; + int rc = 0, i; struct fc_vport_identifiers vport_id; struct fc_vport *new_fc_vport; struct Scsi_Host *shost; struct lpfc_vport *vport; uint16_t offset = 0; uint8_t *vport_buff; + struct lpfc_dmabuf *mp; + uint32_t byte_count = 0; pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) { @@ -2271,7 +2331,9 @@ lpfc_create_static_vport(struct lpfc_hba *phba) vport_buff = (uint8_t *) vport_info; do { - lpfc_dump_static_vport(phba, pmb, offset); + if (lpfc_dump_static_vport(phba, pmb, offset)) + goto out; + pmb->vport = phba->pport; rc = lpfc_sli_issue_mbox_wait(phba, pmb, LPFC_MBOX_TMO); @@ -2284,17 +2346,30 @@ lpfc_create_static_vport(struct lpfc_hba *phba) goto out; } - if (mb->un.varDmp.word_cnt > - sizeof(struct static_vport_info) - offset) - mb->un.varDmp.word_cnt = - sizeof(struct static_vport_info) - offset; - - lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET, - vport_buff + offset, - mb->un.varDmp.word_cnt); - offset += mb->un.varDmp.word_cnt; + if (phba->sli_rev == LPFC_SLI_REV4) { + byte_count = pmb->u.mqe.un.mb_words[5]; + mp = (struct lpfc_dmabuf *) pmb->context2; + if (byte_count > sizeof(struct static_vport_info) - + offset) + byte_count = sizeof(struct static_vport_info) + - offset; + memcpy(vport_buff + offset, mp->virt, byte_count); + offset += byte_count; + } else { + if (mb->un.varDmp.word_cnt > + sizeof(struct static_vport_info) - offset) + mb->un.varDmp.word_cnt = + sizeof(struct static_vport_info) + - offset; + byte_count = mb->un.varDmp.word_cnt; + lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET, + vport_buff + offset, + byte_count); + + offset += byte_count; + } - } while (mb->un.varDmp.word_cnt && + } while (byte_count && offset < sizeof(struct static_vport_info)); @@ -2336,16 +2411,15 @@ lpfc_create_static_vport(struct lpfc_hba *phba) } out: - /* - * If this is timed out command, setting NULL to context2 tell SLI - * layer not to use this buffer. - */ - spin_lock_irq(&phba->hbalock); - pmb->context2 = NULL; - spin_unlock_irq(&phba->hbalock); kfree(vport_info); - if (rc != MBX_TIMEOUT) + if (rc != MBX_TIMEOUT) { + if (pmb->context2) { + mp = (struct lpfc_dmabuf *) pmb->context2; + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + } mempool_free(pmb, phba->mbox_mem_pool); + } return; } diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index a7f32ed256b..18bc5905c44 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -2155,6 +2155,8 @@ lpfc_online(struct lpfc_hba *phba) vports[i]->fc_flag &= ~FC_OFFLINE_MODE; if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + if (phba->sli_rev == LPFC_SLI_REV4) + vports[i]->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; spin_unlock_irq(shost->host_lock); } lpfc_destroy_vport_work_array(phba, vports); @@ -7371,6 +7373,9 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) /* Perform post initialization setup */ lpfc_post_init_setup(phba); + /* Check if there are static vports to be created. */ + lpfc_create_static_vport(phba); + return 0; out_disable_intr: diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 245945f2f3a..a776f86bbcc 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -52,30 +52,51 @@ * This routine prepares the mailbox command for dumping list of static * vports to be created. **/ -void +int lpfc_dump_static_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, uint16_t offset) { MAILBOX_t *mb; - void *ctx; + struct lpfc_dmabuf *mp; mb = &pmb->u.mb; - ctx = pmb->context2; /* Setup to dump vport info region */ memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); mb->mbxCommand = MBX_DUMP_MEMORY; - mb->un.varDmp.cv = 1; mb->un.varDmp.type = DMP_NV_PARAMS; mb->un.varDmp.entry_index = offset; mb->un.varDmp.region_id = DMP_REGION_VPORT; - mb->un.varDmp.word_cnt = DMP_RSP_SIZE/sizeof(uint32_t); - mb->un.varDmp.co = 0; - mb->un.varDmp.resp_offset = 0; - pmb->context2 = ctx; mb->mbxOwner = OWN_HOST; - return; + /* For SLI3 HBAs data is embedded in mailbox */ + if (phba->sli_rev != LPFC_SLI_REV4) { + mb->un.varDmp.cv = 1; + mb->un.varDmp.word_cnt = DMP_RSP_SIZE/sizeof(uint32_t); + return 0; + } + + /* For SLI4 HBAs driver need to allocate memory */ + mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (mp) + mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); + + if (!mp || !mp->virt) { + kfree(mp); + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + "2605 lpfc_dump_static_vport: memory" + " allocation failed\n"); + return 1; + } + memset(mp->virt, 0, LPFC_BPL_SIZE); + INIT_LIST_HEAD(&mp->list); + /* save address for completion */ + pmb->context2 = (uint8_t *) mp; + mb->un.varWords[3] = putPaddrLow(mp->phys); + mb->un.varWords[4] = putPaddrHigh(mp->phys); + mb->un.varDmp.sli4_length = sizeof(struct static_vport_info); + + return 0; } /** @@ -1805,6 +1826,7 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys) /** * lpfc_init_vpi - Initialize the INIT_VPI mailbox command + * @phba: pointer to the hba structure to init the VPI for. * @mbox: pointer to lpfc mbox command to initialize. * @vpi: VPI to be initialized. * @@ -1815,11 +1837,14 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys) * successful virtual NPort login. **/ void -lpfc_init_vpi(struct lpfcMboxq *mbox, uint16_t vpi) +lpfc_init_vpi(struct lpfc_hba *phba, struct lpfcMboxq *mbox, uint16_t vpi) { memset(mbox, 0, sizeof(*mbox)); bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_INIT_VPI); - bf_set(lpfc_init_vpi_vpi, &mbox->u.mqe.un.init_vpi, vpi); + bf_set(lpfc_init_vpi_vpi, &mbox->u.mqe.un.init_vpi, + vpi + phba->vpi_base); + bf_set(lpfc_init_vpi_vfi, &mbox->u.mqe.un.init_vpi, + phba->pport->vfi + phba->vfi_base); } /** diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index a0f973e7acb..62f98b343b8 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -11341,7 +11341,7 @@ lpfc_sli4_init_vpi(struct lpfc_hba *phba, uint16_t vpi) mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) return -ENOMEM; - lpfc_init_vpi(mboxq, vpi); + lpfc_init_vpi(phba, mboxq, vpi); mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_INIT_VPI); rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo); if (rc != MBX_TIMEOUT) diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index e0b49922193..9ba2a01c0e3 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -313,22 +313,6 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) goto error_out; } - /* - * In SLI4, the vpi must be activated before it can be used - * by the port. - */ - if (phba->sli_rev == LPFC_SLI_REV4) { - rc = lpfc_sli4_init_vpi(phba, vpi); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, - "1838 Failed to INIT_VPI on vpi %d " - "status %d\n", vpi, rc); - rc = VPORT_NORESOURCES; - lpfc_free_vpi(phba, vpi); - goto error_out; - } - } - /* Assign an unused board number */ if ((instance = lpfc_get_instance()) < 0) { lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, @@ -367,12 +351,8 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) goto error_out; } - memcpy(vport->fc_portname.u.wwn, vport->fc_sparam.portName.u.wwn, 8); - memcpy(vport->fc_nodename.u.wwn, vport->fc_sparam.nodeName.u.wwn, 8); - if (fc_vport->node_name != 0) - u64_to_wwn(fc_vport->node_name, vport->fc_nodename.u.wwn); - if (fc_vport->port_name != 0) - u64_to_wwn(fc_vport->port_name, vport->fc_portname.u.wwn); + u64_to_wwn(fc_vport->node_name, vport->fc_nodename.u.wwn); + u64_to_wwn(fc_vport->port_name, vport->fc_portname.u.wwn); memcpy(&vport->fc_sparam.portName, vport->fc_portname.u.wwn, 8); memcpy(&vport->fc_sparam.nodeName, vport->fc_nodename.u.wwn, 8); @@ -404,7 +384,34 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) *(struct lpfc_vport **)fc_vport->dd_data = vport; vport->fc_vport = fc_vport; + /* + * In SLI4, the vpi must be activated before it can be used + * by the port. + */ + if ((phba->sli_rev == LPFC_SLI_REV4) && + (pport->vfi_state & LPFC_VFI_REGISTERED)) { + rc = lpfc_sli4_init_vpi(phba, vpi); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, + "1838 Failed to INIT_VPI on vpi %d " + "status %d\n", vpi, rc); + rc = VPORT_NORESOURCES; + lpfc_free_vpi(phba, vpi); + goto error_out; + } + } else if (phba->sli_rev == LPFC_SLI_REV4) { + /* + * Driver cannot INIT_VPI now. Set the flags to + * init_vpi when reg_vfi complete. + */ + vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; + lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN); + rc = VPORT_OK; + goto out; + } + if ((phba->link_state < LPFC_LINK_UP) || + (pport->port_state < LPFC_FABRIC_CFG_LINK) || (phba->fc_topology == TOPOLOGY_LOOP)) { lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN); rc = VPORT_OK; -- cgit v1.2.3-18-g5258 From f1c3b0fcbb8104dac92d65d5016500a09beea287 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sun, 19 Jul 2009 10:01:32 -0400 Subject: [SCSI] lpfc 8.3.4: Add bsg (SGIOv4) support for ELS/CT support Add bsg (SGIOv4) support for sending and receiving ELS, CT commands This patch adds a new file, lpfc_bsg.c. Signed-off-by: James Smart Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/lpfc/Makefile | 2 +- drivers/scsi/lpfc/lpfc.h | 11 + drivers/scsi/lpfc/lpfc_attr.c | 3 + drivers/scsi/lpfc/lpfc_bsg.c | 904 ++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/lpfc/lpfc_crtn.h | 8 + drivers/scsi/lpfc/lpfc_ct.c | 2 + drivers/scsi/lpfc/lpfc_els.c | 2 +- drivers/scsi/lpfc/lpfc_init.c | 3 + drivers/scsi/lpfc/lpfc_nl.h | 20 + drivers/scsi/lpfc/lpfc_scsi.c | 1 + 10 files changed, 954 insertions(+), 2 deletions(-) create mode 100644 drivers/scsi/lpfc/lpfc_bsg.c (limited to 'drivers') diff --git a/drivers/scsi/lpfc/Makefile b/drivers/scsi/lpfc/Makefile index 1c286707dd5..ad05d6edb8f 100644 --- a/drivers/scsi/lpfc/Makefile +++ b/drivers/scsi/lpfc/Makefile @@ -28,4 +28,4 @@ obj-$(CONFIG_SCSI_LPFC) := lpfc.o lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o lpfc_hbadisc.o \ lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o lpfc_scsi.o lpfc_attr.o \ - lpfc_vport.o lpfc_debugfs.o + lpfc_vport.o lpfc_debugfs.o lpfc_bsg.o diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 8cca3619c74..aa10f795163 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -441,6 +441,12 @@ enum intr_type_t { MSIX, }; +struct unsol_rcv_ct_ctx { + uint32_t ctxt_id; + uint32_t SID; + uint32_t oxid; +}; + struct lpfc_hba { /* SCSI interface function jump table entries */ int (*lpfc_new_scsi_buf) @@ -776,6 +782,11 @@ struct lpfc_hba { uint8_t valid_vlan; uint16_t vlan_id; struct list_head fcf_conn_rec_list; + + struct mutex ct_event_mutex; /* synchronize access to ct_ev_waiters */ + struct list_head ct_ev_waiters; + struct unsol_rcv_ct_ctx ct_ctx[64]; + uint32_t ctx_idx; }; static inline struct Scsi_Host * diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 7a629511338..e1a30a16a9f 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -4132,6 +4132,9 @@ struct fc_function_template lpfc_transport_functions = { .vport_disable = lpfc_vport_disable, .set_vport_symbolic_name = lpfc_set_vport_symbolic_name, + + .bsg_request = lpfc_bsg_request, + .bsg_timeout = lpfc_bsg_timeout, }; struct fc_function_template lpfc_vport_transport_functions = { diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c new file mode 100644 index 00000000000..da6bf5aac9d --- /dev/null +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -0,0 +1,904 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * + * Copyright (C) 2009 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * + * www.emulex.com * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of version 2 of the GNU General * + * Public License as published by the Free Software Foundation. * + * This program is distributed in the hope that it will be useful. * + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * + * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * + * TO BE LEGALLY INVALID. See the GNU General Public License for * + * more details, a copy of which can be found in the file COPYING * + * included with this package. * + *******************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include + +#include "lpfc_hw4.h" +#include "lpfc_hw.h" +#include "lpfc_sli.h" +#include "lpfc_sli4.h" +#include "lpfc_nl.h" +#include "lpfc_disc.h" +#include "lpfc_scsi.h" +#include "lpfc.h" +#include "lpfc_logmsg.h" +#include "lpfc_crtn.h" +#include "lpfc_vport.h" +#include "lpfc_version.h" + +/** + * lpfc_bsg_rport_ct - send a CT command from a bsg request + * @job: fc_bsg_job to handle + */ +static int +lpfc_bsg_rport_ct(struct fc_bsg_job *job) +{ + struct Scsi_Host *shost = job->shost; + struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct lpfc_rport_data *rdata = job->rport->dd_data; + struct lpfc_nodelist *ndlp = rdata->pnode; + struct ulp_bde64 *bpl = NULL; + uint32_t timeout; + struct lpfc_iocbq *cmdiocbq = NULL; + struct lpfc_iocbq *rspiocbq = NULL; + IOCB_t *cmd; + IOCB_t *rsp; + struct lpfc_dmabuf *bmp = NULL; + int request_nseg; + int reply_nseg; + struct scatterlist *sgel = NULL; + int numbde; + dma_addr_t busaddr; + int rc = 0; + + /* in case no data is transferred */ + job->reply->reply_payload_rcv_len = 0; + + if (!lpfc_nlp_get(ndlp)) { + job->reply->result = -ENODEV; + return 0; + } + + if (ndlp->nlp_flag & NLP_ELS_SND_MASK) { + rc = -ENODEV; + goto free_ndlp_exit; + } + + spin_lock_irq(shost->host_lock); + cmdiocbq = lpfc_sli_get_iocbq(phba); + if (!cmdiocbq) { + rc = -ENOMEM; + spin_unlock_irq(shost->host_lock); + goto free_ndlp_exit; + } + cmd = &cmdiocbq->iocb; + + rspiocbq = lpfc_sli_get_iocbq(phba); + if (!rspiocbq) { + rc = -ENOMEM; + goto free_cmdiocbq; + } + spin_unlock_irq(shost->host_lock); + + rsp = &rspiocbq->iocb; + + bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (!bmp) { + rc = -ENOMEM; + spin_lock_irq(shost->host_lock); + goto free_rspiocbq; + } + + spin_lock_irq(shost->host_lock); + bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); + if (!bmp->virt) { + rc = -ENOMEM; + goto free_bmp; + } + spin_unlock_irq(shost->host_lock); + + INIT_LIST_HEAD(&bmp->list); + bpl = (struct ulp_bde64 *) bmp->virt; + + request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, + job->request_payload.sg_cnt, DMA_TO_DEVICE); + for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { + busaddr = sg_dma_address(sgel); + bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; + bpl->tus.f.bdeSize = sg_dma_len(sgel); + bpl->tus.w = cpu_to_le32(bpl->tus.w); + bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); + bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); + bpl++; + } + + reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list, + job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) { + busaddr = sg_dma_address(sgel); + bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; + bpl->tus.f.bdeSize = sg_dma_len(sgel); + bpl->tus.w = cpu_to_le32(bpl->tus.w); + bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); + bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); + bpl++; + } + + cmd->un.genreq64.bdl.ulpIoTag32 = 0; + cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); + cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); + cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; + cmd->un.genreq64.bdl.bdeSize = + (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); + cmd->ulpCommand = CMD_GEN_REQUEST64_CR; + cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); + cmd->un.genreq64.w5.hcsw.Dfctl = 0; + cmd->un.genreq64.w5.hcsw.Rctl = FC_UNSOL_CTL; + cmd->un.genreq64.w5.hcsw.Type = FC_COMMON_TRANSPORT_ULP; + cmd->ulpBdeCount = 1; + cmd->ulpLe = 1; + cmd->ulpClass = CLASS3; + cmd->ulpContext = ndlp->nlp_rpi; + cmd->ulpOwner = OWN_CHIP; + cmdiocbq->vport = phba->pport; + cmdiocbq->context1 = NULL; + cmdiocbq->context2 = NULL; + cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; + + timeout = phba->fc_ratov * 2; + job->dd_data = cmdiocbq; + + rc = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, rspiocbq, + timeout + LPFC_DRVR_TIMEOUT); + + if (rc != IOCB_TIMEDOUT) { + pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, + job->request_payload.sg_cnt, DMA_TO_DEVICE); + pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, + job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + } + + if (rc == IOCB_TIMEDOUT) { + lpfc_sli_release_iocbq(phba, rspiocbq); + rc = -EACCES; + goto free_ndlp_exit; + } + + if (rc != IOCB_SUCCESS) { + rc = -EACCES; + goto free_outdmp; + } + + if (rsp->ulpStatus) { + if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { + switch (rsp->un.ulpWord[4] & 0xff) { + case IOERR_SEQUENCE_TIMEOUT: + rc = -ETIMEDOUT; + break; + case IOERR_INVALID_RPI: + rc = -EFAULT; + break; + default: + rc = -EACCES; + break; + } + goto free_outdmp; + } + } else + job->reply->reply_payload_rcv_len = + rsp->un.genreq64.bdl.bdeSize; + +free_outdmp: + spin_lock_irq(shost->host_lock); + lpfc_mbuf_free(phba, bmp->virt, bmp->phys); +free_bmp: + kfree(bmp); +free_rspiocbq: + lpfc_sli_release_iocbq(phba, rspiocbq); +free_cmdiocbq: + lpfc_sli_release_iocbq(phba, cmdiocbq); + spin_unlock_irq(shost->host_lock); +free_ndlp_exit: + lpfc_nlp_put(ndlp); + + /* make error code available to userspace */ + job->reply->result = rc; + /* complete the job back to userspace */ + job->job_done(job); + + return 0; +} + +/** + * lpfc_bsg_rport_els - send an ELS command from a bsg request + * @job: fc_bsg_job to handle + */ +static int +lpfc_bsg_rport_els(struct fc_bsg_job *job) +{ + struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct lpfc_rport_data *rdata = job->rport->dd_data; + struct lpfc_nodelist *ndlp = rdata->pnode; + + uint32_t elscmd; + uint32_t cmdsize; + uint32_t rspsize; + struct lpfc_iocbq *rspiocbq; + struct lpfc_iocbq *cmdiocbq; + IOCB_t *rsp; + uint16_t rpi = 0; + struct lpfc_dmabuf *pcmd; + struct lpfc_dmabuf *prsp; + struct lpfc_dmabuf *pbuflist = NULL; + struct ulp_bde64 *bpl; + int iocb_status; + int request_nseg; + int reply_nseg; + struct scatterlist *sgel = NULL; + int numbde; + dma_addr_t busaddr; + int rc = 0; + + /* in case no data is transferred */ + job->reply->reply_payload_rcv_len = 0; + + if (!lpfc_nlp_get(ndlp)) { + rc = -ENODEV; + goto out; + } + + elscmd = job->request->rqst_data.r_els.els_code; + cmdsize = job->request_payload.payload_len; + rspsize = job->reply_payload.payload_len; + rspiocbq = lpfc_sli_get_iocbq(phba); + if (!rspiocbq) { + lpfc_nlp_put(ndlp); + rc = -ENOMEM; + goto out; + } + + rsp = &rspiocbq->iocb; + rpi = ndlp->nlp_rpi; + + cmdiocbq = lpfc_prep_els_iocb(phba->pport, 1, cmdsize, 0, ndlp, + ndlp->nlp_DID, elscmd); + + if (!cmdiocbq) { + lpfc_sli_release_iocbq(phba, rspiocbq); + return -EIO; + } + + job->dd_data = cmdiocbq; + pcmd = (struct lpfc_dmabuf *) cmdiocbq->context2; + prsp = (struct lpfc_dmabuf *) pcmd->list.next; + + lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); + kfree(pcmd); + lpfc_mbuf_free(phba, prsp->virt, prsp->phys); + kfree(prsp); + cmdiocbq->context2 = NULL; + + pbuflist = (struct lpfc_dmabuf *) cmdiocbq->context3; + bpl = (struct ulp_bde64 *) pbuflist->virt; + + request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, + job->request_payload.sg_cnt, DMA_TO_DEVICE); + + for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { + busaddr = sg_dma_address(sgel); + bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; + bpl->tus.f.bdeSize = sg_dma_len(sgel); + bpl->tus.w = cpu_to_le32(bpl->tus.w); + bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); + bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); + bpl++; + } + + reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list, + job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) { + busaddr = sg_dma_address(sgel); + bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; + bpl->tus.f.bdeSize = sg_dma_len(sgel); + bpl->tus.w = cpu_to_le32(bpl->tus.w); + bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); + bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); + bpl++; + } + + cmdiocbq->iocb.un.elsreq64.bdl.bdeSize = + (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); + cmdiocbq->iocb.ulpContext = rpi; + cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; + cmdiocbq->context1 = NULL; + cmdiocbq->context2 = NULL; + + iocb_status = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, + rspiocbq, (phba->fc_ratov * 2) + + LPFC_DRVR_TIMEOUT); + + /* release the new ndlp once the iocb completes */ + lpfc_nlp_put(ndlp); + if (iocb_status != IOCB_TIMEDOUT) { + pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, + job->request_payload.sg_cnt, DMA_TO_DEVICE); + pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, + job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + } + + if (iocb_status == IOCB_SUCCESS) { + if (rsp->ulpStatus == IOSTAT_SUCCESS) { + job->reply->reply_payload_rcv_len = + rsp->un.elsreq64.bdl.bdeSize; + rc = 0; + } else if (rsp->ulpStatus == IOSTAT_LS_RJT) { + struct fc_bsg_ctels_reply *els_reply; + /* LS_RJT data returned in word 4 */ + uint8_t *rjt_data = (uint8_t *)&rsp->un.ulpWord[4]; + + els_reply = &job->reply->reply_data.ctels_reply; + job->reply->result = 0; + els_reply->status = FC_CTELS_STATUS_REJECT; + els_reply->rjt_data.action = rjt_data[0]; + els_reply->rjt_data.reason_code = rjt_data[1]; + els_reply->rjt_data.reason_explanation = rjt_data[2]; + els_reply->rjt_data.vendor_unique = rjt_data[3]; + } else + rc = -EIO; + } else + rc = -EIO; + + if (iocb_status != IOCB_TIMEDOUT) + lpfc_els_free_iocb(phba, cmdiocbq); + + lpfc_sli_release_iocbq(phba, rspiocbq); + +out: + /* make error code available to userspace */ + job->reply->result = rc; + /* complete the job back to userspace */ + job->job_done(job); + + return 0; +} + +struct lpfc_ct_event { + struct list_head node; + int ref; + wait_queue_head_t wq; + + /* Event type and waiter identifiers */ + uint32_t type_mask; + uint32_t req_id; + uint32_t reg_id; + + /* next two flags are here for the auto-delete logic */ + unsigned long wait_time_stamp; + int waiting; + + /* seen and not seen events */ + struct list_head events_to_get; + struct list_head events_to_see; +}; + +struct event_data { + struct list_head node; + uint32_t type; + uint32_t immed_dat; + void *data; + uint32_t len; +}; + +static struct lpfc_ct_event * +lpfc_ct_event_new(int ev_reg_id, uint32_t ev_req_id) +{ + struct lpfc_ct_event *evt = kzalloc(sizeof(*evt), GFP_KERNEL); + if (!evt) + return NULL; + + INIT_LIST_HEAD(&evt->events_to_get); + INIT_LIST_HEAD(&evt->events_to_see); + evt->req_id = ev_req_id; + evt->reg_id = ev_reg_id; + evt->wait_time_stamp = jiffies; + init_waitqueue_head(&evt->wq); + + return evt; +} + +static void +lpfc_ct_event_free(struct lpfc_ct_event *evt) +{ + struct event_data *ed; + + list_del(&evt->node); + + while (!list_empty(&evt->events_to_get)) { + ed = list_entry(evt->events_to_get.next, typeof(*ed), node); + list_del(&ed->node); + kfree(ed->data); + kfree(ed); + } + + while (!list_empty(&evt->events_to_see)) { + ed = list_entry(evt->events_to_see.next, typeof(*ed), node); + list_del(&ed->node); + kfree(ed->data); + kfree(ed); + } + + kfree(evt); +} + +static inline void +lpfc_ct_event_ref(struct lpfc_ct_event *evt) +{ + evt->ref++; +} + +static inline void +lpfc_ct_event_unref(struct lpfc_ct_event *evt) +{ + if (--evt->ref < 0) + lpfc_ct_event_free(evt); +} + +#define SLI_CT_ELX_LOOPBACK 0x10 + +enum ELX_LOOPBACK_CMD { + ELX_LOOPBACK_XRI_SETUP, + ELX_LOOPBACK_DATA, +}; + +/** + * lpfc_bsg_ct_unsol_event - process an unsolicited CT command + * @phba: + * @pring: + * @piocbq: + * + * This function is called when an unsolicited CT command is received. It + * forwards the event to any processes registerd to receive CT events. + */ +void +lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + struct lpfc_iocbq *piocbq) +{ + uint32_t evt_req_id = 0; + uint32_t cmd; + uint32_t len; + struct lpfc_dmabuf *dmabuf = NULL; + struct lpfc_ct_event *evt; + struct event_data *evt_dat = NULL; + struct lpfc_iocbq *iocbq; + size_t offset = 0; + struct list_head head; + struct ulp_bde64 *bde; + dma_addr_t dma_addr; + int i; + struct lpfc_dmabuf *bdeBuf1 = piocbq->context2; + struct lpfc_dmabuf *bdeBuf2 = piocbq->context3; + struct lpfc_hbq_entry *hbqe; + struct lpfc_sli_ct_request *ct_req; + + INIT_LIST_HEAD(&head); + list_add_tail(&head, &piocbq->list); + + if (piocbq->iocb.ulpBdeCount == 0 || + piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0) + goto error_ct_unsol_exit; + + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) + dmabuf = bdeBuf1; + else { + dma_addr = getPaddr(piocbq->iocb.un.cont64[0].addrHigh, + piocbq->iocb.un.cont64[0].addrLow); + dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, dma_addr); + } + + ct_req = (struct lpfc_sli_ct_request *)dmabuf->virt; + evt_req_id = ct_req->FsType; + cmd = ct_req->CommandResponse.bits.CmdRsp; + len = ct_req->CommandResponse.bits.Size; + if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) + lpfc_sli_ringpostbuf_put(phba, pring, dmabuf); + + mutex_lock(&phba->ct_event_mutex); + list_for_each_entry(evt, &phba->ct_ev_waiters, node) { + if (evt->req_id != evt_req_id) + continue; + + lpfc_ct_event_ref(evt); + + evt_dat = kzalloc(sizeof(*evt_dat), GFP_KERNEL); + if (!evt_dat) { + lpfc_ct_event_unref(evt); + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2614 Memory allocation failed for " + "CT event\n"); + break; + } + + mutex_unlock(&phba->ct_event_mutex); + + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { + /* take accumulated byte count from the last iocbq */ + iocbq = list_entry(head.prev, typeof(*iocbq), list); + evt_dat->len = iocbq->iocb.unsli3.rcvsli3.acc_len; + } else { + list_for_each_entry(iocbq, &head, list) { + for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) + evt_dat->len += + iocbq->iocb.un.cont64[i].tus.f.bdeSize; + } + } + + evt_dat->data = kzalloc(evt_dat->len, GFP_KERNEL); + if (!evt_dat->data) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2615 Memory allocation failed for " + "CT event data, size %d\n", + evt_dat->len); + kfree(evt_dat); + mutex_lock(&phba->ct_event_mutex); + lpfc_ct_event_unref(evt); + mutex_unlock(&phba->ct_event_mutex); + goto error_ct_unsol_exit; + } + + list_for_each_entry(iocbq, &head, list) { + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { + bdeBuf1 = iocbq->context2; + bdeBuf2 = iocbq->context3; + } + for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) { + int size = 0; + if (phba->sli3_options & + LPFC_SLI3_HBQ_ENABLED) { + if (i == 0) { + hbqe = (struct lpfc_hbq_entry *) + &iocbq->iocb.un.ulpWord[0]; + size = hbqe->bde.tus.f.bdeSize; + dmabuf = bdeBuf1; + } else if (i == 1) { + hbqe = (struct lpfc_hbq_entry *) + &iocbq->iocb.unsli3. + sli3Words[4]; + size = hbqe->bde.tus.f.bdeSize; + dmabuf = bdeBuf2; + } + if ((offset + size) > evt_dat->len) + size = evt_dat->len - offset; + } else { + size = iocbq->iocb.un.cont64[i]. + tus.f.bdeSize; + bde = &iocbq->iocb.un.cont64[i]; + dma_addr = getPaddr(bde->addrHigh, + bde->addrLow); + dmabuf = lpfc_sli_ringpostbuf_get(phba, + pring, dma_addr); + } + if (!dmabuf) { + lpfc_printf_log(phba, KERN_ERR, + LOG_LIBDFC, "2616 No dmabuf " + "found for iocbq 0x%p\n", + iocbq); + kfree(evt_dat->data); + kfree(evt_dat); + mutex_lock(&phba->ct_event_mutex); + lpfc_ct_event_unref(evt); + mutex_unlock(&phba->ct_event_mutex); + goto error_ct_unsol_exit; + } + memcpy((char *)(evt_dat->data) + offset, + dmabuf->virt, size); + offset += size; + if (evt_req_id != SLI_CT_ELX_LOOPBACK && + !(phba->sli3_options & + LPFC_SLI3_HBQ_ENABLED)) { + lpfc_sli_ringpostbuf_put(phba, pring, + dmabuf); + } else { + switch (cmd) { + case ELX_LOOPBACK_XRI_SETUP: + if (!(phba->sli3_options & + LPFC_SLI3_HBQ_ENABLED)) + lpfc_post_buffer(phba, + pring, + 1); + else + lpfc_in_buf_free(phba, + dmabuf); + break; + default: + if (!(phba->sli3_options & + LPFC_SLI3_HBQ_ENABLED)) + lpfc_post_buffer(phba, + pring, + 1); + break; + } + } + } + } + + mutex_lock(&phba->ct_event_mutex); + if (phba->sli_rev == LPFC_SLI_REV4) { + evt_dat->immed_dat = phba->ctx_idx; + phba->ctx_idx = (phba->ctx_idx + 1) % 64; + phba->ct_ctx[evt_dat->immed_dat].oxid = + piocbq->iocb.ulpContext; + phba->ct_ctx[evt_dat->immed_dat].SID = + piocbq->iocb.un.rcvels.remoteID; + } else + evt_dat->immed_dat = piocbq->iocb.ulpContext; + + evt_dat->type = FC_REG_CT_EVENT; + list_add(&evt_dat->node, &evt->events_to_see); + wake_up_interruptible(&evt->wq); + lpfc_ct_event_unref(evt); + if (evt_req_id == SLI_CT_ELX_LOOPBACK) + break; + } + mutex_unlock(&phba->ct_event_mutex); + +error_ct_unsol_exit: + if (!list_empty(&head)) + list_del(&head); + + return; +} + +/** + * lpfc_bsg_set_event - process a SET_EVENT bsg vendor command + * @job: SET_EVENT fc_bsg_job + */ +static int +lpfc_bsg_set_event(struct fc_bsg_job *job) +{ + struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct set_ct_event *event_req; + struct lpfc_ct_event *evt; + int rc = 0; + + if (job->request_len < + sizeof(struct fc_bsg_request) + sizeof(struct set_ct_event)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2612 Received SET_CT_EVENT below minimum " + "size\n"); + return -EINVAL; + } + + event_req = (struct set_ct_event *) + job->request->rqst_data.h_vendor.vendor_cmd; + + mutex_lock(&phba->ct_event_mutex); + list_for_each_entry(evt, &phba->ct_ev_waiters, node) { + if (evt->reg_id == event_req->ev_reg_id) { + lpfc_ct_event_ref(evt); + evt->wait_time_stamp = jiffies; + break; + } + } + mutex_unlock(&phba->ct_event_mutex); + + if (&evt->node == &phba->ct_ev_waiters) { + /* no event waiting struct yet - first call */ + evt = lpfc_ct_event_new(event_req->ev_reg_id, + event_req->ev_req_id); + if (!evt) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2617 Failed allocation of event " + "waiter\n"); + return -ENOMEM; + } + + mutex_lock(&phba->ct_event_mutex); + list_add(&evt->node, &phba->ct_ev_waiters); + lpfc_ct_event_ref(evt); + mutex_unlock(&phba->ct_event_mutex); + } + + evt->waiting = 1; + if (wait_event_interruptible(evt->wq, + !list_empty(&evt->events_to_see))) { + mutex_lock(&phba->ct_event_mutex); + lpfc_ct_event_unref(evt); /* release ref */ + lpfc_ct_event_unref(evt); /* delete */ + mutex_unlock(&phba->ct_event_mutex); + rc = -EINTR; + goto set_event_out; + } + + evt->wait_time_stamp = jiffies; + evt->waiting = 0; + + mutex_lock(&phba->ct_event_mutex); + list_move(evt->events_to_see.prev, &evt->events_to_get); + lpfc_ct_event_unref(evt); /* release ref */ + mutex_unlock(&phba->ct_event_mutex); + +set_event_out: + /* set_event carries no reply payload */ + job->reply->reply_payload_rcv_len = 0; + /* make error code available to userspace */ + job->reply->result = rc; + /* complete the job back to userspace */ + job->job_done(job); + + return 0; +} + +/** + * lpfc_bsg_get_event - process a GET_EVENT bsg vendor command + * @job: GET_EVENT fc_bsg_job + */ +static int +lpfc_bsg_get_event(struct fc_bsg_job *job) +{ + struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct get_ct_event *event_req; + struct get_ct_event_reply *event_reply; + struct lpfc_ct_event *evt; + struct event_data *evt_dat = NULL; + int rc = 0; + + if (job->request_len < + sizeof(struct fc_bsg_request) + sizeof(struct get_ct_event)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2613 Received GET_CT_EVENT request below " + "minimum size\n"); + return -EINVAL; + } + + event_req = (struct get_ct_event *) + job->request->rqst_data.h_vendor.vendor_cmd; + + event_reply = (struct get_ct_event_reply *) + job->reply->reply_data.vendor_reply.vendor_rsp; + + mutex_lock(&phba->ct_event_mutex); + list_for_each_entry(evt, &phba->ct_ev_waiters, node) { + if (evt->reg_id == event_req->ev_reg_id) { + if (list_empty(&evt->events_to_get)) + break; + lpfc_ct_event_ref(evt); + evt->wait_time_stamp = jiffies; + evt_dat = list_entry(evt->events_to_get.prev, + struct event_data, node); + list_del(&evt_dat->node); + break; + } + } + mutex_unlock(&phba->ct_event_mutex); + + if (!evt_dat) { + job->reply->reply_payload_rcv_len = 0; + rc = -ENOENT; + goto error_get_event_exit; + } + + if (evt_dat->len > job->reply_payload.payload_len) { + evt_dat->len = job->reply_payload.payload_len; + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "2618 Truncated event data at %d " + "bytes\n", + job->reply_payload.payload_len); + } + + event_reply->immed_data = evt_dat->immed_dat; + + if (evt_dat->len > 0) + job->reply->reply_payload_rcv_len = + sg_copy_from_buffer(job->reply_payload.sg_list, + job->reply_payload.sg_cnt, + evt_dat->data, evt_dat->len); + else + job->reply->reply_payload_rcv_len = 0; + rc = 0; + + if (evt_dat) + kfree(evt_dat->data); + kfree(evt_dat); + mutex_lock(&phba->ct_event_mutex); + lpfc_ct_event_unref(evt); + mutex_unlock(&phba->ct_event_mutex); + +error_get_event_exit: + /* make error code available to userspace */ + job->reply->result = rc; + /* complete the job back to userspace */ + job->job_done(job); + + return rc; +} + +/** + * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job + * @job: fc_bsg_job to handle + */ +static int +lpfc_bsg_hst_vendor(struct fc_bsg_job *job) +{ + int command = job->request->rqst_data.h_vendor.vendor_cmd[0]; + + switch (command) { + case LPFC_BSG_VENDOR_SET_CT_EVENT: + return lpfc_bsg_set_event(job); + break; + + case LPFC_BSG_VENDOR_GET_CT_EVENT: + return lpfc_bsg_get_event(job); + break; + + default: + return -EINVAL; + } +} + +/** + * lpfc_bsg_request - handle a bsg request from the FC transport + * @job: fc_bsg_job to handle + */ +int +lpfc_bsg_request(struct fc_bsg_job *job) +{ + uint32_t msgcode; + int rc = -EINVAL; + + msgcode = job->request->msgcode; + + switch (msgcode) { + case FC_BSG_HST_VENDOR: + rc = lpfc_bsg_hst_vendor(job); + break; + case FC_BSG_RPT_ELS: + rc = lpfc_bsg_rport_els(job); + break; + case FC_BSG_RPT_CT: + rc = lpfc_bsg_rport_ct(job); + break; + default: + break; + } + + return rc; +} + +/** + * lpfc_bsg_timeout - handle timeout of a bsg request from the FC transport + * @job: fc_bsg_job that has timed out + * + * This function just aborts the job's IOCB. The aborted IOCB will return to + * the waiting function which will handle passing the error back to userspace + */ +int +lpfc_bsg_timeout(struct fc_bsg_job *job) +{ + struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *)job->dd_data; + struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; + + if (cmdiocb) + lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb); + + return 0; +} diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 48943d34414..0830f37409a 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -137,6 +137,9 @@ int lpfc_els_disc_adisc(struct lpfc_vport *); int lpfc_els_disc_plogi(struct lpfc_vport *); void lpfc_els_timeout(unsigned long); void lpfc_els_timeout_handler(struct lpfc_vport *); +struct lpfc_iocbq *lpfc_prep_els_iocb(struct lpfc_vport *, uint8_t, uint16_t, + uint8_t, struct lpfc_nodelist *, + uint32_t, uint32_t); void lpfc_hb_timeout_handler(struct lpfc_hba *); void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, @@ -364,3 +367,8 @@ void lpfc_start_fdiscs(struct lpfc_hba *phba); #define HBA_EVENT_LINK_UP 2 #define HBA_EVENT_LINK_DOWN 3 +/* functions to support SGIOv4/bsg interface */ +int lpfc_bsg_request(struct fc_bsg_job *); +int lpfc_bsg_timeout(struct fc_bsg_job *); +void lpfc_bsg_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, + struct lpfc_iocbq *); diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 0e532f072eb..9df7ed38e1b 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -97,6 +97,8 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct list_head head; struct lpfc_dmabuf *bdeBuf; + lpfc_bsg_ct_unsol_event(phba, pring, piocbq); + if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) { lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); } else if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) && diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index f72fdf23bf1..45337cd23fe 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -146,7 +146,7 @@ lpfc_els_chk_latt(struct lpfc_vport *vport) * Pointer to the newly allocated/prepared els iocb data structure * NULL - when els iocb data structure allocation/preparation failed **/ -static struct lpfc_iocbq * +struct lpfc_iocbq * lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, uint16_t cmdSize, uint8_t retry, struct lpfc_nodelist *ndlp, uint32_t did, diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 18bc5905c44..08112e7a834 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -4171,6 +4171,9 @@ lpfc_hba_alloc(struct pci_dev *pdev) return NULL; } + mutex_init(&phba->ct_event_mutex); + INIT_LIST_HEAD(&phba->ct_ev_waiters); + return phba; } diff --git a/drivers/scsi/lpfc/lpfc_nl.h b/drivers/scsi/lpfc/lpfc_nl.h index 27d1a88a98f..d655ed3eebe 100644 --- a/drivers/scsi/lpfc/lpfc_nl.h +++ b/drivers/scsi/lpfc/lpfc_nl.h @@ -177,3 +177,23 @@ struct temp_event { uint32_t data; }; +/* bsg definitions */ +#define LPFC_BSG_VENDOR_SET_CT_EVENT 1 +#define LPFC_BSG_VENDOR_GET_CT_EVENT 2 + +struct set_ct_event { + uint32_t command; + uint32_t ev_req_id; + uint32_t ev_reg_id; +}; + +struct get_ct_event { + uint32_t command; + uint32_t ev_reg_id; + uint32_t ev_req_id; +}; + +struct get_ct_event_reply { + uint32_t immed_data; + uint32_t type; +}; diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index da59c4f0168..6ba2c3bae2a 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -3584,6 +3584,7 @@ struct scsi_host_template lpfc_template = { .use_clustering = ENABLE_CLUSTERING, .shost_attrs = lpfc_hba_attrs, .max_sectors = 0xFFFF, + .vendor_id = LPFC_NL_VENDOR_ID, }; struct scsi_host_template lpfc_vport_template = { -- cgit v1.2.3-18-g5258 From e4e74273c3e8d0dc54ddce4fed27e266927c7ad0 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sun, 19 Jul 2009 10:01:38 -0400 Subject: [SCSI] lpfc 8.3.4: Remove spaces before newlines in several log messages Remove spaces before newlines in several log messages Signed-off-by: James Smart Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_hbadisc.c | 2 +- drivers/scsi/lpfc/lpfc_init.c | 10 +++++----- drivers/scsi/lpfc/lpfc_mbox.c | 2 +- drivers/scsi/lpfc/lpfc_scsi.c | 6 +++--- drivers/scsi/lpfc/lpfc_sli.c | 4 ++-- drivers/scsi/lpfc/lpfc_vport.c | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 491c53fd1ca..e6a47e25b21 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -2402,7 +2402,7 @@ lpfc_create_static_vport(struct lpfc_hba *phba) if (!new_fc_vport) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "0546 lpfc_create_static_vport failed to" - " create vport \n"); + " create vport\n"); continue; } diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 08112e7a834..562d8cee874 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -580,7 +580,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) KERN_ERR, LOG_INIT, "0456 Adapter failed to issue " - "ASYNCEVT_ENABLE mbox status x%x \n.", + "ASYNCEVT_ENABLE mbox status x%x\n", rc); mempool_free(pmb, phba->mbox_mem_pool); } @@ -594,7 +594,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0435 Adapter failed " - "to get Option ROM version status x%x\n.", rc); + "to get Option ROM version status x%x\n", rc); mempool_free(pmb, phba->mbox_mem_pool); } @@ -2923,7 +2923,7 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, switch (event_type) { case LPFC_FCOE_EVENT_TYPE_NEW_FCF: lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "2546 New FCF found index 0x%x tag 0x%x \n", + "2546 New FCF found index 0x%x tag 0x%x\n", acqe_fcoe->fcf_index, acqe_fcoe->event_tag); /* @@ -2949,7 +2949,7 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, case LPFC_FCOE_EVENT_TYPE_FCF_TABLE_FULL: lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2548 FCF Table full count 0x%x tag 0x%x \n", + "2548 FCF Table full count 0x%x tag 0x%x\n", bf_get(lpfc_acqe_fcoe_fcf_count, acqe_fcoe), acqe_fcoe->event_tag); break; @@ -2957,7 +2957,7 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, case LPFC_FCOE_EVENT_TYPE_FCF_DEAD: lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, "2549 FCF disconnected fron network index 0x%x" - " tag 0x%x \n", acqe_fcoe->fcf_index, + " tag 0x%x\n", acqe_fcoe->fcf_index, acqe_fcoe->event_tag); /* If the event is not for currently used fcf do nothing */ if (phba->fcf.fcf_indx != acqe_fcoe->fcf_index) diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index a776f86bbcc..1ab405902a1 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1893,7 +1893,7 @@ lpfc_dump_fcoe_param(struct lpfc_hba *phba, /* dump_fcoe_param failed to allocate memory */ lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, "2569 lpfc_dump_fcoe_param: memory" - " allocation failed \n"); + " allocation failed\n"); return 1; } diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 6ba2c3bae2a..61d08970380 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -2142,7 +2142,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, } else if (resp_info & RESID_OVER) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "9028 FCP command x%x residual overrun error. " - "Data: x%x x%x \n", cmnd->cmnd[0], + "Data: x%x x%x\n", cmnd->cmnd[0], scsi_bufflen(cmnd), scsi_get_resid(cmnd)); host_status = DID_ERROR; @@ -2843,7 +2843,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) dif_op_str[scsi_get_prot_op(cmnd)]); lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9034 BLKGRD: CDB: %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x \n", + "%02x %02x %02x %02x %02x\n", cmnd->cmnd[0], cmnd->cmnd[1], cmnd->cmnd[2], cmnd->cmnd[3], cmnd->cmnd[4], cmnd->cmnd[5], cmnd->cmnd[6], cmnd->cmnd[7], cmnd->cmnd[8], @@ -2871,7 +2871,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) dif_op_str[scsi_get_prot_op(cmnd)]); lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9039 BLKGRD: CDB: %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x \n", + "%02x %02x %02x %02x %02x\n", cmnd->cmnd[0], cmnd->cmnd[1], cmnd->cmnd[2], cmnd->cmnd[3], cmnd->cmnd[4], cmnd->cmnd[5], cmnd->cmnd[6], cmnd->cmnd[7], cmnd->cmnd[8], diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 62f98b343b8..43cbe336f1f 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -4304,7 +4304,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) */ if (lpfc_sli4_read_fcoe_params(phba, mboxq)) lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT, - "2570 Failed to read FCoE parameters \n"); + "2570 Failed to read FCoE parameters\n"); /* Issue READ_REV to collect vpd and FW information. */ vpd_size = PAGE_SIZE; @@ -6326,7 +6326,7 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba, KERN_ERR, LOG_SLI, "0346 Ring %d handler: unexpected ASYNC_STATUS" - " evt_code 0x%x \n" + " evt_code 0x%x\n" "W0 0x%08x W1 0x%08x W2 0x%08x W3 0x%08x\n" "W4 0x%08x W5 0x%08x W6 0x%08x W7 0x%08x\n" "W8 0x%08x W9 0x%08x W10 0x%08x W11 0x%08x\n" diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index 9ba2a01c0e3..606efa76754 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -668,7 +668,7 @@ lpfc_vport_delete(struct fc_vport *fc_vport) lpfc_printf_log(vport->phba, KERN_WARNING, LOG_VPORT, "1829 CT command failed to " - "delete objects on fabric. \n"); + "delete objects on fabric\n"); } /* First look for the Fabric ndlp */ ndlp = lpfc_findnode_did(vport, Fabric_DID); -- cgit v1.2.3-18-g5258 From 7cfbc8d9663c88d11e2c1acd2009f1786e150cf6 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sun, 19 Jul 2009 10:01:44 -0400 Subject: [SCSI] lpfc 8.3.4: Update driver version to 8.3.4 Update driver version to 8.3.4 Signed-off-by: James Smart Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 41094e02304..9ae20af4bdb 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.3.3" +#define LPFC_DRIVER_VERSION "8.3.4" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" -- cgit v1.2.3-18-g5258 From 4643682ba50634db5cd61292711d031630baf233 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 28 Jul 2009 12:30:01 -0400 Subject: [SCSI] fc_transport: Correct max fc_host attribute count Signed-off-by: James Smart Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_fc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 751f239e01e..b98885de687 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -291,7 +291,7 @@ static void fc_scsi_scan_rport(struct work_struct *work); #define FC_STARGET_NUM_ATTRS 3 #define FC_RPORT_NUM_ATTRS 10 #define FC_VPORT_NUM_ATTRS 9 -#define FC_HOST_NUM_ATTRS 21 +#define FC_HOST_NUM_ATTRS 22 struct fc_internal { struct scsi_transport_template t; -- cgit v1.2.3-18-g5258 From a4a8b064dd06d30d007e46445d17575e2875c340 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 28 Jul 2009 16:39:05 +0000 Subject: [SCSI] scsi_transport_sas: fix incorrect duplicate setup of max_phys There are two setup places for max_phys in scsi_transport_sas.c; one incorrectly places a NULL into host_attrs instead of port_attrs. Remove it. Reported-by: Roel Kluin Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_sas.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 0895d3c71b0..fd47cb1bee1 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -1691,10 +1691,6 @@ sas_attach_transport(struct sas_function_template *ft) i->f = ft; - count = 0; - SETUP_PORT_ATTRIBUTE(num_phys); - i->host_attrs[count] = NULL; - count = 0; SETUP_PHY_ATTRIBUTE(initiator_port_protocols); SETUP_PHY_ATTRIBUTE(target_port_protocols); -- cgit v1.2.3-18-g5258 From 3c0d1d94aa516cad50274fe1aa9f745957b67a65 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Tue, 28 Jul 2009 23:08:06 -0500 Subject: [SCSI] ALUA: send STPG if explicit and implicit is supported alua_activate only sends a STPG if only explicit is suppored. As a result, for EMC targets that support both we end up doing a implicit failover when X commands are finally sent to the other SP. This patch does a AND on the h->tpgs, so we do a explicit failover right away. Signed-off-by: Mike Christie Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/device_handler/scsi_dh_alua.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index dba154c8ff6..b5cdefaf260 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -663,7 +663,7 @@ static int alua_activate(struct scsi_device *sdev) goto out; } - if (h->tpgs == TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED) + if (h->tpgs & TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED) err = alua_stpg(sdev, TPGS_STATE_OPTIMIZED, h); out: -- cgit v1.2.3-18-g5258 From 7a7f0c7f7a0cbda062d1ff2ff1d3f99d0e41d2af Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Wed, 29 Jul 2009 17:03:50 -0700 Subject: [SCSI] fcoe: Fix validation of mac address when checking for spma support Fix this bug of validating the wrong mac address while checking for SAN MAC address support from LLD as we should check ha->addr not ctlr.ctl_src_addr. Signed-off-by: Yi Zou Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 0a5609bb581..b7dfc6ebed3 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -329,7 +329,7 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) rcu_read_lock(); for_each_dev_addr(netdev, ha) { if ((ha->type == NETDEV_HW_ADDR_T_SAN) && - (is_valid_ether_addr(fc->ctlr.ctl_src_addr))) { + (is_valid_ether_addr(ha->addr))) { memcpy(fc->ctlr.ctl_src_addr, ha->addr, ETH_ALEN); fc->ctlr.spma = 1; break; -- cgit v1.2.3-18-g5258 From 5a84baeaf7b8bb4188219140cb326a3e859b2312 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Wed, 29 Jul 2009 17:03:55 -0700 Subject: [SCSI] libfcoe: Set fip_flags according to fcf and lport's capability of SPMA support When encap the els for FIP, set the fip_flags according to the FCF and lport's capability of supporting SPMA or FPMA or both. Signed-off-by: Yi Zou Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/fcoe/libfcoe.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index d6ed3f8255a..78caa6be113 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -413,10 +413,18 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fip_mac_desc *mac; struct fcoe_fcf *fcf; size_t dlen; + u16 fip_flags; fcf = fip->sel_fcf; if (!fcf) return -ENODEV; + + /* set flags according to both FCF and lport's capability on SPMA */ + fip_flags = fcf->flags; + fip_flags &= fip->spma ? FIP_FL_SPMA | FIP_FL_FPMA : FIP_FL_FPMA; + if (!fip_flags) + return -ENODEV; + dlen = sizeof(struct fip_encaps) + skb->len; /* len before push */ cap = (struct fip_encaps_head *)skb_push(skb, sizeof(*cap)); @@ -429,9 +437,7 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, cap->fip.fip_op = htons(FIP_OP_LS); cap->fip.fip_subcode = FIP_SC_REQ; cap->fip.fip_dl_len = htons((dlen + sizeof(*mac)) / FIP_BPW); - cap->fip.fip_flags = htons(FIP_FL_FPMA); - if (fip->spma) - cap->fip.fip_flags |= htons(FIP_FL_SPMA); + cap->fip.fip_flags = htons(fip_flags); cap->encaps.fd_desc.fip_dtype = dtype; cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW; -- cgit v1.2.3-18-g5258 From 2f718d64ecc7010463d36e6ec4ae37778d03fc0b Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Wed, 29 Jul 2009 17:04:01 -0700 Subject: [SCSI] fcoe: Call dev_ethtool_get_settings() in fcoe_link_ok No need to check phys_dev here, just call dev_ethtool_get_settings() directly will take care of this. Signed-off-by: Yi Zou Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index b7dfc6ebed3..81601269f4c 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1635,29 +1635,25 @@ int fcoe_link_ok(struct fc_lport *lp) struct fcoe_softc *fc = lport_priv(lp); struct net_device *dev = fc->real_dev; struct ethtool_cmd ecmd = { ETHTOOL_GSET }; - int rc = 0; - if ((dev->flags & IFF_UP) && netif_carrier_ok(dev)) { - dev = fc->phys_dev; - if (dev->ethtool_ops->get_settings) { - dev->ethtool_ops->get_settings(dev, &ecmd); - lp->link_supported_speeds &= - ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT); - if (ecmd.supported & (SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full)) - lp->link_supported_speeds |= FC_PORTSPEED_1GBIT; - if (ecmd.supported & SUPPORTED_10000baseT_Full) - lp->link_supported_speeds |= - FC_PORTSPEED_10GBIT; - if (ecmd.speed == SPEED_1000) - lp->link_speed = FC_PORTSPEED_1GBIT; - if (ecmd.speed == SPEED_10000) - lp->link_speed = FC_PORTSPEED_10GBIT; - } - } else - rc = -1; + if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) && + (!dev_ethtool_get_settings(dev, &ecmd))) { + lp->link_supported_speeds &= + ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT); + if (ecmd.supported & (SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full)) + lp->link_supported_speeds |= FC_PORTSPEED_1GBIT; + if (ecmd.supported & SUPPORTED_10000baseT_Full) + lp->link_supported_speeds |= + FC_PORTSPEED_10GBIT; + if (ecmd.speed == SPEED_1000) + lp->link_speed = FC_PORTSPEED_1GBIT; + if (ecmd.speed == SPEED_10000) + lp->link_speed = FC_PORTSPEED_10GBIT; - return rc; + return 0; + } + return -1; } /** -- cgit v1.2.3-18-g5258 From f161fb72104c7addac3d404a1ff543b2491c1426 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Wed, 29 Jul 2009 17:04:17 -0700 Subject: [SCSI] fcoe: stop delivery of received frames before doing lport_destroy() To be more sure that no more input arrives at the local port as it is being destroyed, clean the queues in the per-cpu receive threads. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 81601269f4c..14a4017a153 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -466,6 +466,9 @@ static int fcoe_if_destroy(struct net_device *netdev) /* tear-down the FCoE controller */ fcoe_ctlr_destroy(&fc->ctlr); + /* Free queued packets for the per-CPU receive threads */ + fcoe_percpu_clean(lp); + /* Cleanup the fc_lport */ fc_lport_destroy(lp); fc_fcp_destroy(lp); @@ -478,9 +481,6 @@ static int fcoe_if_destroy(struct net_device *netdev) if (lp->emp) fc_exch_mgr_free(lp->emp); - /* Free the per-CPU receive threads */ - fcoe_percpu_clean(lp); - /* Free existing skbs */ fcoe_clean_pending_queue(lp); -- cgit v1.2.3-18-g5258 From b1d9fd5574763abe5c763e32e3547a4adee9bd88 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Wed, 29 Jul 2009 17:04:22 -0700 Subject: [SCSI] libfc: rename lport NONE state to DISABLED The state NONE was meant to be invalid, but has been used as the initial state. Rename it to be DISABLED, as more descriptive. Further patches will make it the like the RESET state, except it won't transition to FLOGI until fc_lport_fabric_login() is called. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_exch.c | 2 +- drivers/scsi/libfc/fc_lport.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 145ab9ba55e..e6d82d780ac 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -1875,7 +1875,7 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, u32 f_ctl; /* lport lock ? */ - if (!lp || !mp || (lp->state == LPORT_ST_NONE)) { + if (!lp || !mp || lp->state == LPORT_ST_DISABLED) { FC_LPORT_DBG(lp, "Receiving frames for an lport that " "has not been initialized correctly\n"); fc_frame_free(fp); diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 745fa5555d6..3b28190ca2e 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -113,7 +113,7 @@ static void fc_lport_enter_ready(struct fc_lport *); static void fc_lport_enter_logo(struct fc_lport *); static const char *fc_lport_state_names[] = { - [LPORT_ST_NONE] = "none", + [LPORT_ST_DISABLED] = "disabled", [LPORT_ST_FLOGI] = "FLOGI", [LPORT_ST_DNS] = "dNS", [LPORT_ST_RPN_ID] = "RPN_ID", @@ -550,7 +550,7 @@ int fc_fabric_login(struct fc_lport *lport) int rc = -1; mutex_lock(&lport->lp_mutex); - if (lport->state == LPORT_ST_NONE) { + if (lport->state == LPORT_ST_DISABLED) { fc_lport_enter_reset(lport); rc = 0; } @@ -637,7 +637,7 @@ EXPORT_SYMBOL(fc_fabric_logoff); int fc_lport_destroy(struct fc_lport *lport) { mutex_lock(&lport->lp_mutex); - lport->state = LPORT_ST_NONE; + lport->state = LPORT_ST_DISABLED; lport->link_up = 0; lport->tt.frame_send = fc_frame_drop; mutex_unlock(&lport->lp_mutex); @@ -992,7 +992,7 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp) schedule_delayed_work(&lport->retry_work, delay); } else { switch (lport->state) { - case LPORT_ST_NONE: + case LPORT_ST_DISABLED: case LPORT_ST_READY: case LPORT_ST_RESET: case LPORT_ST_RPN_ID: @@ -1316,7 +1316,7 @@ static void fc_lport_timeout(struct work_struct *work) mutex_lock(&lport->lp_mutex); switch (lport->state) { - case LPORT_ST_NONE: + case LPORT_ST_DISABLED: case LPORT_ST_READY: case LPORT_ST_RESET: WARN_ON(1); @@ -1550,7 +1550,7 @@ int fc_lport_config(struct fc_lport *lport) INIT_DELAYED_WORK(&lport->retry_work, fc_lport_timeout); mutex_init(&lport->lp_mutex); - fc_lport_state_enter(lport, LPORT_ST_NONE); + fc_lport_state_enter(lport, LPORT_ST_DISABLED); fc_lport_add_fc4_type(lport, FC_TYPE_FCP); fc_lport_add_fc4_type(lport, FC_TYPE_CT); -- cgit v1.2.3-18-g5258 From 1190d925813aab80d17ff10f26c115f5846b3308 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Wed, 29 Jul 2009 17:04:27 -0700 Subject: [SCSI] libfc: stop login after fabric logoff When removing the fcoe module, several lports were being shut down through fc_lport_fabric_logoff(). Occasionally, one would enter reset state before fc_lport_destroy() was called, and since link_up was still true, it would log back in. If we just clear link_up earlier, then we wouldn't be accepting LOGO requests from other initiators while we are shutting down. Fix by changing the LOGO response handler to enter DISABLED instead of RESET. Add an fc_lport_enter_disabled() function which does what fc_lport_enter_reset() did, except it doesn't proceed to FLOGI state. Move the code that was common between fc_lport_enter_reset() and fc_lport_enter_disabled() into a new fc_lport_reset_locked() function. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_lport.c | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 3b28190ca2e..7bb451ab0b8 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -930,19 +930,14 @@ int fc_lport_reset(struct fc_lport *lport) EXPORT_SYMBOL(fc_lport_reset); /** - * fc_rport_enter_reset() - Reset the local port + * fc_lport_reset_locked() - Reset the local port * @lport: Fibre Channel local port to be reset * * Locking Note: The lport lock is expected to be held before calling * this routine. */ -static void fc_lport_enter_reset(struct fc_lport *lport) +static void fc_lport_reset_locked(struct fc_lport *lport) { - FC_LPORT_DBG(lport, "Entered RESET state from %s state\n", - fc_lport_state(lport)); - - fc_lport_state_enter(lport, LPORT_ST_RESET); - if (lport->dns_rp) lport->tt.rport_logoff(lport->dns_rp); @@ -956,11 +951,42 @@ static void fc_lport_enter_reset(struct fc_lport *lport) lport->tt.exch_mgr_reset(lport, 0, 0); fc_host_fabric_name(lport->host) = 0; fc_host_port_id(lport->host) = 0; +} + +/** + * fc_lport_enter_reset() - Reset the local port + * @lport: Fibre Channel local port to be reset + * + * Locking Note: The lport lock is expected to be held before calling + * this routine. + */ +static void fc_lport_enter_reset(struct fc_lport *lport) +{ + FC_LPORT_DBG(lport, "Entered RESET state from %s state\n", + fc_lport_state(lport)); + fc_lport_state_enter(lport, LPORT_ST_RESET); + fc_lport_reset_locked(lport); if (lport->link_up) fc_lport_enter_flogi(lport); } +/** + * fc_lport_enter_disabled() - disable the local port + * @lport: Fibre Channel local port to be reset + * + * Locking Note: The lport lock is expected to be held before calling + * this routine. + */ +static void fc_lport_enter_disabled(struct fc_lport *lport) +{ + FC_LPORT_DBG(lport, "Entered disabled state from %s state\n", + fc_lport_state(lport)); + + fc_lport_state_enter(lport, LPORT_ST_DISABLED); + fc_lport_reset_locked(lport); +} + /** * fc_lport_error() - Handler for any errors * @lport: The fc_lport object @@ -1382,7 +1408,7 @@ static void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, op = fc_frame_payload_op(fp); if (op == ELS_LS_ACC) - fc_lport_enter_reset(lport); + fc_lport_enter_disabled(lport); else fc_lport_error(lport, fp); -- cgit v1.2.3-18-g5258 From e9ba8b427852937caee6ca39bb6f9a893bb32ae1 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Wed, 29 Jul 2009 17:04:33 -0700 Subject: [SCSI] libfc: in fc_lport_destroy, flush rports after turning off link During an fcoe module unload, we saw a problem where fc_rport_work() finds the lport has been freed. The rdata points to an area containing 0x6b6b6b6b... the pool poison value from kmem_free(). In fcoe_if_destroy() we call fc_fabric_logoff() then fc_lport_destroy(). fc_fabric_logoff() flushes the remote port work, but we're still receiving requests, and an RSCN or PLOGI arrives which creates more rports. Note that although the LLD also checks link_up, it doesn't do it under the lport mutex, so it can deliver frames to fc_lport_recv_req() even after link_up is cleared. So, re-check link_up there. We need to flush the rports by calling disc_stop_final() after we clear link_up. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_lport.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 7bb451ab0b8..a430335ebf5 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -643,6 +643,7 @@ int fc_lport_destroy(struct fc_lport *lport) mutex_unlock(&lport->lp_mutex); lport->tt.fcp_abort_io(lport); + lport->tt.disc_stop_final(lport); lport->tt.exch_mgr_reset(lport, 0, 0); return 0; } @@ -844,7 +845,10 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, * RSCN here. These don't require a session. * Even if we had a session, it might not be ready. */ - if (fh->fh_type == FC_TYPE_ELS && fh->fh_r_ctl == FC_RCTL_ELS_REQ) { + if (!lport->link_up) + fc_frame_free(fp); + else if (fh->fh_type == FC_TYPE_ELS && + fh->fh_r_ctl == FC_RCTL_ELS_REQ) { /* * Check opcode. */ -- cgit v1.2.3-18-g5258 From 84b05445b9f0b1ac2192f32260c916426d902d79 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Wed, 29 Jul 2009 17:04:38 -0700 Subject: [SCSI] libfc: fix WARNING from fc_seq_start_next on closed exchanges We saw periodic messages like: WARNING: at drivers/scsi/libfc/fc_exch.c:825 fc_seq_start_next+0x30/0x4b This was due to trying to allocate a sequence in a request handler when the exchange had been reset. Delete the WARN_ON. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_exch.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index e6d82d780ac..cab54996375 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -822,7 +822,6 @@ struct fc_seq *fc_seq_start_next(struct fc_seq *sp) struct fc_exch *ep = fc_seq_exch(sp); spin_lock_bh(&ep->ex_lock); - WARN_ON((ep->esb_stat & ESB_ST_COMPLETE) != 0); sp = fc_seq_start_next_locked(sp); spin_unlock_bh(&ep->ex_lock); -- cgit v1.2.3-18-g5258 From 141940548c6919c22bf0573c68fd59d961e22475 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Wed, 29 Jul 2009 17:04:43 -0700 Subject: [SCSI] libfc: rename rport state "NONE" to "DELETE". State RPORT_ST_NONE was intented to be an invalid state (0), never used. This was a misguided attempt to be sure it was always initialized. Having an extra state meaning nothing requires switch statements to have a case covering that state. State NONE has been used instead to mean the remote port is being deleted. Changing the name to RPORT_ST_DELETE. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 7162385f52e..bf7364fc16c 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -77,13 +77,13 @@ static void fc_rport_error_retry(struct fc_rport *, struct fc_frame *); static void fc_rport_work(struct work_struct *); static const char *fc_rport_state_names[] = { - [RPORT_ST_NONE] = "None", [RPORT_ST_INIT] = "Init", [RPORT_ST_PLOGI] = "PLOGI", [RPORT_ST_PRLI] = "PRLI", [RPORT_ST_RTV] = "RTV", [RPORT_ST_READY] = "Ready", [RPORT_ST_LOGO] = "LOGO", + [RPORT_ST_DELETE] = "Delete", }; static void fc_rport_rogue_destroy(struct device *dev) @@ -326,8 +326,8 @@ int fc_rport_logoff(struct fc_rport *rport) FC_RPORT_DBG(rport, "Remove port\n"); - if (rdata->rp_state == RPORT_ST_NONE) { - FC_RPORT_DBG(rport, "Port in NONE state, not removing\n"); + if (rdata->rp_state == RPORT_ST_DELETE) { + FC_RPORT_DBG(rport, "Port in Delete state, not removing\n"); mutex_unlock(&rdata->rp_mutex); goto out; } @@ -335,10 +335,10 @@ int fc_rport_logoff(struct fc_rport *rport) fc_rport_enter_logo(rport); /* - * Change the state to NONE so that we discard + * Change the state to Delete so that we discard * the response. */ - fc_rport_state_enter(rport, RPORT_ST_NONE); + fc_rport_state_enter(rport, RPORT_ST_DELETE); mutex_unlock(&rdata->rp_mutex); @@ -405,7 +405,7 @@ static void fc_rport_timeout(struct work_struct *work) break; case RPORT_ST_READY: case RPORT_ST_INIT: - case RPORT_ST_NONE: + case RPORT_ST_DELETE: break; } @@ -433,14 +433,14 @@ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) case RPORT_ST_PRLI: case RPORT_ST_LOGO: rdata->event = RPORT_EV_FAILED; - fc_rport_state_enter(rport, RPORT_ST_NONE); + fc_rport_state_enter(rport, RPORT_ST_DELETE); queue_work(rport_event_queue, &rdata->event_work); break; case RPORT_ST_RTV: fc_rport_enter_ready(rport); break; - case RPORT_ST_NONE: + case RPORT_ST_DELETE: case RPORT_ST_READY: case RPORT_ST_INIT: break; @@ -652,7 +652,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, } else { FC_RPORT_DBG(rport, "Bad ELS response for PRLI command\n"); rdata->event = RPORT_EV_FAILED; - fc_rport_state_enter(rport, RPORT_ST_NONE); + fc_rport_state_enter(rport, RPORT_ST_DELETE); queue_work(rport_event_queue, &rdata->event_work); } @@ -703,7 +703,7 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, } else { FC_RPORT_DBG(rport, "Bad ELS response for LOGO command\n"); rdata->event = RPORT_EV_LOGO; - fc_rport_state_enter(rport, RPORT_ST_NONE); + fc_rport_state_enter(rport, RPORT_ST_DELETE); queue_work(rport_event_queue, &rdata->event_work); } @@ -1012,7 +1012,7 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, "- ignored for now\n", rdata->rp_state); /* XXX TBD - should reset */ break; - case RPORT_ST_NONE: + case RPORT_ST_DELETE: default: FC_RPORT_DBG(rport, "Received PLOGI in unexpected " "state %d\n", rdata->rp_state); @@ -1238,7 +1238,7 @@ static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp, FC_RPORT_DBG(rport, "Received PRLO request while in state %s\n", fc_rport_state(rport)); - if (rdata->rp_state == RPORT_ST_NONE) { + if (rdata->rp_state == RPORT_ST_DELETE) { fc_frame_free(fp); return; } @@ -1271,13 +1271,13 @@ static void fc_rport_recv_logo_req(struct fc_rport *rport, struct fc_seq *sp, FC_RPORT_DBG(rport, "Received LOGO request while in state %s\n", fc_rport_state(rport)); - if (rdata->rp_state == RPORT_ST_NONE) { + if (rdata->rp_state == RPORT_ST_DELETE) { fc_frame_free(fp); return; } rdata->event = RPORT_EV_LOGO; - fc_rport_state_enter(rport, RPORT_ST_NONE); + fc_rport_state_enter(rport, RPORT_ST_DELETE); queue_work(rport_event_queue, &rdata->event_work); lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); -- cgit v1.2.3-18-g5258 From 5f7ea3b7f81d5e5180647a071998b73a841bdba9 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Wed, 29 Jul 2009 17:04:49 -0700 Subject: [SCSI] libfc: fc_rport_logoff should not drop the lock fc_rport_logoff drops the rport lock in order to cancel work that may be pending. This is undesirable as the state can completely change, and the caller may not expect that the lock could've been dropped. If there is work pending, it will acquire the rdata mutex and so we're protected and can change the event from READY to DELETE. Queue the work only if there is no event already pending. There were a couple other cases where the state was set to DELETE and work queued, even though the state may have already been DELETE. Fix these using a common function fc_rport_enter_delete(). Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 60 +++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index bf7364fc16c..a86df0b41ae 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -230,6 +230,7 @@ static void fc_rport_work(struct work_struct *work) ids.port_name = rport->port_name; ids.node_name = rport->node_name; + rdata->event = RPORT_EV_NONE; mutex_unlock(&rdata->rp_mutex); new_rport = fc_remote_port_add(lport->host, 0, &ids); @@ -310,6 +311,37 @@ int fc_rport_login(struct fc_rport *rport) return 0; } +/** + * fc_rport_enter_delete() - schedule a remote port to be deleted. + * @rport: Fibre Channel remote port + * @event: event to report as the reason for deletion + * + * Locking Note: Called with the rport lock held. + * + * Allow state change into DELETE only once. + * + * Call queue_work only if there's no event already pending. + * Set the new event so that the old pending event will not occur. + * Since we have the mutex, even if fc_rport_work() is already started, + * it'll see the new event. + */ +static void fc_rport_enter_delete(struct fc_rport *rport, + enum fc_rport_event event) +{ + struct fc_rport_libfc_priv *rdata = rport->dd_data; + + if (rdata->rp_state == RPORT_ST_DELETE) + return; + + FC_RPORT_DBG(rport, "Delete port\n"); + + fc_rport_state_enter(rport, RPORT_ST_DELETE); + + if (rdata->event == RPORT_EV_NONE) + queue_work(rport_event_queue, &rdata->event_work); + rdata->event = event; +} + /** * fc_rport_logoff() - Logoff and remove an rport * @rport: Fibre Channel remote port to be removed @@ -338,17 +370,7 @@ int fc_rport_logoff(struct fc_rport *rport) * Change the state to Delete so that we discard * the response. */ - fc_rport_state_enter(rport, RPORT_ST_DELETE); - - mutex_unlock(&rdata->rp_mutex); - - cancel_delayed_work_sync(&rdata->retry_work); - - mutex_lock(&rdata->rp_mutex); - - rdata->event = RPORT_EV_STOP; - queue_work(rport_event_queue, &rdata->event_work); - + fc_rport_enter_delete(rport, RPORT_EV_STOP); mutex_unlock(&rdata->rp_mutex); out: @@ -370,8 +392,9 @@ static void fc_rport_enter_ready(struct fc_rport *rport) FC_RPORT_DBG(rport, "Port is Ready\n"); + if (rdata->event == RPORT_EV_NONE) + queue_work(rport_event_queue, &rdata->event_work); rdata->event = RPORT_EV_CREATED; - queue_work(rport_event_queue, &rdata->event_work); } /** @@ -432,10 +455,7 @@ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) case RPORT_ST_PLOGI: case RPORT_ST_PRLI: case RPORT_ST_LOGO: - rdata->event = RPORT_EV_FAILED; - fc_rport_state_enter(rport, RPORT_ST_DELETE); - queue_work(rport_event_queue, - &rdata->event_work); + fc_rport_enter_delete(rport, RPORT_EV_FAILED); break; case RPORT_ST_RTV: fc_rport_enter_ready(rport); @@ -651,9 +671,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, } else { FC_RPORT_DBG(rport, "Bad ELS response for PRLI command\n"); - rdata->event = RPORT_EV_FAILED; - fc_rport_state_enter(rport, RPORT_ST_DELETE); - queue_work(rport_event_queue, &rdata->event_work); + fc_rport_enter_delete(rport, RPORT_EV_FAILED); } out: @@ -702,9 +720,7 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, fc_rport_enter_rtv(rport); } else { FC_RPORT_DBG(rport, "Bad ELS response for LOGO command\n"); - rdata->event = RPORT_EV_LOGO; - fc_rport_state_enter(rport, RPORT_ST_DELETE); - queue_work(rport_event_queue, &rdata->event_work); + fc_rport_enter_delete(rport, RPORT_EV_LOGO); } out: -- cgit v1.2.3-18-g5258 From 201e5795b7b9582accb6d83316e30f24d7d40fd3 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Wed, 29 Jul 2009 17:04:54 -0700 Subject: [SCSI] libfc: fix: cancel rport retry timer The timer for rport retries wasn't getting canceled, and would occasionally go off after the module was unloaded. Add logic to cancel the timer in fc_rport_work(). Since we cancel the timer before deleting the rdata, it is no longer necessary to do a get_device() for the pending timer. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index a86df0b41ae..90cc90dd3b5 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -276,6 +276,7 @@ static void fc_rport_work(struct work_struct *work) mutex_unlock(&rdata->rp_mutex); if (rport_ops->event_callback) rport_ops->event_callback(lport, rport, event); + cancel_delayed_work_sync(&rdata->retry_work); if (trans_state == FC_PORTSTATE_ROGUE) put_device(&rport->dev); else { @@ -433,7 +434,6 @@ static void fc_rport_timeout(struct work_struct *work) } mutex_unlock(&rdata->rp_mutex); - put_device(&rport->dev); } /** @@ -494,7 +494,6 @@ static void fc_rport_error_retry(struct fc_rport *rport, struct fc_frame *fp) /* no additional delay on exchange timeouts */ if (PTR_ERR(fp) == -FC_EX_TIMEOUT) delay = 0; - get_device(&rport->dev); schedule_delayed_work(&rdata->retry_work, delay); return; } -- cgit v1.2.3-18-g5258 From 96316099ac3cb259eac2d6891f3c75b38b29d26e Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Wed, 29 Jul 2009 17:05:00 -0700 Subject: [SCSI] fcoe, libfc: adds exchange manager(EM) anchor list per lport and related APIs Adds EM list using a anchor struct fc_exch_mgr_anchor, anchor is used to allow same EM instance sharing across more than one lport on a eth device, this implementation is per discussed design posted at http://www.open-fcoe.org/pipermail/devel/2009-June/002566.html. The shared EM is required for multiple lports on eth device when using multiple VLANs or NPIV. Adds fc_exch_mgr_add API to add a EM to the lport and fc_exch_mgr_del API to delete previously added EM. Also adds function fc_exch_mgr_destroy() to destroy allocated EM. The kref is added to the EM to keep track of EM usage count, the EM is destroyed when no longer in use upon kref reaching to zero. The caller can specify match function to fc_exch_mgr_add, this will be used in determining exchange allocation from its EM or not. Moved calling of fcoe_em_config below fcoe_libfc_config calling, so that list head lp->ema_list is initialized before configuring EM. Signed-off-by: Vasu Dev Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 14 ++++++------- drivers/scsi/libfc/fc_exch.c | 48 +++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/libfc/fc_lport.c | 1 + 3 files changed, 56 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 14a4017a153..719a99d4a43 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -603,18 +603,18 @@ static int fcoe_if_create(struct net_device *netdev) goto out_netdev_cleanup; } - /* lport exch manager allocation */ - rc = fcoe_em_config(lp); + /* Initialize the library */ + rc = fcoe_libfc_config(lp, &fcoe_libfc_fcn_templ); if (rc) { - FCOE_NETDEV_DBG(netdev, "Could not configure the EM for the " + FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the " "interface\n"); - goto out_netdev_cleanup; + goto out_lp_destroy; } - /* Initialize the library */ - rc = fcoe_libfc_config(lp, &fcoe_libfc_fcn_templ); + /* lport exch manager allocation */ + rc = fcoe_em_config(lp); if (rc) { - FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the " + FCOE_NETDEV_DBG(netdev, "Could not configure the EM for the " "interface\n"); goto out_lp_destroy; } diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index cab54996375..f1fa2b196e9 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -55,6 +55,7 @@ static struct kmem_cache *fc_em_cachep; /* cache for exchanges */ */ struct fc_exch_mgr { enum fc_class class; /* default class for sequences */ + struct kref kref; /* exchange mgr reference count */ spinlock_t em_lock; /* exchange manager lock, must be taken before ex_lock */ u16 last_xid; /* last allocated exchange ID */ @@ -84,6 +85,12 @@ struct fc_exch_mgr { }; #define fc_seq_exch(sp) container_of(sp, struct fc_exch, seq) +struct fc_exch_mgr_anchor { + struct list_head ema_list; + struct fc_exch_mgr *mp; + bool (*match)(struct fc_frame *); +}; + static void fc_exch_rrq(struct fc_exch *); static void fc_seq_ls_acc(struct fc_seq *); static void fc_seq_ls_rjt(struct fc_seq *, enum fc_els_rjt_reason, @@ -1729,6 +1736,47 @@ reject: fc_frame_free(fp); } +struct fc_exch_mgr_anchor *fc_exch_mgr_add(struct fc_lport *lport, + struct fc_exch_mgr *mp, + bool (*match)(struct fc_frame *)) +{ + struct fc_exch_mgr_anchor *ema; + + ema = kmalloc(sizeof(*ema), GFP_ATOMIC); + if (!ema) + return ema; + + ema->mp = mp; + ema->match = match; + /* add EM anchor to EM anchors list */ + list_add_tail(&ema->ema_list, &lport->ema_list); + kref_get(&mp->kref); + return ema; +} +EXPORT_SYMBOL(fc_exch_mgr_add); + +static void fc_exch_mgr_destroy(struct kref *kref) +{ + struct fc_exch_mgr *mp = container_of(kref, struct fc_exch_mgr, kref); + + /* + * The total exch count must be zero + * before freeing exchange manager. + */ + WARN_ON(mp->total_exches != 0); + mempool_destroy(mp->ep_pool); + kfree(mp); +} + +void fc_exch_mgr_del(struct fc_exch_mgr_anchor *ema) +{ + /* remove EM anchor from EM anchors list */ + list_del(&ema->ema_list); + kref_put(&ema->mp->kref, fc_exch_mgr_destroy); + kfree(ema); +} +EXPORT_SYMBOL(fc_exch_mgr_del); + struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, enum fc_class class, u16 min_xid, u16 max_xid) diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index a430335ebf5..ca8ea264b68 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -1618,6 +1618,7 @@ int fc_lport_init(struct fc_lport *lport) if (lport->link_supported_speeds & FC_PORTSPEED_10GBIT) fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_10GBIT; + INIT_LIST_HEAD(&lport->ema_list); return 0; } EXPORT_SYMBOL(fc_lport_init); -- cgit v1.2.3-18-g5258 From d459b7ea1b4c7aa3dacfeee174d02b2f7a95850d Mon Sep 17 00:00:00 2001 From: Robert Love Date: Wed, 29 Jul 2009 17:05:05 -0700 Subject: [SCSI] libfc: Remove the FC_EM_DBG macro Currently there is a 1:1 relationship between the lport and exchange manager. This macro takes an EM as an argument and determines the lport from it. However, later patches will use an EM list per lport, so we will no longer have this 1:1 relationship- this macro must change. The FC_EM_DBG macro is rarely used. There are four callers, two can use FC_LPORT_DBG instead and two can be removed since they're not necessary. This patch makes those changes and removes the macro. Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_exch.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index f1fa2b196e9..3ad7f88e7ae 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -1129,7 +1129,7 @@ static void fc_exch_recv_req(struct fc_lport *lp, struct fc_exch_mgr *mp, lp->tt.lport_recv(lp, sp, fp); fc_exch_release(ep); /* release from lookup */ } else { - FC_EM_DBG(mp, "exch/seq lookup failed: reject %x\n", reject); + FC_LPORT_DBG(lp, "exch/seq lookup failed: reject %x\n", reject); fc_frame_free(fp); } } @@ -1235,13 +1235,12 @@ static void fc_exch_recv_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) struct fc_seq *sp; sp = fc_seq_lookup_orig(mp, fp); /* doesn't hold sequence */ - if (!sp) { + + if (!sp) atomic_inc(&mp->stats.xid_not_found); - FC_EM_DBG(mp, "seq lookup failed\n"); - } else { + else atomic_inc(&mp->stats.non_bls_resp); - FC_EM_DBG(mp, "non-BLS response to sequence"); - } + fc_frame_free(fp); } @@ -1950,7 +1949,7 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, fc_exch_recv_req(lp, mp, fp); break; default: - FC_EM_DBG(mp, "dropping invalid frame (eof %x)", fr_eof(fp)); + FC_LPORT_DBG(lp, "dropping invalid frame (eof %x)", fr_eof(fp)); fc_frame_free(fp); break; } -- cgit v1.2.3-18-g5258 From 52ff878c912215210f53c0a080552dd6ba3055a2 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Wed, 29 Jul 2009 17:05:10 -0700 Subject: [SCSI] fcoe, fnic, libfc: modifies current code paths to use EM anchor list Modifies current code to use EM anchor list in EM allocation, EM free, EM reset, exch allocation and exch lookup code paths. 1. Modifies fc_exch_mgr_alloc to accept EM match function and then have allocated EM added to the lport using fc_exch_mgr_add API while also updating EM kref for newly added EM. 2. Updates fc_exch_mgr_free API to accept only lport pointer instead EM and then have this API free all EMs of the lport from EM anchor list. 3. Removes single lport pointer link from the EM, which was used in associating lport pointer in newly allocated exchange. Instead have lport pointer passed along new exchange allocation call path and then store passed lport pointer in newly allocated exchange, this will allow a single EM instance to be used across more than one lport and used in EM reset to reset only lport specific exchanges. 4. Modifies fc_exch_mgr_reset to reset all EMs from the EM anchor list of the lport, adds additional exch lport pointer (ep->lp) check for shared EM case to reset exchange specific to a lport requested reset. 5. Updates exch allocation API fc_exch_alloc to use EM anchor list and its anchor match func pointer. The fc_exch_alloc will walk the list of EMs until it finds a match, a match will be either null match func pointer or call to match function returning true value. 6. Updates fc_exch_recv to accept incoming frame on local port using only lport pointer and frame pointer without specifying EM instance of incoming frame. Instead modified fc_exch_recv to locate EM for the incoming frame by matching xid of incoming frame against a EM xid range. This change was required to use EM list in libfc Rx path and after this change the lport fc_exch_mgr pointer emp is not needed anymore, so removed emp pointer. 7. Updates fnic for removed lport emp pointer and above modified libfc APIs fc_exch_recv, fc_exch_mgr_alloc and fc_exch_mgr_free. 8. Removes exch_get and exch_put from libfc_function_template as these are no longer needed with EM anchor list and its match function use. Also removes its default function fc_exch_get. A defect this patch introduced regarding the libfc initialization order in the fnic driver was fixed by Joe Eykholt . Signed-off-by: Vasu Dev Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 16 ++-- drivers/scsi/fcoe/libfcoe.c | 2 +- drivers/scsi/fnic/fnic_fcs.c | 2 +- drivers/scsi/fnic/fnic_main.c | 20 ++--- drivers/scsi/libfc/fc_exch.c | 191 ++++++++++++++++++++++++++---------------- 5 files changed, 134 insertions(+), 97 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 719a99d4a43..ebf2e20370d 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -423,11 +423,8 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost, */ static inline int fcoe_em_config(struct fc_lport *lp) { - BUG_ON(lp->emp); - - lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3, - FCOE_MIN_XID, FCOE_MAX_XID); - if (!lp->emp) + if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCOE_MIN_XID, + FCOE_MAX_XID, NULL)) return -ENOMEM; return 0; @@ -478,8 +475,7 @@ static int fcoe_if_destroy(struct net_device *netdev) scsi_remove_host(lp->host); /* There are no more rports or I/O, free the EM */ - if (lp->emp) - fc_exch_mgr_free(lp->emp); + fc_exch_mgr_free(lp); /* Free existing skbs */ fcoe_clean_pending_queue(lp); @@ -634,7 +630,7 @@ static int fcoe_if_create(struct net_device *netdev) return rc; out_lp_destroy: - fc_exch_mgr_free(lp->emp); /* Free the EM */ + fc_exch_mgr_free(lp); out_netdev_cleanup: fcoe_netdev_cleanup(fc); out_host_put: @@ -1277,7 +1273,7 @@ int fcoe_percpu_receive_thread(void *arg) fh = fc_frame_header_get(fp); if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && fh->fh_type == FC_TYPE_FCP) { - fc_exch_recv(lp, lp->emp, fp); + fc_exch_recv(lp, fp); continue; } if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) { @@ -1298,7 +1294,7 @@ int fcoe_percpu_receive_thread(void *arg) fc_frame_free(fp); continue; } - fc_exch_recv(lp, lp->emp, fp); + fc_exch_recv(lp, fp); } return 0; } diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index 78caa6be113..4db719d6ada 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -885,7 +885,7 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) stats->RxFrames++; stats->RxWords += skb->len / FIP_BPW; - fc_exch_recv(lp, lp->emp, fp); + fc_exch_recv(lp, fp); return; len_err: diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index 07e6eedb83c..50db3e36a61 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -115,7 +115,7 @@ void fnic_handle_frame(struct work_struct *work) } spin_unlock_irqrestore(&fnic->fnic_lock, flags); - fc_exch_recv(lp, lp->emp, fp); + fc_exch_recv(lp, fp); } } diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 2c266c01dc5..71c7bbe26d0 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -671,14 +671,6 @@ static int __devinit fnic_probe(struct pci_dev *pdev, lp->link_up = 0; lp->tt = fnic_transport_template; - lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3, - FCPIO_HOST_EXCH_RANGE_START, - FCPIO_HOST_EXCH_RANGE_END); - if (!lp->emp) { - err = -ENOMEM; - goto err_out_remove_scsi_host; - } - lp->max_retry_count = fnic->config.flogi_retries; lp->max_rport_retry_count = fnic->config.plogi_retries; lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | @@ -693,12 +685,18 @@ static int __devinit fnic_probe(struct pci_dev *pdev, fc_set_wwnn(lp, fnic->config.node_wwn); fc_set_wwpn(lp, fnic->config.port_wwn); - fc_exch_init(lp); fc_lport_init(lp); + fc_exch_init(lp); fc_elsct_init(lp); fc_rport_init(lp); fc_disc_init(lp); + if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCPIO_HOST_EXCH_RANGE_START, + FCPIO_HOST_EXCH_RANGE_END, NULL)) { + err = -ENOMEM; + goto err_out_remove_scsi_host; + } + fc_lport_config(lp); if (fc_set_mfs(lp, fnic->config.maxdatafieldsize + @@ -738,7 +736,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev, return 0; err_out_free_exch_mgr: - fc_exch_mgr_free(lp->emp); + fc_exch_mgr_free(lp); err_out_remove_scsi_host: fc_remove_host(fnic->lport->host); scsi_remove_host(fnic->lport->host); @@ -827,7 +825,7 @@ static void __devexit fnic_remove(struct pci_dev *pdev) fc_remove_host(fnic->lport->host); scsi_remove_host(fnic->lport->host); - fc_exch_mgr_free(fnic->lport->emp); + fc_exch_mgr_free(fnic->lport); vnic_dev_notify_unset(fnic->vdev); fnic_free_vnic_resources(fnic); fnic_free_intr(fnic); diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 3ad7f88e7ae..324589a5cc0 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -65,7 +65,6 @@ struct fc_exch_mgr { u16 last_read; /* last xid allocated for read */ u32 total_exches; /* total allocated exchanges */ struct list_head ex_list; /* allocated exchanges list */ - struct fc_lport *lp; /* fc device instance */ mempool_t *ep_pool; /* reserve ep's */ /* @@ -275,8 +274,6 @@ static void fc_exch_release(struct fc_exch *ep) mp = ep->em; if (ep->destructor) ep->destructor(&ep->seq, ep->arg); - if (ep->lp->tt.exch_put) - ep->lp->tt.exch_put(ep->lp, mp, ep->xid); WARN_ON(!(ep->esb_stat & ESB_ST_COMPLETE)); mempool_free(ep, mp->ep_pool); } @@ -513,17 +510,20 @@ static u16 fc_em_alloc_xid(struct fc_exch_mgr *mp, const struct fc_frame *fp) return xid; } -/* - * fc_exch_alloc - allocate an exchange. - * @mp : ptr to the exchange manager - * @xid: input xid +/** + * fc_exch_em_alloc() - allocate an exchange from a specified EM. + * @lport: ptr to the local port + * @mp: ptr to the exchange manager + * @fp: ptr to the FC frame + * @xid: input xid * * if xid is supplied zero then assign next free exchange ID * from exchange manager, otherwise use supplied xid. * Returns with exch lock held. */ -struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, - struct fc_frame *fp, u16 xid) +static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, + struct fc_exch_mgr *mp, + struct fc_frame *fp, u16 xid) { struct fc_exch *ep; @@ -566,7 +566,7 @@ struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, */ ep->oxid = ep->xid = xid; ep->em = mp; - ep->lp = mp->lp; + ep->lp = lport; ep->f_ctl = FC_FC_FIRST_SEQ; /* next seq is first seq */ ep->rxid = FC_XID_UNKNOWN; ep->class = mp->class; @@ -579,6 +579,31 @@ err: mempool_free(ep, mp->ep_pool); return NULL; } + +/** + * fc_exch_alloc() - allocate an exchange. + * @lport: ptr to the local port + * @fp: ptr to the FC frame + * + * This function walks the list of the exchange manager(EM) + * anchors to select a EM for new exchange allocation. The + * EM is selected having either a NULL match function pointer + * or call to match function returning true. + */ +struct fc_exch *fc_exch_alloc(struct fc_lport *lport, struct fc_frame *fp) +{ + struct fc_exch_mgr_anchor *ema; + struct fc_exch *ep; + + list_for_each_entry(ema, &lport->ema_list, ema_list) { + if (!ema->match || ema->match(fp)) { + ep = fc_exch_em_alloc(lport, ema->mp, fp, 0); + if (ep) + return ep; + } + } + return NULL; +} EXPORT_SYMBOL(fc_exch_alloc); /* @@ -617,12 +642,14 @@ EXPORT_SYMBOL(fc_exch_done); * Allocate a new exchange as responder. * Sets the responder ID in the frame header. */ -static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) +static struct fc_exch *fc_exch_resp(struct fc_lport *lport, + struct fc_exch_mgr *mp, + struct fc_frame *fp) { struct fc_exch *ep; struct fc_frame_header *fh; - ep = mp->lp->tt.exch_get(mp->lp, fp); + ep = fc_exch_alloc(lport, fp); if (ep) { ep->class = fc_frame_class(fp); @@ -648,7 +675,7 @@ static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) ep->esb_stat &= ~ESB_ST_SEQ_INIT; fc_exch_hold(ep); /* hold for caller */ - spin_unlock_bh(&ep->ex_lock); /* lock from exch_get */ + spin_unlock_bh(&ep->ex_lock); /* lock from fc_exch_alloc */ } return ep; } @@ -658,7 +685,8 @@ static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) * If fc_pf_rjt_reason is FC_RJT_NONE then this function will have a hold * on the ep that should be released by the caller. */ -static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_exch_mgr *mp, +static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_lport *lport, + struct fc_exch_mgr *mp, struct fc_frame *fp) { struct fc_frame_header *fh = fc_frame_header_get(fp); @@ -712,7 +740,7 @@ static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_exch_mgr *mp, reject = FC_RJT_RX_ID; goto rel; } - ep = fc_exch_resp(mp, fp); + ep = fc_exch_resp(lport, mp, fp); if (!ep) { reject = FC_RJT_EXCH_EST; /* XXX */ goto out; @@ -1103,7 +1131,7 @@ static void fc_exch_recv_req(struct fc_lport *lp, struct fc_exch_mgr *mp, enum fc_pf_rjt_reason reject; fr_seq(fp) = NULL; - reject = fc_seq_lookup_recip(mp, fp); + reject = fc_seq_lookup_recip(lp, mp, fp); if (reject == FC_RJT_NONE) { sp = fr_seq(fp); /* sequence will be held */ ep = fc_seq_exch(sp); @@ -1467,29 +1495,34 @@ void fc_exch_mgr_reset(struct fc_lport *lp, u32 sid, u32 did) { struct fc_exch *ep; struct fc_exch *next; - struct fc_exch_mgr *mp = lp->emp; + struct fc_exch_mgr *mp; + struct fc_exch_mgr_anchor *ema; - spin_lock_bh(&mp->em_lock); + list_for_each_entry(ema, &lp->ema_list, ema_list) { + mp = ema->mp; + spin_lock_bh(&mp->em_lock); restart: - list_for_each_entry_safe(ep, next, &mp->ex_list, ex_list) { - if ((sid == 0 || sid == ep->sid) && - (did == 0 || did == ep->did)) { - fc_exch_hold(ep); - spin_unlock_bh(&mp->em_lock); - - fc_exch_reset(ep); - - fc_exch_release(ep); - spin_lock_bh(&mp->em_lock); - - /* - * must restart loop incase while lock was down - * multiple eps were released. - */ - goto restart; + list_for_each_entry_safe(ep, next, &mp->ex_list, ex_list) { + if ((lp == ep->lp) && + (sid == 0 || sid == ep->sid) && + (did == 0 || did == ep->did)) { + fc_exch_hold(ep); + spin_unlock_bh(&mp->em_lock); + + fc_exch_reset(ep); + + fc_exch_release(ep); + spin_lock_bh(&mp->em_lock); + + /* + * must restart loop incase while lock + * was down multiple eps were released. + */ + goto restart; + } } + spin_unlock_bh(&mp->em_lock); } - spin_unlock_bh(&mp->em_lock); } EXPORT_SYMBOL(fc_exch_mgr_reset); @@ -1778,7 +1811,8 @@ EXPORT_SYMBOL(fc_exch_mgr_del); struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, enum fc_class class, - u16 min_xid, u16 max_xid) + u16 min_xid, u16 max_xid, + bool (*match)(struct fc_frame *)) { struct fc_exch_mgr *mp; size_t len; @@ -1803,7 +1837,6 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, mp->class = class; mp->total_exches = 0; mp->exches = (struct fc_exch **)(mp + 1); - mp->lp = lp; /* adjust em exch xid range for offload */ mp->min_xid = min_xid; mp->max_xid = max_xid; @@ -1826,6 +1859,18 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, if (!mp->ep_pool) goto free_mp; + kref_init(&mp->kref); + if (!fc_exch_mgr_add(lp, mp, match)) { + mempool_destroy(mp->ep_pool); + goto free_mp; + } + + /* + * Above kref_init() sets mp->kref to 1 and then + * call to fc_exch_mgr_add incremented mp->kref again, + * so adjust that extra increment. + */ + kref_put(&mp->kref, fc_exch_mgr_destroy); return mp; free_mp: @@ -1834,27 +1879,15 @@ free_mp: } EXPORT_SYMBOL(fc_exch_mgr_alloc); -void fc_exch_mgr_free(struct fc_exch_mgr *mp) +void fc_exch_mgr_free(struct fc_lport *lport) { - WARN_ON(!mp); - /* - * The total exch count must be zero - * before freeing exchange manager. - */ - WARN_ON(mp->total_exches != 0); - mempool_destroy(mp->ep_pool); - kfree(mp); + struct fc_exch_mgr_anchor *ema, *next; + + list_for_each_entry_safe(ema, next, &lport->ema_list, ema_list) + fc_exch_mgr_del(ema); } EXPORT_SYMBOL(fc_exch_mgr_free); -struct fc_exch *fc_exch_get(struct fc_lport *lp, struct fc_frame *fp) -{ - if (!lp || !lp->emp) - return NULL; - - return fc_exch_alloc(lp->emp, fp, 0); -} -EXPORT_SYMBOL(fc_exch_get); struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, struct fc_frame *fp, @@ -1869,7 +1902,7 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, struct fc_frame_header *fh; int rc = 1; - ep = lp->tt.exch_get(lp, fp); + ep = fc_exch_alloc(lp, fp); if (!ep) { fc_frame_free(fp); return NULL; @@ -1914,24 +1947,44 @@ EXPORT_SYMBOL(fc_exch_seq_send); /* * Receive a frame */ -void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, - struct fc_frame *fp) +void fc_exch_recv(struct fc_lport *lp, struct fc_frame *fp) { struct fc_frame_header *fh = fc_frame_header_get(fp); - u32 f_ctl; + struct fc_exch_mgr_anchor *ema; + u32 f_ctl, found = 0; + u16 oxid; /* lport lock ? */ - if (!lp || !mp || lp->state == LPORT_ST_DISABLED) { + if (!lp || lp->state == LPORT_ST_DISABLED) { FC_LPORT_DBG(lp, "Receiving frames for an lport that " "has not been initialized correctly\n"); fc_frame_free(fp); return; } + f_ctl = ntoh24(fh->fh_f_ctl); + oxid = ntohs(fh->fh_ox_id); + if (f_ctl & FC_FC_EX_CTX) { + list_for_each_entry(ema, &lp->ema_list, ema_list) { + if ((oxid >= ema->mp->min_xid) && + (oxid <= ema->mp->max_xid)) { + found = 1; + break; + } + } + + if (!found) { + FC_LPORT_DBG(lp, "Received response for out " + "of range oxid:%hx\n", oxid); + fc_frame_free(fp); + return; + } + } else + ema = list_entry(lp->ema_list.prev, typeof(*ema), ema_list); + /* * If frame is marked invalid, just drop it. */ - f_ctl = ntoh24(fh->fh_f_ctl); switch (fr_eof(fp)) { case FC_EOF_T: if (f_ctl & FC_FC_END_SEQ) @@ -1939,34 +1992,24 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, /* fall through */ case FC_EOF_N: if (fh->fh_type == FC_TYPE_BLS) - fc_exch_recv_bls(mp, fp); + fc_exch_recv_bls(ema->mp, fp); else if ((f_ctl & (FC_FC_EX_CTX | FC_FC_SEQ_CTX)) == FC_FC_EX_CTX) - fc_exch_recv_seq_resp(mp, fp); + fc_exch_recv_seq_resp(ema->mp, fp); else if (f_ctl & FC_FC_SEQ_CTX) - fc_exch_recv_resp(mp, fp); + fc_exch_recv_resp(ema->mp, fp); else - fc_exch_recv_req(lp, mp, fp); + fc_exch_recv_req(lp, ema->mp, fp); break; default: FC_LPORT_DBG(lp, "dropping invalid frame (eof %x)", fr_eof(fp)); fc_frame_free(fp); - break; } } EXPORT_SYMBOL(fc_exch_recv); int fc_exch_init(struct fc_lport *lp) { - if (!lp->tt.exch_get) { - /* - * exch_put() should be NULL if - * exch_get() is NULL - */ - WARN_ON(lp->tt.exch_put); - lp->tt.exch_get = fc_exch_get; - } - if (!lp->tt.seq_start_next) lp->tt.seq_start_next = fc_seq_start_next; -- cgit v1.2.3-18-g5258 From e8af4d4380babc89d193c16163f070a6418f033b Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Wed, 29 Jul 2009 17:05:15 -0700 Subject: [SCSI] fcoe: modifies fcoe_hostlist_lock uses as prep work to add shared offload EM Modifies fcoe_hostlist_lock uses such that a new EM allocation in fcoe_em_config and adding new fcoe_softc using fcoe_hostlist_add are atomic, this is to ensure that a shared offload EM gets allocated only once per eth device for its all lports. Signed-off-by: Vasu Dev Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index ebf2e20370d..86410b9a30c 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -419,6 +419,8 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost, * fcoe_em_config() - allocates em for this lport * @lp: the port that em is to allocated for * + * Called with write fcoe_hostlist_lock held. + * * Returns : 0 on success */ static inline int fcoe_em_config(struct fc_lport *lp) @@ -607,6 +609,13 @@ static int fcoe_if_create(struct net_device *netdev) goto out_lp_destroy; } + /* + * fcoe_em_alloc() and fcoe_hostlist_add() both + * need to be atomic under fcoe_hostlist_lock + * since fcoe_em_alloc() looks for an existing EM + * instance on host list updated by fcoe_hostlist_add(). + */ + write_lock(&fcoe_hostlist_lock); /* lport exch manager allocation */ rc = fcoe_em_config(lp); if (rc) { @@ -617,6 +626,7 @@ static int fcoe_if_create(struct net_device *netdev) /* add to lports list */ fcoe_hostlist_add(lp); + write_unlock(&fcoe_hostlist_lock); lp->boot_time = jiffies; @@ -1720,6 +1730,8 @@ int fcoe_reset(struct Scsi_Host *shost) * fcoe_hostlist_lookup_softc() - find the corresponding lport by a given device * @dev: this is currently ptr to net_device * + * Called with fcoe_hostlist_lock held. + * * Returns: NULL or the located fcoe_softc */ static struct fcoe_softc * @@ -1727,14 +1739,10 @@ fcoe_hostlist_lookup_softc(const struct net_device *dev) { struct fcoe_softc *fc; - read_lock(&fcoe_hostlist_lock); list_for_each_entry(fc, &fcoe_hostlist, list) { - if (fc->real_dev == dev) { - read_unlock(&fcoe_hostlist_lock); + if (fc->real_dev == dev) return fc; - } } - read_unlock(&fcoe_hostlist_lock); return NULL; } @@ -1748,7 +1756,9 @@ struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) { struct fcoe_softc *fc; + read_lock(&fcoe_hostlist_lock); fc = fcoe_hostlist_lookup_softc(netdev); + read_unlock(&fcoe_hostlist_lock); return (fc) ? fc->ctlr.lp : NULL; } @@ -1757,6 +1767,8 @@ struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) * fcoe_hostlist_add() - Add a lport to lports list * @lp: ptr to the fc_lport to be added * + * Called with write fcoe_hostlist_lock held. + * * Returns: 0 for success */ int fcoe_hostlist_add(const struct fc_lport *lp) @@ -1766,9 +1778,7 @@ int fcoe_hostlist_add(const struct fc_lport *lp) fc = fcoe_hostlist_lookup_softc(fcoe_netdev(lp)); if (!fc) { fc = lport_priv(lp); - write_lock_bh(&fcoe_hostlist_lock); list_add_tail(&fc->list, &fcoe_hostlist); - write_unlock_bh(&fcoe_hostlist_lock); } return 0; } @@ -1783,9 +1793,9 @@ int fcoe_hostlist_remove(const struct fc_lport *lp) { struct fcoe_softc *fc; + write_lock_bh(&fcoe_hostlist_lock); fc = fcoe_hostlist_lookup_softc(fcoe_netdev(lp)); BUG_ON(!fc); - write_lock_bh(&fcoe_hostlist_lock); list_del(&fc->list); write_unlock_bh(&fcoe_hostlist_lock); -- cgit v1.2.3-18-g5258 From d7179680d04f1e196b7a5f70e7f93bb1850407c6 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Wed, 29 Jul 2009 17:05:21 -0700 Subject: [SCSI] fcoe, libfc: adds offload EM per eth device with only single xid range per EM Updates fcoe_em_config to allocate a single instance of sharable offload EM for supported lp->lro_xid per eth device, and then share this EM for subsequently more lports creation on same eth device (e.g when using VLAN). Adds tiny fcoe_oem_match function for offload EM to return true for read types IO to have read IO exchanges allocated from offload shared EM. Removes fc_em_alloc_xid function completely which was needed to manage two xid ranges within a EM, this is not needed any more with allocation of separate sharable offload EM per eth device. Instead this patch adds simple xid allocation logic to manage single xid range. Adds fc_exch_em_alloc with mp->next_xid as cursor to allocate new xid from single xid range of EM, uses mp->next_xid instead removed mp->last_xid which slightly increase probability of finding empty xid on exch allocation. Removes restriction of not allowing use of xid zero along with changing two xid range change to single xid range. Makes fc_fcp_ddp_setup calling conditional to only xid allocated from shared offload EM. Signed-off-by: Vasu Dev Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 67 ++++++++++++++++++++++++++++++- drivers/scsi/fcoe/fcoe.h | 3 +- drivers/scsi/libfc/fc_exch.c | 94 +++++++++----------------------------------- 3 files changed, 85 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 86410b9a30c..0306aa95eb3 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -415,6 +415,17 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost, return 0; } +/* + * fcoe_oem_match() - match for read types IO + * @fp: the fc_frame for new IO. + * + * Returns : true for read types IO, otherwise returns false. + */ +bool fcoe_oem_match(struct fc_frame *fp) +{ + return fc_fcp_is_read(fr_fsp(fp)); +} + /** * fcoe_em_config() - allocates em for this lport * @lp: the port that em is to allocated for @@ -425,9 +436,61 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost, */ static inline int fcoe_em_config(struct fc_lport *lp) { - if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCOE_MIN_XID, - FCOE_MAX_XID, NULL)) + struct fcoe_softc *fc = lport_priv(lp); + struct fcoe_softc *oldfc = NULL; + u16 min_xid = FCOE_MIN_XID; + u16 max_xid = FCOE_MAX_XID; + + /* + * Check if need to allocate an em instance for + * offload exchange ids to be shared across all VN_PORTs/lport. + */ + if (!lp->lro_enabled || !lp->lro_xid || (lp->lro_xid >= max_xid)) { + lp->lro_xid = 0; + goto skip_oem; + } + + /* + * Reuse existing offload em instance in case + * it is already allocated on phys_dev. + */ + list_for_each_entry(oldfc, &fcoe_hostlist, list) { + if (oldfc->phys_dev == fc->phys_dev) { + fc->oem = oldfc->oem; + break; + } + } + + if (fc->oem) { + if (!fc_exch_mgr_add(lp, fc->oem, fcoe_oem_match)) { + printk(KERN_ERR "fcoe_em_config: failed to add " + "offload em:%p on interface:%s\n", + fc->oem, fc->real_dev->name); + return -ENOMEM; + } + } else { + fc->oem = fc_exch_mgr_alloc(lp, FC_CLASS_3, + FCOE_MIN_XID, lp->lro_xid, + fcoe_oem_match); + if (!fc->oem) { + printk(KERN_ERR "fcoe_em_config: failed to allocate " + "em for offload exches on interface:%s\n", + fc->real_dev->name); + return -ENOMEM; + } + } + + /* + * Exclude offload EM xid range from next EM xid range. + */ + min_xid += lp->lro_xid + 1; + +skip_oem: + if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, min_xid, max_xid, NULL)) { + printk(KERN_ERR "fcoe_em_config: failed to " + "allocate em on interface %s\n", fc->real_dev->name); return -ENOMEM; + } return 0; } diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index 0d724fa0898..6905efc166b 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h @@ -37,7 +37,7 @@ #define FCOE_MAX_OUTSTANDING_COMMANDS 1024 -#define FCOE_MIN_XID 0x0001 /* the min xid supported by fcoe_sw */ +#define FCOE_MIN_XID 0x0000 /* the min xid supported by fcoe_sw */ #define FCOE_MAX_XID 0x07ef /* the max xid supported by fcoe_sw */ unsigned int fcoe_debug_logging; @@ -81,6 +81,7 @@ struct fcoe_softc { struct list_head list; struct net_device *real_dev; struct net_device *phys_dev; /* device with ethtool_ops */ + struct fc_exch_mgr *oem; /* offload exchange manger */ struct packet_type fcoe_packet_type; struct packet_type fip_packet_type; struct sk_buff_head fcoe_pending_queue; diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 324589a5cc0..11ddd115efb 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -58,7 +58,7 @@ struct fc_exch_mgr { struct kref kref; /* exchange mgr reference count */ spinlock_t em_lock; /* exchange manager lock, must be taken before ex_lock */ - u16 last_xid; /* last allocated exchange ID */ + u16 next_xid; /* next possible free exchange ID */ u16 min_xid; /* min exchange ID */ u16 max_xid; /* max exchange ID */ u16 max_read; /* max exchange ID for read */ @@ -464,68 +464,21 @@ static struct fc_seq *fc_seq_alloc(struct fc_exch *ep, u8 seq_id) return sp; } -/* - * fc_em_alloc_xid - returns an xid based on request type - * @lp : ptr to associated lport - * @fp : ptr to the assocated frame - * - * check the associated fc_fsp_pkt to get scsi command type and - * command direction to decide from which range this exch id - * will be allocated from. - * - * Returns : 0 or an valid xid - */ -static u16 fc_em_alloc_xid(struct fc_exch_mgr *mp, const struct fc_frame *fp) -{ - u16 xid, min, max; - u16 *plast; - struct fc_exch *ep = NULL; - - if (mp->max_read) { - if (fc_fcp_is_read(fr_fsp(fp))) { - min = mp->min_xid; - max = mp->max_read; - plast = &mp->last_read; - } else { - min = mp->max_read + 1; - max = mp->max_xid; - plast = &mp->last_xid; - } - } else { - min = mp->min_xid; - max = mp->max_xid; - plast = &mp->last_xid; - } - xid = *plast; - do { - xid = (xid == max) ? min : xid + 1; - ep = mp->exches[xid - mp->min_xid]; - } while ((ep != NULL) && (xid != *plast)); - - if (unlikely(ep)) - xid = 0; - else - *plast = xid; - - return xid; -} - /** * fc_exch_em_alloc() - allocate an exchange from a specified EM. * @lport: ptr to the local port * @mp: ptr to the exchange manager - * @fp: ptr to the FC frame - * @xid: input xid * - * if xid is supplied zero then assign next free exchange ID - * from exchange manager, otherwise use supplied xid. - * Returns with exch lock held. + * Returns pointer to allocated fc_exch with exch lock held. */ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, - struct fc_exch_mgr *mp, - struct fc_frame *fp, u16 xid) + struct fc_exch_mgr *mp) { struct fc_exch *ep; + u16 min, max, xid; + + min = mp->min_xid; + max = mp->max_xid; /* allocate memory for exchange */ ep = mempool_alloc(mp->ep_pool, GFP_ATOMIC); @@ -536,15 +489,14 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, memset(ep, 0, sizeof(*ep)); spin_lock_bh(&mp->em_lock); - /* alloc xid if input xid 0 */ - if (!xid) { - /* alloc a new xid */ - xid = fc_em_alloc_xid(mp, fp); - if (!xid) { - printk(KERN_WARNING "libfc: Failed to allocate an exhange\n"); + xid = mp->next_xid; + /* alloc a new xid */ + while (mp->exches[xid - min]) { + xid = (xid == max) ? min : xid + 1; + if (xid == mp->next_xid) goto err; - } } + mp->next_xid = (xid == max) ? min : xid + 1; fc_exch_hold(ep); /* hold for exch in mp */ spin_lock_init(&ep->ex_lock); @@ -597,7 +549,7 @@ struct fc_exch *fc_exch_alloc(struct fc_lport *lport, struct fc_frame *fp) list_for_each_entry(ema, &lport->ema_list, ema_list) { if (!ema->match || ema->match(fp)) { - ep = fc_exch_em_alloc(lport, ema->mp, fp, 0); + ep = fc_exch_em_alloc(lport, ema->mp); if (ep) return ep; } @@ -1817,7 +1769,7 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, struct fc_exch_mgr *mp; size_t len; - if (max_xid <= min_xid || min_xid == 0 || max_xid == FC_XID_UNKNOWN) { + if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN) { FC_LPORT_DBG(lp, "Invalid min_xid 0x:%x and max_xid 0x:%x\n", min_xid, max_xid); return NULL; @@ -1826,7 +1778,6 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, /* * Memory need for EM */ -#define xid_ok(i, m1, m2) (((i) >= (m1)) && ((i) <= (m2))) len = (max_xid - min_xid + 1) * (sizeof(struct fc_exch *)); len += sizeof(struct fc_exch_mgr); @@ -1840,17 +1791,7 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, /* adjust em exch xid range for offload */ mp->min_xid = min_xid; mp->max_xid = max_xid; - mp->last_xid = min_xid - 1; - mp->max_read = 0; - mp->last_read = 0; - if (lp->lro_enabled && xid_ok(lp->lro_xid, min_xid, max_xid)) { - mp->max_read = lp->lro_xid; - mp->last_read = min_xid - 1; - mp->last_xid = mp->max_read; - } else { - /* disable lro if no xid control over read */ - lp->lro_enabled = 0; - } + mp->next_xid = min_xid; INIT_LIST_HEAD(&mp->ex_list); spin_lock_init(&mp->em_lock); @@ -1922,7 +1863,8 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, fc_exch_setup_hdr(ep, fp, ep->f_ctl); sp->cnt++; - fc_fcp_ddp_setup(fr_fsp(fp), ep->xid); + if (ep->xid <= lp->lro_xid) + fc_fcp_ddp_setup(fr_fsp(fp), ep->xid); if (unlikely(lp->tt.frame_send(lp, fp))) goto err; -- cgit v1.2.3-18-g5258 From 15a521b4243f3d61971f8422f3e514ef009a42b8 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Wed, 29 Jul 2009 17:05:26 -0700 Subject: [SCSI] fcoe: Remove ifdef for NETIF_F_FCOE_CRC and NETIF_F_FSO Remove the extra ifdef for NETIF_F_FSO and NETIF_F_FCOE_CRC since they are already defined in the current kernel as in include/linux/netdevice.h. Signed-off-by: Yi Zou Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 0306aa95eb3..ad21e87e400 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -300,20 +300,16 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) if (fc->real_dev->features & NETIF_F_SG) lp->sg_supp = 1; -#ifdef NETIF_F_FCOE_CRC if (netdev->features & NETIF_F_FCOE_CRC) { lp->crc_offload = 1; FCOE_NETDEV_DBG(netdev, "Supports FCCRC offload\n"); } -#endif -#ifdef NETIF_F_FSO if (netdev->features & NETIF_F_FSO) { lp->seq_offload = 1; lp->lso_max = netdev->gso_max_size; FCOE_NETDEV_DBG(netdev, "Supports LSO for max len 0x%x\n", lp->lso_max); } -#endif if (netdev->fcoe_ddp_xid) { lp->lro_enabled = 1; lp->lro_xid = netdev->fcoe_ddp_xid; @@ -1205,7 +1201,6 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER); hp->fcoe_sof = sof; -#ifdef NETIF_F_FSO /* fcoe lso, mss is in max_payload which is non-zero for FCP data */ if (lp->seq_offload && fr_max_payload(fp)) { skb_shinfo(skb)->gso_type = SKB_GSO_FCOE; @@ -1214,7 +1209,6 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) skb_shinfo(skb)->gso_type = 0; skb_shinfo(skb)->gso_size = 0; } -#endif /* update tx stats: regardless if LLD fails */ stats = fc_lport_get_stats(lp); stats->TxFrames++; -- cgit v1.2.3-18-g5258 From 537029f8e950776951ca2a3fe30121d5c05643d1 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Wed, 29 Jul 2009 17:05:32 -0700 Subject: [SCSI] libfc: Remove FC_FRAME_SG_LEN in fc_fcp_send_data FC_FRAME_SG_LEN is 4 which is too small when offload is enabled. Actually, the WARN_ON() in fc_fcp_send_data() should be: WARN_ON(skb_shinfo(fp_skb(fp))->nr_frags > MAX_SKB_FRAGS); But since we will not get anything more than 64K anyway, so there is no need to do this anyway here. Therefore, I am getting rid of FC_FRAME_SG_LEN here and the WARN_ON here. Signed-off-by: Yi Zou Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_fcp.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index e303e0d12c4..2069edf8026 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -569,8 +569,6 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq, } sg_bytes = min(tlen, sg->length - offset); if (using_sg) { - WARN_ON(skb_shinfo(fp_skb(fp))->nr_frags > - FC_FRAME_SG_LEN); get_page(sg_page(sg)); skb_fill_page_desc(fp_skb(fp), skb_shinfo(fp_skb(fp))->nr_frags, -- cgit v1.2.3-18-g5258 From 53fcfbbef569819706b880a502ff62e2852edfce Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Wed, 29 Jul 2009 17:05:40 -0700 Subject: [SCSI] libfc: Remove page flags check for sglist I don't believe this check is needed any more in the current kernel, which, if I understand correctly, is for compound page where only the first page is supposed to get ref-counted. Signed-off-by: Yi Zou Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_fcp.c | 27 --------------------------- 1 file changed, 27 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 2069edf8026..7d5ffcbbf39 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -507,33 +507,6 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq, f_ctl = FC_FC_REL_OFF; WARN_ON(!seq); - /* - * If a get_page()/put_page() will fail, don't use sg lists - * in the fc_frame structure. - * - * The put_page() may be long after the I/O has completed - * in the case of FCoE, since the network driver does it - * via free_skb(). See the test in free_pages_check(). - * - * Test this case with 'dd /dev/st0 bs=64k'. - */ - if (using_sg) { - for (sg = scsi_sglist(sc); sg; sg = sg_next(sg)) { - if (page_count(sg_page(sg)) == 0 || - (sg_page(sg)->flags & (1 << PG_lru | - 1 << PG_private | - 1 << PG_locked | - 1 << PG_active | - 1 << PG_slab | - 1 << PG_swapcache | - 1 << PG_writeback | - 1 << PG_reserved | - 1 << PG_buddy))) { - using_sg = 0; - break; - } - } - } sg = scsi_sglist(sc); while (remaining > 0 && sg) { -- cgit v1.2.3-18-g5258 From 1d1b88dc01e5fd2b3e2abb7aa42d0f1eca4c33ea Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Wed, 29 Jul 2009 17:05:45 -0700 Subject: [SCSI] fcoe: removes phys_dev and renames real_dev to netdev. The phys_dev was used only to locate common offload EM instance for all FCoE instances on a eth devices in function fcoe_em_config, so just updated fcoe_em_config to look for actual real eth device in locating common offload EM instance and then no need to store phys_dev in fcoe_softc, so removes phys_dev from fcoe_softc also. Renames fcoe_softc real_dev to netdev and updates all its uses to use netdev. So effectively no functional change, use of single netdev instead phys_dev and real_dev saves one pointer memory in fcoe_softc, also real_dev used here was confusing with vlan driver terminology since real_dev in vlan driver is referred to physical eth device. Signed-off-by: Vasu Dev Signed-off-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 93 +++++++++++++++++++++++++----------------------- drivers/scsi/fcoe/fcoe.h | 5 ++- 2 files changed, 51 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index ad21e87e400..757aa28f0f0 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -159,7 +159,7 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev, */ static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) { - skb->dev = fcoe_from_ctlr(fip)->real_dev; + skb->dev = fcoe_from_ctlr(fip)->netdev; dev_queue_xmit(skb); } @@ -179,8 +179,8 @@ static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new) fc = fcoe_from_ctlr(fip); rtnl_lock(); if (!is_zero_ether_addr(old)) - dev_unicast_delete(fc->real_dev, old); - dev_unicast_add(fc->real_dev, new); + dev_unicast_delete(fc->netdev, old); + dev_unicast_add(fc->netdev, new); rtnl_unlock(); } @@ -231,12 +231,12 @@ void fcoe_netdev_cleanup(struct fcoe_softc *fc) /* Delete secondary MAC addresses */ rtnl_lock(); memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); - dev_unicast_delete(fc->real_dev, flogi_maddr); + dev_unicast_delete(fc->netdev, flogi_maddr); if (!is_zero_ether_addr(fc->ctlr.data_src_addr)) - dev_unicast_delete(fc->real_dev, fc->ctlr.data_src_addr); + dev_unicast_delete(fc->netdev, fc->ctlr.data_src_addr); if (fc->ctlr.spma) - dev_unicast_delete(fc->real_dev, fc->ctlr.ctl_src_addr); - dev_mc_delete(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); + dev_unicast_delete(fc->netdev, fc->ctlr.ctl_src_addr); + dev_mc_delete(fc->netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); rtnl_unlock(); } @@ -272,17 +272,12 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) /* Setup lport private data to point to fcoe softc */ fc = lport_priv(lp); fc->ctlr.lp = lp; - fc->real_dev = netdev; - fc->phys_dev = netdev; - - /* Require support for get_pauseparam ethtool op. */ - if (netdev->priv_flags & IFF_802_1Q_VLAN) - fc->phys_dev = vlan_dev_real_dev(netdev); + fc->netdev = netdev; /* Do not support for bonding device */ - if ((fc->real_dev->priv_flags & IFF_MASTER_ALB) || - (fc->real_dev->priv_flags & IFF_SLAVE_INACTIVE) || - (fc->real_dev->priv_flags & IFF_MASTER_8023AD)) { + if ((netdev->priv_flags & IFF_MASTER_ALB) || + (netdev->priv_flags & IFF_SLAVE_INACTIVE) || + (netdev->priv_flags & IFF_MASTER_8023AD)) { return -EOPNOTSUPP; } @@ -291,13 +286,13 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) * user-configured limit. If the MFS is too low, fcoe_link_ok() * will return 0, so do this first. */ - mfs = fc->real_dev->mtu - (sizeof(struct fcoe_hdr) + - sizeof(struct fcoe_crc_eof)); + mfs = netdev->mtu - (sizeof(struct fcoe_hdr) + + sizeof(struct fcoe_crc_eof)); if (fc_set_mfs(lp, mfs)) return -EINVAL; /* offload features support */ - if (fc->real_dev->features & NETIF_F_SG) + if (netdev->features & NETIF_F_SG) lp->sg_supp = 1; if (netdev->features & NETIF_F_FCOE_CRC) { @@ -335,13 +330,13 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) /* setup Source Mac Address */ if (!fc->ctlr.spma) - memcpy(fc->ctlr.ctl_src_addr, fc->real_dev->dev_addr, - fc->real_dev->addr_len); + memcpy(fc->ctlr.ctl_src_addr, netdev->dev_addr, + fc->netdev->addr_len); - wwnn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 1, 0); + wwnn = fcoe_wwn_from_mac(netdev->dev_addr, 1, 0); fc_set_wwnn(lp, wwnn); /* XXX - 3rd arg needs to be vlan id */ - wwpn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 2, 0); + wwpn = fcoe_wwn_from_mac(netdev->dev_addr, 2, 0); fc_set_wwpn(lp, wwpn); /* @@ -351,10 +346,10 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) */ rtnl_lock(); memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); - dev_unicast_add(fc->real_dev, flogi_maddr); + dev_unicast_add(netdev, flogi_maddr); if (fc->ctlr.spma) - dev_unicast_add(fc->real_dev, fc->ctlr.ctl_src_addr); - dev_mc_add(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); + dev_unicast_add(netdev, fc->ctlr.ctl_src_addr); + dev_mc_add(netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); rtnl_unlock(); /* @@ -363,12 +358,12 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) */ fc->fcoe_packet_type.func = fcoe_rcv; fc->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); - fc->fcoe_packet_type.dev = fc->real_dev; + fc->fcoe_packet_type.dev = netdev; dev_add_pack(&fc->fcoe_packet_type); fc->fip_packet_type.func = fcoe_fip_recv; fc->fip_packet_type.type = htons(ETH_P_FIP); - fc->fip_packet_type.dev = fc->real_dev; + fc->fip_packet_type.dev = netdev; dev_add_pack(&fc->fip_packet_type); return 0; @@ -434,6 +429,7 @@ static inline int fcoe_em_config(struct fc_lport *lp) { struct fcoe_softc *fc = lport_priv(lp); struct fcoe_softc *oldfc = NULL; + struct net_device *old_real_dev, *cur_real_dev; u16 min_xid = FCOE_MIN_XID; u16 max_xid = FCOE_MAX_XID; @@ -448,10 +444,20 @@ static inline int fcoe_em_config(struct fc_lport *lp) /* * Reuse existing offload em instance in case - * it is already allocated on phys_dev. + * it is already allocated on real eth device */ + if (fc->netdev->priv_flags & IFF_802_1Q_VLAN) + cur_real_dev = vlan_dev_real_dev(fc->netdev); + else + cur_real_dev = fc->netdev; + list_for_each_entry(oldfc, &fcoe_hostlist, list) { - if (oldfc->phys_dev == fc->phys_dev) { + if (oldfc->netdev->priv_flags & IFF_802_1Q_VLAN) + old_real_dev = vlan_dev_real_dev(oldfc->netdev); + else + old_real_dev = oldfc->netdev; + + if (cur_real_dev == old_real_dev) { fc->oem = oldfc->oem; break; } @@ -461,7 +467,7 @@ static inline int fcoe_em_config(struct fc_lport *lp) if (!fc_exch_mgr_add(lp, fc->oem, fcoe_oem_match)) { printk(KERN_ERR "fcoe_em_config: failed to add " "offload em:%p on interface:%s\n", - fc->oem, fc->real_dev->name); + fc->oem, fc->netdev->name); return -ENOMEM; } } else { @@ -471,7 +477,7 @@ static inline int fcoe_em_config(struct fc_lport *lp) if (!fc->oem) { printk(KERN_ERR "fcoe_em_config: failed to allocate " "em for offload exches on interface:%s\n", - fc->real_dev->name); + fc->netdev->name); return -ENOMEM; } } @@ -484,7 +490,7 @@ static inline int fcoe_em_config(struct fc_lport *lp) skip_oem: if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, min_xid, max_xid, NULL)) { printk(KERN_ERR "fcoe_em_config: failed to " - "allocate em on interface %s\n", fc->real_dev->name); + "allocate em on interface %s\n", fc->netdev->name); return -ENOMEM; } @@ -548,7 +554,7 @@ static int fcoe_if_destroy(struct net_device *netdev) fc_lport_free_stats(lp); /* Release the net_device and Scsi_Host */ - dev_put(fc->real_dev); + dev_put(netdev); scsi_host_put(lp->host); return 0; @@ -1179,7 +1185,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) skb_reset_network_header(skb); skb->mac_len = elen; skb->protocol = htons(ETH_P_FCOE); - skb->dev = fc->real_dev; + skb->dev = fc->netdev; /* fill up mac and fcoe headers */ eh = eth_hdr(skb); @@ -1454,7 +1460,7 @@ static int fcoe_device_notification(struct notifier_block *notifier, ulong event, void *ptr) { struct fc_lport *lp = NULL; - struct net_device *real_dev = ptr; + struct net_device *netdev = ptr; struct fcoe_softc *fc; struct fcoe_dev_stats *stats; u32 link_possible = 1; @@ -1463,7 +1469,7 @@ static int fcoe_device_notification(struct notifier_block *notifier, read_lock(&fcoe_hostlist_lock); list_for_each_entry(fc, &fcoe_hostlist, list) { - if (fc->real_dev == real_dev) { + if (fc->netdev == netdev) { lp = fc->ctlr.lp; break; } @@ -1483,16 +1489,15 @@ static int fcoe_device_notification(struct notifier_block *notifier, case NETDEV_CHANGE: break; case NETDEV_CHANGEMTU: - mfs = fc->real_dev->mtu - - (sizeof(struct fcoe_hdr) + - sizeof(struct fcoe_crc_eof)); + mfs = netdev->mtu - (sizeof(struct fcoe_hdr) + + sizeof(struct fcoe_crc_eof)); if (mfs >= FC_MIN_MAX_FRAME) fc_set_mfs(lp, mfs); break; case NETDEV_REGISTER: break; default: - FCOE_NETDEV_DBG(real_dev, "Unknown event %ld " + FCOE_NETDEV_DBG(netdev, "Unknown event %ld " "from netdev netlink\n", event); } if (link_possible && !fcoe_link_ok(lp)) @@ -1696,7 +1701,7 @@ MODULE_PARM_DESC(destroy, "Destroy fcoe port"); int fcoe_link_ok(struct fc_lport *lp) { struct fcoe_softc *fc = lport_priv(lp); - struct net_device *dev = fc->real_dev; + struct net_device *dev = fc->netdev; struct ethtool_cmd ecmd = { ETHTOOL_GSET }; if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) && @@ -1797,7 +1802,7 @@ fcoe_hostlist_lookup_softc(const struct net_device *dev) struct fcoe_softc *fc; list_for_each_entry(fc, &fcoe_hostlist, list) { - if (fc->real_dev == dev) + if (fc->netdev == dev) return fc; } return NULL; @@ -1916,7 +1921,7 @@ static void __exit fcoe_exit(void) /* releases the associated fcoe hosts */ list_for_each_entry_safe(fc, tmp, &fcoe_hostlist, list) - fcoe_if_destroy(fc->real_dev); + fcoe_if_destroy(fc->netdev); unregister_hotcpu_notifier(&fcoe_cpu_notifier); diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index 6905efc166b..5ae8ca71afc 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h @@ -79,8 +79,7 @@ struct fcoe_percpu_s { */ struct fcoe_softc { struct list_head list; - struct net_device *real_dev; - struct net_device *phys_dev; /* device with ethtool_ops */ + struct net_device *netdev; struct fc_exch_mgr *oem; /* offload exchange manger */ struct packet_type fcoe_packet_type; struct packet_type fip_packet_type; @@ -95,7 +94,7 @@ struct fcoe_softc { static inline struct net_device *fcoe_netdev( const struct fc_lport *lp) { - return ((struct fcoe_softc *)lport_priv(lp))->real_dev; + return ((struct fcoe_softc *)lport_priv(lp))->netdev; } #endif /* _FCOE_H_ */ -- cgit v1.2.3-18-g5258 From 534cc9c165017dd29ae0f4458832893dc8033c6f Mon Sep 17 00:00:00 2001 From: Anil Veerabhadrappa Date: Wed, 29 Jul 2009 21:49:48 -0700 Subject: [SCSI] bnx2i : Fix command session number jump issue seen during cable pull test Without the fix bnx2i would fail tt->xmit_task() when link is down and libiscsi would have already incremented session->cmdsn before calling bnx2i's xmit_task() entry point and will just return the command to SCSI-ML when xmit_task() fails. libiscsi does not retract the session->cmdsn as the command was never sent on wire. It is generally good idea for LLD, bnx2i to accept the scsi cmnd/nopout and let upper layer timeout and go though normal session recovery process. When link is down, unsolicited nopout will not be accepted by bnx2i and connection will never enter recovery state. This fix is required for MPIO to work corectly Signed-off-by: Anil Veerabhadrappa Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/bnx2i/bnx2i_iscsi.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index 98148f3f3c6..40120a242ef 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -1160,9 +1160,6 @@ static int bnx2i_task_xmit(struct iscsi_task *task) struct bnx2i_cmd *cmd = task->dd_data; struct iscsi_cmd *hdr = (struct iscsi_cmd *) task->hdr; - if (test_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state)) - return -ENOTCONN; - if (!bnx2i_conn->is_bound) return -ENOTCONN; -- cgit v1.2.3-18-g5258 From c19dcd011238118ad07d3ab7ed1bbc4916826324 Mon Sep 17 00:00:00 2001 From: Anil Veerabhadrappa Date: Wed, 29 Jul 2009 21:50:11 -0700 Subject: [SCSI] bnx2i : Fix "cid #n not valid" issue When bnx2i_adapter_ready() fails, connection handle(cid) = 0 is wrongly freed because 'cid' is not yet allocated for the endpoint. Fix is to initialize bnx2i_ep->ep_iscsi_cid to '-1' in bnx2i_alloc_ep() and not in bnx2i_ep_connect() to avoid releasing invalid 'cid'. There is already a check in bnx2i_free_iscsi_cid() not to free invalid iscsi connection handle (-1) Signed-off-by: Anil Veerabhadrappa Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/bnx2i/bnx2i_iscsi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index 40120a242ef..9a7ba71f1af 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -387,6 +387,7 @@ static struct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba) bnx2i_ep = ep->dd_data; INIT_LIST_HEAD(&bnx2i_ep->link); bnx2i_ep->state = EP_STATE_IDLE; + bnx2i_ep->ep_iscsi_cid = (u16) -1; bnx2i_ep->hba = hba; bnx2i_ep->hba_age = hba->age; hba->ofld_conns_active++; @@ -1681,8 +1682,6 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, goto net_if_down; } - bnx2i_ep->state = EP_STATE_IDLE; - bnx2i_ep->ep_iscsi_cid = (u16) -1; bnx2i_ep->num_active_cmds = 0; iscsi_cid = bnx2i_alloc_iscsi_cid(hba); if (iscsi_cid == -1) { -- cgit v1.2.3-18-g5258 From 0124ca9d8ee58b3cd028a23cef2fe225fcfee3b8 Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 30 Jul 2009 10:58:51 -0500 Subject: [SCSI] ipr: fix buffer overflow ipr_cmd_label[] isn't big enough for an eight byte string plus terminator. Fix by shortening the string to seven bytes. Signed-off-by: Brian King Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/ipr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 4b63dd6b1c8..163245a1c3e 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -1199,7 +1199,7 @@ struct ipr_ioa_cfg { struct ata_host ata_host; char ipr_cmd_label[8]; -#define IPR_CMD_LABEL "ipr_cmnd" +#define IPR_CMD_LABEL "ipr_cmd" struct ipr_cmnd *ipr_cmnd_list[IPR_NUM_CMD_BLKS]; u32 ipr_cmnd_list_dma[IPR_NUM_CMD_BLKS]; }; -- cgit v1.2.3-18-g5258 From 163f52b6cf3a639df6a72c7937e0eb88b20f1ef3 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sat, 1 Aug 2009 00:39:36 +0000 Subject: [SCSI] ses: fix hotplug with multiple devices and expanders In a situation either with expanders or with multiple enclosure devices, hot add doesn't always work. This is because we try to find a single enclosure device attached to the host. Fix this by looping over all enclosure devices attached to the host and also by making the find loop recognise that the enclosure devices may be expander remote (i.e. not parented by the host). Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/misc/enclosure.c | 44 ++++++++++++++++++++++++++++++++------------ drivers/scsi/ses.c | 10 ++++++---- 2 files changed, 38 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index 348443bdb23..789d12128c2 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -33,24 +33,44 @@ static DEFINE_MUTEX(container_list_lock); static struct class enclosure_class; /** - * enclosure_find - find an enclosure given a device - * @dev: the device to find for + * enclosure_find - find an enclosure given a parent device + * @dev: the parent to match against + * @start: Optional enclosure device to start from (NULL if none) * - * Looks through the list of registered enclosures to see - * if it can find a match for a device. Returns NULL if no - * enclosure is found. Obtains a reference to the enclosure class - * device which must be released with device_put(). + * Looks through the list of registered enclosures to find all those + * with @dev as a parent. Returns NULL if no enclosure is + * found. @start can be used as a starting point to obtain multiple + * enclosures per parent (should begin with NULL and then be set to + * each returned enclosure device). Obtains a reference to the + * enclosure class device which must be released with device_put(). + * If @start is not NULL, a reference must be taken on it which is + * released before returning (this allows a loop through all + * enclosures to exit with only the reference on the enclosure of + * interest held). Note that the @dev may correspond to the actual + * device housing the enclosure, in which case no iteration via @start + * is required. */ -struct enclosure_device *enclosure_find(struct device *dev) +struct enclosure_device *enclosure_find(struct device *dev, + struct enclosure_device *start) { struct enclosure_device *edev; mutex_lock(&container_list_lock); - list_for_each_entry(edev, &container_list, node) { - if (edev->edev.parent == dev) { - get_device(&edev->edev); - mutex_unlock(&container_list_lock); - return edev; + edev = list_prepare_entry(start, &container_list, node); + if (start) + put_device(&start->edev); + + list_for_each_entry_continue(edev, &container_list, node) { + struct device *parent = edev->edev.parent; + /* parent might not be immediate, so iterate up to + * the root of the tree if necessary */ + while (parent) { + if (parent == dev) { + get_device(&edev->edev); + mutex_unlock(&container_list_lock); + return edev; + } + parent = parent->parent; } } mutex_unlock(&container_list_lock); diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 4f618f48735..e1b8c828f03 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -413,10 +413,11 @@ static int ses_intf_add(struct device *cdev, if (!scsi_device_enclosure(sdev)) { /* not an enclosure, but might be in one */ - edev = enclosure_find(&sdev->host->shost_gendev); - if (edev) { + struct enclosure_device *prev = NULL; + + while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) { ses_match_to_enclosure(edev, sdev); - put_device(&edev->edev); + prev = edev; } return -ENODEV; } @@ -625,7 +626,8 @@ static void ses_intf_remove(struct device *cdev, if (!scsi_device_enclosure(sdev)) return; - edev = enclosure_find(cdev->parent); + /* exact match to this enclosure */ + edev = enclosure_find(cdev->parent, NULL); if (!edev) return; -- cgit v1.2.3-18-g5258 From 43d8eb9cfd0aea93be32181c64e18191b69c211c Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sat, 1 Aug 2009 00:41:22 +0000 Subject: [SCSI] ses: add support for enclosure component hot removal Right at the moment, hot removal of a device within an enclosure does nothing (because the intf_remove only copes with enclosure removal not with component removal). Fix this by adding a function to remove the component. Also needed to fix the prototype of enclosure_remove_device, since we know the device we've removed but not the internal component number Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/misc/enclosure.c | 22 ++++++++++++++-------- drivers/scsi/ses.c | 33 ++++++++++++++++++++++++++------- 2 files changed, 40 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index 789d12128c2..850706a5e55 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -332,19 +332,25 @@ EXPORT_SYMBOL_GPL(enclosure_add_device); * Returns zero on success or an error. * */ -int enclosure_remove_device(struct enclosure_device *edev, int component) +int enclosure_remove_device(struct enclosure_device *edev, struct device *dev) { struct enclosure_component *cdev; + int i; - if (!edev || component >= edev->components) + if (!edev || !dev) return -EINVAL; - cdev = &edev->component[component]; - - device_del(&cdev->cdev); - put_device(cdev->dev); - cdev->dev = NULL; - return device_add(&cdev->cdev); + for (i = 0; i < edev->components; i++) { + cdev = &edev->component[i]; + if (cdev->dev == dev) { + enclosure_remove_links(cdev); + device_del(&cdev->cdev); + put_device(dev); + cdev->dev = NULL; + return device_add(&cdev->cdev); + } + } + return -ENODEV; } EXPORT_SYMBOL_GPL(enclosure_remove_device); diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index e1b8c828f03..be593c8525b 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -616,18 +616,26 @@ static int ses_remove(struct device *dev) return 0; } -static void ses_intf_remove(struct device *cdev, - struct class_interface *intf) +static void ses_intf_remove_component(struct scsi_device *sdev) +{ + struct enclosure_device *edev, *prev = NULL; + + while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) { + prev = edev; + if (!enclosure_remove_device(edev, &sdev->sdev_gendev)) + break; + } + if (edev) + put_device(&edev->edev); +} + +static void ses_intf_remove_enclosure(struct scsi_device *sdev) { - struct scsi_device *sdev = to_scsi_device(cdev->parent); struct enclosure_device *edev; struct ses_device *ses_dev; - if (!scsi_device_enclosure(sdev)) - return; - /* exact match to this enclosure */ - edev = enclosure_find(cdev->parent, NULL); + edev = enclosure_find(&sdev->sdev_gendev, NULL); if (!edev) return; @@ -645,6 +653,17 @@ static void ses_intf_remove(struct device *cdev, enclosure_unregister(edev); } +static void ses_intf_remove(struct device *cdev, + struct class_interface *intf) +{ + struct scsi_device *sdev = to_scsi_device(cdev->parent); + + if (!scsi_device_enclosure(sdev)) + ses_intf_remove_component(sdev); + else + ses_intf_remove_enclosure(sdev); +} + static struct class_interface ses_interface = { .add_dev = ses_intf_add, .remove_dev = ses_intf_remove, -- cgit v1.2.3-18-g5258 From 21fab1d0595eacf781705ec3509012a28f298245 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sat, 1 Aug 2009 00:43:59 +0000 Subject: [SCSI] ses: update enclosure data on hot add Now that hot add works correctly, if a new device is added, we're still operating on stale enclosure data, so fix that by updating the enclosure diagnostic pages when we get notified of a device hot add Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/misc/enclosure.c | 3 + drivers/scsi/ses.c | 168 +++++++++++++++++++++++++++-------------------- 2 files changed, 100 insertions(+), 71 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index 850706a5e55..7b039306037 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -315,6 +315,9 @@ int enclosure_add_device(struct enclosure_device *edev, int component, cdev = &edev->component[component]; + if (cdev->dev == dev) + return -EEXIST; + if (cdev->dev) enclosure_remove_links(cdev); diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index be593c8525b..55b034b7270 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -347,6 +347,97 @@ static int ses_enclosure_find_by_addr(struct enclosure_device *edev, return 0; } +#define INIT_ALLOC_SIZE 32 + +static void ses_enclosure_data_process(struct enclosure_device *edev, + struct scsi_device *sdev, + int create) +{ + u32 result; + unsigned char *buf = NULL, *type_ptr, *desc_ptr, *addl_desc_ptr = NULL; + int i, j, page7_len, len, components; + struct ses_device *ses_dev = edev->scratch; + int types = ses_dev->page1[10]; + unsigned char *hdr_buf = kzalloc(INIT_ALLOC_SIZE, GFP_KERNEL); + + if (!hdr_buf) + goto simple_populate; + + /* re-read page 10 */ + if (ses_dev->page10) + ses_recv_diag(sdev, 10, ses_dev->page10, ses_dev->page10_len); + /* Page 7 for the descriptors is optional */ + result = ses_recv_diag(sdev, 7, hdr_buf, INIT_ALLOC_SIZE); + if (result) + goto simple_populate; + + page7_len = len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; + /* add 1 for trailing '\0' we'll use */ + buf = kzalloc(len + 1, GFP_KERNEL); + if (!buf) + goto simple_populate; + result = ses_recv_diag(sdev, 7, buf, len); + if (result) { + simple_populate: + kfree(buf); + buf = NULL; + desc_ptr = NULL; + len = 0; + page7_len = 0; + } else { + desc_ptr = buf + 8; + len = (desc_ptr[2] << 8) + desc_ptr[3]; + /* skip past overall descriptor */ + desc_ptr += len + 4; + if (ses_dev->page10) + addl_desc_ptr = ses_dev->page10 + 8; + } + type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; + components = 0; + for (i = 0; i < types; i++, type_ptr += 4) { + for (j = 0; j < type_ptr[1]; j++) { + char *name = NULL; + struct enclosure_component *ecomp; + + if (desc_ptr) { + if (desc_ptr >= buf + page7_len) { + desc_ptr = NULL; + } else { + len = (desc_ptr[2] << 8) + desc_ptr[3]; + desc_ptr += 4; + /* Add trailing zero - pushes into + * reserved space */ + desc_ptr[len] = '\0'; + name = desc_ptr; + } + } + if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || + type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) { + + if (create) + ecomp = enclosure_component_register(edev, + components++, + type_ptr[0], + name); + else + ecomp = &edev->component[components++]; + + if (!IS_ERR(ecomp) && addl_desc_ptr) + ses_process_descriptor(ecomp, + addl_desc_ptr); + } + if (desc_ptr) + desc_ptr += len; + + if (addl_desc_ptr) + addl_desc_ptr += addl_desc_ptr[1] + 2; + + } + } + kfree(buf); + kfree(hdr_buf); +} + static void ses_match_to_enclosure(struct enclosure_device *edev, struct scsi_device *sdev) { @@ -361,6 +452,8 @@ static void ses_match_to_enclosure(struct enclosure_device *edev, if (!buf) return; + ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0); + vpd_len = ((buf[2] << 8) | buf[3]) + 4; desc = buf + 4; @@ -395,18 +488,15 @@ static void ses_match_to_enclosure(struct enclosure_device *edev, kfree(buf); } -#define INIT_ALLOC_SIZE 32 - static int ses_intf_add(struct device *cdev, struct class_interface *intf) { struct scsi_device *sdev = to_scsi_device(cdev->parent); struct scsi_device *tmp_sdev; - unsigned char *buf = NULL, *hdr_buf, *type_ptr, *desc_ptr = NULL, - *addl_desc_ptr = NULL; + unsigned char *buf = NULL, *hdr_buf, *type_ptr; struct ses_device *ses_dev; u32 result; - int i, j, types, len, page7_len = 0, components = 0; + int i, types, len, components = 0; int err = -ENOMEM; struct enclosure_device *edev; struct ses_component *scomp = NULL; @@ -501,6 +591,7 @@ static int ses_intf_add(struct device *cdev, ses_dev->page10_len = len; buf = NULL; } + kfree(hdr_buf); scomp = kzalloc(sizeof(struct ses_component) * components, GFP_KERNEL); if (!scomp) @@ -517,72 +608,7 @@ static int ses_intf_add(struct device *cdev, for (i = 0; i < components; i++) edev->component[i].scratch = scomp + i; - /* Page 7 for the descriptors is optional */ - result = ses_recv_diag(sdev, 7, hdr_buf, INIT_ALLOC_SIZE); - if (result) - goto simple_populate; - - page7_len = len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; - /* add 1 for trailing '\0' we'll use */ - buf = kzalloc(len + 1, GFP_KERNEL); - if (!buf) - goto simple_populate; - result = ses_recv_diag(sdev, 7, buf, len); - if (result) { - simple_populate: - kfree(buf); - buf = NULL; - desc_ptr = NULL; - addl_desc_ptr = NULL; - } else { - desc_ptr = buf + 8; - len = (desc_ptr[2] << 8) + desc_ptr[3]; - /* skip past overall descriptor */ - desc_ptr += len + 4; - if (ses_dev->page10) - addl_desc_ptr = ses_dev->page10 + 8; - } - type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; - components = 0; - for (i = 0; i < types; i++, type_ptr += 4) { - for (j = 0; j < type_ptr[1]; j++) { - char *name = NULL; - struct enclosure_component *ecomp; - - if (desc_ptr) { - if (desc_ptr >= buf + page7_len) { - desc_ptr = NULL; - } else { - len = (desc_ptr[2] << 8) + desc_ptr[3]; - desc_ptr += 4; - /* Add trailing zero - pushes into - * reserved space */ - desc_ptr[len] = '\0'; - name = desc_ptr; - } - } - if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || - type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) { - - ecomp = enclosure_component_register(edev, - components++, - type_ptr[0], - name); - - if (!IS_ERR(ecomp) && addl_desc_ptr) - ses_process_descriptor(ecomp, - addl_desc_ptr); - } - if (desc_ptr) - desc_ptr += len; - - if (addl_desc_ptr) - addl_desc_ptr += addl_desc_ptr[1] + 2; - - } - } - kfree(buf); - kfree(hdr_buf); + ses_enclosure_data_process(edev, sdev, 1); /* see if there are any devices matching before * we found the enclosure */ -- cgit v1.2.3-18-g5258 From 18ee70c9d7b2dcd312a1f8c6536841e7c0fea5ca Mon Sep 17 00:00:00 2001 From: Chandra Seetharaman Date: Mon, 3 Aug 2009 12:42:33 -0700 Subject: [SCSI] scsi_dh: add the interface scsi_dh_set_params() When we moved the device handler functionality from dm layer to SCSI layer we dropped the parameter functionality. This path adds an interface to scsi dh layer to set device handler parameters. Basically, multipath layer need to create a string with all the parameters and call scsi_dh_set_params() after it called scsi_dh_attach() on a device. If a device handler provides such an interface it will handle the parameters as it expects them. Reported-by: Eddie Williams Signed-off-by: Chandra Seetharaman Tested-by: Eddie Williams Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/device_handler/scsi_dh.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index 53a7385e1b4..3ee1cbc8947 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c @@ -451,6 +451,39 @@ int scsi_dh_activate(struct request_queue *q) } EXPORT_SYMBOL_GPL(scsi_dh_activate); +/* + * scsi_dh_set_params - set the parameters for the device as per the + * string specified in params. + * @q - Request queue that is associated with the scsi_device for + * which the parameters to be set. + * @params - parameters in the following format + * "no_of_params\0param1\0param2\0param3\0...\0" + * for example, string for 2 parameters with value 10 and 21 + * is specified as "2\010\021\0". + */ +int scsi_dh_set_params(struct request_queue *q, const char *params) +{ + int err = -SCSI_DH_NOSYS; + unsigned long flags; + struct scsi_device *sdev; + struct scsi_device_handler *scsi_dh = NULL; + + spin_lock_irqsave(q->queue_lock, flags); + sdev = q->queuedata; + if (sdev && sdev->scsi_dh_data) + scsi_dh = sdev->scsi_dh_data->scsi_dh; + if (scsi_dh && scsi_dh->set_params && get_device(&sdev->sdev_gendev)) + err = 0; + spin_unlock_irqrestore(q->queue_lock, flags); + + if (err) + return err; + err = scsi_dh->set_params(sdev, params); + put_device(&sdev->sdev_gendev); + return err; +} +EXPORT_SYMBOL_GPL(scsi_dh_set_params); + /* * scsi_dh_handler_exist - Return TRUE(1) if a device handler exists for * the given name. FALSE(0) otherwise. -- cgit v1.2.3-18-g5258 From 14d9cb5f760c86b3a8f686909465982231c06627 Mon Sep 17 00:00:00 2001 From: Chandra Seetharaman Date: Mon, 3 Aug 2009 12:42:39 -0700 Subject: [SCSI] scsi_dh: Provide set_params interface in emc device handler Handle the parameters provided by user thru multipath. This handler expects only 2 parameters and their value can either be 0 or 1. This code originates from the old dm-emc.c file. Appropriate changes have been made to make it work in the new design. Reported-by: Eddie Williams Signed-off-by: Chandra Seetharaman Tested-by: Eddie Williams Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/device_handler/scsi_dh_emc.c | 59 +++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index 0e572d2c5b0..0cffe84976f 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c @@ -561,6 +561,61 @@ done: return result; } +/* + * params - parameters in the following format + * "no_of_params\0param1\0param2\0param3\0...\0" + * for example, string for 2 parameters with value 10 and 21 + * is specified as "2\010\021\0". + */ +static int clariion_set_params(struct scsi_device *sdev, const char *params) +{ + struct clariion_dh_data *csdev = get_clariion_data(sdev); + unsigned int hr = 0, st = 0, argc; + const char *p = params; + int result = SCSI_DH_OK; + + if ((sscanf(params, "%u", &argc) != 1) || (argc != 2)) + return -EINVAL; + + while (*p++) + ; + if ((sscanf(p, "%u", &st) != 1) || (st > 1)) + return -EINVAL; + + while (*p++) + ; + if ((sscanf(p, "%u", &hr) != 1) || (hr > 1)) + return -EINVAL; + + if (st) + csdev->flags |= CLARIION_SHORT_TRESPASS; + else + csdev->flags &= ~CLARIION_SHORT_TRESPASS; + + if (hr) + csdev->flags |= CLARIION_HONOR_RESERVATIONS; + else + csdev->flags &= ~CLARIION_HONOR_RESERVATIONS; + + /* + * If this path is owned, we have to send a trespass command + * with the new parameters. If not, simply return. Next trespass + * command would use the parameters. + */ + if (csdev->lun_state != CLARIION_LUN_OWNED) + goto done; + + csdev->lun_state = CLARIION_LUN_UNINITIALIZED; + result = send_trespass_cmd(sdev, csdev); + if (result != SCSI_DH_OK) + goto done; + + /* Update status */ + result = clariion_send_inquiry(sdev, csdev); + +done: + return result; +} static const struct scsi_dh_devlist clariion_dev_list[] = { {"DGC", "RAID"}, @@ -581,11 +636,9 @@ static struct scsi_device_handler clariion_dh = { .check_sense = clariion_check_sense, .activate = clariion_activate, .prep_fn = clariion_prep_fn, + .set_params = clariion_set_params, }; -/* - * TODO: need some interface so we can set trespass values - */ static int clariion_bus_attach(struct scsi_device *sdev) { struct scsi_dh_data *scsi_dh_data; -- cgit v1.2.3-18-g5258 From 2bfd2e1337f0d8bb6ff45ce12934c45b83d70ee0 Mon Sep 17 00:00:00 2001 From: Chandra Seetharaman Date: Mon, 3 Aug 2009 12:42:45 -0700 Subject: [SCSI] scsi_dh: Use scsi_dh_set_params() in multipath. Use scsi_dh_set_params() set parameters provided. Save the parameters in parse_hw_handler() and use it in parse_path(). Reported-by: Eddie Williams Signed-off-by: Chandra Seetharaman Tested-by: Eddie Williams Cc: Alasdair G Kergon Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/md/dm-mpath.c | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 6f0d90d4a54..32d0b878ecc 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -64,6 +64,7 @@ struct multipath { spinlock_t lock; const char *hw_handler_name; + char *hw_handler_params; unsigned nr_priority_groups; struct list_head priority_groups; unsigned pg_init_required; /* pg_init needs calling? */ @@ -219,6 +220,7 @@ static void free_multipath(struct multipath *m) } kfree(m->hw_handler_name); + kfree(m->hw_handler_params); mempool_destroy(m->mpio_pool); kfree(m); } @@ -615,6 +617,17 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps, dm_put_device(ti, p->path.dev); goto bad; } + + if (m->hw_handler_params) { + r = scsi_dh_set_params(q, m->hw_handler_params); + if (r < 0) { + ti->error = "unable to set hardware " + "handler parameters"; + scsi_dh_detach(q); + dm_put_device(ti, p->path.dev); + goto bad; + } + } } r = ps->type->add_path(ps, &p->path, as->argc, as->argv, &ti->error); @@ -705,6 +718,7 @@ static struct priority_group *parse_priority_group(struct arg_set *as, static int parse_hw_handler(struct arg_set *as, struct multipath *m) { unsigned hw_argc; + int ret; struct dm_target *ti = m->ti; static struct param _params[] = { @@ -726,17 +740,33 @@ static int parse_hw_handler(struct arg_set *as, struct multipath *m) request_module("scsi_dh_%s", m->hw_handler_name); if (scsi_dh_handler_exist(m->hw_handler_name) == 0) { ti->error = "unknown hardware handler type"; - kfree(m->hw_handler_name); - m->hw_handler_name = NULL; - return -EINVAL; + ret = -EINVAL; + goto fail; } - if (hw_argc > 1) - DMWARN("Ignoring user-specified arguments for " - "hardware handler \"%s\"", m->hw_handler_name); + if (hw_argc > 1) { + char *p; + int i, j, len = 4; + + for (i = 0; i <= hw_argc - 2; i++) + len += strlen(as->argv[i]) + 1; + p = m->hw_handler_params = kzalloc(len, GFP_KERNEL); + if (!p) { + ti->error = "memory allocation failed"; + ret = -ENOMEM; + goto fail; + } + j = sprintf(p, "%d", hw_argc - 1); + for (i = 0, p+=j+1; i <= hw_argc - 2; i++, p+=j+1) + j = sprintf(p, "%s", as->argv[i]); + } consume(as, hw_argc - 1); return 0; +fail: + kfree(m->hw_handler_name); + m->hw_handler_name = NULL; + return ret; } static int parse_features(struct arg_set *as, struct multipath *m) -- cgit v1.2.3-18-g5258 From 8f1f3ece891e8fe6ee69fa27617b60cb26e37bec Mon Sep 17 00:00:00 2001 From: Ravi Anand Date: Fri, 31 Jul 2009 15:09:23 -0700 Subject: [SCSI] qla2xxx: Pass the command's data residual to upper-layer callers. Signed-off-by: Ravi Anand Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_isr.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 245e7afb4c4..f966d540d2c 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1223,6 +1223,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) cp->device->id, cp->device->lun, resid, scsi_bufflen(cp))); + scsi_set_resid(cp, resid); cp->result = DID_ERROR << 16; break; } -- cgit v1.2.3-18-g5258 From 9764ff8807a2455218e2ec5024e823cc09b01906 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 31 Jul 2009 15:09:24 -0700 Subject: [SCSI] qla2xxx: Correctly handle 'global port-unavailable' AEN. Treat a global port-unavailable PORT_UPDATE (8014h) AEN as a loop-down event. For this case, within the FCoE domain, the 'logical' interface has been terminated, but the driver will not receive the classic LOOP_DOWN AEN. Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_isr.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index f966d540d2c..417a9b9fb19 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -599,8 +599,36 @@ skip_rio: case MBA_PORT_UPDATE: /* Port database update */ /* Only handle SCNs for our Vport index. */ - if (vha->vp_idx && vha->vp_idx != (mb[3] & 0xff)) + if (mb[1] != 0xffff && + vha->vp_idx && vha->vp_idx != (mb[3] & 0xff)) + break; + + /* Global event -- port logout or port unavailable. */ + if (mb[1] == 0xffff && mb[2] == 0x7) { + DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n", + vha->host_no)); + DEBUG(printk(KERN_INFO + "scsi(%ld): Port unavailable %04x %04x %04x.\n", + vha->host_no, mb[1], mb[2], mb[3])); + + if (atomic_read(&vha->loop_state) != LOOP_DOWN) { + atomic_set(&vha->loop_state, LOOP_DOWN); + atomic_set(&vha->loop_down_timer, + LOOP_DOWN_TIME); + vha->device_flags |= DFLG_NO_CABLE; + qla2x00_mark_all_devices_lost(vha, 1); + } + + if (vha->vp_idx) { + atomic_set(&vha->vp_state, VP_FAILED); + fc_vport_set_state(vha->fc_vport, + FC_VPORT_FAILED); + } + + vha->flags.management_server_logged_in = 0; + ha->link_data_rate = PORT_SPEED_UNKNOWN; break; + } /* * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET -- cgit v1.2.3-18-g5258 From 55903b9d152e91d4df2ab242c33efbd33e03e499 Mon Sep 17 00:00:00 2001 From: Santosh Vernekar Date: Fri, 31 Jul 2009 15:09:25 -0700 Subject: [SCSI] qla2xxx: Skip RSCN processing on vha if event is global. The RSCN processing is skipped if the event received is global and vha is not recipient. Signed-off-by: Santosh Vernekar Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_isr.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 417a9b9fb19..00f23d20a98 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -598,10 +598,26 @@ skip_rio: break; case MBA_PORT_UPDATE: /* Port database update */ - /* Only handle SCNs for our Vport index. */ - if (mb[1] != 0xffff && - vha->vp_idx && vha->vp_idx != (mb[3] & 0xff)) - break; + /* + * Handle only global and vn-port update events + * + * Relevant inputs: + * mb[1] = N_Port handle of changed port + * OR 0xffff for global event + * mb[2] = New login state + * 7 = Port logged out + * mb[3] = LSB is vp_idx, 0xff = all vps + * + * Skip processing if: + * Event is global, vp_idx is NOT all vps, + * vp_idx does not match + * Event is not global, vp_idx does not match + */ + if ((mb[1] == 0xffff && (mb[3] & 0xff) != 0xff) + || (mb[1] != 0xffff)) { + if (vha->vp_idx != (mb[3] & 0xff)) + break; + } /* Global event -- port logout or port unavailable. */ if (mb[1] == 0xffff && mb[2] == 0x7) { -- cgit v1.2.3-18-g5258 From faadc5e71cb69cff9c4517f7a4add97f92820120 Mon Sep 17 00:00:00 2001 From: Santosh Vernekar Date: Fri, 31 Jul 2009 15:09:26 -0700 Subject: [SCSI] qla2xxx: Mark all devices lost on loss of fc port. Signed-off-by: Santosh Vernekar Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_isr.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 00f23d20a98..63e7cdce244 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -639,6 +639,7 @@ skip_rio: atomic_set(&vha->vp_state, VP_FAILED); fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED); + qla2x00_mark_all_devices_lost(vha, 1); } vha->flags.management_server_logged_in = 0; -- cgit v1.2.3-18-g5258 From 4b785241ad6d07176a692631dbda3605f4917a18 Mon Sep 17 00:00:00 2001 From: Lalit Chandivade Date: Fri, 31 Jul 2009 15:09:27 -0700 Subject: [SCSI] qla2xxx: Process DPC requests within valid Fabric topologies. If vports are created and topology is changed to Loop only, the driver continuously gets a LIP reset occurred and keeps trying to enable the vport. Only manage requests during F_Port. Signed-off-by: Lalit Chandivade Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_mid.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index cd78c501803..6238be37d7b 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -250,6 +250,9 @@ qla2x00_do_dpc_vp(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); + if (!(ha->current_topology & ISP_CFG_F)) + return 0; + if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) { /* VP acquired. complete port configuration */ if (atomic_read(&base_vha->loop_state) == LOOP_READY) { -- cgit v1.2.3-18-g5258 From a2d301e8d62ecd36dbfec69be13859ae3050f6fa Mon Sep 17 00:00:00 2001 From: Santosh Vernekar Date: Fri, 31 Jul 2009 15:09:29 -0700 Subject: [SCSI] qla2xxx: Handle RSCN's per master/slave vn-port basis. Signed-off-by: Santosh Vernekar Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_isr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 63e7cdce244..40014f3407b 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -685,7 +685,7 @@ skip_rio: if (vha->vp_idx && test_bit(VP_SCR_NEEDED, &vha->vp_flags)) break; /* Only handle SCNs for our Vport index. */ - if (vha->vp_idx && vha->vp_idx != (mb[3] & 0xff)) + if (vha->vp_idx != (mb[3] & 0xff)) break; DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n", vha->host_no)); -- cgit v1.2.3-18-g5258 From f9e899ebe502e547fca37f64ebc4b1399880d8f7 Mon Sep 17 00:00:00 2001 From: Shyam Sundar Date: Fri, 31 Jul 2009 15:09:30 -0700 Subject: [SCSI] qla2xxx: Pad IOCB structure for size requirements. One byte added to make the IOCB structure satisfy size requirements. Signed-off-by: Shyam Sundar Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_fw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index dfde2dd865c..66a8da5d7d0 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -1126,7 +1126,7 @@ struct vp_config_entry_24xx { uint16_t id; uint16_t reserved_4; uint16_t hopct; - uint8_t reserved_5; + uint8_t reserved_5[2]; }; #define VP_RPT_ID_IOCB_TYPE 0x32 /* Report ID Acquisition entry. */ -- cgit v1.2.3-18-g5258 From 80de7efa6d6a4eb72e917bb2d814f38332090d45 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 31 Jul 2009 15:09:33 -0700 Subject: [SCSI] qla2xxx: ISP21xx/22xx do not support FDMI registrations. Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_gs.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 917534b9f22..4647015eba6 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1674,6 +1674,10 @@ int qla2x00_fdmi_register(scsi_qla_host_t *vha) { int rval; + struct qla_hw_data *ha = vha->hw; + + if (IS_QLA2100(ha) || IS_QLA2200(ha)) + return QLA_FUNCTION_FAILED; rval = qla2x00_mgmt_svr_login(vha); if (rval) -- cgit v1.2.3-18-g5258 From eb94114bfd894dce1955e2ece575db544cecd921 Mon Sep 17 00:00:00 2001 From: Anirban Chakraborty Date: Tue, 4 Aug 2009 16:12:13 -0700 Subject: [SCSI] qla2xxx: Fix a bug that clears the interrupt status register for the base queue The interrupt handler clears the interrupt status register for response updates in the base queue while working in the multique mode. This could lead to missing interrupt for async events, mail box completions etc. as these are also handled in the base queue. The fix ensures that the interrupt bit is not cleared for response updates in the ISR when the driver is working in multiqueue mode. Signed-off-by: Anirban Chakraborty Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_isr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 40014f3407b..74fa6f99204 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1769,8 +1769,10 @@ qla24xx_msix_rsp_q(int irq, void *dev_id) vha = qla25xx_get_host(rsp); qla24xx_process_response_queue(vha, rsp); - WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); - + if (!ha->mqenable) { + WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); + RD_REG_DWORD_RELAXED(®->hccr); + } spin_unlock_irq(&ha->hardware_lock); return IRQ_HANDLED; -- cgit v1.2.3-18-g5258 From 09ccbcc628f71e7f57b4a96982ad1bb2084391d8 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Tue, 4 Aug 2009 23:38:21 -0700 Subject: [SCSI] qla2xxx: Correct display of vp_count in debug printk. Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_mbx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index fe69f305767..8fcd99eeec0 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -2746,7 +2746,8 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, if (rptid_entry->format == 0) { DEBUG15(printk("%s:format 0 : scsi(%ld) number of VPs setup %d," " number of VPs acquired %d\n", __func__, vha->host_no, - MSB(rptid_entry->vp_count), LSB(rptid_entry->vp_count))); + MSB(le16_to_cpu(rptid_entry->vp_count)), + LSB(le16_to_cpu(rptid_entry->vp_count)))); DEBUG15(printk("%s primary port id %02x%02x%02x\n", __func__, rptid_entry->port_id[2], rptid_entry->port_id[1], rptid_entry->port_id[0])); -- cgit v1.2.3-18-g5258 From 7163ea815170f8c5d56ead27d7e6fa3fa1f9844b Mon Sep 17 00:00:00 2001 From: Anirban Chakraborty Date: Wed, 5 Aug 2009 09:18:40 -0700 Subject: [SCSI] qla2xxx: Fix to ensure driver works in sinlge queue mode if multiqueue fails When the multiqueue mode fails to work, the driver falls back on single queue mode. This ensures that the firmware is reinitialized with single queue options and all the resources are readjusted accordingly. Signed-off-by: Anirban Chakraborty Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 4 ++-- drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_init.c | 5 ++--- drivers/scsi/qla2xxx/qla_iocb.c | 2 +- drivers/scsi/qla2xxx/qla_mbx.c | 4 ++-- drivers/scsi/qla2xxx/qla_os.c | 23 +++++++++++++++++++---- 6 files changed, 27 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 0f879620150..5b0a222241b 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1670,7 +1670,7 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) qla24xx_vport_disable(fc_vport, disable); - if (ql2xmultique_tag) { + if (ha->flags.cpu_affinity_enabled) { req = ha->req_q_map[1]; goto vport_queue; } else if (ql2xmaxqueues == 1 || !ha->npiv_info) @@ -1743,7 +1743,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) vha->host_no, vha->vp_idx, vha)); } - if (vha->req->id && !ql2xmultique_tag) { + if (vha->req->id && !ha->flags.cpu_affinity_enabled) { if (qla25xx_delete_req_que(vha, vha->req) != QLA_SUCCESS) qla_printk(KERN_WARNING, ha, "Queue delete failed.\n"); diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 9fde8bfe760..68ab28c8152 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2224,6 +2224,7 @@ struct qla_hw_data { uint32_t chip_reset_done :1; uint32_t port0 :1; uint32_t running_gold_fw :1; + uint32_t cpu_affinity_enabled :1; } flags; /* This spinlock is used to protect "io transactions", you must diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index f2ce8e3cc91..0cbe39e9250 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -987,7 +987,6 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) ha->phy_version); if (rval != QLA_SUCCESS) goto failed; - ha->flags.npiv_supported = 0; if (IS_QLA2XXX_MIDTYPE(ha) && (ha->fw_attributes & BIT_2)) { @@ -3244,7 +3243,7 @@ qla2x00_loop_resync(scsi_qla_host_t *vha) struct req_que *req; struct rsp_que *rsp; - if (ql2xmultique_tag) + if (vha->hw->flags.cpu_affinity_enabled) req = vha->hw->req_q_map[0]; else req = vha->req; @@ -4264,7 +4263,7 @@ qla24xx_configure_vhba(scsi_qla_host_t *vha) return -EINVAL; rval = qla2x00_fw_ready(base_vha); - if (ql2xmultique_tag) + if (ha->flags.cpu_affinity_enabled) req = ha->req_q_map[0]; else req = vha->req; diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 13396beae2c..c0ba370b23c 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -852,7 +852,7 @@ static void qla25xx_set_que(srb_t *sp, struct rsp_que **rsp) struct qla_hw_data *ha = sp->fcport->vha->hw; int affinity = cmd->request->cpu; - if (ql2xmultique_tag && affinity >= 0 && + if (ha->flags.cpu_affinity_enabled && affinity >= 0 && affinity < ha->max_rsp_queues - 1) *rsp = ha->rsp_q_map[affinity + 1]; else diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 8fcd99eeec0..b6202fe118a 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1507,7 +1507,7 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); - if (ql2xmultique_tag) + if (ha->flags.cpu_affinity_enabled) req = ha->req_q_map[0]; else req = vha->req; @@ -2324,7 +2324,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, vha = fcport->vha; ha = vha->hw; req = vha->req; - if (ql2xmultique_tag) + if (ha->flags.cpu_affinity_enabled) rsp = ha->rsp_q_map[tag + 1]; else rsp = req->rsp; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index f0396e79b6f..d7b271339a5 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -287,9 +287,12 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha) int ques, req, ret; struct qla_hw_data *ha = vha->hw; + if (!(ha->fw_attributes & BIT_6)) { + qla_printk(KERN_INFO, ha, + "Firmware is not multi-queue capable\n"); + goto fail; + } if (ql2xmultique_tag) { - /* CPU affinity mode */ - ha->wq = create_workqueue("qla2xxx_wq"); /* create a request queue for IO */ options |= BIT_7; req = qla25xx_create_req_que(ha, options, 0, 0, -1, @@ -299,6 +302,7 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha) "Can't create request queue\n"); goto fail; } + ha->wq = create_workqueue("qla2xxx_wq"); vha->req = ha->req_q_map[req]; options |= BIT_1; for (ques = 1; ques < ha->max_rsp_queues; ques++) { @@ -309,6 +313,8 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha) goto fail2; } } + ha->flags.cpu_affinity_enabled = 1; + DEBUG2(qla_printk(KERN_INFO, ha, "CPU affinity mode enabled, no. of response" " queues:%d, no. of request queues:%d\n", @@ -317,8 +323,13 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha) return 0; fail2: qla25xx_delete_queues(vha); + destroy_workqueue(ha->wq); + ha->wq = NULL; fail: ha->mqenable = 0; + kfree(ha->req_q_map); + kfree(ha->rsp_q_map); + ha->max_req_queues = ha->max_rsp_queues = 1; return 1; } @@ -1923,6 +1934,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) goto probe_init_failed; /* Alloc arrays of request and response ring ptrs */ +que_init: if (!qla2x00_alloc_queues(ha)) { qla_printk(KERN_WARNING, ha, "[ERROR] Failed to allocate memory for queue" @@ -1959,11 +1971,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) goto probe_failed; } - if (ha->mqenable) - if (qla25xx_setup_mode(base_vha)) + if (ha->mqenable) { + if (qla25xx_setup_mode(base_vha)) { qla_printk(KERN_WARNING, ha, "Can't create queues, falling back to single" " queue mode\n"); + goto que_init; + } + } if (ha->flags.running_gold_fw) goto skip_dpc; -- cgit v1.2.3-18-g5258 From d430ddc660d2f9875125b4f13a2b9279313db529 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Fri, 31 Jul 2009 15:09:34 -0700 Subject: [SCSI] qla2xxx: Update version number to 8.03.01-k5 Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 84369705a9a..87a884e341a 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.03.01-k4" +#define QLA2XXX_VERSION "8.03.01-k5" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 3 -- cgit v1.2.3-18-g5258 From d68866927ddd0ed3145cb3fba4a1c07ca5e4709d Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 3 Aug 2009 13:54:47 -0700 Subject: [SCSI] ibmvscsi: avoid unnecessary use of kzalloc_pool The allocated struct is manually zeroed after allocation, so avoid using the (broken) kzalloc mempool (which does not re-zero previously used items when they are returned to the pool). Acked-by: Brian King Signed-off-by: Sage Weil Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvfc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 166d96450a0..bb2c696c006 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -4217,7 +4217,7 @@ static int ibmvfc_alloc_mem(struct ibmvfc_host *vhost) if (!vhost->trace) goto free_disc_buffer; - vhost->tgt_pool = mempool_create_kzalloc_pool(IBMVFC_TGT_MEMPOOL_SZ, + vhost->tgt_pool = mempool_create_kmalloc_pool(IBMVFC_TGT_MEMPOOL_SZ, sizeof(struct ibmvfc_target)); if (!vhost->tgt_pool) { -- cgit v1.2.3-18-g5258 From a2cf8a6306c89223d0ed35a7e9d40da99902e32a Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso A Date: Fri, 7 Aug 2009 16:42:21 -0400 Subject: [SCSI] ch: Check NULL for kmalloc() return Verify that ch->dt is not NULL before using it. Signed-off-by: Davidlohr Bueso Signed-off-by: James Bottomley --- drivers/scsi/ch.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 7b1633a8c15..fe11c1d4b31 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -353,6 +353,12 @@ ch_readconfig(scsi_changer *ch) /* look up the devices of the data transfer elements */ ch->dt = kmalloc(ch->counts[CHET_DT]*sizeof(struct scsi_device), GFP_KERNEL); + + if (!ch->dt) { + kfree(buffer); + return -ENOMEM; + } + for (elem = 0; elem < ch->counts[CHET_DT]; elem++) { id = -1; lun = 0; -- cgit v1.2.3-18-g5258 From edced191e4512b7795380563634f4d44b21c684a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Sat, 8 Aug 2009 11:36:06 +0200 Subject: [SCSI] nsp_cs: fix buf overflow In nsp_cs_config there is a wrong struct nsp_cs_configdata allocation. It allocates only sizeof(pointer to nsp_cs_configdata) for a whole structure. Add a dereference to the sizeof to allocate sizeof(nsp_cs_configdata). Signed-off-by: Jiri Slaby Signed-off-by: James Bottomley --- drivers/scsi/pcmcia/nsp_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 70b60ade049..e32c344d7ad 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -1713,7 +1713,7 @@ static int nsp_cs_config(struct pcmcia_device *link) nsp_dbg(NSP_DEBUG_INIT, "in"); - cfg_mem = kzalloc(sizeof(cfg_mem), GFP_KERNEL); + cfg_mem = kzalloc(sizeof(*cfg_mem), GFP_KERNEL); if (!cfg_mem) return -ENOMEM; cfg_mem->data = data; -- cgit v1.2.3-18-g5258 From 5f91bb050ecc4ff1d8d3d07edbe550c8f431c5e1 Mon Sep 17 00:00:00 2001 From: Michael Reed Date: Mon, 10 Aug 2009 11:59:28 -0500 Subject: [SCSI] reservation conflict after timeout causes device to be taken offline An IBM tape drive failed to complete a PERSISTENT RESERVE IN within the scsi cmd timeout. Error recovery was initiated and it sequenced from abort through taking the tape drive offline. The device was taken offline because it repeatedly responded to the TUR command issued by error recovery with a RESERVATION CONFLICT status. The tape drive was reserved to another system. This is perfectly legitimate response to TUR, and is one that an escalation of recovery is unlikely to clear. Further, escalation of recovery can have undesirable side effects on the operation of tape drives shared with other initiators. Instead of escalating recovery, error recovery should treat the RESERVATION CONFLICT response to the TUR as a good status, giving the issuer of the command the opportunity to handle the timeout and reservation conflict. Signed-off-by: Michael reed Signed-off-by: James Bottomley --- drivers/scsi/scsi_error.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index a1689353d7f..877204daf54 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -382,9 +382,13 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd) * who knows? FIXME(eric) */ return SUCCESS; + case RESERVATION_CONFLICT: + /* + * let issuer deal with this, it could be just fine + */ + return SUCCESS; case BUSY: case QUEUE_FULL: - case RESERVATION_CONFLICT: default: return FAILED; } -- cgit v1.2.3-18-g5258 From 95a3639e275fb7aec5c9a2116c88a2cdd23e0b8b Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 11 Aug 2009 10:59:09 -0500 Subject: [SCSI] fix bugs in scsi_vpd_inquiry() Universally, SCSI functions assume the lengths fed in are those of the buffer to DMA data to, not the lengths of the data minus the header. scsi_vpd_inquiry() assumed the latter and got it wrong, so fix up all the functions to use the correct assumption (and fix a bug where INQUIRY in SCSI-2 dcannot go over 255). [jejb: Matthew posted an identical version of this at the same time I did] Signed-off-by: Matthew Wilcox Signed-off-by: James Bottomley --- drivers/scsi/scsi.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 2de5f3ad640..b6e03074cb8 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -994,7 +994,7 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer, * all the existing users tried this hard. */ result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, - len + 4, NULL, 30 * HZ, 3, NULL); + len, NULL, 30 * HZ, 3, NULL); if (result) return result; @@ -1021,13 +1021,14 @@ unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page) { int i, result; unsigned int len; - unsigned char *buf = kmalloc(259, GFP_KERNEL); + const unsigned int init_vpd_len = 255; + unsigned char *buf = kmalloc(init_vpd_len, GFP_KERNEL); if (!buf) return NULL; /* Ask for all the pages supported by this device */ - result = scsi_vpd_inquiry(sdev, buf, 0, 255); + result = scsi_vpd_inquiry(sdev, buf, 0, init_vpd_len); if (result) goto fail; @@ -1050,12 +1051,12 @@ unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page) * Some pages are longer than 255 bytes. The actual length of * the page is returned in the header. */ - len = (buf[2] << 8) | buf[3]; - if (len <= 255) + len = ((buf[2] << 8) | buf[3]) + 4; + if (len <= init_vpd_len) return buf; kfree(buf); - buf = kmalloc(len + 4, GFP_KERNEL); + buf = kmalloc(len, GFP_KERNEL); result = scsi_vpd_inquiry(sdev, buf, page, len); if (result) goto fail; -- cgit v1.2.3-18-g5258 From 4dbfb544ad5a28ac9e60634bdfbf09d2eb39cdb5 Mon Sep 17 00:00:00 2001 From: Chandra Seetharaman Date: Wed, 12 Aug 2009 12:43:20 -0700 Subject: [SCSI] scsi_dh: add two SUN devices to the list of devices supported by default Reported-by: Rice Brown Signed-Off-by: Chandra Seetharaman Signed-off-by: James Bottomley --- drivers/scsi/device_handler/scsi_dh_rdac.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index fd0544f7da8..bea92ef7e26 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -633,6 +633,8 @@ static const struct scsi_dh_devlist rdac_dev_list[] = { {"DELL", "MD3000i"}, {"LSI", "INF-01-00"}, {"ENGENIO", "INF-01-00"}, + {"STK", "FLEXLINE 380"}, + {"SUN", "CSM100_R_FC"}, {NULL, NULL}, }; -- cgit v1.2.3-18-g5258 From 9d2e9d66a3f032667934144cd61c396ba49f090d Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 5 Aug 2009 12:48:44 +0530 Subject: [SCSI] mptsas : Change DEFINED value of can queue for FC and SAS devices. Change DEFINED value of can queue for FC and SAS devices. Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.h | 3 ++- drivers/message/fusion/mptsas.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 1c8514dc31c..73810fa5345 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -157,8 +157,9 @@ /* * Try to keep these at 2^N-1 */ -#define MPT_FC_CAN_QUEUE 127 +#define MPT_FC_CAN_QUEUE 1024 #define MPT_SCSI_CAN_QUEUE 127 +#define MPT_SAS_CAN_QUEUE 127 /* * Set the MAX_SGE value based on user input. diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 55ff25244af..c03968b9e7d 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1891,7 +1891,7 @@ static struct scsi_host_template mptsas_driver_template = { .eh_bus_reset_handler = mptscsih_bus_reset, .eh_host_reset_handler = mptscsih_host_reset, .bios_param = mptscsih_bios_param, - .can_queue = MPT_FC_CAN_QUEUE, + .can_queue = MPT_SAS_CAN_QUEUE, .this_id = -1, .sg_tablesize = MPT_SCSI_SG_DEPTH, .max_sectors = 8192, -- cgit v1.2.3-18-g5258 From a247fa4521ccec7cb82a9f2d4e8544fce27ea109 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 5 Aug 2009 12:50:02 +0530 Subject: [SCSI] mptsas : Removed mptscsih_timer_expired. Removed mptscsih_timer_expired. This timer is no more use. Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.h | 14 ------------ drivers/message/fusion/mptfc.c | 19 ---------------- drivers/message/fusion/mptsas.c | 19 ---------------- drivers/message/fusion/mptscsih.c | 48 --------------------------------------- drivers/message/fusion/mptscsih.h | 1 - drivers/message/fusion/mptspi.c | 21 ----------------- 6 files changed, 122 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 73810fa5345..bf446d41cda 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -880,23 +880,9 @@ typedef enum { typedef struct _MPT_SCSI_HOST { MPT_ADAPTER *ioc; - int port; - u32 pad0; - MPT_LOCAL_REPLY *pLocal; /* used for internal commands */ - struct timer_list timer; - /* Pool of memory for holding SCpnts before doing - * OS callbacks. freeQ is the free pool. - */ - u8 negoNvram; /* DV disabled, nego NVRAM */ - u8 pad1; - u8 rsvd[2]; - MPT_FRAME_HDR *cmdPtr; /* Ptr to nonOS request */ - struct scsi_cmnd *abortSCpnt; - MPT_LOCAL_REPLY localReply; /* internal cmd reply struct */ ushort sel_timeout[MPT_MAX_FC_DEVICES]; char *info_kbuf; long last_queue_full; - u16 tm_iocstatus; u16 spi_pending; struct list_head target_reset_list; } MPT_SCSI_HOST; diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index e61df133a59..ebf6ae024da 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -1288,25 +1288,6 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", ioc->name, ioc->ScsiLookup)); - /* Clear the TM flags - */ - hd->abortSCpnt = NULL; - - /* Clear the pointer used to store - * single-threaded commands, i.e., those - * issued during a bus scan, dv and - * configuration pages. - */ - hd->cmdPtr = NULL; - - /* Initialize this SCSI Hosts' timers - * To use, set the timer expires field - * and add_timer - */ - init_timer(&hd->timer); - hd->timer.data = (unsigned long) hd; - hd->timer.function = mptscsih_timer_expired; - hd->last_queue_full = 0; sh->transportt = mptfc_transport_template; diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index c03968b9e7d..54fc73c380e 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -4821,25 +4821,6 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", ioc->name, ioc->ScsiLookup)); - /* Clear the TM flags - */ - hd->abortSCpnt = NULL; - - /* Clear the pointer used to store - * single-threaded commands, i.e., those - * issued during a bus scan, dv and - * configuration pages. - */ - hd->cmdPtr = NULL; - - /* Initialize this SCSI Hosts' timers - * To use, set the timer expires field - * and add_timer - */ - init_timer(&hd->timer); - hd->timer.data = (unsigned long) hd; - hd->timer.function = mptscsih_timer_expired; - ioc->sas_data.ptClear = mpt_pt_clear; hd->last_queue_full = 0; diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 8440f78f696..abdc727c4a5 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -1729,9 +1729,6 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) */ mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx); ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext; - - hd->abortSCpnt = SCpnt; - retval = mptscsih_IssueTaskMgmt(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, vdevice->vtarget->channel, @@ -2627,50 +2624,6 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, return 1; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* mptscsih_timer_expired - Call back for timer process. - * Used only for dv functionality. - * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long - * - */ -void -mptscsih_timer_expired(unsigned long data) -{ - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data; - MPT_ADAPTER *ioc = hd->ioc; - - ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", ioc->name, hd->cmdPtr)); - - if (hd->cmdPtr) { - MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr; - - if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) { - /* Desire to issue a task management request here. - * TM requests MUST be single threaded. - * If old eh code and no TM current, issue request. - * If new eh code, do nothing. Wait for OS cmd timeout - * for bus reset. - */ - } else { - /* Perform a FW reload */ - if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) { - printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name); - } - } - } else { - /* This should NEVER happen */ - printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", ioc->name); - } - - /* No more processing. - * TM call will generate an interrupt for SCSI TM Management. - * The FW will reply to all outstanding commands, callback will finish cleanup. - * Hard reset clean-up will free all resources. - */ - ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name)); - - return; -} /** * mptscsih_get_completion_code - @@ -3265,6 +3218,5 @@ EXPORT_SYMBOL(mptscsih_scandv_complete); EXPORT_SYMBOL(mptscsih_event_process); EXPORT_SYMBOL(mptscsih_ioc_reset); EXPORT_SYMBOL(mptscsih_change_queue_depth); -EXPORT_SYMBOL(mptscsih_timer_expired); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index eb3f677528a..e0b33e04a33 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -129,7 +129,6 @@ extern int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRA extern int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth); -extern void mptscsih_timer_expired(unsigned long data); extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id); extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id); extern struct device_attribute *mptscsih_host_attrs[]; diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index c5b808fd55b..69f4257419b 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -1472,28 +1472,7 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", ioc->name, ioc->ScsiLookup)); - /* Clear the TM flags - */ - hd->abortSCpnt = NULL; - - /* Clear the pointer used to store - * single-threaded commands, i.e., those - * issued during a bus scan, dv and - * configuration pages. - */ - hd->cmdPtr = NULL; - - /* Initialize this SCSI Hosts' timers - * To use, set the timer expires field - * and add_timer - */ - init_timer(&hd->timer); - hd->timer.data = (unsigned long) hd; - hd->timer.function = mptscsih_timer_expired; - ioc->spi_data.Saf_Te = mpt_saf_te; - - hd->negoNvram = MPT_SCSICFG_USE_NVRAM; ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "saf_te %x\n", ioc->name, -- cgit v1.2.3-18-g5258 From d23321b4880fb7a95fa58277fafb98a4368b4c92 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 5 Aug 2009 12:51:25 +0530 Subject: [SCSI] mptsas : Handle INSUFFICIENT resources status as similar to IOC BUSY status Handle insufficient resources status as similar to busy status. Signed-off-by: James Bottomley --- drivers/message/fusion/mptscsih.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index abdc727c4a5..1466a5aed5f 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -689,6 +689,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) switch(status) { case MPI_IOCSTATUS_BUSY: /* 0x0002 */ + case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */ /* CHECKME! * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry) * But not: DID_BUS_BUSY lest one risk @@ -872,7 +873,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */ case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */ case MPI_IOCSTATUS_RESERVED: /* 0x0005 */ - case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */ case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */ case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */ case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ -- cgit v1.2.3-18-g5258 From 4b97650b555b1cd09b547104d98da0ff700187d9 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 5 Aug 2009 12:52:03 +0530 Subject: [SCSI] mptsas : Change config request timeout value to 30 seconds. Change config request timeout value to 30 seconds. Signed-off-by: James Bottomley --- drivers/message/fusion/mptsas.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 54fc73c380e..936e35ae88d 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -72,6 +72,7 @@ */ #define MPTSAS_RAID_CHANNEL 1 +#define SAS_CONFIG_PAGE_TIMEOUT 30 MODULE_AUTHOR(MODULEAUTHOR); MODULE_DESCRIPTION(my_NAME); MODULE_LICENSE("GPL"); @@ -661,7 +662,7 @@ mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc, cfg.pageAddr = starget->id; cfg.cfghdr.hdr = &hdr; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; if (mpt_config(ioc, &cfg) != 0) goto out; @@ -1318,7 +1319,7 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, cfg.pageAddr = form + form_specific; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; error = mpt_config(ioc, &cfg); if (error) @@ -1926,7 +1927,7 @@ static int mptsas_get_linkerrors(struct sas_phy *phy) cfg.pageAddr = phy->identify.phy_identifier; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; error = mpt_config(ioc, &cfg); if (error) @@ -2278,7 +2279,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) cfg.pageAddr = 0; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; error = mpt_config(ioc, &cfg); if (error) @@ -2349,7 +2350,7 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc) cfg.cfghdr.ehdr = &hdr; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED; cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION; @@ -2411,7 +2412,7 @@ mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, cfg.cfghdr.ehdr = &hdr; cfg.dir = 0; /* read */ - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; /* Get Phy Pg 0 for each Phy. */ cfg.physAddr = -1; @@ -2479,7 +2480,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, cfg.physAddr = -1; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; memset(device_info, 0, sizeof(struct mptsas_devinfo)); error = mpt_config(ioc, &cfg); @@ -2554,7 +2555,7 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, cfg.pageAddr = form + form_specific; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; memset(port_info, 0, sizeof(struct mptsas_portinfo)); error = mpt_config(ioc, &cfg); @@ -2635,7 +2636,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, cfg.pageAddr = form + form_specific; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; error = mpt_config(ioc, &cfg); if (error) -- cgit v1.2.3-18-g5258 From 79a3ec1ace2329d115ecd2445379b46aed3286b0 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 5 Aug 2009 12:52:58 +0530 Subject: [SCSI] mptsas : set max_id to infinite value. Do not set max_id value received from FW. Once SAS transport layer is introduced max_id value is missleading to SCSI mid layer. Use max_id to infinite value. logic of can queue of scsi host is changed. Signed-off-by: James Bottomley --- drivers/message/fusion/mptsas.c | 5 ++--- drivers/message/fusion/mptscsih.c | 5 ++++- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 936e35ae88d..21bd78e4f30 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -4761,10 +4761,9 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* set 16 byte cdb's */ sh->max_cmd_len = 16; - - sh->max_id = ioc->pfacts[0].PortSCSIID; + sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue); + sh->max_id = -1; sh->max_lun = max_lun; - sh->transportt = mptsas_transport_template; /* Required entry. diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 1466a5aed5f..0e402eb9571 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -2290,7 +2290,10 @@ mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth) else max_depth = MPT_SCSI_CMD_PER_DEV_LOW; } else - max_depth = MPT_SCSI_CMD_PER_DEV_HIGH; + max_depth = ioc->sh->can_queue; + + if (!sdev->tagged_supported) + max_depth = 1; if (qdepth > max_depth) qdepth = max_depth; -- cgit v1.2.3-18-g5258 From d130691725e9c4a098a59fc64f5ac3dcb1e2aa3b Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 5 Aug 2009 12:53:51 +0530 Subject: [SCSI] mptsas : Code cleanup of host page alloc and diag reset. Code cleanup of host page alloc and diag reset. Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 84 ++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 5d0ba4f5924..8ab7b37ed70 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -1297,12 +1297,8 @@ mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init) psge = (char *)&ioc_init->HostPageBufferSGE; flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_SYSTEM_ADDRESS | - MPI_SGE_FLAGS_32_BIT_ADDRESSING | MPI_SGE_FLAGS_HOST_TO_IOC | MPI_SGE_FLAGS_END_OF_BUFFER; - if (sizeof(dma_addr_t) == sizeof(u64)) { - flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING; - } flags_length = flags_length << MPI_SGE_FLAGS_SHIFT; flags_length |= ioc->HostPageBuffer_sz; ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma); @@ -2224,8 +2220,6 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) int hard; int rc=0; int ii; - u8 cb_idx; - int handlers; int ret = 0; int reset_alt_ioc_active = 0; int irq_allocated = 0; @@ -2548,34 +2542,6 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) mpt_get_manufacturing_pg_0(ioc); } - /* - * Call each currently registered protocol IOC reset handler - * with post-reset indication. - * NOTE: If we're doing _IOC_BRINGUP, there can be no - * MptResetHandlers[] registered yet. - */ - if (hard_reset_done) { - rc = handlers = 0; - for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { - if ((ret == 0) && MptResetHandlers[cb_idx]) { - dprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Calling IOC post_reset handler #%d\n", - ioc->name, cb_idx)); - rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET); - handlers++; - } - - if (alt_ioc_ready && MptResetHandlers[cb_idx]) { - drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Calling IOC post_reset handler #%d\n", - ioc->alt_ioc->name, cb_idx)); - rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET); - handlers++; - } - } - /* FIXME? Examine results here? */ - } - out: if ((ret != 0) && irq_allocated) { free_irq(ioc->pci_irq, ioc); @@ -3938,6 +3904,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) int count = 0; u32 diag1val = 0; MpiFwHeader_t *cached_fw; /* Pointer to FW */ + u8 cb_idx; /* Clear any existing interrupts */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); @@ -3956,6 +3923,18 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) else mdelay(1); + /* + * Call each currently registered protocol IOC reset handler + * with pre-reset indication. + * NOTE: If we're doing _IOC_BRINGUP, there can be no + * MptResetHandlers[] registered yet. + */ + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) + (*(MptResetHandlers[cb_idx]))(ioc, + MPT_IOC_PRE_RESET); + } + for (count = 0; count < 60; count ++) { doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); doorbell &= MPI_IOC_STATE_MASK; @@ -4052,25 +4031,15 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) * NOTE: If we're doing _IOC_BRINGUP, there can be no * MptResetHandlers[] registered yet. */ - { - u8 cb_idx; - int r = 0; - - for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { - if (MptResetHandlers[cb_idx]) { - dprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Calling IOC pre_reset handler #%d\n", - ioc->name, cb_idx)); - r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET); - if (ioc->alt_ioc) { - dprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Calling alt-%s pre_reset handler #%d\n", - ioc->name, ioc->alt_ioc->name, cb_idx)); - r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET); - } + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) { + mpt_signal_reset(cb_idx, + ioc, MPT_IOC_PRE_RESET); + if (ioc->alt_ioc) { + mpt_signal_reset(cb_idx, + ioc->alt_ioc, MPT_IOC_PRE_RESET); } } - /* FIXME? Examine results here? */ } if (ioc->cached_fw) @@ -6956,7 +6925,7 @@ EXPORT_SYMBOL(mpt_halt_firmware); int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) { - int rc; + int rc; u8 cb_idx; unsigned long flags; unsigned long time_count; @@ -6982,8 +6951,6 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) ioc->alt_ioc->ioc_reset_in_progress = 1; spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); - /* FIXME: If do_ioc_recovery fails, repeat.... - */ /* The SCSI driver needs to adjust timeouts on all current * commands prior to the diagnostic reset being issued. @@ -7020,6 +6987,15 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) } spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) { + mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET); + if (ioc->alt_ioc) + mpt_signal_reset(cb_idx, + ioc->alt_ioc, MPT_IOC_POST_RESET); + } + } + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler: completed (%d seconds): %s\n", ioc->name, -- cgit v1.2.3-18-g5258 From 8ea0696e9251c2283d3d306c6b096e71cf6a60c0 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 5 Aug 2009 12:54:32 +0530 Subject: [SCSI] mptsas : Bump version to 3.04.11 Bump version to 3.04.11 Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index bf446d41cda..79b17ceb714 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -76,8 +76,8 @@ #define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.04.10" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.09" +#define MPT_LINUX_VERSION_COMMON "3.04.11" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.11" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ -- cgit v1.2.3-18-g5258 From 155d5561f570c5b3af7a178670061927d89209fb Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 21 Aug 2009 16:20:43 +0000 Subject: bnx2: Zero out status block before chip reset. In case IRQs are shared, we will not mistakenly start processing the ring based on old status block indices. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 756d4b4f0a9..e75b6e94f65 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -4858,6 +4858,7 @@ bnx2_init_chip(struct bnx2 *bp) bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG2, BNX2_RBUF_CONFIG2_VAL(mtu)); bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG3, BNX2_RBUF_CONFIG3_VAL(mtu)); + memset(bp->bnx2_napi[0].status_blk.msi, 0, bp->status_stats_size); for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) bp->bnx2_napi[i].last_status_idx = 0; -- cgit v1.2.3-18-g5258 From 3767546cc24de8f104e745d59a0a43a09d9267df Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 21 Aug 2009 16:20:44 +0000 Subject: bnx2: Check if_running() before touching chip registers. Add this check to bnx2_netif_stop() and bnx2_vlan_rx_register() to prevent bus lockups on some systems when the chip is in low power state. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index e75b6e94f65..9cfd46017e4 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -619,6 +619,9 @@ bnx2_disable_int_sync(struct bnx2 *bp) int i; atomic_inc(&bp->intr_sem); + if (!netif_running(bp->dev)) + return; + bnx2_disable_int(bp); for (i = 0; i < bp->irq_nvecs; i++) synchronize_irq(bp->irq_tbl[i].vector); @@ -6254,9 +6257,14 @@ bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp) { struct bnx2 *bp = netdev_priv(dev); - bnx2_netif_stop(bp); + if (netif_running(dev)) + bnx2_netif_stop(bp); bp->vlgrp = vlgrp; + + if (!netif_running(dev)) + return; + bnx2_set_rx_mode(dev); if (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN) bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1); -- cgit v1.2.3-18-g5258 From 6fefb65e78f098c09d0ab877b2c70421e4c84116 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 21 Aug 2009 16:20:45 +0000 Subject: bnx2: Close device if MTU change or ring size change fails. When unable to allocate memory for new MTU or new ring size, we need to close the device to prevent it from crashing. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 9cfd46017e4..1d502e6f6c9 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6992,9 +6992,14 @@ bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx) int rc; rc = bnx2_alloc_mem(bp); - if (rc) + if (!rc) + rc = bnx2_init_nic(bp, 0); + + if (rc) { + bnx2_napi_enable(bp); + dev_close(bp->dev); return rc; - bnx2_init_nic(bp, 0); + } bnx2_netif_start(bp); } return 0; -- cgit v1.2.3-18-g5258 From 61d9e3fa7eacabfb7879e3da91709f1a5420c507 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 21 Aug 2009 16:20:46 +0000 Subject: bnx2: Apply BROKEN_STATS workaround to 5706 and 5708. Add flag to expand the workaround to both chips. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 7 ++++--- drivers/net/bnx2.h | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 1d502e6f6c9..085c2dd8e7f 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -4900,7 +4900,7 @@ bnx2_init_chip(struct bnx2 *bp) REG_WR(bp, BNX2_HC_CMD_TICKS, (bp->cmd_ticks_int << 16) | bp->cmd_ticks); - if (CHIP_NUM(bp) == CHIP_NUM_5708) + if (bp->flags & BNX2_FLAG_BROKEN_STATS) REG_WR(bp, BNX2_HC_STATS_TICKS, 0); else REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks); @@ -6025,7 +6025,7 @@ bnx2_timer(unsigned long data) bnx2_reg_rd_ind(bp, BNX2_FW_RX_DROP_COUNT); /* workaround occasional corrupted counters */ - if (CHIP_NUM(bp) == CHIP_NUM_5708 && bp->stats_ticks) + if ((bp->flags & BNX2_FLAG_BROKEN_STATS) && bp->stats_ticks) REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_STATS_NOW); @@ -6941,7 +6941,7 @@ bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal) 0xff; bp->stats_ticks = coal->stats_block_coalesce_usecs; - if (CHIP_NUM(bp) == CHIP_NUM_5708) { + if (bp->flags & BNX2_FLAG_BROKEN_STATS) { if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC) bp->stats_ticks = USEC_PER_SEC; } @@ -7722,6 +7722,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) rc = -EIO; goto err_out_unmap; } + bp->flags |= BNX2_FLAG_BROKEN_STATS; } if (CHIP_NUM(bp) == CHIP_NUM_5709 && CHIP_REV(bp) != CHIP_REV_Ax) { diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index f1edfaa9e56..3c004b44cf7 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6718,6 +6718,7 @@ struct bnx2 { BNX2_FLAG_USING_MSIX) #define BNX2_FLAG_JUMBO_BROKEN 0x00000800 #define BNX2_FLAG_CAN_KEEP_VLAN 0x00001000 +#define BNX2_FLAG_BROKEN_STATS 0x00002000 struct bnx2_napi bnx2_napi[BNX2_MAX_MSIX_VEC]; -- cgit v1.2.3-18-g5258 From 790dab2f671cb477e6179322a6c48c898e311e72 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 21 Aug 2009 16:20:47 +0000 Subject: bnx2: Report FTQ discard counter. Report this counter to ethtool -S and include it in netstat. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 085c2dd8e7f..e025833e664 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6485,7 +6485,8 @@ bnx2_get_stats(struct net_device *dev) stats_blk->stat_EtherStatsOverrsizePkts); net_stats->rx_over_errors = - (unsigned long) stats_blk->stat_IfInMBUFDiscards; + (unsigned long) (stats_blk->stat_IfInFTQDiscards + + stats_blk->stat_IfInMBUFDiscards); net_stats->rx_frame_errors = (unsigned long) stats_blk->stat_Dot3StatsAlignmentErrors; @@ -6518,8 +6519,8 @@ bnx2_get_stats(struct net_device *dev) net_stats->tx_carrier_errors; net_stats->rx_missed_errors = - (unsigned long) (stats_blk->stat_IfInMBUFDiscards + - stats_blk->stat_FwRxDrop); + (unsigned long) (stats_blk->stat_IfInFTQDiscards + + stats_blk->stat_IfInMBUFDiscards + stats_blk->stat_FwRxDrop); return net_stats; } @@ -7090,11 +7091,9 @@ bnx2_set_tso(struct net_device *dev, u32 data) return 0; } -#define BNX2_NUM_STATS 46 - static struct { char string[ETH_GSTRING_LEN]; -} bnx2_stats_str_arr[BNX2_NUM_STATS] = { +} bnx2_stats_str_arr[] = { { "rx_bytes" }, { "rx_error_bytes" }, { "tx_bytes" }, @@ -7139,10 +7138,14 @@ static struct { { "tx_xoff_frames" }, { "rx_mac_ctrl_frames" }, { "rx_filtered_packets" }, + { "rx_ftq_discards" }, { "rx_discards" }, { "rx_fw_discards" }, }; +#define BNX2_NUM_STATS (sizeof(bnx2_stats_str_arr)/\ + sizeof(bnx2_stats_str_arr[0])) + #define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4) static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = { @@ -7190,6 +7193,7 @@ static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = { STATS_OFFSET32(stat_OutXoffSent), STATS_OFFSET32(stat_MacControlFramesReceived), STATS_OFFSET32(stat_IfInFramesL2FilterDiscards), + STATS_OFFSET32(stat_IfInFTQDiscards), STATS_OFFSET32(stat_IfInMBUFDiscards), STATS_OFFSET32(stat_FwRxDrop), }; @@ -7202,7 +7206,7 @@ static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = { 4,0,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4, + 4,4,4,4,4,4,4, }; static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = { @@ -7210,7 +7214,7 @@ static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = { 4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4, + 4,4,4,4,4,4,4, }; #define BNX2_NUM_TESTS 6 -- cgit v1.2.3-18-g5258 From cf7474a6f4eda22603591b7d6253dffc224e4784 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 21 Aug 2009 16:20:48 +0000 Subject: bnx2: Refine coalescing parameters. - Set the USE_INT_PARAM bit so the rx-frames-irq and tx-frames-irq will take effect on 5709. - Increase the default rx-frames to reduce interrupt count. - Decrease the default rx-frames-irq and tx-frames-irq to catch more events during NAPI poll. All these will reduce interrupts without affecting latency. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index e025833e664..ea6e6b73f49 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -4921,7 +4921,7 @@ bnx2_init_chip(struct bnx2 *bp) } if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI) - val |= BNX2_HC_CONFIG_ONE_SHOT; + val |= BNX2_HC_CONFIG_ONE_SHOT | BNX2_HC_CONFIG_USE_INT_PARAM; REG_WR(bp, BNX2_HC_CONFIG, val); @@ -7858,13 +7858,13 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->rx_csum = 1; - bp->tx_quick_cons_trip_int = 20; + bp->tx_quick_cons_trip_int = 2; bp->tx_quick_cons_trip = 20; - bp->tx_ticks_int = 80; + bp->tx_ticks_int = 18; bp->tx_ticks = 80; - bp->rx_quick_cons_trip_int = 6; - bp->rx_quick_cons_trip = 6; + bp->rx_quick_cons_trip_int = 2; + bp->rx_quick_cons_trip = 12; bp->rx_ticks_int = 18; bp->rx_ticks = 18; -- cgit v1.2.3-18-g5258 From 0ced9d01d19795f913b95cebedd7d03986671379 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 21 Aug 2009 16:20:49 +0000 Subject: bnx2: Use const on flash_table structure. The structure, once initialized, never changes. Signed-off-by: Benjamin Li Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 6 +++--- drivers/net/bnx2.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index ea6e6b73f49..58ab3f4fa5f 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -145,7 +145,7 @@ static DEFINE_PCI_DEVICE_TABLE(bnx2_pci_tbl) = { { 0, } }; -static struct flash_spec flash_table[] = +static const struct flash_spec flash_table[] = { #define BUFFERED_FLAGS (BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE) #define NONBUFFERED_FLAGS (BNX2_NV_WREN) @@ -234,7 +234,7 @@ static struct flash_spec flash_table[] = "Buffered flash (256kB)"}, }; -static struct flash_spec flash_5709 = { +static const struct flash_spec flash_5709 = { .flags = BNX2_NV_BUFFERED, .page_bits = BCM5709_FLASH_PAGE_BITS, .page_size = BCM5709_FLASH_PAGE_SIZE, @@ -4227,7 +4227,7 @@ bnx2_init_nvram(struct bnx2 *bp) { u32 val; int j, entry_count, rc = 0; - struct flash_spec *flash; + const struct flash_spec *flash; if (CHIP_NUM(bp) == CHIP_NUM_5709) { bp->flash_info = &flash_5709; diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 3c004b44cf7..7544188b654 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6889,7 +6889,7 @@ struct bnx2 { int pm_cap; int pcix_cap; - struct flash_spec *flash_info; + const struct flash_spec *flash_info; u32 flash_size; int status_stats_size; -- cgit v1.2.3-18-g5258 From 8fea0f0db87a4aaed41a93eed147af61cc5f9e3f Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 21 Aug 2009 16:20:50 +0000 Subject: bnx2: Update version to 2.0.2. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 58ab3f4fa5f..4450177a162 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -59,8 +59,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "2.0.1" -#define DRV_MODULE_RELDATE "May 6, 2009" +#define DRV_MODULE_VERSION "2.0.2" +#define DRV_MODULE_RELDATE "Aug 21, 2009" #define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-4.6.16.fw" #define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-4.6.16.fw" #define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-4.6.17.fw" -- cgit v1.2.3-18-g5258 From 1bb482f8a46000f77577948ff1c350275bba7dc9 Mon Sep 17 00:00:00 2001 From: Narender Kumar Date: Sun, 23 Aug 2009 08:35:09 +0000 Subject: netxen: ethtool statistics and control for LRO Add ethtool -K knob to control LRO in firmware. LRO path is completely separated from GRO, LRO packets are still fed with netif_receive_skb(). Also fix ethtool statistics to include LRO packets. Also use correct message type while configuring interrupt coalescing. Signed-off-by: Narender Kumar Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 22 +++++++++++-- drivers/net/netxen/netxen_nic_ctx.c | 2 -- drivers/net/netxen/netxen_nic_ethtool.c | 27 +++++++++++++++- drivers/net/netxen/netxen_nic_hw.c | 56 ++++++++++++++++++++++++++++++++- drivers/net/netxen/netxen_nic_init.c | 7 ++++- drivers/net/netxen/netxen_nic_main.c | 8 ++++- 6 files changed, 114 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 5abb41e2d02..fa43aa059c4 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -576,7 +576,8 @@ struct netxen_adapter_stats { u64 rxdropped; u64 txdropped; u64 csummed; - u64 no_rcv; + u64 rx_pkts; + u64 lro_pkts; u64 rxbytes; u64 txbytes; }; @@ -958,7 +959,8 @@ typedef struct { #define NX_NIC_H2C_OPCODE_PROXY_STOP_DONE 20 #define NX_NIC_H2C_OPCODE_GET_LINKEVENT 21 #define NX_NIC_C2C_OPCODE 22 -#define NX_NIC_H2C_OPCODE_LAST 23 +#define NX_NIC_H2C_OPCODE_CONFIG_HW_LRO 24 +#define NX_NIC_H2C_OPCODE_LAST 25 /* * Firmware --> Driver @@ -984,6 +986,19 @@ typedef struct { #define VPORT_MISS_MODE_ACCEPT_ALL 1 /* accept all packets */ #define VPORT_MISS_MODE_ACCEPT_MULTI 2 /* accept unmatched multicast */ +#define NX_NIC_LRO_REQUEST_FIRST 0 +#define NX_NIC_LRO_REQUEST_ADD_FLOW 1 +#define NX_NIC_LRO_REQUEST_DELETE_FLOW 2 +#define NX_NIC_LRO_REQUEST_TIMER 3 +#define NX_NIC_LRO_REQUEST_CLEANUP 4 +#define NX_NIC_LRO_REQUEST_ADD_FLOW_SCHEDULED 5 +#define NX_TOE_LRO_REQUEST_ADD_FLOW 6 +#define NX_TOE_LRO_REQUEST_ADD_FLOW_RESPONSE 7 +#define NX_TOE_LRO_REQUEST_DELETE_FLOW 8 +#define NX_TOE_LRO_REQUEST_DELETE_FLOW_RESPONSE 9 +#define NX_TOE_LRO_REQUEST_TIMER 10 +#define NX_NIC_LRO_REQUEST_LAST 11 + #define NX_FW_CAPABILITY_LINK_NOTIFICATION (1 << 5) #define NX_FW_CAPABILITY_SWITCHING (1 << 6) #define NX_FW_CAPABILITY_PEXQ (1 << 7) @@ -1064,6 +1079,7 @@ typedef struct { #define NETXEN_NIC_MSI_ENABLED 0x02 #define NETXEN_NIC_MSIX_ENABLED 0x04 +#define NETXEN_NIC_LRO_ENABLED 0x08 #define NETXEN_IS_MSI_FAMILY(adapter) \ ((adapter)->flags & (NETXEN_NIC_MSI_ENABLED | NETXEN_NIC_MSIX_ENABLED)) @@ -1290,6 +1306,8 @@ void netxen_advert_link_change(struct netxen_adapter *adapter, int linkup); int nx_fw_cmd_set_mtu(struct netxen_adapter *adapter, int mtu); int netxen_nic_change_mtu(struct net_device *netdev, int new_mtu); +int netxen_config_hw_lro(struct netxen_adapter *adapter, int enable); +int netxen_send_lro_cleanup(struct netxen_adapter *adapter); int netxen_nic_set_mac(struct net_device *netdev, void *p); struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev); diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 412d65829d2..9e0469643d3 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -203,8 +203,6 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter) cap = (NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN); cap |= (NX_CAP0_JUMBO_CONTIGUOUS | NX_CAP0_LRO_CONTIGUOUS); - if (adapter->capabilities & NX_FW_CAPABILITY_HW_LRO) - cap |= NX_CAP0_HW_LRO; prq->capabilities[0] = cpu_to_le32(cap); prq->host_int_crb_mode = diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 39a308c363c..db66e7053b9 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -57,7 +57,8 @@ static const struct netxen_nic_stats netxen_nic_gstrings_stats[] = { {"rx_dropped", NETXEN_NIC_STAT(stats.rxdropped)}, {"tx_dropped", NETXEN_NIC_STAT(stats.txdropped)}, {"csummed", NETXEN_NIC_STAT(stats.csummed)}, - {"no_rcv", NETXEN_NIC_STAT(stats.no_rcv)}, + {"rx_pkts", NETXEN_NIC_STAT(stats.rx_pkts)}, + {"lro_pkts", NETXEN_NIC_STAT(stats.lro_pkts)}, {"rx_bytes", NETXEN_NIC_STAT(stats.rxbytes)}, {"tx_bytes", NETXEN_NIC_STAT(stats.txbytes)}, }; @@ -941,6 +942,28 @@ static int netxen_get_intr_coalesce(struct net_device *netdev, return 0; } +static int netxen_nic_set_flags(struct net_device *netdev, u32 data) +{ + struct netxen_adapter *adapter = netdev_priv(netdev); + int hw_lro; + + if (!(adapter->capabilities & NX_FW_CAPABILITY_HW_LRO)) + return -EINVAL; + + ethtool_op_set_flags(netdev, data); + + hw_lro = (data & ETH_FLAG_LRO) ? NETXEN_NIC_LRO_ENABLED : 0; + + if (netxen_config_hw_lro(adapter, hw_lro)) + return -EIO; + + if ((hw_lro == 0) && netxen_send_lro_cleanup(adapter)) + return -EIO; + + + return 0; +} + struct ethtool_ops netxen_nic_ethtool_ops = { .get_settings = netxen_nic_get_settings, .set_settings = netxen_nic_set_settings, @@ -968,4 +991,6 @@ struct ethtool_ops netxen_nic_ethtool_ops = { .set_rx_csum = netxen_nic_set_rx_csum, .get_coalesce = netxen_get_intr_coalesce, .set_coalesce = netxen_set_intr_coalesce, + .get_flags = ethtool_op_get_flags, + .set_flags = netxen_nic_set_flags, }; diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 673dcf5ea53..965f783d39f 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -643,7 +643,7 @@ int netxen_config_intr_coalesce(struct netxen_adapter *adapter) memset(&req, 0, sizeof(nx_nic_req_t)); - req.qhdr = cpu_to_le64(NX_NIC_REQUEST << 23); + req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23); word = NETXEN_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16); req.req_hdr = cpu_to_le64(word); @@ -659,6 +659,35 @@ int netxen_config_intr_coalesce(struct netxen_adapter *adapter) return rv; } +int netxen_config_hw_lro(struct netxen_adapter *adapter, int enable) +{ + nx_nic_req_t req; + u64 word; + int rv = 0; + + if ((adapter->flags & NETXEN_NIC_LRO_ENABLED) == enable) + return 0; + + memset(&req, 0, sizeof(nx_nic_req_t)); + + req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23); + + word = NX_NIC_H2C_OPCODE_CONFIG_HW_LRO | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + + req.words[0] = cpu_to_le64(enable); + + rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) { + printk(KERN_ERR "ERROR. Could not send " + "configure hw lro request\n"); + } + + adapter->flags ^= NETXEN_NIC_LRO_ENABLED; + + return rv; +} + #define RSS_HASHTYPE_IP_TCP 0x3 int netxen_config_rss(struct netxen_adapter *adapter, int enable) @@ -752,6 +781,29 @@ int netxen_linkevent_request(struct netxen_adapter *adapter, int enable) return rv; } +int netxen_send_lro_cleanup(struct netxen_adapter *adapter) +{ + nx_nic_req_t req; + u64 word; + int rv; + + memset(&req, 0, sizeof(nx_nic_req_t)); + req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23); + + word = NX_NIC_H2C_OPCODE_LRO_REQUEST | + ((u64)adapter->portnum << 16) | + ((u64)NX_NIC_LRO_REQUEST_CLEANUP << 56) ; + + req.req_hdr = cpu_to_le64(word); + + rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) { + printk(KERN_ERR "%s: could not cleanup lro flows\n", + adapter->netdev->name); + } + return rv; +} + /* * netxen_nic_change_mtu - Change the Maximum Transfer Unit * @returns 0 on success, negative on failure @@ -2066,6 +2118,8 @@ void netxen_nic_get_firmware_info(struct netxen_adapter *adapter) if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222)) adapter->capabilities = NXRD32(adapter, CRB_FW_CAPABILITIES_1); + + adapter->flags &= ~NETXEN_NIC_LRO_ENABLED; } int diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index e8bdbf9fefb..c3609e42287 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1277,7 +1277,7 @@ netxen_process_rcv(struct netxen_adapter *adapter, napi_gro_receive(&sds_ring->napi, skb); - adapter->stats.no_rcv++; + adapter->stats.rx_pkts++; adapter->stats.rxbytes += length; return buffer; @@ -1350,8 +1350,13 @@ netxen_process_lro(struct netxen_adapter *adapter, th->psh = push; th->seq = htonl(seq_number); + length = skb->len; + netif_receive_skb(skb); + adapter->stats.lro_pkts++; + adapter->stats.rxbytes += length; + return buffer; } diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 4e3fb30d66f..de67e42a297 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -892,6 +892,9 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) netxen_config_intr_coalesce(adapter); + if (adapter->capabilities & NX_FW_CAPABILITY_HW_LRO) + netxen_config_hw_lro(adapter, NETXEN_NIC_LRO_ENABLED); + netxen_napi_enable(adapter); if (adapter->capabilities & NX_FW_CAPABILITY_LINK_NOTIFICATION) @@ -1077,6 +1080,9 @@ netxen_setup_netdev(struct netxen_adapter *adapter, if (adapter->capabilities & NX_FW_CAPABILITY_FVLANTX) netdev->features |= (NETIF_F_HW_VLAN_TX); + if (adapter->capabilities & NX_FW_CAPABILITY_HW_LRO) + netdev->features |= NETIF_F_LRO; + netdev->irq = adapter->msix_entries[0].vector; err = netxen_napi_add(adapter, netdev); @@ -1812,7 +1818,7 @@ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev) memset(stats, 0, sizeof(*stats)); - stats->rx_packets = adapter->stats.no_rcv; + stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts; stats->tx_packets = adapter->stats.xmitfinished; stats->rx_bytes = adapter->stats.rxbytes; stats->tx_bytes = adapter->stats.txbytes; -- cgit v1.2.3-18-g5258 From 1dbc84a7f6c2ebd8c69299e1adef22ee26db38c0 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 23 Aug 2009 08:35:10 +0000 Subject: netxen: fix firmware reset logic If netxen_need_fw_reset() return 0 [ implies firmware is up and running], still go through dma mask check, etc. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index de67e42a297..008657423f8 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -754,8 +754,10 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) netxen_request_firmware(adapter); err = netxen_need_fw_reset(adapter); - if (err <= 0) + if (err < 0) return err; + if (err == 0) + goto wait_init; if (first_boot != 0x55555555) { NXWR32(adapter, CRB_CMDPEG_STATE, 0); -- cgit v1.2.3-18-g5258 From ce644ed4db3ee1075ebd9f4acc403e1f9410db21 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 23 Aug 2009 08:35:11 +0000 Subject: netxen: refactor tx dma mapping code Move all tx skb mapping code into netxen_map_tx_skb(). Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_main.c | 112 +++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 008657423f8..f618e7c8eeb 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1518,22 +1518,52 @@ netxen_tso_check(struct net_device *netdev, barrier(); } -static void -netxen_clean_tx_dma_mapping(struct pci_dev *pdev, - struct netxen_cmd_buffer *pbuf, int last) +static int +netxen_map_tx_skb(struct pci_dev *pdev, + struct sk_buff *skb, struct netxen_cmd_buffer *pbuf) { - int k; - struct netxen_skb_frag *buffrag; + struct netxen_skb_frag *nf; + struct skb_frag_struct *frag; + int i, nr_frags; + dma_addr_t map; + + nr_frags = skb_shinfo(skb)->nr_frags; + nf = &pbuf->frag_array[0]; + + map = pci_map_single(pdev, skb->data, + skb_headlen(skb), PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, map)) + goto out_err; - buffrag = &pbuf->frag_array[0]; - pci_unmap_single(pdev, buffrag->dma, - buffrag->length, PCI_DMA_TODEVICE); + nf->dma = map; + nf->length = skb_headlen(skb); + + for (i = 0; i < nr_frags; i++) { + frag = &skb_shinfo(skb)->frags[i]; + nf = &pbuf->frag_array[i+1]; + + map = pci_map_page(pdev, frag->page, frag->page_offset, + frag->size, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, map)) + goto unwind; + + nf->dma = map; + nf->length = frag->size; + } + + return 0; - for (k = 1; k < last; k++) { - buffrag = &pbuf->frag_array[k]; - pci_unmap_page(pdev, buffrag->dma, - buffrag->length, PCI_DMA_TODEVICE); +unwind: + while (i > 0) { + nf = &pbuf->frag_array[i]; + pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE); } + + nf = &pbuf->frag_array[0]; + pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE); + +out_err: + return -ENOMEM; } static inline void @@ -1548,17 +1578,14 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct netxen_adapter *adapter = netdev_priv(netdev); struct nx_host_tx_ring *tx_ring = adapter->tx_ring; - struct skb_frag_struct *frag; struct netxen_cmd_buffer *pbuf; struct netxen_skb_frag *buffrag; struct cmd_desc_type0 *hwdesc, *first_desc; struct pci_dev *pdev; - dma_addr_t temp_dma; int i, k; - unsigned long offset; u32 producer; - int len, frag_count, no_of_desc; + int frag_count, no_of_desc; u32 num_txd = tx_ring->num_desc; frag_count = skb_shinfo(skb)->nr_frags + 1; @@ -1572,72 +1599,53 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } producer = tx_ring->producer; + pbuf = &tx_ring->cmd_buf_arr[producer]; pdev = adapter->pdev; - len = skb->len - skb->data_len; - temp_dma = pci_map_single(pdev, skb->data, len, PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(pdev, temp_dma)) + if (netxen_map_tx_skb(pdev, skb, pbuf)) goto drop_packet; - pbuf = &tx_ring->cmd_buf_arr[producer]; pbuf->skb = skb; pbuf->frag_count = frag_count; - buffrag = &pbuf->frag_array[0]; - buffrag->dma = temp_dma; - buffrag->length = len; - first_desc = hwdesc = &tx_ring->desc_head[producer]; netxen_clear_cmddesc((u64 *)hwdesc); - netxen_set_tx_frags_len(hwdesc, frag_count, skb->len); - netxen_set_tx_port(hwdesc, adapter->portnum); - hwdesc->buffer_length[0] = cpu_to_le16(len); - hwdesc->addr_buffer1 = cpu_to_le64(temp_dma); + netxen_set_tx_frags_len(first_desc, frag_count, skb->len); + netxen_set_tx_port(first_desc, adapter->portnum); - for (i = 1, k = 1; i < frag_count; i++, k++) { + for (i = 0; i < frag_count; i++) { - /* move to next desc. if there is a need */ - if ((i & 0x3) == 0) { - k = 0; + k = i % 4; + + if ((k == 0) && (i > 0)) { + /* move to next desc.*/ producer = get_next_index(producer, num_txd); hwdesc = &tx_ring->desc_head[producer]; netxen_clear_cmddesc((u64 *)hwdesc); - pbuf = &tx_ring->cmd_buf_arr[producer]; - pbuf->skb = NULL; - } - buffrag = &pbuf->frag_array[i]; - frag = &skb_shinfo(skb)->frags[i - 1]; - len = frag->size; - offset = frag->page_offset; - - temp_dma = pci_map_page(pdev, frag->page, offset, - len, PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(pdev, temp_dma)) { - netxen_clean_tx_dma_mapping(pdev, pbuf, i); - goto drop_packet; + tx_ring->cmd_buf_arr[producer].skb = NULL; } - buffrag->dma = temp_dma; - buffrag->length = len; + buffrag = &pbuf->frag_array[i]; - hwdesc->buffer_length[k] = cpu_to_le16(len); + hwdesc->buffer_length[k] = cpu_to_le16(buffrag->length); switch (k) { case 0: - hwdesc->addr_buffer1 = cpu_to_le64(temp_dma); + hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma); break; case 1: - hwdesc->addr_buffer2 = cpu_to_le64(temp_dma); + hwdesc->addr_buffer2 = cpu_to_le64(buffrag->dma); break; case 2: - hwdesc->addr_buffer3 = cpu_to_le64(temp_dma); + hwdesc->addr_buffer3 = cpu_to_le64(buffrag->dma); break; case 3: - hwdesc->addr_buffer4 = cpu_to_le64(temp_dma); + hwdesc->addr_buffer4 = cpu_to_le64(buffrag->dma); break; } } + tx_ring->producer = get_next_index(producer, num_txd); netxen_tso_check(netdev, tx_ring, first_desc, skb); -- cgit v1.2.3-18-g5258 From 22b5794b5d58ea81e91d68d00e49357b66d5a559 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Sun, 23 Aug 2009 08:35:12 +0000 Subject: netxen: implement pci driver shutdown Implement pci driver shutdown functionality, this helps quiescing all PCI transaction before chipset is reset. Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_main.c | 38 ++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index f618e7c8eeb..794c19b2254 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -922,6 +922,8 @@ netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) netxen_p3_free_mac_list(adapter); + adapter->set_promisc(adapter, NETXEN_NIU_NON_PROMISC_MODE); + netxen_napi_disable(adapter); netxen_release_tx_buffers(adapter); @@ -1288,14 +1290,11 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) free_netdev(netdev); } - -#ifdef CONFIG_PM -static int -netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state) +static int __netxen_nic_shutdown(struct pci_dev *pdev) { - struct netxen_adapter *adapter = pci_get_drvdata(pdev); struct net_device *netdev = adapter->netdev; + int retval; netif_device_detach(netdev); @@ -1307,7 +1306,12 @@ netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state) netxen_nic_detach(adapter); - pci_save_state(pdev); + if (adapter->portnum == 0) + netxen_free_dummy_dma(adapter); + + retval = pci_save_state(pdev); + if (retval) + return retval; if (netxen_nic_wol_supported(adapter)) { pci_enable_wake(pdev, PCI_D3cold, 1); @@ -1315,10 +1319,27 @@ netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state) } pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; } +static void netxen_nic_shutdown(struct pci_dev *pdev) +{ + if (__netxen_nic_shutdown(pdev)) + return; +} +#ifdef CONFIG_PM +static int +netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state) +{ + int retval; + + retval = __netxen_nic_shutdown(pdev); + if (retval) + return retval; + + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} static int netxen_nic_resume(struct pci_dev *pdev) @@ -2068,8 +2089,9 @@ static struct pci_driver netxen_driver = { .remove = __devexit_p(netxen_nic_remove), #ifdef CONFIG_PM .suspend = netxen_nic_suspend, - .resume = netxen_nic_resume + .resume = netxen_nic_resume, #endif + .shutdown = netxen_nic_shutdown }; static int __init netxen_init_module(void) -- cgit v1.2.3-18-g5258 From 7d6fd5e7e97a2188d56441e4e96494c21c5994a7 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sun, 23 Aug 2009 08:35:13 +0000 Subject: netxen: remove netxen_nic_phan_reg.h Consolidate register definitions in netxen_nic_hdr.h Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 31 +++--- drivers/net/netxen/netxen_nic_ctx.c | 1 - drivers/net/netxen/netxen_nic_ethtool.c | 1 - drivers/net/netxen/netxen_nic_hdr.h | 85 ++++++++++++++- drivers/net/netxen/netxen_nic_hw.c | 1 - drivers/net/netxen/netxen_nic_hw.h | 18 ---- drivers/net/netxen/netxen_nic_init.c | 1 - drivers/net/netxen/netxen_nic_main.c | 1 - drivers/net/netxen/netxen_nic_phan_reg.h | 178 ------------------------------- 9 files changed, 102 insertions(+), 215 deletions(-) delete mode 100644 drivers/net/netxen/netxen_nic_phan_reg.h (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index fa43aa059c4..7a93f8275c9 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -53,6 +53,7 @@ #include #include +#include "netxen_nic_hdr.h" #include "netxen_nic_hw.h" #define _NETXEN_NIC_LINUX_MAJOR 4 @@ -227,8 +228,6 @@ #define MPORT_SINGLE_FUNCTION_MODE 0x1111 #define MPORT_MULTI_FUNCTION_MODE 0x2222 -#include "netxen_nic_phan_reg.h" - /* * NetXen host-peg signal message structure * @@ -503,17 +502,11 @@ struct netxen_skb_frag { u64 length; }; -#define _netxen_set_bits(config_word, start, bits, val) {\ - unsigned long long __tmask = (((1ULL << (bits)) - 1) << (start));\ - unsigned long long __tvalue = (val); \ - (config_word) &= ~__tmask; \ - (config_word) |= (((__tvalue) << (start)) & __tmask); \ -} - -#define _netxen_clear_bits(config_word, start, bits) {\ - unsigned long long __tmask = (((1ULL << (bits)) - 1) << (start)); \ - (config_word) &= ~__tmask; \ -} +struct netxen_recv_crb { + u32 crb_rcv_producer[NUM_RCV_DESC_RINGS]; + u32 crb_sts_consumer[NUM_STS_DESC_RINGS]; + u32 sw_int_mask[NUM_STS_DESC_RINGS]; +}; /* Following defines are for the state of the buffers */ #define NETXEN_BUFFER_FREE 0 @@ -1194,6 +1187,18 @@ struct netxen_adapter { const struct firmware *fw; }; +/* Set promiscuous mode for a GbE interface */ +int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, u32 mode); +int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, + u32 mode); +/* Generic enable for GbE ports. Will detect the speed of the link. */ +int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port); +int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port); + +/* Disable a GbE interface */ +int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter); +int netxen_niu_disable_xg_port(struct netxen_adapter *adapter); + int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter); int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter); int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter); diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 9e0469643d3..3d676fecb0a 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -30,7 +30,6 @@ #include "netxen_nic_hw.h" #include "netxen_nic.h" -#include "netxen_nic_phan_reg.h" #define NXHAL_VERSION 1 diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index db66e7053b9..3886135006e 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -37,7 +37,6 @@ #include "netxen_nic.h" #include "netxen_nic_hw.h" -#include "netxen_nic_phan_reg.h" struct netxen_nic_stats { char stat_string[ETH_GSTRING_LEN]; diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index a7328584a21..c4a4a8ba14f 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h @@ -723,9 +723,92 @@ enum { #define NETXEN_FW_VERSION_MINOR (NETXEN_CAM_RAM(0x154)) #define NETXEN_FW_VERSION_SUB (NETXEN_CAM_RAM(0x158)) #define NETXEN_ROM_LOCK_ID (NETXEN_CAM_RAM(0x100)) +#define NETXEN_PHY_LOCK_ID (NETXEN_CAM_RAM(0x120)) #define NETXEN_CRB_WIN_LOCK_ID (NETXEN_CAM_RAM(0x124)) -#define NETXEN_PHY_LOCK_ID (NETXEN_CAM_RAM(0x120)) +#define NIC_CRB_BASE (NETXEN_CAM_RAM(0x200)) +#define NIC_CRB_BASE_2 (NETXEN_CAM_RAM(0x700)) +#define NETXEN_NIC_REG(X) (NIC_CRB_BASE+(X)) +#define NETXEN_NIC_REG_2(X) (NIC_CRB_BASE_2+(X)) + +#define NX_CDRP_CRB_OFFSET (NETXEN_NIC_REG(0x18)) +#define NX_ARG1_CRB_OFFSET (NETXEN_NIC_REG(0x1c)) +#define NX_ARG2_CRB_OFFSET (NETXEN_NIC_REG(0x20)) +#define NX_ARG3_CRB_OFFSET (NETXEN_NIC_REG(0x24)) +#define NX_SIGN_CRB_OFFSET (NETXEN_NIC_REG(0x28)) + +#define CRB_HOST_DUMMY_BUF_ADDR_HI (NETXEN_NIC_REG(0x3c)) +#define CRB_HOST_DUMMY_BUF_ADDR_LO (NETXEN_NIC_REG(0x40)) + +#define CRB_CMDPEG_STATE (NETXEN_NIC_REG(0x50)) +#define CRB_RCVPEG_STATE (NETXEN_NIC_REG(0x13c)) + +#define CRB_XG_STATE (NETXEN_NIC_REG(0x94)) +#define CRB_XG_STATE_P3 (NETXEN_NIC_REG(0x98)) +#define CRB_PF_LINK_SPEED_1 (NETXEN_NIC_REG(0xe8)) +#define CRB_PF_LINK_SPEED_2 (NETXEN_NIC_REG(0xec)) + +#define CRB_MPORT_MODE (NETXEN_NIC_REG(0xc4)) +#define CRB_DMA_SHIFT (NETXEN_NIC_REG(0xcc)) +#define CRB_INT_VECTOR (NETXEN_NIC_REG(0xd4)) + +#define CRB_CMD_PRODUCER_OFFSET (NETXEN_NIC_REG(0x08)) +#define CRB_CMD_CONSUMER_OFFSET (NETXEN_NIC_REG(0x0c)) +#define CRB_CMD_PRODUCER_OFFSET_1 (NETXEN_NIC_REG(0x1ac)) +#define CRB_CMD_CONSUMER_OFFSET_1 (NETXEN_NIC_REG(0x1b0)) +#define CRB_CMD_PRODUCER_OFFSET_2 (NETXEN_NIC_REG(0x1b8)) +#define CRB_CMD_CONSUMER_OFFSET_2 (NETXEN_NIC_REG(0x1bc)) +#define CRB_CMD_PRODUCER_OFFSET_3 (NETXEN_NIC_REG(0x1d0)) +#define CRB_CMD_CONSUMER_OFFSET_3 (NETXEN_NIC_REG(0x1d4)) +#define CRB_TEMP_STATE (NETXEN_NIC_REG(0x1b4)) + +#define CRB_V2P_0 (NETXEN_NIC_REG(0x290)) +#define CRB_V2P(port) (CRB_V2P_0+((port)*4)) +#define CRB_DRIVER_VERSION (NETXEN_NIC_REG(0x2a0)) + +#define CRB_SW_INT_MASK_0 (NETXEN_NIC_REG(0x1d8)) +#define CRB_SW_INT_MASK_1 (NETXEN_NIC_REG(0x1e0)) +#define CRB_SW_INT_MASK_2 (NETXEN_NIC_REG(0x1e4)) +#define CRB_SW_INT_MASK_3 (NETXEN_NIC_REG(0x1e8)) + +#define CRB_FW_CAPABILITIES_1 (NETXEN_CAM_RAM(0x128)) +#define CRB_MAC_BLOCK_START (NETXEN_CAM_RAM(0x1c0)) + +/* + * capabilities register, can be used to selectively enable/disable features + * for backward compability + */ +#define CRB_NIC_CAPABILITIES_HOST NETXEN_NIC_REG(0x1a8) +#define CRB_NIC_CAPABILITIES_FW NETXEN_NIC_REG(0x1dc) +#define CRB_NIC_MSI_MODE_HOST NETXEN_NIC_REG(0x270) +#define CRB_NIC_MSI_MODE_FW NETXEN_NIC_REG(0x274) + +#define INTR_SCHEME_PERPORT 0x1 +#define MSI_MODE_MULTIFUNC 0x1 + +/* used for ethtool tests */ +#define CRB_SCRATCHPAD_TEST NETXEN_NIC_REG(0x280) + +/* + * CrbPortPhanCntrHi/Lo is used to pass the address of HostPhantomIndex address + * which can be read by the Phantom host to get producer/consumer indexes from + * Phantom/Casper. If it is not HOST_SHARED_MEMORY, then the following + * registers will be used for the addresses of the ring's shared memory + * on the Phantom. + */ + +#define nx_get_temp_val(x) ((x) >> 16) +#define nx_get_temp_state(x) ((x) & 0xffff) +#define nx_encode_temp(val, state) (((val) << 16) | (state)) + +/* + * Temperature control. + */ +enum { + NX_TEMP_NORMAL = 0x1, /* Normal operating range */ + NX_TEMP_WARN, /* Sound alert, temperature getting high */ + NX_TEMP_PANIC /* Fatal error, hardware has shut down. */ +}; /* Lock IDs for PHY lock */ #define PHY_LOCK_DRIVER 0x44524956 diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 965f783d39f..9138bbcbb80 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -30,7 +30,6 @@ #include "netxen_nic.h" #include "netxen_nic_hw.h" -#include "netxen_nic_phan_reg.h" #include diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h index d4e83333978..fc0638f2d6d 100644 --- a/drivers/net/netxen/netxen_nic_hw.h +++ b/drivers/net/netxen/netxen_nic_hw.h @@ -31,8 +31,6 @@ #ifndef __NETXEN_NIC_HW_H_ #define __NETXEN_NIC_HW_H_ -#include "netxen_nic_hdr.h" - /* Hardware memory size of 128 meg */ #define NETXEN_MEMADDR_MAX (128 * 1024 * 1024) @@ -387,22 +385,6 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter); #define netxen_xg_soft_reset(config_word) \ ((config_word) |= 1 << 4) -/* Set promiscuous mode for a GbE interface */ -int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, - u32 mode); -int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, - u32 mode); - -/* Generic enable for GbE ports. Will detect the speed of the link. */ -int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port); - -int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port); - -/* Disable a GbE interface */ -int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter); - -int netxen_niu_disable_xg_port(struct netxen_adapter *adapter); - typedef struct { unsigned valid; unsigned start_128M; diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index c3609e42287..474c568adcc 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -32,7 +32,6 @@ #include #include "netxen_nic.h" #include "netxen_nic_hw.h" -#include "netxen_nic_phan_reg.h" struct crb_addr_pair { u32 addr; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 794c19b2254..bd4589f1d46 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -33,7 +33,6 @@ #include "netxen_nic_hw.h" #include "netxen_nic.h" -#include "netxen_nic_phan_reg.h" #include #include diff --git a/drivers/net/netxen/netxen_nic_phan_reg.h b/drivers/net/netxen/netxen_nic_phan_reg.h deleted file mode 100644 index b73a62ca74f..00000000000 --- a/drivers/net/netxen/netxen_nic_phan_reg.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2003 - 2009 NetXen, Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA. - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE. - * - * Contact Information: - * info@netxen.com - * NetXen Inc, - * 18922 Forge Drive - * Cupertino, CA 95014-0701 - * - */ - -#ifndef __NIC_PHAN_REG_H_ -#define __NIC_PHAN_REG_H_ - -/* - * CRB Registers or queue message done only at initialization time. - */ -#define NIC_CRB_BASE NETXEN_CAM_RAM(0x200) -#define NETXEN_NIC_REG(X) (NIC_CRB_BASE+(X)) -#define NIC_CRB_BASE_2 NETXEN_CAM_RAM(0x700) -#define NETXEN_NIC_REG_2(X) (NIC_CRB_BASE_2+(X)) - -#define CRB_PHAN_CNTRL_LO_OFFSET NETXEN_NIC_REG(0x00) -#define CRB_PHAN_CNTRL_HI_OFFSET NETXEN_NIC_REG(0x04) -#define CRB_CMD_PRODUCER_OFFSET NETXEN_NIC_REG(0x08) -#define CRB_CMD_CONSUMER_OFFSET NETXEN_NIC_REG(0x0c) -#define CRB_PAUSE_ADDR_LO NETXEN_NIC_REG(0x10) -#define CRB_PAUSE_ADDR_HI NETXEN_NIC_REG(0x14) -#define NX_CDRP_CRB_OFFSET NETXEN_NIC_REG(0x18) -#define NX_ARG1_CRB_OFFSET NETXEN_NIC_REG(0x1c) -#define NX_ARG2_CRB_OFFSET NETXEN_NIC_REG(0x20) -#define NX_ARG3_CRB_OFFSET NETXEN_NIC_REG(0x24) -#define NX_SIGN_CRB_OFFSET NETXEN_NIC_REG(0x28) -#define CRB_CMD_INTR_LOOP NETXEN_NIC_REG(0x20) -#define CRB_CMD_DMA_LOOP NETXEN_NIC_REG(0x24) -#define CRB_RCV_INTR_LOOP NETXEN_NIC_REG(0x28) -#define CRB_RCV_DMA_LOOP NETXEN_NIC_REG(0x2c) -#define CRB_ENABLE_TX_INTR NETXEN_NIC_REG(0x30) -#define CRB_MMAP_ADDR_3 NETXEN_NIC_REG(0x34) -#define CRB_CMDPEG_CMDRING NETXEN_NIC_REG(0x38) -#define CRB_HOST_DUMMY_BUF_ADDR_HI NETXEN_NIC_REG(0x3c) -#define CRB_HOST_DUMMY_BUF_ADDR_LO NETXEN_NIC_REG(0x40) -#define CRB_MMAP_ADDR_0 NETXEN_NIC_REG(0x44) -#define CRB_MMAP_ADDR_1 NETXEN_NIC_REG(0x48) -#define CRB_MMAP_ADDR_2 NETXEN_NIC_REG(0x4c) -#define CRB_CMDPEG_STATE NETXEN_NIC_REG(0x50) -#define CRB_MMAP_SIZE_0 NETXEN_NIC_REG(0x54) -#define CRB_MMAP_SIZE_1 NETXEN_NIC_REG(0x58) -#define CRB_MMAP_SIZE_2 NETXEN_NIC_REG(0x5c) -#define CRB_MMAP_SIZE_3 NETXEN_NIC_REG(0x60) -#define CRB_GLOBAL_INT_COAL NETXEN_NIC_REG(0x64) -#define CRB_INT_COAL_MODE NETXEN_NIC_REG(0x68) -#define CRB_MAX_RCV_BUFS NETXEN_NIC_REG(0x6c) -#define CRB_TX_INT_THRESHOLD NETXEN_NIC_REG(0x70) -#define CRB_RX_PKT_TIMER NETXEN_NIC_REG(0x74) -#define CRB_TX_PKT_TIMER NETXEN_NIC_REG(0x78) -#define CRB_RX_PKT_CNT NETXEN_NIC_REG(0x7c) -#define CRB_RX_TMR_CNT NETXEN_NIC_REG(0x80) -#define CRB_RX_LRO_TIMER NETXEN_NIC_REG(0x84) -#define CRB_RX_LRO_MID_TIMER NETXEN_NIC_REG(0x88) -#define CRB_DMA_MAX_RCV_BUFS NETXEN_NIC_REG(0x8c) -#define CRB_MAX_DMA_ENTRIES NETXEN_NIC_REG(0x90) -#define CRB_XG_STATE NETXEN_NIC_REG(0x94) /* XG Link status */ -#define CRB_XG_STATE_P3 NETXEN_NIC_REG(0x98) /* XG PF Link status */ -#define CRB_AGENT_TX_SIZE NETXEN_NIC_REG(0x9c) -#define CRB_AGENT_TX_TYPE NETXEN_NIC_REG(0xa0) -#define CRB_AGENT_TX_ADDR NETXEN_NIC_REG(0xa4) -#define CRB_AGENT_TX_MSS NETXEN_NIC_REG(0xa8) -#define CRB_TX_STATE NETXEN_NIC_REG(0xac) -#define CRB_TX_COUNT NETXEN_NIC_REG(0xb0) -#define CRB_RX_STATE NETXEN_NIC_REG(0xb4) -#define CRB_RX_PERF_DEBUG_1 NETXEN_NIC_REG(0xb8) -#define CRB_RX_LRO_CONTROL NETXEN_NIC_REG(0xbc) -#define CRB_RX_LRO_START_NUM NETXEN_NIC_REG(0xc0) -#define CRB_MPORT_MODE NETXEN_NIC_REG(0xc4) -#define CRB_CMD_RING_SIZE NETXEN_NIC_REG(0xc8) -#define CRB_DMA_SHIFT NETXEN_NIC_REG(0xcc) -#define CRB_INT_VECTOR NETXEN_NIC_REG(0xd4) -#define CRB_CTX_RESET NETXEN_NIC_REG(0xd8) -#define CRB_HOST_STS_PROD NETXEN_NIC_REG(0xdc) -#define CRB_HOST_STS_CONS NETXEN_NIC_REG(0xe0) -#define CRB_PEG_CMD_PROD NETXEN_NIC_REG(0xe4) -#define CRB_PF_LINK_SPEED_1 NETXEN_NIC_REG(0xe8) -#define CRB_PF_LINK_SPEED_2 NETXEN_NIC_REG(0xec) -#define CRB_HOST_BUFFER_CONS NETXEN_NIC_REG(0xf0) -#define CRB_JUMBO_BUFFER_PROD NETXEN_NIC_REG(0xf4) -#define CRB_JUMBO_BUFFER_CONS NETXEN_NIC_REG(0xf8) -#define CRB_HOST_DUMMY_BUF NETXEN_NIC_REG(0xfc) - -#define CRB_RCVPEG_STATE NETXEN_NIC_REG(0x13c) -#define CRB_CMD_PRODUCER_OFFSET_1 NETXEN_NIC_REG(0x1ac) -#define CRB_CMD_CONSUMER_OFFSET_1 NETXEN_NIC_REG(0x1b0) -#define CRB_CMD_PRODUCER_OFFSET_2 NETXEN_NIC_REG(0x1b8) -#define CRB_CMD_CONSUMER_OFFSET_2 NETXEN_NIC_REG(0x1bc) -#define CRB_CMD_PRODUCER_OFFSET_3 NETXEN_NIC_REG(0x1d0) -#define CRB_CMD_CONSUMER_OFFSET_3 NETXEN_NIC_REG(0x1d4) -#define CRB_TEMP_STATE NETXEN_NIC_REG(0x1b4) - -#define CRB_V2P_0 NETXEN_NIC_REG(0x290) -#define CRB_V2P_1 NETXEN_NIC_REG(0x294) -#define CRB_V2P_2 NETXEN_NIC_REG(0x298) -#define CRB_V2P_3 NETXEN_NIC_REG(0x29c) -#define CRB_V2P(port) (CRB_V2P_0+((port)*4)) -#define CRB_DRIVER_VERSION NETXEN_NIC_REG(0x2a0) -#define CRB_SW_INT_MASK_0 NETXEN_NIC_REG(0x1d8) -#define CRB_SW_INT_MASK_1 NETXEN_NIC_REG(0x1e0) -#define CRB_SW_INT_MASK_2 NETXEN_NIC_REG(0x1e4) -#define CRB_SW_INT_MASK_3 NETXEN_NIC_REG(0x1e8) - -#define CRB_FW_CAPABILITIES_1 NETXEN_CAM_RAM(0x128) -#define CRB_MAC_BLOCK_START NETXEN_CAM_RAM(0x1c0) - -/* - * capabilities register, can be used to selectively enable/disable features - * for backward compability - */ -#define CRB_NIC_CAPABILITIES_HOST NETXEN_NIC_REG(0x1a8) -#define CRB_NIC_CAPABILITIES_FW NETXEN_NIC_REG(0x1dc) -#define CRB_NIC_MSI_MODE_HOST NETXEN_NIC_REG(0x270) -#define CRB_NIC_MSI_MODE_FW NETXEN_NIC_REG(0x274) - -#define INTR_SCHEME_PERPORT 0x1 -#define MSI_MODE_MULTIFUNC 0x1 - -/* used for ethtool tests */ -#define CRB_SCRATCHPAD_TEST NETXEN_NIC_REG(0x280) - -/* - * CrbPortPhanCntrHi/Lo is used to pass the address of HostPhantomIndex address - * which can be read by the Phantom host to get producer/consumer indexes from - * Phantom/Casper. If it is not HOST_SHARED_MEMORY, then the following - * registers will be used for the addresses of the ring's shared memory - * on the Phantom. - */ - -#define nx_get_temp_val(x) ((x) >> 16) -#define nx_get_temp_state(x) ((x) & 0xffff) -#define nx_encode_temp(val, state) (((val) << 16) | (state)) - -/* - * CRB registers used by the receive peg logic. - */ - -struct netxen_recv_crb { - u32 crb_rcv_producer[NUM_RCV_DESC_RINGS]; - u32 crb_sts_consumer[NUM_STS_DESC_RINGS]; - u32 sw_int_mask[NUM_STS_DESC_RINGS]; -}; - -/* - * Temperature control. - */ -enum { - NX_TEMP_NORMAL = 0x1, /* Normal operating range */ - NX_TEMP_WARN, /* Sound alert, temperature getting high */ - NX_TEMP_PANIC /* Fatal error, hardware has shut down. */ -}; - -#endif /* __NIC_PHAN_REG_H_ */ -- cgit v1.2.3-18-g5258 From d516478ff67b2abb2f3ecc998a598576d92b0b5e Mon Sep 17 00:00:00 2001 From: Mark Kelly Date: Thu, 20 Aug 2009 01:26:12 +0000 Subject: r6040: remove unused pioaddr variable This patch removes the unused pioaddr variable. Signed-off-by: Mark Kelly Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/r6040.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 840677f5ee8..60bd010e8e4 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -1091,7 +1091,6 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, int err, io_size = R6040_IO_SIZE; static int card_idx = -1; int bar = 0; - long pioaddr; u16 *adrp; printk(KERN_INFO "%s\n", version); @@ -1121,7 +1120,6 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, goto err_out; } - pioaddr = pci_resource_start(pdev, bar); /* IO map base address */ pci_set_master(pdev); dev = alloc_etherdev(sizeof(struct r6040_private)); -- cgit v1.2.3-18-g5258 From e03f614af7811f9d089862a8700e683dcc6963c6 Mon Sep 17 00:00:00 2001 From: Mark Kelly Date: Thu, 20 Aug 2009 01:26:20 +0000 Subject: r6040: move down second PHY detection to r6040_init_one Instead of fully initializing an unusable second r6040 device, perform the PHY detection earlier and bail out in r6040_init_one when we could not read the PHY identifier. Signed-off-by: Mark Kelly Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/r6040.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 60bd010e8e4..7238a6fae14 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -750,14 +750,6 @@ static int r6040_up(struct net_device *dev) struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; int ret; - u16 val; - - /* Check presence of a second PHY */ - val = r6040_phy_read(ioaddr, lp->phy_addr, 2); - if (val == 0xFFFF) { - printk(KERN_ERR DRV_NAME " no second PHY attached\n"); - return -EIO; - } /* Initialise and alloc RX/TX buffers */ r6040_init_txbufs(dev); @@ -1194,6 +1186,13 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, lp->mii_if.phy_id_mask = 0x1f; lp->mii_if.reg_num_mask = 0x1f; + /* Check the vendor ID on the PHY, if 0xffff assume none attached */ + if (r6040_phy_read(ioaddr, lp->phy_addr, 2) == 0xffff) { + printk(KERN_ERR DRV_NAME ": Failed to detect an attached PHY\n"); + err = -ENODEV; + goto err_out_unmap; + } + /* Register net device. After this dev->name assign */ err = register_netdev(dev); if (err) { -- cgit v1.2.3-18-g5258 From 9818f660f433b58e770cfeb2ee9566f7b42ca0ae Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 20 Aug 2009 01:26:23 +0000 Subject: r6040: bump to version 0.25 and 20 August 2009 release date Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/r6040.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 7238a6fae14..8068a07eb2b 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -49,8 +49,8 @@ #include #define DRV_NAME "r6040" -#define DRV_VERSION "0.24" -#define DRV_RELDATE "08Jul2009" +#define DRV_VERSION "0.25" +#define DRV_RELDATE "20Aug2009" /* PHY CHIP Address */ #define PHY1_ADDR 1 /* For MAC1 */ -- cgit v1.2.3-18-g5258 From d2e353f7c3c5fbb3add0341c10ae167ee745d23b Mon Sep 17 00:00:00 2001 From: Wending Weng Date: Mon, 24 Aug 2009 16:05:17 -0400 Subject: Bluetooth: Fix false errors from bcsp_pkt_cull function The error message "Removed only %u out of %u pkts" is printed when multiple to be acked packets are queued. if (i++ >= pkts_to_be_removed) break; This will break out of the loop and increase the counter i when i==pkts_to_be_removed and the loop ends up with i=pkts_to_be_removed+1. The following line if (i != pkts_to_be_removed) { BT_ERR("Removed only %u out of %u pkts", i, pkts_to_be_removed); } will then display the false message. The counter i must not increase on the same statement. Signed-off-by: Wending Weng Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_bcsp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 894b2cb11ea..40aec0fb859 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -373,8 +373,9 @@ static void bcsp_pkt_cull(struct bcsp_struct *bcsp) i = 0; skb_queue_walk_safe(&bcsp->unack, skb, tmp) { - if (i++ >= pkts_to_be_removed) + if (i >= pkts_to_be_removed) break; + i++; __skb_unlink(skb, &bcsp->unack); kfree_skb(skb); -- cgit v1.2.3-18-g5258 From 7bee549e197c9c0e92b89857a409675c1d5e9dff Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 24 Aug 2009 23:44:59 +0200 Subject: Bluetooth: Add USB autosuspend support to btusb driver This patch adds support of USB autosuspend to the btusb driver. If the device doesn't support remote wakeup, simple support based on up/down is provided. If the device supports remote wakeup, additional support for autosuspend while the interface is up is provided. This is done by queueing URBs in an anchor structure and waking the device up from a work queue on sending. Reception triggers remote wakeup. The last busy facility of the USB autosuspend code is used. To close a race between autosuspend and transmission, a counter of ongoing transmissions is maintained. Add #ifdefs for CONFIG_PM as necessary. Signed-off-by: Oliver Neukum Tested-by: Sarah Sharp Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 194 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 174 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 124db8cd144..7ba91aa3fe8 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -35,7 +35,7 @@ #include #include -#define VERSION "0.5" +#define VERSION "0.6" static int ignore_dga; static int ignore_csr; @@ -145,6 +145,7 @@ static struct usb_device_id blacklist_table[] = { #define BTUSB_INTR_RUNNING 0 #define BTUSB_BULK_RUNNING 1 #define BTUSB_ISOC_RUNNING 2 +#define BTUSB_SUSPENDING 3 struct btusb_data { struct hci_dev *hdev; @@ -157,11 +158,15 @@ struct btusb_data { unsigned long flags; struct work_struct work; + struct work_struct waker; struct usb_anchor tx_anchor; struct usb_anchor intr_anchor; struct usb_anchor bulk_anchor; struct usb_anchor isoc_anchor; + struct usb_anchor deferred; + int tx_in_flight; + spinlock_t txlock; struct usb_endpoint_descriptor *intr_ep; struct usb_endpoint_descriptor *bulk_tx_ep; @@ -174,8 +179,23 @@ struct btusb_data { unsigned int sco_num; int isoc_altsetting; int suspend_count; + int did_iso_resume:1; }; +static int inc_tx(struct btusb_data *data) +{ + unsigned long flags; + int rv; + + spin_lock_irqsave(&data->txlock, flags); + rv = test_bit(BTUSB_SUSPENDING, &data->flags); + if (!rv) + data->tx_in_flight++; + spin_unlock_irqrestore(&data->txlock, flags); + + return rv; +} + static void btusb_intr_complete(struct urb *urb) { struct hci_dev *hdev = urb->context; @@ -202,6 +222,7 @@ static void btusb_intr_complete(struct urb *urb) if (!test_bit(BTUSB_INTR_RUNNING, &data->flags)) return; + usb_mark_last_busy(data->udev); usb_anchor_urb(urb, &data->intr_anchor); err = usb_submit_urb(urb, GFP_ATOMIC); @@ -325,6 +346,7 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags) urb->transfer_flags |= URB_FREE_BUFFER; + usb_mark_last_busy(data->udev); usb_anchor_urb(urb, &data->bulk_anchor); err = usb_submit_urb(urb, mem_flags); @@ -460,6 +482,33 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags) } static void btusb_tx_complete(struct urb *urb) +{ + struct sk_buff *skb = urb->context; + struct hci_dev *hdev = (struct hci_dev *) skb->dev; + struct btusb_data *data = hdev->driver_data; + + BT_DBG("%s urb %p status %d count %d", hdev->name, + urb, urb->status, urb->actual_length); + + if (!test_bit(HCI_RUNNING, &hdev->flags)) + goto done; + + if (!urb->status) + hdev->stat.byte_tx += urb->transfer_buffer_length; + else + hdev->stat.err_tx++; + +done: + spin_lock(&data->txlock); + data->tx_in_flight--; + spin_unlock(&data->txlock); + + kfree(urb->setup_packet); + + kfree_skb(skb); +} + +static void btusb_isoc_tx_complete(struct urb *urb) { struct sk_buff *skb = urb->context; struct hci_dev *hdev = (struct hci_dev *) skb->dev; @@ -488,11 +537,17 @@ static int btusb_open(struct hci_dev *hdev) BT_DBG("%s", hdev->name); + err = usb_autopm_get_interface(data->intf); + if (err < 0) + return err; + + data->intf->needs_remote_wakeup = 1; + if (test_and_set_bit(HCI_RUNNING, &hdev->flags)) - return 0; + goto done; if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags)) - return 0; + goto done; err = btusb_submit_intr_urb(hdev, GFP_KERNEL); if (err < 0) @@ -507,17 +562,28 @@ static int btusb_open(struct hci_dev *hdev) set_bit(BTUSB_BULK_RUNNING, &data->flags); btusb_submit_bulk_urb(hdev, GFP_KERNEL); +done: + usb_autopm_put_interface(data->intf); return 0; failed: clear_bit(BTUSB_INTR_RUNNING, &data->flags); clear_bit(HCI_RUNNING, &hdev->flags); + usb_autopm_put_interface(data->intf); return err; } +static void btusb_stop_traffic(struct btusb_data *data) +{ + usb_kill_anchored_urbs(&data->intr_anchor); + usb_kill_anchored_urbs(&data->bulk_anchor); + usb_kill_anchored_urbs(&data->isoc_anchor); +} + static int btusb_close(struct hci_dev *hdev) { struct btusb_data *data = hdev->driver_data; + int err; BT_DBG("%s", hdev->name); @@ -527,13 +593,16 @@ static int btusb_close(struct hci_dev *hdev) cancel_work_sync(&data->work); clear_bit(BTUSB_ISOC_RUNNING, &data->flags); - usb_kill_anchored_urbs(&data->isoc_anchor); - clear_bit(BTUSB_BULK_RUNNING, &data->flags); - usb_kill_anchored_urbs(&data->bulk_anchor); - clear_bit(BTUSB_INTR_RUNNING, &data->flags); - usb_kill_anchored_urbs(&data->intr_anchor); + + btusb_stop_traffic(data); + err = usb_autopm_get_interface(data->intf); + if (err < 0) + return 0; + + data->intf->needs_remote_wakeup = 0; + usb_autopm_put_interface(data->intf); return 0; } @@ -620,7 +689,7 @@ static int btusb_send_frame(struct sk_buff *skb) urb->dev = data->udev; urb->pipe = pipe; urb->context = skb; - urb->complete = btusb_tx_complete; + urb->complete = btusb_isoc_tx_complete; urb->interval = data->isoc_tx_ep->bInterval; urb->transfer_flags = URB_ISO_ASAP; @@ -631,12 +700,21 @@ static int btusb_send_frame(struct sk_buff *skb) le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize)); hdev->stat.sco_tx++; - break; + goto skip_waking; default: return -EILSEQ; } + err = inc_tx(data); + if (err) { + usb_anchor_urb(urb, &data->deferred); + schedule_work(&data->waker); + err = 0; + goto done; + } + +skip_waking: usb_anchor_urb(urb, &data->tx_anchor); err = usb_submit_urb(urb, GFP_ATOMIC); @@ -644,10 +722,13 @@ static int btusb_send_frame(struct sk_buff *skb) BT_ERR("%s urb %p submission failed", hdev->name, urb); kfree(urb->setup_packet); usb_unanchor_urb(urb); + } else { + usb_mark_last_busy(data->udev); } usb_free_urb(urb); +done: return err; } @@ -719,8 +800,19 @@ static void btusb_work(struct work_struct *work) { struct btusb_data *data = container_of(work, struct btusb_data, work); struct hci_dev *hdev = data->hdev; + int err; if (hdev->conn_hash.sco_num > 0) { + if (!data->did_iso_resume) { + err = usb_autopm_get_interface(data->isoc); + if (err < 0) { + clear_bit(BTUSB_ISOC_RUNNING, &data->flags); + usb_kill_anchored_urbs(&data->isoc_anchor); + return; + } + + data->did_iso_resume = 1; + } if (data->isoc_altsetting != 2) { clear_bit(BTUSB_ISOC_RUNNING, &data->flags); usb_kill_anchored_urbs(&data->isoc_anchor); @@ -740,9 +832,25 @@ static void btusb_work(struct work_struct *work) usb_kill_anchored_urbs(&data->isoc_anchor); __set_isoc_interface(hdev, 0); + if (data->did_iso_resume) { + data->did_iso_resume = 0; + usb_autopm_put_interface(data->isoc); + } } } +static void btusb_waker(struct work_struct *work) +{ + struct btusb_data *data = container_of(work, struct btusb_data, waker); + int err; + + err = usb_autopm_get_interface(data->intf); + if (err < 0) + return; + + usb_autopm_put_interface(data->intf); +} + static int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -812,11 +920,14 @@ static int btusb_probe(struct usb_interface *intf, spin_lock_init(&data->lock); INIT_WORK(&data->work, btusb_work); + INIT_WORK(&data->waker, btusb_waker); + spin_lock_init(&data->txlock); init_usb_anchor(&data->tx_anchor); init_usb_anchor(&data->intr_anchor); init_usb_anchor(&data->bulk_anchor); init_usb_anchor(&data->isoc_anchor); + init_usb_anchor(&data->deferred); hdev = hci_alloc_dev(); if (!hdev) { @@ -941,6 +1052,7 @@ static void btusb_disconnect(struct usb_interface *intf) hci_free_dev(hdev); } +#ifdef CONFIG_PM static int btusb_suspend(struct usb_interface *intf, pm_message_t message) { struct btusb_data *data = usb_get_intfdata(intf); @@ -950,22 +1062,44 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message) if (data->suspend_count++) return 0; + spin_lock_irq(&data->txlock); + if (!(interface_to_usbdev(intf)->auto_pm && data->tx_in_flight)) { + set_bit(BTUSB_SUSPENDING, &data->flags); + spin_unlock_irq(&data->txlock); + } else { + spin_unlock_irq(&data->txlock); + data->suspend_count--; + return -EBUSY; + } + cancel_work_sync(&data->work); + btusb_stop_traffic(data); usb_kill_anchored_urbs(&data->tx_anchor); - usb_kill_anchored_urbs(&data->isoc_anchor); - usb_kill_anchored_urbs(&data->bulk_anchor); - usb_kill_anchored_urbs(&data->intr_anchor); - return 0; } +static void play_deferred(struct btusb_data *data) +{ + struct urb *urb; + int err; + + while ((urb = usb_get_from_anchor(&data->deferred))) { + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err < 0) + break; + + data->tx_in_flight++; + } + usb_scuttle_anchored_urbs(&data->deferred); +} + static int btusb_resume(struct usb_interface *intf) { struct btusb_data *data = usb_get_intfdata(intf); struct hci_dev *hdev = data->hdev; - int err; + int err = 0; BT_DBG("intf %p", intf); @@ -973,13 +1107,13 @@ static int btusb_resume(struct usb_interface *intf) return 0; if (!test_bit(HCI_RUNNING, &hdev->flags)) - return 0; + goto done; if (test_bit(BTUSB_INTR_RUNNING, &data->flags)) { err = btusb_submit_intr_urb(hdev, GFP_NOIO); if (err < 0) { clear_bit(BTUSB_INTR_RUNNING, &data->flags); - return err; + goto failed; } } @@ -987,9 +1121,10 @@ static int btusb_resume(struct usb_interface *intf) err = btusb_submit_bulk_urb(hdev, GFP_NOIO); if (err < 0) { clear_bit(BTUSB_BULK_RUNNING, &data->flags); - return err; - } else - btusb_submit_bulk_urb(hdev, GFP_NOIO); + goto failed; + } + + btusb_submit_bulk_urb(hdev, GFP_NOIO); } if (test_bit(BTUSB_ISOC_RUNNING, &data->flags)) { @@ -999,16 +1134,35 @@ static int btusb_resume(struct usb_interface *intf) btusb_submit_isoc_urb(hdev, GFP_NOIO); } + spin_lock_irq(&data->txlock); + play_deferred(data); + clear_bit(BTUSB_SUSPENDING, &data->flags); + spin_unlock_irq(&data->txlock); + schedule_work(&data->work); + return 0; + +failed: + usb_scuttle_anchored_urbs(&data->deferred); +done: + spin_lock_irq(&data->txlock); + clear_bit(BTUSB_SUSPENDING, &data->flags); + spin_unlock_irq(&data->txlock); + + return err; } +#endif static struct usb_driver btusb_driver = { .name = "btusb", .probe = btusb_probe, .disconnect = btusb_disconnect, +#ifdef CONFIG_PM .suspend = btusb_suspend, .resume = btusb_resume, +#endif .id_table = btusb_table, + .supports_autosuspend = 1, }; static int __init btusb_init(void) -- cgit v1.2.3-18-g5258 From 42960a13001aa6df52ca9952ce996f94a744ea65 Mon Sep 17 00:00:00 2001 From: Jan Scholz Date: Wed, 26 Aug 2009 13:18:51 +0200 Subject: HID: completely remove apple mightymouse from blacklist Commit fa047e4f6fa63a6e9d0ae4d7749538830d14a343 "HID: fix inverted wheel for bluetooth version of apple mighty mouse" is incomplete. If we remove Apple MightyMouse (bluetooth version) from the list of apple_devices in drivers/hid/hid-apple.c we have to remove it from hid_blacklist in drivers/hid/hid-core.c as well. Signed-off-by: Jan Scholz Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 5eb10c2ce66..047844df992 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1319,7 +1319,6 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) }, { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) }, { } }; -- cgit v1.2.3-18-g5258 From cb7e4b6e37144f5d131ee09296be3c21c41f28d8 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Mon, 24 Aug 2009 19:23:25 +0000 Subject: netxen: remove unused code Remove code for phy access on unreleased NX2031 based quad-gig board. NX3031 based production quad-gig boards do not require direct phy access by driver. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 13 -- drivers/net/netxen/netxen_nic_hw.h | 107 ---------------- drivers/net/netxen/netxen_nic_init.c | 41 ++---- drivers/net/netxen/netxen_nic_niu.c | 240 ----------------------------------- 4 files changed, 11 insertions(+), 390 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 7a93f8275c9..74ccef5a5c9 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1148,8 +1148,6 @@ struct netxen_adapter { struct netxen_recv_context recv_ctx; struct nx_host_tx_ring *tx_ring; - int (*enable_phy_interrupts) (struct netxen_adapter *); - int (*disable_phy_interrupts) (struct netxen_adapter *); int (*macaddr_set) (struct netxen_adapter *, u8 *); int (*set_mtu) (struct netxen_adapter *, int); int (*set_promisc) (struct netxen_adapter *, u32); @@ -1187,22 +1185,11 @@ struct netxen_adapter { const struct firmware *fw; }; -/* Set promiscuous mode for a GbE interface */ -int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, u32 mode); int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, u32 mode); -/* Generic enable for GbE ports. Will detect the speed of the link. */ -int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port); int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port); - -/* Disable a GbE interface */ -int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter); int netxen_niu_disable_xg_port(struct netxen_adapter *adapter); -int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter); -int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter); -int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter); -int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter); int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, __u32 * readval); int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h index fc0638f2d6d..98e4b95788b 100644 --- a/drivers/net/netxen/netxen_nic_hw.h +++ b/drivers/net/netxen/netxen_nic_hw.h @@ -61,10 +61,6 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter); * Bit 31: soft_reset => 1:reset the MAC and the SERDES, 0:no-op */ -#define netxen_gb_enable_tx(config_word) \ - ((config_word) |= 1 << 0) -#define netxen_gb_enable_rx(config_word) \ - ((config_word) |= 1 << 2) #define netxen_gb_tx_flowctl(config_word) \ ((config_word) |= 1 << 4) #define netxen_gb_rx_flowctl(config_word) \ @@ -77,8 +73,6 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter); ((config_word) |= 1 << 18) #define netxen_gb_rx_reset_mac(config_word) \ ((config_word) |= 1 << 19) -#define netxen_gb_soft_reset(config_word) \ - ((config_word) |= 1 << 31) #define netxen_gb_unset_tx_flowctl(config_word) \ ((config_word) &= ~(1 << 4)) @@ -240,7 +234,6 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter); * Bits 14-15 : speed => 0:10Mb/s, 1:100Mb/s, 2:1000Mb/s, 3:rsvd */ -#define netxen_get_phy_cablelen(config_word) (((config_word) >> 7) & 0x07) #define netxen_get_phy_speed(config_word) (((config_word) >> 14) & 0x03) #define netxen_set_phy_speed(config_word, val) \ @@ -250,84 +243,11 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter); #define netxen_clear_phy_duplex(config_word) \ ((config_word) &= ~(1 << 13)) -#define netxen_get_phy_jabber(config_word) \ - _netxen_crb_get_bit(config_word, 0) -#define netxen_get_phy_polarity(config_word) \ - _netxen_crb_get_bit(config_word, 1) -#define netxen_get_phy_recvpause(config_word) \ - _netxen_crb_get_bit(config_word, 2) -#define netxen_get_phy_xmitpause(config_word) \ - _netxen_crb_get_bit(config_word, 3) -#define netxen_get_phy_energydetect(config_word) \ - _netxen_crb_get_bit(config_word, 4) -#define netxen_get_phy_downshift(config_word) \ - _netxen_crb_get_bit(config_word, 5) -#define netxen_get_phy_crossover(config_word) \ - _netxen_crb_get_bit(config_word, 6) #define netxen_get_phy_link(config_word) \ _netxen_crb_get_bit(config_word, 10) -#define netxen_get_phy_resolved(config_word) \ - _netxen_crb_get_bit(config_word, 11) -#define netxen_get_phy_pagercvd(config_word) \ - _netxen_crb_get_bit(config_word, 12) #define netxen_get_phy_duplex(config_word) \ _netxen_crb_get_bit(config_word, 13) -/* - * Interrupt Register definition - * This definition applies to registers 18 and 19 (int enable and int status). - * Bit 0 : jabber - * Bit 1 : polarity_changed - * Bit 4 : energy_detect - * Bit 5 : downshift - * Bit 6 : mdi_xover_changed - * Bit 7 : fifo_over_underflow - * Bit 8 : false_carrier - * Bit 9 : symbol_error - * Bit 10: link_status_changed - * Bit 11: autoneg_completed - * Bit 12: page_received - * Bit 13: duplex_changed - * Bit 14: speed_changed - * Bit 15: autoneg_error - */ - -#define netxen_get_phy_int_jabber(config_word) \ - _netxen_crb_get_bit(config_word, 0) -#define netxen_get_phy_int_polarity_changed(config_word) \ - _netxen_crb_get_bit(config_word, 1) -#define netxen_get_phy_int_energy_detect(config_word) \ - _netxen_crb_get_bit(config_word, 4) -#define netxen_get_phy_int_downshift(config_word) \ - _netxen_crb_get_bit(config_word, 5) -#define netxen_get_phy_int_mdi_xover_changed(config_word) \ - _netxen_crb_get_bit(config_word, 6) -#define netxen_get_phy_int_fifo_over_underflow(config_word) \ - _netxen_crb_get_bit(config_word, 7) -#define netxen_get_phy_int_false_carrier(config_word) \ - _netxen_crb_get_bit(config_word, 8) -#define netxen_get_phy_int_symbol_error(config_word) \ - _netxen_crb_get_bit(config_word, 9) -#define netxen_get_phy_int_link_status_changed(config_word) \ - _netxen_crb_get_bit(config_word, 10) -#define netxen_get_phy_int_autoneg_completed(config_word) \ - _netxen_crb_get_bit(config_word, 11) -#define netxen_get_phy_int_page_received(config_word) \ - _netxen_crb_get_bit(config_word, 12) -#define netxen_get_phy_int_duplex_changed(config_word) \ - _netxen_crb_get_bit(config_word, 13) -#define netxen_get_phy_int_speed_changed(config_word) \ - _netxen_crb_get_bit(config_word, 14) -#define netxen_get_phy_int_autoneg_error(config_word) \ - _netxen_crb_get_bit(config_word, 15) - -#define netxen_set_phy_int_link_status_changed(config_word) \ - ((config_word) |= 1 << 10) -#define netxen_set_phy_int_autoneg_completed(config_word) \ - ((config_word) |= 1 << 11) -#define netxen_set_phy_int_speed_changed(config_word) \ - ((config_word) |= 1 << 14) - /* * NIU Mode Register. * Bit 0 : enable FibreChannel @@ -342,33 +262,6 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter); #define NETXEN_NIU_PROMISC_MODE 1 #define NETXEN_NIU_ALLMULTI_MODE 2 -/* - * NIU GB Drop CRC Register - * - * Bit 0 : drop_gb0 => 1:drop pkts with bad CRCs, 0:pass them on - * Bit 1 : drop_gb1 => 1:drop pkts with bad CRCs, 0:pass them on - * Bit 2 : drop_gb2 => 1:drop pkts with bad CRCs, 0:pass them on - * Bit 3 : drop_gb3 => 1:drop pkts with bad CRCs, 0:pass them on - */ - -#define netxen_set_gb_drop_gb0(config_word) \ - ((config_word) |= 1 << 0) -#define netxen_set_gb_drop_gb1(config_word) \ - ((config_word) |= 1 << 1) -#define netxen_set_gb_drop_gb2(config_word) \ - ((config_word) |= 1 << 2) -#define netxen_set_gb_drop_gb3(config_word) \ - ((config_word) |= 1 << 3) - -#define netxen_clear_gb_drop_gb0(config_word) \ - ((config_word) &= ~(1 << 0)) -#define netxen_clear_gb_drop_gb1(config_word) \ - ((config_word) &= ~(1 << 1)) -#define netxen_clear_gb_drop_gb2(config_word) \ - ((config_word) &= ~(1 << 2)) -#define netxen_clear_gb_drop_gb3(config_word) \ - ((config_word) &= ~(1 << 3)) - /* * NIU XG MAC Config Register * diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 474c568adcc..f5807dae09e 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -321,44 +321,25 @@ err_out: void netxen_initialize_adapter_ops(struct netxen_adapter *adapter) { - adapter->macaddr_set = netxen_p2_nic_set_mac_addr; - adapter->set_multi = netxen_p2_nic_set_multi; - - switch (adapter->ahw.port_type) { - case NETXEN_NIC_GBE: - adapter->enable_phy_interrupts = - netxen_niu_gbe_enable_phy_interrupts; - adapter->disable_phy_interrupts = - netxen_niu_gbe_disable_phy_interrupts; - adapter->set_mtu = netxen_nic_set_mtu_gb; - adapter->set_promisc = netxen_niu_set_promiscuous_mode; - adapter->phy_read = netxen_niu_gbe_phy_read; - adapter->phy_write = netxen_niu_gbe_phy_write; - adapter->init_port = netxen_niu_gbe_init_port; - adapter->stop_port = netxen_niu_disable_gbe_port; - break; + adapter->init_port = netxen_niu_xg_init_port; + adapter->stop_port = netxen_niu_disable_xg_port; - case NETXEN_NIC_XGBE: - adapter->enable_phy_interrupts = - netxen_niu_xgbe_enable_phy_interrupts; - adapter->disable_phy_interrupts = - netxen_niu_xgbe_disable_phy_interrupts; + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + adapter->macaddr_set = netxen_p2_nic_set_mac_addr; + adapter->set_multi = netxen_p2_nic_set_multi; adapter->set_mtu = netxen_nic_set_mtu_xgb; - adapter->init_port = netxen_niu_xg_init_port; adapter->set_promisc = netxen_niu_xg_set_promiscuous_mode; - adapter->stop_port = netxen_niu_disable_xg_port; - break; - - default: - break; - } - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { + } else { adapter->set_mtu = nx_fw_cmd_set_mtu; adapter->set_promisc = netxen_p3_nic_set_promisc; adapter->macaddr_set = netxen_p3_nic_set_mac_addr; adapter->set_multi = netxen_p3_nic_set_multi; } + + if (adapter->ahw.port_type == NETXEN_NIC_GBE) { + adapter->phy_read = netxen_niu_gbe_phy_read; + adapter->phy_write = netxen_niu_gbe_phy_write; + } } /* diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c index 5941c79be72..8b7cd9e1851 100644 --- a/drivers/net/netxen/netxen_nic_niu.c +++ b/drivers/net/netxen/netxen_nic_niu.c @@ -30,11 +30,6 @@ #include "netxen_nic.h" -#define NETXEN_GB_MAC_SOFT_RESET 0x80000000 -#define NETXEN_GB_MAC_RESET_PROT_BLK 0x000F0000 -#define NETXEN_GB_MAC_ENABLE_TX_RX 0x00000005 -#define NETXEN_GB_MAC_PAUSED_FRMS 0x00000020 - static long phy_lock_timeout = 100000000; static int phy_lock(struct netxen_adapter *adapter) @@ -227,171 +222,6 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, return result; } -int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter) -{ - NXWR32(adapter, NETXEN_NIU_INT_MASK, 0x3f); - return 0; -} - -int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter) -{ - int result = 0; - __u32 enable = 0; - netxen_set_phy_int_link_status_changed(enable); - netxen_set_phy_int_autoneg_completed(enable); - netxen_set_phy_int_speed_changed(enable); - - if (0 != - netxen_niu_gbe_phy_write(adapter, - NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, - enable)) - result = -EIO; - - return result; -} - -int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter) -{ - NXWR32(adapter, NETXEN_NIU_INT_MASK, 0x7f); - return 0; -} - -int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter) -{ - int result = 0; - if (0 != - netxen_niu_gbe_phy_write(adapter, - NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, 0)) - result = -EIO; - - return result; -} - -static int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter) -{ - int result = 0; - if (0 != - netxen_niu_gbe_phy_write(adapter, - NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, - -EIO)) - result = -EIO; - - return result; -} - -/* - * netxen_niu_gbe_set_mii_mode- Set 10/100 Mbit Mode for GbE MAC - * - */ -static void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, - int port, long enable) -{ - NXWR32(adapter, NETXEN_NIU_MODE, 0x2); - NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x80000000); - NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x0000f0025); - NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_1(port), 0xf1ff); - NXWR32(adapter, NETXEN_NIU_GB0_GMII_MODE + (port << 3), 0); - NXWR32(adapter, NETXEN_NIU_GB0_MII_MODE + (port << 3), 1); - NXWR32(adapter, (NETXEN_NIU_GB0_HALF_DUPLEX + port * 4), 0); - NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7); - - if (enable) { - /* - * Do NOT enable flow control until a suitable solution for - * shutting down pause frames is found. - */ - NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x5); - } - - if (netxen_niu_gbe_enable_phy_interrupts(adapter)) - printk(KERN_ERR "ERROR enabling PHY interrupts\n"); - if (netxen_niu_gbe_clear_phy_interrupts(adapter)) - printk(KERN_ERR "ERROR clearing PHY interrupts\n"); -} - -/* - * netxen_niu_gbe_set_gmii_mode- Set GbE Mode for GbE MAC - */ -static void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, - int port, long enable) -{ - NXWR32(adapter, NETXEN_NIU_MODE, 0x2); - NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x80000000); - NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x0000f0025); - NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_1(port), 0xf2ff); - NXWR32(adapter, NETXEN_NIU_GB0_MII_MODE + (port << 3), 0); - NXWR32(adapter, NETXEN_NIU_GB0_GMII_MODE + (port << 3), 1); - NXWR32(adapter, (NETXEN_NIU_GB0_HALF_DUPLEX + port * 4), 0); - NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7); - - if (enable) { - /* - * Do NOT enable flow control until a suitable solution for - * shutting down pause frames is found. - */ - NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x5); - } - - if (netxen_niu_gbe_enable_phy_interrupts(adapter)) - printk(KERN_ERR "ERROR enabling PHY interrupts\n"); - if (netxen_niu_gbe_clear_phy_interrupts(adapter)) - printk(KERN_ERR "ERROR clearing PHY interrupts\n"); -} - -int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) -{ - int result = 0; - __u32 status; - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - return 0; - - if (adapter->disable_phy_interrupts) - adapter->disable_phy_interrupts(adapter); - mdelay(2); - - if (0 == netxen_niu_gbe_phy_read(adapter, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, &status)) { - if (netxen_get_phy_link(status)) { - if (netxen_get_phy_speed(status) == 2) { - netxen_niu_gbe_set_gmii_mode(adapter, port, 1); - } else if ((netxen_get_phy_speed(status) == 1) - || (netxen_get_phy_speed(status) == 0)) { - netxen_niu_gbe_set_mii_mode(adapter, port, 1); - } else { - result = -1; - } - - } else { - /* - * We don't have link. Cable must be unconnected. - * Enable phy interrupts so we take action when - * plugged in. - */ - - NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), - NETXEN_GB_MAC_SOFT_RESET); - NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), - NETXEN_GB_MAC_RESET_PROT_BLK | - NETXEN_GB_MAC_ENABLE_TX_RX | - NETXEN_GB_MAC_PAUSED_FRMS); - if (netxen_niu_gbe_clear_phy_interrupts(adapter)) - printk(KERN_ERR - "ERROR clearing PHY interrupts\n"); - if (netxen_niu_gbe_enable_phy_interrupts(adapter)) - printk(KERN_ERR - "ERROR enabling PHY interrupts\n"); - if (netxen_niu_gbe_clear_phy_interrupts(adapter)) - printk(KERN_ERR - "ERROR clearing PHY interrupts\n"); - result = -1; - } - } else { - result = -EIO; - } - return result; -} - int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port) { if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { @@ -402,24 +232,6 @@ int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port) return 0; } -/* Disable a GbE interface */ -int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter) -{ - __u32 mac_cfg0; - u32 port = adapter->physical_port; - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - return 0; - - if (port > NETXEN_NIU_MAX_GBE_PORTS) - return -EINVAL; - mac_cfg0 = 0; - netxen_gb_soft_reset(mac_cfg0); - if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), mac_cfg0)) - return -EIO; - return 0; -} - /* Disable an XG interface */ int netxen_niu_disable_xg_port(struct netxen_adapter *adapter) { @@ -439,58 +251,6 @@ int netxen_niu_disable_xg_port(struct netxen_adapter *adapter) return 0; } -/* Set promiscuous mode for a GbE interface */ -int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, - u32 mode) -{ - __u32 reg; - u32 port = adapter->physical_port; - - if (port > NETXEN_NIU_MAX_GBE_PORTS) - return -EINVAL; - - /* save previous contents */ - reg = NXRD32(adapter, NETXEN_NIU_GB_DROP_WRONGADDR); - if (mode == NETXEN_NIU_PROMISC_MODE) { - switch (port) { - case 0: - netxen_clear_gb_drop_gb0(reg); - break; - case 1: - netxen_clear_gb_drop_gb1(reg); - break; - case 2: - netxen_clear_gb_drop_gb2(reg); - break; - case 3: - netxen_clear_gb_drop_gb3(reg); - break; - default: - return -EIO; - } - } else { - switch (port) { - case 0: - netxen_set_gb_drop_gb0(reg); - break; - case 1: - netxen_set_gb_drop_gb1(reg); - break; - case 2: - netxen_set_gb_drop_gb2(reg); - break; - case 3: - netxen_set_gb_drop_gb3(reg); - break; - default: - return -EIO; - } - } - if (NXWR32(adapter, NETXEN_NIU_GB_DROP_WRONGADDR, reg)) - return -EIO; - return 0; -} - int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, u32 mode) { -- cgit v1.2.3-18-g5258 From c9517e5893db03ca8bd32b8783b39af58176947c Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Mon, 24 Aug 2009 19:23:26 +0000 Subject: netxen: implement generic pcie semaphore functions Implement common function for locking/unlocking 8 hardware semaphores used for serializing access to shared resouces on a NIC board by different PCI functions. As by definition, callers of these semaphore API can be put to sleep till the semaphore is locked. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 24 +++++++++++++++ drivers/net/netxen/netxen_nic_ctx.c | 35 ---------------------- drivers/net/netxen/netxen_nic_hdr.h | 8 +++++ drivers/net/netxen/netxen_nic_hw.c | 57 ++++++++++++++++++------------------ drivers/net/netxen/netxen_nic_init.c | 52 +++++--------------------------- drivers/net/netxen/netxen_nic_niu.c | 39 ++---------------------- 6 files changed, 71 insertions(+), 144 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 74ccef5a5c9..061e8aa419b 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1207,6 +1207,30 @@ int netxen_p3_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr); #define NXWR32(adapter, off, val) \ (adapter->hw_write_wx(adapter, off, val)) +int netxen_pcie_sem_lock(struct netxen_adapter *, int, u32); +void netxen_pcie_sem_unlock(struct netxen_adapter *, int); + +#define netxen_rom_lock(a) \ + netxen_pcie_sem_lock((a), 2, NETXEN_ROM_LOCK_ID) +#define netxen_rom_unlock(a) \ + netxen_pcie_sem_unlock((a), 2) +#define netxen_phy_lock(a) \ + netxen_pcie_sem_lock((a), 3, NETXEN_PHY_LOCK_ID) +#define netxen_phy_unlock(a) \ + netxen_pcie_sem_unlock((a), 3) +#define netxen_api_lock(a) \ + netxen_pcie_sem_lock((a), 5, 0) +#define netxen_api_unlock(a) \ + netxen_pcie_sem_unlock((a), 5) +#define netxen_sw_lock(a) \ + netxen_pcie_sem_lock((a), 6, 0) +#define netxen_sw_unlock(a) \ + netxen_pcie_sem_unlock((a), 6) +#define crb_win_lock(a) \ + netxen_pcie_sem_lock((a), 7, NETXEN_CRB_WIN_LOCK_ID) +#define crb_win_unlock(a) \ + netxen_pcie_sem_unlock((a), 7) + int netxen_nic_get_board_info(struct netxen_adapter *adapter); void netxen_nic_get_firmware_info(struct netxen_adapter *adapter); int netxen_nic_wol_supported(struct netxen_adapter *adapter); diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 3d676fecb0a..ef846b43390 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -33,41 +33,6 @@ #define NXHAL_VERSION 1 -static int -netxen_api_lock(struct netxen_adapter *adapter) -{ - u32 done = 0, timeout = 0; - - for (;;) { - /* Acquire PCIE HW semaphore5 */ - done = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM5_LOCK)); - - if (done == 1) - break; - - if (++timeout >= NX_OS_CRB_RETRY_COUNT) { - printk(KERN_ERR "%s: lock timeout.\n", __func__); - return -1; - } - - msleep(1); - } - -#if 0 - NXWR32(adapter, - NETXEN_API_LOCK_ID, NX_OS_API_LOCK_DRIVER); -#endif - return 0; -} - -static int -netxen_api_unlock(struct netxen_adapter *adapter) -{ - /* Release PCIE HW semaphore5 */ - NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM5_UNLOCK)); - return 0; -} - static u32 netxen_poll_rsp(struct netxen_adapter *adapter) { diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index c4a4a8ba14f..92f5970c9aa 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h @@ -899,16 +899,24 @@ enum { #define PCIE_DCR 0x00d8 +#define PCIE_SEM0_LOCK (0x1c000) +#define PCIE_SEM0_UNLOCK (0x1c004) +#define PCIE_SEM1_LOCK (0x1c008) +#define PCIE_SEM1_UNLOCK (0x1c00c) #define PCIE_SEM2_LOCK (0x1c010) /* Flash lock */ #define PCIE_SEM2_UNLOCK (0x1c014) /* Flash unlock */ #define PCIE_SEM3_LOCK (0x1c018) /* Phy lock */ #define PCIE_SEM3_UNLOCK (0x1c01c) /* Phy unlock */ +#define PCIE_SEM4_LOCK (0x1c020) +#define PCIE_SEM4_UNLOCK (0x1c024) #define PCIE_SEM5_LOCK (0x1c028) /* API lock */ #define PCIE_SEM5_UNLOCK (0x1c02c) /* API unlock */ #define PCIE_SEM6_LOCK (0x1c030) /* sw lock */ #define PCIE_SEM6_UNLOCK (0x1c034) /* sw unlock */ #define PCIE_SEM7_LOCK (0x1c038) /* crb win lock */ #define PCIE_SEM7_UNLOCK (0x1c03c) /* crbwin unlock*/ +#define PCIE_SEM_LOCK(N) (PCIE_SEM0_LOCK + 8*(N)) +#define PCIE_SEM_UNLOCK(N) (PCIE_SEM0_UNLOCK + 8*(N)) #define PCIE_SETUP_FUNCTION (0x12040) #define PCIE_SETUP_FUNCTION2 (0x12048) diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 9138bbcbb80..cbfe44c8a7f 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -86,7 +86,6 @@ static void __iomem *pci_base_offset(struct netxen_adapter *adapter, return NULL; } -#define CRB_WIN_LOCK_TIMEOUT 100000000 static crb_128M_2M_block_map_t crb_128M_2M_map[64] __cacheline_aligned_in_smp = { {{{0, 0, 0, 0} } }, /* 0: PCI */ @@ -320,6 +319,35 @@ static unsigned crb_hub_agt[64] = #define NETXEN_WINDOW_ONE 0x2000000 /*CRB Window: bit 25 of CRB address */ +#define NETXEN_PCIE_SEM_TIMEOUT 10000 + +int +netxen_pcie_sem_lock(struct netxen_adapter *adapter, int sem, u32 id_reg) +{ + int done = 0, timeout = 0; + + while (!done) { + done = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM_LOCK(sem))); + if (done == 1) + break; + if (++timeout >= NETXEN_PCIE_SEM_TIMEOUT) + return -1; + msleep(1); + } + + if (id_reg) + NXWR32(adapter, id_reg, adapter->portnum); + + return 0; +} + +void +netxen_pcie_sem_unlock(struct netxen_adapter *adapter, int sem) +{ + int val; + val = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM_UNLOCK(sem))); +} + #define NETXEN_UNICAST_ADDR(port, index) \ (NETXEN_UNICAST_ADDR_BASE+(port*32)+(index*8)) #define NETXEN_MCAST_ADDR(port, index) \ @@ -906,33 +934,6 @@ int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, __le64 *mac) return 0; } -#define CRB_WIN_LOCK_TIMEOUT 100000000 - -static int crb_win_lock(struct netxen_adapter *adapter) -{ - int done = 0, timeout = 0; - - while (!done) { - /* acquire semaphore3 from PCI HW block */ - done = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM7_LOCK)); - if (done == 1) - break; - if (timeout >= CRB_WIN_LOCK_TIMEOUT) - return -1; - timeout++; - udelay(1); - } - NXWR32(adapter, NETXEN_CRB_WIN_LOCK_ID, adapter->portnum); - return 0; -} - -static void crb_win_unlock(struct netxen_adapter *adapter) -{ - int val; - - val = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM7_UNLOCK)); -} - /* * Changes the CRB window to the specified window. */ diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index f5807dae09e..313cd261b2b 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -369,37 +369,7 @@ static u32 netxen_decode_crb_addr(u32 addr) return (pci_base + offset); } -static long rom_max_timeout = 100; -static long rom_lock_timeout = 10000; - -static int rom_lock(struct netxen_adapter *adapter) -{ - int iter; - u32 done = 0; - int timeout = 0; - - while (!done) { - /* acquire semaphore2 from PCI HW block */ - done = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM2_LOCK)); - if (done == 1) - break; - if (timeout >= rom_lock_timeout) - return -EIO; - - timeout++; - /* - * Yield CPU - */ - if (!in_atomic()) - schedule(); - else { - for (iter = 0; iter < 20; iter++) - cpu_relax(); /*This a nop instr on i386 */ - } - } - NXWR32(adapter, NETXEN_ROM_LOCK_ID, ROM_LOCK_DRIVER); - return 0; -} +#define NETXEN_MAX_ROM_WAIT_USEC 100 static int netxen_wait_rom_done(struct netxen_adapter *adapter) { @@ -411,22 +381,16 @@ static int netxen_wait_rom_done(struct netxen_adapter *adapter) while (done == 0) { done = NXRD32(adapter, NETXEN_ROMUSB_GLB_STATUS); done &= 2; - timeout++; - if (timeout >= rom_max_timeout) { - printk("Timeout reached waiting for rom done"); + if (++timeout >= NETXEN_MAX_ROM_WAIT_USEC) { + dev_err(&adapter->pdev->dev, + "Timeout reached waiting for rom done"); return -EIO; } + udelay(1); } return 0; } -static void netxen_rom_unlock(struct netxen_adapter *adapter) -{ - /* release semaphore2 */ - NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM2_UNLOCK)); - -} - static int do_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp) { @@ -471,7 +435,7 @@ netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr, { int ret; - ret = rom_lock(adapter); + ret = netxen_rom_lock(adapter); if (ret < 0) return ret; @@ -485,7 +449,7 @@ int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp) { int ret; - if (rom_lock(adapter) != 0) + if (netxen_rom_lock(adapter) != 0) return -EIO; ret = do_rom_fast_read(adapter, addr, valp); @@ -506,7 +470,7 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose) u32 off; /* resetall */ - rom_lock(adapter); + netxen_rom_lock(adapter); NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0xffffffff); netxen_rom_unlock(adapter); diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c index 8b7cd9e1851..1392e8994f2 100644 --- a/drivers/net/netxen/netxen_nic_niu.c +++ b/drivers/net/netxen/netxen_nic_niu.c @@ -30,40 +30,6 @@ #include "netxen_nic.h" -static long phy_lock_timeout = 100000000; - -static int phy_lock(struct netxen_adapter *adapter) -{ - int i; - int done = 0, timeout = 0; - - while (!done) { - done = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM3_LOCK)); - if (done == 1) - break; - if (timeout >= phy_lock_timeout) { - return -1; - } - timeout++; - if (!in_atomic()) - schedule(); - else { - for (i = 0; i < 20; i++) - cpu_relax(); - } - } - - NXWR32(adapter, NETXEN_PHY_LOCK_ID, PHY_LOCK_DRIVER); - return 0; -} - -static int phy_unlock(struct netxen_adapter *adapter) -{ - adapter->pci_read_immediate(adapter, NETXEN_PCIE_REG(PCIE_SEM3_UNLOCK)); - - return 0; -} - /* * netxen_niu_gbe_phy_read - read a register from the GbE PHY via * mii management interface. @@ -89,9 +55,8 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, __u32 status; __u32 mac_cfg0; - if (phy_lock(adapter) != 0) { + if (netxen_phy_lock(adapter) != 0) return -1; - } /* * MII mgmt all goes through port 0 MAC interface, @@ -141,7 +106,7 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, if (restore) if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), mac_cfg0)) return -EIO; - phy_unlock(adapter); + netxen_phy_unlock(adapter); return result; } -- cgit v1.2.3-18-g5258 From 3ad4467ca43e7a2556e26e4e304faf3385048834 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Mon, 24 Aug 2009 19:23:27 +0000 Subject: netxen: remove netxen_nic_niu.c Consolidate all MAC/PHY access functions into netxen_nic_hw.c Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/Makefile | 2 +- drivers/net/netxen/netxen_nic.h | 27 ++-- drivers/net/netxen/netxen_nic_ctx.c | 38 +++++ drivers/net/netxen/netxen_nic_hw.c | 79 ++++++++++ drivers/net/netxen/netxen_nic_init.c | 10 +- drivers/net/netxen/netxen_nic_niu.c | 275 ----------------------------------- 6 files changed, 141 insertions(+), 290 deletions(-) delete mode 100644 drivers/net/netxen/netxen_nic_niu.c (limited to 'drivers') diff --git a/drivers/net/netxen/Makefile b/drivers/net/netxen/Makefile index cf01a9130c9..a70b682f616 100644 --- a/drivers/net/netxen/Makefile +++ b/drivers/net/netxen/Makefile @@ -31,4 +31,4 @@ obj-$(CONFIG_NETXEN_NIC) := netxen_nic.o netxen_nic-y := netxen_nic_hw.o netxen_nic_main.o netxen_nic_init.o \ - netxen_nic_ethtool.o netxen_nic_niu.o netxen_nic_ctx.o + netxen_nic_ethtool.o netxen_nic_ctx.o diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 061e8aa419b..63e2f793ae0 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -684,7 +684,19 @@ struct netxen_recv_context { #define NX_CDRP_CMD_GET_STATISTICS 0x0000000f #define NX_CDRP_CMD_DELETE_STATISTICS 0x00000010 #define NX_CDRP_CMD_SET_MTU 0x00000012 -#define NX_CDRP_CMD_MAX 0x00000013 +#define NX_CDRP_CMD_READ_PHY 0x00000013 +#define NX_CDRP_CMD_WRITE_PHY 0x00000014 +#define NX_CDRP_CMD_READ_HW_REG 0x00000015 +#define NX_CDRP_CMD_GET_FLOW_CTL 0x00000016 +#define NX_CDRP_CMD_SET_FLOW_CTL 0x00000017 +#define NX_CDRP_CMD_READ_MAX_MTU 0x00000018 +#define NX_CDRP_CMD_READ_MAX_LRO 0x00000019 +#define NX_CDRP_CMD_CONFIGURE_TOE 0x0000001a +#define NX_CDRP_CMD_FUNC_ATTRIB 0x0000001b +#define NX_CDRP_CMD_READ_PEXQ_PARAMETERS 0x0000001c +#define NX_CDRP_CMD_GET_LIC_CAPABILITIES 0x0000001d +#define NX_CDRP_CMD_READ_MAX_LRO_PER_BOARD 0x0000001e +#define NX_CDRP_CMD_MAX 0x0000001f #define NX_RCODE_SUCCESS 0 #define NX_RCODE_NO_HOST_MEM 1 @@ -1152,8 +1164,8 @@ struct netxen_adapter { int (*set_mtu) (struct netxen_adapter *, int); int (*set_promisc) (struct netxen_adapter *, u32); void (*set_multi) (struct net_device *); - int (*phy_read) (struct netxen_adapter *, long reg, u32 *); - int (*phy_write) (struct netxen_adapter *, long reg, u32 val); + int (*phy_read) (struct netxen_adapter *, u32 reg, u32 *); + int (*phy_write) (struct netxen_adapter *, u32 reg, u32 val); int (*init_port) (struct netxen_adapter *, int); int (*stop_port) (struct netxen_adapter *); @@ -1185,15 +1197,11 @@ struct netxen_adapter { const struct firmware *fw; }; -int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, - u32 mode); int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port); int netxen_niu_disable_xg_port(struct netxen_adapter *adapter); -int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, - __u32 * readval); -int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, - long reg, __u32 val); +int nx_fw_cmd_query_phy(struct netxen_adapter *adapter, u32 reg, u32 *val); +int nx_fw_cmd_set_phy(struct netxen_adapter *adapter, u32 reg, u32 val); /* Functions available from netxen_nic_hw.c */ int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu); @@ -1313,6 +1321,7 @@ int netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max); void netxen_p2_nic_set_multi(struct net_device *netdev); void netxen_p3_nic_set_multi(struct net_device *netdev); void netxen_p3_free_mac_list(struct netxen_adapter *adapter); +int netxen_p2_nic_set_promisc(struct netxen_adapter *adapter, u32 mode); int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32); int netxen_config_intr_coalesce(struct netxen_adapter *adapter); int netxen_config_rss(struct netxen_adapter *adapter, int enable); diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index ef846b43390..0f42ab99836 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -380,6 +380,44 @@ nx_fw_cmd_destroy_tx_ctx(struct netxen_adapter *adapter) } } +int +nx_fw_cmd_query_phy(struct netxen_adapter *adapter, u32 reg, u32 *val) +{ + u32 rcode; + + rcode = netxen_issue_cmd(adapter, + adapter->ahw.pci_func, + NXHAL_VERSION, + reg, + 0, + 0, + NX_CDRP_CMD_READ_PHY); + + if (rcode != NX_RCODE_SUCCESS) + return -EIO; + + return NXRD32(adapter, NX_ARG1_CRB_OFFSET); +} + +int +nx_fw_cmd_set_phy(struct netxen_adapter *adapter, u32 reg, u32 val) +{ + u32 rcode; + + rcode = netxen_issue_cmd(adapter, + adapter->ahw.pci_func, + NXHAL_VERSION, + reg, + val, + 0, + NX_CDRP_CMD_WRITE_PHY); + + if (rcode != NX_RCODE_SUCCESS) + return -EIO; + + return 0; +} + static u64 ctx_addr_sig_regs[][3] = { {NETXEN_NIC_REG(0x188), NETXEN_NIC_REG(0x18c), NETXEN_NIC_REG(0x1c0)}, {NETXEN_NIC_REG(0x190), NETXEN_NIC_REG(0x194), NETXEN_NIC_REG(0x1c4)}, diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index cbfe44c8a7f..1a8ad62e12e 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -348,6 +348,35 @@ netxen_pcie_sem_unlock(struct netxen_adapter *adapter, int sem) val = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM_UNLOCK(sem))); } +int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port) +{ + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_1+(0x10000*port), 0x1447); + NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_0+(0x10000*port), 0x5); + } + + return 0; +} + +/* Disable an XG interface */ +int netxen_niu_disable_xg_port(struct netxen_adapter *adapter) +{ + __u32 mac_cfg; + u32 port = adapter->physical_port; + + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + return 0; + + if (port > NETXEN_NIU_MAX_XG_PORTS) + return -EINVAL; + + mac_cfg = 0; + if (NXWR32(adapter, + NETXEN_NIU_XGE_CONFIG_0 + (0x10000 * port), mac_cfg)) + return -EIO; + return 0; +} + #define NETXEN_UNICAST_ADDR(port, index) \ (NETXEN_UNICAST_ADDR_BASE+(port*32)+(index*8)) #define NETXEN_MCAST_ADDR(port, index) \ @@ -357,6 +386,56 @@ netxen_pcie_sem_unlock(struct netxen_adapter *adapter, int sem) #define MAC_LO(addr) \ ((addr[5] << 16) | (addr[4] << 8) | (addr[3])) +int netxen_p2_nic_set_promisc(struct netxen_adapter *adapter, u32 mode) +{ + __u32 reg; + u32 port = adapter->physical_port; + + if (port > NETXEN_NIU_MAX_XG_PORTS) + return -EINVAL; + + reg = NXRD32(adapter, NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port)); + if (mode == NETXEN_NIU_PROMISC_MODE) + reg = (reg | 0x2000UL); + else + reg = (reg & ~0x2000UL); + + if (mode == NETXEN_NIU_ALLMULTI_MODE) + reg = (reg | 0x1000UL); + else + reg = (reg & ~0x1000UL); + + NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), reg); + + return 0; +} + +int netxen_p2_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr) +{ + u32 mac_hi, mac_lo; + u32 reg_hi, reg_lo; + + u8 phy = adapter->physical_port; + + if (phy >= NETXEN_NIU_MAX_XG_PORTS) + return -EINVAL; + + mac_lo = ((u32)addr[0] << 16) | ((u32)addr[1] << 24); + mac_hi = addr[2] | ((u32)addr[3] << 8) | + ((u32)addr[4] << 16) | ((u32)addr[5] << 24); + + reg_lo = NETXEN_NIU_XGE_STATION_ADDR_0_1 + (0x10000 * phy); + reg_hi = NETXEN_NIU_XGE_STATION_ADDR_0_HI + (0x10000 * phy); + + /* write twice to flush */ + if (NXWR32(adapter, reg_lo, mac_lo) || NXWR32(adapter, reg_hi, mac_hi)) + return -EIO; + if (NXWR32(adapter, reg_lo, mac_lo) || NXWR32(adapter, reg_hi, mac_hi)) + return -EIO; + + return 0; +} + static int netxen_nic_enable_mcast_filter(struct netxen_adapter *adapter) { diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 313cd261b2b..8d4aa6f74bf 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -328,17 +328,17 @@ void netxen_initialize_adapter_ops(struct netxen_adapter *adapter) adapter->macaddr_set = netxen_p2_nic_set_mac_addr; adapter->set_multi = netxen_p2_nic_set_multi; adapter->set_mtu = netxen_nic_set_mtu_xgb; - adapter->set_promisc = netxen_niu_xg_set_promiscuous_mode; + adapter->set_promisc = netxen_p2_nic_set_promisc; } else { adapter->set_mtu = nx_fw_cmd_set_mtu; adapter->set_promisc = netxen_p3_nic_set_promisc; adapter->macaddr_set = netxen_p3_nic_set_mac_addr; adapter->set_multi = netxen_p3_nic_set_multi; - } - if (adapter->ahw.port_type == NETXEN_NIC_GBE) { - adapter->phy_read = netxen_niu_gbe_phy_read; - adapter->phy_write = netxen_niu_gbe_phy_write; + if (adapter->ahw.port_type == NETXEN_NIC_GBE) { + adapter->phy_read = nx_fw_cmd_query_phy; + adapter->phy_write = nx_fw_cmd_set_phy; + } } } diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c deleted file mode 100644 index 1392e8994f2..00000000000 --- a/drivers/net/netxen/netxen_nic_niu.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (C) 2003 - 2009 NetXen, Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA. - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE. - * - * Contact Information: - * info@netxen.com - * NetXen Inc, - * 18922 Forge Drive - * Cupertino, CA 95014-0701 - * - */ - -#include "netxen_nic.h" - -/* - * netxen_niu_gbe_phy_read - read a register from the GbE PHY via - * mii management interface. - * - * Note: The MII management interface goes through port 0. - * Individual phys are addressed as follows: - * @param phy [15:8] phy id - * @param reg [7:0] register number - * - * @returns 0 on success - * -1 on error - * - */ -int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, - __u32 * readval) -{ - long timeout = 0; - long result = 0; - long restore = 0; - long phy = adapter->physical_port; - __u32 address; - __u32 command; - __u32 status; - __u32 mac_cfg0; - - if (netxen_phy_lock(adapter) != 0) - return -1; - - /* - * MII mgmt all goes through port 0 MAC interface, - * so it cannot be in reset - */ - - mac_cfg0 = NXRD32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0)); - if (netxen_gb_get_soft_reset(mac_cfg0)) { - __u32 temp; - temp = 0; - netxen_gb_tx_reset_pb(temp); - netxen_gb_rx_reset_pb(temp); - netxen_gb_tx_reset_mac(temp); - netxen_gb_rx_reset_mac(temp); - if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), temp)) - return -EIO; - restore = 1; - } - - address = 0; - netxen_gb_mii_mgmt_reg_addr(address, reg); - netxen_gb_mii_mgmt_phy_addr(address, phy); - if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR(0), address)) - return -EIO; - command = 0; /* turn off any prior activity */ - if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), command)) - return -EIO; - /* send read command */ - netxen_gb_mii_mgmt_set_read_cycle(command); - if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), command)) - return -EIO; - - status = 0; - do { - status = NXRD32(adapter, NETXEN_NIU_GB_MII_MGMT_INDICATE(0)); - timeout++; - } while ((netxen_get_gb_mii_mgmt_busy(status) - || netxen_get_gb_mii_mgmt_notvalid(status)) - && (timeout++ < NETXEN_NIU_PHY_WAITMAX)); - - if (timeout < NETXEN_NIU_PHY_WAITMAX) { - *readval = NXRD32(adapter, NETXEN_NIU_GB_MII_MGMT_STATUS(0)); - result = 0; - } else - result = -1; - - if (restore) - if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), mac_cfg0)) - return -EIO; - netxen_phy_unlock(adapter); - return result; -} - -/* - * netxen_niu_gbe_phy_write - write a register to the GbE PHY via - * mii management interface. - * - * Note: The MII management interface goes through port 0. - * Individual phys are addressed as follows: - * @param phy [15:8] phy id - * @param reg [7:0] register number - * - * @returns 0 on success - * -1 on error - * - */ -int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, - __u32 val) -{ - long timeout = 0; - long result = 0; - long restore = 0; - long phy = adapter->physical_port; - __u32 address; - __u32 command; - __u32 status; - __u32 mac_cfg0; - - /* - * MII mgmt all goes through port 0 MAC interface, so it - * cannot be in reset - */ - - mac_cfg0 = NXRD32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0)); - if (netxen_gb_get_soft_reset(mac_cfg0)) { - __u32 temp; - temp = 0; - netxen_gb_tx_reset_pb(temp); - netxen_gb_rx_reset_pb(temp); - netxen_gb_tx_reset_mac(temp); - netxen_gb_rx_reset_mac(temp); - - if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), temp)) - return -EIO; - restore = 1; - } - - command = 0; /* turn off any prior activity */ - if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), command)) - return -EIO; - - address = 0; - netxen_gb_mii_mgmt_reg_addr(address, reg); - netxen_gb_mii_mgmt_phy_addr(address, phy); - if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR(0), address)) - return -EIO; - - if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_CTRL(0), val)) - return -EIO; - - status = 0; - do { - status = NXRD32(adapter, NETXEN_NIU_GB_MII_MGMT_INDICATE(0)); - timeout++; - } while ((netxen_get_gb_mii_mgmt_busy(status)) - && (timeout++ < NETXEN_NIU_PHY_WAITMAX)); - - if (timeout < NETXEN_NIU_PHY_WAITMAX) - result = 0; - else - result = -EIO; - - /* restore the state of port 0 MAC in case we tampered with it */ - if (restore) - if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), mac_cfg0)) - return -EIO; - - return result; -} - -int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port) -{ - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { - NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_1+(0x10000*port), 0x1447); - NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_0+(0x10000*port), 0x5); - } - - return 0; -} - -/* Disable an XG interface */ -int netxen_niu_disable_xg_port(struct netxen_adapter *adapter) -{ - __u32 mac_cfg; - u32 port = adapter->physical_port; - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - return 0; - - if (port > NETXEN_NIU_MAX_XG_PORTS) - return -EINVAL; - - mac_cfg = 0; - if (NXWR32(adapter, - NETXEN_NIU_XGE_CONFIG_0 + (0x10000 * port), mac_cfg)) - return -EIO; - return 0; -} - -int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, - u32 mode) -{ - __u32 reg; - u32 port = adapter->physical_port; - - if (port > NETXEN_NIU_MAX_XG_PORTS) - return -EINVAL; - - reg = NXRD32(adapter, NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port)); - if (mode == NETXEN_NIU_PROMISC_MODE) - reg = (reg | 0x2000UL); - else - reg = (reg & ~0x2000UL); - - if (mode == NETXEN_NIU_ALLMULTI_MODE) - reg = (reg | 0x1000UL); - else - reg = (reg & ~0x1000UL); - - NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), reg); - - return 0; -} - -int netxen_p2_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr) -{ - u32 mac_hi, mac_lo; - u32 reg_hi, reg_lo; - - u8 phy = adapter->physical_port; - u8 phy_count = (adapter->ahw.port_type == NETXEN_NIC_XGBE) ? - NETXEN_NIU_MAX_XG_PORTS : NETXEN_NIU_MAX_GBE_PORTS; - - if (phy >= phy_count) - return -EINVAL; - - mac_lo = ((u32)addr[0] << 16) | ((u32)addr[1] << 24); - mac_hi = addr[2] | ((u32)addr[3] << 8) | - ((u32)addr[4] << 16) | ((u32)addr[5] << 24); - - if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { - reg_lo = NETXEN_NIU_XGE_STATION_ADDR_0_1 + (0x10000 * phy); - reg_hi = NETXEN_NIU_XGE_STATION_ADDR_0_HI + (0x10000 * phy); - } else { - reg_lo = NETXEN_NIU_GB_STATION_ADDR_1(phy); - reg_hi = NETXEN_NIU_GB_STATION_ADDR_0(phy); - } - - /* write twice to flush */ - if (NXWR32(adapter, reg_lo, mac_lo) || NXWR32(adapter, reg_hi, mac_hi)) - return -EIO; - if (NXWR32(adapter, reg_lo, mac_lo) || NXWR32(adapter, reg_hi, mac_hi)) - return -EIO; - - return 0; -} -- cgit v1.2.3-18-g5258 From fa3ce355c1bf1a83b843420228202fd6f8023ad3 Mon Sep 17 00:00:00 2001 From: Narender Kumar Date: Mon, 24 Aug 2009 19:23:28 +0000 Subject: netxen: bridged mode optimizations When the interface is put in bridged mode, destination mac addresses are unknown to firmware. So packets take a slow path (lower priority) in firmware reducing performance. Firmware can cache limited number of remote unicast mac addresses for certain interval, if "dynamic mac learning" mode is enabled. Driver needs to enable this "mac learning" mode in firmware. Currently this is done through net device class sysfs entry, possibly this can also be done upon netlink notifications to from bridge. Signed-off-by: Narender Kumar Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 3 ++ drivers/net/netxen/netxen_nic_hw.c | 31 +++++++++++++ drivers/net/netxen/netxen_nic_main.c | 84 +++++++++++++++++++++++++++++++++++- 3 files changed, 116 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 63e2f793ae0..449d3511628 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -964,6 +964,7 @@ typedef struct { #define NX_NIC_H2C_OPCODE_PROXY_STOP_DONE 20 #define NX_NIC_H2C_OPCODE_GET_LINKEVENT 21 #define NX_NIC_C2C_OPCODE 22 +#define NX_NIC_H2C_OPCODE_CONFIG_BRIDGING 23 #define NX_NIC_H2C_OPCODE_CONFIG_HW_LRO 24 #define NX_NIC_H2C_OPCODE_LAST 25 @@ -1085,6 +1086,7 @@ typedef struct { #define NETXEN_NIC_MSI_ENABLED 0x02 #define NETXEN_NIC_MSIX_ENABLED 0x04 #define NETXEN_NIC_LRO_ENABLED 0x08 +#define NETXEN_NIC_BRIDGE_ENABLED 0X10 #define NETXEN_IS_MSI_FAMILY(adapter) \ ((adapter)->flags & (NETXEN_NIC_MSI_ENABLED | NETXEN_NIC_MSIX_ENABLED)) @@ -1332,6 +1334,7 @@ void netxen_advert_link_change(struct netxen_adapter *adapter, int linkup); int nx_fw_cmd_set_mtu(struct netxen_adapter *adapter, int mtu); int netxen_nic_change_mtu(struct net_device *netdev, int new_mtu); int netxen_config_hw_lro(struct netxen_adapter *adapter, int enable); +int netxen_config_bridged_mode(struct netxen_adapter *adapter, int enable); int netxen_send_lro_cleanup(struct netxen_adapter *adapter); int netxen_nic_set_mac(struct net_device *netdev, void *p); diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 1a8ad62e12e..db510cee809 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -794,6 +794,37 @@ int netxen_config_hw_lro(struct netxen_adapter *adapter, int enable) return rv; } +int netxen_config_bridged_mode(struct netxen_adapter *adapter, int enable) +{ + nx_nic_req_t req; + u64 word; + int rv = 0; + + if (!!(adapter->flags & NETXEN_NIC_BRIDGE_ENABLED) == enable) + return rv; + + memset(&req, 0, sizeof(nx_nic_req_t)); + + req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23); + + word = NX_NIC_H2C_OPCODE_CONFIG_BRIDGING | + ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + + req.words[0] = cpu_to_le64(enable); + + rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) { + printk(KERN_ERR "ERROR. Could not send " + "configure bridge mode request\n"); + } + + adapter->flags ^= NETXEN_NIC_BRIDGE_ENABLED; + + return rv; +} + + #define RSS_HASHTYPE_IP_TCP 0x3 int netxen_config_rss(struct netxen_adapter *adapter, int enable) diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index bd4589f1d46..fab51d16f5f 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -71,6 +71,10 @@ static int netxen_nic_poll(struct napi_struct *napi, int budget); #ifdef CONFIG_NET_POLL_CONTROLLER static void netxen_nic_poll_controller(struct net_device *netdev); #endif + +static void netxen_create_sysfs_entries(struct netxen_adapter *adapter); +static void netxen_remove_sysfs_entries(struct netxen_adapter *adapter); + static irqreturn_t netxen_intr(int irq, void *data); static irqreturn_t netxen_msi_intr(int irq, void *data); static irqreturn_t netxen_msix_intr(int irq, void *data); @@ -94,8 +98,6 @@ static struct pci_device_id netxen_pci_tbl[] __devinitdata = { MODULE_DEVICE_TABLE(pci, netxen_pci_tbl); -static void netxen_watchdog(unsigned long); - static uint32_t crb_cmd_producer[4] = { CRB_CMD_PRODUCER_OFFSET, CRB_CMD_PRODUCER_OFFSET_1, CRB_CMD_PRODUCER_OFFSET_2, CRB_CMD_PRODUCER_OFFSET_3 @@ -995,6 +997,8 @@ netxen_nic_attach(struct netxen_adapter *adapter) if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) netxen_nic_init_coalesce_defaults(adapter); + netxen_create_sysfs_entries(adapter); + adapter->is_up = NETXEN_ADAPTER_UP_MAGIC; return 0; @@ -1012,6 +1016,8 @@ netxen_nic_detach(struct netxen_adapter *adapter) if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) return; + netxen_remove_sysfs_entries(adapter); + netxen_free_hw_resources(adapter); netxen_release_rx_buffers(adapter); netxen_nic_free_irq(adapter); @@ -1959,6 +1965,80 @@ static void netxen_nic_poll_controller(struct net_device *netdev) } #endif +static ssize_t +netxen_store_bridged_mode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct net_device *net = to_net_dev(dev); + struct netxen_adapter *adapter = netdev_priv(net); + unsigned long new; + int ret = -EINVAL; + + if (!(adapter->capabilities & NX_FW_CAPABILITY_BDG)) + goto err_out; + + if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) + goto err_out; + + if (strict_strtoul(buf, 2, &new)) + goto err_out; + + if (!netxen_config_bridged_mode(adapter, !!new)) + ret = len; + +err_out: + return ret; +} + +static ssize_t +netxen_show_bridged_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct net_device *net = to_net_dev(dev); + struct netxen_adapter *adapter; + int bridged_mode = 0; + + adapter = netdev_priv(net); + + if (adapter->capabilities & NX_FW_CAPABILITY_BDG) + bridged_mode = !!(adapter->flags & NETXEN_NIC_BRIDGE_ENABLED); + + return sprintf(buf, "%d\n", bridged_mode); +} + +static struct device_attribute dev_attr_bridged_mode = { + .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)}, + .show = netxen_show_bridged_mode, + .store = netxen_store_bridged_mode, +}; + +static void +netxen_create_sysfs_entries(struct netxen_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct device *dev = &netdev->dev; + + if (adapter->capabilities & NX_FW_CAPABILITY_BDG) { + /* bridged_mode control */ + if (device_create_file(dev, &dev_attr_bridged_mode)) { + dev_warn(&netdev->dev, + "failed to create bridged_mode sysfs entry\n"); + } + } +} + +static void +netxen_remove_sysfs_entries(struct netxen_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct device *dev = &netdev->dev; + + if (adapter->capabilities & NX_FW_CAPABILITY_BDG) + device_remove_file(dev, &dev_attr_bridged_mode); +} + +static void netxen_watchdog(unsigned long); + #ifdef CONFIG_INET #define is_netxen_netdev(dev) (dev->netdev_ops == &netxen_netdev_ops) -- cgit v1.2.3-18-g5258 From 46a72b35144769d1e9c23c3a9a26c1776ef7d8f6 Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Tue, 25 Aug 2009 04:47:11 +0000 Subject: ixgbe: Fix isues while reporting 8259x backplane link capabilities Fix ethtool get_settings logic to report 10G & 1G advertised and supported link modes in all 8259x 10G backplane connection types except for 82598EB BX network connection type. Signed-off-by: Mallikarjuna R Chilakala Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_ethtool.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index dd221bba54d..1444ec51253 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -169,23 +169,20 @@ static int ixgbe_get_settings(struct net_device *netdev, } } else if (hw->phy.media_type == ixgbe_media_type_backplane) { /* Set as FIBRE until SERDES defined in kernel */ - switch (hw->device_id) { - case IXGBE_DEV_ID_82598: - ecmd->supported |= (SUPPORTED_1000baseT_Full | - SUPPORTED_FIBRE); - ecmd->advertising = (ADVERTISED_10000baseT_Full | - ADVERTISED_1000baseT_Full | - ADVERTISED_FIBRE); - ecmd->port = PORT_FIBRE; - break; - case IXGBE_DEV_ID_82598_BX: + if (hw->device_id == IXGBE_DEV_ID_82598_BX) { ecmd->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE); ecmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_FIBRE); ecmd->port = PORT_FIBRE; ecmd->autoneg = AUTONEG_DISABLE; - break; + } else { + ecmd->supported |= (SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE); + ecmd->advertising = (ADVERTISED_10000baseT_Full | + ADVERTISED_1000baseT_Full | + ADVERTISED_FIBRE); + ecmd->port = PORT_FIBRE; } } else { ecmd->supported |= SUPPORTED_FIBRE; -- cgit v1.2.3-18-g5258 From 7b25cdbafd757b1255725d4ffb5b1081714b4256 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Tue, 25 Aug 2009 04:47:32 +0000 Subject: ixgbe: cleanup functions that should have been defined static We have some ~40 functions that were being called out with 'make namespacecheck'. This patch changes these functions to be static. Signed-off-by: Don Skidmore Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe.h | 35 --------- drivers/net/ixgbe/ixgbe_82598.c | 6 +- drivers/net/ixgbe/ixgbe_82599.c | 156 +++++++++++++++++++-------------------- drivers/net/ixgbe/ixgbe_common.c | 3 +- drivers/net/ixgbe/ixgbe_common.h | 1 - drivers/net/ixgbe/ixgbe_main.c | 2 +- 6 files changed, 81 insertions(+), 122 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 8f1f8bab0fd..c983c89630a 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -424,55 +424,20 @@ extern s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc); extern s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw, struct ixgbe_atr_input *input, u8 queue); -extern s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw, - struct ixgbe_atr_input *input, - u16 soft_id, - u8 queue); -extern u16 ixgbe_atr_compute_hash_82599(struct ixgbe_atr_input *input, u32 key); extern s32 ixgbe_atr_set_vlan_id_82599(struct ixgbe_atr_input *input, u16 vlan_id); extern s32 ixgbe_atr_set_src_ipv4_82599(struct ixgbe_atr_input *input, u32 src_addr); extern s32 ixgbe_atr_set_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 dst_addr); -extern s32 ixgbe_atr_set_src_ipv6_82599(struct ixgbe_atr_input *input, - u32 src_addr_1, u32 src_addr_2, - u32 src_addr_3, u32 src_addr_4); -extern s32 ixgbe_atr_set_dst_ipv6_82599(struct ixgbe_atr_input *input, - u32 dst_addr_1, u32 dst_addr_2, - u32 dst_addr_3, u32 dst_addr_4); extern s32 ixgbe_atr_set_src_port_82599(struct ixgbe_atr_input *input, u16 src_port); extern s32 ixgbe_atr_set_dst_port_82599(struct ixgbe_atr_input *input, u16 dst_port); extern s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input, u16 flex_byte); -extern s32 ixgbe_atr_set_vm_pool_82599(struct ixgbe_atr_input *input, - u8 vm_pool); extern s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input, u8 l4type); -extern s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, - u16 *vlan_id); -extern s32 ixgbe_atr_get_src_ipv4_82599(struct ixgbe_atr_input *input, - u32 *src_addr); -extern s32 ixgbe_atr_get_dst_ipv4_82599(struct ixgbe_atr_input *input, - u32 *dst_addr); -extern s32 ixgbe_atr_get_src_ipv6_82599(struct ixgbe_atr_input *input, - u32 *src_addr_1, u32 *src_addr_2, - u32 *src_addr_3, u32 *src_addr_4); -extern s32 ixgbe_atr_get_dst_ipv6_82599(struct ixgbe_atr_input *input, - u32 *dst_addr_1, u32 *dst_addr_2, - u32 *dst_addr_3, u32 *dst_addr_4); -extern s32 ixgbe_atr_get_src_port_82599(struct ixgbe_atr_input *input, - u16 *src_port); -extern s32 ixgbe_atr_get_dst_port_82599(struct ixgbe_atr_input *input, - u16 *dst_port); -extern s32 ixgbe_atr_get_flex_byte_82599(struct ixgbe_atr_input *input, - u16 *flex_byte); -extern s32 ixgbe_atr_get_vm_pool_82599(struct ixgbe_atr_input *input, - u8 *vm_pool); -extern s32 ixgbe_atr_get_l4type_82599(struct ixgbe_atr_input *input, - u8 *l4type); #ifdef IXGBE_FCOE extern void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter); extern int ixgbe_fso(struct ixgbe_adapter *adapter, diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 1c227b0777a..916430f2a7e 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -59,7 +59,7 @@ static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, * increase the value to either 10ms to 250ms for capability version 1 config, * or 16ms to 55ms for version 2. **/ -void ixgbe_set_pcie_completion_timeout(struct ixgbe_hw *hw) +static void ixgbe_set_pcie_completion_timeout(struct ixgbe_hw *hw) { struct ixgbe_adapter *adapter = hw->back; u32 gcr = IXGBE_READ_REG(hw, IXGBE_GCR); @@ -143,7 +143,7 @@ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) * not known. Perform the SFP init if necessary. * **/ -s32 ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw) +static s32 ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; struct ixgbe_phy_info *phy = &hw->phy; @@ -204,7 +204,7 @@ out: * Starts the hardware using the generic start_hw function. * Then set pcie completion timeout **/ -s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw) +static s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw) { s32 ret_val = 0; diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 1984cab7d48..364b6d2279e 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -38,22 +38,15 @@ #define IXGBE_82599_MC_TBL_SIZE 128 #define IXGBE_82599_VFT_TBL_SIZE 128 -s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, - ixgbe_link_speed *speed, - bool *autoneg); -enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw); -s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw); -s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, +static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw); +static s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg, bool autoneg_wait_to_complete); -s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw); -s32 ixgbe_check_mac_link_82599(struct ixgbe_hw *hw, - ixgbe_link_speed *speed, - bool *link_up, bool link_up_wait_to_complete); -s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, - ixgbe_link_speed speed, - bool autoneg, - bool autoneg_wait_to_complete); +static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw); +static s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete); static s32 ixgbe_get_copper_link_capabilities_82599(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *autoneg); @@ -62,21 +55,9 @@ static s32 ixgbe_setup_copper_link_speed_82599(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg, bool autoneg_wait_to_complete); -s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw); -s32 ixgbe_set_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq); -s32 ixgbe_clear_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq); -s32 ixgbe_set_vfta_82599(struct ixgbe_hw *hw, u32 vlan, - u32 vind, bool vlan_on); -s32 ixgbe_clear_vfta_82599(struct ixgbe_hw *hw); -s32 ixgbe_init_uta_tables_82599(struct ixgbe_hw *hw); -s32 ixgbe_read_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 *val); -s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val); -s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw); -s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw); -u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw); static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw); -void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) +static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; if (hw->phy.multispeed_fiber) { @@ -93,7 +74,7 @@ void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) } } -s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) +static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) { s32 ret_val = 0; u16 list_offset, data_offset, data_value; @@ -143,7 +124,7 @@ setup_sfp_out: * Read PCIe configuration space, and get the MSI-X vector count from * the capabilities table. **/ -u32 ixgbe_get_pcie_msix_count_82599(struct ixgbe_hw *hw) +static u32 ixgbe_get_pcie_msix_count_82599(struct ixgbe_hw *hw) { struct ixgbe_adapter *adapter = hw->back; u16 msix_count; @@ -182,7 +163,7 @@ static s32 ixgbe_get_invariants_82599(struct ixgbe_hw *hw) * not known. Perform the SFP init if necessary. * **/ -s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw) +static s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; struct ixgbe_phy_info *phy = &hw->phy; @@ -225,9 +206,9 @@ s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw) * * Determines the link capabilities by reading the AUTOC register. **/ -s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, - ixgbe_link_speed *speed, - bool *negotiation) +static s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *negotiation) { s32 status = 0; u32 autoc = 0; @@ -344,7 +325,7 @@ static s32 ixgbe_get_copper_link_capabilities_82599(struct ixgbe_hw *hw, * * Returns the media type (fiber, copper, backplane) **/ -enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw) +static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw) { enum ixgbe_media_type media_type; @@ -379,7 +360,7 @@ out: * Configures link settings based on values in the ixgbe_hw struct. * Restarts the link. Performs autonegotiation if needed. **/ -s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw) +static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw) { u32 autoc_reg; u32 links_reg; @@ -428,7 +409,7 @@ s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw) * fails at 10G. * Performs autonegotiation if needed. **/ -s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw) +static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw) { s32 status = 0; ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_82599_AUTONEG; @@ -446,7 +427,7 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw) * * Set the link speed in the AUTOC register and restarts link. **/ -s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, +static s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg, bool autoneg_wait_to_complete) @@ -613,8 +594,10 @@ out: * * Reads the links register to determine if link is up and the current speed **/ -s32 ixgbe_check_mac_link_82599(struct ixgbe_hw *hw, ixgbe_link_speed *speed, - bool *link_up, bool link_up_wait_to_complete) +static s32 ixgbe_check_mac_link_82599(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *link_up, + bool link_up_wait_to_complete) { u32 links_reg; u32 i; @@ -665,9 +648,10 @@ s32 ixgbe_check_mac_link_82599(struct ixgbe_hw *hw, ixgbe_link_speed *speed, * * Set the link speed in the AUTOC register and restarts link. **/ -s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, - ixgbe_link_speed speed, bool autoneg, - bool autoneg_wait_to_complete) +static s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete) { s32 status = 0; u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); @@ -818,7 +802,7 @@ static s32 ixgbe_setup_copper_link_speed_82599(struct ixgbe_hw *hw, * and clears all interrupts, perform a PHY reset, and perform a link (MAC) * reset. **/ -s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) +static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) { s32 status = 0; u32 ctrl, ctrl_ext; @@ -943,7 +927,7 @@ reset_hw_out: * @rar: receive address register index to disassociate * @vmdq: VMDq pool index to remove from the rar **/ -s32 ixgbe_clear_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq) +static s32 ixgbe_clear_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq) { u32 mpsar_lo, mpsar_hi; u32 rar_entries = hw->mac.num_rar_entries; @@ -989,7 +973,7 @@ done: * @rar: receive address register index to associate with a VMDq index * @vmdq: VMDq pool index **/ -s32 ixgbe_set_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq) +static s32 ixgbe_set_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq) { u32 mpsar; u32 rar_entries = hw->mac.num_rar_entries; @@ -1019,8 +1003,8 @@ s32 ixgbe_set_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq) * * Turn on/off specified VLAN in the VLAN filter table. **/ -s32 ixgbe_set_vfta_82599(struct ixgbe_hw *hw, u32 vlan, u32 vind, - bool vlan_on) +static s32 ixgbe_set_vfta_82599(struct ixgbe_hw *hw, u32 vlan, u32 vind, + bool vlan_on) { u32 regindex; u32 bitindex; @@ -1133,7 +1117,7 @@ out: * * Clears the VLAN filer table, and the VMDq index associated with the filter **/ -s32 ixgbe_clear_vfta_82599(struct ixgbe_hw *hw) +static s32 ixgbe_clear_vfta_82599(struct ixgbe_hw *hw) { u32 offset; @@ -1153,7 +1137,7 @@ s32 ixgbe_clear_vfta_82599(struct ixgbe_hw *hw) * ixgbe_init_uta_tables_82599 - Initialize the Unicast Table Array * @hw: pointer to hardware structure **/ -s32 ixgbe_init_uta_tables_82599(struct ixgbe_hw *hw) +static s32 ixgbe_init_uta_tables_82599(struct ixgbe_hw *hw) { int i; hw_dbg(hw, " Clearing UTA\n"); @@ -1430,7 +1414,8 @@ s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc) * @stream: input bitstream to compute the hash on * @key: 32-bit hash key **/ -u16 ixgbe_atr_compute_hash_82599(struct ixgbe_atr_input *atr_input, u32 key) +static u16 ixgbe_atr_compute_hash_82599(struct ixgbe_atr_input *atr_input, + u32 key) { /* * The algorithm is as follows: @@ -1602,8 +1587,8 @@ s32 ixgbe_atr_set_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 dst_addr) * @src_addr_4: the fourth 4 bytes of the IP address to load **/ s32 ixgbe_atr_set_src_ipv6_82599(struct ixgbe_atr_input *input, - u32 src_addr_1, u32 src_addr_2, - u32 src_addr_3, u32 src_addr_4) + u32 src_addr_1, u32 src_addr_2, + u32 src_addr_3, u32 src_addr_4) { input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET] = src_addr_4 & 0xff; input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 1] = @@ -1645,8 +1630,8 @@ s32 ixgbe_atr_set_src_ipv6_82599(struct ixgbe_atr_input *input, * @dst_addr_4: the fourth 4 bytes of the IP address to load **/ s32 ixgbe_atr_set_dst_ipv6_82599(struct ixgbe_atr_input *input, - u32 dst_addr_1, u32 dst_addr_2, - u32 dst_addr_3, u32 dst_addr_4) + u32 dst_addr_1, u32 dst_addr_2, + u32 dst_addr_3, u32 dst_addr_4) { input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET] = dst_addr_4 & 0xff; input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 1] = @@ -1723,7 +1708,8 @@ s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input, u16 flex_byte) * @input: input stream to modify * @vm_pool: the Virtual Machine pool to load **/ -s32 ixgbe_atr_set_vm_pool_82599(struct ixgbe_atr_input *input, u8 vm_pool) +s32 ixgbe_atr_set_vm_pool_82599(struct ixgbe_atr_input *input, + u8 vm_pool) { input->byte_stream[IXGBE_ATR_VM_POOL_OFFSET] = vm_pool; @@ -1747,7 +1733,8 @@ s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input, u8 l4type) * @input: input stream to search * @vlan: the VLAN id to load **/ -s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, u16 *vlan) +static s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, + u16 *vlan) { *vlan = input->byte_stream[IXGBE_ATR_VLAN_OFFSET]; *vlan |= input->byte_stream[IXGBE_ATR_VLAN_OFFSET + 1] << 8; @@ -1760,7 +1747,8 @@ s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, u16 *vlan) * @input: input stream to search * @src_addr: the IP address to load **/ -s32 ixgbe_atr_get_src_ipv4_82599(struct ixgbe_atr_input *input, u32 *src_addr) +static s32 ixgbe_atr_get_src_ipv4_82599(struct ixgbe_atr_input *input, + u32 *src_addr) { *src_addr = input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET]; *src_addr |= input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 1] << 8; @@ -1775,7 +1763,8 @@ s32 ixgbe_atr_get_src_ipv4_82599(struct ixgbe_atr_input *input, u32 *src_addr) * @input: input stream to search * @dst_addr: the IP address to load **/ -s32 ixgbe_atr_get_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 *dst_addr) +static s32 ixgbe_atr_get_dst_ipv4_82599(struct ixgbe_atr_input *input, + u32 *dst_addr) { *dst_addr = input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET]; *dst_addr |= input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 1] << 8; @@ -1793,9 +1782,9 @@ s32 ixgbe_atr_get_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 *dst_addr) * @src_addr_3: the third 4 bytes of the IP address to load * @src_addr_4: the fourth 4 bytes of the IP address to load **/ -s32 ixgbe_atr_get_src_ipv6_82599(struct ixgbe_atr_input *input, - u32 *src_addr_1, u32 *src_addr_2, - u32 *src_addr_3, u32 *src_addr_4) +static s32 ixgbe_atr_get_src_ipv6_82599(struct ixgbe_atr_input *input, + u32 *src_addr_1, u32 *src_addr_2, + u32 *src_addr_3, u32 *src_addr_4) { *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 12]; *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 13] << 8; @@ -1829,8 +1818,8 @@ s32 ixgbe_atr_get_src_ipv6_82599(struct ixgbe_atr_input *input, * @dst_addr_4: the fourth 4 bytes of the IP address to load **/ s32 ixgbe_atr_get_dst_ipv6_82599(struct ixgbe_atr_input *input, - u32 *dst_addr_1, u32 *dst_addr_2, - u32 *dst_addr_3, u32 *dst_addr_4) + u32 *dst_addr_1, u32 *dst_addr_2, + u32 *dst_addr_3, u32 *dst_addr_4) { *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 12]; *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 13] << 8; @@ -1865,7 +1854,8 @@ s32 ixgbe_atr_get_dst_ipv6_82599(struct ixgbe_atr_input *input, * endianness when retrieving the data. This can be confusing since the * internal hash engine expects it to be big-endian. **/ -s32 ixgbe_atr_get_src_port_82599(struct ixgbe_atr_input *input, u16 *src_port) +static s32 ixgbe_atr_get_src_port_82599(struct ixgbe_atr_input *input, + u16 *src_port) { *src_port = input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET] << 8; *src_port |= input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET + 1]; @@ -1883,7 +1873,8 @@ s32 ixgbe_atr_get_src_port_82599(struct ixgbe_atr_input *input, u16 *src_port) * endianness when retrieving the data. This can be confusing since the * internal hash engine expects it to be big-endian. **/ -s32 ixgbe_atr_get_dst_port_82599(struct ixgbe_atr_input *input, u16 *dst_port) +static s32 ixgbe_atr_get_dst_port_82599(struct ixgbe_atr_input *input, + u16 *dst_port) { *dst_port = input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET] << 8; *dst_port |= input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET + 1]; @@ -1896,7 +1887,8 @@ s32 ixgbe_atr_get_dst_port_82599(struct ixgbe_atr_input *input, u16 *dst_port) * @input: input stream to modify * @flex_bytes: the flexible bytes to load **/ -s32 ixgbe_atr_get_flex_byte_82599(struct ixgbe_atr_input *input, u16 *flex_byte) +static s32 ixgbe_atr_get_flex_byte_82599(struct ixgbe_atr_input *input, + u16 *flex_byte) { *flex_byte = input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET]; *flex_byte |= input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET + 1] << 8; @@ -1909,7 +1901,8 @@ s32 ixgbe_atr_get_flex_byte_82599(struct ixgbe_atr_input *input, u16 *flex_byte) * @input: input stream to modify * @vm_pool: the Virtual Machine pool to load **/ -s32 ixgbe_atr_get_vm_pool_82599(struct ixgbe_atr_input *input, u8 *vm_pool) +s32 ixgbe_atr_get_vm_pool_82599(struct ixgbe_atr_input *input, + u8 *vm_pool) { *vm_pool = input->byte_stream[IXGBE_ATR_VM_POOL_OFFSET]; @@ -1921,7 +1914,8 @@ s32 ixgbe_atr_get_vm_pool_82599(struct ixgbe_atr_input *input, u8 *vm_pool) * @input: input stream to modify * @l4type: the layer 4 type value to load **/ -s32 ixgbe_atr_get_l4type_82599(struct ixgbe_atr_input *input, u8 *l4type) +static s32 ixgbe_atr_get_l4type_82599(struct ixgbe_atr_input *input, + u8 *l4type) { *l4type = input->byte_stream[IXGBE_ATR_L4TYPE_OFFSET]; @@ -2002,9 +1996,9 @@ s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw, * hardware writes must be protected from one another. **/ s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw, - struct ixgbe_atr_input *input, - u16 soft_id, - u8 queue) + struct ixgbe_atr_input *input, + u16 soft_id, + u8 queue) { u32 fdircmd = 0; u32 fdirhash; @@ -2097,7 +2091,7 @@ s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw, * * Performs read operation to Omer analog register specified. **/ -s32 ixgbe_read_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 *val) +static s32 ixgbe_read_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 *val) { u32 core_ctl; @@ -2119,7 +2113,7 @@ s32 ixgbe_read_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 *val) * * Performs write operation to Omer analog register specified. **/ -s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val) +static s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val) { u32 core_ctl; @@ -2139,7 +2133,7 @@ s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val) * Then performs device-specific: * Clears the rate limiter registers. **/ -s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) +static s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) { u32 q_num; s32 ret_val; @@ -2168,7 +2162,7 @@ s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) * * Determines the physical layer module found on the current adapter. **/ -s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw) +static s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw) { s32 status = IXGBE_ERR_PHY_ADDR_INVALID; status = ixgbe_identify_phy_generic(hw); @@ -2183,7 +2177,7 @@ s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw) * * Determines physical layer capabilities of the current configuration. **/ -u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw) +static u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw) { u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); @@ -2290,7 +2284,7 @@ out: * * Enables the Rx DMA unit for 82599 **/ -s32 ixgbe_enable_rx_dma_82599(struct ixgbe_hw *hw, u32 regval) +static s32 ixgbe_enable_rx_dma_82599(struct ixgbe_hw *hw, u32 regval) { #define IXGBE_MAX_SECRX_POLL 30 int i; @@ -2335,7 +2329,7 @@ s32 ixgbe_enable_rx_dma_82599(struct ixgbe_hw *hw, u32 regval) * This function will read the EEPROM location for the device capabilities, * and return the word through device_caps. **/ -s32 ixgbe_get_device_caps_82599(struct ixgbe_hw *hw, u16 *device_caps) +static s32 ixgbe_get_device_caps_82599(struct ixgbe_hw *hw, u16 *device_caps) { hw->eeprom.ops.read(hw, IXGBE_DEVICE_CAPS, device_caps); @@ -2351,8 +2345,8 @@ s32 ixgbe_get_device_caps_82599(struct ixgbe_hw *hw, u16 *device_caps) * pointer, and returns the value at that location. This is used in both * get and set mac_addr routines. **/ -s32 ixgbe_get_san_mac_addr_offset_82599(struct ixgbe_hw *hw, - u16 *san_mac_offset) +static s32 ixgbe_get_san_mac_addr_offset_82599(struct ixgbe_hw *hw, + u16 *san_mac_offset) { /* * First read the EEPROM pointer to see if the MAC addresses are @@ -2373,7 +2367,7 @@ s32 ixgbe_get_san_mac_addr_offset_82599(struct ixgbe_hw *hw, * set_lan_id() is called by identify_sfp(), but this cannot be relied * upon for non-SFP connections, so we must call it here. **/ -s32 ixgbe_get_san_mac_addr_82599(struct ixgbe_hw *hw, u8 *san_mac_addr) +static s32 ixgbe_get_san_mac_addr_82599(struct ixgbe_hw *hw, u8 *san_mac_addr) { u16 san_mac_data, san_mac_offset; u8 i; diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 96a18595377..6621e172df3 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -53,6 +53,7 @@ static void ixgbe_enable_rar(struct ixgbe_hw *hw, u32 index); static void ixgbe_disable_rar(struct ixgbe_hw *hw, u32 index); static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr); static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq); +static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num); /** * ixgbe_start_hw_generic - Prepare hardware for Tx/Rx @@ -1815,7 +1816,7 @@ out: * * Called at init time to set up flow control. **/ -s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) +static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) { s32 ret_val = 0; u32 reg; diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h index 0d34d4d8244..27f3214bed2 100644 --- a/drivers/net/ixgbe/ixgbe_common.h +++ b/drivers/net/ixgbe/ixgbe_common.h @@ -64,7 +64,6 @@ s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw); s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw); s32 ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval); -s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num); s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packtetbuf_num); s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw); diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index d69d277886e..3f1770690bf 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3615,7 +3615,7 @@ static void ixgbe_free_q_vectors(struct ixgbe_adapter *adapter) } } -void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter) +static void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter) { if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED; -- cgit v1.2.3-18-g5258 From cd1da503847a28775f60b959cb7b0123cee2a1a3 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 25 Aug 2009 04:47:50 +0000 Subject: igb/ixgbe: add IPV6_CSUM support to vlan_features We were already exporting TSO6 to the vlan, but we weren't exporting the checksum support for IPV6 which was causing warning messages to be displayed when doing IPv6 TSO over a vlan. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/igb_main.c | 1 + drivers/net/ixgbe/ixgbe_main.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index fb327351758..cef4289d571 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -1380,6 +1380,7 @@ static int __devinit igb_probe(struct pci_dev *pdev, netdev->vlan_features |= NETIF_F_TSO; netdev->vlan_features |= NETIF_F_TSO6; netdev->vlan_features |= NETIF_F_IP_CSUM; + netdev->vlan_features |= NETIF_F_IPV6_CSUM; netdev->vlan_features |= NETIF_F_SG; if (pci_using_dac) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 3f1770690bf..0bea096e964 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -5575,6 +5575,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, netdev->vlan_features |= NETIF_F_TSO; netdev->vlan_features |= NETIF_F_TSO6; netdev->vlan_features |= NETIF_F_IP_CSUM; + netdev->vlan_features |= NETIF_F_IPV6_CSUM; netdev->vlan_features |= NETIF_F_SG; if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) -- cgit v1.2.3-18-g5258 From c46b59b241ec52ffaf92ece8d8ab726621d580fb Mon Sep 17 00:00:00 2001 From: "Graham, David" Date: Tue, 25 Aug 2009 04:43:17 +0000 Subject: e1000: Remove unused function e1000_mta_set. Remove function e1000_mta_set, as it is no longer called Signed-off-by: Dave Graham Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000/e1000_hw.c | 46 -------------------------------------------- 1 file changed, 46 deletions(-) (limited to 'drivers') diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 1e5ae112d57..cda6b397550 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -5758,52 +5758,6 @@ u32 e1000_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr) return hash_value; } -/****************************************************************************** - * Sets the bit in the multicast table corresponding to the hash value. - * - * hw - Struct containing variables accessed by shared code - * hash_value - Multicast address hash value - *****************************************************************************/ -void e1000_mta_set(struct e1000_hw *hw, u32 hash_value) -{ - u32 hash_bit, hash_reg; - u32 mta; - u32 temp; - - /* The MTA is a register array of 128 32-bit registers. - * It is treated like an array of 4096 bits. We want to set - * bit BitArray[hash_value]. So we figure out what register - * the bit is in, read it, OR in the new bit, then write - * back the new value. The register is determined by the - * upper 7 bits of the hash value and the bit within that - * register are determined by the lower 5 bits of the value. - */ - hash_reg = (hash_value >> 5) & 0x7F; - if (hw->mac_type == e1000_ich8lan) - hash_reg &= 0x1F; - - hash_bit = hash_value & 0x1F; - - mta = E1000_READ_REG_ARRAY(hw, MTA, hash_reg); - - mta |= (1 << hash_bit); - - /* If we are on an 82544 and we are trying to write an odd offset - * in the MTA, save off the previous entry before writing and - * restore the old value after writing. - */ - if ((hw->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) { - temp = E1000_READ_REG_ARRAY(hw, MTA, (hash_reg - 1)); - E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta); - E1000_WRITE_FLUSH(); - E1000_WRITE_REG_ARRAY(hw, MTA, (hash_reg - 1), temp); - E1000_WRITE_FLUSH(); - } else { - E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta); - E1000_WRITE_FLUSH(); - } -} - /****************************************************************************** * Puts an ethernet address into a receive address register. * -- cgit v1.2.3-18-g5258 From 521e6b90dd3f0392062845d7ef13e6e41bb99d8a Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:06:01 +0000 Subject: tg3: Fix 57780 asic rev PCIe link receiver errors This patch fixes some PCIe link receiver errors by decreasing the internal electrical idle timeout. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 5 +++++ drivers/net/tg3.h | 13 +++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 46a3f86125b..e8def28877c 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6719,6 +6719,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) val |= PCIE_PWR_MGMT_EXT_ASPM_TMR_EN | PCIE_PWR_MGMT_L1_THRESH_4MS; tw32(PCIE_PWR_MGMT_THRESH, val); + + val = tr32(TG3_PCIE_EIDLE_DELAY) & ~TG3_PCIE_EIDLE_DELAY_MASK; + tw32(TG3_PCIE_EIDLE_DELAY, val | TG3_PCIE_EIDLE_DELAY_13_CLKS); + + tw32(TG3_CORR_ERR_STAT, TG3_CORR_ERR_STAT_CLEAR); } /* This works around an issue with Athlon chipsets on diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index b3347c41a1a..c613cbb40c2 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -214,9 +214,11 @@ #define DUAL_MAC_CTRL_ID 0x00000004 #define TG3PCI_PRODID_ASICREV 0x000000bc #define PROD_ID_ASIC_REV_MASK 0x0fffffff -/* 0xc0 --> 0x100 unused */ +/* 0xc0 --> 0x110 unused */ -/* 0x100 --> 0x200 unused */ +#define TG3_CORR_ERR_STAT 0x00000110 +#define TG3_CORR_ERR_STAT_CLEAR 0xffffffff +/* 0x114 --> 0x200 unused */ /* Mailbox registers */ #define MAILBOX_INTERRUPT_0 0x00000200 /* 64-bit */ @@ -1696,11 +1698,18 @@ #define PCIE_TRANSACTION_CFG 0x00007c04 #define PCIE_TRANS_CFG_1SHOT_MSI 0x20000000 #define PCIE_TRANS_CFG_LOM 0x00000020 +/* 0x7c08 --> 0x7d28 unused */ #define PCIE_PWR_MGMT_THRESH 0x00007d28 #define PCIE_PWR_MGMT_L1_THRESH_MSK 0x0000ff00 #define PCIE_PWR_MGMT_L1_THRESH_4MS 0x0000ff00 #define PCIE_PWR_MGMT_EXT_ASPM_TMR_EN 0x01000000 +/* 0x7d2c --> 0x7e70 unused */ + +#define TG3_PCIE_EIDLE_DELAY 0x00007e70 +#define TG3_PCIE_EIDLE_DELAY_MASK 0x0000001f +#define TG3_PCIE_EIDLE_DELAY_13_CLKS 0x0000000c +/* 0x7e74 --> 0x8000 unused */ /* OTP bit definitions */ -- cgit v1.2.3-18-g5258 From 255ca311b650caece3ec4f78b88ef298664d561f Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:07:27 +0000 Subject: tg3: Prevent tx BD corruption This patch prevents a tx BD corruption bug by preventing the device from powering down the PLL from L1 if the link speed is 10Mbps or 100Mbps. The same bits are also used to prevent a system hang during chip reset resulting from a complicated set of events that ultimately leads to PCIe block register corruption. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 28 ++++++++++++++++++++++++++++ drivers/net/tg3.h | 9 ++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e8def28877c..595ddf2eb7d 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3167,6 +3167,15 @@ relink: pci_write_config_word(tp->pdev, tp->pcie_cap + PCI_EXP_LNKCTL, newlnkctl); + } else if (tp->tg3_flags3 & TG3_FLG3_TOGGLE_10_100_L1PLLPD) { + u32 newreg, oldreg = tr32(TG3_PCIE_LNKCTL); + if (tp->link_config.active_speed == SPEED_100 || + tp->link_config.active_speed == SPEED_10) + newreg = oldreg & ~TG3_PCIE_LNKCTL_L1_PLL_PD_EN; + else + newreg = oldreg | TG3_PCIE_LNKCTL_L1_PLL_PD_EN; + if (newreg != oldreg) + tw32(TG3_PCIE_LNKCTL, newreg); } if (current_link_up != netif_carrier_ok(tp->dev)) { @@ -6160,6 +6169,11 @@ static int tg3_chip_reset(struct tg3 *tp) smp_mb(); synchronize_irq(tp->pdev->irq); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) { + val = tr32(TG3_PCIE_LNKCTL) & ~TG3_PCIE_LNKCTL_L1_PLL_PD_EN; + tw32(TG3_PCIE_LNKCTL, val | TG3_PCIE_LNKCTL_L1_PLL_PD_DIS); + } + /* do the reset */ val = GRC_MISC_CFG_CORECLK_RESET; @@ -6726,6 +6740,15 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(TG3_CORR_ERR_STAT, TG3_CORR_ERR_STAT_CLEAR); } + if (tp->tg3_flags3 & TG3_FLG3_TOGGLE_10_100_L1PLLPD) { + val = tr32(TG3_PCIE_LNKCTL); + if (tp->tg3_flags3 & TG3_FLG3_CLKREQ_BUG) + val |= TG3_PCIE_LNKCTL_L1_PLL_PD_DIS; + else + val &= ~TG3_PCIE_LNKCTL_L1_PLL_PD_DIS; + tw32(TG3_PCIE_LNKCTL, val); + } + /* This works around an issue with Athlon chipsets on * B3 tigon3 silicon. This bit has no effect on any * other revision. But do not set this on PCI Express @@ -12274,6 +12297,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) tp->tg3_flags3 |= TG3_FLG3_USE_PHYLIB; + if ((tp->pci_chip_rev_id == CHIPREV_ID_57780_A1 && + tr32(RCVLPC_STATS_ENABLE) & RCVLPC_STATSENAB_ASF_FIX) || + tp->pci_chip_rev_id == CHIPREV_ID_57780_A0) + tp->tg3_flags3 |= TG3_FLG3_TOGGLE_10_100_L1PLLPD; + err = tg3_mdio_init(tp); if (err) return err; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index c613cbb40c2..bb8591ea330 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -866,6 +866,7 @@ #define RCVLPC_STATSCTRL_ENABLE 0x00000001 #define RCVLPC_STATSCTRL_FASTUPD 0x00000002 #define RCVLPC_STATS_ENABLE 0x00002018 +#define RCVLPC_STATSENAB_ASF_FIX 0x00000002 #define RCVLPC_STATSENAB_DACK_FIX 0x00040000 #define RCVLPC_STATSENAB_LNGBRST_RFIX 0x00400000 #define RCVLPC_STATS_INCMASK 0x0000201c @@ -1704,7 +1705,12 @@ #define PCIE_PWR_MGMT_L1_THRESH_MSK 0x0000ff00 #define PCIE_PWR_MGMT_L1_THRESH_4MS 0x0000ff00 #define PCIE_PWR_MGMT_EXT_ASPM_TMR_EN 0x01000000 -/* 0x7d2c --> 0x7e70 unused */ +/* 0x7d2c --> 0x7d54 unused */ + +#define TG3_PCIE_LNKCTL 0x00007d54 +#define TG3_PCIE_LNKCTL_L1_PLL_PD_EN 0x00000008 +#define TG3_PCIE_LNKCTL_L1_PLL_PD_DIS 0x00000080 +/* 0x7d58 --> 0x7e70 unused */ #define TG3_PCIE_EIDLE_DELAY 0x00007e70 #define TG3_PCIE_EIDLE_DELAY_MASK 0x0000001f @@ -2650,6 +2656,7 @@ struct tg3 { #define TG3_FLG3_PHY_ENABLE_APD 0x00001000 #define TG3_FLG3_5755_PLUS 0x00002000 #define TG3_FLG3_NO_NVRAM 0x00004000 +#define TG3_FLG3_TOGGLE_10_100_L1PLLPD 0x00008000 struct timer_list timer; u16 timer_counter; -- cgit v1.2.3-18-g5258 From 29ea095fb727ac48228ff2d1af484c27bf1dcbd4 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:07:54 +0000 Subject: tg3: Fix TSO test against wrong flags var Julia Lawall discovered that the TG3_FLG2_TSO_CAPABLE flag was being compared against the wrong flags device member. This patch implements the fix. Signed-off-by: Julia Lawall Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 595ddf2eb7d..ca3052d5c40 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7192,7 +7192,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { - if ((tp->tg3_flags & TG3_FLG2_TSO_CAPABLE) && + if ((tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) && (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 || tp->pci_chip_rev_id == CHIPREV_ID_5705_A2)) { /* nothing */ -- cgit v1.2.3-18-g5258 From e7126997342560533317d8467e8516119ebcbd21 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:08:16 +0000 Subject: tg3: Preserve PCIe MPS setting for new devs Most older tg3 devices only supported a PCIe maximum payload size of 128 bytes. More recent devices bump this limit up to 256 bytes though. This patch modifies the code so that the MPS limit is only enforced on those devices that only allow the 128 byte setting. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index ca3052d5c40..356b5d0f040 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6226,6 +6226,8 @@ static int tg3_chip_reset(struct tg3 *tp) udelay(120); if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && tp->pcie_cap) { + u16 val16; + if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A0) { int i; u32 cfg_val; @@ -6239,12 +6241,22 @@ static int tg3_chip_reset(struct tg3 *tp) cfg_val | (1 << 15)); } - /* Set PCIE max payload size to 128 bytes and - * clear the "no snoop" and "relaxed ordering" bits. + /* Clear the "no snoop" and "relaxed ordering" bits. */ + pci_read_config_word(tp->pdev, + tp->pcie_cap + PCI_EXP_DEVCTL, + &val16); + val16 &= ~(PCI_EXP_DEVCTL_RELAX_EN | + PCI_EXP_DEVCTL_NOSNOOP_EN); + /* + * Older PCIe devices only support the 128 byte + * MPS setting. Enforce the restriction. */ + if (!(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)) + val16 &= ~PCI_EXP_DEVCTL_PAYLOAD; pci_write_config_word(tp->pdev, tp->pcie_cap + PCI_EXP_DEVCTL, - 0); + val16); pcie_set_readrq(tp->pdev, 4096); -- cgit v1.2.3-18-g5258 From 5e7ccf2003e6a9c35b5aa24953ba5009a1a8b653 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:08:42 +0000 Subject: tg3: Add 57788, remove 57720 This patch adds support for the 57788 and removes support for the 57720 which was never released. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 5 ++++- drivers/net/tg3.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 356b5d0f040..9ae33208358 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -223,7 +223,7 @@ static struct pci_device_id tg3_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57780)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57760)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57790)}, - {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57720)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57788)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)}, {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)}, @@ -11525,6 +11525,9 @@ out_not_found: else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 && tp->pdev->device == TG3PCI_DEVICE_TIGON3_57790) strcpy(tp->board_part_number, "BCM57790"); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 && + tp->pdev->device == TG3PCI_DEVICE_TIGON3_57788) + strcpy(tp->board_part_number, "BCM57788"); else strcpy(tp->board_part_number, "none"); } diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index bb8591ea330..636008cf3c8 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -43,7 +43,7 @@ #define TG3PCI_DEVICE_TIGON3_57780 0x1692 #define TG3PCI_DEVICE_TIGON3_57760 0x1690 #define TG3PCI_DEVICE_TIGON3_57790 0x1694 -#define TG3PCI_DEVICE_TIGON3_57720 0x168c +#define TG3PCI_DEVICE_TIGON3_57788 0x1691 /* 0x04 --> 0x64 unused */ #define TG3PCI_MSI_DATA 0x00000064 /* 0x66 --> 0x68 unused */ -- cgit v1.2.3-18-g5258 From bb85fbb6a98d8edab81599913559c7ff0a963984 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:09:07 +0000 Subject: tg3: Tune 5785 clock switching This patch tunes the timeouts the CPMU uses to decide when to switch from the clocks output by the PHY to internal clock sources. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 15 ++++++++++----- drivers/net/tg3.h | 4 ++++ 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 9ae33208358..41e0d40259e 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -917,7 +917,9 @@ static void tg3_mdio_config_5785(struct tg3 *tp) tw32(MAC_PHYCFG2, val); val = tr32(MAC_PHYCFG1); - val &= ~MAC_PHYCFG1_RGMII_INT; + val &= ~(MAC_PHYCFG1_RGMII_INT | + MAC_PHYCFG1_RXCLK_TO_MASK | MAC_PHYCFG1_TXCLK_TO_MASK); + val |= MAC_PHYCFG1_RXCLK_TIMEOUT | MAC_PHYCFG1_TXCLK_TIMEOUT; tw32(MAC_PHYCFG1, val); return; @@ -933,15 +935,18 @@ static void tg3_mdio_config_5785(struct tg3 *tp) tw32(MAC_PHYCFG2, val); - val = tr32(MAC_PHYCFG1) & ~(MAC_PHYCFG1_RGMII_EXT_RX_DEC | - MAC_PHYCFG1_RGMII_SND_STAT_EN); - if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE) { + val = tr32(MAC_PHYCFG1); + val &= ~(MAC_PHYCFG1_RXCLK_TO_MASK | MAC_PHYCFG1_TXCLK_TO_MASK | + MAC_PHYCFG1_RGMII_EXT_RX_DEC | MAC_PHYCFG1_RGMII_SND_STAT_EN); + if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE)) { if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) val |= MAC_PHYCFG1_RGMII_EXT_RX_DEC; if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN) val |= MAC_PHYCFG1_RGMII_SND_STAT_EN; } - tw32(MAC_PHYCFG1, val | MAC_PHYCFG1_RGMII_INT | MAC_PHYCFG1_TXC_DRV); + val |= MAC_PHYCFG1_RXCLK_TIMEOUT | MAC_PHYCFG1_TXCLK_TIMEOUT | + MAC_PHYCFG1_RGMII_INT | MAC_PHYCFG1_TXC_DRV; + tw32(MAC_PHYCFG1, val); val = tr32(MAC_EXT_RGMII_MODE); val &= ~(MAC_RGMII_MODE_RX_INT_B | diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 636008cf3c8..d096e10ad63 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -524,6 +524,10 @@ /* 0x598 --> 0x5a0 unused */ #define MAC_PHYCFG1 0x000005a0 #define MAC_PHYCFG1_RGMII_INT 0x00000001 +#define MAC_PHYCFG1_RXCLK_TO_MASK 0x00001ff0 +#define MAC_PHYCFG1_RXCLK_TIMEOUT 0x00001000 +#define MAC_PHYCFG1_TXCLK_TO_MASK 0x01ff0000 +#define MAC_PHYCFG1_TXCLK_TIMEOUT 0x01000000 #define MAC_PHYCFG1_RGMII_EXT_RX_DEC 0x02000000 #define MAC_PHYCFG1_RGMII_SND_STAT_EN 0x04000000 #define MAC_PHYCFG1_TXC_DRV 0x20000000 -- cgit v1.2.3-18-g5258 From 535ef6e1124d445efbcc13b7126561dc544b0b64 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:09:36 +0000 Subject: tg3: Create MII_TG3_FET namespace Broadcom's phys come in two distinctly different register layouts. For the lack of an official term to distinguish between the two formats, we can loosely categorize them by their fast ethernet or gigabit ethernet transceiver description. This patch creates the (driver-internal) Fast Ethernet Transceiver (FET) namespace and converts the 5906 EPHY definitions over. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 38 +++++++++++++++++++++----------------- drivers/net/tg3.h | 21 +++++++++++++-------- 2 files changed, 34 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 41e0d40259e..800f98069c1 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1514,17 +1514,19 @@ static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { u32 ephy; - if (!tg3_readphy(tp, MII_TG3_EPHY_TEST, &ephy)) { - tg3_writephy(tp, MII_TG3_EPHY_TEST, - ephy | MII_TG3_EPHY_SHADOW_EN); - if (!tg3_readphy(tp, MII_TG3_EPHYTST_MISCCTRL, &phy)) { + if (!tg3_readphy(tp, MII_TG3_FET_TEST, &ephy)) { + u32 reg = MII_TG3_FET_SHDW_MISCCTRL; + + tg3_writephy(tp, MII_TG3_FET_TEST, + ephy | MII_TG3_FET_SHADOW_EN); + if (!tg3_readphy(tp, reg, &phy)) { if (enable) - phy |= MII_TG3_EPHYTST_MISCCTRL_MDIX; + phy |= MII_TG3_FET_SHDW_MISCCTRL_MDIX; else - phy &= ~MII_TG3_EPHYTST_MISCCTRL_MDIX; - tg3_writephy(tp, MII_TG3_EPHYTST_MISCCTRL, phy); + phy &= ~MII_TG3_FET_SHDW_MISCCTRL_MDIX; + tg3_writephy(tp, reg, phy); } - tg3_writephy(tp, MII_TG3_EPHY_TEST, ephy); + tg3_writephy(tp, MII_TG3_FET_TEST, ephy); } } else { phy = MII_TG3_AUXCTL_MISC_RDSEL_MISC | @@ -1915,7 +1917,7 @@ out: if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { /* adjust output voltage */ - tg3_writephy(tp, MII_TG3_EPHY_PTEST, 0x12); + tg3_writephy(tp, MII_TG3_FET_PTEST, 0x12); } tg3_phy_toggle_automdix(tp, 1); @@ -9747,14 +9749,16 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { u32 phytest; - if (!tg3_readphy(tp, MII_TG3_EPHY_TEST, &phytest)) { - u32 phy; + if (!tg3_readphy(tp, MII_TG3_FET_TEST, &phytest)) { + u32 phy, reg = MII_TG3_FET_SHDW_AUXSTAT2; - tg3_writephy(tp, MII_TG3_EPHY_TEST, - phytest | MII_TG3_EPHY_SHADOW_EN); - if (!tg3_readphy(tp, 0x1b, &phy)) - tg3_writephy(tp, 0x1b, phy & ~0x20); - tg3_writephy(tp, MII_TG3_EPHY_TEST, phytest); + tg3_writephy(tp, MII_TG3_FET_TEST, + phytest | MII_TG3_FET_SHADOW_EN); + if (!tg3_readphy(tp, reg, &phy)) { + phy &= ~MII_TG3_FET_SHDW_AUXSTAT2_APD; + tg3_writephy(tp, reg, phy); + } + tg3_writephy(tp, MII_TG3_FET_TEST, phytest); } val = BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED100; } else @@ -9767,7 +9771,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) mac_mode = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { - tg3_writephy(tp, MII_TG3_EPHY_PTEST, 0x1800); + tg3_writephy(tp, MII_TG3_FET_PTEST, 0x1800); mac_mode |= MAC_MODE_PORT_MODE_MII; } else mac_mode |= MAC_MODE_PORT_MODE_GMII; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index d096e10ad63..b8339c9ae0e 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1909,7 +1909,6 @@ #define MII_TG3_DSP_RW_PORT 0x15 /* DSP coefficient read/write port */ -#define MII_TG3_EPHY_PTEST 0x17 /* 5906 PHY register */ #define MII_TG3_DSP_ADDRESS 0x17 /* DSP address register */ #define MII_TG3_DSP_TAP1 0x0001 @@ -1976,17 +1975,23 @@ #define MII_TG3_MISC_SHDW_SCR5_LPED 0x0010 #define MII_TG3_MISC_SHDW_SCR5_SEL 0x1400 - -#define MII_TG3_EPHY_TEST 0x1f /* 5906 PHY register */ -#define MII_TG3_EPHY_SHADOW_EN 0x80 - -#define MII_TG3_EPHYTST_MISCCTRL 0x10 /* 5906 EPHY misc ctrl shadow register */ -#define MII_TG3_EPHYTST_MISCCTRL_MDIX 0x4000 - #define MII_TG3_TEST1 0x1e #define MII_TG3_TEST1_TRIM_EN 0x0010 #define MII_TG3_TEST1_CRC_EN 0x8000 + +/* Fast Ethernet Tranceiver definitions */ +#define MII_TG3_FET_PTEST 0x17 +#define MII_TG3_FET_TEST 0x1f +#define MII_TG3_FET_SHADOW_EN 0x0080 + +#define MII_TG3_FET_SHDW_MISCCTRL 0x10 +#define MII_TG3_FET_SHDW_MISCCTRL_MDIX 0x4000 + +#define MII_TG3_FET_SHDW_AUXSTAT2 0x1b +#define MII_TG3_FET_SHDW_AUXSTAT2_APD 0x0020 + + /* APE registers. Accessible through BAR1 */ #define TG3_APE_EVENT 0x000c #define APE_EVENT_1 0x00000001 -- cgit v1.2.3-18-g5258 From 7f97a4bd47291e4ec9b9eaf63d7275ddfb498cb3 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:10:03 +0000 Subject: tg3: Convert code to use PHY_IS_FET This patch converts the code to use the PHY_IS_FET flag rather than the ASIC revision to decide whether or not to use FET paths. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 73 +++++++++++++++++++++++++++++++++++-------------------- drivers/net/tg3.h | 1 + 2 files changed, 47 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 800f98069c1..2808152e869 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -784,7 +784,7 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val) unsigned int loops; int ret; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 && + if ((tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) && (reg == MII_TG3_CTRL || reg == MII_TG3_AUX_CTRL)) return 0; @@ -1069,6 +1069,7 @@ static int tg3_mdio_init(struct tg3 *tp) case TG3_PHY_ID_RTL8201E: case TG3_PHY_ID_BCMAC131: phydev->interface = PHY_INTERFACE_MODE_MII; + tp->tg3_flags3 |= TG3_FLG3_PHY_IS_FET; break; } @@ -1474,13 +1475,37 @@ static void tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val) tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val); } +static void tg3_phy_fet_toggle_apd(struct tg3 *tp, bool enable) +{ + u32 phytest; + + if (!tg3_readphy(tp, MII_TG3_FET_TEST, &phytest)) { + u32 phy; + + tg3_writephy(tp, MII_TG3_FET_TEST, + phytest | MII_TG3_FET_SHADOW_EN); + if (!tg3_readphy(tp, MII_TG3_FET_SHDW_AUXSTAT2, &phy)) { + if (enable) + phy |= MII_TG3_FET_SHDW_AUXSTAT2_APD; + else + phy &= ~MII_TG3_FET_SHDW_AUXSTAT2_APD; + tg3_writephy(tp, MII_TG3_FET_SHDW_AUXSTAT2, phy); + } + tg3_writephy(tp, MII_TG3_FET_TEST, phytest); + } +} + static void tg3_phy_toggle_apd(struct tg3 *tp, bool enable) { u32 reg; - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + return; + + if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) { + tg3_phy_fet_toggle_apd(tp, enable); return; + } reg = MII_TG3_MISC_SHDW_WREN | MII_TG3_MISC_SHDW_SCR5_SEL | @@ -1511,7 +1536,7 @@ static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable) (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) return; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { + if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) { u32 ephy; if (!tg3_readphy(tp, MII_TG3_FET_TEST, &ephy)) { @@ -2662,7 +2687,7 @@ static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8 break; default: - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { + if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) { *speed = (val & MII_TG3_AUX_STAT_100) ? SPEED_100 : SPEED_10; *duplex = (val & MII_TG3_AUX_STAT_FULL) ? DUPLEX_FULL : @@ -2997,7 +3022,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) if (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) tg3_writephy(tp, MII_TG3_IMASK, ~MII_TG3_INT_LINKCHG); - else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) + else if (!(tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET)) tg3_writephy(tp, MII_TG3_IMASK, ~0); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || @@ -3107,7 +3132,9 @@ relink: tp->mac_mode |= MAC_MODE_PORT_MODE_MII; else tp->mac_mode |= MAC_MODE_PORT_MODE_GMII; - } else + } else if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) + tp->mac_mode |= MAC_MODE_PORT_MODE_MII; + else tp->mac_mode |= MAC_MODE_PORT_MODE_GMII; tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX; @@ -7349,7 +7376,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) return err; if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) { + !(tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET)) { u32 tmp; /* Clear CRC stats. */ @@ -9746,20 +9773,8 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) } else if (loopback_mode == TG3_PHY_LOOPBACK) { u32 val; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { - u32 phytest; - - if (!tg3_readphy(tp, MII_TG3_FET_TEST, &phytest)) { - u32 phy, reg = MII_TG3_FET_SHDW_AUXSTAT2; - - tg3_writephy(tp, MII_TG3_FET_TEST, - phytest | MII_TG3_FET_SHADOW_EN); - if (!tg3_readphy(tp, reg, &phy)) { - phy &= ~MII_TG3_FET_SHDW_AUXSTAT2_APD; - tg3_writephy(tp, reg, phy); - } - tg3_writephy(tp, MII_TG3_FET_TEST, phytest); - } + if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) { + tg3_phy_fet_toggle_apd(tp, false); val = BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED100; } else val = BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED1000; @@ -9770,8 +9785,9 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) udelay(40); mac_mode = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { - tg3_writephy(tp, MII_TG3_FET_PTEST, 0x1800); + if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) + tg3_writephy(tp, MII_TG3_FET_PTEST, 0x1800); mac_mode |= MAC_MODE_PORT_MODE_MII; } else mac_mode |= MAC_MODE_PORT_MODE_GMII; @@ -12268,12 +12284,15 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags |= TG3_FLAG_WOL_SPEED_100MB; } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) + tp->tg3_flags3 |= TG3_FLG3_PHY_IS_FET; + /* A few boards don't want Ethernet@WireSpeed phy feature */ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) || ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) && (tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) && (tp->pci_chip_rev_id != CHIPREV_ID_5705_A1)) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) || + (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) || (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) tp->tg3_flags2 |= TG3_FLG2_NO_ETH_WIRE_SPEED; @@ -12284,7 +12303,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_PHY_5704_A0_BUG; if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906 && + !(tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || @@ -12409,7 +12428,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F || tp->pdev->device == PCI_DEVICE_ID_TIGON3_5787F)) || tp->pdev->device == TG3PCI_DEVICE_TIGON3_57790 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) + (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET)) tp->tg3_flags |= TG3_FLAG_10_100_ONLY; err = tg3_phy_probe(tp); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index b8339c9ae0e..60b12ab7933 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2666,6 +2666,7 @@ struct tg3 { #define TG3_FLG3_5755_PLUS 0x00002000 #define TG3_FLG3_NO_NVRAM 0x00004000 #define TG3_FLG3_TOGGLE_10_100_L1PLLPD 0x00008000 +#define TG3_FLG3_PHY_IS_FET 0x00010000 struct timer_list timer; u16 timer_counter; -- cgit v1.2.3-18-g5258 From 4f4598fd0a87f39955e71bcb7447f403dafc20ba Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:10:30 +0000 Subject: broadcom: Add BCM50610M support This patch adds support for the BCM50610M phy ID. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/phy/broadcom.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 190efc3301c..dec4dec23b6 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -18,6 +18,7 @@ #include #define PHY_ID_BCM50610 0x0143bd60 +#define PHY_ID_BCM50610M 0x0143bd70 #define MII_BCM54XX_ECR 0x10 /* BCM54xx extended control register */ #define MII_BCM54XX_ECR_IM 0x1000 /* Interrupt mask */ @@ -447,7 +448,7 @@ static struct phy_driver bcm5411_driver = { .read_status = genphy_read_status, .ack_interrupt = bcm54xx_ack_interrupt, .config_intr = bcm54xx_config_intr, - .driver = { .owner = THIS_MODULE }, + .driver = { .owner = THIS_MODULE }, }; static struct phy_driver bcm5421_driver = { @@ -462,7 +463,7 @@ static struct phy_driver bcm5421_driver = { .read_status = genphy_read_status, .ack_interrupt = bcm54xx_ack_interrupt, .config_intr = bcm54xx_config_intr, - .driver = { .owner = THIS_MODULE }, + .driver = { .owner = THIS_MODULE }, }; static struct phy_driver bcm5461_driver = { @@ -477,7 +478,7 @@ static struct phy_driver bcm5461_driver = { .read_status = genphy_read_status, .ack_interrupt = bcm54xx_ack_interrupt, .config_intr = bcm54xx_config_intr, - .driver = { .owner = THIS_MODULE }, + .driver = { .owner = THIS_MODULE }, }; static struct phy_driver bcm5464_driver = { @@ -492,7 +493,7 @@ static struct phy_driver bcm5464_driver = { .read_status = genphy_read_status, .ack_interrupt = bcm54xx_ack_interrupt, .config_intr = bcm54xx_config_intr, - .driver = { .owner = THIS_MODULE }, + .driver = { .owner = THIS_MODULE }, }; static struct phy_driver bcm5481_driver = { @@ -507,7 +508,7 @@ static struct phy_driver bcm5481_driver = { .read_status = genphy_read_status, .ack_interrupt = bcm54xx_ack_interrupt, .config_intr = bcm54xx_config_intr, - .driver = { .owner = THIS_MODULE }, + .driver = { .owner = THIS_MODULE }, }; static struct phy_driver bcm5482_driver = { @@ -522,7 +523,7 @@ static struct phy_driver bcm5482_driver = { .read_status = bcm5482_read_status, .ack_interrupt = bcm54xx_ack_interrupt, .config_intr = bcm54xx_config_intr, - .driver = { .owner = THIS_MODULE }, + .driver = { .owner = THIS_MODULE }, }; static struct phy_driver bcm50610_driver = { @@ -537,7 +538,22 @@ static struct phy_driver bcm50610_driver = { .read_status = genphy_read_status, .ack_interrupt = bcm54xx_ack_interrupt, .config_intr = bcm54xx_config_intr, - .driver = { .owner = THIS_MODULE }, + .driver = { .owner = THIS_MODULE }, +}; + +static struct phy_driver bcm50610m_driver = { + .phy_id = PHY_ID_BCM50610M, + .phy_id_mask = 0xfffffff0, + .name = "Broadcom BCM50610M", + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .config_init = bcm54xx_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = bcm54xx_ack_interrupt, + .config_intr = bcm54xx_config_intr, + .driver = { .owner = THIS_MODULE }, }; static struct phy_driver bcm57780_driver = { @@ -552,7 +568,7 @@ static struct phy_driver bcm57780_driver = { .read_status = genphy_read_status, .ack_interrupt = bcm54xx_ack_interrupt, .config_intr = bcm54xx_config_intr, - .driver = { .owner = THIS_MODULE }, + .driver = { .owner = THIS_MODULE }, }; static int __init broadcom_init(void) @@ -580,12 +596,17 @@ static int __init broadcom_init(void) ret = phy_driver_register(&bcm50610_driver); if (ret) goto out_50610; + ret = phy_driver_register(&bcm50610m_driver); + if (ret) + goto out_50610m; ret = phy_driver_register(&bcm57780_driver); if (ret) goto out_57780; return ret; out_57780: + phy_driver_unregister(&bcm50610m_driver); +out_50610m: phy_driver_unregister(&bcm50610_driver); out_50610: phy_driver_unregister(&bcm5482_driver); @@ -606,6 +627,7 @@ out_5411: static void __exit broadcom_exit(void) { phy_driver_unregister(&bcm57780_driver); + phy_driver_unregister(&bcm50610m_driver); phy_driver_unregister(&bcm50610_driver); phy_driver_unregister(&bcm5482_driver); phy_driver_unregister(&bcm5481_driver); -- cgit v1.2.3-18-g5258 From d7a2ed9248a3c3ec6afe3be0c351bd1ca9e981f3 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:10:58 +0000 Subject: broadcom: Add AC131 phy support This patch adds support for the AC131 fast ethernet transceiver. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/phy/broadcom.c | 158 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) (limited to 'drivers') diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index dec4dec23b6..3262a2474b0 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -142,6 +142,35 @@ #define PHY_BCM_FLAGS_MODE_1000BX 0x00000002 #define PHY_BCM_FLAGS_MODE_COPPER 0x00000001 + +/*****************************************************************************/ +/* Fast Ethernet Transceiver definitions. */ +/*****************************************************************************/ + +#define MII_BRCM_FET_INTREG 0x1a /* Interrupt register */ +#define MII_BRCM_FET_IR_MASK 0x0100 /* Mask all interrupts */ +#define MII_BRCM_FET_IR_LINK_EN 0x0200 /* Link status change enable */ +#define MII_BRCM_FET_IR_SPEED_EN 0x0400 /* Link speed change enable */ +#define MII_BRCM_FET_IR_DUPLEX_EN 0x0800 /* Duplex mode change enable */ +#define MII_BRCM_FET_IR_ENABLE 0x4000 /* Interrupt enable */ + +#define MII_BRCM_FET_BRCMTEST 0x1f /* Brcm test register */ +#define MII_BRCM_FET_BT_SRE 0x0080 /* Shadow register enable */ + + +/*** Shadow register definitions ***/ + +#define MII_BRCM_FET_SHDW_MISCCTRL 0x10 /* Shadow misc ctrl */ +#define MII_BRCM_FET_SHDW_MC_FAME 0x4000 /* Force Auto MDIX enable */ + +#define MII_BRCM_FET_SHDW_AUXMODE4 0x1a /* Auxiliary mode 4 */ +#define MII_BRCM_FET_SHDW_AM4_LED_MASK 0x0003 +#define MII_BRCM_FET_SHDW_AM4_LED_MODE1 0x0001 + +#define MII_BRCM_FET_SHDW_AUXSTAT2 0x1b /* Auxiliary status 2 */ +#define MII_BRCM_FET_SHDW_AS2_APDE 0x0020 /* Auto power down enable */ + + MODULE_DESCRIPTION("Broadcom PHY driver"); MODULE_AUTHOR("Maciej W. Rozycki"); MODULE_LICENSE("GPL"); @@ -436,6 +465,114 @@ static int bcm5481_config_aneg(struct phy_device *phydev) return ret; } +static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set) +{ + int val; + + val = phy_read(phydev, reg); + if (val < 0) + return val; + + return phy_write(phydev, reg, val | set); +} + +static int brcm_fet_config_init(struct phy_device *phydev) +{ + int reg, err, err2, brcmtest; + + /* Reset the PHY to bring it to a known state. */ + err = phy_write(phydev, MII_BMCR, BMCR_RESET); + if (err < 0) + return err; + + reg = phy_read(phydev, MII_BRCM_FET_INTREG); + if (reg < 0) + return reg; + + /* Unmask events we are interested in and mask interrupts globally. */ + reg = MII_BRCM_FET_IR_DUPLEX_EN | + MII_BRCM_FET_IR_SPEED_EN | + MII_BRCM_FET_IR_LINK_EN | + MII_BRCM_FET_IR_ENABLE | + MII_BRCM_FET_IR_MASK; + + err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); + if (err < 0) + return err; + + /* Enable shadow register access */ + brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST); + if (brcmtest < 0) + return brcmtest; + + reg = brcmtest | MII_BRCM_FET_BT_SRE; + + err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg); + if (err < 0) + return err; + + /* Set the LED mode */ + reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4); + if (reg < 0) { + err = reg; + goto done; + } + + reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK; + reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1; + + err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg); + if (err < 0) + goto done; + + /* Enable auto MDIX */ + err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL, + MII_BRCM_FET_SHDW_MC_FAME); + if (err < 0) + goto done; + + /* Enable auto power down */ + err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2, + MII_BRCM_FET_SHDW_AS2_APDE); + +done: + /* Disable shadow register access */ + err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest); + if (!err) + err = err2; + + return err; +} + +static int brcm_fet_ack_interrupt(struct phy_device *phydev) +{ + int reg; + + /* Clear pending interrupts. */ + reg = phy_read(phydev, MII_BRCM_FET_INTREG); + if (reg < 0) + return reg; + + return 0; +} + +static int brcm_fet_config_intr(struct phy_device *phydev) +{ + int reg, err; + + reg = phy_read(phydev, MII_BRCM_FET_INTREG); + if (reg < 0) + return reg; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + reg &= ~MII_BRCM_FET_IR_MASK; + else + reg |= MII_BRCM_FET_IR_MASK; + + err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); + return err; +} + static struct phy_driver bcm5411_driver = { .phy_id = 0x00206070, .phy_id_mask = 0xfffffff0, @@ -571,6 +708,21 @@ static struct phy_driver bcm57780_driver = { .driver = { .owner = THIS_MODULE }, }; +static struct phy_driver bcmac131_driver = { + .phy_id = 0x0143bc70, + .phy_id_mask = 0xfffffff0, + .name = "Broadcom BCMAC131", + .features = PHY_BASIC_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .config_init = brcm_fet_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = brcm_fet_ack_interrupt, + .config_intr = brcm_fet_config_intr, + .driver = { .owner = THIS_MODULE }, +}; + static int __init broadcom_init(void) { int ret; @@ -602,8 +754,13 @@ static int __init broadcom_init(void) ret = phy_driver_register(&bcm57780_driver); if (ret) goto out_57780; + ret = phy_driver_register(&bcmac131_driver); + if (ret) + goto out_ac131; return ret; +out_ac131: + phy_driver_unregister(&bcm57780_driver); out_57780: phy_driver_unregister(&bcm50610m_driver); out_50610m: @@ -626,6 +783,7 @@ out_5411: static void __exit broadcom_exit(void) { + phy_driver_unregister(&bcmac131_driver); phy_driver_unregister(&bcm57780_driver); phy_driver_unregister(&bcm50610m_driver); phy_driver_unregister(&bcm50610_driver); -- cgit v1.2.3-18-g5258 From d9221e66002a7f24fb71b73132aa46c40079745f Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:11:26 +0000 Subject: broadcom: Make the 57780 IEEE compliant This brings the 57780's phy into IEEE compliance by suppressing the common mode oscillation. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/phy/broadcom.c | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 3262a2474b0..f81e5322223 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -19,6 +19,11 @@ #define PHY_ID_BCM50610 0x0143bd60 #define PHY_ID_BCM50610M 0x0143bd70 +#define PHY_ID_BCM57780 0x03625d90 + +#define BRCM_PHY_MODEL(phydev) \ + ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask) + #define MII_BCM54XX_ECR 0x10 /* BCM54xx extended control register */ #define MII_BCM54XX_ECR_IM 0x1000 /* Interrupt mask */ @@ -118,6 +123,7 @@ #define MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE 0x0200 #define MII_BCM54XX_EXP_EXP75 0x0f75 #define MII_BCM54XX_EXP_EXP75_VDACCTRL 0x003c +#define MII_BCM54XX_EXP_EXP75_CM_OSC 0x0001 #define MII_BCM54XX_EXP_EXP96 0x0f96 #define MII_BCM54XX_EXP_EXP96_MYST 0x0010 #define MII_BCM54XX_EXP_EXP97 0x0f97 @@ -194,7 +200,7 @@ static int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow, u16 val) } /* Indirect register access functions for the Expansion Registers */ -static int bcm54xx_exp_read(struct phy_device *phydev, u8 regnum) +static int bcm54xx_exp_read(struct phy_device *phydev, u16 regnum) { int val; @@ -308,6 +314,33 @@ static int bcm54xx_config_init(struct phy_device *phydev) return err; } + if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) { + int err2; + + err = bcm54xx_auxctl_write(phydev, + MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, + MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA | + MII_BCM54XX_AUXCTL_ACTL_TX_6DB); + if (err < 0) + return err; + + reg = bcm54xx_exp_read(phydev, MII_BCM54XX_EXP_EXP75); + if (reg < 0) + goto error; + + reg |= MII_BCM54XX_EXP_EXP75_CM_OSC; + err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, reg); + +error: + err2 = bcm54xx_auxctl_write(phydev, + MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, + MII_BCM54XX_AUXCTL_ACTL_TX_6DB); + if (err) + return err; + if (err2) + return err2; + } + return 0; } @@ -694,7 +727,7 @@ static struct phy_driver bcm50610m_driver = { }; static struct phy_driver bcm57780_driver = { - .phy_id = 0x03625d90, + .phy_id = PHY_ID_BCM57780, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM57780", .features = PHY_GBIT_FEATURES | -- cgit v1.2.3-18-g5258 From f656f39801b00c3c2aa26cefbdee2775d6706d45 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 25 Aug 2009 10:11:55 +0000 Subject: tg3: Update version to 3.100 This patch updates the tg3 version to 3.100. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 2808152e869..8af2cdf181d 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -68,8 +68,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.99" -#define DRV_MODULE_RELDATE "April 20, 2009" +#define DRV_MODULE_VERSION "3.100" +#define DRV_MODULE_RELDATE "August 25, 2009" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v1.2.3-18-g5258 From 58490f18071de525f42b6ed264a87116ec49ef0f Mon Sep 17 00:00:00 2001 From: Klaus-Dieter Wacker Date: Wed, 26 Aug 2009 02:01:06 +0000 Subject: qeth: HiperSockets SIGA retry support on CC=2. Qeth HiperSockets support now retries sending of packets when the IBM System z signals a temporary resource shortage (e.g. target buffer full). The packet is enqueued into the device queue. After 3 times of unsuccessful send the packet is dropped. Signed-off-by: Klaus-Dieter Wacker Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 9 ++++++ drivers/s390/net/qeth_core_main.c | 60 +++++++++++++++++++++++++++++++++------ 2 files changed, 61 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 447e1d19581..03161e650b2 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -435,6 +435,7 @@ struct qeth_qdio_out_q { * index of buffer to be filled by driver; state EMPTY or PACKING */ int next_buf_to_fill; + int sync_iqdio_error; /* * number of buffers that are currently filled (PRIMED) * -> these buffers are hardware-owned @@ -685,6 +686,14 @@ struct qeth_mc_mac { int is_vmac; }; +struct qeth_skb_data { + __u32 magic; + int count; +}; + +#define QETH_SKB_MAGIC 0x71657468 +#define QETH_SIGA_CC2_RETRIES 3 + struct qeth_card { struct list_head list; enum qeth_card_states state; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index d53621c4acb..ac7270d2170 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -927,8 +927,8 @@ out: return; } -static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, - struct qeth_qdio_out_buffer *buf) +static void __qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, + struct qeth_qdio_out_buffer *buf, unsigned int qeth_skip_skb) { int i; struct sk_buff *skb; @@ -937,11 +937,13 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, if (buf->buffer->element[0].flags & 0x40) atomic_dec(&queue->set_pci_flags_count); - skb = skb_dequeue(&buf->skb_list); - while (skb) { - atomic_dec(&skb->users); - dev_kfree_skb_any(skb); + if (!qeth_skip_skb) { skb = skb_dequeue(&buf->skb_list); + while (skb) { + atomic_dec(&skb->users); + dev_kfree_skb_any(skb); + skb = skb_dequeue(&buf->skb_list); + } } for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(queue->card); ++i) { if (buf->buffer->element[i].addr && buf->is_header[i]) @@ -957,6 +959,12 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY); } +static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, + struct qeth_qdio_out_buffer *buf) +{ + __qeth_clear_output_buffer(queue, buf, 0); +} + void qeth_clear_qdio_buffers(struct qeth_card *card) { int i, j; @@ -2685,6 +2693,13 @@ static int qeth_handle_send_error(struct qeth_card *card, int sbalf15 = buffer->buffer->element[15].flags & 0xff; QETH_DBF_TEXT(TRACE, 6, "hdsnderr"); + if (card->info.type == QETH_CARD_TYPE_IQD) { + if (sbalf15 == 0) { + qdio_err = 0; + } else { + qdio_err = 1; + } + } qeth_check_qdio_errors(buffer->buffer, qdio_err, "qouterr"); if (!qdio_err) @@ -2817,6 +2832,7 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, } } + queue->sync_iqdio_error = 0; queue->card->dev->trans_start = jiffies; if (queue->card->options.performance_stats) { queue->card->perf_stats.outbound_do_qdio_cnt++; @@ -2832,6 +2848,10 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, queue->card->perf_stats.outbound_do_qdio_time += qeth_get_micros() - queue->card->perf_stats.outbound_do_qdio_start_time; + if (rc > 0) { + if (!(rc & QDIO_ERROR_SIGA_BUSY)) + queue->sync_iqdio_error = rc & 3; + } if (rc) { queue->card->stats.tx_errors += count; /* ignore temporary SIGA errors without busy condition */ @@ -2899,6 +2919,7 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev, struct qeth_qdio_out_q *queue = card->qdio.out_qs[__queue]; struct qeth_qdio_out_buffer *buffer; int i; + unsigned qeth_send_err; QETH_DBF_TEXT(TRACE, 6, "qdouhdl"); if (qdio_error & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) { @@ -2915,8 +2936,9 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev, } for (i = first_element; i < (first_element + count); ++i) { buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q]; - qeth_handle_send_error(card, buffer, qdio_error); - qeth_clear_output_buffer(queue, buffer); + qeth_send_err = qeth_handle_send_error(card, buffer, qdio_error); + __qeth_clear_output_buffer(queue, buffer, + (qeth_send_err == QETH_SEND_ERROR_RETRY) ? 1 : 0); } atomic_sub(count, &queue->used_buffers); /* check if we need to do something on this outbound queue */ @@ -3159,7 +3181,10 @@ int qeth_do_send_packet_fast(struct qeth_card *card, int offset, int hd_len) { struct qeth_qdio_out_buffer *buffer; + struct sk_buff *skb1; + struct qeth_skb_data *retry_ctrl; int index; + int rc; /* spin until we get the queue ... */ while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED, @@ -3178,6 +3203,25 @@ int qeth_do_send_packet_fast(struct qeth_card *card, atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len); qeth_flush_buffers(queue, index, 1); + if (queue->sync_iqdio_error == 2) { + skb1 = skb_dequeue(&buffer->skb_list); + while (skb1) { + atomic_dec(&skb1->users); + skb1 = skb_dequeue(&buffer->skb_list); + } + retry_ctrl = (struct qeth_skb_data *) &skb->cb[16]; + if (retry_ctrl->magic != QETH_SKB_MAGIC) { + retry_ctrl->magic = QETH_SKB_MAGIC; + retry_ctrl->count = 0; + } + if (retry_ctrl->count < QETH_SIGA_CC2_RETRIES) { + retry_ctrl->count++; + rc = dev_queue_xmit(skb); + } else { + dev_kfree_skb_any(skb); + QETH_DBF_TEXT(QERR, 2, "qrdrop"); + } + } return 0; out: atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); -- cgit v1.2.3-18-g5258 From e806904057253e4f7651a8594456e68857c24e1b Mon Sep 17 00:00:00 2001 From: Frank Blaschka Date: Wed, 26 Aug 2009 02:01:07 +0000 Subject: qeth: scheduling while atomic during ifconfig online sequence In case the IP address list contains entries (not removed when the device was set offline) this entries should be registered next time the device is brought online. In the past this was done implicitly with the device open call but since we wait in the set IPv4 IPA and the device open common code holds various locks this does not work any longer. Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 048defaea81..77e04b7fad1 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -3180,6 +3180,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) netif_carrier_on(card->dev); qeth_set_allowed_threads(card, 0xffffffff, 0); + qeth_l3_set_ip_addr_list(card); if (recover_flag == CARD_STATE_RECOVER) { if (recovery_mode) qeth_l3_open(card->dev); -- cgit v1.2.3-18-g5258 From ce73e10ee0cb6cde1c5075a2803da0f0eb5b2324 Mon Sep 17 00:00:00 2001 From: Klaus-Dieter Wacker Date: Wed, 26 Aug 2009 02:01:08 +0000 Subject: qeth: Cleanup for cast-type determination. Clear separation of cast-type determination (send path) for layer-2 resp. layer-3. Allowing to have inline functions for qeth layer- discipline. Signed-off-by: Klaus-Dieter Wacker Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 1 - drivers/s390/net/qeth_core_main.c | 49 --------------------------------------- drivers/s390/net/qeth_l2_main.c | 42 +++++++++------------------------ drivers/s390/net/qeth_l3_main.c | 47 ++++++++++++++++++++++++++++++++++++- 4 files changed, 57 insertions(+), 82 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 03161e650b2..31a2b4e502c 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -843,7 +843,6 @@ int qeth_default_setadapterparms_cb(struct qeth_card *, struct qeth_reply *, int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *, int (*reply_cb)(struct qeth_card *, struct qeth_reply*, unsigned long), void *reply_param); -int qeth_get_cast_type(struct qeth_card *, struct sk_buff *); int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int); int qeth_get_elements_no(struct qeth_card *, void *, struct sk_buff *, int); int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *, diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index ac7270d2170..1560bb621a3 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -2952,55 +2952,6 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev, } EXPORT_SYMBOL_GPL(qeth_qdio_output_handler); -int qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb) -{ - int cast_type = RTN_UNSPEC; - - if (card->info.type == QETH_CARD_TYPE_OSN) - return cast_type; - - if (skb_dst(skb) && skb_dst(skb)->neighbour) { - cast_type = skb_dst(skb)->neighbour->type; - if ((cast_type == RTN_BROADCAST) || - (cast_type == RTN_MULTICAST) || - (cast_type == RTN_ANYCAST)) - return cast_type; - else - return RTN_UNSPEC; - } - /* try something else */ - if (skb->protocol == ETH_P_IPV6) - return (skb_network_header(skb)[24] == 0xff) ? - RTN_MULTICAST : 0; - else if (skb->protocol == ETH_P_IP) - return ((skb_network_header(skb)[16] & 0xf0) == 0xe0) ? - RTN_MULTICAST : 0; - /* ... */ - if (!memcmp(skb->data, skb->dev->broadcast, 6)) - return RTN_BROADCAST; - else { - u16 hdr_mac; - - hdr_mac = *((u16 *)skb->data); - /* tr multicast? */ - switch (card->info.link_type) { - case QETH_LINK_TYPE_HSTR: - case QETH_LINK_TYPE_LANE_TR: - if ((hdr_mac == QETH_TR_MAC_NC) || - (hdr_mac == QETH_TR_MAC_C)) - return RTN_MULTICAST; - break; - /* eth or so multicast? */ - default: - if ((hdr_mac == QETH_ETH_MAC_V4) || - (hdr_mac == QETH_ETH_MAC_V6)) - return RTN_MULTICAST; - } - } - return cast_type; -} -EXPORT_SYMBOL_GPL(qeth_get_cast_type); - int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb, int ipv, int cast_type) { diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 2cfc338c462..12ee7a35ca5 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -216,36 +216,16 @@ static void qeth_l2_del_all_mc(struct qeth_card *card) spin_unlock_bh(&card->mclock); } -static void qeth_l2_get_packet_type(struct qeth_card *card, - struct qeth_hdr *hdr, struct sk_buff *skb) +static inline int qeth_l2_get_cast_type(struct qeth_card *card, + struct sk_buff *skb) { - __u16 hdr_mac; - - if (!memcmp(skb->data + QETH_HEADER_SIZE, - skb->dev->broadcast, 6)) { - /* broadcast? */ - hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_BROADCAST; - return; - } - hdr_mac = *((__u16 *)skb->data); - /* tr multicast? */ - switch (card->info.link_type) { - case QETH_LINK_TYPE_HSTR: - case QETH_LINK_TYPE_LANE_TR: - if ((hdr_mac == QETH_TR_MAC_NC) || - (hdr_mac == QETH_TR_MAC_C)) - hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_MULTICAST; - else - hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_UNICAST; - break; - /* eth or so multicast? */ - default: - if ((hdr_mac == QETH_ETH_MAC_V4) || - (hdr_mac == QETH_ETH_MAC_V6)) - hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_MULTICAST; - else - hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_UNICAST; - } + if (card->info.type == QETH_CARD_TYPE_OSN) + return RTN_UNSPEC; + if (is_broadcast_ether_addr(skb->data)) + return RTN_BROADCAST; + if (is_multicast_ether_addr(skb->data)) + return RTN_MULTICAST; + return RTN_UNSPEC; } static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, @@ -262,7 +242,7 @@ static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, else if (cast_type == RTN_BROADCAST) hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_BROADCAST; else - qeth_l2_get_packet_type(card, hdr, skb); + hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_UNICAST; hdr->hdr.l2.pkt_length = skb->len-QETH_HEADER_SIZE; /* VSWITCH relies on the VLAN @@ -672,7 +652,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) struct qeth_card *card = dev->ml_priv; struct sk_buff *new_skb = skb; int ipv = qeth_get_ip_version(skb); - int cast_type = qeth_get_cast_type(card, skb); + int cast_type = qeth_l2_get_cast_type(card, skb); struct qeth_qdio_out_q *queue = card->qdio.out_qs [qeth_get_priority_queue(card, skb, ipv, cast_type)]; int tx_bytes = skb->len; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 77e04b7fad1..d9fabe30c0d 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2525,6 +2525,51 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return rc; } +int inline qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb) +{ + int cast_type = RTN_UNSPEC; + + if (skb_dst(skb) && skb_dst(skb)->neighbour) { + cast_type = skb_dst(skb)->neighbour->type; + if ((cast_type == RTN_BROADCAST) || + (cast_type == RTN_MULTICAST) || + (cast_type == RTN_ANYCAST)) + return cast_type; + else + return RTN_UNSPEC; + } + /* try something else */ + if (skb->protocol == ETH_P_IPV6) + return (skb_network_header(skb)[24] == 0xff) ? + RTN_MULTICAST : 0; + else if (skb->protocol == ETH_P_IP) + return ((skb_network_header(skb)[16] & 0xf0) == 0xe0) ? + RTN_MULTICAST : 0; + /* ... */ + if (!memcmp(skb->data, skb->dev->broadcast, 6)) + return RTN_BROADCAST; + else { + u16 hdr_mac; + + hdr_mac = *((u16 *)skb->data); + /* tr multicast? */ + switch (card->info.link_type) { + case QETH_LINK_TYPE_HSTR: + case QETH_LINK_TYPE_LANE_TR: + if ((hdr_mac == QETH_TR_MAC_NC) || + (hdr_mac == QETH_TR_MAC_C)) + return RTN_MULTICAST; + break; + /* eth or so multicast? */ + default: + if ((hdr_mac == QETH_ETH_MAC_V4) || + (hdr_mac == QETH_ETH_MAC_V6)) + return RTN_MULTICAST; + } + } + return cast_type; +} + static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, struct sk_buff *skb, int ipv, int cast_type) { @@ -2650,7 +2695,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) struct qeth_card *card = dev->ml_priv; struct sk_buff *new_skb = NULL; int ipv = qeth_get_ip_version(skb); - int cast_type = qeth_get_cast_type(card, skb); + int cast_type = qeth_l3_get_cast_type(card, skb); struct qeth_qdio_out_q *queue = card->qdio.out_qs [qeth_get_priority_queue(card, skb, ipv, cast_type)]; int tx_bytes = skb->len; -- cgit v1.2.3-18-g5258 From 0d788c7d285a91ef72a7b436dbe753d117856b3d Mon Sep 17 00:00:00 2001 From: Klaus-Dieter Wacker Date: Wed, 26 Aug 2009 02:01:09 +0000 Subject: qeth: display service_level info only when valid. qeth displayed an entry in /proc/service_level even when no valid MCL-string was available (the MCL info is blank). The change is to create an entry in /proc/service_level only when MCL-string is non-zero. Signed-off-by: Klaus-Dieter Wacker Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 1560bb621a3..c4a42d97015 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1160,8 +1160,9 @@ static void qeth_core_sl_print(struct seq_file *m, struct service_level *slr) { struct qeth_card *card = container_of(slr, struct qeth_card, qeth_service_level); - seq_printf(m, "qeth: %s firmware level %s\n", CARD_BUS_ID(card), - card->info.mcl_level); + if (card->info.mcl_level[0]) + seq_printf(m, "qeth: %s firmware level %s\n", + CARD_BUS_ID(card), card->info.mcl_level); } static struct qeth_card *qeth_alloc_card(void) -- cgit v1.2.3-18-g5258 From 7c6a3ed5bd61ec981c8a0d0111cfd435adf3f2b7 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Wed, 26 Aug 2009 02:01:10 +0000 Subject: qeth: display "undefined" value of sysfs-attribute "layer2" If nothing has been written into the qeth sysfs-attribute layer2, its value is "-1" meaning "not yet defined". But the value is displayed as "1" meaning "layer2 selected". The patch changes the reading of this "-1"-value to "-1" to make clear the layer2-attribute has not yet been defined. Signed-off-by: Ursula Braun Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_sys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index 568465d7517..33505c2a0e3 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -364,7 +364,7 @@ static ssize_t qeth_dev_layer2_show(struct device *dev, if (!card) return -EINVAL; - return sprintf(buf, "%i\n", card->options.layer2 ? 1:0); + return sprintf(buf, "%i\n", card->options.layer2); } static ssize_t qeth_dev_layer2_store(struct device *dev, -- cgit v1.2.3-18-g5258 From aed0628dae0c26b47d40d65f942abe30279b52a5 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 26 Aug 2009 08:16:27 +0000 Subject: sfc: Fix ordering of device registration and initial netif_carrier_off() We must call netif_carrier_off() after the device is registered, not before, to set the operational state and user-space IFF_RUNNING flag correctly. Since we don't want observers to see an intermediate state, open-code register_netdev() and add efx_update_name() and netif_carrier_off() into the locked region. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 343e8da1fa3..d4dc92042d7 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1614,21 +1614,24 @@ static int efx_register_netdev(struct efx_nic *efx) SET_NETDEV_DEV(net_dev, &efx->pci_dev->dev); SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops); - /* Always start with carrier off; PHY events will detect the link */ - netif_carrier_off(efx->net_dev); - /* Clear MAC statistics */ efx->mac_op->update_stats(efx); memset(&efx->mac_stats, 0, sizeof(efx->mac_stats)); - rc = register_netdev(net_dev); - if (rc) { - EFX_ERR(efx, "could not register net dev\n"); - return rc; - } - rtnl_lock(); + + rc = dev_alloc_name(net_dev, net_dev->name); + if (rc < 0) + goto fail_locked; efx_update_name(efx); + + rc = register_netdevice(net_dev); + if (rc) + goto fail_locked; + + /* Always start with carrier off; PHY events will detect the link */ + netif_carrier_off(efx->net_dev); + rtnl_unlock(); rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_type); @@ -1639,6 +1642,11 @@ static int efx_register_netdev(struct efx_nic *efx) return 0; +fail_locked: + rtnl_unlock(); + EFX_ERR(efx, "could not register net dev\n"); + return rc; + fail_registered: unregister_netdev(net_dev); return rc; -- cgit v1.2.3-18-g5258 From d4ec09acdb15cdb5afdb5cd03f6bceb5c3c690a5 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 26 Aug 2009 08:16:46 +0000 Subject: sfc: Do not reinitialise XAUI serdes before it has completed reset falcon_reset_xaui() waits for XGXS reset to complete, but the XAUI serdes reset may take longer. It needs to check both reset active bits. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/falcon_hwdefs.h | 2 ++ drivers/net/sfc/falcon_xmac.c | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sfc/falcon_hwdefs.h b/drivers/net/sfc/falcon_hwdefs.h index 375e2a5961e..2d2261117ac 100644 --- a/drivers/net/sfc/falcon_hwdefs.h +++ b/drivers/net/sfc/falcon_hwdefs.h @@ -700,6 +700,8 @@ /* XGXS/XAUI powerdown/reset register */ #define XX_PWR_RST_REG 0x1300 +#define XX_SD_RST_ACT_LBN 16 +#define XX_SD_RST_ACT_WIDTH 1 #define XX_PWRDND_EN_LBN 15 #define XX_PWRDND_EN_WIDTH 1 #define XX_PWRDNC_EN_LBN 14 diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index 2b3269c0326..bec52ca37ee 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -64,13 +64,15 @@ int falcon_reset_xaui(struct efx_nic *efx) efx_oword_t reg; int count; + /* Start reset sequence */ EFX_POPULATE_DWORD_1(reg, XX_RST_XX_EN, 1); falcon_write(efx, ®, XX_PWR_RST_REG); - /* Give some time for the link to establish */ - for (count = 0; count < 1000; count++) { /* wait upto 10ms */ + /* Wait up to 10 ms for completion, then reinitialise */ + for (count = 0; count < 1000; count++) { falcon_read(efx, ®, XX_PWR_RST_REG); - if (EFX_OWORD_FIELD(reg, XX_RST_XX_EN) == 0) { + if (EFX_OWORD_FIELD(reg, XX_RST_XX_EN) == 0 && + EFX_OWORD_FIELD(reg, XX_SD_RST_ACT) == 0) { falcon_setup_xaui(efx); return 0; } -- cgit v1.2.3-18-g5258 From 771046d7b1def64c00a5a47ca48526cbbacd7fe3 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 26 Aug 2009 08:16:58 +0000 Subject: mdio: Check MDIO_STAT1_FAULT in mdio45_links_ok() Some PHYs will report that the link is up even though there is a fault condition. Therefore, check the fault flag too. We must also read STAT2 to reset this flag. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/mdio.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c index 6851bdb2ce2..7d2e610f14f 100644 --- a/drivers/net/mdio.c +++ b/drivers/net/mdio.c @@ -109,13 +109,20 @@ int mdio45_links_ok(const struct mdio_if_info *mdio, u32 mmd_mask) if (mmd_mask & (1 << devad)) { mmd_mask &= ~(1 << devad); - /* Read twice because link state is latched and a - * read moves the current state into the register */ + /* Reset the latched status and fault flags */ mdio->mdio_read(mdio->dev, mdio->prtad, devad, MDIO_STAT1); + if (devad == MDIO_MMD_PMAPMD || devad == MDIO_MMD_PCS || + devad == MDIO_MMD_PHYXS || devad == MDIO_MMD_DTEXS) + mdio->mdio_read(mdio->dev, mdio->prtad, + devad, MDIO_STAT2); + + /* Check the current status and fault flags */ reg = mdio->mdio_read(mdio->dev, mdio->prtad, devad, MDIO_STAT1); - if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS)) + if (reg < 0 || + (reg & (MDIO_STAT1_FAULT | MDIO_STAT1_LSTATUS)) != + MDIO_STAT1_LSTATUS) return false; } } -- cgit v1.2.3-18-g5258 From 5afaa753d681c437419e3dd9b532c2712dd1d2ea Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 26 Aug 2009 08:17:19 +0000 Subject: sfc: QT2025C: Use hard reset only At probe time, falcon_reset_hw() performs a hard reset of the PHY along with Falcon. There is no need to perform a soft reset later, and any access to standard MDIO registers before the PHY firmware has booted can interrupt the boot process, making the port unusable. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/xfp_phy.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c index bb2e6afd082..e6b3d5eaddb 100644 --- a/drivers/net/sfc/xfp_phy.c +++ b/drivers/net/sfc/xfp_phy.c @@ -97,23 +97,24 @@ static int qt2025c_wait_reset(struct efx_nic *efx) return 0; } -/* Reset the PHYXS MMD. This is documented (for the Quake PHYs) as doing - * a complete soft reset. - */ static int xfp_reset_phy(struct efx_nic *efx) { int rc; - rc = efx_mdio_reset_mmd(efx, MDIO_MMD_PHYXS, - XFP_MAX_RESET_TIME / XFP_RESET_WAIT, - XFP_RESET_WAIT); - if (rc < 0) - goto fail; - if (efx->phy_type == PHY_TYPE_QT2025C) { + /* Wait for the reset triggered by falcon_reset_hw() + * to complete */ rc = qt2025c_wait_reset(efx); if (rc < 0) goto fail; + } else { + /* Reset the PHYXS MMD. This is documented as doing + * a complete soft reset. */ + rc = efx_mdio_reset_mmd(efx, MDIO_MMD_PHYXS, + XFP_MAX_RESET_TIME / XFP_RESET_WAIT, + XFP_RESET_WAIT); + if (rc < 0) + goto fail; } /* Wait 250ms for the PHY to complete bootup */ -- cgit v1.2.3-18-g5258 From cc11763b3510e4942bfece052ccf329a7b086a32 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 26 Aug 2009 08:17:59 +0000 Subject: sfc: Work around XMAC bug causing packet loss with some peers Received frames must be re-clocked by the local XGXS to the 156.25 MHz (DDR) clock of the XGMII. If the remote clock is slightly faster this can reduce a minimum IPG of 64 bit-times (1 cycle) to 32 bit-times (half a cycle). If the XMAC detects that a frame has reached the maximum RX frame length in the same cycle that it receives one of these reduced IPGs, it may miss the IPG, causing two valid frames to be treated as a single invalid frame (over-length with bad CRC). We work around this by increasing the maximum RX frame length so that peers with matched MTU will not provoke this bug. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/net_driver.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 5eabede9ac1..298566da638 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -984,9 +984,14 @@ static inline void clear_bit_le(unsigned nr, unsigned char *addr) * * The 10G MAC used in Falcon requires 8-byte alignment on the frame * length, so we round up to the nearest 8. + * + * Re-clocking by the XGXS on RX can reduce an IPG to 32 bits (half an + * XGMII cycle). If the frame length reaches the maximum value in the + * same cycle, the XMAC can miss the IPG altogether. We work around + * this by adding a further 16 bytes. */ #define EFX_MAX_FRAME_LEN(mtu) \ - ((((mtu) + ETH_HLEN + VLAN_HLEN + 4/* FCS */) + 7) & ~7) + ((((mtu) + ETH_HLEN + VLAN_HLEN + 4/* FCS */ + 7) & ~7) + 16) #endif /* EFX_NET_DRIVER_H */ -- cgit v1.2.3-18-g5258 From 5c8af3b9aa4d19fba7f5a9224636fc70e476eb4f Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 26 Aug 2009 08:18:13 +0000 Subject: sfc: Improve reliability of RX queue flushing Reconfiguring the port requires us to flush all DMA queues. In repeated testing we have found that RX flushes would sometimes fail because the RX DMA engine was not properly isolated from the MACs. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index d4dc92042d7..07a7e4b8f8f 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1179,6 +1179,8 @@ static void efx_stop_all(struct efx_nic *efx) /* Isolate the MAC from the TX and RX engines, so that queue * flushes will complete in a timely fashion. */ + falcon_deconfigure_mac_wrapper(efx); + msleep(10); /* Let the Rx FIFO drain */ falcon_drain_tx_fifo(efx); /* Stop the kernel transmit interface late, so the watchdog -- cgit v1.2.3-18-g5258 From 999b874f4aa39b7abf45662ff0900f943ddb2d02 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Tue, 25 Aug 2009 19:24:22 -0700 Subject: Input: joydev - validate axis/button maps before clobbering current ones Up to now axis and button map validation was done after the user-supplied values were copied over the driver's map. This patch copies the user-supplied values into temporary buffers and validated them before overwriting the driver's permanent maps. Also change JSIOCGBTNMAP and JSIOCGAXMAP to return number of bytes returned to userspace instead of 0. Signed-off-by: Stephen Kitt Signed-off-by: Dmitry Torokhov --- drivers/input/joydev.c | 106 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 74 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 9a1d55b74d7..901b2525993 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -452,6 +452,76 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait) (joydev->exist ? 0 : (POLLHUP | POLLERR)); } +static int joydev_handle_JSIOCSAXMAP(struct joydev *joydev, + void __user *argp, size_t len) +{ + __u8 *abspam; + int i; + int retval = 0; + + len = min(len, sizeof(joydev->abspam)); + + /* Validate the map. */ + abspam = kmalloc(len, GFP_KERNEL); + if (!abspam) + return -ENOMEM; + + if (copy_from_user(abspam, argp, len)) { + retval = -EFAULT; + goto out; + } + + for (i = 0; i < joydev->nabs; i++) { + if (abspam[i] > ABS_MAX) { + retval = -EINVAL; + goto out; + } + } + + memcpy(joydev->abspam, abspam, len); + + out: + kfree(abspam); + return retval; +} + +static int joydev_handle_JSIOCSBTNMAP(struct joydev *joydev, + void __user *argp, size_t len) +{ + __u16 *keypam; + int i; + int retval = 0; + + len = min(len, sizeof(joydev->keypam)); + + /* Validate the map. */ + keypam = kmalloc(len, GFP_KERNEL); + if (!keypam) + return -ENOMEM; + + if (copy_from_user(keypam, argp, len)) { + retval = -EFAULT; + goto out; + } + + for (i = 0; i < joydev->nkey; i++) { + if (keypam[i] > KEY_MAX || keypam[i] < BTN_MISC) { + retval = -EINVAL; + goto out; + } + } + + memcpy(joydev->keypam, keypam, len); + + for (i = 0; i < joydev->nkey; i++) + joydev->keymap[keypam[i] - BTN_MISC] = i; + + out: + kfree(keypam); + return retval; +} + + static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp) { @@ -512,46 +582,18 @@ static int joydev_ioctl_common(struct joydev *joydev, switch (cmd & ~IOCSIZE_MASK) { case (JSIOCSAXMAP & ~IOCSIZE_MASK): - len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->abspam)); - /* - * FIXME: we should not copy into our axis map before - * validating the data. - */ - if (copy_from_user(joydev->abspam, argp, len)) - return -EFAULT; - - for (i = 0; i < joydev->nabs; i++) { - if (joydev->abspam[i] > ABS_MAX) - return -EINVAL; - joydev->absmap[joydev->abspam[i]] = i; - } - return 0; + return joydev_handle_JSIOCSAXMAP(joydev, argp, _IOC_SIZE(cmd)); case (JSIOCGAXMAP & ~IOCSIZE_MASK): len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->abspam)); - return copy_to_user(argp, joydev->abspam, len) ? -EFAULT : 0; + return copy_to_user(argp, joydev->abspam, len) ? -EFAULT : len; case (JSIOCSBTNMAP & ~IOCSIZE_MASK): - len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->keypam)); - /* - * FIXME: we should not copy into our keymap before - * validating the data. - */ - if (copy_from_user(joydev->keypam, argp, len)) - return -EFAULT; - - for (i = 0; i < joydev->nkey; i++) { - if (joydev->keypam[i] > KEY_MAX || - joydev->keypam[i] < BTN_MISC) - return -EINVAL; - joydev->keymap[joydev->keypam[i] - BTN_MISC] = i; - } - - return 0; + return joydev_handle_JSIOCSBTNMAP(joydev, argp, _IOC_SIZE(cmd)); case (JSIOCGBTNMAP & ~IOCSIZE_MASK): len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->keypam)); - return copy_to_user(argp, joydev->keypam, len) ? -EFAULT : 0; + return copy_to_user(argp, joydev->keypam, len) ? -EFAULT : len; case JSIOCGNAME(0): name = dev->name; -- cgit v1.2.3-18-g5258 From 8fbac18e8edd974b5234d96a9b8e2a26ab2ac556 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 25 Aug 2009 19:24:23 -0700 Subject: Input: tosakbd - fix cleaning up KEY_STROBEs after error Direct to fail2 to gpio_free() the KEY_STROBEs as well as the KEY_SENSEs. [dtor@mail.ru: change keymap from unsigned int to unsigned short] Signed-off-by: Roel Kluin Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tosakbd.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/tosakbd.c b/drivers/input/keyboard/tosakbd.c index 677276b1202..42cb3faf733 100644 --- a/drivers/input/keyboard/tosakbd.c +++ b/drivers/input/keyboard/tosakbd.c @@ -31,7 +31,7 @@ #define KB_DISCHARGE_DELAY 10 #define KB_ACTIVATE_DELAY 10 -static unsigned int tosakbd_keycode[NR_SCANCODES] = { +static unsigned short tosakbd_keycode[NR_SCANCODES] = { 0, 0, KEY_W, 0, 0, 0, KEY_K, KEY_BACKSPACE, KEY_P, 0, 0, 0, 0, 0, 0, 0, 0, @@ -50,9 +50,9 @@ KEY_X, KEY_F, KEY_SPACE, KEY_APOSTROPHE, TOSA_KEY_MAIL, KEY_LEFT, KEY_DOWN, KEY_ }; struct tosakbd { - unsigned int keycode[ARRAY_SIZE(tosakbd_keycode)]; + unsigned short keycode[ARRAY_SIZE(tosakbd_keycode)]; struct input_dev *input; - int suspended; + bool suspended; spinlock_t lock; /* protect kbd scanning */ struct timer_list timer; }; @@ -215,7 +215,7 @@ static int tosakbd_suspend(struct platform_device *dev, pm_message_t state) unsigned long flags; spin_lock_irqsave(&tosakbd->lock, flags); - tosakbd->suspended = 1; + tosakbd->suspended = true; spin_unlock_irqrestore(&tosakbd->lock, flags); del_timer_sync(&tosakbd->timer); @@ -227,7 +227,7 @@ static int tosakbd_resume(struct platform_device *dev) { struct tosakbd *tosakbd = platform_get_drvdata(dev); - tosakbd->suspended = 0; + tosakbd->suspended = false; tosakbd_scankeyboard(dev); return 0; @@ -277,14 +277,14 @@ static int __devinit tosakbd_probe(struct platform_device *pdev) { input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); input_dev->keycode = tosakbd->keycode; - input_dev->keycodesize = sizeof(unsigned int); + input_dev->keycodesize = sizeof(tosakbd->keycode[0]); input_dev->keycodemax = ARRAY_SIZE(tosakbd_keycode); memcpy(tosakbd->keycode, tosakbd_keycode, sizeof(tosakbd_keycode)); for (i = 0; i < ARRAY_SIZE(tosakbd_keycode); i++) __set_bit(tosakbd->keycode[i], input_dev->keybit); - clear_bit(0, input_dev->keybit); + __clear_bit(KEY_RESERVED, input_dev->keybit); /* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */ for (i = 0; i < TOSA_KEY_SENSE_NUM; i++) { @@ -344,7 +344,7 @@ static int __devinit tosakbd_probe(struct platform_device *pdev) { " direction for GPIO %d, error %d\n", gpio, error); gpio_free(gpio); - goto fail; + goto fail2; } } @@ -353,7 +353,7 @@ static int __devinit tosakbd_probe(struct platform_device *pdev) { if (error) { printk(KERN_ERR "tosakbd: Unable to register input device, " "error: %d\n", error); - goto fail; + goto fail2; } printk(KERN_INFO "input: Tosa Keyboard Registered\n"); -- cgit v1.2.3-18-g5258 From 77a53fd21870c726b670c0d8179294ac1ea33468 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 25 Aug 2009 19:24:13 -0700 Subject: Input: matrix-keypad - add function to build device keymap Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/matrix_keypad.c | 15 +++------------ drivers/input/keyboard/w90p910_keypad.c | 16 ++-------------- 2 files changed, 5 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 541b981ff07..91cfe517026 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -319,7 +319,6 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev) struct input_dev *input_dev; unsigned short *keycodes; unsigned int row_shift; - int i; int err; pdata = pdev->dev.platform_data; @@ -363,18 +362,10 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev) input_dev->keycode = keycodes; input_dev->keycodesize = sizeof(*keycodes); - input_dev->keycodemax = pdata->num_row_gpios << keypad->row_shift; - - for (i = 0; i < keymap_data->keymap_size; i++) { - unsigned int key = keymap_data->keymap[i]; - unsigned int row = KEY_ROW(key); - unsigned int col = KEY_COL(key); - unsigned short code = KEY_VAL(key); + input_dev->keycodemax = pdata->num_row_gpios << row_shift; - keycodes[MATRIX_SCAN_CODE(row, col, row_shift)] = code; - __set_bit(code, input_dev->keybit); - } - __clear_bit(KEY_RESERVED, input_dev->keybit); + matrix_keypad_build_keymap(keymap_data, row_shift, + input_dev->keycode, input_dev->keybit); input_set_capability(input_dev, EV_MSC, MSC_SCAN); input_set_drvdata(input_dev, keypad); diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c index b8598ae124e..2d03dd0f9e0 100644 --- a/drivers/input/keyboard/w90p910_keypad.c +++ b/drivers/input/keyboard/w90p910_keypad.c @@ -126,7 +126,6 @@ static int __devinit w90p910_keypad_probe(struct platform_device *pdev) struct resource *res; int irq; int error; - int i; if (!pdata) { dev_err(&pdev->dev, "no platform data defined\n"); @@ -197,19 +196,8 @@ static int __devinit w90p910_keypad_probe(struct platform_device *pdev) input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); input_set_capability(input_dev, EV_MSC, MSC_SCAN); - for (i = 0; i < keymap_data->keymap_size; i++) { - unsigned int key = keymap_data->keymap[i]; - unsigned int row = KEY_ROW(key); - unsigned int col = KEY_COL(key); - unsigned short keycode = KEY_VAL(key); - unsigned int scancode = MATRIX_SCAN_CODE(row, col, - W90P910_ROW_SHIFT); - - keypad->keymap[scancode] = keycode; - __set_bit(keycode, input_dev->keybit); - } - __clear_bit(KEY_RESERVED, input_dev->keybit); - + matrix_keypad_build_keymap(keymap_data, W90P910_ROW_SHIFT, + input_dev->keycode, input_dev->keybit); error = request_irq(keypad->irq, w90p910_keypad_irq_handler, IRQF_DISABLED, pdev->name, keypad); -- cgit v1.2.3-18-g5258 From 9d8340687c524ce61e3c9c76758c4c81303acfc0 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 25 Aug 2009 19:24:14 -0700 Subject: Input: add twl4030_keypad driver Add a driver for the keypad controller on TWL4030 family chips. These support up to an 8x8 key matrix. The TWL4030 multifunction chips are mostly used on OMAP3 (or OMAP 2430) based boards. [dtor@mail.ru: switch to matrix-keypad framework, fix changing keymap from userspace] Reviewed-by: Trilok Soni Signed-off-by: David Brownell Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/Kconfig | 11 + drivers/input/keyboard/Makefile | 1 + drivers/input/keyboard/twl4030_keypad.c | 480 ++++++++++++++++++++++++++++++++ 3 files changed, 492 insertions(+) create mode 100644 drivers/input/keyboard/twl4030_keypad.c (limited to 'drivers') diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 50e407de8a7..3525c19be42 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -330,6 +330,17 @@ config KEYBOARD_OMAP To compile this driver as a module, choose M here: the module will be called omap-keypad. +config KEYBOARD_TWL4030 + tristate "TI TWL4030/TWL5030/TPS659x0 keypad support" + depends on TWL4030_CORE + help + Say Y here if your board use the keypad controller on + TWL4030 family chips. It's safe to say enable this + even on boards that don't use the keypad controller. + + To compile this driver as a module, choose M here: the + module will be called twl4030_keypad. + config KEYBOARD_TOSA tristate "Tosa keyboard" depends on MACH_TOSA diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 15230302920..8a7a22b3026 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -30,5 +30,6 @@ obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o +obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c new file mode 100644 index 00000000000..9a2977c2169 --- /dev/null +++ b/drivers/input/keyboard/twl4030_keypad.c @@ -0,0 +1,480 @@ +/* + * twl4030_keypad.c - driver for 8x8 keypad controller in twl4030 chips + * + * Copyright (C) 2007 Texas Instruments, Inc. + * Copyright (C) 2008 Nokia Corporation + * + * Code re-written for 2430SDP by: + * Syed Mohammed Khasim + * + * Initial Code: + * Manjunatha G K + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + + +/* + * The TWL4030 family chips include a keypad controller that supports + * up to an 8x8 switch matrix. The controller can issue system wakeup + * events, since it uses only the always-on 32KiHz oscillator, and has + * an internal state machine that decodes pressed keys, including + * multi-key combinations. + * + * This driver lets boards define what keycodes they wish to report for + * which scancodes, as part of the "struct twl4030_keypad_data" used in + * the probe() routine. + * + * See the TPS65950 documentation; that's the general availability + * version of the TWL5030 second generation part. + */ +#define TWL4030_MAX_ROWS 8 /* TWL4030 hard limit */ +#define TWL4030_MAX_COLS 8 +#define TWL4030_ROW_SHIFT 3 +#define TWL4030_KEYMAP_SIZE (TWL4030_MAX_ROWS * TWL4030_MAX_COLS) + +struct twl4030_keypad { + unsigned short keymap[TWL4030_KEYMAP_SIZE]; + u16 kp_state[TWL4030_MAX_ROWS]; + unsigned n_rows; + unsigned n_cols; + unsigned irq; + + struct device *dbg_dev; + struct input_dev *input; +}; + +/*----------------------------------------------------------------------*/ + +/* arbitrary prescaler value 0..7 */ +#define PTV_PRESCALER 4 + +/* Register Offsets */ +#define KEYP_CTRL 0x00 +#define KEYP_DEB 0x01 +#define KEYP_LONG_KEY 0x02 +#define KEYP_LK_PTV 0x03 +#define KEYP_TIMEOUT_L 0x04 +#define KEYP_TIMEOUT_H 0x05 +#define KEYP_KBC 0x06 +#define KEYP_KBR 0x07 +#define KEYP_SMS 0x08 +#define KEYP_FULL_CODE_7_0 0x09 /* row 0 column status */ +#define KEYP_FULL_CODE_15_8 0x0a /* ... row 1 ... */ +#define KEYP_FULL_CODE_23_16 0x0b +#define KEYP_FULL_CODE_31_24 0x0c +#define KEYP_FULL_CODE_39_32 0x0d +#define KEYP_FULL_CODE_47_40 0x0e +#define KEYP_FULL_CODE_55_48 0x0f +#define KEYP_FULL_CODE_63_56 0x10 +#define KEYP_ISR1 0x11 +#define KEYP_IMR1 0x12 +#define KEYP_ISR2 0x13 +#define KEYP_IMR2 0x14 +#define KEYP_SIR 0x15 +#define KEYP_EDR 0x16 /* edge triggers */ +#define KEYP_SIH_CTRL 0x17 + +/* KEYP_CTRL_REG Fields */ +#define KEYP_CTRL_SOFT_NRST BIT(0) +#define KEYP_CTRL_SOFTMODEN BIT(1) +#define KEYP_CTRL_LK_EN BIT(2) +#define KEYP_CTRL_TOE_EN BIT(3) +#define KEYP_CTRL_TOLE_EN BIT(4) +#define KEYP_CTRL_RP_EN BIT(5) +#define KEYP_CTRL_KBD_ON BIT(6) + +/* KEYP_DEB, KEYP_LONG_KEY, KEYP_TIMEOUT_x*/ +#define KEYP_PERIOD_US(t, prescale) ((t) / (31 << (prescale + 1)) - 1) + +/* KEYP_LK_PTV_REG Fields */ +#define KEYP_LK_PTV_PTV_SHIFT 5 + +/* KEYP_{IMR,ISR,SIR} Fields */ +#define KEYP_IMR1_MIS BIT(3) +#define KEYP_IMR1_TO BIT(2) +#define KEYP_IMR1_LK BIT(1) +#define KEYP_IMR1_KP BIT(0) + +/* KEYP_EDR Fields */ +#define KEYP_EDR_KP_FALLING 0x01 +#define KEYP_EDR_KP_RISING 0x02 +#define KEYP_EDR_KP_BOTH 0x03 +#define KEYP_EDR_LK_FALLING 0x04 +#define KEYP_EDR_LK_RISING 0x08 +#define KEYP_EDR_TO_FALLING 0x10 +#define KEYP_EDR_TO_RISING 0x20 +#define KEYP_EDR_MIS_FALLING 0x40 +#define KEYP_EDR_MIS_RISING 0x80 + + +/*----------------------------------------------------------------------*/ + +static int twl4030_kpread(struct twl4030_keypad *kp, + u8 *data, u32 reg, u8 num_bytes) +{ + int ret = twl4030_i2c_read(TWL4030_MODULE_KEYPAD, data, reg, num_bytes); + + if (ret < 0) + dev_warn(kp->dbg_dev, + "Couldn't read TWL4030: %X - ret %d[%x]\n", + reg, ret, ret); + + return ret; +} + +static int twl4030_kpwrite_u8(struct twl4030_keypad *kp, u8 data, u32 reg) +{ + int ret = twl4030_i2c_write_u8(TWL4030_MODULE_KEYPAD, data, reg); + + if (ret < 0) + dev_warn(kp->dbg_dev, + "Could not write TWL4030: %X - ret %d[%x]\n", + reg, ret, ret); + + return ret; +} + +static inline u16 twl4030_col_xlate(struct twl4030_keypad *kp, u8 col) +{ + /* If all bits in a row are active for all coloumns then + * we have that row line connected to gnd. Mark this + * key on as if it was on matrix position n_cols (ie + * one higher than the size of the matrix). + */ + if (col == 0xFF) + return 1 << kp->n_cols; + else + return col & ((1 << kp->n_cols) - 1); +} + +static int twl4030_read_kp_matrix_state(struct twl4030_keypad *kp, u16 *state) +{ + u8 new_state[TWL4030_MAX_ROWS]; + int row; + int ret = twl4030_kpread(kp, new_state, + KEYP_FULL_CODE_7_0, kp->n_rows); + if (ret >= 0) + for (row = 0; row < kp->n_rows; row++) + state[row] = twl4030_col_xlate(kp, new_state[row]); + + return ret; +} + +static int twl4030_is_in_ghost_state(struct twl4030_keypad *kp, u16 *key_state) +{ + int i; + u16 check = 0; + + for (i = 0; i < kp->n_rows; i++) { + u16 col = key_state[i]; + + if ((col & check) && hweight16(col) > 1) + return 1; + + check |= col; + } + + return 0; +} + +static void twl4030_kp_scan(struct twl4030_keypad *kp, bool release_all) +{ + struct input_dev *input = kp->input; + u16 new_state[TWL4030_MAX_ROWS]; + int col, row; + + if (release_all) + memset(new_state, 0, sizeof(new_state)); + else { + /* check for any changes */ + int ret = twl4030_read_kp_matrix_state(kp, new_state); + + if (ret < 0) /* panic ... */ + return; + + if (twl4030_is_in_ghost_state(kp, new_state)) + return; + } + + /* check for changes and print those */ + for (row = 0; row < kp->n_rows; row++) { + int changed = new_state[row] ^ kp->kp_state[row]; + + if (!changed) + continue; + + for (col = 0; col < kp->n_cols; col++) { + int code; + + if (!(changed & (1 << col))) + continue; + + dev_dbg(kp->dbg_dev, "key [%d:%d] %s\n", row, col, + (new_state[row] & (1 << col)) ? + "press" : "release"); + + code = MATRIX_SCAN_CODE(row, col, TWL4030_ROW_SHIFT); + input_event(input, EV_MSC, MSC_SCAN, code); + input_report_key(input, kp->keymap[code], + new_state[row] & (1 << col)); + } + kp->kp_state[row] = new_state[row]; + } + input_sync(input); +} + +/* + * Keypad interrupt handler + */ +static irqreturn_t do_kp_irq(int irq, void *_kp) +{ + struct twl4030_keypad *kp = _kp; + u8 reg; + int ret; + +#ifdef CONFIG_LOCKDEP + /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which + * we don't want and can't tolerate. Although it might be + * friendlier not to borrow this thread context... + */ + local_irq_enable(); +#endif + + /* Read & Clear TWL4030 pending interrupt */ + ret = twl4030_kpread(kp, ®, KEYP_ISR1, 1); + + /* Release all keys if I2C has gone bad or + * the KEYP has gone to idle state */ + if (ret >= 0 && (reg & KEYP_IMR1_KP)) + twl4030_kp_scan(kp, false); + else + twl4030_kp_scan(kp, true); + + return IRQ_HANDLED; +} + +static int __devinit twl4030_kp_program(struct twl4030_keypad *kp) +{ + u8 reg; + int i; + + /* Enable controller, with hardware decoding but not autorepeat */ + reg = KEYP_CTRL_SOFT_NRST | KEYP_CTRL_SOFTMODEN + | KEYP_CTRL_TOE_EN | KEYP_CTRL_KBD_ON; + if (twl4030_kpwrite_u8(kp, reg, KEYP_CTRL) < 0) + return -EIO; + + /* NOTE: we could use sih_setup() here to package keypad + * event sources as four different IRQs ... but we don't. + */ + + /* Enable TO rising and KP rising and falling edge detection */ + reg = KEYP_EDR_KP_BOTH | KEYP_EDR_TO_RISING; + if (twl4030_kpwrite_u8(kp, reg, KEYP_EDR) < 0) + return -EIO; + + /* Set PTV prescaler Field */ + reg = (PTV_PRESCALER << KEYP_LK_PTV_PTV_SHIFT); + if (twl4030_kpwrite_u8(kp, reg, KEYP_LK_PTV) < 0) + return -EIO; + + /* Set key debounce time to 20 ms */ + i = KEYP_PERIOD_US(20000, PTV_PRESCALER); + if (twl4030_kpwrite_u8(kp, i, KEYP_DEB) < 0) + return -EIO; + + /* Set timeout period to 100 ms */ + i = KEYP_PERIOD_US(200000, PTV_PRESCALER); + if (twl4030_kpwrite_u8(kp, (i & 0xFF), KEYP_TIMEOUT_L) < 0) + return -EIO; + + if (twl4030_kpwrite_u8(kp, (i >> 8), KEYP_TIMEOUT_H) < 0) + return -EIO; + + /* + * Enable Clear-on-Read; disable remembering events that fire + * after the IRQ but before our handler acks (reads) them, + */ + reg = TWL4030_SIH_CTRL_COR_MASK | TWL4030_SIH_CTRL_PENDDIS_MASK; + if (twl4030_kpwrite_u8(kp, reg, KEYP_SIH_CTRL) < 0) + return -EIO; + + /* initialize key state; irqs update it from here on */ + if (twl4030_read_kp_matrix_state(kp, kp->kp_state) < 0) + return -EIO; + + return 0; +} + +/* + * Registers keypad device with input subsystem + * and configures TWL4030 keypad registers + */ +static int __devinit twl4030_kp_probe(struct platform_device *pdev) +{ + struct twl4030_keypad_data *pdata = pdev->dev.platform_data; + const struct matrix_keymap_data *keymap_data = pdata->keymap_data; + struct twl4030_keypad *kp; + struct input_dev *input; + u8 reg; + int error; + + if (!pdata || !pdata->rows || !pdata->cols || + pdata->rows > TWL4030_MAX_ROWS || pdata->cols > TWL4030_MAX_COLS) { + dev_err(&pdev->dev, "Invalid platform_data\n"); + return -EINVAL; + } + + kp = kzalloc(sizeof(*kp), GFP_KERNEL); + input = input_allocate_device(); + if (!kp || !input) { + error = -ENOMEM; + goto err1; + } + + /* Get the debug Device */ + kp->dbg_dev = &pdev->dev; + kp->input = input; + + kp->n_rows = pdata->rows; + kp->n_cols = pdata->cols; + kp->irq = platform_get_irq(pdev, 0); + + /* setup input device */ + __set_bit(EV_KEY, input->evbit); + + /* Enable auto repeat feature of Linux input subsystem */ + if (pdata->rep) + __set_bit(EV_REP, input->evbit); + + input_set_capability(input, EV_MSC, MSC_SCAN); + + input->name = "TWL4030 Keypad"; + input->phys = "twl4030_keypad/input0"; + input->dev.parent = &pdev->dev; + + input->id.bustype = BUS_HOST; + input->id.vendor = 0x0001; + input->id.product = 0x0001; + input->id.version = 0x0003; + + input->keycode = kp->keymap; + input->keycodesize = sizeof(kp->keymap[0]); + input->keycodemax = ARRAY_SIZE(kp->keymap); + + matrix_keypad_build_keymap(keymap_data, TWL4030_ROW_SHIFT, + input->keycode, input->keybit); + + error = input_register_device(input); + if (error) { + dev_err(kp->dbg_dev, + "Unable to register twl4030 keypad device\n"); + goto err1; + } + + error = twl4030_kp_program(kp); + if (error) + goto err2; + + /* + * This ISR will always execute in kernel thread context because of + * the need to access the TWL4030 over the I2C bus. + * + * NOTE: we assume this host is wired to TWL4040 INT1, not INT2 ... + */ + error = request_irq(kp->irq, do_kp_irq, 0, pdev->name, kp); + if (error) { + dev_info(kp->dbg_dev, "request_irq failed for irq no=%d\n", + kp->irq); + goto err3; + } + + /* Enable KP and TO interrupts now. */ + reg = (u8) ~(KEYP_IMR1_KP | KEYP_IMR1_TO); + if (twl4030_kpwrite_u8(kp, reg, KEYP_IMR1)) { + error = -EIO; + goto err4; + } + + platform_set_drvdata(pdev, kp); + return 0; + +err4: + /* mask all events - we don't care about the result */ + (void) twl4030_kpwrite_u8(kp, 0xff, KEYP_IMR1); +err3: + free_irq(kp->irq, NULL); +err2: + input_unregister_device(input); + input = NULL; +err1: + input_free_device(input); + kfree(kp); + return error; +} + +static int __devexit twl4030_kp_remove(struct platform_device *pdev) +{ + struct twl4030_keypad *kp = platform_get_drvdata(pdev); + + free_irq(kp->irq, kp); + input_unregister_device(kp->input); + platform_set_drvdata(pdev, NULL); + kfree(kp); + + return 0; +} + +/* + * NOTE: twl4030 are multi-function devices connected via I2C. + * So this device is a child of an I2C parent, thus it needs to + * support unplug/replug (which most platform devices don't). + */ + +static struct platform_driver twl4030_kp_driver = { + .probe = twl4030_kp_probe, + .remove = __devexit_p(twl4030_kp_remove), + .driver = { + .name = "twl4030_keypad", + .owner = THIS_MODULE, + }, +}; + +static int __init twl4030_kp_init(void) +{ + return platform_driver_register(&twl4030_kp_driver); +} +module_init(twl4030_kp_init); + +static void __exit twl4030_kp_exit(void) +{ + platform_driver_unregister(&twl4030_kp_driver); +} +module_exit(twl4030_kp_exit); + +MODULE_AUTHOR("Texas Instruments"); +MODULE_DESCRIPTION("TWL4030 Keypad Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:twl4030_keypad"); + -- cgit v1.2.3-18-g5258 From 90d6f92828a081a86cb4f9644b6eef6207855050 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Thu, 20 Aug 2009 20:22:01 +0200 Subject: p54: fix broadcast buffering in AP mode The patch "mac80211: fix PS-poll response race" somehow broke broadcast buffering in a funny way. During normal operation - stations are awake - the firmware refused to transmit broadcast frames and reported P54_TX_PSM_CANCELLED. But everything worked as soon as one station entered PSM. The reason: The stack sets IEEE80211_TX_CTL_SEND_AFTER_DTIM for outgoing broadcast frames as soon as a station is marked as sleeping. This flag triggers a path which will reroute these frames into p54's "content after beacon" queue, which is designed to cope with the demands for psm. This patch restores the old behavior. IEEE80211_TX_CTL_CLEAR_PS_FILT will once again be used to signalize the firmware to ignore the ps canceling for certain frames. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/txrx.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 6fc0b6148c8..b6dda2b27fb 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -623,6 +623,9 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb, if (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE) *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; + if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) + *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; + *queue = skb_get_queue_mapping(skb) + P54_QUEUE_DATA; switch (priv->mode) { -- cgit v1.2.3-18-g5258 From 5eb6ba83aa326e2f2cf9109d20df5d6a497b36bb Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Thu, 20 Aug 2009 19:12:07 -0700 Subject: ath9k: Add support FIF_OTHER_BSS filtering mode. Support for FIF_OTHER_BSS was missing. This patch adds support for this filtering mode which in turn resolves a problem where mesh interfaces would not receive broadcast traffic. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 7b62c220d5f..52e62daad3c 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -423,11 +423,12 @@ u32 ath_calcrxfilter(struct ath_softc *sc) if (sc->rx.rxfilter & FIF_PSPOLL) rfilt |= ATH9K_RX_FILTER_PSPOLL; - if (sc->sec_wiphy) { + if (sc->sec_wiphy || (sc->rx.rxfilter & FIF_OTHER_BSS)) { /* TODO: only needed if more than one BSSID is in use in * station/adhoc mode */ - /* TODO: for older chips, may need to add ATH9K_RX_FILTER_PROM - */ + /* The following may also be needed for other older chips */ + if (sc->sc_ah->hw_version.macVersion == AR_SREV_VERSION_9160) + rfilt |= ATH9K_RX_FILTER_PROM; rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL; } -- cgit v1.2.3-18-g5258 From 40ba60ddfeff8ef42fb33c0bdacfbb5f83e96b32 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 20 Aug 2009 21:00:34 +0300 Subject: rndis_wlan: fix broken logic in add_wep_key() add_wep_key() tries to check if key length is not 5 AND not 13 but uses (key_len != 5 || key_len != 13) instead. Fix this. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index d42692dfbc6..c5b921bf5a9 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1214,7 +1214,7 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) struct ndis_80211_wep_key ndis_key; int cipher, ret; - if ((key_len != 5 || key_len != 13) || index < 0 || index > 3) + if ((key_len != 5 && key_len != 13) || index < 0 || index > 3) return -EINVAL; if (key_len == 5) -- cgit v1.2.3-18-g5258 From b0a4e7d8a291de63f35b04464de9ab4a83d38a7c Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 20 Aug 2009 14:48:03 -0400 Subject: libipw: switch from ieee80211_* to libipw_* naming policy This eliminates the dual definition of ieee80211_channel (and possibly others), further clarifying who defines what and paving the way for inclusion of cfg80211.h. Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ieee80211.h | 1087 -------------------------- drivers/net/wireless/ipw2x00/ipw2100.c | 198 ++--- drivers/net/wireless/ipw2x00/ipw2100.h | 14 +- drivers/net/wireless/ipw2x00/ipw2200.c | 902 ++++++++++----------- drivers/net/wireless/ipw2x00/ipw2200.h | 14 +- drivers/net/wireless/ipw2x00/libipw.h | 1087 ++++++++++++++++++++++++++ drivers/net/wireless/ipw2x00/libipw_geo.c | 80 +- drivers/net/wireless/ipw2x00/libipw_module.c | 80 +- drivers/net/wireless/ipw2x00/libipw_rx.c | 403 +++++----- drivers/net/wireless/ipw2x00/libipw_tx.c | 68 +- drivers/net/wireless/ipw2x00/libipw_wx.c | 92 +-- 11 files changed, 2013 insertions(+), 2012 deletions(-) delete mode 100644 drivers/net/wireless/ipw2x00/ieee80211.h create mode 100644 drivers/net/wireless/ipw2x00/libipw.h (limited to 'drivers') diff --git a/drivers/net/wireless/ipw2x00/ieee80211.h b/drivers/net/wireless/ipw2x00/ieee80211.h deleted file mode 100644 index 70755c1336d..00000000000 --- a/drivers/net/wireless/ipw2x00/ieee80211.h +++ /dev/null @@ -1,1087 +0,0 @@ -/* - * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11 - * remains copyright by the original authors - * - * Portions of the merged code are based on Host AP (software wireless - * LAN access point) driver for Intersil Prism2/2.5/3. - * - * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * - * Copyright (c) 2002-2003, Jouni Malinen - * - * Adaption to a generic IEEE 802.11 stack by James Ketrenos - * - * Copyright (c) 2004-2005, Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. See README and COPYING for - * more details. - * - * API Version History - * 1.0.x -- Initial version - * 1.1.x -- Added radiotap, QoS, TIM, ieee80211_geo APIs, - * various structure changes, and crypto API init method - */ -#ifndef IEEE80211_H -#define IEEE80211_H -#include /* ETH_ALEN */ -#include /* ARRAY_SIZE */ -#include -#include - -#include - -#define IEEE80211_VERSION "git-1.1.13" - -#define IEEE80211_DATA_LEN 2304 -/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section - 6.2.1.1.2. - - The figure in section 7.1.2 suggests a body size of up to 2312 - bytes is allowed, which is a bit confusing, I suspect this - represents the 2304 bytes of real data, plus a possible 8 bytes of - WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ - -#define IEEE80211_1ADDR_LEN 10 -#define IEEE80211_2ADDR_LEN 16 -#define IEEE80211_3ADDR_LEN 24 -#define IEEE80211_4ADDR_LEN 30 -#define IEEE80211_FCS_LEN 4 -#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) -#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) - -#define MIN_FRAG_THRESHOLD 256U -#define MAX_FRAG_THRESHOLD 2346U - -/* QOS control */ -#define IEEE80211_QCTL_TID 0x000F - -/* debug macros */ - -#ifdef CONFIG_LIBIPW_DEBUG -extern u32 ieee80211_debug_level; -#define IEEE80211_DEBUG(level, fmt, args...) \ -do { if (ieee80211_debug_level & (level)) \ - printk(KERN_DEBUG "ieee80211: %c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) -static inline bool ieee80211_ratelimit_debug(u32 level) -{ - return (ieee80211_debug_level & level) && net_ratelimit(); -} -#else -#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0) -static inline bool ieee80211_ratelimit_debug(u32 level) -{ - return false; -} -#endif /* CONFIG_LIBIPW_DEBUG */ - -/* - * To use the debug system: - * - * If you are defining a new debug classification, simply add it to the #define - * list here in the form of: - * - * #define IEEE80211_DL_xxxx VALUE - * - * shifting value to the left one bit from the previous entry. xxxx should be - * the name of the classification (for example, WEP) - * - * You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your - * classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want - * to send output to that classification. - * - * To add your debug level to the list of levels seen when you perform - * - * % cat /proc/net/ieee80211/debug_level - * - * you simply need to add your entry to the ieee80211_debug_level array. - * - * If you do not see debug_level in /proc/net/ieee80211 then you do not have - * CONFIG_LIBIPW_DEBUG defined in your kernel configuration - * - */ - -#define IEEE80211_DL_INFO (1<<0) -#define IEEE80211_DL_WX (1<<1) -#define IEEE80211_DL_SCAN (1<<2) -#define IEEE80211_DL_STATE (1<<3) -#define IEEE80211_DL_MGMT (1<<4) -#define IEEE80211_DL_FRAG (1<<5) -#define IEEE80211_DL_DROP (1<<7) - -#define IEEE80211_DL_TX (1<<8) -#define IEEE80211_DL_RX (1<<9) -#define IEEE80211_DL_QOS (1<<31) - -#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a) -#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a) -#define IEEE80211_DEBUG_INFO(f, a...) IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a) - -#define IEEE80211_DEBUG_WX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a) -#define IEEE80211_DEBUG_SCAN(f, a...) IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a) -#define IEEE80211_DEBUG_STATE(f, a...) IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a) -#define IEEE80211_DEBUG_MGMT(f, a...) IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a) -#define IEEE80211_DEBUG_FRAG(f, a...) IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a) -#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a) -#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a) -#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a) -#define IEEE80211_DEBUG_QOS(f, a...) IEEE80211_DEBUG(IEEE80211_DL_QOS, f, ## a) -#include -#include /* ARPHRD_ETHER */ - -#ifndef WIRELESS_SPY -#define WIRELESS_SPY /* enable iwspy support */ -#endif -#include /* new driver API */ - -#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ - -#ifndef ETH_P_80211_RAW -#define ETH_P_80211_RAW (ETH_P_ECONET + 1) -#endif - -/* IEEE 802.11 defines */ - -#define P80211_OUI_LEN 3 - -struct ieee80211_snap_hdr { - - u8 dsap; /* always 0xAA */ - u8 ssap; /* always 0xAA */ - u8 ctrl; /* always 0x03 */ - u8 oui[P80211_OUI_LEN]; /* organizational universal id */ - -} __attribute__ ((packed)); - -#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) - -#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS) -#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE) -#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE) - -#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG) -#define WLAN_GET_SEQ_SEQ(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) - -#define IEEE80211_STATMASK_SIGNAL (1<<0) -#define IEEE80211_STATMASK_RSSI (1<<1) -#define IEEE80211_STATMASK_NOISE (1<<2) -#define IEEE80211_STATMASK_RATE (1<<3) -#define IEEE80211_STATMASK_WEMASK 0x7 - -#define IEEE80211_CCK_MODULATION (1<<0) -#define IEEE80211_OFDM_MODULATION (1<<1) - -#define IEEE80211_24GHZ_BAND (1<<0) -#define IEEE80211_52GHZ_BAND (1<<1) - -#define IEEE80211_CCK_RATE_1MB 0x02 -#define IEEE80211_CCK_RATE_2MB 0x04 -#define IEEE80211_CCK_RATE_5MB 0x0B -#define IEEE80211_CCK_RATE_11MB 0x16 -#define IEEE80211_OFDM_RATE_6MB 0x0C -#define IEEE80211_OFDM_RATE_9MB 0x12 -#define IEEE80211_OFDM_RATE_12MB 0x18 -#define IEEE80211_OFDM_RATE_18MB 0x24 -#define IEEE80211_OFDM_RATE_24MB 0x30 -#define IEEE80211_OFDM_RATE_36MB 0x48 -#define IEEE80211_OFDM_RATE_48MB 0x60 -#define IEEE80211_OFDM_RATE_54MB 0x6C -#define IEEE80211_BASIC_RATE_MASK 0x80 - -#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) -#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) -#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) -#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) -#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) -#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) -#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) -#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) -#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) -#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) -#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) -#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) - -#define IEEE80211_CCK_RATES_MASK 0x0000000F -#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ - IEEE80211_CCK_RATE_2MB_MASK) -#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ - IEEE80211_CCK_RATE_5MB_MASK | \ - IEEE80211_CCK_RATE_11MB_MASK) - -#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 -#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ - IEEE80211_OFDM_RATE_12MB_MASK | \ - IEEE80211_OFDM_RATE_24MB_MASK) -#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ - IEEE80211_OFDM_RATE_9MB_MASK | \ - IEEE80211_OFDM_RATE_18MB_MASK | \ - IEEE80211_OFDM_RATE_36MB_MASK | \ - IEEE80211_OFDM_RATE_48MB_MASK | \ - IEEE80211_OFDM_RATE_54MB_MASK) -#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ - IEEE80211_CCK_DEFAULT_RATES_MASK) - -#define IEEE80211_NUM_OFDM_RATES 8 -#define IEEE80211_NUM_CCK_RATES 4 -#define IEEE80211_OFDM_SHIFT_MASK_A 4 - -/* NOTE: This data is for statistical purposes; not all hardware provides this - * information for frames received. - * For ieee80211_rx_mgt, you need to set at least the 'len' parameter. - */ -struct ieee80211_rx_stats { - u32 mac_time; - s8 rssi; - u8 signal; - u8 noise; - u16 rate; /* in 100 kbps */ - u8 received_channel; - u8 control; - u8 mask; - u8 freq; - u16 len; - u64 tsf; - u32 beacon_time; -}; - -/* IEEE 802.11 requires that STA supports concurrent reception of at least - * three fragmented frames. This define can be increased to support more - * concurrent frames, but it should be noted that each entry can consume about - * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ -#define IEEE80211_FRAG_CACHE_LEN 4 - -struct ieee80211_frag_entry { - unsigned long first_frag_time; - unsigned int seq; - unsigned int last_frag; - struct sk_buff *skb; - u8 src_addr[ETH_ALEN]; - u8 dst_addr[ETH_ALEN]; -}; - -struct ieee80211_stats { - unsigned int tx_unicast_frames; - unsigned int tx_multicast_frames; - unsigned int tx_fragments; - unsigned int tx_unicast_octets; - unsigned int tx_multicast_octets; - unsigned int tx_deferred_transmissions; - unsigned int tx_single_retry_frames; - unsigned int tx_multiple_retry_frames; - unsigned int tx_retry_limit_exceeded; - unsigned int tx_discards; - unsigned int rx_unicast_frames; - unsigned int rx_multicast_frames; - unsigned int rx_fragments; - unsigned int rx_unicast_octets; - unsigned int rx_multicast_octets; - unsigned int rx_fcs_errors; - unsigned int rx_discards_no_buffer; - unsigned int tx_discards_wrong_sa; - unsigned int rx_discards_undecryptable; - unsigned int rx_message_in_msg_fragments; - unsigned int rx_message_in_bad_msg_fragments; -}; - -struct ieee80211_device; - -#define SEC_KEY_1 (1<<0) -#define SEC_KEY_2 (1<<1) -#define SEC_KEY_3 (1<<2) -#define SEC_KEY_4 (1<<3) -#define SEC_ACTIVE_KEY (1<<4) -#define SEC_AUTH_MODE (1<<5) -#define SEC_UNICAST_GROUP (1<<6) -#define SEC_LEVEL (1<<7) -#define SEC_ENABLED (1<<8) -#define SEC_ENCRYPT (1<<9) - -#define SEC_LEVEL_0 0 /* None */ -#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ -#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ -#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ -#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ - -#define SEC_ALG_NONE 0 -#define SEC_ALG_WEP 1 -#define SEC_ALG_TKIP 2 -#define SEC_ALG_CCMP 3 - -#define WEP_KEYS 4 -#define WEP_KEY_LEN 13 -#define SCM_KEY_LEN 32 -#define SCM_TEMPORAL_KEY_LENGTH 16 - -struct ieee80211_security { - u16 active_key:2, enabled:1, unicast_uses_group:1, encrypt:1; - u8 auth_mode; - u8 encode_alg[WEP_KEYS]; - u8 key_sizes[WEP_KEYS]; - u8 keys[WEP_KEYS][SCM_KEY_LEN]; - u8 level; - u16 flags; -} __attribute__ ((packed)); - -/* - - 802.11 data frame from AP - - ,-------------------------------------------------------------------. -Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | - |------|------|---------|---------|---------|------|---------|------| -Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs | - | | tion | (BSSID) | | | ence | data | | - `-------------------------------------------------------------------' - -Total: 28-2340 bytes - -*/ - -#define BEACON_PROBE_SSID_ID_POSITION 12 - -struct ieee80211_hdr_1addr { - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 payload[0]; -} __attribute__ ((packed)); - -struct ieee80211_hdr_2addr { - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 payload[0]; -} __attribute__ ((packed)); - -struct ieee80211_hdr_3addr { - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - __le16 seq_ctl; - u8 payload[0]; -} __attribute__ ((packed)); - -struct ieee80211_hdr_4addr { - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - __le16 seq_ctl; - u8 addr4[ETH_ALEN]; - u8 payload[0]; -} __attribute__ ((packed)); - -struct ieee80211_hdr_3addrqos { - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - __le16 seq_ctl; - u8 payload[0]; - __le16 qos_ctl; -} __attribute__ ((packed)); - -struct ieee80211_info_element { - u8 id; - u8 len; - u8 data[0]; -} __attribute__ ((packed)); - -/* - * These are the data types that can make up management packets - * - u16 auth_algorithm; - u16 auth_sequence; - u16 beacon_interval; - u16 capability; - u8 current_ap[ETH_ALEN]; - u16 listen_interval; - struct { - u16 association_id:14, reserved:2; - } __attribute__ ((packed)); - u32 time_stamp[2]; - u16 reason; - u16 status; -*/ - -struct ieee80211_auth { - struct ieee80211_hdr_3addr header; - __le16 algorithm; - __le16 transaction; - __le16 status; - /* challenge */ - struct ieee80211_info_element info_element[0]; -} __attribute__ ((packed)); - -struct ieee80211_channel_switch { - u8 id; - u8 len; - u8 mode; - u8 channel; - u8 count; -} __attribute__ ((packed)); - -struct ieee80211_action { - struct ieee80211_hdr_3addr header; - u8 category; - u8 action; - union { - struct ieee80211_action_exchange { - u8 token; - struct ieee80211_info_element info_element[0]; - } exchange; - struct ieee80211_channel_switch channel_switch; - - } format; -} __attribute__ ((packed)); - -struct ieee80211_disassoc { - struct ieee80211_hdr_3addr header; - __le16 reason; -} __attribute__ ((packed)); - -/* Alias deauth for disassoc */ -#define ieee80211_deauth ieee80211_disassoc - -struct ieee80211_probe_request { - struct ieee80211_hdr_3addr header; - /* SSID, supported rates */ - struct ieee80211_info_element info_element[0]; -} __attribute__ ((packed)); - -struct ieee80211_probe_response { - struct ieee80211_hdr_3addr header; - __le32 time_stamp[2]; - __le16 beacon_interval; - __le16 capability; - /* SSID, supported rates, FH params, DS params, - * CF params, IBSS params, TIM (if beacon), RSN */ - struct ieee80211_info_element info_element[0]; -} __attribute__ ((packed)); - -/* Alias beacon for probe_response */ -#define ieee80211_beacon ieee80211_probe_response - -struct ieee80211_assoc_request { - struct ieee80211_hdr_3addr header; - __le16 capability; - __le16 listen_interval; - /* SSID, supported rates, RSN */ - struct ieee80211_info_element info_element[0]; -} __attribute__ ((packed)); - -struct ieee80211_reassoc_request { - struct ieee80211_hdr_3addr header; - __le16 capability; - __le16 listen_interval; - u8 current_ap[ETH_ALEN]; - struct ieee80211_info_element info_element[0]; -} __attribute__ ((packed)); - -struct ieee80211_assoc_response { - struct ieee80211_hdr_3addr header; - __le16 capability; - __le16 status; - __le16 aid; - /* supported rates */ - struct ieee80211_info_element info_element[0]; -} __attribute__ ((packed)); - -struct ieee80211_txb { - u8 nr_frags; - u8 encrypted; - u8 rts_included; - u8 reserved; - u16 frag_size; - u16 payload_size; - struct sk_buff *fragments[0]; -}; - -/* SWEEP TABLE ENTRIES NUMBER */ -#define MAX_SWEEP_TAB_ENTRIES 42 -#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7 -/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs - * only use 8, and then use extended rates for the remaining supported - * rates. Other APs, however, stick all of their supported rates on the - * main rates information element... */ -#define MAX_RATES_LENGTH ((u8)12) -#define MAX_RATES_EX_LENGTH ((u8)16) -#define MAX_NETWORK_COUNT 128 - -#define CRC_LENGTH 4U - -#define MAX_WPA_IE_LEN 64 - -#define NETWORK_HAS_OFDM (1<<1) -#define NETWORK_HAS_CCK (1<<2) - -/* QoS structure */ -#define NETWORK_HAS_QOS_PARAMETERS (1<<3) -#define NETWORK_HAS_QOS_INFORMATION (1<<4) -#define NETWORK_HAS_QOS_MASK (NETWORK_HAS_QOS_PARAMETERS | \ - NETWORK_HAS_QOS_INFORMATION) - -/* 802.11h */ -#define NETWORK_HAS_POWER_CONSTRAINT (1<<5) -#define NETWORK_HAS_CSA (1<<6) -#define NETWORK_HAS_QUIET (1<<7) -#define NETWORK_HAS_IBSS_DFS (1<<8) -#define NETWORK_HAS_TPC_REPORT (1<<9) - -#define NETWORK_HAS_ERP_VALUE (1<<10) - -#define QOS_QUEUE_NUM 4 -#define QOS_OUI_LEN 3 -#define QOS_OUI_TYPE 2 -#define QOS_ELEMENT_ID 221 -#define QOS_OUI_INFO_SUB_TYPE 0 -#define QOS_OUI_PARAM_SUB_TYPE 1 -#define QOS_VERSION_1 1 -#define QOS_AIFSN_MIN_VALUE 2 - -struct ieee80211_qos_information_element { - u8 elementID; - u8 length; - u8 qui[QOS_OUI_LEN]; - u8 qui_type; - u8 qui_subtype; - u8 version; - u8 ac_info; -} __attribute__ ((packed)); - -struct ieee80211_qos_ac_parameter { - u8 aci_aifsn; - u8 ecw_min_max; - __le16 tx_op_limit; -} __attribute__ ((packed)); - -struct ieee80211_qos_parameter_info { - struct ieee80211_qos_information_element info_element; - u8 reserved; - struct ieee80211_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM]; -} __attribute__ ((packed)); - -struct ieee80211_qos_parameters { - __le16 cw_min[QOS_QUEUE_NUM]; - __le16 cw_max[QOS_QUEUE_NUM]; - u8 aifs[QOS_QUEUE_NUM]; - u8 flag[QOS_QUEUE_NUM]; - __le16 tx_op_limit[QOS_QUEUE_NUM]; -} __attribute__ ((packed)); - -struct ieee80211_qos_data { - struct ieee80211_qos_parameters parameters; - int active; - int supported; - u8 param_count; - u8 old_param_count; -}; - -struct ieee80211_tim_parameters { - u8 tim_count; - u8 tim_period; -} __attribute__ ((packed)); - -/*******************************************************/ - -enum { /* ieee80211_basic_report.map */ - IEEE80211_BASIC_MAP_BSS = (1 << 0), - IEEE80211_BASIC_MAP_OFDM = (1 << 1), - IEEE80211_BASIC_MAP_UNIDENTIFIED = (1 << 2), - IEEE80211_BASIC_MAP_RADAR = (1 << 3), - IEEE80211_BASIC_MAP_UNMEASURED = (1 << 4), - /* Bits 5-7 are reserved */ - -}; -struct ieee80211_basic_report { - u8 channel; - __le64 start_time; - __le16 duration; - u8 map; -} __attribute__ ((packed)); - -enum { /* ieee80211_measurement_request.mode */ - /* Bit 0 is reserved */ - IEEE80211_MEASUREMENT_ENABLE = (1 << 1), - IEEE80211_MEASUREMENT_REQUEST = (1 << 2), - IEEE80211_MEASUREMENT_REPORT = (1 << 3), - /* Bits 4-7 are reserved */ -}; - -enum { - IEEE80211_REPORT_BASIC = 0, /* required */ - IEEE80211_REPORT_CCA = 1, /* optional */ - IEEE80211_REPORT_RPI = 2, /* optional */ - /* 3-255 reserved */ -}; - -struct ieee80211_measurement_params { - u8 channel; - __le64 start_time; - __le16 duration; -} __attribute__ ((packed)); - -struct ieee80211_measurement_request { - struct ieee80211_info_element ie; - u8 token; - u8 mode; - u8 type; - struct ieee80211_measurement_params params[0]; -} __attribute__ ((packed)); - -struct ieee80211_measurement_report { - struct ieee80211_info_element ie; - u8 token; - u8 mode; - u8 type; - union { - struct ieee80211_basic_report basic[0]; - } u; -} __attribute__ ((packed)); - -struct ieee80211_tpc_report { - u8 transmit_power; - u8 link_margin; -} __attribute__ ((packed)); - -struct ieee80211_channel_map { - u8 channel; - u8 map; -} __attribute__ ((packed)); - -struct ieee80211_ibss_dfs { - struct ieee80211_info_element ie; - u8 owner[ETH_ALEN]; - u8 recovery_interval; - struct ieee80211_channel_map channel_map[0]; -}; - -struct ieee80211_csa { - u8 mode; - u8 channel; - u8 count; -} __attribute__ ((packed)); - -struct ieee80211_quiet { - u8 count; - u8 period; - u8 duration; - u8 offset; -} __attribute__ ((packed)); - -struct ieee80211_network { - /* These entries are used to identify a unique network */ - u8 bssid[ETH_ALEN]; - u8 channel; - /* Ensure null-terminated for any debug msgs */ - u8 ssid[IW_ESSID_MAX_SIZE + 1]; - u8 ssid_len; - - struct ieee80211_qos_data qos_data; - - /* These are network statistics */ - struct ieee80211_rx_stats stats; - u16 capability; - u8 rates[MAX_RATES_LENGTH]; - u8 rates_len; - u8 rates_ex[MAX_RATES_EX_LENGTH]; - u8 rates_ex_len; - unsigned long last_scanned; - u8 mode; - u32 flags; - u32 last_associate; - u32 time_stamp[2]; - u16 beacon_interval; - u16 listen_interval; - u16 atim_window; - u8 erp_value; - u8 wpa_ie[MAX_WPA_IE_LEN]; - size_t wpa_ie_len; - u8 rsn_ie[MAX_WPA_IE_LEN]; - size_t rsn_ie_len; - struct ieee80211_tim_parameters tim; - - /* 802.11h info */ - - /* Power Constraint - mandatory if spctrm mgmt required */ - u8 power_constraint; - - /* TPC Report - mandatory if spctrm mgmt required */ - struct ieee80211_tpc_report tpc_report; - - /* IBSS DFS - mandatory if spctrm mgmt required and IBSS - * NOTE: This is variable length and so must be allocated dynamically */ - struct ieee80211_ibss_dfs *ibss_dfs; - - /* Channel Switch Announcement - optional if spctrm mgmt required */ - struct ieee80211_csa csa; - - /* Quiet - optional if spctrm mgmt required */ - struct ieee80211_quiet quiet; - - struct list_head list; -}; - -enum ieee80211_state { - IEEE80211_UNINITIALIZED = 0, - IEEE80211_INITIALIZED, - IEEE80211_ASSOCIATING, - IEEE80211_ASSOCIATED, - IEEE80211_AUTHENTICATING, - IEEE80211_AUTHENTICATED, - IEEE80211_SHUTDOWN -}; - -#define DEFAULT_MAX_SCAN_AGE (15 * HZ) -#define DEFAULT_FTS 2346 - -#define CFG_IEEE80211_RESERVE_FCS (1<<0) -#define CFG_IEEE80211_COMPUTE_FCS (1<<1) -#define CFG_IEEE80211_RTS (1<<2) - -#define IEEE80211_24GHZ_MIN_CHANNEL 1 -#define IEEE80211_24GHZ_MAX_CHANNEL 14 -#define IEEE80211_24GHZ_CHANNELS (IEEE80211_24GHZ_MAX_CHANNEL - \ - IEEE80211_24GHZ_MIN_CHANNEL + 1) - -#define IEEE80211_52GHZ_MIN_CHANNEL 34 -#define IEEE80211_52GHZ_MAX_CHANNEL 165 -#define IEEE80211_52GHZ_CHANNELS (IEEE80211_52GHZ_MAX_CHANNEL - \ - IEEE80211_52GHZ_MIN_CHANNEL + 1) - -enum { - IEEE80211_CH_PASSIVE_ONLY = (1 << 0), - IEEE80211_CH_80211H_RULES = (1 << 1), - IEEE80211_CH_B_ONLY = (1 << 2), - IEEE80211_CH_NO_IBSS = (1 << 3), - IEEE80211_CH_UNIFORM_SPREADING = (1 << 4), - IEEE80211_CH_RADAR_DETECT = (1 << 5), - IEEE80211_CH_INVALID = (1 << 6), -}; - -struct ieee80211_channel { - u32 freq; /* in MHz */ - u8 channel; - u8 flags; - u8 max_power; /* in dBm */ -}; - -struct ieee80211_geo { - u8 name[4]; - u8 bg_channels; - u8 a_channels; - struct ieee80211_channel bg[IEEE80211_24GHZ_CHANNELS]; - struct ieee80211_channel a[IEEE80211_52GHZ_CHANNELS]; -}; - -struct ieee80211_device { - struct net_device *dev; - struct ieee80211_security sec; - - /* Bookkeeping structures */ - struct ieee80211_stats ieee_stats; - - struct ieee80211_geo geo; - - /* Probe / Beacon management */ - struct list_head network_free_list; - struct list_head network_list; - struct ieee80211_network *networks; - int scans; - int scan_age; - - int iw_mode; /* operating mode (IW_MODE_*) */ - struct iw_spy_data spy_data; /* iwspy support */ - - spinlock_t lock; - - int tx_headroom; /* Set to size of any additional room needed at front - * of allocated Tx SKBs */ - u32 config; - - /* WEP and other encryption related settings at the device level */ - int open_wep; /* Set to 1 to allow unencrypted frames */ - - int reset_on_keychange; /* Set to 1 if the HW needs to be reset on - * WEP key changes */ - - /* If the host performs {en,de}cryption, then set to 1 */ - int host_encrypt; - int host_encrypt_msdu; - int host_decrypt; - /* host performs multicast decryption */ - int host_mc_decrypt; - - /* host should strip IV and ICV from protected frames */ - /* meaningful only when hardware decryption is being used */ - int host_strip_iv_icv; - - int host_open_frag; - int host_build_iv; - int ieee802_1x; /* is IEEE 802.1X used */ - - /* WPA data */ - int wpa_enabled; - int drop_unencrypted; - int privacy_invoked; - size_t wpa_ie_len; - u8 *wpa_ie; - - struct lib80211_crypt_info crypt_info; - - int bcrx_sta_key; /* use individual keys to override default keys even - * with RX of broad/multicast frames */ - - /* Fragmentation structures */ - struct ieee80211_frag_entry frag_cache[IEEE80211_FRAG_CACHE_LEN]; - unsigned int frag_next_idx; - u16 fts; /* Fragmentation Threshold */ - u16 rts; /* RTS threshold */ - - /* Association info */ - u8 bssid[ETH_ALEN]; - - enum ieee80211_state state; - - int mode; /* A, B, G */ - int modulation; /* CCK, OFDM */ - int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ - int abg_true; /* ABG flag */ - - int perfect_rssi; - int worst_rssi; - - u16 prev_seq_ctl; /* used to drop duplicate frames */ - - /* Callback functions */ - void (*set_security) (struct net_device * dev, - struct ieee80211_security * sec); - int (*hard_start_xmit) (struct ieee80211_txb * txb, - struct net_device * dev, int pri); - int (*reset_port) (struct net_device * dev); - int (*is_queue_full) (struct net_device * dev, int pri); - - int (*handle_management) (struct net_device * dev, - struct ieee80211_network * network, u16 type); - int (*is_qos_active) (struct net_device *dev, struct sk_buff *skb); - - /* Typical STA methods */ - int (*handle_auth) (struct net_device * dev, - struct ieee80211_auth * auth); - int (*handle_deauth) (struct net_device * dev, - struct ieee80211_deauth * auth); - int (*handle_action) (struct net_device * dev, - struct ieee80211_action * action, - struct ieee80211_rx_stats * stats); - int (*handle_disassoc) (struct net_device * dev, - struct ieee80211_disassoc * assoc); - int (*handle_beacon) (struct net_device * dev, - struct ieee80211_beacon * beacon, - struct ieee80211_network * network); - int (*handle_probe_response) (struct net_device * dev, - struct ieee80211_probe_response * resp, - struct ieee80211_network * network); - int (*handle_probe_request) (struct net_device * dev, - struct ieee80211_probe_request * req, - struct ieee80211_rx_stats * stats); - int (*handle_assoc_response) (struct net_device * dev, - struct ieee80211_assoc_response * resp, - struct ieee80211_network * network); - - /* Typical AP methods */ - int (*handle_assoc_request) (struct net_device * dev); - int (*handle_reassoc_request) (struct net_device * dev, - struct ieee80211_reassoc_request * req); - - /* This must be the last item so that it points to the data - * allocated beyond this structure by alloc_ieee80211 */ - u8 priv[0]; -}; - -#define IEEE_A (1<<0) -#define IEEE_B (1<<1) -#define IEEE_G (1<<2) -#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) - -static inline void *ieee80211_priv(struct net_device *dev) -{ - return ((struct ieee80211_device *)netdev_priv(dev))->priv; -} - -static inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, - int mode) -{ - /* - * It is possible for both access points and our device to support - * combinations of modes, so as long as there is one valid combination - * of ap/device supported modes, then return success - * - */ - if ((mode & IEEE_A) && - (ieee->modulation & IEEE80211_OFDM_MODULATION) && - (ieee->freq_band & IEEE80211_52GHZ_BAND)) - return 1; - - if ((mode & IEEE_G) && - (ieee->modulation & IEEE80211_OFDM_MODULATION) && - (ieee->freq_band & IEEE80211_24GHZ_BAND)) - return 1; - - if ((mode & IEEE_B) && - (ieee->modulation & IEEE80211_CCK_MODULATION) && - (ieee->freq_band & IEEE80211_24GHZ_BAND)) - return 1; - - return 0; -} - -static inline int ieee80211_get_hdrlen(u16 fc) -{ - int hdrlen = IEEE80211_3ADDR_LEN; - u16 stype = WLAN_FC_GET_STYPE(fc); - - switch (WLAN_FC_GET_TYPE(fc)) { - case IEEE80211_FTYPE_DATA: - if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) - hdrlen = IEEE80211_4ADDR_LEN; - if (stype & IEEE80211_STYPE_QOS_DATA) - hdrlen += 2; - break; - case IEEE80211_FTYPE_CTL: - switch (WLAN_FC_GET_STYPE(fc)) { - case IEEE80211_STYPE_CTS: - case IEEE80211_STYPE_ACK: - hdrlen = IEEE80211_1ADDR_LEN; - break; - default: - hdrlen = IEEE80211_2ADDR_LEN; - break; - } - break; - } - - return hdrlen; -} - -static inline u8 *ieee80211_get_payload(struct ieee80211_hdr *hdr) -{ - switch (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control))) { - case IEEE80211_1ADDR_LEN: - return ((struct ieee80211_hdr_1addr *)hdr)->payload; - case IEEE80211_2ADDR_LEN: - return ((struct ieee80211_hdr_2addr *)hdr)->payload; - case IEEE80211_3ADDR_LEN: - return ((struct ieee80211_hdr_3addr *)hdr)->payload; - case IEEE80211_4ADDR_LEN: - return ((struct ieee80211_hdr_4addr *)hdr)->payload; - } - return NULL; -} - -static inline int ieee80211_is_ofdm_rate(u8 rate) -{ - switch (rate & ~IEEE80211_BASIC_RATE_MASK) { - case IEEE80211_OFDM_RATE_6MB: - case IEEE80211_OFDM_RATE_9MB: - case IEEE80211_OFDM_RATE_12MB: - case IEEE80211_OFDM_RATE_18MB: - case IEEE80211_OFDM_RATE_24MB: - case IEEE80211_OFDM_RATE_36MB: - case IEEE80211_OFDM_RATE_48MB: - case IEEE80211_OFDM_RATE_54MB: - return 1; - } - return 0; -} - -static inline int ieee80211_is_cck_rate(u8 rate) -{ - switch (rate & ~IEEE80211_BASIC_RATE_MASK) { - case IEEE80211_CCK_RATE_1MB: - case IEEE80211_CCK_RATE_2MB: - case IEEE80211_CCK_RATE_5MB: - case IEEE80211_CCK_RATE_11MB: - return 1; - } - return 0; -} - -/* ieee80211.c */ -extern void free_ieee80211(struct net_device *dev); -extern struct net_device *alloc_ieee80211(int sizeof_priv); -extern int ieee80211_change_mtu(struct net_device *dev, int new_mtu); - -extern void ieee80211_networks_age(struct ieee80211_device *ieee, - unsigned long age_secs); - -extern int ieee80211_set_encryption(struct ieee80211_device *ieee); - -/* ieee80211_tx.c */ -extern int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev); -extern void ieee80211_txb_free(struct ieee80211_txb *); - -/* ieee80211_rx.c */ -extern void ieee80211_rx_any(struct ieee80211_device *ieee, - struct sk_buff *skb, struct ieee80211_rx_stats *stats); -extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, - struct ieee80211_rx_stats *rx_stats); -/* make sure to set stats->len */ -extern void ieee80211_rx_mgt(struct ieee80211_device *ieee, - struct ieee80211_hdr_4addr *header, - struct ieee80211_rx_stats *stats); -extern void ieee80211_network_reset(struct ieee80211_network *network); - -/* ieee80211_geo.c */ -extern const struct ieee80211_geo *ieee80211_get_geo(struct ieee80211_device - *ieee); -extern int ieee80211_set_geo(struct ieee80211_device *ieee, - const struct ieee80211_geo *geo); - -extern int ieee80211_is_valid_channel(struct ieee80211_device *ieee, - u8 channel); -extern int ieee80211_channel_to_index(struct ieee80211_device *ieee, - u8 channel); -extern u8 ieee80211_freq_to_channel(struct ieee80211_device *ieee, u32 freq); -extern u8 ieee80211_get_channel_flags(struct ieee80211_device *ieee, - u8 channel); -extern const struct ieee80211_channel *ieee80211_get_channel(struct - ieee80211_device - *ieee, u8 channel); -extern u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee, - u8 channel); - -/* ieee80211_wx.c */ -extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key); -extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key); -extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key); -extern int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); -extern int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); - -static inline void ieee80211_increment_scans(struct ieee80211_device *ieee) -{ - ieee->scans++; -} - -static inline int ieee80211_get_scans(struct ieee80211_device *ieee) -{ - return ieee->scans; -} - -#endif /* IEEE80211_H */ diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index dee50ed0897..33bdb20e9f1 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -1673,7 +1673,7 @@ static int ipw2100_start_scan(struct ipw2100_priv *priv) return err; } -static const struct ieee80211_geo ipw_geos[] = { +static const struct libipw_geo ipw_geos[] = { { /* Restricted */ "---", .bg_channels = 14, @@ -1694,7 +1694,7 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) /* Age scan list entries found before suspend */ if (priv->suspend_time) { - ieee80211_networks_age(priv->ieee, priv->suspend_time); + libipw_networks_age(priv->ieee, priv->suspend_time); priv->suspend_time = 0; } @@ -1752,11 +1752,11 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) } /* Initialize the geo */ - if (ieee80211_set_geo(priv->ieee, &ipw_geos[0])) { + if (libipw_set_geo(priv->ieee, &ipw_geos[0])) { printk(KERN_WARNING DRV_NAME "Could not set geo\n"); return 0; } - priv->ieee->freq_band = IEEE80211_24GHZ_BAND; + priv->ieee->freq_band = LIBIPW_24GHZ_BAND; lock = LOCK_NONE; if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) { @@ -1817,7 +1817,7 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) /* Called by register_netdev() */ static int ipw2100_net_init(struct net_device *dev) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); return ipw2100_up(priv, 1); } @@ -2340,8 +2340,8 @@ static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf, * * When packet is provided by the firmware, it contains the following: * - * . ieee80211_hdr - * . ieee80211_snap_hdr + * . libipw_hdr + * . libipw_snap_hdr * * The size of the constructed ethernet * @@ -2396,7 +2396,7 @@ static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i) } static void isr_rx(struct ipw2100_priv *priv, int i, - struct ieee80211_rx_stats *stats) + struct libipw_rx_stats *stats) { struct net_device *dev = priv->net_dev; struct ipw2100_status *status = &priv->status_queue.drv[i]; @@ -2435,13 +2435,13 @@ static void isr_rx(struct ipw2100_priv *priv, int i, #ifdef IPW2100_RX_DEBUG /* Make a copy of the frame so we can dump it to the logs if - * ieee80211_rx fails */ + * libipw_rx fails */ skb_copy_from_linear_data(packet->skb, packet_data, min_t(u32, status->frame_size, IPW_RX_NIC_BUFFER_LENGTH)); #endif - if (!ieee80211_rx(priv->ieee, packet->skb, stats)) { + if (!libipw_rx(priv->ieee, packet->skb, stats)) { #ifdef IPW2100_RX_DEBUG IPW_DEBUG_DROP("%s: Non consumed packet:\n", dev->name); @@ -2449,7 +2449,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i, #endif dev->stats.rx_errors++; - /* ieee80211_rx failed, so it didn't free the SKB */ + /* libipw_rx failed, so it didn't free the SKB */ dev_kfree_skb_any(packet->skb); packet->skb = NULL; } @@ -2470,7 +2470,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i, #ifdef CONFIG_IPW2100_MONITOR static void isr_rx_monitor(struct ipw2100_priv *priv, int i, - struct ieee80211_rx_stats *stats) + struct libipw_rx_stats *stats) { struct net_device *dev = priv->net_dev; struct ipw2100_status *status = &priv->status_queue.drv[i]; @@ -2528,10 +2528,10 @@ static void isr_rx_monitor(struct ipw2100_priv *priv, int i, skb_put(packet->skb, status->frame_size + sizeof(struct ipw_rt_hdr)); - if (!ieee80211_rx(priv->ieee, packet->skb, stats)) { + if (!libipw_rx(priv->ieee, packet->skb, stats)) { dev->stats.rx_errors++; - /* ieee80211_rx failed, so it didn't free the SKB */ + /* libipw_rx failed, so it didn't free the SKB */ dev_kfree_skb_any(packet->skb); packet->skb = NULL; } @@ -2615,7 +2615,7 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv) u16 frame_type; u32 r, w, i, s; struct ipw2100_rx *u; - struct ieee80211_rx_stats stats = { + struct libipw_rx_stats stats = { .mac_time = jiffies, }; @@ -2661,8 +2661,8 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv) stats.mask = 0; if (stats.rssi != 0) - stats.mask |= IEEE80211_STATMASK_RSSI; - stats.freq = IEEE80211_24GHZ_BAND; + stats.mask |= LIBIPW_STATMASK_RSSI; + stats.freq = LIBIPW_24GHZ_BAND; IPW_DEBUG_RX("%s: '%s' frame type received (%d).\n", priv->net_dev->name, frame_types[frame_type], @@ -2686,11 +2686,11 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv) break; } #endif - if (stats.len < sizeof(struct ieee80211_hdr_3addr)) + if (stats.len < sizeof(struct libipw_hdr_3addr)) break; switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) { case IEEE80211_FTYPE_MGMT: - ieee80211_rx_mgt(priv->ieee, + libipw_rx_mgt(priv->ieee, &u->rx_data.header, &stats); break; @@ -2884,7 +2884,7 @@ static int __ipw2100_tx_process(struct ipw2100_priv *priv) tbd->buf_length, PCI_DMA_TODEVICE); } - ieee80211_txb_free(packet->info.d_struct.txb); + libipw_txb_free(packet->info.d_struct.txb); packet->info.d_struct.txb = NULL; list_add_tail(element, &priv->tx_free_list); @@ -3028,7 +3028,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) int next = txq->next; int i = 0; struct ipw2100_data_header *ipw_hdr; - struct ieee80211_hdr_3addr *hdr; + struct libipw_hdr_3addr *hdr; while (!list_empty(&priv->tx_pend_list)) { /* if there isn't enough space in TBD queue, then @@ -3062,7 +3062,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) packet->index = txq->next; ipw_hdr = packet->info.d_struct.data; - hdr = (struct ieee80211_hdr_3addr *)packet->info.d_struct.txb-> + hdr = (struct libipw_hdr_3addr *)packet->info.d_struct.txb-> fragments[0]->data; if (priv->ieee->iw_mode == IW_MODE_INFRA) { @@ -3086,7 +3086,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) if (packet->info.d_struct.txb->nr_frags > 1) ipw_hdr->fragment_size = packet->info.d_struct.txb->frag_size - - IEEE80211_3ADDR_LEN; + LIBIPW_3ADDR_LEN; else ipw_hdr->fragment_size = 0; @@ -3119,13 +3119,13 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT; tbd->buf_length = packet->info.d_struct.txb-> - fragments[i]->len - IEEE80211_3ADDR_LEN; + fragments[i]->len - LIBIPW_3ADDR_LEN; tbd->host_addr = pci_map_single(priv->pci_dev, packet->info.d_struct. txb->fragments[i]-> data + - IEEE80211_3ADDR_LEN, + LIBIPW_3ADDR_LEN, tbd->buf_length, PCI_DMA_TODEVICE); @@ -3330,10 +3330,10 @@ static irqreturn_t ipw2100_interrupt(int irq, void *data) return IRQ_NONE; } -static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev, +static int ipw2100_tx(struct libipw_txb *txb, struct net_device *dev, int pri) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); struct list_head *element; struct ipw2100_tx_packet *packet; unsigned long flags; @@ -4488,7 +4488,7 @@ static void ipw2100_tx_initialize(struct ipw2100_priv *priv) /* We simply drop any SKBs that have been queued for * transmit */ if (priv->tx_buffers[i].info.d_struct.txb) { - ieee80211_txb_free(priv->tx_buffers[i].info.d_struct. + libipw_txb_free(priv->tx_buffers[i].info.d_struct. txb); priv->tx_buffers[i].info.d_struct.txb = NULL; } @@ -4527,7 +4527,7 @@ static void ipw2100_tx_free(struct ipw2100_priv *priv) for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) { if (priv->tx_buffers[i].info.d_struct.txb) { - ieee80211_txb_free(priv->tx_buffers[i].info.d_struct. + libipw_txb_free(priv->tx_buffers[i].info.d_struct. txb); priv->tx_buffers[i].info.d_struct.txb = NULL; } @@ -5558,9 +5558,9 @@ static void ipw2100_security_work(struct work_struct *work) } static void shim__set_security(struct net_device *dev, - struct ieee80211_security *sec) + struct libipw_security *sec) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int i, force_update = 0; mutex_lock(&priv->action_mutex); @@ -5753,7 +5753,7 @@ static int ipw2100_adapter_setup(struct ipw2100_priv *priv) * method as well) to talk to the firmware */ static int ipw2100_set_address(struct net_device *dev, void *p) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); struct sockaddr *addr = p; int err = 0; @@ -5781,7 +5781,7 @@ static int ipw2100_set_address(struct net_device *dev, void *p) static int ipw2100_open(struct net_device *dev) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); unsigned long flags; IPW_DEBUG_INFO("dev->open\n"); @@ -5797,7 +5797,7 @@ static int ipw2100_open(struct net_device *dev) static int ipw2100_close(struct net_device *dev) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); unsigned long flags; struct list_head *element; struct ipw2100_tx_packet *packet; @@ -5818,7 +5818,7 @@ static int ipw2100_close(struct net_device *dev) list_del(element); DEC_STAT(&priv->tx_pend_stat); - ieee80211_txb_free(packet->info.d_struct.txb); + libipw_txb_free(packet->info.d_struct.txb); packet->info.d_struct.txb = NULL; list_add_tail(element, &priv->tx_free_list); @@ -5836,7 +5836,7 @@ static int ipw2100_close(struct net_device *dev) */ static void ipw2100_tx_timeout(struct net_device *dev) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); dev->stats.tx_errors++; @@ -5861,8 +5861,8 @@ static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value) static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value) { - struct ieee80211_device *ieee = priv->ieee; - struct ieee80211_security sec = { + struct libipw_device *ieee = priv->ieee; + struct libipw_security sec = { .flags = SEC_AUTH_MODE, }; int ret = 0; @@ -5907,7 +5907,7 @@ static void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv, static void ipw_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); char fw_ver[64], ucode_ver[64]; strcpy(info->driver, DRV_NAME); @@ -5924,7 +5924,7 @@ static void ipw_ethtool_get_drvinfo(struct net_device *dev, static u32 ipw2100_ethtool_get_link(struct net_device *dev) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); return (priv->status & STATUS_ASSOCIATED) ? 1 : 0; } @@ -6011,8 +6011,8 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv); static const struct net_device_ops ipw2100_netdev_ops = { .ndo_open = ipw2100_open, .ndo_stop = ipw2100_close, - .ndo_start_xmit = ieee80211_xmit, - .ndo_change_mtu = ieee80211_change_mtu, + .ndo_start_xmit = libipw_xmit, + .ndo_change_mtu = libipw_change_mtu, .ndo_init = ipw2100_net_init, .ndo_tx_timeout = ipw2100_tx_timeout, .ndo_set_mac_address = ipw2100_set_address, @@ -6032,7 +6032,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, dev = alloc_ieee80211(sizeof(struct ipw2100_priv)); if (!dev) return NULL; - priv = ieee80211_priv(dev); + priv = libipw_priv(dev); priv->ieee = netdev_priv(dev); priv->pci_dev = pci_dev; priv->net_dev = dev; @@ -6046,7 +6046,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, dev->netdev_ops = &ipw2100_netdev_ops; dev->ethtool_ops = &ipw2100_ethtool_ops; dev->wireless_handlers = &ipw2100_wx_handler_def; - priv->wireless_data.ieee80211 = priv->ieee; + priv->wireless_data.libipw = priv->ieee; dev->wireless_data = &priv->wireless_data; dev->watchdog_timeo = 3 * HZ; dev->irq = 0; @@ -6202,7 +6202,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, return err; } - priv = ieee80211_priv(dev); + priv = libipw_priv(dev); pci_set_master(pci_dev); pci_set_drvdata(pci_dev, priv); @@ -6629,7 +6629,7 @@ static int ipw2100_wx_get_name(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); if (!(priv->status & STATUS_ASSOCIATED)) strcpy(wrqu->name, "unassociated"); else @@ -6643,7 +6643,7 @@ static int ipw2100_wx_set_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); struct iw_freq *fwrq = &wrqu->freq; int err = 0; @@ -6693,7 +6693,7 @@ static int ipw2100_wx_get_freq(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); wrqu->freq.e = 0; @@ -6714,7 +6714,7 @@ static int ipw2100_wx_set_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int err = 0; IPW_DEBUG_WX("SET Mode -> %d \n", wrqu->mode); @@ -6757,7 +6757,7 @@ static int ipw2100_wx_get_mode(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); wrqu->mode = priv->ieee->iw_mode; IPW_DEBUG_WX("GET Mode -> %d\n", wrqu->mode); @@ -6792,7 +6792,7 @@ static int ipw2100_wx_get_range(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); struct iw_range *range = (struct iw_range *)extra; u16 val; int i, level; @@ -6913,7 +6913,7 @@ static int ipw2100_wx_set_wap(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int err = 0; static const unsigned char any[] = { @@ -6962,7 +6962,7 @@ static int ipw2100_wx_get_wap(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); /* If we are associated, trying to associate, or have a statically * configured BSSID then return that; otherwise return ANY */ @@ -6980,7 +6980,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); char *essid = ""; /* ANY */ int length = 0; int err = 0; @@ -7035,7 +7035,7 @@ static int ipw2100_wx_get_essid(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); DECLARE_SSID_BUF(ssid); /* If we are associated, trying to associate, or have a statically @@ -7063,7 +7063,7 @@ static int ipw2100_wx_set_nick(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); if (wrqu->data.length > IW_ESSID_MAX_SIZE) return -E2BIG; @@ -7085,7 +7085,7 @@ static int ipw2100_wx_get_nick(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); wrqu->data.length = strlen(priv->nick); memcpy(extra, priv->nick, wrqu->data.length); @@ -7100,7 +7100,7 @@ static int ipw2100_wx_set_rate(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); u32 target_rate = wrqu->bitrate.value; u32 rate; int err = 0; @@ -7140,7 +7140,7 @@ static int ipw2100_wx_get_rate(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int val; unsigned int len = sizeof(val); int err = 0; @@ -7192,7 +7192,7 @@ static int ipw2100_wx_set_rts(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int value, err; /* Auto RTS not yet supported */ @@ -7231,7 +7231,7 @@ static int ipw2100_wx_get_rts(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); wrqu->rts.value = priv->rts_threshold & ~RTS_DISABLED; wrqu->rts.fixed = 1; /* no auto select */ @@ -7248,7 +7248,7 @@ static int ipw2100_wx_set_txpow(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int err = 0, value; if (ipw_radio_kill_sw(priv, wrqu->txpower.disabled)) @@ -7293,7 +7293,7 @@ static int ipw2100_wx_get_txpow(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); wrqu->txpower.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0; @@ -7320,7 +7320,7 @@ static int ipw2100_wx_set_frag(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); if (!wrqu->frag.fixed) return -EINVAL; @@ -7350,7 +7350,7 @@ static int ipw2100_wx_get_frag(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); wrqu->frag.value = priv->frag_threshold & ~FRAG_DISABLED; wrqu->frag.fixed = 0; /* no auto select */ wrqu->frag.disabled = (priv->frag_threshold & FRAG_DISABLED) ? 1 : 0; @@ -7364,7 +7364,7 @@ static int ipw2100_wx_set_retry(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int err = 0; if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled) @@ -7412,7 +7412,7 @@ static int ipw2100_wx_get_retry(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); wrqu->retry.disabled = 0; /* can't be disabled */ @@ -7440,7 +7440,7 @@ static int ipw2100_wx_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int err = 0; mutex_lock(&priv->action_mutex); @@ -7472,8 +7472,8 @@ static int ipw2100_wx_get_scan(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra); + struct ipw2100_priv *priv = libipw_priv(dev); + return libipw_wx_get_scan(priv->ieee, info, wrqu, extra); } /* @@ -7487,8 +7487,8 @@ static int ipw2100_wx_set_encode(struct net_device *dev, * No check of STATUS_INITIALIZED required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_set_encode(priv->ieee, info, wrqu, key); + struct ipw2100_priv *priv = libipw_priv(dev); + return libipw_wx_set_encode(priv->ieee, info, wrqu, key); } static int ipw2100_wx_get_encode(struct net_device *dev, @@ -7499,15 +7499,15 @@ static int ipw2100_wx_get_encode(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_encode(priv->ieee, info, wrqu, key); + struct ipw2100_priv *priv = libipw_priv(dev); + return libipw_wx_get_encode(priv->ieee, info, wrqu, key); } static int ipw2100_wx_set_power(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int err = 0; mutex_lock(&priv->action_mutex); @@ -7556,7 +7556,7 @@ static int ipw2100_wx_get_power(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); if (!(priv->power_mode & IPW_POWER_ENABLED)) wrqu->power.disabled = 1; @@ -7580,8 +7580,8 @@ static int ipw2100_wx_set_genie(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; + struct ipw2100_priv *priv = libipw_priv(dev); + struct libipw_device *ieee = priv->ieee; u8 *buf; if (!ieee->wpa_enabled) @@ -7615,8 +7615,8 @@ static int ipw2100_wx_get_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; + struct ipw2100_priv *priv = libipw_priv(dev); + struct libipw_device *ieee = priv->ieee; if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) { wrqu->data.length = 0; @@ -7637,8 +7637,8 @@ static int ipw2100_wx_set_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; + struct ipw2100_priv *priv = libipw_priv(dev); + struct libipw_device *ieee = priv->ieee; struct iw_param *param = &wrqu->param; struct lib80211_crypt_data *crypt; unsigned long flags; @@ -7682,7 +7682,7 @@ static int ipw2100_wx_set_auth(struct net_device *dev, * can use this to determine if the CAP_PRIVACY_ON bit should * be set. */ - struct ieee80211_security sec = { + struct libipw_security sec = { .flags = SEC_ENABLED, .enabled = param->value, }; @@ -7730,8 +7730,8 @@ static int ipw2100_wx_get_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; + struct ipw2100_priv *priv = libipw_priv(dev); + struct libipw_device *ieee = priv->ieee; struct lib80211_crypt_data *crypt; struct iw_param *param = &wrqu->param; int ret = 0; @@ -7792,8 +7792,8 @@ static int ipw2100_wx_set_encodeext(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_set_encodeext(priv->ieee, info, wrqu, extra); + struct ipw2100_priv *priv = libipw_priv(dev); + return libipw_wx_set_encodeext(priv->ieee, info, wrqu, extra); } /* SIOCGIWENCODEEXT */ @@ -7801,8 +7801,8 @@ static int ipw2100_wx_get_encodeext(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_encodeext(priv->ieee, info, wrqu, extra); + struct ipw2100_priv *priv = libipw_priv(dev); + return libipw_wx_get_encodeext(priv->ieee, info, wrqu, extra); } /* SIOCSIWMLME */ @@ -7810,7 +7810,7 @@ static int ipw2100_wx_set_mlme(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); struct iw_mlme *mlme = (struct iw_mlme *)extra; __le16 reason; @@ -7841,7 +7841,7 @@ static int ipw2100_wx_set_promisc(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int *parms = (int *)extra; int enable = (parms[0] > 0); int err = 0; @@ -7872,7 +7872,7 @@ static int ipw2100_wx_reset(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); if (priv->status & STATUS_INITIALIZED) schedule_reset(priv); return 0; @@ -7884,7 +7884,7 @@ static int ipw2100_wx_set_powermode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int err = 0, mode = *(int *)extra; mutex_lock(&priv->action_mutex); @@ -7912,7 +7912,7 @@ static int ipw2100_wx_get_powermode(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int level = IPW_POWER_LEVEL(priv->power_mode); s32 timeout, period; @@ -7948,7 +7948,7 @@ static int ipw2100_wx_set_preamble(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int err, mode = *(int *)extra; mutex_lock(&priv->action_mutex); @@ -7981,7 +7981,7 @@ static int ipw2100_wx_get_preamble(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); if (priv->config & CFG_LONG_PREAMBLE) snprintf(wrqu->name, IFNAMSIZ, "long (1)"); @@ -7996,7 +7996,7 @@ static int ipw2100_wx_set_crc_check(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); int err, mode = *(int *)extra; mutex_lock(&priv->action_mutex); @@ -8028,7 +8028,7 @@ static int ipw2100_wx_get_crc_check(struct net_device *dev, * This can be called at any time. No action lock required */ - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); if (priv->config & CFG_CRC_CHECK) snprintf(wrqu->name, IFNAMSIZ, "CRC checked (1)"); @@ -8181,7 +8181,7 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev) int beacon_qual; int quality; - struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ipw2100_priv *priv = libipw_priv(dev); struct iw_statistics *wstats; u32 rssi, tx_retries, missed_beacons, tx_failures; u32 ord_len = sizeof(u32); diff --git a/drivers/net/wireless/ipw2x00/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h index f183d951cd3..af175bdc9f2 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.h +++ b/drivers/net/wireless/ipw2x00/ipw2100.h @@ -46,7 +46,7 @@ #include #include -#include "ieee80211.h" +#include "libipw.h" struct ipw2100_priv; struct ipw2100_tx_packet; @@ -343,7 +343,7 @@ struct ipw2100_tx_packet { struct { /* DATA */ struct ipw2100_data_header *data; dma_addr_t data_phys; - struct ieee80211_txb *txb; + struct libipw_txb *txb; } d_struct; } info; int jiffy_start; @@ -492,7 +492,7 @@ struct ipw2100_priv { int stop_hang_check; /* Set 1 when shutting down to kill hang_check */ int stop_rf_kill; /* Set 1 when shutting down to kill rf_kill */ - struct ieee80211_device *ieee; + struct libipw_device *ieee; unsigned long status; unsigned long config; unsigned long capability; @@ -788,7 +788,7 @@ struct ipw2100_priv { #define IPW_CARD_DISABLE_PHY_OFF_COMPLETE_WAIT 100 // 100 milli #define IPW_PREPARE_POWER_DOWN_COMPLETE_WAIT 100 // 100 milli -#define IPW_HEADER_802_11_SIZE sizeof(struct ieee80211_hdr_3addr) +#define IPW_HEADER_802_11_SIZE sizeof(struct libipw_hdr_3addr) #define IPW_MAX_80211_PAYLOAD_SIZE 2304U #define IPW_MAX_802_11_PAYLOAD_LENGTH 2312 #define IPW_MAX_ACCEPTABLE_TX_FRAME_LENGTH 1536 @@ -803,13 +803,13 @@ struct ipw2100_priv { IPW_802_11_FCS_LENGTH) #define IPW_802_11_PAYLOAD_OFFSET \ - (sizeof(struct ieee80211_hdr_3addr) + \ - sizeof(struct ieee80211_snap_hdr)) + (sizeof(struct libipw_hdr_3addr) + \ + sizeof(struct libipw_snap_hdr)) struct ipw2100_rx { union { unsigned char payload[IPW_RX_NIC_BUFFER_LENGTH]; - struct ieee80211_hdr_4addr header; + struct libipw_hdr_4addr header; u32 status; struct ipw2100_notification notification; struct ipw2100_cmd_header command; diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 8e18d534835..3617e3c1e9e 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -111,7 +111,7 @@ static int qos_no_ack_mask = 0; static int burst_duration_CCK = 0; static int burst_duration_OFDM = 0; -static struct ieee80211_qos_parameters def_qos_parameters_OFDM = { +static struct libipw_qos_parameters def_qos_parameters_OFDM = { {QOS_TX0_CW_MIN_OFDM, QOS_TX1_CW_MIN_OFDM, QOS_TX2_CW_MIN_OFDM, QOS_TX3_CW_MIN_OFDM}, {QOS_TX0_CW_MAX_OFDM, QOS_TX1_CW_MAX_OFDM, QOS_TX2_CW_MAX_OFDM, @@ -122,7 +122,7 @@ static struct ieee80211_qos_parameters def_qos_parameters_OFDM = { QOS_TX2_TXOP_LIMIT_OFDM, QOS_TX3_TXOP_LIMIT_OFDM} }; -static struct ieee80211_qos_parameters def_qos_parameters_CCK = { +static struct libipw_qos_parameters def_qos_parameters_CCK = { {QOS_TX0_CW_MIN_CCK, QOS_TX1_CW_MIN_CCK, QOS_TX2_CW_MIN_CCK, QOS_TX3_CW_MIN_CCK}, {QOS_TX0_CW_MAX_CCK, QOS_TX1_CW_MAX_CCK, QOS_TX2_CW_MAX_CCK, @@ -133,7 +133,7 @@ static struct ieee80211_qos_parameters def_qos_parameters_CCK = { QOS_TX3_TXOP_LIMIT_CCK} }; -static struct ieee80211_qos_parameters def_parameters_OFDM = { +static struct libipw_qos_parameters def_parameters_OFDM = { {DEF_TX0_CW_MIN_OFDM, DEF_TX1_CW_MIN_OFDM, DEF_TX2_CW_MIN_OFDM, DEF_TX3_CW_MIN_OFDM}, {DEF_TX0_CW_MAX_OFDM, DEF_TX1_CW_MAX_OFDM, DEF_TX2_CW_MAX_OFDM, @@ -144,7 +144,7 @@ static struct ieee80211_qos_parameters def_parameters_OFDM = { DEF_TX2_TXOP_LIMIT_OFDM, DEF_TX3_TXOP_LIMIT_OFDM} }; -static struct ieee80211_qos_parameters def_parameters_CCK = { +static struct libipw_qos_parameters def_parameters_CCK = { {DEF_TX0_CW_MIN_CCK, DEF_TX1_CW_MIN_CCK, DEF_TX2_CW_MIN_CCK, DEF_TX3_CW_MIN_CCK}, {DEF_TX0_CW_MAX_CCK, DEF_TX1_CW_MAX_CCK, DEF_TX2_CW_MAX_CCK, @@ -164,9 +164,9 @@ static int from_priority_to_tx_queue[] = { static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv); -static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters +static int ipw_send_qos_params_command(struct ipw_priv *priv, struct libipw_qos_parameters *qos_param); -static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element +static int ipw_send_qos_info_command(struct ipw_priv *priv, struct libipw_qos_information_element *qos_param); #endif /* CONFIG_IPW2200_QOS */ @@ -1830,7 +1830,7 @@ static ssize_t store_speed_scan(struct device *d, struct device_attribute *attr, break; } - if (ieee80211_is_valid_channel(priv->ieee, channel)) + if (libipw_is_valid_channel(priv->ieee, channel)) priv->speed_scan[pos++] = channel; else IPW_WARNING("Skipping invalid channel request: %d\n", @@ -1882,7 +1882,7 @@ static ssize_t show_channels(struct device *d, char *buf) { struct ipw_priv *priv = dev_get_drvdata(d); - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + const struct libipw_geo *geo = libipw_get_geo(priv->ieee); int len = 0, i; len = sprintf(&buf[len], @@ -1892,14 +1892,14 @@ static ssize_t show_channels(struct device *d, for (i = 0; i < geo->bg_channels; i++) { len += sprintf(&buf[len], "%d: BSS%s%s, %s, Band %s.\n", geo->bg[i].channel, - geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT ? + geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT ? " (radar spectrum)" : "", - ((geo->bg[i].flags & IEEE80211_CH_NO_IBSS) || - (geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT)) + ((geo->bg[i].flags & LIBIPW_CH_NO_IBSS) || + (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)) ? "" : ", IBSS", - geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY ? + geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY ? "passive only" : "active/passive", - geo->bg[i].flags & IEEE80211_CH_B_ONLY ? + geo->bg[i].flags & LIBIPW_CH_B_ONLY ? "B" : "B/G"); } @@ -1909,12 +1909,12 @@ static ssize_t show_channels(struct device *d, for (i = 0; i < geo->a_channels; i++) { len += sprintf(&buf[len], "%d: BSS%s%s, %s.\n", geo->a[i].channel, - geo->a[i].flags & IEEE80211_CH_RADAR_DETECT ? + geo->a[i].flags & LIBIPW_CH_RADAR_DETECT ? " (radar spectrum)" : "", - ((geo->a[i].flags & IEEE80211_CH_NO_IBSS) || - (geo->a[i].flags & IEEE80211_CH_RADAR_DETECT)) + ((geo->a[i].flags & LIBIPW_CH_NO_IBSS) || + (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT)) ? "" : ", IBSS", - geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY ? + geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY ? "passive only" : "active/passive"); } @@ -2429,7 +2429,7 @@ static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power) static int ipw_set_tx_power(struct ipw_priv *priv) { - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + const struct libipw_geo *geo = libipw_get_geo(priv->ieee); struct ipw_tx_power tx_power; s8 max_power; int i; @@ -2960,12 +2960,12 @@ static int ipw_fw_dma_wait(struct ipw_priv *priv) static void ipw_remove_current_network(struct ipw_priv *priv) { struct list_head *element, *safe; - struct ieee80211_network *network = NULL; + struct libipw_network *network = NULL; unsigned long flags; spin_lock_irqsave(&priv->ieee->lock, flags); list_for_each_safe(element, safe, &priv->ieee->network_list) { - network = list_entry(element, struct ieee80211_network, list); + network = list_entry(element, struct libipw_network, list); if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { list_del(element); list_add_tail(&network->list, @@ -3751,7 +3751,7 @@ static void ipw_queue_tx_free_tfd(struct ipw_priv *priv, le16_to_cpu(bd->u.data.chunk_len[i]), PCI_DMA_TODEVICE); if (txq->txb[txq->q.last_used]) { - ieee80211_txb_free(txq->txb[txq->q.last_used]); + libipw_txb_free(txq->txb[txq->q.last_used]); txq->txb[txq->q.last_used] = NULL; } } @@ -4070,7 +4070,7 @@ static u32 ipw_get_max_rate(struct ipw_priv *priv) /* If currently associated in B mode, restrict the maximum * rate match to B rates */ if (priv->assoc_request.ieee_mode == IPW_B_MODE) - mask &= IEEE80211_CCK_RATES_MASK; + mask &= LIBIPW_CCK_RATES_MASK; /* TODO: Verify that the rate is supported by the current rates * list. */ @@ -4078,29 +4078,29 @@ static u32 ipw_get_max_rate(struct ipw_priv *priv) while (i && !(mask & i)) i >>= 1; switch (i) { - case IEEE80211_CCK_RATE_1MB_MASK: + case LIBIPW_CCK_RATE_1MB_MASK: return 1000000; - case IEEE80211_CCK_RATE_2MB_MASK: + case LIBIPW_CCK_RATE_2MB_MASK: return 2000000; - case IEEE80211_CCK_RATE_5MB_MASK: + case LIBIPW_CCK_RATE_5MB_MASK: return 5500000; - case IEEE80211_OFDM_RATE_6MB_MASK: + case LIBIPW_OFDM_RATE_6MB_MASK: return 6000000; - case IEEE80211_OFDM_RATE_9MB_MASK: + case LIBIPW_OFDM_RATE_9MB_MASK: return 9000000; - case IEEE80211_CCK_RATE_11MB_MASK: + case LIBIPW_CCK_RATE_11MB_MASK: return 11000000; - case IEEE80211_OFDM_RATE_12MB_MASK: + case LIBIPW_OFDM_RATE_12MB_MASK: return 12000000; - case IEEE80211_OFDM_RATE_18MB_MASK: + case LIBIPW_OFDM_RATE_18MB_MASK: return 18000000; - case IEEE80211_OFDM_RATE_24MB_MASK: + case LIBIPW_OFDM_RATE_24MB_MASK: return 24000000; - case IEEE80211_OFDM_RATE_36MB_MASK: + case LIBIPW_OFDM_RATE_36MB_MASK: return 36000000; - case IEEE80211_OFDM_RATE_48MB_MASK: + case LIBIPW_OFDM_RATE_48MB_MASK: return 48000000; - case IEEE80211_OFDM_RATE_54MB_MASK: + case LIBIPW_OFDM_RATE_54MB_MASK: return 54000000; } @@ -4466,11 +4466,11 @@ static void ipw_rx_notification(struct ipw_priv *priv, == IEEE80211_STYPE_ASSOC_RESP)) { if ((sizeof (struct - ieee80211_assoc_response) + libipw_assoc_response) <= size) && (size <= 2314)) { struct - ieee80211_rx_stats + libipw_rx_stats stats = { .len = size - 1, }; @@ -4478,10 +4478,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG_QOS ("QoS Associate " "size %d\n", size); - ieee80211_rx_mgt(priv-> + libipw_rx_mgt(priv-> ieee, (struct - ieee80211_hdr_4addr + libipw_hdr_4addr *) ¬if->u.raw, &stats); } @@ -4537,11 +4537,11 @@ static void ipw_rx_notification(struct ipw_priv *priv, case CMAS_INIT:{ if (priv->status & STATUS_AUTH) { struct - ieee80211_assoc_response + libipw_assoc_response *resp; resp = (struct - ieee80211_assoc_response + libipw_assoc_response *)¬if->u.raw; IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | @@ -5227,33 +5227,33 @@ static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *priv) static int ipw_is_rate_in_mask(struct ipw_priv *priv, int ieee_mode, u8 rate) { - rate &= ~IEEE80211_BASIC_RATE_MASK; + rate &= ~LIBIPW_BASIC_RATE_MASK; if (ieee_mode == IEEE_A) { switch (rate) { - case IEEE80211_OFDM_RATE_6MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_6MB_MASK ? + case LIBIPW_OFDM_RATE_6MB: + return priv->rates_mask & LIBIPW_OFDM_RATE_6MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_9MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_9MB_MASK ? + case LIBIPW_OFDM_RATE_9MB: + return priv->rates_mask & LIBIPW_OFDM_RATE_9MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_12MB: + case LIBIPW_OFDM_RATE_12MB: return priv-> - rates_mask & IEEE80211_OFDM_RATE_12MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_18MB: + rates_mask & LIBIPW_OFDM_RATE_12MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_18MB: return priv-> - rates_mask & IEEE80211_OFDM_RATE_18MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_24MB: + rates_mask & LIBIPW_OFDM_RATE_18MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_24MB: return priv-> - rates_mask & IEEE80211_OFDM_RATE_24MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_36MB: + rates_mask & LIBIPW_OFDM_RATE_24MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_36MB: return priv-> - rates_mask & IEEE80211_OFDM_RATE_36MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_48MB: + rates_mask & LIBIPW_OFDM_RATE_36MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_48MB: return priv-> - rates_mask & IEEE80211_OFDM_RATE_48MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_54MB: + rates_mask & LIBIPW_OFDM_RATE_48MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_54MB: return priv-> - rates_mask & IEEE80211_OFDM_RATE_54MB_MASK ? 1 : 0; + rates_mask & LIBIPW_OFDM_RATE_54MB_MASK ? 1 : 0; default: return 0; } @@ -5261,14 +5261,14 @@ static int ipw_is_rate_in_mask(struct ipw_priv *priv, int ieee_mode, u8 rate) /* B and G mixed */ switch (rate) { - case IEEE80211_CCK_RATE_1MB: - return priv->rates_mask & IEEE80211_CCK_RATE_1MB_MASK ? 1 : 0; - case IEEE80211_CCK_RATE_2MB: - return priv->rates_mask & IEEE80211_CCK_RATE_2MB_MASK ? 1 : 0; - case IEEE80211_CCK_RATE_5MB: - return priv->rates_mask & IEEE80211_CCK_RATE_5MB_MASK ? 1 : 0; - case IEEE80211_CCK_RATE_11MB: - return priv->rates_mask & IEEE80211_CCK_RATE_11MB_MASK ? 1 : 0; + case LIBIPW_CCK_RATE_1MB: + return priv->rates_mask & LIBIPW_CCK_RATE_1MB_MASK ? 1 : 0; + case LIBIPW_CCK_RATE_2MB: + return priv->rates_mask & LIBIPW_CCK_RATE_2MB_MASK ? 1 : 0; + case LIBIPW_CCK_RATE_5MB: + return priv->rates_mask & LIBIPW_CCK_RATE_5MB_MASK ? 1 : 0; + case LIBIPW_CCK_RATE_11MB: + return priv->rates_mask & LIBIPW_CCK_RATE_11MB_MASK ? 1 : 0; } /* If we are limited to B modulations, bail at this point */ @@ -5277,29 +5277,29 @@ static int ipw_is_rate_in_mask(struct ipw_priv *priv, int ieee_mode, u8 rate) /* G */ switch (rate) { - case IEEE80211_OFDM_RATE_6MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_6MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_9MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_9MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_12MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_12MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_18MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_18MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_24MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_24MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_36MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_36MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_48MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_48MB_MASK ? 1 : 0; - case IEEE80211_OFDM_RATE_54MB: - return priv->rates_mask & IEEE80211_OFDM_RATE_54MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_6MB: + return priv->rates_mask & LIBIPW_OFDM_RATE_6MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_9MB: + return priv->rates_mask & LIBIPW_OFDM_RATE_9MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_12MB: + return priv->rates_mask & LIBIPW_OFDM_RATE_12MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_18MB: + return priv->rates_mask & LIBIPW_OFDM_RATE_18MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_24MB: + return priv->rates_mask & LIBIPW_OFDM_RATE_24MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_36MB: + return priv->rates_mask & LIBIPW_OFDM_RATE_36MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_48MB: + return priv->rates_mask & LIBIPW_OFDM_RATE_48MB_MASK ? 1 : 0; + case LIBIPW_OFDM_RATE_54MB: + return priv->rates_mask & LIBIPW_OFDM_RATE_54MB_MASK ? 1 : 0; } return 0; } static int ipw_compatible_rates(struct ipw_priv *priv, - const struct ieee80211_network *network, + const struct libipw_network *network, struct ipw_supported_rates *rates) { int num_rates, i; @@ -5311,7 +5311,7 @@ static int ipw_compatible_rates(struct ipw_priv *priv, if (!ipw_is_rate_in_mask(priv, network->mode, network->rates[i])) { - if (network->rates[i] & IEEE80211_BASIC_RATE_MASK) { + if (network->rates[i] & LIBIPW_BASIC_RATE_MASK) { IPW_DEBUG_SCAN("Adding masked mandatory " "rate %02X\n", network->rates[i]); @@ -5333,7 +5333,7 @@ static int ipw_compatible_rates(struct ipw_priv *priv, for (i = 0; i < num_rates; i++) { if (!ipw_is_rate_in_mask(priv, network->mode, network->rates_ex[i])) { - if (network->rates_ex[i] & IEEE80211_BASIC_RATE_MASK) { + if (network->rates_ex[i] & LIBIPW_BASIC_RATE_MASK) { IPW_DEBUG_SCAN("Adding masked mandatory " "rate %02X\n", network->rates_ex[i]); @@ -5369,73 +5369,73 @@ static void ipw_copy_rates(struct ipw_supported_rates *dest, static void ipw_add_cck_scan_rates(struct ipw_supported_rates *rates, u8 modulation, u32 rate_mask) { - u8 basic_mask = (IEEE80211_OFDM_MODULATION == modulation) ? - IEEE80211_BASIC_RATE_MASK : 0; + u8 basic_mask = (LIBIPW_OFDM_MODULATION == modulation) ? + LIBIPW_BASIC_RATE_MASK : 0; - if (rate_mask & IEEE80211_CCK_RATE_1MB_MASK) + if (rate_mask & LIBIPW_CCK_RATE_1MB_MASK) rates->supported_rates[rates->num_rates++] = - IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; + LIBIPW_BASIC_RATE_MASK | LIBIPW_CCK_RATE_1MB; - if (rate_mask & IEEE80211_CCK_RATE_2MB_MASK) + if (rate_mask & LIBIPW_CCK_RATE_2MB_MASK) rates->supported_rates[rates->num_rates++] = - IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; + LIBIPW_BASIC_RATE_MASK | LIBIPW_CCK_RATE_2MB; - if (rate_mask & IEEE80211_CCK_RATE_5MB_MASK) + if (rate_mask & LIBIPW_CCK_RATE_5MB_MASK) rates->supported_rates[rates->num_rates++] = basic_mask | - IEEE80211_CCK_RATE_5MB; + LIBIPW_CCK_RATE_5MB; - if (rate_mask & IEEE80211_CCK_RATE_11MB_MASK) + if (rate_mask & LIBIPW_CCK_RATE_11MB_MASK) rates->supported_rates[rates->num_rates++] = basic_mask | - IEEE80211_CCK_RATE_11MB; + LIBIPW_CCK_RATE_11MB; } static void ipw_add_ofdm_scan_rates(struct ipw_supported_rates *rates, u8 modulation, u32 rate_mask) { - u8 basic_mask = (IEEE80211_OFDM_MODULATION == modulation) ? - IEEE80211_BASIC_RATE_MASK : 0; + u8 basic_mask = (LIBIPW_OFDM_MODULATION == modulation) ? + LIBIPW_BASIC_RATE_MASK : 0; - if (rate_mask & IEEE80211_OFDM_RATE_6MB_MASK) + if (rate_mask & LIBIPW_OFDM_RATE_6MB_MASK) rates->supported_rates[rates->num_rates++] = basic_mask | - IEEE80211_OFDM_RATE_6MB; + LIBIPW_OFDM_RATE_6MB; - if (rate_mask & IEEE80211_OFDM_RATE_9MB_MASK) + if (rate_mask & LIBIPW_OFDM_RATE_9MB_MASK) rates->supported_rates[rates->num_rates++] = - IEEE80211_OFDM_RATE_9MB; + LIBIPW_OFDM_RATE_9MB; - if (rate_mask & IEEE80211_OFDM_RATE_12MB_MASK) + if (rate_mask & LIBIPW_OFDM_RATE_12MB_MASK) rates->supported_rates[rates->num_rates++] = basic_mask | - IEEE80211_OFDM_RATE_12MB; + LIBIPW_OFDM_RATE_12MB; - if (rate_mask & IEEE80211_OFDM_RATE_18MB_MASK) + if (rate_mask & LIBIPW_OFDM_RATE_18MB_MASK) rates->supported_rates[rates->num_rates++] = - IEEE80211_OFDM_RATE_18MB; + LIBIPW_OFDM_RATE_18MB; - if (rate_mask & IEEE80211_OFDM_RATE_24MB_MASK) + if (rate_mask & LIBIPW_OFDM_RATE_24MB_MASK) rates->supported_rates[rates->num_rates++] = basic_mask | - IEEE80211_OFDM_RATE_24MB; + LIBIPW_OFDM_RATE_24MB; - if (rate_mask & IEEE80211_OFDM_RATE_36MB_MASK) + if (rate_mask & LIBIPW_OFDM_RATE_36MB_MASK) rates->supported_rates[rates->num_rates++] = - IEEE80211_OFDM_RATE_36MB; + LIBIPW_OFDM_RATE_36MB; - if (rate_mask & IEEE80211_OFDM_RATE_48MB_MASK) + if (rate_mask & LIBIPW_OFDM_RATE_48MB_MASK) rates->supported_rates[rates->num_rates++] = - IEEE80211_OFDM_RATE_48MB; + LIBIPW_OFDM_RATE_48MB; - if (rate_mask & IEEE80211_OFDM_RATE_54MB_MASK) + if (rate_mask & LIBIPW_OFDM_RATE_54MB_MASK) rates->supported_rates[rates->num_rates++] = - IEEE80211_OFDM_RATE_54MB; + LIBIPW_OFDM_RATE_54MB; } struct ipw_network_match { - struct ieee80211_network *network; + struct libipw_network *network; struct ipw_supported_rates rates; }; static int ipw_find_adhoc_network(struct ipw_priv *priv, struct ipw_network_match *match, - struct ieee80211_network *network, + struct libipw_network *network, int roaming) { struct ipw_supported_rates rates; @@ -5556,7 +5556,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, } /* Filter out any incompatible freq / mode combinations */ - if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { + if (!libipw_is_valid_mode(priv->ieee, network->mode)) { IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of invalid frequency/mode " "combination.\n", @@ -5606,7 +5606,7 @@ static void ipw_merge_adhoc_network(struct work_struct *work) DECLARE_SSID_BUF(ssid); struct ipw_priv *priv = container_of(work, struct ipw_priv, merge_networks); - struct ieee80211_network *network = NULL; + struct libipw_network *network = NULL; struct ipw_network_match match = { .network = priv->assoc_network }; @@ -5648,7 +5648,7 @@ static void ipw_merge_adhoc_network(struct work_struct *work) static int ipw_best_network(struct ipw_priv *priv, struct ipw_network_match *match, - struct ieee80211_network *network, int roaming) + struct libipw_network *network, int roaming) { struct ipw_supported_rates rates; DECLARE_SSID_BUF(ssid); @@ -5782,7 +5782,7 @@ static int ipw_best_network(struct ipw_priv *priv, } /* Filter out any incompatible freq / mode combinations */ - if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { + if (!libipw_is_valid_mode(priv->ieee, network->mode)) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of invalid frequency/mode " "combination.\n", @@ -5793,7 +5793,7 @@ static int ipw_best_network(struct ipw_priv *priv, } /* Filter out invalid channel in current GEO */ - if (!ieee80211_is_valid_channel(priv->ieee, network->channel)) { + if (!libipw_is_valid_channel(priv->ieee, network->channel)) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of invalid channel in current GEO\n", print_ssid(ssid, network->ssid, @@ -5839,9 +5839,9 @@ static int ipw_best_network(struct ipw_priv *priv, } static void ipw_adhoc_create(struct ipw_priv *priv, - struct ieee80211_network *network) + struct libipw_network *network) { - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + const struct libipw_geo *geo = libipw_get_geo(priv->ieee); int i; /* @@ -5856,25 +5856,25 @@ static void ipw_adhoc_create(struct ipw_priv *priv, * FW fatal error. * */ - switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { - case IEEE80211_52GHZ_BAND: + switch (libipw_is_valid_channel(priv->ieee, priv->channel)) { + case LIBIPW_52GHZ_BAND: network->mode = IEEE_A; - i = ieee80211_channel_to_index(priv->ieee, priv->channel); + i = libipw_channel_to_index(priv->ieee, priv->channel); BUG_ON(i == -1); - if (geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY) { + if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY) { IPW_WARNING("Overriding invalid channel\n"); priv->channel = geo->a[0].channel; } break; - case IEEE80211_24GHZ_BAND: + case LIBIPW_24GHZ_BAND: if (priv->ieee->mode & IEEE_G) network->mode = IEEE_G; else network->mode = IEEE_B; - i = ieee80211_channel_to_index(priv->ieee, priv->channel); + i = libipw_channel_to_index(priv->ieee, priv->channel); BUG_ON(i == -1); - if (geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY) { + if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY) { IPW_WARNING("Overriding invalid channel\n"); priv->channel = geo->bg[0].channel; } @@ -6110,9 +6110,9 @@ static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode) * Tx rates */ switch (priv->ieee->freq_band) { - case IEEE80211_52GHZ_BAND: /* A only */ + case LIBIPW_52GHZ_BAND: /* A only */ /* IEEE_A */ - if (priv->rates_mask & ~IEEE80211_OFDM_RATES_MASK) { + if (priv->rates_mask & ~LIBIPW_OFDM_RATES_MASK) { /* Invalid fixed rate mask */ IPW_DEBUG_WX ("invalid fixed rate mask in ipw_set_fixed_rate\n"); @@ -6120,13 +6120,13 @@ static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode) break; } - new_tx_rates >>= IEEE80211_OFDM_SHIFT_MASK_A; + new_tx_rates >>= LIBIPW_OFDM_SHIFT_MASK_A; break; default: /* 2.4Ghz or Mixed */ /* IEEE_B */ if (mode == IEEE_B) { - if (new_tx_rates & ~IEEE80211_CCK_RATES_MASK) { + if (new_tx_rates & ~LIBIPW_CCK_RATES_MASK) { /* Invalid fixed rate mask */ IPW_DEBUG_WX ("invalid fixed rate mask in ipw_set_fixed_rate\n"); @@ -6136,8 +6136,8 @@ static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode) } /* IEEE_G */ - if (new_tx_rates & ~(IEEE80211_CCK_RATES_MASK | - IEEE80211_OFDM_RATES_MASK)) { + if (new_tx_rates & ~(LIBIPW_CCK_RATES_MASK | + LIBIPW_OFDM_RATES_MASK)) { /* Invalid fixed rate mask */ IPW_DEBUG_WX ("invalid fixed rate mask in ipw_set_fixed_rate\n"); @@ -6145,19 +6145,19 @@ static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode) break; } - if (IEEE80211_OFDM_RATE_6MB_MASK & new_tx_rates) { - mask |= (IEEE80211_OFDM_RATE_6MB_MASK >> 1); - new_tx_rates &= ~IEEE80211_OFDM_RATE_6MB_MASK; + if (LIBIPW_OFDM_RATE_6MB_MASK & new_tx_rates) { + mask |= (LIBIPW_OFDM_RATE_6MB_MASK >> 1); + new_tx_rates &= ~LIBIPW_OFDM_RATE_6MB_MASK; } - if (IEEE80211_OFDM_RATE_9MB_MASK & new_tx_rates) { - mask |= (IEEE80211_OFDM_RATE_9MB_MASK >> 1); - new_tx_rates &= ~IEEE80211_OFDM_RATE_9MB_MASK; + if (LIBIPW_OFDM_RATE_9MB_MASK & new_tx_rates) { + mask |= (LIBIPW_OFDM_RATE_9MB_MASK >> 1); + new_tx_rates &= ~LIBIPW_OFDM_RATE_9MB_MASK; } - if (IEEE80211_OFDM_RATE_12MB_MASK & new_tx_rates) { - mask |= (IEEE80211_OFDM_RATE_12MB_MASK >> 1); - new_tx_rates &= ~IEEE80211_OFDM_RATE_12MB_MASK; + if (LIBIPW_OFDM_RATE_12MB_MASK & new_tx_rates) { + mask |= (LIBIPW_OFDM_RATE_12MB_MASK >> 1); + new_tx_rates &= ~LIBIPW_OFDM_RATE_12MB_MASK; } new_tx_rates |= mask; @@ -6190,12 +6190,12 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, int scan_type) { int channel_index = 0; - const struct ieee80211_geo *geo; + const struct libipw_geo *geo; int i; - geo = ieee80211_get_geo(priv->ieee); + geo = libipw_get_geo(priv->ieee); - if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) { + if (priv->ieee->freq_band & LIBIPW_52GHZ_BAND) { int start = channel_index; for (i = 0; i < geo->a_channels; i++) { if ((priv->status & STATUS_ASSOCIATED) && @@ -6205,7 +6205,7 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, scan->channels_list[channel_index] = geo->a[i].channel; ipw_set_scan_type(scan, channel_index, geo->a[i]. - flags & IEEE80211_CH_PASSIVE_ONLY ? + flags & LIBIPW_CH_PASSIVE_ONLY ? IPW_SCAN_PASSIVE_FULL_DWELL_SCAN : scan_type); } @@ -6217,11 +6217,11 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, } } - if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) { + if (priv->ieee->freq_band & LIBIPW_24GHZ_BAND) { int start = channel_index; if (priv->config & CFG_SPEED_SCAN) { int index; - u8 channels[IEEE80211_24GHZ_CHANNELS] = { + u8 channels[LIBIPW_24GHZ_CHANNELS] = { /* nop out the list */ [0] = 0 }; @@ -6253,11 +6253,11 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, channel_index++; scan->channels_list[channel_index] = channel; index = - ieee80211_channel_to_index(priv->ieee, channel); + libipw_channel_to_index(priv->ieee, channel); ipw_set_scan_type(scan, channel_index, geo->bg[index]. flags & - IEEE80211_CH_PASSIVE_ONLY ? + LIBIPW_CH_PASSIVE_ONLY ? IPW_SCAN_PASSIVE_FULL_DWELL_SCAN : scan_type); } @@ -6272,7 +6272,7 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, ipw_set_scan_type(scan, channel_index, geo->bg[i]. flags & - IEEE80211_CH_PASSIVE_ONLY ? + LIBIPW_CH_PASSIVE_ONLY ? IPW_SCAN_PASSIVE_FULL_DWELL_SCAN : scan_type); } @@ -6339,7 +6339,7 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct) } memset(&scan, 0, sizeof(scan)); - scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee)); + scan.full_scan_index = cpu_to_le32(libipw_get_scans(priv->ieee)); if (type == IW_SCAN_TYPE_PASSIVE) { IPW_DEBUG_WX("use passive scanning\n"); @@ -6370,13 +6370,13 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct) u8 channel; u8 band = 0; - switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { - case IEEE80211_52GHZ_BAND: + switch (libipw_is_valid_channel(priv->ieee, priv->channel)) { + case LIBIPW_52GHZ_BAND: band = (u8) (IPW_A_MODE << 6) | 1; channel = priv->channel; break; - case IEEE80211_24GHZ_BAND: + case LIBIPW_24GHZ_BAND: band = (u8) (IPW_B_MODE << 6) | 1; channel = priv->channel; break; @@ -6497,8 +6497,8 @@ static int ipw_wpa_enable(struct ipw_priv *priv, int value) static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value) { - struct ieee80211_device *ieee = priv->ieee; - struct ieee80211_security sec = { + struct libipw_device *ieee = priv->ieee; + struct libipw_security sec = { .flags = SEC_AUTH_MODE, }; int ret = 0; @@ -6548,8 +6548,8 @@ static int ipw_wx_set_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; + struct ipw_priv *priv = libipw_priv(dev); + struct libipw_device *ieee = priv->ieee; u8 *buf; int err = 0; @@ -6584,8 +6584,8 @@ static int ipw_wx_get_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; + struct ipw_priv *priv = libipw_priv(dev); + struct libipw_device *ieee = priv->ieee; int err = 0; if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) { @@ -6627,8 +6627,8 @@ static int ipw_wx_set_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; + struct ipw_priv *priv = libipw_priv(dev); + struct libipw_device *ieee = priv->ieee; struct iw_param *param = &wrqu->param; struct lib80211_crypt_data *crypt; unsigned long flags; @@ -6679,7 +6679,7 @@ static int ipw_wx_set_auth(struct net_device *dev, * can use this to determine if the CAP_PRIVACY_ON bit should * be set. */ - struct ieee80211_security sec = { + struct libipw_security sec = { .flags = SEC_ENABLED, .enabled = param->value, }; @@ -6727,8 +6727,8 @@ static int ipw_wx_get_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; + struct ipw_priv *priv = libipw_priv(dev); + struct libipw_device *ieee = priv->ieee; struct lib80211_crypt_data *crypt; struct iw_param *param = &wrqu->param; int ret = 0; @@ -6786,7 +6786,7 @@ static int ipw_wx_set_encodeext(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; if (hwcrypto) { @@ -6808,7 +6808,7 @@ static int ipw_wx_set_encodeext(struct net_device *dev, } } - return ieee80211_wx_set_encodeext(priv->ieee, info, wrqu, extra); + return libipw_wx_set_encodeext(priv->ieee, info, wrqu, extra); } /* SIOCGIWENCODEEXT */ @@ -6816,8 +6816,8 @@ static int ipw_wx_get_encodeext(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_encodeext(priv->ieee, info, wrqu, extra); + struct ipw_priv *priv = libipw_priv(dev); + return libipw_wx_get_encodeext(priv->ieee, info, wrqu, extra); } /* SIOCSIWMLME */ @@ -6825,7 +6825,7 @@ static int ipw_wx_set_mlme(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); struct iw_mlme *mlme = (struct iw_mlme *)extra; __le16 reason; @@ -6875,9 +6875,9 @@ static u8 ipw_qos_current_mode(struct ipw_priv * priv) */ static int ipw_qos_handle_probe_response(struct ipw_priv *priv, int active_network, - struct ieee80211_network *network) + struct libipw_network *network) { - u32 size = sizeof(struct ieee80211_qos_parameters); + u32 size = sizeof(struct libipw_qos_parameters); if (network->capability & WLAN_CAPABILITY_IBSS) network->qos_data.active = network->qos_data.supported; @@ -6935,12 +6935,12 @@ static int ipw_qos_handle_probe_response(struct ipw_priv *priv, * IPW_CMD_QOS_PARAMETERS and IPW_CMD_WME_INFO */ static int ipw_qos_activate(struct ipw_priv *priv, - struct ieee80211_qos_data *qos_network_data) + struct libipw_qos_data *qos_network_data) { int err; - struct ieee80211_qos_parameters qos_parameters[QOS_QOS_SETS]; - struct ieee80211_qos_parameters *active_one = NULL; - u32 size = sizeof(struct ieee80211_qos_parameters); + struct libipw_qos_parameters qos_parameters[QOS_QOS_SETS]; + struct libipw_qos_parameters *active_one = NULL; + u32 size = sizeof(struct libipw_qos_parameters); u32 burst_duration; int i; u8 type; @@ -7001,7 +7001,7 @@ static int ipw_qos_activate(struct ipw_priv *priv, IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n"); err = ipw_send_qos_params_command(priv, - (struct ieee80211_qos_parameters *) + (struct libipw_qos_parameters *) &(qos_parameters[0])); if (err) IPW_DEBUG_QOS("QoS IPW_CMD_QOS_PARAMETERS failed\n"); @@ -7015,13 +7015,13 @@ static int ipw_qos_activate(struct ipw_priv *priv, static int ipw_qos_set_info_element(struct ipw_priv *priv) { int ret = 0; - struct ieee80211_qos_information_element qos_info; + struct libipw_qos_information_element qos_info; if (priv == NULL) return -1; qos_info.elementID = QOS_ELEMENT_ID; - qos_info.length = sizeof(struct ieee80211_qos_information_element) - 2; + qos_info.length = sizeof(struct libipw_qos_information_element) - 2; qos_info.version = QOS_VERSION_1; qos_info.ac_info = 0; @@ -7041,11 +7041,11 @@ static int ipw_qos_set_info_element(struct ipw_priv *priv) * Set the QoS parameter with the association request structure */ static int ipw_qos_association(struct ipw_priv *priv, - struct ieee80211_network *network) + struct libipw_network *network) { int err = 0; - struct ieee80211_qos_data *qos_data = NULL; - struct ieee80211_qos_data ibss_data = { + struct libipw_qos_data *qos_data = NULL; + struct libipw_qos_data ibss_data = { .supported = 1, .active = 1, }; @@ -7087,11 +7087,11 @@ static int ipw_qos_association(struct ipw_priv *priv, * setting */ static int ipw_qos_association_resp(struct ipw_priv *priv, - struct ieee80211_network *network) + struct libipw_network *network) { int ret = 0; unsigned long flags; - u32 size = sizeof(struct ieee80211_qos_parameters); + u32 size = sizeof(struct libipw_qos_parameters); int set_qos_param = 0; if ((priv == NULL) || (network == NULL) || @@ -7107,7 +7107,7 @@ static int ipw_qos_association_resp(struct ipw_priv *priv, spin_lock_irqsave(&priv->ieee->lock, flags); if (network->flags & NETWORK_HAS_QOS_PARAMETERS) { memcpy(&priv->assoc_network->qos_data, &network->qos_data, - sizeof(struct ieee80211_qos_data)); + sizeof(struct libipw_qos_data)); priv->assoc_network->qos_data.active = 1; if ((network->qos_data.old_param_count != network->qos_data.param_count)) { @@ -7143,7 +7143,7 @@ static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv) if ((priv == NULL)) return 0; - if (!(priv->ieee->modulation & IEEE80211_OFDM_MODULATION)) + if (!(priv->ieee->modulation & LIBIPW_OFDM_MODULATION)) ret = priv->qos_data.burst_duration_CCK; else ret = priv->qos_data.burst_duration_OFDM; @@ -7195,8 +7195,8 @@ static int ipw_get_tx_queue_number(struct ipw_priv *priv, u16 priority) static int ipw_is_qos_active(struct net_device *dev, struct sk_buff *skb) { - struct ipw_priv *priv = ieee80211_priv(dev); - struct ieee80211_qos_data *qos_data = NULL; + struct ipw_priv *priv = libipw_priv(dev); + struct libipw_qos_data *qos_data = NULL; int active, supported; u8 *daddr = skb->data + ETH_ALEN; int unicast = !is_multicast_ether_addr(daddr); @@ -7260,10 +7260,10 @@ static void ipw_bg_qos_activate(struct work_struct *work) } static int ipw_handle_probe_response(struct net_device *dev, - struct ieee80211_probe_response *resp, - struct ieee80211_network *network) + struct libipw_probe_response *resp, + struct libipw_network *network) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int active_network = ((priv->status & STATUS_ASSOCIATED) && (network == priv->assoc_network)); @@ -7273,10 +7273,10 @@ static int ipw_handle_probe_response(struct net_device *dev, } static int ipw_handle_beacon(struct net_device *dev, - struct ieee80211_beacon *resp, - struct ieee80211_network *network) + struct libipw_beacon *resp, + struct libipw_network *network) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int active_network = ((priv->status & STATUS_ASSOCIATED) && (network == priv->assoc_network)); @@ -7286,22 +7286,22 @@ static int ipw_handle_beacon(struct net_device *dev, } static int ipw_handle_assoc_response(struct net_device *dev, - struct ieee80211_assoc_response *resp, - struct ieee80211_network *network) + struct libipw_assoc_response *resp, + struct libipw_network *network) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); ipw_qos_association_resp(priv, network); return 0; } -static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters +static int ipw_send_qos_params_command(struct ipw_priv *priv, struct libipw_qos_parameters *qos_param) { return ipw_send_cmd_pdu(priv, IPW_CMD_QOS_PARAMETERS, sizeof(*qos_param) * 3, qos_param); } -static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element +static int ipw_send_qos_info_command(struct ipw_priv *priv, struct libipw_qos_information_element *qos_param) { return ipw_send_cmd_pdu(priv, IPW_CMD_WME_INFO, sizeof(*qos_param), @@ -7311,7 +7311,7 @@ static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos #endif /* CONFIG_IPW2200_QOS */ static int ipw_associate_network(struct ipw_priv *priv, - struct ieee80211_network *network, + struct libipw_network *network, struct ipw_supported_rates *rates, int roaming) { int err; @@ -7493,7 +7493,7 @@ static int ipw_associate_network(struct ipw_priv *priv, static void ipw_roam(void *data) { struct ipw_priv *priv = data; - struct ieee80211_network *network = NULL; + struct libipw_network *network = NULL; struct ipw_network_match match = { .network = priv->assoc_network }; @@ -7568,7 +7568,7 @@ static int ipw_associate(void *data) { struct ipw_priv *priv = data; - struct ieee80211_network *network = NULL; + struct libipw_network *network = NULL; struct ipw_network_match match = { .network = NULL }; @@ -7622,8 +7622,8 @@ static int ipw_associate(void *data) priv->config & CFG_STATIC_CHANNEL) { /* Use oldest network if the free list is empty */ if (list_empty(&priv->ieee->network_free_list)) { - struct ieee80211_network *oldest = NULL; - struct ieee80211_network *target; + struct libipw_network *oldest = NULL; + struct libipw_network *target; list_for_each_entry(target, &priv->ieee->network_list, list) { if ((oldest == NULL) || @@ -7644,7 +7644,7 @@ static int ipw_associate(void *data) } element = priv->ieee->network_free_list.next; - network = list_entry(element, struct ieee80211_network, list); + network = list_entry(element, struct libipw_network, list); ipw_adhoc_create(priv, network); rates = &priv->rates; list_del(element); @@ -7700,18 +7700,18 @@ static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv, switch (priv->ieee->sec.level) { case SEC_LEVEL_3: /* Remove CCMP HDR */ - memmove(skb->data + IEEE80211_3ADDR_LEN, - skb->data + IEEE80211_3ADDR_LEN + 8, - skb->len - IEEE80211_3ADDR_LEN - 8); + memmove(skb->data + LIBIPW_3ADDR_LEN, + skb->data + LIBIPW_3ADDR_LEN + 8, + skb->len - LIBIPW_3ADDR_LEN - 8); skb_trim(skb, skb->len - 16); /* CCMP_HDR_LEN + CCMP_MIC_LEN */ break; case SEC_LEVEL_2: break; case SEC_LEVEL_1: /* Remove IV */ - memmove(skb->data + IEEE80211_3ADDR_LEN, - skb->data + IEEE80211_3ADDR_LEN + 4, - skb->len - IEEE80211_3ADDR_LEN - 4); + memmove(skb->data + LIBIPW_3ADDR_LEN, + skb->data + LIBIPW_3ADDR_LEN + 4, + skb->len - LIBIPW_3ADDR_LEN - 4); skb_trim(skb, skb->len - 8); /* IV + ICV */ break; case SEC_LEVEL_0: @@ -7725,10 +7725,10 @@ static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv, static void ipw_handle_data_packet(struct ipw_priv *priv, struct ipw_rx_mem_buffer *rxb, - struct ieee80211_rx_stats *stats) + struct libipw_rx_stats *stats) { struct net_device *dev = priv->net_dev; - struct ieee80211_hdr_4addr *hdr; + struct libipw_hdr_4addr *hdr; struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data; /* We received data from the HW, so stop the watchdog */ @@ -7758,15 +7758,15 @@ static void ipw_handle_data_packet(struct ipw_priv *priv, IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); /* HW decrypt will not clear the WEP bit, MIC, PN, etc. */ - hdr = (struct ieee80211_hdr_4addr *)rxb->skb->data; + hdr = (struct libipw_hdr_4addr *)rxb->skb->data; if (priv->ieee->iw_mode != IW_MODE_MONITOR && (is_multicast_ether_addr(hdr->addr1) ? !priv->ieee->host_mc_decrypt : !priv->ieee->host_decrypt)) ipw_rebuild_decrypted_skb(priv, rxb->skb); - if (!ieee80211_rx(priv->ieee, rxb->skb, stats)) + if (!libipw_rx(priv->ieee, rxb->skb, stats)) dev->stats.rx_errors++; - else { /* ieee80211_rx succeeded, so it now owns the SKB */ + else { /* libipw_rx succeeded, so it now owns the SKB */ rxb->skb = NULL; __ipw_led_activity_on(priv); } @@ -7775,7 +7775,7 @@ static void ipw_handle_data_packet(struct ipw_priv *priv, #ifdef CONFIG_IPW2200_RADIOTAP static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, struct ipw_rx_mem_buffer *rxb, - struct ieee80211_rx_stats *stats) + struct libipw_rx_stats *stats) { struct net_device *dev = priv->net_dev; struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data; @@ -7921,9 +7921,9 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); - if (!ieee80211_rx(priv->ieee, rxb->skb, stats)) + if (!libipw_rx(priv->ieee, rxb->skb, stats)) dev->stats.rx_errors++; - else { /* ieee80211_rx succeeded, so it now owns the SKB */ + else { /* libipw_rx succeeded, so it now owns the SKB */ rxb->skb = NULL; /* no LED during capture */ } @@ -7931,28 +7931,28 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, #endif #ifdef CONFIG_IPW2200_PROMISCUOUS -#define ieee80211_is_probe_response(fc) \ +#define libipw_is_probe_response(fc) \ ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && \ (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP ) -#define ieee80211_is_management(fc) \ +#define libipw_is_management(fc) \ ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) -#define ieee80211_is_control(fc) \ +#define libipw_is_control(fc) \ ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) -#define ieee80211_is_data(fc) \ +#define libipw_is_data(fc) \ ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) -#define ieee80211_is_assoc_request(fc) \ +#define libipw_is_assoc_request(fc) \ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ) -#define ieee80211_is_reassoc_request(fc) \ +#define libipw_is_reassoc_request(fc) \ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ) static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, struct ipw_rx_mem_buffer *rxb, - struct ieee80211_rx_stats *stats) + struct libipw_rx_stats *stats) { struct net_device *dev = priv->prom_net_dev; struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data; @@ -8002,17 +8002,17 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, } hdr = (void *)rxb->skb->data + IPW_RX_FRAME_SIZE; - if (ieee80211_is_management(le16_to_cpu(hdr->frame_control))) { + if (libipw_is_management(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_MGMT) return; if (filter & IPW_PROM_MGMT_HEADER_ONLY) hdr_only = 1; - } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_control))) { + } else if (libipw_is_control(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_CTL) return; if (filter & IPW_PROM_CTL_HEADER_ONLY) hdr_only = 1; - } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_control))) { + } else if (libipw_is_data(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_DATA) return; if (filter & IPW_PROM_DATA_HEADER_ONLY) @@ -8030,7 +8030,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, ipw_rt = (void *)skb->data; if (hdr_only) - len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); + len = libipw_get_hdrlen(le16_to_cpu(hdr->frame_control)); memcpy(ipw_rt->payload, hdr, len); @@ -8127,7 +8127,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, IPW_DEBUG_RX("Rx packet of %d bytes.\n", skb->len); - if (!ieee80211_rx(priv->prom_priv->ieee, skb, stats)) { + if (!libipw_rx(priv->prom_priv->ieee, skb, stats)) { dev->stats.rx_errors++; dev_kfree_skb_any(skb); } @@ -8135,7 +8135,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, #endif static int is_network_packet(struct ipw_priv *priv, - struct ieee80211_hdr_4addr *header) + struct libipw_hdr_4addr *header) { /* Filter incoming packets to determine if they are targetted toward * this network, discarding packets coming from ourselves */ @@ -8173,7 +8173,7 @@ static int is_network_packet(struct ipw_priv *priv, #define IPW_PACKET_RETRY_TIME HZ static int is_duplicate_packet(struct ipw_priv *priv, - struct ieee80211_hdr_4addr *header) + struct libipw_hdr_4addr *header) { u16 sc = le16_to_cpu(header->seq_ctl); u16 seq = WLAN_GET_SEQ_SEQ(sc); @@ -8247,14 +8247,14 @@ static int is_duplicate_packet(struct ipw_priv *priv, static void ipw_handle_mgmt_packet(struct ipw_priv *priv, struct ipw_rx_mem_buffer *rxb, - struct ieee80211_rx_stats *stats) + struct libipw_rx_stats *stats) { struct sk_buff *skb = rxb->skb; struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)skb->data; - struct ieee80211_hdr_4addr *header = (struct ieee80211_hdr_4addr *) + struct libipw_hdr_4addr *header = (struct libipw_hdr_4addr *) (skb->data + IPW_RX_FRAME_SIZE); - ieee80211_rx_mgt(priv->ieee, header, stats); + libipw_rx_mgt(priv->ieee, header, stats); if (priv->ieee->iw_mode == IW_MODE_ADHOC && ((WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) == @@ -8276,12 +8276,12 @@ static void ipw_handle_mgmt_packet(struct ipw_priv *priv, /* Advance past the ipw packet header to the 802.11 frame */ skb_pull(skb, IPW_RX_FRAME_SIZE); - /* Push the ieee80211_rx_stats before the 802.11 frame */ + /* Push the libipw_rx_stats before the 802.11 frame */ memcpy(skb_push(skb, sizeof(*stats)), stats, sizeof(*stats)); skb->dev = priv->ieee->dev; - /* Point raw at the ieee80211_stats */ + /* Point raw at the libipw_stats */ skb_reset_mac_header(skb); skb->pkt_type = PACKET_OTHERHOST; @@ -8301,7 +8301,7 @@ static void ipw_rx(struct ipw_priv *priv) { struct ipw_rx_mem_buffer *rxb; struct ipw_rx_packet *pkt; - struct ieee80211_hdr_4addr *header; + struct libipw_hdr_4addr *header; u32 r, w, i; u8 network_packet; u8 fill_rx = 0; @@ -8332,7 +8332,7 @@ static void ipw_rx(struct ipw_priv *priv) switch (pkt->header.message_type) { case RX_FRAME_TYPE: /* 802.11 frame */ { - struct ieee80211_rx_stats stats = { + struct libipw_rx_stats stats = { .rssi = pkt->u.frame.rssi_dbm - IPW_RSSI_TO_DBM, .signal = @@ -8347,19 +8347,19 @@ static void ipw_rx(struct ipw_priv *priv) .freq = (pkt->u.frame. control & (1 << 0)) ? - IEEE80211_24GHZ_BAND : - IEEE80211_52GHZ_BAND, + LIBIPW_24GHZ_BAND : + LIBIPW_52GHZ_BAND, .len = le16_to_cpu(pkt->u.frame.length), }; if (stats.rssi != 0) - stats.mask |= IEEE80211_STATMASK_RSSI; + stats.mask |= LIBIPW_STATMASK_RSSI; if (stats.signal != 0) - stats.mask |= IEEE80211_STATMASK_SIGNAL; + stats.mask |= LIBIPW_STATMASK_SIGNAL; if (stats.noise != 0) - stats.mask |= IEEE80211_STATMASK_NOISE; + stats.mask |= LIBIPW_STATMASK_NOISE; if (stats.rate != 0) - stats.mask |= IEEE80211_STATMASK_RATE; + stats.mask |= LIBIPW_STATMASK_RATE; priv->rx_packets++; @@ -8384,7 +8384,7 @@ static void ipw_rx(struct ipw_priv *priv) #endif header = - (struct ieee80211_hdr_4addr *)(rxb->skb-> + (struct libipw_hdr_4addr *)(rxb->skb-> data + IPW_RX_FRAME_SIZE); /* TODO: Check Ad-Hoc dest/source and make sure @@ -8407,7 +8407,7 @@ static void ipw_rx(struct ipw_priv *priv) le16_to_cpu(pkt->u.frame.length)); if (le16_to_cpu(pkt->u.frame.length) < - ieee80211_get_hdrlen(le16_to_cpu( + libipw_get_hdrlen(le16_to_cpu( header->frame_ctl))) { IPW_DEBUG_DROP ("Received packet is too small. " @@ -8592,9 +8592,9 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) ": Detected Intel PRO/Wireless 2915ABG Network " "Connection\n"); priv->ieee->abg_true = 1; - band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND; - modulation = IEEE80211_OFDM_MODULATION | - IEEE80211_CCK_MODULATION; + band = LIBIPW_52GHZ_BAND | LIBIPW_24GHZ_BAND; + modulation = LIBIPW_OFDM_MODULATION | + LIBIPW_CCK_MODULATION; priv->adapter = IPW_2915ABG; priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B; } else { @@ -8604,9 +8604,9 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) "Connection\n"); priv->ieee->abg_true = 0; - band = IEEE80211_24GHZ_BAND; - modulation = IEEE80211_OFDM_MODULATION | - IEEE80211_CCK_MODULATION; + band = LIBIPW_24GHZ_BAND; + modulation = LIBIPW_OFDM_MODULATION | + LIBIPW_CCK_MODULATION; priv->adapter = IPW_2200BG; priv->ieee->mode = IEEE_G | IEEE_B; } @@ -8614,7 +8614,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) priv->ieee->freq_band = band; priv->ieee->modulation = modulation; - priv->rates_mask = IEEE80211_DEFAULT_RATES_MASK; + priv->rates_mask = LIBIPW_DEFAULT_RATES_MASK; priv->disassociate_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT; priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT; @@ -8644,7 +8644,7 @@ static int ipw_wx_get_name(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); if (priv->status & STATUS_RF_KILL_MASK) strcpy(wrqu->name, "radio off"); @@ -8714,8 +8714,8 @@ static int ipw_wx_set_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + struct ipw_priv *priv = libipw_priv(dev); + const struct libipw_geo *geo = libipw_get_geo(priv->ieee); struct iw_freq *fwrq = &wrqu->freq; int ret = 0, i; u8 channel, flags; @@ -8730,23 +8730,23 @@ static int ipw_wx_set_freq(struct net_device *dev, } /* if setting by freq convert to channel */ if (fwrq->e == 1) { - channel = ieee80211_freq_to_channel(priv->ieee, fwrq->m); + channel = libipw_freq_to_channel(priv->ieee, fwrq->m); if (channel == 0) return -EINVAL; } else channel = fwrq->m; - if (!(band = ieee80211_is_valid_channel(priv->ieee, channel))) + if (!(band = libipw_is_valid_channel(priv->ieee, channel))) return -EINVAL; if (priv->ieee->iw_mode == IW_MODE_ADHOC) { - i = ieee80211_channel_to_index(priv->ieee, channel); + i = libipw_channel_to_index(priv->ieee, channel); if (i == -1) return -EINVAL; - flags = (band == IEEE80211_24GHZ_BAND) ? + flags = (band == LIBIPW_24GHZ_BAND) ? geo->bg[i].flags : geo->a[i].flags; - if (flags & IEEE80211_CH_PASSIVE_ONLY) { + if (flags & LIBIPW_CH_PASSIVE_ONLY) { IPW_DEBUG_WX("Invalid Ad-Hoc channel for 802.11a\n"); return -EINVAL; } @@ -8763,7 +8763,7 @@ static int ipw_wx_get_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); wrqu->freq.e = 0; @@ -8774,16 +8774,16 @@ static int ipw_wx_get_freq(struct net_device *dev, priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) { int i; - i = ieee80211_channel_to_index(priv->ieee, priv->channel); + i = libipw_channel_to_index(priv->ieee, priv->channel); BUG_ON(i == -1); wrqu->freq.e = 1; - switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { - case IEEE80211_52GHZ_BAND: + switch (libipw_is_valid_channel(priv->ieee, priv->channel)) { + case LIBIPW_52GHZ_BAND: wrqu->freq.m = priv->ieee->geo.a[i].freq * 100000; break; - case IEEE80211_24GHZ_BAND: + case LIBIPW_24GHZ_BAND: wrqu->freq.m = priv->ieee->geo.bg[i].freq * 100000; break; @@ -8802,7 +8802,7 @@ static int ipw_wx_set_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int err = 0; IPW_DEBUG_WX("Set MODE: %d\n", wrqu->mode); @@ -8854,7 +8854,7 @@ static int ipw_wx_get_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); wrqu->mode = priv->ieee->iw_mode; IPW_DEBUG_WX("Get MODE -> %d\n", wrqu->mode); @@ -8883,9 +8883,9 @@ static int ipw_wx_get_range(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); struct iw_range *range = (struct iw_range *)extra; - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + const struct libipw_geo *geo = libipw_get_geo(priv->ieee); int i = 0, j; wrqu->data.length = sizeof(*range); @@ -8929,7 +8929,7 @@ static int ipw_wx_get_range(struct net_device *dev, if (priv->ieee->mode & (IEEE_B | IEEE_G)) { for (j = 0; j < geo->bg_channels && i < IW_MAX_FREQUENCIES; j++) { if ((priv->ieee->iw_mode == IW_MODE_ADHOC) && - (geo->bg[j].flags & IEEE80211_CH_PASSIVE_ONLY)) + (geo->bg[j].flags & LIBIPW_CH_PASSIVE_ONLY)) continue; range->freq[i].i = geo->bg[j].channel; @@ -8942,7 +8942,7 @@ static int ipw_wx_get_range(struct net_device *dev, if (priv->ieee->mode & IEEE_A) { for (j = 0; j < geo->a_channels && i < IW_MAX_FREQUENCIES; j++) { if ((priv->ieee->iw_mode == IW_MODE_ADHOC) && - (geo->a[j].flags & IEEE80211_CH_PASSIVE_ONLY)) + (geo->a[j].flags & LIBIPW_CH_PASSIVE_ONLY)) continue; range->freq[i].i = geo->a[j].channel; @@ -8977,7 +8977,7 @@ static int ipw_wx_set_wap(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); static const unsigned char any[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff @@ -9026,7 +9026,7 @@ static int ipw_wx_get_wap(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); /* If we are associated, trying to associate, or have a statically * configured BSSID then return that; otherwise return ANY */ @@ -9048,7 +9048,7 @@ static int ipw_wx_set_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int length; DECLARE_SSID_BUF(ssid); @@ -9094,7 +9094,7 @@ static int ipw_wx_get_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); DECLARE_SSID_BUF(ssid); /* If we are associated, trying to associate, or have a statically @@ -9120,7 +9120,7 @@ static int ipw_wx_set_nick(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); IPW_DEBUG_WX("Setting nick to '%s'\n", extra); if (wrqu->data.length > IW_ESSID_MAX_SIZE) @@ -9139,7 +9139,7 @@ static int ipw_wx_get_nick(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); IPW_DEBUG_WX("Getting nick\n"); mutex_lock(&priv->mutex); wrqu->data.length = strlen(priv->nick); @@ -9153,7 +9153,7 @@ static int ipw_wx_set_sens(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int err = 0; IPW_DEBUG_WX("Setting roaming threshold to %d\n", wrqu->sens.value); @@ -9183,7 +9183,7 @@ static int ipw_wx_get_sens(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); wrqu->sens.fixed = 1; wrqu->sens.value = priv->roaming_threshold; @@ -9200,7 +9200,7 @@ static int ipw_wx_set_rate(struct net_device *dev, union iwreq_data *wrqu, char *extra) { /* TODO: We should use semaphores or locks for access to priv */ - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); u32 target_rate = wrqu->bitrate.value; u32 fixed, mask; @@ -9210,7 +9210,7 @@ static int ipw_wx_set_rate(struct net_device *dev, if (target_rate == -1) { fixed = 0; - mask = IEEE80211_DEFAULT_RATES_MASK; + mask = LIBIPW_DEFAULT_RATES_MASK; /* Now we should reassociate */ goto apply; } @@ -9219,62 +9219,62 @@ static int ipw_wx_set_rate(struct net_device *dev, fixed = wrqu->bitrate.fixed; if (target_rate == 1000000 || !fixed) - mask |= IEEE80211_CCK_RATE_1MB_MASK; + mask |= LIBIPW_CCK_RATE_1MB_MASK; if (target_rate == 1000000) goto apply; if (target_rate == 2000000 || !fixed) - mask |= IEEE80211_CCK_RATE_2MB_MASK; + mask |= LIBIPW_CCK_RATE_2MB_MASK; if (target_rate == 2000000) goto apply; if (target_rate == 5500000 || !fixed) - mask |= IEEE80211_CCK_RATE_5MB_MASK; + mask |= LIBIPW_CCK_RATE_5MB_MASK; if (target_rate == 5500000) goto apply; if (target_rate == 6000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_6MB_MASK; + mask |= LIBIPW_OFDM_RATE_6MB_MASK; if (target_rate == 6000000) goto apply; if (target_rate == 9000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_9MB_MASK; + mask |= LIBIPW_OFDM_RATE_9MB_MASK; if (target_rate == 9000000) goto apply; if (target_rate == 11000000 || !fixed) - mask |= IEEE80211_CCK_RATE_11MB_MASK; + mask |= LIBIPW_CCK_RATE_11MB_MASK; if (target_rate == 11000000) goto apply; if (target_rate == 12000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_12MB_MASK; + mask |= LIBIPW_OFDM_RATE_12MB_MASK; if (target_rate == 12000000) goto apply; if (target_rate == 18000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_18MB_MASK; + mask |= LIBIPW_OFDM_RATE_18MB_MASK; if (target_rate == 18000000) goto apply; if (target_rate == 24000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_24MB_MASK; + mask |= LIBIPW_OFDM_RATE_24MB_MASK; if (target_rate == 24000000) goto apply; if (target_rate == 36000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_36MB_MASK; + mask |= LIBIPW_OFDM_RATE_36MB_MASK; if (target_rate == 36000000) goto apply; if (target_rate == 48000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_48MB_MASK; + mask |= LIBIPW_OFDM_RATE_48MB_MASK; if (target_rate == 48000000) goto apply; if (target_rate == 54000000 || !fixed) - mask |= IEEE80211_OFDM_RATE_54MB_MASK; + mask |= LIBIPW_OFDM_RATE_54MB_MASK; if (target_rate == 54000000) goto apply; @@ -9285,7 +9285,7 @@ static int ipw_wx_set_rate(struct net_device *dev, IPW_DEBUG_WX("Setting rate mask to 0x%08X [%s]\n", mask, fixed ? "fixed" : "sub-rates"); mutex_lock(&priv->mutex); - if (mask == IEEE80211_DEFAULT_RATES_MASK) { + if (mask == LIBIPW_DEFAULT_RATES_MASK) { priv->config &= ~CFG_FIXED_RATE; ipw_set_fixed_rate(priv, priv->ieee->mode); } else @@ -9312,7 +9312,7 @@ static int ipw_wx_get_rate(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); wrqu->bitrate.value = priv->last_rate; wrqu->bitrate.fixed = (priv->config & CFG_FIXED_RATE) ? 1 : 0; @@ -9325,7 +9325,7 @@ static int ipw_wx_set_rts(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); if (wrqu->rts.disabled || !wrqu->rts.fixed) priv->rts_threshold = DEFAULT_RTS_THRESHOLD; @@ -9348,7 +9348,7 @@ static int ipw_wx_get_rts(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); wrqu->rts.value = priv->rts_threshold; wrqu->rts.fixed = 0; /* no auto select */ @@ -9362,7 +9362,7 @@ static int ipw_wx_set_txpow(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int err = 0; mutex_lock(&priv->mutex); @@ -9396,7 +9396,7 @@ static int ipw_wx_get_txpow(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); wrqu->power.value = priv->tx_power; wrqu->power.fixed = 1; @@ -9414,7 +9414,7 @@ static int ipw_wx_set_frag(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); if (wrqu->frag.disabled || !wrqu->frag.fixed) priv->ieee->fts = DEFAULT_FTS; @@ -9438,7 +9438,7 @@ static int ipw_wx_get_frag(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); wrqu->frag.value = priv->ieee->fts; wrqu->frag.fixed = 0; /* no auto select */ @@ -9453,7 +9453,7 @@ static int ipw_wx_set_retry(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled) return -EINVAL; @@ -9486,7 +9486,7 @@ static int ipw_wx_get_retry(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); wrqu->retry.disabled = 0; @@ -9517,7 +9517,7 @@ static int ipw_wx_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); struct iw_scan_req *req = (struct iw_scan_req *)extra; struct delayed_work *work = NULL; @@ -9553,20 +9553,20 @@ static int ipw_wx_get_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra); + struct ipw_priv *priv = libipw_priv(dev); + return libipw_wx_get_scan(priv->ieee, info, wrqu, extra); } static int ipw_wx_set_encode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *key) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int ret; u32 cap = priv->capability; mutex_lock(&priv->mutex); - ret = ieee80211_wx_set_encode(priv->ieee, info, wrqu, key); + ret = libipw_wx_set_encode(priv->ieee, info, wrqu, key); /* In IBSS mode, we need to notify the firmware to update * the beacon info after we changed the capability. */ @@ -9583,15 +9583,15 @@ static int ipw_wx_get_encode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *key) { - struct ipw_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_encode(priv->ieee, info, wrqu, key); + struct ipw_priv *priv = libipw_priv(dev); + return libipw_wx_get_encode(priv->ieee, info, wrqu, key); } static int ipw_wx_set_power(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int err; mutex_lock(&priv->mutex); if (wrqu->power.disabled) { @@ -9642,7 +9642,7 @@ static int ipw_wx_get_power(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); if (!(priv->power_mode & IPW_POWER_ENABLED)) wrqu->power.disabled = 1; @@ -9659,7 +9659,7 @@ static int ipw_wx_set_powermode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int mode = *(int *)extra; int err; @@ -9685,7 +9685,7 @@ static int ipw_wx_get_powermode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int level = IPW_POWER_LEVEL(priv->power_mode); char *p = extra; @@ -9717,7 +9717,7 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int mode = *(int *)extra; u8 band = 0, modulation = 0; @@ -9729,8 +9729,8 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, if (priv->adapter == IPW_2915ABG) { priv->ieee->abg_true = 1; if (mode & IEEE_A) { - band |= IEEE80211_52GHZ_BAND; - modulation |= IEEE80211_OFDM_MODULATION; + band |= LIBIPW_52GHZ_BAND; + modulation |= LIBIPW_OFDM_MODULATION; } else priv->ieee->abg_true = 0; } else { @@ -9745,14 +9745,14 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, } if (mode & IEEE_B) { - band |= IEEE80211_24GHZ_BAND; - modulation |= IEEE80211_CCK_MODULATION; + band |= LIBIPW_24GHZ_BAND; + modulation |= LIBIPW_CCK_MODULATION; } else priv->ieee->abg_true = 0; if (mode & IEEE_G) { - band |= IEEE80211_24GHZ_BAND; - modulation |= IEEE80211_OFDM_MODULATION; + band |= LIBIPW_24GHZ_BAND; + modulation |= LIBIPW_OFDM_MODULATION; } else priv->ieee->abg_true = 0; @@ -9782,7 +9782,7 @@ static int ipw_wx_get_wireless_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); switch (priv->ieee->mode) { case IEEE_A: @@ -9823,7 +9823,7 @@ static int ipw_wx_set_preamble(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int mode = *(int *)extra; mutex_lock(&priv->mutex); /* Switching from SHORT -> LONG requires a disassociation */ @@ -9856,7 +9856,7 @@ static int ipw_wx_get_preamble(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); if (priv->config & CFG_PREAMBLE_LONG) snprintf(wrqu->name, IFNAMSIZ, "long (1)"); @@ -9871,7 +9871,7 @@ static int ipw_wx_set_monitor(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int *parms = (int *)extra; int enable = (parms[0] > 0); mutex_lock(&priv->mutex); @@ -9905,7 +9905,7 @@ static int ipw_wx_reset(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); IPW_DEBUG_WX("RESET\n"); queue_work(priv->workqueue, &priv->adapter_restart); return 0; @@ -9915,7 +9915,7 @@ static int ipw_wx_sw_reset(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); union iwreq_data wrqu_sec = { .encoding = { .flags = IW_ENCODE_DISABLED, @@ -9938,7 +9938,7 @@ static int ipw_wx_sw_reset(struct net_device *dev, ipw_radio_kill_sw(priv, priv->status & STATUS_RF_KILL_SW); mutex_unlock(&priv->mutex); - ieee80211_wx_set_encode(priv->ieee, info, &wrqu_sec, NULL); + libipw_wx_set_encode(priv->ieee, info, &wrqu_sec, NULL); mutex_lock(&priv->mutex); if (!(priv->status & STATUS_RF_KILL_MASK)) { @@ -10083,7 +10083,7 @@ static struct iw_handler_def ipw_wx_handler_def = { */ static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); struct iw_statistics *wstats; wstats = &priv->wstats; @@ -10164,13 +10164,13 @@ static int ipw_net_stop(struct net_device *dev) todo: modify to send one tfd per fragment instead of using chunking. otherwise -we need to heavily modify the ieee80211_skb_to_txb. +we need to heavily modify the libipw_skb_to_txb. */ -static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, +static int ipw_tx_skb(struct ipw_priv *priv, struct libipw_txb *txb, int pri) { - struct ieee80211_hdr_3addrqos *hdr = (struct ieee80211_hdr_3addrqos *) + struct libipw_hdr_3addrqos *hdr = (struct libipw_hdr_3addrqos *) txb->fragments[0]->data; int i = 0; struct tfd_frame *tfd; @@ -10187,7 +10187,7 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, if (!(priv->status & STATUS_ASSOCIATED)) goto drop; - hdr_len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + hdr_len = libipw_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); switch (priv->ieee->iw_mode) { case IW_MODE_ADHOC: unicast = !is_multicast_ether_addr(hdr->addr1); @@ -10356,13 +10356,13 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, drop: IPW_DEBUG_DROP("Silently dropping Tx packet.\n"); - ieee80211_txb_free(txb); + libipw_txb_free(txb); return NETDEV_TX_OK; } static int ipw_net_is_queue_full(struct net_device *dev, int pri) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); #ifdef CONFIG_IPW2200_QOS int tx_id = ipw_get_tx_queue_number(priv, pri); struct clx2_tx_queue *txq = &priv->txq[tx_id]; @@ -10378,9 +10378,9 @@ static int ipw_net_is_queue_full(struct net_device *dev, int pri) #ifdef CONFIG_IPW2200_PROMISCUOUS static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, - struct ieee80211_txb *txb) + struct libipw_txb *txb) { - struct ieee80211_rx_stats dummystats; + struct libipw_rx_stats dummystats; struct ieee80211_hdr *hdr; u8 n; u16 filter = priv->prom_priv->filter; @@ -10393,17 +10393,17 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, /* Filtering of fragment chains is done agains the first fragment */ hdr = (void *)txb->fragments[0]->data; - if (ieee80211_is_management(le16_to_cpu(hdr->frame_control))) { + if (libipw_is_management(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_MGMT) return; if (filter & IPW_PROM_MGMT_HEADER_ONLY) hdr_only = 1; - } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_control))) { + } else if (libipw_is_control(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_CTL) return; if (filter & IPW_PROM_CTL_HEADER_ONLY) hdr_only = 1; - } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_control))) { + } else if (libipw_is_data(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_DATA) return; if (filter & IPW_PROM_DATA_HEADER_ONLY) @@ -10418,7 +10418,7 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, if (hdr_only) { hdr = (void *)src->data; - len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); + len = libipw_get_hdrlen(le16_to_cpu(hdr->frame_control)); } else len = src->len; @@ -10452,16 +10452,16 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, skb_copy_from_linear_data(src, skb_put(dst, len), len); - if (!ieee80211_rx(priv->prom_priv->ieee, dst, &dummystats)) + if (!libipw_rx(priv->prom_priv->ieee, dst, &dummystats)) dev_kfree_skb_any(dst); } } #endif -static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, +static int ipw_net_hard_start_xmit(struct libipw_txb *txb, struct net_device *dev, int pri) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); unsigned long flags; int ret; @@ -10488,7 +10488,7 @@ static void ipw_net_set_multicast_list(struct net_device *dev) static int ipw_net_set_mac_address(struct net_device *dev, void *p) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); struct sockaddr *addr = p; if (!is_valid_ether_addr(addr->sa_data)) @@ -10506,7 +10506,7 @@ static int ipw_net_set_mac_address(struct net_device *dev, void *p) static void ipw_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct ipw_priv *p = ieee80211_priv(dev); + struct ipw_priv *p = libipw_priv(dev); char vers[64]; char date[32]; u32 len; @@ -10527,7 +10527,7 @@ static void ipw_ethtool_get_drvinfo(struct net_device *dev, static u32 ipw_ethtool_get_link(struct net_device *dev) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); return (priv->status & STATUS_ASSOCIATED) != 0; } @@ -10539,7 +10539,7 @@ static int ipw_ethtool_get_eeprom_len(struct net_device *dev) static int ipw_ethtool_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 * bytes) { - struct ipw_priv *p = ieee80211_priv(dev); + struct ipw_priv *p = libipw_priv(dev); if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE) return -EINVAL; @@ -10552,7 +10552,7 @@ static int ipw_ethtool_get_eeprom(struct net_device *dev, static int ipw_ethtool_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 * bytes) { - struct ipw_priv *p = ieee80211_priv(dev); + struct ipw_priv *p = libipw_priv(dev); int i; if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE) @@ -10768,9 +10768,9 @@ static int __devinit ipw_setup_deferred_work(struct ipw_priv *priv) } static void shim__set_security(struct net_device *dev, - struct ieee80211_security *sec) + struct libipw_security *sec) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); int i; for (i = 0; i < 4; i++) { if (sec->flags & (1 << i)) { @@ -10855,21 +10855,21 @@ static int init_supported_rates(struct ipw_priv *priv, memset(rates, 0, sizeof(*rates)); /* configure supported rates */ switch (priv->ieee->freq_band) { - case IEEE80211_52GHZ_BAND: + case LIBIPW_52GHZ_BAND: rates->ieee_mode = IPW_A_MODE; rates->purpose = IPW_RATE_CAPABILITIES; - ipw_add_ofdm_scan_rates(rates, IEEE80211_CCK_MODULATION, - IEEE80211_OFDM_DEFAULT_RATES_MASK); + ipw_add_ofdm_scan_rates(rates, LIBIPW_CCK_MODULATION, + LIBIPW_OFDM_DEFAULT_RATES_MASK); break; default: /* Mixed or 2.4Ghz */ rates->ieee_mode = IPW_G_MODE; rates->purpose = IPW_RATE_CAPABILITIES; - ipw_add_cck_scan_rates(rates, IEEE80211_CCK_MODULATION, - IEEE80211_CCK_DEFAULT_RATES_MASK); - if (priv->ieee->modulation & IEEE80211_OFDM_MODULATION) { - ipw_add_ofdm_scan_rates(rates, IEEE80211_CCK_MODULATION, - IEEE80211_OFDM_DEFAULT_RATES_MASK); + ipw_add_cck_scan_rates(rates, LIBIPW_CCK_MODULATION, + LIBIPW_CCK_DEFAULT_RATES_MASK); + if (priv->ieee->modulation & LIBIPW_OFDM_MODULATION) { + ipw_add_ofdm_scan_rates(rates, LIBIPW_CCK_MODULATION, + LIBIPW_OFDM_DEFAULT_RATES_MASK); } break; } @@ -10975,7 +10975,7 @@ static int ipw_config(struct ipw_priv *priv) * table. * */ -static const struct ieee80211_geo ipw_geos[] = { +static const struct libipw_geo ipw_geos[] = { { /* Restricted */ "---", .bg_channels = 11, @@ -10997,10 +10997,10 @@ static const struct ieee80211_geo ipw_geos[] = { {5200, 40}, {5220, 44}, {5240, 48}, - {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, - {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, - {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, - {5320, 64, IEEE80211_CH_PASSIVE_ONLY}}, + {5260, 52, LIBIPW_CH_PASSIVE_ONLY}, + {5280, 56, LIBIPW_CH_PASSIVE_ONLY}, + {5300, 60, LIBIPW_CH_PASSIVE_ONLY}, + {5320, 64, LIBIPW_CH_PASSIVE_ONLY}}, }, { /* Rest of World */ @@ -11025,10 +11025,10 @@ static const struct ieee80211_geo ipw_geos[] = { {5200, 40}, {5220, 44}, {5240, 48}, - {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, - {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, - {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, - {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, + {5260, 52, LIBIPW_CH_PASSIVE_ONLY}, + {5280, 56, LIBIPW_CH_PASSIVE_ONLY}, + {5300, 60, LIBIPW_CH_PASSIVE_ONLY}, + {5320, 64, LIBIPW_CH_PASSIVE_ONLY}, {5745, 149}, {5765, 153}, {5785, 157}, @@ -11048,15 +11048,15 @@ static const struct ieee80211_geo ipw_geos[] = { {5200, 40}, {5220, 44}, {5240, 48}, - {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, - {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, - {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, - {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, - {5745, 149, IEEE80211_CH_PASSIVE_ONLY}, - {5765, 153, IEEE80211_CH_PASSIVE_ONLY}, - {5785, 157, IEEE80211_CH_PASSIVE_ONLY}, - {5805, 161, IEEE80211_CH_PASSIVE_ONLY}, - {5825, 165, IEEE80211_CH_PASSIVE_ONLY}}, + {5260, 52, LIBIPW_CH_PASSIVE_ONLY}, + {5280, 56, LIBIPW_CH_PASSIVE_ONLY}, + {5300, 60, LIBIPW_CH_PASSIVE_ONLY}, + {5320, 64, LIBIPW_CH_PASSIVE_ONLY}, + {5745, 149, LIBIPW_CH_PASSIVE_ONLY}, + {5765, 153, LIBIPW_CH_PASSIVE_ONLY}, + {5785, 157, LIBIPW_CH_PASSIVE_ONLY}, + {5805, 161, LIBIPW_CH_PASSIVE_ONLY}, + {5825, 165, LIBIPW_CH_PASSIVE_ONLY}}, }, { /* Custom Japan */ @@ -11093,21 +11093,21 @@ static const struct ieee80211_geo ipw_geos[] = { {5200, 40}, {5220, 44}, {5240, 48}, - {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, - {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, - {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, - {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, - {5500, 100, IEEE80211_CH_PASSIVE_ONLY}, - {5520, 104, IEEE80211_CH_PASSIVE_ONLY}, - {5540, 108, IEEE80211_CH_PASSIVE_ONLY}, - {5560, 112, IEEE80211_CH_PASSIVE_ONLY}, - {5580, 116, IEEE80211_CH_PASSIVE_ONLY}, - {5600, 120, IEEE80211_CH_PASSIVE_ONLY}, - {5620, 124, IEEE80211_CH_PASSIVE_ONLY}, - {5640, 128, IEEE80211_CH_PASSIVE_ONLY}, - {5660, 132, IEEE80211_CH_PASSIVE_ONLY}, - {5680, 136, IEEE80211_CH_PASSIVE_ONLY}, - {5700, 140, IEEE80211_CH_PASSIVE_ONLY}}, + {5260, 52, LIBIPW_CH_PASSIVE_ONLY}, + {5280, 56, LIBIPW_CH_PASSIVE_ONLY}, + {5300, 60, LIBIPW_CH_PASSIVE_ONLY}, + {5320, 64, LIBIPW_CH_PASSIVE_ONLY}, + {5500, 100, LIBIPW_CH_PASSIVE_ONLY}, + {5520, 104, LIBIPW_CH_PASSIVE_ONLY}, + {5540, 108, LIBIPW_CH_PASSIVE_ONLY}, + {5560, 112, LIBIPW_CH_PASSIVE_ONLY}, + {5580, 116, LIBIPW_CH_PASSIVE_ONLY}, + {5600, 120, LIBIPW_CH_PASSIVE_ONLY}, + {5620, 124, LIBIPW_CH_PASSIVE_ONLY}, + {5640, 128, LIBIPW_CH_PASSIVE_ONLY}, + {5660, 132, LIBIPW_CH_PASSIVE_ONLY}, + {5680, 136, LIBIPW_CH_PASSIVE_ONLY}, + {5700, 140, LIBIPW_CH_PASSIVE_ONLY}}, }, { /* Custom Japan */ @@ -11117,7 +11117,7 @@ static const struct ieee80211_geo ipw_geos[] = { {2427, 4}, {2432, 5}, {2437, 6}, {2442, 7}, {2447, 8}, {2452, 9}, {2457, 10}, {2462, 11}, {2467, 12}, - {2472, 13}, {2484, 14, IEEE80211_CH_B_ONLY}}, + {2472, 13}, {2484, 14, LIBIPW_CH_B_ONLY}}, .a_channels = 4, .a = {{5170, 34}, {5190, 38}, {5210, 42}, {5230, 46}}, @@ -11130,8 +11130,8 @@ static const struct ieee80211_geo ipw_geos[] = { {2427, 4}, {2432, 5}, {2437, 6}, {2442, 7}, {2447, 8}, {2452, 9}, {2457, 10}, {2462, 11}, {2467, 12}, - {2472, 13}, {2484, 14, IEEE80211_CH_B_ONLY | - IEEE80211_CH_PASSIVE_ONLY}}, + {2472, 13}, {2484, 14, LIBIPW_CH_B_ONLY | + LIBIPW_CH_PASSIVE_ONLY}}, }, { /* High Band */ @@ -11141,8 +11141,8 @@ static const struct ieee80211_geo ipw_geos[] = { {2427, 4}, {2432, 5}, {2437, 6}, {2442, 7}, {2447, 8}, {2452, 9}, {2457, 10}, {2462, 11}, - {2467, 12, IEEE80211_CH_PASSIVE_ONLY}, - {2472, 13, IEEE80211_CH_PASSIVE_ONLY}}, + {2467, 12, LIBIPW_CH_PASSIVE_ONLY}, + {2472, 13, LIBIPW_CH_PASSIVE_ONLY}}, .a_channels = 4, .a = {{5745, 149}, {5765, 153}, {5785, 157}, {5805, 161}}, @@ -11168,33 +11168,33 @@ static const struct ieee80211_geo ipw_geos[] = { {2427, 4}, {2432, 5}, {2437, 6}, {2442, 7}, {2447, 8}, {2452, 9}, {2457, 10}, {2462, 11}, - {2467, 12, IEEE80211_CH_PASSIVE_ONLY}, - {2472, 13, IEEE80211_CH_PASSIVE_ONLY}}, + {2467, 12, LIBIPW_CH_PASSIVE_ONLY}, + {2472, 13, LIBIPW_CH_PASSIVE_ONLY}}, .a_channels = 24, - .a = {{5180, 36, IEEE80211_CH_PASSIVE_ONLY}, - {5200, 40, IEEE80211_CH_PASSIVE_ONLY}, - {5220, 44, IEEE80211_CH_PASSIVE_ONLY}, - {5240, 48, IEEE80211_CH_PASSIVE_ONLY}, - {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, - {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, - {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, - {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, - {5500, 100, IEEE80211_CH_PASSIVE_ONLY}, - {5520, 104, IEEE80211_CH_PASSIVE_ONLY}, - {5540, 108, IEEE80211_CH_PASSIVE_ONLY}, - {5560, 112, IEEE80211_CH_PASSIVE_ONLY}, - {5580, 116, IEEE80211_CH_PASSIVE_ONLY}, - {5600, 120, IEEE80211_CH_PASSIVE_ONLY}, - {5620, 124, IEEE80211_CH_PASSIVE_ONLY}, - {5640, 128, IEEE80211_CH_PASSIVE_ONLY}, - {5660, 132, IEEE80211_CH_PASSIVE_ONLY}, - {5680, 136, IEEE80211_CH_PASSIVE_ONLY}, - {5700, 140, IEEE80211_CH_PASSIVE_ONLY}, - {5745, 149, IEEE80211_CH_PASSIVE_ONLY}, - {5765, 153, IEEE80211_CH_PASSIVE_ONLY}, - {5785, 157, IEEE80211_CH_PASSIVE_ONLY}, - {5805, 161, IEEE80211_CH_PASSIVE_ONLY}, - {5825, 165, IEEE80211_CH_PASSIVE_ONLY}}, + .a = {{5180, 36, LIBIPW_CH_PASSIVE_ONLY}, + {5200, 40, LIBIPW_CH_PASSIVE_ONLY}, + {5220, 44, LIBIPW_CH_PASSIVE_ONLY}, + {5240, 48, LIBIPW_CH_PASSIVE_ONLY}, + {5260, 52, LIBIPW_CH_PASSIVE_ONLY}, + {5280, 56, LIBIPW_CH_PASSIVE_ONLY}, + {5300, 60, LIBIPW_CH_PASSIVE_ONLY}, + {5320, 64, LIBIPW_CH_PASSIVE_ONLY}, + {5500, 100, LIBIPW_CH_PASSIVE_ONLY}, + {5520, 104, LIBIPW_CH_PASSIVE_ONLY}, + {5540, 108, LIBIPW_CH_PASSIVE_ONLY}, + {5560, 112, LIBIPW_CH_PASSIVE_ONLY}, + {5580, 116, LIBIPW_CH_PASSIVE_ONLY}, + {5600, 120, LIBIPW_CH_PASSIVE_ONLY}, + {5620, 124, LIBIPW_CH_PASSIVE_ONLY}, + {5640, 128, LIBIPW_CH_PASSIVE_ONLY}, + {5660, 132, LIBIPW_CH_PASSIVE_ONLY}, + {5680, 136, LIBIPW_CH_PASSIVE_ONLY}, + {5700, 140, LIBIPW_CH_PASSIVE_ONLY}, + {5745, 149, LIBIPW_CH_PASSIVE_ONLY}, + {5765, 153, LIBIPW_CH_PASSIVE_ONLY}, + {5785, 157, LIBIPW_CH_PASSIVE_ONLY}, + {5805, 161, LIBIPW_CH_PASSIVE_ONLY}, + {5825, 165, LIBIPW_CH_PASSIVE_ONLY}}, }, { /* Europe */ @@ -11205,19 +11205,19 @@ static const struct ieee80211_geo ipw_geos[] = { {2442, 7}, {2447, 8}, {2452, 9}, {2457, 10}, {2462, 11}}, .a_channels = 13, - .a = {{5180, 36, IEEE80211_CH_PASSIVE_ONLY}, - {5200, 40, IEEE80211_CH_PASSIVE_ONLY}, - {5220, 44, IEEE80211_CH_PASSIVE_ONLY}, - {5240, 48, IEEE80211_CH_PASSIVE_ONLY}, - {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, - {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, - {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, - {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, - {5745, 149, IEEE80211_CH_PASSIVE_ONLY}, - {5765, 153, IEEE80211_CH_PASSIVE_ONLY}, - {5785, 157, IEEE80211_CH_PASSIVE_ONLY}, - {5805, 161, IEEE80211_CH_PASSIVE_ONLY}, - {5825, 165, IEEE80211_CH_PASSIVE_ONLY}}, + .a = {{5180, 36, LIBIPW_CH_PASSIVE_ONLY}, + {5200, 40, LIBIPW_CH_PASSIVE_ONLY}, + {5220, 44, LIBIPW_CH_PASSIVE_ONLY}, + {5240, 48, LIBIPW_CH_PASSIVE_ONLY}, + {5260, 52, LIBIPW_CH_PASSIVE_ONLY}, + {5280, 56, LIBIPW_CH_PASSIVE_ONLY}, + {5300, 60, LIBIPW_CH_PASSIVE_ONLY}, + {5320, 64, LIBIPW_CH_PASSIVE_ONLY}, + {5745, 149, LIBIPW_CH_PASSIVE_ONLY}, + {5765, 153, LIBIPW_CH_PASSIVE_ONLY}, + {5785, 157, LIBIPW_CH_PASSIVE_ONLY}, + {5805, 161, LIBIPW_CH_PASSIVE_ONLY}, + {5825, 165, LIBIPW_CH_PASSIVE_ONLY}}, } }; @@ -11228,7 +11228,7 @@ static int ipw_up(struct ipw_priv *priv) /* Age scan list entries found before suspend */ if (priv->suspend_time) { - ieee80211_networks_age(priv->ieee, priv->suspend_time); + libipw_networks_age(priv->ieee, priv->suspend_time); priv->suspend_time = 0; } @@ -11273,7 +11273,7 @@ static int ipw_up(struct ipw_priv *priv) priv->eeprom[EEPROM_COUNTRY_CODE + 2]); j = 0; } - if (ieee80211_set_geo(priv->ieee, &ipw_geos[j])) { + if (libipw_set_geo(priv->ieee, &ipw_geos[j])) { IPW_WARNING("Could not set geography."); return 0; } @@ -11401,7 +11401,7 @@ static void ipw_bg_down(struct work_struct *work) /* Called by register_netdev() */ static int ipw_net_init(struct net_device *dev) { - struct ipw_priv *priv = ieee80211_priv(dev); + struct ipw_priv *priv = libipw_priv(dev); mutex_lock(&priv->mutex); if (ipw_up(priv)) { @@ -11480,7 +11480,7 @@ static struct attribute_group ipw_attribute_group = { #ifdef CONFIG_IPW2200_PROMISCUOUS static int ipw_prom_open(struct net_device *dev) { - struct ipw_prom_priv *prom_priv = ieee80211_priv(dev); + struct ipw_prom_priv *prom_priv = libipw_priv(dev); struct ipw_priv *priv = prom_priv->priv; IPW_DEBUG_INFO("prom dev->open\n"); @@ -11500,7 +11500,7 @@ static int ipw_prom_open(struct net_device *dev) static int ipw_prom_stop(struct net_device *dev) { - struct ipw_prom_priv *prom_priv = ieee80211_priv(dev); + struct ipw_prom_priv *prom_priv = libipw_priv(dev); struct ipw_priv *priv = prom_priv->priv; IPW_DEBUG_INFO("prom dev->stop\n"); @@ -11528,7 +11528,7 @@ static const struct net_device_ops ipw_prom_netdev_ops = { .ndo_open = ipw_prom_open, .ndo_stop = ipw_prom_stop, .ndo_start_xmit = ipw_prom_hard_start_xmit, - .ndo_change_mtu = ieee80211_change_mtu, + .ndo_change_mtu = libipw_change_mtu, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, }; @@ -11544,7 +11544,7 @@ static int ipw_prom_alloc(struct ipw_priv *priv) if (priv->prom_net_dev == NULL) return -ENOMEM; - priv->prom_priv = ieee80211_priv(priv->prom_net_dev); + priv->prom_priv = libipw_priv(priv->prom_net_dev); priv->prom_priv->ieee = netdev_priv(priv->prom_net_dev); priv->prom_priv->priv = priv; @@ -11586,8 +11586,8 @@ static const struct net_device_ops ipw_netdev_ops = { .ndo_stop = ipw_net_stop, .ndo_set_multicast_list = ipw_net_set_multicast_list, .ndo_set_mac_address = ipw_net_set_mac_address, - .ndo_start_xmit = ieee80211_xmit, - .ndo_change_mtu = ieee80211_change_mtu, + .ndo_start_xmit = libipw_xmit, + .ndo_change_mtu = libipw_change_mtu, .ndo_validate_addr = eth_validate_addr, }; @@ -11607,7 +11607,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, goto out; } - priv = ieee80211_priv(net_dev); + priv = libipw_priv(net_dev); priv->ieee = netdev_priv(net_dev); priv->net_dev = net_dev; diff --git a/drivers/net/wireless/ipw2x00/ipw2200.h b/drivers/net/wireless/ipw2x00/ipw2200.h index 05e8ccf01c5..4448bad51b8 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.h +++ b/drivers/net/wireless/ipw2x00/ipw2200.h @@ -55,7 +55,7 @@ #include -#include "ieee80211.h" +#include "libipw.h" /* Authentication and Association States */ enum connection_manager_assoc_states { @@ -365,8 +365,8 @@ enum connection_manager_assoc_states { /* QoS sturctures */ struct ipw_qos_info { int qos_enable; - struct ieee80211_qos_parameters *def_qos_parm_OFDM; - struct ieee80211_qos_parameters *def_qos_parm_CCK; + struct libipw_qos_parameters *def_qos_parm_OFDM; + struct libipw_qos_parameters *def_qos_parm_CCK; u32 burst_duration_CCK; u32 burst_duration_OFDM; u16 qos_no_ack_mask; @@ -534,7 +534,7 @@ typedef void destructor_func(const void *); struct clx2_tx_queue { struct clx2_queue q; struct tfd_frame *bd; - struct ieee80211_txb **txb; + struct libipw_txb **txb; }; /* @@ -1144,7 +1144,7 @@ enum ipw_prom_filter { struct ipw_priv; struct ipw_prom_priv { struct ipw_priv *priv; - struct ieee80211_device *ieee; + struct libipw_device *ieee; enum ipw_prom_filter filter; int tx_packets; int rx_packets; @@ -1175,7 +1175,7 @@ struct ipw_rt_hdr { struct ipw_priv { /* ieee device used by generic ieee processing code */ - struct ieee80211_device *ieee; + struct libipw_device *ieee; spinlock_t lock; spinlock_t irq_lock; @@ -1222,7 +1222,7 @@ struct ipw_priv { u32 roaming_threshold; struct ipw_associate assoc_request; - struct ieee80211_network *assoc_network; + struct libipw_network *assoc_network; unsigned long ts_scan_abort; struct ipw_supported_rates rates; diff --git a/drivers/net/wireless/ipw2x00/libipw.h b/drivers/net/wireless/ipw2x00/libipw.h new file mode 100644 index 00000000000..cefb94262cc --- /dev/null +++ b/drivers/net/wireless/ipw2x00/libipw.h @@ -0,0 +1,1087 @@ +/* + * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11 + * remains copyright by the original authors + * + * Portions of the merged code are based on Host AP (software wireless + * LAN access point) driver for Intersil Prism2/2.5/3. + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * + * Copyright (c) 2002-2003, Jouni Malinen + * + * Adaption to a generic IEEE 802.11 stack by James Ketrenos + * + * Copyright (c) 2004-2005, Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + * + * API Version History + * 1.0.x -- Initial version + * 1.1.x -- Added radiotap, QoS, TIM, libipw_geo APIs, + * various structure changes, and crypto API init method + */ +#ifndef LIBIPW_H +#define LIBIPW_H +#include /* ETH_ALEN */ +#include /* ARRAY_SIZE */ +#include +#include + +#include + +#define LIBIPW_VERSION "git-1.1.13" + +#define LIBIPW_DATA_LEN 2304 +/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section + 6.2.1.1.2. + + The figure in section 7.1.2 suggests a body size of up to 2312 + bytes is allowed, which is a bit confusing, I suspect this + represents the 2304 bytes of real data, plus a possible 8 bytes of + WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ + +#define LIBIPW_1ADDR_LEN 10 +#define LIBIPW_2ADDR_LEN 16 +#define LIBIPW_3ADDR_LEN 24 +#define LIBIPW_4ADDR_LEN 30 +#define LIBIPW_FCS_LEN 4 +#define LIBIPW_HLEN (LIBIPW_4ADDR_LEN) +#define LIBIPW_FRAME_LEN (LIBIPW_DATA_LEN + LIBIPW_HLEN) + +#define MIN_FRAG_THRESHOLD 256U +#define MAX_FRAG_THRESHOLD 2346U + +/* QOS control */ +#define LIBIPW_QCTL_TID 0x000F + +/* debug macros */ + +#ifdef CONFIG_LIBIPW_DEBUG +extern u32 libipw_debug_level; +#define LIBIPW_DEBUG(level, fmt, args...) \ +do { if (libipw_debug_level & (level)) \ + printk(KERN_DEBUG "ieee80211: %c %s " fmt, \ + in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) +static inline bool libipw_ratelimit_debug(u32 level) +{ + return (libipw_debug_level & level) && net_ratelimit(); +} +#else +#define LIBIPW_DEBUG(level, fmt, args...) do {} while (0) +static inline bool libipw_ratelimit_debug(u32 level) +{ + return false; +} +#endif /* CONFIG_LIBIPW_DEBUG */ + +/* + * To use the debug system: + * + * If you are defining a new debug classification, simply add it to the #define + * list here in the form of: + * + * #define LIBIPW_DL_xxxx VALUE + * + * shifting value to the left one bit from the previous entry. xxxx should be + * the name of the classification (for example, WEP) + * + * You then need to either add a LIBIPW_xxxx_DEBUG() macro definition for your + * classification, or use LIBIPW_DEBUG(LIBIPW_DL_xxxx, ...) whenever you want + * to send output to that classification. + * + * To add your debug level to the list of levels seen when you perform + * + * % cat /proc/net/ieee80211/debug_level + * + * you simply need to add your entry to the libipw_debug_level array. + * + * If you do not see debug_level in /proc/net/ieee80211 then you do not have + * CONFIG_LIBIPW_DEBUG defined in your kernel configuration + * + */ + +#define LIBIPW_DL_INFO (1<<0) +#define LIBIPW_DL_WX (1<<1) +#define LIBIPW_DL_SCAN (1<<2) +#define LIBIPW_DL_STATE (1<<3) +#define LIBIPW_DL_MGMT (1<<4) +#define LIBIPW_DL_FRAG (1<<5) +#define LIBIPW_DL_DROP (1<<7) + +#define LIBIPW_DL_TX (1<<8) +#define LIBIPW_DL_RX (1<<9) +#define LIBIPW_DL_QOS (1<<31) + +#define LIBIPW_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a) +#define LIBIPW_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a) +#define LIBIPW_DEBUG_INFO(f, a...) LIBIPW_DEBUG(LIBIPW_DL_INFO, f, ## a) + +#define LIBIPW_DEBUG_WX(f, a...) LIBIPW_DEBUG(LIBIPW_DL_WX, f, ## a) +#define LIBIPW_DEBUG_SCAN(f, a...) LIBIPW_DEBUG(LIBIPW_DL_SCAN, f, ## a) +#define LIBIPW_DEBUG_STATE(f, a...) LIBIPW_DEBUG(LIBIPW_DL_STATE, f, ## a) +#define LIBIPW_DEBUG_MGMT(f, a...) LIBIPW_DEBUG(LIBIPW_DL_MGMT, f, ## a) +#define LIBIPW_DEBUG_FRAG(f, a...) LIBIPW_DEBUG(LIBIPW_DL_FRAG, f, ## a) +#define LIBIPW_DEBUG_DROP(f, a...) LIBIPW_DEBUG(LIBIPW_DL_DROP, f, ## a) +#define LIBIPW_DEBUG_TX(f, a...) LIBIPW_DEBUG(LIBIPW_DL_TX, f, ## a) +#define LIBIPW_DEBUG_RX(f, a...) LIBIPW_DEBUG(LIBIPW_DL_RX, f, ## a) +#define LIBIPW_DEBUG_QOS(f, a...) LIBIPW_DEBUG(LIBIPW_DL_QOS, f, ## a) +#include +#include /* ARPHRD_ETHER */ + +#ifndef WIRELESS_SPY +#define WIRELESS_SPY /* enable iwspy support */ +#endif +#include /* new driver API */ + +#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ + +#ifndef ETH_P_80211_RAW +#define ETH_P_80211_RAW (ETH_P_ECONET + 1) +#endif + +/* IEEE 802.11 defines */ + +#define P80211_OUI_LEN 3 + +struct libipw_snap_hdr { + + u8 dsap; /* always 0xAA */ + u8 ssap; /* always 0xAA */ + u8 ctrl; /* always 0x03 */ + u8 oui[P80211_OUI_LEN]; /* organizational universal id */ + +} __attribute__ ((packed)); + +#define SNAP_SIZE sizeof(struct libipw_snap_hdr) + +#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS) +#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE) +#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE) + +#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG) +#define WLAN_GET_SEQ_SEQ(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) + +#define LIBIPW_STATMASK_SIGNAL (1<<0) +#define LIBIPW_STATMASK_RSSI (1<<1) +#define LIBIPW_STATMASK_NOISE (1<<2) +#define LIBIPW_STATMASK_RATE (1<<3) +#define LIBIPW_STATMASK_WEMASK 0x7 + +#define LIBIPW_CCK_MODULATION (1<<0) +#define LIBIPW_OFDM_MODULATION (1<<1) + +#define LIBIPW_24GHZ_BAND (1<<0) +#define LIBIPW_52GHZ_BAND (1<<1) + +#define LIBIPW_CCK_RATE_1MB 0x02 +#define LIBIPW_CCK_RATE_2MB 0x04 +#define LIBIPW_CCK_RATE_5MB 0x0B +#define LIBIPW_CCK_RATE_11MB 0x16 +#define LIBIPW_OFDM_RATE_6MB 0x0C +#define LIBIPW_OFDM_RATE_9MB 0x12 +#define LIBIPW_OFDM_RATE_12MB 0x18 +#define LIBIPW_OFDM_RATE_18MB 0x24 +#define LIBIPW_OFDM_RATE_24MB 0x30 +#define LIBIPW_OFDM_RATE_36MB 0x48 +#define LIBIPW_OFDM_RATE_48MB 0x60 +#define LIBIPW_OFDM_RATE_54MB 0x6C +#define LIBIPW_BASIC_RATE_MASK 0x80 + +#define LIBIPW_CCK_RATE_1MB_MASK (1<<0) +#define LIBIPW_CCK_RATE_2MB_MASK (1<<1) +#define LIBIPW_CCK_RATE_5MB_MASK (1<<2) +#define LIBIPW_CCK_RATE_11MB_MASK (1<<3) +#define LIBIPW_OFDM_RATE_6MB_MASK (1<<4) +#define LIBIPW_OFDM_RATE_9MB_MASK (1<<5) +#define LIBIPW_OFDM_RATE_12MB_MASK (1<<6) +#define LIBIPW_OFDM_RATE_18MB_MASK (1<<7) +#define LIBIPW_OFDM_RATE_24MB_MASK (1<<8) +#define LIBIPW_OFDM_RATE_36MB_MASK (1<<9) +#define LIBIPW_OFDM_RATE_48MB_MASK (1<<10) +#define LIBIPW_OFDM_RATE_54MB_MASK (1<<11) + +#define LIBIPW_CCK_RATES_MASK 0x0000000F +#define LIBIPW_CCK_BASIC_RATES_MASK (LIBIPW_CCK_RATE_1MB_MASK | \ + LIBIPW_CCK_RATE_2MB_MASK) +#define LIBIPW_CCK_DEFAULT_RATES_MASK (LIBIPW_CCK_BASIC_RATES_MASK | \ + LIBIPW_CCK_RATE_5MB_MASK | \ + LIBIPW_CCK_RATE_11MB_MASK) + +#define LIBIPW_OFDM_RATES_MASK 0x00000FF0 +#define LIBIPW_OFDM_BASIC_RATES_MASK (LIBIPW_OFDM_RATE_6MB_MASK | \ + LIBIPW_OFDM_RATE_12MB_MASK | \ + LIBIPW_OFDM_RATE_24MB_MASK) +#define LIBIPW_OFDM_DEFAULT_RATES_MASK (LIBIPW_OFDM_BASIC_RATES_MASK | \ + LIBIPW_OFDM_RATE_9MB_MASK | \ + LIBIPW_OFDM_RATE_18MB_MASK | \ + LIBIPW_OFDM_RATE_36MB_MASK | \ + LIBIPW_OFDM_RATE_48MB_MASK | \ + LIBIPW_OFDM_RATE_54MB_MASK) +#define LIBIPW_DEFAULT_RATES_MASK (LIBIPW_OFDM_DEFAULT_RATES_MASK | \ + LIBIPW_CCK_DEFAULT_RATES_MASK) + +#define LIBIPW_NUM_OFDM_RATES 8 +#define LIBIPW_NUM_CCK_RATES 4 +#define LIBIPW_OFDM_SHIFT_MASK_A 4 + +/* NOTE: This data is for statistical purposes; not all hardware provides this + * information for frames received. + * For libipw_rx_mgt, you need to set at least the 'len' parameter. + */ +struct libipw_rx_stats { + u32 mac_time; + s8 rssi; + u8 signal; + u8 noise; + u16 rate; /* in 100 kbps */ + u8 received_channel; + u8 control; + u8 mask; + u8 freq; + u16 len; + u64 tsf; + u32 beacon_time; +}; + +/* IEEE 802.11 requires that STA supports concurrent reception of at least + * three fragmented frames. This define can be increased to support more + * concurrent frames, but it should be noted that each entry can consume about + * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ +#define LIBIPW_FRAG_CACHE_LEN 4 + +struct libipw_frag_entry { + unsigned long first_frag_time; + unsigned int seq; + unsigned int last_frag; + struct sk_buff *skb; + u8 src_addr[ETH_ALEN]; + u8 dst_addr[ETH_ALEN]; +}; + +struct libipw_stats { + unsigned int tx_unicast_frames; + unsigned int tx_multicast_frames; + unsigned int tx_fragments; + unsigned int tx_unicast_octets; + unsigned int tx_multicast_octets; + unsigned int tx_deferred_transmissions; + unsigned int tx_single_retry_frames; + unsigned int tx_multiple_retry_frames; + unsigned int tx_retry_limit_exceeded; + unsigned int tx_discards; + unsigned int rx_unicast_frames; + unsigned int rx_multicast_frames; + unsigned int rx_fragments; + unsigned int rx_unicast_octets; + unsigned int rx_multicast_octets; + unsigned int rx_fcs_errors; + unsigned int rx_discards_no_buffer; + unsigned int tx_discards_wrong_sa; + unsigned int rx_discards_undecryptable; + unsigned int rx_message_in_msg_fragments; + unsigned int rx_message_in_bad_msg_fragments; +}; + +struct libipw_device; + +#define SEC_KEY_1 (1<<0) +#define SEC_KEY_2 (1<<1) +#define SEC_KEY_3 (1<<2) +#define SEC_KEY_4 (1<<3) +#define SEC_ACTIVE_KEY (1<<4) +#define SEC_AUTH_MODE (1<<5) +#define SEC_UNICAST_GROUP (1<<6) +#define SEC_LEVEL (1<<7) +#define SEC_ENABLED (1<<8) +#define SEC_ENCRYPT (1<<9) + +#define SEC_LEVEL_0 0 /* None */ +#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ +#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ +#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ +#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ + +#define SEC_ALG_NONE 0 +#define SEC_ALG_WEP 1 +#define SEC_ALG_TKIP 2 +#define SEC_ALG_CCMP 3 + +#define WEP_KEYS 4 +#define WEP_KEY_LEN 13 +#define SCM_KEY_LEN 32 +#define SCM_TEMPORAL_KEY_LENGTH 16 + +struct libipw_security { + u16 active_key:2, enabled:1, unicast_uses_group:1, encrypt:1; + u8 auth_mode; + u8 encode_alg[WEP_KEYS]; + u8 key_sizes[WEP_KEYS]; + u8 keys[WEP_KEYS][SCM_KEY_LEN]; + u8 level; + u16 flags; +} __attribute__ ((packed)); + +/* + + 802.11 data frame from AP + + ,-------------------------------------------------------------------. +Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | + |------|------|---------|---------|---------|------|---------|------| +Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs | + | | tion | (BSSID) | | | ence | data | | + `-------------------------------------------------------------------' + +Total: 28-2340 bytes + +*/ + +#define BEACON_PROBE_SSID_ID_POSITION 12 + +struct libipw_hdr_1addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 payload[0]; +} __attribute__ ((packed)); + +struct libipw_hdr_2addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 payload[0]; +} __attribute__ ((packed)); + +struct libipw_hdr_3addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 payload[0]; +} __attribute__ ((packed)); + +struct libipw_hdr_4addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 addr4[ETH_ALEN]; + u8 payload[0]; +} __attribute__ ((packed)); + +struct libipw_hdr_3addrqos { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 payload[0]; + __le16 qos_ctl; +} __attribute__ ((packed)); + +struct libipw_info_element { + u8 id; + u8 len; + u8 data[0]; +} __attribute__ ((packed)); + +/* + * These are the data types that can make up management packets + * + u16 auth_algorithm; + u16 auth_sequence; + u16 beacon_interval; + u16 capability; + u8 current_ap[ETH_ALEN]; + u16 listen_interval; + struct { + u16 association_id:14, reserved:2; + } __attribute__ ((packed)); + u32 time_stamp[2]; + u16 reason; + u16 status; +*/ + +struct libipw_auth { + struct libipw_hdr_3addr header; + __le16 algorithm; + __le16 transaction; + __le16 status; + /* challenge */ + struct libipw_info_element info_element[0]; +} __attribute__ ((packed)); + +struct libipw_channel_switch { + u8 id; + u8 len; + u8 mode; + u8 channel; + u8 count; +} __attribute__ ((packed)); + +struct libipw_action { + struct libipw_hdr_3addr header; + u8 category; + u8 action; + union { + struct libipw_action_exchange { + u8 token; + struct libipw_info_element info_element[0]; + } exchange; + struct libipw_channel_switch channel_switch; + + } format; +} __attribute__ ((packed)); + +struct libipw_disassoc { + struct libipw_hdr_3addr header; + __le16 reason; +} __attribute__ ((packed)); + +/* Alias deauth for disassoc */ +#define libipw_deauth libipw_disassoc + +struct libipw_probe_request { + struct libipw_hdr_3addr header; + /* SSID, supported rates */ + struct libipw_info_element info_element[0]; +} __attribute__ ((packed)); + +struct libipw_probe_response { + struct libipw_hdr_3addr header; + __le32 time_stamp[2]; + __le16 beacon_interval; + __le16 capability; + /* SSID, supported rates, FH params, DS params, + * CF params, IBSS params, TIM (if beacon), RSN */ + struct libipw_info_element info_element[0]; +} __attribute__ ((packed)); + +/* Alias beacon for probe_response */ +#define libipw_beacon libipw_probe_response + +struct libipw_assoc_request { + struct libipw_hdr_3addr header; + __le16 capability; + __le16 listen_interval; + /* SSID, supported rates, RSN */ + struct libipw_info_element info_element[0]; +} __attribute__ ((packed)); + +struct libipw_reassoc_request { + struct libipw_hdr_3addr header; + __le16 capability; + __le16 listen_interval; + u8 current_ap[ETH_ALEN]; + struct libipw_info_element info_element[0]; +} __attribute__ ((packed)); + +struct libipw_assoc_response { + struct libipw_hdr_3addr header; + __le16 capability; + __le16 status; + __le16 aid; + /* supported rates */ + struct libipw_info_element info_element[0]; +} __attribute__ ((packed)); + +struct libipw_txb { + u8 nr_frags; + u8 encrypted; + u8 rts_included; + u8 reserved; + u16 frag_size; + u16 payload_size; + struct sk_buff *fragments[0]; +}; + +/* SWEEP TABLE ENTRIES NUMBER */ +#define MAX_SWEEP_TAB_ENTRIES 42 +#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7 +/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs + * only use 8, and then use extended rates for the remaining supported + * rates. Other APs, however, stick all of their supported rates on the + * main rates information element... */ +#define MAX_RATES_LENGTH ((u8)12) +#define MAX_RATES_EX_LENGTH ((u8)16) +#define MAX_NETWORK_COUNT 128 + +#define CRC_LENGTH 4U + +#define MAX_WPA_IE_LEN 64 + +#define NETWORK_HAS_OFDM (1<<1) +#define NETWORK_HAS_CCK (1<<2) + +/* QoS structure */ +#define NETWORK_HAS_QOS_PARAMETERS (1<<3) +#define NETWORK_HAS_QOS_INFORMATION (1<<4) +#define NETWORK_HAS_QOS_MASK (NETWORK_HAS_QOS_PARAMETERS | \ + NETWORK_HAS_QOS_INFORMATION) + +/* 802.11h */ +#define NETWORK_HAS_POWER_CONSTRAINT (1<<5) +#define NETWORK_HAS_CSA (1<<6) +#define NETWORK_HAS_QUIET (1<<7) +#define NETWORK_HAS_IBSS_DFS (1<<8) +#define NETWORK_HAS_TPC_REPORT (1<<9) + +#define NETWORK_HAS_ERP_VALUE (1<<10) + +#define QOS_QUEUE_NUM 4 +#define QOS_OUI_LEN 3 +#define QOS_OUI_TYPE 2 +#define QOS_ELEMENT_ID 221 +#define QOS_OUI_INFO_SUB_TYPE 0 +#define QOS_OUI_PARAM_SUB_TYPE 1 +#define QOS_VERSION_1 1 +#define QOS_AIFSN_MIN_VALUE 2 + +struct libipw_qos_information_element { + u8 elementID; + u8 length; + u8 qui[QOS_OUI_LEN]; + u8 qui_type; + u8 qui_subtype; + u8 version; + u8 ac_info; +} __attribute__ ((packed)); + +struct libipw_qos_ac_parameter { + u8 aci_aifsn; + u8 ecw_min_max; + __le16 tx_op_limit; +} __attribute__ ((packed)); + +struct libipw_qos_parameter_info { + struct libipw_qos_information_element info_element; + u8 reserved; + struct libipw_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM]; +} __attribute__ ((packed)); + +struct libipw_qos_parameters { + __le16 cw_min[QOS_QUEUE_NUM]; + __le16 cw_max[QOS_QUEUE_NUM]; + u8 aifs[QOS_QUEUE_NUM]; + u8 flag[QOS_QUEUE_NUM]; + __le16 tx_op_limit[QOS_QUEUE_NUM]; +} __attribute__ ((packed)); + +struct libipw_qos_data { + struct libipw_qos_parameters parameters; + int active; + int supported; + u8 param_count; + u8 old_param_count; +}; + +struct libipw_tim_parameters { + u8 tim_count; + u8 tim_period; +} __attribute__ ((packed)); + +/*******************************************************/ + +enum { /* libipw_basic_report.map */ + LIBIPW_BASIC_MAP_BSS = (1 << 0), + LIBIPW_BASIC_MAP_OFDM = (1 << 1), + LIBIPW_BASIC_MAP_UNIDENTIFIED = (1 << 2), + LIBIPW_BASIC_MAP_RADAR = (1 << 3), + LIBIPW_BASIC_MAP_UNMEASURED = (1 << 4), + /* Bits 5-7 are reserved */ + +}; +struct libipw_basic_report { + u8 channel; + __le64 start_time; + __le16 duration; + u8 map; +} __attribute__ ((packed)); + +enum { /* libipw_measurement_request.mode */ + /* Bit 0 is reserved */ + LIBIPW_MEASUREMENT_ENABLE = (1 << 1), + LIBIPW_MEASUREMENT_REQUEST = (1 << 2), + LIBIPW_MEASUREMENT_REPORT = (1 << 3), + /* Bits 4-7 are reserved */ +}; + +enum { + LIBIPW_REPORT_BASIC = 0, /* required */ + LIBIPW_REPORT_CCA = 1, /* optional */ + LIBIPW_REPORT_RPI = 2, /* optional */ + /* 3-255 reserved */ +}; + +struct libipw_measurement_params { + u8 channel; + __le64 start_time; + __le16 duration; +} __attribute__ ((packed)); + +struct libipw_measurement_request { + struct libipw_info_element ie; + u8 token; + u8 mode; + u8 type; + struct libipw_measurement_params params[0]; +} __attribute__ ((packed)); + +struct libipw_measurement_report { + struct libipw_info_element ie; + u8 token; + u8 mode; + u8 type; + union { + struct libipw_basic_report basic[0]; + } u; +} __attribute__ ((packed)); + +struct libipw_tpc_report { + u8 transmit_power; + u8 link_margin; +} __attribute__ ((packed)); + +struct libipw_channel_map { + u8 channel; + u8 map; +} __attribute__ ((packed)); + +struct libipw_ibss_dfs { + struct libipw_info_element ie; + u8 owner[ETH_ALEN]; + u8 recovery_interval; + struct libipw_channel_map channel_map[0]; +}; + +struct libipw_csa { + u8 mode; + u8 channel; + u8 count; +} __attribute__ ((packed)); + +struct libipw_quiet { + u8 count; + u8 period; + u8 duration; + u8 offset; +} __attribute__ ((packed)); + +struct libipw_network { + /* These entries are used to identify a unique network */ + u8 bssid[ETH_ALEN]; + u8 channel; + /* Ensure null-terminated for any debug msgs */ + u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 ssid_len; + + struct libipw_qos_data qos_data; + + /* These are network statistics */ + struct libipw_rx_stats stats; + u16 capability; + u8 rates[MAX_RATES_LENGTH]; + u8 rates_len; + u8 rates_ex[MAX_RATES_EX_LENGTH]; + u8 rates_ex_len; + unsigned long last_scanned; + u8 mode; + u32 flags; + u32 last_associate; + u32 time_stamp[2]; + u16 beacon_interval; + u16 listen_interval; + u16 atim_window; + u8 erp_value; + u8 wpa_ie[MAX_WPA_IE_LEN]; + size_t wpa_ie_len; + u8 rsn_ie[MAX_WPA_IE_LEN]; + size_t rsn_ie_len; + struct libipw_tim_parameters tim; + + /* 802.11h info */ + + /* Power Constraint - mandatory if spctrm mgmt required */ + u8 power_constraint; + + /* TPC Report - mandatory if spctrm mgmt required */ + struct libipw_tpc_report tpc_report; + + /* IBSS DFS - mandatory if spctrm mgmt required and IBSS + * NOTE: This is variable length and so must be allocated dynamically */ + struct libipw_ibss_dfs *ibss_dfs; + + /* Channel Switch Announcement - optional if spctrm mgmt required */ + struct libipw_csa csa; + + /* Quiet - optional if spctrm mgmt required */ + struct libipw_quiet quiet; + + struct list_head list; +}; + +enum libipw_state { + LIBIPW_UNINITIALIZED = 0, + LIBIPW_INITIALIZED, + LIBIPW_ASSOCIATING, + LIBIPW_ASSOCIATED, + LIBIPW_AUTHENTICATING, + LIBIPW_AUTHENTICATED, + LIBIPW_SHUTDOWN +}; + +#define DEFAULT_MAX_SCAN_AGE (15 * HZ) +#define DEFAULT_FTS 2346 + +#define CFG_LIBIPW_RESERVE_FCS (1<<0) +#define CFG_LIBIPW_COMPUTE_FCS (1<<1) +#define CFG_LIBIPW_RTS (1<<2) + +#define LIBIPW_24GHZ_MIN_CHANNEL 1 +#define LIBIPW_24GHZ_MAX_CHANNEL 14 +#define LIBIPW_24GHZ_CHANNELS (LIBIPW_24GHZ_MAX_CHANNEL - \ + LIBIPW_24GHZ_MIN_CHANNEL + 1) + +#define LIBIPW_52GHZ_MIN_CHANNEL 34 +#define LIBIPW_52GHZ_MAX_CHANNEL 165 +#define LIBIPW_52GHZ_CHANNELS (LIBIPW_52GHZ_MAX_CHANNEL - \ + LIBIPW_52GHZ_MIN_CHANNEL + 1) + +enum { + LIBIPW_CH_PASSIVE_ONLY = (1 << 0), + LIBIPW_CH_80211H_RULES = (1 << 1), + LIBIPW_CH_B_ONLY = (1 << 2), + LIBIPW_CH_NO_IBSS = (1 << 3), + LIBIPW_CH_UNIFORM_SPREADING = (1 << 4), + LIBIPW_CH_RADAR_DETECT = (1 << 5), + LIBIPW_CH_INVALID = (1 << 6), +}; + +struct libipw_channel { + u32 freq; /* in MHz */ + u8 channel; + u8 flags; + u8 max_power; /* in dBm */ +}; + +struct libipw_geo { + u8 name[4]; + u8 bg_channels; + u8 a_channels; + struct libipw_channel bg[LIBIPW_24GHZ_CHANNELS]; + struct libipw_channel a[LIBIPW_52GHZ_CHANNELS]; +}; + +struct libipw_device { + struct net_device *dev; + struct libipw_security sec; + + /* Bookkeeping structures */ + struct libipw_stats ieee_stats; + + struct libipw_geo geo; + + /* Probe / Beacon management */ + struct list_head network_free_list; + struct list_head network_list; + struct libipw_network *networks; + int scans; + int scan_age; + + int iw_mode; /* operating mode (IW_MODE_*) */ + struct iw_spy_data spy_data; /* iwspy support */ + + spinlock_t lock; + + int tx_headroom; /* Set to size of any additional room needed at front + * of allocated Tx SKBs */ + u32 config; + + /* WEP and other encryption related settings at the device level */ + int open_wep; /* Set to 1 to allow unencrypted frames */ + + int reset_on_keychange; /* Set to 1 if the HW needs to be reset on + * WEP key changes */ + + /* If the host performs {en,de}cryption, then set to 1 */ + int host_encrypt; + int host_encrypt_msdu; + int host_decrypt; + /* host performs multicast decryption */ + int host_mc_decrypt; + + /* host should strip IV and ICV from protected frames */ + /* meaningful only when hardware decryption is being used */ + int host_strip_iv_icv; + + int host_open_frag; + int host_build_iv; + int ieee802_1x; /* is IEEE 802.1X used */ + + /* WPA data */ + int wpa_enabled; + int drop_unencrypted; + int privacy_invoked; + size_t wpa_ie_len; + u8 *wpa_ie; + + struct lib80211_crypt_info crypt_info; + + int bcrx_sta_key; /* use individual keys to override default keys even + * with RX of broad/multicast frames */ + + /* Fragmentation structures */ + struct libipw_frag_entry frag_cache[LIBIPW_FRAG_CACHE_LEN]; + unsigned int frag_next_idx; + u16 fts; /* Fragmentation Threshold */ + u16 rts; /* RTS threshold */ + + /* Association info */ + u8 bssid[ETH_ALEN]; + + enum libipw_state state; + + int mode; /* A, B, G */ + int modulation; /* CCK, OFDM */ + int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ + int abg_true; /* ABG flag */ + + int perfect_rssi; + int worst_rssi; + + u16 prev_seq_ctl; /* used to drop duplicate frames */ + + /* Callback functions */ + void (*set_security) (struct net_device * dev, + struct libipw_security * sec); + int (*hard_start_xmit) (struct libipw_txb * txb, + struct net_device * dev, int pri); + int (*reset_port) (struct net_device * dev); + int (*is_queue_full) (struct net_device * dev, int pri); + + int (*handle_management) (struct net_device * dev, + struct libipw_network * network, u16 type); + int (*is_qos_active) (struct net_device *dev, struct sk_buff *skb); + + /* Typical STA methods */ + int (*handle_auth) (struct net_device * dev, + struct libipw_auth * auth); + int (*handle_deauth) (struct net_device * dev, + struct libipw_deauth * auth); + int (*handle_action) (struct net_device * dev, + struct libipw_action * action, + struct libipw_rx_stats * stats); + int (*handle_disassoc) (struct net_device * dev, + struct libipw_disassoc * assoc); + int (*handle_beacon) (struct net_device * dev, + struct libipw_beacon * beacon, + struct libipw_network * network); + int (*handle_probe_response) (struct net_device * dev, + struct libipw_probe_response * resp, + struct libipw_network * network); + int (*handle_probe_request) (struct net_device * dev, + struct libipw_probe_request * req, + struct libipw_rx_stats * stats); + int (*handle_assoc_response) (struct net_device * dev, + struct libipw_assoc_response * resp, + struct libipw_network * network); + + /* Typical AP methods */ + int (*handle_assoc_request) (struct net_device * dev); + int (*handle_reassoc_request) (struct net_device * dev, + struct libipw_reassoc_request * req); + + /* This must be the last item so that it points to the data + * allocated beyond this structure by alloc_ieee80211 */ + u8 priv[0]; +}; + +#define IEEE_A (1<<0) +#define IEEE_B (1<<1) +#define IEEE_G (1<<2) +#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) + +static inline void *libipw_priv(struct net_device *dev) +{ + return ((struct libipw_device *)netdev_priv(dev))->priv; +} + +static inline int libipw_is_valid_mode(struct libipw_device *ieee, + int mode) +{ + /* + * It is possible for both access points and our device to support + * combinations of modes, so as long as there is one valid combination + * of ap/device supported modes, then return success + * + */ + if ((mode & IEEE_A) && + (ieee->modulation & LIBIPW_OFDM_MODULATION) && + (ieee->freq_band & LIBIPW_52GHZ_BAND)) + return 1; + + if ((mode & IEEE_G) && + (ieee->modulation & LIBIPW_OFDM_MODULATION) && + (ieee->freq_band & LIBIPW_24GHZ_BAND)) + return 1; + + if ((mode & IEEE_B) && + (ieee->modulation & LIBIPW_CCK_MODULATION) && + (ieee->freq_band & LIBIPW_24GHZ_BAND)) + return 1; + + return 0; +} + +static inline int libipw_get_hdrlen(u16 fc) +{ + int hdrlen = LIBIPW_3ADDR_LEN; + u16 stype = WLAN_FC_GET_STYPE(fc); + + switch (WLAN_FC_GET_TYPE(fc)) { + case IEEE80211_FTYPE_DATA: + if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) + hdrlen = LIBIPW_4ADDR_LEN; + if (stype & IEEE80211_STYPE_QOS_DATA) + hdrlen += 2; + break; + case IEEE80211_FTYPE_CTL: + switch (WLAN_FC_GET_STYPE(fc)) { + case IEEE80211_STYPE_CTS: + case IEEE80211_STYPE_ACK: + hdrlen = LIBIPW_1ADDR_LEN; + break; + default: + hdrlen = LIBIPW_2ADDR_LEN; + break; + } + break; + } + + return hdrlen; +} + +static inline u8 *libipw_get_payload(struct ieee80211_hdr *hdr) +{ + switch (libipw_get_hdrlen(le16_to_cpu(hdr->frame_control))) { + case LIBIPW_1ADDR_LEN: + return ((struct libipw_hdr_1addr *)hdr)->payload; + case LIBIPW_2ADDR_LEN: + return ((struct libipw_hdr_2addr *)hdr)->payload; + case LIBIPW_3ADDR_LEN: + return ((struct libipw_hdr_3addr *)hdr)->payload; + case LIBIPW_4ADDR_LEN: + return ((struct libipw_hdr_4addr *)hdr)->payload; + } + return NULL; +} + +static inline int libipw_is_ofdm_rate(u8 rate) +{ + switch (rate & ~LIBIPW_BASIC_RATE_MASK) { + case LIBIPW_OFDM_RATE_6MB: + case LIBIPW_OFDM_RATE_9MB: + case LIBIPW_OFDM_RATE_12MB: + case LIBIPW_OFDM_RATE_18MB: + case LIBIPW_OFDM_RATE_24MB: + case LIBIPW_OFDM_RATE_36MB: + case LIBIPW_OFDM_RATE_48MB: + case LIBIPW_OFDM_RATE_54MB: + return 1; + } + return 0; +} + +static inline int libipw_is_cck_rate(u8 rate) +{ + switch (rate & ~LIBIPW_BASIC_RATE_MASK) { + case LIBIPW_CCK_RATE_1MB: + case LIBIPW_CCK_RATE_2MB: + case LIBIPW_CCK_RATE_5MB: + case LIBIPW_CCK_RATE_11MB: + return 1; + } + return 0; +} + +/* ieee80211.c */ +extern void free_ieee80211(struct net_device *dev); +extern struct net_device *alloc_ieee80211(int sizeof_priv); +extern int libipw_change_mtu(struct net_device *dev, int new_mtu); + +extern void libipw_networks_age(struct libipw_device *ieee, + unsigned long age_secs); + +extern int libipw_set_encryption(struct libipw_device *ieee); + +/* libipw_tx.c */ +extern int libipw_xmit(struct sk_buff *skb, struct net_device *dev); +extern void libipw_txb_free(struct libipw_txb *); + +/* libipw_rx.c */ +extern void libipw_rx_any(struct libipw_device *ieee, + struct sk_buff *skb, struct libipw_rx_stats *stats); +extern int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb, + struct libipw_rx_stats *rx_stats); +/* make sure to set stats->len */ +extern void libipw_rx_mgt(struct libipw_device *ieee, + struct libipw_hdr_4addr *header, + struct libipw_rx_stats *stats); +extern void libipw_network_reset(struct libipw_network *network); + +/* libipw_geo.c */ +extern const struct libipw_geo *libipw_get_geo(struct libipw_device + *ieee); +extern int libipw_set_geo(struct libipw_device *ieee, + const struct libipw_geo *geo); + +extern int libipw_is_valid_channel(struct libipw_device *ieee, + u8 channel); +extern int libipw_channel_to_index(struct libipw_device *ieee, + u8 channel); +extern u8 libipw_freq_to_channel(struct libipw_device *ieee, u32 freq); +extern u8 libipw_get_channel_flags(struct libipw_device *ieee, + u8 channel); +extern const struct libipw_channel *libipw_get_channel(struct + libipw_device + *ieee, u8 channel); +extern u32 libipw_channel_to_freq(struct libipw_device * ieee, + u8 channel); + +/* libipw_wx.c */ +extern int libipw_wx_get_scan(struct libipw_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +extern int libipw_wx_set_encode(struct libipw_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +extern int libipw_wx_get_encode(struct libipw_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +extern int libipw_wx_set_encodeext(struct libipw_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +extern int libipw_wx_get_encodeext(struct libipw_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +static inline void libipw_increment_scans(struct libipw_device *ieee) +{ + ieee->scans++; +} + +static inline int libipw_get_scans(struct libipw_device *ieee) +{ + return ieee->scans; +} + +#endif /* LIBIPW_H */ diff --git a/drivers/net/wireless/ipw2x00/libipw_geo.c b/drivers/net/wireless/ipw2x00/libipw_geo.c index 9dfbb8760f6..d04979ba2a5 100644 --- a/drivers/net/wireless/ipw2x00/libipw_geo.c +++ b/drivers/net/wireless/ipw2x00/libipw_geo.c @@ -41,9 +41,9 @@ #include #include -#include "ieee80211.h" +#include "libipw.h" -int ieee80211_is_valid_channel(struct ieee80211_device *ieee, u8 channel) +int libipw_is_valid_channel(struct libipw_device *ieee, u8 channel) { int i; @@ -52,27 +52,27 @@ int ieee80211_is_valid_channel(struct ieee80211_device *ieee, u8 channel) if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0) return 0; - if (ieee->freq_band & IEEE80211_24GHZ_BAND) + if (ieee->freq_band & LIBIPW_24GHZ_BAND) for (i = 0; i < ieee->geo.bg_channels; i++) /* NOTE: If G mode is currently supported but * this is a B only channel, we don't see it * as valid. */ if ((ieee->geo.bg[i].channel == channel) && - !(ieee->geo.bg[i].flags & IEEE80211_CH_INVALID) && + !(ieee->geo.bg[i].flags & LIBIPW_CH_INVALID) && (!(ieee->mode & IEEE_G) || - !(ieee->geo.bg[i].flags & IEEE80211_CH_B_ONLY))) - return IEEE80211_24GHZ_BAND; + !(ieee->geo.bg[i].flags & LIBIPW_CH_B_ONLY))) + return LIBIPW_24GHZ_BAND; - if (ieee->freq_band & IEEE80211_52GHZ_BAND) + if (ieee->freq_band & LIBIPW_52GHZ_BAND) for (i = 0; i < ieee->geo.a_channels; i++) if ((ieee->geo.a[i].channel == channel) && - !(ieee->geo.a[i].flags & IEEE80211_CH_INVALID)) - return IEEE80211_52GHZ_BAND; + !(ieee->geo.a[i].flags & LIBIPW_CH_INVALID)) + return LIBIPW_52GHZ_BAND; return 0; } -int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel) +int libipw_channel_to_index(struct libipw_device *ieee, u8 channel) { int i; @@ -81,12 +81,12 @@ int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel) if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0) return -1; - if (ieee->freq_band & IEEE80211_24GHZ_BAND) + if (ieee->freq_band & LIBIPW_24GHZ_BAND) for (i = 0; i < ieee->geo.bg_channels; i++) if (ieee->geo.bg[i].channel == channel) return i; - if (ieee->freq_band & IEEE80211_52GHZ_BAND) + if (ieee->freq_band & LIBIPW_52GHZ_BAND) for (i = 0; i < ieee->geo.a_channels; i++) if (ieee->geo.a[i].channel == channel) return i; @@ -94,22 +94,22 @@ int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel) return -1; } -u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee, u8 channel) +u32 libipw_channel_to_freq(struct libipw_device * ieee, u8 channel) { - const struct ieee80211_channel * ch; + const struct libipw_channel * ch; /* Driver needs to initialize the geography map before using * these helper functions */ if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0) return 0; - ch = ieee80211_get_channel(ieee, channel); + ch = libipw_get_channel(ieee, channel); if (!ch->channel) return 0; return ch->freq; } -u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq) +u8 libipw_freq_to_channel(struct libipw_device * ieee, u32 freq) { int i; @@ -120,12 +120,12 @@ u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq) freq /= 100000; - if (ieee->freq_band & IEEE80211_24GHZ_BAND) + if (ieee->freq_band & LIBIPW_24GHZ_BAND) for (i = 0; i < ieee->geo.bg_channels; i++) if (ieee->geo.bg[i].freq == freq) return ieee->geo.bg[i].channel; - if (ieee->freq_band & IEEE80211_52GHZ_BAND) + if (ieee->freq_band & LIBIPW_52GHZ_BAND) for (i = 0; i < ieee->geo.a_channels; i++) if (ieee->geo.a[i].freq == freq) return ieee->geo.a[i].channel; @@ -133,63 +133,63 @@ u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq) return 0; } -int ieee80211_set_geo(struct ieee80211_device *ieee, - const struct ieee80211_geo *geo) +int libipw_set_geo(struct libipw_device *ieee, + const struct libipw_geo *geo) { memcpy(ieee->geo.name, geo->name, 3); ieee->geo.name[3] = '\0'; ieee->geo.bg_channels = geo->bg_channels; ieee->geo.a_channels = geo->a_channels; memcpy(ieee->geo.bg, geo->bg, geo->bg_channels * - sizeof(struct ieee80211_channel)); + sizeof(struct libipw_channel)); memcpy(ieee->geo.a, geo->a, ieee->geo.a_channels * - sizeof(struct ieee80211_channel)); + sizeof(struct libipw_channel)); return 0; } -const struct ieee80211_geo *ieee80211_get_geo(struct ieee80211_device *ieee) +const struct libipw_geo *libipw_get_geo(struct libipw_device *ieee) { return &ieee->geo; } -u8 ieee80211_get_channel_flags(struct ieee80211_device * ieee, u8 channel) +u8 libipw_get_channel_flags(struct libipw_device * ieee, u8 channel) { - int index = ieee80211_channel_to_index(ieee, channel); + int index = libipw_channel_to_index(ieee, channel); if (index == -1) - return IEEE80211_CH_INVALID; + return LIBIPW_CH_INVALID; - if (channel <= IEEE80211_24GHZ_CHANNELS) + if (channel <= LIBIPW_24GHZ_CHANNELS) return ieee->geo.bg[index].flags; return ieee->geo.a[index].flags; } -static const struct ieee80211_channel bad_channel = { +static const struct libipw_channel bad_channel = { .channel = 0, - .flags = IEEE80211_CH_INVALID, + .flags = LIBIPW_CH_INVALID, .max_power = 0, }; -const struct ieee80211_channel *ieee80211_get_channel(struct ieee80211_device +const struct libipw_channel *libipw_get_channel(struct libipw_device *ieee, u8 channel) { - int index = ieee80211_channel_to_index(ieee, channel); + int index = libipw_channel_to_index(ieee, channel); if (index == -1) return &bad_channel; - if (channel <= IEEE80211_24GHZ_CHANNELS) + if (channel <= LIBIPW_24GHZ_CHANNELS) return &ieee->geo.bg[index]; return &ieee->geo.a[index]; } -EXPORT_SYMBOL(ieee80211_get_channel); -EXPORT_SYMBOL(ieee80211_get_channel_flags); -EXPORT_SYMBOL(ieee80211_is_valid_channel); -EXPORT_SYMBOL(ieee80211_freq_to_channel); -EXPORT_SYMBOL(ieee80211_channel_to_freq); -EXPORT_SYMBOL(ieee80211_channel_to_index); -EXPORT_SYMBOL(ieee80211_set_geo); -EXPORT_SYMBOL(ieee80211_get_geo); +EXPORT_SYMBOL(libipw_get_channel); +EXPORT_SYMBOL(libipw_get_channel_flags); +EXPORT_SYMBOL(libipw_is_valid_channel); +EXPORT_SYMBOL(libipw_freq_to_channel); +EXPORT_SYMBOL(libipw_channel_to_freq); +EXPORT_SYMBOL(libipw_channel_to_index); +EXPORT_SYMBOL(libipw_set_geo); +EXPORT_SYMBOL(libipw_get_geo); diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c index 8ce6e961c5d..00c3640b0f8 100644 --- a/drivers/net/wireless/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/ipw2x00/libipw_module.c @@ -50,11 +50,11 @@ #include #include -#include "ieee80211.h" +#include "libipw.h" #define DRV_DESCRIPTION "802.11 data/management/control stack" #define DRV_NAME "ieee80211" -#define DRV_VERSION IEEE80211_VERSION +#define DRV_VERSION LIBIPW_VERSION #define DRV_COPYRIGHT "Copyright (C) 2004-2005 Intel Corporation " MODULE_VERSION(DRV_VERSION); @@ -62,13 +62,13 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); -static int ieee80211_networks_allocate(struct ieee80211_device *ieee) +static int libipw_networks_allocate(struct libipw_device *ieee) { if (ieee->networks) return 0; ieee->networks = - kzalloc(MAX_NETWORK_COUNT * sizeof(struct ieee80211_network), + kzalloc(MAX_NETWORK_COUNT * sizeof(struct libipw_network), GFP_KERNEL); if (!ieee->networks) { printk(KERN_WARNING "%s: Out of memory allocating beacons\n", @@ -79,7 +79,7 @@ static int ieee80211_networks_allocate(struct ieee80211_device *ieee) return 0; } -void ieee80211_network_reset(struct ieee80211_network *network) +void libipw_network_reset(struct libipw_network *network) { if (!network) return; @@ -90,7 +90,7 @@ void ieee80211_network_reset(struct ieee80211_network *network) } } -static inline void ieee80211_networks_free(struct ieee80211_device *ieee) +static inline void libipw_networks_free(struct libipw_device *ieee) { int i; @@ -105,10 +105,10 @@ static inline void ieee80211_networks_free(struct ieee80211_device *ieee) ieee->networks = NULL; } -void ieee80211_networks_age(struct ieee80211_device *ieee, +void libipw_networks_age(struct libipw_device *ieee, unsigned long age_secs) { - struct ieee80211_network *network = NULL; + struct libipw_network *network = NULL; unsigned long flags; unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC); @@ -118,9 +118,9 @@ void ieee80211_networks_age(struct ieee80211_device *ieee, } spin_unlock_irqrestore(&ieee->lock, flags); } -EXPORT_SYMBOL(ieee80211_networks_age); +EXPORT_SYMBOL(libipw_networks_age); -static void ieee80211_networks_initialize(struct ieee80211_device *ieee) +static void libipw_networks_initialize(struct libipw_device *ieee) { int i; @@ -131,38 +131,38 @@ static void ieee80211_networks_initialize(struct ieee80211_device *ieee) &ieee->network_free_list); } -int ieee80211_change_mtu(struct net_device *dev, int new_mtu) +int libipw_change_mtu(struct net_device *dev, int new_mtu) { - if ((new_mtu < 68) || (new_mtu > IEEE80211_DATA_LEN)) + if ((new_mtu < 68) || (new_mtu > LIBIPW_DATA_LEN)) return -EINVAL; dev->mtu = new_mtu; return 0; } -EXPORT_SYMBOL(ieee80211_change_mtu); +EXPORT_SYMBOL(libipw_change_mtu); struct net_device *alloc_ieee80211(int sizeof_priv) { - struct ieee80211_device *ieee; + struct libipw_device *ieee; struct net_device *dev; int err; - IEEE80211_DEBUG_INFO("Initializing...\n"); + LIBIPW_DEBUG_INFO("Initializing...\n"); - dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv); + dev = alloc_etherdev(sizeof(struct libipw_device) + sizeof_priv); if (!dev) { - IEEE80211_ERROR("Unable to allocate network device.\n"); + LIBIPW_ERROR("Unable to allocate network device.\n"); goto failed; } ieee = netdev_priv(dev); ieee->dev = dev; - err = ieee80211_networks_allocate(ieee); + err = libipw_networks_allocate(ieee); if (err) { - IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err); + LIBIPW_ERROR("Unable to allocate beacon storage: %d\n", err); goto failed_free_netdev; } - ieee80211_networks_initialize(ieee); + libipw_networks_initialize(ieee); /* Default fragmentation threshold is maximum payload size */ ieee->fts = DEFAULT_FTS; @@ -201,25 +201,25 @@ failed: void free_ieee80211(struct net_device *dev) { - struct ieee80211_device *ieee = netdev_priv(dev); + struct libipw_device *ieee = netdev_priv(dev); lib80211_crypt_info_free(&ieee->crypt_info); - ieee80211_networks_free(ieee); + libipw_networks_free(ieee); free_netdev(dev); } #ifdef CONFIG_LIBIPW_DEBUG static int debug = 0; -u32 ieee80211_debug_level = 0; -EXPORT_SYMBOL_GPL(ieee80211_debug_level); -static struct proc_dir_entry *ieee80211_proc = NULL; +u32 libipw_debug_level = 0; +EXPORT_SYMBOL_GPL(libipw_debug_level); +static struct proc_dir_entry *libipw_proc = NULL; static int show_debug_level(char *page, char **start, off_t offset, int count, int *eof, void *data) { - return snprintf(page, count, "0x%08X\n", ieee80211_debug_level); + return snprintf(page, count, "0x%08X\n", libipw_debug_level); } static int store_debug_level(struct file *file, const char __user * buffer, @@ -236,29 +236,29 @@ static int store_debug_level(struct file *file, const char __user * buffer, printk(KERN_INFO DRV_NAME ": %s is not in hex or decimal form.\n", buf); else - ieee80211_debug_level = val; + libipw_debug_level = val; return strnlen(buf, len); } #endif /* CONFIG_LIBIPW_DEBUG */ -static int __init ieee80211_init(void) +static int __init libipw_init(void) { #ifdef CONFIG_LIBIPW_DEBUG struct proc_dir_entry *e; - ieee80211_debug_level = debug; - ieee80211_proc = proc_mkdir(DRV_NAME, init_net.proc_net); - if (ieee80211_proc == NULL) { - IEEE80211_ERROR("Unable to create " DRV_NAME + libipw_debug_level = debug; + libipw_proc = proc_mkdir(DRV_NAME, init_net.proc_net); + if (libipw_proc == NULL) { + LIBIPW_ERROR("Unable to create " DRV_NAME " proc directory\n"); return -EIO; } e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR, - ieee80211_proc); + libipw_proc); if (!e) { remove_proc_entry(DRV_NAME, init_net.proc_net); - ieee80211_proc = NULL; + libipw_proc = NULL; return -EIO; } e->read_proc = show_debug_level; @@ -272,13 +272,13 @@ static int __init ieee80211_init(void) return 0; } -static void __exit ieee80211_exit(void) +static void __exit libipw_exit(void) { #ifdef CONFIG_LIBIPW_DEBUG - if (ieee80211_proc) { - remove_proc_entry("debug_level", ieee80211_proc); + if (libipw_proc) { + remove_proc_entry("debug_level", libipw_proc); remove_proc_entry(DRV_NAME, init_net.proc_net); - ieee80211_proc = NULL; + libipw_proc = NULL; } #endif /* CONFIG_LIBIPW_DEBUG */ } @@ -289,8 +289,8 @@ module_param(debug, int, 0444); MODULE_PARM_DESC(debug, "debug output mask"); #endif /* CONFIG_LIBIPW_DEBUG */ -module_exit(ieee80211_exit); -module_init(ieee80211_init); +module_exit(libipw_exit); +module_init(libipw_init); EXPORT_SYMBOL(alloc_ieee80211); EXPORT_SYMBOL(free_ieee80211); diff --git a/drivers/net/wireless/ipw2x00/libipw_rx.c b/drivers/net/wireless/ipw2x00/libipw_rx.c index dae4b8e4d8e..282b1f7ff1e 100644 --- a/drivers/net/wireless/ipw2x00/libipw_rx.c +++ b/drivers/net/wireless/ipw2x00/libipw_rx.c @@ -34,18 +34,18 @@ #include -#include "ieee80211.h" +#include "libipw.h" -static void ieee80211_monitor_rx(struct ieee80211_device *ieee, +static void libipw_monitor_rx(struct libipw_device *ieee, struct sk_buff *skb, - struct ieee80211_rx_stats *rx_stats) + struct libipw_rx_stats *rx_stats) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; u16 fc = le16_to_cpu(hdr->frame_control); skb->dev = ieee->dev; skb_reset_mac_header(skb); - skb_pull(skb, ieee80211_get_hdrlen(fc)); + skb_pull(skb, libipw_get_hdrlen(fc)); skb->pkt_type = PACKET_OTHERHOST; skb->protocol = htons(ETH_P_80211_RAW); memset(skb->cb, 0, sizeof(skb->cb)); @@ -53,22 +53,22 @@ static void ieee80211_monitor_rx(struct ieee80211_device *ieee, } /* Called only as a tasklet (software IRQ) */ -static struct ieee80211_frag_entry *ieee80211_frag_cache_find(struct - ieee80211_device +static struct libipw_frag_entry *libipw_frag_cache_find(struct + libipw_device *ieee, unsigned int seq, unsigned int frag, u8 * src, u8 * dst) { - struct ieee80211_frag_entry *entry; + struct libipw_frag_entry *entry; int i; - for (i = 0; i < IEEE80211_FRAG_CACHE_LEN; i++) { + for (i = 0; i < LIBIPW_FRAG_CACHE_LEN; i++) { entry = &ieee->frag_cache[i]; if (entry->skb != NULL && time_after(jiffies, entry->first_frag_time + 2 * HZ)) { - IEEE80211_DEBUG_FRAG("expiring fragment cache entry " + LIBIPW_DEBUG_FRAG("expiring fragment cache entry " "seq=%u last_frag=%u\n", entry->seq, entry->last_frag); dev_kfree_skb_any(entry->skb); @@ -86,13 +86,13 @@ static struct ieee80211_frag_entry *ieee80211_frag_cache_find(struct } /* Called only as a tasklet (software IRQ) */ -static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee, - struct ieee80211_hdr_4addr *hdr) +static struct sk_buff *libipw_frag_cache_get(struct libipw_device *ieee, + struct libipw_hdr_4addr *hdr) { struct sk_buff *skb = NULL; u16 sc; unsigned int frag, seq; - struct ieee80211_frag_entry *entry; + struct libipw_frag_entry *entry; sc = le16_to_cpu(hdr->seq_ctl); frag = WLAN_GET_SEQ_FRAG(sc); @@ -101,7 +101,7 @@ static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee, if (frag == 0) { /* Reserve enough space to fit maximum frame length */ skb = dev_alloc_skb(ieee->dev->mtu + - sizeof(struct ieee80211_hdr_4addr) + + sizeof(struct libipw_hdr_4addr) + 8 /* LLC */ + 2 /* alignment */ + 8 /* WEP */ + ETH_ALEN /* WDS */ ); @@ -110,7 +110,7 @@ static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee, entry = &ieee->frag_cache[ieee->frag_next_idx]; ieee->frag_next_idx++; - if (ieee->frag_next_idx >= IEEE80211_FRAG_CACHE_LEN) + if (ieee->frag_next_idx >= LIBIPW_FRAG_CACHE_LEN) ieee->frag_next_idx = 0; if (entry->skb != NULL) @@ -125,7 +125,7 @@ static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee, } else { /* received a fragment of a frame for which the head fragment * should have already been received */ - entry = ieee80211_frag_cache_find(ieee, seq, frag, hdr->addr2, + entry = libipw_frag_cache_find(ieee, seq, frag, hdr->addr2, hdr->addr1); if (entry != NULL) { entry->last_frag = frag; @@ -137,21 +137,21 @@ static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee, } /* Called only as a tasklet (software IRQ) */ -static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee, - struct ieee80211_hdr_4addr *hdr) +static int libipw_frag_cache_invalidate(struct libipw_device *ieee, + struct libipw_hdr_4addr *hdr) { u16 sc; unsigned int seq; - struct ieee80211_frag_entry *entry; + struct libipw_frag_entry *entry; sc = le16_to_cpu(hdr->seq_ctl); seq = WLAN_GET_SEQ_SEQ(sc); - entry = ieee80211_frag_cache_find(ieee, seq, -1, hdr->addr2, + entry = libipw_frag_cache_find(ieee, seq, -1, hdr->addr2, hdr->addr1); if (entry == NULL) { - IEEE80211_DEBUG_FRAG("could not invalidate fragment cache " + LIBIPW_DEBUG_FRAG("could not invalidate fragment cache " "entry (seq=%u)\n", seq); return -1; } @@ -161,14 +161,14 @@ static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee, } #ifdef NOT_YET -/* ieee80211_rx_frame_mgtmt +/* libipw_rx_frame_mgtmt * * Responsible for handling management control frames * - * Called by ieee80211_rx */ + * Called by libipw_rx */ static int -ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb, - struct ieee80211_rx_stats *rx_stats, u16 type, +libipw_rx_frame_mgmt(struct libipw_device *ieee, struct sk_buff *skb, + struct libipw_rx_stats *rx_stats, u16 type, u16 stype) { if (ieee->iw_mode == IW_MODE_MASTER) { @@ -176,7 +176,7 @@ ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb, ieee->dev->name); return 0; /* - hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr_4addr *) + hostap_update_sta_ps(ieee, (struct hostap_libipw_hdr_4addr *) skb->data);*/ } @@ -219,26 +219,27 @@ ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb, /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ -static unsigned char rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; +static unsigned char libipw_rfc1042_header[] = + { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ -static unsigned char bridge_tunnel_header[] = +static unsigned char libipw_bridge_tunnel_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; /* No encapsulation header if EtherType < 0x600 (=length) */ -/* Called by ieee80211_rx_frame_decrypt */ -static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee, +/* Called by libipw_rx_frame_decrypt */ +static int libipw_is_eapol_frame(struct libipw_device *ieee, struct sk_buff *skb) { struct net_device *dev = ieee->dev; u16 fc, ethertype; - struct ieee80211_hdr_3addr *hdr; + struct libipw_hdr_3addr *hdr; u8 *pos; if (skb->len < 24) return 0; - hdr = (struct ieee80211_hdr_3addr *)skb->data; + hdr = (struct libipw_hdr_3addr *)skb->data; fc = le16_to_cpu(hdr->frame_ctl); /* check that the frame is unicast frame to us */ @@ -266,28 +267,28 @@ static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee, return 0; } -/* Called only as a tasklet (software IRQ), by ieee80211_rx */ +/* Called only as a tasklet (software IRQ), by libipw_rx */ static int -ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb, +libipw_rx_frame_decrypt(struct libipw_device *ieee, struct sk_buff *skb, struct lib80211_crypt_data *crypt) { - struct ieee80211_hdr_3addr *hdr; + struct libipw_hdr_3addr *hdr; int res, hdrlen; if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) return 0; - hdr = (struct ieee80211_hdr_3addr *)skb->data; - hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + hdr = (struct libipw_hdr_3addr *)skb->data; + hdrlen = libipw_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); atomic_inc(&crypt->refcnt); res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); atomic_dec(&crypt->refcnt); if (res < 0) { - IEEE80211_DEBUG_DROP("decryption failed (SA=%pM) res=%d\n", + LIBIPW_DEBUG_DROP("decryption failed (SA=%pM) res=%d\n", hdr->addr2, res); if (res == -2) - IEEE80211_DEBUG_DROP("Decryption failed ICV " + LIBIPW_DEBUG_DROP("Decryption failed ICV " "mismatch (key %d)\n", skb->data[hdrlen + 3] >> 6); ieee->ieee_stats.rx_discards_undecryptable++; @@ -297,20 +298,20 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb, return res; } -/* Called only as a tasklet (software IRQ), by ieee80211_rx */ +/* Called only as a tasklet (software IRQ), by libipw_rx */ static int -ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee, +libipw_rx_frame_decrypt_msdu(struct libipw_device *ieee, struct sk_buff *skb, int keyidx, struct lib80211_crypt_data *crypt) { - struct ieee80211_hdr_3addr *hdr; + struct libipw_hdr_3addr *hdr; int res, hdrlen; if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) return 0; - hdr = (struct ieee80211_hdr_3addr *)skb->data; - hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + hdr = (struct libipw_hdr_3addr *)skb->data; + hdrlen = libipw_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); atomic_inc(&crypt->refcnt); res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); @@ -328,11 +329,11 @@ ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee, /* All received frames are sent to this function. @skb contains the frame in * IEEE 802.11 format, i.e., in the format it was sent over air. * This function is called only as a tasklet (software IRQ). */ -int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, - struct ieee80211_rx_stats *rx_stats) +int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb, + struct libipw_rx_stats *rx_stats) { struct net_device *dev = ieee->dev; - struct ieee80211_hdr_4addr *hdr; + struct libipw_hdr_4addr *hdr; size_t hdrlen; u16 fc, type, stype, sc; unsigned int frag; @@ -352,7 +353,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, int keyidx = 0; int can_be_decrypted = 0; - hdr = (struct ieee80211_hdr_4addr *)skb->data; + hdr = (struct libipw_hdr_4addr *)skb->data; if (skb->len < 10) { printk(KERN_INFO "%s: SKB length < 10\n", dev->name); goto rx_dropped; @@ -363,7 +364,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, stype = WLAN_FC_GET_STYPE(fc); sc = le16_to_cpu(hdr->seq_ctl); frag = WLAN_GET_SEQ_FRAG(sc); - hdrlen = ieee80211_get_hdrlen(fc); + hdrlen = libipw_get_hdrlen(fc); if (skb->len < hdrlen) { printk(KERN_INFO "%s: invalid SKB length %d\n", @@ -380,19 +381,19 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, struct iw_quality wstats; wstats.updated = 0; - if (rx_stats->mask & IEEE80211_STATMASK_RSSI) { + if (rx_stats->mask & LIBIPW_STATMASK_RSSI) { wstats.level = rx_stats->signal; wstats.updated |= IW_QUAL_LEVEL_UPDATED; } else wstats.updated |= IW_QUAL_LEVEL_INVALID; - if (rx_stats->mask & IEEE80211_STATMASK_NOISE) { + if (rx_stats->mask & LIBIPW_STATMASK_NOISE) { wstats.noise = rx_stats->noise; wstats.updated |= IW_QUAL_NOISE_UPDATED; } else wstats.updated |= IW_QUAL_NOISE_INVALID; - if (rx_stats->mask & IEEE80211_STATMASK_SIGNAL) { + if (rx_stats->mask & LIBIPW_STATMASK_SIGNAL) { wstats.qual = rx_stats->signal; wstats.updated |= IW_QUAL_QUAL_UPDATED; } else @@ -411,7 +412,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, if (ieee->iw_mode == IW_MODE_MONITOR) { dev->stats.rx_packets++; dev->stats.rx_bytes += skb->len; - ieee80211_monitor_rx(ieee, skb, rx_stats); + libipw_monitor_rx(ieee, skb, rx_stats); return 1; } @@ -457,7 +458,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, * frames from other than current BSS, so just drop the * frames silently instead of filling system log with * these reports. */ - IEEE80211_DEBUG_DROP("Decryption failed (not set)" + LIBIPW_DEBUG_DROP("Decryption failed (not set)" " (SA=%pM)\n", hdr->addr2); ieee->ieee_stats.rx_discards_undecryptable++; goto rx_dropped; @@ -475,7 +476,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, goto rx_dropped; } - if (ieee80211_rx_frame_mgmt(ieee, skb, rx_stats, type, stype)) + if (libipw_rx_frame_mgmt(ieee, skb, rx_stats, type, stype)) goto rx_dropped; else goto rx_exit; @@ -488,7 +489,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, ieee->prev_seq_ctl = sc; /* Data frame - extract src/dst addresses */ - if (skb->len < IEEE80211_3ADDR_LEN) + if (skb->len < LIBIPW_3ADDR_LEN) goto rx_dropped; switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { @@ -501,7 +502,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, memcpy(src, hdr->addr2, ETH_ALEN); break; case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: - if (skb->len < IEEE80211_4ADDR_LEN) + if (skb->len < LIBIPW_4ADDR_LEN) goto rx_dropped; memcpy(dst, hdr->addr3, ETH_ALEN); memcpy(src, hdr->addr4, ETH_ALEN); @@ -560,7 +561,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, stype != IEEE80211_STYPE_DATA_CFPOLL && stype != IEEE80211_STYPE_DATA_CFACKPOLL) { if (stype != IEEE80211_STYPE_NULLFUNC) - IEEE80211_DEBUG_DROP("RX: dropped data frame " + LIBIPW_DEBUG_DROP("RX: dropped data frame " "with no data (type=0x%02x, " "subtype=0x%02x, len=%d)\n", type, stype, skb->len); @@ -570,21 +571,21 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted && - (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0) + (keyidx = libipw_rx_frame_decrypt(ieee, skb, crypt)) < 0) goto rx_dropped; - hdr = (struct ieee80211_hdr_4addr *)skb->data; + hdr = (struct libipw_hdr_4addr *)skb->data; /* skb: hdr + (possibly fragmented) plaintext payload */ // PR: FIXME: hostap has additional conditions in the "if" below: // ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && if ((frag != 0) || (fc & IEEE80211_FCTL_MOREFRAGS)) { int flen; - struct sk_buff *frag_skb = ieee80211_frag_cache_get(ieee, hdr); - IEEE80211_DEBUG_FRAG("Rx Fragment received (%u)\n", frag); + struct sk_buff *frag_skb = libipw_frag_cache_get(ieee, hdr); + LIBIPW_DEBUG_FRAG("Rx Fragment received (%u)\n", frag); if (!frag_skb) { - IEEE80211_DEBUG(IEEE80211_DL_RX | IEEE80211_DL_FRAG, + LIBIPW_DEBUG(LIBIPW_DL_RX | LIBIPW_DL_FRAG, "Rx cannot get skb from fragment " "cache (morefrag=%d seq=%u frag=%u)\n", (fc & IEEE80211_FCTL_MOREFRAGS) != 0, @@ -600,7 +601,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, printk(KERN_WARNING "%s: host decrypted and " "reassembled frame did not fit skb\n", dev->name); - ieee80211_frag_cache_invalidate(ieee, hdr); + libipw_frag_cache_invalidate(ieee, hdr); goto rx_dropped; } @@ -627,24 +628,24 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, /* this was the last fragment and the frame will be * delivered, so remove skb from fragment cache */ skb = frag_skb; - hdr = (struct ieee80211_hdr_4addr *)skb->data; - ieee80211_frag_cache_invalidate(ieee, hdr); + hdr = (struct libipw_hdr_4addr *)skb->data; + libipw_frag_cache_invalidate(ieee, hdr); } /* skb: hdr + (possible reassembled) full MSDU payload; possibly still * encrypted/authenticated */ if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted && - ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt)) + libipw_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt)) goto rx_dropped; - hdr = (struct ieee80211_hdr_4addr *)skb->data; + hdr = (struct libipw_hdr_4addr *)skb->data; if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep) { if ( /*ieee->ieee802_1x && */ - ieee80211_is_eapol_frame(ieee, skb)) { + libipw_is_eapol_frame(ieee, skb)) { /* pass unencrypted EAPOL frames even if encryption is * configured */ } else { - IEEE80211_DEBUG_DROP("encryption configured, but RX " + LIBIPW_DEBUG_DROP("encryption configured, but RX " "frame not encrypted (SA=%pM)\n", hdr->addr2); goto rx_dropped; @@ -652,8 +653,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, } if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep && - !ieee80211_is_eapol_frame(ieee, skb)) { - IEEE80211_DEBUG_DROP("dropped unencrypted RX data " + !libipw_is_eapol_frame(ieee, skb)) { + LIBIPW_DEBUG_DROP("dropped unencrypted RX data " "frame from %pM (drop_unencrypted=1)\n", hdr->addr2); goto rx_dropped; @@ -736,9 +737,9 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, /* convert hdr + possible LLC headers into Ethernet header */ if (skb->len - hdrlen >= 8 && - ((memcmp(payload, rfc1042_header, SNAP_SIZE) == 0 && + ((memcmp(payload, libipw_rfc1042_header, SNAP_SIZE) == 0 && ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || - memcmp(payload, bridge_tunnel_header, SNAP_SIZE) == 0)) { + memcmp(payload, libipw_bridge_tunnel_header, SNAP_SIZE) == 0)) { /* remove RFC1042 or Bridge-Tunnel encapsulation and * replace EtherType */ skb_pull(skb, hdrlen + SNAP_SIZE); @@ -807,7 +808,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, /* netif_rx always succeeds, but it might drop * the packet. If it drops the packet, we log that * in our stats. */ - IEEE80211_DEBUG_DROP + LIBIPW_DEBUG_DROP ("RX: netif_rx dropped the packet\n"); dev->stats.rx_dropped++; } @@ -829,18 +830,18 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, return 0; } -/* Filter out unrelated packets, call ieee80211_rx[_mgt] +/* Filter out unrelated packets, call libipw_rx[_mgt] * This function takes over the skb, it should not be used again after calling * this function. */ -void ieee80211_rx_any(struct ieee80211_device *ieee, - struct sk_buff *skb, struct ieee80211_rx_stats *stats) +void libipw_rx_any(struct libipw_device *ieee, + struct sk_buff *skb, struct libipw_rx_stats *stats) { - struct ieee80211_hdr_4addr *hdr; + struct libipw_hdr_4addr *hdr; int is_packet_for_us; u16 fc; if (ieee->iw_mode == IW_MODE_MONITOR) { - if (!ieee80211_rx(ieee, skb, stats)) + if (!libipw_rx(ieee, skb, stats)) dev_kfree_skb_irq(skb); return; } @@ -848,7 +849,7 @@ void ieee80211_rx_any(struct ieee80211_device *ieee, if (skb->len < sizeof(struct ieee80211_hdr)) goto drop_free; - hdr = (struct ieee80211_hdr_4addr *)skb->data; + hdr = (struct libipw_hdr_4addr *)skb->data; fc = le16_to_cpu(hdr->frame_ctl); if ((fc & IEEE80211_FCTL_VERS) != 0) @@ -856,9 +857,9 @@ void ieee80211_rx_any(struct ieee80211_device *ieee, switch (fc & IEEE80211_FCTL_FTYPE) { case IEEE80211_FTYPE_MGMT: - if (skb->len < sizeof(struct ieee80211_hdr_3addr)) + if (skb->len < sizeof(struct libipw_hdr_3addr)) goto drop_free; - ieee80211_rx_mgt(ieee, hdr, stats); + libipw_rx_mgt(ieee, hdr, stats); dev_kfree_skb_irq(skb); return; case IEEE80211_FTYPE_DATA: @@ -910,7 +911,7 @@ void ieee80211_rx_any(struct ieee80211_device *ieee, } if (is_packet_for_us) - if (!ieee80211_rx(ieee, skb, stats)) + if (!libipw_rx(ieee, skb, stats)) dev_kfree_skb_irq(skb); return; @@ -928,7 +929,7 @@ static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; * Make ther structure we read from the beacon packet has * the right values */ -static int ieee80211_verify_qos_info(struct ieee80211_qos_information_element +static int libipw_verify_qos_info(struct libipw_qos_information_element *info_element, int sub_type) { @@ -947,12 +948,12 @@ static int ieee80211_verify_qos_info(struct ieee80211_qos_information_element /* * Parse a QoS parameter element */ -static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info - *element_param, struct ieee80211_info_element +static int libipw_read_qos_param_element(struct libipw_qos_parameter_info + *element_param, struct libipw_info_element *info_element) { int ret = 0; - u16 size = sizeof(struct ieee80211_qos_parameter_info) - 2; + u16 size = sizeof(struct libipw_qos_parameter_info) - 2; if ((info_element == NULL) || (element_param == NULL)) return -1; @@ -965,7 +966,7 @@ static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info } else ret = -1; if (ret == 0) - ret = ieee80211_verify_qos_info(&element_param->info_element, + ret = libipw_verify_qos_info(&element_param->info_element, QOS_OUI_PARAM_SUB_TYPE); return ret; } @@ -973,13 +974,13 @@ static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info /* * Parse a QoS information element */ -static int ieee80211_read_qos_info_element(struct - ieee80211_qos_information_element - *element_info, struct ieee80211_info_element +static int libipw_read_qos_info_element(struct + libipw_qos_information_element + *element_info, struct libipw_info_element *info_element) { int ret = 0; - u16 size = sizeof(struct ieee80211_qos_information_element) - 2; + u16 size = sizeof(struct libipw_qos_information_element) - 2; if (element_info == NULL) return -1; @@ -995,7 +996,7 @@ static int ieee80211_read_qos_info_element(struct ret = -1; if (ret == 0) - ret = ieee80211_verify_qos_info(element_info, + ret = libipw_verify_qos_info(element_info, QOS_OUI_INFO_SUB_TYPE); return ret; } @@ -1003,15 +1004,15 @@ static int ieee80211_read_qos_info_element(struct /* * Write QoS parameters from the ac parameters. */ -static int ieee80211_qos_convert_ac_to_parameters(struct - ieee80211_qos_parameter_info +static int libipw_qos_convert_ac_to_parameters(struct + libipw_qos_parameter_info *param_elm, struct - ieee80211_qos_parameters + libipw_qos_parameters *qos_param) { int rc = 0; int i; - struct ieee80211_qos_ac_parameter *ac_params; + struct libipw_qos_ac_parameter *ac_params; u32 txop; u8 cw_min; u8 cw_max; @@ -1042,27 +1043,27 @@ static int ieee80211_qos_convert_ac_to_parameters(struct * parameters element. check the information element length to decide * which type to read */ -static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element +static int libipw_parse_qos_info_param_IE(struct libipw_info_element *info_element, - struct ieee80211_network *network) + struct libipw_network *network) { int rc = 0; - struct ieee80211_qos_parameters *qos_param = NULL; - struct ieee80211_qos_information_element qos_info_element; + struct libipw_qos_parameters *qos_param = NULL; + struct libipw_qos_information_element qos_info_element; - rc = ieee80211_read_qos_info_element(&qos_info_element, info_element); + rc = libipw_read_qos_info_element(&qos_info_element, info_element); if (rc == 0) { network->qos_data.param_count = qos_info_element.ac_info & 0x0F; network->flags |= NETWORK_HAS_QOS_INFORMATION; } else { - struct ieee80211_qos_parameter_info param_element; + struct libipw_qos_parameter_info param_element; - rc = ieee80211_read_qos_param_element(¶m_element, + rc = libipw_read_qos_param_element(¶m_element, info_element); if (rc == 0) { qos_param = &(network->qos_data.parameters); - ieee80211_qos_convert_ac_to_parameters(¶m_element, + libipw_qos_convert_ac_to_parameters(¶m_element, qos_param); network->flags |= NETWORK_HAS_QOS_PARAMETERS; network->qos_data.param_count = @@ -1071,7 +1072,7 @@ static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element } if (rc == 0) { - IEEE80211_DEBUG_QOS("QoS is supported\n"); + LIBIPW_DEBUG_QOS("QoS is supported\n"); network->qos_data.supported = 1; } return rc; @@ -1116,9 +1117,9 @@ static const char *get_info_element_string(u16 id) } #endif -static int ieee80211_parse_info_param(struct ieee80211_info_element +static int libipw_parse_info_param(struct libipw_info_element *info_element, u16 length, - struct ieee80211_network *network) + struct libipw_network *network) { DECLARE_SSID_BUF(ssid); u8 i; @@ -1129,7 +1130,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element while (length >= sizeof(*info_element)) { if (sizeof(*info_element) + info_element->len > length) { - IEEE80211_DEBUG_MGMT("Info elem: parse failed: " + LIBIPW_DEBUG_MGMT("Info elem: parse failed: " "info_element->len + 2 > left : " "info_element->len+2=%zd left=%d, id=%d.\n", info_element->len + @@ -1151,7 +1152,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element memset(network->ssid + network->ssid_len, 0, IW_ESSID_MAX_SIZE - network->ssid_len); - IEEE80211_DEBUG_MGMT("WLAN_EID_SSID: '%s' len=%d.\n", + LIBIPW_DEBUG_MGMT("WLAN_EID_SSID: '%s' len=%d.\n", print_ssid(ssid, network->ssid, network->ssid_len), network->ssid_len); @@ -1170,17 +1171,17 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element (p - rates_str), "%02X ", network->rates[i]); #endif - if (ieee80211_is_ofdm_rate + if (libipw_is_ofdm_rate (info_element->data[i])) { network->flags |= NETWORK_HAS_OFDM; if (info_element->data[i] & - IEEE80211_BASIC_RATE_MASK) + LIBIPW_BASIC_RATE_MASK) network->flags &= ~NETWORK_HAS_CCK; } } - IEEE80211_DEBUG_MGMT("WLAN_EID_SUPP_RATES: '%s' (%d)\n", + LIBIPW_DEBUG_MGMT("WLAN_EID_SUPP_RATES: '%s' (%d)\n", rates_str, network->rates_len); break; @@ -1197,61 +1198,61 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element (p - rates_str), "%02X ", network->rates[i]); #endif - if (ieee80211_is_ofdm_rate + if (libipw_is_ofdm_rate (info_element->data[i])) { network->flags |= NETWORK_HAS_OFDM; if (info_element->data[i] & - IEEE80211_BASIC_RATE_MASK) + LIBIPW_BASIC_RATE_MASK) network->flags &= ~NETWORK_HAS_CCK; } } - IEEE80211_DEBUG_MGMT("WLAN_EID_EXT_SUPP_RATES: '%s' (%d)\n", + LIBIPW_DEBUG_MGMT("WLAN_EID_EXT_SUPP_RATES: '%s' (%d)\n", rates_str, network->rates_ex_len); break; case WLAN_EID_DS_PARAMS: - IEEE80211_DEBUG_MGMT("WLAN_EID_DS_PARAMS: %d\n", + LIBIPW_DEBUG_MGMT("WLAN_EID_DS_PARAMS: %d\n", info_element->data[0]); network->channel = info_element->data[0]; break; case WLAN_EID_FH_PARAMS: - IEEE80211_DEBUG_MGMT("WLAN_EID_FH_PARAMS: ignored\n"); + LIBIPW_DEBUG_MGMT("WLAN_EID_FH_PARAMS: ignored\n"); break; case WLAN_EID_CF_PARAMS: - IEEE80211_DEBUG_MGMT("WLAN_EID_CF_PARAMS: ignored\n"); + LIBIPW_DEBUG_MGMT("WLAN_EID_CF_PARAMS: ignored\n"); break; case WLAN_EID_TIM: network->tim.tim_count = info_element->data[0]; network->tim.tim_period = info_element->data[1]; - IEEE80211_DEBUG_MGMT("WLAN_EID_TIM: partially ignored\n"); + LIBIPW_DEBUG_MGMT("WLAN_EID_TIM: partially ignored\n"); break; case WLAN_EID_ERP_INFO: network->erp_value = info_element->data[0]; network->flags |= NETWORK_HAS_ERP_VALUE; - IEEE80211_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n", + LIBIPW_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n", network->erp_value); break; case WLAN_EID_IBSS_PARAMS: network->atim_window = info_element->data[0]; - IEEE80211_DEBUG_MGMT("WLAN_EID_IBSS_PARAMS: %d\n", + LIBIPW_DEBUG_MGMT("WLAN_EID_IBSS_PARAMS: %d\n", network->atim_window); break; case WLAN_EID_CHALLENGE: - IEEE80211_DEBUG_MGMT("WLAN_EID_CHALLENGE: ignored\n"); + LIBIPW_DEBUG_MGMT("WLAN_EID_CHALLENGE: ignored\n"); break; case WLAN_EID_GENERIC: - IEEE80211_DEBUG_MGMT("WLAN_EID_GENERIC: %d bytes\n", + LIBIPW_DEBUG_MGMT("WLAN_EID_GENERIC: %d bytes\n", info_element->len); - if (!ieee80211_parse_qos_info_param_IE(info_element, + if (!libipw_parse_qos_info_param_IE(info_element, network)) break; @@ -1268,7 +1269,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element break; case WLAN_EID_RSN: - IEEE80211_DEBUG_MGMT("WLAN_EID_RSN: %d bytes\n", + LIBIPW_DEBUG_MGMT("WLAN_EID_RSN: %d bytes\n", info_element->len); network->rsn_ie_len = min(info_element->len + 2, MAX_WPA_IE_LEN); @@ -1318,7 +1319,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element break; default: - IEEE80211_DEBUG_MGMT + LIBIPW_DEBUG_MGMT ("Unsupported info element: %s (%d)\n", get_info_element_string(info_element->id), info_element->id); @@ -1327,20 +1328,20 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element length -= sizeof(*info_element) + info_element->len; info_element = - (struct ieee80211_info_element *)&info_element-> + (struct libipw_info_element *)&info_element-> data[info_element->len]; } return 0; } -static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct ieee80211_assoc_response - *frame, struct ieee80211_rx_stats *stats) +static int libipw_handle_assoc_resp(struct libipw_device *ieee, struct libipw_assoc_response + *frame, struct libipw_rx_stats *stats) { - struct ieee80211_network network_resp = { + struct libipw_network network_resp = { .ibss_dfs = NULL, }; - struct ieee80211_network *network = &network_resp; + struct libipw_network *network = &network_resp; struct net_device *dev = ieee->dev; network->flags = 0; @@ -1361,7 +1362,7 @@ static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct iee network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ? 0x3 : 0x0; - if (stats->freq == IEEE80211_52GHZ_BAND) { + if (stats->freq == LIBIPW_52GHZ_BAND) { /* for A band (No DS info) */ network->channel = stats->received_channel; } else @@ -1370,12 +1371,12 @@ static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct iee network->wpa_ie_len = 0; network->rsn_ie_len = 0; - if (ieee80211_parse_info_param + if (libipw_parse_info_param (frame->info_element, stats->len - sizeof(*frame), network)) return 1; network->mode = 0; - if (stats->freq == IEEE80211_52GHZ_BAND) + if (stats->freq == LIBIPW_52GHZ_BAND) network->mode = IEEE_A; else { if (network->flags & NETWORK_HAS_OFDM) @@ -1394,10 +1395,10 @@ static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct iee /***************************************************/ -static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee80211_probe_response +static int libipw_network_init(struct libipw_device *ieee, struct libipw_probe_response *beacon, - struct ieee80211_network *network, - struct ieee80211_rx_stats *stats) + struct libipw_network *network, + struct libipw_rx_stats *stats) { DECLARE_SSID_BUF(ssid); @@ -1423,7 +1424,7 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021 network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ? 0x3 : 0x0; - if (stats->freq == IEEE80211_52GHZ_BAND) { + if (stats->freq == LIBIPW_52GHZ_BAND) { /* for A band (No DS info) */ network->channel = stats->received_channel; } else @@ -1432,12 +1433,12 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021 network->wpa_ie_len = 0; network->rsn_ie_len = 0; - if (ieee80211_parse_info_param + if (libipw_parse_info_param (beacon->info_element, stats->len - sizeof(*beacon), network)) return 1; network->mode = 0; - if (stats->freq == IEEE80211_52GHZ_BAND) + if (stats->freq == LIBIPW_52GHZ_BAND) network->mode = IEEE_A; else { if (network->flags & NETWORK_HAS_OFDM) @@ -1447,7 +1448,7 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021 } if (network->mode == 0) { - IEEE80211_DEBUG_SCAN("Filtered out '%s (%pM)' " + LIBIPW_DEBUG_SCAN("Filtered out '%s (%pM)' " "network.\n", print_ssid(ssid, network->ssid, network->ssid_len), @@ -1460,8 +1461,8 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021 return 0; } -static inline int is_same_network(struct ieee80211_network *src, - struct ieee80211_network *dst) +static inline int is_same_network(struct libipw_network *src, + struct libipw_network *dst) { /* A network is only a duplicate if the channel, BSSID, and ESSID * all match. We treat all with the same BSSID and channel @@ -1472,13 +1473,13 @@ static inline int is_same_network(struct ieee80211_network *src, !memcmp(src->ssid, dst->ssid, src->ssid_len)); } -static void update_network(struct ieee80211_network *dst, - struct ieee80211_network *src) +static void update_network(struct libipw_network *dst, + struct libipw_network *src) { int qos_active; u8 old_param; - ieee80211_network_reset(dst); + libipw_network_reset(dst); dst->ibss_dfs = src->ibss_dfs; /* We only update the statistics if they were created by receiving @@ -1488,9 +1489,9 @@ static void update_network(struct ieee80211_network *dst, * down the signal level of an AP. */ if (dst->channel == src->stats.received_channel) memcpy(&dst->stats, &src->stats, - sizeof(struct ieee80211_rx_stats)); + sizeof(struct libipw_rx_stats)); else - IEEE80211_DEBUG_SCAN("Network %pM info received " + LIBIPW_DEBUG_SCAN("Network %pM info received " "off channel (%d vs. %d)\n", src->bssid, dst->channel, src->stats.received_channel); @@ -1521,7 +1522,7 @@ static void update_network(struct ieee80211_network *dst, old_param = dst->qos_data.old_param_count; if (dst->flags & NETWORK_HAS_QOS_MASK) memcpy(&dst->qos_data, &src->qos_data, - sizeof(struct ieee80211_qos_data)); + sizeof(struct libipw_qos_data)); else { dst->qos_data.supported = src->qos_data.supported; dst->qos_data.param_count = src->qos_data.param_count; @@ -1529,11 +1530,11 @@ static void update_network(struct ieee80211_network *dst, if (dst->qos_data.supported == 1) { if (dst->ssid_len) - IEEE80211_DEBUG_QOS + LIBIPW_DEBUG_QOS ("QoS the network %s is QoS supported\n", dst->ssid); else - IEEE80211_DEBUG_QOS + LIBIPW_DEBUG_QOS ("QoS the network is QoS supported\n"); } dst->qos_data.active = qos_active; @@ -1547,25 +1548,25 @@ static inline int is_beacon(__le16 fc) return (WLAN_FC_GET_STYPE(le16_to_cpu(fc)) == IEEE80211_STYPE_BEACON); } -static void ieee80211_process_probe_response(struct ieee80211_device +static void libipw_process_probe_response(struct libipw_device *ieee, struct - ieee80211_probe_response - *beacon, struct ieee80211_rx_stats + libipw_probe_response + *beacon, struct libipw_rx_stats *stats) { struct net_device *dev = ieee->dev; - struct ieee80211_network network = { + struct libipw_network network = { .ibss_dfs = NULL, }; - struct ieee80211_network *target; - struct ieee80211_network *oldest = NULL; + struct libipw_network *target; + struct libipw_network *oldest = NULL; #ifdef CONFIG_LIBIPW_DEBUG - struct ieee80211_info_element *info_element = beacon->info_element; + struct libipw_info_element *info_element = beacon->info_element; #endif unsigned long flags; DECLARE_SSID_BUF(ssid); - IEEE80211_DEBUG_SCAN("'%s' (%pM" + LIBIPW_DEBUG_SCAN("'%s' (%pM" "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n", print_ssid(ssid, info_element->data, info_element->len), beacon->header.addr3, @@ -1586,8 +1587,8 @@ static void ieee80211_process_probe_response(struct ieee80211_device (beacon->capability & cpu_to_le16(1 << 0x1)) ? '1' : '0', (beacon->capability & cpu_to_le16(1 << 0x0)) ? '1' : '0'); - if (ieee80211_network_init(ieee, beacon, &network, stats)) { - IEEE80211_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n", + if (libipw_network_init(ieee, beacon, &network, stats)) { + LIBIPW_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n", print_ssid(ssid, info_element->data, info_element->len), beacon->header.addr3, @@ -1624,21 +1625,21 @@ static void ieee80211_process_probe_response(struct ieee80211_device /* If there are no more slots, expire the oldest */ list_del(&oldest->list); target = oldest; - IEEE80211_DEBUG_SCAN("Expired '%s' (%pM) from " + LIBIPW_DEBUG_SCAN("Expired '%s' (%pM) from " "network list.\n", print_ssid(ssid, target->ssid, target->ssid_len), target->bssid); - ieee80211_network_reset(target); + libipw_network_reset(target); } else { /* Otherwise just pull from the free list */ target = list_entry(ieee->network_free_list.next, - struct ieee80211_network, list); + struct libipw_network, list); list_del(ieee->network_free_list.next); } #ifdef CONFIG_LIBIPW_DEBUG - IEEE80211_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n", + LIBIPW_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n", print_ssid(ssid, network.ssid, network.ssid_len), network.bssid, @@ -1649,7 +1650,7 @@ static void ieee80211_process_probe_response(struct ieee80211_device network.ibss_dfs = NULL; list_add_tail(&target->list, &ieee->network_list); } else { - IEEE80211_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n", + LIBIPW_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n", print_ssid(ssid, target->ssid, target->ssid_len), target->bssid, @@ -1670,121 +1671,121 @@ static void ieee80211_process_probe_response(struct ieee80211_device } } -void ieee80211_rx_mgt(struct ieee80211_device *ieee, - struct ieee80211_hdr_4addr *header, - struct ieee80211_rx_stats *stats) +void libipw_rx_mgt(struct libipw_device *ieee, + struct libipw_hdr_4addr *header, + struct libipw_rx_stats *stats) { switch (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl))) { case IEEE80211_STYPE_ASSOC_RESP: - IEEE80211_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n", + LIBIPW_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); - ieee80211_handle_assoc_resp(ieee, - (struct ieee80211_assoc_response *) + libipw_handle_assoc_resp(ieee, + (struct libipw_assoc_response *) header, stats); break; case IEEE80211_STYPE_REASSOC_RESP: - IEEE80211_DEBUG_MGMT("received REASSOCIATION RESPONSE (%d)\n", + LIBIPW_DEBUG_MGMT("received REASSOCIATION RESPONSE (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); break; case IEEE80211_STYPE_PROBE_REQ: - IEEE80211_DEBUG_MGMT("received auth (%d)\n", + LIBIPW_DEBUG_MGMT("received auth (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); if (ieee->handle_probe_request != NULL) ieee->handle_probe_request(ieee->dev, (struct - ieee80211_probe_request *) + libipw_probe_request *) header, stats); break; case IEEE80211_STYPE_PROBE_RESP: - IEEE80211_DEBUG_MGMT("received PROBE RESPONSE (%d)\n", + LIBIPW_DEBUG_MGMT("received PROBE RESPONSE (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); - IEEE80211_DEBUG_SCAN("Probe response\n"); - ieee80211_process_probe_response(ieee, + LIBIPW_DEBUG_SCAN("Probe response\n"); + libipw_process_probe_response(ieee, (struct - ieee80211_probe_response *) + libipw_probe_response *) header, stats); break; case IEEE80211_STYPE_BEACON: - IEEE80211_DEBUG_MGMT("received BEACON (%d)\n", + LIBIPW_DEBUG_MGMT("received BEACON (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); - IEEE80211_DEBUG_SCAN("Beacon\n"); - ieee80211_process_probe_response(ieee, + LIBIPW_DEBUG_SCAN("Beacon\n"); + libipw_process_probe_response(ieee, (struct - ieee80211_probe_response *) + libipw_probe_response *) header, stats); break; case IEEE80211_STYPE_AUTH: - IEEE80211_DEBUG_MGMT("received auth (%d)\n", + LIBIPW_DEBUG_MGMT("received auth (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); if (ieee->handle_auth != NULL) ieee->handle_auth(ieee->dev, - (struct ieee80211_auth *)header); + (struct libipw_auth *)header); break; case IEEE80211_STYPE_DISASSOC: if (ieee->handle_disassoc != NULL) ieee->handle_disassoc(ieee->dev, - (struct ieee80211_disassoc *) + (struct libipw_disassoc *) header); break; case IEEE80211_STYPE_ACTION: - IEEE80211_DEBUG_MGMT("ACTION\n"); + LIBIPW_DEBUG_MGMT("ACTION\n"); if (ieee->handle_action) ieee->handle_action(ieee->dev, - (struct ieee80211_action *) + (struct libipw_action *) header, stats); break; case IEEE80211_STYPE_REASSOC_REQ: - IEEE80211_DEBUG_MGMT("received reassoc (%d)\n", + LIBIPW_DEBUG_MGMT("received reassoc (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); - IEEE80211_DEBUG_MGMT("%s: IEEE80211_REASSOC_REQ received\n", + LIBIPW_DEBUG_MGMT("%s: LIBIPW_REASSOC_REQ received\n", ieee->dev->name); if (ieee->handle_reassoc_request != NULL) ieee->handle_reassoc_request(ieee->dev, - (struct ieee80211_reassoc_request *) + (struct libipw_reassoc_request *) header); break; case IEEE80211_STYPE_ASSOC_REQ: - IEEE80211_DEBUG_MGMT("received assoc (%d)\n", + LIBIPW_DEBUG_MGMT("received assoc (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); - IEEE80211_DEBUG_MGMT("%s: IEEE80211_ASSOC_REQ received\n", + LIBIPW_DEBUG_MGMT("%s: LIBIPW_ASSOC_REQ received\n", ieee->dev->name); if (ieee->handle_assoc_request != NULL) ieee->handle_assoc_request(ieee->dev); break; case IEEE80211_STYPE_DEAUTH: - IEEE80211_DEBUG_MGMT("DEAUTH\n"); + LIBIPW_DEBUG_MGMT("DEAUTH\n"); if (ieee->handle_deauth != NULL) ieee->handle_deauth(ieee->dev, - (struct ieee80211_deauth *) + (struct libipw_deauth *) header); break; default: - IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n", + LIBIPW_DEBUG_MGMT("received UNKNOWN (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); - IEEE80211_DEBUG_MGMT("%s: Unknown management packet: %d\n", + LIBIPW_DEBUG_MGMT("%s: Unknown management packet: %d\n", ieee->dev->name, WLAN_FC_GET_STYPE(le16_to_cpu (header->frame_ctl))); @@ -1792,6 +1793,6 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee, } } -EXPORT_SYMBOL_GPL(ieee80211_rx_any); -EXPORT_SYMBOL(ieee80211_rx_mgt); -EXPORT_SYMBOL(ieee80211_rx); +EXPORT_SYMBOL_GPL(libipw_rx_any); +EXPORT_SYMBOL(libipw_rx_mgt); +EXPORT_SYMBOL(libipw_rx); diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c index 2e8f84fb29f..ce1855f32b7 100644 --- a/drivers/net/wireless/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/ipw2x00/libipw_tx.c @@ -41,7 +41,7 @@ #include #include -#include "ieee80211.h" +#include "libipw.h" /* @@ -126,12 +126,12 @@ payload of each frame is reduced to 492 bytes. static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; -static int ieee80211_copy_snap(u8 * data, __be16 h_proto) +static int libipw_copy_snap(u8 * data, __be16 h_proto) { - struct ieee80211_snap_hdr *snap; + struct libipw_snap_hdr *snap; u8 *oui; - snap = (struct ieee80211_snap_hdr *)data; + snap = (struct libipw_snap_hdr *)data; snap->dsap = 0xaa; snap->ssap = 0xaa; snap->ctrl = 0x03; @@ -149,7 +149,7 @@ static int ieee80211_copy_snap(u8 * data, __be16 h_proto) return SNAP_SIZE + sizeof(u16); } -static int ieee80211_encrypt_fragment(struct ieee80211_device *ieee, +static int libipw_encrypt_fragment(struct libipw_device *ieee, struct sk_buff *frag, int hdr_len) { struct lib80211_crypt_data *crypt = @@ -177,7 +177,7 @@ static int ieee80211_encrypt_fragment(struct ieee80211_device *ieee, return 0; } -void ieee80211_txb_free(struct ieee80211_txb *txb) +void libipw_txb_free(struct libipw_txb *txb) { int i; if (unlikely(!txb)) @@ -188,17 +188,17 @@ void ieee80211_txb_free(struct ieee80211_txb *txb) kfree(txb); } -static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, +static struct libipw_txb *libipw_alloc_txb(int nr_frags, int txb_size, int headroom, gfp_t gfp_mask) { - struct ieee80211_txb *txb; + struct libipw_txb *txb; int i; - txb = kmalloc(sizeof(struct ieee80211_txb) + (sizeof(u8 *) * nr_frags), + txb = kmalloc(sizeof(struct libipw_txb) + (sizeof(u8 *) * nr_frags), gfp_mask); if (!txb) return NULL; - memset(txb, 0, sizeof(struct ieee80211_txb)); + memset(txb, 0, sizeof(struct libipw_txb)); txb->nr_frags = nr_frags; txb->frag_size = txb_size; @@ -220,7 +220,7 @@ static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, return txb; } -static int ieee80211_classify(struct sk_buff *skb) +static int libipw_classify(struct sk_buff *skb) { struct ethhdr *eth; struct iphdr *ip; @@ -252,11 +252,11 @@ static int ieee80211_classify(struct sk_buff *skb) /* Incoming skb is converted to a txb which consists of * a block of 802.11 fragment packets (stored as skbs) */ -int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) +int libipw_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ieee80211_device *ieee = netdev_priv(dev); - struct ieee80211_txb *txb = NULL; - struct ieee80211_hdr_3addrqos *frag_hdr; + struct libipw_device *ieee = netdev_priv(dev); + struct libipw_txb *txb = NULL; + struct libipw_hdr_3addrqos *frag_hdr; int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size, rts_required; unsigned long flags; @@ -264,7 +264,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) __be16 ether_type; int bytes, fc, hdr_len; struct sk_buff *skb_frag; - struct ieee80211_hdr_3addrqos header = {/* Ensure zero initialized */ + struct libipw_hdr_3addrqos header = {/* Ensure zero initialized */ .duration_id = 0, .seq_ctl = 0, .qos_ctl = 0 @@ -331,14 +331,14 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) memcpy(header.addr2, src, ETH_ALEN); memcpy(header.addr3, ieee->bssid, ETH_ALEN); } - hdr_len = IEEE80211_3ADDR_LEN; + hdr_len = LIBIPW_3ADDR_LEN; if (ieee->is_qos_active && ieee->is_qos_active(dev, skb)) { fc |= IEEE80211_STYPE_QOS_DATA; hdr_len += 2; - skb->priority = ieee80211_classify(skb); - header.qos_ctl |= cpu_to_le16(skb->priority & IEEE80211_QCTL_TID); + skb->priority = libipw_classify(skb); + header.qos_ctl |= cpu_to_le16(skb->priority & LIBIPW_QCTL_TID); } header.frame_ctl = cpu_to_le16(fc); @@ -362,12 +362,12 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len); memcpy(skb_put(skb_new, hdr_len), &header, hdr_len); snapped = 1; - ieee80211_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)), + libipw_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)), ether_type); skb_copy_from_linear_data(skb, skb_put(skb_new, skb->len), skb->len); res = crypt->ops->encrypt_msdu(skb_new, hdr_len, crypt->priv); if (res < 0) { - IEEE80211_ERROR("msdu encryption failed\n"); + LIBIPW_ERROR("msdu encryption failed\n"); dev_kfree_skb_any(skb_new); goto failed; } @@ -393,8 +393,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) * for it when determining the amount of payload space. */ bytes_per_frag = frag_size - hdr_len; if (ieee->config & - (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) - bytes_per_frag -= IEEE80211_FCS_LEN; + (CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS)) + bytes_per_frag -= LIBIPW_FCS_LEN; /* Each fragment may need to have room for encryptiong * pre/postfix */ @@ -417,14 +417,14 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) } rts_required = (frag_size > ieee->rts - && ieee->config & CFG_IEEE80211_RTS); + && ieee->config & CFG_LIBIPW_RTS); if (rts_required) nr_frags++; /* When we allocate the TXB we allocate enough space for the reserve * and full fragment bytes (bytes_per_frag doesn't include prefix, * postfix, header, FCS, etc.) */ - txb = ieee80211_alloc_txb(nr_frags, frag_size, + txb = libipw_alloc_txb(nr_frags, frag_size, ieee->tx_headroom, GFP_ATOMIC); if (unlikely(!txb)) { printk(KERN_WARNING "%s: Could not allocate TXB\n", @@ -441,7 +441,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) if (rts_required) { skb_frag = txb->fragments[0]; frag_hdr = - (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len); + (struct libipw_hdr_3addrqos *)skb_put(skb_frag, hdr_len); /* * Set header frame_ctl to the RTS. @@ -456,7 +456,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) header.frame_ctl = cpu_to_le16(fc); if (ieee->config & - (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) + (CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS)) skb_put(skb_frag, 4); txb->rts_included = 1; @@ -472,7 +472,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) crypt->ops->extra_mpdu_prefix_len); frag_hdr = - (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len); + (struct libipw_hdr_3addrqos *)skb_put(skb_frag, hdr_len); memcpy(frag_hdr, &header, hdr_len); /* If this is not the last fragment, then add the MOREFRAGS @@ -487,7 +487,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) } if (i == 0 && !snapped) { - ieee80211_copy_snap(skb_put + libipw_copy_snap(skb_put (skb_frag, SNAP_SIZE + sizeof(u16)), ether_type); bytes -= SNAP_SIZE + sizeof(u16); @@ -501,7 +501,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) /* Encryption routine will move the header forward in order * to insert the IV between the header and the payload */ if (host_encrypt) - ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); + libipw_encrypt_fragment(ieee, skb_frag, hdr_len); else if (host_build_iv) { atomic_inc(&crypt->refcnt); if (crypt->ops->build_iv) @@ -513,7 +513,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) } if (ieee->config & - (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) + (CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS)) skb_put(skb_frag, 4); } @@ -530,7 +530,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } - ieee80211_txb_free(txb); + libipw_txb_free(txb); } return NETDEV_TX_OK; @@ -541,6 +541,6 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_errors++; return NETDEV_TX_BUSY; } -EXPORT_SYMBOL(ieee80211_xmit); +EXPORT_SYMBOL(libipw_xmit); -EXPORT_SYMBOL(ieee80211_txb_free); +EXPORT_SYMBOL(libipw_txb_free); diff --git a/drivers/net/wireless/ipw2x00/libipw_wx.c b/drivers/net/wireless/ipw2x00/libipw_wx.c index 3c0812db030..f79ce57ebe6 100644 --- a/drivers/net/wireless/ipw2x00/libipw_wx.c +++ b/drivers/net/wireless/ipw2x00/libipw_wx.c @@ -37,9 +37,9 @@ #include #include -#include "ieee80211.h" +#include "libipw.h" -static const char *ieee80211_modes[] = { +static const char *libipw_modes[] = { "?", "a", "b", "ab", "g", "ag", "bg", "abg" }; @@ -54,9 +54,9 @@ static inline unsigned int elapsed_jiffies_msecs(unsigned long start) } #define MAX_CUSTOM_LEN 64 -static char *ieee80211_translate_scan(struct ieee80211_device *ieee, +static char *libipw_translate_scan(struct libipw_device *ieee, char *start, char *stop, - struct ieee80211_network *network, + struct libipw_network *network, struct iw_request_info *info) { char custom[MAX_CUSTOM_LEN]; @@ -84,7 +84,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, /* Add the protocol name */ iwe.cmd = SIOCGIWNAME; snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", - ieee80211_modes[network->mode]); + libipw_modes[network->mode]); start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN); /* Add mode */ @@ -102,7 +102,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, /* Add channel and frequency */ /* Note : userspace automatically computes channel using iwrange */ iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel); + iwe.u.freq.m = libipw_channel_to_freq(ieee, network->channel); iwe.u.freq.e = 6; iwe.u.freq.i = 0; start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); @@ -155,7 +155,7 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_UPDATED; - if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) { + if (!(network->stats.mask & LIBIPW_STATMASK_RSSI)) { iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; iwe.u.qual.qual = 0; @@ -180,14 +180,14 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, iwe.u.qual.qual = 0; } - if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) { + if (!(network->stats.mask & LIBIPW_STATMASK_NOISE)) { iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID; iwe.u.qual.noise = 0; } else { iwe.u.qual.noise = network->stats.noise; } - if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) { + if (!(network->stats.mask & LIBIPW_STATMASK_SIGNAL)) { iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID; iwe.u.qual.level = 0; } else { @@ -237,14 +237,14 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, p = custom; p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: "); - if (ieee80211_get_channel_flags(ieee, network->channel) & - IEEE80211_CH_INVALID) { + if (libipw_get_channel_flags(ieee, network->channel) & + LIBIPW_CH_INVALID) { iwe.cmd = IWEVCUSTOM; p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID "); } - if (ieee80211_get_channel_flags(ieee, network->channel) & - IEEE80211_CH_RADAR_DETECT) { + if (libipw_get_channel_flags(ieee, network->channel) & + LIBIPW_CH_RADAR_DETECT) { iwe.cmd = IWEVCUSTOM; p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS "); } @@ -259,11 +259,11 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, #define SCAN_ITEM_SIZE 128 -int ieee80211_wx_get_scan(struct ieee80211_device *ieee, +int libipw_wx_get_scan(struct libipw_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ieee80211_network *network; + struct libipw_network *network; unsigned long flags; int err = 0; @@ -272,7 +272,7 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, int i = 0; DECLARE_SSID_BUF(ssid); - IEEE80211_DEBUG_WX("Getting scan\n"); + LIBIPW_DEBUG_WX("Getting scan\n"); spin_lock_irqsave(&ieee->lock, flags); @@ -285,10 +285,10 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, if (ieee->scan_age == 0 || time_after(network->last_scanned + ieee->scan_age, jiffies)) - ev = ieee80211_translate_scan(ieee, ev, stop, network, + ev = libipw_translate_scan(ieee, ev, stop, network, info); else { - IEEE80211_DEBUG_SCAN("Not showing network '%s (" + LIBIPW_DEBUG_SCAN("Not showing network '%s (" "%pM)' due to age (%ums).\n", print_ssid(ssid, network->ssid, network->ssid_len), @@ -303,18 +303,18 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, wrqu->data.length = ev - extra; wrqu->data.flags = 0; - IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i); + LIBIPW_DEBUG_WX("exit: %d networks returned.\n", i); return err; } -int ieee80211_wx_set_encode(struct ieee80211_device *ieee, +int libipw_wx_set_encode(struct libipw_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *keybuf) { struct iw_point *erq = &(wrqu->encoding); struct net_device *dev = ieee->dev; - struct ieee80211_security sec = { + struct libipw_security sec = { .flags = 0 }; int i, key, key_provided, len; @@ -322,7 +322,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv; DECLARE_SSID_BUF(ssid); - IEEE80211_DEBUG_WX("SET_ENCODE\n"); + LIBIPW_DEBUG_WX("SET_ENCODE\n"); key = erq->flags & IW_ENCODE_INDEX; if (key) { @@ -335,18 +335,18 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, key = ieee->crypt_info.tx_keyidx; } - IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ? + LIBIPW_DEBUG_WX("Key: %d [%s]\n", key, key_provided ? "provided" : "default"); crypt = &ieee->crypt_info.crypt[key]; if (erq->flags & IW_ENCODE_DISABLED) { if (key_provided && *crypt) { - IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n", + LIBIPW_DEBUG_WX("Disabling encryption on key %d.\n", key); lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); } else - IEEE80211_DEBUG_WX("Disabling encryption.\n"); + LIBIPW_DEBUG_WX("Disabling encryption.\n"); /* Check all the keys to see if any are still configured, * and if no key index was provided, de-init them all */ @@ -410,7 +410,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, /* If a new key was provided, set it up */ if (erq->length > 0) { -#ifdef CONFIG_IEEE80211_DEBUG +#ifdef CONFIG_LIBIPW_DEBUG DECLARE_SSID_BUF(ssid); #endif @@ -419,7 +419,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, if (len > erq->length) memset(sec.keys[key] + erq->length, 0, len - erq->length); - IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n", + LIBIPW_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n", key, print_ssid(ssid, sec.keys[key], len), erq->length, len); sec.key_sizes[key] = len; @@ -438,7 +438,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, NULL, (*crypt)->priv); if (len == 0) { /* Set a default key of all 0 */ - IEEE80211_DEBUG_WX("Setting key %d to all " + LIBIPW_DEBUG_WX("Setting key %d to all " "zero.\n", key); memset(sec.keys[key], 0, 13); (*crypt)->ops->set_key(sec.keys[key], 13, NULL, @@ -449,7 +449,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, } /* No key data - just set the default TX key index */ if (key_provided) { - IEEE80211_DEBUG_WX("Setting key %d to default Tx " + LIBIPW_DEBUG_WX("Setting key %d to default Tx " "key.\n", key); ieee->crypt_info.tx_keyidx = key; sec.active_key = key; @@ -461,7 +461,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; sec.flags |= SEC_AUTH_MODE; - IEEE80211_DEBUG_WX("Auth: %s\n", + LIBIPW_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ? "OPEN" : "SHARED KEY"); } @@ -490,16 +490,16 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, return 0; } -int ieee80211_wx_get_encode(struct ieee80211_device *ieee, +int libipw_wx_get_encode(struct libipw_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *keybuf) { struct iw_point *erq = &(wrqu->encoding); int len, key; struct lib80211_crypt_data *crypt; - struct ieee80211_security *sec = &ieee->sec; + struct libipw_security *sec = &ieee->sec; - IEEE80211_DEBUG_WX("GET_ENCODE\n"); + LIBIPW_DEBUG_WX("GET_ENCODE\n"); key = erq->flags & IW_ENCODE_INDEX; if (key) { @@ -532,7 +532,7 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee, return 0; } -int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, +int libipw_wx_set_encodeext(struct libipw_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { @@ -545,7 +545,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, struct lib80211_crypto_ops *ops; struct lib80211_crypt_data **crypt; - struct ieee80211_security sec = { + struct libipw_security sec = { .flags = 0, }; @@ -611,7 +611,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, module = "lib80211_crypt_ccmp"; break; default: - IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", + LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n", dev->name, ext->alg); ret = -EINVAL; goto done; @@ -623,7 +623,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, ops = lib80211_get_crypto_ops(alg); } if (ops == NULL) { - IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", + LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n", dev->name, ext->alg); ret = -EINVAL; goto done; @@ -653,7 +653,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, if (ext->key_len > 0 && (*crypt)->ops->set_key && (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, (*crypt)->priv) < 0) { - IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name); + LIBIPW_DEBUG_WX("%s: key setting failed\n", dev->name); ret = -EINVAL; goto done; } @@ -700,20 +700,20 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, if (ieee->reset_on_keychange && ieee->iw_mode != IW_MODE_INFRA && ieee->reset_port && ieee->reset_port(dev)) { - IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name); + LIBIPW_DEBUG_WX("%s: reset_port failed\n", dev->name); return -EINVAL; } return ret; } -int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, +int libipw_wx_get_encodeext(struct libipw_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct iw_point *encoding = &wrqu->encoding; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - struct ieee80211_security *sec = &ieee->sec; + struct libipw_security *sec = &ieee->sec; int idx, max_key_len; max_key_len = encoding->length - sizeof(*ext); @@ -763,9 +763,9 @@ int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, return 0; } -EXPORT_SYMBOL(ieee80211_wx_set_encodeext); -EXPORT_SYMBOL(ieee80211_wx_get_encodeext); +EXPORT_SYMBOL(libipw_wx_set_encodeext); +EXPORT_SYMBOL(libipw_wx_get_encodeext); -EXPORT_SYMBOL(ieee80211_wx_get_scan); -EXPORT_SYMBOL(ieee80211_wx_set_encode); -EXPORT_SYMBOL(ieee80211_wx_get_encode); +EXPORT_SYMBOL(libipw_wx_get_scan); +EXPORT_SYMBOL(libipw_wx_set_encode); +EXPORT_SYMBOL(libipw_wx_get_encode); -- cgit v1.2.3-18-g5258 From 3d832611d794b3d312d26a4b251ac5285206f90d Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 21 Aug 2009 12:00:28 +0530 Subject: ath9k: Fix chainmask selection during scanning The TX/RX chainmasks were set to 1x1 during scanning. Configure them properly with the values retrieved from the EEPROM. Also, this requires scan_start/scan_end callbacks to be locked with sc->mutex. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9b9b4e8ee1e..eb8d673cde5 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -439,7 +439,7 @@ static void ath_start_ani(struct ath_softc *sc) */ void ath_update_chainmask(struct ath_softc *sc, int is_ht) { - if (is_ht || + if ((sc->sc_flags & SC_OP_SCANNING) || is_ht || (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)) { sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask; sc->rx_chainmask = sc->sc_ah->caps.rx_chainmask; @@ -2713,6 +2713,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw) struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + mutex_lock(&sc->mutex); if (ath9k_wiphy_scanning(sc)) { printk(KERN_DEBUG "ath9k: Two wiphys trying to scan at the " "same time\n"); @@ -2720,6 +2721,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw) * Do not allow the concurrent scanning state for now. This * could be improved with scanning control moved into ath9k. */ + mutex_unlock(&sc->mutex); return; } @@ -2729,6 +2731,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw) spin_lock_bh(&sc->ani_lock); sc->sc_flags |= SC_OP_SCANNING; spin_unlock_bh(&sc->ani_lock); + mutex_unlock(&sc->mutex); } static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) @@ -2736,11 +2739,13 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + mutex_lock(&sc->mutex); spin_lock_bh(&sc->ani_lock); aphy->state = ATH_WIPHY_ACTIVE; sc->sc_flags &= ~SC_OP_SCANNING; sc->sc_flags |= SC_OP_FULL_RESET; spin_unlock_bh(&sc->ani_lock); + mutex_unlock(&sc->mutex); } struct ieee80211_ops ath9k_ops = { -- cgit v1.2.3-18-g5258 From 1e3d31c589a6bcb05cd7fccccf9657c27b0e3dd1 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Sun, 2 Aug 2009 09:44:12 +0200 Subject: libertas: Read buffer overflow Check whether index is within bounds before testing the element. (also includes "Libertas: Association request to the driver failed" The size of the tmp buffer was too small, causing a regression rates->rates has an arraysize of 1, so a memcpy with MAX_RATES (14) was already causing reads out of bounds. In get_common_rates() the memset/memcpy can be moved upwards. -- JWL) Signed-off-by: Roel Kluin Tested-by: Daniel Mack Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 81f86ef2699..a9440a96b2e 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -44,12 +44,11 @@ static int get_common_rates(struct lbs_private *priv, { u8 *card_rates = lbs_bg_rates; size_t num_card_rates = sizeof(lbs_bg_rates); - int ret = 0, i, j; + int i, j; u8 *tmp; size_t tmp_size = 0; - tmp = kzalloc((ARRAY_SIZE(lbs_bg_rates) - 1) * (*rates_size - 1), - GFP_KERNEL); + tmp = kzalloc(MAX_RATES * ARRAY_SIZE(lbs_bg_rates), GFP_KERNEL); if (!tmp) return -1; @@ -66,24 +65,24 @@ static int get_common_rates(struct lbs_private *priv, lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); + memset(rates, 0, *rates_size); + *rates_size = min_t(u16, tmp_size, *rates_size); + memcpy(rates, tmp, *rates_size); + if (!priv->enablehwauto) { for (i = 0; i < tmp_size; i++) { if (tmp[i] == priv->cur_rate) - goto done; + break; + } + if (i == tmp_size) { + lbs_pr_alert("Previously set fixed data rate %#x isn't " + "compatible with the network.\n", + priv->cur_rate); + return -1; } - lbs_pr_alert("Previously set fixed data rate %#x isn't " - "compatible with the network.\n", priv->cur_rate); - ret = -1; - goto done; } - ret = 0; - -done: - memset(rates, 0, *rates_size); - *rates_size = min_t(int, tmp_size, *rates_size); - memcpy(rates, tmp, *rates_size); kfree(tmp); - return ret; + return 0; } @@ -325,8 +324,8 @@ static int lbs_associate(struct lbs_private *priv, rates = (struct mrvl_ie_rates_param_set *) pos; rates->header.type = cpu_to_le16(TLV_TYPE_RATES); - memcpy(&rates->rates, &bss->rates, MAX_RATES); tmplen = MAX_RATES; + memcpy(&rates->rates, &bss->rates, tmplen); if (get_common_rates(priv, rates->rates, &tmplen)) { ret = -1; goto done; -- cgit v1.2.3-18-g5258 From ca4fe30097d700c595c13362200083650759e104 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 21 Aug 2009 09:35:20 -0500 Subject: libertas: clean up and clarify get_common_rates Clarify what the heck the function is doing with better variable names and less indirection and better comments. Also ensure callers use the proper minimum size, even though all rates arrays should be size MAX_RATES anyway. Reverts part of Andrey's dynamic alloc patch since we don't really need it. Also leaves the passed-in rates array alone on errors. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 58 ++++++++++++++++------------------- 1 file changed, 27 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index a9440a96b2e..dd8732611ba 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -34,7 +34,8 @@ static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = * * @param priv A pointer to struct lbs_private structure * @param rates the buffer which keeps input and output - * @param rates_size the size of rate1 buffer; new size of buffer on return + * @param rates_size the size of rates buffer; new size of buffer on return, + * which will be less than or equal to original rates_size * * @return 0 on success, or -1 on error */ @@ -42,46 +43,41 @@ static int get_common_rates(struct lbs_private *priv, u8 *rates, u16 *rates_size) { - u8 *card_rates = lbs_bg_rates; - size_t num_card_rates = sizeof(lbs_bg_rates); int i, j; - u8 *tmp; - size_t tmp_size = 0; + u8 intersection[MAX_RATES]; + u16 intersection_size; + u16 num_rates = 0; - tmp = kzalloc(MAX_RATES * ARRAY_SIZE(lbs_bg_rates), GFP_KERNEL); - if (!tmp) - return -1; + intersection_size = min_t(u16, *rates_size, ARRAY_SIZE(intersection)); - /* For each rate in card_rates that exists in rate1, copy to tmp */ - for (i = 0; card_rates[i] && (i < num_card_rates); i++) { - for (j = 0; rates[j] && (j < *rates_size); j++) { - if (rates[j] == card_rates[i]) - tmp[tmp_size++] = card_rates[i]; + /* Allow each rate from 'rates' that is supported by the hardware */ + for (i = 0; i < ARRAY_SIZE(lbs_bg_rates) && lbs_bg_rates[i]; i++) { + for (j = 0; j < intersection_size && rates[j]; j++) { + if (rates[j] == lbs_bg_rates[i]) + intersection[num_rates++] = rates[j]; } } lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size); - lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates); - lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); + lbs_deb_hex(LBS_DEB_JOIN, "card rates ", lbs_bg_rates, + ARRAY_SIZE(lbs_bg_rates)); + lbs_deb_hex(LBS_DEB_JOIN, "common rates", intersection, num_rates); lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); - memset(rates, 0, *rates_size); - *rates_size = min_t(u16, tmp_size, *rates_size); - memcpy(rates, tmp, *rates_size); - if (!priv->enablehwauto) { - for (i = 0; i < tmp_size; i++) { - if (tmp[i] == priv->cur_rate) - break; - } - if (i == tmp_size) { - lbs_pr_alert("Previously set fixed data rate %#x isn't " - "compatible with the network.\n", - priv->cur_rate); - return -1; + for (i = 0; i < num_rates; i++) { + if (intersection[i] == priv->cur_rate) + goto done; } + lbs_pr_alert("Previously set fixed data rate %#x isn't " + "compatible with the network.\n", priv->cur_rate); + return -1; } - kfree(tmp); + +done: + memset(rates, 0, *rates_size); + *rates_size = num_rates; + memcpy(rates, intersection, num_rates); return 0; } @@ -324,7 +320,7 @@ static int lbs_associate(struct lbs_private *priv, rates = (struct mrvl_ie_rates_param_set *) pos; rates->header.type = cpu_to_le16(TLV_TYPE_RATES); - tmplen = MAX_RATES; + tmplen = min_t(u16, ARRAY_SIZE(bss->rates), MAX_RATES); memcpy(&rates->rates, &bss->rates, tmplen); if (get_common_rates(priv, rates->rates, &tmplen)) { ret = -1; @@ -599,7 +595,7 @@ static int lbs_adhoc_join(struct lbs_private *priv, /* Copy Data rates from the rates recorded in scan response */ memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates)); - ratesize = min_t(u16, sizeof(cmd.bss.rates), MAX_RATES); + ratesize = min_t(u16, ARRAY_SIZE(cmd.bss.rates), ARRAY_SIZE (bss->rates)); memcpy(cmd.bss.rates, bss->rates, ratesize); if (get_common_rates(priv, cmd.bss.rates, &ratesize)) { lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n"); -- cgit v1.2.3-18-g5258 From 9d45368a3825349d8ba686bc36df589d16577dd4 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 21 Aug 2009 04:08:16 +0200 Subject: libertas: Add support for Marvell Libertas CF8305 The CF8305 is a very old silicon running firmware version 3.0 . This card also needs some special treatment as it's so old it can't do unaligned register access. But since that happens only at one place, there were no changes made to the register access functions, but instead that particular place was fixed. Also, this card uses only one-stage firmware which is loaded the same way as helper firmware. The second-stage firmware isn't loaded on this card and doesn't therefore have to be supplied. Signed-off-by: Marek Vasut Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_cs.c | 39 +++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index f658fd6a2c0..62381768f2d 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -59,6 +59,7 @@ struct if_cs_card { struct pcmcia_device *p_dev; struct lbs_private *priv; void __iomem *iobase; + bool align_regs; }; @@ -274,16 +275,25 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r #define IF_CS_PRODUCT_ID 0x0000001C #define IF_CS_CF8385_B1_REV 0x12 #define IF_CS_CF8381_B3_REV 0x04 +#define IF_CS_CF8305_B1_REV 0x03 /* * Used to detect other cards than CF8385 since their revisions of silicon * doesn't match those from CF8385, eg. CF8381 B3 works with this driver. */ +#define CF8305_MANFID 0x02db +#define CF8305_CARDID 0x8103 #define CF8381_MANFID 0x02db #define CF8381_CARDID 0x6064 #define CF8385_MANFID 0x02df #define CF8385_CARDID 0x8103 +static inline int if_cs_hw_is_cf8305(struct pcmcia_device *p_dev) +{ + return (p_dev->manf_id == CF8305_MANFID && + p_dev->card_id == CF8305_CARDID); +} + static inline int if_cs_hw_is_cf8381(struct pcmcia_device *p_dev) { return (p_dev->manf_id == CF8381_MANFID && @@ -556,7 +566,15 @@ static int if_cs_prog_helper(struct if_cs_card *card) lbs_deb_enter(LBS_DEB_CS); - scratch = if_cs_read8(card, IF_CS_SCRATCH); + /* + * This is the only place where an unaligned register access happens on + * the CF8305 card, therefore for the sake of speed of the driver, we do + * the alignment correction here. + */ + if (card->align_regs) + scratch = if_cs_read16(card, IF_CS_SCRATCH) >> 8; + else + scratch = if_cs_read8(card, IF_CS_SCRATCH); /* "If the value is 0x5a, the firmware is already * downloaded successfully" @@ -880,8 +898,24 @@ static int if_cs_probe(struct pcmcia_device *p_dev) p_dev->irq.AssignedIRQ, p_dev->io.BasePort1, p_dev->io.BasePort1 + p_dev->io.NumPorts1 - 1); + /* + * Most of the libertas cards can do unaligned register access, but some + * weird ones can not. That's especially true for the CF8305 card. + */ + card->align_regs = 0; + /* Check if we have a current silicon */ prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID); + if (if_cs_hw_is_cf8305(p_dev)) { + card->align_regs = 1; + if (prod_id < IF_CS_CF8305_B1_REV) { + lbs_pr_err("old chips like 8305 rev B3 " + "aren't supported\n"); + ret = -ENODEV; + goto out2; + } + } + if (if_cs_hw_is_cf8381(p_dev) && prod_id < IF_CS_CF8381_B3_REV) { lbs_pr_err("old chips like 8381 rev B3 aren't supported\n"); ret = -ENODEV; @@ -896,7 +930,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) /* Load the firmware early, before calling into libertas.ko */ ret = if_cs_prog_helper(card); - if (ret == 0) + if (ret == 0 && !if_cs_hw_is_cf8305(p_dev)) ret = if_cs_prog_real(card); if (ret) goto out2; @@ -976,6 +1010,7 @@ static void if_cs_detach(struct pcmcia_device *p_dev) /********************************************************************/ static struct pcmcia_device_id if_cs_ids[] = { + PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID), PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID), PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID), PCMCIA_DEVICE_NULL, -- cgit v1.2.3-18-g5258 From aa065263ecb0b0df096ff4b02b2fb88060dd2d45 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Fri, 21 Aug 2009 20:44:09 +0200 Subject: iwlwifi: Make injection of non-broadcast frames work again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 1ccb84d87d04df3c76cd4352fe69786d8c7cf016 by Wey-Yi Guy ("iwlwifi: clean up unused NL80211_IFTYPE_MONITOR for Monitor mode") broke injection of non-broadcast frames to unassociated stations (causing a SYSASSERT for all such injected frames), due to injected frames no longer automatically getting a broadcast station ID assigned. This patch restores the old behavior, fixing the aforementioned regression. Also, consistently check for IEEE80211_TX_CTL_INJECTED instead of iwl_is_monitor_mode in the TX path, as TX_CTL_INJECTED specifically means that a given packet is coming from a monitor interface, while iwl_is_monitor_mode only shows whether a monitor interface exists on the device. Signed-off-by: Gábor Stefanik Acked-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 10 ++++++---- drivers/net/wireless/iwlwifi/iwl3945-base.c | 9 ++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 7686fc72eb8..7bc9c0039f7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -718,10 +718,9 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "Sending REASSOC frame\n"); #endif - /* drop all data frame if we are not associated */ + /* drop all non-injected data frame if we are not associated */ if (ieee80211_is_data(fc) && - (!iwl_is_monitor_mode(priv) || - !(info->flags & IEEE80211_TX_CTL_INJECTED)) && /* packet injection */ + !(info->flags & IEEE80211_TX_CTL_INJECTED) && (!iwl_is_associated(priv) || ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id) || !priv->assoc_station_added)) { @@ -732,7 +731,10 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr_len = ieee80211_hdrlen(fc); /* Find (or create) index into station table for destination station */ - sta_id = iwl_get_sta_id(priv, hdr); + if (info->flags & IEEE80211_TX_CTL_INJECTED) + sta_id = priv->hw_params.bcast_sta_id; + else + sta_id = iwl_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", hdr->addr1); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index f339c5bd1fd..34790413ead 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -518,9 +518,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "Sending REASSOC frame\n"); #endif - /* drop all data frame if we are not associated */ + /* drop all non-injected data frame if we are not associated */ if (ieee80211_is_data(fc) && - (!iwl_is_monitor_mode(priv)) && /* packet injection */ + !(info->flags & IEEE80211_TX_CTL_INJECTED) && (!iwl_is_associated(priv) || ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id))) { IWL_DEBUG_DROP(priv, "Dropping - !iwl_is_associated\n"); @@ -532,7 +532,10 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr_len = ieee80211_hdrlen(fc); /* Find (or create) index into station table for destination station */ - sta_id = iwl_get_sta_id(priv, hdr); + if (info->flags & IEEE80211_TX_CTL_INJECTED) + sta_id = priv->hw_params.bcast_sta_id; + else + sta_id = iwl_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", hdr->addr1); -- cgit v1.2.3-18-g5258 From 02eec9c5a1d3e9a2bed5e6221970febef38fc080 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 21 Aug 2009 13:34:14 -0700 Subject: iwlwifi: set default tx power user limit to minimal Set the tx_power_user_lmt to the lowest power level this value will get overwritten by channel's max power avg from eeprom Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index f1f6dabd8fb..43781dc9adf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1671,7 +1671,10 @@ int iwl_init_drv(struct iwl_priv *priv) priv->qos_data.qos_cap.val = 0; priv->rates_mask = IWL_RATES_MASK; - priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MAX; + /* Set the tx_power_user_lmt to the lowest power level + * this value will get overwritten by channel max power avg + * from eeprom */ + priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MIN; ret = iwl_init_channel_map(priv); if (ret) { -- cgit v1.2.3-18-g5258 From 08f2d58d0e573d13a8eb0afbb6f3122da37b9ce3 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 21 Aug 2009 13:34:15 -0700 Subject: iwlwifi: do not allow set tx power over channel power limit When setting tx power in sysfs, check against max channel tx power limit instead of IWL_TX_POWER_TARGET_POWER_MAX. Different devices have different max tx power limit; using IWL_TX_POWER_TARGET_POWER_MAX can excess the limitaion and give wrong information. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 43781dc9adf..faafcaeae0a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1708,10 +1708,10 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) return -EINVAL; } - if (tx_power > IWL_TX_POWER_TARGET_POWER_MAX) { - IWL_WARN(priv, "Requested user TXPOWER %d above upper limit %d.\n", - tx_power, - IWL_TX_POWER_TARGET_POWER_MAX); + if (tx_power > priv->tx_power_channel_lmt) { + IWL_WARN(priv, + "Requested user TXPOWER %d above upper limit %d.\n", + tx_power, priv->tx_power_channel_lmt); return -EINVAL; } -- cgit v1.2.3-18-g5258 From dc1b09733215e19f6a0f676be2744fe2f5471d85 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 21 Aug 2009 13:34:16 -0700 Subject: iwlwifi: name changes from "tx_power_channel_lmt" to "tx_power_device_lmt" Changing the name from "tx_power_channel_lmt" to "tx_power_device_lmt"; to give idea that scope of limit is for overall device, not any individual channels Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 8 ++++---- drivers/net/wireless/iwlwifi/iwl-dev.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index faafcaeae0a..82dadd043b8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -543,8 +543,8 @@ int iwlcore_init_geos(struct iwl_priv *priv) geo_ch->flags |= ch->ht40_extension_channel; - if (ch->max_power_avg > priv->tx_power_channel_lmt) - priv->tx_power_channel_lmt = ch->max_power_avg; + if (ch->max_power_avg > priv->tx_power_device_lmt) + priv->tx_power_device_lmt = ch->max_power_avg; } else { geo_ch->flags |= IEEE80211_CHAN_DISABLED; } @@ -1708,10 +1708,10 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) return -EINVAL; } - if (tx_power > priv->tx_power_channel_lmt) { + if (tx_power > priv->tx_power_device_lmt) { IWL_WARN(priv, "Requested user TXPOWER %d above upper limit %d.\n", - tx_power, priv->tx_power_channel_lmt); + tx_power, priv->tx_power_device_lmt); return -EINVAL; } diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0178734499f..ccea2e4ab45 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1215,7 +1215,7 @@ struct iwl_priv { /* TX Power */ s8 tx_power_user_lmt; - s8 tx_power_channel_lmt; + s8 tx_power_device_lmt; #ifdef CONFIG_IWLWIFI_DEBUG -- cgit v1.2.3-18-g5258 From 5eadd94bd4006aacf12052c447bcc997bf6ecd28 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 21 Aug 2009 13:34:17 -0700 Subject: iwlwifi: error checking for setting tx_power in sysfs Perform error checking and report failure when setting tx power from sysfs. If fail to set the tx power, do not update the local copy, so user will not see the incorrect tx power in sysfs Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 13 +++++++++---- drivers/net/wireless/iwlwifi/iwl-core.c | 28 +++++++++++++++++++++------- 2 files changed, 30 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 2232b1794e7..533b393e8cf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2477,10 +2477,15 @@ static ssize_t store_tx_power(struct device *d, ret = strict_strtoul(buf, 10, &val); if (ret) IWL_INFO(priv, "%s is not in decimal form.\n", buf); - else - iwl_set_tx_power(priv, val, false); - - return count; + else { + ret = iwl_set_tx_power(priv, val, false); + if (ret) + IWL_ERR(priv, "failed setting tx power (0x%d).\n", + ret); + else + ret = count; + } + return ret; } static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 82dadd043b8..c62c081cfbb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1701,6 +1701,8 @@ EXPORT_SYMBOL(iwl_init_drv); int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) { int ret = 0; + s8 prev_tx_power = priv->tx_power_user_lmt; + if (tx_power < IWL_TX_POWER_TARGET_POWER_MIN) { IWL_WARN(priv, "Requested user TXPOWER %d below lower limit %d.\n", tx_power, @@ -1718,15 +1720,27 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) if (priv->tx_power_user_lmt != tx_power) force = true; - priv->tx_power_user_lmt = tx_power; - /* if nic is not up don't send command */ - if (!iwl_is_ready_rf(priv)) - return ret; - - if (force && priv->cfg->ops->lib->send_tx_power) - ret = priv->cfg->ops->lib->send_tx_power(priv); + if (iwl_is_ready_rf(priv)) { + priv->tx_power_user_lmt = tx_power; + if (force && priv->cfg->ops->lib->send_tx_power) + ret = priv->cfg->ops->lib->send_tx_power(priv); + else if (!priv->cfg->ops->lib->send_tx_power) + ret = -EOPNOTSUPP; + /* + * if fail to set tx_power, restore the orig. tx power + */ + if (ret) + priv->tx_power_user_lmt = prev_tx_power; + } + /* + * Even this is an async host command, the command + * will always report success from uCode + * So once driver can placing the command into the queue + * successfully, driver can use priv->tx_power_user_lmt + * to reflect the current tx power + */ return ret; } EXPORT_SYMBOL(iwl_set_tx_power); -- cgit v1.2.3-18-g5258 From fcbaf8b06da385c73cb6218f079e9ddba9ee9f7c Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 21 Aug 2009 13:34:18 -0700 Subject: iwlwifi: change IWL6000_UCODE_API_MAX to v4 uCode version changed to v4 for 6000 series The additional parameter added to v4 is providing current tx power for each chain in tx statistics portion of "statistics notification" command. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-commands.h | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 383177db7de..33ef736a485 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -46,8 +46,8 @@ #include "iwl-5000-hw.h" /* Highest firmware API version supported */ -#define IWL6000_UCODE_API_MAX 3 -#define IWL6050_UCODE_API_MAX 3 +#define IWL6000_UCODE_API_MAX 4 +#define IWL6050_UCODE_API_MAX 4 /* Lowest firmware API version supported */ #define IWL6000_UCODE_API_MIN 1 diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index f4303843ff9..6b82d4ecd3e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2930,6 +2930,20 @@ struct statistics_rx { struct statistics_rx_ht_phy ofdm_ht; } __attribute__ ((packed)); +/** + * struct statistics_tx_power - current tx power + * + * @ant_a: current tx power on chain a in 1/2 dB step + * @ant_b: current tx power on chain b in 1/2 dB step + * @ant_c: current tx power on chain c in 1/2 dB step + */ +struct statistics_tx_power { + u8 ant_a; + u8 ant_b; + u8 ant_c; + u8 reserved; +} __attribute__ ((packed)); + struct statistics_tx_non_phy_agg { __le32 ba_timeout; __le32 ba_reschedule_frames; @@ -2941,8 +2955,6 @@ struct statistics_tx_non_phy_agg { __le32 underrun; __le32 bt_prio_kill; __le32 rx_ba_rsp_cnt; - __le32 reserved2; - __le32 reserved3; } __attribute__ ((packed)); struct statistics_tx { @@ -2961,6 +2973,8 @@ struct statistics_tx { __le32 cts_timeout_collision; __le32 ack_or_ba_timeout_collision; struct statistics_tx_non_phy_agg agg; + struct statistics_tx_power tx_power; + __le32 reserved1; } __attribute__ ((packed)); -- cgit v1.2.3-18-g5258 From f204b2487e5503ca4a9f3e69dcd63f6af979aaac Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 21 Aug 2009 13:34:19 -0700 Subject: iwlwifi: show current tx power debugFs file show current tx power for all the transmit chains Adding "tx_power" file in /sys/kernal/debug/ieee80211/phy0/iwlagn/debug to display current tx power for all the active chains in 1/2 dB step. Show tx power information "Not available" if uCode can not provide the information or interface is down. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debug.h | 1 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 54 ++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 723f38a023c..cbc62904655 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -107,6 +107,7 @@ struct iwl_debugfs { struct dentry *file_ucode_general_stats; struct dentry *file_sensitivity; struct dentry *file_chain_noise; + struct dentry *file_tx_power; } dbgfs_debug_files; u32 sram_offset; u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index f68fb4711da..fb844859a44 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1563,6 +1563,57 @@ static ssize_t iwl_dbgfs_chain_noise_read(struct file *file, return ret; } +static ssize_t iwl_dbgfs_tx_power_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + char buf[128]; + int pos = 0; + ssize_t ret; + const size_t bufsz = sizeof(buf); + struct statistics_tx *tx; + + if (!iwl_is_alive(priv)) + pos += scnprintf(buf + pos, bufsz - pos, "N/A\n"); + else { + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + ret = iwl_send_statistics_request(priv, 0); + mutex_unlock(&priv->mutex); + + if (ret) { + IWL_ERR(priv, "Error sending statistics request: %zd\n", + ret); + return -EAGAIN; + } + tx = &priv->statistics.tx; + if (tx->tx_power.ant_a || + tx->tx_power.ant_b || + tx->tx_power.ant_c) { + pos += scnprintf(buf + pos, bufsz - pos, + "tx power: (1/2 dB step)\n"); + if ((priv->cfg->valid_tx_ant & ANT_A) && + tx->tx_power.ant_a) + pos += scnprintf(buf + pos, bufsz - pos, + "\tantenna A: 0x%X\n", + tx->tx_power.ant_a); + if ((priv->cfg->valid_tx_ant & ANT_B) && + tx->tx_power.ant_b) + pos += scnprintf(buf + pos, bufsz - pos, + "\tantenna B: 0x%X\n", + tx->tx_power.ant_b); + if ((priv->cfg->valid_tx_ant & ANT_C) && + tx->tx_power.ant_c) + pos += scnprintf(buf + pos, bufsz - pos, + "\tantenna C: 0x%X\n", + tx->tx_power.ant_c); + } else + pos += scnprintf(buf + pos, bufsz - pos, "N/A\n"); + } + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); @@ -1573,6 +1624,7 @@ DEBUGFS_READ_FILE_OPS(ucode_tx_stats); DEBUGFS_READ_FILE_OPS(ucode_general_stats); DEBUGFS_READ_FILE_OPS(sensitivity); DEBUGFS_READ_FILE_OPS(chain_noise); +DEBUGFS_READ_FILE_OPS(tx_power); /* * Create the debugfs files and directories @@ -1621,6 +1673,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(traffic_log, debug); DEBUGFS_ADD_FILE(rx_queue, debug); DEBUGFS_ADD_FILE(tx_queue, debug); + DEBUGFS_ADD_FILE(tx_power, debug); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_ADD_FILE(ucode_rx_stats, debug); DEBUGFS_ADD_FILE(ucode_tx_stats, debug); @@ -1674,6 +1727,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_traffic_log); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_queue); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. file_ucode_rx_stats); -- cgit v1.2.3-18-g5258 From 7ebaeff8ae0ba14c086b117f451c5b40bea8a64b Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Fri, 21 Aug 2009 13:34:20 -0700 Subject: iwlwifi: clear rate control flags on non-HT packet Clear the flags (most importantly, the IEEE80211_TX_RC_MCS flag) when sending a non-HT packet so that the rate index can be properly treated. This fixes the reporting of legacy rates in wireless-extensions for packets sent after an HT packet. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index fee110de5c6..26ec969e265 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2546,6 +2546,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, rate_idx = rate_lowest_index(sband, sta); else if (sband->band == IEEE80211_BAND_5GHZ) rate_idx -= IWL_FIRST_OFDM_RATE; + info->control.rates[0].flags = 0; } info->control.rates[0].idx = rate_idx; -- cgit v1.2.3-18-g5258 From c5f8cdb72e3940d647980358dec0aba945a3bb57 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Fri, 21 Aug 2009 13:34:21 -0700 Subject: iwlwifi: set HT flags in ieee80211_rx_status for received packets Add code to set the HT flags (HT, 40 MHz, Short guard interval) in the ieee80211_rx_status field passed to mac80211. This ensures that mac80211 processes these HT packets correctly. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-rx.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 353d9a2ddbc..e34d3fcb6c3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -915,6 +915,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, u32 len; u32 ampdu_status; u16 fc; + u32 rate_n_flags; /** * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently. @@ -1032,6 +1033,15 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) rx_status.flag |= RX_FLAG_SHORTPRE; + /* Set up the HT phy flags */ + rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); + if (rate_n_flags & RATE_MCS_HT_MSK) + rx_status.flag |= RX_FLAG_HT; + if (rate_n_flags & RATE_MCS_HT40_MSK) + rx_status.flag |= RX_FLAG_40MHZ; + if (rate_n_flags & RATE_MCS_SGI_MSK) + rx_status.flag |= RX_FLAG_SHORT_GI; + if (iwl_is_network_packet(priv, header)) { priv->last_rx_rssi = rx_status.signal; priv->last_beacon_time = priv->ucode_beacon_time; -- cgit v1.2.3-18-g5258 From c4d9b50986b4264f32883d19ac260a11647860e1 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 21 Aug 2009 13:34:22 -0700 Subject: iwlwifi: remove duplicated define Remove duplicated define "STA_FLG_PWR_SAVE_MSK" Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 6b82d4ecd3e..2c5c88fc38f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -886,7 +886,6 @@ struct iwl_qosparam_cmd { #define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2); #define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8); -#define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8); #define STA_FLG_RTS_MIMO_PROT_MSK cpu_to_le32(1 << 17) #define STA_FLG_AGG_MPDU_8US_MSK cpu_to_le32(1 << 18) #define STA_FLG_MAX_AGG_SIZE_POS (19) -- cgit v1.2.3-18-g5258 From ab9fd1bf76ffebf6c3b3d5800092387edf1201b9 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 21 Aug 2009 13:34:23 -0700 Subject: iwlwifi: read enhanced tx power info from EEPROM image For 6000 series and up, additional enhanced regulatory tx power limitation information is added to EEPROM image. In order to setup the tx power limitation per channel correctly. Read the enhanced tx power information from EEPROM image and update accordingly. The information is provided per SISO (a,b,c) chain based, it also has information for both MIMO2 and MIMO3. For tx power regulatory limitation, take the highest number from all the chains and update. Also update tx_power_user_lmt to the highest power supported by any channels and chains Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 1 + drivers/net/wireless/iwlwifi/iwl-eeprom.c | 252 ++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-eeprom.h | 80 +++++++++- 3 files changed, 332 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 33ef736a485..82b9c93dff5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -126,6 +126,7 @@ static struct iwl_lib_ops iwl6000_lib = { .release_semaphore = iwlcore_eeprom_release_semaphore, .calib_version = iwl5000_eeprom_calib_version, .query_addr = iwl5000_eeprom_query_addr, + .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, .post_associate = iwl_post_associate, .isr = iwl_isr_ict, diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 01b95e89009..3d2b93a61e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -135,6 +135,78 @@ static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */ 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157 }; +/** + * struct iwl_txpwr_section: eeprom section information + * @offset: indirect address into eeprom image + * @count: number of "struct iwl_eeprom_enhanced_txpwr" in this section + * @band: band type for the section + * @is_common - true: common section, false: channel section + * @is_cck - true: cck section, false: not cck section + * @is_ht_40 - true: all channel in the section are HT40 channel, + * false: legacy or HT 20 MHz + * ignore if it is common section + * @iwl_eeprom_section_channel: channel array in the section, + * ignore if common section + */ +struct iwl_txpwr_section { + u32 offset; + u8 count; + enum ieee80211_band band; + bool is_common; + bool is_cck; + bool is_ht40; + u8 iwl_eeprom_section_channel[EEPROM_MAX_TXPOWER_SECTION_ELEMENTS]; +}; + +/** + * section 1 - 3 are regulatory tx power apply to all channels based on + * modulation: CCK, OFDM + * Band: 2.4GHz, 5.2GHz + * section 4 - 10 are regulatory tx power apply to specified channels + * For example: + * 1L - Channel 1 Legacy + * 1HT - Channel 1 HT + * (1,+1) - Channel 1 HT40 "_above_" + * + * Section 1: all CCK channels + * Section 2: all 2.4 GHz OFDM (Legacy, HT and HT40) channels + * Section 3: all 5.2 GHz OFDM (Legacy, HT and HT40) channels + * Section 4: 2.4 GHz 20MHz channels: 1L, 1HT, 2L, 2HT, 10L, 10HT, 11L, 11HT + * Section 5: 2.4 GHz 40MHz channels: (1,+1) (2,+1) (6,+1) (7,+1) (9,+1) + * Section 6: 5.2 GHz 20MHz channels: 36L, 64L, 100L, 36HT, 64HT, 100HT + * Section 7: 5.2 GHz 40MHz channels: (36,+1) (60,+1) (100,+1) + * Section 8: 2.4 GHz channel: 13L, 13HT + * Section 9: 2.4 GHz channel: 140L, 140HT + * Section 10: 2.4 GHz 40MHz channels: (132,+1) (44,+1) + * + */ +static const struct iwl_txpwr_section enhinfo[] = { + { EEPROM_LB_CCK_20_COMMON, 1, IEEE80211_BAND_2GHZ, true, true, false }, + { EEPROM_LB_OFDM_COMMON, 3, IEEE80211_BAND_2GHZ, true, false, false }, + { EEPROM_HB_OFDM_COMMON, 3, IEEE80211_BAND_5GHZ, true, false, false }, + { EEPROM_LB_OFDM_20_BAND, 8, IEEE80211_BAND_2GHZ, + false, false, false, + {1, 1, 2, 2, 10, 10, 11, 11 } }, + { EEPROM_LB_OFDM_HT40_BAND, 5, IEEE80211_BAND_2GHZ, + false, false, true, + { 1, 2, 6, 7, 9 } }, + { EEPROM_HB_OFDM_20_BAND, 6, IEEE80211_BAND_5GHZ, + false, false, false, + { 36, 64, 100, 36, 64, 100 } }, + { EEPROM_HB_OFDM_HT40_BAND, 3, IEEE80211_BAND_5GHZ, + false, false, true, + { 36, 60, 100 } }, + { EEPROM_LB_OFDM_20_CHANNEL_13, 2, IEEE80211_BAND_2GHZ, + false, false, false, + { 13, 13 } }, + { EEPROM_HB_OFDM_20_CHANNEL_140, 2, IEEE80211_BAND_5GHZ, + false, false, false, + { 140, 140 } }, + { EEPROM_HB_OFDM_HT40_BAND_1, 2, IEEE80211_BAND_5GHZ, + false, false, true, + { 132, 44 } }, +}; + /****************************************************************************** * * EEPROM related functions @@ -643,6 +715,178 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv, return 0; } +/** + * iwl_get_max_txpower_avg - get the highest tx power from all chains. + * find the highest tx power from all chains for the channel + */ +static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, + struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, int element) +{ + s8 max_txpower_avg = 0; /* (dBm) */ + + IWL_DEBUG_INFO(priv, "%d - " + "chain_a: %d dB chain_b: %d dB " + "chain_c: %d dB mimo2: %d dB mimo3: %d dB\n", + element, + enhanced_txpower[element].chain_a_max >> 1, + enhanced_txpower[element].chain_b_max >> 1, + enhanced_txpower[element].chain_c_max >> 1, + enhanced_txpower[element].mimo2_max >> 1, + enhanced_txpower[element].mimo3_max >> 1); + /* Take the highest tx power from any valid chains */ + if ((priv->cfg->valid_tx_ant & ANT_A) && + (enhanced_txpower[element].chain_a_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].chain_a_max; + if ((priv->cfg->valid_tx_ant & ANT_B) && + (enhanced_txpower[element].chain_b_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].chain_b_max; + if ((priv->cfg->valid_tx_ant & ANT_C) && + (enhanced_txpower[element].chain_c_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].chain_c_max; + if (((priv->cfg->valid_tx_ant == ANT_AB) | + (priv->cfg->valid_tx_ant == ANT_BC) | + (priv->cfg->valid_tx_ant == ANT_AC)) && + (enhanced_txpower[element].mimo2_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].mimo2_max; + if ((priv->cfg->valid_tx_ant == ANT_ABC) && + (enhanced_txpower[element].mimo3_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].mimo3_max; + + /* max. tx power in EEPROM is in 1/2 dBm format + * convert from 1/2 dBm to dBm + */ + return max_txpower_avg >> 1; +} + +/** + * iwl_update_common_txpower: update channel tx power + * update tx power per band based on EEPROM enhanced tx power info. + */ +static s8 iwl_update_common_txpower(struct iwl_priv *priv, + struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, + int section, int element) +{ + struct iwl_channel_info *ch_info; + int ch; + bool is_ht40 = false; + s8 max_txpower_avg; /* (dBm) */ + + /* it is common section, contain all type (Legacy, HT and HT40) + * based on the element in the section to determine + * is it HT 40 or not + */ + if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX) + is_ht40 = true; + max_txpower_avg = + iwl_get_max_txpower_avg(priv, enhanced_txpower, element); + ch_info = priv->channel_info; + + for (ch = 0; ch < priv->channel_count; ch++) { + /* find matching band and update tx power if needed */ + if ((ch_info->band == enhinfo[section].band) && + (ch_info->max_power_avg < max_txpower_avg) && (!is_ht40)) { + /* Update regulatory-based run-time data */ + ch_info->max_power_avg = ch_info->curr_txpow = + max_txpower_avg; + ch_info->scan_power = max_txpower_avg; + } + if ((ch_info->band == enhinfo[section].band) && is_ht40 && + ch_info->ht40_max_power_avg && + (ch_info->ht40_max_power_avg < max_txpower_avg)) { + /* Update regulatory-based run-time data */ + ch_info->ht40_max_power_avg = max_txpower_avg; + ch_info->ht40_curr_txpow = max_txpower_avg; + ch_info->ht40_scan_power = max_txpower_avg; + } + ch_info++; + } + return max_txpower_avg; +} + +/** + * iwl_update_channel_txpower: update channel tx power + * update channel tx power based on EEPROM enhanced tx power info. + */ +static s8 iwl_update_channel_txpower(struct iwl_priv *priv, + struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, + int section, int element) +{ + struct iwl_channel_info *ch_info; + int ch; + u8 channel; + s8 max_txpower_avg; /* (dBm) */ + + channel = enhinfo[section].iwl_eeprom_section_channel[element]; + max_txpower_avg = + iwl_get_max_txpower_avg(priv, enhanced_txpower, element); + + ch_info = priv->channel_info; + for (ch = 0; ch < priv->channel_count; ch++) { + /* find matching channel and update tx power if needed */ + if (ch_info->channel == channel) { + if ((ch_info->max_power_avg < max_txpower_avg) && + (!enhinfo[section].is_ht40)) { + /* Update regulatory-based run-time data */ + ch_info->max_power_avg = max_txpower_avg; + ch_info->curr_txpow = max_txpower_avg; + ch_info->scan_power = max_txpower_avg; + } + if ((enhinfo[section].is_ht40) && + (ch_info->ht40_max_power_avg) && + (ch_info->ht40_max_power_avg < max_txpower_avg)) { + /* Update regulatory-based run-time data */ + ch_info->ht40_max_power_avg = max_txpower_avg; + ch_info->ht40_curr_txpow = max_txpower_avg; + ch_info->ht40_scan_power = max_txpower_avg; + } + break; + } + ch_info++; + } + return max_txpower_avg; +} + +/** + * iwlcore_eeprom_enhanced_txpower: process enhanced tx power info + */ +void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) +{ + int eeprom_section_count = 0; + int section, element; + struct iwl_eeprom_enhanced_txpwr *enhanced_txpower; + u32 offset; + s8 max_txpower_avg; /* (dBm) */ + + /* Loop through all the sections + * adjust bands and channel's max tx power + * Set the tx_power_user_lmt to the highest power + * supported by any channels and chains + */ + for (section = 0; section < ARRAY_SIZE(enhinfo); section++) { + eeprom_section_count = enhinfo[section].count; + offset = enhinfo[section].offset; + enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *) + iwl_eeprom_query_addr(priv, offset); + + for (element = 0; element < eeprom_section_count; element++) { + if (enhinfo[section].is_common) + max_txpower_avg = + iwl_update_common_txpower(priv, + enhanced_txpower, section, element); + else + max_txpower_avg = + iwl_update_channel_txpower(priv, + enhanced_txpower, section, element); + + /* Update the tx_power_user_lmt to the highest power + * supported by any channel */ + if (max_txpower_avg > priv->tx_power_user_lmt) + priv->tx_power_user_lmt = max_txpower_avg; + } + } +} +EXPORT_SYMBOL(iwlcore_eeprom_enhanced_txpower); + #define CHECK_AND_PRINT_I(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \ ? # x " " : "") @@ -790,6 +1034,14 @@ int iwl_init_channel_map(struct iwl_priv *priv) } } + /* for newer device (6000 series and up) + * EEPROM contain enhanced tx power information + * driver need to process addition information + * to determine the max channel tx power limits + */ + if (priv->cfg->ops->lib->eeprom_ops.update_enhanced_txpower) + priv->cfg->ops->lib->eeprom_ops.update_enhanced_txpower(priv); + return 0; } EXPORT_SYMBOL(iwl_init_channel_map); diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index ca7920a8f52..6b68db7b1b8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -118,6 +118,30 @@ struct iwl_eeprom_channel { s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ } __attribute__ ((packed)); +/** + * iwl_eeprom_enhanced_txpwr structure + * This structure presents the enhanced regulatory tx power limit layout + * in eeprom image + * Enhanced regulatory tx power portion of eeprom image can be broken down + * into individual structures; each one is 8 bytes in size and contain the + * following information + * @chain_a_max_pwr: chain a max power in 1/2 dBm + * @chain_b_max_pwr: chain b max power in 1/2 dBm + * @chain_c_max_pwr: chain c max power in 1/2 dBm + * @mimo2_max_pwr: mimo2 max power in 1/2 dBm + * @mimo3_max_pwr: mimo3 max power in 1/2 dBm + * + */ +struct iwl_eeprom_enhanced_txpwr { + u16 reserved; + s8 chain_a_max; + s8 chain_b_max; + s8 chain_c_max; + s8 reserved1; + s8 mimo2_max; + s8 mimo3_max; +} __attribute__ ((packed)); + /* 3945 Specific */ #define EEPROM_3945_EEPROM_VERSION (0x2f) @@ -175,6 +199,59 @@ struct iwl_eeprom_channel { #define EEPROM_5000_REG_BAND_52_HT40_CHANNELS ((0x92)\ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */ +/* 6000 and up regulatory tx power - indirect access */ +/* max. elements per section */ +#define EEPROM_MAX_TXPOWER_SECTION_ELEMENTS (8) +#define EEPROM_TXPOWER_COMMON_HT40_INDEX (2) + +/** + * Partition the enhanced tx power portion of eeprom image into + * 10 sections based on band, modulation, frequency and channel + * + * Section 1: all CCK channels + * Section 2: all 2.4 GHz OFDM (Legacy, HT and HT40 ) channels + * Section 3: all 5.2 GHz OFDM (Legacy, HT and HT40) channels + * Section 4: 2.4 GHz 20MHz channels: 1, 2, 10, 11. Both Legacy and HT + * Section 5: 2.4 GHz 40MHz channels: 1, 2, 6, 7, 9, (_above_) + * Section 6: 5.2 GHz 20MHz channels: 36, 64, 100, both Legacy and HT + * Section 7: 5.2 GHz 40MHz channels: 36, 60, 100 (_above_) + * Section 8: 2.4 GHz channel 13, Both Legacy and HT + * Section 9: 2.4 GHz channel 140, Both Legacy and HT + * Section 10: 2.4 GHz 40MHz channels: 132, 44 (_above_) + */ +/* 2.4 GHz band: CCK */ +#define EEPROM_LB_CCK_20_COMMON ((0xAA)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 8 bytes */ +/* 2.4 GHz band: 20MHz-Legacy, 20MHz-HT, 40MHz-HT */ +#define EEPROM_LB_OFDM_COMMON ((0xB2)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */ +/* 5.2 GHz band: 20MHz-Legacy, 20MHz-HT, 40MHz-HT */ +#define EEPROM_HB_OFDM_COMMON ((0xCA)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */ +/* 2.4GHz band channels: + * 1Legacy, 1HT, 2Legacy, 2HT, 10Legacy, 10HT, 11Legacy, 11HT */ +#define EEPROM_LB_OFDM_20_BAND ((0xE2)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 64 bytes */ +/* 2.4 GHz band HT40 channels: (1,+1) (2,+1) (6,+1) (7,+1) (9,+1) */ +#define EEPROM_LB_OFDM_HT40_BAND ((0x122)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 40 bytes */ +/* 5.2GHz band channels: 36Legacy, 36HT, 64Legacy, 64HT, 100Legacy, 100HT */ +#define EEPROM_HB_OFDM_20_BAND ((0x14A)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 48 bytes */ +/* 5.2 GHz band HT40 channels: (36,+1) (60,+1) (100,+1) */ +#define EEPROM_HB_OFDM_HT40_BAND ((0x17A)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */ +/* 2.4 GHz band, channnel 13: Legacy, HT */ +#define EEPROM_LB_OFDM_20_CHANNEL_13 ((0x192)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */ +/* 5.2 GHz band, channnel 140: Legacy, HT */ +#define EEPROM_HB_OFDM_20_CHANNEL_140 ((0x1A2)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */ +/* 5.2 GHz band, HT40 channnels (132,+1) (44,+1) */ +#define EEPROM_HB_OFDM_HT40_BAND_1 ((0x1B2)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */ + + /* 5050 Specific */ #define EEPROM_5050_TX_POWER_VERSION (4) #define EEPROM_5050_EEPROM_VERSION (0x21E) @@ -389,6 +466,7 @@ struct iwl_eeprom_ops { void (*release_semaphore) (struct iwl_priv *priv); u16 (*calib_version) (struct iwl_priv *priv); const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset); + void (*update_enhanced_txpower) (struct iwl_priv *priv); }; @@ -403,7 +481,7 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv); int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv); void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv); const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); - +void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv); int iwl_init_channel_map(struct iwl_priv *priv); void iwl_free_channel_map(struct iwl_priv *priv); const struct iwl_channel_info *iwl_get_channel_info( -- cgit v1.2.3-18-g5258 From b2ccb4dbe77eaebb6b286402c31b4e2b1155660f Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Fri, 21 Aug 2009 13:34:24 -0700 Subject: iwlwifi: fix remove key error Fix following error by sending synchronous command and waiting for the command to complete. mac80211-phy0: failed to remove key (0, ff:ff:ff:ff:ff:ff) from hardware (-16). -16 is EBUSY error. The asynchronous command tests for STATUS_EXIT_PENDING while interface is getting down and it returns -EBUSY error if set. Changing the host command from asynchronous call to synchronous call enables command to be run while interface is going down. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-sta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index c6633fec821..a2b9ec82b96 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -520,7 +520,7 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty) struct iwl_host_cmd cmd = { .id = REPLY_WEPKEY, .data = wep_cmd, - .flags = CMD_ASYNC, + .flags = CMD_SYNC, }; memset(wep_cmd, 0, cmd_size + -- cgit v1.2.3-18-g5258 From 5bddf54962bf68002816df710348ba197d6391bb Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 21 Aug 2009 13:34:25 -0700 Subject: iwlwifi: fix unloading driver while scanning If NetworkManager is busy scanning when user tries to unload the module, the driver can not be unloaded because HW still scanning. Make sure driver sends abort scan host command to uCode if it is in the middle of scanning during driver unload. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +- drivers/net/wireless/iwlwifi/iwl-scan.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 533b393e8cf..00457bff1ed 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2155,7 +2155,7 @@ static void iwl_mac_stop(struct ieee80211_hw *hw) priv->is_open = 0; - if (iwl_is_ready_rf(priv)) { + if (iwl_is_ready_rf(priv) || test_bit(STATUS_SCAN_HW, &priv->status)) { /* stop mac, cancel any scan request and clear * RXON_FILTER_ASSOC_MSK BIT */ diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index c4c916df4a4..4f3a108fa99 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -796,7 +796,8 @@ void iwl_bg_abort_scan(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan); - if (!iwl_is_ready(priv)) + if (!test_bit(STATUS_READY, &priv->status) || + !test_bit(STATUS_GEO_CONFIGURED, &priv->status)) return; mutex_lock(&priv->mutex); -- cgit v1.2.3-18-g5258 From c1eb2c82e5ccc9b691f737c3150e746c9af3ffab Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 21 Aug 2009 13:34:26 -0700 Subject: ipw2x00: update contact information Intel Linux wireless folks can be reached via this address. Signed-off-by: Reinette Chatre Acked-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2100.c | 2 +- drivers/net/wireless/ipw2x00/ipw2100.h | 2 +- drivers/net/wireless/ipw2x00/ipw2200.c | 2 +- drivers/net/wireless/ipw2x00/ipw2200.h | 2 +- drivers/net/wireless/ipw2x00/libipw_geo.c | 2 +- drivers/net/wireless/ipw2x00/libipw_module.c | 2 +- drivers/net/wireless/ipw2x00/libipw_tx.c | 2 +- drivers/net/wireless/ipw2x00/libipw_wx.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 33bdb20e9f1..8caa07a213b 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -19,7 +19,7 @@ file called LICENSE. Contact Information: - James P. Ketrenos + Intel Linux Wireless Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 Portions of this file are based on the sample_* files provided by Wireless diff --git a/drivers/net/wireless/ipw2x00/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h index af175bdc9f2..1eab0d698f4 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.h +++ b/drivers/net/wireless/ipw2x00/ipw2100.h @@ -19,7 +19,7 @@ file called LICENSE. Contact Information: - James P. Ketrenos + Intel Linux Wireless Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ******************************************************************************/ diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 3617e3c1e9e..0ccec9f9f95 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -25,7 +25,7 @@ file called LICENSE. Contact Information: - James P. Ketrenos + Intel Linux Wireless Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ******************************************************************************/ diff --git a/drivers/net/wireless/ipw2x00/ipw2200.h b/drivers/net/wireless/ipw2x00/ipw2200.h index 4448bad51b8..bf0eeb2e873 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.h +++ b/drivers/net/wireless/ipw2x00/ipw2200.h @@ -19,7 +19,7 @@ file called LICENSE. Contact Information: - James P. Ketrenos + Intel Linux Wireless Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ******************************************************************************/ diff --git a/drivers/net/wireless/ipw2x00/libipw_geo.c b/drivers/net/wireless/ipw2x00/libipw_geo.c index d04979ba2a5..65e8c175a4a 100644 --- a/drivers/net/wireless/ipw2x00/libipw_geo.c +++ b/drivers/net/wireless/ipw2x00/libipw_geo.c @@ -19,7 +19,7 @@ file called LICENSE. Contact Information: - James P. Ketrenos + Intel Linux Wireless Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ******************************************************************************/ diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c index 00c3640b0f8..eb2b60834c1 100644 --- a/drivers/net/wireless/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/ipw2x00/libipw_module.c @@ -25,7 +25,7 @@ file called LICENSE. Contact Information: - James P. Ketrenos + Intel Linux Wireless Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c index ce1855f32b7..46530ce56ea 100644 --- a/drivers/net/wireless/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/ipw2x00/libipw_tx.c @@ -19,7 +19,7 @@ file called LICENSE. Contact Information: - James P. Ketrenos + Intel Linux Wireless Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ******************************************************************************/ diff --git a/drivers/net/wireless/ipw2x00/libipw_wx.c b/drivers/net/wireless/ipw2x00/libipw_wx.c index f79ce57ebe6..4d89f66f53b 100644 --- a/drivers/net/wireless/ipw2x00/libipw_wx.c +++ b/drivers/net/wireless/ipw2x00/libipw_wx.c @@ -25,7 +25,7 @@ file called LICENSE. Contact Information: - James P. Ketrenos + Intel Linux Wireless Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ******************************************************************************/ -- cgit v1.2.3-18-g5258 From ea39d1a4027cca99cc75126f574633c3b72da04a Mon Sep 17 00:00:00 2001 From: Joerg Albert Date: Fri, 21 Aug 2009 23:25:07 +0200 Subject: ar9170: cleanup of bss_info_changed and beacon config Add beacon control by BSS_CHANGED_BEACON_ENABLED and bss_conf->enable_beacon from mac80211. Signed-off-by: Joerg Albert Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/ar9170.h | 1 + drivers/net/wireless/ath/ar9170/mac.c | 24 +++++++++++++----------- drivers/net/wireless/ath/ar9170/main.c | 14 +++++++------- 3 files changed, 21 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index ce407248d7d..914e4718a9a 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -178,6 +178,7 @@ struct ar9170 { /* beaconing */ struct sk_buff *beacon; struct work_struct beacon_work; + bool enable_beacon; /* cryptographic engine */ u64 usedkeys; diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c index 60049366e86..614e3218a2b 100644 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ b/drivers/net/wireless/ath/ar9170/mac.c @@ -383,24 +383,26 @@ int ar9170_set_beacon_timers(struct ar9170 *ar) if (ar->vif) { v |= ar->vif->bss_conf.beacon_int; - switch (ar->vif->type) { - case NL80211_IFTYPE_MESH_POINT: - case NL80211_IFTYPE_ADHOC: - v |= BIT(25); - break; - case NL80211_IFTYPE_AP: - v |= BIT(24); - pretbtt = (ar->vif->bss_conf.beacon_int - 6) << 16; - break; - default: + if (ar->enable_beacon) { + switch (ar->vif->type) { + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_ADHOC: + v |= BIT(25); + break; + case NL80211_IFTYPE_AP: + v |= BIT(24); + pretbtt = (ar->vif->bss_conf.beacon_int - 6) << + 16; + break; + default: break; + } } v |= ar->vif->bss_conf.dtim_period << 16; } ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_PRETBTT, pretbtt); ar9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, v); ar9170_regwrite_finish(); diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 658b32312ca..c0fc3554c92 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -2148,11 +2148,17 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, goto out; } - if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) { + if (changed & BSS_CHANGED_BEACON_ENABLED) + ar->enable_beacon = bss_conf->enable_beacon; + + if (changed & BSS_CHANGED_BEACON) { err = ar9170_update_beacon(ar); if (err) goto out; + } + if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON | + BSS_CHANGED_BEACON_INT)) { err = ar9170_set_beacon_timers(ar); if (err) goto out; @@ -2165,12 +2171,6 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, #endif /* CONFIG_AR9170_LEDS */ } - if (changed & BSS_CHANGED_BEACON_INT) { - err = ar9170_set_beacon_timers(ar); - if (err) - goto out; - } - if (changed & BSS_CHANGED_HT) { /* TODO */ err = 0; -- cgit v1.2.3-18-g5258 From 229a7ef7c2861f9ecb7e025f4bd4ea1167fbb0a7 Mon Sep 17 00:00:00 2001 From: Joerg Albert Date: Fri, 21 Aug 2009 22:53:37 +0200 Subject: ar9170: remove unnecessary call to ar9170_set_beacon_timers Signed-off-by: Joerg Albert Acked-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/main.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index c0fc3554c92..c1f8c69db16 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -2031,12 +2031,6 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) goto out; } - if (changed & BSS_CHANGED_BEACON_INT) { - err = ar9170_set_beacon_timers(ar); - if (err) - goto out; - } - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { /* adjust slot time for 5 GHz */ -- cgit v1.2.3-18-g5258 From 942457d63fedd08ce7330b89fc2934be02c3fecc Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 24 Aug 2009 15:42:36 +0200 Subject: mwl8k: fix inverted error test in mwl8k_bss_info_changed() Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 41a708ce873..4d3353cb308 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2617,7 +2617,7 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, priv->capture_beacon = false; rc = mwl8k_fw_lock(hw); - if (!rc) + if (rc) return; if (info->assoc) { -- cgit v1.2.3-18-g5258 From 39a1e42eb4d0a2bc3f1211e9012bd23734ab86db Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 24 Aug 2009 15:42:46 +0200 Subject: mwl8k: fix pci dma mapping leak in mwl8k_post_cmd() error path Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 4d3353cb308..a4336f45f52 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1439,8 +1439,11 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) return -ENOMEM; rc = mwl8k_fw_lock(hw); - if (rc) + if (rc) { + pci_unmap_single(priv->pdev, dma_addr, dma_size, + PCI_DMA_BIDIRECTIONAL); return rc; + } priv->hostcmd_wait = &cmd_wait; iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR); -- cgit v1.2.3-18-g5258 From 76c962a204f8d36b762440aa941fcea3d44e2fd2 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 24 Aug 2009 15:42:56 +0200 Subject: mwl8k: missing endian conversion when printing firmware command result Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index a4336f45f52..6e017db05b8 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1474,7 +1474,7 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) printk(KERN_ERR "%s: Command %s error 0x%x\n", priv->name, mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), - cmd->result); + le16_to_cpu(cmd->result)); } return rc; -- cgit v1.2.3-18-g5258 From 2aa7b01fe4f2d0978115bfd40364f52d86003606 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 24 Aug 2009 15:48:07 +0200 Subject: mwl8k: separate driver and device info reporting during probe Only print the driver version once, and condense all per-PHY information to a single line. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 6e017db05b8..746532ebe5a 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -164,7 +164,7 @@ struct mwl8k_priv { u16 num_mcaddrs; u8 hw_rev; - __le32 fw_rev; + u32 fw_rev; /* * Running count of TX packets in flight, to avoid @@ -2825,11 +2825,16 @@ static void mwl8k_finalize_join_worker(struct work_struct *work) static int __devinit mwl8k_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + static int printed_version = 0; struct ieee80211_hw *hw; struct mwl8k_priv *priv; int rc; int i; - u8 *fw; + + if (!printed_version) { + printk(KERN_INFO "%s version %s\n", MWL8K_DESC, MWL8K_VERSION); + printed_version = 1; + } rc = pci_enable_device(pdev); if (rc) { @@ -3004,13 +3009,11 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, goto err_stop_firmware; } - fw = (u8 *)&priv->fw_rev; - printk(KERN_INFO "%s: 88W%u %s\n", priv->name, priv->part_num, - MWL8K_DESC); - printk(KERN_INFO "%s: Driver Ver:%s Firmware Ver:%u.%u.%u.%u\n", - priv->name, MWL8K_VERSION, fw[3], fw[2], fw[1], fw[0]); - printk(KERN_INFO "%s: MAC Address: %pM\n", priv->name, - hw->wiphy->perm_addr); + printk(KERN_INFO "%s: 88w%u v%d, %pM, firmware version %u.%u.%u.%u\n", + wiphy_name(hw->wiphy), priv->part_num, priv->hw_rev, + hw->wiphy->perm_addr, + (priv->fw_rev >> 24) & 0xff, (priv->fw_rev >> 16) & 0xff, + (priv->fw_rev >> 8) & 0xff, priv->fw_rev & 0xff); return 0; -- cgit v1.2.3-18-g5258 From 56d1de0a21db28e41741cfa0a66e18bc8d920554 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 24 Aug 2009 23:00:30 -0400 Subject: ath5k: clean up filter flags setting The maze of if() statements in configure_filter is confusing. Reorganizing it as a switch statement makes it more apparent what is going on and reveals several suspicious settings. This has no functional changes, though it does remove some redundant flags that are set earlier. Also now that we can sleep, protect sc->filter_flags with the sc lock. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 39 +++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 5056410d788..c4adf984641 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2918,6 +2918,8 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, struct ath5k_hw *ah = sc->ah; u32 mfilt[2], rfilt; + mutex_lock(&sc->lock); + mfilt[0] = multicast; mfilt[1] = multicast >> 32; @@ -2968,22 +2970,25 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, /* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */ - if (sc->opmode == NL80211_IFTYPE_MONITOR) - rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON | - AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM; - if (sc->opmode != NL80211_IFTYPE_STATION) - rfilt |= AR5K_RX_FILTER_PROBEREQ; - if (sc->opmode != NL80211_IFTYPE_AP && - sc->opmode != NL80211_IFTYPE_MESH_POINT && - test_bit(ATH_STAT_PROMISC, sc->status)) - rfilt |= AR5K_RX_FILTER_PROM; - if ((sc->opmode == NL80211_IFTYPE_STATION && sc->assoc) || - sc->opmode == NL80211_IFTYPE_ADHOC || - sc->opmode == NL80211_IFTYPE_AP) - rfilt |= AR5K_RX_FILTER_BEACON; - if (sc->opmode == NL80211_IFTYPE_MESH_POINT) - rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON | - AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM; + switch (sc->opmode) { + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_MONITOR: + rfilt |= AR5K_RX_FILTER_CONTROL | + AR5K_RX_FILTER_BEACON | + AR5K_RX_FILTER_PROBEREQ | + AR5K_RX_FILTER_PROM; + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_ADHOC: + rfilt |= AR5K_RX_FILTER_PROBEREQ | + AR5K_RX_FILTER_BEACON; + break; + case NL80211_IFTYPE_STATION: + if (sc->assoc) + rfilt |= AR5K_RX_FILTER_BEACON; + default: + break; + } /* Set filters */ ath5k_hw_set_rx_filter(ah, rfilt); @@ -2993,6 +2998,8 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, /* Set the cached hw filter flags, this will alter actually * be set in HW */ sc->filter_flags = rfilt; + + mutex_unlock(&sc->lock); } static int -- cgit v1.2.3-18-g5258 From 09c9bae26b0d3c9472cb6ae45010460a2cee8b8d Mon Sep 17 00:00:00 2001 From: Marcos Chaparro Date: Mon, 24 Aug 2009 23:00:31 -0400 Subject: ath5k: add led pin configuration for compaq c700 laptop With this patch, a compaq c700 can turn on the wifi led. The array of compatible devices now includes the hardware present in this computer, as well as the led pin and polarity. Signed-off-by: Marcos Chaparro Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/led.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c index 876725f08b6..b767c3b67b2 100644 --- a/drivers/net/wireless/ath/ath5k/led.c +++ b/drivers/net/wireless/ath/ath5k/led.c @@ -69,6 +69,8 @@ static const struct pci_device_id ath5k_led_devices[] = { { ATH_SDEVICE(PCI_VENDOR_ID_AZWAVE, 0x1026), ATH_LED(3, 0) }, /* IBM ThinkPad AR5BXB6 (legovini@spiro.fisica.unipd.it) */ { ATH_SDEVICE(PCI_VENDOR_ID_IBM, 0x058a), ATH_LED(1, 0) }, + /* HP Compaq C700 (nitrousnrg@gmail.com) */ + { ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137b), ATH_LED(3, 1) }, /* IBM-specific AR5212 (all others) */ { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5212_IBM), ATH_LED(0, 0) }, { } -- cgit v1.2.3-18-g5258 From 1c5256bb168faca5ce32a9c9511c8389f9fed31c Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 24 Aug 2009 23:00:32 -0400 Subject: ath5k: use the skb->cb directly for RX status Save a memcpy by just storing updates directly in the skb control block. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 41 ++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index c4adf984641..10bf0154706 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1741,7 +1741,7 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, static void ath5k_tasklet_rx(unsigned long data) { - struct ieee80211_rx_status rxs = {}; + struct ieee80211_rx_status *rxs; struct ath5k_rx_status rs = {}; struct sk_buff *skb, *next_skb; dma_addr_t next_skb_addr; @@ -1751,6 +1751,7 @@ ath5k_tasklet_rx(unsigned long data) int ret; int hdrlen; int padsize; + int rx_flag; spin_lock(&sc->rxbuflock); if (list_empty(&sc->rxbuf)) { @@ -1758,7 +1759,7 @@ ath5k_tasklet_rx(unsigned long data) goto unlock; } do { - rxs.flag = 0; + rx_flag = 0; bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); BUG_ON(bf->skb == NULL); @@ -1802,7 +1803,7 @@ ath5k_tasklet_rx(unsigned long data) goto accept; } if (rs.rs_status & AR5K_RXERR_MIC) { - rxs.flag |= RX_FLAG_MMIC_ERROR; + rx_flag |= RX_FLAG_MMIC_ERROR; goto accept; } @@ -1840,6 +1841,7 @@ accept: memmove(skb->data + padsize, skb->data, hdrlen); skb_pull(skb, padsize); } + rxs = IEEE80211_SKB_RXCB(skb); /* * always extend the mac timestamp, since this information is @@ -1861,41 +1863,40 @@ accept: * impossible to comply to that. This affects IBSS merge only * right now, so it's not too bad... */ - rxs.mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp); - rxs.flag |= RX_FLAG_TSFT; + rxs->mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp); + rxs->flag = rx_flag | RX_FLAG_TSFT; - rxs.freq = sc->curchan->center_freq; - rxs.band = sc->curband->band; + rxs->freq = sc->curchan->center_freq; + rxs->band = sc->curband->band; - rxs.noise = sc->ah->ah_noise_floor; - rxs.signal = rxs.noise + rs.rs_rssi; + rxs->noise = sc->ah->ah_noise_floor; + rxs->signal = rxs->noise + rs.rs_rssi; /* An rssi of 35 indicates you should be able use * 54 Mbps reliably. A more elaborate scheme can be used * here but it requires a map of SNR/throughput for each * possible mode used */ - rxs.qual = rs.rs_rssi * 100 / 35; + rxs->qual = rs.rs_rssi * 100 / 35; /* rssi can be more than 35 though, anything above that * should be considered at 100% */ - if (rxs.qual > 100) - rxs.qual = 100; + if (rxs->qual > 100) + rxs->qual = 100; - rxs.antenna = rs.rs_antenna; - rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); - rxs.flag |= ath5k_rx_decrypted(sc, ds, skb, &rs); + rxs->antenna = rs.rs_antenna; + rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); + rxs->flag |= ath5k_rx_decrypted(sc, ds, skb, &rs); - if (rxs.rate_idx >= 0 && rs.rs_rate == - sc->curband->bitrates[rxs.rate_idx].hw_value_short) - rxs.flag |= RX_FLAG_SHORTPRE; + if (rxs->rate_idx >= 0 && rs.rs_rate == + sc->curband->bitrates[rxs->rate_idx].hw_value_short) + rxs->flag |= RX_FLAG_SHORTPRE; ath5k_debug_dump_skb(sc, skb, "RX ", 0); /* check beacons in IBSS mode */ if (sc->opmode == NL80211_IFTYPE_ADHOC) - ath5k_check_ibss_tsf(sc, skb, &rxs); + ath5k_check_ibss_tsf(sc, skb, rxs); - memcpy(IEEE80211_SKB_RXCB(skb), &rxs, sizeof(rxs)); ieee80211_rx(sc->hw, skb); bf->skb = next_skb; -- cgit v1.2.3-18-g5258 From 1c81874078dc96b8158ce7b0dab54afe43c8d03e Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 24 Aug 2009 23:00:33 -0400 Subject: ath5k: add hardware CCMP encyption support Recent ath5k hardware is capable of doing CCMP acceleration. Enable it for the cards that support it. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 1 + drivers/net/wireless/ath/ath5k/attach.c | 10 ++++++++++ drivers/net/wireless/ath/ath5k/base.c | 3 +++ 3 files changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 862762cea54..cdc79cd134c 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1037,6 +1037,7 @@ struct ath5k_hw { bool ah_turbo; bool ah_calibration; bool ah_single_chip; + bool ah_aes_support; bool ah_combined_mic; enum ath5k_version ah_version; diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 65d438b59f6..109ab7ba304 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -106,6 +106,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) { struct ath5k_hw *ah; struct pci_dev *pdev = sc->pdev; + struct ath5k_eeprom_info *ee; int ret; u32 srev; @@ -315,6 +316,15 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) goto err_free; } + /* Crypto settings */ + ee = &ah->ah_capabilities.cap_eeprom; + ah->ah_aes_support = + (ee->ee_version >= AR5K_EEPROM_VERSION_5_0 && + !AR5K_EEPROM_AES_DIS(ee->ee_misc5) && + (ah->ah_mac_version > (AR5K_SREV_AR5212 >> 4) || + (ah->ah_mac_version == (AR5K_SREV_AR5212 >> 4) && + ah->ah_mac_revision >= (AR5K_SREV_AR5211 >> 4)))); + if (srev >= AR5K_SREV_AR2414) { ah->ah_combined_mic = true; AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE, diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 10bf0154706..94d46fd94ff 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -3022,6 +3022,9 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, case ALG_TKIP: break; case ALG_CCMP: + if (sc->ah->ah_aes_support) + break; + return -EOPNOTSUPP; default: WARN_ON(1); -- cgit v1.2.3-18-g5258 From 1e4c7ddc3c34b3e129ec34b3f90bd6359743a5bb Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Tue, 25 Aug 2009 15:28:45 +0530 Subject: PRISM54: fix compilation warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC [M] drivers/net/wireless/prism54/islpci_eth.o drivers/net/wireless/prism54/islpci_eth.c: In function ‘islpci_eth_cleanup_transmit’: drivers/net/wireless/prism54/islpci_eth.c:53: warning: cast from pointer to integer of different size drivers/net/wireless/prism54/islpci_eth.c: In function ‘islpci_eth_receive’: drivers/net/wireless/prism54/islpci_eth.c:453: warning: cast from pointer to integer of different size Signed-off-by: Jaswinder Singh Rajput Signed-off-by: John W. Linville --- drivers/net/wireless/prism54/islpci_eth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index c255d9c6a5f..9b5ee341928 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -50,7 +50,7 @@ islpci_eth_cleanup_transmit(islpci_private *priv, /* check for holes in the arrays caused by multi fragment frames * searching for the last fragment of a frame */ - if (priv->pci_map_tx_address[index] != (dma_addr_t) NULL) { + if (priv->pci_map_tx_address[index]) { /* entry is the last fragment of a frame * free the skb structure and unmap pci memory */ skb = priv->data_low_tx[index]; @@ -450,7 +450,7 @@ islpci_eth_receive(islpci_private *priv) pci_map_single(priv->pdev, (void *) skb->data, MAX_FRAGMENT_SIZE_RX + 2, PCI_DMA_FROMDEVICE); - if (unlikely(priv->pci_map_rx_address[index] == (dma_addr_t) NULL)) { + if (unlikely(!priv->pci_map_rx_address[index])) { /* error mapping the buffer to device accessable memory address */ DEBUG(SHOW_ERROR_MESSAGES, "Error mapping DMA address\n"); -- cgit v1.2.3-18-g5258 From 6bd5f5208fac04d00325b458355e4a4abda76595 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Tue, 25 Aug 2009 16:17:48 +0200 Subject: b43: LP-PHY: Fix a few typos in the RC calibration code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The RC calibration code has some typos - fix them. Also, make the default channel 7, as channel 1 is still broken (only channels 7 and 8, and occasionally 9 work). Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 2d3a5d812c4..7e70c078475 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -44,7 +44,7 @@ static inline u16 channel2freq_lp(u8 channel) static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev) { if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - return 1; + return 7; //FIXME temporary - channel 1 is broken return 36; } @@ -705,7 +705,7 @@ static void lpphy_set_rc_cap(struct b43_wldev *dev) u8 rc_cap = (lpphy->rc_cap & 0x1F) >> 1; if (dev->phy.rev == 1) //FIXME check channel 14! - rc_cap = max_t(u8, rc_cap + 5, 15); + rc_cap = min_t(u8, rc_cap + 5, 15); b43_radio_write(dev, B2062_N_RXBB_CALIB2, max_t(u8, lpphy->rc_cap - 4, 0x80)); @@ -1008,6 +1008,7 @@ static int lpphy_loopback(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x3); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3); + b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 1); b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x800); @@ -1213,7 +1214,7 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) mean_sq_pwr = ideal_pwr - normal_pwr; mean_sq_pwr *= mean_sq_pwr; inner_sum += mean_sq_pwr; - if ((i = 128) || (inner_sum < mean_sq_pwr_min)) { + if ((i == 128) || (inner_sum < mean_sq_pwr_min)) { lpphy->rc_cap = i; mean_sq_pwr_min = inner_sum; } -- cgit v1.2.3-18-g5258 From 73f57f8398ed6cba82f9856e20d94d71e6edb3e2 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Fri, 7 Aug 2009 23:50:00 +0200 Subject: ath9k: Fix read buffer overflow Prevent a read of powInfo[-1] in the first iteration. Signed-off-by: Roel Kluin Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 958948bc73f..b6e52d0f8c4 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -143,10 +143,10 @@ void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, IS_CHAN_2GHZ(chan))) { matchIndex = i; break; - } else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) && - (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, - IS_CHAN_2GHZ(chan)))) { + } else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan)) && i > 0 && + freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, + IS_CHAN_2GHZ(chan))) { lowIndex = i - 1; break; } @@ -198,10 +198,10 @@ void ath9k_hw_get_target_powers(struct ath_hw *ah, matchIndex = i; break; } else - if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) && - (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, - IS_CHAN_2GHZ(chan)))) { + if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan)) && i > 0 && + freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, + IS_CHAN_2GHZ(chan))) { lowIndex = i - 1; break; } -- cgit v1.2.3-18-g5258 From b8ecd988b1670035a05035c553c08331214d6603 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 25 Aug 2009 14:12:25 -0400 Subject: libipw: initiate cfg80211 API conversion Initiate the conversion of libipw to the new cfg80211 configuration API. For now, leave CONFIG_IPW2200_PROMISCUOUS stuff alone. Eventually migrate it to cfg80211 when the add/del/change_virtual_intf methods are implemented. Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2100.c | 6 +- drivers/net/wireless/ipw2x00/ipw2200.c | 141 +++++++++++++++++++++------ drivers/net/wireless/ipw2x00/libipw.h | 8 +- drivers/net/wireless/ipw2x00/libipw_module.c | 42 +++++++- 4 files changed, 161 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 8caa07a213b..77457386e0a 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -6029,7 +6029,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, struct ipw2100_priv *priv; struct net_device *dev; - dev = alloc_ieee80211(sizeof(struct ipw2100_priv)); + dev = alloc_ieee80211(sizeof(struct ipw2100_priv), 0); if (!dev) return NULL; priv = libipw_priv(dev); @@ -6342,7 +6342,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group); - free_ieee80211(dev); + free_ieee80211(dev, 0); pci_set_drvdata(pci_dev, NULL); } @@ -6400,7 +6400,7 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev) if (dev->base_addr) iounmap((void __iomem *)dev->base_addr); - free_ieee80211(dev); + free_ieee80211(dev, 0); } pci_release_regions(pci_dev); diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 0ccec9f9f95..3f8372daf46 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -103,6 +103,25 @@ static int antenna = CFG_SYS_ANTENNA_BOTH; static int rtap_iface = 0; /* def: 0 -- do not create rtap interface */ #endif +static struct ieee80211_rate ipw2200_rates[] = { + { .bitrate = 10 }, + { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60 }, + { .bitrate = 90 }, + { .bitrate = 120 }, + { .bitrate = 180 }, + { .bitrate = 240 }, + { .bitrate = 360 }, + { .bitrate = 480 }, + { .bitrate = 540 } +}; + +#define ipw2200_a_rates (ipw2200_rates + 4) +#define ipw2200_num_a_rates 8 +#define ipw2200_bg_rates (ipw2200_rates + 0) +#define ipw2200_num_bg_rates 12 #ifdef CONFIG_IPW2200_QOS static int qos_enable = 0; @@ -8640,24 +8659,6 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) * */ -static int ipw_wx_get_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = libipw_priv(dev); - mutex_lock(&priv->mutex); - if (priv->status & STATUS_RF_KILL_MASK) - strcpy(wrqu->name, "radio off"); - else if (!(priv->status & STATUS_ASSOCIATED)) - strcpy(wrqu->name, "unassociated"); - else - snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c", - ipw_modes[priv->assoc_request.ieee_mode]); - IPW_DEBUG_WX("Name: %s\n", wrqu->name); - mutex_unlock(&priv->mutex); - return 0; -} - static int ipw_set_channel(struct ipw_priv *priv, u8 channel) { if (channel == 0) { @@ -9957,7 +9958,7 @@ static int ipw_wx_sw_reset(struct net_device *dev, /* Rebase the WE IOCTLs to zero for the handler array */ #define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT] static iw_handler ipw_wx_handlers[] = { - IW_IOCTL(SIOCGIWNAME) = ipw_wx_get_name, + IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname, IW_IOCTL(SIOCSIWFREQ) = ipw_wx_set_freq, IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq, IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode, @@ -11401,16 +11402,100 @@ static void ipw_bg_down(struct work_struct *work) /* Called by register_netdev() */ static int ipw_net_init(struct net_device *dev) { + int i, rc = 0; struct ipw_priv *priv = libipw_priv(dev); + const struct libipw_geo *geo = libipw_get_geo(priv->ieee); + struct wireless_dev *wdev = &priv->ieee->wdev; mutex_lock(&priv->mutex); if (ipw_up(priv)) { - mutex_unlock(&priv->mutex); - return -EIO; + rc = -EIO; + goto out; } + memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN); + + /* fill-out priv->ieee->bg_band */ + if (geo->bg_channels) { + struct ieee80211_supported_band *bg_band = &priv->ieee->bg_band; + + bg_band->band = IEEE80211_BAND_2GHZ; + bg_band->n_channels = geo->bg_channels; + bg_band->channels = + kzalloc(geo->bg_channels * + sizeof(struct ieee80211_channel), GFP_KERNEL); + /* translate geo->bg to bg_band.channels */ + for (i = 0; i < geo->bg_channels; i++) { + bg_band->channels[i].band = IEEE80211_BAND_2GHZ; + bg_band->channels[i].center_freq = geo->bg[i].freq; + bg_band->channels[i].hw_value = geo->bg[i].channel; + bg_band->channels[i].max_power = geo->bg[i].max_power; + if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY) + bg_band->channels[i].flags |= + IEEE80211_CHAN_PASSIVE_SCAN; + if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS) + bg_band->channels[i].flags |= + IEEE80211_CHAN_NO_IBSS; + if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT) + bg_band->channels[i].flags |= + IEEE80211_CHAN_RADAR; + /* No equivalent for LIBIPW_CH_80211H_RULES, + LIBIPW_CH_UNIFORM_SPREADING, or + LIBIPW_CH_B_ONLY... */ + } + /* point at bitrate info */ + bg_band->bitrates = ipw2200_bg_rates; + bg_band->n_bitrates = ipw2200_num_bg_rates; + + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = bg_band; + } + + /* fill-out priv->ieee->a_band */ + if (geo->a_channels) { + struct ieee80211_supported_band *a_band = &priv->ieee->a_band; + + a_band->band = IEEE80211_BAND_5GHZ; + a_band->n_channels = geo->a_channels; + a_band->channels = + kzalloc(geo->a_channels * + sizeof(struct ieee80211_channel), GFP_KERNEL); + /* translate geo->bg to a_band.channels */ + for (i = 0; i < geo->a_channels; i++) { + a_band->channels[i].band = IEEE80211_BAND_2GHZ; + a_band->channels[i].center_freq = geo->a[i].freq; + a_band->channels[i].hw_value = geo->a[i].channel; + a_band->channels[i].max_power = geo->a[i].max_power; + if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY) + a_band->channels[i].flags |= + IEEE80211_CHAN_PASSIVE_SCAN; + if (geo->a[i].flags & LIBIPW_CH_NO_IBSS) + a_band->channels[i].flags |= + IEEE80211_CHAN_NO_IBSS; + if (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT) + a_band->channels[i].flags |= + IEEE80211_CHAN_RADAR; + /* No equivalent for LIBIPW_CH_80211H_RULES, + LIBIPW_CH_UNIFORM_SPREADING, or + LIBIPW_CH_B_ONLY... */ + } + /* point at bitrate info */ + a_band->bitrates = ipw2200_a_rates; + a_band->n_bitrates = ipw2200_num_a_rates; + + wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = a_band; + } + + set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev); + + /* With that information in place, we can now register the wiphy... */ + if (wiphy_register(wdev->wiphy)) { + rc = -EIO; + goto out; + } + +out: mutex_unlock(&priv->mutex); - return 0; + return rc; } /* PCI driver stuff */ @@ -11540,7 +11625,7 @@ static int ipw_prom_alloc(struct ipw_priv *priv) if (priv->prom_net_dev) return -EPERM; - priv->prom_net_dev = alloc_ieee80211(sizeof(struct ipw_prom_priv)); + priv->prom_net_dev = alloc_ieee80211(sizeof(struct ipw_prom_priv), 1); if (priv->prom_net_dev == NULL) return -ENOMEM; @@ -11559,7 +11644,7 @@ static int ipw_prom_alloc(struct ipw_priv *priv) rc = register_netdev(priv->prom_net_dev); if (rc) { - free_ieee80211(priv->prom_net_dev); + free_ieee80211(priv->prom_net_dev, 1); priv->prom_net_dev = NULL; return rc; } @@ -11573,7 +11658,7 @@ static void ipw_prom_free(struct ipw_priv *priv) return; unregister_netdev(priv->prom_net_dev); - free_ieee80211(priv->prom_net_dev); + free_ieee80211(priv->prom_net_dev, 1); priv->prom_net_dev = NULL; } @@ -11601,7 +11686,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, struct ipw_priv *priv; int i; - net_dev = alloc_ieee80211(sizeof(struct ipw_priv)); + net_dev = alloc_ieee80211(sizeof(struct ipw_priv), 0); if (net_dev == NULL) { err = -ENOMEM; goto out; @@ -11749,7 +11834,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); out_free_ieee80211: - free_ieee80211(priv->net_dev); + free_ieee80211(priv->net_dev, 0); out: return err; } @@ -11816,7 +11901,7 @@ static void __devexit ipw_pci_remove(struct pci_dev *pdev) pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); - free_ieee80211(priv->net_dev); + free_ieee80211(priv->net_dev, 0); free_firmware(); } diff --git a/drivers/net/wireless/ipw2x00/libipw.h b/drivers/net/wireless/ipw2x00/libipw.h index cefb94262cc..8f91d3427ce 100644 --- a/drivers/net/wireless/ipw2x00/libipw.h +++ b/drivers/net/wireless/ipw2x00/libipw.h @@ -31,6 +31,7 @@ #include #include +#include #define LIBIPW_VERSION "git-1.1.13" @@ -783,12 +784,15 @@ struct libipw_geo { struct libipw_device { struct net_device *dev; + struct wireless_dev wdev; struct libipw_security sec; /* Bookkeeping structures */ struct libipw_stats ieee_stats; struct libipw_geo geo; + struct ieee80211_supported_band bg_band; + struct ieee80211_supported_band a_band; /* Probe / Beacon management */ struct list_head network_free_list; @@ -1014,8 +1018,8 @@ static inline int libipw_is_cck_rate(u8 rate) } /* ieee80211.c */ -extern void free_ieee80211(struct net_device *dev); -extern struct net_device *alloc_ieee80211(int sizeof_priv); +extern void free_ieee80211(struct net_device *dev, int monitor); +extern struct net_device *alloc_ieee80211(int sizeof_priv, int monitor); extern int libipw_change_mtu(struct net_device *dev, int new_mtu); extern void libipw_networks_age(struct libipw_device *ieee, diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c index eb2b60834c1..a0e9f6aed7d 100644 --- a/drivers/net/wireless/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/ipw2x00/libipw_module.c @@ -62,6 +62,9 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); +struct cfg80211_ops libipw_config_ops = { }; +void *libipw_wiphy_privid = &libipw_wiphy_privid; + static int libipw_networks_allocate(struct libipw_device *ieee) { if (ieee->networks) @@ -140,7 +143,7 @@ int libipw_change_mtu(struct net_device *dev, int new_mtu) } EXPORT_SYMBOL(libipw_change_mtu); -struct net_device *alloc_ieee80211(int sizeof_priv) +struct net_device *alloc_ieee80211(int sizeof_priv, int monitor) { struct libipw_device *ieee; struct net_device *dev; @@ -157,10 +160,31 @@ struct net_device *alloc_ieee80211(int sizeof_priv) ieee->dev = dev; + if (!monitor) { + ieee->wdev.wiphy = wiphy_new(&libipw_config_ops, 0); + if (!ieee->wdev.wiphy) { + LIBIPW_ERROR("Unable to allocate wiphy.\n"); + goto failed_free_netdev; + } + + ieee->dev->ieee80211_ptr = &ieee->wdev; + ieee->wdev.iftype = NL80211_IFTYPE_STATION; + + /* Fill-out wiphy structure bits we know... Not enough info + here to call set_wiphy_dev or set MAC address or channel info + -- have to do that in ->ndo_init... */ + ieee->wdev.wiphy->privid = libipw_wiphy_privid; + + ieee->wdev.wiphy->max_scan_ssids = 1; + ieee->wdev.wiphy->max_scan_ie_len = 0; + ieee->wdev.wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) + | BIT(NL80211_IFTYPE_ADHOC); + } + err = libipw_networks_allocate(ieee); if (err) { LIBIPW_ERROR("Unable to allocate beacon storage: %d\n", err); - goto failed_free_netdev; + goto failed_free_wiphy; } libipw_networks_initialize(ieee); @@ -193,19 +217,31 @@ struct net_device *alloc_ieee80211(int sizeof_priv) return dev; +failed_free_wiphy: + if (!monitor) + wiphy_free(ieee->wdev.wiphy); failed_free_netdev: free_netdev(dev); failed: return NULL; } -void free_ieee80211(struct net_device *dev) +void free_ieee80211(struct net_device *dev, int monitor) { struct libipw_device *ieee = netdev_priv(dev); lib80211_crypt_info_free(&ieee->crypt_info); libipw_networks_free(ieee); + + /* free cfg80211 resources */ + if (!monitor) { + wiphy_unregister(ieee->wdev.wiphy); + kfree(ieee->a_band.channels); + kfree(ieee->bg_band.channels); + wiphy_free(ieee->wdev.wiphy); + } + free_netdev(dev); } -- cgit v1.2.3-18-g5258 From a13883b0bfcc435e4b7fbbde6334339aac8b1dc4 Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 26 Aug 2009 08:39:40 +0530 Subject: ath9k: Reduce the frequency of PA offset calibration PA calibration need not be done if the offset is not varying. The current logic does PA calibration even if the offset is the same. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/calib.c | 25 +++++++++++++++++++++---- drivers/net/wireless/ath/ath9k/calib.h | 7 +++++++ drivers/net/wireless/ath/ath9k/hw.h | 1 + 3 files changed, 29 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 20f74b5b570..47a024da29c 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -861,7 +861,7 @@ static void ath9k_hw_9271_pa_cal(struct ath_hw *ah) REG_WRITE(ah, regList[i][0], regList[i][1]); } -static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah) +static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset) { u32 regVal; @@ -877,6 +877,8 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah) { 0x7838, 0 }, }; + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "Running PA Calibration\n"); + if (AR_SREV_9285_11(ah)) { REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); udelay(10); @@ -936,6 +938,17 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah) offs_6_1 = offset>>1; offs_0 = offset & 1; + if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) { + if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT) + ah->pacal_info.max_skipcount = + 2 * ah->pacal_info.max_skipcount; + ah->pacal_info.skipcount = ah->pacal_info.max_skipcount; + } else { + ah->pacal_info.max_skipcount = 1; + ah->pacal_info.skipcount = 0; + ah->pacal_info.prev_offset = offset; + } + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1); REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0); @@ -982,8 +995,12 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, /* Do periodic PAOffset Cal */ if (AR_SREV_9271(ah)) ath9k_hw_9271_pa_cal(ah); - else if (AR_SREV_9285_11_OR_LATER(ah)) - ath9k_hw_9285_pa_cal(ah); + else if (AR_SREV_9285_11_OR_LATER(ah)) { + if (!ah->pacal_info.skipcount) + ath9k_hw_9285_pa_cal(ah, false); + else + ah->pacal_info.skipcount--; + } if (OLC_FOR_AR9280_20_LATER || OLC_FOR_AR9287_10_LATER) ath9k_olc_temp_compensation(ah); @@ -1081,7 +1098,7 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) /* Do PA Calibration */ if (AR_SREV_9285_11_OR_LATER(ah)) - ath9k_hw_9285_pa_cal(ah); + ath9k_hw_9285_pa_cal(ah, true); /* Do NF Calibration after DC offset and other calibrations */ REG_WRITE(ah, AR_PHY_AGC_CONTROL, diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index 547e697b905..019bcbba40e 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -110,6 +110,13 @@ struct ath9k_nfcal_hist { u8 invalidNFcount; }; +#define MAX_PACAL_SKIPCOUNT 8 +struct ath9k_pacal_info{ + int32_t prev_offset; /* Previous value of PA offset value */ + int8_t max_skipcount; /* Max No. of times PACAL can be skipped */ + int8_t skipcount; /* No. of times the PACAL to be skipped */ +}; + bool ath9k_hw_reset_calvalid(struct ath_hw *ah); void ath9k_hw_start_nfcal(struct ath_hw *ah); void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 24b30631d93..b24150a1b4a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -424,6 +424,7 @@ struct ath_hw { enum ath9k_power_mode power_mode; struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; + struct ath9k_pacal_info pacal_info; struct ar5416Stats stats; struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES]; -- cgit v1.2.3-18-g5258 From 0abb0968795b55ecb102bf635a94a087bbb5aff5 Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 26 Aug 2009 08:39:50 +0530 Subject: ath9k: Fix bugs in programming registers during PA CAL * First PA driver (PDPADRV1) was not powered down properly. * Compensation capacitor for dynamic PA was programmed incorrectly. Also, remove a stray REG_READ. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/calib.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 47a024da29c..f9de16c3131 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -901,13 +901,13 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset) REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 1); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0); REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP); - REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 7); + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf); REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); udelay(30); @@ -919,7 +919,6 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset) regVal |= (1 << (19 + i)); REG_WRITE(ah, 0x7834, regVal); udelay(1); - regVal = REG_READ(ah, 0x7834); regVal &= (~(0x1 << (19 + i))); reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9); regVal |= (reg_field << (19 + i)); -- cgit v1.2.3-18-g5258 From 20caf0dd4131d030c2a4099e2c2766ec7a5e83ea Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 26 Aug 2009 08:39:52 +0530 Subject: ath9k: Handle PA cal usage properly PA Calibration is not needed for high power solutions. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/calib.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index f9de16c3131..3234995e888 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -879,6 +879,11 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset) DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "Running PA Calibration\n"); + /* PA CAL is not needed for high power solution */ + if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == + AR5416_EEP_TXGAIN_HIGH_POWER) + return; + if (AR_SREV_9285_11(ah)) { REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); udelay(10); -- cgit v1.2.3-18-g5258 From b264c673a03329b5e5bab79b705b5bb5ab1fe965 Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 26 Aug 2009 08:39:55 +0530 Subject: ath9k: Update INITVALs for AR9285 Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/initvals.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h index 27a86bb7c4c..8622265a030 100644 --- a/drivers/net/wireless/ath/ath9k/initvals.h +++ b/drivers/net/wireless/ath/ath9k/initvals.h @@ -4133,7 +4133,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = { { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 }, { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, - { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e }, { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, @@ -4158,7 +4158,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = { { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, - { 0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329 }, + { 0x000099c8, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f }, { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, @@ -4601,7 +4601,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { { 0x00008258, 0x00000000 }, { 0x0000825c, 0x400000ff }, { 0x00008260, 0x00080922 }, - { 0x00008264, 0xa8a00010 }, + { 0x00008264, 0x88a00010 }, { 0x00008270, 0x00000000 }, { 0x00008274, 0x40000000 }, { 0x00008278, 0x003e4180 }, @@ -4650,7 +4650,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { { 0x00009954, 0x5f3ca3de }, { 0x00009958, 0x2108ecff }, { 0x00009968, 0x000003ce }, - { 0x00009970, 0x192bb515 }, + { 0x00009970, 0x192bb514 }, { 0x00009974, 0x00000000 }, { 0x00009978, 0x00000001 }, { 0x0000997c, 0x00000000 }, @@ -4728,7 +4728,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { { 0x00007800, 0x00140000 }, { 0x00007804, 0x0e4548d8 }, { 0x00007808, 0x54214514 }, - { 0x0000780c, 0x02025820 }, + { 0x0000780c, 0x02025830 }, { 0x00007810, 0x71c0d388 }, { 0x00007814, 0x924934a8 }, { 0x0000781c, 0x00000000 }, -- cgit v1.2.3-18-g5258 From 7cf4a2e778ab18c66cd8dd4785aceb2800d49f79 Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 26 Aug 2009 11:11:57 +0530 Subject: ath9k: Wrap DMA dump function with PS wakeup/restore When dumping register contents, HW has to be awake. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 9e369208f7d..2be4c225204 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -93,6 +93,8 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, int i, qcuOffset = 0, dcuOffset = 0; u32 *qcuBase = &val[0], *dcuBase = &val[4]; + ath9k_ps_wakeup(sc); + REG_WRITE(ah, AR_MACMISC, ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | (AR_MACMISC_MISC_OBS_BUS_1 << @@ -159,6 +161,8 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, len += snprintf(buf + len, sizeof(buf) - len, "AR_CR: 0x%x \n", REG_READ(ah, AR_CR)); + ath9k_ps_restore(sc); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); } -- cgit v1.2.3-18-g5258 From 4a7f13eef508012bd1b0ffbb24b807e3494f31cd Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Wed, 26 Aug 2009 15:53:02 +0300 Subject: rndis_wlan: set cipher suites for cfg80211 rndis_wlan does not set cipher suites list for cfg80211 which causes wext-compat-range to report rndis_wlan not supporting WPA. Patch adds cipher suites list and fixes NetworkManager not being able to connect to WPA encrypted APs. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index c5b921bf5a9..f181b00f253 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -413,6 +413,13 @@ static const struct ieee80211_rate rndis_rates[] = { { .bitrate = 540 } }; +static const u32 rndis_cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, +}; + struct rndis_wlan_encr_key { int len; int cipher; @@ -441,6 +448,7 @@ struct rndis_wlan_private { struct ieee80211_supported_band band; struct ieee80211_channel channels[ARRAY_SIZE(rndis_channels)]; struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)]; + u32 cipher_suites[ARRAY_SIZE(rndis_cipher_suites)]; struct iw_statistics iwstats; struct iw_statistics privstats; @@ -2892,7 +2900,7 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) | BIT(NL80211_IFTYPE_ADHOC); wiphy->max_scan_ssids = 1; - /* TODO: fill-out band information based on priv->caps */ + /* TODO: fill-out band/encr information based on priv->caps */ rndis_wlan_get_caps(usbdev); memcpy(priv->channels, rndis_channels, sizeof(rndis_channels)); @@ -2904,6 +2912,11 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; + memcpy(priv->cipher_suites, rndis_cipher_suites, + sizeof(rndis_cipher_suites)); + wiphy->cipher_suites = priv->cipher_suites; + wiphy->n_cipher_suites = ARRAY_SIZE(rndis_cipher_suites); + set_wiphy_dev(wiphy, &usbdev->udev->dev); if (wiphy_register(wiphy)) { -- cgit v1.2.3-18-g5258 From f985ad12b595094839fddaf757fcf5d853ed3d7f Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 26 Aug 2009 21:08:43 +0530 Subject: ath9k: Split ath9k_hw_btcoex_enable() into two logical pieces This function currently does initialization + enable the btcoex support. Split it into two logical functions which does the above operations separately. Btcoex initialization is done during attach time and enabling this feature is done in start(). Also, add code to disable btcoex support in stop(). Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/hw.c | 17 ++++++++++++++++- drivers/net/wireless/ath/ath9k/hw.h | 2 ++ drivers/net/wireless/ath/ath9k/main.c | 11 +++++++++-- 4 files changed, 28 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 7705da1103f..08688008336 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -521,6 +521,7 @@ struct ath_led { #define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17) #define SC_OP_WAIT_FOR_TX_ACK BIT(18) #define SC_OP_BEACON_SYNC BIT(19) +#define SC_OP_BTCOEX_ENABLED BIT(20) struct ath_bus_ops { void (*read_cachesize)(struct ath_softc *sc, int *csz); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 4f3d5ea3481..d81e826b682 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -4073,7 +4073,7 @@ void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode) /* Bluetooth Coexistence */ /***************************/ -void ath9k_hw_btcoex_enable(struct ath_hw *ah) +void ath9k_hw_btcoex_init(struct ath_hw *ah) { /* connect bt_active to baseband */ REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, @@ -4090,8 +4090,23 @@ void ath9k_hw_btcoex_enable(struct ath_hw *ah) /* Configure the desired gpio port for input */ ath9k_hw_cfg_gpio_input(ah, ah->btactive_gpio); +} +void ath9k_hw_btcoex_enable(struct ath_hw *ah) +{ /* Configure the desired GPIO port for TX_FRAME output */ ath9k_hw_cfg_output(ah, ah->wlanactive_gpio, AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); + + ah->ah_sc->sc_flags |= SC_OP_BTCOEX_ENABLED; +} + +void ath9k_hw_btcoex_disable(struct ath_hw *ah) +{ + ath9k_hw_set_gpio(ah, ah->wlanactive_gpio, 0); + + ath9k_hw_cfg_output(ah, ah->wlanactive_gpio, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + + ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED; } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index b24150a1b4a..e634cb448ca 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -614,6 +614,8 @@ bool ath9k_hw_intrpend(struct ath_hw *ah); bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked); enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints); +void ath9k_hw_btcoex_init(struct ath_hw *ah); void ath9k_hw_btcoex_enable(struct ath_hw *ah); +void ath9k_hw_btcoex_disable(struct ath_hw *ah); #endif diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index eb8d673cde5..878d3be7c71 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1509,8 +1509,8 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc) ARRAY_SIZE(ath9k_5ghz_chantable); } - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX) - ath9k_hw_btcoex_enable(sc->sc_ah); + if (ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX) + ath9k_hw_btcoex_init(ah); return 0; bad2: @@ -1992,6 +1992,10 @@ static int ath9k_start(struct ieee80211_hw *hw) ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); + if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX) && + !(sc->sc_flags & SC_OP_BTCOEX_ENABLED)) + ath9k_hw_btcoex_enable(sc->sc_ah); + mutex_unlock: mutex_unlock(&sc->mutex); @@ -2138,6 +2142,9 @@ static void ath9k_stop(struct ieee80211_hw *hw) wiphy_rfkill_stop_polling(sc->hw->wiphy); + if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) + ath9k_hw_btcoex_disable(sc->sc_ah); + /* disable HAL and put h/w to sleep */ ath9k_hw_disable(sc->sc_ah); ath9k_hw_configpcipowersave(sc->sc_ah, 1); -- cgit v1.2.3-18-g5258 From 17d50d1df48631ae868958032edada7aa920636b Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 26 Aug 2009 21:08:44 +0530 Subject: ath9k: Move btcoex stuff from hw.[ch] to new btcoex.[ch] Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/Makefile | 3 +- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/btcoex.c | 55 +++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/btcoex.h | 24 ++++++++++++++ drivers/net/wireless/ath/ath9k/hw.c | 42 ------------------------- drivers/net/wireless/ath/ath9k/hw.h | 4 --- 6 files changed, 82 insertions(+), 47 deletions(-) create mode 100644 drivers/net/wireless/ath/ath9k/btcoex.c create mode 100644 drivers/net/wireless/ath/ath9k/btcoex.h (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 28443e05ec1..ff2c9a26c10 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -12,7 +12,8 @@ ath9k-y += hw.o \ recv.o \ xmit.o \ virtual.o \ - rc.o + rc.o \ + btcoex.o ath9k-$(CONFIG_PCI) += pci.o ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 08688008336..1a8d6799766 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -26,6 +26,7 @@ #include "rc.h" #include "debug.h" #include "../ath.h" +#include "btcoex.h" struct ath_node; diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c new file mode 100644 index 00000000000..abaf92d8074 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +void ath9k_hw_btcoex_init(struct ath_hw *ah) +{ + /* connect bt_active to baseband */ + REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, + (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | + AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF)); + + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, + AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB); + + /* Set input mux for bt_active to gpio pin */ + REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, + AR_GPIO_INPUT_MUX1_BT_ACTIVE, + ah->btactive_gpio); + + /* Configure the desired gpio port for input */ + ath9k_hw_cfg_gpio_input(ah, ah->btactive_gpio); +} + +void ath9k_hw_btcoex_enable(struct ath_hw *ah) +{ + /* Configure the desired GPIO port for TX_FRAME output */ + ath9k_hw_cfg_output(ah, ah->wlanactive_gpio, + AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); + + ah->ah_sc->sc_flags |= SC_OP_BTCOEX_ENABLED; +} + +void ath9k_hw_btcoex_disable(struct ath_hw *ah) +{ + ath9k_hw_set_gpio(ah, ah->wlanactive_gpio, 0); + + ath9k_hw_cfg_output(ah, ah->wlanactive_gpio, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + + ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED; +} diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h new file mode 100644 index 00000000000..99542808b8e --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef BTCOEX_H +#define BTCOEX_H + +void ath9k_hw_btcoex_init(struct ath_hw *ah); +void ath9k_hw_btcoex_enable(struct ath_hw *ah); +void ath9k_hw_btcoex_disable(struct ath_hw *ah); + +#endif diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index d81e826b682..c3ecc7ee2ac 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -4068,45 +4068,3 @@ void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode) REG_WRITE(ah, AR_2040_MODE, macmode); } - -/***************************/ -/* Bluetooth Coexistence */ -/***************************/ - -void ath9k_hw_btcoex_init(struct ath_hw *ah) -{ - /* connect bt_active to baseband */ - REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, - (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | - AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF)); - - REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, - AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB); - - /* Set input mux for bt_active to gpio pin */ - REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, - AR_GPIO_INPUT_MUX1_BT_ACTIVE, - ah->btactive_gpio); - - /* Configure the desired gpio port for input */ - ath9k_hw_cfg_gpio_input(ah, ah->btactive_gpio); -} - -void ath9k_hw_btcoex_enable(struct ath_hw *ah) -{ - /* Configure the desired GPIO port for TX_FRAME output */ - ath9k_hw_cfg_output(ah, ah->wlanactive_gpio, - AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); - - ah->ah_sc->sc_flags |= SC_OP_BTCOEX_ENABLED; -} - -void ath9k_hw_btcoex_disable(struct ath_hw *ah) -{ - ath9k_hw_set_gpio(ah, ah->wlanactive_gpio, 0); - - ath9k_hw_cfg_output(ah, ah->wlanactive_gpio, - AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - - ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED; -} diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index e634cb448ca..32f7c4b86ed 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -614,8 +614,4 @@ bool ath9k_hw_intrpend(struct ath_hw *ah); bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked); enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints); -void ath9k_hw_btcoex_init(struct ath_hw *ah); -void ath9k_hw_btcoex_enable(struct ath_hw *ah); -void ath9k_hw_btcoex_disable(struct ath_hw *ah); - #endif -- cgit v1.2.3-18-g5258 From 42cc41edf24b75fc6c37c99aed6e85455687e080 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 26 Aug 2009 21:08:45 +0530 Subject: ath9k: Configure btcoex register during every reset Make sure btcoex register configured with appropriate values after it is initialized with the default values from initvals.h during reset. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index c3ecc7ee2ac..d7e03f9788c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2555,6 +2555,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, #endif } + if (ah->ah_sc->sc_flags & SC_OP_BTCOEX_ENABLED) + ath9k_hw_btcoex_enable(ah); + return 0; } -- cgit v1.2.3-18-g5258 From f14462c6661c6b9e91d436f7ab66b35ed52ea703 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 26 Aug 2009 21:08:46 +0530 Subject: ath9k: Move btcoex related data to a separate struct Also define macros for wlanactive and btactive (5 & 6) gpios. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/btcoex.c | 16 +++++++++++----- drivers/net/wireless/ath/ath9k/btcoex.h | 8 ++++++++ drivers/net/wireless/ath/ath9k/hw.c | 4 ++-- drivers/net/wireless/ath/ath9k/hw.h | 2 -- 5 files changed, 22 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 1a8d6799766..83f2c8fa887 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -611,6 +611,7 @@ struct ath_softc { struct ath_bus_ops *bus_ops; struct ath_beacon_config cur_beacon_conf; struct delayed_work tx_complete_work; + struct ath_btcoex_info btcoex_info; }; struct ath_wiphy { diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index abaf92d8074..9f19cd1c1be 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -18,6 +18,8 @@ void ath9k_hw_btcoex_init(struct ath_hw *ah) { + struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info; + /* connect bt_active to baseband */ REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | @@ -29,16 +31,18 @@ void ath9k_hw_btcoex_init(struct ath_hw *ah) /* Set input mux for bt_active to gpio pin */ REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, AR_GPIO_INPUT_MUX1_BT_ACTIVE, - ah->btactive_gpio); + btcoex_info->btactive_gpio); /* Configure the desired gpio port for input */ - ath9k_hw_cfg_gpio_input(ah, ah->btactive_gpio); + ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); } void ath9k_hw_btcoex_enable(struct ath_hw *ah) { + struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info; + /* Configure the desired GPIO port for TX_FRAME output */ - ath9k_hw_cfg_output(ah, ah->wlanactive_gpio, + ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); ah->ah_sc->sc_flags |= SC_OP_BTCOEX_ENABLED; @@ -46,9 +50,11 @@ void ath9k_hw_btcoex_enable(struct ath_hw *ah) void ath9k_hw_btcoex_disable(struct ath_hw *ah) { - ath9k_hw_set_gpio(ah, ah->wlanactive_gpio, 0); + struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info; + + ath9k_hw_set_gpio(ah, btcoex_info->wlanactive_gpio, 0); - ath9k_hw_cfg_output(ah, ah->wlanactive_gpio, + ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED; diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 99542808b8e..c80492bac76 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -17,6 +17,14 @@ #ifndef BTCOEX_H #define BTCOEX_H +#define ATH_WLANACTIVE_GPIO 5 +#define ATH_BTACTIVE_GPIO 6 + +struct ath_btcoex_info { + u8 wlanactive_gpio; + u8 btactive_gpio; +}; + void ath9k_hw_btcoex_init(struct ath_hw *ah); void ath9k_hw_btcoex_enable(struct ath_hw *ah); void ath9k_hw_btcoex_disable(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index d7e03f9788c..3bb6abd7b2b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3666,8 +3666,8 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9280_10_OR_LATER(ah) && btcoex_enable) { pCap->hw_caps |= ATH9K_HW_CAP_BT_COEX; - ah->btactive_gpio = 6; - ah->wlanactive_gpio = 5; + ah->ah_sc->btcoex_info.btactive_gpio = ATH_BTACTIVE_GPIO; + ah->ah_sc->btcoex_info.wlanactive_gpio = ATH_WLANACTIVE_GPIO; } } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 32f7c4b86ed..259936c9046 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -414,8 +414,6 @@ struct ath_hw { u16 rfsilent; u32 rfkill_gpio; u32 rfkill_polarity; - u32 btactive_gpio; - u32 wlanactive_gpio; u32 ah_flags; bool htc_reset_init; -- cgit v1.2.3-18-g5258 From 22f25d0d5e146112d4ec464564ebb49a5b8a547b Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 26 Aug 2009 21:08:47 +0530 Subject: ath9k: Determine btcoex scheme type based on chip version Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/btcoex.h | 7 +++++++ drivers/net/wireless/ath/ath9k/hw.c | 12 ++++++++++-- drivers/net/wireless/ath/ath9k/main.c | 4 +++- 3 files changed, 20 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index c80492bac76..cdfa80d0eb4 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -20,7 +20,14 @@ #define ATH_WLANACTIVE_GPIO 5 #define ATH_BTACTIVE_GPIO 6 +enum ath_btcoex_scheme { + ATH_BTCOEX_CFG_NONE, + ATH_BTCOEX_CFG_2WIRE, + ATH_BTCOEX_CFG_3WIRE, +}; + struct ath_btcoex_info { + enum ath_btcoex_scheme btcoex_scheme; u8 wlanactive_gpio; u8 btactive_gpio; }; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 3bb6abd7b2b..7b4bc8b74bb 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3489,6 +3489,7 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) { struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); + struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info; u16 capField = 0, eeval; @@ -3666,8 +3667,15 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9280_10_OR_LATER(ah) && btcoex_enable) { pCap->hw_caps |= ATH9K_HW_CAP_BT_COEX; - ah->ah_sc->btcoex_info.btactive_gpio = ATH_BTACTIVE_GPIO; - ah->ah_sc->btcoex_info.wlanactive_gpio = ATH_WLANACTIVE_GPIO; + btcoex_info->btactive_gpio = ATH_BTACTIVE_GPIO; + btcoex_info->wlanactive_gpio = ATH_WLANACTIVE_GPIO; + + if (AR_SREV_9285(ah)) + btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_3WIRE; + else + btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_2WIRE; + } else { + btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_NONE; } } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 878d3be7c71..8a2f000274b 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1509,7 +1509,8 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc) ARRAY_SIZE(ath9k_5ghz_chantable); } - if (ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX) + if ((ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX) && + (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_2WIRE)) ath9k_hw_btcoex_init(ah); return 0; @@ -1993,6 +1994,7 @@ static int ath9k_start(struct ieee80211_hw *hw) ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX) && + (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) && !(sc->sc_flags & SC_OP_BTCOEX_ENABLED)) ath9k_hw_btcoex_enable(sc->sc_ah); -- cgit v1.2.3-18-g5258 From 81fa16fbe06cb3a4d29cc5a6f925132554521c72 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 26 Aug 2009 21:08:48 +0530 Subject: ath9k: Remove hw capability bit meant for btcoex We don't need a hw cap bit for btcoex anymore as btcoex scheme type is enough to do this. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 1 - drivers/net/wireless/ath/ath9k/hw.h | 1 - drivers/net/wireless/ath/ath9k/main.c | 8 +++----- 3 files changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 7b4bc8b74bb..c80be8c78e8 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3666,7 +3666,6 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ); if (AR_SREV_9280_10_OR_LATER(ah) && btcoex_enable) { - pCap->hw_caps |= ATH9K_HW_CAP_BT_COEX; btcoex_info->btactive_gpio = ATH_BTACTIVE_GPIO; btcoex_info->wlanactive_gpio = ATH_WLANACTIVE_GPIO; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 259936c9046..de10de8370d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -151,7 +151,6 @@ enum ath9k_hw_caps { ATH9K_HW_CAP_ENHANCEDPM = BIT(14), ATH9K_HW_CAP_AUTOSLEEP = BIT(15), ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(16), - ATH9K_HW_CAP_BT_COEX = BIT(17) }; enum ath9k_capability_type { diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 8a2f000274b..215c67251f7 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -440,7 +440,7 @@ static void ath_start_ani(struct ath_softc *sc) void ath_update_chainmask(struct ath_softc *sc, int is_ht) { if ((sc->sc_flags & SC_OP_SCANNING) || is_ht || - (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)) { + (sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE)) { sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask; sc->rx_chainmask = sc->sc_ah->caps.rx_chainmask; } else { @@ -1509,8 +1509,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc) ARRAY_SIZE(ath9k_5ghz_chantable); } - if ((ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX) && - (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_2WIRE)) + if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) ath9k_hw_btcoex_init(ah); return 0; @@ -1993,8 +1992,7 @@ static int ath9k_start(struct ieee80211_hw *hw) ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); - if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX) && - (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) && + if ((sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) && !(sc->sc_flags & SC_OP_BTCOEX_ENABLED)) ath9k_hw_btcoex_enable(sc->sc_ah); -- cgit v1.2.3-18-g5258 From ff155a45cea56ad7a90c3f5192db59a4c7812fde Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 26 Aug 2009 21:08:49 +0530 Subject: ath9k: Add infrastructure for generic hw timers Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.h | 1 + drivers/net/wireless/ath/ath9k/hw.c | 212 +++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/hw.h | 52 ++++++++ drivers/net/wireless/ath/ath9k/reg.h | 15 ++- 4 files changed, 278 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 5e56b79d0cb..ea0dd1ec15c 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -30,6 +30,7 @@ enum ATH_DEBUG { ATH_DBG_CONFIG = 0x00000200, ATH_DBG_FATAL = 0x00000400, ATH_DBG_PS = 0x00000800, + ATH_DBG_HWTIMER = 0x00001000, ATH_DBG_ANY = 0xffffffff }; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index c80be8c78e8..3afd7a9fc8a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3215,6 +3215,23 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) if (AR_SREV_9100(ah)) return true; + if (isr & AR_ISR_GENTMR) { + u32 s5_s; + + s5_s = REG_READ(ah, AR_ISR_S5_S); + if (isr & AR_ISR_GENTMR) { + ah->intr_gen_timer_trigger = + MS(s5_s, AR_ISR_S5_GENTIMER_TRIG); + + ah->intr_gen_timer_thresh = + MS(s5_s, AR_ISR_S5_GENTIMER_THRESH); + + if (ah->intr_gen_timer_trigger) + *masked |= ATH9K_INT_GENTIMER; + + } + } + if (sync_cause) { fatal_int = (sync_cause & @@ -4078,3 +4095,198 @@ void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode) REG_WRITE(ah, AR_2040_MODE, macmode); } + +/* HW Generic timers configuration */ + +static const struct ath_gen_timer_configuration gen_tmr_configuration[] = +{ + {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080}, + {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080}, + {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080}, + {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080}, + {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080}, + {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080}, + {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080}, + {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080}, + {AR_NEXT_NDP2_TIMER, AR_NDP2_PERIOD, AR_NDP2_TIMER_MODE, 0x0001}, + {AR_NEXT_NDP2_TIMER + 1*4, AR_NDP2_PERIOD + 1*4, + AR_NDP2_TIMER_MODE, 0x0002}, + {AR_NEXT_NDP2_TIMER + 2*4, AR_NDP2_PERIOD + 2*4, + AR_NDP2_TIMER_MODE, 0x0004}, + {AR_NEXT_NDP2_TIMER + 3*4, AR_NDP2_PERIOD + 3*4, + AR_NDP2_TIMER_MODE, 0x0008}, + {AR_NEXT_NDP2_TIMER + 4*4, AR_NDP2_PERIOD + 4*4, + AR_NDP2_TIMER_MODE, 0x0010}, + {AR_NEXT_NDP2_TIMER + 5*4, AR_NDP2_PERIOD + 5*4, + AR_NDP2_TIMER_MODE, 0x0020}, + {AR_NEXT_NDP2_TIMER + 6*4, AR_NDP2_PERIOD + 6*4, + AR_NDP2_TIMER_MODE, 0x0040}, + {AR_NEXT_NDP2_TIMER + 7*4, AR_NDP2_PERIOD + 7*4, + AR_NDP2_TIMER_MODE, 0x0080} +}; + +/* HW generic timer primitives */ + +/* compute and clear index of rightmost 1 */ +static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask) +{ + u32 b; + + b = *mask; + b &= (0-b); + *mask &= ~b; + b *= debruijn32; + b >>= 27; + + return timer_table->gen_timer_index[b]; +} + +static u32 ath9k_hw_gettsf32(struct ath_hw *ah) +{ + return REG_READ(ah, AR_TSF_L32); +} + +struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, + void (*trigger)(void *), + void (*overflow)(void *), + void *arg, + u8 timer_index) +{ + struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; + struct ath_gen_timer *timer; + + timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL); + + if (timer == NULL) { + printk(KERN_DEBUG "Failed to allocate memory" + "for hw timer[%d]\n", timer_index); + return NULL; + } + + /* allocate a hardware generic timer slot */ + timer_table->timers[timer_index] = timer; + timer->index = timer_index; + timer->trigger = trigger; + timer->overflow = overflow; + timer->arg = arg; + + return timer; +} + +void ath_gen_timer_start(struct ath_hw *ah, + struct ath_gen_timer *timer, + u32 timer_next, u32 timer_period) +{ + struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; + u32 tsf; + + BUG_ON(!timer_period); + + set_bit(timer->index, &timer_table->timer_mask.timer_bits); + + tsf = ath9k_hw_gettsf32(ah); + + DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER, "curent tsf %x period %x" + "timer_next %x\n", tsf, timer_period, timer_next); + + /* + * Pull timer_next forward if the current TSF already passed it + * because of software latency + */ + if (timer_next < tsf) + timer_next = tsf + timer_period; + + /* + * Program generic timer registers + */ + REG_WRITE(ah, gen_tmr_configuration[timer->index].next_addr, + timer_next); + REG_WRITE(ah, gen_tmr_configuration[timer->index].period_addr, + timer_period); + REG_SET_BIT(ah, gen_tmr_configuration[timer->index].mode_addr, + gen_tmr_configuration[timer->index].mode_mask); + + /* Enable both trigger and thresh interrupt masks */ + REG_SET_BIT(ah, AR_IMR_S5, + (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) | + SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG))); + + if ((ah->ah_sc->imask & ATH9K_INT_GENTIMER) == 0) { + ath9k_hw_set_interrupts(ah, 0); + ah->ah_sc->imask |= ATH9K_INT_GENTIMER; + ath9k_hw_set_interrupts(ah, ah->ah_sc->imask); + } +} + +void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) +{ + struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; + + if ((timer->index < AR_FIRST_NDP_TIMER) || + (timer->index >= ATH_MAX_GEN_TIMER)) { + return; + } + + /* Clear generic timer enable bits. */ + REG_CLR_BIT(ah, gen_tmr_configuration[timer->index].mode_addr, + gen_tmr_configuration[timer->index].mode_mask); + + /* Disable both trigger and thresh interrupt masks */ + REG_CLR_BIT(ah, AR_IMR_S5, + (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) | + SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG))); + + clear_bit(timer->index, &timer_table->timer_mask.timer_bits); + + /* if no timer is enabled, turn off interrupt mask */ + if (timer_table->timer_mask.val == 0) { + ath9k_hw_set_interrupts(ah, 0); + ah->ah_sc->imask &= ~ATH9K_INT_GENTIMER; + ath9k_hw_set_interrupts(ah, ah->ah_sc->imask); + } +} + +void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer) +{ + struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; + + /* free the hardware generic timer slot */ + timer_table->timers[timer->index] = NULL; + kfree(timer); +} + +/* + * Generic Timer Interrupts handling + */ +void ath_gen_timer_isr(struct ath_hw *ah) +{ + struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; + struct ath_gen_timer *timer; + u32 trigger_mask, thresh_mask, index; + + /* get hardware generic timer interrupt status */ + trigger_mask = ah->intr_gen_timer_trigger; + thresh_mask = ah->intr_gen_timer_thresh; + trigger_mask &= timer_table->timer_mask.val; + thresh_mask &= timer_table->timer_mask.val; + + trigger_mask &= ~thresh_mask; + + while (thresh_mask) { + index = rightmost_index(timer_table, &thresh_mask); + timer = timer_table->timers[index]; + BUG_ON(!timer); + DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER, + "TSF overflow for Gen timer %d\n", index); + timer->overflow(timer->arg); + } + + while (trigger_mask) { + index = rightmost_index(timer_table, &trigger_mask); + timer = timer_table->timers[index]; + BUG_ON(!timer); + DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER, + "Gen timer[%d] trigger\n", index); + timer->trigger(timer->arg); + } +} diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index de10de8370d..052a9c4ebb9 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -237,6 +237,7 @@ enum ath9k_int { ATH9K_INT_GPIO = 0x01000000, ATH9K_INT_CABEND = 0x02000000, ATH9K_INT_TSFOOR = 0x04000000, + ATH9K_INT_GENTIMER = 0x08000000, ATH9K_INT_CST = 0x10000000, ATH9K_INT_GTT = 0x20000000, ATH9K_INT_FATAL = 0x40000000, @@ -390,6 +391,41 @@ struct ath9k_hw_version { u16 analog2GhzRev; }; +/* Generic TSF timer definitions */ + +#define ATH_MAX_GEN_TIMER 16 + +#define AR_GENTMR_BIT(_index) (1 << (_index)) + +/* + * Using de Bruijin sequence to to look up 1's index in a 32 bit number + * debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001 + */ +#define debruijn32 0x077CB531UL + +struct ath_gen_timer_configuration { + u32 next_addr; + u32 period_addr; + u32 mode_addr; + u32 mode_mask; +}; + +struct ath_gen_timer { + void (*trigger)(void *arg); + void (*overflow)(void *arg); + void *arg; + u8 index; +}; + +struct ath_gen_timer_table { + u32 gen_timer_index[32]; + struct ath_gen_timer *timers[ATH_MAX_GEN_TIMER]; + union { + unsigned long timer_bits; + u16 val; + } timer_mask; +}; + struct ath_hw { struct ath_softc *ah_sc; struct ath9k_hw_version hw_version; @@ -536,6 +572,10 @@ struct ath_hw { struct ar5416IniArray iniModesAdditional; struct ar5416IniArray iniModesRxGain; struct ar5416IniArray iniModesTxGain; + + u32 intr_gen_timer_trigger; + u32 intr_gen_timer_thresh; + struct ath_gen_timer_table hw_gen_timers; }; /* Initialization, Detach, Reset */ @@ -611,4 +651,16 @@ bool ath9k_hw_intrpend(struct ath_hw *ah); bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked); enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints); +/* Generic hw timer primitives */ +struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, + void (*trigger)(void *), + void (*overflow)(void *), + void *arg, + u8 timer_index); +void ath_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer, + u32 timer_next, u32 timer_period); +void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer); +void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer); +void ath_gen_timer_isr(struct ath_hw *hw); + #endif diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index c9e1ac92d0e..1d8e0a8b587 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -234,7 +234,15 @@ #define AR_IMR_S5 0x00b8 #define AR_IMR_S5_TIM_TIMER 0x00000010 #define AR_IMR_S5_DTIM_TIMER 0x00000020 - +#define AR_ISR_S5_GENTIMER_TRIG 0x0000FF80 +#define AR_ISR_S5_GENTIMER_TRIG_S 0 +#define AR_ISR_S5_GENTIMER_THRESH 0xFF800000 +#define AR_ISR_S5_GENTIMER_THRESH_S 16 +#define AR_ISR_S5_S 0x00d8 +#define AR_IMR_S5_GENTIMER_TRIG 0x0000FF80 +#define AR_IMR_S5_GENTIMER_TRIG_S 0 +#define AR_IMR_S5_GENTIMER_THRESH 0xFF800000 +#define AR_IMR_S5_GENTIMER_THRESH_S 16 #define AR_IMR 0x00a0 #define AR_IMR_RXOK 0x00000001 @@ -1516,7 +1524,10 @@ enum { #define AR_TXOP_8_11 0x81f8 #define AR_TXOP_12_15 0x81fc - +#define AR_NEXT_NDP2_TIMER 0x8180 +#define AR_FIRST_NDP_TIMER 7 +#define AR_NDP2_PERIOD 0x81a0 +#define AR_NDP2_TIMER_MODE 0x81c0 #define AR_NEXT_TBTT_TIMER 0x8200 #define AR_NEXT_DMA_BEACON_ALERT 0x8204 #define AR_NEXT_SWBA 0x8208 -- cgit v1.2.3-18-g5258 From 1773912bd25196c2a3ca6c174574561363f43b2b Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 26 Aug 2009 21:08:50 +0530 Subject: ath9k: Add Bluetooth Coexistence 3-wire support This patch adds 3-wire bluetooth coex support for AR9285. This support can be enabled through btcoex_enable modparam. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 + drivers/net/wireless/ath/ath9k/btcoex.c | 290 ++++++++++++++++++++++++++++++-- drivers/net/wireless/ath/ath9k/btcoex.h | 61 ++++++- drivers/net/wireless/ath/ath9k/debug.h | 1 + drivers/net/wireless/ath/ath9k/hw.c | 2 +- drivers/net/wireless/ath/ath9k/hw.h | 2 + drivers/net/wireless/ath/ath9k/main.c | 34 +++- drivers/net/wireless/ath/ath9k/reg.h | 49 ++++++ drivers/net/wireless/ath/ath9k/xmit.c | 9 +- 9 files changed, 423 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 83f2c8fa887..1c68a9da22d 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -523,6 +523,7 @@ struct ath_led { #define SC_OP_WAIT_FOR_TX_ACK BIT(18) #define SC_OP_BEACON_SYNC BIT(19) #define SC_OP_BTCOEX_ENABLED BIT(20) +#define SC_OP_BT_PRIORITY_DETECTED BIT(21) struct ath_bus_ops { void (*read_cachesize)(struct ath_softc *sc, int *csz); @@ -708,4 +709,5 @@ bool ath9k_all_wiphys_idle(struct ath_softc *sc); void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val); unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset); +int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype); #endif /* ATH9K_H */ diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 9f19cd1c1be..8fb35674882 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -16,34 +16,251 @@ #include "ath9k.h" -void ath9k_hw_btcoex_init(struct ath_hw *ah) +static const struct ath_btcoex_config ath_bt_config = { 0, true, true, + ATH_BT_COEX_MODE_SLOTTED, true, true, 2, 5, true }; + + +/* + * Detects if there is any priority bt traffic + */ +static void ath_detect_bt_priority(struct ath_softc *sc) +{ + struct ath_btcoex_info *btinfo = &sc->btcoex_info; + + if (ath9k_hw_gpio_get(sc->sc_ah, btinfo->btpriority_gpio)) + btinfo->bt_priority_cnt++; + + if (time_after(jiffies, btinfo->bt_priority_time + + msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { + if (btinfo->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { + DPRINTF(sc, ATH_DBG_BTCOEX, + "BT priority traffic detected"); + sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; + } else { + sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; + } + + btinfo->bt_priority_cnt = 0; + btinfo->bt_priority_time = jiffies; + } +} + +/* + * Configures appropriate weight based on stomp type. + */ +static void ath_btcoex_bt_stomp(struct ath_softc *sc, + struct ath_btcoex_info *btinfo, + int stomp_type) +{ + + switch (stomp_type) { + case ATH_BTCOEX_STOMP_ALL: + ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, + AR_STOMP_ALL_WLAN_WGHT); + break; + case ATH_BTCOEX_STOMP_LOW: + ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT); + break; + case ATH_BTCOEX_STOMP_NONE: + ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, + AR_STOMP_NONE_WLAN_WGHT); + break; + default: + DPRINTF(sc, ATH_DBG_BTCOEX, "Invalid Stomptype\n"); + break; + } + + ath9k_hw_btcoex_enable(sc->sc_ah); +} + +/* + * This is the master bt coex timer which runs for every + * 45ms, bt traffic will be given priority during 55% of this + * period while wlan gets remaining 45% + */ + +static void ath_btcoex_period_timer(unsigned long data) +{ + struct ath_softc *sc = (struct ath_softc *) data; + struct ath_btcoex_info *btinfo = &sc->btcoex_info; + unsigned long flags; + + ath_detect_bt_priority(sc); + + spin_lock_irqsave(&btinfo->btcoex_lock, flags); + + ath_btcoex_bt_stomp(sc, btinfo, btinfo->bt_stomp_type); + + spin_unlock_irqrestore(&btinfo->btcoex_lock, flags); + + if (btinfo->btcoex_period != btinfo->btcoex_no_stomp) { + if (btinfo->hw_timer_enabled) + ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer); + + ath_gen_timer_start(sc->sc_ah, + btinfo->no_stomp_timer, + (ath9k_hw_gettsf32(sc->sc_ah) + + btinfo->btcoex_no_stomp), + btinfo->btcoex_no_stomp * 10); + btinfo->hw_timer_enabled = true; + } + + mod_timer(&btinfo->period_timer, jiffies + + msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); +} + +/* + * Generic tsf based hw timer which configures weight + * registers to time slice between wlan and bt traffic + */ + +static void ath_btcoex_no_stomp_timer(void *arg) +{ + struct ath_softc *sc = (struct ath_softc *)arg; + struct ath_btcoex_info *btinfo = &sc->btcoex_info; + unsigned long flags; + + DPRINTF(sc, ATH_DBG_BTCOEX, "no stomp timer running \n"); + + spin_lock_irqsave(&btinfo->btcoex_lock, flags); + + if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) + ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_NONE); + else if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) + ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_LOW); + + spin_unlock_irqrestore(&btinfo->btcoex_lock, flags); +} + +static int ath_init_btcoex_info(struct ath_hw *hw, + struct ath_btcoex_info *btcoex_info) +{ + u32 i; + int qnum; + + qnum = ath_tx_get_qnum(hw->ah_sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); + + btcoex_info->bt_coex_mode = + (btcoex_info->bt_coex_mode & AR_BT_QCU_THRESH) | + SM(ath_bt_config.bt_time_extend, AR_BT_TIME_EXTEND) | + SM(ath_bt_config.bt_txstate_extend, AR_BT_TXSTATE_EXTEND) | + SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) | + SM(ath_bt_config.bt_mode, AR_BT_MODE) | + SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) | + SM(ath_bt_config.bt_rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) | + SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) | + SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) | + SM(qnum, AR_BT_QCU_THRESH); + + btcoex_info->bt_coex_mode2 = + SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) | + SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) | + AR_BT_DISABLE_BT_ANT; + + btcoex_info->bt_stomp_type = ATH_BTCOEX_STOMP_LOW; + + btcoex_info->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000; + + btcoex_info->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * + btcoex_info->btcoex_period / 100; + + for (i = 0; i < 32; i++) + hw->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i; + + setup_timer(&btcoex_info->period_timer, ath_btcoex_period_timer, + (unsigned long) hw->ah_sc); + + btcoex_info->no_stomp_timer = ath_gen_timer_alloc(hw, + ath_btcoex_no_stomp_timer, + ath_btcoex_no_stomp_timer, + (void *)hw->ah_sc, AR_FIRST_NDP_TIMER); + + if (btcoex_info->no_stomp_timer == NULL) + return -ENOMEM; + + spin_lock_init(&btcoex_info->btcoex_lock); + + return 0; +} + +int ath9k_hw_btcoex_init(struct ath_hw *ah) { struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info; + int ret = 0; + + if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) { + /* connect bt_active to baseband */ + REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, + (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | + AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF)); + + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, + AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB); + + /* Set input mux for bt_active to gpio pin */ + REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, + AR_GPIO_INPUT_MUX1_BT_ACTIVE, + btcoex_info->btactive_gpio); - /* connect bt_active to baseband */ - REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, - (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | - AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF)); + /* Configure the desired gpio port for input */ + ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); + } else { + /* btcoex 3-wire */ + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, + (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB | + AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB)); - REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, - AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB); + /* Set input mux for bt_prority_async and + * bt_active_async to GPIO pins */ + REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, + AR_GPIO_INPUT_MUX1_BT_ACTIVE, + btcoex_info->btactive_gpio); - /* Set input mux for bt_active to gpio pin */ - REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, - AR_GPIO_INPUT_MUX1_BT_ACTIVE, - btcoex_info->btactive_gpio); + REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, + AR_GPIO_INPUT_MUX1_BT_PRIORITY, + btcoex_info->btpriority_gpio); - /* Configure the desired gpio port for input */ - ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); + /* Configure the desired GPIO ports for input */ + + ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); + ath9k_hw_cfg_gpio_input(ah, btcoex_info->btpriority_gpio); + + ret = ath_init_btcoex_info(ah, btcoex_info); + } + + return ret; } void ath9k_hw_btcoex_enable(struct ath_hw *ah) { struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info; - /* Configure the desired GPIO port for TX_FRAME output */ - ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, - AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); + if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) { + /* Configure the desired GPIO port for TX_FRAME output */ + ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, + AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); + } else { + /* + * Program coex mode and weight registers to + * enable coex 3-wire + */ + REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_info->bt_coex_mode); + REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_info->bt_coex_weights); + REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_info->bt_coex_mode2); + + REG_RMW_FIELD(ah, AR_QUIET1, + AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); + REG_RMW_FIELD(ah, AR_PCU_MISC, + AR_PCU_BT_ANT_PREVENT_RX, 0); + + ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, + AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL); + } + + REG_RMW(ah, AR_GPIO_PDPU, + (0x2 << (btcoex_info->btactive_gpio * 2)), + (0x3 << (btcoex_info->btactive_gpio * 2))); ah->ah_sc->sc_flags |= SC_OP_BTCOEX_ENABLED; } @@ -57,5 +274,46 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah) ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) { + REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE); + REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0); + REG_WRITE(ah, AR_BT_COEX_MODE2, 0); + } + ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED; } + +/* + * Pause btcoex timer and bt duty cycle timer + */ +void ath_btcoex_timer_pause(struct ath_softc *sc, + struct ath_btcoex_info *btinfo) +{ + + del_timer_sync(&btinfo->period_timer); + + if (btinfo->hw_timer_enabled) + ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer); + + btinfo->hw_timer_enabled = false; +} + +/* + * (Re)start btcoex timers + */ +void ath_btcoex_timer_resume(struct ath_softc *sc, + struct ath_btcoex_info *btinfo) +{ + + DPRINTF(sc, ATH_DBG_BTCOEX, "Starting btcoex timers"); + + /* make sure duty cycle timer is also stopped when resuming */ + if (btinfo->hw_timer_enabled) + ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer); + + btinfo->bt_priority_cnt = 0; + btinfo->bt_priority_time = jiffies; + sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; + + mod_timer(&btinfo->period_timer, jiffies); +} diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index cdfa80d0eb4..45568196c59 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -20,20 +20,79 @@ #define ATH_WLANACTIVE_GPIO 5 #define ATH_BTACTIVE_GPIO 6 +#define ATH_BTCOEX_DEF_BT_PERIOD 45 +#define ATH_BTCOEX_DEF_DUTY_CYCLE 55 +#define ATH_BTCOEX_BMISS_THRESH 50 + +#define ATH_BT_PRIORITY_TIME_THRESHOLD 1000 /* ms */ +#define ATH_BT_CNT_THRESHOLD 3 + enum ath_btcoex_scheme { ATH_BTCOEX_CFG_NONE, ATH_BTCOEX_CFG_2WIRE, ATH_BTCOEX_CFG_3WIRE, }; +enum ath_stomp_type { + ATH_BTCOEX_NO_STOMP, + ATH_BTCOEX_STOMP_ALL, + ATH_BTCOEX_STOMP_LOW, + ATH_BTCOEX_STOMP_NONE +}; + +enum ath_bt_mode { + ATH_BT_COEX_MODE_LEGACY, /* legacy rx_clear mode */ + ATH_BT_COEX_MODE_UNSLOTTED, /* untimed/unslotted mode */ + ATH_BT_COEX_MODE_SLOTTED, /* slotted mode */ + ATH_BT_COEX_MODE_DISALBED, /* coexistence disabled */ +}; + +struct ath_btcoex_config { + u8 bt_time_extend; + bool bt_txstate_extend; + bool bt_txframe_extend; + enum ath_bt_mode bt_mode; /* coexistence mode */ + bool bt_quiet_collision; + bool bt_rxclear_polarity; /* invert rx_clear as WLAN_ACTIVE*/ + u8 bt_priority_time; + u8 bt_first_slot_time; + bool bt_hold_rx_clear; +}; + struct ath_btcoex_info { enum ath_btcoex_scheme btcoex_scheme; u8 wlanactive_gpio; u8 btactive_gpio; + u8 btpriority_gpio; + u8 bt_duty_cycle; /* BT duty cycle in percentage */ + int bt_stomp_type; /* Types of BT stomping */ + u32 bt_coex_mode; /* Register setting for AR_BT_COEX_MODE */ + u32 bt_coex_weights; /* Register setting for AR_BT_COEX_WEIGHT */ + u32 bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */ + u32 btcoex_no_stomp; /* in usec */ + u32 btcoex_period; /* in usec */ + u32 bt_priority_cnt; + unsigned long bt_priority_time; + bool hw_timer_enabled; + spinlock_t btcoex_lock; + struct timer_list period_timer; /* Timer for BT period */ + struct ath_gen_timer *no_stomp_timer; /*Timer for no BT stomping*/ }; -void ath9k_hw_btcoex_init(struct ath_hw *ah); +int ath9k_hw_btcoex_init(struct ath_hw *ah); void ath9k_hw_btcoex_enable(struct ath_hw *ah); void ath9k_hw_btcoex_disable(struct ath_hw *ah); +void ath_btcoex_timer_resume(struct ath_softc *sc, + struct ath_btcoex_info *btinfo); +void ath_btcoex_timer_pause(struct ath_softc *sc, + struct ath_btcoex_info *btinfo); + +static inline void ath_btcoex_set_weight(struct ath_btcoex_info *btcoex_info, + u32 bt_weight, + u32 wlan_weight) +{ + btcoex_info->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | + SM(wlan_weight, AR_BTCOEX_WL_WGHT); +} #endif diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index ea0dd1ec15c..7241f474833 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -31,6 +31,7 @@ enum ATH_DEBUG { ATH_DBG_FATAL = 0x00000400, ATH_DBG_PS = 0x00000800, ATH_DBG_HWTIMER = 0x00001000, + ATH_DBG_BTCOEX = 0x00002000, ATH_DBG_ANY = 0xffffffff }; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 3afd7a9fc8a..e340dacc6eb 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -4141,7 +4141,7 @@ static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask) return timer_table->gen_timer_index[b]; } -static u32 ath9k_hw_gettsf32(struct ath_hw *ah) +u32 ath9k_hw_gettsf32(struct ath_hw *ah) { return REG_READ(ah, AR_TSF_L32); } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 052a9c4ebb9..5ca6ffa7091 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -79,6 +79,7 @@ #define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1 #define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED 2 #define AR_GPIO_OUTPUT_MUX_AS_TX_FRAME 3 +#define AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL 4 #define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5 #define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6 @@ -662,5 +663,6 @@ void ath_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer, void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer); void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer); void ath_gen_timer_isr(struct ath_hw *hw); +u32 ath9k_hw_gettsf32(struct ath_hw *ah); #endif diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 215c67251f7..4fae699a53c 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -602,6 +602,10 @@ irqreturn_t ath_isr(int irq, void *dev) sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; } + if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) + if (status & ATH9K_INT_GENTIMER) + ath_gen_timer_isr(ah); + chip_reset: ath_debug_stat_interrupt(sc, status); @@ -1279,6 +1283,10 @@ void ath_detach(struct ath_softc *sc) if (ATH_TXQ_SETUP(sc, i)) ath_tx_cleanupq(sc, &sc->tx.txq[i]); + if ((sc->btcoex_info.no_stomp_timer) && + sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) + ath_gen_timer_free(sc->sc_ah, sc->btcoex_info.no_stomp_timer); + ath9k_hw_detach(sc->sc_ah); sc->sc_ah = NULL; ath9k_exit_debug(sc); @@ -1509,8 +1517,11 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc) ARRAY_SIZE(ath9k_5ghz_chantable); } - if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) - ath9k_hw_btcoex_init(ah); + if (sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) { + r = ath9k_hw_btcoex_init(ah); + if (r) + goto bad2; + } return 0; bad2: @@ -1992,10 +2003,16 @@ static int ath9k_start(struct ieee80211_hw *hw) ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); - if ((sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) && - !(sc->sc_flags & SC_OP_BTCOEX_ENABLED)) + if ((sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) && + !(sc->sc_flags & SC_OP_BTCOEX_ENABLED)) { + ath_btcoex_set_weight(&sc->btcoex_info, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT); ath9k_hw_btcoex_enable(sc->sc_ah); + if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) + ath_btcoex_timer_resume(sc, &sc->btcoex_info); + } + mutex_unlock: mutex_unlock(&sc->mutex); @@ -2129,6 +2146,12 @@ static void ath9k_stop(struct ieee80211_hw *hw) return; /* another wiphy still in use */ } + if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) { + ath9k_hw_btcoex_disable(sc->sc_ah); + if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) + ath_btcoex_timer_pause(sc, &sc->btcoex_info); + } + /* make sure h/w will not generate any interrupt * before setting the invalid flag. */ ath9k_hw_set_interrupts(sc->sc_ah, 0); @@ -2142,9 +2165,6 @@ static void ath9k_stop(struct ieee80211_hw *hw) wiphy_rfkill_stop_polling(sc->hw->wiphy); - if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) - ath9k_hw_btcoex_disable(sc->sc_ah); - /* disable HAL and put h/w to sleep */ ath9k_hw_disable(sc->sc_ah); ath9k_hw_configpcipowersave(sc->sc_ah, 1); diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 1d8e0a8b587..3ddb243f000 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -970,6 +970,8 @@ enum { #define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF_S 7 #define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB 0x00001000 #define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB_S 12 +#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB 0x00001000 +#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB_S 1 #define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB 0x00008000 #define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB_S 15 #define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000 @@ -978,6 +980,8 @@ enum { #define AR_GPIO_INPUT_MUX1 0x4058 #define AR_GPIO_INPUT_MUX1_BT_ACTIVE 0x000f0000 #define AR_GPIO_INPUT_MUX1_BT_ACTIVE_S 16 +#define AR_GPIO_INPUT_MUX1_BT_PRIORITY 0x00000f00 +#define AR_GPIO_INPUT_MUX1_BT_PRIORITY_S 8 #define AR_GPIO_INPUT_MUX2 0x405c #define AR_GPIO_INPUT_MUX2_CLK25 0x0000000f @@ -1003,6 +1007,8 @@ enum { #define AR_OBS 0x4080 +#define AR_GPIO_PDPU 0x4088 + #define AR_PCIE_MSI 0x4094 #define AR_PCIE_MSI_ENABLE 0x00000001 @@ -1436,6 +1442,7 @@ enum { #define AR_QUIET1_NEXT_QUIET_M 0x0000ffff #define AR_QUIET1_QUIET_ENABLE 0x00010000 #define AR_QUIET1_QUIET_ACK_CTS_ENABLE 0x00020000 +#define AR_QUIET1_QUIET_ACK_CTS_ENABLE_S 17 #define AR_QUIET2 0x8100 #define AR_QUIET2_QUIET_PERIOD_S 0 #define AR_QUIET2_QUIET_PERIOD_M 0x0000ffff @@ -1481,6 +1488,8 @@ enum { #define AR_PCU_CLEAR_VMF 0x01000000 #define AR_PCU_CLEAR_BA_VALID 0x04000000 +#define AR_PCU_BT_ANT_PREVENT_RX 0x00100000 +#define AR_PCU_BT_ANT_PREVENT_RX_S 20 #define AR_FILT_OFDM 0x8124 #define AR_FILT_OFDM_COUNT 0x00FFFFFF @@ -1508,6 +1517,46 @@ enum { #define AR_PHY_ERR_3_COUNT 0x00FFFFFF #define AR_PHY_ERR_MASK_3 0x816c +#define AR_BT_COEX_MODE 0x8170 +#define AR_BT_TIME_EXTEND 0x000000ff +#define AR_BT_TIME_EXTEND_S 0 +#define AR_BT_TXSTATE_EXTEND 0x00000100 +#define AR_BT_TXSTATE_EXTEND_S 8 +#define AR_BT_TX_FRAME_EXTEND 0x00000200 +#define AR_BT_TX_FRAME_EXTEND_S 9 +#define AR_BT_MODE 0x00000c00 +#define AR_BT_MODE_S 10 +#define AR_BT_QUIET 0x00001000 +#define AR_BT_QUIET_S 12 +#define AR_BT_QCU_THRESH 0x0001e000 +#define AR_BT_QCU_THRESH_S 13 +#define AR_BT_RX_CLEAR_POLARITY 0x00020000 +#define AR_BT_RX_CLEAR_POLARITY_S 17 +#define AR_BT_PRIORITY_TIME 0x00fc0000 +#define AR_BT_PRIORITY_TIME_S 18 +#define AR_BT_FIRST_SLOT_TIME 0xff000000 +#define AR_BT_FIRST_SLOT_TIME_S 24 + +#define AR_BT_COEX_WEIGHT 0x8174 +#define AR_BT_COEX_WGHT 0xff55 +#define AR_STOMP_ALL_WLAN_WGHT 0xffcc +#define AR_STOMP_LOW_WLAN_WGHT 0xaaa8 +#define AR_STOMP_NONE_WLAN_WGHT 0xaa00 +#define AR_BTCOEX_BT_WGHT 0x0000ffff +#define AR_BTCOEX_BT_WGHT_S 0 +#define AR_BTCOEX_WL_WGHT 0xffff0000 +#define AR_BTCOEX_WL_WGHT_S 16 + +#define AR_BT_COEX_MODE2 0x817c +#define AR_BT_BCN_MISS_THRESH 0x000000ff +#define AR_BT_BCN_MISS_THRESH_S 0 +#define AR_BT_BCN_MISS_CNT 0x0000ff00 +#define AR_BT_BCN_MISS_CNT_S 8 +#define AR_BT_HOLD_RX_CLEAR 0x00010000 +#define AR_BT_HOLD_RX_CLEAR_S 16 +#define AR_BT_DISABLE_BT_ANT 0x00100000 +#define AR_BT_DISABLE_BT_ANT_S 20 + #define AR_TXSIFS 0x81d0 #define AR_TXSIFS_TIME 0x000000FF #define AR_TXSIFS_TX_LATENCY 0x00000F00 diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 87762da0383..42551a48c8a 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -493,7 +493,12 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy) return 0; - aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_MAX); + if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED) + aggr_limit = min((max_4ms_framelen * 3) / 8, + (u32)ATH_AMPDU_LIMIT_MAX); + else + aggr_limit = min(max_4ms_framelen, + (u32)ATH_AMPDU_LIMIT_MAX); /* * h/w can accept aggregates upto 16 bit lengths (65535). @@ -872,7 +877,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) return &sc->tx.txq[qnum]; } -static int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype) +int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype) { int qnum; -- cgit v1.2.3-18-g5258 From 6a8171f261eec3577c2a5985e3a2b51377e48931 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Wed, 26 Aug 2009 13:54:08 -0300 Subject: rtl8187: fix circular locking (rtl8187_stop/rtl8187_work) Larry Finger reports following lockdep warning: [ INFO: possible circular locking dependency detected ] 2.6.31-rc6-wl #201 ------------------------------------------------------- rfkill/30578 is trying to acquire lock: (&(&priv->work)->work#2){+.+...}, at: [] __cancel_work_timer+0xd9/0x222 but task is already holding lock: (&priv->conf_mutex#2){+.+.+.}, at: [] rtl8187_stop+0x31/0x364 [rtl8187] which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (&priv->conf_mutex#2){+.+.+.}: [] __lock_acquire+0x12d0/0x1614 [] lock_acquire+0xb9/0xdd [] mutex_lock_nested+0x56/0x2a8 [] rtl8187_work+0x3b/0xf2 [rtl8187] [] worker_thread+0x1fa/0x30a [] kthread+0x8f/0x97 [] child_rip+0xa/0x20 [] 0xffffffffffffffff -> #0 (&(&priv->work)->work#2){+.+...}: [] __lock_acquire+0x1005/0x1614 [] lock_acquire+0xb9/0xdd [] __cancel_work_timer+0x112/0x222 [] cancel_delayed_work_sync+0xd/0xf [] rtl8187_stop+0x34c/0x364 [rtl8187] [] ieee80211_stop_device+0x29/0x61 [mac80211] [] ieee80211_stop+0x476/0x530 [mac80211] [] dev_close+0x8a/0xac [] cfg80211_rfkill_set_block+0x4a/0x7a [cfg80211] [] rfkill_set_block+0x84/0xd9 [rfkill] [] rfkill_fop_write+0xda/0x124 [rfkill] [] vfs_write+0xae/0x14a [] sys_write+0x47/0x6e [] system_call_fastpath+0x16/0x1b [] 0xffffffffffffffff The problem here is that rtl8187_stop, while helding priv->conf_mutex, runs cancel_delayed_work_sync on an workqueue that runs rtl8187_work, which also takes priv->conf_mutex lock. Move cancel_delayed_work_sync out of rtl8187_stop priv->conf_mutex locking region. Reported-by: Larry Finger Tested-by: Larry Finger Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187_dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 90f38357393..5573e347680 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -1014,9 +1014,10 @@ static void rtl8187_stop(struct ieee80211_hw *dev) dev_kfree_skb_any(skb); usb_kill_anchored_urbs(&priv->anchored); + mutex_unlock(&priv->conf_mutex); + if (!priv->is_rtl8187b) cancel_delayed_work_sync(&priv->work); - mutex_unlock(&priv->conf_mutex); } static int rtl8187_add_interface(struct ieee80211_hw *dev, -- cgit v1.2.3-18-g5258 From ca9152e37f57259ca92486ca5753af16fd9155c6 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Wed, 26 Aug 2009 13:54:09 -0300 Subject: rtl8187: Implement rfkill support This change implements rfkill support for RTL8187B and RTL8187L devices, using new cfg80211 rfkill API. Acked-by: Larry Finger Tested-by: Hin-Tak Leung Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/Makefile | 2 +- drivers/net/wireless/rtl818x/rtl8187.h | 1 + drivers/net/wireless/rtl818x/rtl8187_dev.c | 28 +++++++----- drivers/net/wireless/rtl818x/rtl8187_leds.c | 4 +- drivers/net/wireless/rtl818x/rtl8187_rfkill.c | 63 +++++++++++++++++++++++++++ drivers/net/wireless/rtl818x/rtl8187_rfkill.h | 8 ++++ drivers/net/wireless/rtl818x/rtl818x.h | 5 ++- 7 files changed, 94 insertions(+), 17 deletions(-) create mode 100644 drivers/net/wireless/rtl818x/rtl8187_rfkill.c create mode 100644 drivers/net/wireless/rtl818x/rtl8187_rfkill.h (limited to 'drivers') diff --git a/drivers/net/wireless/rtl818x/Makefile b/drivers/net/wireless/rtl818x/Makefile index 37e3d4db0c4..93cbfbedb46 100644 --- a/drivers/net/wireless/rtl818x/Makefile +++ b/drivers/net/wireless/rtl818x/Makefile @@ -1,5 +1,5 @@ rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o -rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o rtl8187_leds.o +rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o rtl8187_leds.o rtl8187_rfkill.o obj-$(CONFIG_RTL8180) += rtl8180.o obj-$(CONFIG_RTL8187) += rtl8187.o diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h index c09bfefc70f..bf9175a8c1f 100644 --- a/drivers/net/wireless/rtl818x/rtl8187.h +++ b/drivers/net/wireless/rtl818x/rtl8187.h @@ -133,6 +133,7 @@ struct rtl8187_priv { __le16 bits16; __le32 bits32; } *io_dmabuf; + bool rfkill_off; }; void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 5573e347680..9679b29e1c4 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -32,6 +32,7 @@ #ifdef CONFIG_RTL8187_LEDS #include "rtl8187_leds.h" #endif +#include "rtl8187_rfkill.h" MODULE_AUTHOR("Michael Wu "); MODULE_AUTHOR("Andrea Merello "); @@ -648,10 +649,10 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev) /* setup card */ rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0); - rtl818x_iowrite8(priv, &priv->map->GPIO, 0); + rtl818x_iowrite8(priv, &priv->map->GPIO0, 0); rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8)); - rtl818x_iowrite8(priv, &priv->map->GPIO, 1); + rtl818x_iowrite8(priv, &priv->map->GPIO0, 1); rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); @@ -674,11 +675,11 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev) /* host_usb_init */ rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0); - rtl818x_iowrite8(priv, &priv->map->GPIO, 0); + rtl818x_iowrite8(priv, &priv->map->GPIO0, 0); reg = rtl818x_ioread8(priv, (u8 *)0xFE53); rtl818x_iowrite8(priv, (u8 *)0xFE53, reg | (1 << 7)); rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8)); - rtl818x_iowrite8(priv, &priv->map->GPIO, 0x20); + rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x20); rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x80); rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x80); @@ -907,12 +908,12 @@ static int rtl8187_start(struct ieee80211_hw *dev) u32 reg; int ret; + mutex_lock(&priv->conf_mutex); + ret = (!priv->is_rtl8187b) ? rtl8187_init_hw(dev) : rtl8187b_init_hw(dev); if (ret) - return ret; - - mutex_lock(&priv->conf_mutex); + goto rtl8187_start_exit; init_usb_anchor(&priv->anchored); priv->dev = dev; @@ -939,8 +940,7 @@ static int rtl8187_start(struct ieee80211_hw *dev) (7 << 21 /* MAX TX DMA */)); rtl8187_init_urbs(dev); rtl8187b_init_status_urb(dev); - mutex_unlock(&priv->conf_mutex); - return 0; + goto rtl8187_start_exit; } rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); @@ -984,9 +984,10 @@ static int rtl8187_start(struct ieee80211_hw *dev) reg |= RTL818X_CMD_RX_ENABLE; rtl818x_iowrite8(priv, &priv->map->CMD, reg); INIT_DELAYED_WORK(&priv->work, rtl8187_work); - mutex_unlock(&priv->conf_mutex); - return 0; +rtl8187_start_exit: + mutex_unlock(&priv->conf_mutex); + return ret; } static void rtl8187_stop(struct ieee80211_hw *dev) @@ -1277,7 +1278,8 @@ static const struct ieee80211_ops rtl8187_ops = { .bss_info_changed = rtl8187_bss_info_changed, .prepare_multicast = rtl8187_prepare_multicast, .configure_filter = rtl8187_configure_filter, - .conf_tx = rtl8187_conf_tx + .conf_tx = rtl8187_conf_tx, + .rfkill_poll = rtl8187_rfkill_poll }; static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom) @@ -1517,6 +1519,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, reg &= 0xFF; rtl8187_leds_init(dev, reg); #endif + rtl8187_rfkill_init(dev); return 0; @@ -1540,6 +1543,7 @@ static void __devexit rtl8187_disconnect(struct usb_interface *intf) #ifdef CONFIG_RTL8187_LEDS rtl8187_leds_exit(dev); #endif + rtl8187_rfkill_exit(dev); ieee80211_unregister_hw(dev); priv = dev->priv; diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.c b/drivers/net/wireless/rtl818x/rtl8187_leds.c index a6cfb7e7799..a1c670fc155 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_leds.c +++ b/drivers/net/wireless/rtl818x/rtl8187_leds.c @@ -42,7 +42,7 @@ static void led_turn_on(struct work_struct *work) mutex_lock(&priv->conf_mutex); switch (led->ledpin) { case LED_PIN_GPIO0: - rtl818x_iowrite8(priv, &priv->map->GPIO, 0x01); + rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x01); rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x00); break; case LED_PIN_LED0: @@ -80,7 +80,7 @@ static void led_turn_off(struct work_struct *work) mutex_lock(&priv->conf_mutex); switch (led->ledpin) { case LED_PIN_GPIO0: - rtl818x_iowrite8(priv, &priv->map->GPIO, 0x01); + rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x01); rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x01); break; case LED_PIN_LED0: diff --git a/drivers/net/wireless/rtl818x/rtl8187_rfkill.c b/drivers/net/wireless/rtl818x/rtl8187_rfkill.c new file mode 100644 index 00000000000..9fab13e4004 --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8187_rfkill.c @@ -0,0 +1,63 @@ +/* + * Linux RFKILL support for RTL8187 + * + * Copyright (c) 2009 Herton Ronaldo Krzesinski + * + * Based on the RFKILL handling in the r8187 driver, which is: + * Copyright (c) Realtek Semiconductor Corp. All rights reserved. + * + * Thanks to Realtek for their support! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include "rtl8187.h" + +static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv) +{ + u8 gpio; + + gpio = rtl818x_ioread8(priv, &priv->map->GPIO0); + rtl818x_iowrite8(priv, &priv->map->GPIO0, gpio & ~0x02); + gpio = rtl818x_ioread8(priv, &priv->map->GPIO1); + + return gpio & 0x02; +} + +void rtl8187_rfkill_init(struct ieee80211_hw *hw) +{ + struct rtl8187_priv *priv = hw->priv; + + priv->rfkill_off = rtl8187_is_radio_enabled(priv); + printk(KERN_INFO "rtl8187: wireless switch is %s\n", + priv->rfkill_off ? "on" : "off"); + wiphy_rfkill_set_hw_state(hw->wiphy, !priv->rfkill_off); + wiphy_rfkill_start_polling(hw->wiphy); +} + +void rtl8187_rfkill_poll(struct ieee80211_hw *hw) +{ + bool enabled; + struct rtl8187_priv *priv = hw->priv; + + mutex_lock(&priv->conf_mutex); + enabled = rtl8187_is_radio_enabled(priv); + if (unlikely(enabled != priv->rfkill_off)) { + priv->rfkill_off = enabled; + printk(KERN_INFO "rtl8187: wireless radio switch turned %s\n", + enabled ? "on" : "off"); + wiphy_rfkill_set_hw_state(hw->wiphy, !enabled); + } + mutex_unlock(&priv->conf_mutex); +} + +void rtl8187_rfkill_exit(struct ieee80211_hw *hw) +{ + wiphy_rfkill_stop_polling(hw->wiphy); +} diff --git a/drivers/net/wireless/rtl818x/rtl8187_rfkill.h b/drivers/net/wireless/rtl818x/rtl8187_rfkill.h new file mode 100644 index 00000000000..e12575e96d1 --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8187_rfkill.h @@ -0,0 +1,8 @@ +#ifndef RTL8187_RFKILL_H +#define RTL8187_RFKILL_H + +void rtl8187_rfkill_init(struct ieee80211_hw *hw); +void rtl8187_rfkill_poll(struct ieee80211_hw *hw); +void rtl8187_rfkill_exit(struct ieee80211_hw *hw); + +#endif /* RTL8187_RFKILL_H */ diff --git a/drivers/net/wireless/rtl818x/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h index 562222e6cf1..8522490d2e2 100644 --- a/drivers/net/wireless/rtl818x/rtl818x.h +++ b/drivers/net/wireless/rtl818x/rtl818x.h @@ -138,8 +138,9 @@ struct rtl818x_csr { __le32 RF_PARA; __le32 RF_TIMING; u8 GP_ENABLE; - u8 GPIO; - u8 reserved_12[2]; + u8 GPIO0; + u8 GPIO1; + u8 reserved_12; __le32 HSSI_PARA; u8 reserved_13[4]; u8 TX_AGC_CTL; -- cgit v1.2.3-18-g5258 From d8fa338ee01e7de029d2441a8c2b9c5fbfeac82f Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Wed, 26 Aug 2009 20:51:24 +0200 Subject: b43: LP-PHY: Fix and simplify Qdiv roundup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Qdiv roundup routine is essentially a fixed-point division algorithm, using only integer math. However, the version in the specs had a major error that has been recently fixed (a missing quotient++). Replace Qdiv roundup with a rewritten, simplified version. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 7e70c078475..5306f2c66b3 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1032,9 +1032,10 @@ static int lpphy_loopback(struct b43_wldev *dev) return index; } +/* Fixed-point division algorithm using only integer math. */ static u32 lpphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision) { - u32 quotient, remainder, rbit, roundup, tmp; + u32 quotient, remainder; if (divisor == 0) return 0; @@ -1042,20 +1043,16 @@ static u32 lpphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision) quotient = dividend / divisor; remainder = dividend % divisor; - rbit = divisor & 0x1; - roundup = (divisor >> 1) + rbit; - - while (precision != 0) { - tmp = remainder - roundup; + while (precision > 0) { quotient <<= 1; - if (remainder >= roundup) - remainder = (tmp << 1) + rbit; - else - remainder <<= 1; + if (remainder << 1 >= divisor) { + quotient++; + remainder = (remainder << 1) - divisor; + } precision--; } - if (remainder >= roundup) + if (remainder << 1 >= divisor) quotient++; return quotient; -- cgit v1.2.3-18-g5258 From 68ec53292c7f09056152efa9a6ee2591c794f08c Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Wed, 26 Aug 2009 20:51:25 +0200 Subject: b43: Fix and update LP-PHY code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -Fix a few nasty typos (b43_phy_* operations instead of b43_radio_*) in the channel tune routines. -Fix some typos & spec errors found by MMIO tracing. -Optimize b43_phy_write & b43_phy_mask/set/maskset to use only the minimal number of MMIO accesses. (Write is possible using a single 32-bit MMIO write, while set/mask/maskset can be done in 3 16-bit MMIOs). -Set the default channel back to 1, as the bug forcing us to use channel 7 is now fixed. With this, the device comes up, scans, associates, transmits, receives, monitors and injects on all channels - in other words, it's fully functional. Sensitivity and TX power are still sub-optimal, due to the lack of calibration (that's next on my list). Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_common.c | 27 +++++++--- drivers/net/wireless/b43/phy_common.h | 3 ++ drivers/net/wireless/b43/phy_lp.c | 91 ++++++++++++++++++--------------- drivers/net/wireless/b43/phy_lp.h | 3 ++ drivers/net/wireless/b43/tables_lpphy.c | 79 ++++++++++++++++------------ 5 files changed, 122 insertions(+), 81 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 51686ec9698..6e704becda6 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -249,20 +249,35 @@ void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg) void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask) { - b43_phy_write(dev, offset, - b43_phy_read(dev, offset) & mask); + if (dev->phy.ops->phy_maskset) { + assert_mac_suspended(dev); + dev->phy.ops->phy_maskset(dev, offset, mask, 0); + } else { + b43_phy_write(dev, offset, + b43_phy_read(dev, offset) & mask); + } } void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set) { - b43_phy_write(dev, offset, - b43_phy_read(dev, offset) | set); + if (dev->phy.ops->phy_maskset) { + assert_mac_suspended(dev); + dev->phy.ops->phy_maskset(dev, offset, 0xFFFF, set); + } else { + b43_phy_write(dev, offset, + b43_phy_read(dev, offset) | set); + } } void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) { - b43_phy_write(dev, offset, - (b43_phy_read(dev, offset) & mask) | set); + if (dev->phy.ops->phy_maskset) { + assert_mac_suspended(dev); + dev->phy.ops->phy_maskset(dev, offset, mask, set); + } else { + b43_phy_write(dev, offset, + (b43_phy_read(dev, offset) & mask) | set); + } } int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel) diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 9f9f23cab72..b47a0f55c0b 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -95,6 +95,8 @@ enum b43_txpwr_result { * Must not be NULL. * @phy_write: Write to a PHY register. * Must not be NULL. + * @phy_maskset: Maskset a PHY register, taking shortcuts. + * If it is NULL, a generic algorithm is used. * @radio_read: Read from a Radio register. * Must not be NULL. * @radio_write: Write to a Radio register. @@ -154,6 +156,7 @@ struct b43_phy_operations { /* Register access */ u16 (*phy_read)(struct b43_wldev *dev, u16 reg); void (*phy_write)(struct b43_wldev *dev, u16 reg, u16 value); + void (*phy_maskset)(struct b43_wldev *dev, u16 reg, u16 mask, u16 set); u16 (*radio_read)(struct b43_wldev *dev, u16 reg); void (*radio_write)(struct b43_wldev *dev, u16 reg, u16 value); diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 5306f2c66b3..1a57d3390e9 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -44,7 +44,7 @@ static inline u16 channel2freq_lp(u8 channel) static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev) { if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - return 7; //FIXME temporary - channel 1 is broken + return 1; return 36; } @@ -182,8 +182,8 @@ static void lpphy_adjust_gain_table(struct b43_wldev *dev, u32 freq) temp[1] = temp[0] + 0x1000; temp[2] = temp[0] + 0x2000; - b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), 3, temp); b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), 3, temp); + b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), 3, temp); } static void lpphy_table_init(struct b43_wldev *dev) @@ -223,8 +223,8 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0x0006); b43_phy_mask(dev, B43_LPPHY_RX_RADIO_CTL, 0xFFFE); b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x0005); - b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC10, 0x0180); - b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x3800); + b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC1F, 0x0180); + b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x3C00); b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFFF0, 0x0005); b43_phy_maskset(dev, B43_LPPHY_GAIN_MISMATCH_LIMIT, 0xFFC0, 0x001A); b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0xFF00, 0x00B3); @@ -237,7 +237,7 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) /* TODO: * Set the LDO voltage to 0x0028 - FIXME: What is this? * Call sb_pmu_set_ldo_voltage with 4 and the LDO voltage - * as arguments + * as arguments * Call sb_pmu_paref_ldo_enable with argument TRUE */ if (dev->phy.rev == 0) { @@ -340,11 +340,11 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) if (dev->phy.rev == 1) { tmp = b43_phy_read(dev, B43_LPPHY_CLIPCTRTHRESH); tmp2 = (tmp & 0x03E0) >> 5; - tmp2 |= tmp << 5; + tmp2 |= tmp2 << 5; b43_phy_write(dev, B43_LPPHY_4C3, tmp2); - tmp = b43_phy_read(dev, B43_LPPHY_OFDMSYNCTHRESH0); + tmp = b43_phy_read(dev, B43_LPPHY_GAINDIRECTMISMATCH); tmp2 = (tmp & 0x1F00) >> 8; - tmp2 |= tmp << 5; + tmp2 |= tmp2 << 5; b43_phy_write(dev, B43_LPPHY_4C4, tmp2); tmp = b43_phy_read(dev, B43_LPPHY_VERYLOWGAINDB); tmp2 = tmp & 0x00FF; @@ -761,7 +761,7 @@ static void lpphy_disable_crs(struct b43_wldev *dev, bool user) b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3); b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFB); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x4); - b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFF7); + b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFF7); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x10); b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10); @@ -956,7 +956,7 @@ static void lpphy_run_ddfs(struct b43_wldev *dev, int i_on, int q_on, b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFF9F, scale_idx << 5); b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFB); b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x2); - b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x20); + b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x20); } static bool lpphy_rx_iq_est(struct b43_wldev *dev, u16 samples, u8 time, @@ -968,7 +968,7 @@ static bool lpphy_rx_iq_est(struct b43_wldev *dev, u16 samples, u8 time, b43_phy_write(dev, B43_LPPHY_IQ_NUM_SMPLS_ADDR, samples); b43_phy_maskset(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFF00, time); b43_phy_mask(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFEFF); - b43_phy_set(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFDFF); + b43_phy_set(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0x200); for (i = 0; i < 500; i++) { if (!(b43_phy_read(dev, @@ -1135,9 +1135,9 @@ static void lpphy_set_tx_power_control(struct b43_wldev *dev, } if (dev->phy.rev >= 2) { if (mode == B43_LPPHY_TXPCTL_HW) - b43_phy_maskset(dev, B43_PHY_OFDM(0xD0), 0xFD, 0x2); + b43_phy_set(dev, B43_PHY_OFDM(0xD0), 0x2); else - b43_phy_maskset(dev, B43_PHY_OFDM(0xD0), 0xFD, 0); + b43_phy_mask(dev, B43_PHY_OFDM(0xD0), 0xFFFD); } lpphy_write_tx_pctl_mode_to_hardware(dev); } @@ -1169,7 +1169,7 @@ static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev) err = b43_lpphy_op_switch_channel(dev, 7); if (err) { b43dbg(dev->wl, - "RC calib: Failed to switch to channel 7, error = %d", + "RC calib: Failed to switch to channel 7, error = %d\n", err); } old_txg_ovr = !!(b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40); @@ -1499,9 +1499,16 @@ static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg) } static void b43_lpphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + b43_write32(dev, B43_MMIO_PHY_CONTROL, ((u32)value << 16) | reg); +} + +static void b43_lpphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask, + u16 set) { b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); - b43_write16(dev, B43_MMIO_PHY_DATA, value); + b43_write16(dev, B43_MMIO_PHY_DATA, + (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set); } static u16 b43_lpphy_op_radio_read(struct b43_wldev *dev, u16 reg) @@ -1920,8 +1927,8 @@ static void lpphy_b2062_reset_pll_bias(struct b43_wldev *dev) static void lpphy_b2062_vco_calib(struct b43_wldev *dev) { - b43_phy_write(dev, B2062_S_RFPLL_CTL21, 0x42); - b43_phy_write(dev, B2062_S_RFPLL_CTL21, 0x62); + b43_radio_write(dev, B2062_S_RFPLL_CTL21, 0x42); + b43_radio_write(dev, B2062_S_RFPLL_CTL21, 0x62); udelay(200); } @@ -1980,7 +1987,7 @@ static int lpphy_b2062_tune(struct b43_wldev *dev, tmp6 = tmp5 / tmp4; tmp7 = tmp5 % tmp4; b43_radio_write(dev, B2062_S_RFPLL_CTL29, tmp6 + ((2 * tmp7) / tmp4)); - tmp8 = b43_phy_read(dev, B2062_S_RFPLL_CTL19); + tmp8 = b43_radio_read(dev, B2062_S_RFPLL_CTL19); tmp9 = ((2 * tmp3 * (tmp8 + 1)) + (3 * tmp1)) / (6 * tmp1); b43_radio_write(dev, B2062_S_RFPLL_CTL23, (tmp9 >> 8) + 16); b43_radio_write(dev, B2062_S_RFPLL_CTL24, tmp9 & 0xFF); @@ -2019,17 +2026,17 @@ static void lpphy_b2063_vco_calib(struct b43_wldev *dev) { u16 tmp; - b43_phy_mask(dev, B2063_PLL_SP1, ~0x40); - tmp = b43_phy_read(dev, B2063_PLL_JTAG_CALNRST) & 0xF8; - b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp); + b43_radio_mask(dev, B2063_PLL_SP1, ~0x40); + tmp = b43_radio_read(dev, B2063_PLL_JTAG_CALNRST) & 0xF8; + b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp); udelay(1); - b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x4); + b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x4); udelay(1); - b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x6); + b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x6); udelay(1); - b43_phy_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x7); + b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x7); udelay(300); - b43_phy_set(dev, B2063_PLL_SP1, 0x40); + b43_radio_set(dev, B2063_PLL_SP1, 0x40); } static int lpphy_b2063_tune(struct b43_wldev *dev, @@ -2124,31 +2131,31 @@ static int lpphy_b2063_tune(struct b43_wldev *dev, scale = 0; tmp5 = ((tmp4 + (tmp3 >> 1)) / tmp3) - 8; } - b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFC0, tmp5); - b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFBF, scale << 6); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFC0, tmp5); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFBF, scale << 6); tmp6 = lpphy_qdiv_roundup(100 * val1, val3, 16); tmp6 *= (tmp5 * 8) * (scale + 1); if (tmp6 > 150) tmp6 = 0; - b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFE0, tmp6); - b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFDF, scale << 5); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFE0, tmp6); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFDF, scale << 5); - b43_phy_maskset(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFFFB, 0x4); + b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFFFB, 0x4); if (crystal_freq > 26000000) - b43_phy_set(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0x2); + b43_radio_set(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0x2); else - b43_phy_mask(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFD); + b43_radio_mask(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFD); if (val1 == 45) - b43_phy_set(dev, B2063_PLL_JTAG_PLL_VCO1, 0x2); + b43_radio_set(dev, B2063_PLL_JTAG_PLL_VCO1, 0x2); else - b43_phy_mask(dev, B2063_PLL_JTAG_PLL_VCO1, 0xFD); + b43_radio_mask(dev, B2063_PLL_JTAG_PLL_VCO1, 0xFD); - b43_phy_set(dev, B2063_PLL_SP2, 0x3); + b43_radio_set(dev, B2063_PLL_SP2, 0x3); udelay(1); - b43_phy_mask(dev, B2063_PLL_SP2, 0xFFFC); + b43_radio_mask(dev, B2063_PLL_SP2, 0xFFFC); lpphy_b2063_vco_calib(dev); b43_radio_write(dev, B2063_COMM15, old_comm15); @@ -2158,10 +2165,9 @@ static int lpphy_b2063_tune(struct b43_wldev *dev, static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, unsigned int new_channel) { + struct b43_phy_lp *lpphy = dev->phy.lp; int err; - b43_write16(dev, B43_MMIO_CHANNEL, new_channel); - if (dev->phy.radio_ver == 0x2063) { err = lpphy_b2063_tune(dev, new_channel); if (err) @@ -2174,6 +2180,9 @@ static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel)); } + lpphy->channel = new_channel; + b43_write16(dev, B43_MMIO_CHANNEL, new_channel); + return 0; } @@ -2185,10 +2194,9 @@ static int b43_lpphy_op_init(struct b43_wldev *dev) lpphy_baseband_init(dev); lpphy_radio_init(dev); lpphy_calibrate_rc(dev); - err = b43_lpphy_op_switch_channel(dev, - b43_lpphy_op_get_default_chan(dev)); + err = b43_lpphy_op_switch_channel(dev, 7); if (err) { - b43dbg(dev->wl, "Switch to init channel failed, error = %d.\n", + b43dbg(dev->wl, "Switch to channel 7 failed, error = %d.\n", err); } lpphy_tx_pctl_init(dev); @@ -2222,6 +2230,7 @@ const struct b43_phy_operations b43_phyops_lp = { .init = b43_lpphy_op_init, .phy_read = b43_lpphy_op_read, .phy_write = b43_lpphy_op_write, + .phy_maskset = b43_lpphy_op_maskset, .radio_read = b43_lpphy_op_radio_read, .radio_write = b43_lpphy_op_radio_write, .software_rfkill = b43_lpphy_op_software_rfkill, diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h index e158d1f66c0..c3232c17b60 100644 --- a/drivers/net/wireless/b43/phy_lp.h +++ b/drivers/net/wireless/b43/phy_lp.h @@ -888,6 +888,9 @@ struct b43_phy_lp { bool crs_usr_disable, crs_sys_disable; unsigned int pdiv; + + /* The channel we are tuned to */ + u8 channel; }; enum tssi_mux_mode { diff --git a/drivers/net/wireless/b43/tables_lpphy.c b/drivers/net/wireless/b43/tables_lpphy.c index 60d472f285a..c784def19b1 100644 --- a/drivers/net/wireless/b43/tables_lpphy.c +++ b/drivers/net/wireless/b43/tables_lpphy.c @@ -624,30 +624,35 @@ u32 b43_lptab_read(struct b43_wldev *dev, u32 offset) void b43_lptab_read_bulk(struct b43_wldev *dev, u32 offset, unsigned int nr_elements, void *_data) { - u32 type, value; + u32 type; u8 *data = _data; unsigned int i; type = offset & B43_LPTAB_TYPEMASK; + offset &= ~B43_LPTAB_TYPEMASK; + B43_WARN_ON(offset > 0xFFFF); + + b43_phy_write(dev, B43_LPPHY_TABLE_ADDR, offset); + for (i = 0; i < nr_elements; i++) { - value = b43_lptab_read(dev, offset); switch (type) { case B43_LPTAB_8BIT: - *data = value; + *data = b43_phy_read(dev, B43_LPPHY_TABLEDATALO) & 0xFF; data++; break; case B43_LPTAB_16BIT: - *((u16 *)data) = value; + *((u16 *)data) = b43_phy_read(dev, B43_LPPHY_TABLEDATALO); data += 2; break; case B43_LPTAB_32BIT: - *((u32 *)data) = value; + *((u32 *)data) = b43_phy_read(dev, B43_LPPHY_TABLEDATAHI); + *((u32 *)data) <<= 16; + *((u32 *)data) |= b43_phy_read(dev, B43_LPPHY_TABLEDATALO); data += 4; break; default: B43_WARN_ON(1); } - offset++; } } @@ -688,26 +693,34 @@ void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset, unsigned int i; type = offset & B43_LPTAB_TYPEMASK; + offset &= ~B43_LPTAB_TYPEMASK; + B43_WARN_ON(offset > 0xFFFF); + + b43_phy_write(dev, B43_LPPHY_TABLE_ADDR, offset); + for (i = 0; i < nr_elements; i++) { switch (type) { case B43_LPTAB_8BIT: value = *data; data++; + B43_WARN_ON(value & ~0xFF); + b43_phy_write(dev, B43_LPPHY_TABLEDATALO, value); break; case B43_LPTAB_16BIT: value = *((u16 *)data); data += 2; + B43_WARN_ON(value & ~0xFFFF); + b43_phy_write(dev, B43_LPPHY_TABLEDATALO, value); break; case B43_LPTAB_32BIT: value = *((u32 *)data); data += 4; + b43_phy_write(dev, B43_LPPHY_TABLEDATAHI, value >> 16); + b43_phy_write(dev, B43_LPPHY_TABLEDATALO, value); break; default: B43_WARN_ON(1); - value = 0; } - b43_lptab_write(dev, offset, value); - offset++; } } @@ -777,7 +790,7 @@ static const u8 lpphy_pll_fraction_table[] = { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, }; -static const u16 lpphy_iq_local_table[] = { +static const u16 lpphy_iqlo_cal_table[] = { 0x0200, 0x0300, 0x0400, 0x0600, 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -789,10 +802,17 @@ static const u16 lpphy_iq_local_table[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, }; -static const u16 lpphy_ofdm_cck_gain_table[] = { +static const u16 lpphy_rev0_ofdm_cck_gain_table[] = { + 0x0001, 0x0001, 0x0001, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001, 0x5001, + 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055, 0x2065, 0x2075, + 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d, 0x135d, 0x055d, 0x155d, + 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d, 0x755d, +}; + +static const u16 lpphy_rev1_ofdm_cck_gain_table[] = { 0x5000, 0x6000, 0x7000, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001, 0x5001, 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055, 0x2065, 0x2075, 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d, 0x135d, 0x055d, 0x155d, @@ -2263,11 +2283,18 @@ void lpphy_rev0_1_table_init(struct b43_wldev *dev) b43_lptab_write_bulk(dev, B43_LPTAB8(6, 0), ARRAY_SIZE(lpphy_pll_fraction_table), lpphy_pll_fraction_table); b43_lptab_write_bulk(dev, B43_LPTAB16(0, 0), - ARRAY_SIZE(lpphy_iq_local_table), lpphy_iq_local_table); - b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), - ARRAY_SIZE(lpphy_ofdm_cck_gain_table), lpphy_ofdm_cck_gain_table); - b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), - ARRAY_SIZE(lpphy_ofdm_cck_gain_table), lpphy_ofdm_cck_gain_table); + ARRAY_SIZE(lpphy_iqlo_cal_table), lpphy_iqlo_cal_table); + if (dev->phy.rev == 0) { + b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), + ARRAY_SIZE(lpphy_rev0_ofdm_cck_gain_table), lpphy_rev0_ofdm_cck_gain_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), + ARRAY_SIZE(lpphy_rev0_ofdm_cck_gain_table), lpphy_rev0_ofdm_cck_gain_table); + } else { + b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), + ARRAY_SIZE(lpphy_rev1_ofdm_cck_gain_table), lpphy_rev1_ofdm_cck_gain_table); + b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), + ARRAY_SIZE(lpphy_rev1_ofdm_cck_gain_table), lpphy_rev1_ofdm_cck_gain_table); +} b43_lptab_write_bulk(dev, B43_LPTAB16(15, 0), ARRAY_SIZE(lpphy_gain_delta_table), lpphy_gain_delta_table); b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0), @@ -2281,22 +2308,6 @@ void lpphy_rev2plus_table_init(struct b43_wldev *dev) B43_WARN_ON(dev->phy.rev < 2); - /* - * FIXME This code follows the specs, but it looks wrong: - * In each pass, it writes 4 bytes to an offset in table ID 7, - * then increments the offset by 1 for the next pass. This results - * in the first 3 bytes of each pass except the first one getting - * written to a location that has already been zeroed in the previous - * pass. - * This is what the vendor driver does, but it still looks suspicious. - * - * This should probably suffice: - * - * for (i = 0; i < 704; i+=4) - * b43_lptab_write(dev, B43_LPTAB32(7, i), 0) - * - * This should be tested once the code is functional. - */ for (i = 0; i < 704; i++) b43_lptab_write(dev, B43_LPTAB32(7, i), 0); @@ -2323,7 +2334,7 @@ void lpphy_rev2plus_table_init(struct b43_wldev *dev) b43_lptab_write_bulk(dev, B43_LPTAB8(6, 0), ARRAY_SIZE(lpphy_pll_fraction_table), lpphy_pll_fraction_table); b43_lptab_write_bulk(dev, B43_LPTAB16(0, 0), - ARRAY_SIZE(lpphy_iq_local_table), lpphy_iq_local_table); + ARRAY_SIZE(lpphy_iqlo_cal_table), lpphy_iqlo_cal_table); b43_lptab_write_bulk(dev, B43_LPTAB32(9, 0), ARRAY_SIZE(lpphy_papd_eps_table), lpphy_papd_eps_table); b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0), -- cgit v1.2.3-18-g5258 From 06e4da268c0e8f3b8408403d65e47d2885a78ff2 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Wed, 26 Aug 2009 20:51:26 +0200 Subject: ssb: Implement PMU LDO control and use it in b43 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement the "PMU LDO set voltage" and "PMU LDO PA ref enable" functions, and use them during LP-PHY baseband init in b43. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 10 ++-- drivers/ssb/driver_chipcommon_pmu.c | 94 +++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 1a57d3390e9..80f245c0404 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -234,19 +234,15 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev) if ((bus->sprom.boardflags_lo & B43_BFL_FEM) && ((b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) || (bus->sprom.boardflags_hi & B43_BFH_PAREF))) { - /* TODO: - * Set the LDO voltage to 0x0028 - FIXME: What is this? - * Call sb_pmu_set_ldo_voltage with 4 and the LDO voltage - * as arguments - * Call sb_pmu_paref_ldo_enable with argument TRUE - */ + ssb_pmu_set_ldo_voltage(&bus->chipco, LDO_PAREF, 0x28); + ssb_pmu_set_ldo_paref(&bus->chipco, true); if (dev->phy.rev == 0) { b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT, 0xFFCF, 0x0010); } b43_lptab_write(dev, B43_LPTAB16(11, 7), 60); } else { - //TODO: Call ssb_pmu_paref_ldo_enable with argument FALSE + ssb_pmu_set_ldo_paref(&bus->chipco, false); b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT, 0xFFCF, 0x0020); b43_lptab_write(dev, B43_LPTAB16(11, 7), 100); diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c index 4aaddeec55a..64abd11f6fb 100644 --- a/drivers/ssb/driver_chipcommon_pmu.c +++ b/drivers/ssb/driver_chipcommon_pmu.c @@ -28,6 +28,21 @@ static void ssb_chipco_pll_write(struct ssb_chipcommon *cc, chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, value); } +static void ssb_chipco_regctl_maskset(struct ssb_chipcommon *cc, + u32 offset, u32 mask, u32 set) +{ + u32 value; + + chipco_read32(cc, SSB_CHIPCO_REGCTL_ADDR); + chipco_write32(cc, SSB_CHIPCO_REGCTL_ADDR, offset); + chipco_read32(cc, SSB_CHIPCO_REGCTL_ADDR); + value = chipco_read32(cc, SSB_CHIPCO_REGCTL_DATA); + value &= mask; + value |= set; + chipco_write32(cc, SSB_CHIPCO_REGCTL_DATA, value); + chipco_read32(cc, SSB_CHIPCO_REGCTL_DATA); +} + struct pmu0_plltab_entry { u16 freq; /* Crystal frequency in kHz.*/ u8 xf; /* Crystal frequency value for PMU control */ @@ -506,3 +521,82 @@ void ssb_pmu_init(struct ssb_chipcommon *cc) ssb_pmu_pll_init(cc); ssb_pmu_resources_init(cc); } + +void ssb_pmu_set_ldo_voltage(struct ssb_chipcommon *cc, + enum ssb_pmu_ldo_volt_id id, u32 voltage) +{ + struct ssb_bus *bus = cc->dev->bus; + u32 addr, shift, mask; + + switch (bus->chip_id) { + case 0x4328: + case 0x5354: + switch (id) { + case LDO_VOLT1: + addr = 2; + shift = 25; + mask = 0xF; + break; + case LDO_VOLT2: + addr = 3; + shift = 1; + mask = 0xF; + break; + case LDO_VOLT3: + addr = 3; + shift = 9; + mask = 0xF; + break; + case LDO_PAREF: + addr = 3; + shift = 17; + mask = 0x3F; + break; + default: + SSB_WARN_ON(1); + return; + } + break; + case 0x4312: + if (SSB_WARN_ON(id != LDO_PAREF)) + return; + addr = 0; + shift = 21; + mask = 0x3F; + break; + default: + return; + } + + ssb_chipco_regctl_maskset(cc, addr, ~(mask << shift), + (voltage & mask) << shift); +} + +void ssb_pmu_set_ldo_paref(struct ssb_chipcommon *cc, bool on) +{ + struct ssb_bus *bus = cc->dev->bus; + int ldo; + + switch (bus->chip_id) { + case 0x4312: + ldo = SSB_PMURES_4312_PA_REF_LDO; + break; + case 0x4328: + ldo = SSB_PMURES_4328_PA_REF_LDO; + break; + case 0x5354: + ldo = SSB_PMURES_5354_PA_REF_LDO; + break; + default: + return; + } + + if (on) + chipco_set32(cc, SSB_CHIPCO_PMU_MINRES_MSK, 1 << ldo); + else + chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK, ~(1 << ldo)); + chipco_read32(cc, SSB_CHIPCO_PMU_MINRES_MSK); //SPEC FIXME found via mmiotrace - dummy read? +} + +EXPORT_SYMBOL(ssb_pmu_set_ldo_voltage); +EXPORT_SYMBOL(ssb_pmu_set_ldo_paref); -- cgit v1.2.3-18-g5258 From 924d6356b216e592f596595757db8e955391a489 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 26 Aug 2009 21:04:08 +0200 Subject: rt2x00: Cleanup rt2x00mac_bss_info_changed() Since patch "rt2x00: bss_info_changed() callback is allowed to sleep" the variable delayed wasn't used anymore. This means it can be removed along with the call to schedule_work which depended on that variable. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00mac.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index a91f316cd45..929b85f34f3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -582,7 +582,6 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(vif); - unsigned int delayed = 0; int update_bssid = 0; /* @@ -645,13 +644,6 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, */ if (changes & ~(BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) rt2x00lib_config_erp(rt2x00dev, intf, bss_conf); - - spin_lock(&intf->lock); - if (delayed) { - intf->delayed_flags |= delayed; - schedule_work(&rt2x00dev->intf_work); - } - spin_unlock(&intf->lock); } EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed); -- cgit v1.2.3-18-g5258 From 1303dcfd0504565aef8ef63487443ab1f814c00f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Aug 2009 22:15:13 +0200 Subject: iwlwifi: fix ICT irq table endianness The ICT IRQ table is a set of __le32 values, not u32 values, so when reading it we need to take into account that it has to be converted to CPU endianness. This was causing a lot of trouble on my powerpc box where various things would simply not work for no apparent reason with 5xxx cards, but worked with 4965 -- which doesn't use the ICT table. Signed-off-by: Johannes Berg Acked-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 10 +++++----- drivers/net/wireless/iwlwifi/iwl-dev.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c62c081cfbb..0bfd4e91813 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1823,7 +1823,7 @@ int iwl_reset_ict(struct iwl_priv *priv) spin_lock_irqsave(&priv->lock, flags); iwl_disable_interrupts(priv); - memset(&priv->ict_tbl[0],0, sizeof(u32) * ICT_COUNT); + memset(&priv->ict_tbl[0], 0, sizeof(u32) * ICT_COUNT); val = priv->aligned_ict_tbl_dma >> PAGE_SHIFT; @@ -1901,13 +1901,13 @@ irqreturn_t iwl_isr_ict(int irq, void *data) /* read all entries that not 0 start with ict_index */ while (priv->ict_tbl[priv->ict_index]) { - val |= priv->ict_tbl[priv->ict_index]; + val |= le32_to_cpu(priv->ict_tbl[priv->ict_index]); IWL_DEBUG_ISR(priv, "ICT index %d value 0x%08X\n", - priv->ict_index, - priv->ict_tbl[priv->ict_index]); + priv->ict_index, + le32_to_cpu(priv->ict_tbl[priv->ict_index])); priv->ict_tbl[priv->ict_index] = 0; priv->ict_index = iwl_queue_inc_wrap(priv->ict_index, - ICT_COUNT); + ICT_COUNT); } diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index ccea2e4ab45..028d5059955 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1170,7 +1170,7 @@ struct iwl_priv { struct iwl_hw_params hw_params; /* INT ICT Table */ - u32 *ict_tbl; + __le32 *ict_tbl; dma_addr_t ict_tbl_dma; dma_addr_t aligned_ict_tbl_dma; int ict_index; -- cgit v1.2.3-18-g5258 From 00fa928df428521793866ff6832569d99be7f3e3 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Wed, 26 Aug 2009 23:46:18 +0200 Subject: b43: LP-PHY: Revert to the original PHY register write routine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After some discussion on IRC about the PHY register write change, I am not sure anymore if this is the right thing to do. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 80f245c0404..7d2a7027235 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1496,7 +1496,8 @@ static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg) static void b43_lpphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) { - b43_write32(dev, B43_MMIO_PHY_CONTROL, ((u32)value << 16) | reg); + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16(dev, B43_MMIO_PHY_DATA, value); } static void b43_lpphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask, -- cgit v1.2.3-18-g5258 From ca5efbe243dde7d269b6bbae7feaa5e4740db36e Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Thu, 27 Aug 2009 15:17:15 -0400 Subject: ath5k: clarify srev comparison for CCMP check As Pavel Roskin noted, the check for mac version as copied from legacy_hal made no sense. This replaces it with the equivalent and makes up a suitable #define for the mac version legacy_hal checked. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 1 + drivers/net/wireless/ath/ath5k/attach.c | 7 ++----- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index cdc79cd134c..1275ba0990b 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -306,6 +306,7 @@ struct ath5k_srev_name { #define AR5K_SREV_AR5311B 0x30 /* Spirit */ #define AR5K_SREV_AR5211 0x40 /* Oahu */ #define AR5K_SREV_AR5212 0x50 /* Venice */ +#define AR5K_SREV_AR5212_V4 0x54 /* ??? */ #define AR5K_SREV_AR5213 0x55 /* ??? */ #define AR5K_SREV_AR5213A 0x59 /* Hainan */ #define AR5K_SREV_AR2413 0x78 /* Griffin lite */ diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 109ab7ba304..4819f39da70 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -318,12 +318,9 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) /* Crypto settings */ ee = &ah->ah_capabilities.cap_eeprom; - ah->ah_aes_support = + ah->ah_aes_support = srev >= AR5K_SREV_AR5212_V4 && (ee->ee_version >= AR5K_EEPROM_VERSION_5_0 && - !AR5K_EEPROM_AES_DIS(ee->ee_misc5) && - (ah->ah_mac_version > (AR5K_SREV_AR5212 >> 4) || - (ah->ah_mac_version == (AR5K_SREV_AR5212 >> 4) && - ah->ah_mac_revision >= (AR5K_SREV_AR5211 >> 4)))); + !AR5K_EEPROM_AES_DIS(ee->ee_misc5)); if (srev >= AR5K_SREV_AR2414) { ah->ah_combined_mic = true; -- cgit v1.2.3-18-g5258 From 3b3ee43da43aca1cbf4c3651379b2b1492e49dd6 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Wed, 26 Aug 2009 22:30:00 -0400 Subject: ath5k: fix uninitialized value use in ath5k_eeprom_read_turbo_modes() The `val' variable in ath5k_eeprom_read_turbo_modes() is used uninitialized. gcc 4.4.1 with -fno-inline-functions-called-once reports it: eeprom.c: In function 'ath5k_eeprom_read_turbo_modes': eeprom.c:441: warning: 'val' may be used uninitialized in this function Comparing the code to the Atheros HAL, it's clear that the split between ath5k_eeprom_read_modes() and ath5k_eeprom_read_turbo_modes() was incorrect. The Atheros HAL reads both turbo and non-turbo data from EEPROM in one function. Some turbo mode parameters are derived from the same EEPROM values as non-turbo parameters, just from different bits. Merge ath5k_eeprom_read_turbo_modes() into ath5k_eeprom_read_modes() to fix the warning. The actual values and offsets have been cross-checked against Atheros HAL. Signed-off-by: Pavel Roskin Acked-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/eeprom.c | 29 +++++------------------------ 1 file changed, 5 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index 8af477dd6fc..644962adda9 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -414,27 +414,11 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, break; } -done: - /* return new offset */ - *offset = o; - - return 0; -} - -/* - * Read turbo mode information on newer EEPROM versions - */ -static int -ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah, - u32 *offset, unsigned int mode) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - u32 o = *offset; - u16 val; - int ret; - + /* + * Read turbo mode information on newer EEPROM versions + */ if (ee->ee_version < AR5K_EEPROM_VERSION_5_0) - return 0; + goto done; switch (mode){ case AR5K_EEPROM_MODE_11A: @@ -468,6 +452,7 @@ ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah, break; } +done: /* return new offset */ *offset = o; @@ -504,10 +489,6 @@ ath5k_eeprom_init_modes(struct ath5k_hw *ah) ret = ath5k_eeprom_read_modes(ah, &offset, mode); if (ret) return ret; - - ret = ath5k_eeprom_read_turbo_modes(ah, &offset, mode); - if (ret) - return ret; } /* override for older eeprom versions for better performance */ -- cgit v1.2.3-18-g5258 From 97a81f5c5033cb02ae56dd80ff9c38866c777bd8 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Wed, 26 Aug 2009 22:30:09 -0400 Subject: ath5k: don't use PCI ID to find the chip revision AR5K_SREV is available even if the chip has been put to sleep. Relying on the chip register allows binding non-standard PCI IDs by echo VENDOR_ID PRODUCT_ID >/sys/bus/pci/drivers/ath5k/new_id without having to specify the driver data as well. Signed-off-by: Pavel Roskin Acked-by: Bob Copeland Acked-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 2 +- drivers/net/wireless/ath/ath5k/attach.c | 14 +++++++----- drivers/net/wireless/ath/ath5k/base.c | 38 ++++++++++++++++----------------- 3 files changed, 29 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 1275ba0990b..6cd5efcec41 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1160,7 +1160,7 @@ struct ath5k_hw { */ /* Attach/Detach Functions */ -extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version); +extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc); extern void ath5k_hw_detach(struct ath5k_hw *ah); /* LED functions */ diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 4819f39da70..71a1bd25451 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -95,14 +95,13 @@ static int ath5k_hw_post(struct ath5k_hw *ah) * ath5k_hw_attach - Check if hw is supported and init the needed structs * * @sc: The &struct ath5k_softc we got from the driver's attach function - * @mac_version: The mac version id (check out ath5k.h) based on pci id * * Check if the device is supported, perform a POST and initialize the needed * structs. Returns -ENOMEM if we don't have memory for the needed structs, * -ENODEV if the device is not supported or prints an error msg if something * else went wrong. */ -struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) +struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc) { struct ath5k_hw *ah; struct pci_dev *pdev = sc->pdev; @@ -136,9 +135,15 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) ah->ah_software_retry = false; /* - * Set the mac version based on the pci id + * Find the mac version */ - ah->ah_version = mac_version; + srev = ath5k_hw_reg_read(ah, AR5K_SREV); + if (srev < AR5K_SREV_AR5311) + ah->ah_version = AR5K_AR5210; + else if (srev < AR5K_SREV_AR5212) + ah->ah_version = AR5K_AR5211; + else + ah->ah_version = AR5K_AR5212; /*Fill the ath5k_hw struct with the needed functions*/ ret = ath5k_hw_init_desc_functions(ah); @@ -151,7 +156,6 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) goto err_free; /* Get MAC, PHY and RADIO revisions */ - srev = ath5k_hw_reg_read(ah, AR5K_SREV); ah->ah_mac_srev = srev; ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER); ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 94d46fd94ff..9c6ab5378f6 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -84,24 +84,24 @@ MODULE_VERSION("0.6.0 (EXPERIMENTAL)"); /* Known PCI ids */ static const struct pci_device_id ath5k_pci_id_table[] = { - { PCI_VDEVICE(ATHEROS, 0x0207), .driver_data = AR5K_AR5210 }, /* 5210 early */ - { PCI_VDEVICE(ATHEROS, 0x0007), .driver_data = AR5K_AR5210 }, /* 5210 */ - { PCI_VDEVICE(ATHEROS, 0x0011), .driver_data = AR5K_AR5211 }, /* 5311 - this is on AHB bus !*/ - { PCI_VDEVICE(ATHEROS, 0x0012), .driver_data = AR5K_AR5211 }, /* 5211 */ - { PCI_VDEVICE(ATHEROS, 0x0013), .driver_data = AR5K_AR5212 }, /* 5212 */ - { PCI_VDEVICE(3COM_2, 0x0013), .driver_data = AR5K_AR5212 }, /* 3com 5212 */ - { PCI_VDEVICE(3COM, 0x0013), .driver_data = AR5K_AR5212 }, /* 3com 3CRDAG675 5212 */ - { PCI_VDEVICE(ATHEROS, 0x1014), .driver_data = AR5K_AR5212 }, /* IBM minipci 5212 */ - { PCI_VDEVICE(ATHEROS, 0x0014), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ - { PCI_VDEVICE(ATHEROS, 0x0015), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ - { PCI_VDEVICE(ATHEROS, 0x0016), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ - { PCI_VDEVICE(ATHEROS, 0x0017), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ - { PCI_VDEVICE(ATHEROS, 0x0018), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ - { PCI_VDEVICE(ATHEROS, 0x0019), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ - { PCI_VDEVICE(ATHEROS, 0x001a), .driver_data = AR5K_AR5212 }, /* 2413 Griffin-lite */ - { PCI_VDEVICE(ATHEROS, 0x001b), .driver_data = AR5K_AR5212 }, /* 5413 Eagle */ - { PCI_VDEVICE(ATHEROS, 0x001c), .driver_data = AR5K_AR5212 }, /* PCI-E cards */ - { PCI_VDEVICE(ATHEROS, 0x001d), .driver_data = AR5K_AR5212 }, /* 2417 Nala */ + { PCI_VDEVICE(ATHEROS, 0x0207) }, /* 5210 early */ + { PCI_VDEVICE(ATHEROS, 0x0007) }, /* 5210 */ + { PCI_VDEVICE(ATHEROS, 0x0011) }, /* 5311 - this is on AHB bus !*/ + { PCI_VDEVICE(ATHEROS, 0x0012) }, /* 5211 */ + { PCI_VDEVICE(ATHEROS, 0x0013) }, /* 5212 */ + { PCI_VDEVICE(3COM_2, 0x0013) }, /* 3com 5212 */ + { PCI_VDEVICE(3COM, 0x0013) }, /* 3com 3CRDAG675 5212 */ + { PCI_VDEVICE(ATHEROS, 0x1014) }, /* IBM minipci 5212 */ + { PCI_VDEVICE(ATHEROS, 0x0014) }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0015) }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0016) }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0017) }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0018) }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0019) }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x001a) }, /* 2413 Griffin-lite */ + { PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */ + { PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */ + { PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */ { 0 } }; MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table); @@ -566,7 +566,7 @@ ath5k_pci_probe(struct pci_dev *pdev, } /* Initialize device */ - sc->ah = ath5k_hw_attach(sc, id->driver_data); + sc->ah = ath5k_hw_attach(sc); if (IS_ERR(sc->ah)) { ret = PTR_ERR(sc->ah); goto err_irq; -- cgit v1.2.3-18-g5258 From 867b2efe68b6bb929e3bd1c6d699ba61ff2cf847 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Thu, 27 Aug 2009 17:24:23 +0200 Subject: b43: Enable LP-PHY support by default and remove Kconfig warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The most common LP-PHY device, BCM4312, is now fully functional. So, no need to say "probably won't work for you" anymore. It's also not "for debuggers and developers only", as it is perfectly usable for end-users now (at least for BCM4312). Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/Kconfig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 237b1aadf9b..2af3b352232 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -82,15 +82,13 @@ config B43_NPHY config B43_PHY_LP bool "Support for low-power (LP-PHY) devices (EXPERIMENTAL)" depends on B43 && EXPERIMENTAL + default y ---help--- Support for the LP-PHY. The LP-PHY is a low-power PHY built into some notebooks and embedded devices. It supports 802.11a/g (802.11a support is optional, and currently disabled). - This is heavily experimental, and probably will not work for you. - Say N unless you want to help debug the driver. - # This config option automatically enables b43 LEDS support, # if it's possible. config B43_LEDS -- cgit v1.2.3-18-g5258 From 64e368bf9c3690eebd4b3a5cc243f39e902ecdd1 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Thu, 27 Aug 2009 22:49:49 +0200 Subject: b43: Implement antenna diversity support for LP-PHY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The A/G-PHY changes are fallout fixes from the enum change, which in turn allows the LP-PHY code to be much simpler. The antenna_to_phyctl change is a fix for a potential existing bug that this patch may otherwise trigger. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 3 ++- drivers/net/wireless/b43/phy_a.c | 2 +- drivers/net/wireless/b43/phy_common.h | 10 +++++----- drivers/net/wireless/b43/phy_g.c | 2 +- drivers/net/wireless/b43/phy_lp.c | 9 ++++++++- 5 files changed, 17 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index f5bdf1cae1d..0f168443ad4 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1456,7 +1456,8 @@ static u16 b43_antenna_to_phyctl(int antenna) return B43_TXH_PHY_ANT2; case B43_ANTENNA3: return B43_TXH_PHY_ANT3; - case B43_ANTENNA_AUTO: + case B43_ANTENNA_AUTO0: + case B43_ANTENNA_AUTO1: return B43_TXH_PHY_ANT01AUTO; } B43_WARN_ON(1); diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index 816e028a262..809ec97031c 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c @@ -531,7 +531,7 @@ static void b43_aphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) tmp = b43_phy_read(dev, B43_PHY_BBANDCFG); tmp &= ~B43_PHY_BBANDCFG_RXANT; - tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) + tmp |= (autodiv ? B43_ANTENNA_AUTO1 : antenna) << B43_PHY_BBANDCFG_RXANT_SHIFT; b43_phy_write(dev, B43_PHY_BBANDCFG, tmp); diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index b47a0f55c0b..28e384633c3 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -49,11 +49,11 @@ enum b43_interference_mitigation { /* Antenna identifiers */ enum { - B43_ANTENNA0, /* Antenna 0 */ - B43_ANTENNA1, /* Antenna 0 */ - B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */ - B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */ - B43_ANTENNA2, + B43_ANTENNA0 = 0, /* Antenna 0 */ + B43_ANTENNA1 = 1, /* Antenna 1 */ + B43_ANTENNA_AUTO0 = 2, /* Automatic, starting with antenna 0 */ + B43_ANTENNA_AUTO1 = 3, /* Automatic, starting with antenna 1 */ + B43_ANTENNA2 = 4, B43_ANTENNA3 = 8, B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0, diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index e47131216a6..bdff9afe3f8 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -2664,7 +2664,7 @@ static void b43_gphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) tmp = b43_phy_read(dev, B43_PHY_BBANDCFG); tmp &= ~B43_PHY_BBANDCFG_RXANT; - tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) + tmp |= (autodiv ? B43_ANTENNA_AUTO1 : antenna) << B43_PHY_BBANDCFG_RXANT_SHIFT; b43_phy_write(dev, B43_PHY_BBANDCFG, tmp); diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 7d2a7027235..1ab00b034cb 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -2205,7 +2205,14 @@ static int b43_lpphy_op_init(struct b43_wldev *dev) static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) { - //TODO + if (dev->phy.rev >= 2) + return; // rev2+ doesn't support antenna diversity + + if (B43_WARN_ON(antenna > B43_ANTENNA_AUTO1)) + return; + + b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFD, antenna & 0x2); + b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFE, antenna & 0x1); } static void b43_lpphy_op_adjust_txpower(struct b43_wldev *dev) -- cgit v1.2.3-18-g5258 From 5f81ff5a7a12a9281d03be103382971ce490268e Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 12:58:49 +0300 Subject: rndis_wlan: ignore OID_802_11_ADD_KEY triggered media connect indications Setting WPA keys with OID_802_11_ADD_KEY sometimes trigger instant media connect indication. These indications are extranous and should be ignored, as otherwise driver would send reassociation event to userspace which in this case is not needed. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index f181b00f253..612c2c75a99 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -470,6 +470,7 @@ struct rndis_wlan_private { int radio_on; int infra_mode; struct ndis_80211_ssid essid; + __le32 current_command_oid; /* encryption stuff */ int encr_tx_key_index; @@ -665,7 +666,9 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) u.get->msg_len = cpu_to_le32(sizeof *u.get); u.get->oid = oid; + priv->current_command_oid = oid; ret = rndis_command(dev, u.header, buflen); + priv->current_command_oid = 0; if (ret < 0) devdbg(dev, "rndis_query_oid(%s): rndis_command() failed, %d " "(%08x)", oid_to_string(oid), ret, @@ -725,7 +728,9 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) u.set->handle = cpu_to_le32(0); memcpy(u.buf + sizeof(*u.set), data, len); + priv->current_command_oid = oid; ret = rndis_command(dev, u.header, buflen); + priv->current_command_oid = 0; if (ret < 0) devdbg(dev, "rndis_set_oid(%s): rndis_command() failed, %d " "(%08x)", oid_to_string(oid), ret, @@ -760,6 +765,7 @@ static int rndis_reset(struct usbnet *usbdev) memset(reset, 0, sizeof(*reset)); reset->msg_type = RNDIS_MSG_RESET; reset->msg_len = cpu_to_le32(sizeof(*reset)); + priv->current_command_oid = 0; ret = rndis_command(usbdev, (void *)reset, CONTROL_BUFFER_SIZE); mutex_unlock(&priv->command_lock); @@ -2558,6 +2564,17 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) switch (msg->status) { case RNDIS_STATUS_MEDIA_CONNECT: + if (priv->current_command_oid == OID_802_11_ADD_KEY) { + /* OID_802_11_ADD_KEY causes sometimes extra + * "media connect" indications which confuses driver + * and userspace to think that device is + * roaming/reassociating when it isn't. + */ + devdbg(usbdev, "ignored OID_802_11_ADD_KEY triggered " + "'media connect'"); + return; + } + usbnet_pause_rx(usbdev); devinfo(usbdev, "media connect"); -- cgit v1.2.3-18-g5258 From db0dd396da45502e02c64c4153c5822ab5a59a5f Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 12:58:55 +0300 Subject: rndis_wlan: get bssid scan list before new scan OID_802_11_BSSID_LIST_SCAN clears device's bssid list, so retrieve current bssid list from device before issuing new scan. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 612c2c75a99..37796210db5 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -926,6 +926,7 @@ static int freq_to_dsconfig(struct iw_freq *freq, unsigned int *dsconfig) * common functions */ static void restore_keys(struct usbnet *usbdev); +static int rndis_check_bssid_list(struct usbnet *usbdev); static int get_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) { @@ -1616,6 +1617,11 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, devdbg(usbdev, "cfg80211.scan"); + /* Get current bssid list from device before new scan, as new scan + * clears internal bssid list. + */ + rndis_check_bssid_list(usbdev); + if (!request) return -EINVAL; -- cgit v1.2.3-18-g5258 From 5fd8f2503b0888ed0c8e0017264059a3f9dc51c0 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 12:59:00 +0300 Subject: rndis_wlan: resize bssid list if too small Buffer used for bssid list might be too small. Change rndis_query_oid() to return required buffer length to caller and make rndis_check_bssid_list() resize buffer when needed. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 37796210db5..2309ad2214a 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -676,7 +676,8 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) if (ret == 0) { ret = le32_to_cpu(u.get_c->len); - *len = (*len > ret) ? ret : *len; + if (ret > *len) + *len = ret; memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len); ret = rndis_error_status(u.get_c->status); @@ -1656,6 +1657,9 @@ static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev, int ie_len, bssid_len; u8 *ie; + devdbg(usbdev, " found bssid: '%.32s' [%pM]", bssid->ssid.essid, + bssid->mac); + /* parse bssid structure */ bssid_len = le32_to_cpu(bssid->length); @@ -1695,10 +1699,12 @@ static int rndis_check_bssid_list(struct usbnet *usbdev) struct ndis_80211_bssid_list_ex *bssid_list; struct ndis_80211_bssid_ex *bssid; int ret = -EINVAL, len, count, bssid_len; + bool resized = false; devdbg(usbdev, "check_bssid_list"); len = CONTROL_BUFFER_SIZE; +resize_buf: buf = kmalloc(len, GFP_KERNEL); if (!buf) { ret = -ENOMEM; @@ -1709,11 +1715,18 @@ static int rndis_check_bssid_list(struct usbnet *usbdev) if (ret != 0) goto out; + if (!resized && len > CONTROL_BUFFER_SIZE) { + resized = true; + kfree(buf); + goto resize_buf; + } + bssid_list = buf; bssid = bssid_list->bssid; bssid_len = le32_to_cpu(bssid->length); count = le32_to_cpu(bssid_list->num_items); - devdbg(usbdev, "check_bssid_list: %d BSSIDs found", count); + devdbg(usbdev, "check_bssid_list: %d BSSIDs found (buflen: %d)", count, + len); while (count && ((void *)bssid + bssid_len) <= (buf + len)) { rndis_bss_info_update(usbdev, bssid); -- cgit v1.2.3-18-g5258 From b1d25a67647efacf2a9f2a1800f0c8195827f923 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 12:59:05 +0300 Subject: rndis_wlan: increase scan timer delay Increase scan delay from 1 sec to 6 sec. Spec says that scan by OID_802_11_BSSID_LIST_SCAN completes in 6 seconds. Before rfkill patch too short delay was not problem as device was always active (radio on) and performing background scanning. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 2309ad2214a..cb362b086ff 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1607,7 +1607,7 @@ static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm) } -#define SCAN_DELAY_JIFFIES (HZ) +#define SCAN_DELAY_JIFFIES (6 * HZ) static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request) { -- cgit v1.2.3-18-g5258 From 0848e6c698237ba51c69eca10580d2f38a1179ad Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 12:59:10 +0300 Subject: rndis_wlan: move link up/down work to separate functions Move link up/down work to separate functions and use local array for allocating memory for info structure instead of kzmalloc. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 101 +++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index cb362b086ff..dc3083ba838 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2319,68 +2319,77 @@ static const struct iw_handler_def rndis_iw_handlers = { }; -static void rndis_wlan_worker(struct work_struct *work) +static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) { - struct rndis_wlan_private *priv = - container_of(work, struct rndis_wlan_private, work); - struct usbnet *usbdev = priv->usbdev; - union iwreq_data evt; - unsigned char bssid[ETH_ALEN]; struct ndis_80211_assoc_info *info; - int assoc_size = sizeof(*info) + IW_CUSTOM_MAX + 32; + union iwreq_data evt; + u8 assoc_buf[sizeof(*info) + IW_CUSTOM_MAX + 32]; + u8 bssid[ETH_ALEN]; int ret, offset; - if (test_and_clear_bit(WORK_LINK_UP, &priv->work_pending)) { - netif_carrier_on(usbdev->net); - - info = kzalloc(assoc_size, GFP_KERNEL); - if (!info) - goto get_bssid; - - /* Get association info IEs from device and send them back to - * userspace. */ - ret = get_association_info(usbdev, info, assoc_size); - if (!ret) { - evt.data.length = le32_to_cpu(info->req_ie_length); - if (evt.data.length > 0) { - offset = le32_to_cpu(info->offset_req_ies); - wireless_send_event(usbdev->net, - IWEVASSOCREQIE, &evt, - (char *)info + offset); - } - - evt.data.length = le32_to_cpu(info->resp_ie_length); - if (evt.data.length > 0) { - offset = le32_to_cpu(info->offset_resp_ies); - wireless_send_event(usbdev->net, - IWEVASSOCRESPIE, &evt, - (char *)info + offset); - } + memset(assoc_buf, 0, sizeof(assoc_buf)); + info = (void *)assoc_buf; + + netif_carrier_on(usbdev->net); + + /* Get association info IEs from device and send them back to + * userspace. */ + ret = get_association_info(usbdev, info, sizeof(assoc_buf)); + if (!ret) { + evt.data.length = le32_to_cpu(info->req_ie_length); + if (evt.data.length > 0) { + offset = le32_to_cpu(info->offset_req_ies); + wireless_send_event(usbdev->net, + IWEVASSOCREQIE, &evt, + (char *)info + offset); } - kfree(info); - -get_bssid: - ret = get_bssid(usbdev, bssid); - if (!ret) { - evt.data.flags = 0; - evt.data.length = 0; - memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN); - wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL); + evt.data.length = le32_to_cpu(info->resp_ie_length); + if (evt.data.length > 0) { + offset = le32_to_cpu(info->offset_resp_ies); + wireless_send_event(usbdev->net, + IWEVASSOCRESPIE, &evt, + (char *)info + offset); } usbnet_resume_rx(usbdev); } - if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) { - netif_carrier_off(usbdev->net); - + ret = get_bssid(usbdev, bssid); + if (!ret) { evt.data.flags = 0; evt.data.length = 0; - memset(evt.ap_addr.sa_data, 0, ETH_ALEN); + memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN); wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL); } + usbnet_resume_rx(usbdev); +} + +static void rndis_wlan_do_link_down_work(struct usbnet *usbdev) +{ + union iwreq_data evt; + + netif_carrier_off(usbdev->net); + + evt.data.flags = 0; + evt.data.length = 0; + memset(evt.ap_addr.sa_data, 0, ETH_ALEN); + wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL); +} + +static void rndis_wlan_worker(struct work_struct *work) +{ + struct rndis_wlan_private *priv = + container_of(work, struct rndis_wlan_private, work); + struct usbnet *usbdev = priv->usbdev; + + if (test_and_clear_bit(WORK_LINK_UP, &priv->work_pending)) + rndis_wlan_do_link_up_work(usbdev); + + if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending)) + rndis_wlan_do_link_down_work(usbdev); + if (test_and_clear_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending)) set_multicast_list(usbdev); } -- cgit v1.2.3-18-g5258 From 7b1fff996a5408261ca458f82369d1f5b7aad2d4 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 12:59:15 +0300 Subject: rndis_wlan: use is_zero_ether_addr() and is_broadcast_ether_addr() Use is_zero_ether_addr() and is_broadcast_ether_addr() instead of memcmp against ffff_bssid/zero_bssid. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index dc3083ba838..c28fde59c32 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -514,11 +514,6 @@ static struct cfg80211_ops rndis_config_ops = { static void *rndis_wiphy_privid = &rndis_wiphy_privid; -static const unsigned char zero_bssid[ETH_ALEN] = {0,}; -static const unsigned char ffff_bssid[ETH_ALEN] = { 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff }; - - static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev) { return (struct rndis_wlan_private *)dev->driver_priv; @@ -995,7 +990,7 @@ static int is_associated(struct usbnet *usbdev) ret = get_bssid(usbdev, bssid); - return(ret == 0 && memcmp(bssid, zero_bssid, ETH_ALEN) != 0); + return (ret == 0 && !is_zero_ether_addr(bssid)); } @@ -1293,8 +1288,8 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, devdbg(usbdev, "add_wpa_key: recv seq flag without buffer"); return -EINVAL; } - is_addr_ok = addr && memcmp(addr, zero_bssid, ETH_ALEN) != 0 && - memcmp(addr, ffff_bssid, ETH_ALEN) != 0; + is_addr_ok = addr && !is_zero_ether_addr(addr) && + !is_broadcast_ether_addr(addr); if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !is_addr_ok) { devdbg(usbdev, "add_wpa_key: pairwise but bssid invalid (%pM)", addr); @@ -1379,8 +1374,8 @@ static int restore_key(struct usbnet *usbdev, int key_idx) /*if (priv->encr_tx_key_index == key_idx) flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY;*/ - if (memcmp(key.bssid, zero_bssid, ETH_ALEN) != 0 && - memcmp(key.bssid, ffff_bssid, ETH_ALEN) != 0) + if (!is_zero_ether_addr(key.bssid) && + !is_broadcast_ether_addr(key.bssid)) flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY; return add_wpa_key(usbdev, key.material, key.len, key_idx, @@ -1430,7 +1425,7 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) remove_key.index = cpu_to_le32(index); if (bssid) { /* pairwise key */ - if (memcmp(bssid, ffff_bssid, ETH_ALEN) != 0) + if (!is_broadcast_ether_addr(bssid)) remove_key.index |= NDIS_80211_ADDKEY_PAIRWISE_KEY; memcpy(remove_key.bssid, bssid, -- cgit v1.2.3-18-g5258 From 161391725eba1f07e98594369cfcb10c848ef352 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 12:59:21 +0300 Subject: rndis_wlan: set ieee80211_ptr->iftype in rndis_change_virtual_intf Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index c28fde59c32..d11762011dc 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1526,7 +1526,8 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { - struct usbnet *usbdev = netdev_priv(dev); + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; int mode; switch (type) { @@ -1540,6 +1541,8 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, return -EINVAL; } + priv->wdev.iftype = type; + return set_infra_mode(usbdev, mode); } -- cgit v1.2.3-18-g5258 From 9f77ccab57534f45b0289ceae3a6b85478d14182 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 12:59:26 +0300 Subject: rndis_wlan: enable infrastructure before setting random essid Random essid must be set to turn on radio when not connected. If device is in ad-hoc mode, this results 'media connect' indications with the random essid which should be ignored. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index d11762011dc..c5a674d8d1f 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -921,6 +921,7 @@ static int freq_to_dsconfig(struct iw_freq *freq, unsigned int *dsconfig) /* * common functions */ +static int set_infra_mode(struct usbnet *usbdev, int mode); static void restore_keys(struct usbnet *usbdev); static int rndis_check_bssid_list(struct usbnet *usbdev); @@ -1014,6 +1015,11 @@ static int disassociate(struct usbnet *usbdev, int reset_ssid) /* disassociate causes radio to be turned off; if reset_ssid * is given, set random ssid to enable radio */ if (reset_ssid) { + /* Set device to infrastructure mode so we don't get ad-hoc + * 'media connect' indications with the random ssid. + */ + set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); + ssid.length = cpu_to_le32(sizeof(ssid.essid)); get_random_bytes(&ssid.essid[2], sizeof(ssid.essid)-2); ssid.essid[0] = 0x1; -- cgit v1.2.3-18-g5258 From 5c52323e8c44a06183052986dbd028ce15622166 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 13:27:47 +0300 Subject: rndis_wlan: add cfg80211 connect, disconnect, join_ibss and leave_ibss Add cfg80211 connect functions for station and ad-hoc modes and convert wext to use theim. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 669 ++++++++++++++++++++++++++------------ 1 file changed, 460 insertions(+), 209 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index c5a674d8d1f..c2af5be35d3 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -358,13 +358,6 @@ struct ndis_80211_assoc_info { __le32 offset_resp_ies; } __attribute__((packed)); -/* these have to match what is in wpa_supplicant */ -enum wpa_alg { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP }; -enum wpa_cipher { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP, - CIPHER_WEP104 }; -enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, - KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE }; - /* * private data */ @@ -379,6 +372,15 @@ enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, #define WORK_LINK_DOWN (1<<1) #define WORK_SET_MULTICAST_LIST (1<<2) +#define RNDIS_WLAN_ALG_NONE 0 +#define RNDIS_WLAN_ALG_WEP (1<<0) +#define RNDIS_WLAN_ALG_TKIP (1<<1) +#define RNDIS_WLAN_ALG_CCMP (1<<2) + +#define RNDIS_WLAN_KEY_MGMT_NONE 0 +#define RNDIS_WLAN_KEY_MGMT_802_1X (1<<0) +#define RNDIS_WLAN_KEY_MGMT_PSK (1<<1) + #define COMMAND_BUFFER_SIZE (CONTROL_BUFFER_SIZE + sizeof(struct rndis_set)) static const struct ieee80211_channel rndis_channels[] = { @@ -469,15 +471,16 @@ struct rndis_wlan_private { /* hardware state */ int radio_on; int infra_mode; + bool connected; struct ndis_80211_ssid essid; __le32 current_command_oid; /* encryption stuff */ int encr_tx_key_index; struct rndis_wlan_encr_key encr_keys[4]; + enum nl80211_auth_type wpa_auth_type; int wpa_version; int wpa_keymgmt; - int wpa_authalg; int wpa_ie_len; u8 *wpa_ie; int wpa_cipher_pair; @@ -503,12 +506,27 @@ static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, int dbm); static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm); +static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme); + +static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code); + +static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params); + +static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev); + static struct cfg80211_ops rndis_config_ops = { .change_virtual_intf = rndis_change_virtual_intf, .scan = rndis_scan, .set_wiphy_params = rndis_set_wiphy_params, .set_tx_power = rndis_set_tx_power, .get_tx_power = rndis_get_tx_power, + .connect = rndis_connect, + .disconnect = rndis_disconnect, + .join_ibss = rndis_join_ibss, + .leave_ibss = rndis_leave_ibss, }; static void *rndis_wiphy_privid = &rndis_wiphy_privid; @@ -545,6 +563,34 @@ static bool is_wpa_key(struct rndis_wlan_private *priv, int idx) } +static int rndis_cipher_to_alg(u32 cipher) +{ + switch (cipher) { + default: + return RNDIS_WLAN_ALG_NONE; + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + return RNDIS_WLAN_ALG_WEP; + case WLAN_CIPHER_SUITE_TKIP: + return RNDIS_WLAN_ALG_TKIP; + case WLAN_CIPHER_SUITE_CCMP: + return RNDIS_WLAN_ALG_CCMP; + } +} + +static int rndis_akm_suite_to_key_mgmt(u32 akm_suite) +{ + switch (akm_suite) { + default: + return RNDIS_WLAN_KEY_MGMT_NONE; + case WLAN_AKM_SUITE_8021X: + return RNDIS_WLAN_KEY_MGMT_802_1X; + case WLAN_AKM_SUITE_PSK: + return RNDIS_WLAN_KEY_MGMT_PSK; + } +} + + #ifdef DEBUG static const char *oid_to_string(__le32 oid) { @@ -925,35 +971,16 @@ static int set_infra_mode(struct usbnet *usbdev, int mode); static void restore_keys(struct usbnet *usbdev); static int rndis_check_bssid_list(struct usbnet *usbdev); -static int get_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) -{ - int ret, len; - - len = sizeof(*ssid); - ret = rndis_query_oid(usbdev, OID_802_11_SSID, ssid, &len); - - if (ret != 0) - ssid->length = 0; - -#ifdef DEBUG - { - unsigned char tmp[NDIS_802_11_LENGTH_SSID + 1]; - - memcpy(tmp, ssid->essid, le32_to_cpu(ssid->length)); - tmp[le32_to_cpu(ssid->length)] = 0; - devdbg(usbdev, "get_essid: '%s', ret: %d", tmp, ret); - } -#endif - return ret; -} - - static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret; ret = rndis_set_oid(usbdev, OID_802_11_SSID, ssid, sizeof(*ssid)); + if (ret < 0) { + devwarn(usbdev, "setting SSID failed (%08X)", ret); + return ret; + } if (ret == 0) { memcpy(&priv->essid, ssid, sizeof(priv->essid)); priv->radio_on = 1; @@ -963,6 +990,25 @@ static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) return ret; } +static int set_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN]) +{ + int ret; + + ret = rndis_set_oid(usbdev, OID_802_11_BSSID, bssid, ETH_ALEN); + if (ret < 0) { + devwarn(usbdev, "setting BSSID[%pM] failed (%08X)", bssid, ret); + return ret; + } + + return ret; +} + +static int clear_bssid(struct usbnet *usbdev) +{ + u8 broadcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + return set_bssid(usbdev, broadcast_mac); +} static int get_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN]) { @@ -984,11 +1030,15 @@ static int get_association_info(struct usbnet *usbdev, info, &len); } -static int is_associated(struct usbnet *usbdev) +static bool is_associated(struct usbnet *usbdev) { + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); u8 bssid[ETH_ALEN]; int ret; + if (!priv->radio_on) + return false; + ret = get_bssid(usbdev, bssid); return (ret == 0 && !is_zero_ether_addr(bssid)); @@ -1032,34 +1082,34 @@ static int disassociate(struct usbnet *usbdev, int reset_ssid) } -static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg) +static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version, + enum nl80211_auth_type auth_type, int keymgmt) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; int auth_mode, ret; devdbg(usbdev, "set_auth_mode: wpa_version=0x%x authalg=0x%x " - "keymgmt=0x%x", wpa_version, authalg, priv->wpa_keymgmt); + "keymgmt=0x%x", wpa_version, auth_type, keymgmt); - if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) { - if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X) + if (wpa_version & NL80211_WPA_VERSION_2) { + if (keymgmt & RNDIS_WLAN_KEY_MGMT_802_1X) auth_mode = NDIS_80211_AUTH_WPA2; else auth_mode = NDIS_80211_AUTH_WPA2_PSK; - } else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) { - if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X) + } else if (wpa_version & NL80211_WPA_VERSION_1) { + if (keymgmt & RNDIS_WLAN_KEY_MGMT_802_1X) auth_mode = NDIS_80211_AUTH_WPA; - else if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_PSK) + else if (keymgmt & RNDIS_WLAN_KEY_MGMT_PSK) auth_mode = NDIS_80211_AUTH_WPA_PSK; else auth_mode = NDIS_80211_AUTH_WPA_NONE; - } else if (authalg & IW_AUTH_ALG_SHARED_KEY) { - if (authalg & IW_AUTH_ALG_OPEN_SYSTEM) - auth_mode = NDIS_80211_AUTH_AUTO_SWITCH; - else - auth_mode = NDIS_80211_AUTH_SHARED; - } else + } else if (auth_type == NL80211_AUTHTYPE_SHARED_KEY) + auth_mode = NDIS_80211_AUTH_SHARED; + else if (auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) auth_mode = NDIS_80211_AUTH_OPEN; + else + return -ENOTSUPP; tmp = cpu_to_le32(auth_mode); ret = rndis_set_oid(usbdev, OID_802_11_AUTHENTICATION_MODE, &tmp, @@ -1070,7 +1120,9 @@ static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg) } priv->wpa_version = wpa_version; - priv->wpa_authalg = authalg; + priv->wpa_auth_type = auth_type; + priv->wpa_keymgmt = keymgmt; + return 0; } @@ -1082,8 +1134,8 @@ static int set_priv_filter(struct usbnet *usbdev) devdbg(usbdev, "set_priv_filter: wpa_version=0x%x", priv->wpa_version); - if (priv->wpa_version & IW_AUTH_WPA_VERSION_WPA2 || - priv->wpa_version & IW_AUTH_WPA_VERSION_WPA) + if (priv->wpa_version & NL80211_WPA_VERSION_2 || + priv->wpa_version & NL80211_WPA_VERSION_1) tmp = cpu_to_le32(NDIS_80211_PRIV_8021X_WEP); else tmp = cpu_to_le32(NDIS_80211_PRIV_ACCEPT_ALL); @@ -1100,19 +1152,17 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) int encr_mode, ret; devdbg(usbdev, "set_encr_mode: cipher_pair=0x%x cipher_group=0x%x", - pairwise, - groupwise); + pairwise, groupwise); - if (pairwise & IW_AUTH_CIPHER_CCMP) + if (pairwise & RNDIS_WLAN_ALG_CCMP) encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; - else if (pairwise & IW_AUTH_CIPHER_TKIP) + else if (pairwise & RNDIS_WLAN_ALG_TKIP) encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; - else if (pairwise & - (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104)) + else if (pairwise & RNDIS_WLAN_ALG_WEP) encr_mode = NDIS_80211_ENCR_WEP_ENABLED; - else if (groupwise & IW_AUTH_CIPHER_CCMP) + else if (groupwise & RNDIS_WLAN_ALG_CCMP) encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; - else if (groupwise & IW_AUTH_CIPHER_TKIP) + else if (groupwise & RNDIS_WLAN_ALG_TKIP) encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; else encr_mode = NDIS_80211_ENCR_DISABLED; @@ -1131,18 +1181,6 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) } -static int set_assoc_params(struct usbnet *usbdev) -{ - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - set_auth_mode(usbdev, priv->wpa_version, priv->wpa_authalg); - set_priv_filter(usbdev); - set_encr_mode(usbdev, priv->wpa_cipher_pair, priv->wpa_cipher_group); - - return 0; -} - - static int set_infra_mode(struct usbnet *usbdev, int mode) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -1201,16 +1239,11 @@ static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold) static void set_default_iw_params(struct usbnet *usbdev) { - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - priv->wpa_keymgmt = 0; - priv->wpa_version = 0; - set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); - set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED, - IW_AUTH_ALG_OPEN_SYSTEM); + set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_OPEN_SYSTEM, + RNDIS_WLAN_KEY_MGMT_NONE); set_priv_filter(usbdev); - set_encr_mode(usbdev, IW_AUTH_CIPHER_NONE, IW_AUTH_CIPHER_NONE); + set_encr_mode(usbdev, RNDIS_WLAN_ALG_NONE, RNDIS_WLAN_ALG_NONE); } @@ -1224,8 +1257,40 @@ static int deauthenticate(struct usbnet *usbdev) } +static int set_channel(struct usbnet *usbdev, int channel) +{ + struct ndis_80211_conf config; + unsigned int dsconfig; + int len, ret; + + devdbg(usbdev, "set_channel(%d)", channel); + + /* this OID is valid only when not associated */ + if (is_associated(usbdev)) + return 0; + + dsconfig = ieee80211_dsss_chan_to_freq(channel) * 1000; + + len = sizeof(config); + ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len); + if (ret < 0) { + devdbg(usbdev, "set_channel: querying configuration failed"); + return ret; + } + + config.ds_config = cpu_to_le32(dsconfig); + ret = rndis_set_oid(usbdev, OID_802_11_CONFIGURATION, &config, + sizeof(config)); + + devdbg(usbdev, "set_channel: %d -> %d", channel, ret); + + return ret; +} + + /* index must be 0 - N, as per NDIS */ -static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) +static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, + int index) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_wep_key ndis_key; @@ -1248,8 +1313,8 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) if (index == priv->encr_tx_key_index) { ndis_key.index |= NDIS_80211_ADDWEP_TRANSMIT_KEY; - ret = set_encr_mode(usbdev, IW_AUTH_CIPHER_WEP104, - IW_AUTH_CIPHER_NONE); + ret = set_encr_mode(usbdev, RNDIS_WLAN_ALG_WEP, + RNDIS_WLAN_ALG_NONE); if (ret) devwarn(usbdev, "encryption couldn't be enabled (%08X)", ret); @@ -1458,7 +1523,7 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) /* if it is transmit key, disable encryption */ if (index == priv->encr_tx_key_index) - set_encr_mode(usbdev, IW_AUTH_CIPHER_NONE, IW_AUTH_CIPHER_NONE); + set_encr_mode(usbdev, RNDIS_WLAN_ALG_NONE, RNDIS_WLAN_ALG_NONE); return 0; } @@ -1765,6 +1830,243 @@ static void rndis_get_scan_results(struct work_struct *work) priv->scan_request = NULL; } +static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + struct ieee80211_channel *channel = sme->channel; + struct ndis_80211_ssid ssid; + int pairwise = RNDIS_WLAN_ALG_NONE; + int groupwise = RNDIS_WLAN_ALG_NONE; + int keymgmt = RNDIS_WLAN_KEY_MGMT_NONE; + int length, i, ret, chan = -1; + + if (channel) + chan = ieee80211_frequency_to_channel(channel->center_freq); + + groupwise = rndis_cipher_to_alg(sme->crypto.cipher_group); + for (i = 0; i < sme->crypto.n_ciphers_pairwise; i++) + pairwise |= + rndis_cipher_to_alg(sme->crypto.ciphers_pairwise[i]); + + if (sme->crypto.n_ciphers_pairwise > 0 && + pairwise == RNDIS_WLAN_ALG_NONE) { + deverr(usbdev, "Unsupported pairwise cipher"); + return -ENOTSUPP; + } + + for (i = 0; i < sme->crypto.n_akm_suites; i++) + keymgmt |= + rndis_akm_suite_to_key_mgmt(sme->crypto.akm_suites[i]); + + if (sme->crypto.n_akm_suites > 0 && + keymgmt == RNDIS_WLAN_KEY_MGMT_NONE) { + deverr(usbdev, "Invalid keymgmt"); + return -ENOTSUPP; + } + + devdbg(usbdev, "cfg80211.connect('%.32s':[%pM]:%d:[%d,0x%x:0x%x]:[0x%x:" + "0x%x]:0x%x)", sme->ssid, sme->bssid, chan, + sme->privacy, sme->crypto.wpa_versions, sme->auth_type, + groupwise, pairwise, keymgmt); + + if (is_associated(usbdev)) + disassociate(usbdev, false); + + ret = set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); + if (ret < 0) { + devdbg(usbdev, "connect: set_infra_mode failed, %d", ret); + goto err_turn_radio_on; + } + + ret = set_auth_mode(usbdev, sme->crypto.wpa_versions, sme->auth_type, + keymgmt); + if (ret < 0) { + devdbg(usbdev, "connect: set_auth_mode failed, %d", ret); + goto err_turn_radio_on; + } + + set_priv_filter(usbdev); + + ret = set_encr_mode(usbdev, pairwise, groupwise); + if (ret < 0) { + devdbg(usbdev, "connect: set_encr_mode failed, %d", ret); + goto err_turn_radio_on; + } + + if (channel) { + ret = set_channel(usbdev, chan); + if (ret < 0) { + devdbg(usbdev, "connect: set_channel failed, %d", ret); + goto err_turn_radio_on; + } + } + + if (sme->key && ((groupwise | pairwise) & RNDIS_WLAN_ALG_WEP)) { + priv->encr_tx_key_index = sme->key_idx; + ret = add_wep_key(usbdev, sme->key, sme->key_len, sme->key_idx); + if (ret < 0) { + devdbg(usbdev, "connect: add_wep_key failed, %d " + "(%d, %d)", ret, sme->key_len, sme->key_idx); + goto err_turn_radio_on; + } + } + + if (sme->bssid && !is_zero_ether_addr(sme->bssid) && + !is_broadcast_ether_addr(sme->bssid)) { + ret = set_bssid(usbdev, sme->bssid); + if (ret < 0) { + devdbg(usbdev, "connect: set_bssid failed, %d", ret); + goto err_turn_radio_on; + } + } else + clear_bssid(usbdev); + + length = sme->ssid_len; + if (length > NDIS_802_11_LENGTH_SSID) + length = NDIS_802_11_LENGTH_SSID; + + memset(&ssid, 0, sizeof(ssid)); + ssid.length = cpu_to_le32(length); + memcpy(ssid.essid, sme->ssid, length); + + /* Pause and purge rx queue, so we don't pass packets before + * 'media connect'-indication. + */ + usbnet_pause_rx(usbdev); + usbnet_purge_paused_rxq(usbdev); + + ret = set_essid(usbdev, &ssid); + if (ret < 0) + devdbg(usbdev, "connect: set_essid failed, %d", ret); + return ret; + +err_turn_radio_on: + disassociate(usbdev, 1); + + return ret; +} + +static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + + devdbg(usbdev, "cfg80211.disconnect(%d)", reason_code); + + priv->connected = false; + + return deauthenticate(usbdev); +} + +static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + struct ieee80211_channel *channel = params->channel; + struct ndis_80211_ssid ssid; + enum nl80211_auth_type auth_type; + int ret, alg, length, chan = -1; + + if (channel) + chan = ieee80211_frequency_to_channel(channel->center_freq); + + /* TODO: How to handle ad-hoc encryption? + * connect() has *key, join_ibss() doesn't. RNDIS requires key to be + * pre-shared for encryption (open/shared/wpa), is key set before + * join_ibss? Which auth_type to use (not in params)? What about WPA? + */ + if (params->privacy) { + auth_type = NL80211_AUTHTYPE_SHARED_KEY; + alg = RNDIS_WLAN_ALG_WEP; + } else { + auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM; + alg = RNDIS_WLAN_ALG_NONE; + } + + devdbg(usbdev, "cfg80211.join_ibss('%.32s':[%pM]:%d:%d)", params->ssid, + params->bssid, chan, params->privacy); + + if (is_associated(usbdev)) + disassociate(usbdev, false); + + ret = set_infra_mode(usbdev, NDIS_80211_INFRA_ADHOC); + if (ret < 0) { + devdbg(usbdev, "join_ibss: set_infra_mode failed, %d", ret); + goto err_turn_radio_on; + } + + ret = set_auth_mode(usbdev, 0, auth_type, RNDIS_WLAN_KEY_MGMT_NONE); + if (ret < 0) { + devdbg(usbdev, "join_ibss: set_auth_mode failed, %d", ret); + goto err_turn_radio_on; + } + + set_priv_filter(usbdev); + + ret = set_encr_mode(usbdev, alg, RNDIS_WLAN_ALG_NONE); + if (ret < 0) { + devdbg(usbdev, "join_ibss: set_encr_mode failed, %d", ret); + goto err_turn_radio_on; + } + + if (channel) { + ret = set_channel(usbdev, chan); + if (ret < 0) { + devdbg(usbdev, "join_ibss: set_channel failed, %d", + ret); + goto err_turn_radio_on; + } + } + + if (params->bssid && !is_zero_ether_addr(params->bssid) && + !is_broadcast_ether_addr(params->bssid)) { + ret = set_bssid(usbdev, params->bssid); + if (ret < 0) { + devdbg(usbdev, "join_ibss: set_bssid failed, %d", ret); + goto err_turn_radio_on; + } + } else + clear_bssid(usbdev); + + length = params->ssid_len; + if (length > NDIS_802_11_LENGTH_SSID) + length = NDIS_802_11_LENGTH_SSID; + + memset(&ssid, 0, sizeof(ssid)); + ssid.length = cpu_to_le32(length); + memcpy(ssid.essid, params->ssid, length); + + /* Don't need to pause rx queue for ad-hoc. */ + usbnet_purge_paused_rxq(usbdev); + usbnet_resume_rx(usbdev); + + ret = set_essid(usbdev, &ssid); + if (ret < 0) + devdbg(usbdev, "join_ibss: set_essid failed, %d", ret); + return ret; + +err_turn_radio_on: + disassociate(usbdev, 1); + + return ret; +} + +static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + + devdbg(usbdev, "cfg80211.leave_ibss()"); + + priv->connected = false; + + return deauthenticate(usbdev); +} + /* * wireless extension handlers @@ -1777,7 +2079,10 @@ static int rndis_iw_commit(struct net_device *dev, return 0; } - +#if 0 +/* Commented code out instead of removing to have more sane patch for review. + * Will be removed later in the set. + */ static int rndis_iw_set_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *essid) { @@ -1990,6 +2295,7 @@ static int rndis_iw_get_auth(struct net_device *dev, } return 0; } +#endif static int rndis_iw_set_encode(struct net_device *dev, @@ -2024,11 +2330,11 @@ static int rndis_iw_set_encode(struct net_device *dev, /* global encryption state (for all keys) */ if (wrqu->data.flags & IW_ENCODE_OPEN) - ret = set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED, - IW_AUTH_ALG_OPEN_SYSTEM); + ret = set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_OPEN_SYSTEM, + RNDIS_WLAN_KEY_MGMT_NONE); else /*if (wrqu->data.flags & IW_ENCODE_RESTRICTED)*/ - ret = set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED, - IW_AUTH_ALG_SHARED_KEY); + ret = set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_SHARED_KEY, + RNDIS_WLAN_KEY_MGMT_NONE); if (ret != 0) return ret; @@ -2077,7 +2383,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, return -EINVAL; } - if (ext->alg == WPA_ALG_WEP) { + if (ext->alg == IW_ENCODE_ALG_WEP) { if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) priv->encr_tx_key_index = keyidx; return add_wep_key(usbdev, ext->key, ext->key_len, keyidx); @@ -2110,63 +2416,6 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, } -static int rndis_iw_set_genie(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int ret = 0; - -#ifdef DEBUG - int j; - u8 *gie = extra; - for (j = 0; j < wrqu->data.length; j += 8) - devdbg(usbdev, - "SIOCSIWGENIE %04x - " - "%02x %02x %02x %02x %02x %02x %02x %02x", j, - gie[j + 0], gie[j + 1], gie[j + 2], gie[j + 3], - gie[j + 4], gie[j + 5], gie[j + 6], gie[j + 7]); -#endif - /* clear existing IEs */ - if (priv->wpa_ie_len) { - kfree(priv->wpa_ie); - priv->wpa_ie_len = 0; - } - - /* set new IEs */ - priv->wpa_ie = kmalloc(wrqu->data.length, GFP_KERNEL); - if (priv->wpa_ie) { - priv->wpa_ie_len = wrqu->data.length; - memcpy(priv->wpa_ie, extra, priv->wpa_ie_len); - } else - ret = -ENOMEM; - return ret; -} - - -static int rndis_iw_get_genie(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - devdbg(usbdev, "SIOCGIWGENIE"); - - if (priv->wpa_ie_len == 0 || priv->wpa_ie == NULL) { - wrqu->data.length = 0; - return 0; - } - - if (wrqu->data.length < priv->wpa_ie_len) - return -E2BIG; - - wrqu->data.length = priv->wpa_ie_len; - memcpy(extra, priv->wpa_ie, priv->wpa_ie_len); - - return 0; -} - - static int rndis_iw_set_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { @@ -2233,32 +2482,6 @@ static int rndis_iw_get_rate(struct net_device *dev, } -static int rndis_iw_set_mlme(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct iw_mlme *mlme = (struct iw_mlme *)extra; - unsigned char bssid[ETH_ALEN]; - - get_bssid(usbdev, bssid); - - if (memcmp(bssid, mlme->addr.sa_data, ETH_ALEN)) - return -EINVAL; - - switch (mlme->cmd) { - case IW_MLME_DEAUTH: - return deauthenticate(usbdev); - case IW_MLME_DISASSOC: - return disassociate(usbdev, priv->radio_on); - default: - return -EOPNOTSUPP; - } - - return 0; -} - - static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) { struct usbnet *usbdev = netdev_priv(dev); @@ -2283,12 +2506,12 @@ static const iw_handler rndis_iw_handler[] = IW_IOCTL(SIOCSIWMODE) = (iw_handler) cfg80211_wext_siwmode, IW_IOCTL(SIOCGIWMODE) = (iw_handler) cfg80211_wext_giwmode, IW_IOCTL(SIOCGIWRANGE) = (iw_handler) cfg80211_wext_giwrange, - IW_IOCTL(SIOCSIWAP) = rndis_iw_set_bssid, - IW_IOCTL(SIOCGIWAP) = rndis_iw_get_bssid, + IW_IOCTL(SIOCSIWAP) = (iw_handler) cfg80211_wext_siwap, + IW_IOCTL(SIOCGIWAP) = (iw_handler) cfg80211_wext_giwap, IW_IOCTL(SIOCSIWSCAN) = (iw_handler) cfg80211_wext_siwscan, IW_IOCTL(SIOCGIWSCAN) = (iw_handler) cfg80211_wext_giwscan, - IW_IOCTL(SIOCSIWESSID) = rndis_iw_set_essid, - IW_IOCTL(SIOCGIWESSID) = rndis_iw_get_essid, + IW_IOCTL(SIOCSIWESSID) = (iw_handler) cfg80211_wext_siwessid, + IW_IOCTL(SIOCGIWESSID) = (iw_handler) cfg80211_wext_giwessid, IW_IOCTL(SIOCGIWRATE) = rndis_iw_get_rate, IW_IOCTL(SIOCSIWRTS) = (iw_handler) cfg80211_wext_siwrts, IW_IOCTL(SIOCGIWRTS) = (iw_handler) cfg80211_wext_giwrts, @@ -2298,11 +2521,10 @@ static const iw_handler rndis_iw_handler[] = IW_IOCTL(SIOCGIWTXPOW) = (iw_handler) cfg80211_wext_giwtxpower, IW_IOCTL(SIOCSIWENCODE) = rndis_iw_set_encode, IW_IOCTL(SIOCSIWENCODEEXT) = rndis_iw_set_encode_ext, - IW_IOCTL(SIOCSIWAUTH) = rndis_iw_set_auth, - IW_IOCTL(SIOCGIWAUTH) = rndis_iw_get_auth, - IW_IOCTL(SIOCSIWGENIE) = rndis_iw_set_genie, - IW_IOCTL(SIOCGIWGENIE) = rndis_iw_get_genie, - IW_IOCTL(SIOCSIWMLME) = rndis_iw_set_mlme, + IW_IOCTL(SIOCSIWAUTH) = (iw_handler) cfg80211_wext_siwauth, + IW_IOCTL(SIOCGIWAUTH) = (iw_handler) cfg80211_wext_giwauth, + IW_IOCTL(SIOCSIWGENIE) = (iw_handler) cfg80211_wext_siwgenie, + IW_IOCTL(SIOCSIWMLME) = (iw_handler) cfg80211_wext_siwmlme, }; static const iw_handler rndis_wlan_private_handler[] = { @@ -2325,49 +2547,78 @@ static const struct iw_handler_def rndis_iw_handlers = { static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) { + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_assoc_info *info; - union iwreq_data evt; u8 assoc_buf[sizeof(*info) + IW_CUSTOM_MAX + 32]; u8 bssid[ETH_ALEN]; + int resp_ie_len, req_ie_len; + u8 *req_ie, *resp_ie; int ret, offset; + bool roamed = false; + + if (priv->infra_mode == NDIS_80211_INFRA_INFRA && priv->connected) { + /* received media connect indication while connected, either + * device reassociated with same AP or roamed to new. */ + roamed = true; + } + + req_ie_len = 0; + resp_ie_len = 0; + req_ie = NULL; + resp_ie = NULL; + + if (priv->infra_mode == NDIS_80211_INFRA_INFRA) { + memset(assoc_buf, 0, sizeof(assoc_buf)); + info = (void *)assoc_buf; + + /* Get association info IEs from device and send them back to + * userspace. */ + ret = get_association_info(usbdev, info, sizeof(assoc_buf)); + if (!ret) { + req_ie_len = le32_to_cpu(info->req_ie_length); + if (req_ie_len > 0) { + offset = le32_to_cpu(info->offset_req_ies); + req_ie = (u8 *)info + offset; + } - memset(assoc_buf, 0, sizeof(assoc_buf)); - info = (void *)assoc_buf; + resp_ie_len = le32_to_cpu(info->resp_ie_length); + if (resp_ie_len > 0) { + offset = le32_to_cpu(info->offset_resp_ies); + resp_ie = (u8 *)info + offset; + } + } + } else if (WARN_ON(priv->infra_mode != NDIS_80211_INFRA_ADHOC)) + return; - netif_carrier_on(usbdev->net); + ret = get_bssid(usbdev, bssid); + if (ret < 0) + memset(bssid, 0, sizeof(bssid)); - /* Get association info IEs from device and send them back to - * userspace. */ - ret = get_association_info(usbdev, info, sizeof(assoc_buf)); - if (!ret) { - evt.data.length = le32_to_cpu(info->req_ie_length); - if (evt.data.length > 0) { - offset = le32_to_cpu(info->offset_req_ies); - wireless_send_event(usbdev->net, - IWEVASSOCREQIE, &evt, - (char *)info + offset); - } + devdbg(usbdev, "link up work: [%pM] %s", bssid, roamed ? "roamed" : ""); - evt.data.length = le32_to_cpu(info->resp_ie_length); - if (evt.data.length > 0) { - offset = le32_to_cpu(info->offset_resp_ies); - wireless_send_event(usbdev->net, - IWEVASSOCRESPIE, &evt, - (char *)info + offset); - } + /* Internal bss list in device always contains at least the currently + * connected bss and we can get it to cfg80211 with + * rndis_check_bssid_list(). + * NOTE: This is true for Broadcom chip, but not mentioned in RNDIS + * spec. + */ + rndis_check_bssid_list(usbdev); - usbnet_resume_rx(usbdev); - } + if (priv->infra_mode == NDIS_80211_INFRA_INFRA) { + if (!roamed) + cfg80211_connect_result(usbdev->net, bssid, req_ie, + req_ie_len, resp_ie, + resp_ie_len, 0, GFP_KERNEL); + else + cfg80211_roamed(usbdev->net, bssid, req_ie, req_ie_len, + resp_ie, resp_ie_len, GFP_KERNEL); + } else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC) + cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL); - ret = get_bssid(usbdev, bssid); - if (!ret) { - evt.data.flags = 0; - evt.data.length = 0; - memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN); - wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL); - } + priv->connected = true; usbnet_resume_rx(usbdev); + netif_carrier_on(usbdev->net); } static void rndis_wlan_do_link_down_work(struct usbnet *usbdev) -- cgit v1.2.3-18-g5258 From 5554adbe0d366f6a5096e6f74b48dcad5698c528 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 13:27:53 +0300 Subject: rndis_wlan: add cfg80211 set_channel Add cfg80211 set_channel and convert wext to use it. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 105 ++++++-------------------------------- 1 file changed, 15 insertions(+), 90 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index c2af5be35d3..ffb195dcf4f 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -517,6 +517,9 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev); +static int rndis_set_channel(struct wiphy *wiphy, + struct ieee80211_channel *chan, enum nl80211_channel_type channel_type); + static struct cfg80211_ops rndis_config_ops = { .change_virtual_intf = rndis_change_virtual_intf, .scan = rndis_scan, @@ -527,6 +530,7 @@ static struct cfg80211_ops rndis_config_ops = { .disconnect = rndis_disconnect, .join_ibss = rndis_join_ibss, .leave_ibss = rndis_leave_ibss, + .set_channel = rndis_set_channel, }; static void *rndis_wiphy_privid = &rndis_wiphy_privid; @@ -924,46 +928,6 @@ static int level_to_qual(int level) } -static void dsconfig_to_freq(unsigned int dsconfig, struct iw_freq *freq) -{ - freq->e = 0; - freq->i = 0; - freq->flags = 0; - - /* see comment in wireless.h above the "struct iw_freq" - * definition for an explanation of this if - * NOTE: 1000000 is due to the kHz - */ - if (dsconfig > 1000000) { - freq->m = dsconfig / 10; - freq->e = 1; - } else - freq->m = dsconfig; - - /* convert from kHz to Hz */ - freq->e += 3; -} - - -static int freq_to_dsconfig(struct iw_freq *freq, unsigned int *dsconfig) -{ - if (freq->m < 1000 && freq->e == 0) { - if (freq->m >= 1 && freq->m <= 14) - *dsconfig = ieee80211_dsss_chan_to_freq(freq->m) * 1000; - else - return -1; - } else { - int i; - *dsconfig = freq->m; - for (i = freq->e; i > 0; i--) - *dsconfig *= 10; - *dsconfig /= 1000; - } - - return 0; -} - - /* * common functions */ @@ -2067,6 +2031,15 @@ static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev) return deauthenticate(usbdev); } +static int rndis_set_channel(struct wiphy *wiphy, + struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + + return set_channel(usbdev, + ieee80211_frequency_to_channel(chan->center_freq)); +} /* * wireless extension handlers @@ -2416,54 +2389,6 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, } -static int rndis_iw_set_freq(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct ndis_80211_conf config; - unsigned int dsconfig; - int len, ret; - - /* this OID is valid only when not associated */ - if (is_associated(usbdev)) - return 0; - - dsconfig = 0; - if (freq_to_dsconfig(&wrqu->freq, &dsconfig)) - return -EINVAL; - - len = sizeof(config); - ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len); - if (ret != 0) { - devdbg(usbdev, "SIOCSIWFREQ: querying configuration failed"); - return 0; - } - - config.ds_config = cpu_to_le32(dsconfig); - - devdbg(usbdev, "SIOCSIWFREQ: %d * 10^%d", wrqu->freq.m, wrqu->freq.e); - return rndis_set_oid(usbdev, OID_802_11_CONFIGURATION, &config, - sizeof(config)); -} - - -static int rndis_iw_get_freq(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct ndis_80211_conf config; - int len, ret; - - len = sizeof(config); - ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len); - if (ret == 0) - dsconfig_to_freq(le32_to_cpu(config.ds_config), &wrqu->freq); - - devdbg(usbdev, "SIOCGIWFREQ: %d", wrqu->freq.m); - return ret; -} - - static int rndis_iw_get_rate(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { @@ -2501,8 +2426,8 @@ static const iw_handler rndis_iw_handler[] = { IW_IOCTL(SIOCSIWCOMMIT) = rndis_iw_commit, IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname, - IW_IOCTL(SIOCSIWFREQ) = rndis_iw_set_freq, - IW_IOCTL(SIOCGIWFREQ) = rndis_iw_get_freq, + IW_IOCTL(SIOCSIWFREQ) = (iw_handler) cfg80211_wext_siwfreq, + IW_IOCTL(SIOCGIWFREQ) = (iw_handler) cfg80211_wext_giwfreq, IW_IOCTL(SIOCSIWMODE) = (iw_handler) cfg80211_wext_siwmode, IW_IOCTL(SIOCGIWMODE) = (iw_handler) cfg80211_wext_giwmode, IW_IOCTL(SIOCGIWRANGE) = (iw_handler) cfg80211_wext_giwrange, -- cgit v1.2.3-18-g5258 From 84bf8400cee127be3b58a9d9b8cfa453dad999ab Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 13:27:58 +0300 Subject: rndis_wlan: add cfg80211 key handling Add cfg80211 add_key/del_key/set_default_key and convert wext to use theim. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 133 +++++++++++++++++++++++++++++--------- 1 file changed, 103 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index ffb195dcf4f..93b504bc2dc 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -424,7 +424,7 @@ static const u32 rndis_cipher_suites[] = { struct rndis_wlan_encr_key { int len; - int cipher; + u32 cipher; u8 material[32]; u8 bssid[ETH_ALEN]; bool pairwise; @@ -520,6 +520,16 @@ static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev); static int rndis_set_channel(struct wiphy *wiphy, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type); +static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, const u8 *mac_addr, + struct key_params *params); + +static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, const u8 *mac_addr); + +static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index); + static struct cfg80211_ops rndis_config_ops = { .change_virtual_intf = rndis_change_virtual_intf, .scan = rndis_scan, @@ -531,6 +541,9 @@ static struct cfg80211_ops rndis_config_ops = { .join_ibss = rndis_join_ibss, .leave_ibss = rndis_leave_ibss, .set_channel = rndis_set_channel, + .add_key = rndis_add_key, + .del_key = rndis_del_key, + .set_default_key = rndis_set_default_key, }; static void *rndis_wiphy_privid = &rndis_wiphy_privid; @@ -1258,7 +1271,10 @@ static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_wep_key ndis_key; - int cipher, ret; + u32 cipher; + int ret; + + devdbg(usbdev, "add_wep_key(idx: %d, len: %d)", index, key_len); if ((key_len != 5 && key_len != 13) || index < 0 || index > 3) return -EINVAL; @@ -1302,8 +1318,8 @@ static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, - int index, const u8 *addr, const u8 *rx_seq, int cipher, - int flags) + int index, const u8 *addr, const u8 *rx_seq, + int seq_len, u32 cipher, int flags) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_key ndis_key; @@ -1319,10 +1335,18 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, key_len); return -EINVAL; } - if ((flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) && !rx_seq) { - devdbg(usbdev, "add_wpa_key: recv seq flag without buffer"); - return -EINVAL; + if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) { + if (!rx_seq || seq_len <= 0) { + devdbg(usbdev, "add_wpa_key: recv seq flag without" + "buffer"); + return -EINVAL; + } + if (rx_seq && seq_len > sizeof(ndis_key.rsc)) { + devdbg(usbdev, "add_wpa_key: too big recv seq buffer"); + return -EINVAL; + } } + is_addr_ok = addr && !is_zero_ether_addr(addr) && !is_broadcast_ether_addr(addr); if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !is_addr_ok) { @@ -1353,7 +1377,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, memcpy(ndis_key.material, key, key_len); if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) - memcpy(ndis_key.rsc, rx_seq, 6); + memcpy(ndis_key.rsc, rx_seq, seq_len); if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) { /* pairwise key */ @@ -1392,31 +1416,17 @@ static int restore_key(struct usbnet *usbdev, int key_idx) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct rndis_wlan_encr_key key; - int flags; + + if (is_wpa_key(priv, key_idx)) + return 0; key = priv->encr_keys[key_idx]; - devdbg(usbdev, "restore_key: %i:%s:%i", key_idx, - is_wpa_key(priv, key_idx) ? "wpa" : "wep", - key.len); + devdbg(usbdev, "restore_key: %i:%i", key_idx, key.len); if (key.len == 0) return 0; - if (is_wpa_key(priv, key_idx)) { - flags = 0; - - /*if (priv->encr_tx_key_index == key_idx) - flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY;*/ - - if (!is_zero_ether_addr(key.bssid) && - !is_broadcast_ether_addr(key.bssid)) - flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY; - - return add_wpa_key(usbdev, key.material, key.len, key_idx, - key.bssid, NULL, key.cipher, flags); - } - return add_wep_key(usbdev, key.material, key.len, key_idx); } @@ -1437,7 +1447,7 @@ static void clear_key(struct rndis_wlan_private *priv, int idx) /* remove_key is for both wep and wpa */ -static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) +static int remove_key(struct usbnet *usbdev, int index, const u8 *bssid) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_remove_key remove_key; @@ -2041,6 +2051,69 @@ static int rndis_set_channel(struct wiphy *wiphy, ieee80211_frequency_to_channel(chan->center_freq)); } +static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, const u8 *mac_addr, + struct key_params *params) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + int flags; + + devdbg(usbdev, "rndis_add_key(%i, %pM, %08x)", key_index, mac_addr, + params->cipher); + + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + return add_wep_key(usbdev, params->key, params->key_len, + key_index); + case WLAN_CIPHER_SUITE_TKIP: + case WLAN_CIPHER_SUITE_CCMP: + flags = 0; + + if (params->seq && params->seq_len > 0) + flags |= NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ; + if (mac_addr) + flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY | + NDIS_80211_ADDKEY_TRANSMIT_KEY; + + return add_wpa_key(usbdev, params->key, params->key_len, + key_index, mac_addr, params->seq, + params->seq_len, params->cipher, flags); + default: + devdbg(usbdev, "rndis_add_key: unsupported cipher %08x", + params->cipher); + return -ENOTSUPP; + } +} + +static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, const u8 *mac_addr) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + + devdbg(usbdev, "rndis_del_key(%i, %pM)", key_index, mac_addr); + + return remove_key(usbdev, key_index, mac_addr); +} + +static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + struct rndis_wlan_encr_key key; + + devdbg(usbdev, "rndis_set_default_key(%i)", key_index); + + priv->encr_tx_key_index = key_index; + + key = priv->encr_keys[key_index]; + + return add_wep_key(usbdev, key.material, key.len, key_index); +} + /* * wireless extension handlers */ @@ -2268,7 +2341,6 @@ static int rndis_iw_get_auth(struct net_device *dev, } return 0; } -#endif static int rndis_iw_set_encode(struct net_device *dev, @@ -2387,6 +2459,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, (u8 *)&ext->addr.sa_data, ext->rx_seq, cipher, flags); } +#endif static int rndis_iw_get_rate(struct net_device *dev, @@ -2444,8 +2517,8 @@ static const iw_handler rndis_iw_handler[] = IW_IOCTL(SIOCGIWFRAG) = (iw_handler) cfg80211_wext_giwfrag, IW_IOCTL(SIOCSIWTXPOW) = (iw_handler) cfg80211_wext_siwtxpower, IW_IOCTL(SIOCGIWTXPOW) = (iw_handler) cfg80211_wext_giwtxpower, - IW_IOCTL(SIOCSIWENCODE) = rndis_iw_set_encode, - IW_IOCTL(SIOCSIWENCODEEXT) = rndis_iw_set_encode_ext, + IW_IOCTL(SIOCSIWENCODE) = (iw_handler) cfg80211_wext_siwencode, + IW_IOCTL(SIOCSIWENCODEEXT) = (iw_handler) cfg80211_wext_siwencodeext, IW_IOCTL(SIOCSIWAUTH) = (iw_handler) cfg80211_wext_siwauth, IW_IOCTL(SIOCGIWAUTH) = (iw_handler) cfg80211_wext_giwauth, IW_IOCTL(SIOCSIWGENIE) = (iw_handler) cfg80211_wext_siwgenie, -- cgit v1.2.3-18-g5258 From 8b89a2883be4b6bad8ac0c5928784febb2b34172 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 13:28:03 +0300 Subject: rndis_wlan: add cfg80211 get_station Add cfg80211 get_station and convert SIOCGIWRATE and get_wireless_stats to cfg80211. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 118 ++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 93b504bc2dc..061bfec14a9 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -444,17 +444,14 @@ struct rndis_wlan_private { struct delayed_work scan_work; struct work_struct work; struct mutex command_lock; - spinlock_t stats_lock; unsigned long work_pending; + int last_qual; struct ieee80211_supported_band band; struct ieee80211_channel channels[ARRAY_SIZE(rndis_channels)]; struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)]; u32 cipher_suites[ARRAY_SIZE(rndis_cipher_suites)]; - struct iw_statistics iwstats; - struct iw_statistics privstats; - int caps; int multicast_size; @@ -472,6 +469,7 @@ struct rndis_wlan_private { int radio_on; int infra_mode; bool connected; + u8 bssid[ETH_ALEN]; struct ndis_80211_ssid essid; __le32 current_command_oid; @@ -530,6 +528,9 @@ static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev, static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index); +static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_info *sinfo); + static struct cfg80211_ops rndis_config_ops = { .change_virtual_intf = rndis_change_virtual_intf, .scan = rndis_scan, @@ -544,6 +545,7 @@ static struct cfg80211_ops rndis_config_ops = { .add_key = rndis_add_key, .del_key = rndis_del_key, .set_default_key = rndis_set_default_key, + .get_station = rndis_get_station, }; static void *rndis_wiphy_privid = &rndis_wiphy_privid; @@ -1931,6 +1933,7 @@ static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev, devdbg(usbdev, "cfg80211.disconnect(%d)", reason_code); priv->connected = false; + memset(priv->bssid, 0, ETH_ALEN); return deauthenticate(usbdev); } @@ -2037,6 +2040,7 @@ static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev) devdbg(usbdev, "cfg80211.leave_ibss()"); priv->connected = false; + memset(priv->bssid, 0, ETH_ALEN); return deauthenticate(usbdev); } @@ -2114,6 +2118,43 @@ static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, return add_wep_key(usbdev, key.material, key.len, key_index); } +static void rndis_fill_station_info(struct usbnet *usbdev, + struct station_info *sinfo) +{ + __le32 linkspeed, rssi; + int ret, len; + + memset(sinfo, 0, sizeof(*sinfo)); + + len = sizeof(linkspeed); + ret = rndis_query_oid(usbdev, OID_GEN_LINK_SPEED, &linkspeed, &len); + if (ret == 0) { + sinfo->txrate.legacy = le32_to_cpu(linkspeed) / 1000; + sinfo->filled |= STATION_INFO_TX_BITRATE; + } + + len = sizeof(rssi); + ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len); + if (ret == 0) { + sinfo->signal = level_to_qual(le32_to_cpu(rssi)); + sinfo->filled |= STATION_INFO_SIGNAL; + } +} + +static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_info *sinfo) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + + if (compare_ether_addr(priv->bssid, mac)) + return -ENOENT; + + rndis_fill_station_info(usbdev, sinfo); + + return 0; +} + /* * wireless extension handlers */ @@ -2459,7 +2500,6 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, (u8 *)&ext->addr.sa_data, ext->rx_seq, cipher, flags); } -#endif static int rndis_iw_get_rate(struct net_device *dev, @@ -2492,6 +2532,7 @@ static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) return &priv->iwstats; } +#endif #define IW_IOCTL(x) [(x) - SIOCSIWCOMMIT] @@ -2510,7 +2551,7 @@ static const iw_handler rndis_iw_handler[] = IW_IOCTL(SIOCGIWSCAN) = (iw_handler) cfg80211_wext_giwscan, IW_IOCTL(SIOCSIWESSID) = (iw_handler) cfg80211_wext_siwessid, IW_IOCTL(SIOCGIWESSID) = (iw_handler) cfg80211_wext_giwessid, - IW_IOCTL(SIOCGIWRATE) = rndis_iw_get_rate, + IW_IOCTL(SIOCGIWRATE) = (iw_handler) cfg80211_wext_giwrate, IW_IOCTL(SIOCSIWRTS) = (iw_handler) cfg80211_wext_siwrts, IW_IOCTL(SIOCGIWRTS) = (iw_handler) cfg80211_wext_giwrts, IW_IOCTL(SIOCSIWFRAG) = (iw_handler) cfg80211_wext_siwfrag, @@ -2539,7 +2580,7 @@ static const struct iw_handler_def rndis_iw_handlers = { .standard = (iw_handler *)rndis_iw_handler, .private = (iw_handler *)rndis_wlan_private_handler, .private_args = (struct iw_priv_args *)rndis_wlan_private_args, - .get_wireless_stats = rndis_get_wireless_stats, + .get_wireless_stats = cfg80211_wireless_stats, }; @@ -2614,6 +2655,7 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL); priv->connected = true; + memcpy(priv->bssid, bssid, ETH_ALEN); usbnet_resume_rx(usbdev); netif_carrier_on(usbdev->net); @@ -2928,64 +2970,30 @@ static void rndis_update_wireless_stats(struct work_struct *work) struct rndis_wlan_private *priv = container_of(work, struct rndis_wlan_private, stats_work.work); struct usbnet *usbdev = priv->usbdev; - struct iw_statistics iwstats; __le32 rssi, tmp; int len, ret, j; - unsigned long flags; int update_jiffies = STATS_UPDATE_JIFFIES; void *buf; - spin_lock_irqsave(&priv->stats_lock, flags); - memcpy(&iwstats, &priv->privstats, sizeof(iwstats)); - spin_unlock_irqrestore(&priv->stats_lock, flags); - - /* only update stats when connected */ - if (!is_associated(usbdev)) { - iwstats.qual.qual = 0; - iwstats.qual.level = 0; - iwstats.qual.updated = IW_QUAL_QUAL_UPDATED - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_NOISE_INVALID - | IW_QUAL_QUAL_INVALID - | IW_QUAL_LEVEL_INVALID; + /* Only check/do workaround when connected. Calling is_associated() + * also polls device with rndis_command() and catches for media link + * indications. + */ + if (!is_associated(usbdev)) goto end; - } len = sizeof(rssi); ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len); + if (ret == 0) + priv->last_qual = level_to_qual(le32_to_cpu(rssi)); devdbg(usbdev, "stats: OID_802_11_RSSI -> %d, rssi:%d", ret, le32_to_cpu(rssi)); - if (ret == 0) { - memset(&iwstats.qual, 0, sizeof(iwstats.qual)); - iwstats.qual.qual = level_to_qual(le32_to_cpu(rssi)); - iwstats.qual.level = level_to_qual(le32_to_cpu(rssi)); - iwstats.qual.updated = IW_QUAL_QUAL_UPDATED - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_NOISE_INVALID; - } - - memset(&iwstats.discard, 0, sizeof(iwstats.discard)); - - len = sizeof(tmp); - ret = rndis_query_oid(usbdev, OID_GEN_XMIT_ERROR, &tmp, &len); - if (ret == 0) - iwstats.discard.misc += le32_to_cpu(tmp); - - len = sizeof(tmp); - ret = rndis_query_oid(usbdev, OID_GEN_RCV_ERROR, &tmp, &len); - if (ret == 0) - iwstats.discard.misc += le32_to_cpu(tmp); - - len = sizeof(tmp); - ret = rndis_query_oid(usbdev, OID_GEN_RCV_NO_BUFFER, &tmp, &len); - if (ret == 0) - iwstats.discard.misc += le32_to_cpu(tmp); /* Workaround transfer stalls on poor quality links. * TODO: find right way to fix these stalls (as stalls do not happen * with ndiswrapper/windows driver). */ - if (iwstats.qual.qual <= 25) { + if (priv->last_qual <= 25) { /* Decrease stats worker interval to catch stalls. * faster. Faster than 400-500ms causes packet loss, * Slower doesn't catch stalls fast enough. @@ -3013,9 +3021,6 @@ static void rndis_update_wireless_stats(struct work_struct *work) kfree(buf); } end: - spin_lock_irqsave(&priv->stats_lock, flags); - memcpy(&priv->privstats, &iwstats, sizeof(iwstats)); - spin_unlock_irqrestore(&priv->stats_lock, flags); if (update_jiffies >= HZ) update_jiffies = round_jiffies_relative(update_jiffies); @@ -3146,7 +3151,6 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) priv->usbdev = usbdev; mutex_init(&priv->command_lock); - spin_lock_init(&priv->stats_lock); /* because rndis_command() sleeps we need to use workqueue */ priv->workqueue = create_singlethread_workqueue("rndis_wlan"); @@ -3183,14 +3187,6 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) else usbdev->net->flags &= ~IFF_MULTICAST; - priv->iwstats.qual.qual = 0; - priv->iwstats.qual.level = 0; - priv->iwstats.qual.updated = IW_QUAL_QUAL_UPDATED - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_NOISE_INVALID - | IW_QUAL_QUAL_INVALID - | IW_QUAL_LEVEL_INVALID; - /* fill-out wiphy structure and register w/ cfg80211 */ memcpy(wiphy->perm_addr, usbdev->net->dev_addr, ETH_ALEN); wiphy->privid = rndis_wiphy_privid; -- cgit v1.2.3-18-g5258 From d695df9049199bdeadd81c29104da8e2542062cf Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 13:28:09 +0300 Subject: rndis_wlan: add cfg80211 dump_station Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 061bfec14a9..351affe793c 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -531,6 +531,9 @@ static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev, static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_info *sinfo); +static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, + int idx, u8 *mac, struct station_info *sinfo); + static struct cfg80211_ops rndis_config_ops = { .change_virtual_intf = rndis_change_virtual_intf, .scan = rndis_scan, @@ -546,6 +549,7 @@ static struct cfg80211_ops rndis_config_ops = { .del_key = rndis_del_key, .set_default_key = rndis_set_default_key, .get_station = rndis_get_station, + .dump_station = rndis_dump_station, }; static void *rndis_wiphy_privid = &rndis_wiphy_privid; @@ -2155,6 +2159,22 @@ static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev, return 0; } +static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, + int idx, u8 *mac, struct station_info *sinfo) +{ + struct rndis_wlan_private *priv = wiphy_priv(wiphy); + struct usbnet *usbdev = priv->usbdev; + + if (idx != 0) + return -ENOENT; + + memcpy(mac, priv->bssid, ETH_ALEN); + + rndis_fill_station_info(usbdev, sinfo); + + return 0; +} + /* * wireless extension handlers */ -- cgit v1.2.3-18-g5258 From 305e243e6868eb6cf898183a523455bb9264cd2c Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 13:28:14 +0300 Subject: rndis_wlan: rename wireless stats worker to device poller Stats worker no longer poll stats from device anymore. It's still needed to poll device control channel for connect/disconnect events, so rename stats worker as device poller. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 351affe793c..61a7693baf9 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -440,7 +440,7 @@ struct rndis_wlan_private { struct cfg80211_scan_request *scan_request; struct workqueue_struct *workqueue; - struct delayed_work stats_work; + struct delayed_work dev_poller_work; struct delayed_work scan_work; struct work_struct work; struct mutex command_lock; @@ -2984,15 +2984,16 @@ static int rndis_wlan_get_caps(struct usbnet *usbdev) } -#define STATS_UPDATE_JIFFIES (HZ) -static void rndis_update_wireless_stats(struct work_struct *work) +#define DEVICE_POLLER_JIFFIES (HZ) +static void rndis_device_poller(struct work_struct *work) { struct rndis_wlan_private *priv = - container_of(work, struct rndis_wlan_private, stats_work.work); + container_of(work, struct rndis_wlan_private, + dev_poller_work.work); struct usbnet *usbdev = priv->usbdev; __le32 rssi, tmp; int len, ret, j; - int update_jiffies = STATS_UPDATE_JIFFIES; + int update_jiffies = DEVICE_POLLER_JIFFIES; void *buf; /* Only check/do workaround when connected. Calling is_associated() @@ -3007,8 +3008,8 @@ static void rndis_update_wireless_stats(struct work_struct *work) if (ret == 0) priv->last_qual = level_to_qual(le32_to_cpu(rssi)); - devdbg(usbdev, "stats: OID_802_11_RSSI -> %d, rssi:%d", ret, - le32_to_cpu(rssi)); + devdbg(usbdev, "dev-poller: OID_802_11_RSSI -> %d, rssi:%d, qual: %d", + ret, le32_to_cpu(rssi), level_to_qual(le32_to_cpu(rssi))); /* Workaround transfer stalls on poor quality links. * TODO: find right way to fix these stalls (as stalls do not happen @@ -3019,8 +3020,8 @@ static void rndis_update_wireless_stats(struct work_struct *work) * Slower doesn't catch stalls fast enough. */ j = msecs_to_jiffies(priv->param_workaround_interval); - if (j > STATS_UPDATE_JIFFIES) - j = STATS_UPDATE_JIFFIES; + if (j > DEVICE_POLLER_JIFFIES) + j = DEVICE_POLLER_JIFFIES; else if (j <= 0) j = 1; update_jiffies = j; @@ -3040,8 +3041,8 @@ static void rndis_update_wireless_stats(struct work_struct *work) rndis_query_oid(usbdev, OID_802_11_BSSID_LIST, buf, &len); kfree(buf); } -end: +end: if (update_jiffies >= HZ) update_jiffies = round_jiffies_relative(update_jiffies); else { @@ -3050,7 +3051,8 @@ end: update_jiffies = j; } - queue_delayed_work(priv->workqueue, &priv->stats_work, update_jiffies); + queue_delayed_work(priv->workqueue, &priv->dev_poller_work, + update_jiffies); } @@ -3175,7 +3177,7 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) /* because rndis_command() sleeps we need to use workqueue */ priv->workqueue = create_singlethread_workqueue("rndis_wlan"); INIT_WORK(&priv->work, rndis_wlan_worker); - INIT_DELAYED_WORK(&priv->stats_work, rndis_update_wireless_stats); + INIT_DELAYED_WORK(&priv->dev_poller_work, rndis_device_poller); INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results); /* try bind rndis_host */ @@ -3252,7 +3254,7 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) return 0; fail: - cancel_delayed_work_sync(&priv->stats_work); + cancel_delayed_work_sync(&priv->dev_poller_work); cancel_delayed_work_sync(&priv->scan_work); cancel_work_sync(&priv->work); flush_workqueue(priv->workqueue); @@ -3270,7 +3272,7 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) /* turn radio off */ disassociate(usbdev, 0); - cancel_delayed_work_sync(&priv->stats_work); + cancel_delayed_work_sync(&priv->dev_poller_work); cancel_delayed_work_sync(&priv->scan_work); cancel_work_sync(&priv->work); flush_workqueue(priv->workqueue); @@ -3301,8 +3303,8 @@ static int rndis_wlan_reset(struct usbnet *usbdev) (set_multicast_list() also turns on current packet filter) */ set_multicast_list(usbdev); - queue_delayed_work(priv->workqueue, &priv->stats_work, - round_jiffies_relative(STATS_UPDATE_JIFFIES)); + queue_delayed_work(priv->workqueue, &priv->dev_poller_work, + round_jiffies_relative(DEVICE_POLLER_JIFFIES)); return deauthenticate(usbdev); } @@ -3319,7 +3321,7 @@ static int rndis_wlan_stop(struct usbnet *usbdev) retval = disassociate(usbdev, 0); priv->work_pending = 0; - cancel_delayed_work_sync(&priv->stats_work); + cancel_delayed_work_sync(&priv->dev_poller_work); cancel_delayed_work_sync(&priv->scan_work); cancel_work_sync(&priv->work); flush_workqueue(priv->workqueue); -- cgit v1.2.3-18-g5258 From 3334943cefa03a5384060e321e3dd9e686097caf Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 13:28:19 +0300 Subject: rndis_wlan: remove unneeded SIOCSIWCOMMIT Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 61a7693baf9..9425b3c2ef2 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2179,13 +2179,6 @@ static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, * wireless extension handlers */ -static int rndis_iw_commit(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - /* dummy op */ - return 0; -} - #if 0 /* Commented code out instead of removing to have more sane patch for review. * Will be removed later in the set. @@ -2558,7 +2551,6 @@ static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) #define IW_IOCTL(x) [(x) - SIOCSIWCOMMIT] static const iw_handler rndis_iw_handler[] = { - IW_IOCTL(SIOCSIWCOMMIT) = rndis_iw_commit, IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname, IW_IOCTL(SIOCSIWFREQ) = (iw_handler) cfg80211_wext_siwfreq, IW_IOCTL(SIOCGIWFREQ) = (iw_handler) cfg80211_wext_giwfreq, -- cgit v1.2.3-18-g5258 From a0f9ce2ac35a0c57413dafd90e316c4048d1b43e Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 13:28:24 +0300 Subject: rndis_wlan: convert mic failure wireless event to cfg80211 Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 9425b3c2ef2..c0c6d66f7d9 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2720,9 +2720,10 @@ static void rndis_wlan_auth_indication(struct usbnet *usbdev, { u8 *buf; const char *type; - int flags, buflen; + int flags, buflen, key_id; bool pairwise_error, group_error; struct ndis_80211_auth_request *auth_req; + enum nl80211_key_type key_type; /* must have at least one array entry */ if (len < offsetof(struct ndis_80211_status_indication, u) + @@ -2758,23 +2759,24 @@ static void rndis_wlan_auth_indication(struct usbnet *usbdev, devinfo(usbdev, "authentication indication: %s (0x%08x)", type, le32_to_cpu(auth_req->flags)); - if (pairwise_error || group_error) { - union iwreq_data wrqu; - struct iw_michaelmicfailure micfailure; + if (pairwise_error) { + key_type = NL80211_KEYTYPE_PAIRWISE; + key_id = -1; - memset(&micfailure, 0, sizeof(micfailure)); - if (pairwise_error) - micfailure.flags |= IW_MICFAILURE_PAIRWISE; - if (group_error) - micfailure.flags |= IW_MICFAILURE_GROUP; + cfg80211_michael_mic_failure(usbdev->net, + auth_req->bssid, + key_type, key_id, NULL, + GFP_KERNEL); + } - memcpy(micfailure.src_addr.sa_data, auth_req->bssid, - ETH_ALEN); + if (group_error) { + key_type = NL80211_KEYTYPE_GROUP; + key_id = -1; - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = sizeof(micfailure); - wireless_send_event(usbdev->net, IWEVMICHAELMICFAILURE, - &wrqu, (u8 *)&micfailure); + cfg80211_michael_mic_failure(usbdev->net, + auth_req->bssid, + key_type, key_id, NULL, + GFP_KERNEL); } buflen -= le32_to_cpu(auth_req->length); -- cgit v1.2.3-18-g5258 From 21ec2d8d0fee4f3bf0d2e25e5b63bf2637233b43 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 13:28:30 +0300 Subject: rndis_wlan: disable IWEVPMKIDCAND wireless event Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index c0c6d66f7d9..9d9750dbec8 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2821,14 +2821,16 @@ static void rndis_wlan_pmkid_cand_list_indication(struct usbnet *usbdev, return; for (i = 0; i < le32_to_cpu(cand_list->num_candidates); i++) { - struct iw_pmkid_cand pcand; - union iwreq_data wrqu; struct ndis_80211_pmkid_candidate *cand = &cand_list->candidate_list[i]; devdbg(usbdev, "cand[%i]: flags: 0x%08x, bssid: %pM", i, le32_to_cpu(cand->flags), cand->bssid); +#if 0 + struct iw_pmkid_cand pcand; + union iwreq_data wrqu; + memset(&pcand, 0, sizeof(pcand)); if (le32_to_cpu(cand->flags) & 0x01) pcand.flags |= IW_PMKID_CAND_PREAUTH; @@ -2839,6 +2841,7 @@ static void rndis_wlan_pmkid_cand_list_indication(struct usbnet *usbdev, wrqu.data.length = sizeof(pcand); wireless_send_event(usbdev->net, IWEVPMKIDCAND, &wrqu, (u8 *)&pcand); +#endif } } -- cgit v1.2.3-18-g5258 From 04a6445f6f5e439ef775bd18cf3f485f84bbfb1b Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 28 Aug 2009 13:28:35 +0300 Subject: rndis_wlan: use cfg80211_wext_handler Now that cfg80211 functions are added and wext converted to use wext-compat functions, remove wext structures and disabled code. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 421 -------------------------------------- 1 file changed, 421 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 9d9750dbec8..402d3675776 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2175,426 +2175,6 @@ static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, return 0; } -/* - * wireless extension handlers - */ - -#if 0 -/* Commented code out instead of removing to have more sane patch for review. - * Will be removed later in the set. - */ -static int rndis_iw_set_essid(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *essid) -{ - struct ndis_80211_ssid ssid; - int length = wrqu->essid.length; - struct usbnet *usbdev = netdev_priv(dev); - - devdbg(usbdev, "SIOCSIWESSID: [flags:%d,len:%d] '%.32s'", - wrqu->essid.flags, wrqu->essid.length, essid); - - if (length > NDIS_802_11_LENGTH_SSID) - length = NDIS_802_11_LENGTH_SSID; - - ssid.length = cpu_to_le32(length); - if (length > 0) - memcpy(ssid.essid, essid, length); - else - memset(ssid.essid, 0, NDIS_802_11_LENGTH_SSID); - - set_assoc_params(usbdev); - - if (!wrqu->essid.flags || length == 0) - return disassociate(usbdev, 1); - else { - /* Pause and purge rx queue, so we don't pass packets before - * 'media connect'-indication. - */ - usbnet_pause_rx(usbdev); - usbnet_purge_paused_rxq(usbdev); - - return set_essid(usbdev, &ssid); - } -} - - -static int rndis_iw_get_essid(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *essid) -{ - struct ndis_80211_ssid ssid; - struct usbnet *usbdev = netdev_priv(dev); - int ret; - - ret = get_essid(usbdev, &ssid); - - if (ret == 0 && le32_to_cpu(ssid.length) > 0) { - wrqu->essid.flags = 1; - wrqu->essid.length = le32_to_cpu(ssid.length); - memcpy(essid, ssid.essid, wrqu->essid.length); - essid[wrqu->essid.length] = 0; - } else { - memset(essid, 0, sizeof(NDIS_802_11_LENGTH_SSID)); - wrqu->essid.flags = 0; - wrqu->essid.length = 0; - } - devdbg(usbdev, "SIOCGIWESSID: %s", essid); - return ret; -} - - -static int rndis_iw_get_bssid(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - unsigned char bssid[ETH_ALEN]; - int ret; - - ret = get_bssid(usbdev, bssid); - - if (ret == 0) - devdbg(usbdev, "SIOCGIWAP: %pM", bssid); - else - devdbg(usbdev, "SIOCGIWAP: "); - - wrqu->ap_addr.sa_family = ARPHRD_ETHER; - memcpy(wrqu->ap_addr.sa_data, bssid, ETH_ALEN); - - return ret; -} - - -static int rndis_iw_set_bssid(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - u8 *bssid = (u8 *)wrqu->ap_addr.sa_data; - int ret; - - devdbg(usbdev, "SIOCSIWAP: %pM", bssid); - - ret = rndis_set_oid(usbdev, OID_802_11_BSSID, bssid, ETH_ALEN); - - /* user apps may set ap's mac address, which is not required; - * they may fail to work if this function fails, so return - * success */ - if (ret) - devwarn(usbdev, "setting AP mac address failed (%08X)", ret); - - return 0; -} - - -static int rndis_iw_set_auth(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *p = &wrqu->param; - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int ret = -ENOTSUPP; - - switch (p->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - devdbg(usbdev, "SIOCSIWAUTH: WPA_VERSION, %08x", p->value); - priv->wpa_version = p->value; - ret = 0; - break; - - case IW_AUTH_CIPHER_PAIRWISE: - devdbg(usbdev, "SIOCSIWAUTH: CIPHER_PAIRWISE, %08x", p->value); - priv->wpa_cipher_pair = p->value; - ret = 0; - break; - - case IW_AUTH_CIPHER_GROUP: - devdbg(usbdev, "SIOCSIWAUTH: CIPHER_GROUP, %08x", p->value); - priv->wpa_cipher_group = p->value; - ret = 0; - break; - - case IW_AUTH_KEY_MGMT: - devdbg(usbdev, "SIOCSIWAUTH: KEY_MGMT, %08x", p->value); - priv->wpa_keymgmt = p->value; - ret = 0; - break; - - case IW_AUTH_TKIP_COUNTERMEASURES: - devdbg(usbdev, "SIOCSIWAUTH: TKIP_COUNTERMEASURES, %08x", - p->value); - ret = 0; - break; - - case IW_AUTH_DROP_UNENCRYPTED: - devdbg(usbdev, "SIOCSIWAUTH: DROP_UNENCRYPTED, %08x", p->value); - ret = 0; - break; - - case IW_AUTH_80211_AUTH_ALG: - devdbg(usbdev, "SIOCSIWAUTH: 80211_AUTH_ALG, %08x", p->value); - priv->wpa_authalg = p->value; - ret = 0; - break; - - case IW_AUTH_WPA_ENABLED: - devdbg(usbdev, "SIOCSIWAUTH: WPA_ENABLED, %08x", p->value); - if (wrqu->param.value) - deauthenticate(usbdev); - ret = 0; - break; - - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - devdbg(usbdev, "SIOCSIWAUTH: RX_UNENCRYPTED_EAPOL, %08x", - p->value); - ret = 0; - break; - - case IW_AUTH_ROAMING_CONTROL: - devdbg(usbdev, "SIOCSIWAUTH: ROAMING_CONTROL, %08x", p->value); - ret = 0; - break; - - case IW_AUTH_PRIVACY_INVOKED: - devdbg(usbdev, "SIOCSIWAUTH: invalid cmd %d", - wrqu->param.flags & IW_AUTH_INDEX); - return -EOPNOTSUPP; - - default: - devdbg(usbdev, "SIOCSIWAUTH: UNKNOWN %08x, %08x", - p->flags & IW_AUTH_INDEX, p->value); - } - return ret; -} - - -static int rndis_iw_get_auth(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *p = &wrqu->param; - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - - switch (p->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - p->value = priv->wpa_version; - break; - case IW_AUTH_CIPHER_PAIRWISE: - p->value = priv->wpa_cipher_pair; - break; - case IW_AUTH_CIPHER_GROUP: - p->value = priv->wpa_cipher_group; - break; - case IW_AUTH_KEY_MGMT: - p->value = priv->wpa_keymgmt; - break; - case IW_AUTH_80211_AUTH_ALG: - p->value = priv->wpa_authalg; - break; - default: - devdbg(usbdev, "SIOCGIWAUTH: invalid cmd %d", - wrqu->param.flags & IW_AUTH_INDEX); - return -EOPNOTSUPP; - } - return 0; -} - - -static int rndis_iw_set_encode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - struct rndis_wlan_encr_key key; - int ret, index, key_len; - u8 *keybuf; - - index = (wrqu->encoding.flags & IW_ENCODE_INDEX); - - /* iwconfig gives index as 1 - N */ - if (index > 0) - index--; - else - index = priv->encr_tx_key_index; - - if (index < 0 || index >= 4) { - devwarn(usbdev, "encryption index out of range (%u)", index); - return -EINVAL; - } - - /* remove key if disabled */ - if (wrqu->data.flags & IW_ENCODE_DISABLED) { - if (remove_key(usbdev, index, NULL)) - return -EINVAL; - else - return 0; - } - - /* global encryption state (for all keys) */ - if (wrqu->data.flags & IW_ENCODE_OPEN) - ret = set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_OPEN_SYSTEM, - RNDIS_WLAN_KEY_MGMT_NONE); - else /*if (wrqu->data.flags & IW_ENCODE_RESTRICTED)*/ - ret = set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_SHARED_KEY, - RNDIS_WLAN_KEY_MGMT_NONE); - if (ret != 0) - return ret; - - if (wrqu->data.length > 0) { - key_len = wrqu->data.length; - keybuf = extra; - } else { - /* must be set as tx key */ - if (priv->encr_keys[index].len == 0) - return -EINVAL; - key = priv->encr_keys[index]; - key_len = key.len; - keybuf = key.material; - priv->encr_tx_key_index = index; - } - - if (add_wep_key(usbdev, keybuf, key_len, index) != 0) - return -EINVAL; - - if (index == priv->encr_tx_key_index) - /* ndis drivers want essid to be set after setting encr */ - set_essid(usbdev, &priv->essid); - - return 0; -} - - -static int rndis_iw_set_encode_ext(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - int keyidx, flags, cipher; - - keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX; - - /* iwconfig gives index as 1 - N */ - if (keyidx) - keyidx--; - else - keyidx = priv->encr_tx_key_index; - - if (keyidx < 0 || keyidx >= 4) { - devwarn(usbdev, "encryption index out of range (%u)", keyidx); - return -EINVAL; - } - - if (ext->alg == IW_ENCODE_ALG_WEP) { - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - priv->encr_tx_key_index = keyidx; - return add_wep_key(usbdev, ext->key, ext->key_len, keyidx); - } - - cipher = -1; - if (ext->alg == IW_ENCODE_ALG_TKIP) - cipher = WLAN_CIPHER_SUITE_TKIP; - else if (ext->alg == IW_ENCODE_ALG_CCMP) - cipher = WLAN_CIPHER_SUITE_CCMP; - - if ((wrqu->encoding.flags & IW_ENCODE_DISABLED) || - ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0) - return remove_key(usbdev, keyidx, NULL); - - if (cipher == -1) - return -EOPNOTSUPP; - - flags = 0; - if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) - flags |= NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ; - if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)) - flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY; - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY; - - return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx, - (u8 *)&ext->addr.sa_data, ext->rx_seq, cipher, - flags); -} - - -static int rndis_iw_get_rate(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - __le32 tmp; - int ret, len; - - len = sizeof(tmp); - ret = rndis_query_oid(usbdev, OID_GEN_LINK_SPEED, &tmp, &len); - if (ret == 0) { - wrqu->bitrate.value = le32_to_cpu(tmp) * 100; - wrqu->bitrate.disabled = 0; - wrqu->bitrate.flags = 1; - } - return ret; -} - - -static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - unsigned long flags; - - spin_lock_irqsave(&priv->stats_lock, flags); - memcpy(&priv->iwstats, &priv->privstats, sizeof(priv->iwstats)); - spin_unlock_irqrestore(&priv->stats_lock, flags); - - return &priv->iwstats; -} -#endif - - -#define IW_IOCTL(x) [(x) - SIOCSIWCOMMIT] -static const iw_handler rndis_iw_handler[] = -{ - IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname, - IW_IOCTL(SIOCSIWFREQ) = (iw_handler) cfg80211_wext_siwfreq, - IW_IOCTL(SIOCGIWFREQ) = (iw_handler) cfg80211_wext_giwfreq, - IW_IOCTL(SIOCSIWMODE) = (iw_handler) cfg80211_wext_siwmode, - IW_IOCTL(SIOCGIWMODE) = (iw_handler) cfg80211_wext_giwmode, - IW_IOCTL(SIOCGIWRANGE) = (iw_handler) cfg80211_wext_giwrange, - IW_IOCTL(SIOCSIWAP) = (iw_handler) cfg80211_wext_siwap, - IW_IOCTL(SIOCGIWAP) = (iw_handler) cfg80211_wext_giwap, - IW_IOCTL(SIOCSIWSCAN) = (iw_handler) cfg80211_wext_siwscan, - IW_IOCTL(SIOCGIWSCAN) = (iw_handler) cfg80211_wext_giwscan, - IW_IOCTL(SIOCSIWESSID) = (iw_handler) cfg80211_wext_siwessid, - IW_IOCTL(SIOCGIWESSID) = (iw_handler) cfg80211_wext_giwessid, - IW_IOCTL(SIOCGIWRATE) = (iw_handler) cfg80211_wext_giwrate, - IW_IOCTL(SIOCSIWRTS) = (iw_handler) cfg80211_wext_siwrts, - IW_IOCTL(SIOCGIWRTS) = (iw_handler) cfg80211_wext_giwrts, - IW_IOCTL(SIOCSIWFRAG) = (iw_handler) cfg80211_wext_siwfrag, - IW_IOCTL(SIOCGIWFRAG) = (iw_handler) cfg80211_wext_giwfrag, - IW_IOCTL(SIOCSIWTXPOW) = (iw_handler) cfg80211_wext_siwtxpower, - IW_IOCTL(SIOCGIWTXPOW) = (iw_handler) cfg80211_wext_giwtxpower, - IW_IOCTL(SIOCSIWENCODE) = (iw_handler) cfg80211_wext_siwencode, - IW_IOCTL(SIOCSIWENCODEEXT) = (iw_handler) cfg80211_wext_siwencodeext, - IW_IOCTL(SIOCSIWAUTH) = (iw_handler) cfg80211_wext_siwauth, - IW_IOCTL(SIOCGIWAUTH) = (iw_handler) cfg80211_wext_giwauth, - IW_IOCTL(SIOCSIWGENIE) = (iw_handler) cfg80211_wext_siwgenie, - IW_IOCTL(SIOCSIWMLME) = (iw_handler) cfg80211_wext_siwmlme, -}; - -static const iw_handler rndis_wlan_private_handler[] = { -}; - -static const struct iw_priv_args rndis_wlan_private_args[] = { -}; - - -static const struct iw_handler_def rndis_iw_handlers = { - .num_standard = ARRAY_SIZE(rndis_iw_handler), - .num_private = ARRAY_SIZE(rndis_wlan_private_handler), - .num_private_args = ARRAY_SIZE(rndis_wlan_private_args), - .standard = (iw_handler *)rndis_iw_handler, - .private = (iw_handler *)rndis_wlan_private_handler, - .private_args = (struct iw_priv_args *)rndis_wlan_private_args, - .get_wireless_stats = cfg80211_wireless_stats, -}; - static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) { @@ -3166,7 +2746,6 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) * Otherwise we'll be in big trouble in rndis_wlan_early_init(). */ usbdev->driver_priv = priv; - usbdev->net->wireless_handlers = &rndis_iw_handlers; priv->usbdev = usbdev; mutex_init(&priv->command_lock); -- cgit v1.2.3-18-g5258 From ad43f8bfb7b9a6a8b800cdad24c4a62180a5eb3d Mon Sep 17 00:00:00 2001 From: Kiran Divekar Date: Fri, 28 Aug 2009 17:47:59 +0530 Subject: libertas: add NULL check on return value of get_zeroed_page Most of the places in debugfs.c are missing a NULL check on the return value of get_zeroed_page API call. Added required NULL check at appropriate places. Signed-off-by: Kiran Divekar Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/debugfs.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 811ffc3ef41..893a55ca344 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -45,6 +45,8 @@ static ssize_t lbs_dev_info(struct file *file, char __user *userbuf, unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; ssize_t res; + if (!buf) + return -ENOMEM; pos += snprintf(buf+pos, len-pos, "state = %s\n", szStates[priv->connect_status]); @@ -68,6 +70,8 @@ static ssize_t lbs_getscantable(struct file *file, char __user *userbuf, char *buf = (char *)addr; DECLARE_SSID_BUF(ssid); struct bss_descriptor * iter_bss; + if (!buf) + return -ENOMEM; pos += snprintf(buf+pos, len-pos, "# | ch | rssi | bssid | cap | Qual | SSID \n"); @@ -110,6 +114,8 @@ static ssize_t lbs_sleepparams_write(struct file *file, int p1, p2, p3, p4, p5, p6; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, user_buf, buf_size)) { @@ -148,6 +154,8 @@ static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf, struct sleep_params sp; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp); if (ret) @@ -433,6 +441,8 @@ static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf, int ret; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; offval.offset = priv->mac_offset; offval.value = 0; @@ -457,6 +467,8 @@ static ssize_t lbs_rdmac_write(struct file *file, ssize_t res, buf_size; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { @@ -481,6 +493,8 @@ static ssize_t lbs_wrmac_write(struct file *file, struct lbs_offset_value offval; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { @@ -515,6 +529,8 @@ static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf, int ret; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; offval.offset = priv->bbp_offset; offval.value = 0; @@ -540,6 +556,8 @@ static ssize_t lbs_rdbbp_write(struct file *file, ssize_t res, buf_size; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { @@ -564,6 +582,8 @@ static ssize_t lbs_wrbbp_write(struct file *file, struct lbs_offset_value offval; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { @@ -598,6 +618,8 @@ static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf, int ret; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; offval.offset = priv->rf_offset; offval.value = 0; @@ -623,6 +645,8 @@ static ssize_t lbs_rdrf_write(struct file *file, ssize_t res, buf_size; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { @@ -647,6 +671,8 @@ static ssize_t lbs_wrrf_write(struct file *file, struct lbs_offset_value offval; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { @@ -853,6 +879,8 @@ static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf, struct debug_data *d; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + if (!buf) + return -ENOMEM; p = buf; -- cgit v1.2.3-18-g5258 From 278339a42a1bcef1fb448d275056d519307e6025 Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Fri, 28 Aug 2009 12:05:12 +0000 Subject: bonding: propogate vlan_features to bonding master Propogate the vlan_features of the slave devices to the bonding master device, using the same logic as for regular features. Tested by Or Gerlitz , who also removed the debug logic from the original test patch. Signed-off-by: Or Gerlitz Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 4798d30c954..1aeb36c5147 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1331,6 +1331,7 @@ static int bond_compute_features(struct bonding *bond) struct slave *slave; struct net_device *bond_dev = bond->dev; unsigned long features = bond_dev->features; + unsigned long vlan_features = 0; unsigned short max_hard_header_len = max((u16)ETH_HLEN, bond_dev->hard_header_len); int i; @@ -1343,10 +1344,14 @@ static int bond_compute_features(struct bonding *bond) features &= ~NETIF_F_ONE_FOR_ALL; + vlan_features = bond->first_slave->dev->vlan_features; bond_for_each_slave(bond, slave, i) { features = netdev_increment_features(features, slave->dev->features, NETIF_F_ONE_FOR_ALL); + vlan_features = netdev_increment_features(vlan_features, + slave->dev->vlan_features, + NETIF_F_ONE_FOR_ALL); if (slave->dev->hard_header_len > max_hard_header_len) max_hard_header_len = slave->dev->hard_header_len; } @@ -1354,6 +1359,7 @@ static int bond_compute_features(struct bonding *bond) done: features |= (bond_dev->features & BOND_VLAN_FEATURES); bond_dev->features = netdev_fix_features(features, NULL); + bond_dev->vlan_features = netdev_fix_features(vlan_features, NULL); bond_dev->hard_header_len = max_hard_header_len; return 0; -- cgit v1.2.3-18-g5258 From 89c76c62f191daa7ede3d1d0c510a5ccfbcae571 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 28 Aug 2009 12:05:13 +0000 Subject: bonding: use compare_ether_addr Bonding can use compare_ether_addr() in bond_release. Signed-off-by: Stephen Hemminger Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 1aeb36c5147..ed00ba919d9 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1796,7 +1796,6 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) struct bonding *bond = netdev_priv(bond_dev); struct slave *slave, *oldcurrent; struct sockaddr addr; - int mac_addr_differ; /* slave is not a slave or master is not master of this slave */ if (!(slave_dev->flags & IFF_SLAVE) || @@ -1820,9 +1819,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) } if (!bond->params.fail_over_mac) { - mac_addr_differ = memcmp(bond_dev->dev_addr, slave->perm_hwaddr, - ETH_ALEN); - if (!mac_addr_differ && (bond->slave_cnt > 1)) + if (!compare_ether_addr(bond_dev->dev_addr, slave->perm_hwaddr) + && bond->slave_cnt > 1) pr_warning(DRV_NAME ": %s: Warning: the permanent HWaddr of %s - " "%pM - is still in use by %s. " -- cgit v1.2.3-18-g5258 From f584130616dfae757b888b7ee472e7c824f59e6a Mon Sep 17 00:00:00 2001 From: Nicolas de Pesloüan Date: Fri, 28 Aug 2009 13:18:34 +0000 Subject: bonding: Fix useless test: int > INT_MAX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit max_bonds is of type int and cannot be greater than INT_MAX. Signed-off-by: Nicolas de Pesloüan Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index ed00ba919d9..6b9f15b32a3 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4759,7 +4759,7 @@ static int bond_check_params(struct bond_params *params) params->ad_select = BOND_AD_STABLE; } - if (max_bonds < 0 || max_bonds > INT_MAX) { + if (max_bonds < 0) { pr_warning(DRV_NAME ": Warning: max_bonds (%d) not in range %d-%d, so it " "was reset to BOND_DEFAULT_MAX_BONDS (%d)\n", -- cgit v1.2.3-18-g5258 From 6c9888532bb540cb692f51f1d34fe9344eed5a0d Mon Sep 17 00:00:00 2001 From: Petri Gynther Date: Fri, 28 Aug 2009 12:05:15 +0000 Subject: bonding: Have bond_check_dev_link examine netif_running bonding: Have bond_check_dev_link examine netif_running Some network devices do not call netif_carrier_off when they are set administratively down. Have the bonding link check function also inspect the netif_running state. Ignore netif_running if the bond_check_dev_link function is called with "reporting" set, as in that case it's inspecting the capabilities of the non-netif_carrier device driver. Signed-off-by: Petri Gynther Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 6b9f15b32a3..7c0e0bded15 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -695,6 +695,9 @@ static int bond_check_dev_link(struct bonding *bond, struct ifreq ifr; struct mii_ioctl_data *mii; + if (!reporting && !netif_running(slave_dev)) + return 0; + if (bond->params.use_carrier) return netif_carrier_ok(slave_dev) ? BMSR_LSTATUS : 0; -- cgit v1.2.3-18-g5258 From b2014ff8ac314f58d6542ec4ea7b576a2de21c8b Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Thu, 27 Aug 2009 11:02:09 +0000 Subject: qlge: Get rid of 'default' rx_ring type. Currently we have three types of RX rings. 1) Default ring - services rx_ring for broadcast/multicast, handles firmware events, and errors. 2) TX completion ring - handles only outbound completions. 3) RSS ring - handles only inbound completions. This patch gets rid of the default ring type and moves it's functionality into the first RSS ring. This makes better use of MSIX vectors since they are a limited resource on some platforms. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge.h | 4 +-- drivers/net/qlge/qlge_dbg.c | 2 -- drivers/net/qlge/qlge_ethtool.c | 16 +++++----- drivers/net/qlge/qlge_main.c | 70 +++++++++++------------------------------ 4 files changed, 28 insertions(+), 64 deletions(-) (limited to 'drivers') diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 6ed5317ab1c..ed5dbca01bd 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -1287,7 +1287,7 @@ struct rx_ring { u32 sbq_free_cnt; /* free buffer desc cnt */ /* Misc. handler elements. */ - u32 type; /* Type of queue, tx, rx, or default. */ + u32 type; /* Type of queue, tx, rx. */ u32 irq; /* Which vector this ring is assigned. */ u32 cpu; /* Which CPU this should run on. */ char name[IFNAMSIZ + 5]; @@ -1486,11 +1486,9 @@ struct ql_adapter { struct intr_context intr_context[MAX_RX_RINGS]; int tx_ring_count; /* One per online CPU. */ - u32 rss_ring_first_cq_id;/* index of first inbound (rss) rx_ring */ u32 rss_ring_count; /* One per online CPU. */ /* * rx_ring_count = - * one default queue + * (CPU count * outbound completion rx_ring) + * (CPU count * inbound (RSS) completion rx_ring) */ diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c index 40a70c36f5a..aa88cb3f41c 100644 --- a/drivers/net/qlge/qlge_dbg.c +++ b/drivers/net/qlge/qlge_dbg.c @@ -418,8 +418,6 @@ void ql_dump_qdev(struct ql_adapter *qdev) printk(KERN_ERR PFX "qdev->intr_count = %d.\n", qdev->intr_count); printk(KERN_ERR PFX "qdev->tx_ring = %p.\n", qdev->tx_ring); - printk(KERN_ERR PFX "qdev->rss_ring_first_cq_id = %d.\n", - qdev->rss_ring_first_cq_id); printk(KERN_ERR PFX "qdev->rss_ring_count = %d.\n", qdev->rss_ring_count); printk(KERN_ERR PFX "qdev->rx_ring = %p.\n", qdev->rx_ring); diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c index eb6a9ee640e..68f9bd280f8 100644 --- a/drivers/net/qlge/qlge_ethtool.c +++ b/drivers/net/qlge/qlge_ethtool.c @@ -49,10 +49,11 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev) /* Skip the default queue, and update the outbound handler * queues if they changed. */ - cqicb = (struct cqicb *)&qdev->rx_ring[1]; + cqicb = (struct cqicb *)&qdev->rx_ring[qdev->rss_ring_count]; if (le16_to_cpu(cqicb->irq_delay) != qdev->tx_coalesce_usecs || - le16_to_cpu(cqicb->pkt_delay) != qdev->tx_max_coalesced_frames) { - for (i = 1; i < qdev->rss_ring_first_cq_id; i++, rx_ring++) { + le16_to_cpu(cqicb->pkt_delay) != + qdev->tx_max_coalesced_frames) { + for (i = qdev->rss_ring_count; i < qdev->rx_ring_count; i++) { rx_ring = &qdev->rx_ring[i]; cqicb = (struct cqicb *)rx_ring; cqicb->irq_delay = cpu_to_le16(qdev->tx_coalesce_usecs); @@ -70,12 +71,11 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev) } /* Update the inbound (RSS) handler queues if they changed. */ - cqicb = (struct cqicb *)&qdev->rx_ring[qdev->rss_ring_first_cq_id]; + cqicb = (struct cqicb *)&qdev->rx_ring[0]; if (le16_to_cpu(cqicb->irq_delay) != qdev->rx_coalesce_usecs || - le16_to_cpu(cqicb->pkt_delay) != qdev->rx_max_coalesced_frames) { - for (i = qdev->rss_ring_first_cq_id; - i <= qdev->rss_ring_first_cq_id + qdev->rss_ring_count; - i++) { + le16_to_cpu(cqicb->pkt_delay) != + qdev->rx_max_coalesced_frames) { + for (i = 0; i < qdev->rss_ring_count; i++, rx_ring++) { rx_ring = &qdev->rx_ring[i]; cqicb = (struct cqicb *)rx_ring; cqicb->irq_delay = cpu_to_le16(qdev->rx_coalesce_usecs); diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 3a271afdd8f..89ea9c7a58c 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -370,9 +370,7 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type, cam_output = (CAM_OUT_ROUTE_NIC | (qdev-> func << CAM_OUT_FUNC_SHIFT) | - (qdev-> - rss_ring_first_cq_id << - CAM_OUT_CQ_ID_SHIFT)); + (0 << CAM_OUT_CQ_ID_SHIFT)); if (qdev->vlgrp) cam_output |= CAM_OUT_RV; /* route to NIC core */ @@ -1649,8 +1647,7 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev, qdev->stats.rx_packets++; qdev->stats.rx_bytes += skb->len; - skb_record_rx_queue(skb, - rx_ring->cq_id - qdev->rss_ring_first_cq_id); + skb_record_rx_queue(skb, rx_ring->cq_id); if (skb->ip_summed == CHECKSUM_UNNECESSARY) { if (qdev->vlgrp && (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) && @@ -2044,7 +2041,7 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) ql_disable_completion_interrupt(qdev, intr_context-> intr); - if (i < qdev->rss_ring_first_cq_id) + if (i >= qdev->rss_ring_count) queue_delayed_work_on(rx_ring->cpu, qdev->q_workqueue, &rx_ring->rx_work, @@ -2908,28 +2905,20 @@ static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev) INTR_EN_TYPE_READ | INTR_EN_IHD_MASK | INTR_EN_IHD | i; - if (i == 0) { + if (i < qdev->rss_ring_count) { /* - * Default queue handles bcast/mcast plus - * async events. Needs buffers. + * Inbound queues handle unicast frames only. */ - intr_context->handler = qlge_isr; - sprintf(intr_context->name, "%s-default-queue", - qdev->ndev->name); - } else if (i < qdev->rss_ring_first_cq_id) { + intr_context->handler = qlge_msix_rx_isr; + sprintf(intr_context->name, "%s-rx-%d", + qdev->ndev->name, i); + } else { /* * Outbound queue is for outbound completions only. */ intr_context->handler = qlge_msix_tx_isr; sprintf(intr_context->name, "%s-tx-%d", qdev->ndev->name, i); - } else { - /* - * Inbound queues handle unicast frames only. - */ - intr_context->handler = qlge_msix_rx_isr; - sprintf(intr_context->name, "%s-rx-%d", - qdev->ndev->name, i); } } } else { @@ -3062,7 +3051,7 @@ static int ql_start_rss(struct ql_adapter *qdev) memset((void *)ricb, 0, sizeof(*ricb)); - ricb->base_cq = qdev->rss_ring_first_cq_id | RSS_L4K; + ricb->base_cq = RSS_L4K; ricb->flags = (RSS_L6K | RSS_LI | RSS_LB | RSS_LM | RSS_RI4 | RSS_RI6 | RSS_RT4 | RSS_RT6); @@ -3264,7 +3253,7 @@ static int ql_adapter_initialize(struct ql_adapter *qdev) } /* Start NAPI for the RSS queues. */ - for (i = qdev->rss_ring_first_cq_id; i < qdev->rx_ring_count; i++) { + for (i = 0; i < qdev->rss_ring_count; i++) { QPRINTK(qdev, IFUP, DEBUG, "Enabling NAPI for rx_ring[%d].\n", i); napi_enable(&qdev->rx_ring[i].napi); @@ -3355,7 +3344,7 @@ static int ql_adapter_down(struct ql_adapter *qdev) * environment. Outbound completion processing * is done in interrupt context. */ - if (i >= qdev->rss_ring_first_cq_id) { + if (i <= qdev->rss_ring_count) { napi_disable(&rx_ring->napi); } else { cancel_delayed_work_sync(&rx_ring->rx_work); @@ -3370,7 +3359,7 @@ static int ql_adapter_down(struct ql_adapter *qdev) /* Call netif_napi_del() from common point. */ - for (i = qdev->rss_ring_first_cq_id; i < qdev->rx_ring_count; i++) + for (i = 0; i < qdev->rss_ring_count; i++) netif_napi_del(&qdev->rx_ring[i].napi); ql_free_rx_buffers(qdev); @@ -3476,8 +3465,6 @@ static int ql_configure_rings(struct ql_adapter *qdev) qdev->tx_ring_count = cpu_cnt; /* Allocate inbound completion (RSS) ring for each CPU. */ qdev->rss_ring_count = cpu_cnt; - /* cq_id for the first inbound ring handler. */ - qdev->rss_ring_first_cq_id = cpu_cnt + 1; /* * qdev->rx_ring_count: * Total number of rx_rings. This includes the one @@ -3485,7 +3472,7 @@ static int ql_configure_rings(struct ql_adapter *qdev) * handler rx_rings, and the number of inbound * completion handler rx_rings. */ - qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count + 1; + qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count; for (i = 0; i < qdev->tx_ring_count; i++) { tx_ring = &qdev->tx_ring[i]; @@ -3500,7 +3487,7 @@ static int ql_configure_rings(struct ql_adapter *qdev) * The completion queue ID for the tx rings start * immediately after the default Q ID, which is zero. */ - tx_ring->cq_id = i + 1; + tx_ring->cq_id = i + qdev->rss_ring_count; } for (i = 0; i < qdev->rx_ring_count; i++) { @@ -3509,11 +3496,8 @@ static int ql_configure_rings(struct ql_adapter *qdev) rx_ring->qdev = qdev; rx_ring->cq_id = i; rx_ring->cpu = i % cpu_cnt; /* CPU to run handler on. */ - if (i == 0) { /* Default queue at index 0. */ - /* - * Default queue handles bcast/mcast plus - * async events. Needs buffers. - */ + if (i < qdev->rss_ring_count) { + /* Inbound completions (RSS) queues */ rx_ring->cq_len = qdev->rx_ring_size; rx_ring->cq_size = rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb); @@ -3525,8 +3509,8 @@ static int ql_configure_rings(struct ql_adapter *qdev) rx_ring->sbq_size = rx_ring->sbq_len * sizeof(__le64); rx_ring->sbq_buf_size = SMALL_BUFFER_SIZE * 2; - rx_ring->type = DEFAULT_Q; - } else if (i < qdev->rss_ring_first_cq_id) { + rx_ring->type = RX_Q; + } else { /* * Outbound queue handles outbound completions only. */ @@ -3541,22 +3525,6 @@ static int ql_configure_rings(struct ql_adapter *qdev) rx_ring->sbq_size = 0; rx_ring->sbq_buf_size = 0; rx_ring->type = TX_Q; - } else { /* Inbound completions (RSS) queues */ - /* - * Inbound queues handle unicast frames only. - */ - rx_ring->cq_len = qdev->rx_ring_size; - rx_ring->cq_size = - rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb); - rx_ring->lbq_len = NUM_LARGE_BUFFERS; - rx_ring->lbq_size = - rx_ring->lbq_len * sizeof(__le64); - rx_ring->lbq_buf_size = LARGE_BUFFER_SIZE; - rx_ring->sbq_len = NUM_SMALL_BUFFERS; - rx_ring->sbq_size = - rx_ring->sbq_len * sizeof(__le64); - rx_ring->sbq_buf_size = SMALL_BUFFER_SIZE * 2; - rx_ring->type = RX_Q; } } return 0; -- cgit v1.2.3-18-g5258 From a4ab613717184138763c5fb4a4b4bbc354d5b0ee Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Thu, 27 Aug 2009 11:02:10 +0000 Subject: qlge: Allow running MSIx with fewer vectors. Currently we downshift to MSI/Legacy if we don't get enough vectors for cpu_count RSS rings plus cpu_count TX completion rings. This patch allows running MSIX with the vector count that the platform provides. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 85 ++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 89ea9c7a58c..0cbda4d47dc 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -2815,17 +2815,20 @@ static void ql_disable_msix(struct ql_adapter *qdev) } } +/* We start by trying to get the number of vectors + * stored in qdev->intr_count. If we don't get that + * many then we reduce the count and try again. + */ static void ql_enable_msix(struct ql_adapter *qdev) { - int i; + int i, err; - qdev->intr_count = 1; /* Get the MSIX vectors. */ if (irq_type == MSIX_IRQ) { /* Try to alloc space for the msix struct, * if it fails then go to MSI/legacy. */ - qdev->msi_x_entry = kcalloc(qdev->rx_ring_count, + qdev->msi_x_entry = kcalloc(qdev->intr_count, sizeof(struct msix_entry), GFP_KERNEL); if (!qdev->msi_x_entry) { @@ -2833,26 +2836,36 @@ static void ql_enable_msix(struct ql_adapter *qdev) goto msi; } - for (i = 0; i < qdev->rx_ring_count; i++) + for (i = 0; i < qdev->intr_count; i++) qdev->msi_x_entry[i].entry = i; - if (!pci_enable_msix - (qdev->pdev, qdev->msi_x_entry, qdev->rx_ring_count)) { - set_bit(QL_MSIX_ENABLED, &qdev->flags); - qdev->intr_count = qdev->rx_ring_count; - QPRINTK(qdev, IFUP, DEBUG, - "MSI-X Enabled, got %d vectors.\n", - qdev->intr_count); - return; - } else { + /* Loop to get our vectors. We start with + * what we want and settle for what we get. + */ + do { + err = pci_enable_msix(qdev->pdev, + qdev->msi_x_entry, qdev->intr_count); + if (err > 0) + qdev->intr_count = err; + } while (err > 0); + + if (err < 0) { kfree(qdev->msi_x_entry); qdev->msi_x_entry = NULL; QPRINTK(qdev, IFUP, WARNING, "MSI-X Enable failed, trying MSI.\n"); + qdev->intr_count = 1; irq_type = MSI_IRQ; + } else if (err == 0) { + set_bit(QL_MSIX_ENABLED, &qdev->flags); + QPRINTK(qdev, IFUP, INFO, + "MSI-X Enabled, got %d vectors.\n", + qdev->intr_count); + return; } } msi: + qdev->intr_count = 1; if (irq_type == MSI_IRQ) { if (!pci_enable_msi(qdev->pdev)) { set_bit(QL_MSI_ENABLED, &qdev->flags); @@ -2876,8 +2889,6 @@ static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev) int i = 0; struct intr_context *intr_context = &qdev->intr_context[0]; - ql_enable_msix(qdev); - if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags))) { /* Each rx_ring has it's * own intr_context since we have separate @@ -3438,40 +3449,20 @@ static int ql_configure_rings(struct ql_adapter *qdev) int i; struct rx_ring *rx_ring; struct tx_ring *tx_ring; - int cpu_cnt = num_online_cpus(); - - /* - * For each processor present we allocate one - * rx_ring for outbound completions, and one - * rx_ring for inbound completions. Plus there is - * always the one default queue. For the CPU - * counts we end up with the following rx_rings: - * rx_ring count = - * one default queue + - * (CPU count * outbound completion rx_ring) + - * (CPU count * inbound (RSS) completion rx_ring) - * To keep it simple we limit the total number of - * queues to < 32, so we truncate CPU to 8. - * This limitation can be removed when requested. + int cpu_cnt = min(MAX_CPUS, (int)num_online_cpus()); + + /* In a perfect world we have one RSS ring for each CPU + * and each has it's own vector. To do that we ask for + * cpu_cnt vectors. ql_enable_msix() will adjust the + * vector count to what we actually get. We then + * allocate an RSS ring for each. + * Essentially, we are doing min(cpu_count, msix_vector_count). */ - - if (cpu_cnt > MAX_CPUS) - cpu_cnt = MAX_CPUS; - - /* - * rx_ring[0] is always the default queue. - */ - /* Allocate outbound completion ring for each CPU. */ + qdev->intr_count = cpu_cnt; + ql_enable_msix(qdev); + /* Adjust the RSS ring count to the actual vector count. */ + qdev->rss_ring_count = qdev->intr_count; qdev->tx_ring_count = cpu_cnt; - /* Allocate inbound completion (RSS) ring for each CPU. */ - qdev->rss_ring_count = cpu_cnt; - /* - * qdev->rx_ring_count: - * Total number of rx_rings. This includes the one - * default queue, a number of outbound completion - * handler rx_rings, and the number of inbound - * completion handler rx_rings. - */ qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count; for (i = 0; i < qdev->tx_ring_count; i++) { -- cgit v1.2.3-18-g5258 From 39aa81659353becbe4ee34d72cf79e02182e858a Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Thu, 27 Aug 2009 11:02:11 +0000 Subject: qlge: Move TX completions from workqueue to NAPI. TX completions were running in a workqueue queued by the ISR. This patch moves the processing of TX completions to an existing RSS NAPI context. Now each irq vector runs NAPI for one RSS ring and one or more TX completion rings. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge.h | 7 +- drivers/net/qlge/qlge_main.c | 266 ++++++++++++++++++++++--------------------- 2 files changed, 137 insertions(+), 136 deletions(-) (limited to 'drivers') diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index ed5dbca01bd..a9845a2f243 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -1292,7 +1292,6 @@ struct rx_ring { u32 cpu; /* Which CPU this should run on. */ char name[IFNAMSIZ + 5]; struct napi_struct napi; - struct delayed_work rx_work; u8 reserved; struct ql_adapter *qdev; }; @@ -1366,6 +1365,7 @@ struct nic_stats { struct intr_context { struct ql_adapter *qdev; u32 intr; + u32 irq_mask; /* Mask of which rings the vector services. */ u32 hooked; u32 intr_en_mask; /* value/mask used to enable this intr */ u32 intr_dis_mask; /* value/mask used to disable this intr */ @@ -1486,11 +1486,11 @@ struct ql_adapter { struct intr_context intr_context[MAX_RX_RINGS]; int tx_ring_count; /* One per online CPU. */ - u32 rss_ring_count; /* One per online CPU. */ + u32 rss_ring_count; /* One per irq vector. */ /* * rx_ring_count = * (CPU count * outbound completion rx_ring) + - * (CPU count * inbound (RSS) completion rx_ring) + * (irq_vector_cnt * inbound (RSS) completion rx_ring) */ int rx_ring_count; int ring_mem_size; @@ -1517,7 +1517,6 @@ struct ql_adapter { union flash_params flash; struct net_device_stats stats; - struct workqueue_struct *q_workqueue; struct workqueue_struct *workqueue; struct delayed_work asic_reset_work; struct delayed_work mpi_reset_work; diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 0cbda4d47dc..8dd266befdc 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -1859,11 +1859,41 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget) { struct rx_ring *rx_ring = container_of(napi, struct rx_ring, napi); struct ql_adapter *qdev = rx_ring->qdev; - int work_done = ql_clean_inbound_rx_ring(rx_ring, budget); + struct rx_ring *trx_ring; + int i, work_done = 0; + struct intr_context *ctx = &qdev->intr_context[rx_ring->cq_id]; QPRINTK(qdev, RX_STATUS, DEBUG, "Enter, NAPI POLL cq_id = %d.\n", rx_ring->cq_id); + /* Service the TX rings first. They start + * right after the RSS rings. */ + for (i = qdev->rss_ring_count; i < qdev->rx_ring_count; i++) { + trx_ring = &qdev->rx_ring[i]; + /* If this TX completion ring belongs to this vector and + * it's not empty then service it. + */ + if ((ctx->irq_mask & (1 << trx_ring->cq_id)) && + (ql_read_sh_reg(trx_ring->prod_idx_sh_reg) != + trx_ring->cnsmr_idx)) { + QPRINTK(qdev, INTR, DEBUG, + "%s: Servicing TX completion ring %d.\n", + __func__, trx_ring->cq_id); + ql_clean_outbound_rx_ring(trx_ring); + } + } + + /* + * Now service the RSS ring if it's active. + */ + if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) != + rx_ring->cnsmr_idx) { + QPRINTK(qdev, INTR, DEBUG, + "%s: Servicing RX completion ring %d.\n", + __func__, rx_ring->cq_id); + work_done = ql_clean_inbound_rx_ring(rx_ring, budget); + } + if (work_done < budget) { napi_complete(napi); ql_enable_completion_interrupt(qdev, rx_ring->irq); @@ -1925,38 +1955,6 @@ static void ql_vlan_rx_kill_vid(struct net_device *ndev, u16 vid) } -/* Worker thread to process a given rx_ring that is dedicated - * to outbound completions. - */ -static void ql_tx_clean(struct work_struct *work) -{ - struct rx_ring *rx_ring = - container_of(work, struct rx_ring, rx_work.work); - ql_clean_outbound_rx_ring(rx_ring); - ql_enable_completion_interrupt(rx_ring->qdev, rx_ring->irq); - -} - -/* Worker thread to process a given rx_ring that is dedicated - * to inbound completions. - */ -static void ql_rx_clean(struct work_struct *work) -{ - struct rx_ring *rx_ring = - container_of(work, struct rx_ring, rx_work.work); - ql_clean_inbound_rx_ring(rx_ring, 64); - ql_enable_completion_interrupt(rx_ring->qdev, rx_ring->irq); -} - -/* MSI-X Multiple Vector Interrupt Handler for outbound completions. */ -static irqreturn_t qlge_msix_tx_isr(int irq, void *dev_id) -{ - struct rx_ring *rx_ring = dev_id; - queue_delayed_work_on(rx_ring->cpu, rx_ring->qdev->q_workqueue, - &rx_ring->rx_work, 0); - return IRQ_HANDLED; -} - /* MSI-X Multiple Vector Interrupt Handler for inbound completions. */ static irqreturn_t qlge_msix_rx_isr(int irq, void *dev_id) { @@ -1976,7 +1974,6 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) struct ql_adapter *qdev = rx_ring->qdev; struct intr_context *intr_context = &qdev->intr_context[0]; u32 var; - int i; int work_done = 0; spin_lock(&qdev->hw_lock); @@ -2017,41 +2014,18 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) } /* - * Check the default queue and wake handler if active. + * Get the bit-mask that shows the active queues for this + * pass. Compare it to the queues that this irq services + * and call napi if there's a match. */ - rx_ring = &qdev->rx_ring[0]; - if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) != rx_ring->cnsmr_idx) { - QPRINTK(qdev, INTR, INFO, "Waking handler for rx_ring[0].\n"); - ql_disable_completion_interrupt(qdev, intr_context->intr); - queue_delayed_work_on(smp_processor_id(), qdev->q_workqueue, - &rx_ring->rx_work, 0); - work_done++; - } - - if (!test_bit(QL_MSIX_ENABLED, &qdev->flags)) { - /* - * Start the DPC for each active queue. - */ - for (i = 1; i < qdev->rx_ring_count; i++) { - rx_ring = &qdev->rx_ring[i]; - if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) != - rx_ring->cnsmr_idx) { + var = ql_read32(qdev, ISR1); + if (var & intr_context->irq_mask) { QPRINTK(qdev, INTR, INFO, - "Waking handler for rx_ring[%d].\n", i); - ql_disable_completion_interrupt(qdev, - intr_context-> - intr); - if (i >= qdev->rss_ring_count) - queue_delayed_work_on(rx_ring->cpu, - qdev->q_workqueue, - &rx_ring->rx_work, - 0); - else + "Waking handler for rx_ring[0].\n"); + ql_disable_completion_interrupt(qdev, intr_context->intr); napi_schedule(&rx_ring->napi); work_done++; } - } - } ql_enable_completion_interrupt(qdev, intr_context->intr); return work_done ? IRQ_HANDLED : IRQ_NONE; } @@ -2703,35 +2677,9 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) } switch (rx_ring->type) { case TX_Q: - /* If there's only one interrupt, then we use - * worker threads to process the outbound - * completion handling rx_rings. We do this so - * they can be run on multiple CPUs. There is - * room to play with this more where we would only - * run in a worker if there are more than x number - * of outbound completions on the queue and more - * than one queue active. Some threshold that - * would indicate a benefit in spite of the cost - * of a context switch. - * If there's more than one interrupt, then the - * outbound completions are processed in the ISR. - */ - if (!test_bit(QL_MSIX_ENABLED, &qdev->flags)) - INIT_DELAYED_WORK(&rx_ring->rx_work, ql_tx_clean); - else { - /* With all debug warnings on we see a WARN_ON message - * when we free the skb in the interrupt context. - */ - INIT_DELAYED_WORK(&rx_ring->rx_work, ql_tx_clean); - } cqicb->irq_delay = cpu_to_le16(qdev->tx_coalesce_usecs); cqicb->pkt_delay = cpu_to_le16(qdev->tx_max_coalesced_frames); break; - case DEFAULT_Q: - INIT_DELAYED_WORK(&rx_ring->rx_work, ql_rx_clean); - cqicb->irq_delay = 0; - cqicb->pkt_delay = 0; - break; case RX_Q: /* Inbound completion handling rx_rings run in * separate NAPI contexts. @@ -2878,6 +2826,71 @@ msi: QPRINTK(qdev, IFUP, DEBUG, "Running with legacy interrupts.\n"); } +/* Each vector services 1 RSS ring and and 1 or more + * TX completion rings. This function loops through + * the TX completion rings and assigns the vector that + * will service it. An example would be if there are + * 2 vectors (so 2 RSS rings) and 8 TX completion rings. + * This would mean that vector 0 would service RSS ring 0 + * and TX competion rings 0,1,2 and 3. Vector 1 would + * service RSS ring 1 and TX completion rings 4,5,6 and 7. + */ +static void ql_set_tx_vect(struct ql_adapter *qdev) +{ + int i, j, vect; + u32 tx_rings_per_vector = qdev->tx_ring_count / qdev->intr_count; + + if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags))) { + /* Assign irq vectors to TX rx_rings.*/ + for (vect = 0, j = 0, i = qdev->rss_ring_count; + i < qdev->rx_ring_count; i++) { + if (j == tx_rings_per_vector) { + vect++; + j = 0; + } + qdev->rx_ring[i].irq = vect; + j++; + } + } else { + /* For single vector all rings have an irq + * of zero. + */ + for (i = 0; i < qdev->rx_ring_count; i++) + qdev->rx_ring[i].irq = 0; + } +} + +/* Set the interrupt mask for this vector. Each vector + * will service 1 RSS ring and 1 or more TX completion + * rings. This function sets up a bit mask per vector + * that indicates which rings it services. + */ +static void ql_set_irq_mask(struct ql_adapter *qdev, struct intr_context *ctx) +{ + int j, vect = ctx->intr; + u32 tx_rings_per_vector = qdev->tx_ring_count / qdev->intr_count; + + if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags))) { + /* Add the RSS ring serviced by this vector + * to the mask. + */ + ctx->irq_mask = (1 << qdev->rx_ring[vect].cq_id); + /* Add the TX ring(s) serviced by this vector + * to the mask. */ + for (j = 0; j < tx_rings_per_vector; j++) { + ctx->irq_mask |= + (1 << qdev->rx_ring[qdev->rss_ring_count + + (vect * tx_rings_per_vector) + j].cq_id); + } + } else { + /* For single vector we just shift each queue's + * ID into the mask. + */ + for (j = 0; j < qdev->rx_ring_count; j++) + ctx->irq_mask |= (1 << qdev->rx_ring[j].cq_id); + } +} + /* * Here we build the intr_context structures based on * our rx_ring count and intr vector count. @@ -2893,12 +2906,15 @@ static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev) /* Each rx_ring has it's * own intr_context since we have separate * vectors for each queue. - * This only true when MSI-X is enabled. */ for (i = 0; i < qdev->intr_count; i++, intr_context++) { qdev->rx_ring[i].irq = i; intr_context->intr = i; intr_context->qdev = qdev; + /* Set up this vector's bit-mask that indicates + * which queues it services. + */ + ql_set_irq_mask(qdev, intr_context); /* * We set up each vectors enable/disable/read bits so * there's no bit/mask calculations in the critical path. @@ -2915,20 +2931,21 @@ static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev) INTR_EN_TYPE_MASK | INTR_EN_INTR_MASK | INTR_EN_TYPE_READ | INTR_EN_IHD_MASK | INTR_EN_IHD | i; - - if (i < qdev->rss_ring_count) { - /* - * Inbound queues handle unicast frames only. + if (i == 0) { + /* The first vector/queue handles + * broadcast/multicast, fatal errors, + * and firmware events. This in addition + * to normal inbound NAPI processing. */ - intr_context->handler = qlge_msix_rx_isr; + intr_context->handler = qlge_isr; sprintf(intr_context->name, "%s-rx-%d", qdev->ndev->name, i); } else { /* - * Outbound queue is for outbound completions only. + * Inbound queues handle unicast frames only. */ - intr_context->handler = qlge_msix_tx_isr; - sprintf(intr_context->name, "%s-tx-%d", + intr_context->handler = qlge_msix_rx_isr; + sprintf(intr_context->name, "%s-rx-%d", qdev->ndev->name, i); } } @@ -2955,9 +2972,17 @@ static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev) */ intr_context->handler = qlge_isr; sprintf(intr_context->name, "%s-single_irq", qdev->ndev->name); - for (i = 0; i < qdev->rx_ring_count; i++) - qdev->rx_ring[i].irq = 0; + /* Set up this vector's bit-mask that indicates + * which queues it services. In this case there is + * a single vector so it will service all RSS and + * TX completion rings. + */ + ql_set_irq_mask(qdev, intr_context); } + /* Tell the TX completion rings which MSIx vector + * they will be using. + */ + ql_set_tx_vect(qdev); } static void ql_free_irq(struct ql_adapter *qdev) @@ -3326,7 +3351,6 @@ static void ql_display_dev_info(struct net_device *ndev) static int ql_adapter_down(struct ql_adapter *qdev) { int i, status = 0; - struct rx_ring *rx_ring; ql_link_off(qdev); @@ -3340,27 +3364,8 @@ static int ql_adapter_down(struct ql_adapter *qdev) cancel_delayed_work_sync(&qdev->mpi_idc_work); cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); - /* The default queue at index 0 is always processed in - * a workqueue. - */ - cancel_delayed_work_sync(&qdev->rx_ring[0].rx_work); - - /* The rest of the rx_rings are processed in - * a workqueue only if it's a single interrupt - * environment (MSI/Legacy). - */ - for (i = 1; i < qdev->rx_ring_count; i++) { - rx_ring = &qdev->rx_ring[i]; - /* Only the RSS rings use NAPI on multi irq - * environment. Outbound completion processing - * is done in interrupt context. - */ - if (i <= qdev->rss_ring_count) { - napi_disable(&rx_ring->napi); - } else { - cancel_delayed_work_sync(&rx_ring->rx_work); - } - } + for (i = 0; i < qdev->rss_ring_count; i++) + napi_disable(&qdev->rx_ring[i].napi); clear_bit(QL_ADAPTER_UP, &qdev->flags); @@ -3476,9 +3481,9 @@ static int ql_configure_rings(struct ql_adapter *qdev) /* * The completion queue ID for the tx rings start - * immediately after the default Q ID, which is zero. + * immediately after the rss rings. */ - tx_ring->cq_id = i + qdev->rss_ring_count; + tx_ring->cq_id = qdev->rss_ring_count + i; } for (i = 0; i < qdev->rx_ring_count; i++) { @@ -3488,7 +3493,9 @@ static int ql_configure_rings(struct ql_adapter *qdev) rx_ring->cq_id = i; rx_ring->cpu = i % cpu_cnt; /* CPU to run handler on. */ if (i < qdev->rss_ring_count) { - /* Inbound completions (RSS) queues */ + /* + * Inbound (RSS) queues. + */ rx_ring->cq_len = qdev->rx_ring_size; rx_ring->cq_size = rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb); @@ -3804,10 +3811,7 @@ static void ql_release_all(struct pci_dev *pdev) destroy_workqueue(qdev->workqueue); qdev->workqueue = NULL; } - if (qdev->q_workqueue) { - destroy_workqueue(qdev->q_workqueue); - qdev->q_workqueue = NULL; - } + if (qdev->reg_base) iounmap(qdev->reg_base); if (qdev->doorbell_area) @@ -3920,8 +3924,6 @@ static int __devinit ql_init_device(struct pci_dev *pdev, * Set up the operating parameters. */ qdev->rx_csum = 1; - - qdev->q_workqueue = create_workqueue(ndev->name); qdev->workqueue = create_singlethread_workqueue(ndev->name); INIT_DELAYED_WORK(&qdev->asic_reset_work, ql_asic_reset_work); INIT_DELAYED_WORK(&qdev->mpi_reset_work, ql_mpi_reset_work); -- cgit v1.2.3-18-g5258 From ec0248ea35f6e1fc7426f377a7df071d997bdedd Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 26 Aug 2009 09:49:22 +0000 Subject: cnic: Put rx/tx ring allocation in separate function. This will allow the 10G iSCSI code to reuse the function. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/cnic.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c index 4869d77cbe9..039900c4169 100644 --- a/drivers/net/cnic.c +++ b/drivers/net/cnic.c @@ -742,6 +742,26 @@ static int cnic_alloc_context(struct cnic_dev *dev) return 0; } +static int cnic_alloc_l2_rings(struct cnic_dev *dev, int pages) +{ + struct cnic_local *cp = dev->cnic_priv; + + cp->l2_ring_size = pages * BCM_PAGE_SIZE; + cp->l2_ring = pci_alloc_consistent(dev->pcidev, cp->l2_ring_size, + &cp->l2_ring_map); + if (!cp->l2_ring) + return -ENOMEM; + + cp->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size; + cp->l2_buf_size = PAGE_ALIGN(cp->l2_buf_size); + cp->l2_buf = pci_alloc_consistent(dev->pcidev, cp->l2_buf_size, + &cp->l2_buf_map); + if (!cp->l2_buf) + return -ENOMEM; + + return 0; +} + static int cnic_alloc_bnx2_resc(struct cnic_dev *dev) { struct cnic_local *cp = dev->cnic_priv; @@ -762,17 +782,8 @@ static int cnic_alloc_bnx2_resc(struct cnic_dev *dev) if (ret) goto error; - cp->l2_ring_size = 2 * BCM_PAGE_SIZE; - cp->l2_ring = pci_alloc_consistent(dev->pcidev, cp->l2_ring_size, - &cp->l2_ring_map); - if (!cp->l2_ring) - goto error; - - cp->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size; - cp->l2_buf_size = PAGE_ALIGN(cp->l2_buf_size); - cp->l2_buf = pci_alloc_consistent(dev->pcidev, cp->l2_buf_size, - &cp->l2_buf_map); - if (!cp->l2_buf) + ret = cnic_alloc_l2_rings(dev, 2); + if (ret) goto error; uinfo = kzalloc(sizeof(*uinfo), GFP_ATOMIC); -- cgit v1.2.3-18-g5258 From 5e9b2dbfcbc9b180a0064d8a473a4652ee99c9ad Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 26 Aug 2009 09:49:23 +0000 Subject: cnic: Put uio init in separate function. This will allow the 10G iSCSI code to reuse the function. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/cnic.c | 68 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c index 039900c4169..f8a09236dc0 100644 --- a/drivers/net/cnic.c +++ b/drivers/net/cnic.c @@ -762,33 +762,14 @@ static int cnic_alloc_l2_rings(struct cnic_dev *dev, int pages) return 0; } -static int cnic_alloc_bnx2_resc(struct cnic_dev *dev) -{ +static int cnic_alloc_uio(struct cnic_dev *dev) { struct cnic_local *cp = dev->cnic_priv; struct uio_info *uinfo; int ret; - ret = cnic_alloc_dma(dev, &cp->kwq_info, KWQ_PAGE_CNT, 1); - if (ret) - goto error; - cp->kwq = (struct kwqe **) cp->kwq_info.pg_arr; - - ret = cnic_alloc_dma(dev, &cp->kcq_info, KCQ_PAGE_CNT, 1); - if (ret) - goto error; - cp->kcq = (struct kcqe **) cp->kcq_info.pg_arr; - - ret = cnic_alloc_context(dev); - if (ret) - goto error; - - ret = cnic_alloc_l2_rings(dev, 2); - if (ret) - goto error; - uinfo = kzalloc(sizeof(*uinfo), GFP_ATOMIC); if (!uinfo) - goto error; + return -ENOMEM; uinfo->mem[0].addr = dev->netdev->base_addr; uinfo->mem[0].internal_addr = dev->regview; @@ -796,10 +777,15 @@ static int cnic_alloc_bnx2_resc(struct cnic_dev *dev) uinfo->mem[0].memtype = UIO_MEM_PHYS; uinfo->mem[1].addr = (unsigned long) cp->status_blk & PAGE_MASK; - if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) - uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE * 9; - else - uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE; + if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) { + if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) + uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE * 9; + else + uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE; + + uinfo->name = "bnx2_cnic"; + } + uinfo->mem[1].memtype = UIO_MEM_LOGICAL; uinfo->mem[2].addr = (unsigned long) cp->l2_ring; @@ -810,7 +796,6 @@ static int cnic_alloc_bnx2_resc(struct cnic_dev *dev) uinfo->mem[3].size = cp->l2_buf_size; uinfo->mem[3].memtype = UIO_MEM_LOGICAL; - uinfo->name = "bnx2_cnic"; uinfo->version = CNIC_MODULE_VERSION; uinfo->irq = UIO_IRQ_CUSTOM; @@ -822,10 +807,39 @@ static int cnic_alloc_bnx2_resc(struct cnic_dev *dev) ret = uio_register_device(&dev->pcidev->dev, uinfo); if (ret) { kfree(uinfo); - goto error; + return ret; } cp->cnic_uinfo = uinfo; + return 0; +} + +static int cnic_alloc_bnx2_resc(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + int ret; + + ret = cnic_alloc_dma(dev, &cp->kwq_info, KWQ_PAGE_CNT, 1); + if (ret) + goto error; + cp->kwq = (struct kwqe **) cp->kwq_info.pg_arr; + + ret = cnic_alloc_dma(dev, &cp->kcq_info, KCQ_PAGE_CNT, 1); + if (ret) + goto error; + cp->kcq = (struct kcqe **) cp->kcq_info.pg_arr; + + ret = cnic_alloc_context(dev); + if (ret) + goto error; + + ret = cnic_alloc_l2_rings(dev, 2); + if (ret) + goto error; + + ret = cnic_alloc_uio(dev); + if (ret) + goto error; return 0; -- cgit v1.2.3-18-g5258 From 078b0735881c7969aaf21469f3577831cddd9f8c Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sat, 29 Aug 2009 00:02:46 -0700 Subject: bnx2: Update firmware to 5.0.0.j3. - Better small packet receive performance. - Better handling of Flow control on 5709. - Fixed iSCSI TMP ABORT TASK problem. - Added iSCSI TCP timestamp option. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 4450177a162..c4e85f69427 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -61,10 +61,11 @@ #define PFX DRV_MODULE_NAME ": " #define DRV_MODULE_VERSION "2.0.2" #define DRV_MODULE_RELDATE "Aug 21, 2009" -#define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-4.6.16.fw" -#define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-4.6.16.fw" -#define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-4.6.17.fw" -#define FW_RV2P_FILE_09 "bnx2/bnx2-rv2p-09-4.6.15.fw" +#define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-5.0.0.j3.fw" +#define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-5.0.0.j3.fw" +#define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-5.0.0.j3.fw" +#define FW_RV2P_FILE_09_Ax "bnx2/bnx2-rv2p-09ax-5.0.0.j3.fw" +#define FW_RV2P_FILE_09 "bnx2/bnx2-rv2p-09-5.0.0.j3.fw" #define RUN_AT(x) (jiffies + (x)) @@ -82,6 +83,7 @@ MODULE_FIRMWARE(FW_MIPS_FILE_06); MODULE_FIRMWARE(FW_RV2P_FILE_06); MODULE_FIRMWARE(FW_MIPS_FILE_09); MODULE_FIRMWARE(FW_RV2P_FILE_09); +MODULE_FIRMWARE(FW_RV2P_FILE_09_Ax); static int disable_msi = 0; @@ -3621,7 +3623,11 @@ bnx2_request_firmware(struct bnx2 *bp) if (CHIP_NUM(bp) == CHIP_NUM_5709) { mips_fw_file = FW_MIPS_FILE_09; - rv2p_fw_file = FW_RV2P_FILE_09; + if ((CHIP_ID(bp) == CHIP_ID_5709_A0) || + (CHIP_ID(bp) == CHIP_ID_5709_A1)) + rv2p_fw_file = FW_RV2P_FILE_09_Ax; + else + rv2p_fw_file = FW_RV2P_FILE_09; } else { mips_fw_file = FW_MIPS_FILE_06; rv2p_fw_file = FW_RV2P_FILE_06; -- cgit v1.2.3-18-g5258 From 38edb5b87ea26314cb6ad4524c3f3b0fea0e33de Mon Sep 17 00:00:00 2001 From: Krzysztof Halasa Date: Wed, 19 Aug 2009 23:56:20 +0000 Subject: WAN/LMC: Fix type_trans(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix lmc_proto_type() invocation. Signed-off-by: Krzysztof HaÅ‚asa Signed-off-by: David S. Miller --- drivers/net/wan/lmc/lmc_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index 6e6b08c3a1e..4b83d887285 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -1657,7 +1657,7 @@ static int lmc_rx(struct net_device *dev) } skb_copy_from_linear_data(skb, skb_put(nsb, len), len); - nsb->protocol = lmc_proto_type(sc, skb); + nsb->protocol = lmc_proto_type(sc, nsb); skb_reset_mac_header(nsb); /* skb_reset_network_header(nsb); */ nsb->dev = dev; -- cgit v1.2.3-18-g5258 From 2db9517ef3dd48790c02a531e2b0db1957afd891 Mon Sep 17 00:00:00 2001 From: "Rajashekhara, Sudhakar" Date: Wed, 19 Aug 2009 10:39:55 +0000 Subject: TI DaVinci EMAC: delay DaVinci EMAC initialization On TI's DA850/OMAP-L138 EVM, MAC address is stored in SPI flash which is accessed using MTD interface. This patch delays the initialization of DaVinci EMAC driver by changing module_init to late_initcall. This helps SPI and MTD drivers to get initialized before EMAC thereby enabling EMAC driver to read the MAC address while booting and use it. Tested with NFS on DM644x, DM6467, DA830/OMAP-L137 and DA850/OMAP-L138 EVMs. Signed-off-by: Sudhakar Rajashekhara Reviewed-by: Chaithrika U S Signed-off-by: Kevin Hilman Signed-off-by: David S. Miller --- drivers/net/davinci_emac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 12fd446f989..5e6652b8728 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -2817,7 +2817,7 @@ static int __init davinci_emac_init(void) { return platform_driver_register(&davinci_emac_driver); } -module_init(davinci_emac_init); +late_initcall(davinci_emac_init); /** * davinci_emac_exit: EMAC driver module exit -- cgit v1.2.3-18-g5258 From 4923576b8ac5bfd36ab2beb176aeb747aaab7e41 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Thu, 27 Aug 2009 23:25:03 +0000 Subject: net: sh_eth: add value of ether_link pin in platform_data The method of ETHER_LINK pin is board dependence. This patch adding paramters are: - no_ether_link : If set to 1, do not use ETHER_LINK - ether_link_active_low : If set to 1, ETHER_LINK is active low. Signed-off-by: Yoshihiro Shimoda Signed-off-by: David S. Miller --- drivers/net/sh_eth.c | 6 +++++- drivers/net/sh_eth.h | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 4c4dcbf1902..f49d0800c1d 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -772,13 +772,15 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) mdp->stats.tx_carrier_errors++; if (felic_stat & ECSR_LCHNG) { /* Link Changed */ - if (mdp->cd->no_psr) { + if (mdp->cd->no_psr || mdp->no_ether_link) { if (mdp->link == PHY_DOWN) link_stat = 0; else link_stat = PHY_ST_LINK; } else { link_stat = (ctrl_inl(ioaddr + PSR)); + if (mdp->ether_link_active_low) + link_stat = ~link_stat; } if (!(link_stat & PHY_ST_LINK)) { /* Link Down : disable tx and rx */ @@ -1410,6 +1412,8 @@ static int sh_eth_drv_probe(struct platform_device *pdev) mdp->phy_id = pd->phy; /* EDMAC endian */ mdp->edmac_endian = pd->edmac_endian; + mdp->no_ether_link = pd->no_ether_link; + mdp->ether_link_active_low = pd->ether_link_active_low; /* set cpu data */ mdp->cd = &sh_eth_my_cpu_data; diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h index 9afe5b4c855..ba151f86ae7 100644 --- a/drivers/net/sh_eth.h +++ b/drivers/net/sh_eth.h @@ -729,6 +729,9 @@ struct sh_eth_private { char post_rx; /* POST receive */ char post_fw; /* POST forward */ struct net_device_stats tsu_stats; /* TSU forward status */ + + unsigned no_ether_link:1; + unsigned ether_link_active_low:1; }; static inline void sh_eth_soft_swap(char *src, int len) -- cgit v1.2.3-18-g5258 From 70590ea75b7f9ef4846b0b0f4400e8338dbcc7eb Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Wed, 26 Aug 2009 16:21:54 -0700 Subject: pci/intr_remapping: Allocate irq_iommu on node make it use the node from irq_desc. Signed-off-by: Yinghai Lu Acked-by: Jesse Barnes Cc: Andrew Morton LKML-Reference: <4A95C392.5050903@kernel.org> Signed-off-by: Ingo Molnar --- drivers/pci/intr_remapping.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index 4f5b8712931..44803644ca0 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c @@ -55,15 +55,12 @@ static struct irq_2_iommu *irq_2_iommu(unsigned int irq) return desc->irq_2_iommu; } -static struct irq_2_iommu *irq_2_iommu_alloc_node(unsigned int irq, int node) +static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq) { struct irq_desc *desc; struct irq_2_iommu *irq_iommu; - /* - * alloc irq desc if not allocated already. - */ - desc = irq_to_desc_alloc_node(irq, node); + desc = irq_to_desc(irq); if (!desc) { printk(KERN_INFO "can not get irq_desc for %d\n", irq); return NULL; @@ -72,16 +69,11 @@ static struct irq_2_iommu *irq_2_iommu_alloc_node(unsigned int irq, int node) irq_iommu = desc->irq_2_iommu; if (!irq_iommu) - desc->irq_2_iommu = get_one_free_irq_2_iommu(node); + desc->irq_2_iommu = get_one_free_irq_2_iommu(irq_node(irq)); return desc->irq_2_iommu; } -static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq) -{ - return irq_2_iommu_alloc_node(irq, cpu_to_node(boot_cpu_id)); -} - #else /* !CONFIG_SPARSE_IRQ */ static struct irq_2_iommu irq_2_iommuX[NR_IRQS]; -- cgit v1.2.3-18-g5258 From 0a9140cff22e405fce1747a2e02d41851c36c55a Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 12:27:50 +0000 Subject: tg3: Delay mdio bus init until fw finishes The device firmware uses the MDIO bus during early setup. If the driver modifies the MDIO bus configuration while it is in use by the firmware, any number of bad things can happen. This patch delays MDIO setup until after the firmware posts its magic signature, signifying initialization is complete. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 8af2cdf181d..ab3159ef4c5 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6348,14 +6348,14 @@ static int tg3_chip_reset(struct tg3 *tp) tw32_f(MAC_MODE, 0); udelay(40); - tg3_mdio_start(tp); - tg3_ape_unlock(tp, TG3_APE_LOCK_GRC); err = tg3_poll_fw(tp); if (err) return err; + tg3_mdio_start(tp); + if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) { val = tr32(0x7c00); -- cgit v1.2.3-18-g5258 From 2befdcea96fcd9a13e94373c66ea1dd7365d2a74 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 12:28:45 +0000 Subject: tg3: Add new 5785 10/100 only device ID This patch adds a new device ID for those 5785 devices that will only use 10/100 phys. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 3 ++- drivers/net/tg3.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index ab3159ef4c5..d43b30b80f1 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -219,7 +219,8 @@ static struct pci_device_id tg3_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5761S)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5761SE)}, - {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5785)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5785_G)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5785_F)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57780)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57760)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57790)}, diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 60b12ab7933..1c9495df67c 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -44,6 +44,8 @@ #define TG3PCI_DEVICE_TIGON3_57760 0x1690 #define TG3PCI_DEVICE_TIGON3_57790 0x1694 #define TG3PCI_DEVICE_TIGON3_57788 0x1691 +#define TG3PCI_DEVICE_TIGON3_5785_G 0x1699 /* GPHY */ +#define TG3PCI_DEVICE_TIGON3_5785_F 0x16a0 /* 10/100 only */ /* 0x04 --> 0x64 unused */ #define TG3PCI_MSI_DATA 0x00000064 /* 0x66 --> 0x68 unused */ -- cgit v1.2.3-18-g5258 From 8590a603e5e20ccf49d6cf0ea71ecf5388d1f9da Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 12:29:16 +0000 Subject: tg3: Reformat NVRAM case statements This patch fixes up the NVRAM detection switch statements to conform to the kernel coding style. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 369 +++++++++++++++++++++++++++--------------------------- 1 file changed, 183 insertions(+), 186 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index d43b30b80f1..4c4d164a4b4 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10302,8 +10302,7 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) nvcfg1 = tr32(NVRAM_CFG1); if (nvcfg1 & NVRAM_CFG1_FLASHIF_ENAB) { tp->tg3_flags2 |= TG3_FLG2_FLASH; - } - else { + } else { nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; tw32(NVRAM_CFG1, nvcfg1); } @@ -10311,37 +10310,36 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) { - case FLASH_VENDOR_ATMEL_FLASH_BUFFERED: - tp->nvram_jedecnum = JEDEC_ATMEL; - tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - break; - case FLASH_VENDOR_ATMEL_FLASH_UNBUFFERED: - tp->nvram_jedecnum = JEDEC_ATMEL; - tp->nvram_pagesize = ATMEL_AT25F512_PAGE_SIZE; - break; - case FLASH_VENDOR_ATMEL_EEPROM: - tp->nvram_jedecnum = JEDEC_ATMEL; - tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - break; - case FLASH_VENDOR_ST: - tp->nvram_jedecnum = JEDEC_ST; - tp->nvram_pagesize = ST_M45PEX0_PAGE_SIZE; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - break; - case FLASH_VENDOR_SAIFUN: - tp->nvram_jedecnum = JEDEC_SAIFUN; - tp->nvram_pagesize = SAIFUN_SA25F0XX_PAGE_SIZE; - break; - case FLASH_VENDOR_SST_SMALL: - case FLASH_VENDOR_SST_LARGE: - tp->nvram_jedecnum = JEDEC_SST; - tp->nvram_pagesize = SST_25VF0X0_PAGE_SIZE; - break; + case FLASH_VENDOR_ATMEL_FLASH_BUFFERED: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + break; + case FLASH_VENDOR_ATMEL_FLASH_UNBUFFERED: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->nvram_pagesize = ATMEL_AT25F512_PAGE_SIZE; + break; + case FLASH_VENDOR_ATMEL_EEPROM: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + break; + case FLASH_VENDOR_ST: + tp->nvram_jedecnum = JEDEC_ST; + tp->nvram_pagesize = ST_M45PEX0_PAGE_SIZE; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + break; + case FLASH_VENDOR_SAIFUN: + tp->nvram_jedecnum = JEDEC_SAIFUN; + tp->nvram_pagesize = SAIFUN_SA25F0XX_PAGE_SIZE; + break; + case FLASH_VENDOR_SST_SMALL: + case FLASH_VENDOR_SST_LARGE: + tp->nvram_jedecnum = JEDEC_SST; + tp->nvram_pagesize = SST_25VF0X0_PAGE_SIZE; + break; } - } - else { + } else { tp->nvram_jedecnum = JEDEC_ATMEL; tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE; tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; @@ -10359,48 +10357,47 @@ static void __devinit tg3_get_5752_nvram_info(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_PROTECTED_NVRAM; switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { - case FLASH_5752VENDOR_ATMEL_EEPROM_64KHZ: - case FLASH_5752VENDOR_ATMEL_EEPROM_376KHZ: - tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - break; - case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED: - tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; - break; - case FLASH_5752VENDOR_ST_M45PE10: - case FLASH_5752VENDOR_ST_M45PE20: - case FLASH_5752VENDOR_ST_M45PE40: - tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; - break; + case FLASH_5752VENDOR_ATMEL_EEPROM_64KHZ: + case FLASH_5752VENDOR_ATMEL_EEPROM_376KHZ: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + break; + case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + break; + case FLASH_5752VENDOR_ST_M45PE10: + case FLASH_5752VENDOR_ST_M45PE20: + case FLASH_5752VENDOR_ST_M45PE40: + tp->nvram_jedecnum = JEDEC_ST; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + break; } if (tp->tg3_flags2 & TG3_FLG2_FLASH) { switch (nvcfg1 & NVRAM_CFG1_5752PAGE_SIZE_MASK) { - case FLASH_5752PAGE_SIZE_256: - tp->nvram_pagesize = 256; - break; - case FLASH_5752PAGE_SIZE_512: - tp->nvram_pagesize = 512; - break; - case FLASH_5752PAGE_SIZE_1K: - tp->nvram_pagesize = 1024; - break; - case FLASH_5752PAGE_SIZE_2K: - tp->nvram_pagesize = 2048; - break; - case FLASH_5752PAGE_SIZE_4K: - tp->nvram_pagesize = 4096; - break; - case FLASH_5752PAGE_SIZE_264: - tp->nvram_pagesize = 264; - break; + case FLASH_5752PAGE_SIZE_256: + tp->nvram_pagesize = 256; + break; + case FLASH_5752PAGE_SIZE_512: + tp->nvram_pagesize = 512; + break; + case FLASH_5752PAGE_SIZE_1K: + tp->nvram_pagesize = 1024; + break; + case FLASH_5752PAGE_SIZE_2K: + tp->nvram_pagesize = 2048; + break; + case FLASH_5752PAGE_SIZE_4K: + tp->nvram_pagesize = 4096; + break; + case FLASH_5752PAGE_SIZE_264: + tp->nvram_pagesize = 264; + break; } - } - else { + } else { /* For eeprom, set pagesize to maximum eeprom size */ tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; @@ -10423,45 +10420,45 @@ static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp) nvcfg1 &= NVRAM_CFG1_5752VENDOR_MASK; switch (nvcfg1) { - case FLASH_5755VENDOR_ATMEL_FLASH_1: - case FLASH_5755VENDOR_ATMEL_FLASH_2: - case FLASH_5755VENDOR_ATMEL_FLASH_3: - case FLASH_5755VENDOR_ATMEL_FLASH_5: - tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; - tp->nvram_pagesize = 264; - if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_1 || - nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_5) - tp->nvram_size = (protect ? 0x3e200 : - TG3_NVRAM_SIZE_512KB); - else if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_2) - tp->nvram_size = (protect ? 0x1f200 : - TG3_NVRAM_SIZE_256KB); - else - tp->nvram_size = (protect ? 0x1f200 : - TG3_NVRAM_SIZE_128KB); - break; - case FLASH_5752VENDOR_ST_M45PE10: - case FLASH_5752VENDOR_ST_M45PE20: - case FLASH_5752VENDOR_ST_M45PE40: - tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; - tp->nvram_pagesize = 256; - if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE10) - tp->nvram_size = (protect ? - TG3_NVRAM_SIZE_64KB : - TG3_NVRAM_SIZE_128KB); - else if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE20) - tp->nvram_size = (protect ? - TG3_NVRAM_SIZE_64KB : - TG3_NVRAM_SIZE_256KB); - else - tp->nvram_size = (protect ? - TG3_NVRAM_SIZE_128KB : - TG3_NVRAM_SIZE_512KB); - break; + case FLASH_5755VENDOR_ATMEL_FLASH_1: + case FLASH_5755VENDOR_ATMEL_FLASH_2: + case FLASH_5755VENDOR_ATMEL_FLASH_3: + case FLASH_5755VENDOR_ATMEL_FLASH_5: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + tp->nvram_pagesize = 264; + if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_1 || + nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_5) + tp->nvram_size = (protect ? 0x3e200 : + TG3_NVRAM_SIZE_512KB); + else if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_2) + tp->nvram_size = (protect ? 0x1f200 : + TG3_NVRAM_SIZE_256KB); + else + tp->nvram_size = (protect ? 0x1f200 : + TG3_NVRAM_SIZE_128KB); + break; + case FLASH_5752VENDOR_ST_M45PE10: + case FLASH_5752VENDOR_ST_M45PE20: + case FLASH_5752VENDOR_ST_M45PE40: + tp->nvram_jedecnum = JEDEC_ST; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + tp->nvram_pagesize = 256; + if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE10) + tp->nvram_size = (protect ? + TG3_NVRAM_SIZE_64KB : + TG3_NVRAM_SIZE_128KB); + else if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE20) + tp->nvram_size = (protect ? + TG3_NVRAM_SIZE_64KB : + TG3_NVRAM_SIZE_256KB); + else + tp->nvram_size = (protect ? + TG3_NVRAM_SIZE_128KB : + TG3_NVRAM_SIZE_512KB); + break; } } @@ -10472,34 +10469,34 @@ static void __devinit tg3_get_5787_nvram_info(struct tg3 *tp) nvcfg1 = tr32(NVRAM_CFG1); switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { - case FLASH_5787VENDOR_ATMEL_EEPROM_64KHZ: - case FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ: - case FLASH_5787VENDOR_MICRO_EEPROM_64KHZ: - case FLASH_5787VENDOR_MICRO_EEPROM_376KHZ: - tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; + case FLASH_5787VENDOR_ATMEL_EEPROM_64KHZ: + case FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ: + case FLASH_5787VENDOR_MICRO_EEPROM_64KHZ: + case FLASH_5787VENDOR_MICRO_EEPROM_376KHZ: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; - nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; - tw32(NVRAM_CFG1, nvcfg1); - break; - case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED: - case FLASH_5755VENDOR_ATMEL_FLASH_1: - case FLASH_5755VENDOR_ATMEL_FLASH_2: - case FLASH_5755VENDOR_ATMEL_FLASH_3: - tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; - tp->nvram_pagesize = 264; - break; - case FLASH_5752VENDOR_ST_M45PE10: - case FLASH_5752VENDOR_ST_M45PE20: - case FLASH_5752VENDOR_ST_M45PE40: - tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; - tp->nvram_pagesize = 256; - break; + nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; + tw32(NVRAM_CFG1, nvcfg1); + break; + case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED: + case FLASH_5755VENDOR_ATMEL_FLASH_1: + case FLASH_5755VENDOR_ATMEL_FLASH_2: + case FLASH_5755VENDOR_ATMEL_FLASH_3: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + tp->nvram_pagesize = 264; + break; + case FLASH_5752VENDOR_ST_M45PE10: + case FLASH_5752VENDOR_ST_M45PE20: + case FLASH_5752VENDOR_ST_M45PE40: + tp->nvram_jedecnum = JEDEC_ST; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + tp->nvram_pagesize = 256; + break; } } @@ -10517,63 +10514,63 @@ static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp) nvcfg1 &= NVRAM_CFG1_5752VENDOR_MASK; switch (nvcfg1) { - case FLASH_5761VENDOR_ATMEL_ADB021D: - case FLASH_5761VENDOR_ATMEL_ADB041D: - case FLASH_5761VENDOR_ATMEL_ADB081D: - case FLASH_5761VENDOR_ATMEL_ADB161D: - case FLASH_5761VENDOR_ATMEL_MDB021D: - case FLASH_5761VENDOR_ATMEL_MDB041D: - case FLASH_5761VENDOR_ATMEL_MDB081D: - case FLASH_5761VENDOR_ATMEL_MDB161D: - tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; - tp->nvram_pagesize = 256; - break; - case FLASH_5761VENDOR_ST_A_M45PE20: - case FLASH_5761VENDOR_ST_A_M45PE40: - case FLASH_5761VENDOR_ST_A_M45PE80: - case FLASH_5761VENDOR_ST_A_M45PE16: - case FLASH_5761VENDOR_ST_M_M45PE20: - case FLASH_5761VENDOR_ST_M_M45PE40: - case FLASH_5761VENDOR_ST_M_M45PE80: - case FLASH_5761VENDOR_ST_M_M45PE16: - tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; - tp->nvram_pagesize = 256; - break; + case FLASH_5761VENDOR_ATMEL_ADB021D: + case FLASH_5761VENDOR_ATMEL_ADB041D: + case FLASH_5761VENDOR_ATMEL_ADB081D: + case FLASH_5761VENDOR_ATMEL_ADB161D: + case FLASH_5761VENDOR_ATMEL_MDB021D: + case FLASH_5761VENDOR_ATMEL_MDB041D: + case FLASH_5761VENDOR_ATMEL_MDB081D: + case FLASH_5761VENDOR_ATMEL_MDB161D: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; + tp->nvram_pagesize = 256; + break; + case FLASH_5761VENDOR_ST_A_M45PE20: + case FLASH_5761VENDOR_ST_A_M45PE40: + case FLASH_5761VENDOR_ST_A_M45PE80: + case FLASH_5761VENDOR_ST_A_M45PE16: + case FLASH_5761VENDOR_ST_M_M45PE20: + case FLASH_5761VENDOR_ST_M_M45PE40: + case FLASH_5761VENDOR_ST_M_M45PE80: + case FLASH_5761VENDOR_ST_M_M45PE16: + tp->nvram_jedecnum = JEDEC_ST; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + tp->nvram_pagesize = 256; + break; } if (protect) { tp->nvram_size = tr32(NVRAM_ADDR_LOCKOUT); } else { switch (nvcfg1) { - case FLASH_5761VENDOR_ATMEL_ADB161D: - case FLASH_5761VENDOR_ATMEL_MDB161D: - case FLASH_5761VENDOR_ST_A_M45PE16: - case FLASH_5761VENDOR_ST_M_M45PE16: - tp->nvram_size = TG3_NVRAM_SIZE_2MB; - break; - case FLASH_5761VENDOR_ATMEL_ADB081D: - case FLASH_5761VENDOR_ATMEL_MDB081D: - case FLASH_5761VENDOR_ST_A_M45PE80: - case FLASH_5761VENDOR_ST_M_M45PE80: - tp->nvram_size = TG3_NVRAM_SIZE_1MB; - break; - case FLASH_5761VENDOR_ATMEL_ADB041D: - case FLASH_5761VENDOR_ATMEL_MDB041D: - case FLASH_5761VENDOR_ST_A_M45PE40: - case FLASH_5761VENDOR_ST_M_M45PE40: - tp->nvram_size = TG3_NVRAM_SIZE_512KB; - break; - case FLASH_5761VENDOR_ATMEL_ADB021D: - case FLASH_5761VENDOR_ATMEL_MDB021D: - case FLASH_5761VENDOR_ST_A_M45PE20: - case FLASH_5761VENDOR_ST_M_M45PE20: - tp->nvram_size = TG3_NVRAM_SIZE_256KB; - break; + case FLASH_5761VENDOR_ATMEL_ADB161D: + case FLASH_5761VENDOR_ATMEL_MDB161D: + case FLASH_5761VENDOR_ST_A_M45PE16: + case FLASH_5761VENDOR_ST_M_M45PE16: + tp->nvram_size = TG3_NVRAM_SIZE_2MB; + break; + case FLASH_5761VENDOR_ATMEL_ADB081D: + case FLASH_5761VENDOR_ATMEL_MDB081D: + case FLASH_5761VENDOR_ST_A_M45PE80: + case FLASH_5761VENDOR_ST_M_M45PE80: + tp->nvram_size = TG3_NVRAM_SIZE_1MB; + break; + case FLASH_5761VENDOR_ATMEL_ADB041D: + case FLASH_5761VENDOR_ATMEL_MDB041D: + case FLASH_5761VENDOR_ST_A_M45PE40: + case FLASH_5761VENDOR_ST_M_M45PE40: + tp->nvram_size = TG3_NVRAM_SIZE_512KB; + break; + case FLASH_5761VENDOR_ATMEL_ADB021D: + case FLASH_5761VENDOR_ATMEL_MDB021D: + case FLASH_5761VENDOR_ST_A_M45PE20: + case FLASH_5761VENDOR_ST_M_M45PE20: + tp->nvram_size = TG3_NVRAM_SIZE_256KB; + break; } } } -- cgit v1.2.3-18-g5258 From fdb72b38c94c0ead1f78ecc8db64b832feda22c3 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 13:57:12 +0000 Subject: tg3: Break out mini producer ring handling This patch separates the code that sets up the mini producer ring from the code that sets up the jumbo producer rings. The 5717 asic rev devices do not have a mini ring, but do have a jumbo frame implementation similar to the 5704 and previous devices. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 4c4d164a4b4..606703cf961 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6967,19 +6967,16 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR, NIC_SRAM_RX_BUFFER_DESC); - /* Don't even try to program the JUMBO/MINI buffer descriptor - * configs on 5705. - */ - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { - tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS, - RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT); - } else { - tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS, - RX_STD_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT); - + /* Disable the mini ring */ + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS, BDINFO_FLAGS_DISABLED); + /* Program the jumbo buffer descriptor ring control + * blocks on those devices that have them. + */ + if ((tp->tg3_flags2 & TG3_FLG2_JUMBO_CAPABLE) && + !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { /* Setup replenish threshold. */ tw32(RCVBDI_JUMBO_THRESH, tp->rx_jumbo_pending / 8); @@ -6997,7 +6994,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) BDINFO_FLAGS_DISABLED); } - } + val = RX_STD_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT; + } else + val = RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT; + + tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS, val); /* There is only one send ring on 5705/5750, no need to explicitly * disable the others. -- cgit v1.2.3-18-g5258 From 8f666b07ac53eeedd6c035adf6d4299f9ed0df2d Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 13:58:24 +0000 Subject: tg3: Move the JUMBO_CAPABLE and SUPPORT_MSI flags This patch moves where the jumbo capable and msi support flags are located. This is prep work for the addition of msix support flags. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 10 +++++----- drivers/net/tg3.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 606703cf961..5e74a19e7c1 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -92,7 +92,7 @@ /* hardware minimum and maximum for a single frame's data payload */ #define TG3_MIN_MTU 60 #define TG3_MAX_MTU(tp) \ - ((tp->tg3_flags2 & TG3_FLG2_JUMBO_CAPABLE) ? 9000 : 1500) + ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) ? 9000 : 1500) /* These numbers seem to be hard coded in the NIC firmware somehow. * You can't change the ring sizes, but you can change where you place @@ -1921,7 +1921,7 @@ out: if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) { /* Cannot do read-modify-write on 5401 */ tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4c20); - } else if (tp->tg3_flags2 & TG3_FLG2_JUMBO_CAPABLE) { + } else if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { u32 phy_reg; /* Set bit 14 with read-modify-write to preserve other bits */ @@ -1933,7 +1933,7 @@ out: /* Set phy register 0x10 bit 0 to high fifo elasticity to support * jumbo frames transmission. */ - if (tp->tg3_flags2 & TG3_FLG2_JUMBO_CAPABLE) { + if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { u32 phy_reg; if (!tg3_readphy(tp, MII_TG3_EXT_CTRL, &phy_reg)) @@ -6975,7 +6975,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) /* Program the jumbo buffer descriptor ring control * blocks on those devices that have them. */ - if ((tp->tg3_flags2 & TG3_FLG2_JUMBO_CAPABLE) && + if ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) && !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { /* Setup replenish threshold. */ tw32(RCVBDI_JUMBO_THRESH, tp->rx_jumbo_pending / 8); @@ -12034,7 +12034,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) - tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE; + tp->tg3_flags |= TG3_FLAG_JUMBO_CAPABLE; pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, &pci_state_reg); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 1c9495df67c..5efae2c5138 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2601,6 +2601,7 @@ struct tg3 { #define TG3_FLAG_EEPROM_WRITE_PROT 0x00001000 #define TG3_FLAG_NVRAM 0x00002000 #define TG3_FLAG_NVRAM_BUFFERED 0x00004000 +#define TG3_FLAG_SUPPORT_MSI 0x00008000 #define TG3_FLAG_PCIX_MODE 0x00020000 #define TG3_FLAG_PCI_HIGH_SPEED 0x00040000 #define TG3_FLAG_PCI_32BIT 0x00080000 @@ -2613,7 +2614,7 @@ struct tg3 { #define TG3_FLAG_CPMU_PRESENT 0x04000000 #define TG3_FLAG_40BIT_DMA_BUG 0x08000000 #define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000 -#define TG3_FLAG_SUPPORT_MSI 0x20000000 +#define TG3_FLAG_JUMBO_CAPABLE 0x20000000 #define TG3_FLAG_CHIP_RESETTING 0x40000000 #define TG3_FLAG_INIT_COMPLETE 0x80000000 u32 tg3_flags2; @@ -2639,7 +2640,6 @@ struct tg3 { #define TG3_FLG2_5750_PLUS 0x00080000 #define TG3_FLG2_PROTECTED_NVRAM 0x00100000 #define TG3_FLG2_USING_MSI 0x00200000 -#define TG3_FLG2_JUMBO_CAPABLE 0x00400000 #define TG3_FLG2_MII_SERDES 0x00800000 #define TG3_FLG2_ANY_SERDES (TG3_FLG2_PHY_SERDES | \ TG3_FLG2_MII_SERDES) -- cgit v1.2.3-18-g5258 From 287be12e1774d842bff21ea0c1809c2387d7b310 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 13:58:46 +0000 Subject: tg3: Clarify rx buffer relationships This patch attempts to document the various rx buffer sizes used by the driver and how they relate to each other. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 42 +++++++++++++++++++++++------------------- drivers/net/tg3.h | 2 +- 2 files changed, 24 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 5e74a19e7c1..a2a5f318315 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -125,8 +125,15 @@ TG3_TX_RING_SIZE) #define NEXT_TX(N) (((N) + 1) & (TG3_TX_RING_SIZE - 1)) -#define RX_PKT_BUF_SZ (1536 + tp->rx_offset + 64) -#define RX_JUMBO_PKT_BUF_SZ (9046 + tp->rx_offset + 64) +#define TG3_DMA_BYTE_ENAB 64 + +#define TG3_RX_STD_DMA_SZ 1536 +#define TG3_RX_JMB_DMA_SZ 9046 + +#define TG3_RX_DMA_TO_MAP_SZ(x) ((x) + TG3_DMA_BYTE_ENAB) + +#define TG3_RX_STD_MAP_SZ TG3_RX_DMA_TO_MAP_SZ(TG3_RX_STD_DMA_SZ) +#define TG3_RX_JMB_MAP_SZ TG3_RX_DMA_TO_MAP_SZ(TG3_RX_JMB_DMA_SZ) /* minimum number of free TX descriptors required to wake up TX process */ #define TG3_TX_WAKEUP_THRESH(tp) ((tp)->tx_pending / 4) @@ -4354,7 +4361,7 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key, map = &tp->rx_std_buffers[dest_idx]; if (src_idx >= 0) src_map = &tp->rx_std_buffers[src_idx]; - skb_size = tp->rx_pkt_buf_sz; + skb_size = tp->rx_pkt_map_sz; break; case RXD_OPAQUE_RING_JUMBO: @@ -4363,7 +4370,7 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key, map = &tp->rx_jumbo_buffers[dest_idx]; if (src_idx >= 0) src_map = &tp->rx_jumbo_buffers[src_idx]; - skb_size = RX_JUMBO_PKT_BUF_SZ; + skb_size = TG3_RX_JMB_MAP_SZ; break; default: @@ -4376,14 +4383,13 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key, * Callers depend upon this behavior and assume that * we leave everything unchanged if we fail. */ - skb = netdev_alloc_skb(tp->dev, skb_size); + skb = netdev_alloc_skb(tp->dev, skb_size + tp->rx_offset); if (skb == NULL) return -ENOMEM; skb_reserve(skb, tp->rx_offset); - mapping = pci_map_single(tp->pdev, skb->data, - skb_size - tp->rx_offset, + mapping = pci_map_single(tp->pdev, skb->data, skb_size, PCI_DMA_FROMDEVICE); map->skb = skb; @@ -4540,8 +4546,7 @@ static int tg3_rx(struct tg3 *tp, int budget) if (skb_size < 0) goto drop_it; - pci_unmap_single(tp->pdev, dma_addr, - skb_size - tp->rx_offset, + pci_unmap_single(tp->pdev, dma_addr, skb_size, PCI_DMA_FROMDEVICE); skb_put(skb, len); @@ -5531,7 +5536,7 @@ static void tg3_free_rings(struct tg3 *tp) continue; pci_unmap_single(tp->pdev, pci_unmap_addr(rxp, mapping), - tp->rx_pkt_buf_sz - tp->rx_offset, + tp->rx_pkt_map_sz, PCI_DMA_FROMDEVICE); dev_kfree_skb_any(rxp->skb); rxp->skb = NULL; @@ -5544,7 +5549,7 @@ static void tg3_free_rings(struct tg3 *tp) continue; pci_unmap_single(tp->pdev, pci_unmap_addr(rxp, mapping), - RX_JUMBO_PKT_BUF_SZ - tp->rx_offset, + TG3_RX_JMB_MAP_SZ, PCI_DMA_FROMDEVICE); dev_kfree_skb_any(rxp->skb); rxp->skb = NULL; @@ -5581,7 +5586,7 @@ static void tg3_free_rings(struct tg3 *tp) */ static int tg3_init_rings(struct tg3 *tp) { - u32 i; + u32 i, rx_pkt_dma_sz; /* Free up all the SKBs. */ tg3_free_rings(tp); @@ -5592,10 +5597,11 @@ static int tg3_init_rings(struct tg3 *tp) memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); - tp->rx_pkt_buf_sz = RX_PKT_BUF_SZ; + rx_pkt_dma_sz = TG3_RX_STD_DMA_SZ; if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) && - (tp->dev->mtu > ETH_DATA_LEN)) - tp->rx_pkt_buf_sz = RX_JUMBO_PKT_BUF_SZ; + tp->dev->mtu > ETH_DATA_LEN) + rx_pkt_dma_sz = TG3_RX_JMB_DMA_SZ; + tp->rx_pkt_map_sz = TG3_RX_DMA_TO_MAP_SZ(rx_pkt_dma_sz); /* Initialize invariants of the rings, we only set this * stuff once. This works because the card does not @@ -5605,8 +5611,7 @@ static int tg3_init_rings(struct tg3 *tp) struct tg3_rx_buffer_desc *rxd; rxd = &tp->rx_std[i]; - rxd->idx_len = (tp->rx_pkt_buf_sz - tp->rx_offset - 64) - << RXD_LEN_SHIFT; + rxd->idx_len = rx_pkt_dma_sz << RXD_LEN_SHIFT; rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT); rxd->opaque = (RXD_OPAQUE_RING_STD | (i << RXD_OPAQUE_INDEX_SHIFT)); @@ -5617,8 +5622,7 @@ static int tg3_init_rings(struct tg3 *tp) struct tg3_rx_buffer_desc *rxd; rxd = &tp->rx_jumbo[i]; - rxd->idx_len = (RX_JUMBO_PKT_BUF_SZ - tp->rx_offset - 64) - << RXD_LEN_SHIFT; + rxd->idx_len = TG3_RX_JMB_DMA_SZ << RXD_LEN_SHIFT; rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) | RXD_FLAG_JUMBO; rxd->opaque = (RXD_OPAQUE_RING_JUMBO | diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 5efae2c5138..d029b4b9b92 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2571,7 +2571,7 @@ struct tg3 { struct tg3_rx_buffer_desc *rx_rcb; dma_addr_t rx_rcb_mapping; - u32 rx_pkt_buf_sz; + u32 rx_pkt_map_sz; /* begin "everything else" cacheline(s) section */ struct net_device_stats net_stats; -- cgit v1.2.3-18-g5258 From cf7a7298c4f47ab7546b933bb54ad3ea03a1daf6 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 13:59:57 +0000 Subject: tg3: Create rx producer ring setup routines Later patches are going to complicate the ring initialization routines. This patch breaks out the setup and teardown of the rx producer rings into separate functions to make the code more readable. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 231 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 144 insertions(+), 87 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index a2a5f318315..5d0a1e6e051 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5517,14 +5517,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) return err; } -/* Free up pending packets in all rx/tx rings. - * - * The chip has been shut down and the driver detached from - * the networking, so no interrupts or new tx packets will - * end up in the driver. tp->{tx,}lock is not held and we are not - * in an interrupt context and thus may sleep. - */ -static void tg3_free_rings(struct tg3 *tp) +static void tg3_rx_prodring_free(struct tg3 *tp) { struct ring_info *rxp; int i; @@ -5534,46 +5527,29 @@ static void tg3_free_rings(struct tg3 *tp) if (rxp->skb == NULL) continue; - pci_unmap_single(tp->pdev, - pci_unmap_addr(rxp, mapping), - tp->rx_pkt_map_sz, - PCI_DMA_FROMDEVICE); - dev_kfree_skb_any(rxp->skb); - rxp->skb = NULL; - } - - for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) { - rxp = &tp->rx_jumbo_buffers[i]; - if (rxp->skb == NULL) - continue; pci_unmap_single(tp->pdev, pci_unmap_addr(rxp, mapping), - TG3_RX_JMB_MAP_SZ, + tp->rx_pkt_map_sz, PCI_DMA_FROMDEVICE); dev_kfree_skb_any(rxp->skb); rxp->skb = NULL; } - for (i = 0; i < TG3_TX_RING_SIZE; ) { - struct tx_ring_info *txp; - struct sk_buff *skb; + if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { + for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) { + rxp = &tp->rx_jumbo_buffers[i]; - txp = &tp->tx_buffers[i]; - skb = txp->skb; + if (rxp->skb == NULL) + continue; - if (skb == NULL) { - i++; - continue; + pci_unmap_single(tp->pdev, + pci_unmap_addr(rxp, mapping), + TG3_RX_JMB_MAP_SZ, + PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(rxp->skb); + rxp->skb = NULL; } - - skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE); - - txp->skb = NULL; - - i += skb_shinfo(skb)->nr_frags + 1; - - dev_kfree_skb_any(skb); } } @@ -5584,18 +5560,12 @@ static void tg3_free_rings(struct tg3 *tp) * end up in the driver. tp->{tx,}lock are held and thus * we may not sleep. */ -static int tg3_init_rings(struct tg3 *tp) +static int tg3_rx_prodring_alloc(struct tg3 *tp) { u32 i, rx_pkt_dma_sz; - /* Free up all the SKBs. */ - tg3_free_rings(tp); - /* Zero out all descriptors. */ memset(tp->rx_std, 0, TG3_RX_RING_BYTES); - memset(tp->rx_jumbo, 0, TG3_RX_JUMBO_RING_BYTES); - memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); - memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); rx_pkt_dma_sz = TG3_RX_STD_DMA_SZ; if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) && @@ -5617,19 +5587,6 @@ static int tg3_init_rings(struct tg3 *tp) (i << RXD_OPAQUE_INDEX_SHIFT)); } - if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) { - for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) { - struct tg3_rx_buffer_desc *rxd; - - rxd = &tp->rx_jumbo[i]; - rxd->idx_len = TG3_RX_JMB_DMA_SZ << RXD_LEN_SHIFT; - rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) | - RXD_FLAG_JUMBO; - rxd->opaque = (RXD_OPAQUE_RING_JUMBO | - (i << RXD_OPAQUE_INDEX_SHIFT)); - } - } - /* Now allocate fresh SKBs for each rx ring. */ for (i = 0; i < tp->rx_pending; i++) { if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_STD, -1, i) < 0) { @@ -5639,13 +5596,29 @@ static int tg3_init_rings(struct tg3 *tp) "successfully.\n", tp->dev->name, i, tp->rx_pending); if (i == 0) - return -ENOMEM; + goto initfail; tp->rx_pending = i; break; } } + if (!(tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE)) + goto done; + + memset(tp->rx_jumbo, 0, TG3_RX_JUMBO_RING_BYTES); + if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) { + for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) { + struct tg3_rx_buffer_desc *rxd; + + rxd = &tp->rx_jumbo[i]; + rxd->idx_len = TG3_RX_JMB_DMA_SZ << RXD_LEN_SHIFT; + rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) | + RXD_FLAG_JUMBO; + rxd->opaque = (RXD_OPAQUE_RING_JUMBO | + (i << RXD_OPAQUE_INDEX_SHIFT)); + } + for (i = 0; i < tp->rx_jumbo_pending; i++) { if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_JUMBO, -1, i) < 0) { @@ -5654,26 +5627,28 @@ static int tg3_init_rings(struct tg3 *tp) "only %d out of %d buffers were " "allocated successfully.\n", tp->dev->name, i, tp->rx_jumbo_pending); - if (i == 0) { - tg3_free_rings(tp); - return -ENOMEM; - } + if (i == 0) + goto initfail; tp->rx_jumbo_pending = i; break; } } } + +done: return 0; + +initfail: + tg3_rx_prodring_free(tp); + return -ENOMEM; } -/* - * Must not be invoked with interrupt sources disabled and - * the hardware shutdown down. - */ -static void tg3_free_consistent(struct tg3 *tp) +static void tg3_rx_prodring_fini(struct tg3 *tp) { kfree(tp->rx_std_buffers); tp->rx_std_buffers = NULL; + kfree(tp->rx_jumbo_buffers); + tp->rx_jumbo_buffers = NULL; if (tp->rx_std) { pci_free_consistent(tp->pdev, TG3_RX_RING_BYTES, tp->rx_std, tp->rx_std_mapping); @@ -5684,6 +5659,103 @@ static void tg3_free_consistent(struct tg3 *tp) tp->rx_jumbo, tp->rx_jumbo_mapping); tp->rx_jumbo = NULL; } +} + +static int tg3_rx_prodring_init(struct tg3 *tp) +{ + tp->rx_std_buffers = kzalloc(sizeof(struct ring_info) * + TG3_RX_RING_SIZE, GFP_KERNEL); + if (!tp->rx_std_buffers) + return -ENOMEM; + + tp->rx_std = pci_alloc_consistent(tp->pdev, TG3_RX_RING_BYTES, + &tp->rx_std_mapping); + if (!tp->rx_std) + goto err_out; + + if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { + tp->rx_jumbo_buffers = kzalloc(sizeof(struct ring_info) * + TG3_RX_JUMBO_RING_SIZE, + GFP_KERNEL); + if (!tp->rx_jumbo_buffers) + goto err_out; + + tp->rx_jumbo = pci_alloc_consistent(tp->pdev, + TG3_RX_JUMBO_RING_BYTES, + &tp->rx_jumbo_mapping); + if (!tp->rx_jumbo) + goto err_out; + } + + return 0; + +err_out: + tg3_rx_prodring_fini(tp); + return -ENOMEM; +} + +/* Free up pending packets in all rx/tx rings. + * + * The chip has been shut down and the driver detached from + * the networking, so no interrupts or new tx packets will + * end up in the driver. tp->{tx,}lock is not held and we are not + * in an interrupt context and thus may sleep. + */ +static void tg3_free_rings(struct tg3 *tp) +{ + int i; + + for (i = 0; i < TG3_TX_RING_SIZE; ) { + struct tx_ring_info *txp; + struct sk_buff *skb; + + txp = &tp->tx_buffers[i]; + skb = txp->skb; + + if (skb == NULL) { + i++; + continue; + } + + skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE); + + txp->skb = NULL; + + i += skb_shinfo(skb)->nr_frags + 1; + + dev_kfree_skb_any(skb); + } + + tg3_rx_prodring_free(tp); +} + +/* Initialize tx/rx rings for packet processing. + * + * The chip has been shut down and the driver detached from + * the networking, so no interrupts or new tx packets will + * end up in the driver. tp->{tx,}lock are held and thus + * we may not sleep. + */ +static int tg3_init_rings(struct tg3 *tp) +{ + /* Free up all the SKBs. */ + tg3_free_rings(tp); + + /* Zero out all descriptors. */ + memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); + memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); + + return tg3_rx_prodring_alloc(tp); +} + +/* + * Must not be invoked with interrupt sources disabled and + * the hardware shutdown down. + */ +static void tg3_free_consistent(struct tg3 *tp) +{ + kfree(tp->tx_buffers); + tp->tx_buffers = NULL; if (tp->rx_rcb) { pci_free_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp), tp->rx_rcb, tp->rx_rcb_mapping); @@ -5704,6 +5776,7 @@ static void tg3_free_consistent(struct tg3 *tp) tp->hw_stats, tp->stats_mapping); tp->hw_stats = NULL; } + tg3_rx_prodring_fini(tp); } /* @@ -5712,28 +5785,12 @@ static void tg3_free_consistent(struct tg3 *tp) */ static int tg3_alloc_consistent(struct tg3 *tp) { - tp->rx_std_buffers = kzalloc((sizeof(struct ring_info) * - (TG3_RX_RING_SIZE + - TG3_RX_JUMBO_RING_SIZE)) + - (sizeof(struct tx_ring_info) * - TG3_TX_RING_SIZE), - GFP_KERNEL); - if (!tp->rx_std_buffers) + if (tg3_rx_prodring_init(tp)) return -ENOMEM; - tp->rx_jumbo_buffers = &tp->rx_std_buffers[TG3_RX_RING_SIZE]; - tp->tx_buffers = (struct tx_ring_info *) - &tp->rx_jumbo_buffers[TG3_RX_JUMBO_RING_SIZE]; - - tp->rx_std = pci_alloc_consistent(tp->pdev, TG3_RX_RING_BYTES, - &tp->rx_std_mapping); - if (!tp->rx_std) - goto err_out; - - tp->rx_jumbo = pci_alloc_consistent(tp->pdev, TG3_RX_JUMBO_RING_BYTES, - &tp->rx_jumbo_mapping); - - if (!tp->rx_jumbo) + tp->tx_buffers = kzalloc(sizeof(struct tx_ring_info) * + TG3_TX_RING_SIZE, GFP_KERNEL); + if (!tp->tx_buffers) goto err_out; tp->rx_rcb = pci_alloc_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp), -- cgit v1.2.3-18-g5258 From 21f581a5366d48d86b9ae86043fc61d44e992c0c Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 14:00:25 +0000 Subject: tg3: Create a new prodring_set structure This patch migrates most of the rx producer ring variables to a new tg3_rx_prodring_set structure and modifies the code accordingly. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 163 ++++++++++++++++++++++++++++-------------------------- drivers/net/tg3.h | 27 +++++---- 2 files changed, 100 insertions(+), 90 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 5d0a1e6e051..053d4e85820 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4352,24 +4352,25 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key, struct sk_buff *skb; dma_addr_t mapping; int skb_size, dest_idx; + struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; src_map = NULL; switch (opaque_key) { case RXD_OPAQUE_RING_STD: dest_idx = dest_idx_unmasked % TG3_RX_RING_SIZE; - desc = &tp->rx_std[dest_idx]; - map = &tp->rx_std_buffers[dest_idx]; + desc = &tpr->rx_std[dest_idx]; + map = &tpr->rx_std_buffers[dest_idx]; if (src_idx >= 0) - src_map = &tp->rx_std_buffers[src_idx]; + src_map = &tpr->rx_std_buffers[src_idx]; skb_size = tp->rx_pkt_map_sz; break; case RXD_OPAQUE_RING_JUMBO: dest_idx = dest_idx_unmasked % TG3_RX_JUMBO_RING_SIZE; - desc = &tp->rx_jumbo[dest_idx]; - map = &tp->rx_jumbo_buffers[dest_idx]; + desc = &tpr->rx_jmb[dest_idx]; + map = &tpr->rx_jmb_buffers[dest_idx]; if (src_idx >= 0) - src_map = &tp->rx_jumbo_buffers[src_idx]; + src_map = &tpr->rx_jmb_buffers[src_idx]; skb_size = TG3_RX_JMB_MAP_SZ; break; @@ -4414,22 +4415,23 @@ static void tg3_recycle_rx(struct tg3 *tp, u32 opaque_key, struct tg3_rx_buffer_desc *src_desc, *dest_desc; struct ring_info *src_map, *dest_map; int dest_idx; + struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; switch (opaque_key) { case RXD_OPAQUE_RING_STD: dest_idx = dest_idx_unmasked % TG3_RX_RING_SIZE; - dest_desc = &tp->rx_std[dest_idx]; - dest_map = &tp->rx_std_buffers[dest_idx]; - src_desc = &tp->rx_std[src_idx]; - src_map = &tp->rx_std_buffers[src_idx]; + dest_desc = &tpr->rx_std[dest_idx]; + dest_map = &tpr->rx_std_buffers[dest_idx]; + src_desc = &tpr->rx_std[src_idx]; + src_map = &tpr->rx_std_buffers[src_idx]; break; case RXD_OPAQUE_RING_JUMBO: dest_idx = dest_idx_unmasked % TG3_RX_JUMBO_RING_SIZE; - dest_desc = &tp->rx_jumbo[dest_idx]; - dest_map = &tp->rx_jumbo_buffers[dest_idx]; - src_desc = &tp->rx_jumbo[src_idx]; - src_map = &tp->rx_jumbo_buffers[src_idx]; + dest_desc = &tpr->rx_jmb[dest_idx]; + dest_map = &tpr->rx_jmb_buffers[dest_idx]; + src_desc = &tpr->rx_jmb[src_idx]; + src_map = &tpr->rx_jmb_buffers[src_idx]; break; default: @@ -4482,6 +4484,7 @@ static int tg3_rx(struct tg3 *tp, int budget) u32 sw_idx = tp->rx_rcb_ptr; u16 hw_idx; int received; + struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; hw_idx = tp->hw_status->idx[0].rx_producer; /* @@ -4501,20 +4504,18 @@ static int tg3_rx(struct tg3 *tp, int budget) desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK; opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK; if (opaque_key == RXD_OPAQUE_RING_STD) { - dma_addr = pci_unmap_addr(&tp->rx_std_buffers[desc_idx], - mapping); - skb = tp->rx_std_buffers[desc_idx].skb; - post_ptr = &tp->rx_std_ptr; + struct ring_info *ri = &tpr->rx_std_buffers[desc_idx]; + dma_addr = pci_unmap_addr(ri, mapping); + skb = ri->skb; + post_ptr = &tpr->rx_std_ptr; rx_std_posted++; } else if (opaque_key == RXD_OPAQUE_RING_JUMBO) { - dma_addr = pci_unmap_addr(&tp->rx_jumbo_buffers[desc_idx], - mapping); - skb = tp->rx_jumbo_buffers[desc_idx].skb; - post_ptr = &tp->rx_jumbo_ptr; - } - else { + struct ring_info *ri = &tpr->rx_jmb_buffers[desc_idx]; + dma_addr = pci_unmap_addr(ri, mapping); + skb = ri->skb; + post_ptr = &tpr->rx_jmb_ptr; + } else goto next_pkt_nopost; - } work_mask |= opaque_key; @@ -4627,12 +4628,12 @@ next_pkt_nopost: /* Refill RX ring(s). */ if (work_mask & RXD_OPAQUE_RING_STD) { - sw_idx = tp->rx_std_ptr % TG3_RX_RING_SIZE; + sw_idx = tpr->rx_std_ptr % TG3_RX_RING_SIZE; tw32_rx_mbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW, sw_idx); } if (work_mask & RXD_OPAQUE_RING_JUMBO) { - sw_idx = tp->rx_jumbo_ptr % TG3_RX_JUMBO_RING_SIZE; + sw_idx = tpr->rx_jmb_ptr % TG3_RX_JUMBO_RING_SIZE; tw32_rx_mbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW, sw_idx); } @@ -5517,13 +5518,14 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) return err; } -static void tg3_rx_prodring_free(struct tg3 *tp) +static void tg3_rx_prodring_free(struct tg3 *tp, + struct tg3_rx_prodring_set *tpr) { struct ring_info *rxp; int i; for (i = 0; i < TG3_RX_RING_SIZE; i++) { - rxp = &tp->rx_std_buffers[i]; + rxp = &tpr->rx_std_buffers[i]; if (rxp->skb == NULL) continue; @@ -5538,7 +5540,7 @@ static void tg3_rx_prodring_free(struct tg3 *tp) if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) { - rxp = &tp->rx_jumbo_buffers[i]; + rxp = &tpr->rx_jmb_buffers[i]; if (rxp->skb == NULL) continue; @@ -5560,12 +5562,13 @@ static void tg3_rx_prodring_free(struct tg3 *tp) * end up in the driver. tp->{tx,}lock are held and thus * we may not sleep. */ -static int tg3_rx_prodring_alloc(struct tg3 *tp) +static int tg3_rx_prodring_alloc(struct tg3 *tp, + struct tg3_rx_prodring_set *tpr) { u32 i, rx_pkt_dma_sz; /* Zero out all descriptors. */ - memset(tp->rx_std, 0, TG3_RX_RING_BYTES); + memset(tpr->rx_std, 0, TG3_RX_RING_BYTES); rx_pkt_dma_sz = TG3_RX_STD_DMA_SZ; if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) && @@ -5580,7 +5583,7 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp) for (i = 0; i < TG3_RX_RING_SIZE; i++) { struct tg3_rx_buffer_desc *rxd; - rxd = &tp->rx_std[i]; + rxd = &tpr->rx_std[i]; rxd->idx_len = rx_pkt_dma_sz << RXD_LEN_SHIFT; rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT); rxd->opaque = (RXD_OPAQUE_RING_STD | @@ -5605,13 +5608,13 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp) if (!(tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE)) goto done; - memset(tp->rx_jumbo, 0, TG3_RX_JUMBO_RING_BYTES); + memset(tpr->rx_jmb, 0, TG3_RX_JUMBO_RING_BYTES); if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) { for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) { struct tg3_rx_buffer_desc *rxd; - rxd = &tp->rx_jumbo[i]; + rxd = &tpr->rx_jmb[i]; rxd->idx_len = TG3_RX_JMB_DMA_SZ << RXD_LEN_SHIFT; rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) | RXD_FLAG_JUMBO; @@ -5639,58 +5642,60 @@ done: return 0; initfail: - tg3_rx_prodring_free(tp); + tg3_rx_prodring_free(tp, tpr); return -ENOMEM; } -static void tg3_rx_prodring_fini(struct tg3 *tp) +static void tg3_rx_prodring_fini(struct tg3 *tp, + struct tg3_rx_prodring_set *tpr) { - kfree(tp->rx_std_buffers); - tp->rx_std_buffers = NULL; - kfree(tp->rx_jumbo_buffers); - tp->rx_jumbo_buffers = NULL; - if (tp->rx_std) { + kfree(tpr->rx_std_buffers); + tpr->rx_std_buffers = NULL; + kfree(tpr->rx_jmb_buffers); + tpr->rx_jmb_buffers = NULL; + if (tpr->rx_std) { pci_free_consistent(tp->pdev, TG3_RX_RING_BYTES, - tp->rx_std, tp->rx_std_mapping); - tp->rx_std = NULL; + tpr->rx_std, tpr->rx_std_mapping); + tpr->rx_std = NULL; } - if (tp->rx_jumbo) { + if (tpr->rx_jmb) { pci_free_consistent(tp->pdev, TG3_RX_JUMBO_RING_BYTES, - tp->rx_jumbo, tp->rx_jumbo_mapping); - tp->rx_jumbo = NULL; + tpr->rx_jmb, tpr->rx_jmb_mapping); + tpr->rx_jmb = NULL; } } -static int tg3_rx_prodring_init(struct tg3 *tp) +static int tg3_rx_prodring_init(struct tg3 *tp, + struct tg3_rx_prodring_set *tpr) { - tp->rx_std_buffers = kzalloc(sizeof(struct ring_info) * - TG3_RX_RING_SIZE, GFP_KERNEL); - if (!tp->rx_std_buffers) + tpr->rx_std_buffers = kzalloc(sizeof(struct ring_info) * + TG3_RX_RING_SIZE, GFP_KERNEL); + if (!tpr->rx_std_buffers) return -ENOMEM; - tp->rx_std = pci_alloc_consistent(tp->pdev, TG3_RX_RING_BYTES, - &tp->rx_std_mapping); - if (!tp->rx_std) + tpr->rx_std = pci_alloc_consistent(tp->pdev, TG3_RX_RING_BYTES, + &tpr->rx_std_mapping); + if (!tpr->rx_std) goto err_out; if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { - tp->rx_jumbo_buffers = kzalloc(sizeof(struct ring_info) * - TG3_RX_JUMBO_RING_SIZE, - GFP_KERNEL); - if (!tp->rx_jumbo_buffers) + tpr->rx_jmb_buffers = kzalloc(sizeof(struct ring_info) * + TG3_RX_JUMBO_RING_SIZE, + GFP_KERNEL); + if (!tpr->rx_jmb_buffers) goto err_out; - tp->rx_jumbo = pci_alloc_consistent(tp->pdev, - TG3_RX_JUMBO_RING_BYTES, - &tp->rx_jumbo_mapping); - if (!tp->rx_jumbo) + tpr->rx_jmb = pci_alloc_consistent(tp->pdev, + TG3_RX_JUMBO_RING_BYTES, + &tpr->rx_jmb_mapping); + if (!tpr->rx_jmb) goto err_out; } return 0; err_out: - tg3_rx_prodring_fini(tp); + tg3_rx_prodring_fini(tp, tpr); return -ENOMEM; } @@ -5726,7 +5731,7 @@ static void tg3_free_rings(struct tg3 *tp) dev_kfree_skb_any(skb); } - tg3_rx_prodring_free(tp); + tg3_rx_prodring_free(tp, &tp->prodring[0]); } /* Initialize tx/rx rings for packet processing. @@ -5745,7 +5750,7 @@ static int tg3_init_rings(struct tg3 *tp) memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); - return tg3_rx_prodring_alloc(tp); + return tg3_rx_prodring_alloc(tp, &tp->prodring[0]); } /* @@ -5776,7 +5781,7 @@ static void tg3_free_consistent(struct tg3 *tp) tp->hw_stats, tp->stats_mapping); tp->hw_stats = NULL; } - tg3_rx_prodring_fini(tp); + tg3_rx_prodring_fini(tp, &tp->prodring[0]); } /* @@ -5785,7 +5790,7 @@ static void tg3_free_consistent(struct tg3 *tp) */ static int tg3_alloc_consistent(struct tg3 *tp) { - if (tg3_rx_prodring_init(tp)) + if (tg3_rx_prodring_init(tp, &tp->prodring[0])) return -ENOMEM; tp->tx_buffers = kzalloc(sizeof(struct tx_ring_info) * @@ -6794,6 +6799,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) { u32 val, rdmac_mode; int i, err, limit; + struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; tg3_disable_ints(tp); @@ -7022,9 +7028,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) * configurable. */ tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH, - ((u64) tp->rx_std_mapping >> 32)); + ((u64) tpr->rx_std_mapping >> 32)); tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW, - ((u64) tp->rx_std_mapping & 0xffffffff)); + ((u64) tpr->rx_std_mapping & 0xffffffff)); tw32(RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR, NIC_SRAM_RX_BUFFER_DESC); @@ -7043,9 +7049,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) { tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH, - ((u64) tp->rx_jumbo_mapping >> 32)); + ((u64) tpr->rx_jmb_mapping >> 32)); tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW, - ((u64) tp->rx_jumbo_mapping & 0xffffffff)); + ((u64) tpr->rx_jmb_mapping & 0xffffffff)); tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS, RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT); tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR, @@ -7102,14 +7108,14 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) BDINFO_FLAGS_MAXLEN_SHIFT), 0); - tp->rx_std_ptr = tp->rx_pending; + tpr->rx_std_ptr = tp->rx_pending; tw32_rx_mbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW, - tp->rx_std_ptr); + tpr->rx_std_ptr); - tp->rx_jumbo_ptr = (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) ? - tp->rx_jumbo_pending : 0; + tpr->rx_jmb_ptr = (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) ? + tp->rx_jumbo_pending : 0; tw32_rx_mbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW, - tp->rx_jumbo_ptr); + tpr->rx_jmb_ptr); /* Initialize MAC address and backoff seed. */ __tg3_set_mac_addr(tp, 0); @@ -9815,6 +9821,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) dma_addr_t map; int num_pkts, tx_len, rx_len, i, err; struct tg3_rx_buffer_desc *desc; + struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; if (loopback_mode == TG3_MAC_LOOPBACK) { /* HW errata - mac loopback fails in some cases on 5780. @@ -9949,9 +9956,9 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) if (rx_len != tx_len) goto out; - rx_skb = tp->rx_std_buffers[desc_idx].skb; + rx_skb = tpr->rx_std_buffers[desc_idx].skb; - map = pci_unmap_addr(&tp->rx_std_buffers[desc_idx], mapping); + map = pci_unmap_addr(&tpr->rx_std_buffers[desc_idx], mapping); pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len, PCI_DMA_FROMDEVICE); for (i = 14; i < tx_len; i++) { diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index d029b4b9b92..7a27cffb5ad 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2476,6 +2476,17 @@ struct tg3_ethtool_stats { u64 nic_tx_threshold_hit; }; +struct tg3_rx_prodring_set { + u32 rx_std_ptr; + u32 rx_jmb_ptr; + struct tg3_rx_buffer_desc *rx_std; + struct tg3_rx_buffer_desc *rx_jmb; + struct ring_info *rx_std_buffers; + struct ring_info *rx_jmb_buffers; + dma_addr_t rx_std_mapping; + dma_addr_t rx_jmb_mapping; +}; + struct tg3 { /* begin "general, frequently-used members" cacheline section */ @@ -2551,27 +2562,19 @@ struct tg3 { void (*write32_rx_mbox) (struct tg3 *, u32, u32); u32 rx_rcb_ptr; - u32 rx_std_ptr; - u32 rx_jumbo_ptr; u32 rx_pending; u32 rx_jumbo_pending; + u32 rx_std_max_post; + u32 rx_pkt_map_sz; #if TG3_VLAN_TAG_USED struct vlan_group *vlgrp; #endif - struct tg3_rx_buffer_desc *rx_std; - struct ring_info *rx_std_buffers; - dma_addr_t rx_std_mapping; - u32 rx_std_max_post; - - struct tg3_rx_buffer_desc *rx_jumbo; - struct ring_info *rx_jumbo_buffers; - dma_addr_t rx_jumbo_mapping; - struct tg3_rx_buffer_desc *rx_rcb; dma_addr_t rx_rcb_mapping; - u32 rx_pkt_map_sz; + struct tg3_rx_prodring_set prodring[1]; + /* begin "everything else" cacheline(s) section */ struct net_device_stats net_stats; -- cgit v1.2.3-18-g5258 From 79ed5ac7ddd5f8d6463f5a17b3575772e9896481 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 14:00:55 +0000 Subject: tg3: Use ext rx bds The 5717 only uses extended buffer descriptors for the jumbo producer ring. Extended buffer descriptors are available on all devices that support a separate jumbo producer ring so make the change universal. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 17 +++++++++-------- drivers/net/tg3.h | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 053d4e85820..3725ac85708 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -117,10 +117,10 @@ #define TG3_RX_RING_BYTES (sizeof(struct tg3_rx_buffer_desc) * \ TG3_RX_RING_SIZE) -#define TG3_RX_JUMBO_RING_BYTES (sizeof(struct tg3_rx_buffer_desc) * \ - TG3_RX_JUMBO_RING_SIZE) +#define TG3_RX_JUMBO_RING_BYTES (sizeof(struct tg3_ext_rx_buffer_desc) * \ + TG3_RX_JUMBO_RING_SIZE) #define TG3_RX_RCB_RING_BYTES(tp) (sizeof(struct tg3_rx_buffer_desc) * \ - TG3_RX_RCB_RING_SIZE(tp)) + TG3_RX_RCB_RING_SIZE(tp)) #define TG3_TX_RING_BYTES (sizeof(struct tg3_tx_buffer_desc) * \ TG3_TX_RING_SIZE) #define NEXT_TX(N) (((N) + 1) & (TG3_TX_RING_SIZE - 1)) @@ -4367,7 +4367,7 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key, case RXD_OPAQUE_RING_JUMBO: dest_idx = dest_idx_unmasked % TG3_RX_JUMBO_RING_SIZE; - desc = &tpr->rx_jmb[dest_idx]; + desc = &tpr->rx_jmb[dest_idx].std; map = &tpr->rx_jmb_buffers[dest_idx]; if (src_idx >= 0) src_map = &tpr->rx_jmb_buffers[src_idx]; @@ -4428,9 +4428,9 @@ static void tg3_recycle_rx(struct tg3 *tp, u32 opaque_key, case RXD_OPAQUE_RING_JUMBO: dest_idx = dest_idx_unmasked % TG3_RX_JUMBO_RING_SIZE; - dest_desc = &tpr->rx_jmb[dest_idx]; + dest_desc = &tpr->rx_jmb[dest_idx].std; dest_map = &tpr->rx_jmb_buffers[dest_idx]; - src_desc = &tpr->rx_jmb[src_idx]; + src_desc = &tpr->rx_jmb[src_idx].std; src_map = &tpr->rx_jmb_buffers[src_idx]; break; @@ -5614,7 +5614,7 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp, for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) { struct tg3_rx_buffer_desc *rxd; - rxd = &tpr->rx_jmb[i]; + rxd = &tpr->rx_jmb[i].std; rxd->idx_len = TG3_RX_JMB_DMA_SZ << RXD_LEN_SHIFT; rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) | RXD_FLAG_JUMBO; @@ -7053,7 +7053,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW, ((u64) tpr->rx_jmb_mapping & 0xffffffff)); tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS, - RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT); + (RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT) | + BDINFO_FLAGS_USE_EXT_RECV); tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR, NIC_SRAM_RX_JUMBO_BUFFER_DESC); } else { diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 7a27cffb5ad..982171f293f 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2480,7 +2480,7 @@ struct tg3_rx_prodring_set { u32 rx_std_ptr; u32 rx_jmb_ptr; struct tg3_rx_buffer_desc *rx_std; - struct tg3_rx_buffer_desc *rx_jmb; + struct tg3_ext_rx_buffer_desc *rx_jmb; struct ring_info *rx_std_buffers; struct ring_info *rx_jmb_buffers; dma_addr_t rx_std_mapping; -- cgit v1.2.3-18-g5258 From 07b0173cb5d6a9d77646cd855066ebe90b9203f2 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 14:01:15 +0000 Subject: tg3: Cleanup interrupt setup / teardown Later patches will be adding MSIX support, which will complicate interrupt initialization. This patch prepares for the integration by breaking out the interrupt setup and teardown code into separate functions and cleaning up the error return paths. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 94 +++++++++++++++++++++++++++---------------------------- 1 file changed, 46 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 3725ac85708..37a462986db 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7865,6 +7865,33 @@ static int tg3_request_firmware(struct tg3 *tp) return 0; } +static void tg3_ints_init(struct tg3 *tp) +{ + if (tp->tg3_flags & TG3_FLAG_SUPPORT_MSI) { + /* All MSI supporting chips should support tagged + * status. Assert that this is the case. + */ + if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { + printk(KERN_WARNING PFX "%s: MSI without TAGGED? " + "Not using MSI.\n", tp->dev->name); + } else if (pci_enable_msi(tp->pdev) == 0) { + u32 msi_mode; + + msi_mode = tr32(MSGINT_MODE); + tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE); + tp->tg3_flags2 |= TG3_FLG2_USING_MSI; + } + } +} + +static void tg3_ints_fini(struct tg3 *tp) +{ + if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { + pci_disable_msi(tp->pdev); + tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; + } +} + static int tg3_open(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); @@ -7906,33 +7933,14 @@ static int tg3_open(struct net_device *dev) if (err) return err; - if (tp->tg3_flags & TG3_FLAG_SUPPORT_MSI) { - /* All MSI supporting chips should support tagged - * status. Assert that this is the case. - */ - if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { - printk(KERN_WARNING PFX "%s: MSI without TAGGED? " - "Not using MSI.\n", tp->dev->name); - } else if (pci_enable_msi(tp->pdev) == 0) { - u32 msi_mode; + tg3_ints_init(tp); - msi_mode = tr32(MSGINT_MODE); - tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE); - tp->tg3_flags2 |= TG3_FLG2_USING_MSI; - } - } - err = tg3_request_irq(tp); + napi_enable(&tp->napi); - if (err) { - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { - pci_disable_msi(tp->pdev); - tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; - } - tg3_free_consistent(tp); - return err; - } + err = tg3_request_irq(tp); - napi_enable(&tp->napi); + if (err) + goto err_out1; tg3_full_lock(tp, 0); @@ -7960,36 +7968,19 @@ static int tg3_open(struct net_device *dev) tg3_full_unlock(tp); - if (err) { - napi_disable(&tp->napi); - free_irq(tp->pdev->irq, dev); - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { - pci_disable_msi(tp->pdev); - tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; - } - tg3_free_consistent(tp); - return err; - } + if (err) + goto err_out2; if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { err = tg3_test_msi(tp); if (err) { tg3_full_lock(tp, 0); - - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { - pci_disable_msi(tp->pdev); - tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; - } tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_free_rings(tp); - tg3_free_consistent(tp); - tg3_full_unlock(tp); - napi_disable(&tp->napi); - - return err; + goto err_out1; } if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { @@ -8015,6 +8006,15 @@ static int tg3_open(struct net_device *dev) netif_start_queue(dev); return 0; + +err_out2: + free_irq(tp->pdev->irq, dev); + +err_out1: + napi_disable(&tp->napi); + tg3_ints_fini(tp); + tg3_free_consistent(tp); + return err; } #if 0 @@ -8273,10 +8273,8 @@ static int tg3_close(struct net_device *dev) tg3_full_unlock(tp); free_irq(tp->pdev->irq, dev); - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { - pci_disable_msi(tp->pdev); - tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; - } + + tg3_ints_fini(tp); memcpy(&tp->net_stats_prev, tg3_get_stats(tp->dev), sizeof(tp->net_stats_prev)); -- cgit v1.2.3-18-g5258 From 8ef0442f98850333196bc56415192e52a6267878 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 14:01:37 +0000 Subject: tg3: Move napi to per-int struct This patch creates a per-interrupt data structure, moves the napi member over, and creates a tg3 pointer back to the device structure. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 39 +++++++++++++++++---------------------- drivers/net/tg3.h | 9 ++++++++- 2 files changed, 25 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 37a462986db..b308c409e47 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -687,7 +687,7 @@ static void tg3_restart_ints(struct tg3 *tp) static inline void tg3_netif_stop(struct tg3 *tp) { tp->dev->trans_start = jiffies; /* prevent tx timeout */ - napi_disable(&tp->napi); + napi_disable(&tp->napi[0].napi); netif_tx_disable(tp->dev); } @@ -698,7 +698,7 @@ static inline void tg3_netif_start(struct tg3 *tp) * so long as all callers are assured to have free tx slots * (such as after tg3_init_hw) */ - napi_enable(&tp->napi); + napi_enable(&tp->napi[0].napi); tp->hw_status->status |= SD_STATUS_UPDATED; tg3_enable_ints(tp); } @@ -4447,13 +4447,6 @@ static void tg3_recycle_rx(struct tg3 *tp, u32 opaque_key, src_map->skb = NULL; } -#if TG3_VLAN_TAG_USED -static int tg3_vlan_rx(struct tg3 *tp, struct sk_buff *skb, u16 vlan_tag) -{ - return vlan_gro_receive(&tp->napi, tp->vlgrp, vlan_tag, skb); -} -#endif - /* The RX ring scheme is composed of multiple rings which post fresh * buffers to the chip, and one special ring the chip uses to report * status back to the host. @@ -4591,11 +4584,11 @@ static int tg3_rx(struct tg3 *tp, int budget) #if TG3_VLAN_TAG_USED if (tp->vlgrp != NULL && desc->type_flags & RXD_FLAG_VLAN) { - tg3_vlan_rx(tp, skb, - desc->err_vlan & RXD_VLAN_MASK); + vlan_gro_receive(&tp->napi[0].napi, tp->vlgrp, + desc->err_vlan & RXD_VLAN_MASK, skb); } else #endif - napi_gro_receive(&tp->napi, skb); + napi_gro_receive(&tp->napi[0].napi, skb); received++; budget--; @@ -4686,7 +4679,8 @@ static int tg3_poll_work(struct tg3 *tp, int work_done, int budget) static int tg3_poll(struct napi_struct *napi, int budget) { - struct tg3 *tp = container_of(napi, struct tg3, napi); + struct tg3_napi *tnapi = container_of(napi, struct tg3_napi, napi); + struct tg3 *tp = tnapi->tp; int work_done = 0; struct tg3_hw_status *sblk = tp->hw_status; @@ -4770,7 +4764,7 @@ static irqreturn_t tg3_msi_1shot(int irq, void *dev_id) prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); if (likely(!tg3_irq_sync(tp))) - napi_schedule(&tp->napi); + napi_schedule(&tp->napi[0].napi); return IRQ_HANDLED; } @@ -4795,7 +4789,7 @@ static irqreturn_t tg3_msi(int irq, void *dev_id) */ tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); if (likely(!tg3_irq_sync(tp))) - napi_schedule(&tp->napi); + napi_schedule(&tp->napi[0].napi); return IRQ_RETVAL(1); } @@ -4837,7 +4831,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id) sblk->status &= ~SD_STATUS_UPDATED; if (likely(tg3_has_work(tp))) { prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); - napi_schedule(&tp->napi); + napi_schedule(&tp->napi[0].napi); } else { /* No work, shared interrupt perhaps? re-enable * interrupts, and flush that PCI write @@ -4895,7 +4889,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); - napi_schedule(&tp->napi); + napi_schedule(&tp->napi[0].napi); out: return IRQ_RETVAL(handled); @@ -4936,7 +4930,7 @@ static int tg3_restart_hw(struct tg3 *tp, int reset_phy) tg3_full_unlock(tp); del_timer_sync(&tp->timer); tp->irq_sync = 0; - napi_enable(&tp->napi); + napi_enable(&tp->napi[0].napi); dev_close(tp->dev); tg3_full_lock(tp, 0); } @@ -7935,7 +7929,7 @@ static int tg3_open(struct net_device *dev) tg3_ints_init(tp); - napi_enable(&tp->napi); + napi_enable(&tp->napi[0].napi); err = tg3_request_irq(tp); @@ -8011,7 +8005,7 @@ err_out2: free_irq(tp->pdev->irq, dev); err_out1: - napi_disable(&tp->napi); + napi_disable(&tp->napi[0].napi); tg3_ints_fini(tp); tg3_free_consistent(tp); return err; @@ -8252,7 +8246,7 @@ static int tg3_close(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); - napi_disable(&tp->napi); + napi_disable(&tp->napi[0].napi); cancel_work_sync(&tp->reset_task); netif_stop_queue(dev); @@ -13396,7 +13390,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING; tp->tx_pending = TG3_DEF_TX_RING_PENDING; - netif_napi_add(dev, &tp->napi, tg3_poll, 64); + tp->napi[0].tp = tp; + netif_napi_add(dev, &tp->napi[0].napi, tg3_poll, 64); dev->ethtool_ops = &tg3_ethtool_ops; dev->watchdog_timeo = TG3_TX_TIMEOUT; dev->irq = pdev->irq; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 982171f293f..aff3f046c90 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2487,6 +2487,13 @@ struct tg3_rx_prodring_set { dma_addr_t rx_jmb_mapping; }; +#define TG3_IRQ_MAX_VECS 1 + +struct tg3_napi { + struct napi_struct napi ____cacheline_aligned; + struct tg3 *tp; +}; + struct tg3 { /* begin "general, frequently-used members" cacheline section */ @@ -2558,7 +2565,7 @@ struct tg3 { dma_addr_t tx_desc_mapping; /* begin "rx thread" cacheline section */ - struct napi_struct napi; + struct tg3_napi napi[TG3_IRQ_MAX_VECS]; void (*write32_rx_mbox) (struct tg3 *, u32, u32); u32 rx_rcb_ptr; -- cgit v1.2.3-18-g5258 From 09943a1819a240ff4a72f924d0038818fcdd0a90 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 14:01:57 +0000 Subject: tg3: Convert ISR parameter to tnapi This patch migrates the ISR parameter from struct net_device to struct tg3_napi. Checkpatch complains about the existence of the preexisting IRQF_SAMPLE_RANDOM flag. I've opted to keep this patch conservative and let it continue to exist until the flag gets officially purged from the kernel. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 49 +++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b308c409e47..bf9a3330531 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4757,14 +4757,14 @@ static inline void tg3_full_unlock(struct tg3 *tp) */ static irqreturn_t tg3_msi_1shot(int irq, void *dev_id) { - struct net_device *dev = dev_id; - struct tg3 *tp = netdev_priv(dev); + struct tg3_napi *tnapi = dev_id; + struct tg3 *tp = tnapi->tp; prefetch(tp->hw_status); prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); if (likely(!tg3_irq_sync(tp))) - napi_schedule(&tp->napi[0].napi); + napi_schedule(&tnapi->napi); return IRQ_HANDLED; } @@ -4775,8 +4775,8 @@ static irqreturn_t tg3_msi_1shot(int irq, void *dev_id) */ static irqreturn_t tg3_msi(int irq, void *dev_id) { - struct net_device *dev = dev_id; - struct tg3 *tp = netdev_priv(dev); + struct tg3_napi *tnapi = dev_id; + struct tg3 *tp = tnapi->tp; prefetch(tp->hw_status); prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); @@ -4789,15 +4789,15 @@ static irqreturn_t tg3_msi(int irq, void *dev_id) */ tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); if (likely(!tg3_irq_sync(tp))) - napi_schedule(&tp->napi[0].napi); + napi_schedule(&tnapi->napi); return IRQ_RETVAL(1); } static irqreturn_t tg3_interrupt(int irq, void *dev_id) { - struct net_device *dev = dev_id; - struct tg3 *tp = netdev_priv(dev); + struct tg3_napi *tnapi = dev_id; + struct tg3 *tp = tnapi->tp; struct tg3_hw_status *sblk = tp->hw_status; unsigned int handled = 1; @@ -4831,7 +4831,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id) sblk->status &= ~SD_STATUS_UPDATED; if (likely(tg3_has_work(tp))) { prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); - napi_schedule(&tp->napi[0].napi); + napi_schedule(&tnapi->napi); } else { /* No work, shared interrupt perhaps? re-enable * interrupts, and flush that PCI write @@ -4845,8 +4845,8 @@ out: static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) { - struct net_device *dev = dev_id; - struct tg3 *tp = netdev_priv(dev); + struct tg3_napi *tnapi = dev_id; + struct tg3 *tp = tnapi->tp; struct tg3_hw_status *sblk = tp->hw_status; unsigned int handled = 1; @@ -4889,7 +4889,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); - napi_schedule(&tp->napi[0].napi); + napi_schedule(&tnapi->napi); out: return IRQ_RETVAL(handled); @@ -4898,8 +4898,8 @@ out: /* ISR for interrupt test */ static irqreturn_t tg3_test_isr(int irq, void *dev_id) { - struct net_device *dev = dev_id; - struct tg3 *tp = netdev_priv(dev); + struct tg3_napi *tnapi = dev_id; + struct tg3 *tp = tnapi->tp; struct tg3_hw_status *sblk = tp->hw_status; if ((sblk->status & SD_STATUS_UPDATED) || @@ -7697,7 +7697,7 @@ static int tg3_request_irq(struct tg3 *tp) { irq_handler_t fn; unsigned long flags; - struct net_device *dev = tp->dev; + char *name = tp->dev->name; if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { fn = tg3_msi; @@ -7710,11 +7710,12 @@ static int tg3_request_irq(struct tg3 *tp) fn = tg3_interrupt_tagged; flags = IRQF_SHARED | IRQF_SAMPLE_RANDOM; } - return (request_irq(tp->pdev->irq, fn, flags, dev->name, dev)); + return request_irq(tp->pdev->irq, fn, flags, name, &tp->napi[0]); } static int tg3_test_interrupt(struct tg3 *tp) { + struct tg3_napi *tnapi = &tp->napi[0]; struct net_device *dev = tp->dev; int err, i, intr_ok = 0; @@ -7723,10 +7724,10 @@ static int tg3_test_interrupt(struct tg3 *tp) tg3_disable_ints(tp); - free_irq(tp->pdev->irq, dev); + free_irq(tp->pdev->irq, tnapi); err = request_irq(tp->pdev->irq, tg3_test_isr, - IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev); + IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, tnapi); if (err) return err; @@ -7754,7 +7755,7 @@ static int tg3_test_interrupt(struct tg3 *tp) tg3_disable_ints(tp); - free_irq(tp->pdev->irq, dev); + free_irq(tp->pdev->irq, tnapi); err = tg3_request_irq(tp); @@ -7772,7 +7773,6 @@ static int tg3_test_interrupt(struct tg3 *tp) */ static int tg3_test_msi(struct tg3 *tp) { - struct net_device *dev = tp->dev; int err; u16 pci_cmd; @@ -7803,7 +7803,8 @@ static int tg3_test_msi(struct tg3 *tp) "the PCI maintainer and include system chipset information.\n", tp->dev->name); - free_irq(tp->pdev->irq, dev); + free_irq(tp->pdev->irq, &tp->napi[0]); + pci_disable_msi(tp->pdev); tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; @@ -7823,7 +7824,7 @@ static int tg3_test_msi(struct tg3 *tp) tg3_full_unlock(tp); if (err) - free_irq(tp->pdev->irq, dev); + free_irq(tp->pdev->irq, &tp->napi[0]); return err; } @@ -8002,7 +8003,7 @@ static int tg3_open(struct net_device *dev) return 0; err_out2: - free_irq(tp->pdev->irq, dev); + free_irq(tp->pdev->irq, &tp->napi[0]); err_out1: napi_disable(&tp->napi[0].napi); @@ -8266,7 +8267,7 @@ static int tg3_close(struct net_device *dev) tg3_full_unlock(tp); - free_irq(tp->pdev->irq, dev); + free_irq(tp->pdev->irq, &tp->napi[0]); tg3_ints_fini(tp); -- cgit v1.2.3-18-g5258 From 17375d25d3dcd3d4caf9456fa94f60e29d6b1146 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 14:02:18 +0000 Subject: tg3: Convert napi handlers to use tnapi This patch converts the napi interrupt handler functions to accept and use tg3_napi structures. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 55 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index bf9a3330531..27ebe3b363c 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -643,8 +643,9 @@ static void tg3_enable_ints(struct tg3 *tp) tg3_cond_int(tp); } -static inline unsigned int tg3_has_work(struct tg3 *tp) +static inline unsigned int tg3_has_work(struct tg3_napi *tnapi) { + struct tg3 *tp = tnapi->tp; struct tg3_hw_status *sblk = tp->hw_status; unsigned int work_exists = 0; @@ -663,13 +664,15 @@ static inline unsigned int tg3_has_work(struct tg3 *tp) return work_exists; } -/* tg3_restart_ints +/* tg3_int_reenable * similar to tg3_enable_ints, but it accurately determines whether there * is new work pending and can return without flushing the PIO write * which reenables interrupts */ -static void tg3_restart_ints(struct tg3 *tp) +static void tg3_int_reenable(struct tg3_napi *tnapi) { + struct tg3 *tp = tnapi->tp; + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, tp->last_tag << 24); mmiowb(); @@ -679,7 +682,7 @@ static void tg3_restart_ints(struct tg3 *tp) * work we've completed. */ if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && - tg3_has_work(tp)) + tg3_has_work(tnapi)) tw32(HOSTCC_MODE, tp->coalesce_mode | (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW)); } @@ -4278,8 +4281,9 @@ static inline u32 tg3_tx_avail(struct tg3 *tp) * need special logic to handle SKBs that have not had all * of their frags sent yet, like SunGEM does. */ -static void tg3_tx(struct tg3 *tp) +static void tg3_tx(struct tg3_napi *tnapi) { + struct tg3 *tp = tnapi->tp; u32 hw_idx = tp->hw_status->idx[0].tx_consumer; u32 sw_idx = tp->tx_cons; @@ -4344,9 +4348,10 @@ static void tg3_tx(struct tg3 *tp) * buffers the cpu only reads the last cacheline of the RX descriptor * (to fetch the error flags, vlan tag, checksum, and opaque cookie). */ -static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key, +static int tg3_alloc_rx_skb(struct tg3_napi *tnapi, u32 opaque_key, int src_idx, u32 dest_idx_unmasked) { + struct tg3 *tp = tnapi->tp; struct tg3_rx_buffer_desc *desc; struct ring_info *map, *src_map; struct sk_buff *skb; @@ -4409,9 +4414,10 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key, * members of the RX descriptor are invariant. See notes above * tg3_alloc_rx_skb for full details. */ -static void tg3_recycle_rx(struct tg3 *tp, u32 opaque_key, +static void tg3_recycle_rx(struct tg3_napi *tnapi, u32 opaque_key, int src_idx, u32 dest_idx_unmasked) { + struct tg3 *tp = tnapi->tp; struct tg3_rx_buffer_desc *src_desc, *dest_desc; struct ring_info *src_map, *dest_map; int dest_idx; @@ -4471,8 +4477,9 @@ static void tg3_recycle_rx(struct tg3 *tp, u32 opaque_key, * If both the host and chip were to write into the same ring, cache line * eviction could occur since both entities want it in an exclusive state. */ -static int tg3_rx(struct tg3 *tp, int budget) +static int tg3_rx(struct tg3_napi *tnapi, int budget) { + struct tg3 *tp = tnapi->tp; u32 work_mask, rx_std_posted = 0; u32 sw_idx = tp->rx_rcb_ptr; u16 hw_idx; @@ -4515,7 +4522,7 @@ static int tg3_rx(struct tg3 *tp, int budget) if ((desc->err_vlan & RXD_ERR_MASK) != 0 && (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) { drop_it: - tg3_recycle_rx(tp, opaque_key, + tg3_recycle_rx(tnapi, opaque_key, desc_idx, *post_ptr); drop_it_no_recycle: /* Other statistics kept track of by card. */ @@ -4535,7 +4542,7 @@ static int tg3_rx(struct tg3 *tp, int budget) ) { int skb_size; - skb_size = tg3_alloc_rx_skb(tp, opaque_key, + skb_size = tg3_alloc_rx_skb(tnapi, opaque_key, desc_idx, *post_ptr); if (skb_size < 0) goto drop_it; @@ -4547,7 +4554,7 @@ static int tg3_rx(struct tg3 *tp, int budget) } else { struct sk_buff *copy_skb; - tg3_recycle_rx(tp, opaque_key, + tg3_recycle_rx(tnapi, opaque_key, desc_idx, *post_ptr); copy_skb = netdev_alloc_skb(tp->dev, @@ -4584,11 +4591,11 @@ static int tg3_rx(struct tg3 *tp, int budget) #if TG3_VLAN_TAG_USED if (tp->vlgrp != NULL && desc->type_flags & RXD_FLAG_VLAN) { - vlan_gro_receive(&tp->napi[0].napi, tp->vlgrp, + vlan_gro_receive(&tnapi->napi, tp->vlgrp, desc->err_vlan & RXD_VLAN_MASK, skb); } else #endif - napi_gro_receive(&tp->napi[0].napi, skb); + napi_gro_receive(&tnapi->napi, skb); received++; budget--; @@ -4635,8 +4642,9 @@ next_pkt_nopost: return received; } -static int tg3_poll_work(struct tg3 *tp, int work_done, int budget) +static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) { + struct tg3 *tp = tnapi->tp; struct tg3_hw_status *sblk = tp->hw_status; /* handle link change and other phy events */ @@ -4662,7 +4670,7 @@ static int tg3_poll_work(struct tg3 *tp, int work_done, int budget) /* run TX completion thread */ if (sblk->idx[0].tx_consumer != tp->tx_cons) { - tg3_tx(tp); + tg3_tx(tnapi); if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) return work_done; } @@ -4672,7 +4680,7 @@ static int tg3_poll_work(struct tg3 *tp, int work_done, int budget) * code synchronizes with tg3->napi.poll() */ if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) - work_done += tg3_rx(tp, budget - work_done); + work_done += tg3_rx(tnapi, budget - work_done); return work_done; } @@ -4685,7 +4693,7 @@ static int tg3_poll(struct napi_struct *napi, int budget) struct tg3_hw_status *sblk = tp->hw_status; while (1) { - work_done = tg3_poll_work(tp, work_done, budget); + work_done = tg3_poll_work(tnapi, work_done, budget); if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) goto tx_recovery; @@ -4694,7 +4702,7 @@ static int tg3_poll(struct napi_struct *napi, int budget) break; if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { - /* tp->last_tag is used in tg3_restart_ints() below + /* tp->last_tag is used in tg3_int_reenable() below * to tell the hw how much work has been processed, * so we must read it before checking for more work. */ @@ -4704,9 +4712,9 @@ static int tg3_poll(struct napi_struct *napi, int budget) } else sblk->status &= ~SD_STATUS_UPDATED; - if (likely(!tg3_has_work(tp))) { + if (likely(!tg3_has_work(tnapi))) { napi_complete(napi); - tg3_restart_ints(tp); + tg3_int_reenable(tnapi); break; } } @@ -4829,7 +4837,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id) if (tg3_irq_sync(tp)) goto out; sblk->status &= ~SD_STATUS_UPDATED; - if (likely(tg3_has_work(tp))) { + if (likely(tg3_has_work(tnapi))) { prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); napi_schedule(&tnapi->napi); } else { @@ -5560,6 +5568,7 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp, struct tg3_rx_prodring_set *tpr) { u32 i, rx_pkt_dma_sz; + struct tg3_napi *tnapi = &tp->napi[0]; /* Zero out all descriptors. */ memset(tpr->rx_std, 0, TG3_RX_RING_BYTES); @@ -5586,7 +5595,7 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp, /* Now allocate fresh SKBs for each rx ring. */ for (i = 0; i < tp->rx_pending; i++) { - if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_STD, -1, i) < 0) { + if (tg3_alloc_rx_skb(tnapi, RXD_OPAQUE_RING_STD, -1, i) < 0) { printk(KERN_WARNING PFX "%s: Using a smaller RX standard ring, " "only %d out of %d buffers were allocated " @@ -5617,7 +5626,7 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp, } for (i = 0; i < tp->rx_jumbo_pending; i++) { - if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_JUMBO, + if (tg3_alloc_rx_skb(tnapi, RXD_OPAQUE_RING_JUMBO, -1, i) < 0) { printk(KERN_WARNING PFX "%s: Using a smaller RX jumbo ring, " -- cgit v1.2.3-18-g5258 From 898a56f8d8170c188e47ae3acb90d2ea9a585ebe Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 14:02:40 +0000 Subject: tg3: Move general int members to a per-int struct This patch moves the last_tag, last_tag_irq, and hw_status device members to a per-interrupt structure. It also adds a new interrupt mailbox member (int_mbox) and converts the code to use it rather than a direct preprocessor constant. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 134 +++++++++++++++++++++++++++++------------------------- drivers/net/tg3.h | 12 +++-- 2 files changed, 80 insertions(+), 66 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 27ebe3b363c..5b8d6e03318 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -615,13 +615,13 @@ static void tg3_disable_ints(struct tg3 *tp) { tw32(TG3PCI_MISC_HOST_CTRL, (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT)); - tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); + tw32_mailbox_f(tp->napi[0].int_mbox, 0x00000001); } static inline void tg3_cond_int(struct tg3 *tp) { if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && - (tp->hw_status->status & SD_STATUS_UPDATED)) + (tp->napi[0].hw_status->status & SD_STATUS_UPDATED)) tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); else tw32(HOSTCC_MODE, tp->coalesce_mode | @@ -630,23 +630,22 @@ static inline void tg3_cond_int(struct tg3 *tp) static void tg3_enable_ints(struct tg3 *tp) { + struct tg3_napi *tnapi = &tp->napi[0]; tp->irq_sync = 0; wmb(); tw32(TG3PCI_MISC_HOST_CTRL, (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT)); - tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, - (tp->last_tag << 24)); + tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) - tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, - (tp->last_tag << 24)); + tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); tg3_cond_int(tp); } static inline unsigned int tg3_has_work(struct tg3_napi *tnapi) { struct tg3 *tp = tnapi->tp; - struct tg3_hw_status *sblk = tp->hw_status; + struct tg3_hw_status *sblk = tnapi->hw_status; unsigned int work_exists = 0; /* check for phy events */ @@ -673,8 +672,7 @@ static void tg3_int_reenable(struct tg3_napi *tnapi) { struct tg3 *tp = tnapi->tp; - tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, - tp->last_tag << 24); + tw32_mailbox(tnapi->int_mbox, tnapi->last_tag << 24); mmiowb(); /* When doing tagged status, this work check is unnecessary. @@ -696,13 +694,14 @@ static inline void tg3_netif_stop(struct tg3 *tp) static inline void tg3_netif_start(struct tg3 *tp) { + struct tg3_napi *tnapi = &tp->napi[0]; netif_wake_queue(tp->dev); /* NOTE: unconditional netif_wake_queue is only appropriate * so long as all callers are assured to have free tx slots * (such as after tg3_init_hw) */ - napi_enable(&tp->napi[0].napi); - tp->hw_status->status |= SD_STATUS_UPDATED; + napi_enable(&tnapi->napi); + tnapi->hw_status->status |= SD_STATUS_UPDATED; tg3_enable_ints(tp); } @@ -3902,9 +3901,9 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset) else current_link_up = tg3_setup_fiber_by_hand(tp, mac_status); - tp->hw_status->status = + tp->napi[0].hw_status->status = (SD_STATUS_UPDATED | - (tp->hw_status->status & ~SD_STATUS_LINK_CHG)); + (tp->napi[0].hw_status->status & ~SD_STATUS_LINK_CHG)); for (i = 0; i < 100; i++) { tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | @@ -4284,7 +4283,7 @@ static inline u32 tg3_tx_avail(struct tg3 *tp) static void tg3_tx(struct tg3_napi *tnapi) { struct tg3 *tp = tnapi->tp; - u32 hw_idx = tp->hw_status->idx[0].tx_consumer; + u32 hw_idx = tnapi->hw_status->idx[0].tx_consumer; u32 sw_idx = tp->tx_cons; while (sw_idx != hw_idx) { @@ -4486,7 +4485,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget) int received; struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; - hw_idx = tp->hw_status->idx[0].rx_producer; + hw_idx = tnapi->hw_status->idx[0].rx_producer; /* * We need to order the read of hw_idx and the read of * the opaque cookie. @@ -4617,7 +4616,7 @@ next_pkt_nopost: /* Refresh hw_idx to see if there is new work */ if (sw_idx == hw_idx) { - hw_idx = tp->hw_status->idx[0].rx_producer; + hw_idx = tnapi->hw_status->idx[0].rx_producer; rmb(); } } @@ -4645,7 +4644,7 @@ next_pkt_nopost: static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) { struct tg3 *tp = tnapi->tp; - struct tg3_hw_status *sblk = tp->hw_status; + struct tg3_hw_status *sblk = tnapi->hw_status; /* handle link change and other phy events */ if (!(tp->tg3_flags & @@ -4690,7 +4689,7 @@ static int tg3_poll(struct napi_struct *napi, int budget) struct tg3_napi *tnapi = container_of(napi, struct tg3_napi, napi); struct tg3 *tp = tnapi->tp; int work_done = 0; - struct tg3_hw_status *sblk = tp->hw_status; + struct tg3_hw_status *sblk = tnapi->hw_status; while (1) { work_done = tg3_poll_work(tnapi, work_done, budget); @@ -4706,8 +4705,8 @@ static int tg3_poll(struct napi_struct *napi, int budget) * to tell the hw how much work has been processed, * so we must read it before checking for more work. */ - tp->last_tag = sblk->status_tag; - tp->last_irq_tag = tp->last_tag; + tnapi->last_tag = sblk->status_tag; + tnapi->last_irq_tag = tnapi->last_tag; rmb(); } else sblk->status &= ~SD_STATUS_UPDATED; @@ -4768,7 +4767,7 @@ static irqreturn_t tg3_msi_1shot(int irq, void *dev_id) struct tg3_napi *tnapi = dev_id; struct tg3 *tp = tnapi->tp; - prefetch(tp->hw_status); + prefetch(tnapi->hw_status); prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); if (likely(!tg3_irq_sync(tp))) @@ -4786,7 +4785,7 @@ static irqreturn_t tg3_msi(int irq, void *dev_id) struct tg3_napi *tnapi = dev_id; struct tg3 *tp = tnapi->tp; - prefetch(tp->hw_status); + prefetch(tnapi->hw_status); prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); /* * Writing any value to intr-mbox-0 clears PCI INTA# and @@ -4806,7 +4805,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id) { struct tg3_napi *tnapi = dev_id; struct tg3 *tp = tnapi->tp; - struct tg3_hw_status *sblk = tp->hw_status; + struct tg3_hw_status *sblk = tnapi->hw_status; unsigned int handled = 1; /* In INTx mode, it is possible for the interrupt to arrive at @@ -4855,7 +4854,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) { struct tg3_napi *tnapi = dev_id; struct tg3 *tp = tnapi->tp; - struct tg3_hw_status *sblk = tp->hw_status; + struct tg3_hw_status *sblk = tnapi->hw_status; unsigned int handled = 1; /* In INTx mode, it is possible for the interrupt to arrive at @@ -4863,7 +4862,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) * Reading the PCI State register will confirm whether the * interrupt is ours and will flush the status block. */ - if (unlikely(sblk->status_tag == tp->last_irq_tag)) { + if (unlikely(sblk->status_tag == tnapi->last_irq_tag)) { if ((tp->tg3_flags & TG3_FLAG_CHIP_RESETTING) || (tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) { handled = 0; @@ -4890,7 +4889,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) * so that the above check can report that the screaming interrupts * are unhandled. Eventually they will be silenced. */ - tp->last_irq_tag = sblk->status_tag; + tnapi->last_irq_tag = sblk->status_tag; if (tg3_irq_sync(tp)) goto out; @@ -4908,7 +4907,7 @@ static irqreturn_t tg3_test_isr(int irq, void *dev_id) { struct tg3_napi *tnapi = dev_id; struct tg3 *tp = tnapi->tp; - struct tg3_hw_status *sblk = tp->hw_status; + struct tg3_hw_status *sblk = tnapi->hw_status; if ((sblk->status & SD_STATUS_UPDATED) || !(tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) { @@ -5762,6 +5761,8 @@ static int tg3_init_rings(struct tg3 *tp) */ static void tg3_free_consistent(struct tg3 *tp) { + struct tg3_napi *tnapi = &tp->napi[0]; + kfree(tp->tx_buffers); tp->tx_buffers = NULL; if (tp->rx_rcb) { @@ -5774,10 +5775,11 @@ static void tg3_free_consistent(struct tg3 *tp) tp->tx_ring, tp->tx_desc_mapping); tp->tx_ring = NULL; } - if (tp->hw_status) { + if (tnapi->hw_status) { pci_free_consistent(tp->pdev, TG3_HW_STATUS_SIZE, - tp->hw_status, tp->status_mapping); - tp->hw_status = NULL; + tnapi->hw_status, + tnapi->status_mapping); + tnapi->hw_status = NULL; } if (tp->hw_stats) { pci_free_consistent(tp->pdev, sizeof(struct tg3_hw_stats), @@ -5793,6 +5795,8 @@ static void tg3_free_consistent(struct tg3 *tp) */ static int tg3_alloc_consistent(struct tg3 *tp) { + struct tg3_napi *tnapi = &tp->napi[0]; + if (tg3_rx_prodring_init(tp, &tp->prodring[0])) return -ENOMEM; @@ -5811,19 +5815,20 @@ static int tg3_alloc_consistent(struct tg3 *tp) if (!tp->tx_ring) goto err_out; - tp->hw_status = pci_alloc_consistent(tp->pdev, - TG3_HW_STATUS_SIZE, - &tp->status_mapping); - if (!tp->hw_status) + tnapi->hw_status = pci_alloc_consistent(tp->pdev, + TG3_HW_STATUS_SIZE, + &tnapi->status_mapping); + if (!tnapi->hw_status) goto err_out; + memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); + tp->hw_stats = pci_alloc_consistent(tp->pdev, sizeof(struct tg3_hw_stats), &tp->stats_mapping); if (!tp->hw_stats) goto err_out; - memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE); memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats)); return 0; @@ -5885,6 +5890,7 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, int static int tg3_abort_hw(struct tg3 *tp, int silent) { int i, err; + struct tg3_napi *tnapi = &tp->napi[0]; tg3_disable_ints(tp); @@ -5936,8 +5942,8 @@ static int tg3_abort_hw(struct tg3 *tp, int silent) err |= tg3_stop_block(tp, BUFMGR_MODE, BUFMGR_MODE_ENABLE, silent); err |= tg3_stop_block(tp, MEMARB_MODE, MEMARB_MODE_ENABLE, silent); - if (tp->hw_status) - memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE); + if (tnapi->hw_status) + memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); if (tp->hw_stats) memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats)); @@ -6264,12 +6270,12 @@ static int tg3_chip_reset(struct tg3 *tp) * sharing or irqpoll. */ tp->tg3_flags |= TG3_FLAG_CHIP_RESETTING; - if (tp->hw_status) { - tp->hw_status->status = 0; - tp->hw_status->status_tag = 0; + if (tp->napi[0].hw_status) { + tp->napi[0].hw_status->status = 0; + tp->napi[0].hw_status->status_tag = 0; } - tp->last_tag = 0; - tp->last_irq_tag = 0; + tp->napi[0].last_tag = 0; + tp->napi[0].last_irq_tag = 0; smp_mb(); synchronize_irq(tp->pdev->irq); @@ -7210,9 +7216,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) /* set status block DMA address */ tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH, - ((u64) tp->status_mapping >> 32)); + ((u64) tp->napi[0].status_mapping >> 32)); tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW, - ((u64) tp->status_mapping & 0xffffffff)); + ((u64) tp->napi[0].status_mapping & 0xffffffff)); if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { /* Status/statistics block address. See tg3_timer, @@ -7241,7 +7247,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tg3_write_mem(tp, i, 0); udelay(40); } - memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE); + memset(tp->napi[0].hw_status, 0, TG3_HW_STATUS_SIZE); if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) { tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT; @@ -7294,7 +7300,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); udelay(100); - tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0); + tw32_mailbox_f(tp->napi[0].int_mbox, 0); if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { tw32_f(DMAC_MODE, DMAC_MODE_ENABLE); @@ -7596,7 +7602,7 @@ static void tg3_timer(unsigned long __opaque) * IRQ status the mailbox/status_block protocol the chip * uses with the cpu is race prone. */ - if (tp->hw_status->status & SD_STATUS_UPDATED) { + if (tp->napi[0].hw_status->status & SD_STATUS_UPDATED) { tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); } else { @@ -7740,7 +7746,7 @@ static int tg3_test_interrupt(struct tg3 *tp) if (err) return err; - tp->hw_status->status &= ~SD_STATUS_UPDATED; + tnapi->hw_status->status &= ~SD_STATUS_UPDATED; tg3_enable_ints(tp); tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE | @@ -7749,8 +7755,7 @@ static int tg3_test_interrupt(struct tg3 *tp) for (i = 0; i < 5; i++) { u32 int_mbox, misc_host_ctrl; - int_mbox = tr32_mailbox(MAILBOX_INTERRUPT_0 + - TG3_64BIT_REG_LOW); + int_mbox = tr32_mailbox(tnapi->int_mbox); misc_host_ctrl = tr32(TG3PCI_MISC_HOST_CTRL); if ((int_mbox != 0) || @@ -8027,6 +8032,7 @@ err_out1: u32 val32, val32_2, val32_3, val32_4, val32_5; u16 val16; int i; + struct tg3_hw_status *sblk = tp->napi[0]->hw_status; pci_read_config_word(tp->pdev, PCI_STATUS, &val16); pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, &val32); @@ -8179,14 +8185,15 @@ err_out1: val32, val32_2, val32_3, val32_4, val32_5); /* SW status block */ - printk("DEBUG: Host status block [%08x:%08x:(%04x:%04x:%04x):(%04x:%04x)]\n", - tp->hw_status->status, - tp->hw_status->status_tag, - tp->hw_status->rx_jumbo_consumer, - tp->hw_status->rx_consumer, - tp->hw_status->rx_mini_consumer, - tp->hw_status->idx[0].rx_producer, - tp->hw_status->idx[0].tx_consumer); + printk(KERN_DEBUG + "Host status block [%08x:%08x:(%04x:%04x:%04x):(%04x:%04x)]\n", + sblk->status, + sblk->status_tag, + sblk->rx_jumbo_consumer, + sblk->rx_consumer, + sblk->rx_mini_consumer, + sblk->idx[0].rx_producer, + sblk->idx[0].tx_consumer); /* SW statistics block */ printk("DEBUG: Host statistics block [%08x:%08x:%08x:%08x]\n", @@ -9824,8 +9831,12 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) dma_addr_t map; int num_pkts, tx_len, rx_len, i, err; struct tg3_rx_buffer_desc *desc; + struct tg3_napi *tnapi, *rnapi; struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; + tnapi = &tp->napi[0]; + rnapi = &tp->napi[0]; + if (loopback_mode == TG3_MAC_LOOPBACK) { /* HW errata - mac loopback fails in some cases on 5780. * Normal traffic and PHY loopback are not affected by @@ -9907,7 +9918,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) udelay(10); - rx_start_idx = tp->hw_status->idx[0].rx_producer; + rx_start_idx = rnapi->hw_status->idx[0].rx_producer; num_pkts = 0; @@ -9929,8 +9940,8 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) udelay(10); - tx_idx = tp->hw_status->idx[0].tx_consumer; - rx_idx = tp->hw_status->idx[0].rx_producer; + tx_idx = tnapi->hw_status->idx[0].tx_consumer; + rx_idx = rnapi->hw_status->idx[0].rx_producer; if ((tx_idx == tp->tx_prod) && (rx_idx == (rx_start_idx + num_pkts))) break; @@ -13401,6 +13412,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tp->tx_pending = TG3_DEF_TX_RING_PENDING; tp->napi[0].tp = tp; + tp->napi[0].int_mbox = MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW; netif_napi_add(dev, &tp->napi[0].napi, tg3_poll, 64); dev->ethtool_ops = &tg3_ethtool_ops; dev->watchdog_timeo = TG3_TX_TIMEOUT; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index aff3f046c90..f46e6198a82 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2492,6 +2492,13 @@ struct tg3_rx_prodring_set { struct tg3_napi { struct napi_struct napi ____cacheline_aligned; struct tg3 *tp; + struct tg3_hw_status *hw_status; + + u32 last_tag; + u32 last_irq_tag; + u32 int_mbox; + + dma_addr_t status_mapping; }; struct tg3 { @@ -2546,11 +2553,6 @@ struct tg3 { struct net_device *dev; struct pci_dev *pdev; - struct tg3_hw_status *hw_status; - dma_addr_t status_mapping; - u32 last_tag; - u32 last_irq_tag; - u32 msg_enable; /* begin "tx thread" cacheline section */ -- cgit v1.2.3-18-g5258 From 723344820aa405ac2663ab9e36fd27833d06129b Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 14:03:01 +0000 Subject: tg3: Move per-int rx members to per-int struct This patch moves the rx_rcb, rx_rcb_mapping, and rx_rcb_ptr return ring device members to a per-interrupt structure. It also adds a new return ring consumer mailbox register member (consmbox) and converts the code to use it rather than a preprocessor constant. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 57 +++++++++++++++++++++++++++++++------------------------ drivers/net/tg3.h | 9 +++++---- 2 files changed, 37 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 5b8d6e03318..939574c571f 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -657,7 +657,7 @@ static inline unsigned int tg3_has_work(struct tg3_napi *tnapi) } /* check for RX/TX work to do */ if (sblk->idx[0].tx_consumer != tp->tx_cons || - sblk->idx[0].rx_producer != tp->rx_rcb_ptr) + sblk->idx[0].rx_producer != tnapi->rx_rcb_ptr) work_exists = 1; return work_exists; @@ -4480,7 +4480,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget) { struct tg3 *tp = tnapi->tp; u32 work_mask, rx_std_posted = 0; - u32 sw_idx = tp->rx_rcb_ptr; + u32 sw_idx = tnapi->rx_rcb_ptr; u16 hw_idx; int received; struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; @@ -4494,7 +4494,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget) work_mask = 0; received = 0; while (sw_idx != hw_idx && budget > 0) { - struct tg3_rx_buffer_desc *desc = &tp->rx_rcb[sw_idx]; + struct tg3_rx_buffer_desc *desc = &tnapi->rx_rcb[sw_idx]; unsigned int len; struct sk_buff *skb; dma_addr_t dma_addr; @@ -4622,8 +4622,8 @@ next_pkt_nopost: } /* ACK the status ring. */ - tp->rx_rcb_ptr = sw_idx; - tw32_rx_mbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, sw_idx); + tnapi->rx_rcb_ptr = sw_idx; + tw32_rx_mbox(tnapi->consmbox, sw_idx); /* Refill RX ring(s). */ if (work_mask & RXD_OPAQUE_RING_STD) { @@ -4678,7 +4678,7 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) * All RX "locking" is done by ensuring outside * code synchronizes with tg3->napi.poll() */ - if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) + if (sblk->idx[0].rx_producer != tnapi->rx_rcb_ptr) work_done += tg3_rx(tnapi, budget - work_done); return work_done; @@ -4768,7 +4768,7 @@ static irqreturn_t tg3_msi_1shot(int irq, void *dev_id) struct tg3 *tp = tnapi->tp; prefetch(tnapi->hw_status); - prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); + prefetch(&tnapi->rx_rcb[tnapi->rx_rcb_ptr]); if (likely(!tg3_irq_sync(tp))) napi_schedule(&tnapi->napi); @@ -4786,7 +4786,7 @@ static irqreturn_t tg3_msi(int irq, void *dev_id) struct tg3 *tp = tnapi->tp; prefetch(tnapi->hw_status); - prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); + prefetch(&tnapi->rx_rcb[tnapi->rx_rcb_ptr]); /* * Writing any value to intr-mbox-0 clears PCI INTA# and * chip-internal interrupt pending events. @@ -4837,7 +4837,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id) goto out; sblk->status &= ~SD_STATUS_UPDATED; if (likely(tg3_has_work(tnapi))) { - prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); + prefetch(&tnapi->rx_rcb[tnapi->rx_rcb_ptr]); napi_schedule(&tnapi->napi); } else { /* No work, shared interrupt perhaps? re-enable @@ -4894,7 +4894,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) if (tg3_irq_sync(tp)) goto out; - prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); + prefetch(&tnapi->rx_rcb[tnapi->rx_rcb_ptr]); napi_schedule(&tnapi->napi); @@ -5745,13 +5745,17 @@ static void tg3_free_rings(struct tg3 *tp) */ static int tg3_init_rings(struct tg3 *tp) { + struct tg3_napi *tnapi = &tp->napi[0]; + /* Free up all the SKBs. */ tg3_free_rings(tp); /* Zero out all descriptors. */ - memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); + tnapi->rx_rcb_ptr = 0; + memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); + return tg3_rx_prodring_alloc(tp, &tp->prodring[0]); } @@ -5765,16 +5769,16 @@ static void tg3_free_consistent(struct tg3 *tp) kfree(tp->tx_buffers); tp->tx_buffers = NULL; - if (tp->rx_rcb) { - pci_free_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp), - tp->rx_rcb, tp->rx_rcb_mapping); - tp->rx_rcb = NULL; - } if (tp->tx_ring) { pci_free_consistent(tp->pdev, TG3_TX_RING_BYTES, tp->tx_ring, tp->tx_desc_mapping); tp->tx_ring = NULL; } + if (tnapi->rx_rcb) { + pci_free_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp), + tnapi->rx_rcb, tnapi->rx_rcb_mapping); + tnapi->rx_rcb = NULL; + } if (tnapi->hw_status) { pci_free_consistent(tp->pdev, TG3_HW_STATUS_SIZE, tnapi->hw_status, @@ -5805,11 +5809,6 @@ static int tg3_alloc_consistent(struct tg3 *tp) if (!tp->tx_buffers) goto err_out; - tp->rx_rcb = pci_alloc_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp), - &tp->rx_rcb_mapping); - if (!tp->rx_rcb) - goto err_out; - tp->tx_ring = pci_alloc_consistent(tp->pdev, TG3_TX_RING_BYTES, &tp->tx_desc_mapping); if (!tp->tx_ring) @@ -5823,6 +5822,14 @@ static int tg3_alloc_consistent(struct tg3 *tp) memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); + tnapi->rx_rcb = pci_alloc_consistent(tp->pdev, + TG3_RX_RCB_RING_BYTES(tp), + &tnapi->rx_rcb_mapping); + if (!tnapi->rx_rcb) + goto err_out; + + memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); + tp->hw_stats = pci_alloc_consistent(tp->pdev, sizeof(struct tg3_hw_stats), &tp->stats_mapping); @@ -7109,11 +7116,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) } } - tp->rx_rcb_ptr = 0; - tw32_rx_mbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, 0); + tw32_rx_mbox(tp->napi[0].consmbox, 0); tg3_set_bdinfo(tp, NIC_SRAM_RCV_RET_RCB, - tp->rx_rcb_mapping, + tp->napi[0].rx_rcb_mapping, (TG3_RX_RCB_RING_SIZE(tp) << BDINFO_FLAGS_MAXLEN_SHIFT), 0); @@ -9956,7 +9962,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) if (rx_idx != rx_start_idx + num_pkts) goto out; - desc = &tp->rx_rcb[rx_start_idx]; + desc = &rnapi->rx_rcb[rx_start_idx]; desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK; opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK; if (opaque_key != RXD_OPAQUE_RING_STD) @@ -13413,6 +13419,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tp->napi[0].tp = tp; tp->napi[0].int_mbox = MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW; + tp->napi[0].consmbox = MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW; netif_napi_add(dev, &tp->napi[0].napi, tg3_poll, 64); dev->ethtool_ops = &tg3_ethtool_ops; dev->watchdog_timeo = TG3_TX_TIMEOUT; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index f46e6198a82..b91ac29ae16 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2497,8 +2497,13 @@ struct tg3_napi { u32 last_tag; u32 last_irq_tag; u32 int_mbox; + u32 consmbox; + u32 rx_rcb_ptr; + + struct tg3_rx_buffer_desc *rx_rcb; dma_addr_t status_mapping; + dma_addr_t rx_rcb_mapping; }; struct tg3 { @@ -2570,7 +2575,6 @@ struct tg3 { struct tg3_napi napi[TG3_IRQ_MAX_VECS]; void (*write32_rx_mbox) (struct tg3 *, u32, u32); - u32 rx_rcb_ptr; u32 rx_pending; u32 rx_jumbo_pending; u32 rx_std_max_post; @@ -2579,9 +2583,6 @@ struct tg3 { struct vlan_group *vlgrp; #endif - struct tg3_rx_buffer_desc *rx_rcb; - dma_addr_t rx_rcb_mapping; - struct tg3_rx_prodring_set prodring[1]; -- cgit v1.2.3-18-g5258 From f3f3f27e5b4e27737f824535e6f145a3c88b976c Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 14:03:21 +0000 Subject: tg3: Move per-int tx members to a per-int struct This patch moves the tx_prod, tx_cons, tx_pending, tx_ring, and tx_buffers transmit ring device members to a per-interrupt structure. It also adds a new transmit producer mailbox member (prodmbox) and converts the code to use it rather than a preprocessor constant. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 150 ++++++++++++++++++++++++++++-------------------------- drivers/net/tg3.h | 15 +++--- 2 files changed, 86 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 939574c571f..e36b0b25972 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -136,7 +136,7 @@ #define TG3_RX_JMB_MAP_SZ TG3_RX_DMA_TO_MAP_SZ(TG3_RX_JMB_DMA_SZ) /* minimum number of free TX descriptors required to wake up TX process */ -#define TG3_TX_WAKEUP_THRESH(tp) ((tp)->tx_pending / 4) +#define TG3_TX_WAKEUP_THRESH(tnapi) ((tnapi)->tx_pending / 4) #define TG3_RAW_IP_ALIGN 2 @@ -656,7 +656,7 @@ static inline unsigned int tg3_has_work(struct tg3_napi *tnapi) work_exists = 1; } /* check for RX/TX work to do */ - if (sblk->idx[0].tx_consumer != tp->tx_cons || + if (sblk->idx[0].tx_consumer != tnapi->tx_cons || sblk->idx[0].rx_producer != tnapi->rx_rcb_ptr) work_exists = 1; @@ -4269,11 +4269,11 @@ static void tg3_tx_recover(struct tg3 *tp) spin_unlock(&tp->lock); } -static inline u32 tg3_tx_avail(struct tg3 *tp) +static inline u32 tg3_tx_avail(struct tg3_napi *tnapi) { smp_mb(); - return (tp->tx_pending - - ((tp->tx_prod - tp->tx_cons) & (TG3_TX_RING_SIZE - 1))); + return tnapi->tx_pending - + ((tnapi->tx_prod - tnapi->tx_cons) & (TG3_TX_RING_SIZE - 1)); } /* Tigon3 never reports partial packet sends. So we do not @@ -4284,10 +4284,10 @@ static void tg3_tx(struct tg3_napi *tnapi) { struct tg3 *tp = tnapi->tp; u32 hw_idx = tnapi->hw_status->idx[0].tx_consumer; - u32 sw_idx = tp->tx_cons; + u32 sw_idx = tnapi->tx_cons; while (sw_idx != hw_idx) { - struct tx_ring_info *ri = &tp->tx_buffers[sw_idx]; + struct tx_ring_info *ri = &tnapi->tx_buffers[sw_idx]; struct sk_buff *skb = ri->skb; int i, tx_bug = 0; @@ -4303,7 +4303,7 @@ static void tg3_tx(struct tg3_napi *tnapi) sw_idx = NEXT_TX(sw_idx); for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - ri = &tp->tx_buffers[sw_idx]; + ri = &tnapi->tx_buffers[sw_idx]; if (unlikely(ri->skb != NULL || sw_idx == hw_idx)) tx_bug = 1; sw_idx = NEXT_TX(sw_idx); @@ -4317,7 +4317,7 @@ static void tg3_tx(struct tg3_napi *tnapi) } } - tp->tx_cons = sw_idx; + tnapi->tx_cons = sw_idx; /* Need to make the tx_cons update visible to tg3_start_xmit() * before checking for netif_queue_stopped(). Without the @@ -4327,10 +4327,10 @@ static void tg3_tx(struct tg3_napi *tnapi) smp_mb(); if (unlikely(netif_queue_stopped(tp->dev) && - (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)))) { + (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi)))) { netif_tx_lock(tp->dev); if (netif_queue_stopped(tp->dev) && - (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp))) + (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi))) netif_wake_queue(tp->dev); netif_tx_unlock(tp->dev); } @@ -4668,7 +4668,7 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) } /* run TX completion thread */ - if (sblk->idx[0].tx_consumer != tp->tx_cons) { + if (tnapi->hw_status->idx[0].tx_consumer != tnapi->tx_cons) { tg3_tx(tnapi); if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) return work_done; @@ -5044,13 +5044,14 @@ static inline int tg3_40bit_overflow_test(struct tg3 *tp, dma_addr_t mapping, #endif } -static void tg3_set_txd(struct tg3 *, int, dma_addr_t, int, u32, u32); +static void tg3_set_txd(struct tg3_napi *, int, dma_addr_t, int, u32, u32); /* Workaround 4GB and 40-bit hardware DMA bugs. */ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, u32 last_plus_one, u32 *start, u32 base_flags, u32 mss) { + struct tg3_napi *tnapi = &tp->napi[0]; struct sk_buff *new_skb; dma_addr_t new_addr = 0; u32 entry = *start; @@ -5085,7 +5086,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, dev_kfree_skb(new_skb); new_skb = NULL; } else { - tg3_set_txd(tp, entry, new_addr, new_skb->len, + tg3_set_txd(tnapi, entry, new_addr, new_skb->len, base_flags, 1 | (mss << 1)); *start = NEXT_TX(entry); } @@ -5094,11 +5095,10 @@ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, /* Now clean up the sw ring entries. */ i = 0; while (entry != last_plus_one) { - if (i == 0) { - tp->tx_buffers[entry].skb = new_skb; - } else { - tp->tx_buffers[entry].skb = NULL; - } + if (i == 0) + tnapi->tx_buffers[entry].skb = new_skb; + else + tnapi->tx_buffers[entry].skb = NULL; entry = NEXT_TX(entry); i++; } @@ -5109,11 +5109,11 @@ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, return ret; } -static void tg3_set_txd(struct tg3 *tp, int entry, +static void tg3_set_txd(struct tg3_napi *tnapi, int entry, dma_addr_t mapping, int len, u32 flags, u32 mss_and_is_end) { - struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry]; + struct tg3_tx_buffer_desc *txd = &tnapi->tx_ring[entry]; int is_end = (mss_and_is_end & 0x1); u32 mss = (mss_and_is_end >> 1); u32 vlan_tag = 0; @@ -5141,6 +5141,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 len, entry, base_flags, mss; struct skb_shared_info *sp; dma_addr_t mapping; + struct tg3_napi *tnapi = &tp->napi[0]; len = skb_headlen(skb); @@ -5149,7 +5150,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) * interrupt. Furthermore, IRQ processing runs lockless so we have * no IRQ context deadlocks to worry about either. Rejoice! */ - if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->nr_frags + 1))) { + if (unlikely(tg3_tx_avail(tnapi) <= (skb_shinfo(skb)->nr_frags + 1))) { if (!netif_queue_stopped(dev)) { netif_stop_queue(dev); @@ -5160,7 +5161,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; } - entry = tp->tx_prod; + entry = tnapi->tx_prod; base_flags = 0; mss = 0; if ((mss = skb_shinfo(skb)->gso_size) != 0) { @@ -5208,9 +5209,9 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) mapping = sp->dma_head; - tp->tx_buffers[entry].skb = skb; + tnapi->tx_buffers[entry].skb = skb; - tg3_set_txd(tp, entry, mapping, len, base_flags, + tg3_set_txd(tnapi, entry, mapping, len, base_flags, (skb_shinfo(skb)->nr_frags == 0) | (mss << 1)); entry = NEXT_TX(entry); @@ -5225,9 +5226,9 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) len = frag->size; mapping = sp->dma_maps[i]; - tp->tx_buffers[entry].skb = NULL; + tnapi->tx_buffers[entry].skb = NULL; - tg3_set_txd(tp, entry, mapping, len, + tg3_set_txd(tnapi, entry, mapping, len, base_flags, (i == last) | (mss << 1)); entry = NEXT_TX(entry); @@ -5235,12 +5236,12 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) } /* Packets are ready, update Tx producer idx local and on card. */ - tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry); + tw32_tx_mbox(tnapi->prodmbox, entry); - tp->tx_prod = entry; - if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) { + tnapi->tx_prod = entry; + if (unlikely(tg3_tx_avail(tnapi) <= (MAX_SKB_FRAGS + 1))) { netif_stop_queue(dev); - if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)) + if (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi)) netif_wake_queue(tp->dev); } @@ -5258,11 +5259,12 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *, struct net_device *); static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb) { struct sk_buff *segs, *nskb; + u32 frag_cnt_est = skb_shinfo(skb)->gso_segs * 3; /* Estimate the number of fragments in the worst case */ - if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->gso_segs * 3))) { + if (unlikely(tg3_tx_avail(&tp->napi[0]) <= frag_cnt_est)) { netif_stop_queue(tp->dev); - if (tg3_tx_avail(tp) <= (skb_shinfo(skb)->gso_segs * 3)) + if (tg3_tx_avail(&tp->napi[0]) <= frag_cnt_est) return NETDEV_TX_BUSY; netif_wake_queue(tp->dev); @@ -5295,6 +5297,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) struct skb_shared_info *sp; int would_hit_hwbug; dma_addr_t mapping; + struct tg3_napi *tnapi = &tp->napi[0]; len = skb_headlen(skb); @@ -5303,7 +5306,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) * interrupt. Furthermore, IRQ processing runs lockless so we have * no IRQ context deadlocks to worry about either. Rejoice! */ - if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->nr_frags + 1))) { + if (unlikely(tg3_tx_avail(tnapi) <= (skb_shinfo(skb)->nr_frags + 1))) { if (!netif_queue_stopped(dev)) { netif_stop_queue(dev); @@ -5314,7 +5317,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; } - entry = tp->tx_prod; + entry = tnapi->tx_prod; base_flags = 0; if (skb->ip_summed == CHECKSUM_PARTIAL) base_flags |= TXD_FLAG_TCPUDP_CSUM; @@ -5384,7 +5387,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) mapping = sp->dma_head; - tp->tx_buffers[entry].skb = skb; + tnapi->tx_buffers[entry].skb = skb; would_hit_hwbug = 0; @@ -5393,7 +5396,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) else if (tg3_4g_overflow_test(mapping, len)) would_hit_hwbug = 1; - tg3_set_txd(tp, entry, mapping, len, base_flags, + tg3_set_txd(tnapi, entry, mapping, len, base_flags, (skb_shinfo(skb)->nr_frags == 0) | (mss << 1)); entry = NEXT_TX(entry); @@ -5409,7 +5412,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) len = frag->size; mapping = sp->dma_maps[i]; - tp->tx_buffers[entry].skb = NULL; + tnapi->tx_buffers[entry].skb = NULL; if (tg3_4g_overflow_test(mapping, len)) would_hit_hwbug = 1; @@ -5418,10 +5421,10 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) would_hit_hwbug = 1; if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) - tg3_set_txd(tp, entry, mapping, len, + tg3_set_txd(tnapi, entry, mapping, len, base_flags, (i == last)|(mss << 1)); else - tg3_set_txd(tp, entry, mapping, len, + tg3_set_txd(tnapi, entry, mapping, len, base_flags, (i == last)); entry = NEXT_TX(entry); @@ -5446,12 +5449,12 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) } /* Packets are ready, update Tx producer idx local and on card. */ - tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry); + tw32_tx_mbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, entry); - tp->tx_prod = entry; - if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) { + tnapi->tx_prod = entry; + if (unlikely(tg3_tx_avail(tnapi) <= (MAX_SKB_FRAGS + 1))) { netif_stop_queue(dev); - if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)) + if (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi)) netif_wake_queue(tp->dev); } @@ -5522,8 +5525,8 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) static void tg3_rx_prodring_free(struct tg3 *tp, struct tg3_rx_prodring_set *tpr) { - struct ring_info *rxp; int i; + struct ring_info *rxp; for (i = 0; i < TG3_RX_RING_SIZE; i++) { rxp = &tpr->rx_std_buffers[i]; @@ -5710,13 +5713,14 @@ err_out: */ static void tg3_free_rings(struct tg3 *tp) { + struct tg3_napi *tnapi = &tp->napi[0]; int i; for (i = 0; i < TG3_TX_RING_SIZE; ) { struct tx_ring_info *txp; struct sk_buff *skb; - txp = &tp->tx_buffers[i]; + txp = &tnapi->tx_buffers[i]; skb = txp->skb; if (skb == NULL) { @@ -5751,7 +5755,7 @@ static int tg3_init_rings(struct tg3 *tp) tg3_free_rings(tp); /* Zero out all descriptors. */ - memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); + memset(tnapi->tx_ring, 0, TG3_TX_RING_BYTES); tnapi->rx_rcb_ptr = 0; memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); @@ -5767,12 +5771,12 @@ static void tg3_free_consistent(struct tg3 *tp) { struct tg3_napi *tnapi = &tp->napi[0]; - kfree(tp->tx_buffers); - tp->tx_buffers = NULL; - if (tp->tx_ring) { + kfree(tnapi->tx_buffers); + tnapi->tx_buffers = NULL; + if (tnapi->tx_ring) { pci_free_consistent(tp->pdev, TG3_TX_RING_BYTES, - tp->tx_ring, tp->tx_desc_mapping); - tp->tx_ring = NULL; + tnapi->tx_ring, tnapi->tx_desc_mapping); + tnapi->tx_ring = NULL; } if (tnapi->rx_rcb) { pci_free_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp), @@ -5804,14 +5808,14 @@ static int tg3_alloc_consistent(struct tg3 *tp) if (tg3_rx_prodring_init(tp, &tp->prodring[0])) return -ENOMEM; - tp->tx_buffers = kzalloc(sizeof(struct tx_ring_info) * - TG3_TX_RING_SIZE, GFP_KERNEL); - if (!tp->tx_buffers) + tnapi->tx_buffers = kzalloc(sizeof(struct tx_ring_info) * + TG3_TX_RING_SIZE, GFP_KERNEL); + if (!tnapi->tx_buffers) goto err_out; - tp->tx_ring = pci_alloc_consistent(tp->pdev, TG3_TX_RING_BYTES, - &tp->tx_desc_mapping); - if (!tp->tx_ring) + tnapi->tx_ring = pci_alloc_consistent(tp->pdev, TG3_TX_RING_BYTES, + &tnapi->tx_desc_mapping); + if (!tnapi->tx_ring) goto err_out; tnapi->hw_status = pci_alloc_consistent(tp->pdev, @@ -7094,13 +7098,15 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) BDINFO_FLAGS_DISABLED); } - tp->tx_prod = 0; - tp->tx_cons = 0; - tw32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0); + tp->napi[0].tx_prod = 0; + tp->napi[0].tx_cons = 0; tw32_tx_mbox(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0); + val = MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW; + tw32_mailbox(val, 0); + tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB, - tp->tx_desc_mapping, + tp->napi[0].tx_desc_mapping, (TG3_TX_RING_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT), NIC_SRAM_TX_BUFFER_DESC); @@ -9093,7 +9099,7 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam * else ering->rx_jumbo_pending = 0; - ering->tx_pending = tp->tx_pending; + ering->tx_pending = tp->napi[0].tx_pending; } static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) @@ -9123,7 +9129,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e tp->rx_pending > 63) tp->rx_pending = 63; tp->rx_jumbo_pending = ering->rx_jumbo_pending; - tp->tx_pending = ering->tx_pending; + tp->napi[0].tx_pending = ering->tx_pending; if (netif_running(dev)) { tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); @@ -9928,14 +9934,13 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) num_pkts = 0; - tg3_set_txd(tp, tp->tx_prod, map, tx_len, 0, 1); + tg3_set_txd(tnapi, tnapi->tx_prod, map, tx_len, 0, 1); - tp->tx_prod++; + tnapi->tx_prod++; num_pkts++; - tw32_tx_mbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, - tp->tx_prod); - tr32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW); + tw32_tx_mbox(tnapi->prodmbox, tnapi->tx_prod); + tr32_mailbox(tnapi->prodmbox); udelay(10); @@ -9948,7 +9953,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) tx_idx = tnapi->hw_status->idx[0].tx_consumer; rx_idx = rnapi->hw_status->idx[0].rx_producer; - if ((tx_idx == tp->tx_prod) && + if ((tx_idx == tnapi->tx_prod) && (rx_idx == (rx_start_idx + num_pkts))) break; } @@ -9956,7 +9961,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) pci_unmap_single(tp->pdev, map, tx_len, PCI_DMA_TODEVICE); dev_kfree_skb(skb); - if (tx_idx != tp->tx_prod) + if (tx_idx != tnapi->tx_prod) goto out; if (rx_idx != rx_start_idx + num_pkts) @@ -13415,11 +13420,12 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tp->rx_pending = TG3_DEF_RX_RING_PENDING; tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING; - tp->tx_pending = TG3_DEF_TX_RING_PENDING; tp->napi[0].tp = tp; tp->napi[0].int_mbox = MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW; tp->napi[0].consmbox = MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW; + tp->napi[0].prodmbox = MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW; + tp->napi[0].tx_pending = TG3_DEF_TX_RING_PENDING; netif_napi_add(dev, &tp->napi[0].napi, tg3_poll, 64); dev->ethtool_ops = &tg3_ethtool_ops; dev->watchdog_timeo = TG3_TX_TIMEOUT; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index b91ac29ae16..a816b2c0f16 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2497,13 +2497,21 @@ struct tg3_napi { u32 last_tag; u32 last_irq_tag; u32 int_mbox; + u32 tx_prod; + u32 tx_cons; + u32 tx_pending; + u32 prodmbox; + u32 consmbox; u32 rx_rcb_ptr; struct tg3_rx_buffer_desc *rx_rcb; + struct tg3_tx_buffer_desc *tx_ring; + struct tx_ring_info *tx_buffers; dma_addr_t status_mapping; dma_addr_t rx_rcb_mapping; + dma_addr_t tx_desc_mapping; }; struct tg3 { @@ -2563,13 +2571,6 @@ struct tg3 { /* begin "tx thread" cacheline section */ void (*write32_tx_mbox) (struct tg3 *, u32, u32); - u32 tx_prod; - u32 tx_cons; - u32 tx_pending; - - struct tg3_tx_buffer_desc *tx_ring; - struct tx_ring_info *tx_buffers; - dma_addr_t tx_desc_mapping; /* begin "rx thread" cacheline section */ struct tg3_napi napi[TG3_IRQ_MAX_VECS]; -- cgit v1.2.3-18-g5258 From fc57e515a2c02599b00d252545521288dfc0158a Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 28 Aug 2009 14:03:44 +0000 Subject: tg3: Update version to 3.101 This patch updates the tg3 version to 3.101. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e36b0b25972..a7d14aae258 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -68,8 +68,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.100" -#define DRV_MODULE_RELDATE "August 25, 2009" +#define DRV_MODULE_VERSION "3.101" +#define DRV_MODULE_RELDATE "August 28, 2009" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v1.2.3-18-g5258 From 903b9124eae00edf8a9d6491dab60fcda777aabd Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 30 Aug 2009 11:30:48 -0700 Subject: Input: w90p910_keypad - move a dereference below a NULL test We should first check whether platform data is NULL or not, before dereferencing it to get the keymap. Signed-off-by: Julia Lawall Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/w90p910_keypad.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c index 2d03dd0f9e0..6032def0370 100644 --- a/drivers/input/keyboard/w90p910_keypad.c +++ b/drivers/input/keyboard/w90p910_keypad.c @@ -120,7 +120,7 @@ static int __devinit w90p910_keypad_probe(struct platform_device *pdev) { const struct w90p910_keypad_platform_data *pdata = pdev->dev.platform_data; - const struct matrix_keymap_data *keymap_data = pdata->keymap_data; + const struct matrix_keymap_data *keymap_data; struct w90p910_keypad *keypad; struct input_dev *input_dev; struct resource *res; @@ -132,6 +132,8 @@ static int __devinit w90p910_keypad_probe(struct platform_device *pdev) return -EINVAL; } + keymap_data = pdata->keymap_data; + irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "failed to get keypad irq\n"); -- cgit v1.2.3-18-g5258 From e0ad2cd8ff7fb957be867d17d44fb4b7093c91bd Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 27 Aug 2009 07:35:47 +0000 Subject: ucc_geth: Fix NULL pointer dereference in uec_get_ethtool_stats() In commit 3e73fc9a12679a546284d597c1f19165792d0b83 ("ucc_geth: Fix IO memory (un)mapping code") I fixed ug_regs IO memory leak by properly freeing the allocated memory. But ethtool_stats() callback doesn't check for ug_regs being NULL, and that causes following oops if 'ethtool -S' is executed on a closed eth device: Unable to handle kernel paging request for data at address 0x00000180 Faulting instruction address: 0xc0208228 Oops: Kernel access of bad area, sig: 11 [#1] ... NIP [c0208228] uec_get_ethtool_stats+0x38/0x140 LR [c02559a0] ethtool_get_stats+0xf8/0x23c Call Trace: [ef87bcd0] [c025597c] ethtool_get_stats+0xd4/0x23c (unreliable) [ef87bd00] [c025706c] dev_ethtool+0xfe8/0x11bc [ef87be00] [c0252b5c] dev_ioctl+0x454/0x6a8 ... ---[ end trace 77fff1162a9586b0 ]--- Segmentation fault This patch fixes the issue. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/ucc_geth_ethtool.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c index 61fe80dda3e..304128fa605 100644 --- a/drivers/net/ucc_geth_ethtool.c +++ b/drivers/net/ucc_geth_ethtool.c @@ -319,9 +319,13 @@ static void uec_get_ethtool_stats(struct net_device *netdev, int i, j = 0; if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) { - base = (u32 __iomem *)&ugeth->ug_regs->tx64; + if (ugeth->ug_regs) + base = (u32 __iomem *)&ugeth->ug_regs->tx64; + else + base = NULL; + for (i = 0; i < UEC_HW_STATS_LEN; i++) - data[j++] = in_be32(&base[i]); + data[j++] = base ? in_be32(&base[i]) : 0; } if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) { base = (u32 __iomem *)ugeth->p_tx_fw_statistics_pram; -- cgit v1.2.3-18-g5258 From 54b15983840c9eb264e41f3b14af398a72ebd426 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 27 Aug 2009 07:35:54 +0000 Subject: ucc_geth: Factor out MAC initialization steps into a call This patch factors out MAC initialization into ucc_geth_init_mac() function that we'll use for suspend/resume. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/ucc_geth.c | 87 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 52a6750b820..e474e57d96f 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3429,46 +3429,25 @@ static int ucc_geth_set_mac_addr(struct net_device *dev, void *p) return 0; } -/* Called when something needs to use the ethernet device */ -/* Returns 0 for success. */ -static int ucc_geth_open(struct net_device *dev) +static int ucc_geth_init_mac(struct ucc_geth_private *ugeth) { - struct ucc_geth_private *ugeth = netdev_priv(dev); + struct net_device *dev = ugeth->ndev; int err; - ugeth_vdbg("%s: IN", __func__); - - /* Test station address */ - if (dev->dev_addr[0] & ENET_GROUP_ADDR) { - if (netif_msg_ifup(ugeth)) - ugeth_err("%s: Multicast address used for station address" - " - is this what you wanted?", __func__); - return -EINVAL; - } - - err = init_phy(dev); - if (err) { - if (netif_msg_ifup(ugeth)) - ugeth_err("%s: Cannot initialize PHY, aborting.", - dev->name); - return err; - } - err = ucc_struct_init(ugeth); if (err) { if (netif_msg_ifup(ugeth)) - ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name); - goto out_err_stop; + ugeth_err("%s: Cannot configure internal struct, " + "aborting.", dev->name); + goto err; } - napi_enable(&ugeth->napi); - err = ucc_geth_startup(ugeth); if (err) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: Cannot configure net device, aborting.", dev->name); - goto out_err; + goto err; } err = adjust_enet_interface(ugeth); @@ -3476,7 +3455,7 @@ static int ucc_geth_open(struct net_device *dev) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Cannot configure net device, aborting.", dev->name); - goto out_err; + goto err; } /* Set MACSTNADDR1, MACSTNADDR2 */ @@ -3490,13 +3469,51 @@ static int ucc_geth_open(struct net_device *dev) &ugeth->ug_regs->macstnaddr1, &ugeth->ug_regs->macstnaddr2); - phy_start(ugeth->phydev); - err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); if (err) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: Cannot enable net device, aborting.", dev->name); - goto out_err; + goto err; + } + + return 0; +err: + ucc_geth_stop(ugeth); + return err; +} + +/* Called when something needs to use the ethernet device */ +/* Returns 0 for success. */ +static int ucc_geth_open(struct net_device *dev) +{ + struct ucc_geth_private *ugeth = netdev_priv(dev); + int err; + + ugeth_vdbg("%s: IN", __func__); + + /* Test station address */ + if (dev->dev_addr[0] & ENET_GROUP_ADDR) { + if (netif_msg_ifup(ugeth)) + ugeth_err("%s: Multicast address used for station " + "address - is this what you wanted?", + __func__); + return -EINVAL; + } + + err = init_phy(dev); + if (err) { + if (netif_msg_ifup(ugeth)) + ugeth_err("%s: Cannot initialize PHY, aborting.", + dev->name); + return err; + } + + err = ucc_geth_init_mac(ugeth); + if (err) { + if (netif_msg_ifup(ugeth)) + ugeth_err("%s: Cannot initialize MAC, aborting.", + dev->name); + goto err; } err = request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, @@ -3505,16 +3522,16 @@ static int ucc_geth_open(struct net_device *dev) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Cannot get IRQ for net device, aborting.", dev->name); - goto out_err; + goto err; } + phy_start(ugeth->phydev); + napi_enable(&ugeth->napi); netif_start_queue(dev); return err; -out_err: - napi_disable(&ugeth->napi); -out_err_stop: +err: ucc_geth_stop(ugeth); return err; } -- cgit v1.2.3-18-g5258 From bf5aec2e79418adb42f1457152b427fd3d6316d9 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 27 Aug 2009 07:35:56 +0000 Subject: ucc_geth: Remove UGETH_MAGIC_PACKET Kconfig symbol and code This patch removes currently unused UGETH_MAGIC_PACKET Kconfig symbol and code, i.e. magic_packet_detection_{enable,disable} functions. The two functions each contain just two steps that we'll place into suspend/resume code path under CONFIG_PM. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/Kconfig | 4 ---- drivers/net/ucc_geth.c | 32 -------------------------------- 2 files changed, 36 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index bbe77a06584..fed9bdaecfa 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2373,10 +2373,6 @@ config UCC_GETH This driver supports the Gigabit Ethernet mode of the QUICC Engine, which is available on some Freescale SOCs. -config UGETH_MAGIC_PACKET - bool "Magic Packet detection support" - depends on UCC_GETH - config UGETH_TX_ON_DEMAND bool "Transmit on Demand support" depends on UCC_GETH diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index e474e57d96f..d2ca61d3dff 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -438,38 +438,6 @@ static void hw_add_addr_in_hash(struct ucc_geth_private *ugeth, QE_CR_PROTOCOL_ETHERNET, 0); } -#ifdef CONFIG_UGETH_MAGIC_PACKET -static void magic_packet_detection_enable(struct ucc_geth_private *ugeth) -{ - struct ucc_fast_private *uccf; - struct ucc_geth __iomem *ug_regs; - - uccf = ugeth->uccf; - ug_regs = ugeth->ug_regs; - - /* Enable interrupts for magic packet detection */ - setbits32(uccf->p_uccm, UCC_GETH_UCCE_MPD); - - /* Enable magic packet detection */ - setbits32(&ug_regs->maccfg2, MACCFG2_MPE); -} - -static void magic_packet_detection_disable(struct ucc_geth_private *ugeth) -{ - struct ucc_fast_private *uccf; - struct ucc_geth __iomem *ug_regs; - - uccf = ugeth->uccf; - ug_regs = ugeth->ug_regs; - - /* Disable interrupts for magic packet detection */ - clrbits32(uccf->p_uccm, UCC_GETH_UCCE_MPD); - - /* Disable magic packet detection */ - clrbits32(&ug_regs->maccfg2, MACCFG2_MPE); -} -#endif /* MAGIC_PACKET */ - static inline int compare_addr(u8 **addr1, u8 **addr2) { return memcmp(addr1, addr2, ENET_NUM_OCTETS_PER_ADDRESS); -- cgit v1.2.3-18-g5258 From 2394905f67aeec5f9452f2881cbeb2b42009de0e Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 27 Aug 2009 07:35:57 +0000 Subject: ucc_geth: Implement suspend/resume and Wake-On-LAN support This patch implements suspend/resume and WOL support for UCC Ethernet driver. We support two wake up events: wake on PHY/link changes and wake on magic packet. In some CPUs (like MPC8569) QE shuts down during sleep, so magic packet detection is unusable, and also on resume we should fully reinitialize UCC structures. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/ucc_geth.c | 85 ++++++++++++++++++++++++++++++++++++++++++ drivers/net/ucc_geth.h | 1 + drivers/net/ucc_geth_ethtool.c | 40 ++++++++++++++++++++ 3 files changed, 126 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index d2ca61d3dff..7fb96f33bad 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3497,6 +3497,10 @@ static int ucc_geth_open(struct net_device *dev) napi_enable(&ugeth->napi); netif_start_queue(dev); + device_set_wakeup_capable(&dev->dev, + qe_alive_during_sleep() || ugeth->phydev->irq); + device_set_wakeup_enable(&dev->dev, ugeth->wol_en); + return err; err: @@ -3561,6 +3565,85 @@ static void ucc_geth_timeout(struct net_device *dev) schedule_work(&ugeth->timeout_work); } + +#ifdef CONFIG_PM + +static int ucc_geth_suspend(struct of_device *ofdev, pm_message_t state) +{ + struct net_device *ndev = dev_get_drvdata(&ofdev->dev); + struct ucc_geth_private *ugeth = netdev_priv(ndev); + + if (!netif_running(ndev)) + return 0; + + napi_disable(&ugeth->napi); + + /* + * Disable the controller, otherwise we'll wakeup on any network + * activity. + */ + ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); + + if (ugeth->wol_en & WAKE_MAGIC) { + setbits32(ugeth->uccf->p_uccm, UCC_GETH_UCCE_MPD); + setbits32(&ugeth->ug_regs->maccfg2, MACCFG2_MPE); + ucc_fast_enable(ugeth->uccf, COMM_DIR_RX_AND_TX); + } else if (!(ugeth->wol_en & WAKE_PHY)) { + phy_stop(ugeth->phydev); + } + + return 0; +} + +static int ucc_geth_resume(struct of_device *ofdev) +{ + struct net_device *ndev = dev_get_drvdata(&ofdev->dev); + struct ucc_geth_private *ugeth = netdev_priv(ndev); + int err; + + if (!netif_running(ndev)) + return 0; + + if (qe_alive_during_sleep()) { + if (ugeth->wol_en & WAKE_MAGIC) { + ucc_fast_disable(ugeth->uccf, COMM_DIR_RX_AND_TX); + clrbits32(&ugeth->ug_regs->maccfg2, MACCFG2_MPE); + clrbits32(ugeth->uccf->p_uccm, UCC_GETH_UCCE_MPD); + } + ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); + } else { + /* + * Full reinitialization is required if QE shuts down + * during sleep. + */ + ucc_geth_memclean(ugeth); + + err = ucc_geth_init_mac(ugeth); + if (err) { + ugeth_err("%s: Cannot initialize MAC, aborting.", + ndev->name); + return err; + } + } + + ugeth->oldlink = 0; + ugeth->oldspeed = 0; + ugeth->oldduplex = -1; + + phy_stop(ugeth->phydev); + phy_start(ugeth->phydev); + + napi_enable(&ugeth->napi); + netif_start_queue(ndev); + + return 0; +} + +#else +#define ucc_geth_suspend NULL +#define ucc_geth_resume NULL +#endif + static phy_interface_t to_phy_interface(const char *phy_connection_type) { if (strcasecmp(phy_connection_type, "mii") == 0) @@ -3852,6 +3935,8 @@ static struct of_platform_driver ucc_geth_driver = { .match_table = ucc_geth_match, .probe = ucc_geth_probe, .remove = ucc_geth_remove, + .suspend = ucc_geth_suspend, + .resume = ucc_geth_resume, }; static int __init ucc_geth_init(void) diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index cfb31afc08a..03a6ca016d5 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -1222,6 +1222,7 @@ struct ucc_geth_private { int oldspeed; int oldduplex; int oldlink; + int wol_en; struct device_node *node; }; diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c index 304128fa605..7075f26e97d 100644 --- a/drivers/net/ucc_geth_ethtool.c +++ b/drivers/net/ucc_geth_ethtool.c @@ -359,6 +359,44 @@ uec_get_drvinfo(struct net_device *netdev, drvinfo->regdump_len = uec_get_regs_len(netdev); } +#ifdef CONFIG_PM + +static void uec_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct ucc_geth_private *ugeth = netdev_priv(netdev); + struct phy_device *phydev = ugeth->phydev; + + if (phydev && phydev->irq) + wol->supported |= WAKE_PHY; + if (qe_alive_during_sleep()) + wol->supported |= WAKE_MAGIC; + + wol->wolopts = ugeth->wol_en; +} + +static int uec_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct ucc_geth_private *ugeth = netdev_priv(netdev); + struct phy_device *phydev = ugeth->phydev; + + if (wol->wolopts & ~(WAKE_PHY | WAKE_MAGIC)) + return -EINVAL; + else if (wol->wolopts & WAKE_PHY && (!phydev || !phydev->irq)) + return -EINVAL; + else if (wol->wolopts & WAKE_MAGIC && !qe_alive_during_sleep()) + return -EINVAL; + + ugeth->wol_en = wol->wolopts; + device_set_wakeup_enable(&netdev->dev, ugeth->wol_en); + + return 0; +} + +#else +#define uec_get_wol NULL +#define uec_set_wol NULL +#endif /* CONFIG_PM */ + static const struct ethtool_ops uec_ethtool_ops = { .get_settings = uec_get_settings, .set_settings = uec_set_settings, @@ -377,6 +415,8 @@ static const struct ethtool_ops uec_ethtool_ops = { .get_sset_count = uec_get_sset_count, .get_strings = uec_get_strings, .get_ethtool_stats = uec_get_ethtool_stats, + .get_wol = uec_get_wol, + .set_wol = uec_set_wol, }; void uec_set_ethtool_ops(struct net_device *netdev) -- cgit v1.2.3-18-g5258 From 5de3fcab91b0e1809eec030355d15801daf25083 Mon Sep 17 00:00:00 2001 From: roel kluin Date: Thu, 20 Aug 2009 04:04:40 +0000 Subject: WAN: bit and/or confusion Fix the tests that check whether Frame* bits are not set Signed-off-by: Roel Kluin Signed-off-by: David S. Miller --- drivers/net/wan/dscc4.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index e81946d9854..cc00e0f89ec 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -663,12 +663,12 @@ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, } else { if (skb->data[pkt_len] & FrameRdo) dev->stats.rx_fifo_errors++; - else if (!(skb->data[pkt_len] | ~FrameCrc)) + else if (!(skb->data[pkt_len] & FrameCrc)) dev->stats.rx_crc_errors++; - else if (!(skb->data[pkt_len] | ~(FrameVfr | FrameRab))) + else if ((skb->data[pkt_len] & (FrameVfr | FrameRab)) != + FrameVfr | FrameRab) dev->stats.rx_length_errors++; - else - dev->stats.rx_errors++; + dev->stats.rx_errors++; dev_kfree_skb_irq(skb); } refill: -- cgit v1.2.3-18-g5258 From 6fce365df8c4af573ea77e744fe310e034931d42 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 24 Aug 2009 17:29:40 +0000 Subject: s2io.c: Use const for strings Signed-off-by: Joe Perches Acked-by: Sreenivasa Honnur Signed-off-by: David S. Miller --- drivers/net/s2io.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index bd6d713c861..07e95e9b1c9 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -125,7 +125,7 @@ static inline int is_s2io_card_up(const struct s2io_nic * sp) } /* Ethtool related variables and Macros. */ -static char s2io_gstrings[][ETH_GSTRING_LEN] = { +static const char s2io_gstrings[][ETH_GSTRING_LEN] = { "Register test\t(offline)", "Eeprom test\t(offline)", "Link test\t(online)", @@ -133,7 +133,7 @@ static char s2io_gstrings[][ETH_GSTRING_LEN] = { "BIST Test\t(offline)" }; -static char ethtool_xena_stats_keys[][ETH_GSTRING_LEN] = { +static const char ethtool_xena_stats_keys[][ETH_GSTRING_LEN] = { {"tmac_frms"}, {"tmac_data_octets"}, {"tmac_drop_frms"}, @@ -230,7 +230,7 @@ static char ethtool_xena_stats_keys[][ETH_GSTRING_LEN] = { {"rxf_wr_cnt"} }; -static char ethtool_enhanced_stats_keys[][ETH_GSTRING_LEN] = { +static const char ethtool_enhanced_stats_keys[][ETH_GSTRING_LEN] = { {"rmac_ttl_1519_4095_frms"}, {"rmac_ttl_4096_8191_frms"}, {"rmac_ttl_8192_max_frms"}, @@ -249,7 +249,7 @@ static char ethtool_enhanced_stats_keys[][ETH_GSTRING_LEN] = { {"link_fault_cnt"} }; -static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { +static const char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { {"\n DRIVER STATISTICS"}, {"single_bit_ecc_errs"}, {"double_bit_ecc_errs"}, -- cgit v1.2.3-18-g5258 From 13d866a9c912d6bc7133f4ef4d536c3a960b06cb Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 24 Aug 2009 17:29:41 +0000 Subject: s2io.c: Shorten code line length by using intermediate pointers Repeated variable use and line wrapping is hard to read. Use temp variables instead of direct references. struct fifo_info *fifo = &mac_control->fifos[i]; struct ring_info *ring = &mac_control->rings[i]; struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; Signed-off-by: Joe Perches Acked-by: Sreenivasa Honnur Signed-off-by: David S. Miller --- drivers/net/s2io.c | 393 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 224 insertions(+), 169 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 07e95e9b1c9..b6bd3c812ad 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -364,13 +364,19 @@ static void s2io_vlan_rx_register(struct net_device *dev, struct mac_info *mac_control = &nic->mac_control; struct config_param *config = &nic->config; - for (i = 0; i < config->tx_fifo_num; i++) - spin_lock_irqsave(&mac_control->fifos[i].tx_lock, flags[i]); + for (i = 0; i < config->tx_fifo_num; i++) { + struct fifo_info *fifo = &mac_control->fifos[i]; + + spin_lock_irqsave(&fifo->tx_lock, flags[i]); + } nic->vlgrp = grp; - for (i = config->tx_fifo_num - 1; i >= 0; i--) - spin_unlock_irqrestore(&mac_control->fifos[i].tx_lock, - flags[i]); + + for (i = config->tx_fifo_num - 1; i >= 0; i--) { + struct fifo_info *fifo = &mac_control->fifos[i]; + + spin_unlock_irqrestore(&fifo->tx_lock, flags[i]); + } } /* Unregister the vlan */ @@ -382,15 +388,20 @@ static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) struct mac_info *mac_control = &nic->mac_control; struct config_param *config = &nic->config; - for (i = 0; i < config->tx_fifo_num; i++) - spin_lock_irqsave(&mac_control->fifos[i].tx_lock, flags[i]); + for (i = 0; i < config->tx_fifo_num; i++) { + struct fifo_info *fifo = &mac_control->fifos[i]; + + spin_lock_irqsave(&fifo->tx_lock, flags[i]); + } if (nic->vlgrp) vlan_group_set_device(nic->vlgrp, vid, NULL); - for (i = config->tx_fifo_num - 1; i >= 0; i--) - spin_unlock_irqrestore(&mac_control->fifos[i].tx_lock, - flags[i]); + for (i = config->tx_fifo_num - 1; i >= 0; i--) { + struct fifo_info *fifo = &mac_control->fifos[i]; + + spin_unlock_irqrestore(&fifo->tx_lock, flags[i]); + } } /* @@ -635,11 +646,12 @@ static int init_shared_mem(struct s2io_nic *nic) mac_control = &nic->mac_control; config = &nic->config; - - /* Allocation and initialization of TXDLs in FIOFs */ + /* Allocation and initialization of TXDLs in FIFOs */ size = 0; for (i = 0; i < config->tx_fifo_num; i++) { - size += config->tx_cfg[i].fifo_len; + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + + size += tx_cfg->fifo_len; } if (size > MAX_AVAILABLE_TXDS) { DBG_PRINT(ERR_DBG, "s2io: Requested TxDs too high, "); @@ -649,7 +661,9 @@ static int init_shared_mem(struct s2io_nic *nic) size = 0; for (i = 0; i < config->tx_fifo_num; i++) { - size = config->tx_cfg[i].fifo_len; + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + + size = tx_cfg->fifo_len; /* * Legal values are from 2 to 8192 */ @@ -666,11 +680,13 @@ static int init_shared_mem(struct s2io_nic *nic) lst_per_page = PAGE_SIZE / lst_size; for (i = 0; i < config->tx_fifo_num; i++) { - int fifo_len = config->tx_cfg[i].fifo_len; + struct fifo_info *fifo = &mac_control->fifos[i]; + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + int fifo_len = tx_cfg->fifo_len; int list_holder_size = fifo_len * sizeof(struct list_info_hold); - mac_control->fifos[i].list_info = kzalloc(list_holder_size, - GFP_KERNEL); - if (!mac_control->fifos[i].list_info) { + + fifo->list_info = kzalloc(list_holder_size, GFP_KERNEL); + if (!fifo->list_info) { DBG_PRINT(INFO_DBG, "Malloc failed for list_info\n"); return -ENOMEM; @@ -680,16 +696,17 @@ static int init_shared_mem(struct s2io_nic *nic) for (i = 0; i < config->tx_fifo_num; i++) { int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len, lst_per_page); - mac_control->fifos[i].tx_curr_put_info.offset = 0; - mac_control->fifos[i].tx_curr_put_info.fifo_len = - config->tx_cfg[i].fifo_len - 1; - mac_control->fifos[i].tx_curr_get_info.offset = 0; - mac_control->fifos[i].tx_curr_get_info.fifo_len = - config->tx_cfg[i].fifo_len - 1; - mac_control->fifos[i].fifo_no = i; - mac_control->fifos[i].nic = nic; - mac_control->fifos[i].max_txds = MAX_SKB_FRAGS + 2; - mac_control->fifos[i].dev = dev; + struct fifo_info *fifo = &mac_control->fifos[i]; + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + + fifo->tx_curr_put_info.offset = 0; + fifo->tx_curr_put_info.fifo_len = tx_cfg->fifo_len - 1; + fifo->tx_curr_get_info.offset = 0; + fifo->tx_curr_get_info.fifo_len = tx_cfg->fifo_len - 1; + fifo->fifo_no = i; + fifo->nic = nic; + fifo->max_txds = MAX_SKB_FRAGS + 2; + fifo->dev = dev; for (j = 0; j < page_num; j++) { int k = 0; @@ -726,11 +743,11 @@ static int init_shared_mem(struct s2io_nic *nic) } while (k < lst_per_page) { int l = (j * lst_per_page) + k; - if (l == config->tx_cfg[i].fifo_len) + if (l == tx_cfg->fifo_len) break; - mac_control->fifos[i].list_info[l].list_virt_addr = + fifo->list_info[l].list_virt_addr = tmp_v + (k * lst_size); - mac_control->fifos[i].list_info[l].list_phy_addr = + fifo->list_info[l].list_phy_addr = tmp_p + (k * lst_size); k++; } @@ -738,10 +755,12 @@ static int init_shared_mem(struct s2io_nic *nic) } for (i = 0; i < config->tx_fifo_num; i++) { - size = config->tx_cfg[i].fifo_len; - mac_control->fifos[i].ufo_in_band_v - = kcalloc(size, sizeof(u64), GFP_KERNEL); - if (!mac_control->fifos[i].ufo_in_band_v) + struct fifo_info *fifo = &mac_control->fifos[i]; + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + + size = tx_cfg->fifo_len; + fifo->ufo_in_band_v = kcalloc(size, sizeof(u64), GFP_KERNEL); + if (!fifo->ufo_in_band_v) return -ENOMEM; mem_allocated += (size * sizeof(u64)); } @@ -749,20 +768,19 @@ static int init_shared_mem(struct s2io_nic *nic) /* Allocation and initialization of RXDs in Rings */ size = 0; for (i = 0; i < config->rx_ring_num; i++) { - if (config->rx_cfg[i].num_rxd % - (rxd_count[nic->rxd_mode] + 1)) { + struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; + struct ring_info *ring = &mac_control->rings[i]; + + if (rx_cfg->num_rxd % (rxd_count[nic->rxd_mode] + 1)) { DBG_PRINT(ERR_DBG, "%s: RxD count of ", dev->name); - DBG_PRINT(ERR_DBG, "Ring%d is not a multiple of ", - i); + DBG_PRINT(ERR_DBG, "Ring%d is not a multiple of ", i); DBG_PRINT(ERR_DBG, "RxDs per Block"); return FAILURE; } - size += config->rx_cfg[i].num_rxd; - mac_control->rings[i].block_count = - config->rx_cfg[i].num_rxd / + size += rx_cfg->num_rxd; + ring->block_count = rx_cfg->num_rxd / (rxd_count[nic->rxd_mode] + 1 ); - mac_control->rings[i].pkt_cnt = config->rx_cfg[i].num_rxd - - mac_control->rings[i].block_count; + ring->pkt_cnt = rx_cfg->num_rxd - ring->block_count; } if (nic->rxd_mode == RXD_MODE_1) size = (size * (sizeof(struct RxD1))); @@ -770,26 +788,26 @@ static int init_shared_mem(struct s2io_nic *nic) size = (size * (sizeof(struct RxD3))); for (i = 0; i < config->rx_ring_num; i++) { - mac_control->rings[i].rx_curr_get_info.block_index = 0; - mac_control->rings[i].rx_curr_get_info.offset = 0; - mac_control->rings[i].rx_curr_get_info.ring_len = - config->rx_cfg[i].num_rxd - 1; - mac_control->rings[i].rx_curr_put_info.block_index = 0; - mac_control->rings[i].rx_curr_put_info.offset = 0; - mac_control->rings[i].rx_curr_put_info.ring_len = - config->rx_cfg[i].num_rxd - 1; - mac_control->rings[i].nic = nic; - mac_control->rings[i].ring_no = i; - mac_control->rings[i].lro = lro_enable; - - blk_cnt = config->rx_cfg[i].num_rxd / - (rxd_count[nic->rxd_mode] + 1); + struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; + struct ring_info *ring = &mac_control->rings[i]; + + ring->rx_curr_get_info.block_index = 0; + ring->rx_curr_get_info.offset = 0; + ring->rx_curr_get_info.ring_len = rx_cfg->num_rxd - 1; + ring->rx_curr_put_info.block_index = 0; + ring->rx_curr_put_info.offset = 0; + ring->rx_curr_put_info.ring_len = rx_cfg->num_rxd - 1; + ring->nic = nic; + ring->ring_no = i; + ring->lro = lro_enable; + + blk_cnt = rx_cfg->num_rxd / (rxd_count[nic->rxd_mode] + 1); /* Allocating all the Rx blocks */ for (j = 0; j < blk_cnt; j++) { struct rx_block_info *rx_blocks; int l; - rx_blocks = &mac_control->rings[i].rx_blocks[j]; + rx_blocks = &ring->rx_blocks[j]; size = SIZE_OF_BLOCK; //size is always page size tmp_v_addr = pci_alloc_consistent(nic->pdev, size, &tmp_p_addr); @@ -825,16 +843,11 @@ static int init_shared_mem(struct s2io_nic *nic) } /* Interlinking all Rx Blocks */ for (j = 0; j < blk_cnt; j++) { - tmp_v_addr = - mac_control->rings[i].rx_blocks[j].block_virt_addr; - tmp_v_addr_next = - mac_control->rings[i].rx_blocks[(j + 1) % - blk_cnt].block_virt_addr; - tmp_p_addr = - mac_control->rings[i].rx_blocks[j].block_dma_addr; - tmp_p_addr_next = - mac_control->rings[i].rx_blocks[(j + 1) % - blk_cnt].block_dma_addr; + int next = (j + 1) % blk_cnt; + tmp_v_addr = ring->rx_blocks[j].block_virt_addr; + tmp_v_addr_next = ring->rx_blocks[next].block_virt_addr; + tmp_p_addr = ring->rx_blocks[j].block_dma_addr; + tmp_p_addr_next = ring->rx_blocks[next].block_dma_addr; pre_rxd_blk = (struct RxD_block *) tmp_v_addr; pre_rxd_blk->reserved_2_pNext_RxD_block = @@ -849,26 +862,28 @@ static int init_shared_mem(struct s2io_nic *nic) * and the buffers as well. */ for (i = 0; i < config->rx_ring_num; i++) { - blk_cnt = config->rx_cfg[i].num_rxd / - (rxd_count[nic->rxd_mode]+ 1); - mac_control->rings[i].ba = - kmalloc((sizeof(struct buffAdd *) * blk_cnt), - GFP_KERNEL); - if (!mac_control->rings[i].ba) + struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; + struct ring_info *ring = &mac_control->rings[i]; + + blk_cnt = rx_cfg->num_rxd / + (rxd_count[nic->rxd_mode]+ 1); + ring->ba = kmalloc((sizeof(struct buffAdd *) * blk_cnt), + GFP_KERNEL); + if (!ring->ba) return -ENOMEM; mem_allocated +=(sizeof(struct buffAdd *) * blk_cnt); for (j = 0; j < blk_cnt; j++) { int k = 0; - mac_control->rings[i].ba[j] = + ring->ba[j] = kmalloc((sizeof(struct buffAdd) * (rxd_count[nic->rxd_mode] + 1)), GFP_KERNEL); - if (!mac_control->rings[i].ba[j]) + if (!ring->ba[j]) return -ENOMEM; mem_allocated += (sizeof(struct buffAdd) * \ (rxd_count[nic->rxd_mode] + 1)); while (k != rxd_count[nic->rxd_mode]) { - ba = &mac_control->rings[i].ba[j][k]; + ba = &ring->ba[j][k]; ba->ba_0_org = (void *) kmalloc (BUF0_LEN + ALIGN_SIZE, GFP_KERNEL); @@ -952,22 +967,23 @@ static void free_shared_mem(struct s2io_nic *nic) lst_per_page = PAGE_SIZE / lst_size; for (i = 0; i < config->tx_fifo_num; i++) { - page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len, - lst_per_page); + struct fifo_info *fifo = &mac_control->fifos[i]; + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + + page_num = TXD_MEM_PAGE_CNT(tx_cfg->fifo_len, lst_per_page); for (j = 0; j < page_num; j++) { int mem_blks = (j * lst_per_page); - if (!mac_control->fifos[i].list_info) + struct list_info_hold *fli; + + if (!fifo->list_info) return; - if (!mac_control->fifos[i].list_info[mem_blks]. - list_virt_addr) + + fli = &fifo->list_info[mem_blks]; + if (!fli->list_virt_addr) break; pci_free_consistent(nic->pdev, PAGE_SIZE, - mac_control->fifos[i]. - list_info[mem_blks]. - list_virt_addr, - mac_control->fifos[i]. - list_info[mem_blks]. - list_phy_addr); + fli->list_virt_addr, + fli->list_phy_addr); nic->mac_control.stats_info->sw_stat.mem_freed += PAGE_SIZE; } @@ -986,25 +1002,25 @@ static void free_shared_mem(struct s2io_nic *nic) nic->mac_control.stats_info->sw_stat.mem_freed += PAGE_SIZE; } - kfree(mac_control->fifos[i].list_info); + kfree(fifo->list_info); nic->mac_control.stats_info->sw_stat.mem_freed += (nic->config.tx_cfg[i].fifo_len *sizeof(struct list_info_hold)); } size = SIZE_OF_BLOCK; for (i = 0; i < config->rx_ring_num; i++) { - blk_cnt = mac_control->rings[i].block_count; + struct ring_info *ring = &mac_control->rings[i]; + + blk_cnt = ring->block_count; for (j = 0; j < blk_cnt; j++) { - tmp_v_addr = mac_control->rings[i].rx_blocks[j]. - block_virt_addr; - tmp_p_addr = mac_control->rings[i].rx_blocks[j]. - block_dma_addr; + tmp_v_addr = ring->rx_blocks[j].block_virt_addr; + tmp_p_addr = ring->rx_blocks[j].block_dma_addr; if (tmp_v_addr == NULL) break; pci_free_consistent(nic->pdev, size, tmp_v_addr, tmp_p_addr); nic->mac_control.stats_info->sw_stat.mem_freed += size; - kfree(mac_control->rings[i].rx_blocks[j].rxds); + kfree(ring->rx_blocks[j].rxds); nic->mac_control.stats_info->sw_stat.mem_freed += ( sizeof(struct rxd_info)* rxd_count[nic->rxd_mode]); } @@ -1013,15 +1029,17 @@ static void free_shared_mem(struct s2io_nic *nic) if (nic->rxd_mode == RXD_MODE_3B) { /* Freeing buffer storage addresses in 2BUFF mode. */ for (i = 0; i < config->rx_ring_num; i++) { - blk_cnt = config->rx_cfg[i].num_rxd / - (rxd_count[nic->rxd_mode] + 1); + struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; + struct ring_info *ring = &mac_control->rings[i]; + + blk_cnt = rx_cfg->num_rxd / + (rxd_count[nic->rxd_mode] + 1); for (j = 0; j < blk_cnt; j++) { int k = 0; - if (!mac_control->rings[i].ba[j]) + if (!ring->ba[j]) continue; while (k != rxd_count[nic->rxd_mode]) { - struct buffAdd *ba = - &mac_control->rings[i].ba[j][k]; + struct buffAdd *ba = &ring->ba[j][k]; kfree(ba->ba_0_org); nic->mac_control.stats_info->sw_stat.\ mem_freed += (BUF0_LEN + ALIGN_SIZE); @@ -1030,22 +1048,25 @@ static void free_shared_mem(struct s2io_nic *nic) mem_freed += (BUF1_LEN + ALIGN_SIZE); k++; } - kfree(mac_control->rings[i].ba[j]); + kfree(ring->ba[j]); nic->mac_control.stats_info->sw_stat.mem_freed += (sizeof(struct buffAdd) * (rxd_count[nic->rxd_mode] + 1)); } - kfree(mac_control->rings[i].ba); + kfree(ring->ba); nic->mac_control.stats_info->sw_stat.mem_freed += (sizeof(struct buffAdd *) * blk_cnt); } } for (i = 0; i < nic->config.tx_fifo_num; i++) { - if (mac_control->fifos[i].ufo_in_band_v) { + struct fifo_info *fifo = &mac_control->fifos[i]; + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + + if (fifo->ufo_in_band_v) { nic->mac_control.stats_info->sw_stat.mem_freed - += (config->tx_cfg[i].fifo_len * sizeof(u64)); - kfree(mac_control->fifos[i].ufo_in_band_v); + += (tx_cfg->fifo_len * sizeof(u64)); + kfree(fifo->ufo_in_band_v); } } @@ -1339,10 +1360,10 @@ static int init_nic(struct s2io_nic *nic) for (i = 0, j = 0; i < config->tx_fifo_num; i++) { - val64 |= - vBIT(config->tx_cfg[i].fifo_len - 1, ((j * 32) + 19), - 13) | vBIT(config->tx_cfg[i].fifo_priority, - ((j * 32) + 5), 3); + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + + val64 |= vBIT(tx_cfg->fifo_len - 1, ((j * 32) + 19), 13) | + vBIT(tx_cfg->fifo_priority, ((j * 32) + 5), 3); if (i == (config->tx_fifo_num - 1)) { if (i % 2 == 0) @@ -1400,9 +1421,9 @@ static int init_nic(struct s2io_nic *nic) /* Rx DMA intialization. */ val64 = 0; for (i = 0; i < config->rx_ring_num; i++) { - val64 |= - vBIT(config->rx_cfg[i].ring_priority, (5 + (i * 8)), - 3); + struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; + + val64 |= vBIT(rx_cfg->ring_priority, (5 + (i * 8)), 3); } writeq(val64, &bar0->rx_queue_priority); @@ -2276,7 +2297,9 @@ static int start_nic(struct s2io_nic *nic) /* PRC Initialization and configuration */ for (i = 0; i < config->rx_ring_num; i++) { - writeq((u64) mac_control->rings[i].rx_blocks[0].block_dma_addr, + struct ring_info *ring = &mac_control->rings[i]; + + writeq((u64) ring->rx_blocks[0].block_dma_addr, &bar0->prc_rxd0_n[i]); val64 = readq(&bar0->prc_ctrl_n[i]); @@ -2434,11 +2457,13 @@ static void free_tx_buffers(struct s2io_nic *nic) config = &nic->config; for (i = 0; i < config->tx_fifo_num; i++) { + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + struct fifo_info *fifo = &mac_control->fifos[i]; unsigned long flags; - spin_lock_irqsave(&mac_control->fifos[i].tx_lock, flags); - for (j = 0; j < config->tx_cfg[i].fifo_len; j++) { - txdp = (struct TxD *) \ - mac_control->fifos[i].list_info[j].list_virt_addr; + + spin_lock_irqsave(&fifo->tx_lock, flags); + for (j = 0; j < tx_cfg->fifo_len; j++) { + txdp = (struct TxD *)fifo->list_info[j].list_virt_addr; skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j); if (skb) { nic->mac_control.stats_info->sw_stat.mem_freed @@ -2450,9 +2475,9 @@ static void free_tx_buffers(struct s2io_nic *nic) DBG_PRINT(INTR_DBG, "%s:forcibly freeing %d skbs on FIFO%d\n", dev->name, cnt, i); - mac_control->fifos[i].tx_curr_get_info.offset = 0; - mac_control->fifos[i].tx_curr_put_info.offset = 0; - spin_unlock_irqrestore(&mac_control->fifos[i].tx_lock, flags); + fifo->tx_curr_get_info.offset = 0; + fifo->tx_curr_put_info.offset = 0; + spin_unlock_irqrestore(&fifo->tx_lock, flags); } } @@ -2795,14 +2820,16 @@ static void free_rx_buffers(struct s2io_nic *sp) config = &sp->config; for (i = 0; i < config->rx_ring_num; i++) { + struct ring_info *ring = &mac_control->rings[i]; + for (blk = 0; blk < rx_ring_sz[i]; blk++) free_rxd_blk(sp,i,blk); - mac_control->rings[i].rx_curr_put_info.block_index = 0; - mac_control->rings[i].rx_curr_get_info.block_index = 0; - mac_control->rings[i].rx_curr_put_info.offset = 0; - mac_control->rings[i].rx_curr_get_info.offset = 0; - mac_control->rings[i].rx_bufs_left = 0; + ring->rx_curr_put_info.block_index = 0; + ring->rx_curr_get_info.block_index = 0; + ring->rx_curr_put_info.offset = 0; + ring->rx_curr_get_info.offset = 0; + ring->rx_bufs_left = 0; DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n", dev->name, buf_cnt, i); } @@ -2866,7 +2893,6 @@ static int s2io_poll_msix(struct napi_struct *napi, int budget) static int s2io_poll_inta(struct napi_struct *napi, int budget) { struct s2io_nic *nic = container_of(napi, struct s2io_nic, napi); - struct ring_info *ring; struct config_param *config; struct mac_info *mac_control; int pkts_processed = 0; @@ -2881,7 +2907,7 @@ static int s2io_poll_inta(struct napi_struct *napi, int budget) return 0; for (i = 0; i < config->rx_ring_num; i++) { - ring = &mac_control->rings[i]; + struct ring_info *ring = &mac_control->rings[i]; ring_pkts_processed = rx_intr_handler(ring, budget); s2io_chk_rx_buffers(nic, ring); pkts_processed += ring_pkts_processed; @@ -2936,12 +2962,16 @@ static void s2io_netpoll(struct net_device *dev) tx_intr_handler(&mac_control->fifos[i]); /* check for received packet and indicate up to network */ - for (i = 0; i < config->rx_ring_num; i++) - rx_intr_handler(&mac_control->rings[i], 0); + for (i = 0; i < config->rx_ring_num; i++) { + struct ring_info *ring = &mac_control->rings[i]; + + rx_intr_handler(ring, 0); + } for (i = 0; i < config->rx_ring_num; i++) { - if (fill_rx_buffers(nic, &mac_control->rings[i], 0) == - -ENOMEM) { + struct ring_info *ring = &mac_control->rings[i]; + + if (fill_rx_buffers(nic, ring, 0) == -ENOMEM) { DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name); DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n"); break; @@ -4803,8 +4833,11 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) if (reason & GEN_INTR_RXTRAFFIC) writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int); - for (i = 0; i < config->rx_ring_num; i++) - rx_intr_handler(&mac_control->rings[i], 0); + for (i = 0; i < config->rx_ring_num; i++) { + struct ring_info *ring = &mac_control->rings[i]; + + rx_intr_handler(ring, 0); + } } /* @@ -4825,8 +4858,11 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) * Reallocate the buffers from the interrupt handler itself. */ if (!config->napi) { - for (i = 0; i < config->rx_ring_num; i++) - s2io_chk_rx_buffers(sp, &mac_control->rings[i]); + for (i = 0; i < config->rx_ring_num; i++) { + struct ring_info *ring = &mac_control->rings[i]; + + s2io_chk_rx_buffers(sp, ring); + } } writeq(sp->general_int_mask, &bar0->general_int_mask); readl(&bar0->general_int_status); @@ -4923,8 +4959,10 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev) /* collect per-ring rx_packets and rx_bytes */ dev->stats.rx_packets = dev->stats.rx_bytes = 0; for (i = 0; i < config->rx_ring_num; i++) { - dev->stats.rx_packets += mac_control->rings[i].rx_packets; - dev->stats.rx_bytes += mac_control->rings[i].rx_bytes; + struct ring_info *ring = &mac_control->rings[i]; + + dev->stats.rx_packets += ring->rx_packets; + dev->stats.rx_bytes += ring->rx_bytes; } return (&dev->stats); @@ -6974,15 +7012,16 @@ static int rxd_owner_bit_reset(struct s2io_nic *sp) size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4; for (i = 0; i < config->rx_ring_num; i++) { - blk_cnt = config->rx_cfg[i].num_rxd / - (rxd_count[sp->rxd_mode] +1); + struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; + struct ring_info *ring = &mac_control->rings[i]; + + blk_cnt = rx_cfg->num_rxd / (rxd_count[sp->rxd_mode] +1); for (j = 0; j < blk_cnt; j++) { for (k = 0; k < rxd_count[sp->rxd_mode]; k++) { - rxdp = mac_control->rings[i]. - rx_blocks[j].rxds[k].virt_addr; + rxdp = ring-> rx_blocks[j].rxds[k].virt_addr; if(sp->rxd_mode == RXD_MODE_3B) - ba = &mac_control->rings[i].ba[j][k]; + ba = &ring->ba[j][k]; if (set_rxd_buffer_pointer(sp, rxdp, ba, &skb,(u64 *)&temp0_64, (u64 *)&temp1_64, @@ -7205,8 +7244,10 @@ static int s2io_card_up(struct s2io_nic * sp) config = &sp->config; for (i = 0; i < config->rx_ring_num; i++) { - mac_control->rings[i].mtu = dev->mtu; - ret = fill_rx_buffers(sp, &mac_control->rings[i], 1); + struct ring_info *ring = &mac_control->rings[i]; + + ring->mtu = dev->mtu; + ret = fill_rx_buffers(sp, ring, 1); if (ret) { DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n", dev->name); @@ -7215,7 +7256,7 @@ static int s2io_card_up(struct s2io_nic * sp) return -ENOMEM; } DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i, - mac_control->rings[i].rx_bufs_left); + ring->rx_bufs_left); } /* Initialise napi */ @@ -7875,8 +7916,10 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) config->multiq = dev_multiq; for (i = 0; i < config->tx_fifo_num; i++) { - config->tx_cfg[i].fifo_len = tx_fifo_len[i]; - config->tx_cfg[i].fifo_priority = i; + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + + tx_cfg->fifo_len = tx_fifo_len[i]; + tx_cfg->fifo_priority = i; } /* mapping the QoS priority to the configured fifos */ @@ -7890,9 +7933,10 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) config->tx_intr_type = TXD_INT_TYPE_UTILZ; for (i = 0; i < config->tx_fifo_num; i++) { - config->tx_cfg[i].f_no_snoop = - (NO_SNOOP_TXD | NO_SNOOP_TXD_BUFFER); - if (config->tx_cfg[i].fifo_len < 65) { + struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; + + tx_cfg->f_no_snoop = (NO_SNOOP_TXD | NO_SNOOP_TXD_BUFFER); + if (tx_cfg->fifo_len < 65) { config->tx_intr_type = TXD_INT_TYPE_PER_LIST; break; } @@ -7903,20 +7947,23 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* Rx side parameters. */ config->rx_ring_num = rx_ring_num; for (i = 0; i < config->rx_ring_num; i++) { - config->rx_cfg[i].num_rxd = rx_ring_sz[i] * - (rxd_count[sp->rxd_mode] + 1); - config->rx_cfg[i].ring_priority = i; - mac_control->rings[i].rx_bufs_left = 0; - mac_control->rings[i].rxd_mode = sp->rxd_mode; - mac_control->rings[i].rxd_count = rxd_count[sp->rxd_mode]; - mac_control->rings[i].pdev = sp->pdev; - mac_control->rings[i].dev = sp->dev; + struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; + struct ring_info *ring = &mac_control->rings[i]; + + rx_cfg->num_rxd = rx_ring_sz[i] * (rxd_count[sp->rxd_mode] + 1); + rx_cfg->ring_priority = i; + ring->rx_bufs_left = 0; + ring->rxd_mode = sp->rxd_mode; + ring->rxd_count = rxd_count[sp->rxd_mode]; + ring->pdev = sp->pdev; + ring->dev = sp->dev; } for (i = 0; i < rx_ring_num; i++) { - config->rx_cfg[i].ring_org = RING_ORG_BUFF1; - config->rx_cfg[i].f_no_snoop = - (NO_SNOOP_RXD | NO_SNOOP_RXD_BUFFER); + struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; + + rx_cfg->ring_org = RING_ORG_BUFF1; + rx_cfg->f_no_snoop = (NO_SNOOP_RXD | NO_SNOOP_RXD_BUFFER); } /* Setting Mac Control parameters */ @@ -8015,9 +8062,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) } if (config->intr_type == MSI_X) { - for (i = 0; i < config->rx_ring_num ; i++) - netif_napi_add(dev, &mac_control->rings[i].napi, - s2io_poll_msix, 64); + for (i = 0; i < config->rx_ring_num ; i++) { + struct ring_info *ring = &mac_control->rings[i]; + + netif_napi_add(dev, &ring->napi, s2io_poll_msix, 64); + } } else { netif_napi_add(dev, &sp->napi, s2io_poll_inta, 64); } @@ -8089,8 +8138,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) sp->state = 0; /* Initialize spinlocks */ - for (i = 0; i < sp->config.tx_fifo_num; i++) - spin_lock_init(&mac_control->fifos[i].tx_lock); + for (i = 0; i < sp->config.tx_fifo_num; i++) { + struct fifo_info *fifo = &mac_control->fifos[i]; + + spin_lock_init(&fifo->tx_lock); + } /* * SXE-002: Configure link and activity LED to init state @@ -8165,8 +8217,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) break; } if (sp->config.multiq) { - for (i = 0; i < sp->config.tx_fifo_num; i++) - mac_control->fifos[i].multiq = config->multiq; + for (i = 0; i < sp->config.tx_fifo_num; i++) { + struct fifo_info *fifo = &mac_control->fifos[i]; + + fifo->multiq = config->multiq; + } DBG_PRINT(ERR_DBG, "%s: Multiqueue support enabled\n", dev->name); } else -- cgit v1.2.3-18-g5258 From 4f87032021be1aa0c3bb66b0c89d30cb35b57f8f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 24 Aug 2009 17:29:42 +0000 Subject: s2io.c: Use calculated size in kmallocs Use consistent style. Don't calculate the kmalloc size multiple times Signed-off-by: Joe Perches Acked-by: Sreenivasa Honnur Signed-off-by: David S. Miller --- drivers/net/s2io.c | 63 ++++++++++++++++++++++++------------------------------ 1 file changed, 28 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index b6bd3c812ad..75f2209bc01 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -823,15 +823,15 @@ static int init_shared_mem(struct s2io_nic *nic) } mem_allocated += size; memset(tmp_v_addr, 0, size); + + size = sizeof(struct rxd_info) * + rxd_count[nic->rxd_mode]; rx_blocks->block_virt_addr = tmp_v_addr; rx_blocks->block_dma_addr = tmp_p_addr; - rx_blocks->rxds = kmalloc(sizeof(struct rxd_info)* - rxd_count[nic->rxd_mode], - GFP_KERNEL); + rx_blocks->rxds = kmalloc(size, GFP_KERNEL); if (!rx_blocks->rxds) return -ENOMEM; - mem_allocated += - (sizeof(struct rxd_info)* rxd_count[nic->rxd_mode]); + mem_allocated += size; for (l=0; lrxd_mode];l++) { rx_blocks->rxds[l].virt_addr = rx_blocks->block_virt_addr + @@ -867,41 +867,37 @@ static int init_shared_mem(struct s2io_nic *nic) blk_cnt = rx_cfg->num_rxd / (rxd_count[nic->rxd_mode]+ 1); - ring->ba = kmalloc((sizeof(struct buffAdd *) * blk_cnt), - GFP_KERNEL); + size = sizeof(struct buffAdd *) * blk_cnt; + ring->ba = kmalloc(size, GFP_KERNEL); if (!ring->ba) return -ENOMEM; - mem_allocated +=(sizeof(struct buffAdd *) * blk_cnt); + mem_allocated += size; for (j = 0; j < blk_cnt; j++) { int k = 0; - ring->ba[j] = - kmalloc((sizeof(struct buffAdd) * - (rxd_count[nic->rxd_mode] + 1)), - GFP_KERNEL); + + size = sizeof(struct buffAdd) * + (rxd_count[nic->rxd_mode] + 1); + ring->ba[j] = kmalloc(size, GFP_KERNEL); if (!ring->ba[j]) return -ENOMEM; - mem_allocated += (sizeof(struct buffAdd) * \ - (rxd_count[nic->rxd_mode] + 1)); + mem_allocated += size; while (k != rxd_count[nic->rxd_mode]) { ba = &ring->ba[j][k]; - - ba->ba_0_org = (void *) kmalloc - (BUF0_LEN + ALIGN_SIZE, GFP_KERNEL); + size = BUF0_LEN + ALIGN_SIZE; + ba->ba_0_org = kmalloc(size, GFP_KERNEL); if (!ba->ba_0_org) return -ENOMEM; - mem_allocated += - (BUF0_LEN + ALIGN_SIZE); + mem_allocated += size; tmp = (unsigned long)ba->ba_0_org; tmp += ALIGN_SIZE; tmp &= ~((unsigned long) ALIGN_SIZE); ba->ba_0 = (void *) tmp; - ba->ba_1_org = (void *) kmalloc - (BUF1_LEN + ALIGN_SIZE, GFP_KERNEL); + size = BUF1_LEN + ALIGN_SIZE; + ba->ba_1_org = kmalloc(size, GFP_KERNEL); if (!ba->ba_1_org) return -ENOMEM; - mem_allocated - += (BUF1_LEN + ALIGN_SIZE); + mem_allocated += size; tmp = (unsigned long) ba->ba_1_org; tmp += ALIGN_SIZE; tmp &= ~((unsigned long) ALIGN_SIZE); @@ -3835,23 +3831,22 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) u64 rx_mat; u16 msi_control; /* Temp variable */ int ret, i, j, msix_indx = 1; + int size; - nic->entries = kmalloc(nic->num_entries * sizeof(struct msix_entry), - GFP_KERNEL); + size = nic->num_entries * sizeof(struct msix_entry); + nic->entries = kmalloc(size, GFP_KERNEL); if (!nic->entries) { DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", \ __func__); nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; return -ENOMEM; } - nic->mac_control.stats_info->sw_stat.mem_allocated - += (nic->num_entries * sizeof(struct msix_entry)); + nic->mac_control.stats_info->sw_stat.mem_allocated += size; - memset(nic->entries, 0, nic->num_entries * sizeof(struct msix_entry)); + memset(nic->entries, 0, size); - nic->s2io_entries = - kmalloc(nic->num_entries * sizeof(struct s2io_msix_entry), - GFP_KERNEL); + size = nic->num_entries * sizeof(struct s2io_msix_entry); + nic->s2io_entries = kmalloc(size, GFP_KERNEL); if (!nic->s2io_entries) { DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __func__); @@ -3861,10 +3856,8 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) += (nic->num_entries * sizeof(struct msix_entry)); return -ENOMEM; } - nic->mac_control.stats_info->sw_stat.mem_allocated - += (nic->num_entries * sizeof(struct s2io_msix_entry)); - memset(nic->s2io_entries, 0, - nic->num_entries * sizeof(struct s2io_msix_entry)); + nic->mac_control.stats_info->sw_stat.mem_allocated += size; + memset(nic->s2io_entries, 0, size); nic->entries[0].entry = 0; nic->s2io_entries[0].entry = 0; -- cgit v1.2.3-18-g5258 From 44364a035a4f7c5b58fd96b1a90b52746d1aab6b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 24 Aug 2009 17:29:43 +0000 Subject: s2io.c: use kzalloc Signed-off-by: Joe Perches Acked-by: Sreenivasa Honnur Signed-off-by: David S. Miller --- drivers/net/s2io.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 75f2209bc01..134cdb39e70 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -3834,7 +3834,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) int size; size = nic->num_entries * sizeof(struct msix_entry); - nic->entries = kmalloc(size, GFP_KERNEL); + nic->entries = kzalloc(size, GFP_KERNEL); if (!nic->entries) { DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", \ __func__); @@ -3843,10 +3843,8 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) } nic->mac_control.stats_info->sw_stat.mem_allocated += size; - memset(nic->entries, 0, size); - size = nic->num_entries * sizeof(struct s2io_msix_entry); - nic->s2io_entries = kmalloc(size, GFP_KERNEL); + nic->s2io_entries = kzalloc(size, GFP_KERNEL); if (!nic->s2io_entries) { DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __func__); @@ -3857,7 +3855,6 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) return -ENOMEM; } nic->mac_control.stats_info->sw_stat.mem_allocated += size; - memset(nic->s2io_entries, 0, size); nic->entries[0].entry = 0; nic->s2io_entries[0].entry = 0; -- cgit v1.2.3-18-g5258 From d44570e4067aa8b832b1c1e1eb6da079f590d501 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 24 Aug 2009 17:29:44 +0000 Subject: s2io.c: Make more conforming to normal kernel style Still has a few long lines. checkpatch was: total: 263 errors, 53 warnings, 8751 lines checked is: total: 4 errors, 35 warnings, 8767 lines checked Signed-off-by: Joe Perches Acked-by: Sreenivasa Honnur Signed-off-by: David S. Miller --- drivers/net/s2io.c | 2232 ++++++++++++++++++++++++++-------------------------- 1 file changed, 1124 insertions(+), 1108 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 134cdb39e70..003dd8c4734 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -1,7 +1,7 @@ /************************************************************************ * s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC * Copyright(c) 2002-2007 Neterion Inc. - + * * This software may be used and distributed according to the terms of * the GNU General Public License (GPL), incorporated herein by reference. * Drivers based on or derived from this code fall under the GPL and must @@ -75,11 +75,11 @@ #include #include #include +#include +#include #include #include -#include -#include #include #include @@ -93,15 +93,15 @@ static char s2io_driver_name[] = "Neterion"; static char s2io_driver_version[] = DRV_VERSION; -static int rxd_size[2] = {32,48}; -static int rxd_count[2] = {127,85}; +static int rxd_size[2] = {32, 48}; +static int rxd_count[2] = {127, 85}; static inline int RXD_IS_UP2DT(struct RxD_t *rxdp) { int ret; ret = ((!(rxdp->Control_1 & RXD_OWN_XENA)) && - (GET_RXD_MARKER(rxdp->Control_2) != THE_RXD_MARK)); + (GET_RXD_MARKER(rxdp->Control_2) != THE_RXD_MARK)); return ret; } @@ -111,15 +111,15 @@ static inline int RXD_IS_UP2DT(struct RxD_t *rxdp) * problem, 600B, 600C, 600D, 640B, 640C and 640D. * macro below identifies these cards given the subsystem_id. */ -#define CARDS_WITH_FAULTY_LINK_INDICATORS(dev_type, subid) \ - (dev_type == XFRAME_I_DEVICE) ? \ - ((((subid >= 0x600B) && (subid <= 0x600D)) || \ - ((subid >= 0x640B) && (subid <= 0x640D))) ? 1 : 0) : 0 +#define CARDS_WITH_FAULTY_LINK_INDICATORS(dev_type, subid) \ + (dev_type == XFRAME_I_DEVICE) ? \ + ((((subid >= 0x600B) && (subid <= 0x600D)) || \ + ((subid >= 0x640B) && (subid <= 0x640D))) ? 1 : 0) : 0 #define LINK_IS_UP(val64) (!(val64 & (ADAPTER_STATUS_RMAC_REMOTE_FAULT | \ ADAPTER_STATUS_RMAC_LOCAL_FAULT))) -static inline int is_s2io_card_up(const struct s2io_nic * sp) +static inline int is_s2io_card_up(const struct s2io_nic *sp) { return test_bit(__S2IO_STATE_CARD_UP, &sp->state); } @@ -328,20 +328,20 @@ static const char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { #define S2IO_ENHANCED_STAT_LEN ARRAY_SIZE(ethtool_enhanced_stats_keys) #define S2IO_DRIVER_STAT_LEN ARRAY_SIZE(ethtool_driver_stats_keys) -#define XFRAME_I_STAT_LEN (S2IO_XENA_STAT_LEN + S2IO_DRIVER_STAT_LEN ) -#define XFRAME_II_STAT_LEN (XFRAME_I_STAT_LEN + S2IO_ENHANCED_STAT_LEN ) +#define XFRAME_I_STAT_LEN (S2IO_XENA_STAT_LEN + S2IO_DRIVER_STAT_LEN) +#define XFRAME_II_STAT_LEN (XFRAME_I_STAT_LEN + S2IO_ENHANCED_STAT_LEN) -#define XFRAME_I_STAT_STRINGS_LEN ( XFRAME_I_STAT_LEN * ETH_GSTRING_LEN ) -#define XFRAME_II_STAT_STRINGS_LEN ( XFRAME_II_STAT_LEN * ETH_GSTRING_LEN ) +#define XFRAME_I_STAT_STRINGS_LEN (XFRAME_I_STAT_LEN * ETH_GSTRING_LEN) +#define XFRAME_II_STAT_STRINGS_LEN (XFRAME_II_STAT_LEN * ETH_GSTRING_LEN) #define S2IO_TEST_LEN ARRAY_SIZE(s2io_gstrings) -#define S2IO_STRINGS_LEN S2IO_TEST_LEN * ETH_GSTRING_LEN +#define S2IO_STRINGS_LEN (S2IO_TEST_LEN * ETH_GSTRING_LEN) -#define S2IO_TIMER_CONF(timer, handle, arg, exp) \ - init_timer(&timer); \ - timer.function = handle; \ - timer.data = (unsigned long) arg; \ - mod_timer(&timer, (jiffies + exp)) \ +#define S2IO_TIMER_CONF(timer, handle, arg, exp) \ + init_timer(&timer); \ + timer.function = handle; \ + timer.data = (unsigned long)arg; \ + mod_timer(&timer, (jiffies + exp)) \ /* copy mac addr to def_mac_addr array */ static void do_s2io_copy_mac_addr(struct s2io_nic *sp, int offset, u64 mac_addr) @@ -507,11 +507,11 @@ S2IO_PARM_INT(ufo, 0); S2IO_PARM_INT(vlan_tag_strip, NO_STRIP_IN_PROMISC); static unsigned int tx_fifo_len[MAX_TX_FIFOS] = - {DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN}; +{DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN}; static unsigned int rx_ring_sz[MAX_RX_RINGS] = - {[0 ...(MAX_RX_RINGS - 1)] = SMALL_BLK_CNT}; +{[0 ...(MAX_RX_RINGS - 1)] = SMALL_BLK_CNT}; static unsigned int rts_frm_len[MAX_RX_RINGS] = - {[0 ...(MAX_RX_RINGS - 1)] = 0 }; +{[0 ...(MAX_RX_RINGS - 1)] = 0 }; module_param_array(tx_fifo_len, uint, NULL, 0); module_param_array(rx_ring_sz, uint, NULL, 0); @@ -527,9 +527,9 @@ static struct pci_device_id s2io_tbl[] __devinitdata = { {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_UNI, PCI_ANY_ID, PCI_ANY_ID}, {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_WIN, - PCI_ANY_ID, PCI_ANY_ID}, - {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_UNI, - PCI_ANY_ID, PCI_ANY_ID}, + PCI_ANY_ID, PCI_ANY_ID}, + {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_UNI, + PCI_ANY_ID, PCI_ANY_ID}, {0,} }; @@ -542,11 +542,11 @@ static struct pci_error_handlers s2io_err_handler = { }; static struct pci_driver s2io_driver = { - .name = "S2IO", - .id_table = s2io_tbl, - .probe = s2io_init_nic, - .remove = __devexit_p(s2io_rem_nic), - .err_handler = &s2io_err_handler, + .name = "S2IO", + .id_table = s2io_tbl, + .probe = s2io_init_nic, + .remove = __devexit_p(s2io_rem_nic), + .err_handler = &s2io_err_handler, }; /* A simplifier macro used both by init and free shared_mem Fns(). */ @@ -655,7 +655,8 @@ static int init_shared_mem(struct s2io_nic *nic) } if (size > MAX_AVAILABLE_TXDS) { DBG_PRINT(ERR_DBG, "s2io: Requested TxDs too high, "); - DBG_PRINT(ERR_DBG, "Requested: %d, max supported: 8192\n", size); + DBG_PRINT(ERR_DBG, "Requested: %d, max supported: 8192\n", + size); return -EINVAL; } @@ -671,7 +672,7 @@ static int init_shared_mem(struct s2io_nic *nic) DBG_PRINT(ERR_DBG, "s2io: Invalid fifo len (%d)", size); DBG_PRINT(ERR_DBG, "for fifo %d\n", i); DBG_PRINT(ERR_DBG, "s2io: Legal values for fifo len" - "are 2 to 8192\n"); + "are 2 to 8192\n"); return -EINVAL; } } @@ -687,8 +688,7 @@ static int init_shared_mem(struct s2io_nic *nic) fifo->list_info = kzalloc(list_holder_size, GFP_KERNEL); if (!fifo->list_info) { - DBG_PRINT(INFO_DBG, - "Malloc failed for list_info\n"); + DBG_PRINT(INFO_DBG, "Malloc failed for list_info\n"); return -ENOMEM; } mem_allocated += list_holder_size; @@ -715,8 +715,7 @@ static int init_shared_mem(struct s2io_nic *nic) tmp_v = pci_alloc_consistent(nic->pdev, PAGE_SIZE, &tmp_p); if (!tmp_v) { - DBG_PRINT(INFO_DBG, - "pci_alloc_consistent "); + DBG_PRINT(INFO_DBG, "pci_alloc_consistent "); DBG_PRINT(INFO_DBG, "failed for TxDL\n"); return -ENOMEM; } @@ -728,15 +727,17 @@ static int init_shared_mem(struct s2io_nic *nic) if (!tmp_p) { mac_control->zerodma_virt_addr = tmp_v; DBG_PRINT(INIT_DBG, - "%s: Zero DMA address for TxDL. ", dev->name); + "%s: Zero DMA address for TxDL. ", + dev->name); DBG_PRINT(INIT_DBG, - "Virtual address %p\n", tmp_v); + "Virtual address %p\n", tmp_v); tmp_v = pci_alloc_consistent(nic->pdev, - PAGE_SIZE, &tmp_p); + PAGE_SIZE, &tmp_p); if (!tmp_v) { DBG_PRINT(INFO_DBG, - "pci_alloc_consistent "); - DBG_PRINT(INFO_DBG, "failed for TxDL\n"); + "pci_alloc_consistent "); + DBG_PRINT(INFO_DBG, + "failed for TxDL\n"); return -ENOMEM; } mem_allocated += PAGE_SIZE; @@ -746,9 +747,9 @@ static int init_shared_mem(struct s2io_nic *nic) if (l == tx_cfg->fifo_len) break; fifo->list_info[l].list_virt_addr = - tmp_v + (k * lst_size); + tmp_v + (k * lst_size); fifo->list_info[l].list_phy_addr = - tmp_p + (k * lst_size); + tmp_p + (k * lst_size); k++; } } @@ -779,7 +780,7 @@ static int init_shared_mem(struct s2io_nic *nic) } size += rx_cfg->num_rxd; ring->block_count = rx_cfg->num_rxd / - (rxd_count[nic->rxd_mode] + 1 ); + (rxd_count[nic->rxd_mode] + 1); ring->pkt_cnt = rx_cfg->num_rxd - ring->block_count; } if (nic->rxd_mode == RXD_MODE_1) @@ -808,7 +809,7 @@ static int init_shared_mem(struct s2io_nic *nic) int l; rx_blocks = &ring->rx_blocks[j]; - size = SIZE_OF_BLOCK; //size is always page size + size = SIZE_OF_BLOCK; /* size is always page size */ tmp_v_addr = pci_alloc_consistent(nic->pdev, size, &tmp_p_addr); if (tmp_v_addr == NULL) { @@ -832,7 +833,7 @@ static int init_shared_mem(struct s2io_nic *nic) if (!rx_blocks->rxds) return -ENOMEM; mem_allocated += size; - for (l=0; lrxd_mode];l++) { + for (l = 0; l < rxd_count[nic->rxd_mode]; l++) { rx_blocks->rxds[l].virt_addr = rx_blocks->block_virt_addr + (rxd_size[nic->rxd_mode] * l); @@ -849,11 +850,11 @@ static int init_shared_mem(struct s2io_nic *nic) tmp_p_addr = ring->rx_blocks[j].block_dma_addr; tmp_p_addr_next = ring->rx_blocks[next].block_dma_addr; - pre_rxd_blk = (struct RxD_block *) tmp_v_addr; + pre_rxd_blk = (struct RxD_block *)tmp_v_addr; pre_rxd_blk->reserved_2_pNext_RxD_block = - (unsigned long) tmp_v_addr_next; + (unsigned long)tmp_v_addr_next; pre_rxd_blk->pNext_RxD_Blk_physical = - (u64) tmp_p_addr_next; + (u64)tmp_p_addr_next; } } if (nic->rxd_mode == RXD_MODE_3B) { @@ -866,7 +867,7 @@ static int init_shared_mem(struct s2io_nic *nic) struct ring_info *ring = &mac_control->rings[i]; blk_cnt = rx_cfg->num_rxd / - (rxd_count[nic->rxd_mode]+ 1); + (rxd_count[nic->rxd_mode] + 1); size = sizeof(struct buffAdd *) * blk_cnt; ring->ba = kmalloc(size, GFP_KERNEL); if (!ring->ba) @@ -890,18 +891,18 @@ static int init_shared_mem(struct s2io_nic *nic) mem_allocated += size; tmp = (unsigned long)ba->ba_0_org; tmp += ALIGN_SIZE; - tmp &= ~((unsigned long) ALIGN_SIZE); - ba->ba_0 = (void *) tmp; + tmp &= ~((unsigned long)ALIGN_SIZE); + ba->ba_0 = (void *)tmp; size = BUF1_LEN + ALIGN_SIZE; ba->ba_1_org = kmalloc(size, GFP_KERNEL); if (!ba->ba_1_org) return -ENOMEM; mem_allocated += size; - tmp = (unsigned long) ba->ba_1_org; + tmp = (unsigned long)ba->ba_1_org; tmp += ALIGN_SIZE; - tmp &= ~((unsigned long) ALIGN_SIZE); - ba->ba_1 = (void *) tmp; + tmp &= ~((unsigned long)ALIGN_SIZE); + ba->ba_1 = (void *)tmp; k++; } } @@ -910,8 +911,9 @@ static int init_shared_mem(struct s2io_nic *nic) /* Allocation and initialization of Statistics block */ size = sizeof(struct stat_block); - mac_control->stats_mem = pci_alloc_consistent - (nic->pdev, size, &mac_control->stats_mem_phy); + mac_control->stats_mem = + pci_alloc_consistent(nic->pdev, size, + &mac_control->stats_mem_phy); if (!mac_control->stats_mem) { /* @@ -925,10 +927,10 @@ static int init_shared_mem(struct s2io_nic *nic) mac_control->stats_mem_sz = size; tmp_v_addr = mac_control->stats_mem; - mac_control->stats_info = (struct stat_block *) tmp_v_addr; + mac_control->stats_info = (struct stat_block *)tmp_v_addr; memset(tmp_v_addr, 0, size); DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name, - (unsigned long long) tmp_p_addr); + (unsigned long long)tmp_p_addr); mac_control->stats_info->sw_stat.mem_allocated += mem_allocated; return SUCCESS; } @@ -959,7 +961,7 @@ static void free_shared_mem(struct s2io_nic *nic) mac_control = &nic->mac_control; config = &nic->config; - lst_size = (sizeof(struct TxD) * config->max_txds); + lst_size = sizeof(struct TxD) * config->max_txds; lst_per_page = PAGE_SIZE / lst_size; for (i = 0; i < config->tx_fifo_num; i++) { @@ -981,7 +983,7 @@ static void free_shared_mem(struct s2io_nic *nic) fli->list_virt_addr, fli->list_phy_addr); nic->mac_control.stats_info->sw_stat.mem_freed - += PAGE_SIZE; + += PAGE_SIZE; } /* If we got a zero DMA address during allocation, * free the page now @@ -991,16 +993,17 @@ static void free_shared_mem(struct s2io_nic *nic) mac_control->zerodma_virt_addr, (dma_addr_t)0); DBG_PRINT(INIT_DBG, - "%s: Freeing TxDL with zero DMA addr. ", - dev->name); + "%s: Freeing TxDL with zero DMA addr. ", + dev->name); DBG_PRINT(INIT_DBG, "Virtual address %p\n", - mac_control->zerodma_virt_addr); + mac_control->zerodma_virt_addr); nic->mac_control.stats_info->sw_stat.mem_freed - += PAGE_SIZE; + += PAGE_SIZE; } kfree(fifo->list_info); nic->mac_control.stats_info->sw_stat.mem_freed += - (nic->config.tx_cfg[i].fifo_len *sizeof(struct list_info_hold)); + nic->config.tx_cfg[i].fifo_len * + sizeof(struct list_info_hold); } size = SIZE_OF_BLOCK; @@ -1018,7 +1021,7 @@ static void free_shared_mem(struct s2io_nic *nic) nic->mac_control.stats_info->sw_stat.mem_freed += size; kfree(ring->rx_blocks[j].rxds); nic->mac_control.stats_info->sw_stat.mem_freed += - ( sizeof(struct rxd_info)* rxd_count[nic->rxd_mode]); + sizeof(struct rxd_info) * rxd_count[nic->rxd_mode]; } } @@ -1038,20 +1041,20 @@ static void free_shared_mem(struct s2io_nic *nic) struct buffAdd *ba = &ring->ba[j][k]; kfree(ba->ba_0_org); nic->mac_control.stats_info->sw_stat.\ - mem_freed += (BUF0_LEN + ALIGN_SIZE); + mem_freed += (BUF0_LEN + ALIGN_SIZE); kfree(ba->ba_1_org); nic->mac_control.stats_info->sw_stat.\ - mem_freed += (BUF1_LEN + ALIGN_SIZE); + mem_freed += (BUF1_LEN + ALIGN_SIZE); k++; } kfree(ring->ba[j]); nic->mac_control.stats_info->sw_stat.mem_freed += (sizeof(struct buffAdd) * - (rxd_count[nic->rxd_mode] + 1)); + (rxd_count[nic->rxd_mode] + 1)); } kfree(ring->ba); nic->mac_control.stats_info->sw_stat.mem_freed += - (sizeof(struct buffAdd *) * blk_cnt); + (sizeof(struct buffAdd *) * blk_cnt); } } @@ -1089,7 +1092,7 @@ static int s2io_verify_pci_mode(struct s2io_nic *nic) val64 = readq(&bar0->pci_mode); mode = (u8)GET_PCI_MODE(val64); - if ( val64 & PCI_MODE_UNKNOWN_MODE) + if (val64 & PCI_MODE_UNKNOWN_MODE) return -1; /* Unknown PCI mode */ return mode; } @@ -1124,50 +1127,47 @@ static int s2io_print_pci_mode(struct s2io_nic *nic) val64 = readq(&bar0->pci_mode); mode = (u8)GET_PCI_MODE(val64); - if ( val64 & PCI_MODE_UNKNOWN_MODE) + if (val64 & PCI_MODE_UNKNOWN_MODE) return -1; /* Unknown PCI mode */ config->bus_speed = bus_speed[mode]; if (s2io_on_nec_bridge(nic->pdev)) { DBG_PRINT(ERR_DBG, "%s: Device is on PCI-E bus\n", - nic->dev->name); + nic->dev->name); return mode; } - if (val64 & PCI_MODE_32_BITS) { - DBG_PRINT(ERR_DBG, "%s: Device is on 32 bit ", nic->dev->name); - } else { - DBG_PRINT(ERR_DBG, "%s: Device is on 64 bit ", nic->dev->name); - } + DBG_PRINT(ERR_DBG, "%s: Device is on %d bit ", + nic->dev->name, val64 & PCI_MODE_32_BITS ? 32 : 64); - switch(mode) { - case PCI_MODE_PCI_33: - DBG_PRINT(ERR_DBG, "33MHz PCI bus\n"); - break; - case PCI_MODE_PCI_66: - DBG_PRINT(ERR_DBG, "66MHz PCI bus\n"); - break; - case PCI_MODE_PCIX_M1_66: - DBG_PRINT(ERR_DBG, "66MHz PCIX(M1) bus\n"); - break; - case PCI_MODE_PCIX_M1_100: - DBG_PRINT(ERR_DBG, "100MHz PCIX(M1) bus\n"); - break; - case PCI_MODE_PCIX_M1_133: - DBG_PRINT(ERR_DBG, "133MHz PCIX(M1) bus\n"); - break; - case PCI_MODE_PCIX_M2_66: - DBG_PRINT(ERR_DBG, "133MHz PCIX(M2) bus\n"); - break; - case PCI_MODE_PCIX_M2_100: - DBG_PRINT(ERR_DBG, "200MHz PCIX(M2) bus\n"); - break; - case PCI_MODE_PCIX_M2_133: - DBG_PRINT(ERR_DBG, "266MHz PCIX(M2) bus\n"); - break; - default: - return -1; /* Unsupported bus speed */ + switch (mode) { + case PCI_MODE_PCI_33: + DBG_PRINT(ERR_DBG, "33MHz PCI bus\n"); + break; + case PCI_MODE_PCI_66: + DBG_PRINT(ERR_DBG, "66MHz PCI bus\n"); + break; + case PCI_MODE_PCIX_M1_66: + DBG_PRINT(ERR_DBG, "66MHz PCIX(M1) bus\n"); + break; + case PCI_MODE_PCIX_M1_100: + DBG_PRINT(ERR_DBG, "100MHz PCIX(M1) bus\n"); + break; + case PCI_MODE_PCIX_M1_133: + DBG_PRINT(ERR_DBG, "133MHz PCIX(M1) bus\n"); + break; + case PCI_MODE_PCIX_M2_66: + DBG_PRINT(ERR_DBG, "133MHz PCIX(M2) bus\n"); + break; + case PCI_MODE_PCIX_M2_100: + DBG_PRINT(ERR_DBG, "200MHz PCIX(M2) bus\n"); + break; + case PCI_MODE_PCIX_M2_133: + DBG_PRINT(ERR_DBG, "266MHz PCIX(M2) bus\n"); + break; + default: + return -1; /* Unsupported bus speed */ } return mode; @@ -1205,9 +1205,9 @@ static int init_tti(struct s2io_nic *nic, int link) val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078); val64 |= TTI_DATA1_MEM_TX_URNG_A(0xA) | - TTI_DATA1_MEM_TX_URNG_B(0x10) | - TTI_DATA1_MEM_TX_URNG_C(0x30) | - TTI_DATA1_MEM_TX_TIMER_AC_EN; + TTI_DATA1_MEM_TX_URNG_B(0x10) | + TTI_DATA1_MEM_TX_URNG_C(0x30) | + TTI_DATA1_MEM_TX_TIMER_AC_EN; if (i == 0) if (use_continuous_tx_intrs && (link == LINK_UP)) val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN; @@ -1220,11 +1220,11 @@ static int init_tti(struct s2io_nic *nic, int link) TTI_DATA2_MEM_TX_UFC_D(0x300); } else { if ((nic->config.tx_steering_type == - TX_DEFAULT_STEERING) && - (config->tx_fifo_num > 1) && - (i >= nic->udp_fifo_idx) && - (i < (nic->udp_fifo_idx + - nic->total_udp_fifos))) + TX_DEFAULT_STEERING) && + (config->tx_fifo_num > 1) && + (i >= nic->udp_fifo_idx) && + (i < (nic->udp_fifo_idx + + nic->total_udp_fifos))) val64 = TTI_DATA2_MEM_TX_UFC_A(0x50) | TTI_DATA2_MEM_TX_UFC_B(0x80) | TTI_DATA2_MEM_TX_UFC_C(0x100) | @@ -1238,12 +1238,14 @@ static int init_tti(struct s2io_nic *nic, int link) writeq(val64, &bar0->tti_data2_mem); - val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD | - TTI_CMD_MEM_OFFSET(i); + val64 = TTI_CMD_MEM_WE | + TTI_CMD_MEM_STROBE_NEW_CMD | + TTI_CMD_MEM_OFFSET(i); writeq(val64, &bar0->tti_command_mem); if (wait_for_cmd_complete(&bar0->tti_command_mem, - TTI_CMD_MEM_STROBE_NEW_CMD, S2IO_BIT_RESET) != SUCCESS) + TTI_CMD_MEM_STROBE_NEW_CMD, + S2IO_BIT_RESET) != SUCCESS) return FAILURE; } @@ -1277,8 +1279,8 @@ static int init_nic(struct s2io_nic *nic) config = &nic->config; /* to set the swapper controle on the card */ - if(s2io_set_swapper(nic)) { - DBG_PRINT(ERR_DBG,"ERROR: Setting Swapper failed\n"); + if (s2io_set_swapper(nic)) { + DBG_PRINT(ERR_DBG, "ERROR: Setting Swapper failed\n"); return -EIO; } @@ -1317,7 +1319,7 @@ static int init_nic(struct s2io_nic *nic) val64 = readq(&bar0->mac_cfg); val64 |= MAC_RMAC_BCAST_ENABLE; writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); - writel((u32) val64, add); + writel((u32)val64, add); writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); writel((u32) (val64 >> 32), (add + 4)); @@ -1354,7 +1356,6 @@ static int init_nic(struct s2io_nic *nic) writeq(val64, &bar0->tx_fifo_partition_2); writeq(val64, &bar0->tx_fifo_partition_3); - for (i = 0, j = 0; i < config->tx_fifo_num; i++) { struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; @@ -1397,21 +1398,22 @@ static int init_nic(struct s2io_nic *nic) * Disable 4 PCCs for Xena1, 2 and 3 as per H/W bug * SXE-008 TRANSMIT DMA ARBITRATION ISSUE. */ - if ((nic->device_type == XFRAME_I_DEVICE) && - (nic->pdev->revision < 4)) + if ((nic->device_type == XFRAME_I_DEVICE) && (nic->pdev->revision < 4)) writeq(PCC_ENABLE_FOUR, &bar0->pcc_enable); val64 = readq(&bar0->tx_fifo_partition_0); DBG_PRINT(INIT_DBG, "Fifo partition at: 0x%p is: 0x%llx\n", - &bar0->tx_fifo_partition_0, (unsigned long long) val64); + &bar0->tx_fifo_partition_0, (unsigned long long)val64); /* * Initialization of Tx_PA_CONFIG register to ignore packet * integrity checking. */ val64 = readq(&bar0->tx_pa_cfg); - val64 |= TX_PA_CFG_IGNORE_FRM_ERR | TX_PA_CFG_IGNORE_SNAP_OUI | - TX_PA_CFG_IGNORE_LLC_CTRL | TX_PA_CFG_IGNORE_L2_ERR; + val64 |= TX_PA_CFG_IGNORE_FRM_ERR | + TX_PA_CFG_IGNORE_SNAP_OUI | + TX_PA_CFG_IGNORE_LLC_CTRL | + TX_PA_CFG_IGNORE_L2_ERR; writeq(val64, &bar0->tx_pa_cfg); /* Rx DMA intialization. */ @@ -1703,7 +1705,7 @@ static int init_nic(struct s2io_nic *nic) */ if (rts_frm_len[i] != 0) { writeq(MAC_RTS_FRM_LEN_SET(rts_frm_len[i]), - &bar0->rts_frm_len_n[i]); + &bar0->rts_frm_len_n[i]); } } @@ -1711,7 +1713,7 @@ static int init_nic(struct s2io_nic *nic) for (i = 0; i < 64; i++) { if (rts_ds_steer(nic, i, 0) == FAILURE) { DBG_PRINT(ERR_DBG, "%s: failed rts ds steering", - dev->name); + dev->name); DBG_PRINT(ERR_DBG, "set on codepoint %d\n", i); return -ENODEV; } @@ -1730,7 +1732,7 @@ static int init_nic(struct s2io_nic *nic) * bandwidth utilization. */ val64 = MAC_TX_LINK_UTIL_VAL(tmac_util_period) | - MAC_RX_LINK_UTIL_VAL(rmac_util_period); + MAC_RX_LINK_UTIL_VAL(rmac_util_period); writeq(val64, &bar0->mac_link_util); /* @@ -1753,24 +1755,26 @@ static int init_nic(struct s2io_nic *nic) } else val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF); val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) | - RTI_DATA1_MEM_RX_URNG_B(0x10) | - RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN; + RTI_DATA1_MEM_RX_URNG_B(0x10) | + RTI_DATA1_MEM_RX_URNG_C(0x30) | + RTI_DATA1_MEM_RX_TIMER_AC_EN; writeq(val64, &bar0->rti_data1_mem); val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) | RTI_DATA2_MEM_RX_UFC_B(0x2) ; if (nic->config.intr_type == MSI_X) - val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \ - RTI_DATA2_MEM_RX_UFC_D(0x40)); + val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | + RTI_DATA2_MEM_RX_UFC_D(0x40)); else - val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \ - RTI_DATA2_MEM_RX_UFC_D(0x80)); + val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | + RTI_DATA2_MEM_RX_UFC_D(0x80)); writeq(val64, &bar0->rti_data2_mem); for (i = 0; i < config->rx_ring_num; i++) { - val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD - | RTI_CMD_MEM_OFFSET(i); + val64 = RTI_CMD_MEM_WE | + RTI_CMD_MEM_STROBE_NEW_CMD | + RTI_CMD_MEM_OFFSET(i); writeq(val64, &bar0->rti_command_mem); /* @@ -1843,19 +1847,17 @@ static int init_nic(struct s2io_nic *nic) */ val64 = 0; for (i = 0; i < 4; i++) { - val64 |= - (((u64) 0xFF00 | nic->mac_control. - mc_pause_threshold_q0q3) - << (i * 2 * 8)); + val64 |= (((u64)0xFF00 | + nic->mac_control.mc_pause_threshold_q0q3) + << (i * 2 * 8)); } writeq(val64, &bar0->mc_pause_thresh_q0q3); val64 = 0; for (i = 0; i < 4; i++) { - val64 |= - (((u64) 0xFF00 | nic->mac_control. - mc_pause_threshold_q4q7) - << (i * 2 * 8)); + val64 |= (((u64)0xFF00 | + nic->mac_control.mc_pause_threshold_q4q7) + << (i * 2 * 8)); } writeq(val64, &bar0->mc_pause_thresh_q4q7); @@ -1918,10 +1920,10 @@ static void do_s2io_write_bits(u64 value, int flag, void __iomem *addr) temp64 = readq(addr); - if(flag == ENABLE_INTRS) - temp64 &= ~((u64) value); + if (flag == ENABLE_INTRS) + temp64 &= ~((u64)value); else - temp64 |= ((u64) value); + temp64 |= ((u64)value); writeq(temp64, addr); } @@ -1933,124 +1935,125 @@ static void en_dis_err_alarms(struct s2io_nic *nic, u16 mask, int flag) writeq(DISABLE_ALL_INTRS, &bar0->general_int_mask); if (mask & TX_DMA_INTR) { - gen_int_mask |= TXDMA_INT_M; do_s2io_write_bits(TXDMA_TDA_INT | TXDMA_PFC_INT | - TXDMA_PCC_INT | TXDMA_TTI_INT | - TXDMA_LSO_INT | TXDMA_TPA_INT | - TXDMA_SM_INT, flag, &bar0->txdma_int_mask); + TXDMA_PCC_INT | TXDMA_TTI_INT | + TXDMA_LSO_INT | TXDMA_TPA_INT | + TXDMA_SM_INT, flag, &bar0->txdma_int_mask); do_s2io_write_bits(PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM | - PFC_MISC_0_ERR | PFC_MISC_1_ERR | - PFC_PCIX_ERR | PFC_ECC_SG_ERR, flag, - &bar0->pfc_err_mask); + PFC_MISC_0_ERR | PFC_MISC_1_ERR | + PFC_PCIX_ERR | PFC_ECC_SG_ERR, flag, + &bar0->pfc_err_mask); do_s2io_write_bits(TDA_Fn_ECC_DB_ERR | TDA_SM0_ERR_ALARM | - TDA_SM1_ERR_ALARM | TDA_Fn_ECC_SG_ERR | - TDA_PCIX_ERR, flag, &bar0->tda_err_mask); + TDA_SM1_ERR_ALARM | TDA_Fn_ECC_SG_ERR | + TDA_PCIX_ERR, flag, &bar0->tda_err_mask); do_s2io_write_bits(PCC_FB_ECC_DB_ERR | PCC_TXB_ECC_DB_ERR | - PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM | - PCC_N_SERR | PCC_6_COF_OV_ERR | - PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR | - PCC_7_LSO_OV_ERR | PCC_FB_ECC_SG_ERR | - PCC_TXB_ECC_SG_ERR, flag, &bar0->pcc_err_mask); + PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM | + PCC_N_SERR | PCC_6_COF_OV_ERR | + PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR | + PCC_7_LSO_OV_ERR | PCC_FB_ECC_SG_ERR | + PCC_TXB_ECC_SG_ERR, + flag, &bar0->pcc_err_mask); do_s2io_write_bits(TTI_SM_ERR_ALARM | TTI_ECC_SG_ERR | - TTI_ECC_DB_ERR, flag, &bar0->tti_err_mask); + TTI_ECC_DB_ERR, flag, &bar0->tti_err_mask); do_s2io_write_bits(LSO6_ABORT | LSO7_ABORT | - LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM | - LSO6_SEND_OFLOW | LSO7_SEND_OFLOW, - flag, &bar0->lso_err_mask); + LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM | + LSO6_SEND_OFLOW | LSO7_SEND_OFLOW, + flag, &bar0->lso_err_mask); do_s2io_write_bits(TPA_SM_ERR_ALARM | TPA_TX_FRM_DROP, - flag, &bar0->tpa_err_mask); + flag, &bar0->tpa_err_mask); do_s2io_write_bits(SM_SM_ERR_ALARM, flag, &bar0->sm_err_mask); - } if (mask & TX_MAC_INTR) { gen_int_mask |= TXMAC_INT_M; do_s2io_write_bits(MAC_INT_STATUS_TMAC_INT, flag, - &bar0->mac_int_mask); + &bar0->mac_int_mask); do_s2io_write_bits(TMAC_TX_BUF_OVRN | TMAC_TX_SM_ERR | - TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR | - TMAC_DESC_ECC_SG_ERR | TMAC_DESC_ECC_DB_ERR, - flag, &bar0->mac_tmac_err_mask); + TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR | + TMAC_DESC_ECC_SG_ERR | TMAC_DESC_ECC_DB_ERR, + flag, &bar0->mac_tmac_err_mask); } if (mask & TX_XGXS_INTR) { gen_int_mask |= TXXGXS_INT_M; do_s2io_write_bits(XGXS_INT_STATUS_TXGXS, flag, - &bar0->xgxs_int_mask); + &bar0->xgxs_int_mask); do_s2io_write_bits(TXGXS_ESTORE_UFLOW | TXGXS_TX_SM_ERR | - TXGXS_ECC_SG_ERR | TXGXS_ECC_DB_ERR, - flag, &bar0->xgxs_txgxs_err_mask); + TXGXS_ECC_SG_ERR | TXGXS_ECC_DB_ERR, + flag, &bar0->xgxs_txgxs_err_mask); } if (mask & RX_DMA_INTR) { gen_int_mask |= RXDMA_INT_M; do_s2io_write_bits(RXDMA_INT_RC_INT_M | RXDMA_INT_RPA_INT_M | - RXDMA_INT_RDA_INT_M | RXDMA_INT_RTI_INT_M, - flag, &bar0->rxdma_int_mask); + RXDMA_INT_RDA_INT_M | RXDMA_INT_RTI_INT_M, + flag, &bar0->rxdma_int_mask); do_s2io_write_bits(RC_PRCn_ECC_DB_ERR | RC_FTC_ECC_DB_ERR | - RC_PRCn_SM_ERR_ALARM | RC_FTC_SM_ERR_ALARM | - RC_PRCn_ECC_SG_ERR | RC_FTC_ECC_SG_ERR | - RC_RDA_FAIL_WR_Rn, flag, &bar0->rc_err_mask); + RC_PRCn_SM_ERR_ALARM | RC_FTC_SM_ERR_ALARM | + RC_PRCn_ECC_SG_ERR | RC_FTC_ECC_SG_ERR | + RC_RDA_FAIL_WR_Rn, flag, &bar0->rc_err_mask); do_s2io_write_bits(PRC_PCI_AB_RD_Rn | PRC_PCI_AB_WR_Rn | - PRC_PCI_AB_F_WR_Rn | PRC_PCI_DP_RD_Rn | - PRC_PCI_DP_WR_Rn | PRC_PCI_DP_F_WR_Rn, flag, - &bar0->prc_pcix_err_mask); + PRC_PCI_AB_F_WR_Rn | PRC_PCI_DP_RD_Rn | + PRC_PCI_DP_WR_Rn | PRC_PCI_DP_F_WR_Rn, flag, + &bar0->prc_pcix_err_mask); do_s2io_write_bits(RPA_SM_ERR_ALARM | RPA_CREDIT_ERR | - RPA_ECC_SG_ERR | RPA_ECC_DB_ERR, flag, - &bar0->rpa_err_mask); + RPA_ECC_SG_ERR | RPA_ECC_DB_ERR, flag, + &bar0->rpa_err_mask); do_s2io_write_bits(RDA_RXDn_ECC_DB_ERR | RDA_FRM_ECC_DB_N_AERR | - RDA_SM1_ERR_ALARM | RDA_SM0_ERR_ALARM | - RDA_RXD_ECC_DB_SERR | RDA_RXDn_ECC_SG_ERR | - RDA_FRM_ECC_SG_ERR | RDA_MISC_ERR|RDA_PCIX_ERR, - flag, &bar0->rda_err_mask); + RDA_SM1_ERR_ALARM | RDA_SM0_ERR_ALARM | + RDA_RXD_ECC_DB_SERR | RDA_RXDn_ECC_SG_ERR | + RDA_FRM_ECC_SG_ERR | + RDA_MISC_ERR|RDA_PCIX_ERR, + flag, &bar0->rda_err_mask); do_s2io_write_bits(RTI_SM_ERR_ALARM | - RTI_ECC_SG_ERR | RTI_ECC_DB_ERR, - flag, &bar0->rti_err_mask); + RTI_ECC_SG_ERR | RTI_ECC_DB_ERR, + flag, &bar0->rti_err_mask); } if (mask & RX_MAC_INTR) { gen_int_mask |= RXMAC_INT_M; do_s2io_write_bits(MAC_INT_STATUS_RMAC_INT, flag, - &bar0->mac_int_mask); - interruptible = RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR | - RMAC_UNUSED_INT | RMAC_SINGLE_ECC_ERR | - RMAC_DOUBLE_ECC_ERR; + &bar0->mac_int_mask); + interruptible = (RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR | + RMAC_UNUSED_INT | RMAC_SINGLE_ECC_ERR | + RMAC_DOUBLE_ECC_ERR); if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) interruptible |= RMAC_LINK_STATE_CHANGE_INT; do_s2io_write_bits(interruptible, - flag, &bar0->mac_rmac_err_mask); + flag, &bar0->mac_rmac_err_mask); } - if (mask & RX_XGXS_INTR) - { + if (mask & RX_XGXS_INTR) { gen_int_mask |= RXXGXS_INT_M; do_s2io_write_bits(XGXS_INT_STATUS_RXGXS, flag, - &bar0->xgxs_int_mask); + &bar0->xgxs_int_mask); do_s2io_write_bits(RXGXS_ESTORE_OFLOW | RXGXS_RX_SM_ERR, flag, - &bar0->xgxs_rxgxs_err_mask); + &bar0->xgxs_rxgxs_err_mask); } if (mask & MC_INTR) { gen_int_mask |= MC_INT_M; - do_s2io_write_bits(MC_INT_MASK_MC_INT, flag, &bar0->mc_int_mask); + do_s2io_write_bits(MC_INT_MASK_MC_INT, + flag, &bar0->mc_int_mask); do_s2io_write_bits(MC_ERR_REG_SM_ERR | MC_ERR_REG_ECC_ALL_SNG | - MC_ERR_REG_ECC_ALL_DBL | PLL_LOCK_N, flag, - &bar0->mc_err_mask); + MC_ERR_REG_ECC_ALL_DBL | PLL_LOCK_N, flag, + &bar0->mc_err_mask); } nic->general_int_mask = gen_int_mask; /* Remove this line when alarm interrupts are enabled */ nic->general_int_mask = 0; } + /** * en_dis_able_nic_intrs - Enable or Disable the interrupts * @nic: device private variable, @@ -2082,11 +2085,11 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) * TODO */ if (s2io_link_fault_indication(nic) == - LINK_UP_DOWN_INTERRUPT ) { + LINK_UP_DOWN_INTERRUPT) { do_s2io_write_bits(PIC_INT_GPIO, flag, - &bar0->pic_int_mask); + &bar0->pic_int_mask); do_s2io_write_bits(GPIO_INT_MASK_LINK_UP, flag, - &bar0->gpio_int_mask); + &bar0->gpio_int_mask); } else writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask); } else if (flag == DISABLE_INTRS) { @@ -2133,7 +2136,7 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) temp64 = readq(&bar0->general_int_mask); if (flag == ENABLE_INTRS) - temp64 &= ~((u64) intr_mask); + temp64 &= ~((u64)intr_mask); else temp64 = DISABLE_ALL_INTRS; writeq(temp64, &bar0->general_int_mask); @@ -2198,7 +2201,7 @@ static int verify_xena_quiescence(struct s2io_nic *sp) return 0; } if (!(val64 & ADAPTER_STATUS_RDMA_READY)) { - DBG_PRINT(ERR_DBG, "%s", "RDMA is not ready!"); + DBG_PRINT(ERR_DBG, "%s", "RDMA is not ready!"); return 0; } if (!(val64 & ADAPTER_STATUS_PFC_READY)) { @@ -2232,13 +2235,13 @@ static int verify_xena_quiescence(struct s2io_nic *sp) * not be asserted. */ if (!(val64 & ADAPTER_STATUS_P_PLL_LOCK) && - sp->device_type == XFRAME_II_DEVICE && mode != - PCI_MODE_PCI_33) { + sp->device_type == XFRAME_II_DEVICE && + mode != PCI_MODE_PCI_33) { DBG_PRINT(ERR_DBG, "%s", "P_PLL is not locked!"); return 0; } if (!((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == - ADAPTER_STATUS_RC_PRC_QUIESCENT)) { + ADAPTER_STATUS_RC_PRC_QUIESCENT)) { DBG_PRINT(ERR_DBG, "%s", "RC_PRC is not QUIESCENT!"); return 0; } @@ -2253,7 +2256,7 @@ static int verify_xena_quiescence(struct s2io_nic *sp) * */ -static void fix_mac_address(struct s2io_nic * sp) +static void fix_mac_address(struct s2io_nic *sp) { struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64; @@ -2295,7 +2298,7 @@ static int start_nic(struct s2io_nic *nic) for (i = 0; i < config->rx_ring_num; i++) { struct ring_info *ring = &mac_control->rings[i]; - writeq((u64) ring->rx_blocks[0].block_dma_addr, + writeq((u64)ring->rx_blocks[0].block_dma_addr, &bar0->prc_rxd0_n[i]); val64 = readq(&bar0->prc_ctrl_n[i]); @@ -2349,7 +2352,7 @@ static int start_nic(struct s2io_nic *nic) if (!verify_xena_quiescence(nic)) { DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name); DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n", - (unsigned long long) val64); + (unsigned long long)val64); return FAILURE; } @@ -2389,8 +2392,8 @@ static int start_nic(struct s2io_nic *nic) /** * s2io_txdl_getskb - Get the skb from txdl, unmap and return skb */ -static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, struct \ - TxD *txdlp, int get_off) +static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, + struct TxD *txdlp, int get_off) { struct s2io_nic *nic = fifo_data->nic; struct sk_buff *skb; @@ -2399,22 +2402,18 @@ static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, struct \ txds = txdlp; if (txds->Host_Control == (u64)(long)fifo_data->ufo_in_band_v) { - pci_unmap_single(nic->pdev, (dma_addr_t) - txds->Buffer_Pointer, sizeof(u64), - PCI_DMA_TODEVICE); + pci_unmap_single(nic->pdev, (dma_addr_t)txds->Buffer_Pointer, + sizeof(u64), PCI_DMA_TODEVICE); txds++; } - skb = (struct sk_buff *) ((unsigned long) - txds->Host_Control); + skb = (struct sk_buff *)((unsigned long)txds->Host_Control); if (!skb) { memset(txdlp, 0, (sizeof(struct TxD) * fifo_data->max_txds)); return NULL; } - pci_unmap_single(nic->pdev, (dma_addr_t) - txds->Buffer_Pointer, - skb->len - skb->data_len, - PCI_DMA_TODEVICE); + pci_unmap_single(nic->pdev, (dma_addr_t)txds->Buffer_Pointer, + skb->len - skb->data_len, PCI_DMA_TODEVICE); frg_cnt = skb_shinfo(skb)->nr_frags; if (frg_cnt) { txds++; @@ -2422,13 +2421,13 @@ static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, struct \ skb_frag_t *frag = &skb_shinfo(skb)->frags[j]; if (!txds->Buffer_Pointer) break; - pci_unmap_page(nic->pdev, (dma_addr_t) - txds->Buffer_Pointer, + pci_unmap_page(nic->pdev, + (dma_addr_t)txds->Buffer_Pointer, frag->size, PCI_DMA_TODEVICE); } } - memset(txdlp,0, (sizeof(struct TxD) * fifo_data->max_txds)); - return(skb); + memset(txdlp, 0, (sizeof(struct TxD) * fifo_data->max_txds)); + return skb; } /** @@ -2437,7 +2436,7 @@ static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, struct \ * Description: * Free all queued Tx buffers. * Return Value: void -*/ + */ static void free_tx_buffers(struct s2io_nic *nic) { @@ -2533,7 +2532,7 @@ static void stop_nic(struct s2io_nic *nic) * SUCCESS on success or an appropriate -ve value on failure. */ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, - int from_card_up) + int from_card_up) { struct sk_buff *skb; struct RxD_t *rxdp; @@ -2564,17 +2563,16 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, rxd_index += (block_no * ring->rxd_count); if ((block_no == block_no1) && - (off == ring->rx_curr_get_info.offset) && - (rxdp->Host_Control)) { - DBG_PRINT(INTR_DBG, "%s: Get and Put", - ring->dev->name); + (off == ring->rx_curr_get_info.offset) && + (rxdp->Host_Control)) { + DBG_PRINT(INTR_DBG, "%s: Get and Put", ring->dev->name); DBG_PRINT(INTR_DBG, " info equated\n"); goto end; } if (off && (off == ring->rxd_count)) { ring->rx_curr_put_info.block_index++; if (ring->rx_curr_put_info.block_index == - ring->block_count) + ring->block_count) ring->rx_curr_put_info.block_index = 0; block_no = ring->rx_curr_put_info.block_index; off = 0; @@ -2586,14 +2584,15 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, } if ((rxdp->Control_1 & RXD_OWN_XENA) && - ((ring->rxd_mode == RXD_MODE_3B) && - (rxdp->Control_2 & s2BIT(0)))) { + ((ring->rxd_mode == RXD_MODE_3B) && + (rxdp->Control_2 & s2BIT(0)))) { ring->rx_curr_put_info.offset = off; goto end; } /* calculate size of skb based on ring mode */ - size = ring->mtu + HEADER_ETHERNET_II_802_3_SIZE + - HEADER_802_2_SIZE + HEADER_SNAP_SIZE; + size = ring->mtu + + HEADER_ETHERNET_II_802_3_SIZE + + HEADER_802_2_SIZE + HEADER_SNAP_SIZE; if (ring->rxd_mode == RXD_MODE_1) size += NET_IP_ALIGN; else @@ -2601,7 +2600,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, /* allocate skb */ skb = dev_alloc_skb(size); - if(!skb) { + if (!skb) { DBG_PRINT(INFO_DBG, "%s: Out of ", ring->dev->name); DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n"); if (first_rxdp) { @@ -2616,19 +2615,20 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, if (ring->rxd_mode == RXD_MODE_1) { /* 1 buffer mode - normal operation mode */ - rxdp1 = (struct RxD1*)rxdp; + rxdp1 = (struct RxD1 *)rxdp; memset(rxdp, 0, sizeof(struct RxD1)); skb_reserve(skb, NET_IP_ALIGN); - rxdp1->Buffer0_ptr = pci_map_single - (ring->pdev, skb->data, size - NET_IP_ALIGN, - PCI_DMA_FROMDEVICE); + rxdp1->Buffer0_ptr = + pci_map_single(ring->pdev, skb->data, + size - NET_IP_ALIGN, + PCI_DMA_FROMDEVICE); if (pci_dma_mapping_error(nic->pdev, - rxdp1->Buffer0_ptr)) + rxdp1->Buffer0_ptr)) goto pci_map_failed; rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN); - rxdp->Host_Control = (unsigned long) (skb); + rxdp->Host_Control = (unsigned long)skb; } else if (ring->rxd_mode == RXD_MODE_3B) { /* * 2 buffer mode - @@ -2636,7 +2636,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, * byte aligned receive buffers. */ - rxdp3 = (struct RxD3*)rxdp; + rxdp3 = (struct RxD3 *)rxdp; /* save buffer pointers to avoid frequent dma mapping */ Buffer0_ptr = rxdp3->Buffer0_ptr; Buffer1_ptr = rxdp3->Buffer1_ptr; @@ -2647,7 +2647,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, ba = &ring->ba[block_no][off]; skb_reserve(skb, BUF0_LEN); - tmp = (u64)(unsigned long) skb->data; + tmp = (u64)(unsigned long)skb->data; tmp += ALIGN_SIZE; tmp &= ~ALIGN_SIZE; skb->data = (void *) (unsigned long)tmp; @@ -2655,15 +2655,17 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, if (from_card_up) { rxdp3->Buffer0_ptr = - pci_map_single(ring->pdev, ba->ba_0, - BUF0_LEN, PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(nic->pdev, - rxdp3->Buffer0_ptr)) + pci_map_single(ring->pdev, ba->ba_0, + BUF0_LEN, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(nic->pdev, + rxdp3->Buffer0_ptr)) goto pci_map_failed; } else pci_dma_sync_single_for_device(ring->pdev, - (dma_addr_t) rxdp3->Buffer0_ptr, - BUF0_LEN, PCI_DMA_FROMDEVICE); + (dma_addr_t)rxdp3->Buffer0_ptr, + BUF0_LEN, + PCI_DMA_FROMDEVICE); rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN); if (ring->rxd_mode == RXD_MODE_3B) { @@ -2673,34 +2675,35 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, * Buffer2 will have L3/L4 header plus * L4 payload */ - rxdp3->Buffer2_ptr = pci_map_single - (ring->pdev, skb->data, ring->mtu + 4, - PCI_DMA_FROMDEVICE); + rxdp3->Buffer2_ptr = pci_map_single(ring->pdev, + skb->data, + ring->mtu + 4, + PCI_DMA_FROMDEVICE); if (pci_dma_mapping_error(nic->pdev, - rxdp3->Buffer2_ptr)) + rxdp3->Buffer2_ptr)) goto pci_map_failed; if (from_card_up) { rxdp3->Buffer1_ptr = pci_map_single(ring->pdev, - ba->ba_1, BUF1_LEN, - PCI_DMA_FROMDEVICE); + ba->ba_1, + BUF1_LEN, + PCI_DMA_FROMDEVICE); if (pci_dma_mapping_error(nic->pdev, - rxdp3->Buffer1_ptr)) { - pci_unmap_single - (ring->pdev, - (dma_addr_t)(unsigned long) - skb->data, - ring->mtu + 4, - PCI_DMA_FROMDEVICE); + rxdp3->Buffer1_ptr)) { + pci_unmap_single(ring->pdev, + (dma_addr_t)(unsigned long) + skb->data, + ring->mtu + 4, + PCI_DMA_FROMDEVICE); goto pci_map_failed; } } rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1); rxdp->Control_2 |= SET_BUFFER2_SIZE_3 - (ring->mtu + 4); + (ring->mtu + 4); } rxdp->Control_2 |= s2BIT(0); rxdp->Host_Control = (unsigned long) (skb); @@ -2724,7 +2727,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, alloc_tab++; } - end: +end: /* Transfer ownership of first descriptor to adapter just before * exiting. Before that, use memory barrier so that ownership * and other fields are seen by adapter correctly. @@ -2735,6 +2738,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, } return SUCCESS; + pci_map_failed: stats->pci_map_fail_cnt++; stats->mem_freed += skb->truesize; @@ -2756,38 +2760,34 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk) mac_control = &sp->mac_control; for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) { rxdp = mac_control->rings[ring_no]. - rx_blocks[blk].rxds[j].virt_addr; - skb = (struct sk_buff *) - ((unsigned long) rxdp->Host_Control); - if (!skb) { + rx_blocks[blk].rxds[j].virt_addr; + skb = (struct sk_buff *)((unsigned long)rxdp->Host_Control); + if (!skb) continue; - } if (sp->rxd_mode == RXD_MODE_1) { - rxdp1 = (struct RxD1*)rxdp; - pci_unmap_single(sp->pdev, (dma_addr_t) - rxdp1->Buffer0_ptr, - dev->mtu + - HEADER_ETHERNET_II_802_3_SIZE - + HEADER_802_2_SIZE + - HEADER_SNAP_SIZE, - PCI_DMA_FROMDEVICE); + rxdp1 = (struct RxD1 *)rxdp; + pci_unmap_single(sp->pdev, + (dma_addr_t)rxdp1->Buffer0_ptr, + dev->mtu + + HEADER_ETHERNET_II_802_3_SIZE + + HEADER_802_2_SIZE + HEADER_SNAP_SIZE, + PCI_DMA_FROMDEVICE); memset(rxdp, 0, sizeof(struct RxD1)); - } else if(sp->rxd_mode == RXD_MODE_3B) { - rxdp3 = (struct RxD3*)rxdp; - ba = &mac_control->rings[ring_no]. - ba[blk][j]; - pci_unmap_single(sp->pdev, (dma_addr_t) - rxdp3->Buffer0_ptr, - BUF0_LEN, - PCI_DMA_FROMDEVICE); - pci_unmap_single(sp->pdev, (dma_addr_t) - rxdp3->Buffer1_ptr, - BUF1_LEN, - PCI_DMA_FROMDEVICE); - pci_unmap_single(sp->pdev, (dma_addr_t) - rxdp3->Buffer2_ptr, - dev->mtu + 4, - PCI_DMA_FROMDEVICE); + } else if (sp->rxd_mode == RXD_MODE_3B) { + rxdp3 = (struct RxD3 *)rxdp; + ba = &mac_control->rings[ring_no].ba[blk][j]; + pci_unmap_single(sp->pdev, + (dma_addr_t)rxdp3->Buffer0_ptr, + BUF0_LEN, + PCI_DMA_FROMDEVICE); + pci_unmap_single(sp->pdev, + (dma_addr_t)rxdp3->Buffer1_ptr, + BUF1_LEN, + PCI_DMA_FROMDEVICE); + pci_unmap_single(sp->pdev, + (dma_addr_t)rxdp3->Buffer2_ptr, + dev->mtu + 4, + PCI_DMA_FROMDEVICE); memset(rxdp, 0, sizeof(struct RxD3)); } sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize; @@ -2819,7 +2819,7 @@ static void free_rx_buffers(struct s2io_nic *sp) struct ring_info *ring = &mac_control->rings[i]; for (blk = 0; blk < rx_ring_sz[i]; blk++) - free_rxd_blk(sp,i,blk); + free_rxd_blk(sp, i, blk); ring->rx_curr_put_info.block_index = 0; ring->rx_curr_get_info.block_index = 0; @@ -2886,6 +2886,7 @@ static int s2io_poll_msix(struct napi_struct *napi, int budget) } return pkts_processed; } + static int s2io_poll_inta(struct napi_struct *napi, int budget) { struct s2io_nic *nic = container_of(napi, struct s2io_nic, napi); @@ -2999,8 +3000,8 @@ static int rx_intr_handler(struct ring_info *ring_data, int budget) struct sk_buff *skb; int pkt_cnt = 0, napi_pkts = 0; int i; - struct RxD1* rxdp1; - struct RxD3* rxdp3; + struct RxD1 *rxdp1; + struct RxD3 *rxdp3; get_info = ring_data->rx_curr_get_info; get_block = get_info.block_index; @@ -3016,10 +3017,10 @@ static int rx_intr_handler(struct ring_info *ring_data, int budget) if ((get_block == put_block) && (get_info.offset + 1) == put_info.offset) { DBG_PRINT(INTR_DBG, "%s: Ring Full\n", - ring_data->dev->name); + ring_data->dev->name); break; } - skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control); + skb = (struct sk_buff *)((unsigned long)rxdp->Host_Control); if (skb == NULL) { DBG_PRINT(ERR_DBG, "%s: The skb is ", ring_data->dev->name); @@ -3027,30 +3028,31 @@ static int rx_intr_handler(struct ring_info *ring_data, int budget) return 0; } if (ring_data->rxd_mode == RXD_MODE_1) { - rxdp1 = (struct RxD1*)rxdp; + rxdp1 = (struct RxD1 *)rxdp; pci_unmap_single(ring_data->pdev, (dma_addr_t) - rxdp1->Buffer0_ptr, - ring_data->mtu + - HEADER_ETHERNET_II_802_3_SIZE + - HEADER_802_2_SIZE + - HEADER_SNAP_SIZE, - PCI_DMA_FROMDEVICE); + rxdp1->Buffer0_ptr, + ring_data->mtu + + HEADER_ETHERNET_II_802_3_SIZE + + HEADER_802_2_SIZE + + HEADER_SNAP_SIZE, + PCI_DMA_FROMDEVICE); } else if (ring_data->rxd_mode == RXD_MODE_3B) { - rxdp3 = (struct RxD3*)rxdp; - pci_dma_sync_single_for_cpu(ring_data->pdev, (dma_addr_t) - rxdp3->Buffer0_ptr, - BUF0_LEN, PCI_DMA_FROMDEVICE); - pci_unmap_single(ring_data->pdev, (dma_addr_t) - rxdp3->Buffer2_ptr, - ring_data->mtu + 4, - PCI_DMA_FROMDEVICE); + rxdp3 = (struct RxD3 *)rxdp; + pci_dma_sync_single_for_cpu(ring_data->pdev, + (dma_addr_t)rxdp3->Buffer0_ptr, + BUF0_LEN, + PCI_DMA_FROMDEVICE); + pci_unmap_single(ring_data->pdev, + (dma_addr_t)rxdp3->Buffer2_ptr, + ring_data->mtu + 4, + PCI_DMA_FROMDEVICE); } prefetch(skb->data); rx_osm_handler(ring_data, rxdp); get_info.offset++; ring_data->rx_curr_get_info.offset = get_info.offset; rxdp = ring_data->rx_blocks[get_block]. - rxds[get_info.offset].virt_addr; + rxds[get_info.offset].virt_addr; if (get_info.offset == rxd_count[ring_data->rxd_mode]) { get_info.offset = 0; ring_data->rx_curr_get_info.offset = get_info.offset; @@ -3073,7 +3075,7 @@ static int rx_intr_handler(struct ring_info *ring_data, int budget) } if (ring_data->lro) { /* Clear all LRO sessions before exiting */ - for (i=0; ilro0_n[i]; if (lro->in_use) { update_L3L4_header(ring_data->nic, lro); @@ -3082,7 +3084,7 @@ static int rx_intr_handler(struct ring_info *ring_data, int budget) } } } - return(napi_pkts); + return napi_pkts; } /** @@ -3108,12 +3110,12 @@ static void tx_intr_handler(struct fifo_info *fifo_data) u8 err_mask; if (!spin_trylock_irqsave(&fifo_data->tx_lock, flags)) - return; + return; get_info = fifo_data->tx_curr_get_info; memcpy(&put_info, &fifo_data->tx_curr_put_info, sizeof(put_info)); - txdlp = (struct TxD *) fifo_data->list_info[get_info.offset]. - list_virt_addr; + txdlp = (struct TxD *) + fifo_data->list_info[get_info.offset].list_virt_addr; while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) && (get_info.offset != put_info.offset) && (txdlp->Host_Control)) { @@ -3123,44 +3125,43 @@ static void tx_intr_handler(struct fifo_info *fifo_data) err = txdlp->Control_1 & TXD_T_CODE; if (err & 0x1) { nic->mac_control.stats_info->sw_stat. - parity_err_cnt++; + parity_err_cnt++; } /* update t_code statistics */ err_mask = err >> 48; - switch(err_mask) { - case 2: - nic->mac_control.stats_info->sw_stat. - tx_buf_abort_cnt++; + switch (err_mask) { + case 2: + nic->mac_control.stats_info->sw_stat. + tx_buf_abort_cnt++; break; - case 3: - nic->mac_control.stats_info->sw_stat. - tx_desc_abort_cnt++; + case 3: + nic->mac_control.stats_info->sw_stat. + tx_desc_abort_cnt++; break; - case 7: - nic->mac_control.stats_info->sw_stat. - tx_parity_err_cnt++; + case 7: + nic->mac_control.stats_info->sw_stat. + tx_parity_err_cnt++; break; - case 10: - nic->mac_control.stats_info->sw_stat. - tx_link_loss_cnt++; + case 10: + nic->mac_control.stats_info->sw_stat. + tx_link_loss_cnt++; break; - case 15: - nic->mac_control.stats_info->sw_stat. - tx_list_proc_err_cnt++; + case 15: + nic->mac_control.stats_info->sw_stat. + tx_list_proc_err_cnt++; break; - } + } } skb = s2io_txdl_getskb(fifo_data, txdlp, get_info.offset); if (skb == NULL) { spin_unlock_irqrestore(&fifo_data->tx_lock, flags); - DBG_PRINT(ERR_DBG, "%s: Null skb ", - __func__); + DBG_PRINT(ERR_DBG, "%s: Null skb ", __func__); DBG_PRINT(ERR_DBG, "in Tx Free Intr\n"); return; } @@ -3174,10 +3175,9 @@ static void tx_intr_handler(struct fifo_info *fifo_data) get_info.offset++; if (get_info.offset == get_info.fifo_len + 1) get_info.offset = 0; - txdlp = (struct TxD *) fifo_data->list_info - [get_info.offset].list_virt_addr; - fifo_data->tx_curr_get_info.offset = - get_info.offset; + txdlp = (struct TxD *) + fifo_data->list_info[get_info.offset].list_virt_addr; + fifo_data->tx_curr_get_info.offset = get_info.offset; } s2io_wake_tx_queue(fifo_data, pkt_cnt, nic->config.multiq); @@ -3195,43 +3195,41 @@ static void tx_intr_handler(struct fifo_info *fifo_data) * This function is used to write values to the MDIO registers * NONE */ -static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev) +static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, + struct net_device *dev) { - u64 val64 = 0x0; + u64 val64; struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; - //address transaction - val64 = val64 | MDIO_MMD_INDX_ADDR(addr) - | MDIO_MMD_DEV_ADDR(mmd_type) - | MDIO_MMS_PRT_ADDR(0x0); + /* address transaction */ + val64 = MDIO_MMD_INDX_ADDR(addr) | + MDIO_MMD_DEV_ADDR(mmd_type) | + MDIO_MMS_PRT_ADDR(0x0); writeq(val64, &bar0->mdio_control); val64 = val64 | MDIO_CTRL_START_TRANS(0xE); writeq(val64, &bar0->mdio_control); udelay(100); - //Data transaction - val64 = 0x0; - val64 = val64 | MDIO_MMD_INDX_ADDR(addr) - | MDIO_MMD_DEV_ADDR(mmd_type) - | MDIO_MMS_PRT_ADDR(0x0) - | MDIO_MDIO_DATA(value) - | MDIO_OP(MDIO_OP_WRITE_TRANS); + /* Data transaction */ + val64 = MDIO_MMD_INDX_ADDR(addr) | + MDIO_MMD_DEV_ADDR(mmd_type) | + MDIO_MMS_PRT_ADDR(0x0) | + MDIO_MDIO_DATA(value) | + MDIO_OP(MDIO_OP_WRITE_TRANS); writeq(val64, &bar0->mdio_control); val64 = val64 | MDIO_CTRL_START_TRANS(0xE); writeq(val64, &bar0->mdio_control); udelay(100); - val64 = 0x0; - val64 = val64 | MDIO_MMD_INDX_ADDR(addr) - | MDIO_MMD_DEV_ADDR(mmd_type) - | MDIO_MMS_PRT_ADDR(0x0) - | MDIO_OP(MDIO_OP_READ_TRANS); + val64 = MDIO_MMD_INDX_ADDR(addr) | + MDIO_MMD_DEV_ADDR(mmd_type) | + MDIO_MMS_PRT_ADDR(0x0) | + MDIO_OP(MDIO_OP_READ_TRANS); writeq(val64, &bar0->mdio_control); val64 = val64 | MDIO_CTRL_START_TRANS(0xE); writeq(val64, &bar0->mdio_control); udelay(100); - } /** @@ -3251,20 +3249,19 @@ static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev) struct XENA_dev_config __iomem *bar0 = sp->bar0; /* address transaction */ - val64 = val64 | MDIO_MMD_INDX_ADDR(addr) - | MDIO_MMD_DEV_ADDR(mmd_type) - | MDIO_MMS_PRT_ADDR(0x0); + val64 = val64 | (MDIO_MMD_INDX_ADDR(addr) + | MDIO_MMD_DEV_ADDR(mmd_type) + | MDIO_MMS_PRT_ADDR(0x0)); writeq(val64, &bar0->mdio_control); val64 = val64 | MDIO_CTRL_START_TRANS(0xE); writeq(val64, &bar0->mdio_control); udelay(100); /* Data transaction */ - val64 = 0x0; - val64 = val64 | MDIO_MMD_INDX_ADDR(addr) - | MDIO_MMD_DEV_ADDR(mmd_type) - | MDIO_MMS_PRT_ADDR(0x0) - | MDIO_OP(MDIO_OP_READ_TRANS); + val64 = MDIO_MMD_INDX_ADDR(addr) | + MDIO_MMD_DEV_ADDR(mmd_type) | + MDIO_MMS_PRT_ADDR(0x0) | + MDIO_OP(MDIO_OP_READ_TRANS); writeq(val64, &bar0->mdio_control); val64 = val64 | MDIO_CTRL_START_TRANS(0xE); writeq(val64, &bar0->mdio_control); @@ -3276,6 +3273,7 @@ static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev) rval64 = rval64 >> 16; return rval64; } + /** * s2io_chk_xpak_counter - Function to check the status of the xpak counters * @counter : couter value to be updated @@ -3286,45 +3284,43 @@ static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev) * NONE */ -static void s2io_chk_xpak_counter(u64 *counter, u64 * regs_stat, u32 index, u16 flag, u16 type) +static void s2io_chk_xpak_counter(u64 *counter, u64 * regs_stat, u32 index, + u16 flag, u16 type) { u64 mask = 0x3; u64 val64; int i; - for(i = 0; i 0) - { + if (flag > 0) { *counter = *counter + 1; val64 = *regs_stat & mask; val64 = val64 >> (index * 0x2); val64 = val64 + 1; - if(val64 == 3) - { - switch(type) - { + if (val64 == 3) { + switch (type) { case 1: DBG_PRINT(ERR_DBG, "Take Xframe NIC out of " "service. Excessive temperatures may " "result in premature transceiver " "failure \n"); - break; + break; case 2: DBG_PRINT(ERR_DBG, "Take Xframe NIC out of " "service Excessive bias currents may " "indicate imminent laser diode " "failure \n"); - break; + break; case 3: DBG_PRINT(ERR_DBG, "Take Xframe NIC out of " "service Excessive laser output " "power may saturate far-end " "receiver\n"); - break; + break; default: - DBG_PRINT(ERR_DBG, "Incorrect XPAK Alarm " - "type \n"); + DBG_PRINT(ERR_DBG, + "Incorrect XPAK Alarm type\n"); } val64 = 0x0; } @@ -3358,16 +3354,14 @@ static void s2io_updt_xpak_counter(struct net_device *dev) addr = MDIO_CTRL1; val64 = 0x0; val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); - if((val64 == 0xFFFF) || (val64 == 0x0000)) - { + if ((val64 == 0xFFFF) || (val64 == 0x0000)) { DBG_PRINT(ERR_DBG, "ERR: MDIO slave access failed - " "Returned %llx\n", (unsigned long long)val64); return; } /* Check for the expected value of control reg 1 */ - if(val64 != MDIO_CTRL1_SPEED10G) - { + if (val64 != MDIO_CTRL1_SPEED10G) { DBG_PRINT(ERR_DBG, "Incorrect value at PMA address 0x0000 - "); DBG_PRINT(ERR_DBG, "Returned: %llx- Expected: 0x%x\n", (unsigned long long)val64, MDIO_CTRL1_SPEED10G); @@ -3387,28 +3381,28 @@ static void s2io_updt_xpak_counter(struct net_device *dev) flag = CHECKBIT(val64, 0x7); type = 1; s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_transceiver_temp_high, - &stat_info->xpak_stat.xpak_regs_stat, - 0x0, flag, type); + &stat_info->xpak_stat.xpak_regs_stat, + 0x0, flag, type); - if(CHECKBIT(val64, 0x6)) + if (CHECKBIT(val64, 0x6)) stat_info->xpak_stat.alarm_transceiver_temp_low++; flag = CHECKBIT(val64, 0x3); type = 2; s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_bias_current_high, - &stat_info->xpak_stat.xpak_regs_stat, - 0x2, flag, type); + &stat_info->xpak_stat.xpak_regs_stat, + 0x2, flag, type); - if(CHECKBIT(val64, 0x2)) + if (CHECKBIT(val64, 0x2)) stat_info->xpak_stat.alarm_laser_bias_current_low++; flag = CHECKBIT(val64, 0x1); type = 3; s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_output_power_high, - &stat_info->xpak_stat.xpak_regs_stat, - 0x4, flag, type); + &stat_info->xpak_stat.xpak_regs_stat, + 0x4, flag, type); - if(CHECKBIT(val64, 0x0)) + if (CHECKBIT(val64, 0x0)) stat_info->xpak_stat.alarm_laser_output_power_low++; /* Reading the Warning flags */ @@ -3416,22 +3410,22 @@ static void s2io_updt_xpak_counter(struct net_device *dev) val64 = 0x0; val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); - if(CHECKBIT(val64, 0x7)) + if (CHECKBIT(val64, 0x7)) stat_info->xpak_stat.warn_transceiver_temp_high++; - if(CHECKBIT(val64, 0x6)) + if (CHECKBIT(val64, 0x6)) stat_info->xpak_stat.warn_transceiver_temp_low++; - if(CHECKBIT(val64, 0x3)) + if (CHECKBIT(val64, 0x3)) stat_info->xpak_stat.warn_laser_bias_current_high++; - if(CHECKBIT(val64, 0x2)) + if (CHECKBIT(val64, 0x2)) stat_info->xpak_stat.warn_laser_bias_current_low++; - if(CHECKBIT(val64, 0x1)) + if (CHECKBIT(val64, 0x1)) stat_info->xpak_stat.warn_laser_output_power_high++; - if(CHECKBIT(val64, 0x0)) + if (CHECKBIT(val64, 0x0)) stat_info->xpak_stat.warn_laser_output_power_low++; } @@ -3447,7 +3441,7 @@ static void s2io_updt_xpak_counter(struct net_device *dev) */ static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit, - int bit_state) + int bit_state) { int ret = FAILURE, cnt = 0, delay = 1; u64 val64; @@ -3469,7 +3463,7 @@ static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit, } } - if(in_interrupt()) + if (in_interrupt()) mdelay(delay); else msleep(delay); @@ -3509,7 +3503,7 @@ static u16 check_pci_device_id(u16 id) * void. */ -static void s2io_reset(struct s2io_nic * sp) +static void s2io_reset(struct s2io_nic *sp) { struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64; @@ -3519,17 +3513,16 @@ static void s2io_reset(struct s2io_nic * sp) unsigned long long up_cnt, down_cnt, up_time, down_time, reset_cnt; unsigned long long mem_alloc_cnt, mem_free_cnt, watchdog_cnt; - DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n", - __func__, sp->dev->name); + DBG_PRINT(INIT_DBG, "%s - Resetting XFrame card %s\n", + __func__, sp->dev->name); /* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */ pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd)); val64 = SW_RESET_ALL; writeq(val64, &bar0->sw_reset); - if (strstr(sp->product_name, "CX4")) { + if (strstr(sp->product_name, "CX4")) msleep(750); - } msleep(250); for (i = 0; i < S2IO_MAX_PCI_CONFIG_SPACE_REINIT; i++) { @@ -3541,9 +3534,8 @@ static void s2io_reset(struct s2io_nic * sp) msleep(200); } - if (check_pci_device_id(val16) == (u16)PCI_ANY_ID) { - DBG_PRINT(ERR_DBG,"%s SW_Reset failed!\n", __func__); - } + if (check_pci_device_id(val16) == (u16)PCI_ANY_ID) + DBG_PRINT(ERR_DBG, "%s SW_Reset failed!\n", __func__); pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, pci_cmd); @@ -3571,7 +3563,7 @@ static void s2io_reset(struct s2io_nic * sp) } /* Reset device statistics maintained by OS */ - memset(&sp->stats, 0, sizeof (struct net_device_stats)); + memset(&sp->stats, 0, sizeof(struct net_device_stats)); up_cnt = sp->mac_control.stats_info->sw_stat.link_up_cnt; down_cnt = sp->mac_control.stats_info->sw_stat.link_down_cnt; @@ -3626,7 +3618,7 @@ static void s2io_reset(struct s2io_nic * sp) * SUCCESS on success and FAILURE on failure. */ -static int s2io_set_swapper(struct s2io_nic * sp) +static int s2io_set_swapper(struct s2io_nic *sp) { struct net_device *dev = sp->dev; struct XENA_dev_config __iomem *bar0 = sp->bar0; @@ -3645,7 +3637,7 @@ static int s2io_set_swapper(struct s2io_nic * sp) 0x4200004242000042ULL, /* FE=0, SE=1 */ 0}; /* FE=0, SE=0 */ - while(i<4) { + while (i < 4) { writeq(value[i], &bar0->swapper_ctrl); val64 = readq(&bar0->pif_rd_swapper_fb); if (val64 == 0x0123456789ABCDEFULL) @@ -3654,9 +3646,9 @@ static int s2io_set_swapper(struct s2io_nic * sp) } if (i == 4) { DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ", - dev->name); + dev->name); DBG_PRINT(ERR_DBG, "feedback read %llx\n", - (unsigned long long) val64); + (unsigned long long)val64); return FAILURE; } valr = value[i]; @@ -3668,22 +3660,22 @@ static int s2io_set_swapper(struct s2io_nic * sp) writeq(valt, &bar0->xmsi_address); val64 = readq(&bar0->xmsi_address); - if(val64 != valt) { + if (val64 != valt) { int i = 0; u64 value[] = { 0x00C3C30000C3C300ULL, /* FE=1, SE=1 */ 0x0081810000818100ULL, /* FE=1, SE=0 */ 0x0042420000424200ULL, /* FE=0, SE=1 */ 0}; /* FE=0, SE=0 */ - while(i<4) { + while (i < 4) { writeq((value[i] | valr), &bar0->swapper_ctrl); writeq(valt, &bar0->xmsi_address); val64 = readq(&bar0->xmsi_address); - if(val64 == valt) + if (val64 == valt) break; i++; } - if(i == 4) { + if (i == 4) { unsigned long long x = val64; DBG_PRINT(ERR_DBG, "Write failed, Xmsi_addr "); DBG_PRINT(ERR_DBG, "reads:0x%llx\n", x); @@ -3693,21 +3685,22 @@ static int s2io_set_swapper(struct s2io_nic * sp) val64 = readq(&bar0->swapper_ctrl); val64 &= 0xFFFF000000000000ULL; -#ifdef __BIG_ENDIAN +#ifdef __BIG_ENDIAN /* * The device by default set to a big endian format, so a * big endian driver need not set anything. */ val64 |= (SWAPPER_CTRL_TXP_FE | - SWAPPER_CTRL_TXP_SE | - SWAPPER_CTRL_TXD_R_FE | - SWAPPER_CTRL_TXD_W_FE | - SWAPPER_CTRL_TXF_R_FE | - SWAPPER_CTRL_RXD_R_FE | - SWAPPER_CTRL_RXD_W_FE | - SWAPPER_CTRL_RXF_W_FE | - SWAPPER_CTRL_XMSI_FE | - SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); + SWAPPER_CTRL_TXP_SE | + SWAPPER_CTRL_TXD_R_FE | + SWAPPER_CTRL_TXD_W_FE | + SWAPPER_CTRL_TXF_R_FE | + SWAPPER_CTRL_RXD_R_FE | + SWAPPER_CTRL_RXD_W_FE | + SWAPPER_CTRL_RXF_W_FE | + SWAPPER_CTRL_XMSI_FE | + SWAPPER_CTRL_STATS_FE | + SWAPPER_CTRL_STATS_SE); if (sp->config.intr_type == INTA) val64 |= SWAPPER_CTRL_XMSI_SE; writeq(val64, &bar0->swapper_ctrl); @@ -3718,19 +3711,20 @@ static int s2io_set_swapper(struct s2io_nic * sp) * we want to set. */ val64 |= (SWAPPER_CTRL_TXP_FE | - SWAPPER_CTRL_TXP_SE | - SWAPPER_CTRL_TXD_R_FE | - SWAPPER_CTRL_TXD_R_SE | - SWAPPER_CTRL_TXD_W_FE | - SWAPPER_CTRL_TXD_W_SE | - SWAPPER_CTRL_TXF_R_FE | - SWAPPER_CTRL_RXD_R_FE | - SWAPPER_CTRL_RXD_R_SE | - SWAPPER_CTRL_RXD_W_FE | - SWAPPER_CTRL_RXD_W_SE | - SWAPPER_CTRL_RXF_W_FE | - SWAPPER_CTRL_XMSI_FE | - SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); + SWAPPER_CTRL_TXP_SE | + SWAPPER_CTRL_TXD_R_FE | + SWAPPER_CTRL_TXD_R_SE | + SWAPPER_CTRL_TXD_W_FE | + SWAPPER_CTRL_TXD_W_SE | + SWAPPER_CTRL_TXF_R_FE | + SWAPPER_CTRL_RXD_R_FE | + SWAPPER_CTRL_RXD_R_SE | + SWAPPER_CTRL_RXD_W_FE | + SWAPPER_CTRL_RXD_W_SE | + SWAPPER_CTRL_RXF_W_FE | + SWAPPER_CTRL_XMSI_FE | + SWAPPER_CTRL_STATS_FE | + SWAPPER_CTRL_STATS_SE); if (sp->config.intr_type == INTA) val64 |= SWAPPER_CTRL_XMSI_SE; writeq(val64, &bar0->swapper_ctrl); @@ -3747,7 +3741,7 @@ static int s2io_set_swapper(struct s2io_nic * sp) DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ", dev->name); DBG_PRINT(ERR_DBG, "feedback read %llx\n", - (unsigned long long) val64); + (unsigned long long)val64); return FAILURE; } @@ -3766,7 +3760,7 @@ static int wait_for_msix_trans(struct s2io_nic *nic, int i) break; mdelay(1); cnt++; - } while(cnt < 5); + } while (cnt < 5); if (cnt == 5) { DBG_PRINT(ERR_DBG, "XMSI # %d Access failed\n", i); ret = 1; @@ -3781,12 +3775,11 @@ static void restore_xmsi_data(struct s2io_nic *nic) u64 val64; int i, msix_index; - if (nic->device_type == XFRAME_I_DEVICE) return; - for (i=0; i < MAX_REQUESTED_MSI_X; i++) { - msix_index = (i) ? ((i-1) * 8 + 1): 0; + for (i = 0; i < MAX_REQUESTED_MSI_X; i++) { + msix_index = (i) ? ((i-1) * 8 + 1) : 0; writeq(nic->msix_info[i].addr, &bar0->xmsi_address); writeq(nic->msix_info[i].data, &bar0->xmsi_data); val64 = (s2BIT(7) | s2BIT(15) | vBIT(msix_index, 26, 6)); @@ -3808,8 +3801,8 @@ static void store_xmsi_data(struct s2io_nic *nic) return; /* Store and display */ - for (i=0; i < MAX_REQUESTED_MSI_X; i++) { - msix_index = (i) ? ((i-1) * 8 + 1): 0; + for (i = 0; i < MAX_REQUESTED_MSI_X; i++) { + msix_index = (i) ? ((i-1) * 8 + 1) : 0; val64 = (s2BIT(15) | vBIT(msix_index, 26, 6)); writeq(val64, &bar0->xmsi_access); if (wait_for_msix_trans(nic, msix_index)) { @@ -3836,8 +3829,8 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) size = nic->num_entries * sizeof(struct msix_entry); nic->entries = kzalloc(size, GFP_KERNEL); if (!nic->entries) { - DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", \ - __func__); + DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", + __func__); nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; return -ENOMEM; } @@ -3847,7 +3840,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) nic->s2io_entries = kzalloc(size, GFP_KERNEL); if (!nic->s2io_entries) { DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", - __func__); + __func__); nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; kfree(nic->entries); nic->mac_control.stats_info->sw_stat.mem_freed @@ -3926,14 +3919,14 @@ static int s2io_test_msi(struct s2io_nic *sp) u64 val64, saved64; err = request_irq(sp->entries[1].vector, s2io_test_intr, 0, - sp->name, sp); + sp->name, sp); if (err) { DBG_PRINT(ERR_DBG, "%s: PCI %s: cannot assign irq %d\n", - sp->dev->name, pci_name(pdev), pdev->irq); + sp->dev->name, pci_name(pdev), pdev->irq); return err; } - init_waitqueue_head (&sp->msi_wait); + init_waitqueue_head(&sp->msi_wait); sp->msi_detected = 0; saved64 = val64 = readq(&bar0->scheduled_int_ctrl); @@ -3947,8 +3940,8 @@ static int s2io_test_msi(struct s2io_nic *sp) if (!sp->msi_detected) { /* MSI(X) test failed, go back to INTx mode */ DBG_PRINT(ERR_DBG, "%s: PCI %s: No interrupt was generated " - "using MSI(X) during test\n", sp->dev->name, - pci_name(pdev)); + "using MSI(X) during test\n", sp->dev->name, + pci_name(pdev)); err = -EOPNOTSUPP; } @@ -3966,8 +3959,7 @@ static void remove_msix_isr(struct s2io_nic *sp) u16 msi_control; for (i = 0; i < sp->num_entries; i++) { - if (sp->s2io_entries[i].in_use == - MSIX_REGISTERED_SUCCESS) { + if (sp->s2io_entries[i].in_use == MSIX_REGISTERED_SUCCESS) { int vector = sp->entries[i].vector; void *arg = sp->s2io_entries[i].arg; free_irq(vector, arg); @@ -4043,12 +4035,12 @@ hw_init_failed: if (sp->entries) { kfree(sp->entries); sp->mac_control.stats_info->sw_stat.mem_freed - += (sp->num_entries * sizeof(struct msix_entry)); + += (sp->num_entries * sizeof(struct msix_entry)); } if (sp->s2io_entries) { kfree(sp->s2io_entries); sp->mac_control.stats_info->sw_stat.mem_freed - += (sp->num_entries * sizeof(struct s2io_msix_entry)); + += (sp->num_entries * sizeof(struct s2io_msix_entry)); } } return err; @@ -4075,8 +4067,8 @@ static int s2io_close(struct net_device *dev) int offset; /* Return if the device is already closed * - * Can happen when s2io_card_up failed in change_mtu * - */ + * Can happen when s2io_card_up failed in change_mtu * + */ if (!is_s2io_card_up(sp)) return 0; @@ -4152,20 +4144,20 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) if ((ip->frag_off & htons(IP_OFFSET|IP_MF)) == 0) { th = (struct tcphdr *)(((unsigned char *)ip) + - ip->ihl*4); + ip->ihl*4); if (ip->protocol == IPPROTO_TCP) { queue_len = sp->total_tcp_fifos; queue = (ntohs(th->source) + - ntohs(th->dest)) & - sp->fifo_selector[queue_len - 1]; + ntohs(th->dest)) & + sp->fifo_selector[queue_len - 1]; if (queue >= queue_len) queue = queue_len - 1; } else if (ip->protocol == IPPROTO_UDP) { queue_len = sp->total_udp_fifos; queue = (ntohs(th->source) + - ntohs(th->dest)) & - sp->fifo_selector[queue_len - 1]; + ntohs(th->dest)) & + sp->fifo_selector[queue_len - 1]; if (queue >= queue_len) queue = queue_len - 1; queue += sp->udp_fifo_idx; @@ -4178,7 +4170,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) } else if (sp->config.tx_steering_type == TX_PRIORITY_STEERING) /* get fifo number based on skb->priority value */ queue = config->fifo_mapping - [skb->priority & (MAX_TX_FIFOS - 1)]; + [skb->priority & (MAX_TX_FIFOS - 1)]; fifo = &mac_control->fifos[queue]; if (do_spin_lock) @@ -4200,14 +4192,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) } } - put_off = (u16) fifo->tx_curr_put_info.offset; - get_off = (u16) fifo->tx_curr_get_info.offset; - txdp = (struct TxD *) fifo->list_info[put_off].list_virt_addr; + put_off = (u16)fifo->tx_curr_put_info.offset; + get_off = (u16)fifo->tx_curr_get_info.offset; + txdp = (struct TxD *)fifo->list_info[put_off].list_virt_addr; queue_len = fifo->tx_curr_put_info.fifo_len + 1; /* Avoid "put" pointer going beyond "get" pointer */ if (txdp->Host_Control || - ((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) { + ((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) { DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n"); s2io_stop_tx_queue(sp, fifo->fifo_no); dev_kfree_skb(skb); @@ -4221,9 +4213,9 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb)); } if (skb->ip_summed == CHECKSUM_PARTIAL) { - txdp->Control_2 |= - (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN | - TXD_TX_CKO_UDP_EN); + txdp->Control_2 |= (TXD_TX_CKO_IPV4_EN | + TXD_TX_CKO_TCP_EN | + TXD_TX_CKO_UDP_EN); } txdp->Control_1 |= TXD_GATHER_CODE_FIRST; txdp->Control_1 |= TXD_LIST_OWN_XENA; @@ -4248,26 +4240,27 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) #ifdef __BIG_ENDIAN /* both variants do cpu_to_be64(be32_to_cpu(...)) */ fifo->ufo_in_band_v[put_off] = - (__force u64)skb_shinfo(skb)->ip6_frag_id; + (__force u64)skb_shinfo(skb)->ip6_frag_id; #else fifo->ufo_in_band_v[put_off] = - (__force u64)skb_shinfo(skb)->ip6_frag_id << 32; + (__force u64)skb_shinfo(skb)->ip6_frag_id << 32; #endif txdp->Host_Control = (unsigned long)fifo->ufo_in_band_v; txdp->Buffer_Pointer = pci_map_single(sp->pdev, - fifo->ufo_in_band_v, - sizeof(u64), PCI_DMA_TODEVICE); + fifo->ufo_in_band_v, + sizeof(u64), + PCI_DMA_TODEVICE); if (pci_dma_mapping_error(sp->pdev, txdp->Buffer_Pointer)) goto pci_map_failed; txdp++; } - txdp->Buffer_Pointer = pci_map_single - (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE); + txdp->Buffer_Pointer = pci_map_single(sp->pdev, skb->data, + frg_len, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(sp->pdev, txdp->Buffer_Pointer)) goto pci_map_failed; - txdp->Host_Control = (unsigned long) skb; + txdp->Host_Control = (unsigned long)skb; txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len); if (offload_type == SKB_GSO_UDP) txdp->Control_1 |= TXD_UFO_EN; @@ -4280,9 +4273,10 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) if (!frag->size) continue; txdp++; - txdp->Buffer_Pointer = (u64) pci_map_page - (sp->pdev, frag->page, frag->page_offset, - frag->size, PCI_DMA_TODEVICE); + txdp->Buffer_Pointer = (u64)pci_map_page(sp->pdev, frag->page, + frag->page_offset, + frag->size, + PCI_DMA_TODEVICE); txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size); if (offload_type == SKB_GSO_UDP) txdp->Control_1 |= TXD_UFO_EN; @@ -4422,17 +4416,16 @@ static void s2io_txpic_intr_handle(struct s2io_nic *sp) * This is unstable state so clear both up/down * interrupt and adapter to re-evaluate the link state. */ - val64 |= GPIO_INT_REG_LINK_DOWN; + val64 |= GPIO_INT_REG_LINK_DOWN; val64 |= GPIO_INT_REG_LINK_UP; writeq(val64, &bar0->gpio_int_reg); val64 = readq(&bar0->gpio_int_mask); val64 &= ~(GPIO_INT_MASK_LINK_UP | GPIO_INT_MASK_LINK_DOWN); writeq(val64, &bar0->gpio_int_mask); - } - else if (val64 & GPIO_INT_REG_LINK_UP) { + } else if (val64 & GPIO_INT_REG_LINK_UP) { val64 = readq(&bar0->adapter_status); - /* Enable Adapter */ + /* Enable Adapter */ val64 = readq(&bar0->adapter_control); val64 |= ADAPTER_CNTL_EN; writeq(val64, &bar0->adapter_control); @@ -4451,7 +4444,7 @@ static void s2io_txpic_intr_handle(struct s2io_nic *sp) val64 |= GPIO_INT_MASK_LINK_UP; writeq(val64, &bar0->gpio_int_mask); - }else if (val64 & GPIO_INT_REG_LINK_DOWN) { + } else if (val64 & GPIO_INT_REG_LINK_DOWN) { val64 = readq(&bar0->adapter_status); s2io_link(sp, LINK_DOWN); /* Link is down so unmaks link up interrupt */ @@ -4462,7 +4455,7 @@ static void s2io_txpic_intr_handle(struct s2io_nic *sp) /* turn off LED */ val64 = readq(&bar0->adapter_control); - val64 = val64 &(~ADAPTER_LED_ON); + val64 = val64 & (~ADAPTER_LED_ON); writeq(val64, &bar0->adapter_control); } } @@ -4479,12 +4472,12 @@ static void s2io_txpic_intr_handle(struct s2io_nic *sp) * 1 - if alarm bit set * 0 - if alarm bit is not set */ -static int do_s2io_chk_alarm_bit(u64 value, void __iomem * addr, - unsigned long long *cnt) +static int do_s2io_chk_alarm_bit(u64 value, void __iomem *addr, + unsigned long long *cnt) { u64 val64; val64 = readq(addr); - if ( val64 & value ) { + if (val64 & value) { writeq(val64, addr); (*cnt)++; return 1; @@ -4501,12 +4494,12 @@ static int do_s2io_chk_alarm_bit(u64 value, void __iomem * addr, * Return Value: * NONE */ -static void s2io_handle_errors(void * dev_id) +static void s2io_handle_errors(void *dev_id) { - struct net_device *dev = (struct net_device *) dev_id; + struct net_device *dev = (struct net_device *)dev_id; struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; - u64 temp64 = 0,val64=0; + u64 temp64 = 0, val64 = 0; int i = 0; struct swStat *sw_stat = &sp->mac_control.stats_info->sw_stat; @@ -4519,10 +4512,10 @@ static void s2io_handle_errors(void * dev_id) return; memset(&sw_stat->ring_full_cnt, 0, - sizeof(sw_stat->ring_full_cnt)); + sizeof(sw_stat->ring_full_cnt)); /* Handling the XPAK counters update */ - if(stats->xpak_timer_count < 72000) { + if (stats->xpak_timer_count < 72000) { /* waiting for an hour */ stats->xpak_timer_count++; } else { @@ -4541,191 +4534,227 @@ static void s2io_handle_errors(void * dev_id) /* In case of a serious error, the device will be Reset. */ if (do_s2io_chk_alarm_bit(SERR_SOURCE_ANY, &bar0->serr_source, - &sw_stat->serious_err_cnt)) + &sw_stat->serious_err_cnt)) goto reset; /* Check for data parity error */ if (do_s2io_chk_alarm_bit(GPIO_INT_REG_DP_ERR_INT, &bar0->gpio_int_reg, - &sw_stat->parity_err_cnt)) + &sw_stat->parity_err_cnt)) goto reset; /* Check for ring full counter */ if (sp->device_type == XFRAME_II_DEVICE) { val64 = readq(&bar0->ring_bump_counter1); - for (i=0; i<4; i++) { - temp64 = ( val64 & vBIT(0xFFFF,(i*16),16)); + for (i = 0; i < 4; i++) { + temp64 = (val64 & vBIT(0xFFFF, (i*16), 16)); temp64 >>= 64 - ((i+1)*16); sw_stat->ring_full_cnt[i] += temp64; } val64 = readq(&bar0->ring_bump_counter2); - for (i=0; i<4; i++) { - temp64 = ( val64 & vBIT(0xFFFF,(i*16),16)); + for (i = 0; i < 4; i++) { + temp64 = (val64 & vBIT(0xFFFF, (i*16), 16)); temp64 >>= 64 - ((i+1)*16); - sw_stat->ring_full_cnt[i+4] += temp64; + sw_stat->ring_full_cnt[i+4] += temp64; } } val64 = readq(&bar0->txdma_int_status); /*check for pfc_err*/ if (val64 & TXDMA_PFC_INT) { - if (do_s2io_chk_alarm_bit(PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM| - PFC_MISC_0_ERR | PFC_MISC_1_ERR| - PFC_PCIX_ERR, &bar0->pfc_err_reg, - &sw_stat->pfc_err_cnt)) + if (do_s2io_chk_alarm_bit(PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM | + PFC_MISC_0_ERR | PFC_MISC_1_ERR | + PFC_PCIX_ERR, + &bar0->pfc_err_reg, + &sw_stat->pfc_err_cnt)) goto reset; - do_s2io_chk_alarm_bit(PFC_ECC_SG_ERR, &bar0->pfc_err_reg, - &sw_stat->pfc_err_cnt); + do_s2io_chk_alarm_bit(PFC_ECC_SG_ERR, + &bar0->pfc_err_reg, + &sw_stat->pfc_err_cnt); } /*check for tda_err*/ if (val64 & TXDMA_TDA_INT) { - if(do_s2io_chk_alarm_bit(TDA_Fn_ECC_DB_ERR | TDA_SM0_ERR_ALARM | - TDA_SM1_ERR_ALARM, &bar0->tda_err_reg, - &sw_stat->tda_err_cnt)) + if (do_s2io_chk_alarm_bit(TDA_Fn_ECC_DB_ERR | + TDA_SM0_ERR_ALARM | + TDA_SM1_ERR_ALARM, + &bar0->tda_err_reg, + &sw_stat->tda_err_cnt)) goto reset; do_s2io_chk_alarm_bit(TDA_Fn_ECC_SG_ERR | TDA_PCIX_ERR, - &bar0->tda_err_reg, &sw_stat->tda_err_cnt); + &bar0->tda_err_reg, + &sw_stat->tda_err_cnt); } /*check for pcc_err*/ if (val64 & TXDMA_PCC_INT) { - if (do_s2io_chk_alarm_bit(PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM - | PCC_N_SERR | PCC_6_COF_OV_ERR - | PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR - | PCC_7_LSO_OV_ERR | PCC_FB_ECC_DB_ERR - | PCC_TXB_ECC_DB_ERR, &bar0->pcc_err_reg, - &sw_stat->pcc_err_cnt)) + if (do_s2io_chk_alarm_bit(PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM | + PCC_N_SERR | PCC_6_COF_OV_ERR | + PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR | + PCC_7_LSO_OV_ERR | PCC_FB_ECC_DB_ERR | + PCC_TXB_ECC_DB_ERR, + &bar0->pcc_err_reg, + &sw_stat->pcc_err_cnt)) goto reset; do_s2io_chk_alarm_bit(PCC_FB_ECC_SG_ERR | PCC_TXB_ECC_SG_ERR, - &bar0->pcc_err_reg, &sw_stat->pcc_err_cnt); + &bar0->pcc_err_reg, + &sw_stat->pcc_err_cnt); } /*check for tti_err*/ if (val64 & TXDMA_TTI_INT) { - if (do_s2io_chk_alarm_bit(TTI_SM_ERR_ALARM, &bar0->tti_err_reg, - &sw_stat->tti_err_cnt)) + if (do_s2io_chk_alarm_bit(TTI_SM_ERR_ALARM, + &bar0->tti_err_reg, + &sw_stat->tti_err_cnt)) goto reset; do_s2io_chk_alarm_bit(TTI_ECC_SG_ERR | TTI_ECC_DB_ERR, - &bar0->tti_err_reg, &sw_stat->tti_err_cnt); + &bar0->tti_err_reg, + &sw_stat->tti_err_cnt); } /*check for lso_err*/ if (val64 & TXDMA_LSO_INT) { - if (do_s2io_chk_alarm_bit(LSO6_ABORT | LSO7_ABORT - | LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM, - &bar0->lso_err_reg, &sw_stat->lso_err_cnt)) + if (do_s2io_chk_alarm_bit(LSO6_ABORT | LSO7_ABORT | + LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM, + &bar0->lso_err_reg, + &sw_stat->lso_err_cnt)) goto reset; do_s2io_chk_alarm_bit(LSO6_SEND_OFLOW | LSO7_SEND_OFLOW, - &bar0->lso_err_reg, &sw_stat->lso_err_cnt); + &bar0->lso_err_reg, + &sw_stat->lso_err_cnt); } /*check for tpa_err*/ if (val64 & TXDMA_TPA_INT) { - if (do_s2io_chk_alarm_bit(TPA_SM_ERR_ALARM, &bar0->tpa_err_reg, - &sw_stat->tpa_err_cnt)) + if (do_s2io_chk_alarm_bit(TPA_SM_ERR_ALARM, + &bar0->tpa_err_reg, + &sw_stat->tpa_err_cnt)) goto reset; - do_s2io_chk_alarm_bit(TPA_TX_FRM_DROP, &bar0->tpa_err_reg, - &sw_stat->tpa_err_cnt); + do_s2io_chk_alarm_bit(TPA_TX_FRM_DROP, + &bar0->tpa_err_reg, + &sw_stat->tpa_err_cnt); } /*check for sm_err*/ if (val64 & TXDMA_SM_INT) { - if (do_s2io_chk_alarm_bit(SM_SM_ERR_ALARM, &bar0->sm_err_reg, - &sw_stat->sm_err_cnt)) + if (do_s2io_chk_alarm_bit(SM_SM_ERR_ALARM, + &bar0->sm_err_reg, + &sw_stat->sm_err_cnt)) goto reset; } val64 = readq(&bar0->mac_int_status); if (val64 & MAC_INT_STATUS_TMAC_INT) { if (do_s2io_chk_alarm_bit(TMAC_TX_BUF_OVRN | TMAC_TX_SM_ERR, - &bar0->mac_tmac_err_reg, - &sw_stat->mac_tmac_err_cnt)) + &bar0->mac_tmac_err_reg, + &sw_stat->mac_tmac_err_cnt)) goto reset; - do_s2io_chk_alarm_bit(TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR - | TMAC_DESC_ECC_SG_ERR | TMAC_DESC_ECC_DB_ERR, - &bar0->mac_tmac_err_reg, - &sw_stat->mac_tmac_err_cnt); + do_s2io_chk_alarm_bit(TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR | + TMAC_DESC_ECC_SG_ERR | + TMAC_DESC_ECC_DB_ERR, + &bar0->mac_tmac_err_reg, + &sw_stat->mac_tmac_err_cnt); } val64 = readq(&bar0->xgxs_int_status); if (val64 & XGXS_INT_STATUS_TXGXS) { if (do_s2io_chk_alarm_bit(TXGXS_ESTORE_UFLOW | TXGXS_TX_SM_ERR, - &bar0->xgxs_txgxs_err_reg, - &sw_stat->xgxs_txgxs_err_cnt)) + &bar0->xgxs_txgxs_err_reg, + &sw_stat->xgxs_txgxs_err_cnt)) goto reset; do_s2io_chk_alarm_bit(TXGXS_ECC_SG_ERR | TXGXS_ECC_DB_ERR, - &bar0->xgxs_txgxs_err_reg, - &sw_stat->xgxs_txgxs_err_cnt); + &bar0->xgxs_txgxs_err_reg, + &sw_stat->xgxs_txgxs_err_cnt); } val64 = readq(&bar0->rxdma_int_status); if (val64 & RXDMA_INT_RC_INT_M) { - if (do_s2io_chk_alarm_bit(RC_PRCn_ECC_DB_ERR | RC_FTC_ECC_DB_ERR - | RC_PRCn_SM_ERR_ALARM |RC_FTC_SM_ERR_ALARM, - &bar0->rc_err_reg, &sw_stat->rc_err_cnt)) + if (do_s2io_chk_alarm_bit(RC_PRCn_ECC_DB_ERR | + RC_FTC_ECC_DB_ERR | + RC_PRCn_SM_ERR_ALARM | + RC_FTC_SM_ERR_ALARM, + &bar0->rc_err_reg, + &sw_stat->rc_err_cnt)) goto reset; - do_s2io_chk_alarm_bit(RC_PRCn_ECC_SG_ERR | RC_FTC_ECC_SG_ERR - | RC_RDA_FAIL_WR_Rn, &bar0->rc_err_reg, - &sw_stat->rc_err_cnt); - if (do_s2io_chk_alarm_bit(PRC_PCI_AB_RD_Rn | PRC_PCI_AB_WR_Rn - | PRC_PCI_AB_F_WR_Rn, &bar0->prc_pcix_err_reg, - &sw_stat->prc_pcix_err_cnt)) + do_s2io_chk_alarm_bit(RC_PRCn_ECC_SG_ERR | + RC_FTC_ECC_SG_ERR | + RC_RDA_FAIL_WR_Rn, &bar0->rc_err_reg, + &sw_stat->rc_err_cnt); + if (do_s2io_chk_alarm_bit(PRC_PCI_AB_RD_Rn | + PRC_PCI_AB_WR_Rn | + PRC_PCI_AB_F_WR_Rn, + &bar0->prc_pcix_err_reg, + &sw_stat->prc_pcix_err_cnt)) goto reset; - do_s2io_chk_alarm_bit(PRC_PCI_DP_RD_Rn | PRC_PCI_DP_WR_Rn - | PRC_PCI_DP_F_WR_Rn, &bar0->prc_pcix_err_reg, - &sw_stat->prc_pcix_err_cnt); + do_s2io_chk_alarm_bit(PRC_PCI_DP_RD_Rn | + PRC_PCI_DP_WR_Rn | + PRC_PCI_DP_F_WR_Rn, + &bar0->prc_pcix_err_reg, + &sw_stat->prc_pcix_err_cnt); } if (val64 & RXDMA_INT_RPA_INT_M) { if (do_s2io_chk_alarm_bit(RPA_SM_ERR_ALARM | RPA_CREDIT_ERR, - &bar0->rpa_err_reg, &sw_stat->rpa_err_cnt)) + &bar0->rpa_err_reg, + &sw_stat->rpa_err_cnt)) goto reset; do_s2io_chk_alarm_bit(RPA_ECC_SG_ERR | RPA_ECC_DB_ERR, - &bar0->rpa_err_reg, &sw_stat->rpa_err_cnt); + &bar0->rpa_err_reg, + &sw_stat->rpa_err_cnt); } if (val64 & RXDMA_INT_RDA_INT_M) { - if (do_s2io_chk_alarm_bit(RDA_RXDn_ECC_DB_ERR - | RDA_FRM_ECC_DB_N_AERR | RDA_SM1_ERR_ALARM - | RDA_SM0_ERR_ALARM | RDA_RXD_ECC_DB_SERR, - &bar0->rda_err_reg, &sw_stat->rda_err_cnt)) + if (do_s2io_chk_alarm_bit(RDA_RXDn_ECC_DB_ERR | + RDA_FRM_ECC_DB_N_AERR | + RDA_SM1_ERR_ALARM | + RDA_SM0_ERR_ALARM | + RDA_RXD_ECC_DB_SERR, + &bar0->rda_err_reg, + &sw_stat->rda_err_cnt)) goto reset; - do_s2io_chk_alarm_bit(RDA_RXDn_ECC_SG_ERR | RDA_FRM_ECC_SG_ERR - | RDA_MISC_ERR | RDA_PCIX_ERR, - &bar0->rda_err_reg, &sw_stat->rda_err_cnt); + do_s2io_chk_alarm_bit(RDA_RXDn_ECC_SG_ERR | + RDA_FRM_ECC_SG_ERR | + RDA_MISC_ERR | + RDA_PCIX_ERR, + &bar0->rda_err_reg, + &sw_stat->rda_err_cnt); } if (val64 & RXDMA_INT_RTI_INT_M) { - if (do_s2io_chk_alarm_bit(RTI_SM_ERR_ALARM, &bar0->rti_err_reg, - &sw_stat->rti_err_cnt)) + if (do_s2io_chk_alarm_bit(RTI_SM_ERR_ALARM, + &bar0->rti_err_reg, + &sw_stat->rti_err_cnt)) goto reset; do_s2io_chk_alarm_bit(RTI_ECC_SG_ERR | RTI_ECC_DB_ERR, - &bar0->rti_err_reg, &sw_stat->rti_err_cnt); + &bar0->rti_err_reg, + &sw_stat->rti_err_cnt); } val64 = readq(&bar0->mac_int_status); if (val64 & MAC_INT_STATUS_RMAC_INT) { if (do_s2io_chk_alarm_bit(RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR, - &bar0->mac_rmac_err_reg, - &sw_stat->mac_rmac_err_cnt)) + &bar0->mac_rmac_err_reg, + &sw_stat->mac_rmac_err_cnt)) goto reset; - do_s2io_chk_alarm_bit(RMAC_UNUSED_INT|RMAC_SINGLE_ECC_ERR| - RMAC_DOUBLE_ECC_ERR, &bar0->mac_rmac_err_reg, - &sw_stat->mac_rmac_err_cnt); + do_s2io_chk_alarm_bit(RMAC_UNUSED_INT | + RMAC_SINGLE_ECC_ERR | + RMAC_DOUBLE_ECC_ERR, + &bar0->mac_rmac_err_reg, + &sw_stat->mac_rmac_err_cnt); } val64 = readq(&bar0->xgxs_int_status); if (val64 & XGXS_INT_STATUS_RXGXS) { if (do_s2io_chk_alarm_bit(RXGXS_ESTORE_OFLOW | RXGXS_RX_SM_ERR, - &bar0->xgxs_rxgxs_err_reg, - &sw_stat->xgxs_rxgxs_err_cnt)) + &bar0->xgxs_rxgxs_err_reg, + &sw_stat->xgxs_rxgxs_err_cnt)) goto reset; } val64 = readq(&bar0->mc_int_status); - if(val64 & MC_INT_STATUS_MC_INT) { - if (do_s2io_chk_alarm_bit(MC_ERR_REG_SM_ERR, &bar0->mc_err_reg, - &sw_stat->mc_err_cnt)) + if (val64 & MC_INT_STATUS_MC_INT) { + if (do_s2io_chk_alarm_bit(MC_ERR_REG_SM_ERR, + &bar0->mc_err_reg, + &sw_stat->mc_err_cnt)) goto reset; /* Handling Ecc errors */ @@ -4738,10 +4767,10 @@ static void s2io_handle_errors(void * dev_id) * Reset XframeI only if critical error */ if (val64 & - (MC_ERR_REG_MIRI_ECC_DB_ERR_0 | - MC_ERR_REG_MIRI_ECC_DB_ERR_1)) - goto reset; - } + (MC_ERR_REG_MIRI_ECC_DB_ERR_0 | + MC_ERR_REG_MIRI_ECC_DB_ERR_1)) + goto reset; + } } else sw_stat->single_ecc_errs++; } @@ -4770,7 +4799,7 @@ reset: */ static irqreturn_t s2io_isr(int irq, void *dev_id) { - struct net_device *dev = (struct net_device *) dev_id; + struct net_device *dev = (struct net_device *)dev_id; struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; int i; @@ -4797,14 +4826,11 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) */ reason = readq(&bar0->general_int_status); - if (unlikely(reason == S2IO_MINUS_ONE) ) { - /* Nothing much can be done. Get out */ - return IRQ_HANDLED; - } + if (unlikely(reason == S2IO_MINUS_ONE)) + return IRQ_HANDLED; /* Nothing much can be done. Get out */ - if (reason & (GEN_INTR_RXTRAFFIC | - GEN_INTR_TXTRAFFIC | GEN_INTR_TXPIC)) - { + if (reason & + (GEN_INTR_RXTRAFFIC | GEN_INTR_TXTRAFFIC | GEN_INTR_TXPIC)) { writeq(S2IO_MINUS_ONE, &bar0->general_int_mask); if (config->napi) { @@ -4859,8 +4885,7 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) return IRQ_HANDLED; - } - else if (!reason) { + } else if (!reason) { /* The interrupt was not raised by us */ return IRQ_NONE; } @@ -4890,7 +4915,7 @@ static void s2io_updt_stats(struct s2io_nic *sp) cnt++; if (cnt == 5) break; /* Updt failed */ - } while(1); + } while (1); } } @@ -4921,7 +4946,7 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev) /* Using sp->stats as a staging area, because reset (due to mtu change, for example) will clear some hardware counters */ dev->stats.tx_packets += - le32_to_cpu(mac_control->stats_info->tmac_frms) - + le32_to_cpu(mac_control->stats_info->tmac_frms) - sp->stats.tx_packets; sp->stats.tx_packets = le32_to_cpu(mac_control->stats_info->tmac_frms); @@ -4936,12 +4961,12 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev) sp->stats.rx_errors = le64_to_cpu(mac_control->stats_info->rmac_drop_frms); dev->stats.multicast = - le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms) - + le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms) - sp->stats.multicast; sp->stats.multicast = le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms); dev->stats.rx_length_errors = - le64_to_cpu(mac_control->stats_info->rmac_long_frms) - + le64_to_cpu(mac_control->stats_info->rmac_long_frms) - sp->stats.rx_length_errors; sp->stats.rx_length_errors = le64_to_cpu(mac_control->stats_info->rmac_long_frms); @@ -4955,7 +4980,7 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev) dev->stats.rx_bytes += ring->rx_bytes; } - return (&dev->stats); + return &dev->stats; } /** @@ -4978,7 +5003,7 @@ static void s2io_set_multicast(struct net_device *dev) struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64 = 0, multi_mac = 0x010203040506ULL, mask = - 0xfeffffffffffULL; + 0xfeffffffffffULL; u64 dis_addr = S2IO_DISABLE_MAC_ENTRY, mac_addr = 0; void __iomem *add; struct config_param *config = &sp->config; @@ -4990,13 +5015,13 @@ static void s2io_set_multicast(struct net_device *dev) writeq(RMAC_ADDR_DATA1_MEM_MASK(mask), &bar0->rmac_addr_data1_mem); val64 = RMAC_ADDR_CMD_MEM_WE | - RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | - RMAC_ADDR_CMD_MEM_OFFSET(config->max_mc_addr - 1); + RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | + RMAC_ADDR_CMD_MEM_OFFSET(config->max_mc_addr - 1); writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait till command completes */ wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, - S2IO_BIT_RESET); + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET); sp->m_cast_flg = 1; sp->all_multi_pos = config->max_mc_addr - 1; @@ -5007,13 +5032,13 @@ static void s2io_set_multicast(struct net_device *dev) writeq(RMAC_ADDR_DATA1_MEM_MASK(0x0), &bar0->rmac_addr_data1_mem); val64 = RMAC_ADDR_CMD_MEM_WE | - RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | - RMAC_ADDR_CMD_MEM_OFFSET(sp->all_multi_pos); + RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | + RMAC_ADDR_CMD_MEM_OFFSET(sp->all_multi_pos); writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait till command completes */ wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, - S2IO_BIT_RESET); + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET); sp->m_cast_flg = 0; sp->all_multi_pos = 0; @@ -5026,7 +5051,7 @@ static void s2io_set_multicast(struct net_device *dev) val64 |= MAC_CFG_RMAC_PROM_ENABLE; writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); - writel((u32) val64, add); + writel((u32)val64, add); writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); writel((u32) (val64 >> 32), (add + 4)); @@ -5048,7 +5073,7 @@ static void s2io_set_multicast(struct net_device *dev) val64 &= ~MAC_CFG_RMAC_PROM_ENABLE; writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); - writel((u32) val64, add); + writel((u32)val64, add); writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); writel((u32) (val64 >> 32), (add + 4)); @@ -5084,19 +5109,18 @@ static void s2io_set_multicast(struct net_device *dev) writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr), &bar0->rmac_addr_data0_mem); writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL), - &bar0->rmac_addr_data1_mem); + &bar0->rmac_addr_data1_mem); val64 = RMAC_ADDR_CMD_MEM_WE | - RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | - RMAC_ADDR_CMD_MEM_OFFSET - (config->mc_start_offset + i); + RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | + RMAC_ADDR_CMD_MEM_OFFSET + (config->mc_start_offset + i); writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait for command completes */ if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, - S2IO_BIT_RESET)) { - DBG_PRINT(ERR_DBG, "%s: Adding ", - dev->name); + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET)) { + DBG_PRINT(ERR_DBG, "%s: Adding ", dev->name); DBG_PRINT(ERR_DBG, "Multicasts failed\n"); return; } @@ -5116,19 +5140,18 @@ static void s2io_set_multicast(struct net_device *dev) writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr), &bar0->rmac_addr_data0_mem); writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL), - &bar0->rmac_addr_data1_mem); + &bar0->rmac_addr_data1_mem); val64 = RMAC_ADDR_CMD_MEM_WE | - RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | - RMAC_ADDR_CMD_MEM_OFFSET - (i + config->mc_start_offset); + RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | + RMAC_ADDR_CMD_MEM_OFFSET + (i + config->mc_start_offset); writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait for command completes */ if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, - S2IO_BIT_RESET)) { - DBG_PRINT(ERR_DBG, "%s: Adding ", - dev->name); + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET)) { + DBG_PRINT(ERR_DBG, "%s: Adding ", dev->name); DBG_PRINT(ERR_DBG, "Multicasts failed\n"); return; } @@ -5163,11 +5186,11 @@ static void do_s2io_restore_unicast_mc(struct s2io_nic *sp) /* restore unicast mac address */ for (offset = 0; offset < config->max_mac_addr; offset++) do_s2io_prog_unicast(sp->dev, - sp->def_mac_addr[offset].mac_addr); + sp->def_mac_addr[offset].mac_addr); /* restore multicast mac address */ for (offset = config->mc_start_offset; - offset < config->max_mc_addr; offset++) + offset < config->max_mc_addr; offset++) do_s2io_add_mc(sp, sp->def_mac_addr[offset].mac_addr); } @@ -5197,13 +5220,13 @@ static int do_s2io_add_mc(struct s2io_nic *sp, u8 *addr) } if (i == config->max_mc_addr) { DBG_PRINT(ERR_DBG, - "CAM full no space left for multicast MAC\n"); + "CAM full no space left for multicast MAC\n"); return FAILURE; } /* Update the internal structure with this new mac address */ do_s2io_copy_mac_addr(sp, i, mac_addr); - return (do_s2io_add_mac(sp, mac_addr, i)); + return do_s2io_add_mac(sp, mac_addr, i); } /* add MAC address to CAM */ @@ -5213,17 +5236,16 @@ static int do_s2io_add_mac(struct s2io_nic *sp, u64 addr, int off) struct XENA_dev_config __iomem *bar0 = sp->bar0; writeq(RMAC_ADDR_DATA0_MEM_ADDR(addr), - &bar0->rmac_addr_data0_mem); + &bar0->rmac_addr_data0_mem); - val64 = - RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | + val64 = RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | RMAC_ADDR_CMD_MEM_OFFSET(off); writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait till command completes */ if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, - S2IO_BIT_RESET)) { + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET)) { DBG_PRINT(INFO_DBG, "do_s2io_add_mac failed\n"); return FAILURE; } @@ -5237,7 +5259,7 @@ static int do_s2io_delete_unicast_mc(struct s2io_nic *sp, u64 addr) struct config_param *config = &sp->config; for (offset = 1; - offset < config->max_mc_addr; offset++) { + offset < config->max_mc_addr; offset++) { tmp64 = do_s2io_read_unicast_mc(sp, offset); if (tmp64 == addr) { /* disable the entry by writing 0xffffffffffffULL */ @@ -5249,7 +5271,7 @@ static int do_s2io_delete_unicast_mc(struct s2io_nic *sp, u64 addr) } } DBG_PRINT(ERR_DBG, "MAC address 0x%llx not found in CAM\n", - (unsigned long long)addr); + (unsigned long long)addr); return FAILURE; } @@ -5260,20 +5282,20 @@ static u64 do_s2io_read_unicast_mc(struct s2io_nic *sp, int offset) struct XENA_dev_config __iomem *bar0 = sp->bar0; /* read mac addr */ - val64 = - RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | + val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | RMAC_ADDR_CMD_MEM_OFFSET(offset); writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait till command completes */ if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, - S2IO_BIT_RESET)) { + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET)) { DBG_PRINT(INFO_DBG, "do_s2io_read_unicast_mc failed\n"); return FAILURE; } tmp64 = readq(&bar0->rmac_addr_data0_mem); - return (tmp64 >> 16); + + return tmp64 >> 16; } /** @@ -5290,7 +5312,7 @@ static int s2io_set_mac_addr(struct net_device *dev, void *p) memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); /* store the MAC address in CAM */ - return (do_s2io_prog_unicast(dev, dev->dev_addr)); + return do_s2io_prog_unicast(dev, dev->dev_addr); } /** * do_s2io_prog_unicast - Programs the Xframe mac address @@ -5311,10 +5333,10 @@ static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr) struct config_param *config = &sp->config; /* - * Set the new MAC address as the new unicast filter and reflect this - * change on the device address registered with the OS. It will be - * at offset 0. - */ + * Set the new MAC address as the new unicast filter and reflect this + * change on the device address registered with the OS. It will be + * at offset 0. + */ for (i = 0; i < ETH_ALEN; i++) { mac_addr <<= 8; mac_addr |= addr[i]; @@ -5334,8 +5356,8 @@ static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr) if (tmp64 == mac_addr) { DBG_PRINT(INFO_DBG, - "MAC addr:0x%llx already present in CAM\n", - (unsigned long long)mac_addr); + "MAC addr:0x%llx already present in CAM\n", + (unsigned long long)mac_addr); return SUCCESS; } } @@ -5345,7 +5367,8 @@ static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr) } /* Update the internal structure with this new mac address */ do_s2io_copy_mac_addr(sp, i, mac_addr); - return (do_s2io_add_mac(sp, mac_addr, i)); + + return do_s2io_add_mac(sp, mac_addr, i); } /** @@ -5358,14 +5381,15 @@ static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr) * the NIC. * Return value: * 0 on success. -*/ + */ static int s2io_ethtool_sset(struct net_device *dev, struct ethtool_cmd *info) { struct s2io_nic *sp = netdev_priv(dev); if ((info->autoneg == AUTONEG_ENABLE) || - (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL)) + (info->speed != SPEED_10000) || + (info->duplex != DUPLEX_FULL)) return -EINVAL; else { s2io_close(sp->dev); @@ -5446,14 +5470,14 @@ static void s2io_ethtool_gdrvinfo(struct net_device *dev, * buffer area. * Return value : * void . -*/ + */ static void s2io_ethtool_gregs(struct net_device *dev, struct ethtool_regs *regs, void *space) { int i; u64 reg; - u8 *reg_space = (u8 *) space; + u8 *reg_space = (u8 *)space; struct s2io_nic *sp = netdev_priv(dev); regs->len = XENA_REG_SPACE; @@ -5473,17 +5497,17 @@ static void s2io_ethtool_gregs(struct net_device *dev, * adapter LED bit of the adapter control bit to set/reset every time on * invocation. The timer is set for 1/2 a second, hence tha NIC blinks * once every second. -*/ + */ static void s2io_phy_id(unsigned long data) { - struct s2io_nic *sp = (struct s2io_nic *) data; + struct s2io_nic *sp = (struct s2io_nic *)data; struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64 = 0; u16 subid; subid = sp->pdev->subsystem_device; if ((sp->device_type == XFRAME_II_DEVICE) || - ((subid & 0xFF) >= 0x07)) { + ((subid & 0xFF) >= 0x07)) { val64 = readq(&bar0->gpio_control); val64 ^= GPIO_CTRL_GPIO_0; writeq(val64, &bar0->gpio_control); @@ -5520,8 +5544,7 @@ static int s2io_ethtool_idnic(struct net_device *dev, u32 data) subid = sp->pdev->subsystem_device; last_gpio_ctrl_val = readq(&bar0->gpio_control); - if ((sp->device_type == XFRAME_I_DEVICE) && - ((subid & 0xFF) < 0x07)) { + if ((sp->device_type == XFRAME_I_DEVICE) && ((subid & 0xFF) < 0x07)) { val64 = readq(&bar0->adapter_control); if (!(val64 & ADAPTER_CNTL_EN)) { printk(KERN_ERR @@ -5532,7 +5555,7 @@ static int s2io_ethtool_idnic(struct net_device *dev, u32 data) if (sp->id_timer.function == NULL) { init_timer(&sp->id_timer); sp->id_timer.function = s2io_phy_id; - sp->id_timer.data = (unsigned long) sp; + sp->id_timer.data = (unsigned long)sp; } mod_timer(&sp->id_timer, jiffies); if (data) @@ -5550,10 +5573,10 @@ static int s2io_ethtool_idnic(struct net_device *dev, u32 data) } static void s2io_ethtool_gringparam(struct net_device *dev, - struct ethtool_ringparam *ering) + struct ethtool_ringparam *ering) { struct s2io_nic *sp = netdev_priv(dev); - int i,tx_desc_count=0,rx_desc_count=0; + int i, tx_desc_count = 0, rx_desc_count = 0; if (sp->rxd_mode == RXD_MODE_1) ering->rx_max_pending = MAX_RX_DESC_1; @@ -5564,7 +5587,7 @@ static void s2io_ethtool_gringparam(struct net_device *dev, for (i = 0 ; i < sp->config.tx_fifo_num ; i++) tx_desc_count += sp->config.tx_cfg[i].fifo_len; - DBG_PRINT(INFO_DBG,"\nmax txds : %d\n",sp->config.max_txds); + DBG_PRINT(INFO_DBG, "\nmax txds : %d\n", sp->config.max_txds); ering->tx_pending = tx_desc_count; rx_desc_count = 0; for (i = 0 ; i < sp->config.rx_ring_num ; i++) @@ -5574,7 +5597,7 @@ static void s2io_ethtool_gringparam(struct net_device *dev, ering->rx_mini_max_pending = 0; ering->rx_mini_pending = 0; - if(sp->rxd_mode == RXD_MODE_1) + if (sp->rxd_mode == RXD_MODE_1) ering->rx_jumbo_max_pending = MAX_RX_DESC_1; else if (sp->rxd_mode == RXD_MODE_3B) ering->rx_jumbo_max_pending = MAX_RX_DESC_2; @@ -5619,7 +5642,7 @@ static void s2io_ethtool_getpause_data(struct net_device *dev, */ static int s2io_ethtool_setpause_data(struct net_device *dev, - struct ethtool_pauseparam *ep) + struct ethtool_pauseparam *ep) { u64 val64; struct s2io_nic *sp = netdev_priv(dev); @@ -5655,7 +5678,7 @@ static int s2io_ethtool_setpause_data(struct net_device *dev, */ #define S2IO_DEV_ID 5 -static int read_eeprom(struct s2io_nic * sp, int off, u64 * data) +static int read_eeprom(struct s2io_nic *sp, int off, u64 *data) { int ret = -1; u32 exit_cnt = 0; @@ -5663,9 +5686,11 @@ static int read_eeprom(struct s2io_nic * sp, int off, u64 * data) struct XENA_dev_config __iomem *bar0 = sp->bar0; if (sp->device_type == XFRAME_I_DEVICE) { - val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) | - I2C_CONTROL_BYTE_CNT(0x3) | I2C_CONTROL_READ | - I2C_CONTROL_CNTL_START; + val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | + I2C_CONTROL_ADDR(off) | + I2C_CONTROL_BYTE_CNT(0x3) | + I2C_CONTROL_READ | + I2C_CONTROL_CNTL_START; SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF); while (exit_cnt < 5) { @@ -5720,16 +5745,18 @@ static int read_eeprom(struct s2io_nic * sp, int off, u64 * data) * 0 on success, -1 on failure. */ -static int write_eeprom(struct s2io_nic * sp, int off, u64 data, int cnt) +static int write_eeprom(struct s2io_nic *sp, int off, u64 data, int cnt) { int exit_cnt = 0, ret = -1; u64 val64; struct XENA_dev_config __iomem *bar0 = sp->bar0; if (sp->device_type == XFRAME_I_DEVICE) { - val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) | - I2C_CONTROL_BYTE_CNT(cnt) | I2C_CONTROL_SET_DATA((u32)data) | - I2C_CONTROL_CNTL_START; + val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | + I2C_CONTROL_ADDR(off) | + I2C_CONTROL_BYTE_CNT(cnt) | + I2C_CONTROL_SET_DATA((u32)data) | + I2C_CONTROL_CNTL_START; SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF); while (exit_cnt < 5) { @@ -5746,7 +5773,7 @@ static int write_eeprom(struct s2io_nic * sp, int off, u64 data, int cnt) if (sp->device_type == XFRAME_II_DEVICE) { int write_cnt = (cnt == 8) ? 0 : cnt; - writeq(SPI_DATA_WRITE(data,(cnt<<3)), &bar0->spi_data); + writeq(SPI_DATA_WRITE(data, (cnt << 3)), &bar0->spi_data); val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 | SPI_CONTROL_BYTECNT(write_cnt) | @@ -5773,14 +5800,13 @@ static void s2io_vpd_read(struct s2io_nic *nic) { u8 *vpd_data; u8 data; - int i=0, cnt, fail = 0; + int i = 0, cnt, fail = 0; int vpd_addr = 0x80; if (nic->device_type == XFRAME_II_DEVICE) { strcpy(nic->product_name, "Xframe II 10GbE network adapter"); vpd_addr = 0x80; - } - else { + } else { strcpy(nic->product_name, "Xframe I 10GbE network adapter"); vpd_addr = 0x50; } @@ -5793,11 +5819,11 @@ static void s2io_vpd_read(struct s2io_nic *nic) } nic->mac_control.stats_info->sw_stat.mem_allocated += 256; - for (i = 0; i < 256; i +=4 ) { + for (i = 0; i < 256; i += 4) { pci_write_config_byte(nic->pdev, (vpd_addr + 2), i); pci_read_config_byte(nic->pdev, (vpd_addr + 2), &data); pci_write_config_byte(nic->pdev, (vpd_addr + 3), 0); - for (cnt = 0; cnt <5; cnt++) { + for (cnt = 0; cnt < 5; cnt++) { msleep(2); pci_read_config_byte(nic->pdev, (vpd_addr + 3), &data); if (data == 0x80) @@ -5812,15 +5838,15 @@ static void s2io_vpd_read(struct s2io_nic *nic) (u32 *)&vpd_data[i]); } - if(!fail) { + if (!fail) { /* read serial number of adapter */ for (cnt = 0; cnt < 256; cnt++) { - if ((vpd_data[cnt] == 'S') && - (vpd_data[cnt+1] == 'N') && - (vpd_data[cnt+2] < VPD_STRING_LEN)) { + if ((vpd_data[cnt] == 'S') && + (vpd_data[cnt+1] == 'N') && + (vpd_data[cnt+2] < VPD_STRING_LEN)) { memset(nic->serial_num, 0, VPD_STRING_LEN); memcpy(nic->serial_num, &vpd_data[cnt + 3], - vpd_data[cnt+2]); + vpd_data[cnt+2]); break; } } @@ -5848,7 +5874,7 @@ static void s2io_vpd_read(struct s2io_nic *nic) */ static int s2io_ethtool_geeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 * data_buf) + struct ethtool_eeprom *eeprom, u8 * data_buf) { u32 i, valid; u64 data; @@ -5886,7 +5912,7 @@ static int s2io_ethtool_geeprom(struct net_device *dev, static int s2io_ethtool_seeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, - u8 * data_buf) + u8 *data_buf) { int len = eeprom->len, cnt = 0; u64 valid = 0, data; @@ -5895,16 +5921,15 @@ static int s2io_ethtool_seeprom(struct net_device *dev, if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) { DBG_PRINT(ERR_DBG, "ETHTOOL_WRITE_EEPROM Err: Magic value "); - DBG_PRINT(ERR_DBG, "is wrong, Its not 0x%x\n", - eeprom->magic); + DBG_PRINT(ERR_DBG, "is wrong, Its not 0x%x\n", eeprom->magic); return -EFAULT; } while (len) { - data = (u32) data_buf[cnt] & 0x000000FF; - if (data) { - valid = (u32) (data << 24); - } else + data = (u32)data_buf[cnt] & 0x000000FF; + if (data) + valid = (u32)(data << 24); + else valid = data; if (write_eeprom(sp, (eeprom->offset + cnt), valid, 0)) { @@ -5934,7 +5959,7 @@ static int s2io_ethtool_seeprom(struct net_device *dev, * 0 on success. */ -static int s2io_register_test(struct s2io_nic * sp, uint64_t * data) +static int s2io_register_test(struct s2io_nic *sp, uint64_t *data) { struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64 = 0, exp_val; @@ -6001,7 +6026,7 @@ static int s2io_register_test(struct s2io_nic * sp, uint64_t * data) * 0 on success. */ -static int s2io_eeprom_test(struct s2io_nic * sp, uint64_t * data) +static int s2io_eeprom_test(struct s2io_nic *sp, uint64_t *data) { int fail = 0; u64 ret_data, org_4F0, org_7F0; @@ -6030,9 +6055,9 @@ static int s2io_eeprom_test(struct s2io_nic * sp, uint64_t * data) if (ret_data != 0x012345) { DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x4F0. " - "Data written %llx Data read %llx\n", - dev->name, (unsigned long long)0x12345, - (unsigned long long)ret_data); + "Data written %llx Data read %llx\n", + dev->name, (unsigned long long)0x12345, + (unsigned long long)ret_data); fail = 1; } @@ -6052,9 +6077,9 @@ static int s2io_eeprom_test(struct s2io_nic * sp, uint64_t * data) if (ret_data != 0x012345) { DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x7F0. " - "Data written %llx Data read %llx\n", - dev->name, (unsigned long long)0x12345, - (unsigned long long)ret_data); + "Data written %llx Data read %llx\n", + dev->name, (unsigned long long)0x12345, + (unsigned long long)ret_data); fail = 1; } @@ -6103,7 +6128,7 @@ static int s2io_eeprom_test(struct s2io_nic * sp, uint64_t * data) * 0 on success and -1 on failure. */ -static int s2io_bist_test(struct s2io_nic * sp, uint64_t * data) +static int s2io_bist_test(struct s2io_nic *sp, uint64_t *data) { u8 bist = 0; int cnt = 0, ret = -1; @@ -6139,13 +6164,13 @@ static int s2io_bist_test(struct s2io_nic * sp, uint64_t * data) * 0 on success. */ -static int s2io_link_test(struct s2io_nic * sp, uint64_t * data) +static int s2io_link_test(struct s2io_nic *sp, uint64_t *data) { struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64; val64 = readq(&bar0->adapter_status); - if(!(LINK_IS_UP(val64))) + if (!(LINK_IS_UP(val64))) *data = 1; else *data = 0; @@ -6166,7 +6191,7 @@ static int s2io_link_test(struct s2io_nic * sp, uint64_t * data) * 0 on success. */ -static int s2io_rldram_test(struct s2io_nic * sp, uint64_t * data) +static int s2io_rldram_test(struct s2io_nic *sp, uint64_t *data) { struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64; @@ -6189,28 +6214,26 @@ static int s2io_rldram_test(struct s2io_nic * sp, uint64_t * data) while (iteration < 2) { val64 = 0x55555555aaaa0000ULL; - if (iteration == 1) { + if (iteration == 1) val64 ^= 0xFFFFFFFFFFFF0000ULL; - } writeq(val64, &bar0->mc_rldram_test_d0); val64 = 0xaaaa5a5555550000ULL; - if (iteration == 1) { + if (iteration == 1) val64 ^= 0xFFFFFFFFFFFF0000ULL; - } writeq(val64, &bar0->mc_rldram_test_d1); val64 = 0x55aaaaaaaa5a0000ULL; - if (iteration == 1) { + if (iteration == 1) val64 ^= 0xFFFFFFFFFFFF0000ULL; - } writeq(val64, &bar0->mc_rldram_test_d2); val64 = (u64) (0x0000003ffffe0100ULL); writeq(val64, &bar0->mc_rldram_test_add); - val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_WRITE | - MC_RLDRAM_TEST_GO; + val64 = MC_RLDRAM_TEST_MODE | + MC_RLDRAM_TEST_WRITE | + MC_RLDRAM_TEST_GO; SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF); for (cnt = 0; cnt < 5; cnt++) { @@ -6268,7 +6291,7 @@ static int s2io_rldram_test(struct s2io_nic * sp, uint64_t * data) static void s2io_ethtool_test(struct net_device *dev, struct ethtool_test *ethtest, - uint64_t * data) + uint64_t *data) { struct s2io_nic *sp = netdev_priv(dev); int orig_state = netif_running(sp->dev); @@ -6301,8 +6324,7 @@ static void s2io_ethtool_test(struct net_device *dev, } else { /* Online Tests. */ if (!orig_state) { - DBG_PRINT(ERR_DBG, - "%s: is not up, cannot run test\n", + DBG_PRINT(ERR_DBG, "%s: is not up, cannot run test\n", dev->name); data[0] = -1; data[1] = -1; @@ -6323,7 +6345,7 @@ static void s2io_ethtool_test(struct net_device *dev, static void s2io_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *estats, - u64 * tmp_stats) + u64 *tmp_stats) { int i = 0, k; struct s2io_nic *sp = netdev_priv(dev); @@ -6344,19 +6366,19 @@ static void s2io_get_ethtool_stats(struct net_device *dev, (u64)le32_to_cpu(stat_info->tmac_bcst_frms_oflow) << 32 | le32_to_cpu(stat_info->tmac_bcst_frms); tmp_stats[i++] = le64_to_cpu(stat_info->tmac_pause_ctrl_frms); - tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_ttl_octets_oflow) << 32 | - le32_to_cpu(stat_info->tmac_ttl_octets); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_ucst_frms_oflow) << 32 | - le32_to_cpu(stat_info->tmac_ucst_frms); + (u64)le32_to_cpu(stat_info->tmac_ttl_octets_oflow) << 32 | + le32_to_cpu(stat_info->tmac_ttl_octets); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_nucst_frms_oflow) << 32 | - le32_to_cpu(stat_info->tmac_nucst_frms); + (u64)le32_to_cpu(stat_info->tmac_ucst_frms_oflow) << 32 | + le32_to_cpu(stat_info->tmac_ucst_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->tmac_nucst_frms_oflow) << 32 | + le32_to_cpu(stat_info->tmac_nucst_frms); tmp_stats[i++] = (u64)le32_to_cpu(stat_info->tmac_any_err_frms_oflow) << 32 | le32_to_cpu(stat_info->tmac_any_err_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->tmac_ttl_less_fb_octets); + tmp_stats[i++] = le64_to_cpu(stat_info->tmac_ttl_less_fb_octets); tmp_stats[i++] = le64_to_cpu(stat_info->tmac_vld_ip_octets); tmp_stats[i++] = (u64)le32_to_cpu(stat_info->tmac_vld_ip_oflow) << 32 | @@ -6392,23 +6414,23 @@ static void s2io_get_ethtool_stats(struct net_device *dev, tmp_stats[i++] = le64_to_cpu(stat_info->rmac_long_frms); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_pause_ctrl_frms); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_unsup_ctrl_frms); - tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_ttl_octets_oflow) << 32 | + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_ttl_octets_oflow) << 32 | le32_to_cpu(stat_info->rmac_ttl_octets); - tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_accepted_ucst_frms_oflow) - << 32 | le32_to_cpu(stat_info->rmac_accepted_ucst_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_accepted_nucst_frms_oflow) - << 32 | le32_to_cpu(stat_info->rmac_accepted_nucst_frms); + (u64)le32_to_cpu(stat_info->rmac_accepted_ucst_frms_oflow) << 32 + | le32_to_cpu(stat_info->rmac_accepted_ucst_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_accepted_nucst_frms_oflow) + << 32 | le32_to_cpu(stat_info->rmac_accepted_nucst_frms); tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_discarded_frms_oflow) << 32 | le32_to_cpu(stat_info->rmac_discarded_frms); - tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_drop_events_oflow) - << 32 | le32_to_cpu(stat_info->rmac_drop_events); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_less_fb_octets); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_drop_events_oflow) + << 32 | le32_to_cpu(stat_info->rmac_drop_events); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_less_fb_octets); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_frms); tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_usized_frms_oflow) << 32 | le32_to_cpu(stat_info->rmac_usized_frms); @@ -6422,11 +6444,11 @@ static void s2io_get_ethtool_stats(struct net_device *dev, (u64)le32_to_cpu(stat_info->rmac_jabber_frms_oflow) << 32 | le32_to_cpu(stat_info->rmac_jabber_frms); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_64_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_65_127_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_128_255_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_256_511_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_512_1023_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1024_1518_frms); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_65_127_frms); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_128_255_frms); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_256_511_frms); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_512_1023_frms); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1024_1518_frms); tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_ip_oflow) << 32 | le32_to_cpu(stat_info->rmac_ip); @@ -6446,27 +6468,27 @@ static void s2io_get_ethtool_stats(struct net_device *dev, (u64)le32_to_cpu(stat_info->rmac_err_drp_udp_oflow) << 32 | le32_to_cpu(stat_info->rmac_err_drp_udp); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_err_sym); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q0); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q1); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q2); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q3); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q4); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q5); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q6); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q7); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q0); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q1); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q2); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q3); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q4); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q5); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q6); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q7); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q0); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q1); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q2); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q3); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q4); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q5); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q6); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q7); + tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q0); + tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q1); + tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q2); + tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q3); + tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q4); + tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q5); + tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q6); + tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q7); tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_pause_cnt_oflow) << 32 | le32_to_cpu(stat_info->rmac_pause_cnt); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_data_err_cnt); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_ctrl_err_cnt); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_ctrl_err_cnt); tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_accepted_ip_oflow) << 32 | le32_to_cpu(stat_info->rmac_accepted_ip); @@ -6491,13 +6513,13 @@ static void s2io_get_ethtool_stats(struct net_device *dev, tmp_stats[i++] = le32_to_cpu(stat_info->rxf_wr_cnt); /* Enhanced statistics exist only for Hercules */ - if(sp->device_type == XFRAME_II_DEVICE) { + if (sp->device_type == XFRAME_II_DEVICE) { tmp_stats[i++] = - le64_to_cpu(stat_info->rmac_ttl_1519_4095_frms); + le64_to_cpu(stat_info->rmac_ttl_1519_4095_frms); tmp_stats[i++] = - le64_to_cpu(stat_info->rmac_ttl_4096_8191_frms); + le64_to_cpu(stat_info->rmac_ttl_4096_8191_frms); tmp_stats[i++] = - le64_to_cpu(stat_info->rmac_ttl_8192_max_frms); + le64_to_cpu(stat_info->rmac_ttl_8192_max_frms); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_gt_max_frms); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_osized_alt_frms); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_jabber_alt_frms); @@ -6550,8 +6572,7 @@ static void s2io_get_ethtool_stats(struct net_device *dev, count++; } tmp_stats[i++] = count; - } - else + } else tmp_stats[i++] = 0; tmp_stats[i++] = stat_info->sw_stat.mem_alloc_fail_cnt; tmp_stats[i++] = stat_info->sw_stat.pci_map_fail_cnt; @@ -6599,15 +6620,15 @@ static void s2io_get_ethtool_stats(struct net_device *dev, static int s2io_ethtool_get_regs_len(struct net_device *dev) { - return (XENA_REG_SPACE); + return XENA_REG_SPACE; } -static u32 s2io_ethtool_get_rx_csum(struct net_device * dev) +static u32 s2io_ethtool_get_rx_csum(struct net_device *dev) { struct s2io_nic *sp = netdev_priv(dev); - return (sp->rx_csum); + return sp->rx_csum; } static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data) @@ -6624,7 +6645,7 @@ static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data) static int s2io_get_eeprom_len(struct net_device *dev) { - return (XENA_EEPROM_SPACE); + return XENA_EEPROM_SPACE; } static int s2io_get_sset_count(struct net_device *dev, int sset) @@ -6635,7 +6656,7 @@ static int s2io_get_sset_count(struct net_device *dev, int sset) case ETH_SS_TEST: return S2IO_TEST_LEN; case ETH_SS_STATS: - switch(sp->device_type) { + switch (sp->device_type) { case XFRAME_I_DEVICE: return XFRAME_I_STAT_LEN; case XFRAME_II_DEVICE: @@ -6649,7 +6670,7 @@ static int s2io_get_sset_count(struct net_device *dev, int sset) } static void s2io_ethtool_get_strings(struct net_device *dev, - u32 stringset, u8 * data) + u32 stringset, u8 *data) { int stat_size = 0; struct s2io_nic *sp = netdev_priv(dev); @@ -6660,16 +6681,16 @@ static void s2io_ethtool_get_strings(struct net_device *dev, break; case ETH_SS_STATS: stat_size = sizeof(ethtool_xena_stats_keys); - memcpy(data, ðtool_xena_stats_keys,stat_size); - if(sp->device_type == XFRAME_II_DEVICE) { + memcpy(data, ðtool_xena_stats_keys, stat_size); + if (sp->device_type == XFRAME_II_DEVICE) { memcpy(data + stat_size, - ðtool_enhanced_stats_keys, - sizeof(ethtool_enhanced_stats_keys)); + ðtool_enhanced_stats_keys, + sizeof(ethtool_enhanced_stats_keys)); stat_size += sizeof(ethtool_enhanced_stats_keys); } memcpy(data + stat_size, ðtool_driver_stats_keys, - sizeof(ethtool_driver_stats_keys)); + sizeof(ethtool_driver_stats_keys)); } } @@ -6758,8 +6779,7 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu) int ret = 0; if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) { - DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n", - dev->name); + DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n", dev->name); return -EPERM; } @@ -6792,7 +6812,8 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu) static void s2io_set_link(struct work_struct *work) { - struct s2io_nic *nic = container_of(work, struct s2io_nic, set_link_task); + struct s2io_nic *nic = container_of(work, struct s2io_nic, + set_link_task); struct net_device *dev = nic->dev; struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 val64; @@ -6825,7 +6846,7 @@ static void s2io_set_link(struct work_struct *work) val64 |= ADAPTER_CNTL_EN; writeq(val64, &bar0->adapter_control); if (CARDS_WITH_FAULTY_LINK_INDICATORS( - nic->device_type, subid)) { + nic->device_type, subid)) { val64 = readq(&bar0->gpio_control); val64 |= GPIO_CTRL_GPIO_0; writeq(val64, &bar0->gpio_control); @@ -6855,7 +6876,7 @@ static void s2io_set_link(struct work_struct *work) } /* turn off LED */ val64 = readq(&bar0->adapter_control); - val64 = val64 &(~ADAPTER_LED_ON); + val64 = val64 & (~ADAPTER_LED_ON); writeq(val64, &bar0->adapter_control); s2io_link(nic, LINK_DOWN); } @@ -6866,9 +6887,9 @@ out_unlock: } static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, - struct buffAdd *ba, - struct sk_buff **skb, u64 *temp0, u64 *temp1, - u64 *temp2, int size) + struct buffAdd *ba, + struct sk_buff **skb, u64 *temp0, u64 *temp1, + u64 *temp2, int size) { struct net_device *dev = sp->dev; struct swStat *stats = &sp->mac_control.stats_info->sw_stat; @@ -6890,7 +6911,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name); DBG_PRINT(INFO_DBG, "memory to allocate "); DBG_PRINT(INFO_DBG, "1 buf mode SKBs\n"); - sp->mac_control.stats_info->sw_stat. \ + sp->mac_control.stats_info->sw_stat. mem_alloc_fail_cnt++; return -ENOMEM ; } @@ -6901,9 +6922,9 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, * Host Control is NULL */ rxdp1->Buffer0_ptr = *temp0 = - pci_map_single( sp->pdev, (*skb)->data, - size - NET_IP_ALIGN, - PCI_DMA_FROMDEVICE); + pci_map_single(sp->pdev, (*skb)->data, + size - NET_IP_ALIGN, + PCI_DMA_FROMDEVICE); if (pci_dma_mapping_error(sp->pdev, rxdp1->Buffer0_ptr)) goto memalloc_failed; rxdp->Host_Control = (unsigned long) (*skb); @@ -6921,7 +6942,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name); DBG_PRINT(INFO_DBG, "memory to allocate "); DBG_PRINT(INFO_DBG, "2 buf mode SKBs\n"); - sp->mac_control.stats_info->sw_stat. \ + sp->mac_control.stats_info->sw_stat. mem_alloc_fail_cnt++; return -ENOMEM; } @@ -6934,13 +6955,14 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, if (pci_dma_mapping_error(sp->pdev, rxdp3->Buffer2_ptr)) goto memalloc_failed; rxdp3->Buffer0_ptr = *temp0 = - pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN, - PCI_DMA_FROMDEVICE); + pci_map_single(sp->pdev, ba->ba_0, BUF0_LEN, + PCI_DMA_FROMDEVICE); if (pci_dma_mapping_error(sp->pdev, - rxdp3->Buffer0_ptr)) { - pci_unmap_single (sp->pdev, - (dma_addr_t)rxdp3->Buffer2_ptr, - dev->mtu + 4, PCI_DMA_FROMDEVICE); + rxdp3->Buffer0_ptr)) { + pci_unmap_single(sp->pdev, + (dma_addr_t)rxdp3->Buffer2_ptr, + dev->mtu + 4, + PCI_DMA_FROMDEVICE); goto memalloc_failed; } rxdp->Host_Control = (unsigned long) (*skb); @@ -6948,25 +6970,27 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, /* Buffer-1 will be dummy buffer not used */ rxdp3->Buffer1_ptr = *temp1 = pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN, - PCI_DMA_FROMDEVICE); + PCI_DMA_FROMDEVICE); if (pci_dma_mapping_error(sp->pdev, - rxdp3->Buffer1_ptr)) { - pci_unmap_single (sp->pdev, - (dma_addr_t)rxdp3->Buffer0_ptr, - BUF0_LEN, PCI_DMA_FROMDEVICE); - pci_unmap_single (sp->pdev, - (dma_addr_t)rxdp3->Buffer2_ptr, - dev->mtu + 4, PCI_DMA_FROMDEVICE); + rxdp3->Buffer1_ptr)) { + pci_unmap_single(sp->pdev, + (dma_addr_t)rxdp3->Buffer0_ptr, + BUF0_LEN, PCI_DMA_FROMDEVICE); + pci_unmap_single(sp->pdev, + (dma_addr_t)rxdp3->Buffer2_ptr, + dev->mtu + 4, + PCI_DMA_FROMDEVICE); goto memalloc_failed; } } } return 0; - memalloc_failed: - stats->pci_map_fail_cnt++; - stats->mem_freed += (*skb)->truesize; - dev_kfree_skb(*skb); - return -ENOMEM; + +memalloc_failed: + stats->pci_map_fail_cnt++; + stats->mem_freed += (*skb)->truesize; + dev_kfree_skb(*skb); + return -ENOMEM; } static void set_rxd_buffer_size(struct s2io_nic *sp, struct RxD_t *rxdp, @@ -6974,18 +6998,18 @@ static void set_rxd_buffer_size(struct s2io_nic *sp, struct RxD_t *rxdp, { struct net_device *dev = sp->dev; if (sp->rxd_mode == RXD_MODE_1) { - rxdp->Control_2 = SET_BUFFER0_SIZE_1( size - NET_IP_ALIGN); + rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN); } else if (sp->rxd_mode == RXD_MODE_3B) { rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN); rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1); - rxdp->Control_2 |= SET_BUFFER2_SIZE_3( dev->mtu + 4); + rxdp->Control_2 |= SET_BUFFER2_SIZE_3(dev->mtu + 4); } } static int rxd_owner_bit_reset(struct s2io_nic *sp) { int i, j, k, blk_cnt = 0, size; - struct mac_info * mac_control = &sp->mac_control; + struct mac_info *mac_control = &sp->mac_control; struct config_param *config = &sp->config; struct net_device *dev = sp->dev; struct RxD_t *rxdp = NULL; @@ -7005,18 +7029,18 @@ static int rxd_owner_bit_reset(struct s2io_nic *sp) struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; struct ring_info *ring = &mac_control->rings[i]; - blk_cnt = rx_cfg->num_rxd / (rxd_count[sp->rxd_mode] +1); + blk_cnt = rx_cfg->num_rxd / (rxd_count[sp->rxd_mode] + 1); for (j = 0; j < blk_cnt; j++) { for (k = 0; k < rxd_count[sp->rxd_mode]; k++) { - rxdp = ring-> rx_blocks[j].rxds[k].virt_addr; - if(sp->rxd_mode == RXD_MODE_3B) + rxdp = ring->rx_blocks[j].rxds[k].virt_addr; + if (sp->rxd_mode == RXD_MODE_3B) ba = &ring->ba[j][k]; - if (set_rxd_buffer_pointer(sp, rxdp, ba, - &skb,(u64 *)&temp0_64, - (u64 *)&temp1_64, - (u64 *)&temp2_64, - size) == -ENOMEM) { + if (set_rxd_buffer_pointer(sp, rxdp, ba, &skb, + (u64 *)&temp0_64, + (u64 *)&temp1_64, + (u64 *)&temp2_64, + size) == -ENOMEM) { return 0; } @@ -7031,7 +7055,7 @@ static int rxd_owner_bit_reset(struct s2io_nic *sp) } -static int s2io_add_isr(struct s2io_nic * sp) +static int s2io_add_isr(struct s2io_nic *sp) { int ret = 0; struct net_device *dev = sp->dev; @@ -7044,7 +7068,10 @@ static int s2io_add_isr(struct s2io_nic * sp) sp->config.intr_type = INTA; } - /* Store the values of the MSIX table in the struct s2io_nic structure */ + /* + * Store the values of the MSIX table in + * the struct s2io_nic structure + */ store_xmsi_data(sp); /* After proper initialization of H/W, register ISR */ @@ -7054,45 +7081,47 @@ static int s2io_add_isr(struct s2io_nic * sp) for (i = 0; i < sp->num_entries; i++) { if (sp->s2io_entries[i].in_use == MSIX_FLG) { if (sp->s2io_entries[i].type == - MSIX_RING_TYPE) { + MSIX_RING_TYPE) { sprintf(sp->desc[i], "%s:MSI-X-%d-RX", dev->name, i); err = request_irq(sp->entries[i].vector, - s2io_msix_ring_handle, 0, - sp->desc[i], - sp->s2io_entries[i].arg); + s2io_msix_ring_handle, + 0, + sp->desc[i], + sp->s2io_entries[i].arg); } else if (sp->s2io_entries[i].type == - MSIX_ALARM_TYPE) { + MSIX_ALARM_TYPE) { sprintf(sp->desc[i], "%s:MSI-X-%d-TX", - dev->name, i); + dev->name, i); err = request_irq(sp->entries[i].vector, - s2io_msix_fifo_handle, 0, - sp->desc[i], - sp->s2io_entries[i].arg); + s2io_msix_fifo_handle, + 0, + sp->desc[i], + sp->s2io_entries[i].arg); } /* if either data or addr is zero print it. */ if (!(sp->msix_info[i].addr && - sp->msix_info[i].data)) { + sp->msix_info[i].data)) { DBG_PRINT(ERR_DBG, - "%s @Addr:0x%llx Data:0x%llx\n", - sp->desc[i], - (unsigned long long) - sp->msix_info[i].addr, - (unsigned long long) - ntohl(sp->msix_info[i].data)); + "%s @Addr:0x%llx Data:0x%llx\n", + sp->desc[i], + (unsigned long long) + sp->msix_info[i].addr, + (unsigned long long) + ntohl(sp->msix_info[i].data)); } else msix_rx_cnt++; if (err) { remove_msix_isr(sp); DBG_PRINT(ERR_DBG, - "%s:MSI-X-%d registration " - "failed\n", dev->name, i); + "%s:MSI-X-%d registration " + "failed\n", dev->name, i); DBG_PRINT(ERR_DBG, - "%s: Defaulting to INTA\n", - dev->name); + "%s: Defaulting to INTA\n", + dev->name); sp->config.intr_type = INTA; break; } @@ -7102,14 +7131,14 @@ static int s2io_add_isr(struct s2io_nic * sp) } if (!err) { printk(KERN_INFO "MSI-X-RX %d entries enabled\n", - --msix_rx_cnt); + --msix_rx_cnt); DBG_PRINT(INFO_DBG, "MSI-X-TX entries enabled" - " through alarm vector\n"); + " through alarm vector\n"); } } if (sp->config.intr_type == INTA) { - err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED, - sp->name, dev); + err = request_irq((int)sp->pdev->irq, s2io_isr, IRQF_SHARED, + sp->name, dev); if (err) { DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n", dev->name); @@ -7118,7 +7147,8 @@ static int s2io_add_isr(struct s2io_nic * sp) } return 0; } -static void s2io_rem_isr(struct s2io_nic * sp) + +static void s2io_rem_isr(struct s2io_nic *sp) { if (sp->config.intr_type == MSI_X) remove_msix_isr(sp); @@ -7126,7 +7156,7 @@ static void s2io_rem_isr(struct s2io_nic * sp) remove_inta_isr(sp); } -static void do_s2io_card_down(struct s2io_nic * sp, int do_io) +static void do_s2io_card_down(struct s2io_nic *sp, int do_io) { int cnt = 0; struct XENA_dev_config __iomem *bar0 = sp->bar0; @@ -7139,9 +7169,8 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) del_timer_sync(&sp->alarm_timer); /* If s2io_set_link task is executing, wait till it completes. */ - while (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(sp->state))) { + while (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(sp->state))) msleep(50); - } clear_bit(__S2IO_STATE_CARD_UP, &sp->state); /* Disable napi */ @@ -7150,7 +7179,7 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) if (config->intr_type == MSI_X) { for (; off < sp->config.rx_ring_num; off++) napi_disable(&sp->mac_control.rings[off].napi); - } + } else napi_disable(&sp->napi); } @@ -7165,7 +7194,7 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) s2io_link(sp, LINK_DOWN); /* Check if the device is Quiescent and then Reset the NIC */ - while(do_io) { + while (do_io) { /* As per the HW requirement we need to replenish the * receive buffer to avoid the ring bump. Since there is * no intention of processing the Rx frame at this pointwe are @@ -7177,17 +7206,16 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) val64 = readq(&bar0->adapter_status); if (verify_xena_quiescence(sp)) { - if(verify_pcc_quiescent(sp, sp->device_enabled_once)) - break; + if (verify_pcc_quiescent(sp, sp->device_enabled_once)) + break; } msleep(50); cnt++; if (cnt == 10) { - DBG_PRINT(ERR_DBG, - "s2io_close:Device not Quiescent "); + DBG_PRINT(ERR_DBG, "s2io_close:Device not Quiescent "); DBG_PRINT(ERR_DBG, "adaper status reads 0x%llx\n", - (unsigned long long) val64); + (unsigned long long)val64); break; } } @@ -7203,17 +7231,17 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) clear_bit(__S2IO_STATE_LINK_TASK, &(sp->state)); } -static void s2io_card_down(struct s2io_nic * sp) +static void s2io_card_down(struct s2io_nic *sp) { do_s2io_card_down(sp, 1); } -static int s2io_card_up(struct s2io_nic * sp) +static int s2io_card_up(struct s2io_nic *sp) { int i, ret = 0; struct mac_info *mac_control; struct config_param *config; - struct net_device *dev = (struct net_device *) sp->dev; + struct net_device *dev = (struct net_device *)sp->dev; u16 interruptible; /* Initialize the H/W I/O registers */ @@ -7264,7 +7292,7 @@ static int s2io_card_up(struct s2io_nic * sp) sp->promisc_flg = 0; if (sp->m_cast_flg) { sp->m_cast_flg = 0; - sp->all_multi_pos= 0; + sp->all_multi_pos = 0; } /* Setting its receive mode */ @@ -7273,7 +7301,7 @@ static int s2io_card_up(struct s2io_nic * sp) if (sp->lro) { /* Initialize max aggregatable pkts per session based on MTU */ sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu; - /* Check if we can use(if specified) user provided value */ + /* Check if we can use (if specified) user provided value */ if (lro_max_pkts < sp->lro_max_aggr_per_sess) sp->lro_max_aggr_per_sess = lro_max_pkts; } @@ -7335,12 +7363,10 @@ static void s2io_restart_nic(struct work_struct *work) s2io_card_down(sp); if (s2io_card_up(sp)) { - DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n", - dev->name); + DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n", dev->name); } s2io_wake_all_tx_queue(sp); - DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n", - dev->name); + DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n", dev->name); out_unlock: rtnl_unlock(); } @@ -7389,9 +7415,9 @@ static void s2io_tx_watchdog(struct net_device *dev) static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) { struct s2io_nic *sp = ring_data->nic; - struct net_device *dev = (struct net_device *) ring_data->dev; + struct net_device *dev = (struct net_device *)ring_data->dev; struct sk_buff *skb = (struct sk_buff *) - ((unsigned long) rxdp->Host_Control); + ((unsigned long)rxdp->Host_Control); int ring_no = ring_data->ring_no; u16 l3_csum, l4_csum; unsigned long long err = rxdp->Control_1 & RXD_T_CODE; @@ -7402,66 +7428,57 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) if (err) { /* Check for parity error */ - if (err & 0x1) { + if (err & 0x1) sp->mac_control.stats_info->sw_stat.parity_err_cnt++; - } + err_mask = err >> 48; - switch(err_mask) { - case 1: - sp->mac_control.stats_info->sw_stat. - rx_parity_err_cnt++; + switch (err_mask) { + case 1: + sp->mac_control.stats_info->sw_stat.rx_parity_err_cnt++; break; - case 2: - sp->mac_control.stats_info->sw_stat. - rx_abort_cnt++; + case 2: + sp->mac_control.stats_info->sw_stat.rx_abort_cnt++; break; - case 3: - sp->mac_control.stats_info->sw_stat. - rx_parity_abort_cnt++; + case 3: + sp->mac_control.stats_info->sw_stat.rx_parity_abort_cnt++; break; - case 4: - sp->mac_control.stats_info->sw_stat. - rx_rda_fail_cnt++; + case 4: + sp->mac_control.stats_info->sw_stat.rx_rda_fail_cnt++; break; - case 5: - sp->mac_control.stats_info->sw_stat. - rx_unkn_prot_cnt++; + case 5: + sp->mac_control.stats_info->sw_stat.rx_unkn_prot_cnt++; break; - case 6: - sp->mac_control.stats_info->sw_stat. - rx_fcs_err_cnt++; + case 6: + sp->mac_control.stats_info->sw_stat.rx_fcs_err_cnt++; break; - case 7: - sp->mac_control.stats_info->sw_stat. - rx_buf_size_err_cnt++; + case 7: + sp->mac_control.stats_info->sw_stat.rx_buf_size_err_cnt++; break; - case 8: - sp->mac_control.stats_info->sw_stat. - rx_rxd_corrupt_cnt++; + case 8: + sp->mac_control.stats_info->sw_stat.rx_rxd_corrupt_cnt++; break; - case 15: - sp->mac_control.stats_info->sw_stat. - rx_unkn_err_cnt++; + case 15: + sp->mac_control.stats_info->sw_stat.rx_unkn_err_cnt++; break; } /* - * Drop the packet if bad transfer code. Exception being - * 0x5, which could be due to unsupported IPv6 extension header. - * In this case, we let stack handle the packet. - * Note that in this case, since checksum will be incorrect, - * stack will validate the same. - */ + * Drop the packet if bad transfer code. Exception being + * 0x5, which could be due to unsupported IPv6 extension header. + * In this case, we let stack handle the packet. + * Note that in this case, since checksum will be incorrect, + * stack will validate the same. + */ if (err_mask != 0x5) { DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%x\n", - dev->name, err_mask); + dev->name, err_mask); dev->stats.rx_crc_errors++; sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize; @@ -7494,8 +7511,9 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) skb_put(skb, buf2_len); } - if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!ring_data->lro) || - (ring_data->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) && + if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && + ((!ring_data->lro) || + (ring_data->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) && (sp->rx_csum)) { l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1); l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1); @@ -7512,52 +7530,44 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) int ret = 0; ret = s2io_club_tcp_session(ring_data, - skb->data, &tcp, &tcp_len, &lro, - rxdp, sp); + skb->data, &tcp, + &tcp_len, &lro, + rxdp, sp); switch (ret) { - case 3: /* Begin anew */ - lro->parent = skb; - goto aggregate; - case 1: /* Aggregate */ - { - lro_append_pkt(sp, lro, - skb, tcp_len); - goto aggregate; - } - case 4: /* Flush session */ - { - lro_append_pkt(sp, lro, - skb, tcp_len); - queue_rx_frame(lro->parent, - lro->vlan_tag); - clear_lro_session(lro); - sp->mac_control.stats_info-> - sw_stat.flush_max_pkts++; - goto aggregate; - } - case 2: /* Flush both */ - lro->parent->data_len = - lro->frags_len; - sp->mac_control.stats_info-> - sw_stat.sending_both++; - queue_rx_frame(lro->parent, - lro->vlan_tag); - clear_lro_session(lro); - goto send_up; - case 0: /* sessions exceeded */ - case -1: /* non-TCP or not - * L2 aggregatable - */ - case 5: /* - * First pkt in session not - * L3/L4 aggregatable - */ - break; - default: - DBG_PRINT(ERR_DBG, - "%s: Samadhana!!\n", - __func__); - BUG(); + case 3: /* Begin anew */ + lro->parent = skb; + goto aggregate; + case 1: /* Aggregate */ + lro_append_pkt(sp, lro, skb, tcp_len); + goto aggregate; + case 4: /* Flush session */ + lro_append_pkt(sp, lro, skb, tcp_len); + queue_rx_frame(lro->parent, + lro->vlan_tag); + clear_lro_session(lro); + sp->mac_control.stats_info-> + sw_stat.flush_max_pkts++; + goto aggregate; + case 2: /* Flush both */ + lro->parent->data_len = lro->frags_len; + sp->mac_control.stats_info-> + sw_stat.sending_both++; + queue_rx_frame(lro->parent, + lro->vlan_tag); + clear_lro_session(lro); + goto send_up; + case 0: /* sessions exceeded */ + case -1: /* non-TCP or not L2 aggregatable */ + case 5: /* + * First pkt in session not + * L3/L4 aggregatable + */ + break; + default: + DBG_PRINT(ERR_DBG, + "%s: Samadhana!!\n", + __func__); + BUG(); } } } else { @@ -7592,9 +7602,9 @@ aggregate: * void. */ -static void s2io_link(struct s2io_nic * sp, int link) +static void s2io_link(struct s2io_nic *sp, int link) { - struct net_device *dev = (struct net_device *) sp->dev; + struct net_device *dev = (struct net_device *)sp->dev; if (link != sp->last_link_state) { init_tti(sp, link); @@ -7602,15 +7612,16 @@ static void s2io_link(struct s2io_nic * sp, int link) DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name); s2io_stop_all_tx_queue(sp); netif_carrier_off(dev); - if(sp->mac_control.stats_info->sw_stat.link_up_cnt) - sp->mac_control.stats_info->sw_stat.link_up_time = - jiffies - sp->start_time; + if (sp->mac_control.stats_info->sw_stat.link_up_cnt) + sp->mac_control.stats_info->sw_stat. + link_up_time = jiffies - sp->start_time; sp->mac_control.stats_info->sw_stat.link_down_cnt++; } else { DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name); if (sp->mac_control.stats_info->sw_stat.link_down_cnt) - sp->mac_control.stats_info->sw_stat.link_down_time = - jiffies - sp->start_time; + sp->mac_control.stats_info-> + sw_stat.link_down_time = + jiffies - sp->start_time; sp->mac_control.stats_info->sw_stat.link_up_cnt++; netif_carrier_on(dev); s2io_wake_all_tx_queue(sp); @@ -7631,7 +7642,7 @@ static void s2io_link(struct s2io_nic * sp, int link) * void */ -static void s2io_init_pci(struct s2io_nic * sp) +static void s2io_init_pci(struct s2io_nic *sp) { u16 pci_cmd = 0, pcix_cmd = 0; @@ -7651,12 +7662,11 @@ static void s2io_init_pci(struct s2io_nic * sp) } static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, - u8 *dev_multiq) + u8 *dev_multiq) { - if ((tx_fifo_num > MAX_TX_FIFOS) || - (tx_fifo_num < 1)) { + if ((tx_fifo_num > MAX_TX_FIFOS) || (tx_fifo_num < 1)) { DBG_PRINT(ERR_DBG, "s2io: Requested number of tx fifos " - "(%d) not supported\n", tx_fifo_num); + "(%d) not supported\n", tx_fifo_num); if (tx_fifo_num < 1) tx_fifo_num = 1; @@ -7673,24 +7683,24 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, if (tx_steering_type && (1 == tx_fifo_num)) { if (tx_steering_type != TX_DEFAULT_STEERING) DBG_PRINT(ERR_DBG, - "s2io: Tx steering is not supported with " - "one fifo. Disabling Tx steering.\n"); + "s2io: Tx steering is not supported with " + "one fifo. Disabling Tx steering.\n"); tx_steering_type = NO_STEERING; } if ((tx_steering_type < NO_STEERING) || - (tx_steering_type > TX_DEFAULT_STEERING)) { - DBG_PRINT(ERR_DBG, "s2io: Requested transmit steering not " - "supported\n"); + (tx_steering_type > TX_DEFAULT_STEERING)) { + DBG_PRINT(ERR_DBG, + "s2io: Requested transmit steering not supported\n"); DBG_PRINT(ERR_DBG, "s2io: Disabling transmit steering\n"); tx_steering_type = NO_STEERING; } if (rx_ring_num > MAX_RX_RINGS) { - DBG_PRINT(ERR_DBG, "s2io: Requested number of rx rings not " - "supported\n"); + DBG_PRINT(ERR_DBG, + "s2io: Requested number of rx rings not supported\n"); DBG_PRINT(ERR_DBG, "s2io: Default to %d rx rings\n", - MAX_RX_RINGS); + MAX_RX_RINGS); rx_ring_num = MAX_RX_RINGS; } @@ -7701,10 +7711,10 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, } if ((*dev_intr_type == MSI_X) && - ((pdev->device != PCI_DEVICE_ID_HERC_WIN) && - (pdev->device != PCI_DEVICE_ID_HERC_UNI))) { + ((pdev->device != PCI_DEVICE_ID_HERC_WIN) && + (pdev->device != PCI_DEVICE_ID_HERC_UNI))) { DBG_PRINT(ERR_DBG, "s2io: Xframe I does not support MSI_X. " - "Defaulting to INTA\n"); + "Defaulting to INTA\n"); *dev_intr_type = INTA; } @@ -7743,8 +7753,8 @@ static int rts_ds_steer(struct s2io_nic *nic, u8 ds_codepoint, u8 ring) writeq(val64, &bar0->rts_ds_mem_ctrl); return wait_for_cmd_complete(&bar0->rts_ds_mem_ctrl, - RTS_DS_MEM_CTRL_STROBE_CMD_BEING_EXECUTED, - S2IO_BIT_RESET); + RTS_DS_MEM_CTRL_STROBE_CMD_BEING_EXECUTED, + S2IO_BIT_RESET); } static const struct net_device_ops s2io_netdev_ops = { @@ -7800,7 +7810,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (ret) return ret; - if ((ret = pci_enable_device(pdev))) { + ret = pci_enable_device(pdev); + if (ret) { DBG_PRINT(ERR_DBG, "s2io_init_nic: pci_enable_device failed\n"); return ret; @@ -7809,11 +7820,10 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n"); dma_flag = true; - if (pci_set_consistent_dma_mask - (pdev, DMA_BIT_MASK(64))) { + if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { DBG_PRINT(ERR_DBG, - "Unable to obtain 64bit DMA for \ - consistent allocations\n"); + "Unable to obtain 64bit DMA " + "for consistent allocations\n"); pci_disable_device(pdev); return -ENOMEM; } @@ -7823,8 +7833,10 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) pci_disable_device(pdev); return -ENOMEM; } - if ((ret = pci_request_regions(pdev, s2io_driver_name))) { - DBG_PRINT(ERR_DBG, "%s: Request Regions failed - %x \n", __func__, ret); + ret = pci_request_regions(pdev, s2io_driver_name); + if (ret) { + DBG_PRINT(ERR_DBG, "%s: Request Regions failed - %x \n", + __func__, ret); pci_disable_device(pdev); return -ENODEV; } @@ -7858,7 +7870,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) sp->config.intr_type = dev_intr_type; if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) || - (pdev->device == PCI_DEVICE_ID_HERC_UNI)) + (pdev->device == PCI_DEVICE_ID_HERC_UNI)) sp->device_type = XFRAME_II_DEVICE; else sp->device_type = XFRAME_I_DEVICE; @@ -7889,16 +7901,16 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* Initialize the fifos used for tx steering */ if (config->tx_fifo_num < 5) { - if (config->tx_fifo_num == 1) - sp->total_tcp_fifos = 1; - else - sp->total_tcp_fifos = config->tx_fifo_num - 1; - sp->udp_fifo_idx = config->tx_fifo_num - 1; - sp->total_udp_fifos = 1; - sp->other_fifo_idx = sp->total_tcp_fifos - 1; + if (config->tx_fifo_num == 1) + sp->total_tcp_fifos = 1; + else + sp->total_tcp_fifos = config->tx_fifo_num - 1; + sp->udp_fifo_idx = config->tx_fifo_num - 1; + sp->total_udp_fifos = 1; + sp->other_fifo_idx = sp->total_tcp_fifos - 1; } else { sp->total_tcp_fifos = (tx_fifo_num - FIFO_UDP_MAX_NUM - - FIFO_OTHER_MAX_NUM); + FIFO_OTHER_MAX_NUM); sp->udp_fifo_idx = sp->total_tcp_fifos; sp->total_udp_fifos = FIFO_UDP_MAX_NUM; sp->other_fifo_idx = sp->udp_fifo_idx + FIFO_UDP_MAX_NUM; @@ -7964,8 +7976,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* initialize the shared memory used by the NIC and the host */ if (init_shared_mem(sp)) { - DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", - dev->name); + DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", dev->name); ret = -ENOMEM; goto mem_alloc_failed; } @@ -7987,12 +7998,13 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) } dev->irq = pdev->irq; - dev->base_addr = (unsigned long) sp->bar0; + dev->base_addr = (unsigned long)sp->bar0; /* Initializing the BAR1 address as the start of the FIFO pointer. */ for (j = 0; j < MAX_TX_FIFOS; j++) { - mac_control->tx_FIFO_start[j] = (struct TxFIFO_element __iomem *) - (sp->bar1 + (j * 0x00020000)); + mac_control->tx_FIFO_start[j] = + (struct TxFIFO_element __iomem *) + (sp->bar1 + (j * 0x00020000)); } /* Driver entry points */ @@ -8046,7 +8058,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (ret) { DBG_PRINT(ERR_DBG, - "s2io: MSI-X requested but failed to enable\n"); + "s2io: MSI-X requested but failed to enable\n"); sp->config.intr_type = INTA; } } @@ -8077,12 +8089,13 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) */ bar0 = sp->bar0; val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | - RMAC_ADDR_CMD_MEM_OFFSET(0 + S2IO_MAC_ADDR_START_OFFSET); + RMAC_ADDR_CMD_MEM_OFFSET(0 + S2IO_MAC_ADDR_START_OFFSET); writeq(val64, &bar0->rmac_addr_cmd_mem); wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET); + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET); tmp64 = readq(&bar0->rmac_addr_data0_mem); - mac_down = (u32) tmp64; + mac_down = (u32)tmp64; mac_up = (u32) (tmp64 >> 32); sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_up); @@ -8113,10 +8126,10 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* Configure MSIX vector for number of rings configured plus one */ if ((sp->device_type == XFRAME_II_DEVICE) && - (config->intr_type == MSI_X)) + (config->intr_type == MSI_X)) sp->num_entries = config->rx_ring_num + 1; - /* Store the values of the MSIX table in the s2io_nic structure */ + /* Store the values of the MSIX table in the s2io_nic structure */ store_xmsi_data(sp); /* reset Nic and bring it to known state */ s2io_reset(sp); @@ -8144,7 +8157,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) val64 |= 0x0000800000000000ULL; writeq(val64, &bar0->gpio_control); val64 = 0x0411040400000000ULL; - writeq(val64, (void __iomem *) bar0 + 0x2700); + writeq(val64, (void __iomem *)bar0 + 0x2700); val64 = readq(&bar0->gpio_control); } @@ -8157,7 +8170,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) } s2io_vpd_read(sp); DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2007 Neterion Inc.\n"); - DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n",dev->name, + DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n", dev->name, sp->product_name, pdev->revision); DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name, s2io_driver_version); @@ -8172,15 +8185,15 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) goto set_swap_failed; } } - switch(sp->rxd_mode) { - case RXD_MODE_1: - DBG_PRINT(ERR_DBG, "%s: 1-Buffer receive mode enabled\n", - dev->name); - break; - case RXD_MODE_3B: - DBG_PRINT(ERR_DBG, "%s: 2-Buffer receive mode enabled\n", - dev->name); - break; + switch (sp->rxd_mode) { + case RXD_MODE_1: + DBG_PRINT(ERR_DBG, "%s: 1-Buffer receive mode enabled\n", + dev->name); + break; + case RXD_MODE_3B: + DBG_PRINT(ERR_DBG, "%s: 2-Buffer receive mode enabled\n", + dev->name); + break; } switch (sp->config.napi) { @@ -8193,18 +8206,18 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) } DBG_PRINT(ERR_DBG, "%s: Using %d Tx fifo(s)\n", dev->name, - sp->config.tx_fifo_num); + sp->config.tx_fifo_num); DBG_PRINT(ERR_DBG, "%s: Using %d Rx ring(s)\n", dev->name, sp->config.rx_ring_num); - switch(sp->config.intr_type) { - case INTA: - DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name); - break; - case MSI_X: - DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI-X\n", dev->name); - break; + switch (sp->config.intr_type) { + case INTA: + DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name); + break; + case MSI_X: + DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI-X\n", dev->name); + break; } if (sp->config.multiq) { for (i = 0; i < sp->config.tx_fifo_num; i++) { @@ -8213,31 +8226,34 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) fifo->multiq = config->multiq; } DBG_PRINT(ERR_DBG, "%s: Multiqueue support enabled\n", - dev->name); + dev->name); } else DBG_PRINT(ERR_DBG, "%s: Multiqueue support disabled\n", - dev->name); + dev->name); switch (sp->config.tx_steering_type) { case NO_STEERING: - DBG_PRINT(ERR_DBG, "%s: No steering enabled for" - " transmit\n", dev->name); - break; + DBG_PRINT(ERR_DBG, "%s: No steering enabled for transmit\n", + dev->name); + break; case TX_PRIORITY_STEERING: - DBG_PRINT(ERR_DBG, "%s: Priority steering enabled for" - " transmit\n", dev->name); + DBG_PRINT(ERR_DBG, + "%s: Priority steering enabled for transmit\n", + dev->name); break; case TX_DEFAULT_STEERING: - DBG_PRINT(ERR_DBG, "%s: Default steering enabled for" - " transmit\n", dev->name); + DBG_PRINT(ERR_DBG, + "%s: Default steering enabled for transmit\n", + dev->name); } if (sp->lro) DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n", dev->name); if (ufo) - DBG_PRINT(ERR_DBG, "%s: UDP Fragmentation Offload(UFO)" - " enabled\n", dev->name); + DBG_PRINT(ERR_DBG, + "%s: UDP Fragmentation Offload(UFO) enabled\n", + dev->name); /* Initialize device name */ sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name); @@ -8255,13 +8271,13 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) return 0; - register_failed: - set_swap_failed: +register_failed: +set_swap_failed: iounmap(sp->bar1); - bar1_remap_failed: +bar1_remap_failed: iounmap(sp->bar0); - bar0_remap_failed: - mem_alloc_failed: +bar0_remap_failed: +mem_alloc_failed: free_shared_mem(sp); pci_disable_device(pdev); pci_release_regions(pdev); @@ -8283,7 +8299,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) static void __devexit s2io_rem_nic(struct pci_dev *pdev) { struct net_device *dev = - (struct net_device *) pci_get_drvdata(pdev); + (struct net_device *)pci_get_drvdata(pdev); struct s2io_nic *sp; if (dev == NULL) { @@ -8331,28 +8347,28 @@ module_init(s2io_starter); module_exit(s2io_closer); static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip, - struct tcphdr **tcp, struct RxD_t *rxdp, - struct s2io_nic *sp) + struct tcphdr **tcp, struct RxD_t *rxdp, + struct s2io_nic *sp) { int ip_off; u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len; if (!(rxdp->Control_1 & RXD_FRAME_PROTO_TCP)) { - DBG_PRINT(INIT_DBG,"%s: Non-TCP frames not supported for LRO\n", + DBG_PRINT(INIT_DBG, + "%s: Non-TCP frames not supported for LRO\n", __func__); return -1; } /* Checking for DIX type or DIX type with VLAN */ - if ((l2_type == 0) - || (l2_type == 4)) { + if ((l2_type == 0) || (l2_type == 4)) { ip_off = HEADER_ETHERNET_II_802_3_SIZE; /* * If vlan stripping is disabled and the frame is VLAN tagged, * shift the offset by the VLAN header size bytes. */ if ((!sp->vlan_strip_flag) && - (rxdp->Control_1 & RXD_FRAME_VLAN_TAG)) + (rxdp->Control_1 & RXD_FRAME_VLAN_TAG)) ip_off += HEADER_VLAN_SIZE; } else { /* LLC, SNAP etc are considered non-mergeable */ @@ -8370,22 +8386,25 @@ static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip, static int check_for_socket_match(struct lro *lro, struct iphdr *ip, struct tcphdr *tcp) { - DBG_PRINT(INFO_DBG,"%s: Been here...\n", __func__); - if ((lro->iph->saddr != ip->saddr) || (lro->iph->daddr != ip->daddr) || - (lro->tcph->source != tcp->source) || (lro->tcph->dest != tcp->dest)) + DBG_PRINT(INFO_DBG, "%s: Been here...\n", __func__); + if ((lro->iph->saddr != ip->saddr) || + (lro->iph->daddr != ip->daddr) || + (lro->tcph->source != tcp->source) || + (lro->tcph->dest != tcp->dest)) return -1; return 0; } static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp) { - return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2)); + return ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2); } static void initiate_new_session(struct lro *lro, u8 *l2h, - struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len, u16 vlan_tag) + struct iphdr *ip, struct tcphdr *tcp, + u32 tcp_pyld_len, u16 vlan_tag) { - DBG_PRINT(INFO_DBG,"%s: Been here...\n", __func__); + DBG_PRINT(INFO_DBG, "%s: Been here...\n", __func__); lro->l2h = l2h; lro->iph = ip; lro->tcph = tcp; @@ -8396,9 +8415,9 @@ static void initiate_new_session(struct lro *lro, u8 *l2h, lro->frags_len = 0; lro->vlan_tag = vlan_tag; /* - * check if we saw TCP timestamp. Other consistency checks have - * already been done. - */ + * Check if we saw TCP timestamp. + * Other consistency checks have already been done. + */ if (tcp->doff == 8) { __be32 *ptr; ptr = (__be32 *)(tcp+1); @@ -8415,7 +8434,7 @@ static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro) struct tcphdr *tcp = lro->tcph; __sum16 nchk; struct stat_block *statinfo = sp->mac_control.stats_info; - DBG_PRINT(INFO_DBG,"%s: Been here...\n", __func__); + DBG_PRINT(INFO_DBG, "%s: Been here...\n", __func__); /* Update L3 header */ ip->tot_len = htons(lro->total_len); @@ -8441,9 +8460,9 @@ static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro) } static void aggregate_new_rx(struct lro *lro, struct iphdr *ip, - struct tcphdr *tcp, u32 l4_pyld) + struct tcphdr *tcp, u32 l4_pyld) { - DBG_PRINT(INFO_DBG,"%s: Been here...\n", __func__); + DBG_PRINT(INFO_DBG, "%s: Been here...\n", __func__); lro->total_len += l4_pyld; lro->frags_len += l4_pyld; lro->tcp_next_seq += l4_pyld; @@ -8467,7 +8486,7 @@ static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip, { u8 *ptr; - DBG_PRINT(INFO_DBG,"%s: Been here...\n", __func__); + DBG_PRINT(INFO_DBG, "%s: Been here...\n", __func__); if (!tcp_pyld_len) { /* Runt frame or a pure ack */ @@ -8482,8 +8501,9 @@ static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip, return -1; /* If we see ECE or CWR flags in TCP header, packet is not mergeable */ - if (tcp->urg || tcp->psh || tcp->rst || tcp->syn || tcp->fin || - tcp->ece || tcp->cwr || !tcp->ack) { + if (tcp->urg || tcp->psh || tcp->rst || + tcp->syn || tcp->fin || + tcp->ece || tcp->cwr || !tcp->ack) { /* * Currently recognize only the ack control word and * any other control field being set would result in @@ -8519,27 +8539,26 @@ static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip, return 0; } -static int -s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, u8 **tcp, - u32 *tcp_len, struct lro **lro, struct RxD_t *rxdp, - struct s2io_nic *sp) +static int s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, + u8 **tcp, u32 *tcp_len, struct lro **lro, + struct RxD_t *rxdp, struct s2io_nic *sp) { struct iphdr *ip; struct tcphdr *tcph; int ret = 0, i; u16 vlan_tag = 0; - if (!(ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp, - rxdp, sp))) { - DBG_PRINT(INFO_DBG,"IP Saddr: %x Daddr: %x\n", - ip->saddr, ip->daddr); - } else + ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp, + rxdp, sp); + if (ret) return ret; + DBG_PRINT(INFO_DBG, "IP Saddr: %x Daddr: %x\n", ip->saddr, ip->daddr); + vlan_tag = RXD_GET_VLAN_TAG(rxdp->Control_2); tcph = (struct tcphdr *)*tcp; *tcp_len = get_l4_pyld_length(ip, tcph); - for (i=0; ilro0_n[i]; if (l_lro->in_use) { if (check_for_socket_match(l_lro, ip, tcph)) @@ -8554,12 +8573,13 @@ s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, u8 **tcp, ntohl(tcph->seq)); sp->mac_control.stats_info-> - sw_stat.outof_sequence_pkts++; + sw_stat.outof_sequence_pkts++; ret = 2; break; } - if (!verify_l3_l4_lro_capable(l_lro, ip, tcph,*tcp_len)) + if (!verify_l3_l4_lro_capable(l_lro, ip, tcph, + *tcp_len)) ret = 1; /* Aggregate */ else ret = 2; /* Flush both */ @@ -8573,11 +8593,10 @@ s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, u8 **tcp, * don't create new LRO session. Just send this * packet up. */ - if (verify_l3_l4_lro_capable(NULL, ip, tcph, *tcp_len)) { + if (verify_l3_l4_lro_capable(NULL, ip, tcph, *tcp_len)) return 5; - } - for (i=0; ilro0_n[i]; if (!(l_lro->in_use)) { *lro = l_lro; @@ -8588,31 +8607,30 @@ s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, u8 **tcp, } if (ret == 0) { /* sessions exceeded */ - DBG_PRINT(INFO_DBG,"%s:All LRO sessions already in use\n", + DBG_PRINT(INFO_DBG, "%s:All LRO sessions already in use\n", __func__); *lro = NULL; return ret; } switch (ret) { - case 3: - initiate_new_session(*lro, buffer, ip, tcph, *tcp_len, - vlan_tag); - break; - case 2: + case 3: + initiate_new_session(*lro, buffer, ip, tcph, *tcp_len, + vlan_tag); + break; + case 2: + update_L3L4_header(sp, *lro); + break; + case 1: + aggregate_new_rx(*lro, ip, tcph, *tcp_len); + if ((*lro)->sg_num == sp->lro_max_aggr_per_sess) { update_L3L4_header(sp, *lro); - break; - case 1: - aggregate_new_rx(*lro, ip, tcph, *tcp_len); - if ((*lro)->sg_num == sp->lro_max_aggr_per_sess) { - update_L3L4_header(sp, *lro); - ret = 4; /* Flush the LRO */ - } - break; - default: - DBG_PRINT(ERR_DBG,"%s:Dont know, can't say!!\n", - __func__); - break; + ret = 4; /* Flush the LRO */ + } + break; + default: + DBG_PRINT(ERR_DBG, "%s:Dont know, can't say!!\n", __func__); + break; } return ret; @@ -8631,8 +8649,7 @@ static void queue_rx_frame(struct sk_buff *skb, u16 vlan_tag) struct s2io_nic *sp = netdev_priv(dev); skb->protocol = eth_type_trans(skb, dev); - if (sp->vlgrp && vlan_tag - && (sp->vlan_strip_flag)) { + if (sp->vlgrp && vlan_tag && (sp->vlan_strip_flag)) { /* Queueing the vlan frame to the upper layer */ if (sp->config.napi) vlan_hwaccel_receive_skb(skb, sp->vlgrp, vlan_tag); @@ -8647,8 +8664,7 @@ static void queue_rx_frame(struct sk_buff *skb, u16 vlan_tag) } static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro, - struct sk_buff *skb, - u32 tcp_len) + struct sk_buff *skb, u32 tcp_len) { struct sk_buff *first = lro->parent; @@ -8674,7 +8690,7 @@ static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro, * this device has been detected. */ static pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev, - pci_channel_state_t state) + pci_channel_state_t state) { struct net_device *netdev = pci_get_drvdata(pdev); struct s2io_nic *sp = netdev_priv(netdev); -- cgit v1.2.3-18-g5258 From 6cef2b8eb73f1a8fd7c0ed528091ddc406fef950 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 24 Aug 2009 17:29:45 +0000 Subject: s2io.c: convert printks to pr_ Fixed trivial typo as well Signed-off-by: Joe Perches Acked-by: Sreenivasa Honnur Signed-off-by: David S. Miller --- drivers/net/s2io.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 003dd8c4734..2805edd1a9c 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -54,6 +54,8 @@ * Possible values '1' for enable and '0' for disable. Default is '0' ************************************************************************/ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -5547,8 +5549,7 @@ static int s2io_ethtool_idnic(struct net_device *dev, u32 data) if ((sp->device_type == XFRAME_I_DEVICE) && ((subid & 0xFF) < 0x07)) { val64 = readq(&bar0->adapter_control); if (!(val64 & ADAPTER_CNTL_EN)) { - printk(KERN_ERR - "Adapter Link down, cannot blink LED\n"); + pr_err("Adapter Link down, cannot blink LED\n"); return -EFAULT; } } @@ -7130,8 +7131,7 @@ static int s2io_add_isr(struct s2io_nic *sp) } } if (!err) { - printk(KERN_INFO "MSI-X-RX %d entries enabled\n", - --msix_rx_cnt); + pr_info("MSI-X-RX %d entries enabled\n", --msix_rx_cnt); DBG_PRINT(INFO_DBG, "MSI-X-TX entries enabled" " through alarm vector\n"); } @@ -8724,8 +8724,7 @@ static pci_ers_result_t s2io_io_slot_reset(struct pci_dev *pdev) struct s2io_nic *sp = netdev_priv(netdev); if (pci_enable_device(pdev)) { - printk(KERN_ERR "s2io: " - "Cannot re-enable PCI device after reset.\n"); + pr_err("Cannot re-enable PCI device after reset.\n"); return PCI_ERS_RESULT_DISCONNECT; } @@ -8749,15 +8748,13 @@ static void s2io_io_resume(struct pci_dev *pdev) if (netif_running(netdev)) { if (s2io_card_up(sp)) { - printk(KERN_ERR "s2io: " - "Can't bring device back up after reset.\n"); + pr_err("Can't bring device back up after reset.\n"); return; } if (s2io_set_mac_addr(netdev, netdev->dev_addr) == FAILURE) { s2io_card_down(sp); - printk(KERN_ERR "s2io: " - "Can't resetore mac addr after reset.\n"); + pr_err("Can't restore mac addr after reset.\n"); return; } } -- cgit v1.2.3-18-g5258 From a2a20aef44da92b1c3b8c86ea069117dc3bc8bd6 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 24 Aug 2009 17:29:46 +0000 Subject: s2io.c: fix spelling explaination Signed-off-by: Joe Perches Acked-by: Sreenivasa Honnur Signed-off-by: David S. Miller --- drivers/net/s2io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 2805edd1a9c..4897f0449db 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -25,7 +25,7 @@ * Christopher Hellwig : Some more 2.6 specific issues in the driver. * * The module loadable parameters that are supported by the driver and a brief - * explaination of all the variables. + * explanation of all the variables. * * rx_ring_num : This can be used to program the number of receive rings used * in the driver. -- cgit v1.2.3-18-g5258 From ffb5df6ce776a05eec1fbe4876cc6603c6336140 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 24 Aug 2009 17:29:47 +0000 Subject: s2io.c: Standardize statistics accessors Regularize the declaration and uses of struct config_param *config = &sp->config; struct mac_info *mac_control = &sp->mac_control; and use struct stat_block *stats = mac_control->stats_info; struct swStat *swstats = &stats->sw_stat; struct xpakStat *xstats = &stats->xpak_stat; and convert the longish uses like nic->mac_control.stats_info->sw_stat. to swstats-> etc. This also makes the statistics code marginally smaller and presumably faster. Old: $ size s2io.o text data bss dec hex filename 114289 516 33360 148165 242c5 s2io.o New: $ size s2io.o text data bss dec hex filename 114097 516 33360 147973 24205 s2io.o Signed-off-by: Joe Perches Acked-by: Sreenivasa Honnur Signed-off-by: David S. Miller --- drivers/net/s2io.c | 851 +++++++++++++++++++++++++---------------------------- 1 file changed, 408 insertions(+), 443 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 4897f0449db..06223dfd2e8 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -363,8 +363,8 @@ static void s2io_vlan_rx_register(struct net_device *dev, int i; struct s2io_nic *nic = netdev_priv(dev); unsigned long flags[MAX_TX_FIFOS]; - struct mac_info *mac_control = &nic->mac_control; struct config_param *config = &nic->config; + struct mac_info *mac_control = &nic->mac_control; for (i = 0; i < config->tx_fifo_num; i++) { struct fifo_info *fifo = &mac_control->fifos[i]; @@ -387,8 +387,8 @@ static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) int i; struct s2io_nic *nic = netdev_priv(dev); unsigned long flags[MAX_TX_FIFOS]; - struct mac_info *mac_control = &nic->mac_control; struct config_param *config = &nic->config; + struct mac_info *mac_control = &nic->mac_control; for (i = 0; i < config->tx_fifo_num; i++) { struct fifo_info *fifo = &mac_control->fifos[i]; @@ -640,14 +640,10 @@ static int init_shared_mem(struct s2io_nic *nic) struct net_device *dev = nic->dev; unsigned long tmp; struct buffAdd *ba; - - struct mac_info *mac_control; - struct config_param *config; + struct config_param *config = &nic->config; + struct mac_info *mac_control = &nic->mac_control; unsigned long long mem_allocated = 0; - mac_control = &nic->mac_control; - config = &nic->config; - /* Allocation and initialization of TXDLs in FIFOs */ size = 0; for (i = 0; i < config->tx_fifo_num; i++) { @@ -949,19 +945,23 @@ static void free_shared_mem(struct s2io_nic *nic) int i, j, blk_cnt, size; void *tmp_v_addr; dma_addr_t tmp_p_addr; - struct mac_info *mac_control; - struct config_param *config; int lst_size, lst_per_page; struct net_device *dev; int page_num = 0; + struct config_param *config; + struct mac_info *mac_control; + struct stat_block *stats; + struct swStat *swstats; if (!nic) return; dev = nic->dev; - mac_control = &nic->mac_control; config = &nic->config; + mac_control = &nic->mac_control; + stats = mac_control->stats_info; + swstats = &stats->sw_stat; lst_size = sizeof(struct TxD) * config->max_txds; lst_per_page = PAGE_SIZE / lst_size; @@ -984,8 +984,7 @@ static void free_shared_mem(struct s2io_nic *nic) pci_free_consistent(nic->pdev, PAGE_SIZE, fli->list_virt_addr, fli->list_phy_addr); - nic->mac_control.stats_info->sw_stat.mem_freed - += PAGE_SIZE; + swstats->mem_freed += PAGE_SIZE; } /* If we got a zero DMA address during allocation, * free the page now @@ -999,12 +998,10 @@ static void free_shared_mem(struct s2io_nic *nic) dev->name); DBG_PRINT(INIT_DBG, "Virtual address %p\n", mac_control->zerodma_virt_addr); - nic->mac_control.stats_info->sw_stat.mem_freed - += PAGE_SIZE; + swstats->mem_freed += PAGE_SIZE; } kfree(fifo->list_info); - nic->mac_control.stats_info->sw_stat.mem_freed += - nic->config.tx_cfg[i].fifo_len * + swstats->mem_freed += nic->config.tx_cfg[i].fifo_len * sizeof(struct list_info_hold); } @@ -1020,10 +1017,10 @@ static void free_shared_mem(struct s2io_nic *nic) break; pci_free_consistent(nic->pdev, size, tmp_v_addr, tmp_p_addr); - nic->mac_control.stats_info->sw_stat.mem_freed += size; + swstats->mem_freed += size; kfree(ring->rx_blocks[j].rxds); - nic->mac_control.stats_info->sw_stat.mem_freed += - sizeof(struct rxd_info) * rxd_count[nic->rxd_mode]; + swstats->mem_freed += sizeof(struct rxd_info) * + rxd_count[nic->rxd_mode]; } } @@ -1042,21 +1039,20 @@ static void free_shared_mem(struct s2io_nic *nic) while (k != rxd_count[nic->rxd_mode]) { struct buffAdd *ba = &ring->ba[j][k]; kfree(ba->ba_0_org); - nic->mac_control.stats_info->sw_stat.\ - mem_freed += (BUF0_LEN + ALIGN_SIZE); + swstats->mem_freed += + BUF0_LEN + ALIGN_SIZE; kfree(ba->ba_1_org); - nic->mac_control.stats_info->sw_stat.\ - mem_freed += (BUF1_LEN + ALIGN_SIZE); + swstats->mem_freed += + BUF1_LEN + ALIGN_SIZE; k++; } kfree(ring->ba[j]); - nic->mac_control.stats_info->sw_stat.mem_freed += - (sizeof(struct buffAdd) * - (rxd_count[nic->rxd_mode] + 1)); + swstats->mem_freed += sizeof(struct buffAdd) * + (rxd_count[nic->rxd_mode] + 1); } kfree(ring->ba); - nic->mac_control.stats_info->sw_stat.mem_freed += - (sizeof(struct buffAdd *) * blk_cnt); + swstats->mem_freed += sizeof(struct buffAdd *) * + blk_cnt; } } @@ -1065,15 +1061,14 @@ static void free_shared_mem(struct s2io_nic *nic) struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; if (fifo->ufo_in_band_v) { - nic->mac_control.stats_info->sw_stat.mem_freed - += (tx_cfg->fifo_len * sizeof(u64)); + swstats->mem_freed += tx_cfg->fifo_len * + sizeof(u64); kfree(fifo->ufo_in_band_v); } } if (mac_control->stats_mem) { - nic->mac_control.stats_info->sw_stat.mem_freed += - mac_control->stats_mem_sz; + swstats->mem_freed += mac_control->stats_mem_sz; pci_free_consistent(nic->pdev, mac_control->stats_mem_sz, mac_control->stats_mem, @@ -1190,9 +1185,7 @@ static int init_tti(struct s2io_nic *nic, int link) struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 val64 = 0; int i; - struct config_param *config; - - config = &nic->config; + struct config_param *config = &nic->config; for (i = 0; i < config->tx_fifo_num; i++) { /* @@ -1271,14 +1264,11 @@ static int init_nic(struct s2io_nic *nic) void __iomem *add; u32 time; int i, j; - struct mac_info *mac_control; - struct config_param *config; int dtx_cnt = 0; unsigned long long mem_share; int mem_size; - - mac_control = &nic->mac_control; - config = &nic->config; + struct config_param *config = &nic->config; + struct mac_info *mac_control = &nic->mac_control; /* to set the swapper controle on the card */ if (s2io_set_swapper(nic)) { @@ -2290,11 +2280,8 @@ static int start_nic(struct s2io_nic *nic) struct net_device *dev = nic->dev; register u64 val64 = 0; u16 subid, i; - struct mac_info *mac_control; - struct config_param *config; - - mac_control = &nic->mac_control; - config = &nic->config; + struct config_param *config = &nic->config; + struct mac_info *mac_control = &nic->mac_control; /* PRC Initialization and configuration */ for (i = 0; i < config->rx_ring_num; i++) { @@ -2446,12 +2433,11 @@ static void free_tx_buffers(struct s2io_nic *nic) struct sk_buff *skb; struct TxD *txdp; int i, j; - struct mac_info *mac_control; - struct config_param *config; int cnt = 0; - - mac_control = &nic->mac_control; - config = &nic->config; + struct config_param *config = &nic->config; + struct mac_info *mac_control = &nic->mac_control; + struct stat_block *stats = mac_control->stats_info; + struct swStat *swstats = &stats->sw_stat; for (i = 0; i < config->tx_fifo_num; i++) { struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; @@ -2463,8 +2449,7 @@ static void free_tx_buffers(struct s2io_nic *nic) txdp = (struct TxD *)fifo->list_info[j].list_virt_addr; skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j); if (skb) { - nic->mac_control.stats_info->sw_stat.mem_freed - += skb->truesize; + swstats->mem_freed += skb->truesize; dev_kfree_skb(skb); cnt++; } @@ -2493,11 +2478,6 @@ static void stop_nic(struct s2io_nic *nic) struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 val64 = 0; u16 interruptible; - struct mac_info *mac_control; - struct config_param *config; - - mac_control = &nic->mac_control; - config = &nic->config; /* Disable all interrupts */ en_dis_err_alarms(nic, ENA_ALL_INTRS, DISABLE_INTRS); @@ -2548,7 +2528,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, int rxd_index = 0; struct RxD1 *rxdp1; struct RxD3 *rxdp3; - struct swStat *stats = &ring->nic->mac_control.stats_info->sw_stat; + struct swStat *swstats = &ring->nic->mac_control.stats_info->sw_stat; alloc_cnt = ring->pkt_cnt - ring->rx_bufs_left; @@ -2609,11 +2589,11 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, wmb(); first_rxdp->Control_1 |= RXD_OWN_XENA; } - stats->mem_alloc_fail_cnt++; + swstats->mem_alloc_fail_cnt++; return -ENOMEM ; } - stats->mem_allocated += skb->truesize; + swstats->mem_allocated += skb->truesize; if (ring->rxd_mode == RXD_MODE_1) { /* 1 buffer mode - normal operation mode */ @@ -2742,8 +2722,8 @@ end: return SUCCESS; pci_map_failed: - stats->pci_map_fail_cnt++; - stats->mem_freed += skb->truesize; + swstats->pci_map_fail_cnt++; + swstats->mem_freed += skb->truesize; dev_kfree_skb_irq(skb); return -ENOMEM; } @@ -2754,12 +2734,13 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk) int j; struct sk_buff *skb; struct RxD_t *rxdp; - struct mac_info *mac_control; struct buffAdd *ba; struct RxD1 *rxdp1; struct RxD3 *rxdp3; + struct mac_info *mac_control = &sp->mac_control; + struct stat_block *stats = mac_control->stats_info; + struct swStat *swstats = &stats->sw_stat; - mac_control = &sp->mac_control; for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) { rxdp = mac_control->rings[ring_no]. rx_blocks[blk].rxds[j].virt_addr; @@ -2792,7 +2773,7 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk) PCI_DMA_FROMDEVICE); memset(rxdp, 0, sizeof(struct RxD3)); } - sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize; + swstats->mem_freed += skb->truesize; dev_kfree_skb(skb); mac_control->rings[ring_no].rx_bufs_left -= 1; } @@ -2811,11 +2792,8 @@ static void free_rx_buffers(struct s2io_nic *sp) { struct net_device *dev = sp->dev; int i, blk = 0, buf_cnt = 0; - struct mac_info *mac_control; - struct config_param *config; - - mac_control = &sp->mac_control; - config = &sp->config; + struct config_param *config = &sp->config; + struct mac_info *mac_control = &sp->mac_control; for (i = 0; i < config->rx_ring_num; i++) { struct ring_info *ring = &mac_control->rings[i]; @@ -2859,8 +2837,6 @@ static int s2io_poll_msix(struct napi_struct *napi, int budget) { struct ring_info *ring = container_of(napi, struct ring_info, napi); struct net_device *dev = ring->dev; - struct config_param *config; - struct mac_info *mac_control; int pkts_processed = 0; u8 __iomem *addr = NULL; u8 val8 = 0; @@ -2868,9 +2844,6 @@ static int s2io_poll_msix(struct napi_struct *napi, int budget) struct XENA_dev_config __iomem *bar0 = nic->bar0; int budget_org = budget; - config = &nic->config; - mac_control = &nic->mac_control; - if (unlikely(!is_s2io_card_up(nic))) return 0; @@ -2892,15 +2865,12 @@ static int s2io_poll_msix(struct napi_struct *napi, int budget) static int s2io_poll_inta(struct napi_struct *napi, int budget) { struct s2io_nic *nic = container_of(napi, struct s2io_nic, napi); - struct config_param *config; - struct mac_info *mac_control; int pkts_processed = 0; int ring_pkts_processed, i; struct XENA_dev_config __iomem *bar0 = nic->bar0; int budget_org = budget; - - config = &nic->config; - mac_control = &nic->mac_control; + struct config_param *config = &nic->config; + struct mac_info *mac_control = &nic->mac_control; if (unlikely(!is_s2io_card_up(nic))) return 0; @@ -2936,20 +2906,17 @@ static int s2io_poll_inta(struct napi_struct *napi, int budget) static void s2io_netpoll(struct net_device *dev) { struct s2io_nic *nic = netdev_priv(dev); - struct mac_info *mac_control; - struct config_param *config; struct XENA_dev_config __iomem *bar0 = nic->bar0; u64 val64 = 0xFFFFFFFFFFFFFFFFULL; int i; + struct config_param *config = &nic->config; + struct mac_info *mac_control = &nic->mac_control; if (pci_channel_offline(nic->pdev)) return; disable_irq(dev->irq); - mac_control = &nic->mac_control; - config = &nic->config; - writeq(val64, &bar0->rx_traffic_int); writeq(val64, &bar0->tx_traffic_int); @@ -3110,6 +3077,8 @@ static void tx_intr_handler(struct fifo_info *fifo_data) int pkt_cnt = 0; unsigned long flags = 0; u8 err_mask; + struct stat_block *stats = nic->mac_control.stats_info; + struct swStat *swstats = &stats->sw_stat; if (!spin_trylock_irqsave(&fifo_data->tx_lock, flags)) return; @@ -3126,36 +3095,30 @@ static void tx_intr_handler(struct fifo_info *fifo_data) unsigned long long err; err = txdlp->Control_1 & TXD_T_CODE; if (err & 0x1) { - nic->mac_control.stats_info->sw_stat. - parity_err_cnt++; + swstats->parity_err_cnt++; } /* update t_code statistics */ err_mask = err >> 48; switch (err_mask) { case 2: - nic->mac_control.stats_info->sw_stat. - tx_buf_abort_cnt++; + swstats->tx_buf_abort_cnt++; break; case 3: - nic->mac_control.stats_info->sw_stat. - tx_desc_abort_cnt++; + swstats->tx_desc_abort_cnt++; break; case 7: - nic->mac_control.stats_info->sw_stat. - tx_parity_err_cnt++; + swstats->tx_parity_err_cnt++; break; case 10: - nic->mac_control.stats_info->sw_stat. - tx_link_loss_cnt++; + swstats->tx_link_loss_cnt++; break; case 15: - nic->mac_control.stats_info->sw_stat. - tx_list_proc_err_cnt++; + swstats->tx_list_proc_err_cnt++; break; } } @@ -3171,7 +3134,7 @@ static void tx_intr_handler(struct fifo_info *fifo_data) /* Updating the statistics block */ nic->dev->stats.tx_bytes += skb->len; - nic->mac_control.stats_info->sw_stat.mem_freed += skb->truesize; + swstats->mem_freed += skb->truesize; dev_kfree_skb_irq(skb); get_info.offset++; @@ -3350,7 +3313,8 @@ static void s2io_updt_xpak_counter(struct net_device *dev) u64 addr = 0x0; struct s2io_nic *sp = netdev_priv(dev); - struct stat_block *stat_info = sp->mac_control.stats_info; + struct stat_block *stats = sp->mac_control.stats_info; + struct xpakStat *xstats = &stats->xpak_stat; /* Check the communication with the MDIO slave */ addr = MDIO_CTRL1; @@ -3382,30 +3346,30 @@ static void s2io_updt_xpak_counter(struct net_device *dev) flag = CHECKBIT(val64, 0x7); type = 1; - s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_transceiver_temp_high, - &stat_info->xpak_stat.xpak_regs_stat, + s2io_chk_xpak_counter(&xstats->alarm_transceiver_temp_high, + &xstats->xpak_regs_stat, 0x0, flag, type); if (CHECKBIT(val64, 0x6)) - stat_info->xpak_stat.alarm_transceiver_temp_low++; + xstats->alarm_transceiver_temp_low++; flag = CHECKBIT(val64, 0x3); type = 2; - s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_bias_current_high, - &stat_info->xpak_stat.xpak_regs_stat, + s2io_chk_xpak_counter(&xstats->alarm_laser_bias_current_high, + &xstats->xpak_regs_stat, 0x2, flag, type); if (CHECKBIT(val64, 0x2)) - stat_info->xpak_stat.alarm_laser_bias_current_low++; + xstats->alarm_laser_bias_current_low++; flag = CHECKBIT(val64, 0x1); type = 3; - s2io_chk_xpak_counter(&stat_info->xpak_stat.alarm_laser_output_power_high, - &stat_info->xpak_stat.xpak_regs_stat, + s2io_chk_xpak_counter(&xstats->alarm_laser_output_power_high, + &xstats->xpak_regs_stat, 0x4, flag, type); if (CHECKBIT(val64, 0x0)) - stat_info->xpak_stat.alarm_laser_output_power_low++; + xstats->alarm_laser_output_power_low++; /* Reading the Warning flags */ addr = 0xA074; @@ -3413,22 +3377,22 @@ static void s2io_updt_xpak_counter(struct net_device *dev) val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); if (CHECKBIT(val64, 0x7)) - stat_info->xpak_stat.warn_transceiver_temp_high++; + xstats->warn_transceiver_temp_high++; if (CHECKBIT(val64, 0x6)) - stat_info->xpak_stat.warn_transceiver_temp_low++; + xstats->warn_transceiver_temp_low++; if (CHECKBIT(val64, 0x3)) - stat_info->xpak_stat.warn_laser_bias_current_high++; + xstats->warn_laser_bias_current_high++; if (CHECKBIT(val64, 0x2)) - stat_info->xpak_stat.warn_laser_bias_current_low++; + xstats->warn_laser_bias_current_low++; if (CHECKBIT(val64, 0x1)) - stat_info->xpak_stat.warn_laser_output_power_high++; + xstats->warn_laser_output_power_high++; if (CHECKBIT(val64, 0x0)) - stat_info->xpak_stat.warn_laser_output_power_low++; + xstats->warn_laser_output_power_low++; } /** @@ -3514,6 +3478,8 @@ static void s2io_reset(struct s2io_nic *sp) u16 val16; unsigned long long up_cnt, down_cnt, up_time, down_time, reset_cnt; unsigned long long mem_alloc_cnt, mem_free_cnt, watchdog_cnt; + struct stat_block *stats; + struct swStat *swstats; DBG_PRINT(INIT_DBG, "%s - Resetting XFrame card %s\n", __func__, sp->dev->name); @@ -3567,25 +3533,30 @@ static void s2io_reset(struct s2io_nic *sp) /* Reset device statistics maintained by OS */ memset(&sp->stats, 0, sizeof(struct net_device_stats)); - up_cnt = sp->mac_control.stats_info->sw_stat.link_up_cnt; - down_cnt = sp->mac_control.stats_info->sw_stat.link_down_cnt; - up_time = sp->mac_control.stats_info->sw_stat.link_up_time; - down_time = sp->mac_control.stats_info->sw_stat.link_down_time; - reset_cnt = sp->mac_control.stats_info->sw_stat.soft_reset_cnt; - mem_alloc_cnt = sp->mac_control.stats_info->sw_stat.mem_allocated; - mem_free_cnt = sp->mac_control.stats_info->sw_stat.mem_freed; - watchdog_cnt = sp->mac_control.stats_info->sw_stat.watchdog_timer_cnt; + stats = sp->mac_control.stats_info; + swstats = &stats->sw_stat; + /* save link up/down time/cnt, reset/memory/watchdog cnt */ - memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block)); + up_cnt = swstats->link_up_cnt; + down_cnt = swstats->link_down_cnt; + up_time = swstats->link_up_time; + down_time = swstats->link_down_time; + reset_cnt = swstats->soft_reset_cnt; + mem_alloc_cnt = swstats->mem_allocated; + mem_free_cnt = swstats->mem_freed; + watchdog_cnt = swstats->watchdog_timer_cnt; + + memset(stats, 0, sizeof(struct stat_block)); + /* restore link up/down time/cnt, reset/memory/watchdog cnt */ - sp->mac_control.stats_info->sw_stat.link_up_cnt = up_cnt; - sp->mac_control.stats_info->sw_stat.link_down_cnt = down_cnt; - sp->mac_control.stats_info->sw_stat.link_up_time = up_time; - sp->mac_control.stats_info->sw_stat.link_down_time = down_time; - sp->mac_control.stats_info->sw_stat.soft_reset_cnt = reset_cnt; - sp->mac_control.stats_info->sw_stat.mem_allocated = mem_alloc_cnt; - sp->mac_control.stats_info->sw_stat.mem_freed = mem_free_cnt; - sp->mac_control.stats_info->sw_stat.watchdog_timer_cnt = watchdog_cnt; + swstats->link_up_cnt = up_cnt; + swstats->link_down_cnt = down_cnt; + swstats->link_up_time = up_time; + swstats->link_down_time = down_time; + swstats->soft_reset_cnt = reset_cnt; + swstats->mem_allocated = mem_alloc_cnt; + swstats->mem_freed = mem_free_cnt; + swstats->watchdog_timer_cnt = watchdog_cnt; /* SXE-002: Configure link and activity LED to turn it off */ subid = sp->pdev->subsystem_device; @@ -3827,29 +3798,31 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) u16 msi_control; /* Temp variable */ int ret, i, j, msix_indx = 1; int size; + struct stat_block *stats = nic->mac_control.stats_info; + struct swStat *swstats = &stats->sw_stat; size = nic->num_entries * sizeof(struct msix_entry); nic->entries = kzalloc(size, GFP_KERNEL); if (!nic->entries) { DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __func__); - nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; + swstats->mem_alloc_fail_cnt++; return -ENOMEM; } - nic->mac_control.stats_info->sw_stat.mem_allocated += size; + swstats->mem_allocated += size; size = nic->num_entries * sizeof(struct s2io_msix_entry); nic->s2io_entries = kzalloc(size, GFP_KERNEL); if (!nic->s2io_entries) { DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __func__); - nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; + swstats->mem_alloc_fail_cnt++; kfree(nic->entries); - nic->mac_control.stats_info->sw_stat.mem_freed + swstats->mem_freed += (nic->num_entries * sizeof(struct msix_entry)); return -ENOMEM; } - nic->mac_control.stats_info->sw_stat.mem_allocated += size; + swstats->mem_allocated += size; nic->entries[0].entry = 0; nic->s2io_entries[0].entry = 0; @@ -3880,11 +3853,11 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) if (ret) { DBG_PRINT(ERR_DBG, "s2io: Enabling MSI-X failed\n"); kfree(nic->entries); - nic->mac_control.stats_info->sw_stat.mem_freed - += (nic->num_entries * sizeof(struct msix_entry)); + swstats->mem_freed += nic->num_entries * + sizeof(struct msix_entry); kfree(nic->s2io_entries); - nic->mac_control.stats_info->sw_stat.mem_freed - += (nic->num_entries * sizeof(struct s2io_msix_entry)); + swstats->mem_freed += nic->num_entries * + sizeof(struct s2io_msix_entry); nic->entries = NULL; nic->s2io_entries = NULL; return -ENOMEM; @@ -4006,6 +3979,7 @@ static void remove_inta_isr(struct s2io_nic *sp) static int s2io_open(struct net_device *dev) { struct s2io_nic *sp = netdev_priv(dev); + struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; int err = 0; /* @@ -4036,13 +4010,13 @@ hw_init_failed: if (sp->config.intr_type == MSI_X) { if (sp->entries) { kfree(sp->entries); - sp->mac_control.stats_info->sw_stat.mem_freed - += (sp->num_entries * sizeof(struct msix_entry)); + swstats->mem_freed += sp->num_entries * + sizeof(struct msix_entry); } if (sp->s2io_entries) { kfree(sp->s2io_entries); - sp->mac_control.stats_info->sw_stat.mem_freed - += (sp->num_entries * sizeof(struct s2io_msix_entry)); + swstats->mem_freed += sp->num_entries * + sizeof(struct s2io_msix_entry); } } return err; @@ -4110,15 +4084,13 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags = 0; u16 vlan_tag = 0; struct fifo_info *fifo = NULL; - struct mac_info *mac_control; - struct config_param *config; int do_spin_lock = 1; int offload_type; int enable_per_list_interrupt = 0; - struct swStat *stats = &sp->mac_control.stats_info->sw_stat; - - mac_control = &sp->mac_control; - config = &sp->config; + struct config_param *config = &sp->config; + struct mac_info *mac_control = &sp->mac_control; + struct stat_block *stats = mac_control->stats_info; + struct swStat *swstats = &stats->sw_stat; DBG_PRINT(TX_DBG, "%s: In Neterion Tx routine\n", dev->name); @@ -4308,23 +4280,24 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) /* Avoid "put" pointer going beyond "get" pointer */ if (((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) { - sp->mac_control.stats_info->sw_stat.fifo_full_cnt++; + swstats->fifo_full_cnt++; DBG_PRINT(TX_DBG, "No free TxDs for xmit, Put: 0x%x Get:0x%x\n", put_off, get_off); s2io_stop_tx_queue(sp, fifo->fifo_no); } - mac_control->stats_info->sw_stat.mem_allocated += skb->truesize; + swstats->mem_allocated += skb->truesize; spin_unlock_irqrestore(&fifo->tx_lock, flags); if (sp->config.intr_type == MSI_X) tx_intr_handler(fifo); return NETDEV_TX_OK; + pci_map_failed: - stats->pci_map_fail_cnt++; + swstats->pci_map_fail_cnt++; s2io_stop_tx_queue(sp, fifo->fifo_no); - stats->mem_freed += skb->truesize; + swstats->mem_freed += skb->truesize; dev_kfree_skb(skb); spin_unlock_irqrestore(&fifo->tx_lock, flags); return NETDEV_TX_OK; @@ -4816,8 +4789,8 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) if (!is_s2io_card_up(sp)) return IRQ_NONE; - mac_control = &sp->mac_control; config = &sp->config; + mac_control = &sp->mac_control; /* * Identify the cause for interrupt and call the appropriate @@ -4934,44 +4907,35 @@ static void s2io_updt_stats(struct s2io_nic *sp) static struct net_device_stats *s2io_get_stats(struct net_device *dev) { struct s2io_nic *sp = netdev_priv(dev); - struct mac_info *mac_control; - struct config_param *config; + struct config_param *config = &sp->config; + struct mac_info *mac_control = &sp->mac_control; + struct stat_block *stats = mac_control->stats_info; int i; - - mac_control = &sp->mac_control; - config = &sp->config; - /* Configure Stats for immediate updt */ s2io_updt_stats(sp); /* Using sp->stats as a staging area, because reset (due to mtu change, for example) will clear some hardware counters */ - dev->stats.tx_packets += - le32_to_cpu(mac_control->stats_info->tmac_frms) - + dev->stats.tx_packets += le32_to_cpu(stats->tmac_frms) - sp->stats.tx_packets; - sp->stats.tx_packets = - le32_to_cpu(mac_control->stats_info->tmac_frms); - dev->stats.tx_errors += - le32_to_cpu(mac_control->stats_info->tmac_any_err_frms) - + sp->stats.tx_packets = le32_to_cpu(stats->tmac_frms); + + dev->stats.tx_errors += le32_to_cpu(stats->tmac_any_err_frms) - sp->stats.tx_errors; - sp->stats.tx_errors = - le32_to_cpu(mac_control->stats_info->tmac_any_err_frms); - dev->stats.rx_errors += - le64_to_cpu(mac_control->stats_info->rmac_drop_frms) - + sp->stats.tx_errors = le32_to_cpu(stats->tmac_any_err_frms); + + dev->stats.rx_errors += le64_to_cpu(stats->rmac_drop_frms) - sp->stats.rx_errors; - sp->stats.rx_errors = - le64_to_cpu(mac_control->stats_info->rmac_drop_frms); - dev->stats.multicast = - le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms) - + sp->stats.rx_errors = le64_to_cpu(stats->rmac_drop_frms); + + dev->stats.multicast = le32_to_cpu(stats->rmac_vld_mcst_frms) - sp->stats.multicast; - sp->stats.multicast = - le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms); - dev->stats.rx_length_errors = - le64_to_cpu(mac_control->stats_info->rmac_long_frms) - + sp->stats.multicast = le32_to_cpu(stats->rmac_vld_mcst_frms); + + dev->stats.rx_length_errors = le64_to_cpu(stats->rmac_long_frms) - sp->stats.rx_length_errors; - sp->stats.rx_length_errors = - le64_to_cpu(mac_control->stats_info->rmac_long_frms); + sp->stats.rx_length_errors = le64_to_cpu(stats->rmac_long_frms); /* collect per-ring rx_packets and rx_bytes */ dev->stats.rx_packets = dev->stats.rx_bytes = 0; @@ -5803,6 +5767,7 @@ static void s2io_vpd_read(struct s2io_nic *nic) u8 data; int i = 0, cnt, fail = 0; int vpd_addr = 0x80; + struct swStat *swstats = &nic->mac_control.stats_info->sw_stat; if (nic->device_type == XFRAME_II_DEVICE) { strcpy(nic->product_name, "Xframe II 10GbE network adapter"); @@ -5815,10 +5780,10 @@ static void s2io_vpd_read(struct s2io_nic *nic) vpd_data = kmalloc(256, GFP_KERNEL); if (!vpd_data) { - nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; + swstats->mem_alloc_fail_cnt++; return; } - nic->mac_control.stats_info->sw_stat.mem_allocated += 256; + swstats->mem_allocated += 256; for (i = 0; i < 256; i += 4) { pci_write_config_byte(nic->pdev, (vpd_addr + 2), i); @@ -5858,7 +5823,7 @@ static void s2io_vpd_read(struct s2io_nic *nic) memcpy(nic->product_name, &vpd_data[3], vpd_data[1]); } kfree(vpd_data); - nic->mac_control.stats_info->sw_stat.mem_freed += 256; + swstats->mem_freed += 256; } /** @@ -6350,273 +6315,275 @@ static void s2io_get_ethtool_stats(struct net_device *dev, { int i = 0, k; struct s2io_nic *sp = netdev_priv(dev); - struct stat_block *stat_info = sp->mac_control.stats_info; + struct stat_block *stats = sp->mac_control.stats_info; + struct swStat *swstats = &stats->sw_stat; + struct xpakStat *xstats = &stats->xpak_stat; s2io_updt_stats(sp); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_frms_oflow) << 32 | - le32_to_cpu(stat_info->tmac_frms); + (u64)le32_to_cpu(stats->tmac_frms_oflow) << 32 | + le32_to_cpu(stats->tmac_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_data_octets_oflow) << 32 | - le32_to_cpu(stat_info->tmac_data_octets); - tmp_stats[i++] = le64_to_cpu(stat_info->tmac_drop_frms); + (u64)le32_to_cpu(stats->tmac_data_octets_oflow) << 32 | + le32_to_cpu(stats->tmac_data_octets); + tmp_stats[i++] = le64_to_cpu(stats->tmac_drop_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_mcst_frms_oflow) << 32 | - le32_to_cpu(stat_info->tmac_mcst_frms); + (u64)le32_to_cpu(stats->tmac_mcst_frms_oflow) << 32 | + le32_to_cpu(stats->tmac_mcst_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_bcst_frms_oflow) << 32 | - le32_to_cpu(stat_info->tmac_bcst_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->tmac_pause_ctrl_frms); + (u64)le32_to_cpu(stats->tmac_bcst_frms_oflow) << 32 | + le32_to_cpu(stats->tmac_bcst_frms); + tmp_stats[i++] = le64_to_cpu(stats->tmac_pause_ctrl_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_ttl_octets_oflow) << 32 | - le32_to_cpu(stat_info->tmac_ttl_octets); + (u64)le32_to_cpu(stats->tmac_ttl_octets_oflow) << 32 | + le32_to_cpu(stats->tmac_ttl_octets); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_ucst_frms_oflow) << 32 | - le32_to_cpu(stat_info->tmac_ucst_frms); + (u64)le32_to_cpu(stats->tmac_ucst_frms_oflow) << 32 | + le32_to_cpu(stats->tmac_ucst_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_nucst_frms_oflow) << 32 | - le32_to_cpu(stat_info->tmac_nucst_frms); + (u64)le32_to_cpu(stats->tmac_nucst_frms_oflow) << 32 | + le32_to_cpu(stats->tmac_nucst_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_any_err_frms_oflow) << 32 | - le32_to_cpu(stat_info->tmac_any_err_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->tmac_ttl_less_fb_octets); - tmp_stats[i++] = le64_to_cpu(stat_info->tmac_vld_ip_octets); + (u64)le32_to_cpu(stats->tmac_any_err_frms_oflow) << 32 | + le32_to_cpu(stats->tmac_any_err_frms); + tmp_stats[i++] = le64_to_cpu(stats->tmac_ttl_less_fb_octets); + tmp_stats[i++] = le64_to_cpu(stats->tmac_vld_ip_octets); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_vld_ip_oflow) << 32 | - le32_to_cpu(stat_info->tmac_vld_ip); + (u64)le32_to_cpu(stats->tmac_vld_ip_oflow) << 32 | + le32_to_cpu(stats->tmac_vld_ip); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_drop_ip_oflow) << 32 | - le32_to_cpu(stat_info->tmac_drop_ip); + (u64)le32_to_cpu(stats->tmac_drop_ip_oflow) << 32 | + le32_to_cpu(stats->tmac_drop_ip); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_icmp_oflow) << 32 | - le32_to_cpu(stat_info->tmac_icmp); + (u64)le32_to_cpu(stats->tmac_icmp_oflow) << 32 | + le32_to_cpu(stats->tmac_icmp); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->tmac_rst_tcp_oflow) << 32 | - le32_to_cpu(stat_info->tmac_rst_tcp); - tmp_stats[i++] = le64_to_cpu(stat_info->tmac_tcp); - tmp_stats[i++] = (u64)le32_to_cpu(stat_info->tmac_udp_oflow) << 32 | - le32_to_cpu(stat_info->tmac_udp); + (u64)le32_to_cpu(stats->tmac_rst_tcp_oflow) << 32 | + le32_to_cpu(stats->tmac_rst_tcp); + tmp_stats[i++] = le64_to_cpu(stats->tmac_tcp); + tmp_stats[i++] = (u64)le32_to_cpu(stats->tmac_udp_oflow) << 32 | + le32_to_cpu(stats->tmac_udp); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_vld_frms_oflow) << 32 | - le32_to_cpu(stat_info->rmac_vld_frms); + (u64)le32_to_cpu(stats->rmac_vld_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_vld_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_data_octets_oflow) << 32 | - le32_to_cpu(stat_info->rmac_data_octets); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_fcs_err_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_drop_frms); + (u64)le32_to_cpu(stats->rmac_data_octets_oflow) << 32 | + le32_to_cpu(stats->rmac_data_octets); + tmp_stats[i++] = le64_to_cpu(stats->rmac_fcs_err_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_drop_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_vld_mcst_frms_oflow) << 32 | - le32_to_cpu(stat_info->rmac_vld_mcst_frms); + (u64)le32_to_cpu(stats->rmac_vld_mcst_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_vld_mcst_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_vld_bcst_frms_oflow) << 32 | - le32_to_cpu(stat_info->rmac_vld_bcst_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_in_rng_len_err_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_out_rng_len_err_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_long_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_pause_ctrl_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_unsup_ctrl_frms); + (u64)le32_to_cpu(stats->rmac_vld_bcst_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_vld_bcst_frms); + tmp_stats[i++] = le32_to_cpu(stats->rmac_in_rng_len_err_frms); + tmp_stats[i++] = le32_to_cpu(stats->rmac_out_rng_len_err_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_long_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_pause_ctrl_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_unsup_ctrl_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_ttl_octets_oflow) << 32 | - le32_to_cpu(stat_info->rmac_ttl_octets); + (u64)le32_to_cpu(stats->rmac_ttl_octets_oflow) << 32 | + le32_to_cpu(stats->rmac_ttl_octets); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_accepted_ucst_frms_oflow) << 32 - | le32_to_cpu(stat_info->rmac_accepted_ucst_frms); + (u64)le32_to_cpu(stats->rmac_accepted_ucst_frms_oflow) << 32 + | le32_to_cpu(stats->rmac_accepted_ucst_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_accepted_nucst_frms_oflow) - << 32 | le32_to_cpu(stat_info->rmac_accepted_nucst_frms); + (u64)le32_to_cpu(stats->rmac_accepted_nucst_frms_oflow) + << 32 | le32_to_cpu(stats->rmac_accepted_nucst_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_discarded_frms_oflow) << 32 | - le32_to_cpu(stat_info->rmac_discarded_frms); + (u64)le32_to_cpu(stats->rmac_discarded_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_discarded_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_drop_events_oflow) - << 32 | le32_to_cpu(stat_info->rmac_drop_events); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_less_fb_octets); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_frms); + (u64)le32_to_cpu(stats->rmac_drop_events_oflow) + << 32 | le32_to_cpu(stats->rmac_drop_events); + tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_less_fb_octets); + tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_usized_frms_oflow) << 32 | - le32_to_cpu(stat_info->rmac_usized_frms); + (u64)le32_to_cpu(stats->rmac_usized_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_usized_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_osized_frms_oflow) << 32 | - le32_to_cpu(stat_info->rmac_osized_frms); + (u64)le32_to_cpu(stats->rmac_osized_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_osized_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_frag_frms_oflow) << 32 | - le32_to_cpu(stat_info->rmac_frag_frms); + (u64)le32_to_cpu(stats->rmac_frag_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_frag_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_jabber_frms_oflow) << 32 | - le32_to_cpu(stat_info->rmac_jabber_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_64_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_65_127_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_128_255_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_256_511_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_512_1023_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1024_1518_frms); + (u64)le32_to_cpu(stats->rmac_jabber_frms_oflow) << 32 | + le32_to_cpu(stats->rmac_jabber_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_64_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_65_127_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_128_255_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_256_511_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_512_1023_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_1024_1518_frms); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_ip_oflow) << 32 | - le32_to_cpu(stat_info->rmac_ip); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ip_octets); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_hdr_err_ip); + (u64)le32_to_cpu(stats->rmac_ip_oflow) << 32 | + le32_to_cpu(stats->rmac_ip); + tmp_stats[i++] = le64_to_cpu(stats->rmac_ip_octets); + tmp_stats[i++] = le32_to_cpu(stats->rmac_hdr_err_ip); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_drop_ip_oflow) << 32 | - le32_to_cpu(stat_info->rmac_drop_ip); + (u64)le32_to_cpu(stats->rmac_drop_ip_oflow) << 32 | + le32_to_cpu(stats->rmac_drop_ip); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_icmp_oflow) << 32 | - le32_to_cpu(stat_info->rmac_icmp); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_tcp); + (u64)le32_to_cpu(stats->rmac_icmp_oflow) << 32 | + le32_to_cpu(stats->rmac_icmp); + tmp_stats[i++] = le64_to_cpu(stats->rmac_tcp); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_udp_oflow) << 32 | - le32_to_cpu(stat_info->rmac_udp); + (u64)le32_to_cpu(stats->rmac_udp_oflow) << 32 | + le32_to_cpu(stats->rmac_udp); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_err_drp_udp_oflow) << 32 | - le32_to_cpu(stat_info->rmac_err_drp_udp); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_err_sym); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q0); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q1); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q2); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q3); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q4); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q5); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q6); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_frms_q7); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q0); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q1); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q2); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q3); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q4); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q5); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q6); - tmp_stats[i++] = le16_to_cpu(stat_info->rmac_full_q7); + (u64)le32_to_cpu(stats->rmac_err_drp_udp_oflow) << 32 | + le32_to_cpu(stats->rmac_err_drp_udp); + tmp_stats[i++] = le64_to_cpu(stats->rmac_xgmii_err_sym); + tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q0); + tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q1); + tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q2); + tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q3); + tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q4); + tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q5); + tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q6); + tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q7); + tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q0); + tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q1); + tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q2); + tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q3); + tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q4); + tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q5); + tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q6); + tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q7); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_pause_cnt_oflow) << 32 | - le32_to_cpu(stat_info->rmac_pause_cnt); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_data_err_cnt); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_xgmii_ctrl_err_cnt); + (u64)le32_to_cpu(stats->rmac_pause_cnt_oflow) << 32 | + le32_to_cpu(stats->rmac_pause_cnt); + tmp_stats[i++] = le64_to_cpu(stats->rmac_xgmii_data_err_cnt); + tmp_stats[i++] = le64_to_cpu(stats->rmac_xgmii_ctrl_err_cnt); tmp_stats[i++] = - (u64)le32_to_cpu(stat_info->rmac_accepted_ip_oflow) << 32 | - le32_to_cpu(stat_info->rmac_accepted_ip); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_tcp); - tmp_stats[i++] = le32_to_cpu(stat_info->rd_req_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->new_rd_req_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->new_rd_req_rtry_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->rd_rtry_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->wr_rtry_rd_ack_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->wr_req_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->new_wr_req_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->new_wr_req_rtry_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->wr_rtry_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->wr_disc_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->rd_rtry_wr_ack_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->txp_wr_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->txd_rd_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->txd_wr_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->rxd_rd_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->rxd_wr_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->txf_rd_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->rxf_wr_cnt); + (u64)le32_to_cpu(stats->rmac_accepted_ip_oflow) << 32 | + le32_to_cpu(stats->rmac_accepted_ip); + tmp_stats[i++] = le32_to_cpu(stats->rmac_err_tcp); + tmp_stats[i++] = le32_to_cpu(stats->rd_req_cnt); + tmp_stats[i++] = le32_to_cpu(stats->new_rd_req_cnt); + tmp_stats[i++] = le32_to_cpu(stats->new_rd_req_rtry_cnt); + tmp_stats[i++] = le32_to_cpu(stats->rd_rtry_cnt); + tmp_stats[i++] = le32_to_cpu(stats->wr_rtry_rd_ack_cnt); + tmp_stats[i++] = le32_to_cpu(stats->wr_req_cnt); + tmp_stats[i++] = le32_to_cpu(stats->new_wr_req_cnt); + tmp_stats[i++] = le32_to_cpu(stats->new_wr_req_rtry_cnt); + tmp_stats[i++] = le32_to_cpu(stats->wr_rtry_cnt); + tmp_stats[i++] = le32_to_cpu(stats->wr_disc_cnt); + tmp_stats[i++] = le32_to_cpu(stats->rd_rtry_wr_ack_cnt); + tmp_stats[i++] = le32_to_cpu(stats->txp_wr_cnt); + tmp_stats[i++] = le32_to_cpu(stats->txd_rd_cnt); + tmp_stats[i++] = le32_to_cpu(stats->txd_wr_cnt); + tmp_stats[i++] = le32_to_cpu(stats->rxd_rd_cnt); + tmp_stats[i++] = le32_to_cpu(stats->rxd_wr_cnt); + tmp_stats[i++] = le32_to_cpu(stats->txf_rd_cnt); + tmp_stats[i++] = le32_to_cpu(stats->rxf_wr_cnt); /* Enhanced statistics exist only for Hercules */ if (sp->device_type == XFRAME_II_DEVICE) { tmp_stats[i++] = - le64_to_cpu(stat_info->rmac_ttl_1519_4095_frms); + le64_to_cpu(stats->rmac_ttl_1519_4095_frms); tmp_stats[i++] = - le64_to_cpu(stat_info->rmac_ttl_4096_8191_frms); + le64_to_cpu(stats->rmac_ttl_4096_8191_frms); tmp_stats[i++] = - le64_to_cpu(stat_info->rmac_ttl_8192_max_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_gt_max_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_osized_alt_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_jabber_alt_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_gt_max_alt_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_vlan_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_len_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_fcs_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_pf_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_da_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_red_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_rts_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_ingm_full_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->link_fault_cnt); + le64_to_cpu(stats->rmac_ttl_8192_max_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_gt_max_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_osized_alt_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_jabber_alt_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_gt_max_alt_frms); + tmp_stats[i++] = le64_to_cpu(stats->rmac_vlan_frms); + tmp_stats[i++] = le32_to_cpu(stats->rmac_len_discard); + tmp_stats[i++] = le32_to_cpu(stats->rmac_fcs_discard); + tmp_stats[i++] = le32_to_cpu(stats->rmac_pf_discard); + tmp_stats[i++] = le32_to_cpu(stats->rmac_da_discard); + tmp_stats[i++] = le32_to_cpu(stats->rmac_red_discard); + tmp_stats[i++] = le32_to_cpu(stats->rmac_rts_discard); + tmp_stats[i++] = le32_to_cpu(stats->rmac_ingm_full_discard); + tmp_stats[i++] = le32_to_cpu(stats->link_fault_cnt); } tmp_stats[i++] = 0; - tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs; - tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs; - tmp_stats[i++] = stat_info->sw_stat.parity_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.serious_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.soft_reset_cnt; - tmp_stats[i++] = stat_info->sw_stat.fifo_full_cnt; + tmp_stats[i++] = swstats->single_ecc_errs; + tmp_stats[i++] = swstats->double_ecc_errs; + tmp_stats[i++] = swstats->parity_err_cnt; + tmp_stats[i++] = swstats->serious_err_cnt; + tmp_stats[i++] = swstats->soft_reset_cnt; + tmp_stats[i++] = swstats->fifo_full_cnt; for (k = 0; k < MAX_RX_RINGS; k++) - tmp_stats[i++] = stat_info->sw_stat.ring_full_cnt[k]; - tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_high; - tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_low; - tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_high; - tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_low; - tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_output_power_high; - tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_output_power_low; - tmp_stats[i++] = stat_info->xpak_stat.warn_transceiver_temp_high; - tmp_stats[i++] = stat_info->xpak_stat.warn_transceiver_temp_low; - tmp_stats[i++] = stat_info->xpak_stat.warn_laser_bias_current_high; - tmp_stats[i++] = stat_info->xpak_stat.warn_laser_bias_current_low; - tmp_stats[i++] = stat_info->xpak_stat.warn_laser_output_power_high; - tmp_stats[i++] = stat_info->xpak_stat.warn_laser_output_power_low; - tmp_stats[i++] = stat_info->sw_stat.clubbed_frms_cnt; - tmp_stats[i++] = stat_info->sw_stat.sending_both; - tmp_stats[i++] = stat_info->sw_stat.outof_sequence_pkts; - tmp_stats[i++] = stat_info->sw_stat.flush_max_pkts; - if (stat_info->sw_stat.num_aggregations) { - u64 tmp = stat_info->sw_stat.sum_avg_pkts_aggregated; + tmp_stats[i++] = swstats->ring_full_cnt[k]; + tmp_stats[i++] = xstats->alarm_transceiver_temp_high; + tmp_stats[i++] = xstats->alarm_transceiver_temp_low; + tmp_stats[i++] = xstats->alarm_laser_bias_current_high; + tmp_stats[i++] = xstats->alarm_laser_bias_current_low; + tmp_stats[i++] = xstats->alarm_laser_output_power_high; + tmp_stats[i++] = xstats->alarm_laser_output_power_low; + tmp_stats[i++] = xstats->warn_transceiver_temp_high; + tmp_stats[i++] = xstats->warn_transceiver_temp_low; + tmp_stats[i++] = xstats->warn_laser_bias_current_high; + tmp_stats[i++] = xstats->warn_laser_bias_current_low; + tmp_stats[i++] = xstats->warn_laser_output_power_high; + tmp_stats[i++] = xstats->warn_laser_output_power_low; + tmp_stats[i++] = swstats->clubbed_frms_cnt; + tmp_stats[i++] = swstats->sending_both; + tmp_stats[i++] = swstats->outof_sequence_pkts; + tmp_stats[i++] = swstats->flush_max_pkts; + if (swstats->num_aggregations) { + u64 tmp = swstats->sum_avg_pkts_aggregated; int count = 0; /* * Since 64-bit divide does not work on all platforms, * do repeated subtraction. */ - while (tmp >= stat_info->sw_stat.num_aggregations) { - tmp -= stat_info->sw_stat.num_aggregations; + while (tmp >= swstats->num_aggregations) { + tmp -= swstats->num_aggregations; count++; } tmp_stats[i++] = count; } else tmp_stats[i++] = 0; - tmp_stats[i++] = stat_info->sw_stat.mem_alloc_fail_cnt; - tmp_stats[i++] = stat_info->sw_stat.pci_map_fail_cnt; - tmp_stats[i++] = stat_info->sw_stat.watchdog_timer_cnt; - tmp_stats[i++] = stat_info->sw_stat.mem_allocated; - tmp_stats[i++] = stat_info->sw_stat.mem_freed; - tmp_stats[i++] = stat_info->sw_stat.link_up_cnt; - tmp_stats[i++] = stat_info->sw_stat.link_down_cnt; - tmp_stats[i++] = stat_info->sw_stat.link_up_time; - tmp_stats[i++] = stat_info->sw_stat.link_down_time; - - tmp_stats[i++] = stat_info->sw_stat.tx_buf_abort_cnt; - tmp_stats[i++] = stat_info->sw_stat.tx_desc_abort_cnt; - tmp_stats[i++] = stat_info->sw_stat.tx_parity_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.tx_link_loss_cnt; - tmp_stats[i++] = stat_info->sw_stat.tx_list_proc_err_cnt; - - tmp_stats[i++] = stat_info->sw_stat.rx_parity_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.rx_abort_cnt; - tmp_stats[i++] = stat_info->sw_stat.rx_parity_abort_cnt; - tmp_stats[i++] = stat_info->sw_stat.rx_rda_fail_cnt; - tmp_stats[i++] = stat_info->sw_stat.rx_unkn_prot_cnt; - tmp_stats[i++] = stat_info->sw_stat.rx_fcs_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.rx_buf_size_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.rx_rxd_corrupt_cnt; - tmp_stats[i++] = stat_info->sw_stat.rx_unkn_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.tda_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.pfc_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.pcc_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.tti_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.tpa_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.sm_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.lso_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.mac_tmac_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.mac_rmac_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.xgxs_txgxs_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.xgxs_rxgxs_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.rc_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.prc_pcix_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.rpa_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.rda_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.rti_err_cnt; - tmp_stats[i++] = stat_info->sw_stat.mc_err_cnt; + tmp_stats[i++] = swstats->mem_alloc_fail_cnt; + tmp_stats[i++] = swstats->pci_map_fail_cnt; + tmp_stats[i++] = swstats->watchdog_timer_cnt; + tmp_stats[i++] = swstats->mem_allocated; + tmp_stats[i++] = swstats->mem_freed; + tmp_stats[i++] = swstats->link_up_cnt; + tmp_stats[i++] = swstats->link_down_cnt; + tmp_stats[i++] = swstats->link_up_time; + tmp_stats[i++] = swstats->link_down_time; + + tmp_stats[i++] = swstats->tx_buf_abort_cnt; + tmp_stats[i++] = swstats->tx_desc_abort_cnt; + tmp_stats[i++] = swstats->tx_parity_err_cnt; + tmp_stats[i++] = swstats->tx_link_loss_cnt; + tmp_stats[i++] = swstats->tx_list_proc_err_cnt; + + tmp_stats[i++] = swstats->rx_parity_err_cnt; + tmp_stats[i++] = swstats->rx_abort_cnt; + tmp_stats[i++] = swstats->rx_parity_abort_cnt; + tmp_stats[i++] = swstats->rx_rda_fail_cnt; + tmp_stats[i++] = swstats->rx_unkn_prot_cnt; + tmp_stats[i++] = swstats->rx_fcs_err_cnt; + tmp_stats[i++] = swstats->rx_buf_size_err_cnt; + tmp_stats[i++] = swstats->rx_rxd_corrupt_cnt; + tmp_stats[i++] = swstats->rx_unkn_err_cnt; + tmp_stats[i++] = swstats->tda_err_cnt; + tmp_stats[i++] = swstats->pfc_err_cnt; + tmp_stats[i++] = swstats->pcc_err_cnt; + tmp_stats[i++] = swstats->tti_err_cnt; + tmp_stats[i++] = swstats->tpa_err_cnt; + tmp_stats[i++] = swstats->sm_err_cnt; + tmp_stats[i++] = swstats->lso_err_cnt; + tmp_stats[i++] = swstats->mac_tmac_err_cnt; + tmp_stats[i++] = swstats->mac_rmac_err_cnt; + tmp_stats[i++] = swstats->xgxs_txgxs_err_cnt; + tmp_stats[i++] = swstats->xgxs_rxgxs_err_cnt; + tmp_stats[i++] = swstats->rc_err_cnt; + tmp_stats[i++] = swstats->prc_pcix_err_cnt; + tmp_stats[i++] = swstats->rpa_err_cnt; + tmp_stats[i++] = swstats->rda_err_cnt; + tmp_stats[i++] = swstats->rti_err_cnt; + tmp_stats[i++] = swstats->mc_err_cnt; } static int s2io_ethtool_get_regs_len(struct net_device *dev) @@ -6912,12 +6879,10 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name); DBG_PRINT(INFO_DBG, "memory to allocate "); DBG_PRINT(INFO_DBG, "1 buf mode SKBs\n"); - sp->mac_control.stats_info->sw_stat. - mem_alloc_fail_cnt++; + stats->mem_alloc_fail_cnt++; return -ENOMEM ; } - sp->mac_control.stats_info->sw_stat.mem_allocated - += (*skb)->truesize; + stats->mem_allocated += (*skb)->truesize; /* storing the mapped addr in a temp variable * such it will be used for next rxd whose * Host Control is NULL @@ -6943,12 +6908,10 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name); DBG_PRINT(INFO_DBG, "memory to allocate "); DBG_PRINT(INFO_DBG, "2 buf mode SKBs\n"); - sp->mac_control.stats_info->sw_stat. - mem_alloc_fail_cnt++; + stats->mem_alloc_fail_cnt++; return -ENOMEM; } - sp->mac_control.stats_info->sw_stat.mem_allocated - += (*skb)->truesize; + stats->mem_allocated += (*skb)->truesize; rxdp3->Buffer2_ptr = *temp2 = pci_map_single(sp->pdev, (*skb)->data, dev->mtu + 4, @@ -7010,8 +6973,8 @@ static void set_rxd_buffer_size(struct s2io_nic *sp, struct RxD_t *rxdp, static int rxd_owner_bit_reset(struct s2io_nic *sp) { int i, j, k, blk_cnt = 0, size; - struct mac_info *mac_control = &sp->mac_control; struct config_param *config = &sp->config; + struct mac_info *mac_control = &sp->mac_control; struct net_device *dev = sp->dev; struct RxD_t *rxdp = NULL; struct sk_buff *skb = NULL; @@ -7239,8 +7202,8 @@ static void s2io_card_down(struct s2io_nic *sp) static int s2io_card_up(struct s2io_nic *sp) { int i, ret = 0; - struct mac_info *mac_control; struct config_param *config; + struct mac_info *mac_control; struct net_device *dev = (struct net_device *)sp->dev; u16 interruptible; @@ -7258,8 +7221,8 @@ static int s2io_card_up(struct s2io_nic *sp) * Initializing the Rx buffers. For now we are considering only 1 * Rx ring and initializing buffers into 30 Rx blocks */ - mac_control = &sp->mac_control; config = &sp->config; + mac_control = &sp->mac_control; for (i = 0; i < config->rx_ring_num; i++) { struct ring_info *ring = &mac_control->rings[i]; @@ -7387,11 +7350,12 @@ out_unlock: static void s2io_tx_watchdog(struct net_device *dev) { struct s2io_nic *sp = netdev_priv(dev); + struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; if (netif_carrier_ok(dev)) { - sp->mac_control.stats_info->sw_stat.watchdog_timer_cnt++; + swstats->watchdog_timer_cnt++; schedule_work(&sp->rst_timer_task); - sp->mac_control.stats_info->sw_stat.soft_reset_cnt++; + swstats->soft_reset_cnt++; } } @@ -7423,50 +7387,51 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) unsigned long long err = rxdp->Control_1 & RXD_T_CODE; struct lro *uninitialized_var(lro); u8 err_mask; + struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; skb->dev = dev; if (err) { /* Check for parity error */ if (err & 0x1) - sp->mac_control.stats_info->sw_stat.parity_err_cnt++; + swstats->parity_err_cnt++; err_mask = err >> 48; switch (err_mask) { case 1: - sp->mac_control.stats_info->sw_stat.rx_parity_err_cnt++; + swstats->rx_parity_err_cnt++; break; case 2: - sp->mac_control.stats_info->sw_stat.rx_abort_cnt++; + swstats->rx_abort_cnt++; break; case 3: - sp->mac_control.stats_info->sw_stat.rx_parity_abort_cnt++; + swstats->rx_parity_abort_cnt++; break; case 4: - sp->mac_control.stats_info->sw_stat.rx_rda_fail_cnt++; + swstats->rx_rda_fail_cnt++; break; case 5: - sp->mac_control.stats_info->sw_stat.rx_unkn_prot_cnt++; + swstats->rx_unkn_prot_cnt++; break; case 6: - sp->mac_control.stats_info->sw_stat.rx_fcs_err_cnt++; + swstats->rx_fcs_err_cnt++; break; case 7: - sp->mac_control.stats_info->sw_stat.rx_buf_size_err_cnt++; + swstats->rx_buf_size_err_cnt++; break; case 8: - sp->mac_control.stats_info->sw_stat.rx_rxd_corrupt_cnt++; + swstats->rx_rxd_corrupt_cnt++; break; case 15: - sp->mac_control.stats_info->sw_stat.rx_unkn_err_cnt++; + swstats->rx_unkn_err_cnt++; break; } /* @@ -7480,7 +7445,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%x\n", dev->name, err_mask); dev->stats.rx_crc_errors++; - sp->mac_control.stats_info->sw_stat.mem_freed + swstats->mem_freed += skb->truesize; dev_kfree_skb(skb); ring_data->rx_bufs_left -= 1; @@ -7545,13 +7510,11 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) queue_rx_frame(lro->parent, lro->vlan_tag); clear_lro_session(lro); - sp->mac_control.stats_info-> - sw_stat.flush_max_pkts++; + swstats->flush_max_pkts++; goto aggregate; case 2: /* Flush both */ lro->parent->data_len = lro->frags_len; - sp->mac_control.stats_info-> - sw_stat.sending_both++; + swstats->sending_both++; queue_rx_frame(lro->parent, lro->vlan_tag); clear_lro_session(lro); @@ -7580,7 +7543,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) } else skb->ip_summed = CHECKSUM_NONE; - sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize; + swstats->mem_freed += skb->truesize; send_up: skb_record_rx_queue(skb, ring_no); queue_rx_frame(skb, RXD_GET_VLAN_TAG(rxdp->Control_2)); @@ -7605,6 +7568,7 @@ aggregate: static void s2io_link(struct s2io_nic *sp, int link) { struct net_device *dev = (struct net_device *)sp->dev; + struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; if (link != sp->last_link_state) { init_tti(sp, link); @@ -7612,17 +7576,16 @@ static void s2io_link(struct s2io_nic *sp, int link) DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name); s2io_stop_all_tx_queue(sp); netif_carrier_off(dev); - if (sp->mac_control.stats_info->sw_stat.link_up_cnt) - sp->mac_control.stats_info->sw_stat. - link_up_time = jiffies - sp->start_time; - sp->mac_control.stats_info->sw_stat.link_down_cnt++; + if (swstats->link_up_cnt) + swstats->link_up_time = + jiffies - sp->start_time; + swstats->link_down_cnt++; } else { DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name); - if (sp->mac_control.stats_info->sw_stat.link_down_cnt) - sp->mac_control.stats_info-> - sw_stat.link_down_time = + if (swstats->link_down_cnt) + swstats->link_down_time = jiffies - sp->start_time; - sp->mac_control.stats_info->sw_stat.link_up_cnt++; + swstats->link_up_cnt++; netif_carrier_on(dev); s2io_wake_all_tx_queue(sp); } @@ -7800,8 +7763,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) u64 val64 = 0, tmp64 = 0; struct XENA_dev_config __iomem *bar0 = NULL; u16 subid; - struct mac_info *mac_control; struct config_param *config; + struct mac_info *mac_control; int mode; u8 dev_intr_type = intr_type; u8 dev_multiq = 0; @@ -7887,8 +7850,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) * these parameters are not not specified during load time, they * are initialized with default values. */ - mac_control = &sp->mac_control; config = &sp->config; + mac_control = &sp->mac_control; config->napi = napi; config->tx_steering_type = tx_steering_type; @@ -8433,7 +8396,8 @@ static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro) struct iphdr *ip = lro->iph; struct tcphdr *tcp = lro->tcph; __sum16 nchk; - struct stat_block *statinfo = sp->mac_control.stats_info; + struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; + DBG_PRINT(INFO_DBG, "%s: Been here...\n", __func__); /* Update L3 header */ @@ -8455,8 +8419,8 @@ static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro) /* Update counters required for calculation of * average no. of packets aggregated. */ - statinfo->sw_stat.sum_avg_pkts_aggregated += lro->sg_num; - statinfo->sw_stat.num_aggregations++; + swstats->sum_avg_pkts_aggregated += lro->sg_num; + swstats->num_aggregations++; } static void aggregate_new_rx(struct lro *lro, struct iphdr *ip, @@ -8547,6 +8511,7 @@ static int s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, struct tcphdr *tcph; int ret = 0, i; u16 vlan_tag = 0; + struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp, rxdp, sp); @@ -8572,8 +8537,7 @@ static int s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, (*lro)->tcp_next_seq, ntohl(tcph->seq)); - sp->mac_control.stats_info-> - sw_stat.outof_sequence_pkts++; + swstats->outof_sequence_pkts++; ret = 2; break; } @@ -8667,6 +8631,7 @@ static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro, struct sk_buff *skb, u32 tcp_len) { struct sk_buff *first = lro->parent; + struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; first->len += tcp_len; first->data_len = lro->frags_len; @@ -8677,7 +8642,7 @@ static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro, skb_shinfo(first)->frag_list = skb; first->truesize += skb->truesize; lro->last_frag = skb; - sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++; + swstats->clubbed_frms_cnt++; return; } -- cgit v1.2.3-18-g5258 From 82c2d02356229c66daa6b6e51f8da559327b87b0 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 24 Aug 2009 17:29:48 +0000 Subject: s2io.c: Convert skipped nic->config.tx_cfg[i]. to tx_cfg-> Missed doing the conversion in earlier patch. Signed-off-by: Joe Perches Acked-by: Sreenivasa Honnur Signed-off-by: David S. Miller --- drivers/net/s2io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 06223dfd2e8..1d13f60a9f5 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -1001,7 +1001,7 @@ static void free_shared_mem(struct s2io_nic *nic) swstats->mem_freed += PAGE_SIZE; } kfree(fifo->list_info); - swstats->mem_freed += nic->config.tx_cfg[i].fifo_len * + swstats->mem_freed += tx_cfg->fifo_len * sizeof(struct list_info_hold); } -- cgit v1.2.3-18-g5258 From 9e39f7c5b311a306977c5471f9e2ce4c456aa038 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 25 Aug 2009 08:52:00 +0000 Subject: s2io: Generate complete messages using single line DBG_PRINTs Single line log messages should be emitted by a single call where possible. Converted multiple calls to DBG_PRINT to single call form. Removed "s2io:" preface from DBG_PRINTs. The DBG_PRINT macro now emits a log level and is surrounded by a do {...} while (0) All s2io log output is now prefaced with KBUILD_MODNAME ": " via pr_fmt. The DBG_PRINT macro should probably be converted to use the dev_ form eventually. Signed-off-by: Joe Perches Acked-by: Sreenivasa Honnur Signed-off-by: David S. Miller --- drivers/net/s2io.c | 321 +++++++++++++++++++++++++++-------------------------- drivers/net/s2io.h | 5 +- 2 files changed, 165 insertions(+), 161 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 1d13f60a9f5..3138df5773e 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -652,9 +652,9 @@ static int init_shared_mem(struct s2io_nic *nic) size += tx_cfg->fifo_len; } if (size > MAX_AVAILABLE_TXDS) { - DBG_PRINT(ERR_DBG, "s2io: Requested TxDs too high, "); - DBG_PRINT(ERR_DBG, "Requested: %d, max supported: 8192\n", - size); + DBG_PRINT(ERR_DBG, + "Too many TxDs requested: %d, max supported: %d\n", + size, MAX_AVAILABLE_TXDS); return -EINVAL; } @@ -667,10 +667,9 @@ static int init_shared_mem(struct s2io_nic *nic) * Legal values are from 2 to 8192 */ if (size < 2) { - DBG_PRINT(ERR_DBG, "s2io: Invalid fifo len (%d)", size); - DBG_PRINT(ERR_DBG, "for fifo %d\n", i); - DBG_PRINT(ERR_DBG, "s2io: Legal values for fifo len" - "are 2 to 8192\n"); + DBG_PRINT(ERR_DBG, "Fifo %d: Invalid length (%d) - " + "Valid lengths are 2 through 8192\n", + i, size); return -EINVAL; } } @@ -713,8 +712,8 @@ static int init_shared_mem(struct s2io_nic *nic) tmp_v = pci_alloc_consistent(nic->pdev, PAGE_SIZE, &tmp_p); if (!tmp_v) { - DBG_PRINT(INFO_DBG, "pci_alloc_consistent "); - DBG_PRINT(INFO_DBG, "failed for TxDL\n"); + DBG_PRINT(INFO_DBG, + "pci_alloc_consistent failed for TxDL\n"); return -ENOMEM; } /* If we got a zero DMA address(can happen on @@ -725,17 +724,14 @@ static int init_shared_mem(struct s2io_nic *nic) if (!tmp_p) { mac_control->zerodma_virt_addr = tmp_v; DBG_PRINT(INIT_DBG, - "%s: Zero DMA address for TxDL. ", - dev->name); - DBG_PRINT(INIT_DBG, - "Virtual address %p\n", tmp_v); + "%s: Zero DMA address for TxDL. " + "Virtual address %p\n", + dev->name, tmp_v); tmp_v = pci_alloc_consistent(nic->pdev, PAGE_SIZE, &tmp_p); if (!tmp_v) { DBG_PRINT(INFO_DBG, - "pci_alloc_consistent "); - DBG_PRINT(INFO_DBG, - "failed for TxDL\n"); + "pci_alloc_consistent failed for TxDL\n"); return -ENOMEM; } mem_allocated += PAGE_SIZE; @@ -771,9 +767,9 @@ static int init_shared_mem(struct s2io_nic *nic) struct ring_info *ring = &mac_control->rings[i]; if (rx_cfg->num_rxd % (rxd_count[nic->rxd_mode] + 1)) { - DBG_PRINT(ERR_DBG, "%s: RxD count of ", dev->name); - DBG_PRINT(ERR_DBG, "Ring%d is not a multiple of ", i); - DBG_PRINT(ERR_DBG, "RxDs per Block"); + DBG_PRINT(ERR_DBG, "%s: Ring%d RxD count is not a " + "multiple of RxDs per Block\n", + dev->name, i); return FAILURE; } size += rx_cfg->num_rxd; @@ -927,7 +923,7 @@ static int init_shared_mem(struct s2io_nic *nic) tmp_v_addr = mac_control->stats_mem; mac_control->stats_info = (struct stat_block *)tmp_v_addr; memset(tmp_v_addr, 0, size); - DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name, + DBG_PRINT(INIT_DBG, "%s: Ring Mem PHY: 0x%llx\n", dev->name, (unsigned long long)tmp_p_addr); mac_control->stats_info->sw_stat.mem_allocated += mem_allocated; return SUCCESS; @@ -994,10 +990,9 @@ static void free_shared_mem(struct s2io_nic *nic) mac_control->zerodma_virt_addr, (dma_addr_t)0); DBG_PRINT(INIT_DBG, - "%s: Freeing TxDL with zero DMA addr. ", - dev->name); - DBG_PRINT(INIT_DBG, "Virtual address %p\n", - mac_control->zerodma_virt_addr); + "%s: Freeing TxDL with zero DMA address. " + "Virtual address %p\n", + dev->name, mac_control->zerodma_virt_addr); swstats->mem_freed += PAGE_SIZE; } kfree(fifo->list_info); @@ -1120,6 +1115,7 @@ static int s2io_print_pci_mode(struct s2io_nic *nic) register u64 val64 = 0; int mode; struct config_param *config = &nic->config; + const char *pcimode; val64 = readq(&bar0->pci_mode); mode = (u8)GET_PCI_MODE(val64); @@ -1135,38 +1131,39 @@ static int s2io_print_pci_mode(struct s2io_nic *nic) return mode; } - DBG_PRINT(ERR_DBG, "%s: Device is on %d bit ", - nic->dev->name, val64 & PCI_MODE_32_BITS ? 32 : 64); - switch (mode) { case PCI_MODE_PCI_33: - DBG_PRINT(ERR_DBG, "33MHz PCI bus\n"); + pcimode = "33MHz PCI bus"; break; case PCI_MODE_PCI_66: - DBG_PRINT(ERR_DBG, "66MHz PCI bus\n"); + pcimode = "66MHz PCI bus"; break; case PCI_MODE_PCIX_M1_66: - DBG_PRINT(ERR_DBG, "66MHz PCIX(M1) bus\n"); + pcimode = "66MHz PCIX(M1) bus"; break; case PCI_MODE_PCIX_M1_100: - DBG_PRINT(ERR_DBG, "100MHz PCIX(M1) bus\n"); + pcimode = "100MHz PCIX(M1) bus"; break; case PCI_MODE_PCIX_M1_133: - DBG_PRINT(ERR_DBG, "133MHz PCIX(M1) bus\n"); + pcimode = "133MHz PCIX(M1) bus"; break; case PCI_MODE_PCIX_M2_66: - DBG_PRINT(ERR_DBG, "133MHz PCIX(M2) bus\n"); + pcimode = "133MHz PCIX(M2) bus"; break; case PCI_MODE_PCIX_M2_100: - DBG_PRINT(ERR_DBG, "200MHz PCIX(M2) bus\n"); + pcimode = "200MHz PCIX(M2) bus"; break; case PCI_MODE_PCIX_M2_133: - DBG_PRINT(ERR_DBG, "266MHz PCIX(M2) bus\n"); + pcimode = "266MHz PCIX(M2) bus"; break; default: - return -1; /* Unsupported bus speed */ + pcimode = "unsupported bus!"; + mode = -1; } + DBG_PRINT(ERR_DBG, "%s: Device is on %d bit %s\n", + nic->dev->name, val64 & PCI_MODE_32_BITS ? 32 : 64, pcimode); + return mode; } @@ -1704,9 +1701,9 @@ static int init_nic(struct s2io_nic *nic) /* Disable differentiated services steering logic */ for (i = 0; i < 64; i++) { if (rts_ds_steer(nic, i, 0) == FAILURE) { - DBG_PRINT(ERR_DBG, "%s: failed rts ds steering", - dev->name); - DBG_PRINT(ERR_DBG, "set on codepoint %d\n", i); + DBG_PRINT(ERR_DBG, + "%s: rts_ds_steer failed on codepoint %d\n", + dev->name, i); return -ENODEV; } } @@ -1783,7 +1780,7 @@ static int init_nic(struct s2io_nic *nic) break; if (time > 10) { - DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n", + DBG_PRINT(ERR_DBG, "%s: RTI init failed\n", dev->name); return -ENODEV; } @@ -2189,35 +2186,35 @@ static int verify_xena_quiescence(struct s2io_nic *sp) mode = s2io_verify_pci_mode(sp); if (!(val64 & ADAPTER_STATUS_TDMA_READY)) { - DBG_PRINT(ERR_DBG, "%s", "TDMA is not ready!"); + DBG_PRINT(ERR_DBG, "TDMA is not ready!\n"); return 0; } if (!(val64 & ADAPTER_STATUS_RDMA_READY)) { - DBG_PRINT(ERR_DBG, "%s", "RDMA is not ready!"); + DBG_PRINT(ERR_DBG, "RDMA is not ready!\n"); return 0; } if (!(val64 & ADAPTER_STATUS_PFC_READY)) { - DBG_PRINT(ERR_DBG, "%s", "PFC is not ready!"); + DBG_PRINT(ERR_DBG, "PFC is not ready!\n"); return 0; } if (!(val64 & ADAPTER_STATUS_TMAC_BUF_EMPTY)) { - DBG_PRINT(ERR_DBG, "%s", "TMAC BUF is not empty!"); + DBG_PRINT(ERR_DBG, "TMAC BUF is not empty!\n"); return 0; } if (!(val64 & ADAPTER_STATUS_PIC_QUIESCENT)) { - DBG_PRINT(ERR_DBG, "%s", "PIC is not QUIESCENT!"); + DBG_PRINT(ERR_DBG, "PIC is not QUIESCENT!\n"); return 0; } if (!(val64 & ADAPTER_STATUS_MC_DRAM_READY)) { - DBG_PRINT(ERR_DBG, "%s", "MC_DRAM is not ready!"); + DBG_PRINT(ERR_DBG, "MC_DRAM is not ready!\n"); return 0; } if (!(val64 & ADAPTER_STATUS_MC_QUEUES_READY)) { - DBG_PRINT(ERR_DBG, "%s", "MC_QUEUES is not ready!"); + DBG_PRINT(ERR_DBG, "MC_QUEUES is not ready!\n"); return 0; } if (!(val64 & ADAPTER_STATUS_M_PLL_LOCK)) { - DBG_PRINT(ERR_DBG, "%s", "M_PLL is not locked!"); + DBG_PRINT(ERR_DBG, "M_PLL is not locked!\n"); return 0; } @@ -2229,12 +2226,12 @@ static int verify_xena_quiescence(struct s2io_nic *sp) if (!(val64 & ADAPTER_STATUS_P_PLL_LOCK) && sp->device_type == XFRAME_II_DEVICE && mode != PCI_MODE_PCI_33) { - DBG_PRINT(ERR_DBG, "%s", "P_PLL is not locked!"); + DBG_PRINT(ERR_DBG, "P_PLL is not locked!\n"); return 0; } if (!((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == ADAPTER_STATUS_RC_PRC_QUIESCENT)) { - DBG_PRINT(ERR_DBG, "%s", "RC_PRC is not QUIESCENT!"); + DBG_PRINT(ERR_DBG, "RC_PRC is not QUIESCENT!\n"); return 0; } return 1; @@ -2339,9 +2336,9 @@ static int start_nic(struct s2io_nic *nic) */ val64 = readq(&bar0->adapter_status); if (!verify_xena_quiescence(nic)) { - DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name); - DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n", - (unsigned long long)val64); + DBG_PRINT(ERR_DBG, "%s: device is not ready, " + "Adapter status reads: 0x%llx\n", + dev->name, (unsigned long long)val64); return FAILURE; } @@ -2455,7 +2452,7 @@ static void free_tx_buffers(struct s2io_nic *nic) } } DBG_PRINT(INTR_DBG, - "%s:forcibly freeing %d skbs on FIFO%d\n", + "%s: forcibly freeing %d skbs on FIFO%d\n", dev->name, cnt, i); fifo->tx_curr_get_info.offset = 0; fifo->tx_curr_put_info.offset = 0; @@ -2547,8 +2544,8 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, if ((block_no == block_no1) && (off == ring->rx_curr_get_info.offset) && (rxdp->Host_Control)) { - DBG_PRINT(INTR_DBG, "%s: Get and Put", ring->dev->name); - DBG_PRINT(INTR_DBG, " info equated\n"); + DBG_PRINT(INTR_DBG, "%s: Get and Put info equated\n", + ring->dev->name); goto end; } if (off && (off == ring->rxd_count)) { @@ -2583,8 +2580,8 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, /* allocate skb */ skb = dev_alloc_skb(size); if (!skb) { - DBG_PRINT(INFO_DBG, "%s: Out of ", ring->dev->name); - DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n"); + DBG_PRINT(INFO_DBG, "%s: Could not allocate skb\n", + ring->dev->name); if (first_rxdp) { wmb(); first_rxdp->Control_1 |= RXD_OWN_XENA; @@ -2806,7 +2803,7 @@ static void free_rx_buffers(struct s2io_nic *sp) ring->rx_curr_put_info.offset = 0; ring->rx_curr_get_info.offset = 0; ring->rx_bufs_left = 0; - DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n", + DBG_PRINT(INIT_DBG, "%s: Freed 0x%x Rx Buffers on ring%d\n", dev->name, buf_cnt, i); } } @@ -2814,8 +2811,8 @@ static void free_rx_buffers(struct s2io_nic *sp) static int s2io_chk_rx_buffers(struct s2io_nic *nic, struct ring_info *ring) { if (fill_rx_buffers(nic, ring, 0) == -ENOMEM) { - DBG_PRINT(INFO_DBG, "%s:Out of memory", ring->dev->name); - DBG_PRINT(INFO_DBG, " in Rx Intr!!\n"); + DBG_PRINT(INFO_DBG, "%s: Out of memory in Rx Intr!!\n", + ring->dev->name); } return 0; } @@ -2938,8 +2935,9 @@ static void s2io_netpoll(struct net_device *dev) struct ring_info *ring = &mac_control->rings[i]; if (fill_rx_buffers(nic, ring, 0) == -ENOMEM) { - DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name); - DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n"); + DBG_PRINT(INFO_DBG, + "%s: Out of memory in Rx Netpoll!!\n", + dev->name); break; } } @@ -2991,9 +2989,8 @@ static int rx_intr_handler(struct ring_info *ring_data, int budget) } skb = (struct sk_buff *)((unsigned long)rxdp->Host_Control); if (skb == NULL) { - DBG_PRINT(ERR_DBG, "%s: The skb is ", + DBG_PRINT(ERR_DBG, "%s: NULL skb in Rx Intr\n", ring_data->dev->name); - DBG_PRINT(ERR_DBG, "Null in Rx Intr\n"); return 0; } if (ring_data->rxd_mode == RXD_MODE_1) { @@ -3126,8 +3123,8 @@ static void tx_intr_handler(struct fifo_info *fifo_data) skb = s2io_txdl_getskb(fifo_data, txdlp, get_info.offset); if (skb == NULL) { spin_unlock_irqrestore(&fifo_data->tx_lock, flags); - DBG_PRINT(ERR_DBG, "%s: Null skb ", __func__); - DBG_PRINT(ERR_DBG, "in Tx Free Intr\n"); + DBG_PRINT(ERR_DBG, "%s: NULL skb in Tx Free Intr\n", + __func__); return; } pkt_cnt++; @@ -3266,22 +3263,22 @@ static void s2io_chk_xpak_counter(u64 *counter, u64 * regs_stat, u32 index, if (val64 == 3) { switch (type) { case 1: - DBG_PRINT(ERR_DBG, "Take Xframe NIC out of " - "service. Excessive temperatures may " - "result in premature transceiver " - "failure \n"); + DBG_PRINT(ERR_DBG, + "Take Xframe NIC out of service.\n"); + DBG_PRINT(ERR_DBG, +"Excessive temperatures may result in premature transceiver failure.\n"); break; case 2: - DBG_PRINT(ERR_DBG, "Take Xframe NIC out of " - "service Excessive bias currents may " - "indicate imminent laser diode " - "failure \n"); + DBG_PRINT(ERR_DBG, + "Take Xframe NIC out of service.\n"); + DBG_PRINT(ERR_DBG, +"Excessive bias currents may indicate imminent laser diode failure.\n"); break; case 3: - DBG_PRINT(ERR_DBG, "Take Xframe NIC out of " - "service Excessive laser output " - "power may saturate far-end " - "receiver\n"); + DBG_PRINT(ERR_DBG, + "Take Xframe NIC out of service.\n"); + DBG_PRINT(ERR_DBG, +"Excessive laser output power may saturate far-end receiver.\n"); break; default: DBG_PRINT(ERR_DBG, @@ -3321,15 +3318,16 @@ static void s2io_updt_xpak_counter(struct net_device *dev) val64 = 0x0; val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); if ((val64 == 0xFFFF) || (val64 == 0x0000)) { - DBG_PRINT(ERR_DBG, "ERR: MDIO slave access failed - " - "Returned %llx\n", (unsigned long long)val64); + DBG_PRINT(ERR_DBG, + "ERR: MDIO slave access failed - Returned %llx\n", + (unsigned long long)val64); return; } /* Check for the expected value of control reg 1 */ if (val64 != MDIO_CTRL1_SPEED10G) { - DBG_PRINT(ERR_DBG, "Incorrect value at PMA address 0x0000 - "); - DBG_PRINT(ERR_DBG, "Returned: %llx- Expected: 0x%x\n", + DBG_PRINT(ERR_DBG, "Incorrect value at PMA address 0x0000 - " + "Returned: %llx- Expected: 0x%x\n", (unsigned long long)val64, MDIO_CTRL1_SPEED10G); return; } @@ -3481,7 +3479,7 @@ static void s2io_reset(struct s2io_nic *sp) struct stat_block *stats; struct swStat *swstats; - DBG_PRINT(INIT_DBG, "%s - Resetting XFrame card %s\n", + DBG_PRINT(INIT_DBG, "%s: Resetting XFrame card %s\n", __func__, sp->dev->name); /* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */ @@ -3618,10 +3616,9 @@ static int s2io_set_swapper(struct s2io_nic *sp) i++; } if (i == 4) { - DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ", - dev->name); - DBG_PRINT(ERR_DBG, "feedback read %llx\n", - (unsigned long long)val64); + DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, " + "feedback read %llx\n", + dev->name, (unsigned long long)val64); return FAILURE; } valr = value[i]; @@ -3650,8 +3647,8 @@ static int s2io_set_swapper(struct s2io_nic *sp) } if (i == 4) { unsigned long long x = val64; - DBG_PRINT(ERR_DBG, "Write failed, Xmsi_addr "); - DBG_PRINT(ERR_DBG, "reads:0x%llx\n", x); + DBG_PRINT(ERR_DBG, + "Write failed, Xmsi_addr reads:0x%llx\n", x); return FAILURE; } } @@ -3711,10 +3708,9 @@ static int s2io_set_swapper(struct s2io_nic *sp) val64 = readq(&bar0->pif_rd_swapper_fb); if (val64 != 0x0123456789ABCDEFULL) { /* Endian settings are incorrect, calls for another dekko. */ - DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, ", - dev->name); - DBG_PRINT(ERR_DBG, "feedback read %llx\n", - (unsigned long long)val64); + DBG_PRINT(ERR_DBG, + "%s: Endian settings are wrong, feedback read %llx\n", + dev->name, (unsigned long long)val64); return FAILURE; } @@ -3758,7 +3754,8 @@ static void restore_xmsi_data(struct s2io_nic *nic) val64 = (s2BIT(7) | s2BIT(15) | vBIT(msix_index, 26, 6)); writeq(val64, &bar0->xmsi_access); if (wait_for_msix_trans(nic, msix_index)) { - DBG_PRINT(ERR_DBG, "failed in %s\n", __func__); + DBG_PRINT(ERR_DBG, "%s: index: %d failed\n", + __func__, msix_index); continue; } } @@ -3779,7 +3776,8 @@ static void store_xmsi_data(struct s2io_nic *nic) val64 = (s2BIT(15) | vBIT(msix_index, 26, 6)); writeq(val64, &bar0->xmsi_access); if (wait_for_msix_trans(nic, msix_index)) { - DBG_PRINT(ERR_DBG, "failed in %s\n", __func__); + DBG_PRINT(ERR_DBG, "%s: index: %d failed\n", + __func__, msix_index); continue; } addr = readq(&bar0->xmsi_address); @@ -3851,7 +3849,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) ret = pci_enable_msix(nic->pdev, nic->entries, nic->num_entries); /* We fail init if error or we get less vectors than min required */ if (ret) { - DBG_PRINT(ERR_DBG, "s2io: Enabling MSI-X failed\n"); + DBG_PRINT(ERR_DBG, "Enabling MSI-X failed\n"); kfree(nic->entries); swstats->mem_freed += nic->num_entries * sizeof(struct msix_entry); @@ -3915,8 +3913,8 @@ static int s2io_test_msi(struct s2io_nic *sp) if (!sp->msi_detected) { /* MSI(X) test failed, go back to INTx mode */ DBG_PRINT(ERR_DBG, "%s: PCI %s: No interrupt was generated " - "using MSI(X) during test\n", sp->dev->name, - pci_name(pdev)); + "using MSI(X) during test\n", + sp->dev->name, pci_name(pdev)); err = -EOPNOTSUPP; } @@ -4095,7 +4093,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) DBG_PRINT(TX_DBG, "%s: In Neterion Tx routine\n", dev->name); if (unlikely(skb->len <= 0)) { - DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name); + DBG_PRINT(TX_DBG, "%s: Buffer has no data..\n", dev->name); dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -5052,18 +5050,17 @@ static void s2io_set_multicast(struct net_device *dev) val64 = readq(&bar0->mac_cfg); sp->promisc_flg = 0; - DBG_PRINT(INFO_DBG, "%s: left promiscuous mode\n", - dev->name); + DBG_PRINT(INFO_DBG, "%s: left promiscuous mode\n", dev->name); } /* Update individual M_CAST address list */ if ((!sp->m_cast_flg) && dev->mc_count) { if (dev->mc_count > (config->max_mc_addr - config->max_mac_addr)) { - DBG_PRINT(ERR_DBG, "%s: No more Rx filters ", + DBG_PRINT(ERR_DBG, + "%s: No more Rx filters can be added - " + "please enable ALL_MULTI instead\n", dev->name); - DBG_PRINT(ERR_DBG, "can be added, please enable "); - DBG_PRINT(ERR_DBG, "ALL_MULTI instead\n"); return; } @@ -5086,8 +5083,9 @@ static void s2io_set_multicast(struct net_device *dev) if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET)) { - DBG_PRINT(ERR_DBG, "%s: Adding ", dev->name); - DBG_PRINT(ERR_DBG, "Multicasts failed\n"); + DBG_PRINT(ERR_DBG, + "%s: Adding Multicasts failed\n", + dev->name); return; } } @@ -5117,8 +5115,9 @@ static void s2io_set_multicast(struct net_device *dev) if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET)) { - DBG_PRINT(ERR_DBG, "%s: Adding ", dev->name); - DBG_PRINT(ERR_DBG, "Multicasts failed\n"); + DBG_PRINT(ERR_DBG, + "%s: Adding Multicasts failed\n", + dev->name); return; } } @@ -5552,7 +5551,7 @@ static void s2io_ethtool_gringparam(struct net_device *dev, for (i = 0 ; i < sp->config.tx_fifo_num ; i++) tx_desc_count += sp->config.tx_cfg[i].fifo_len; - DBG_PRINT(INFO_DBG, "\nmax txds : %d\n", sp->config.max_txds); + DBG_PRINT(INFO_DBG, "max txds: %d\n", sp->config.max_txds); ering->tx_pending = tx_desc_count; rx_desc_count = 0; for (i = 0 ; i < sp->config.rx_ring_num ; i++) @@ -5886,8 +5885,10 @@ static int s2io_ethtool_seeprom(struct net_device *dev, if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) { DBG_PRINT(ERR_DBG, - "ETHTOOL_WRITE_EEPROM Err: Magic value "); - DBG_PRINT(ERR_DBG, "is wrong, Its not 0x%x\n", eeprom->magic); + "ETHTOOL_WRITE_EEPROM Err: " + "Magic value is wrong, it is 0x%x should be 0x%x\n", + (sp->pdev->vendor | (sp->pdev->device << 16)), + eeprom->magic); return -EFAULT; } @@ -5900,9 +5901,8 @@ static int s2io_ethtool_seeprom(struct net_device *dev, if (write_eeprom(sp, (eeprom->offset + cnt), valid, 0)) { DBG_PRINT(ERR_DBG, - "ETHTOOL_WRITE_EEPROM Err: Cannot "); - DBG_PRINT(ERR_DBG, - "write into the specified offset\n"); + "ETHTOOL_WRITE_EEPROM Err: " + "Cannot write into the specified offset\n"); return -EFAULT; } cnt++; @@ -5934,13 +5934,13 @@ static int s2io_register_test(struct s2io_nic *sp, uint64_t *data) val64 = readq(&bar0->pif_rd_swapper_fb); if (val64 != 0x123456789abcdefULL) { fail = 1; - DBG_PRINT(INFO_DBG, "Read Test level 1 fails\n"); + DBG_PRINT(INFO_DBG, "Read Test level %d fails\n", 1); } val64 = readq(&bar0->rmac_pause_cfg); if (val64 != 0xc000ffff00000000ULL) { fail = 1; - DBG_PRINT(INFO_DBG, "Read Test level 2 fails\n"); + DBG_PRINT(INFO_DBG, "Read Test level %d fails\n", 2); } val64 = readq(&bar0->rx_queue_cfg); @@ -5950,13 +5950,13 @@ static int s2io_register_test(struct s2io_nic *sp, uint64_t *data) exp_val = 0x0808080808080808ULL; if (val64 != exp_val) { fail = 1; - DBG_PRINT(INFO_DBG, "Read Test level 3 fails\n"); + DBG_PRINT(INFO_DBG, "Read Test level %d fails\n", 3); } val64 = readq(&bar0->xgxs_efifo_cfg); if (val64 != 0x000000001923141EULL) { fail = 1; - DBG_PRINT(INFO_DBG, "Read Test level 4 fails\n"); + DBG_PRINT(INFO_DBG, "Read Test level %d fails\n", 4); } val64 = 0x5A5A5A5A5A5A5A5AULL; @@ -5964,7 +5964,7 @@ static int s2io_register_test(struct s2io_nic *sp, uint64_t *data) val64 = readq(&bar0->xmsi_data); if (val64 != 0x5A5A5A5A5A5A5A5AULL) { fail = 1; - DBG_PRINT(ERR_DBG, "Write Test level 1 fails\n"); + DBG_PRINT(ERR_DBG, "Write Test level %d fails\n", 1); } val64 = 0xA5A5A5A5A5A5A5A5ULL; @@ -5972,7 +5972,7 @@ static int s2io_register_test(struct s2io_nic *sp, uint64_t *data) val64 = readq(&bar0->xmsi_data); if (val64 != 0xA5A5A5A5A5A5A5A5ULL) { fail = 1; - DBG_PRINT(ERR_DBG, "Write Test level 2 fails\n"); + DBG_PRINT(ERR_DBG, "Write Test level %d fails\n", 2); } *data = fail; @@ -6825,8 +6825,9 @@ static void s2io_set_link(struct work_struct *work) } nic->device_enabled_once = true; } else { - DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name); - DBG_PRINT(ERR_DBG, "device is not Quiescent\n"); + DBG_PRINT(ERR_DBG, + "%s: Error: device is not Quiescent\n", + dev->name); s2io_stop_all_tx_queue(nic); } } @@ -6876,9 +6877,9 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, } else { *skb = dev_alloc_skb(size); if (!(*skb)) { - DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name); - DBG_PRINT(INFO_DBG, "memory to allocate "); - DBG_PRINT(INFO_DBG, "1 buf mode SKBs\n"); + DBG_PRINT(INFO_DBG, + "%s: Out of memory to allocate %s\n", + dev->name, "1 buf mode SKBs"); stats->mem_alloc_fail_cnt++; return -ENOMEM ; } @@ -6905,9 +6906,10 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, } else { *skb = dev_alloc_skb(size); if (!(*skb)) { - DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name); - DBG_PRINT(INFO_DBG, "memory to allocate "); - DBG_PRINT(INFO_DBG, "2 buf mode SKBs\n"); + DBG_PRINT(INFO_DBG, + "%s: Out of memory to allocate %s\n", + dev->name, + "2 buf mode SKBs"); stats->mem_alloc_fail_cnt++; return -ENOMEM; } @@ -7095,8 +7097,8 @@ static int s2io_add_isr(struct s2io_nic *sp) } if (!err) { pr_info("MSI-X-RX %d entries enabled\n", --msix_rx_cnt); - DBG_PRINT(INFO_DBG, "MSI-X-TX entries enabled" - " through alarm vector\n"); + DBG_PRINT(INFO_DBG, + "MSI-X-TX entries enabled through alarm vector\n"); } } if (sp->config.intr_type == INTA) { @@ -7176,8 +7178,8 @@ static void do_s2io_card_down(struct s2io_nic *sp, int do_io) msleep(50); cnt++; if (cnt == 10) { - DBG_PRINT(ERR_DBG, "s2io_close:Device not Quiescent "); - DBG_PRINT(ERR_DBG, "adaper status reads 0x%llx\n", + DBG_PRINT(ERR_DBG, "Device not Quiescent - " + "adapter status reads 0x%llx\n", (unsigned long long)val64); break; } @@ -7628,7 +7630,7 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, u8 *dev_multiq) { if ((tx_fifo_num > MAX_TX_FIFOS) || (tx_fifo_num < 1)) { - DBG_PRINT(ERR_DBG, "s2io: Requested number of tx fifos " + DBG_PRINT(ERR_DBG, "Requested number of tx fifos " "(%d) not supported\n", tx_fifo_num); if (tx_fifo_num < 1) @@ -7636,8 +7638,7 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, else tx_fifo_num = MAX_TX_FIFOS; - DBG_PRINT(ERR_DBG, "s2io: Default to %d ", tx_fifo_num); - DBG_PRINT(ERR_DBG, "tx fifos\n"); + DBG_PRINT(ERR_DBG, "Default to %d tx fifos\n", tx_fifo_num); } if (multiq) @@ -7646,7 +7647,7 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, if (tx_steering_type && (1 == tx_fifo_num)) { if (tx_steering_type != TX_DEFAULT_STEERING) DBG_PRINT(ERR_DBG, - "s2io: Tx steering is not supported with " + "Tx steering is not supported with " "one fifo. Disabling Tx steering.\n"); tx_steering_type = NO_STEERING; } @@ -7654,21 +7655,21 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, if ((tx_steering_type < NO_STEERING) || (tx_steering_type > TX_DEFAULT_STEERING)) { DBG_PRINT(ERR_DBG, - "s2io: Requested transmit steering not supported\n"); - DBG_PRINT(ERR_DBG, "s2io: Disabling transmit steering\n"); + "Requested transmit steering not supported\n"); + DBG_PRINT(ERR_DBG, "Disabling transmit steering\n"); tx_steering_type = NO_STEERING; } if (rx_ring_num > MAX_RX_RINGS) { DBG_PRINT(ERR_DBG, - "s2io: Requested number of rx rings not supported\n"); - DBG_PRINT(ERR_DBG, "s2io: Default to %d rx rings\n", + "Requested number of rx rings not supported\n"); + DBG_PRINT(ERR_DBG, "Default to %d rx rings\n", MAX_RX_RINGS); rx_ring_num = MAX_RX_RINGS; } if ((*dev_intr_type != INTA) && (*dev_intr_type != MSI_X)) { - DBG_PRINT(ERR_DBG, "s2io: Wrong intr_type requested. " + DBG_PRINT(ERR_DBG, "Wrong intr_type requested. " "Defaulting to INTA\n"); *dev_intr_type = INTA; } @@ -7676,14 +7677,14 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, if ((*dev_intr_type == MSI_X) && ((pdev->device != PCI_DEVICE_ID_HERC_WIN) && (pdev->device != PCI_DEVICE_ID_HERC_UNI))) { - DBG_PRINT(ERR_DBG, "s2io: Xframe I does not support MSI_X. " + DBG_PRINT(ERR_DBG, "Xframe I does not support MSI_X. " "Defaulting to INTA\n"); *dev_intr_type = INTA; } if ((rx_ring_mode != 1) && (rx_ring_mode != 2)) { - DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n"); - DBG_PRINT(ERR_DBG, "s2io: Defaulting to 1-buffer mode\n"); + DBG_PRINT(ERR_DBG, "Requested ring mode not supported\n"); + DBG_PRINT(ERR_DBG, "Defaulting to 1-buffer mode\n"); rx_ring_mode = 1; } return SUCCESS; @@ -7776,12 +7777,12 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) ret = pci_enable_device(pdev); if (ret) { DBG_PRINT(ERR_DBG, - "s2io_init_nic: pci_enable_device failed\n"); + "%s: pci_enable_device failed\n", __func__); return ret; } if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n"); + DBG_PRINT(INIT_DBG, "%s: Using 64bit DMA\n", __func__); dma_flag = true; if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { DBG_PRINT(ERR_DBG, @@ -7791,14 +7792,14 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) return -ENOMEM; } } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 32bit DMA\n"); + DBG_PRINT(INIT_DBG, "%s: Using 32bit DMA\n", __func__); } else { pci_disable_device(pdev); return -ENOMEM; } ret = pci_request_regions(pdev, s2io_driver_name); if (ret) { - DBG_PRINT(ERR_DBG, "%s: Request Regions failed - %x \n", + DBG_PRINT(ERR_DBG, "%s: Request Regions failed - %x\n", __func__, ret); pci_disable_device(pdev); return -ENODEV; @@ -7992,7 +7993,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* Setting swapper control on the NIC, for proper reset operation */ if (s2io_set_swapper(sp)) { - DBG_PRINT(ERR_DBG, "%s:swapper settings are wrong\n", + DBG_PRINT(ERR_DBG, "%s: swapper settings are wrong\n", dev->name); ret = -EAGAIN; goto set_swap_failed; @@ -8002,8 +8003,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (sp->device_type & XFRAME_II_DEVICE) { mode = s2io_verify_pci_mode(sp); if (mode < 0) { - DBG_PRINT(ERR_DBG, "%s: ", __func__); - DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n"); + DBG_PRINT(ERR_DBG, "%s: Unsupported PCI bus mode\n", + __func__); ret = -EBADSLT; goto set_swap_failed; } @@ -8021,7 +8022,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (ret) { DBG_PRINT(ERR_DBG, - "s2io: MSI-X requested but failed to enable\n"); + "MSI-X requested but failed to enable\n"); sp->config.intr_type = INTA; } } @@ -8137,12 +8138,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) sp->product_name, pdev->revision); DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name, s2io_driver_version); - DBG_PRINT(ERR_DBG, "%s: MAC ADDR: %pM\n", dev->name, dev->dev_addr); - DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num); + DBG_PRINT(ERR_DBG, "%s: MAC Address: %pM\n", dev->name, dev->dev_addr); + DBG_PRINT(ERR_DBG, "Serial number: %s\n", sp->serial_num); if (sp->device_type & XFRAME_II_DEVICE) { mode = s2io_print_pci_mode(sp); if (mode < 0) { - DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n"); ret = -EBADSLT; unregister_netdev(dev); goto set_swap_failed; @@ -8532,8 +8532,9 @@ static int s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, *lro = l_lro; if ((*lro)->tcp_next_seq != ntohl(tcph->seq)) { - DBG_PRINT(INFO_DBG, "%s:Out of order. expected " - "0x%x, actual 0x%x\n", __func__, + DBG_PRINT(INFO_DBG, "%s: Out of sequence. " + "expected 0x%x, actual 0x%x\n", + __func__, (*lro)->tcp_next_seq, ntohl(tcph->seq)); @@ -8571,7 +8572,7 @@ static int s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, } if (ret == 0) { /* sessions exceeded */ - DBG_PRINT(INFO_DBG, "%s:All LRO sessions already in use\n", + DBG_PRINT(INFO_DBG, "%s: All LRO sessions already in use\n", __func__); *lro = NULL; return ret; @@ -8593,7 +8594,7 @@ static int s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, } break; default: - DBG_PRINT(ERR_DBG, "%s:Dont know, can't say!!\n", __func__); + DBG_PRINT(ERR_DBG, "%s: Don't know, can't say!!\n", __func__); break; } diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index d5c5be6c07b..47c36e0994f 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -64,7 +64,10 @@ enum { static int debug_level = ERR_DBG; /* DEBUG message print. */ -#define DBG_PRINT(dbg_level, args...) if(!(debug_level= debug_level) \ + pr_info(fmt, ##args); \ + } while (0) /* Protocol assist features of the NIC */ #define L3_CKSUM_OK 0xFFFF -- cgit v1.2.3-18-g5258 From 5027309b5581e9c251a46f0ecbf88996d5e0f1e0 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Fri, 28 Aug 2009 09:44:45 -0700 Subject: iwlwifi: remove 60 Mbps from sband bitrates table ieee80211_supported_band is supposed to only contain legacy rates in the bitrates table (HT rates go in the ieee80211_sta_ht_cap substruct). Make iwlwifi driver obey this restriction by removing the 60 Mbps rate. Also, clean up a few pieces of other code that formerly relied on 60 Mbps being in sband->bitrates. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 48 +++++++++++++------------------ drivers/net/wireless/iwlwifi/iwl-agn-rs.h | 1 + drivers/net/wireless/iwlwifi/iwl-core.c | 12 ++++---- 3 files changed, 27 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 26ec969e265..8239e5508ca 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -818,15 +818,15 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, { int status; u8 retries; - int rs_index, index = 0; + int rs_index, mac_index, index = 0; struct iwl_lq_sta *lq_sta = priv_sta; struct iwl_link_quality_cmd *table; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct iwl_priv *priv = (struct iwl_priv *)priv_r; - struct ieee80211_hw *hw = priv->hw; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_rate_scale_data *window = NULL; struct iwl_rate_scale_data *search_win = NULL; + enum mac80211_rate_control_flags mac_flags; u32 tx_rate; struct iwl_scale_tbl_info tbl_type; struct iwl_scale_tbl_info *curr_tbl, *search_tbl; @@ -876,16 +876,17 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); if (priv->band == IEEE80211_BAND_5GHZ) rs_index -= IWL_FIRST_OFDM_RATE; + mac_flags = info->status.rates[0].flags; + mac_index = info->status.rates[0].idx; - if ((info->status.rates[0].idx < 0) || - (tbl_type.is_SGI != !!(info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) || - (tbl_type.is_ht40 != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || - (tbl_type.is_dup != !!(info->status.rates[0].flags & IEEE80211_TX_RC_DUP_DATA)) || + if ((mac_index < 0) || + (tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) || + (tbl_type.is_ht40 != !!(mac_flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || + (tbl_type.is_dup != !!(mac_flags & IEEE80211_TX_RC_DUP_DATA)) || (tbl_type.ant_type != info->antenna_sel_tx) || - (!!(tx_rate & RATE_MCS_HT_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) || - (!!(tx_rate & RATE_MCS_GF_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)) || - (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != - hw->wiphy->bands[info->band]->bitrates[info->status.rates[0].idx].bitrate)) { + (!!(tx_rate & RATE_MCS_HT_MSK) != !!(mac_flags & IEEE80211_TX_RC_MCS)) || + (!!(tx_rate & RATE_MCS_GF_MSK) != !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) || + rs_index != mac_index) { IWL_DEBUG_RATE(priv, "initial rate does not match 0x%x\n", tx_rate); /* the last LQ command could failed so the LQ in ucode not * the same in driver sync up @@ -2542,8 +2543,12 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, if (lq_sta->last_rate_n_flags & RATE_MCS_GF_MSK) info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD; } else { - if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT) + /* Check for invalid rates */ + if ((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT_LEGACY) || + ((sband->band == IEEE80211_BAND_5GHZ) && + (rate_idx < IWL_FIRST_OFDM_RATE))) rate_idx = rate_lowest_index(sband, sta); + /* On valid 5 GHz rate, adjust index */ else if (sband->band == IEEE80211_BAND_5GHZ) rate_idx -= IWL_FIRST_OFDM_RATE; info->control.rates[0].flags = 0; @@ -2584,9 +2589,6 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, struct ieee80211_conf *conf = &priv->hw->conf; struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; struct iwl_lq_sta *lq_sta = priv_sta; - u16 mask_bit = 0; - int count; - int start_rate = 0; lq_sta->flush_timer = 0; lq_sta->supp_rates = sta->supp_rates[sband->band]; @@ -2661,20 +2663,10 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; lq_sta->drv = priv; - /* Find highest tx rate supported by hardware and destination station */ - mask_bit = sta->supp_rates[sband->band]; - count = sband->n_bitrates; - if (sband->band == IEEE80211_BAND_5GHZ) { - count += IWL_FIRST_OFDM_RATE; - start_rate = IWL_FIRST_OFDM_RATE; - mask_bit <<= IWL_FIRST_OFDM_RATE; - } - - mask_bit = mask_bit & lq_sta->active_legacy_rate; - lq_sta->last_txrate_idx = 4; - for (i = start_rate; i < count; i++) - if (mask_bit & BIT(i)) - lq_sta->last_txrate_idx = i; + /* Set last_txrate_idx to lowest rate */ + lq_sta->last_txrate_idx = rate_lowest_index(sband, sta); + if (sband->band == IEEE80211_BAND_5GHZ) + lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; rs_initialize_lq(priv, conf, sta, lq_sta); } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 25050bf315a..9fac530cfb7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -73,6 +73,7 @@ enum { IWL_RATE_54M_INDEX, IWL_RATE_60M_INDEX, IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/ + IWL_RATE_COUNT_LEGACY = IWL_RATE_COUNT - 1, /* Excluding 60M */ IWL_RATE_COUNT_3945 = IWL_RATE_COUNT - 1, IWL_RATE_INVM_INDEX = IWL_RATE_COUNT, IWL_RATE_INVALID = IWL_RATE_COUNT, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 0bfd4e91813..813582467ff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -439,12 +439,12 @@ static void iwlcore_init_hw_rates(struct iwl_priv *priv, { int i; - for (i = 0; i < IWL_RATE_COUNT; i++) { + for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) { rates[i].bitrate = iwl_rates[i].ieee * 5; rates[i].hw_value = i; /* Rate scaling will work on indexes */ rates[i].hw_value_short = i; rates[i].flags = 0; - if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) { + if ((i >= IWL_FIRST_CCK_RATE) && (i <= IWL_LAST_CCK_RATE)) { /* * If CCK != 1M then set short preamble rate flag. */ @@ -480,7 +480,7 @@ int iwlcore_init_geos(struct iwl_priv *priv) if (!channels) return -ENOMEM; - rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)), + rates = kzalloc((sizeof(struct ieee80211_rate) * IWL_RATE_COUNT_LEGACY), GFP_KERNEL); if (!rates) { kfree(channels); @@ -492,7 +492,7 @@ int iwlcore_init_geos(struct iwl_priv *priv) sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)]; /* just OFDM */ sband->bitrates = &rates[IWL_FIRST_OFDM_RATE]; - sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE; + sband->n_bitrates = IWL_RATE_COUNT_LEGACY - IWL_FIRST_OFDM_RATE; if (priv->cfg->sku & IWL_SKU_N) iwlcore_init_ht_hw_capab(priv, &sband->ht_cap, @@ -502,7 +502,7 @@ int iwlcore_init_geos(struct iwl_priv *priv) sband->channels = channels; /* OFDM & CCK */ sband->bitrates = rates; - sband->n_bitrates = IWL_RATE_COUNT; + sband->n_bitrates = IWL_RATE_COUNT_LEGACY; if (priv->cfg->sku & IWL_SKU_N) iwlcore_init_ht_hw_capab(priv, &sband->ht_cap, @@ -1231,7 +1231,7 @@ static void iwl_set_rate(struct iwl_priv *priv) for (i = 0; i < hw->n_bitrates; i++) { rate = &(hw->bitrates[i]); - if (rate->hw_value < IWL_RATE_COUNT) + if (rate->hw_value < IWL_RATE_COUNT_LEGACY) priv->active_rate |= (1 << rate->hw_value); } -- cgit v1.2.3-18-g5258 From b58ef214b7db57cfcbca0e1edae08566cdfd56b7 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Fri, 28 Aug 2009 09:44:46 -0700 Subject: iwlwifi: remove incorrect uses of ieee80211_get_tx_rate to prevent TX stall Refactor and correct rate selection for outgoing transmitted packets. First, note that HT rates in the mac80211 rate table do not provide valid indices when ieee80211_get_tx_rate is called; the check to see if we could to abort a transmission early in iwl_tx_skb() would thus occasionally read invalid memory and occasionally stall transmission (if the erroneous byte was 0xff). We remove that code; the check wasn't valid anyway. Second, iwl_tx_cmd_build_rate() also called ieee80211_get_tx_rate to be used for sending management packets, which do not use the uCode station table. This patch refactors that function and adds comments to enhance legibility, replaces the call to ieee80211_get_tx_rate() with a direct lookup, and adds error handling in case the table entry is invalid. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 111 +++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 7bc9c0039f7..a7422e52d88 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -566,62 +566,81 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv, static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, struct iwl_tx_cmd *tx_cmd, struct ieee80211_tx_info *info, - __le16 fc, int sta_id, - int is_hcca) + __le16 fc, int is_hcca) { - u32 rate_flags = 0; + u32 rate_flags; int rate_idx; - u8 rts_retry_limit = 0; - u8 data_retry_limit = 0; + u8 rts_retry_limit; + u8 data_retry_limit; u8 rate_plcp; - rate_idx = min(ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xffff, - IWL_RATE_COUNT - 1); - - rate_plcp = iwl_rates[rate_idx].plcp; - - rts_retry_limit = (is_hcca) ? - RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT; - - if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE)) - rate_flags |= RATE_MCS_CCK_MSK; - - - if (ieee80211_is_probe_resp(fc)) { - data_retry_limit = 3; - if (data_retry_limit < rts_retry_limit) - rts_retry_limit = data_retry_limit; - } else - data_retry_limit = IWL_DEFAULT_TX_RETRY; - + /* Set retry limit on DATA packets and Probe Responses*/ if (priv->data_retry_limit != -1) data_retry_limit = priv->data_retry_limit; + else if (ieee80211_is_probe_resp(fc)) + data_retry_limit = 3; + else + data_retry_limit = IWL_DEFAULT_TX_RETRY; + tx_cmd->data_retry_limit = data_retry_limit; + /* Set retry limit on RTS packets */ + rts_retry_limit = (is_hcca) ? RTS_HCCA_RETRY_LIMIT : + RTS_DFAULT_RETRY_LIMIT; + if (data_retry_limit < rts_retry_limit) + rts_retry_limit = data_retry_limit; + tx_cmd->rts_retry_limit = rts_retry_limit; + /* DATA packets will use the uCode station table for rate/antenna + * selection */ if (ieee80211_is_data(fc)) { tx_cmd->initial_rate_index = 0; tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK; - } else { - switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { - case cpu_to_le16(IEEE80211_STYPE_AUTH): - case cpu_to_le16(IEEE80211_STYPE_DEAUTH): - case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): - case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): - if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) { - tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK; - tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK; - } - break; - default: - break; - } + return; + } + + /** + * If the current TX rate stored in mac80211 has the MCS bit set, it's + * not really a TX rate. Thus, we use the lowest supported rate for + * this band. Also use the lowest supported rate if the stored rate + * index is invalid. + */ + rate_idx = info->control.rates[0].idx; + if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS || + (rate_idx < 0) || (rate_idx > IWL_RATE_COUNT_LEGACY)) + rate_idx = rate_lowest_index(&priv->bands[info->band], + info->control.sta); + /* For 5 GHZ band, remap mac80211 rate indices into driver indices */ + if (info->band == IEEE80211_BAND_5GHZ) + rate_idx += IWL_FIRST_OFDM_RATE; + /* Get PLCP rate for tx_cmd->rate_n_flags */ + rate_plcp = iwl_rates[rate_idx].plcp; + /* Zero out flags for this packet */ + rate_flags = 0; - priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant); - rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant); + /* Set CCK flag as needed */ + if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE)) + rate_flags |= RATE_MCS_CCK_MSK; + + /* Set up RTS and CTS flags for certain packets */ + switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { + case cpu_to_le16(IEEE80211_STYPE_AUTH): + case cpu_to_le16(IEEE80211_STYPE_DEAUTH): + case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): + case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): + if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) { + tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK; + tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK; + } + break; + default: + break; } - tx_cmd->rts_retry_limit = rts_retry_limit; - tx_cmd->data_retry_limit = data_retry_limit; + /* Set up antennas */ + priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant); + rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant); + + /* Set the rate in the TX cmd */ tx_cmd->rate_n_flags = iwl_hw_set_rate_n_flags(rate_plcp, rate_flags); } @@ -701,12 +720,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) goto drop_unlock; } - if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) == - IWL_INVALID_RATE) { - IWL_ERR(priv, "ERROR: No TX rate available.\n"); - goto drop_unlock; - } - fc = hdr->frame_control; #ifdef CONFIG_IWLWIFI_DEBUG @@ -807,7 +820,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) iwl_dbg_log_tx_data_frame(priv, len, hdr); /* set is_hcca to 0; it probably will never be implemented */ - iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0); + iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, 0); iwl_update_stats(priv, true, fc, len); /* -- cgit v1.2.3-18-g5258 From 31513be8a06874eb359908b7b735929837831a9a Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Fri, 28 Aug 2009 09:44:47 -0700 Subject: iwlwifi: use iwl_hwrate_get_mac80211_idx where appropriate For HT packets, mac80211 expects the rate_idx to be an MCS number, which is the lower byte of rate_n_flags. However, iwl_hwrate_to_plcp_idx takes the MCS number and reduces it down to the range 0-8 (6 to 60 Mbps), removing the bits that signify multiply streams, HT40 Duplicate mode, or unequal modulation. This version is used for various internal purposes through the driver. Add the function iwl_hwrate_get_mac80211_idx, an alternate version which takes the rate and the band and returns the mac80211 index (MCS, for HT packets, and PLCP rate, for legacy packets). Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 10 ++++++++-- drivers/net/wireless/iwlwifi/iwl-core.c | 27 ++++++++++++++++++++++----- drivers/net/wireless/iwlwifi/iwl-core.h | 1 + drivers/net/wireless/iwlwifi/iwl-rx.c | 9 ++++----- 4 files changed, 35 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 8239e5508ca..40b207aa8fe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -878,6 +878,12 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, rs_index -= IWL_FIRST_OFDM_RATE; mac_flags = info->status.rates[0].flags; mac_index = info->status.rates[0].idx; + /* For HT packets, map MCS to PLCP */ + if (mac_flags & IEEE80211_TX_RC_MCS) { + mac_index &= RATE_MCS_CODE_MSK; /* Remove # of streams */ + if (mac_index >= (IWL_RATE_9M_INDEX - IWL_FIRST_OFDM_RATE)) + mac_index++; + } if ((mac_index < 0) || (tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) || @@ -886,8 +892,8 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, (tbl_type.ant_type != info->antenna_sel_tx) || (!!(tx_rate & RATE_MCS_HT_MSK) != !!(mac_flags & IEEE80211_TX_RC_MCS)) || (!!(tx_rate & RATE_MCS_GF_MSK) != !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) || - rs_index != mac_index) { - IWL_DEBUG_RATE(priv, "initial rate does not match 0x%x\n", tx_rate); + (rs_index != mac_index)) { + IWL_DEBUG_RATE(priv, "initial rate %d does not match %d (0x%x)\n", mac_index, rs_index, tx_rate); /* the last LQ command could failed so the LQ in ucode not * the same in driver sync up */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 813582467ff..acfd7b40afb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -96,7 +96,6 @@ EXPORT_SYMBOL(iwl_rates); void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, struct ieee80211_tx_info *info) { - int rate_index; struct ieee80211_tx_rate *r = &info->control.rates[0]; info->antenna_sel_tx = @@ -111,10 +110,7 @@ void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, r->flags |= IEEE80211_TX_RC_DUP_DATA; if (rate_n_flags & RATE_MCS_SGI_MSK) r->flags |= IEEE80211_TX_RC_SHORT_GI; - rate_index = iwl_hwrate_to_plcp_idx(rate_n_flags); - if (info->band == IEEE80211_BAND_5GHZ) - rate_index -= IWL_FIRST_OFDM_RATE; - r->idx = rate_index; + r->idx = iwl_hwrate_to_mac80211_idx(rate_n_flags, info->band); } EXPORT_SYMBOL(iwl_hwrate_to_tx_control); @@ -149,6 +145,27 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) } EXPORT_SYMBOL(iwl_hwrate_to_plcp_idx); +int iwl_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band) +{ + int idx = 0; + int band_offset = 0; + + /* HT rate format: mac80211 wants an MCS number, which is just LSB */ + if (rate_n_flags & RATE_MCS_HT_MSK) { + idx = (rate_n_flags & 0xff); + return idx; + /* Legacy rate format, search for match in table */ + } else { + if (band == IEEE80211_BAND_5GHZ) + band_offset = IWL_FIRST_OFDM_RATE; + for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++) + if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF)) + return idx - band_offset; + } + + return -1; +} + u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant) { int i; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 62d90364b61..c04d2a27081 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -423,6 +423,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force); void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, struct ieee80211_tx_info *info); int iwl_hwrate_to_plcp_idx(u32 rate_n_flags); +int iwl_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band); u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index e34d3fcb6c3..8150c5c3a16 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -962,6 +962,9 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, return; } + /* This will be used in several places later */ + rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); + /* rx_status carries information about the packet to mac80211 */ rx_status.mactime = le64_to_cpu(phy_res->timestamp); rx_status.freq = @@ -969,10 +972,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; rx_status.rate_idx = - iwl_hwrate_to_plcp_idx(le32_to_cpu(phy_res->rate_n_flags)); - if (rx_status.band == IEEE80211_BAND_5GHZ) - rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; - + iwl_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band); rx_status.flag = 0; /* TSF isn't reliable. In order to allow smooth user experience, @@ -1034,7 +1034,6 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, rx_status.flag |= RX_FLAG_SHORTPRE; /* Set up the HT phy flags */ - rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); if (rate_n_flags & RATE_MCS_HT_MSK) rx_status.flag |= RX_FLAG_HT; if (rate_n_flags & RATE_MCS_HT40_MSK) -- cgit v1.2.3-18-g5258 From 4c561a02291326c50f9b1f647eae891af9d1f3b2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 28 Aug 2009 09:44:48 -0700 Subject: iwlwifi: use sleep interval succession Some concerns were raised about the automatic adjustment of sleep intervals to all the same, potentially high, value, and I can imagine the hardware behaving better when we don't ask too much of it. So let's convert to use a succession of sleep levels when requesting to go to deeper sleeps (which can only happen with large DTIM intervals), using the succession values from power level three, which have the benefit of also having been tested extensively already. As a result, the automatic sleep level adjustment will now be mostly equivalent to power level three, except for the RX/TX timeouts and possibly using smaller sleep vectors to account for networking latency. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-power.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 0b16841f45f..081a7ea40c6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -216,8 +216,27 @@ static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd, int dynps_ms, int wakeup_period) { + /* + * These are the original power level 3 sleep successions. The + * device may behave better with such succession and was also + * only tested with that. Just like the original sleep commands, + * also adjust the succession here to the wakeup_period below. + * The ranges are the same as for the sleep commands, 0-2, 3-9 + * and >10, which is selected based on the DTIM interval for + * the sleep index but here we use the wakeup period since that + * is what we need to do for the latency requirements. + */ + static const u8 slp_succ_r0[IWL_POWER_VEC_SIZE] = { 2, 2, 2, 2, 2 }; + static const u8 slp_succ_r1[IWL_POWER_VEC_SIZE] = { 2, 4, 6, 7, 9 }; + static const u8 slp_succ_r2[IWL_POWER_VEC_SIZE] = { 2, 7, 9, 9, 0xFF }; + const u8 *slp_succ = slp_succ_r0; int i; + if (wakeup_period > IWL_DTIM_RANGE_0_MAX) + slp_succ = slp_succ_r1; + if (wakeup_period > IWL_DTIM_RANGE_1_MAX) + slp_succ = slp_succ_r2; + memset(cmd, 0, sizeof(*cmd)); cmd->flags = IWL_POWER_DRIVER_ALLOW_SLEEP_MSK | @@ -230,7 +249,8 @@ static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv, cmd->tx_data_timeout = cpu_to_le32(1000 * dynps_ms); for (i = 0; i < IWL_POWER_VEC_SIZE; i++) - cmd->sleep_interval[i] = cpu_to_le32(wakeup_period); + cmd->sleep_interval[i] = + cpu_to_le32(min_t(int, slp_succ[i], wakeup_period)); IWL_DEBUG_POWER(priv, "Automatic sleep command\n"); } -- cgit v1.2.3-18-g5258 From b57d46aa0db87b6349737e7b110ebe48ee14c143 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 28 Aug 2009 09:44:49 -0700 Subject: iwlwifi: fix situation in which debug message is printed 3945 does not have update_chain_flags defined and because if this we always see the debug message that does not apply to it. Add a check to be specific about what is actually happening. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 081a7ea40c6..4ec6a8307cc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -321,7 +321,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) if (priv->cfg->ops->lib->update_chain_flags && update_chains) priv->cfg->ops->lib->update_chain_flags(priv); - else + else if (priv->cfg->ops->lib->update_chain_flags) IWL_DEBUG_POWER(priv, "Cannot update the power, chain noise " "calibration running: %d\n", -- cgit v1.2.3-18-g5258 From af472a953ef23d6b9fe717486974d7caff3fa194 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 28 Aug 2009 09:58:50 -0700 Subject: iwl3945: reduce debug noise when default debug flags used Significant literature suggests users use debug flags 0x43fff - this causes the debug flags to be set that causes information to be printed for every received frame - including beacons. In the best case it fills up the logs, at worst it slows driver down and causes failures due to timeouts. In the RX handler, print debugging only if user requested RX debugging. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 34790413ead..2238c9f2018 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1373,7 +1373,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) fill_rx = 1; /* Rx interrupt, but nothing sent from uCode */ if (i == r) - IWL_DEBUG(priv, IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i); + IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i); while (i != r) { rxb = rxq->queue[i]; @@ -1404,15 +1404,13 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) * handle those that need handling via function in * rx_handlers table. See iwl3945_setup_rx_handlers() */ if (priv->rx_handlers[pkt->hdr.cmd]) { - IWL_DEBUG(priv, IWL_DL_HCMD | IWL_DL_RX | IWL_DL_ISR, - "r = %d, i = %d, %s, 0x%02x\n", r, i, + IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r, i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); priv->isr_stats.rx_handlers[pkt->hdr.cmd]++; } else { /* No handling needed */ - IWL_DEBUG(priv, IWL_DL_HCMD | IWL_DL_RX | IWL_DL_ISR, - "r %d i %d No handler needed for %s, 0x%02x\n", + IWL_DEBUG_RX(priv, "r %d i %d No handler needed for %s, 0x%02x\n", r, i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); } -- cgit v1.2.3-18-g5258 From c206a39d58fa335275403088171482f66fdbedcf Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Fri, 28 Aug 2009 21:37:00 +0200 Subject: b43: Refactor and update antenna diversity for A/G-PHY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -Make use of the b43_phy_set/mask/maskset helpers. -Fix a few errors in the code. -Make the code more readable. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_a.c | 48 ++++++++++++------------------------ drivers/net/wireless/b43/phy_g.c | 53 ++++++++++++++++------------------------ 2 files changed, 36 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index 809ec97031c..d90217c3a70 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c @@ -518,58 +518,40 @@ static unsigned int b43_aphy_op_get_default_chan(struct b43_wldev *dev) static void b43_aphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) {//TODO struct b43_phy *phy = &dev->phy; - u64 hf; u16 tmp; int autodiv = 0; if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1) autodiv = 1; - hf = b43_hf_read(dev); - hf &= ~B43_HF_ANTDIVHELP; - b43_hf_write(dev, hf); + b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ANTDIVHELP); - tmp = b43_phy_read(dev, B43_PHY_BBANDCFG); - tmp &= ~B43_PHY_BBANDCFG_RXANT; - tmp |= (autodiv ? B43_ANTENNA_AUTO1 : antenna) - << B43_PHY_BBANDCFG_RXANT_SHIFT; - b43_phy_write(dev, B43_PHY_BBANDCFG, tmp); + b43_phy_maskset(dev, B43_PHY_BBANDCFG, ~B43_PHY_BBANDCFG_RXANT, + (autodiv ? B43_ANTENNA_AUTO1 : antenna) << + B43_PHY_BBANDCFG_RXANT_SHIFT); if (autodiv) { tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); - if (antenna == B43_ANTENNA_AUTO0) + if (antenna == B43_ANTENNA_AUTO1) tmp &= ~B43_PHY_ANTDWELL_AUTODIV1; else tmp |= B43_PHY_ANTDWELL_AUTODIV1; b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); } - if (phy->rev < 3) { - tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); - tmp = (tmp & 0xFF00) | 0x24; - b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); - } else { - tmp = b43_phy_read(dev, B43_PHY_OFDM61); - tmp |= 0x10; - b43_phy_write(dev, B43_PHY_OFDM61, tmp); - if (phy->analog == 3) { - b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, - 0x1D); - b43_phy_write(dev, B43_PHY_ADIVRELATED, - 8); + if (phy->rev < 3) + b43_phy_maskset(dev, B43_PHY_ANTDWELL, 0xFF00, 0x24); + else { + b43_phy_set(dev, B43_PHY_OFDM61, 0x10); + if (phy->rev == 3) { + b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, 0x1D); + b43_phy_write(dev, B43_PHY_ADIVRELATED, 8); } else { - b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, - 0x3A); - tmp = - b43_phy_read(dev, - B43_PHY_ADIVRELATED); - tmp = (tmp & 0xFF00) | 8; - b43_phy_write(dev, B43_PHY_ADIVRELATED, - tmp); + b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, 0x3A); + b43_phy_maskset(dev, B43_PHY_ADIVRELATED, 0xFF00, 8); } } - hf |= B43_HF_ANTDIVHELP; - b43_hf_write(dev, hf); + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ANTDIVHELP); } static void b43_aphy_op_adjust_txpower(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index bdff9afe3f8..5afa4df0b02 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -2651,65 +2651,54 @@ static unsigned int b43_gphy_op_get_default_chan(struct b43_wldev *dev) static void b43_gphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) { struct b43_phy *phy = &dev->phy; - u64 hf; u16 tmp; int autodiv = 0; if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1) autodiv = 1; - hf = b43_hf_read(dev); - hf &= ~B43_HF_ANTDIVHELP; - b43_hf_write(dev, hf); + b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ANTDIVHELP); - tmp = b43_phy_read(dev, B43_PHY_BBANDCFG); - tmp &= ~B43_PHY_BBANDCFG_RXANT; - tmp |= (autodiv ? B43_ANTENNA_AUTO1 : antenna) - << B43_PHY_BBANDCFG_RXANT_SHIFT; - b43_phy_write(dev, B43_PHY_BBANDCFG, tmp); + b43_phy_maskset(dev, B43_PHY_BBANDCFG, ~B43_PHY_BBANDCFG_RXANT, + (autodiv ? B43_ANTENNA_AUTO1 : antenna) << + B43_PHY_BBANDCFG_RXANT_SHIFT); if (autodiv) { tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); - if (antenna == B43_ANTENNA_AUTO0) + if (antenna == B43_ANTENNA_AUTO1) tmp &= ~B43_PHY_ANTDWELL_AUTODIV1; else tmp |= B43_PHY_ANTDWELL_AUTODIV1; b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); } + tmp = b43_phy_read(dev, B43_PHY_ANTWRSETT); if (autodiv) tmp |= B43_PHY_ANTWRSETT_ARXDIV; else tmp &= ~B43_PHY_ANTWRSETT_ARXDIV; b43_phy_write(dev, B43_PHY_ANTWRSETT, tmp); - if (phy->rev >= 2) { - tmp = b43_phy_read(dev, B43_PHY_OFDM61); - tmp |= B43_PHY_OFDM61_10; - b43_phy_write(dev, B43_PHY_OFDM61, tmp); - tmp = - b43_phy_read(dev, B43_PHY_DIVSRCHGAINBACK); - tmp = (tmp & 0xFF00) | 0x15; - b43_phy_write(dev, B43_PHY_DIVSRCHGAINBACK, - tmp); + if (autodiv) + b43_phy_set(dev, B43_PHY_ANTWRSETT, B43_PHY_ANTWRSETT_ARXDIV); + else { + b43_phy_mask(dev, B43_PHY_ANTWRSETT, + B43_PHY_ANTWRSETT_ARXDIV); + } - if (phy->rev == 2) { - b43_phy_write(dev, B43_PHY_ADIVRELATED, - 8); - } else { - tmp = - b43_phy_read(dev, - B43_PHY_ADIVRELATED); - tmp = (tmp & 0xFF00) | 8; - b43_phy_write(dev, B43_PHY_ADIVRELATED, - tmp); - } + if (phy->rev >= 2) { + b43_phy_set(dev, B43_PHY_OFDM61, B43_PHY_OFDM61_10); + b43_phy_maskset(dev, B43_PHY_DIVSRCHGAINBACK, 0xFF00, 0x15); + + if (phy->rev == 2) + b43_phy_write(dev, B43_PHY_ADIVRELATED, 8); + else + b43_phy_maskset(dev, B43_PHY_ADIVRELATED, 0xFF00, 8); } if (phy->rev >= 6) b43_phy_write(dev, B43_PHY_OFDM9B, 0xDC); - hf |= B43_HF_ANTDIVHELP; - b43_hf_write(dev, hf); + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ANTDIVHELP); } static int b43_gphy_op_interf_mitigation(struct b43_wldev *dev, -- cgit v1.2.3-18-g5258 From 0136e51edbdae7f82aa1c32ad5cd6a49ec917c9c Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Fri, 28 Aug 2009 22:32:17 +0200 Subject: b43: Add myself to module authors & to LP-PHY file copyright notices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also mark the LP-PHY driver "802.11a/g" instead of "802.11g", as LP-PHY is capable of both 2GHz and 5GHz operation. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 1 + drivers/net/wireless/b43/phy_lp.c | 3 ++- drivers/net/wireless/b43/tables_lpphy.c | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 0f168443ad4..2852cacfa66 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -58,6 +58,7 @@ MODULE_DESCRIPTION("Broadcom B43 wireless driver"); MODULE_AUTHOR("Martin Langer"); MODULE_AUTHOR("Stefano Brivio"); MODULE_AUTHOR("Michael Buesch"); +MODULE_AUTHOR("Gábor Stefanik"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID); diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 1ab00b034cb..3e02d969f68 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -1,9 +1,10 @@ /* Broadcom B43 wireless driver - IEEE 802.11g LP-PHY driver + IEEE 802.11a/g LP-PHY driver Copyright (c) 2008-2009 Michael Buesch + Copyright (c) 2009 Gábor Stefanik This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/drivers/net/wireless/b43/tables_lpphy.c b/drivers/net/wireless/b43/tables_lpphy.c index c784def19b1..cb56882e037 100644 --- a/drivers/net/wireless/b43/tables_lpphy.c +++ b/drivers/net/wireless/b43/tables_lpphy.c @@ -1,9 +1,10 @@ /* Broadcom B43 wireless driver - IEEE 802.11g LP-PHY and radio device data tables + IEEE 802.11a/g LP-PHY and radio device data tables Copyright (c) 2009 Michael Buesch + Copyright (c) 2009 Gábor Stefanik This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -- cgit v1.2.3-18-g5258 From c71dbd3316d9ae8bc49d90b5a0b2915cd5089cff Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Fri, 28 Aug 2009 22:34:21 +0200 Subject: b43: Fix typo in modparam_btcoex description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 2852cacfa66..ae05f667114 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -91,7 +91,7 @@ MODULE_PARM_DESC(qos, "Enable QOS support (default on)"); static int modparam_btcoex = 1; module_param_named(btcoex, modparam_btcoex, int, 0444); -MODULE_PARM_DESC(btcoex, "Enable Bluetooth coexistance (default on)"); +MODULE_PARM_DESC(btcoex, "Enable Bluetooth coexistence (default on)"); int b43_modparam_verbose = B43_VERBOSITY_DEFAULT; module_param_named(verbose, b43_modparam_verbose, int, 0644); -- cgit v1.2.3-18-g5258 From 1ee50cd9a22fdb22ce7bdb7f978d25b79993788d Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Fri, 28 Aug 2009 22:36:02 +0200 Subject: b43: LP-PHY: Fix TX gain tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rev1 2GHz and rev2 5GHz gain tables were incorrectly documented on the specs originally. Update these gaintables to match the cor- rected specs. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/tables_lpphy.c | 306 ++++++++++++++++---------------- 1 file changed, 153 insertions(+), 153 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/tables_lpphy.c b/drivers/net/wireless/b43/tables_lpphy.c index cb56882e037..61027ee84fb 100644 --- a/drivers/net/wireless/b43/tables_lpphy.c +++ b/drivers/net/wireless/b43/tables_lpphy.c @@ -1613,11 +1613,62 @@ static struct lpphy_tx_gain_table_entry lpphy_rev1_nopa_tx_gain_table[] = { }; static struct lpphy_tx_gain_table_entry lpphy_rev1_2ghz_tx_gain_table[] = { - { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 85, }, - { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 81, }, - { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 78, }, - { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 76, }, - { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 74, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 90, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 88, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 85, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 83, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 81, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 78, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 76, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 74, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 15, .pad = 15, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 15, .pad = 14, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 15, .pad = 13, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 15, .pad = 12, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 15, .pad = 11, .dac = 0, .bb_mult = 59, }, + { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 72, }, + { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 70, }, + { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 68, }, + { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 66, }, + { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 64, }, + { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 62, }, + { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 60, }, + { .gm = 4, .pga = 15, .pad = 10, .dac = 0, .bb_mult = 59, }, { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 72, }, { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 70, }, { .gm = 4, .pga = 15, .pad = 9, .dac = 0, .bb_mult = 68, }, @@ -1690,57 +1741,6 @@ static struct lpphy_tx_gain_table_entry lpphy_rev1_2ghz_tx_gain_table[] = { { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 64, }, { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 62, }, { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 60, }, - { .gm = 4, .pga = 10, .pad = 6, .dac = 0, .bb_mult = 59, }, - { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 72, }, - { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 70, }, - { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 68, }, - { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 66, }, - { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 64, }, - { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 62, }, - { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 60, }, - { .gm = 4, .pga = 10, .pad = 5, .dac = 0, .bb_mult = 59, }, - { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 70, }, - { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 68, }, - { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 66, }, - { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 64, }, - { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 63, }, - { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 61, }, - { .gm = 4, .pga = 9, .pad = 5, .dac = 0, .bb_mult = 59, }, - { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 71, }, - { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 69, }, - { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 67, }, - { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 65, }, - { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 63, }, - { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 62, }, - { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 60, }, - { .gm = 4, .pga = 9, .pad = 4, .dac = 0, .bb_mult = 58, }, - { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 70, }, - { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 68, }, - { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 66, }, - { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 65, }, - { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 63, }, - { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 61, }, - { .gm = 4, .pga = 8, .pad = 4, .dac = 0, .bb_mult = 59, }, - { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 68, }, - { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 66, }, - { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 64, }, - { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 62, }, - { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 61, }, - { .gm = 4, .pga = 7, .pad = 4, .dac = 0, .bb_mult = 59, }, - { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 67, }, - { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 65, }, - { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 63, }, - { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 62, }, - { .gm = 4, .pga = 7, .pad = 3, .dac = 0, .bb_mult = 60, }, - { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 65, }, - { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 63, }, - { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 61, }, - { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 60, }, - { .gm = 4, .pga = 6, .pad = 3, .dac = 0, .bb_mult = 58, }, - { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 68, }, - { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 66, }, - { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 64, }, - { .gm = 4, .pga = 5, .pad = 3, .dac = 0, .bb_mult = 62, }, }; static struct lpphy_tx_gain_table_entry lpphy_rev1_5ghz_tx_gain_table[] = { @@ -2168,103 +2168,103 @@ static struct lpphy_tx_gain_table_entry lpphy_rev2_5ghz_tx_gain_table[] = { { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 68, }, { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 66, }, { .gm = 255, .pga = 255, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 248, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 241, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 234, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 227, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 221, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 215, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 208, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 203, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 197, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 191, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 186, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 181, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 175, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 170, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 166, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 161, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 156, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 152, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 148, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 143, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 139, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 135, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 132, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 128, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 124, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 121, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 117, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 114, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 111, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 108, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 104, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 102, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 99, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 96, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 93, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 90, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 88, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 85, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 83, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 81, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 78, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 76, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 74, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 72, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 70, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 68, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 66, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 64, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 64, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 62, .pad = 255, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 62, .pad = 248, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 60, .pad = 248, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 60, .pad = 241, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 59, .pad = 241, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 59, .pad = 234, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 57, .pad = 234, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 57, .pad = 227, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 55, .pad = 227, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 55, .pad = 221, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 54, .pad = 221, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 54, .pad = 215, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 52, .pad = 215, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 52, .pad = 208, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 51, .pad = 208, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 51, .pad = 203, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 49, .pad = 203, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 49, .pad = 197, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 48, .pad = 197, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 48, .pad = 191, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 47, .pad = 191, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 47, .pad = 186, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 45, .pad = 186, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 45, .pad = 181, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 44, .pad = 181, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 44, .pad = 175, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 43, .pad = 175, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 43, .pad = 170, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 42, .pad = 170, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 42, .pad = 166, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 40, .pad = 166, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 40, .pad = 161, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 39, .pad = 161, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 39, .pad = 156, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 38, .pad = 156, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 38, .pad = 152, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 37, .pad = 152, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 37, .pad = 148, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 36, .pad = 148, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 36, .pad = 143, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 35, .pad = 143, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 35, .pad = 139, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 34, .pad = 139, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 34, .pad = 135, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 33, .pad = 135, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 33, .pad = 132, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 32, .pad = 132, .dac = 0, .bb_mult = 64, }, - { .gm = 255, .pga = 32, .pad = 128, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 248, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 241, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 234, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 227, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 221, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 215, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 208, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 203, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 197, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 191, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 186, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 181, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 175, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 170, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 166, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 161, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 156, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 152, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 148, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 143, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 139, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 135, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 132, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 128, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 124, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 121, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 117, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 114, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 111, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 108, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 104, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 102, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 99, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 96, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 93, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 90, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 88, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 85, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 83, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 81, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 78, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 76, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 74, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 72, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 70, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 68, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 66, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 64, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 64, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 255, .pad = 62, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 248, .pad = 62, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 248, .pad = 60, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 241, .pad = 60, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 241, .pad = 59, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 234, .pad = 59, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 234, .pad = 57, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 227, .pad = 57, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 227, .pad = 55, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 221, .pad = 55, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 221, .pad = 54, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 215, .pad = 54, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 215, .pad = 52, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 208, .pad = 52, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 208, .pad = 51, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 203, .pad = 51, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 203, .pad = 49, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 197, .pad = 49, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 197, .pad = 48, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 191, .pad = 48, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 191, .pad = 47, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 186, .pad = 47, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 186, .pad = 45, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 181, .pad = 45, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 181, .pad = 44, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 175, .pad = 44, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 175, .pad = 43, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 170, .pad = 43, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 170, .pad = 42, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 166, .pad = 42, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 166, .pad = 40, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 161, .pad = 40, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 161, .pad = 39, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 156, .pad = 39, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 156, .pad = 38, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 152, .pad = 38, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 152, .pad = 37, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 148, .pad = 37, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 148, .pad = 36, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 143, .pad = 36, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 143, .pad = 35, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 139, .pad = 35, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 139, .pad = 34, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 135, .pad = 34, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 135, .pad = 33, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 132, .pad = 33, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 132, .pad = 32, .dac = 0, .bb_mult = 64, }, + { .gm = 255, .pga = 128, .pad = 32, .dac = 0, .bb_mult = 64, }, }; void lpphy_rev0_1_table_init(struct b43_wldev *dev) -- cgit v1.2.3-18-g5258 From 2e27cff871dec9371e41022aaaebb3452ec069c0 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 29 Aug 2009 19:10:14 +0200 Subject: rt2x00: Fix TX status reporting Not all values of the TX status enumeration were covered during updating of the TX statistics. This could lead to wrong bitrate tuning but also wrong behavior in tools like hostapd. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 3f8c70ebe9a..0647e514dde 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -206,6 +206,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, unsigned int header_length = ieee80211_get_hdrlen_from_skb(entry->skb); u8 rate_idx, rate_flags, retry_rates; unsigned int i; + bool success; /* * Unmap the skb. @@ -234,13 +235,18 @@ void rt2x00lib_txdone(struct queue_entry *entry, rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb); /* - * Update TX statistics. + * Determine if the frame has been successfully transmitted. */ - rt2x00dev->link.qual.tx_success += + success = test_bit(TXDONE_SUCCESS, &txdesc->flags) || - test_bit(TXDONE_UNKNOWN, &txdesc->flags); - rt2x00dev->link.qual.tx_failed += - test_bit(TXDONE_FAILURE, &txdesc->flags); + test_bit(TXDONE_UNKNOWN, &txdesc->flags) || + test_bit(TXDONE_FALLBACK, &txdesc->flags); + + /* + * Update TX statistics. + */ + rt2x00dev->link.qual.tx_success += success; + rt2x00dev->link.qual.tx_failed += !success; rate_idx = skbdesc->tx_rate_idx; rate_flags = skbdesc->tx_rate_flags; @@ -263,22 +269,20 @@ void rt2x00lib_txdone(struct queue_entry *entry, tx_info->status.rates[i].flags = rate_flags; tx_info->status.rates[i].count = 1; } - if (i < (IEEE80211_TX_MAX_RATES -1)) + if (i < (IEEE80211_TX_MAX_RATES - 1)) tx_info->status.rates[i].idx = -1; /* terminate */ if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (test_bit(TXDONE_SUCCESS, &txdesc->flags) || - test_bit(TXDONE_UNKNOWN, &txdesc->flags)) + if (success) tx_info->flags |= IEEE80211_TX_STAT_ACK; - else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) + else rt2x00dev->low_level_stats.dot11ACKFailureCount++; } if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { - if (test_bit(TXDONE_SUCCESS, &txdesc->flags) || - test_bit(TXDONE_UNKNOWN, &txdesc->flags)) + if (success) rt2x00dev->low_level_stats.dot11RTSSuccessCount++; - else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) + else rt2x00dev->low_level_stats.dot11RTSFailureCount++; } -- cgit v1.2.3-18-g5258 From daee6c092aa49ea090612738253ef0d11d120344 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 29 Aug 2009 20:30:45 +0200 Subject: rt2x00: Reorganize padding & L2 padding The old function rt2x00queue_payload_align() handled both adding and removing L2 padding and some basic frame alignment. The entire function was being abused because it had multiple functions and the header length argument was somtimes used to align the header instead of the payload. Additionally there was a bug when inserting L2 padding that only the payload was aligned but not the header. This happens when the header wasn't aligned properly by mac80211, but rt2x00lib only moves the payload. A secondary problem was that when removing L2 padding during TXdone or RX the skb wasn't resized to the proper size. Split the function into seperate functions each handling its task as it should. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00crypto.c | 6 +- drivers/net/wireless/rt2x00/rt2x00dev.c | 10 +-- drivers/net/wireless/rt2x00/rt2x00lib.h | 45 ++++++++++---- drivers/net/wireless/rt2x00/rt2x00queue.c | 99 ++++++++++++++++++++++-------- 4 files changed, 116 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index 30fbd3bbe08..de36837dcf8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -154,7 +154,7 @@ void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length) skbdesc->flags &= ~SKBDESC_IV_STRIPPED; } -void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad, +void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int header_length, struct rxdone_entry_desc *rxdesc) { @@ -199,7 +199,7 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad, * move the header more then iv_len since we must * make room for the payload move as well. */ - if (l2pad) { + if (rxdesc->dev_flags & RXDONE_L2PAD) { skb_push(skb, iv_len - align); skb_put(skb, icv_len); @@ -230,7 +230,7 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad, * Move payload for alignment purposes. Note that * this is only needed when no l2 padding is present. */ - if (!l2pad) { + if (!(rxdesc->dev_flags & RXDONE_L2PAD)) { memmove(skb->data + transfer, skb->data + transfer + align, payload_len); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 0647e514dde..71761b34383 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -217,7 +217,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, * Remove L2 padding which was added during */ if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags)) - rt2x00queue_payload_align(entry->skb, true, header_length); + rt2x00queue_remove_l2pad(entry->skb, header_length); /* * If the IV/EIV data was stripped from the frame before it was @@ -364,7 +364,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb; struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status; unsigned int header_length; - bool l2pad; int rate_idx; /* * Allocate a new sk_buffer. If no new buffer available, drop the @@ -393,7 +392,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, * aligned on a 4 byte boundary. */ header_length = ieee80211_get_hdrlen_from_skb(entry->skb); - l2pad = !!(rxdesc.dev_flags & RXDONE_L2PAD); /* * Hardware might have stripped the IV/EIV/ICV data, @@ -403,10 +401,12 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, */ if ((rxdesc.dev_flags & RXDONE_CRYPTO_IV) && (rxdesc.flags & RX_FLAG_IV_STRIPPED)) - rt2x00crypto_rx_insert_iv(entry->skb, l2pad, header_length, + rt2x00crypto_rx_insert_iv(entry->skb, header_length, &rxdesc); + else if (rxdesc.dev_flags & RXDONE_L2PAD) + rt2x00queue_remove_l2pad(entry->skb, header_length); else - rt2x00queue_payload_align(entry->skb, l2pad, header_length); + rt2x00queue_align_payload(entry->skb, header_length); /* * Check if the frame was received using HT. In that case, diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index eeb2881e818..5462cb5ad99 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -120,21 +120,42 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); /** - * rt2x00queue_payload_align - Align 802.11 payload to 4-byte boundary + * rt2x00queue_align_frame - Align 802.11 frame to 4-byte boundary + * @skb: The skb to align + * + * Align the start of the 802.11 frame to a 4-byte boundary, this could + * mean the payload is not aligned properly though. + */ +void rt2x00queue_align_frame(struct sk_buff *skb); + +/** + * rt2x00queue_align_payload - Align 802.11 payload to 4-byte boundary + * @skb: The skb to align + * @header_length: Length of 802.11 header + * + * Align the 802.11 payload to a 4-byte boundary, this could + * mean the header is not aligned properly though. + */ +void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length); + +/** + * rt2x00queue_insert_l2pad - Align 802.11 header & payload to 4-byte boundary + * @skb: The skb to align + * @header_length: Length of 802.11 header + * + * Apply L2 padding to align both header and payload to 4-byte boundary + */ +void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length); + +/** + * rt2x00queue_insert_l2pad - Remove L2 padding from 802.11 frame * @skb: The skb to align - * @l2pad: Should L2 padding be used * @header_length: Length of 802.11 header * - * This function prepares the @skb to be send to the device or mac80211. - * If @l2pad is set to true padding will occur between the 802.11 header - * and payload. Otherwise the padding will be done in front of the 802.11 - * header. - * When @l2pad is set the function will check for the &SKBDESC_L2_PADDED - * flag in &skb_frame_desc. If that flag is set, the padding is removed - * and the flag cleared. Otherwise the padding is added and the flag is set. + * Remove L2 padding used to align both header and payload to 4-byte boundary, + * by removing the L2 padding the header will no longer be 4-byte aligned. */ -void rt2x00queue_payload_align(struct sk_buff *skb, - bool l2pad, unsigned int header_length); +void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length); /** * rt2x00queue_write_tx_frame - Write TX frame to hardware @@ -324,7 +345,7 @@ void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, struct txentry_desc *txdesc); void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length); -void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad, +void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int header_length, struct rxdone_entry_desc *rxdesc); #else diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 06af823efd8..577029efe32 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -148,35 +148,89 @@ void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) dev_kfree_skb_any(skb); } -void rt2x00queue_payload_align(struct sk_buff *skb, - bool l2pad, unsigned int header_length) +void rt2x00queue_align_frame(struct sk_buff *skb) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); unsigned int frame_length = skb->len; - unsigned int align = ALIGN_SIZE(skb, header_length); + unsigned int align = ALIGN_SIZE(skb, 0); if (!align) return; - if (l2pad) { - if (skbdesc->flags & SKBDESC_L2_PADDED) { - /* Remove L2 padding */ - memmove(skb->data + align, skb->data, header_length); - skb_pull(skb, align); - skbdesc->flags &= ~SKBDESC_L2_PADDED; - } else { - /* Add L2 padding */ - skb_push(skb, align); - memmove(skb->data, skb->data + align, header_length); - skbdesc->flags |= SKBDESC_L2_PADDED; - } + skb_push(skb, align); + memmove(skb->data, skb->data + align, frame_length); + skb_trim(skb, frame_length); +} + +void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_lengt) +{ + unsigned int frame_length = skb->len; + unsigned int align = ALIGN_SIZE(skb, header_lengt); + + if (!align) + return; + + skb_push(skb, align); + memmove(skb->data, skb->data + align, frame_length); + skb_trim(skb, frame_length); +} + +void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) +{ + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + unsigned int frame_length = skb->len; + unsigned int header_align = ALIGN_SIZE(skb, 0); + unsigned int payload_align = ALIGN_SIZE(skb, header_length); + unsigned int l2pad = 4 - (payload_align - header_align); + + if (header_align == payload_align) { + /* + * Both header and payload must be moved the same + * amount of bytes to align them properly. This means + * we don't use the L2 padding but just move the entire + * frame. + */ + rt2x00queue_align_frame(skb); + } else if (!payload_align) { + /* + * Simple L2 padding, only the header needs to be moved, + * the payload is already properly aligned. + */ + skb_push(skb, header_align); + memmove(skb->data, skb->data + header_align, frame_length); + skbdesc->flags |= SKBDESC_L2_PADDED; } else { - /* Generic payload alignment to 4-byte boundary */ - skb_push(skb, align); - memmove(skb->data, skb->data + align, frame_length); + /* + * + * Complicated L2 padding, both header and payload need + * to be moved. By default we only move to the start + * of the buffer, so our header alignment needs to be + * increased if there is not enough room for the header + * to be moved. + */ + if (payload_align > header_align) + header_align += 4; + + skb_push(skb, header_align); + memmove(skb->data, skb->data + header_align, header_length); + memmove(skb->data + header_length + l2pad, + skb->data + header_length + l2pad + header_align, + frame_length - header_length); + skbdesc->flags |= SKBDESC_L2_PADDED; } } +void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length) +{ + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + unsigned int l2pad = 4 - (header_length & 3); + + if (!l2pad || (skbdesc->flags & SKBDESC_L2_PADDED)) + return; + + memmove(skb->data + l2pad, skb->data, header_length); + skb_pull(skb, l2pad); +} + static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry, struct txentry_desc *txdesc) { @@ -456,18 +510,15 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) /* * When DMA allocation is required we should guarentee to the * driver that the DMA is aligned to a 4-byte boundary. - * Aligning the header to this boundary can be done by calling - * rt2x00queue_payload_align with the header length of 0. * However some drivers require L2 padding to pad the payload * rather then the header. This could be a requirement for * PCI and USB devices, while header alignment only is valid * for PCI devices. */ if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags)) - rt2x00queue_payload_align(entry->skb, true, - txdesc.header_length); + rt2x00queue_insert_l2pad(entry->skb, txdesc.header_length); else if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) - rt2x00queue_payload_align(entry->skb, false, 0); + rt2x00queue_align_frame(entry->skb); /* * It could be possible that the queue was corrupted and this -- cgit v1.2.3-18-g5258 From 3107edbae8216a80920bed7f8d4ec2e6b62390f2 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 30 Aug 2009 13:22:57 -0700 Subject: ipw2200: fix kconfig dependencies Fix kconfig dependencies for ipw2x00 drivers, fixes build errors: ERROR: "wiphy_free" [drivers/net/wireless/ipw2x00/libipw.ko] undefined! ERROR: "wiphy_unregister" [drivers/net/wireless/ipw2x00/libipw.ko] undefined! ERROR: "wiphy_new" [drivers/net/wireless/ipw2x00/libipw.ko] undefined! ERROR: "cfg80211_wext_giwname" [drivers/net/wireless/ipw2x00/ipw2200.ko] undefined! ERROR: "wiphy_register" [drivers/net/wireless/ipw2x00/ipw2200.ko] undefined! Signed-off-by: Randy Dunlap Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig index 85cc79995f6..a8131384c6b 100644 --- a/drivers/net/wireless/ipw2x00/Kconfig +++ b/drivers/net/wireless/ipw2x00/Kconfig @@ -4,7 +4,7 @@ config IPW2100 tristate "Intel PRO/Wireless 2100 Network Connection" - depends on PCI && WLAN_80211 + depends on PCI && WLAN_80211 && CFG80211 select WIRELESS_EXT select FW_LOADER select LIB80211 @@ -63,7 +63,7 @@ config IPW2100_DEBUG config IPW2200 tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" - depends on PCI && WLAN_80211 + depends on PCI && WLAN_80211 && CFG80211 select WIRELESS_EXT select FW_LOADER select LIB80211 @@ -150,7 +150,7 @@ config IPW2200_DEBUG config LIBIPW tristate - depends on PCI && WLAN_80211 + depends on PCI && WLAN_80211 && CFG80211 select WIRELESS_EXT select CRYPTO select CRYPTO_ARC4 -- cgit v1.2.3-18-g5258 From 1c29ce672fe817c208309eea0c1ff7bf76250f15 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 31 Aug 2009 17:48:36 +0530 Subject: ath9k: Do an AHB reset before doing RTC reset Doing an RTC reset when DMA is active may corrupt memory, make sure no DMA is active at this moment by doing an AHB reset. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index e340dacc6eb..71f27f324ce 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1712,8 +1712,15 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); + if (!AR_SREV_9100(ah)) + REG_WRITE(ah, AR_RC, AR_RC_AHB); + REG_WRITE(ah, AR_RTC_RESET, 0); udelay(2); + + if (!AR_SREV_9100(ah)) + REG_WRITE(ah, AR_RC, 0); + REG_WRITE(ah, AR_RTC_RESET, 1); if (!ath9k_hw_wait(ah, -- cgit v1.2.3-18-g5258 From 2b980dbd77d229eb60588802162c9659726b11f4 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 28 Aug 2009 18:12:43 -0400 Subject: lsm: Add hooks to the TUN driver The TUN driver lacks any LSM hooks which makes it difficult for LSM modules, such as SELinux, to enforce access controls on network traffic generated by TUN users; this is particularly problematic for virtualization apps such as QEMU and KVM. This patch adds three new LSM hooks designed to control the creation and attachment of TUN devices, the hooks are: * security_tun_dev_create() Provides access control for the creation of new TUN devices * security_tun_dev_post_create() Provides the ability to create the necessary socket LSM state for newly created TUN devices * security_tun_dev_attach() Provides access control for attaching to existing, persistent TUN devices and the ability to update the TUN device's socket LSM state as necessary Signed-off-by: Paul Moore Acked-by: Eric Paris Acked-by: Serge Hallyn Acked-by: David S. Miller Signed-off-by: James Morris --- drivers/net/tun.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 42b6c6319bc..87214a257d2 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -130,17 +130,10 @@ static inline struct tun_sock *tun_sk(struct sock *sk) static int tun_attach(struct tun_struct *tun, struct file *file) { struct tun_file *tfile = file->private_data; - const struct cred *cred = current_cred(); int err; ASSERT_RTNL(); - /* Check permissions */ - if (((tun->owner != -1 && cred->euid != tun->owner) || - (tun->group != -1 && !in_egroup_p(tun->group))) && - !capable(CAP_NET_ADMIN)) - return -EPERM; - netif_tx_lock_bh(tun->dev); err = -EINVAL; @@ -926,6 +919,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) dev = __dev_get_by_name(net, ifr->ifr_name); if (dev) { + const struct cred *cred = current_cred(); + if (ifr->ifr_flags & IFF_TUN_EXCL) return -EBUSY; if ((ifr->ifr_flags & IFF_TUN) && dev->netdev_ops == &tun_netdev_ops) @@ -935,6 +930,14 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) else return -EINVAL; + if (((tun->owner != -1 && cred->euid != tun->owner) || + (tun->group != -1 && !in_egroup_p(tun->group))) && + !capable(CAP_NET_ADMIN)) + return -EPERM; + err = security_tun_dev_attach(tun->sk); + if (err < 0) + return err; + err = tun_attach(tun, file); if (err < 0) return err; @@ -947,6 +950,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) if (!capable(CAP_NET_ADMIN)) return -EPERM; + err = security_tun_dev_create(); + if (err < 0) + return err; /* Set dev type */ if (ifr->ifr_flags & IFF_TUN) { @@ -989,6 +995,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) tun->sk = sk; container_of(sk, struct tun_sock, sk)->tun = tun; + security_tun_dev_post_create(sk); + tun_net_init(dev); if (strchr(dev->name, '%')) { -- cgit v1.2.3-18-g5258 From 6fef4c0c8eeff7de13007a5f56113475444a253d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:41 +0000 Subject: netdev: convert pseudo-devices to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/ieee1394/eth1394.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index f5c586c2bba..1ad8785e398 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -169,7 +169,8 @@ static int ether1394_header_cache(const struct neighbour *neigh, static void ether1394_header_cache_update(struct hh_cache *hh, const struct net_device *dev, const unsigned char *haddr); -static int ether1394_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ether1394_tx(struct sk_buff *skb, + struct net_device *dev); static void ether1394_iso(struct hpsb_iso *iso); static struct ethtool_ops ethtool_ops; @@ -1555,7 +1556,8 @@ static void ether1394_complete_cb(void *__ptask) } /* Transmit a packet (called by kernel) */ -static int ether1394_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ether1394_tx(struct sk_buff *skb, + struct net_device *dev) { struct eth1394hdr hdr_buf; struct eth1394_priv *priv = netdev_priv(dev); @@ -1694,14 +1696,6 @@ fail: dev->stats.tx_errors++; spin_unlock_irqrestore(&priv->lock, flags); - /* - * FIXME: According to a patch from 2003-02-26, "returning non-zero - * causes serious problems" here, allegedly. Before that patch, - * -ERRNO was returned which is not appropriate under Linux 2.6. - * Perhaps more needs to be done? Stop the queue in serious - * conditions and restart it elsewhere? - */ - /* return NETDEV_TX_BUSY; */ return NETDEV_TX_OK; } -- cgit v1.2.3-18-g5258 From 36e4d64a82d9a91a73a2b9b32117aedfe2211fb3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:43 +0000 Subject: convert hamradio drivers to netdev_txreturnt_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hamradio/6pack.c | 2 +- drivers/net/hamradio/bpqether.c | 2 +- drivers/net/hamradio/hdlcdrv.c | 3 ++- drivers/net/hamradio/mkiss.c | 2 +- drivers/net/hamradio/scc.c | 5 +++-- drivers/net/hamradio/yam.c | 3 ++- 6 files changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 6cb2bdfd7b1..fb588301a05 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -242,7 +242,7 @@ out_drop: /* Encapsulate an IP datagram and kick it into a TTY queue. */ -static int sp_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t sp_xmit(struct sk_buff *skb, struct net_device *dev) { struct sixpack *sp = netdev_priv(dev); diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 4c5f4dfbe05..3c7cc7f4580 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -247,7 +247,7 @@ drop: /* * Send an AX.25 frame via an ethernet interface */ -static int bpq_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t bpq_xmit(struct sk_buff *skb, struct net_device *dev) { struct sk_buff *newskb; unsigned char *ptr; diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c index 16b060b9211..0013c409782 100644 --- a/drivers/net/hamradio/hdlcdrv.c +++ b/drivers/net/hamradio/hdlcdrv.c @@ -399,7 +399,8 @@ void hdlcdrv_arbitrate(struct net_device *dev, struct hdlcdrv_state *s) * ===================== network driver interface ========================= */ -static int hdlcdrv_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t hdlcdrv_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct hdlcdrv_state *sm = netdev_priv(dev); diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index ac191ef2119..33b55f72974 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -525,7 +525,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) } /* Encapsulate an AX.25 packet and kick it into a TTY queue. */ -static int ax_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ax_xmit(struct sk_buff *skb, struct net_device *dev) { struct mkiss *ax = netdev_priv(dev); diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index c5406525c1a..35c936175bb 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -209,7 +209,8 @@ static void scc_net_setup(struct net_device *dev); static int scc_net_open(struct net_device *dev); static int scc_net_close(struct net_device *dev); static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb); -static int scc_net_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t scc_net_tx(struct sk_buff *skb, + struct net_device *dev); static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static int scc_net_set_mac_address(struct net_device *dev, void *addr); static struct net_device_stats * scc_net_get_stats(struct net_device *dev); @@ -1634,7 +1635,7 @@ static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb) /* ----> transmit frame <---- */ -static int scc_net_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t scc_net_tx(struct sk_buff *skb, struct net_device *dev) { struct scc_channel *scc = (struct scc_channel *) dev->ml_priv; unsigned long flags; diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index b85aa162314..694132e04af 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -594,7 +594,8 @@ static void ptt_off(struct net_device *dev) outb(PTT_OFF, MCR(dev->base_addr)); } -static int yam_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t yam_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct yam_port *yp = netdev_priv(dev); -- cgit v1.2.3-18-g5258 From 8b62ff2dbc3d6c13997b9d440dfd0ed00e6df96d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:44 +0000 Subject: isdn: convert to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/isdn/hysdn/hysdn_net.c | 2 +- drivers/isdn/i4l/isdn_net.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c index c73004b3b2a..72eb92647c1 100644 --- a/drivers/isdn/hysdn/hysdn_net.c +++ b/drivers/isdn/hysdn/hysdn_net.c @@ -119,7 +119,7 @@ net_close(struct net_device *dev) /* send a packet on this interface. */ /* new style for kernel >= 2.3.33 */ /************************************/ -static int +static netdev_tx_t net_send_packet(struct sk_buff *skb, struct net_device *dev) { struct net_local *lp = (struct net_local *) dev; diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 57bf4bf5027..90b56ed8651 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -176,7 +176,8 @@ static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp) /* Prototypes */ static int isdn_net_force_dial_lp(isdn_net_local *); -static int isdn_net_start_xmit(struct sk_buff *, struct net_device *); +static netdev_tx_t isdn_net_start_xmit(struct sk_buff *, + struct net_device *); static void isdn_net_ciscohdlck_connected(isdn_net_local *lp); static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp); @@ -1160,7 +1161,7 @@ static void isdn_net_tx_timeout(struct net_device * ndev) * If this interface isn't connected to a ISDN-Channel, find a free channel, * and start dialing. */ -static int +static netdev_tx_t isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) { isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev); -- cgit v1.2.3-18-g5258 From 25a79c41ce0ce88a4288adf278e9b0e00f228383 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:45 +0000 Subject: usbnet: convert to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/usb/catc.c | 3 ++- drivers/net/usb/cdc-phonet.c | 6 +++--- drivers/net/usb/hso.c | 3 ++- drivers/net/usb/kaweth.c | 3 ++- drivers/net/usb/pegasus.c | 3 ++- drivers/net/usb/rtl8150.c | 3 ++- drivers/net/usb/usbnet.c | 8 ++++---- drivers/usb/gadget/u_ether.c | 3 ++- 8 files changed, 19 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index 7abdc4abbe0..0ffc0c6d03b 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -411,7 +411,8 @@ static void catc_tx_done(struct urb *urb) spin_unlock_irqrestore(&catc->tx_lock, flags); } -static int catc_start_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t catc_start_xmit(struct sk_buff *skb, + struct net_device *netdev) { struct catc *catc = netdev_priv(netdev); unsigned long flags; diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c index 792af72da8a..0ca5916ca8d 100644 --- a/drivers/net/usb/cdc-phonet.c +++ b/drivers/net/usb/cdc-phonet.c @@ -55,7 +55,7 @@ static void rx_complete(struct urb *req); /* * Network device callbacks */ -static int usbpn_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t usbpn_xmit(struct sk_buff *skb, struct net_device *dev) { struct usbpn_dev *pnd = netdev_priv(dev); struct urb *req = NULL; @@ -82,12 +82,12 @@ static int usbpn_xmit(struct sk_buff *skb, struct net_device *dev) if (pnd->tx_queue >= dev->tx_queue_len) netif_stop_queue(dev); spin_unlock_irqrestore(&pnd->tx_lock, flags); - return 0; + return NETDEV_TX_OK; drop: dev_kfree_skb(skb); dev->stats.tx_dropped++; - return 0; + return NETDEV_TX_OK; } static void tx_complete(struct urb *req) diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index ffe41063573..123f9b84dd2 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -771,7 +771,8 @@ static void write_bulk_callback(struct urb *urb) } /* called by kernel when we need to transmit a packet */ -static int hso_net_start_xmit(struct sk_buff *skb, struct net_device *net) +static netdev_tx_t hso_net_start_xmit(struct sk_buff *skb, + struct net_device *net) { struct hso_net *odev = netdev_priv(net); int result; diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index 200fe3d525c..7f397365b43 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -803,7 +803,8 @@ static void kaweth_usb_transmit_complete(struct urb *urb) /**************************************************************** * kaweth_start_xmit ****************************************************************/ -static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) +static netdev_tx_t kaweth_start_xmit(struct sk_buff *skb, + struct net_device *net) { struct kaweth_device *kaweth = netdev_priv(net); __le16 *private_header; diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 69d2df95ac8..7b935b84642 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -876,7 +876,8 @@ static void pegasus_tx_timeout(struct net_device *net) pegasus->stats.tx_errors++; } -static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net) +static netdev_tx_t pegasus_start_xmit(struct sk_buff *skb, + struct net_device *net) { pegasus_t *pegasus = netdev_priv(net); int count = ((skb->len + 2) & 0x3f) ? skb->len + 2 : skb->len + 3; diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index bac8b77fb25..d9f84f22fbc 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -727,7 +727,8 @@ static void rtl8150_set_multicast(struct net_device *netdev) netif_wake_queue(netdev); } -static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + struct net_device *netdev) { rtl8150_t *dev = netdev_priv(netdev); int count, res; diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 7d471fca274..d166e3385c6 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1007,15 +1007,16 @@ EXPORT_SYMBOL_GPL(usbnet_tx_timeout); /*-------------------------------------------------------------------------*/ -int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) +netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, + struct net_device *net) { struct usbnet *dev = netdev_priv(net); int length; - int retval = NET_XMIT_SUCCESS; struct urb *urb = NULL; struct skb_data *entry; struct driver_info *info = dev->driver_info; unsigned long flags; + int retval; // some devices want funky USB-level framing, for // win32 driver (usually) and/or hardware quirks @@ -1079,7 +1080,6 @@ int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) if (netif_msg_tx_err (dev)) devdbg (dev, "drop, code %d", retval); drop: - retval = NET_XMIT_SUCCESS; dev->net->stats.tx_dropped++; if (skb) dev_kfree_skb_any (skb); @@ -1088,7 +1088,7 @@ drop: devdbg (dev, "> tx, len %d, type 0x%x", length, skb->protocol); } - return retval; + return NETDEV_TX_OK; } EXPORT_SYMBOL_GPL(usbnet_start_xmit); diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index aac69b591ae..dc3ebd1e68c 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -465,7 +465,8 @@ static inline int is_promisc(u16 cdc_filter) return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS; } -static int eth_start_xmit(struct sk_buff *skb, struct net_device *net) +static netdev_tx_t eth_start_xmit(struct sk_buff *skb, + struct net_device *net) { struct eth_dev *dev = netdev_priv(net); int length = skb->len; -- cgit v1.2.3-18-g5258 From 61a84108547c1c017683f15311ccbede249fc6fa Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:46 +0000 Subject: tokenring: convert to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/tokenring/3c359.c | 4 ++-- drivers/net/tokenring/ibmtr.c | 6 ++++-- drivers/net/tokenring/lanstreamer.c | 6 ++++-- drivers/net/tokenring/olympic.c | 6 ++++-- drivers/net/tokenring/smctr.c | 6 ++++-- drivers/net/tokenring/tms380tr.c | 19 +++++++++++-------- 6 files changed, 29 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index 1787d52941b..724158966ec 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -128,7 +128,7 @@ static int xl_init(struct net_device *dev); static int xl_open(struct net_device *dev); static int xl_open_hw(struct net_device *dev) ; static int xl_hw_reset(struct net_device *dev); -static int xl_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t xl_xmit(struct sk_buff *skb, struct net_device *dev); static void xl_dn_comp(struct net_device *dev); static int xl_close(struct net_device *dev); static void xl_set_rx_mode(struct net_device *dev); @@ -1193,7 +1193,7 @@ static irqreturn_t xl_interrupt(int irq, void *dev_id) * Tx - Polling configuration */ -static int xl_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t xl_xmit(struct sk_buff *skb, struct net_device *dev) { struct xl_private *xl_priv=netdev_priv(dev); struct xl_tx_desc *txd ; diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 96d00c8f8d3..525bbc5b9c9 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -191,7 +191,8 @@ static int tok_init_card(struct net_device *dev); static void tok_open_adapter(unsigned long dev_addr); static void open_sap(unsigned char type, struct net_device *dev); static void tok_set_multicast_list(struct net_device *dev); -static int tok_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t tok_send_packet(struct sk_buff *skb, + struct net_device *dev); static int tok_close(struct net_device *dev); static irqreturn_t tok_interrupt(int irq, void *dev_id); static void initial_tok_int(struct net_device *dev); @@ -1022,7 +1023,8 @@ static void tok_set_multicast_list(struct net_device *dev) #define STATION_ID_OFST 4 -static int tok_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t tok_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct tok_info *ti; unsigned long flags; diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index d07e61a9499..26dca2b2bdb 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -203,7 +203,8 @@ static int streamer_ioctl(struct net_device *, struct ifreq *, int); static int streamer_reset(struct net_device *dev); static int streamer_open(struct net_device *dev); -static int streamer_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t streamer_xmit(struct sk_buff *skb, + struct net_device *dev); static int streamer_close(struct net_device *dev); static void streamer_set_rx_mode(struct net_device *dev); static irqreturn_t streamer_interrupt(int irq, void *dev_id); @@ -1141,7 +1142,8 @@ static irqreturn_t streamer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int streamer_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t streamer_xmit(struct sk_buff *skb, + struct net_device *dev) { struct streamer_private *streamer_priv = netdev_priv(dev); diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index f73f4e684f3..d9ec7f0bbd0 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -182,7 +182,8 @@ MODULE_DEVICE_TABLE(pci,olympic_pci_tbl) ; static int olympic_probe(struct pci_dev *pdev, const struct pci_device_id *ent); static int olympic_init(struct net_device *dev); static int olympic_open(struct net_device *dev); -static int olympic_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t olympic_xmit(struct sk_buff *skb, + struct net_device *dev); static int olympic_close(struct net_device *dev); static void olympic_set_rx_mode(struct net_device *dev); static void olympic_freemem(struct net_device *dev) ; @@ -1030,7 +1031,8 @@ static irqreturn_t olympic_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int olympic_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t olympic_xmit(struct sk_buff *skb, + struct net_device *dev) { struct olympic_private *olympic_priv=netdev_priv(dev); u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index 23e012f5bbf..ebda61bc4c2 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -234,7 +234,8 @@ static int smctr_rx_frame(struct net_device *dev); /* S */ static int smctr_send_dat(struct net_device *dev); -static int smctr_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t smctr_send_packet(struct sk_buff *skb, + struct net_device *dev); static int smctr_send_lobe_media_test(struct net_device *dev); static int smctr_send_rpt_addr(struct net_device *dev, MAC_HEADER *rmf, __u16 correlator); @@ -4571,7 +4572,8 @@ static void smctr_timeout(struct net_device *dev) /* * Gets skb from system, queues it and checks if it can be sent */ -static int smctr_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t smctr_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct net_local *tp = netdev_priv(dev); diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index 07f6dfd3ba0..a7b6888829b 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -144,8 +144,8 @@ static void tms380tr_exec_sifcmd(struct net_device *dev, unsigned int WriteValu /* "G" */ static struct net_device_stats *tms380tr_get_stats(struct net_device *dev); /* "H" */ -static int tms380tr_hardware_send_packet(struct sk_buff *skb, - struct net_device *dev); +static netdev_tx_t tms380tr_hardware_send_packet(struct sk_buff *skb, + struct net_device *dev); /* "I" */ static int tms380tr_init_adapter(struct net_device *dev); static void tms380tr_init_ipb(struct net_local *tp); @@ -165,7 +165,8 @@ static int tms380tr_reset_adapter(struct net_device *dev); static void tms380tr_reset_interrupt(struct net_device *dev); static void tms380tr_ring_status_irq(struct net_device *dev); /* "S" */ -static int tms380tr_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t tms380tr_send_packet(struct sk_buff *skb, + struct net_device *dev); static void tms380tr_set_multicast_list(struct net_device *dev); static int tms380tr_set_mac_address(struct net_device *dev, void *addr); /* "T" */ @@ -599,21 +600,23 @@ static void tms380tr_timeout(struct net_device *dev) /* * Gets skb from system, queues it and checks if it can be sent */ -static int tms380tr_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t tms380tr_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct net_local *tp = netdev_priv(dev); - int err; + netdev_tx_t rc; - err = tms380tr_hardware_send_packet(skb, dev); + rc = tms380tr_hardware_send_packet(skb, dev); if(tp->TplFree->NextTPLPtr->BusyFlag) netif_stop_queue(dev); - return (err); + return rc; } /* * Move frames into adapter tx queue */ -static int tms380tr_hardware_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t tms380tr_hardware_send_packet(struct sk_buff *skb, + struct net_device *dev) { TPL *tpl; short length; -- cgit v1.2.3-18-g5258 From d71a674922e7519edb477ecb585e7d29d69c7aa7 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:47 +0000 Subject: wan: convert drivers to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/wan/cosa.c | 7 ++++--- drivers/net/wan/cycx_x25.c | 8 ++++---- drivers/net/wan/dlci.c | 13 +++++++------ drivers/net/wan/dscc4.c | 6 ++++-- drivers/net/wan/farsync.c | 2 +- drivers/net/wan/hd64570.c | 4 ++-- drivers/net/wan/hd64572.c | 4 ++-- drivers/net/wan/hdlc.c | 2 +- drivers/net/wan/hdlc_fr.c | 2 +- drivers/net/wan/hdlc_raw_eth.c | 2 +- drivers/net/wan/hdlc_x25.c | 6 +++--- drivers/net/wan/hostess_sv11.c | 3 ++- drivers/net/wan/lapbether.c | 3 ++- drivers/net/wan/lmc/lmc_main.c | 9 +++++---- drivers/net/wan/sbni.c | 7 ++++--- drivers/net/wan/sdla.c | 5 +++-- drivers/net/wan/sealevel.c | 3 ++- drivers/net/wan/wanxl.c | 2 +- drivers/net/wan/x25_asy.c | 3 ++- drivers/net/wan/z85230.c | 9 ++++----- drivers/net/wan/z85230.h | 3 ++- 21 files changed, 57 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 61581ee5f08..66360a2a14c 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -279,7 +279,7 @@ static int cosa_net_attach(struct net_device *dev, unsigned short encoding, static int cosa_net_open(struct net_device *d); static int cosa_net_close(struct net_device *d); static void cosa_net_timeout(struct net_device *d); -static int cosa_net_tx(struct sk_buff *skb, struct net_device *d); +static netdev_tx_t cosa_net_tx(struct sk_buff *skb, struct net_device *d); static char *cosa_net_setup_rx(struct channel_data *channel, int size); static int cosa_net_rx_done(struct channel_data *channel); static int cosa_net_tx_done(struct channel_data *channel, int size); @@ -672,7 +672,8 @@ static int cosa_net_open(struct net_device *dev) return 0; } -static int cosa_net_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t cosa_net_tx(struct sk_buff *skb, + struct net_device *dev) { struct channel_data *chan = dev_to_chan(dev); @@ -680,7 +681,7 @@ static int cosa_net_tx(struct sk_buff *skb, struct net_device *dev) chan->tx_skb = skb; cosa_start_tx(chan, skb->data, skb->len); - return 0; + return NETDEV_TX_OK; } static void cosa_net_timeout(struct net_device *dev) diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index 4ae9bd297cc..2573c18b6aa 100644 --- a/drivers/net/wan/cycx_x25.c +++ b/drivers/net/wan/cycx_x25.c @@ -139,8 +139,8 @@ static int cycx_netdevice_hard_header(struct sk_buff *skb, const void *daddr, const void *saddr, unsigned len); static int cycx_netdevice_rebuild_header(struct sk_buff *skb); -static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb, - struct net_device *dev); +static netdev_tx_t cycx_netdevice_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev); static struct net_device_stats * cycx_netdevice_get_stats(struct net_device *dev); @@ -593,8 +593,8 @@ static int cycx_netdevice_rebuild_header(struct sk_buff *skb) * bottom half" (with interrupts enabled). * 2. Setting tbusy flag will inhibit further transmit requests from the * protocol stack and can be used for flow control with protocol layer. */ -static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb, - struct net_device *dev) +static netdev_tx_t cycx_netdevice_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct cycx_x25_channel *chan = netdev_priv(dev); struct cycx_device *card = chan->card; diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 8526b6d1ee4..69d269d32b5 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -186,12 +186,11 @@ static void dlci_receive(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); } -static int dlci_transmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t dlci_transmit(struct sk_buff *skb, + struct net_device *dev) { struct dlci_local *dlp; - int ret; - - ret = 0; + netdev_tx_t ret; if (!skb || !dev) return NETDEV_TX_OK; @@ -200,6 +199,8 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); + /* This is hackish, overloads driver specific return values + on top of normal transmit return! */ ret = dlp->slave->netdev_ops->ndo_start_xmit(skb, dlp->slave); switch (ret) { @@ -207,11 +208,11 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_packets++; ret = NETDEV_TX_OK; break; - case DLCI_RET_ERR: + case DLCI_RET_ERR: dev->stats.tx_errors++; ret = NETDEV_TX_OK; break; - case DLCI_RET_DROP: + case DLCI_RET_DROP: dev->stats.tx_dropped++; ret = NETDEV_TX_BUSY; break; diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index cc00e0f89ec..b2247bd0d49 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -359,7 +359,8 @@ static void dscc4_tx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *); static int dscc4_found1(struct pci_dev *, void __iomem *ioaddr); static int dscc4_init_one(struct pci_dev *, const struct pci_device_id *ent); static int dscc4_open(struct net_device *); -static int dscc4_start_xmit(struct sk_buff *, struct net_device *); +static netdev_tx_t dscc4_start_xmit(struct sk_buff *, + struct net_device *); static int dscc4_close(struct net_device *); static int dscc4_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int dscc4_init_ring(struct net_device *); @@ -1148,7 +1149,8 @@ static int dscc4_tx_poll(struct dscc4_dev_priv *dpriv, struct net_device *dev) } #endif /* DSCC4_POLLING */ -static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t dscc4_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct dscc4_dev_priv *dpriv = dscc4_priv(dev); struct dscc4_pci_priv *ppriv = dpriv->pci_priv; diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 20a1237a3d7..3e90eb81618 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -2274,7 +2274,7 @@ fst_tx_timeout(struct net_device *dev) port->start = 0; } -static int +static netdev_tx_t fst_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct fst_card_info *card; diff --git a/drivers/net/wan/hd64570.c b/drivers/net/wan/hd64570.c index 1ea1ef6c3b9..80114c93bae 100644 --- a/drivers/net/wan/hd64570.c +++ b/drivers/net/wan/hd64570.c @@ -620,7 +620,7 @@ static void sca_dump_rings(struct net_device *dev) #endif /* DEBUG_RINGS */ -static int sca_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t sca_xmit(struct sk_buff *skb, struct net_device *dev) { port_t *port = dev_to_port(dev); card_t *card = port_to_card(port); @@ -674,7 +674,7 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&port->lock); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/wan/hd64572.c b/drivers/net/wan/hd64572.c index f099c34a3ae..84f01373e11 100644 --- a/drivers/net/wan/hd64572.c +++ b/drivers/net/wan/hd64572.c @@ -562,7 +562,7 @@ static void sca_dump_rings(struct net_device *dev) #endif /* DEBUG_RINGS */ -static int sca_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t sca_xmit(struct sk_buff *skb, struct net_device *dev) { port_t *port = dev_to_port(dev); card_t *card = port->card; @@ -601,7 +601,7 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&port->lock); dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c index 7596eae1b35..cc07236ea73 100644 --- a/drivers/net/wan/hdlc.c +++ b/drivers/net/wan/hdlc.c @@ -66,7 +66,7 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, return hdlc->proto->netif_rx(skb); } -int hdlc_start_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t hdlc_start_xmit(struct sk_buff *skb, struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index 52438c76bf8..840cff72a0f 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -407,7 +407,7 @@ static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -EINVAL; } -static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t pvc_xmit(struct sk_buff *skb, struct net_device *dev) { pvc_device *pvc = dev->ml_priv; diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c index 49e68f5ca5f..1b30fcc2414 100644 --- a/drivers/net/wan/hdlc_raw_eth.c +++ b/drivers/net/wan/hdlc_raw_eth.c @@ -25,7 +25,7 @@ static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr); -static int eth_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t eth_tx(struct sk_buff *skb, struct net_device *dev) { int pad = ETH_ZLEN - skb->len; if (pad > 0) { /* Pad the frame with zeros */ diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c index b1dc29ed158..aa9248f8eb1 100644 --- a/drivers/net/wan/hdlc_x25.c +++ b/drivers/net/wan/hdlc_x25.c @@ -87,7 +87,7 @@ static void x25_data_transmit(struct net_device *dev, struct sk_buff *skb) -static int x25_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t x25_xmit(struct sk_buff *skb, struct net_device *dev) { int result; @@ -98,7 +98,7 @@ static int x25_xmit(struct sk_buff *skb, struct net_device *dev) skb_pull(skb, 1); if ((result = lapb_data_request(dev, skb)) != LAPB_OK) dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; case 1: if ((result = lapb_connect_request(dev))!= LAPB_OK) { @@ -129,7 +129,7 @@ static int x25_xmit(struct sk_buff *skb, struct net_device *dev) } dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c index 567d4f5062d..15002c3d0d9 100644 --- a/drivers/net/wan/hostess_sv11.c +++ b/drivers/net/wan/hostess_sv11.c @@ -156,7 +156,8 @@ static int hostess_ioctl(struct net_device *d, struct ifreq *ifr, int cmd) * Passed network frames, fire them downwind. */ -static int hostess_queue_xmit(struct sk_buff *skb, struct net_device *d) +static netdev_tx_t hostess_queue_xmit(struct sk_buff *skb, + struct net_device *d) { return z8530_queue_xmit(&dev_to_sv(d)->chanA, skb); } diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index aff4f6bdf3d..d1e3c673e9b 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -147,7 +147,8 @@ static int lapbeth_data_indication(struct net_device *dev, struct sk_buff *skb) /* * Send a LAPB frame via an ethernet interface */ -static int lapbeth_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t lapbeth_xmit(struct sk_buff *skb, + struct net_device *dev) { int err; diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index 4b83d887285..7ea71b33d2e 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -89,7 +89,8 @@ MODULE_DEVICE_TABLE(pci, lmc_pci_tbl); MODULE_LICENSE("GPL v2"); -static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t lmc_start_xmit(struct sk_buff *skb, + struct net_device *dev); static int lmc_rx (struct net_device *dev); static int lmc_open(struct net_device *dev); static int lmc_close(struct net_device *dev); @@ -1423,12 +1424,12 @@ lmc_int_fail_out: return IRQ_RETVAL(handled); } -static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t lmc_start_xmit(struct sk_buff *skb, + struct net_device *dev) { lmc_softc_t *sc = dev_to_sc(dev); u32 flag; int entry; - int ret = NETDEV_TX_OK; unsigned long flags; lmc_trace(dev, "lmc_start_xmit in"); @@ -1510,7 +1511,7 @@ static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&sc->lmc_lock, flags); lmc_trace(dev, "lmc_start_xmit_out"); - return ret; + return NETDEV_TX_OK; } diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 85c02a2ec2e..1cc24a45f00 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -114,7 +114,8 @@ static int sbni_pci_probe( struct net_device * ); static struct net_device *sbni_probe1(struct net_device *, unsigned long, int); static int sbni_open( struct net_device * ); static int sbni_close( struct net_device * ); -static int sbni_start_xmit( struct sk_buff *, struct net_device * ); +static netdev_tx_t sbni_start_xmit(struct sk_buff *, + struct net_device * ); static int sbni_ioctl( struct net_device *, struct ifreq *, int ); static void set_multicast_list( struct net_device * ); @@ -444,7 +445,7 @@ sbni_probe1( struct net_device *dev, unsigned long ioaddr, int irq ) #ifdef CONFIG_SBNI_MULTILINE -static int +static netdev_tx_t sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) { struct net_device *p; @@ -472,7 +473,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) #else /* CONFIG_SBNI_MULTILINE */ -static int +static netdev_tx_t sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) { struct net_local *nl = netdev_priv(dev); diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 1d637f407a0..63c76458431 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -651,7 +651,8 @@ static int sdla_dlci_conf(struct net_device *slave, struct net_device *master, i **************************/ /* NOTE: the DLCI driver deals with freeing the SKB!! */ -static int sdla_transmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t sdla_transmit(struct sk_buff *skb, + struct net_device *dev) { struct frad_local *flp; int ret, addr, accept, i; @@ -737,7 +738,7 @@ static int sdla_transmit(struct sk_buff *skb, struct net_device *dev) if(flp->master[i]!=NULL) netif_wake_queue(flp->master[i]); } - return(ret); + return NETDEV_TX_OK; } static void sdla_receive(struct net_device *dev) diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c index 23b26902745..0c525e24b24 100644 --- a/drivers/net/wan/sealevel.c +++ b/drivers/net/wan/sealevel.c @@ -156,7 +156,8 @@ static int sealevel_ioctl(struct net_device *d, struct ifreq *ifr, int cmd) * Passed network frames, fire them downwind. */ -static int sealevel_queue_xmit(struct sk_buff *skb, struct net_device *d) +static netdev_tx_t sealevel_queue_xmit(struct sk_buff *skb, + struct net_device *d) { return z8530_queue_xmit(dev_to_chan(d)->chan, skb); } diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c index 03b76adbe5f..daee8a0624e 100644 --- a/drivers/net/wan/wanxl.c +++ b/drivers/net/wan/wanxl.c @@ -268,7 +268,7 @@ static irqreturn_t wanxl_intr(int irq, void* dev_id) -static int wanxl_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t wanxl_xmit(struct sk_buff *skb, struct net_device *dev) { port_t *port = dev_to_port(dev); desc_t *desc; diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index 1047920e742..27945049c9e 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -299,7 +299,8 @@ static void x25_asy_timeout(struct net_device *dev) /* Encapsulate an IP datagram and kick it into a TTY queue. */ -static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t x25_asy_xmit(struct sk_buff *skb, + struct net_device *dev) { struct x25_asy *sl = netdev_priv(dev); int err; diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c index ad4e79c4c5c..0be7ec7299d 100644 --- a/drivers/net/wan/z85230.c +++ b/drivers/net/wan/z85230.c @@ -1727,15 +1727,14 @@ static inline int spans_boundary(struct sk_buff *skb) * point. */ -int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb) +netdev_tx_t z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb) { unsigned long flags; netif_stop_queue(c->netdevice); if(c->tx_next_skb) - { - return 1; - } + return NETDEV_TX_BUSY; + /* PC SPECIFIC - DMA limits */ @@ -1767,7 +1766,7 @@ int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb) z8530_tx_begin(c); spin_unlock_irqrestore(c->lock, flags); - return 0; + return NETDEV_TX_OK; } EXPORT_SYMBOL(z8530_queue_xmit); diff --git a/drivers/net/wan/z85230.h b/drivers/net/wan/z85230.h index 85b3e785d48..f29d554fc07 100644 --- a/drivers/net/wan/z85230.h +++ b/drivers/net/wan/z85230.h @@ -406,7 +406,8 @@ extern int z8530_sync_dma_close(struct net_device *, struct z8530_channel *); extern int z8530_sync_txdma_open(struct net_device *, struct z8530_channel *); extern int z8530_sync_txdma_close(struct net_device *, struct z8530_channel *); extern int z8530_channel_load(struct z8530_channel *, u8 *); -extern int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb); +extern netdev_tx_t z8530_queue_xmit(struct z8530_channel *c, + struct sk_buff *skb); extern void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb); -- cgit v1.2.3-18-g5258 From 4c5d502d8b2db8947c44dc44bdc67dbe55cce2b9 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:48 +0000 Subject: hdlc: convert to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/char/pcmcia/synclink_cs.c | 7 +++---- drivers/char/synclink.c | 7 +++---- drivers/char/synclink_gt.c | 7 +++---- drivers/char/synclinkmp.c | 7 +++---- 4 files changed, 12 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 77b36488922..caf6e4d1946 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -4005,10 +4005,9 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, * * skb socket buffer containing HDLC frame * dev pointer to network device structure - * - * returns 0 if success, otherwise error code */ -static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, + struct net_device *dev) { MGSLPC_INFO *info = dev_to_port(dev); unsigned long flags; @@ -4043,7 +4042,7 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) } spin_unlock_irqrestore(&info->lock,flags); - return 0; + return NETDEV_TX_OK; } /** diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 813552f1488..4846b73ef28 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -7697,10 +7697,9 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, * * skb socket buffer containing HDLC frame * dev pointer to network device structure - * - * returns 0 if success, otherwise error code */ -static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, + struct net_device *dev) { struct mgsl_struct *info = dev_to_port(dev); unsigned long flags; @@ -7731,7 +7730,7 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) usc_start_transmitter(info); spin_unlock_irqrestore(&info->irq_spinlock,flags); - return 0; + return NETDEV_TX_OK; } /** diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 91f20a92fdd..8678f0c8699 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -1497,10 +1497,9 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, * * skb socket buffer containing HDLC frame * dev pointer to network device structure - * - * returns 0 if success, otherwise error code */ -static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, + struct net_device *dev) { struct slgt_info *info = dev_to_port(dev); unsigned long flags; @@ -1529,7 +1528,7 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) update_tx_timer(info); spin_unlock_irqrestore(&info->lock,flags); - return 0; + return NETDEV_TX_OK; } /** diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 8d4a2a8a0a7..2b18adc4ee1 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -1608,10 +1608,9 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, * * skb socket buffer containing HDLC frame * dev pointer to network device structure - * - * returns 0 if success, otherwise error code */ -static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, + struct net_device *dev) { SLMP_INFO *info = dev_to_port(dev); unsigned long flags; @@ -1642,7 +1641,7 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) tx_start(info); spin_unlock_irqrestore(&info->lock,flags); - return 0; + return NETDEV_TX_OK; } /** -- cgit v1.2.3-18-g5258 From dbf02fae406daf4d583a279743869c686024c341 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:49 +0000 Subject: netdev: convert pcmcia drivers to netdev_tx_t Update all the pcmcia network drivers for netdev_tx_t. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/pcmcia/3c574_cs.c | 6 ++++-- drivers/net/pcmcia/3c589_cs.c | 6 ++++-- drivers/net/pcmcia/axnet_cs.c | 6 ++++-- drivers/net/pcmcia/fmvj18x_cs.c | 6 ++++-- drivers/net/pcmcia/nmclan_cs.c | 6 ++++-- drivers/net/pcmcia/smc91c92_cs.c | 6 ++++-- drivers/net/pcmcia/xirc2ps_cs.c | 5 +++-- 7 files changed, 27 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index a23aa872404..382d26520ac 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -239,7 +239,8 @@ static void tc574_wait_for_completion(struct net_device *dev, int cmd); static void tc574_reset(struct net_device *dev); static void media_check(unsigned long arg); static int el3_open(struct net_device *dev); -static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t el3_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t el3_interrupt(int irq, void *dev_id); static void update_stats(struct net_device *dev); static struct net_device_stats *el3_get_stats(struct net_device *dev); @@ -778,7 +779,8 @@ static void pop_tx_status(struct net_device *dev) } } -static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t el3_start_xmit(struct sk_buff *skb, + struct net_device *dev) { unsigned int ioaddr = dev->base_addr; struct el3_private *lp = netdev_priv(dev); diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index d2156ab3da2..569fb06793c 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -149,7 +149,8 @@ static void tc589_reset(struct net_device *dev); static void media_check(unsigned long arg); static int el3_config(struct net_device *dev, struct ifmap *map); static int el3_open(struct net_device *dev); -static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t el3_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t el3_interrupt(int irq, void *dev_id); static void update_stats(struct net_device *dev); static struct net_device_stats *el3_get_stats(struct net_device *dev); @@ -604,7 +605,8 @@ static void pop_tx_status(struct net_device *dev) } } -static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t el3_start_xmit(struct sk_buff *skb, + struct net_device *dev) { unsigned int ioaddr = dev->base_addr; struct el3_private *priv = netdev_priv(dev); diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 1e87d634d7b..3b681c1d752 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -92,7 +92,8 @@ static void axnet_release(struct pcmcia_device *link); static int axnet_open(struct net_device *dev); static int axnet_close(struct net_device *dev); static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static int axnet_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t axnet_start_xmit(struct sk_buff *skb, + struct net_device *dev); static struct net_device_stats *get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); static void axnet_tx_timeout(struct net_device *dev); @@ -1063,7 +1064,8 @@ static void axnet_tx_timeout(struct net_device *dev) * Sends a packet to an 8390 network device. */ -static int axnet_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t axnet_start_xmit(struct sk_buff *skb, + struct net_device *dev) { long e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 434d9407bfb..7e01fbdb87e 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -96,7 +96,8 @@ static void fmvj18x_detach(struct pcmcia_device *p_dev); static int fjn_config(struct net_device *dev, struct ifmap *map); static int fjn_open(struct net_device *dev); static int fjn_close(struct net_device *dev); -static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t fjn_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t fjn_interrupt(int irq, void *dev_id); static void fjn_rx(struct net_device *dev); static void fjn_reset(struct net_device *dev); @@ -856,7 +857,8 @@ static void fjn_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t fjn_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct local_info_t *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index dd605907670..5ed6339c52b 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -424,7 +424,8 @@ static void nmclan_reset(struct net_device *dev); static int mace_config(struct net_device *dev, struct ifmap *map); static int mace_open(struct net_device *dev); static int mace_close(struct net_device *dev); -static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t mace_start_xmit(struct sk_buff *skb, + struct net_device *dev); static void mace_tx_timeout(struct net_device *dev); static irqreturn_t mace_interrupt(int irq, void *dev_id); static struct net_device_stats *mace_get_stats(struct net_device *dev); @@ -937,7 +938,8 @@ static void mace_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t mace_start_xmit(struct sk_buff *skb, + struct net_device *dev) { mace_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 2f39244c17f..7bde2cd34c7 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -288,7 +288,8 @@ static int smc_open(struct net_device *dev); static int smc_close(struct net_device *dev); static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void smc_tx_timeout(struct net_device *dev); -static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t smc_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t smc_interrupt(int irq, void *dev_id); static void smc_rx(struct net_device *dev); static void set_rx_mode(struct net_device *dev); @@ -1370,7 +1371,8 @@ static void smc_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t smc_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct smc_private *smc = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index eda7bf6047c..68de89167b4 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -352,7 +352,8 @@ typedef struct local_info_t { /**************** * Some more prototypes */ -static int do_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t do_start_xmit(struct sk_buff *skb, + struct net_device *dev); static void xirc_tx_timeout(struct net_device *dev); static void xirc2ps_tx_timeout_task(struct work_struct *work); static void set_addresses(struct net_device *dev); @@ -1361,7 +1362,7 @@ xirc_tx_timeout(struct net_device *dev) schedule_work(&lp->tx_timeout_task); } -static int +static netdev_tx_t do_start_xmit(struct sk_buff *skb, struct net_device *dev) { local_info_t *lp = netdev_priv(dev); -- cgit v1.2.3-18-g5258 From 6518bbb803fe02b15a3211c8db2afdff0ac4f808 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:50 +0000 Subject: irda: convert to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/irda/ali-ircc.c | 12 ++++++++---- drivers/net/irda/donauboe.c | 2 +- drivers/net/irda/irda-usb.c | 6 ++++-- drivers/net/irda/kingsun-sir.c | 5 +++-- drivers/net/irda/ks959-sir.c | 3 ++- drivers/net/irda/ksdazzle-sir.c | 3 ++- drivers/net/irda/mcs7780.c | 3 ++- drivers/net/irda/mcs7780.h | 3 ++- drivers/net/irda/nsc-ircc.c | 12 ++++++++---- drivers/net/irda/sir_dev.c | 3 ++- drivers/net/irda/smsc-ircc2.c | 15 ++++++++++----- drivers/net/irda/stir4200.c | 3 ++- drivers/net/irda/via-ircc.c | 16 ++++++++-------- drivers/net/irda/vlsi_ir.c | 3 ++- drivers/net/irda/w83977af_ir.c | 6 ++++-- 15 files changed, 60 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index f0d0cea6e32..12c7b006f76 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -111,7 +111,8 @@ static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud); /* SIR function */ -static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ali_ircc_sir_hard_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t ali_ircc_sir_interrupt(struct ali_ircc_cb *self); static void ali_ircc_sir_receive(struct ali_ircc_cb *self); static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self); @@ -119,7 +120,8 @@ static int ali_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len); static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed); /* FIR function */ -static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ali_ircc_fir_hard_xmit(struct sk_buff *skb, + struct net_device *dev); static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 speed); static irqreturn_t ali_ircc_fir_interrupt(struct ali_ircc_cb *self); static int ali_ircc_dma_receive(struct ali_ircc_cb *self); @@ -1435,7 +1437,8 @@ static int ali_ircc_net_close(struct net_device *dev) * Transmit the frame * */ -static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ali_ircc_fir_hard_xmit(struct sk_buff *skb, + struct net_device *dev) { struct ali_ircc_cb *self; unsigned long flags; @@ -1957,7 +1960,8 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) * Transmit the frame! * */ -static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ali_ircc_sir_hard_xmit(struct sk_buff *skb, + struct net_device *dev) { struct ali_ircc_cb *self; unsigned long flags; diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index e4e905698dc..2d7b5c1d557 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -970,7 +970,7 @@ toshoboe_probe (struct toshoboe_cb *self) /* Netdev style code */ /* Transmit something */ -static int +static netdev_tx_t toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) { struct toshoboe_cb *self; diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 6a1aa7a40fe..215adf6377d 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -111,7 +111,8 @@ static void irda_usb_init_qos(struct irda_usb_cb *self) ; static struct irda_class_desc *irda_usb_find_class_desc(struct usb_interface *intf); static void irda_usb_disconnect(struct usb_interface *intf); static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self); -static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t irda_usb_hard_xmit(struct sk_buff *skb, + struct net_device *dev); static int irda_usb_open(struct irda_usb_cb *self); static void irda_usb_close(struct irda_usb_cb *self); static void speed_bulk_callback(struct urb *urb); @@ -381,7 +382,8 @@ static void speed_bulk_callback(struct urb *urb) /* * Send an IrDA frame to the USB dongle (for transmission) */ -static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t irda_usb_hard_xmit(struct sk_buff *skb, + struct net_device *netdev) { struct irda_usb_cb *self = netdev_priv(netdev); struct urb *urb = self->tx_urb; diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c index c3e4e2c435b..2fc30b449ee 100644 --- a/drivers/net/irda/kingsun-sir.c +++ b/drivers/net/irda/kingsun-sir.c @@ -150,7 +150,8 @@ static void kingsun_send_irq(struct urb *urb) /* * Called from net/core when new frame is available. */ -static int kingsun_hard_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t kingsun_hard_xmit(struct sk_buff *skb, + struct net_device *netdev) { struct kingsun_cb *kingsun; int wraplen; @@ -416,7 +417,7 @@ static int kingsun_net_ioctl(struct net_device *netdev, struct ifreq *rq, } static const struct net_device_ops kingsun_ops = { - .ndo_start_xmit = kingsun_hard_xmit, + .ndo_start_xmit = kingsun_hard_xmit, .ndo_open = kingsun_net_open, .ndo_stop = kingsun_net_close, .ndo_do_ioctl = kingsun_net_ioctl, diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c index d73b8b64fcb..f4d13fc51cb 100644 --- a/drivers/net/irda/ks959-sir.c +++ b/drivers/net/irda/ks959-sir.c @@ -385,7 +385,8 @@ static void ks959_send_irq(struct urb *urb) /* * Called from net/core when new frame is available. */ -static int ks959_hard_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t ks959_hard_xmit(struct sk_buff *skb, + struct net_device *netdev) { struct ks959_cb *kingsun; unsigned int wraplen; diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c index 1ef45ec7442..5f9d7335397 100644 --- a/drivers/net/irda/ksdazzle-sir.c +++ b/drivers/net/irda/ksdazzle-sir.c @@ -298,7 +298,8 @@ static void ksdazzle_send_irq(struct urb *urb) /* * Called from net/core when new frame is available. */ -static int ksdazzle_hard_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t ksdazzle_hard_xmit(struct sk_buff *skb, + struct net_device *netdev) { struct ksdazzle_cb *kingsun; unsigned int wraplen; diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index f4df1001983..b3d30bcb88e 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -817,7 +817,8 @@ static void mcs_send_irq(struct urb *urb) } /* Transmit callback funtion. */ -static int mcs_hard_xmit(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t mcs_hard_xmit(struct sk_buff *skb, + struct net_device *ndev) { unsigned long flags; struct mcs_cb *mcs; diff --git a/drivers/net/irda/mcs7780.h b/drivers/net/irda/mcs7780.h index 6bdc621e67c..b10689b2887 100644 --- a/drivers/net/irda/mcs7780.h +++ b/drivers/net/irda/mcs7780.h @@ -156,7 +156,8 @@ static int mcs_net_open(struct net_device *netdev); static void mcs_receive_irq(struct urb *urb); static void mcs_send_irq(struct urb *urb); -static int mcs_hard_xmit(struct sk_buff *skb, struct net_device *netdev); +static netdev_tx_t mcs_hard_xmit(struct sk_buff *skb, + struct net_device *netdev); static int mcs_probe(struct usb_interface *intf, const struct usb_device_id *id); diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 51ca89c9a0b..2413295ebd9 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -173,8 +173,10 @@ static int nsc_ircc_setup(chipio_t *info); static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self); static int nsc_ircc_dma_receive(struct nsc_ircc_cb *self); static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase); -static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev); -static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t nsc_ircc_hard_xmit_sir(struct sk_buff *skb, + struct net_device *dev); +static netdev_tx_t nsc_ircc_hard_xmit_fir(struct sk_buff *skb, + struct net_device *dev); static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size); static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase); static __u8 nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 baud); @@ -1355,7 +1357,8 @@ static __u8 nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 speed) * Transmit the frame! * */ -static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t nsc_ircc_hard_xmit_sir(struct sk_buff *skb, + struct net_device *dev) { struct nsc_ircc_cb *self; unsigned long flags; @@ -1427,7 +1430,8 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } -static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t nsc_ircc_hard_xmit_fir(struct sk_buff *skb, + struct net_device *dev) { struct nsc_ircc_cb *self; unsigned long flags; diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index 71dce20e62b..4b2a1a9eac2 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -582,7 +582,8 @@ EXPORT_SYMBOL(sirdev_receive); /* callbacks from network layer */ -static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t sirdev_hard_xmit(struct sk_buff *skb, + struct net_device *ndev) { struct sir_dev *dev = netdev_priv(ndev); unsigned long flags; diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 15f8a7f8160..1e8dd8c74a6 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -194,8 +194,10 @@ static int __exit smsc_ircc_close(struct smsc_ircc_cb *self); static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self); static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self); static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self); -static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev); -static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t smsc_ircc_hard_xmit_sir(struct sk_buff *skb, + struct net_device *dev); +static netdev_tx_t smsc_ircc_hard_xmit_fir(struct sk_buff *skb, + struct net_device *dev); static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int bofs); static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self); static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed); @@ -486,7 +488,8 @@ static int __init smsc_ircc_init(void) return ret; } -static int smsc_ircc_net_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t smsc_ircc_net_xmit(struct sk_buff *skb, + struct net_device *dev) { struct smsc_ircc_cb *self = netdev_priv(dev); @@ -878,7 +881,8 @@ static void smsc_ircc_timeout(struct net_device *dev) * waits until the next transmit interrupt, and continues until the * frame is transmitted. */ -static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t smsc_ircc_hard_xmit_sir(struct sk_buff *skb, + struct net_device *dev) { struct smsc_ircc_cb *self; unsigned long flags; @@ -1183,7 +1187,8 @@ static void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, __u32 speed) * Transmit the frame! * */ -static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t smsc_ircc_hard_xmit_fir(struct sk_buff *skb, + struct net_device *dev) { struct smsc_ircc_cb *self; unsigned long flags; diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index c475b23091b..528767dec9d 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -560,7 +560,8 @@ static int change_speed(struct stir_cb *stir, unsigned speed) /* * Called from net/core when new frame is available. */ -static int stir_hard_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t stir_hard_xmit(struct sk_buff *skb, + struct net_device *netdev) { struct stir_cb *stir = netdev_priv(netdev); diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 36a60748447..a5ca71cec02 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -87,10 +87,10 @@ static int via_ircc_close(struct via_ircc_cb *self); static int via_ircc_dma_receive(struct via_ircc_cb *self); static int via_ircc_dma_receive_complete(struct via_ircc_cb *self, int iobase); -static int via_ircc_hard_xmit_sir(struct sk_buff *skb, - struct net_device *dev); -static int via_ircc_hard_xmit_fir(struct sk_buff *skb, - struct net_device *dev); +static netdev_tx_t via_ircc_hard_xmit_sir(struct sk_buff *skb, + struct net_device *dev); +static netdev_tx_t via_ircc_hard_xmit_fir(struct sk_buff *skb, + struct net_device *dev); static void via_hw_init(struct via_ircc_cb *self); static void via_ircc_change_speed(struct via_ircc_cb *self, __u32 baud); static irqreturn_t via_ircc_interrupt(int irq, void *dev_id); @@ -823,8 +823,8 @@ static void via_ircc_change_speed(struct via_ircc_cb *self, __u32 speed) * Transmit the frame! * */ -static int via_ircc_hard_xmit_sir(struct sk_buff *skb, - struct net_device *dev) +static netdev_tx_t via_ircc_hard_xmit_sir(struct sk_buff *skb, + struct net_device *dev) { struct via_ircc_cb *self; unsigned long flags; @@ -895,8 +895,8 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb, return NETDEV_TX_OK; } -static int via_ircc_hard_xmit_fir(struct sk_buff *skb, - struct net_device *dev) +static netdev_tx_t via_ircc_hard_xmit_fir(struct sk_buff *skb, + struct net_device *dev) { struct via_ircc_cb *self; u16 iobase; diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index 08e26f1297b..7cfb8b6593c 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -854,7 +854,8 @@ static int vlsi_set_baud(vlsi_irda_dev_t *idev, unsigned iobase) return ret; } -static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t vlsi_hard_start_xmit(struct sk_buff *skb, + struct net_device *ndev) { vlsi_irda_dev_t *idev = netdev_priv(ndev); struct vlsi_ring *r = idev->tx_ring; diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index 462bc437080..551810fd297 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -93,7 +93,8 @@ static int w83977af_close(struct w83977af_ir *self); static int w83977af_probe(int iobase, int irq, int dma); static int w83977af_dma_receive(struct w83977af_ir *self); static int w83977af_dma_receive_complete(struct w83977af_ir *self); -static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb, + struct net_device *dev); static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size); static void w83977af_dma_write(struct w83977af_ir *self, int iobase); static void w83977af_change_speed(struct w83977af_ir *self, __u32 speed); @@ -490,7 +491,8 @@ static void w83977af_change_speed(struct w83977af_ir *self, __u32 speed) * Sets up a DMA transfer to send the current frame. * */ -static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb, + struct net_device *dev) { struct w83977af_ir *self; __s32 speed; -- cgit v1.2.3-18-g5258 From 424efe9caf6047ffbcd6b383ff4d2347254aabf1 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:51 +0000 Subject: netdev: convert pseudo drivers to netdev_tx_t These are all drivers that don't touch real hardware. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/firewire/net.c | 2 +- drivers/net/bonding/bond_main.c | 2 +- drivers/net/can/vcan.c | 2 +- drivers/net/dummy.c | 22 ++++++++++------------ drivers/net/eql.c | 4 ++-- drivers/net/ifb.c | 9 ++++----- drivers/net/macvlan.c | 3 ++- drivers/net/ppp_generic.c | 2 +- drivers/net/slip.c | 2 +- drivers/net/tun.c | 2 +- drivers/net/veth.c | 2 +- drivers/net/virtio_net.c | 2 +- 12 files changed, 26 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index a42209a73ae..d923d1dc458 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -1188,7 +1188,7 @@ static int fwnet_stop(struct net_device *net) return 0; } -static int fwnet_tx(struct sk_buff *skb, struct net_device *net) +static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) { struct fwnet_header hdr_buf; struct fwnet_device *dev = netdev_priv(net); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 7c0e0bded15..a7e731f8a0d 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4450,7 +4450,7 @@ static void bond_set_xmit_hash_policy(struct bonding *bond) } } -static int bond_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev) { const struct bonding *bond = netdev_priv(dev); diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c index a10c1d7b3b0..6971f6cd37f 100644 --- a/drivers/net/can/vcan.c +++ b/drivers/net/can/vcan.c @@ -83,7 +83,7 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev) netif_rx(skb); } -static int vcan_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev) { struct net_device_stats *stats = &dev->stats; int loop; diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 713ce6c532c..37dcfdc6345 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -39,8 +39,6 @@ static int numdummies = 1; -static int dummy_xmit(struct sk_buff *skb, struct net_device *dev); - static int dummy_set_address(struct net_device *dev, void *p) { struct sockaddr *sa = p; @@ -57,6 +55,16 @@ static void set_multicast_list(struct net_device *dev) { } + +static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev) +{ + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + + dev_kfree_skb(skb); + return NETDEV_TX_OK; +} + static const struct net_device_ops dummy_netdev_ops = { .ndo_start_xmit = dummy_xmit, .ndo_validate_addr = eth_validate_addr, @@ -78,16 +86,6 @@ static void dummy_setup(struct net_device *dev) dev->flags &= ~IFF_MULTICAST; random_ether_addr(dev->dev_addr); } - -static int dummy_xmit(struct sk_buff *skb, struct net_device *dev) -{ - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - - dev_kfree_skb(skb); - return NETDEV_TX_OK; -} - static int dummy_validate(struct nlattr *tb[], struct nlattr *data[]) { if (tb[IFLA_ADDRESS]) { diff --git a/drivers/net/eql.c b/drivers/net/eql.c index c0e69c5cae8..d4d9a3eda69 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -127,7 +127,7 @@ static int eql_open(struct net_device *dev); static int eql_close(struct net_device *dev); static int eql_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t eql_slave_xmit(struct sk_buff *skb, struct net_device *dev); #define eql_is_slave(dev) ((dev->flags & IFF_SLAVE) == IFF_SLAVE) #define eql_is_master(dev) ((dev->flags & IFF_MASTER) == IFF_MASTER) @@ -325,7 +325,7 @@ static slave_t *__eql_schedule_slaves(slave_queue_t *queue) return best_slave; } -static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t eql_slave_xmit(struct sk_buff *skb, struct net_device *dev) { equalizer_t *eql = netdev_priv(dev); slave_t *slave; diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 0a79b451780..801f088c134 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -59,7 +59,7 @@ struct ifb_private { static int numifbs = 2; static void ri_tasklet(unsigned long dev); -static int ifb_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev); static int ifb_open(struct net_device *dev); static int ifb_close(struct net_device *dev); @@ -160,11 +160,10 @@ static void ifb_setup(struct net_device *dev) random_ether_addr(dev->dev_addr); } -static int ifb_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev) { struct ifb_private *dp = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; - int ret = NETDEV_TX_OK; u32 from = G_TC_FROM(skb->tc_verd); stats->rx_packets++; @@ -173,7 +172,7 @@ static int ifb_xmit(struct sk_buff *skb, struct net_device *dev) if (!(from & (AT_INGRESS|AT_EGRESS)) || !skb->iif) { dev_kfree_skb(skb); stats->rx_dropped++; - return ret; + return NETDEV_TX_OK; } if (skb_queue_len(&dp->rq) >= dev->tx_queue_len) { @@ -187,7 +186,7 @@ static int ifb_xmit(struct sk_buff *skb, struct net_device *dev) tasklet_schedule(&dp->ifb_tasklet); } - return ret; + return NETDEV_TX_OK; } static int ifb_close(struct net_device *dev) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 99eed9f37c8..f893cd41580 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -184,7 +184,8 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) return NULL; } -static int macvlan_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, + struct net_device *dev) { const struct macvlan_dev *vlan = netdev_priv(dev); unsigned int len = skb->len; diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 35be2e8f0c9..9bf2a6be903 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -951,7 +951,7 @@ out: /* * Network interface unit routines. */ -static int +static netdev_tx_t ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ppp *ppp = netdev_priv(dev); diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 899c4a2112c..26f6ee93a06 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -474,7 +474,7 @@ out: /* Encapsulate an IP datagram and kick it into a TTY queue. */ -static int +static netdev_tx_t sl_xmit(struct sk_buff *skb, struct net_device *dev) { struct slip *sl = netdev_priv(dev); diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 2533f5cf2e4..5f7842e4d4a 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -358,7 +358,7 @@ static int tun_net_close(struct net_device *dev) } /* Net device start xmit */ -static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) { struct tun_struct *tun = netdev_priv(dev); diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 190f784c9cf..d1941cdff62 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -148,7 +148,7 @@ static struct ethtool_ops veth_ethtool_ops = { * xmit */ -static int veth_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_device *rcv = NULL; struct veth_priv *priv, *rcv_priv; diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index a6f903f0092..31279c4c02c 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -519,7 +519,7 @@ static void xmit_tasklet(unsigned long data) netif_tx_unlock_bh(vi->dev); } -static int start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) { struct virtnet_info *vi = netdev_priv(dev); -- cgit v1.2.3-18-g5258 From 3a27c149ab0e31a7b86e5ee6a27bb3b8b5687f32 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:52 +0000 Subject: uwb: convert to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h | 3 ++- drivers/uwb/i1480/i1480u-wlp/tx.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h b/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h index 3421d3339d7..2e31f536a34 100644 --- a/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h +++ b/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h @@ -267,7 +267,8 @@ extern void i1480u_sysfs_release(struct i1480u *); /* netdev interface */ extern int i1480u_open(struct net_device *); extern int i1480u_stop(struct net_device *); -extern int i1480u_hard_start_xmit(struct sk_buff *, struct net_device *); +extern netdev_tx_t i1480u_hard_start_xmit(struct sk_buff *, + struct net_device *); extern void i1480u_tx_timeout(struct net_device *); extern int i1480u_set_config(struct net_device *, struct ifmap *); extern int i1480u_change_mtu(struct net_device *, int); diff --git a/drivers/uwb/i1480/i1480u-wlp/tx.c b/drivers/uwb/i1480/i1480u-wlp/tx.c index 26bacc009c6..3db3449dbda 100644 --- a/drivers/uwb/i1480/i1480u-wlp/tx.c +++ b/drivers/uwb/i1480/i1480u-wlp/tx.c @@ -503,7 +503,8 @@ out: * * @net_dev->xmit_lock is held */ -int i1480u_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev) +netdev_tx_t i1480u_hard_start_xmit(struct sk_buff *skb, + struct net_device *net_dev) { int result; struct i1480u *i1480u = netdev_priv(net_dev); -- cgit v1.2.3-18-g5258 From ad096463f7ff809389454ea4219058a36564d55e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:53 +0000 Subject: tulip: convert drivers to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/tulip/de2104x.c | 3 ++- drivers/net/tulip/de4x5.c | 11 +++++------ drivers/net/tulip/dmfe.c | 5 +++-- drivers/net/tulip/tulip_core.c | 5 +++-- drivers/net/tulip/uli526x.c | 6 ++++-- drivers/net/tulip/winbond-840.c | 4 ++-- drivers/net/tulip/xircom_cb.c | 6 ++++-- 7 files changed, 23 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index bc8a6b263b4..74e5ba42d38 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -599,7 +599,8 @@ next: netif_wake_queue(de->dev); } -static int de_start_xmit (struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t de_start_xmit (struct sk_buff *skb, + struct net_device *dev) { struct de_private *de = netdev_priv(dev); unsigned int entry, tx_free; diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index acfdccd4456..a8349b7200b 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -895,7 +895,8 @@ static struct { ** Public Functions */ static int de4x5_open(struct net_device *dev); -static int de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t de4x5_queue_pkt(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t de4x5_interrupt(int irq, void *dev_id); static int de4x5_close(struct net_device *dev); static struct net_device_stats *de4x5_get_stats(struct net_device *dev); @@ -1456,18 +1457,16 @@ de4x5_sw_reset(struct net_device *dev) /* ** Writes a socket buffer address to the next available transmit descriptor. */ -static int +static netdev_tx_t de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev) { struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; - int status = NETDEV_TX_OK; u_long flags = 0; netif_stop_queue(dev); - if (!lp->tx_enable) { /* Cannot send for now */ + if (!lp->tx_enable) /* Cannot send for now */ return NETDEV_TX_LOCKED; - } /* ** Clean out the TX ring asynchronously to interrupts - sometimes the @@ -1521,7 +1520,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev) lp->cache.lock = 0; - return status; + return NETDEV_TX_OK; } /* diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index 5e15fab58c1..a45ded0538b 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -311,7 +311,7 @@ static u8 SF_mode; /* Special Function: 1:VLAN, 2:RX Flow Control /* function declaration ------------------------------------- */ static int dmfe_open(struct DEVICE *); -static int dmfe_start_xmit(struct sk_buff *, struct DEVICE *); +static netdev_tx_t dmfe_start_xmit(struct sk_buff *, struct DEVICE *); static int dmfe_stop(struct DEVICE *); static void dmfe_set_filter_mode(struct DEVICE *); static const struct ethtool_ops netdev_ethtool_ops; @@ -661,7 +661,8 @@ static void dmfe_init_dm910x(struct DEVICE *dev) * Send a packet to media from the upper layer. */ -static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) +static netdev_tx_t dmfe_start_xmit(struct sk_buff *skb, + struct DEVICE *dev) { struct dmfe_board_info *db = netdev_priv(dev); struct tx_desc *txptr; diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 019050f273a..2a01f0e421a 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -256,7 +256,8 @@ const char tulip_media_cap[32] = static void tulip_tx_timeout(struct net_device *dev); static void tulip_init_ring(struct net_device *dev); static void tulip_free_ring(struct net_device *dev); -static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t tulip_start_xmit(struct sk_buff *skb, + struct net_device *dev); static int tulip_open(struct net_device *dev); static int tulip_close(struct net_device *dev); static void tulip_up(struct net_device *dev); @@ -645,7 +646,7 @@ static void tulip_init_ring(struct net_device *dev) tp->tx_ring[i-1].buffer2 = cpu_to_le32(tp->tx_ring_dma); } -static int +static netdev_tx_t tulip_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct tulip_private *tp = netdev_priv(dev); diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index 9074a34eb81..c457a0ca55a 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -215,7 +215,8 @@ static int mode = 8; /* function declaration ------------------------------------- */ static int uli526x_open(struct net_device *); -static int uli526x_start_xmit(struct sk_buff *, struct net_device *); +static netdev_tx_t uli526x_start_xmit(struct sk_buff *, + struct net_device *); static int uli526x_stop(struct net_device *); static void uli526x_set_filter_mode(struct net_device *); static const struct ethtool_ops netdev_ethtool_ops; @@ -567,7 +568,8 @@ static void uli526x_init(struct net_device *dev) * Send a packet to media from the upper layer. */ -static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t uli526x_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct uli526x_board_info *db = netdev_priv(dev); struct tx_desc *txptr; diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 1853530a32a..3e59397e538 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -333,7 +333,7 @@ static void init_registers(struct net_device *dev); static void tx_timeout(struct net_device *dev); static int alloc_ringdesc(struct net_device *dev); static void free_ringdesc(struct netdev_private *np); -static int start_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t intr_handler(int irq, void *dev_instance); static void netdev_error(struct net_device *dev, int intr_status); static int netdev_rx(struct net_device *dev); @@ -997,7 +997,7 @@ static void free_ringdesc(struct netdev_private *np) } -static int start_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); unsigned entry; diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index 22b6a239fb3..0f2ca5980c3 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -113,7 +113,8 @@ struct xircom_private { static int xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id); static void xircom_remove(struct pci_dev *pdev); static irqreturn_t xircom_interrupt(int irq, void *dev_instance); -static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t xircom_start_xmit(struct sk_buff *skb, + struct net_device *dev); static int xircom_open(struct net_device *dev); static int xircom_close(struct net_device *dev); static void xircom_up(struct xircom_private *card); @@ -384,7 +385,8 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance) return IRQ_HANDLED; } -static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t xircom_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct xircom_private *card; unsigned long flags; -- cgit v1.2.3-18-g5258 From 27a1de95a1461ec0589005c293d6ac23a46cb72d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:54 +0000 Subject: 3com: convert drivers to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/3c501.c | 2 +- drivers/net/3c501.h | 2 +- drivers/net/3c505.c | 4 ++-- drivers/net/3c507.c | 6 ++++-- drivers/net/3c509.c | 4 ++-- drivers/net/3c515.c | 8 ++++---- drivers/net/3c523.c | 4 ++-- drivers/net/3c527.c | 6 ++++-- drivers/net/3c59x.c | 10 ++++++---- 9 files changed, 26 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index e29fb1a4a61..f60309175ef 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -409,7 +409,7 @@ static void el_timeout(struct net_device *dev) * no real choice. */ -static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t el_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; diff --git a/drivers/net/3c501.h b/drivers/net/3c501.h index f40b0493337..183fd55f03c 100644 --- a/drivers/net/3c501.h +++ b/drivers/net/3c501.h @@ -6,7 +6,7 @@ static int el1_probe1(struct net_device *dev, int ioaddr); static int el_open(struct net_device *dev); static void el_timeout(struct net_device *dev); -static int el_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t el_start_xmit(struct sk_buff *skb, struct net_device *dev); static irqreturn_t el_interrupt(int irq, void *dev_id); static void el_receive(struct net_device *dev); static void el_reset(struct net_device *dev); diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index 7bba480d722..a21c9d15ef8 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -976,7 +976,7 @@ static int elp_open(struct net_device *dev) * ******************************************************/ -static bool send_packet(struct net_device *dev, struct sk_buff *skb) +static netdev_tx_t send_packet(struct net_device *dev, struct sk_buff *skb) { elp_device *adapter = netdev_priv(dev); unsigned long target; @@ -1067,7 +1067,7 @@ static void elp_timeout(struct net_device *dev) * ******************************************************/ -static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t elp_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned long flags; elp_device *adapter = netdev_priv(dev); diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index 9e93a0b39b6..a6dc8bcbc7d 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -284,7 +284,8 @@ static unsigned short init_words[] = { static int el16_probe1(struct net_device *dev, int ioaddr); static int el16_open(struct net_device *dev); -static int el16_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t el16_send_packet(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t el16_interrupt(int irq, void *dev_id); static void el16_rx(struct net_device *dev); static int el16_close(struct net_device *dev); @@ -509,7 +510,8 @@ static void el16_tx_timeout (struct net_device *dev) } -static int el16_send_packet (struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t el16_send_packet (struct sk_buff *skb, + struct net_device *dev) { struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index d2515d840c0..3b00a4e927a 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -191,7 +191,7 @@ static void el3_common_remove(struct net_device *dev); static ushort id_read_eeprom(int index); static ushort read_eeprom(int ioaddr, int index); static int el3_open(struct net_device *dev); -static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t el3_start_xmit(struct sk_buff *skb, struct net_device *dev); static irqreturn_t el3_interrupt(int irq, void *dev_id); static void update_stats(struct net_device *dev); static struct net_device_stats *el3_get_stats(struct net_device *dev); @@ -816,7 +816,7 @@ el3_tx_timeout (struct net_device *dev) } -static int +static netdev_tx_t el3_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct el3_private *lp = netdev_priv(dev); diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 3116410b349..4adcb950f5f 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -369,8 +369,8 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, struct pnp_dev *idev, int card_number); static int corkscrew_open(struct net_device *dev); static void corkscrew_timer(unsigned long arg); -static int corkscrew_start_xmit(struct sk_buff *skb, - struct net_device *dev); +static netdev_tx_t corkscrew_start_xmit(struct sk_buff *skb, + struct net_device *dev); static int corkscrew_rx(struct net_device *dev); static void corkscrew_timeout(struct net_device *dev); static int boomerang_rx(struct net_device *dev); @@ -998,8 +998,8 @@ static void corkscrew_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int corkscrew_start_xmit(struct sk_buff *skb, - struct net_device *dev) +static netdev_tx_t corkscrew_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct corkscrew_private *vp = netdev_priv(dev); int ioaddr = dev->base_addr; diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index 70c701b80d9..cb0b730799b 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -183,7 +183,7 @@ sizeof(nop_cmd) = 8; static irqreturn_t elmc_interrupt(int irq, void *dev_id); static int elmc_open(struct net_device *dev); static int elmc_close(struct net_device *dev); -static int elmc_send_packet(struct sk_buff *, struct net_device *); +static netdev_tx_t elmc_send_packet(struct sk_buff *, struct net_device *); static struct net_device_stats *elmc_get_stats(struct net_device *dev); static void elmc_timeout(struct net_device *dev); #ifdef ELMC_MULTICAST @@ -1129,7 +1129,7 @@ static void elmc_timeout(struct net_device *dev) * send frame */ -static int elmc_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t elmc_send_packet(struct sk_buff *skb, struct net_device *dev) { int len; int i; diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index 72b9ed7f464..6021e6dded8 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -213,7 +213,8 @@ static int mc32_probe1(struct net_device *dev, int ioaddr); static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len); static int mc32_open(struct net_device *dev); static void mc32_timeout(struct net_device *dev); -static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t mc32_send_packet(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t mc32_interrupt(int irq, void *dev_id); static int mc32_close(struct net_device *dev); static struct net_device_stats *mc32_get_stats(struct net_device *dev); @@ -1020,7 +1021,8 @@ static void mc32_timeout(struct net_device *dev) * */ -static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t mc32_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct mc32_local *lp = netdev_priv(dev); u32 head = atomic_read(&lp->tx_ring_head); diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index beb040264db..7adff4d0960 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -716,8 +716,10 @@ static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *vp, int phy_id, int location, int value); static void vortex_timer(unsigned long arg); static void rx_oom_timer(unsigned long arg); -static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t vortex_start_xmit(struct sk_buff *skb, + struct net_device *dev); +static netdev_tx_t boomerang_start_xmit(struct sk_buff *skb, + struct net_device *dev); static int vortex_rx(struct net_device *dev); static int boomerang_rx(struct net_device *dev); static irqreturn_t vortex_interrupt(int irq, void *dev_id); @@ -2035,7 +2037,7 @@ vortex_error(struct net_device *dev, int status) } } -static int +static netdev_tx_t vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct vortex_private *vp = netdev_priv(dev); @@ -2090,7 +2092,7 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } -static int +static netdev_tx_t boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct vortex_private *vp = netdev_priv(dev); -- cgit v1.2.3-18-g5258 From 3b29a56d31d585d39bf9ffe9ef1f10bd637ee0f1 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:55 +0000 Subject: intel: convert drivers to netdev_tx_t Get rid of some bogus return wrapping as well. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/e100.c | 3 ++- drivers/net/e1000/e1000_main.c | 6 ++++-- drivers/net/e1000e/netdev.c | 3 ++- drivers/net/igb/igb_main.c | 19 +++++++++++-------- drivers/net/igbvf/netdev.c | 14 ++++++-------- drivers/net/ixgb/ixgb_main.c | 5 +++-- drivers/net/ixgbe/ixgbe_main.c | 3 ++- 7 files changed, 30 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 569df19f0df..6a3176042c4 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1690,7 +1690,8 @@ static void e100_xmit_prepare(struct nic *nic, struct cb *cb, cb->u.tcb.tbd.size = cpu_to_le16(skb->len); } -static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t e100_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) { struct nic *nic = netdev_priv(netdev); int err; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index d7df00c2dbd..b3063e60be6 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -125,7 +125,8 @@ static void e1000_set_rx_mode(struct net_device *netdev); static void e1000_update_phy_info(unsigned long data); static void e1000_watchdog(unsigned long data); static void e1000_82547_tx_fifo_stall(unsigned long data); -static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev); +static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, + struct net_device *netdev); static struct net_device_stats * e1000_get_stats(struct net_device *netdev); static int e1000_change_mtu(struct net_device *netdev, int new_mtu); static int e1000_set_mac(struct net_device *netdev, void *p); @@ -3249,7 +3250,8 @@ static int e1000_maybe_stop_tx(struct net_device *netdev, } #define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 ) -static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 63415bb6f48..428bf6d72f3 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -4097,7 +4097,8 @@ static int e1000_maybe_stop_tx(struct net_device *netdev, int size) } #define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 ) -static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_ring *tx_ring = adapter->tx_ring; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index cef4289d571..7a054d99bff 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -98,9 +98,11 @@ static void igb_set_multi(struct net_device *); static void igb_update_phy_info(unsigned long); static void igb_watchdog(unsigned long); static void igb_watchdog_task(struct work_struct *); -static int igb_xmit_frame_ring_adv(struct sk_buff *, struct net_device *, - struct igb_ring *); -static int igb_xmit_frame_adv(struct sk_buff *skb, struct net_device *); +static netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *, + struct net_device *, + struct igb_ring *); +static netdev_tx_t igb_xmit_frame_adv(struct sk_buff *skb, + struct net_device *); static struct net_device_stats *igb_get_stats(struct net_device *); static int igb_change_mtu(struct net_device *, int); static int igb_set_mac(struct net_device *, void *); @@ -3295,9 +3297,9 @@ static int igb_maybe_stop_tx(struct net_device *netdev, return __igb_maybe_stop_tx(netdev, tx_ring, size); } -static int igb_xmit_frame_ring_adv(struct sk_buff *skb, - struct net_device *netdev, - struct igb_ring *tx_ring) +static netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *skb, + struct net_device *netdev, + struct igb_ring *tx_ring) { struct igb_adapter *adapter = netdev_priv(netdev); unsigned int first; @@ -3385,7 +3387,8 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, return NETDEV_TX_OK; } -static int igb_xmit_frame_adv(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t igb_xmit_frame_adv(struct sk_buff *skb, + struct net_device *netdev) { struct igb_adapter *adapter = netdev_priv(netdev); struct igb_ring *tx_ring; @@ -3398,7 +3401,7 @@ static int igb_xmit_frame_adv(struct sk_buff *skb, struct net_device *netdev) * to a flow. Right now, performance is impacted slightly negatively * if using multiple tx queues. If the stack breaks away from a * single qdisc implementation, we can look at this again. */ - return (igb_xmit_frame_ring_adv(skb, netdev, tx_ring)); + return igb_xmit_frame_ring_adv(skb, netdev, tx_ring); } /** diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index 3f03c42ece9..dadb78229ad 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -2204,9 +2204,9 @@ static inline void igbvf_tx_queue_adv(struct igbvf_adapter *adapter, mmiowb(); } -static int igbvf_xmit_frame_ring_adv(struct sk_buff *skb, - struct net_device *netdev, - struct igbvf_ring *tx_ring) +static netdev_tx_t igbvf_xmit_frame_ring_adv(struct sk_buff *skb, + struct net_device *netdev, + struct igbvf_ring *tx_ring) { struct igbvf_adapter *adapter = netdev_priv(netdev); unsigned int first, tx_flags = 0; @@ -2279,11 +2279,11 @@ static int igbvf_xmit_frame_ring_adv(struct sk_buff *skb, return NETDEV_TX_OK; } -static int igbvf_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t igbvf_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) { struct igbvf_adapter *adapter = netdev_priv(netdev); struct igbvf_ring *tx_ring; - int retval; if (test_bit(__IGBVF_DOWN, &adapter->state)) { dev_kfree_skb_any(skb); @@ -2292,9 +2292,7 @@ static int igbvf_xmit_frame(struct sk_buff *skb, struct net_device *netdev) tx_ring = &adapter->tx_ring[0]; - retval = igbvf_xmit_frame_ring_adv(skb, netdev, tx_ring); - - return retval; + return igbvf_xmit_frame_ring_adv(skb, netdev, tx_ring); } /** diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index fad08ce8a6c..8aa44dca57e 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -81,7 +81,8 @@ static void ixgb_clean_tx_ring(struct ixgb_adapter *adapter); static void ixgb_clean_rx_ring(struct ixgb_adapter *adapter); static void ixgb_set_multi(struct net_device *netdev); static void ixgb_watchdog(unsigned long data); -static int ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev); +static netdev_tx_t ixgb_xmit_frame(struct sk_buff *skb, + struct net_device *netdev); static struct net_device_stats *ixgb_get_stats(struct net_device *netdev); static int ixgb_change_mtu(struct net_device *netdev, int new_mtu); static int ixgb_set_mac(struct net_device *netdev, void *p); @@ -1442,7 +1443,7 @@ static int ixgb_maybe_stop_tx(struct net_device *netdev, MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1 /* for context */ \ + 1 /* one more needed for sentinel TSO workaround */ -static int +static netdev_tx_t ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct ixgb_adapter *adapter = netdev_priv(netdev); diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 0bea096e964..7e964a68988 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -5107,7 +5107,8 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb) return skb_tx_hash(dev, skb); } -static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_ring *tx_ring; -- cgit v1.2.3-18-g5258 From 0fc480987e69f22b9212f087545b4d1ca6950807 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:56 +0000 Subject: appletalk: convert drivers to netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/appletalk/cops.c | 6 ++++-- drivers/net/appletalk/ipddp.c | 5 +++-- drivers/net/appletalk/ltpc.c | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index 29b279f88ef..b5dc7f55072 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -192,7 +192,8 @@ static irqreturn_t cops_interrupt (int irq, void *dev_id); static void cops_poll (unsigned long ltdev); static void cops_timeout(struct net_device *dev); static void cops_rx (struct net_device *dev); -static int cops_send_packet (struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t cops_send_packet (struct sk_buff *skb, + struct net_device *dev); static void set_multicast_list (struct net_device *dev); static int cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); static int cops_close (struct net_device *dev); @@ -875,7 +876,8 @@ static void cops_timeout(struct net_device *dev) * Make the card transmit a LocalTalk packet. */ -static int cops_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t cops_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct cops_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index 6cfd961bb8d..bea87da97e3 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -48,7 +48,8 @@ static int ipddp_mode = IPDDP_DECAP; #endif /* Index to functions, as function prototypes. */ -static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ipddp_xmit(struct sk_buff *skb, + struct net_device *dev); static int ipddp_create(struct ipddp_route *new_rt); static int ipddp_delete(struct ipddp_route *rt); static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt); @@ -113,7 +114,7 @@ static struct net_device * __init ipddp_init(void) /* * Transmit LLAP/ELAP frame using aarp_send_ddp. */ -static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ipddp_xmit(struct sk_buff *skb, struct net_device *dev) { __be32 paddr = skb_rtable(skb)->rt_gateway; struct ddpehdr *ddp; diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index c80fb9cf8ff..08760baece7 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -697,7 +697,7 @@ static int do_read(struct net_device *dev, void *cbuf, int cbuflen, static struct timer_list ltpc_timer; -static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ltpc_xmit(struct sk_buff *skb, struct net_device *dev); static int read_30 ( struct net_device *dev) { @@ -895,7 +895,7 @@ static void ltpc_poll(unsigned long l) /* DDP to LLAP translation */ -static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ltpc_xmit(struct sk_buff *skb, struct net_device *dev) { /* in kernel 1.3.xx, on entry skb->data points to ddp header, * and skb->len is the length of the ddp data + ddp header -- cgit v1.2.3-18-g5258 From d0cf9c0dadcdc89a755bcb301cfc9c796eb28ccf Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:57 +0000 Subject: wireless: convert drivers to netdev_tx_t Mostly just simple conversions: * ray_cs had bogus return of NET_TX_LOCKED but driver was not using NETIF_F_LLTX * hostap and ipw2x00 had some code that returned value from a called function that also had to change to return netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/wimax/i2400m/netdev.c | 12 ++++++------ drivers/net/wireless/airo.c | 12 +++++++++--- drivers/net/wireless/arlan-main.c | 4 ++-- drivers/net/wireless/atmel.c | 2 +- drivers/net/wireless/hostap/hostap_80211.h | 10 +++++++--- drivers/net/wireless/hostap/hostap_80211_tx.c | 11 +++++++---- drivers/net/wireless/ipw2x00/ipw2100.c | 10 +++++----- drivers/net/wireless/ipw2x00/ipw2200.c | 9 +++++---- drivers/net/wireless/ipw2x00/libipw.h | 7 ++++--- drivers/net/wireless/ipw2x00/libipw_tx.c | 6 +++--- drivers/net/wireless/libertas/decl.h | 5 +++-- drivers/net/wireless/libertas/main.c | 3 ++- drivers/net/wireless/libertas/tx.c | 6 ++---- drivers/net/wireless/mac80211_hwsim.c | 3 ++- drivers/net/wireless/netwave_cs.c | 6 ++++-- drivers/net/wireless/orinoco/main.c | 2 +- drivers/net/wireless/prism54/islpci_eth.c | 2 +- drivers/net/wireless/prism54/islpci_eth.h | 2 +- drivers/net/wireless/ray_cs.c | 14 +++++++++----- drivers/net/wireless/strip.c | 2 +- drivers/net/wireless/wavelan.c | 3 ++- drivers/net/wireless/wavelan.p.h | 2 +- drivers/net/wireless/wavelan_cs.c | 2 +- drivers/net/wireless/wavelan_cs.p.h | 2 +- drivers/net/wireless/wl3501_cs.c | 3 ++- drivers/net/wireless/zd1201.c | 3 ++- 26 files changed, 84 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c index 9653f478b38..796396cb4c8 100644 --- a/drivers/net/wimax/i2400m/netdev.c +++ b/drivers/net/wimax/i2400m/netdev.c @@ -334,12 +334,12 @@ int i2400m_net_tx(struct i2400m *i2400m, struct net_device *net_dev, * that will sleep. See i2400m_net_wake_tx() for details. */ static -int i2400m_hard_start_xmit(struct sk_buff *skb, - struct net_device *net_dev) +netdev_tx_t i2400m_hard_start_xmit(struct sk_buff *skb, + struct net_device *net_dev) { - int result; struct i2400m *i2400m = net_dev_to_i2400m(net_dev); struct device *dev = i2400m_dev(i2400m); + int result; d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev); if (i2400m->state == I2400M_SS_IDLE) @@ -353,9 +353,9 @@ int i2400m_hard_start_xmit(struct sk_buff *skb, net_dev->stats.tx_bytes += skb->len; } kfree_skb(skb); - result = NETDEV_TX_OK; - d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result); - return result; + + d_fnend(3, dev, "(skb %p net_dev %p)\n", skb, net_dev); + return NETDEV_TX_OK; } diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index c150c485857..7116a1aa20c 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -1920,7 +1920,9 @@ static int airo_open(struct net_device *dev) { return 0; } -static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { +static netdev_tx_t mpi_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ int npacks, pending; unsigned long flags; struct airo_info *ai = dev->ml_priv; @@ -2119,7 +2121,9 @@ static void airo_end_xmit(struct net_device *dev) { dev_kfree_skb(skb); } -static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { +static netdev_tx_t airo_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ s16 len; int i, j; struct airo_info *priv = dev->ml_priv; @@ -2184,7 +2188,9 @@ static void airo_end_xmit11(struct net_device *dev) { dev_kfree_skb(skb); } -static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { +static netdev_tx_t airo_start_xmit11(struct sk_buff *skb, + struct net_device *dev) +{ s16 len; int i, j; struct airo_info *priv = dev->ml_priv; diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index f96c634e2d3..921a082487a 100644 --- a/drivers/net/wireless/arlan-main.c +++ b/drivers/net/wireless/arlan-main.c @@ -77,7 +77,7 @@ struct arlan_conf_stru arlan_conf[MAX_ARLANS]; static int arlans_found; static int arlan_open(struct net_device *dev); -static int arlan_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t arlan_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t arlan_interrupt(int irq, void *dev_id); static int arlan_close(struct net_device *dev); static struct net_device_stats * @@ -1169,7 +1169,7 @@ static void arlan_tx_timeout (struct net_device *dev) } -static int arlan_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t arlan_tx(struct sk_buff *skb, struct net_device *dev) { short length; unsigned char *buf; diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 05813bc3e30..a3b36b3a9d6 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -781,7 +781,7 @@ static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, priv->tx_free_mem -= len; } -static int start_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) { static const u8 SNAP_RFC1024[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; struct atmel_private *priv = netdev_priv(dev); diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h index 2e9fb0f383f..7f9d8d976aa 100644 --- a/drivers/net/wireless/hostap/hostap_80211.h +++ b/drivers/net/wireless/hostap/hostap_80211.h @@ -3,6 +3,7 @@ #include #include +#include struct hostap_ieee80211_mgmt { __le16 frame_control; @@ -85,8 +86,11 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats); void hostap_dump_tx_80211(const char *name, struct sk_buff *skb); -int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev); -int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev); -int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev); +netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb, + struct net_device *dev); +netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb, + struct net_device *dev); +netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb, + struct net_device *dev); #endif /* HOSTAP_80211_H */ diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index 1fe1bbabb90..90108b698f1 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -53,7 +53,8 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) /* hard_start_xmit function for data interfaces (wlan#, wlan#wds#, wlan#sta) * Convert Ethernet header into a suitable IEEE 802.11 header depending on * device configuration. */ -int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct hostap_interface *iface; local_info_t *local; @@ -261,7 +262,8 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) /* hard_start_xmit function for hostapd wlan#ap interfaces */ -int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct hostap_interface *iface; local_info_t *local; @@ -373,11 +375,12 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, /* hard_start_xmit function for master radio interface wifi#. * AP processing (TX rate control, power save buffering, etc.). * Use hardware TX function to send the frame. */ -int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct hostap_interface *iface; local_info_t *local; - int ret = NETDEV_TX_BUSY; + netdev_tx_t ret = NETDEV_TX_BUSY; u16 fc; struct hostap_tx_data tx; ap_tx_ret tx_ret; diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 77457386e0a..240cff1e697 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -3330,8 +3330,8 @@ static irqreturn_t ipw2100_interrupt(int irq, void *data) return IRQ_NONE; } -static int ipw2100_tx(struct libipw_txb *txb, struct net_device *dev, - int pri) +static netdev_tx_t ipw2100_tx(struct libipw_txb *txb, + struct net_device *dev, int pri) { struct ipw2100_priv *priv = libipw_priv(dev); struct list_head *element; @@ -3369,12 +3369,12 @@ static int ipw2100_tx(struct libipw_txb *txb, struct net_device *dev, ipw2100_tx_send_data(priv); spin_unlock_irqrestore(&priv->low_lock, flags); - return 0; + return NETDEV_TX_OK; - fail_unlock: +fail_unlock: netif_stop_queue(dev); spin_unlock_irqrestore(&priv->low_lock, flags); - return 1; + return NETDEV_TX_BUSY; } static int ipw2100_msg_allocate(struct ipw2100_priv *priv) diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 3f8372daf46..3838f9f9a47 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -10459,12 +10459,12 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, } #endif -static int ipw_net_hard_start_xmit(struct libipw_txb *txb, - struct net_device *dev, int pri) +static netdev_tx_t ipw_net_hard_start_xmit(struct libipw_txb *txb, + struct net_device *dev, int pri) { struct ipw_priv *priv = libipw_priv(dev); unsigned long flags; - int ret; + netdev_tx_t ret; IPW_DEBUG_TX("dev->xmit(%d bytes)\n", txb->payload_size); spin_lock_irqsave(&priv->lock, flags); @@ -11602,7 +11602,8 @@ static int ipw_prom_stop(struct net_device *dev) return 0; } -static int ipw_prom_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ipw_prom_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) { IPW_DEBUG_INFO("prom dev->xmit\n"); dev_kfree_skb(skb); diff --git a/drivers/net/wireless/ipw2x00/libipw.h b/drivers/net/wireless/ipw2x00/libipw.h index 8f91d3427ce..bf45391172f 100644 --- a/drivers/net/wireless/ipw2x00/libipw.h +++ b/drivers/net/wireless/ipw2x00/libipw.h @@ -867,8 +867,8 @@ struct libipw_device { /* Callback functions */ void (*set_security) (struct net_device * dev, struct libipw_security * sec); - int (*hard_start_xmit) (struct libipw_txb * txb, - struct net_device * dev, int pri); + netdev_tx_t (*hard_start_xmit) (struct libipw_txb * txb, + struct net_device * dev, int pri); int (*reset_port) (struct net_device * dev); int (*is_queue_full) (struct net_device * dev, int pri); @@ -1028,7 +1028,8 @@ extern void libipw_networks_age(struct libipw_device *ieee, extern int libipw_set_encryption(struct libipw_device *ieee); /* libipw_tx.c */ -extern int libipw_xmit(struct sk_buff *skb, struct net_device *dev); +extern netdev_tx_t libipw_xmit(struct sk_buff *skb, + struct net_device *dev); extern void libipw_txb_free(struct libipw_txb *); /* libipw_rx.c */ diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c index 46530ce56ea..da8beac7fcf 100644 --- a/drivers/net/wireless/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/ipw2x00/libipw_tx.c @@ -252,7 +252,7 @@ static int libipw_classify(struct sk_buff *skb) /* Incoming skb is converted to a txb which consists of * a block of 802.11 fragment packets (stored as skbs) */ -int libipw_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev) { struct libipw_device *ieee = netdev_priv(dev); struct libipw_txb *txb = NULL; @@ -523,8 +523,8 @@ int libipw_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb_any(skb); if (txb) { - int ret = (*ieee->hard_start_xmit) (txb, dev, priority); - if (ret == 0) { + netdev_tx_t ret = (*ieee->hard_start_xmit)(txb, dev, priority); + if (ret == NETDEV_TX_OK) { dev->stats.tx_packets++; dev->stats.tx_bytes += txb->payload_size; return NETDEV_TX_OK; diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 0b84bdca072..8b15380ae6e 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -6,7 +6,7 @@ #ifndef _LBS_DECL_H_ #define _LBS_DECL_H_ -#include +#include #include "defs.h" @@ -41,7 +41,8 @@ u8 lbs_data_rate_to_fw_index(u32 rate); int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len); void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd, int result); -int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); +netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev); int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band); int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 8df1cfd5f93..87b4e497faa 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1647,7 +1647,8 @@ static int lbs_rtap_stop(struct net_device *dev) return 0; } -static int lbs_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t lbs_rtap_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) { netif_stop_queue(dev); return NETDEV_TX_BUSY; diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index 160cfd8311c..4c018f7a0a8 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -57,19 +57,17 @@ static u32 convert_radiotap_rate_to_mv(u8 rate) * @param skb A pointer to skb which includes TX packet * @return 0 or -1 */ -int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned long flags; struct lbs_private *priv = dev->ml_priv; struct txpd *txpd; char *p802x_hdr; uint16_t pkt_len; - int ret; + netdev_tx_t ret = NETDEV_TX_OK; lbs_deb_enter(LBS_DEB_TX); - ret = NETDEV_TX_OK; - /* We need to protect against the queues being restarted before we get round to stopping them */ spin_lock_irqsave(&priv->driver_lock, flags); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 6f6cd43592c..896f532182f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -312,7 +312,8 @@ struct hwsim_radiotap_hdr { } __attribute__ ((packed)); -static int hwsim_mon_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb, + struct net_device *dev) { /* TODO: allow packet injection */ dev_kfree_skb(skb); diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index 712f26eef35..9498b46c99a 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -203,7 +203,8 @@ static int netwave_open(struct net_device *dev); /* Open the device */ static int netwave_close(struct net_device *dev); /* Close the device */ /* Packet transmission and Packet reception */ -static int netwave_start_xmit( struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t netwave_start_xmit( struct sk_buff *skb, + struct net_device *dev); static int netwave_rx( struct net_device *dev); /* Interrupt routines */ @@ -1026,7 +1027,8 @@ static int netwave_hw_xmit(unsigned char* data, int len, return 0; } -static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) { +static netdev_tx_t netwave_start_xmit(struct sk_buff *skb, + struct net_device *dev) { /* This flag indicate that the hardware can't perform a transmission. * Theoritically, NET3 check it before sending a packet to the driver, * but in fact it never do that and pool continuously. diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 2c7dc65cd2b..7a32bcb0c03 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -337,7 +337,7 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu) /* Tx path */ /********************************************************************/ -static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev) { struct orinoco_private *priv = ndev_priv(dev); struct net_device_stats *stats = &priv->stats; diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index 9b5ee341928..872b64783e7 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -72,7 +72,7 @@ islpci_eth_cleanup_transmit(islpci_private *priv, } } -int +netdev_tx_t islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) { islpci_private *priv = netdev_priv(ndev); diff --git a/drivers/net/wireless/prism54/islpci_eth.h b/drivers/net/wireless/prism54/islpci_eth.h index 61454d32d74..54f9a4b7bf9 100644 --- a/drivers/net/wireless/prism54/islpci_eth.h +++ b/drivers/net/wireless/prism54/islpci_eth.h @@ -64,7 +64,7 @@ struct avs_80211_1_header { }; void islpci_eth_cleanup_transmit(islpci_private *, isl38xx_control_block *); -int islpci_eth_transmit(struct sk_buff *, struct net_device *); +netdev_tx_t islpci_eth_transmit(struct sk_buff *, struct net_device *); int islpci_eth_receive(islpci_private *); void islpci_eth_tx_timeout(struct net_device *); void islpci_do_reset_and_wake(struct work_struct *); diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 325206969c9..88cd58eb3b9 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -104,7 +104,8 @@ static int ray_dev_init(struct net_device *dev); static const struct ethtool_ops netdev_ethtool_ops; static int ray_open(struct net_device *dev); -static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb, + struct net_device *dev); static void set_multicast_list(struct net_device *dev); static void ray_update_multi_list(struct net_device *dev, int all); static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, @@ -915,16 +916,19 @@ static int ray_dev_config(struct net_device *dev, struct ifmap *map) } /*===========================================================================*/ -static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb, + struct net_device *dev) { ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link = local->finder; short length = skb->len; - if (!(pcmcia_dev_present(link))) { + if (!pcmcia_dev_present(link)) { DEBUG(2, "ray_dev_start_xmit - device not present\n"); - return NETDEV_TX_LOCKED; + dev_kfree_skb(skb); + return NETDEV_TX_OK; } + DEBUG(3, "ray_dev_start_xmit(skb=%p, dev=%p)\n", skb, dev); if (local->authentication_state == NEED_TO_AUTH) { DEBUG(0, "ray_cs Sending authentication request.\n"); @@ -951,8 +955,8 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) default: dev->trans_start = jiffies; dev_kfree_skb(skb); - return NETDEV_TX_OK; } + return NETDEV_TX_OK; } /* ray_dev_start_xmit */ diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index ef2cb20e96a..ea6a87c1931 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -1533,7 +1533,7 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb) } /* Encapsulate a datagram and kick it into a TTY queue. */ -static int strip_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t strip_xmit(struct sk_buff *skb, struct net_device *dev) { struct strip *strip_info = netdev_priv(dev); diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index 5cb5329a20d..d634b2da3b8 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -2841,7 +2841,8 @@ static int wv_packet_write(struct net_device * dev, void *buf, short length) * the packet. We also prevent reentrance. Then we call the function * to send the packet. */ -static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) +static netdev_tx_t wavelan_packet_xmit(struct sk_buff *skb, + struct net_device * dev) { net_local *lp = netdev_priv(dev); unsigned long flags; diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h index 2daa0210d78..dbe8de6e5f5 100644 --- a/drivers/net/wireless/wavelan.p.h +++ b/drivers/net/wireless/wavelan.p.h @@ -611,7 +611,7 @@ static inline int wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer. */ void *, short); -static int +static netdev_tx_t wavelan_packet_xmit(struct sk_buff *, /* Send a packet. */ struct net_device *); /* -------------------- HARDWARE CONFIGURATION -------------------- */ diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index b9748d43201..431a20ec6db 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -3078,7 +3078,7 @@ wv_packet_write(struct net_device * dev, * the packet. We also prevent reentrance. Then, we call the function * to send the packet... */ -static int +static netdev_tx_t wavelan_packet_xmit(struct sk_buff * skb, struct net_device * dev) { diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h index 706fd3007d2..81d91531c4f 100644 --- a/drivers/net/wireless/wavelan_cs.p.h +++ b/drivers/net/wireless/wavelan_cs.p.h @@ -707,7 +707,7 @@ static void wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer */ void *, short); -static int +static netdev_tx_t wavelan_packet_xmit(struct sk_buff *, /* Send a packet */ struct net_device *); /* -------------------- HARDWARE CONFIGURATION -------------------- */ diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index a83a5621ec4..4f1e0cfe609 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1333,7 +1333,8 @@ static void wl3501_tx_timeout(struct net_device *dev) * 1 - Could not transmit (dev_queue_xmit will queue it) * and try to sent it later */ -static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t wl3501_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) { int enabled, rc; struct wl3501_card *this = netdev_priv(dev); diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index dae1bfb7655..bc81974a2bc 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -779,7 +779,8 @@ static int zd1201_net_stop(struct net_device *dev) (llc+snap+type+payload) zd 1 null byte, zd1201 packet type */ -static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t zd1201_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct zd1201 *zd = netdev_priv(dev); unsigned char *txbuf = zd->txdata; -- cgit v1.2.3-18-g5258 From 61357325f377889a1daffa14962d705dc814dd0e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:58 +0000 Subject: netdev: convert bulk of drivers to netdev_tx_t In a couple of cases collapse some extra code like: int retval = NETDEV_TX_OK; ... return retval; into return NETDEV_TX_OK; Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/ieee802154/fakehard.c | 3 ++- drivers/net/8139cp.c | 3 ++- drivers/net/8139too.c | 7 ++++--- drivers/net/82596.c | 5 ++--- drivers/net/8390.c | 2 +- drivers/net/8390.h | 4 ++-- drivers/net/8390p.c | 2 +- drivers/net/a2065.c | 3 ++- drivers/net/acenic.c | 3 ++- drivers/net/acenic.h | 3 ++- drivers/net/amd8111e.c | 3 ++- drivers/net/arcnet/arcnet.c | 3 ++- drivers/net/ariadne.c | 6 ++++-- drivers/net/at1700.c | 6 ++++-- drivers/net/atl1c/atl1c_main.c | 3 ++- drivers/net/atl1e/atl1e_main.c | 3 ++- drivers/net/atlx/atl1.c | 3 ++- drivers/net/atlx/atl2.c | 3 ++- drivers/net/atp.c | 6 ++++-- drivers/net/au1000_eth.c | 2 +- drivers/net/b44.c | 2 +- drivers/net/benet/be_main.c | 3 ++- drivers/net/bnx2.c | 2 +- drivers/net/bnx2x_main.c | 2 +- drivers/net/can/sja1000/sja1000.c | 3 ++- drivers/net/cassini.c | 2 +- drivers/net/chelsio/sge.c | 2 +- drivers/net/chelsio/sge.h | 2 +- drivers/net/cs89x0.c | 4 ++-- drivers/net/cxgb3/adapter.h | 2 +- drivers/net/cxgb3/sge.c | 2 +- drivers/net/defxx.c | 10 ++++------ drivers/net/depca.c | 6 ++++-- drivers/net/dl2k.c | 4 ++-- drivers/net/dnet.c | 2 +- drivers/net/eepro.c | 6 ++++-- drivers/net/eexpress.c | 5 +++-- drivers/net/enc28j60.c | 3 ++- drivers/net/enic/enic_main.c | 3 ++- drivers/net/epic100.c | 5 +++-- drivers/net/eth16i.c | 4 ++-- drivers/net/ethoc.c | 2 +- drivers/net/ewrk3.c | 4 ++-- drivers/net/fealnx.c | 4 ++-- drivers/net/forcedeth.c | 5 +++-- drivers/net/hamachi.c | 6 ++++-- drivers/net/hp100.c | 13 ++++++++----- drivers/net/ibmlana.c | 2 +- drivers/net/ibmveth.c | 3 ++- drivers/net/ipg.c | 3 ++- drivers/net/jme.c | 2 +- drivers/net/ks8842.c | 3 ++- drivers/net/ks8851.c | 5 +++-- drivers/net/lance.c | 6 ++++-- drivers/net/lib8390.c | 3 ++- drivers/net/loopback.c | 3 ++- drivers/net/lp486e.c | 4 ++-- drivers/net/mlx4/en_tx.c | 2 +- drivers/net/mlx4/mlx4_en.h | 2 +- drivers/net/myri10ge/myri10ge.c | 11 +++++++---- drivers/net/natsemi.c | 4 ++-- drivers/net/netxen/netxen_nic_main.c | 5 +++-- drivers/net/ni52.c | 5 +++-- drivers/net/ni65.c | 6 ++++-- drivers/net/niu.c | 3 ++- drivers/net/ns83820.c | 3 ++- drivers/net/pcnet32.c | 6 ++++-- drivers/net/qla3xxx.c | 3 ++- drivers/net/qlge/qlge_main.c | 2 +- drivers/net/r6040.c | 10 +++++----- drivers/net/r8169.c | 12 ++++++------ drivers/net/rrunner.c | 3 ++- drivers/net/rrunner.h | 3 ++- drivers/net/s2io.c | 2 +- drivers/net/sb1000.c | 5 +++-- drivers/net/sc92031.c | 3 ++- drivers/net/seeq8005.c | 6 ++++-- drivers/net/sfc/efx.h | 5 +++-- drivers/net/sfc/selftest.c | 3 ++- drivers/net/sfc/tx.c | 18 ++++++++---------- drivers/net/sfc/tx.h | 3 ++- drivers/net/sis190.c | 3 ++- drivers/net/sis900.c | 5 +++-- drivers/net/skfp/skfddi.c | 6 ++++-- drivers/net/skge.c | 3 ++- drivers/net/sky2.c | 3 ++- drivers/net/smc9194.c | 6 ++++-- drivers/net/smsc9420.c | 3 ++- drivers/net/starfire.c | 4 ++-- drivers/net/sundance.c | 4 ++-- drivers/net/sungem.c | 3 ++- drivers/net/sunhme.c | 3 ++- drivers/net/tehuti.c | 3 ++- drivers/net/tg3.c | 9 ++++++--- drivers/net/tlan.c | 4 ++-- drivers/net/typhoon.c | 2 +- drivers/net/via-rhine.c | 6 ++++-- drivers/net/via-velocity.c | 3 ++- drivers/net/vxge/vxge-main.c | 2 +- drivers/net/yellowfin.c | 6 ++++-- drivers/net/znet.c | 5 +++-- 101 files changed, 251 insertions(+), 172 deletions(-) (limited to 'drivers') diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index c1c9697f9fd..96a2959ce87 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c @@ -257,7 +257,8 @@ static int ieee802154_fake_close(struct net_device *dev) return 0; } -static int ieee802154_fake_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ieee802154_fake_xmit(struct sk_buff *skb, + struct net_device *dev) { skb->iif = dev->ifindex; skb->dev = dev; diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 4a8995aaeca..462d9f59c53 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -736,7 +736,8 @@ static void cp_tx (struct cp_private *cp) netif_wake_queue(cp->dev); } -static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t cp_start_xmit (struct sk_buff *skb, + struct net_device *dev) { struct cp_private *cp = netdev_priv(dev); unsigned entry; diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index b39ec98345e..4a362875502 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -628,8 +628,8 @@ static void mdio_write (struct net_device *dev, int phy_id, int location, static void rtl8139_start_thread(struct rtl8139_private *tp); static void rtl8139_tx_timeout (struct net_device *dev); static void rtl8139_init_ring (struct net_device *dev); -static int rtl8139_start_xmit (struct sk_buff *skb, - struct net_device *dev); +static netdev_tx_t rtl8139_start_xmit (struct sk_buff *skb, + struct net_device *dev); #ifdef CONFIG_NET_POLL_CONTROLLER static void rtl8139_poll_controller(struct net_device *dev); #endif @@ -1687,7 +1687,8 @@ static void rtl8139_tx_timeout (struct net_device *dev) } } -static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t rtl8139_start_xmit (struct sk_buff *skb, + struct net_device *dev) { struct rtl8139_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 996cc910221..ea6b139b812 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -356,7 +356,7 @@ static char init_setup[] = 0x7f /* *multi IA */ }; static int i596_open(struct net_device *dev); -static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev); static irqreturn_t i596_interrupt(int irq, void *dev_id); static int i596_close(struct net_device *dev); static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd); @@ -1054,8 +1054,7 @@ static void i596_tx_timeout (struct net_device *dev) netif_wake_queue (dev); } - -static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct i596_private *lp = dev->ml_priv; struct tx_cmd *tx_cmd; diff --git a/drivers/net/8390.c b/drivers/net/8390.c index 21153dea8eb..7c7518be175 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -17,7 +17,7 @@ int ei_close(struct net_device *dev) } EXPORT_SYMBOL(ei_close); -int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t ei_start_xmit(struct sk_buff *skb, struct net_device *dev) { return __ei_start_xmit(skb, dev); } diff --git a/drivers/net/8390.h b/drivers/net/8390.h index 3c61d6d2748..3d9e8fb4fbe 100644 --- a/drivers/net/8390.h +++ b/drivers/net/8390.h @@ -40,7 +40,7 @@ extern int ei_open(struct net_device *dev); extern int ei_close(struct net_device *dev); extern irqreturn_t ei_interrupt(int irq, void *dev_id); extern void ei_tx_timeout(struct net_device *dev); -extern int ei_start_xmit(struct sk_buff *skb, struct net_device *dev); +extern netdev_tx_t ei_start_xmit(struct sk_buff *skb, struct net_device *dev); extern void ei_set_multicast_list(struct net_device *dev); extern struct net_device_stats *ei_get_stats(struct net_device *dev); @@ -58,7 +58,7 @@ extern int eip_open(struct net_device *dev); extern int eip_close(struct net_device *dev); extern irqreturn_t eip_interrupt(int irq, void *dev_id); extern void eip_tx_timeout(struct net_device *dev); -extern int eip_start_xmit(struct sk_buff *skb, struct net_device *dev); +extern netdev_tx_t eip_start_xmit(struct sk_buff *skb, struct net_device *dev); extern void eip_set_multicast_list(struct net_device *dev); extern struct net_device_stats *eip_get_stats(struct net_device *dev); diff --git a/drivers/net/8390p.c b/drivers/net/8390p.c index d225c291fd9..a2a64ea0b69 100644 --- a/drivers/net/8390p.c +++ b/drivers/net/8390p.c @@ -22,7 +22,7 @@ int eip_close(struct net_device *dev) } EXPORT_SYMBOL(eip_close); -int eip_start_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t eip_start_xmit(struct sk_buff *skb, struct net_device *dev) { return __ei_start_xmit(skb, dev); } diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 174a81187a9..b7ec0368d7e 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -547,7 +547,8 @@ static void lance_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t lance_start_xmit (struct sk_buff *skb, + struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 08419ee1029..5f0b05c2d71 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -2464,7 +2464,8 @@ ace_load_tx_bd(struct ace_private *ap, struct tx_desc *desc, u64 addr, } -static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ace_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct ace_private *ap = netdev_priv(dev); struct ace_regs __iomem *regs = ap->regs; diff --git a/drivers/net/acenic.h b/drivers/net/acenic.h index c987c9b5a13..17079b927ff 100644 --- a/drivers/net/acenic.h +++ b/drivers/net/acenic.h @@ -775,7 +775,8 @@ static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs); static irqreturn_t ace_interrupt(int irq, void *dev_id); static int ace_load_firmware(struct net_device *dev); static int ace_open(struct net_device *dev); -static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ace_start_xmit(struct sk_buff *skb, + struct net_device *dev); static int ace_close(struct net_device *dev); static void ace_tasklet(unsigned long dev); static void ace_dump_trace(struct ace_private *ap); diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 61ac671f97b..98b5f462c09 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1300,7 +1300,8 @@ static int amd8111e_tx_queue_avail(struct amd8111e_priv* lp ) This function will queue the transmit packets to the descriptors and will trigger the send operation. It also initializes the transmit descriptors with buffer physical address, byte count, ownership to hardware etc. */ -static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev) +static netdev_tx_t amd8111e_start_xmit(struct sk_buff *skb, + struct net_device * dev) { struct amd8111e_priv *lp = netdev_priv(dev); int tx_index; diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 7d227cdab9f..75a57256090 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -591,7 +591,8 @@ static int arcnet_rebuild_header(struct sk_buff *skb) /* Called by the kernel in order to transmit a packet. */ -int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t arcnet_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct arcnet_local *lp = netdev_priv(dev); struct archdr *pkt; diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 47d976cc3d7..c35af3e106b 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -115,7 +115,8 @@ struct lancedata { static int ariadne_open(struct net_device *dev); static void ariadne_init_ring(struct net_device *dev); -static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ariadne_start_xmit(struct sk_buff *skb, + struct net_device *dev); static void ariadne_tx_timeout(struct net_device *dev); static int ariadne_rx(struct net_device *dev); static void ariadne_reset(struct net_device *dev); @@ -589,7 +590,8 @@ static void ariadne_tx_timeout(struct net_device *dev) } -static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ariadne_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct ariadne_private *priv = netdev_priv(dev); volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index 5349c58d1fa..544d5af6950 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -159,7 +159,8 @@ struct net_local { static int at1700_probe1(struct net_device *dev, int ioaddr); static int read_eeprom(long ioaddr, int location); static int net_open(struct net_device *dev); -static int net_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t net_send_packet(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t net_interrupt(int irq, void *dev_id); static void net_rx(struct net_device *dev); static int net_close(struct net_device *dev); @@ -595,7 +596,8 @@ static void net_tx_timeout (struct net_device *dev) } -static int net_send_packet (struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t net_send_packet (struct sk_buff *skb, + struct net_device *dev) { struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index 1d601ce7d5b..bf7cc83e983 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -2055,7 +2055,8 @@ static void atl1c_tx_queue(struct atl1c_adapter *adapter, struct sk_buff *skb, AT_WRITE_REG(&adapter->hw, REG_MB_PRIO_PROD_IDX, prod_data); } -static int atl1c_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) { struct atl1c_adapter *adapter = netdev_priv(netdev); unsigned long flags; diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index 4570749e3d3..bca127e65f9 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -1839,7 +1839,8 @@ static void atl1e_tx_queue(struct atl1e_adapter *adapter, u16 count, AT_WRITE_REG(&adapter->hw, REG_MB_TPD_PROD_IDX, tx_ring->next_to_use); } -static int atl1e_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t atl1e_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) { struct atl1e_adapter *adapter = netdev_priv(netdev); unsigned long flags; diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 8bca12f7139..00569dc1313 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -2349,7 +2349,8 @@ static void atl1_tx_queue(struct atl1_adapter *adapter, u16 count, atomic_set(&tpd_ring->next_to_use, next_to_use); } -static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t atl1_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) { struct atl1_adapter *adapter = netdev_priv(netdev); struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index 204db961029..d0bcb572d51 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -821,7 +821,8 @@ static inline int TxdFreeBytes(struct atl2_adapter *adapter) (int) (txd_read_ptr - adapter->txd_write_ptr - 1); } -static int atl2_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t atl2_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) { struct atl2_adapter *adapter = netdev_priv(netdev); struct tx_pkt_header *txph; diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 4beacc9c909..9043294fe61 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -199,7 +199,8 @@ static int net_open(struct net_device *dev); static void hardware_init(struct net_device *dev); static void write_packet(long ioaddr, int length, unsigned char *packet, int pad, int mode); static void trigger_send(long ioaddr, int length); -static int atp_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t atp_send_packet(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t atp_interrupt(int irq, void *dev_id); static void net_rx(struct net_device *dev); static void read_block(long ioaddr, int length, unsigned char *buffer, int data_mode); @@ -552,7 +553,8 @@ static void tx_timeout(struct net_device *dev) dev->stats.tx_errors++; } -static int atp_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t atp_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct net_local *lp = netdev_priv(dev); long ioaddr = dev->base_addr; diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 2aab1ebc6cd..407fd45f56a 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -937,7 +937,7 @@ static int au1000_close(struct net_device *dev) /* * Au1000 transmit routine. */ -static int au1000_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t au1000_tx(struct sk_buff *skb, struct net_device *dev) { struct au1000_private *aup = netdev_priv(dev); struct net_device_stats *ps = &dev->stats; diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 07c92f34d8d..bee510177a3 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -946,7 +946,7 @@ static void b44_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t b44_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct b44 *bp = netdev_priv(dev); int rc = NETDEV_TX_OK; diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 7b9efee890f..e19fe1dcd14 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -427,7 +427,8 @@ static int make_tx_wrbs(struct be_adapter *adapter, return copied; } -static int be_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t be_xmit(struct sk_buff *skb, + struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); struct be_tx_obj *tx_obj = &adapter->tx_obj; diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index c4e85f69427..fcaf3bc8277 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6283,7 +6283,7 @@ bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp) * bnx2_tx_int() runs without netif_tx_lock unless it needs to call * netif_wake_queue(). */ -static int +static netdev_tx_t bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct bnx2 *bp = netdev_priv(dev); diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index b318d16a4d9..e2e50267cc6 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -10936,7 +10936,7 @@ exit_lbl: * bnx2x_tx_int() runs without netif_tx_lock unless it needs to call * netif_wake_queue() */ -static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct bnx2x *bp = netdev_priv(dev); struct bnx2x_fastpath *fp, *fp_stat; diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index b3004de1e5e..9ce3ddac4e9 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -238,7 +238,8 @@ static void chipset_init(struct net_device *dev) * xx xx xx xx ff ll 00 11 22 33 44 55 66 77 * [ can-id ] [flags] [len] [can data (up to 8 bytes] */ -static int sja1000_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct sja1000_priv *priv = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 299a33b914f..7517dc1da65 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -2918,7 +2918,7 @@ static inline int cas_xmit_tx_ringN(struct cas *cp, int ring, return 0; } -static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t cas_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct cas *cp = netdev_priv(dev); diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 3711d64e45e..8c658cf6f62 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -1776,7 +1776,7 @@ static inline int eth_hdr_len(const void *data) /* * Adds the CPL header to the sk_buff and passes it to t1_sge_tx. */ -int t1_start_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct adapter *adapter = dev->ml_priv; struct sge *sge = adapter->sge; diff --git a/drivers/net/chelsio/sge.h b/drivers/net/chelsio/sge.h index 8c940512399..00cc37fc1f6 100644 --- a/drivers/net/chelsio/sge.h +++ b/drivers/net/chelsio/sge.h @@ -78,7 +78,7 @@ void t1_sge_destroy(struct sge *); irqreturn_t t1_interrupt(int irq, void *cookie); int t1_poll(struct napi_struct *, int); -int t1_start_xmit(struct sk_buff *skb, struct net_device *dev); +netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev); void t1_set_vlan_accel(struct adapter *adapter, int on_off); void t1_sge_start(struct sge *); void t1_sge_stop(struct sge *); diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 839cac5fd8a..0c54219960e 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -246,7 +246,7 @@ struct net_local { static int cs89x0_probe1(struct net_device *dev, int ioaddr, int modular); static int net_open(struct net_device *dev); -static int net_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t net_send_packet(struct sk_buff *skb, struct net_device *dev); static irqreturn_t net_interrupt(int irq, void *dev_id); static void set_multicast_list(struct net_device *dev); static void net_timeout(struct net_device *dev); @@ -1518,7 +1518,7 @@ static void net_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int net_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t net_send_packet(struct sk_buff *skb,struct net_device *dev) { struct net_local *lp = netdev_priv(dev); unsigned long flags; diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index 74723f2e743..2b1aea6aa55 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -309,7 +309,7 @@ void t3_stop_sge_timers(struct adapter *adap); void t3_free_sge_resources(struct adapter *adap); void t3_sge_err_intr_handler(struct adapter *adapter); irq_handler_t t3_intr_handler(struct adapter *adap, int polling); -int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev); +netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev); int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb); void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p); int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 29c79eb43be..f86612857a7 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -1216,7 +1216,7 @@ static inline void t3_stop_tx_queue(struct netdev_queue *txq, * * Add a packet to an SGE Tx queue. Runs with softirqs disabled. */ -int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) { int qidx; unsigned int ndesc, pidx, credits, gen, compl; diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index b2e0a8fc21d..6a6ea038d7a 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -300,7 +300,8 @@ static int dfx_rcv_init(DFX_board_t *bp, int get_buffers); static void dfx_rcv_queue_process(DFX_board_t *bp); static void dfx_rcv_flush(DFX_board_t *bp); -static int dfx_xmt_queue_pkt(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t dfx_xmt_queue_pkt(struct sk_buff *skb, + struct net_device *dev); static int dfx_xmt_done(DFX_board_t *bp); static void dfx_xmt_flush(DFX_board_t *bp); @@ -3188,11 +3189,8 @@ static void dfx_rcv_queue_process( * None */ -static int dfx_xmt_queue_pkt( - struct sk_buff *skb, - struct net_device *dev - ) - +static netdev_tx_t dfx_xmt_queue_pkt(struct sk_buff *skb, + struct net_device *dev) { DFX_board_t *bp = netdev_priv(dev); u8 prod; /* local transmit producer index */ diff --git a/drivers/net/depca.c b/drivers/net/depca.c index adb997c5bb5..9686c1fa28f 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -516,7 +516,8 @@ struct depca_private { ** Public Functions */ static int depca_open(struct net_device *dev); -static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t depca_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t depca_interrupt(int irq, void *dev_id); static int depca_close(struct net_device *dev); static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); @@ -928,7 +929,8 @@ static void depca_tx_timeout(struct net_device *dev) /* ** Writes a socket buffer to TX descriptor ring and starts transmission */ -static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t depca_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct depca_private *lp = netdev_priv(dev); u_long ioaddr = dev->base_addr; diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 4b6a219fece..7fa7a907f13 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -59,7 +59,7 @@ static int rio_open (struct net_device *dev); static void rio_timer (unsigned long data); static void rio_tx_timeout (struct net_device *dev); static void alloc_list (struct net_device *dev); -static int start_xmit (struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t start_xmit (struct sk_buff *skb, struct net_device *dev); static irqreturn_t rio_interrupt (int irq, void *dev_instance); static void rio_free_tx (struct net_device *dev, int irq); static void tx_error (struct net_device *dev, int tx_status); @@ -600,7 +600,7 @@ alloc_list (struct net_device *dev) return; } -static int +static netdev_tx_t start_xmit (struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); diff --git a/drivers/net/dnet.c b/drivers/net/dnet.c index 2818d5de394..234685213f1 100644 --- a/drivers/net/dnet.c +++ b/drivers/net/dnet.c @@ -541,7 +541,7 @@ static inline void dnet_print_skb(struct sk_buff *skb) #define dnet_print_skb(skb) do {} while (0) #endif -static int dnet_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t dnet_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct dnet *bp = netdev_priv(dev); diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 53317a83857..1e934160062 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -309,7 +309,8 @@ struct eepro_local { static int eepro_probe1(struct net_device *dev, int autoprobe); static int eepro_open(struct net_device *dev); -static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t eepro_send_packet(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t eepro_interrupt(int irq, void *dev_id); static void eepro_rx(struct net_device *dev); static void eepro_transmit_interrupt(struct net_device *dev); @@ -1133,7 +1134,8 @@ static void eepro_tx_timeout (struct net_device *dev) } -static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t eepro_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct eepro_local *lp = netdev_priv(dev); unsigned long flags; diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index d1b6368faac..592de8f1668 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -246,7 +246,8 @@ static char mca_irqmap[] = { 12, 9, 3, 4, 5, 10, 11, 15 }; static int eexp_open(struct net_device *dev); static int eexp_close(struct net_device *dev); static void eexp_timeout(struct net_device *dev); -static int eexp_xmit(struct sk_buff *buf, struct net_device *dev); +static netdev_tx_t eexp_xmit(struct sk_buff *buf, + struct net_device *dev); static irqreturn_t eexp_irq(int irq, void *dev_addr); static void eexp_set_multicast(struct net_device *dev); @@ -650,7 +651,7 @@ static void eexp_timeout(struct net_device *dev) * Called to transmit a packet, or to allow us to right ourselves * if the kernel thinks we've died. */ -static int eexp_xmit(struct sk_buff *buf, struct net_device *dev) +static netdev_tx_t eexp_xmit(struct sk_buff *buf, struct net_device *dev) { short length = buf->len; #ifdef CONFIG_SMP diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index 372d6c6a4e7..117fc6c12e3 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -1276,7 +1276,8 @@ static void enc28j60_hw_tx(struct enc28j60_net *priv) locked_reg_bfset(priv, ECON1, ECON1_TXRTS); } -static int enc28j60_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t enc28j60_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct enc28j60_net *priv = netdev_priv(dev); diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 8005b602f77..49912eb2a33 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -622,7 +622,8 @@ static inline void enic_queue_wq_skb(struct enic *enic, } /* netif_tx_lock held, process context with BHs disabled, or BH */ -static int enic_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb, + struct net_device *netdev) { struct enic *enic = netdev_priv(netdev); struct vnic_wq *wq = &enic->wq[0]; diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index d668ff2af6e..641a10d2e84 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -298,7 +298,8 @@ static void epic_restart(struct net_device *dev); static void epic_timer(unsigned long data); static void epic_tx_timeout(struct net_device *dev); static void epic_init_ring(struct net_device *dev); -static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t epic_start_xmit(struct sk_buff *skb, + struct net_device *dev); static int epic_rx(struct net_device *dev, int budget); static int epic_poll(struct napi_struct *napi, int budget); static irqreturn_t epic_interrupt(int irq, void *dev_instance); @@ -961,7 +962,7 @@ static void epic_init_ring(struct net_device *dev) return; } -static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t epic_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct epic_private *ep = netdev_priv(dev); int entry, free_count; diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index 97d5205edc8..71bfeec33a0 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -405,7 +405,7 @@ static int eth16i_read_eeprom_word(int ioaddr); static void eth16i_eeprom_cmd(int ioaddr, unsigned char command); static int eth16i_open(struct net_device *dev); static int eth16i_close(struct net_device *dev); -static int eth16i_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t eth16i_tx(struct sk_buff *skb, struct net_device *dev); static void eth16i_rx(struct net_device *dev); static void eth16i_timeout(struct net_device *dev); static irqreturn_t eth16i_interrupt(int irq, void *dev_id); @@ -1053,7 +1053,7 @@ static void eth16i_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int eth16i_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t eth16i_tx(struct sk_buff *skb, struct net_device *dev) { struct eth16i_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index 4dbe5f17327..b871aefed9c 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -802,7 +802,7 @@ static struct net_device_stats *ethoc_stats(struct net_device *dev) return &priv->stats; } -static int ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ethoc *priv = netdev_priv(dev); struct ethoc_bd bd; diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 9c51bc813ad..b2a5ec8f372 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -298,7 +298,7 @@ struct ewrk3_private { ** Public Functions */ static int ewrk3_open(struct net_device *dev); -static int ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev); static irqreturn_t ewrk3_interrupt(int irq, void *dev_id); static int ewrk3_close(struct net_device *dev); static void set_multicast_list(struct net_device *dev); @@ -764,7 +764,7 @@ static void ewrk3_timeout(struct net_device *dev) /* ** Writes a socket buffer to the free page queue */ -static int ewrk3_queue_pkt (struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev) { struct ewrk3_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index f66da84a939..18d5fbb9673 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -433,7 +433,7 @@ static void netdev_timer(unsigned long data); static void reset_timer(unsigned long data); static void fealnx_tx_timeout(struct net_device *dev); static void init_ring(struct net_device *dev); -static int start_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t intr_handler(int irq, void *dev_instance); static int netdev_rx(struct net_device *dev); static void set_rx_mode(struct net_device *dev); @@ -1305,7 +1305,7 @@ static void init_ring(struct net_device *dev) } -static int start_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); unsigned long flags; diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 3b4e0766c7b..0a1c2bb27d4 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -2137,7 +2137,7 @@ static void nv_gear_backoff_reseed(struct net_device *dev) * nv_start_xmit: dev->hard_start_xmit function * Called with netif_tx_lock held. */ -static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); u32 tx_flags = 0; @@ -2257,7 +2257,8 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } -static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, + struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); u32 tx_flags = 0; diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 635341d6a02..1d5064a09ac 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -557,7 +557,8 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void hamachi_timer(unsigned long data); static void hamachi_tx_timeout(struct net_device *dev); static void hamachi_init_ring(struct net_device *dev); -static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t hamachi_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t hamachi_interrupt(int irq, void *dev_instance); static int hamachi_rx(struct net_device *dev); static inline int hamachi_tx(struct net_device *dev); @@ -1263,7 +1264,8 @@ do { \ } while (0) #endif -static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t hamachi_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct hamachi_private *hmp = netdev_priv(dev); unsigned entry; diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index d1b63387e9b..a9a1a99f02d 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -240,9 +240,10 @@ static int hp100_probe1(struct net_device *dev, int ioaddr, u_char bus, static int hp100_open(struct net_device *dev); static int hp100_close(struct net_device *dev); -static int hp100_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int hp100_start_xmit_bm(struct sk_buff *skb, - struct net_device *dev); +static netdev_tx_t hp100_start_xmit(struct sk_buff *skb, + struct net_device *dev); +static netdev_tx_t hp100_start_xmit_bm(struct sk_buff *skb, + struct net_device *dev); static void hp100_rx(struct net_device *dev); static struct net_device_stats *hp100_get_stats(struct net_device *dev); static void hp100_misc_interrupt(struct net_device *dev); @@ -1483,7 +1484,8 @@ static int hp100_check_lan(struct net_device *dev) */ /* tx function for busmaster mode */ -static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t hp100_start_xmit_bm(struct sk_buff *skb, + struct net_device *dev) { unsigned long flags; int i, ok_flag; @@ -1635,7 +1637,8 @@ static void hp100_clean_txring(struct net_device *dev) } /* tx function for slave modes */ -static int hp100_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t hp100_start_xmit(struct sk_buff *skb, + struct net_device *dev) { unsigned long flags; int i, ok_flag; diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index 448098d3b39..090a6d3af11 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -812,7 +812,7 @@ static int ibmlana_close(struct net_device *dev) /* transmit a block. */ -static int ibmlana_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ibmlana_tx(struct sk_buff *skb, struct net_device *dev) { ibmlana_priv *priv = netdev_priv(dev); int tmplen, addr; diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 76b295a1818..5862282ab2f 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -887,7 +887,8 @@ static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) #define page_offset(v) ((unsigned long)(v) & ((1 << 12) - 1)) -static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, + struct net_device *netdev) { struct ibmveth_adapter *adapter = netdev_priv(netdev); union ibmveth_buf_desc desc; diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index 43019461b77..382c5532e6c 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -1858,7 +1858,8 @@ static int ipg_nic_stop(struct net_device *dev) return 0; } -static int ipg_nic_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ipg_nic_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct ipg_nic_private *sp = netdev_priv(dev); void __iomem *ioaddr = sp->ioaddr; diff --git a/drivers/net/jme.c b/drivers/net/jme.c index e7068c7cd62..1d2a32544ed 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -1931,7 +1931,7 @@ jme_stop_queue_if_full(struct jme_adapter *jme) * This function is already protected by netif_tx_lock() */ -static int +static netdev_tx_t jme_start_xmit(struct sk_buff *skb, struct net_device *netdev) { struct jme_adapter *jme = netdev_priv(netdev); diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c index 39b0aea2aab..6e74aa9eea4 100644 --- a/drivers/net/ks8842.c +++ b/drivers/net/ks8842.c @@ -551,7 +551,8 @@ static int ks8842_close(struct net_device *netdev) return 0; } -static int ks8842_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t ks8842_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) { int ret; struct ks8842_adapter *adapter = netdev_priv(netdev); diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c index 9a1dea60c1c..547ac7c7479 100644 --- a/drivers/net/ks8851.c +++ b/drivers/net/ks8851.c @@ -868,11 +868,12 @@ static int ks8851_net_stop(struct net_device *dev) * and secondly so we can round up more than one packet to transmit which * means we can try and avoid generating too many transmit done interrupts. */ -static int ks8851_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ks8851_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct ks8851_net *ks = netdev_priv(dev); unsigned needed = calc_txlen(skb->len); - int ret = NETDEV_TX_OK; + netdev_tx_t ret = NETDEV_TX_OK; if (netif_msg_tx_queued(ks)) ks_dbg(ks, "%s: skb %p, %d@%p\n", __func__, diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 30fd4f5f1d5..dcda30338b6 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -300,7 +300,8 @@ static unsigned char lance_need_isa_bounce_buffers = 1; static int lance_open(struct net_device *dev); static void lance_init_ring(struct net_device *dev, gfp_t mode); -static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t lance_start_xmit(struct sk_buff *skb, + struct net_device *dev); static int lance_rx(struct net_device *dev); static irqreturn_t lance_interrupt(int irq, void *dev_id); static int lance_close(struct net_device *dev); @@ -949,7 +950,8 @@ static void lance_tx_timeout (struct net_device *dev) } -static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t lance_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct lance_private *lp = dev->ml_priv; int ioaddr = dev->base_addr; diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c index d6be36000c5..256119882b1 100644 --- a/drivers/net/lib8390.c +++ b/drivers/net/lib8390.c @@ -299,7 +299,8 @@ static void __ei_tx_timeout(struct net_device *dev) * Sends a packet to an 8390 network device. */ -static int __ei_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t __ei_start_xmit(struct sk_buff *skb, + struct net_device *dev) { unsigned long e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 51bbce72bed..1bc654a73c4 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -69,7 +69,8 @@ struct pcpu_lstats { * The higher levels take care of making this non-reentrant (it's * called with bh's disabled). */ -static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t loopback_xmit(struct sk_buff *skb, + struct net_device *dev) { struct pcpu_lstats *pcpu_lstats, *lb_stats; int len; diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index c292bad411e..cc3ed9cf28b 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -377,7 +377,7 @@ static char init_setup[14] = { }; static int i596_open(struct net_device *dev); -static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev); static irqreturn_t i596_interrupt(int irq, void *dev_id); static int i596_close(struct net_device *dev); static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd); @@ -863,7 +863,7 @@ static int i596_open(struct net_device *dev) return 0; /* Always succeed */ } -static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) { +static netdev_tx_t i596_start_xmit (struct sk_buff *skb, struct net_device *dev) { struct tx_cmd *tx_cmd; short length; diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index 0ecc1e1b013..d3d6e991065 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c @@ -588,7 +588,7 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb) return skb_tx_hash(dev, skb); } -int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) { struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index 4513fb4960d..4376147b0ea 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -518,7 +518,7 @@ int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); void mlx4_en_poll_tx_cq(unsigned long data); void mlx4_en_tx_irq(struct mlx4_cq *mcq); u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb); -int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev); +netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev); int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, u32 size, u16 stride); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 75deef35b1e..6930c87f362 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -360,7 +360,8 @@ MODULE_PARM_DESC(myri10ge_dca, "Enable DCA if possible"); #define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8) static void myri10ge_set_multicast_list(struct net_device *dev); -static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t myri10ge_sw_tso(struct sk_buff *skb, + struct net_device *dev); static inline void put_be32(__be32 val, __be32 __iomem * p) { @@ -2656,7 +2657,8 @@ myri10ge_submit_req(struct myri10ge_tx_buf *tx, struct mcp_kreq_ether_send *src, * it and try again. */ -static int myri10ge_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t myri10ge_xmit(struct sk_buff *skb, + struct net_device *dev) { struct myri10ge_priv *mgp = netdev_priv(dev); struct myri10ge_slice_state *ss; @@ -2947,12 +2949,13 @@ drop: } -static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t myri10ge_sw_tso(struct sk_buff *skb, + struct net_device *dev) { struct sk_buff *segs, *curr; struct myri10ge_priv *mgp = netdev_priv(dev); struct myri10ge_slice_state *ss; - int status; + netdev_tx_t status; segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO6); if (IS_ERR(segs)) diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 32db12a2734..bd41351e4e2 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -621,7 +621,7 @@ static void drain_ring(struct net_device *dev); static void free_ring(struct net_device *dev); static void reinit_ring(struct net_device *dev); static void init_registers(struct net_device *dev); -static int start_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t intr_handler(int irq, void *dev_instance); static void netdev_error(struct net_device *dev, int intr_status); static int natsemi_poll(struct napi_struct *napi, int budget); @@ -2079,7 +2079,7 @@ static void reinit_ring(struct net_device *dev) reinit_rx(dev); } -static int start_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); void __iomem * ioaddr = ns_ioaddr(dev); diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index fab51d16f5f..f824a392bf5 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -63,7 +63,8 @@ static int __devinit netxen_nic_probe(struct pci_dev *pdev, static void __devexit netxen_nic_remove(struct pci_dev *pdev); static int netxen_nic_open(struct net_device *netdev); static int netxen_nic_close(struct net_device *netdev); -static int netxen_nic_xmit_frame(struct sk_buff *, struct net_device *); +static netdev_tx_t netxen_nic_xmit_frame(struct sk_buff *, + struct net_device *); static void netxen_tx_timeout(struct net_device *netdev); static void netxen_reset_task(struct work_struct *work); static void netxen_watchdog(unsigned long); @@ -1599,7 +1600,7 @@ netxen_clear_cmddesc(u64 *desc) desc[2] = 0ULL; } -static int +static netdev_tx_t netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct netxen_adapter *adapter = netdev_priv(netdev); diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index a0ac5d4f27d..bd0ac690d12 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -170,7 +170,7 @@ static int ni52_probe1(struct net_device *dev, int ioaddr); static irqreturn_t ni52_interrupt(int irq, void *dev_id); static int ni52_open(struct net_device *dev); static int ni52_close(struct net_device *dev); -static int ni52_send_packet(struct sk_buff *, struct net_device *); +static netdev_tx_t ni52_send_packet(struct sk_buff *, struct net_device *); static struct net_device_stats *ni52_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); static void ni52_timeout(struct net_device *dev); @@ -1173,7 +1173,8 @@ static void ni52_timeout(struct net_device *dev) * send frame */ -static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ni52_send_packet(struct sk_buff *skb, + struct net_device *dev) { int len, i; #ifndef NO_NOPCOMMANDS diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index 81a06178589..752c2e4d9cf 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -252,7 +252,8 @@ static void ni65_xmit_intr(struct net_device *dev,int); static int ni65_open(struct net_device *dev); static int ni65_lance_reinit(struct net_device *dev); static void ni65_init_lance(struct priv *p,unsigned char*,int,int); -static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t ni65_send_packet(struct sk_buff *skb, + struct net_device *dev); static void ni65_timeout(struct net_device *dev); static int ni65_close(struct net_device *dev); static int ni65_alloc_buffer(struct net_device *dev); @@ -1157,7 +1158,8 @@ static void ni65_timeout(struct net_device *dev) * Send a packet */ -static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ni65_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct priv *p = dev->ml_priv; diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 3ada7ea2abc..119fd4e0414 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -6657,7 +6657,8 @@ static u64 niu_compute_tx_flags(struct sk_buff *skb, struct ethhdr *ehdr, return ret; } -static int niu_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t niu_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct niu *np = netdev_priv(dev); unsigned long align, headroom; diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 1576ac07216..c594e194647 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1077,7 +1077,8 @@ static void ns83820_cleanup_tx(struct ns83820 *dev) * while trying to track down a bug in either the zero copy code or * the tx fifo (hence the MAX_FRAG_LEN). */ -static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t ns83820_hard_start_xmit(struct sk_buff *skb, + struct net_device *ndev) { struct ns83820 *dev = PRIV(ndev); u32 free_idx, cmdsts, extsts; diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 6859442f186..6d28b18e7e2 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -303,7 +303,8 @@ static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *); static int pcnet32_probe1(unsigned long, int, struct pci_dev *); static int pcnet32_open(struct net_device *); static int pcnet32_init_ring(struct net_device *); -static int pcnet32_start_xmit(struct sk_buff *, struct net_device *); +static netdev_tx_t pcnet32_start_xmit(struct sk_buff *, + struct net_device *); static void pcnet32_tx_timeout(struct net_device *dev); static irqreturn_t pcnet32_interrupt(int, void *); static int pcnet32_close(struct net_device *); @@ -2481,7 +2482,8 @@ static void pcnet32_tx_timeout(struct net_device *dev) spin_unlock_irqrestore(&lp->lock, flags); } -static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t pcnet32_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct pcnet32_private *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index 3e4b67aaa6e..4c610511eb4 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -2572,7 +2572,8 @@ map_error: * The IOCB is always the top of the chain followed by one or more * OALs (when necessary). */ -static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t ql3xxx_send(struct sk_buff *skb, + struct net_device *ndev) { struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev); struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 8dd266befdc..22052925782 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -2103,7 +2103,7 @@ static void ql_hw_csum_setup(struct sk_buff *skb, iph->daddr, len, iph->protocol, 0); } -static int qlge_send(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t qlge_send(struct sk_buff *skb, struct net_device *ndev) { struct tx_ring_desc *tx_ring_desc; struct ob_mac_iocb_req *mac_iocb_ptr; diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 8068a07eb2b..7dfcb58b0eb 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -883,13 +883,13 @@ static int r6040_open(struct net_device *dev) return 0; } -static int r6040_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t r6040_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct r6040_private *lp = netdev_priv(dev); struct r6040_descriptor *descptr; void __iomem *ioaddr = lp->base; unsigned long flags; - int ret = NETDEV_TX_OK; /* Critical Section */ spin_lock_irqsave(&lp->lock, flags); @@ -899,8 +899,7 @@ static int r6040_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&lp->lock, flags); netif_stop_queue(dev); printk(KERN_ERR DRV_NAME ": no tx descriptor\n"); - ret = NETDEV_TX_BUSY; - return ret; + return NETDEV_TX_BUSY; } /* Statistic Counter */ @@ -928,7 +927,8 @@ static int r6040_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; spin_unlock_irqrestore(&lp->lock, flags); - return ret; + + return NETDEV_TX_OK; } static void r6040_multicast_list(struct net_device *dev) diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 8cd85309c67..ec0092affd5 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -507,7 +507,8 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(RTL8169_VERSION); static int rtl8169_open(struct net_device *dev); -static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance); static int rtl8169_init_ring(struct net_device *dev); static void rtl_hw_start(struct net_device *dev); @@ -3357,7 +3358,8 @@ static inline u32 rtl8169_tso_csum(struct sk_buff *skb, struct net_device *dev) return 0; } -static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); unsigned int frags, entry = tp->cur_tx % NUM_TX_DESC; @@ -3366,7 +3368,6 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev) dma_addr_t mapping; u32 status, len; u32 opts1; - int ret = NETDEV_TX_OK; if (unlikely(TX_BUFFS_AVAIL(tp) < skb_shinfo(skb)->nr_frags)) { if (netif_msg_drv(tp)) { @@ -3418,13 +3419,12 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev) } out: - return ret; + return NETDEV_TX_OK; err_stop: netif_stop_queue(dev); - ret = NETDEV_TX_BUSY; dev->stats.tx_dropped++; - goto out; + return NETDEV_TX_BUSY; } static void rtl8169_pcierr_interrupt(struct net_device *dev) diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index d9553465591..20a71749154 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -1401,7 +1401,8 @@ static int rr_close(struct net_device *dev) } -static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t rr_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct rr_private *rrpriv = netdev_priv(dev); struct rr_regs __iomem *regs = rrpriv->regs; diff --git a/drivers/net/rrunner.h b/drivers/net/rrunner.h index 6173f11218d..28169043ae4 100644 --- a/drivers/net/rrunner.h +++ b/drivers/net/rrunner.h @@ -831,7 +831,8 @@ static int rr_init1(struct net_device *dev); static irqreturn_t rr_interrupt(int irq, void *dev_id); static int rr_open(struct net_device *dev); -static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t rr_start_xmit(struct sk_buff *skb, + struct net_device *dev); static int rr_close(struct net_device *dev); static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static unsigned int rr_read_eeprom(struct rr_private *rrpriv, diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 3138df5773e..ddccf5fa56b 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -4072,7 +4072,7 @@ static int s2io_close(struct net_device *dev) * 0 on success & 1 on failure. */ -static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t s2io_xmit(struct sk_buff *skb, struct net_device *dev) { struct s2io_nic *sp = netdev_priv(dev); u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off; diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index 6a81aec645d..ee366c5a8fa 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -82,7 +82,8 @@ struct sb1000_private { extern int sb1000_probe(struct net_device *dev); static int sb1000_open(struct net_device *dev); static int sb1000_dev_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd); -static int sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t sb1000_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t sb1000_interrupt(int irq, void *dev_id); static int sb1000_close(struct net_device *dev); @@ -1080,7 +1081,7 @@ static int sb1000_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } /* transmit function: do nothing since SB1000 can't send anything out */ -static int +static netdev_tx_t sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev) { printk(KERN_WARNING "%s: trying to transmit!!!\n", dev->name); diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c index e3156c97bb5..8d6030022d1 100644 --- a/drivers/net/sc92031.c +++ b/drivers/net/sc92031.c @@ -941,7 +941,8 @@ static struct net_device_stats *sc92031_get_stats(struct net_device *dev) return &dev->stats; } -static int sc92031_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t sc92031_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct sc92031_priv *priv = netdev_priv(dev); void __iomem *port_base = priv->port_base; diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index 7cc8bb81413..39246d457ac 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -81,7 +81,8 @@ struct net_local { static int seeq8005_probe1(struct net_device *dev, int ioaddr); static int seeq8005_open(struct net_device *dev); static void seeq8005_timeout(struct net_device *dev); -static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t seeq8005_send_packet(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t seeq8005_interrupt(int irq, void *dev_id); static void seeq8005_rx(struct net_device *dev); static int seeq8005_close(struct net_device *dev); @@ -394,7 +395,8 @@ static void seeq8005_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t seeq8005_send_packet(struct sk_buff *skb, + struct net_device *dev) { short length = skb->len; unsigned char *buf; diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index da157aa74b8..aecaf62f492 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -20,8 +20,9 @@ #define FALCON_B_P_DEVID 0x0710 /* TX */ -extern int efx_xmit(struct efx_nic *efx, - struct efx_tx_queue *tx_queue, struct sk_buff *skb); +extern netdev_tx_t efx_xmit(struct efx_nic *efx, + struct efx_tx_queue *tx_queue, + struct sk_buff *skb); extern void efx_stop_queue(struct efx_nic *efx); extern void efx_wake_queue(struct efx_nic *efx); diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index b67ccca3fc1..817c7efc11e 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -400,7 +400,8 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) struct efx_loopback_state *state = efx->loopback_selftest; struct efx_loopback_payload *payload; struct sk_buff *skb; - int i, rc; + int i; + netdev_tx_t rc; /* Transmit N copies of buffer */ for (i = 0; i < state->packet_count; i++) { diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index 14a14788566..489c4de3144 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -138,8 +138,8 @@ static void efx_tsoh_free(struct efx_tx_queue *tx_queue, * Returns NETDEV_TX_OK or NETDEV_TX_BUSY * You must hold netif_tx_lock() to call this function. */ -static int efx_enqueue_skb(struct efx_tx_queue *tx_queue, - struct sk_buff *skb) +static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, + struct sk_buff *skb) { struct efx_nic *efx = tx_queue->efx; struct pci_dev *pci_dev = efx->pci_dev; @@ -152,7 +152,7 @@ static int efx_enqueue_skb(struct efx_tx_queue *tx_queue, unsigned int dma_len; bool unmap_single; int q_space, i = 0; - int rc = NETDEV_TX_OK; + netdev_tx_t rc = NETDEV_TX_OK; EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count); @@ -353,14 +353,11 @@ static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue, * * Context: netif_tx_lock held */ -inline int efx_xmit(struct efx_nic *efx, - struct efx_tx_queue *tx_queue, struct sk_buff *skb) +inline netdev_tx_t efx_xmit(struct efx_nic *efx, + struct efx_tx_queue *tx_queue, struct sk_buff *skb) { - int rc; - /* Map fragments for DMA and add to TX queue */ - rc = efx_enqueue_skb(tx_queue, skb); - return rc; + return efx_enqueue_skb(tx_queue, skb); } /* Initiate a packet transmission. We use one channel per CPU @@ -372,7 +369,8 @@ inline int efx_xmit(struct efx_nic *efx, * Note that returning anything other than NETDEV_TX_OK will cause the * OS to free the skb. */ -int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev) +netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, + struct net_device *net_dev) { struct efx_nic *efx = netdev_priv(net_dev); struct efx_tx_queue *tx_queue; diff --git a/drivers/net/sfc/tx.h b/drivers/net/sfc/tx.h index 5e1cc234e42..e3678962a5b 100644 --- a/drivers/net/sfc/tx.h +++ b/drivers/net/sfc/tx.h @@ -18,7 +18,8 @@ void efx_remove_tx_queue(struct efx_tx_queue *tx_queue); void efx_init_tx_queue(struct efx_tx_queue *tx_queue); void efx_fini_tx_queue(struct efx_tx_queue *tx_queue); -int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev); +netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, + struct net_device *net_dev); void efx_release_tx_buffers(struct efx_tx_queue *tx_queue); #endif /* EFX_TX_H */ diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 1f040e8a000..7cc9898f4e0 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -1168,7 +1168,8 @@ static int sis190_close(struct net_device *dev) return 0; } -static int sis190_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t sis190_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct sis190_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 61ceeaaf104..d8827323507 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -214,7 +214,8 @@ static void sis900_check_mode (struct net_device *net_dev, struct mii_phy *mii_p static void sis900_tx_timeout(struct net_device *net_dev); static void sis900_init_tx_ring(struct net_device *net_dev); static void sis900_init_rx_ring(struct net_device *net_dev); -static int sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev); +static netdev_tx_t sis900_start_xmit(struct sk_buff *skb, + struct net_device *net_dev); static int sis900_rx(struct net_device *net_dev); static void sis900_finish_xmit (struct net_device *net_dev); static irqreturn_t sis900_interrupt(int irq, void *dev_instance); @@ -1571,7 +1572,7 @@ static void sis900_tx_timeout(struct net_device *net_dev) * tell upper layer if the buffer is full */ -static int +static netdev_tx_t sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) { struct sis900_private *sis_priv = netdev_priv(net_dev); diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index 888a14a045e..38a508b4aad 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -107,7 +107,8 @@ static void skfp_ctl_set_multicast_list(struct net_device *dev); static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev); static int skfp_ctl_set_mac_address(struct net_device *dev, void *addr); static int skfp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t skfp_send_pkt(struct sk_buff *skb, + struct net_device *dev); static void send_queued_packets(struct s_smc *smc); static void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr); static void ResetAdapter(struct s_smc *smc); @@ -1056,7 +1057,8 @@ static int skfp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) * Side Effects: * None */ -static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t skfp_send_pkt(struct sk_buff *skb, + struct net_device *dev) { struct s_smc *smc = netdev_priv(dev); skfddi_priv *bp = &smc->os; diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 543af2044f4..1a1e68549f5 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2746,7 +2746,8 @@ static inline int skge_avail(const struct skge_ring *ring) + (ring->to_clean - ring->to_use) - 1; } -static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t skge_xmit_frame(struct sk_buff *skb, + struct net_device *dev) { struct skge_port *skge = netdev_priv(dev); struct skge_hw *hw = skge->hw; diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index dd630cf18b4..c7c0a5b7b53 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1574,7 +1574,8 @@ static void sky2_tx_unmap(struct pci_dev *pdev, * the number of ring elements will probably be less than the number * of list elements used. */ -static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb, + struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 0a1b6f40108..934a1201282 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -299,7 +299,8 @@ static void smc_hardware_send_packet( struct net_device * dev ); . to store the packet, I call this routine, which either sends it . now, or generates an interrupt when the card is ready for the . packet */ -static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device *dev ); +static netdev_tx_t smc_wait_to_send_packet( struct sk_buff * skb, + struct net_device *dev ); /* this does a soft reset on the device */ static void smc_reset( int ioaddr ); @@ -487,7 +488,8 @@ static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs . o (NO): Enable interrupts and let the interrupt handler deal with it. . o (YES):Send it now. */ -static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * dev ) +static netdev_tx_t smc_wait_to_send_packet(struct sk_buff *skb, + struct net_device *dev) { struct smc_local *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c index 60abdb1081a..514311d67b3 100644 --- a/drivers/net/smsc9420.c +++ b/drivers/net/smsc9420.c @@ -968,7 +968,8 @@ static void smsc9420_complete_tx(struct net_device *dev) } } -static int smsc9420_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t smsc9420_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct smsc9420_pdata *pd = netdev_priv(dev); dma_addr_t mapping; diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 5e7645ee8ab..a36e2b51e88 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -595,7 +595,7 @@ static int netdev_open(struct net_device *dev); static void check_duplex(struct net_device *dev); static void tx_timeout(struct net_device *dev); static void init_ring(struct net_device *dev); -static int start_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t intr_handler(int irq, void *dev_instance); static void netdev_error(struct net_device *dev, int intr_status); static int __netdev_rx(struct net_device *dev, int *quota); @@ -1223,7 +1223,7 @@ static void init_ring(struct net_device *dev) } -static int start_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); unsigned int entry; diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index d09be481bcc..e13685a570f 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -415,7 +415,7 @@ static void check_duplex(struct net_device *dev); static void netdev_timer(unsigned long data); static void tx_timeout(struct net_device *dev); static void init_ring(struct net_device *dev); -static int start_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev); static int reset_tx (struct net_device *dev); static irqreturn_t intr_handler(int irq, void *dev_instance); static void rx_poll(unsigned long data); @@ -1053,7 +1053,7 @@ static void tx_poll (unsigned long data) return; } -static int +static netdev_tx_t start_tx (struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index d2dfe0ab510..e0dfdd24647 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -1015,7 +1015,8 @@ static __inline__ int gem_intme(int entry) return 0; } -static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t gem_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct gem *gp = netdev_priv(dev); int entry; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 008bd59fc64..37d721bbdb3 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2252,7 +2252,8 @@ static void happy_meal_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t happy_meal_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct happy_meal *hp = netdev_priv(dev); int entry; diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 3c2679cd196..918d4c9e49b 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -1622,7 +1622,8 @@ static inline int bdx_tx_space(struct bdx_priv *priv) * the driver. Note: the driver must NOT put the skb in its DMA ring. * o NETDEV_TX_LOCKED Locking failed, please retry quickly. */ -static int bdx_tx_transmit(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t bdx_tx_transmit(struct sk_buff *skb, + struct net_device *ndev) { struct bdx_priv *priv = netdev_priv(ndev); struct txd_fifo *f = &priv->txd_fifo0; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index a7d14aae258..9d5c1786c66 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5135,7 +5135,8 @@ static void tg3_set_txd(struct tg3_napi *tnapi, int entry, /* hard_start_xmit for devices that don't have any bugs and * support TG3_FLG2_HW_TSO_2 only. */ -static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); u32 len, entry, base_flags, mss; @@ -5251,7 +5252,8 @@ out_unlock: return NETDEV_TX_OK; } -static int tg3_start_xmit_dma_bug(struct sk_buff *, struct net_device *); +static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *, + struct net_device *); /* Use GSO to workaround a rare TSO bug that may be triggered when the * TSO header is greater than 80 bytes. @@ -5290,7 +5292,8 @@ tg3_tso_bug_end: /* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and * support TG3_FLG2_HW_TSO_1 or firmware TSO only. */ -static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, + struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); u32 len, entry, base_flags, mss; diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 70c9ec45d8f..49e273bceed 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -289,7 +289,7 @@ static void TLan_EisaProbe( void ); static void TLan_Eisa_Cleanup( void ); static int TLan_Init( struct net_device * ); static int TLan_Open( struct net_device *dev ); -static int TLan_StartTx( struct sk_buff *, struct net_device *); +static netdev_tx_t TLan_StartTx( struct sk_buff *, struct net_device *); static irqreturn_t TLan_HandleInterrupt( int, void *); static int TLan_Close( struct net_device *); static struct net_device_stats *TLan_GetStats( struct net_device *); @@ -1083,7 +1083,7 @@ static void TLan_tx_timeout_work(struct work_struct *work) * **************************************************************/ -static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) +static netdev_tx_t TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) { TLanPrivateInfo *priv = netdev_priv(dev); dma_addr_t tail_list_phys; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 2c26b4577e8..d6d345229fe 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -762,7 +762,7 @@ typhoon_tso_fill(struct sk_buff *skb, struct transmit_ring *txRing, tcpd->status = 0; } -static int +static netdev_tx_t typhoon_start_tx(struct sk_buff *skb, struct net_device *dev) { struct typhoon *tp = netdev_priv(dev); diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 46eb618bbc9..081402cb05f 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -408,7 +408,8 @@ static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static int rhine_open(struct net_device *dev); static void rhine_tx_timeout(struct net_device *dev); -static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t rhine_start_tx(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t rhine_interrupt(int irq, void *dev_instance); static void rhine_tx(struct net_device *dev); static int rhine_rx(struct net_device *dev, int limit); @@ -1213,7 +1214,8 @@ static void rhine_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } -static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t rhine_start_tx(struct sk_buff *skb, + struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 47be41a39d3..e56cf6b548d 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -2465,7 +2465,8 @@ static int velocity_close(struct net_device *dev) * Called by the networ layer to request a packet is queued to * the velocity. Returns zero on success. */ -static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t velocity_xmit(struct sk_buff *skb, + struct net_device *dev) { struct velocity_info *vptr = netdev_priv(dev); int qnum = 0; diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 094d15548a2..41dccba50c4 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -812,7 +812,7 @@ static int vxge_learn_mac(struct vxgedev *vdev, u8 *mac_header) * NOTE: when device cant queue the pkt, just the trans_start variable will * not be upadted. */ -static int +static netdev_tx_t vxge_xmit(struct sk_buff *skb, struct net_device *dev) { struct vxge_fifo *fifo = NULL; diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 76764237cde..9509477f61f 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -347,7 +347,8 @@ static int yellowfin_open(struct net_device *dev); static void yellowfin_timer(unsigned long data); static void yellowfin_tx_timeout(struct net_device *dev); static void yellowfin_init_ring(struct net_device *dev); -static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t yellowfin_start_xmit(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance); static int yellowfin_rx(struct net_device *dev); static void yellowfin_error(struct net_device *dev, int intr_status); @@ -808,7 +809,8 @@ static void yellowfin_init_ring(struct net_device *dev) return; } -static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t yellowfin_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct yellowfin_private *yp = netdev_priv(dev); unsigned entry; diff --git a/drivers/net/znet.c b/drivers/net/znet.c index 7f9e14131a5..a0384b6f09b 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -156,7 +156,8 @@ struct netidblk { }; static int znet_open(struct net_device *dev); -static int znet_send_packet(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t znet_send_packet(struct sk_buff *skb, + struct net_device *dev); static irqreturn_t znet_interrupt(int irq, void *dev_id); static void znet_rx(struct net_device *dev); static int znet_close(struct net_device *dev); @@ -534,7 +535,7 @@ static void znet_tx_timeout (struct net_device *dev) netif_wake_queue (dev); } -static int znet_send_packet(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t znet_send_packet(struct sk_buff *skb, struct net_device *dev) { int ioaddr = dev->base_addr; struct znet_private *znet = netdev_priv(dev); -- cgit v1.2.3-18-g5258 From 8450ff8cd7fba6e78c07d7c14bf4dc582f8a6c3d Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Mon, 31 Aug 2009 12:32:14 +0000 Subject: ixgbe: Add support for the net_device_ops.ndo_fcoe_enable/disable to 82599 This adds support to the net_device_ops.ndo_fcoe_enable/disable for 82599. This consequently allows us to dynamically turn FCoE offload feature on or off upon incoming calls to ndo_fcoe_enable/disable. When this happens, FCoE offload features are enabled/disabled accordingly, and this is regardless of whether DCB being turned on or not. Signed-off-by: Yi Zou Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe.h | 2 + drivers/net/ixgbe/ixgbe_dcb_nl.c | 33 -------------- drivers/net/ixgbe/ixgbe_fcoe.c | 94 ++++++++++++++++++++++++++++++++++++++++ drivers/net/ixgbe/ixgbe_main.c | 2 + 4 files changed, 98 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index c983c89630a..daed0ac60ec 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -450,6 +450,8 @@ extern int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, extern int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, struct scatterlist *sgl, unsigned int sgc); extern int ixgbe_fcoe_ddp_put(struct net_device *netdev, u16 xid); +extern int ixgbe_fcoe_enable(struct net_device *netdev); +extern int ixgbe_fcoe_disable(struct net_device *netdev); #endif /* IXGBE_FCOE */ #endif /* _IXGBE_H_ */ diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index 34bca45fbd1..e05c62ac56b 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -139,23 +139,6 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE; } adapter->flags |= IXGBE_FLAG_DCB_ENABLED; -#ifdef IXGBE_FCOE - /* Turn on FCoE offload */ - if ((adapter->flags & IXGBE_FLAG_FCOE_CAPABLE) && - (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED))) { - adapter->flags |= IXGBE_FLAG_FCOE_ENABLED; - adapter->ring_feature[RING_F_FCOE].indices = - IXGBE_FCRETA_SIZE; - netdev->features |= NETIF_F_FCOE_CRC; - netdev->features |= NETIF_F_FSO; - netdev->features |= NETIF_F_FCOE_MTU; - netdev->vlan_features |= NETIF_F_FCOE_CRC; - netdev->vlan_features |= NETIF_F_FSO; - netdev->vlan_features |= NETIF_F_FCOE_MTU; - netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1; - netdev_features_change(netdev); - } -#endif /* IXGBE_FCOE */ ixgbe_init_interrupt_scheme(adapter); if (netif_running(netdev)) netdev->netdev_ops->ndo_open(netdev); @@ -174,22 +157,6 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) if (adapter->hw.mac.type == ixgbe_mac_82599EB) adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE; -#ifdef IXGBE_FCOE - /* Turn off FCoE offload */ - if (adapter->flags & (IXGBE_FLAG_FCOE_CAPABLE | - IXGBE_FLAG_FCOE_ENABLED)) { - adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED; - adapter->ring_feature[RING_F_FCOE].indices = 0; - netdev->features &= ~NETIF_F_FCOE_CRC; - netdev->features &= ~NETIF_F_FSO; - netdev->features &= ~NETIF_F_FCOE_MTU; - netdev->vlan_features &= ~NETIF_F_FCOE_CRC; - netdev->vlan_features &= ~NETIF_F_FSO; - netdev->vlan_features &= ~NETIF_F_FCOE_MTU; - netdev->fcoe_ddp_xid = 0; - netdev_features_change(netdev); - } -#endif /* IXGBE_FCOE */ ixgbe_init_interrupt_scheme(adapter); if (netif_running(netdev)) netdev->netdev_ops->ndo_open(netdev); diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index 28cf104e36c..26fe46fb13f 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -554,3 +554,97 @@ void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter) fcoe->pool = NULL; } } + +/** + * ixgbe_fcoe_enable - turn on FCoE offload feature + * @netdev: the corresponding netdev + * + * Turns on FCoE offload feature in 82599. + * + * Returns : 0 indicates success or -EINVAL on failure + */ +int ixgbe_fcoe_enable(struct net_device *netdev) +{ + int rc = -EINVAL; + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + + if (!(adapter->flags & IXGBE_FLAG_FCOE_CAPABLE)) + goto out_enable; + + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) + goto out_enable; + + DPRINTK(DRV, INFO, "Enabling FCoE offload features.\n"); + if (netif_running(netdev)) + netdev->netdev_ops->ndo_stop(netdev); + + ixgbe_clear_interrupt_scheme(adapter); + + adapter->flags |= IXGBE_FLAG_FCOE_ENABLED; + adapter->ring_feature[RING_F_FCOE].indices = IXGBE_FCRETA_SIZE; + netdev->features |= NETIF_F_FCOE_CRC; + netdev->features |= NETIF_F_FSO; + netdev->features |= NETIF_F_FCOE_MTU; + netdev->vlan_features |= NETIF_F_FCOE_CRC; + netdev->vlan_features |= NETIF_F_FSO; + netdev->vlan_features |= NETIF_F_FCOE_MTU; + netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1; + netdev_features_change(netdev); + + ixgbe_init_interrupt_scheme(adapter); + + if (netif_running(netdev)) + netdev->netdev_ops->ndo_open(netdev); + rc = 0; + +out_enable: + return rc; +} + +/** + * ixgbe_fcoe_disable - turn off FCoE offload feature + * @netdev: the corresponding netdev + * + * Turns off FCoE offload feature in 82599. + * + * Returns : 0 indicates success or -EINVAL on failure + */ +int ixgbe_fcoe_disable(struct net_device *netdev) +{ + int rc = -EINVAL; + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + if (!(adapter->flags & IXGBE_FLAG_FCOE_CAPABLE)) + goto out_disable; + + if (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) + goto out_disable; + + DPRINTK(DRV, INFO, "Disabling FCoE offload features.\n"); + if (netif_running(netdev)) + netdev->netdev_ops->ndo_stop(netdev); + + ixgbe_clear_interrupt_scheme(adapter); + + adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED; + adapter->ring_feature[RING_F_FCOE].indices = 0; + netdev->features &= ~NETIF_F_FCOE_CRC; + netdev->features &= ~NETIF_F_FSO; + netdev->features &= ~NETIF_F_FCOE_MTU; + netdev->vlan_features &= ~NETIF_F_FCOE_CRC; + netdev->vlan_features &= ~NETIF_F_FSO; + netdev->vlan_features &= ~NETIF_F_FCOE_MTU; + netdev->fcoe_ddp_xid = 0; + netdev_features_change(netdev); + + ixgbe_cleanup_fcoe(adapter); + + ixgbe_init_interrupt_scheme(adapter); + if (netif_running(netdev)) + netdev->netdev_ops->ndo_open(netdev); + rc = 0; + +out_disable: + return rc; +} diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 7e964a68988..30a58fbbeed 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -5377,6 +5377,8 @@ static const struct net_device_ops ixgbe_netdev_ops = { #ifdef IXGBE_FCOE .ndo_fcoe_ddp_setup = ixgbe_fcoe_ddp_get, .ndo_fcoe_ddp_done = ixgbe_fcoe_ddp_put, + .ndo_fcoe_enable = ixgbe_fcoe_enable, + .ndo_fcoe_disable = ixgbe_fcoe_disable, #endif /* IXGBE_FCOE */ }; -- cgit v1.2.3-18-g5258 From 6ee1652051f14d1c110f48a5b3ee037d63d0c2fa Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Mon, 31 Aug 2009 12:34:28 +0000 Subject: ixgbe: Add support for dcbnl_rtnl_ops.setapp/getapp Add support for dcbnl_rtnl_ops.setapp/getapp to set or get the current user priority bitmap for the given application protocol. Currently, 82599 only supports setapp/getapp for Fiber Channel over Ethernet (FCoE) protocol. Signed-off-by: Yi Zou Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe.h | 4 +++ drivers/net/ixgbe/ixgbe_dcb_nl.c | 60 +++++++++++++++++++++++++++++++++++++ drivers/net/ixgbe/ixgbe_fcoe.c | 64 ++++++++++++++++++++++++++++++++++++++++ drivers/net/ixgbe/ixgbe_fcoe.h | 4 +++ drivers/net/ixgbe/ixgbe_main.c | 2 ++ 5 files changed, 134 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index daed0ac60ec..dd688d45e9c 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -452,6 +452,10 @@ extern int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, extern int ixgbe_fcoe_ddp_put(struct net_device *netdev, u16 xid); extern int ixgbe_fcoe_enable(struct net_device *netdev); extern int ixgbe_fcoe_disable(struct net_device *netdev); +#ifdef CONFIG_IXGBE_DCB +extern u8 ixgbe_fcoe_getapp(struct ixgbe_adapter *adapter); +extern u8 ixgbe_fcoe_setapp(struct ixgbe_adapter *adapter, u8 up); +#endif /* CONFIG_IXGBE_DCB */ #endif /* IXGBE_FCOE */ #endif /* _IXGBE_H_ */ diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index e05c62ac56b..47d9dde82a8 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -480,6 +480,64 @@ static void ixgbe_dcbnl_setpfcstate(struct net_device *netdev, u8 state) return; } +/** + * ixgbe_dcbnl_getapp - retrieve the DCBX application user priority + * @netdev : the corresponding netdev + * @idtype : identifies the id as ether type or TCP/UDP port number + * @id: id is either ether type or TCP/UDP port number + * + * Returns : on success, returns a non-zero 802.1p user priority bitmap + * otherwise returns 0 as the invalid user priority bitmap to indicate an + * error. + */ +static u8 ixgbe_dcbnl_getapp(struct net_device *netdev, u8 idtype, u16 id) +{ + u8 rval = 0; + + switch (idtype) { + case DCB_APP_IDTYPE_ETHTYPE: +#ifdef IXGBE_FCOE + if (id == ETH_P_FCOE) + rval = ixgbe_fcoe_getapp(netdev_priv(netdev)); +#endif + break; + case DCB_APP_IDTYPE_PORTNUM: + break; + default: + break; + } + return rval; +} + +/** + * ixgbe_dcbnl_setapp - set the DCBX application user priority + * @netdev : the corresponding netdev + * @idtype : identifies the id as ether type or TCP/UDP port number + * @id: id is either ether type or TCP/UDP port number + * @up: the 802.1p user priority bitmap + * + * Returns : 0 on success or 1 on error + */ +static u8 ixgbe_dcbnl_setapp(struct net_device *netdev, + u8 idtype, u16 id, u8 up) +{ + u8 rval = 1; + + switch (idtype) { + case DCB_APP_IDTYPE_ETHTYPE: +#ifdef IXGBE_FCOE + if (id == ETH_P_FCOE) + rval = ixgbe_fcoe_setapp(netdev_priv(netdev), up); +#endif + break; + case DCB_APP_IDTYPE_PORTNUM: + break; + default: + break; + } + return rval; +} + struct dcbnl_rtnl_ops dcbnl_ops = { .getstate = ixgbe_dcbnl_get_state, .setstate = ixgbe_dcbnl_set_state, @@ -500,5 +558,7 @@ struct dcbnl_rtnl_ops dcbnl_ops = { .setnumtcs = ixgbe_dcbnl_setnumtcs, .getpfcstate = ixgbe_dcbnl_getpfcstate, .setpfcstate = ixgbe_dcbnl_setpfcstate, + .getapp = ixgbe_dcbnl_getapp, + .setapp = ixgbe_dcbnl_setapp, }; diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index 26fe46fb13f..0607cffbb21 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -27,6 +27,9 @@ #include "ixgbe.h" +#ifdef CONFIG_IXGBE_DCB +#include "ixgbe_dcb_82599.h" +#endif /* CONFIG_IXGBE_DCB */ #include #include #include @@ -648,3 +651,64 @@ int ixgbe_fcoe_disable(struct net_device *netdev) out_disable: return rc; } + +#ifdef CONFIG_IXGBE_DCB +/** + * ixgbe_fcoe_getapp - retrieves current user priority bitmap for FCoE + * @adapter : ixgbe adapter + * + * Finds out the corresponding user priority bitmap from the current + * traffic class that FCoE belongs to. Returns 0 as the invalid user + * priority bitmap to indicate an error. + * + * Returns : 802.1p user priority bitmap for FCoE + */ +u8 ixgbe_fcoe_getapp(struct ixgbe_adapter *adapter) +{ + int i; + u8 tc; + u32 up2tc; + + up2tc = IXGBE_READ_REG(&adapter->hw, IXGBE_RTTUP2TC); + for (i = 0; i < MAX_USER_PRIORITY; i++) { + tc = (u8)(up2tc >> (i * IXGBE_RTTUP2TC_UP_SHIFT)); + tc &= (MAX_TRAFFIC_CLASS - 1); + if (adapter->fcoe.tc == tc) + return 1 << i; + } + + return 0; +} + +/** + * ixgbe_fcoe_setapp - sets the user priority bitmap for FCoE + * @adapter : ixgbe adapter + * @up : 802.1p user priority bitmap + * + * Finds out the traffic class from the input user priority + * bitmap for FCoE. + * + * Returns : 0 on success otherwise returns 1 on error + */ +u8 ixgbe_fcoe_setapp(struct ixgbe_adapter *adapter, u8 up) +{ + int i; + u32 up2tc; + + /* valid user priority bitmap must not be 0 */ + if (up) { + /* from user priority to the corresponding traffic class */ + up2tc = IXGBE_READ_REG(&adapter->hw, IXGBE_RTTUP2TC); + for (i = 0; i < MAX_USER_PRIORITY; i++) { + if (up & (1 << i)) { + up2tc >>= (i * IXGBE_RTTUP2TC_UP_SHIFT); + up2tc &= (MAX_TRAFFIC_CLASS - 1); + adapter->fcoe.tc = (u8)up2tc; + return 0; + } + } + } + + return 1; +} +#endif /* CONFIG_IXGBE_DCB */ diff --git a/drivers/net/ixgbe/ixgbe_fcoe.h b/drivers/net/ixgbe/ixgbe_fcoe.h index c5b50026a89..b5dee7b3ef1 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.h +++ b/drivers/net/ixgbe/ixgbe_fcoe.h @@ -46,6 +46,9 @@ #define IXGBE_FCBUFF_MIN 4096 /* 4KB min */ #define IXGBE_FCOE_DDP_MAX 512 /* 9 bits xid */ +/* Default traffic class to use for FCoE */ +#define IXGBE_FCOE_DEFTC 3 + /* fcerr */ #define IXGBE_FCERR_BADCRC 0x00100000 @@ -59,6 +62,7 @@ struct ixgbe_fcoe_ddp { }; struct ixgbe_fcoe { + u8 tc; spinlock_t lock; struct pci_pool *pool; struct ixgbe_fcoe_ddp ddp[IXGBE_FCOE_DDP_MAX]; diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 30a58fbbeed..f907836eed2 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3801,6 +3801,8 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) adapter->flags |= IXGBE_FLAG_FCOE_CAPABLE; adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED; adapter->ring_feature[RING_F_FCOE].indices = 0; + /* Default traffic class to use for FCoE */ + adapter->fcoe.tc = IXGBE_FCOE_DEFTC; #endif /* IXGBE_FCOE */ } -- cgit v1.2.3-18-g5258 From ebb8e1d78c2f8b1737627ec260d7e39c4bd47385 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 1 Sep 2009 17:46:32 +0530 Subject: ath9k: Move generic hw timer intr handler to bottom-half There is no point handling this in hard irq, move it to tasklet. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 4fae699a53c..efee193801d 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -506,6 +506,10 @@ static void ath9k_tasklet(unsigned long data) sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC; } + if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) + if (status & ATH9K_INT_GENTIMER) + ath_gen_timer_isr(sc->sc_ah); + /* re-enable hardware interrupt */ ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); ath9k_ps_restore(sc); @@ -521,7 +525,8 @@ irqreturn_t ath_isr(int irq, void *dev) ATH9K_INT_TX | \ ATH9K_INT_BMISS | \ ATH9K_INT_CST | \ - ATH9K_INT_TSFOOR) + ATH9K_INT_TSFOOR | \ + ATH9K_INT_GENTIMER) struct ath_softc *sc = dev; struct ath_hw *ah = sc->sc_ah; @@ -602,10 +607,6 @@ irqreturn_t ath_isr(int irq, void *dev) sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; } - if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) - if (status & ATH9K_INT_GENTIMER) - ath_gen_timer_isr(ah); - chip_reset: ath_debug_stat_interrupt(sc, status); -- cgit v1.2.3-18-g5258 From 8f43161aa6bd7bfed0905d3de6cc660fd6b9c2bc Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 1 Sep 2009 17:46:33 +0530 Subject: ath9k: Call spin_lock_bh() on btcoex_lock As generic hw timer interrupt handler is moved to tasklet, we no more need to call spin_lock_irqsave(). Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/btcoex.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 8fb35674882..e8bfb01ee78 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -84,15 +84,14 @@ static void ath_btcoex_period_timer(unsigned long data) { struct ath_softc *sc = (struct ath_softc *) data; struct ath_btcoex_info *btinfo = &sc->btcoex_info; - unsigned long flags; ath_detect_bt_priority(sc); - spin_lock_irqsave(&btinfo->btcoex_lock, flags); + spin_lock_bh(&btinfo->btcoex_lock); ath_btcoex_bt_stomp(sc, btinfo, btinfo->bt_stomp_type); - spin_unlock_irqrestore(&btinfo->btcoex_lock, flags); + spin_unlock_bh(&btinfo->btcoex_lock); if (btinfo->btcoex_period != btinfo->btcoex_no_stomp) { if (btinfo->hw_timer_enabled) @@ -119,18 +118,17 @@ static void ath_btcoex_no_stomp_timer(void *arg) { struct ath_softc *sc = (struct ath_softc *)arg; struct ath_btcoex_info *btinfo = &sc->btcoex_info; - unsigned long flags; DPRINTF(sc, ATH_DBG_BTCOEX, "no stomp timer running \n"); - spin_lock_irqsave(&btinfo->btcoex_lock, flags); + spin_lock_bh(&btinfo->btcoex_lock); if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_NONE); else if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_LOW); - spin_unlock_irqrestore(&btinfo->btcoex_lock, flags); + spin_unlock_bh(&btinfo->btcoex_lock); } static int ath_init_btcoex_info(struct ath_hw *hw, -- cgit v1.2.3-18-g5258 From 051ae0bf7ff67c0a64485ac3b46a29aeb55a28dc Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 1 Sep 2009 15:32:55 +0300 Subject: rndis_wlan: use bool for on/off switches Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 402d3675776..dc2804f9a08 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -466,7 +466,7 @@ struct rndis_wlan_private { u32 param_workaround_interval; /* hardware state */ - int radio_on; + bool radio_on; int infra_mode; bool connected; u8 bssid[ETH_ALEN]; @@ -966,8 +966,8 @@ static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) } if (ret == 0) { memcpy(&priv->essid, ssid, sizeof(priv->essid)); - priv->radio_on = 1; - devdbg(usbdev, "set_essid: radio_on = 1"); + priv->radio_on = true; + devdbg(usbdev, "set_essid: radio_on = true"); } return ret; @@ -1028,7 +1028,7 @@ static bool is_associated(struct usbnet *usbdev) } -static int disassociate(struct usbnet *usbdev, int reset_ssid) +static int disassociate(struct usbnet *usbdev, bool reset_ssid) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_ssid ssid; @@ -1037,8 +1037,8 @@ static int disassociate(struct usbnet *usbdev, int reset_ssid) if (priv->radio_on) { ret = rndis_set_oid(usbdev, OID_802_11_DISASSOCIATE, NULL, 0); if (ret == 0) { - priv->radio_on = 0; - devdbg(usbdev, "disassociate: radio_on = 0"); + priv->radio_on = false; + devdbg(usbdev, "disassociate: radio_on = false"); if (reset_ssid) msleep(100); @@ -1234,7 +1234,7 @@ static int deauthenticate(struct usbnet *usbdev) { int ret; - ret = disassociate(usbdev, 1); + ret = disassociate(usbdev, true); set_default_iw_params(usbdev); return ret; } @@ -1634,7 +1634,7 @@ static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, */ if (type == TX_POWER_AUTOMATIC || dbm == get_bcm4320_power_dbm(priv)) { if (!priv->radio_on) - disassociate(usbdev, 1); /* turn on radio */ + disassociate(usbdev, true); /* turn on radio */ return 0; } @@ -1923,7 +1923,7 @@ static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, return ret; err_turn_radio_on: - disassociate(usbdev, 1); + disassociate(usbdev, true); return ret; } @@ -2031,7 +2031,7 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, return ret; err_turn_radio_on: - disassociate(usbdev, 1); + disassociate(usbdev, true); return ret; } @@ -2823,8 +2823,8 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) WIPHY_PARAM_FRAG_THRESHOLD | WIPHY_PARAM_RTS_THRESHOLD); /* turn radio on */ - priv->radio_on = 1; - disassociate(usbdev, 1); + priv->radio_on = true; + disassociate(usbdev, true); netif_carrier_off(usbdev->net); return 0; @@ -2846,7 +2846,7 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); /* turn radio off */ - disassociate(usbdev, 0); + disassociate(usbdev, false); cancel_delayed_work_sync(&priv->dev_poller_work); cancel_delayed_work_sync(&priv->scan_work); @@ -2894,7 +2894,7 @@ static int rndis_wlan_stop(struct usbnet *usbdev) devdbg(usbdev, "rndis_wlan_stop"); - retval = disassociate(usbdev, 0); + retval = disassociate(usbdev, false); priv->work_pending = 0; cancel_delayed_work_sync(&priv->dev_poller_work); -- cgit v1.2.3-18-g5258 From c5c4fe90e399e4c1265414249c33429c19a16ea8 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 1 Sep 2009 15:33:00 +0300 Subject: rndis_wlan: cleanup - remove double newlines between functions - remove commented out function (rndis_set_config_parameter_u32()) - coding style fix in rndis_set_config_parameter_str() - add comment banners between function sections Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 62 +++++---------------------------------- 1 file changed, 7 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index dc2804f9a08..add2eb8a1c5 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -560,7 +560,6 @@ static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev) return (struct rndis_wlan_private *)dev->driver_priv; } - static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv) { switch (priv->param_power_output) { @@ -576,7 +575,6 @@ static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv) } } - static bool is_wpa_key(struct rndis_wlan_private *priv, int idx) { int cipher = priv->encr_keys[idx].cipher; @@ -585,7 +583,6 @@ static bool is_wpa_key(struct rndis_wlan_private *priv, int idx) cipher == WLAN_CIPHER_SUITE_TKIP); } - static int rndis_cipher_to_alg(u32 cipher) { switch (cipher) { @@ -613,7 +610,6 @@ static int rndis_akm_suite_to_key_mgmt(u32 akm_suite) } } - #ifdef DEBUG static const char *oid_to_string(__le32 oid) { @@ -675,7 +671,6 @@ static const char *oid_to_string(__le32 oid) } #endif - /* translate error code */ static int rndis_error_status(__le32 rndis_status) { @@ -699,7 +694,6 @@ static int rndis_error_status(__le32 rndis_status) return ret; } - static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); @@ -758,7 +752,6 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) return ret; } - static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); @@ -817,7 +810,6 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) return ret; } - static int rndis_reset(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -840,7 +832,6 @@ static int rndis_reset(struct usbnet *usbdev) return 0; } - /* * Specs say that we can only set config parameters only soon after device * initialization. @@ -927,16 +918,9 @@ static int rndis_set_config_parameter(struct usbnet *dev, char *param, static int rndis_set_config_parameter_str(struct usbnet *dev, char *param, char *value) { - return(rndis_set_config_parameter(dev, param, 2, value)); + return rndis_set_config_parameter(dev, param, 2, value); } -/*static int rndis_set_config_parameter_u32(struct usbnet *dev, - char *param, u32 value) -{ - return(rndis_set_config_parameter(dev, param, 0, &value)); -}*/ - - /* * data conversion functions */ @@ -946,7 +930,6 @@ static int level_to_qual(int level) return qual >= 0 ? (qual <= 100 ? qual : 100) : 0; } - /* * common functions */ @@ -1027,7 +1010,6 @@ static bool is_associated(struct usbnet *usbdev) return (ret == 0 && !is_zero_ether_addr(bssid)); } - static int disassociate(struct usbnet *usbdev, bool reset_ssid) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -1064,7 +1046,6 @@ static int disassociate(struct usbnet *usbdev, bool reset_ssid) return ret; } - static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version, enum nl80211_auth_type auth_type, int keymgmt) { @@ -1109,7 +1090,6 @@ static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version, return 0; } - static int set_priv_filter(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -1127,7 +1107,6 @@ static int set_priv_filter(struct usbnet *usbdev) sizeof(tmp)); } - static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -1163,7 +1142,6 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) return 0; } - static int set_infra_mode(struct usbnet *usbdev, int mode) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -1189,7 +1167,6 @@ static int set_infra_mode(struct usbnet *usbdev, int mode) return 0; } - static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold) { __le32 tmp; @@ -1204,7 +1181,6 @@ static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold) sizeof(tmp)); } - static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold) { __le32 tmp; @@ -1219,7 +1195,6 @@ static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold) sizeof(tmp)); } - static void set_default_iw_params(struct usbnet *usbdev) { set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); @@ -1229,7 +1204,6 @@ static void set_default_iw_params(struct usbnet *usbdev) set_encr_mode(usbdev, RNDIS_WLAN_ALG_NONE, RNDIS_WLAN_ALG_NONE); } - static int deauthenticate(struct usbnet *usbdev) { int ret; @@ -1239,7 +1213,6 @@ static int deauthenticate(struct usbnet *usbdev) return ret; } - static int set_channel(struct usbnet *usbdev, int channel) { struct ndis_80211_conf config; @@ -1270,7 +1243,6 @@ static int set_channel(struct usbnet *usbdev, int channel) return ret; } - /* index must be 0 - N, as per NDIS */ static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, int index) @@ -1322,7 +1294,6 @@ static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, return 0; } - static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, int index, const u8 *addr, const u8 *rx_seq, int seq_len, u32 cipher, int flags) @@ -1417,7 +1388,6 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, return 0; } - static int restore_key(struct usbnet *usbdev, int key_idx) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -1436,7 +1406,6 @@ static int restore_key(struct usbnet *usbdev, int key_idx) return add_wep_key(usbdev, key.material, key.len, key_idx); } - static void restore_keys(struct usbnet *usbdev) { int i; @@ -1445,13 +1414,11 @@ static void restore_keys(struct usbnet *usbdev) restore_key(usbdev, i); } - static void clear_key(struct rndis_wlan_private *priv, int idx) { memset(&priv->encr_keys[idx], 0, sizeof(priv->encr_keys[idx])); } - /* remove_key is for both wep and wpa */ static int remove_key(struct usbnet *usbdev, int index, const u8 *bssid) { @@ -1508,7 +1475,6 @@ static int remove_key(struct usbnet *usbdev, int index, const u8 *bssid) return 0; } - static void set_multicast_list(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -1568,7 +1534,6 @@ static void set_multicast_list(struct usbnet *usbdev) le32_to_cpu(filter), ret); } - /* * cfg80211 ops */ @@ -1597,7 +1562,6 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, return set_infra_mode(usbdev, mode); } - static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed) { struct rndis_wlan_private *priv = wiphy_priv(wiphy); @@ -1619,7 +1583,6 @@ static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed) return 0; } - static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, int dbm) { @@ -1642,7 +1605,6 @@ static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, return -ENOTSUPP; } - static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm) { struct rndis_wlan_private *priv = wiphy_priv(wiphy); @@ -1655,7 +1617,6 @@ static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm) return 0; } - #define SCAN_DELAY_JIFFIES (6 * HZ) static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request) @@ -1692,7 +1653,6 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, return ret; } - static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev, struct ndis_80211_bssid_ex *bssid) { @@ -1741,7 +1701,6 @@ static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev, GFP_KERNEL); } - static int rndis_check_bssid_list(struct usbnet *usbdev) { void *buf = NULL; @@ -1790,7 +1749,6 @@ out: return ret; } - static void rndis_get_scan_results(struct work_struct *work) { struct rndis_wlan_private *priv = @@ -2175,7 +2133,9 @@ static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev, return 0; } - +/* + * workers, indication handlers, device poller + */ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -2293,7 +2253,6 @@ static void rndis_wlan_set_multicast_list(struct net_device *dev) queue_work(priv->workqueue, &priv->work); } - static void rndis_wlan_auth_indication(struct usbnet *usbdev, struct ndis_80211_status_indication *indication, int len) @@ -2476,7 +2435,6 @@ static void rndis_wlan_media_specific_indication(struct usbnet *usbdev, } } - static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -2523,7 +2481,6 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) } } - static int rndis_wlan_get_caps(struct usbnet *usbdev) { struct { @@ -2560,7 +2517,6 @@ static int rndis_wlan_get_caps(struct usbnet *usbdev) return retval; } - #define DEVICE_POLLER_JIFFIES (HZ) static void rndis_device_poller(struct work_struct *work) { @@ -2632,7 +2588,9 @@ end: update_jiffies); } - +/* + * driver/device initialization + */ static int bcm4320a_early_init(struct usbnet *usbdev) { /* bcm4320a doesn't handle configuration parameters well. Try @@ -2642,7 +2600,6 @@ static int bcm4320a_early_init(struct usbnet *usbdev) return 0; } - static int bcm4320b_early_init(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -2721,7 +2678,6 @@ static const struct net_device_ops rndis_wlan_netdev_ops = { .ndo_set_multicast_list = rndis_wlan_set_multicast_list, }; - static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) { struct wiphy *wiphy; @@ -2840,7 +2796,6 @@ fail: return retval; } - static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -2863,7 +2818,6 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) wiphy_free(priv->wdev.wiphy); } - static int rndis_wlan_reset(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -2885,7 +2839,6 @@ static int rndis_wlan_reset(struct usbnet *usbdev) return deauthenticate(usbdev); } - static int rndis_wlan_stop(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -2916,7 +2869,6 @@ static int rndis_wlan_stop(struct usbnet *usbdev) return retval; } - static const struct driver_info bcm4320b_info = { .description = "Wireless RNDIS device, BCM4320b based", .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT | -- cgit v1.2.3-18-g5258 From 53d27eaf55fb5a6e820d8e3759588473826d659e Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 1 Sep 2009 15:33:06 +0300 Subject: rndis_wlan: fix sparse endianess warnings Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index add2eb8a1c5..54175b6fa86 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -253,8 +253,8 @@ struct ndis_80211_pmkid_cand_list { struct ndis_80211_status_indication { __le32 status_type; union { - enum ndis_80211_media_stream_mode media_stream_mode; - enum ndis_80211_radio_status radio_status; + __le32 media_stream_mode; + __le32 radio_status; struct ndis_80211_auth_request auth_request[0]; struct ndis_80211_pmkid_cand_list cand_list; } u; @@ -1296,7 +1296,7 @@ static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, int index, const u8 *addr, const u8 *rx_seq, - int seq_len, u32 cipher, int flags) + int seq_len, u32 cipher, __le32 flags) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_key ndis_key; @@ -2023,7 +2023,7 @@ static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev, { struct rndis_wlan_private *priv = wiphy_priv(wiphy); struct usbnet *usbdev = priv->usbdev; - int flags; + __le32 flags; devdbg(usbdev, "rndis_add_key(%i, %pM, %08x)", key_index, mac_addr, params->cipher); -- cgit v1.2.3-18-g5258 From 2b7dcfb7d01c9fc9efc6e39618cbf495a6051f9a Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 1 Sep 2009 15:33:11 +0300 Subject: rndis_wlan: remove 'select WIRELESS_EXT' in Kconfig Since rndis_wlan is now converted to cfg80211, WIRELESS_EXT isn't required anymore. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index dda7cc2e1f5..623897f2b0c 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -337,7 +337,6 @@ config USB_NET_RNDIS_WLAN select USB_USBNET select USB_NET_CDCETHER select USB_NET_RNDIS_HOST - select WIRELESS_EXT ---help--- This is a driver for wireless RNDIS devices. These are USB based adapters found in devices such as: -- cgit v1.2.3-18-g5258 From ae73abf2350de7cbfc5c46a936f4d2a532b36679 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 1 Sep 2009 15:13:58 +0200 Subject: iwmc3200wifi: invalidate profile when necessary before connect If cfg80211 requests to connect when we have already had an active profile, invalidate the current profile first before sending a new profile to UMAC. Signed-off-by: Zhu Yi Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index a6e852f4f92..789ef5ca88b 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -326,11 +326,8 @@ static int iwm_cfg80211_change_iface(struct wiphy *wiphy, iwm->umac_profile->mode = cpu_to_le32(iwm->conf.mode); - if (iwm->umac_profile_active) { - int ret = iwm_invalidate_mlme_profile(iwm); - if (ret < 0) - IWM_ERR(iwm, "Couldn't invalidate profile\n"); - } + if (iwm->umac_profile_active) + iwm_invalidate_mlme_profile(iwm); return 0; } @@ -573,6 +570,14 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, if (!sme->ssid) return -EINVAL; + if (iwm->umac_profile_active) { + ret = iwm_invalidate_mlme_profile(iwm); + if (ret) { + IWM_ERR(iwm, "Couldn't invalidate profile\n"); + return ret; + } + } + if (chan) iwm->channel = ieee80211_frequency_to_channel(chan->center_freq); -- cgit v1.2.3-18-g5258 From b90a5c9561d3f75f906a84613cc0071121143fb6 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 1 Sep 2009 15:13:59 +0200 Subject: iwmc3200wifi: Set WEP key from connect When connect is called with the LEGACY_PSK authentication type set, and a proper sme->key, we need to set the WEP key straight after setting the profile otherwise the authentication will never start. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 44 +++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 789ef5ca88b..d8bb723d88d 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -562,6 +562,7 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, { struct iwm_priv *iwm = wiphy_to_iwm(wiphy); struct ieee80211_channel *chan = sme->channel; + struct key_params key_param; int ret; if (!test_bit(IWM_STATUS_READY, &iwm->status)) @@ -619,7 +620,48 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, return ret; } - return iwm_send_mlme_profile(iwm); + /* + * We save the WEP key in case we want to do shared authentication. + * We have to do it so because UMAC will assert whenever it gets a + * key before a profile. + */ + if (sme->key) { + key_param.key = kmemdup(sme->key, sme->key_len, GFP_KERNEL); + if (key_param.key == NULL) + return -ENOMEM; + key_param.key_len = sme->key_len; + key_param.seq_len = 0; + key_param.cipher = sme->crypto.ciphers_pairwise[0]; + + ret = iwm_key_init(&iwm->keys[sme->key_idx], sme->key_idx, + NULL, &key_param); + kfree(key_param.key); + if (ret < 0) { + IWM_ERR(iwm, "Invalid key_params\n"); + return ret; + } + + iwm->default_key = sme->key_idx; + } + + ret = iwm_send_mlme_profile(iwm); + + if (iwm->umac_profile->sec.auth_type != UMAC_AUTH_TYPE_LEGACY_PSK || + sme->key == NULL) + return ret; + + /* + * We want to do shared auth. + * We need to actually set the key we previously cached, + * and then tell the UMAC it's the default one. + * That will trigger the auth+assoc UMAC machinery, and again, + * this must be done after setting the profile. + */ + ret = iwm_set_key(iwm, 0, &iwm->keys[sme->key_idx]); + if (ret < 0) + return ret; + + return iwm_set_tx_key(iwm, iwm->default_key); } static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, -- cgit v1.2.3-18-g5258 From d041811d931d4f515fd58e222757cbc7d6375db4 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 1 Sep 2009 15:14:00 +0200 Subject: iwmc3200wifi: Fix sparse warning iwm_cfg80211_get_station() should be static. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index d8bb723d88d..2784b089f49 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -238,8 +238,9 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy, return iwm_set_tx_key(iwm, key_index); } -int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, - u8 *mac, struct station_info *sinfo) +static int iwm_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *ndev, + u8 *mac, struct station_info *sinfo) { struct iwm_priv *iwm = ndev_to_iwm(ndev); -- cgit v1.2.3-18-g5258 From de15fd31fcabb4b81a556736dd67ec4f71462f07 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 1 Sep 2009 15:14:01 +0200 Subject: iwmc3200wifi: use cfg80211_roamed to send roam event The device sends connection terminated and [re]association success (or failure) events when roaming occours. The patch uses cfg80211_roamed instead of cfg80211_connect_result to notify SME for roaming. Signed-off-by: Zhu Yi Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 2 +- drivers/net/wireless/iwmc3200wifi/commands.c | 1 + drivers/net/wireless/iwmc3200wifi/iwm.h | 2 +- drivers/net/wireless/iwmc3200wifi/rx.c | 26 ++++++++++++++++++++------ 4 files changed, 23 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 2784b089f49..a56a2b0ac99 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -673,7 +673,7 @@ static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active); if (iwm->umac_profile_active) - return iwm_invalidate_mlme_profile(iwm); + iwm_invalidate_mlme_profile(iwm); return 0; } diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index a68a2aff3c1..23b52fa2605 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -756,6 +756,7 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm) return ret; } + set_bit(IWM_STATUS_SME_CONNECTING, &iwm->status); return 0; } diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 7a51bc340fd..f054cc828d8 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -175,7 +175,7 @@ struct iwm_key { #define IWM_STATUS_READY 0 #define IWM_STATUS_SCANNING 1 #define IWM_STATUS_SCAN_ABORTING 2 -#define IWM_STATUS_ASSOCIATING 3 +#define IWM_STATUS_SME_CONNECTING 3 #define IWM_STATUS_ASSOCIATED 4 struct iwm_tx_queue { diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 86079a187ee..9e6f2cd38d6 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -487,8 +487,6 @@ static int iwm_mlme_assoc_start(struct iwm_priv *iwm, u8 *buf, start = (struct iwm_umac_notif_assoc_start *)buf; - set_bit(IWM_STATUS_ASSOCIATING, &iwm->status); - IWM_DBG_MLME(iwm, INFO, "Association with %pM Started, reason: %d\n", start->bssid, le32_to_cpu(start->roam_reason)); @@ -507,14 +505,23 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n", complete->bssid, complete->status); - clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status); - switch (le32_to_cpu(complete->status)) { case UMAC_ASSOC_COMPLETE_SUCCESS: set_bit(IWM_STATUS_ASSOCIATED, &iwm->status); memcpy(iwm->bssid, complete->bssid, ETH_ALEN); iwm->channel = complete->channel; + /* Internal roaming state, avoid notifying SME. */ + if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status) + && iwm->conf.mode == UMAC_MODE_BSS) { + cfg80211_roamed(iwm_to_ndev(iwm), + complete->bssid, + iwm->req_ie, iwm->req_ie_len, + iwm->resp_ie, iwm->resp_ie_len, + GFP_KERNEL); + break; + } + iwm_link_on(iwm); if (iwm->conf.mode == UMAC_MODE_IBSS) @@ -531,6 +538,11 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, memset(iwm->bssid, 0, ETH_ALEN); iwm->channel = 0; + /* Internal roaming state, avoid notifying SME. */ + if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status) + && iwm->conf.mode == UMAC_MODE_BSS) + break; + iwm_link_off(iwm); if (iwm->conf.mode == UMAC_MODE_IBSS) @@ -540,6 +552,7 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL); + break; default: break; } @@ -562,7 +575,7 @@ static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf, IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n", le32_to_cpu(invalid->reason)); - clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status); + clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status); clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); iwm->umac_profile_active = 0; @@ -813,7 +826,8 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf, iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable, iwm->resp_ie_len, GFP_KERNEL); } else { - IWM_ERR(iwm, "Unsupported management frame"); + IWM_ERR(iwm, "Unsupported management frame: 0x%x", + cpu_to_le16(mgt->frame_control)); return 0; } -- cgit v1.2.3-18-g5258 From c7436273889e0ce511b317041f35344e92344885 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 1 Sep 2009 15:14:02 +0200 Subject: iwmc3200wifi: add disconnect work When the driver receives "connection terminated" event from device, it could be caused by 2 reasons: the firmware is roaming or the connection is lost (AP disappears). For the former, an association complete event is supposed to come within 3 seconds. For the latter, the driver won't receive any event except the connection terminated. So we kick a delayed work (5*HZ) when we receive the connection terminated event. It will be canceled if it turns out to be a roaming event later. Otherwise we notify SME and userspace the disconnection. Signed-off-by: Zhu Yi Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/iwm.h | 1 + drivers/net/wireless/iwmc3200wifi/main.c | 21 +++++++++++++++++++++ drivers/net/wireless/iwmc3200wifi/rx.c | 32 +++++++++++++++++++++++++++----- 3 files changed, 49 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index f054cc828d8..da49df6f402 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -273,6 +273,7 @@ struct iwm_priv { struct iw_statistics wstats; struct delayed_work stats_request; + struct delayed_work disconnect; struct iwm_debugfs dbg; diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index cf2574442b5..c41fa8c5fa1 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -108,6 +108,26 @@ static void iwm_statistics_request(struct work_struct *work) iwm_send_umac_stats_req(iwm, 0); } +static void iwm_disconnect_work(struct work_struct *work) +{ + struct iwm_priv *iwm = + container_of(work, struct iwm_priv, disconnect.work); + + if (iwm->umac_profile_active) + iwm_invalidate_mlme_profile(iwm); + + clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); + iwm->umac_profile_active = 0; + memset(iwm->bssid, 0, ETH_ALEN); + iwm->channel = 0; + + iwm_link_off(iwm); + + wake_up_interruptible(&iwm->mlme_queue); + + cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL); +} + int __iwm_up(struct iwm_priv *iwm); int __iwm_down(struct iwm_priv *iwm); @@ -198,6 +218,7 @@ int iwm_priv_init(struct iwm_priv *iwm) spin_lock_init(&iwm->cmd_lock); iwm->scan_id = 1; INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request); + INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work); INIT_WORK(&iwm->reset_worker, iwm_reset_worker); INIT_LIST_HEAD(&iwm->bss_list); diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 9e6f2cd38d6..4d9793e6865 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -514,6 +514,7 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, /* Internal roaming state, avoid notifying SME. */ if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status) && iwm->conf.mode == UMAC_MODE_BSS) { + cancel_delayed_work(&iwm->disconnect); cfg80211_roamed(iwm_to_ndev(iwm), complete->bssid, iwm->req_ie, iwm->req_ie_len, @@ -540,8 +541,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, /* Internal roaming state, avoid notifying SME. */ if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status) - && iwm->conf.mode == UMAC_MODE_BSS) + && iwm->conf.mode == UMAC_MODE_BSS) { + cancel_delayed_work(&iwm->disconnect); break; + } iwm_link_off(iwm); @@ -569,11 +572,18 @@ static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf, struct iwm_wifi_cmd *cmd) { struct iwm_umac_notif_profile_invalidate *invalid; + u32 reason; invalid = (struct iwm_umac_notif_profile_invalidate *)buf; + reason = le32_to_cpu(invalid->reason); + + IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n", reason); - IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n", - le32_to_cpu(invalid->reason)); + if (reason != UMAC_PROFILE_INVALID_REQUEST && + test_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)) + cfg80211_connect_result(iwm_to_ndev(iwm), NULL, NULL, 0, NULL, + 0, WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status); clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); @@ -589,6 +599,19 @@ static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf, return 0; } +#define IWM_DISCONNECT_INTERVAL (5 * HZ) + +static int iwm_mlme_connection_terminated(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + IWM_DBG_MLME(iwm, DBG, "Connection terminated\n"); + + schedule_delayed_work(&iwm->disconnect, IWM_DISCONNECT_INTERVAL); + + return 0; +} + static int iwm_mlme_scan_complete(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, struct iwm_wifi_cmd *cmd) @@ -848,8 +871,7 @@ static int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf, case WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE: return iwm_mlme_profile_invalidate(iwm, buf, buf_size, cmd); case WIFI_IF_NTFY_CONNECTION_TERMINATED: - IWM_DBG_MLME(iwm, DBG, "Connection terminated\n"); - break; + return iwm_mlme_connection_terminated(iwm, buf, buf_size, cmd); case WIFI_IF_NTFY_SCAN_COMPLETE: return iwm_mlme_scan_complete(iwm, buf, buf_size, cmd); case WIFI_IF_NTFY_STA_TABLE_CHANGE: -- cgit v1.2.3-18-g5258 From 31452420ca956f2cf37f705c869e265c33894f07 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 1 Sep 2009 15:14:03 +0200 Subject: iwmc3200wifi: fix misuse of le16_to_cpu Also mark some functions static. Signed-off-by: Zhu Yi Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/main.c | 8 ++++---- drivers/net/wireless/iwmc3200wifi/rx.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index c41fa8c5fa1..6cf2f0c0911 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -128,8 +128,8 @@ static void iwm_disconnect_work(struct work_struct *work) cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL); } -int __iwm_up(struct iwm_priv *iwm); -int __iwm_down(struct iwm_priv *iwm); +static int __iwm_up(struct iwm_priv *iwm); +static int __iwm_down(struct iwm_priv *iwm); static void iwm_reset_worker(struct work_struct *work) { @@ -559,7 +559,7 @@ static int iwm_channels_init(struct iwm_priv *iwm) return 0; } -int __iwm_up(struct iwm_priv *iwm) +static int __iwm_up(struct iwm_priv *iwm) { int ret; struct iwm_notif *notif_reboot, *notif_ack = NULL; @@ -693,7 +693,7 @@ int iwm_up(struct iwm_priv *iwm) return ret; } -int __iwm_down(struct iwm_priv *iwm) +static int __iwm_down(struct iwm_priv *iwm) { int ret; diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 4d9793e6865..2daa58633e6 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -850,7 +850,7 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf, iwm->resp_ie_len, GFP_KERNEL); } else { IWM_ERR(iwm, "Unsupported management frame: 0x%x", - cpu_to_le16(mgt->frame_control)); + le16_to_cpu(mgt->frame_control)); return 0; } -- cgit v1.2.3-18-g5258 From d04bd6283cf7433d56f3d8f648f1d6963fda4fdc Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 1 Sep 2009 15:14:04 +0200 Subject: iwmc3200wifi: New initial LMAC calibration The LMAC calibration API got broken mostly by having a configuration bitmap being different than the result one. This patch tries to address that issue by correctly running calibrations with the newest firmwares, and keeping a backward compatibility fallback path for older firmwares, where the configuration and result bitmaps were identical. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/fw.c | 56 ++++++++++++++++++++++---------- drivers/net/wireless/iwmc3200wifi/iwm.h | 1 + drivers/net/wireless/iwmc3200wifi/lmac.h | 15 +++++++++ drivers/net/wireless/iwmc3200wifi/main.c | 7 +++- 4 files changed, 61 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c index 0f32cab9ced..6b0bcad758c 100644 --- a/drivers/net/wireless/iwmc3200wifi/fw.c +++ b/drivers/net/wireless/iwmc3200wifi/fw.c @@ -261,6 +261,33 @@ static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name) cpu_to_le32(UMAC_RST_CTRL_FLG_LARC_CLK_EN), 0); } +static int iwm_init_calib(struct iwm_priv *iwm, unsigned long cfg_bitmap, + unsigned long expected_bitmap, u8 rx_iq_cmd) +{ + /* Read RX IQ calibration result from EEPROM */ + if (test_bit(rx_iq_cmd, &cfg_bitmap)) { + iwm_store_rxiq_calib_result(iwm); + set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map); + } + + iwm_send_prio_table(iwm); + iwm_send_init_calib_cfg(iwm, cfg_bitmap); + + while (iwm->calib_done_map != expected_bitmap) { + if (iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION, + IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT)) { + IWM_DBG_FW(iwm, DBG, "Initial calibration timeout\n"); + return -ETIMEDOUT; + } + + IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: " + "0x%lx, expected calibrations: 0x%lx\n", + iwm->calib_done_map, expected_bitmap); + } + + return 0; +} + /* * We currently have to load 3 FWs: * 1) The UMAC (Upper MAC). @@ -276,6 +303,7 @@ static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name) int iwm_load_fw(struct iwm_priv *iwm) { unsigned long init_calib_map, periodic_calib_map; + unsigned long expected_calib_map; int ret; /* We first start downloading the UMAC */ @@ -317,27 +345,21 @@ int iwm_load_fw(struct iwm_priv *iwm) } init_calib_map = iwm->conf.calib_map & IWM_CALIB_MAP_INIT_MSK; + expected_calib_map = iwm->conf.expected_calib_map & + IWM_CALIB_MAP_INIT_MSK; periodic_calib_map = IWM_CALIB_MAP_PER_LMAC(iwm->conf.calib_map); - /* Read RX IQ calibration result from EEPROM */ - if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &init_calib_map)) { - iwm_store_rxiq_calib_result(iwm); - set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map); - } - - iwm_send_prio_table(iwm); - iwm_send_init_calib_cfg(iwm, init_calib_map); - - while (iwm->calib_done_map != init_calib_map) { - ret = iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION, - IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT); - if (ret) { - IWM_ERR(iwm, "Wait for calibration result timeout\n"); + ret = iwm_init_calib(iwm, init_calib_map, expected_calib_map, + CALIB_CFG_RX_IQ_IDX); + if (ret < 0) { + /* Let's try the old way */ + ret = iwm_init_calib(iwm, expected_calib_map, + expected_calib_map, + PHY_CALIBRATE_RX_IQ_CMD); + if (ret < 0) { + IWM_ERR(iwm, "Calibration result timeout\n"); goto out; } - IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: " - "0x%lx, requested calibrations: 0x%lx\n", - iwm->calib_done_map, init_calib_map); } /* Handle LMAC CALIBRATION_COMPLETE notification */ diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index da49df6f402..74964ee93bb 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -64,6 +64,7 @@ struct iwm_conf { u32 sdio_ior_timeout; unsigned long calib_map; + unsigned long expected_calib_map; bool reset_on_fatal_err; bool auto_connect; bool wimax_not_present; diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h index 19213e165f5..6c1a14c4480 100644 --- a/drivers/net/wireless/iwmc3200wifi/lmac.h +++ b/drivers/net/wireless/iwmc3200wifi/lmac.h @@ -396,9 +396,24 @@ enum { CALIBRATION_CMD_NUM, }; +enum { + CALIB_CFG_RX_BB_IDX = 0, + CALIB_CFG_DC_IDX = 1, + CALIB_CFG_LO_IDX = 2, + CALIB_CFG_TX_IQ_IDX = 3, + CALIB_CFG_RX_IQ_IDX = 4, + CALIB_CFG_NOISE_IDX = 5, + CALIB_CFG_CRYSTAL_IDX = 6, + CALIB_CFG_TEMPERATURE_IDX = 7, + CALIB_CFG_PAPD_IDX = 8, + CALIB_CFG_LAST_IDX = CALIB_CFG_PAPD_IDX, + CALIB_CFG_MODULE_NUM, +}; + #define IWM_CALIB_MAP_INIT_MSK 0xFFFF #define IWM_CALIB_MAP_PER_LMAC(m) ((m & 0xFF0000) >> 16) #define IWM_CALIB_MAP_PER_UMAC(m) ((m & 0xFF000000) >> 24) +#define IWM_CALIB_OPCODE_TO_INDEX(op) (op - PHY_CALIBRATE_OPCODES_NUM) struct iwm_lmac_calib_hdr { u8 opcode; diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 6cf2f0c0911..fc7fce44a9d 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -53,7 +53,12 @@ static struct iwm_conf def_iwm_conf = { .sdio_ior_timeout = 5000, - .calib_map = BIT(PHY_CALIBRATE_DC_CMD) | + .calib_map = BIT(CALIB_CFG_DC_IDX) | + BIT(CALIB_CFG_LO_IDX) | + BIT(CALIB_CFG_TX_IQ_IDX) | + BIT(CALIB_CFG_RX_IQ_IDX) | + BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD), + .expected_calib_map = BIT(PHY_CALIBRATE_DC_CMD) | BIT(PHY_CALIBRATE_LO_CMD) | BIT(PHY_CALIBRATE_TX_IQ_CMD) | BIT(PHY_CALIBRATE_RX_IQ_CMD) | -- cgit v1.2.3-18-g5258 From d210176eaaed0c7883caba52665bcfb5d420c660 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 1 Sep 2009 15:14:05 +0200 Subject: iwmc3200wifi: Handle UMAC stalls and UMAC assert properly When UMAC stalls or asserts, we want to reset the device. But when we're associated, the current reset worker will end up calling cfg80211_connect_result() with the cfg80211 sme layer knowing that we're reassociating. That ends up with some ugly warnings. With this patch we're telling the upper layer that we've roamed if reassociation succeeds, and that we're disconnected if it fails. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/iwm.h | 2 ++ drivers/net/wireless/iwmc3200wifi/main.c | 18 +++++++++++++++--- drivers/net/wireless/iwmc3200wifi/rx.c | 29 +++++++++++++++++++++++------ 3 files changed, 40 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 74964ee93bb..f5c2d6f3fd4 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -178,6 +178,7 @@ struct iwm_key { #define IWM_STATUS_SCAN_ABORTING 2 #define IWM_STATUS_SME_CONNECTING 3 #define IWM_STATUS_ASSOCIATED 4 +#define IWM_STATUS_RESETTING 5 struct iwm_tx_queue { int id; @@ -317,6 +318,7 @@ int iwm_mode_to_nl80211_iftype(int mode); int iwm_priv_init(struct iwm_priv *iwm); void iwm_priv_deinit(struct iwm_priv *iwm); void iwm_reset(struct iwm_priv *iwm); +void iwm_resetting(struct iwm_priv *iwm); void iwm_tx_credit_init_pools(struct iwm_priv *iwm, struct iwm_umac_notif_alive *alive); int iwm_tx_credit_alloc(struct iwm_priv *iwm, int id, int nb); diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index fc7fce44a9d..6a5b76acb64 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -187,7 +187,8 @@ static void iwm_reset_worker(struct work_struct *work) memcpy(iwm->umac_profile, profile, sizeof(*profile)); iwm_send_mlme_profile(iwm); kfree(profile); - } + } else + clear_bit(IWM_STATUS_RESETTING, &iwm->status); out: mutex_unlock(&iwm->mutex); @@ -200,7 +201,7 @@ static void iwm_watchdog(unsigned long data) IWM_WARN(iwm, "Watchdog expired: UMAC stalls!\n"); if (modparam_reset) - schedule_work(&iwm->reset_worker); + iwm_resetting(iwm); } int iwm_priv_init(struct iwm_priv *iwm) @@ -284,7 +285,11 @@ void iwm_reset(struct iwm_priv *iwm) if (test_bit(IWM_STATUS_READY, &iwm->status)) iwm_target_reset(iwm); - iwm->status = 0; + if (test_bit(IWM_STATUS_RESETTING, &iwm->status)) { + iwm->status = 0; + set_bit(IWM_STATUS_RESETTING, &iwm->status); + } else + iwm->status = 0; iwm->scan_id = 1; list_for_each_entry_safe(notif, next, &iwm->pending_notif, pending) { @@ -300,6 +305,13 @@ void iwm_reset(struct iwm_priv *iwm) iwm_link_off(iwm); } +void iwm_resetting(struct iwm_priv *iwm) +{ + set_bit(IWM_STATUS_RESETTING, &iwm->status); + + schedule_work(&iwm->reset_worker); +} + /* * Notification code: * diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 2daa58633e6..14950b147f9 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -118,6 +118,8 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf, IWM_ERR(iwm, "\tLMAC status: 0x%x\n", le32_to_cpu(fw_err->lmac_status)); IWM_ERR(iwm, "\tSDIO status: 0x%x\n", le32_to_cpu(fw_err->sdio_status)); + iwm_resetting(iwm); + return 0; } @@ -528,11 +530,19 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, if (iwm->conf.mode == UMAC_MODE_IBSS) goto ibss; - cfg80211_connect_result(iwm_to_ndev(iwm), + if (!test_bit(IWM_STATUS_RESETTING, &iwm->status)) + cfg80211_connect_result(iwm_to_ndev(iwm), + complete->bssid, + iwm->req_ie, iwm->req_ie_len, + iwm->resp_ie, iwm->resp_ie_len, + WLAN_STATUS_SUCCESS, + GFP_KERNEL); + else + cfg80211_roamed(iwm_to_ndev(iwm), complete->bssid, iwm->req_ie, iwm->req_ie_len, iwm->resp_ie, iwm->resp_ie_len, - WLAN_STATUS_SUCCESS, GFP_KERNEL); + GFP_KERNEL); break; case UMAC_ASSOC_COMPLETE_FAILURE: clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); @@ -551,19 +561,26 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, if (iwm->conf.mode == UMAC_MODE_IBSS) goto ibss; - cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid, - NULL, 0, NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL); + if (!test_bit(IWM_STATUS_RESETTING, &iwm->status)) + cfg80211_connect_result(iwm_to_ndev(iwm), + complete->bssid, + NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); + else + cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, + GFP_KERNEL); break; default: break; } + clear_bit(IWM_STATUS_RESETTING, &iwm->status); return 0; ibss: cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL); + clear_bit(IWM_STATUS_RESETTING, &iwm->status); return 0; } -- cgit v1.2.3-18-g5258 From 04e715cd46ba523806070fbf9ded009f10e107cd Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 1 Sep 2009 15:14:06 +0200 Subject: iwmc3200wifi: Add a last_fw_err debugfs entry In order to check what was the last fw error we got accross resets, we add this debugfs entry. It displays the complete ASSERT information. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/debug.h | 2 + drivers/net/wireless/iwmc3200wifi/debugfs.c | 105 ++++++++++++++++++++++++++-- drivers/net/wireless/iwmc3200wifi/iwm.h | 2 + drivers/net/wireless/iwmc3200wifi/main.c | 6 ++ drivers/net/wireless/iwmc3200wifi/rx.c | 2 + 5 files changed, 113 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwmc3200wifi/debug.h b/drivers/net/wireless/iwmc3200wifi/debug.h index 8fbb42d9c21..e35c9b693d1 100644 --- a/drivers/net/wireless/iwmc3200wifi/debug.h +++ b/drivers/net/wireless/iwmc3200wifi/debug.h @@ -108,6 +108,8 @@ struct iwm_debugfs { struct dentry *txq_dentry; struct dentry *tx_credit_dentry; struct dentry *rx_ticket_dentry; + + struct dentry *fw_err_dentry; }; #ifdef CONFIG_IWM_DEBUG diff --git a/drivers/net/wireless/iwmc3200wifi/debugfs.c b/drivers/net/wireless/iwmc3200wifi/debugfs.c index 0fa7b9150d5..1465379f900 100644 --- a/drivers/net/wireless/iwmc3200wifi/debugfs.c +++ b/drivers/net/wireless/iwmc3200wifi/debugfs.c @@ -98,7 +98,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_modules, iwm_debugfs_u32_read, iwm_debugfs_dbg_modules_write, "%llu\n"); -static int iwm_txrx_open(struct inode *inode, struct file *filp) +static int iwm_generic_open(struct inode *inode, struct file *filp) { filp->private_data = inode->i_private; return 0; @@ -289,25 +289,111 @@ static ssize_t iwm_debugfs_rx_ticket_read(struct file *filp, return ret; } +static ssize_t iwm_debugfs_fw_err_read(struct file *filp, + char __user *buffer, + size_t count, loff_t *ppos) +{ + + struct iwm_priv *iwm = filp->private_data; + char buf[512]; + int buf_len = 512; + size_t len = 0; + + if (*ppos != 0) + return 0; + if (count < sizeof(buf)) + return -ENOSPC; + + if (!iwm->last_fw_err) + return -ENOMEM; + + if (iwm->last_fw_err->line_num == 0) + goto out; + + len += snprintf(buf + len, buf_len - len, "%cMAC FW ERROR:\n", + (le32_to_cpu(iwm->last_fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) + ? 'L' : 'U'); + len += snprintf(buf + len, buf_len - len, + "\tCategory: %d\n", + le32_to_cpu(iwm->last_fw_err->category)); + + len += snprintf(buf + len, buf_len - len, + "\tStatus: 0x%x\n", + le32_to_cpu(iwm->last_fw_err->status)); + + len += snprintf(buf + len, buf_len - len, + "\tPC: 0x%x\n", + le32_to_cpu(iwm->last_fw_err->pc)); + + len += snprintf(buf + len, buf_len - len, + "\tblink1: %d\n", + le32_to_cpu(iwm->last_fw_err->blink1)); + + len += snprintf(buf + len, buf_len - len, + "\tblink2: %d\n", + le32_to_cpu(iwm->last_fw_err->blink2)); + + len += snprintf(buf + len, buf_len - len, + "\tilink1: %d\n", + le32_to_cpu(iwm->last_fw_err->ilink1)); + + len += snprintf(buf + len, buf_len - len, + "\tilink2: %d\n", + le32_to_cpu(iwm->last_fw_err->ilink2)); + + len += snprintf(buf + len, buf_len - len, + "\tData1: 0x%x\n", + le32_to_cpu(iwm->last_fw_err->data1)); + + len += snprintf(buf + len, buf_len - len, + "\tData2: 0x%x\n", + le32_to_cpu(iwm->last_fw_err->data2)); + + len += snprintf(buf + len, buf_len - len, + "\tLine number: %d\n", + le32_to_cpu(iwm->last_fw_err->line_num)); + + len += snprintf(buf + len, buf_len - len, + "\tUMAC status: 0x%x\n", + le32_to_cpu(iwm->last_fw_err->umac_status)); + + len += snprintf(buf + len, buf_len - len, + "\tLMAC status: 0x%x\n", + le32_to_cpu(iwm->last_fw_err->lmac_status)); + + len += snprintf(buf + len, buf_len - len, + "\tSDIO status: 0x%x\n", + le32_to_cpu(iwm->last_fw_err->sdio_status)); + +out: + + return simple_read_from_buffer(buffer, len, ppos, buf, buf_len); +} static const struct file_operations iwm_debugfs_txq_fops = { .owner = THIS_MODULE, - .open = iwm_txrx_open, + .open = iwm_generic_open, .read = iwm_debugfs_txq_read, }; static const struct file_operations iwm_debugfs_tx_credit_fops = { .owner = THIS_MODULE, - .open = iwm_txrx_open, + .open = iwm_generic_open, .read = iwm_debugfs_tx_credit_read, }; static const struct file_operations iwm_debugfs_rx_ticket_fops = { .owner = THIS_MODULE, - .open = iwm_txrx_open, + .open = iwm_generic_open, .read = iwm_debugfs_rx_ticket_read, }; +static const struct file_operations iwm_debugfs_fw_err_fops = { + .owner = THIS_MODULE, + .open = iwm_generic_open, + .read = iwm_debugfs_fw_err_read, +}; + int iwm_debugfs_init(struct iwm_priv *iwm) { int i, result; @@ -423,6 +509,16 @@ int iwm_debugfs_init(struct iwm_priv *iwm) goto error; } + iwm->dbg.fw_err_dentry = debugfs_create_file("last_fw_err", 0200, + iwm->dbg.dbgdir, iwm, + &iwm_debugfs_fw_err_fops); + result = PTR_ERR(iwm->dbg.fw_err_dentry); + if (IS_ERR(iwm->dbg.fw_err_dentry) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create last FW err: %d\n", result); + goto error; + } + + return 0; error: @@ -441,6 +537,7 @@ void iwm_debugfs_exit(struct iwm_priv *iwm) debugfs_remove(iwm->dbg.txq_dentry); debugfs_remove(iwm->dbg.tx_credit_dentry); debugfs_remove(iwm->dbg.rx_ticket_dentry); + debugfs_remove(iwm->dbg.fw_err_dentry); if (iwm->bus_ops->debugfs_exit) iwm->bus_ops->debugfs_exit(iwm); diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index f5c2d6f3fd4..1b02a4e2a1a 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -289,6 +289,8 @@ struct iwm_priv { u8 *resp_ie; int resp_ie_len; + struct iwm_fw_error_hdr *last_fw_err; + char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); }; diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 6a5b76acb64..d668e475632 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -260,6 +260,11 @@ int iwm_priv_init(struct iwm_priv *iwm) iwm->watchdog.data = (unsigned long)iwm; mutex_init(&iwm->mutex); + iwm->last_fw_err = kzalloc(sizeof(struct iwm_fw_error_hdr), + GFP_KERNEL); + if (iwm->last_fw_err == NULL) + return -ENOMEM; + return 0; } @@ -271,6 +276,7 @@ void iwm_priv_deinit(struct iwm_priv *iwm) destroy_workqueue(iwm->txq[i].wq); destroy_workqueue(iwm->rx_wq); + kfree(iwm->last_fw_err); } /* diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 14950b147f9..40dbcbc1659 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -102,6 +102,8 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf, error = (struct iwm_umac_notif_error *)buf; fw_err = &error->err; + memcpy(iwm->last_fw_err, fw_err, sizeof(struct iwm_fw_error_hdr)); + IWM_ERR(iwm, "%cMAC FW ERROR:\n", (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U'); IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category)); -- cgit v1.2.3-18-g5258 From 54c38444fad6a99b4b19512f8f0055d69115e69e Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 7 Apr 2009 19:13:15 -0400 Subject: [libata] EH: freeze port before aborting commands Call the ->freeze() hook before aborting qc's, because some hardware requires special handling prior to accessing the taskfile registers (for diagnosis/analysis/reset). Most notably, hardware may wish to disable the DMA engine or interrupts in the ->freeze() hook. Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 79711b64054..9159abe5211 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -999,7 +999,9 @@ static void __ata_port_freeze(struct ata_port *ap) * ata_port_freeze - abort & freeze port * @ap: ATA port to freeze * - * Abort and freeze @ap. + * Abort and freeze @ap. The freeze operation must be called + * first, because some hardware requires special operations + * before the taskfile registers are accessible. * * LOCKING: * spin_lock_irqsave(host lock) @@ -1013,8 +1015,8 @@ int ata_port_freeze(struct ata_port *ap) WARN_ON(!ap->ops->error_handler); - nr_aborted = ata_port_abort(ap); __ata_port_freeze(ap); + nr_aborted = ata_port_abort(ap); return nr_aborted; } -- cgit v1.2.3-18-g5258 From 2fc37adba0fb05760b8635c6706773af828ccf3c Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 7 Apr 2009 19:18:32 -0400 Subject: [libata] sata_sil: disable DMA engine in sil_freeze() We must disable the DMA engine before accessing taskfile registers. Signed-off-by: Jeff Garzik --- drivers/ata/sata_sil.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 35bd5cc7f28..3cb69d5fb81 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -565,6 +565,19 @@ static void sil_freeze(struct ata_port *ap) tmp |= SIL_MASK_IDE0_INT << ap->port_no; writel(tmp, mmio_base + SIL_SYSCFG); readl(mmio_base + SIL_SYSCFG); /* flush */ + + /* Ensure DMA_ENABLE is off. + * + * This is because the controller will not give us access to the + * taskfile registers while a DMA is in progress + */ + iowrite8(ioread8(ap->ioaddr.bmdma_addr) & ~SIL_DMA_ENABLE, + ap->ioaddr.bmdma_addr); + + /* According to ata_bmdma_stop, an HDMA transition requires + * on PIO cycle. But we can't read a taskfile register. + */ + ioread8(ap->ioaddr.bmdma_addr); } static void sil_thaw(struct ata_port *ap) -- cgit v1.2.3-18-g5258 From 388539f3ff0cf1de926b03f94e1eec112358f74d Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Mon, 27 Jul 2009 09:24:35 +0800 Subject: [libata] add DMA setup FIS auto-activate feature Hopefully results in fewer on-the-wire FIS's and no breakage. We'll see! Signed-off-by: Shaohua Li Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 2 +- drivers/ata/libata-core.c | 36 +++++++++++++++++++++++++++++------- 2 files changed, 30 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index fe3eba5d6b3..7a3124a9abc 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -2869,7 +2869,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* prepare host */ if (hpriv->cap & HOST_CAP_NCQ) - pi.flags |= ATA_FLAG_NCQ; + pi.flags |= ATA_FLAG_NCQ | ATA_FLAG_FPDMA_AA; if (hpriv->cap & HOST_CAP_PMP) pi.flags |= ATA_FLAG_PMP; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 072ba5ea138..98af50f16e0 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2299,29 +2299,49 @@ static inline u8 ata_dev_knobble(struct ata_device *dev) return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id))); } -static void ata_dev_config_ncq(struct ata_device *dev, +static int ata_dev_config_ncq(struct ata_device *dev, char *desc, size_t desc_sz) { struct ata_port *ap = dev->link->ap; int hdepth = 0, ddepth = ata_id_queue_depth(dev->id); + unsigned int err_mask; + char *aa_desc = ""; if (!ata_id_has_ncq(dev->id)) { desc[0] = '\0'; - return; + return 0; } if (dev->horkage & ATA_HORKAGE_NONCQ) { snprintf(desc, desc_sz, "NCQ (not used)"); - return; + return 0; } if (ap->flags & ATA_FLAG_NCQ) { hdepth = min(ap->scsi_host->can_queue, ATA_MAX_QUEUE - 1); dev->flags |= ATA_DFLAG_NCQ; } + if (!(dev->horkage & ATA_HORKAGE_BROKEN_FPDMA_AA) && + (ap->flags & ATA_FLAG_FPDMA_AA) && + ata_id_has_fpdma_aa(dev->id)) { + err_mask = ata_dev_set_feature(dev, SETFEATURES_SATA_ENABLE, + SATA_FPDMA_AA); + if (err_mask) { + ata_dev_printk(dev, KERN_ERR, "failed to enable AA" + "(error_mask=0x%x)\n", err_mask); + if (err_mask != AC_ERR_DEV) { + dev->horkage |= ATA_HORKAGE_BROKEN_FPDMA_AA; + return -EIO; + } + } else + aa_desc = ", AA"; + } + if (hdepth >= ddepth) - snprintf(desc, desc_sz, "NCQ (depth %d)", ddepth); + snprintf(desc, desc_sz, "NCQ (depth %d)%s", ddepth, aa_desc); else - snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth); + snprintf(desc, desc_sz, "NCQ (depth %d/%d)%s", hdepth, + ddepth, aa_desc); + return 0; } /** @@ -2461,7 +2481,7 @@ int ata_dev_configure(struct ata_device *dev) if (ata_id_has_lba(id)) { const char *lba_desc; - char ncq_desc[20]; + char ncq_desc[24]; lba_desc = "LBA"; dev->flags |= ATA_DFLAG_LBA; @@ -2475,7 +2495,9 @@ int ata_dev_configure(struct ata_device *dev) } /* config NCQ */ - ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc)); + rc = ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc)); + if (rc) + return rc; /* print device info to dmesg */ if (ata_msg_drv(ap) && print_info) { -- cgit v1.2.3-18-g5258 From 1e641060c4b564e820abdb6a4c7a603a0d386250 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 17 Jul 2009 11:58:33 +0900 Subject: libata: clear eh_info on reset completion Resets are done with port frozen but some controllers still issue interrupts during reset and they may end up recording error conditions in ehi leading to unnecessary EH retrials. This patch makes ata_eh_reset() clear ehi on reset completion. As reset is the most severe recovery action, there's nothing to lose by clearing ehi on its completion. Signed-off-by: Tejun Heo Reported-by: Zdenek Kaspar Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 9159abe5211..2c34de841e1 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2576,11 +2576,17 @@ int ata_eh_reset(struct ata_link *link, int classify, postreset(slave, classes); } - /* clear cached SError */ + /* + * Some controllers can't be frozen very well and may set + * spuruious error conditions during reset. Clear accumulated + * error information. As reset is the final recovery action, + * nothing is lost by doing this. + */ spin_lock_irqsave(link->ap->lock, flags); - link->eh_info.serror = 0; + memset(&link->eh_info, 0, sizeof(link->eh_info)); if (slave) - slave->eh_info.serror = 0; + memset(&slave->eh_info, 0, sizeof(link->eh_info)); + ap->pflags &= ~ATA_PFLAG_EH_PENDING; spin_unlock_irqrestore(link->ap->lock, flags); /* Make sure onlineness and classification result correspond. -- cgit v1.2.3-18-g5258 From 6521148c6449724c3b707820b9c535c7e8b8afcd Mon Sep 17 00:00:00 2001 From: Robert Hancock Date: Tue, 14 Jul 2009 20:43:39 -0600 Subject: libata: add command name parsing for error output This patch improve libata's output for error/notification messages to allow easier comprehension and debugging: When ATAPI commands issued through the SCSI layer fail, use SCSI functions to print the CDB in human-readable form instead of just dumping out the CDB in hex. Print out the name of the failed command (as defined by the ATA specification) in error handling output along with the raw register contents. When reporting status of ACPI taskfile commands executed on resume, also output the names of the commands being executed (or not) in readable form. Since the extra data for printing command names increases kernel size slightly, a config option has been added to allow disabling command name output (as well as some of the error register parsing) for those highly sensitive to kernel text size. Signed-off-by: Robert Hancock Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 11 ++++ drivers/ata/libata-acpi.c | 7 ++- drivers/ata/libata-eh.c | 128 +++++++++++++++++++++++++++++++++++++++++++++- drivers/ata/libata.h | 1 + 4 files changed, 143 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index b17c57f8503..8e64d3c81d5 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -26,6 +26,17 @@ config ATA_NONSTANDARD bool default n +config ATA_VERBOSE_ERROR + bool "Verbose ATA error reporting" + default y + help + This option adds parsing of ATA command descriptions and error bits + in libata kernel output, making it easier to interpret. + This option will enlarge the kernel by approx. 6KB. Disable it only + if kernel size is more important than ease of debugging. + + If unsure, say Y. + config ATA_ACPI bool "ATA ACPI Support" depends on ACPI && PCI diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index ac176da1f94..01964b6e6f6 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -689,6 +689,7 @@ static int ata_acpi_run_tf(struct ata_device *dev, struct ata_taskfile tf, ptf, rtf; unsigned int err_mask; const char *level; + const char *descr; char msg[60]; int rc; @@ -736,11 +737,13 @@ static int ata_acpi_run_tf(struct ata_device *dev, snprintf(msg, sizeof(msg), "filtered out"); rc = 0; } + descr = ata_get_cmd_descript(tf.command); ata_dev_printk(dev, level, - "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x %s\n", + "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x (%s) %s\n", tf.command, tf.feature, tf.nsect, tf.lbal, - tf.lbam, tf.lbah, tf.device, msg); + tf.lbam, tf.lbah, tf.device, + (descr ? descr : "unknown"), msg); return rc; } diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 2c34de841e1..a04488f0de8 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "../scsi/scsi_transport_api.h" #include @@ -2111,6 +2112,116 @@ void ata_eh_autopsy(struct ata_port *ap) ata_eh_link_autopsy(&ap->link); } +/** + * ata_get_cmd_descript - get description for ATA command + * @command: ATA command code to get description for + * + * Return a textual description of the given command, or NULL if the + * command is not known. + * + * LOCKING: + * None + */ +const char *ata_get_cmd_descript(u8 command) +{ +#ifdef CONFIG_ATA_VERBOSE_ERROR + static const struct + { + u8 command; + const char *text; + } cmd_descr[] = { + { ATA_CMD_DEV_RESET, "DEVICE RESET" }, + { ATA_CMD_CHK_POWER, "CHECK POWER MODE" }, + { ATA_CMD_STANDBY, "STANDBY" }, + { ATA_CMD_IDLE, "IDLE" }, + { ATA_CMD_EDD, "EXECUTE DEVICE DIAGNOSTIC" }, + { ATA_CMD_DOWNLOAD_MICRO, "DOWNLOAD MICROCODE" }, + { ATA_CMD_NOP, "NOP" }, + { ATA_CMD_FLUSH, "FLUSH CACHE" }, + { ATA_CMD_FLUSH_EXT, "FLUSH CACHE EXT" }, + { ATA_CMD_ID_ATA, "IDENTIFY DEVICE" }, + { ATA_CMD_ID_ATAPI, "IDENTIFY PACKET DEVICE" }, + { ATA_CMD_SERVICE, "SERVICE" }, + { ATA_CMD_READ, "READ DMA" }, + { ATA_CMD_READ_EXT, "READ DMA EXT" }, + { ATA_CMD_READ_QUEUED, "READ DMA QUEUED" }, + { ATA_CMD_READ_STREAM_EXT, "READ STREAM EXT" }, + { ATA_CMD_READ_STREAM_DMA_EXT, "READ STREAM DMA EXT" }, + { ATA_CMD_WRITE, "WRITE DMA" }, + { ATA_CMD_WRITE_EXT, "WRITE DMA EXT" }, + { ATA_CMD_WRITE_QUEUED, "WRITE DMA QUEUED EXT" }, + { ATA_CMD_WRITE_STREAM_EXT, "WRITE STREAM EXT" }, + { ATA_CMD_WRITE_STREAM_DMA_EXT, "WRITE STREAM DMA EXT" }, + { ATA_CMD_WRITE_FUA_EXT, "WRITE DMA FUA EXT" }, + { ATA_CMD_WRITE_QUEUED_FUA_EXT, "WRITE DMA QUEUED FUA EXT" }, + { ATA_CMD_FPDMA_READ, "READ FPDMA QUEUED" }, + { ATA_CMD_FPDMA_WRITE, "WRITE FPDMA QUEUED" }, + { ATA_CMD_PIO_READ, "READ SECTOR(S)" }, + { ATA_CMD_PIO_READ_EXT, "READ SECTOR(S) EXT" }, + { ATA_CMD_PIO_WRITE, "WRITE SECTOR(S)" }, + { ATA_CMD_PIO_WRITE_EXT, "WRITE SECTOR(S) EXT" }, + { ATA_CMD_READ_MULTI, "READ MULTIPLE" }, + { ATA_CMD_READ_MULTI_EXT, "READ MULTIPLE EXT" }, + { ATA_CMD_WRITE_MULTI, "WRITE MULTIPLE" }, + { ATA_CMD_WRITE_MULTI_EXT, "WRITE MULTIPLE EXT" }, + { ATA_CMD_WRITE_MULTI_FUA_EXT, "WRITE MULTIPLE FUA EXT" }, + { ATA_CMD_SET_FEATURES, "SET FEATURES" }, + { ATA_CMD_SET_MULTI, "SET MULTIPLE MODE" }, + { ATA_CMD_VERIFY, "READ VERIFY SECTOR(S)" }, + { ATA_CMD_VERIFY_EXT, "READ VERIFY SECTOR(S) EXT" }, + { ATA_CMD_WRITE_UNCORR_EXT, "WRITE UNCORRECTABLE EXT" }, + { ATA_CMD_STANDBYNOW1, "STANDBY IMMEDIATE" }, + { ATA_CMD_IDLEIMMEDIATE, "IDLE IMMEDIATE" }, + { ATA_CMD_SLEEP, "SLEEP" }, + { ATA_CMD_INIT_DEV_PARAMS, "INITIALIZE DEVICE PARAMETERS" }, + { ATA_CMD_READ_NATIVE_MAX, "READ NATIVE MAX ADDRESS" }, + { ATA_CMD_READ_NATIVE_MAX_EXT, "READ NATIVE MAX ADDRESS EXT" }, + { ATA_CMD_SET_MAX, "SET MAX ADDRESS" }, + { ATA_CMD_SET_MAX_EXT, "SET MAX ADDRESS EXT" }, + { ATA_CMD_READ_LOG_EXT, "READ LOG EXT" }, + { ATA_CMD_WRITE_LOG_EXT, "WRITE LOG EXT" }, + { ATA_CMD_READ_LOG_DMA_EXT, "READ LOG DMA EXT" }, + { ATA_CMD_WRITE_LOG_DMA_EXT, "WRITE LOG DMA EXT" }, + { ATA_CMD_TRUSTED_RCV, "TRUSTED RECEIVE" }, + { ATA_CMD_TRUSTED_RCV_DMA, "TRUSTED RECEIVE DMA" }, + { ATA_CMD_TRUSTED_SND, "TRUSTED SEND" }, + { ATA_CMD_TRUSTED_SND_DMA, "TRUSTED SEND DMA" }, + { ATA_CMD_PMP_READ, "READ BUFFER" }, + { ATA_CMD_PMP_WRITE, "WRITE BUFFER" }, + { ATA_CMD_CONF_OVERLAY, "DEVICE CONFIGURATION OVERLAY" }, + { ATA_CMD_SEC_SET_PASS, "SECURITY SET PASSWORD" }, + { ATA_CMD_SEC_UNLOCK, "SECURITY UNLOCK" }, + { ATA_CMD_SEC_ERASE_PREP, "SECURITY ERASE PREPARE" }, + { ATA_CMD_SEC_ERASE_UNIT, "SECURITY ERASE UNIT" }, + { ATA_CMD_SEC_FREEZE_LOCK, "SECURITY FREEZE LOCK" }, + { ATA_CMD_SEC_DISABLE_PASS, "SECURITY DISABLE PASSWORD" }, + { ATA_CMD_CONFIG_STREAM, "CONFIGURE STREAM" }, + { ATA_CMD_SMART, "SMART" }, + { ATA_CMD_MEDIA_LOCK, "DOOR LOCK" }, + { ATA_CMD_MEDIA_UNLOCK, "DOOR UNLOCK" }, + { ATA_CMD_CHK_MED_CRD_TYP, "CHECK MEDIA CARD TYPE" }, + { ATA_CMD_CFA_REQ_EXT_ERR, "CFA REQUEST EXTENDED ERROR" }, + { ATA_CMD_CFA_WRITE_NE, "CFA WRITE SECTORS WITHOUT ERASE" }, + { ATA_CMD_CFA_TRANS_SECT, "CFA TRANSLATE SECTOR" }, + { ATA_CMD_CFA_ERASE, "CFA ERASE SECTORS" }, + { ATA_CMD_CFA_WRITE_MULT_NE, "CFA WRITE MULTIPLE WITHOUT ERASE" }, + { ATA_CMD_READ_LONG, "READ LONG (with retries)" }, + { ATA_CMD_READ_LONG_ONCE, "READ LONG (without retries)" }, + { ATA_CMD_WRITE_LONG, "WRITE LONG (with retries)" }, + { ATA_CMD_WRITE_LONG_ONCE, "WRITE LONG (without retries)" }, + { ATA_CMD_RESTORE, "RECALIBRATE" }, + { 0, NULL } /* terminate list */ + }; + + unsigned int i; + for (i = 0; cmd_descr[i].text; i++) + if (cmd_descr[i].command == command) + return cmd_descr[i].text; +#endif + + return NULL; +} + /** * ata_eh_link_report - report error handling to user * @link: ATA link EH is going on @@ -2177,6 +2288,7 @@ static void ata_eh_link_report(struct ata_link *link) ata_link_printk(link, KERN_ERR, "%s\n", desc); } +#ifdef CONFIG_ATA_VERBOSE_ERROR if (ehc->i.serror) ata_link_printk(link, KERN_ERR, "SError: { %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s}\n", @@ -2197,6 +2309,7 @@ static void ata_eh_link_report(struct ata_link *link) ehc->i.serror & SERR_TRANS_ST_ERROR ? "TrStaTrns " : "", ehc->i.serror & SERR_UNRECOG_FIS ? "UnrecFIS " : "", ehc->i.serror & SERR_DEV_XCHG ? "DevExch " : ""); +#endif for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); @@ -2228,14 +2341,23 @@ static void ata_eh_link_report(struct ata_link *link) dma_str[qc->dma_dir]); } - if (ata_is_atapi(qc->tf.protocol)) - snprintf(cdb_buf, sizeof(cdb_buf), + if (ata_is_atapi(qc->tf.protocol)) { + if (qc->scsicmd) + scsi_print_command(qc->scsicmd); + else + snprintf(cdb_buf, sizeof(cdb_buf), "cdb %02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x\n ", cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11], cdb[12], cdb[13], cdb[14], cdb[15]); + } else { + const char *descr = ata_get_cmd_descript(cmd->command); + if (descr) + ata_dev_printk(qc->dev, KERN_ERR, + "failed command: %s\n", descr); + } ata_dev_printk(qc->dev, KERN_ERR, "cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " @@ -2254,6 +2376,7 @@ static void ata_eh_link_report(struct ata_link *link) res->device, qc->err_mask, ata_err_string(qc->err_mask), qc->err_mask & AC_ERR_NCQ ? " " : ""); +#ifdef CONFIG_ATA_VERBOSE_ERROR if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR)) { if (res->command & ATA_BUSY) @@ -2277,6 +2400,7 @@ static void ata_eh_link_report(struct ata_link *link) res->feature & ATA_UNC ? "UNC " : "", res->feature & ATA_IDNF ? "IDNF " : "", res->feature & ATA_ABORTED ? "ABRT " : ""); +#endif } } diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 89a1e0018e7..be8e2628f82 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -164,6 +164,7 @@ extern void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, extern void ata_eh_done(struct ata_link *link, struct ata_device *dev, unsigned int action); extern void ata_eh_autopsy(struct ata_port *ap); +const char *ata_get_cmd_descript(u8 command); extern void ata_eh_report(struct ata_port *ap); extern int ata_eh_reset(struct ata_link *link, int classify, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, -- cgit v1.2.3-18-g5258 From 051d9fbdd1d1ec85ea18ba20581234cf23f1c217 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 3 Jul 2009 11:46:12 +0900 Subject: libata: remove spindown skipping and warning This was a hack to give userland shutdown tools time to drop manual spindown. All popular distros updated quite some time ago and the due is well passed. Drop it. Signed-off-by: Tejun Heo Cc: Jaswinder Singh Rajput Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 51 ----------------------------------------------- 1 file changed, 51 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index d0dfeef55db..de3a0050760 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1257,23 +1257,6 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth) return queue_depth; } -/* XXX: for spindown warning */ -static void ata_delayed_done_timerfn(unsigned long arg) -{ - struct scsi_cmnd *scmd = (void *)arg; - - scmd->scsi_done(scmd); -} - -/* XXX: for spindown warning */ -static void ata_delayed_done(struct scsi_cmnd *scmd) -{ - static struct timer_list timer; - - setup_timer(&timer, ata_delayed_done_timerfn, (unsigned long)scmd); - mod_timer(&timer, jiffies + 5 * HZ); -} - /** * ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command * @qc: Storage for translated ATA taskfile @@ -1338,32 +1321,6 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc) system_entering_hibernation()) goto skip; - /* XXX: This is for backward compatibility, will be - * removed. Read Documentation/feature-removal-schedule.txt - * for more info. - */ - if ((qc->dev->flags & ATA_DFLAG_SPUNDOWN) && - (system_state == SYSTEM_HALT || - system_state == SYSTEM_POWER_OFF)) { - static unsigned long warned; - - if (!test_and_set_bit(0, &warned)) { - ata_dev_printk(qc->dev, KERN_WARNING, - "DISK MIGHT NOT BE SPUN DOWN PROPERLY. " - "UPDATE SHUTDOWN UTILITY\n"); - ata_dev_printk(qc->dev, KERN_WARNING, - "For more info, visit " - "http://linux-ata.org/shutdown.html\n"); - - /* ->scsi_done is not used, use it for - * delayed completion. - */ - scmd->scsi_done = qc->scsidone; - qc->scsidone = ata_delayed_done; - } - goto skip; - } - /* Issue ATA STANDBY IMMEDIATE command */ tf->command = ATA_CMD_STANDBYNOW1; } @@ -1764,14 +1721,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) } } - /* XXX: track spindown state for spindown skipping and warning */ - if (unlikely(qc->tf.command == ATA_CMD_STANDBY || - qc->tf.command == ATA_CMD_STANDBYNOW1)) - qc->dev->flags |= ATA_DFLAG_SPUNDOWN; - else if (likely(system_state != SYSTEM_HALT && - system_state != SYSTEM_POWER_OFF)) - qc->dev->flags &= ~ATA_DFLAG_SPUNDOWN; - if (need_sense && !ap->ops->error_handler) ata_dump_status(ap->print_id, &qc->result_tf); -- cgit v1.2.3-18-g5258 From 87c8b22be201cc4c139f98ef5e0471dd15c01239 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 28 Jun 2009 09:26:17 -0700 Subject: drivers/ata: Remove unnecessary semicolons Signed-off-by: Joe Perches Signed-off-by: Jeff Garzik --- drivers/ata/pata_octeon_cf.c | 2 +- drivers/ata/sata_inic162x.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c index abdd19fe990..e807cc3b6ab 100644 --- a/drivers/ata/pata_octeon_cf.c +++ b/drivers/ata/pata_octeon_cf.c @@ -213,7 +213,7 @@ static void octeon_cf_set_dmamode(struct ata_port *ap, struct ata_device *dev) * This is tI, C.F. spec. says 0, but Sony CF card requires * more, we use 20 nS. */ - dma_tim.s.dmack_s = ns_to_tim_reg(tim_mult, 20);; + dma_tim.s.dmack_s = ns_to_tim_reg(tim_mult, 20); dma_tim.s.dmack_h = ns_to_tim_reg(tim_mult, dma_ackh); dma_tim.s.dmarq = dma_arq; diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 8d890cc5a7e..4406902b429 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -405,7 +405,7 @@ static irqreturn_t inic_interrupt(int irq, void *dev_instance) struct ata_host *host = dev_instance; struct inic_host_priv *hpriv = host->private_data; u16 host_irq_stat; - int i, handled = 0;; + int i, handled = 0; host_irq_stat = readw(hpriv->mmio_base + HOST_IRQ_STAT); -- cgit v1.2.3-18-g5258 From 6b406782ad0408f9cb480c2e1b543d194e8206d0 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 24 Jun 2009 18:29:44 +0100 Subject: [libata] Add pata_rdc driver for RDC ATA devices From: Alan Cox Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 10 ++ drivers/ata/Makefile | 1 + drivers/ata/pata_rdc.c | 400 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 411 insertions(+) create mode 100644 drivers/ata/pata_rdc.c (limited to 'drivers') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 8e64d3c81d5..ab2fa4eeb36 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -597,6 +597,16 @@ config PATA_RB532 If unsure, say N. +config PATA_RDC + tristate "RDC PATA support" + depends on PCI + help + This option enables basic support for the later RDC PATA controllers + controllers via the new ATA layer. For the RDC 1010, you need to + enable the IT821X driver instead. + + If unsure, say N. + config PATA_RZ1000 tristate "PC Tech RZ1000 PATA support" depends on PCI diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 38906f9bbb4..463eb52236a 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -57,6 +57,7 @@ obj-$(CONFIG_PATA_PDC_OLD) += pata_pdc202xx_old.o obj-$(CONFIG_PATA_QDI) += pata_qdi.o obj-$(CONFIG_PATA_RADISYS) += pata_radisys.o obj-$(CONFIG_PATA_RB532) += pata_rb532_cf.o +obj-$(CONFIG_PATA_RDC) += pata_rdc.o obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o obj-$(CONFIG_PATA_SC1200) += pata_sc1200.o obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o diff --git a/drivers/ata/pata_rdc.c b/drivers/ata/pata_rdc.c new file mode 100644 index 00000000000..c843a1e07c4 --- /dev/null +++ b/drivers/ata/pata_rdc.c @@ -0,0 +1,400 @@ +/* + * pata_rdc - Driver for later RDC PATA controllers + * + * This is actually a driver for hardware meeting + * INCITS 370-2004 (1510D): ATA Host Adapter Standards + * + * Based on ata_piix. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "pata_rdc" +#define DRV_VERSION "0.01" + +struct rdc_host_priv { + u32 saved_iocfg; +}; + +/** + * rdc_pata_cable_detect - Probe host controller cable detect info + * @ap: Port for which cable detect info is desired + * + * Read 80c cable indicator from ATA PCI device's PCI config + * register. This register is normally set by firmware (BIOS). + * + * LOCKING: + * None (inherited from caller). + */ + +static int rdc_pata_cable_detect(struct ata_port *ap) +{ + struct rdc_host_priv *hpriv = ap->host->private_data; + u8 mask; + + /* check BIOS cable detect results */ + mask = 0x30 << (2 * ap->port_no); + if ((hpriv->saved_iocfg & mask) == 0) + return ATA_CBL_PATA40; + return ATA_CBL_PATA80; +} + +/** + * rdc_pata_prereset - prereset for PATA host controller + * @link: Target link + * @deadline: deadline jiffies for the operation + * + * LOCKING: + * None (inherited from caller). + */ +static int rdc_pata_prereset(struct ata_link *link, unsigned long deadline) +{ + struct ata_port *ap = link->ap; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + + static const struct pci_bits rdc_enable_bits[] = { + { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ + { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */ + }; + + if (!pci_test_config_bits(pdev, &rdc_enable_bits[ap->port_no])) + return -ENOENT; + return ata_sff_prereset(link, deadline); +} + +/** + * rdc_set_piomode - Initialize host controller PATA PIO timings + * @ap: Port whose timings we are configuring + * @adev: um + * + * Set PIO mode for device, in host controller PCI config space. + * + * LOCKING: + * None (inherited from caller). + */ + +static void rdc_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + unsigned int pio = adev->pio_mode - XFER_PIO_0; + struct pci_dev *dev = to_pci_dev(ap->host->dev); + unsigned int is_slave = (adev->devno != 0); + unsigned int master_port= ap->port_no ? 0x42 : 0x40; + unsigned int slave_port = 0x44; + u16 master_data; + u8 slave_data; + u8 udma_enable; + int control = 0; + + static const /* ISP RTC */ + u8 timings[][2] = { { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; + + if (pio >= 2) + control |= 1; /* TIME1 enable */ + if (ata_pio_need_iordy(adev)) + control |= 2; /* IE enable */ + + if (adev->class == ATA_DEV_ATA) + control |= 4; /* PPE enable */ + + /* PIO configuration clears DTE unconditionally. It will be + * programmed in set_dmamode which is guaranteed to be called + * after set_piomode if any DMA mode is available. + */ + pci_read_config_word(dev, master_port, &master_data); + if (is_slave) { + /* clear TIME1|IE1|PPE1|DTE1 */ + master_data &= 0xff0f; + /* Enable SITRE (separate slave timing register) */ + master_data |= 0x4000; + /* enable PPE1, IE1 and TIME1 as needed */ + master_data |= (control << 4); + pci_read_config_byte(dev, slave_port, &slave_data); + slave_data &= (ap->port_no ? 0x0f : 0xf0); + /* Load the timing nibble for this slave */ + slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) + << (ap->port_no ? 4 : 0); + } else { + /* clear ISP|RCT|TIME0|IE0|PPE0|DTE0 */ + master_data &= 0xccf0; + /* Enable PPE, IE and TIME as appropriate */ + master_data |= control; + /* load ISP and RCT */ + master_data |= + (timings[pio][0] << 12) | + (timings[pio][1] << 8); + } + pci_write_config_word(dev, master_port, master_data); + if (is_slave) + pci_write_config_byte(dev, slave_port, slave_data); + + /* Ensure the UDMA bit is off - it will be turned back on if + UDMA is selected */ + + pci_read_config_byte(dev, 0x48, &udma_enable); + udma_enable &= ~(1 << (2 * ap->port_no + adev->devno)); + pci_write_config_byte(dev, 0x48, udma_enable); +} + +/** + * rdc_set_dmamode - Initialize host controller PATA PIO timings + * @ap: Port whose timings we are configuring + * @adev: Drive in question + * + * Set UDMA mode for device, in host controller PCI config space. + * + * LOCKING: + * None (inherited from caller). + */ + +static void rdc_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + struct pci_dev *dev = to_pci_dev(ap->host->dev); + u8 master_port = ap->port_no ? 0x42 : 0x40; + u16 master_data; + u8 speed = adev->dma_mode; + int devid = adev->devno + 2 * ap->port_no; + u8 udma_enable = 0; + + static const /* ISP RTC */ + u8 timings[][2] = { { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; + + pci_read_config_word(dev, master_port, &master_data); + pci_read_config_byte(dev, 0x48, &udma_enable); + + if (speed >= XFER_UDMA_0) { + unsigned int udma = adev->dma_mode - XFER_UDMA_0; + u16 udma_timing; + u16 ideconf; + int u_clock, u_speed; + + /* + * UDMA is handled by a combination of clock switching and + * selection of dividers + * + * Handy rule: Odd modes are UDMATIMx 01, even are 02 + * except UDMA0 which is 00 + */ + u_speed = min(2 - (udma & 1), udma); + if (udma == 5) + u_clock = 0x1000; /* 100Mhz */ + else if (udma > 2) + u_clock = 1; /* 66Mhz */ + else + u_clock = 0; /* 33Mhz */ + + udma_enable |= (1 << devid); + + /* Load the CT/RP selection */ + pci_read_config_word(dev, 0x4A, &udma_timing); + udma_timing &= ~(3 << (4 * devid)); + udma_timing |= u_speed << (4 * devid); + pci_write_config_word(dev, 0x4A, udma_timing); + + /* Select a 33/66/100Mhz clock */ + pci_read_config_word(dev, 0x54, &ideconf); + ideconf &= ~(0x1001 << devid); + ideconf |= u_clock << devid; + pci_write_config_word(dev, 0x54, ideconf); + } else { + /* + * MWDMA is driven by the PIO timings. We must also enable + * IORDY unconditionally along with TIME1. PPE has already + * been set when the PIO timing was set. + */ + unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0; + unsigned int control; + u8 slave_data; + const unsigned int needed_pio[3] = { + XFER_PIO_0, XFER_PIO_3, XFER_PIO_4 + }; + int pio = needed_pio[mwdma] - XFER_PIO_0; + + control = 3; /* IORDY|TIME1 */ + + /* If the drive MWDMA is faster than it can do PIO then + we must force PIO into PIO0 */ + + if (adev->pio_mode < needed_pio[mwdma]) + /* Enable DMA timing only */ + control |= 8; /* PIO cycles in PIO0 */ + + if (adev->devno) { /* Slave */ + master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */ + master_data |= control << 4; + pci_read_config_byte(dev, 0x44, &slave_data); + slave_data &= (ap->port_no ? 0x0f : 0xf0); + /* Load the matching timing */ + slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0); + pci_write_config_byte(dev, 0x44, slave_data); + } else { /* Master */ + master_data &= 0xCCF4; /* Mask out IORDY|TIME1|DMAONLY + and master timing bits */ + master_data |= control; + master_data |= + (timings[pio][0] << 12) | + (timings[pio][1] << 8); + } + + udma_enable &= ~(1 << devid); + pci_write_config_word(dev, master_port, master_data); + } + pci_write_config_byte(dev, 0x48, udma_enable); +} + +static struct ata_port_operations rdc_pata_ops = { + .inherits = &ata_bmdma32_port_ops, + .cable_detect = rdc_pata_cable_detect, + .set_piomode = rdc_set_piomode, + .set_dmamode = rdc_set_dmamode, + .prereset = rdc_pata_prereset, +}; + +static struct ata_port_info rdc_port_info = { + + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, + .port_ops = &rdc_pata_ops, +}; + +static struct scsi_host_template rdc_sht = { + ATA_BMDMA_SHT(DRV_NAME), +}; + +/** + * rdc_init_one - Register PIIX ATA PCI device with kernel services + * @pdev: PCI device to register + * @ent: Entry in rdc_pci_tbl matching with @pdev + * + * Called from kernel PCI layer. We probe for combined mode (sigh), + * and then hand over control to libata, for it to do the rest. + * + * LOCKING: + * Inherited from PCI layer (may sleep). + * + * RETURNS: + * Zero on success, or -ERRNO value. + */ + +static int __devinit rdc_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int printed_version; + struct device *dev = &pdev->dev; + struct ata_port_info port_info[2]; + const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] }; + unsigned long port_flags; + struct ata_host *host; + struct rdc_host_priv *hpriv; + int rc; + + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); + + port_info[0] = rdc_port_info; + port_info[1] = rdc_port_info; + + port_flags = port_info[0].flags; + + /* enable device and prepare host */ + rc = pcim_enable_device(pdev); + if (rc) + return rc; + + hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) + return -ENOMEM; + + /* Save IOCFG, this will be used for cable detection, quirk + * detection and restoration on detach. + */ + pci_read_config_dword(pdev, 0x54, &hpriv->saved_iocfg); + + rc = ata_pci_sff_prepare_host(pdev, ppi, &host); + if (rc) + return rc; + host->private_data = hpriv; + + pci_intx(pdev, 1); + + host->flags |= ATA_HOST_PARALLEL_SCAN; + + pci_set_master(pdev); + return ata_pci_sff_activate_host(host, ata_sff_interrupt, &rdc_sht); +} + +static void rdc_remove_one(struct pci_dev *pdev) +{ + struct ata_host *host = dev_get_drvdata(&pdev->dev); + struct rdc_host_priv *hpriv = host->private_data; + + pci_write_config_dword(pdev, 0x54, hpriv->saved_iocfg); + + ata_pci_remove_one(pdev); +} + +static const struct pci_device_id rdc_pci_tbl[] = { + { PCI_DEVICE(0x17F3, 0x1011), }, + { PCI_DEVICE(0x17F3, 0x1012), }, + { } /* terminate list */ +}; + +static struct pci_driver rdc_pci_driver = { + .name = DRV_NAME, + .id_table = rdc_pci_tbl, + .probe = rdc_init_one, + .remove = rdc_remove_one, +}; + + +static int __init rdc_init(void) +{ + return pci_register_driver(&rdc_pci_driver); +} + +static void __exit rdc_exit(void) +{ + pci_unregister_driver(&rdc_pci_driver); +} + +module_init(rdc_init); +module_exit(rdc_exit); + +MODULE_AUTHOR("Alan Cox (based on ata_piix)"); +MODULE_DESCRIPTION("SCSI low-level driver for RDC PATA controllers"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, rdc_pci_tbl); +MODULE_VERSION(DRV_VERSION); -- cgit v1.2.3-18-g5258 From f17259a31237cf0fd5c6c8cf2a4f9e6df405744b Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Wed, 24 Jun 2009 21:01:45 -0400 Subject: libata: Delegate nonrot flag setting to SCSI Now that the SCSI disk driver correctly handles non-rotational devices we can move setting the queue flag to SCSI. Signed-off-by: Martin K. Petersen Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index de3a0050760..5d7a1bd37e9 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1119,10 +1119,6 @@ static int ata_scsi_dev_config(struct scsi_device *sdev, blk_queue_dma_drain(q, atapi_drain_needed, buf, ATAPI_MAX_DRAIN); } else { - if (ata_id_is_ssd(dev->id)) - queue_flag_set_unlocked(QUEUE_FLAG_NONROT, - sdev->request_queue); - /* ATA devices must be sector aligned */ blk_queue_update_dma_alignment(sdev->request_queue, ATA_SECT_SIZE - 1); -- cgit v1.2.3-18-g5258 From 77cdec1ad527560b59ab8dbb063dbb3d0a138bf7 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 17 Jul 2009 19:13:47 +0100 Subject: libata: Export AHCI capabilities AHCI exports various capability bits that may be of interest to userspace such as whether the BIOS claims a port is hotpluggable or eSATA. Providing these via sysfs along with the version of the AHCI spec implemented by the host allows userspace to make policy decisions for things like ALPM. Signed-off-by: Matthew Garrett Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 7a3124a9abc..be4c39f8ab8 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -329,10 +329,24 @@ static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val); static void ahci_init_sw_activity(struct ata_link *link); +static ssize_t ahci_show_host_caps(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t ahci_show_host_version(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t ahci_show_port_cmd(struct device *dev, + struct device_attribute *attr, char *buf); + +DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL); +DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL); +DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL); + static struct device_attribute *ahci_shost_attrs[] = { &dev_attr_link_power_management_policy, &dev_attr_em_message_type, &dev_attr_em_message, + &dev_attr_ahci_host_caps, + &dev_attr_ahci_host_version, + &dev_attr_ahci_port_cmd, NULL }; @@ -702,6 +716,36 @@ static void ahci_enable_ahci(void __iomem *mmio) WARN_ON(1); } +static ssize_t ahci_show_host_caps(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + struct ahci_host_priv *hpriv = ap->host->private_data; + + return sprintf(buf, "%x\n", hpriv->cap); +} + +static ssize_t ahci_show_host_version(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; + + return sprintf(buf, "%x\n", readl(mmio + HOST_VERSION)); +} + +static ssize_t ahci_show_port_cmd(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + void __iomem *port_mmio = ahci_port_base(ap); + + return sprintf(buf, "%x\n", readl(port_mmio + PORT_CMD)); +} + /** * ahci_save_initial_config - Save and fixup initial config values * @pdev: target PCI device -- cgit v1.2.3-18-g5258 From 4f1a0ee11d6f9c104c8e6a13dae995709a6922a8 Mon Sep 17 00:00:00 2001 From: Robert Hancock Date: Thu, 30 Jul 2009 14:11:29 -0600 Subject: sata_sil24: always set protocol override for non-ATAPI data commands The sil24 hardware has a built-in list of commands and associated protocols that gets used by default to decide how to handle a given command. However, if the command is not known to the controller then it presumably assumes it to be a non-data command which then causes protocol mismatch errors if the device ends up requesting data transfer. The new DATA SET MANAGEMENT - Trim command causes this issue since it's a DMA data-out command. Since we should always know best what protocol the command should be using, let's just set the override flag to inform the controller what protocol to use for all non-ATAPI commands with data transfer. Signed-off-by: Robert Hancock Tested-by: Mark Lord Signed-off-by: Jeff Garzik --- drivers/ata/sata_sil24.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 77aa8d7ecec..e6946fc527d 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -846,6 +846,17 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc) if (!ata_is_atapi(qc->tf.protocol)) { prb = &cb->ata.prb; sge = cb->ata.sge; + if (ata_is_data(qc->tf.protocol)) { + u16 prot = 0; + ctrl = PRB_CTRL_PROTOCOL; + if (ata_is_ncq(qc->tf.protocol)) + prot |= PRB_PROT_NCQ; + if (qc->tf.flags & ATA_TFLAG_WRITE) + prot |= PRB_PROT_WRITE; + else + prot |= PRB_PROT_READ; + prb->prot = cpu_to_le16(prot); + } } else { prb = &cb->atapi.prb; sge = cb->atapi.sge; -- cgit v1.2.3-18-g5258 From fd38d7a0a0618656e491ed67af735bc4e3600367 Mon Sep 17 00:00:00 2001 From: "Graham, David" Date: Mon, 31 Aug 2009 14:12:51 +0000 Subject: e1000: Fix for e1000 kills IPMI on a tagged vlan. Enabling VLAN filters (VFE) when the primary interface is brought up (per commit 78ed11a) has caused problems for some users who manage their systems using IPMI over a VLAN. This is because when the driver enables the VLAN filter, this same filter table is enabled for the management channel, and the table is initially empty, which means that the IPMI/VLAN packets are filtered out and not received by the BMC. This is a problem only on e1000 class adapters, as it is only on e1000 that the filter table is common to the management and host streams. With this change, filtering is only enabled when one or more host VLANs exist, and is disabled when the last host VLAN is removed. VLAN filtering is always disabled when the primary interface is in promiscuous mode, and will be (re)enabled if VLANs exist when the interface exits promiscuous mode. Note that this does not completely resolve the issue for those using VLAN management, because if the host adds a VLAN, then the above problem occurs when that VLAN is enabled. However, it does mean the there is no problem for configurations where management is on a VLAN and the host is not. A complete solution to this issue would require further driver changes. The driver would need to discover if (and which) management VLANs are active before enabling VLAN filtering, so that it could ensure that the managed VLANs are included in the VLAN filter table. This discovery requires that the BMC identifies its VLAN in registers accessible to the driver, and at least on Dell PE2850 systems the BMC does not identify its VLAN to allow such discovery. Intel is pursuing this issue with the BMC vendor. Signed-off-by: Dave Graham Signed-off-by: Jeff Kirsher Tested-by: Krzysztof Piotr Oledzki Signed-off-by: David S. Miller --- drivers/net/e1000/e1000_main.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index b3063e60be6..2c723b1b882 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2402,7 +2402,9 @@ static void e1000_set_rx_mode(struct net_device *netdev) rctl &= ~E1000_RCTL_MPE; } if (adapter->hw.mac_type != e1000_ich8lan) - rctl |= E1000_RCTL_VFE; + /* Enable VLAN filter if there is a VLAN */ + if (adapter->vlgrp) + rctl |= E1000_RCTL_VFE; } if (netdev->uc.count > rar_entries - 1) { @@ -4856,6 +4858,8 @@ static void e1000_vlan_rx_register(struct net_device *netdev, /* enable VLAN receive filtering */ rctl = er32(RCTL); rctl &= ~E1000_RCTL_CFIEN; + if (!(netdev->flags & IFF_PROMISC)) + rctl |= E1000_RCTL_VFE; ew32(RCTL, rctl); e1000_update_mng_vlan(adapter); } @@ -4866,6 +4870,11 @@ static void e1000_vlan_rx_register(struct net_device *netdev, ew32(CTRL, ctrl); if (adapter->hw.mac_type != e1000_ich8lan) { + /* disable VLAN receive filtering */ + rctl = er32(RCTL); + rctl &= ~E1000_RCTL_VFE; + ew32(RCTL, rctl); + if (adapter->mng_vlan_id != (u16)E1000_MNG_VLAN_NONE) { e1000_vlan_rx_kill_vid(netdev, -- cgit v1.2.3-18-g5258 From 8620a103b5e38d952280f3d97b5e1bcce8d7874c Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Tue, 1 Sep 2009 13:49:35 +0000 Subject: ixgbe: refactor link setup code Link code cleanup: a number of redundant functions and MAC variables are cleaned up, with some functions being consolidated into a single-purpose code path. Removed following deprecated link functions and mac variables * ixgbe_setup_copper_link_speed_82598 * ixgbe_setup_mac_link_speed_multispeed_fiber * ixgbe_setup_mac_link_speed_82599 * mac.autoneg, mac.autoneg_succeeded, phy.autoneg_wait_to_complete Signed-off-by: Mallikarjuna R Chilakala Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_82598.c | 49 ++++---------- drivers/net/ixgbe/ixgbe_82599.c | 135 +++++++++++++------------------------- drivers/net/ixgbe/ixgbe_ethtool.c | 4 +- drivers/net/ixgbe/ixgbe_main.c | 17 +++-- drivers/net/ixgbe/ixgbe_type.h | 7 +- 5 files changed, 67 insertions(+), 145 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 916430f2a7e..cb7f0c3c6e1 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -41,8 +41,7 @@ static s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *autoneg); -static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw); -static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, +static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg, bool autoneg_wait_to_complete); @@ -156,8 +155,6 @@ static s32 ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw) /* Overwrite the link function pointers if copper PHY */ if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper) { mac->ops.setup_link = &ixgbe_setup_copper_link_82598; - mac->ops.setup_link_speed = - &ixgbe_setup_copper_link_speed_82598; mac->ops.get_link_capabilities = &ixgbe_get_copper_link_capabilities_82598; } @@ -465,13 +462,14 @@ out: } /** - * ixgbe_setup_mac_link_82598 - Configures MAC link settings + * ixgbe_start_mac_link_82598 - Configures MAC link settings * @hw: pointer to hardware structure * * Configures link settings based on values in the ixgbe_hw struct. * Restarts the link. Performs autonegotiation if needed. **/ -static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw) +static s32 ixgbe_start_mac_link_82598(struct ixgbe_hw *hw, + bool autoneg_wait_to_complete) { u32 autoc_reg; u32 links_reg; @@ -484,7 +482,7 @@ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); /* Only poll for autoneg to complete if specified to do so */ - if (hw->phy.autoneg_wait_to_complete) { + if (autoneg_wait_to_complete) { if ((autoc_reg & IXGBE_AUTOC_LMS_MASK) == IXGBE_AUTOC_LMS_KX4_AN || (autoc_reg & IXGBE_AUTOC_LMS_MASK) == @@ -600,7 +598,7 @@ out: /** - * ixgbe_setup_mac_link_speed_82598 - Set MAC link speed + * ixgbe_setup_mac_link_82598 - Set MAC link speed * @hw: pointer to hardware structure * @speed: new link speed * @autoneg: true if auto-negotiation enabled @@ -608,7 +606,7 @@ out: * * Set the link speed in the AUTOC register and restarts link. **/ -static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, +static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg, bool autoneg_wait_to_complete) { @@ -638,14 +636,12 @@ static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, } if (status == 0) { - hw->phy.autoneg_wait_to_complete = autoneg_wait_to_complete; - /* * Setup and restart the link based on the new values in * ixgbe_hw This will write the AUTOC register based on the new * stored values */ - status = ixgbe_setup_mac_link_82598(hw); + status = ixgbe_start_mac_link_82598(hw, autoneg_wait_to_complete); } return status; @@ -653,29 +649,7 @@ static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, /** - * ixgbe_setup_copper_link_82598 - Setup copper link settings - * @hw: pointer to hardware structure - * - * Configures link settings based on values in the ixgbe_hw struct. - * Restarts the link. Performs autonegotiation if needed. Restart - * phy and wait for autonegotiate to finish. Then synchronize the - * MAC and PHY. - **/ -static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw) -{ - s32 status; - - /* Restart autonegotiation on PHY */ - status = hw->phy.ops.setup_link(hw); - - /* Set up MAC */ - ixgbe_setup_mac_link_82598(hw); - - return status; -} - -/** - * ixgbe_setup_copper_link_speed_82598 - Set the PHY autoneg advertised field + * ixgbe_setup_copper_link_82598 - Set the PHY autoneg advertised field * @hw: pointer to hardware structure * @speed: new link speed * @autoneg: true if autonegotiation enabled @@ -683,7 +657,7 @@ static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw) * * Sets the link speed in the AUTOC register in the MAC and restarts link. **/ -static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, +static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg, bool autoneg_wait_to_complete) @@ -695,7 +669,7 @@ static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, autoneg_wait_to_complete); /* Set up MAC */ - ixgbe_setup_mac_link_82598(hw); + ixgbe_start_mac_link_82598(hw, autoneg_wait_to_complete); return status; } @@ -1163,7 +1137,6 @@ static struct ixgbe_mac_operations mac_ops_82598 = { .read_analog_reg8 = &ixgbe_read_analog_reg8_82598, .write_analog_reg8 = &ixgbe_write_analog_reg8_82598, .setup_link = &ixgbe_setup_mac_link_82598, - .setup_link_speed = &ixgbe_setup_mac_link_speed_82598, .check_link = &ixgbe_check_mac_link_82598, .get_link_capabilities = &ixgbe_get_link_capabilities_82598, .led_on = &ixgbe_led_on_generic, diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 364b6d2279e..5ee56085526 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -38,23 +38,23 @@ #define IXGBE_82599_MC_TBL_SIZE 128 #define IXGBE_82599_VFT_TBL_SIZE 128 -static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw); -static s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, - ixgbe_link_speed speed, bool autoneg, - bool autoneg_wait_to_complete); -static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw); -static s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, - ixgbe_link_speed speed, - bool autoneg, - bool autoneg_wait_to_complete); +s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete); +s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, + bool autoneg_wait_to_complete); +s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete); static s32 ixgbe_get_copper_link_capabilities_82599(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *autoneg); -static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw); -static s32 ixgbe_setup_copper_link_speed_82599(struct ixgbe_hw *hw, - ixgbe_link_speed speed, - bool autoneg, - bool autoneg_wait_to_complete); +static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete); static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw); static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) @@ -62,15 +62,9 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) struct ixgbe_mac_info *mac = &hw->mac; if (hw->phy.multispeed_fiber) { /* Set up dual speed SFP+ support */ - mac->ops.setup_link = - &ixgbe_setup_mac_link_multispeed_fiber; - mac->ops.setup_link_speed = - &ixgbe_setup_mac_link_speed_multispeed_fiber; + mac->ops.setup_link = &ixgbe_setup_mac_link_multispeed_fiber; } else { - mac->ops.setup_link = - &ixgbe_setup_mac_link_82599; - mac->ops.setup_link_speed = - &ixgbe_setup_mac_link_speed_82599; + mac->ops.setup_link = &ixgbe_setup_mac_link_82599; } } @@ -178,8 +172,6 @@ static s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw) /* If copper media, overwrite with copper function pointers */ if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper) { mac->ops.setup_link = &ixgbe_setup_copper_link_82599; - mac->ops.setup_link_speed = - &ixgbe_setup_copper_link_speed_82599; mac->ops.get_link_capabilities = &ixgbe_get_copper_link_capabilities_82599; } @@ -354,13 +346,15 @@ out: } /** - * ixgbe_setup_mac_link_82599 - Setup MAC link settings + * ixgbe_start_mac_link_82599 - Setup MAC link settings * @hw: pointer to hardware structure + * @autoneg_wait_to_complete: true when waiting for completion is needed * * Configures link settings based on values in the ixgbe_hw struct. * Restarts the link. Performs autonegotiation if needed. **/ -static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw) +s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, + bool autoneg_wait_to_complete) { u32 autoc_reg; u32 links_reg; @@ -373,7 +367,7 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); /* Only poll for autoneg to complete if specified to do so */ - if (hw->phy.autoneg_wait_to_complete) { + if (autoneg_wait_to_complete) { if ((autoc_reg & IXGBE_AUTOC_LMS_MASK) == IXGBE_AUTOC_LMS_KX4_KX_KR || (autoc_reg & IXGBE_AUTOC_LMS_MASK) == @@ -401,25 +395,7 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw) } /** - * ixgbe_setup_mac_link_multispeed_fiber - Setup MAC link settings - * @hw: pointer to hardware structure - * - * Configures link settings based on values in the ixgbe_hw struct. - * Restarts the link for multi-speed fiber at 1G speed, if link - * fails at 10G. - * Performs autonegotiation if needed. - **/ -static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw) -{ - s32 status = 0; - ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_82599_AUTONEG; - status = ixgbe_setup_mac_link_speed_multispeed_fiber(hw, link_speed, - true, true); - return status; -} - -/** - * ixgbe_setup_mac_link_speed_multispeed_fiber - Set MAC link speed + * ixgbe_setup_mac_link_multispeed_fiber - Set MAC link speed * @hw: pointer to hardware structure * @speed: new link speed * @autoneg: true if autonegotiation enabled @@ -427,10 +403,10 @@ static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw) * * Set the link speed in the AUTOC register and restarts link. **/ -static s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, - ixgbe_link_speed speed, - bool autoneg, - bool autoneg_wait_to_complete) +s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete) { s32 status = 0; ixgbe_link_speed phy_link_speed; @@ -485,10 +461,10 @@ static s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, /* Allow module to change analog characteristics (1G->10G) */ msleep(40); - status = ixgbe_setup_mac_link_speed_82599(hw, - IXGBE_LINK_SPEED_10GB_FULL, - autoneg, - autoneg_wait_to_complete); + status = ixgbe_setup_mac_link_82599(hw, + IXGBE_LINK_SPEED_10GB_FULL, + autoneg, + autoneg_wait_to_complete); if (status != 0) goto out; @@ -539,7 +515,7 @@ static s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, /* Allow module to change analog characteristics (10G->1G) */ msleep(40); - status = ixgbe_setup_mac_link_speed_82599(hw, + status = ixgbe_setup_mac_link_82599(hw, IXGBE_LINK_SPEED_1GB_FULL, autoneg, autoneg_wait_to_complete); @@ -576,10 +552,10 @@ static s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, * single highest speed that the user requested. */ if (speedcnt > 1) - status = ixgbe_setup_mac_link_speed_multispeed_fiber(hw, - highest_link_speed, - autoneg, - autoneg_wait_to_complete); + status = ixgbe_setup_mac_link_multispeed_fiber(hw, + highest_link_speed, + autoneg, + autoneg_wait_to_complete); out: return status; @@ -640,7 +616,7 @@ static s32 ixgbe_check_mac_link_82599(struct ixgbe_hw *hw, } /** - * ixgbe_setup_mac_link_speed_82599 - Set MAC link speed + * ixgbe_setup_mac_link_82599 - Set MAC link speed * @hw: pointer to hardware structure * @speed: new link speed * @autoneg: true if autonegotiation enabled @@ -648,10 +624,9 @@ static s32 ixgbe_check_mac_link_82599(struct ixgbe_hw *hw, * * Set the link speed in the AUTOC register and restarts link. **/ -static s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, - ixgbe_link_speed speed, - bool autoneg, - bool autoneg_wait_to_complete) +s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, + ixgbe_link_speed speed, bool autoneg, + bool autoneg_wait_to_complete) { s32 status = 0; u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); @@ -751,26 +726,7 @@ out: } /** - * ixgbe_setup_copper_link_82599 - Setup copper link settings - * @hw: pointer to hardware structure - * - * Restarts the link on PHY and then MAC. Performs autonegotiation if needed. - **/ -static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw) -{ - s32 status; - - /* Restart autonegotiation on PHY */ - status = hw->phy.ops.setup_link(hw); - - /* Set up MAC */ - ixgbe_setup_mac_link_82599(hw); - - return status; -} - -/** - * ixgbe_setup_copper_link_speed_82599 - Set the PHY autoneg advertised field + * ixgbe_setup_copper_link_82599 - Set the PHY autoneg advertised field * @hw: pointer to hardware structure * @speed: new link speed * @autoneg: true if autonegotiation enabled @@ -778,10 +734,10 @@ static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw) * * Restarts link on PHY and MAC based on settings passed in. **/ -static s32 ixgbe_setup_copper_link_speed_82599(struct ixgbe_hw *hw, - ixgbe_link_speed speed, - bool autoneg, - bool autoneg_wait_to_complete) +static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete) { s32 status; @@ -789,7 +745,7 @@ static s32 ixgbe_setup_copper_link_speed_82599(struct ixgbe_hw *hw, status = hw->phy.ops.setup_link_speed(hw, speed, autoneg, autoneg_wait_to_complete); /* Set up MAC */ - ixgbe_setup_mac_link_82599(hw); + ixgbe_start_mac_link_82599(hw, autoneg_wait_to_complete); return status; } @@ -2470,7 +2426,6 @@ static struct ixgbe_mac_operations mac_ops_82599 = { .read_analog_reg8 = &ixgbe_read_analog_reg8_82599, .write_analog_reg8 = &ixgbe_write_analog_reg8_82599, .setup_link = &ixgbe_setup_mac_link_82599, - .setup_link_speed = &ixgbe_setup_mac_link_speed_82599, .check_link = &ixgbe_check_mac_link_82599, .get_link_capabilities = &ixgbe_get_link_capabilities_82599, .led_on = &ixgbe_led_on_generic, diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 1444ec51253..026e94a9984 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -233,11 +233,11 @@ static int ixgbe_set_settings(struct net_device *netdev, return err; /* this sets the link speed and restarts auto-neg */ hw->mac.autotry_restart = true; - err = hw->mac.ops.setup_link_speed(hw, advertised, true, true); + err = hw->mac.ops.setup_link(hw, advertised, true, true); if (err) { DPRINTK(PROBE, INFO, "setup link failed with code %d\n", err); - hw->mac.ops.setup_link_speed(hw, old, true, true); + hw->mac.ops.setup_link(hw, old, true, true); } } else { /* in this case we currently only support 10Gb/FULL */ diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index f907836eed2..4042d878670 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2516,7 +2516,7 @@ static void ixgbe_sfp_link_config(struct ixgbe_adapter *adapter) static int ixgbe_non_sfp_link_config(struct ixgbe_hw *hw) { u32 autoneg; - bool link_up = false; + bool negotiation, link_up = false; u32 ret = IXGBE_ERR_LINK_SETUP; if (hw->mac.ops.check_link) @@ -2526,13 +2526,12 @@ static int ixgbe_non_sfp_link_config(struct ixgbe_hw *hw) goto link_cfg_out; if (hw->mac.ops.get_link_capabilities) - ret = hw->mac.ops.get_link_capabilities(hw, &autoneg, - &hw->mac.autoneg); + ret = hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation); if (ret) goto link_cfg_out; - if (hw->mac.ops.setup_link_speed) - ret = hw->mac.ops.setup_link_speed(hw, autoneg, true, link_up); + if (hw->mac.ops.setup_link) + ret = hw->mac.ops.setup_link(hw, autoneg, negotiation, link_up); link_cfg_out: return ret; } @@ -4517,14 +4516,14 @@ static void ixgbe_multispeed_fiber_task(struct work_struct *work) multispeed_fiber_task); struct ixgbe_hw *hw = &adapter->hw; u32 autoneg; + bool negotiation; adapter->flags |= IXGBE_FLAG_IN_SFP_LINK_TASK; autoneg = hw->phy.autoneg_advertised; if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) - hw->mac.ops.get_link_capabilities(hw, &autoneg, - &hw->mac.autoneg); - if (hw->mac.ops.setup_link_speed) - hw->mac.ops.setup_link_speed(hw, autoneg, true, true); + hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation); + if (hw->mac.ops.setup_link) + hw->mac.ops.setup_link(hw, autoneg, negotiation, true); adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; adapter->flags &= ~IXGBE_FLAG_IN_SFP_LINK_TASK; } diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index f0f3406ef00..8ba90eec1dc 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -2332,9 +2332,7 @@ struct ixgbe_mac_operations { s32 (*enable_rx_dma)(struct ixgbe_hw *, u32); /* Link */ - s32 (*setup_link)(struct ixgbe_hw *); - s32 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool, - bool); + s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool, bool); s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool); s32 (*get_link_capabilities)(struct ixgbe_hw *, ixgbe_link_speed *, bool *); @@ -2406,8 +2404,6 @@ struct ixgbe_mac_info { u32 orig_autoc; u32 orig_autoc2; bool orig_link_settings_stored; - bool autoneg; - bool autoneg_succeeded; bool autotry_restart; }; @@ -2422,7 +2418,6 @@ struct ixgbe_phy_info { enum ixgbe_media_type media_type; bool reset_disable; ixgbe_autoneg_advertised autoneg_advertised; - bool autoneg_wait_to_complete; bool multispeed_fiber; }; -- cgit v1.2.3-18-g5258 From b7fdb714856541cd4b659a7b86ec04415e2809f7 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Tue, 1 Sep 2009 13:49:56 +0000 Subject: ixgbe: Properly disable DCB arbiters prior to applying changes When disabling the Rx and Tx data arbiters prior to configuration changes, the arbiters were not being shut down properly. This can create a race in the DCB hardware blocks, and potentially hang the arbiters. Also, the Tx descriptor arbiter shouldn't be disabled when applying configuration changes; disabling this arbiter can cause a Tx hang. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_dcb_82599.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ixgbe/ixgbe_dcb_82599.c index 589f62c7062..ec8a252636d 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82599.c +++ b/drivers/net/ixgbe/ixgbe_dcb_82599.c @@ -145,8 +145,12 @@ s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw, u32 credit_max = 0; u8 i = 0; - /* Disable the arbiter before changing parameters */ - IXGBE_WRITE_REG(hw, IXGBE_RTRPCS, IXGBE_RTRPCS_ARBDIS); + /* + * Disable the arbiter before changing parameters + * (always enable recycle mode; WSP) + */ + reg = IXGBE_RTRPCS_RRM | IXGBE_RTRPCS_RAC | IXGBE_RTRPCS_ARBDIS; + IXGBE_WRITE_REG(hw, IXGBE_RTRPCS, reg); /* Map all traffic classes to their UP, 1 to 1 */ reg = 0; @@ -194,9 +198,6 @@ s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw, u32 reg, max_credits; u8 i; - /* Disable the arbiter before changing parameters */ - IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, IXGBE_RTTDCS_ARBDIS); - /* Clear the per-Tx queue credits; we use per-TC instead */ for (i = 0; i < 128; i++) { IXGBE_WRITE_REG(hw, IXGBE_RTTDQSEL, i); @@ -244,8 +245,14 @@ s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw, u32 reg; u8 i; - /* Disable the arbiter before changing parameters */ - IXGBE_WRITE_REG(hw, IXGBE_RTTPCS, IXGBE_RTTPCS_ARBDIS); + /* + * Disable the arbiter before changing parameters + * (always enable recycle mode; SP; arb delay) + */ + reg = IXGBE_RTTPCS_TPPAC | IXGBE_RTTPCS_TPRM | + (IXGBE_RTTPCS_ARBD_DCB << IXGBE_RTTPCS_ARBD_SHIFT) | + IXGBE_RTTPCS_ARBDIS; + IXGBE_WRITE_REG(hw, IXGBE_RTTPCS, reg); /* Map all traffic classes to their UP, 1 to 1 */ reg = 0; -- cgit v1.2.3-18-g5258 From c3c7432741211bc9f6b072958653647b9d5cdd5d Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Tue, 1 Sep 2009 13:50:14 +0000 Subject: ixgbe: Patch to fix 82599 multispeed fiber link issues when driver is loaded without any cable and reconnecting it to 1G partner In 82599 multi speed fiber case when driver is loaded without any cable and reconnecting the cable with a 1G partner does not bring up the link in 1Gb mode. When there is no link we first setup the link at 10G & 1G and then try to re-establish the link at highest speed 10G and thereby changing autoneg_advertised value to highest speed 10G. After connecting back the cable to a 1G link partner we never try 1G as autoneg advertised value is changed to link at 10G only. The following patch fixes the issue by properly initializing the autoneg_advertised value just before exiting from link setup routine. Signed-off-by: Mallikarjuna R Chilakala Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_82599.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 5ee56085526..61af47e75aa 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -421,15 +421,6 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, hw->mac.ops.get_link_capabilities(hw, &phy_link_speed, &negotiation); speed &= phy_link_speed; - /* Set autoneg_advertised value based on input link speed */ - hw->phy.autoneg_advertised = 0; - - if (speed & IXGBE_LINK_SPEED_10GB_FULL) - hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; - - if (speed & IXGBE_LINK_SPEED_1GB_FULL) - hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; - /* * When the driver changes the link speeds that it can support, * it sets autotry_restart to true to indicate that we need to @@ -466,7 +457,7 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, autoneg, autoneg_wait_to_complete); if (status != 0) - goto out; + return status; /* Flap the tx laser if it has not already been done */ if (hw->mac.autotry_restart) { @@ -520,7 +511,7 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, autoneg, autoneg_wait_to_complete); if (status != 0) - goto out; + return status; /* Flap the tx laser if it has not already been done */ if (hw->mac.autotry_restart) { @@ -558,6 +549,15 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, autoneg_wait_to_complete); out: + /* Set autoneg_advertised value based on input link speed */ + hw->phy.autoneg_advertised = 0; + + if (speed & IXGBE_LINK_SPEED_10GB_FULL) + hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; + + if (speed & IXGBE_LINK_SPEED_1GB_FULL) + hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; + return status; } -- cgit v1.2.3-18-g5258 From ac06713d55d450cbc9ef871b1b238409238f0fe0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 1 Sep 2009 05:46:05 +0000 Subject: macvlan: Use compare_ether_addr_64bits() To speedup ether addresses compares, we can use compare_ether_addr_64bits() (all operands are guaranteed to be at least 8 bytes long) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index f893cd41580..c85c46d2a30 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -54,7 +54,7 @@ static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port, struct hlist_node *n; hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[addr[5]], hlist) { - if (!compare_ether_addr(vlan->dev->dev_addr, addr)) + if (!compare_ether_addr_64bits(vlan->dev->dev_addr, addr)) return vlan; } return NULL; @@ -92,7 +92,7 @@ static int macvlan_addr_busy(const struct macvlan_port *port, * currently in use by the underlying device or * another macvlan. */ - if (memcmp(port->dev->dev_addr, addr, ETH_ALEN) == 0) + if (!compare_ether_addr_64bits(port->dev->dev_addr, addr)) return 1; if (macvlan_hash_lookup(port, addr)) @@ -130,7 +130,7 @@ static void macvlan_broadcast(struct sk_buff *skb, dev->stats.multicast++; nskb->dev = dev; - if (!compare_ether_addr(eth->h_dest, dev->broadcast)) + if (!compare_ether_addr_64bits(eth->h_dest, dev->broadcast)) nskb->pkt_type = PACKET_BROADCAST; else nskb->pkt_type = PACKET_MULTICAST; -- cgit v1.2.3-18-g5258 From 885a136c52a8871175477baf3903e1c38751b35a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 1 Sep 2009 06:31:18 +0000 Subject: bonding: use compare_ether_addr_64bits() in ALB We can speedup ether addresses compares using compare_ether_addr_64bits() instead of memcmp(). We make sure all operands are at least 8 bytes long and 16bits aligned (or better, long word aligned if possible) Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/bonding/bond_alb.c | 71 ++++++++++++++++++++++-------------------- drivers/net/bonding/bonding.h | 2 +- 2 files changed, 38 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 2108706d2f0..9b5936f072d 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -79,8 +79,15 @@ */ #define RLB_PROMISC_TIMEOUT 10*ALB_TIMER_TICKS_PER_SEC -static const u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; -static const u8 mac_v6_allmcast[ETH_ALEN] = {0x33,0x33,0x00,0x00,0x00,0x01}; +#ifndef __long_aligned +#define __long_aligned __attribute__((aligned((sizeof(long))))) +#endif +static const u8 mac_bcast[ETH_ALEN] __long_aligned = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; +static const u8 mac_v6_allmcast[ETH_ALEN] __long_aligned = { + 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 +}; static const int alb_delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC; #pragma pack(1) @@ -460,8 +467,8 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave) if (assigned_slave) { rx_hash_table[index].slave = assigned_slave; - if (memcmp(rx_hash_table[index].mac_dst, - mac_bcast, ETH_ALEN)) { + if (compare_ether_addr_64bits(rx_hash_table[index].mac_dst, + mac_bcast)) { bond_info->rx_hashtbl[index].ntt = 1; bond_info->rx_ntt = 1; /* A slave has been removed from the @@ -575,7 +582,7 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla client_info = &(bond_info->rx_hashtbl[hash_index]); if ((client_info->slave == slave) && - memcmp(client_info->mac_dst, mac_bcast, ETH_ALEN)) { + compare_ether_addr_64bits(client_info->mac_dst, mac_bcast)) { client_info->ntt = 1; ntt = 1; } @@ -616,9 +623,9 @@ static void rlb_req_update_subnet_clients(struct bonding *bond, __be32 src_ip) * unicast mac address. */ if ((client_info->ip_src == src_ip) && - memcmp(client_info->slave->dev->dev_addr, - bond->dev->dev_addr, ETH_ALEN) && - memcmp(client_info->mac_dst, mac_bcast, ETH_ALEN)) { + compare_ether_addr_64bits(client_info->slave->dev->dev_addr, + bond->dev->dev_addr) && + compare_ether_addr_64bits(client_info->mac_dst, mac_bcast)) { client_info->ntt = 1; bond_info->rx_ntt = 1; } @@ -645,7 +652,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon if ((client_info->ip_src == arp->ip_src) && (client_info->ip_dst == arp->ip_dst)) { /* the entry is already assigned to this client */ - if (memcmp(arp->mac_dst, mac_bcast, ETH_ALEN)) { + if (compare_ether_addr_64bits(arp->mac_dst, mac_bcast)) { /* update mac address from arp */ memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN); } @@ -680,7 +687,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN); client_info->slave = assigned_slave; - if (memcmp(client_info->mac_dst, mac_bcast, ETH_ALEN)) { + if (compare_ether_addr_64bits(client_info->mac_dst, mac_bcast)) { client_info->ntt = 1; bond->alb_info.rx_ntt = 1; } else { @@ -1046,21 +1053,18 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla int perm_curr_diff; int perm_bond_diff; - perm_curr_diff = memcmp(slave->perm_hwaddr, - slave->dev->dev_addr, - ETH_ALEN); - perm_bond_diff = memcmp(slave->perm_hwaddr, - bond->dev->dev_addr, - ETH_ALEN); + perm_curr_diff = compare_ether_addr_64bits(slave->perm_hwaddr, + slave->dev->dev_addr); + perm_bond_diff = compare_ether_addr_64bits(slave->perm_hwaddr, + bond->dev->dev_addr); if (perm_curr_diff && perm_bond_diff) { struct slave *tmp_slave; int i, found = 0; bond_for_each_slave(bond, tmp_slave, i) { - if (!memcmp(slave->perm_hwaddr, - tmp_slave->dev->dev_addr, - ETH_ALEN)) { + if (!compare_ether_addr_64bits(slave->perm_hwaddr, + tmp_slave->dev->dev_addr)) { found = 1; break; } @@ -1114,10 +1118,10 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav * check uniqueness of slave's mac address against the other * slaves in the bond. */ - if (memcmp(slave->perm_hwaddr, bond->dev->dev_addr, ETH_ALEN)) { + if (compare_ether_addr_64bits(slave->perm_hwaddr, bond->dev->dev_addr)) { bond_for_each_slave(bond, tmp_slave1, i) { - if (!memcmp(tmp_slave1->dev->dev_addr, slave->dev->dev_addr, - ETH_ALEN)) { + if (!compare_ether_addr_64bits(tmp_slave1->dev->dev_addr, + slave->dev->dev_addr)) { found = 1; break; } @@ -1140,9 +1144,8 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav bond_for_each_slave(bond, tmp_slave1, i) { found = 0; bond_for_each_slave(bond, tmp_slave2, j) { - if (!memcmp(tmp_slave1->perm_hwaddr, - tmp_slave2->dev->dev_addr, - ETH_ALEN)) { + if (!compare_ether_addr_64bits(tmp_slave1->perm_hwaddr, + tmp_slave2->dev->dev_addr)) { found = 1; break; } @@ -1157,9 +1160,8 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav } if (!has_bond_addr) { - if (!memcmp(tmp_slave1->dev->dev_addr, - bond->dev->dev_addr, - ETH_ALEN)) { + if (!compare_ether_addr_64bits(tmp_slave1->dev->dev_addr, + bond->dev->dev_addr)) { has_bond_addr = tmp_slave1; } @@ -1313,7 +1315,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) case ETH_P_IP: { const struct iphdr *iph = ip_hdr(skb); - if ((memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) || + if (!compare_ether_addr_64bits(eth_data->h_dest, mac_bcast) || (iph->daddr == ip_bcast) || (iph->protocol == IPPROTO_IGMP)) { do_tx_balance = 0; @@ -1327,7 +1329,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) /* IPv6 doesn't really use broadcast mac address, but leave * that here just in case. */ - if (memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) { + if (!compare_ether_addr_64bits(eth_data->h_dest, mac_bcast)) { do_tx_balance = 0; break; } @@ -1335,7 +1337,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) /* IPv6 uses all-nodes multicast as an equivalent to * broadcasts in IPv4. */ - if (memcmp(eth_data->h_dest, mac_v6_allmcast, ETH_ALEN) == 0) { + if (!compare_ether_addr_64bits(eth_data->h_dest, mac_v6_allmcast)) { do_tx_balance = 0; break; } @@ -1660,8 +1662,8 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave struct slave *tmp_slave; /* find slave that is holding the bond's mac address */ bond_for_each_slave(bond, tmp_slave, i) { - if (!memcmp(tmp_slave->dev->dev_addr, - bond->dev->dev_addr, ETH_ALEN)) { + if (!compare_ether_addr_64bits(tmp_slave->dev->dev_addr, + bond->dev->dev_addr)) { swap_slave = tmp_slave; break; } @@ -1739,7 +1741,8 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) swap_slave = NULL; bond_for_each_slave(bond, slave, i) { - if (!memcmp(slave->dev->dev_addr, bond_dev->dev_addr, ETH_ALEN)) { + if (!compare_ether_addr_64bits(slave->dev->dev_addr, + bond_dev->dev_addr)) { swap_slave = slave; break; } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 6290a502742..68247714466 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -163,9 +163,9 @@ struct slave { u32 original_flags; u32 original_mtu; u32 link_failure_count; + u8 perm_hwaddr[ETH_ALEN]; u16 speed; u8 duplex; - u8 perm_hwaddr[ETH_ALEN]; struct ad_slave_info ad_info; /* HUGE - better to dynamically alloc */ struct tlb_slave_info tlb_info; }; -- cgit v1.2.3-18-g5258 From 89f56d1e91cfa535ccc6cc60e9e12e02682fd972 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Sun, 30 Aug 2009 07:04:42 +0000 Subject: tun: reuse struct sock fields As tun always has an embeedded struct sock, use sk and sk_receive_queue fields instead of duplicating them in tun_struct. Signed-off-by: Michael S. Tsirkin Signed-off-by: David S. Miller --- drivers/net/tun.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 5f7842e4d4a..589a44acdc7 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -103,13 +103,10 @@ struct tun_struct { uid_t owner; gid_t group; - struct sk_buff_head readq; - struct net_device *dev; struct fasync_struct *fasync; struct tap_filter txflt; - struct sock *sk; struct socket socket; #ifdef TUN_DEBUG @@ -155,7 +152,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file) tfile->tun = tun; tun->tfile = tfile; dev_hold(tun->dev); - sock_hold(tun->sk); + sock_hold(tun->socket.sk); atomic_inc(&tfile->count); out: @@ -171,7 +168,7 @@ static void __tun_detach(struct tun_struct *tun) netif_tx_unlock_bh(tun->dev); /* Drop read queue */ - skb_queue_purge(&tun->readq); + skb_queue_purge(&tun->socket.sk->sk_receive_queue); /* Drop the extra count on the net device */ dev_put(tun->dev); @@ -340,7 +337,7 @@ static void tun_free_netdev(struct net_device *dev) { struct tun_struct *tun = netdev_priv(dev); - sock_put(tun->sk); + sock_put(tun->socket.sk); } /* Net device open. */ @@ -374,7 +371,7 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) if (!check_filter(&tun->txflt, skb)) goto drop; - if (skb_queue_len(&tun->readq) >= dev->tx_queue_len) { + if (skb_queue_len(&tun->socket.sk->sk_receive_queue) >= dev->tx_queue_len) { if (!(tun->flags & TUN_ONE_QUEUE)) { /* Normal queueing mode. */ /* Packet scheduler handles dropping of further packets. */ @@ -391,7 +388,7 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) } /* Enqueue packet */ - skb_queue_tail(&tun->readq, skb); + skb_queue_tail(&tun->socket.sk->sk_receive_queue, skb); dev->trans_start = jiffies; /* Notify and wake up reader process */ @@ -492,13 +489,13 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait) if (!tun) return POLLERR; - sk = tun->sk; + sk = tun->socket.sk; DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name); poll_wait(file, &tun->socket.wait, wait); - if (!skb_queue_empty(&tun->readq)) + if (!skb_queue_empty(&sk->sk_receive_queue)) mask |= POLLIN | POLLRDNORM; if (sock_writeable(sk) || @@ -519,7 +516,7 @@ static inline struct sk_buff *tun_alloc_skb(struct tun_struct *tun, size_t prepad, size_t len, size_t linear, int noblock) { - struct sock *sk = tun->sk; + struct sock *sk = tun->socket.sk; struct sk_buff *skb; int err; @@ -787,7 +784,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, current->state = TASK_INTERRUPTIBLE; /* Read frames from the queue */ - if (!(skb=skb_dequeue(&tun->readq))) { + if (!(skb=skb_dequeue(&tun->socket.sk->sk_receive_queue))) { if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; break; @@ -824,8 +821,6 @@ static void tun_setup(struct net_device *dev) { struct tun_struct *tun = netdev_priv(dev); - skb_queue_head_init(&tun->readq); - tun->owner = -1; tun->group = -1; @@ -991,7 +986,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) sk->sk_write_space = tun_sock_write_space; sk->sk_sndbuf = INT_MAX; - tun->sk = sk; container_of(sk, struct tun_sock, sk)->tun = tun; tun_net_init(dev); @@ -1249,7 +1243,7 @@ static long tun_chr_ioctl(struct file *file, unsigned int cmd, break; case TUNGETSNDBUF: - sndbuf = tun->sk->sk_sndbuf; + sndbuf = tun->socket.sk->sk_sndbuf; if (copy_to_user(argp, &sndbuf, sizeof(sndbuf))) ret = -EFAULT; break; @@ -1260,7 +1254,7 @@ static long tun_chr_ioctl(struct file *file, unsigned int cmd, break; } - tun->sk->sk_sndbuf = sndbuf; + tun->socket.sk->sk_sndbuf = sndbuf; break; default: @@ -1343,7 +1337,7 @@ static int tun_chr_close(struct inode *inode, struct file *file) tun = tfile->tun; if (tun) - sock_put(tun->sk); + sock_put(tun->socket.sk); put_net(tfile->net); kfree(tfile); -- cgit v1.2.3-18-g5258 From 10547ae2c01acdace636e23c991b21fef05428b4 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 07:31:41 +0000 Subject: sky2: fix management of driver LED Observed by Mike McCormack. The LED bit here is just a software controlled value used to turn on one of the LED's on some boards. The register value was wrong, which could have been causing some power control issues. Get rid of problematic define use the correct mask. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 12 ++++++------ drivers/net/sky2.h | 9 +-------- 2 files changed, 7 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index c7c0a5b7b53..ba5180a2326 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -256,6 +256,9 @@ static void sky2_power_on(struct sky2_hw *hw) sky2_read32(hw, B2_GP_IO); } + + /* Turn on "driver loaded" LED */ + sky2_write16(hw, B0_CTST, Y2_LED_STAT_ON); } static void sky2_power_aux(struct sky2_hw *hw) @@ -274,6 +277,9 @@ static void sky2_power_aux(struct sky2_hw *hw) sky2_write8(hw, B0_POWER_CTRL, (PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF)); + + /* turn off "driver loaded LED" */ + sky2_write16(hw, B0_CTST, Y2_LED_STAT_OFF); } static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port) @@ -1867,9 +1873,6 @@ static int sky2_down(struct net_device *dev) sky2_phy_power_down(hw, port); spin_unlock_bh(&sky2->phy_lock); - /* turn off LED's */ - sky2_write16(hw, B0_Y2LED, LED_STAT_OFF); - sky2_tx_reset(hw, port); /* Free any pending frames stuck in HW queue */ @@ -2983,8 +2986,6 @@ static void sky2_reset(struct sky2_hw *hw) sky2_write8(hw, B2_TI_CTRL, TIM_STOP); sky2_write8(hw, B2_TI_CTRL, TIM_CLR_IRQ); - sky2_write8(hw, B0_Y2LED, LED_STAT_ON); - /* Turn off descriptor polling */ sky2_write32(hw, B28_DPT_CTRL, DPT_STOP); @@ -4601,7 +4602,6 @@ static void __devexit sky2_remove(struct pci_dev *pdev) sky2_power_aux(hw); - sky2_write16(hw, B0_Y2LED, LED_STAT_OFF); sky2_write8(hw, B0_CTST, CS_RST_SET); sky2_read8(hw, B0_CTST); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 73c95471246..34042ff7c12 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -155,7 +155,7 @@ enum pci_cfg_reg1 { enum csr_regs { B0_RAP = 0x0000, B0_CTST = 0x0004, - B0_Y2LED = 0x0005, + B0_POWER_CTRL = 0x0007, B0_ISRC = 0x0008, B0_IMSK = 0x000c, @@ -283,13 +283,6 @@ enum { CS_RST_SET = 1, /* Set Software reset */ }; -/* B0_LED 8 Bit LED register */ -enum { -/* Bit 7.. 2: reserved */ - LED_STAT_ON = 1<<1, /* Status LED on */ - LED_STAT_OFF = 1, /* Status LED off */ -}; - /* B0_POWER_CTRL 8 Bit Power Control reg (YUKON only) */ enum { PC_VAUX_ENA = 1<<7, /* Switch VAUX Enable */ -- cgit v1.2.3-18-g5258 From 90bbebb4a8258a398705ecaa2e6b9e177928ee7a Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Tue, 1 Sep 2009 03:21:35 +0000 Subject: sky2: Create buffer alloc and free helpers Refactor similar two sections of code that free buffers into one. Only call tx_init if all buffer allocations succeed. Signed-off-by: Mike McCormack Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 113 ++++++++++++++++++++++++++++------------------------- 1 file changed, 60 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index ba5180a2326..7108b1292b9 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1405,6 +1405,61 @@ nomem: return -ENOMEM; } +static int sky2_alloc_buffers(struct sky2_port *sky2) +{ + struct sky2_hw *hw = sky2->hw; + + /* must be power of 2 */ + sky2->tx_le = pci_alloc_consistent(hw->pdev, + sky2->tx_ring_size * + sizeof(struct sky2_tx_le), + &sky2->tx_le_map); + if (!sky2->tx_le) + goto nomem; + + sky2->tx_ring = kcalloc(sky2->tx_ring_size, sizeof(struct tx_ring_info), + GFP_KERNEL); + if (!sky2->tx_ring) + goto nomem; + + sky2->rx_le = pci_alloc_consistent(hw->pdev, RX_LE_BYTES, + &sky2->rx_le_map); + if (!sky2->rx_le) + goto nomem; + memset(sky2->rx_le, 0, RX_LE_BYTES); + + sky2->rx_ring = kcalloc(sky2->rx_pending, sizeof(struct rx_ring_info), + GFP_KERNEL); + if (!sky2->rx_ring) + goto nomem; + + return 0; +nomem: + return -ENOMEM; +} + +static void sky2_free_buffers(struct sky2_port *sky2) +{ + struct sky2_hw *hw = sky2->hw; + + if (sky2->rx_le) { + pci_free_consistent(hw->pdev, RX_LE_BYTES, + sky2->rx_le, sky2->rx_le_map); + sky2->rx_le = NULL; + } + if (sky2->tx_le) { + pci_free_consistent(hw->pdev, + sky2->tx_ring_size * sizeof(struct sky2_tx_le), + sky2->tx_le, sky2->tx_le_map); + sky2->tx_le = NULL; + } + kfree(sky2->tx_ring); + kfree(sky2->rx_ring); + + sky2->tx_ring = NULL; + sky2->rx_ring = NULL; +} + /* Bring up network interface. */ static int sky2_up(struct net_device *dev) { @@ -1412,7 +1467,7 @@ static int sky2_up(struct net_device *dev) struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; u32 imask, ramsize; - int cap, err = -ENOMEM; + int cap, err; struct net_device *otherdev = hw->dev[sky2->port^1]; /* @@ -1431,32 +1486,12 @@ static int sky2_up(struct net_device *dev) netif_carrier_off(dev); - /* must be power of 2 */ - sky2->tx_le = pci_alloc_consistent(hw->pdev, - sky2->tx_ring_size * - sizeof(struct sky2_tx_le), - &sky2->tx_le_map); - if (!sky2->tx_le) - goto err_out; - - sky2->tx_ring = kcalloc(sky2->tx_ring_size, sizeof(struct tx_ring_info), - GFP_KERNEL); - if (!sky2->tx_ring) + err = sky2_alloc_buffers(sky2); + if (err) goto err_out; tx_init(sky2); - sky2->rx_le = pci_alloc_consistent(hw->pdev, RX_LE_BYTES, - &sky2->rx_le_map); - if (!sky2->rx_le) - goto err_out; - memset(sky2->rx_le, 0, RX_LE_BYTES); - - sky2->rx_ring = kcalloc(sky2->rx_pending, sizeof(struct rx_ring_info), - GFP_KERNEL); - if (!sky2->rx_ring) - goto err_out; - sky2_mac_init(hw, port); /* Register is number of 4K blocks on internal RAM buffer. */ @@ -1513,22 +1548,7 @@ static int sky2_up(struct net_device *dev) return 0; err_out: - if (sky2->rx_le) { - pci_free_consistent(hw->pdev, RX_LE_BYTES, - sky2->rx_le, sky2->rx_le_map); - sky2->rx_le = NULL; - } - if (sky2->tx_le) { - pci_free_consistent(hw->pdev, - sky2->tx_ring_size * sizeof(struct sky2_tx_le), - sky2->tx_le, sky2->tx_le_map); - sky2->tx_le = NULL; - } - kfree(sky2->tx_ring); - kfree(sky2->rx_ring); - - sky2->tx_ring = NULL; - sky2->rx_ring = NULL; + sky2_free_buffers(sky2); return err; } @@ -1880,20 +1900,7 @@ static int sky2_down(struct net_device *dev) sky2_rx_clean(sky2); - pci_free_consistent(hw->pdev, RX_LE_BYTES, - sky2->rx_le, sky2->rx_le_map); - kfree(sky2->rx_ring); - - pci_free_consistent(hw->pdev, - sky2->tx_ring_size * sizeof(struct sky2_tx_le), - sky2->tx_le, sky2->tx_le_map); - kfree(sky2->tx_ring); - - sky2->tx_le = NULL; - sky2->rx_le = NULL; - - sky2->rx_ring = NULL; - sky2->tx_ring = NULL; + sky2_free_buffers(sky2); return 0; } -- cgit v1.2.3-18-g5258 From 72c60683282a6cd047db47d605eb96e2a6fac72c Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Tue, 1 Sep 2009 03:54:27 +0000 Subject: sky2: Use 32bit read to read Y2_VAUX_AVAIL B0_CTST is a 24bit register according to the vendor driver (sk98lin). A 16bit read on B0_CTST will always return 0 for Y2_VAUX_AVAIL (1<<16), so use a 32bit read when testing Y2_VAUX_AVAIL Signed-off-by: Mike McCormack Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 2 +- drivers/net/sky2.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 7108b1292b9..d1f3b46a2b0 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -273,7 +273,7 @@ static void sky2_power_aux(struct sky2_hw *hw) Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS); /* switch power to VAUX */ - if (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL) + if (sky2_read32(hw, B0_CTST) & Y2_VAUX_AVAIL) sky2_write8(hw, B0_POWER_CTRL, (PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF)); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 34042ff7c12..e0f23a10104 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -260,7 +260,7 @@ enum csr_regs { Y2_CFG_AER = 0x1d00, /* PCI Advanced Error Report region */ }; -/* B0_CTST 16 bit Control/Status register */ +/* B0_CTST 24 bit Control/Status register */ enum { Y2_VMAIN_AVAIL = 1<<17,/* VMAIN available (YUKON-2 only) */ Y2_VAUX_AVAIL = 1<<16,/* VAUX available (YUKON-2 only) */ -- cgit v1.2.3-18-g5258 From dcbfef820bdd1cdb412ccf234840e23edf67014f Mon Sep 17 00:00:00 2001 From: roel kluin Date: Sun, 30 Aug 2009 22:40:15 +0000 Subject: au1000_eth: possible NULL dereference of aup->mii_bus->irq in au1000_probe() aup->mii_bus->irq allocation may fail, prevent a dereference of NULL. Signed-off-by: Roel Kluin Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/au1000_eth.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 407fd45f56a..fdf5937233f 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -1157,6 +1157,9 @@ static struct net_device * au1000_probe(int port_num) aup->mii_bus->name = "au1000_eth_mii"; snprintf(aup->mii_bus->id, MII_BUS_ID_SIZE, "%x", aup->mac_id); aup->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); + if (aup->mii_bus->irq == NULL) + goto err_out; + for(i = 0; i < PHY_MAX_ADDR; ++i) aup->mii_bus->irq[i] = PHY_POLL; -- cgit v1.2.3-18-g5258 From 3732e9bd2d841db588624b1bf560bfc9d0dcb1fd Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 1 Sep 2009 17:50:50 -0700 Subject: xilinx_emaclite: Fix permissions on driver sources. Noticed by Michal Simek. Signed-off-by: David S. Miller --- drivers/net/xilinx_emaclite.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 drivers/net/xilinx_emaclite.c (limited to 'drivers') diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c old mode 100755 new mode 100644 -- cgit v1.2.3-18-g5258 From f19af9c2cc015e42dfe4bd5c383e32066ec2801c Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 12:47:49 +0000 Subject: tg3: inline tg3_cond_int() This patch inlines the code of tg3_cond_int() into the function's only callsite. This prep work makes the following patch cleaner. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 9d5c1786c66..65ff286b508 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -618,18 +618,9 @@ static void tg3_disable_ints(struct tg3 *tp) tw32_mailbox_f(tp->napi[0].int_mbox, 0x00000001); } -static inline void tg3_cond_int(struct tg3 *tp) -{ - if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && - (tp->napi[0].hw_status->status & SD_STATUS_UPDATED)) - tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); - else - tw32(HOSTCC_MODE, tp->coalesce_mode | - (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW)); -} - static void tg3_enable_ints(struct tg3 *tp) { + u32 coal_now; struct tg3_napi *tnapi = &tp->napi[0]; tp->irq_sync = 0; wmb(); @@ -639,7 +630,16 @@ static void tg3_enable_ints(struct tg3 *tp) tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); - tg3_cond_int(tp); + + coal_now = HOSTCC_MODE_NOW; + + /* Force an initial interrupt */ + if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && + (tp->napi[0].hw_status->status & SD_STATUS_UPDATED)) + tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); + else + tw32(HOSTCC_MODE, tp->coalesce_mode | + HOSTCC_MODE_ENABLE | coal_now); } static inline unsigned int tg3_has_work(struct tg3_napi *tnapi) -- cgit v1.2.3-18-g5258 From fd2ce37f8e4a570ce90b141a2e7c476c5b399836 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 12:51:13 +0000 Subject: tg3: Add per-int coalesce now member Each interrupt vector has its own bit in the host coalescing register to force that vector's status block to be updated and generate an interrupt. This patch adds a member to the per-interrupt structure that records which bit belongs to that vector. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 16 +++++++++------- drivers/net/tg3.h | 2 ++ 2 files changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 65ff286b508..ff65ae8b592 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -631,7 +631,7 @@ static void tg3_enable_ints(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); - coal_now = HOSTCC_MODE_NOW; + coal_now = tnapi->coal_now; /* Force an initial interrupt */ if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && @@ -682,7 +682,7 @@ static void tg3_int_reenable(struct tg3_napi *tnapi) if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && tg3_has_work(tnapi)) tw32(HOSTCC_MODE, tp->coalesce_mode | - (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW)); + HOSTCC_MODE_ENABLE | tnapi->coal_now); } static inline void tg3_netif_stop(struct tg3 *tp) @@ -7622,7 +7622,7 @@ static void tg3_timer(unsigned long __opaque) tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); } else { tw32(HOSTCC_MODE, tp->coalesce_mode | - (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW)); + HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW); } if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { @@ -7765,7 +7765,7 @@ static int tg3_test_interrupt(struct tg3 *tp) tg3_enable_ints(tp); tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE | - HOSTCC_MODE_NOW); + tnapi->coal_now); for (i = 0; i < 5; i++) { u32 int_mbox, misc_host_ctrl; @@ -9840,7 +9840,7 @@ static int tg3_test_memory(struct tg3 *tp) static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) { u32 mac_mode, rx_start_idx, rx_idx, tx_idx, opaque_key; - u32 desc_idx; + u32 desc_idx, coal_now; struct sk_buff *skb, *rx_skb; u8 *tx_data; dma_addr_t map; @@ -9851,6 +9851,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) tnapi = &tp->napi[0]; rnapi = &tp->napi[0]; + coal_now = tnapi->coal_now | rnapi->coal_now; if (loopback_mode == TG3_MAC_LOOPBACK) { /* HW errata - mac loopback fails in some cases on 5780. @@ -9929,7 +9930,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) map = pci_map_single(tp->pdev, skb->data, tx_len, PCI_DMA_TODEVICE); tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE | - HOSTCC_MODE_NOW); + rnapi->coal_now); udelay(10); @@ -9950,7 +9951,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) /* 250 usec to allow enough time on some 10/100 Mbps devices. */ for (i = 0; i < 25; i++) { tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE | - HOSTCC_MODE_NOW); + coal_now); udelay(10); @@ -13428,6 +13429,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tp->napi[0].int_mbox = MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW; tp->napi[0].consmbox = MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW; tp->napi[0].prodmbox = MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW; + tp->napi[0].coal_now = HOSTCC_MODE_NOW; tp->napi[0].tx_pending = TG3_DEF_TX_RING_PENDING; netif_napi_add(dev, &tp->napi[0].napi, tg3_poll, 64); dev->ethtool_ops = &tg3_ethtool_ops; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index a816b2c0f16..626b96805c3 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1031,6 +1031,7 @@ #define HOSTCC_MODE_CLRTICK_TXBD 0x00000400 #define HOSTCC_MODE_NOINT_ON_NOW 0x00000800 #define HOSTCC_MODE_NOINT_ON_FORCE 0x00001000 +#define HOSTCC_MODE_COAL_VEC1_NOW 0x00002000 #define HOSTCC_STATUS 0x00003c04 #define HOSTCC_STATUS_ERROR_ATTN 0x00000004 #define HOSTCC_RXCOL_TICKS 0x00003c08 @@ -2497,6 +2498,7 @@ struct tg3_napi { u32 last_tag; u32 last_irq_tag; u32 int_mbox; + u32 coal_now; u32 tx_prod; u32 tx_cons; u32 tx_pending; -- cgit v1.2.3-18-g5258 From 2d31ecaf10c4ae03d49aed516481b2839b0220f6 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 12:53:31 +0000 Subject: tg3: Create tg3_rings_reset() This patch moves most of the chip ring setup logic into a separate function. This will make it easier to verify the multi ring setup changes. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 140 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 81 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index ff65ae8b592..14cead69c4c 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6817,6 +6817,76 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) } } +/* tp->lock is held. */ +static void tg3_rings_reset(struct tg3 *tp) +{ + int i; + u32 txrcb, rxrcb, limit; + struct tg3_napi *tnapi = &tp->napi[0]; + + /* Disable all transmit rings but the first. */ + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 16; + else + limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE; + + for (txrcb = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE; + txrcb < limit; txrcb += TG3_BDINFO_SIZE) + tg3_write_mem(tp, txrcb + TG3_BDINFO_MAXLEN_FLAGS, + BDINFO_FLAGS_DISABLED); + + + /* Disable all receive return rings but the first. */ + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 16; + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) + limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 4; + else + limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE; + + for (rxrcb = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE; + rxrcb < limit; rxrcb += TG3_BDINFO_SIZE) + tg3_write_mem(tp, rxrcb + TG3_BDINFO_MAXLEN_FLAGS, + BDINFO_FLAGS_DISABLED); + + /* Disable interrupts */ + tw32_mailbox_f(tp->napi[0].int_mbox, 1); + + /* Zero mailbox registers. */ + tp->napi[0].tx_prod = 0; + tp->napi[0].tx_cons = 0; + tw32_mailbox(tp->napi[0].prodmbox, 0); + tw32_rx_mbox(tp->napi[0].consmbox, 0); + + /* Make sure the NIC-based send BD rings are disabled. */ + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + u32 mbox = MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW; + for (i = 0; i < 16; i++) + tw32_tx_mbox(mbox + i * 8, 0); + } + + txrcb = NIC_SRAM_SEND_RCB; + rxrcb = NIC_SRAM_RCV_RET_RCB; + + /* Clear status block in ram. */ + memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); + + /* Set status block DMA address */ + tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH, + ((u64) tnapi->status_mapping >> 32)); + tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW, + ((u64) tnapi->status_mapping & 0xffffffff)); + + tg3_set_bdinfo(tp, txrcb, tnapi->tx_desc_mapping, + (TG3_TX_RING_SIZE << + BDINFO_FLAGS_MAXLEN_SHIFT), + NIC_SRAM_TX_BUFFER_DESC); + + tg3_set_bdinfo(tp, rxrcb, tnapi->rx_rcb_mapping, + (TG3_RX_RCB_RING_SIZE(tp) << + BDINFO_FLAGS_MAXLEN_SHIFT), 0); +} + /* tp->lock is held. */ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) { @@ -7091,48 +7161,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS, val); - /* There is only one send ring on 5705/5750, no need to explicitly - * disable the others. - */ - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { - /* Clear out send RCB ring in SRAM. */ - for (i = NIC_SRAM_SEND_RCB; i < NIC_SRAM_RCV_RET_RCB; i += TG3_BDINFO_SIZE) - tg3_write_mem(tp, i + TG3_BDINFO_MAXLEN_FLAGS, - BDINFO_FLAGS_DISABLED); - } - - tp->napi[0].tx_prod = 0; - tp->napi[0].tx_cons = 0; - tw32_tx_mbox(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0); - - val = MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW; - tw32_mailbox(val, 0); - - tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB, - tp->napi[0].tx_desc_mapping, - (TG3_TX_RING_SIZE << - BDINFO_FLAGS_MAXLEN_SHIFT), - NIC_SRAM_TX_BUFFER_DESC); - - /* There is only one receive return ring on 5705/5750, no need - * to explicitly disable the others. - */ - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { - for (i = NIC_SRAM_RCV_RET_RCB; i < NIC_SRAM_STATS_BLK; - i += TG3_BDINFO_SIZE) { - tg3_write_mem(tp, i + TG3_BDINFO_MAXLEN_FLAGS, - BDINFO_FLAGS_DISABLED); - } - } - - tw32_rx_mbox(tp->napi[0].consmbox, 0); - - tg3_set_bdinfo(tp, NIC_SRAM_RCV_RET_RCB, - tp->napi[0].rx_rcb_mapping, - (TG3_RX_RCB_RING_SIZE(tp) << - BDINFO_FLAGS_MAXLEN_SHIFT), - 0); - tpr->rx_std_ptr = tp->rx_pending; tw32_rx_mbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW, tpr->rx_std_ptr); @@ -7142,6 +7170,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32_rx_mbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW, tpr->rx_jmb_ptr); + tg3_rings_reset(tp); + /* Initialize MAC address and backoff seed. */ __tg3_set_mac_addr(tp, 0); @@ -7229,12 +7259,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) __tg3_set_coalesce(tp, &tp->coal); - /* set status block DMA address */ - tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH, - ((u64) tp->napi[0].status_mapping >> 32)); - tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW, - ((u64) tp->napi[0].status_mapping & 0xffffffff)); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { /* Status/statistics block address. See tg3_timer, * the tg3_periodic_fetch_stats call there, and @@ -7245,7 +7269,16 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW, ((u64) tp->stats_mapping & 0xffffffff)); tw32(HOSTCC_STATS_BLK_NIC_ADDR, NIC_SRAM_STATS_BLK); + tw32(HOSTCC_STATUS_BLK_NIC_ADDR, NIC_SRAM_STATUS_BLK); + + /* Clear statistics and status block memory areas */ + for (i = NIC_SRAM_STATS_BLK; + i < NIC_SRAM_STATUS_BLK + TG3_HW_STATUS_SIZE; + i += sizeof(u32)) { + tg3_write_mem(tp, i, 0); + udelay(40); + } } tw32(HOSTCC_MODE, HOSTCC_MODE_ENABLE | tp->coalesce_mode); @@ -7255,15 +7288,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) tw32(RCVLSC_MODE, RCVLSC_MODE_ENABLE | RCVLSC_MODE_ATTN_ENABLE); - /* Clear statistics/status block in chip, and status block in ram. */ - for (i = NIC_SRAM_STATS_BLK; - i < NIC_SRAM_STATUS_BLK + TG3_HW_STATUS_SIZE; - i += sizeof(u32)) { - tg3_write_mem(tp, i, 0); - udelay(40); - } - memset(tp->napi[0].hw_status, 0, TG3_HW_STATUS_SIZE); - if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) { tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT; /* reset to prevent losing 1st rx packet intermittently */ @@ -7315,8 +7339,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); udelay(100); - tw32_mailbox_f(tp->napi[0].int_mbox, 0); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { tw32_f(DMAC_MODE, DMAC_MODE_ENABLE); udelay(40); -- cgit v1.2.3-18-g5258 From 4f125f42dd55390016e21f8b3960f99d02d1001f Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 12:55:02 +0000 Subject: tg3: Add support code around kernel interrupt API This patch adds code to support multiple interrupt vectors around the kernel's interrupt API. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 73 +++++++++++++++++++++++++++++++++++++++++-------------- drivers/net/tg3.h | 6 +++++ 2 files changed, 61 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 14cead69c4c..7717eae1221 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4729,12 +4729,15 @@ tx_recovery: static void tg3_irq_quiesce(struct tg3 *tp) { + int i; + BUG_ON(tp->irq_sync); tp->irq_sync = 1; smp_mb(); - synchronize_irq(tp->pdev->irq); + for (i = 0; i < tp->irq_cnt; i++) + synchronize_irq(tp->napi[i].irq_vec); } static inline int tg3_irq_sync(struct tg3 *tp) @@ -4947,9 +4950,11 @@ static int tg3_restart_hw(struct tg3 *tp, int reset_phy) #ifdef CONFIG_NET_POLL_CONTROLLER static void tg3_poll_controller(struct net_device *dev) { + int i; struct tg3 *tp = netdev_priv(dev); - tg3_interrupt(tp->pdev->irq, dev); + for (i = 0; i < tp->irq_cnt; i++) + tg3_interrupt(tp->napi[i].irq_vec, dev); } #endif @@ -6244,7 +6249,7 @@ static int tg3_chip_reset(struct tg3 *tp) { u32 val; void (*write_op)(struct tg3 *, u32, u32); - int err; + int i, err; tg3_nvram_lock(tp); @@ -6291,7 +6296,9 @@ static int tg3_chip_reset(struct tg3 *tp) tp->napi[0].last_tag = 0; tp->napi[0].last_irq_tag = 0; smp_mb(); - synchronize_irq(tp->pdev->irq); + + for (i = 0; i < tp->irq_cnt; i++) + synchronize_irq(tp->napi[i].irq_vec); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) { val = tr32(TG3_PCIE_LNKCTL) & ~TG3_PCIE_LNKCTL_L1_PLL_PD_EN; @@ -7745,11 +7752,20 @@ restart_timer: add_timer(&tp->timer); } -static int tg3_request_irq(struct tg3 *tp) +static int tg3_request_irq(struct tg3 *tp, int irq_num) { irq_handler_t fn; unsigned long flags; - char *name = tp->dev->name; + char *name; + struct tg3_napi *tnapi = &tp->napi[irq_num]; + + if (tp->irq_cnt == 1) + name = tp->dev->name; + else { + name = &tnapi->irq_lbl[0]; + snprintf(name, IFNAMSIZ, "%s-%d", tp->dev->name, irq_num); + name[IFNAMSIZ-1] = 0; + } if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { fn = tg3_msi; @@ -7762,7 +7778,8 @@ static int tg3_request_irq(struct tg3 *tp) fn = tg3_interrupt_tagged; flags = IRQF_SHARED | IRQF_SAMPLE_RANDOM; } - return request_irq(tp->pdev->irq, fn, flags, name, &tp->napi[0]); + + return request_irq(tnapi->irq_vec, fn, flags, name, tnapi); } static int tg3_test_interrupt(struct tg3 *tp) @@ -7776,9 +7793,9 @@ static int tg3_test_interrupt(struct tg3 *tp) tg3_disable_ints(tp); - free_irq(tp->pdev->irq, tnapi); + free_irq(tnapi->irq_vec, tnapi); - err = request_irq(tp->pdev->irq, tg3_test_isr, + err = request_irq(tnapi->irq_vec, tg3_test_isr, IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, tnapi); if (err) return err; @@ -7806,9 +7823,9 @@ static int tg3_test_interrupt(struct tg3 *tp) tg3_disable_ints(tp); - free_irq(tp->pdev->irq, tnapi); + free_irq(tnapi->irq_vec, tnapi); - err = tg3_request_irq(tp); + err = tg3_request_irq(tp, 0); if (err) return err; @@ -7854,13 +7871,13 @@ static int tg3_test_msi(struct tg3 *tp) "the PCI maintainer and include system chipset information.\n", tp->dev->name); - free_irq(tp->pdev->irq, &tp->napi[0]); + free_irq(tp->napi[0].irq_vec, &tp->napi[0]); pci_disable_msi(tp->pdev); tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; - err = tg3_request_irq(tp); + err = tg3_request_irq(tp, 0); if (err) return err; @@ -7875,7 +7892,7 @@ static int tg3_test_msi(struct tg3 *tp) tg3_full_unlock(tp); if (err) - free_irq(tp->pdev->irq, &tp->napi[0]); + free_irq(tp->napi[0].irq_vec, &tp->napi[0]); return err; } @@ -7928,6 +7945,9 @@ static void tg3_ints_init(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_USING_MSI; } } + + tp->irq_cnt = 1; + tp->napi[0].irq_vec = tp->pdev->irq; } static void tg3_ints_fini(struct tg3 *tp) @@ -7941,7 +7961,7 @@ static void tg3_ints_fini(struct tg3 *tp) static int tg3_open(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); - int err; + int i, err; if (tp->fw_needed) { err = tg3_request_firmware(tp); @@ -7983,7 +8003,15 @@ static int tg3_open(struct net_device *dev) napi_enable(&tp->napi[0].napi); - err = tg3_request_irq(tp); + for (i = 0; i < tp->irq_cnt; i++) { + struct tg3_napi *tnapi = &tp->napi[i]; + err = tg3_request_irq(tp, i); + if (err) { + for (i--; i >= 0; i--) + free_irq(tnapi->irq_vec, tnapi); + break; + } + } if (err) goto err_out1; @@ -8054,7 +8082,10 @@ static int tg3_open(struct net_device *dev) return 0; err_out2: - free_irq(tp->pdev->irq, &tp->napi[0]); + for (i = tp->irq_cnt - 1; i >= 0; i--) { + struct tg3_napi *tnapi = &tp->napi[i]; + free_irq(tnapi->irq_vec, tnapi); + } err_out1: napi_disable(&tp->napi[0].napi); @@ -8298,6 +8329,7 @@ static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *); static int tg3_close(struct net_device *dev) { + int i; struct tg3 *tp = netdev_priv(dev); napi_disable(&tp->napi[0].napi); @@ -8320,7 +8352,10 @@ static int tg3_close(struct net_device *dev) tg3_full_unlock(tp); - free_irq(tp->pdev->irq, &tp->napi[0]); + for (i = tp->irq_cnt - 1; i >= 0; i--) { + struct tg3_napi *tnapi = &tp->napi[i]; + free_irq(tnapi->irq_vec, tnapi); + } tg3_ints_fini(tp); @@ -12151,6 +12186,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } } + tp->irq_max = 1; + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags |= TG3_FLAG_JUMBO_CAPABLE; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 626b96805c3..a78a0db15a7 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2514,6 +2514,9 @@ struct tg3_napi { dma_addr_t status_mapping; dma_addr_t rx_rcb_mapping; dma_addr_t tx_desc_mapping; + + char irq_lbl[IFNAMSIZ]; + unsigned int irq_vec; }; struct tg3 { @@ -2829,6 +2832,9 @@ struct tg3 { #define SST_25VF0X0_PAGE_SIZE 4098 + unsigned int irq_max; + unsigned int irq_cnt; + struct ethtool_coalesce coal; /* firmware info */ -- cgit v1.2.3-18-g5258 From 679563f47cd2547a0e091b5bd3ddf30027af6b08 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 12:55:46 +0000 Subject: tg3: Add MSI-X support This patch adds MSI-X support. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 108 ++++++++++++++++++++++++++++++++++++++++-------------- drivers/net/tg3.h | 6 +++ 2 files changed, 87 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7717eae1221..12ead83bd06 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -160,6 +160,7 @@ MODULE_FIRMWARE(FIRMWARE_TG3); MODULE_FIRMWARE(FIRMWARE_TG3TSO); MODULE_FIRMWARE(FIRMWARE_TG3TSO5); +#define TG3_RSS_MIN_NUM_MSIX_VECS 2 static int tg3_debug = -1; /* -1 == use TG3_DEF_MSG_ENABLE as value */ module_param(tg3_debug, int, 0); @@ -7767,7 +7768,7 @@ static int tg3_request_irq(struct tg3 *tp, int irq_num) name[IFNAMSIZ-1] = 0; } - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { + if (tp->tg3_flags2 & TG3_FLG2_USING_MSI_OR_MSIX) { fn = tg3_msi; if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) fn = tg3_msi_1shot; @@ -7928,34 +7929,81 @@ static int tg3_request_firmware(struct tg3 *tp) return 0; } +static bool tg3_enable_msix(struct tg3 *tp) +{ + int i, rc, cpus = num_online_cpus(); + struct msix_entry msix_ent[tp->irq_max]; + + if (cpus == 1) + /* Just fallback to the simpler MSI mode. */ + return false; + + /* + * We want as many rx rings enabled as there are cpus. + * The first MSIX vector only deals with link interrupts, etc, + * so we add one to the number of vectors we are requesting. + */ + tp->irq_cnt = min_t(unsigned, cpus + 1, tp->irq_max); + + for (i = 0; i < tp->irq_max; i++) { + msix_ent[i].entry = i; + msix_ent[i].vector = 0; + } + + rc = pci_enable_msix(tp->pdev, msix_ent, tp->irq_cnt); + if (rc != 0) { + if (rc < TG3_RSS_MIN_NUM_MSIX_VECS) + return false; + if (pci_enable_msix(tp->pdev, msix_ent, rc)) + return false; + printk(KERN_NOTICE + "%s: Requested %d MSI-X vectors, received %d\n", + tp->dev->name, tp->irq_cnt, rc); + tp->irq_cnt = rc; + } + + for (i = 0; i < tp->irq_max; i++) + tp->napi[i].irq_vec = msix_ent[i].vector; + + return true; +} + static void tg3_ints_init(struct tg3 *tp) { - if (tp->tg3_flags & TG3_FLAG_SUPPORT_MSI) { + if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSI_OR_MSIX) && + !(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { /* All MSI supporting chips should support tagged * status. Assert that this is the case. */ - if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { - printk(KERN_WARNING PFX "%s: MSI without TAGGED? " - "Not using MSI.\n", tp->dev->name); - } else if (pci_enable_msi(tp->pdev) == 0) { - u32 msi_mode; - - msi_mode = tr32(MSGINT_MODE); - tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE); - tp->tg3_flags2 |= TG3_FLG2_USING_MSI; - } + printk(KERN_WARNING PFX "%s: MSI without TAGGED? " + "Not using MSI.\n", tp->dev->name); + goto defcfg; } - tp->irq_cnt = 1; - tp->napi[0].irq_vec = tp->pdev->irq; + if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX) && tg3_enable_msix(tp)) + tp->tg3_flags2 |= TG3_FLG2_USING_MSIX; + else if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSI) && + pci_enable_msi(tp->pdev) == 0) + tp->tg3_flags2 |= TG3_FLG2_USING_MSI; + + if (tp->tg3_flags2 & TG3_FLG2_USING_MSI_OR_MSIX) { + u32 msi_mode = tr32(MSGINT_MODE); + tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE); + } +defcfg: + if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSIX)) { + tp->irq_cnt = 1; + tp->napi[0].irq_vec = tp->pdev->irq; + } } static void tg3_ints_fini(struct tg3 *tp) { - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { - pci_disable_msi(tp->pdev); - tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; - } + if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) + pci_disable_msix(tp->pdev); + else if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) + pci_disable_msi(tp->pdev); + tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI_OR_MSIX; } static int tg3_open(struct net_device *dev) @@ -7992,14 +8040,18 @@ static int tg3_open(struct net_device *dev) tg3_full_unlock(tp); + /* + * Setup interrupts first so we know how + * many NAPI resources to allocate + */ + tg3_ints_init(tp); + /* The placement of this call is tied * to the setup and use of Host TX descriptors. */ err = tg3_alloc_consistent(tp); if (err) - return err; - - tg3_ints_init(tp); + goto err_out1; napi_enable(&tp->napi[0].napi); @@ -8014,7 +8066,7 @@ static int tg3_open(struct net_device *dev) } if (err) - goto err_out1; + goto err_out2; tg3_full_lock(tp, 0); @@ -8043,7 +8095,7 @@ static int tg3_open(struct net_device *dev) tg3_full_unlock(tp); if (err) - goto err_out2; + goto err_out3; if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { err = tg3_test_msi(tp); @@ -8054,7 +8106,7 @@ static int tg3_open(struct net_device *dev) tg3_free_rings(tp); tg3_full_unlock(tp); - goto err_out1; + goto err_out2; } if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { @@ -8081,16 +8133,18 @@ static int tg3_open(struct net_device *dev) return 0; -err_out2: +err_out3: for (i = tp->irq_cnt - 1; i >= 0; i--) { struct tg3_napi *tnapi = &tp->napi[i]; free_irq(tnapi->irq_vec, tnapi); } -err_out1: +err_out2: napi_disable(&tp->napi[0].napi); - tg3_ints_fini(tp); tg3_free_consistent(tp); + +err_out1: + tg3_ints_fini(tp); return err; } diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index a78a0db15a7..65bbd773606 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2621,6 +2621,9 @@ struct tg3 { #define TG3_FLAG_NVRAM 0x00002000 #define TG3_FLAG_NVRAM_BUFFERED 0x00004000 #define TG3_FLAG_SUPPORT_MSI 0x00008000 +#define TG3_FLAG_SUPPORT_MSIX 0x00010000 +#define TG3_FLAG_SUPPORT_MSI_OR_MSIX (TG3_FLAG_SUPPORT_MSI | \ + TG3_FLAG_SUPPORT_MSIX) #define TG3_FLAG_PCIX_MODE 0x00020000 #define TG3_FLAG_PCI_HIGH_SPEED 0x00040000 #define TG3_FLAG_PCI_32BIT 0x00080000 @@ -2659,6 +2662,9 @@ struct tg3 { #define TG3_FLG2_5750_PLUS 0x00080000 #define TG3_FLG2_PROTECTED_NVRAM 0x00100000 #define TG3_FLG2_USING_MSI 0x00200000 +#define TG3_FLG2_USING_MSIX 0x00400000 +#define TG3_FLG2_USING_MSI_OR_MSIX (TG3_FLG2_USING_MSI | \ + TG3_FLG2_USING_MSIX) #define TG3_FLG2_MII_SERDES 0x00800000 #define TG3_FLG2_ANY_SERDES (TG3_FLG2_PHY_SERDES | \ TG3_FLG2_MII_SERDES) -- cgit v1.2.3-18-g5258 From 646c9eddcffd202bb0f3d906cecf94eaf10cad31 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 12:58:41 +0000 Subject: tg3: Add mailbox assignments The 5717 assigns mailbox locations to interrupt vectors in a rather non-intuitive way. (Much of the complexity stems from legacy compatibility issues.) This patch implements the assignment scheme. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 12ead83bd06..4d16ce05dba 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -9219,7 +9219,7 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam * static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) { struct tg3 *tp = netdev_priv(dev); - int irq_sync = 0, err = 0; + int i, irq_sync = 0, err = 0; if ((ering->rx_pending > TG3_RX_RING_SIZE - 1) || (ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) || @@ -9243,7 +9243,9 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e tp->rx_pending > 63) tp->rx_pending = 63; tp->rx_jumbo_pending = ering->rx_jumbo_pending; - tp->napi[0].tx_pending = ering->tx_pending; + + for (i = 0; i < TG3_IRQ_MAX_VECS; i++) + tp->napi[i].tx_pending = ering->tx_pending; if (netif_running(dev)) { tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); @@ -13443,7 +13445,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, static int tg3_version_printed = 0; struct net_device *dev; struct tg3 *tp; - int err, pm_cap; + int i, err, pm_cap; + u32 sndmbx, rcvmbx, intmbx; char str[40]; u64 dma_mask, persist_dma_mask; @@ -13538,12 +13541,50 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tp->rx_pending = TG3_DEF_RX_RING_PENDING; tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING; - tp->napi[0].tp = tp; - tp->napi[0].int_mbox = MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW; - tp->napi[0].consmbox = MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW; - tp->napi[0].prodmbox = MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW; - tp->napi[0].coal_now = HOSTCC_MODE_NOW; - tp->napi[0].tx_pending = TG3_DEF_TX_RING_PENDING; + intmbx = MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW; + rcvmbx = MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW; + sndmbx = MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW; + for (i = 0; i < TG3_IRQ_MAX_VECS; i++) { + struct tg3_napi *tnapi = &tp->napi[i]; + + tnapi->tp = tp; + tnapi->tx_pending = TG3_DEF_TX_RING_PENDING; + + tnapi->int_mbox = intmbx; + if (i < 4) + intmbx += 0x8; + else + intmbx += 0x4; + + tnapi->consmbox = rcvmbx; + tnapi->prodmbox = sndmbx; + + if (i) + tnapi->coal_now = HOSTCC_MODE_COAL_VEC1_NOW << (i - 1); + else + tnapi->coal_now = HOSTCC_MODE_NOW; + + if (!(tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX)) + break; + + /* + * If we support MSIX, we'll be using RSS. If we're using + * RSS, the first vector only handles link interrupts and the + * remaining vectors handle rx and tx interrupts. Reuse the + * mailbox values for the next iteration. The values we setup + * above are still useful for the single vectored mode. + */ + if (!i) + continue; + + rcvmbx += 0x8; + + if (sndmbx & 0x4) + sndmbx -= 0x4; + else + sndmbx += 0xc; + } + netif_napi_add(dev, &tp->napi[0].napi, tg3_poll, 64); dev->ethtool_ops = &tg3_ethtool_ops; dev->watchdog_timeo = TG3_TX_TIMEOUT; -- cgit v1.2.3-18-g5258 From f77a6a8e6cee17b21a43bdf6b853cc2fc0e2c4df Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:04:37 +0000 Subject: tg3: Add tx and rx ring resource tracking This patch adds code to assign status block, tx producer ring and rx return ring resources needed for the other interrupt vectors. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 242 +++++++++++++++++++++++++++++++++++------------------- drivers/net/tg3.h | 3 +- 2 files changed, 160 insertions(+), 85 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 4d16ce05dba..58a8986f3e0 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5722,28 +5722,31 @@ err_out: */ static void tg3_free_rings(struct tg3 *tp) { - struct tg3_napi *tnapi = &tp->napi[0]; - int i; + int i, j; - for (i = 0; i < TG3_TX_RING_SIZE; ) { - struct tx_ring_info *txp; - struct sk_buff *skb; + for (j = 0; j < tp->irq_cnt; j++) { + struct tg3_napi *tnapi = &tp->napi[j]; - txp = &tnapi->tx_buffers[i]; - skb = txp->skb; + for (i = 0; i < TG3_TX_RING_SIZE; ) { + struct tx_ring_info *txp; + struct sk_buff *skb; - if (skb == NULL) { - i++; - continue; - } + txp = &tnapi->tx_buffers[i]; + skb = txp->skb; - skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE); + if (skb == NULL) { + i++; + continue; + } - txp->skb = NULL; + skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE); - i += skb_shinfo(skb)->nr_frags + 1; + txp->skb = NULL; - dev_kfree_skb_any(skb); + i += skb_shinfo(skb)->nr_frags + 1; + + dev_kfree_skb_any(skb); + } } tg3_rx_prodring_free(tp, &tp->prodring[0]); @@ -5758,16 +5761,27 @@ static void tg3_free_rings(struct tg3 *tp) */ static int tg3_init_rings(struct tg3 *tp) { - struct tg3_napi *tnapi = &tp->napi[0]; + int i; /* Free up all the SKBs. */ tg3_free_rings(tp); - /* Zero out all descriptors. */ - memset(tnapi->tx_ring, 0, TG3_TX_RING_BYTES); + for (i = 0; i < tp->irq_cnt; i++) { + struct tg3_napi *tnapi = &tp->napi[i]; - tnapi->rx_rcb_ptr = 0; - memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); + tnapi->last_tag = 0; + tnapi->last_irq_tag = 0; + tnapi->hw_status->status = 0; + tnapi->hw_status->status_tag = 0; + memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); + + tnapi->tx_prod = 0; + tnapi->tx_cons = 0; + memset(tnapi->tx_ring, 0, TG3_TX_RING_BYTES); + + tnapi->rx_rcb_ptr = 0; + memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); + } return tg3_rx_prodring_alloc(tp, &tp->prodring[0]); } @@ -5778,31 +5792,41 @@ static int tg3_init_rings(struct tg3 *tp) */ static void tg3_free_consistent(struct tg3 *tp) { - struct tg3_napi *tnapi = &tp->napi[0]; + int i; - kfree(tnapi->tx_buffers); - tnapi->tx_buffers = NULL; - if (tnapi->tx_ring) { - pci_free_consistent(tp->pdev, TG3_TX_RING_BYTES, - tnapi->tx_ring, tnapi->tx_desc_mapping); - tnapi->tx_ring = NULL; - } - if (tnapi->rx_rcb) { - pci_free_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp), - tnapi->rx_rcb, tnapi->rx_rcb_mapping); - tnapi->rx_rcb = NULL; - } - if (tnapi->hw_status) { - pci_free_consistent(tp->pdev, TG3_HW_STATUS_SIZE, - tnapi->hw_status, - tnapi->status_mapping); - tnapi->hw_status = NULL; + for (i = 0; i < tp->irq_cnt; i++) { + struct tg3_napi *tnapi = &tp->napi[i]; + + if (tnapi->tx_ring) { + pci_free_consistent(tp->pdev, TG3_TX_RING_BYTES, + tnapi->tx_ring, tnapi->tx_desc_mapping); + tnapi->tx_ring = NULL; + } + + kfree(tnapi->tx_buffers); + tnapi->tx_buffers = NULL; + + if (tnapi->rx_rcb) { + pci_free_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp), + tnapi->rx_rcb, + tnapi->rx_rcb_mapping); + tnapi->rx_rcb = NULL; + } + + if (tnapi->hw_status) { + pci_free_consistent(tp->pdev, TG3_HW_STATUS_SIZE, + tnapi->hw_status, + tnapi->status_mapping); + tnapi->hw_status = NULL; + } } + if (tp->hw_stats) { pci_free_consistent(tp->pdev, sizeof(struct tg3_hw_stats), tp->hw_stats, tp->stats_mapping); tp->hw_stats = NULL; } + tg3_rx_prodring_fini(tp, &tp->prodring[0]); } @@ -5812,44 +5836,49 @@ static void tg3_free_consistent(struct tg3 *tp) */ static int tg3_alloc_consistent(struct tg3 *tp) { - struct tg3_napi *tnapi = &tp->napi[0]; + int i; if (tg3_rx_prodring_init(tp, &tp->prodring[0])) return -ENOMEM; - tnapi->tx_buffers = kzalloc(sizeof(struct tx_ring_info) * - TG3_TX_RING_SIZE, GFP_KERNEL); - if (!tnapi->tx_buffers) + tp->hw_stats = pci_alloc_consistent(tp->pdev, + sizeof(struct tg3_hw_stats), + &tp->stats_mapping); + if (!tp->hw_stats) goto err_out; - tnapi->tx_ring = pci_alloc_consistent(tp->pdev, TG3_TX_RING_BYTES, - &tnapi->tx_desc_mapping); - if (!tnapi->tx_ring) - goto err_out; + memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats)); - tnapi->hw_status = pci_alloc_consistent(tp->pdev, - TG3_HW_STATUS_SIZE, - &tnapi->status_mapping); - if (!tnapi->hw_status) - goto err_out; + for (i = 0; i < tp->irq_cnt; i++) { + struct tg3_napi *tnapi = &tp->napi[i]; - memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); + tnapi->hw_status = pci_alloc_consistent(tp->pdev, + TG3_HW_STATUS_SIZE, + &tnapi->status_mapping); + if (!tnapi->hw_status) + goto err_out; - tnapi->rx_rcb = pci_alloc_consistent(tp->pdev, - TG3_RX_RCB_RING_BYTES(tp), - &tnapi->rx_rcb_mapping); - if (!tnapi->rx_rcb) - goto err_out; + memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); - memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); + tnapi->rx_rcb = pci_alloc_consistent(tp->pdev, + TG3_RX_RCB_RING_BYTES(tp), + &tnapi->rx_rcb_mapping); + if (!tnapi->rx_rcb) + goto err_out; - tp->hw_stats = pci_alloc_consistent(tp->pdev, - sizeof(struct tg3_hw_stats), - &tp->stats_mapping); - if (!tp->hw_stats) - goto err_out; + memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); - memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats)); + tnapi->tx_buffers = kzalloc(sizeof(struct tx_ring_info) * + TG3_TX_RING_SIZE, GFP_KERNEL); + if (!tnapi->tx_buffers) + goto err_out; + + tnapi->tx_ring = pci_alloc_consistent(tp->pdev, + TG3_TX_RING_BYTES, + &tnapi->tx_desc_mapping); + if (!tnapi->tx_ring) + goto err_out; + } return 0; @@ -5910,7 +5939,6 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, int static int tg3_abort_hw(struct tg3 *tp, int silent) { int i, err; - struct tg3_napi *tnapi = &tp->napi[0]; tg3_disable_ints(tp); @@ -5962,8 +5990,11 @@ static int tg3_abort_hw(struct tg3 *tp, int silent) err |= tg3_stop_block(tp, BUFMGR_MODE, BUFMGR_MODE_ENABLE, silent); err |= tg3_stop_block(tp, MEMARB_MODE, MEMARB_MODE_ENABLE, silent); - if (tnapi->hw_status) - memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); + for (i = 0; i < tp->irq_cnt; i++) { + struct tg3_napi *tnapi = &tp->napi[i]; + if (tnapi->hw_status) + memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); + } if (tp->hw_stats) memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats)); @@ -6290,12 +6321,15 @@ static int tg3_chip_reset(struct tg3 *tp) * sharing or irqpoll. */ tp->tg3_flags |= TG3_FLAG_CHIP_RESETTING; - if (tp->napi[0].hw_status) { - tp->napi[0].hw_status->status = 0; - tp->napi[0].hw_status->status_tag = 0; + for (i = 0; i < tp->irq_cnt; i++) { + struct tg3_napi *tnapi = &tp->napi[i]; + if (tnapi->hw_status) { + tnapi->hw_status->status = 0; + tnapi->hw_status->status_tag = 0; + } + tnapi->last_tag = 0; + tnapi->last_irq_tag = 0; } - tp->napi[0].last_tag = 0; - tp->napi[0].last_irq_tag = 0; smp_mb(); for (i = 0; i < tp->irq_cnt; i++) @@ -6829,7 +6863,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) static void tg3_rings_reset(struct tg3 *tp) { int i; - u32 txrcb, rxrcb, limit; + u32 stblk, txrcb, rxrcb, limit; struct tg3_napi *tnapi = &tp->napi[0]; /* Disable all transmit rings but the first. */ @@ -6861,10 +6895,20 @@ static void tg3_rings_reset(struct tg3 *tp) tw32_mailbox_f(tp->napi[0].int_mbox, 1); /* Zero mailbox registers. */ - tp->napi[0].tx_prod = 0; - tp->napi[0].tx_cons = 0; - tw32_mailbox(tp->napi[0].prodmbox, 0); - tw32_rx_mbox(tp->napi[0].consmbox, 0); + if (tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX) { + for (i = 1; i < TG3_IRQ_MAX_VECS; i++) { + tp->napi[i].tx_prod = 0; + tp->napi[i].tx_cons = 0; + tw32_mailbox(tp->napi[i].prodmbox, 0); + tw32_rx_mbox(tp->napi[i].consmbox, 0); + tw32_mailbox_f(tp->napi[i].int_mbox, 1); + } + } else { + tp->napi[0].tx_prod = 0; + tp->napi[0].tx_cons = 0; + tw32_mailbox(tp->napi[0].prodmbox, 0); + tw32_rx_mbox(tp->napi[0].consmbox, 0); + } /* Make sure the NIC-based send BD rings are disabled. */ if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { @@ -6885,14 +6929,44 @@ static void tg3_rings_reset(struct tg3 *tp) tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW, ((u64) tnapi->status_mapping & 0xffffffff)); - tg3_set_bdinfo(tp, txrcb, tnapi->tx_desc_mapping, - (TG3_TX_RING_SIZE << - BDINFO_FLAGS_MAXLEN_SHIFT), - NIC_SRAM_TX_BUFFER_DESC); + if (tnapi->tx_ring) { + tg3_set_bdinfo(tp, txrcb, tnapi->tx_desc_mapping, + (TG3_TX_RING_SIZE << + BDINFO_FLAGS_MAXLEN_SHIFT), + NIC_SRAM_TX_BUFFER_DESC); + txrcb += TG3_BDINFO_SIZE; + } - tg3_set_bdinfo(tp, rxrcb, tnapi->rx_rcb_mapping, - (TG3_RX_RCB_RING_SIZE(tp) << - BDINFO_FLAGS_MAXLEN_SHIFT), 0); + if (tnapi->rx_rcb) { + tg3_set_bdinfo(tp, rxrcb, tnapi->rx_rcb_mapping, + (TG3_RX_RCB_RING_SIZE(tp) << + BDINFO_FLAGS_MAXLEN_SHIFT), 0); + rxrcb += TG3_BDINFO_SIZE; + } + + stblk = HOSTCC_STATBLCK_RING1; + + for (i = 1, tnapi++; i < tp->irq_cnt; i++, tnapi++) { + u64 mapping = (u64)tnapi->status_mapping; + tw32(stblk + TG3_64BIT_REG_HIGH, mapping >> 32); + tw32(stblk + TG3_64BIT_REG_LOW, mapping & 0xffffffff); + + /* Clear status block in ram. */ + memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); + + tg3_set_bdinfo(tp, txrcb, tnapi->tx_desc_mapping, + (TG3_TX_RING_SIZE << + BDINFO_FLAGS_MAXLEN_SHIFT), + NIC_SRAM_TX_BUFFER_DESC); + + tg3_set_bdinfo(tp, rxrcb, tnapi->rx_rcb_mapping, + (TG3_RX_RCB_RING_SIZE(tp) << + BDINFO_FLAGS_MAXLEN_SHIFT), 0); + + stblk += 8; + txrcb += TG3_BDINFO_SIZE; + rxrcb += TG3_BDINFO_SIZE; + } } /* tp->lock is held. */ diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 65bbd773606..6452d48201e 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1117,7 +1117,8 @@ #define HOSTCC_SND_CON_IDX_13 0x00003cf4 #define HOSTCC_SND_CON_IDX_14 0x00003cf8 #define HOSTCC_SND_CON_IDX_15 0x00003cfc -/* 0x3d00 --> 0x4000 unused */ +#define HOSTCC_STATBLCK_RING1 0x00003d00 +/* 0x3d04 --> 0x4000 unused */ /* Memory arbiter control registers */ #define MEMARB_MODE 0x00004000 -- cgit v1.2.3-18-g5258 From 89aeb3bceaa1a02651206a76a7b9dcb8f3884702 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:08:58 +0000 Subject: tg3: Update intmbox and coal_now for msix This patch fixes up two spots that need attention now that msix support has been added. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 58a8986f3e0..53896541f7d 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -614,25 +614,33 @@ static void tg3_ape_unlock(struct tg3 *tp, int locknum) static void tg3_disable_ints(struct tg3 *tp) { + int i; + tw32(TG3PCI_MISC_HOST_CTRL, (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT)); - tw32_mailbox_f(tp->napi[0].int_mbox, 0x00000001); + for (i = 0; i < tp->irq_max; i++) + tw32_mailbox_f(tp->napi[i].int_mbox, 0x00000001); } static void tg3_enable_ints(struct tg3 *tp) { - u32 coal_now; - struct tg3_napi *tnapi = &tp->napi[0]; + int i; + u32 coal_now = 0; + tp->irq_sync = 0; wmb(); tw32(TG3PCI_MISC_HOST_CTRL, (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT)); - tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); - if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) + + for (i = 0; i < tp->irq_cnt; i++) { + struct tg3_napi *tnapi = &tp->napi[i]; tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); + if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) + tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); - coal_now = tnapi->coal_now; + coal_now |= tnapi->coal_now; + } /* Force an initial interrupt */ if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && -- cgit v1.2.3-18-g5258 From fe5f5787f0866e9f883bdd90018a354f2f3defd1 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:09:39 +0000 Subject: tg3: Add TSS support This patch exposes the additional transmit rings to the kernel and makes the necessary modifications to transmit, open, and close paths. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 54 ++++++++++++++++++++++++++++++++++++------------------ drivers/net/tg3.h | 1 + 2 files changed, 37 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 53896541f7d..2e0f4a50633 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -704,11 +704,13 @@ static inline void tg3_netif_stop(struct tg3 *tp) static inline void tg3_netif_start(struct tg3 *tp) { struct tg3_napi *tnapi = &tp->napi[0]; - netif_wake_queue(tp->dev); - /* NOTE: unconditional netif_wake_queue is only appropriate - * so long as all callers are assured to have free tx slots - * (such as after tg3_init_hw) + + /* NOTE: unconditional netif_tx_wake_all_queues is only + * appropriate so long as all callers are assured to + * have free tx slots (such as after tg3_init_hw) */ + netif_tx_wake_all_queues(tp->dev); + napi_enable(&tnapi->napi); tnapi->hw_status->status |= SD_STATUS_UPDATED; tg3_enable_ints(tp); @@ -4294,6 +4296,13 @@ static void tg3_tx(struct tg3_napi *tnapi) struct tg3 *tp = tnapi->tp; u32 hw_idx = tnapi->hw_status->idx[0].tx_consumer; u32 sw_idx = tnapi->tx_cons; + struct netdev_queue *txq; + int index = tnapi - tp->napi; + + if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) + index--; + + txq = netdev_get_tx_queue(tp->dev, index); while (sw_idx != hw_idx) { struct tx_ring_info *ri = &tnapi->tx_buffers[sw_idx]; @@ -4335,13 +4344,13 @@ static void tg3_tx(struct tg3_napi *tnapi) */ smp_mb(); - if (unlikely(netif_queue_stopped(tp->dev) && + if (unlikely(netif_tx_queue_stopped(txq) && (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi)))) { - netif_tx_lock(tp->dev); - if (netif_queue_stopped(tp->dev) && + __netif_tx_lock(txq, smp_processor_id()); + if (netif_tx_queue_stopped(txq) && (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi))) - netif_wake_queue(tp->dev); - netif_tx_unlock(tp->dev); + netif_tx_wake_queue(txq); + __netif_tx_unlock(txq); } } @@ -5156,9 +5165,13 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, u32 len, entry, base_flags, mss; struct skb_shared_info *sp; dma_addr_t mapping; - struct tg3_napi *tnapi = &tp->napi[0]; + struct tg3_napi *tnapi; + struct netdev_queue *txq; - len = skb_headlen(skb); + txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); + tnapi = &tp->napi[skb_get_queue_mapping(skb)]; + if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) + tnapi++; /* We are running in BH disabled context with netif_tx_lock * and TX reclaim runs via tp->napi.poll inside of a software @@ -5166,8 +5179,8 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, * no IRQ context deadlocks to worry about either. Rejoice! */ if (unlikely(tg3_tx_avail(tnapi) <= (skb_shinfo(skb)->nr_frags + 1))) { - if (!netif_queue_stopped(dev)) { - netif_stop_queue(dev); + if (!netif_tx_queue_stopped(txq)) { + netif_tx_stop_queue(txq); /* This is a hard error, log it. */ printk(KERN_ERR PFX "%s: BUG! Tx Ring full when " @@ -5226,6 +5239,8 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, tnapi->tx_buffers[entry].skb = skb; + len = skb_headlen(skb); + tg3_set_txd(tnapi, entry, mapping, len, base_flags, (skb_shinfo(skb)->nr_frags == 0) | (mss << 1)); @@ -5255,9 +5270,9 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, tnapi->tx_prod = entry; if (unlikely(tg3_tx_avail(tnapi) <= (MAX_SKB_FRAGS + 1))) { - netif_stop_queue(dev); + netif_tx_stop_queue(txq); if (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi)) - netif_wake_queue(tp->dev); + netif_tx_wake_queue(txq); } out_unlock: @@ -8047,6 +8062,8 @@ static bool tg3_enable_msix(struct tg3 *tp) for (i = 0; i < tp->irq_max; i++) tp->napi[i].irq_vec = msix_ent[i].vector; + tp->dev->real_num_tx_queues = tp->irq_cnt - 1; + return true; } @@ -8076,6 +8093,7 @@ defcfg: if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSIX)) { tp->irq_cnt = 1; tp->napi[0].irq_vec = tp->pdev->irq; + tp->dev->real_num_tx_queues = 1; } } @@ -8211,7 +8229,7 @@ static int tg3_open(struct net_device *dev) tg3_full_unlock(tp); - netif_start_queue(dev); + netif_tx_start_all_queues(dev); return 0; @@ -8471,7 +8489,7 @@ static int tg3_close(struct net_device *dev) napi_disable(&tp->napi[0].napi); cancel_work_sync(&tp->reset_task); - netif_stop_queue(dev); + netif_tx_stop_all_queues(dev); del_timer_sync(&tp->timer); @@ -13560,7 +13578,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, goto err_out_free_res; } - dev = alloc_etherdev(sizeof(*tp)); + dev = alloc_etherdev_mq(sizeof(*tp), TG3_IRQ_MAX_VECS); if (!dev) { printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n"); err = -ENOMEM; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 6452d48201e..d1c7addd1d2 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -822,6 +822,7 @@ #define SNDBDI_MODE_RESET 0x00000001 #define SNDBDI_MODE_ENABLE 0x00000002 #define SNDBDI_MODE_ATTN_ENABLE 0x00000004 +#define SNDBDI_MODE_MULTI_TXQ_EN 0x00000020 #define SNDBDI_STATUS 0x00001804 #define SNDBDI_STATUS_ERROR_ATTN 0x00000004 #define SNDBDI_IN_PROD_IDX_0 0x00001808 -- cgit v1.2.3-18-g5258 From fed9781081aa9600765346c108ff22751e003715 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:10:19 +0000 Subject: tg3: Enable NAPI instances for other int vectors This patch adds code to enable and disable the rest of the NAPI instances. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 2e0f4a50633..a4e46e4de92 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -694,25 +694,39 @@ static void tg3_int_reenable(struct tg3_napi *tnapi) HOSTCC_MODE_ENABLE | tnapi->coal_now); } +static void tg3_napi_disable(struct tg3 *tp) +{ + int i; + + for (i = tp->irq_cnt - 1; i >= 0; i--) + napi_disable(&tp->napi[i].napi); +} + +static void tg3_napi_enable(struct tg3 *tp) +{ + int i; + + for (i = 0; i < tp->irq_cnt; i++) + napi_enable(&tp->napi[i].napi); +} + static inline void tg3_netif_stop(struct tg3 *tp) { tp->dev->trans_start = jiffies; /* prevent tx timeout */ - napi_disable(&tp->napi[0].napi); + tg3_napi_disable(tp); netif_tx_disable(tp->dev); } static inline void tg3_netif_start(struct tg3 *tp) { - struct tg3_napi *tnapi = &tp->napi[0]; - /* NOTE: unconditional netif_tx_wake_all_queues is only * appropriate so long as all callers are assured to * have free tx slots (such as after tg3_init_hw) */ netif_tx_wake_all_queues(tp->dev); - napi_enable(&tnapi->napi); - tnapi->hw_status->status |= SD_STATUS_UPDATED; + tg3_napi_enable(tp); + tp->napi[0].hw_status->status |= SD_STATUS_UPDATED; tg3_enable_ints(tp); } @@ -4958,7 +4972,7 @@ static int tg3_restart_hw(struct tg3 *tp, int reset_phy) tg3_full_unlock(tp); del_timer_sync(&tp->timer); tp->irq_sync = 0; - napi_enable(&tp->napi[0].napi); + tg3_napi_enable(tp); dev_close(tp->dev); tg3_full_lock(tp, 0); } @@ -8153,7 +8167,7 @@ static int tg3_open(struct net_device *dev) if (err) goto err_out1; - napi_enable(&tp->napi[0].napi); + tg3_napi_enable(tp); for (i = 0; i < tp->irq_cnt; i++) { struct tg3_napi *tnapi = &tp->napi[i]; @@ -8240,7 +8254,7 @@ err_out3: } err_out2: - napi_disable(&tp->napi[0].napi); + tg3_napi_disable(tp); tg3_free_consistent(tp); err_out1: @@ -8486,7 +8500,7 @@ static int tg3_close(struct net_device *dev) int i; struct tg3 *tp = netdev_priv(dev); - napi_disable(&tp->napi[0].napi); + tg3_napi_disable(tp); cancel_work_sync(&tp->reset_task); netif_tx_stop_all_queues(dev); -- cgit v1.2.3-18-g5258 From b6080e126012047d42e53154189fdca286d0600e Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:12:00 +0000 Subject: tg3: Add coalesce parameters for msix vectors This patch adds code to tune the coalescing parameters for the other msix vectors. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++--------- drivers/net/tg3.h | 10 +++++++++- 2 files changed, 57 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index a4e46e4de92..f51c29c6474 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6876,24 +6876,63 @@ static void tg3_set_bdinfo(struct tg3 *tp, u32 bdinfo_addr, static void __tg3_set_rx_mode(struct net_device *); static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) { - tw32(HOSTCC_RXCOL_TICKS, ec->rx_coalesce_usecs); - tw32(HOSTCC_TXCOL_TICKS, ec->tx_coalesce_usecs); - tw32(HOSTCC_RXMAX_FRAMES, ec->rx_max_coalesced_frames); - tw32(HOSTCC_TXMAX_FRAMES, ec->tx_max_coalesced_frames); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { - tw32(HOSTCC_RXCOAL_TICK_INT, ec->rx_coalesce_usecs_irq); - tw32(HOSTCC_TXCOAL_TICK_INT, ec->tx_coalesce_usecs_irq); + int i; + + if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSIX)) { + tw32(HOSTCC_TXCOL_TICKS, ec->tx_coalesce_usecs); + tw32(HOSTCC_TXMAX_FRAMES, ec->tx_max_coalesced_frames); + tw32(HOSTCC_TXCOAL_MAXF_INT, ec->tx_max_coalesced_frames_irq); + + tw32(HOSTCC_RXCOL_TICKS, ec->rx_coalesce_usecs); + tw32(HOSTCC_RXMAX_FRAMES, ec->rx_max_coalesced_frames); + tw32(HOSTCC_RXCOAL_MAXF_INT, ec->rx_max_coalesced_frames_irq); + } else { + tw32(HOSTCC_TXCOL_TICKS, 0); + tw32(HOSTCC_TXMAX_FRAMES, 0); + tw32(HOSTCC_TXCOAL_MAXF_INT, 0); + + tw32(HOSTCC_RXCOL_TICKS, 0); + tw32(HOSTCC_RXMAX_FRAMES, 0); + tw32(HOSTCC_RXCOAL_MAXF_INT, 0); } - tw32(HOSTCC_RXCOAL_MAXF_INT, ec->rx_max_coalesced_frames_irq); - tw32(HOSTCC_TXCOAL_MAXF_INT, ec->tx_max_coalesced_frames_irq); + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { u32 val = ec->stats_block_coalesce_usecs; + tw32(HOSTCC_RXCOAL_TICK_INT, ec->rx_coalesce_usecs_irq); + tw32(HOSTCC_TXCOAL_TICK_INT, ec->tx_coalesce_usecs_irq); + if (!netif_carrier_ok(tp->dev)) val = 0; tw32(HOSTCC_STAT_COAL_TICKS, val); } + + for (i = 0; i < tp->irq_cnt - 1; i++) { + u32 reg; + + reg = HOSTCC_RXCOL_TICKS_VEC1 + i * 0x18; + tw32(reg, ec->rx_coalesce_usecs); + reg = HOSTCC_TXCOL_TICKS_VEC1 + i * 0x18; + tw32(reg, ec->tx_coalesce_usecs); + reg = HOSTCC_RXMAX_FRAMES_VEC1 + i * 0x18; + tw32(reg, ec->rx_max_coalesced_frames); + reg = HOSTCC_TXMAX_FRAMES_VEC1 + i * 0x18; + tw32(reg, ec->tx_max_coalesced_frames); + reg = HOSTCC_RXCOAL_MAXF_INT_VEC1 + i * 0x18; + tw32(reg, ec->rx_max_coalesced_frames_irq); + reg = HOSTCC_TXCOAL_MAXF_INT_VEC1 + i * 0x18; + tw32(reg, ec->tx_max_coalesced_frames_irq); + } + + for (; i < tp->irq_max - 1; i++) { + tw32(HOSTCC_RXCOL_TICKS_VEC1 + i * 0x18, 0); + tw32(HOSTCC_TXCOL_TICKS_VEC1 + i * 0x18, 0); + tw32(HOSTCC_RXMAX_FRAMES_VEC1 + i * 0x18, 0); + tw32(HOSTCC_TXMAX_FRAMES_VEC1 + i * 0x18, 0); + tw32(HOSTCC_RXCOAL_MAXF_INT_VEC1 + i * 0x18, 0); + tw32(HOSTCC_TXCOAL_MAXF_INT_VEC1 + i * 0x18, 0); + } } /* tp->lock is held. */ diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index d1c7addd1d2..978b6d9546f 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1119,7 +1119,15 @@ #define HOSTCC_SND_CON_IDX_14 0x00003cf8 #define HOSTCC_SND_CON_IDX_15 0x00003cfc #define HOSTCC_STATBLCK_RING1 0x00003d00 -/* 0x3d04 --> 0x4000 unused */ +/* 0x3d00 --> 0x3d80 unused */ + +#define HOSTCC_RXCOL_TICKS_VEC1 0x00003d80 +#define HOSTCC_TXCOL_TICKS_VEC1 0x00003d84 +#define HOSTCC_RXMAX_FRAMES_VEC1 0x00003d88 +#define HOSTCC_TXMAX_FRAMES_VEC1 0x00003d8c +#define HOSTCC_RXCOAL_MAXF_INT_VEC1 0x00003d90 +#define HOSTCC_TXCOAL_MAXF_INT_VEC1 0x00003d94 +/* 0x3d98 --> 0x4000 unused */ /* Memory arbiter control registers */ #define MEMARB_MODE 0x00004000 -- cgit v1.2.3-18-g5258 From baf8a94a572928710e9e60967d153a7bf3aebd9c Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:13:00 +0000 Subject: tg3: Add RSS support This patch adds code needed to enable RSS. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- drivers/net/tg3.h | 25 ++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f51c29c6474..26e9db8c1b9 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -102,6 +102,7 @@ #define TG3_DEF_RX_RING_PENDING 200 #define TG3_RX_JUMBO_RING_SIZE 256 #define TG3_DEF_RX_JUMBO_RING_PENDING 100 +#define TG3_RSS_INDIR_TBL_SIZE 128 /* Do not place this n-ring entries value into the tp struct itself, * we really want to expose these constants to GCC so that modulo et @@ -7497,6 +7498,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); udelay(100); + if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) { + val = tr32(MSGINT_MODE); + val |= MSGINT_MODE_MULTIVEC_EN | MSGINT_MODE_ENABLE; + tw32(MSGINT_MODE, val); + } + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { tw32_f(DMAC_MODE, DMAC_MODE_ENABLE); udelay(40); @@ -7565,7 +7572,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE); if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE | 0x8); - tw32(SNDBDI_MODE, SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE); + val = SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE; + if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) + val |= SNDBDI_MODE_MULTI_TXQ_EN; + tw32(SNDBDI_MODE, val); tw32(SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE); if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0) { @@ -7584,10 +7594,46 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32_f(MAC_TX_MODE, tp->tx_mode); udelay(100); + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) { + u32 reg = MAC_RSS_INDIR_TBL_0; + u8 *ent = (u8 *)&val; + + /* Setup the indirection table */ + for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++) { + int idx = i % sizeof(val); + + ent[idx] = i % (tp->irq_cnt - 1); + if (idx == sizeof(val) - 1) { + tw32(reg, val); + reg += 4; + } + } + + /* Setup the "secret" hash key. */ + tw32(MAC_RSS_HASH_KEY_0, 0x5f865437); + tw32(MAC_RSS_HASH_KEY_1, 0xe4ac62cc); + tw32(MAC_RSS_HASH_KEY_2, 0x50103a45); + tw32(MAC_RSS_HASH_KEY_3, 0x36621985); + tw32(MAC_RSS_HASH_KEY_4, 0xbf14c0e8); + tw32(MAC_RSS_HASH_KEY_5, 0x1bc27a1e); + tw32(MAC_RSS_HASH_KEY_6, 0x84f4b556); + tw32(MAC_RSS_HASH_KEY_7, 0x094ea6fe); + tw32(MAC_RSS_HASH_KEY_8, 0x7dda01e7); + tw32(MAC_RSS_HASH_KEY_9, 0xc04d7481); + } + tp->rx_mode = RX_MODE_ENABLE; if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE; + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) + tp->rx_mode |= RX_MODE_RSS_ENABLE | + RX_MODE_RSS_ITBL_HASH_BITS_7 | + RX_MODE_RSS_IPV6_HASH_EN | + RX_MODE_RSS_TCP_IPV6_HASH_EN | + RX_MODE_RSS_IPV4_HASH_EN | + RX_MODE_RSS_TCP_IPV4_HASH_EN; + tw32_f(MAC_RX_MODE, tp->rx_mode); udelay(10); @@ -8112,6 +8158,8 @@ static bool tg3_enable_msix(struct tg3 *tp) tp->irq_cnt = rc; } + tp->tg3_flags3 |= TG3_FLG3_ENABLE_RSS; + for (i = 0; i < tp->irq_max; i++) tp->napi[i].irq_vec = msix_ent[i].vector; @@ -8140,6 +8188,8 @@ static void tg3_ints_init(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_USING_MSI_OR_MSIX) { u32 msi_mode = tr32(MSGINT_MODE); + if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) + msi_mode |= MSGINT_MODE_MULTIVEC_EN; tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE); } defcfg: @@ -8157,6 +8207,7 @@ static void tg3_ints_fini(struct tg3 *tp) else if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) pci_disable_msi(tp->pdev); tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI_OR_MSIX; + tp->tg3_flags3 &= ~TG3_FLG3_ENABLE_RSS; } static int tg3_open(struct net_device *dev) diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 978b6d9546f..348add254d1 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -446,6 +446,12 @@ #define RX_MODE_PROMISC 0x00000100 #define RX_MODE_NO_CRC_CHECK 0x00000200 #define RX_MODE_KEEP_VLAN_TAG 0x00000400 +#define RX_MODE_RSS_IPV4_HASH_EN 0x00010000 +#define RX_MODE_RSS_TCP_IPV4_HASH_EN 0x00020000 +#define RX_MODE_RSS_IPV6_HASH_EN 0x00040000 +#define RX_MODE_RSS_TCP_IPV6_HASH_EN 0x00080000 +#define RX_MODE_RSS_ITBL_HASH_BITS_7 0x00700000 +#define RX_MODE_RSS_ENABLE 0x00800000 #define RX_MODE_IPV6_CSUM_ENABLE 0x01000000 #define MAC_RX_STATUS 0x0000046c #define RX_STATUS_REMOTE_TX_XOFFED 0x00000001 @@ -690,7 +696,22 @@ /* 0x5b8 --> 0x600 unused */ #define MAC_TX_MAC_STATE_BASE 0x00000600 /* 16 bytes */ #define MAC_RX_MAC_STATE_BASE 0x00000610 /* 20 bytes */ -/* 0x624 --> 0x800 unused */ +/* 0x624 --> 0x670 unused */ + +#define MAC_RSS_INDIR_TBL_0 0x00000630 + +#define MAC_RSS_HASH_KEY_0 0x00000670 +#define MAC_RSS_HASH_KEY_1 0x00000674 +#define MAC_RSS_HASH_KEY_2 0x00000678 +#define MAC_RSS_HASH_KEY_3 0x0000067c +#define MAC_RSS_HASH_KEY_4 0x00000680 +#define MAC_RSS_HASH_KEY_5 0x00000684 +#define MAC_RSS_HASH_KEY_6 0x00000688 +#define MAC_RSS_HASH_KEY_7 0x0000068c +#define MAC_RSS_HASH_KEY_8 0x00000690 +#define MAC_RSS_HASH_KEY_9 0x00000694 +/* 0x698 --> 0x800 unused */ + #define MAC_TX_STATS_OCTETS 0x00000800 #define MAC_TX_STATS_RESV1 0x00000804 #define MAC_TX_STATS_COLLISIONS 0x00000808 @@ -1465,6 +1486,7 @@ #define MSGINT_MODE 0x00006000 #define MSGINT_MODE_RESET 0x00000001 #define MSGINT_MODE_ENABLE 0x00000002 +#define MSGINT_MODE_MULTIVEC_EN 0x00000080 #define MSGINT_STATUS 0x00006004 #define MSGINT_FIFO 0x00006008 /* 0x600c --> 0x6400 unused */ @@ -2704,6 +2726,7 @@ struct tg3 { #define TG3_FLG3_NO_NVRAM 0x00004000 #define TG3_FLG3_TOGGLE_10_100_L1PLLPD 0x00008000 #define TG3_FLG3_PHY_IS_FET 0x00010000 +#define TG3_FLG3_ENABLE_RSS 0x00020000 struct timer_list timer; u16 timer_counter; -- cgit v1.2.3-18-g5258 From 0c1d0e2b05e92ad847b3ebe1c75b7974086bc8fa Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:16:33 +0000 Subject: tg3: Adjust RSS ring allocation strategies When multivector RSS is enabled, the first interrupt vector is only used to report link interrupts and error conditions. This patch changes the code so that rx and tx ring resources are not allocated for this vector. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 26e9db8c1b9..5782511c945 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4804,7 +4804,8 @@ static irqreturn_t tg3_msi_1shot(int irq, void *dev_id) struct tg3 *tp = tnapi->tp; prefetch(tnapi->hw_status); - prefetch(&tnapi->rx_rcb[tnapi->rx_rcb_ptr]); + if (tnapi->rx_rcb) + prefetch(&tnapi->rx_rcb[tnapi->rx_rcb_ptr]); if (likely(!tg3_irq_sync(tp))) napi_schedule(&tnapi->napi); @@ -4822,7 +4823,8 @@ static irqreturn_t tg3_msi(int irq, void *dev_id) struct tg3 *tp = tnapi->tp; prefetch(tnapi->hw_status); - prefetch(&tnapi->rx_rcb[tnapi->rx_rcb_ptr]); + if (tnapi->rx_rcb) + prefetch(&tnapi->rx_rcb[tnapi->rx_rcb_ptr]); /* * Writing any value to intr-mbox-0 clears PCI INTA# and * chip-internal interrupt pending events. @@ -5765,6 +5767,9 @@ static void tg3_free_rings(struct tg3 *tp) for (j = 0; j < tp->irq_cnt; j++) { struct tg3_napi *tnapi = &tp->napi[j]; + if (!tnapi->tx_buffers) + continue; + for (i = 0; i < TG3_TX_RING_SIZE; ) { struct tx_ring_info *txp; struct sk_buff *skb; @@ -5815,10 +5820,12 @@ static int tg3_init_rings(struct tg3 *tp) tnapi->tx_prod = 0; tnapi->tx_cons = 0; - memset(tnapi->tx_ring, 0, TG3_TX_RING_BYTES); + if (tnapi->tx_ring) + memset(tnapi->tx_ring, 0, TG3_TX_RING_BYTES); tnapi->rx_rcb_ptr = 0; - memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); + if (tnapi->rx_rcb) + memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); } return tg3_rx_prodring_alloc(tp, &tp->prodring[0]); @@ -5898,6 +5905,13 @@ static int tg3_alloc_consistent(struct tg3 *tp) memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); + /* + * If multivector RSS is enabled, vector 0 does not handle + * rx or tx interrupts. Don't allocate any resources for it. + */ + if (!i && (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS)) + continue; + tnapi->rx_rcb = pci_alloc_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp), &tnapi->rx_rcb_mapping); @@ -10166,8 +10180,13 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) struct tg3_napi *tnapi, *rnapi; struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; - tnapi = &tp->napi[0]; - rnapi = &tp->napi[0]; + if (tp->irq_cnt > 1) { + tnapi = &tp->napi[1]; + rnapi = &tp->napi[1]; + } else { + tnapi = &tp->napi[0]; + rnapi = &tp->napi[0]; + } coal_now = tnapi->coal_now | rnapi->coal_now; if (loopback_mode == TG3_MAC_LOOPBACK) { -- cgit v1.2.3-18-g5258 From 8d9d7cfc0ec2fe37ff9afd74326d03f38f96ad1b Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:19:05 +0000 Subject: tg3: Assign rx ret producer indexes by vector When RSS is enabled, the status block format changes slightly. The "rx_jumbo_consumer", "reserved", and "rx_mini_consumer" members get mapped to the other three rx return ring producer indexes. This patch introduces a new per-interrupt member which identifies which location in the status block a particular vector should look for return ring updates. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 31 +++++++++++++++++++++++++++---- drivers/net/tg3.h | 1 + 2 files changed, 28 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 5782511c945..f71ea462ca4 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -667,7 +667,7 @@ static inline unsigned int tg3_has_work(struct tg3_napi *tnapi) } /* check for RX/TX work to do */ if (sblk->idx[0].tx_consumer != tnapi->tx_cons || - sblk->idx[0].rx_producer != tnapi->rx_rcb_ptr) + *(tnapi->rx_rcb_prod_idx) != tnapi->rx_rcb_ptr) work_exists = 1; return work_exists; @@ -4518,7 +4518,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget) int received; struct tg3_rx_prodring_set *tpr = &tp->prodring[0]; - hw_idx = tnapi->hw_status->idx[0].rx_producer; + hw_idx = *(tnapi->rx_rcb_prod_idx); /* * We need to order the read of hw_idx and the read of * the opaque cookie. @@ -4649,7 +4649,7 @@ next_pkt_nopost: /* Refresh hw_idx to see if there is new work */ if (sw_idx == hw_idx) { - hw_idx = tnapi->hw_status->idx[0].rx_producer; + hw_idx = *(tnapi->rx_rcb_prod_idx); rmb(); } } @@ -4711,7 +4711,7 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) * All RX "locking" is done by ensuring outside * code synchronizes with tg3->napi.poll() */ - if (sblk->idx[0].rx_producer != tnapi->rx_rcb_ptr) + if (*(tnapi->rx_rcb_prod_idx) != tnapi->rx_rcb_ptr) work_done += tg3_rx(tnapi, budget - work_done); return work_done; @@ -5896,6 +5896,7 @@ static int tg3_alloc_consistent(struct tg3 *tp) for (i = 0; i < tp->irq_cnt; i++) { struct tg3_napi *tnapi = &tp->napi[i]; + struct tg3_hw_status *sblk; tnapi->hw_status = pci_alloc_consistent(tp->pdev, TG3_HW_STATUS_SIZE, @@ -5904,6 +5905,28 @@ static int tg3_alloc_consistent(struct tg3 *tp) goto err_out; memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); + sblk = tnapi->hw_status; + + /* + * When RSS is enabled, the status block format changes + * slightly. The "rx_jumbo_consumer", "reserved", + * and "rx_mini_consumer" members get mapped to the + * other three rx return ring producer indexes. + */ + switch (i) { + default: + tnapi->rx_rcb_prod_idx = &sblk->idx[0].rx_producer; + break; + case 2: + tnapi->rx_rcb_prod_idx = &sblk->rx_jumbo_consumer; + break; + case 3: + tnapi->rx_rcb_prod_idx = &sblk->reserved; + break; + case 4: + tnapi->rx_rcb_prod_idx = &sblk->rx_mini_consumer; + break; + } /* * If multivector RSS is enabled, vector 0 does not handle diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 348add254d1..685d9712a80 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2538,6 +2538,7 @@ struct tg3_napi { u32 consmbox; u32 rx_rcb_ptr; + u16 *rx_rcb_prod_idx; struct tg3_rx_buffer_desc *rx_rcb; struct tg3_tx_buffer_desc *tx_ring; -- cgit v1.2.3-18-g5258 From f6eb9b1fc1411d22c073f5264e5630a541d0f7df Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:19:53 +0000 Subject: tg3: Add 5717 asic rev This patch adds the 5717 asic rev. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 130 ++++++++++++++++++++++++++++++++++++++++++------------ drivers/net/tg3.h | 25 ++++++++--- 2 files changed, 119 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f71ea462ca4..f8bb5b737eb 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -111,7 +111,8 @@ * replace things like '% foo' with '& (foo - 1)'. */ #define TG3_RX_RCB_RING_SIZE(tp) \ - ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ? 512 : 1024) + (((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) && \ + !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) ? 512 : 1024) #define TG3_TX_RING_SIZE 512 #define TG3_DEF_TX_RING_PENDING (TG3_TX_RING_SIZE - 1) @@ -733,13 +734,15 @@ static inline void tg3_netif_start(struct tg3 *tp) static void tg3_switch_clocks(struct tg3 *tp) { - u32 clock_ctrl = tr32(TG3PCI_CLOCK_CTRL); + u32 clock_ctrl; u32 orig_clock_ctrl; if ((tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) return; + clock_ctrl = tr32(TG3PCI_CLOCK_CTRL); + orig_clock_ctrl = clock_ctrl; clock_ctrl &= (CLOCK_CTRL_FORCE_CLKRUN | CLOCK_CTRL_CLKRUN_OENABLE | @@ -1993,8 +1996,9 @@ static void tg3_frob_aux_power(struct tg3 *tp) if ((tp->tg3_flags2 & TG3_FLG2_IS_NIC) == 0) return; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) { struct net_device *dev_peer; dev_peer = pci_get_drvdata(tp->pdev_peer); @@ -5211,6 +5215,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, mss = 0; if ((mss = skb_shinfo(skb)->gso_size) != 0) { int tcp_opt_len, ip_tcp_len; + u32 hdrlen; if (skb_header_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { @@ -5219,7 +5224,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, } if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) - mss |= (skb_headlen(skb) - ETH_HLEN) << 9; + hdrlen = skb_headlen(skb) - ETH_HLEN; else { struct iphdr *iph = ip_hdr(skb); @@ -5228,9 +5233,17 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, iph->check = 0; iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len); - mss |= (ip_tcp_len + tcp_opt_len) << 9; + hdrlen = ip_tcp_len + tcp_opt_len; } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) { + mss |= (hdrlen & 0xc) << 12; + if (hdrlen & 0x10) + base_flags |= 0x00000010; + base_flags |= (hdrlen & 0x3e0) << 5; + } else + mss |= hdrlen << 9; + base_flags |= (TXD_FLAG_CPU_PRE_DMA | TXD_FLAG_CPU_POST_DMA); @@ -5258,6 +5271,10 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, len = skb_headlen(skb); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 && + !mss && skb->len > ETH_DATA_LEN) + base_flags |= TXD_FLAG_JMB_PKT; + tg3_set_txd(tnapi, entry, mapping, len, base_flags, (skb_shinfo(skb)->nr_frags == 0) | (mss << 1)); @@ -6564,7 +6581,9 @@ static int tg3_chip_reset(struct tg3 *tp) tg3_mdio_start(tp); if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && - tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) { + tp->pci_chip_rev_id != CHIPREV_ID_5750_A0 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717) { val = tr32(0x7c00); tw32(0x7c00, val | (1 << 25)); @@ -6993,7 +7012,9 @@ static void tg3_rings_reset(struct tg3 *tp) /* Disable all receive return rings but the first. */ - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) + limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 17; + else if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 16; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 4; @@ -7197,7 +7218,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) return err; if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) { + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717) { /* This value is determined during the probe time DMA * engine test, tg3_test_dma. */ @@ -7351,7 +7373,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) BDINFO_FLAGS_DISABLED); } - val = RX_STD_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) + val = (RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT) | + (RX_STD_MAX_SIZE << 2); + else + val = RX_STD_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT; } else val = RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT; @@ -7366,6 +7392,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32_rx_mbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW, tpr->rx_jmb_ptr); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) { + tw32(STD_REPLENISH_LWM, 32); + tw32(JMB_REPLENISH_LWM, 16); + } + tg3_rings_reset(tp); /* Initialize MAC address and backoff seed. */ @@ -8021,6 +8052,7 @@ static int tg3_test_interrupt(struct tg3 *tp) struct tg3_napi *tnapi = &tp->napi[0]; struct net_device *dev = tp->dev; int err, i, intr_ok = 0; + u32 val; if (!netif_running(dev)) return -ENODEV; @@ -8029,6 +8061,16 @@ static int tg3_test_interrupt(struct tg3 *tp) free_irq(tnapi->irq_vec, tnapi); + /* + * Turn off MSI one shot mode. Otherwise this test has no + * observable way to know whether the interrupt was delivered. + */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 && + (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) { + val = tr32(MSGINT_MODE) | MSGINT_MODE_ONE_SHOT_DISABLE; + tw32(MSGINT_MODE, val); + } + err = request_irq(tnapi->irq_vec, tg3_test_isr, IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, tnapi); if (err) @@ -8064,8 +8106,15 @@ static int tg3_test_interrupt(struct tg3 *tp) if (err) return err; - if (intr_ok) + if (intr_ok) { + /* Reenable MSI one shot mode. */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 && + (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) { + val = tr32(MSGINT_MODE) & ~MSGINT_MODE_ONE_SHOT_DISABLE; + tw32(MSGINT_MODE, val); + } return 0; + } return -EIO; } @@ -8350,13 +8399,13 @@ static int tg3_open(struct net_device *dev) goto err_out2; } - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { - if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) { - u32 val = tr32(PCIE_TRANSACTION_CFG); + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 && + (tp->tg3_flags2 & TG3_FLG2_USING_MSI) && + (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI)) { + u32 val = tr32(PCIE_TRANSACTION_CFG); - tw32(PCIE_TRANSACTION_CFG, - val | PCIE_TRANS_CFG_1SHOT_MSI); - } + tw32(PCIE_TRANSACTION_CFG, + val | PCIE_TRANS_CFG_1SHOT_MSI); } } @@ -9392,7 +9441,8 @@ static int tg3_set_tso(struct net_device *dev, u32 value) (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) dev->features |= NETIF_F_TSO_ECN; } else dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN); @@ -12291,8 +12341,17 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_USE_PROD_ID_REG) { u32 prod_id_asic_rev; - pci_read_config_dword(tp->pdev, TG3PCI_PRODID_ASICREV, - &prod_id_asic_rev); + if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717C || + tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717S || + tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718C || + tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718S) + pci_read_config_dword(tp->pdev, + TG3PCI_GEN2_PRODID_ASICREV, + &prod_id_asic_rev); + else + pci_read_config_dword(tp->pdev, TG3PCI_PRODID_ASICREV, + &prod_id_asic_rev); + tp->pci_chip_rev_id = prod_id_asic_rev; } @@ -12430,8 +12489,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl); - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) tp->pdev_peer = tg3_find_peer(tp); /* Intentionally exclude ASIC_REV_5906 */ @@ -12440,7 +12500,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) tp->tg3_flags3 |= TG3_FLG3_5755_PLUS; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || @@ -12490,8 +12551,16 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->irq_max = 1; +#ifdef TG3_NAPI + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) { + tp->tg3_flags |= TG3_FLAG_SUPPORT_MSIX; + tp->irq_max = TG3_IRQ_MAX_VECS; + } +#endif + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) tp->tg3_flags |= TG3_FLAG_JUMBO_CAPABLE; pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, @@ -12625,7 +12694,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->write32 = tg3_write_flush_reg32; } - if ((tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) || (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)) { tp->write32_tx_mbox = tg3_write32_tx_mbox; @@ -12684,7 +12752,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT; /* Set up tp->grc_local_ctrl before calling tg3_set_power_state(). @@ -12762,7 +12831,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && !(tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780) { + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || @@ -13486,7 +13556,8 @@ static void __devinit tg3_init_link_config(struct tg3 *tp) static void __devinit tg3_init_bufmgr_config(struct tg3 *tp) { - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { + if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717) { tp->bufmgr_config.mbuf_read_dma_low_water = DEFAULT_MB_RDMA_LOW_WATER_5705; tp->bufmgr_config.mbuf_mac_rx_low_water = @@ -13925,7 +13996,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) dev->features |= NETIF_F_TSO_ECN; } diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 685d9712a80..5994476a250 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -46,6 +46,10 @@ #define TG3PCI_DEVICE_TIGON3_57788 0x1691 #define TG3PCI_DEVICE_TIGON3_5785_G 0x1699 /* GPHY */ #define TG3PCI_DEVICE_TIGON3_5785_F 0x16a0 /* 10/100 only */ +#define TG3PCI_DEVICE_TIGON3_5717C 0x1655 +#define TG3PCI_DEVICE_TIGON3_5717S 0x1656 +#define TG3PCI_DEVICE_TIGON3_5718C 0x1665 +#define TG3PCI_DEVICE_TIGON3_5718S 0x1666 /* 0x04 --> 0x64 unused */ #define TG3PCI_MSI_DATA 0x00000064 /* 0x66 --> 0x68 unused */ @@ -117,6 +121,7 @@ #define ASIC_REV_5761 0x5761 #define ASIC_REV_5785 0x5785 #define ASIC_REV_57780 0x57780 +#define ASIC_REV_5717 0x5717 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -203,20 +208,20 @@ #define TG3PCI_MEM_WIN_BASE_ADDR 0x0000007c #define TG3PCI_REG_DATA 0x00000080 #define TG3PCI_MEM_WIN_DATA 0x00000084 -#define TG3PCI_MODE_CTRL 0x00000088 -#define TG3PCI_MISC_CFG 0x0000008c #define TG3PCI_MISC_LOCAL_CTRL 0x00000090 /* 0x94 --> 0x98 unused */ #define TG3PCI_STD_RING_PROD_IDX 0x00000098 /* 64-bit */ #define TG3PCI_RCV_RET_RING_CON_IDX 0x000000a0 /* 64-bit */ -#define TG3PCI_SND_PROD_IDX 0x000000a8 /* 64-bit */ -/* 0xb0 --> 0xb8 unused */ +/* 0xa0 --> 0xb8 unused */ #define TG3PCI_DUAL_MAC_CTRL 0x000000b8 #define DUAL_MAC_CTRL_CH_MASK 0x00000003 #define DUAL_MAC_CTRL_ID 0x00000004 #define TG3PCI_PRODID_ASICREV 0x000000bc #define PROD_ID_ASIC_REV_MASK 0x0fffffff -/* 0xc0 --> 0x110 unused */ +/* 0xc0 --> 0xf4 unused */ + +#define TG3PCI_GEN2_PRODID_ASICREV 0x000000f4 +/* 0xf8 --> 0x200 unused */ #define TG3_CORR_ERR_STAT 0x00000110 #define TG3_CORR_ERR_STAT_CLEAR 0xffffffff @@ -972,7 +977,11 @@ #define RCVBDI_MINI_THRESH 0x00002c14 #define RCVBDI_STD_THRESH 0x00002c18 #define RCVBDI_JUMBO_THRESH 0x00002c1c -/* 0x2c20 --> 0x3000 unused */ +/* 0x2c20 --> 0x2d00 unused */ + +#define STD_REPLENISH_LWM 0x00002d00 +#define JMB_REPLENISH_LWM 0x00002d04 +/* 0x2d08 --> 0x3000 unused */ /* Receive BD Completion Control Registers */ #define RCVCC_MODE 0x00003000 @@ -1486,6 +1495,7 @@ #define MSGINT_MODE 0x00006000 #define MSGINT_MODE_RESET 0x00000001 #define MSGINT_MODE_ENABLE 0x00000002 +#define MSGINT_MODE_ONE_SHOT_DISABLE 0x00000020 #define MSGINT_MODE_MULTIVEC_EN 0x00000080 #define MSGINT_STATUS 0x00006004 #define MSGINT_FIFO 0x00006008 @@ -2124,6 +2134,7 @@ struct tg3_tx_buffer_desc { #define TXD_FLAG_IP_CSUM 0x0002 #define TXD_FLAG_END 0x0004 #define TXD_FLAG_IP_FRAG 0x0008 +#define TXD_FLAG_JMB_PKT 0x0008 #define TXD_FLAG_IP_FRAG_END 0x0010 #define TXD_FLAG_VLAN 0x0040 #define TXD_FLAG_COAL_NOW 0x0080 @@ -2520,7 +2531,7 @@ struct tg3_rx_prodring_set { dma_addr_t rx_jmb_mapping; }; -#define TG3_IRQ_MAX_VECS 1 +#define TG3_IRQ_MAX_VECS 5 struct tg3_napi { struct napi_struct napi ____cacheline_aligned; -- cgit v1.2.3-18-g5258 From a1b950d56de3c72bea3343f54de24c43fb7dc74e Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:20:17 +0000 Subject: tg3: Add 5717 NVRAM detection routines This patch adds NVRAM detection routines for the 5717. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 154 ++++++++++++++++++++++++++++++++++++++---------------- drivers/net/tg3.h | 23 +++++++- 2 files changed, 130 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f8bb5b737eb..2de1ab6278d 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10853,6 +10853,33 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) } } +static void __devinit tg3_nvram_get_pagesize(struct tg3 *tp, u32 nvmcfg1) +{ + switch (nvmcfg1 & NVRAM_CFG1_5752PAGE_SIZE_MASK) { + case FLASH_5752PAGE_SIZE_256: + tp->nvram_pagesize = 256; + break; + case FLASH_5752PAGE_SIZE_512: + tp->nvram_pagesize = 512; + break; + case FLASH_5752PAGE_SIZE_1K: + tp->nvram_pagesize = 1024; + break; + case FLASH_5752PAGE_SIZE_2K: + tp->nvram_pagesize = 2048; + break; + case FLASH_5752PAGE_SIZE_4K: + tp->nvram_pagesize = 4096; + break; + case FLASH_5752PAGE_SIZE_264: + tp->nvram_pagesize = 264; + break; + case FLASH_5752PAGE_SIZE_528: + tp->nvram_pagesize = 528; + break; + } +} + static void __devinit tg3_get_5752_nvram_info(struct tg3 *tp) { u32 nvcfg1; @@ -10884,26 +10911,7 @@ static void __devinit tg3_get_5752_nvram_info(struct tg3 *tp) } if (tp->tg3_flags2 & TG3_FLG2_FLASH) { - switch (nvcfg1 & NVRAM_CFG1_5752PAGE_SIZE_MASK) { - case FLASH_5752PAGE_SIZE_256: - tp->nvram_pagesize = 256; - break; - case FLASH_5752PAGE_SIZE_512: - tp->nvram_pagesize = 512; - break; - case FLASH_5752PAGE_SIZE_1K: - tp->nvram_pagesize = 1024; - break; - case FLASH_5752PAGE_SIZE_2K: - tp->nvram_pagesize = 2048; - break; - case FLASH_5752PAGE_SIZE_4K: - tp->nvram_pagesize = 4096; - break; - case FLASH_5752PAGE_SIZE_264: - tp->nvram_pagesize = 264; - break; - } + tg3_nvram_get_pagesize(tp, nvcfg1); } else { /* For eeprom, set pagesize to maximum eeprom size */ tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; @@ -11156,34 +11164,84 @@ static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp) return; } - switch (nvcfg1 & NVRAM_CFG1_5752PAGE_SIZE_MASK) { - case FLASH_5752PAGE_SIZE_256: + tg3_nvram_get_pagesize(tp, nvcfg1); + if (tp->nvram_pagesize != 264 && tp->nvram_pagesize != 528) tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; - tp->nvram_pagesize = 256; - break; - case FLASH_5752PAGE_SIZE_512: - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; - tp->nvram_pagesize = 512; - break; - case FLASH_5752PAGE_SIZE_1K: - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; - tp->nvram_pagesize = 1024; - break; - case FLASH_5752PAGE_SIZE_2K: - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; - tp->nvram_pagesize = 2048; - break; - case FLASH_5752PAGE_SIZE_4K: - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; - tp->nvram_pagesize = 4096; - break; - case FLASH_5752PAGE_SIZE_264: - tp->nvram_pagesize = 264; +} + + +static void __devinit tg3_get_5717_nvram_info(struct tg3 *tp) +{ + u32 nvcfg1; + + nvcfg1 = tr32(NVRAM_CFG1); + + switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { + case FLASH_5717VENDOR_ATMEL_EEPROM: + case FLASH_5717VENDOR_MICRO_EEPROM: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; + + nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; + tw32(NVRAM_CFG1, nvcfg1); + return; + case FLASH_5717VENDOR_ATMEL_MDB011D: + case FLASH_5717VENDOR_ATMEL_ADB011B: + case FLASH_5717VENDOR_ATMEL_ADB011D: + case FLASH_5717VENDOR_ATMEL_MDB021D: + case FLASH_5717VENDOR_ATMEL_ADB021B: + case FLASH_5717VENDOR_ATMEL_ADB021D: + case FLASH_5717VENDOR_ATMEL_45USPT: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + + switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { + case FLASH_5717VENDOR_ATMEL_MDB021D: + case FLASH_5717VENDOR_ATMEL_ADB021B: + case FLASH_5717VENDOR_ATMEL_ADB021D: + tp->nvram_size = TG3_NVRAM_SIZE_256KB; + break; + default: + tp->nvram_size = TG3_NVRAM_SIZE_128KB; + break; + } break; - case FLASH_5752PAGE_SIZE_528: - tp->nvram_pagesize = 528; + case FLASH_5717VENDOR_ST_M_M25PE10: + case FLASH_5717VENDOR_ST_A_M25PE10: + case FLASH_5717VENDOR_ST_M_M45PE10: + case FLASH_5717VENDOR_ST_A_M45PE10: + case FLASH_5717VENDOR_ST_M_M25PE20: + case FLASH_5717VENDOR_ST_A_M25PE20: + case FLASH_5717VENDOR_ST_M_M45PE20: + case FLASH_5717VENDOR_ST_A_M45PE20: + case FLASH_5717VENDOR_ST_25USPT: + case FLASH_5717VENDOR_ST_45USPT: + tp->nvram_jedecnum = JEDEC_ST; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + + switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { + case FLASH_5717VENDOR_ST_M_M25PE20: + case FLASH_5717VENDOR_ST_A_M25PE20: + case FLASH_5717VENDOR_ST_M_M45PE20: + case FLASH_5717VENDOR_ST_A_M45PE20: + tp->nvram_size = TG3_NVRAM_SIZE_256KB; + break; + default: + tp->nvram_size = TG3_NVRAM_SIZE_128KB; + break; + } break; + default: + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM; + return; } + + tg3_nvram_get_pagesize(tp, nvcfg1); + if (tp->nvram_pagesize != 264 && tp->nvram_pagesize != 528) + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; } /* Chips other than 5700/5701 use the NVRAM for fetching info. */ @@ -11228,6 +11286,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) tg3_get_5906_nvram_info(tp); else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) tg3_get_57780_nvram_info(tp); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) + tg3_get_5717_nvram_info(tp); else tg3_get_nvram_info(tp); @@ -13074,8 +13134,10 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) tw32_f(NVRAM_CMD, NVRAM_CMD_RESET); else tg3_nvram_unlock(tp); - } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) + } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) { + if (tr32(TG3_CPMU_STATUS) & TG3_CPMU_STATUS_PCIE_FUNC) + mac_offset = 0xcc; + } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) mac_offset = 0x10; /* First try to get it from MAC address mailbox. */ diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 5994476a250..ea57a3a4372 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1027,8 +1027,10 @@ #define TG3_CPMU_HST_ACC 0x0000361c #define CPMU_HST_ACC_MACCLK_MASK 0x001f0000 #define CPMU_HST_ACC_MACCLK_6_25 0x00130000 -/* 0x3620 --> 0x3630 unused */ +/* 0x3620 --> 0x362c unused */ +#define TG3_CPMU_STATUS 0x0000362c +#define TG3_CPMU_STATUS_PCIE_FUNC 0x20000000 #define TG3_CPMU_CLCK_STAT 0x00003630 #define CPMU_CLCK_STAT_MAC_CLCK_MASK 0x001f0000 #define CPMU_CLCK_STAT_MAC_CLCK_62_5 0x00000000 @@ -1692,6 +1694,25 @@ #define FLASH_57780VENDOR_ATMEL_AT45DB021B 0x03400002 #define FLASH_57780VENDOR_ATMEL_AT45DB041D 0x00400001 #define FLASH_57780VENDOR_ATMEL_AT45DB041B 0x03400001 +#define FLASH_5717VENDOR_ATMEL_EEPROM 0x02000001 +#define FLASH_5717VENDOR_MICRO_EEPROM 0x02000003 +#define FLASH_5717VENDOR_ATMEL_MDB011D 0x01000001 +#define FLASH_5717VENDOR_ATMEL_MDB021D 0x01000003 +#define FLASH_5717VENDOR_ST_M_M25PE10 0x02000000 +#define FLASH_5717VENDOR_ST_M_M25PE20 0x02000002 +#define FLASH_5717VENDOR_ST_M_M45PE10 0x00000001 +#define FLASH_5717VENDOR_ST_M_M45PE20 0x00000003 +#define FLASH_5717VENDOR_ATMEL_ADB011B 0x01400000 +#define FLASH_5717VENDOR_ATMEL_ADB021B 0x01400002 +#define FLASH_5717VENDOR_ATMEL_ADB011D 0x01400001 +#define FLASH_5717VENDOR_ATMEL_ADB021D 0x01400003 +#define FLASH_5717VENDOR_ST_A_M25PE10 0x02400000 +#define FLASH_5717VENDOR_ST_A_M25PE20 0x02400002 +#define FLASH_5717VENDOR_ST_A_M45PE10 0x02400001 +#define FLASH_5717VENDOR_ST_A_M45PE20 0x02400003 +#define FLASH_5717VENDOR_ATMEL_45USPT 0x03400000 +#define FLASH_5717VENDOR_ST_25USPT 0x03400002 +#define FLASH_5717VENDOR_ST_45USPT 0x03400001 #define NVRAM_CFG1_5752PAGE_SIZE_MASK 0x70000000 #define FLASH_5752PAGE_SIZE_256 0x00000000 #define FLASH_5752PAGE_SIZE_512 0x10000000 -- cgit v1.2.3-18-g5258 From 882e9793faa9425dff581c33b1af45ed10145626 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:21:36 +0000 Subject: tg3: Add MDIO bus address assignments The 5717 is a dual port chip that has a shared MDIO bus design. While it is impossible for one function to interface with the wrong phy, that function still needs to know which MDIO bus address to use when interfacing with its own phy. This patch adds code to determine which MDIO bus address to use. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 23 +++++++++++++++++++---- drivers/net/tg3.h | 3 +++ 2 files changed, 22 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 2de1ab6278d..9ff97cc7e91 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -782,7 +782,7 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val) *val = 0x0; - frame_val = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) & + frame_val = ((tp->phy_addr << MI_COM_PHY_ADDR_SHIFT) & MI_COM_PHY_ADDR_MASK); frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) & MI_COM_REG_ADDR_MASK); @@ -833,7 +833,7 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val) udelay(80); } - frame_val = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) & + frame_val = ((tp->phy_addr << MI_COM_PHY_ADDR_SHIFT) & MI_COM_PHY_ADDR_MASK); frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) & MI_COM_REG_ADDR_MASK); @@ -1021,6 +1021,21 @@ static void tg3_mdio_start(struct tg3 *tp) tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(80); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) { + u32 funcnum, is_serdes; + + funcnum = tr32(TG3_CPMU_STATUS) & TG3_CPMU_STATUS_PCIE_FUNC; + if (funcnum) + tp->phy_addr = 2; + else + tp->phy_addr = 1; + + is_serdes = tr32(SG_DIG_STATUS) & SG_DIG_IS_SERDES; + if (is_serdes) + tp->phy_addr += 7; + } else + tp->phy_addr = PHY_ADDR; + if ((tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) && GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) tg3_mdio_config_5785(tp); @@ -9266,7 +9281,7 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->speed = tp->link_config.active_speed; cmd->duplex = tp->link_config.active_duplex; } - cmd->phy_address = PHY_ADDR; + cmd->phy_address = tp->phy_addr; cmd->transceiver = XCVR_INTERNAL; cmd->autoneg = tp->link_config.autoneg; cmd->maxtxpkt = 0; @@ -10570,7 +10585,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) switch(cmd) { case SIOCGMIIPHY: - data->phy_id = PHY_ADDR; + data->phy_id = tp->phy_addr; /* fallthru */ case SIOCGMIIREG: { diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index ea57a3a4372..82b45d8797b 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -694,6 +694,7 @@ #define SG_DIG_PARTNER_FULL_DUPLEX 0x00020000 /* If !MRADV_CRC16_SELECT */ #define SG_DIG_PARTNER_NEXT_PAGE 0x00010000 /* If !MRADV_CRC16_SELECT */ #define SG_DIG_AUTONEG_STATE_MASK 0x00000ff0 +#define SG_DIG_IS_SERDES 0x00000100 #define SG_DIG_COMMA_DETECTOR 0x00000008 #define SG_DIG_MAC_ACK_STATUS 0x00000004 #define SG_DIG_AUTONEG_COMPLETE 0x00000002 @@ -2805,6 +2806,8 @@ struct tg3 { struct mii_bus *mdio_bus; int mdio_irq[PHY_MAX_ADDR]; + u8 phy_addr; + /* PHY info */ u32 phy_id; #define PHY_ID_MASK 0xfffffff0 -- cgit v1.2.3-18-g5258 From daf09de817353f18bb81a23a023d429cfd258e62 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 1 Sep 2009 13:22:42 +0000 Subject: tg3: Update version to 3.102 This patch updates the tg3 version to 3.102. Signed-off-by: Matt Carlson Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 9ff97cc7e91..bd498105260 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -68,8 +68,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.101" -#define DRV_MODULE_RELDATE "August 28, 2009" +#define DRV_MODULE_VERSION "3.102" +#define DRV_MODULE_RELDATE "September 1, 2009" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v1.2.3-18-g5258 From 0fc0b732eaa38beb93a6fb62f77c7bd9622c76ec Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 2 Sep 2009 01:03:33 -0700 Subject: netdev: drivers should make ethtool_ops const No need to put ethtool_ops in data, they should be const. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/firewire/net.c | 2 +- drivers/ieee1394/eth1394.c | 4 ++-- drivers/infiniband/hw/nes/nes_nic.c | 2 +- drivers/net/arm/ep93xx_eth.c | 2 +- drivers/net/arm/ixp4xx_eth.c | 2 +- drivers/net/arm/ks8695net.c | 2 +- drivers/net/atl1c/atl1c_ethtool.c | 2 +- drivers/net/atl1e/atl1e_ethtool.c | 2 +- drivers/net/atlx/atl2.c | 2 +- drivers/net/benet/be.h | 2 +- drivers/net/benet/be_ethtool.c | 2 +- drivers/net/bfin_mac.c | 2 +- drivers/net/bnx2x_main.c | 2 +- drivers/net/enic/enic_main.c | 2 +- drivers/net/igb/igb_ethtool.c | 2 +- drivers/net/ipg.c | 2 +- drivers/net/korina.c | 2 +- drivers/net/ks8842.c | 2 +- drivers/net/macb.c | 2 +- drivers/net/netxen/netxen_nic.h | 2 +- drivers/net/netxen/netxen_nic_ethtool.c | 2 +- drivers/net/ps3_gelic_net.c | 2 +- drivers/net/ps3_gelic_wireless.c | 2 +- drivers/net/sfc/ethtool.c | 2 +- drivers/net/sfc/ethtool.h | 2 +- drivers/net/tehuti.c | 2 +- drivers/net/usb/asix.c | 4 ++-- drivers/net/usb/catc.c | 2 +- drivers/net/usb/dm9601.c | 2 +- drivers/net/usb/hso.c | 2 +- drivers/net/usb/kaweth.c | 2 +- drivers/net/usb/mcs7830.c | 2 +- drivers/net/usb/pegasus.c | 2 +- drivers/net/usb/rtl8150.c | 2 +- drivers/net/usb/smsc95xx.c | 2 +- drivers/net/usb/usbnet.c | 2 +- drivers/net/veth.c | 2 +- drivers/net/virtio_net.c | 2 +- drivers/net/wireless/libertas/dev.h | 2 +- drivers/net/wireless/libertas/ethtool.c | 2 +- drivers/net/xen-netfront.c | 4 ++-- drivers/s390/net/qeth_l2_main.c | 4 ++-- drivers/s390/net/qeth_l3_main.c | 2 +- drivers/staging/at76_usb/at76_usb.c | 2 +- drivers/staging/octeon/ethernet-mdio.c | 2 +- drivers/staging/octeon/ethernet-mdio.h | 2 +- drivers/staging/sxg/sxg.h | 2 +- drivers/staging/sxg/sxg_ethtool.c | 2 +- drivers/usb/gadget/u_ether.c | 2 +- 49 files changed, 53 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index d923d1dc458..84edc8b84c6 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -1342,7 +1342,7 @@ static void fwnet_get_drvinfo(struct net_device *net, strcpy(info->bus_info, "ieee1394"); } -static struct ethtool_ops fwnet_ethtool_ops = { +static const struct ethtool_ops fwnet_ethtool_ops = { .get_drvinfo = fwnet_get_drvinfo, }; diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 1ad8785e398..3a62c4c2d41 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -173,7 +173,7 @@ static netdev_tx_t ether1394_tx(struct sk_buff *skb, struct net_device *dev); static void ether1394_iso(struct hpsb_iso *iso); -static struct ethtool_ops ethtool_ops; +static const struct ethtool_ops ethtool_ops; static int ether1394_write(struct hpsb_host *host, int srcid, int destid, quadlet_t *data, u64 addr, size_t len, u16 flags); @@ -1706,7 +1706,7 @@ static void ether1394_get_drvinfo(struct net_device *dev, strcpy(info->bus_info, "ieee1394"); /* FIXME provide more detail? */ } -static struct ethtool_ops ethtool_ops = { +static const struct ethtool_ops ethtool_ops = { .get_drvinfo = ether1394_get_drvinfo }; diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index c6e6611d301..538e409d451 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -1508,7 +1508,7 @@ static int nes_netdev_set_settings(struct net_device *netdev, struct ethtool_cmd } -static struct ethtool_ops nes_ethtool_ops = { +static const struct ethtool_ops nes_ethtool_ops = { .get_link = ethtool_op_get_link, .get_settings = nes_netdev_get_settings, .set_settings = nes_netdev_set_settings, diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index fbf4645417d..2be49c81799 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -762,7 +762,7 @@ static u32 ep93xx_get_link(struct net_device *dev) return mii_link_ok(&ep->mii); } -static struct ethtool_ops ep93xx_ethtool_ops = { +static const struct ethtool_ops ep93xx_ethtool_ops = { .get_drvinfo = ep93xx_get_drvinfo, .get_settings = ep93xx_get_settings, .set_settings = ep93xx_set_settings, diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c index 3fe09876e76..691b81eb0f4 100644 --- a/drivers/net/arm/ixp4xx_eth.c +++ b/drivers/net/arm/ixp4xx_eth.c @@ -802,7 +802,7 @@ static int ixp4xx_nway_reset(struct net_device *dev) return phy_start_aneg(port->phydev); } -static struct ethtool_ops ixp4xx_ethtool_ops = { +static const struct ethtool_ops ixp4xx_ethtool_ops = { .get_drvinfo = ixp4xx_get_drvinfo, .get_settings = ixp4xx_get_settings, .set_settings = ixp4xx_set_settings, diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c index 35cd264abae..4f702d52606 100644 --- a/drivers/net/arm/ks8695net.c +++ b/drivers/net/arm/ks8695net.c @@ -1063,7 +1063,7 @@ ks8695_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) sizeof(info->bus_info)); } -static struct ethtool_ops ks8695_ethtool_ops = { +static const struct ethtool_ops ks8695_ethtool_ops = { .get_msglevel = ks8695_get_msglevel, .set_msglevel = ks8695_set_msglevel, .get_settings = ks8695_get_settings, diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/atl1c/atl1c_ethtool.c index 00d11b480af..9b1e0eaebb5 100644 --- a/drivers/net/atl1c/atl1c_ethtool.c +++ b/drivers/net/atl1c/atl1c_ethtool.c @@ -294,7 +294,7 @@ static int atl1c_nway_reset(struct net_device *netdev) return 0; } -static struct ethtool_ops atl1c_ethtool_ops = { +static const struct ethtool_ops atl1c_ethtool_ops = { .get_settings = atl1c_get_settings, .set_settings = atl1c_set_settings, .get_drvinfo = atl1c_get_drvinfo, diff --git a/drivers/net/atl1e/atl1e_ethtool.c b/drivers/net/atl1e/atl1e_ethtool.c index 4003955d7a9..60edb9f232b 100644 --- a/drivers/net/atl1e/atl1e_ethtool.c +++ b/drivers/net/atl1e/atl1e_ethtool.c @@ -378,7 +378,7 @@ static int atl1e_nway_reset(struct net_device *netdev) return 0; } -static struct ethtool_ops atl1e_ethtool_ops = { +static const struct ethtool_ops atl1e_ethtool_ops = { .get_settings = atl1e_get_settings, .set_settings = atl1e_set_settings, .get_drvinfo = atl1e_get_drvinfo, diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index d0bcb572d51..10c06b97001 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -2094,7 +2094,7 @@ static int atl2_nway_reset(struct net_device *netdev) return 0; } -static struct ethtool_ops atl2_ethtool_ops = { +static const struct ethtool_ops atl2_ethtool_ops = { .get_settings = atl2_get_settings, .set_settings = atl2_set_settings, .get_drvinfo = atl2_get_drvinfo, diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index beb13139923..6c45a2233d0 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -259,7 +259,7 @@ struct be_adapter { bool promiscuous; }; -extern struct ethtool_ops be_ethtool_ops; +extern const struct ethtool_ops be_ethtool_ops; #define drvr_stats(adapter) (&adapter->stats.drvr_stats) diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index c480c19200d..4ff3cc46540 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -332,7 +332,7 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) return status; } -struct ethtool_ops be_ethtool_ops = { +const struct ethtool_ops be_ethtool_ops = { .get_settings = be_get_settings, .get_drvinfo = be_get_drvinfo, .get_link = ethtool_op_get_link, diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index f580b21eabd..14bd3801f7d 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -491,7 +491,7 @@ static void bfin_mac_ethtool_getdrvinfo(struct net_device *dev, strcpy(info->bus_info, dev_name(&dev->dev)); } -static struct ethtool_ops bfin_mac_ethtool_ops = { +static const struct ethtool_ops bfin_mac_ethtool_ops = { .get_settings = bfin_mac_ethtool_getsettings, .set_settings = bfin_mac_ethtool_setsettings, .get_link = ethtool_op_get_link, diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index e2e50267cc6..20f0ed956df 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -10606,7 +10606,7 @@ static int bnx2x_phys_id(struct net_device *dev, u32 data) return 0; } -static struct ethtool_ops bnx2x_ethtool_ops = { +static const struct ethtool_ops bnx2x_ethtool_ops = { .get_settings = bnx2x_get_settings, .set_settings = bnx2x_set_settings, .get_drvinfo = bnx2x_get_drvinfo, diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 49912eb2a33..2ea036333db 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -256,7 +256,7 @@ static void enic_set_msglevel(struct net_device *netdev, u32 value) enic->msg_enable = value; } -static struct ethtool_ops enic_ethtool_ops = { +static const struct ethtool_ops enic_ethtool_ops = { .get_settings = enic_get_settings, .get_drvinfo = enic_get_drvinfo, .get_msglevel = enic_get_msglevel, diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 114ccab1f2b..d004c359244 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -2016,7 +2016,7 @@ static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data) } } -static struct ethtool_ops igb_ethtool_ops = { +static const struct ethtool_ops igb_ethtool_ops = { .get_settings = igb_get_settings, .set_settings = igb_set_settings, .get_drvinfo = igb_get_drvinfo, diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index 382c5532e6c..9f7b5d4172b 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -2186,7 +2186,7 @@ static int ipg_nway_reset(struct net_device *dev) return rc; } -static struct ethtool_ops ipg_ethtool_ops = { +static const struct ethtool_ops ipg_ethtool_ops = { .get_settings = ipg_get_settings, .set_settings = ipg_set_settings, .nway_reset = ipg_nway_reset, diff --git a/drivers/net/korina.c b/drivers/net/korina.c index 51ca54c8ec5..03199fa1000 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c @@ -743,7 +743,7 @@ static u32 netdev_get_link(struct net_device *dev) return mii_link_ok(&lp->mii_if); } -static struct ethtool_ops netdev_ethtool_ops = { +static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_settings = netdev_get_settings, .set_settings = netdev_set_settings, diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c index 6e74aa9eea4..99e954167fa 100644 --- a/drivers/net/ks8842.c +++ b/drivers/net/ks8842.c @@ -619,7 +619,7 @@ static const struct net_device_ops ks8842_netdev_ops = { .ndo_validate_addr = eth_validate_addr }; -static struct ethtool_ops ks8842_ethtool_ops = { +static const struct ethtool_ops ks8842_ethtool_ops = { .get_link = ethtool_op_get_link, }; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 01aaca99d29..fb65b427c69 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -1079,7 +1079,7 @@ static void macb_get_drvinfo(struct net_device *dev, strcpy(info->bus_info, dev_name(&bp->pdev->dev)); } -static struct ethtool_ops macb_ethtool_ops = { +static const struct ethtool_ops macb_ethtool_ops = { .get_settings = macb_get_settings, .set_settings = macb_set_settings, .get_drvinfo = macb_get_drvinfo, diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 449d3511628..224a7469131 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1410,6 +1410,6 @@ extern void netxen_change_ringparam(struct netxen_adapter *adapter); extern int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp); -extern struct ethtool_ops netxen_nic_ethtool_ops; +extern const struct ethtool_ops netxen_nic_ethtool_ops; #endif /* __NETXEN_NIC_H_ */ diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 3886135006e..e376a1c4eb0 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -963,7 +963,7 @@ static int netxen_nic_set_flags(struct net_device *netdev, u32 data) return 0; } -struct ethtool_ops netxen_nic_ethtool_ops = { +const struct ethtool_ops netxen_nic_ethtool_ops = { .get_settings = netxen_nic_get_settings, .set_settings = netxen_nic_set_settings, .get_drvinfo = netxen_nic_get_drvinfo, diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index a3932c9f340..b211613e9db 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -1346,7 +1346,7 @@ done: return status; } -static struct ethtool_ops gelic_ether_ethtool_ops = { +static const struct ethtool_ops gelic_ether_ethtool_ops = { .get_drvinfo = gelic_net_get_drvinfo, .get_settings = gelic_ether_get_settings, .get_link = ethtool_op_get_link, diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index 6932b08d746..227b141c4fb 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -2714,7 +2714,7 @@ static const struct net_device_ops gelic_wl_netdevice_ops = { #endif }; -static struct ethtool_ops gelic_wl_ethtool_ops = { +static const struct ethtool_ops gelic_wl_ethtool_ops = { .get_drvinfo = gelic_net_get_drvinfo, .get_link = gelic_wl_get_link, .get_tx_csum = ethtool_op_get_tx_csum, diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 997ea2a3d53..45018f283ff 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -731,7 +731,7 @@ static void efx_ethtool_get_pauseparam(struct net_device *net_dev, } -struct ethtool_ops efx_ethtool_ops = { +const struct ethtool_ops efx_ethtool_ops = { .get_settings = efx_ethtool_get_settings, .set_settings = efx_ethtool_set_settings, .get_drvinfo = efx_ethtool_get_drvinfo, diff --git a/drivers/net/sfc/ethtool.h b/drivers/net/sfc/ethtool.h index 3628e43df14..295ead40335 100644 --- a/drivers/net/sfc/ethtool.h +++ b/drivers/net/sfc/ethtool.h @@ -22,6 +22,6 @@ extern int efx_ethtool_get_settings(struct net_device *net_dev, extern int efx_ethtool_set_settings(struct net_device *net_dev, struct ethtool_cmd *ecmd); -extern struct ethtool_ops efx_ethtool_ops; +extern const struct ethtool_ops efx_ethtool_ops; #endif /* EFX_ETHTOOL_H */ diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 918d4c9e49b..ec9dfb251f3 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -2428,7 +2428,7 @@ static void bdx_get_ethtool_stats(struct net_device *netdev, */ static void bdx_ethtool_ops(struct net_device *netdev) { - static struct ethtool_ops bdx_ethtool_ops = { + static const struct ethtool_ops bdx_ethtool_ops = { .get_settings = bdx_get_settings, .get_drvinfo = bdx_get_drvinfo, .get_link = ethtool_op_get_link, diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 87b4a028991..6ce7f775bb7 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -731,7 +731,7 @@ static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) /* We need to override some ethtool_ops so we require our own structure so we don't interfere with other usbnet devices that may be connected at the same time. */ -static struct ethtool_ops ax88172_ethtool_ops = { +static const struct ethtool_ops ax88172_ethtool_ops = { .get_drvinfo = asix_get_drvinfo, .get_link = asix_get_link, .get_msglevel = usbnet_get_msglevel, @@ -873,7 +873,7 @@ out: return ret; } -static struct ethtool_ops ax88772_ethtool_ops = { +static const struct ethtool_ops ax88772_ethtool_ops = { .get_drvinfo = asix_get_drvinfo, .get_link = asix_get_link, .get_msglevel = usbnet_get_msglevel, diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index 0ffc0c6d03b..2bed6b087d1 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -698,7 +698,7 @@ static int catc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) return 0; } -static struct ethtool_ops ops = { +static const struct ethtool_ops ops = { .get_drvinfo = catc_get_drvinfo, .get_settings = catc_get_settings, .get_link = ethtool_op_get_link diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index 1d3730d6690..72470f77f55 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -356,7 +356,7 @@ static int dm9601_ioctl(struct net_device *net, struct ifreq *rq, int cmd) return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); } -static struct ethtool_ops dm9601_ethtool_ops = { +static const struct ethtool_ops dm9601_ethtool_ops = { .get_drvinfo = dm9601_get_drvinfo, .get_link = dm9601_get_link, .get_msglevel = usbnet_get_msglevel, diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 123f9b84dd2..3f9c92a2afc 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -829,7 +829,7 @@ static void hso_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info usb_make_path(odev->parent->usb, info->bus_info, sizeof info->bus_info); } -static struct ethtool_ops ops = { +static const struct ethtool_ops ops = { .get_drvinfo = hso_get_drvinfo, .get_link = ethtool_op_get_link }; diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index 7f397365b43..e2a39b9be96 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -778,7 +778,7 @@ static u32 kaweth_get_link(struct net_device *dev) return kaweth->linkstate; } -static struct ethtool_ops ops = { +static const struct ethtool_ops ops = { .get_drvinfo = kaweth_get_drvinfo, .get_link = kaweth_get_link }; diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index 7ae9afe99a4..10873d96b2d 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -449,7 +449,7 @@ static void mcs7830_get_regs(struct net_device *net, struct ethtool_regs *regs, mcs7830_get_reg(dev, 0, regs->len, data); } -static struct ethtool_ops mcs7830_ethtool_ops = { +static const struct ethtool_ops mcs7830_ethtool_ops = { .get_drvinfo = mcs7830_get_drvinfo, .get_regs_len = mcs7830_get_regs_len, .get_regs = mcs7830_get_regs, diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 7b935b84642..6fdaba8674b 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -1174,7 +1174,7 @@ static void pegasus_set_msglevel(struct net_device *dev, u32 v) pegasus->msg_enable = v; } -static struct ethtool_ops ops = { +static const struct ethtool_ops ops = { .get_drvinfo = pegasus_get_drvinfo, .get_settings = pegasus_get_settings, .set_settings = pegasus_set_settings, diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index d9f84f22fbc..b091e20ca16 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -865,7 +865,7 @@ static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *e return 0; } -static struct ethtool_ops ops = { +static const struct ethtool_ops ops = { .get_drvinfo = rtl8150_get_drvinfo, .get_settings = rtl8150_get_settings, .get_link = ethtool_op_get_link diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 09bd6351f64..938fb3530a7 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -625,7 +625,7 @@ static int smsc95xx_ethtool_set_tx_csum(struct net_device *netdev, u32 val) return smsc95xx_set_csums(dev); } -static struct ethtool_ops smsc95xx_ethtool_ops = { +static const struct ethtool_ops smsc95xx_ethtool_ops = { .get_link = usbnet_get_link, .nway_reset = usbnet_nway_reset, .get_drvinfo = usbnet_get_drvinfo, diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index d166e3385c6..24b36f79515 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -854,7 +854,7 @@ void usbnet_set_msglevel (struct net_device *net, u32 level) EXPORT_SYMBOL_GPL(usbnet_set_msglevel); /* drivers may override default ethtool_ops in their bind() routine */ -static struct ethtool_ops usbnet_ethtool_ops = { +static const struct ethtool_ops usbnet_ethtool_ops = { .get_settings = usbnet_get_settings, .set_settings = usbnet_set_settings, .get_link = usbnet_get_link, diff --git a/drivers/net/veth.c b/drivers/net/veth.c index d1941cdff62..ade5b344f75 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -129,7 +129,7 @@ static int veth_set_tx_csum(struct net_device *dev, u32 data) return 0; } -static struct ethtool_ops veth_ethtool_ops = { +static const struct ethtool_ops veth_ethtool_ops = { .get_settings = veth_get_settings, .get_drvinfo = veth_get_drvinfo, .get_link = ethtool_op_get_link, diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 51e9ce4907f..32266fb89c2 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -798,7 +798,7 @@ static void virtnet_vlan_rx_kill_vid(struct net_device *dev, u16 vid) dev_warn(&dev->dev, "Failed to kill VLAN ID %d.\n", vid); } -static struct ethtool_ops virtnet_ethtool_ops = { +static const struct ethtool_ops virtnet_ethtool_ops = { .set_tx_csum = virtnet_set_tx_csum, .set_sg = ethtool_op_set_sg, .set_tso = ethtool_op_set_tso, diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 578c6978358..d3b69a4b4b5 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -14,7 +14,7 @@ #include "defs.h" #include "hostcmd.h" -extern struct ethtool_ops lbs_ethtool_ops; +extern const struct ethtool_ops lbs_ethtool_ops; #define MAX_BSSID_PER_CHANNEL 16 diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index b118a35ec60..039b555e4d7 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -183,7 +183,7 @@ static int lbs_ethtool_set_wol(struct net_device *dev, return lbs_host_sleep_cfg(priv, criteria, (struct wol_config *)NULL); } -struct ethtool_ops lbs_ethtool_ops = { +const struct ethtool_ops lbs_ethtool_ops = { .get_drvinfo = lbs_ethtool_get_drvinfo, .get_eeprom = lbs_ethtool_get_eeprom, .get_eeprom_len = lbs_ethtool_get_eeprom_len, diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 3700c49d76c..baa051d5bfb 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -51,7 +51,7 @@ #include #include -static struct ethtool_ops xennet_ethtool_ops; +static const struct ethtool_ops xennet_ethtool_ops; struct netfront_cb { struct page *page; @@ -1627,7 +1627,7 @@ static void backend_changed(struct xenbus_device *dev, } } -static struct ethtool_ops xennet_ethtool_ops = +static const struct ethtool_ops xennet_ethtool_ops = { .set_tx_csum = ethtool_op_set_tx_csum, .set_sg = xennet_set_sg, diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 12ee7a35ca5..94b161121c2 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -863,7 +863,7 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev) return; } -static struct ethtool_ops qeth_l2_ethtool_ops = { +static const struct ethtool_ops qeth_l2_ethtool_ops = { .get_link = ethtool_op_get_link, .get_strings = qeth_core_get_strings, .get_ethtool_stats = qeth_core_get_ethtool_stats, @@ -872,7 +872,7 @@ static struct ethtool_ops qeth_l2_ethtool_ops = { .get_settings = qeth_core_ethtool_get_settings, }; -static struct ethtool_ops qeth_l2_osn_ops = { +static const struct ethtool_ops qeth_l2_osn_ops = { .get_strings = qeth_core_get_strings, .get_ethtool_stats = qeth_core_get_ethtool_stats, .get_stats_count = qeth_core_get_stats_count, diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index d9fabe30c0d..115b4a0dae6 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2946,7 +2946,7 @@ static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data) return 0; } -static struct ethtool_ops qeth_l3_ethtool_ops = { +static const struct ethtool_ops qeth_l3_ethtool_ops = { .get_link = ethtool_op_get_link, .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_hw_csum, diff --git a/drivers/staging/at76_usb/at76_usb.c b/drivers/staging/at76_usb/at76_usb.c index 7b8aa5edf42..c165c50c011 100644 --- a/drivers/staging/at76_usb/at76_usb.c +++ b/drivers/staging/at76_usb/at76_usb.c @@ -3396,7 +3396,7 @@ static u32 at76_ethtool_get_link(struct net_device *netdev) return priv->mac_state == MAC_CONNECTED; } -static struct ethtool_ops at76_ethtool_ops = { +static const struct ethtool_ops at76_ethtool_ops = { .get_drvinfo = at76_ethtool_get_drvinfo, .get_link = at76_ethtool_get_link, }; diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c index 93cab0a4892..42230e62a22 100644 --- a/drivers/staging/octeon/ethernet-mdio.c +++ b/drivers/staging/octeon/ethernet-mdio.c @@ -170,7 +170,7 @@ static u32 cvm_oct_get_link(struct net_device *dev) return ret; } -struct ethtool_ops cvm_oct_ethtool_ops = { +struct const ethtool_ops cvm_oct_ethtool_ops = { .get_drvinfo = cvm_oct_get_drvinfo, .get_settings = cvm_oct_get_settings, .set_settings = cvm_oct_set_settings, diff --git a/drivers/staging/octeon/ethernet-mdio.h b/drivers/staging/octeon/ethernet-mdio.h index 6314141e5ef..b3328aeec2d 100644 --- a/drivers/staging/octeon/ethernet-mdio.h +++ b/drivers/staging/octeon/ethernet-mdio.h @@ -41,6 +41,6 @@ #include #endif /* CONFIG_XFRM */ -extern struct ethtool_ops cvm_oct_ethtool_ops; +extern const struct ethtool_ops cvm_oct_ethtool_ops; int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); int cvm_oct_mdio_setup_device(struct net_device *dev); diff --git a/drivers/staging/sxg/sxg.h b/drivers/staging/sxg/sxg.h index f07aa708d86..110096a5c52 100644 --- a/drivers/staging/sxg/sxg.h +++ b/drivers/staging/sxg/sxg.h @@ -782,6 +782,6 @@ struct slic_crash_info { #define SIOCSLICSETINTAGG (SIOCDEVPRIVATE+10) #define SIOCSLICTRACEDUMP (SIOCDEVPRIVATE+11) -extern struct ethtool_ops sxg_nic_ethtool_ops; +extern const struct ethtool_ops sxg_nic_ethtool_ops; #define SXG_COMPLETE_SLOW_SEND_LIMIT 128 #endif /* __SXG_DRIVER_H__ */ diff --git a/drivers/staging/sxg/sxg_ethtool.c b/drivers/staging/sxg/sxg_ethtool.c index ad89cb829b8..f5a0706478d 100644 --- a/drivers/staging/sxg/sxg_ethtool.c +++ b/drivers/staging/sxg/sxg_ethtool.c @@ -300,7 +300,7 @@ static int sxg_nic_get_eeprom(struct net_device *netdev, return 0; } -struct ethtool_ops sxg_nic_ethtool_ops = { +const struct ethtool_ops sxg_nic_ethtool_ops = { .get_settings = sxg_nic_get_settings, .set_settings = sxg_nic_set_settings, .get_drvinfo = sxg_nic_get_drvinfo, diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index dc3ebd1e68c..c6652195391 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -181,7 +181,7 @@ static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p) * - ... probably more ethtool ops */ -static struct ethtool_ops ops = { +static const struct ethtool_ops ops = { .get_drvinfo = eth_get_drvinfo, .get_link = ethtool_op_get_link, }; -- cgit v1.2.3-18-g5258 From 7064d2092df5cbff289457424969292bc4062df4 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 26 Aug 2009 09:58:24 +0100 Subject: ARM: 5685/1: Make MMCI driver compile without gpiolib The recent addition of optional gpiolib support to check if a card was inserted or write protected was really not optional. It needs this ifdef to become optional so that U300 compiles, for example. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 5eb86a8c943..a923ee27c09 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -619,6 +619,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) writel(0, host->base + MMCIMASK1); writel(0xfff, host->base + MMCICLEAR); +#ifdef CONFIG_GPIOLIB if (gpio_is_valid(plat->gpio_cd)) { ret = gpio_request(plat->gpio_cd, DRIVER_NAME " (cd)"); if (ret == 0) @@ -637,6 +638,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) else if (ret != -ENOSYS) goto err_gpio_wp; } +#endif ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); if (ret) -- cgit v1.2.3-18-g5258 From 8afe0b96b36bb967a00658003736ffa97967ee80 Mon Sep 17 00:00:00 2001 From: Leo Chen Date: Tue, 28 Jul 2009 23:34:59 +0100 Subject: ARM: 5625/1: fix hard coded 4K resource size in amba bus detection This patch modifies the amba bus detection logic in the kernel to detect the AMBA devices using the calculated resource size information rather than the hard coded 4K size. It also calculates the resource size when request mem region and release mem region. Signed-off-by: Leo Chen Signed-off-by: Russell King --- drivers/amba/bus.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 3d763fdf99b..768d973d0de 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -204,6 +204,7 @@ static void amba_device_release(struct device *dev) int amba_device_register(struct amba_device *dev, struct resource *parent) { u32 pid, cid; + u32 size; void __iomem *tmp; int i, ret; @@ -219,16 +220,25 @@ int amba_device_register(struct amba_device *dev, struct resource *parent) if (ret) goto err_out; - tmp = ioremap(dev->res.start, SZ_4K); + /* + * Dynamically calculate the size of the resource + * and use this for iomap + */ + size = resource_size(&dev->res); + tmp = ioremap(dev->res.start, size); if (!tmp) { ret = -ENOMEM; goto err_release; } + /* + * Read pid and cid based on size of resource + * they are located at end of region + */ for (pid = 0, i = 0; i < 4; i++) - pid |= (readl(tmp + 0xfe0 + 4 * i) & 255) << (i * 8); + pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) << (i * 8); for (cid = 0, i = 0; i < 4; i++) - cid |= (readl(tmp + 0xff0 + 4 * i) & 255) << (i * 8); + cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) << (i * 8); iounmap(tmp); @@ -343,11 +353,14 @@ amba_find_device(const char *busid, struct device *parent, unsigned int id, int amba_request_regions(struct amba_device *dev, const char *name) { int ret = 0; + u32 size; if (!name) name = dev->dev.driver->name; - if (!request_mem_region(dev->res.start, SZ_4K, name)) + size = resource_size(&dev->res); + + if (!request_mem_region(dev->res.start, size, name)) ret = -EBUSY; return ret; @@ -361,7 +374,10 @@ int amba_request_regions(struct amba_device *dev, const char *name) */ void amba_release_regions(struct amba_device *dev) { - release_mem_region(dev->res.start, SZ_4K); + u32 size; + + size = resource_size(&dev->res); + release_mem_region(dev->res.start, size); } EXPORT_SYMBOL(amba_driver_register); -- cgit v1.2.3-18-g5258 From b736b89f8a001cb73f020ca90a6fac77861cddf6 Mon Sep 17 00:00:00 2001 From: Leo Chen Date: Tue, 28 Jul 2009 23:43:33 +0100 Subject: ARM: 5626/1: add suspend/resume functions to amba-pl011 serial driver Add suspend/resume functions to the AMBA pl011 serial driver. Signed-off-by: Leo Chen Signed-off-by: Russell King --- drivers/serial/amba-pl011.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index bf82e28770a..72ba0c6d355 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -826,6 +826,28 @@ static int pl011_remove(struct amba_device *dev) return 0; } +#ifdef CONFIG_PM +static int pl011_suspend(struct amba_device *dev, pm_message_t state) +{ + struct uart_amba_port *uap = amba_get_drvdata(dev); + + if (!uap) + return -EINVAL; + + return uart_suspend_port(&amba_reg, &uap->port); +} + +static int pl011_resume(struct amba_device *dev) +{ + struct uart_amba_port *uap = amba_get_drvdata(dev); + + if (!uap) + return -EINVAL; + + return uart_resume_port(&amba_reg, &uap->port); +} +#endif + static struct amba_id pl011_ids[] __initdata = { { .id = 0x00041011, @@ -847,6 +869,10 @@ static struct amba_driver pl011_driver = { .id_table = pl011_ids, .probe = pl011_probe, .remove = pl011_remove, +#ifdef CONFIG_PM + .suspend = pl011_suspend, + .resume = pl011_resume, +#endif }; static int __init pl011_init(void) -- cgit v1.2.3-18-g5258 From 35c9221acb133ecc9abd701a1fb6fa909d177a77 Mon Sep 17 00:00:00 2001 From: wanzongshun Date: Fri, 21 Aug 2009 07:07:46 +0100 Subject: ARM: 5682/1: Add cpu.c and dev.c and modify some files of w90p910 platform Add the cpu.c and dev.c and modify w90p910 platform to apply to use the common API(provided by cpu.c and dev.c) at the same time, I renamed all w90x900 to nuc900 in every c file of w90x900 platform and touchscreen's driver name. Signed-off-by: Wan ZongShun Signed-off-by: Russell King --- drivers/input/touchscreen/w90p910_ts.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c index 6071f588257..937dfe4e9b1 100644 --- a/drivers/input/touchscreen/w90p910_ts.c +++ b/drivers/input/touchscreen/w90p910_ts.c @@ -326,7 +326,7 @@ static struct platform_driver w90x900ts_driver = { .probe = w90x900ts_probe, .remove = __devexit_p(w90x900ts_remove), .driver = { - .name = "w90x900-ts", + .name = "nuc900-ts", .owner = THIS_MODULE, }, }; @@ -347,4 +347,4 @@ module_exit(w90x900ts_exit); MODULE_AUTHOR("Wan ZongShun "); MODULE_DESCRIPTION("w90p910 touch screen driver!"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:w90p910-ts"); +MODULE_ALIAS("platform:nuc900-ts"); -- cgit v1.2.3-18-g5258 From c47a830c08a26a7c210ae16a0ffe3f56ba86ea69 Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Wed, 2 Sep 2009 17:07:29 +0100 Subject: ARM: 5688/1: ks8695_serial: disable_irq() lockup disable_irq() cannot be called from interrupt context without self imposed deadlock. This was happening in ks8695uart_stop_tx(). Signed-off-by: Dick Hollenbeck Signed-off-by: Russell King --- drivers/serial/serial_ks8695.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/serial/serial_ks8695.c b/drivers/serial/serial_ks8695.c index e0665630e4d..52db5cc3f90 100644 --- a/drivers/serial/serial_ks8695.c +++ b/drivers/serial/serial_ks8695.c @@ -110,7 +110,11 @@ static struct console ks8695_console; static void ks8695uart_stop_tx(struct uart_port *port) { if (tx_enabled(port)) { - disable_irq(KS8695_IRQ_UART_TX); + /* use disable_irq_nosync() and not disable_irq() to avoid self + * imposed deadlock by not waiting for irq handler to end, + * since this ks8695uart_stop_tx() is called from interrupt context. + */ + disable_irq_nosync(KS8695_IRQ_UART_TX); tx_enable(port, 0); } } -- cgit v1.2.3-18-g5258 From bcc24fb42585dc9f490cf7789a917358414bdab5 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 31 Aug 2009 10:24:31 -0700 Subject: drm/i915: increase default latency constant (v2 w/comment) Some i915/i945 platforms have a fairly high memory latency in certain situations, so increase our constant a bit to avoid FIFO underruns. The effect should be positive on other platforms as well; we'll have a bit more insurance against a busy memory subsystem due to the extra FIFO entries. Fixes fdo bug #23368. Needed for 2.6.31. Tested-by: Sven Arvidsson Tested-by: Chris Wilson Signed-off-by: Jesse Barnes Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3fadb535885..748ed50c55c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2005,7 +2005,21 @@ static void igd_enable_cxsr(struct drm_device *dev, unsigned long clock, return; } -const static int latency_ns = 3000; /* default for non-igd platforms */ +/* + * Latency for FIFO fetches is dependent on several factors: + * - memory configuration (speed, channels) + * - chipset + * - current MCH state + * It can be fairly high in some situations, so here we assume a fairly + * pessimal value. It's a tradeoff between extra memory fetches (if we + * set this value too high, the FIFO will fetch frequently to stay full) + * and power consumption (set it too low to save power and we might see + * FIFO underruns and display "flicker"). + * + * A value of 5us seems to be a good balance; safe for very low end + * platforms but not overly aggressive on lower latency configs. + */ +const static int latency_ns = 5000; static int intel_get_fifo_size(struct drm_device *dev, int plane) { -- cgit v1.2.3-18-g5258 From 58c2fb647a3cf70a90d7b33a3f2a8396a20a0bc4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 1 Sep 2009 12:02:39 +0100 Subject: drm/i915: Unref old_obj on get_fence_reg() error path Remember to release the local reference if we fail to wait on the rendering. (Also whilst in the vicinity add some whitespace so that the phasing of the operations is clearer.) Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0c07a755b3a..7edb5b9d579 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2267,8 +2267,6 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj) fence_list) { old_obj = old_obj_priv->obj; - reg = &dev_priv->fence_regs[old_obj_priv->fence_reg]; - if (old_obj_priv->pin_count) continue; @@ -2290,8 +2288,11 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj) */ i915_gem_object_flush_gpu_write_domain(old_obj); ret = i915_gem_object_wait_rendering(old_obj); - if (ret != 0) + if (ret != 0) { + drm_gem_object_unreference(old_obj); return ret; + } + break; } @@ -2299,10 +2300,14 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj) * Zap this virtual mapping so we can set up a fence again * for this object next time we need it. */ - i915_gem_release_mmap(reg->obj); + i915_gem_release_mmap(old_obj); + i = old_obj_priv->fence_reg; + reg = &dev_priv->fence_regs[i]; + old_obj_priv->fence_reg = I915_FENCE_REG_NONE; list_del_init(&old_obj_priv->fence_list); + drm_gem_object_unreference(old_obj); } -- cgit v1.2.3-18-g5258 From 07fb6111e7af5fac6b6076e2658d0e32b67f713b Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Thu, 13 Aug 2009 18:57:29 +0800 Subject: agp/intel: support for new chip variant of IGDNG mobile New variant of IGDNG mobile chip has new host bridge id. [anholt: Note that this new PCI ID doesn't impact the DRM, which doesn't care about the PCI ID of the bridge] Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt --- drivers/char/agp/intel-agp.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 8c9d50db5c3..c5855779058 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -49,6 +49,7 @@ #define PCI_DEVICE_ID_INTEL_IGDNG_D_HB 0x0040 #define PCI_DEVICE_ID_INTEL_IGDNG_D_IG 0x0042 #define PCI_DEVICE_ID_INTEL_IGDNG_M_HB 0x0044 +#define PCI_DEVICE_ID_INTEL_IGDNG_MA_HB 0x0062 #define PCI_DEVICE_ID_INTEL_IGDNG_M_IG 0x0046 /* cover 915 and 945 variants */ @@ -81,7 +82,8 @@ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_GM45_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G41_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_D_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_M_HB) + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_M_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_MA_HB) extern int agp_memory_reserved; @@ -1216,6 +1218,7 @@ static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size) case PCI_DEVICE_ID_INTEL_G41_HB: case PCI_DEVICE_ID_INTEL_IGDNG_D_HB: case PCI_DEVICE_ID_INTEL_IGDNG_M_HB: + case PCI_DEVICE_ID_INTEL_IGDNG_MA_HB: *gtt_offset = *gtt_size = MB(2); break; default: @@ -2195,6 +2198,8 @@ static const struct intel_driver_description { "IGDNG/D", NULL, &intel_i965_driver }, { PCI_DEVICE_ID_INTEL_IGDNG_M_HB, PCI_DEVICE_ID_INTEL_IGDNG_M_IG, 0, "IGDNG/M", NULL, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_IGDNG_MA_HB, PCI_DEVICE_ID_INTEL_IGDNG_M_IG, 0, + "IGDNG/MA", NULL, &intel_i965_driver }, { 0, 0, 0, NULL, NULL, NULL } }; @@ -2398,6 +2403,7 @@ static struct pci_device_id agp_intel_pci_table[] = { ID(PCI_DEVICE_ID_INTEL_G41_HB), ID(PCI_DEVICE_ID_INTEL_IGDNG_D_HB), ID(PCI_DEVICE_ID_INTEL_IGDNG_M_HB), + ID(PCI_DEVICE_ID_INTEL_IGDNG_MA_HB), { } }; -- cgit v1.2.3-18-g5258 From 44175272ba5f08e842877ef230ff4ed21cf9ec39 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 1 Sep 2009 08:22:40 -0700 Subject: wireless: update top level wireless driver entry Change it to a menuconfig to give it some documentation, to refer users to our wireless wiki for extra resources and documentation. It seems our wiki is still obscure to some. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 623897f2b0c..a8871a84d87 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -2,8 +2,17 @@ # Wireless LAN device configuration # -menu "Wireless LAN" +menuconfig WLAN + bool "Wireless LAN" depends on !S390 + ---help--- + This section contains all the pre 802.11 and 802.11 wireless + device drivers. For a complete list of drivers and documentation + on them refer to the wireless wiki: + + http://wireless.kernel.org/en/users/Drivers + +if WLAN menuconfig WLAN_PRE80211 bool "Wireless LAN (pre-802.11)" @@ -505,4 +514,4 @@ source "drivers/net/wireless/orinoco/Kconfig" source "drivers/net/wireless/wl12xx/Kconfig" source "drivers/net/wireless/iwmc3200wifi/Kconfig" -endmenu +endif # WLAN -- cgit v1.2.3-18-g5258 From d0bec34293bb0b8dddc26d25bd46a6631d6b3ec3 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Wed, 2 Sep 2009 15:50:55 +0530 Subject: ath9k: Reconfigure beacon timers after the scan is completed. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index efee193801d..c2efdf2d72d 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2773,6 +2773,7 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) sc->sc_flags &= ~SC_OP_SCANNING; sc->sc_flags |= SC_OP_FULL_RESET; spin_unlock_bh(&sc->ani_lock); + ath_beacon_config(sc, NULL); mutex_unlock(&sc->mutex); } -- cgit v1.2.3-18-g5258 From 451f14439847db302e5104c44458b2dbb4b1829d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 31 Aug 2009 06:34:50 +0000 Subject: drivers: Kill now superfluous ->last_rx stores The generic packet receive code takes care of setting netdev->last_rx when necessary, for the sake of the bonding ARP monitor. Signed-off-by: Eric Dumazet Acked-by: Neil Horman Signed-off-by: David S. Miller --- drivers/firewire/net.c | 2 -- drivers/ieee1394/eth1394.c | 1 - drivers/infiniband/hw/amso1100/c2.c | 1 - drivers/infiniband/hw/nes/nes_hw.c | 2 +- drivers/infiniband/ulp/ipoib/ipoib_cm.c | 1 - drivers/infiniband/ulp/ipoib/ipoib_ib.c | 1 - drivers/misc/sgi-xp/xpnet.c | 1 - drivers/net/arm/ks8695net.c | 1 - drivers/net/arm/w90p910_ether.c | 1 - drivers/net/atl1c/atl1c_main.c | 1 - drivers/net/benet/be_main.c | 2 -- drivers/net/can/dev.c | 1 - drivers/net/can/sja1000/sja1000.c | 2 -- drivers/net/davinci_emac.c | 1 - drivers/net/ethoc.c | 1 - drivers/net/igbvf/netdev.c | 4 ---- drivers/net/smsc911x.c | 1 - drivers/net/smsc9420.c | 1 - drivers/net/vxge/vxge-main.c | 2 -- drivers/net/wireless/b43legacy/xmit.c | 1 - drivers/net/xilinx_emaclite.c | 1 - drivers/s390/net/ctcm_main.c | 1 - drivers/s390/net/netiucv.c | 1 - drivers/s390/net/qeth_l2_main.c | 1 - drivers/s390/net/qeth_l3_main.c | 1 - 25 files changed, 1 insertion(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 84edc8b84c6..cbaf420c36c 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -663,8 +663,6 @@ static int fwnet_finish_incoming_packet(struct net_device *net, if (netif_queue_stopped(net)) netif_wake_queue(net); - net->last_rx = jiffies; - return 0; } diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 3a62c4c2d41..a4e9dcb6d4a 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -1301,7 +1301,6 @@ static void ether1394_iso(struct hpsb_iso *iso) hpsb_iso_recv_release_packets(iso, i); - dev->last_rx = jiffies; } /****************************************** diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c index 0cfbb6d2f76..8c5d2842fbb 100644 --- a/drivers/infiniband/hw/amso1100/c2.c +++ b/drivers/infiniband/hw/amso1100/c2.c @@ -530,7 +530,6 @@ static void c2_rx_interrupt(struct net_device *netdev) netif_rx(skb); - netdev->last_rx = jiffies; netdev->stats.rx_packets++; netdev->stats.rx_bytes += buflen; } diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 4a84d02ece0..97d4c2a33ed 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -2741,7 +2741,7 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) } skip_rx_indicate0: - nesvnic->netdev->last_rx = jiffies; + ; /* nesvnic->netstats.rx_packets++; */ /* nesvnic->netstats.rx_bytes += rx_pkt_size; */ } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 181b1f32325..986f07fb3ec 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -663,7 +663,6 @@ copied: skb_reset_mac_header(skb); skb_pull(skb, IPOIB_ENCAP_LEN); - dev->last_rx = jiffies; ++dev->stats.rx_packets; dev->stats.rx_bytes += skb->len; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index e7e5adf84e8..c9dcb2064f2 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -277,7 +277,6 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) skb_reset_mac_header(skb); skb_pull(skb, IPOIB_ENCAP_LEN); - dev->last_rx = jiffies; ++dev->stats.rx_packets; dev->stats.rx_bytes += skb->len; diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 212da9af1ce..16f0abda142 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -240,7 +240,6 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) (void *)skb->head, (void *)skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), skb->len); - xpnet_device->last_rx = jiffies; xpnet_device->stats.rx_packets++; xpnet_device->stats.rx_bytes += skb->len + ETH_HLEN; diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c index 4f702d52606..2a7b7745cc5 100644 --- a/drivers/net/arm/ks8695net.c +++ b/drivers/net/arm/ks8695net.c @@ -467,7 +467,6 @@ ks8695_rx_irq(int irq, void *dev_id) netif_rx(skb); /* Record stats */ - ndev->last_rx = jiffies; ndev->stats.rx_packets++; ndev->stats.rx_bytes += pktlen; goto rx_finished; diff --git a/drivers/net/arm/w90p910_ether.c b/drivers/net/arm/w90p910_ether.c index 3a0948f02b4..25e2627eb11 100644 --- a/drivers/net/arm/w90p910_ether.c +++ b/drivers/net/arm/w90p910_ether.c @@ -777,7 +777,6 @@ static void netdev_rx(struct net_device *dev) rxbd = ðer->rdesc->desclist[ether->cur_rx]; - dev->last_rx = jiffies; } while (1); } diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index bf7cc83e983..e46bf923869 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -1740,7 +1740,6 @@ rrs_checked: } else netif_receive_skb(skb); - netdev->last_rx = jiffies; (*work_done)++; count++; } diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index e19fe1dcd14..bac85f95039 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -775,8 +775,6 @@ static void be_rx_compl_process(struct be_adapter *adapter, netif_receive_skb(skb); } - adapter->netdev->last_rx = jiffies; - return; } diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index e1a4f821423..1d29082d94a 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -357,7 +357,6 @@ void can_restart(unsigned long data) netif_rx(skb); - dev->last_rx = jiffies; stats->rx_packets++; stats->rx_bytes += cf->can_dlc; diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 9ce3ddac4e9..fd7fa716a6c 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -340,7 +340,6 @@ static void sja1000_rx(struct net_device *dev) netif_rx(skb); - dev->last_rx = jiffies; stats->rx_packets++; stats->rx_bytes += dlc; } @@ -455,7 +454,6 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) netif_rx(skb); - dev->last_rx = jiffies; stats->rx_packets++; stats->rx_bytes += cf->can_dlc; diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 5e6652b8728..d465eaa796c 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -1920,7 +1920,6 @@ static int emac_net_rx_cb(struct emac_priv *priv, skb_put(p_skb, net_pkt_list->pkt_length); EMAC_CACHE_INVALIDATE((unsigned long)p_skb->data, p_skb->len); p_skb->protocol = eth_type_trans(p_skb, priv->ndev); - p_skb->dev->last_rx = jiffies; netif_receive_skb(p_skb); priv->net_dev_stats.rx_bytes += net_pkt_list->pkt_length; priv->net_dev_stats.rx_packets++; diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index b871aefed9c..b7311bc0025 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -404,7 +404,6 @@ static int ethoc_rx(struct net_device *dev, int limit) void *src = priv->membase + bd.addr; memcpy_fromio(skb_put(skb, size), src, size); skb->protocol = eth_type_trans(skb, dev); - dev->last_rx = jiffies; priv->stats.rx_packets++; priv->stats.rx_bytes += size; netif_receive_skb(skb); diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index dadb78229ad..91024a3cdad 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -96,8 +96,6 @@ static void igbvf_receive_skb(struct igbvf_adapter *adapter, E1000_RXD_SPC_VLAN_MASK); else netif_receive_skb(skb); - - netdev->last_rx = jiffies; } static inline void igbvf_rx_checksum_adv(struct igbvf_adapter *adapter, @@ -342,8 +340,6 @@ send_up: igbvf_receive_skb(adapter, netdev, skb, staterr, rx_desc->wb.upper.vlan); - netdev->last_rx = jiffies; - next_desc: rx_desc->wb.upper.status_error = 0; diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index c2667855a00..ccdd196f529 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -1047,7 +1047,6 @@ static int smsc911x_poll(struct napi_struct *napi, int budget) /* Update counters */ dev->stats.rx_packets++; dev->stats.rx_bytes += (pktlength - 4); - dev->last_rx = jiffies; } /* Return total received packets */ diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c index 514311d67b3..b4909a2dec6 100644 --- a/drivers/net/smsc9420.c +++ b/drivers/net/smsc9420.c @@ -817,7 +817,6 @@ static void smsc9420_rx_handoff(struct smsc9420_pdata *pd, const int index, skb->protocol = eth_type_trans(skb, dev); netif_receive_skb(skb); - dev->last_rx = jiffies; } static int smsc9420_alloc_rx_buffer(struct smsc9420_pdata *pd, int index) diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 41dccba50c4..b378037a29b 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -588,8 +588,6 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, if (first_dtr) vxge_hw_ring_rxd_post_post_wmb(ringh, first_dtr); - dev->last_rx = jiffies; - vxge_debug_entryexit(VXGE_TRACE, "%s:%d Exiting...", __func__, __LINE__); diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index f79cee82601..103f3c9e7f5 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -590,7 +590,6 @@ void b43legacy_rx(struct b43legacy_wldev *dev, chanstat); } - dev->stats.last_rx = jiffies; memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); ieee80211_rx_irqsafe(dev->wl->hw, skb); diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c index 7e05b40ae36..dc22782633a 100644 --- a/drivers/net/xilinx_emaclite.c +++ b/drivers/net/xilinx_emaclite.c @@ -587,7 +587,6 @@ static void xemaclite_rx_handler(struct net_device *dev) dev->stats.rx_packets++; dev->stats.rx_bytes += len; - dev->last_rx = jiffies; netif_rx(skb); /* Send the packet upstream */ } diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 38b5079f159..c5b83874500 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -164,7 +164,6 @@ void ctcm_unpack_skb(struct channel *ch, struct sk_buff *pskb) priv->stats.rx_packets++; priv->stats.rx_bytes += skblen; netif_rx_ni(skb); - dev->last_rx = jiffies; if (len > 0) { skb_pull(pskb, header->length); if (skb_tailroom(pskb) < LL_HEADER_LENGTH) { diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index bb1183a2ed6..271c4a82e84 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -676,7 +676,6 @@ static void netiucv_unpack_skb(struct iucv_connection *conn, * we must use netif_rx_ni() instead of netif_rx() */ netif_rx_ni(skb); - dev->last_rx = jiffies; skb_pull(pskb, header->next); skb_put(pskb, NETIUCV_HDRLEN); } diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 94b161121c2..f4f3ca1393b 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -449,7 +449,6 @@ static void qeth_l2_process_inbound_buffer(struct qeth_card *card, QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN); continue; } - card->dev->last_rx = jiffies; card->stats.rx_packets++; card->stats.rx_bytes += len; } diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 115b4a0dae6..073b6d35491 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1987,7 +1987,6 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card, continue; } - card->dev->last_rx = jiffies; card->stats.rx_packets++; card->stats.rx_bytes += len; } -- cgit v1.2.3-18-g5258 From ab08999d6029bb2c79c16be5405d63d2bedbdfea Mon Sep 17 00:00:00 2001 From: roel kluin Date: Tue, 1 Sep 2009 06:24:53 +0000 Subject: WARNING: some request_irq() failures ignored in el2_open() Request_irq() may fail in different ways, handle accordingly. Signed-off-by: Roel Kluin Signed-off-by: David S. Miller --- drivers/net/3c503.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index 134638a9759..81c148a59ad 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -383,7 +383,7 @@ out: static int el2_open(struct net_device *dev) { - int retval = -EAGAIN; + int retval; if (dev->irq < 2) { int irqlist[] = {5, 9, 3, 4, 0}; @@ -391,7 +391,8 @@ el2_open(struct net_device *dev) outb(EGACFR_NORM, E33G_GACFR); /* Enable RAM and interrupts. */ do { - if (request_irq (*irqp, NULL, 0, "bogus", dev) != -EBUSY) { + retval = request_irq(*irqp, NULL, 0, "bogus", dev); + if (retval >= 0) { /* Twinkle the interrupt, and check if it's seen. */ unsigned long cookie = probe_irq_on(); outb_p(0x04 << ((*irqp == 9) ? 2 : *irqp), E33G_IDCFR); @@ -400,11 +401,14 @@ el2_open(struct net_device *dev) && ((retval = request_irq(dev->irq = *irqp, eip_interrupt, 0, dev->name, dev)) == 0)) break; + } else { + if (retval != -EBUSY) + return reval; } } while (*++irqp); if (*irqp == 0) { outb(EGACFR_IRQOFF, E33G_GACFR); /* disable interrupts. */ - return retval; + return -EAGAIN; } } else { if ((retval = request_irq(dev->irq, eip_interrupt, 0, dev->name, dev))) { -- cgit v1.2.3-18-g5258 From 3eb0027594e25f5947f074ae53fea30c15c5a7f6 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 2 Sep 2009 23:09:29 -0700 Subject: NET: Fix possible corruption in bpqether driver The bpq ether driver is modifying the data art of the skb by first dropping the KISS byte (a command byte for the radio) then prepending the length + 4 of the remaining AX.25 packet to be transmitted as a little endian 16-bit number. If the high byte of the length has a different value than the dropped KISS byte users of clones of the skb may observe this as corruption. This was observed with by running listen(8) -a which uses a packet socket which clones transmit packets. The corruption will then typically be displayed for as a KISS "TX Delay" command for AX.25 packets in the range of 252..508 bytes or any other KISS command for yet larger packets. Fixed by using skb_cow to create a private copy should the skb be cloned. Using skb_cow also allows us to cleanup the old logic to ensure sufficient headroom in the skb. While at it, replace a return of 0 from bpq_xmit with the proper constant NETDEV_TX_OK which is now being used everywhere else in this function. Affected: all 2.2, 2.4 and 2.6 kernels. Signed-off-by: Ralf Baechle Reported-by: Jann Traschewski Signed-off-by: David S. Miller --- drivers/net/hamradio/bpqether.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 3c7cc7f4580..fe893c91a01 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -249,7 +249,6 @@ drop: */ static netdev_tx_t bpq_xmit(struct sk_buff *skb, struct net_device *dev) { - struct sk_buff *newskb; unsigned char *ptr; struct bpqdev *bpq; int size; @@ -263,28 +262,23 @@ static netdev_tx_t bpq_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } - skb_pull(skb, 1); + skb_pull(skb, 1); /* Drop KISS byte */ size = skb->len; /* - * The AX.25 code leaves enough room for the ethernet header, but - * sendto() does not. + * We're about to mess with the skb which may still shared with the + * generic networking code so unshare and ensure it's got enough + * space for the BPQ headers. */ - if (skb_headroom(skb) < AX25_BPQ_HEADER_LEN) { /* Ough! */ - if ((newskb = skb_realloc_headroom(skb, AX25_BPQ_HEADER_LEN)) == NULL) { - printk(KERN_WARNING "bpqether: out of memory\n"); - kfree_skb(skb); - return NETDEV_TX_OK; - } - - if (skb->sk != NULL) - skb_set_owner_w(newskb, skb->sk); - + if (skb_cow(skb, AX25_BPQ_HEADER_LEN)) { + if (net_ratelimit()) + pr_err("bpqether: out of memory\n"); kfree_skb(skb); - skb = newskb; + + return NETDEV_TX_OK; } - ptr = skb_push(skb, 2); + ptr = skb_push(skb, 2); /* Make space for length */ *ptr++ = (size + 5) % 256; *ptr++ = (size + 5) / 256; -- cgit v1.2.3-18-g5258 From 84177a20799072c65a69b62571660d4d9780823c Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 1 Sep 2009 23:14:15 +0000 Subject: fec: fix recursive locking of mii_lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mii_discover_phy is only called by fec_enet_mii (via mip->mii_func). So &fep->mii_lock is already held and mii_discover_phy must not call mii_queue which locks &fep->mii_lock, too. This was noticed by lockdep: ============================================= [ INFO: possible recursive locking detected ] 2.6.31-rc8-00038-g37d0892 #109 --------------------------------------------- swapper/1 is trying to acquire lock: (&fep->mii_lock){-.....}, at: [] mii_queue+0x2c/0xcc but task is already holding lock: (&fep->mii_lock){-.....}, at: [] fec_enet_interrupt+0x78/0x460 other info that might help us debug this: 2 locks held by swapper/1: #0: (rtnl_mutex){+.+.+.}, at: [] rtnl_lock+0x18/0x20 #1: (&fep->mii_lock){-.....}, at: [] fec_enet_interrupt+0x78/0x460 stack backtrace: Backtrace: [] (dump_backtrace+0x0/0x108) from [] (dump_stack+0x18/0x1c) r6:c781d118 r5:c03e41d8 r4:00000001 [] (dump_stack+0x0/0x1c) from [] (__lock_acquire+0x1a20/0x1a88) [] (__lock_acquire+0x0/0x1a88) from [] (lock_acquire+0x60/0x74) [] (lock_acquire+0x0/0x74) from [] (_spin_lock_irqsave+0x54/0x68) r7:60000093 r6:c01569f8 r5:c785e468 r4:00000000 [] (_spin_lock_irqsave+0x0/0x68) from [] (mii_queue+0x2c/0xcc) r7:c785e468 r6:c0156b24 r5:600a0000 r4:c785e000 [] (mii_queue+0x0/0xcc) from [] (mii_discover_phy+0x54/0xa8) r8:00000002 r7:00000032 r6:c785e000 r5:c785e360 r4:c785e000 [] (mii_discover_phy+0x0/0xa8) from [] (fec_enet_interrupt+0xa4/0x460) r5:c785e360 r4:c077a170 [] (fec_enet_interrupt+0x0/0x460) from [] (handle_IRQ_event+0x48/0x120) [] (handle_IRQ_event+0x0/0x120) from [] (handle_level_irq+0x94/0x11c) ... Signed-off-by: Uwe Kleine-König Cc: Greg Ungerer Cc: Ben Hutchings Cc: Patrick McHardy Cc: Sascha Hauer Cc: Matt Waddel Cc: netdev@vger.kernel.org Cc: Tim Sander Acked-by: Greg Ungerer Signed-off-by: David S. Miller --- drivers/net/fec.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 967ad01b192..e730da26d29 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -637,16 +637,15 @@ unlock: } static int -mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_device *)) +mii_queue_unlocked(struct net_device *dev, int regval, + void (*func)(uint, struct net_device *)) { struct fec_enet_private *fep; - unsigned long flags; mii_list_t *mip; int retval; /* Add PHY address to register command */ fep = netdev_priv(dev); - spin_lock_irqsave(&fep->mii_lock, flags); regval |= fep->phy_addr << 23; retval = 0; @@ -667,6 +666,19 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi retval = 1; } + return retval; +} + +static int +mii_queue(struct net_device *dev, int regval, + void (*func)(uint, struct net_device *)) +{ + struct fec_enet_private *fep; + unsigned long flags; + int retval; + fep = netdev_priv(dev); + spin_lock_irqsave(&fep->mii_lock, flags); + retval = mii_queue_unlocked(dev, regval, func); spin_unlock_irqrestore(&fep->mii_lock, flags); return retval; } @@ -1373,11 +1385,11 @@ mii_discover_phy(uint mii_reg, struct net_device *dev) /* Got first part of ID, now get remainder */ fep->phy_id = phytype << 16; - mii_queue(dev, mk_mii_read(MII_REG_PHYIR2), + mii_queue_unlocked(dev, mk_mii_read(MII_REG_PHYIR2), mii_discover_phy3); } else { fep->phy_addr++; - mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), + mii_queue_unlocked(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy); } } else { -- cgit v1.2.3-18-g5258 From 81538e74ca12a71ea37ce72f809ebc65a90b9538 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 1 Sep 2009 23:14:16 +0000 Subject: fec: don't enable irqs in hard irq context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fec_enet_mii, fec_enet_rx and fec_enet_tx are both only called by fec_enet_interrupt in interrupt context. So they must not use spin_lock_irq/spin_unlock_irq. This fixes: WARNING: at kernel/lockdep.c:2140 trace_hardirqs_on_caller+0x130/0x194() ... Signed-off-by: Uwe Kleine-König Cc: Greg Ungerer Cc: Ben Hutchings Cc: Patrick McHardy Cc: Sascha Hauer Cc: Matt Waddel Cc: netdev@vger.kernel.org Cc: Tim Sander Acked-by: Greg Ungerer Signed-off-by: David S. Miller --- drivers/net/fec.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index e730da26d29..b47201874d8 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -427,7 +427,7 @@ fec_enet_tx(struct net_device *dev) struct sk_buff *skb; fep = netdev_priv(dev); - spin_lock_irq(&fep->hw_lock); + spin_lock(&fep->hw_lock); bdp = fep->dirty_tx; while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) { @@ -486,7 +486,7 @@ fec_enet_tx(struct net_device *dev) } } fep->dirty_tx = bdp; - spin_unlock_irq(&fep->hw_lock); + spin_unlock(&fep->hw_lock); } @@ -509,7 +509,7 @@ fec_enet_rx(struct net_device *dev) flush_cache_all(); #endif - spin_lock_irq(&fep->hw_lock); + spin_lock(&fep->hw_lock); /* First, grab all of the stats for the incoming packet. * These get messed up if we get called due to a busy condition. @@ -604,7 +604,7 @@ rx_processing_done: } fep->cur_rx = bdp; - spin_unlock_irq(&fep->hw_lock); + spin_unlock(&fep->hw_lock); } /* called from interrupt context */ @@ -615,7 +615,7 @@ fec_enet_mii(struct net_device *dev) mii_list_t *mip; fep = netdev_priv(dev); - spin_lock_irq(&fep->mii_lock); + spin_lock(&fep->mii_lock); if ((mip = mii_head) == NULL) { printk("MII and no head!\n"); @@ -633,7 +633,7 @@ fec_enet_mii(struct net_device *dev) writel(mip->mii_regval, fep->hwp + FEC_MII_DATA); unlock: - spin_unlock_irq(&fep->mii_lock); + spin_unlock(&fep->mii_lock); } static int -- cgit v1.2.3-18-g5258 From ff41f8dcc63b4d027ed314ae909df53746c40632 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 3 Sep 2009 14:48:56 +0000 Subject: igb: add support for set_rx_mode netdevice operation This patch adds support for the set_rx_mode netdevice operation so that igb can better support multiple unicast addresses. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/igb_main.c | 73 ++++++++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 7a054d99bff..95089a8feee 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -94,7 +94,7 @@ static void igb_clean_all_tx_rings(struct igb_adapter *); static void igb_clean_all_rx_rings(struct igb_adapter *); static void igb_clean_tx_ring(struct igb_ring *); static void igb_clean_rx_ring(struct igb_ring *); -static void igb_set_multi(struct net_device *); +static void igb_set_rx_mode(struct net_device *); static void igb_update_phy_info(unsigned long); static void igb_watchdog(unsigned long); static void igb_watchdog_task(struct work_struct *); @@ -928,7 +928,7 @@ static void igb_configure(struct igb_adapter *adapter) int i; igb_get_hw_control(adapter); - igb_set_multi(netdev); + igb_set_rx_mode(netdev); igb_restore_vlan(adapter); @@ -1169,7 +1169,8 @@ static const struct net_device_ops igb_netdev_ops = { .ndo_stop = igb_close, .ndo_start_xmit = igb_xmit_frame_adv, .ndo_get_stats = igb_get_stats, - .ndo_set_multicast_list = igb_set_multi, + .ndo_set_rx_mode = igb_set_rx_mode, + .ndo_set_multicast_list = igb_set_rx_mode, .ndo_set_mac_address = igb_set_mac, .ndo_change_mtu = igb_change_mtu, .ndo_do_ioctl = igb_ioctl, @@ -2519,48 +2520,70 @@ static int igb_set_mac(struct net_device *netdev, void *p) memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len); - hw->mac.ops.rar_set(hw, hw->mac.addr, 0); - + igb_rar_set(hw, hw->mac.addr, 0); igb_set_rah_pool(hw, adapter->vfs_allocated_count, 0); return 0; } /** - * igb_set_multi - Multicast and Promiscuous mode set + * igb_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set * @netdev: network interface device structure * - * The set_multi entry point is called whenever the multicast address - * list or the network interface flags are updated. This routine is - * responsible for configuring the hardware for proper multicast, + * The set_rx_mode entry point is called whenever the unicast or multicast + * address lists or the network interface flags are updated. This routine is + * responsible for configuring the hardware for proper unicast, multicast, * promiscuous mode, and all-multi behavior. **/ -static void igb_set_multi(struct net_device *netdev) +static void igb_set_rx_mode(struct net_device *netdev) { struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - struct dev_mc_list *mc_ptr; + unsigned int rar_entries = hw->mac.rar_entry_count - + (adapter->vfs_allocated_count + 1); + struct dev_mc_list *mc_ptr = netdev->mc_list; u8 *mta_list = NULL; u32 rctl; int i; /* Check for Promiscuous and All Multicast modes */ - rctl = rd32(E1000_RCTL); if (netdev->flags & IFF_PROMISC) { rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); rctl &= ~E1000_RCTL_VFE; } else { - if (netdev->flags & IFF_ALLMULTI) { + if (netdev->flags & IFF_ALLMULTI) rctl |= E1000_RCTL_MPE; + else + rctl &= ~E1000_RCTL_MPE; + + if (netdev->uc.count > rar_entries) + rctl |= E1000_RCTL_UPE; + else rctl &= ~E1000_RCTL_UPE; - } else - rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); rctl |= E1000_RCTL_VFE; } wr32(E1000_RCTL, rctl); + if (netdev->uc.count && rar_entries) { + struct netdev_hw_addr *ha; + list_for_each_entry(ha, &netdev->uc.list, list) { + if (!rar_entries) + break; + igb_rar_set(hw, ha->addr, rar_entries); + igb_set_rah_pool(hw, adapter->vfs_allocated_count, + rar_entries); + rar_entries--; + } + } + /* write the addresses in reverse order to avoid write combining */ + for (; rar_entries > 0 ; rar_entries--) { + wr32(E1000_RAH(rar_entries), 0); + wr32(E1000_RAL(rar_entries), 0); + } + wrfl(); + if (!netdev->mc_count) { /* nothing to program, so clear mc list */ igb_update_mc_addr_list(hw, NULL, 0); @@ -2576,8 +2599,6 @@ static void igb_set_multi(struct net_device *netdev) } /* The shared function expects a packed array of only addresses. */ - mc_ptr = netdev->mc_list; - for (i = 0; i < netdev->mc_count; i++) { if (!mc_ptr) break; @@ -3938,7 +3959,7 @@ static int igb_set_vf_multicasts(struct igb_adapter *adapter, vf_data->vf_mc_hashes[i] = hash_list[i];; /* Flush and reset the mta with the new values */ - igb_set_multi(adapter->netdev); + igb_set_rx_mode(adapter->netdev); return 0; } @@ -4072,13 +4093,14 @@ static inline void igb_vf_reset_event(struct igb_adapter *adapter, u32 vf) adapter->vf_data[vf].num_vf_mc_hashes = 0; /* Flush and reset the mta with the new values */ - igb_set_multi(adapter->netdev); + igb_set_rx_mode(adapter->netdev); } static inline void igb_vf_reset_msg(struct igb_adapter *adapter, u32 vf) { struct e1000_hw *hw = &adapter->hw; unsigned char *vf_mac = adapter->vf_data[vf].vf_mac_addresses; + int rar_entry = hw->mac.rar_entry_count - (vf + 1); u32 reg, msgbuf[3]; u8 *addr = (u8 *)(&msgbuf[1]); @@ -4086,8 +4108,8 @@ static inline void igb_vf_reset_msg(struct igb_adapter *adapter, u32 vf) igb_vf_reset_event(adapter, vf); /* set vf mac address */ - igb_rar_set(hw, vf_mac, vf + 1); - igb_set_rah_pool(hw, vf, vf + 1); + igb_rar_set(hw, vf_mac, rar_entry); + igb_set_rah_pool(hw, vf, rar_entry); /* enable transmit and receive for vf */ reg = rd32(E1000_VFTE); @@ -5228,7 +5250,7 @@ static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake) if (wufc) { igb_setup_rctl(adapter); - igb_set_multi(netdev); + igb_set_rx_mode(netdev); /* turn on all-multi mode if wake on multicast is enabled */ if (wufc & E1000_WUFC_MC) { @@ -5482,12 +5504,13 @@ static int igb_set_vf_mac(struct igb_adapter *adapter, int vf, unsigned char *mac_addr) { struct e1000_hw *hw = &adapter->hw; - int rar_entry = vf + 1; /* VF MAC addresses start at entry 1 */ - - igb_rar_set(hw, mac_addr, rar_entry); + /* VF MAC addresses start at end of receive addresses and moves + * torwards the first, as a result a collision should not be possible */ + int rar_entry = hw->mac.rar_entry_count - (vf + 1); memcpy(adapter->vf_data[vf].vf_mac_addresses, mac_addr, ETH_ALEN); + igb_rar_set(hw, mac_addr, rar_entry); igb_set_rah_pool(hw, vf, rar_entry); return 0; -- cgit v1.2.3-18-g5258 From 2dfd12126573d6feb12f1d215a352851750fcbd7 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 3 Sep 2009 14:49:15 +0000 Subject: igb: only disable/enable interrupt bits for igb physical function The igb_irq_disable/enable calls were causing virtual functions associated with the igb physical function to have their interrupts disabled. In order to prevent this from occuring we should only clear/set the bits related to the physical function. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/igb_main.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 95089a8feee..1d03fcb0bd6 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -821,9 +821,11 @@ static void igb_irq_disable(struct igb_adapter *adapter) struct e1000_hw *hw = &adapter->hw; if (adapter->msix_entries) { - wr32(E1000_EIAM, 0); - wr32(E1000_EIMC, ~0); - wr32(E1000_EIAC, 0); + u32 regval = rd32(E1000_EIAM); + wr32(E1000_EIAM, regval & ~adapter->eims_enable_mask); + wr32(E1000_EIMC, adapter->eims_enable_mask); + regval = rd32(E1000_EIAC); + wr32(E1000_EIAC, regval & ~adapter->eims_enable_mask); } wr32(E1000_IAM, 0); @@ -841,8 +843,10 @@ static void igb_irq_enable(struct igb_adapter *adapter) struct e1000_hw *hw = &adapter->hw; if (adapter->msix_entries) { - wr32(E1000_EIAC, adapter->eims_enable_mask); - wr32(E1000_EIAM, adapter->eims_enable_mask); + u32 regval = rd32(E1000_EIAC); + wr32(E1000_EIAC, regval | adapter->eims_enable_mask); + regval = rd32(E1000_EIAM); + wr32(E1000_EIAM, regval | adapter->eims_enable_mask); wr32(E1000_EIMS, adapter->eims_enable_mask); if (adapter->vfs_allocated_count) wr32(E1000_MBVFIMR, 0xFF); -- cgit v1.2.3-18-g5258 From ae641bdc264a5998b7872622c86f0690a5b1c5b5 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 3 Sep 2009 14:49:33 +0000 Subject: igb: set vf rlpml wasn't taking vlan tag into account This patch updates things so that vlan tags are taken into account when setting the receive large packet maximum length. This allows the VF driver to correctly receive full sized frames when vlans are enabled. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/igb/igb.h | 1 + drivers/net/igb/igb_main.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) (limited to 'drivers') diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index b2c98dea9ee..7126fea26fe 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -70,6 +70,7 @@ struct vf_data_storage { unsigned char vf_mac_addresses[ETH_ALEN]; u16 vf_mc_hashes[IGB_MAX_VF_MC_ENTRIES]; u16 num_vf_mc_hashes; + u16 vlans_enabled; bool clear_to_send; }; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 1d03fcb0bd6..90b0b1b9173 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -154,6 +154,12 @@ static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size, struct e1000_hw *hw = &adapter->hw; u32 vmolr; + /* if it isn't the PF check to see if VFs are enabled and + * increase the size to support vlan tags */ + if (vfn < adapter->vfs_allocated_count && + adapter->vf_data[vfn].vlans_enabled) + size += VLAN_TAG_SIZE; + vmolr = rd32(E1000_VMOLR(vfn)); vmolr &= ~E1000_VMOLR_RLPML_MASK; vmolr |= size | E1000_VMOLR_LPE; @@ -4006,6 +4012,8 @@ static void igb_clear_vf_vfta(struct igb_adapter *adapter, u32 vf) wr32(E1000_VLVF(i), reg); } + + adapter->vf_data[vf].vlans_enabled = 0; } static s32 igb_vlvf_set(struct igb_adapter *adapter, u32 vid, bool add, u32 vf) @@ -4054,6 +4062,22 @@ static s32 igb_vlvf_set(struct igb_adapter *adapter, u32 vid, bool add, u32 vf) reg |= vid; wr32(E1000_VLVF(i), reg); + + /* do not modify RLPML for PF devices */ + if (vf >= adapter->vfs_allocated_count) + return 0; + + if (!adapter->vf_data[vf].vlans_enabled) { + u32 size; + reg = rd32(E1000_VMOLR(vf)); + size = reg & E1000_VMOLR_RLPML_MASK; + size += 4; + reg &= ~E1000_VMOLR_RLPML_MASK; + reg |= size; + wr32(E1000_VMOLR(vf), reg); + } + adapter->vf_data[vf].vlans_enabled++; + return 0; } } else { @@ -4066,6 +4090,21 @@ static s32 igb_vlvf_set(struct igb_adapter *adapter, u32 vid, bool add, u32 vf) igb_vfta_set(hw, vid, false); } wr32(E1000_VLVF(i), reg); + + /* do not modify RLPML for PF devices */ + if (vf >= adapter->vfs_allocated_count) + return 0; + + adapter->vf_data[vf].vlans_enabled--; + if (!adapter->vf_data[vf].vlans_enabled) { + u32 size; + reg = rd32(E1000_VMOLR(vf)); + size = reg & E1000_VMOLR_RLPML_MASK; + size -= 4; + reg &= ~E1000_VMOLR_RLPML_MASK; + reg |= size; + wr32(E1000_VMOLR(vf), reg); + } return 0; } } -- cgit v1.2.3-18-g5258 From 8de8b2e63490fe7e90128299983198d09d1679c9 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Thu, 3 Sep 2009 14:55:50 +0000 Subject: ixgbe: Add support for multiple Tx queues for FCoE in 82599 This patch adds support for multiple transmit queues to the Fiber Channel over Ethernet (FCoE) feature found in 82599. Currently, FCoE has multiple Rx queues available, along with a redirection table, that helps distribute the I/O load across multiple CPUs based on the FC exchange ID. To make this the most effective, we need to provide the same layout of transmit queues to match receive. Particularly, when Data Center Bridging (DCB) is enabled, the designated traffic class for FCoE can have dedicated queues for just FCoE traffic, while not affecting any other type of traffic flow. Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_dcb_nl.c | 37 ++++++++++++++++++++++++++++------ drivers/net/ixgbe/ixgbe_main.c | 43 +++++++++++++++++++++++++++++++--------- 2 files changed, 65 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index 47d9dde82a8..a6bc1ef28f9 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -36,6 +36,7 @@ #define BIT_PFC 0x02 #define BIT_PG_RX 0x04 #define BIT_PG_TX 0x08 +#define BIT_APP_UPCHG 0x10 #define BIT_RESETLINK 0x40 #define BIT_LINKSPEED 0x80 @@ -348,8 +349,14 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) msleep(1); - if (netif_running(netdev)) - ixgbe_down(adapter); + if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) { + if (netif_running(netdev)) + netdev->netdev_ops->ndo_stop(netdev); + ixgbe_clear_interrupt_scheme(adapter); + } else { + if (netif_running(netdev)) + ixgbe_down(adapter); + } } ret = ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg, &adapter->dcb_cfg, @@ -373,8 +380,14 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) } if (adapter->dcb_set_bitmap & BIT_RESETLINK) { - if (netif_running(netdev)) - ixgbe_up(adapter); + if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) { + ixgbe_init_interrupt_scheme(adapter); + if (netif_running(netdev)) + netdev->netdev_ops->ndo_open(netdev); + } else { + if (netif_running(netdev)) + ixgbe_up(adapter); + } ret = DCB_HW_CHG_RST; } else if (adapter->dcb_set_bitmap & BIT_PFC) { if (adapter->hw.mac.type == ixgbe_mac_82598EB) @@ -526,8 +539,20 @@ static u8 ixgbe_dcbnl_setapp(struct net_device *netdev, switch (idtype) { case DCB_APP_IDTYPE_ETHTYPE: #ifdef IXGBE_FCOE - if (id == ETH_P_FCOE) - rval = ixgbe_fcoe_setapp(netdev_priv(netdev), up); + if (id == ETH_P_FCOE) { + u8 tc; + struct ixgbe_adapter *adapter; + + adapter = netdev_priv(netdev); + tc = adapter->fcoe.tc; + rval = ixgbe_fcoe_setapp(adapter, up); + if ((!rval) && (tc != adapter->fcoe.tc) && + (adapter->flags & IXGBE_FLAG_DCB_ENABLED) && + (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) { + adapter->dcb_set_bitmap |= BIT_APP_UPCHG; + adapter->dcb_set_bitmap |= BIT_RESETLINK; + } + } #endif break; case DCB_APP_IDTYPE_PORTNUM: diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 4042d878670..724754a64d0 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3113,14 +3113,16 @@ static inline bool ixgbe_set_fcoe_queues(struct ixgbe_adapter *adapter) f->indices = min((int)num_online_cpus(), f->indices); if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { + adapter->num_rx_queues = 1; + adapter->num_tx_queues = 1; #ifdef CONFIG_IXGBE_DCB if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { - DPRINTK(PROBE, INFO, "FCOE enabled with DCB \n"); + DPRINTK(PROBE, INFO, "FCoE enabled with DCB \n"); ixgbe_set_dcb_queues(adapter); } #endif if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { - DPRINTK(PROBE, INFO, "FCOE enabled with RSS \n"); + DPRINTK(PROBE, INFO, "FCoE enabled with RSS \n"); if ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) || (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)) ixgbe_set_fdir_queues(adapter); @@ -3130,8 +3132,7 @@ static inline bool ixgbe_set_fcoe_queues(struct ixgbe_adapter *adapter) /* adding FCoE rx rings to the end */ f->mask = adapter->num_rx_queues; adapter->num_rx_queues += f->indices; - if (adapter->num_tx_queues == 0) - adapter->num_tx_queues = f->indices; + adapter->num_tx_queues += f->indices; ret = true; } @@ -3371,15 +3372,36 @@ static bool inline ixgbe_cache_ring_fdir(struct ixgbe_adapter *adapter) */ static inline bool ixgbe_cache_ring_fcoe(struct ixgbe_adapter *adapter) { - int i, fcoe_i = 0; + int i, fcoe_rx_i = 0, fcoe_tx_i = 0; bool ret = false; struct ixgbe_ring_feature *f = &adapter->ring_feature[RING_F_FCOE]; if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { #ifdef CONFIG_IXGBE_DCB if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + struct ixgbe_fcoe *fcoe = &adapter->fcoe; + ixgbe_cache_ring_dcb(adapter); - fcoe_i = adapter->rx_ring[0].reg_idx + 1; + /* find out queues in TC for FCoE */ + fcoe_rx_i = adapter->rx_ring[fcoe->tc].reg_idx + 1; + fcoe_tx_i = adapter->tx_ring[fcoe->tc].reg_idx + 1; + /* + * In 82599, the number of Tx queues for each traffic + * class for both 8-TC and 4-TC modes are: + * TCs : TC0 TC1 TC2 TC3 TC4 TC5 TC6 TC7 + * 8 TCs: 32 32 16 16 8 8 8 8 + * 4 TCs: 64 64 32 32 + * We have max 8 queues for FCoE, where 8 the is + * FCoE redirection table size. If TC for FCoE is + * less than or equal to TC3, we have enough queues + * to add max of 8 queues for FCoE, so we start FCoE + * tx descriptor from the next one, i.e., reg_idx + 1. + * If TC for FCoE is above TC3, implying 8 TC mode, + * and we need 8 for FCoE, we have to take all queues + * in that traffic class for FCoE. + */ + if ((f->indices == IXGBE_FCRETA_SIZE) && (fcoe->tc > 3)) + fcoe_tx_i--; } #endif /* CONFIG_IXGBE_DCB */ if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { @@ -3389,10 +3411,13 @@ static inline bool ixgbe_cache_ring_fcoe(struct ixgbe_adapter *adapter) else ixgbe_cache_ring_rss(adapter); - fcoe_i = f->mask; + fcoe_rx_i = f->mask; + fcoe_tx_i = f->mask; + } + for (i = 0; i < f->indices; i++, fcoe_rx_i++, fcoe_tx_i++) { + adapter->rx_ring[f->mask + i].reg_idx = fcoe_rx_i; + adapter->tx_ring[f->mask + i].reg_idx = fcoe_tx_i; } - for (i = 0; i < f->indices; i++, fcoe_i++) - adapter->rx_ring[f->mask + i].reg_idx = fcoe_i; ret = true; } return ret; -- cgit v1.2.3-18-g5258 From 09ad1cc099f4ba4735d11ce1c5f024ffc521be3b Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Thu, 3 Sep 2009 14:56:10 +0000 Subject: ixgbe: Distribute transmission of FCoE traffic in 82599 This adds a simple selection of a FCoE tx queue based on the current cpu id to distribute transmission of FCoE traffic evenly among multiple FCoE transmit queues. Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 724754a64d0..45bf8b9716e 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -5168,9 +5168,15 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb, tx_ring = &adapter->tx_ring[r_idx]; if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) && - (skb->protocol == htons(ETH_P_FCOE))) + (skb->protocol == htons(ETH_P_FCOE))) { tx_flags |= IXGBE_TX_FLAGS_FCOE; - +#ifdef IXGBE_FCOE + r_idx = smp_processor_id(); + r_idx &= (adapter->ring_feature[RING_F_FCOE].indices - 1); + r_idx += adapter->ring_feature[RING_F_FCOE].mask; + tx_ring = &adapter->tx_ring[r_idx]; +#endif + } /* four things can cause us to need a context descriptor */ if (skb_is_gso(skb) || (skb->ip_summed == CHECKSUM_PARTIAL) || -- cgit v1.2.3-18-g5258 From d4ab88194e982a0d213000a75475d3e76b2626f0 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Thu, 3 Sep 2009 14:56:31 +0000 Subject: ixgbe: Add support for using FCoE DDP in 82599 as FCoE targets The FCoE DDP in 82599 can be used for both FCoE initiator as well as FCoE target, depending on the indication of the exchange being the responder or originator in the F_CTL (frame control) field in the encapsulated Fiber Channel frame header (T10 Spec., FC-FS). For the initiator, OX_ID is used for FCoE DDP, where for the target RX_ID is used for FCoE DDP. Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_fcoe.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index 0607cffbb21..a3c9f99515e 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -292,6 +292,7 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, struct sk_buff *skb) { u16 xid; + u32 fctl; u32 sterr, fceofe, fcerr, fcstat; int rc = -EINVAL; struct ixgbe_fcoe *fcoe; @@ -312,7 +313,12 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, skb_set_transport_header(skb, skb_network_offset(skb) + sizeof(struct fcoe_hdr)); fh = (struct fc_frame_header *)skb_transport_header(skb); - xid = be16_to_cpu(fh->fh_ox_id); + fctl = ntoh24(fh->fh_f_ctl); + if (fctl & FC_FC_EX_CTX) + xid = be16_to_cpu(fh->fh_ox_id); + else + xid = be16_to_cpu(fh->fh_rx_id); + if (xid >= IXGBE_FCOE_DDP_MAX) goto ddp_out; -- cgit v1.2.3-18-g5258 From bc75e5bfad2a6d24fc5a9885a2f6b93f82c6c5f1 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Thu, 3 Sep 2009 13:10:53 +0000 Subject: netxen: fix lro buffer allocation Alloc 12k skbuffs so that firmware can aggregate more packets into one buffer. This doesn't raise memory consumption since 9k skbs use 16k slab cache anyway. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 1 + drivers/net/netxen/netxen_nic_init.c | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 224a7469131..ede2fa7477a 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -149,6 +149,7 @@ #define NX_P2_RX_JUMBO_BUF_MAX_LEN (NX_MAX_ETHERHDR + P2_MAX_MTU) #define NX_P3_RX_JUMBO_BUF_MAX_LEN (NX_MAX_ETHERHDR + P3_MAX_MTU) #define NX_CT_DEFAULT_RX_BUF_LEN 2048 +#define NX_LRO_BUFFER_EXTRA 2048 #define NX_RX_LRO_BUFFER_LENGTH (8060) diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 8d4aa6f74bf..04e36f2b1a9 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -265,6 +265,10 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter) else rds_ring->dma_size = NX_P2_RX_JUMBO_BUF_MAX_LEN; + + if (adapter->capabilities & NX_CAP0_HW_LRO) + rds_ring->dma_size += NX_LRO_BUFFER_EXTRA; + rds_ring->skb_size = rds_ring->dma_size + NET_IP_ALIGN; break; @@ -1217,6 +1221,7 @@ netxen_process_rcv(struct netxen_adapter *adapter, if (pkt_offset) skb_pull(skb, pkt_offset); + skb->truesize = skb->len + sizeof(struct sk_buff); skb->protocol = eth_type_trans(skb, netdev); napi_gro_receive(&sds_ring->napi, skb); @@ -1278,8 +1283,7 @@ netxen_process_lro(struct netxen_adapter *adapter, skb_put(skb, lro_length + data_offset); - skb->truesize = (skb->len + sizeof(struct sk_buff) + - ((unsigned long)skb->data - (unsigned long)skb->head)); + skb->truesize = skb->len + sizeof(struct sk_buff) + skb_headroom(skb); skb_pull(skb, l2_hdr_offset); skb->protocol = eth_type_trans(skb, netdev); -- cgit v1.2.3-18-g5258 From 270e57e133a9e61c8c62ea4a0d1ffdf53f91caf1 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Thu, 3 Sep 2009 13:10:54 +0000 Subject: netxen: remove duplicate napi_add Remove duplicate calls to netxen_napi_add(). Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_main.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index f824a392bf5..53d57dc4d64 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1095,10 +1095,6 @@ netxen_setup_netdev(struct netxen_adapter *adapter, netdev->irq = adapter->msix_entries[0].vector; - err = netxen_napi_add(adapter, netdev); - if (err) - return err; - init_timer(&adapter->watchdog_timer); adapter->watchdog_timer.function = &netxen_watchdog; adapter->watchdog_timer.data = (unsigned long)adapter; @@ -2038,8 +2034,6 @@ netxen_remove_sysfs_entries(struct netxen_adapter *adapter) device_remove_file(dev, &dev_attr_bridged_mode); } -static void netxen_watchdog(unsigned long); - #ifdef CONFIG_INET #define is_netxen_netdev(dev) (dev->netdev_ops == &netxen_netdev_ops) -- cgit v1.2.3-18-g5258 From cf503e8f458cec455b18d3938b3b27de6db3105e Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Thu, 3 Sep 2009 13:10:55 +0000 Subject: netxen: fix infinite loop on dma mapping failure Fix a perpetual while() loop in unwinding partial mapped tx skb on dma mapping failure. Reported-by: "Juha Leppanen" Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 53d57dc4d64..41b29671fc9 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1577,8 +1577,8 @@ netxen_map_tx_skb(struct pci_dev *pdev, return 0; unwind: - while (i > 0) { - nf = &pbuf->frag_array[i]; + while (--i >= 0) { + nf = &pbuf->frag_array[i+1]; pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE); } -- cgit v1.2.3-18-g5258 From c23ddf8f22fc2c871ce476ff917d1208bbe4f3de Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 3 Sep 2009 06:16:25 +0000 Subject: sky2: only enable Vaux if capable of wakeup While perusing vendor driver, I saw that it did not enable the Vaux power unless device was able to wake from lan for D3cold. This might help for Rene's power issue. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index d1f3b46a2b0..bab591b418d 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -272,8 +272,9 @@ static void sky2_power_aux(struct sky2_hw *hw) Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS | Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS); - /* switch power to VAUX */ - if (sky2_read32(hw, B0_CTST) & Y2_VAUX_AVAIL) + /* switch power to VAUX if supported and PME from D3cold */ + if ( (sky2_read32(hw, B0_CTST) & Y2_VAUX_AVAIL) && + pci_pme_capable(hw->pdev, PCI_D3cold)) sky2_write8(hw, B0_POWER_CTRL, (PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF)); -- cgit v1.2.3-18-g5258 From aae5e7c30fc660c50dfecbdd745799b05af90f01 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 3 Sep 2009 10:38:33 +0000 Subject: netdev: Remove SIOCDEVPRIVATE aliases for MDIO ioctls The standard MDIO ioctl numbers are well-established and these should no longer be needed. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/ibm_newemac/core.c | 3 --- drivers/net/natsemi.c | 3 --- 2 files changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index d7579e4feef..24ae671e4cb 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -2218,16 +2218,13 @@ static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) switch (cmd) { case SIOCGMIIPHY: - case SIOCDEVPRIVATE: data[0] = dev->phy.address; /* Fall through */ case SIOCGMIIREG: - case SIOCDEVPRIVATE + 1: data[3] = emac_mdio_read(ndev, dev->phy.address, data[1]); return 0; case SIOCSMIIREG: - case SIOCDEVPRIVATE + 2: if (!capable(CAP_NET_ADMIN)) return -EPERM; emac_mdio_write(ndev, dev->phy.address, data[1], data[2]); diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index bd41351e4e2..b52e5d98a3b 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -3053,12 +3053,10 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) switch(cmd) { case SIOCGMIIPHY: /* Get address of MII PHY in use. */ - case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ data->phy_id = np->phy_addr_external; /* Fall Through */ case SIOCGMIIREG: /* Read MII PHY register. */ - case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ /* The phy_id is not enough to uniquely identify * the intended target. Therefore the command is sent to * the given mii on the current port. @@ -3077,7 +3075,6 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) return -EPERM; if (dev->if_port == PORT_TP) { -- cgit v1.2.3-18-g5258 From 7ab0f2736bfe137a82a7084bbfb5f809da95cabd Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 3 Sep 2009 10:39:43 +0000 Subject: netdev: Remove redundant checks for CAP_NET_ADMIN in MDIO implementations dev_ioctl() already checks capable(CAP_NET_ADMIN) before calling the driver's implementation of MDIO ioctls. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/amd8111e.c | 3 --- drivers/net/atl1c/atl1c_main.c | 8 -------- drivers/net/atl1e/atl1e_main.c | 8 -------- drivers/net/atlx/atl2.c | 4 ---- drivers/net/bnx2.c | 3 --- drivers/net/cassini.c | 4 ---- drivers/net/e1000/e1000_main.c | 4 ---- drivers/net/e1000e/netdev.c | 2 -- drivers/net/ibm_newemac/core.c | 2 -- drivers/net/igb/igb_main.c | 2 -- drivers/net/mdio.c | 3 --- drivers/net/mii.c | 3 --- drivers/net/natsemi.c | 2 -- drivers/net/pci-skeleton.c | 5 ----- drivers/net/pcmcia/3c574_cs.c | 2 -- drivers/net/pcmcia/axnet_cs.c | 2 -- drivers/net/pcmcia/pcnet_cs.c | 2 -- drivers/net/pcmcia/xirc2ps_cs.c | 2 -- drivers/net/phy/phy.c | 3 --- drivers/net/r8169.c | 2 -- drivers/net/sis900.c | 2 -- drivers/net/skge.c | 3 --- drivers/net/sky2.c | 3 --- drivers/net/sungem.c | 4 +--- drivers/net/tg3.c | 3 --- drivers/net/tlan.c | 2 -- drivers/net/tulip/tulip_core.c | 2 -- drivers/net/tulip/winbond-840.c | 2 -- drivers/net/via-velocity.c | 4 ---- drivers/net/yellowfin.c | 2 -- 30 files changed, 1 insertion(+), 92 deletions(-) (limited to 'drivers') diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 98b5f462c09..4e6359fff0e 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1524,9 +1524,6 @@ static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd) int err; u32 mii_regval; - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - switch(cmd) { case SIOCGMIIPHY: data->phy_id = lp->ext_phy_addr; diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index e46bf923869..be2c6cfe6e8 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -534,10 +534,6 @@ static int atl1c_mii_ioctl(struct net_device *netdev, break; case SIOCGMIIREG: - if (!capable(CAP_NET_ADMIN)) { - retval = -EPERM; - goto out; - } if (atl1c_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, &data->val_out)) { retval = -EIO; @@ -546,10 +542,6 @@ static int atl1c_mii_ioctl(struct net_device *netdev, break; case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) { - retval = -EPERM; - goto out; - } if (data->reg_num & ~(0x1F)) { retval = -EFAULT; goto out; diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index bca127e65f9..69b830f4b68 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -453,10 +453,6 @@ static int atl1e_mii_ioctl(struct net_device *netdev, break; case SIOCGMIIREG: - if (!capable(CAP_NET_ADMIN)) { - retval = -EPERM; - goto out; - } if (atl1e_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, &data->val_out)) { retval = -EIO; @@ -465,10 +461,6 @@ static int atl1e_mii_ioctl(struct net_device *netdev, break; case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) { - retval = -EPERM; - goto out; - } if (data->reg_num & ~(0x1F)) { retval = -EFAULT; goto out; diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index 10c06b97001..ab688862093 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -966,8 +966,6 @@ static int atl2_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) data->phy_id = 0; break; case SIOCGMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; spin_lock_irqsave(&adapter->stats_lock, flags); if (atl2_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, &data->val_out)) { @@ -977,8 +975,6 @@ static int atl2_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) spin_unlock_irqrestore(&adapter->stats_lock, flags); break; case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; if (data->reg_num & ~(0x1F)) return -EFAULT; spin_lock_irqsave(&adapter->stats_lock, flags); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 1357d548e69..08cddb6ff74 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -7480,9 +7480,6 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) return -EOPNOTSUPP; diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 7517dc1da65..05916aafa4f 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -4875,10 +4875,6 @@ static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) break; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) { - rc = -EPERM; - break; - } spin_lock_irqsave(&cp->lock, flags); cas_mif_poll(cp, 0); rc = cas_phy_write(cp, data->reg_num & 0x1f, data->val_in); diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 2c723b1b882..c66dd4f9437 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -4714,8 +4714,6 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, data->phy_id = hw->phy_addr; break; case SIOCGMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; spin_lock_irqsave(&adapter->stats_lock, flags); if (e1000_read_phy_reg(hw, data->reg_num & 0x1F, &data->val_out)) { @@ -4725,8 +4723,6 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, spin_unlock_irqrestore(&adapter->stats_lock, flags); break; case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; if (data->reg_num & ~(0x1F)) return -EFAULT; mii_reg = data->val_in; diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 0f8d9619ade..16c193a6c95 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -4346,8 +4346,6 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, data->phy_id = adapter->hw.phy.addr; break; case SIOCGMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; switch (data->reg_num & 0x1F) { case MII_BMCR: data->val_out = adapter->phy_regs.bmcr; diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 24ae671e4cb..8a95234d419 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -2225,8 +2225,6 @@ static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) return 0; case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; emac_mdio_write(ndev, dev->phy.address, data[1], data[2]); return 0; default: diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 90b0b1b9173..943186b7848 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -4914,8 +4914,6 @@ static int igb_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) data->phy_id = adapter->hw.phy.addr; break; case SIOCGMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; if (igb_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, &data->val_out)) return -EIO; diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c index 7d2e610f14f..21f8754fcf4 100644 --- a/drivers/net/mdio.c +++ b/drivers/net/mdio.c @@ -380,10 +380,7 @@ int mdio_mii_ioctl(const struct mdio_if_info *mdio, cmd = SIOCGMIIREG; break; case SIOCGMIIREG: - break; case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; break; default: return -EOPNOTSUPP; diff --git a/drivers/net/mii.c b/drivers/net/mii.c index d81a5d22a3a..210b2b164b3 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -433,9 +433,6 @@ int generic_mii_ioctl(struct mii_if_info *mii_if, case SIOCSMIIREG: { u16 val = mii_data->val_in; - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (mii_data->phy_id == mii_if->phy_id) { switch(mii_data->reg_num) { case MII_BMCR: { diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index b52e5d98a3b..b2722c44337 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -3075,8 +3075,6 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; if (dev->if_port == PORT_TP) { if ((data->phy_id & 0x1f) == np->phy_addr_external) { if ((data->reg_num & 0x1f) == MII_ADVERTISE) diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index c47ba3610c5..0c44b48f138 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -1784,11 +1784,6 @@ static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) break; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable (CAP_NET_ADMIN)) { - rc = -EPERM; - break; - } - spin_lock_irqsave (&tp->lock, flags); mdio_write (dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); spin_unlock_irqrestore (&tp->lock, flags); diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 382d26520ac..d836af1b903 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -1124,8 +1124,6 @@ static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) int saved_window; unsigned long flags; - if (!capable(CAP_NET_ADMIN)) - return -EPERM; spin_lock_irqsave(&lp->window_lock, flags); saved_window = inw(ioaddr + EL3_CMD) >> 13; EL3WINDOW(4); diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 3b681c1d752..4f2fef6cf6d 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -706,8 +706,6 @@ static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) data[3] = mdio_read(mii_addr, data[0], data[1] & 0x1f); return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; mdio_write(mii_addr, data[0], data[1] & 0x1f, data[2]); return 0; } diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 9ef1c1bfa83..8996b45ffff 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1204,8 +1204,6 @@ static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) data[3] = mdio_read(mii_addr, data[0], data[1] & 0x1f); return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; mdio_write(mii_addr, data[0], data[1] & 0x1f, data[2]); return 0; } diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 68de89167b4..9709dd173dd 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -1575,8 +1575,6 @@ do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) data[3] = mii_rd(ioaddr, data[0] & 0x1f, data[1] & 0x1f); break; case SIOCSMIIREG: /* Write the specified MII register */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; mii_wr(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2], 16); break; default: diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index eda94fcd406..6b71b003406 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -324,9 +324,6 @@ int phy_mii_ioctl(struct phy_device *phydev, break; case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (mii_data->phy_id == phydev->addr) { switch(mii_data->reg_num) { case MII_BMCR: diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index ec0092affd5..a91e9b3a3eb 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1991,8 +1991,6 @@ static int rtl_xmii_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *dat return 0; case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; mdio_write(tp->mmio_addr, data->reg_num & 0x1f, data->val_in); return 0; } diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index d8827323507..97949d0a699 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -2128,8 +2128,6 @@ static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd) return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; mdio_write(net_dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); return 0; default: diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 1a1e68549f5..62e852e21ab 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2496,9 +2496,6 @@ static int skge_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - spin_lock_bh(&hw->phy_lock); if (hw->chip_id == CHIP_ID_GENESIS) err = xm_phy_write(hw, skge->port, data->reg_num & 0x1f, diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index bab591b418d..00bc65a0aac 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1214,9 +1214,6 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - spin_lock_bh(&sky2->phy_lock); err = gm_phy_write(hw, sky2->port, data->reg_num & 0x1f, data->val_in); diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index e0dfdd24647..305ec3d783d 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -2852,9 +2852,7 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) break; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) - rc = -EPERM; - else if (!gp->running) + if (!gp->running) rc = -EAGAIN; else { __phy_write(gp, data->phy_id & 0x1f, data->reg_num & 0x1f, diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index bd498105260..7cf80006eaf 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10610,9 +10610,6 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) break; /* We have no PHY */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (tp->link_config.phy_is_low_power) return -EAGAIN; diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 49e273bceed..3d31b47332b 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -1004,8 +1004,6 @@ static int TLan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; TLan_MiiWriteReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); return 0; diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index b89b73c0b30..6b2330e4206 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -923,8 +923,6 @@ static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable (CAP_NET_ADMIN)) - return -EPERM; if (regnum & ~0x1f) return -EINVAL; if (data->phy_id == phy) { diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 3e59397e538..b38d3b7f6e3 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -1470,8 +1470,6 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; spin_lock_irq(&np->lock); mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); spin_unlock_irq(&np->lock); diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index ced1446dec0..e04e5bee005 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -2328,14 +2328,10 @@ static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd miidata->phy_id = readb(®s->MIIADR) & 0x1f; break; case SIOCGMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; if (velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0) return -ETIMEDOUT; break; case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; spin_lock_irqsave(&vptr->lock, flags); err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in); spin_unlock_irqrestore(&vptr->lock, flags); diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 4987040c414..40ad0dee040 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -1365,8 +1365,6 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; if (data->phy_id == np->phys[0]) { u16 value = data->val_in; switch (data->reg_num) { -- cgit v1.2.3-18-g5258 From 0fa0ee053aaa53939306376719450cfe56e33e3b Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 3 Sep 2009 10:41:17 +0000 Subject: netdev: Convert MDIO ioctl implementation to use struct mii_ioctl_data A few drivers still access the arguments to MDIO ioctls as an array of u16. Convert them to use struct mii_ioctl_data. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/ibm_newemac/core.c | 10 ++++++---- drivers/net/pcmcia/3c574_cs.c | 13 ++++++++----- drivers/net/pcmcia/axnet_cs.c | 9 +++++---- drivers/net/pcmcia/pcnet_cs.c | 9 +++++---- drivers/net/pcmcia/xirc2ps_cs.c | 13 ++++++++----- 5 files changed, 32 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 8a95234d419..1d7d7fef414 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -2209,7 +2209,7 @@ static const struct ethtool_ops emac_ethtool_ops = { static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) { struct emac_instance *dev = netdev_priv(ndev); - uint16_t *data = (uint16_t *) & rq->ifr_ifru; + struct mii_ioctl_data *data = if_mii(rq); DBG(dev, "ioctl %08x" NL, cmd); @@ -2218,14 +2218,16 @@ static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) switch (cmd) { case SIOCGMIIPHY: - data[0] = dev->phy.address; + data->phy_id = dev->phy.address; /* Fall through */ case SIOCGMIIREG: - data[3] = emac_mdio_read(ndev, dev->phy.address, data[1]); + data->val_out = emac_mdio_read(ndev, dev->phy.address, + data->reg_num); return 0; case SIOCSMIIREG: - emac_mdio_write(ndev, dev->phy.address, data[1], data[2]); + emac_mdio_write(ndev, dev->phy.address, data->reg_num, + data->val_in); return 0; default: return -EOPNOTSUPP; diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index d836af1b903..ee8ad3e180d 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -85,6 +85,7 @@ earlier 3Com products. #include #include #include +#include #include #include @@ -1096,16 +1097,16 @@ static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_ifru; + struct mii_ioctl_data *data = if_mii(rq); int phy = lp->phys & 0x1f; DEBUG(2, "%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n", dev->name, rq->ifr_ifrn.ifrn_name, cmd, - data[0], data[1], data[2], data[3]); + data->phy_id, data->reg_num, data->val_in, data->val_out); switch(cmd) { case SIOCGMIIPHY: /* Get the address of the PHY in use. */ - data[0] = phy; + data->phy_id = phy; case SIOCGMIIREG: /* Read the specified MII register. */ { int saved_window; @@ -1114,7 +1115,8 @@ static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) spin_lock_irqsave(&lp->window_lock, flags); saved_window = inw(ioaddr + EL3_CMD) >> 13; EL3WINDOW(4); - data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); + data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, + data->reg_num & 0x1f); EL3WINDOW(saved_window); spin_unlock_irqrestore(&lp->window_lock, flags); return 0; @@ -1127,7 +1129,8 @@ static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) spin_lock_irqsave(&lp->window_lock, flags); saved_window = inw(ioaddr + EL3_CMD) >> 13; EL3WINDOW(4); - mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); + mdio_write(ioaddr, data->phy_id & 0x1f, + data->reg_num & 0x1f, data->val_in); EL3WINDOW(saved_window); spin_unlock_irqrestore(&lp->window_lock, flags); return 0; diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 4f2fef6cf6d..3131a59a8d3 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "../8390.h" #include @@ -697,16 +698,16 @@ static const struct ethtool_ops netdev_ethtool_ops = { static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { axnet_dev_t *info = PRIV(dev); - u16 *data = (u16 *)&rq->ifr_ifru; + struct mii_ioctl_data *data = if_mii(rq); unsigned int mii_addr = dev->base_addr + AXNET_MII_EEP; switch (cmd) { case SIOCGMIIPHY: - data[0] = info->phy_id; + data->phy_id = info->phy_id; case SIOCGMIIREG: /* Read MII PHY register. */ - data[3] = mdio_read(mii_addr, data[0], data[1] & 0x1f); + data->val_out = mdio_read(mii_addr, data->phy_id, data->reg_num & 0x1f); return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - mdio_write(mii_addr, data[0], data[1] & 0x1f, data[2]); + mdio_write(mii_addr, data->phy_id, data->reg_num & 0x1f, data->val_in); return 0; } return -EOPNOTSUPP; diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 8996b45ffff..90a94d21583 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "../8390.h" #include @@ -1191,7 +1192,7 @@ static const struct ethtool_ops netdev_ethtool_ops = { static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { pcnet_dev_t *info = PRIV(dev); - u16 *data = (u16 *)&rq->ifr_ifru; + struct mii_ioctl_data *data = if_mii(rq); unsigned int mii_addr = dev->base_addr + DLINK_GPIO; if (!(info->flags & (IS_DL10019|IS_DL10022))) @@ -1199,12 +1200,12 @@ static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) switch (cmd) { case SIOCGMIIPHY: - data[0] = info->phy_id; + data->phy_id = info->phy_id; case SIOCGMIIREG: /* Read MII PHY register. */ - data[3] = mdio_read(mii_addr, data[0], data[1] & 0x1f); + data->val_out = mdio_read(mii_addr, data->phy_id, data->reg_num & 0x1f); return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - mdio_write(mii_addr, data[0], data[1] & 0x1f, data[2]); + mdio_write(mii_addr, data->phy_id, data->reg_num & 0x1f, data->val_in); return 0; } return -EOPNOTSUPP; diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 9709dd173dd..cf842310253 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -80,6 +80,7 @@ #include #include #include +#include #include #include @@ -1558,24 +1559,26 @@ do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { local_info_t *local = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_ifru; + struct mii_ioctl_data *data = if_mii(rq); DEBUG(1, "%s: ioctl(%-.6s, %#04x) %04x %04x %04x %04x\n", dev->name, rq->ifr_ifrn.ifrn_name, cmd, - data[0], data[1], data[2], data[3]); + data->phy_id, data->reg_num, data->val_in, data->val_out); if (!local->mohawk) return -EOPNOTSUPP; switch(cmd) { case SIOCGMIIPHY: /* Get the address of the PHY in use. */ - data[0] = 0; /* we have only this address */ + data->phy_id = 0; /* we have only this address */ /* fall through */ case SIOCGMIIREG: /* Read the specified MII register. */ - data[3] = mii_rd(ioaddr, data[0] & 0x1f, data[1] & 0x1f); + data->val_out = mii_rd(ioaddr, data->phy_id & 0x1f, + data->reg_num & 0x1f); break; case SIOCSMIIREG: /* Write the specified MII register */ - mii_wr(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2], 16); + mii_wr(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in, + 16); break; default: return -EOPNOTSUPP; -- cgit v1.2.3-18-g5258 From 2c11455321f37da6fe6cc36353149f9ac9183334 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 3 Sep 2009 00:11:45 +0000 Subject: macvlan: add multiqueue capability macvlan devices are currently not multi-queue capable. We can do that defining rtnl_link_ops method, get_tx_queues(), called from rtnl_create_link() This new method gets num_tx_queues/real_num_tx_queues from lower device. macvlan_get_tx_queues() is a copy of vlan_get_tx_queues(). Because macvlan_start_xmit() has to update netdev_queue stats only (and not dev->stats), I chose to change tx_errors/tx_aborted_errors accounting to tx_dropped, since netdev_queue structure doesnt define tx_errors / tx_aborted_errors. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index c85c46d2a30..3aabfd9dd21 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -187,6 +187,8 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, struct net_device *dev) { + int i = skb_get_queue_mapping(skb); + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); const struct macvlan_dev *vlan = netdev_priv(dev); unsigned int len = skb->len; int ret; @@ -195,12 +197,11 @@ static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, ret = dev_queue_xmit(skb); if (likely(ret == NET_XMIT_SUCCESS)) { - dev->stats.tx_packets++; - dev->stats.tx_bytes += len; - } else { - dev->stats.tx_errors++; - dev->stats.tx_aborted_errors++; - } + txq->tx_packets++; + txq->tx_bytes += len; + } else + txq->tx_dropped++; + return NETDEV_TX_OK; } @@ -484,6 +485,25 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) return 0; } +static int macvlan_get_tx_queues(struct net *net, + struct nlattr *tb[], + unsigned int *num_tx_queues, + unsigned int *real_num_tx_queues) +{ + struct net_device *real_dev; + + if (!tb[IFLA_LINK]) + return -EINVAL; + + real_dev = __dev_get_by_index(net, nla_get_u32(tb[IFLA_LINK])); + if (!real_dev) + return -ENODEV; + + *num_tx_queues = real_dev->num_tx_queues; + *real_num_tx_queues = real_dev->real_num_tx_queues; + return 0; +} + static int macvlan_newlink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { @@ -550,6 +570,7 @@ static void macvlan_dellink(struct net_device *dev) static struct rtnl_link_ops macvlan_link_ops __read_mostly = { .kind = "macvlan", .priv_size = sizeof(struct macvlan_dev), + .get_tx_queues = macvlan_get_tx_queues, .setup = macvlan_setup, .validate = macvlan_validate, .newlink = macvlan_newlink, -- cgit v1.2.3-18-g5258 From 27e6c7d33835e7f347cdfb5025766b7d9a6596d1 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:01:53 +0000 Subject: enic: add support for multiple BARs Nic firmware can place resources (queues, intrs, etc) on multiple BARs, so allow driver to discover/map resources beyond BAR0. Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/enic/enic.h | 8 +++++--- drivers/net/enic/enic_main.c | 48 ++++++++++++++++++++++---------------------- drivers/net/enic/vnic_dev.c | 41 +++++++++++++++++++++++++++++-------- drivers/net/enic/vnic_dev.h | 5 ++++- 4 files changed, 66 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index c26cea0b300..cfe94b2e03a 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -33,13 +33,15 @@ #define DRV_NAME "enic" #define DRV_DESCRIPTION "Cisco 10G Ethernet Driver" -#define DRV_VERSION "1.0.0.933" -#define DRV_COPYRIGHT "Copyright 2008 Cisco Systems, Inc" +#define DRV_VERSION "1.1.0.100" +#define DRV_COPYRIGHT "Copyright 2008-2009 Cisco Systems, Inc" #define PFX DRV_NAME ": " #define ENIC_LRO_MAX_DESC 8 #define ENIC_LRO_MAX_AGGR 64 +#define ENIC_BARS_MAX 6 + enum enic_cq_index { ENIC_CQ_RQ, ENIC_CQ_WQ, @@ -73,7 +75,7 @@ struct enic { struct net_device *netdev; struct pci_dev *pdev; struct vnic_enet_config config; - struct vnic_dev_bar bar0; + struct vnic_dev_bar bar[ENIC_BARS_MAX]; struct vnic_dev *vdev; struct timer_list notify_timer; struct work_struct reset; diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 2ea036333db..2821a1db547 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -1609,12 +1609,6 @@ static void enic_clear_intr_mode(struct enic *enic) vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN); } -static void enic_iounmap(struct enic *enic) -{ - if (enic->bar0.vaddr) - iounmap(enic->bar0.vaddr); -} - static const struct net_device_ops enic_netdev_ops = { .ndo_open = enic_open, .ndo_stop = enic_stop, @@ -1633,6 +1627,15 @@ static const struct net_device_ops enic_netdev_ops = { #endif }; +static void enic_iounmap(struct enic *enic) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(enic->bar); i++) + if (enic->bar[i].vaddr) + iounmap(enic->bar[i].vaddr); +} + static int __devinit enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1710,31 +1713,28 @@ static int __devinit enic_probe(struct pci_dev *pdev, using_dac = 1; } - /* Map vNIC resources from BAR0 + /* Map vNIC resources from BAR0-5 */ - if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { - printk(KERN_ERR PFX - "BAR0 not memory-map'able, aborting.\n"); - err = -ENODEV; - goto err_out_release_regions; - } - - enic->bar0.vaddr = pci_iomap(pdev, 0, enic->bar0.len); - enic->bar0.bus_addr = pci_resource_start(pdev, 0); - enic->bar0.len = pci_resource_len(pdev, 0); - - if (!enic->bar0.vaddr) { - printk(KERN_ERR PFX - "Cannot memory-map BAR0 res hdr, aborting.\n"); - err = -ENODEV; - goto err_out_release_regions; + for (i = 0; i < ARRAY_SIZE(enic->bar); i++) { + if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM)) + continue; + enic->bar[i].len = pci_resource_len(pdev, i); + enic->bar[i].vaddr = pci_iomap(pdev, i, enic->bar[i].len); + if (!enic->bar[i].vaddr) { + printk(KERN_ERR PFX + "Cannot memory-map BAR %d, aborting.\n", i); + err = -ENODEV; + goto err_out_iounmap; + } + enic->bar[i].bus_addr = pci_resource_start(pdev, i); } /* Register vNIC device */ - enic->vdev = vnic_dev_register(NULL, enic, pdev, &enic->bar0); + enic->vdev = vnic_dev_register(NULL, enic, pdev, enic->bar, + ARRAY_SIZE(enic->bar)); if (!enic->vdev) { printk(KERN_ERR PFX "vNIC registration failed, aborting.\n"); diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c index e21b9d636ae..d5c28efedd9 100644 --- a/drivers/net/enic/vnic_dev.c +++ b/drivers/net/enic/vnic_dev.c @@ -31,6 +31,7 @@ struct vnic_res { void __iomem *vaddr; + dma_addr_t bus_addr; unsigned int count; }; @@ -67,12 +68,15 @@ void *vnic_dev_priv(struct vnic_dev *vdev) } static int vnic_dev_discover_res(struct vnic_dev *vdev, - struct vnic_dev_bar *bar) + struct vnic_dev_bar *bar, unsigned int num_bars) { struct vnic_resource_header __iomem *rh; struct vnic_resource __iomem *r; u8 type; + if (num_bars == 0) + return -EINVAL; + if (bar->len < VNIC_MAX_RES_HDR_SIZE) { printk(KERN_ERR "vNIC BAR0 res hdr length error\n"); return -EINVAL; @@ -104,7 +108,10 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev, r++; - if (bar_num != 0) /* only mapping in BAR0 resources */ + if (bar_num >= num_bars) + continue; + + if (!bar[bar_num].len || !bar[bar_num].vaddr) continue; switch (type) { @@ -114,13 +121,13 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev, case RES_TYPE_INTR_CTRL: /* each count is stride bytes long */ len = count * VNIC_RES_STRIDE; - if (len + bar_offset > bar->len) { + if (len + bar_offset > bar[bar_num].len) { printk(KERN_ERR "vNIC BAR0 resource %d " "out-of-bounds, offset 0x%x + " "size 0x%x > bar len 0x%lx\n", type, bar_offset, len, - bar->len); + bar[bar_num].len); return -EINVAL; } break; @@ -133,7 +140,9 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev, } vdev->res[type].count = count; - vdev->res[type].vaddr = (char __iomem *)bar->vaddr + bar_offset; + vdev->res[type].vaddr = (char __iomem *)bar[bar_num].vaddr + + bar_offset; + vdev->res[type].bus_addr = bar[bar_num].bus_addr + bar_offset; } return 0; @@ -163,6 +172,21 @@ void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type, } } +dma_addr_t vnic_dev_get_res_bus_addr(struct vnic_dev *vdev, + enum vnic_res_type type, unsigned int index) +{ + switch (type) { + case RES_TYPE_WQ: + case RES_TYPE_RQ: + case RES_TYPE_CQ: + case RES_TYPE_INTR_CTRL: + return vdev->res[type].bus_addr + + index * VNIC_RES_STRIDE; + default: + return vdev->res[type].bus_addr; + } +} + unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring, unsigned int desc_count, unsigned int desc_size) { @@ -257,7 +281,7 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, iowrite32(cmd, &devcmd->cmd); if ((_CMD_FLAGS(cmd) & _CMD_FLAGS_NOWAIT)) - return 0; + return 0; for (delay = 0; delay < wait; delay++) { @@ -684,7 +708,8 @@ void vnic_dev_unregister(struct vnic_dev *vdev) } struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, - void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar) + void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar, + unsigned int num_bars) { if (!vdev) { vdev = kzalloc(sizeof(struct vnic_dev), GFP_ATOMIC); @@ -695,7 +720,7 @@ struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, vdev->priv = priv; vdev->pdev = pdev; - if (vnic_dev_discover_res(vdev, bar)) + if (vnic_dev_discover_res(vdev, bar, num_bars)) goto err_out; vdev->devcmd = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD, 0); diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h index 8aa8db2fd03..d960edb8cdf 100644 --- a/drivers/net/enic/vnic_dev.h +++ b/drivers/net/enic/vnic_dev.h @@ -75,6 +75,8 @@ unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev, enum vnic_res_type type); void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type, unsigned int index); +dma_addr_t vnic_dev_get_res_bus_addr(struct vnic_dev *vdev, + enum vnic_res_type type, unsigned int index); unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring, unsigned int desc_count, unsigned int desc_size); void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring); @@ -117,6 +119,7 @@ void vnic_dev_set_intr_mode(struct vnic_dev *vdev, enum vnic_dev_intr_mode vnic_dev_get_intr_mode(struct vnic_dev *vdev); void vnic_dev_unregister(struct vnic_dev *vdev); struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, - void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar); + void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar, + unsigned int num_bars); #endif /* _VNIC_DEV_H_ */ -- cgit v1.2.3-18-g5258 From 4badc385d1a9e140ad0992537237fc22211adad0 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:01:58 +0000 Subject: enic: workaround A0 erratum A0 revision ASIC has an erratum on the RQ desc cache on chip where the cache can become corrupted causing pkt buf writes to wrong locations. The s/w workaround is to post a dummy RQ desc in the ring every 32 descs, causing a flush of the cache. A0 parts are not production, but there are enough of these parts in the wild in test setups to warrant including workaround. A1 revision ASIC parts fix erratum. Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/enic/enic_main.c | 50 +++++++++++++++++++++++++++++++++++++++++--- drivers/net/enic/vnic_dev.c | 19 +++++++++++++++++ drivers/net/enic/vnic_dev.h | 8 +++++++ drivers/net/enic/vnic_rq.h | 7 ++++++- 4 files changed, 80 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 2821a1db547..58cae6e6a59 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -851,6 +851,50 @@ static int enic_rq_alloc_buf(struct vnic_rq *rq) return 0; } +static int enic_rq_alloc_buf_a1(struct vnic_rq *rq) +{ + struct rq_enet_desc *desc = vnic_rq_next_desc(rq); + + if (vnic_rq_posting_soon(rq)) { + + /* SW workaround for A0 HW erratum: if we're just about + * to write posted_index, insert a dummy desc + * of type resvd + */ + + rq_enet_desc_enc(desc, 0, RQ_ENET_TYPE_RESV2, 0); + vnic_rq_post(rq, 0, 0, 0, 0); + } else { + return enic_rq_alloc_buf(rq); + } + + return 0; +} + +static int enic_set_rq_alloc_buf(struct enic *enic) +{ + enum vnic_dev_hw_version hw_ver; + int err; + + err = vnic_dev_hw_version(enic->vdev, &hw_ver); + if (err) + return err; + + switch (hw_ver) { + case VNIC_DEV_HW_VER_A1: + enic->rq_alloc_buf = enic_rq_alloc_buf_a1; + break; + case VNIC_DEV_HW_VER_A2: + case VNIC_DEV_HW_VER_UNKNOWN: + enic->rq_alloc_buf = enic_rq_alloc_buf; + break; + default: + return -ENODEV; + } + + return 0; +} + static int enic_get_skb_header(struct sk_buff *skb, void **iphdr, void **tcph, u64 *hdr_flags, void *priv) { @@ -1058,7 +1102,7 @@ static int enic_poll(struct napi_struct *napi, int budget) /* Replenish RQ */ - vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf); + vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf); } else { @@ -1093,7 +1137,7 @@ static int enic_poll_msix(struct napi_struct *napi, int budget) /* Replenish RQ */ - vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf); + vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf); /* Return intr event credits for this polling * cycle. An intr event is the completion of a @@ -1269,7 +1313,7 @@ static int enic_open(struct net_device *netdev) } for (i = 0; i < enic->rq_count; i++) { - err = vnic_rq_fill(&enic->rq[i], enic_rq_alloc_buf); + err = vnic_rq_fill(&enic->rq[i], enic->rq_alloc_buf); if (err) { printk(KERN_ERR PFX "%s: Unable to alloc receive buffers.\n", diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c index d5c28efedd9..c8d3fc7517b 100644 --- a/drivers/net/enic/vnic_dev.c +++ b/drivers/net/enic/vnic_dev.c @@ -349,6 +349,25 @@ int vnic_dev_fw_info(struct vnic_dev *vdev, return err; } +int vnic_dev_hw_version(struct vnic_dev *vdev, enum vnic_dev_hw_version *hw_ver) +{ + struct vnic_devcmd_fw_info *fw_info; + int err; + + err = vnic_dev_fw_info(vdev, &fw_info); + if (err) + return err; + + if (strncmp(fw_info->hw_version, "A1", sizeof("A1")) == 0) + *hw_ver = VNIC_DEV_HW_VER_A1; + else if (strncmp(fw_info->hw_version, "A2", sizeof("A2")) == 0) + *hw_ver = VNIC_DEV_HW_VER_A2; + else + *hw_ver = VNIC_DEV_HW_VER_UNKNOWN; + + return 0; +} + int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size, void *value) { diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h index d960edb8cdf..db1d63e0b97 100644 --- a/drivers/net/enic/vnic_dev.h +++ b/drivers/net/enic/vnic_dev.h @@ -41,6 +41,12 @@ static inline void writeq(u64 val, void __iomem *reg) } #endif +enum vnic_dev_hw_version { + VNIC_DEV_HW_VER_UNKNOWN, + VNIC_DEV_HW_VER_A1, + VNIC_DEV_HW_VER_A2, +}; + enum vnic_dev_intr_mode { VNIC_DEV_INTR_MODE_UNKNOWN, VNIC_DEV_INTR_MODE_INTX, @@ -88,6 +94,8 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, u64 *a0, u64 *a1, int wait); int vnic_dev_fw_info(struct vnic_dev *vdev, struct vnic_devcmd_fw_info **fw_info); +int vnic_dev_hw_version(struct vnic_dev *vdev, + enum vnic_dev_hw_version *hw_ver); int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size, void *value); int vnic_dev_stats_clear(struct vnic_dev *vdev); diff --git a/drivers/net/enic/vnic_rq.h b/drivers/net/enic/vnic_rq.h index fd0ef66d2e9..f7b5730cb74 100644 --- a/drivers/net/enic/vnic_rq.h +++ b/drivers/net/enic/vnic_rq.h @@ -143,6 +143,11 @@ static inline void vnic_rq_post(struct vnic_rq *rq, } } +static inline int vnic_rq_posting_soon(struct vnic_rq *rq) +{ + return ((rq->to_use->index & VNIC_RQ_RETURN_RATE) == 0); +} + static inline void vnic_rq_return_descs(struct vnic_rq *rq, unsigned int count) { rq->ring.desc_avail += count; @@ -186,7 +191,7 @@ static inline int vnic_rq_fill(struct vnic_rq *rq, { int err; - while (vnic_rq_desc_avail(rq) > 1) { + while (vnic_rq_desc_avail(rq) > 0) { err = (*buf_fill)(rq); if (err) -- cgit v1.2.3-18-g5258 From ea0d7d9181b0831f1b570b02fa02a15f25520c12 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:02:03 +0000 Subject: enic: bug fix: split TSO fragments larger than 16K into multiple descs enic WQ desc supports a maximum 16K buf size, so split any send fragments larger than 16K into several descs. Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/enic/enic_main.c | 87 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 58cae6e6a59..bc5cb225dda 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -44,10 +44,15 @@ #include "enic.h" #define ENIC_NOTIFY_TIMER_PERIOD (2 * HZ) +#define WQ_ENET_MAX_DESC_LEN (1 << WQ_ENET_LEN_BITS) +#define MAX_TSO (1 << 16) +#define ENIC_DESC_MAX_SPLITS (MAX_TSO / WQ_ENET_MAX_DESC_LEN + 1) + +#define PCI_DEVICE_ID_CISCO_VIC_ENET 0x0043 /* ethernet vnic */ /* Supported devices */ static struct pci_device_id enic_id_table[] = { - { PCI_VDEVICE(CISCO, 0x0043) }, + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) }, { 0, } /* end of table */ }; @@ -310,7 +315,8 @@ static int enic_wq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc, opaque); if (netif_queue_stopped(enic->netdev) && - vnic_wq_desc_avail(&enic->wq[q_number]) >= MAX_SKB_FRAGS + 1) + vnic_wq_desc_avail(&enic->wq[q_number]) >= + (MAX_SKB_FRAGS + ENIC_DESC_MAX_SPLITS)) netif_wake_queue(enic->netdev); spin_unlock(&enic->wq_lock[q_number]); @@ -525,7 +531,11 @@ static inline void enic_queue_wq_skb_vlan(struct enic *enic, unsigned int len_left = skb->len - head_len; int eop = (len_left == 0); - /* Queue the main skb fragment */ + /* Queue the main skb fragment. The fragments are no larger + * than max MTU(9000)+ETH_HDR_LEN(14) bytes, which is less + * than WQ_ENET_MAX_DESC_LEN length. So only one descriptor + * per fragment is queued. + */ enic_queue_wq_desc(wq, skb, pci_map_single(enic->pdev, skb->data, head_len, PCI_DMA_TODEVICE), @@ -547,7 +557,11 @@ static inline void enic_queue_wq_skb_csum_l4(struct enic *enic, unsigned int csum_offset = hdr_len + skb->csum_offset; int eop = (len_left == 0); - /* Queue the main skb fragment */ + /* Queue the main skb fragment. The fragments are no larger + * than max MTU(9000)+ETH_HDR_LEN(14) bytes, which is less + * than WQ_ENET_MAX_DESC_LEN length. So only one descriptor + * per fragment is queued. + */ enic_queue_wq_desc_csum_l4(wq, skb, pci_map_single(enic->pdev, skb->data, head_len, PCI_DMA_TODEVICE), @@ -565,10 +579,14 @@ static inline void enic_queue_wq_skb_tso(struct enic *enic, struct vnic_wq *wq, struct sk_buff *skb, unsigned int mss, int vlan_tag_insert, unsigned int vlan_tag) { - unsigned int head_len = skb_headlen(skb); - unsigned int len_left = skb->len - head_len; + unsigned int frag_len_left = skb_headlen(skb); + unsigned int len_left = skb->len - frag_len_left; unsigned int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); int eop = (len_left == 0); + unsigned int len; + dma_addr_t dma_addr; + unsigned int offset = 0; + skb_frag_t *frag; /* Preload TCP csum field with IP pseudo hdr calculated * with IP length set to zero. HW will later add in length @@ -584,17 +602,49 @@ static inline void enic_queue_wq_skb_tso(struct enic *enic, &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); } - /* Queue the main skb fragment */ - enic_queue_wq_desc_tso(wq, skb, - pci_map_single(enic->pdev, skb->data, - head_len, PCI_DMA_TODEVICE), - head_len, - mss, hdr_len, - vlan_tag_insert, vlan_tag, - eop); + /* Queue WQ_ENET_MAX_DESC_LEN length descriptors + * for the main skb fragment + */ + while (frag_len_left) { + len = min(frag_len_left, (unsigned int)WQ_ENET_MAX_DESC_LEN); + dma_addr = pci_map_single(enic->pdev, skb->data + offset, + len, PCI_DMA_TODEVICE); + enic_queue_wq_desc_tso(wq, skb, + dma_addr, + len, + mss, hdr_len, + vlan_tag_insert, vlan_tag, + eop && (len == frag_len_left)); + frag_len_left -= len; + offset += len; + } - if (!eop) - enic_queue_wq_skb_cont(enic, wq, skb, len_left); + if (eop) + return; + + /* Queue WQ_ENET_MAX_DESC_LEN length descriptors + * for additional data fragments + */ + for (frag = skb_shinfo(skb)->frags; len_left; frag++) { + len_left -= frag->size; + frag_len_left = frag->size; + offset = frag->page_offset; + + while (frag_len_left) { + len = min(frag_len_left, + (unsigned int)WQ_ENET_MAX_DESC_LEN); + dma_addr = pci_map_page(enic->pdev, frag->page, + offset, len, + PCI_DMA_TODEVICE); + enic_queue_wq_desc_cont(wq, skb, + dma_addr, + len, + (len_left == 0) && + (len == frag_len_left)); /* EOP? */ + frag_len_left -= len; + offset += len; + } + } } static inline void enic_queue_wq_skb(struct enic *enic, @@ -648,7 +698,8 @@ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb, spin_lock_irqsave(&enic->wq_lock[0], flags); - if (vnic_wq_desc_avail(wq) < skb_shinfo(skb)->nr_frags + 1) { + if (vnic_wq_desc_avail(wq) < + skb_shinfo(skb)->nr_frags + ENIC_DESC_MAX_SPLITS) { netif_stop_queue(netdev); /* This is a hard error, log it */ printk(KERN_ERR PFX "%s: BUG! Tx ring full when " @@ -659,7 +710,7 @@ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb, enic_queue_wq_skb(enic, wq, skb); - if (vnic_wq_desc_avail(wq) < MAX_SKB_FRAGS + 1) + if (vnic_wq_desc_avail(wq) < MAX_SKB_FRAGS + ENIC_DESC_MAX_SPLITS) netif_stop_queue(netdev); spin_unlock_irqrestore(&enic->wq_lock[0], flags); -- cgit v1.2.3-18-g5258 From d19e22dc2c1c43724c1d9ce4a5456ae74eeb6da8 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:02:08 +0000 Subject: enic: use netdev_alloc_skb Use netdev_alloc_skb rather than dev_alloc_skb Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/enic/enic_main.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index bc5cb225dda..73f01075287 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -869,11 +869,12 @@ static void enic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf) dev_kfree_skb_any(buf->os_buf); } -static inline struct sk_buff *enic_rq_alloc_skb(unsigned int size) +static inline struct sk_buff *enic_rq_alloc_skb(struct net_device *netdev, + unsigned int size) { struct sk_buff *skb; - skb = dev_alloc_skb(size + NET_IP_ALIGN); + skb = netdev_alloc_skb(netdev, size + NET_IP_ALIGN); if (skb) skb_reserve(skb, NET_IP_ALIGN); @@ -884,12 +885,13 @@ static inline struct sk_buff *enic_rq_alloc_skb(unsigned int size) static int enic_rq_alloc_buf(struct vnic_rq *rq) { struct enic *enic = vnic_dev_priv(rq->vdev); + struct net_device *netdev = enic->netdev; struct sk_buff *skb; - unsigned int len = enic->netdev->mtu + ETH_HLEN; + unsigned int len = netdev->mtu + ETH_HLEN; unsigned int os_buf_index = 0; dma_addr_t dma_addr; - skb = enic_rq_alloc_skb(len); + skb = enic_rq_alloc_skb(netdev, len); if (!skb) return -ENOMEM; -- cgit v1.2.3-18-g5258 From 56ac88b38e5918d92bdfc97c528068e45ff4581c Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:02:14 +0000 Subject: enic: bug fix: protect fw call i/f with spinlock Some driver -> nic firmware calls weren't guarded with a spinlock, exposing the call i/f to a race between two threads Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/enic/enic_main.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 73f01075287..36cf0fcc66f 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -1316,6 +1316,7 @@ static int enic_notify_set(struct enic *enic) { int err; + spin_lock(&enic->devcmd_lock); switch (vnic_dev_get_intr_mode(enic->vdev)) { case VNIC_DEV_INTR_MODE_INTX: err = vnic_dev_notify_set(enic->vdev, ENIC_INTX_NOTIFY); @@ -1327,6 +1328,7 @@ static int enic_notify_set(struct enic *enic) err = vnic_dev_notify_set(enic->vdev, -1 /* no intr */); break; } + spin_unlock(&enic->devcmd_lock); return err; } @@ -1380,12 +1382,16 @@ static int enic_open(struct net_device *netdev) for (i = 0; i < enic->rq_count; i++) vnic_rq_enable(&enic->rq[i]); + spin_lock(&enic->devcmd_lock); enic_add_station_addr(enic); + spin_unlock(&enic->devcmd_lock); enic_set_multicast_list(netdev); netif_wake_queue(netdev); napi_enable(&enic->napi); + spin_lock(&enic->devcmd_lock); vnic_dev_enable(enic->vdev); + spin_unlock(&enic->devcmd_lock); for (i = 0; i < enic->intr_count; i++) vnic_intr_unmask(&enic->intr[i]); @@ -1395,7 +1401,9 @@ static int enic_open(struct net_device *netdev) return 0; err_out_notify_unset: + spin_lock(&enic->devcmd_lock); vnic_dev_notify_unset(enic->vdev); + spin_unlock(&enic->devcmd_lock); err_out_free_intr: enic_free_intr(enic); @@ -1411,7 +1419,9 @@ static int enic_stop(struct net_device *netdev) del_timer_sync(&enic->notify_timer); + spin_lock(&enic->devcmd_lock); vnic_dev_disable(enic->vdev); + spin_unlock(&enic->devcmd_lock); napi_disable(&enic->napi); netif_stop_queue(netdev); @@ -1429,7 +1439,9 @@ static int enic_stop(struct net_device *netdev) return err; } + spin_lock(&enic->devcmd_lock); vnic_dev_notify_unset(enic->vdev); + spin_unlock(&enic->devcmd_lock); enic_free_intr(enic); (void)vnic_cq_service(&enic->cq[ENIC_CQ_RQ], -- cgit v1.2.3-18-g5258 From 350991e12ac1ac407850169a0d65f522a7fd029e Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:02:19 +0000 Subject: enic: bug fix: included MAC drops in rx_dropped netstat Bug fix: included MAC drops in rx_dropped netstat. Also track Rx trunctations stat at the MAC Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/enic/enic.h | 1 + drivers/net/enic/enic_main.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index cfe94b2e03a..f7c5b334bc7 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -99,6 +99,7 @@ struct enic { ____cacheline_aligned struct vnic_rq rq[1]; unsigned int rq_count; int (*rq_alloc_buf)(struct vnic_rq *rq); + u64 rq_truncated_pkts; u64 rq_bad_fcs; struct napi_struct napi; struct net_lro_mgr lro_mgr; diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 36cf0fcc66f..b265b103c21 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -738,8 +738,9 @@ static struct net_device_stats *enic_get_stats(struct net_device *netdev) net_stats->rx_bytes = stats->rx.rx_bytes_ok; net_stats->rx_errors = stats->rx.rx_errors; net_stats->multicast = stats->rx.rx_multicast_frames_ok; + net_stats->rx_over_errors = enic->rq_truncated_pkts; net_stats->rx_crc_errors = enic->rq_bad_fcs; - net_stats->rx_dropped = stats->rx.rx_no_bufs; + net_stats->rx_dropped = stats->rx.rx_no_bufs + stats->rx.rx_drop; return net_stats; } @@ -1029,8 +1030,12 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, if (packet_error) { - if (bytes_written > 0 && !fcs_ok) - enic->rq_bad_fcs++; + if (!fcs_ok) { + if (bytes_written > 0) + enic->rq_bad_fcs++; + else if (bytes_written == 0) + enic->rq_truncated_pkts++; + } dev_kfree_skb_any(skb); -- cgit v1.2.3-18-g5258 From 6ba9cdc09678d6925c205ef0b0bd374e31589ecf Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:02:24 +0000 Subject: enic: provision for multiple Rx/Tx queues; prepare for RSS support Provision for multiple Rx/Tx queues. Max of 8 WQs and 8 RQs. Max for completion queue is 8+8=16 and max for interrupt resources is 8+8+2. Add driver/firmware interface for setting up RSS secret key and indirection table. Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/enic/enic.h | 16 ++++++++++------ drivers/net/enic/enic_main.c | 6 +++--- drivers/net/enic/enic_res.c | 33 ++++++++++++++++++++++++++++----- drivers/net/enic/enic_res.h | 2 ++ drivers/net/enic/vnic_nic.h | 7 +++++++ 5 files changed, 50 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index f7c5b334bc7..e1c2076228b 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -29,6 +29,7 @@ #include "vnic_cq.h" #include "vnic_intr.h" #include "vnic_stats.h" +#include "vnic_nic.h" #include "vnic_rss.h" #define DRV_NAME "enic" @@ -42,17 +43,20 @@ #define ENIC_BARS_MAX 6 +#define ENIC_WQ_MAX 8 +#define ENIC_RQ_MAX 8 +#define ENIC_CQ_MAX (ENIC_WQ_MAX + ENIC_RQ_MAX) +#define ENIC_INTR_MAX (ENIC_CQ_MAX + 2) + enum enic_cq_index { ENIC_CQ_RQ, ENIC_CQ_WQ, - ENIC_CQ_MAX, }; enum enic_intx_intr_index { ENIC_INTX_WQ_RQ, ENIC_INTX_ERR, ENIC_INTX_NOTIFY, - ENIC_INTX_MAX, }; enum enic_msix_intr_index { @@ -90,13 +94,13 @@ struct enic { u32 port_mtu; /* work queue cache line section */ - ____cacheline_aligned struct vnic_wq wq[1]; - spinlock_t wq_lock[1]; + ____cacheline_aligned struct vnic_wq wq[ENIC_WQ_MAX]; + spinlock_t wq_lock[ENIC_WQ_MAX]; unsigned int wq_count; struct vlan_group *vlan_group; /* receive queue cache line section */ - ____cacheline_aligned struct vnic_rq rq[1]; + ____cacheline_aligned struct vnic_rq rq[ENIC_RQ_MAX]; unsigned int rq_count; int (*rq_alloc_buf)(struct vnic_rq *rq); u64 rq_truncated_pkts; @@ -106,7 +110,7 @@ struct enic { struct net_lro_desc lro_desc[ENIC_LRO_MAX_DESC]; /* interrupt resource cache line section */ - ____cacheline_aligned struct vnic_intr intr[ENIC_MSIX_MAX]; + ____cacheline_aligned struct vnic_intr intr[ENIC_INTR_MAX]; unsigned int intr_count; u32 __iomem *legacy_pba; /* memory-mapped */ diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index b265b103c21..e01067e727b 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -1586,7 +1586,7 @@ static int enic_set_niccfg(struct enic *enic) const u8 ig_vlan_strip_en = 1; /* Enable VLAN tag stripping. RSS not enabled (yet). - */ + */ return enic_set_nic_cfg(enic, rss_default_cpu, rss_hash_type, @@ -1621,8 +1621,8 @@ static void enic_reset(struct work_struct *work) static int enic_set_intr_mode(struct enic *enic) { - unsigned int n = ARRAY_SIZE(enic->rq); - unsigned int m = ARRAY_SIZE(enic->wq); + unsigned int n = 1; + unsigned int m = 1; unsigned int i; /* Set interrupt mode (INTx, MSI, MSI-X) depending diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c index e5fc9384f8f..32111144efc 100644 --- a/drivers/net/enic/enic_res.c +++ b/drivers/net/enic/enic_res.c @@ -156,6 +156,22 @@ int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type, return vnic_dev_cmd(enic->vdev, CMD_NIC_CFG, &a0, &a1, wait); } +int enic_set_rss_key(struct enic *enic, dma_addr_t key_pa, u64 len) +{ + u64 a0 = (u64)key_pa, a1 = len; + int wait = 1000; + + return vnic_dev_cmd(enic->vdev, CMD_RSS_KEY, &a0, &a1, wait); +} + +int enic_set_rss_cpu(struct enic *enic, dma_addr_t cpu_pa, u64 len) +{ + u64 a0 = (u64)cpu_pa, a1 = len; + int wait = 1000; + + return vnic_dev_cmd(enic->vdev, CMD_RSS_CPU, &a0, &a1, wait); +} + void enic_free_vnic_resources(struct enic *enic) { unsigned int i; @@ -172,11 +188,18 @@ void enic_free_vnic_resources(struct enic *enic) void enic_get_res_counts(struct enic *enic) { - enic->wq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ); - enic->rq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_RQ); - enic->cq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_CQ); - enic->intr_count = vnic_dev_get_res_count(enic->vdev, - RES_TYPE_INTR_CTRL); + enic->wq_count = min_t(int, + vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ), + ENIC_WQ_MAX); + enic->rq_count = min_t(int, + vnic_dev_get_res_count(enic->vdev, RES_TYPE_RQ), + ENIC_RQ_MAX); + enic->cq_count = min_t(int, + vnic_dev_get_res_count(enic->vdev, RES_TYPE_CQ), + ENIC_CQ_MAX); + enic->intr_count = min_t(int, + vnic_dev_get_res_count(enic->vdev, RES_TYPE_INTR_CTRL), + ENIC_INTR_MAX); printk(KERN_INFO PFX "vNIC resources avail: " "wq %d rq %d cq %d intr %d\n", diff --git a/drivers/net/enic/enic_res.h b/drivers/net/enic/enic_res.h index 7bf272fa859..abc19741ab0 100644 --- a/drivers/net/enic/enic_res.h +++ b/drivers/net/enic/enic_res.h @@ -139,6 +139,8 @@ void enic_del_vlan(struct enic *enic, u16 vlanid); int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type, u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable, u8 tso_ipid_split_en, u8 ig_vlan_strip_en); +int enic_set_rss_key(struct enic *enic, dma_addr_t key_pa, u64 len); +int enic_set_rss_cpu(struct enic *enic, dma_addr_t cpu_pa, u64 len); void enic_get_res_counts(struct enic *enic); void enic_init_vnic_resources(struct enic *enic); int enic_alloc_vnic_resources(struct enic *); diff --git a/drivers/net/enic/vnic_nic.h b/drivers/net/enic/vnic_nic.h index dadf26fae69..eeaf329945d 100644 --- a/drivers/net/enic/vnic_nic.h +++ b/drivers/net/enic/vnic_nic.h @@ -41,6 +41,13 @@ #define NIC_CFG_IG_VLAN_STRIP_EN_MASK_FIELD 1UL #define NIC_CFG_IG_VLAN_STRIP_EN_SHIFT 24 +#define NIC_CFG_RSS_HASH_TYPE_IPV4 (1 << 0) +#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV4 (1 << 1) +#define NIC_CFG_RSS_HASH_TYPE_IPV6 (1 << 2) +#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6 (1 << 3) +#define NIC_CFG_RSS_HASH_TYPE_IPV6_EX (1 << 4) +#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6_EX (1 << 5) + static inline void vnic_set_nic_cfg(u32 *nic_cfg, u8 rss_default_cpu, u8 rss_hash_type, u8 rss_hash_bits, u8 rss_base_cpu, -- cgit v1.2.3-18-g5258 From 9f63a7c6aef00a8eafa7521342099f199f68c575 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:02:29 +0000 Subject: enic: bug fix: enable VLAN filtering Bug fix: enable VLAN filtering Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/enic/enic_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index e01067e727b..e0bf224d7f9 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -1968,7 +1968,8 @@ static int __devinit enic_probe(struct pci_dev *pdev, break; } - netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + netdev->features |= NETIF_F_HW_VLAN_TX | + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; if (ENIC_SETTING(enic, TXCSUM)) netdev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; if (ENIC_SETTING(enic, TSO)) -- cgit v1.2.3-18-g5258 From d73149f51e165f5872bc431ae181650396145265 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:02:35 +0000 Subject: enic: changes to driver/firmware interface Deprecate some old APIa; change arguments to stats dump all API; add new interrupt assert API Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/enic/vnic_dev.c | 14 ++++++++++++++ drivers/net/enic/vnic_dev.h | 1 + drivers/net/enic/vnic_devcmd.h | 20 ++++++++++---------- drivers/net/enic/vnic_intr.c | 5 +++++ 4 files changed, 30 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c index c8d3fc7517b..29a48e8b59d 100644 --- a/drivers/net/enic/vnic_dev.c +++ b/drivers/net/enic/vnic_dev.c @@ -560,6 +560,20 @@ void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr) printk(KERN_ERR "Can't del addr [%pM], %d\n", addr, err); } +int vnic_dev_raise_intr(struct vnic_dev *vdev, u16 intr) +{ + u64 a0 = intr, a1 = 0; + int wait = 1000; + int err; + + err = vnic_dev_cmd(vdev, CMD_IAR, &a0, &a1, wait); + if (err) + printk(KERN_ERR "Failed to raise INTR[%d], err %d\n", + intr, err); + + return err; +} + int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr) { u64 a0, a1; diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h index db1d63e0b97..fc5e3eb35a5 100644 --- a/drivers/net/enic/vnic_dev.h +++ b/drivers/net/enic/vnic_dev.h @@ -106,6 +106,7 @@ void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast, void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr); void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr); int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr); +int vnic_dev_raise_intr(struct vnic_dev *vdev, u16 intr); int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr); void vnic_dev_notify_unset(struct vnic_dev *vdev); int vnic_dev_link_status(struct vnic_dev *vdev); diff --git a/drivers/net/enic/vnic_devcmd.h b/drivers/net/enic/vnic_devcmd.h index 2587f34fbfb..d78bbcc1fdf 100644 --- a/drivers/net/enic/vnic_devcmd.h +++ b/drivers/net/enic/vnic_devcmd.h @@ -105,14 +105,6 @@ enum vnic_devcmd_cmd { CMD_MAC_ADDR = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ENET | _CMD_VTYPE_FC, 9), - /* disable/enable promisc mode: (u8)a0=0/1 */ -/***** XXX DEPRECATED *****/ - CMD_PROMISC_MODE = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 10), - - /* disable/enable all-multi mode: (u8)a0=0/1 */ -/***** XXX DEPRECATED *****/ - CMD_ALLMULTI_MODE = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 11), - /* add addr from (u48)a0 */ CMD_ADDR_ADD = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET | _CMD_VTYPE_FC, 12), @@ -182,7 +174,9 @@ enum vnic_devcmd_cmd { /* disable virtual link */ CMD_DISABLE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 29), - /* stats dump all vnics on uplink in mem: (u64)a0=paddr (u32)a1=uif */ + /* stats dump sum of all vnic stats on same uplink in mem: + * (u64)a0=paddr + * (u16)a1=sizeof stats area */ CMD_STATS_DUMP_ALL = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 30), /* init status: @@ -211,7 +205,12 @@ enum vnic_devcmd_cmd { /* persistent binding info * in: (u64)a0=paddr of arg * (u32)a1=CMD_PERBI_XXX */ - CMD_PERBI = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_FC, 37), + CMD_PERBI = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_FC, 37), + + /* Interrupt Assert Register functionality + * in: (u16)a0=interrupt number to assert + */ + CMD_IAR = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 38), }; /* flags for CMD_OPEN */ @@ -244,6 +243,7 @@ enum vnic_devcmd_error { ERR_ENOMEM = 7, ERR_ETIMEDOUT = 8, ERR_ELINKDOWN = 9, + ERR_EMAXRES = 10, }; struct vnic_devcmd_fw_info { diff --git a/drivers/net/enic/vnic_intr.c b/drivers/net/enic/vnic_intr.c index ddc38f8f465..1f8786d7195 100644 --- a/drivers/net/enic/vnic_intr.c +++ b/drivers/net/enic/vnic_intr.c @@ -60,3 +60,8 @@ void vnic_intr_clean(struct vnic_intr *intr) { iowrite32(0, &intr->ctrl->int_credits); } + +void vnic_intr_raise(struct vnic_intr *intr) +{ + vnic_dev_raise_intr(intr->vdev, (u16)intr->index); +} -- cgit v1.2.3-18-g5258 From 491598a44f12fe8b862ab4123de1a1ffe9b86832 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:02:40 +0000 Subject: enic: bug fix: check for zero port MTU before posting warning Nic firmware can return zero for port MTU, so check for non-zero value before checking for change in port MTU. Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/enic/enic_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index e0bf224d7f9..f800218c659 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -362,7 +362,7 @@ static void enic_mtu_check(struct enic *enic) { u32 mtu = vnic_dev_mtu(enic->vdev); - if (mtu != enic->port_mtu) { + if (mtu && mtu != enic->port_mtu) { if (mtu < enic->netdev->mtu) printk(KERN_WARNING PFX "%s: interface MTU (%d) set higher " -- cgit v1.2.3-18-g5258 From 6fdfa97073a2bcbb60d900654c612b2ff09b9cb7 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 3 Sep 2009 17:02:45 +0000 Subject: enic: organize device initialization/deinit into separate functions To unclutter probe() a little bit, put all device initialization code in one spot and device deinit code in another spot. Also remove unused rq->buf_index variable/func. Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/enic/enic_main.c | 145 ++++++++++++++++++++++++++----------------- drivers/net/enic/vnic_rq.c | 27 +++++--- drivers/net/enic/vnic_rq.h | 12 ++-- drivers/net/enic/vnic_wq.c | 20 +++++- drivers/net/enic/vnic_wq.h | 4 ++ 5 files changed, 133 insertions(+), 75 deletions(-) (limited to 'drivers') diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index f800218c659..d69d52ed772 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -1741,6 +1741,88 @@ static const struct net_device_ops enic_netdev_ops = { #endif }; +void enic_dev_deinit(struct enic *enic) +{ + netif_napi_del(&enic->napi); + enic_free_vnic_resources(enic); + enic_clear_intr_mode(enic); +} + +int enic_dev_init(struct enic *enic) +{ + struct net_device *netdev = enic->netdev; + int err; + + /* Get vNIC configuration + */ + + err = enic_get_vnic_config(enic); + if (err) { + printk(KERN_ERR PFX + "Get vNIC configuration failed, aborting.\n"); + return err; + } + + /* Get available resource counts + */ + + enic_get_res_counts(enic); + + /* Set interrupt mode based on resource counts and system + * capabilities + */ + + err = enic_set_intr_mode(enic); + if (err) { + printk(KERN_ERR PFX + "Failed to set intr mode, aborting.\n"); + return err; + } + + /* Allocate and configure vNIC resources + */ + + err = enic_alloc_vnic_resources(enic); + if (err) { + printk(KERN_ERR PFX + "Failed to alloc vNIC resources, aborting.\n"); + goto err_out_free_vnic_resources; + } + + enic_init_vnic_resources(enic); + + err = enic_set_rq_alloc_buf(enic); + if (err) { + printk(KERN_ERR PFX + "Failed to set RQ buffer allocator, aborting.\n"); + goto err_out_free_vnic_resources; + } + + err = enic_set_niccfg(enic); + if (err) { + printk(KERN_ERR PFX + "Failed to config nic, aborting.\n"); + goto err_out_free_vnic_resources; + } + + switch (vnic_dev_get_intr_mode(enic->vdev)) { + default: + netif_napi_add(netdev, &enic->napi, enic_poll, 64); + break; + case VNIC_DEV_INTR_MODE_MSIX: + netif_napi_add(netdev, &enic->napi, enic_poll_msix, 64); + break; + } + + return 0; + +err_out_free_vnic_resources: + enic_clear_intr_mode(enic); + enic_free_vnic_resources(enic); + + return err; +} + static void enic_iounmap(struct enic *enic) { unsigned int i; @@ -1883,51 +1965,13 @@ static int __devinit enic_probe(struct pci_dev *pdev, goto err_out_dev_close; } - /* Get vNIC configuration - */ - - err = enic_get_vnic_config(enic); + err = enic_dev_init(enic); if (err) { printk(KERN_ERR PFX - "Get vNIC configuration failed, aborting.\n"); + "Device initialization failed, aborting.\n"); goto err_out_dev_close; } - /* Get available resource counts - */ - - enic_get_res_counts(enic); - - /* Set interrupt mode based on resource counts and system - * capabilities - */ - - err = enic_set_intr_mode(enic); - if (err) { - printk(KERN_ERR PFX - "Failed to set intr mode, aborting.\n"); - goto err_out_dev_close; - } - - /* Allocate and configure vNIC resources - */ - - err = enic_alloc_vnic_resources(enic); - if (err) { - printk(KERN_ERR PFX - "Failed to alloc vNIC resources, aborting.\n"); - goto err_out_free_vnic_resources; - } - - enic_init_vnic_resources(enic); - - err = enic_set_niccfg(enic); - if (err) { - printk(KERN_ERR PFX - "Failed to config nic, aborting.\n"); - goto err_out_free_vnic_resources; - } - /* Setup notification timer, HW reset task, and locks */ @@ -1952,22 +1996,13 @@ static int __devinit enic_probe(struct pci_dev *pdev, if (err) { printk(KERN_ERR PFX "Invalid MAC address, aborting.\n"); - goto err_out_free_vnic_resources; + goto err_out_dev_deinit; } netdev->netdev_ops = &enic_netdev_ops; netdev->watchdog_timeo = 2 * HZ; netdev->ethtool_ops = &enic_ethtool_ops; - switch (vnic_dev_get_intr_mode(enic->vdev)) { - default: - netif_napi_add(netdev, &enic->napi, enic_poll, 64); - break; - case VNIC_DEV_INTR_MODE_MSIX: - netif_napi_add(netdev, &enic->napi, enic_poll_msix, 64); - break; - } - netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; if (ENIC_SETTING(enic, TXCSUM)) @@ -1995,17 +2030,16 @@ static int __devinit enic_probe(struct pci_dev *pdev, if (err) { printk(KERN_ERR PFX "Cannot register net device, aborting.\n"); - goto err_out_free_vnic_resources; + goto err_out_dev_deinit; } return 0; -err_out_free_vnic_resources: - enic_free_vnic_resources(enic); +err_out_dev_deinit: + enic_dev_deinit(enic); err_out_dev_close: vnic_dev_close(enic->vdev); err_out_vnic_unregister: - enic_clear_intr_mode(enic); vnic_dev_unregister(enic->vdev); err_out_iounmap: enic_iounmap(enic); @@ -2029,9 +2063,8 @@ static void __devexit enic_remove(struct pci_dev *pdev) flush_scheduled_work(); unregister_netdev(netdev); - enic_free_vnic_resources(enic); + enic_dev_deinit(enic); vnic_dev_close(enic->vdev); - enic_clear_intr_mode(enic); vnic_dev_unregister(enic->vdev); enic_iounmap(enic); pci_release_regions(pdev); diff --git a/drivers/net/enic/vnic_rq.c b/drivers/net/enic/vnic_rq.c index 9365e63e821..75583978a5e 100644 --- a/drivers/net/enic/vnic_rq.c +++ b/drivers/net/enic/vnic_rq.c @@ -62,7 +62,6 @@ static int vnic_rq_alloc_bufs(struct vnic_rq *rq) } rq->to_use = rq->to_clean = rq->bufs[0]; - rq->buf_index = 0; return 0; } @@ -113,12 +112,12 @@ int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index, return 0; } -void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index, +void vnic_rq_init_start(struct vnic_rq *rq, unsigned int cq_index, + unsigned int fetch_index, unsigned int posted_index, unsigned int error_interrupt_enable, unsigned int error_interrupt_offset) { u64 paddr; - u32 fetch_index; paddr = (u64)rq->ring.base_addr | VNIC_PADDR_TARGET; writeq(paddr, &rq->ctrl->ring_base); @@ -128,15 +127,27 @@ void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index, iowrite32(error_interrupt_offset, &rq->ctrl->error_interrupt_offset); iowrite32(0, &rq->ctrl->dropped_packet_count); iowrite32(0, &rq->ctrl->error_status); + iowrite32(fetch_index, &rq->ctrl->fetch_index); + iowrite32(posted_index, &rq->ctrl->posted_index); - /* Use current fetch_index as the ring starting point */ - fetch_index = ioread32(&rq->ctrl->fetch_index); rq->to_use = rq->to_clean = &rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES] [fetch_index % VNIC_RQ_BUF_BLK_ENTRIES]; - iowrite32(fetch_index, &rq->ctrl->posted_index); +} + +void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index, + unsigned int error_interrupt_enable, + unsigned int error_interrupt_offset) +{ + u32 fetch_index; - rq->buf_index = 0; + /* Use current fetch_index as the ring starting point */ + fetch_index = ioread32(&rq->ctrl->fetch_index); + + vnic_rq_init_start(rq, cq_index, + fetch_index, fetch_index, + error_interrupt_enable, + error_interrupt_offset); } unsigned int vnic_rq_error_status(struct vnic_rq *rq) @@ -192,8 +203,6 @@ void vnic_rq_clean(struct vnic_rq *rq, [fetch_index % VNIC_RQ_BUF_BLK_ENTRIES]; iowrite32(fetch_index, &rq->ctrl->posted_index); - rq->buf_index = 0; - vnic_dev_clear_desc_ring(&rq->ring); } diff --git a/drivers/net/enic/vnic_rq.h b/drivers/net/enic/vnic_rq.h index f7b5730cb74..35e736cc2d8 100644 --- a/drivers/net/enic/vnic_rq.h +++ b/drivers/net/enic/vnic_rq.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. + * Copyright 2008, 2009 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. * * This program is free software; you may redistribute it and/or modify @@ -79,7 +79,6 @@ struct vnic_rq { struct vnic_rq_buf *to_use; struct vnic_rq_buf *to_clean; void *os_buf_head; - unsigned int buf_index; unsigned int pkts_outstanding; }; @@ -105,11 +104,6 @@ static inline unsigned int vnic_rq_next_index(struct vnic_rq *rq) return rq->to_use->index; } -static inline unsigned int vnic_rq_next_buf_index(struct vnic_rq *rq) -{ - return rq->buf_index++; -} - static inline void vnic_rq_post(struct vnic_rq *rq, void *os_buf, unsigned int os_buf_index, dma_addr_t dma_addr, unsigned int len) @@ -204,6 +198,10 @@ static inline int vnic_rq_fill(struct vnic_rq *rq, void vnic_rq_free(struct vnic_rq *rq); int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index, unsigned int desc_count, unsigned int desc_size); +void vnic_rq_init_start(struct vnic_rq *rq, unsigned int cq_index, + unsigned int fetch_index, unsigned int posted_index, + unsigned int error_interrupt_enable, + unsigned int error_interrupt_offset); void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index, unsigned int error_interrupt_enable, unsigned int error_interrupt_offset); diff --git a/drivers/net/enic/vnic_wq.c b/drivers/net/enic/vnic_wq.c index a576d04708e..d2e00e51b7b 100644 --- a/drivers/net/enic/vnic_wq.c +++ b/drivers/net/enic/vnic_wq.c @@ -112,7 +112,8 @@ int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index, return 0; } -void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index, +void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index, + unsigned int fetch_index, unsigned int posted_index, unsigned int error_interrupt_enable, unsigned int error_interrupt_offset) { @@ -121,12 +122,25 @@ void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index, paddr = (u64)wq->ring.base_addr | VNIC_PADDR_TARGET; writeq(paddr, &wq->ctrl->ring_base); iowrite32(wq->ring.desc_count, &wq->ctrl->ring_size); - iowrite32(0, &wq->ctrl->fetch_index); - iowrite32(0, &wq->ctrl->posted_index); + iowrite32(fetch_index, &wq->ctrl->fetch_index); + iowrite32(posted_index, &wq->ctrl->posted_index); iowrite32(cq_index, &wq->ctrl->cq_index); iowrite32(error_interrupt_enable, &wq->ctrl->error_interrupt_enable); iowrite32(error_interrupt_offset, &wq->ctrl->error_interrupt_offset); iowrite32(0, &wq->ctrl->error_status); + + wq->to_use = wq->to_clean = + &wq->bufs[fetch_index / VNIC_WQ_BUF_BLK_ENTRIES] + [fetch_index % VNIC_WQ_BUF_BLK_ENTRIES]; +} + +void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index, + unsigned int error_interrupt_enable, + unsigned int error_interrupt_offset) +{ + vnic_wq_init_start(wq, cq_index, 0, 0, + error_interrupt_enable, + error_interrupt_offset); } unsigned int vnic_wq_error_status(struct vnic_wq *wq) diff --git a/drivers/net/enic/vnic_wq.h b/drivers/net/enic/vnic_wq.h index c826137dc65..9c34d41a887 100644 --- a/drivers/net/enic/vnic_wq.h +++ b/drivers/net/enic/vnic_wq.h @@ -149,6 +149,10 @@ static inline void vnic_wq_service(struct vnic_wq *wq, void vnic_wq_free(struct vnic_wq *wq); int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index, unsigned int desc_count, unsigned int desc_size); +void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index, + unsigned int fetch_index, unsigned int posted_index, + unsigned int error_interrupt_enable, + unsigned int error_interrupt_offset); void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index, unsigned int error_interrupt_enable, unsigned int error_interrupt_offset); -- cgit v1.2.3-18-g5258 From 1ba36e11b227e32f818aea5b4d84f5cbff71e7db Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 3 Sep 2009 17:22:04 -0700 Subject: Input: atkbd - allow setting force-release bitmap via sysfs There are more and more laptop requiring use of force_release quirk for their multimedia and other specialized keys. Adding their DMI data to the kernel is not sustainable; instead we will rely on help from userspace (HAL) to do that for us. This patch creates a new 'force_release' sysfs attribute (that belongs to serio device to which keyboard is attached) which can be used to set up force_release keymap. For example, Dell laptop owners might do: echo 133-139,143,147 > /sys/devices/platform/i8042/serio0/force_release Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/atkbd.c | 43 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 95fe0452dae..80835080fee 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -68,7 +68,9 @@ MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and * are loadable via a userland utility. */ -static const unsigned short atkbd_set2_keycode[512] = { +#define ATKBD_KEYMAP_SIZE 512 + +static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = { #ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES @@ -99,7 +101,7 @@ static const unsigned short atkbd_set2_keycode[512] = { #endif }; -static const unsigned short atkbd_set3_keycode[512] = { +static const unsigned short atkbd_set3_keycode[ATKBD_KEYMAP_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60, 131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62, @@ -200,8 +202,8 @@ struct atkbd { char phys[32]; unsigned short id; - unsigned short keycode[512]; - DECLARE_BITMAP(force_release_mask, 512); + unsigned short keycode[ATKBD_KEYMAP_SIZE]; + DECLARE_BITMAP(force_release_mask, ATKBD_KEYMAP_SIZE); unsigned char set; unsigned char translated; unsigned char extra; @@ -253,6 +255,7 @@ static struct device_attribute atkbd_attr_##_name = \ __ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name); ATKBD_DEFINE_ATTR(extra); +ATKBD_DEFINE_ATTR(force_release); ATKBD_DEFINE_ATTR(scroll); ATKBD_DEFINE_ATTR(set); ATKBD_DEFINE_ATTR(softrepeat); @@ -272,6 +275,7 @@ ATKBD_DEFINE_RO_ATTR(err_count); static struct attribute *atkbd_attributes[] = { &atkbd_attr_extra.attr, + &atkbd_attr_force_release.attr, &atkbd_attr_scroll.attr, &atkbd_attr_set.attr, &atkbd_attr_softrepeat.attr, @@ -926,7 +930,7 @@ static void atkbd_set_keycode_table(struct atkbd *atkbd) int i, j; memset(atkbd->keycode, 0, sizeof(atkbd->keycode)); - bitmap_zero(atkbd->force_release_mask, 512); + bitmap_zero(atkbd->force_release_mask, ATKBD_KEYMAP_SIZE); if (atkbd->translated) { for (i = 0; i < 128; i++) { @@ -1033,7 +1037,7 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd) input_dev->keycodesize = sizeof(unsigned short); input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode); - for (i = 0; i < 512; i++) + for (i = 0; i < ATKBD_KEYMAP_SIZE; i++) if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL) __set_bit(atkbd->keycode[i], input_dev->keybit); } @@ -1301,6 +1305,33 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun return count; } +static ssize_t atkbd_show_force_release(struct atkbd *atkbd, char *buf) +{ + size_t len = bitmap_scnlistprintf(buf, PAGE_SIZE - 2, + atkbd->force_release_mask, ATKBD_KEYMAP_SIZE); + + buf[len++] = '\n'; + buf[len] = '\0'; + + return len; +} + +static ssize_t atkbd_set_force_release(struct atkbd *atkbd, + const char *buf, size_t count) +{ + /* 64 bytes on stack should be acceptable */ + DECLARE_BITMAP(new_mask, ATKBD_KEYMAP_SIZE); + int err; + + err = bitmap_parselist(buf, new_mask, ATKBD_KEYMAP_SIZE); + if (err) + return err; + + memcpy(atkbd->force_release_mask, new_mask, sizeof(atkbd->force_release_mask)); + return count; +} + + static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf) { return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0); -- cgit v1.2.3-18-g5258 From 41c372dcad935fe7c27ec45211bad810515110bd Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 3 Sep 2009 17:22:03 -0700 Subject: Input: wacom_w8001 - simplify querying logic There is no need for locking when we send query and start commands to the touchscreen since there is no concurrency. Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wacom_w8001.c | 121 +++++++++++--------------------- 1 file changed, 40 insertions(+), 81 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c index 2f33a016764..56dc35c94bb 100644 --- a/drivers/input/touchscreen/wacom_w8001.c +++ b/drivers/input/touchscreen/wacom_w8001.c @@ -25,18 +25,16 @@ MODULE_AUTHOR("Jaya Kumar "); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -/* - * Definitions & global arrays. - */ - #define W8001_MAX_LENGTH 11 -#define W8001_PACKET_LEN 11 -#define W8001_LEAD_MASK 0x80 -#define W8001_LEAD_BYTE 0x80 -#define W8001_TAB_MASK 0x40 -#define W8001_TAB_BYTE 0x40 +#define W8001_LEAD_MASK 0x80 +#define W8001_LEAD_BYTE 0x80 +#define W8001_TAB_MASK 0x40 +#define W8001_TAB_BYTE 0x40 -#define W8001_QUERY_PACKET 0x20 +#define W8001_QUERY_PACKET 0x20 + +#define W8001_CMD_START '1' +#define W8001_CMD_QUERY '*' struct w8001_coord { u8 rdy; @@ -57,18 +55,19 @@ struct w8001_coord { struct w8001 { struct input_dev *dev; struct serio *serio; - struct mutex cmd_mutex; struct completion cmd_done; int id; int idx; - unsigned char expected_packet; + unsigned char response_type; + unsigned char response[W8001_MAX_LENGTH]; unsigned char data[W8001_MAX_LENGTH]; - unsigned char response[W8001_PACKET_LEN]; char phys[32]; }; -static int parse_data(u8 *data, struct w8001_coord *coord) +static void parse_data(u8 *data, struct w8001_coord *coord) { + memset(coord, 0, sizeof(*coord)); + coord->rdy = data[0] & 0x20; coord->tsw = data[0] & 0x01; coord->f1 = data[0] & 0x02; @@ -87,15 +86,15 @@ static int parse_data(u8 *data, struct w8001_coord *coord) coord->tilt_x = data[7] & 0x7F; coord->tilt_y = data[8] & 0x7F; - - return 0; } -static void w8001_process_data(struct w8001 *w8001, unsigned char data) +static irqreturn_t w8001_interrupt(struct serio *serio, + unsigned char data, unsigned int flags) { + struct w8001 *w8001 = serio_get_drvdata(serio); struct input_dev *dev = w8001->dev; - u8 tmp; struct w8001_coord coord; + unsigned char tmp; w8001->data[w8001->idx] = data; switch (w8001->idx++) { @@ -105,12 +104,13 @@ static void w8001_process_data(struct w8001 *w8001, unsigned char data) w8001->idx = 0; } break; + case 8: tmp = w8001->data[0] & W8001_TAB_MASK; if (unlikely(tmp == W8001_TAB_BYTE)) break; + w8001->idx = 0; - memset(&coord, 0, sizeof(coord)); parse_data(w8001->data, &coord); input_report_abs(dev, ABS_X, coord.x); input_report_abs(dev, ABS_Y, coord.y); @@ -118,86 +118,48 @@ static void w8001_process_data(struct w8001 *w8001, unsigned char data) input_report_key(dev, BTN_TOUCH, coord.tsw); input_sync(dev); break; + case 10: w8001->idx = 0; - memcpy(w8001->response, &w8001->data, W8001_PACKET_LEN); - w8001->expected_packet = W8001_QUERY_PACKET; + memcpy(w8001->response, w8001->data, W8001_MAX_LENGTH); + w8001->response_type = W8001_QUERY_PACKET; complete(&w8001->cmd_done); break; } -} - - -static irqreturn_t w8001_interrupt(struct serio *serio, - unsigned char data, unsigned int flags) -{ - struct w8001 *w8001 = serio_get_drvdata(serio); - - w8001_process_data(w8001, data); return IRQ_HANDLED; } -static int w8001_async_command(struct w8001 *w8001, unsigned char *packet, - int len) -{ - int rc = -1; - int i; - - mutex_lock(&w8001->cmd_mutex); - - for (i = 0; i < len; i++) { - if (serio_write(w8001->serio, packet[i])) - goto out; - } - rc = 0; - -out: - mutex_unlock(&w8001->cmd_mutex); - return rc; -} - -static int w8001_command(struct w8001 *w8001, unsigned char *packet, int len) +static int w8001_command(struct w8001 *w8001, unsigned char command, + bool wait_response) { - int rc = -1; - int i; + int rc; - mutex_lock(&w8001->cmd_mutex); - - serio_pause_rx(w8001->serio); + w8001->response_type = 0; init_completion(&w8001->cmd_done); - serio_continue_rx(w8001->serio); - - for (i = 0; i < len; i++) { - if (serio_write(w8001->serio, packet[i])) - goto out; - } - wait_for_completion_timeout(&w8001->cmd_done, HZ); + rc = serio_write(w8001->serio, command); + if (rc == 0 && wait_response) { - if (w8001->expected_packet == W8001_QUERY_PACKET) { - /* We are back in reporting mode, the query was ACKed */ - memcpy(packet, w8001->response, W8001_PACKET_LEN); - rc = 0; + wait_for_completion_timeout(&w8001->cmd_done, HZ); + if (w8001->response_type != W8001_QUERY_PACKET) + rc = -EIO; } -out: - mutex_unlock(&w8001->cmd_mutex); return rc; } static int w8001_setup(struct w8001 *w8001) { - struct w8001_coord coord; struct input_dev *dev = w8001->dev; - unsigned char start[1] = { '1' }; - unsigned char query[11] = { '*' }; + struct w8001_coord coord; + int error; - if (w8001_command(w8001, query, 1)) - return -1; + error = w8001_command(w8001, W8001_CMD_QUERY, true); + if (error) + return error; - memset(&coord, 0, sizeof(coord)); - parse_data(query, &coord); + parse_data(w8001->response, &coord); input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0); input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0); @@ -205,10 +167,7 @@ static int w8001_setup(struct w8001 *w8001) input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0); input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0); - if (w8001_async_command(w8001, start, 1)) - return -1; - - return 0; + return w8001_command(w8001, W8001_CMD_START, false); } /* @@ -249,7 +208,6 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv) w8001->serio = serio; w8001->id = serio->id.id; w8001->dev = input_dev; - mutex_init(&w8001->cmd_mutex); init_completion(&w8001->cmd_done); snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys); @@ -269,7 +227,8 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv) if (err) goto fail2; - if (w8001_setup(w8001)) + err = w8001_setup(w8001); + if (err) goto fail3; err = input_register_device(w8001->dev); -- cgit v1.2.3-18-g5258 From fab4e76373a614d3af624caedf18bee43fc6ca16 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 3 Sep 2009 21:34:39 -0700 Subject: WAN: dscc4: Fix warning pointing out a bug. Noticed by Stephen Rothwell: Today's linux-next build (x86_64 allmodconfig gcc-4.4.0) produced this warning: drivers/net/wan/dscc4.c: In function 'dscc4_rx_skb': drivers/net/wan/dscc4.c:670: warning: suggest parentheses around comparison in operand of '|' which actually points out a bug, I think. It is doing (x & (y | z)) != y | z when it probably means (x & (y | z)) != (y | z) Introduced by commit 5de3fcab91b0e1809eec030355d15801daf25083 ("WAN: bit and/or confusion"). Signed-off-by: David S. Miller --- drivers/net/wan/dscc4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index b2247bd0d49..81c8aec9df9 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -667,7 +667,7 @@ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, else if (!(skb->data[pkt_len] & FrameCrc)) dev->stats.rx_crc_errors++; else if ((skb->data[pkt_len] & (FrameVfr | FrameRab)) != - FrameVfr | FrameRab) + (FrameVfr | FrameRab)) dev->stats.rx_length_errors++; dev->stats.rx_errors++; dev_kfree_skb_irq(skb); -- cgit v1.2.3-18-g5258 From 39e3ab6fded4d7e66e01a878f0cae23ddd480c3b Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Tue, 1 Sep 2009 05:26:12 +0000 Subject: can: add can_free_echo_skb() for upcoming drivers This patch adds the function can_free_echo_skb to the CAN device interface to allow upcoming drivers to release echo skb's in case of error. Signed-off-by: Wolfgang Grandegger Signed-off-by: David S. Miller --- drivers/net/can/dev.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 1d29082d94a..f0b9a1e1db4 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -315,13 +315,29 @@ void can_get_echo_skb(struct net_device *dev, int idx) { struct can_priv *priv = netdev_priv(dev); - if ((dev->flags & IFF_ECHO) && priv->echo_skb[idx]) { + if (priv->echo_skb[idx]) { netif_rx(priv->echo_skb[idx]); priv->echo_skb[idx] = NULL; } } EXPORT_SYMBOL_GPL(can_get_echo_skb); +/* + * Remove the skb from the stack and free it. + * + * The function is typically called when TX failed. + */ +void can_free_echo_skb(struct net_device *dev, int idx) +{ + struct can_priv *priv = netdev_priv(dev); + + if (priv->echo_skb[idx]) { + kfree_skb(priv->echo_skb[idx]); + priv->echo_skb[idx] = NULL; + } +} +EXPORT_SYMBOL_GPL(can_free_echo_skb); + /* * CAN device restart for bus-off recovery */ -- cgit v1.2.3-18-g5258 From 8935f57e68c40c6469efe03f996bfb6150e18c6b Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Tue, 1 Sep 2009 05:29:41 +0000 Subject: can: sja1000: fix network statistics update The member "tx_bytes" of "struct net_device_stats" should be incremented when the interrupt is done and an "arbitration lost error" is a TX error and the statistics should be updated accordingly. Signed-off-by: Wolfgang Grandegger Signed-off-by: David S. Miller --- drivers/net/can/sja1000/sja1000.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index fd7fa716a6c..16d2ecd2a3b 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -242,7 +242,6 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct sja1000_priv *priv = netdev_priv(dev); - struct net_device_stats *stats = &dev->stats; struct can_frame *cf = (struct can_frame *)skb->data; uint8_t fi; uint8_t dlc; @@ -276,7 +275,6 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb, for (i = 0; i < dlc; i++) priv->write_reg(priv, dreg++, cf->data[i]); - stats->tx_bytes += dlc; dev->trans_start = jiffies; can_put_echo_skb(skb, dev, 0); @@ -427,7 +425,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) dev_dbg(dev->dev.parent, "arbitration lost interrupt\n"); alc = priv->read_reg(priv, REG_ALC); priv->can.can_stats.arbitration_lost++; - stats->rx_errors++; + stats->tx_errors++; cf->can_id |= CAN_ERR_LOSTARB; cf->data[0] = alc & 0x1f; } @@ -484,6 +482,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) if (isrc & IRQ_TI) { /* transmission complete interrupt */ + stats->tx_bytes += priv->read_reg(priv, REG_FI) & 0xf; stats->tx_packets++; can_get_echo_skb(dev, 0); netif_wake_queue(dev); -- cgit v1.2.3-18-g5258 From 2a6ba39ad6a277595ef9a0187a44f09e062dd3b2 Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Tue, 1 Sep 2009 05:37:33 +0000 Subject: can: sja1000: legacy SJA1000 ISA bus driver This patch adds support for legacy SJA1000 CAN controllers on the ISA or PC-104 bus. The I/O port or memory address and the IRQ number must be specified via module parameters: insmod sja1000_isa.ko port=0x310,0x380 irq=7,11 for ISA devices using I/O ports or: insmod sja1000_isa.ko mem=0xd1000,0xd1000 irq=7,11 for memory mapped ISA devices. Indirect access via address and data port is supported as well: insmod sja1000_isa.ko port=0x310,0x380 indirect=1 irq=7,11 Here is a full list of the supported module parameters: port:I/O port number (array of ulong) mem:I/O memory address (array of ulong) indirect:Indirect access via address and data port (array of byte) irq:IRQ number (array of int) clk:External oscillator clock frequency (default=16000000 [16 MHz]) (array of int) cdr:Clock divider register (default=0x48 [CDR_CBP | CDR_CLK_OFF]) (array of byte) ocr:Output clock register (default=0x18 [OCR_TX0_PUSHPULL]) (array of byte) Note: for clk, cdr, ocr, the first argument re-defines the default for all other devices, e.g.: insmod sja1000_isa.ko mem=0xd1000,0xd1000 irq=7,11 clk=24000000 is equivalent to insmod sja1000_isa.ko mem=0xd1000,0xd1000 irq=7,11 \ clk=24000000,24000000 Signed-off-by: Wolfgang Grandegger Tested-by: Oliver Hartkopp Signed-off-by: David S. Miller --- drivers/net/can/Kconfig | 7 + drivers/net/can/sja1000/Makefile | 1 + drivers/net/can/sja1000/sja1000_isa.c | 281 ++++++++++++++++++++++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 drivers/net/can/sja1000/sja1000_isa.c (limited to 'drivers') diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 30ae55d7167..09007437246 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -41,6 +41,13 @@ config CAN_SJA1000 ---help--- Driver for the SJA1000 CAN controllers from Philips or NXP +config CAN_SJA1000_ISA + depends on CAN_SJA1000 && ISA + tristate "ISA Bus based legacy SJA1000 driver" + ---help--- + This driver adds legacy support for SJA1000 chips connected to + the ISA bus using I/O port, memory mapped or indirect access. + config CAN_SJA1000_PLATFORM depends on CAN_SJA1000 tristate "Generic Platform Bus based SJA1000 driver" diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile index 9d0c08da273..9d245ac0396 100644 --- a/drivers/net/can/sja1000/Makefile +++ b/drivers/net/can/sja1000/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_CAN_SJA1000) += sja1000.o +obj-$(CONFIG_CAN_SJA1000_ISA) += sja1000_isa.o obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o diff --git a/drivers/net/can/sja1000/sja1000_isa.c b/drivers/net/can/sja1000/sja1000_isa.c new file mode 100644 index 00000000000..a6a51f15596 --- /dev/null +++ b/drivers/net/can/sja1000/sja1000_isa.c @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2009 Wolfgang Grandegger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sja1000.h" + +#define DRV_NAME "sja1000_isa" + +#define MAXDEV 8 + +MODULE_AUTHOR("Wolfgang Grandegger "); +MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the ISA bus"); +MODULE_LICENSE("GPL v2"); + +#define CLK_DEFAULT 16000000 /* 16 MHz */ +#define CDR_DEFAULT (CDR_CBP | CDR_CLK_OFF) +#define OCR_DEFAULT OCR_TX0_PUSHPULL + +static unsigned long port[MAXDEV]; +static unsigned long mem[MAXDEV]; +static int __devinitdata irq[MAXDEV]; +static int __devinitdata clk[MAXDEV]; +static char __devinitdata cdr[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1}; +static char __devinitdata ocr[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1}; +static char __devinitdata indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1}; + +module_param_array(port, ulong, NULL, S_IRUGO); +MODULE_PARM_DESC(port, "I/O port number"); + +module_param_array(mem, ulong, NULL, S_IRUGO); +MODULE_PARM_DESC(mem, "I/O memory address"); + +module_param_array(indirect, byte, NULL, S_IRUGO); +MODULE_PARM_DESC(indirect, "Indirect access via address and data port"); + +module_param_array(irq, int, NULL, S_IRUGO); +MODULE_PARM_DESC(irq, "IRQ number"); + +module_param_array(clk, int, NULL, S_IRUGO); +MODULE_PARM_DESC(clk, "External oscillator clock frequency " + "(default=16000000 [16 MHz])"); + +module_param_array(cdr, byte, NULL, S_IRUGO); +MODULE_PARM_DESC(cdr, "Clock divider register " + "(default=0x48 [CDR_CBP | CDR_CLK_OFF])"); + +module_param_array(ocr, byte, NULL, S_IRUGO); +MODULE_PARM_DESC(ocr, "Output control register " + "(default=0x18 [OCR_TX0_PUSHPULL])"); + +#define SJA1000_IOSIZE 0x20 +#define SJA1000_IOSIZE_INDIRECT 0x02 + +static u8 sja1000_isa_mem_read_reg(const struct sja1000_priv *priv, int reg) +{ + return readb(priv->reg_base + reg); +} + +static void sja1000_isa_mem_write_reg(const struct sja1000_priv *priv, + int reg, u8 val) +{ + writeb(val, priv->reg_base + reg); +} + +static u8 sja1000_isa_port_read_reg(const struct sja1000_priv *priv, int reg) +{ + return inb((unsigned long)priv->reg_base + reg); +} + +static void sja1000_isa_port_write_reg(const struct sja1000_priv *priv, + int reg, u8 val) +{ + outb(val, (unsigned long)priv->reg_base + reg); +} + +static u8 sja1000_isa_port_read_reg_indirect(const struct sja1000_priv *priv, + int reg) +{ + unsigned long base = (unsigned long)priv->reg_base; + + outb(reg, base); + return inb(base + 1); +} + +static void sja1000_isa_port_write_reg_indirect(const struct sja1000_priv *priv, + int reg, u8 val) +{ + unsigned long base = (unsigned long)priv->reg_base; + + outb(reg, base); + outb(val, base + 1); +} + +static int __devinit sja1000_isa_match(struct device *pdev, unsigned int idx) +{ + if (port[idx] || mem[idx]) { + if (irq[idx]) + return 1; + } else if (idx) + return 0; + + dev_err(pdev, "insufficient parameters supplied\n"); + return 0; +} + +static int __devinit sja1000_isa_probe(struct device *pdev, unsigned int idx) +{ + struct net_device *dev; + struct sja1000_priv *priv; + void __iomem *base = NULL; + int iosize = SJA1000_IOSIZE; + int err; + + if (mem[idx]) { + if (!request_mem_region(mem[idx], iosize, DRV_NAME)) { + err = -EBUSY; + goto exit; + } + base = ioremap_nocache(mem[idx], iosize); + if (!base) { + err = -ENOMEM; + goto exit_release; + } + } else { + if (indirect[idx] > 0 || + (indirect[idx] == -1 && indirect[0] > 0)) + iosize = SJA1000_IOSIZE_INDIRECT; + if (!request_region(port[idx], iosize, DRV_NAME)) { + err = -EBUSY; + goto exit; + } + } + + dev = alloc_sja1000dev(0); + if (!dev) { + err = -ENOMEM; + goto exit_unmap; + } + priv = netdev_priv(dev); + + dev->irq = irq[idx]; + priv->irq_flags = IRQF_SHARED; + if (mem[idx]) { + priv->reg_base = base; + dev->base_addr = mem[idx]; + priv->read_reg = sja1000_isa_mem_read_reg; + priv->write_reg = sja1000_isa_mem_write_reg; + } else { + priv->reg_base = (void __iomem *)port[idx]; + dev->base_addr = port[idx]; + + if (iosize == SJA1000_IOSIZE_INDIRECT) { + priv->read_reg = sja1000_isa_port_read_reg_indirect; + priv->write_reg = sja1000_isa_port_write_reg_indirect; + } else { + priv->read_reg = sja1000_isa_port_read_reg; + priv->write_reg = sja1000_isa_port_write_reg; + } + } + + if (clk[idx]) + priv->can.clock.freq = clk[idx] / 2; + else if (clk[0]) + priv->can.clock.freq = clk[0] / 2; + else + priv->can.clock.freq = CLK_DEFAULT / 2; + + if (ocr[idx] != -1) + priv->ocr = ocr[idx] & 0xff; + else if (ocr[0] != -1) + priv->ocr = ocr[0] & 0xff; + else + priv->ocr = OCR_DEFAULT; + + if (cdr[idx] != -1) + priv->cdr = cdr[idx] & 0xff; + else if (cdr[0] != -1) + priv->cdr = cdr[0] & 0xff; + else + priv->cdr = CDR_DEFAULT; + + dev_set_drvdata(pdev, dev); + SET_NETDEV_DEV(dev, pdev); + + err = register_sja1000dev(dev); + if (err) { + dev_err(pdev, "registering %s failed (err=%d)\n", + DRV_NAME, err); + goto exit_unmap; + } + + dev_info(pdev, "%s device registered (reg_base=0x%p, irq=%d)\n", + DRV_NAME, priv->reg_base, dev->irq); + return 0; + + exit_unmap: + if (mem[idx]) + iounmap(base); + exit_release: + if (mem[idx]) + release_mem_region(mem[idx], iosize); + else + release_region(port[idx], iosize); + exit: + return err; +} + +static int __devexit sja1000_isa_remove(struct device *pdev, unsigned int idx) +{ + struct net_device *dev = dev_get_drvdata(pdev); + struct sja1000_priv *priv = netdev_priv(dev); + + unregister_sja1000dev(dev); + dev_set_drvdata(pdev, NULL); + + if (mem[idx]) { + iounmap(priv->reg_base); + release_mem_region(mem[idx], SJA1000_IOSIZE); + } else { + if (priv->read_reg == sja1000_isa_port_read_reg_indirect) + release_region(port[idx], SJA1000_IOSIZE_INDIRECT); + else + release_region(port[idx], SJA1000_IOSIZE); + } + free_sja1000dev(dev); + + return 0; +} + +static struct isa_driver sja1000_isa_driver = { + .match = sja1000_isa_match, + .probe = sja1000_isa_probe, + .remove = __devexit_p(sja1000_isa_remove), + .driver = { + .name = DRV_NAME, + }, +}; + +static int __init sja1000_isa_init(void) +{ + int err = isa_register_driver(&sja1000_isa_driver, MAXDEV); + + if (!err) + printk(KERN_INFO + "Legacy %s driver for max. %d devices registered\n", + DRV_NAME, MAXDEV); + return err; +} + +static void __exit sja1000_isa_exit(void) +{ + isa_unregister_driver(&sja1000_isa_driver); +} + +module_init(sja1000_isa_init); +module_exit(sja1000_isa_exit); -- cgit v1.2.3-18-g5258 From 8a34e2f8ba7d4302977c90e357921994a6c39af9 Mon Sep 17 00:00:00 2001 From: Sachin Sant Date: Fri, 4 Sep 2009 03:41:07 -0700 Subject: net: Fix a build break because of a typo in drivers/net/3c503.c Signed-off-by: Sachin Sant Signed-off-by: David S. Miller --- drivers/net/3c503.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index 81c148a59ad..c71e12d05f6 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -403,7 +403,7 @@ el2_open(struct net_device *dev) break; } else { if (retval != -EBUSY) - return reval; + return retval; } } while (*++irqp); if (*irqp == 0) { -- cgit v1.2.3-18-g5258 From cdf69bb91b0ef14f0e0a987a4430764e6c290644 Mon Sep 17 00:00:00 2001 From: "Yanqing_Liu@Dell.com" Date: Mon, 17 Aug 2009 14:31:42 -0500 Subject: [SCSI] scsi_dh_rdac: add support for next generation of Dell PV array This patch is to add DM support for next generation of Dell PowerVault storage array. Signed-off-by: Yanqing Liu Acked-by: Chandra Seetharaman Signed-off-by: James Bottomley --- drivers/scsi/device_handler/scsi_dh_rdac.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index bea92ef7e26..872292f659c 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -631,6 +631,8 @@ static const struct scsi_dh_devlist rdac_dev_list[] = { {"SUN", "LCSM100_F"}, {"DELL", "MD3000"}, {"DELL", "MD3000i"}, + {"DELL", "MD32xx"}, + {"DELL", "MD32xxi"}, {"LSI", "INF-01-00"}, {"ENGENIO", "INF-01-00"}, {"STK", "FLEXLINE 380"}, -- cgit v1.2.3-18-g5258 From a67417ab7eeff45bba55666c0e1083260f3624ee Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 18 Aug 2009 15:43:06 +0200 Subject: [SCSI] zfcp: invalid usage after free of port resources In certain error scenarios ports, rports are getting attached, validated and removed from the systems environment. Depending on the layer this occurs asynchronously. This patch fixes the few races which existed and ensures all references and cross references are cleared at the time they're invalid. In addition fc transports actions are only scheduled when required. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 7 +++++-- drivers/s390/scsi/zfcp_scsi.c | 6 ++++-- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 2ccbd185a5f..fa2460b4229 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -672,12 +672,15 @@ err_out: */ void zfcp_port_dequeue(struct zfcp_port *port) { - wait_event(port->remove_wq, atomic_read(&port->refcount) == 0); write_lock_irq(&zfcp_data.config_lock); list_del(&port->list); write_unlock_irq(&zfcp_data.config_lock); - if (port->rport) + if (port->rport) { port->rport->dd_data = NULL; + port->rport = NULL; + } + wait_event(port->remove_wq, atomic_read(&port->refcount) == 0); + cancel_work_sync(&port->rport_work); /* usually not necessary */ zfcp_adapter_put(port->adapter); sysfs_remove_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs); device_unregister(&port->sysfs_device); diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 6925a178468..54a7a7474aa 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -582,8 +582,10 @@ void zfcp_scsi_schedule_rport_block(struct zfcp_port *port) zfcp_port_get(port); port->rport_task = RPORT_DEL; - if (!queue_work(zfcp_data.work_queue, &port->rport_work)) - zfcp_port_put(port); + if (port->rport && queue_work(zfcp_data.work_queue, &port->rport_work)) + return; + + zfcp_port_put(port); } void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter) -- cgit v1.2.3-18-g5258 From d46f384a89c2378cb7858747faa1935db17e22a8 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 18 Aug 2009 15:43:07 +0200 Subject: [SCSI] zfcp: Move debug data from zfcp_data to own data structure The struct zfcp_adapter includes everything related to the debug traces. This introduces dependences between the definitions in zfcp_def.h and zfcp_dbf.h. Move all debug related data structures to a new data structure to break those dependencies and manage the debug data in zfcp_dbf.[hc]. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 4 - drivers/s390/scsi/zfcp_dbf.c | 217 ++++++++++++++++++++++++------------------- drivers/s390/scsi/zfcp_dbf.h | 17 +++- drivers/s390/scsi/zfcp_def.h | 15 +-- drivers/s390/scsi/zfcp_fsf.h | 3 +- 5 files changed, 143 insertions(+), 113 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index fa2460b4229..870fe79bc7e 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -502,10 +502,6 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) spin_lock_init(&adapter->req_list_lock); - spin_lock_init(&adapter->hba_dbf_lock); - spin_lock_init(&adapter->san_dbf_lock); - spin_lock_init(&adapter->scsi_dbf_lock); - spin_lock_init(&adapter->rec_dbf_lock); spin_lock_init(&adapter->req_q_lock); spin_lock_init(&adapter->qdio_stat_lock); diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index b99b87ce5a3..995e6128b6c 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -3,7 +3,7 @@ * * Debug traces for zfcp. * - * Copyright IBM Corporation 2002, 2008 + * Copyright IBM Corporation 2002, 2009 */ #define KMSG_COMPONENT "zfcp" @@ -11,6 +11,7 @@ #include #include +#include "zfcp_dbf.h" #include "zfcp_ext.h" static u32 dbfsize = 4; @@ -126,6 +127,7 @@ static int zfcp_dbf_view_header(debug_info_t *id, struct debug_view *view, void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) { struct zfcp_adapter *adapter = fsf_req->adapter; + struct zfcp_dbf *dbf = adapter->dbf; struct fsf_qtcb *qtcb = fsf_req->qtcb; union fsf_prot_status_qual *prot_status_qual = &qtcb->prefix.prot_status_qual; @@ -134,12 +136,12 @@ void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) struct zfcp_port *port; struct zfcp_unit *unit; struct zfcp_send_els *send_els; - struct zfcp_hba_dbf_record *rec = &adapter->hba_dbf_buf; + struct zfcp_hba_dbf_record *rec = &dbf->hba_dbf_buf; struct zfcp_hba_dbf_record_response *response = &rec->u.response; int level; unsigned long flags; - spin_lock_irqsave(&adapter->hba_dbf_lock, flags); + spin_lock_irqsave(&dbf->hba_dbf_lock, flags); memset(rec, 0, sizeof(*rec)); strncpy(rec->tag, "resp", ZFCP_DBF_TAG_SIZE); @@ -224,7 +226,7 @@ void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) break; } - debug_event(adapter->hba_dbf, level, rec, sizeof(*rec)); + debug_event(dbf->hba_dbf, level, rec, sizeof(*rec)); /* have fcp channel microcode fixed to use as little as possible */ if (fsf_req->fsf_command != FSF_QTCB_FCP_CMND) { @@ -232,11 +234,11 @@ void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) char *buf = (char *)qtcb + qtcb->header.log_start; int len = qtcb->header.log_length; for (; len && !buf[len - 1]; len--); - zfcp_dbf_hexdump(adapter->hba_dbf, rec, sizeof(*rec), level, - buf, len); + zfcp_dbf_hexdump(dbf->hba_dbf, rec, sizeof(*rec), level, buf, + len); } - spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags); + spin_unlock_irqrestore(&dbf->hba_dbf_lock, flags); } /** @@ -248,10 +250,11 @@ void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) void zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter, struct fsf_status_read_buffer *status_buffer) { - struct zfcp_hba_dbf_record *rec = &adapter->hba_dbf_buf; + struct zfcp_dbf *dbf = adapter->dbf; + struct zfcp_hba_dbf_record *rec = &dbf->hba_dbf_buf; unsigned long flags; - spin_lock_irqsave(&adapter->hba_dbf_lock, flags); + spin_lock_irqsave(&dbf->hba_dbf_lock, flags); memset(rec, 0, sizeof(*rec)); strncpy(rec->tag, "stat", ZFCP_DBF_TAG_SIZE); strncpy(rec->tag2, tag, ZFCP_DBF_TAG_SIZE); @@ -293,8 +296,8 @@ void zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter, &status_buffer->payload, rec->u.status.payload_size); } - debug_event(adapter->hba_dbf, 2, rec, sizeof(*rec)); - spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags); + debug_event(dbf->hba_dbf, 2, rec, sizeof(*rec)); + spin_unlock_irqrestore(&dbf->hba_dbf_lock, flags); } /** @@ -308,17 +311,18 @@ void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter, unsigned int qdio_error, int sbal_index, int sbal_count) { - struct zfcp_hba_dbf_record *r = &adapter->hba_dbf_buf; + struct zfcp_dbf *dbf = adapter->dbf; + struct zfcp_hba_dbf_record *r = &dbf->hba_dbf_buf; unsigned long flags; - spin_lock_irqsave(&adapter->hba_dbf_lock, flags); + spin_lock_irqsave(&dbf->hba_dbf_lock, flags); memset(r, 0, sizeof(*r)); strncpy(r->tag, "qdio", ZFCP_DBF_TAG_SIZE); r->u.qdio.qdio_error = qdio_error; r->u.qdio.sbal_index = sbal_index; r->u.qdio.sbal_count = sbal_count; - debug_event(adapter->hba_dbf, 0, r, sizeof(*r)); - spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags); + debug_event(dbf->hba_dbf, 0, r, sizeof(*r)); + spin_unlock_irqrestore(&dbf->hba_dbf_lock, flags); } /** @@ -329,17 +333,18 @@ void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter, void zfcp_hba_dbf_event_berr(struct zfcp_adapter *adapter, struct zfcp_fsf_req *req) { - struct zfcp_hba_dbf_record *r = &adapter->hba_dbf_buf; + struct zfcp_dbf *dbf = adapter->dbf; + struct zfcp_hba_dbf_record *r = &dbf->hba_dbf_buf; struct fsf_status_read_buffer *sr_buf = req->data; struct fsf_bit_error_payload *err = &sr_buf->payload.bit_error; unsigned long flags; - spin_lock_irqsave(&adapter->hba_dbf_lock, flags); + spin_lock_irqsave(&dbf->hba_dbf_lock, flags); memset(r, 0, sizeof(*r)); strncpy(r->tag, "berr", ZFCP_DBF_TAG_SIZE); memcpy(&r->u.berr, err, sizeof(struct fsf_bit_error_payload)); - debug_event(adapter->hba_dbf, 0, r, sizeof(*r)); - spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags); + debug_event(dbf->hba_dbf, 0, r, sizeof(*r)); + spin_unlock_irqrestore(&dbf->hba_dbf_lock, flags); } static void zfcp_hba_dbf_view_response(char **p, struct zfcp_hba_dbf_record_response *r) @@ -554,7 +559,8 @@ static struct debug_view zfcp_rec_dbf_view = { */ void zfcp_rec_dbf_event_thread(char *id2, struct zfcp_adapter *adapter) { - struct zfcp_rec_dbf_record *r = &adapter->rec_dbf_buf; + struct zfcp_dbf *dbf = adapter->dbf; + struct zfcp_rec_dbf_record *r = &dbf->rec_dbf_buf; unsigned long flags = 0; struct list_head *entry; unsigned ready = 0, running = 0, total; @@ -565,15 +571,15 @@ void zfcp_rec_dbf_event_thread(char *id2, struct zfcp_adapter *adapter) running++; total = adapter->erp_total_count; - spin_lock_irqsave(&adapter->rec_dbf_lock, flags); + spin_lock_irqsave(&dbf->rec_dbf_lock, flags); memset(r, 0, sizeof(*r)); r->id = ZFCP_REC_DBF_ID_THREAD; memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE); r->u.thread.total = total; r->u.thread.ready = ready; r->u.thread.running = running; - debug_event(adapter->rec_dbf, 6, r, sizeof(*r)); - spin_unlock_irqrestore(&adapter->rec_dbf_lock, flags); + debug_event(dbf->rec_dbf, 6, r, sizeof(*r)); + spin_unlock_irqrestore(&dbf->rec_dbf_lock, flags); } /** @@ -596,10 +602,11 @@ static void zfcp_rec_dbf_event_target(char *id2, void *ref, atomic_t *status, atomic_t *erp_count, u64 wwpn, u32 d_id, u64 fcp_lun) { - struct zfcp_rec_dbf_record *r = &adapter->rec_dbf_buf; + struct zfcp_dbf *dbf = adapter->dbf; + struct zfcp_rec_dbf_record *r = &dbf->rec_dbf_buf; unsigned long flags; - spin_lock_irqsave(&adapter->rec_dbf_lock, flags); + spin_lock_irqsave(&dbf->rec_dbf_lock, flags); memset(r, 0, sizeof(*r)); r->id = ZFCP_REC_DBF_ID_TARGET; memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE); @@ -609,8 +616,8 @@ static void zfcp_rec_dbf_event_target(char *id2, void *ref, r->u.target.d_id = d_id; r->u.target.fcp_lun = fcp_lun; r->u.target.erp_count = atomic_read(erp_count); - debug_event(adapter->rec_dbf, 3, r, sizeof(*r)); - spin_unlock_irqrestore(&adapter->rec_dbf_lock, flags); + debug_event(dbf->rec_dbf, 3, r, sizeof(*r)); + spin_unlock_irqrestore(&dbf->rec_dbf_lock, flags); } /** @@ -672,10 +679,11 @@ void zfcp_rec_dbf_event_trigger(char *id2, void *ref, u8 want, u8 need, void *action, struct zfcp_adapter *adapter, struct zfcp_port *port, struct zfcp_unit *unit) { - struct zfcp_rec_dbf_record *r = &adapter->rec_dbf_buf; + struct zfcp_dbf *dbf = adapter->dbf; + struct zfcp_rec_dbf_record *r = &dbf->rec_dbf_buf; unsigned long flags; - spin_lock_irqsave(&adapter->rec_dbf_lock, flags); + spin_lock_irqsave(&dbf->rec_dbf_lock, flags); memset(r, 0, sizeof(*r)); r->id = ZFCP_REC_DBF_ID_TRIGGER; memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE); @@ -692,8 +700,8 @@ void zfcp_rec_dbf_event_trigger(char *id2, void *ref, u8 want, u8 need, r->u.trigger.us = atomic_read(&unit->status); r->u.trigger.fcp_lun = unit->fcp_lun; } - debug_event(adapter->rec_dbf, action ? 1 : 4, r, sizeof(*r)); - spin_unlock_irqrestore(&adapter->rec_dbf_lock, flags); + debug_event(dbf->rec_dbf, action ? 1 : 4, r, sizeof(*r)); + spin_unlock_irqrestore(&dbf->rec_dbf_lock, flags); } /** @@ -704,10 +712,11 @@ void zfcp_rec_dbf_event_trigger(char *id2, void *ref, u8 want, u8 need, void zfcp_rec_dbf_event_action(char *id2, struct zfcp_erp_action *erp_action) { struct zfcp_adapter *adapter = erp_action->adapter; - struct zfcp_rec_dbf_record *r = &adapter->rec_dbf_buf; + struct zfcp_dbf *dbf = adapter->dbf; + struct zfcp_rec_dbf_record *r = &dbf->rec_dbf_buf; unsigned long flags; - spin_lock_irqsave(&adapter->rec_dbf_lock, flags); + spin_lock_irqsave(&dbf->rec_dbf_lock, flags); memset(r, 0, sizeof(*r)); r->id = ZFCP_REC_DBF_ID_ACTION; memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE); @@ -715,8 +724,8 @@ void zfcp_rec_dbf_event_action(char *id2, struct zfcp_erp_action *erp_action) r->u.action.status = erp_action->status; r->u.action.step = erp_action->step; r->u.action.fsf_req = (unsigned long)erp_action->fsf_req; - debug_event(adapter->rec_dbf, 5, r, sizeof(*r)); - spin_unlock_irqrestore(&adapter->rec_dbf_lock, flags); + debug_event(dbf->rec_dbf, 5, r, sizeof(*r)); + spin_unlock_irqrestore(&dbf->rec_dbf_lock, flags); } /** @@ -728,13 +737,14 @@ void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req) struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data; struct zfcp_wka_port *wka_port = ct->wka_port; struct zfcp_adapter *adapter = wka_port->adapter; + struct zfcp_dbf *dbf = adapter->dbf; struct ct_hdr *hdr = sg_virt(ct->req); - struct zfcp_san_dbf_record *r = &adapter->san_dbf_buf; + struct zfcp_san_dbf_record *r = &dbf->san_dbf_buf; struct zfcp_san_dbf_record_ct_request *oct = &r->u.ct_req; int level = 3; unsigned long flags; - spin_lock_irqsave(&adapter->san_dbf_lock, flags); + spin_lock_irqsave(&dbf->san_dbf_lock, flags); memset(r, 0, sizeof(*r)); strncpy(r->tag, "octc", ZFCP_DBF_TAG_SIZE); r->fsf_reqid = fsf_req->req_id; @@ -749,10 +759,10 @@ void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req) oct->max_res_size = hdr->max_res_size; oct->len = min((int)ct->req->length - (int)sizeof(struct ct_hdr), ZFCP_DBF_SAN_MAX_PAYLOAD); - debug_event(adapter->san_dbf, level, r, sizeof(*r)); - zfcp_dbf_hexdump(adapter->san_dbf, r, sizeof(*r), level, + debug_event(dbf->san_dbf, level, r, sizeof(*r)); + zfcp_dbf_hexdump(dbf->san_dbf, r, sizeof(*r), level, (void *)hdr + sizeof(struct ct_hdr), oct->len); - spin_unlock_irqrestore(&adapter->san_dbf_lock, flags); + spin_unlock_irqrestore(&dbf->san_dbf_lock, flags); } /** @@ -765,12 +775,13 @@ void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req) struct zfcp_wka_port *wka_port = ct->wka_port; struct zfcp_adapter *adapter = wka_port->adapter; struct ct_hdr *hdr = sg_virt(ct->resp); - struct zfcp_san_dbf_record *r = &adapter->san_dbf_buf; + struct zfcp_dbf *dbf = adapter->dbf; + struct zfcp_san_dbf_record *r = &dbf->san_dbf_buf; struct zfcp_san_dbf_record_ct_response *rct = &r->u.ct_resp; int level = 3; unsigned long flags; - spin_lock_irqsave(&adapter->san_dbf_lock, flags); + spin_lock_irqsave(&dbf->san_dbf_lock, flags); memset(r, 0, sizeof(*r)); strncpy(r->tag, "rctc", ZFCP_DBF_TAG_SIZE); r->fsf_reqid = fsf_req->req_id; @@ -785,10 +796,10 @@ void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req) rct->max_res_size = hdr->max_res_size; rct->len = min((int)ct->resp->length - (int)sizeof(struct ct_hdr), ZFCP_DBF_SAN_MAX_PAYLOAD); - debug_event(adapter->san_dbf, level, r, sizeof(*r)); - zfcp_dbf_hexdump(adapter->san_dbf, r, sizeof(*r), level, + debug_event(dbf->san_dbf, level, r, sizeof(*r)); + zfcp_dbf_hexdump(dbf->san_dbf, r, sizeof(*r), level, (void *)hdr + sizeof(struct ct_hdr), rct->len); - spin_unlock_irqrestore(&adapter->san_dbf_lock, flags); + spin_unlock_irqrestore(&dbf->san_dbf_lock, flags); } static void zfcp_san_dbf_event_els(const char *tag, int level, @@ -797,10 +808,11 @@ static void zfcp_san_dbf_event_els(const char *tag, int level, int buflen) { struct zfcp_adapter *adapter = fsf_req->adapter; - struct zfcp_san_dbf_record *rec = &adapter->san_dbf_buf; + struct zfcp_dbf *dbf = adapter->dbf; + struct zfcp_san_dbf_record *rec = &dbf->san_dbf_buf; unsigned long flags; - spin_lock_irqsave(&adapter->san_dbf_lock, flags); + spin_lock_irqsave(&dbf->san_dbf_lock, flags); memset(rec, 0, sizeof(*rec)); strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE); rec->fsf_reqid = fsf_req->req_id; @@ -808,10 +820,10 @@ static void zfcp_san_dbf_event_els(const char *tag, int level, rec->s_id = s_id; rec->d_id = d_id; rec->u.els.ls_code = ls_code; - debug_event(adapter->san_dbf, level, rec, sizeof(*rec)); - zfcp_dbf_hexdump(adapter->san_dbf, rec, sizeof(*rec), level, + debug_event(dbf->san_dbf, level, rec, sizeof(*rec)); + zfcp_dbf_hexdump(dbf->san_dbf, rec, sizeof(*rec), level, buffer, min(buflen, ZFCP_DBF_SAN_MAX_PAYLOAD)); - spin_unlock_irqrestore(&adapter->san_dbf_lock, flags); + spin_unlock_irqrestore(&dbf->san_dbf_lock, flags); } /** @@ -915,14 +927,15 @@ static void zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level, struct zfcp_fsf_req *fsf_req, unsigned long old_req_id) { - struct zfcp_scsi_dbf_record *rec = &adapter->scsi_dbf_buf; + struct zfcp_dbf *dbf = adapter->dbf; + struct zfcp_scsi_dbf_record *rec = &dbf->scsi_dbf_buf; struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)rec; unsigned long flags; struct fcp_rsp_iu *fcp_rsp; char *fcp_rsp_info = NULL, *fcp_sns_info = NULL; int offset = 0, buflen = 0; - spin_lock_irqsave(&adapter->scsi_dbf_lock, flags); + spin_lock_irqsave(&dbf->scsi_dbf_lock, flags); do { memset(rec, 0, sizeof(*rec)); if (offset == 0) { @@ -981,9 +994,9 @@ static void zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level, memcpy(dump->data, fcp_sns_info + offset, dump->size); offset += dump->size; } - debug_event(adapter->scsi_dbf, level, rec, sizeof(*rec)); + debug_event(dbf->scsi_dbf, level, rec, sizeof(*rec)); } while (offset < buflen); - spin_unlock_irqrestore(&adapter->scsi_dbf_lock, flags); + spin_unlock_irqrestore(&dbf->scsi_dbf_lock, flags); } /** @@ -1087,6 +1100,22 @@ static struct debug_view zfcp_scsi_dbf_view = { NULL }; +static debug_info_t *zfcp_dbf_reg(const char *name, int level, + struct debug_view *view, int size) +{ + struct debug_info *d; + + d = debug_register(name, dbfsize, level, size); + if (!d) + return NULL; + + debug_register_view(d, &debug_hex_ascii_view); + debug_register_view(d, view); + debug_set_level(d, level); + + return d; +} + /** * zfcp_adapter_debug_register - registers debug feature for an adapter * @adapter: pointer to adapter for which debug features should be registered @@ -1095,52 +1124,56 @@ static struct debug_view zfcp_scsi_dbf_view = { int zfcp_adapter_debug_register(struct zfcp_adapter *adapter) { char dbf_name[DEBUG_MAX_NAME_LEN]; + struct zfcp_dbf *dbf; + + dbf = kmalloc(sizeof(struct zfcp_dbf), GFP_KERNEL); + if (!dbf) + return -ENOMEM; + + spin_lock_init(&dbf->hba_dbf_lock); + spin_lock_init(&dbf->san_dbf_lock); + spin_lock_init(&dbf->scsi_dbf_lock); + spin_lock_init(&dbf->rec_dbf_lock); /* debug feature area which records recovery activity */ sprintf(dbf_name, "zfcp_%s_rec", dev_name(&adapter->ccw_device->dev)); - adapter->rec_dbf = debug_register(dbf_name, dbfsize, 1, - sizeof(struct zfcp_rec_dbf_record)); - if (!adapter->rec_dbf) - goto failed; - debug_register_view(adapter->rec_dbf, &debug_hex_ascii_view); - debug_register_view(adapter->rec_dbf, &zfcp_rec_dbf_view); - debug_set_level(adapter->rec_dbf, 3); + dbf->rec_dbf = zfcp_dbf_reg(dbf_name, 3, &zfcp_rec_dbf_view, + sizeof(struct zfcp_rec_dbf_record)); + if (!dbf->rec_dbf) + goto fail_rec; /* debug feature area which records HBA (FSF and QDIO) conditions */ sprintf(dbf_name, "zfcp_%s_hba", dev_name(&adapter->ccw_device->dev)); - adapter->hba_dbf = debug_register(dbf_name, dbfsize, 1, - sizeof(struct zfcp_hba_dbf_record)); - if (!adapter->hba_dbf) - goto failed; - debug_register_view(adapter->hba_dbf, &debug_hex_ascii_view); - debug_register_view(adapter->hba_dbf, &zfcp_hba_dbf_view); - debug_set_level(adapter->hba_dbf, 3); + dbf->hba_dbf = zfcp_dbf_reg(dbf_name, 3, &zfcp_hba_dbf_view, + sizeof(struct zfcp_hba_dbf_record)); + if (!dbf->hba_dbf) + goto fail_hba; /* debug feature area which records SAN command failures and recovery */ sprintf(dbf_name, "zfcp_%s_san", dev_name(&adapter->ccw_device->dev)); - adapter->san_dbf = debug_register(dbf_name, dbfsize, 1, - sizeof(struct zfcp_san_dbf_record)); - if (!adapter->san_dbf) - goto failed; - debug_register_view(adapter->san_dbf, &debug_hex_ascii_view); - debug_register_view(adapter->san_dbf, &zfcp_san_dbf_view); - debug_set_level(adapter->san_dbf, 6); + dbf->san_dbf = zfcp_dbf_reg(dbf_name, 6, &zfcp_san_dbf_view, + sizeof(struct zfcp_san_dbf_record)); + if (!dbf->san_dbf) + goto fail_san; /* debug feature area which records SCSI command failures and recovery */ sprintf(dbf_name, "zfcp_%s_scsi", dev_name(&adapter->ccw_device->dev)); - adapter->scsi_dbf = debug_register(dbf_name, dbfsize, 1, - sizeof(struct zfcp_scsi_dbf_record)); - if (!adapter->scsi_dbf) - goto failed; - debug_register_view(adapter->scsi_dbf, &debug_hex_ascii_view); - debug_register_view(adapter->scsi_dbf, &zfcp_scsi_dbf_view); - debug_set_level(adapter->scsi_dbf, 3); + dbf->scsi_dbf = zfcp_dbf_reg(dbf_name, 3, &zfcp_scsi_dbf_view, + sizeof(struct zfcp_scsi_dbf_record)); + if (!dbf->scsi_dbf) + goto fail_scsi; + adapter->dbf = dbf; return 0; - failed: - zfcp_adapter_debug_unregister(adapter); - +fail_scsi: + debug_unregister(dbf->san_dbf); +fail_san: + debug_unregister(dbf->hba_dbf); +fail_hba: + debug_unregister(dbf->rec_dbf); +fail_rec: + kfree(dbf); return -ENOMEM; } @@ -1150,12 +1183,10 @@ int zfcp_adapter_debug_register(struct zfcp_adapter *adapter) */ void zfcp_adapter_debug_unregister(struct zfcp_adapter *adapter) { - debug_unregister(adapter->scsi_dbf); - debug_unregister(adapter->san_dbf); - debug_unregister(adapter->hba_dbf); - debug_unregister(adapter->rec_dbf); - adapter->scsi_dbf = NULL; - adapter->san_dbf = NULL; - adapter->hba_dbf = NULL; - adapter->rec_dbf = NULL; + debug_unregister(adapter->dbf->scsi_dbf); + debug_unregister(adapter->dbf->san_dbf); + debug_unregister(adapter->dbf->hba_dbf); + debug_unregister(adapter->dbf->rec_dbf); + kfree(adapter->dbf); + adapter->dbf = NULL; } diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index a573f7344dd..4cfd68fe8a2 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -2,7 +2,7 @@ * This file is part of the zfcp device driver for * FCP adapters for IBM System z9 and zSeries. * - * Copyright IBM Corp. 2008, 2008 + * Copyright IBM Corp. 2008, 2009 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -222,4 +222,19 @@ struct zfcp_scsi_dbf_record { u8 sns_info[ZFCP_DBF_SCSI_FCP_SNS_INFO]; } __attribute__ ((packed)); +struct zfcp_dbf { + debug_info_t *rec_dbf; + debug_info_t *hba_dbf; + debug_info_t *san_dbf; + debug_info_t *scsi_dbf; + spinlock_t rec_dbf_lock; + spinlock_t hba_dbf_lock; + spinlock_t san_dbf_lock; + spinlock_t scsi_dbf_lock; + struct zfcp_rec_dbf_record rec_dbf_buf; + struct zfcp_hba_dbf_record hba_dbf_buf; + struct zfcp_san_dbf_record san_dbf_buf; + struct zfcp_scsi_dbf_record scsi_dbf_buf; +}; + #endif /* ZFCP_DBF_H */ diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 49d0532bca1..601f5a575de 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -37,10 +37,8 @@ #include #include #include -#include "zfcp_dbf.h" #include "zfcp_fsf.h" - /********************* GENERAL DEFINES *********************************/ #define REQUEST_LIST_SIZE 128 @@ -468,18 +466,7 @@ struct zfcp_adapter { u32 erp_low_mem_count; /* nr of erp actions waiting for memory */ struct zfcp_wka_ports *gs; /* generic services */ - debug_info_t *rec_dbf; - debug_info_t *hba_dbf; - debug_info_t *san_dbf; /* debug feature areas */ - debug_info_t *scsi_dbf; - spinlock_t rec_dbf_lock; - spinlock_t hba_dbf_lock; - spinlock_t san_dbf_lock; - spinlock_t scsi_dbf_lock; - struct zfcp_rec_dbf_record rec_dbf_buf; - struct zfcp_hba_dbf_record hba_dbf_buf; - struct zfcp_san_dbf_record san_dbf_buf; - struct zfcp_scsi_dbf_record scsi_dbf_buf; + struct zfcp_dbf *dbf; /* debug traces */ struct zfcp_adapter_mempool pool; /* Adapter memory pools */ struct qdio_initialize qdio_init_data; /* for qdio_establish */ struct fc_host_statistics *fc_stats; diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index df7f232faba..dcc7c1dbcf5 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -3,13 +3,14 @@ * * Interface to the FSF support functions. * - * Copyright IBM Corporation 2002, 2008 + * Copyright IBM Corporation 2002, 2009 */ #ifndef FSF_H #define FSF_H #include +#include #define FSF_QTCB_CURRENT_VERSION 0x00000001 -- cgit v1.2.3-18-g5258 From dcd20e2316cdc333dfdee09649dbe3642eb30e75 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 18 Aug 2009 15:43:08 +0200 Subject: [SCSI] zfcp: Only collect SCSI debug data for matching trace levels The default trace level is to only trace failed SCSI commands. Thus it is not necessary to collect trace data for most SCSI commands since it will be thrown away later. Restructure the SCSI trace infrastructure to first check the trace level in a inline function and only do the expensive data collection for matching trace levels. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 58 +++------------------------------------ drivers/s390/scsi/zfcp_dbf.h | 63 +++++++++++++++++++++++++++++++++++++++++++ drivers/s390/scsi/zfcp_ext.h | 11 +++----- drivers/s390/scsi/zfcp_fsf.c | 1 + drivers/s390/scsi/zfcp_scsi.c | 3 ++- 5 files changed, 73 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 995e6128b6c..61776d490d1 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -921,13 +921,11 @@ static struct debug_view zfcp_san_dbf_view = { NULL }; -static void zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level, - struct zfcp_adapter *adapter, - struct scsi_cmnd *scsi_cmnd, - struct zfcp_fsf_req *fsf_req, - unsigned long old_req_id) +void _zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level, + struct zfcp_dbf *dbf, struct scsi_cmnd *scsi_cmnd, + struct zfcp_fsf_req *fsf_req, + unsigned long old_req_id) { - struct zfcp_dbf *dbf = adapter->dbf; struct zfcp_scsi_dbf_record *rec = &dbf->scsi_dbf_buf; struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)rec; unsigned long flags; @@ -999,54 +997,6 @@ static void zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level, spin_unlock_irqrestore(&dbf->scsi_dbf_lock, flags); } -/** - * zfcp_scsi_dbf_event_result - trace event for SCSI command completion - * @tag: tag indicating success or failure of SCSI command - * @level: trace level applicable for this event - * @adapter: adapter that has been used to issue the SCSI command - * @scsi_cmnd: SCSI command pointer - * @fsf_req: request used to issue SCSI command (might be NULL) - */ -void zfcp_scsi_dbf_event_result(const char *tag, int level, - struct zfcp_adapter *adapter, - struct scsi_cmnd *scsi_cmnd, - struct zfcp_fsf_req *fsf_req) -{ - zfcp_scsi_dbf_event("rslt", tag, level, adapter, scsi_cmnd, fsf_req, 0); -} - -/** - * zfcp_scsi_dbf_event_abort - trace event for SCSI command abort - * @tag: tag indicating success or failure of abort operation - * @adapter: adapter thas has been used to issue SCSI command to be aborted - * @scsi_cmnd: SCSI command to be aborted - * @new_fsf_req: request containing abort (might be NULL) - * @old_req_id: identifier of request containg SCSI command to be aborted - */ -void zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter, - struct scsi_cmnd *scsi_cmnd, - struct zfcp_fsf_req *new_fsf_req, - unsigned long old_req_id) -{ - zfcp_scsi_dbf_event("abrt", tag, 1, adapter, scsi_cmnd, new_fsf_req, - old_req_id); -} - -/** - * zfcp_scsi_dbf_event_devreset - trace event for Logical Unit or Target Reset - * @tag: tag indicating success or failure of reset operation - * @flag: indicates type of reset (Target Reset, Logical Unit Reset) - * @unit: unit that needs reset - * @scsi_cmnd: SCSI command which caused this error recovery - */ -void zfcp_scsi_dbf_event_devreset(const char *tag, u8 flag, - struct zfcp_unit *unit, - struct scsi_cmnd *scsi_cmnd) -{ - zfcp_scsi_dbf_event(flag == FCP_TARGET_RESET ? "trst" : "lrst", tag, 1, - unit->port->adapter, scsi_cmnd, NULL, 0); -} - static int zfcp_scsi_dbf_view_format(debug_info_t *id, struct debug_view *view, char *out_buf, const char *in_buf) { diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 4cfd68fe8a2..c2d5ef18b73 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -22,7 +22,9 @@ #ifndef ZFCP_DBF_H #define ZFCP_DBF_H +#include "zfcp_ext.h" #include "zfcp_fsf.h" +#include "zfcp_def.h" #define ZFCP_DBF_TAG_SIZE 4 #define ZFCP_DBF_ID_SIZE 7 @@ -237,4 +239,65 @@ struct zfcp_dbf { struct zfcp_scsi_dbf_record scsi_dbf_buf; }; +static inline +void zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level, + struct zfcp_adapter *adapter, struct scsi_cmnd *scmd, + struct zfcp_fsf_req *req, unsigned long old_id) +{ + struct zfcp_dbf *dbf = adapter->dbf; + + if (level <= dbf->scsi_dbf->level) + _zfcp_scsi_dbf_event(tag, tag2, level, dbf, scmd, req, old_id); +} + +/** + * zfcp_scsi_dbf_event_result - trace event for SCSI command completion + * @tag: tag indicating success or failure of SCSI command + * @level: trace level applicable for this event + * @adapter: adapter that has been used to issue the SCSI command + * @scmd: SCSI command pointer + * @fsf_req: request used to issue SCSI command (might be NULL) + */ +static inline +void zfcp_scsi_dbf_event_result(const char *tag, int level, + struct zfcp_adapter *adapter, + struct scsi_cmnd *scmd, + struct zfcp_fsf_req *fsf_req) +{ + zfcp_scsi_dbf_event("rslt", tag, level, adapter, scmd, fsf_req, 0); +} + +/** + * zfcp_scsi_dbf_event_abort - trace event for SCSI command abort + * @tag: tag indicating success or failure of abort operation + * @adapter: adapter thas has been used to issue SCSI command to be aborted + * @scmd: SCSI command to be aborted + * @new_req: request containing abort (might be NULL) + * @old_id: identifier of request containg SCSI command to be aborted + */ +static inline +void zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter, + struct scsi_cmnd *scmd, + struct zfcp_fsf_req *new_req, + unsigned long old_id) +{ + zfcp_scsi_dbf_event("abrt", tag, 1, adapter, scmd, new_req, old_id); +} + +/** + * zfcp_scsi_dbf_event_devreset - trace event for Logical Unit or Target Reset + * @tag: tag indicating success or failure of reset operation + * @flag: indicates type of reset (Target Reset, Logical Unit Reset) + * @unit: unit that needs reset + * @scsi_cmnd: SCSI command which caused this error recovery + */ +static inline +void zfcp_scsi_dbf_event_devreset(const char *tag, u8 flag, + struct zfcp_unit *unit, + struct scsi_cmnd *scsi_cmnd) +{ + zfcp_scsi_dbf_event(flag == FCP_TARGET_RESET ? "trst" : "lrst", tag, 1, + unit->port->adapter, scsi_cmnd, NULL, 0); +} + #endif /* ZFCP_DBF_H */ diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 3044c601030..28e76f5be1a 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -57,14 +57,9 @@ extern void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *); extern void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *); extern void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *); extern void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *); -extern void zfcp_scsi_dbf_event_result(const char *, int, struct zfcp_adapter *, - struct scsi_cmnd *, - struct zfcp_fsf_req *); -extern void zfcp_scsi_dbf_event_abort(const char *, struct zfcp_adapter *, - struct scsi_cmnd *, struct zfcp_fsf_req *, - unsigned long); -extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *, - struct scsi_cmnd *); +extern void _zfcp_scsi_dbf_event(const char *, const char *, int, + struct zfcp_dbf *, struct scsi_cmnd *, + struct zfcp_fsf_req *, unsigned long); /* zfcp_erp.c */ extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, char *, diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 47795fbf081..2635216bfd9 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -11,6 +11,7 @@ #include #include "zfcp_ext.h" +#include "zfcp_dbf.h" #define ZFCP_REQ_AUTO_CLEANUP 0x00000002 #define ZFCP_REQ_NO_QTCB 0x00000008 diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 54a7a7474aa..0bd80a90426 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -9,8 +9,9 @@ #define KMSG_COMPONENT "zfcp" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt -#include "zfcp_ext.h" #include +#include "zfcp_ext.h" +#include "zfcp_dbf.h" static unsigned int default_depth = 32; module_param_named(queue_depth, default_depth, uint, 0600); -- cgit v1.2.3-18-g5258 From 2e261af84cdb6a6008a9c361443e35ea646ec683 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 18 Aug 2009 15:43:09 +0200 Subject: [SCSI] zfcp: Only collect FSF/HBA debug data for matching trace levels The default trace level is to only trace failed FSF commands. Thus it is not necessary to collect trace data for most FSF commands, since it will be thrown away later. Restructure the FSF/HBA trace infrastructure to first check the trace level in a inline function and only do the expensive data collection for matching trace levels. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 44 +++++++----------------------------- drivers/s390/scsi/zfcp_dbf.h | 53 ++++++++++++++++++++++++++++++++++++++++++++ drivers/s390/scsi/zfcp_ext.h | 9 +++++--- 3 files changed, 67 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 61776d490d1..5568440ec2f 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -120,14 +120,10 @@ static int zfcp_dbf_view_header(debug_info_t *id, struct debug_view *view, return p - out_buf; } -/** - * zfcp_hba_dbf_event_fsf_response - trace event for request completion - * @fsf_req: request that has been completed - */ -void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) +void _zfcp_hba_dbf_event_fsf_response(const char *tag2, int level, + struct zfcp_fsf_req *fsf_req, + struct zfcp_dbf *dbf) { - struct zfcp_adapter *adapter = fsf_req->adapter; - struct zfcp_dbf *dbf = adapter->dbf; struct fsf_qtcb *qtcb = fsf_req->qtcb; union fsf_prot_status_qual *prot_status_qual = &qtcb->prefix.prot_status_qual; @@ -138,31 +134,12 @@ void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) struct zfcp_send_els *send_els; struct zfcp_hba_dbf_record *rec = &dbf->hba_dbf_buf; struct zfcp_hba_dbf_record_response *response = &rec->u.response; - int level; unsigned long flags; spin_lock_irqsave(&dbf->hba_dbf_lock, flags); memset(rec, 0, sizeof(*rec)); strncpy(rec->tag, "resp", ZFCP_DBF_TAG_SIZE); - - if ((qtcb->prefix.prot_status != FSF_PROT_GOOD) && - (qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) { - strncpy(rec->tag2, "perr", ZFCP_DBF_TAG_SIZE); - level = 1; - } else if (qtcb->header.fsf_status != FSF_GOOD) { - strncpy(rec->tag2, "ferr", ZFCP_DBF_TAG_SIZE); - level = 1; - } else if ((fsf_req->fsf_command == FSF_QTCB_OPEN_PORT_WITH_DID) || - (fsf_req->fsf_command == FSF_QTCB_OPEN_LUN)) { - strncpy(rec->tag2, "open", ZFCP_DBF_TAG_SIZE); - level = 4; - } else if (qtcb->header.log_length) { - strncpy(rec->tag2, "qtcb", ZFCP_DBF_TAG_SIZE); - level = 5; - } else { - strncpy(rec->tag2, "norm", ZFCP_DBF_TAG_SIZE); - level = 6; - } + strncpy(rec->tag2, tag2, ZFCP_DBF_TAG_SIZE); response->fsf_command = fsf_req->fsf_command; response->fsf_reqid = fsf_req->req_id; @@ -241,14 +218,9 @@ void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) spin_unlock_irqrestore(&dbf->hba_dbf_lock, flags); } -/** - * zfcp_hba_dbf_event_fsf_unsol - trace event for an unsolicited status buffer - * @tag: tag indicating which kind of unsolicited status has been received - * @adapter: adapter that has issued the unsolicited status buffer - * @status_buffer: buffer containing payload of unsolicited status - */ -void zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter, - struct fsf_status_read_buffer *status_buffer) +void _zfcp_hba_dbf_event_fsf_unsol(const char *tag, int level, + struct zfcp_adapter *adapter, + struct fsf_status_read_buffer *status_buffer) { struct zfcp_dbf *dbf = adapter->dbf; struct zfcp_hba_dbf_record *rec = &dbf->hba_dbf_buf; @@ -296,7 +268,7 @@ void zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter, &status_buffer->payload, rec->u.status.payload_size); } - debug_event(dbf->hba_dbf, 2, rec, sizeof(*rec)); + debug_event(dbf->hba_dbf, level, rec, sizeof(*rec)); spin_unlock_irqrestore(&dbf->hba_dbf_lock, flags); } diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index c2d5ef18b73..bceaff44903 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -239,6 +239,59 @@ struct zfcp_dbf { struct zfcp_scsi_dbf_record scsi_dbf_buf; }; +static inline +void zfcp_hba_dbf_event_fsf_resp(const char *tag2, int level, + struct zfcp_fsf_req *req, struct zfcp_dbf *dbf) +{ + if (level <= dbf->hba_dbf->level) + _zfcp_hba_dbf_event_fsf_response(tag2, level, req, dbf); +} + +/** + * zfcp_hba_dbf_event_fsf_response - trace event for request completion + * @fsf_req: request that has been completed + */ +static inline void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *req) +{ + struct zfcp_dbf *dbf = req->adapter->dbf; + struct fsf_qtcb *qtcb = req->qtcb; + + if ((qtcb->prefix.prot_status != FSF_PROT_GOOD) && + (qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) { + zfcp_hba_dbf_event_fsf_resp("perr", 1, req, dbf); + + } else if (qtcb->header.fsf_status != FSF_GOOD) { + zfcp_hba_dbf_event_fsf_resp("ferr", 1, req, dbf); + + } else if ((req->fsf_command == FSF_QTCB_OPEN_PORT_WITH_DID) || + (req->fsf_command == FSF_QTCB_OPEN_LUN)) { + zfcp_hba_dbf_event_fsf_resp("open", 4, req, dbf); + + } else if (qtcb->header.log_length) { + zfcp_hba_dbf_event_fsf_resp("qtcb", 5, req, dbf); + + } else { + zfcp_hba_dbf_event_fsf_resp("norm", 6, req, dbf); + } + } + +/** + * zfcp_hba_dbf_event_fsf_unsol - trace event for an unsolicited status buffer + * @tag: tag indicating which kind of unsolicited status has been received + * @adapter: adapter that has issued the unsolicited status buffer + * @status_buffer: buffer containing payload of unsolicited status + */ +static inline +void zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter, + struct fsf_status_read_buffer *buf) +{ + struct zfcp_dbf *dbf = adapter->dbf; + int level = 2; + + if (level <= dbf->hba_dbf->level) + _zfcp_hba_dbf_event_fsf_unsol(tag, level, adapter, buf); +} + static inline void zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level, struct zfcp_adapter *adapter, struct scsi_cmnd *scmd, diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 28e76f5be1a..eeed322f32d 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -45,9 +45,12 @@ extern void zfcp_rec_dbf_event_trigger(char *, void *, u8, u8, void *, struct zfcp_adapter *, struct zfcp_port *, struct zfcp_unit *); extern void zfcp_rec_dbf_event_action(char *, struct zfcp_erp_action *); -extern void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *); -extern void zfcp_hba_dbf_event_fsf_unsol(const char *, struct zfcp_adapter *, - struct fsf_status_read_buffer *); +extern void _zfcp_hba_dbf_event_fsf_response(const char *, int level, + struct zfcp_fsf_req *, + struct zfcp_dbf *dbf); +extern void _zfcp_hba_dbf_event_fsf_unsol(const char *, int level, + struct zfcp_adapter *, + struct fsf_status_read_buffer *); extern void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *, unsigned int, int, int); extern void zfcp_hba_dbf_event_berr(struct zfcp_adapter *, -- cgit v1.2.3-18-g5258 From 44f09f73766a97d9c1ff8bf787cfe6b932eabc2c Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 18 Aug 2009 15:43:10 +0200 Subject: [SCSI] zfcp: Remove useless assignment Using a bitwise OR to not set anything at all is pointless so remove the useless statement. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_fsf.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 2635216bfd9..c023db864dc 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -832,7 +832,6 @@ int zfcp_fsf_status_read(struct zfcp_adapter *adapter) } sbale = zfcp_qdio_sbale_req(req); - sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS; sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY; req->sbale_curr = 2; -- cgit v1.2.3-18-g5258 From 14e242ea55a8b807dc1fb7654941caf68a20cd81 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 18 Aug 2009 15:43:11 +0200 Subject: [SCSI] zfcp: Only issue one test link command per port When the FCP channel returns a series of commands with the error status "test link", zfcp will send a series of ELS ADISC commands. This is technically no problem, but it is enough to only issue one test command per remote port. So, track whether a ELS ADISC command is already pending, and do not send a new one if there is already a pending command. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_def.h | 1 + drivers/s390/scsi/zfcp_fc.c | 9 +++++++++ 2 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 601f5a575de..c1becfc1e7f 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -232,6 +232,7 @@ struct zfcp_ls_adisc { /* remote port status */ #define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001 +#define ZFCP_STATUS_PORT_LINK_TEST 0x00000002 /* well known address (WKA) port status*/ enum zfcp_wka_status { diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 47daebfa7e5..94c13bd32b5 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -404,6 +404,7 @@ static void zfcp_fc_adisc_handler(unsigned long data) /* port is good, unblock rport without going through erp */ zfcp_scsi_schedule_rport_register(port); out: + atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); zfcp_port_put(port); kfree(adisc); } @@ -450,13 +451,21 @@ void zfcp_fc_link_test_work(struct work_struct *work) port->rport_task = RPORT_DEL; zfcp_scsi_rport_work(&port->rport_work); + /* only issue one test command at one time per port */ + if (atomic_read(&port->status) & ZFCP_STATUS_PORT_LINK_TEST) + goto out; + + atomic_set_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); + retval = zfcp_fc_adisc(port); if (retval == 0) return; /* send of ADISC was not possible */ + atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL); +out: zfcp_port_put(port); } -- cgit v1.2.3-18-g5258 From 55c770fa11d21456e02dc7afb9a37404da9c7b4c Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 18 Aug 2009 15:43:12 +0200 Subject: [SCSI] zfcp: Implicitly close all wka ports An adapter shutdown implicitly closes all open ports. Make sure to mark all WKA ports as offline, not only the directory server. Also make sure that no pending wka port work is running when the adapter is being removed. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 1 + drivers/s390/scsi/zfcp_erp.c | 2 +- drivers/s390/scsi/zfcp_ext.h | 4 +--- drivers/s390/scsi/zfcp_fc.c | 11 ++++++++++- 4 files changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 870fe79bc7e..7aba6840243 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -555,6 +555,7 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) cancel_work_sync(&adapter->scan_work); cancel_work_sync(&adapter->stat_work); + zfcp_fc_wka_ports_force_offline(adapter->gs); zfcp_adapter_scsi_unregister(adapter); sysfs_remove_group(&adapter->ccw_device->dev.kobj, &zfcp_sysfs_adapter_attrs); diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index c75d6f35cb5..39e4dd15453 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -714,7 +714,7 @@ static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act) zfcp_qdio_close(adapter); zfcp_fsf_req_dismiss_all(adapter); adapter->fsf_req_seq_no = 0; - zfcp_fc_wka_port_force_offline(&adapter->gs->ds); + zfcp_fc_wka_ports_force_offline(adapter->gs); /* all ports and units are closed */ zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL, ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index eeed322f32d..1a66695f11a 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -104,12 +104,10 @@ extern int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *); extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); extern void zfcp_test_link(struct zfcp_port *); extern void zfcp_fc_link_test_work(struct work_struct *); -extern void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *); +extern void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *); extern void zfcp_fc_wka_ports_init(struct zfcp_adapter *); extern int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *); extern int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *); -extern void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *); - /* zfcp_fsf.c */ extern int zfcp_fsf_open_port(struct zfcp_erp_action *); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 94c13bd32b5..6d0fef92567 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -132,7 +132,7 @@ static void zfcp_fc_wka_port_init(struct zfcp_wka_port *wka_port, u32 d_id, INIT_DELAYED_WORK(&wka_port->work, zfcp_wka_port_offline); } -void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *wka) +static void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *wka) { cancel_delayed_work_sync(&wka->work); mutex_lock(&wka->mutex); @@ -140,6 +140,15 @@ void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *wka) mutex_unlock(&wka->mutex); } +void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *gs) +{ + zfcp_fc_wka_port_force_offline(&gs->ms); + zfcp_fc_wka_port_force_offline(&gs->ts); + zfcp_fc_wka_port_force_offline(&gs->ds); + zfcp_fc_wka_port_force_offline(&gs->as); + zfcp_fc_wka_port_force_offline(&gs->ks); +} + void zfcp_fc_wka_ports_init(struct zfcp_adapter *adapter) { struct zfcp_wka_ports *gs = adapter->gs; -- cgit v1.2.3-18-g5258 From bd63eaf4b8d783e6033930e377e516169abcadc4 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 18 Aug 2009 15:43:13 +0200 Subject: [SCSI] zfcp: fix layering oddities between zfcp_fsf and zfcp_qdio There is no need for the QDIO layer to have knowledge or do things wich are done better by the FSF layer and vice versa. Straighten a few things to improve vividness. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_ext.h | 2 +- drivers/s390/scsi/zfcp_fsf.c | 100 +++++++++++++++++++++++++++++------------- drivers/s390/scsi/zfcp_qdio.c | 45 +------------------ 3 files changed, 73 insertions(+), 74 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 1a66695f11a..6a3727bdb38 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -133,11 +133,11 @@ extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *, extern int zfcp_fsf_send_els(struct zfcp_send_els *); extern int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *, struct scsi_cmnd *); -extern void zfcp_fsf_req_complete(struct zfcp_fsf_req *); extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *, u8); extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long, struct zfcp_unit *); +extern void zfcp_fsf_reqid_check(struct zfcp_adapter *, int); /* zfcp_qdio.c */ extern int zfcp_qdio_allocate(struct zfcp_adapter *); diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index c023db864dc..7ca2995aaf6 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -122,35 +122,6 @@ void zfcp_fsf_req_free(struct zfcp_fsf_req *req) } } -/** - * zfcp_fsf_req_dismiss_all - dismiss all fsf requests - * @adapter: pointer to struct zfcp_adapter - * - * Never ever call this without shutting down the adapter first. - * Otherwise the adapter would continue using and corrupting s390 storage. - * Included BUG_ON() call to ensure this is done. - * ERP is supposed to be the only user of this function. - */ -void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) -{ - struct zfcp_fsf_req *req, *tmp; - unsigned long flags; - LIST_HEAD(remove_queue); - unsigned int i; - - BUG_ON(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP); - spin_lock_irqsave(&adapter->req_list_lock, flags); - for (i = 0; i < REQUEST_LIST_SIZE; i++) - list_splice_init(&adapter->req_list[i], &remove_queue); - spin_unlock_irqrestore(&adapter->req_list_lock, flags); - - list_for_each_entry_safe(req, tmp, &remove_queue, list) { - list_del(&req->list); - req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; - zfcp_fsf_req_complete(req); - } -} - static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req) { struct fsf_status_read_buffer *sr_buf = req->data; @@ -459,7 +430,7 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req) * is called to process the completion status and trigger further * events related to the FSF request. */ -void zfcp_fsf_req_complete(struct zfcp_fsf_req *req) +static void zfcp_fsf_req_complete(struct zfcp_fsf_req *req) { if (unlikely(req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) { zfcp_fsf_status_read_handler(req); @@ -492,6 +463,35 @@ void zfcp_fsf_req_complete(struct zfcp_fsf_req *req) wake_up(&req->completion_wq); } +/** + * zfcp_fsf_req_dismiss_all - dismiss all fsf requests + * @adapter: pointer to struct zfcp_adapter + * + * Never ever call this without shutting down the adapter first. + * Otherwise the adapter would continue using and corrupting s390 storage. + * Included BUG_ON() call to ensure this is done. + * ERP is supposed to be the only user of this function. + */ +void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) +{ + struct zfcp_fsf_req *req, *tmp; + unsigned long flags; + LIST_HEAD(remove_queue); + unsigned int i; + + BUG_ON(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP); + spin_lock_irqsave(&adapter->req_list_lock, flags); + for (i = 0; i < REQUEST_LIST_SIZE; i++) + list_splice_init(&adapter->req_list[i], &remove_queue); + spin_unlock_irqrestore(&adapter->req_list_lock, flags); + + list_for_each_entry_safe(req, tmp, &remove_queue, list) { + list_del(&req->list); + req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; + zfcp_fsf_req_complete(req); + } +} + static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) { struct fsf_qtcb_bottom_config *bottom; @@ -2578,3 +2578,43 @@ out: } return ERR_PTR(retval); } + +/** + * zfcp_fsf_reqid_check - validate req_id contained in SBAL returned by QDIO + * @adapter: pointer to struct zfcp_adapter + * @sbal_idx: response queue index of SBAL to be processed + */ +void zfcp_fsf_reqid_check(struct zfcp_adapter *adapter, int sbal_idx) +{ + struct qdio_buffer *sbal = adapter->resp_q.sbal[sbal_idx]; + struct qdio_buffer_element *sbale; + struct zfcp_fsf_req *fsf_req; + unsigned long flags, req_id; + int idx; + + for (idx = 0; idx < QDIO_MAX_ELEMENTS_PER_BUFFER; idx++) { + + sbale = &sbal->element[idx]; + req_id = (unsigned long) sbale->addr; + spin_lock_irqsave(&adapter->req_list_lock, flags); + fsf_req = zfcp_reqlist_find(adapter, req_id); + + if (!fsf_req) + /* + * Unknown request means that we have potentially memory + * corruption and must stop the machine immediately. + */ + panic("error: unknown req_id (%lx) on adapter %s.\n", + req_id, dev_name(&adapter->ccw_device->dev)); + + list_del(&fsf_req->list); + spin_unlock_irqrestore(&adapter->req_list_lock, flags); + + fsf_req->sbal_response = sbal_idx; + fsf_req->qdio_inb_usage = atomic_read(&adapter->resp_q.count); + zfcp_fsf_req_complete(fsf_req); + + if (likely(sbale->flags & SBAL_FLAGS_LAST_ENTRY)) + break; + } +} diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index e0a215309df..2e9b3a9cebd 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -112,31 +112,6 @@ static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err, wake_up(&adapter->request_wq); } -static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, - unsigned long req_id, int sbal_idx) -{ - struct zfcp_fsf_req *fsf_req; - unsigned long flags; - - spin_lock_irqsave(&adapter->req_list_lock, flags); - fsf_req = zfcp_reqlist_find(adapter, req_id); - - if (!fsf_req) - /* - * Unknown request means that we have potentially memory - * corruption and must stop the machine immediatly. - */ - panic("error: unknown request id (%lx) on adapter %s.\n", - req_id, dev_name(&adapter->ccw_device->dev)); - - zfcp_reqlist_remove(adapter, fsf_req); - spin_unlock_irqrestore(&adapter->req_list_lock, flags); - - fsf_req->sbal_response = sbal_idx; - fsf_req->qdio_inb_usage = atomic_read(&adapter->resp_q.count); - zfcp_fsf_req_complete(fsf_req); -} - static void zfcp_qdio_resp_put_back(struct zfcp_adapter *adapter, int processed) { struct zfcp_qdio_queue *queue = &adapter->resp_q; @@ -163,9 +138,7 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, unsigned long parm) { struct zfcp_adapter *adapter = (struct zfcp_adapter *) parm; - struct zfcp_qdio_queue *queue = &adapter->resp_q; - struct qdio_buffer_element *sbale; - int sbal_idx, sbale_idx, sbal_no; + int sbal_idx, sbal_no; if (unlikely(qdio_err)) { zfcp_hba_dbf_event_qdio(adapter, qdio_err, first, count); @@ -179,22 +152,8 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, */ for (sbal_no = 0; sbal_no < count; sbal_no++) { sbal_idx = (first + sbal_no) % QDIO_MAX_BUFFERS_PER_Q; - /* go through all SBALEs of SBAL */ - for (sbale_idx = 0; sbale_idx < QDIO_MAX_ELEMENTS_PER_BUFFER; - sbale_idx++) { - sbale = zfcp_qdio_sbale(queue, sbal_idx, sbale_idx); - zfcp_qdio_reqid_check(adapter, - (unsigned long) sbale->addr, - sbal_idx); - if (likely(sbale->flags & SBAL_FLAGS_LAST_ENTRY)) - break; - }; - - if (unlikely(!(sbale->flags & SBAL_FLAGS_LAST_ENTRY))) - dev_warn(&adapter->ccw_device->dev, - "A QDIO protocol error occurred, " - "operations continue\n"); + zfcp_fsf_reqid_check(adapter, sbal_idx); } /* -- cgit v1.2.3-18-g5258 From 058b8647892ed49ba6a0d2c0966a72e20e2e69ff Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 18 Aug 2009 15:43:14 +0200 Subject: [SCSI] zfcp: Replace fsf_req wait_queue with completion The combination wait_queue/wakeup in conjunction with the flag ZFCP_STATUS_FSFREQ_COMPLETED to signal the completion of an fsfreq was not race-safe and can be better solved by a completion. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_def.h | 3 +-- drivers/s390/scsi/zfcp_erp.c | 3 +-- drivers/s390/scsi/zfcp_fsf.c | 26 ++++++-------------------- drivers/s390/scsi/zfcp_scsi.c | 6 ++---- 4 files changed, 10 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index c1becfc1e7f..944f67754ee 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -248,7 +248,6 @@ enum zfcp_wka_status { /* FSF request status (this does not have a common part) */ #define ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT 0x00000002 -#define ZFCP_STATUS_FSFREQ_COMPLETED 0x00000004 #define ZFCP_STATUS_FSFREQ_ERROR 0x00000008 #define ZFCP_STATUS_FSFREQ_CLEANUP 0x00000010 #define ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED 0x00000040 @@ -532,7 +531,7 @@ struct zfcp_fsf_req { u8 sbale_curr; /* current SBALE during creation of request */ u8 sbal_response; /* SBAL used in interrupt */ - wait_queue_head_t completion_wq; /* can be used by a routine + struct completion completion; /* can be used by a routine to wait for completion */ u32 status; /* status of this request */ u32 fsf_command; /* FSF Command copy */ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 39e4dd15453..a377e2f9125 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -485,8 +485,7 @@ static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act) } if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) zfcp_rec_dbf_event_action("erscf_2", act); - if (act->fsf_req->status & (ZFCP_STATUS_FSFREQ_COMPLETED | - ZFCP_STATUS_FSFREQ_DISMISSED)) + if (act->fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) act->fsf_req = NULL; } else act->fsf_req = NULL; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 7ca2995aaf6..ed06a1d17b7 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -444,23 +444,11 @@ static void zfcp_fsf_req_complete(struct zfcp_fsf_req *req) if (req->erp_action) zfcp_erp_notify(req->erp_action, 0); - req->status |= ZFCP_STATUS_FSFREQ_COMPLETED; if (likely(req->status & ZFCP_STATUS_FSFREQ_CLEANUP)) zfcp_fsf_req_free(req); else - /* notify initiator waiting for the requests completion */ - /* - * FIXME: Race! We must not access fsf_req here as it might have been - * cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED - * flag. It's an improbable case. But, we have the same paranoia for - * the cleanup flag already. - * Might better be handled using complete()? - * (setting the flag and doing wakeup ought to be atomic - * with regard to checking the flag as long as waitqueue is - * part of the to be released structure) - */ - wake_up(&req->completion_wq); + complete(&req->completion); } /** @@ -733,7 +721,7 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter, INIT_LIST_HEAD(&req->list); init_timer(&req->timer); - init_waitqueue_head(&req->completion_wq); + init_completion(&req->completion); req->adapter = adapter; req->fsf_command = fsf_cmd; @@ -1309,8 +1297,7 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, retval = zfcp_fsf_req_send(req); spin_unlock_bh(&adapter->req_q_lock); if (!retval) - wait_event(req->completion_wq, - req->status & ZFCP_STATUS_FSFREQ_COMPLETED); + wait_for_completion(&req->completion); zfcp_fsf_req_free(req); return retval; @@ -1405,8 +1392,8 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, spin_unlock_bh(&adapter->req_q_lock); if (!retval) - wait_event(req->completion_wq, - req->status & ZFCP_STATUS_FSFREQ_COMPLETED); + wait_for_completion(&req->completion); + zfcp_fsf_req_free(req); return retval; @@ -2572,8 +2559,7 @@ out: spin_unlock_bh(&adapter->req_q_lock); if (!retval) { - wait_event(req->completion_wq, - req->status & ZFCP_STATUS_FSFREQ_COMPLETED); + wait_for_completion(&req->completion); return req; } return ERR_PTR(retval); diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 0bd80a90426..0de059161b3 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -206,8 +206,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) if (!abrt_req) return FAILED; - wait_event(abrt_req->completion_wq, - abrt_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); + wait_for_completion(&abrt_req->completion); if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) dbf_tag = "okay"; @@ -246,8 +245,7 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) if (!fsf_req) return FAILED; - wait_event(fsf_req->completion_wq, - fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); + wait_for_completion(&fsf_req->completion); if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt); -- cgit v1.2.3-18-g5258 From a4623c467ff76f9258555d44d68371e10c5406c2 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 18 Aug 2009 15:43:15 +0200 Subject: [SCSI] zfcp: Improve request allocation through mempools Remove the special case for NO_QTCB requests and optimize the mempool and cache processing for fsfreqs. Especially use seperate mempools for the zfcp_fsf_req and zfcp_qtcb structs. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 98 +++++++++++++++++++++++++------------------- drivers/s390/scsi/zfcp_def.h | 31 ++++++++------ drivers/s390/scsi/zfcp_fc.c | 19 +++------ drivers/s390/scsi/zfcp_fsf.c | 92 ++++++++++++++++++++++------------------- 4 files changed, 127 insertions(+), 113 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 7aba6840243..de623292277 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -42,6 +42,12 @@ static char *init_device; module_param_named(device, init_device, charp, 0400); MODULE_PARM_DESC(device, "specify initial device"); +static struct kmem_cache *zfcp_cache_hw_align(const char *name, + unsigned long size) +{ + return kmem_cache_create(name, size, roundup_pow_of_two(size), 0, NULL); +} + static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter) { int idx; @@ -110,14 +116,6 @@ out_adapter: return; } -static struct kmem_cache *zfcp_cache_create(int size, char *name) -{ - int align = 1; - while ((size - align) > 0) - align <<= 1; - return kmem_cache_create(name , size, align, 0, NULL); -} - static void __init zfcp_init_device_setup(char *devstr) { char *token; @@ -158,18 +156,23 @@ static int __init zfcp_module_init(void) { int retval = -ENOMEM; - zfcp_data.fsf_req_qtcb_cache = zfcp_cache_create( - sizeof(struct zfcp_fsf_req_qtcb), "zfcp_fsf"); - if (!zfcp_data.fsf_req_qtcb_cache) + zfcp_data.gpn_ft_cache = zfcp_cache_hw_align("zfcp_gpn", + sizeof(struct ct_iu_gpn_ft_req)); + if (!zfcp_data.gpn_ft_cache) goto out; - zfcp_data.sr_buffer_cache = zfcp_cache_create( - sizeof(struct fsf_status_read_buffer), "zfcp_sr"); + zfcp_data.qtcb_cache = zfcp_cache_hw_align("zfcp_qtcb", + sizeof(struct fsf_qtcb)); + if (!zfcp_data.qtcb_cache) + goto out_qtcb_cache; + + zfcp_data.sr_buffer_cache = zfcp_cache_hw_align("zfcp_sr", + sizeof(struct fsf_status_read_buffer)); if (!zfcp_data.sr_buffer_cache) goto out_sr_cache; - zfcp_data.gid_pn_cache = zfcp_cache_create( - sizeof(struct zfcp_gid_pn_data), "zfcp_gid"); + zfcp_data.gid_pn_cache = zfcp_cache_hw_align("zfcp_gid", + sizeof(struct zfcp_gid_pn_data)); if (!zfcp_data.gid_pn_cache) goto out_gid_cache; @@ -209,7 +212,9 @@ out_transport: out_gid_cache: kmem_cache_destroy(zfcp_data.sr_buffer_cache); out_sr_cache: - kmem_cache_destroy(zfcp_data.fsf_req_qtcb_cache); + kmem_cache_destroy(zfcp_data.qtcb_cache); +out_qtcb_cache: + kmem_cache_destroy(zfcp_data.gpn_ft_cache); out: return retval; } @@ -354,36 +359,41 @@ void zfcp_unit_dequeue(struct zfcp_unit *unit) static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) { /* must only be called with zfcp_data.config_sema taken */ - adapter->pool.fsf_req_erp = - mempool_create_slab_pool(1, zfcp_data.fsf_req_qtcb_cache); - if (!adapter->pool.fsf_req_erp) + adapter->pool.erp_req = + mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req)); + if (!adapter->pool.erp_req) return -ENOMEM; - adapter->pool.fsf_req_scsi = - mempool_create_slab_pool(1, zfcp_data.fsf_req_qtcb_cache); - if (!adapter->pool.fsf_req_scsi) + adapter->pool.scsi_req = + mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req)); + if (!adapter->pool.scsi_req) return -ENOMEM; - adapter->pool.fsf_req_abort = - mempool_create_slab_pool(1, zfcp_data.fsf_req_qtcb_cache); - if (!adapter->pool.fsf_req_abort) + adapter->pool.scsi_abort = + mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req)); + if (!adapter->pool.scsi_abort) return -ENOMEM; - adapter->pool.fsf_req_status_read = + adapter->pool.status_read_req = mempool_create_kmalloc_pool(FSF_STATUS_READS_RECOM, sizeof(struct zfcp_fsf_req)); - if (!adapter->pool.fsf_req_status_read) + if (!adapter->pool.status_read_req) + return -ENOMEM; + + adapter->pool.qtcb_pool = + mempool_create_slab_pool(3, zfcp_data.qtcb_cache); + if (!adapter->pool.qtcb_pool) return -ENOMEM; - adapter->pool.data_status_read = + adapter->pool.status_read_data = mempool_create_slab_pool(FSF_STATUS_READS_RECOM, zfcp_data.sr_buffer_cache); - if (!adapter->pool.data_status_read) + if (!adapter->pool.status_read_data) return -ENOMEM; - adapter->pool.data_gid_pn = + adapter->pool.gid_pn_data = mempool_create_slab_pool(1, zfcp_data.gid_pn_cache); - if (!adapter->pool.data_gid_pn) + if (!adapter->pool.gid_pn_data) return -ENOMEM; return 0; @@ -392,18 +402,20 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) { /* zfcp_data.config_sema must be held */ - if (adapter->pool.fsf_req_erp) - mempool_destroy(adapter->pool.fsf_req_erp); - if (adapter->pool.fsf_req_scsi) - mempool_destroy(adapter->pool.fsf_req_scsi); - if (adapter->pool.fsf_req_abort) - mempool_destroy(adapter->pool.fsf_req_abort); - if (adapter->pool.fsf_req_status_read) - mempool_destroy(adapter->pool.fsf_req_status_read); - if (adapter->pool.data_status_read) - mempool_destroy(adapter->pool.data_status_read); - if (adapter->pool.data_gid_pn) - mempool_destroy(adapter->pool.data_gid_pn); + if (adapter->pool.erp_req) + mempool_destroy(adapter->pool.erp_req); + if (adapter->pool.scsi_req) + mempool_destroy(adapter->pool.scsi_req); + if (adapter->pool.scsi_abort) + mempool_destroy(adapter->pool.scsi_abort); + if (adapter->pool.qtcb_pool) + mempool_destroy(adapter->pool.qtcb_pool); + if (adapter->pool.status_read_req) + mempool_destroy(adapter->pool.status_read_req); + if (adapter->pool.status_read_data) + mempool_destroy(adapter->pool.status_read_data); + if (adapter->pool.gid_pn_data) + mempool_destroy(adapter->pool.gid_pn_data); } /** diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 944f67754ee..1e27ed5d90e 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -264,12 +264,13 @@ struct zfcp_fsf_req; /* holds various memory pools of an adapter */ struct zfcp_adapter_mempool { - mempool_t *fsf_req_erp; - mempool_t *fsf_req_scsi; - mempool_t *fsf_req_abort; - mempool_t *fsf_req_status_read; - mempool_t *data_status_read; - mempool_t *data_gid_pn; + mempool_t *erp_req; + mempool_t *scsi_req; + mempool_t *scsi_abort; + mempool_t *status_read_req; + mempool_t *status_read_data; + mempool_t *gid_pn_data; + mempool_t *qtcb_pool; }; /* @@ -303,6 +304,15 @@ struct ct_iu_gid_pn_resp { u32 d_id; } __attribute__ ((packed)); +struct ct_iu_gpn_ft_req { + struct ct_hdr header; + u8 flags; + u8 domain_id_scope; + u8 area_id_scope; + u8 fc4_type; +} __attribute__ ((packed)); + + /** * struct zfcp_send_ct - used to pass parameters to function zfcp_fsf_send_ct * @wka_port: port where the request is sent to @@ -559,18 +569,13 @@ struct zfcp_data { lists */ struct semaphore config_sema; /* serialises configuration changes */ - struct kmem_cache *fsf_req_qtcb_cache; + struct kmem_cache *gpn_ft_cache; + struct kmem_cache *qtcb_cache; struct kmem_cache *sr_buffer_cache; struct kmem_cache *gid_pn_cache; struct workqueue_struct *work_queue; }; -/* struct used by memory pools for fsf_requests */ -struct zfcp_fsf_req_qtcb { - struct zfcp_fsf_req fsf_req; - struct fsf_qtcb qtcb; -}; - /********************** ZFCP SPECIFIC DEFINES ********************************/ #define ZFCP_SET 0x00000100 diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 6d0fef92567..acadcd3c276 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -25,14 +25,6 @@ static u32 rscn_range_mask[] = { [RSCN_FABRIC_ADDRESS] = 0x000000, }; -struct ct_iu_gpn_ft_req { - struct ct_hdr header; - u8 flags; - u8 domain_id_scope; - u8 area_id_scope; - u8 fc4_type; -} __attribute__ ((packed)); - struct gpn_ft_resp_acc { u8 control; u8 port_id[3]; @@ -322,8 +314,7 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, init_completion(&compl_rec.done); compl_rec.handler = zfcp_fc_ns_gid_pn_eval; compl_rec.handler_data = (unsigned long) gid_pn; - ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp, - erp_action); + ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.erp_req, erp_action); if (!ret) wait_for_completion(&compl_rec.done); return ret; @@ -340,7 +331,7 @@ int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *erp_action) struct zfcp_gid_pn_data *gid_pn; struct zfcp_adapter *adapter = erp_action->adapter; - gid_pn = mempool_alloc(adapter->pool.data_gid_pn, GFP_ATOMIC); + gid_pn = mempool_alloc(adapter->pool.gid_pn_data, GFP_ATOMIC); if (!gid_pn) return -ENOMEM; @@ -354,7 +345,7 @@ int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *erp_action) zfcp_wka_port_put(&adapter->gs->ds); out: - mempool_free(gid_pn, adapter->pool.data_gid_pn); + mempool_free(gid_pn, adapter->pool.gid_pn_data); return ret; } @@ -497,7 +488,7 @@ static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num) { struct scatterlist *sg = &gpn_ft->sg_req; - kfree(sg_virt(sg)); /* free request buffer */ + kmem_cache_free(zfcp_data.gpn_ft_cache, sg_virt(sg)); zfcp_sg_free_table(gpn_ft->sg_resp, buf_num); kfree(gpn_ft); @@ -512,7 +503,7 @@ static struct zfcp_gpn_ft *zfcp_alloc_sg_env(int buf_num) if (!gpn_ft) return NULL; - req = kzalloc(sizeof(struct ct_iu_gpn_ft_req), GFP_KERNEL); + req = kmem_cache_alloc(zfcp_data.gpn_ft_cache, GFP_KERNEL); if (!req) { kfree(gpn_ft); gpn_ft = NULL; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index ed06a1d17b7..96c580ee750 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -14,7 +14,6 @@ #include "zfcp_dbf.h" #define ZFCP_REQ_AUTO_CLEANUP 0x00000002 -#define ZFCP_REQ_NO_QTCB 0x00000008 static void zfcp_fsf_request_timeout_handler(unsigned long data) { @@ -112,14 +111,15 @@ static void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req) void zfcp_fsf_req_free(struct zfcp_fsf_req *req) { if (likely(req->pool)) { + if (likely(req->qtcb)) + mempool_free(req->qtcb, req->adapter->pool.qtcb_pool); mempool_free(req, req->pool); return; } - if (req->qtcb) { - kmem_cache_free(zfcp_data.fsf_req_qtcb_cache, req); - return; - } + if (likely(req->qtcb)) + kmem_cache_free(zfcp_data.qtcb_cache, req->qtcb); + kfree(req); } static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req) @@ -251,7 +251,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { zfcp_hba_dbf_event_fsf_unsol("dism", adapter, sr_buf); - mempool_free(sr_buf, adapter->pool.data_status_read); + mempool_free(sr_buf, adapter->pool.status_read_data); zfcp_fsf_req_free(req); return; } @@ -303,7 +303,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) break; } - mempool_free(sr_buf, adapter->pool.data_status_read); + mempool_free(sr_buf, adapter->pool.status_read_data); zfcp_fsf_req_free(req); atomic_inc(&adapter->stat_miss); @@ -669,34 +669,37 @@ static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter) return -EIO; } -static struct zfcp_fsf_req *zfcp_fsf_alloc_noqtcb(mempool_t *pool) +static struct zfcp_fsf_req *zfcp_fsf_alloc(mempool_t *pool) { struct zfcp_fsf_req *req; - req = mempool_alloc(pool, GFP_ATOMIC); - if (!req) + + if (likely(pool)) + req = mempool_alloc(pool, GFP_ATOMIC); + else + req = kmalloc(sizeof(*req), GFP_ATOMIC); + + if (unlikely(!req)) return NULL; + memset(req, 0, sizeof(*req)); req->pool = pool; return req; } -static struct zfcp_fsf_req *zfcp_fsf_alloc_qtcb(mempool_t *pool) +static struct fsf_qtcb *zfcp_qtcb_alloc(mempool_t *pool) { - struct zfcp_fsf_req_qtcb *qtcb; + struct fsf_qtcb *qtcb; if (likely(pool)) qtcb = mempool_alloc(pool, GFP_ATOMIC); else - qtcb = kmem_cache_alloc(zfcp_data.fsf_req_qtcb_cache, - GFP_ATOMIC); + qtcb = kmem_cache_alloc(zfcp_data.qtcb_cache, GFP_ATOMIC); + if (unlikely(!qtcb)) return NULL; memset(qtcb, 0, sizeof(*qtcb)); - qtcb->fsf_req.qtcb = &qtcb->qtcb; - qtcb->fsf_req.pool = pool; - - return &qtcb->fsf_req; + return qtcb; } static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter, @@ -704,14 +707,8 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter, mempool_t *pool) { struct qdio_buffer_element *sbale; - - struct zfcp_fsf_req *req; struct zfcp_qdio_queue *req_q = &adapter->req_q; - - if (req_flags & ZFCP_REQ_NO_QTCB) - req = zfcp_fsf_alloc_noqtcb(pool); - else - req = zfcp_fsf_alloc_qtcb(pool); + struct zfcp_fsf_req *req = zfcp_fsf_alloc(pool); if (unlikely(!req)) return ERR_PTR(-ENOMEM); @@ -735,7 +732,17 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter, sbale[0].addr = (void *) req->req_id; sbale[0].flags |= SBAL_FLAGS0_COMMAND; - if (likely(req->qtcb)) { + if (likely(fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS)) { + if (likely(pool)) + req->qtcb = zfcp_qtcb_alloc(adapter->pool.qtcb_pool); + else + req->qtcb = zfcp_qtcb_alloc(NULL); + + if (unlikely(!req->qtcb)) { + zfcp_fsf_req_free(req); + return ERR_PTR(-ENOMEM); + } + req->qtcb->prefix.req_seq_no = req->adapter->fsf_req_seq_no; req->qtcb->prefix.req_id = req->req_id; req->qtcb->prefix.ulp_info = 26; @@ -811,9 +818,8 @@ int zfcp_fsf_status_read(struct zfcp_adapter *adapter) if (zfcp_fsf_req_sbal_get(adapter)) goto out; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS, - ZFCP_REQ_NO_QTCB, - adapter->pool.fsf_req_status_read); + req = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS, 0, + adapter->pool.status_read_req); if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; @@ -823,7 +829,7 @@ int zfcp_fsf_status_read(struct zfcp_adapter *adapter) sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY; req->sbale_curr = 2; - sr_buf = mempool_alloc(adapter->pool.data_status_read, GFP_ATOMIC); + sr_buf = mempool_alloc(adapter->pool.status_read_data, GFP_ATOMIC); if (!sr_buf) { retval = -ENOMEM; goto failed_buf; @@ -841,7 +847,7 @@ int zfcp_fsf_status_read(struct zfcp_adapter *adapter) goto out; failed_req_send: - mempool_free(sr_buf, adapter->pool.data_status_read); + mempool_free(sr_buf, adapter->pool.status_read_data); failed_buf: zfcp_fsf_req_free(req); zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL); @@ -919,7 +925,7 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id, if (zfcp_fsf_req_sbal_get(adapter)) goto out; req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND, - 0, adapter->pool.fsf_req_abort); + 0, adapter->pool.scsi_abort); if (IS_ERR(req)) { req = NULL; goto out; @@ -1231,7 +1237,7 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, ZFCP_REQ_AUTO_CLEANUP, - adapter->pool.fsf_req_erp); + adapter->pool.erp_req); if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; @@ -1327,7 +1333,7 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) goto out; req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, ZFCP_REQ_AUTO_CLEANUP, - adapter->pool.fsf_req_erp); + adapter->pool.erp_req); if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; @@ -1497,7 +1503,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) req = zfcp_fsf_req_create(adapter, FSF_QTCB_OPEN_PORT_WITH_DID, ZFCP_REQ_AUTO_CLEANUP, - adapter->pool.fsf_req_erp); + adapter->pool.erp_req); if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; @@ -1566,7 +1572,7 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT, ZFCP_REQ_AUTO_CLEANUP, - adapter->pool.fsf_req_erp); + adapter->pool.erp_req); if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; @@ -1643,7 +1649,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_wka_port *wka_port) req = zfcp_fsf_req_create(adapter, FSF_QTCB_OPEN_PORT_WITH_DID, ZFCP_REQ_AUTO_CLEANUP, - adapter->pool.fsf_req_erp); + adapter->pool.erp_req); if (unlikely(IS_ERR(req))) { retval = PTR_ERR(req); goto out; @@ -1697,7 +1703,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_wka_port *wka_port) req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT, ZFCP_REQ_AUTO_CLEANUP, - adapter->pool.fsf_req_erp); + adapter->pool.erp_req); if (unlikely(IS_ERR(req))) { retval = PTR_ERR(req); goto out; @@ -1788,7 +1794,7 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PHYSICAL_PORT, ZFCP_REQ_AUTO_CLEANUP, - adapter->pool.fsf_req_erp); + adapter->pool.erp_req); if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; @@ -1960,7 +1966,7 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) req = zfcp_fsf_req_create(adapter, FSF_QTCB_OPEN_LUN, ZFCP_REQ_AUTO_CLEANUP, - adapter->pool.fsf_req_erp); + adapter->pool.erp_req); if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; @@ -2045,7 +2051,7 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) goto out; req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_LUN, ZFCP_REQ_AUTO_CLEANUP, - adapter->pool.fsf_req_erp); + adapter->pool.erp_req); if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; @@ -2349,7 +2355,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, } req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, ZFCP_REQ_AUTO_CLEANUP, - adapter->pool.fsf_req_scsi); + adapter->pool.scsi_req); if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; @@ -2460,7 +2466,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags) if (zfcp_fsf_req_sbal_get(adapter)) goto out; req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, 0, - adapter->pool.fsf_req_scsi); + adapter->pool.scsi_req); if (IS_ERR(req)) { req = NULL; goto out; -- cgit v1.2.3-18-g5258 From 09a46c6e34ba152169b7400d266d2efb4c391a43 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 18 Aug 2009 15:43:16 +0200 Subject: [SCSI] zfcp: Remove the useless ZFCP_REQ_AUTO_CLEANUP flag The flag ZFCP_REQ_AUTO_CLEANUP was useless as the ZFCP_STATUS_FSFREQ_CLEANUP flag is there for exactly the same purpose. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_fsf.c | 80 +++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 96c580ee750..70a978a14f2 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -13,8 +13,6 @@ #include "zfcp_ext.h" #include "zfcp_dbf.h" -#define ZFCP_REQ_AUTO_CLEANUP 0x00000002 - static void zfcp_fsf_request_timeout_handler(unsigned long data) { struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; @@ -703,8 +701,7 @@ static struct fsf_qtcb *zfcp_qtcb_alloc(mempool_t *pool) } static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter, - u32 fsf_cmd, int req_flags, - mempool_t *pool) + u32 fsf_cmd, mempool_t *pool) { struct qdio_buffer_element *sbale; struct zfcp_qdio_queue *req_q = &adapter->req_q; @@ -761,9 +758,6 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter, return ERR_PTR(-EIO); } - if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP)) - req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - return req; } @@ -818,7 +812,7 @@ int zfcp_fsf_status_read(struct zfcp_adapter *adapter) if (zfcp_fsf_req_sbal_get(adapter)) goto out; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS, 0, + req = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS, adapter->pool.status_read_req); if (IS_ERR(req)) { retval = PTR_ERR(req); @@ -925,7 +919,7 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id, if (zfcp_fsf_req_sbal_get(adapter)) goto out; req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND, - 0, adapter->pool.scsi_abort); + adapter->pool.scsi_abort); if (IS_ERR(req)) { req = NULL; goto out; @@ -1081,13 +1075,14 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, if (zfcp_fsf_req_sbal_get(adapter)) goto out; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC, - ZFCP_REQ_AUTO_CLEANUP, pool); + req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC, pool); + if (IS_ERR(req)) { ret = PTR_ERR(req); goto out; } + req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; ret = zfcp_fsf_setup_ct_els_sbals(req, ct->req, ct->resp, FSF_MAX_SBALS_PER_REQ); if (ret) @@ -1189,13 +1184,15 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els) spin_lock_bh(&adapter->req_q_lock); if (zfcp_fsf_req_sbal_get(adapter)) goto out; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS, - ZFCP_REQ_AUTO_CLEANUP, NULL); + + req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS, NULL); + if (IS_ERR(req)) { ret = PTR_ERR(req); goto out; } + req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; ret = zfcp_fsf_setup_ct_els_sbals(req, els->req, els->resp, 2); if (ret) @@ -1234,15 +1231,16 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) spin_lock_bh(&adapter->req_q_lock); if (zfcp_fsf_req_sbal_get(adapter)) goto out; - req = zfcp_fsf_req_create(adapter, - FSF_QTCB_EXCHANGE_CONFIG_DATA, - ZFCP_REQ_AUTO_CLEANUP, + + req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, adapter->pool.erp_req); + if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; } + req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; sbale = zfcp_qdio_sbale_req(req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1278,8 +1276,8 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, if (zfcp_fsf_req_sbal_get(adapter)) goto out_unlock; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, - 0, NULL); + req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, NULL); + if (IS_ERR(req)) { retval = PTR_ERR(req); goto out_unlock; @@ -1331,14 +1329,16 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) spin_lock_bh(&adapter->req_q_lock); if (zfcp_fsf_req_sbal_get(adapter)) goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, - ZFCP_REQ_AUTO_CLEANUP, adapter->pool.erp_req); + if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; } + req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; sbale = zfcp_qdio_sbale_req(req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1378,8 +1378,8 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, if (zfcp_fsf_req_sbal_get(adapter)) goto out_unlock; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, 0, - NULL); + req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, NULL); + if (IS_ERR(req)) { retval = PTR_ERR(req); goto out_unlock; @@ -1500,15 +1500,15 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) if (zfcp_fsf_req_sbal_get(adapter)) goto out; - req = zfcp_fsf_req_create(adapter, - FSF_QTCB_OPEN_PORT_WITH_DID, - ZFCP_REQ_AUTO_CLEANUP, + req = zfcp_fsf_req_create(adapter, FSF_QTCB_OPEN_PORT_WITH_DID, adapter->pool.erp_req); + if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; } + req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; sbale = zfcp_qdio_sbale_req(req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1571,13 +1571,14 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) goto out; req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT, - ZFCP_REQ_AUTO_CLEANUP, adapter->pool.erp_req); + if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; } + req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; sbale = zfcp_qdio_sbale_req(req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1646,15 +1647,15 @@ int zfcp_fsf_open_wka_port(struct zfcp_wka_port *wka_port) if (zfcp_fsf_req_sbal_get(adapter)) goto out; - req = zfcp_fsf_req_create(adapter, - FSF_QTCB_OPEN_PORT_WITH_DID, - ZFCP_REQ_AUTO_CLEANUP, + req = zfcp_fsf_req_create(adapter, FSF_QTCB_OPEN_PORT_WITH_DID, adapter->pool.erp_req); + if (unlikely(IS_ERR(req))) { retval = PTR_ERR(req); goto out; } + req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; sbale = zfcp_qdio_sbale_req(req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1702,13 +1703,14 @@ int zfcp_fsf_close_wka_port(struct zfcp_wka_port *wka_port) goto out; req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT, - ZFCP_REQ_AUTO_CLEANUP, adapter->pool.erp_req); + if (unlikely(IS_ERR(req))) { retval = PTR_ERR(req); goto out; } + req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; sbale = zfcp_qdio_sbale_req(req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1793,13 +1795,14 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) goto out; req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PHYSICAL_PORT, - ZFCP_REQ_AUTO_CLEANUP, adapter->pool.erp_req); + if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; } + req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; sbale = zfcp_qdio_sbale_req(req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1965,13 +1968,14 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) goto out; req = zfcp_fsf_req_create(adapter, FSF_QTCB_OPEN_LUN, - ZFCP_REQ_AUTO_CLEANUP, adapter->pool.erp_req); + if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; } + req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; sbale = zfcp_qdio_sbale_req(req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -2049,14 +2053,16 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) spin_lock_bh(&adapter->req_q_lock); if (zfcp_fsf_req_sbal_get(adapter)) goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_LUN, - ZFCP_REQ_AUTO_CLEANUP, adapter->pool.erp_req); + if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; } + req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; sbale = zfcp_qdio_sbale_req(req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -2353,14 +2359,16 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, atomic_inc(&adapter->qdio_outb_full); goto out; } + req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, - ZFCP_REQ_AUTO_CLEANUP, adapter->pool.scsi_req); + if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; } + req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; zfcp_unit_get(unit); req->unit = unit; req->data = scsi_cmnd; @@ -2465,8 +2473,10 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags) spin_lock_bh(&adapter->req_q_lock); if (zfcp_fsf_req_sbal_get(adapter)) goto out; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, 0, + + req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, adapter->pool.scsi_req); + if (IS_ERR(req)) { req = NULL; goto out; @@ -2537,7 +2547,7 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, if (zfcp_fsf_req_sbal_get(adapter)) goto out; - req = zfcp_fsf_req_create(adapter, fsf_cfdc->command, 0, NULL); + req = zfcp_fsf_req_create(adapter, fsf_cfdc->command, NULL); if (IS_ERR(req)) { retval = -EPERM; goto out; -- cgit v1.2.3-18-g5258 From 4544683a4b1d4e65ccca8c736bac56a195a5206b Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 18 Aug 2009 15:43:17 +0200 Subject: [SCSI] zfcp: Move workqueue to adapter struct Remove the global driver work queue and replace it with a workqueue local to the adapter. The usage of this workqueue makes this the correct place for the structure. In addition multiple adapters won't block each other due to the serialization of the queued work. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 29 +++++++++++++++++++++++++++-- drivers/s390/scsi/zfcp_def.h | 2 +- drivers/s390/scsi/zfcp_erp.c | 2 +- drivers/s390/scsi/zfcp_fc.c | 2 +- drivers/s390/scsi/zfcp_fsf.c | 2 +- drivers/s390/scsi/zfcp_scsi.c | 5 +++-- 6 files changed, 34 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index de623292277..f785cbc7520 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -176,8 +176,6 @@ static int __init zfcp_module_init(void) if (!zfcp_data.gid_pn_cache) goto out_gid_cache; - zfcp_data.work_queue = create_singlethread_workqueue("zfcp_wq"); - sema_init(&zfcp_data.config_sema, 1); rwlock_init(&zfcp_data.config_lock); @@ -458,6 +456,27 @@ static void zfcp_print_sl(struct seq_file *m, struct service_level *sl) adapter->fsf_lic_version); } +static int zfcp_setup_adapter_work_queue(struct zfcp_adapter *adapter) +{ + char name[TASK_COMM_LEN]; + + snprintf(name, sizeof(name), "zfcp_q_%s", + dev_name(&adapter->ccw_device->dev)); + adapter->work_queue = create_singlethread_workqueue(name); + + if (adapter->work_queue) + return 0; + return -ENOMEM; +} + +static void zfcp_destroy_adapter_work_queue(struct zfcp_adapter *adapter) +{ + if (adapter->work_queue) + destroy_workqueue(adapter->work_queue); + adapter->work_queue = NULL; + +} + /** * zfcp_adapter_enqueue - enqueue a new adapter to the list * @ccw_device: pointer to the struct cc_device @@ -504,6 +523,9 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) if (zfcp_adapter_debug_register(adapter)) goto debug_register_failed; + if (zfcp_setup_adapter_work_queue(adapter)) + goto work_queue_failed; + init_waitqueue_head(&adapter->remove_wq); init_waitqueue_head(&adapter->erp_thread_wqh); init_waitqueue_head(&adapter->erp_done_wqh); @@ -543,6 +565,8 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) return 0; sysfs_failed: + zfcp_destroy_adapter_work_queue(adapter); +work_queue_failed: zfcp_adapter_debug_unregister(adapter); debug_register_failed: dev_set_drvdata(&ccw_device->dev, NULL); @@ -579,6 +603,7 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) if (!retval) return; + zfcp_destroy_adapter_work_queue(adapter); zfcp_adapter_debug_unregister(adapter); zfcp_qdio_free(adapter); zfcp_free_low_mem_buffers(adapter); diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 1e27ed5d90e..2715a103e5a 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -485,6 +485,7 @@ struct zfcp_adapter { struct work_struct scan_work; struct service_level service_level; atomic_t qdio_outb_full; /* queue full incidents */ + struct workqueue_struct *work_queue; }; struct zfcp_port { @@ -573,7 +574,6 @@ struct zfcp_data { struct kmem_cache *qtcb_cache; struct kmem_cache *sr_buffer_cache; struct kmem_cache *gid_pn_cache; - struct workqueue_struct *work_queue; }; /********************** ZFCP SPECIFIC DEFINES ********************************/ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index a377e2f9125..50e5fbe2252 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -875,7 +875,7 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) return zfcp_erp_open_ptp_port(act); if (!port->d_id) { zfcp_port_get(port); - if (!queue_work(zfcp_data.work_queue, + if (!queue_work(adapter->work_queue, &port->gid_pn_work)) zfcp_port_put(port); return ZFCP_ERP_CONTINUES; diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index acadcd3c276..8921e16fdab 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -480,7 +480,7 @@ out: void zfcp_test_link(struct zfcp_port *port) { zfcp_port_get(port); - if (!queue_work(zfcp_data.work_queue, &port->test_link_work)) + if (!queue_work(port->adapter->work_queue, &port->test_link_work)) zfcp_port_put(port); } diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 70a978a14f2..5b73f989a62 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -305,7 +305,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) zfcp_fsf_req_free(req); atomic_inc(&adapter->stat_miss); - queue_work(zfcp_data.work_queue, &adapter->stat_work); + queue_work(adapter->work_queue, &adapter->stat_work); } static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req) diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 0de059161b3..2e13d41269a 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -572,7 +572,7 @@ void zfcp_scsi_schedule_rport_register(struct zfcp_port *port) zfcp_port_get(port); port->rport_task = RPORT_ADD; - if (!queue_work(zfcp_data.work_queue, &port->rport_work)) + if (!queue_work(port->adapter->work_queue, &port->rport_work)) zfcp_port_put(port); } @@ -581,7 +581,8 @@ void zfcp_scsi_schedule_rport_block(struct zfcp_port *port) zfcp_port_get(port); port->rport_task = RPORT_DEL; - if (port->rport && queue_work(zfcp_data.work_queue, &port->rport_work)) + if (port->rport && queue_work(port->adapter->work_queue, + &port->rport_work)) return; zfcp_port_put(port); -- cgit v1.2.3-18-g5258 From 42428f747a8a0db9c6de03e105932316defad65d Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 18 Aug 2009 15:43:18 +0200 Subject: [SCSI] zfcp: Separate qdio attributes from zfcp_fsf_req Split all qdio related attributes out of zfcp_fsf_req and put it in new structure. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 6 +-- drivers/s390/scsi/zfcp_def.h | 84 +++++++++++++++++++++++++------------- drivers/s390/scsi/zfcp_ext.h | 11 +++-- drivers/s390/scsi/zfcp_fsf.c | 79 ++++++++++++++++++----------------- drivers/s390/scsi/zfcp_qdio.c | 95 +++++++++++++++++++++++-------------------- 5 files changed, 160 insertions(+), 115 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 5568440ec2f..fc7f3d66fe3 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -152,9 +152,9 @@ void _zfcp_hba_dbf_event_fsf_response(const char *tag2, int level, memcpy(response->fsf_status_qual, fsf_status_qual, FSF_STATUS_QUALIFIER_SIZE); response->fsf_req_status = fsf_req->status; - response->sbal_first = fsf_req->sbal_first; - response->sbal_last = fsf_req->sbal_last; - response->sbal_response = fsf_req->sbal_response; + response->sbal_first = fsf_req->queue_req.sbal_first; + response->sbal_last = fsf_req->queue_req.sbal_last; + response->sbal_response = fsf_req->queue_req.sbal_response; response->pool = fsf_req->pool != NULL; response->erp_action = (unsigned long)fsf_req->erp_action; diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 2715a103e5a..a04bdfd4d2f 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -529,36 +529,64 @@ struct zfcp_unit { struct work_struct scsi_work; }; -/* FSF request */ +/** + * struct zfcp_queue_req - queue related values for a request + * @sbal_number: number of free SBALs + * @sbal_first: first SBAL for this request + * @sbal_last: last SBAL for this request + * @sbal_limit: last possible SBAL for this request + * @sbale_curr: current SBALE at creation of this request + * @sbal_response: SBAL used in interrupt + * @qdio_outb_usage: usage of outbound queue + * @qdio_inb_usage: usage of inbound queue + */ +struct zfcp_queue_req { + u8 sbal_number; + u8 sbal_first; + u8 sbal_last; + u8 sbal_limit; + u8 sbale_curr; + u8 sbal_response; + u16 qdio_outb_usage; + u16 qdio_inb_usage; +}; + +/** + * struct zfcp_fsf_req - basic FSF request structure + * @list: list of FSF requests + * @req_id: unique request ID + * @adapter: adapter this request belongs to + * @queue_req: queue related values + * @completion: used to signal the completion of the request + * @status: status of the request + * @fsf_command: FSF command issued + * @qtcb: associated QTCB + * @seq_no: sequence number of this request + * @data: private data + * @timer: timer data of this request + * @erp_action: reference to erp action if request issued on behalf of ERP + * @pool: reference to memory pool if used for this request + * @issued: time when request was send (STCK) + * @unit: reference to unit if this request is a SCSI request + * @handler: handler which should be called to process response + */ struct zfcp_fsf_req { - struct list_head list; /* list of FSF requests */ - unsigned long req_id; /* unique request ID */ - struct zfcp_adapter *adapter; /* adapter request belongs to */ - u8 sbal_number; /* nr of SBALs free for use */ - u8 sbal_first; /* first SBAL for this request */ - u8 sbal_last; /* last SBAL for this request */ - u8 sbal_limit; /* last possible SBAL for - this reuest */ - u8 sbale_curr; /* current SBALE during creation - of request */ - u8 sbal_response; /* SBAL used in interrupt */ - struct completion completion; /* can be used by a routine - to wait for completion */ - u32 status; /* status of this request */ - u32 fsf_command; /* FSF Command copy */ - struct fsf_qtcb *qtcb; /* address of associated QTCB */ - u32 seq_no; /* Sequence number of request */ - void *data; /* private data of request */ - struct timer_list timer; /* used for erp or scsi er */ - struct zfcp_erp_action *erp_action; /* used if this request is - issued on behalf of erp */ - mempool_t *pool; /* used if request was alloacted - from emergency pool */ - unsigned long long issued; /* request sent time (STCK) */ - struct zfcp_unit *unit; + struct list_head list; + unsigned long req_id; + struct zfcp_adapter *adapter; + struct zfcp_queue_req queue_req; + struct completion completion; + u32 status; + u32 fsf_command; + struct fsf_qtcb *qtcb; + u32 seq_no; + void *data; + struct timer_list timer; + struct zfcp_erp_action *erp_action; + mempool_t *pool; + unsigned long long issued; + struct zfcp_unit *unit; void (*handler)(struct zfcp_fsf_req *); - u16 qdio_outb_usage;/* usage of outbound queue */ - u16 qdio_inb_usage; /* usage of inbound queue */ }; /* driver data */ diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 6a3727bdb38..d11c0f44dad 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -142,10 +142,13 @@ extern void zfcp_fsf_reqid_check(struct zfcp_adapter *, int); /* zfcp_qdio.c */ extern int zfcp_qdio_allocate(struct zfcp_adapter *); extern void zfcp_qdio_free(struct zfcp_adapter *); -extern int zfcp_qdio_send(struct zfcp_fsf_req *); -extern struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_fsf_req *); -extern struct qdio_buffer_element *zfcp_qdio_sbale_curr(struct zfcp_fsf_req *); -extern int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *, unsigned long, +extern int zfcp_qdio_send(struct zfcp_adapter *, struct zfcp_queue_req *); +extern struct qdio_buffer_element + *zfcp_qdio_sbale_req(struct zfcp_adapter *, struct zfcp_queue_req *); +extern struct qdio_buffer_element + *zfcp_qdio_sbale_curr(struct zfcp_adapter *, struct zfcp_queue_req *); +extern int zfcp_qdio_sbals_from_sg(struct zfcp_adapter *, + struct zfcp_queue_req *, unsigned long, struct scatterlist *, int); extern int zfcp_qdio_open(struct zfcp_adapter *); extern void zfcp_qdio_close(struct zfcp_adapter *); diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 5b73f989a62..e88b7804780 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -720,12 +720,12 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter, req->adapter = adapter; req->fsf_command = fsf_cmd; req->req_id = adapter->req_no; - req->sbal_number = 1; - req->sbal_first = req_q->first; - req->sbal_last = req_q->first; - req->sbale_curr = 1; + req->queue_req.sbal_number = 1; + req->queue_req.sbal_first = req_q->first; + req->queue_req.sbal_last = req_q->first; + req->queue_req.sbale_curr = 1; - sbale = zfcp_qdio_sbale_req(req); + sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); sbale[0].addr = (void *) req->req_id; sbale[0].flags |= SBAL_FLAGS0_COMMAND; @@ -774,9 +774,9 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *req) list_add_tail(&req->list, &adapter->req_list[idx]); spin_unlock_irqrestore(&adapter->req_list_lock, flags); - req->qdio_outb_usage = atomic_read(&adapter->req_q.count); + req->queue_req.qdio_outb_usage = atomic_read(&adapter->req_q.count); req->issued = get_clock(); - if (zfcp_qdio_send(req)) { + if (zfcp_qdio_send(adapter, &req->queue_req)) { del_timer(&req->timer); spin_lock_irqsave(&adapter->req_list_lock, flags); /* lookup request again, list might have changed */ @@ -819,9 +819,9 @@ int zfcp_fsf_status_read(struct zfcp_adapter *adapter) goto out; } - sbale = zfcp_qdio_sbale_req(req); + sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY; - req->sbale_curr = 2; + req->queue_req.sbale_curr = 2; sr_buf = mempool_alloc(adapter->pool.status_read_data, GFP_ATOMIC); if (!sr_buf) { @@ -830,7 +830,7 @@ int zfcp_fsf_status_read(struct zfcp_adapter *adapter) } memset(sr_buf, 0, sizeof(*sr_buf)); req->data = sr_buf; - sbale = zfcp_qdio_sbale_curr(req); + sbale = zfcp_qdio_sbale_curr(adapter, &req->queue_req); sbale->addr = (void *) sr_buf; sbale->length = sizeof(*sr_buf); @@ -929,7 +929,7 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id, ZFCP_STATUS_COMMON_UNBLOCKED))) goto out_error_free; - sbale = zfcp_qdio_sbale_req(req); + sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1023,8 +1023,10 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, struct scatterlist *sg_resp, int max_sbals) { - struct qdio_buffer_element *sbale = zfcp_qdio_sbale_req(req); - u32 feat = req->adapter->adapter_features; + struct zfcp_adapter *adapter = req->adapter; + struct qdio_buffer_element *sbale = zfcp_qdio_sbale_req(adapter, + &req->queue_req); + u32 feat = adapter->adapter_features; int bytes; if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) { @@ -1041,14 +1043,16 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, return 0; } - bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ, + bytes = zfcp_qdio_sbals_from_sg(adapter, &req->queue_req, + SBAL_FLAGS0_TYPE_WRITE_READ, sg_req, max_sbals); if (bytes <= 0) return -EIO; req->qtcb->bottom.support.req_buf_length = bytes; - req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL; + req->queue_req.sbale_curr = ZFCP_LAST_SBALE_PER_SBAL; - bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ, + bytes = zfcp_qdio_sbals_from_sg(adapter, &req->queue_req, + SBAL_FLAGS0_TYPE_WRITE_READ, sg_resp, max_sbals); if (bytes <= 0) return -EIO; @@ -1241,7 +1245,7 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(req); + sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1283,7 +1287,7 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, goto out_unlock; } - sbale = zfcp_qdio_sbale_req(req); + sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; req->handler = zfcp_fsf_exchange_config_data_handler; @@ -1339,7 +1343,7 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(req); + sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1388,7 +1392,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, if (data) req->data = data; - sbale = zfcp_qdio_sbale_req(req); + sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1509,7 +1513,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(req); + sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1579,7 +1583,7 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(req); + sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1656,7 +1660,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_wka_port *wka_port) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(req); + sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1711,7 +1715,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_wka_port *wka_port) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(req); + sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1803,7 +1807,7 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(req); + sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1976,7 +1980,7 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(req); + sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -2063,7 +2067,7 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(req); + sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -2140,8 +2144,8 @@ static void zfcp_fsf_trace_latency(struct zfcp_fsf_req *fsf_req) } if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) trace.flags |= ZFCP_BLK_REQ_ERROR; - trace.inb_usage = fsf_req->qdio_inb_usage; - trace.outb_usage = fsf_req->qdio_outb_usage; + trace.inb_usage = fsf_req->queue_req.qdio_inb_usage; + trace.outb_usage = fsf_req->queue_req.qdio_outb_usage; blk_add_driver_data(req->q, req, &trace, sizeof(trace)); } @@ -2420,11 +2424,11 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) + fcp_cmnd_iu->add_fcp_cdb_length + sizeof(u32); - real_bytes = zfcp_qdio_sbals_from_sg(req, sbtype, + real_bytes = zfcp_qdio_sbals_from_sg(adapter, &req->queue_req, sbtype, scsi_sglist(scsi_cmnd), FSF_MAX_SBALS_PER_REQ); if (unlikely(real_bytes < 0)) { - if (req->sbal_number >= FSF_MAX_SBALS_PER_REQ) { + if (req->queue_req.sbal_number >= FSF_MAX_SBALS_PER_REQ) { dev_err(&adapter->ccw_device->dev, "Oversize data package, unit 0x%016Lx " "on port 0x%016Lx closed\n", @@ -2492,7 +2496,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags) req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) + sizeof(u32); - sbale = zfcp_qdio_sbale_req(req); + sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -2555,15 +2559,15 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, req->handler = zfcp_fsf_control_file_handler; - sbale = zfcp_qdio_sbale_req(req); + sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); sbale[0].flags |= direction; bottom = &req->qtcb->bottom.support; bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE; bottom->option = fsf_cfdc->option; - bytes = zfcp_qdio_sbals_from_sg(req, direction, fsf_cfdc->sg, - FSF_MAX_SBALS_PER_REQ); + bytes = zfcp_qdio_sbals_from_sg(adapter, &req->queue_req, direction, + fsf_cfdc->sg, FSF_MAX_SBALS_PER_REQ); if (bytes != ZFCP_CFDC_MAX_SIZE) { zfcp_fsf_req_free(req); goto out; @@ -2612,8 +2616,9 @@ void zfcp_fsf_reqid_check(struct zfcp_adapter *adapter, int sbal_idx) list_del(&fsf_req->list); spin_unlock_irqrestore(&adapter->req_list_lock, flags); - fsf_req->sbal_response = sbal_idx; - fsf_req->qdio_inb_usage = atomic_read(&adapter->resp_q.count); + fsf_req->queue_req.sbal_response = sbal_idx; + fsf_req->queue_req.qdio_inb_usage = + atomic_read(&adapter->resp_q.count); zfcp_fsf_req_complete(fsf_req); if (likely(sbale->flags & SBAL_FLAGS_LAST_ENTRY)) diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 2e9b3a9cebd..e118874976f 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -3,7 +3,7 @@ * * Setup and helper functions to access QDIO. * - * Copyright IBM Corporation 2002, 2008 + * Copyright IBM Corporation 2002, 2009 */ #define KMSG_COMPONENT "zfcp" @@ -165,12 +165,14 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, /** * zfcp_qdio_sbale_req - return ptr to SBALE of req_q for a struct zfcp_fsf_req - * @fsf_req: pointer to struct fsf_req + * @adapter: pointer to struct zfcp_adapter + * @q_rec: pointer to struct zfcp_queue_rec * Returns: pointer to qdio_buffer_element (SBALE) structure */ -struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_fsf_req *req) +struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_adapter *adapter, + struct zfcp_queue_req *q_req) { - return zfcp_qdio_sbale(&req->adapter->req_q, req->sbal_last, 0); + return zfcp_qdio_sbale(&adapter->req_q, q_req->sbal_last, 0); } /** @@ -178,74 +180,80 @@ struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_fsf_req *req) * @fsf_req: pointer to struct fsf_req * Returns: pointer to qdio_buffer_element (SBALE) structure */ -struct qdio_buffer_element *zfcp_qdio_sbale_curr(struct zfcp_fsf_req *req) +struct qdio_buffer_element *zfcp_qdio_sbale_curr(struct zfcp_adapter *adapter, + struct zfcp_queue_req *q_req) { - return zfcp_qdio_sbale(&req->adapter->req_q, req->sbal_last, - req->sbale_curr); + return zfcp_qdio_sbale(&adapter->req_q, q_req->sbal_last, + q_req->sbale_curr); } -static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals) +static void zfcp_qdio_sbal_limit(struct zfcp_adapter *adapter, + struct zfcp_queue_req *q_req, int max_sbals) { - int count = atomic_read(&fsf_req->adapter->req_q.count); + int count = atomic_read(&adapter->req_q.count); count = min(count, max_sbals); - fsf_req->sbal_limit = (fsf_req->sbal_first + count - 1) + q_req->sbal_limit = (q_req->sbal_first + count - 1) % QDIO_MAX_BUFFERS_PER_Q; } static struct qdio_buffer_element * -zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) +zfcp_qdio_sbal_chain(struct zfcp_adapter *adapter, struct zfcp_queue_req *q_req, + unsigned long sbtype) { struct qdio_buffer_element *sbale; /* set last entry flag in current SBALE of current SBAL */ - sbale = zfcp_qdio_sbale_curr(fsf_req); + sbale = zfcp_qdio_sbale_curr(adapter, q_req); sbale->flags |= SBAL_FLAGS_LAST_ENTRY; /* don't exceed last allowed SBAL */ - if (fsf_req->sbal_last == fsf_req->sbal_limit) + if (q_req->sbal_last == q_req->sbal_limit) return NULL; /* set chaining flag in first SBALE of current SBAL */ - sbale = zfcp_qdio_sbale_req(fsf_req); + sbale = zfcp_qdio_sbale_req(adapter, q_req); sbale->flags |= SBAL_FLAGS0_MORE_SBALS; /* calculate index of next SBAL */ - fsf_req->sbal_last++; - fsf_req->sbal_last %= QDIO_MAX_BUFFERS_PER_Q; + q_req->sbal_last++; + q_req->sbal_last %= QDIO_MAX_BUFFERS_PER_Q; /* keep this requests number of SBALs up-to-date */ - fsf_req->sbal_number++; + q_req->sbal_number++; /* start at first SBALE of new SBAL */ - fsf_req->sbale_curr = 0; + q_req->sbale_curr = 0; /* set storage-block type for new SBAL */ - sbale = zfcp_qdio_sbale_curr(fsf_req); + sbale = zfcp_qdio_sbale_curr(adapter, q_req); sbale->flags |= sbtype; return sbale; } static struct qdio_buffer_element * -zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) +zfcp_qdio_sbale_next(struct zfcp_adapter *adapter, struct zfcp_queue_req *q_req, + unsigned int sbtype) { - if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL) - return zfcp_qdio_sbal_chain(fsf_req, sbtype); - fsf_req->sbale_curr++; - return zfcp_qdio_sbale_curr(fsf_req); + if (q_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL) + return zfcp_qdio_sbal_chain(adapter, q_req, sbtype); + q_req->sbale_curr++; + return zfcp_qdio_sbale_curr(adapter, q_req); } -static void zfcp_qdio_undo_sbals(struct zfcp_fsf_req *fsf_req) +static void zfcp_qdio_undo_sbals(struct zfcp_adapter *adapter, + struct zfcp_queue_req *q_req) { - struct qdio_buffer **sbal = fsf_req->adapter->req_q.sbal; - int first = fsf_req->sbal_first; - int last = fsf_req->sbal_last; + struct qdio_buffer **sbal = adapter->req_q.sbal; + int first = q_req->sbal_first; + int last = q_req->sbal_last; int count = (last - first + QDIO_MAX_BUFFERS_PER_Q) % QDIO_MAX_BUFFERS_PER_Q + 1; zfcp_qdio_zero_sbals(sbal, first, count); } -static int zfcp_qdio_fill_sbals(struct zfcp_fsf_req *fsf_req, +static int zfcp_qdio_fill_sbals(struct zfcp_adapter *adapter, + struct zfcp_queue_req *q_req, unsigned int sbtype, void *start_addr, unsigned int total_length) { @@ -256,10 +264,10 @@ static int zfcp_qdio_fill_sbals(struct zfcp_fsf_req *fsf_req, /* split segment up */ for (addr = start_addr, remaining = total_length; remaining > 0; addr += length, remaining -= length) { - sbale = zfcp_qdio_sbale_next(fsf_req, sbtype); + sbale = zfcp_qdio_sbale_next(adapter, q_req, sbtype); if (!sbale) { - atomic_inc(&fsf_req->adapter->qdio_outb_full); - zfcp_qdio_undo_sbals(fsf_req); + atomic_inc(&adapter->qdio_outb_full); + zfcp_qdio_undo_sbals(adapter, q_req); return -EINVAL; } @@ -281,29 +289,31 @@ static int zfcp_qdio_fill_sbals(struct zfcp_fsf_req *fsf_req, * @max_sbals: upper bound for number of SBALs to be used * Returns: number of bytes, or error (negativ) */ -int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, - struct scatterlist *sg, int max_sbals) +int zfcp_qdio_sbals_from_sg(struct zfcp_adapter *adapter, + struct zfcp_queue_req *q_req, + unsigned long sbtype, struct scatterlist *sg, + int max_sbals) { struct qdio_buffer_element *sbale; int retval, bytes = 0; /* figure out last allowed SBAL */ - zfcp_qdio_sbal_limit(fsf_req, max_sbals); + zfcp_qdio_sbal_limit(adapter, q_req, max_sbals); /* set storage-block type for this request */ - sbale = zfcp_qdio_sbale_req(fsf_req); + sbale = zfcp_qdio_sbale_req(adapter, q_req); sbale->flags |= sbtype; for (; sg; sg = sg_next(sg)) { - retval = zfcp_qdio_fill_sbals(fsf_req, sbtype, sg_virt(sg), - sg->length); + retval = zfcp_qdio_fill_sbals(adapter, q_req, sbtype, + sg_virt(sg), sg->length); if (retval < 0) return retval; bytes += sg->length; } /* assume that no other SBALEs are to follow in the same SBAL */ - sbale = zfcp_qdio_sbale_curr(fsf_req); + sbale = zfcp_qdio_sbale_curr(adapter, q_req); sbale->flags |= SBAL_FLAGS_LAST_ENTRY; return bytes; @@ -314,12 +324,11 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, * @fsf_req: pointer to struct zfcp_fsf_req * Returns: 0 on success, error otherwise */ -int zfcp_qdio_send(struct zfcp_fsf_req *fsf_req) +int zfcp_qdio_send(struct zfcp_adapter *adapter, struct zfcp_queue_req *q_req) { - struct zfcp_adapter *adapter = fsf_req->adapter; struct zfcp_qdio_queue *req_q = &adapter->req_q; - int first = fsf_req->sbal_first; - int count = fsf_req->sbal_number; + int first = q_req->sbal_first; + int count = q_req->sbal_number; int retval; unsigned int qdio_flags = QDIO_FLAG_SYNC_OUTPUT; -- cgit v1.2.3-18-g5258 From 564e1c86c810f9ccfe4300afa402815e3db4886d Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 18 Aug 2009 15:43:19 +0200 Subject: [SCSI] zfcp: Move qdio related data out of zfcp_adapter The zfcp_adapter structure was growing over time to a size of almost one memory page. To reduce the size of the data structure and to seperate different layers, put all qdio related data in the new zfcp_qdio data structure. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 20 ++- drivers/s390/scsi/zfcp_dbf.c | 6 +- drivers/s390/scsi/zfcp_def.h | 34 +++-- drivers/s390/scsi/zfcp_erp.c | 8 +- drivers/s390/scsi/zfcp_ext.h | 26 ++-- drivers/s390/scsi/zfcp_fsf.c | 299 +++++++++++++++++++++-------------------- drivers/s390/scsi/zfcp_qdio.c | 224 +++++++++++++++--------------- drivers/s390/scsi/zfcp_scsi.c | 6 +- drivers/s390/scsi/zfcp_sysfs.c | 16 +-- 9 files changed, 343 insertions(+), 296 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index f785cbc7520..ed7211ef04e 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -428,7 +428,7 @@ static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) int zfcp_status_read_refill(struct zfcp_adapter *adapter) { while (atomic_read(&adapter->stat_miss) > 0) - if (zfcp_fsf_status_read(adapter)) { + if (zfcp_fsf_status_read(adapter->qdio)) { if (atomic_read(&adapter->stat_miss) >= 16) { zfcp_erp_adapter_reopen(adapter, 0, "axsref1", NULL); @@ -507,11 +507,16 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) return -ENOMEM; } + adapter->qdio = kzalloc(sizeof(struct zfcp_qdio), GFP_KERNEL); + if (!adapter->qdio) + goto qdio_mem_failed; + + adapter->qdio->adapter = adapter; ccw_device->handler = NULL; adapter->ccw_device = ccw_device; atomic_set(&adapter->refcount, 0); - if (zfcp_qdio_allocate(adapter)) + if (zfcp_qdio_allocate(adapter->qdio, ccw_device)) goto qdio_allocate_failed; if (zfcp_allocate_low_mem_buffers(adapter)) @@ -536,8 +541,8 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) spin_lock_init(&adapter->req_list_lock); - spin_lock_init(&adapter->req_q_lock); - spin_lock_init(&adapter->qdio_stat_lock); + spin_lock_init(&adapter->qdio->req_q_lock); + spin_lock_init(&adapter->qdio->stat_lock); rwlock_init(&adapter->erp_lock); rwlock_init(&adapter->abort_lock); @@ -574,7 +579,9 @@ debug_register_failed: failed_low_mem_buffers: zfcp_free_low_mem_buffers(adapter); qdio_allocate_failed: - zfcp_qdio_free(adapter); + zfcp_qdio_free(adapter->qdio); + kfree(adapter->qdio); +qdio_mem_failed: kfree(adapter); return -ENOMEM; } @@ -605,12 +612,13 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) zfcp_destroy_adapter_work_queue(adapter); zfcp_adapter_debug_unregister(adapter); - zfcp_qdio_free(adapter); + zfcp_qdio_free(adapter->qdio); zfcp_free_low_mem_buffers(adapter); kfree(adapter->req_list); kfree(adapter->fc_stats); kfree(adapter->stats_reset_data); kfree(adapter->gs); + kfree(adapter->qdio); kfree(adapter); } diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index fc7f3d66fe3..3179b08bda6 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -274,16 +274,16 @@ void _zfcp_hba_dbf_event_fsf_unsol(const char *tag, int level, /** * zfcp_hba_dbf_event_qdio - trace event for QDIO related failure - * @adapter: adapter affected by this QDIO related event + * @qdio: qdio structure affected by this QDIO related event * @qdio_error: as passed by qdio module * @sbal_index: first buffer with error condition, as passed by qdio module * @sbal_count: number of buffers affected, as passed by qdio module */ -void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter, +void zfcp_hba_dbf_event_qdio(struct zfcp_qdio *qdio, unsigned int qdio_error, int sbal_index, int sbal_count) { - struct zfcp_dbf *dbf = adapter->dbf; + struct zfcp_dbf *dbf = qdio->adapter->dbf; struct zfcp_hba_dbf_record *r = &dbf->hba_dbf_buf; unsigned long flags; diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index a04bdfd4d2f..bac5c497eab 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -428,6 +428,29 @@ struct zfcp_latencies { spinlock_t lock; }; +/** struct zfcp_qdio - basic QDIO data structure + * @resp_q: response queue + * @req_q: request queue + * @stat_lock: lock to protect req_q_util and req_q_time + * @req_q_lock; lock to serialize access to request queue + * @req_q_time: time of last fill level change + * @req_q_util: used for accounting + * @req_q_full: queue full incidents + * @req_q_wq: used to wait for SBAL availability + * @adapter: adapter used in conjunction with this QDIO structure + */ +struct zfcp_qdio { + struct zfcp_qdio_queue resp_q; + struct zfcp_qdio_queue req_q; + spinlock_t stat_lock; + spinlock_t req_q_lock; + ktime_t req_q_time; + u64 req_q_util; + atomic_t req_q_full; + wait_queue_head_t req_q_wq; + struct zfcp_adapter *adapter; +}; + struct zfcp_adapter { atomic_t refcount; /* reference count */ wait_queue_head_t remove_wq; /* can be used to wait for @@ -436,6 +459,7 @@ struct zfcp_adapter { u64 peer_wwpn; /* P2P peer WWPN */ u32 peer_d_id; /* P2P peer D_ID */ struct ccw_device *ccw_device; /* S/390 ccw device */ + struct zfcp_qdio *qdio; u32 hydra_version; /* Hydra version */ u32 fsf_lic_version; u32 adapter_features; /* FCP channel features */ @@ -447,15 +471,7 @@ struct zfcp_adapter { unsigned long req_no; /* unique FSF req number */ struct list_head *req_list; /* list of pending reqs */ spinlock_t req_list_lock; /* request list lock */ - struct zfcp_qdio_queue req_q; /* request queue */ - spinlock_t req_q_lock; /* for operations on queue */ - ktime_t req_q_time; /* time of last fill level change */ - u64 req_q_util; /* for accounting */ - spinlock_t qdio_stat_lock; u32 fsf_req_seq_no; /* FSF cmnd seq number */ - wait_queue_head_t request_wq; /* can be used to wait for - more avaliable SBALs */ - struct zfcp_qdio_queue resp_q; /* response queue */ rwlock_t abort_lock; /* Protects against SCSI stack abort/command completion races */ @@ -478,13 +494,11 @@ struct zfcp_adapter { struct zfcp_wka_ports *gs; /* generic services */ struct zfcp_dbf *dbf; /* debug traces */ struct zfcp_adapter_mempool pool; /* Adapter memory pools */ - struct qdio_initialize qdio_init_data; /* for qdio_establish */ struct fc_host_statistics *fc_stats; struct fsf_qtcb_bottom_port *stats_reset_data; unsigned long stats_reset; struct work_struct scan_work; struct service_level service_level; - atomic_t qdio_outb_full; /* queue full incidents */ struct workqueue_struct *work_queue; }; diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 50e5fbe2252..feda1db56b2 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -603,9 +603,11 @@ static void zfcp_erp_wakeup(struct zfcp_adapter *adapter) static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act) { - if (zfcp_qdio_open(act->adapter)) + struct zfcp_qdio *qdio = act->adapter->qdio; + + if (zfcp_qdio_open(qdio)) return ZFCP_ERP_FAILED; - init_waitqueue_head(&act->adapter->request_wq); + init_waitqueue_head(&qdio->req_q_wq); atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status); return ZFCP_ERP_SUCCEEDED; } @@ -710,7 +712,7 @@ static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act) struct zfcp_adapter *adapter = act->adapter; /* close queues to ensure that buffers are not accessed by adapter */ - zfcp_qdio_close(adapter); + zfcp_qdio_close(adapter->qdio); zfcp_fsf_req_dismiss_all(adapter); adapter->fsf_req_seq_no = 0; zfcp_fc_wka_ports_force_offline(adapter->gs); diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index d11c0f44dad..e97947d2f2e 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -51,7 +51,7 @@ extern void _zfcp_hba_dbf_event_fsf_response(const char *, int level, extern void _zfcp_hba_dbf_event_fsf_unsol(const char *, int level, struct zfcp_adapter *, struct fsf_status_read_buffer *); -extern void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *, unsigned int, int, +extern void zfcp_hba_dbf_event_qdio(struct zfcp_qdio *, unsigned int, int, int); extern void zfcp_hba_dbf_event_berr(struct zfcp_adapter *, struct zfcp_fsf_req *); @@ -118,15 +118,15 @@ extern int zfcp_fsf_close_physical_port(struct zfcp_erp_action *); extern int zfcp_fsf_open_unit(struct zfcp_erp_action *); extern int zfcp_fsf_close_unit(struct zfcp_erp_action *); extern int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *); -extern int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *, +extern int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *, struct fsf_qtcb_bottom_config *); extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *); -extern int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *, +extern int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *, struct fsf_qtcb_bottom_port *); extern struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *, struct zfcp_fsf_cfdc *); extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); -extern int zfcp_fsf_status_read(struct zfcp_adapter *); +extern int zfcp_fsf_status_read(struct zfcp_qdio *); extern int zfcp_status_read_refill(struct zfcp_adapter *adapter); extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *, struct zfcp_erp_action *); @@ -137,21 +137,21 @@ extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *, u8); extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long, struct zfcp_unit *); -extern void zfcp_fsf_reqid_check(struct zfcp_adapter *, int); +extern void zfcp_fsf_reqid_check(struct zfcp_qdio *, int); /* zfcp_qdio.c */ -extern int zfcp_qdio_allocate(struct zfcp_adapter *); -extern void zfcp_qdio_free(struct zfcp_adapter *); -extern int zfcp_qdio_send(struct zfcp_adapter *, struct zfcp_queue_req *); +extern int zfcp_qdio_allocate(struct zfcp_qdio *, struct ccw_device *); +extern void zfcp_qdio_free(struct zfcp_qdio *); +extern int zfcp_qdio_send(struct zfcp_qdio *, struct zfcp_queue_req *); extern struct qdio_buffer_element - *zfcp_qdio_sbale_req(struct zfcp_adapter *, struct zfcp_queue_req *); + *zfcp_qdio_sbale_req(struct zfcp_qdio *, struct zfcp_queue_req *); extern struct qdio_buffer_element - *zfcp_qdio_sbale_curr(struct zfcp_adapter *, struct zfcp_queue_req *); -extern int zfcp_qdio_sbals_from_sg(struct zfcp_adapter *, + *zfcp_qdio_sbale_curr(struct zfcp_qdio *, struct zfcp_queue_req *); +extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *, struct zfcp_queue_req *, unsigned long, struct scatterlist *, int); -extern int zfcp_qdio_open(struct zfcp_adapter *); -extern void zfcp_qdio_close(struct zfcp_adapter *); +extern int zfcp_qdio_open(struct zfcp_qdio *); +extern void zfcp_qdio_close(struct zfcp_qdio *); /* zfcp_scsi.c */ extern struct zfcp_data zfcp_data; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index e88b7804780..b9a16e4b48b 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -637,33 +637,34 @@ static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req) } } -static int zfcp_fsf_sbal_check(struct zfcp_adapter *adapter) +static int zfcp_fsf_sbal_check(struct zfcp_qdio *qdio) { - struct zfcp_qdio_queue *req_q = &adapter->req_q; + struct zfcp_qdio_queue *req_q = &qdio->req_q; - spin_lock_bh(&adapter->req_q_lock); + spin_lock_bh(&qdio->req_q_lock); if (atomic_read(&req_q->count)) return 1; - spin_unlock_bh(&adapter->req_q_lock); + spin_unlock_bh(&qdio->req_q_lock); return 0; } -static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter) +static int zfcp_fsf_req_sbal_get(struct zfcp_qdio *qdio) { + struct zfcp_adapter *adapter = qdio->adapter; long ret; - spin_unlock_bh(&adapter->req_q_lock); - ret = wait_event_interruptible_timeout(adapter->request_wq, - zfcp_fsf_sbal_check(adapter), 5 * HZ); + spin_unlock_bh(&qdio->req_q_lock); + ret = wait_event_interruptible_timeout(qdio->req_q_wq, + zfcp_fsf_sbal_check(qdio), 5 * HZ); if (ret > 0) return 0; if (!ret) { - atomic_inc(&adapter->qdio_outb_full); + atomic_inc(&qdio->req_q_full); /* assume hanging outbound queue, try queue recovery */ zfcp_erp_adapter_reopen(adapter, 0, "fsrsg_1", NULL); } - spin_lock_bh(&adapter->req_q_lock); + spin_lock_bh(&qdio->req_q_lock); return -EIO; } @@ -700,11 +701,12 @@ static struct fsf_qtcb *zfcp_qtcb_alloc(mempool_t *pool) return qtcb; } -static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter, +static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio, u32 fsf_cmd, mempool_t *pool) { struct qdio_buffer_element *sbale; - struct zfcp_qdio_queue *req_q = &adapter->req_q; + struct zfcp_qdio_queue *req_q = &qdio->req_q; + struct zfcp_adapter *adapter = qdio->adapter; struct zfcp_fsf_req *req = zfcp_fsf_alloc(pool); if (unlikely(!req)) @@ -725,7 +727,7 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter, req->queue_req.sbal_last = req_q->first; req->queue_req.sbale_curr = 1; - sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); + sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); sbale[0].addr = (void *) req->req_id; sbale[0].flags |= SBAL_FLAGS0_COMMAND; @@ -740,7 +742,7 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter, return ERR_PTR(-ENOMEM); } - req->qtcb->prefix.req_seq_no = req->adapter->fsf_req_seq_no; + req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no; req->qtcb->prefix.req_id = req->req_id; req->qtcb->prefix.ulp_info = 26; req->qtcb->prefix.qtcb_type = fsf_qtcb_type[req->fsf_command]; @@ -764,6 +766,7 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter, static int zfcp_fsf_req_send(struct zfcp_fsf_req *req) { struct zfcp_adapter *adapter = req->adapter; + struct zfcp_qdio *qdio = adapter->qdio; unsigned long flags; int idx; int with_qtcb = (req->qtcb != NULL); @@ -774,9 +777,9 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *req) list_add_tail(&req->list, &adapter->req_list[idx]); spin_unlock_irqrestore(&adapter->req_list_lock, flags); - req->queue_req.qdio_outb_usage = atomic_read(&adapter->req_q.count); + req->queue_req.qdio_outb_usage = atomic_read(&qdio->req_q.count); req->issued = get_clock(); - if (zfcp_qdio_send(adapter, &req->queue_req)) { + if (zfcp_qdio_send(qdio, &req->queue_req)) { del_timer(&req->timer); spin_lock_irqsave(&adapter->req_list_lock, flags); /* lookup request again, list might have changed */ @@ -801,25 +804,26 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *req) * @req_flags: request flags * Returns: 0 on success, ERROR otherwise */ -int zfcp_fsf_status_read(struct zfcp_adapter *adapter) +int zfcp_fsf_status_read(struct zfcp_qdio *qdio) { + struct zfcp_adapter *adapter = qdio->adapter; struct zfcp_fsf_req *req; struct fsf_status_read_buffer *sr_buf; struct qdio_buffer_element *sbale; int retval = -EIO; - spin_lock_bh(&adapter->req_q_lock); - if (zfcp_fsf_req_sbal_get(adapter)) + spin_lock_bh(&qdio->req_q_lock); + if (zfcp_fsf_req_sbal_get(qdio)) goto out; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS, + req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS, adapter->pool.status_read_req); if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; } - sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); + sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY; req->queue_req.sbale_curr = 2; @@ -830,7 +834,7 @@ int zfcp_fsf_status_read(struct zfcp_adapter *adapter) } memset(sr_buf, 0, sizeof(*sr_buf)); req->data = sr_buf; - sbale = zfcp_qdio_sbale_curr(adapter, &req->queue_req); + sbale = zfcp_qdio_sbale_curr(qdio, &req->queue_req); sbale->addr = (void *) sr_buf; sbale->length = sizeof(*sr_buf); @@ -846,7 +850,7 @@ failed_buf: zfcp_fsf_req_free(req); zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL); out: - spin_unlock_bh(&adapter->req_q_lock); + spin_unlock_bh(&qdio->req_q_lock); return retval; } @@ -913,13 +917,13 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id, { struct qdio_buffer_element *sbale; struct zfcp_fsf_req *req = NULL; - struct zfcp_adapter *adapter = unit->port->adapter; + struct zfcp_qdio *qdio = unit->port->adapter->qdio; - spin_lock_bh(&adapter->req_q_lock); - if (zfcp_fsf_req_sbal_get(adapter)) + spin_lock_bh(&qdio->req_q_lock); + if (zfcp_fsf_req_sbal_get(qdio)) goto out; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND, - adapter->pool.scsi_abort); + req = zfcp_fsf_req_create(qdio, FSF_QTCB_ABORT_FCP_CMND, + qdio->adapter->pool.scsi_abort); if (IS_ERR(req)) { req = NULL; goto out; @@ -929,7 +933,7 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id, ZFCP_STATUS_COMMON_UNBLOCKED))) goto out_error_free; - sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); + sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -947,7 +951,7 @@ out_error_free: zfcp_fsf_req_free(req); req = NULL; out: - spin_unlock_bh(&adapter->req_q_lock); + spin_unlock_bh(&qdio->req_q_lock); return req; } @@ -1024,7 +1028,7 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, int max_sbals) { struct zfcp_adapter *adapter = req->adapter; - struct qdio_buffer_element *sbale = zfcp_qdio_sbale_req(adapter, + struct qdio_buffer_element *sbale = zfcp_qdio_sbale_req(adapter->qdio, &req->queue_req); u32 feat = adapter->adapter_features; int bytes; @@ -1043,7 +1047,7 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, return 0; } - bytes = zfcp_qdio_sbals_from_sg(adapter, &req->queue_req, + bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->queue_req, SBAL_FLAGS0_TYPE_WRITE_READ, sg_req, max_sbals); if (bytes <= 0) @@ -1051,7 +1055,7 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, req->qtcb->bottom.support.req_buf_length = bytes; req->queue_req.sbale_curr = ZFCP_LAST_SBALE_PER_SBAL; - bytes = zfcp_qdio_sbals_from_sg(adapter, &req->queue_req, + bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->queue_req, SBAL_FLAGS0_TYPE_WRITE_READ, sg_resp, max_sbals); if (bytes <= 0) @@ -1071,15 +1075,15 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, struct zfcp_erp_action *erp_action) { struct zfcp_wka_port *wka_port = ct->wka_port; - struct zfcp_adapter *adapter = wka_port->adapter; + struct zfcp_qdio *qdio = wka_port->adapter->qdio; struct zfcp_fsf_req *req; int ret = -EIO; - spin_lock_bh(&adapter->req_q_lock); - if (zfcp_fsf_req_sbal_get(adapter)) + spin_lock_bh(&qdio->req_q_lock); + if (zfcp_fsf_req_sbal_get(qdio)) goto out; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC, pool); + req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_GENERIC, pool); if (IS_ERR(req)) { ret = PTR_ERR(req); @@ -1118,7 +1122,7 @@ failed_send: if (erp_action) erp_action->fsf_req = NULL; out: - spin_unlock_bh(&adapter->req_q_lock); + spin_unlock_bh(&qdio->req_q_lock); return ret; } @@ -1181,15 +1185,15 @@ skip_fsfstatus: int zfcp_fsf_send_els(struct zfcp_send_els *els) { struct zfcp_fsf_req *req; - struct zfcp_adapter *adapter = els->adapter; + struct zfcp_qdio *qdio = els->adapter->qdio; struct fsf_qtcb_bottom_support *bottom; int ret = -EIO; - spin_lock_bh(&adapter->req_q_lock); - if (zfcp_fsf_req_sbal_get(adapter)) + spin_lock_bh(&qdio->req_q_lock); + if (zfcp_fsf_req_sbal_get(qdio)) goto out; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS, NULL); + req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_ELS, NULL); if (IS_ERR(req)) { ret = PTR_ERR(req); @@ -1221,7 +1225,7 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els) failed_send: zfcp_fsf_req_free(req); out: - spin_unlock_bh(&adapter->req_q_lock); + spin_unlock_bh(&qdio->req_q_lock); return ret; } @@ -1229,15 +1233,15 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) { struct qdio_buffer_element *sbale; struct zfcp_fsf_req *req; - struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_qdio *qdio = erp_action->adapter->qdio; int retval = -EIO; - spin_lock_bh(&adapter->req_q_lock); - if (zfcp_fsf_req_sbal_get(adapter)) + spin_lock_bh(&qdio->req_q_lock); + if (zfcp_fsf_req_sbal_get(qdio)) goto out; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, - adapter->pool.erp_req); + req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA, + qdio->adapter->pool.erp_req); if (IS_ERR(req)) { retval = PTR_ERR(req); @@ -1245,7 +1249,7 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); + sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1265,29 +1269,29 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) erp_action->fsf_req = NULL; } out: - spin_unlock_bh(&adapter->req_q_lock); + spin_unlock_bh(&qdio->req_q_lock); return retval; } -int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, +int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio, struct fsf_qtcb_bottom_config *data) { struct qdio_buffer_element *sbale; struct zfcp_fsf_req *req = NULL; int retval = -EIO; - spin_lock_bh(&adapter->req_q_lock); - if (zfcp_fsf_req_sbal_get(adapter)) + spin_lock_bh(&qdio->req_q_lock); + if (zfcp_fsf_req_sbal_get(qdio)) goto out_unlock; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, NULL); + req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA, NULL); if (IS_ERR(req)) { retval = PTR_ERR(req); goto out_unlock; } - sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); + sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; req->handler = zfcp_fsf_exchange_config_data_handler; @@ -1303,7 +1307,7 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(req); - spin_unlock_bh(&adapter->req_q_lock); + spin_unlock_bh(&qdio->req_q_lock); if (!retval) wait_for_completion(&req->completion); @@ -1311,7 +1315,7 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, return retval; out_unlock: - spin_unlock_bh(&adapter->req_q_lock); + spin_unlock_bh(&qdio->req_q_lock); return retval; } @@ -1322,20 +1326,20 @@ out_unlock: */ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) { + struct zfcp_qdio *qdio = erp_action->adapter->qdio; struct qdio_buffer_element *sbale; struct zfcp_fsf_req *req; - struct zfcp_adapter *adapter = erp_action->adapter; int retval = -EIO; - if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) + if (!(qdio->adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) return -EOPNOTSUPP; - spin_lock_bh(&adapter->req_q_lock); - if (zfcp_fsf_req_sbal_get(adapter)) + spin_lock_bh(&qdio->req_q_lock); + if (zfcp_fsf_req_sbal_get(qdio)) goto out; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, - adapter->pool.erp_req); + req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA, + qdio->adapter->pool.erp_req); if (IS_ERR(req)) { retval = PTR_ERR(req); @@ -1343,7 +1347,7 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); + sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1358,31 +1362,31 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) erp_action->fsf_req = NULL; } out: - spin_unlock_bh(&adapter->req_q_lock); + spin_unlock_bh(&qdio->req_q_lock); return retval; } /** * zfcp_fsf_exchange_port_data_sync - request information about local port - * @adapter: pointer to struct zfcp_adapter + * @qdio: pointer to struct zfcp_qdio * @data: pointer to struct fsf_qtcb_bottom_port * Returns: 0 on success, error otherwise */ -int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, +int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio, struct fsf_qtcb_bottom_port *data) { struct qdio_buffer_element *sbale; struct zfcp_fsf_req *req = NULL; int retval = -EIO; - if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) + if (!(qdio->adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) return -EOPNOTSUPP; - spin_lock_bh(&adapter->req_q_lock); - if (zfcp_fsf_req_sbal_get(adapter)) + spin_lock_bh(&qdio->req_q_lock); + if (zfcp_fsf_req_sbal_get(qdio)) goto out_unlock; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, NULL); + req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA, NULL); if (IS_ERR(req)) { retval = PTR_ERR(req); @@ -1392,14 +1396,14 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, if (data) req->data = data; - sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); + sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; req->handler = zfcp_fsf_exchange_port_data_handler; zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(req); - spin_unlock_bh(&adapter->req_q_lock); + spin_unlock_bh(&qdio->req_q_lock); if (!retval) wait_for_completion(&req->completion); @@ -1409,7 +1413,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, return retval; out_unlock: - spin_unlock_bh(&adapter->req_q_lock); + spin_unlock_bh(&qdio->req_q_lock); return retval; } @@ -1495,17 +1499,17 @@ out: int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) { struct qdio_buffer_element *sbale; - struct zfcp_adapter *adapter = erp_action->adapter; - struct zfcp_fsf_req *req; + struct zfcp_qdio *qdio = erp_action->adapter->qdio; struct zfcp_port *port = erp_action->port; + struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&adapter->req_q_lock); - if (zfcp_fsf_req_sbal_get(adapter)) + spin_lock_bh(&qdio->req_q_lock); + if (zfcp_fsf_req_sbal_get(qdio)) goto out; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_OPEN_PORT_WITH_DID, - adapter->pool.erp_req); + req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID, + qdio->adapter->pool.erp_req); if (IS_ERR(req)) { retval = PTR_ERR(req); @@ -1513,7 +1517,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); + sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1532,7 +1536,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) zfcp_port_put(port); } out: - spin_unlock_bh(&adapter->req_q_lock); + spin_unlock_bh(&qdio->req_q_lock); return retval; } @@ -1566,16 +1570,16 @@ static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req) int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) { struct qdio_buffer_element *sbale; - struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_qdio *qdio = erp_action->adapter->qdio; struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&adapter->req_q_lock); - if (zfcp_fsf_req_sbal_get(adapter)) + spin_lock_bh(&qdio->req_q_lock); + if (zfcp_fsf_req_sbal_get(qdio)) goto out; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT, - adapter->pool.erp_req); + req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT, + qdio->adapter->pool.erp_req); if (IS_ERR(req)) { retval = PTR_ERR(req); @@ -1583,7 +1587,7 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); + sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1600,7 +1604,7 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) erp_action->fsf_req = NULL; } out: - spin_unlock_bh(&adapter->req_q_lock); + spin_unlock_bh(&qdio->req_q_lock); return retval; } @@ -1643,16 +1647,16 @@ out: int zfcp_fsf_open_wka_port(struct zfcp_wka_port *wka_port) { struct qdio_buffer_element *sbale; - struct zfcp_adapter *adapter = wka_port->adapter; + struct zfcp_qdio *qdio = wka_port->adapter->qdio; struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&adapter->req_q_lock); - if (zfcp_fsf_req_sbal_get(adapter)) + spin_lock_bh(&qdio->req_q_lock); + if (zfcp_fsf_req_sbal_get(qdio)) goto out; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_OPEN_PORT_WITH_DID, - adapter->pool.erp_req); + req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID, + qdio->adapter->pool.erp_req); if (unlikely(IS_ERR(req))) { retval = PTR_ERR(req); @@ -1660,7 +1664,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_wka_port *wka_port) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); + sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1673,7 +1677,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_wka_port *wka_port) if (retval) zfcp_fsf_req_free(req); out: - spin_unlock_bh(&adapter->req_q_lock); + spin_unlock_bh(&qdio->req_q_lock); return retval; } @@ -1698,16 +1702,16 @@ static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req) int zfcp_fsf_close_wka_port(struct zfcp_wka_port *wka_port) { struct qdio_buffer_element *sbale; - struct zfcp_adapter *adapter = wka_port->adapter; + struct zfcp_qdio *qdio = wka_port->adapter->qdio; struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&adapter->req_q_lock); - if (zfcp_fsf_req_sbal_get(adapter)) + spin_lock_bh(&qdio->req_q_lock); + if (zfcp_fsf_req_sbal_get(qdio)) goto out; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT, - adapter->pool.erp_req); + req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT, + qdio->adapter->pool.erp_req); if (unlikely(IS_ERR(req))) { retval = PTR_ERR(req); @@ -1715,7 +1719,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_wka_port *wka_port) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); + sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1728,7 +1732,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_wka_port *wka_port) if (retval) zfcp_fsf_req_free(req); out: - spin_unlock_bh(&adapter->req_q_lock); + spin_unlock_bh(&qdio->req_q_lock); return retval; } @@ -1790,16 +1794,16 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) { struct qdio_buffer_element *sbale; - struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_qdio *qdio = erp_action->adapter->qdio; struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&adapter->req_q_lock); - if (zfcp_fsf_req_sbal_get(adapter)) + spin_lock_bh(&qdio->req_q_lock); + if (zfcp_fsf_req_sbal_get(qdio)) goto out; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PHYSICAL_PORT, - adapter->pool.erp_req); + req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PHYSICAL_PORT, + qdio->adapter->pool.erp_req); if (IS_ERR(req)) { retval = PTR_ERR(req); @@ -1807,7 +1811,7 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); + sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1824,7 +1828,7 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) erp_action->fsf_req = NULL; } out: - spin_unlock_bh(&adapter->req_q_lock); + spin_unlock_bh(&qdio->req_q_lock); return retval; } @@ -1964,14 +1968,15 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) { struct qdio_buffer_element *sbale; struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_qdio *qdio = adapter->qdio; struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&adapter->req_q_lock); - if (zfcp_fsf_req_sbal_get(adapter)) + spin_lock_bh(&qdio->req_q_lock); + if (zfcp_fsf_req_sbal_get(qdio)) goto out; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_OPEN_LUN, + req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_LUN, adapter->pool.erp_req); if (IS_ERR(req)) { @@ -1980,7 +1985,7 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); + sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -2001,7 +2006,7 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) erp_action->fsf_req = NULL; } out: - spin_unlock_bh(&adapter->req_q_lock); + spin_unlock_bh(&qdio->req_q_lock); return retval; } @@ -2050,16 +2055,16 @@ static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req) int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) { struct qdio_buffer_element *sbale; - struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_qdio *qdio = erp_action->adapter->qdio; struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&adapter->req_q_lock); - if (zfcp_fsf_req_sbal_get(adapter)) + spin_lock_bh(&qdio->req_q_lock); + if (zfcp_fsf_req_sbal_get(qdio)) goto out; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_LUN, - adapter->pool.erp_req); + req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_LUN, + qdio->adapter->pool.erp_req); if (IS_ERR(req)) { retval = PTR_ERR(req); @@ -2067,7 +2072,7 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); + sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -2085,7 +2090,7 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) erp_action->fsf_req = NULL; } out: - spin_unlock_bh(&adapter->req_q_lock); + spin_unlock_bh(&qdio->req_q_lock); return retval; } @@ -2353,18 +2358,19 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, unsigned int sbtype = SBAL_FLAGS0_TYPE_READ; int real_bytes, retval = -EIO; struct zfcp_adapter *adapter = unit->port->adapter; + struct zfcp_qdio *qdio = adapter->qdio; if (unlikely(!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_UNBLOCKED))) return -EBUSY; - spin_lock(&adapter->req_q_lock); - if (atomic_read(&adapter->req_q.count) <= 0) { - atomic_inc(&adapter->qdio_outb_full); + spin_lock(&qdio->req_q_lock); + if (atomic_read(&qdio->req_q.count) <= 0) { + atomic_inc(&qdio->req_q_full); goto out; } - req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, + req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND, adapter->pool.scsi_req); if (IS_ERR(req)) { @@ -2424,7 +2430,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) + fcp_cmnd_iu->add_fcp_cdb_length + sizeof(u32); - real_bytes = zfcp_qdio_sbals_from_sg(adapter, &req->queue_req, sbtype, + real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->queue_req, sbtype, scsi_sglist(scsi_cmnd), FSF_MAX_SBALS_PER_REQ); if (unlikely(real_bytes < 0)) { @@ -2453,7 +2459,7 @@ failed_scsi_cmnd: zfcp_fsf_req_free(req); scsi_cmnd->host_scribble = NULL; out: - spin_unlock(&adapter->req_q_lock); + spin_unlock(&qdio->req_q_lock); return retval; } @@ -2468,18 +2474,18 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags) struct qdio_buffer_element *sbale; struct zfcp_fsf_req *req = NULL; struct fcp_cmnd_iu *fcp_cmnd_iu; - struct zfcp_adapter *adapter = unit->port->adapter; + struct zfcp_qdio *qdio = unit->port->adapter->qdio; if (unlikely(!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_UNBLOCKED))) return NULL; - spin_lock_bh(&adapter->req_q_lock); - if (zfcp_fsf_req_sbal_get(adapter)) + spin_lock_bh(&qdio->req_q_lock); + if (zfcp_fsf_req_sbal_get(qdio)) goto out; - req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, - adapter->pool.scsi_req); + req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND, + qdio->adapter->pool.scsi_req); if (IS_ERR(req)) { req = NULL; @@ -2496,7 +2502,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags) req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) + sizeof(u32); - sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); + sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -2511,7 +2517,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags) zfcp_fsf_req_free(req); req = NULL; out: - spin_unlock_bh(&adapter->req_q_lock); + spin_unlock_bh(&qdio->req_q_lock); return req; } @@ -2529,6 +2535,7 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, struct zfcp_fsf_cfdc *fsf_cfdc) { struct qdio_buffer_element *sbale; + struct zfcp_qdio *qdio = adapter->qdio; struct zfcp_fsf_req *req = NULL; struct fsf_qtcb_bottom_support *bottom; int direction, retval = -EIO, bytes; @@ -2547,11 +2554,11 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, return ERR_PTR(-EINVAL); } - spin_lock_bh(&adapter->req_q_lock); - if (zfcp_fsf_req_sbal_get(adapter)) + spin_lock_bh(&qdio->req_q_lock); + if (zfcp_fsf_req_sbal_get(qdio)) goto out; - req = zfcp_fsf_req_create(adapter, fsf_cfdc->command, NULL); + req = zfcp_fsf_req_create(qdio, fsf_cfdc->command, NULL); if (IS_ERR(req)) { retval = -EPERM; goto out; @@ -2559,15 +2566,16 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, req->handler = zfcp_fsf_control_file_handler; - sbale = zfcp_qdio_sbale_req(adapter, &req->queue_req); + sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); sbale[0].flags |= direction; bottom = &req->qtcb->bottom.support; bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE; bottom->option = fsf_cfdc->option; - bytes = zfcp_qdio_sbals_from_sg(adapter, &req->queue_req, direction, - fsf_cfdc->sg, FSF_MAX_SBALS_PER_REQ); + bytes = zfcp_qdio_sbals_from_sg(qdio, &req->queue_req, + direction, fsf_cfdc->sg, + FSF_MAX_SBALS_PER_REQ); if (bytes != ZFCP_CFDC_MAX_SIZE) { zfcp_fsf_req_free(req); goto out; @@ -2576,7 +2584,7 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(req); out: - spin_unlock_bh(&adapter->req_q_lock); + spin_unlock_bh(&qdio->req_q_lock); if (!retval) { wait_for_completion(&req->completion); @@ -2590,9 +2598,10 @@ out: * @adapter: pointer to struct zfcp_adapter * @sbal_idx: response queue index of SBAL to be processed */ -void zfcp_fsf_reqid_check(struct zfcp_adapter *adapter, int sbal_idx) +void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx) { - struct qdio_buffer *sbal = adapter->resp_q.sbal[sbal_idx]; + struct zfcp_adapter *adapter = qdio->adapter; + struct qdio_buffer *sbal = qdio->resp_q.sbal[sbal_idx]; struct qdio_buffer_element *sbale; struct zfcp_fsf_req *fsf_req; unsigned long flags, req_id; @@ -2618,7 +2627,7 @@ void zfcp_fsf_reqid_check(struct zfcp_adapter *adapter, int sbal_idx) fsf_req->queue_req.sbal_response = sbal_idx; fsf_req->queue_req.qdio_inb_usage = - atomic_read(&adapter->resp_q.count); + atomic_read(&qdio->resp_q.count); zfcp_fsf_req_complete(fsf_req); if (likely(sbale->flags & SBAL_FLAGS_LAST_ENTRY)) diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index e118874976f..0b3f634509b 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -36,18 +36,18 @@ zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx) /** * zfcp_qdio_free - free memory used by request- and resposne queue - * @adapter: pointer to the zfcp_adapter structure + * @qdio: pointer to the zfcp_qdio structure */ -void zfcp_qdio_free(struct zfcp_adapter *adapter) +void zfcp_qdio_free(struct zfcp_qdio *qdio) { struct qdio_buffer **sbal_req, **sbal_resp; int p; - if (adapter->ccw_device) - qdio_free(adapter->ccw_device); + if (qdio->adapter->ccw_device) + qdio_free(qdio->adapter->ccw_device); - sbal_req = adapter->req_q.sbal; - sbal_resp = adapter->resp_q.sbal; + sbal_req = qdio->req_q.sbal; + sbal_resp = qdio->resp_q.sbal; for (p = 0; p < QDIO_MAX_BUFFERS_PER_Q; p += QBUFF_PER_PAGE) { free_page((unsigned long) sbal_req[p]); @@ -55,8 +55,10 @@ void zfcp_qdio_free(struct zfcp_adapter *adapter) } } -static void zfcp_qdio_handler_error(struct zfcp_adapter *adapter, char *id) +static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id) { + struct zfcp_adapter *adapter = qdio->adapter; + dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n"); zfcp_erp_adapter_reopen(adapter, @@ -75,47 +77,47 @@ static void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int cnt) } /* this needs to be called prior to updating the queue fill level */ -static void zfcp_qdio_account(struct zfcp_adapter *adapter) +static void zfcp_qdio_account(struct zfcp_qdio *qdio) { ktime_t now; s64 span; int free, used; - spin_lock(&adapter->qdio_stat_lock); + spin_lock(&qdio->stat_lock); now = ktime_get(); - span = ktime_us_delta(now, adapter->req_q_time); - free = max(0, atomic_read(&adapter->req_q.count)); + span = ktime_us_delta(now, qdio->req_q_time); + free = max(0, atomic_read(&qdio->req_q.count)); used = QDIO_MAX_BUFFERS_PER_Q - free; - adapter->req_q_util += used * span; - adapter->req_q_time = now; - spin_unlock(&adapter->qdio_stat_lock); + qdio->req_q_util += used * span; + qdio->req_q_time = now; + spin_unlock(&qdio->stat_lock); } static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err, int queue_no, int first, int count, unsigned long parm) { - struct zfcp_adapter *adapter = (struct zfcp_adapter *) parm; - struct zfcp_qdio_queue *queue = &adapter->req_q; + struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm; + struct zfcp_qdio_queue *queue = &qdio->req_q; if (unlikely(qdio_err)) { - zfcp_hba_dbf_event_qdio(adapter, qdio_err, first, count); - zfcp_qdio_handler_error(adapter, "qdireq1"); + zfcp_hba_dbf_event_qdio(qdio, qdio_err, first, count); + zfcp_qdio_handler_error(qdio, "qdireq1"); return; } /* cleanup all SBALs being program-owned now */ zfcp_qdio_zero_sbals(queue->sbal, first, count); - zfcp_qdio_account(adapter); + zfcp_qdio_account(qdio); atomic_add(count, &queue->count); - wake_up(&adapter->request_wq); + wake_up(&qdio->req_q_wq); } -static void zfcp_qdio_resp_put_back(struct zfcp_adapter *adapter, int processed) +static void zfcp_qdio_resp_put_back(struct zfcp_qdio *qdio, int processed) { - struct zfcp_qdio_queue *queue = &adapter->resp_q; - struct ccw_device *cdev = adapter->ccw_device; + struct zfcp_qdio_queue *queue = &qdio->resp_q; + struct ccw_device *cdev = qdio->adapter->ccw_device; u8 count, start = queue->first; unsigned int retval; @@ -137,12 +139,12 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, int queue_no, int first, int count, unsigned long parm) { - struct zfcp_adapter *adapter = (struct zfcp_adapter *) parm; + struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm; int sbal_idx, sbal_no; if (unlikely(qdio_err)) { - zfcp_hba_dbf_event_qdio(adapter, qdio_err, first, count); - zfcp_qdio_handler_error(adapter, "qdires1"); + zfcp_hba_dbf_event_qdio(qdio, qdio_err, first, count); + zfcp_qdio_handler_error(qdio, "qdires1"); return; } @@ -153,26 +155,26 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, for (sbal_no = 0; sbal_no < count; sbal_no++) { sbal_idx = (first + sbal_no) % QDIO_MAX_BUFFERS_PER_Q; /* go through all SBALEs of SBAL */ - zfcp_fsf_reqid_check(adapter, sbal_idx); + zfcp_fsf_reqid_check(qdio, sbal_idx); } /* * put range of SBALs back to response queue * (including SBALs which have already been free before) */ - zfcp_qdio_resp_put_back(adapter, count); + zfcp_qdio_resp_put_back(qdio, count); } /** * zfcp_qdio_sbale_req - return ptr to SBALE of req_q for a struct zfcp_fsf_req - * @adapter: pointer to struct zfcp_adapter + * @qdio: pointer to struct zfcp_qdio * @q_rec: pointer to struct zfcp_queue_rec * Returns: pointer to qdio_buffer_element (SBALE) structure */ -struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_adapter *adapter, +struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_qdio *qdio, struct zfcp_queue_req *q_req) { - return zfcp_qdio_sbale(&adapter->req_q, q_req->sbal_last, 0); + return zfcp_qdio_sbale(&qdio->req_q, q_req->sbal_last, 0); } /** @@ -180,30 +182,30 @@ struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_adapter *adapter, * @fsf_req: pointer to struct fsf_req * Returns: pointer to qdio_buffer_element (SBALE) structure */ -struct qdio_buffer_element *zfcp_qdio_sbale_curr(struct zfcp_adapter *adapter, +struct qdio_buffer_element *zfcp_qdio_sbale_curr(struct zfcp_qdio *qdio, struct zfcp_queue_req *q_req) { - return zfcp_qdio_sbale(&adapter->req_q, q_req->sbal_last, + return zfcp_qdio_sbale(&qdio->req_q, q_req->sbal_last, q_req->sbale_curr); } -static void zfcp_qdio_sbal_limit(struct zfcp_adapter *adapter, +static void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio, struct zfcp_queue_req *q_req, int max_sbals) { - int count = atomic_read(&adapter->req_q.count); + int count = atomic_read(&qdio->req_q.count); count = min(count, max_sbals); q_req->sbal_limit = (q_req->sbal_first + count - 1) % QDIO_MAX_BUFFERS_PER_Q; } static struct qdio_buffer_element * -zfcp_qdio_sbal_chain(struct zfcp_adapter *adapter, struct zfcp_queue_req *q_req, +zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_queue_req *q_req, unsigned long sbtype) { struct qdio_buffer_element *sbale; /* set last entry flag in current SBALE of current SBAL */ - sbale = zfcp_qdio_sbale_curr(adapter, q_req); + sbale = zfcp_qdio_sbale_curr(qdio, q_req); sbale->flags |= SBAL_FLAGS_LAST_ENTRY; /* don't exceed last allowed SBAL */ @@ -211,7 +213,7 @@ zfcp_qdio_sbal_chain(struct zfcp_adapter *adapter, struct zfcp_queue_req *q_req, return NULL; /* set chaining flag in first SBALE of current SBAL */ - sbale = zfcp_qdio_sbale_req(adapter, q_req); + sbale = zfcp_qdio_sbale_req(qdio, q_req); sbale->flags |= SBAL_FLAGS0_MORE_SBALS; /* calculate index of next SBAL */ @@ -225,26 +227,26 @@ zfcp_qdio_sbal_chain(struct zfcp_adapter *adapter, struct zfcp_queue_req *q_req, q_req->sbale_curr = 0; /* set storage-block type for new SBAL */ - sbale = zfcp_qdio_sbale_curr(adapter, q_req); + sbale = zfcp_qdio_sbale_curr(qdio, q_req); sbale->flags |= sbtype; return sbale; } static struct qdio_buffer_element * -zfcp_qdio_sbale_next(struct zfcp_adapter *adapter, struct zfcp_queue_req *q_req, +zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_queue_req *q_req, unsigned int sbtype) { if (q_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL) - return zfcp_qdio_sbal_chain(adapter, q_req, sbtype); + return zfcp_qdio_sbal_chain(qdio, q_req, sbtype); q_req->sbale_curr++; - return zfcp_qdio_sbale_curr(adapter, q_req); + return zfcp_qdio_sbale_curr(qdio, q_req); } -static void zfcp_qdio_undo_sbals(struct zfcp_adapter *adapter, +static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio, struct zfcp_queue_req *q_req) { - struct qdio_buffer **sbal = adapter->req_q.sbal; + struct qdio_buffer **sbal = qdio->req_q.sbal; int first = q_req->sbal_first; int last = q_req->sbal_last; int count = (last - first + QDIO_MAX_BUFFERS_PER_Q) % @@ -252,7 +254,7 @@ static void zfcp_qdio_undo_sbals(struct zfcp_adapter *adapter, zfcp_qdio_zero_sbals(sbal, first, count); } -static int zfcp_qdio_fill_sbals(struct zfcp_adapter *adapter, +static int zfcp_qdio_fill_sbals(struct zfcp_qdio *qdio, struct zfcp_queue_req *q_req, unsigned int sbtype, void *start_addr, unsigned int total_length) @@ -264,10 +266,10 @@ static int zfcp_qdio_fill_sbals(struct zfcp_adapter *adapter, /* split segment up */ for (addr = start_addr, remaining = total_length; remaining > 0; addr += length, remaining -= length) { - sbale = zfcp_qdio_sbale_next(adapter, q_req, sbtype); + sbale = zfcp_qdio_sbale_next(qdio, q_req, sbtype); if (!sbale) { - atomic_inc(&adapter->qdio_outb_full); - zfcp_qdio_undo_sbals(adapter, q_req); + atomic_inc(&qdio->req_q_full); + zfcp_qdio_undo_sbals(qdio, q_req); return -EINVAL; } @@ -289,7 +291,7 @@ static int zfcp_qdio_fill_sbals(struct zfcp_adapter *adapter, * @max_sbals: upper bound for number of SBALs to be used * Returns: number of bytes, or error (negativ) */ -int zfcp_qdio_sbals_from_sg(struct zfcp_adapter *adapter, +int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_queue_req *q_req, unsigned long sbtype, struct scatterlist *sg, int max_sbals) @@ -298,14 +300,14 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_adapter *adapter, int retval, bytes = 0; /* figure out last allowed SBAL */ - zfcp_qdio_sbal_limit(adapter, q_req, max_sbals); + zfcp_qdio_sbal_limit(qdio, q_req, max_sbals); /* set storage-block type for this request */ - sbale = zfcp_qdio_sbale_req(adapter, q_req); + sbale = zfcp_qdio_sbale_req(qdio, q_req); sbale->flags |= sbtype; for (; sg; sg = sg_next(sg)) { - retval = zfcp_qdio_fill_sbals(adapter, q_req, sbtype, + retval = zfcp_qdio_fill_sbals(qdio, q_req, sbtype, sg_virt(sg), sg->length); if (retval < 0) return retval; @@ -313,7 +315,7 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_adapter *adapter, } /* assume that no other SBALEs are to follow in the same SBAL */ - sbale = zfcp_qdio_sbale_curr(adapter, q_req); + sbale = zfcp_qdio_sbale_curr(qdio, q_req); sbale->flags |= SBAL_FLAGS_LAST_ENTRY; return bytes; @@ -321,20 +323,22 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_adapter *adapter, /** * zfcp_qdio_send - set PCI flag in first SBALE and send req to QDIO - * @fsf_req: pointer to struct zfcp_fsf_req + * @qdio: pointer to struct zfcp_qdio + * @q_req: pointer to struct zfcp_queue_req * Returns: 0 on success, error otherwise */ -int zfcp_qdio_send(struct zfcp_adapter *adapter, struct zfcp_queue_req *q_req) +int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_queue_req *q_req) { - struct zfcp_qdio_queue *req_q = &adapter->req_q; + struct zfcp_qdio_queue *req_q = &qdio->req_q; int first = q_req->sbal_first; int count = q_req->sbal_number; int retval; unsigned int qdio_flags = QDIO_FLAG_SYNC_OUTPUT; - zfcp_qdio_account(adapter); + zfcp_qdio_account(qdio); - retval = do_QDIO(adapter->ccw_device, qdio_flags, 0, first, count); + retval = do_QDIO(qdio->adapter->ccw_device, qdio_flags, 0, first, + count); if (unlikely(retval)) { zfcp_qdio_zero_sbals(req_q->sbal, first, count); return retval; @@ -347,63 +351,69 @@ int zfcp_qdio_send(struct zfcp_adapter *adapter, struct zfcp_queue_req *q_req) return 0; } + +static void zfcp_qdio_setup_init_data(struct qdio_initialize *id, + struct zfcp_qdio *qdio) +{ + + id->cdev = qdio->adapter->ccw_device; + id->q_format = QDIO_ZFCP_QFMT; + memcpy(id->adapter_name, dev_name(&id->cdev->dev), 8); + ASCEBC(id->adapter_name, 8); + id->qib_param_field_format = 0; + id->qib_param_field = NULL; + id->input_slib_elements = NULL; + id->output_slib_elements = NULL; + id->no_input_qs = 1; + id->no_output_qs = 1; + id->input_handler = zfcp_qdio_int_resp; + id->output_handler = zfcp_qdio_int_req; + id->int_parm = (unsigned long) qdio; + id->flags = QDIO_INBOUND_0COPY_SBALS | + QDIO_OUTBOUND_0COPY_SBALS | QDIO_USE_OUTBOUND_PCIS; + id->input_sbal_addr_array = (void **) (qdio->resp_q.sbal); + id->output_sbal_addr_array = (void **) (qdio->req_q.sbal); + +} /** * zfcp_qdio_allocate - allocate queue memory and initialize QDIO data * @adapter: pointer to struct zfcp_adapter * Returns: -ENOMEM on memory allocation error or return value from * qdio_allocate */ -int zfcp_qdio_allocate(struct zfcp_adapter *adapter) +int zfcp_qdio_allocate(struct zfcp_qdio *qdio, struct ccw_device *ccw_dev) { - struct qdio_initialize *init_data; + struct qdio_initialize init_data; - if (zfcp_qdio_buffers_enqueue(adapter->req_q.sbal) || - zfcp_qdio_buffers_enqueue(adapter->resp_q.sbal)) + if (zfcp_qdio_buffers_enqueue(qdio->req_q.sbal) || + zfcp_qdio_buffers_enqueue(qdio->resp_q.sbal)) return -ENOMEM; - init_data = &adapter->qdio_init_data; - - init_data->cdev = adapter->ccw_device; - init_data->q_format = QDIO_ZFCP_QFMT; - memcpy(init_data->adapter_name, dev_name(&adapter->ccw_device->dev), 8); - ASCEBC(init_data->adapter_name, 8); - init_data->qib_param_field_format = 0; - init_data->qib_param_field = NULL; - init_data->input_slib_elements = NULL; - init_data->output_slib_elements = NULL; - init_data->no_input_qs = 1; - init_data->no_output_qs = 1; - init_data->input_handler = zfcp_qdio_int_resp; - init_data->output_handler = zfcp_qdio_int_req; - init_data->int_parm = (unsigned long) adapter; - init_data->flags = QDIO_INBOUND_0COPY_SBALS | - QDIO_OUTBOUND_0COPY_SBALS | QDIO_USE_OUTBOUND_PCIS; - init_data->input_sbal_addr_array = - (void **) (adapter->resp_q.sbal); - init_data->output_sbal_addr_array = - (void **) (adapter->req_q.sbal); - - return qdio_allocate(init_data); + zfcp_qdio_setup_init_data(&init_data, qdio); + + return qdio_allocate(&init_data); } /** * zfcp_close_qdio - close qdio queues for an adapter + * @qdio: pointer to structure zfcp_qdio */ -void zfcp_qdio_close(struct zfcp_adapter *adapter) +void zfcp_qdio_close(struct zfcp_qdio *qdio) { struct zfcp_qdio_queue *req_q; int first, count; - if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) + if (!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) return; /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */ - req_q = &adapter->req_q; - spin_lock_bh(&adapter->req_q_lock); - atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); - spin_unlock_bh(&adapter->req_q_lock); + req_q = &qdio->req_q; + spin_lock_bh(&qdio->req_q_lock); + atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status); + spin_unlock_bh(&qdio->req_q_lock); - qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR); + qdio_shutdown(qdio->adapter->ccw_device, + QDIO_FLAG_CLEANUP_USING_CLEAR); /* cleanup used outbound sbals */ count = atomic_read(&req_q->count); @@ -414,50 +424,54 @@ void zfcp_qdio_close(struct zfcp_adapter *adapter) } req_q->first = 0; atomic_set(&req_q->count, 0); - adapter->resp_q.first = 0; - atomic_set(&adapter->resp_q.count, 0); + qdio->resp_q.first = 0; + atomic_set(&qdio->resp_q.count, 0); } /** * zfcp_qdio_open - prepare and initialize response queue - * @adapter: pointer to struct zfcp_adapter + * @qdio: pointer to struct zfcp_qdio * Returns: 0 on success, otherwise -EIO */ -int zfcp_qdio_open(struct zfcp_adapter *adapter) +int zfcp_qdio_open(struct zfcp_qdio *qdio) { struct qdio_buffer_element *sbale; + struct qdio_initialize init_data; + struct ccw_device *cdev = qdio->adapter->ccw_device; int cc; - if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP) + if (atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP) return -EIO; - if (qdio_establish(&adapter->qdio_init_data)) + zfcp_qdio_setup_init_data(&init_data, qdio); + + if (qdio_establish(&init_data)) goto failed_establish; - if (qdio_activate(adapter->ccw_device)) + if (qdio_activate(cdev)) goto failed_qdio; for (cc = 0; cc < QDIO_MAX_BUFFERS_PER_Q; cc++) { - sbale = &(adapter->resp_q.sbal[cc]->element[0]); + sbale = &(qdio->resp_q.sbal[cc]->element[0]); sbale->length = 0; sbale->flags = SBAL_FLAGS_LAST_ENTRY; sbale->addr = NULL; } - if (do_QDIO(adapter->ccw_device, QDIO_FLAG_SYNC_INPUT, 0, 0, + if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, 0, QDIO_MAX_BUFFERS_PER_Q)) goto failed_qdio; /* set index of first avalable SBALS / number of available SBALS */ - adapter->req_q.first = 0; - atomic_set(&adapter->req_q.count, QDIO_MAX_BUFFERS_PER_Q); + qdio->req_q.first = 0; + atomic_set(&qdio->req_q.count, QDIO_MAX_BUFFERS_PER_Q); return 0; failed_qdio: - qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR); + qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR); failed_establish: - dev_err(&adapter->ccw_device->dev, + dev_err(&cdev->dev, "Setting up the QDIO connection to the FCP adapter failed\n"); return -EIO; } diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 2e13d41269a..4414720c87f 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -225,7 +225,7 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) { struct zfcp_unit *unit = scpnt->device->hostdata; struct zfcp_adapter *adapter = unit->port->adapter; - struct zfcp_fsf_req *fsf_req; + struct zfcp_fsf_req *fsf_req = NULL; int retval = SUCCESS; int retry = 3; @@ -429,7 +429,7 @@ static struct fc_host_statistics *zfcp_get_fc_host_stats(struct Scsi_Host *host) if (!data) return NULL; - ret = zfcp_fsf_exchange_port_data_sync(adapter, data); + ret = zfcp_fsf_exchange_port_data_sync(adapter->qdio, data); if (ret) { kfree(data); return NULL; @@ -458,7 +458,7 @@ static void zfcp_reset_fc_host_stats(struct Scsi_Host *shost) if (!data) return; - ret = zfcp_fsf_exchange_port_data_sync(adapter, data); + ret = zfcp_fsf_exchange_port_data_sync(adapter->qdio, data); if (ret) kfree(data); else { diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index 0fe5cce818c..a6cf6263683 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -425,7 +425,7 @@ static ssize_t zfcp_sysfs_adapter_util_show(struct device *dev, if (!qtcb_port) return -ENOMEM; - retval = zfcp_fsf_exchange_port_data_sync(adapter, qtcb_port); + retval = zfcp_fsf_exchange_port_data_sync(adapter->qdio, qtcb_port); if (!retval) retval = sprintf(buf, "%u %u %u\n", qtcb_port->cp_util, qtcb_port->cb_util, qtcb_port->a_util); @@ -451,7 +451,7 @@ static int zfcp_sysfs_adapter_ex_config(struct device *dev, if (!qtcb_config) return -ENOMEM; - retval = zfcp_fsf_exchange_config_data_sync(adapter, qtcb_config); + retval = zfcp_fsf_exchange_config_data_sync(adapter->qdio, qtcb_config); if (!retval) *stat_inf = qtcb_config->stat_info; @@ -492,15 +492,15 @@ static ssize_t zfcp_sysfs_adapter_q_full_show(struct device *dev, char *buf) { struct Scsi_Host *scsi_host = class_to_shost(dev); - struct zfcp_adapter *adapter = - (struct zfcp_adapter *) scsi_host->hostdata[0]; + struct zfcp_qdio *qdio = + ((struct zfcp_adapter *) scsi_host->hostdata[0])->qdio; u64 util; - spin_lock_bh(&adapter->qdio_stat_lock); - util = adapter->req_q_util; - spin_unlock_bh(&adapter->qdio_stat_lock); + spin_lock_bh(&qdio->stat_lock); + util = qdio->req_q_util; + spin_unlock_bh(&qdio->stat_lock); - return sprintf(buf, "%d %llu\n", atomic_read(&adapter->qdio_outb_full), + return sprintf(buf, "%d %llu\n", atomic_read(&qdio->req_q_full), (unsigned long long)util); } static DEVICE_ATTR(queue_full, S_IRUGO, zfcp_sysfs_adapter_q_full_show, NULL); -- cgit v1.2.3-18-g5258 From 799b76d09aeee558d18c1f5b93e63f58f1d1fc11 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 18 Aug 2009 15:43:20 +0200 Subject: [SCSI] zfcp: Decouple gid_pn requests from erp Don't let the erp wait for gid_pn requests to complete. Instead, queue the gid_pn work, exit erp and let the finished gid_pn work trigger a new port reopen. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 9 +++++++-- drivers/s390/scsi/zfcp_def.h | 1 + drivers/s390/scsi/zfcp_erp.c | 28 +-------------------------- drivers/s390/scsi/zfcp_ext.h | 6 ++---- drivers/s390/scsi/zfcp_fc.c | 45 +++++++++++++++++++++++++++++++++----------- drivers/s390/scsi/zfcp_fsf.c | 14 ++------------ 6 files changed, 47 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index ed7211ef04e..572dcd67e71 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -362,6 +362,11 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) if (!adapter->pool.erp_req) return -ENOMEM; + adapter->pool.gid_pn_req = + mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req)); + if (!adapter->pool.gid_pn_req) + return -ENOMEM; + adapter->pool.scsi_req = mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req)); if (!adapter->pool.scsi_req) @@ -379,7 +384,7 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) return -ENOMEM; adapter->pool.qtcb_pool = - mempool_create_slab_pool(3, zfcp_data.qtcb_cache); + mempool_create_slab_pool(4, zfcp_data.qtcb_cache); if (!adapter->pool.qtcb_pool) return -ENOMEM; @@ -652,7 +657,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, init_waitqueue_head(&port->remove_wq); INIT_LIST_HEAD(&port->unit_list_head); - INIT_WORK(&port->gid_pn_work, zfcp_erp_port_strategy_open_lookup); + INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup); INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); INIT_WORK(&port->rport_work, zfcp_scsi_rport_work); diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index bac5c497eab..9a8ff055342 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -265,6 +265,7 @@ struct zfcp_fsf_req; /* holds various memory pools of an adapter */ struct zfcp_adapter_mempool { mempool_t *erp_req; + mempool_t *gid_pn_req; mempool_t *scsi_req; mempool_t *scsi_abort; mempool_t *status_read_req; diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index feda1db56b2..67297d2744f 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -26,7 +26,6 @@ enum zfcp_erp_steps { ZFCP_ERP_STEP_FSF_XCONFIG = 0x0001, ZFCP_ERP_STEP_PHYS_PORT_CLOSING = 0x0010, ZFCP_ERP_STEP_PORT_CLOSING = 0x0100, - ZFCP_ERP_STEP_NAMESERVER_LOOKUP = 0x0400, ZFCP_ERP_STEP_PORT_OPENING = 0x0800, ZFCP_ERP_STEP_UNIT_CLOSING = 0x1000, ZFCP_ERP_STEP_UNIT_OPENING = 0x2000, @@ -842,27 +841,6 @@ static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act) return zfcp_erp_port_strategy_open_port(act); } -void zfcp_erp_port_strategy_open_lookup(struct work_struct *work) -{ - int retval; - struct zfcp_port *port = container_of(work, struct zfcp_port, - gid_pn_work); - - retval = zfcp_fc_ns_gid_pn(&port->erp_action); - if (!retval) { - port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP; - goto out; - } - if (retval == -ENOMEM) { - zfcp_erp_notify(&port->erp_action, ZFCP_STATUS_ERP_LOWMEM); - goto out; - } - /* all other error condtions */ - zfcp_erp_notify(&port->erp_action, 0); -out: - zfcp_port_put(port); -} - static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) { struct zfcp_adapter *adapter = act->adapter; @@ -880,12 +858,8 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) if (!queue_work(adapter->work_queue, &port->gid_pn_work)) zfcp_port_put(port); - return ZFCP_ERP_CONTINUES; + return ZFCP_ERP_EXIT; } - /* fall through */ - case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: - if (!port->d_id) - return ZFCP_ERP_FAILED; return zfcp_erp_port_strategy_open_port(act); case ZFCP_ERP_STEP_PORT_OPENING: diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index e97947d2f2e..7650cec7f71 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -94,13 +94,12 @@ extern void zfcp_erp_unit_access_denied(struct zfcp_unit *, char *, void *); extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, char *, void *); extern void zfcp_erp_timeout_handler(unsigned long); -extern void zfcp_erp_port_strategy_open_lookup(struct work_struct *); /* zfcp_fc.c */ extern int zfcp_scan_ports(struct zfcp_adapter *); extern void _zfcp_scan_ports_later(struct work_struct *); extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *); -extern int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *); +extern void zfcp_fc_port_did_lookup(struct work_struct *); extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); extern void zfcp_test_link(struct zfcp_port *); extern void zfcp_fc_link_test_work(struct work_struct *); @@ -128,8 +127,7 @@ extern struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *, extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); extern int zfcp_fsf_status_read(struct zfcp_qdio *); extern int zfcp_status_read_refill(struct zfcp_adapter *adapter); -extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *, - struct zfcp_erp_action *); +extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *); extern int zfcp_fsf_send_els(struct zfcp_send_els *); extern int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *, struct scsi_cmnd *); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 8921e16fdab..bc0c9f54d0d 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -282,15 +282,15 @@ static void zfcp_fc_ns_gid_pn_eval(unsigned long data) port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK; } -int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, +static int zfcp_fc_ns_gid_pn_request(struct zfcp_port *port, struct zfcp_gid_pn_data *gid_pn) { - struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_adapter *adapter = port->adapter; struct zfcp_fc_ns_handler_data compl_rec; int ret; /* setup parameters for send generic command */ - gid_pn->port = erp_action->port; + gid_pn->port = port; gid_pn->ct.wka_port = &adapter->gs->ds; gid_pn->ct.handler = zfcp_fc_ns_handler; gid_pn->ct.handler_data = (unsigned long) &compl_rec; @@ -309,12 +309,12 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, gid_pn->ct_iu_req.header.options = ZFCP_CT_SYNCHRONOUS; gid_pn->ct_iu_req.header.cmd_rsp_code = ZFCP_CT_GID_PN; gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_SIZE_ONE_PAGE / 4; - gid_pn->ct_iu_req.wwpn = erp_action->port->wwpn; + gid_pn->ct_iu_req.wwpn = port->wwpn; init_completion(&compl_rec.done); compl_rec.handler = zfcp_fc_ns_gid_pn_eval; compl_rec.handler_data = (unsigned long) gid_pn; - ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.erp_req, erp_action); + ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.gid_pn_req); if (!ret) wait_for_completion(&compl_rec.done); return ret; @@ -322,14 +322,14 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, /** * zfcp_fc_ns_gid_pn_request - initiate GID_PN nameserver request - * @erp_action: pointer to zfcp_erp_action where GID_PN request is needed + * @port: port where GID_PN request is needed * return: -ENOMEM on error, 0 otherwise */ -int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *erp_action) +static int zfcp_fc_ns_gid_pn(struct zfcp_port *port) { int ret; struct zfcp_gid_pn_data *gid_pn; - struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_adapter *adapter = port->adapter; gid_pn = mempool_alloc(adapter->pool.gid_pn_data, GFP_ATOMIC); if (!gid_pn) @@ -341,7 +341,7 @@ int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *erp_action) if (ret) goto out; - ret = zfcp_fc_ns_gid_pn_request(erp_action, gid_pn); + ret = zfcp_fc_ns_gid_pn_request(port, gid_pn); zfcp_wka_port_put(&adapter->gs->ds); out: @@ -349,6 +349,29 @@ out: return ret; } +void zfcp_fc_port_did_lookup(struct work_struct *work) +{ + int ret; + struct zfcp_port *port = container_of(work, struct zfcp_port, + gid_pn_work); + + ret = zfcp_fc_ns_gid_pn(port); + if (ret) { + /* could not issue gid_pn for some reason */ + zfcp_erp_adapter_reopen(port->adapter, 0, "fcgpn_1", NULL); + goto out; + } + + if (!port->d_id) { + zfcp_erp_port_failed(port, "fcgpn_2", NULL); + goto out; + } + + zfcp_erp_port_reopen(port, 0, "fcgpn_3", NULL); +out: + zfcp_port_put(port); +} + /** * zfcp_fc_plogi_evaluate - evaluate PLOGI playload * @port: zfcp_port structure @@ -551,7 +574,7 @@ static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, init_completion(&compl_rec.done); compl_rec.handler = NULL; - ret = zfcp_fsf_send_ct(ct, NULL, NULL); + ret = zfcp_fsf_send_ct(ct, NULL); if (!ret) wait_for_completion(&compl_rec.done); return ret; @@ -840,7 +863,7 @@ int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *job) ct_fc_job->ct.completion = NULL; ct_fc_job->job = job; - ret = zfcp_fsf_send_ct(&ct_fc_job->ct, NULL, NULL); + ret = zfcp_fsf_send_ct(&ct_fc_job->ct, NULL); if (ret) { kfree(ct_fc_job); zfcp_wka_port_put(ct_fc_job->ct.wka_port); diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index b9a16e4b48b..048f1a848f3 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -1069,10 +1069,8 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS) * @ct: pointer to struct zfcp_send_ct with data for request * @pool: if non-null this mempool is used to allocate struct zfcp_fsf_req - * @erp_action: if non-null the Generic Service request sent within ERP */ -int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, - struct zfcp_erp_action *erp_action) +int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool) { struct zfcp_wka_port *wka_port = ct->wka_port; struct zfcp_qdio *qdio = wka_port->adapter->qdio; @@ -1103,13 +1101,7 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, req->data = ct; zfcp_san_dbf_event_ct_request(req); - - if (erp_action) { - erp_action->fsf_req = req; - req->erp_action = erp_action; - zfcp_fsf_start_erp_timer(req); - } else - zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); + zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); ret = zfcp_fsf_req_send(req); if (ret) @@ -1119,8 +1111,6 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, failed_send: zfcp_fsf_req_free(req); - if (erp_action) - erp_action->fsf_req = NULL; out: spin_unlock_bh(&qdio->req_q_lock); return ret; -- cgit v1.2.3-18-g5258 From 5771710bd5edfafcb8656f49b93690a6fae5a4d2 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 18 Aug 2009 15:43:21 +0200 Subject: [SCSI] zfcp: Update dbf calls Change the dbf data and functions to use the zfcp_dbf prefix throughout the code. Also change the calls to dbf to use zfcp_dbf instead of zfcp_adapter. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 7 +- drivers/s390/scsi/zfcp_dbf.c | 408 ++++++++++++++++++++---------------------- drivers/s390/scsi/zfcp_dbf.h | 152 ++++++++-------- drivers/s390/scsi/zfcp_erp.c | 49 +++-- drivers/s390/scsi/zfcp_ext.h | 52 +++--- drivers/s390/scsi/zfcp_fc.c | 2 +- drivers/s390/scsi/zfcp_fsf.c | 24 +-- drivers/s390/scsi/zfcp_qdio.c | 6 +- drivers/s390/scsi/zfcp_scsi.c | 27 ++- 9 files changed, 347 insertions(+), 380 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 572dcd67e71..7a50f64c36b 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -517,6 +517,7 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) goto qdio_mem_failed; adapter->qdio->adapter = adapter; + ccw_device->handler = NULL; adapter->ccw_device = ccw_device; atomic_set(&adapter->refcount, 0); @@ -530,7 +531,7 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) if (zfcp_reqlist_alloc(adapter)) goto failed_low_mem_buffers; - if (zfcp_adapter_debug_register(adapter)) + if (zfcp_dbf_adapter_register(adapter)) goto debug_register_failed; if (zfcp_setup_adapter_work_queue(adapter)) @@ -577,7 +578,7 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) sysfs_failed: zfcp_destroy_adapter_work_queue(adapter); work_queue_failed: - zfcp_adapter_debug_unregister(adapter); + zfcp_dbf_adapter_unregister(adapter->dbf); debug_register_failed: dev_set_drvdata(&ccw_device->dev, NULL); kfree(adapter->req_list); @@ -616,7 +617,7 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) return; zfcp_destroy_adapter_work_queue(adapter); - zfcp_adapter_debug_unregister(adapter); + zfcp_dbf_adapter_unregister(adapter->dbf); zfcp_qdio_free(adapter->qdio); zfcp_free_low_mem_buffers(adapter); kfree(adapter->req_list); diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 3179b08bda6..c066428b287 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -120,9 +120,9 @@ static int zfcp_dbf_view_header(debug_info_t *id, struct debug_view *view, return p - out_buf; } -void _zfcp_hba_dbf_event_fsf_response(const char *tag2, int level, - struct zfcp_fsf_req *fsf_req, - struct zfcp_dbf *dbf) +void _zfcp_dbf_hba_fsf_response(const char *tag2, int level, + struct zfcp_fsf_req *fsf_req, + struct zfcp_dbf *dbf) { struct fsf_qtcb *qtcb = fsf_req->qtcb; union fsf_prot_status_qual *prot_status_qual = @@ -132,11 +132,11 @@ void _zfcp_hba_dbf_event_fsf_response(const char *tag2, int level, struct zfcp_port *port; struct zfcp_unit *unit; struct zfcp_send_els *send_els; - struct zfcp_hba_dbf_record *rec = &dbf->hba_dbf_buf; - struct zfcp_hba_dbf_record_response *response = &rec->u.response; + struct zfcp_dbf_hba_record *rec = &dbf->hba_buf; + struct zfcp_dbf_hba_record_response *response = &rec->u.response; unsigned long flags; - spin_lock_irqsave(&dbf->hba_dbf_lock, flags); + spin_lock_irqsave(&dbf->hba_lock, flags); memset(rec, 0, sizeof(*rec)); strncpy(rec->tag, "resp", ZFCP_DBF_TAG_SIZE); strncpy(rec->tag2, tag2, ZFCP_DBF_TAG_SIZE); @@ -203,7 +203,7 @@ void _zfcp_hba_dbf_event_fsf_response(const char *tag2, int level, break; } - debug_event(dbf->hba_dbf, level, rec, sizeof(*rec)); + debug_event(dbf->hba, level, rec, sizeof(*rec)); /* have fcp channel microcode fixed to use as little as possible */ if (fsf_req->fsf_command != FSF_QTCB_FCP_CMND) { @@ -211,27 +211,25 @@ void _zfcp_hba_dbf_event_fsf_response(const char *tag2, int level, char *buf = (char *)qtcb + qtcb->header.log_start; int len = qtcb->header.log_length; for (; len && !buf[len - 1]; len--); - zfcp_dbf_hexdump(dbf->hba_dbf, rec, sizeof(*rec), level, buf, + zfcp_dbf_hexdump(dbf->hba, rec, sizeof(*rec), level, buf, len); } - spin_unlock_irqrestore(&dbf->hba_dbf_lock, flags); + spin_unlock_irqrestore(&dbf->hba_lock, flags); } -void _zfcp_hba_dbf_event_fsf_unsol(const char *tag, int level, - struct zfcp_adapter *adapter, - struct fsf_status_read_buffer *status_buffer) +void _zfcp_dbf_hba_fsf_unsol(const char *tag, int level, struct zfcp_dbf *dbf, + struct fsf_status_read_buffer *status_buffer) { - struct zfcp_dbf *dbf = adapter->dbf; - struct zfcp_hba_dbf_record *rec = &dbf->hba_dbf_buf; + struct zfcp_dbf_hba_record *rec = &dbf->hba_buf; unsigned long flags; - spin_lock_irqsave(&dbf->hba_dbf_lock, flags); + spin_lock_irqsave(&dbf->hba_lock, flags); memset(rec, 0, sizeof(*rec)); strncpy(rec->tag, "stat", ZFCP_DBF_TAG_SIZE); strncpy(rec->tag2, tag, ZFCP_DBF_TAG_SIZE); - rec->u.status.failed = atomic_read(&adapter->stat_miss); + rec->u.status.failed = atomic_read(&dbf->adapter->stat_miss); if (status_buffer != NULL) { rec->u.status.status_type = status_buffer->status_type; rec->u.status.status_subtype = status_buffer->status_subtype; @@ -268,58 +266,54 @@ void _zfcp_hba_dbf_event_fsf_unsol(const char *tag, int level, &status_buffer->payload, rec->u.status.payload_size); } - debug_event(dbf->hba_dbf, level, rec, sizeof(*rec)); - spin_unlock_irqrestore(&dbf->hba_dbf_lock, flags); + debug_event(dbf->hba, level, rec, sizeof(*rec)); + spin_unlock_irqrestore(&dbf->hba_lock, flags); } /** - * zfcp_hba_dbf_event_qdio - trace event for QDIO related failure + * zfcp_dbf_hba_qdio - trace event for QDIO related failure * @qdio: qdio structure affected by this QDIO related event * @qdio_error: as passed by qdio module * @sbal_index: first buffer with error condition, as passed by qdio module * @sbal_count: number of buffers affected, as passed by qdio module */ -void zfcp_hba_dbf_event_qdio(struct zfcp_qdio *qdio, - unsigned int qdio_error, int sbal_index, - int sbal_count) +void zfcp_dbf_hba_qdio(struct zfcp_dbf *dbf, unsigned int qdio_error, + int sbal_index, int sbal_count) { - struct zfcp_dbf *dbf = qdio->adapter->dbf; - struct zfcp_hba_dbf_record *r = &dbf->hba_dbf_buf; + struct zfcp_dbf_hba_record *r = &dbf->hba_buf; unsigned long flags; - spin_lock_irqsave(&dbf->hba_dbf_lock, flags); + spin_lock_irqsave(&dbf->hba_lock, flags); memset(r, 0, sizeof(*r)); strncpy(r->tag, "qdio", ZFCP_DBF_TAG_SIZE); r->u.qdio.qdio_error = qdio_error; r->u.qdio.sbal_index = sbal_index; r->u.qdio.sbal_count = sbal_count; - debug_event(dbf->hba_dbf, 0, r, sizeof(*r)); - spin_unlock_irqrestore(&dbf->hba_dbf_lock, flags); + debug_event(dbf->hba, 0, r, sizeof(*r)); + spin_unlock_irqrestore(&dbf->hba_lock, flags); } /** - * zfcp_hba_dbf_event_berr - trace event for bit error threshold - * @adapter: adapter affected by this QDIO related event + * zfcp_dbf_hba_berr - trace event for bit error threshold + * @dbf: dbf structure affected by this QDIO related event * @req: fsf request */ -void zfcp_hba_dbf_event_berr(struct zfcp_adapter *adapter, - struct zfcp_fsf_req *req) +void zfcp_dbf_hba_berr(struct zfcp_dbf *dbf, struct zfcp_fsf_req *req) { - struct zfcp_dbf *dbf = adapter->dbf; - struct zfcp_hba_dbf_record *r = &dbf->hba_dbf_buf; + struct zfcp_dbf_hba_record *r = &dbf->hba_buf; struct fsf_status_read_buffer *sr_buf = req->data; struct fsf_bit_error_payload *err = &sr_buf->payload.bit_error; unsigned long flags; - spin_lock_irqsave(&dbf->hba_dbf_lock, flags); + spin_lock_irqsave(&dbf->hba_lock, flags); memset(r, 0, sizeof(*r)); strncpy(r->tag, "berr", ZFCP_DBF_TAG_SIZE); memcpy(&r->u.berr, err, sizeof(struct fsf_bit_error_payload)); - debug_event(dbf->hba_dbf, 0, r, sizeof(*r)); - spin_unlock_irqrestore(&dbf->hba_dbf_lock, flags); + debug_event(dbf->hba, 0, r, sizeof(*r)); + spin_unlock_irqrestore(&dbf->hba_lock, flags); } -static void zfcp_hba_dbf_view_response(char **p, - struct zfcp_hba_dbf_record_response *r) +static void zfcp_dbf_hba_view_response(char **p, + struct zfcp_dbf_hba_record_response *r) { struct timespec t; @@ -380,8 +374,8 @@ static void zfcp_hba_dbf_view_response(char **p, } } -static void zfcp_hba_dbf_view_status(char **p, - struct zfcp_hba_dbf_record_status *r) +static void zfcp_dbf_hba_view_status(char **p, + struct zfcp_dbf_hba_record_status *r) { zfcp_dbf_out(p, "failed", "0x%02x", r->failed); zfcp_dbf_out(p, "status_type", "0x%08x", r->status_type); @@ -393,14 +387,14 @@ static void zfcp_hba_dbf_view_status(char **p, r->payload_size); } -static void zfcp_hba_dbf_view_qdio(char **p, struct zfcp_hba_dbf_record_qdio *r) +static void zfcp_dbf_hba_view_qdio(char **p, struct zfcp_dbf_hba_record_qdio *r) { zfcp_dbf_out(p, "qdio_error", "0x%08x", r->qdio_error); zfcp_dbf_out(p, "sbal_index", "0x%02x", r->sbal_index); zfcp_dbf_out(p, "sbal_count", "0x%02x", r->sbal_count); } -static void zfcp_hba_dbf_view_berr(char **p, struct fsf_bit_error_payload *r) +static void zfcp_dbf_hba_view_berr(char **p, struct fsf_bit_error_payload *r) { zfcp_dbf_out(p, "link_failures", "%d", r->link_failure_error_count); zfcp_dbf_out(p, "loss_of_sync_err", "%d", r->loss_of_sync_error_count); @@ -424,10 +418,10 @@ static void zfcp_hba_dbf_view_berr(char **p, struct fsf_bit_error_payload *r) r->current_transmit_b2b_credit); } -static int zfcp_hba_dbf_view_format(debug_info_t *id, struct debug_view *view, +static int zfcp_dbf_hba_view_format(debug_info_t *id, struct debug_view *view, char *out_buf, const char *in_buf) { - struct zfcp_hba_dbf_record *r = (struct zfcp_hba_dbf_record *)in_buf; + struct zfcp_dbf_hba_record *r = (struct zfcp_dbf_hba_record *)in_buf; char *p = out_buf; if (strncmp(r->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0) @@ -438,45 +432,42 @@ static int zfcp_hba_dbf_view_format(debug_info_t *id, struct debug_view *view, zfcp_dbf_tag(&p, "tag2", r->tag2); if (strncmp(r->tag, "resp", ZFCP_DBF_TAG_SIZE) == 0) - zfcp_hba_dbf_view_response(&p, &r->u.response); + zfcp_dbf_hba_view_response(&p, &r->u.response); else if (strncmp(r->tag, "stat", ZFCP_DBF_TAG_SIZE) == 0) - zfcp_hba_dbf_view_status(&p, &r->u.status); + zfcp_dbf_hba_view_status(&p, &r->u.status); else if (strncmp(r->tag, "qdio", ZFCP_DBF_TAG_SIZE) == 0) - zfcp_hba_dbf_view_qdio(&p, &r->u.qdio); + zfcp_dbf_hba_view_qdio(&p, &r->u.qdio); else if (strncmp(r->tag, "berr", ZFCP_DBF_TAG_SIZE) == 0) - zfcp_hba_dbf_view_berr(&p, &r->u.berr); + zfcp_dbf_hba_view_berr(&p, &r->u.berr); if (strncmp(r->tag, "resp", ZFCP_DBF_TAG_SIZE) != 0) p += sprintf(p, "\n"); return p - out_buf; } -static struct debug_view zfcp_hba_dbf_view = { - "structured", - NULL, - &zfcp_dbf_view_header, - &zfcp_hba_dbf_view_format, - NULL, - NULL +static struct debug_view zfcp_dbf_hba_view = { + .name = "structured", + .header_proc = zfcp_dbf_view_header, + .format_proc = zfcp_dbf_hba_view_format, }; -static const char *zfcp_rec_dbf_tags[] = { +static const char *zfcp_dbf_rec_tags[] = { [ZFCP_REC_DBF_ID_THREAD] = "thread", [ZFCP_REC_DBF_ID_TARGET] = "target", [ZFCP_REC_DBF_ID_TRIGGER] = "trigger", [ZFCP_REC_DBF_ID_ACTION] = "action", }; -static int zfcp_rec_dbf_view_format(debug_info_t *id, struct debug_view *view, +static int zfcp_dbf_rec_view_format(debug_info_t *id, struct debug_view *view, char *buf, const char *_rec) { - struct zfcp_rec_dbf_record *r = (struct zfcp_rec_dbf_record *)_rec; + struct zfcp_dbf_rec_record *r = (struct zfcp_dbf_rec_record *)_rec; char *p = buf; char hint[ZFCP_DBF_ID_SIZE + 1]; memcpy(hint, r->id2, ZFCP_DBF_ID_SIZE); hint[ZFCP_DBF_ID_SIZE] = 0; - zfcp_dbf_outs(&p, "tag", zfcp_rec_dbf_tags[r->id]); + zfcp_dbf_outs(&p, "tag", zfcp_dbf_rec_tags[r->id]); zfcp_dbf_outs(&p, "hint", hint); switch (r->id) { case ZFCP_REC_DBF_ID_THREAD: @@ -514,25 +505,22 @@ static int zfcp_rec_dbf_view_format(debug_info_t *id, struct debug_view *view, return p - buf; } -static struct debug_view zfcp_rec_dbf_view = { - "structured", - NULL, - &zfcp_dbf_view_header, - &zfcp_rec_dbf_view_format, - NULL, - NULL +static struct debug_view zfcp_dbf_rec_view = { + .name = "structured", + .header_proc = zfcp_dbf_view_header, + .format_proc = zfcp_dbf_rec_view_format, }; /** - * zfcp_rec_dbf_event_thread - trace event related to recovery thread operation + * zfcp_dbf_rec_thread - trace event related to recovery thread operation * @id2: identifier for event - * @adapter: adapter + * @dbf: reference to dbf structure * This function assumes that the caller is holding erp_lock. */ -void zfcp_rec_dbf_event_thread(char *id2, struct zfcp_adapter *adapter) +void zfcp_dbf_rec_thread(char *id2, struct zfcp_dbf *dbf) { - struct zfcp_dbf *dbf = adapter->dbf; - struct zfcp_rec_dbf_record *r = &dbf->rec_dbf_buf; + struct zfcp_adapter *adapter = dbf->adapter; + struct zfcp_dbf_rec_record *r = &dbf->rec_buf; unsigned long flags = 0; struct list_head *entry; unsigned ready = 0, running = 0, total; @@ -543,42 +531,41 @@ void zfcp_rec_dbf_event_thread(char *id2, struct zfcp_adapter *adapter) running++; total = adapter->erp_total_count; - spin_lock_irqsave(&dbf->rec_dbf_lock, flags); + spin_lock_irqsave(&dbf->rec_lock, flags); memset(r, 0, sizeof(*r)); r->id = ZFCP_REC_DBF_ID_THREAD; memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE); r->u.thread.total = total; r->u.thread.ready = ready; r->u.thread.running = running; - debug_event(dbf->rec_dbf, 6, r, sizeof(*r)); - spin_unlock_irqrestore(&dbf->rec_dbf_lock, flags); + debug_event(dbf->rec, 6, r, sizeof(*r)); + spin_unlock_irqrestore(&dbf->rec_lock, flags); } /** - * zfcp_rec_dbf_event_thread - trace event related to recovery thread operation + * zfcp_dbf_rec_thread - trace event related to recovery thread operation * @id2: identifier for event * @adapter: adapter * This function assumes that the caller does not hold erp_lock. */ -void zfcp_rec_dbf_event_thread_lock(char *id2, struct zfcp_adapter *adapter) +void zfcp_dbf_rec_thread_lock(char *id2, struct zfcp_dbf *dbf) { + struct zfcp_adapter *adapter = dbf->adapter; unsigned long flags; read_lock_irqsave(&adapter->erp_lock, flags); - zfcp_rec_dbf_event_thread(id2, adapter); + zfcp_dbf_rec_thread(id2, dbf); read_unlock_irqrestore(&adapter->erp_lock, flags); } -static void zfcp_rec_dbf_event_target(char *id2, void *ref, - struct zfcp_adapter *adapter, - atomic_t *status, atomic_t *erp_count, - u64 wwpn, u32 d_id, u64 fcp_lun) +static void zfcp_dbf_rec_target(char *id2, void *ref, struct zfcp_dbf *dbf, + atomic_t *status, atomic_t *erp_count, u64 wwpn, + u32 d_id, u64 fcp_lun) { - struct zfcp_dbf *dbf = adapter->dbf; - struct zfcp_rec_dbf_record *r = &dbf->rec_dbf_buf; + struct zfcp_dbf_rec_record *r = &dbf->rec_buf; unsigned long flags; - spin_lock_irqsave(&dbf->rec_dbf_lock, flags); + spin_lock_irqsave(&dbf->rec_lock, flags); memset(r, 0, sizeof(*r)); r->id = ZFCP_REC_DBF_ID_TARGET; memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE); @@ -588,56 +575,57 @@ static void zfcp_rec_dbf_event_target(char *id2, void *ref, r->u.target.d_id = d_id; r->u.target.fcp_lun = fcp_lun; r->u.target.erp_count = atomic_read(erp_count); - debug_event(dbf->rec_dbf, 3, r, sizeof(*r)); - spin_unlock_irqrestore(&dbf->rec_dbf_lock, flags); + debug_event(dbf->rec, 3, r, sizeof(*r)); + spin_unlock_irqrestore(&dbf->rec_lock, flags); } /** - * zfcp_rec_dbf_event_adapter - trace event for adapter state change + * zfcp_dbf_rec_adapter - trace event for adapter state change * @id: identifier for trigger of state change * @ref: additional reference (e.g. request) - * @adapter: adapter + * @dbf: reference to dbf structure */ -void zfcp_rec_dbf_event_adapter(char *id, void *ref, - struct zfcp_adapter *adapter) +void zfcp_dbf_rec_adapter(char *id, void *ref, struct zfcp_dbf *dbf) { - zfcp_rec_dbf_event_target(id, ref, adapter, &adapter->status, + struct zfcp_adapter *adapter = dbf->adapter; + + zfcp_dbf_rec_target(id, ref, dbf, &adapter->status, &adapter->erp_counter, 0, 0, 0); } /** - * zfcp_rec_dbf_event_port - trace event for port state change + * zfcp_dbf_rec_port - trace event for port state change * @id: identifier for trigger of state change * @ref: additional reference (e.g. request) * @port: port */ -void zfcp_rec_dbf_event_port(char *id, void *ref, struct zfcp_port *port) +void zfcp_dbf_rec_port(char *id, void *ref, struct zfcp_port *port) { - struct zfcp_adapter *adapter = port->adapter; + struct zfcp_dbf *dbf = port->adapter->dbf; - zfcp_rec_dbf_event_target(id, ref, adapter, &port->status, + zfcp_dbf_rec_target(id, ref, dbf, &port->status, &port->erp_counter, port->wwpn, port->d_id, 0); } /** - * zfcp_rec_dbf_event_unit - trace event for unit state change + * zfcp_dbf_rec_unit - trace event for unit state change * @id: identifier for trigger of state change * @ref: additional reference (e.g. request) * @unit: unit */ -void zfcp_rec_dbf_event_unit(char *id, void *ref, struct zfcp_unit *unit) +void zfcp_dbf_rec_unit(char *id, void *ref, struct zfcp_unit *unit) { struct zfcp_port *port = unit->port; - struct zfcp_adapter *adapter = port->adapter; + struct zfcp_dbf *dbf = port->adapter->dbf; - zfcp_rec_dbf_event_target(id, ref, adapter, &unit->status, + zfcp_dbf_rec_target(id, ref, dbf, &unit->status, &unit->erp_counter, port->wwpn, port->d_id, unit->fcp_lun); } /** - * zfcp_rec_dbf_event_trigger - trace event for triggered error recovery + * zfcp_dbf_rec_trigger - trace event for triggered error recovery * @id2: identifier for error recovery trigger * @ref: additional reference (e.g. request) * @want: originally requested error recovery action @@ -647,15 +635,15 @@ void zfcp_rec_dbf_event_unit(char *id, void *ref, struct zfcp_unit *unit) * @port: port * @unit: unit */ -void zfcp_rec_dbf_event_trigger(char *id2, void *ref, u8 want, u8 need, - void *action, struct zfcp_adapter *adapter, - struct zfcp_port *port, struct zfcp_unit *unit) +void zfcp_dbf_rec_trigger(char *id2, void *ref, u8 want, u8 need, void *action, + struct zfcp_adapter *adapter, struct zfcp_port *port, + struct zfcp_unit *unit) { struct zfcp_dbf *dbf = adapter->dbf; - struct zfcp_rec_dbf_record *r = &dbf->rec_dbf_buf; + struct zfcp_dbf_rec_record *r = &dbf->rec_buf; unsigned long flags; - spin_lock_irqsave(&dbf->rec_dbf_lock, flags); + spin_lock_irqsave(&dbf->rec_lock, flags); memset(r, 0, sizeof(*r)); r->id = ZFCP_REC_DBF_ID_TRIGGER; memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE); @@ -672,23 +660,22 @@ void zfcp_rec_dbf_event_trigger(char *id2, void *ref, u8 want, u8 need, r->u.trigger.us = atomic_read(&unit->status); r->u.trigger.fcp_lun = unit->fcp_lun; } - debug_event(dbf->rec_dbf, action ? 1 : 4, r, sizeof(*r)); - spin_unlock_irqrestore(&dbf->rec_dbf_lock, flags); + debug_event(dbf->rec, action ? 1 : 4, r, sizeof(*r)); + spin_unlock_irqrestore(&dbf->rec_lock, flags); } /** - * zfcp_rec_dbf_event_action - trace event showing progress of recovery action + * zfcp_dbf_rec_action - trace event showing progress of recovery action * @id2: identifier * @erp_action: error recovery action struct pointer */ -void zfcp_rec_dbf_event_action(char *id2, struct zfcp_erp_action *erp_action) +void zfcp_dbf_rec_action(char *id2, struct zfcp_erp_action *erp_action) { - struct zfcp_adapter *adapter = erp_action->adapter; - struct zfcp_dbf *dbf = adapter->dbf; - struct zfcp_rec_dbf_record *r = &dbf->rec_dbf_buf; + struct zfcp_dbf *dbf = erp_action->adapter->dbf; + struct zfcp_dbf_rec_record *r = &dbf->rec_buf; unsigned long flags; - spin_lock_irqsave(&dbf->rec_dbf_lock, flags); + spin_lock_irqsave(&dbf->rec_lock, flags); memset(r, 0, sizeof(*r)); r->id = ZFCP_REC_DBF_ID_ACTION; memcpy(r->id2, id2, ZFCP_DBF_ID_SIZE); @@ -696,27 +683,27 @@ void zfcp_rec_dbf_event_action(char *id2, struct zfcp_erp_action *erp_action) r->u.action.status = erp_action->status; r->u.action.step = erp_action->step; r->u.action.fsf_req = (unsigned long)erp_action->fsf_req; - debug_event(dbf->rec_dbf, 5, r, sizeof(*r)); - spin_unlock_irqrestore(&dbf->rec_dbf_lock, flags); + debug_event(dbf->rec, 5, r, sizeof(*r)); + spin_unlock_irqrestore(&dbf->rec_lock, flags); } /** - * zfcp_san_dbf_event_ct_request - trace event for issued CT request + * zfcp_dbf_san_ct_request - trace event for issued CT request * @fsf_req: request containing issued CT data */ -void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req) +void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *fsf_req) { struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data; struct zfcp_wka_port *wka_port = ct->wka_port; struct zfcp_adapter *adapter = wka_port->adapter; struct zfcp_dbf *dbf = adapter->dbf; struct ct_hdr *hdr = sg_virt(ct->req); - struct zfcp_san_dbf_record *r = &dbf->san_dbf_buf; - struct zfcp_san_dbf_record_ct_request *oct = &r->u.ct_req; + struct zfcp_dbf_san_record *r = &dbf->san_buf; + struct zfcp_dbf_san_record_ct_request *oct = &r->u.ct_req; int level = 3; unsigned long flags; - spin_lock_irqsave(&dbf->san_dbf_lock, flags); + spin_lock_irqsave(&dbf->san_lock, flags); memset(r, 0, sizeof(*r)); strncpy(r->tag, "octc", ZFCP_DBF_TAG_SIZE); r->fsf_reqid = fsf_req->req_id; @@ -731,29 +718,29 @@ void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req) oct->max_res_size = hdr->max_res_size; oct->len = min((int)ct->req->length - (int)sizeof(struct ct_hdr), ZFCP_DBF_SAN_MAX_PAYLOAD); - debug_event(dbf->san_dbf, level, r, sizeof(*r)); - zfcp_dbf_hexdump(dbf->san_dbf, r, sizeof(*r), level, + debug_event(dbf->san, level, r, sizeof(*r)); + zfcp_dbf_hexdump(dbf->san, r, sizeof(*r), level, (void *)hdr + sizeof(struct ct_hdr), oct->len); - spin_unlock_irqrestore(&dbf->san_dbf_lock, flags); + spin_unlock_irqrestore(&dbf->san_lock, flags); } /** - * zfcp_san_dbf_event_ct_response - trace event for completion of CT request + * zfcp_dbf_san_ct_response - trace event for completion of CT request * @fsf_req: request containing CT response */ -void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req) +void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *fsf_req) { struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data; struct zfcp_wka_port *wka_port = ct->wka_port; struct zfcp_adapter *adapter = wka_port->adapter; struct ct_hdr *hdr = sg_virt(ct->resp); struct zfcp_dbf *dbf = adapter->dbf; - struct zfcp_san_dbf_record *r = &dbf->san_dbf_buf; - struct zfcp_san_dbf_record_ct_response *rct = &r->u.ct_resp; + struct zfcp_dbf_san_record *r = &dbf->san_buf; + struct zfcp_dbf_san_record_ct_response *rct = &r->u.ct_resp; int level = 3; unsigned long flags; - spin_lock_irqsave(&dbf->san_dbf_lock, flags); + spin_lock_irqsave(&dbf->san_lock, flags); memset(r, 0, sizeof(*r)); strncpy(r->tag, "rctc", ZFCP_DBF_TAG_SIZE); r->fsf_reqid = fsf_req->req_id; @@ -768,23 +755,22 @@ void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req) rct->max_res_size = hdr->max_res_size; rct->len = min((int)ct->resp->length - (int)sizeof(struct ct_hdr), ZFCP_DBF_SAN_MAX_PAYLOAD); - debug_event(dbf->san_dbf, level, r, sizeof(*r)); - zfcp_dbf_hexdump(dbf->san_dbf, r, sizeof(*r), level, + debug_event(dbf->san, level, r, sizeof(*r)); + zfcp_dbf_hexdump(dbf->san, r, sizeof(*r), level, (void *)hdr + sizeof(struct ct_hdr), rct->len); - spin_unlock_irqrestore(&dbf->san_dbf_lock, flags); + spin_unlock_irqrestore(&dbf->san_lock, flags); } -static void zfcp_san_dbf_event_els(const char *tag, int level, - struct zfcp_fsf_req *fsf_req, u32 s_id, - u32 d_id, u8 ls_code, void *buffer, - int buflen) +static void zfcp_dbf_san_els(const char *tag, int level, + struct zfcp_fsf_req *fsf_req, u32 s_id, u32 d_id, + u8 ls_code, void *buffer, int buflen) { struct zfcp_adapter *adapter = fsf_req->adapter; struct zfcp_dbf *dbf = adapter->dbf; - struct zfcp_san_dbf_record *rec = &dbf->san_dbf_buf; + struct zfcp_dbf_san_record *rec = &dbf->san_buf; unsigned long flags; - spin_lock_irqsave(&dbf->san_dbf_lock, flags); + spin_lock_irqsave(&dbf->san_lock, flags); memset(rec, 0, sizeof(*rec)); strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE); rec->fsf_reqid = fsf_req->req_id; @@ -792,45 +778,45 @@ static void zfcp_san_dbf_event_els(const char *tag, int level, rec->s_id = s_id; rec->d_id = d_id; rec->u.els.ls_code = ls_code; - debug_event(dbf->san_dbf, level, rec, sizeof(*rec)); - zfcp_dbf_hexdump(dbf->san_dbf, rec, sizeof(*rec), level, + debug_event(dbf->san, level, rec, sizeof(*rec)); + zfcp_dbf_hexdump(dbf->san, rec, sizeof(*rec), level, buffer, min(buflen, ZFCP_DBF_SAN_MAX_PAYLOAD)); - spin_unlock_irqrestore(&dbf->san_dbf_lock, flags); + spin_unlock_irqrestore(&dbf->san_lock, flags); } /** - * zfcp_san_dbf_event_els_request - trace event for issued ELS + * zfcp_dbf_san_els_request - trace event for issued ELS * @fsf_req: request containing issued ELS */ -void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req) +void zfcp_dbf_san_els_request(struct zfcp_fsf_req *fsf_req) { struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data; - zfcp_san_dbf_event_els("oels", 2, fsf_req, + zfcp_dbf_san_els("oels", 2, fsf_req, fc_host_port_id(els->adapter->scsi_host), els->d_id, *(u8 *) sg_virt(els->req), sg_virt(els->req), els->req->length); } /** - * zfcp_san_dbf_event_els_response - trace event for completed ELS + * zfcp_dbf_san_els_response - trace event for completed ELS * @fsf_req: request containing ELS response */ -void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req) +void zfcp_dbf_san_els_response(struct zfcp_fsf_req *fsf_req) { struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data; - zfcp_san_dbf_event_els("rels", 2, fsf_req, els->d_id, + zfcp_dbf_san_els("rels", 2, fsf_req, els->d_id, fc_host_port_id(els->adapter->scsi_host), *(u8 *)sg_virt(els->req), sg_virt(els->resp), els->resp->length); } /** - * zfcp_san_dbf_event_incoming_els - trace event for incomig ELS + * zfcp_dbf_san_incoming_els - trace event for incomig ELS * @fsf_req: request containing unsolicited status buffer with incoming ELS */ -void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req) +void zfcp_dbf_san_incoming_els(struct zfcp_fsf_req *fsf_req) { struct zfcp_adapter *adapter = fsf_req->adapter; struct fsf_status_read_buffer *buf = @@ -838,16 +824,16 @@ void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req) int length = (int)buf->length - (int)((void *)&buf->payload - (void *)buf); - zfcp_san_dbf_event_els("iels", 1, fsf_req, buf->d_id, + zfcp_dbf_san_els("iels", 1, fsf_req, buf->d_id, fc_host_port_id(adapter->scsi_host), buf->payload.data[0], (void *)buf->payload.data, length); } -static int zfcp_san_dbf_view_format(debug_info_t *id, struct debug_view *view, +static int zfcp_dbf_san_view_format(debug_info_t *id, struct debug_view *view, char *out_buf, const char *in_buf) { - struct zfcp_san_dbf_record *r = (struct zfcp_san_dbf_record *)in_buf; + struct zfcp_dbf_san_record *r = (struct zfcp_dbf_san_record *)in_buf; char *p = out_buf; if (strncmp(r->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0) @@ -860,7 +846,7 @@ static int zfcp_san_dbf_view_format(debug_info_t *id, struct debug_view *view, zfcp_dbf_out(&p, "d_id", "0x%06x", r->d_id); if (strncmp(r->tag, "octc", ZFCP_DBF_TAG_SIZE) == 0) { - struct zfcp_san_dbf_record_ct_request *ct = &r->u.ct_req; + struct zfcp_dbf_san_record_ct_request *ct = &r->u.ct_req; zfcp_dbf_out(&p, "cmd_req_code", "0x%04x", ct->cmd_req_code); zfcp_dbf_out(&p, "revision", "0x%02x", ct->revision); zfcp_dbf_out(&p, "gs_type", "0x%02x", ct->gs_type); @@ -868,7 +854,7 @@ static int zfcp_san_dbf_view_format(debug_info_t *id, struct debug_view *view, zfcp_dbf_out(&p, "options", "0x%02x", ct->options); zfcp_dbf_out(&p, "max_res_size", "0x%04x", ct->max_res_size); } else if (strncmp(r->tag, "rctc", ZFCP_DBF_TAG_SIZE) == 0) { - struct zfcp_san_dbf_record_ct_response *ct = &r->u.ct_resp; + struct zfcp_dbf_san_record_ct_response *ct = &r->u.ct_resp; zfcp_dbf_out(&p, "cmd_rsp_code", "0x%04x", ct->cmd_rsp_code); zfcp_dbf_out(&p, "revision", "0x%02x", ct->revision); zfcp_dbf_out(&p, "reason_code", "0x%02x", ct->reason_code); @@ -878,34 +864,30 @@ static int zfcp_san_dbf_view_format(debug_info_t *id, struct debug_view *view, } else if (strncmp(r->tag, "oels", ZFCP_DBF_TAG_SIZE) == 0 || strncmp(r->tag, "rels", ZFCP_DBF_TAG_SIZE) == 0 || strncmp(r->tag, "iels", ZFCP_DBF_TAG_SIZE) == 0) { - struct zfcp_san_dbf_record_els *els = &r->u.els; + struct zfcp_dbf_san_record_els *els = &r->u.els; zfcp_dbf_out(&p, "ls_code", "0x%02x", els->ls_code); } return p - out_buf; } -static struct debug_view zfcp_san_dbf_view = { - "structured", - NULL, - &zfcp_dbf_view_header, - &zfcp_san_dbf_view_format, - NULL, - NULL +static struct debug_view zfcp_dbf_san_view = { + .name = "structured", + .header_proc = zfcp_dbf_view_header, + .format_proc = zfcp_dbf_san_view_format, }; -void _zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level, - struct zfcp_dbf *dbf, struct scsi_cmnd *scsi_cmnd, - struct zfcp_fsf_req *fsf_req, - unsigned long old_req_id) +void _zfcp_dbf_scsi(const char *tag, const char *tag2, int level, + struct zfcp_dbf *dbf, struct scsi_cmnd *scsi_cmnd, + struct zfcp_fsf_req *fsf_req, unsigned long old_req_id) { - struct zfcp_scsi_dbf_record *rec = &dbf->scsi_dbf_buf; + struct zfcp_dbf_scsi_record *rec = &dbf->scsi_buf; struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)rec; unsigned long flags; struct fcp_rsp_iu *fcp_rsp; char *fcp_rsp_info = NULL, *fcp_sns_info = NULL; int offset = 0, buflen = 0; - spin_lock_irqsave(&dbf->scsi_dbf_lock, flags); + spin_lock_irqsave(&dbf->scsi_lock, flags); do { memset(rec, 0, sizeof(*rec)); if (offset == 0) { @@ -959,20 +941,20 @@ void _zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level, dump->offset = offset; dump->size = min(buflen - offset, (int)sizeof(struct - zfcp_scsi_dbf_record) - + zfcp_dbf_scsi_record) - (int)sizeof(struct zfcp_dbf_dump)); memcpy(dump->data, fcp_sns_info + offset, dump->size); offset += dump->size; } - debug_event(dbf->scsi_dbf, level, rec, sizeof(*rec)); + debug_event(dbf->scsi, level, rec, sizeof(*rec)); } while (offset < buflen); - spin_unlock_irqrestore(&dbf->scsi_dbf_lock, flags); + spin_unlock_irqrestore(&dbf->scsi_lock, flags); } -static int zfcp_scsi_dbf_view_format(debug_info_t *id, struct debug_view *view, +static int zfcp_dbf_scsi_view_format(debug_info_t *id, struct debug_view *view, char *out_buf, const char *in_buf) { - struct zfcp_scsi_dbf_record *r = (struct zfcp_scsi_dbf_record *)in_buf; + struct zfcp_dbf_scsi_record *r = (struct zfcp_dbf_scsi_record *)in_buf; struct timespec t; char *p = out_buf; @@ -1013,13 +995,10 @@ static int zfcp_scsi_dbf_view_format(debug_info_t *id, struct debug_view *view, return p - out_buf; } -static struct debug_view zfcp_scsi_dbf_view = { - "structured", - NULL, - &zfcp_dbf_view_header, - &zfcp_scsi_dbf_view_format, - NULL, - NULL +static struct debug_view zfcp_dbf_scsi_view = { + .name = "structured", + .header_proc = zfcp_dbf_view_header, + .format_proc = zfcp_dbf_scsi_view_format, }; static debug_info_t *zfcp_dbf_reg(const char *name, int level, @@ -1043,7 +1022,7 @@ static debug_info_t *zfcp_dbf_reg(const char *name, int level, * @adapter: pointer to adapter for which debug features should be registered * return: -ENOMEM on error, 0 otherwise */ -int zfcp_adapter_debug_register(struct zfcp_adapter *adapter) +int zfcp_dbf_adapter_register(struct zfcp_adapter *adapter) { char dbf_name[DEBUG_MAX_NAME_LEN]; struct zfcp_dbf *dbf; @@ -1052,63 +1031,60 @@ int zfcp_adapter_debug_register(struct zfcp_adapter *adapter) if (!dbf) return -ENOMEM; - spin_lock_init(&dbf->hba_dbf_lock); - spin_lock_init(&dbf->san_dbf_lock); - spin_lock_init(&dbf->scsi_dbf_lock); - spin_lock_init(&dbf->rec_dbf_lock); + dbf->adapter = adapter; + + spin_lock_init(&dbf->hba_lock); + spin_lock_init(&dbf->san_lock); + spin_lock_init(&dbf->scsi_lock); + spin_lock_init(&dbf->rec_lock); /* debug feature area which records recovery activity */ sprintf(dbf_name, "zfcp_%s_rec", dev_name(&adapter->ccw_device->dev)); - dbf->rec_dbf = zfcp_dbf_reg(dbf_name, 3, &zfcp_rec_dbf_view, - sizeof(struct zfcp_rec_dbf_record)); - if (!dbf->rec_dbf) - goto fail_rec; + dbf->rec = zfcp_dbf_reg(dbf_name, 3, &zfcp_dbf_rec_view, + sizeof(struct zfcp_dbf_rec_record)); + if (!dbf->rec) + goto err_out; /* debug feature area which records HBA (FSF and QDIO) conditions */ sprintf(dbf_name, "zfcp_%s_hba", dev_name(&adapter->ccw_device->dev)); - dbf->hba_dbf = zfcp_dbf_reg(dbf_name, 3, &zfcp_hba_dbf_view, - sizeof(struct zfcp_hba_dbf_record)); - if (!dbf->hba_dbf) - goto fail_hba; + dbf->hba = zfcp_dbf_reg(dbf_name, 3, &zfcp_dbf_hba_view, + sizeof(struct zfcp_dbf_hba_record)); + if (!dbf->hba) + goto err_out; /* debug feature area which records SAN command failures and recovery */ sprintf(dbf_name, "zfcp_%s_san", dev_name(&adapter->ccw_device->dev)); - dbf->san_dbf = zfcp_dbf_reg(dbf_name, 6, &zfcp_san_dbf_view, - sizeof(struct zfcp_san_dbf_record)); - if (!dbf->san_dbf) - goto fail_san; + dbf->san = zfcp_dbf_reg(dbf_name, 6, &zfcp_dbf_san_view, + sizeof(struct zfcp_dbf_san_record)); + if (!dbf->san) + goto err_out; /* debug feature area which records SCSI command failures and recovery */ sprintf(dbf_name, "zfcp_%s_scsi", dev_name(&adapter->ccw_device->dev)); - dbf->scsi_dbf = zfcp_dbf_reg(dbf_name, 3, &zfcp_scsi_dbf_view, - sizeof(struct zfcp_scsi_dbf_record)); - if (!dbf->scsi_dbf) - goto fail_scsi; + dbf->scsi = zfcp_dbf_reg(dbf_name, 3, &zfcp_dbf_scsi_view, + sizeof(struct zfcp_dbf_scsi_record)); + if (!dbf->scsi) + goto err_out; adapter->dbf = dbf; return 0; -fail_scsi: - debug_unregister(dbf->san_dbf); -fail_san: - debug_unregister(dbf->hba_dbf); -fail_hba: - debug_unregister(dbf->rec_dbf); -fail_rec: - kfree(dbf); +err_out: + zfcp_dbf_adapter_unregister(dbf); return -ENOMEM; } /** * zfcp_adapter_debug_unregister - unregisters debug feature for an adapter - * @adapter: pointer to adapter for which debug features should be unregistered + * @dbf: pointer to dbf for which debug features should be unregistered */ -void zfcp_adapter_debug_unregister(struct zfcp_adapter *adapter) +void zfcp_dbf_adapter_unregister(struct zfcp_dbf *dbf) { - debug_unregister(adapter->dbf->scsi_dbf); - debug_unregister(adapter->dbf->san_dbf); - debug_unregister(adapter->dbf->hba_dbf); - debug_unregister(adapter->dbf->rec_dbf); - kfree(adapter->dbf); - adapter->dbf = NULL; + debug_unregister(dbf->scsi); + debug_unregister(dbf->san); + debug_unregister(dbf->hba); + debug_unregister(dbf->rec); + dbf->adapter->dbf = NULL; + kfree(dbf); } + diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index bceaff44903..6b1461e8f84 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -37,13 +37,13 @@ struct zfcp_dbf_dump { u8 data[]; /* dump data */ } __attribute__ ((packed)); -struct zfcp_rec_dbf_record_thread { +struct zfcp_dbf_rec_record_thread { u32 total; u32 ready; u32 running; }; -struct zfcp_rec_dbf_record_target { +struct zfcp_dbf_rec_record_target { u64 ref; u32 status; u32 d_id; @@ -52,7 +52,7 @@ struct zfcp_rec_dbf_record_target { u32 erp_count; }; -struct zfcp_rec_dbf_record_trigger { +struct zfcp_dbf_rec_record_trigger { u8 want; u8 need; u32 as; @@ -64,21 +64,21 @@ struct zfcp_rec_dbf_record_trigger { u64 fcp_lun; }; -struct zfcp_rec_dbf_record_action { +struct zfcp_dbf_rec_record_action { u32 status; u32 step; u64 action; u64 fsf_req; }; -struct zfcp_rec_dbf_record { +struct zfcp_dbf_rec_record { u8 id; char id2[7]; union { - struct zfcp_rec_dbf_record_action action; - struct zfcp_rec_dbf_record_thread thread; - struct zfcp_rec_dbf_record_target target; - struct zfcp_rec_dbf_record_trigger trigger; + struct zfcp_dbf_rec_record_action action; + struct zfcp_dbf_rec_record_thread thread; + struct zfcp_dbf_rec_record_target target; + struct zfcp_dbf_rec_record_trigger trigger; } u; }; @@ -89,7 +89,7 @@ enum { ZFCP_REC_DBF_ID_TRIGGER, }; -struct zfcp_hba_dbf_record_response { +struct zfcp_dbf_hba_record_response { u32 fsf_command; u64 fsf_reqid; u32 fsf_seqno; @@ -127,7 +127,7 @@ struct zfcp_hba_dbf_record_response { } u; } __attribute__ ((packed)); -struct zfcp_hba_dbf_record_status { +struct zfcp_dbf_hba_record_status { u8 failed; u32 status_type; u32 status_subtype; @@ -141,24 +141,24 @@ struct zfcp_hba_dbf_record_status { u8 payload[ZFCP_DBF_UNSOL_PAYLOAD]; } __attribute__ ((packed)); -struct zfcp_hba_dbf_record_qdio { +struct zfcp_dbf_hba_record_qdio { u32 qdio_error; u8 sbal_index; u8 sbal_count; } __attribute__ ((packed)); -struct zfcp_hba_dbf_record { +struct zfcp_dbf_hba_record { u8 tag[ZFCP_DBF_TAG_SIZE]; u8 tag2[ZFCP_DBF_TAG_SIZE]; union { - struct zfcp_hba_dbf_record_response response; - struct zfcp_hba_dbf_record_status status; - struct zfcp_hba_dbf_record_qdio qdio; + struct zfcp_dbf_hba_record_response response; + struct zfcp_dbf_hba_record_status status; + struct zfcp_dbf_hba_record_qdio qdio; struct fsf_bit_error_payload berr; } u; } __attribute__ ((packed)); -struct zfcp_san_dbf_record_ct_request { +struct zfcp_dbf_san_record_ct_request { u16 cmd_req_code; u8 revision; u8 gs_type; @@ -168,7 +168,7 @@ struct zfcp_san_dbf_record_ct_request { u32 len; } __attribute__ ((packed)); -struct zfcp_san_dbf_record_ct_response { +struct zfcp_dbf_san_record_ct_response { u16 cmd_rsp_code; u8 revision; u8 reason_code; @@ -178,27 +178,27 @@ struct zfcp_san_dbf_record_ct_response { u32 len; } __attribute__ ((packed)); -struct zfcp_san_dbf_record_els { +struct zfcp_dbf_san_record_els { u8 ls_code; u32 len; } __attribute__ ((packed)); -struct zfcp_san_dbf_record { +struct zfcp_dbf_san_record { u8 tag[ZFCP_DBF_TAG_SIZE]; u64 fsf_reqid; u32 fsf_seqno; u32 s_id; u32 d_id; union { - struct zfcp_san_dbf_record_ct_request ct_req; - struct zfcp_san_dbf_record_ct_response ct_resp; - struct zfcp_san_dbf_record_els els; + struct zfcp_dbf_san_record_ct_request ct_req; + struct zfcp_dbf_san_record_ct_response ct_resp; + struct zfcp_dbf_san_record_els els; } u; #define ZFCP_DBF_SAN_MAX_PAYLOAD 1024 u8 payload[32]; } __attribute__ ((packed)); -struct zfcp_scsi_dbf_record { +struct zfcp_dbf_scsi_record { u8 tag[ZFCP_DBF_TAG_SIZE]; u8 tag2[ZFCP_DBF_TAG_SIZE]; u32 scsi_id; @@ -225,86 +225,84 @@ struct zfcp_scsi_dbf_record { } __attribute__ ((packed)); struct zfcp_dbf { - debug_info_t *rec_dbf; - debug_info_t *hba_dbf; - debug_info_t *san_dbf; - debug_info_t *scsi_dbf; - spinlock_t rec_dbf_lock; - spinlock_t hba_dbf_lock; - spinlock_t san_dbf_lock; - spinlock_t scsi_dbf_lock; - struct zfcp_rec_dbf_record rec_dbf_buf; - struct zfcp_hba_dbf_record hba_dbf_buf; - struct zfcp_san_dbf_record san_dbf_buf; - struct zfcp_scsi_dbf_record scsi_dbf_buf; + debug_info_t *rec; + debug_info_t *hba; + debug_info_t *san; + debug_info_t *scsi; + spinlock_t rec_lock; + spinlock_t hba_lock; + spinlock_t san_lock; + spinlock_t scsi_lock; + struct zfcp_dbf_rec_record rec_buf; + struct zfcp_dbf_hba_record hba_buf; + struct zfcp_dbf_san_record san_buf; + struct zfcp_dbf_scsi_record scsi_buf; + struct zfcp_adapter *adapter; }; static inline -void zfcp_hba_dbf_event_fsf_resp(const char *tag2, int level, - struct zfcp_fsf_req *req, struct zfcp_dbf *dbf) +void zfcp_dbf_hba_fsf_resp(const char *tag2, int level, + struct zfcp_fsf_req *req, struct zfcp_dbf *dbf) { - if (level <= dbf->hba_dbf->level) - _zfcp_hba_dbf_event_fsf_response(tag2, level, req, dbf); + if (level <= dbf->hba->level) + _zfcp_dbf_hba_fsf_response(tag2, level, req, dbf); } /** - * zfcp_hba_dbf_event_fsf_response - trace event for request completion + * zfcp_dbf_hba_fsf_response - trace event for request completion * @fsf_req: request that has been completed */ -static inline void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *req) +static inline void zfcp_dbf_hba_fsf_response(struct zfcp_fsf_req *req) { struct zfcp_dbf *dbf = req->adapter->dbf; struct fsf_qtcb *qtcb = req->qtcb; if ((qtcb->prefix.prot_status != FSF_PROT_GOOD) && (qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) { - zfcp_hba_dbf_event_fsf_resp("perr", 1, req, dbf); + zfcp_dbf_hba_fsf_resp("perr", 1, req, dbf); } else if (qtcb->header.fsf_status != FSF_GOOD) { - zfcp_hba_dbf_event_fsf_resp("ferr", 1, req, dbf); + zfcp_dbf_hba_fsf_resp("ferr", 1, req, dbf); } else if ((req->fsf_command == FSF_QTCB_OPEN_PORT_WITH_DID) || (req->fsf_command == FSF_QTCB_OPEN_LUN)) { - zfcp_hba_dbf_event_fsf_resp("open", 4, req, dbf); + zfcp_dbf_hba_fsf_resp("open", 4, req, dbf); } else if (qtcb->header.log_length) { - zfcp_hba_dbf_event_fsf_resp("qtcb", 5, req, dbf); + zfcp_dbf_hba_fsf_resp("qtcb", 5, req, dbf); } else { - zfcp_hba_dbf_event_fsf_resp("norm", 6, req, dbf); + zfcp_dbf_hba_fsf_resp("norm", 6, req, dbf); } } /** - * zfcp_hba_dbf_event_fsf_unsol - trace event for an unsolicited status buffer + * zfcp_dbf_hba_fsf_unsol - trace event for an unsolicited status buffer * @tag: tag indicating which kind of unsolicited status has been received - * @adapter: adapter that has issued the unsolicited status buffer + * @dbf: reference to dbf structure * @status_buffer: buffer containing payload of unsolicited status */ static inline -void zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter, - struct fsf_status_read_buffer *buf) +void zfcp_dbf_hba_fsf_unsol(const char *tag, struct zfcp_dbf *dbf, + struct fsf_status_read_buffer *buf) { - struct zfcp_dbf *dbf = adapter->dbf; int level = 2; - if (level <= dbf->hba_dbf->level) - _zfcp_hba_dbf_event_fsf_unsol(tag, level, adapter, buf); + if (level <= dbf->hba->level) + _zfcp_dbf_hba_fsf_unsol(tag, level, dbf, buf); } static inline -void zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level, - struct zfcp_adapter *adapter, struct scsi_cmnd *scmd, - struct zfcp_fsf_req *req, unsigned long old_id) +void zfcp_dbf_scsi(const char *tag, const char *tag2, int level, + struct zfcp_dbf *dbf, struct scsi_cmnd *scmd, + struct zfcp_fsf_req *req, unsigned long old_id) { - struct zfcp_dbf *dbf = adapter->dbf; - - if (level <= dbf->scsi_dbf->level) - _zfcp_scsi_dbf_event(tag, tag2, level, dbf, scmd, req, old_id); + if (level <= dbf->scsi->level) + _zfcp_dbf_scsi(tag, tag2, level, dbf, scmd, req, old_id); } /** - * zfcp_scsi_dbf_event_result - trace event for SCSI command completion + * zfcp_dbf_scsi_result - trace event for SCSI command completion * @tag: tag indicating success or failure of SCSI command * @level: trace level applicable for this event * @adapter: adapter that has been used to issue the SCSI command @@ -312,16 +310,14 @@ void zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level, * @fsf_req: request used to issue SCSI command (might be NULL) */ static inline -void zfcp_scsi_dbf_event_result(const char *tag, int level, - struct zfcp_adapter *adapter, - struct scsi_cmnd *scmd, - struct zfcp_fsf_req *fsf_req) +void zfcp_dbf_scsi_result(const char *tag, int level, struct zfcp_dbf *dbf, + struct scsi_cmnd *scmd, struct zfcp_fsf_req *fsf_req) { - zfcp_scsi_dbf_event("rslt", tag, level, adapter, scmd, fsf_req, 0); + zfcp_dbf_scsi("rslt", tag, level, dbf, scmd, fsf_req, 0); } /** - * zfcp_scsi_dbf_event_abort - trace event for SCSI command abort + * zfcp_dbf_scsi_abort - trace event for SCSI command abort * @tag: tag indicating success or failure of abort operation * @adapter: adapter thas has been used to issue SCSI command to be aborted * @scmd: SCSI command to be aborted @@ -329,28 +325,26 @@ void zfcp_scsi_dbf_event_result(const char *tag, int level, * @old_id: identifier of request containg SCSI command to be aborted */ static inline -void zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter, - struct scsi_cmnd *scmd, - struct zfcp_fsf_req *new_req, - unsigned long old_id) +void zfcp_dbf_scsi_abort(const char *tag, struct zfcp_dbf *dbf, + struct scsi_cmnd *scmd, struct zfcp_fsf_req *new_req, + unsigned long old_id) { - zfcp_scsi_dbf_event("abrt", tag, 1, adapter, scmd, new_req, old_id); + zfcp_dbf_scsi("abrt", tag, 1, dbf, scmd, new_req, old_id); } /** - * zfcp_scsi_dbf_event_devreset - trace event for Logical Unit or Target Reset + * zfcp_dbf_scsi_devreset - trace event for Logical Unit or Target Reset * @tag: tag indicating success or failure of reset operation * @flag: indicates type of reset (Target Reset, Logical Unit Reset) * @unit: unit that needs reset * @scsi_cmnd: SCSI command which caused this error recovery */ static inline -void zfcp_scsi_dbf_event_devreset(const char *tag, u8 flag, - struct zfcp_unit *unit, - struct scsi_cmnd *scsi_cmnd) +void zfcp_dbf_scsi_devreset(const char *tag, u8 flag, struct zfcp_unit *unit, + struct scsi_cmnd *scsi_cmnd) { - zfcp_scsi_dbf_event(flag == FCP_TARGET_RESET ? "trst" : "lrst", tag, 1, - unit->port->adapter, scsi_cmnd, NULL, 0); + zfcp_dbf_scsi(flag == FCP_TARGET_RESET ? "trst" : "lrst", tag, 1, + unit->port->adapter->dbf, scsi_cmnd, NULL, 0); } #endif /* ZFCP_DBF_H */ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 67297d2744f..373567eda8f 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -74,9 +74,9 @@ static void zfcp_erp_action_ready(struct zfcp_erp_action *act) struct zfcp_adapter *adapter = act->adapter; list_move(&act->list, &act->adapter->erp_ready_head); - zfcp_rec_dbf_event_action("erardy1", act); + zfcp_dbf_rec_action("erardy1", act); up(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread("erardy2", adapter); + zfcp_dbf_rec_thread("erardy2", adapter->dbf); } static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act) @@ -227,11 +227,10 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, ++adapter->erp_total_count; list_add_tail(&act->list, &adapter->erp_ready_head); up(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread("eracte1", adapter); + zfcp_dbf_rec_thread("eracte1", adapter->dbf); retval = 0; out: - zfcp_rec_dbf_event_trigger(id, ref, want, need, act, - adapter, port, unit); + zfcp_dbf_rec_trigger(id, ref, want, need, act, adapter, port, unit); return retval; } @@ -442,28 +441,28 @@ static int status_change_clear(unsigned long mask, atomic_t *status) static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) { if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) - zfcp_rec_dbf_event_adapter("eraubl1", NULL, adapter); + zfcp_dbf_rec_adapter("eraubl1", NULL, adapter->dbf); atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status); } static void zfcp_erp_port_unblock(struct zfcp_port *port) { if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) - zfcp_rec_dbf_event_port("erpubl1", NULL, port); + zfcp_dbf_rec_port("erpubl1", NULL, port); atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status); } static void zfcp_erp_unit_unblock(struct zfcp_unit *unit) { if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status)) - zfcp_rec_dbf_event_unit("eruubl1", NULL, unit); + zfcp_dbf_rec_unit("eruubl1", NULL, unit); atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status); } static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) { list_move(&erp_action->list, &erp_action->adapter->erp_running_head); - zfcp_rec_dbf_event_action("erator1", erp_action); + zfcp_dbf_rec_action("erator1", erp_action); } static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act) @@ -479,11 +478,11 @@ static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act) if (act->status & (ZFCP_STATUS_ERP_DISMISSED | ZFCP_STATUS_ERP_TIMEDOUT)) { act->fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; - zfcp_rec_dbf_event_action("erscf_1", act); + zfcp_dbf_rec_action("erscf_1", act); act->fsf_req->erp_action = NULL; } if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) - zfcp_rec_dbf_event_action("erscf_2", act); + zfcp_dbf_rec_action("erscf_2", act); if (act->fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) act->fsf_req = NULL; } else @@ -641,9 +640,9 @@ static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action) return ZFCP_ERP_FAILED; } - zfcp_rec_dbf_event_thread_lock("erasfx1", adapter); + zfcp_dbf_rec_thread_lock("erasfx1", adapter->dbf); down(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread_lock("erasfx2", adapter); + zfcp_dbf_rec_thread_lock("erasfx2", adapter->dbf); if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) break; @@ -682,9 +681,9 @@ static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act) if (ret) return ZFCP_ERP_FAILED; - zfcp_rec_dbf_event_thread_lock("erasox1", adapter); + zfcp_dbf_rec_thread_lock("erasox1", adapter->dbf); down(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread_lock("erasox2", adapter); + zfcp_dbf_rec_thread_lock("erasox2", adapter->dbf); if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) return ZFCP_ERP_FAILED; @@ -1138,7 +1137,7 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) } list_del(&erp_action->list); - zfcp_rec_dbf_event_action("eractd1", erp_action); + zfcp_dbf_rec_action("eractd1", erp_action); switch (erp_action->action) { case ZFCP_ERP_ACTION_REOPEN_UNIT: @@ -1297,9 +1296,9 @@ static int zfcp_erp_thread(void *data) while (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL)) { - zfcp_rec_dbf_event_thread_lock("erthrd1", adapter); + zfcp_dbf_rec_thread_lock("erthrd1", adapter->dbf); ignore = down_interruptible(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread_lock("erthrd2", adapter); + zfcp_dbf_rec_thread_lock("erthrd2", adapter->dbf); write_lock_irqsave(&adapter->erp_lock, flags); next = adapter->erp_ready_head.next; @@ -1356,7 +1355,7 @@ void zfcp_erp_thread_kill(struct zfcp_adapter *adapter) { atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status); up(&adapter->erp_ready_sem); - zfcp_rec_dbf_event_thread_lock("erthrk1", adapter); + zfcp_dbf_rec_thread_lock("erthrk1", adapter->dbf); wait_event(adapter->erp_thread_wqh, !(atomic_read(&adapter->status) & @@ -1431,11 +1430,11 @@ void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id, if (set_or_clear == ZFCP_SET) { if (status_change_set(mask, &adapter->status)) - zfcp_rec_dbf_event_adapter(id, ref, adapter); + zfcp_dbf_rec_adapter(id, ref, adapter->dbf); atomic_set_mask(mask, &adapter->status); } else { if (status_change_clear(mask, &adapter->status)) - zfcp_rec_dbf_event_adapter(id, ref, adapter); + zfcp_dbf_rec_adapter(id, ref, adapter->dbf); atomic_clear_mask(mask, &adapter->status); if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) atomic_set(&adapter->erp_counter, 0); @@ -1465,11 +1464,11 @@ void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref, if (set_or_clear == ZFCP_SET) { if (status_change_set(mask, &port->status)) - zfcp_rec_dbf_event_port(id, ref, port); + zfcp_dbf_rec_port(id, ref, port); atomic_set_mask(mask, &port->status); } else { if (status_change_clear(mask, &port->status)) - zfcp_rec_dbf_event_port(id, ref, port); + zfcp_dbf_rec_port(id, ref, port); atomic_clear_mask(mask, &port->status); if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) atomic_set(&port->erp_counter, 0); @@ -1494,11 +1493,11 @@ void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref, { if (set_or_clear == ZFCP_SET) { if (status_change_set(mask, &unit->status)) - zfcp_rec_dbf_event_unit(id, ref, unit); + zfcp_dbf_rec_unit(id, ref, unit); atomic_set_mask(mask, &unit->status); } else { if (status_change_clear(mask, &unit->status)) - zfcp_rec_dbf_event_unit(id, ref, unit); + zfcp_dbf_rec_unit(id, ref, unit); atomic_clear_mask(mask, &unit->status); if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) { atomic_set(&unit->erp_counter, 0); diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 7650cec7f71..a49d00921b9 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -34,35 +34,31 @@ extern struct zfcp_adapter *zfcp_get_adapter_by_busid(char *); extern struct miscdevice zfcp_cfdc_misc; /* zfcp_dbf.c */ -extern int zfcp_adapter_debug_register(struct zfcp_adapter *); -extern void zfcp_adapter_debug_unregister(struct zfcp_adapter *); -extern void zfcp_rec_dbf_event_thread(char *, struct zfcp_adapter *); -extern void zfcp_rec_dbf_event_thread_lock(char *, struct zfcp_adapter *); -extern void zfcp_rec_dbf_event_adapter(char *, void *, struct zfcp_adapter *); -extern void zfcp_rec_dbf_event_port(char *, void *, struct zfcp_port *); -extern void zfcp_rec_dbf_event_unit(char *, void *, struct zfcp_unit *); -extern void zfcp_rec_dbf_event_trigger(char *, void *, u8, u8, void *, - struct zfcp_adapter *, - struct zfcp_port *, struct zfcp_unit *); -extern void zfcp_rec_dbf_event_action(char *, struct zfcp_erp_action *); -extern void _zfcp_hba_dbf_event_fsf_response(const char *, int level, - struct zfcp_fsf_req *, - struct zfcp_dbf *dbf); -extern void _zfcp_hba_dbf_event_fsf_unsol(const char *, int level, - struct zfcp_adapter *, +extern int zfcp_dbf_adapter_register(struct zfcp_adapter *); +extern void zfcp_dbf_adapter_unregister(struct zfcp_dbf *); +extern void zfcp_dbf_rec_thread(char *, struct zfcp_dbf *); +extern void zfcp_dbf_rec_thread_lock(char *, struct zfcp_dbf *); +extern void zfcp_dbf_rec_adapter(char *, void *, struct zfcp_dbf *); +extern void zfcp_dbf_rec_port(char *, void *, struct zfcp_port *); +extern void zfcp_dbf_rec_unit(char *, void *, struct zfcp_unit *); +extern void zfcp_dbf_rec_trigger(char *, void *, u8, u8, void *, + struct zfcp_adapter *, struct zfcp_port *, + struct zfcp_unit *); +extern void zfcp_dbf_rec_action(char *, struct zfcp_erp_action *); +extern void _zfcp_dbf_hba_fsf_response(const char *, int, struct zfcp_fsf_req *, + struct zfcp_dbf *); +extern void _zfcp_dbf_hba_fsf_unsol(const char *, int level, struct zfcp_dbf *, struct fsf_status_read_buffer *); -extern void zfcp_hba_dbf_event_qdio(struct zfcp_qdio *, unsigned int, int, - int); -extern void zfcp_hba_dbf_event_berr(struct zfcp_adapter *, - struct zfcp_fsf_req *); -extern void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *); -extern void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *); -extern void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *); -extern void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *); -extern void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *); -extern void _zfcp_scsi_dbf_event(const char *, const char *, int, - struct zfcp_dbf *, struct scsi_cmnd *, - struct zfcp_fsf_req *, unsigned long); +extern void zfcp_dbf_hba_qdio(struct zfcp_dbf *, unsigned int, int, int); +extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *); +extern void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *); +extern void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *); +extern void zfcp_dbf_san_els_request(struct zfcp_fsf_req *); +extern void zfcp_dbf_san_els_response(struct zfcp_fsf_req *); +extern void zfcp_dbf_san_incoming_els(struct zfcp_fsf_req *); +extern void _zfcp_dbf_scsi(const char *, const char *, int, struct zfcp_dbf *, + struct scsi_cmnd *, struct zfcp_fsf_req *, + unsigned long); /* zfcp_erp.c */ extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, char *, diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index bc0c9f54d0d..309f1dfad3f 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -242,7 +242,7 @@ void zfcp_fc_incoming_els(struct zfcp_fsf_req *fsf_req) (struct fsf_status_read_buffer *) fsf_req->data; unsigned int els_type = status_buffer->payload.data[0]; - zfcp_san_dbf_event_incoming_els(fsf_req); + zfcp_dbf_san_incoming_els(fsf_req); if (els_type == LS_PLOGI) zfcp_fc_incoming_plogi(fsf_req); else if (els_type == LS_LOGO) diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 048f1a848f3..665967f049a 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -248,13 +248,13 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) struct fsf_status_read_buffer *sr_buf = req->data; if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { - zfcp_hba_dbf_event_fsf_unsol("dism", adapter, sr_buf); + zfcp_dbf_hba_fsf_unsol("dism", adapter->dbf, sr_buf); mempool_free(sr_buf, adapter->pool.status_read_data); zfcp_fsf_req_free(req); return; } - zfcp_hba_dbf_event_fsf_unsol("read", adapter, sr_buf); + zfcp_dbf_hba_fsf_unsol("read", adapter->dbf, sr_buf); switch (sr_buf->status_type) { case FSF_STATUS_READ_PORT_CLOSED: @@ -269,7 +269,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) dev_warn(&adapter->ccw_device->dev, "The error threshold for checksum statistics " "has been exceeded\n"); - zfcp_hba_dbf_event_berr(adapter, req); + zfcp_dbf_hba_berr(adapter->dbf, req); break; case FSF_STATUS_READ_LINK_DOWN: zfcp_fsf_status_read_link_down(req); @@ -355,7 +355,7 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req) struct fsf_qtcb *qtcb = req->qtcb; union fsf_prot_status_qual *psq = &qtcb->prefix.prot_status_qual; - zfcp_hba_dbf_event_fsf_response(req); + zfcp_dbf_hba_fsf_response(req); if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { req->status |= ZFCP_STATUS_FSFREQ_ERROR | @@ -848,7 +848,7 @@ failed_req_send: mempool_free(sr_buf, adapter->pool.status_read_data); failed_buf: zfcp_fsf_req_free(req); - zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL); + zfcp_dbf_hba_fsf_unsol("fail", adapter->dbf, NULL); out: spin_unlock_bh(&qdio->req_q_lock); return retval; @@ -968,7 +968,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req) switch (header->fsf_status) { case FSF_GOOD: - zfcp_san_dbf_event_ct_response(req); + zfcp_dbf_san_ct_response(req); send_ct->status = 0; break; case FSF_SERVICE_CLASS_NOT_SUPPORTED: @@ -1100,7 +1100,7 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool) req->qtcb->bottom.support.timeout = ct->timeout; req->data = ct; - zfcp_san_dbf_event_ct_request(req); + zfcp_dbf_san_ct_request(req); zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); ret = zfcp_fsf_req_send(req); @@ -1129,7 +1129,7 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req) switch (header->fsf_status) { case FSF_GOOD: - zfcp_san_dbf_event_els_response(req); + zfcp_dbf_san_els_response(req); send_els->status = 0; break; case FSF_SERVICE_CLASS_NOT_SUPPORTED: @@ -1203,7 +1203,7 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els) bottom->timeout = 2 * R_A_TOV; req->data = els; - zfcp_san_dbf_event_els_request(req); + zfcp_dbf_san_els_request(req); zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); ret = zfcp_fsf_req_send(req); @@ -2213,11 +2213,11 @@ static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req) } skip_fsfstatus: if (scpnt->result != 0) - zfcp_scsi_dbf_event_result("erro", 3, req->adapter, scpnt, req); + zfcp_dbf_scsi_result("erro", 3, req->adapter->dbf, scpnt, req); else if (scpnt->retries > 0) - zfcp_scsi_dbf_event_result("retr", 4, req->adapter, scpnt, req); + zfcp_dbf_scsi_result("retr", 4, req->adapter->dbf, scpnt, req); else - zfcp_scsi_dbf_event_result("norm", 6, req->adapter, scpnt, req); + zfcp_dbf_scsi_result("norm", 6, req->adapter->dbf, scpnt, req); scpnt->host_scribble = NULL; (scpnt->scsi_done) (scpnt); diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 0b3f634509b..84527ebbbe5 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -101,7 +101,8 @@ static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err, struct zfcp_qdio_queue *queue = &qdio->req_q; if (unlikely(qdio_err)) { - zfcp_hba_dbf_event_qdio(qdio, qdio_err, first, count); + zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first, + count); zfcp_qdio_handler_error(qdio, "qdireq1"); return; } @@ -143,7 +144,8 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, int sbal_idx, sbal_no; if (unlikely(qdio_err)) { - zfcp_hba_dbf_event_qdio(qdio, qdio_err, first, count); + zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first, + count); zfcp_qdio_handler_error(qdio, "qdires1"); return; } diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 4414720c87f..b6177ad2d5b 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -53,11 +53,11 @@ static int zfcp_scsi_slave_configure(struct scsi_device *sdp) static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) { + struct zfcp_adapter *adapter = + (struct zfcp_adapter *) scpnt->device->host->hostdata[0]; set_host_byte(scpnt, result); if ((scpnt->device != NULL) && (scpnt->device->host != NULL)) - zfcp_scsi_dbf_event_result("fail", 4, - (struct zfcp_adapter*) scpnt->device->host->hostdata[0], - scpnt, NULL); + zfcp_dbf_scsi_result("fail", 4, adapter->dbf, scpnt, NULL); /* return directly */ scpnt->scsi_done(scpnt); } @@ -93,7 +93,7 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, scsi_result = fc_remote_port_chkready(rport); if (unlikely(scsi_result)) { scpnt->result = scsi_result; - zfcp_scsi_dbf_event_result("fail", 4, adapter, scpnt, NULL); + zfcp_dbf_scsi_result("fail", 4, adapter->dbf, scpnt, NULL); scpnt->scsi_done(scpnt); return 0; } @@ -181,8 +181,8 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) spin_unlock(&adapter->req_list_lock); if (!old_req) { write_unlock_irqrestore(&adapter->abort_lock, flags); - zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, - old_reqid); + zfcp_dbf_scsi_abort("lte1", adapter->dbf, scpnt, NULL, + old_reqid); return FAILED; /* completion could be in progress */ } old_req->data = NULL; @@ -198,8 +198,8 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) zfcp_erp_wait(adapter); if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_RUNNING)) { - zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL, - old_reqid); + zfcp_dbf_scsi_abort("nres", adapter->dbf, scpnt, NULL, + old_reqid); return SUCCESS; } } @@ -216,7 +216,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) dbf_tag = "fail"; retval = FAILED; } - zfcp_scsi_dbf_event_abort(dbf_tag, adapter, scpnt, abrt_req, old_reqid); + zfcp_dbf_scsi_abort(dbf_tag, adapter->dbf, scpnt, abrt_req, old_reqid); zfcp_fsf_req_free(abrt_req); return retval; } @@ -237,8 +237,7 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) zfcp_erp_wait(adapter); if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_RUNNING)) { - zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit, - scpnt); + zfcp_dbf_scsi_devreset("nres", tm_flags, unit, scpnt); return SUCCESS; } } @@ -248,13 +247,13 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) wait_for_completion(&fsf_req->completion); if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { - zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt); + zfcp_dbf_scsi_devreset("fail", tm_flags, unit, scpnt); retval = FAILED; } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP) { - zfcp_scsi_dbf_event_devreset("nsup", tm_flags, unit, scpnt); + zfcp_dbf_scsi_devreset("nsup", tm_flags, unit, scpnt); retval = FAILED; } else - zfcp_scsi_dbf_event_devreset("okay", tm_flags, unit, scpnt); + zfcp_dbf_scsi_devreset("okay", tm_flags, unit, scpnt); zfcp_fsf_req_free(fsf_req); return retval; -- cgit v1.2.3-18-g5258 From d5a282a1c5084ec7ebd9e6ab9723317f6b3fcd7b Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 18 Aug 2009 15:43:22 +0200 Subject: [SCSI] zfcp: introduce _setup, _destroy for qdio and FC Extract independent data structures and introduce common _setup and _destroy routines for QDIO and Fibre Channel related data structures Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 42 +++++++++----------------- drivers/s390/scsi/zfcp_ext.h | 7 +++-- drivers/s390/scsi/zfcp_fc.c | 36 ++++++++++++++++------- drivers/s390/scsi/zfcp_qdio.c | 68 +++++++++++++++++++++++++++++-------------- 4 files changed, 89 insertions(+), 64 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 7a50f64c36b..c77686ed938 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -506,30 +506,18 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) if (!adapter) return -ENOMEM; - adapter->gs = kzalloc(sizeof(struct zfcp_wka_ports), GFP_KERNEL); - if (!adapter->gs) { - kfree(adapter); - return -ENOMEM; - } - - adapter->qdio = kzalloc(sizeof(struct zfcp_qdio), GFP_KERNEL); - if (!adapter->qdio) - goto qdio_mem_failed; - - adapter->qdio->adapter = adapter; - ccw_device->handler = NULL; adapter->ccw_device = ccw_device; atomic_set(&adapter->refcount, 0); - if (zfcp_qdio_allocate(adapter->qdio, ccw_device)) - goto qdio_allocate_failed; + if (zfcp_qdio_setup(adapter)) + goto qdio_failed; if (zfcp_allocate_low_mem_buffers(adapter)) - goto failed_low_mem_buffers; + goto low_mem_buffers_failed; if (zfcp_reqlist_alloc(adapter)) - goto failed_low_mem_buffers; + goto low_mem_buffers_failed; if (zfcp_dbf_adapter_register(adapter)) goto debug_register_failed; @@ -537,6 +525,9 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) if (zfcp_setup_adapter_work_queue(adapter)) goto work_queue_failed; + if (zfcp_fc_gs_setup(adapter)) + goto generic_services_failed; + init_waitqueue_head(&adapter->remove_wq); init_waitqueue_head(&adapter->erp_thread_wqh); init_waitqueue_head(&adapter->erp_done_wqh); @@ -547,9 +538,6 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) spin_lock_init(&adapter->req_list_lock); - spin_lock_init(&adapter->qdio->req_q_lock); - spin_lock_init(&adapter->qdio->stat_lock); - rwlock_init(&adapter->erp_lock); rwlock_init(&adapter->abort_lock); @@ -570,24 +558,23 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) goto sysfs_failed; atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); - zfcp_fc_wka_ports_init(adapter); if (!zfcp_adapter_scsi_register(adapter)) return 0; sysfs_failed: + zfcp_fc_gs_destroy(adapter); +generic_services_failed: zfcp_destroy_adapter_work_queue(adapter); work_queue_failed: zfcp_dbf_adapter_unregister(adapter->dbf); debug_register_failed: dev_set_drvdata(&ccw_device->dev, NULL); kfree(adapter->req_list); -failed_low_mem_buffers: +low_mem_buffers_failed: zfcp_free_low_mem_buffers(adapter); -qdio_allocate_failed: - zfcp_qdio_free(adapter->qdio); - kfree(adapter->qdio); -qdio_mem_failed: +qdio_failed: + zfcp_qdio_destroy(adapter->qdio); kfree(adapter); return -ENOMEM; } @@ -616,15 +603,14 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) if (!retval) return; + zfcp_fc_gs_destroy(adapter); zfcp_destroy_adapter_work_queue(adapter); zfcp_dbf_adapter_unregister(adapter->dbf); - zfcp_qdio_free(adapter->qdio); zfcp_free_low_mem_buffers(adapter); + zfcp_qdio_destroy(adapter->qdio); kfree(adapter->req_list); kfree(adapter->fc_stats); kfree(adapter->stats_reset_data); - kfree(adapter->gs); - kfree(adapter->qdio); kfree(adapter); } diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index a49d00921b9..cf09b2838c5 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -100,7 +100,8 @@ extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); extern void zfcp_test_link(struct zfcp_port *); extern void zfcp_fc_link_test_work(struct work_struct *); extern void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *); -extern void zfcp_fc_wka_ports_init(struct zfcp_adapter *); +extern int zfcp_fc_gs_setup(struct zfcp_adapter *); +extern void zfcp_fc_gs_destroy(struct zfcp_adapter *); extern int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *); extern int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *); @@ -134,8 +135,8 @@ extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long, extern void zfcp_fsf_reqid_check(struct zfcp_qdio *, int); /* zfcp_qdio.c */ -extern int zfcp_qdio_allocate(struct zfcp_qdio *, struct ccw_device *); -extern void zfcp_qdio_free(struct zfcp_qdio *); +extern int zfcp_qdio_setup(struct zfcp_adapter *); +extern void zfcp_qdio_destroy(struct zfcp_qdio *); extern int zfcp_qdio_send(struct zfcp_qdio *, struct zfcp_queue_req *); extern struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_qdio *, struct zfcp_queue_req *); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 309f1dfad3f..db8bb41a779 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -141,17 +141,6 @@ void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *gs) zfcp_fc_wka_port_force_offline(&gs->ks); } -void zfcp_fc_wka_ports_init(struct zfcp_adapter *adapter) -{ - struct zfcp_wka_ports *gs = adapter->gs; - - zfcp_fc_wka_port_init(&gs->ms, FC_FID_MGMT_SERV, adapter); - zfcp_fc_wka_port_init(&gs->ts, FC_FID_TIME_SERV, adapter); - zfcp_fc_wka_port_init(&gs->ds, FC_FID_DIR_SERV, adapter); - zfcp_fc_wka_port_init(&gs->as, FC_FID_ALIASES, adapter); - zfcp_fc_wka_port_init(&gs->ks, FC_FID_SEC_KEY, adapter); -} - static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, struct fcp_rscn_element *elem) { @@ -870,3 +859,28 @@ int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *job) } return ret; } + +int zfcp_fc_gs_setup(struct zfcp_adapter *adapter) +{ + struct zfcp_wka_ports *wka_ports; + + wka_ports = kzalloc(sizeof(struct zfcp_wka_ports), GFP_KERNEL); + if (!wka_ports) + return -ENOMEM; + + adapter->gs = wka_ports; + zfcp_fc_wka_port_init(&wka_ports->ms, FC_FID_MGMT_SERV, adapter); + zfcp_fc_wka_port_init(&wka_ports->ts, FC_FID_TIME_SERV, adapter); + zfcp_fc_wka_port_init(&wka_ports->ds, FC_FID_DIR_SERV, adapter); + zfcp_fc_wka_port_init(&wka_ports->as, FC_FID_ALIASES, adapter); + zfcp_fc_wka_port_init(&wka_ports->ks, FC_FID_SEC_KEY, adapter); + + return 0; +} + +void zfcp_fc_gs_destroy(struct zfcp_adapter *adapter) +{ + kfree(adapter->gs); + adapter->gs = NULL; +} + diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 84527ebbbe5..2b499e28ff1 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -34,27 +34,6 @@ zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx) return &q->sbal[sbal_idx]->element[sbale_idx]; } -/** - * zfcp_qdio_free - free memory used by request- and resposne queue - * @qdio: pointer to the zfcp_qdio structure - */ -void zfcp_qdio_free(struct zfcp_qdio *qdio) -{ - struct qdio_buffer **sbal_req, **sbal_resp; - int p; - - if (qdio->adapter->ccw_device) - qdio_free(qdio->adapter->ccw_device); - - sbal_req = qdio->req_q.sbal; - sbal_resp = qdio->resp_q.sbal; - - for (p = 0; p < QDIO_MAX_BUFFERS_PER_Q; p += QBUFF_PER_PAGE) { - free_page((unsigned long) sbal_req[p]); - free_page((unsigned long) sbal_resp[p]); - } -} - static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id) { struct zfcp_adapter *adapter = qdio->adapter; @@ -383,7 +362,7 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id, * Returns: -ENOMEM on memory allocation error or return value from * qdio_allocate */ -int zfcp_qdio_allocate(struct zfcp_qdio *qdio, struct ccw_device *ccw_dev) +static int zfcp_qdio_allocate(struct zfcp_qdio *qdio) { struct qdio_initialize init_data; @@ -477,3 +456,48 @@ failed_establish: "Setting up the QDIO connection to the FCP adapter failed\n"); return -EIO; } + +void zfcp_qdio_destroy(struct zfcp_qdio *qdio) +{ + struct qdio_buffer **sbal_req, **sbal_resp; + int p; + + if (!qdio) + return; + + if (qdio->adapter->ccw_device) + qdio_free(qdio->adapter->ccw_device); + + sbal_req = qdio->req_q.sbal; + sbal_resp = qdio->resp_q.sbal; + + for (p = 0; p < QDIO_MAX_BUFFERS_PER_Q; p += QBUFF_PER_PAGE) { + free_page((unsigned long) sbal_req[p]); + free_page((unsigned long) sbal_resp[p]); + } + + kfree(qdio); +} + +int zfcp_qdio_setup(struct zfcp_adapter *adapter) +{ + struct zfcp_qdio *qdio; + + qdio = kzalloc(sizeof(struct zfcp_qdio), GFP_KERNEL); + if (!qdio) + return -ENOMEM; + + qdio->adapter = adapter; + + if (zfcp_qdio_allocate(qdio)) { + zfcp_qdio_destroy(qdio); + return -ENOMEM; + } + + spin_lock_init(&qdio->req_q_lock); + spin_lock_init(&qdio->stat_lock); + + adapter->qdio = qdio; + return 0; +} + -- cgit v1.2.3-18-g5258 From 6f53a2d2ecaefa3ffff8864f51a3ae38737e1152 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 18 Aug 2009 15:43:23 +0200 Subject: [SCSI] zfcp: Apply common naming conventions to zfcp_fc Update the Fibre Channel related code to use the zfcp_fc prefix. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 2 +- drivers/s390/scsi/zfcp_ext.h | 6 ++--- drivers/s390/scsi/zfcp_fc.c | 51 +++++++++++++++++++++--------------------- drivers/s390/scsi/zfcp_fsf.c | 10 ++++----- drivers/s390/scsi/zfcp_sysfs.c | 2 +- 5 files changed, 35 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index c77686ed938..23b85a03e26 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -544,7 +544,7 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) sema_init(&adapter->erp_ready_sem, 0); INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); - INIT_WORK(&adapter->scan_work, _zfcp_scan_ports_later); + INIT_WORK(&adapter->scan_work, _zfcp_fc_scan_ports_later); adapter->service_level.seq_print = zfcp_print_sl; diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index cf09b2838c5..36935bc0818 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -92,12 +92,12 @@ extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, char *, extern void zfcp_erp_timeout_handler(unsigned long); /* zfcp_fc.c */ -extern int zfcp_scan_ports(struct zfcp_adapter *); -extern void _zfcp_scan_ports_later(struct work_struct *); +extern int zfcp_fc_scan_ports(struct zfcp_adapter *); +extern void _zfcp_fc_scan_ports_later(struct work_struct *); extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *); extern void zfcp_fc_port_did_lookup(struct work_struct *); extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); -extern void zfcp_test_link(struct zfcp_port *); +extern void zfcp_fc_test_link(struct zfcp_port *); extern void zfcp_fc_link_test_work(struct work_struct *); extern void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *); extern int zfcp_fc_gs_setup(struct zfcp_adapter *); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index db8bb41a779..7433da900fa 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -57,7 +57,7 @@ struct zfcp_fc_ns_handler_data { unsigned long handler_data; }; -static int zfcp_wka_port_get(struct zfcp_wka_port *wka_port) +static int zfcp_fc_wka_port_get(struct zfcp_wka_port *wka_port) { if (mutex_lock_interruptible(&wka_port->mutex)) return -ERESTARTSYS; @@ -82,7 +82,7 @@ static int zfcp_wka_port_get(struct zfcp_wka_port *wka_port) return -EIO; } -static void zfcp_wka_port_offline(struct work_struct *work) +static void zfcp_fc_wka_port_offline(struct work_struct *work) { struct delayed_work *dw = to_delayed_work(work); struct zfcp_wka_port *wka_port = @@ -102,7 +102,7 @@ out: mutex_unlock(&wka_port->mutex); } -static void zfcp_wka_port_put(struct zfcp_wka_port *wka_port) +static void zfcp_fc_wka_port_put(struct zfcp_wka_port *wka_port) { if (atomic_dec_return(&wka_port->refcount) != 0) return; @@ -121,7 +121,7 @@ static void zfcp_fc_wka_port_init(struct zfcp_wka_port *wka_port, u32 d_id, wka_port->status = ZFCP_WKA_PORT_OFFLINE; atomic_set(&wka_port->refcount, 0); mutex_init(&wka_port->mutex); - INIT_DELAYED_WORK(&wka_port->work, zfcp_wka_port_offline); + INIT_DELAYED_WORK(&wka_port->work, zfcp_fc_wka_port_offline); } static void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *wka) @@ -150,7 +150,7 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, read_lock_irqsave(&zfcp_data.config_lock, flags); list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) { if ((port->d_id & range) == (elem->nport_did & range)) - zfcp_test_link(port); + zfcp_fc_test_link(port); if (!port->d_id) zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, @@ -326,13 +326,13 @@ static int zfcp_fc_ns_gid_pn(struct zfcp_port *port) memset(gid_pn, 0, sizeof(*gid_pn)); - ret = zfcp_wka_port_get(&adapter->gs->ds); + ret = zfcp_fc_wka_port_get(&adapter->gs->ds); if (ret) goto out; ret = zfcp_fc_ns_gid_pn_request(port, gid_pn); - zfcp_wka_port_put(&adapter->gs->ds); + zfcp_fc_wka_port_put(&adapter->gs->ds); out: mempool_free(gid_pn, adapter->pool.gid_pn_data); return ret; @@ -482,14 +482,14 @@ out: } /** - * zfcp_test_link - lightweight link test procedure + * zfcp_fc_test_link - lightweight link test procedure * @port: port to be tested * * Test status of a link to a remote port using the ELS command ADISC. * If there is a problem with the remote port, error recovery steps * will be triggered. */ -void zfcp_test_link(struct zfcp_port *port) +void zfcp_fc_test_link(struct zfcp_port *port) { zfcp_port_get(port); if (!queue_work(port->adapter->work_queue, &port->test_link_work)) @@ -532,9 +532,8 @@ out: } -static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, - struct zfcp_adapter *adapter, - int max_bytes) +static int zfcp_fc_send_gpn_ft(struct zfcp_gpn_ft *gpn_ft, + struct zfcp_adapter *adapter, int max_bytes) { struct zfcp_send_ct *ct = &gpn_ft->ct; struct ct_iu_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req); @@ -569,7 +568,7 @@ static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, return ret; } -static void zfcp_validate_port(struct zfcp_port *port) +static void zfcp_fc_validate_port(struct zfcp_port *port) { struct zfcp_adapter *adapter = port->adapter; @@ -589,7 +588,7 @@ static void zfcp_validate_port(struct zfcp_port *port) zfcp_port_dequeue(port); } -static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) +static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) { struct zfcp_send_ct *ct = &gpn_ft->ct; struct scatterlist *sg = gpn_ft->sg_resp; @@ -649,16 +648,16 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) zfcp_erp_wait(adapter); list_for_each_entry_safe(port, tmp, &adapter->port_list_head, list) - zfcp_validate_port(port); + zfcp_fc_validate_port(port); up(&zfcp_data.config_sema); return ret; } /** - * zfcp_scan_ports - scan remote ports and attach new ports + * zfcp_fc_scan_ports - scan remote ports and attach new ports * @adapter: pointer to struct zfcp_adapter */ -int zfcp_scan_ports(struct zfcp_adapter *adapter) +int zfcp_fc_scan_ports(struct zfcp_adapter *adapter) { int ret, i; struct zfcp_gpn_ft *gpn_ft; @@ -673,7 +672,7 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV) return 0; - ret = zfcp_wka_port_get(&adapter->gs->ds); + ret = zfcp_fc_wka_port_get(&adapter->gs->ds); if (ret) return ret; @@ -684,9 +683,9 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) } for (i = 0; i < 3; i++) { - ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter, max_bytes); + ret = zfcp_fc_send_gpn_ft(gpn_ft, adapter, max_bytes); if (!ret) { - ret = zfcp_scan_eval_gpn_ft(gpn_ft, max_entries); + ret = zfcp_fc_eval_gpn_ft(gpn_ft, max_entries); if (ret == -EAGAIN) ssleep(1); else @@ -695,14 +694,14 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) } zfcp_free_sg_env(gpn_ft, buf_num); out: - zfcp_wka_port_put(&adapter->gs->ds); + zfcp_fc_wka_port_put(&adapter->gs->ds); return ret; } -void _zfcp_scan_ports_later(struct work_struct *work) +void _zfcp_fc_scan_ports_later(struct work_struct *work) { - zfcp_scan_ports(container_of(work, struct zfcp_adapter, scan_work)); + zfcp_fc_scan_ports(container_of(work, struct zfcp_adapter, scan_work)); } struct zfcp_els_fc_job { @@ -792,7 +791,7 @@ static void zfcp_fc_generic_ct_handler(unsigned long data) job->state_flags = FC_RQST_STATE_DONE; job->job_done(job); - zfcp_wka_port_put(ct_fc_job->ct.wka_port); + zfcp_fc_wka_port_put(ct_fc_job->ct.wka_port); kfree(ct_fc_job); } @@ -838,7 +837,7 @@ int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *job) return -EINVAL; /* no such service */ } - ret = zfcp_wka_port_get(ct_fc_job->ct.wka_port); + ret = zfcp_fc_wka_port_get(ct_fc_job->ct.wka_port); if (ret) { kfree(ct_fc_job); return ret; @@ -855,7 +854,7 @@ int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *job) ret = zfcp_fsf_send_ct(&ct_fc_job->ct, NULL); if (ret) { kfree(ct_fc_job); - zfcp_wka_port_put(ct_fc_job->ct.wka_port); + zfcp_fc_wka_port_put(ct_fc_job->ct.wka_port); } return ret; } diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 665967f049a..c241f032fd4 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -892,7 +892,7 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) case FSF_ADAPTER_STATUS_AVAILABLE: switch (fsq->word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - zfcp_test_link(unit->port); + zfcp_fc_test_link(unit->port); /* fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -1139,7 +1139,7 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req) switch (header->fsf_status_qual.word[0]){ case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: if (port && (send_els->ls_code != ZFCP_LS_ADISC)) - zfcp_test_link(port); + zfcp_fc_test_link(port); /*fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: case FSF_SQ_RETRY_IF_POSSIBLE: @@ -1889,7 +1889,7 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req) case FSF_ADAPTER_STATUS_AVAILABLE: switch (header->fsf_status_qual.word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - zfcp_test_link(unit->port); + zfcp_fc_test_link(unit->port); /* fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -2024,7 +2024,7 @@ static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req) case FSF_ADAPTER_STATUS_AVAILABLE: switch (req->qtcb->header.fsf_status_qual.word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - zfcp_test_link(unit->port); + zfcp_fc_test_link(unit->port); /* fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -2307,7 +2307,7 @@ static void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req) case FSF_ADAPTER_STATUS_AVAILABLE: if (header->fsf_status_qual.word[0] == FSF_SQ_INVOKE_LINK_TEST_PROCEDURE) - zfcp_test_link(unit->port); + zfcp_fc_test_link(unit->port); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; } diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index a6cf6263683..c86496bb608 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -126,7 +126,7 @@ static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev, if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) return -EBUSY; - ret = zfcp_scan_ports(adapter); + ret = zfcp_fc_scan_ports(adapter); return ret ? ret : (ssize_t) count; } static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL, -- cgit v1.2.3-18-g5258 From ea945ff84c2ce1089edb7914ffdd998c24c25903 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Tue, 18 Aug 2009 15:43:24 +0200 Subject: [SCSI] zfcp: resolve false usage of dd_data in fc_rport The fc_rport structure reserves a reference where a LLD can put information required in a situation where the fc transport class is triggering LLD callbacks. The zfcp driver was using this variable directly which is discouraged. This patch solves this issue by making this reference unnecessary. In addition the dev_loss_tmo callback is removed, it is not required: zfcp does not access the fc_rport after calling fc_remote_port_delete. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 4 ---- drivers/s390/scsi/zfcp_fc.c | 2 +- drivers/s390/scsi/zfcp_scsi.c | 22 ++++------------------ 3 files changed, 5 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 23b85a03e26..ed9a8a1517c 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -709,10 +709,6 @@ void zfcp_port_dequeue(struct zfcp_port *port) write_lock_irq(&zfcp_data.config_lock); list_del(&port->list); write_unlock_irq(&zfcp_data.config_lock); - if (port->rport) { - port->rport->dd_data = NULL; - port->rport = NULL; - } wait_event(port->remove_wq, atomic_read(&port->refcount) == 0); cancel_work_sync(&port->rport_work); /* usually not necessary */ zfcp_adapter_put(port->adapter); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 7433da900fa..5c1f12247e4 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -752,7 +752,7 @@ int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *job) els_fc_job->els.adapter = adapter; if (rport) { read_lock_irq(&zfcp_data.config_lock); - port = rport->dd_data; + port = zfcp_get_port_by_wwpn(adapter, rport->port_name); if (port) els_fc_job->els.d_id = port->d_id; read_unlock_irq(&zfcp_data.config_lock); diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index b6177ad2d5b..3ff726afafc 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -490,21 +490,6 @@ static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) rport->dev_loss_tmo = timeout; } -/** - * zfcp_scsi_dev_loss_tmo_callbk - Free any reference to rport - * @rport: The rport that is about to be deleted. - */ -static void zfcp_scsi_dev_loss_tmo_callbk(struct fc_rport *rport) -{ - struct zfcp_port *port; - - write_lock_irq(&zfcp_data.config_lock); - port = rport->dd_data; - if (port) - port->rport = NULL; - write_unlock_irq(&zfcp_data.config_lock); -} - /** * zfcp_scsi_terminate_rport_io - Terminate all I/O on a rport * @rport: The FC rport where to teminate I/O @@ -516,9 +501,12 @@ static void zfcp_scsi_dev_loss_tmo_callbk(struct fc_rport *rport) static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) { struct zfcp_port *port; + struct Scsi_Host *shost = rport_to_shost(rport); + struct zfcp_adapter *adapter = + (struct zfcp_adapter *)shost->hostdata[0]; write_lock_irq(&zfcp_data.config_lock); - port = rport->dd_data; + port = zfcp_get_port_by_wwpn(adapter, rport->port_name); if (port) zfcp_port_get(port); write_unlock_irq(&zfcp_data.config_lock); @@ -550,7 +538,6 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port) return; } - rport->dd_data = port; rport->maxframe_size = port->maxframe_size; rport->supported_classes = port->supported_classes; port->rport = rport; @@ -663,7 +650,6 @@ struct fc_function_template zfcp_transport_functions = { .reset_fc_host_stats = zfcp_reset_fc_host_stats, .set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo, .get_host_port_state = zfcp_get_host_port_state, - .dev_loss_tmo_callbk = zfcp_scsi_dev_loss_tmo_callbk, .terminate_rport_io = zfcp_scsi_terminate_rport_io, .show_host_port_state = 1, .bsg_request = zfcp_execute_fc_job, -- cgit v1.2.3-18-g5258 From 347c6a965dc110c91a77f65181fc011ee257a4a6 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 18 Aug 2009 15:43:25 +0200 Subject: [SCSI] zfcp: Use kthread API for zfcp erp thread Switch the creation of the zfcp erp thread from the deprecated kernel_thread API to the kthread API. This allows also the removal of some flags in zfcp since the kthread API handles thread creation and shutdown internally. To allow the usage of the kthread_stop function, replace the erp ready semaphore with a waitqueue for waiting until erp actions arrive on the ready queue. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 4 +-- drivers/s390/scsi/zfcp_def.h | 6 ++--- drivers/s390/scsi/zfcp_erp.c | 62 +++++++++++++++++--------------------------- 3 files changed, 27 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index ed9a8a1517c..e8f39f02bc3 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -529,7 +529,7 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) goto generic_services_failed; init_waitqueue_head(&adapter->remove_wq); - init_waitqueue_head(&adapter->erp_thread_wqh); + init_waitqueue_head(&adapter->erp_ready_wq); init_waitqueue_head(&adapter->erp_done_wqh); INIT_LIST_HEAD(&adapter->port_list_head); @@ -541,8 +541,6 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) rwlock_init(&adapter->erp_lock); rwlock_init(&adapter->abort_lock); - sema_init(&adapter->erp_ready_sem, 0); - INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); INIT_WORK(&adapter->scan_work, _zfcp_fc_scan_ports_later); diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 9a8ff055342..ce65d88e280 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -222,8 +222,6 @@ struct zfcp_ls_adisc { #define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002 #define ZFCP_STATUS_ADAPTER_XCONFIG_OK 0x00000008 #define ZFCP_STATUS_ADAPTER_HOST_CON_INIT 0x00000010 -#define ZFCP_STATUS_ADAPTER_ERP_THREAD_UP 0x00000020 -#define ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL 0x00000080 #define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100 #define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200 @@ -481,10 +479,9 @@ struct zfcp_adapter { atomic_t status; /* status of this adapter */ struct list_head erp_ready_head; /* error recovery for this adapter/devices */ + wait_queue_head_t erp_ready_wq; struct list_head erp_running_head; rwlock_t erp_lock; - struct semaphore erp_ready_sem; - wait_queue_head_t erp_thread_wqh; wait_queue_head_t erp_done_wqh; struct zfcp_erp_action erp_action; /* pending error recovery */ atomic_t erp_counter; @@ -492,6 +489,7 @@ struct zfcp_adapter { actions */ u32 erp_low_mem_count; /* nr of erp actions waiting for memory */ + struct task_struct *erp_thread; struct zfcp_wka_ports *gs; /* generic services */ struct zfcp_dbf *dbf; /* debug traces */ struct zfcp_adapter_mempool pool; /* Adapter memory pools */ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 373567eda8f..577e1570859 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -9,6 +9,7 @@ #define KMSG_COMPONENT "zfcp" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include #include "zfcp_ext.h" #define ZFCP_MAX_ERPS 3 @@ -75,7 +76,7 @@ static void zfcp_erp_action_ready(struct zfcp_erp_action *act) list_move(&act->list, &act->adapter->erp_ready_head); zfcp_dbf_rec_action("erardy1", act); - up(&adapter->erp_ready_sem); + wake_up(&adapter->erp_ready_wq); zfcp_dbf_rec_thread("erardy2", adapter->dbf); } @@ -212,8 +213,7 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, int retval = 1, need; struct zfcp_erp_action *act = NULL; - if (!(atomic_read(&adapter->status) & - ZFCP_STATUS_ADAPTER_ERP_THREAD_UP)) + if (!adapter->erp_thread) return -EIO; need = zfcp_erp_required_act(want, adapter, port, unit); @@ -226,7 +226,7 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, goto out; ++adapter->erp_total_count; list_add_tail(&act->list, &adapter->erp_ready_head); - up(&adapter->erp_ready_sem); + wake_up(&adapter->erp_ready_wq); zfcp_dbf_rec_thread("eracte1", adapter->dbf); retval = 0; out: @@ -641,7 +641,8 @@ static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action) } zfcp_dbf_rec_thread_lock("erasfx1", adapter->dbf); - down(&adapter->erp_ready_sem); + wait_event(adapter->erp_ready_wq, + !list_empty(&adapter->erp_ready_head)); zfcp_dbf_rec_thread_lock("erasfx2", adapter->dbf); if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) break; @@ -682,7 +683,8 @@ static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act) return ZFCP_ERP_FAILED; zfcp_dbf_rec_thread_lock("erasox1", adapter->dbf); - down(&adapter->erp_ready_sem); + wait_event(adapter->erp_ready_wq, + !list_empty(&adapter->erp_ready_head)); zfcp_dbf_rec_thread_lock("erasox2", adapter->dbf); if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) return ZFCP_ERP_FAILED; @@ -1285,21 +1287,17 @@ static int zfcp_erp_thread(void *data) struct list_head *next; struct zfcp_erp_action *act; unsigned long flags; - int ignore; - - daemonize("zfcperp%s", dev_name(&adapter->ccw_device->dev)); - /* Block all signals */ - siginitsetinv(¤t->blocked, 0); - atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); - wake_up(&adapter->erp_thread_wqh); - - while (!(atomic_read(&adapter->status) & - ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL)) { + for (;;) { zfcp_dbf_rec_thread_lock("erthrd1", adapter->dbf); - ignore = down_interruptible(&adapter->erp_ready_sem); + wait_event_interruptible(adapter->erp_ready_wq, + !list_empty(&adapter->erp_ready_head) || + kthread_should_stop()); zfcp_dbf_rec_thread_lock("erthrd2", adapter->dbf); + if (kthread_should_stop()) + break; + write_lock_irqsave(&adapter->erp_lock, flags); next = adapter->erp_ready_head.next; write_unlock_irqrestore(&adapter->erp_lock, flags); @@ -1313,9 +1311,6 @@ static int zfcp_erp_thread(void *data) } } - atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); - wake_up(&adapter->erp_thread_wqh); - return 0; } @@ -1327,18 +1322,17 @@ static int zfcp_erp_thread(void *data) */ int zfcp_erp_thread_setup(struct zfcp_adapter *adapter) { - int retval; + struct task_struct *thread; - atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); - retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD); - if (retval < 0) { + thread = kthread_run(zfcp_erp_thread, adapter, "zfcperp%s", + dev_name(&adapter->ccw_device->dev)); + if (IS_ERR(thread)) { dev_err(&adapter->ccw_device->dev, "Creating an ERP thread for the FCP device failed.\n"); - return retval; + return PTR_ERR(thread); } - wait_event(adapter->erp_thread_wqh, - atomic_read(&adapter->status) & - ZFCP_STATUS_ADAPTER_ERP_THREAD_UP); + + adapter->erp_thread = thread; return 0; } @@ -1353,16 +1347,8 @@ int zfcp_erp_thread_setup(struct zfcp_adapter *adapter) */ void zfcp_erp_thread_kill(struct zfcp_adapter *adapter) { - atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status); - up(&adapter->erp_ready_sem); - zfcp_dbf_rec_thread_lock("erthrk1", adapter->dbf); - - wait_event(adapter->erp_thread_wqh, - !(atomic_read(&adapter->status) & - ZFCP_STATUS_ADAPTER_ERP_THREAD_UP)); - - atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, - &adapter->status); + kthread_stop(adapter->erp_thread); + adapter->erp_thread = NULL; } /** -- cgit v1.2.3-18-g5258 From 98fc4d5c8cd9bd1a412cca922feecb54c1c22d8e Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 18 Aug 2009 15:43:26 +0200 Subject: [SCSI] zfcp: Simplify and update ct/gs and els timeout handling The recommendation for a timeout of 2 * R_A_TOV is the same for ct/gs and els requests, so set it in the common function used for initializing both request types. Besides, the timer inside zfcp should only run longer than the timeout set for the channel, so 10 seconds more should be enough (instead of 60 seconds). Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_def.h | 5 ----- drivers/s390/scsi/zfcp_fc.c | 3 --- drivers/s390/scsi/zfcp_fsf.c | 15 ++++++--------- 3 files changed, 6 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index ce65d88e280..99830758e87 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -73,9 +73,6 @@ /*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/ -/* timeout for name-server lookup (in seconds) */ -#define ZFCP_NS_GID_PN_TIMEOUT 10 - /* task attribute values in FCP-2 FCP_CMND IU */ #define SIMPLE_Q 0 #define HEAD_OF_Q 1 @@ -319,7 +316,6 @@ struct ct_iu_gpn_ft_req { * @resp: scatter-gather list for response * @handler: handler function (called for response to the request) * @handler_data: data passed to handler function - * @timeout: FSF timeout for this request * @completion: completion for synchronization purposes * @status: used to pass error status to calling function */ @@ -329,7 +325,6 @@ struct zfcp_send_ct { struct scatterlist *resp; void (*handler)(unsigned long); unsigned long handler_data; - int timeout; struct completion *completion; int status; }; diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 5c1f12247e4..82f148d0996 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -283,7 +283,6 @@ static int zfcp_fc_ns_gid_pn_request(struct zfcp_port *port, gid_pn->ct.wka_port = &adapter->gs->ds; gid_pn->ct.handler = zfcp_fc_ns_handler; gid_pn->ct.handler_data = (unsigned long) &compl_rec; - gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; gid_pn->ct.req = &gid_pn->req; gid_pn->ct.resp = &gid_pn->resp; sg_init_one(&gid_pn->req, &gid_pn->ct_iu_req, @@ -556,7 +555,6 @@ static int zfcp_fc_send_gpn_ft(struct zfcp_gpn_ft *gpn_ft, ct->wka_port = &adapter->gs->ds; ct->handler = zfcp_fc_ns_handler; ct->handler_data = (unsigned long)&compl_rec; - ct->timeout = 10; ct->req = &gpn_ft->sg_req; ct->resp = gpn_ft->sg_resp; @@ -845,7 +843,6 @@ int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *job) ct_fc_job->ct.req = job->request_payload.sg_list; ct_fc_job->ct.resp = job->reply_payload.sg_list; - ct_fc_job->ct.timeout = ZFCP_FSF_REQUEST_TIMEOUT; ct_fc_job->ct.handler = zfcp_fc_generic_ct_handler; ct_fc_job->ct.handler_data = (unsigned long) ct_fc_job; ct_fc_job->ct.completion = NULL; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index c241f032fd4..f09c863dc6b 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -1060,7 +1060,12 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, sg_resp, max_sbals); if (bytes <= 0) return -EIO; + + /* common settings for ct/gs and els requests */ req->qtcb->bottom.support.resp_buf_length = bytes; + req->qtcb->bottom.support.service_class = FSF_CLASS_3; + req->qtcb->bottom.support.timeout = 2 * R_A_TOV; + zfcp_fsf_start_timer(req, 2 * R_A_TOV + 10); return 0; } @@ -1096,12 +1101,9 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool) req->handler = zfcp_fsf_send_ct_handler; req->qtcb->header.port_handle = wka_port->handle; - req->qtcb->bottom.support.service_class = FSF_CLASS_3; - req->qtcb->bottom.support.timeout = ct->timeout; req->data = ct; zfcp_dbf_san_ct_request(req); - zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); ret = zfcp_fsf_req_send(req); if (ret) @@ -1176,7 +1178,6 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els) { struct zfcp_fsf_req *req; struct zfcp_qdio *qdio = els->adapter->qdio; - struct fsf_qtcb_bottom_support *bottom; int ret = -EIO; spin_lock_bh(&qdio->req_q_lock); @@ -1196,16 +1197,12 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els) if (ret) goto failed_send; - bottom = &req->qtcb->bottom.support; + req->qtcb->bottom.support.d_id = els->d_id; req->handler = zfcp_fsf_send_els_handler; - bottom->d_id = els->d_id; - bottom->service_class = FSF_CLASS_3; - bottom->timeout = 2 * R_A_TOV; req->data = els; zfcp_dbf_san_els_request(req); - zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); ret = zfcp_fsf_req_send(req); if (ret) goto failed_send; -- cgit v1.2.3-18-g5258 From 143bb6bfe36d20618d8bf667915fe14d14b8ae2f Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 18 Aug 2009 15:43:27 +0200 Subject: [SCSI] zfcp: Defer resource allocation to first ccw_set_online call So far, zfcp allocated all resources required for FCP adapters/subchannels when the device was discovered in the ccw_probe callback. If there are lots of unused FCP subchannels attached to a system, this is a waste of resources. To alleviate this, defer the resource allocation to the first call to ccw_set_online. To avoid disruptions during possible following calls to ccw_set_offline and then ccw_set_online, keep the adapter resources until the device is finally being removed via ccw_remove. While doing this, also manage the zfcp erp thread together with all other adapter resources in zfcp_adapter_enqueue/dequeue. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 6 ++++ drivers/s390/scsi/zfcp_ccw.c | 74 +++++++++++++++++++++++++------------------- drivers/s390/scsi/zfcp_erp.c | 5 +++ 3 files changed, 54 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index e8f39f02bc3..d1e75d36ed1 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -541,6 +541,9 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) rwlock_init(&adapter->erp_lock); rwlock_init(&adapter->abort_lock); + if (zfcp_erp_thread_setup(adapter)) + goto erp_thread_failed; + INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); INIT_WORK(&adapter->scan_work, _zfcp_fc_scan_ports_later); @@ -561,6 +564,8 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) return 0; sysfs_failed: + zfcp_erp_thread_kill(adapter); +erp_thread_failed: zfcp_fc_gs_destroy(adapter); generic_services_failed: zfcp_destroy_adapter_work_queue(adapter); @@ -602,6 +607,7 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) return; zfcp_fc_gs_destroy(adapter); + zfcp_erp_thread_kill(adapter); zfcp_destroy_adapter_work_queue(adapter); zfcp_dbf_adapter_unregister(adapter->dbf); zfcp_free_low_mem_buffers(adapter); diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index d9da5c42ccb..82ae6ed7ef8 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -18,6 +18,9 @@ static int zfcp_ccw_suspend(struct ccw_device *cdev) { struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); + if (!adapter) + return 0; + down(&zfcp_data.config_sema); zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL); @@ -33,6 +36,9 @@ static int zfcp_ccw_activate(struct ccw_device *cdev) { struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); + if (!adapter) + return 0; + zfcp_erp_modify_adapter_status(adapter, "ccresu1", NULL, ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, @@ -63,25 +69,14 @@ int zfcp_ccw_priv_sch(struct zfcp_adapter *adapter) * zfcp_ccw_probe - probe function of zfcp driver * @ccw_device: pointer to belonging ccw device * - * This function gets called by the common i/o layer and sets up the initial - * data structures for each fcp adapter, which was detected by the system. - * Also the sysfs files for this adapter will be created by this function. - * In addition the nameserver port will be added to the ports of the adapter - * and its sysfs representation will be created too. + * This function gets called by the common i/o layer for each FCP + * device found on the current system. This is only a stub to make cio + * work: To only allocate adapter resources for devices actually used, + * the allocation is deferred to the first call to ccw_set_online. */ static int zfcp_ccw_probe(struct ccw_device *ccw_device) { - int retval = 0; - - down(&zfcp_data.config_sema); - if (zfcp_adapter_enqueue(ccw_device)) { - dev_err(&ccw_device->dev, - "Setting up data structures for the " - "FCP adapter failed\n"); - retval = -EINVAL; - } - up(&zfcp_data.config_sema); - return retval; + return 0; } /** @@ -102,8 +97,11 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) LIST_HEAD(port_remove_lh); ccw_device_set_offline(ccw_device); + down(&zfcp_data.config_sema); adapter = dev_get_drvdata(&ccw_device->dev); + if (!adapter) + goto out; write_lock_irq(&zfcp_data.config_lock); list_for_each_entry_safe(port, p, &adapter->port_list_head, list) { @@ -129,6 +127,7 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0); zfcp_adapter_dequeue(adapter); +out: up(&zfcp_data.config_sema); } @@ -136,22 +135,33 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) * zfcp_ccw_set_online - set_online function of zfcp driver * @ccw_device: pointer to belonging ccw device * - * This function gets called by the common i/o layer and sets an adapter - * into state online. Setting an fcp device online means that it will be - * registered with the SCSI stack, that the QDIO queues will be set up - * and that the adapter will be opened (asynchronously). + * This function gets called by the common i/o layer and sets an + * adapter into state online. The first call will allocate all + * adapter resources that will be retained until the device is removed + * via zfcp_ccw_remove. + * + * Setting an fcp device online means that it will be registered with + * the SCSI stack, that the QDIO queues will be set up and that the + * adapter will be opened. */ static int zfcp_ccw_set_online(struct ccw_device *ccw_device) { struct zfcp_adapter *adapter; - int retval; + int ret = 0; down(&zfcp_data.config_sema); adapter = dev_get_drvdata(&ccw_device->dev); - retval = zfcp_erp_thread_setup(adapter); - if (retval) - goto out; + if (!adapter) { + ret = zfcp_adapter_enqueue(ccw_device); + if (ret) { + dev_err(&ccw_device->dev, + "Setting up data structures for the " + "FCP adapter failed\n"); + goto out; + } + adapter = dev_get_drvdata(&ccw_device->dev); + } /* initialize request counter */ BUG_ON(!zfcp_reqlist_isempty(adapter)); @@ -162,13 +172,11 @@ static int zfcp_ccw_set_online(struct ccw_device *ccw_device) zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, "ccsonl2", NULL); zfcp_erp_wait(adapter); +out: up(&zfcp_data.config_sema); - flush_work(&adapter->scan_work); - return 0; - - out: - up(&zfcp_data.config_sema); - return retval; + if (!ret) + flush_work(&adapter->scan_work); + return ret; } /** @@ -184,10 +192,13 @@ static int zfcp_ccw_set_offline(struct ccw_device *ccw_device) down(&zfcp_data.config_sema); adapter = dev_get_drvdata(&ccw_device->dev); + if (!adapter) + goto out; + zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL); zfcp_erp_wait(adapter); - zfcp_erp_thread_kill(adapter); up(&zfcp_data.config_sema); +out: return 0; } @@ -244,6 +255,7 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev) adapter = dev_get_drvdata(&cdev->dev); zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL); zfcp_erp_wait(adapter); + zfcp_erp_thread_kill(adapter); up(&zfcp_data.config_sema); } diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 577e1570859..73d366ba31e 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -150,6 +150,9 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, a_status = atomic_read(&adapter->status); if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE) return 0; + if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) && + !(a_status & ZFCP_STATUS_COMMON_OPEN)) + return 0; /* shutdown requested for closed adapter */ } return need; @@ -1349,6 +1352,8 @@ void zfcp_erp_thread_kill(struct zfcp_adapter *adapter) { kthread_stop(adapter->erp_thread); adapter->erp_thread = NULL; + WARN_ON(!list_empty(&adapter->erp_ready_head)); + WARN_ON(!list_empty(&adapter->erp_running_head)); } /** -- cgit v1.2.3-18-g5258 From 24680defdb55e073c5e43d14318a164b842d8ce7 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 18 Aug 2009 15:43:28 +0200 Subject: [SCSI] zfcp: Replace config semaphore with mutex The config semaphore is only used as a mutex, so replace it with a simple mutex. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 22 +++++++++++----------- drivers/s390/scsi/zfcp_ccw.c | 20 ++++++++++---------- drivers/s390/scsi/zfcp_def.h | 3 +-- drivers/s390/scsi/zfcp_fc.c | 4 ++-- drivers/s390/scsi/zfcp_sysfs.c | 16 ++++++++-------- 5 files changed, 32 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index d1e75d36ed1..8e989159e4e 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -84,7 +84,7 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) struct zfcp_port *port; struct zfcp_unit *unit; - down(&zfcp_data.config_sema); + mutex_lock(&zfcp_data.config_mutex); read_lock_irq(&zfcp_data.config_lock); adapter = zfcp_get_adapter_by_busid(busid); if (adapter) @@ -99,20 +99,20 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) unit = zfcp_unit_enqueue(port, lun); if (IS_ERR(unit)) goto out_unit; - up(&zfcp_data.config_sema); + mutex_unlock(&zfcp_data.config_mutex); ccw_device_set_online(adapter->ccw_device); zfcp_erp_wait(adapter); flush_work(&unit->scsi_work); - down(&zfcp_data.config_sema); + mutex_lock(&zfcp_data.config_mutex); zfcp_unit_put(unit); out_unit: zfcp_port_put(port); out_port: zfcp_adapter_put(adapter); out_adapter: - up(&zfcp_data.config_sema); + mutex_unlock(&zfcp_data.config_mutex); return; } @@ -176,7 +176,7 @@ static int __init zfcp_module_init(void) if (!zfcp_data.gid_pn_cache) goto out_gid_cache; - sema_init(&zfcp_data.config_sema, 1); + mutex_init(&zfcp_data.config_mutex); rwlock_init(&zfcp_data.config_lock); zfcp_data.scsi_transport_template = @@ -266,7 +266,7 @@ static void zfcp_sysfs_unit_release(struct device *dev) * @port: pointer to port where unit is added * @fcp_lun: FCP LUN of unit to be enqueued * Returns: pointer to enqueued unit on success, ERR_PTR on error - * Locks: config_sema must be held to serialize changes to the unit list + * Locks: config_mutex must be held to serialize changes to the unit list * * Sets up some unit internal structures and creates sysfs entry. */ @@ -356,7 +356,7 @@ void zfcp_unit_dequeue(struct zfcp_unit *unit) static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) { - /* must only be called with zfcp_data.config_sema taken */ + /* must only be called with zfcp_data.config_mutex taken */ adapter->pool.erp_req = mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req)); if (!adapter->pool.erp_req) @@ -404,7 +404,7 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) { - /* zfcp_data.config_sema must be held */ + /* zfcp_data.config_mutex must be held */ if (adapter->pool.erp_req) mempool_destroy(adapter->pool.erp_req); if (adapter->pool.scsi_req) @@ -491,7 +491,7 @@ static void zfcp_destroy_adapter_work_queue(struct zfcp_adapter *adapter) * Enqueues an adapter at the end of the adapter list in the driver data. * All adapter internal structures are set up. * Proc-fs entries are also created. - * locks: config_sema must be held to serialise changes to the adapter list + * locks: config_mutex must be held to serialize changes to the adapter list */ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) { @@ -499,7 +499,7 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) /* * Note: It is safe to release the list_lock, as any list changes - * are protected by the config_sema, which must be held to get here + * are protected by the config_mutex, which must be held to get here */ adapter = kzalloc(sizeof(struct zfcp_adapter), GFP_KERNEL); @@ -630,7 +630,7 @@ static void zfcp_sysfs_port_release(struct device *dev) * @status: initial status for the port * @d_id: destination id of the remote port to be enqueued * Returns: pointer to enqueued port on success, ERR_PTR on error - * Locks: config_sema must be held to serialize changes to the port list + * Locks: config_mutex must be held to serialize changes to the port list * * All port internal structures are set up and the sysfs entry is generated. * d_id is used to enqueue ports with a well known address like the Directory diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 82ae6ed7ef8..0c90f8e7160 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -21,12 +21,12 @@ static int zfcp_ccw_suspend(struct ccw_device *cdev) if (!adapter) return 0; - down(&zfcp_data.config_sema); + mutex_lock(&zfcp_data.config_mutex); zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL); zfcp_erp_wait(adapter); - up(&zfcp_data.config_sema); + mutex_unlock(&zfcp_data.config_mutex); return 0; } @@ -98,7 +98,7 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) ccw_device_set_offline(ccw_device); - down(&zfcp_data.config_sema); + mutex_lock(&zfcp_data.config_mutex); adapter = dev_get_drvdata(&ccw_device->dev); if (!adapter) goto out; @@ -128,7 +128,7 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) zfcp_adapter_dequeue(adapter); out: - up(&zfcp_data.config_sema); + mutex_unlock(&zfcp_data.config_mutex); } /** @@ -149,7 +149,7 @@ static int zfcp_ccw_set_online(struct ccw_device *ccw_device) struct zfcp_adapter *adapter; int ret = 0; - down(&zfcp_data.config_sema); + mutex_lock(&zfcp_data.config_mutex); adapter = dev_get_drvdata(&ccw_device->dev); if (!adapter) { @@ -173,7 +173,7 @@ static int zfcp_ccw_set_online(struct ccw_device *ccw_device) "ccsonl2", NULL); zfcp_erp_wait(adapter); out: - up(&zfcp_data.config_sema); + mutex_unlock(&zfcp_data.config_mutex); if (!ret) flush_work(&adapter->scan_work); return ret; @@ -190,14 +190,14 @@ static int zfcp_ccw_set_offline(struct ccw_device *ccw_device) { struct zfcp_adapter *adapter; - down(&zfcp_data.config_sema); + mutex_lock(&zfcp_data.config_mutex); adapter = dev_get_drvdata(&ccw_device->dev); if (!adapter) goto out; zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL); zfcp_erp_wait(adapter); - up(&zfcp_data.config_sema); + mutex_unlock(&zfcp_data.config_mutex); out: return 0; } @@ -251,12 +251,12 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev) { struct zfcp_adapter *adapter; - down(&zfcp_data.config_sema); + mutex_lock(&zfcp_data.config_mutex); adapter = dev_get_drvdata(&cdev->dev); zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL); zfcp_erp_wait(adapter); zfcp_erp_thread_kill(adapter); - up(&zfcp_data.config_sema); + mutex_unlock(&zfcp_data.config_mutex); } static struct ccw_driver zfcp_ccw_driver = { diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 99830758e87..cc98eead2c3 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -604,8 +604,7 @@ struct zfcp_data { rwlock_t config_lock; /* serialises changes to adapter/port/unit lists */ - struct semaphore config_sema; /* serialises configuration - changes */ + struct mutex config_mutex; struct kmem_cache *gpn_ft_cache; struct kmem_cache *qtcb_cache; struct kmem_cache *sr_buffer_cache; diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 82f148d0996..722f22de875 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -613,7 +613,7 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) return -E2BIG; } - down(&zfcp_data.config_sema); + mutex_lock(&zfcp_data.config_mutex); /* first entry is the header */ for (x = 1; x < max_entries && !last; x++) { @@ -647,7 +647,7 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) zfcp_erp_wait(adapter); list_for_each_entry_safe(port, tmp, &adapter->port_list_head, list) zfcp_fc_validate_port(port); - up(&zfcp_data.config_sema); + mutex_unlock(&zfcp_data.config_mutex); return ret; } diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index c86496bb608..079a8cf518a 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -88,7 +88,7 @@ static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \ unsigned long val; \ int retval = 0; \ \ - down(&zfcp_data.config_sema); \ + mutex_lock(&zfcp_data.config_mutex); \ if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_REMOVE) { \ retval = -EBUSY; \ goto out; \ @@ -105,7 +105,7 @@ static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \ _reopen_id, NULL); \ zfcp_erp_wait(_adapter); \ out: \ - up(&zfcp_data.config_sema); \ + mutex_unlock(&zfcp_data.config_mutex); \ return retval ? retval : (ssize_t) count; \ } \ static ZFCP_DEV_ATTR(_feat, failed, S_IWUSR | S_IRUGO, \ @@ -142,7 +142,7 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, int retval = 0; LIST_HEAD(port_remove_lh); - down(&zfcp_data.config_sema); + mutex_lock(&zfcp_data.config_mutex); if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) { retval = -EBUSY; goto out; @@ -173,7 +173,7 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, zfcp_port_put(port); zfcp_port_dequeue(port); out: - up(&zfcp_data.config_sema); + mutex_unlock(&zfcp_data.config_mutex); return retval ? retval : (ssize_t) count; } static ZFCP_DEV_ATTR(adapter, port_remove, S_IWUSR, NULL, @@ -207,7 +207,7 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, u64 fcp_lun; int retval = -EINVAL; - down(&zfcp_data.config_sema); + mutex_lock(&zfcp_data.config_mutex); if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { retval = -EBUSY; goto out; @@ -226,7 +226,7 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, zfcp_erp_wait(unit->port->adapter); zfcp_unit_put(unit); out: - up(&zfcp_data.config_sema); + mutex_unlock(&zfcp_data.config_mutex); return retval ? retval : (ssize_t) count; } static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store); @@ -241,7 +241,7 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, int retval = 0; LIST_HEAD(unit_remove_lh); - down(&zfcp_data.config_sema); + mutex_lock(&zfcp_data.config_mutex); if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { retval = -EBUSY; goto out; @@ -282,7 +282,7 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, zfcp_unit_put(unit); zfcp_unit_dequeue(unit); out: - up(&zfcp_data.config_sema); + mutex_unlock(&zfcp_data.config_mutex); return retval ? retval : (ssize_t) count; } static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); -- cgit v1.2.3-18-g5258 From f4395b652636398eb4712e6f3caf79c9a6c02e21 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 18 Aug 2009 15:43:29 +0200 Subject: [SCSI] zfcp: proper use of device register Don't use kfree directly after device registration started. Signed-off-by: Sebastian Ott Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 8e989159e4e..a7954443ec1 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -309,8 +309,10 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) } read_unlock_irq(&zfcp_data.config_lock); - if (device_register(&unit->sysfs_device)) - goto err_out_free; + if (device_register(&unit->sysfs_device)) { + put_device(&unit->sysfs_device); + return ERR_PTR(-EINVAL); + } if (sysfs_create_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs)) { @@ -675,8 +677,10 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, } read_unlock_irq(&zfcp_data.config_lock); - if (device_register(&port->sysfs_device)) - goto err_out_free; + if (device_register(&port->sysfs_device)) { + put_device(&port->sysfs_device); + goto err_out; + } retval = sysfs_create_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs); -- cgit v1.2.3-18-g5258 From 0fac3f477b6b520ae7d972ceb6e958e6807c8e1a Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 18 Aug 2009 15:43:30 +0200 Subject: [SCSI] zfcp: Handle failures during device allocation correctly dev_set_name tries to allocate memory, so check the return value for allocation failures. After dev_set_name succeeds, call device_register as next step to be able to use put_device during error handling. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 65 ++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index a7954443ec1..1be6bf7e8ce 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -274,6 +274,13 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) { struct zfcp_unit *unit; + read_lock_irq(&zfcp_data.config_lock); + if (zfcp_get_unit_by_lun(port, fcp_lun)) { + read_unlock_irq(&zfcp_data.config_lock); + return ERR_PTR(-EINVAL); + } + read_unlock_irq(&zfcp_data.config_lock); + unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); if (!unit) return ERR_PTR(-ENOMEM); @@ -285,8 +292,11 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) unit->port = port; unit->fcp_lun = fcp_lun; - dev_set_name(&unit->sysfs_device, "0x%016llx", - (unsigned long long) fcp_lun); + if (dev_set_name(&unit->sysfs_device, "0x%016llx", + (unsigned long long) fcp_lun)) { + kfree(unit); + return ERR_PTR(-ENOMEM); + } unit->sysfs_device.parent = &port->sysfs_device; unit->sysfs_device.release = zfcp_sysfs_unit_release; dev_set_drvdata(&unit->sysfs_device, unit); @@ -302,13 +312,6 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) unit->latencies.cmd.channel.min = 0xFFFFFFFF; unit->latencies.cmd.fabric.min = 0xFFFFFFFF; - read_lock_irq(&zfcp_data.config_lock); - if (zfcp_get_unit_by_lun(port, fcp_lun)) { - read_unlock_irq(&zfcp_data.config_lock); - goto err_out_free; - } - read_unlock_irq(&zfcp_data.config_lock); - if (device_register(&unit->sysfs_device)) { put_device(&unit->sysfs_device); return ERR_PTR(-EINVAL); @@ -317,7 +320,7 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) if (sysfs_create_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs)) { device_unregister(&unit->sysfs_device); - return ERR_PTR(-EIO); + return ERR_PTR(-EINVAL); } zfcp_unit_get(unit); @@ -332,10 +335,6 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) zfcp_port_get(port); return unit; - -err_out_free: - kfree(unit); - return ERR_PTR(-EINVAL); } /** @@ -642,7 +641,13 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, u32 status, u32 d_id) { struct zfcp_port *port; - int retval; + + read_lock_irq(&zfcp_data.config_lock); + if (zfcp_get_port_by_wwpn(adapter, wwpn)) { + read_unlock_irq(&zfcp_data.config_lock); + return ERR_PTR(-EINVAL); + } + read_unlock_irq(&zfcp_data.config_lock); port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL); if (!port) @@ -663,31 +668,24 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status); atomic_set(&port->refcount, 0); - dev_set_name(&port->sysfs_device, "0x%016llx", - (unsigned long long)wwpn); + if (dev_set_name(&port->sysfs_device, "0x%016llx", + (unsigned long long)wwpn)) { + kfree(port); + return ERR_PTR(-ENOMEM); + } port->sysfs_device.parent = &adapter->ccw_device->dev; - port->sysfs_device.release = zfcp_sysfs_port_release; dev_set_drvdata(&port->sysfs_device, port); - read_lock_irq(&zfcp_data.config_lock); - if (zfcp_get_port_by_wwpn(adapter, wwpn)) { - read_unlock_irq(&zfcp_data.config_lock); - goto err_out_free; - } - read_unlock_irq(&zfcp_data.config_lock); - if (device_register(&port->sysfs_device)) { put_device(&port->sysfs_device); - goto err_out; + return ERR_PTR(-EINVAL); } - retval = sysfs_create_group(&port->sysfs_device.kobj, - &zfcp_sysfs_port_attrs); - - if (retval) { + if (sysfs_create_group(&port->sysfs_device.kobj, + &zfcp_sysfs_port_attrs)) { device_unregister(&port->sysfs_device); - goto err_out; + return ERR_PTR(-EINVAL); } zfcp_port_get(port); @@ -701,11 +699,6 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, zfcp_adapter_get(adapter); return port; - -err_out_free: - kfree(port); -err_out: - return ERR_PTR(-EINVAL); } /** -- cgit v1.2.3-18-g5258 From b592e89ac9af521be164490e45c53c93e89c776f Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 18 Aug 2009 15:43:31 +0200 Subject: [SCSI] zfcp: Remove duplicated code for debug timestamps The timestamp calculation used for s390dbf output is the same in a private zfcp function and in debug.c. Replace both with a common inline function. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index c066428b287..215b70749e9 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -38,19 +38,6 @@ static void zfcp_dbf_hexdump(debug_info_t *dbf, void *to, int to_len, } } -/* FIXME: this duplicate this code in s390 debug feature */ -static void zfcp_dbf_timestamp(unsigned long long stck, struct timespec *time) -{ - unsigned long long sec; - - stck -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096); - sec = stck >> 12; - do_div(sec, 1000000); - time->tv_sec = sec; - stck -= (sec * 1000000) << 12; - time->tv_nsec = ((stck * 1000) >> 12); -} - static void zfcp_dbf_tag(char **p, const char *label, const char *tag) { int i; @@ -107,7 +94,7 @@ static int zfcp_dbf_view_header(debug_info_t *id, struct debug_view *view, char *p = out_buf; if (strncmp(dump->tag, "dump", ZFCP_DBF_TAG_SIZE) != 0) { - zfcp_dbf_timestamp(entry->id.stck, &t); + stck_to_timespec(entry->id.stck, &t); zfcp_dbf_out(&p, "timestamp", "%011lu:%06lu", t.tv_sec, t.tv_nsec); zfcp_dbf_out(&p, "cpu", "%02i", entry->id.fields.cpuid); @@ -320,7 +307,7 @@ static void zfcp_dbf_hba_view_response(char **p, zfcp_dbf_out(p, "fsf_command", "0x%08x", r->fsf_command); zfcp_dbf_out(p, "fsf_reqid", "0x%0Lx", r->fsf_reqid); zfcp_dbf_out(p, "fsf_seqno", "0x%08x", r->fsf_seqno); - zfcp_dbf_timestamp(r->fsf_issued, &t); + stck_to_timespec(r->fsf_issued, &t); zfcp_dbf_out(p, "fsf_issued", "%011lu:%06lu", t.tv_sec, t.tv_nsec); zfcp_dbf_out(p, "fsf_prot_status", "0x%08x", r->fsf_prot_status); zfcp_dbf_out(p, "fsf_status", "0x%08x", r->fsf_status); @@ -976,7 +963,7 @@ static int zfcp_dbf_scsi_view_format(debug_info_t *id, struct debug_view *view, zfcp_dbf_out(&p, "old_fsf_reqid", "0x%0Lx", r->old_fsf_reqid); zfcp_dbf_out(&p, "fsf_reqid", "0x%0Lx", r->fsf_reqid); zfcp_dbf_out(&p, "fsf_seqno", "0x%08x", r->fsf_seqno); - zfcp_dbf_timestamp(r->fsf_issued, &t); + stck_to_timespec(r->fsf_issued, &t); zfcp_dbf_out(&p, "fsf_issued", "%011lu:%06lu", t.tv_sec, t.tv_nsec); if (strncmp(r->tag, "rslt", ZFCP_DBF_TAG_SIZE) == 0) { -- cgit v1.2.3-18-g5258 From 41e05a12c7aae16f0381103af3e5ca791e87ce59 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 18 Aug 2009 15:43:32 +0200 Subject: [SCSI] zfcp: optimize zfcp_qdio_account Remove expensive ktime_get()/ktime_us_delta() functions from the hot path and use get_clock_monotonic() instead. This elimates seven function calls and avoids a lot of unnecessary calculations. Signed-off-by: Heiko Carstens Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_def.h | 2 +- drivers/s390/scsi/zfcp_qdio.c | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index cc98eead2c3..7da2fad8f51 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -438,7 +438,7 @@ struct zfcp_qdio { struct zfcp_qdio_queue req_q; spinlock_t stat_lock; spinlock_t req_q_lock; - ktime_t req_q_time; + unsigned long long req_q_time; u64 req_q_util; atomic_t req_q_full; wait_queue_head_t req_q_wq; diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 2b499e28ff1..6c5228b627f 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -56,16 +56,15 @@ static void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int cnt) } /* this needs to be called prior to updating the queue fill level */ -static void zfcp_qdio_account(struct zfcp_qdio *qdio) +static inline void zfcp_qdio_account(struct zfcp_qdio *qdio) { - ktime_t now; - s64 span; + unsigned long long now, span; int free, used; spin_lock(&qdio->stat_lock); - now = ktime_get(); - span = ktime_us_delta(now, qdio->req_q_time); - free = max(0, atomic_read(&qdio->req_q.count)); + now = get_clock_monotonic(); + span = (now - qdio->req_q_time) >> 12; + free = atomic_read(&qdio->req_q.count); used = QDIO_MAX_BUFFERS_PER_Q - free; qdio->req_q_util += used * span; qdio->req_q_time = now; -- cgit v1.2.3-18-g5258 From 69cb48750b02034350bc78d8053647d7464cdde0 Mon Sep 17 00:00:00 2001 From: Ed Lin Date: Tue, 18 Aug 2009 12:15:14 -0700 Subject: [SCSI] stex: Add reset code for st_yel (v2) Add reset related code for st_yel. 1. Set the SS_H2I_INT_RESET bit. 2. Wait for the SS_MU_OPERATIONAL flag. This is also part of normal handshake process so move it to handshake routine. 3. Continue handshake with the firmware. Signed-off-by: Ed Lin Signed-off-by: James Bottomley --- drivers/scsi/stex.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index 8d2a95c4e5b..09fa8861fc5 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -55,6 +55,7 @@ enum { OIS = 0x30, /* MU_OUTBOUND_INTERRUPT_STATUS */ OIM = 0x3c, /* MU_OUTBOUND_INTERRUPT_MASK */ + YIOA_STATUS = 0x00, YH2I_INT = 0x20, YINT_EN = 0x34, YI2H_INT = 0x9c, @@ -108,6 +109,10 @@ enum { SS_HEAD_HANDSHAKE = 0x80, + SS_H2I_INT_RESET = 0x100, + + SS_MU_OPERATIONAL = 0x80000000, + STEX_CDB_LENGTH = 16, STATUS_VAR_LEN = 128, @@ -884,7 +889,7 @@ static void stex_ss_mu_intr(struct st_hba *hba) tag = (u16)value; if (unlikely(tag >= hba->host->can_queue)) { printk(KERN_WARNING DRV_NAME - "(%s): invalid tag\n", pci_name(hba->pdev)); + "(%s): invalid tag\n", pci_name(hba->pdev)); continue; } @@ -1040,16 +1045,27 @@ static int stex_ss_handshake(struct st_hba *hba) void __iomem *base = hba->mmio_base; struct st_msg_header *msg_h; struct handshake_frame *h; - __le32 *scratch = hba->scratch; + __le32 *scratch; u32 data; unsigned long before; int ret = 0; - h = (struct handshake_frame *)(hba->alloc_rq(hba)); - msg_h = (struct st_msg_header *)h - 1; + before = jiffies; + while ((readl(base + YIOA_STATUS) & SS_MU_OPERATIONAL) == 0) { + if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { + printk(KERN_ERR DRV_NAME + "(%s): firmware not operational\n", + pci_name(hba->pdev)); + return -1; + } + msleep(1); + } + + msg_h = (struct st_msg_header *)hba->dma_mem; msg_h->handle = cpu_to_le64(hba->dma_handle); msg_h->flag = SS_HEAD_HANDSHAKE; + h = (struct handshake_frame *)(msg_h + 1); h->rb_phy = cpu_to_le64(hba->dma_handle); h->req_sz = cpu_to_le16(hba->rq_size); h->req_cnt = cpu_to_le16(hba->rq_count+1); @@ -1205,6 +1221,13 @@ static void stex_hard_reset(struct st_hba *hba) hba->pdev->saved_config_space[i]); } +static void stex_ss_reset(struct st_hba *hba) +{ + writel(SS_H2I_INT_RESET, hba->mmio_base + YH2I_INT); + readl(hba->mmio_base + YH2I_INT); + ssleep(5); +} + static int stex_reset(struct scsi_cmnd *cmd) { struct st_hba *hba; @@ -1221,6 +1244,8 @@ static int stex_reset(struct scsi_cmnd *cmd) if (hba->cardtype == st_shasta) stex_hard_reset(hba); + else if (hba->cardtype == st_yel) + stex_ss_reset(hba); if (hba->cardtype != st_yosemite) { if (stex_handshake(hba)) { -- cgit v1.2.3-18-g5258 From cd4e12e8ad246ec5bc23ab04d0da0e6985025620 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 20 Aug 2009 13:20:54 +0530 Subject: [SCSI] mpt2sas : Rescan topology from Interrupt context instead of work thread Following host reset its possible that the controller firmware could assign new handles for devices, as well as adding or deleting devices. There is code in the driver that will rescan the topology folowing host reset; updating device handles, and remove devices that are no longer responding. This patch will improve the responsivness by moving this rescaning from the delayed hotplug worker thread to immediately following the host reset. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Cc: Stable Tree Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.c | 3 + drivers/scsi/mpt2sas/mpt2sas_base.h | 1 + drivers/scsi/mpt2sas/mpt2sas_scsih.c | 142 +++++++++++++---------------------- 3 files changed, 57 insertions(+), 89 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 35a13867495..cc5a8dae4ae 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -3536,5 +3536,8 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); ioc->ioc_reset_in_progress = 0; spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + + if (!r) + _base_reset_handler(ioc, MPT2_IOC_RUNNING); return r; } diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index acdcff150a3..998a7b847b3 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -119,6 +119,7 @@ #define MPT2_IOC_PRE_RESET 1 /* prior to host reset */ #define MPT2_IOC_AFTER_RESET 2 /* just after host reset */ #define MPT2_IOC_DONE_RESET 3 /* links re-initialized */ +#define MPT2_IOC_RUNNING 4 /* shost running */ /* * logging format diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 2e9a4445596..471c3b60459 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -103,7 +103,6 @@ struct sense_info { }; -#define MPT2SAS_RESCAN_AFTER_HOST_RESET (0xFFFF) /** * struct fw_event_work - firmware event struct * @list: link list framework @@ -2404,27 +2403,6 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc, spin_unlock_irqrestore(&ioc->fw_event_lock, flags); } -/** - * _scsih_queue_rescan - queue a topology rescan from user context - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_scsih_queue_rescan(struct MPT2SAS_ADAPTER *ioc) -{ - struct fw_event_work *fw_event; - - if (ioc->wait_for_port_enable_to_complete) - return; - fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); - if (!fw_event) - return; - fw_event->event = MPT2SAS_RESCAN_AFTER_HOST_RESET; - fw_event->ioc = ioc; - _scsih_fw_event_add(ioc, fw_event); -} - /** * _scsih_flush_running_cmds - completing outstanding commands. * @ioc: per adapter object @@ -2455,46 +2433,6 @@ _scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc) ioc->name, count)); } -/** - * mpt2sas_scsih_reset_handler - reset callback handler (for scsih) - * @ioc: per adapter object - * @reset_phase: phase - * - * The handler for doing any required cleanup or initialization. - * - * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET, - * MPT2_IOC_DONE_RESET - * - * Return nothing. - */ -void -mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) -{ - switch (reset_phase) { - case MPT2_IOC_PRE_RESET: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " - "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); - _scsih_fw_event_off(ioc); - break; - case MPT2_IOC_AFTER_RESET: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " - "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); - if (ioc->tm_cmds.status & MPT2_CMD_PENDING) { - ioc->tm_cmds.status |= MPT2_CMD_RESET; - mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid); - complete(&ioc->tm_cmds.done); - } - _scsih_fw_event_on(ioc); - _scsih_flush_running_cmds(ioc); - break; - case MPT2_IOC_DONE_RESET: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " - "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); - _scsih_queue_rescan(ioc); - break; - } -} - /** * _scsih_setup_eedp - setup MPI request for EEDP transfer * @scmd: pointer to scsi command object @@ -5156,22 +5094,9 @@ static void _scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc) { struct _sas_device *sas_device, *sas_device_next; - struct _sas_node *sas_expander, *sas_expander_next; + struct _sas_node *sas_expander; struct _raid_device *raid_device, *raid_device_next; - unsigned long flags; - _scsih_search_responding_sas_devices(ioc); - _scsih_search_responding_raid_devices(ioc); - _scsih_search_responding_expanders(ioc); - - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - ioc->shost_recovery = 0; - if (ioc->shost->shost_state == SHOST_RECOVERY) { - printk(MPT2SAS_INFO_FMT "putting controller into " - "SHOST_RUNNING\n", ioc->name); - scsi_host_set_state(ioc->shost, SHOST_RUNNING); - } - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); list_for_each_entry_safe(sas_device, sas_device_next, &ioc->sas_device_list, list) { @@ -5207,16 +5132,63 @@ _scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc) _scsih_raid_device_remove(ioc, raid_device); } - list_for_each_entry_safe(sas_expander, sas_expander_next, - &ioc->sas_expander_list, list) { + retry_expander_search: + sas_expander = NULL; + list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { if (sas_expander->responding) { sas_expander->responding = 0; continue; } - printk("\tremoving expander: handle(0x%04x), " - " sas_addr(0x%016llx)\n", sas_expander->handle, - (unsigned long long)sas_expander->sas_address); _scsih_expander_remove(ioc, sas_expander->handle); + goto retry_expander_search; + } +} + +/** + * mpt2sas_scsih_reset_handler - reset callback handler (for scsih) + * @ioc: per adapter object + * @reset_phase: phase + * + * The handler for doing any required cleanup or initialization. + * + * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET, + * MPT2_IOC_DONE_RESET + * + * Return nothing. + */ +void +mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) +{ + switch (reset_phase) { + case MPT2_IOC_PRE_RESET: + dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); + _scsih_fw_event_off(ioc); + break; + case MPT2_IOC_AFTER_RESET: + dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); + if (ioc->tm_cmds.status & MPT2_CMD_PENDING) { + ioc->tm_cmds.status |= MPT2_CMD_RESET; + mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid); + complete(&ioc->tm_cmds.done); + } + _scsih_fw_event_on(ioc); + _scsih_flush_running_cmds(ioc); + break; + case MPT2_IOC_DONE_RESET: + dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); + _scsih_sas_host_refresh(ioc, 0); + _scsih_search_responding_sas_devices(ioc); + _scsih_search_responding_raid_devices(ioc); + _scsih_search_responding_expanders(ioc); + break; + case MPT2_IOC_RUNNING: + dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + "MPT2_IOC_RUNNING\n", ioc->name, __func__)); + _scsih_remove_unresponding_devices(ioc); + break; } } @@ -5236,14 +5208,6 @@ _firmware_event_work(struct work_struct *work) unsigned long flags; struct MPT2SAS_ADAPTER *ioc = fw_event->ioc; - /* This is invoked by calling _scsih_queue_rescan(). */ - if (fw_event->event == MPT2SAS_RESCAN_AFTER_HOST_RESET) { - _scsih_fw_event_free(ioc, fw_event); - _scsih_sas_host_refresh(ioc, 1); - _scsih_remove_unresponding_devices(ioc); - return; - } - /* the queue is being flushed so ignore this event */ spin_lock_irqsave(&ioc->fw_event_lock, flags); if (ioc->fw_events_off || ioc->remove_host) { -- cgit v1.2.3-18-g5258 From 155dd4c763694222c125e65438d823f58ea653bc Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 20 Aug 2009 13:22:00 +0530 Subject: [SCSI] mpt2sas: Prevent sending command to FW while Host Reset This patch renames the flag for indicating host reset from ioc_reset_in_progress to shost_recovery. It also removes the spin locks surrounding the setting of this flag, which are unnecessary. Sanity checks on the shost_recovery flag were added thru out the code so as to prevent sending firmware commands during host reset. Also, the setting of the shost state to SHOST_RECOVERY was removed to prevent deadlocks, this is actually better handled by the shost_recovery flag. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Cc: Stable Tree Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.c | 13 +++-------- drivers/scsi/mpt2sas/mpt2sas_base.h | 3 +-- drivers/scsi/mpt2sas/mpt2sas_ctl.c | 16 ++----------- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 40 +++++++++++++++++++------------- drivers/scsi/mpt2sas/mpt2sas_transport.c | 29 +++++++++++++---------- 5 files changed, 47 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index cc5a8dae4ae..1cfb503125b 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -94,7 +94,7 @@ _base_fault_reset_work(struct work_struct *work) int rc; spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (ioc->ioc_reset_in_progress) + if (ioc->shost_recovery) goto rearm_timer; spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); @@ -3501,20 +3501,13 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, __func__)); spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (ioc->ioc_reset_in_progress) { + if (ioc->shost_recovery) { spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); printk(MPT2SAS_ERR_FMT "%s: busy\n", ioc->name, __func__); return -EBUSY; } - ioc->ioc_reset_in_progress = 1; ioc->shost_recovery = 1; - if (ioc->shost->shost_state == SHOST_RUNNING) { - /* set back to SHOST_RUNNING in mpt2sas_scsih.c */ - scsi_host_set_state(ioc->shost, SHOST_RECOVERY); - printk(MPT2SAS_INFO_FMT "putting controller into " - "SHOST_RECOVERY\n", ioc->name); - } spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); _base_reset_handler(ioc, MPT2_IOC_PRE_RESET); @@ -3534,7 +3527,7 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED"))); spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - ioc->ioc_reset_in_progress = 0; + ioc->shost_recovery = 0; spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); if (!r) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 998a7b847b3..15827582a90 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -432,7 +432,7 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); * @fw_event_list: list of fw events * @aen_event_read_flag: event log was read * @broadcast_aen_busy: broadcast aen waiting to be serviced - * @ioc_reset_in_progress: host reset in progress + * @shost_recovery: host reset in progress * @ioc_reset_in_progress_lock: * @ioc_link_reset_in_progress: phy/hard reset in progress * @ignore_loginfos: ignore loginfos during task managment @@ -545,7 +545,6 @@ struct MPT2SAS_ADAPTER { /* misc flags */ int aen_event_read_flag; u8 broadcast_aen_busy; - u8 ioc_reset_in_progress; u8 shost_recovery; spinlock_t ioc_reset_in_progress_lock; u8 ioc_link_reset_in_progress; diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 14e473d1fa7..c2a51018910 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -1963,7 +1963,6 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg) { enum block_state state; long ret = -EINVAL; - unsigned long flags; state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING; @@ -1989,13 +1988,8 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg) !ioc) return -ENODEV; - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (ioc->shost_recovery) { - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, - flags); + if (ioc->shost_recovery) return -EAGAIN; - } - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) { uarg = arg; @@ -2098,7 +2092,6 @@ _ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg) struct mpt2_ioctl_command karg; struct MPT2SAS_ADAPTER *ioc; enum block_state state; - unsigned long flags; if (_IOC_SIZE(cmd) != sizeof(struct mpt2_ioctl_command32)) return -EINVAL; @@ -2113,13 +2106,8 @@ _ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg) if (_ctl_verify_adapter(karg32.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (ioc->shost_recovery) { - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, - flags); + if (ioc->shost_recovery) return -EAGAIN; - } - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); memset(&karg, 0, sizeof(struct mpt2_ioctl_command)); karg.hdr.ioc_number = karg32.hdr.ioc_number; diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 471c3b60459..195f5e5aabf 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -1785,17 +1785,18 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun, u32 ioc_state; unsigned long timeleft; u8 VF_ID = 0; - unsigned long flags; - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED || - ioc->shost_recovery) { - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) { + printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n", + __func__, ioc->name); + return; + } + + if (ioc->shost_recovery) { printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", __func__, ioc->name); return; } - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); ioc_state = mpt2sas_base_get_iocstate(ioc, 0); if (ioc_state & MPI2_DOORBELL_USED) { @@ -2553,7 +2554,6 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) Mpi2SCSIIORequest_t *mpi_request; u32 mpi_control; u16 smid; - unsigned long flags; scmd->scsi_done = done; sas_device_priv_data = scmd->device->hostdata; @@ -2572,13 +2572,10 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) } /* see if we are busy with task managment stuff */ - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (sas_target_priv_data->tm_busy || - ioc->shost_recovery || ioc->ioc_link_reset_in_progress) { - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + if (sas_target_priv_data->tm_busy) + return SCSI_MLQUEUE_DEVICE_BUSY; + else if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress) return SCSI_MLQUEUE_HOST_BUSY; - } - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); if (scmd->sc_data_direction == DMA_FROM_DEVICE) mpi_control = MPI2_SCSIIO_CONTROL_READ; @@ -3374,6 +3371,9 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle) if (!handle) return -1; + if (ioc->shost_recovery) + return -1; + if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", @@ -3510,6 +3510,9 @@ _scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u16 handle) struct _sas_node *sas_expander; unsigned long flags; + if (ioc->shost_recovery) + return; + spin_lock_irqsave(&ioc->sas_node_lock, flags); sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, handle); spin_unlock_irqrestore(&ioc->sas_node_lock, flags); @@ -3681,6 +3684,8 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) mutex_unlock(&ioc->tm_cmds.mutex); dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset " "done: handle(0x%04x)\n", ioc->name, device_handle)); + if (ioc->shost_recovery) + goto out; } /* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */ @@ -3846,6 +3851,8 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, "expander event\n", ioc->name)); return; } + if (ioc->shost_recovery) + return; if (event_data->PHY[i].PhyStatus & MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) continue; @@ -5217,13 +5224,10 @@ _firmware_event_work(struct work_struct *work) } spin_unlock_irqrestore(&ioc->fw_event_lock, flags); - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); if (ioc->shost_recovery) { - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); _scsih_fw_event_requeue(ioc, fw_event, 1000); return; } - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); switch (fw_event->event) { case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: @@ -5425,6 +5429,8 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc, if (!sas_device) continue; _scsih_remove_device(ioc, sas_device->handle); + if (ioc->shost_recovery) + return; goto retry_device_search; } } @@ -5446,6 +5452,8 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc, if (!expander_sibling) continue; _scsih_expander_remove(ioc, expander_sibling->handle); + if (ioc->shost_recovery) + return; goto retry_expander_search; } } diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index 686695b155c..a53086d0381 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -140,11 +140,18 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle, u32 device_info; u32 ioc_status; + if (ioc->shost_recovery) { + printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", + __func__, ioc->name); + return -EFAULT; + } + if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); - return -1; + return -ENXIO; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & @@ -153,7 +160,7 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle, printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)" "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status, __FILE__, __LINE__, __func__); - return -1; + return -EIO; } memset(identify, 0, sizeof(identify)); @@ -288,21 +295,17 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, void *psge; u32 sgl_flags; u8 issue_reset = 0; - unsigned long flags; void *data_out = NULL; dma_addr_t data_out_dma; u32 sz; u64 *sas_address_le; u16 wait_state_count; - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (ioc->ioc_reset_in_progress) { - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + if (ioc->shost_recovery) { printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", __func__, ioc->name); return -EFAULT; } - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); mutex_lock(&ioc->transport_cmds.mutex); @@ -806,6 +809,12 @@ mpt2sas_transport_update_phy_link_change(struct MPT2SAS_ADAPTER *ioc, struct _sas_node *sas_node; struct _sas_phy *mpt2sas_phy; + if (ioc->shost_recovery) { + printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", + __func__, ioc->name); + return; + } + spin_lock_irqsave(&ioc->sas_node_lock, flags); sas_node = _transport_sas_node_find_by_handle(ioc, handle); spin_unlock_irqrestore(&ioc->sas_node_lock, flags); @@ -1025,7 +1034,6 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, void *psge; u32 sgl_flags; u8 issue_reset = 0; - unsigned long flags; dma_addr_t dma_addr_in = 0; dma_addr_t dma_addr_out = 0; u16 wait_state_count; @@ -1045,14 +1053,11 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, return -EINVAL; } - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (ioc->ioc_reset_in_progress) { - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + if (ioc->shost_recovery) { printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", __func__, ioc->name); return -EFAULT; } - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex); if (rc) -- cgit v1.2.3-18-g5258 From cc0f5207664f85da8d0b2ebdacec5daaee0ce95f Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 20 Aug 2009 13:22:39 +0530 Subject: [SCSI] mpt2sas: Removed wrapper funtions _scsih_link_change. Deleted the wrapper function called _scsih_link_change. This function was implemented for compatibility reasons only, between different kernel versions. Currently this function is no longer needed. The calling function are converted to calling mpt2sas_transport_update_phy_link_change directly in the transport layer. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.h | 2 +- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 44 ++++++++++---------------------- drivers/scsi/mpt2sas/mpt2sas_transport.c | 4 +-- 3 files changed, 17 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 15827582a90..39dc69627bc 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -798,7 +798,7 @@ int mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev); int mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev); -void mpt2sas_transport_update_phy_link_change(struct MPT2SAS_ADAPTER *ioc, u16 handle, +void mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, u16 handle, u16 attached_handle, u8 phy_number, u8 link_rate); extern struct sas_function_template mpt2sas_transport_functions; extern struct scsi_transport_template *mpt2sas_transport_template; diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 195f5e5aabf..c0d5d5e1f9c 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -3123,25 +3123,6 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) scmd->scsi_done(scmd); } -/** - * _scsih_link_change - process phy link changes - * @ioc: per adapter object - * @handle: phy handle - * @attached_handle: valid for devices attached to link - * @phy_number: phy number - * @link_rate: new link rate - * Context: user. - * - * Return nothing. - */ -static void -_scsih_link_change(struct MPT2SAS_ADAPTER *ioc, u16 handle, u16 attached_handle, - u8 phy_number, u8 link_rate) -{ - mpt2sas_transport_update_phy_link_change(ioc, handle, attached_handle, - phy_number, link_rate); -} - /** * _scsih_sas_host_refresh - refreshing sas host object contents * @ioc: per adapter object @@ -3186,7 +3167,8 @@ _scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc, u8 update) le16_to_cpu(sas_iounit_pg0->PhyData[i]. ControllerDevHandle); if (update) - _scsih_link_change(ioc, + mpt2sas_transport_update_links( + ioc, ioc->sas_hba.phy[i].handle, le16_to_cpu(sas_iounit_pg0->PhyData[i]. AttachedDevHandle), i, @@ -3868,9 +3850,10 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: if (!parent_handle) { if (phy_number < ioc->sas_hba.num_phys) - _scsih_link_change(ioc, - ioc->sas_hba.phy[phy_number].handle, - handle, phy_number, link_rate_); + mpt2sas_transport_update_links( + ioc, + ioc->sas_hba.phy[phy_number].handle, + handle, phy_number, link_rate_); } else { spin_lock_irqsave(&ioc->sas_node_lock, flags); sas_expander = @@ -3880,11 +3863,12 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, flags); if (sas_expander) { if (phy_number < sas_expander->num_phys) - _scsih_link_change(ioc, - sas_expander-> - phy[phy_number].handle, - handle, phy_number, - link_rate_); + mpt2sas_transport_update_links( + ioc, + sas_expander-> + phy[phy_number].handle, + handle, phy_number, + link_rate_); } } if (reason_code == MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED) { @@ -4400,7 +4384,7 @@ _scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc, return; } - _scsih_link_change(ioc, + mpt2sas_transport_update_links(ioc, le16_to_cpu(sas_device_pg0.ParentDevHandle), handle, sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); @@ -4689,7 +4673,7 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, return; } - _scsih_link_change(ioc, + mpt2sas_transport_update_links(ioc, le16_to_cpu(sas_device_pg0.ParentDevHandle), handle, sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index a53086d0381..742324a0a11 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -792,7 +792,7 @@ mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy } /** - * mpt2sas_transport_update_phy_link_change - refreshing phy link changes and attached devices + * mpt2sas_transport_update_links - refreshing phy link changes * @ioc: per adapter object * @handle: handle to sas_host or expander * @attached_handle: attached device handle @@ -802,7 +802,7 @@ mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy * Returns nothing. */ void -mpt2sas_transport_update_phy_link_change(struct MPT2SAS_ADAPTER *ioc, +mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, u16 handle, u16 attached_handle, u8 phy_number, u8 link_rate) { unsigned long flags; -- cgit v1.2.3-18-g5258 From 34a03bef2202d0c9983a8da0a8abaee37d285847 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 20 Aug 2009 13:23:19 +0530 Subject: [SCSI] mpt2sas: setting SDEV into RUNNING state from Interrupt context Changing SDEV Running state from interrupt context. Previously It was handle in work queue thread. With this change It will not wait for work queue thread to execute scsih_ublock_io_device to put SDEV into Running state. This will reduce delay for Device becoming RUNNING. Modified this patch considering James comment "Not to change SDEV state using scsi_device_set_state API, instead use scsi_internal_device_unblock scsi_internal_device_block API" Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Cc: Stable Tree Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.h | 2 ++ drivers/scsi/mpt2sas/mpt2sas_scsih.c | 17 +++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 39dc69627bc..1f3efd6569d 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -802,5 +802,7 @@ void mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, u16 handle, u16 attached_handle, u8 phy_number, u8 link_rate); extern struct sas_function_template mpt2sas_transport_functions; extern struct scsi_transport_template *mpt2sas_transport_template; +extern int scsi_internal_device_block(struct scsi_device *sdev); +extern int scsi_internal_device_unblock(struct scsi_device *sdev); #endif /* MPT2SAS_BASE_H_INCLUDED */ diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index c0d5d5e1f9c..6e6d5af6b36 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -2222,7 +2222,7 @@ _scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) MPT2SAS_INFO_FMT "SDEV_RUNNING: " "handle(0x%04x)\n", ioc->name, handle)); sas_device_priv_data->block = 0; - scsi_device_set_state(sdev, SDEV_RUNNING); + scsi_internal_device_unblock(sdev); } } } @@ -2251,7 +2251,7 @@ _scsih_block_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) MPT2SAS_INFO_FMT "SDEV_BLOCK: " "handle(0x%04x)\n", ioc->name, handle)); sas_device_priv_data->block = 1; - scsi_device_set_state(sdev, SDEV_BLOCK); + scsi_internal_device_block(sdev); } } } @@ -2327,6 +2327,7 @@ _scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc, u16 handle; u16 reason_code; u8 phy_number; + u8 link_rate; for (i = 0; i < event_data->NumEntries; i++) { handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); @@ -2337,6 +2338,11 @@ _scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc, MPI2_EVENT_SAS_TOPO_RC_MASK; if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING) _scsih_block_io_device(ioc, handle); + if (reason_code == MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED) { + link_rate = event_data->PHY[i].LinkRate >> 4; + if (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5) + _scsih_ublock_io_device(ioc, handle); + } } } @@ -3690,6 +3696,9 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) le32_to_cpu(mpi_reply.IOCLogInfo))); out: + + _scsih_ublock_io_device(ioc, handle); + mpt2sas_transport_port_remove(ioc, sas_device->sas_address, sas_device->parent_handle); @@ -3871,10 +3880,6 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, link_rate_); } } - if (reason_code == MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED) { - if (link_rate_ >= MPI2_SAS_NEG_LINK_RATE_1_5) - _scsih_ublock_io_device(ioc, handle); - } if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED) { if (link_rate_ < MPI2_SAS_NEG_LINK_RATE_1_5) break; -- cgit v1.2.3-18-g5258 From ed79f1280d1bc54f168abcffc8c3e0bf8ffb1873 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 20 Aug 2009 13:23:49 +0530 Subject: [SCSI] mpt2sas: Raid 10 Volume is showing as Raid 1E in dmesg This patch modifies the slave_configure callback so the messages that get sent to system log for RAID1E volumes contain the string "RAID10" instead of "RAID1E". These messages contain information regarding what kind of scsi device is being added. Certain OEMS can enable displaying the RAID10 string instead of RAID1E via manufacturing page 10. The driver will read this config page at driver load time, then determine from the GenericFlags0 bits whether display the RAID10 or RAID1E string, also even drive count is taken into consideration. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Cc: Stable Tree Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.c | 7 ++-- drivers/scsi/mpt2sas/mpt2sas_base.h | 37 ++++++++++++++++++++- drivers/scsi/mpt2sas/mpt2sas_config.c | 61 +++++++++++++++++++++++++++++++++++ drivers/scsi/mpt2sas/mpt2sas_scsih.c | 8 ++++- 4 files changed, 109 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 1cfb503125b..2e4bc3d2b43 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -1542,6 +1542,8 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc) (ioc->bios_pg3.BiosVersion & 0x0000FF00) >> 8, ioc->bios_pg3.BiosVersion & 0x000000FF); + _base_display_dell_branding(ioc); + printk(MPT2SAS_INFO_FMT "Protocol=(", ioc->name); if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR) { @@ -1554,8 +1556,6 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc) i++; } - _base_display_dell_branding(ioc); - i = 0; printk("), "); printk("Capabilities=("); @@ -1627,6 +1627,9 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc) u32 iounit_pg1_flags; mpt2sas_config_get_manufacturing_pg0(ioc, &mpi_reply, &ioc->manu_pg0); + if (ioc->ir_firmware) + mpt2sas_config_get_manufacturing_pg10(ioc, &mpi_reply, + &ioc->manu_pg10); mpt2sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2); mpt2sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3); mpt2sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8); diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 1f3efd6569d..ff05ae1e43b 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -197,6 +197,38 @@ struct MPT2SAS_TARGET { * @block: device is in SDEV_BLOCK state * @tlr_snoop_check: flag used in determining whether to disable TLR */ + +/* OEM Identifiers */ +#define MFG10_OEM_ID_INVALID (0x00000000) +#define MFG10_OEM_ID_DELL (0x00000001) +#define MFG10_OEM_ID_FSC (0x00000002) +#define MFG10_OEM_ID_SUN (0x00000003) +#define MFG10_OEM_ID_IBM (0x00000004) + +/* GENERIC Flags 0*/ +#define MFG10_GF0_OCE_DISABLED (0x00000001) +#define MFG10_GF0_R1E_DRIVE_COUNT (0x00000002) +#define MFG10_GF0_R10_DISPLAY (0x00000004) +#define MFG10_GF0_SSD_DATA_SCRUB_DISABLE (0x00000008) +#define MFG10_GF0_SINGLE_DRIVE_R0 (0x00000010) + +/* OEM Specific Flags will come from OEM specific header files */ +typedef struct _MPI2_CONFIG_PAGE_MAN_10 { + MPI2_CONFIG_PAGE_HEADER Header; /* 00h */ + U8 OEMIdentifier; /* 04h */ + U8 Reserved1; /* 05h */ + U16 Reserved2; /* 08h */ + U32 Reserved3; /* 0Ch */ + U32 GenericFlags0; /* 10h */ + U32 GenericFlags1; /* 14h */ + U32 Reserved4; /* 18h */ + U32 OEMSpecificFlags0; /* 1Ch */ + U32 OEMSpecificFlags1; /* 20h */ + U32 Reserved5[18]; /* 24h-60h*/ +} MPI2_CONFIG_PAGE_MAN_10, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_10, + Mpi2ManufacturingPage10_t, MPI2_POINTER pMpi2ManufacturingPage10_t; + struct MPT2SAS_DEVICE { struct MPT2SAS_TARGET *sas_target; unsigned int lun; @@ -461,6 +493,7 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); * @facts: static facts data * @pfacts: static port facts data * @manu_pg0: static manufacturing page 0 + * @manu_pg10: static manufacturing page 10 * @bios_pg2: static bios page 2 * @bios_pg3: static bios page 3 * @ioc_pg8: static ioc page 8 @@ -663,6 +696,7 @@ struct MPT2SAS_ADAPTER { dma_addr_t diag_buffer_dma[MPI2_DIAG_BUF_TYPE_COUNT]; u8 diag_buffer_status[MPI2_DIAG_BUF_TYPE_COUNT]; u32 unique_id[MPI2_DIAG_BUF_TYPE_COUNT]; + Mpi2ManufacturingPage10_t manu_pg10; u32 product_specific[MPI2_DIAG_BUF_TYPE_COUNT][23]; u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT]; }; @@ -734,6 +768,8 @@ void mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 re int mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys); int mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page); +int mpt2sas_config_get_manufacturing_pg10(struct MPT2SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage10_t *config_page); int mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2BiosPage2_t *config_page); int mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t @@ -776,7 +812,6 @@ int mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle, u16 *volume_handle); int mpt2sas_config_get_volume_wwid(struct MPT2SAS_ADAPTER *ioc, u16 volume_handle, u64 *wwid); - /* ctl shared API */ extern struct device_attribute *mpt2sas_host_attrs[]; extern struct device_attribute *mpt2sas_dev_attrs[]; diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c index 6ddee161beb..b9f4d0f97e5 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_config.c +++ b/drivers/scsi/mpt2sas/mpt2sas_config.c @@ -425,6 +425,67 @@ mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc, return r; } +/** + * mpt2sas_config_get_manufacturing_pg10 - obtain manufacturing page 10 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_manufacturing_pg10(struct MPT2SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage10_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + struct config_request mem; + + memset(config_page, 0, sizeof(Mpi2ManufacturingPage10_t)); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; + mpi_request.Header.PageNumber = 10; + mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request.Header.PageType = mpi_reply->Header.PageType; + mpi_request.Header.PageLength = mpi_reply->Header.PageLength; + mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; + if (mem.config_page_sz > ioc->config_page_sz) { + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r) + goto out; + } else { + mem.config_page_dma = ioc->config_page_dma; + mem.config_page = ioc->config_page; + } + ioc->base_add_sg_single(&mpi_request.PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, + mem.config_page_dma); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + if (!r) + memcpy(config_page, mem.config_page, + min_t(u16, mem.config_page_sz, + sizeof(Mpi2ManufacturingPage10_t))); + + if (mem.config_page_sz > ioc->config_page_sz) + _config_free_config_dma_memory(ioc, &mem); + + out: + return r; +} + /** * mpt2sas_config_get_bios_pg2 - obtain bios page 2 * @ioc: per adapter object diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 6e6d5af6b36..e71a6c04298 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -1501,7 +1501,13 @@ _scsih_slave_configure(struct scsi_device *sdev) break; case MPI2_RAID_VOL_TYPE_RAID1E: qdepth = MPT2SAS_RAID_QUEUE_DEPTH; - r_level = "RAID1E"; + if (ioc->manu_pg10.OEMIdentifier && + (ioc->manu_pg10.GenericFlags0 & + MFG10_GF0_R10_DISPLAY) && + !(raid_device->num_pds % 2)) + r_level = "RAID10"; + else + r_level = "RAID1E"; break; case MPI2_RAID_VOL_TYPE_RAID1: qdepth = MPT2SAS_RAID_QUEUE_DEPTH; -- cgit v1.2.3-18-g5258 From 5b768581ea722172f059ad5a5eebea9008961af0 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 20 Aug 2009 13:24:31 +0530 Subject: [SCSI] mpt2sas: cleanup interrupt routine and config_request optimization Cleaned up base_interrupt routine to be more effiecent. Deleted about a third of the config page API by moving redundant code from all the calling functions to _config_request. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.c | 73 ++- drivers/scsi/mpt2sas/mpt2sas_base.h | 2 +- drivers/scsi/mpt2sas/mpt2sas_config.c | 911 ++++++++-------------------------- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 1 + 4 files changed, 234 insertions(+), 753 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 2e4bc3d2b43..d95d2f274cb 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -687,6 +687,14 @@ _base_unmask_interrupts(struct MPT2SAS_ADAPTER *ioc) ioc->mask_interrupts = 0; } +union reply_descriptor { + u64 word; + struct { + u32 low; + u32 high; + } u; +}; + /** * _base_interrupt - MPT adapter (IOC) specific interrupt handler. * @irq: irq number (not used) @@ -698,47 +706,38 @@ _base_unmask_interrupts(struct MPT2SAS_ADAPTER *ioc) static irqreturn_t _base_interrupt(int irq, void *bus_id) { - union reply_descriptor { - u64 word; - struct { - u32 low; - u32 high; - } u; - }; union reply_descriptor rd; - u32 post_index, post_index_next, completed_cmds; + u32 completed_cmds; u8 request_desript_type; u16 smid; u8 cb_idx; u32 reply; u8 VF_ID; - int i; struct MPT2SAS_ADAPTER *ioc = bus_id; + Mpi2ReplyDescriptorsUnion_t *rpf; if (ioc->mask_interrupts) return IRQ_NONE; - post_index = ioc->reply_post_host_index; - request_desript_type = ioc->reply_post_free[post_index]. - Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; + rpf = &ioc->reply_post_free[ioc->reply_post_host_index]; + request_desript_type = rpf->Default.ReplyFlags + & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) return IRQ_NONE; completed_cmds = 0; do { - rd.word = ioc->reply_post_free[post_index].Words; + rd.word = rpf->Words; if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX) goto out; reply = 0; cb_idx = 0xFF; - smid = le16_to_cpu(ioc->reply_post_free[post_index]. - Default.DescriptorTypeDependent1); - VF_ID = ioc->reply_post_free[post_index]. - Default.VF_ID; + smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1); + VF_ID = rpf->Default.VF_ID; if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) { - reply = le32_to_cpu(ioc->reply_post_free[post_index]. - AddressReply.ReplyFrameAddress); + reply = le32_to_cpu + (rpf->AddressReply.ReplyFrameAddress); } else if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER) goto next; @@ -765,21 +764,27 @@ _base_interrupt(int irq, void *bus_id) 0 : ioc->reply_free_host_index + 1; ioc->reply_free[ioc->reply_free_host_index] = cpu_to_le32(reply); + wmb(); writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex); - wmb(); } next: - post_index_next = (post_index == (ioc->reply_post_queue_depth - - 1)) ? 0 : post_index + 1; + + rpf->Words = ULLONG_MAX; + ioc->reply_post_host_index = (ioc->reply_post_host_index == + (ioc->reply_post_queue_depth - 1)) ? 0 : + ioc->reply_post_host_index + 1; request_desript_type = - ioc->reply_post_free[post_index_next].Default.ReplyFlags - & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; + ioc->reply_post_free[ioc->reply_post_host_index].Default. + ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; completed_cmds++; if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) goto out; - post_index = post_index_next; + if (!ioc->reply_post_host_index) + rpf = ioc->reply_post_free; + else + rpf++; } while (1); out: @@ -787,19 +792,8 @@ _base_interrupt(int irq, void *bus_id) if (!completed_cmds) return IRQ_NONE; - /* reply post descriptor handling */ - post_index_next = ioc->reply_post_host_index; - for (i = 0 ; i < completed_cmds; i++) { - post_index = post_index_next; - /* poison the reply post descriptor */ - ioc->reply_post_free[post_index_next].Words = ULLONG_MAX; - post_index_next = (post_index == - (ioc->reply_post_queue_depth - 1)) - ? 0 : post_index + 1; - } - ioc->reply_post_host_index = post_index_next; - writel(post_index_next, &ioc->chip->ReplyPostHostIndex); wmb(); + writel(ioc->reply_post_host_index, &ioc->chip->ReplyPostHostIndex); return IRQ_HANDLED; } @@ -1650,7 +1644,7 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc) iounit_pg1_flags |= MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING; ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags); - mpt2sas_config_set_iounit_pg1(ioc, &mpi_reply, ioc->iounit_pg1); + mpt2sas_config_set_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); } /** @@ -3306,13 +3300,11 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) ioc->tm_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); ioc->tm_cmds.status = MPT2_CMD_NOT_USED; mutex_init(&ioc->tm_cmds.mutex); - init_completion(&ioc->tm_cmds.done); /* config page internal command bits */ ioc->config_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); ioc->config_cmds.status = MPT2_CMD_NOT_USED; mutex_init(&ioc->config_cmds.mutex); - init_completion(&ioc->config_cmds.done); /* ctl module internal command bits */ ioc->ctl_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); @@ -3436,6 +3428,7 @@ _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) if (ioc->config_cmds.status & MPT2_CMD_PENDING) { ioc->config_cmds.status |= MPT2_CMD_RESET; mpt2sas_base_free_smid(ioc, ioc->config_cmds.smid); + ioc->config_cmds.smid = USHORT_MAX; complete(&ioc->config_cmds.done); } break; diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index ff05ae1e43b..f4bf7ff8f48 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -785,7 +785,7 @@ int mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRep int mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page); int mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2IOUnitPage1_t config_page); + *mpi_reply, Mpi2IOUnitPage1_t *config_page); int mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz); int mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c index b9f4d0f97e5..ab8c560865d 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_config.c +++ b/drivers/scsi/mpt2sas/mpt2sas_config.c @@ -72,15 +72,15 @@ /** * struct config_request - obtain dma memory via routine - * @config_page_sz: size - * @config_page: virt pointer - * @config_page_dma: phys pointer + * @sz: size + * @page: virt pointer + * @page_dma: phys pointer * */ struct config_request{ - u16 config_page_sz; - void *config_page; - dma_addr_t config_page_dma; + u16 sz; + void *page; + dma_addr_t page_dma; }; #ifdef CONFIG_SCSI_MPT2SAS_LOGGING @@ -174,6 +174,55 @@ _config_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid, } #endif +/** + * _config_alloc_config_dma_memory - obtain physical memory + * @ioc: per adapter object + * @mem: struct config_request + * + * A wrapper for obtaining dma-able memory for config page request. + * + * Returns 0 for success, non-zero for failure. + */ +static int +_config_alloc_config_dma_memory(struct MPT2SAS_ADAPTER *ioc, + struct config_request *mem) +{ + int r = 0; + + if (mem->sz > ioc->config_page_sz) { + mem->page = dma_alloc_coherent(&ioc->pdev->dev, mem->sz, + &mem->page_dma, GFP_KERNEL); + if (!mem->page) { + printk(MPT2SAS_ERR_FMT "%s: dma_alloc_coherent" + " failed asking for (%d) bytes!!\n", + ioc->name, __func__, mem->sz); + r = -ENOMEM; + } + } else { /* use tmp buffer if less than 512 bytes */ + mem->page = ioc->config_page; + mem->page_dma = ioc->config_page_dma; + } + return r; +} + +/** + * _config_free_config_dma_memory - wrapper to free the memory + * @ioc: per adapter object + * @mem: struct config_request + * + * A wrapper to free dma-able memory when using _config_alloc_config_dma_memory. + * + * Returns 0 for success, non-zero for failure. + */ +static void +_config_free_config_dma_memory(struct MPT2SAS_ADAPTER *ioc, + struct config_request *mem) +{ + if (mem->sz > ioc->config_page_sz) + dma_free_coherent(&ioc->pdev->dev, mem->sz, mem->page, + mem->page_dma); +} + /** * mpt2sas_config_done - config page completion routine * @ioc: per adapter object @@ -206,6 +255,7 @@ mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) #ifdef CONFIG_SCSI_MPT2SAS_LOGGING _config_display_some_debug(ioc, smid, "config_done", mpi_reply); #endif + ioc->config_cmds.smid = USHORT_MAX; complete(&ioc->config_cmds.done); } @@ -215,7 +265,9 @@ mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) * @mpi_request: request message frame * @mpi_reply: reply mf payload returned from firmware * @timeout: timeout in seconds - * Context: sleep, the calling function needs to acquire the config_cmds.mutex + * @config_page: contents of the config page + * @config_page_sz: size of config page + * Context: sleep * * A generic API for config page requests to firmware. * @@ -228,16 +280,17 @@ mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) */ static int _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t - *mpi_request, Mpi2ConfigReply_t *mpi_reply, int timeout) + *mpi_request, Mpi2ConfigReply_t *mpi_reply, int timeout, + void *config_page, u16 config_page_sz) { u16 smid; u32 ioc_state; unsigned long timeleft; Mpi2ConfigRequest_t *config_request; int r; - u8 retry_count; - u8 issue_host_reset = 0; + u8 retry_count, issue_host_reset = 0; u16 wait_state_count; + struct config_request mem; mutex_lock(&ioc->config_cmds.mutex); if (ioc->config_cmds.status != MPT2_CMD_NOT_USED) { @@ -246,12 +299,44 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t mutex_unlock(&ioc->config_cmds.mutex); return -EAGAIN; } + retry_count = 0; + memset(&mem, 0, sizeof(struct config_request)); + + if (config_page) { + mpi_request->Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request->Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request->Header.PageType = mpi_reply->Header.PageType; + mpi_request->Header.PageLength = mpi_reply->Header.PageLength; + mpi_request->ExtPageLength = mpi_reply->ExtPageLength; + mpi_request->ExtPageType = mpi_reply->ExtPageType; + if (mpi_request->Header.PageLength) + mem.sz = mpi_request->Header.PageLength * 4; + else + mem.sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r != 0) + goto out; + if (mpi_request->Action == + MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT) { + ioc->base_add_sg_single(&mpi_request->PageBufferSGE, + MPT2_CONFIG_COMMON_WRITE_SGLFLAGS | mem.sz, + mem.page_dma); + memcpy(mem.page, config_page, min_t(u16, mem.sz, + config_page_sz)); + } else { + memset(config_page, 0, config_page_sz); + ioc->base_add_sg_single(&mpi_request->PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.sz, mem.page_dma); + } + } retry_config: if (retry_count) { - if (retry_count > 2) /* attempt only 2 retries */ - return -EFAULT; + if (retry_count > 2) { /* attempt only 2 retries */ + r = -EFAULT; + goto free_mem; + } printk(MPT2SAS_INFO_FMT "%s: attempting retry (%d)\n", ioc->name, __func__, retry_count); } @@ -262,8 +347,9 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t printk(MPT2SAS_ERR_FMT "%s: failed due to ioc not operational\n", ioc->name, __func__); + ioc->config_cmds.status = MPT2_CMD_NOT_USED; r = -EFAULT; - goto out; + goto free_mem; } ssleep(1); ioc_state = mpt2sas_base_get_iocstate(ioc, 1); @@ -279,8 +365,9 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t if (!smid) { printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", ioc->name, __func__); + ioc->config_cmds.status = MPT2_CMD_NOT_USED; r = -EAGAIN; - goto out; + goto free_mem; } r = 0; @@ -292,6 +379,7 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t #ifdef CONFIG_SCSI_MPT2SAS_LOGGING _config_display_some_debug(ioc, smid, "config_request", NULL); #endif + init_completion(&ioc->config_cmds.done); mpt2sas_base_put_smid_default(ioc, smid, config_request->VF_ID); timeleft = wait_for_completion_timeout(&ioc->config_cmds.done, timeout*HZ); @@ -303,67 +391,37 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t retry_count++; if (ioc->config_cmds.smid == smid) mpt2sas_base_free_smid(ioc, smid); - if ((ioc->shost_recovery) || - (ioc->config_cmds.status & MPT2_CMD_RESET)) + if ((ioc->shost_recovery) || (ioc->config_cmds.status & + MPT2_CMD_RESET)) goto retry_config; issue_host_reset = 1; r = -EFAULT; - goto out; + goto free_mem; } + if (ioc->config_cmds.status & MPT2_CMD_REPLY_VALID) memcpy(mpi_reply, ioc->config_cmds.reply, sizeof(Mpi2ConfigReply_t)); if (retry_count) - printk(MPT2SAS_INFO_FMT "%s: retry completed!!\n", - ioc->name, __func__); -out: + printk(MPT2SAS_INFO_FMT "%s: retry (%d) completed!!\n", + ioc->name, __func__, retry_count); + if (config_page && mpi_request->Action == + MPI2_CONFIG_ACTION_PAGE_READ_CURRENT) + memcpy(config_page, mem.page, min_t(u16, mem.sz, + config_page_sz)); + free_mem: + if (config_page) + _config_free_config_dma_memory(ioc, &mem); + out: ioc->config_cmds.status = MPT2_CMD_NOT_USED; mutex_unlock(&ioc->config_cmds.mutex); + if (issue_host_reset) mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER); return r; } -/** - * _config_alloc_config_dma_memory - obtain physical memory - * @ioc: per adapter object - * @mem: struct config_request - * - * A wrapper for obtaining dma-able memory for config page request. - * - * Returns 0 for success, non-zero for failure. - */ -static int -_config_alloc_config_dma_memory(struct MPT2SAS_ADAPTER *ioc, - struct config_request *mem) -{ - int r = 0; - - mem->config_page = pci_alloc_consistent(ioc->pdev, mem->config_page_sz, - &mem->config_page_dma); - if (!mem->config_page) - r = -ENOMEM; - return r; -} - -/** - * _config_free_config_dma_memory - wrapper to free the memory - * @ioc: per adapter object - * @mem: struct config_request - * - * A wrapper to free dma-able memory when using _config_alloc_config_dma_memory. - * - * Returns 0 for success, non-zero for failure. - */ -static void -_config_free_config_dma_memory(struct MPT2SAS_ADAPTER *ioc, - struct config_request *mem) -{ - pci_free_consistent(ioc->pdev, mem->config_page_sz, mem->config_page, - mem->config_page_dma); -} - /** * mpt2sas_config_get_manufacturing_pg0 - obtain manufacturing page 0 * @ioc: per adapter object @@ -379,9 +437,7 @@ mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc, { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; - memset(config_page, 0, sizeof(Mpi2ManufacturingPage0_t)); memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; @@ -390,37 +446,14 @@ mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc, mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request.Header.PageType = mpi_reply->Header.PageType; - mpi_request.Header.PageLength = mpi_reply->Header.PageLength; - mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); - if (!r) - memcpy(config_page, mem.config_page, - min_t(u16, mem.config_page_sz, - sizeof(Mpi2ManufacturingPage0_t))); - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: return r; } @@ -440,9 +473,7 @@ mpt2sas_config_get_manufacturing_pg10(struct MPT2SAS_ADAPTER *ioc, { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; - memset(config_page, 0, sizeof(Mpi2ManufacturingPage10_t)); memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; @@ -451,37 +482,14 @@ mpt2sas_config_get_manufacturing_pg10(struct MPT2SAS_ADAPTER *ioc, mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request.Header.PageType = mpi_reply->Header.PageType; - mpi_request.Header.PageLength = mpi_reply->Header.PageLength; - mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); - if (!r) - memcpy(config_page, mem.config_page, - min_t(u16, mem.config_page_sz, - sizeof(Mpi2ManufacturingPage10_t))); - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: return r; } @@ -501,9 +509,7 @@ mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc, { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; - memset(config_page, 0, sizeof(Mpi2BiosPage2_t)); memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; @@ -512,37 +518,14 @@ mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc, mpi_request.Header.PageVersion = MPI2_BIOSPAGE2_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request.Header.PageType = mpi_reply->Header.PageType; - mpi_request.Header.PageLength = mpi_reply->Header.PageLength; - mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); - if (!r) - memcpy(config_page, mem.config_page, - min_t(u16, mem.config_page_sz, - sizeof(Mpi2BiosPage2_t))); - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: return r; } @@ -562,9 +545,7 @@ mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; - memset(config_page, 0, sizeof(Mpi2BiosPage3_t)); memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; @@ -573,37 +554,14 @@ mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t mpi_request.Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request.Header.PageType = mpi_reply->Header.PageType; - mpi_request.Header.PageLength = mpi_reply->Header.PageLength; - mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); - if (!r) - memcpy(config_page, mem.config_page, - min_t(u16, mem.config_page_sz, - sizeof(Mpi2BiosPage3_t))); - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: return r; } @@ -623,9 +581,7 @@ mpt2sas_config_get_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; - memset(config_page, 0, sizeof(Mpi2IOUnitPage0_t)); memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; @@ -634,37 +590,14 @@ mpt2sas_config_get_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, mpi_request.Header.PageVersion = MPI2_IOUNITPAGE0_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request.Header.PageType = mpi_reply->Header.PageType; - mpi_request.Header.PageLength = mpi_reply->Header.PageLength; - mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); - if (!r) - memcpy(config_page, mem.config_page, - min_t(u16, mem.config_page_sz, - sizeof(Mpi2IOUnitPage0_t))); - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: return r; } @@ -684,9 +617,7 @@ mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; - memset(config_page, 0, sizeof(Mpi2IOUnitPage1_t)); memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; @@ -695,37 +626,14 @@ mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, mpi_request.Header.PageVersion = MPI2_IOUNITPAGE1_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request.Header.PageType = mpi_reply->Header.PageType; - mpi_request.Header.PageLength = mpi_reply->Header.PageLength; - mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); - if (!r) - memcpy(config_page, mem.config_page, - min_t(u16, mem.config_page_sz, - sizeof(Mpi2IOUnitPage1_t))); - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: return r; } @@ -741,11 +649,10 @@ mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, */ int mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t config_page) + Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page) { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; @@ -755,38 +662,14 @@ mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, mpi_request.Header.PageVersion = MPI2_IOUNITPAGE1_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; - mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request.Header.PageType = mpi_reply->Header.PageType; - mpi_request.Header.PageLength = mpi_reply->Header.PageLength; - mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - - memset(mem.config_page, 0, mem.config_page_sz); - memcpy(mem.config_page, &config_page, - sizeof(Mpi2IOUnitPage1_t)); - - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_WRITE_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: return r; } @@ -806,9 +689,7 @@ mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; - memset(config_page, 0, sizeof(Mpi2IOCPage8_t)); memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; @@ -817,37 +698,14 @@ mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, mpi_request.Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request.Header.PageType = mpi_reply->Header.PageType; - mpi_request.Header.PageLength = mpi_reply->Header.PageLength; - mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); - if (!r) - memcpy(config_page, mem.config_page, - min_t(u16, mem.config_page_sz, - sizeof(Mpi2IOCPage8_t))); - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: return r; } @@ -869,9 +727,7 @@ mpt2sas_config_get_sas_device_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; - memset(config_page, 0, sizeof(Mpi2SasDevicePage0_t)); memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; @@ -881,39 +737,15 @@ mpt2sas_config_get_sas_device_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t mpi_request.Header.PageNumber = 0; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(form | handle); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request.Header.PageType = mpi_reply->Header.PageType; - mpi_request.ExtPageLength = mpi_reply->ExtPageLength; - mpi_request.ExtPageType = mpi_reply->ExtPageType; - mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); - if (!r) - memcpy(config_page, mem.config_page, - min_t(u16, mem.config_page_sz, - sizeof(Mpi2SasDevicePage0_t))); - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: return r; } @@ -935,9 +767,7 @@ mpt2sas_config_get_sas_device_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; - memset(config_page, 0, sizeof(Mpi2SasDevicePage1_t)); memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; @@ -947,39 +777,15 @@ mpt2sas_config_get_sas_device_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t mpi_request.Header.PageNumber = 1; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(form | handle); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request.Header.PageType = mpi_reply->Header.PageType; - mpi_request.ExtPageLength = mpi_reply->ExtPageLength; - mpi_request.ExtPageType = mpi_reply->ExtPageType; - mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); - if (!r) - memcpy(config_page, mem.config_page, - min_t(u16, mem.config_page_sz, - sizeof(Mpi2SasDevicePage1_t))); - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: return r; } @@ -997,11 +803,11 @@ mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys) { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; u16 ioc_status; Mpi2ConfigReply_t mpi_reply; Mpi2SasIOUnitPage0_t config_page; + *num_phys = 0; memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; @@ -1011,44 +817,20 @@ mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys) mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply.Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply.Header.PageNumber; - mpi_request.Header.PageType = mpi_reply.Header.PageType; - mpi_request.ExtPageLength = mpi_reply.ExtPageLength; - mpi_request.ExtPageType = mpi_reply.ExtPageType; - mem.config_page_sz = le16_to_cpu(mpi_reply.ExtPageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, &config_page, + sizeof(Mpi2SasIOUnitPage0_t)); if (!r) { ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { - memcpy(&config_page, mem.config_page, - min_t(u16, mem.config_page_sz, - sizeof(Mpi2SasIOUnitPage0_t))); + if (ioc_status == MPI2_IOCSTATUS_SUCCESS) *num_phys = config_page.NumPhys; - } } - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - out: return r; } @@ -1072,8 +854,7 @@ mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; - memset(config_page, 0, sz); + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; @@ -1083,37 +864,13 @@ mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request.Header.PageType = mpi_reply->Header.PageType; - mpi_request.ExtPageLength = mpi_reply->ExtPageLength; - mpi_request.ExtPageType = mpi_reply->ExtPageType; - mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); - if (!r) - memcpy(config_page, mem.config_page, - min_t(u16, sz, mem.config_page_sz)); - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); out: return r; } @@ -1137,9 +894,7 @@ mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; - memset(config_page, 0, sz); memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; @@ -1149,37 +904,13 @@ mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request.Header.PageType = mpi_reply->Header.PageType; - mpi_request.ExtPageLength = mpi_reply->ExtPageLength; - mpi_request.ExtPageType = mpi_reply->ExtPageType; - mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); - if (!r) - memcpy(config_page, mem.config_page, - min_t(u16, sz, mem.config_page_sz)); - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); out: return r; } @@ -1201,9 +932,7 @@ mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; - memset(config_page, 0, sizeof(Mpi2ExpanderPage0_t)); memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; @@ -1213,39 +942,15 @@ mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t mpi_request.Header.PageVersion = MPI2_SASEXPANDER0_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(form | handle); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request.Header.PageType = mpi_reply->Header.PageType; - mpi_request.ExtPageLength = mpi_reply->ExtPageLength; - mpi_request.ExtPageType = mpi_reply->ExtPageType; - mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); - if (!r) - memcpy(config_page, mem.config_page, - min_t(u16, mem.config_page_sz, - sizeof(Mpi2ExpanderPage0_t))); - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: return r; } @@ -1268,9 +973,7 @@ mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; - memset(config_page, 0, sizeof(Mpi2ExpanderPage1_t)); memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; @@ -1280,7 +983,7 @@ mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t mpi_request.Header.PageVersion = MPI2_SASEXPANDER1_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; @@ -1288,33 +991,9 @@ mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t cpu_to_le32(MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM | (phy_number << MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) | handle); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request.Header.PageType = mpi_reply->Header.PageType; - mpi_request.ExtPageLength = mpi_reply->ExtPageLength; - mpi_request.ExtPageType = mpi_reply->ExtPageType; - mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); - if (!r) - memcpy(config_page, mem.config_page, - min_t(u16, mem.config_page_sz, - sizeof(Mpi2ExpanderPage1_t))); - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: return r; } @@ -1336,9 +1015,7 @@ mpt2sas_config_get_enclosure_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; - memset(config_page, 0, sizeof(Mpi2SasEnclosurePage0_t)); memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; @@ -1348,39 +1025,15 @@ mpt2sas_config_get_enclosure_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t mpi_request.Header.PageVersion = MPI2_SASENCLOSURE0_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(form | handle); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request.Header.PageType = mpi_reply->Header.PageType; - mpi_request.ExtPageLength = mpi_reply->ExtPageLength; - mpi_request.ExtPageType = mpi_reply->ExtPageType; - mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); - if (!r) - memcpy(config_page, mem.config_page, - min_t(u16, mem.config_page_sz, - sizeof(Mpi2SasEnclosurePage0_t))); - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: return r; } @@ -1401,9 +1054,7 @@ mpt2sas_config_get_phy_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; - memset(config_page, 0, sizeof(Mpi2SasPhyPage0_t)); memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; @@ -1413,40 +1064,16 @@ mpt2sas_config_get_phy_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t mpi_request.Header.PageVersion = MPI2_SASPHY0_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request.Header.PageType = mpi_reply->Header.PageType; - mpi_request.ExtPageLength = mpi_reply->ExtPageLength; - mpi_request.ExtPageType = mpi_reply->ExtPageType; - mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); - if (!r) - memcpy(config_page, mem.config_page, - min_t(u16, mem.config_page_sz, - sizeof(Mpi2SasPhyPage0_t))); - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: return r; } @@ -1467,9 +1094,7 @@ mpt2sas_config_get_phy_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; - memset(config_page, 0, sizeof(Mpi2SasPhyPage1_t)); memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; @@ -1479,40 +1104,16 @@ mpt2sas_config_get_phy_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t mpi_request.Header.PageVersion = MPI2_SASPHY1_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request.Header.PageType = mpi_reply->Header.PageType; - mpi_request.ExtPageLength = mpi_reply->ExtPageLength; - mpi_request.ExtPageType = mpi_reply->ExtPageType; - mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); - if (!r) - memcpy(config_page, mem.config_page, - min_t(u16, mem.config_page_sz, - sizeof(Mpi2SasPhyPage1_t))); - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: return r; } @@ -1535,9 +1136,7 @@ mpt2sas_config_get_raid_volume_pg1(struct MPT2SAS_ADAPTER *ioc, { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; - memset(config_page, 0, sizeof(Mpi2RaidVolPage1_t)); memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; @@ -1546,38 +1145,15 @@ mpt2sas_config_get_raid_volume_pg1(struct MPT2SAS_ADAPTER *ioc, mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(form | handle); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request.Header.PageType = mpi_reply->Header.PageType; - mpi_request.Header.PageLength = mpi_reply->Header.PageLength; - mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); - if (!r) - memcpy(config_page, mem.config_page, - min_t(u16, mem.config_page_sz, - sizeof(Mpi2RaidVolPage1_t))); - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: return r; } @@ -1596,10 +1172,9 @@ mpt2sas_config_get_number_pds(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 *num_pds) { Mpi2ConfigRequest_t mpi_request; - Mpi2RaidVolPage0_t *config_page; + Mpi2RaidVolPage0_t config_page; Mpi2ConfigReply_t mpi_reply; int r; - struct config_request mem; u16 ioc_status; memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); @@ -1611,43 +1186,23 @@ mpt2sas_config_get_number_pds(struct MPT2SAS_ADAPTER *ioc, u16 handle, mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(MPI2_RAID_VOLUME_PGAD_FORM_HANDLE | handle); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply.Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply.Header.PageNumber; - mpi_request.Header.PageType = mpi_reply.Header.PageType; - mpi_request.Header.PageLength = mpi_reply.Header.PageLength; - mem.config_page_sz = le16_to_cpu(mpi_reply.Header.PageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, &config_page, + sizeof(Mpi2RaidVolPage0_t)); if (!r) { ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { - config_page = mem.config_page; - *num_pds = config_page->NumPhysDisks; - } + if (ioc_status == MPI2_IOCSTATUS_SUCCESS) + *num_pds = config_page.NumPhysDisks; } - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - out: return r; } @@ -1671,10 +1226,8 @@ mpt2sas_config_get_raid_volume_pg0(struct MPT2SAS_ADAPTER *ioc, { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - memset(config_page, 0, sz); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; @@ -1682,37 +1235,14 @@ mpt2sas_config_get_raid_volume_pg0(struct MPT2SAS_ADAPTER *ioc, mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(form | handle); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request.Header.PageType = mpi_reply->Header.PageType; - mpi_request.Header.PageLength = mpi_reply->Header.PageLength; - mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); - if (!r) - memcpy(config_page, mem.config_page, - min_t(u16, sz, mem.config_page_sz)); - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); out: return r; } @@ -1735,10 +1265,8 @@ mpt2sas_config_get_phys_disk_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { Mpi2ConfigRequest_t mpi_request; int r; - struct config_request mem; memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - memset(config_page, 0, sizeof(Mpi2RaidPhysDiskPage0_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK; @@ -1746,38 +1274,15 @@ mpt2sas_config_get_phys_disk_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t mpi_request.Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(form | form_specific); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request.Header.PageType = mpi_reply->Header.PageType; - mpi_request.Header.PageLength = mpi_reply->Header.PageLength; - mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); - if (!r) - memcpy(config_page, mem.config_page, - min_t(u16, mem.config_page_sz, - sizeof(Mpi2RaidPhysDiskPage0_t))); - - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: return r; } @@ -1795,11 +1300,10 @@ int mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle, u16 *volume_handle) { - Mpi2RaidConfigurationPage0_t *config_page; + Mpi2RaidConfigurationPage0_t *config_page = NULL; Mpi2ConfigRequest_t mpi_request; Mpi2ConfigReply_t mpi_reply; - int r, i; - struct config_request mem; + int r, i, config_page_sz; u16 ioc_status; *volume_handle = 0; @@ -1812,40 +1316,27 @@ mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle, mpi_request.Header.PageNumber = 0; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(MPI2_RAID_PGAD_FORM_ACTIVE_CONFIG); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - mpi_request.Header.PageVersion = mpi_reply.Header.PageVersion; - mpi_request.Header.PageNumber = mpi_reply.Header.PageNumber; - mpi_request.Header.PageType = mpi_reply.Header.PageType; - mpi_request.ExtPageLength = mpi_reply.ExtPageLength; - mpi_request.ExtPageType = mpi_reply.ExtPageType; - mem.config_page_sz = le16_to_cpu(mpi_reply.ExtPageLength) * 4; - if (mem.config_page_sz > ioc->config_page_sz) { - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r) - goto out; - } else { - mem.config_page_dma = ioc->config_page_dma; - mem.config_page = ioc->config_page; - } - ioc->base_add_sg_single(&mpi_request.PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz, - mem.config_page_dma); + config_page_sz = (le16_to_cpu(mpi_reply.ExtPageLength) * 4); + config_page = kmalloc(config_page_sz, GFP_KERNEL); + if (!config_page) + goto out; r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + config_page_sz); if (r) goto out; r = -1; ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - goto done; - config_page = mem.config_page; + goto out; for (i = 0; i < config_page->NumElements; i++) { if ((config_page->ConfigElement[i].ElementFlags & MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE) != @@ -1856,15 +1347,11 @@ mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle, *volume_handle = le16_to_cpu(config_page-> ConfigElement[i].VolDevHandle); r = 0; - goto done; + goto out; } } - - done: - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - out: + kfree(config_page); return r; } diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index e71a6c04298..774b34525bb 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -1836,6 +1836,7 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun, mpi_request->TaskMID = cpu_to_le16(smid_task); int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN); mpt2sas_scsih_set_tm_flag(ioc, handle); + init_completion(&ioc->tm_cmds.done); mpt2sas_base_put_smid_hi_priority(ioc, smid, VF_ID); timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ); mpt2sas_scsih_clear_tm_flag(ioc, handle); -- cgit v1.2.3-18-g5258 From dc162b63bfc4201ca5c13df3fc8836c56979eb07 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 20 Aug 2009 13:25:03 +0530 Subject: [SCSI] mpt2sas: Bump driver version 01.100.06.00 Bump version to 01.100.06.00 Signed-off-by: Kashyap Desai Reviewed-by:: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index f4bf7ff8f48..2faab1e690e 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -69,10 +69,10 @@ #define MPT2SAS_DRIVER_NAME "mpt2sas" #define MPT2SAS_AUTHOR "LSI Corporation " #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" -#define MPT2SAS_DRIVER_VERSION "01.100.04.00" +#define MPT2SAS_DRIVER_VERSION "01.100.06.00" #define MPT2SAS_MAJOR_VERSION 01 #define MPT2SAS_MINOR_VERSION 100 -#define MPT2SAS_BUILD_VERSION 04 +#define MPT2SAS_BUILD_VERSION 06 #define MPT2SAS_RELEASE_VERSION 00 /* -- cgit v1.2.3-18-g5258 From cf53b069f52ae3f83dec1acd339e3c3a2e979478 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Thu, 20 Aug 2009 11:06:04 -0700 Subject: [SCSI] qla2xxx: Generalize srb structure usage. Lay groundwork for adding alternative asynchronous operations by generalize and extending the SRB structure. This allows for follow-on patches to add support for: - Asynchronous logins. - ELS/CT passthru requests. - Loopback requests. - Non-blocking mailbox commands (ABTS, Task Management, etc). Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 3 +++ drivers/scsi/qla2xxx/qla_iocb.c | 2 ++ drivers/scsi/qla2xxx/qla_os.c | 11 +++++++++-- 3 files changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 68ab28c8152..9eb7be684f0 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -189,6 +189,7 @@ struct req_que; */ typedef struct srb { struct fc_port *fcport; + uint32_t handle; struct scsi_cmnd *cmd; /* Linux SCSI command pkt */ @@ -196,6 +197,8 @@ typedef struct srb { uint32_t request_sense_length; uint8_t *request_sense_ptr; + + void *ctx; } srb_t; /* diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index c0ba370b23c..d37554ecd31 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -350,6 +350,7 @@ qla2x00_start_scsi(srb_t *sp) /* Build command packet */ req->current_outstanding_cmd = handle; req->outstanding_cmds[handle] = sp; + sp->handle = handle; sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle; req->cnt -= req_cnt; @@ -778,6 +779,7 @@ qla24xx_start_scsi(srb_t *sp) /* Build command packet. */ req->current_outstanding_cmd = handle; req->outstanding_cmds[handle] = sp; + sp->handle = handle; sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle; req->cnt -= req_cnt; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index d7b271339a5..b6c088caf35 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -473,6 +473,7 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport, sp->flags = 0; CMD_SP(cmd) = (void *)sp; cmd->scsi_done = done; + sp->ctx = NULL; return sp; } @@ -709,6 +710,8 @@ qla2x00_abort_fcport_cmds(fc_port_t *fcport) continue; if (sp->fcport != fcport) continue; + if (sp->ctx) + continue; spin_unlock_irqrestore(&ha->hardware_lock, flags); if (ha->isp_ops->abort_command(sp)) { @@ -794,7 +797,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) if (sp == NULL) continue; - + if (sp->ctx) + continue; if (sp->cmd != cmd) continue; @@ -859,7 +863,8 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t, sp = req->outstanding_cmds[cnt]; if (!sp) continue; - + if (sp->ctx) + continue; if (vha->vp_idx != sp->fcport->vha->vp_idx) continue; match = 0; @@ -2986,6 +2991,8 @@ qla2x00_timer(scsi_qla_host_t *vha) sp = req->outstanding_cmds[index]; if (!sp) continue; + if (sp->ctx) + continue; sfcp = sp->fcport; if (!(sfcp->flags & FCF_TAPE_PRESENT)) continue; -- cgit v1.2.3-18-g5258 From ac280b670e6d6666667aba02324e2fc50bd96ae7 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Thu, 20 Aug 2009 11:06:05 -0700 Subject: [SCSI] qla2xxx: Add asynchronous-login support. ISPs which support this feature include 23xx and above. Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 32 +++++ drivers/scsi/qla2xxx/qla_gbl.h | 20 ++++ drivers/scsi/qla2xxx/qla_init.c | 215 +++++++++++++++++++++++++++++++++- drivers/scsi/qla2xxx/qla_iocb.c | 202 ++++++++++++++++++++++++++++++++ drivers/scsi/qla2xxx/qla_isr.c | 250 ++++++++++++++++++++++++++++++++++++++++ drivers/scsi/qla2xxx/qla_mid.c | 2 + drivers/scsi/qla2xxx/qla_os.c | 72 +++++++++++- 7 files changed, 784 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 9eb7be684f0..efdfb1eb26b 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -206,6 +206,28 @@ typedef struct srb { */ #define SRB_DMA_VALID BIT_0 /* Command sent to ISP */ +/* + * SRB extensions. + */ +struct srb_ctx { +#define SRB_LOGIN_CMD 1 +#define SRB_LOGOUT_CMD 2 + uint16_t type; + struct timer_list timer; + + void (*free)(srb_t *sp); + void (*timeout)(srb_t *sp); +}; + +struct srb_logio { + struct srb_ctx ctx; + +#define SRB_LOGIN_RETRIED BIT_0 +#define SRB_LOGIN_COND_PLOGI BIT_1 +#define SRB_LOGIN_SKIP_PRLI BIT_2 + uint16_t flags; +}; + /* * ISP I/O Register Set structure definitions. */ @@ -2096,6 +2118,10 @@ struct qla_msix_entry { enum qla_work_type { QLA_EVT_AEN, QLA_EVT_IDC_ACK, + QLA_EVT_ASYNC_LOGIN, + QLA_EVT_ASYNC_LOGIN_DONE, + QLA_EVT_ASYNC_LOGOUT, + QLA_EVT_ASYNC_LOGOUT_DONE, }; @@ -2114,6 +2140,11 @@ struct qla_work_evt { #define QLA_IDC_ACK_REGS 7 uint16_t mb[QLA_IDC_ACK_REGS]; } idc_ack; + struct { + struct fc_port *fcport; +#define QLA_LOGIO_LOGIN_RETRIED BIT_0 + u16 data[2]; + } logio; } u; }; @@ -2354,6 +2385,7 @@ struct qla_hw_data { (ha)->flags.msix_enabled) #define IS_FAC_REQUIRED(ha) (IS_QLA81XX(ha)) #define IS_NOCACHE_VPD_TYPE(ha) (IS_QLA81XX(ha)) +#define IS_ALOGIO_CAPABLE(ha) (IS_QLA23XX(ha) || IS_FWI2_CAPABLE(ha)) #define IS_IIDMA_CAPABLE(ha) ((ha)->device_type & DT_IIDMA) #define IS_FWI2_CAPABLE(ha) ((ha)->device_type & DT_FWI2) diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 65b12d82867..f3d1d1afa95 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -52,6 +52,14 @@ extern void qla2x00_try_to_stop_firmware(scsi_qla_host_t *); extern void qla84xx_put_chip(struct scsi_qla_host *); +extern int qla2x00_async_login(struct scsi_qla_host *, fc_port_t *, + uint16_t *); +extern int qla2x00_async_logout(struct scsi_qla_host *, fc_port_t *); +extern int qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *, + uint16_t *); +extern int qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *, + uint16_t *); + /* * Global Data in qla_os.c source file. */ @@ -76,6 +84,15 @@ extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); extern int qla2x00_post_aen_work(struct scsi_qla_host *, enum fc_host_event_code, u32); extern int qla2x00_post_idc_ack_work(struct scsi_qla_host *, uint16_t *); +extern int qla2x00_post_async_login_work(struct scsi_qla_host *, fc_port_t *, + uint16_t *); +extern int qla2x00_post_async_login_done_work(struct scsi_qla_host *, + fc_port_t *, uint16_t *); +extern int qla2x00_post_async_logout_work(struct scsi_qla_host *, fc_port_t *, + uint16_t *); +extern int qla2x00_post_async_logout_done_work(struct scsi_qla_host *, + fc_port_t *, uint16_t *); + extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *); extern void qla2x00_abort_fcport_cmds(fc_port_t *); @@ -83,6 +100,8 @@ extern struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *, struct qla_hw_data *); extern void qla2x00_free_host(struct scsi_qla_host *); extern void qla2x00_relogin(struct scsi_qla_host *); +extern void qla2x00_do_work(struct scsi_qla_host *); + /* * Global Functions in qla_mid.c source file. */ @@ -135,6 +154,7 @@ int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *, uint16_t, uint16_t, uint8_t); int __qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *, uint16_t, uint16_t, uint8_t); +extern int qla2x00_start_sp(srb_t *); /* * Global Function Prototypes in qla_mbx.c source file. diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 0cbe39e9250..37c99a27874 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -40,6 +40,210 @@ static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *); static int qla84xx_init_chip(scsi_qla_host_t *); static int qla25xx_init_queues(struct qla_hw_data *); +/* SRB Extensions ---------------------------------------------------------- */ + +static void +qla2x00_ctx_sp_timeout(unsigned long __data) +{ + srb_t *sp = (srb_t *)__data; + struct srb_ctx *ctx; + fc_port_t *fcport = sp->fcport; + struct qla_hw_data *ha = fcport->vha->hw; + struct req_que *req; + unsigned long flags; + + spin_lock_irqsave(&ha->hardware_lock, flags); + req = ha->req_q_map[0]; + req->outstanding_cmds[sp->handle] = NULL; + ctx = sp->ctx; + ctx->timeout(sp); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + ctx->free(sp); +} + +static void +qla2x00_ctx_sp_free(srb_t *sp) +{ + struct srb_ctx *ctx = sp->ctx; + + kfree(ctx); + mempool_free(sp, sp->fcport->vha->hw->srb_mempool); +} + +inline srb_t * +qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size, + unsigned long tmo) +{ + srb_t *sp; + struct qla_hw_data *ha = vha->hw; + struct srb_ctx *ctx; + + sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL); + if (!sp) + goto done; + ctx = kzalloc(size, GFP_KERNEL); + if (!ctx) { + mempool_free(sp, ha->srb_mempool); + goto done; + } + + memset(sp, 0, sizeof(*sp)); + sp->fcport = fcport; + sp->ctx = ctx; + ctx->free = qla2x00_ctx_sp_free; + + init_timer(&ctx->timer); + if (!tmo) + goto done; + ctx->timer.expires = jiffies + tmo * HZ; + ctx->timer.data = (unsigned long)sp; + ctx->timer.function = qla2x00_ctx_sp_timeout; + add_timer(&ctx->timer); +done: + return sp; +} + +/* Asynchronous Login/Logout Routines -------------------------------------- */ + +#define ELS_TMO_2_RATOV(ha) ((ha)->r_a_tov / 10 * 2) + +static void +qla2x00_async_logio_timeout(srb_t *sp) +{ + fc_port_t *fcport = sp->fcport; + struct srb_logio *lio = sp->ctx; + + DEBUG2(printk(KERN_WARNING + "scsi(%ld:%x): Async-%s timeout.\n", + fcport->vha->host_no, sp->handle, + lio->ctx.type == SRB_LOGIN_CMD ? "login": "logout")); + + if (lio->ctx.type == SRB_LOGIN_CMD) + qla2x00_post_async_logout_work(fcport->vha, fcport, NULL); +} + +int +qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, + uint16_t *data) +{ + struct qla_hw_data *ha = vha->hw; + srb_t *sp; + struct srb_logio *lio; + int rval; + + rval = QLA_FUNCTION_FAILED; + sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_logio), + ELS_TMO_2_RATOV(ha) + 2); + if (!sp) + goto done; + + lio = sp->ctx; + lio->ctx.type = SRB_LOGIN_CMD; + lio->ctx.timeout = qla2x00_async_logio_timeout; + lio->flags |= SRB_LOGIN_COND_PLOGI; + if (data[1] & QLA_LOGIO_LOGIN_RETRIED) + lio->flags |= SRB_LOGIN_RETRIED; + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; + + DEBUG2(printk(KERN_DEBUG + "scsi(%ld:%x): Async-login - loop-id=%x portid=%02x%02x%02x " + "retries=%d.\n", fcport->vha->host_no, sp->handle, fcport->loop_id, + fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, + fcport->login_retry)); + return rval; + +done_free_sp: + del_timer_sync(&lio->ctx.timer); + lio->ctx.free(sp); +done: + return rval; +} + +int +qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport) +{ + struct qla_hw_data *ha = vha->hw; + srb_t *sp; + struct srb_logio *lio; + int rval; + + rval = QLA_FUNCTION_FAILED; + sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_logio), + ELS_TMO_2_RATOV(ha) + 2); + if (!sp) + goto done; + + lio = sp->ctx; + lio->ctx.type = SRB_LOGOUT_CMD; + lio->ctx.timeout = qla2x00_async_logio_timeout; + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; + + DEBUG2(printk(KERN_DEBUG + "scsi(%ld:%x): Async-logout - loop-id=%x portid=%02x%02x%02x.\n", + fcport->vha->host_no, sp->handle, fcport->loop_id, + fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa)); + return rval; + +done_free_sp: + del_timer_sync(&lio->ctx.timer); + lio->ctx.free(sp); +done: + return rval; +} + +int +qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport, + uint16_t *data) +{ + int rval; + uint8_t opts = 0; + + switch (data[0]) { + case MBS_COMMAND_COMPLETE: + if (fcport->flags & FCF_TAPE_PRESENT) + opts |= BIT_1; + rval = qla2x00_get_port_database(vha, fcport, opts); + if (rval != QLA_SUCCESS) + qla2x00_mark_device_lost(vha, fcport, 1, 0); + else + qla2x00_update_fcport(vha, fcport); + break; + case MBS_COMMAND_ERROR: + if (data[1] & QLA_LOGIO_LOGIN_RETRIED) + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + else + qla2x00_mark_device_lost(vha, fcport, 1, 0); + break; + case MBS_PORT_ID_USED: + fcport->loop_id = data[1]; + qla2x00_post_async_login_work(vha, fcport, NULL); + break; + case MBS_LOOP_ID_USED: + fcport->loop_id++; + rval = qla2x00_find_new_loop_id(vha, fcport); + if (rval != QLA_SUCCESS) { + qla2x00_mark_device_lost(vha, fcport, 1, 0); + break; + } + qla2x00_post_async_login_work(vha, fcport, NULL); + break; + } + return QLA_SUCCESS; +} + +int +qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport, + uint16_t *data) +{ + qla2x00_mark_device_lost(vha, fcport, 1, 0); + return QLA_SUCCESS; +} + /****************************************************************************/ /* QLogic ISP2x00 Hardware Support Functions. */ /****************************************************************************/ @@ -1977,7 +2181,7 @@ qla2x00_rport_del(void *data) struct fc_rport *rport; spin_lock_irq(fcport->vha->host->host_lock); - rport = fcport->drport; + rport = fcport->drport ? fcport->drport: fcport->rport; fcport->drport = NULL; spin_unlock_irq(fcport->vha->host->host_lock); if (rport) @@ -2344,8 +2548,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport) struct fc_rport *rport; struct qla_hw_data *ha = vha->hw; - if (fcport->drport) - qla2x00_rport_del(fcport); + qla2x00_rport_del(fcport); rport_ids.node_name = wwn_to_u64(fcport->node_name); rport_ids.port_name = wwn_to_u64(fcport->port_name); @@ -3038,6 +3241,12 @@ qla2x00_fabric_dev_login(scsi_qla_host_t *vha, fc_port_t *fcport, rval = QLA_SUCCESS; retry = 0; + if (IS_ALOGIO_CAPABLE(ha)) { + rval = qla2x00_post_async_login_work(vha, fcport, NULL); + if (!rval) + return rval; + } + rval = qla2x00_fabric_login(vha, fcport, next_loopid); if (rval == QLA_SUCCESS) { /* Send an ADISC to tape devices.*/ diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index d37554ecd31..c5ccac0bef7 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -860,3 +860,205 @@ static void qla25xx_set_que(srb_t *sp, struct rsp_que **rsp) else *rsp = ha->rsp_q_map[0]; } + +/* Generic Control-SRB manipulation functions. */ + +static void * +qla2x00_alloc_iocbs(srb_t *sp) +{ + scsi_qla_host_t *vha = sp->fcport->vha; + struct qla_hw_data *ha = vha->hw; + struct req_que *req = ha->req_q_map[0]; + device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id); + uint32_t index, handle; + request_t *pkt; + uint16_t cnt, req_cnt; + + pkt = NULL; + req_cnt = 1; + + /* Check for room in outstanding command list. */ + handle = req->current_outstanding_cmd; + for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) { + handle++; + if (handle == MAX_OUTSTANDING_COMMANDS) + handle = 1; + if (!req->outstanding_cmds[handle]) + break; + } + if (index == MAX_OUTSTANDING_COMMANDS) + goto queuing_error; + + /* Check for room on request queue. */ + if (req->cnt < req_cnt) { + if (ha->mqenable) + cnt = RD_REG_DWORD(®->isp25mq.req_q_out); + else if (IS_FWI2_CAPABLE(ha)) + cnt = RD_REG_DWORD(®->isp24.req_q_out); + else + cnt = qla2x00_debounce_register( + ISP_REQ_Q_OUT(ha, ®->isp)); + + if (req->ring_index < cnt) + req->cnt = cnt - req->ring_index; + else + req->cnt = req->length - + (req->ring_index - cnt); + } + if (req->cnt < req_cnt) + goto queuing_error; + + /* Prep packet */ + req->current_outstanding_cmd = handle; + req->outstanding_cmds[handle] = sp; + req->cnt -= req_cnt; + + pkt = req->ring_ptr; + memset(pkt, 0, REQUEST_ENTRY_SIZE); + pkt->entry_count = req_cnt; + pkt->handle = handle; + sp->handle = handle; + +queuing_error: + return pkt; +} + +static void +qla2x00_start_iocbs(srb_t *sp) +{ + struct qla_hw_data *ha = sp->fcport->vha->hw; + struct req_que *req = ha->req_q_map[0]; + device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id); + struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp; + + /* Adjust ring index. */ + req->ring_index++; + if (req->ring_index == req->length) { + req->ring_index = 0; + req->ring_ptr = req->ring; + } else + req->ring_ptr++; + + /* Set chip new ring index. */ + if (ha->mqenable) { + WRT_REG_DWORD(®->isp25mq.req_q_in, req->ring_index); + RD_REG_DWORD(&ioreg->hccr); + } else if (IS_FWI2_CAPABLE(ha)) { + WRT_REG_DWORD(®->isp24.req_q_in, req->ring_index); + RD_REG_DWORD_RELAXED(®->isp24.req_q_in); + } else { + WRT_REG_WORD(ISP_REQ_Q_IN(ha, ®->isp), req->ring_index); + RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, ®->isp)); + } +} + +static void +qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio) +{ + struct srb_logio *lio = sp->ctx; + + logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; + logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI); + if (lio->flags & SRB_LOGIN_COND_PLOGI) + logio->control_flags |= cpu_to_le16(LCF_COND_PLOGI); + if (lio->flags & SRB_LOGIN_SKIP_PRLI) + logio->control_flags |= cpu_to_le16(LCF_SKIP_PRLI); + logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); + logio->port_id[0] = sp->fcport->d_id.b.al_pa; + logio->port_id[1] = sp->fcport->d_id.b.area; + logio->port_id[2] = sp->fcport->d_id.b.domain; + logio->vp_index = sp->fcport->vp_idx; +} + +static void +qla2x00_login_iocb(srb_t *sp, struct mbx_entry *mbx) +{ + struct qla_hw_data *ha = sp->fcport->vha->hw; + struct srb_logio *lio = sp->ctx; + uint16_t opts; + + mbx->entry_type = MBX_IOCB_TYPE;; + SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id); + mbx->mb0 = cpu_to_le16(MBC_LOGIN_FABRIC_PORT); + opts = lio->flags & SRB_LOGIN_COND_PLOGI ? BIT_0: 0; + opts |= lio->flags & SRB_LOGIN_SKIP_PRLI ? BIT_1: 0; + if (HAS_EXTENDED_IDS(ha)) { + mbx->mb1 = cpu_to_le16(sp->fcport->loop_id); + mbx->mb10 = cpu_to_le16(opts); + } else { + mbx->mb1 = cpu_to_le16((sp->fcport->loop_id << 8) | opts); + } + mbx->mb2 = cpu_to_le16(sp->fcport->d_id.b.domain); + mbx->mb3 = cpu_to_le16(sp->fcport->d_id.b.area << 8 | + sp->fcport->d_id.b.al_pa); + mbx->mb9 = cpu_to_le16(sp->fcport->vp_idx); +} + +static void +qla24xx_logout_iocb(srb_t *sp, struct logio_entry_24xx *logio) +{ + logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; + logio->control_flags = + cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO); + logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); + logio->port_id[0] = sp->fcport->d_id.b.al_pa; + logio->port_id[1] = sp->fcport->d_id.b.area; + logio->port_id[2] = sp->fcport->d_id.b.domain; + logio->vp_index = sp->fcport->vp_idx; +} + +static void +qla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx) +{ + struct qla_hw_data *ha = sp->fcport->vha->hw; + + mbx->entry_type = MBX_IOCB_TYPE;; + SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id); + mbx->mb0 = cpu_to_le16(MBC_LOGOUT_FABRIC_PORT); + mbx->mb1 = HAS_EXTENDED_IDS(ha) ? + cpu_to_le16(sp->fcport->loop_id): + cpu_to_le16(sp->fcport->loop_id << 8); + mbx->mb2 = cpu_to_le16(sp->fcport->d_id.b.domain); + mbx->mb3 = cpu_to_le16(sp->fcport->d_id.b.area << 8 | + sp->fcport->d_id.b.al_pa); + mbx->mb9 = cpu_to_le16(sp->fcport->vp_idx); + /* Implicit: mbx->mbx10 = 0. */ +} + +int +qla2x00_start_sp(srb_t *sp) +{ + int rval; + struct qla_hw_data *ha = sp->fcport->vha->hw; + void *pkt; + struct srb_ctx *ctx = sp->ctx; + unsigned long flags; + + rval = QLA_FUNCTION_FAILED; + spin_lock_irqsave(&ha->hardware_lock, flags); + pkt = qla2x00_alloc_iocbs(sp); + if (!pkt) + goto done; + + rval = QLA_SUCCESS; + switch (ctx->type) { + case SRB_LOGIN_CMD: + IS_FWI2_CAPABLE(ha) ? + qla24xx_login_iocb(sp, pkt): + qla2x00_login_iocb(sp, pkt); + break; + case SRB_LOGOUT_CMD: + IS_FWI2_CAPABLE(ha) ? + qla24xx_logout_iocb(sp, pkt): + qla2x00_logout_iocb(sp, pkt); + break; + default: + break; + } + + wmb(); + qla2x00_start_iocbs(sp); +done: + spin_unlock_irqrestore(&ha->hardware_lock, flags); + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 74fa6f99204..c0fec6914b9 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -919,6 +919,249 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha, } } +static srb_t * +qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func, + struct req_que *req, void *iocb) +{ + struct qla_hw_data *ha = vha->hw; + sts_entry_t *pkt = iocb; + srb_t *sp = NULL; + uint16_t index; + + index = LSW(pkt->handle); + if (index >= MAX_OUTSTANDING_COMMANDS) { + qla_printk(KERN_WARNING, ha, + "%s: Invalid completion handle (%x).\n", func, index); + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + goto done; + } + sp = req->outstanding_cmds[index]; + if (!sp) { + qla_printk(KERN_WARNING, ha, + "%s: Invalid completion handle (%x) -- timed-out.\n", func, + index); + return sp; + } + if (sp->handle != index) { + qla_printk(KERN_WARNING, ha, + "%s: SRB handle (%x) mismatch %x.\n", func, sp->handle, + index); + return NULL; + } + req->outstanding_cmds[index] = NULL; +done: + return sp; +} + +static void +qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, + struct mbx_entry *mbx) +{ + const char func[] = "MBX-IOCB"; + const char *type; + struct qla_hw_data *ha = vha->hw; + fc_port_t *fcport; + srb_t *sp; + struct srb_logio *lio; + uint16_t data[2]; + + sp = qla2x00_get_sp_from_handle(vha, func, req, mbx); + if (!sp) + return; + + type = NULL; + lio = sp->ctx; + switch (lio->ctx.type) { + case SRB_LOGIN_CMD: + type = "login"; + break; + case SRB_LOGOUT_CMD: + type = "logout"; + break; + default: + qla_printk(KERN_WARNING, ha, + "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp, + lio->ctx.type); + return; + } + + del_timer(&lio->ctx.timer); + fcport = sp->fcport; + + data[0] = data[1] = 0; + if (mbx->entry_status) { + DEBUG2(printk(KERN_WARNING + "scsi(%ld:%x): Async-%s error entry - entry-status=%x " + "status=%x state-flag=%x status-flags=%x.\n", + fcport->vha->host_no, sp->handle, type, + mbx->entry_status, le16_to_cpu(mbx->status), + le16_to_cpu(mbx->state_flags), + le16_to_cpu(mbx->status_flags))); + DEBUG2(qla2x00_dump_buffer((uint8_t *)mbx, sizeof(*mbx))); + + data[0] = MBS_COMMAND_ERROR; + data[1] = lio->flags & SRB_LOGIN_RETRIED ? + QLA_LOGIO_LOGIN_RETRIED: 0; + goto done_post_logio_done_work; + } + + if (!mbx->status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) { + DEBUG2(printk(KERN_DEBUG + "scsi(%ld:%x): Async-%s complete - mbx1=%x.\n", + fcport->vha->host_no, sp->handle, type, + le16_to_cpu(mbx->mb1))); + + data[0] = MBS_COMMAND_COMPLETE; + if (lio->ctx.type == SRB_LOGIN_CMD && le16_to_cpu(mbx->mb1) & BIT_1) + fcport->flags |= FCF_TAPE_PRESENT; + + goto done_post_logio_done_work; + } + + data[0] = le16_to_cpu(mbx->mb0); + switch (data[0]) { + case MBS_PORT_ID_USED: + data[1] = le16_to_cpu(mbx->mb1); + break; + case MBS_LOOP_ID_USED: + break; + default: + data[0] = MBS_COMMAND_ERROR; + data[1] = lio->flags & SRB_LOGIN_RETRIED ? + QLA_LOGIO_LOGIN_RETRIED: 0; + break; + } + + DEBUG2(printk(KERN_WARNING + "scsi(%ld:%x): Async-%s failed - status=%x mb0=%x mb1=%x mb2=%x " + "mb6=%x mb7=%x.\n", + fcport->vha->host_no, sp->handle, type, le16_to_cpu(mbx->status), + le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1), + le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6), + le16_to_cpu(mbx->mb7))); + +done_post_logio_done_work: + lio->ctx.type == SRB_LOGIN_CMD ? + qla2x00_post_async_login_done_work(fcport->vha, fcport, data): + qla2x00_post_async_logout_done_work(fcport->vha, fcport, data); + + lio->ctx.free(sp); +} + +static void +qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, + struct logio_entry_24xx *logio) +{ + const char func[] = "LOGIO-IOCB"; + const char *type; + struct qla_hw_data *ha = vha->hw; + fc_port_t *fcport; + srb_t *sp; + struct srb_logio *lio; + uint16_t data[2]; + uint32_t iop[2]; + + sp = qla2x00_get_sp_from_handle(vha, func, req, logio); + if (!sp) + return; + + type = NULL; + lio = sp->ctx; + switch (lio->ctx.type) { + case SRB_LOGIN_CMD: + type = "login"; + break; + case SRB_LOGOUT_CMD: + type = "logout"; + break; + default: + qla_printk(KERN_WARNING, ha, + "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp, + lio->ctx.type); + return; + } + + del_timer(&lio->ctx.timer); + fcport = sp->fcport; + + data[0] = data[1] = 0; + if (logio->entry_status) { + DEBUG2(printk(KERN_WARNING + "scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n", + fcport->vha->host_no, sp->handle, type, + logio->entry_status)); + DEBUG2(qla2x00_dump_buffer((uint8_t *)logio, sizeof(*logio))); + + data[0] = MBS_COMMAND_ERROR; + data[1] = lio->flags & SRB_LOGIN_RETRIED ? + QLA_LOGIO_LOGIN_RETRIED: 0; + goto done_post_logio_done_work; + } + + if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) { + DEBUG2(printk(KERN_DEBUG + "scsi(%ld:%x): Async-%s complete - iop0=%x.\n", + fcport->vha->host_no, sp->handle, type, + le32_to_cpu(logio->io_parameter[0]))); + + data[0] = MBS_COMMAND_COMPLETE; + if (lio->ctx.type == SRB_LOGOUT_CMD) + goto done_post_logio_done_work; + + iop[0] = le32_to_cpu(logio->io_parameter[0]); + if (iop[0] & BIT_4) { + fcport->port_type = FCT_TARGET; + if (iop[0] & BIT_8) + fcport->flags |= FCF_TAPE_PRESENT; + } + if (iop[0] & BIT_5) + fcport->port_type = FCT_INITIATOR; + if (logio->io_parameter[7] || logio->io_parameter[8]) + fcport->supported_classes |= FC_COS_CLASS2; + if (logio->io_parameter[9] || logio->io_parameter[10]) + fcport->supported_classes |= FC_COS_CLASS3; + + goto done_post_logio_done_work; + } + + iop[0] = le32_to_cpu(logio->io_parameter[0]); + iop[1] = le32_to_cpu(logio->io_parameter[1]); + switch (iop[0]) { + case LSC_SCODE_PORTID_USED: + data[0] = MBS_PORT_ID_USED; + data[1] = LSW(iop[1]); + break; + case LSC_SCODE_NPORT_USED: + data[0] = MBS_LOOP_ID_USED; + break; + case LSC_SCODE_CMD_FAILED: + if ((iop[1] & 0xff) == 0x05) { + data[0] = MBS_NOT_LOGGED_IN; + break; + } + /* Fall through. */ + default: + data[0] = MBS_COMMAND_ERROR; + data[1] = lio->flags & SRB_LOGIN_RETRIED ? + QLA_LOGIO_LOGIN_RETRIED: 0; + break; + } + + DEBUG2(printk(KERN_WARNING + "scsi(%ld:%x): Async-%s failed - comp=%x iop0=%x iop1=%x.\n", + fcport->vha->host_no, sp->handle, type, + le16_to_cpu(logio->comp_status), + le32_to_cpu(logio->io_parameter[0]), + le32_to_cpu(logio->io_parameter[1]))); + +done_post_logio_done_work: + lio->ctx.type == SRB_LOGIN_CMD ? + qla2x00_post_async_login_done_work(fcport->vha, fcport, data): + qla2x00_post_async_logout_done_work(fcport->vha, fcport, data); + + lio->ctx.free(sp); +} + /** * qla2x00_process_response_queue() - Process response queue entries. * @ha: SCSI driver HA context @@ -980,6 +1223,9 @@ qla2x00_process_response_queue(struct rsp_que *rsp) case STATUS_CONT_TYPE: qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt); break; + case MBX_IOCB_TYPE: + qla2x00_mbx_iocb_entry(vha, rsp->req, + (struct mbx_entry *)pkt); default: /* Type Not Supported. */ DEBUG4(printk(KERN_WARNING @@ -1590,6 +1836,10 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, qla24xx_report_id_acquisition(vha, (struct vp_rpt_id_entry_24xx *)pkt); break; + case LOGINOUT_PORT_IOCB_TYPE: + qla24xx_logio_entry(vha, rsp->req, + (struct logio_entry_24xx *)pkt); + break; default: /* Type Not Supported. */ DEBUG4(printk(KERN_WARNING diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 6238be37d7b..a748a95efb1 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -253,6 +253,8 @@ qla2x00_do_dpc_vp(scsi_qla_host_t *vha) if (!(ha->current_topology & ISP_CFG_F)) return 0; + qla2x00_do_work(vha); + if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) { /* VP acquired. complete port configuration */ if (atomic_read(&base_vha->loop_state) == LOOP_READY) { diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index b6c088caf35..5fd7adbff30 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1170,6 +1170,7 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) int que, cnt; unsigned long flags; srb_t *sp; + struct srb_ctx *ctx; struct qla_hw_data *ha = vha->hw; struct req_que *req; @@ -1182,8 +1183,14 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) sp = req->outstanding_cmds[cnt]; if (sp) { req->outstanding_cmds[cnt] = NULL; - sp->cmd->result = res; - qla2x00_sp_compl(ha, sp); + if (!sp->ctx) { + sp->cmd->result = res; + qla2x00_sp_compl(ha, sp); + } else { + ctx = sp->ctx; + del_timer_sync(&ctx->timer); + ctx->free(sp); + } } } } @@ -2618,7 +2625,31 @@ qla2x00_post_idc_ack_work(struct scsi_qla_host *vha, uint16_t *mb) return qla2x00_post_work(vha, e); } -static void +#define qla2x00_post_async_work(name, type) \ +int qla2x00_post_async_##name##_work( \ + struct scsi_qla_host *vha, \ + fc_port_t *fcport, uint16_t *data) \ +{ \ + struct qla_work_evt *e; \ + \ + e = qla2x00_alloc_work(vha, type); \ + if (!e) \ + return QLA_FUNCTION_FAILED; \ + \ + e->u.logio.fcport = fcport; \ + if (data) { \ + e->u.logio.data[0] = data[0]; \ + e->u.logio.data[1] = data[1]; \ + } \ + return qla2x00_post_work(vha, e); \ +} + +qla2x00_post_async_work(login, QLA_EVT_ASYNC_LOGIN); +qla2x00_post_async_work(login_done, QLA_EVT_ASYNC_LOGIN_DONE); +qla2x00_post_async_work(logout, QLA_EVT_ASYNC_LOGOUT); +qla2x00_post_async_work(logout_done, QLA_EVT_ASYNC_LOGOUT_DONE); + +void qla2x00_do_work(struct scsi_qla_host *vha) { struct qla_work_evt *e, *tmp; @@ -2640,6 +2671,21 @@ qla2x00_do_work(struct scsi_qla_host *vha) case QLA_EVT_IDC_ACK: qla81xx_idc_ack(vha, e->u.idc_ack.mb); break; + case QLA_EVT_ASYNC_LOGIN: + qla2x00_async_login(vha, e->u.logio.fcport, + e->u.logio.data); + break; + case QLA_EVT_ASYNC_LOGIN_DONE: + qla2x00_async_login_done(vha, e->u.logio.fcport, + e->u.logio.data); + break; + case QLA_EVT_ASYNC_LOGOUT: + qla2x00_async_logout(vha, e->u.logio.fcport); + break; + case QLA_EVT_ASYNC_LOGOUT_DONE: + qla2x00_async_logout_done(vha, e->u.logio.fcport, + e->u.logio.data); + break; } if (e->flags & QLA_EVT_FLAG_FREE) kfree(e); @@ -2655,6 +2701,7 @@ void qla2x00_relogin(struct scsi_qla_host *vha) int status; uint16_t next_loopid = 0; struct qla_hw_data *ha = vha->hw; + uint16_t data[2]; list_for_each_entry(fcport, &vha->vp_fcports, list) { /* @@ -2664,6 +2711,7 @@ void qla2x00_relogin(struct scsi_qla_host *vha) if (atomic_read(&fcport->state) != FCS_ONLINE && fcport->login_retry) { + fcport->login_retry--; if (fcport->flags & FCF_FABRIC_DEVICE) { if (fcport->flags & FCF_TAPE_PRESENT) ha->isp_ops->fabric_logout(vha, @@ -2672,13 +2720,22 @@ void qla2x00_relogin(struct scsi_qla_host *vha) fcport->d_id.b.area, fcport->d_id.b.al_pa); - status = qla2x00_fabric_login(vha, fcport, - &next_loopid); + if (IS_ALOGIO_CAPABLE(ha)) { + data[0] = 0; + data[1] = QLA_LOGIO_LOGIN_RETRIED; + status = qla2x00_post_async_login_work( + vha, fcport, data); + if (status == QLA_SUCCESS) + continue; + /* Attempt a retry. */ + status = 1; + } else + status = qla2x00_fabric_login(vha, + fcport, &next_loopid); } else status = qla2x00_local_device_login(vha, fcport); - fcport->login_retry--; if (status == QLA_SUCCESS) { fcport->old_loop_id = fcport->loop_id; @@ -2851,6 +2908,9 @@ qla2x00_do_dpc(void *data) */ ha->dpc_active = 0; + /* Cleanup any residual CTX SRBs. */ + qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16); + return 0; } -- cgit v1.2.3-18-g5258 From 523eeac6703a995d58918aaf321f128f75c13108 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 20 Aug 2009 15:10:57 -0500 Subject: [SCSI] iscsi_tcp: Evaluate socket state in data_ready() The network core will call the state_change() callback prior to the data_ready() callback, which might cause us to lose a connection state change. So we have to evaluate the socket state at the end of the data_ready() callback, too. Signed-off-by: Hannes Reinecke Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 518dbd91df8..c7e2ff24ee9 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -99,6 +99,24 @@ static int iscsi_sw_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, return total_consumed; } +/** + * iscsi_sw_sk_state_check - check socket state + * @sk: socket + * + * If the socket is in CLOSE or CLOSE_WAIT we should + * not close the connection if there is still some + * data pending. + */ +static inline int iscsi_sw_sk_state_check(struct sock *sk) +{ + if ((sk->sk_state == TCP_CLOSE_WAIT || + sk->sk_state == TCP_CLOSE) && + !atomic_read(&sk->sk_rmem_alloc)) + return -ECONNRESET; + + return 0; +} + static void iscsi_sw_tcp_data_ready(struct sock *sk, int flag) { struct iscsi_conn *conn = sk->sk_user_data; @@ -117,6 +135,12 @@ static void iscsi_sw_tcp_data_ready(struct sock *sk, int flag) rd_desc.count = 1; tcp_read_sock(sk, &rd_desc, iscsi_sw_tcp_recv); + if (iscsi_sw_sk_state_check(sk) < 0) { + ISCSI_SW_TCP_DBG(conn, "iscsi_tcp_data_ready: " + "TCP_CLOSE|TCP_CLOSE_WAIT\n"); + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + } + read_unlock(&sk->sk_callback_lock); /* If we had to (atomically) map a highmem page, @@ -137,9 +161,7 @@ static void iscsi_sw_tcp_state_change(struct sock *sk) conn = (struct iscsi_conn*)sk->sk_user_data; session = conn->session; - if ((sk->sk_state == TCP_CLOSE_WAIT || - sk->sk_state == TCP_CLOSE) && - !atomic_read(&sk->sk_rmem_alloc)) { + if (iscsi_sw_sk_state_check(sk) < 0) { ISCSI_SW_TCP_DBG(conn, "iscsi_tcp_state_change: " "TCP_CLOSE|TCP_CLOSE_WAIT\n"); iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); -- cgit v1.2.3-18-g5258 From d3305f3407fa3e9452079ec6cc8379067456e4aa Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 20 Aug 2009 15:10:58 -0500 Subject: [SCSI] libiscsi: don't increment cmdsn if cmd is not sent We increment session->cmdsn at the top of iscsi_prep_scsi_cmd_pdu, but if the prep ecb or prep bidi or init_task calls fails then we leave the session->cmdsn incremented. This moves the cmdsn manipulation to the end of the function when we know it has succeeded. It also adds a session->cmdsn--; in queuecommand for if a driver like bnx2i tries to send a a task from that context but it fails. We do not have to do this in the xmit thread context because that code will retry the same task if the initial call fails. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/libiscsi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index a751f6230c2..c68cb53a984 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -301,8 +301,6 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) hdr->flags = ISCSI_ATTR_SIMPLE; int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); memcpy(task->lun, hdr->lun, sizeof(task->lun)); - hdr->cmdsn = task->cmdsn = cpu_to_be32(session->cmdsn); - session->cmdsn++; hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); cmd_len = sc->cmd_len; if (cmd_len < ISCSI_CDB_SIZE) @@ -388,6 +386,8 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) return -EIO; task->state = ISCSI_TASK_RUNNING; + hdr->cmdsn = task->cmdsn = cpu_to_be32(session->cmdsn); + session->cmdsn++; conn->scsicmd_pdus_cnt++; ISCSI_DBG_SESSION(session, "iscsi prep [%s cid %d sc %p cdb 0x%x " @@ -1497,6 +1497,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) } } if (session->tt->xmit_task(task)) { + session->cmdsn--; reason = FAILURE_SESSION_NOT_READY; goto prepd_reject; } -- cgit v1.2.3-18-g5258 From 8afa1439fcff58da8f28c1d083046f229f6ab3de Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 20 Aug 2009 15:10:59 -0500 Subject: [SCSI] libiscsi: handle immediate command rejections If we sent multiple pdus as immediate the target could be rejecting some and we have just been dropping the rejection notification. This adds code to handle nop-out rejections, so if a nop-out was sent as a ping and rejected we do not mark the connection bad. Instead we just clean up the timers since we have pdu making a rount trip we know the connection is good. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/libiscsi.c | 106 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 87 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index c68cb53a984..1d7a8b7e8a7 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -857,27 +857,102 @@ static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr) } } +static int iscsi_nop_out_rsp(struct iscsi_task *task, + struct iscsi_nopin *nop, char *data, int datalen) +{ + struct iscsi_conn *conn = task->conn; + int rc = 0; + + if (conn->ping_task != task) { + /* + * If this is not in response to one of our + * nops then it must be from userspace. + */ + if (iscsi_recv_pdu(conn->cls_conn, (struct iscsi_hdr *)nop, + data, datalen)) + rc = ISCSI_ERR_CONN_FAILED; + } else + mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout); + iscsi_complete_task(task, ISCSI_TASK_COMPLETED); + return rc; +} + static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, char *data, int datalen) { struct iscsi_reject *reject = (struct iscsi_reject *)hdr; struct iscsi_hdr rejected_pdu; + int opcode, rc = 0; conn->exp_statsn = be32_to_cpu(reject->statsn) + 1; - if (reject->reason == ISCSI_REASON_DATA_DIGEST_ERROR) { - if (ntoh24(reject->dlength) > datalen) - return ISCSI_ERR_PROTO; + if (ntoh24(reject->dlength) > datalen || + ntoh24(reject->dlength) < sizeof(struct iscsi_hdr)) { + iscsi_conn_printk(KERN_ERR, conn, "Cannot handle rejected " + "pdu. Invalid data length (pdu dlength " + "%u, datalen %d\n", ntoh24(reject->dlength), + datalen); + return ISCSI_ERR_PROTO; + } + memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr)); + opcode = rejected_pdu.opcode & ISCSI_OPCODE_MASK; - if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) { - memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr)); - iscsi_conn_printk(KERN_ERR, conn, - "pdu (op 0x%x) rejected " - "due to DataDigest error.\n", - rejected_pdu.opcode); + switch (reject->reason) { + case ISCSI_REASON_DATA_DIGEST_ERROR: + iscsi_conn_printk(KERN_ERR, conn, + "pdu (op 0x%x itt 0x%x) rejected " + "due to DataDigest error.\n", + rejected_pdu.itt, opcode); + break; + case ISCSI_REASON_IMM_CMD_REJECT: + iscsi_conn_printk(KERN_ERR, conn, + "pdu (op 0x%x itt 0x%x) rejected. Too many " + "immediate commands.\n", + rejected_pdu.itt, opcode); + /* + * We only send one TMF at a time so if the target could not + * handle it, then it should get fixed (RFC mandates that + * a target can handle one immediate TMF per conn). + * + * For nops-outs, we could have sent more than one if + * the target is sending us lots of nop-ins + */ + if (opcode != ISCSI_OP_NOOP_OUT) + return 0; + + if (rejected_pdu.itt == cpu_to_be32(ISCSI_RESERVED_TAG)) + /* + * nop-out in response to target's nop-out rejected. + * Just resend. + */ + iscsi_send_nopout(conn, + (struct iscsi_nopin*)&rejected_pdu); + else { + struct iscsi_task *task; + /* + * Our nop as ping got dropped. We know the target + * and transport are ok so just clean up + */ + task = iscsi_itt_to_task(conn, rejected_pdu.itt); + if (!task) { + iscsi_conn_printk(KERN_ERR, conn, + "Invalid pdu reject. Could " + "not lookup rejected task.\n"); + rc = ISCSI_ERR_BAD_ITT; + } else + rc = iscsi_nop_out_rsp(task, + (struct iscsi_nopin*)&rejected_pdu, + NULL, 0); } + break; + default: + iscsi_conn_printk(KERN_ERR, conn, + "pdu (op 0x%x itt 0x%x) rejected. Reason " + "code 0x%x\n", rejected_pdu.itt, + rejected_pdu.opcode, reject->reason); + break; } - return 0; + return rc; } /** @@ -1038,15 +1113,8 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, } conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; - if (conn->ping_task != task) - /* - * If this is not in response to one of our - * nops then it must be from userspace. - */ - goto recv_pdu; - - mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout); - iscsi_complete_task(task, ISCSI_TASK_COMPLETED); + rc = iscsi_nop_out_rsp(task, (struct iscsi_nopin*)hdr, + data, datalen); break; default: rc = ISCSI_ERR_BAD_OPCODE; -- cgit v1.2.3-18-g5258 From b06fc73a9ebd352065dd4dd3139fb53ed72ac970 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 20 Aug 2009 15:11:00 -0500 Subject: [SCSI] qla4xxx: Removed residual from overrun debug print The residual variable is only valid for udnerrun so do not print it out for the overrun case. Signed-off-by: Karen Higgins [Mike Christie: Fix coding style issues in patch] Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_isr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index 8025ee16588..c196d55eae3 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -227,11 +227,11 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, case SCS_DATA_UNDERRUN: case SCS_DATA_OVERRUN: if ((sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) || - (sts_entry->completionStatus == SCS_DATA_OVERRUN)) { - DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " "Data overrun, " - "residual = 0x%x\n", ha->host_no, + (sts_entry->completionStatus == SCS_DATA_OVERRUN)) { + DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " "Data overrun\n", + ha->host_no, cmd->device->channel, cmd->device->id, - cmd->device->lun, __func__, residual)); + cmd->device->lun, __func__)); cmd->result = DID_ERROR << 16; break; -- cgit v1.2.3-18-g5258 From 632248aab3170004e24512a4378fc6d9d7f3b4ac Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 20 Aug 2009 15:11:01 -0500 Subject: [SCSI] iscsi class: Add logging to scsi_transport_iscsi.c Logging for connections and sessions in the scsi_transport_iscsi module is now controlled by module parameters. Signed-off-by: Erez Zilber [Mike Christie: newline fixups and modification of some dbg statements] Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_iscsi.c | 73 ++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index b47240ca4b1..ad897df3661 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -36,6 +36,38 @@ #define ISCSI_TRANSPORT_VERSION "2.0-870" +static int dbg_session; +module_param_named(debug_session, dbg_session, int, + S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug_session, + "Turn on debugging for sessions in scsi_transport_iscsi " + "module. Set to 1 to turn on, and zero to turn off. Default " + "is off."); + +static int dbg_conn; +module_param_named(debug_conn, dbg_conn, int, + S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug_conn, + "Turn on debugging for connections in scsi_transport_iscsi " + "module. Set to 1 to turn on, and zero to turn off. Default " + "is off."); + +#define ISCSI_DBG_TRANS_SESSION(_session, dbg_fmt, arg...) \ + do { \ + if (dbg_session) \ + iscsi_cls_session_printk(KERN_INFO, _session, \ + "%s: " dbg_fmt, \ + __func__, ##arg); \ + } while (0); + +#define ISCSI_DBG_TRANS_CONN(_conn, dbg_fmt, arg...) \ + do { \ + if (dbg_conn) \ + iscsi_cls_conn_printk(KERN_INFO, _conn, \ + "%s: " dbg_fmt, \ + __func__, ##arg); \ + } while (0); + struct iscsi_internal { struct scsi_transport_template t; struct iscsi_transport *iscsi_transport; @@ -377,6 +409,7 @@ static void iscsi_session_release(struct device *dev) shost = iscsi_session_to_shost(session); scsi_host_put(shost); + ISCSI_DBG_TRANS_SESSION(session, "Completing session release\n"); kfree(session); } @@ -441,6 +474,9 @@ static int iscsi_user_scan_session(struct device *dev, void *data) return 0; session = iscsi_dev_to_session(dev); + + ISCSI_DBG_TRANS_SESSION(session, "Scanning session\n"); + shost = iscsi_session_to_shost(session); ihost = shost->shost_data; @@ -448,8 +484,7 @@ static int iscsi_user_scan_session(struct device *dev, void *data) spin_lock_irqsave(&session->lock, flags); if (session->state != ISCSI_SESSION_LOGGED_IN) { spin_unlock_irqrestore(&session->lock, flags); - mutex_unlock(&ihost->mutex); - return 0; + goto user_scan_exit; } id = session->target_id; spin_unlock_irqrestore(&session->lock, flags); @@ -462,7 +497,10 @@ static int iscsi_user_scan_session(struct device *dev, void *data) scsi_scan_target(&session->dev, 0, id, scan_data->lun, 1); } + +user_scan_exit: mutex_unlock(&ihost->mutex); + ISCSI_DBG_TRANS_SESSION(session, "Completed session scan\n"); return 0; } @@ -522,7 +560,9 @@ static void session_recovery_timedout(struct work_struct *work) if (session->transport->session_recovery_timedout) session->transport->session_recovery_timedout(session); + ISCSI_DBG_TRANS_SESSION(session, "Unblocking SCSI target\n"); scsi_target_unblock(&session->dev); + ISCSI_DBG_TRANS_SESSION(session, "Completed unblocking SCSI target\n"); } static void __iscsi_unblock_session(struct work_struct *work) @@ -534,6 +574,7 @@ static void __iscsi_unblock_session(struct work_struct *work) struct iscsi_cls_host *ihost = shost->shost_data; unsigned long flags; + ISCSI_DBG_TRANS_SESSION(session, "Unblocking session\n"); /* * The recovery and unblock work get run from the same workqueue, * so try to cancel it if it was going to run after this unblock. @@ -553,6 +594,7 @@ static void __iscsi_unblock_session(struct work_struct *work) if (scsi_queue_work(shost, &session->scan_work)) atomic_inc(&ihost->nr_scans); } + ISCSI_DBG_TRANS_SESSION(session, "Completed unblocking session\n"); } /** @@ -579,10 +621,12 @@ static void __iscsi_block_session(struct work_struct *work) block_work); unsigned long flags; + ISCSI_DBG_TRANS_SESSION(session, "Blocking session\n"); spin_lock_irqsave(&session->lock, flags); session->state = ISCSI_SESSION_FAILED; spin_unlock_irqrestore(&session->lock, flags); scsi_target_block(&session->dev); + ISCSI_DBG_TRANS_SESSION(session, "Completed SCSI target blocking\n"); queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work, session->recovery_tmo * HZ); } @@ -602,6 +646,8 @@ static void __iscsi_unbind_session(struct work_struct *work) struct iscsi_cls_host *ihost = shost->shost_data; unsigned long flags; + ISCSI_DBG_TRANS_SESSION(session, "Unbinding session\n"); + /* Prevent new scans and make sure scanning is not in progress */ mutex_lock(&ihost->mutex); spin_lock_irqsave(&session->lock, flags); @@ -616,6 +662,7 @@ static void __iscsi_unbind_session(struct work_struct *work) scsi_remove_target(&session->dev); iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION); + ISCSI_DBG_TRANS_SESSION(session, "Completed target removal\n"); } struct iscsi_cls_session * @@ -647,6 +694,8 @@ iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport, device_initialize(&session->dev); if (dd_size) session->dd_data = &session[1]; + + ISCSI_DBG_TRANS_SESSION(session, "Completed session allocation\n"); return session; } EXPORT_SYMBOL_GPL(iscsi_alloc_session); @@ -712,6 +761,7 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) spin_unlock_irqrestore(&sesslock, flags); iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION); + ISCSI_DBG_TRANS_SESSION(session, "Completed session adding\n"); return 0; release_host: @@ -752,6 +802,7 @@ static void iscsi_conn_release(struct device *dev) struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev); struct device *parent = conn->dev.parent; + ISCSI_DBG_TRANS_CONN(conn, "Releasing conn\n"); kfree(conn); put_device(parent); } @@ -774,6 +825,8 @@ void iscsi_remove_session(struct iscsi_cls_session *session) unsigned long flags; int err; + ISCSI_DBG_TRANS_SESSION(session, "Removing session\n"); + spin_lock_irqsave(&sesslock, flags); list_del(&session->sess_list); spin_unlock_irqrestore(&sesslock, flags); @@ -807,12 +860,15 @@ void iscsi_remove_session(struct iscsi_cls_session *session) "for session. Error %d.\n", err); transport_unregister_device(&session->dev); + + ISCSI_DBG_TRANS_SESSION(session, "Completing session removal\n"); device_del(&session->dev); } EXPORT_SYMBOL_GPL(iscsi_remove_session); void iscsi_free_session(struct iscsi_cls_session *session) { + ISCSI_DBG_TRANS_SESSION(session, "Freeing session\n"); iscsi_session_event(session, ISCSI_KEVENT_DESTROY_SESSION); put_device(&session->dev); } @@ -828,6 +884,7 @@ EXPORT_SYMBOL_GPL(iscsi_free_session); int iscsi_destroy_session(struct iscsi_cls_session *session) { iscsi_remove_session(session); + ISCSI_DBG_TRANS_SESSION(session, "Completing session destruction\n"); iscsi_free_session(session); return 0; } @@ -885,6 +942,8 @@ iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid) list_add(&conn->conn_list, &connlist); conn->active = 1; spin_unlock_irqrestore(&connlock, flags); + + ISCSI_DBG_TRANS_CONN(conn, "Completed conn creation\n"); return conn; release_parent_ref: @@ -912,6 +971,7 @@ int iscsi_destroy_conn(struct iscsi_cls_conn *conn) spin_unlock_irqrestore(&connlock, flags); transport_unregister_device(&conn->dev); + ISCSI_DBG_TRANS_CONN(conn, "Completing conn destruction\n"); device_unregister(&conn->dev); return 0; } @@ -1200,6 +1260,9 @@ int iscsi_session_event(struct iscsi_cls_session *session, "Cannot notify userspace of session " "event %u. Check iscsi daemon\n", event); + + ISCSI_DBG_TRANS_SESSION(session, "Completed handling event %d rc %d\n", + event, rc); return rc; } EXPORT_SYMBOL_GPL(iscsi_session_event); @@ -1221,6 +1284,8 @@ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_endpoint *ep, shost = iscsi_session_to_shost(session); ev->r.c_session_ret.host_no = shost->host_no; ev->r.c_session_ret.sid = session->sid; + ISCSI_DBG_TRANS_SESSION(session, + "Completed creating transport session\n"); return 0; } @@ -1246,6 +1311,8 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) ev->r.c_conn_ret.sid = session->sid; ev->r.c_conn_ret.cid = conn->cid; + + ISCSI_DBG_TRANS_CONN(conn, "Completed creating transport conn\n"); return 0; } @@ -1258,8 +1325,10 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev if (!conn) return -EINVAL; + ISCSI_DBG_TRANS_CONN(conn, "Destroying transport conn\n"); if (transport->destroy_conn) transport->destroy_conn(conn); + return 0; } -- cgit v1.2.3-18-g5258 From d1af8a328755f51c9b76157a8692e56520d3fd94 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 20 Aug 2009 15:11:02 -0500 Subject: [SCSI] iscsi_tcp: add new conn error to indicate tcp conn closed If a target closed the connection, we will detect it in the state_changed or data_ready callout. This adds a new conn error value to use for this problem, so it is not confused with when the initiator throws a conn error and drops the connection. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index c7e2ff24ee9..2b1b834a098 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -109,11 +109,14 @@ static int iscsi_sw_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, */ static inline int iscsi_sw_sk_state_check(struct sock *sk) { - if ((sk->sk_state == TCP_CLOSE_WAIT || - sk->sk_state == TCP_CLOSE) && - !atomic_read(&sk->sk_rmem_alloc)) - return -ECONNRESET; + struct iscsi_conn *conn = (struct iscsi_conn*)sk->sk_user_data; + if ((sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) && + !atomic_read(&sk->sk_rmem_alloc)) { + ISCSI_SW_TCP_DBG(conn, "TCP_CLOSE|TCP_CLOSE_WAIT\n"); + iscsi_conn_failure(conn, ISCSI_ERR_TCP_CONN_CLOSE); + return -ECONNRESET; + } return 0; } @@ -135,11 +138,7 @@ static void iscsi_sw_tcp_data_ready(struct sock *sk, int flag) rd_desc.count = 1; tcp_read_sock(sk, &rd_desc, iscsi_sw_tcp_recv); - if (iscsi_sw_sk_state_check(sk) < 0) { - ISCSI_SW_TCP_DBG(conn, "iscsi_tcp_data_ready: " - "TCP_CLOSE|TCP_CLOSE_WAIT\n"); - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - } + iscsi_sw_sk_state_check(sk); read_unlock(&sk->sk_callback_lock); @@ -161,11 +160,7 @@ static void iscsi_sw_tcp_state_change(struct sock *sk) conn = (struct iscsi_conn*)sk->sk_user_data; session = conn->session; - if (iscsi_sw_sk_state_check(sk) < 0) { - ISCSI_SW_TCP_DBG(conn, "iscsi_tcp_state_change: " - "TCP_CLOSE|TCP_CLOSE_WAIT\n"); - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - } + iscsi_sw_sk_state_check(sk); tcp_conn = conn->dd_data; tcp_sw_conn = tcp_conn->dd_data; -- cgit v1.2.3-18-g5258 From 70b31c152dc49ef70bd2b34ad53ccbd9bb4116d4 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 20 Aug 2009 15:11:03 -0500 Subject: [SCSI] libiscsi, iscsi_tcp: check suspend bit before each call to xmit_task If we had multiple tasks on the cmd or requeue lists, and iscsi_tcp returns a error, the write_space function can still run and queue iscsi_data_xmit. If it was a legetimate problem and iscsi_conn_failure was run but we raced and iscsi_data_xmit was run first it could miss the suspend bit checks, and start trying to send data again and hit another timeout. A similar problem is present when using cxgb3i. This has libiscsi check the suspend bit before calling the xmit task callout, so we at least do not try sending multiple tasks (one could be sent). Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/libiscsi.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 1d7a8b7e8a7..a7ee4bb4070 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1280,6 +1280,9 @@ static int iscsi_xmit_task(struct iscsi_conn *conn) struct iscsi_task *task = conn->task; int rc; + if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) + return -ENODATA; + __iscsi_get_task(task); spin_unlock_bh(&conn->session->lock); rc = conn->session->tt->xmit_task(task); @@ -1329,7 +1332,7 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) int rc = 0; spin_lock_bh(&conn->session->lock); - if (unlikely(conn->suspend_tx)) { + if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) { ISCSI_DBG_SESSION(conn->session, "Tx suspended!\n"); spin_unlock_bh(&conn->session->lock); return -ENODATA; @@ -1338,7 +1341,7 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) if (conn->task) { rc = iscsi_xmit_task(conn); if (rc) - goto again; + goto done; } /* @@ -1358,7 +1361,7 @@ check_mgmt: } rc = iscsi_xmit_task(conn); if (rc) - goto again; + goto done; } /* process pending command queue */ @@ -1379,14 +1382,14 @@ check_mgmt: list_add_tail(&conn->task->running, &conn->cmdqueue); conn->task = NULL; - goto again; + goto done; } else fail_scsi_task(conn->task, DID_ABORT); continue; } rc = iscsi_xmit_task(conn); if (rc) - goto again; + goto done; /* * we could continuously get new task requests so * we need to check the mgmt queue for nops that need to @@ -1412,16 +1415,14 @@ check_mgmt: conn->task->state = ISCSI_TASK_RUNNING; rc = iscsi_xmit_task(conn); if (rc) - goto again; + goto done; if (!list_empty(&conn->mgmtqueue)) goto check_mgmt; } spin_unlock_bh(&conn->session->lock); return -ENODATA; -again: - if (unlikely(conn->suspend_tx)) - rc = -ENODATA; +done: spin_unlock_bh(&conn->session->lock); return rc; } -- cgit v1.2.3-18-g5258 From ee610c6701875525d5c61fa6e56ddbf3e645b8df Mon Sep 17 00:00:00 2001 From: Robert Love Date: Tue, 25 Aug 2009 13:58:31 -0700 Subject: [SCSI] fcoe: Add format spacing to FCOE_NETDEV_DBG debug macro There's currently no space between the interface name and the user specified format/string. This patch adds a space and a colon to the output to separate the interface name and the user specified string. So, instead of "ethXfoo" it will read "ethX: foo". Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index 5ae8ca71afc..68b9f855073 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h @@ -61,7 +61,7 @@ do { \ #define FCOE_NETDEV_DBG(netdev, fmt, args...) \ FCOE_CHECK_LOGGING(FCOE_NETDEV_LOGGING, \ - printk(KERN_INFO "fcoe: %s" fmt, \ + printk(KERN_INFO "fcoe: %s: " fmt, \ netdev->name, ##args);) /* -- cgit v1.2.3-18-g5258 From cd305ce41be1615dfc72892e0642c6b880f58d95 Mon Sep 17 00:00:00 2001 From: Robert Love Date: Tue, 25 Aug 2009 13:58:37 -0700 Subject: [SCSI] libfc: Fix misleading debug statement The statement reads, "Exchange timed out, notifying the upper layer", however, this statement is printed whenever the timer is armed. This is confusing to someone debugging the code because every time an exchange is initialized, there is an incorrect statement stating that the timer has already timed out. This patch changes the statement to read, "Exchange timer armed" which is more accurate. This patch also adds a debug statement in the timeout handler to properly indicate that the exchange has timed out. Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_exch.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 11ddd115efb..40c34274bd8 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -326,7 +326,7 @@ static inline void fc_exch_timer_set_locked(struct fc_exch *ep, if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE)) return; - FC_EXCH_DBG(ep, "Exchange timed out, notifying the upper layer\n"); + FC_EXCH_DBG(ep, "Exchange timer armed\n"); if (schedule_delayed_work(&ep->timeout_work, msecs_to_jiffies(timer_msec))) @@ -412,6 +412,8 @@ static void fc_exch_timeout(struct work_struct *work) u32 e_stat; int rc = 1; + FC_EXCH_DBG(ep, "Exchange timed out\n"); + spin_lock_bh(&ep->ex_lock); if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE)) goto unlock; -- cgit v1.2.3-18-g5258 From a69b06bc5e7b153043db8984564b731f99e014fc Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 13:58:42 -0700 Subject: [SCSI] fcoe: libfcoe: extra semicolon in CHECK_LOGGING macros causes compile error If using code like this: if (foo) FCOE_DBG("foo\n); else FCOE_DBG("bar\n"); one gets compile errors because FCOE_DBG expands with its own semicolon, making one too many for the if-statement. Remove the offending semicolon in fcoe.h and also a similar case in libfcoe.c. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.h | 2 +- drivers/scsi/fcoe/libfcoe.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index 68b9f855073..65120e21f5c 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h @@ -53,7 +53,7 @@ do { \ do { \ CMD; \ } while (0); \ -} while (0); +} while (0) #define FCOE_DBG(fmt, args...) \ FCOE_CHECK_LOGGING(FCOE_LOGGING, \ diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index 4db719d6ada..d0b5208e1a4 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -69,7 +69,7 @@ do { \ do { \ CMD; \ } while (0); \ -} while (0); +} while (0) #define LIBFCOE_DBG(fmt, args...) \ LIBFCOE_CHECK_LOGGING(LIBFCOE_LOGGING, \ -- cgit v1.2.3-18-g5258 From e4bc50bedf0dd6c63f20a7bc0a2b46667664fba1 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Tue, 25 Aug 2009 13:58:47 -0700 Subject: [SCSI] fcoe, libfc: adds per cpu exch pool within exchange manager(EM) Adds per cpu exch pool for these reasons:- 1. Currently an EM instance is shared across all cpus to manage all exches for all cpus. This required em_lock across all cpus for an exch alloc, free, lookup and reset each frame and that made em_lock expensive, so instead having per cpu exch pool with their own per cpu pool lock will likely reduce locking contention in fast path for an exch alloc, free and lookup. 2. Per cpu exch pool will likely improve cache hit ratio since all frames of an exch will be processed on the same cpu on which exch originated. This patch is only prep work to help in keeping complexity of next patch low, so this patch only sets up per cpu exch pool and related helper funcs to be used by next patch. The next patch fully makes use of per cpu exch pool in all code paths ie. tx, rx and reset. Divides per EM exch id range equally across all cpus to setup per cpu exch pool. This division is such that lower bits of exch id carries cpu number info on which exch originated, later a simple bitwise AND operation on exch id of incoming frame with fc_cpu_mask retrieves cpu number info to direct all frames to same cpu on which exch originated. This required a global fc_cpu_mask and fc_cpu_order initialized to max possible cpus number nr_cpu_ids rounded up to 2's power, this will be used in mapping exch id and exch ptr array index in pool during exch allocation, find or reset code paths. Adds a check in fc_exch_mgr_alloc() to ensure specified min_xid lower bits are zero since these bits are used to carry cpu info. Adds and initializes struct fc_exch_pool with all required fields to manage exches in pool. Allocates per cpu struct fc_exch_pool with memory for exches array for range of exches per pool. The exches array memory is followed by struct fc_exch_pool. Adds fc_exch_ptr_get/set() helper functions to get/set exch ptr in pool exches array at specified array index. Increases default FCOE_MAX_XID to 0x0FFF from 0x07EF, so that more exches are available per cpu after above described exch id range division across all cpus to each pool. Signed-off-by: Vasu Dev Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.h | 2 +- drivers/scsi/libfc/fc_exch.c | 89 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 87 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index 65120e21f5c..550d1e49d1a 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h @@ -38,7 +38,7 @@ #define FCOE_MAX_OUTSTANDING_COMMANDS 1024 #define FCOE_MIN_XID 0x0000 /* the min xid supported by fcoe_sw */ -#define FCOE_MAX_XID 0x07ef /* the max xid supported by fcoe_sw */ +#define FCOE_MAX_XID 0x0FFF /* the max xid supported by fcoe_sw */ unsigned int fcoe_debug_logging; module_param_named(debug_logging, fcoe_debug_logging, int, S_IRUGO|S_IWUSR); diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 40c34274bd8..9cbe8d66eb2 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -32,6 +32,9 @@ #include #include +u16 fc_cpu_mask; /* cpu mask for possible cpus */ +EXPORT_SYMBOL(fc_cpu_mask); +static u16 fc_cpu_order; /* 2's power to represent total possible cpus */ static struct kmem_cache *fc_em_cachep; /* cache for exchanges */ /* @@ -47,6 +50,20 @@ static struct kmem_cache *fc_em_cachep; /* cache for exchanges */ * fc_seq holds the state for an individual sequence. */ +/* + * Per cpu exchange pool + * + * This structure manages per cpu exchanges in array of exchange pointers. + * This array is allocated followed by struct fc_exch_pool memory for + * assigned range of exchanges to per cpu pool. + */ +struct fc_exch_pool { + u16 next_index; /* next possible free exchange index */ + u16 total_exches; /* total allocated exchanges */ + spinlock_t lock; /* exch pool lock */ + struct list_head ex_list; /* allocated exchanges list */ +}; + /* * Exchange manager. * @@ -66,6 +83,8 @@ struct fc_exch_mgr { u32 total_exches; /* total allocated exchanges */ struct list_head ex_list; /* allocated exchanges list */ mempool_t *ep_pool; /* reserve ep's */ + u16 pool_max_index; /* max exch array index in exch pool */ + struct fc_exch_pool *pool; /* per cpu exch pool */ /* * currently exchange mgr stats are updated but not used. @@ -303,6 +322,19 @@ static int fc_exch_done_locked(struct fc_exch *ep) return rc; } +static inline struct fc_exch *fc_exch_ptr_get(struct fc_exch_pool *pool, + u16 index) +{ + struct fc_exch **exches = (struct fc_exch **)(pool + 1); + return exches[index]; +} + +static inline void fc_exch_ptr_set(struct fc_exch_pool *pool, u16 index, + struct fc_exch *ep) +{ + ((struct fc_exch **)(pool + 1))[index] = ep; +} + static void fc_exch_mgr_delete_ep(struct fc_exch *ep) { struct fc_exch_mgr *mp; @@ -1751,6 +1783,7 @@ static void fc_exch_mgr_destroy(struct kref *kref) */ WARN_ON(mp->total_exches != 0); mempool_destroy(mp->ep_pool); + free_percpu(mp->pool); kfree(mp); } @@ -1770,8 +1803,13 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, { struct fc_exch_mgr *mp; size_t len; + u16 pool_exch_range; + size_t pool_size; + unsigned int cpu; + struct fc_exch_pool *pool; - if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN) { + if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN || + (min_xid & fc_cpu_mask) != 0) { FC_LPORT_DBG(lp, "Invalid min_xid 0x:%x and max_xid 0x:%x\n", min_xid, max_xid); return NULL; @@ -1802,10 +1840,31 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, if (!mp->ep_pool) goto free_mp; + /* + * Setup per cpu exch pool with entire exchange id range equally + * divided across all cpus. The exch pointers array memory is + * allocated for exch range per pool. + */ + pool_exch_range = (mp->max_xid - mp->min_xid + 1) / (fc_cpu_mask + 1); + mp->pool_max_index = pool_exch_range - 1; + + /* + * Allocate and initialize per cpu exch pool + */ + pool_size = sizeof(*pool) + pool_exch_range * sizeof(struct fc_exch *); + mp->pool = __alloc_percpu(pool_size, __alignof__(struct fc_exch_pool)); + if (!mp->pool) + goto free_mempool; + for_each_possible_cpu(cpu) { + pool = per_cpu_ptr(mp->pool, cpu); + spin_lock_init(&pool->lock); + INIT_LIST_HEAD(&pool->ex_list); + } + kref_init(&mp->kref); if (!fc_exch_mgr_add(lp, mp, match)) { - mempool_destroy(mp->ep_pool); - goto free_mp; + free_percpu(mp->pool); + goto free_mempool; } /* @@ -1816,6 +1875,8 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, kref_put(&mp->kref, fc_exch_mgr_destroy); return mp; +free_mempool: + mempool_destroy(mp->ep_pool); free_mp: kfree(mp); return NULL; @@ -1975,6 +2036,28 @@ int fc_exch_init(struct fc_lport *lp) if (!lp->tt.seq_exch_abort) lp->tt.seq_exch_abort = fc_seq_exch_abort; + /* + * Initialize fc_cpu_mask and fc_cpu_order. The + * fc_cpu_mask is set for nr_cpu_ids rounded up + * to order of 2's * power and order is stored + * in fc_cpu_order as this is later required in + * mapping between an exch id and exch array index + * in per cpu exch pool. + * + * This round up is required to align fc_cpu_mask + * to exchange id's lower bits such that all incoming + * frames of an exchange gets delivered to the same + * cpu on which exchange originated by simple bitwise + * AND operation between fc_cpu_mask and exchange id. + */ + fc_cpu_mask = 1; + fc_cpu_order = 0; + while (fc_cpu_mask < nr_cpu_ids) { + fc_cpu_mask <<= 1; + fc_cpu_order++; + } + fc_cpu_mask--; + return 0; } EXPORT_SYMBOL(fc_exch_init); -- cgit v1.2.3-18-g5258 From b2f0091fbf8b475fa09b5e1712e0ab84cb3e1ca4 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Tue, 25 Aug 2009 13:58:53 -0700 Subject: [SCSI] fcoe, libfc: fully makes use of per cpu exch pool and then removes em_lock 1. Updates fcoe_rcv() to queue incoming frames to the fcoe per cpu thread on which this frame's exch was originated and simply use current cpu for request exch not originated by initiator. It is redundant to add this code under CONFIG_SMP, so removes CONFIG_SMP uses around this code. 2. Updates fc_exch_em_alloc, fc_exch_delete, fc_exch_find to use per cpu exch pools, here fc_exch_delete is rename of older fc_exch_mgr_delete_ep since ep/exch are now deleted in pools of EM and so brief new name is sufficient and better name. Updates these functions to map exch id to their index into exch pool using fc_cpu_mask, fc_cpu_order and EM min_xid. This mapping is as per detailed explanation about this in last patch and basically this is just as lower fc_cpu_mask bits of exch id as cpu number and upper bit sum of EM min_xid and exch index in pool. Uses pool next_index to keep track of exch allocation from pool along with pool_max_index as upper bound of exches array in pool. 3. Adds exch pool ptr to fc_exch to free exch to its pool in fc_exch_delete. 4. Updates fc_exch_mgr_reset to reset all exch pools of an EM, this required adding fc_exch_pool_reset func to reset exches in pool and then have fc_exch_mgr_reset call fc_exch_pool_reset for each pool within each EM for a lport. 5. Removes no longer needed exches array, em_lock, next_xid, and total_exches from struct fc_exch_mgr, these are not needed after use of per cpu exch pool, also removes not used max_read, last_read from struct fc_exch_mgr. 6. Updates locking notes for exch pool lock with fc_exch lock and uses pool lock in exch allocation, lookup and reset. Signed-off-by: Vasu Dev Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 19 +++-- drivers/scsi/libfc/fc_exch.c | 189 +++++++++++++++++++++++-------------------- 2 files changed, 109 insertions(+), 99 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 757aa28f0f0..e32a0ed266a 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -912,8 +912,7 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev, struct fcoe_softc *fc; struct fc_frame_header *fh; struct fcoe_percpu_s *fps; - unsigned short oxid; - unsigned int cpu = 0; + unsigned int cpu; fc = container_of(ptype, struct fcoe_softc, fcoe_packet_type); lp = fc->ctlr.lp; @@ -947,20 +946,20 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev, skb_set_transport_header(skb, sizeof(struct fcoe_hdr)); fh = (struct fc_frame_header *) skb_transport_header(skb); - oxid = ntohs(fh->fh_ox_id); - fr = fcoe_dev_from_skb(skb); fr->fr_dev = lp; fr->ptype = ptype; -#ifdef CONFIG_SMP /* - * The incoming frame exchange id(oxid) is ANDed with num of online - * cpu bits to get cpu and then this cpu is used for selecting - * a per cpu kernel thread from fcoe_percpu. + * In case the incoming frame's exchange is originated from + * the initiator, then received frame's exchange id is ANDed + * with fc_cpu_mask bits to get the same cpu on which exchange + * was originated, otherwise just use the current cpu. */ - cpu = oxid & (num_online_cpus() - 1); -#endif + if (ntoh24(fh->fh_f_ctl) & FC_FC_EX_CTX) + cpu = ntohs(fh->fh_ox_id) & fc_cpu_mask; + else + cpu = smp_processor_id(); fps = &per_cpu(fcoe_percpu, cpu); spin_lock_bh(&fps->fcoe_rx_list.lock); diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 9cbe8d66eb2..b51db15a387 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -73,14 +73,8 @@ struct fc_exch_pool { struct fc_exch_mgr { enum fc_class class; /* default class for sequences */ struct kref kref; /* exchange mgr reference count */ - spinlock_t em_lock; /* exchange manager lock, - must be taken before ex_lock */ - u16 next_xid; /* next possible free exchange ID */ u16 min_xid; /* min exchange ID */ u16 max_xid; /* max exchange ID */ - u16 max_read; /* max exchange ID for read */ - u16 last_read; /* last xid allocated for read */ - u32 total_exches; /* total allocated exchanges */ struct list_head ex_list; /* allocated exchanges list */ mempool_t *ep_pool; /* reserve ep's */ u16 pool_max_index; /* max exch array index in exch pool */ @@ -99,7 +93,6 @@ struct fc_exch_mgr { atomic_t seq_not_found; atomic_t non_bls_resp; } stats; - struct fc_exch **exches; /* for exch pointers indexed by xid */ }; #define fc_seq_exch(sp) container_of(sp, struct fc_exch, seq) @@ -192,8 +185,8 @@ static struct fc_seq *fc_seq_start_next_locked(struct fc_seq *sp); * sequence allocation and deallocation must be locked. * - exchange refcnt can be done atomicly without locks. * - sequence allocation must be locked by exch lock. - * - If the em_lock and ex_lock must be taken at the same time, then the - * em_lock must be taken before the ex_lock. + * - If the EM pool lock and ex_lock must be taken at the same time, then the + * EM pool lock must be taken before the ex_lock. */ /* @@ -335,17 +328,18 @@ static inline void fc_exch_ptr_set(struct fc_exch_pool *pool, u16 index, ((struct fc_exch **)(pool + 1))[index] = ep; } -static void fc_exch_mgr_delete_ep(struct fc_exch *ep) +static void fc_exch_delete(struct fc_exch *ep) { - struct fc_exch_mgr *mp; + struct fc_exch_pool *pool; - mp = ep->em; - spin_lock_bh(&mp->em_lock); - WARN_ON(mp->total_exches <= 0); - mp->total_exches--; - mp->exches[ep->xid - mp->min_xid] = NULL; + pool = ep->pool; + spin_lock_bh(&pool->lock); + WARN_ON(pool->total_exches <= 0); + pool->total_exches--; + fc_exch_ptr_set(pool, (ep->xid - ep->em->min_xid) >> fc_cpu_order, + NULL); list_del(&ep->ex_list); - spin_unlock_bh(&mp->em_lock); + spin_unlock_bh(&pool->lock); fc_exch_release(ep); /* drop hold for exch in mp */ } @@ -465,7 +459,7 @@ static void fc_exch_timeout(struct work_struct *work) rc = fc_exch_done_locked(ep); spin_unlock_bh(&ep->ex_lock); if (!rc) - fc_exch_mgr_delete_ep(ep); + fc_exch_delete(ep); if (resp) resp(sp, ERR_PTR(-FC_EX_TIMEOUT), arg); fc_seq_exch_abort(sp, 2 * ep->r_a_tov); @@ -509,10 +503,9 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, struct fc_exch_mgr *mp) { struct fc_exch *ep; - u16 min, max, xid; - - min = mp->min_xid; - max = mp->max_xid; + unsigned int cpu; + u16 index; + struct fc_exch_pool *pool; /* allocate memory for exchange */ ep = mempool_alloc(mp->ep_pool, GFP_ATOMIC); @@ -522,15 +515,17 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, } memset(ep, 0, sizeof(*ep)); - spin_lock_bh(&mp->em_lock); - xid = mp->next_xid; - /* alloc a new xid */ - while (mp->exches[xid - min]) { - xid = (xid == max) ? min : xid + 1; - if (xid == mp->next_xid) + cpu = smp_processor_id(); + pool = per_cpu_ptr(mp->pool, cpu); + spin_lock_bh(&pool->lock); + index = pool->next_index; + /* allocate new exch from pool */ + while (fc_exch_ptr_get(pool, index)) { + index = index == mp->pool_max_index ? 0 : index + 1; + if (index == pool->next_index) goto err; } - mp->next_xid = (xid == max) ? min : xid + 1; + pool->next_index = index == mp->pool_max_index ? 0 : index + 1; fc_exch_hold(ep); /* hold for exch in mp */ spin_lock_init(&ep->ex_lock); @@ -541,17 +536,18 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, */ spin_lock_bh(&ep->ex_lock); - mp->exches[xid - mp->min_xid] = ep; - list_add_tail(&ep->ex_list, &mp->ex_list); + fc_exch_ptr_set(pool, index, ep); + list_add_tail(&ep->ex_list, &pool->ex_list); fc_seq_alloc(ep, ep->seq_id++); - mp->total_exches++; - spin_unlock_bh(&mp->em_lock); + pool->total_exches++; + spin_unlock_bh(&pool->lock); /* * update exchange */ - ep->oxid = ep->xid = xid; + ep->oxid = ep->xid = (index << fc_cpu_order | cpu) + mp->min_xid; ep->em = mp; + ep->pool = pool; ep->lp = lport; ep->f_ctl = FC_FC_FIRST_SEQ; /* next seq is first seq */ ep->rxid = FC_XID_UNKNOWN; @@ -560,7 +556,7 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, out: return ep; err: - spin_unlock_bh(&mp->em_lock); + spin_unlock_bh(&pool->lock); atomic_inc(&mp->stats.no_free_exch_xid); mempool_free(ep, mp->ep_pool); return NULL; @@ -597,16 +593,18 @@ EXPORT_SYMBOL(fc_exch_alloc); */ static struct fc_exch *fc_exch_find(struct fc_exch_mgr *mp, u16 xid) { + struct fc_exch_pool *pool; struct fc_exch *ep = NULL; if ((xid >= mp->min_xid) && (xid <= mp->max_xid)) { - spin_lock_bh(&mp->em_lock); - ep = mp->exches[xid - mp->min_xid]; + pool = per_cpu_ptr(mp->pool, xid & fc_cpu_mask); + spin_lock_bh(&pool->lock); + ep = fc_exch_ptr_get(pool, (xid - mp->min_xid) >> fc_cpu_order); if (ep) { fc_exch_hold(ep); WARN_ON(ep->xid != xid); } - spin_unlock_bh(&mp->em_lock); + spin_unlock_bh(&pool->lock); } return ep; } @@ -620,7 +618,7 @@ void fc_exch_done(struct fc_seq *sp) rc = fc_exch_done_locked(ep); spin_unlock_bh(&ep->ex_lock); if (!rc) - fc_exch_mgr_delete_ep(ep); + fc_exch_delete(ep); } EXPORT_SYMBOL(fc_exch_done); @@ -1213,7 +1211,7 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) WARN_ON(fc_seq_exch(sp) != ep); spin_unlock_bh(&ep->ex_lock); if (!rc) - fc_exch_mgr_delete_ep(ep); + fc_exch_delete(ep); } /* @@ -1323,7 +1321,7 @@ static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp) rc = fc_exch_done_locked(ep); spin_unlock_bh(&ep->ex_lock); if (!rc) - fc_exch_mgr_delete_ep(ep); + fc_exch_delete(ep); if (resp) resp(sp, fp, ex_resp_arg); @@ -1466,48 +1464,76 @@ static void fc_exch_reset(struct fc_exch *ep) rc = fc_exch_done_locked(ep); spin_unlock_bh(&ep->ex_lock); if (!rc) - fc_exch_mgr_delete_ep(ep); + fc_exch_delete(ep); if (resp) resp(sp, ERR_PTR(-FC_EX_CLOSED), arg); } -/* - * Reset an exchange manager, releasing all sequences and exchanges. - * If sid is non-zero, reset only exchanges we source from that FID. - * If did is non-zero, reset only exchanges destined to that FID. +/** + * fc_exch_pool_reset() - Resets an per cpu exches pool. + * @lport: ptr to the local port + * @pool: ptr to the per cpu exches pool + * @sid: source FC ID + * @did: destination FC ID + * + * Resets an per cpu exches pool, releasing its all sequences + * and exchanges. If sid is non-zero, then reset only exchanges + * we sourced from that FID. If did is non-zero, reset only + * exchanges destined to that FID. */ -void fc_exch_mgr_reset(struct fc_lport *lp, u32 sid, u32 did) +static void fc_exch_pool_reset(struct fc_lport *lport, + struct fc_exch_pool *pool, + u32 sid, u32 did) { struct fc_exch *ep; struct fc_exch *next; - struct fc_exch_mgr *mp; - struct fc_exch_mgr_anchor *ema; - list_for_each_entry(ema, &lp->ema_list, ema_list) { - mp = ema->mp; - spin_lock_bh(&mp->em_lock); + spin_lock_bh(&pool->lock); restart: - list_for_each_entry_safe(ep, next, &mp->ex_list, ex_list) { - if ((lp == ep->lp) && - (sid == 0 || sid == ep->sid) && - (did == 0 || did == ep->did)) { - fc_exch_hold(ep); - spin_unlock_bh(&mp->em_lock); - - fc_exch_reset(ep); - - fc_exch_release(ep); - spin_lock_bh(&mp->em_lock); - - /* - * must restart loop incase while lock - * was down multiple eps were released. - */ - goto restart; - } + list_for_each_entry_safe(ep, next, &pool->ex_list, ex_list) { + if ((lport == ep->lp) && + (sid == 0 || sid == ep->sid) && + (did == 0 || did == ep->did)) { + fc_exch_hold(ep); + spin_unlock_bh(&pool->lock); + + fc_exch_reset(ep); + + fc_exch_release(ep); + spin_lock_bh(&pool->lock); + + /* + * must restart loop incase while lock + * was down multiple eps were released. + */ + goto restart; } - spin_unlock_bh(&mp->em_lock); + } + spin_unlock_bh(&pool->lock); +} + +/** + * fc_exch_mgr_reset() - Resets all EMs of a lport + * @lport: ptr to the local port + * @sid: source FC ID + * @did: destination FC ID + * + * Reset all EMs of a lport, releasing its all sequences and + * exchanges. If sid is non-zero, then reset only exchanges + * we sourced from that FID. If did is non-zero, reset only + * exchanges destined to that FID. + */ +void fc_exch_mgr_reset(struct fc_lport *lport, u32 sid, u32 did) +{ + struct fc_exch_mgr_anchor *ema; + unsigned int cpu; + + list_for_each_entry(ema, &lport->ema_list, ema_list) { + for_each_possible_cpu(cpu) + fc_exch_pool_reset(lport, + per_cpu_ptr(ema->mp->pool, cpu), + sid, did); } } EXPORT_SYMBOL(fc_exch_mgr_reset); @@ -1777,11 +1803,6 @@ static void fc_exch_mgr_destroy(struct kref *kref) { struct fc_exch_mgr *mp = container_of(kref, struct fc_exch_mgr, kref); - /* - * The total exch count must be zero - * before freeing exchange manager. - */ - WARN_ON(mp->total_exches != 0); mempool_destroy(mp->ep_pool); free_percpu(mp->pool); kfree(mp); @@ -1802,7 +1823,6 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, bool (*match)(struct fc_frame *)) { struct fc_exch_mgr *mp; - size_t len; u16 pool_exch_range; size_t pool_size; unsigned int cpu; @@ -1816,25 +1836,16 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, } /* - * Memory need for EM + * allocate memory for EM */ - len = (max_xid - min_xid + 1) * (sizeof(struct fc_exch *)); - len += sizeof(struct fc_exch_mgr); - - mp = kzalloc(len, GFP_ATOMIC); + mp = kzalloc(sizeof(struct fc_exch_mgr), GFP_ATOMIC); if (!mp) return NULL; mp->class = class; - mp->total_exches = 0; - mp->exches = (struct fc_exch **)(mp + 1); /* adjust em exch xid range for offload */ mp->min_xid = min_xid; mp->max_xid = max_xid; - mp->next_xid = min_xid; - - INIT_LIST_HEAD(&mp->ex_list); - spin_lock_init(&mp->em_lock); mp->ep_pool = mempool_create_slab_pool(2, fc_em_cachep); if (!mp->ep_pool) @@ -1944,7 +1955,7 @@ err: rc = fc_exch_done_locked(ep); spin_unlock_bh(&ep->ex_lock); if (!rc) - fc_exch_mgr_delete_ep(ep); + fc_exch_delete(ep); return NULL; } EXPORT_SYMBOL(fc_exch_seq_send); -- cgit v1.2.3-18-g5258 From 3793d2fc3eac7da11ca44df125cbcedd0b5315d0 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Sat, 5 Sep 2009 20:22:36 -0700 Subject: RDMA/cxgb3: iwch_unregister_device leaks memory The iwcm struct mem is never freed. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb3/iwch_provider.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index e2a63214008..72aa57cdf69 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -1418,6 +1418,7 @@ int iwch_register_device(struct iwch_dev *dev) bail2: ib_unregister_device(&dev->ibdev); bail1: + kfree(dev->ibdev.iwcm); return ret; } @@ -1430,5 +1431,6 @@ void iwch_unregister_device(struct iwch_dev *dev) device_remove_file(&dev->ibdev.dev, iwch_class_attributes[i]); ib_unregister_device(&dev->ibdev); + kfree(dev->ibdev.iwcm); return; } -- cgit v1.2.3-18-g5258 From b496fe82d4075847a1c42efba2e81d28f6467b3a Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Sat, 5 Sep 2009 20:22:37 -0700 Subject: RDMA/cxgb3: Set the appropriate IO channel in rdma_init work requests Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb3/cxio_hal.c | 4 +++- drivers/infiniband/hw/cxgb3/cxio_wr.h | 6 ++++++ drivers/infiniband/hw/cxgb3/iwch_qp.c | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index 62f9cf2f94e..4dec515c676 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -852,7 +852,9 @@ int cxio_rdma_init(struct cxio_rdev *rdev_p, struct t3_rdma_init_attr *attr) wqe->qpcaps = attr->qpcaps; wqe->ulpdu_size = cpu_to_be16(attr->tcp_emss); wqe->rqe_count = cpu_to_be16(attr->rqe_count); - wqe->flags_rtr_type = cpu_to_be16(attr->flags|V_RTR_TYPE(attr->rtr_type)); + wqe->flags_rtr_type = cpu_to_be16(attr->flags | + V_RTR_TYPE(attr->rtr_type) | + V_CHAN(attr->chan)); wqe->ord = cpu_to_be32(attr->ord); wqe->ird = cpu_to_be32(attr->ird); wqe->qp_dma_addr = cpu_to_be64(attr->qp_dma_addr); diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h index 32e3b1461d8..a197a5b7ac7 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_wr.h +++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h @@ -327,6 +327,11 @@ enum rdma_init_rtr_types { #define V_RTR_TYPE(x) ((x) << S_RTR_TYPE) #define G_RTR_TYPE(x) ((((x) >> S_RTR_TYPE)) & M_RTR_TYPE) +#define S_CHAN 4 +#define M_CHAN 0x3 +#define V_CHAN(x) ((x) << S_CHAN) +#define G_CHAN(x) ((((x) >> S_CHAN)) & M_CHAN) + struct t3_rdma_init_attr { u32 tid; u32 qpid; @@ -346,6 +351,7 @@ struct t3_rdma_init_attr { u16 flags; u16 rqe_count; u32 irs; + u32 chan; }; struct t3_rdma_init_wr { diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c index 27bbdc8e773..6e865347194 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_qp.c +++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c @@ -889,6 +889,7 @@ static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp, init_attr.qp_dma_size = (1UL << qhp->wq.size_log2); init_attr.rqe_count = iwch_rqes_posted(qhp); init_attr.flags = qhp->attr.mpa_attr.initiator ? MPA_INITIATOR : 0; + init_attr.chan = qhp->ep->l2t->smt_idx; if (peer2peer) { init_attr.rtr_type = RTR_READ; if (init_attr.ord == 0 && qhp->attr.mpa_attr.initiator) -- cgit v1.2.3-18-g5258 From fa0d4c11c4b6eb49708b82b638ceb0761152f46a Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Sat, 5 Sep 2009 20:22:38 -0700 Subject: RDMA/cxgb3: Handle port events properly Massage the err_handler upcall into an event handler upcall, pass netdev port events to the cxgb3 ULPs and generate RDMA port events based on LLD port events. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb3/iwch.c | 28 ++++++++++++++++++++-------- drivers/net/cxgb3/cxgb3_main.c | 6 ++++-- drivers/net/cxgb3/cxgb3_offload.c | 6 +++--- drivers/net/cxgb3/cxgb3_offload.h | 8 +++++--- drivers/scsi/cxgb3i/cxgb3i_init.c | 12 ++++++------ 5 files changed, 38 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c index 26fc0a4eaa7..5796170b0b2 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.c +++ b/drivers/infiniband/hw/cxgb3/iwch.c @@ -51,7 +51,7 @@ cxgb3_cpl_handler_func t3c_handlers[NUM_CPL_CMDS]; static void open_rnic_dev(struct t3cdev *); static void close_rnic_dev(struct t3cdev *); -static void iwch_err_handler(struct t3cdev *, u32, u32); +static void iwch_event_handler(struct t3cdev *, u32, u32); struct cxgb3_client t3c_client = { .name = "iw_cxgb3", @@ -59,7 +59,7 @@ struct cxgb3_client t3c_client = { .remove = close_rnic_dev, .handlers = t3c_handlers, .redirect = iwch_ep_redirect, - .err_handler = iwch_err_handler + .event_handler = iwch_event_handler }; static LIST_HEAD(dev_list); @@ -162,21 +162,33 @@ static void close_rnic_dev(struct t3cdev *tdev) mutex_unlock(&dev_mutex); } -static void iwch_err_handler(struct t3cdev *tdev, u32 status, u32 error) +static void iwch_event_handler(struct t3cdev *tdev, u32 evt, u32 port_id) { struct cxio_rdev *rdev = tdev->ulp; struct iwch_dev *rnicp = rdev_to_iwch_dev(rdev); struct ib_event event; + u32 portnum = port_id + 1; - if (status == OFFLOAD_STATUS_DOWN) { + switch (evt) { + case OFFLOAD_STATUS_DOWN: { rdev->flags = CXIO_ERROR_FATAL; - - event.device = &rnicp->ibdev; event.event = IB_EVENT_DEVICE_FATAL; - event.element.port_num = 0; - ib_dispatch_event(&event); + break; + } + case OFFLOAD_PORT_DOWN: { + event.event = IB_EVENT_PORT_ERR; + break; + } + case OFFLOAD_PORT_UP: { + event.event = IB_EVENT_PORT_ACTIVE; + break; + } } + event.device = &rnicp->ibdev; + event.element.port_num = portnum; + ib_dispatch_event(&event); + return; } diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index fb5df5c6203..c97ab82ec74 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -1286,6 +1286,7 @@ static int cxgb_open(struct net_device *dev) if (!other_ports) schedule_chk_task(adapter); + cxgb3_event_notify(&adapter->tdev, OFFLOAD_PORT_UP, pi->port_id); return 0; } @@ -1318,6 +1319,7 @@ static int cxgb_close(struct net_device *dev) if (!adapter->open_device_map) cxgb_down(adapter); + cxgb3_event_notify(&adapter->tdev, OFFLOAD_PORT_DOWN, pi->port_id); return 0; } @@ -2717,7 +2719,7 @@ static int t3_adapter_error(struct adapter *adapter, int reset) if (is_offload(adapter) && test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) { - cxgb3_err_notify(&adapter->tdev, OFFLOAD_STATUS_DOWN, 0); + cxgb3_event_notify(&adapter->tdev, OFFLOAD_STATUS_DOWN, 0); offload_close(&adapter->tdev); } @@ -2782,7 +2784,7 @@ static void t3_resume_ports(struct adapter *adapter) } if (is_offload(adapter) && !ofld_disable) - cxgb3_err_notify(&adapter->tdev, OFFLOAD_STATUS_UP, 0); + cxgb3_event_notify(&adapter->tdev, OFFLOAD_STATUS_UP, 0); } /* diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index f9f54b57b28..75064eea1d8 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -153,14 +153,14 @@ void cxgb3_remove_clients(struct t3cdev *tdev) mutex_unlock(&cxgb3_db_lock); } -void cxgb3_err_notify(struct t3cdev *tdev, u32 status, u32 error) +void cxgb3_event_notify(struct t3cdev *tdev, u32 event, u32 port) { struct cxgb3_client *client; mutex_lock(&cxgb3_db_lock); list_for_each_entry(client, &client_list, client_list) { - if (client->err_handler) - client->err_handler(tdev, status, error); + if (client->event_handler) + client->event_handler(tdev, event, port); } mutex_unlock(&cxgb3_db_lock); } diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h index 55945f422ae..670aa62042d 100644 --- a/drivers/net/cxgb3/cxgb3_offload.h +++ b/drivers/net/cxgb3/cxgb3_offload.h @@ -64,14 +64,16 @@ void cxgb3_register_client(struct cxgb3_client *client); void cxgb3_unregister_client(struct cxgb3_client *client); void cxgb3_add_clients(struct t3cdev *tdev); void cxgb3_remove_clients(struct t3cdev *tdev); -void cxgb3_err_notify(struct t3cdev *tdev, u32 status, u32 error); +void cxgb3_event_notify(struct t3cdev *tdev, u32 event, u32 port); typedef int (*cxgb3_cpl_handler_func)(struct t3cdev *dev, struct sk_buff *skb, void *ctx); enum { OFFLOAD_STATUS_UP, - OFFLOAD_STATUS_DOWN + OFFLOAD_STATUS_DOWN, + OFFLOAD_PORT_DOWN, + OFFLOAD_PORT_UP }; struct cxgb3_client { @@ -82,7 +84,7 @@ struct cxgb3_client { int (*redirect)(void *ctx, struct dst_entry *old, struct dst_entry *new, struct l2t_entry *l2t); struct list_head client_list; - void (*err_handler)(struct t3cdev *tdev, u32 status, u32 error); + void (*event_handler)(struct t3cdev *tdev, u32 event, u32 port); }; /* diff --git a/drivers/scsi/cxgb3i/cxgb3i_init.c b/drivers/scsi/cxgb3i/cxgb3i_init.c index 042d9bce991..d0ab23a5835 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_init.c +++ b/drivers/scsi/cxgb3i/cxgb3i_init.c @@ -26,7 +26,7 @@ MODULE_VERSION(DRV_MODULE_VERSION); static void open_s3_dev(struct t3cdev *); static void close_s3_dev(struct t3cdev *); -static void s3_err_handler(struct t3cdev *tdev, u32 status, u32 error); +static void s3_event_handler(struct t3cdev *tdev, u32 event, u32 port); static cxgb3_cpl_handler_func cxgb3i_cpl_handlers[NUM_CPL_CMDS]; static struct cxgb3_client t3c_client = { @@ -34,7 +34,7 @@ static struct cxgb3_client t3c_client = { .handlers = cxgb3i_cpl_handlers, .add = open_s3_dev, .remove = close_s3_dev, - .err_handler = s3_err_handler, + .event_handler = s3_event_handler, }; /** @@ -66,16 +66,16 @@ static void close_s3_dev(struct t3cdev *t3dev) cxgb3i_ddp_cleanup(t3dev); } -static void s3_err_handler(struct t3cdev *tdev, u32 status, u32 error) +static void s3_event_handler(struct t3cdev *tdev, u32 event, u32 port) { struct cxgb3i_adapter *snic = cxgb3i_adapter_find_by_tdev(tdev); - cxgb3i_log_info("snic 0x%p, tdev 0x%p, status 0x%x, err 0x%x.\n", - snic, tdev, status, error); + cxgb3i_log_info("snic 0x%p, tdev 0x%p, event 0x%x, port 0x%x.\n", + snic, tdev, event, port); if (!snic) return; - switch (status) { + switch (event) { case OFFLOAD_STATUS_DOWN: snic->flags |= CXGB3I_ADAPTER_FLAG_RESET; break; -- cgit v1.2.3-18-g5258 From 6e47fe43502ba6dfe86d556661795d9bb0361309 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Sat, 5 Sep 2009 20:22:38 -0700 Subject: RDMA/cxgb3: Don't free endpoints early - Keep ref on connection request endpoints until either accepted or rejected so it doesn't get freed early. - Endpoint flags now need to be set via atomic bitops because they can be set on both the iw_cxgb3 workqueue thread and user disconnect threads. - Don't move out of CLOSING too early due to multiple calls to iwch_ep_disconnect. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb3/iwch_cm.c | 52 +++++++++++++++++++---------------- drivers/infiniband/hw/cxgb3/iwch_cm.h | 9 +++--- 2 files changed, 33 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 52d7bb0c2a1..7f22f179771 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -286,7 +286,7 @@ void __free_ep(struct kref *kref) ep = container_of(container_of(kref, struct iwch_ep_common, kref), struct iwch_ep, com); PDBG("%s ep %p state %s\n", __func__, ep, states[state_read(&ep->com)]); - if (ep->com.flags & RELEASE_RESOURCES) { + if (test_bit(RELEASE_RESOURCES, &ep->com.flags)) { cxgb3_remove_tid(ep->com.tdev, (void *)ep, ep->hwtid); dst_release(ep->dst); l2t_release(L2DATA(ep->com.tdev), ep->l2t); @@ -297,7 +297,7 @@ void __free_ep(struct kref *kref) static void release_ep_resources(struct iwch_ep *ep) { PDBG("%s ep %p tid %d\n", __func__, ep, ep->hwtid); - ep->com.flags |= RELEASE_RESOURCES; + set_bit(RELEASE_RESOURCES, &ep->com.flags); put_ep(&ep->com); } @@ -786,10 +786,12 @@ static void connect_request_upcall(struct iwch_ep *ep) event.private_data_len = ep->plen; event.private_data = ep->mpa_pkt + sizeof(struct mpa_message); event.provider_data = ep; - if (state_read(&ep->parent_ep->com) != DEAD) + if (state_read(&ep->parent_ep->com) != DEAD) { + get_ep(&ep->com); ep->parent_ep->com.cm_id->event_handler( ep->parent_ep->com.cm_id, &event); + } put_ep(&ep->parent_ep->com); ep->parent_ep = NULL; } @@ -1156,8 +1158,7 @@ static int abort_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) * We get 2 abort replies from the HW. The first one must * be ignored except for scribbling that we need one more. */ - if (!(ep->com.flags & ABORT_REQ_IN_PROGRESS)) { - ep->com.flags |= ABORT_REQ_IN_PROGRESS; + if (!test_and_set_bit(ABORT_REQ_IN_PROGRESS, &ep->com.flags)) { return CPL_RET_BUF_DONE; } @@ -1480,7 +1481,6 @@ static int peer_close(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) * rejects the CR. */ __state_set(&ep->com, CLOSING); - get_ep(&ep->com); break; case MPA_REP_SENT: __state_set(&ep->com, CLOSING); @@ -1561,8 +1561,7 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) * We get 2 peer aborts from the HW. The first one must * be ignored except for scribbling that we need one more. */ - if (!(ep->com.flags & PEER_ABORT_IN_PROGRESS)) { - ep->com.flags |= PEER_ABORT_IN_PROGRESS; + if (!test_and_set_bit(PEER_ABORT_IN_PROGRESS, &ep->com.flags)) { return CPL_RET_BUF_DONE; } @@ -1591,7 +1590,6 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) * the reference on it until the ULP accepts or * rejects the CR. */ - get_ep(&ep->com); break; case MORIBUND: case CLOSING: @@ -1797,6 +1795,7 @@ int iwch_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len) err = send_mpa_reject(ep, pdata, pdata_len); err = iwch_ep_disconnect(ep, 0, GFP_KERNEL); } + put_ep(&ep->com); return 0; } @@ -1810,8 +1809,10 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) struct iwch_qp *qp = get_qhp(h, conn_param->qpn); PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid); - if (state_read(&ep->com) == DEAD) - return -ECONNRESET; + if (state_read(&ep->com) == DEAD) { + err = -ECONNRESET; + goto err; + } BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD); BUG_ON(!qp); @@ -1819,7 +1820,8 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) if ((conn_param->ord > qp->rhp->attr.max_rdma_read_qp_depth) || (conn_param->ird > qp->rhp->attr.max_rdma_reads_per_qp)) { abort_connection(ep, NULL, GFP_KERNEL); - return -EINVAL; + err = -EINVAL; + goto err; } cm_id->add_ref(cm_id); @@ -1836,8 +1838,6 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) PDBG("%s %d ird %d ord %d\n", __func__, __LINE__, ep->ird, ep->ord); - get_ep(&ep->com); - /* bind QP to EP and move to RTS */ attrs.mpa_attr = ep->mpa_attr; attrs.max_ird = ep->ird; @@ -1855,30 +1855,31 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) err = iwch_modify_qp(ep->com.qp->rhp, ep->com.qp, mask, &attrs, 1); if (err) - goto err; + goto err1; /* if needed, wait for wr_ack */ if (iwch_rqes_posted(qp)) { wait_event(ep->com.waitq, ep->com.rpl_done); err = ep->com.rpl_err; if (err) - goto err; + goto err1; } err = send_mpa_reply(ep, conn_param->private_data, conn_param->private_data_len); if (err) - goto err; + goto err1; state_set(&ep->com, FPDU_MODE); established_upcall(ep); put_ep(&ep->com); return 0; -err: +err1: ep->com.cm_id = NULL; ep->com.qp = NULL; cm_id->rem_ref(cm_id); +err: put_ep(&ep->com); return err; } @@ -2097,14 +2098,17 @@ int iwch_ep_disconnect(struct iwch_ep *ep, int abrupt, gfp_t gfp) ep->com.state = CLOSING; start_ep_timer(ep); } + set_bit(CLOSE_SENT, &ep->com.flags); break; case CLOSING: - close = 1; - if (abrupt) { - stop_ep_timer(ep); - ep->com.state = ABORTING; - } else - ep->com.state = MORIBUND; + if (!test_and_set_bit(CLOSE_SENT, &ep->com.flags)) { + close = 1; + if (abrupt) { + stop_ep_timer(ep); + ep->com.state = ABORTING; + } else + ep->com.state = MORIBUND; + } break; case MORIBUND: case ABORTING: diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.h b/drivers/infiniband/hw/cxgb3/iwch_cm.h index 43c0aea7ead..b9efadfffb4 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.h +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.h @@ -145,9 +145,10 @@ enum iwch_ep_state { }; enum iwch_ep_flags { - PEER_ABORT_IN_PROGRESS = (1 << 0), - ABORT_REQ_IN_PROGRESS = (1 << 1), - RELEASE_RESOURCES = (1 << 2), + PEER_ABORT_IN_PROGRESS = 0, + ABORT_REQ_IN_PROGRESS = 1, + RELEASE_RESOURCES = 2, + CLOSE_SENT = 3, }; struct iwch_ep_common { @@ -162,7 +163,7 @@ struct iwch_ep_common { wait_queue_head_t waitq; int rpl_done; int rpl_err; - u32 flags; + unsigned long flags; }; struct iwch_listen_ep { -- cgit v1.2.3-18-g5258 From a52bf98d99e922363d1d600a79de6aaf00090d47 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Sat, 5 Sep 2009 20:22:38 -0700 Subject: RDMA/cxgb3: Wake up any waiters on peer close/abort A close/abort while waiting for a wr_ack during connection migration can cause a hung process in iwch_accept_cr/iwch_reject_cr. The fix is to set rpl_error/rpl_done and wake up the waiters when we get a close/abort while in MPA_REQ_RCVD state. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb3/iwch_cm.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 7f22f179771..66b41351910 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -1478,9 +1478,14 @@ static int peer_close(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) /* * We're gonna mark this puppy DEAD, but keep * the reference on it until the ULP accepts or - * rejects the CR. + * rejects the CR. Also wake up anyone waiting + * in rdma connection migration (see iwch_accept_cr()). */ __state_set(&ep->com, CLOSING); + ep->com.rpl_done = 1; + ep->com.rpl_err = -ECONNRESET; + PDBG("waking up ep %p\n", ep); + wake_up(&ep->com.waitq); break; case MPA_REP_SENT: __state_set(&ep->com, CLOSING); @@ -1588,8 +1593,13 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) /* * We're gonna mark this puppy DEAD, but keep * the reference on it until the ULP accepts or - * rejects the CR. + * rejects the CR. Also wake up anyone waiting + * in rdma connection migration (see iwch_accept_cr()). */ + ep->com.rpl_done = 1; + ep->com.rpl_err = -ECONNRESET; + PDBG("waking up ep %p\n", ep); + wake_up(&ep->com.waitq); break; case MORIBUND: case CLOSING: @@ -1828,8 +1838,6 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) ep->com.cm_id = cm_id; ep->com.qp = qp; - ep->com.rpl_done = 0; - ep->com.rpl_err = 0; ep->ird = conn_param->ird; ep->ord = conn_param->ord; -- cgit v1.2.3-18-g5258 From 50d40b8e53fab58b0141a75f7448eb28f9e21338 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Sat, 5 Sep 2009 20:22:54 -0700 Subject: IB/ehca: Make port autodetect mode the default Make port autodetect mode the default for the ehca driver. The autodetect code has been in the kernel for several releases now and has proved to be stable. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index fab18a2c74a..5b635aa5947 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -52,7 +52,7 @@ #include "ehca_tools.h" #include "hcp_if.h" -#define HCAD_VERSION "0028" +#define HCAD_VERSION "0029" MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Christoph Raisch "); @@ -64,7 +64,7 @@ static int ehca_hw_level = 0; static int ehca_poll_all_eqs = 1; int ehca_debug_level = 0; -int ehca_nr_ports = 2; +int ehca_nr_ports = -1; int ehca_use_hp_mr = 0; int ehca_port_act_time = 30; int ehca_static_rate = -1; @@ -95,8 +95,8 @@ MODULE_PARM_DESC(hw_level, "Hardware level (0: autosensing (default), " "0x10..0x14: eHCA, 0x20..0x23: eHCA2)"); MODULE_PARM_DESC(nr_ports, - "number of connected ports (-1: autodetect, 1: port one only, " - "2: two ports (default)"); + "number of connected ports (-1: autodetect (default), " + "1: port one only, 2: two ports)"); MODULE_PARM_DESC(use_hp_mr, "Use high performance MRs (default: no)"); MODULE_PARM_DESC(port_act_time, -- cgit v1.2.3-18-g5258 From d706834d995939c96b4952bf042918879b4db18b Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Sat, 5 Sep 2009 20:22:55 -0700 Subject: IB/ehca: Construct MAD redirect replies from request MAD The old code used a lot of hard-coded values, which might not be valid in all environments (especially routed fabrics or partitioned subnets). Copy as much information as possible from the incoming request to correct that. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_sqp.c | 47 ++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_sqp.c b/drivers/infiniband/hw/ehca/ehca_sqp.c index c568b28f4e2..8c1213f8916 100644 --- a/drivers/infiniband/hw/ehca/ehca_sqp.c +++ b/drivers/infiniband/hw/ehca/ehca_sqp.c @@ -125,14 +125,30 @@ struct ib_perf { u8 data[192]; } __attribute__ ((packed)); +/* TC/SL/FL packed into 32 bits, as in ClassPortInfo */ +struct tcslfl { + u32 tc:8; + u32 sl:4; + u32 fl:20; +} __attribute__ ((packed)); + +/* IP Version/TC/FL packed into 32 bits, as in GRH */ +struct vertcfl { + u32 ver:4; + u32 tc:8; + u32 fl:20; +} __attribute__ ((packed)); static int ehca_process_perf(struct ib_device *ibdev, u8 port_num, + struct ib_wc *in_wc, struct ib_grh *in_grh, struct ib_mad *in_mad, struct ib_mad *out_mad) { struct ib_perf *in_perf = (struct ib_perf *)in_mad; struct ib_perf *out_perf = (struct ib_perf *)out_mad; struct ib_class_port_info *poi = (struct ib_class_port_info *)out_perf->data; + struct tcslfl *tcslfl = + (struct tcslfl *)&poi->redirect_tcslfl; struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device); struct ehca_sport *sport = &shca->sport[port_num - 1]; @@ -158,10 +174,29 @@ static int ehca_process_perf(struct ib_device *ibdev, u8 port_num, poi->base_version = 1; poi->class_version = 1; poi->resp_time_value = 18; - poi->redirect_lid = sport->saved_attr.lid; - poi->redirect_qp = sport->pma_qp_nr; + + /* copy local routing information from WC where applicable */ + tcslfl->sl = in_wc->sl; + poi->redirect_lid = + sport->saved_attr.lid | in_wc->dlid_path_bits; + poi->redirect_qp = sport->pma_qp_nr; poi->redirect_qkey = IB_QP1_QKEY; - poi->redirect_pkey = IB_DEFAULT_PKEY_FULL; + + ehca_query_pkey(ibdev, port_num, in_wc->pkey_index, + &poi->redirect_pkey); + + /* if request was globally routed, copy route info */ + if (in_grh) { + struct vertcfl *vertcfl = + (struct vertcfl *)&in_grh->version_tclass_flow; + memcpy(poi->redirect_gid, in_grh->dgid.raw, + sizeof(poi->redirect_gid)); + tcslfl->tc = vertcfl->tc; + tcslfl->fl = vertcfl->fl; + } else + /* else only fill in default GID */ + ehca_query_gid(ibdev, port_num, 0, + (union ib_gid *)&poi->redirect_gid); ehca_dbg(ibdev, "ehca_pma_lid=%x ehca_pma_qp=%x", sport->saved_attr.lid, sport->pma_qp_nr); @@ -183,8 +218,7 @@ perf_reply: int ehca_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, struct ib_wc *in_wc, struct ib_grh *in_grh, - struct ib_mad *in_mad, - struct ib_mad *out_mad) + struct ib_mad *in_mad, struct ib_mad *out_mad) { int ret; @@ -196,7 +230,8 @@ int ehca_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, return IB_MAD_RESULT_SUCCESS; ehca_dbg(ibdev, "port_num=%x src_qp=%x", port_num, in_wc->src_qp); - ret = ehca_process_perf(ibdev, port_num, in_mad, out_mad); + ret = ehca_process_perf(ibdev, port_num, in_wc, in_grh, + in_mad, out_mad); return ret; } -- cgit v1.2.3-18-g5258 From 6303e74c699d6ba8bd3d44ec6898b2d6aa55d788 Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Sat, 5 Sep 2009 20:22:55 -0700 Subject: IB/ehca: Fix CQE flags reporting The driver was reporting CQE flags in the wrong bit positions, causing consumers to miss incoming immediate data. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_reqs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c index 5a3d96f84c7..8fd88cd828f 100644 --- a/drivers/infiniband/hw/ehca/ehca_reqs.c +++ b/drivers/infiniband/hw/ehca/ehca_reqs.c @@ -786,7 +786,11 @@ repoll: wc->slid = cqe->rlid; wc->dlid_path_bits = cqe->dlid; wc->src_qp = cqe->remote_qp_number; - wc->wc_flags = cqe->w_completion_flags; + /* + * HW has "Immed data present" and "GRH present" in bits 6 and 5. + * SW defines those in bits 1 and 0, so we can just shift and mask. + */ + wc->wc_flags = (cqe->w_completion_flags >> 5) & 3; wc->ex.imm_data = cpu_to_be32(cqe->immediate_data); wc->sl = cqe->service_level; -- cgit v1.2.3-18-g5258 From 286b63d09660de0fbd0d7748984d7ae491c7fdb6 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Sat, 5 Sep 2009 20:23:21 -0700 Subject: IB/ipath: strncpy() doesn't always NUL-terminate strlcpy() will always null terminate the string. node_desc is not guaranteed to be NUL-terminated so just use memcpy(). Signed-off-by: Roel Kluin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_file_ops.c | 2 +- drivers/infiniband/hw/ipath/ipath_mad.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c index 23173982b32..38a28700661 100644 --- a/drivers/infiniband/hw/ipath/ipath_file_ops.c +++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c @@ -1616,7 +1616,7 @@ static int try_alloc_port(struct ipath_devdata *dd, int port, pd->port_cnt = 1; port_fp(fp) = pd; pd->port_pid = get_pid(task_pid(current)); - strncpy(pd->port_comm, current->comm, sizeof(pd->port_comm)); + strlcpy(pd->port_comm, current->comm, sizeof(pd->port_comm)); ipath_stats.sps_ports++; ret = 0; } else diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c index 16a702d4601..ceb98ee7866 100644 --- a/drivers/infiniband/hw/ipath/ipath_mad.c +++ b/drivers/infiniband/hw/ipath/ipath_mad.c @@ -60,7 +60,7 @@ static int recv_subn_get_nodedescription(struct ib_smp *smp, if (smp->attr_mod) smp->status |= IB_SMP_INVALID_FIELD; - strncpy(smp->data, ibdev->node_desc, sizeof(smp->data)); + memcpy(smp->data, ibdev->node_desc, sizeof(smp->data)); return reply(smp); } -- cgit v1.2.3-18-g5258 From cd0bcf4cb963a147baf0b79d94c25ba86220f708 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:23:38 -0700 Subject: IPoIB: Remove unused includes Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_cm.c | 1 - drivers/infiniband/ulp/ipoib/ipoib_ib.c | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 181b1f32325..8f4b4fca2a1 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -31,7 +31,6 @@ */ #include -#include #include #include #include diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index e7e5adf84e8..e35f4a0ea9d 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -36,7 +36,6 @@ #include #include -#include #include #include -- cgit v1.2.3-18-g5258 From 721d67cdca5b7642b380ca0584de8dceecf6102f Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:23:40 -0700 Subject: IPoIB: Drop priv->lock before calling ipoib_send() IPoIB currently must use irqsave locking for priv->lock, since it is taken from interrupt context in one path. However, ipoib_send() does skb_orphan(), and the network stack locking is not IRQ-safe. Therefore we need to make sure we don't hold priv->lock when calling ipoib_send() to avoid lockdep warnings (the code was almost certainly safe in practice, since the only code path that takes priv->lock from interrupt context would never call into the network stack). Addresses: http://bugzilla.kernel.org/show_bug.cgi?id=13757 Reported-by: Bart Van Assche Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_main.c | 7 ++++++- drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index e319d91f60a..2bf5116deec 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -604,8 +604,11 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) skb_queue_len(&neigh->queue)); goto err_drop; } - } else + } else { + spin_unlock_irqrestore(&priv->lock, flags); ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb_dst(skb)->neighbour->ha)); + return; + } } else { neigh->ah = NULL; @@ -688,7 +691,9 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, ipoib_dbg(priv, "Send unicast ARP to %04x\n", be16_to_cpu(path->pathrec.dlid)); + spin_unlock_irqrestore(&priv->lock, flags); ipoib_send(dev, skb, path->ah, IPOIB_QPN(phdr->hwaddr)); + return; } else if ((path->query || !path_rec_start(dev, path)) && skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) { /* put pseudoheader back on for next time */ diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index a0e97532e71..a0825fe451e 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -720,7 +720,9 @@ out: } } + spin_unlock_irqrestore(&priv->lock, flags); ipoib_send(dev, skb, mcast->ah, IB_MULTICAST_QPN); + return; } unlock: -- cgit v1.2.3-18-g5258 From 5e47596bee12597824a3b5b21e20f80b61e58a35 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sat, 5 Sep 2009 20:23:40 -0700 Subject: IPoIB: Check multicast address format Check that the format of multicast link addresses is correct before taking them from dev->mc_list to priv->multicast_list. This way we never try to send a bogus address to the SA, which prevents badness from erronous 'ip maddr addr add', broken bonding drivers, etc. Signed-off-by: Jason Gunthorpe Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index a0825fe451e..25874fc680c 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -760,6 +760,20 @@ void ipoib_mcast_dev_flush(struct net_device *dev) } } +static int ipoib_mcast_addr_is_valid(const u8 *addr, unsigned int addrlen, + const u8 *broadcast) +{ + if (addrlen != INFINIBAND_ALEN) + return 0; + /* reserved QPN, prefix, scope */ + if (memcmp(addr, broadcast, 6)) + return 0; + /* signature lower, pkey */ + if (memcmp(addr + 7, broadcast + 7, 3)) + return 0; + return 1; +} + void ipoib_mcast_restart_task(struct work_struct *work) { struct ipoib_dev_priv *priv = @@ -793,6 +807,11 @@ void ipoib_mcast_restart_task(struct work_struct *work) for (mclist = dev->mc_list; mclist; mclist = mclist->next) { union ib_gid mgid; + if (!ipoib_mcast_addr_is_valid(mclist->dmi_addr, + mclist->dmi_addrlen, + dev->broadcast)) + continue; + memcpy(mgid.raw, mclist->dmi_addr + 4, sizeof mgid); mcast = __ipoib_mcast_find(dev, &mgid); -- cgit v1.2.3-18-g5258 From 60f2b652f54aa4ac4127a538abad05235fb9c469 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:24:10 -0700 Subject: IB/mad: Check hop count field in directed route MAD to avoid array overflow The hop count field in a directed route MAD is only allowed to be in the range 0 to 63 (by spec). Check that this really is the case to avoid accessing outside the bounds of the hop array. Reported-by: Roel Kluin Signed-off-by: Roland Dreier --- drivers/infiniband/core/smi.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/core/smi.c b/drivers/infiniband/core/smi.c index 87236753bce..5855e4405d9 100644 --- a/drivers/infiniband/core/smi.c +++ b/drivers/infiniband/core/smi.c @@ -52,6 +52,10 @@ enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp, hop_cnt = smp->hop_cnt; /* See section 14.2.2.2, Vol 1 IB spec */ + /* C14-6 -- valid hop_cnt values are from 0 to 63 */ + if (hop_cnt >= IB_SMP_MAX_PATH_HOPS) + return IB_SMI_DISCARD; + if (!ib_get_smp_direction(smp)) { /* C14-9:1 */ if (hop_cnt && hop_ptr == 0) { @@ -133,6 +137,10 @@ enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type, hop_cnt = smp->hop_cnt; /* See section 14.2.2.2, Vol 1 IB spec */ + /* C14-6 -- valid hop_cnt values are from 0 to 63 */ + if (hop_cnt >= IB_SMP_MAX_PATH_HOPS) + return IB_SMI_DISCARD; + if (!ib_get_smp_direction(smp)) { /* C14-9:1 -- sender should have incremented hop_ptr */ if (hop_cnt && hop_ptr == 0) -- cgit v1.2.3-18-g5258 From 6276e08a9bdf645b71a092fb4530baf4f6c4c6eb Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:24:23 -0700 Subject: IB: Use DEFINE_SPINLOCK() for static spinlocks Rather than just defining static spinlock_t variables and then initializing them later in init functions, simply define them with DEFINE_SPINLOCK() and remove the calls to spin_lock_init(). This cleans up the source a tad and also shrinks the compiled code; eg on x86-64: add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-40 (-40) function old new delta ib_uverbs_init 336 326 -10 ib_mad_init_module 147 137 -10 ib_sa_init 123 103 -20 Signed-off-by: Roland Dreier --- drivers/infiniband/core/mad.c | 6 +----- drivers/infiniband/core/sa_query.c | 7 ++----- drivers/infiniband/core/uverbs_main.c | 4 +--- 3 files changed, 4 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index de922a04ca2..5cef8f87b96 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -51,8 +51,7 @@ static struct list_head ib_mad_port_list; static u32 ib_mad_client_id = 0; /* Port list lock */ -static spinlock_t ib_mad_port_list_lock; - +static DEFINE_SPINLOCK(ib_mad_port_list_lock); /* Forward declarations */ static int method_in_use(struct ib_mad_mgmt_method_table **method, @@ -2984,8 +2983,6 @@ static int __init ib_mad_init_module(void) { int ret; - spin_lock_init(&ib_mad_port_list_lock); - ib_mad_cache = kmem_cache_create("ib_mad", sizeof(struct ib_mad_private), 0, @@ -3021,4 +3018,3 @@ static void __exit ib_mad_cleanup_module(void) module_init(ib_mad_init_module); module_exit(ib_mad_cleanup_module); - diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 1865049e80f..82543716d59 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -109,10 +109,10 @@ static struct ib_client sa_client = { .remove = ib_sa_remove_one }; -static spinlock_t idr_lock; +static DEFINE_SPINLOCK(idr_lock); static DEFINE_IDR(query_idr); -static spinlock_t tid_lock; +static DEFINE_SPINLOCK(tid_lock); static u32 tid; #define PATH_REC_FIELD(field) \ @@ -1077,9 +1077,6 @@ static int __init ib_sa_init(void) { int ret; - spin_lock_init(&idr_lock); - spin_lock_init(&tid_lock); - get_random_bytes(&tid, sizeof tid); ret = ib_register_client(&sa_client); diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index eb36a81dd09..1a3ac3d882b 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -73,7 +73,7 @@ DEFINE_IDR(ib_uverbs_cq_idr); DEFINE_IDR(ib_uverbs_qp_idr); DEFINE_IDR(ib_uverbs_srq_idr); -static spinlock_t map_lock; +static DEFINE_SPINLOCK(map_lock); static struct ib_uverbs_device *dev_table[IB_UVERBS_MAX_DEVICES]; static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); @@ -836,8 +836,6 @@ static int __init ib_uverbs_init(void) { int ret; - spin_lock_init(&map_lock); - ret = register_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES, "infiniband_verbs"); if (ret) { -- cgit v1.2.3-18-g5258 From 181c74e87eb93df447a759af93cf0a279875ea7d Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sat, 5 Sep 2009 20:24:23 -0700 Subject: RDMA/amso1100: Use %pM conversion specifier Use the %pM conversion specifier to print a MAC address. Signed-off-by: Tobias Klauser Acked-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/amso1100/c2.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c index 0cfbb6d2f76..8250740c94b 100644 --- a/drivers/infiniband/hw/amso1100/c2.c +++ b/drivers/infiniband/hw/amso1100/c2.c @@ -86,11 +86,7 @@ MODULE_DEVICE_TABLE(pci, c2_pci_table); static void c2_print_macaddr(struct net_device *netdev) { - pr_debug("%s: MAC %02X:%02X:%02X:%02X:%02X:%02X, " - "IRQ %u\n", netdev->name, - netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], - netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5], - netdev->irq); + pr_debug("%s: MAC %pM, IRQ %u\n", netdev->name, netdev->dev_addr, netdev->irq); } static void c2_set_rxbufsize(struct c2_port *c2_port) -- cgit v1.2.3-18-g5258 From f1aa78b26e8dabc2956be94a93c40c6cc08eb4a3 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Sat, 5 Sep 2009 20:24:24 -0700 Subject: IB: Use printk_once() for driver versions Replace open-coded reimplementations with printk_once(). Signed-off-by: Marcin Slusarz Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb3/iwch.c | 4 +--- drivers/infiniband/hw/mlx4/main.c | 6 +----- drivers/infiniband/hw/mthca/mthca_main.c | 6 +----- 3 files changed, 3 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c index 26fc0a4eaa7..9cc99df3d61 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.c +++ b/drivers/infiniband/hw/cxgb3/iwch.c @@ -105,11 +105,9 @@ static void rnic_init(struct iwch_dev *rnicp) static void open_rnic_dev(struct t3cdev *tdev) { struct iwch_dev *rnicp; - static int vers_printed; PDBG("%s t3cdev %p\n", __func__, tdev); - if (!vers_printed++) - printk(KERN_INFO MOD "Chelsio T3 RDMA Driver - version %s\n", + printk_once(KERN_INFO MOD "Chelsio T3 RDMA Driver - version %s\n", DRV_VERSION); rnicp = (struct iwch_dev *)ib_alloc_device(sizeof(*rnicp)); if (!rnicp) { diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index ae3d7590346..0b2f77a98e2 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -540,15 +540,11 @@ static struct device_attribute *mlx4_class_attributes[] = { static void *mlx4_ib_add(struct mlx4_dev *dev) { - static int mlx4_ib_version_printed; struct mlx4_ib_dev *ibdev; int num_ports = 0; int i; - if (!mlx4_ib_version_printed) { - printk(KERN_INFO "%s", mlx4_ib_version); - ++mlx4_ib_version_printed; - } + printk_once(KERN_INFO "%s", mlx4_ib_version); mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) num_ports++; diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 13da9f1d24c..2e4e0430378 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -1215,15 +1215,11 @@ int __mthca_restart_one(struct pci_dev *pdev) static int __devinit mthca_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { - static int mthca_version_printed = 0; int ret; mutex_lock(&mthca_device_mutex); - if (!mthca_version_printed) { - printk(KERN_INFO "%s", mthca_version); - ++mthca_version_printed; - } + printk_once(KERN_INFO "%s", mthca_version); if (id->driver_data >= ARRAY_SIZE(mthca_hca_table)) { printk(KERN_ERR PFX "%s has invalid driver data %lx\n", -- cgit v1.2.3-18-g5258 From e1d7806df32bd247af6a2fe52433ecdd34fee773 Mon Sep 17 00:00:00 2001 From: Yossi Etigin Date: Sat, 5 Sep 2009 20:24:24 -0700 Subject: IB/core: Fix send multicast group leave retry Until now, retries were only sent when joining a multicast group. This patch will adds retries when leaving a multicast group as well. Signed-off-by: Ron Livne Signed-off-by: Yossi Etigin Acked-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/multicast.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c index 107f170c57c..8d82ba17135 100644 --- a/drivers/infiniband/core/multicast.c +++ b/drivers/infiniband/core/multicast.c @@ -106,6 +106,8 @@ struct mcast_group { struct ib_sa_query *query; int query_id; u16 pkey_index; + u8 leave_state; + int retries; }; struct mcast_member { @@ -350,6 +352,7 @@ static int send_leave(struct mcast_group *group, u8 leave_state) rec = group->rec; rec.join_state = leave_state; + group->leave_state = leave_state; ret = ib_sa_mcmember_rec_query(&sa_client, port->dev->device, port->port_num, IB_SA_METHOD_DELETE, &rec, @@ -542,7 +545,11 @@ static void leave_handler(int status, struct ib_sa_mcmember_rec *rec, { struct mcast_group *group = context; - mcast_work_handler(&group->work); + if (status && group->retries > 0 && + !send_leave(group, group->leave_state)) + group->retries--; + else + mcast_work_handler(&group->work); } static struct mcast_group *acquire_group(struct mcast_port *port, @@ -565,6 +572,7 @@ static struct mcast_group *acquire_group(struct mcast_port *port, if (!group) return NULL; + group->retries = 3; group->port = port; group->rec.mgid = *mgid; group->pkey_index = MCAST_INVALID_PKEY_INDEX; -- cgit v1.2.3-18-g5258 From b1b8afb83336b66ac7198111aad4ead41132b53f Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Sat, 5 Sep 2009 20:24:24 -0700 Subject: IB/uverbs: Return ENOSYS for unimplemented commands (not EINVAL) Since the original commit 883a99c7 ("[IB] uverbs: Add a mask of device methods allowed for userspace"), the uverbs core returns EINVAL for commands not implemented by a specific low-level driver. This creates a problem that there is no way to tell the difference between an unimplemented command and an implemented one which is incorrectly invoked (which also returns EINVAL). The fix is to have unimplemented commands return ENOSYS. Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 1a3ac3d882b..d3fff9e008a 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -584,14 +584,16 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, if (hdr.command < 0 || hdr.command >= ARRAY_SIZE(uverbs_cmd_table) || - !uverbs_cmd_table[hdr.command] || - !(file->device->ib_dev->uverbs_cmd_mask & (1ull << hdr.command))) + !uverbs_cmd_table[hdr.command]) return -EINVAL; if (!file->ucontext && hdr.command != IB_USER_VERBS_CMD_GET_CONTEXT) return -EINVAL; + if (!(file->device->ib_dev->uverbs_cmd_mask & (1ull << hdr.command))) + return -ENOSYS; + return uverbs_cmd_table[hdr.command](file, buf + sizeof hdr, hdr.in_words * 4, hdr.out_words * 4); } -- cgit v1.2.3-18-g5258 From 1493ab4083c315a978e51b8957bf87859703745d Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Sat, 5 Sep 2009 20:24:24 -0700 Subject: RDMA/amso1100: Check kmalloc() result in c2_register_device() dev->ibdev.iwcm allocation may fail, prevent a dereference. Signed-off-by: Roel Kluin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/amso1100/c2_provider.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c index f1948fad85d..ad723bd8bf4 100644 --- a/drivers/infiniband/hw/amso1100/c2_provider.c +++ b/drivers/infiniband/hw/amso1100/c2_provider.c @@ -780,11 +780,11 @@ int c2_register_device(struct c2_dev *dev) /* Register pseudo network device */ dev->pseudo_netdev = c2_pseudo_netdev_init(dev); if (!dev->pseudo_netdev) - goto out3; + goto out; ret = register_netdev(dev->pseudo_netdev); if (ret) - goto out2; + goto out_free_netdev; pr_debug("%s:%u\n", __func__, __LINE__); strlcpy(dev->ibdev.name, "amso%d", IB_DEVICE_NAME_MAX); @@ -851,6 +851,10 @@ int c2_register_device(struct c2_dev *dev) dev->ibdev.post_recv = c2_post_receive; dev->ibdev.iwcm = kmalloc(sizeof(*dev->ibdev.iwcm), GFP_KERNEL); + if (dev->ibdev.iwcm == NULL) { + ret = -ENOMEM; + goto out_unregister_netdev; + } dev->ibdev.iwcm->add_ref = c2_add_ref; dev->ibdev.iwcm->rem_ref = c2_rem_ref; dev->ibdev.iwcm->get_qp = c2_get_qp; @@ -862,23 +866,25 @@ int c2_register_device(struct c2_dev *dev) ret = ib_register_device(&dev->ibdev); if (ret) - goto out1; + goto out_free_iwcm; for (i = 0; i < ARRAY_SIZE(c2_dev_attributes); ++i) { ret = device_create_file(&dev->ibdev.dev, c2_dev_attributes[i]); if (ret) - goto out0; + goto out_unregister_ibdev; } - goto out3; + goto out; -out0: +out_unregister_ibdev: ib_unregister_device(&dev->ibdev); -out1: +out_free_iwcm: + kfree(dev->ibdev.iwcm); +out_unregister_netdev: unregister_netdev(dev->pseudo_netdev); -out2: +out_free_netdev: free_netdev(dev->pseudo_netdev); -out3: +out: pr_debug("%s:%u ret=%d\n", __func__, __LINE__, ret); return ret; } -- cgit v1.2.3-18-g5258 From a01df0fe5e4db8c272dcc395354884ff7c15fc10 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:24:48 -0700 Subject: mlx4_core: Use pci_request_regions() The old code used two calls to pci_request_region() to get the two BARs for the mlx4 device, for no particularly good reason. Clean up the code a little by converting this to a single call to pci_request_regions(). Signed-off-by: Roland Dreier --- drivers/net/mlx4/main.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index dac621b1e9f..5c1afe0d73e 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -1070,18 +1070,12 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) goto err_disable_pdev; } - err = pci_request_region(pdev, 0, DRV_NAME); + err = pci_request_regions(pdev, DRV_NAME); if (err) { - dev_err(&pdev->dev, "Cannot request control region, aborting.\n"); + dev_err(&pdev->dev, "Couldn't get PCI resources, aborting\n"); goto err_disable_pdev; } - err = pci_request_region(pdev, 2, DRV_NAME); - if (err) { - dev_err(&pdev->dev, "Cannot request UAR region, aborting.\n"); - goto err_release_bar0; - } - pci_set_master(pdev); err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); @@ -1090,7 +1084,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { dev_err(&pdev->dev, "Can't set PCI DMA mask, aborting.\n"); - goto err_release_bar2; + goto err_release_regions; } } err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); @@ -1101,7 +1095,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) if (err) { dev_err(&pdev->dev, "Can't set consistent PCI DMA mask, " "aborting.\n"); - goto err_release_bar2; + goto err_release_regions; } } @@ -1110,7 +1104,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) dev_err(&pdev->dev, "Device struct alloc failed, " "aborting.\n"); err = -ENOMEM; - goto err_release_bar2; + goto err_release_regions; } dev = &priv->dev; @@ -1205,11 +1199,8 @@ err_cmd: err_free_dev: kfree(priv); -err_release_bar2: - pci_release_region(pdev, 2); - -err_release_bar0: - pci_release_region(pdev, 0); +err_release_regions: + pci_release_regions(pdev); err_disable_pdev: pci_disable_device(pdev); @@ -1265,8 +1256,7 @@ static void mlx4_remove_one(struct pci_dev *pdev) pci_disable_msix(pdev); kfree(priv); - pci_release_region(pdev, 2); - pci_release_region(pdev, 0); + pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); } -- cgit v1.2.3-18-g5258 From ff149b2a168296c74763cb4a6e7054bdb0a426a1 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:24:49 -0700 Subject: mlx4_core: Remove unnecessary includes of Lots of mlx4 files with no function annotations included for no reason. Signed-off-by: Roland Dreier --- drivers/net/mlx4/cq.c | 1 - drivers/net/mlx4/eq.c | 1 - drivers/net/mlx4/icm.c | 1 - drivers/net/mlx4/mcg.c | 1 - drivers/net/mlx4/mr.c | 1 - drivers/net/mlx4/pd.c | 1 - drivers/net/mlx4/profile.c | 2 -- drivers/net/mlx4/qp.c | 2 -- drivers/net/mlx4/reset.c | 1 - drivers/net/mlx4/srq.c | 2 -- 10 files changed, 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c index ac57b6a42c6..ccfe276943f 100644 --- a/drivers/net/mlx4/cq.c +++ b/drivers/net/mlx4/cq.c @@ -34,7 +34,6 @@ * SOFTWARE. */ -#include #include #include diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index b9ceddde46c..c11a0525c40 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c @@ -31,7 +31,6 @@ * SOFTWARE. */ -#include #include #include #include diff --git a/drivers/net/mlx4/icm.c b/drivers/net/mlx4/icm.c index baf4bf66062..04b382fcb8c 100644 --- a/drivers/net/mlx4/icm.c +++ b/drivers/net/mlx4/icm.c @@ -31,7 +31,6 @@ * SOFTWARE. */ -#include #include #include #include diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c index 6053c357a47..5ccbce9866f 100644 --- a/drivers/net/mlx4/mcg.c +++ b/drivers/net/mlx4/mcg.c @@ -31,7 +31,6 @@ * SOFTWARE. */ -#include #include #include diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index f96948be0a4..ca7ab8e7b4c 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -32,7 +32,6 @@ * SOFTWARE. */ -#include #include #include diff --git a/drivers/net/mlx4/pd.c b/drivers/net/mlx4/pd.c index 26d1a7a9e37..c4988d6bd5b 100644 --- a/drivers/net/mlx4/pd.c +++ b/drivers/net/mlx4/pd.c @@ -31,7 +31,6 @@ * SOFTWARE. */ -#include #include #include diff --git a/drivers/net/mlx4/profile.c b/drivers/net/mlx4/profile.c index bd22df95adf..ca25b9dc837 100644 --- a/drivers/net/mlx4/profile.c +++ b/drivers/net/mlx4/profile.c @@ -32,8 +32,6 @@ * SOFTWARE. */ -#include - #include "mlx4.h" #include "fw.h" diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c index 1c565ef8d17..42ab9fc01d3 100644 --- a/drivers/net/mlx4/qp.c +++ b/drivers/net/mlx4/qp.c @@ -33,8 +33,6 @@ * SOFTWARE. */ -#include - #include #include diff --git a/drivers/net/mlx4/reset.c b/drivers/net/mlx4/reset.c index 3951b884c0f..e5741dab382 100644 --- a/drivers/net/mlx4/reset.c +++ b/drivers/net/mlx4/reset.c @@ -31,7 +31,6 @@ * SOFTWARE. */ -#include #include #include #include diff --git a/drivers/net/mlx4/srq.c b/drivers/net/mlx4/srq.c index fe9f218691f..1377d0dc8f1 100644 --- a/drivers/net/mlx4/srq.c +++ b/drivers/net/mlx4/srq.c @@ -31,8 +31,6 @@ * SOFTWARE. */ -#include - #include #include "mlx4.h" -- cgit v1.2.3-18-g5258 From 338a8fad27908f64a0d249cc9f5c7d4ddb7e5684 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:24:49 -0700 Subject: IB/mlx4: Annotate CQ locking mlx4_ib_lock_cqs()/mlx4_ib_unlock_cqs() are helper functions that lock/unlock both CQs attached to a QP in the proper order to avoid AB-BA deadlocks. Annotate this so sparse can understand what's going on (and warn us if we misuse these functions). Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/qp.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index c4a02648c8a..219b10397b4 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -615,10 +615,12 @@ static enum mlx4_qp_state to_mlx4_state(enum ib_qp_state state) } static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv_cq) + __acquires(&send_cq->lock) __acquires(&recv_cq->lock) { - if (send_cq == recv_cq) + if (send_cq == recv_cq) { spin_lock_irq(&send_cq->lock); - else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { + __acquire(&recv_cq->lock); + } else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { spin_lock_irq(&send_cq->lock); spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING); } else { @@ -628,10 +630,12 @@ static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv } static void mlx4_ib_unlock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv_cq) + __releases(&send_cq->lock) __releases(&recv_cq->lock) { - if (send_cq == recv_cq) + if (send_cq == recv_cq) { + __release(&recv_cq->lock); spin_unlock_irq(&send_cq->lock); - else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { + } else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { spin_unlock(&recv_cq->lock); spin_unlock_irq(&send_cq->lock); } else { -- cgit v1.2.3-18-g5258 From fa0681d2129732027355d6b7083dd8932b9b799d Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:24:49 -0700 Subject: mlx4_core: Allocate and map sufficient ICM memory for EQ context The current implementation allocates a single host page for EQ context memory, which was OK when we only allocated a few EQs. However, since we now allocate an EQ for each CPU core, this patch removes the hard-coded limit (which we exceed with 4 KB pages and 128 byte EQ context entries with 32 CPUs) and uses the same ICM table code as all other context tables, which ends up simplifying the code quite a bit while fixing the problem. This problem was actually hit in practice on a dual-socket Nehalem box with 16 real hardware threads and sufficiently odd ACPI tables that it shows on boot SMP: Allowing 32 CPUs, 16 hotplug CPUs so num_possible_cpus() ends up 32, and mlx4 ends up creating 33 MSI-X interrupts and 33 EQs. This mlx4 bug means that mlx4 can't even initialize at all on this quite mainstream system. Cc: Reported-by: Eli Cohen Tested-by: Christoph Lameter Signed-off-by: Roland Dreier --- drivers/net/mlx4/eq.c | 42 ------------------------------------------ drivers/net/mlx4/main.c | 9 ++++++--- drivers/net/mlx4/mlx4.h | 7 +------ 3 files changed, 7 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index c11a0525c40..d7974a60b96 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c @@ -525,48 +525,6 @@ static void mlx4_unmap_clr_int(struct mlx4_dev *dev) iounmap(priv->clr_base); } -int mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - int ret; - - /* - * We assume that mapping one page is enough for the whole EQ - * context table. This is fine with all current HCAs, because - * we only use 32 EQs and each EQ uses 64 bytes of context - * memory, or 1 KB total. - */ - priv->eq_table.icm_virt = icm_virt; - priv->eq_table.icm_page = alloc_page(GFP_HIGHUSER); - if (!priv->eq_table.icm_page) - return -ENOMEM; - priv->eq_table.icm_dma = pci_map_page(dev->pdev, priv->eq_table.icm_page, 0, - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(dev->pdev, priv->eq_table.icm_dma)) { - __free_page(priv->eq_table.icm_page); - return -ENOMEM; - } - - ret = mlx4_MAP_ICM_page(dev, priv->eq_table.icm_dma, icm_virt); - if (ret) { - pci_unmap_page(dev->pdev, priv->eq_table.icm_dma, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); - __free_page(priv->eq_table.icm_page); - } - - return ret; -} - -void mlx4_unmap_eq_icm(struct mlx4_dev *dev) -{ - struct mlx4_priv *priv = mlx4_priv(dev); - - mlx4_UNMAP_ICM(dev, priv->eq_table.icm_virt, 1); - pci_unmap_page(dev->pdev, priv->eq_table.icm_dma, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); - __free_page(priv->eq_table.icm_page); -} - int mlx4_alloc_eq_table(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 5c1afe0d73e..528f89b2cde 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -525,7 +525,10 @@ static int mlx4_init_icm(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap, goto err_unmap_aux; } - err = mlx4_map_eq_icm(dev, init_hca->eqc_base); + err = mlx4_init_icm_table(dev, &priv->eq_table.table, + init_hca->eqc_base, dev_cap->eqc_entry_sz, + dev->caps.num_eqs, dev->caps.num_eqs, + 0, 0); if (err) { mlx4_err(dev, "Failed to map EQ context memory, aborting.\n"); goto err_unmap_cmpt; @@ -668,7 +671,7 @@ err_unmap_mtt: mlx4_cleanup_icm_table(dev, &priv->mr_table.mtt_table); err_unmap_eq: - mlx4_unmap_eq_icm(dev); + mlx4_cleanup_icm_table(dev, &priv->eq_table.table); err_unmap_cmpt: mlx4_cleanup_icm_table(dev, &priv->eq_table.cmpt_table); @@ -698,11 +701,11 @@ static void mlx4_free_icms(struct mlx4_dev *dev) mlx4_cleanup_icm_table(dev, &priv->qp_table.qp_table); mlx4_cleanup_icm_table(dev, &priv->mr_table.dmpt_table); mlx4_cleanup_icm_table(dev, &priv->mr_table.mtt_table); + mlx4_cleanup_icm_table(dev, &priv->eq_table.table); mlx4_cleanup_icm_table(dev, &priv->eq_table.cmpt_table); mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table); mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table); mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table); - mlx4_unmap_eq_icm(dev); mlx4_UNMAP_ICM_AUX(dev); mlx4_free_icm(dev, priv->fw.aux_icm, 0); diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index 5bd79c2b184..bc72d6e4919 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h @@ -205,9 +205,7 @@ struct mlx4_eq_table { void __iomem **uar_map; u32 clr_mask; struct mlx4_eq *eq; - u64 icm_virt; - struct page *icm_page; - dma_addr_t icm_dma; + struct mlx4_icm_table table; struct mlx4_icm_table cmpt_table; int have_irq; u8 inta_pin; @@ -373,9 +371,6 @@ u64 mlx4_make_profile(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap, struct mlx4_init_hca_param *init_hca); -int mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt); -void mlx4_unmap_eq_icm(struct mlx4_dev *dev); - int mlx4_cmd_init(struct mlx4_dev *dev); void mlx4_cmd_cleanup(struct mlx4_dev *dev); void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param); -- cgit v1.2.3-18-g5258 From 1af92e2a211b0d46ef60ea9f30f989fd7b5725fa Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Sat, 5 Sep 2009 20:24:49 -0700 Subject: mlx4_core: Avoid double free_icms On the error path of mlx4_init_hca(), mlx4_close_hca() is called, followed by mlx4_free_icms() and mlx4_UNMAP_FA(). But both those functions are also called from mlx4_close_hca(), which leads to a double free. Signed-off-by: Yevgeny Petrilin Signed-off-by: Roland Dreier --- drivers/net/mlx4/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 528f89b2cde..3dd481e77f9 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -789,7 +789,7 @@ static int mlx4_init_hca(struct mlx4_dev *dev) return 0; err_close: - mlx4_close_hca(dev); + mlx4_CLOSE_HCA(dev, 0); err_free_icm: mlx4_free_icms(dev); -- cgit v1.2.3-18-g5258 From f5f5951c7494b6ae89ec53ca7ca6b0177ebd1308 Mon Sep 17 00:00:00 2001 From: Arputham Benjamin Date: Sat, 5 Sep 2009 20:24:50 -0700 Subject: mlx4_core: Distinguish multiple devices in /proc/interrupts When the mlx4 driver uses the same name for interrupts for every device in the system. This can make it very confusing trying to work out exactly which device MSI-X interrupts are for. Change the driver to add the PCI name of the device to the interrupt name. Signed-off-by: Arputham Benjamin Signed-off-by: Roland Dreier --- drivers/net/mlx4/eq.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index d7974a60b96..bffb7995cb7 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c @@ -40,6 +40,10 @@ #include "mlx4.h" #include "fw.h" +enum { + MLX4_IRQNAME_SIZE = 64 +}; + enum { MLX4_NUM_ASYNC_EQE = 0x100, MLX4_NUM_SPARE_EQE = 0x80, @@ -572,7 +576,9 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) priv->eq_table.clr_int = priv->clr_base + (priv->eq_table.inta_pin < 32 ? 4 : 0); - priv->eq_table.irq_names = kmalloc(16 * dev->caps.num_comp_vectors, GFP_KERNEL); + priv->eq_table.irq_names = + kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1), + GFP_KERNEL); if (!priv->eq_table.irq_names) { err = -ENOMEM; goto err_out_bitmap; @@ -595,17 +601,25 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) goto err_out_comp; if (dev->flags & MLX4_FLAG_MSI_X) { - static const char async_eq_name[] = "mlx4-async"; const char *eq_name; for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) { if (i < dev->caps.num_comp_vectors) { - snprintf(priv->eq_table.irq_names + i * 16, 16, - "mlx4-comp-%d", i); - eq_name = priv->eq_table.irq_names + i * 16; - } else - eq_name = async_eq_name; + snprintf(priv->eq_table.irq_names + + i * MLX4_IRQNAME_SIZE, + MLX4_IRQNAME_SIZE, + "mlx4-comp-%d@pci:%s", i, + pci_name(dev->pdev)); + } else { + snprintf(priv->eq_table.irq_names + + i * MLX4_IRQNAME_SIZE, + MLX4_IRQNAME_SIZE, + "mlx4-async@pci:%s", + pci_name(dev->pdev)); + } + eq_name = priv->eq_table.irq_names + + i * MLX4_IRQNAME_SIZE; err = request_irq(priv->eq_table.eq[i].irq, mlx4_msi_x_interrupt, 0, eq_name, priv->eq_table.eq + i); @@ -615,8 +629,12 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) priv->eq_table.eq[i].have_irq = 1; } } else { + snprintf(priv->eq_table.irq_names, + MLX4_IRQNAME_SIZE, + DRV_NAME "@pci:%s", + pci_name(dev->pdev)); err = request_irq(dev->pdev->irq, mlx4_interrupt, - IRQF_SHARED, DRV_NAME, dev); + IRQF_SHARED, priv->eq_table.irq_names, dev); if (err) goto err_out_async; -- cgit v1.2.3-18-g5258 From 3b4a8cd51e59c1c342c51b241bbb96c6ac24a147 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Sat, 5 Sep 2009 20:24:50 -0700 Subject: IB/mlx4: Don't allow userspace open while recovering from catastrophic error Userspace apps are supposed to release all ib device resources if they receive a fatal async event (IBV_EVENT_DEVICE_FATAL). However, the app has no way of knowing when the device has come back up, except to repeatedly attempt ibv_open_device() until it succeeds. However, currently there is no protection against the open succeeding while the device is in being removed following the fatal event. In this case, the open will succeed, but as a result the device waits in the middle of its removal until the new app releases its resources -- and the new app will not do so, since the open succeeded at a point following the fatal event generation. This patch adds an "active" flag to the device. The active flag is set to false (in the fatal event flow) before the "fatal" event is generated, so any subsequent ibv_dev_open() call to the device will fail until the device comes back up, thus preventing the above deadlock. Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/main.c | 6 ++++++ drivers/infiniband/hw/mlx4/mlx4_ib.h | 1 + 2 files changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index ae3d7590346..313ce7fb273 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -342,6 +342,9 @@ static struct ib_ucontext *mlx4_ib_alloc_ucontext(struct ib_device *ibdev, struct mlx4_ib_alloc_ucontext_resp resp; int err; + if (!dev->ib_active) + return ERR_PTR(-EAGAIN); + resp.qp_tab_size = dev->dev->caps.num_qps; resp.bf_reg_size = dev->dev->caps.bf_reg_size; resp.bf_regs_per_page = dev->dev->caps.bf_regs_per_page; @@ -673,6 +676,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) goto err_reg; } + ibdev->ib_active = true; + return ibdev; err_reg: @@ -729,6 +734,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr, break; case MLX4_DEV_EVENT_CATASTROPHIC_ERROR: + ibdev->ib_active = false; ibev.event = IB_EVENT_DEVICE_FATAL; break; diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index 8a7dd6795fa..3486d7675e5 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -175,6 +175,7 @@ struct mlx4_ib_dev { spinlock_t sm_lock; struct mutex cap_mask_mutex; + bool ib_active; }; static inline struct mlx4_ib_dev *to_mdev(struct ib_device *ibdev) -- cgit v1.2.3-18-g5258 From fc1285585f5bfda18e3fe7f90afd47da51b82bd6 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:36:13 -0700 Subject: IB/mthca: Remove unnecessary include of mthca_config_reg.h was including for no reason -- the whole file is just defines of constants, so it's entirely self-contained. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_config_reg.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_config_reg.h b/drivers/infiniband/hw/mthca/mthca_config_reg.h index 75671f75cac..155bc66395b 100644 --- a/drivers/infiniband/hw/mthca/mthca_config_reg.h +++ b/drivers/infiniband/hw/mthca/mthca_config_reg.h @@ -34,8 +34,6 @@ #ifndef MTHCA_CONFIG_REG_H #define MTHCA_CONFIG_REG_H -#include - #define MTHCA_HCR_BASE 0x80680 #define MTHCA_HCR_SIZE 0x0001c #define MTHCA_ECR_BASE 0x80700 -- cgit v1.2.3-18-g5258 From deecb5d6728fff5288b6f7241ee8225ba0d8c6d2 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:36:15 -0700 Subject: IB/mthca: Remove unnecessary include of mthca_reset.c doesn't have any function annotations, so there's no reason to include . Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_reset.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_reset.c b/drivers/infiniband/hw/mthca/mthca_reset.c index acb6817f606..2a13a163d33 100644 --- a/drivers/infiniband/hw/mthca/mthca_reset.c +++ b/drivers/infiniband/hw/mthca/mthca_reset.c @@ -30,7 +30,6 @@ * SOFTWARE. */ -#include #include #include #include -- cgit v1.2.3-18-g5258 From ffe063f32bacad7d5111ae9c2b3e31addb47ce39 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 5 Sep 2009 20:36:15 -0700 Subject: IB/mthca: Annotate CQ locking mthca_ib_lock_cqs()/mthca_ib_unlock_cqs() are helper functions that lock/unlock both CQs attached to a QP in the proper order to avoid AB-BA deadlocks. Annotate this so sparse can understand what's going on (and warn us if we misuse these functions). Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_qp.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index f5081bfde6d..c10576fa60c 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -1319,10 +1319,12 @@ int mthca_alloc_qp(struct mthca_dev *dev, } static void mthca_lock_cqs(struct mthca_cq *send_cq, struct mthca_cq *recv_cq) + __acquires(&send_cq->lock) __acquires(&recv_cq->lock) { - if (send_cq == recv_cq) + if (send_cq == recv_cq) { spin_lock_irq(&send_cq->lock); - else if (send_cq->cqn < recv_cq->cqn) { + __acquire(&recv_cq->lock); + } else if (send_cq->cqn < recv_cq->cqn) { spin_lock_irq(&send_cq->lock); spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING); } else { @@ -1332,10 +1334,12 @@ static void mthca_lock_cqs(struct mthca_cq *send_cq, struct mthca_cq *recv_cq) } static void mthca_unlock_cqs(struct mthca_cq *send_cq, struct mthca_cq *recv_cq) + __releases(&send_cq->lock) __releases(&recv_cq->lock) { - if (send_cq == recv_cq) + if (send_cq == recv_cq) { + __release(&recv_cq->lock); spin_unlock_irq(&send_cq->lock); - else if (send_cq->cqn < recv_cq->cqn) { + } else if (send_cq->cqn < recv_cq->cqn) { spin_unlock(&recv_cq->lock); spin_unlock_irq(&send_cq->lock); } else { -- cgit v1.2.3-18-g5258 From d94a86890137fabcc97eaa324bfef3f1827744c8 Mon Sep 17 00:00:00 2001 From: Arputham Benjamin Date: Sat, 5 Sep 2009 20:36:15 -0700 Subject: IB/mthca: Distinguish multiple devices in /proc/interrupts When the mthca driver uses the same name for interrupts for every device in the system. This can make it very confusing trying to work out exactly which device MSI-X interrupts are for. Change the driver to add the PCI name of the device to the interrupt name. Signed-off-by: Arputham Benjamin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_eq.c | 17 ++++++++++++----- drivers/infiniband/hw/mthca/mthca_provider.h | 1 + 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c index 90e4e450a12..8c31fa36e95 100644 --- a/drivers/infiniband/hw/mthca/mthca_eq.c +++ b/drivers/infiniband/hw/mthca/mthca_eq.c @@ -829,27 +829,34 @@ int mthca_init_eq_table(struct mthca_dev *dev) if (dev->mthca_flags & MTHCA_FLAG_MSI_X) { static const char *eq_name[] = { - [MTHCA_EQ_COMP] = DRV_NAME " (comp)", - [MTHCA_EQ_ASYNC] = DRV_NAME " (async)", - [MTHCA_EQ_CMD] = DRV_NAME " (cmd)" + [MTHCA_EQ_COMP] = DRV_NAME "-comp", + [MTHCA_EQ_ASYNC] = DRV_NAME "-async", + [MTHCA_EQ_CMD] = DRV_NAME "-cmd" }; for (i = 0; i < MTHCA_NUM_EQ; ++i) { + snprintf(dev->eq_table.eq[i].irq_name, + IB_DEVICE_NAME_MAX, + "%s@pci:%s", eq_name[i], + pci_name(dev->pdev)); err = request_irq(dev->eq_table.eq[i].msi_x_vector, mthca_is_memfree(dev) ? mthca_arbel_msi_x_interrupt : mthca_tavor_msi_x_interrupt, - 0, eq_name[i], dev->eq_table.eq + i); + 0, dev->eq_table.eq[i].irq_name, + dev->eq_table.eq + i); if (err) goto err_out_cmd; dev->eq_table.eq[i].have_irq = 1; } } else { + snprintf(dev->eq_table.eq[0].irq_name, IB_DEVICE_NAME_MAX, + DRV_NAME "@pci:%s", pci_name(dev->pdev)); err = request_irq(dev->pdev->irq, mthca_is_memfree(dev) ? mthca_arbel_interrupt : mthca_tavor_interrupt, - IRQF_SHARED, DRV_NAME, dev); + IRQF_SHARED, dev->eq_table.eq[0].irq_name, dev); if (err) goto err_out_cmd; dev->eq_table.have_irq = 1; diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h index c621f8794b8..90f4c4d2e98 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.h +++ b/drivers/infiniband/hw/mthca/mthca_provider.h @@ -113,6 +113,7 @@ struct mthca_eq { int nent; struct mthca_buf_list *page_list; struct mthca_mr mr; + char irq_name[IB_DEVICE_NAME_MAX]; }; struct mthca_av; -- cgit v1.2.3-18-g5258 From d84106477733cb155c5dcaea664ddf120bf69eb7 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Sat, 5 Sep 2009 20:36:16 -0700 Subject: IB/mthca: Don't allow userspace open while recovering from catastrophic error Userspace apps are supposed to release all ib device resources if they receive a fatal async event (IBV_EVENT_DEVICE_FATAL). However, the app has no way of knowing when the device has come back up, except to repeatedly attempt ibv_open_device() until it succeeds. However, currently there is no protection against the open succeeding while the device is in being removed following the fatal event. In this case, the open will succeed, but as a result the device waits in the middle of its removal until the new app releases its resources -- and the new app will not do so, since the open succeeded at a point following the fatal event generation. This patch adds an "active" flag to the device. The active flag is set to false (in the fatal event flow) before the "fatal" event is generated, so any subsequent ibv_dev_open() call to the device will fail until the device comes back up, thus preventing the above deadlock. Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_catas.c | 1 + drivers/infiniband/hw/mthca/mthca_dev.h | 1 + drivers/infiniband/hw/mthca/mthca_main.c | 2 ++ drivers/infiniband/hw/mthca/mthca_provider.c | 3 +++ 4 files changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_catas.c b/drivers/infiniband/hw/mthca/mthca_catas.c index 65ad359fdf1..056b2a4c697 100644 --- a/drivers/infiniband/hw/mthca/mthca_catas.c +++ b/drivers/infiniband/hw/mthca/mthca_catas.c @@ -88,6 +88,7 @@ static void handle_catas(struct mthca_dev *dev) event.device = &dev->ib_dev; event.event = IB_EVENT_DEVICE_FATAL; event.element.port_num = 0; + dev->active = false; ib_dispatch_event(&event); diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index 9ef611f6dd3..7e6a6d64ad4 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h @@ -357,6 +357,7 @@ struct mthca_dev { struct ib_ah *sm_ah[MTHCA_MAX_PORTS]; spinlock_t sm_lock; u8 rate[MTHCA_MAX_PORTS]; + bool active; }; #ifdef CONFIG_INFINIBAND_MTHCA_DEBUG diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 13da9f1d24c..518cc540e51 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -1116,6 +1116,8 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type) pci_set_drvdata(pdev, mdev); mdev->hca_type = hca_type; + mdev->active = true; + return 0; err_unregister: diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 87ad889e367..bcf7a401482 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -334,6 +334,9 @@ static struct ib_ucontext *mthca_alloc_ucontext(struct ib_device *ibdev, struct mthca_ucontext *context; int err; + if (!(to_mdev(ibdev)->active)) + return ERR_PTR(-EAGAIN); + memset(&uresp, 0, sizeof uresp); uresp.qp_tab_size = to_mdev(ibdev)->limits.num_qps; -- cgit v1.2.3-18-g5258 From c4c3f279cd8e9cc1d3e2f364a27beadb2e69cda8 Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:36 -0700 Subject: RDMA/nes: Update refcnt during disconnect During termination, it is possible for the refcnt to go to zero while the worker thread is posting events upward. This fix increments the refcnt before the request is passed to the worker thread. The thread decrements the refcnt when the request is completed. Signed-off-by: Don Wood Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_cm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 114b802771a..fe08eb57c99 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -2456,6 +2456,7 @@ int nes_cm_disconn(struct nes_qp *nesqp) if (nesqp->disconn_pending == 0) { nesqp->disconn_pending++; spin_unlock_irqrestore(&nesqp->lock, flags); + nes_add_ref(&nesqp->ibqp); /* init our disconnect work element, to */ INIT_WORK(&nesqp->disconn_work, nes_disconnect_worker); @@ -2477,6 +2478,7 @@ static void nes_disconnect_worker(struct work_struct *work) nes_debug(NES_DBG_CM, "processing AEQE id 0x%04X for QP%u.\n", nesqp->last_aeq, nesqp->hwqp.qp_id); nes_cm_disconn_true(nesqp); + nes_rem_ref(&nesqp->ibqp); } -- cgit v1.2.3-18-g5258 From 873fcdd4bfc75880888a7d148a71d70ed87c9ebf Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:37 -0700 Subject: RDMA/nes: Allocate work item for disconnect event handling The code currently has a work structure in the QP. This requires a lock and a pending flag to ensure there is never more than one request active. When two events happen quickly (such as FIN and LLP CLOSE), it causes unnecessary timeouts since the second one is dropped. This fix allocates memory for the work request so the second one can be queued. A lock is removed since it is no longer needed. Signed-off-by: Don Wood Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_cm.c | 26 +++++++++++--------------- drivers/infiniband/hw/nes/nes_verbs.h | 7 +++++-- 2 files changed, 16 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index fe08eb57c99..d89bdee0cf5 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -2450,20 +2450,16 @@ static int nes_cm_init_tsa_conn(struct nes_qp *nesqp, struct nes_cm_node *cm_nod */ int nes_cm_disconn(struct nes_qp *nesqp) { - unsigned long flags; + struct disconn_work *work; - spin_lock_irqsave(&nesqp->lock, flags); - if (nesqp->disconn_pending == 0) { - nesqp->disconn_pending++; - spin_unlock_irqrestore(&nesqp->lock, flags); - nes_add_ref(&nesqp->ibqp); - /* init our disconnect work element, to */ - INIT_WORK(&nesqp->disconn_work, nes_disconnect_worker); - - queue_work(g_cm_core->disconn_wq, &nesqp->disconn_work); - } else - spin_unlock_irqrestore(&nesqp->lock, flags); + work = kzalloc(sizeof *work, GFP_ATOMIC); + if (!work) + return -ENOMEM; /* Timer will clean up */ + nes_add_ref(&nesqp->ibqp); + work->nesqp = nesqp; + INIT_WORK(&work->work, nes_disconnect_worker); + queue_work(g_cm_core->disconn_wq, &work->work); return 0; } @@ -2473,8 +2469,10 @@ int nes_cm_disconn(struct nes_qp *nesqp) */ static void nes_disconnect_worker(struct work_struct *work) { - struct nes_qp *nesqp = container_of(work, struct nes_qp, disconn_work); + struct disconn_work *dwork = container_of(work, struct disconn_work, work); + struct nes_qp *nesqp = dwork->nesqp; + kfree(dwork); nes_debug(NES_DBG_CM, "processing AEQE id 0x%04X for QP%u.\n", nesqp->last_aeq, nesqp->hwqp.qp_id); nes_cm_disconn_true(nesqp); @@ -2557,7 +2555,6 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) spin_lock_irqsave(&nesqp->lock, flags); } - nesqp->disconn_pending = 0; /* There might have been another AE while the lock was released */ original_hw_tcp_state = nesqp->hw_tcp_state; original_ibqp_state = nesqp->ibqp_state; @@ -2610,7 +2607,6 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) } } } else { - nesqp->disconn_pending = 0; spin_unlock_irqrestore(&nesqp->lock, flags); } diff --git a/drivers/infiniband/hw/nes/nes_verbs.h b/drivers/infiniband/hw/nes/nes_verbs.h index 41c07f29f7c..7df34fea288 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.h +++ b/drivers/infiniband/hw/nes/nes_verbs.h @@ -119,6 +119,11 @@ struct nes_wq { spinlock_t lock; }; +struct disconn_work { + struct work_struct work; + struct nes_qp *nesqp; +}; + struct iw_cm_id; struct ietf_mpa_frame; @@ -127,7 +132,6 @@ struct nes_qp { void *allocated_buffer; struct iw_cm_id *cm_id; struct workqueue_struct *wq; - struct work_struct disconn_work; struct nes_cq *nesscq; struct nes_cq *nesrcq; struct nes_pd *nespd; @@ -165,7 +169,6 @@ struct nes_qp { u8 hw_iwarp_state; u8 flush_issued; u8 hw_tcp_state; - u8 disconn_pending; u8 destroyed; }; #endif /* NES_VERBS_H */ -- cgit v1.2.3-18-g5258 From ba0c5d9a8975cf740a4a4b8c579cc4b325f8b852 Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:37 -0700 Subject: RDMA/nes: Change memory allocation for cqp request to GFP_ATOMIC The routine to allocate a cqp request is not called from process context code. Since it is not OK to sleep, it needs to use GFP_ATOMIC not GFP_KERNEL. Signed-off-by: Don Wood Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c index a282031d15c..b34072b0437 100644 --- a/drivers/infiniband/hw/nes/nes_utils.c +++ b/drivers/infiniband/hw/nes/nes_utils.c @@ -548,7 +548,7 @@ struct nes_cqp_request *nes_get_cqp_request(struct nes_device *nesdev) spin_unlock_irqrestore(&nesdev->cqp.lock, flags); } if (cqp_request == NULL) { - cqp_request = kzalloc(sizeof(struct nes_cqp_request), GFP_KERNEL); + cqp_request = kzalloc(sizeof(struct nes_cqp_request), GFP_ATOMIC); if (cqp_request) { cqp_request->dynamic = 1; INIT_LIST_HEAD(&cqp_request->list); -- cgit v1.2.3-18-g5258 From 5ee21fe0eaf68fb840f442131ab7addced1a31c3 Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:37 -0700 Subject: RDMA/nes: Clean out CQ completions when QP is destroyed When a QP is destroyed, unprocessed CQ entries could still reference the QP. This change zeroes the context value at QP destroy time. By skipping over cqe's with a zero context, poll_cq no longer processes a cqe for a destroyed QP. Signed-off-by: Don Wood Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_verbs.c | 119 +++++++++++++++++++++++----------- 1 file changed, 80 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 21e0fd336cf..c6b5873416e 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -1505,13 +1505,46 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd, } +/** + * nes_clean_cq + */ +static void nes_clean_cq(struct nes_qp *nesqp, struct nes_cq *nescq) +{ + u32 cq_head; + u32 lo; + u32 hi; + u64 u64temp; + unsigned long flags = 0; + + spin_lock_irqsave(&nescq->lock, flags); + + cq_head = nescq->hw_cq.cq_head; + while (le32_to_cpu(nescq->hw_cq.cq_vbase[cq_head].cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_VALID) { + rmb(); + lo = le32_to_cpu(nescq->hw_cq.cq_vbase[cq_head].cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]); + hi = le32_to_cpu(nescq->hw_cq.cq_vbase[cq_head].cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX]); + u64temp = (((u64)hi) << 32) | ((u64)lo); + u64temp &= ~(NES_SW_CONTEXT_ALIGN-1); + if (u64temp == (u64)(unsigned long)nesqp) { + /* Zero the context value so cqe will be ignored */ + nescq->hw_cq.cq_vbase[cq_head].cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX] = 0; + nescq->hw_cq.cq_vbase[cq_head].cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX] = 0; + } + + if (++cq_head >= nescq->hw_cq.cq_size) + cq_head = 0; + } + + spin_unlock_irqrestore(&nescq->lock, flags); +} + + /** * nes_destroy_qp */ static int nes_destroy_qp(struct ib_qp *ibqp) { struct nes_qp *nesqp = to_nesqp(ibqp); - /* struct nes_vnic *nesvnic = to_nesvnic(ibqp->device); */ struct nes_ucontext *nes_ucontext; struct ib_qp_attr attr; struct iw_cm_id *cm_id; @@ -1548,7 +1581,6 @@ static int nes_destroy_qp(struct ib_qp *ibqp) nes_debug(NES_DBG_QP, "OFA CM event_handler returned, ret=%d\n", ret); } - if (nesqp->user_mode) { if ((ibqp->uobject)&&(ibqp->uobject->context)) { nes_ucontext = to_nesucontext(ibqp->uobject->context); @@ -1560,6 +1592,13 @@ static int nes_destroy_qp(struct ib_qp *ibqp) } if (nesqp->pbl_pbase) kunmap(nesqp->page); + } else { + /* Clean any pending completions from the cq(s) */ + if (nesqp->nesscq) + nes_clean_cq(nesqp, nesqp->nesscq); + + if ((nesqp->nesrcq) && (nesqp->nesrcq != nesqp->nesscq)) + nes_clean_cq(nesqp, nesqp->nesrcq); } nes_rem_ref(&nesqp->ibqp); @@ -3547,7 +3586,6 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) { u64 u64temp; u64 wrid; - /* u64 u64temp; */ unsigned long flags = 0; struct nes_vnic *nesvnic = to_nesvnic(ibcq->device); struct nes_device *nesdev = nesvnic->nesdev; @@ -3560,7 +3598,6 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) u32 cqe_count = 0; u32 wqe_index; u32 u32temp; - /* u32 counter; */ nes_debug(NES_DBG_CQ, "\n"); @@ -3570,24 +3607,27 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) cq_size = nescq->hw_cq.cq_size; while (cqe_count < num_entries) { - if (le32_to_cpu(nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) & - NES_CQE_VALID) { - /* - * Make sure we read CQ entry contents *after* - * we've checked the valid bit. - */ - rmb(); - - cqe = nescq->hw_cq.cq_vbase[head]; - nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0; - u32temp = le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]); - wqe_index = u32temp & - (nesdev->nesadapter->max_qp_wr - 1); - u32temp &= ~(NES_SW_CONTEXT_ALIGN-1); - /* parse CQE, get completion context from WQE (either rq or sq */ - u64temp = (((u64)(le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX])))<<32) | - ((u64)u32temp); - nesqp = *((struct nes_qp **)&u64temp); + if ((le32_to_cpu(nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) & + NES_CQE_VALID) == 0) + break; + + /* + * Make sure we read CQ entry contents *after* + * we've checked the valid bit. + */ + rmb(); + + cqe = nescq->hw_cq.cq_vbase[head]; + nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0; + u32temp = le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]); + wqe_index = u32temp & (nesdev->nesadapter->max_qp_wr - 1); + u32temp &= ~(NES_SW_CONTEXT_ALIGN-1); + /* parse CQE, get completion context from WQE (either rq or sq) */ + u64temp = (((u64)(le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX])))<<32) | + ((u64)u32temp); + + if (u64temp) { + nesqp = (struct nes_qp *)(unsigned long)u64temp; memset(entry, 0, sizeof *entry); if (cqe.cqe_words[NES_CQE_ERROR_CODE_IDX] == 0) { entry->status = IB_WC_SUCCESS; @@ -3601,7 +3641,7 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) if (le32_to_cpu(cqe.cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_SQ) { if (nesqp->skip_lsmm) { nesqp->skip_lsmm = 0; - wq_tail = nesqp->hwqp.sq_tail++; + nesqp->hwqp.sq_tail++; } /* Working on a SQ Completion*/ @@ -3643,24 +3683,25 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wq_tail].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_HIGH_IDX]))<<32); entry->opcode = IB_WC_RECV; } - entry->wr_id = wrid; - if (++head >= cq_size) - head = 0; - cqe_count++; - nescq->polled_completions++; - if ((nescq->polled_completions > (cq_size / 2)) || - (nescq->polled_completions == 255)) { - nes_debug(NES_DBG_CQ, "CQ%u Issuing CQE Allocate since more than half of cqes" - " are pending %u of %u.\n", - nescq->hw_cq.cq_number, nescq->polled_completions, cq_size); - nes_write32(nesdev->regs+NES_CQE_ALLOC, - nescq->hw_cq.cq_number | (nescq->polled_completions << 16)); - nescq->polled_completions = 0; - } + entry->wr_id = wrid; entry++; - } else - break; + cqe_count++; + } + + if (++head >= cq_size) + head = 0; + nescq->polled_completions++; + + if ((nescq->polled_completions > (cq_size / 2)) || + (nescq->polled_completions == 255)) { + nes_debug(NES_DBG_CQ, "CQ%u Issuing CQE Allocate since more than half of cqes" + " are pending %u of %u.\n", + nescq->hw_cq.cq_number, nescq->polled_completions, cq_size); + nes_write32(nesdev->regs+NES_CQE_ALLOC, + nescq->hw_cq.cq_number | (nescq->polled_completions << 16)); + nescq->polled_completions = 0; + } } if (nescq->polled_completions) { -- cgit v1.2.3-18-g5258 From 3c28b4457a4cf95e982ca13578a5613a11009394 Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:38 -0700 Subject: RDMA/nes: Add CQ error handling CQ errors are not being handled correctly. Put in the the upcall for CQ errors. Signed-off-by: Don Wood Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_hw.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 4a84d02ece0..2a0c5a18e13 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -2913,6 +2913,8 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, u64 aeqe_context = 0; unsigned long flags; struct nes_qp *nesqp; + struct nes_hw_cq *hw_cq; + struct nes_cq *nescq; int resource_allocated; /* struct iw_cm_id *cm_id; */ struct nes_adapter *nesadapter = nesdev->nesadapter; @@ -3153,6 +3155,16 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, if (resource_allocated) { printk(KERN_ERR PFX "%s: Processing an NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u\n", __func__, le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])); + hw_cq = (struct nes_hw_cq *)(unsigned long)context; + if (hw_cq) { + nescq = container_of(hw_cq, struct nes_cq, hw_cq); + if (nescq->ibcq.event_handler) { + ibevent.device = nescq->ibcq.device; + ibevent.event = IB_EVENT_CQ_ERR; + ibevent.element.cq = &nescq->ibcq; + nescq->ibcq.event_handler(&ibevent, nescq->ibcq.cq_context); + } + } } break; case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER: -- cgit v1.2.3-18-g5258 From 8b1c9dc4ba713985d33aba87c761bf71d5a96491 Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:38 -0700 Subject: RDMA/nes: Implement Terminate Packet Implement the sending and receiving of Terminate packets. Signed-off-by: Don Wood Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes.h | 2 +- drivers/infiniband/hw/nes/nes_cm.h | 2 - drivers/infiniband/hw/nes/nes_hw.c | 701 +++++++++++++++++++++++----------- drivers/infiniband/hw/nes/nes_hw.h | 91 +++++ drivers/infiniband/hw/nes/nes_utils.c | 3 + drivers/infiniband/hw/nes/nes_verbs.c | 26 +- drivers/infiniband/hw/nes/nes_verbs.h | 7 + 7 files changed, 607 insertions(+), 225 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h index bf1720f7f35..bcc6abc4faf 100644 --- a/drivers/infiniband/hw/nes/nes.h +++ b/drivers/infiniband/hw/nes/nes.h @@ -523,7 +523,7 @@ int nes_cm_disconn(struct nes_qp *); void nes_cm_disconn_worker(void *); /* nes_verbs.c */ -int nes_hw_modify_qp(struct nes_device *, struct nes_qp *, u32, u32); +int nes_hw_modify_qp(struct nes_device *, struct nes_qp *, u32, u32, u32); int nes_modify_qp(struct ib_qp *, struct ib_qp_attr *, int, struct ib_udata *); struct nes_ib_device *nes_init_ofa_device(struct net_device *); void nes_destroy_ofa_device(struct nes_ib_device *); diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h index 8b7e7c0e496..90e8e4d8a5c 100644 --- a/drivers/infiniband/hw/nes/nes_cm.h +++ b/drivers/infiniband/hw/nes/nes_cm.h @@ -410,8 +410,6 @@ struct nes_cm_ops { int schedule_nes_timer(struct nes_cm_node *, struct sk_buff *, enum nes_timer_type, int, int); -int nes_cm_disconn(struct nes_qp *); - int nes_accept(struct iw_cm_id *, struct iw_cm_conn_param *); int nes_reject(struct iw_cm_id *, const void *, u8); int nes_connect(struct iw_cm_id *, struct iw_cm_conn_param *); diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 2a0c5a18e13..297026f0c13 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -74,6 +74,8 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, static void process_critical_error(struct nes_device *nesdev); static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number); static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode); +static void nes_terminate_timeout(unsigned long context); +static void nes_terminate_start_timer(struct nes_qp *nesqp); #ifdef CONFIG_INFINIBAND_NES_DEBUG static unsigned char *nes_iwarp_state_str[] = { @@ -2903,6 +2905,383 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq) } +static u8 *locate_mpa(u8 *pkt, u32 aeq_info) +{ + u16 pkt_len; + + if (aeq_info & NES_AEQE_Q2_DATA_ETHERNET) { + /* skip over ethernet header */ + pkt_len = be16_to_cpu(*(u16 *)(pkt + ETH_HLEN - 2)); + pkt += ETH_HLEN; + + /* Skip over IP and TCP headers */ + pkt += 4 * (pkt[0] & 0x0f); + pkt += 4 * ((pkt[12] >> 4) & 0x0f); + } + return pkt; +} + +/* Determine if incoming error pkt is rdma layer */ +static u32 iwarp_opcode(struct nes_qp *nesqp, u32 aeq_info) +{ + u8 *pkt; + u16 *mpa; + u32 opcode = 0xffffffff; + + if (aeq_info & NES_AEQE_Q2_DATA_WRITTEN) { + pkt = nesqp->hwqp.q2_vbase + BAD_FRAME_OFFSET; + mpa = (u16 *)locate_mpa(pkt, aeq_info); + opcode = be16_to_cpu(mpa[1]) & 0xf; + } + + return opcode; +} + +/* Build iWARP terminate header */ +static int nes_bld_terminate_hdr(struct nes_qp *nesqp, u16 async_event_id, u32 aeq_info) +{ + u8 *pkt = nesqp->hwqp.q2_vbase + BAD_FRAME_OFFSET; + u16 ddp_seg_len; + int copy_len = 0; + u8 is_tagged = 0; + struct nes_terminate_hdr *termhdr; + + termhdr = (struct nes_terminate_hdr *)nesqp->hwqp.q2_vbase; + memset(termhdr, 0, 64); + + if (aeq_info & NES_AEQE_Q2_DATA_WRITTEN) { + + /* Use data from offending packet to fill in ddp & rdma hdrs */ + pkt = locate_mpa(pkt, aeq_info); + ddp_seg_len = be16_to_cpu(*(u16 *)pkt); + if (ddp_seg_len) { + copy_len = 2; + termhdr->hdrct = DDP_LEN_FLAG; + if (pkt[2] & 0x80) { + is_tagged = 1; + if (ddp_seg_len >= TERM_DDP_LEN_TAGGED) { + copy_len += TERM_DDP_LEN_TAGGED; + termhdr->hdrct |= DDP_HDR_FLAG; + } + } else { + if (ddp_seg_len >= TERM_DDP_LEN_UNTAGGED) { + copy_len += TERM_DDP_LEN_UNTAGGED; + termhdr->hdrct |= DDP_HDR_FLAG; + } + + if (ddp_seg_len >= (TERM_DDP_LEN_UNTAGGED + TERM_RDMA_LEN)) { + if ((pkt[3] & RDMA_OPCODE_MASK) == RDMA_READ_REQ_OPCODE) { + copy_len += TERM_RDMA_LEN; + termhdr->hdrct |= RDMA_HDR_FLAG; + } + } + } + } + } + + switch (async_event_id) { + case NES_AEQE_AEID_AMP_UNALLOCATED_STAG: + switch (iwarp_opcode(nesqp, aeq_info)) { + case IWARP_OPCODE_WRITE: + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; + termhdr->error_code = DDP_TAGGED_INV_STAG; + break; + default: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; + termhdr->error_code = RDMAP_INV_STAG; + } + break; + case NES_AEQE_AEID_AMP_INVALID_STAG: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; + termhdr->error_code = RDMAP_INV_STAG; + break; + case NES_AEQE_AEID_AMP_BAD_QP: + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; + termhdr->error_code = DDP_UNTAGGED_INV_QN; + break; + case NES_AEQE_AEID_AMP_BAD_STAG_KEY: + case NES_AEQE_AEID_AMP_BAD_STAG_INDEX: + switch (iwarp_opcode(nesqp, aeq_info)) { + case IWARP_OPCODE_SEND_INV: + case IWARP_OPCODE_SEND_SE_INV: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; + termhdr->error_code = RDMAP_CANT_INV_STAG; + break; + default: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; + termhdr->error_code = RDMAP_INV_STAG; + } + break; + case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION: + if (aeq_info & (NES_AEQE_Q2_DATA_ETHERNET | NES_AEQE_Q2_DATA_MPA)) { + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; + termhdr->error_code = DDP_TAGGED_BOUNDS; + } else { + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; + termhdr->error_code = RDMAP_INV_BOUNDS; + } + break; + case NES_AEQE_AEID_AMP_RIGHTS_VIOLATION: + case NES_AEQE_AEID_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS: + case NES_AEQE_AEID_PRIV_OPERATION_DENIED: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; + termhdr->error_code = RDMAP_ACCESS; + break; + case NES_AEQE_AEID_AMP_TO_WRAP: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; + termhdr->error_code = RDMAP_TO_WRAP; + break; + case NES_AEQE_AEID_AMP_BAD_PD: + switch (iwarp_opcode(nesqp, aeq_info)) { + case IWARP_OPCODE_WRITE: + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; + termhdr->error_code = DDP_TAGGED_UNASSOC_STAG; + break; + case IWARP_OPCODE_SEND_INV: + case IWARP_OPCODE_SEND_SE_INV: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; + termhdr->error_code = RDMAP_CANT_INV_STAG; + break; + default: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; + termhdr->error_code = RDMAP_UNASSOC_STAG; + } + break; + case NES_AEQE_AEID_LLP_RECEIVED_MARKER_AND_LENGTH_FIELDS_DONT_MATCH: + termhdr->layer_etype = (LAYER_MPA << 4) | DDP_LLP; + termhdr->error_code = MPA_MARKER; + break; + case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR: + termhdr->layer_etype = (LAYER_MPA << 4) | DDP_LLP; + termhdr->error_code = MPA_CRC; + break; + case NES_AEQE_AEID_LLP_SEGMENT_TOO_LARGE: + case NES_AEQE_AEID_LLP_SEGMENT_TOO_SMALL: + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_CATASTROPHIC; + termhdr->error_code = DDP_CATASTROPHIC_LOCAL; + break; + case NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC: + case NES_AEQE_AEID_DDP_NO_L_BIT: + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_CATASTROPHIC; + termhdr->error_code = DDP_CATASTROPHIC_LOCAL; + break; + case NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN: + case NES_AEQE_AEID_DDP_INVALID_MSN_RANGE_IS_NOT_VALID: + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; + termhdr->error_code = DDP_UNTAGGED_INV_MSN_RANGE; + break; + case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER: + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; + termhdr->error_code = DDP_UNTAGGED_INV_TOO_LONG; + break; + case NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION: + if (is_tagged) { + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; + termhdr->error_code = DDP_TAGGED_INV_DDP_VER; + } else { + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; + termhdr->error_code = DDP_UNTAGGED_INV_DDP_VER; + } + break; + case NES_AEQE_AEID_DDP_UBE_INVALID_MO: + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; + termhdr->error_code = DDP_UNTAGGED_INV_MO; + break; + case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE: + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; + termhdr->error_code = DDP_UNTAGGED_INV_MSN_NO_BUF; + break; + case NES_AEQE_AEID_DDP_UBE_INVALID_QN: + termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; + termhdr->error_code = DDP_UNTAGGED_INV_QN; + break; + case NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; + termhdr->error_code = RDMAP_INV_RDMAP_VER; + break; + case NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; + termhdr->error_code = RDMAP_UNEXPECTED_OP; + break; + default: + termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; + termhdr->error_code = RDMAP_UNSPECIFIED; + break; + } + + if (copy_len) + memcpy(termhdr + 1, pkt, copy_len); + + return sizeof(struct nes_terminate_hdr) + copy_len; +} + +static void nes_terminate_connection(struct nes_device *nesdev, struct nes_qp *nesqp, + struct nes_hw_aeqe *aeqe, enum ib_event_type eventtype) +{ + u64 context; + unsigned long flags; + u32 aeq_info; + u16 async_event_id; + u8 tcp_state; + u8 iwarp_state; + u32 termlen = 0; + u32 mod_qp_flags = NES_CQP_QP_IWARP_STATE_TERMINATE | + NES_CQP_QP_TERM_DONT_SEND_FIN; + struct nes_adapter *nesadapter = nesdev->nesadapter; + + if (nesqp->term_flags & NES_TERM_SENT) + return; /* Sanity check */ + + aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); + tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT; + iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT; + async_event_id = (u16)aeq_info; + + context = (unsigned long)nesadapter->qp_table[le32_to_cpu( + aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]) - NES_FIRST_QPN]; + if (!context) { + WARN_ON(!context); + return; + } + + nesqp = (struct nes_qp *)(unsigned long)context; + spin_lock_irqsave(&nesqp->lock, flags); + nesqp->hw_iwarp_state = iwarp_state; + nesqp->hw_tcp_state = tcp_state; + nesqp->last_aeq = async_event_id; + nesqp->terminate_eventtype = eventtype; + spin_unlock_irqrestore(&nesqp->lock, flags); + + if (nesadapter->send_term_ok) + termlen = nes_bld_terminate_hdr(nesqp, async_event_id, aeq_info); + else + mod_qp_flags |= NES_CQP_QP_TERM_DONT_SEND_TERM_MSG; + + nes_terminate_start_timer(nesqp); + nesqp->term_flags |= NES_TERM_SENT; + nes_hw_modify_qp(nesdev, nesqp, mod_qp_flags, termlen, 0); +} + +static void nes_terminate_send_fin(struct nes_device *nesdev, + struct nes_qp *nesqp, struct nes_hw_aeqe *aeqe) +{ + u32 aeq_info; + u16 async_event_id; + u8 tcp_state; + u8 iwarp_state; + unsigned long flags; + + aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); + tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT; + iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT; + async_event_id = (u16)aeq_info; + + spin_lock_irqsave(&nesqp->lock, flags); + nesqp->hw_iwarp_state = iwarp_state; + nesqp->hw_tcp_state = tcp_state; + nesqp->last_aeq = async_event_id; + spin_unlock_irqrestore(&nesqp->lock, flags); + + /* Send the fin only */ + nes_hw_modify_qp(nesdev, nesqp, NES_CQP_QP_IWARP_STATE_TERMINATE | + NES_CQP_QP_TERM_DONT_SEND_TERM_MSG, 0, 0); +} + +/* Cleanup after a terminate sent or received */ +static void nes_terminate_done(struct nes_qp *nesqp, int timeout_occurred) +{ + u32 next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR; + unsigned long flags; + struct nes_vnic *nesvnic = to_nesvnic(nesqp->ibqp.device); + struct nes_device *nesdev = nesvnic->nesdev; + u8 first_time = 0; + + spin_lock_irqsave(&nesqp->lock, flags); + if (nesqp->hte_added) { + nesqp->hte_added = 0; + next_iwarp_state |= NES_CQP_QP_DEL_HTE; + } + + first_time = (nesqp->term_flags & NES_TERM_DONE) == 0; + nesqp->term_flags |= NES_TERM_DONE; + spin_unlock_irqrestore(&nesqp->lock, flags); + + /* Make sure we go through this only once */ + if (first_time) { + if (timeout_occurred == 0) + del_timer(&nesqp->terminate_timer); + else + next_iwarp_state |= NES_CQP_QP_RESET; + + nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 0); + nes_cm_disconn(nesqp); + } +} + +static void nes_terminate_received(struct nes_device *nesdev, + struct nes_qp *nesqp, struct nes_hw_aeqe *aeqe) +{ + u32 aeq_info; + u8 *pkt; + u32 *mpa; + u8 ddp_ctl; + u8 rdma_ctl; + u16 aeq_id = 0; + + aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); + if (aeq_info & NES_AEQE_Q2_DATA_WRITTEN) { + /* Terminate is not a performance path so the silicon */ + /* did not validate the frame - do it now */ + pkt = nesqp->hwqp.q2_vbase + BAD_FRAME_OFFSET; + mpa = (u32 *)locate_mpa(pkt, aeq_info); + ddp_ctl = (be32_to_cpu(mpa[0]) >> 8) & 0xff; + rdma_ctl = be32_to_cpu(mpa[0]) & 0xff; + if ((ddp_ctl & 0xc0) != 0x40) + aeq_id = NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC; + else if ((ddp_ctl & 0x03) != 1) + aeq_id = NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION; + else if (be32_to_cpu(mpa[2]) != 2) + aeq_id = NES_AEQE_AEID_DDP_UBE_INVALID_QN; + else if (be32_to_cpu(mpa[3]) != 1) + aeq_id = NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN; + else if (be32_to_cpu(mpa[4]) != 0) + aeq_id = NES_AEQE_AEID_DDP_UBE_INVALID_MO; + else if ((rdma_ctl & 0xc0) != 0x40) + aeq_id = NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION; + + if (aeq_id) { + /* Bad terminate recvd - send back a terminate */ + aeq_info = (aeq_info & 0xffff0000) | aeq_id; + aeqe->aeqe_words[NES_AEQE_MISC_IDX] = cpu_to_le32(aeq_info); + nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL); + return; + } + } + + nesqp->term_flags |= NES_TERM_RCVD; + nesqp->terminate_eventtype = IB_EVENT_QP_FATAL; + nes_terminate_start_timer(nesqp); + nes_terminate_send_fin(nesdev, nesqp, aeqe); +} + +/* Timeout routine in case terminate fails to complete */ +static void nes_terminate_timeout(unsigned long context) +{ + struct nes_qp *nesqp = (struct nes_qp *)(unsigned long)context; + + nes_terminate_done(nesqp, 1); +} + +/* Set a timer in case hw cannot complete the terminate sequence */ +static void nes_terminate_start_timer(struct nes_qp *nesqp) +{ + init_timer(&nesqp->terminate_timer); + nesqp->terminate_timer.function = nes_terminate_timeout; + nesqp->terminate_timer.expires = jiffies + HZ; + nesqp->terminate_timer.data = (unsigned long)nesqp; + add_timer(&nesqp->terminate_timer); +} + /** * nes_process_iwarp_aeqe */ @@ -2910,30 +3289,27 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, struct nes_hw_aeqe *aeqe) { u64 context; - u64 aeqe_context = 0; unsigned long flags; struct nes_qp *nesqp; struct nes_hw_cq *hw_cq; struct nes_cq *nescq; int resource_allocated; - /* struct iw_cm_id *cm_id; */ struct nes_adapter *nesadapter = nesdev->nesadapter; - struct ib_event ibevent; - /* struct iw_cm_event cm_event; */ u32 aeq_info; u32 next_iwarp_state = 0; u16 async_event_id; u8 tcp_state; u8 iwarp_state; + int must_disconn = 1; + int must_terminate = 0; + struct ib_event ibevent; nes_debug(NES_DBG_AEQ, "\n"); aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); - if ((NES_AEQE_INBOUND_RDMA&aeq_info) || (!(NES_AEQE_QP&aeq_info))) { + if ((NES_AEQE_INBOUND_RDMA & aeq_info) || (!(NES_AEQE_QP & aeq_info))) { context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]); context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32; } else { - aeqe_context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]); - aeqe_context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32; context = (unsigned long)nesadapter->qp_table[le32_to_cpu( aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]) - NES_FIRST_QPN]; BUG_ON(!context); @@ -2950,7 +3326,11 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, switch (async_event_id) { case NES_AEQE_AEID_LLP_FIN_RECEIVED: - nesqp = *((struct nes_qp **)&context); + nesqp = (struct nes_qp *)(unsigned long)context; + + if (nesqp->term_flags) + return; /* Ignore it, wait for close complete */ + if (atomic_inc_return(&nesqp->close_timer_started) == 1) { nesqp->cm_id->add_ref(nesqp->cm_id); schedule_nes_timer(nesqp->cm_node, (struct sk_buff *)nesqp, @@ -2961,18 +3341,24 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount), async_event_id, nesqp->last_aeq, tcp_state); } + if ((tcp_state != NES_AEQE_TCP_STATE_CLOSE_WAIT) || (nesqp->ibqp_state != IB_QPS_RTS)) { /* FIN Received but tcp state or IB state moved on, should expect a close complete */ return; } + case NES_AEQE_AEID_LLP_CLOSE_COMPLETE: + nesqp = (struct nes_qp *)(unsigned long)context; + if (nesqp->term_flags) { + nes_terminate_done(nesqp, 0); + return; + } + case NES_AEQE_AEID_LLP_CONNECTION_RESET: - case NES_AEQE_AEID_TERMINATE_SENT: - case NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE: case NES_AEQE_AEID_RESET_SENT: - nesqp = *((struct nes_qp **)&context); + nesqp = (struct nes_qp *)(unsigned long)context; if (async_event_id == NES_AEQE_AEID_RESET_SENT) { tcp_state = NES_AEQE_TCP_STATE_CLOSED; } @@ -2984,12 +3370,7 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, if ((tcp_state == NES_AEQE_TCP_STATE_CLOSED) || (tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT)) { nesqp->hte_added = 0; - spin_unlock_irqrestore(&nesqp->lock, flags); - nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u to remove hte\n", - nesqp->hwqp.qp_id); - nes_hw_modify_qp(nesdev, nesqp, - NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_DEL_HTE, 0); - spin_lock_irqsave(&nesqp->lock, flags); + next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_DEL_HTE; } if ((nesqp->ibqp_state == IB_QPS_RTS) && @@ -3001,151 +3382,106 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING; break; case NES_AEQE_IWARP_STATE_TERMINATE: - next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE; - nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_TERMINATE; - if (async_event_id == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) { - next_iwarp_state |= 0x02000000; - nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; - } + must_disconn = 0; /* terminate path takes care of disconn */ + if (nesqp->term_flags == 0) + must_terminate = 1; break; - default: - next_iwarp_state = 0; - } - spin_unlock_irqrestore(&nesqp->lock, flags); - if (next_iwarp_state) { - nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X," - " also added another reference\n", - nesqp->hwqp.qp_id, next_iwarp_state); - nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0); } - nes_cm_disconn(nesqp); } else { if (async_event_id == NES_AEQE_AEID_LLP_FIN_RECEIVED) { /* FIN Received but ib state not RTS, close complete will be on its way */ - spin_unlock_irqrestore(&nesqp->lock, flags); - return; - } - spin_unlock_irqrestore(&nesqp->lock, flags); - if (async_event_id == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) { - next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000; - nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; - nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X," - " also added another reference\n", - nesqp->hwqp.qp_id, next_iwarp_state); - nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0); + must_disconn = 0; } - nes_cm_disconn(nesqp); } - break; - case NES_AEQE_AEID_LLP_TERMINATE_RECEIVED: - nesqp = *((struct nes_qp **)&context); - spin_lock_irqsave(&nesqp->lock, flags); - nesqp->hw_iwarp_state = iwarp_state; - nesqp->hw_tcp_state = tcp_state; - nesqp->last_aeq = async_event_id; spin_unlock_irqrestore(&nesqp->lock, flags); - nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TERMINATE_RECEIVED" - " event on QP%u \n Q2 Data:\n", - nesqp->hwqp.qp_id); - if (nesqp->ibqp.event_handler) { - ibevent.device = nesqp->ibqp.device; - ibevent.element.qp = &nesqp->ibqp; - ibevent.event = IB_EVENT_QP_FATAL; - nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); - } - if ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) || - ((nesqp->ibqp_state == IB_QPS_RTS)&& - (async_event_id == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { + + if (must_terminate) + nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL); + else if (must_disconn) { + if (next_iwarp_state) { + nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X\n", + nesqp->hwqp.qp_id, next_iwarp_state); + nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 0); + } nes_cm_disconn(nesqp); - } else { - nesqp->in_disconnect = 0; - wake_up(&nesqp->kick_waitq); } break; - case NES_AEQE_AEID_LLP_TOO_MANY_RETRIES: - nesqp = *((struct nes_qp **)&context); - spin_lock_irqsave(&nesqp->lock, flags); - nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_ERROR; - nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; - nesqp->last_aeq = async_event_id; - if (nesqp->cm_id) { - nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TOO_MANY_RETRIES" - " event on QP%u, remote IP = 0x%08X \n", - nesqp->hwqp.qp_id, - ntohl(nesqp->cm_id->remote_addr.sin_addr.s_addr)); - } else { - nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TOO_MANY_RETRIES" - " event on QP%u \n", - nesqp->hwqp.qp_id); - } - spin_unlock_irqrestore(&nesqp->lock, flags); - next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_RESET; - nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0); - if (nesqp->ibqp.event_handler) { - ibevent.device = nesqp->ibqp.device; - ibevent.element.qp = &nesqp->ibqp; - ibevent.event = IB_EVENT_QP_FATAL; - nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); - } + + case NES_AEQE_AEID_TERMINATE_SENT: + nesqp = (struct nes_qp *)(unsigned long)context; + nes_terminate_send_fin(nesdev, nesqp, aeqe); break; - case NES_AEQE_AEID_AMP_BAD_STAG_INDEX: - if (NES_AEQE_INBOUND_RDMA&aeq_info) { - nesqp = nesadapter->qp_table[le32_to_cpu( - aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN]; - } else { - /* TODO: get the actual WQE and mask off wqe index */ - context &= ~((u64)511); - nesqp = *((struct nes_qp **)&context); - } - spin_lock_irqsave(&nesqp->lock, flags); - nesqp->hw_iwarp_state = iwarp_state; - nesqp->hw_tcp_state = tcp_state; - nesqp->last_aeq = async_event_id; - spin_unlock_irqrestore(&nesqp->lock, flags); - nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_AMP_BAD_STAG_INDEX event on QP%u\n", - nesqp->hwqp.qp_id); - if (nesqp->ibqp.event_handler) { - ibevent.device = nesqp->ibqp.device; - ibevent.element.qp = &nesqp->ibqp; - ibevent.event = IB_EVENT_QP_ACCESS_ERR; - nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); - } + + case NES_AEQE_AEID_LLP_TERMINATE_RECEIVED: + nesqp = (struct nes_qp *)(unsigned long)context; + nes_terminate_received(nesdev, nesqp, aeqe); break; + + case NES_AEQE_AEID_AMP_BAD_STAG_KEY: + case NES_AEQE_AEID_AMP_BAD_STAG_INDEX: case NES_AEQE_AEID_AMP_UNALLOCATED_STAG: - nesqp = *((struct nes_qp **)&context); - spin_lock_irqsave(&nesqp->lock, flags); - nesqp->hw_iwarp_state = iwarp_state; - nesqp->hw_tcp_state = tcp_state; - nesqp->last_aeq = async_event_id; - spin_unlock_irqrestore(&nesqp->lock, flags); - nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_AMP_UNALLOCATED_STAG event on QP%u\n", - nesqp->hwqp.qp_id); - if (nesqp->ibqp.event_handler) { - ibevent.device = nesqp->ibqp.device; - ibevent.element.qp = &nesqp->ibqp; - ibevent.event = IB_EVENT_QP_ACCESS_ERR; - nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); - } - break; + case NES_AEQE_AEID_AMP_INVALID_STAG: + case NES_AEQE_AEID_AMP_RIGHTS_VIOLATION: + case NES_AEQE_AEID_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS: case NES_AEQE_AEID_PRIV_OPERATION_DENIED: - nesqp = nesadapter->qp_table[le32_to_cpu(aeqe->aeqe_words - [NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN]; - spin_lock_irqsave(&nesqp->lock, flags); - nesqp->hw_iwarp_state = iwarp_state; - nesqp->hw_tcp_state = tcp_state; - nesqp->last_aeq = async_event_id; - spin_unlock_irqrestore(&nesqp->lock, flags); - nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_PRIV_OPERATION_DENIED event on QP%u," - " nesqp = %p, AE reported %p\n", - nesqp->hwqp.qp_id, nesqp, *((struct nes_qp **)&context)); - if (nesqp->ibqp.event_handler) { - ibevent.device = nesqp->ibqp.device; - ibevent.element.qp = &nesqp->ibqp; - ibevent.event = IB_EVENT_QP_ACCESS_ERR; - nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); + case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER: + case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION: + case NES_AEQE_AEID_AMP_TO_WRAP: + nesqp = (struct nes_qp *)(unsigned long)context; + nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_ACCESS_ERR); + break; + + case NES_AEQE_AEID_LLP_SEGMENT_TOO_LARGE: + case NES_AEQE_AEID_LLP_SEGMENT_TOO_SMALL: + case NES_AEQE_AEID_DDP_UBE_INVALID_MO: + case NES_AEQE_AEID_DDP_UBE_INVALID_QN: + nesqp = (struct nes_qp *)(unsigned long)context; + if (iwarp_opcode(nesqp, aeq_info) > IWARP_OPCODE_TERM) { + aeq_info &= 0xffff0000; + aeq_info |= NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE; + aeqe->aeqe_words[NES_AEQE_MISC_IDX] = cpu_to_le32(aeq_info); } + + case NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE: + case NES_AEQE_AEID_LLP_TOO_MANY_RETRIES: + case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE: + case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR: + case NES_AEQE_AEID_AMP_BAD_QP: + case NES_AEQE_AEID_LLP_RECEIVED_MARKER_AND_LENGTH_FIELDS_DONT_MATCH: + case NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC: + case NES_AEQE_AEID_DDP_NO_L_BIT: + case NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN: + case NES_AEQE_AEID_DDP_INVALID_MSN_RANGE_IS_NOT_VALID: + case NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION: + case NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION: + case NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE: + case NES_AEQE_AEID_AMP_BAD_PD: + case NES_AEQE_AEID_AMP_FASTREG_SHARED: + case NES_AEQE_AEID_AMP_FASTREG_VALID_STAG: + case NES_AEQE_AEID_AMP_FASTREG_MW_STAG: + case NES_AEQE_AEID_AMP_FASTREG_INVALID_RIGHTS: + case NES_AEQE_AEID_AMP_FASTREG_PBL_TABLE_OVERFLOW: + case NES_AEQE_AEID_AMP_FASTREG_INVALID_LENGTH: + case NES_AEQE_AEID_AMP_INVALIDATE_SHARED: + case NES_AEQE_AEID_AMP_INVALIDATE_MR_WITH_BOUND_WINDOWS: + case NES_AEQE_AEID_AMP_MWBIND_VALID_STAG: + case NES_AEQE_AEID_AMP_MWBIND_OF_MR_STAG: + case NES_AEQE_AEID_AMP_MWBIND_TO_ZERO_BASED_STAG: + case NES_AEQE_AEID_AMP_MWBIND_TO_MW_STAG: + case NES_AEQE_AEID_AMP_MWBIND_INVALID_RIGHTS: + case NES_AEQE_AEID_AMP_MWBIND_INVALID_BOUNDS: + case NES_AEQE_AEID_AMP_MWBIND_TO_INVALID_PARENT: + case NES_AEQE_AEID_AMP_MWBIND_BIND_DISABLED: + case NES_AEQE_AEID_BAD_CLOSE: + case NES_AEQE_AEID_RDMA_READ_WHILE_ORD_ZERO: + case NES_AEQE_AEID_STAG_ZERO_INVALID: + case NES_AEQE_AEID_ROE_INVALID_RDMA_READ_REQUEST: + case NES_AEQE_AEID_ROE_INVALID_RDMA_WRITE_OR_READ_RESP: + nesqp = (struct nes_qp *)(unsigned long)context; + nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL); break; + case NES_AEQE_AEID_CQ_OPERATION_ERROR: context <<= 1; nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u, %p\n", @@ -3167,81 +3503,7 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, } } break; - case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER: - nesqp = nesadapter->qp_table[le32_to_cpu( - aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN]; - spin_lock_irqsave(&nesqp->lock, flags); - nesqp->hw_iwarp_state = iwarp_state; - nesqp->hw_tcp_state = tcp_state; - nesqp->last_aeq = async_event_id; - spin_unlock_irqrestore(&nesqp->lock, flags); - nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG" - "_FOR_AVAILABLE_BUFFER event on QP%u\n", - nesqp->hwqp.qp_id); - if (nesqp->ibqp.event_handler) { - ibevent.device = nesqp->ibqp.device; - ibevent.element.qp = &nesqp->ibqp; - ibevent.event = IB_EVENT_QP_ACCESS_ERR; - nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); - } - /* tell cm to disconnect, cm will queue work to thread */ - nes_cm_disconn(nesqp); - break; - case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE: - nesqp = *((struct nes_qp **)&context); - spin_lock_irqsave(&nesqp->lock, flags); - nesqp->hw_iwarp_state = iwarp_state; - nesqp->hw_tcp_state = tcp_state; - nesqp->last_aeq = async_event_id; - spin_unlock_irqrestore(&nesqp->lock, flags); - nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_DDP_UBE_INVALID_MSN" - "_NO_BUFFER_AVAILABLE event on QP%u\n", - nesqp->hwqp.qp_id); - if (nesqp->ibqp.event_handler) { - ibevent.device = nesqp->ibqp.device; - ibevent.element.qp = &nesqp->ibqp; - ibevent.event = IB_EVENT_QP_FATAL; - nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); - } - /* tell cm to disconnect, cm will queue work to thread */ - nes_cm_disconn(nesqp); - break; - case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR: - nesqp = *((struct nes_qp **)&context); - spin_lock_irqsave(&nesqp->lock, flags); - nesqp->hw_iwarp_state = iwarp_state; - nesqp->hw_tcp_state = tcp_state; - nesqp->last_aeq = async_event_id; - spin_unlock_irqrestore(&nesqp->lock, flags); - nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR" - " event on QP%u \n Q2 Data:\n", - nesqp->hwqp.qp_id); - if (nesqp->ibqp.event_handler) { - ibevent.device = nesqp->ibqp.device; - ibevent.element.qp = &nesqp->ibqp; - ibevent.event = IB_EVENT_QP_FATAL; - nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); - } - /* tell cm to disconnect, cm will queue work to thread */ - nes_cm_disconn(nesqp); - break; - /* TODO: additional AEs need to be here */ - case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION: - nesqp = *((struct nes_qp **)&context); - spin_lock_irqsave(&nesqp->lock, flags); - nesqp->hw_iwarp_state = iwarp_state; - nesqp->hw_tcp_state = tcp_state; - nesqp->last_aeq = async_event_id; - spin_unlock_irqrestore(&nesqp->lock, flags); - if (nesqp->ibqp.event_handler) { - ibevent.device = nesqp->ibqp.device; - ibevent.element.qp = &nesqp->ibqp; - ibevent.event = IB_EVENT_QP_ACCESS_ERR; - nesqp->ibqp.event_handler(&ibevent, - nesqp->ibqp.qp_context); - } - nes_cm_disconn(nesqp); - break; + default: nes_debug(NES_DBG_AEQ, "Processing an iWARP related AE for QP, misc = 0x%04X\n", async_event_id); @@ -3250,7 +3512,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, } - /** * nes_iwarp_ce_handler */ diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h index c3654c6383f..4a0bfcd5a62 100644 --- a/drivers/infiniband/hw/nes/nes_hw.h +++ b/drivers/infiniband/hw/nes/nes_hw.h @@ -241,6 +241,7 @@ enum nes_cqp_stag_wqeword_idx { }; #define NES_CQP_OP_IWARP_STATE_SHIFT 28 +#define NES_CQP_OP_TERMLEN_SHIFT 28 enum nes_cqp_qp_bits { NES_CQP_QP_ARP_VALID = (1<<8), @@ -265,6 +266,8 @@ enum nes_cqp_qp_bits { NES_CQP_QP_IWARP_STATE_TERMINATE = (5< 21)) || ((major_ver > 2) && (major_ver != 255))) { nesadapter->virtwq = 1; } + if (((major_ver == 3) && (minor_ver >= 16)) || (major_ver > 3)) + nesadapter->send_term_ok = 1; + nesadapter->firmware_version = (((u32)(u8)(eeprom_data>>8)) << 16) + (u32)((u8)eeprom_data); diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index c6b5873416e..36666ac2f54 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -2923,7 +2923,7 @@ static int nes_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, * nes_hw_modify_qp */ int nes_hw_modify_qp(struct nes_device *nesdev, struct nes_qp *nesqp, - u32 next_iwarp_state, u32 wait_completion) + u32 next_iwarp_state, u32 termlen, u32 wait_completion) { struct nes_hw_cqp_wqe *cqp_wqe; /* struct iw_cm_id *cm_id = nesqp->cm_id; */ @@ -2955,6 +2955,13 @@ int nes_hw_modify_qp(struct nes_device *nesdev, struct nes_qp *nesqp, set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, nesqp->hwqp.qp_id); set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, (u64)nesqp->nesqp_context_pbase); + /* If sending a terminate message, fill in the length (in words) */ + if (((next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK) == NES_CQP_QP_IWARP_STATE_TERMINATE) && + !(next_iwarp_state & NES_CQP_QP_TERM_DONT_SEND_TERM_MSG)) { + termlen = ((termlen + 3) >> 2) << NES_CQP_OP_TERMLEN_SHIFT; + set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_NEW_MSS_IDX, termlen); + } + atomic_set(&cqp_request->refcount, 2); nes_post_cqp_request(nesdev, cqp_request); @@ -3125,6 +3132,9 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, } nes_debug(NES_DBG_MOD_QP, "QP%u: new state = error\n", nesqp->hwqp.qp_id); + if (nesqp->term_flags) + del_timer(&nesqp->terminate_timer); + next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR; /* next_iwarp_state = (NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000); */ if (nesqp->hte_added) { @@ -3202,7 +3212,7 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, if (issue_modify_qp) { nes_debug(NES_DBG_MOD_QP, "call nes_hw_modify_qp\n"); - ret = nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 1); + ret = nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 1); if (ret) nes_debug(NES_DBG_MOD_QP, "nes_hw_modify_qp (next_iwarp_state = 0x%08X)" " failed for QP%u.\n", @@ -3367,6 +3377,12 @@ static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr, head = nesqp->hwqp.sq_head; while (ib_wr) { + /* Check for QP error */ + if (nesqp->term_flags) { + err = -EINVAL; + break; + } + /* Check for SQ overflow */ if (((head + (2 * qsize) - nesqp->hwqp.sq_tail) % qsize) == (qsize - 1)) { err = -EINVAL; @@ -3523,6 +3539,12 @@ static int nes_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr, head = nesqp->hwqp.rq_head; while (ib_wr) { + /* Check for QP error */ + if (nesqp->term_flags) { + err = -EINVAL; + break; + } + if (ib_wr->num_sge > nesdev->nesadapter->max_sge) { err = -EINVAL; break; diff --git a/drivers/infiniband/hw/nes/nes_verbs.h b/drivers/infiniband/hw/nes/nes_verbs.h index 7df34fea288..d92b1ef4653 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.h +++ b/drivers/infiniband/hw/nes/nes_verbs.h @@ -40,6 +40,10 @@ struct nes_device; #define NES_MAX_USER_DB_REGIONS 4096 #define NES_MAX_USER_WQ_REGIONS 4096 +#define NES_TERM_SENT 0x01 +#define NES_TERM_RCVD 0x02 +#define NES_TERM_DONE 0x04 + struct nes_ucontext { struct ib_ucontext ibucontext; struct nes_device *nesdev; @@ -159,6 +163,8 @@ struct nes_qp { void *pbl_vbase; dma_addr_t pbl_pbase; struct page *page; + struct timer_list terminate_timer; + enum ib_event_type terminate_eventtype; wait_queue_head_t kick_waitq; u16 in_disconnect; u16 private_data_len; @@ -169,6 +175,7 @@ struct nes_qp { u8 hw_iwarp_state; u8 flush_issued; u8 hw_tcp_state; + u8 term_flags; u8 destroyed; }; #endif /* NES_VERBS_H */ -- cgit v1.2.3-18-g5258 From 4b281faec3ad00f7fb00080078321e4d819795eb Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:38 -0700 Subject: RDMA/nes: Use flush mechanism to set status for wqe in error When an asynchronous event occurs that requires a terminate, it is sometimes possible to identify the wqe in error. This change uses flush to get this information to the poll routine. The flush operation puts the status into the cqe. If this information is not available, it continues to use the more generic flush code as before. Signed-off-by: Don Wood Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_hw.c | 54 +++++++++++++++++++++++++++++++++++ drivers/infiniband/hw/nes/nes_hw.h | 12 ++++++++ drivers/infiniband/hw/nes/nes_verbs.h | 2 ++ 3 files changed, 68 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 297026f0c13..63a1a8e1e8a 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -2944,6 +2944,7 @@ static int nes_bld_terminate_hdr(struct nes_qp *nesqp, u16 async_event_id, u32 a u16 ddp_seg_len; int copy_len = 0; u8 is_tagged = 0; + u8 flush_code = 0; struct nes_terminate_hdr *termhdr; termhdr = (struct nes_terminate_hdr *)nesqp->hwqp.q2_vbase; @@ -2983,19 +2984,23 @@ static int nes_bld_terminate_hdr(struct nes_qp *nesqp, u16 async_event_id, u32 a case NES_AEQE_AEID_AMP_UNALLOCATED_STAG: switch (iwarp_opcode(nesqp, aeq_info)) { case IWARP_OPCODE_WRITE: + flush_code = IB_WC_LOC_PROT_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; termhdr->error_code = DDP_TAGGED_INV_STAG; break; default: + flush_code = IB_WC_REM_ACCESS_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; termhdr->error_code = RDMAP_INV_STAG; } break; case NES_AEQE_AEID_AMP_INVALID_STAG: + flush_code = IB_WC_REM_ACCESS_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; termhdr->error_code = RDMAP_INV_STAG; break; case NES_AEQE_AEID_AMP_BAD_QP: + flush_code = IB_WC_LOC_QP_OP_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; termhdr->error_code = DDP_UNTAGGED_INV_QN; break; @@ -3004,19 +3009,23 @@ static int nes_bld_terminate_hdr(struct nes_qp *nesqp, u16 async_event_id, u32 a switch (iwarp_opcode(nesqp, aeq_info)) { case IWARP_OPCODE_SEND_INV: case IWARP_OPCODE_SEND_SE_INV: + flush_code = IB_WC_REM_OP_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; termhdr->error_code = RDMAP_CANT_INV_STAG; break; default: + flush_code = IB_WC_REM_ACCESS_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; termhdr->error_code = RDMAP_INV_STAG; } break; case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION: if (aeq_info & (NES_AEQE_Q2_DATA_ETHERNET | NES_AEQE_Q2_DATA_MPA)) { + flush_code = IB_WC_LOC_PROT_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; termhdr->error_code = DDP_TAGGED_BOUNDS; } else { + flush_code = IB_WC_REM_ACCESS_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; termhdr->error_code = RDMAP_INV_BOUNDS; } @@ -3024,57 +3033,69 @@ static int nes_bld_terminate_hdr(struct nes_qp *nesqp, u16 async_event_id, u32 a case NES_AEQE_AEID_AMP_RIGHTS_VIOLATION: case NES_AEQE_AEID_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS: case NES_AEQE_AEID_PRIV_OPERATION_DENIED: + flush_code = IB_WC_REM_ACCESS_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; termhdr->error_code = RDMAP_ACCESS; break; case NES_AEQE_AEID_AMP_TO_WRAP: + flush_code = IB_WC_REM_ACCESS_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; termhdr->error_code = RDMAP_TO_WRAP; break; case NES_AEQE_AEID_AMP_BAD_PD: switch (iwarp_opcode(nesqp, aeq_info)) { case IWARP_OPCODE_WRITE: + flush_code = IB_WC_LOC_PROT_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; termhdr->error_code = DDP_TAGGED_UNASSOC_STAG; break; case IWARP_OPCODE_SEND_INV: case IWARP_OPCODE_SEND_SE_INV: + flush_code = IB_WC_REM_ACCESS_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; termhdr->error_code = RDMAP_CANT_INV_STAG; break; default: + flush_code = IB_WC_REM_ACCESS_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT; termhdr->error_code = RDMAP_UNASSOC_STAG; } break; case NES_AEQE_AEID_LLP_RECEIVED_MARKER_AND_LENGTH_FIELDS_DONT_MATCH: + flush_code = IB_WC_LOC_LEN_ERR; termhdr->layer_etype = (LAYER_MPA << 4) | DDP_LLP; termhdr->error_code = MPA_MARKER; break; case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR: + flush_code = IB_WC_GENERAL_ERR; termhdr->layer_etype = (LAYER_MPA << 4) | DDP_LLP; termhdr->error_code = MPA_CRC; break; case NES_AEQE_AEID_LLP_SEGMENT_TOO_LARGE: case NES_AEQE_AEID_LLP_SEGMENT_TOO_SMALL: + flush_code = IB_WC_LOC_LEN_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_CATASTROPHIC; termhdr->error_code = DDP_CATASTROPHIC_LOCAL; break; case NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC: case NES_AEQE_AEID_DDP_NO_L_BIT: + flush_code = IB_WC_FATAL_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_CATASTROPHIC; termhdr->error_code = DDP_CATASTROPHIC_LOCAL; break; case NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN: case NES_AEQE_AEID_DDP_INVALID_MSN_RANGE_IS_NOT_VALID: + flush_code = IB_WC_GENERAL_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; termhdr->error_code = DDP_UNTAGGED_INV_MSN_RANGE; break; case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER: + flush_code = IB_WC_LOC_LEN_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; termhdr->error_code = DDP_UNTAGGED_INV_TOO_LONG; break; case NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION: + flush_code = IB_WC_GENERAL_ERR; if (is_tagged) { termhdr->layer_etype = (LAYER_DDP << 4) | DDP_TAGGED_BUFFER; termhdr->error_code = DDP_TAGGED_INV_DDP_VER; @@ -3084,26 +3105,32 @@ static int nes_bld_terminate_hdr(struct nes_qp *nesqp, u16 async_event_id, u32 a } break; case NES_AEQE_AEID_DDP_UBE_INVALID_MO: + flush_code = IB_WC_GENERAL_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; termhdr->error_code = DDP_UNTAGGED_INV_MO; break; case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE: + flush_code = IB_WC_REM_OP_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; termhdr->error_code = DDP_UNTAGGED_INV_MSN_NO_BUF; break; case NES_AEQE_AEID_DDP_UBE_INVALID_QN: + flush_code = IB_WC_GENERAL_ERR; termhdr->layer_etype = (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER; termhdr->error_code = DDP_UNTAGGED_INV_QN; break; case NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION: + flush_code = IB_WC_GENERAL_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; termhdr->error_code = RDMAP_INV_RDMAP_VER; break; case NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE: + flush_code = IB_WC_LOC_QP_OP_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; termhdr->error_code = RDMAP_UNEXPECTED_OP; break; default: + flush_code = IB_WC_FATAL_ERR; termhdr->layer_etype = (LAYER_RDMA << 4) | RDMAP_REMOTE_OP; termhdr->error_code = RDMAP_UNSPECIFIED; break; @@ -3112,6 +3139,13 @@ static int nes_bld_terminate_hdr(struct nes_qp *nesqp, u16 async_event_id, u32 a if (copy_len) memcpy(termhdr + 1, pkt, copy_len); + if ((flush_code) && ((NES_AEQE_INBOUND_RDMA & aeq_info) == 0)) { + if (aeq_info & NES_AEQE_SQ) + nesqp->term_sq_flush_code = flush_code; + else + nesqp->term_rq_flush_code = flush_code; + } + return sizeof(struct nes_terminate_hdr) + copy_len; } @@ -3646,6 +3680,8 @@ void flush_wqes(struct nes_device *nesdev, struct nes_qp *nesqp, { struct nes_cqp_request *cqp_request; struct nes_hw_cqp_wqe *cqp_wqe; + u32 sq_code = (NES_IWARP_CQE_MAJOR_FLUSH << 16) | NES_IWARP_CQE_MINOR_FLUSH; + u32 rq_code = (NES_IWARP_CQE_MAJOR_FLUSH << 16) | NES_IWARP_CQE_MINOR_FLUSH; int ret; cqp_request = nes_get_cqp_request(nesdev); @@ -3662,6 +3698,24 @@ void flush_wqes(struct nes_device *nesdev, struct nes_qp *nesqp, cqp_wqe = &cqp_request->cqp_wqe; nes_fill_init_cqp_wqe(cqp_wqe, nesdev); + /* If wqe in error was identified, set code to be put into cqe */ + if ((nesqp->term_sq_flush_code) && (which_wq & NES_CQP_FLUSH_SQ)) { + which_wq |= NES_CQP_FLUSH_MAJ_MIN; + sq_code = (CQE_MAJOR_DRV << 16) | nesqp->term_sq_flush_code; + nesqp->term_sq_flush_code = 0; + } + + if ((nesqp->term_rq_flush_code) && (which_wq & NES_CQP_FLUSH_RQ)) { + which_wq |= NES_CQP_FLUSH_MAJ_MIN; + rq_code = (CQE_MAJOR_DRV << 16) | nesqp->term_rq_flush_code; + nesqp->term_rq_flush_code = 0; + } + + if (which_wq & NES_CQP_FLUSH_MAJ_MIN) { + cqp_wqe->wqe_words[NES_CQP_QP_WQE_FLUSH_SQ_CODE] = cpu_to_le32(sq_code); + cqp_wqe->wqe_words[NES_CQP_QP_WQE_FLUSH_RQ_CODE] = cpu_to_le32(rq_code); + } + cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_FLUSH_WQES | which_wq); cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesqp->hwqp.qp_id); diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h index 4a0bfcd5a62..f28a41ba9fa 100644 --- a/drivers/infiniband/hw/nes/nes_hw.h +++ b/drivers/infiniband/hw/nes/nes_hw.h @@ -274,6 +274,8 @@ enum nes_cqp_qp_bits { enum nes_cqp_qp_wqe_word_idx { NES_CQP_QP_WQE_CONTEXT_LOW_IDX = 6, NES_CQP_QP_WQE_CONTEXT_HIGH_IDX = 7, + NES_CQP_QP_WQE_FLUSH_SQ_CODE = 8, + NES_CQP_QP_WQE_FLUSH_RQ_CODE = 9, NES_CQP_QP_WQE_NEW_MSS_IDX = 15, }; @@ -364,6 +366,7 @@ enum nes_cqp_arp_bits { enum nes_cqp_flush_bits { NES_CQP_FLUSH_SQ = (1<<30), NES_CQP_FLUSH_RQ = (1<<31), + NES_CQP_FLUSH_MAJ_MIN = (1<<28), }; enum nes_cqe_opcode_bits { @@ -757,6 +760,15 @@ enum nes_iwarp_sq_wqe_bits { NES_IWARP_SQ_OP_NOP = 12, }; +enum nes_iwarp_cqe_major_code { + NES_IWARP_CQE_MAJOR_FLUSH = 1, + NES_IWARP_CQE_MAJOR_DRV = 0x8000 +}; + +enum nes_iwarp_cqe_minor_code { + NES_IWARP_CQE_MINOR_FLUSH = 1 +}; + #define NES_EEPROM_READ_REQUEST (1<<16) #define NES_MAC_ADDR_VALID (1<<20) diff --git a/drivers/infiniband/hw/nes/nes_verbs.h b/drivers/infiniband/hw/nes/nes_verbs.h index d92b1ef4653..89822d75f82 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.h +++ b/drivers/infiniband/hw/nes/nes_verbs.h @@ -168,6 +168,8 @@ struct nes_qp { wait_queue_head_t kick_waitq; u16 in_disconnect; u16 private_data_len; + u16 term_sq_flush_code; + u16 term_rq_flush_code; u8 active_conn; u8 skip_lsmm; u8 user_mode; -- cgit v1.2.3-18-g5258 From 6eed5e7c8bdce6ee21bbe0be4a3f3dce4d4b392a Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:39 -0700 Subject: RDMA/nes: Make poll_cq return correct number of wqes during flush When a flush request is given to the hw, it will place one cqe marked as flushed (unless there is nothing to flush). An application that is waiting for all wqe's to complete will be left hanging. This modifies poll_cq to return the correct number of flushes for the pending elements on the wq. Signed-off-by: Don Wood Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_verbs.c | 61 +++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 36666ac2f54..ad3c891d0f6 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -3615,11 +3615,13 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) struct nes_qp *nesqp; struct nes_hw_cqe cqe; u32 head; - u32 wq_tail; + u32 wq_tail = 0; u32 cq_size; u32 cqe_count = 0; u32 wqe_index; u32 u32temp; + u32 move_cq_head = 1; + u32 err_code; nes_debug(NES_DBG_CQ, "\n"); @@ -3640,7 +3642,6 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) rmb(); cqe = nescq->hw_cq.cq_vbase[head]; - nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0; u32temp = le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]); wqe_index = u32temp & (nesdev->nesadapter->max_qp_wr - 1); u32temp &= ~(NES_SW_CONTEXT_ALIGN-1); @@ -3667,16 +3668,14 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) } /* Working on a SQ Completion*/ - wq_tail = wqe_index; - nesqp->hwqp.sq_tail = (wqe_index+1)&(nesqp->hwqp.sq_size - 1); - wrid = (((u64)(cpu_to_le32((u32)nesqp->hwqp.sq_vbase[wq_tail]. + wrid = (((u64)(cpu_to_le32((u32)nesqp->hwqp.sq_vbase[wqe_index]. wqe_words[NES_IWARP_SQ_WQE_COMP_SCRATCH_HIGH_IDX]))) << 32) | - ((u64)(cpu_to_le32((u32)nesqp->hwqp.sq_vbase[wq_tail]. + ((u64)(cpu_to_le32((u32)nesqp->hwqp.sq_vbase[wqe_index]. wqe_words[NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX]))); - entry->byte_len = le32_to_cpu(nesqp->hwqp.sq_vbase[wq_tail]. + entry->byte_len = le32_to_cpu(nesqp->hwqp.sq_vbase[wqe_index]. wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX]); - switch (le32_to_cpu(nesqp->hwqp.sq_vbase[wq_tail]. + switch (le32_to_cpu(nesqp->hwqp.sq_vbase[wqe_index]. wqe_words[NES_IWARP_SQ_WQE_MISC_IDX]) & 0x3f) { case NES_IWARP_SQ_OP_RDMAW: nes_debug(NES_DBG_CQ, "Operation = RDMA WRITE.\n"); @@ -3685,7 +3684,7 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) case NES_IWARP_SQ_OP_RDMAR: nes_debug(NES_DBG_CQ, "Operation = RDMA READ.\n"); entry->opcode = IB_WC_RDMA_READ; - entry->byte_len = le32_to_cpu(nesqp->hwqp.sq_vbase[wq_tail]. + entry->byte_len = le32_to_cpu(nesqp->hwqp.sq_vbase[wqe_index]. wqe_words[NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX]); break; case NES_IWARP_SQ_OP_SENDINV: @@ -3696,14 +3695,24 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) entry->opcode = IB_WC_SEND; break; } + + nesqp->hwqp.sq_tail = (wqe_index+1)&(nesqp->hwqp.sq_size - 1); + if ((entry->status != IB_WC_SUCCESS) && (nesqp->hwqp.sq_tail != nesqp->hwqp.sq_head)) { + move_cq_head = 0; + wq_tail = nesqp->hwqp.sq_tail; + } } else { /* Working on a RQ Completion*/ - wq_tail = wqe_index; - nesqp->hwqp.rq_tail = (wqe_index+1)&(nesqp->hwqp.rq_size - 1); entry->byte_len = le32_to_cpu(cqe.cqe_words[NES_CQE_PAYLOAD_LENGTH_IDX]); - wrid = ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wq_tail].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_LOW_IDX]))) | - ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wq_tail].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_HIGH_IDX]))<<32); + wrid = ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wqe_index].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_LOW_IDX]))) | + ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wqe_index].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_HIGH_IDX]))<<32); entry->opcode = IB_WC_RECV; + + nesqp->hwqp.rq_tail = (wqe_index+1)&(nesqp->hwqp.rq_size - 1); + if ((entry->status != IB_WC_SUCCESS) && (nesqp->hwqp.rq_tail != nesqp->hwqp.rq_head)) { + move_cq_head = 0; + wq_tail = nesqp->hwqp.rq_tail; + } } entry->wr_id = wrid; @@ -3711,18 +3720,28 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) cqe_count++; } - if (++head >= cq_size) - head = 0; - nescq->polled_completions++; + if (move_cq_head) { + nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0; + if (++head >= cq_size) + head = 0; + nescq->polled_completions++; - if ((nescq->polled_completions > (cq_size / 2)) || - (nescq->polled_completions == 255)) { - nes_debug(NES_DBG_CQ, "CQ%u Issuing CQE Allocate since more than half of cqes" + if ((nescq->polled_completions > (cq_size / 2)) || + (nescq->polled_completions == 255)) { + nes_debug(NES_DBG_CQ, "CQ%u Issuing CQE Allocate since more than half of cqes" " are pending %u of %u.\n", nescq->hw_cq.cq_number, nescq->polled_completions, cq_size); - nes_write32(nesdev->regs+NES_CQE_ALLOC, + nes_write32(nesdev->regs+NES_CQE_ALLOC, nescq->hw_cq.cq_number | (nescq->polled_completions << 16)); - nescq->polled_completions = 0; + nescq->polled_completions = 0; + } + } else { + /* Update the wqe index and set status to flush */ + wqe_index = le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]); + wqe_index = (wqe_index & (~(nesdev->nesadapter->max_qp_wr - 1))) | wq_tail; + nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX] = + cpu_to_le32(wqe_index); + move_cq_head = 1; /* ready for next pass */ } } -- cgit v1.2.3-18-g5258 From 320cdfd21d4a9f6ef54b74871e0d6b19a0e86fd6 Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:39 -0700 Subject: RDMA/nes: Use the flush code to fill in cqe error Use the flush status to fill in cqe status when a specific error has been identified. Subsequent flushed completions still use the flushed value. Signed-off-by: Don Wood Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_verbs.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index ad3c891d0f6..993c1d4e061 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -3655,7 +3655,16 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) if (cqe.cqe_words[NES_CQE_ERROR_CODE_IDX] == 0) { entry->status = IB_WC_SUCCESS; } else { - entry->status = IB_WC_WR_FLUSH_ERR; + err_code = le32_to_cpu(cqe.cqe_words[NES_CQE_ERROR_CODE_IDX]); + if (NES_IWARP_CQE_MAJOR_DRV == (err_code >> 16)) { + entry->status = err_code & 0x0000ffff; + + /* The rest of the cqe's will be marked as flushed */ + nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX] = + cpu_to_le32((NES_IWARP_CQE_MAJOR_FLUSH << 16) | + NES_IWARP_CQE_MINOR_FLUSH); + } else + entry->status = IB_WC_WR_FLUSH_ERR; } entry->qp = &nesqp->ibqp; -- cgit v1.2.3-18-g5258 From b29a4fc49b028dbdab53b679826ed1eb658dde59 Mon Sep 17 00:00:00 2001 From: Don Wood Date: Sat, 5 Sep 2009 20:36:39 -0700 Subject: RDMA/nes: Rework the disconn routine for terminate and flushing The disconn routine has been reworked to acoomodate the terminate and flushing changes. The routine has been reorganized to make all the decisions at the start then it performs all the required operations. This simplified the lock handling and is easier to follow. Signed-off-by: Don Wood Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_cm.c | 102 +++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index d89bdee0cf5..73473db1986 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -2493,7 +2493,12 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) u16 last_ae; u8 original_hw_tcp_state; u8 original_ibqp_state; - u8 issued_disconnect_reset = 0; + enum iw_cm_event_type disconn_status = IW_CM_EVENT_STATUS_OK; + int issue_disconn = 0; + int issue_close = 0; + int issue_flush = 0; + u32 flush_q = NES_CQP_FLUSH_RQ; + struct ib_event ibevent; if (!nesqp) { nes_debug(NES_DBG_CM, "disconnect_worker nesqp is NULL\n"); @@ -2517,24 +2522,55 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) original_ibqp_state = nesqp->ibqp_state; last_ae = nesqp->last_aeq; + if (nesqp->term_flags) { + issue_disconn = 1; + issue_close = 1; + nesqp->cm_id = NULL; + if (nesqp->flush_issued == 0) { + nesqp->flush_issued = 1; + issue_flush = 1; + } + } else if ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) || + ((original_ibqp_state == IB_QPS_RTS) && + (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { + issue_disconn = 1; + if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) + disconn_status = IW_CM_EVENT_STATUS_RESET; + } + + if (((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSED) || + (original_hw_tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT) || + (last_ae == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) || + (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { + issue_close = 1; + nesqp->cm_id = NULL; + if (nesqp->flush_issued == 0) { + nesqp->flush_issued = 1; + issue_flush = 1; + } + } + + spin_unlock_irqrestore(&nesqp->lock, flags); - nes_debug(NES_DBG_CM, "set ibqp_state=%u\n", nesqp->ibqp_state); + if ((issue_flush) && (nesqp->destroyed == 0)) { + /* Flush the queue(s) */ + if (nesqp->hw_iwarp_state >= NES_AEQE_IWARP_STATE_TERMINATE) + flush_q |= NES_CQP_FLUSH_SQ; + flush_wqes(nesvnic->nesdev, nesqp, flush_q, 1); - if ((nesqp->cm_id) && (cm_id->event_handler)) { - if ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) || - ((original_ibqp_state == IB_QPS_RTS) && - (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { + if (nesqp->term_flags) { + ibevent.device = nesqp->ibqp.device; + ibevent.event = nesqp->terminate_eventtype; + ibevent.element.qp = &nesqp->ibqp; + nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); + } + } + + if ((cm_id) && (cm_id->event_handler)) { + if (issue_disconn) { atomic_inc(&cm_disconnects); cm_event.event = IW_CM_EVENT_DISCONNECT; - if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) { - cm_event.status = IW_CM_EVENT_STATUS_RESET; - nes_debug(NES_DBG_CM, "Generating a CM " - "Disconnect Event (status reset) for " - "QP%u, cm_id = %p. \n", - nesqp->hwqp.qp_id, cm_id); - } else - cm_event.status = IW_CM_EVENT_STATUS_OK; - + cm_event.status = disconn_status; cm_event.local_addr = cm_id->local_addr; cm_event.remote_addr = cm_id->remote_addr; cm_event.private_data = NULL; @@ -2547,28 +2583,14 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) nesqp->hwqp.sq_tail, cm_id, atomic_read(&nesqp->refcount)); - spin_unlock_irqrestore(&nesqp->lock, flags); ret = cm_id->event_handler(cm_id, &cm_event); if (ret) nes_debug(NES_DBG_CM, "OFA CM event_handler " "returned, ret=%d\n", ret); - spin_lock_irqsave(&nesqp->lock, flags); } - /* There might have been another AE while the lock was released */ - original_hw_tcp_state = nesqp->hw_tcp_state; - original_ibqp_state = nesqp->ibqp_state; - last_ae = nesqp->last_aeq; - - if ((issued_disconnect_reset == 0) && (nesqp->cm_id) && - ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSED) || - (original_hw_tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT) || - (last_ae == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) || - (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { + if (issue_close) { atomic_inc(&cm_closes); - nesqp->cm_id = NULL; - nesqp->in_disconnect = 0; - spin_unlock_irqrestore(&nesqp->lock, flags); nes_disconnect(nesqp, 1); cm_id->provider_data = nesqp; @@ -2587,27 +2609,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) } cm_id->rem_ref(cm_id); - - spin_lock_irqsave(&nesqp->lock, flags); - if (nesqp->flush_issued == 0) { - nesqp->flush_issued = 1; - spin_unlock_irqrestore(&nesqp->lock, flags); - flush_wqes(nesvnic->nesdev, nesqp, - NES_CQP_FLUSH_RQ, 1); - } else - spin_unlock_irqrestore(&nesqp->lock, flags); - } else { - cm_id = nesqp->cm_id; - spin_unlock_irqrestore(&nesqp->lock, flags); - /* check to see if the inbound reset beat the outbound reset */ - if ((!cm_id) && (last_ae==NES_AEQE_AEID_RESET_SENT)) { - nes_debug(NES_DBG_CM, "QP%u: Decing refcount " - "due to inbound reset beating the " - "outbound reset.\n", nesqp->hwqp.qp_id); - } } - } else { - spin_unlock_irqrestore(&nesqp->lock, flags); } return 0; -- cgit v1.2.3-18-g5258 From cd1d3f7abec19719949ec5b5189a821cd52af868 Mon Sep 17 00:00:00 2001 From: Chien Tung Date: Sat, 5 Sep 2009 20:36:39 -0700 Subject: RDMA/nes: Map MTU to IB_MTU_* and correctly report link state Old query_port code reports static MTU and link state values. Instead, map actual MTU to next largest IB_MTU_* constant and correctly report link state. Cc: Steve Wise Reported-by: Jeff Squyres Signed-off-by: Chien Tung Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_verbs.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 993c1d4e061..a680c42d6e8 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -667,15 +667,32 @@ static int nes_query_device(struct ib_device *ibdev, struct ib_device_attr *prop */ static int nes_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr *props) { + struct nes_vnic *nesvnic = to_nesvnic(ibdev); + struct net_device *netdev = nesvnic->netdev; + memset(props, 0, sizeof(*props)); - props->max_mtu = IB_MTU_2048; - props->active_mtu = IB_MTU_2048; + props->max_mtu = IB_MTU_4096; + + if (netdev->mtu >= 4096) + props->active_mtu = IB_MTU_4096; + else if (netdev->mtu >= 2048) + props->active_mtu = IB_MTU_2048; + else if (netdev->mtu >= 1024) + props->active_mtu = IB_MTU_1024; + else if (netdev->mtu >= 512) + props->active_mtu = IB_MTU_512; + else + props->active_mtu = IB_MTU_256; + props->lid = 1; props->lmc = 0; props->sm_lid = 0; props->sm_sl = 0; - props->state = IB_PORT_ACTIVE; + if (nesvnic->linkup) + props->state = IB_PORT_ACTIVE; + else + props->state = IB_PORT_DOWN; props->phys_state = 0; props->port_cap_flags = IB_PORT_CM_SUP | IB_PORT_REINIT_SUP | IB_PORT_VENDOR_CLASS_SUP | IB_PORT_BOOT_MGMT_SUP; -- cgit v1.2.3-18-g5258 From d9d8e0418ffd3d189345c435861e254c17ae06e5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 6 Sep 2009 01:41:02 -0700 Subject: gianfar: Fix build. Reported by Michael Guntsche -------------------- Commit 38bddf04bcfe661fbdab94888c3b72c32f6873b3 gianfar: gfar_remove needs to call unregister_netdev() breaks the build of the gianfar driver because "dev" is undefined in this function. To quickly test rc9 I changed this to priv->ndev but I do not know if this is the correct one. -------------------- Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 24f7ca5e17d..a00ec639c38 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -491,7 +491,7 @@ static int gfar_remove(struct of_device *ofdev) dev_set_drvdata(&ofdev->dev, NULL); - unregister_netdev(dev); + unregister_netdev(priv->ndev); iounmap(priv->regs); free_netdev(priv->ndev); -- cgit v1.2.3-18-g5258 From a54775c8758a754186bc6adbfc518b1e9f8f1e4e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 7 Sep 2009 15:26:19 +1000 Subject: drm/radeon/kms: add LTE/GTE discard + rv515 two sided stencil register. This adds some rv350+ register for LTE/GTE discard, and enables the rv515 two sided stencil register. It also disables the DEPTHXY_OFFSET register which can be used to workaround the CS checker. Moves rs690 to proper place in rs600 and uses correct table on rs600. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r300.c | 2 +- drivers/gpu/drm/radeon/radeon_asic.h | 6 ++-- drivers/gpu/drm/radeon/rs600.c | 65 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/rs690.c | 64 ----------------------------------- drivers/gpu/drm/radeon/rv515.c | 2 +- 5 files changed, 70 insertions(+), 69 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 053f4ec397f..051bca6e3a4 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -995,7 +995,7 @@ static const unsigned r300_reg_safe_bm[159] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, 0xFF80FFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x0003FC01, 0xFFFFFFF8, 0xFE800B19, + 0x0003FC01, 0xFFFFFCF8, 0xFF800B19, }; static int r300_packet0_check(struct radeon_cs_parser *p, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 7ca6c13569b..93d8f888930 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -266,6 +266,7 @@ static struct radeon_asic rs400_asic = { /* * rs600. */ +int rs600_init(struct radeon_device *dev); void rs600_errata(struct radeon_device *rdev); void rs600_vram_info(struct radeon_device *rdev); int rs600_mc_init(struct radeon_device *rdev); @@ -281,7 +282,7 @@ uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); void rs600_bandwidth_update(struct radeon_device *rdev); static struct radeon_asic rs600_asic = { - .init = &r300_init, + .init = &rs600_init, .errata = &rs600_errata, .vram_info = &rs600_vram_info, .gpu_reset = &r300_gpu_reset, @@ -316,7 +317,6 @@ static struct radeon_asic rs600_asic = { /* * rs690,rs740 */ -int rs690_init(struct radeon_device *rdev); void rs690_errata(struct radeon_device *rdev); void rs690_vram_info(struct radeon_device *rdev); int rs690_mc_init(struct radeon_device *rdev); @@ -325,7 +325,7 @@ uint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rs690_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); void rs690_bandwidth_update(struct radeon_device *rdev); static struct radeon_asic rs690_asic = { - .init = &rs690_init, + .init = &rs600_init, .errata = &rs690_errata, .vram_info = &rs690_vram_info, .gpu_reset = &r300_gpu_reset, diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 7e8ce983a90..02fd11aad6a 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -409,3 +409,68 @@ void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) ((reg) & RS600_MC_ADDR_MASK)); WREG32(RS600_MC_DATA, v); } + +static const unsigned rs600_reg_safe_bm[219] = { + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x17FF1FFF, 0xFFFFFFFC, 0xFFFFFFFF, 0xFF30FFBF, + 0xFFFFFFF8, 0xC3E6FFFF, 0xFFFFF6DF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFF03F, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFEFCE, 0xF00EBFFF, 0x007C0000, + 0xF0000078, 0xFF000009, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFF7FF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFC78, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, + 0x38FF8F50, 0xFFF88082, 0xF000000C, 0xFAE009FF, + 0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0x0000C100, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0xFFFF0000, 0xFFFFFFFF, 0xFF80FFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0003FC01, 0xFFFFFCF8, 0xFF800B19, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +}; + +int rs600_init(struct radeon_device *rdev) +{ + rdev->config.r300.reg_safe_bm = rs600_reg_safe_bm; + rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(rs600_reg_safe_bm); + return 0; +} diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index bc6b7c5339b..879882533e4 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -653,67 +653,3 @@ void rs690_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) WREG32(RS690_MC_INDEX, RS690_MC_INDEX_WR_ACK); } -static const unsigned rs690_reg_safe_bm[219] = { - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0x17FF1FFF,0xFFFFFFFC,0xFFFFFFFF,0xFF30FFBF, - 0xFFFFFFF8,0xC3E6FFFF,0xFFFFF6DF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFF03F, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFEFCE,0xF00EBFFF,0x007C0000, - 0xF0000078,0xFF000009,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFF7FF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFC78,0xFFFFFFFF,0xFFFFFFFE,0xFFFFFFFF, - 0x38FF8F50,0xFFF88082,0xF000000C,0xFAE009FF, - 0x0000FFFF,0xFFFFFFFF,0xFFFFFFFF,0x00000000, - 0x00000000,0x0000C100,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0xFFFF0000,0xFFFFFFFF,0xFF80FFFF, - 0x00000000,0x00000000,0x00000000,0x00000000, - 0x0003FC01,0xFFFFFFF8,0xFE800B19,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, -}; - -int rs690_init(struct radeon_device *rdev) -{ - rdev->config.r300.reg_safe_bm = rs690_reg_safe_bm; - rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(rs690_reg_safe_bm); - return 0; -} diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 31a7f668ae5..0566fb67e46 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -508,7 +508,7 @@ static const unsigned r500_reg_safe_bm[219] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF80FFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x0003FC01, 0x3FFFFCF8, 0xFE800B19, 0xFFFFFFFF, + 0x0003FC01, 0x3FFFFCF8, 0xFF800B19, 0xFFDFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, -- cgit v1.2.3-18-g5258 From db4cfd8a6149e778befb2ff6e6f91cdc6394cbe6 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sat, 5 Sep 2009 17:43:07 +0000 Subject: netxen: handle firmware load errors Unwind allocations and release file firmware when when firmware load fails. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_hw.c | 3 +++ drivers/net/netxen/netxen_nic_init.c | 1 + drivers/net/netxen/netxen_nic_main.c | 20 ++++++++++++++++---- 3 files changed, 20 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index db510cee809..d0ac8fabd42 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -566,6 +566,9 @@ netxen_send_cmd_descs(struct netxen_adapter *adapter, i = 0; + if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) + return -EIO; + tx_ring = adapter->tx_ring; __netif_tx_lock_bh(tx_ring->txq); diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 04e36f2b1a9..534994dc167 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -905,6 +905,7 @@ netxen_release_firmware(struct netxen_adapter *adapter) { if (adapter->fw) release_firmware(adapter->fw); + adapter->fw = NULL; } int netxen_init_dummy_dma(struct netxen_adapter *adapter) diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 41b29671fc9..47aede62203 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -757,7 +757,7 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) err = netxen_need_fw_reset(adapter); if (err < 0) - return err; + goto err_out; if (err == 0) goto wait_init; @@ -771,7 +771,9 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) netxen_set_port_mode(adapter); - netxen_load_firmware(adapter); + err = netxen_load_firmware(adapter); + if (err) + goto err_out; if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { @@ -785,7 +787,7 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) err = netxen_init_dummy_dma(adapter); if (err) - return err; + goto err_out; /* * Tell the hardware our version number. @@ -800,7 +802,7 @@ wait_init: err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); if (err) { netxen_free_dummy_dma(adapter); - return err; + goto err_out; } nx_update_dma_mask(adapter); @@ -808,6 +810,10 @@ wait_init: netxen_nic_get_firmware_info(adapter); return 0; + +err_out: + netxen_release_firmware(adapter); + return err; } static int @@ -876,6 +882,9 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) { int err; + if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) + return -EIO; + err = adapter->init_port(adapter, adapter->physical_port); if (err) { printk(KERN_ERR "%s: Failed to initialize port %d\n", @@ -914,6 +923,9 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) static void netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) { + if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) + return; + spin_lock(&adapter->tx_clean_lock); netif_carrier_off(netdev); netif_tx_disable(netdev); -- cgit v1.2.3-18-g5258 From 6a581e93981e8838c85e407303186faf937830d3 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sat, 5 Sep 2009 17:43:08 +0000 Subject: netxen: firmware hang detection Implement state machine to detect firmware hung state and recover. Since firmware will be shared by all PCI functions that have different class drivers (NIC or FCOE or iSCSI), explicit hardware based serialization is required for initializing firmware. o Used global scratchpad register to maintain device reference count. Every probed pci function adds to ref count. o Implement timer (delayed work) for each pci func that checks firmware heartbit every 5 sec and detaches itself if firmware is dead. Last detaching function reloads firmware. Other functions wait for firmware init, and re-attach themselves. Heartbit is not supported by NX2031 firmware. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 17 +- drivers/net/netxen/netxen_nic_ctx.c | 8 + drivers/net/netxen/netxen_nic_hdr.h | 23 +++ drivers/net/netxen/netxen_nic_main.c | 388 +++++++++++++++++++++++++++-------- 4 files changed, 348 insertions(+), 88 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index ede2fa7477a..30a38163b23 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -229,6 +229,8 @@ #define MPORT_SINGLE_FUNCTION_MODE 0x1111 #define MPORT_MULTI_FUNCTION_MODE 0x2222 +#define NX_MAX_PCI_FUNC 8 + /* * NetXen host-peg signal message structure * @@ -1101,6 +1103,10 @@ typedef struct { #define NETXEN_ADAPTER_UP_MAGIC 777 #define NETXEN_NIC_PEG_TUNE 0 +#define __NX_FW_ATTACHED 0 +#define __NX_DEV_UP 1 +#define __NX_RESETTING 2 + struct netxen_dummy_dma { void *addr; dma_addr_t phys_addr; @@ -1137,7 +1143,9 @@ struct netxen_adapter { u8 max_mc_count; u8 rss_supported; u8 link_changed; - u32 resv3; + u8 fw_wait_cnt; + u8 fw_fail_cnt; + u16 resv4; u8 has_link_events; u8 fw_type; @@ -1156,7 +1164,7 @@ struct netxen_adapter { u32 temp; u32 msi_tgt_status; - u32 resv4; + u32 heartbit; struct netxen_adapter_stats stats; @@ -1187,14 +1195,15 @@ struct netxen_adapter { struct netxen_dummy_dma dummy_dma; - struct work_struct watchdog_task; - struct timer_list watchdog_timer; + struct delayed_work fw_work; + struct work_struct tx_timeout_task; struct net_device_stats net_stats; nx_nic_intr_coalesce_t coal; + unsigned long state; u32 resv5; u32 fw_version; const struct firmware *fw; diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 0f42ab99836..8ab5773e47d 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -678,6 +678,9 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + if (test_and_set_bit(__NX_FW_ATTACHED, &adapter->state)) + goto done; + err = nx_fw_cmd_create_rx_ctx(adapter); if (err) goto err_out_free; @@ -690,6 +693,7 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) goto err_out_free; } +done: return 0; err_out_free: @@ -708,6 +712,9 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter) int port = adapter->portnum; if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + if (!test_and_clear_bit(__NX_FW_ATTACHED, &adapter->state)) + goto done; + nx_fw_cmd_destroy_rx_ctx(adapter); nx_fw_cmd_destroy_tx_ctx(adapter); } else { @@ -720,6 +727,7 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter) /* Allow dma queues to drain after context reset */ msleep(20); +done: recv_ctx = &adapter->recv_ctx; if (recv_ctx->hwctx != NULL) { diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index 92f5970c9aa..26188b43abe 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h @@ -433,6 +433,7 @@ enum { #define NETXEN_CRB_PEG_NET_1 NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_PGN1) #define NETXEN_CRB_PEG_NET_2 NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_PGN2) #define NETXEN_CRB_PEG_NET_3 NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_PGN3) +#define NETXEN_CRB_PEG_NET_4 NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_SQS2) #define NETXEN_CRB_PEG_NET_D NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_PGND) #define NETXEN_CRB_PEG_NET_I NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_PGNI) #define NETXEN_CRB_DDR_NET NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_MN) @@ -945,6 +946,28 @@ enum { #define NETXEN_DMA_WATCHDOG_CTRL (NETXEN_CAM_RAM(0x14)) #define NETXEN_PEG_ALIVE_COUNTER (NETXEN_CAM_RAM(0xb0)) +#define NETXEN_PEG_HALT_STATUS1 (NETXEN_CAM_RAM(0xa8)) +#define NETXEN_PEG_HALT_STATUS2 (NETXEN_CAM_RAM(0xac)) +#define NX_CRB_DEV_REF_COUNT (NETXEN_CAM_RAM(0x138)) +#define NX_CRB_DEV_STATE (NETXEN_CAM_RAM(0x140)) + +/* Device State */ +#define NX_DEV_COLD 1 +#define NX_DEV_INITALIZING 2 +#define NX_DEV_READY 3 +#define NX_DEV_NEED_RESET 4 +#define NX_DEV_NEED_QUISCENT 5 +#define NX_DEV_FAILED 6 + +#define NX_RCODE_DRIVER_INFO 0x20000000 +#define NX_RCODE_DRIVER_CAN_RELOAD 0x40000000 +#define NX_RCODE_FATAL_ERROR 0x80000000 +#define NX_FWERROR_PEGNUM(code) ((code) & 0xff) +#define NX_FWERROR_CODE(code) ((code >> 8) & 0xfffff) + +#define FW_POLL_DELAY (2 * HZ) +#define FW_FAIL_THRESH 3 +#define FW_POLL_THRESH 10 #define ISR_MSI_INT_TRIGGER(FUNC) (NETXEN_PCIX_PS_REG(PCIX_MSI_F(FUNC))) #define ISR_LEGACY_INT_TRIGGERED(VAL) (((VAL) & 0x300) == 0x200) diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 47aede62203..49894360137 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -67,7 +67,10 @@ static netdev_tx_t netxen_nic_xmit_frame(struct sk_buff *, struct net_device *); static void netxen_tx_timeout(struct net_device *netdev); static void netxen_reset_task(struct work_struct *work); -static void netxen_watchdog(unsigned long); +static void netxen_fw_poll_work(struct work_struct *work); +static void netxen_schedule_work(struct netxen_adapter *adapter, + work_func_t func, int delay); +static void netxen_cancel_fw_work(struct netxen_adapter *adapter); static int netxen_nic_poll(struct napi_struct *napi, int budget); #ifdef CONFIG_NET_POLL_CONTROLLER static void netxen_nic_poll_controller(struct net_device *netdev); @@ -76,6 +79,9 @@ static void netxen_nic_poll_controller(struct net_device *netdev); static void netxen_create_sysfs_entries(struct netxen_adapter *adapter); static void netxen_remove_sysfs_entries(struct netxen_adapter *adapter); +static int nx_decr_dev_ref_cnt(struct netxen_adapter *adapter); +static int netxen_can_start_firmware(struct netxen_adapter *adapter); + static irqreturn_t netxen_intr(int irq, void *data); static irqreturn_t netxen_msi_intr(int irq, void *data); static irqreturn_t netxen_msix_intr(int irq, void *data); @@ -729,19 +735,12 @@ err_out: } static int -netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) +netxen_start_firmware(struct netxen_adapter *adapter) { int val, err, first_boot; struct pci_dev *pdev = adapter->pdev; - int first_driver = 0; - - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) - first_driver = (adapter->portnum == 0); - else - first_driver = (adapter->ahw.pci_func == 0); - - if (!first_driver) + if (!netxen_can_start_firmware(adapter)) goto wait_init; first_boot = NXRD32(adapter, NETXEN_CAM_RAM(0x1fc)); @@ -752,8 +751,7 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) return err; } - if (request_fw) - netxen_request_firmware(adapter); + netxen_request_firmware(adapter); err = netxen_need_fw_reset(adapter); if (err < 0) @@ -768,6 +766,9 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) } NXWR32(adapter, CRB_DMA_SHIFT, 0x55555555); + NXWR32(adapter, NETXEN_PEG_HALT_STATUS1, 0); + NXWR32(adapter, NETXEN_PEG_HALT_STATUS2, 0); + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) netxen_set_port_mode(adapter); @@ -775,6 +776,8 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) if (err) goto err_out; + netxen_release_firmware(adapter); + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { /* Initialize multicast addr pool owners */ @@ -797,6 +800,8 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) | (_NETXEN_NIC_LINUX_SUBVERSION); NXWR32(adapter, CRB_DRIVER_VERSION, val); + NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_READY); + wait_init: /* Handshake with the card before we register the devices. */ err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); @@ -808,6 +813,7 @@ wait_init: nx_update_dma_mask(adapter); netxen_nic_get_firmware_info(adapter); + netxen_check_options(adapter); return 0; @@ -915,8 +921,7 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) else netxen_nic_set_link_parameters(adapter); - mod_timer(&adapter->watchdog_timer, jiffies); - + set_bit(__NX_DEV_UP, &adapter->state); return 0; } @@ -926,6 +931,8 @@ netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) return; + clear_bit(__NX_DEV_UP, &adapter->state); + spin_lock(&adapter->tx_clean_lock); netif_carrier_off(netdev); netif_tx_disable(netdev); @@ -942,8 +949,6 @@ netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) netxen_release_tx_buffers(adapter); spin_unlock(&adapter->tx_clean_lock); - - del_timer_sync(&adapter->watchdog_timer); } @@ -974,8 +979,6 @@ netxen_nic_attach(struct netxen_adapter *adapter) return err; } - netxen_nic_clear_stats(adapter); - err = netxen_alloc_hw_resources(adapter); if (err) { printk(KERN_ERR "%s: Error in setting hw resources\n", @@ -1046,21 +1049,32 @@ netxen_nic_reset_context(struct netxen_adapter *adapter) int err = 0; struct net_device *netdev = adapter->netdev; + if (test_and_set_bit(__NX_RESETTING, &adapter->state)) + return -EBUSY; + if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) { + netif_device_detach(netdev); + if (netif_running(netdev)) netxen_nic_down(adapter, netdev); netxen_nic_detach(adapter); - err = netxen_nic_attach(adapter); - if (err) - goto done; + if (netif_running(netdev)) { + err = netxen_nic_attach(adapter); + if (!err) + err = netxen_nic_up(adapter, netdev); - if (netif_running(netdev)) - err = netxen_nic_up(adapter, netdev); + if (err) + goto done; + } + + netif_device_attach(netdev); } + done: + clear_bit(__NX_RESETTING, &adapter->state); return err; } @@ -1107,10 +1121,6 @@ netxen_setup_netdev(struct netxen_adapter *adapter, netdev->irq = adapter->msix_entries[0].vector; - init_timer(&adapter->watchdog_timer); - adapter->watchdog_timer.function = &netxen_watchdog; - adapter->watchdog_timer.data = (unsigned long)adapter; - INIT_WORK(&adapter->watchdog_task, netxen_watchdog_task); INIT_WORK(&adapter->tx_timeout_task, netxen_reset_task); if (netxen_read_mac_addr(adapter)) @@ -1214,7 +1224,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) break; } - err = netxen_start_firmware(adapter, 1); + err = netxen_start_firmware(adapter); if (err) goto err_out_iounmap; @@ -1228,7 +1238,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->physical_port = i; } - netxen_check_options(adapter); + netxen_nic_clear_stats(adapter); netxen_setup_intr(adapter); @@ -1238,6 +1248,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, adapter); + netxen_schedule_work(adapter, netxen_fw_poll_work, FW_POLL_DELAY); + switch (adapter->ahw.port_type) { case NETXEN_NIC_GBE: dev_info(&adapter->pdev->dev, "%s: GbE port initialized\n", @@ -1256,6 +1268,8 @@ err_out_disable_msi: netxen_free_dummy_dma(adapter); + nx_decr_dev_ref_cnt(adapter); + err_out_iounmap: netxen_cleanup_pci_map(adapter); @@ -1282,16 +1296,21 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) netdev = adapter->netdev; + netxen_cancel_fw_work(adapter); + unregister_netdev(netdev); - cancel_work_sync(&adapter->watchdog_task); cancel_work_sync(&adapter->tx_timeout_task); netxen_nic_detach(adapter); + nx_decr_dev_ref_cnt(adapter); + if (adapter->portnum == 0) netxen_free_dummy_dma(adapter); + clear_bit(__NX_RESETTING, &adapter->state); + netxen_teardown_intr(adapter); netxen_cleanup_pci_map(adapter); @@ -1312,10 +1331,11 @@ static int __netxen_nic_shutdown(struct pci_dev *pdev) netif_device_detach(netdev); + netxen_cancel_fw_work(adapter); + if (netif_running(netdev)) netxen_nic_down(adapter, netdev); - cancel_work_sync(&adapter->watchdog_task); cancel_work_sync(&adapter->tx_timeout_task); netxen_nic_detach(adapter); @@ -1323,6 +1343,10 @@ static int __netxen_nic_shutdown(struct pci_dev *pdev) if (adapter->portnum == 0) netxen_free_dummy_dma(adapter); + nx_decr_dev_ref_cnt(adapter); + + clear_bit(__NX_RESETTING, &adapter->state); + retval = pci_save_state(pdev); if (retval) return retval; @@ -1371,7 +1395,7 @@ netxen_nic_resume(struct pci_dev *pdev) adapter->curr_window = 255; - err = netxen_start_firmware(adapter, 0); + err = netxen_start_firmware(adapter); if (err) { dev_err(&pdev->dev, "failed to start firmware\n"); return err; @@ -1380,16 +1404,22 @@ netxen_nic_resume(struct pci_dev *pdev) if (netif_running(netdev)) { err = netxen_nic_attach(adapter); if (err) - return err; + goto err_out; err = netxen_nic_up(adapter, netdev); if (err) - return err; + goto err_out_detach; netif_device_attach(netdev); } - return 0; + netxen_schedule_work(adapter, netxen_fw_poll_work, FW_POLL_DELAY); + +err_out_detach: + netxen_nic_detach(adapter); +err_out: + nx_decr_dev_ref_cnt(adapter); + return err; } #endif @@ -1783,59 +1813,13 @@ static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter) netxen_advert_link_change(adapter, linkup); } -static void netxen_nic_thermal_shutdown(struct netxen_adapter *adapter) -{ - struct net_device *netdev = adapter->netdev; - - netif_device_detach(netdev); - netxen_nic_down(adapter, netdev); - netxen_nic_detach(adapter); -} - -static void netxen_watchdog(unsigned long v) -{ - struct netxen_adapter *adapter = (struct netxen_adapter *)v; - - if (netxen_nic_check_temp(adapter)) - goto do_sched; - - if (!adapter->has_link_events) { - netxen_nic_handle_phy_intr(adapter); - - if (adapter->link_changed) - goto do_sched; - } - - if (netif_running(adapter->netdev)) - mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); - - return; - -do_sched: - schedule_work(&adapter->watchdog_task); -} - -void netxen_watchdog_task(struct work_struct *work) -{ - struct netxen_adapter *adapter = - container_of(work, struct netxen_adapter, watchdog_task); - - if (adapter->temp == NX_TEMP_PANIC) { - netxen_nic_thermal_shutdown(adapter); - return; - } - - if (adapter->link_changed) - netxen_nic_set_link_parameters(adapter); - - if (netif_running(adapter->netdev)) - mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); -} - static void netxen_tx_timeout(struct net_device *netdev) { struct netxen_adapter *adapter = netdev_priv(netdev); + if (test_bit(__NX_RESETTING, &adapter->state)) + return; + dev_err(&netdev->dev, "transmit timeout, resetting.\n"); schedule_work(&adapter->tx_timeout_task); } @@ -1848,6 +1832,9 @@ static void netxen_reset_task(struct work_struct *work) if (!netif_running(adapter->netdev)) return; + if (test_bit(__NX_RESETTING, &adapter->state)) + return; + netxen_napi_disable(adapter); adapter->netdev->trans_start = jiffies; @@ -1974,6 +1961,239 @@ static void netxen_nic_poll_controller(struct net_device *netdev) } #endif +static int +nx_incr_dev_ref_cnt(struct netxen_adapter *adapter) +{ + int count; + if (netxen_api_lock(adapter)) + return -EIO; + + count = NXRD32(adapter, NX_CRB_DEV_REF_COUNT); + + NXWR32(adapter, NX_CRB_DEV_REF_COUNT, ++count); + + netxen_api_unlock(adapter); + return count; +} + +static int +nx_decr_dev_ref_cnt(struct netxen_adapter *adapter) +{ + int count; + if (netxen_api_lock(adapter)) + return -EIO; + + count = NXRD32(adapter, NX_CRB_DEV_REF_COUNT); + WARN_ON(count == 0); + + NXWR32(adapter, NX_CRB_DEV_REF_COUNT, --count); + + if (count == 0) + NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_COLD); + + netxen_api_unlock(adapter); + return count; +} + +static int +netxen_can_start_firmware(struct netxen_adapter *adapter) +{ + int count; + int can_start = 0; + + if (netxen_api_lock(adapter)) + return 0; + + count = NXRD32(adapter, NX_CRB_DEV_REF_COUNT); + + if ((count < 0) || (count >= NX_MAX_PCI_FUNC)) + count = 0; + + if (count == 0) { + can_start = 1; + NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_INITALIZING); + } + + NXWR32(adapter, NX_CRB_DEV_REF_COUNT, ++count); + + netxen_api_unlock(adapter); + + return can_start; +} + +static void +netxen_schedule_work(struct netxen_adapter *adapter, + work_func_t func, int delay) +{ + INIT_DELAYED_WORK(&adapter->fw_work, func); + schedule_delayed_work(&adapter->fw_work, delay); +} + +static void +netxen_cancel_fw_work(struct netxen_adapter *adapter) +{ + while (test_and_set_bit(__NX_RESETTING, &adapter->state)) + msleep(10); + + cancel_delayed_work_sync(&adapter->fw_work); +} + +static void +netxen_attach_work(struct work_struct *work) +{ + struct netxen_adapter *adapter = container_of(work, + struct netxen_adapter, fw_work.work); + struct net_device *netdev = adapter->netdev; + int err = 0; + + if (netif_running(netdev)) { + err = netxen_nic_attach(adapter); + if (err) + goto done; + + err = netxen_nic_up(adapter, netdev); + if (err) { + netxen_nic_detach(adapter); + goto done; + } + + } + + netif_device_attach(netdev); + +done: + adapter->fw_fail_cnt = 0; + clear_bit(__NX_RESETTING, &adapter->state); + netxen_schedule_work(adapter, netxen_fw_poll_work, FW_POLL_DELAY); +} + +static void +netxen_fwinit_work(struct work_struct *work) +{ + struct netxen_adapter *adapter = container_of(work, + struct netxen_adapter, fw_work.work); + int dev_state; + + dev_state = NXRD32(adapter, NX_CRB_DEV_STATE); + + switch (dev_state) { + case NX_DEV_COLD: + case NX_DEV_READY: + netxen_start_firmware(adapter); + netxen_schedule_work(adapter, netxen_attach_work, 0); + return; + + case NX_DEV_INITALIZING: + if (++adapter->fw_wait_cnt < FW_POLL_THRESH) { + netxen_schedule_work(adapter, + netxen_fwinit_work, 2 * FW_POLL_DELAY); + return; + } + break; + + case NX_DEV_FAILED: + default: + break; + } + + nx_incr_dev_ref_cnt(adapter); + clear_bit(__NX_RESETTING, &adapter->state); +} + +static void +netxen_detach_work(struct work_struct *work) +{ + struct netxen_adapter *adapter = container_of(work, + struct netxen_adapter, fw_work.work); + struct net_device *netdev = adapter->netdev; + int ref_cnt, delay; + u32 status; + + netif_device_detach(netdev); + + if (netif_running(netdev)) + netxen_nic_down(adapter, netdev); + + netxen_nic_detach(adapter); + + status = NXRD32(adapter, NETXEN_PEG_HALT_STATUS1); + + ref_cnt = nx_decr_dev_ref_cnt(adapter); + + if (status & NX_RCODE_FATAL_ERROR) + return; + + if (adapter->temp == NX_TEMP_PANIC) + return; + + delay = (ref_cnt == 0) ? 0 : (2 * FW_POLL_DELAY); + + adapter->fw_wait_cnt = 0; + netxen_schedule_work(adapter, netxen_fwinit_work, delay); +} + +static int +netxen_check_health(struct netxen_adapter *adapter) +{ + u32 state, heartbit; + struct net_device *netdev = adapter->netdev; + + if (netxen_nic_check_temp(adapter)) + goto detach; + + state = NXRD32(adapter, NX_CRB_DEV_STATE); + if (state == NX_DEV_NEED_RESET) + goto detach; + + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) + return 0; + + heartbit = NXRD32(adapter, NETXEN_PEG_ALIVE_COUNTER); + if (heartbit != adapter->heartbit) { + adapter->heartbit = heartbit; + adapter->fw_fail_cnt = 0; + return 0; + } + + if (++adapter->fw_fail_cnt < FW_FAIL_THRESH) + return 0; + + clear_bit(__NX_FW_ATTACHED, &adapter->state); + + dev_info(&netdev->dev, "firmware hang detected\n"); + +detach: + if (!test_and_set_bit(__NX_RESETTING, &adapter->state)) + netxen_schedule_work(adapter, netxen_detach_work, 0); + return 1; +} + +static void +netxen_fw_poll_work(struct work_struct *work) +{ + struct netxen_adapter *adapter = container_of(work, + struct netxen_adapter, fw_work.work); + + if (test_bit(__NX_RESETTING, &adapter->state)) + goto reschedule; + + if (test_bit(__NX_DEV_UP, &adapter->state)) { + if (!adapter->has_link_events) { + + netxen_nic_handle_phy_intr(adapter); + + if (adapter->link_changed) + netxen_nic_set_link_parameters(adapter); + } + } + + if (netxen_check_health(adapter)) + return; + +reschedule: + netxen_schedule_work(adapter, netxen_fw_poll_work, FW_POLL_DELAY); +} + static ssize_t netxen_store_bridged_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) -- cgit v1.2.3-18-g5258 From d0725e4d3ccf603c4fcf3589850cb464c927d42a Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Sat, 5 Sep 2009 17:43:09 +0000 Subject: netxen: fix ip addr hashing after firmware reset Reprogram local IP addresses after firmware is reset or after resuming from suspend. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_main.c | 61 +++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 49894360137..7038e1baaf4 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -86,6 +86,8 @@ static irqreturn_t netxen_intr(int irq, void *data); static irqreturn_t netxen_msi_intr(int irq, void *data); static irqreturn_t netxen_msix_intr(int irq, void *data); +static void netxen_config_indev_addr(struct net_device *dev, unsigned long); + /* PCI Device ID Table */ #define ENTRY(device) \ {PCI_DEVICE(PCI_VENDOR_ID_NETXEN, (device)), \ @@ -1411,6 +1413,8 @@ netxen_nic_resume(struct pci_dev *pdev) goto err_out_detach; netif_device_attach(netdev); + + netxen_config_indev_addr(netdev, NETDEV_UP); } netxen_schedule_work(adapter, netxen_fw_poll_work, FW_POLL_DELAY); @@ -2057,6 +2061,7 @@ netxen_attach_work(struct work_struct *work) goto done; } + netxen_config_indev_addr(netdev, NETDEV_UP); } netif_device_attach(netdev); @@ -2282,12 +2287,43 @@ netxen_destip_supported(struct netxen_adapter *adapter) return 1; } +static void +netxen_config_indev_addr(struct net_device *dev, unsigned long event) +{ + struct in_device *indev; + struct netxen_adapter *adapter = netdev_priv(dev); + + if (netxen_destip_supported(adapter)) + return; + + indev = in_dev_get(dev); + if (!indev) + return; + + for_ifa(indev) { + switch (event) { + case NETDEV_UP: + netxen_config_ipaddr(adapter, + ifa->ifa_address, NX_IP_UP); + break; + case NETDEV_DOWN: + netxen_config_ipaddr(adapter, + ifa->ifa_address, NX_IP_DOWN); + break; + default: + break; + } + } endfor_ifa(indev); + + in_dev_put(indev); + return; +} + static int netxen_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { struct netxen_adapter *adapter; struct net_device *dev = (struct net_device *)ptr; - struct in_device *indev; recheck: if (dev == NULL) @@ -2303,32 +2339,13 @@ recheck: adapter = netdev_priv(dev); - if (!adapter || !netxen_destip_supported(adapter)) + if (!adapter) goto done; if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) goto done; - indev = in_dev_get(dev); - if (!indev) - goto done; - - for_ifa(indev) { - switch (event) { - case NETDEV_UP: - netxen_config_ipaddr(adapter, - ifa->ifa_address, NX_IP_UP); - break; - case NETDEV_DOWN: - netxen_config_ipaddr(adapter, - ifa->ifa_address, NX_IP_DOWN); - break; - default: - break; - } - } endfor_ifa(indev); - - in_dev_put(indev); + netxen_config_indev_addr(dev, event); done: return NOTIFY_DONE; } -- cgit v1.2.3-18-g5258 From 195c5f9829407857cba86f083caec6302b1fd8e1 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Sat, 5 Sep 2009 17:43:10 +0000 Subject: netxen: pre calculate register addresses For registers accessed in fast path (interrupt / softirq) avoid expensive I/O address translation. These registers are directly mapped in PCI bar 0 and do not require any window checks. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 75 +++++--------- drivers/net/netxen/netxen_nic_ctx.c | 21 ++-- drivers/net/netxen/netxen_nic_ethtool.c | 5 +- drivers/net/netxen/netxen_nic_hw.c | 176 ++++++++++++++++++++++---------- drivers/net/netxen/netxen_nic_init.c | 34 ++---- drivers/net/netxen/netxen_nic_main.c | 90 ++++++++-------- 6 files changed, 210 insertions(+), 191 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 30a38163b23..5bbc40be9de 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -584,11 +584,11 @@ struct netxen_adapter_stats { */ struct nx_host_rds_ring { u32 producer; - u32 crb_rcv_producer; u32 num_desc; u32 dma_size; u32 skb_size; u32 flags; + void __iomem *crb_rcv_producer; struct rcv_desc *desc_head; struct netxen_rx_buffer *rx_buf_arr; struct list_head free_list; @@ -598,9 +598,9 @@ struct nx_host_rds_ring { struct nx_host_sds_ring { u32 consumer; - u32 crb_sts_consumer; - u32 crb_intr_mask; u32 num_desc; + void __iomem *crb_sts_consumer; + void __iomem *crb_intr_mask; struct status_desc *desc_head; struct netxen_adapter *adapter; @@ -617,8 +617,8 @@ struct nx_host_tx_ring { u32 producer; __le32 *hw_consumer; u32 sw_consumer; - u32 crb_cmd_producer; - u32 crb_cmd_consumer; + void __iomem *crb_cmd_producer; + void __iomem *crb_cmd_consumer; u32 num_desc; struct netdev_queue *txq; @@ -1163,7 +1163,7 @@ struct netxen_adapter { u32 irq; u32 temp; - u32 msi_tgt_status; + u32 int_vec_bit; u32 heartbit; struct netxen_adapter_stats stats; @@ -1180,16 +1180,23 @@ struct netxen_adapter { int (*init_port) (struct netxen_adapter *, int); int (*stop_port) (struct netxen_adapter *); - u32 (*hw_read_wx)(struct netxen_adapter *, ulong); - int (*hw_write_wx)(struct netxen_adapter *, ulong, u32); + u32 (*crb_read)(struct netxen_adapter *, ulong); + int (*crb_write)(struct netxen_adapter *, ulong, u32); + int (*pci_mem_read)(struct netxen_adapter *, u64, void *, int); int (*pci_mem_write)(struct netxen_adapter *, u64, void *, int); - int (*pci_write_immediate)(struct netxen_adapter *, u64, u32); - u32 (*pci_read_immediate)(struct netxen_adapter *, u64); + unsigned long (*pci_set_window)(struct netxen_adapter *, unsigned long long); - struct netxen_legacy_intr_set legacy_intr; + u32 (*io_read)(struct netxen_adapter *, void __iomem *); + void (*io_write)(struct netxen_adapter *, void __iomem *, u32); + + void __iomem *tgt_mask_reg; + void __iomem *pci_int_reg; + void __iomem *tgt_status_reg; + void __iomem *crb_int_state_reg; + void __iomem *isr_int_vec; struct msix_entry msix_entries[MSIX_ENTRIES_PER_ADAPTER]; @@ -1223,9 +1230,13 @@ int netxen_p2_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr); int netxen_p3_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr); #define NXRD32(adapter, off) \ - (adapter->hw_read_wx(adapter, off)) + (adapter->crb_read(adapter, off)) #define NXWR32(adapter, off, val) \ - (adapter->hw_write_wx(adapter, off, val)) + (adapter->crb_write(adapter, off, val)) +#define NXRDIO(adapter, addr) \ + (adapter->io_read(adapter, addr)) +#define NXWRIO(adapter, addr, val) \ + (adapter->io_write(adapter, addr, val)) int netxen_pcie_sem_lock(struct netxen_adapter *, int, u32); void netxen_pcie_sem_unlock(struct netxen_adapter *, int); @@ -1255,40 +1266,6 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter); void netxen_nic_get_firmware_info(struct netxen_adapter *adapter); int netxen_nic_wol_supported(struct netxen_adapter *adapter); -u32 netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter, ulong off); -int netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter, - ulong off, u32 data); -int netxen_nic_pci_mem_read_128M(struct netxen_adapter *adapter, - u64 off, void *data, int size); -int netxen_nic_pci_mem_write_128M(struct netxen_adapter *adapter, - u64 off, void *data, int size); -int netxen_nic_pci_write_immediate_128M(struct netxen_adapter *adapter, - u64 off, u32 data); -u32 netxen_nic_pci_read_immediate_128M(struct netxen_adapter *adapter, u64 off); -void netxen_nic_pci_write_normalize_128M(struct netxen_adapter *adapter, - u64 off, u32 data); -u32 netxen_nic_pci_read_normalize_128M(struct netxen_adapter *adapter, u64 off); -unsigned long netxen_nic_pci_set_window_128M(struct netxen_adapter *adapter, - unsigned long long addr); -void netxen_nic_pci_change_crbwindow_128M(struct netxen_adapter *adapter, - u32 wndw); - -u32 netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter, ulong off); -int netxen_nic_hw_write_wx_2M(struct netxen_adapter *adapter, - ulong off, u32 data); -int netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, - u64 off, void *data, int size); -int netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter, - u64 off, void *data, int size); -int netxen_nic_pci_write_immediate_2M(struct netxen_adapter *adapter, - u64 off, u32 data); -u32 netxen_nic_pci_read_immediate_2M(struct netxen_adapter *adapter, u64 off); -void netxen_nic_pci_write_normalize_2M(struct netxen_adapter *adapter, - u64 off, u32 data); -u32 netxen_nic_pci_read_normalize_2M(struct netxen_adapter *adapter, u64 off); -unsigned long netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, - unsigned long long addr); - /* Functions from netxen_nic_init.c */ int netxen_init_dummy_dma(struct netxen_adapter *adapter); void netxen_free_dummy_dma(struct netxen_adapter *adapter); @@ -1316,13 +1293,15 @@ int netxen_rom_se(struct netxen_adapter *adapter, int addr); int netxen_alloc_sw_resources(struct netxen_adapter *adapter); void netxen_free_sw_resources(struct netxen_adapter *adapter); +void netxen_setup_hwops(struct netxen_adapter *adapter); +void __iomem *netxen_get_ioaddr(struct netxen_adapter *, u32); + int netxen_alloc_hw_resources(struct netxen_adapter *adapter); void netxen_free_hw_resources(struct netxen_adapter *adapter); void netxen_release_rx_buffers(struct netxen_adapter *adapter); void netxen_release_tx_buffers(struct netxen_adapter *adapter); -void netxen_initialize_adapter_ops(struct netxen_adapter *adapter); int netxen_init_firmware(struct netxen_adapter *adapter); void netxen_nic_clear_stats(struct netxen_adapter *adapter); void netxen_watchdog_task(struct work_struct *work); diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 8ab5773e47d..33f82db0129 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -229,7 +229,8 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter) rds_ring = &recv_ctx->rds_rings[i]; reg = le32_to_cpu(prsp_rds[i].host_producer_crb); - rds_ring->crb_rcv_producer = NETXEN_NIC_REG(reg - 0x200); + rds_ring->crb_rcv_producer = netxen_get_ioaddr(adapter, + NETXEN_NIC_REG(reg - 0x200)); } prsp_sds = ((nx_cardrsp_sds_ring_t *) @@ -239,10 +240,12 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter) sds_ring = &recv_ctx->sds_rings[i]; reg = le32_to_cpu(prsp_sds[i].host_consumer_crb); - sds_ring->crb_sts_consumer = NETXEN_NIC_REG(reg - 0x200); + sds_ring->crb_sts_consumer = netxen_get_ioaddr(adapter, + NETXEN_NIC_REG(reg - 0x200)); reg = le32_to_cpu(prsp_sds[i].interrupt_crb); - sds_ring->crb_intr_mask = NETXEN_NIC_REG(reg - 0x200); + sds_ring->crb_intr_mask = netxen_get_ioaddr(adapter, + NETXEN_NIC_REG(reg - 0x200)); } recv_ctx->state = le32_to_cpu(prsp->host_ctx_state); @@ -342,7 +345,8 @@ nx_fw_cmd_create_tx_ctx(struct netxen_adapter *adapter) if (err == NX_RCODE_SUCCESS) { temp = le32_to_cpu(prsp->cds_ring.host_producer_crb); - tx_ring->crb_cmd_producer = NETXEN_NIC_REG(temp - 0x200); + tx_ring->crb_cmd_producer = netxen_get_ioaddr(adapter, + NETXEN_NIC_REG(temp - 0x200)); #if 0 adapter->tx_state = le32_to_cpu(prsp->host_ctx_state); @@ -651,7 +655,8 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) rds_ring->crb_rcv_producer = - recv_crb_registers[port].crb_rcv_producer[ring]; + netxen_get_ioaddr(adapter, + recv_crb_registers[port].crb_rcv_producer[ring]); } for (ring = 0; ring < adapter->max_sds_rings; ring++) { @@ -670,10 +675,12 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) sds_ring->desc_head = (struct status_desc *)addr; sds_ring->crb_sts_consumer = - recv_crb_registers[port].crb_sts_consumer[ring]; + netxen_get_ioaddr(adapter, + recv_crb_registers[port].crb_sts_consumer[ring]); sds_ring->crb_intr_mask = - recv_crb_registers[port].sw_int_mask[ring]; + netxen_get_ioaddr(adapter, + recv_crb_registers[port].sw_int_mask[ring]); } diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index e376a1c4eb0..d18832ce4b5 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -84,18 +84,17 @@ static void netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) { struct netxen_adapter *adapter = netdev_priv(dev); - unsigned long flags; u32 fw_major = 0; u32 fw_minor = 0; u32 fw_build = 0; strncpy(drvinfo->driver, netxen_nic_driver_name, 32); strncpy(drvinfo->version, NETXEN_NIC_LINUX_VERSIONID, 32); - write_lock_irqsave(&adapter->adapter_lock, flags); + read_lock(&adapter->adapter_lock); fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR); fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR); fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB); - write_unlock_irqrestore(&adapter->adapter_lock, flags); + read_unlock(&adapter->adapter_lock); sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build); strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index d0ac8fabd42..cbfd6102e45 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -1050,7 +1050,7 @@ int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, __le64 *mac) /* * Changes the CRB window to the specified window. */ -void +static void netxen_nic_pci_change_crbwindow_128M(struct netxen_adapter *adapter, u32 wndw) { void __iomem *offset; @@ -1163,61 +1163,68 @@ netxen_nic_pci_set_crbwindow_2M(struct netxen_adapter *adapter, ulong *off) (ulong)adapter->ahw.pci_base0; } -int +static int netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter, ulong off, u32 data) { + unsigned long flags; void __iomem *addr; - if (ADDR_IN_WINDOW1(off)) { + if (ADDR_IN_WINDOW1(off)) addr = NETXEN_CRB_NORMALIZE(adapter, off); + else + addr = pci_base_offset(adapter, off); + + BUG_ON(!addr); + + if (ADDR_IN_WINDOW1(off)) { /* Window 1 */ + read_lock(&adapter->adapter_lock); + writel(data, addr); + read_unlock(&adapter->adapter_lock); } else { /* Window 0 */ + write_lock_irqsave(&adapter->adapter_lock, flags); addr = pci_base_offset(adapter, off); netxen_nic_pci_change_crbwindow_128M(adapter, 0); - } - - if (!addr) { + writel(data, addr); netxen_nic_pci_change_crbwindow_128M(adapter, 1); - return 1; + write_unlock_irqrestore(&adapter->adapter_lock, flags); } - writel(data, addr); - - if (!ADDR_IN_WINDOW1(off)) - netxen_nic_pci_change_crbwindow_128M(adapter, 1); - return 0; } -u32 +static u32 netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter, ulong off) { + unsigned long flags; void __iomem *addr; u32 data; - if (ADDR_IN_WINDOW1(off)) { /* Window 1 */ + if (ADDR_IN_WINDOW1(off)) addr = NETXEN_CRB_NORMALIZE(adapter, off); - } else { /* Window 0 */ + else addr = pci_base_offset(adapter, off); - netxen_nic_pci_change_crbwindow_128M(adapter, 0); - } - - if (!addr) { - netxen_nic_pci_change_crbwindow_128M(adapter, 1); - return 1; - } - data = readl(addr); + BUG_ON(!addr); - if (!ADDR_IN_WINDOW1(off)) + if (ADDR_IN_WINDOW1(off)) { /* Window 1 */ + read_lock(&adapter->adapter_lock); + data = readl(addr); + read_unlock(&adapter->adapter_lock); + } else { /* Window 0 */ + write_lock_irqsave(&adapter->adapter_lock, flags); + netxen_nic_pci_change_crbwindow_128M(adapter, 0); + data = readl(addr); netxen_nic_pci_change_crbwindow_128M(adapter, 1); + write_unlock_irqrestore(&adapter->adapter_lock, flags); + } return data; } -int +static int netxen_nic_hw_write_wx_2M(struct netxen_adapter *adapter, ulong off, u32 data) { - unsigned long flags = 0; + unsigned long flags; int rv; rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off); @@ -1243,10 +1250,10 @@ netxen_nic_hw_write_wx_2M(struct netxen_adapter *adapter, ulong off, u32 data) return 0; } -u32 +static u32 netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter, ulong off) { - unsigned long flags = 0; + unsigned long flags; int rv; u32 data; @@ -1293,7 +1300,7 @@ netxen_nic_pci_mem_bound_check(struct netxen_adapter *adapter, static int netxen_pci_set_window_warning_count; -unsigned long +static unsigned long netxen_nic_pci_set_window_128M(struct netxen_adapter *adapter, unsigned long long addr) { @@ -1357,22 +1364,56 @@ netxen_nic_pci_set_window_128M(struct netxen_adapter *adapter, return addr; } -/* - * Note : only 32-bit writes! - */ -int netxen_nic_pci_write_immediate_128M(struct netxen_adapter *adapter, - u64 off, u32 data) +/* window 1 registers only */ +static void netxen_nic_io_write_128M(struct netxen_adapter *adapter, + void __iomem *addr, u32 data) { - writel(data, (void __iomem *)(PCI_OFFSET_SECOND_RANGE(adapter, off))); - return 0; + read_lock(&adapter->adapter_lock); + writel(data, addr); + read_unlock(&adapter->adapter_lock); +} + +static u32 netxen_nic_io_read_128M(struct netxen_adapter *adapter, + void __iomem *addr) +{ + u32 val; + + read_lock(&adapter->adapter_lock); + val = readl(addr); + read_unlock(&adapter->adapter_lock); + + return val; } -u32 netxen_nic_pci_read_immediate_128M(struct netxen_adapter *adapter, u64 off) +static void netxen_nic_io_write_2M(struct netxen_adapter *adapter, + void __iomem *addr, u32 data) { - return readl((void __iomem *)(pci_base_offset(adapter, off))); + writel(data, addr); +} + +static u32 netxen_nic_io_read_2M(struct netxen_adapter *adapter, + void __iomem *addr) +{ + return readl(addr); +} + +void __iomem * +netxen_get_ioaddr(struct netxen_adapter *adapter, u32 offset) +{ + ulong off = offset; + + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + if (offset < NETXEN_CRB_PCIX_HOST2 && + offset > NETXEN_CRB_PCIX_HOST) + return PCI_OFFSET_SECOND_RANGE(adapter, offset); + return NETXEN_CRB_NORMALIZE(adapter, offset); + } + + BUG_ON(netxen_nic_pci_get_crb_addr_2M(adapter, &off)); + return (void __iomem *)off; } -unsigned long +static unsigned long netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, unsigned long long addr) { @@ -1616,7 +1657,7 @@ netxen_nic_pci_mem_write_direct(struct netxen_adapter *adapter, u64 off, #define MAX_CTL_CHECK 1000 -int +static int netxen_nic_pci_mem_write_128M(struct netxen_adapter *adapter, u64 off, void *data, int size) { @@ -1709,7 +1750,7 @@ netxen_nic_pci_mem_write_128M(struct netxen_adapter *adapter, return ret; } -int +static int netxen_nic_pci_mem_read_128M(struct netxen_adapter *adapter, u64 off, void *data, int size) { @@ -1800,7 +1841,7 @@ netxen_nic_pci_mem_read_128M(struct netxen_adapter *adapter, return 0; } -int +static int netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter, u64 off, void *data, int size) { @@ -1828,8 +1869,8 @@ netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter, if ((size != 8) || (off0 != 0)) { for (i = 0; i < loop; i++) { - if (adapter->pci_mem_read(adapter, off8 + (i << 3), - &word[i], 8)) + if (adapter->pci_mem_read(adapter, + off8 + (i << 3), &word[i], 8)) return -1; } } @@ -1900,7 +1941,7 @@ netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter, return ret; } -int +static int netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, u64 off, void *data, int size) { @@ -1998,20 +2039,43 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, return 0; } -/* - * Note : only 32-bit writes! - */ -int netxen_nic_pci_write_immediate_2M(struct netxen_adapter *adapter, - u64 off, u32 data) +void +netxen_setup_hwops(struct netxen_adapter *adapter) { - NXWR32(adapter, off, data); + adapter->init_port = netxen_niu_xg_init_port; + adapter->stop_port = netxen_niu_disable_xg_port; - return 0; -} + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + adapter->crb_read = netxen_nic_hw_read_wx_128M, + adapter->crb_write = netxen_nic_hw_write_wx_128M, + adapter->pci_set_window = netxen_nic_pci_set_window_128M, + adapter->pci_mem_read = netxen_nic_pci_mem_read_128M, + adapter->pci_mem_write = netxen_nic_pci_mem_write_128M, + adapter->io_read = netxen_nic_io_read_128M, + adapter->io_write = netxen_nic_io_write_128M, + + adapter->macaddr_set = netxen_p2_nic_set_mac_addr; + adapter->set_multi = netxen_p2_nic_set_multi; + adapter->set_mtu = netxen_nic_set_mtu_xgb; + adapter->set_promisc = netxen_p2_nic_set_promisc; -u32 netxen_nic_pci_read_immediate_2M(struct netxen_adapter *adapter, u64 off) -{ - return NXRD32(adapter, off); + } else { + adapter->crb_read = netxen_nic_hw_read_wx_2M, + adapter->crb_write = netxen_nic_hw_write_wx_2M, + adapter->pci_set_window = netxen_nic_pci_set_window_2M, + adapter->pci_mem_read = netxen_nic_pci_mem_read_2M, + adapter->pci_mem_write = netxen_nic_pci_mem_write_2M, + adapter->io_read = netxen_nic_io_read_2M, + adapter->io_write = netxen_nic_io_write_2M, + + adapter->set_mtu = nx_fw_cmd_set_mtu; + adapter->set_promisc = netxen_p3_nic_set_promisc; + adapter->macaddr_set = netxen_p3_nic_set_mac_addr; + adapter->set_multi = netxen_p3_nic_set_multi; + + adapter->phy_read = nx_fw_cmd_query_phy; + adapter->phy_write = nx_fw_cmd_set_phy; + } } int netxen_nic_get_board_info(struct netxen_adapter *adapter) diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 534994dc167..485b947932a 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -323,29 +323,6 @@ err_out: return -ENOMEM; } -void netxen_initialize_adapter_ops(struct netxen_adapter *adapter) -{ - adapter->init_port = netxen_niu_xg_init_port; - adapter->stop_port = netxen_niu_disable_xg_port; - - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { - adapter->macaddr_set = netxen_p2_nic_set_mac_addr; - adapter->set_multi = netxen_p2_nic_set_multi; - adapter->set_mtu = netxen_nic_set_mtu_xgb; - adapter->set_promisc = netxen_p2_nic_set_promisc; - } else { - adapter->set_mtu = nx_fw_cmd_set_mtu; - adapter->set_promisc = netxen_p3_nic_set_promisc; - adapter->macaddr_set = netxen_p3_nic_set_mac_addr; - adapter->set_multi = netxen_p3_nic_set_multi; - - if (adapter->ahw.port_type == NETXEN_NIC_GBE) { - adapter->phy_read = nx_fw_cmd_query_phy; - adapter->phy_write = nx_fw_cmd_set_phy; - } - } -} - /* * netxen_decode_crb_addr(0 - utility to translate from internal Phantom CRB * address to external PCI CRB address. @@ -1395,7 +1372,7 @@ skip: if (count) { sds_ring->consumer = consumer; - NXWR32(adapter, sds_ring->crb_sts_consumer, consumer); + NXWRIO(adapter, sds_ring->crb_sts_consumer, consumer); } return count; @@ -1513,7 +1490,7 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid, if (count) { rds_ring->producer = producer; - NXWR32(adapter, rds_ring->crb_rcv_producer, + NXWRIO(adapter, rds_ring->crb_rcv_producer, (producer-1) & (rds_ring->num_desc-1)); if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { @@ -1529,9 +1506,10 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid, (rds_ring->num_desc - 1))); netxen_set_msg_ctxid(msg, adapter->portnum); netxen_set_msg_opcode(msg, NETXEN_RCV_PRODUCER(ringid)); - writel(msg, - DB_NORMALIZE(adapter, + read_lock(&adapter->adapter_lock); + writel(msg, DB_NORMALIZE(adapter, NETXEN_RCV_PRODUCER_OFFSET)); + read_unlock(&adapter->adapter_lock); } } } @@ -1573,7 +1551,7 @@ netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, if (count) { rds_ring->producer = producer; - NXWR32(adapter, rds_ring->crb_rcv_producer, + NXWRIO(adapter, rds_ring->crb_rcv_producer, (producer - 1) & (rds_ring->num_desc - 1)); } spin_unlock(&rds_ring->lock); diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 7038e1baaf4..b2fd7132bc3 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -116,7 +116,7 @@ void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter, struct nx_host_tx_ring *tx_ring) { - NXWR32(adapter, tx_ring->crb_cmd_producer, tx_ring->producer); + NXWRIO(adapter, tx_ring->crb_cmd_producer, tx_ring->producer); if (netxen_tx_avail(tx_ring) <= TX_STOP_THRESH) { netif_stop_queue(adapter->netdev); @@ -133,7 +133,7 @@ static inline void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter, struct nx_host_tx_ring *tx_ring) { - NXWR32(adapter, tx_ring->crb_cmd_consumer, tx_ring->sw_consumer); + NXWRIO(adapter, tx_ring->crb_cmd_consumer, tx_ring->sw_consumer); } static uint32_t msi_tgt_status[8] = { @@ -149,18 +149,17 @@ static inline void netxen_nic_disable_int(struct nx_host_sds_ring *sds_ring) { struct netxen_adapter *adapter = sds_ring->adapter; - NXWR32(adapter, sds_ring->crb_intr_mask, 0); + NXWRIO(adapter, sds_ring->crb_intr_mask, 0); } static inline void netxen_nic_enable_int(struct nx_host_sds_ring *sds_ring) { struct netxen_adapter *adapter = sds_ring->adapter; - NXWR32(adapter, sds_ring->crb_intr_mask, 0x1); + NXWRIO(adapter, sds_ring->crb_intr_mask, 0x1); if (!NETXEN_IS_MSI_FAMILY(adapter)) - adapter->pci_write_immediate(adapter, - adapter->legacy_intr.tgt_mask_reg, 0xfbff); + NXWRIO(adapter, adapter->tgt_mask_reg, 0xfbff); } static int @@ -556,10 +555,22 @@ netxen_setup_intr(struct netxen_adapter *adapter) legacy_intrp = &legacy_intr[adapter->ahw.pci_func]; else legacy_intrp = &legacy_intr[0]; - adapter->legacy_intr.int_vec_bit = legacy_intrp->int_vec_bit; - adapter->legacy_intr.tgt_status_reg = legacy_intrp->tgt_status_reg; - adapter->legacy_intr.tgt_mask_reg = legacy_intrp->tgt_mask_reg; - adapter->legacy_intr.pci_int_reg = legacy_intrp->pci_int_reg; + + adapter->int_vec_bit = legacy_intrp->int_vec_bit; + adapter->tgt_status_reg = netxen_get_ioaddr(adapter, + legacy_intrp->tgt_status_reg); + adapter->tgt_mask_reg = netxen_get_ioaddr(adapter, + legacy_intrp->tgt_mask_reg); + adapter->pci_int_reg = netxen_get_ioaddr(adapter, + legacy_intrp->pci_int_reg); + adapter->isr_int_vec = netxen_get_ioaddr(adapter, ISR_INT_VECTOR); + + if (adapter->ahw.revision_id >= NX_P3_B1) + adapter->crb_int_state_reg = netxen_get_ioaddr(adapter, + ISR_INT_STATE_REG); + else + adapter->crb_int_state_reg = netxen_get_ioaddr(adapter, + CRB_INT_VECTOR); netxen_set_msix_bit(pdev, 0); @@ -586,8 +597,8 @@ netxen_setup_intr(struct netxen_adapter *adapter) if (use_msi && !pci_enable_msi(pdev)) { adapter->flags |= NETXEN_NIC_MSI_ENABLED; - adapter->msi_tgt_status = - msi_tgt_status[adapter->ahw.pci_func]; + adapter->tgt_status_reg = netxen_get_ioaddr(adapter, + msi_tgt_status[adapter->ahw.pci_func]); dev_info(&pdev->dev, "using msi interrupts\n"); adapter->msix_entries[0].vector = pdev->irq; return; @@ -647,14 +658,6 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) mem_len = pci_resource_len(pdev, 0); pci_len0 = 0; - adapter->hw_write_wx = netxen_nic_hw_write_wx_128M; - adapter->hw_read_wx = netxen_nic_hw_read_wx_128M; - adapter->pci_read_immediate = netxen_nic_pci_read_immediate_128M; - adapter->pci_write_immediate = netxen_nic_pci_write_immediate_128M; - adapter->pci_set_window = netxen_nic_pci_set_window_128M; - adapter->pci_mem_read = netxen_nic_pci_mem_read_128M; - adapter->pci_mem_write = netxen_nic_pci_mem_write_128M; - /* 128 Meg of memory */ if (mem_len == NETXEN_PCI_128MB_SIZE) { mem_ptr0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE); @@ -667,14 +670,6 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START - SECOND_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE); } else if (mem_len == NETXEN_PCI_2MB_SIZE) { - adapter->hw_write_wx = netxen_nic_hw_write_wx_2M; - adapter->hw_read_wx = netxen_nic_hw_read_wx_2M; - adapter->pci_read_immediate = netxen_nic_pci_read_immediate_2M; - adapter->pci_write_immediate = - netxen_nic_pci_write_immediate_2M; - adapter->pci_set_window = netxen_nic_pci_set_window_2M; - adapter->pci_mem_read = netxen_nic_pci_mem_read_2M; - adapter->pci_mem_write = netxen_nic_pci_mem_write_2M; mem_ptr0 = pci_ioremap_bar(pdev, 0); if (mem_ptr0 == NULL) { @@ -698,6 +693,8 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) return -EIO; } + netxen_setup_hwops(adapter); + dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20)); adapter->ahw.pci_base0 = mem_ptr0; @@ -990,8 +987,10 @@ netxen_nic_attach(struct netxen_adapter *adapter) if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { tx_ring = adapter->tx_ring; - tx_ring->crb_cmd_producer = crb_cmd_producer[adapter->portnum]; - tx_ring->crb_cmd_consumer = crb_cmd_consumer[adapter->portnum]; + tx_ring->crb_cmd_producer = netxen_get_ioaddr(adapter, + crb_cmd_producer[adapter->portnum]); + tx_ring->crb_cmd_consumer = netxen_get_ioaddr(adapter, + crb_cmd_consumer[adapter->portnum]); tx_ring->producer = 0; tx_ring->sw_consumer = 0; @@ -1213,8 +1212,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_iounmap; } - netxen_initialize_adapter_ops(adapter); - /* Mezz cards have PCI function 0,2,3 enabled */ switch (adapter->ahw.board_type) { case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ: @@ -1870,41 +1867,37 @@ static irqreturn_t netxen_intr(int irq, void *data) struct netxen_adapter *adapter = sds_ring->adapter; u32 status = 0; - status = adapter->pci_read_immediate(adapter, ISR_INT_VECTOR); + status = readl(adapter->isr_int_vec); - if (!(status & adapter->legacy_intr.int_vec_bit)) + if (!(status & adapter->int_vec_bit)) return IRQ_NONE; - if (adapter->ahw.revision_id >= NX_P3_B1) { + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { /* check interrupt state machine, to be sure */ - status = adapter->pci_read_immediate(adapter, - ISR_INT_STATE_REG); + status = readl(adapter->crb_int_state_reg); if (!ISR_LEGACY_INT_TRIGGERED(status)) return IRQ_NONE; } else { unsigned long our_int = 0; - our_int = NXRD32(adapter, CRB_INT_VECTOR); + our_int = readl(adapter->crb_int_state_reg); /* not our interrupt */ if (!test_and_clear_bit((7 + adapter->portnum), &our_int)) return IRQ_NONE; /* claim interrupt */ - NXWR32(adapter, CRB_INT_VECTOR, (our_int & 0xffffffff)); - } + writel((our_int & 0xffffffff), adapter->crb_int_state_reg); - /* clear interrupt */ - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) + /* clear interrupt */ netxen_nic_disable_int(sds_ring); + } - adapter->pci_write_immediate(adapter, - adapter->legacy_intr.tgt_status_reg, - 0xffffffff); + writel(0xffffffff, adapter->tgt_status_reg); /* read twice to ensure write is flushed */ - adapter->pci_read_immediate(adapter, ISR_INT_VECTOR); - adapter->pci_read_immediate(adapter, ISR_INT_VECTOR); + readl(adapter->isr_int_vec); + readl(adapter->isr_int_vec); napi_schedule(&sds_ring->napi); @@ -1917,8 +1910,7 @@ static irqreturn_t netxen_msi_intr(int irq, void *data) struct netxen_adapter *adapter = sds_ring->adapter; /* clear interrupt */ - adapter->pci_write_immediate(adapter, - adapter->msi_tgt_status, 0xffffffff); + writel(0xffffffff, adapter->tgt_status_reg); napi_schedule(&sds_ring->napi); return IRQ_HANDLED; -- cgit v1.2.3-18-g5258 From 2b9e62ee7b2f1971c01fdaa7653c9dae7b571187 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sat, 5 Sep 2009 17:43:11 +0000 Subject: netxen: refactor firmware info code o Combine netxen_get_firmware_info(), netxen_check_options() so that they are updated every time firmware is reset. o Set dma mask everytime firmware is reset. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 1 - drivers/net/netxen/netxen_nic_hw.c | 59 --------------- drivers/net/netxen/netxen_nic_main.c | 141 ++++++++++++++++++++++++----------- 3 files changed, 98 insertions(+), 103 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 5bbc40be9de..df03ea4500d 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1263,7 +1263,6 @@ void netxen_pcie_sem_unlock(struct netxen_adapter *, int); netxen_pcie_sem_unlock((a), 7) int netxen_nic_get_board_info(struct netxen_adapter *adapter); -void netxen_nic_get_firmware_info(struct netxen_adapter *adapter); int netxen_nic_wol_supported(struct netxen_adapter *adapter); /* Functions from netxen_nic_init.c */ diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index cbfd6102e45..555bc4a7e88 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -2240,65 +2240,6 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter) } } -void netxen_nic_get_firmware_info(struct netxen_adapter *adapter) -{ - u32 fw_major, fw_minor, fw_build; - char brd_name[NETXEN_MAX_SHORT_NAME]; - char serial_num[32]; - int i, offset, val; - int *ptr32; - struct pci_dev *pdev = adapter->pdev; - - adapter->driver_mismatch = 0; - - ptr32 = (int *)&serial_num; - offset = NX_FW_SERIAL_NUM_OFFSET; - for (i = 0; i < 8; i++) { - if (netxen_rom_fast_read(adapter, offset, &val) == -1) { - dev_err(&pdev->dev, "error reading board info\n"); - adapter->driver_mismatch = 1; - return; - } - ptr32[i] = cpu_to_le32(val); - offset += sizeof(u32); - } - - fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR); - fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR); - fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB); - - adapter->fw_version = NETXEN_VERSION_CODE(fw_major, fw_minor, fw_build); - - if (adapter->portnum == 0) { - get_brd_name_by_type(adapter->ahw.board_type, brd_name); - - printk(KERN_INFO "NetXen %s Board S/N %s Chip rev 0x%x\n", - brd_name, serial_num, adapter->ahw.revision_id); - } - - if (adapter->fw_version < NETXEN_VERSION_CODE(3, 4, 216)) { - adapter->driver_mismatch = 1; - dev_warn(&pdev->dev, "firmware version %d.%d.%d unsupported\n", - fw_major, fw_minor, fw_build); - return; - } - - dev_info(&pdev->dev, "firmware version %d.%d.%d\n", - fw_major, fw_minor, fw_build); - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { - i = NXRD32(adapter, NETXEN_SRE_MISC); - adapter->ahw.cut_through = (i & 0x8000) ? 1 : 0; - dev_info(&pdev->dev, "firmware running in %s mode\n", - adapter->ahw.cut_through ? "cut-through" : "legacy"); - } - - if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222)) - adapter->capabilities = NXRD32(adapter, CRB_FW_CAPABILITIES_1); - - adapter->flags &= ~NETXEN_NIC_LRO_ENABLED; -} - int netxen_nic_wol_supported(struct netxen_adapter *adapter) { diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index b2fd7132bc3..304618aa09d 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -318,44 +318,6 @@ err_out: return err; } -static void -netxen_check_options(struct netxen_adapter *adapter) -{ - if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { - adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G; - adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G; - } else if (adapter->ahw.port_type == NETXEN_NIC_GBE) { - adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G; - adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G; - } - - adapter->msix_supported = 0; - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { - adapter->msix_supported = !!use_msi_x; - adapter->rss_supported = !!use_msi_x; - } else if (adapter->fw_version >= NETXEN_VERSION_CODE(3, 4, 336)) { - switch (adapter->ahw.board_type) { - case NETXEN_BRDTYPE_P2_SB31_10G: - case NETXEN_BRDTYPE_P2_SB31_10G_CX4: - adapter->msix_supported = !!use_msi_x; - adapter->rss_supported = !!use_msi_x; - break; - default: - break; - } - } - - adapter->num_txd = MAX_CMD_DESCRIPTORS; - - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { - adapter->num_lro_rxd = MAX_LRO_RCV_DESCRIPTORS; - adapter->max_rds_rings = 3; - } else { - adapter->num_lro_rxd = 0; - adapter->max_rds_rings = 2; - } -} - static int netxen_check_hw_init(struct netxen_adapter *adapter, int first_boot) { @@ -733,12 +695,110 @@ err_out: return err; } +static void +netxen_check_options(struct netxen_adapter *adapter) +{ + u32 fw_major, fw_minor, fw_build; + char brd_name[NETXEN_MAX_SHORT_NAME]; + char serial_num[32]; + int i, offset, val; + int *ptr32; + struct pci_dev *pdev = adapter->pdev; + + adapter->driver_mismatch = 0; + + ptr32 = (int *)&serial_num; + offset = NX_FW_SERIAL_NUM_OFFSET; + for (i = 0; i < 8; i++) { + if (netxen_rom_fast_read(adapter, offset, &val) == -1) { + dev_err(&pdev->dev, "error reading board info\n"); + adapter->driver_mismatch = 1; + return; + } + ptr32[i] = cpu_to_le32(val); + offset += sizeof(u32); + } + + fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR); + fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR); + fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB); + + adapter->fw_version = NETXEN_VERSION_CODE(fw_major, fw_minor, fw_build); + + if (adapter->portnum == 0) { + get_brd_name_by_type(adapter->ahw.board_type, brd_name); + + printk(KERN_INFO "NetXen %s Board S/N %s Chip rev 0x%x\n", + brd_name, serial_num, adapter->ahw.revision_id); + } + + if (adapter->fw_version < NETXEN_VERSION_CODE(3, 4, 216)) { + adapter->driver_mismatch = 1; + dev_warn(&pdev->dev, "firmware version %d.%d.%d unsupported\n", + fw_major, fw_minor, fw_build); + return; + } + + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { + i = NXRD32(adapter, NETXEN_SRE_MISC); + adapter->ahw.cut_through = (i & 0x8000) ? 1 : 0; + } + + dev_info(&pdev->dev, "firmware v%d.%d.%d [%s]\n", + fw_major, fw_minor, fw_build, + adapter->ahw.cut_through ? "cut-through" : "legacy"); + + if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222)) + adapter->capabilities = NXRD32(adapter, CRB_FW_CAPABILITIES_1); + + adapter->flags &= ~NETXEN_NIC_LRO_ENABLED; + + if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { + adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G; + adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G; + } else if (adapter->ahw.port_type == NETXEN_NIC_GBE) { + adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G; + adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G; + } + + adapter->msix_supported = 0; + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { + adapter->msix_supported = !!use_msi_x; + adapter->rss_supported = !!use_msi_x; + } else if (adapter->fw_version >= NETXEN_VERSION_CODE(3, 4, 336)) { + switch (adapter->ahw.board_type) { + case NETXEN_BRDTYPE_P2_SB31_10G: + case NETXEN_BRDTYPE_P2_SB31_10G_CX4: + adapter->msix_supported = !!use_msi_x; + adapter->rss_supported = !!use_msi_x; + break; + default: + break; + } + } + + adapter->num_txd = MAX_CMD_DESCRIPTORS; + + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + adapter->num_lro_rxd = MAX_LRO_RCV_DESCRIPTORS; + adapter->max_rds_rings = 3; + } else { + adapter->num_lro_rxd = 0; + adapter->max_rds_rings = 2; + } +} + static int netxen_start_firmware(struct netxen_adapter *adapter) { int val, err, first_boot; struct pci_dev *pdev = adapter->pdev; + /* required for NX2031 dummy dma */ + err = nx_set_dma_mask(adapter); + if (err) + return err; + if (!netxen_can_start_firmware(adapter)) goto wait_init; @@ -811,7 +871,6 @@ wait_init: nx_update_dma_mask(adapter); - netxen_nic_get_firmware_info(adapter); netxen_check_options(adapter); return 0; @@ -1191,10 +1250,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) revision_id = pdev->revision; adapter->ahw.revision_id = revision_id; - err = nx_set_dma_mask(adapter); - if (err) - goto err_out_free_netdev; - rwlock_init(&adapter->adapter_lock); spin_lock_init(&adapter->tx_clean_lock); INIT_LIST_HEAD(&adapter->mac_list); -- cgit v1.2.3-18-g5258 From 5877e55f32bb50956c9a1df8e7db3fbc67dc47b6 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Sat, 5 Sep 2009 17:43:12 +0000 Subject: netxen: update version to 4.0.50 Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index df03ea4500d..2a52479bcdf 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -58,8 +58,8 @@ #define _NETXEN_NIC_LINUX_MAJOR 4 #define _NETXEN_NIC_LINUX_MINOR 0 -#define _NETXEN_NIC_LINUX_SUBVERSION 41 -#define NETXEN_NIC_LINUX_VERSIONID "4.0.41" +#define _NETXEN_NIC_LINUX_SUBVERSION 50 +#define NETXEN_NIC_LINUX_VERSIONID "4.0.50" #define NETXEN_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c)) #define _major(v) (((v) >> 24) & 0xff) -- cgit v1.2.3-18-g5258 From 384824281caa9ac4b76664033416f1eac4a652fe Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 4 Sep 2009 05:33:46 +0000 Subject: wan: dlci/sdla transmit return dehacking This is a brute force removal of the wierd slave interface done for DLCI -> SDLA transmit. Before it was using non-standard return values and freeing skb in caller. This changes it to using normal return values, and freeing in the callee. Luckly only one driver pair was doing this. Not tested on real hardware, in fact I wonder if this driver pair is even being used by any users. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/wan/dlci.c | 43 +++++-------------------------------------- drivers/net/wan/sdla.c | 8 ++++---- 2 files changed, 9 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 69d269d32b5..15d353f268b 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -186,46 +186,13 @@ static void dlci_receive(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); } -static netdev_tx_t dlci_transmit(struct sk_buff *skb, - struct net_device *dev) +static netdev_tx_t dlci_transmit(struct sk_buff *skb, struct net_device *dev) { - struct dlci_local *dlp; - netdev_tx_t ret; - - if (!skb || !dev) - return NETDEV_TX_OK; - - dlp = netdev_priv(dev); - - netif_stop_queue(dev); - - /* This is hackish, overloads driver specific return values - on top of normal transmit return! */ - ret = dlp->slave->netdev_ops->ndo_start_xmit(skb, dlp->slave); - switch (ret) - { - case DLCI_RET_OK: - dev->stats.tx_packets++; - ret = NETDEV_TX_OK; - break; - case DLCI_RET_ERR: - dev->stats.tx_errors++; - ret = NETDEV_TX_OK; - break; - case DLCI_RET_DROP: - dev->stats.tx_dropped++; - ret = NETDEV_TX_BUSY; - break; - } - /* Alan Cox recommends always returning 0, and always freeing the packet */ - /* experience suggest a slightly more conservative approach */ + struct dlci_local *dlp = netdev_priv(dev); - if (ret == NETDEV_TX_OK) - { - dev_kfree_skb(skb); - netif_wake_queue(dev); - } - return(ret); + if (skb) + dlp->slave->netdev_ops->ndo_start_xmit(skb, dlp->slave); + return NETDEV_TX_OK; } static int dlci_config(struct net_device *dev, struct dlci_conf __user *conf, int get) diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 63c76458431..2b15a7e40d5 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -652,7 +652,7 @@ static int sdla_dlci_conf(struct net_device *slave, struct net_device *master, i /* NOTE: the DLCI driver deals with freeing the SKB!! */ static netdev_tx_t sdla_transmit(struct sk_buff *skb, - struct net_device *dev) + struct net_device *dev) { struct frad_local *flp; int ret, addr, accept, i; @@ -712,23 +712,21 @@ static netdev_tx_t sdla_transmit(struct sk_buff *skb, } break; } + switch (ret) { case SDLA_RET_OK: dev->stats.tx_packets++; - ret = DLCI_RET_OK; break; case SDLA_RET_CIR_OVERFLOW: case SDLA_RET_BUF_OVERSIZE: case SDLA_RET_NO_BUFS: dev->stats.tx_dropped++; - ret = DLCI_RET_DROP; break; default: dev->stats.tx_errors++; - ret = DLCI_RET_ERR; break; } } @@ -738,6 +736,8 @@ static netdev_tx_t sdla_transmit(struct sk_buff *skb, if(flp->master[i]!=NULL) netif_wake_queue(flp->master[i]); } + + dev_kfree_skb(skb); return NETDEV_TX_OK; } -- cgit v1.2.3-18-g5258 From 84517482e19bc775de7b3b4e998dee2f506bc34e Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Fri, 4 Sep 2009 03:12:16 +0000 Subject: be2net: Changes to support flashing of the be2 network adapter Changes to support flashing of the be2 network adapter using the request_firmware() & ethtool infrastructure. The trigger to flash the device will come from ethtool utility. The driver will invoke request_firmware() to start the flash process. The file containing the flash image is expected to be available in /lib/firmware/ Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/benet/be.h | 4 +- drivers/net/benet/be_cmds.c | 30 +++++++- drivers/net/benet/be_cmds.h | 20 ++++- drivers/net/benet/be_ethtool.c | 15 ++++ drivers/net/benet/be_hw.h | 85 ++++++++++++++++++++- drivers/net/benet/be_main.c | 167 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 317 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 6c45a2233d0..13b72ce870d 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -28,10 +28,11 @@ #include #include #include +#include #include "be_hw.h" -#define DRV_VER "2.0.400" +#define DRV_VER "2.101.205" #define DRV_NAME "be2net" #define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC" #define OC_NAME "Emulex OneConnect 10Gbps NIC" @@ -361,4 +362,5 @@ static inline u8 is_udp_pkt(struct sk_buff *skb) extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped); extern void be_link_status_update(struct be_adapter *adapter, bool link_up); +extern int be_load_fw(struct be_adapter *adapter, u8 *func); #endif /* BE_H */ diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 2547ee296a7..1db09249830 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -155,7 +155,7 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) if (ready) break; - if (cnt > 200000) { + if (cnt > 4000000) { dev_err(&adapter->pdev->dev, "mbox poll timed out\n"); return -1; } @@ -1040,3 +1040,31 @@ int be_cmd_reset_function(struct be_adapter *adapter) spin_unlock(&adapter->mbox_lock); return status; } + +int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, + u32 flash_type, u32 flash_opcode, u32 buf_size) +{ + struct be_mcc_wrb *wrb = wrb_from_mbox(&adapter->mbox_mem); + struct be_cmd_write_flashrom *req = cmd->va; + struct be_sge *sge = nonembedded_sgl(wrb); + int status; + + spin_lock(&adapter->mbox_lock); + memset(wrb, 0, sizeof(*wrb)); + be_wrb_hdr_prepare(wrb, cmd->size, false, 1); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_WRITE_FLASHROM, cmd->size); + sge->pa_hi = cpu_to_le32(upper_32_bits(cmd->dma)); + sge->pa_lo = cpu_to_le32(cmd->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(cmd->size); + + req->params.op_type = cpu_to_le32(flash_type); + req->params.op_code = cpu_to_le32(flash_opcode); + req->params.data_buf_size = cpu_to_le32(buf_size); + + status = be_mbox_notify(adapter); + + spin_unlock(&adapter->mbox_lock); + return status; +} diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 70618064ae1..fd7028e5b78 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -117,6 +117,7 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_NTWK_MULTICAST_SET 3 #define OPCODE_COMMON_NTWK_VLAN_CONFIG 4 #define OPCODE_COMMON_NTWK_LINK_STATUS_QUERY 5 +#define OPCODE_COMMON_WRITE_FLASHROM 7 #define OPCODE_COMMON_CQ_CREATE 12 #define OPCODE_COMMON_EQ_CREATE 13 #define OPCODE_COMMON_MCC_CREATE 21 @@ -693,10 +694,24 @@ struct be_cmd_resp_query_fw_cfg { u32 be_config_number; u32 asic_revision; u32 phys_port; - u32 function_mode; + u32 function_cap; u32 rsvd[26]; }; +/****************** Firmware Flash ******************/ +struct flashrom_params { + u32 op_code; + u32 op_type; + u32 data_buf_size; + u32 offset; + u8 data_buf[4]; +}; + +struct be_cmd_write_flashrom { + struct be_cmd_req_hdr hdr; + struct flashrom_params params; +}; + extern int be_pci_fnum_get(struct be_adapter *adapter); extern int be_cmd_POST(struct be_adapter *adapter); extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, @@ -747,3 +762,6 @@ extern int be_cmd_get_flow_control(struct be_adapter *adapter, extern int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num); extern int be_cmd_reset_function(struct be_adapter *adapter); extern void be_process_mcc(struct be_adapter *adapter); +extern int be_cmd_write_flashrom(struct be_adapter *adapter, + struct be_dma_mem *cmd, u32 flash_oper, + u32 flash_opcode, u32 buf_size); diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 4ff3cc46540..11445df3dbc 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -332,6 +332,20 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) return status; } +static int +be_do_flash(struct net_device *netdev, struct ethtool_flash *efl) +{ + struct be_adapter *adapter = netdev_priv(netdev); + char file_name[ETHTOOL_FLASH_MAX_FILENAME]; + u32 region; + + file_name[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0; + strcpy(file_name, efl->data); + region = efl->region; + + return be_load_fw(adapter, file_name); +} + const struct ethtool_ops be_ethtool_ops = { .get_settings = be_get_settings, .get_drvinfo = be_get_drvinfo, @@ -352,4 +366,5 @@ const struct ethtool_ops be_ethtool_ops = { .get_strings = be_get_stat_strings, .get_stats_count = be_get_stats_count, .get_ethtool_stats = be_get_ethtool_stats, + .flash_device = be_do_flash, }; diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h index d28f0c679bc..a3394b4aa14 100644 --- a/drivers/net/benet/be_hw.h +++ b/drivers/net/benet/be_hw.h @@ -204,7 +204,7 @@ struct amap_eth_rx_compl { u8 numfrags[3]; /* dword 1 */ u8 rss_flush; /* dword 2 */ u8 cast_enc[2]; /* dword 2 */ - u8 qnq; /* dword 2 */ + u8 vtm; /* dword 2 */ u8 rss_bank; /* dword 2 */ u8 rsvd1[23]; /* dword 2 */ u8 lro_pkt; /* dword 2 */ @@ -216,3 +216,86 @@ struct amap_eth_rx_compl { struct be_eth_rx_compl { u32 dw[4]; }; + +/* Flashrom related descriptors */ +#define IMAGE_TYPE_FIRMWARE 160 +#define IMAGE_TYPE_BOOTCODE 224 +#define IMAGE_TYPE_OPTIONROM 32 + +#define NUM_FLASHDIR_ENTRIES 32 + +#define FLASHROM_TYPE_ISCSI_ACTIVE 0 +#define FLASHROM_TYPE_BIOS 2 +#define FLASHROM_TYPE_PXE_BIOS 3 +#define FLASHROM_TYPE_FCOE_BIOS 8 +#define FLASHROM_TYPE_ISCSI_BACKUP 9 +#define FLASHROM_TYPE_FCOE_FW_ACTIVE 10 +#define FLASHROM_TYPE_FCOE_FW_BACKUP 11 + +#define FLASHROM_OPER_FLASH 1 +#define FLASHROM_OPER_SAVE 2 + +#define FLASH_IMAGE_MAX_SIZE (1310720) /* Max firmware image size */ +#define FLASH_BIOS_IMAGE_MAX_SIZE (262144) /* Max OPTION ROM image sz */ + +/* Offsets for components on Flash. */ +#define FLASH_iSCSI_PRIMARY_IMAGE_START (1048576) +#define FLASH_iSCSI_BACKUP_IMAGE_START (2359296) +#define FLASH_FCoE_PRIMARY_IMAGE_START (3670016) +#define FLASH_FCoE_BACKUP_IMAGE_START (4980736) +#define FLASH_iSCSI_BIOS_START (7340032) +#define FLASH_PXE_BIOS_START (7864320) +#define FLASH_FCoE_BIOS_START (524288) + +struct controller_id { + u32 vendor; + u32 device; + u32 subvendor; + u32 subdevice; +}; + +struct flash_file_hdr { + u8 sign[32]; + u32 cksum; + u32 antidote; + struct controller_id cont_id; + u32 file_len; + u32 chunk_num; + u32 total_chunks; + u32 num_imgs; + u8 build[24]; +}; + +struct flash_section_hdr { + u32 format_rev; + u32 cksum; + u32 antidote; + u32 build_no; + u8 id_string[64]; + u32 active_entry_mask; + u32 valid_entry_mask; + u32 org_content_mask; + u32 rsvd0; + u32 rsvd1; + u32 rsvd2; + u32 rsvd3; + u32 rsvd4; +}; + +struct flash_section_entry { + u32 type; + u32 offset; + u32 pad_size; + u32 image_size; + u32 cksum; + u32 entry_point; + u32 rsvd0; + u32 rsvd1; + u8 ver_data[32]; +}; + +struct flash_section_info { + u8 cookie[32]; + struct flash_section_hdr fsec_hdr; + struct flash_section_entry fsec_entry[32]; +}; diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index bac85f95039..d09106f2e08 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1699,6 +1699,173 @@ static int be_close(struct net_device *netdev) return 0; } +#define FW_FILE_HDR_SIGN "ServerEngines Corp. " +char flash_cookie[2][16] = {"*** SE FLAS", + "H DIRECTORY *** "}; +static int be_flash_image(struct be_adapter *adapter, + const struct firmware *fw, + struct be_dma_mem *flash_cmd, u32 flash_type) +{ + int status; + u32 flash_op, image_offset = 0, total_bytes, image_size = 0; + int num_bytes; + const u8 *p = fw->data; + struct be_cmd_write_flashrom *req = flash_cmd->va; + + switch (flash_type) { + case FLASHROM_TYPE_ISCSI_ACTIVE: + image_offset = FLASH_iSCSI_PRIMARY_IMAGE_START; + image_size = FLASH_IMAGE_MAX_SIZE; + break; + case FLASHROM_TYPE_ISCSI_BACKUP: + image_offset = FLASH_iSCSI_BACKUP_IMAGE_START; + image_size = FLASH_IMAGE_MAX_SIZE; + break; + case FLASHROM_TYPE_FCOE_FW_ACTIVE: + image_offset = FLASH_FCoE_PRIMARY_IMAGE_START; + image_size = FLASH_IMAGE_MAX_SIZE; + break; + case FLASHROM_TYPE_FCOE_FW_BACKUP: + image_offset = FLASH_FCoE_BACKUP_IMAGE_START; + image_size = FLASH_IMAGE_MAX_SIZE; + break; + case FLASHROM_TYPE_BIOS: + image_offset = FLASH_iSCSI_BIOS_START; + image_size = FLASH_BIOS_IMAGE_MAX_SIZE; + break; + case FLASHROM_TYPE_FCOE_BIOS: + image_offset = FLASH_FCoE_BIOS_START; + image_size = FLASH_BIOS_IMAGE_MAX_SIZE; + break; + case FLASHROM_TYPE_PXE_BIOS: + image_offset = FLASH_PXE_BIOS_START; + image_size = FLASH_BIOS_IMAGE_MAX_SIZE; + break; + default: + return 0; + } + + p += sizeof(struct flash_file_hdr) + image_offset; + if (p + image_size > fw->data + fw->size) + return -1; + + total_bytes = image_size; + + while (total_bytes) { + if (total_bytes > 32*1024) + num_bytes = 32*1024; + else + num_bytes = total_bytes; + total_bytes -= num_bytes; + + if (!total_bytes) + flash_op = FLASHROM_OPER_FLASH; + else + flash_op = FLASHROM_OPER_SAVE; + memcpy(req->params.data_buf, p, num_bytes); + p += num_bytes; + status = be_cmd_write_flashrom(adapter, flash_cmd, + flash_type, flash_op, num_bytes); + if (status) { + dev_err(&adapter->pdev->dev, + "cmd to write to flash rom failed. type/op %d/%d\n", + flash_type, flash_op); + return -1; + } + yield(); + } + + return 0; +} + +int be_load_fw(struct be_adapter *adapter, u8 *func) +{ + char fw_file[ETHTOOL_FLASH_MAX_FILENAME]; + const struct firmware *fw; + struct flash_file_hdr *fhdr; + struct flash_section_info *fsec = NULL; + struct be_dma_mem flash_cmd; + int status; + const u8 *p; + bool entry_found = false; + int flash_type; + char fw_ver[FW_VER_LEN]; + char fw_cfg; + + status = be_cmd_get_fw_ver(adapter, fw_ver); + if (status) + return status; + + fw_cfg = *(fw_ver + 2); + if (fw_cfg == '0') + fw_cfg = '1'; + strcpy(fw_file, func); + + status = request_firmware(&fw, fw_file, &adapter->pdev->dev); + if (status) + goto fw_exit; + + p = fw->data; + fhdr = (struct flash_file_hdr *) p; + if (memcmp(fhdr->sign, FW_FILE_HDR_SIGN, strlen(FW_FILE_HDR_SIGN))) { + dev_err(&adapter->pdev->dev, + "Firmware(%s) load error (signature did not match)\n", + fw_file); + status = -1; + goto fw_exit; + } + + dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file); + + p += sizeof(struct flash_file_hdr); + while (p < (fw->data + fw->size)) { + fsec = (struct flash_section_info *)p; + if (!memcmp(flash_cookie, fsec->cookie, sizeof(flash_cookie))) { + entry_found = true; + break; + } + p += 32; + } + + if (!entry_found) { + status = -1; + dev_err(&adapter->pdev->dev, + "Flash cookie not found in firmware image\n"); + goto fw_exit; + } + + flash_cmd.size = sizeof(struct be_cmd_write_flashrom) + 32*1024; + flash_cmd.va = pci_alloc_consistent(adapter->pdev, flash_cmd.size, + &flash_cmd.dma); + if (!flash_cmd.va) { + status = -ENOMEM; + dev_err(&adapter->pdev->dev, + "Memory allocation failure while flashing\n"); + goto fw_exit; + } + + for (flash_type = FLASHROM_TYPE_ISCSI_ACTIVE; + flash_type <= FLASHROM_TYPE_FCOE_FW_BACKUP; flash_type++) { + status = be_flash_image(adapter, fw, &flash_cmd, + flash_type); + if (status) + break; + } + + pci_free_consistent(adapter->pdev, flash_cmd.size, flash_cmd.va, + flash_cmd.dma); + if (status) { + dev_err(&adapter->pdev->dev, "Firmware load error\n"); + goto fw_exit; + } + + dev_info(&adapter->pdev->dev, "Firmware flashed succesfully\n"); + +fw_exit: + release_firmware(fw); + return status; +} + static struct net_device_ops be_netdev_ops = { .ndo_open = be_open, .ndo_stop = be_close, -- cgit v1.2.3-18-g5258 From c190e3c8f6b22004b9cdc62ee5e7ba2fa5f74dc7 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Fri, 4 Sep 2009 03:12:29 +0000 Subject: be2net: Code changes in Tx path to use skb_dma_map/skb_dma_unmap Code changes to - In the tx completion processing, there were instances of unmapping a memory as a page which was originally mapped as single. This patch takes care of this by using skb_dma_map()/skb_dma_unmap() to map/unmap Tx buffers. - set gso_max_size to 65535. This was not done till now. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/benet/be_main.c | 62 +++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index d09106f2e08..ce11bba2cb6 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -385,15 +385,19 @@ static int make_tx_wrbs(struct be_adapter *adapter, struct be_eth_wrb *wrb; struct be_eth_hdr_wrb *hdr; - atomic_add(wrb_cnt, &txq->used); hdr = queue_head_node(txq); + atomic_add(wrb_cnt, &txq->used); queue_head_inc(txq); + if (skb_dma_map(&pdev->dev, skb, DMA_TO_DEVICE)) { + dev_err(&pdev->dev, "TX DMA mapping failed\n"); + return 0; + } + if (skb->len > skb->data_len) { int len = skb->len - skb->data_len; - busaddr = pci_map_single(pdev, skb->data, len, - PCI_DMA_TODEVICE); wrb = queue_head_node(txq); + busaddr = skb_shinfo(skb)->dma_head; wrb_fill(wrb, busaddr, len); be_dws_cpu_to_le(wrb, sizeof(*wrb)); queue_head_inc(txq); @@ -403,9 +407,8 @@ static int make_tx_wrbs(struct be_adapter *adapter, for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; - busaddr = pci_map_page(pdev, frag->page, - frag->page_offset, - frag->size, PCI_DMA_TODEVICE); + + busaddr = skb_shinfo(skb)->dma_maps[i]; wrb = queue_head_node(txq); wrb_fill(wrb, busaddr, frag->size); be_dws_cpu_to_le(wrb, sizeof(*wrb)); @@ -429,6 +432,7 @@ static int make_tx_wrbs(struct be_adapter *adapter, static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev) + { struct be_adapter *adapter = netdev_priv(netdev); struct be_tx_obj *tx_obj = &adapter->tx_obj; @@ -440,23 +444,28 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, wrb_cnt = wrb_cnt_for_skb(skb, &dummy_wrb); copied = make_tx_wrbs(adapter, skb, wrb_cnt, dummy_wrb); + if (copied) { + /* record the sent skb in the sent_skb table */ + BUG_ON(tx_obj->sent_skb_list[start]); + tx_obj->sent_skb_list[start] = skb; + + /* Ensure txq has space for the next skb; Else stop the queue + * *BEFORE* ringing the tx doorbell, so that we serialze the + * tx compls of the current transmit which'll wake up the queue + */ + if ((BE_MAX_TX_FRAG_COUNT + atomic_read(&txq->used)) >= + txq->len) { + netif_stop_queue(netdev); + stopped = true; + } - /* record the sent skb in the sent_skb table */ - BUG_ON(tx_obj->sent_skb_list[start]); - tx_obj->sent_skb_list[start] = skb; + be_txq_notify(adapter, txq->id, wrb_cnt); - /* Ensure that txq has space for the next skb; Else stop the queue - * *BEFORE* ringing the tx doorbell, so that we serialze the - * tx compls of the current transmit which'll wake up the queue - */ - if ((BE_MAX_TX_FRAG_COUNT + atomic_read(&txq->used)) >= txq->len) { - netif_stop_queue(netdev); - stopped = true; + be_tx_stats_update(adapter, wrb_cnt, copied, stopped); + } else { + txq->head = start; + dev_kfree_skb_any(skb); } - - be_txq_notify(adapter, txq->id, wrb_cnt); - - be_tx_stats_update(adapter, wrb_cnt, copied, stopped); return NETDEV_TX_OK; } @@ -958,10 +967,8 @@ static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq) static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index) { struct be_queue_info *txq = &adapter->tx_obj.q; - struct be_eth_wrb *wrb; struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list; struct sk_buff *sent_skb; - u64 busaddr; u16 cur_index, num_wrbs = 0; cur_index = txq->tail; @@ -971,19 +978,12 @@ static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index) do { cur_index = txq->tail; - wrb = queue_tail_node(txq); - be_dws_le_to_cpu(wrb, sizeof(*wrb)); - busaddr = ((u64)wrb->frag_pa_hi << 32) | (u64)wrb->frag_pa_lo; - if (busaddr != 0) { - pci_unmap_single(adapter->pdev, busaddr, - wrb->frag_len, PCI_DMA_TODEVICE); - } num_wrbs++; queue_tail_inc(txq); } while (cur_index != last_index); atomic_sub(num_wrbs, &txq->used); - + skb_dma_unmap(&adapter->pdev->dev, sent_skb, DMA_TO_DEVICE); kfree_skb(sent_skb); } @@ -1892,6 +1892,8 @@ static void be_netdev_init(struct net_device *netdev) adapter->rx_csum = true; + netif_set_gso_max_size(netdev, 65535); + BE_SET_NETDEV_OPS(netdev, &be_netdev_ops); SET_ETHTOOL_OPS(netdev, &be_ethtool_ops); -- cgit v1.2.3-18-g5258 From 32e6a0c82e7a7991a02414d830f262e1f4db73e6 Mon Sep 17 00:00:00 2001 From: Krzysztof Halasa Date: Sat, 5 Sep 2009 00:54:30 +0000 Subject: WAN: remove deprecated PCI_DEVICE_ID from PCI200SYN driver. PCI200SYN has its own PCI subsystem device ID for 3+ years, now it's time to remove the generic PLX905[02] ID from the driver. Anyone with old EEPROM data will have to run the upgrade. Having the generic PLX905[02] (PCI-local bus bridge) ID is harmful as the driver tries to handle other devices based on these bridges. Signed-off-by: Krzysztof Halasa Signed-off-by: David S. Miller --- drivers/net/wan/pci200syn.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c index e035d8c57e1..a52f29c72c3 100644 --- a/drivers/net/wan/pci200syn.c +++ b/drivers/net/wan/pci200syn.c @@ -360,15 +360,6 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, " %u RX packets rings\n", ramsize / 1024, ramphys, pdev->irq, card->tx_ring_buffers, card->rx_ring_buffers); - if (pdev->subsystem_device == PCI_DEVICE_ID_PLX_9050) { - printk(KERN_ERR "Detected PCI200SYN card with old " - "configuration data.\n"); - printk(KERN_ERR "See for update.\n"); - printk(KERN_ERR "The card will stop working with" - " future versions of Linux if not updated.\n"); - } - if (card->tx_ring_buffers < 1) { printk(KERN_ERR "pci200syn: RAM test failed\n"); pci200_pci_remove_one(pdev); @@ -426,8 +417,6 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, static struct pci_device_id pci200_pci_tbl[] __devinitdata = { - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_PLX, - PCI_DEVICE_ID_PLX_9050, 0, 0, 0 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_PCI200SYN, 0, 0, 0 }, { 0, } -- cgit v1.2.3-18-g5258 From 5dbc46506a4f7b9f564bb7589a49ed32bc1caa15 Mon Sep 17 00:00:00 2001 From: Krzysztof Halasa Date: Sat, 5 Sep 2009 03:59:49 +0000 Subject: IXP42x HSS support for setting internal clock rate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HSS usually uses external clocks, so it's not a big deal. Internal clock is used for direct DTE-DTE connections and when the DCE doesn't provide it's own clock. This also depends on the oscillator frequency. Intel seems to have calculated the clock register settings for 33.33 MHz (66.66 MHz timer base). Their settings seem quite suboptimal both in terms of average frequency (60 ppm is unacceptable for G.703 applications, their primary intended usage(?)) and jitter. Many (most?) platforms use a 33.333 MHz oscillator, a 10 ppm difference from Intel's base. Instead of creating static tables, I've created a procedure to program the HSS clock register. The register consists of 3 parts (A, B, C). The average frequency (= bit rate) is: 66.66x MHz / (A + (B + 1) / (C + 1)) The procedure aims at the closest average frequency, possibly at the cost of increased jitter. Nobody would be able to directly drive an unbufferred transmitter with a HSS anyway, and the frequency error is what it really counts. I've verified the above with an oscilloscope on IXP425. It seems IXP46x and possibly IXP43x use a bit different clock generation algorithm - it looks like the avg frequency is: (on IXP465) 66.66x MHz / (A + B / (C + 1)). Also they use much greater precomputed A and B - on IXP425 it would simply result in more jitter, but I don't know how does it work on IXP46x (perhaps 3 least significant bits aren't used?). Anyway it looks that they were aiming for exactly +60 ppm or -60 ppm, while <1 ppm is typically possible (with a synchronized clock, of course). The attached patch makes it possible to set almost any bit rate (my IXP425 533 MHz quits at > 22 Mb/s if a single port is used, and the minimum is ca. 65 Kb/s). This is independent of MVIP (multi-E1/T1 on one HSS) mode. Signed-off-by: Krzysztof HaÅ‚asa Signed-off-by: David S. Miller --- drivers/net/wan/ixp4xx_hss.c | 95 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 91 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c index bb719b6114c..c705046d861 100644 --- a/drivers/net/wan/ixp4xx_hss.c +++ b/drivers/net/wan/ixp4xx_hss.c @@ -166,6 +166,29 @@ #define CLK46X_SPEED_4096KHZ (( 16 << 22) | (280 << 12) | 1023) #define CLK46X_SPEED_8192KHZ (( 8 << 22) | (280 << 12) | 2047) +/* + * HSS_CONFIG_CLOCK_CR register consists of 3 parts: + * A (10 bits), B (10 bits) and C (12 bits). + * IXP42x HSS clock generator operation (verified with an oscilloscope): + * Each clock bit takes 7.5 ns (1 / 133.xx MHz). + * The clock sequence consists of (C - B) states of 0s and 1s, each state is + * A bits wide. It's followed by (B + 1) states of 0s and 1s, each state is + * (A + 1) bits wide. + * + * The resulting average clock frequency (assuming 33.333 MHz oscillator) is: + * freq = 66.666 MHz / (A + (B + 1) / (C + 1)) + * minumum freq = 66.666 MHz / (A + 1) + * maximum freq = 66.666 MHz / A + * + * Example: A = 2, B = 2, C = 7, CLOCK_CR register = 2 << 22 | 2 << 12 | 7 + * freq = 66.666 MHz / (2 + (2 + 1) / (7 + 1)) = 28.07 MHz (Mb/s). + * The clock sequence is: 1100110011 (5 doubles) 000111000 (3 triples). + * The sequence takes (C - B) * A + (B + 1) * (A + 1) = 5 * 2 + 3 * 3 bits + * = 19 bits (each 7.5 ns long) = 142.5 ns (then the sequence repeats). + * The sequence consists of 4 complete clock periods, thus the average + * frequency (= clock rate) is 4 / 142.5 ns = 28.07 MHz (Mb/s). + * (max specified clock rate for IXP42x HSS is 8.192 Mb/s). + */ /* hss_config, LUT entries */ #define TDMMAP_UNASSIGNED 0 @@ -239,6 +262,7 @@ struct port { unsigned int clock_type, clock_rate, loopback; unsigned int initialized, carrier; u8 hdlc_cfg; + u32 clock_reg; }; /* NPE message structure */ @@ -393,7 +417,7 @@ static void hss_config(struct port *port) msg.cmd = PORT_CONFIG_WRITE; msg.hss_port = port->id; msg.index = HSS_CONFIG_CLOCK_CR; - msg.data32 = CLK42X_SPEED_2048KHZ /* FIXME */; + msg.data32 = port->clock_reg; hss_npe_send(port, &msg, "HSS_SET_CLOCK_CR"); memset(&msg, 0, sizeof(msg)); @@ -1160,6 +1184,62 @@ static int hss_hdlc_attach(struct net_device *dev, unsigned short encoding, } } +static u32 check_clock(u32 rate, u32 a, u32 b, u32 c, + u32 *best, u32 *best_diff, u32 *reg) +{ + /* a is 10-bit, b is 10-bit, c is 12-bit */ + u64 new_rate; + u32 new_diff; + + new_rate = ixp4xx_timer_freq * (u64)(c + 1); + do_div(new_rate, a * (c + 1) + b + 1); + new_diff = abs((u32)new_rate - rate); + + if (new_diff < *best_diff) { + *best = new_rate; + *best_diff = new_diff; + *reg = (a << 22) | (b << 12) | c; + } + return new_diff; +} + +static void find_best_clock(u32 rate, u32 *best, u32 *reg) +{ + u32 a, b, diff = 0xFFFFFFFF; + + a = ixp4xx_timer_freq / rate; + + if (a > 0x3FF) { /* 10-bit value - we can go as slow as ca. 65 kb/s */ + check_clock(rate, 0x3FF, 1, 1, best, &diff, reg); + return; + } + if (a == 0) { /* > 66.666 MHz */ + a = 1; /* minimum divider is 1 (a = 0, b = 1, c = 1) */ + rate = ixp4xx_timer_freq; + } + + if (rate * a == ixp4xx_timer_freq) { /* don't divide by 0 later */ + check_clock(rate, a - 1, 1, 1, best, &diff, reg); + return; + } + + for (b = 0; b < 0x400; b++) { + u64 c = (b + 1) * (u64)rate; + do_div(c, ixp4xx_timer_freq - rate * a); + c--; + if (c >= 0xFFF) { /* 12-bit - no need to check more 'b's */ + if (b == 0 && /* also try a bit higher rate */ + !check_clock(rate, a - 1, 1, 1, best, &diff, reg)) + return; + check_clock(rate, a, b, 0xFFF, best, &diff, reg); + return; + } + if (!check_clock(rate, a, b, c, best, &diff, reg)) + return; + if (!check_clock(rate, a, b, c + 1, best, &diff, reg)) + return; + } +} static int hss_hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { @@ -1182,7 +1262,7 @@ static int hss_hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } memset(&new_line, 0, sizeof(new_line)); new_line.clock_type = port->clock_type; - new_line.clock_rate = 2048000; /* FIXME */ + new_line.clock_rate = port->clock_rate; new_line.loopback = port->loopback; if (copy_to_user(line, &new_line, size)) return -EFAULT; @@ -1206,7 +1286,13 @@ static int hss_hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -EINVAL; port->clock_type = clk; /* Update settings */ - /* FIXME port->clock_rate = new_line.clock_rate */; + if (clk == CLOCK_INT) + find_best_clock(new_line.clock_rate, &port->clock_rate, + &port->clock_reg); + else { + port->clock_rate = 0; + port->clock_reg = CLK42X_SPEED_2048KHZ; + } port->loopback = new_line.loopback; spin_lock_irqsave(&npe_lock, flags); @@ -1266,7 +1352,8 @@ static int __devinit hss_init_one(struct platform_device *pdev) dev->netdev_ops = &hss_hdlc_ops; dev->tx_queue_len = 100; port->clock_type = CLOCK_EXT; - port->clock_rate = 2048000; + port->clock_rate = 0; + port->clock_reg = CLK42X_SPEED_2048KHZ; port->id = pdev->id; port->dev = &pdev->dev; port->plat = pdev->dev.platform_data; -- cgit v1.2.3-18-g5258 From cf33ce15463b784a1d648905fc067fa4d6b17466 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 4 Sep 2009 14:20:37 +0000 Subject: net: fix hydra printk format warning m68k: drivers/net/hydra.c:178: warning: format '%08lx' expects type 'long unsigned int', but argument 3 has type 'resource_size_t' Signed-off-by: Randy Dunlap Signed-off-by: David S. Miller --- drivers/net/hydra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c index 8ac0930c183..d496b6f4a47 100644 --- a/drivers/net/hydra.c +++ b/drivers/net/hydra.c @@ -173,9 +173,9 @@ static int __devinit hydra_init(struct zorro_dev *z) zorro_set_drvdata(z, dev); - printk(KERN_INFO "%s: Hydra at 0x%08lx, address " + printk(KERN_INFO "%s: Hydra at 0x%08llx, address " "%pM (hydra.c " HYDRA_VERSION ")\n", - dev->name, z->resource.start, dev->dev_addr); + dev->name, (unsigned long long)z->resource.start, dev->dev_addr); return 0; } -- cgit v1.2.3-18-g5258 From 3a5f29c1dbe5814349efacdea483079c470dcc38 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 7 Sep 2009 02:03:37 -0700 Subject: r8169: Fix warning in rtl8169_start_xmit(). Reported by Stephen Rothwell: drivers/net/r8169.c: In function 'rtl8169_start_xmit': drivers/net/r8169.c:3421: warning: label 'out' defined but not used Introduced by commit 61357325f377889a1daffa14962d705dc814dd0e ("netdev: convert bulk of drivers to netdev_tx_t"). Signed-off-by: David S. Miller --- drivers/net/r8169.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index a91e9b3a3eb..50c6a3cfe43 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -3416,7 +3416,6 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, netif_wake_queue(dev); } -out: return NETDEV_TX_OK; err_stop: -- cgit v1.2.3-18-g5258 From 6b2eef8fd78ff909c3396b8671d57c42559cc51d Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 7 Sep 2009 08:27:50 -0700 Subject: IB/mad: Fix possible lock-lock-timer deadlock Lockdep reported a possible deadlock with cm_id_priv->lock, mad_agent_priv->lock and mad_agent_priv->timed_work.timer; this happens because the mad module does cancel_delayed_work(&mad_agent_priv->timed_work); while holding mad_agent_priv->lock. cancel_delayed_work() internally does del_timer_sync(&mad_agent_priv->timed_work.timer). This can turn into a deadlock because mad_agent_priv->lock is taken inside cm_id_priv->lock, so we can get the following set of contexts that deadlock each other: A: holding cm_id_priv->lock, waiting for mad_agent_priv->lock B: holding mad_agent_priv->lock, waiting for del_timer_sync() C: interrupt during mad_agent_priv->timed_work.timer that takes cm_id_priv->lock Fix this by using the new __cancel_delayed_work() interface (which internally does del_timer() instead of del_timer_sync()) in all the places where we are holding a lock. Addresses: http://bugzilla.kernel.org/show_bug.cgi?id=13757 Reported-by: Bart Van Assche Signed-off-by: Roland Dreier --- drivers/infiniband/core/mad.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index de922a04ca2..bc30c00c5d7 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -1974,7 +1974,7 @@ static void adjust_timeout(struct ib_mad_agent_private *mad_agent_priv) unsigned long delay; if (list_empty(&mad_agent_priv->wait_list)) { - cancel_delayed_work(&mad_agent_priv->timed_work); + __cancel_delayed_work(&mad_agent_priv->timed_work); } else { mad_send_wr = list_entry(mad_agent_priv->wait_list.next, struct ib_mad_send_wr_private, @@ -1983,7 +1983,7 @@ static void adjust_timeout(struct ib_mad_agent_private *mad_agent_priv) if (time_after(mad_agent_priv->timeout, mad_send_wr->timeout)) { mad_agent_priv->timeout = mad_send_wr->timeout; - cancel_delayed_work(&mad_agent_priv->timed_work); + __cancel_delayed_work(&mad_agent_priv->timed_work); delay = mad_send_wr->timeout - jiffies; if ((long)delay <= 0) delay = 1; @@ -2023,7 +2023,7 @@ static void wait_for_response(struct ib_mad_send_wr_private *mad_send_wr) /* Reschedule a work item if we have a shorter timeout */ if (mad_agent_priv->wait_list.next == &mad_send_wr->agent_list) { - cancel_delayed_work(&mad_agent_priv->timed_work); + __cancel_delayed_work(&mad_agent_priv->timed_work); queue_delayed_work(mad_agent_priv->qp_info->port_priv->wq, &mad_agent_priv->timed_work, delay); } -- cgit v1.2.3-18-g5258 From b76aabc3956e9b95e7b7dc1aeecb8c6caf57f74c Mon Sep 17 00:00:00 2001 From: Hal Rosenstock Date: Mon, 7 Sep 2009 08:28:48 -0700 Subject: IB/mad: Allow tuning of QP0 and QP1 sizes MADs are UD and can be dropped if there are no receives posted, so allow receive queue size to be set with a module parameter in case the queue needs to be lengthened. Send side tuning is done for symmetry with receive. Signed-off-by: Hal Rosenstock Signed-off-by: Roland Dreier --- drivers/infiniband/core/mad.c | 25 ++++++++++++++++++++----- drivers/infiniband/core/mad_priv.h | 3 +++ 2 files changed, 23 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index bc30c00c5d7..0f7da241fa0 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -2,6 +2,7 @@ * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved. * Copyright (c) 2005 Intel Corporation. All rights reserved. * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -45,6 +46,14 @@ MODULE_DESCRIPTION("kernel IB MAD API"); MODULE_AUTHOR("Hal Rosenstock"); MODULE_AUTHOR("Sean Hefty"); +int mad_sendq_size = IB_MAD_QP_SEND_SIZE; +int mad_recvq_size = IB_MAD_QP_RECV_SIZE; + +module_param_named(send_queue_size, mad_sendq_size, int, 0444); +MODULE_PARM_DESC(send_queue_size, "Size of send queue in number of work requests"); +module_param_named(recv_queue_size, mad_recvq_size, int, 0444); +MODULE_PARM_DESC(recv_queue_size, "Size of receive queue in number of work requests"); + static struct kmem_cache *ib_mad_cache; static struct list_head ib_mad_port_list; @@ -2736,8 +2745,8 @@ static int create_mad_qp(struct ib_mad_qp_info *qp_info, qp_init_attr.send_cq = qp_info->port_priv->cq; qp_init_attr.recv_cq = qp_info->port_priv->cq; qp_init_attr.sq_sig_type = IB_SIGNAL_ALL_WR; - qp_init_attr.cap.max_send_wr = IB_MAD_QP_SEND_SIZE; - qp_init_attr.cap.max_recv_wr = IB_MAD_QP_RECV_SIZE; + qp_init_attr.cap.max_send_wr = mad_sendq_size; + qp_init_attr.cap.max_recv_wr = mad_recvq_size; qp_init_attr.cap.max_send_sge = IB_MAD_SEND_REQ_MAX_SG; qp_init_attr.cap.max_recv_sge = IB_MAD_RECV_REQ_MAX_SG; qp_init_attr.qp_type = qp_type; @@ -2752,8 +2761,8 @@ static int create_mad_qp(struct ib_mad_qp_info *qp_info, goto error; } /* Use minimum queue sizes unless the CQ is resized */ - qp_info->send_queue.max_active = IB_MAD_QP_SEND_SIZE; - qp_info->recv_queue.max_active = IB_MAD_QP_RECV_SIZE; + qp_info->send_queue.max_active = mad_sendq_size; + qp_info->recv_queue.max_active = mad_recvq_size; return 0; error: @@ -2792,7 +2801,7 @@ static int ib_mad_port_open(struct ib_device *device, init_mad_qp(port_priv, &port_priv->qp_info[0]); init_mad_qp(port_priv, &port_priv->qp_info[1]); - cq_size = (IB_MAD_QP_SEND_SIZE + IB_MAD_QP_RECV_SIZE) * 2; + cq_size = (mad_sendq_size + mad_recvq_size) * 2; port_priv->cq = ib_create_cq(port_priv->device, ib_mad_thread_completion_handler, NULL, port_priv, cq_size, 0); @@ -2984,6 +2993,12 @@ static int __init ib_mad_init_module(void) { int ret; + mad_recvq_size = min(mad_recvq_size, IB_MAD_QP_MAX_SIZE); + mad_recvq_size = max(mad_recvq_size, IB_MAD_QP_MIN_SIZE); + + mad_sendq_size = min(mad_sendq_size, IB_MAD_QP_MAX_SIZE); + mad_sendq_size = max(mad_sendq_size, IB_MAD_QP_MIN_SIZE); + spin_lock_init(&ib_mad_port_list_lock); ib_mad_cache = kmem_cache_create("ib_mad", diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h index 05ce331733b..9430ab4969c 100644 --- a/drivers/infiniband/core/mad_priv.h +++ b/drivers/infiniband/core/mad_priv.h @@ -2,6 +2,7 @@ * Copyright (c) 2004, 2005, Voltaire, Inc. All rights reserved. * Copyright (c) 2005 Intel Corporation. All rights reserved. * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -49,6 +50,8 @@ /* QP and CQ parameters */ #define IB_MAD_QP_SEND_SIZE 128 #define IB_MAD_QP_RECV_SIZE 512 +#define IB_MAD_QP_MIN_SIZE 64 +#define IB_MAD_QP_MAX_SIZE 8192 #define IB_MAD_SEND_REQ_MAX_SG 2 #define IB_MAD_RECV_REQ_MAX_SG 1 -- cgit v1.2.3-18-g5258 From 7c8460db30dfd085ef3837c8fb02ecf2e718b983 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Tue, 8 Sep 2009 14:52:25 +0800 Subject: drm/i915: fix mask bits setting eDP is exclusive connector too, and add missing crtc_mask setting for TV. This fixes http://bugzilla.kernel.org/show_bug.cgi?id=14139 Signed-off-by: Zhenyu Wang Reported-and-tested-by: Carlos R. Mafra Signed-off-by: Linus Torvalds --- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_tv.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index f2afc4af4bc..2b914d73207 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1263,7 +1263,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) if (IS_eDP(intel_output)) { intel_output->crtc_mask = (1 << 1); - intel_output->clone_mask = (1 << INTEL_OUTPUT_EDP); + intel_output->clone_mask = (1 << INTEL_EDP_CLONE_BIT); } else intel_output->crtc_mask = (1 << 0) | (1 << 1); connector->interlace_allowed = true; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 25aa6facc12..26a6227c15f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -74,6 +74,7 @@ #define INTEL_LVDS_CLONE_BIT 14 #define INTEL_DVO_TMDS_CLONE_BIT 15 #define INTEL_DVO_LVDS_CLONE_BIT 16 +#define INTEL_EDP_CLONE_BIT 17 #define INTEL_DVO_CHIP_NONE 0 #define INTEL_DVO_CHIP_LVDS 1 diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 2fbe13a0de8..5b1c9e9fdba 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1730,6 +1730,7 @@ intel_tv_init(struct drm_device *dev) drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); tv_priv = (struct intel_tv_priv *)(intel_output + 1); intel_output->type = INTEL_OUTPUT_TVOUT; + intel_output->crtc_mask = (1 << 0) | (1 << 1); intel_output->clone_mask = (1 << INTEL_TV_CLONE_BIT); intel_output->enc.possible_crtcs = ((1 << 0) | (1 << 1)); intel_output->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT); -- cgit v1.2.3-18-g5258 From 5c630ce7e6cb144a29fd5a993363f4928fb4b890 Mon Sep 17 00:00:00 2001 From: Joerg Albert Date: Thu, 3 Sep 2009 01:02:59 +0200 Subject: ar9170: added phy register initialisation from eeprom values This patch adds the initialisation of some PHY registers from the modal_header[] values in the EEPROM (see otus/hal/hpmain.c, line 333 ff.) Signed-off-by: Joerg Albert Acked-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/phy.c | 135 +++++++++++++++++++++++++++++++++- 1 file changed, 134 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c index df86f70cd81..3ace58ab40c 100644 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ b/drivers/net/wireless/ath/ar9170/phy.c @@ -396,6 +396,136 @@ static struct ar9170_phy_init ar5416_phy_init[] = { { 0x1c9384, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, } }; +/* + * look up a certain register in ar5416_phy_init[] and return the init. value + * for the band and bandwidth given. Return 0 if register address not found. + */ +static u32 ar9170_get_default_phy_reg_val(u32 reg, bool is_2ghz, bool is_40mhz) +{ + unsigned int i; + for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) { + if (ar5416_phy_init[i].reg != reg) + continue; + + if (is_2ghz) { + if (is_40mhz) + return ar5416_phy_init[i]._2ghz_40; + else + return ar5416_phy_init[i]._2ghz_20; + } else { + if (is_40mhz) + return ar5416_phy_init[i]._5ghz_40; + else + return ar5416_phy_init[i]._5ghz_20; + } + } + return 0; +} + +/* + * initialize some phy regs from eeprom values in modal_header[] + * acc. to band and bandwith + */ +static int ar9170_init_phy_from_eeprom(struct ar9170 *ar, + bool is_2ghz, bool is_40mhz) +{ + static const u8 xpd2pd[16] = { + 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x6, 0x2, + 0x2, 0x3, 0x7, 0x2, 0xB, 0x2, 0x2, 0x2 + }; + u32 defval, newval; + /* pointer to the modal_header acc. to band */ + struct ar9170_eeprom_modal *m = &ar->eeprom.modal_header[is_2ghz]; + + ar9170_regwrite_begin(ar); + + /* ant common control (index 0) */ + newval = le32_to_cpu(m->antCtrlCommon); + ar9170_regwrite(0x1c5964, newval); + + /* ant control chain 0 (index 1) */ + newval = le32_to_cpu(m->antCtrlChain[0]); + ar9170_regwrite(0x1c5960, newval); + + /* ant control chain 2 (index 2) */ + newval = le32_to_cpu(m->antCtrlChain[1]); + ar9170_regwrite(0x1c7960, newval); + + /* SwSettle (index 3) */ + if (!is_40mhz) { + defval = ar9170_get_default_phy_reg_val(0x1c5844, + is_2ghz, is_40mhz); + newval = (defval & ~0x3f80) | + ((m->switchSettling & 0x7f) << 7); + ar9170_regwrite(0x1c5844, newval); + } + + /* adcDesired, pdaDesired (index 4) */ + defval = ar9170_get_default_phy_reg_val(0x1c5850, is_2ghz, is_40mhz); + newval = (defval & ~0xffff) | ((u8)m->pgaDesiredSize << 8) | + ((u8)m->adcDesiredSize); + ar9170_regwrite(0x1c5850, newval); + + /* TxEndToXpaOff, TxFrameToXpaOn (index 5) */ + defval = ar9170_get_default_phy_reg_val(0x1c5834, is_2ghz, is_40mhz); + newval = (m->txEndToXpaOff << 24) | (m->txEndToXpaOff << 16) | + (m->txFrameToXpaOn << 8) | m->txFrameToXpaOn; + ar9170_regwrite(0x1c5834, newval); + + /* TxEndToRxOn (index 6) */ + defval = ar9170_get_default_phy_reg_val(0x1c5828, is_2ghz, is_40mhz); + newval = (defval & ~0xff0000) | (m->txEndToRxOn << 16); + ar9170_regwrite(0x1c5828, newval); + + /* thresh62 (index 7) */ + defval = ar9170_get_default_phy_reg_val(0x1c8864, is_2ghz, is_40mhz); + newval = (defval & ~0x7f000) | (m->thresh62 << 12); + ar9170_regwrite(0x1c8864, newval); + + /* tx/rx attenuation chain 0 (index 8) */ + defval = ar9170_get_default_phy_reg_val(0x1c5848, is_2ghz, is_40mhz); + newval = (defval & ~0x3f000) | ((m->txRxAttenCh[0] & 0x3f) << 12); + ar9170_regwrite(0x1c5848, newval); + + /* tx/rx attenuation chain 2 (index 9) */ + defval = ar9170_get_default_phy_reg_val(0x1c7848, is_2ghz, is_40mhz); + newval = (defval & ~0x3f000) | ((m->txRxAttenCh[1] & 0x3f) << 12); + ar9170_regwrite(0x1c7848, newval); + + /* tx/rx margin chain 0 (index 10) */ + defval = ar9170_get_default_phy_reg_val(0x1c620c, is_2ghz, is_40mhz); + newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[0] & 0x3f) << 18); + /* bsw margin chain 0 for 5GHz only */ + if (!is_2ghz) + newval = (newval & ~0x3c00) | ((m->bswMargin[0] & 0xf) << 10); + ar9170_regwrite(0x1c620c, newval); + + /* tx/rx margin chain 2 (index 11) */ + defval = ar9170_get_default_phy_reg_val(0x1c820c, is_2ghz, is_40mhz); + newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[1] & 0x3f) << 18); + ar9170_regwrite(0x1c820c, newval); + + /* iqCall, iqCallq chain 0 (index 12) */ + defval = ar9170_get_default_phy_reg_val(0x1c5920, is_2ghz, is_40mhz); + newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[0] & 0x3f) << 5) | + ((u8)m->iqCalQCh[0] & 0x1f); + ar9170_regwrite(0x1c5920, newval); + + /* iqCall, iqCallq chain 2 (index 13) */ + defval = ar9170_get_default_phy_reg_val(0x1c7920, is_2ghz, is_40mhz); + newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[1] & 0x3f) << 5) | + ((u8)m->iqCalQCh[1] & 0x1f); + ar9170_regwrite(0x1c7920, newval); + + /* xpd gain mask (index 14) */ + defval = ar9170_get_default_phy_reg_val(0x1c6258, is_2ghz, is_40mhz); + newval = (defval & ~0xf0000) | (xpd2pd[m->xpdGain & 0xf] << 16); + ar9170_regwrite(0x1c6258, newval); + ar9170_regwrite_finish(); + + return ar9170_regwrite_result(); +} + int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) { int i, err; @@ -426,7 +556,10 @@ int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) if (err) return err; - /* XXX: use EEPROM data here! */ + /* TODO: (heavy clip) regulatory domain power level fine-tuning. */ + err = ar9170_init_phy_from_eeprom(ar, is_2ghz, is_40mhz); + if (err) + return err; err = ar9170_init_power_cal(ar); if (err) -- cgit v1.2.3-18-g5258 From db6be53cbaf118fdad5bdca211a19ca5354c9462 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 2 Sep 2009 16:34:57 -0700 Subject: ath9k: propagate ieee80211_alloc_hw() failure The -ENOMEM was never being passed on failure. While at it use dev_err() as ahb does upon failure. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/pci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 685a8cebb46..17862ccc340 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -160,8 +160,9 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) + sizeof(struct ath_softc), &ath9k_ops); - if (hw == NULL) { - printk(KERN_ERR "ath_pci: no memory for ieee80211_hw\n"); + if (!hw) { + dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); + ret = -ENOMEM; goto bad2; } -- cgit v1.2.3-18-g5258 From 580171f7cd08687cdf1b263aabb35608b3c37433 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 2 Sep 2009 17:02:18 -0700 Subject: ath9k: propagate errors on ath_init_device() and request_irq() We've cleaned up ath_init_device() and its children enough to pass meaninful errors back from probe. When this fails it means our device could not be initialized and a meaninful error will have been passed. Do the same for request_irq() and also synchronize the error messages while at it. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ahb.c | 8 +++----- drivers/net/wireless/ath/ath9k/pci.c | 12 ++++++------ 2 files changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 5618fc25d52..7dc6301ae20 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -120,16 +120,14 @@ static int ath_ahb_probe(struct platform_device *pdev) sc->irq = irq; ret = ath_init_device(AR5416_AR9100_DEVID, sc); - if (ret != 0) { - dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret); - ret = -ENODEV; + if (ret) { + dev_err(&pdev->dev, "failed to initialize device\n"); goto err_free_hw; } ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { - dev_err(&pdev->dev, "request_irq failed, err=%d\n", ret); - ret = -EIO; + dev_err(&pdev->dev, "request_irq failed\n"); goto err_detach; } diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 17862ccc340..bc4bc2c2d37 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -179,17 +179,17 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) sc->mem = mem; sc->bus_ops = &ath_pci_bus_ops; - if (ath_init_device(id->device, sc) != 0) { - ret = -ENODEV; + ret = ath_init_device(id->device, sc); + if (ret) { + dev_err(&pdev->dev, "failed to initialize device\n"); goto bad3; } /* setup interrupt service routine */ - if (request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc)) { - printk(KERN_ERR "%s: request_irq failed\n", - wiphy_name(hw->wiphy)); - ret = -EIO; + ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc); + if (ret) { + dev_err(&pdev->dev, "request_irq failed\n"); goto bad4; } -- cgit v1.2.3-18-g5258 From fc548af877374f7e26c4f670f3843c6d29e02a98 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 2 Sep 2009 17:06:21 -0700 Subject: ath9k: claim irq for ath9k, not ath for pci ath9k ahb requests an IRQ and indicates 'ath9k' claimed it, ath9k pci requests an IRQ and indicates 'ath' claims it; since 'ath' is another module sync both ahb and pci to claim the irq using 'ath9k'. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index bc4bc2c2d37..8bb286df71b 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -187,7 +187,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* setup interrupt service routine */ - ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc); + ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { dev_err(&pdev->dev, "request_irq failed\n"); goto bad4; -- cgit v1.2.3-18-g5258 From 7ea310be65bfcbc6e2395844fd3498762dc2aea6 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 3 Sep 2009 12:08:43 +0530 Subject: ath9k: Fix RX Filter handling for BAR BAR frames have to be sent to mac80211 only if the current channel is HT. Also, move the macro to enum ath9k_rx_filter. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 3 ++- drivers/net/wireless/ath/ath9k/mac.h | 1 + drivers/net/wireless/ath/ath9k/main.c | 2 +- drivers/net/wireless/ath/ath9k/recv.c | 3 +++ drivers/net/wireless/ath/ath9k/reg.h | 1 - 5 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 71f27f324ce..011b14f35e5 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3967,7 +3967,8 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) { u32 phybits; - REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff) | AR_RX_COMPR_BAR); + REG_WRITE(ah, AR_RX_FILTER, bits); + phybits = 0; if (bits & ATH9K_RX_FILTER_PHYRADAR) phybits |= AR_PHY_ERR_RADAR; diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 7b3982295a4..f56e77da6c3 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -568,6 +568,7 @@ enum ath9k_rx_filter { ATH9K_RX_FILTER_PROBEREQ = 0x00000080, ATH9K_RX_FILTER_PHYERR = 0x00000100, ATH9K_RX_FILTER_MYBEACON = 0x00000200, + ATH9K_RX_FILTER_COMP_BAR = 0x00000400, ATH9K_RX_FILTER_PSPOLL = 0x00004000, ATH9K_RX_FILTER_PHYRADAR = 0x00002000, ATH9K_RX_FILTER_MCAST_BCAST_ALL = 0x00008000, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c2efdf2d72d..b1d189c6be8 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2433,7 +2433,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, ath9k_hw_setrxfilter(sc->sc_ah, rfilt); ath9k_ps_restore(sc); - DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter); + DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", rfilt); } static void ath9k_sta_notify(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 52e62daad3c..ec0abf82399 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -423,6 +423,9 @@ u32 ath_calcrxfilter(struct ath_softc *sc) if (sc->rx.rxfilter & FIF_PSPOLL) rfilt |= ATH9K_RX_FILTER_PSPOLL; + if (conf_is_ht(&sc->hw->conf)) + rfilt |= ATH9K_RX_FILTER_COMP_BAR; + if (sc->sec_wiphy || (sc->rx.rxfilter & FIF_OTHER_BSS)) { /* TODO: only needed if more than one BSSID is in use in * station/adhoc mode */ diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 3ddb243f000..e5c29eb86e8 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1325,7 +1325,6 @@ enum { #define AR_CFP_VAL 0x0000FFFF #define AR_RX_FILTER 0x803C -#define AR_RX_COMPR_BAR 0x00000400 #define AR_MCAST_FIL0 0x8040 #define AR_MCAST_FIL1 0x8044 -- cgit v1.2.3-18-g5258 From 8813262ea79acf9daa0e03901bdfe93db4dc4ca5 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 3 Sep 2009 12:08:53 +0530 Subject: ath9k: Fix channelFlags for 2GHZ CHANNEL_G has to be set for 2GHZ channels since IS_CHAN_G() checks for this in channelFlags and not in chanmode. To make things messier, ath9k_hw_process_ini() checks for CHANNEL_G in chanmode and not in channelFlags. The supreme, brain-searing fix is to set the flag in both cases. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b1d189c6be8..a69fda8a910 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1879,7 +1879,7 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, if (chan->band == IEEE80211_BAND_2GHZ) { ichan->chanmode = CHANNEL_G; - ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM; + ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G; } else { ichan->chanmode = CHANNEL_A; ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; -- cgit v1.2.3-18-g5258 From d9c35a506ed7770301f705a9070e05f0c5fae4bd Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Thu, 3 Sep 2009 20:25:31 +0200 Subject: ar9170: implement frequency calibration for one-stage/openfw This patch ports some code from the vendor driver, which is supposed to upload the right calibration values for the chosen frequency. In theory, this should give a better range and throughput for all users with the open, or one-stage firmware. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/phy.c | 122 ++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c index 3ace58ab40c..108ebfe21fc 100644 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ b/drivers/net/wireless/ath/ar9170/phy.c @@ -1120,6 +1120,124 @@ static u8 ar9170_interpolate_u8(u8 x, u8 x1, u8 y1, u8 x2, u8 y2) #undef SHIFT } +static u8 ar9170_interpolate_val(u8 x, u8 *x_array, u8 *y_array) +{ + int i; + + for (i = 0; i < 3; i++) + if (x <= x_array[i + 1]) + break; + + return ar9170_interpolate_u8(x, + x_array[i], + y_array[i], + x_array[i + 1], + y_array[i + 1]); +} + +static int ar9170_set_freq_cal_data(struct ar9170 *ar, + struct ieee80211_channel *channel) +{ + u8 *cal_freq_pier; + u8 vpds[2][AR5416_PD_GAIN_ICEPTS]; + u8 pwrs[2][AR5416_PD_GAIN_ICEPTS]; + int chain, idx, i; + u8 f; + + switch (channel->band) { + case IEEE80211_BAND_2GHZ: + f = channel->center_freq - 2300; + cal_freq_pier = ar->eeprom.cal_freq_pier_2G; + i = AR5416_NUM_2G_CAL_PIERS - 1; + break; + + case IEEE80211_BAND_5GHZ: + f = (channel->center_freq - 4800) / 5; + cal_freq_pier = ar->eeprom.cal_freq_pier_5G; + i = AR5416_NUM_5G_CAL_PIERS - 1; + break; + + default: + return -EINVAL; + break; + } + + for (; i >= 0; i--) { + if (cal_freq_pier[i] != 0xff) + break; + } + if (i < 0) + return -EINVAL; + + idx = ar9170_find_freq_idx(i, cal_freq_pier, f); + + ar9170_regwrite_begin(ar); + + for (chain = 0; chain < AR5416_MAX_CHAINS; chain++) { + for (i = 0; i < AR5416_PD_GAIN_ICEPTS; i++) { + struct ar9170_calibration_data_per_freq *cal_pier_data; + int j; + + switch (channel->band) { + case IEEE80211_BAND_2GHZ: + cal_pier_data = &ar->eeprom. + cal_pier_data_2G[chain][idx]; + break; + + case IEEE80211_BAND_5GHZ: + cal_pier_data = &ar->eeprom. + cal_pier_data_5G[chain][idx]; + break; + + default: + return -EINVAL; + } + + for (j = 0; j < 2; j++) { + vpds[j][i] = ar9170_interpolate_u8(f, + cal_freq_pier[idx], + cal_pier_data->vpd_pdg[j][i], + cal_freq_pier[idx + 1], + cal_pier_data[1].vpd_pdg[j][i]); + + pwrs[j][i] = ar9170_interpolate_u8(f, + cal_freq_pier[idx], + cal_pier_data->pwr_pdg[j][i], + cal_freq_pier[idx + 1], + cal_pier_data[1].pwr_pdg[j][i]) / 2; + } + } + + for (i = 0; i < 76; i++) { + u32 phy_data; + u8 tmp; + + if (i < 25) { + tmp = ar9170_interpolate_val(i, &pwrs[0][0], + &vpds[0][0]); + } else { + tmp = ar9170_interpolate_val(i - 12, + &pwrs[1][0], + &vpds[1][0]); + } + + phy_data |= tmp << ((i & 3) << 3); + if ((i & 3) == 3) { + ar9170_regwrite(0x1c6280 + chain * 0x1000 + + (i & ~3), phy_data); + phy_data = 0; + } + } + + for (i = 19; i < 32; i++) + ar9170_regwrite(0x1c6280 + chain * 0x1000 + (i << 2), + 0x0); + } + + ar9170_regwrite_finish(); + return ar9170_regwrite_result(); +} + static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) { struct ar9170_calibration_target_power_legacy *ctpl; @@ -1340,6 +1458,10 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, if (err) return err; + err = ar9170_set_freq_cal_data(ar, channel); + if (err) + return err; + err = ar9170_set_power_cal(ar, channel->center_freq, bw); if (err) return err; -- cgit v1.2.3-18-g5258 From 36dbd9548e92268127b0c31b0e121e63e9207108 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 4 Sep 2009 22:51:29 +0200 Subject: b43: Use a threaded IRQ handler Use a threaded IRQ handler to allow locking the mutex and sleeping while executing an interrupt. This removes usage of the irq_lock spinlock, but introduces a new hardirq_lock, which is _only_ used for the PCI/SSB lowlevel hard-irq handler. Sleeping busses (SDIO) will use mutex instead. Signed-off-by: Michael Buesch Tested-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 23 +-- drivers/net/wireless/b43/debugfs.c | 53 ++---- drivers/net/wireless/b43/debugfs.h | 3 +- drivers/net/wireless/b43/dma.c | 5 +- drivers/net/wireless/b43/main.c | 319 ++++++++++++++++++---------------- drivers/net/wireless/b43/phy_common.c | 1 - drivers/net/wireless/b43/phy_common.h | 3 +- drivers/net/wireless/b43/phy_g.c | 7 - drivers/net/wireless/b43/phy_g.h | 3 +- drivers/net/wireless/b43/pio.c | 5 +- drivers/net/wireless/b43/sysfs.c | 3 - 11 files changed, 204 insertions(+), 221 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index a1b3b731935..d63af926d05 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -616,6 +616,12 @@ struct b43_wl { /* Pointer to the ieee80211 hardware data structure */ struct ieee80211_hw *hw; + /* Global driver mutex. Every operation must run with this mutex locked. */ + struct mutex mutex; + /* Hard-IRQ spinlock. This lock protects things used in the hard-IRQ + * handler, only. This basically is just the IRQ mask register. */ + spinlock_t hardirq_lock; + /* The number of queues that were registered with the mac80211 subsystem * initially. This is a backup copy of hw->queues in case hw->queues has * to be dynamically lowered at runtime (Firmware does not support QoS). @@ -623,8 +629,6 @@ struct b43_wl { * from the mac80211 subsystem. */ u16 mac80211_initially_registered_queues; - struct mutex mutex; - spinlock_t irq_lock; /* R/W lock for data transmission. * Transmissions on 2+ queues can run concurrently, but somebody else * might sync with TX by write_lock_irqsave()'ing. */ @@ -665,8 +669,7 @@ struct b43_wl { bool radiotap_enabled; bool radio_enabled; - /* The beacon we are currently using (AP or IBSS mode). - * This beacon stuff is protected by the irq_lock. */ + /* The beacon we are currently using (AP or IBSS mode). */ struct sk_buff *current_beacon; bool beacon0_uploaded; bool beacon1_uploaded; @@ -754,14 +757,6 @@ enum { smp_wmb(); \ } while (0) -/* XXX--- HOW LOCKING WORKS IN B43 ---XXX - * - * You should always acquire both, wl->mutex and wl->irq_lock unless: - * - You don't need to acquire wl->irq_lock, if the interface is stopped. - * - You don't need to acquire wl->mutex in the IRQ handler, IRQ tasklet - * and packet TX path (and _ONLY_ there.) - */ - /* Data structure for one wireless device (802.11 core) */ struct b43_wldev { struct ssb_device *dev; @@ -807,14 +802,12 @@ struct b43_wldev { u32 dma_reason[6]; /* The currently active generic-interrupt mask. */ u32 irq_mask; + /* Link Quality calculation context. */ struct b43_noise_calculation noisecalc; /* if > 0 MAC is suspended. if == 0 MAC is enabled. */ int mac_suspended; - /* Interrupt Service Routine tasklet (bottom-half) */ - struct tasklet_struct isr_tasklet; - /* Periodic tasks */ struct delayed_work periodic_work; unsigned int periodic_state; diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index 45e3d6af69f..bf23a3a863f 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -46,8 +46,6 @@ struct b43_debugfs_fops { struct file_operations fops; /* Offset of struct b43_dfs_file in struct b43_dfsentry */ size_t file_struct_offset; - /* Take wl->irq_lock before calling read/write? */ - bool take_irqlock; }; static inline @@ -372,14 +370,12 @@ static ssize_t txstat_read_file(struct b43_wldev *dev, { struct b43_txstatus_log *log = &dev->dfsentry->txstatlog; ssize_t count = 0; - unsigned long flags; int i, idx; struct b43_txstatus *stat; - spin_lock_irqsave(&log->lock, flags); if (log->end < 0) { fappend("Nothing transmitted, yet\n"); - goto out_unlock; + goto out; } fappend("b43 TX status reports:\n\n" "index | cookie | seq | phy_stat | frame_count | " @@ -409,13 +405,11 @@ static ssize_t txstat_read_file(struct b43_wldev *dev, break; i++; } -out_unlock: - spin_unlock_irqrestore(&log->lock, flags); +out: return count; } -/* wl->irq_lock is locked */ static int restart_write_file(struct b43_wldev *dev, const char *buf, size_t count) { @@ -556,12 +550,7 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf, goto out_unlock; } memset(buf, 0, bufsize); - if (dfops->take_irqlock) { - spin_lock_irq(&dev->wl->irq_lock); - ret = dfops->read(dev, buf, bufsize); - spin_unlock_irq(&dev->wl->irq_lock); - } else - ret = dfops->read(dev, buf, bufsize); + ret = dfops->read(dev, buf, bufsize); if (ret <= 0) { free_pages((unsigned long)buf, buforder); err = ret; @@ -623,12 +612,7 @@ static ssize_t b43_debugfs_write(struct file *file, err = -EFAULT; goto out_freepage; } - if (dfops->take_irqlock) { - spin_lock_irq(&dev->wl->irq_lock); - err = dfops->write(dev, buf, count); - spin_unlock_irq(&dev->wl->irq_lock); - } else - err = dfops->write(dev, buf, count); + err = dfops->write(dev, buf, count); if (err) goto out_freepage; @@ -641,7 +625,7 @@ out_unlock: } -#define B43_DEBUGFS_FOPS(name, _read, _write, _take_irqlock) \ +#define B43_DEBUGFS_FOPS(name, _read, _write) \ static struct b43_debugfs_fops fops_##name = { \ .read = _read, \ .write = _write, \ @@ -652,20 +636,19 @@ out_unlock: }, \ .file_struct_offset = offsetof(struct b43_dfsentry, \ file_##name), \ - .take_irqlock = _take_irqlock, \ } -B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file, 1); -B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file, 1); -B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file, 1); -B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file, 1); -B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file, 1); -B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file, 1); -B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file, 1); -B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file, 1); -B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0); -B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1); -B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL, 0); +B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file); +B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file); +B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file); +B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file); +B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file); +B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file); +B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file); +B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file); +B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL); +B43_DEBUGFS_FOPS(restart, NULL, restart_write_file); +B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL); bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature) @@ -738,7 +721,6 @@ void b43_debugfs_add_device(struct b43_wldev *dev) return; } log->end = -1; - spin_lock_init(&log->lock); dev->dfsentry = e; @@ -822,7 +804,6 @@ void b43_debugfs_remove_device(struct b43_wldev *dev) kfree(e); } -/* Called with IRQs disabled. */ void b43_debugfs_log_txstat(struct b43_wldev *dev, const struct b43_txstatus *status) { @@ -834,14 +815,12 @@ void b43_debugfs_log_txstat(struct b43_wldev *dev, if (!e) return; log = &e->txstatlog; - spin_lock(&log->lock); /* IRQs are already disabled. */ i = log->end + 1; if (i == B43_NR_LOGGED_TXSTATUS) i = 0; log->end = i; cur = &(log->log[i]); memcpy(cur, status, sizeof(*cur)); - spin_unlock(&log->lock); } void b43_debugfs_init(void) diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h index b9d4de4a979..e47b4b488b0 100644 --- a/drivers/net/wireless/b43/debugfs.h +++ b/drivers/net/wireless/b43/debugfs.h @@ -23,9 +23,10 @@ struct dentry; #define B43_NR_LOGGED_TXSTATUS 100 struct b43_txstatus_log { + /* This structure is protected by wl->mutex */ + struct b43_txstatus *log; int end; - spinlock_t lock; }; struct b43_dfs_file { diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 289aaf6dfe7..25ced8bdec8 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1387,7 +1387,6 @@ out_unlock: return err; } -/* Called with IRQs disabled. */ void b43_dma_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status) { @@ -1402,7 +1401,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, if (unlikely(!ring)) return; - spin_lock(&ring->lock); /* IRQs are already disabled. */ + spin_lock_irq(&ring->lock); B43_WARN_ON(!ring->tx); ops = ring->ops; @@ -1463,7 +1462,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, } } - spin_unlock(&ring->lock); + spin_unlock_irq(&ring->lock); } void b43_dma_get_tx_stats(struct b43_wldev *dev, diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index ae05f667114..80b688441ff 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -291,7 +291,7 @@ static struct ieee80211_supported_band b43_band_2GHz = { static void b43_wireless_core_exit(struct b43_wldev *dev); static int b43_wireless_core_init(struct b43_wldev *dev); -static void b43_wireless_core_stop(struct b43_wldev *dev); +static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev); static int b43_wireless_core_start(struct b43_wldev *dev); static int b43_ratelimit(struct b43_wl *wl) @@ -685,16 +685,6 @@ static void b43_short_slot_timing_disable(struct b43_wldev *dev) b43_set_slot_time(dev, 20); } -/* Synchronize IRQ top- and bottom-half. - * IRQs must be masked before calling this. - * This must not be called with the irq_lock held. - */ -static void b43_synchronize_irq(struct b43_wldev *dev) -{ - synchronize_irq(dev->dev->irq); - tasklet_kill(&dev->isr_tasklet); -} - /* DummyTransmission function, as documented on * http://bcm-v4.sipsolutions.net/802.11/DummyTransmission */ @@ -720,8 +710,7 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) buffer[0] = 0x000B846E; } - spin_lock_irq(&wl->irq_lock); - write_lock(&wl->tx_lock); + write_lock_irq(&wl->tx_lock); for (i = 0; i < 5; i++) b43_ram_write(dev, i * 4, buffer[i]); @@ -779,8 +768,7 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) b43_radio_write16(dev, 0x0051, 0x0037); - write_unlock(&wl->tx_lock); - spin_unlock_irq(&wl->irq_lock); + write_unlock_irq(&wl->tx_lock); } static void key_write(struct b43_wldev *dev, @@ -1620,6 +1608,27 @@ static void handle_irq_beacon(struct b43_wldev *dev) } } +static void b43_do_beacon_update_trigger_work(struct b43_wldev *dev) +{ + u32 old_irq_mask = dev->irq_mask; + + /* update beacon right away or defer to irq */ + handle_irq_beacon(dev); + if (old_irq_mask != dev->irq_mask) { + /* The handler updated the IRQ mask. */ + B43_WARN_ON(!dev->irq_mask); + if (b43_read32(dev, B43_MMIO_GEN_IRQ_MASK)) { + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); + } else { + /* Device interrupts are currently disabled. That means + * we just ran the hardirq handler and scheduled the + * IRQ thread. The thread will write the IRQ mask when + * it finished, so there's nothing to do here. Writing + * the mask _here_ would incorrectly re-enable IRQs. */ + } + } +} + static void b43_beacon_update_trigger_work(struct work_struct *work) { struct b43_wl *wl = container_of(work, struct b43_wl, @@ -1629,19 +1638,22 @@ static void b43_beacon_update_trigger_work(struct work_struct *work) mutex_lock(&wl->mutex); dev = wl->current_dev; if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) { - spin_lock_irq(&wl->irq_lock); - /* update beacon right away or defer to irq */ - handle_irq_beacon(dev); - /* The handler might have updated the IRQ mask. */ - b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); - mmiowb(); - spin_unlock_irq(&wl->irq_lock); + if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) { + /* wl->mutex is enough. */ + b43_do_beacon_update_trigger_work(dev); + mmiowb(); + } else { + spin_lock_irq(&wl->hardirq_lock); + b43_do_beacon_update_trigger_work(dev); + mmiowb(); + spin_unlock_irq(&wl->hardirq_lock); + } } mutex_unlock(&wl->mutex); } /* Asynchronously update the packet templates in template RAM. - * Locking: Requires wl->irq_lock to be locked. */ + * Locking: Requires wl->mutex to be locked. */ static void b43_update_templates(struct b43_wl *wl) { struct sk_buff *beacon; @@ -1778,18 +1790,15 @@ out: B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK); } -/* Interrupt handler bottom-half */ -static void b43_interrupt_tasklet(struct b43_wldev *dev) +static void b43_do_interrupt_thread(struct b43_wldev *dev) { u32 reason; u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; u32 merged_dma_reason = 0; int i; - unsigned long flags; - - spin_lock_irqsave(&dev->wl->irq_lock, flags); - B43_WARN_ON(b43_status(dev) != B43_STAT_STARTED); + if (unlikely(b43_status(dev) != B43_STAT_STARTED)) + return; reason = dev->irq_reason; for (i = 0; i < ARRAY_SIZE(dma_reason); i++) { @@ -1822,8 +1831,6 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) dma_reason[2], dma_reason[3], dma_reason[4], dma_reason[5]); b43_controller_restart(dev, "DMA error"); - mmiowb(); - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); return; } if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) { @@ -1867,47 +1874,36 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) if (reason & B43_IRQ_TX_OK) handle_irq_transmit_status(dev); + /* Re-enable interrupts on the device by restoring the current interrupt mask. */ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); - mmiowb(); - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); } -static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason) +/* Interrupt thread handler. Handles device interrupts in thread context. */ +static irqreturn_t b43_interrupt_thread_handler(int irq, void *dev_id) { - b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason); + struct b43_wldev *dev = dev_id; - b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]); - b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]); - b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]); - b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]); - b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]); -/* Unused ring - b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]); -*/ + mutex_lock(&dev->wl->mutex); + b43_do_interrupt_thread(dev); + mmiowb(); + mutex_unlock(&dev->wl->mutex); + + return IRQ_HANDLED; } -/* Interrupt handler top-half */ -static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) +static irqreturn_t b43_do_interrupt(struct b43_wldev *dev) { - irqreturn_t ret = IRQ_NONE; - struct b43_wldev *dev = dev_id; u32 reason; - B43_WARN_ON(!dev); + /* This code runs under wl->hardirq_lock, but _only_ on non-SDIO busses. + * On SDIO, this runs under wl->mutex. */ - spin_lock(&dev->wl->irq_lock); - - if (unlikely(b43_status(dev) < B43_STAT_STARTED)) { - /* This can only happen on shared IRQ lines. */ - goto out; - } reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); if (reason == 0xffffffff) /* shared IRQ */ - goto out; - ret = IRQ_HANDLED; + return IRQ_NONE; reason &= dev->irq_mask; if (!reason) - goto out; + return IRQ_HANDLED; dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON) & 0x0001DC00; @@ -1924,15 +1920,38 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) & 0x0000DC00; */ - b43_interrupt_ack(dev, reason); - /* disable all IRQs. They are enabled again in the bottom half. */ + /* ACK the interrupt. */ + b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason); + b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]); + b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]); + b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]); + b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]); + b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]); +/* Unused ring + b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]); +*/ + + /* Disable IRQs on the device. The IRQ thread handler will re-enable them. */ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); - /* save the reason code and call our bottom half. */ + /* Save the reason bitmasks for the IRQ thread handler. */ dev->irq_reason = reason; - tasklet_schedule(&dev->isr_tasklet); -out: + + return IRQ_WAKE_THREAD; +} + +/* Interrupt handler top-half. This runs with interrupts disabled. */ +static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) +{ + struct b43_wldev *dev = dev_id; + irqreturn_t ret; + + if (unlikely(b43_status(dev) < B43_STAT_STARTED)) + return IRQ_NONE; + + spin_lock(&dev->wl->hardirq_lock); + ret = b43_do_interrupt(dev); mmiowb(); - spin_unlock(&dev->wl->irq_lock); + spin_unlock(&dev->wl->hardirq_lock); return ret; } @@ -3038,15 +3057,12 @@ static void b43_security_init(struct b43_wldev *dev) static int b43_rng_read(struct hwrng *rng, u32 *data) { struct b43_wl *wl = (struct b43_wl *)rng->priv; - unsigned long flags; - /* Don't take wl->mutex here, as it could deadlock with - * hwrng internal locking. It's not needed to take - * wl->mutex here, anyway. */ + /* FIXME: We need to take wl->mutex here to make sure the device + * is not going away from under our ass. However it could deadlock + * with hwrng internal locking. */ - spin_lock_irqsave(&wl->irq_lock, flags); *data = b43_read16(wl->current_dev, B43_MMIO_RNG); - spin_unlock_irqrestore(&wl->irq_lock, flags); return (sizeof(u16)); } @@ -3283,22 +3299,20 @@ static int b43_op_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats) { struct b43_wl *wl = hw_to_b43_wl(hw); - struct b43_wldev *dev = wl->current_dev; - unsigned long flags; + struct b43_wldev *dev; int err = -ENODEV; - if (!dev) - goto out; - spin_lock_irqsave(&wl->irq_lock, flags); - if (likely(b43_status(dev) >= B43_STAT_STARTED)) { + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (dev && b43_status(dev) >= B43_STAT_STARTED) { if (b43_using_pio_transfers(dev)) b43_pio_get_tx_stats(dev, stats); else b43_dma_get_tx_stats(dev, stats); err = 0; } - spin_unlock_irqrestore(&wl->irq_lock, flags); -out: + mutex_unlock(&wl->mutex); + return err; } @@ -3306,11 +3320,10 @@ static int b43_op_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { struct b43_wl *wl = hw_to_b43_wl(hw); - unsigned long flags; - spin_lock_irqsave(&wl->irq_lock, flags); + mutex_lock(&wl->mutex); memcpy(stats, &wl->ieee_stats, sizeof(*stats)); - spin_unlock_irqrestore(&wl->irq_lock, flags); + mutex_unlock(&wl->mutex); return 0; } @@ -3322,7 +3335,6 @@ static u64 b43_op_get_tsf(struct ieee80211_hw *hw) u64 tsf; mutex_lock(&wl->mutex); - spin_lock_irq(&wl->irq_lock); dev = wl->current_dev; if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) @@ -3330,7 +3342,6 @@ static u64 b43_op_get_tsf(struct ieee80211_hw *hw) else tsf = 0; - spin_unlock_irq(&wl->irq_lock); mutex_unlock(&wl->mutex); return tsf; @@ -3342,13 +3353,11 @@ static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf) struct b43_wldev *dev; mutex_lock(&wl->mutex); - spin_lock_irq(&wl->irq_lock); dev = wl->current_dev; if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) b43_tsf_write(dev, tsf); - spin_unlock_irq(&wl->irq_lock); mutex_unlock(&wl->mutex); } @@ -3434,7 +3443,7 @@ static int b43_switch_band(struct b43_wl *wl, struct ieee80211_channel *chan) prev_status = b43_status(down_dev); /* Shutdown the currently running core. */ if (prev_status >= B43_STAT_STARTED) - b43_wireless_core_stop(down_dev); + down_dev = b43_wireless_core_stop(down_dev); if (prev_status >= B43_STAT_INITIALIZED) b43_wireless_core_exit(down_dev); @@ -3498,7 +3507,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) struct b43_wldev *dev; struct b43_phy *phy; struct ieee80211_conf *conf = &hw->conf; - unsigned long flags; int antenna; int err = 0; @@ -3529,13 +3537,11 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) /* Adjust the desired TX power level. */ if (conf->power_level != 0) { - spin_lock_irqsave(&wl->irq_lock, flags); if (conf->power_level != phy->desired_txpower) { phy->desired_txpower = conf->power_level; b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME | B43_TXPWR_IGNORE_TSSI); } - spin_unlock_irqrestore(&wl->irq_lock, flags); } /* Antennas for RX and management frame TX. */ @@ -3620,7 +3626,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; - unsigned long flags; mutex_lock(&wl->mutex); @@ -3630,7 +3635,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, B43_WARN_ON(wl->vif != vif); - spin_lock_irqsave(&wl->irq_lock, flags); if (changed & BSS_CHANGED_BSSID) { if (conf->bssid) memcpy(wl->bssid, conf->bssid, ETH_ALEN); @@ -3648,7 +3652,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BSSID) b43_write_mac_bssid_templates(dev); } - spin_unlock_irqrestore(&wl->irq_lock, flags); b43_mac_suspend(dev); @@ -3683,18 +3686,15 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, u8 algorithm; u8 index; int err; + unsigned long flags; static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; if (modparam_nohwcrypt) return -ENOSPC; /* User disabled HW-crypto */ mutex_lock(&wl->mutex); - spin_lock_irq(&wl->irq_lock); - write_lock(&wl->tx_lock); - /* Why do we need all this locking here? - * mutex -> Every config operation must take it. - * irq_lock -> We modify the dev->key array, which is accessed - * in the IRQ handlers. + write_lock_irqsave(&wl->tx_lock, flags); + /* mutex -> Every config operation must take it. * tx_lock -> We modify the dev->key array, which is accessed * in the TX handler. */ @@ -3789,8 +3789,7 @@ out_unlock: sta ? sta->addr : bcast_addr); b43_dump_keymemory(dev); } - write_unlock(&wl->tx_lock); - spin_unlock_irq(&wl->irq_lock); + write_unlock_irqrestore(&wl->tx_lock, flags); mutex_unlock(&wl->mutex); return err; @@ -3801,15 +3800,15 @@ static void b43_op_configure_filter(struct ieee80211_hw *hw, u64 multicast) { struct b43_wl *wl = hw_to_b43_wl(hw); - struct b43_wldev *dev = wl->current_dev; - unsigned long flags; + struct b43_wldev *dev; + mutex_lock(&wl->mutex); + dev = wl->current_dev; if (!dev) { *fflags = 0; - return; + goto out_unlock; } - spin_lock_irqsave(&wl->irq_lock, flags); *fflags &= FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | @@ -3830,41 +3829,66 @@ static void b43_op_configure_filter(struct ieee80211_hw *hw, if (changed && b43_status(dev) >= B43_STAT_INITIALIZED) b43_adjust_opmode(dev); - spin_unlock_irqrestore(&wl->irq_lock, flags); + +out_unlock: + mutex_unlock(&wl->mutex); } -/* Locking: wl->mutex */ -static void b43_wireless_core_stop(struct b43_wldev *dev) +/* Locking: wl->mutex + * Returns the current dev. This might be different from the passed in dev, + * because the core might be gone away while we unlocked the mutex. */ +static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev) { struct b43_wl *wl = dev->wl; - unsigned long flags; + struct b43_wldev *orig_dev; - if (b43_status(dev) < B43_STAT_STARTED) - return; +redo: + if (!dev || b43_status(dev) < B43_STAT_STARTED) + return dev; - /* Disable and sync interrupts. We must do this before than - * setting the status to INITIALIZED, as the interrupt handler - * won't care about IRQs then. */ - spin_lock_irqsave(&wl->irq_lock, flags); - b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); - b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */ - spin_unlock_irqrestore(&wl->irq_lock, flags); - b43_synchronize_irq(dev); + /* Disable periodic work. Unlock to avoid deadlocks. */ + mutex_unlock(&wl->mutex); + cancel_delayed_work_sync(&dev->periodic_work); + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (!dev || b43_status(dev) < B43_STAT_STARTED) { + /* Whoops, aliens ate up the device while we were unlocked. */ + return dev; + } - write_lock_irqsave(&wl->tx_lock, flags); + /* Disable interrupts on the device. */ b43_set_status(dev, B43_STAT_INITIALIZED); - write_unlock_irqrestore(&wl->tx_lock, flags); - - b43_pio_stop(dev); + if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) { + /* wl->mutex is locked. That is enough. */ + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); + b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */ + } else { + spin_lock_irq(&wl->hardirq_lock); + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); + b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */ + spin_unlock_irq(&wl->hardirq_lock); + } + /* Synchronize the interrupt handlers. Unlock to avoid deadlocks. */ + orig_dev = dev; mutex_unlock(&wl->mutex); - /* Must unlock as it would otherwise deadlock. No races here. - * Cancel the possibly running self-rearming periodic work. */ - cancel_delayed_work_sync(&dev->periodic_work); + synchronize_irq(dev->dev->irq); mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (!dev) + return dev; + if (dev != orig_dev) { + if (b43_status(dev) >= B43_STAT_STARTED) + goto redo; + return dev; + } + B43_WARN_ON(b43_read32(dev, B43_MMIO_GEN_IRQ_MASK)); + b43_pio_stop(dev); b43_mac_suspend(dev); free_irq(dev->dev->irq, dev); b43dbg(wl, "Wireless interface stopped\n"); + + return dev; } /* Locking: wl->mutex */ @@ -3875,8 +3899,9 @@ static int b43_wireless_core_start(struct b43_wldev *dev) B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED); drain_txstatus_queue(dev); - err = request_irq(dev->dev->irq, b43_interrupt_handler, - IRQF_SHARED, KBUILD_MODNAME, dev); + err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler, + b43_interrupt_thread_handler, + IRQF_SHARED, KBUILD_MODNAME, dev); if (err) { b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq); goto out; @@ -4155,8 +4180,8 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) { u32 macctl; - B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED); - if (b43_status(dev) != B43_STAT_INITIALIZED) + B43_WARN_ON(dev && b43_status(dev) > B43_STAT_INITIALIZED); + if (!dev || b43_status(dev) != B43_STAT_INITIALIZED) return; b43_set_status(dev, B43_STAT_UNINIT); @@ -4309,7 +4334,6 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; - unsigned long flags; int err = -EOPNOTSUPP; /* TODO: allow WDS/AP devices to coexist */ @@ -4333,12 +4357,10 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, wl->if_type = conf->type; memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); - spin_lock_irqsave(&wl->irq_lock, flags); b43_adjust_opmode(dev); b43_set_pretbtt(dev); b43_set_synth_pu_delay(dev, 0); b43_upload_card_macaddress(dev); - spin_unlock_irqrestore(&wl->irq_lock, flags); err = 0; out_mutex_unlock: @@ -4352,7 +4374,6 @@ static void b43_op_remove_interface(struct ieee80211_hw *hw, { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; - unsigned long flags; b43dbg(wl, "Removing Interface type %d\n", conf->type); @@ -4364,11 +4385,9 @@ static void b43_op_remove_interface(struct ieee80211_hw *hw, wl->operating = 0; - spin_lock_irqsave(&wl->irq_lock, flags); b43_adjust_opmode(dev); memset(wl->mac_addr, 0, ETH_ALEN); b43_upload_card_macaddress(dev); - spin_unlock_irqrestore(&wl->irq_lock, flags); mutex_unlock(&wl->mutex); } @@ -4428,10 +4447,15 @@ static void b43_op_stop(struct ieee80211_hw *hw) cancel_work_sync(&(wl->beacon_update_trigger)); mutex_lock(&wl->mutex); - if (b43_status(dev) >= B43_STAT_STARTED) - b43_wireless_core_stop(dev); + if (b43_status(dev) >= B43_STAT_STARTED) { + dev = b43_wireless_core_stop(dev); + if (!dev) + goto out_unlock; + } b43_wireless_core_exit(dev); wl->radio_enabled = 0; + +out_unlock: mutex_unlock(&wl->mutex); cancel_work_sync(&(wl->txpower_adjust_work)); @@ -4441,11 +4465,10 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) { struct b43_wl *wl = hw_to_b43_wl(hw); - unsigned long flags; - spin_lock_irqsave(&wl->irq_lock, flags); + mutex_lock(&wl->mutex); b43_update_templates(wl); - spin_unlock_irqrestore(&wl->irq_lock, flags); + mutex_unlock(&wl->mutex); return 0; } @@ -4526,8 +4549,13 @@ static void b43_chip_reset(struct work_struct *work) prev_status = b43_status(dev); /* Bring the device down... */ - if (prev_status >= B43_STAT_STARTED) - b43_wireless_core_stop(dev); + if (prev_status >= B43_STAT_STARTED) { + dev = b43_wireless_core_stop(dev); + if (!dev) { + err = -ENODEV; + goto out; + } + } if (prev_status >= B43_STAT_INITIALIZED) b43_wireless_core_exit(dev); @@ -4742,9 +4770,6 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl) wldev->wl = wl; b43_set_status(wldev, B43_STAT_UNINIT); wldev->bad_frames_preempt = modparam_bad_frames_preempt; - tasklet_init(&wldev->isr_tasklet, - (void (*)(unsigned long))b43_interrupt_tasklet, - (unsigned long)wldev); INIT_LIST_HEAD(&wldev->list); err = b43_wireless_core_attach(wldev); @@ -4841,11 +4866,11 @@ static int b43_wireless_init(struct ssb_device *dev) /* Initialize struct b43_wl */ wl->hw = hw; - spin_lock_init(&wl->irq_lock); rwlock_init(&wl->tx_lock); spin_lock_init(&wl->leds_lock); spin_lock_init(&wl->shm_lock); mutex_init(&wl->mutex); + spin_lock_init(&wl->hardirq_lock); INIT_LIST_HEAD(&wl->devlist); INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); @@ -4946,8 +4971,8 @@ static int b43_suspend(struct ssb_device *dev, pm_message_t state) wldev->suspend_in_progress = true; wldev->suspend_init_status = b43_status(wldev); if (wldev->suspend_init_status >= B43_STAT_STARTED) - b43_wireless_core_stop(wldev); - if (wldev->suspend_init_status >= B43_STAT_INITIALIZED) + wldev = b43_wireless_core_stop(wldev); + if (wldev && wldev->suspend_init_status >= B43_STAT_INITIALIZED) b43_wireless_core_exit(wldev); mutex_unlock(&wl->mutex); diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 6e704becda6..75b26e175e8 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -347,7 +347,6 @@ void b43_phy_txpower_adjust_work(struct work_struct *work) mutex_unlock(&wl->mutex); } -/* Called with wl->irq_lock locked */ void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags) { struct b43_phy *phy = &dev->phy; diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 28e384633c3..9edd4e8e0c8 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -131,7 +131,7 @@ enum b43_txpwr_result { * If the parameter "ignore_tssi" is true, the TSSI values should * be ignored and a recalculation of the power settings should be * done even if the TSSI values did not change. - * This callback is called with wl->irq_lock held and must not sleep. + * This function may sleep, but should not. * Must not be NULL. * @adjust_txpower: Write the previously calculated TX power settings * (from @recalc_txpower) to the hardware. @@ -379,7 +379,6 @@ void b43_software_rfkill(struct b43_wldev *dev, bool blocked); * * Compare the current TX power output to the desired power emission * and schedule an adjustment in case it mismatches. - * Requires wl->irq_lock locked. * * @flags: OR'ed enum b43_phy_txpower_check_flags flags. * See the docs below. diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 5afa4df0b02..382826a8da8 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -2823,8 +2823,6 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev) b43_mac_suspend(dev); - spin_lock_irq(&dev->wl->irq_lock); - /* Calculate the new attenuation values. */ bbatt = gphy->bbatt.att; bbatt += gphy->bbatt_delta; @@ -2864,11 +2862,6 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev) gphy->rfatt.att = rfatt; gphy->bbatt.att = bbatt; - /* We drop the lock early, so we can sleep during hardware - * adjustment. Possible races with op_recalc_txpower are harmless, - * as we will be called once again in case we raced. */ - spin_unlock_irq(&dev->wl->irq_lock); - if (b43_debug(dev, B43_DBG_XMITPOWER)) b43dbg(dev->wl, "Adjusting TX power\n"); diff --git a/drivers/net/wireless/b43/phy_g.h b/drivers/net/wireless/b43/phy_g.h index 718947fd41a..8569fdd4c6b 100644 --- a/drivers/net/wireless/b43/phy_g.h +++ b/drivers/net/wireless/b43/phy_g.h @@ -141,8 +141,7 @@ struct b43_phy_g { int tgt_idle_tssi; /* Current idle TSSI */ int cur_idle_tssi; - /* The current average TSSI. - * Needs irq_lock, as it's updated in the IRQ path. */ + /* The current average TSSI. */ u8 average_tssi; /* Current TX power level attenuation control values */ struct b43_bbatt bbatt; diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 3fd653c78b1..ce6f36eb88c 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -570,7 +570,6 @@ out_unlock: return err; } -/* Called with IRQs disabled. */ void b43_pio_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status) { @@ -584,7 +583,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, return; B43_WARN_ON(!pack); - spin_lock(&q->lock); /* IRQs are already disabled. */ + spin_lock_irq(&q->lock); info = IEEE80211_SKB_CB(pack->skb); @@ -604,7 +603,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, q->stopped = 0; } - spin_unlock(&q->lock); + spin_unlock_irq(&q->lock); } void b43_pio_get_tx_stats(struct b43_wldev *dev, diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c index 5adaa3692d7..f1ae4e05a32 100644 --- a/drivers/net/wireless/b43/sysfs.c +++ b/drivers/net/wireless/b43/sysfs.c @@ -94,7 +94,6 @@ static ssize_t b43_attr_interfmode_store(struct device *dev, const char *buf, size_t count) { struct b43_wldev *wldev = dev_to_b43_wldev(dev); - unsigned long flags; int err; int mode; @@ -120,7 +119,6 @@ static ssize_t b43_attr_interfmode_store(struct device *dev, } mutex_lock(&wldev->wl->mutex); - spin_lock_irqsave(&wldev->wl->irq_lock, flags); if (wldev->phy.ops->interf_mitigation) { err = wldev->phy.ops->interf_mitigation(wldev, mode); @@ -132,7 +130,6 @@ static ssize_t b43_attr_interfmode_store(struct device *dev, err = -ENOSYS; mmiowb(); - spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); mutex_unlock(&wldev->wl->mutex); return err ? err : count; -- cgit v1.2.3-18-g5258 From f5d40eedb32aa9a0e226d468e1f89fb676824694 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 4 Sep 2009 22:53:18 +0200 Subject: b43: Remove TX spinlock This removes the TX spinlock and defers TX to a workqueue to allow locking wl->mutex instead and to allow sleeping for register accesses. Signed-off-by: Michael Buesch Tested-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 5 +++ drivers/net/wireless/b43/main.c | 75 +++++++++++++++++++++-------------------- 2 files changed, 43 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index d63af926d05..1cd470d6e2d 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -683,6 +683,11 @@ struct b43_wl { * This is scheduled when we determine that the actual TX output * power doesn't match what we want. */ struct work_struct txpower_adjust_work; + + /* Packet transmit work */ + struct work_struct tx_work; + /* Queue of packets to be transmitted. */ + struct sk_buff_head tx_queue; }; /* The type of the firmware file. */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 80b688441ff..fca2fe947d7 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -690,7 +690,6 @@ static void b43_short_slot_timing_disable(struct b43_wldev *dev) */ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) { - struct b43_wl *wl = dev->wl; struct b43_phy *phy = &dev->phy; unsigned int i, max_loop; u16 value; @@ -710,8 +709,6 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) buffer[0] = 0x000B846E; } - write_lock_irq(&wl->tx_lock); - for (i = 0; i < 5; i++) b43_ram_write(dev, i * 4, buffer[i]); @@ -767,8 +764,6 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) } if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) b43_radio_write16(dev, 0x0051, 0x0037); - - write_unlock_irq(&wl->tx_lock); } static void key_write(struct b43_wldev *dev, @@ -3098,42 +3093,49 @@ static int b43_rng_init(struct b43_wl *wl) return err; } -static int b43_op_tx(struct ieee80211_hw *hw, - struct sk_buff *skb) +static void b43_tx_work(struct work_struct *work) { - struct b43_wl *wl = hw_to_b43_wl(hw); - struct b43_wldev *dev = wl->current_dev; - unsigned long flags; - int err; + struct b43_wl *wl = container_of(work, struct b43_wl, tx_work); + struct b43_wldev *dev; + struct sk_buff *skb; + int err = 0; - if (unlikely(skb->len < 2 + 2 + 6)) { - /* Too short, this can't be a valid frame. */ - goto drop_packet; + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (unlikely(!dev || b43_status(dev) < B43_STAT_STARTED)) { + mutex_unlock(&wl->mutex); + return; } - B43_WARN_ON(skb_shinfo(skb)->nr_frags); - if (unlikely(!dev)) - goto drop_packet; - /* Transmissions on seperate queues can run concurrently. */ - read_lock_irqsave(&wl->tx_lock, flags); + while (skb_queue_len(&wl->tx_queue)) { + skb = skb_dequeue(&wl->tx_queue); - err = -ENODEV; - if (likely(b43_status(dev) >= B43_STAT_STARTED)) { if (b43_using_pio_transfers(dev)) err = b43_pio_tx(dev, skb); else err = b43_dma_tx(dev, skb); + if (unlikely(err)) + dev_kfree_skb(skb); /* Drop it */ } - read_unlock_irqrestore(&wl->tx_lock, flags); + mutex_unlock(&wl->mutex); +} - if (unlikely(err)) - goto drop_packet; - return NETDEV_TX_OK; +static int b43_op_tx(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + + if (unlikely(skb->len < 2 + 2 + 6)) { + /* Too short, this can't be a valid frame. */ + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + B43_WARN_ON(skb_shinfo(skb)->nr_frags); + + skb_queue_tail(&wl->tx_queue, skb); + ieee80211_queue_work(wl->hw, &wl->tx_work); -drop_packet: - /* We can not transmit this packet. Drop it. */ - dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -3686,18 +3688,12 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, u8 algorithm; u8 index; int err; - unsigned long flags; static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; if (modparam_nohwcrypt) return -ENOSPC; /* User disabled HW-crypto */ mutex_lock(&wl->mutex); - write_lock_irqsave(&wl->tx_lock, flags); - /* mutex -> Every config operation must take it. - * tx_lock -> We modify the dev->key array, which is accessed - * in the TX handler. - */ dev = wl->current_dev; err = -ENODEV; @@ -3789,7 +3785,6 @@ out_unlock: sta ? sta->addr : bcast_addr); b43_dump_keymemory(dev); } - write_unlock_irqrestore(&wl->tx_lock, flags); mutex_unlock(&wl->mutex); return err; @@ -3846,9 +3841,10 @@ redo: if (!dev || b43_status(dev) < B43_STAT_STARTED) return dev; - /* Disable periodic work. Unlock to avoid deadlocks. */ + /* Cancel work. Unlock to avoid deadlocks. */ mutex_unlock(&wl->mutex); cancel_delayed_work_sync(&dev->periodic_work); + cancel_work_sync(&wl->tx_work); mutex_lock(&wl->mutex); dev = wl->current_dev; if (!dev || b43_status(dev) < B43_STAT_STARTED) { @@ -3883,6 +3879,10 @@ redo: } B43_WARN_ON(b43_read32(dev, B43_MMIO_GEN_IRQ_MASK)); + /* Drain the TX queue */ + while (skb_queue_len(&wl->tx_queue)) + dev_kfree_skb(skb_dequeue(&wl->tx_queue)); + b43_pio_stop(dev); b43_mac_suspend(dev); free_irq(dev->dev->irq, dev); @@ -4866,7 +4866,6 @@ static int b43_wireless_init(struct ssb_device *dev) /* Initialize struct b43_wl */ wl->hw = hw; - rwlock_init(&wl->tx_lock); spin_lock_init(&wl->leds_lock); spin_lock_init(&wl->shm_lock); mutex_init(&wl->mutex); @@ -4874,6 +4873,8 @@ static int b43_wireless_init(struct ssb_device *dev) INIT_LIST_HEAD(&wl->devlist); INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); + INIT_WORK(&wl->tx_work, b43_tx_work); + skb_queue_head_init(&wl->tx_queue); ssb_set_devtypedata(dev, wl); b43info(wl, "Broadcom %04X WLAN found (core revision %u)\n", -- cgit v1.2.3-18-g5258 From 637dae3f637eb7dab447e74362e0dfeded775c7c Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 4 Sep 2009 22:55:00 +0200 Subject: b43: Remove DMA/PIO queue locks This removes the DMA/PIO queue locks. Locking is handled by wl->mutex now. Signed-off-by: Michael Buesch Tested-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43/dma.c | 30 +++++------------------------- drivers/net/wireless/b43/dma.h | 3 --- drivers/net/wireless/b43/pio.c | 38 ++++++++------------------------------ drivers/net/wireless/b43/pio.h | 2 -- 4 files changed, 13 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 25ced8bdec8..a467ee260a1 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -856,7 +856,6 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, } else B43_WARN_ON(1); } - spin_lock_init(&ring->lock); #ifdef CONFIG_B43_DEBUG ring->last_injected_overflow = jiffies; #endif @@ -1315,7 +1314,6 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) struct b43_dmaring *ring; struct ieee80211_hdr *hdr; int err = 0; - unsigned long flags; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); hdr = (struct ieee80211_hdr *)skb->data; @@ -1331,8 +1329,6 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) dev, skb_get_queue_mapping(skb)); } - spin_lock_irqsave(&ring->lock, flags); - B43_WARN_ON(!ring->tx); if (unlikely(ring->stopped)) { @@ -1343,7 +1339,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) if (b43_debug(dev, B43_DBG_DMAVERBOSE)) b43err(dev->wl, "Packet after queue stopped\n"); err = -ENOSPC; - goto out_unlock; + goto out; } if (unlikely(WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME))) { @@ -1351,7 +1347,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) * full, but queues not stopped. */ b43err(dev->wl, "DMA queue overflow\n"); err = -ENOSPC; - goto out_unlock; + goto out; } /* Assign the queue number to the ring (if not already done before) @@ -1365,11 +1361,11 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) * anymore and must not transmit it unencrypted. */ dev_kfree_skb_any(skb); err = 0; - goto out_unlock; + goto out; } if (unlikely(err)) { b43err(dev->wl, "DMA tx mapping failure\n"); - goto out_unlock; + goto out; } ring->nr_tx_packets++; if ((free_slots(ring) < TX_SLOTS_PER_FRAME) || @@ -1381,8 +1377,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); } } -out_unlock: - spin_unlock_irqrestore(&ring->lock, flags); +out: return err; } @@ -1401,8 +1396,6 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, if (unlikely(!ring)) return; - spin_lock_irq(&ring->lock); - B43_WARN_ON(!ring->tx); ops = ring->ops; while (1) { @@ -1461,8 +1454,6 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); } } - - spin_unlock_irq(&ring->lock); } void b43_dma_get_tx_stats(struct b43_wldev *dev, @@ -1470,17 +1461,14 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev, { const int nr_queues = dev->wl->hw->queues; struct b43_dmaring *ring; - unsigned long flags; int i; for (i = 0; i < nr_queues; i++) { ring = select_ring_by_priority(dev, i); - spin_lock_irqsave(&ring->lock, flags); stats[i].len = ring->used_slots / TX_SLOTS_PER_FRAME; stats[i].limit = ring->nr_slots / TX_SLOTS_PER_FRAME; stats[i].count = ring->nr_tx_packets; - spin_unlock_irqrestore(&ring->lock, flags); } } @@ -1591,22 +1579,14 @@ void b43_dma_rx(struct b43_dmaring *ring) static void b43_dma_tx_suspend_ring(struct b43_dmaring *ring) { - unsigned long flags; - - spin_lock_irqsave(&ring->lock, flags); B43_WARN_ON(!ring->tx); ring->ops->tx_suspend(ring); - spin_unlock_irqrestore(&ring->lock, flags); } static void b43_dma_tx_resume_ring(struct b43_dmaring *ring) { - unsigned long flags; - - spin_lock_irqsave(&ring->lock, flags); B43_WARN_ON(!ring->tx); ring->ops->tx_resume(ring); - spin_unlock_irqrestore(&ring->lock, flags); } void b43_dma_tx_suspend(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index 05dde646d83..f0b0838fb5b 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h @@ -2,7 +2,6 @@ #define B43_DMA_H_ #include -#include #include "b43.h" @@ -244,8 +243,6 @@ struct b43_dmaring { /* The QOS priority assigned to this ring. Only used for TX rings. * This is the mac80211 "queue" value. */ u8 queue_prio; - /* Lock, only used for TX. */ - spinlock_t lock; struct b43_wldev *dev; #ifdef CONFIG_B43_DEBUG /* Maximum number of used slots. */ diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index ce6f36eb88c..4635baa9b99 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -144,7 +144,6 @@ static struct b43_pio_txqueue *b43_setup_pioqueue_tx(struct b43_wldev *dev, q = kzalloc(sizeof(*q), GFP_KERNEL); if (!q) return NULL; - spin_lock_init(&q->lock); q->dev = dev; q->rev = dev->dev->id.revision; q->mmio_base = index_to_pioqueue_base(dev, index) + @@ -179,7 +178,6 @@ static struct b43_pio_rxqueue *b43_setup_pioqueue_rx(struct b43_wldev *dev, q = kzalloc(sizeof(*q), GFP_KERNEL); if (!q) return NULL; - spin_lock_init(&q->lock); q->dev = dev; q->rev = dev->dev->id.revision; q->mmio_base = index_to_pioqueue_base(dev, index) + @@ -494,7 +492,6 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) { struct b43_pio_txqueue *q; struct ieee80211_hdr *hdr; - unsigned long flags; unsigned int hdrlen, total_len; int err = 0; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -512,20 +509,18 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) q = select_queue_by_priority(dev, skb_get_queue_mapping(skb)); } - spin_lock_irqsave(&q->lock, flags); - hdrlen = b43_txhdr_size(dev); total_len = roundup(skb->len + hdrlen, 4); if (unlikely(total_len > q->buffer_size)) { err = -ENOBUFS; b43dbg(dev->wl, "PIO: TX packet longer than queue.\n"); - goto out_unlock; + goto out; } if (unlikely(q->free_packet_slots == 0)) { err = -ENOBUFS; b43warn(dev->wl, "PIO: TX packet overflow.\n"); - goto out_unlock; + goto out; } B43_WARN_ON(q->buffer_used > q->buffer_size); @@ -534,7 +529,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) err = -EBUSY; ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = 1; - goto out_unlock; + goto out; } /* Assign the queue number to the ring (if not already done before) @@ -548,11 +543,11 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) * anymore and must not transmit it unencrypted. */ dev_kfree_skb_any(skb); err = 0; - goto out_unlock; + goto out; } if (unlikely(err)) { b43err(dev->wl, "PIO transmission failure\n"); - goto out_unlock; + goto out; } q->nr_tx_packets++; @@ -564,9 +559,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) q->stopped = 1; } -out_unlock: - spin_unlock_irqrestore(&q->lock, flags); - +out: return err; } @@ -583,8 +576,6 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, return; B43_WARN_ON(!pack); - spin_lock_irq(&q->lock); - info = IEEE80211_SKB_CB(pack->skb); b43_fill_txstatus_report(dev, info, status); @@ -602,8 +593,6 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, ieee80211_wake_queue(dev->wl->hw, q->queue_prio); q->stopped = 0; } - - spin_unlock_irq(&q->lock); } void b43_pio_get_tx_stats(struct b43_wldev *dev, @@ -611,17 +600,14 @@ void b43_pio_get_tx_stats(struct b43_wldev *dev, { const int nr_queues = dev->wl->hw->queues; struct b43_pio_txqueue *q; - unsigned long flags; int i; for (i = 0; i < nr_queues; i++) { q = select_queue_by_priority(dev, i); - spin_lock_irqsave(&q->lock, flags); stats[i].len = B43_PIO_MAX_NR_TXPACKETS - q->free_packet_slots; stats[i].limit = B43_PIO_MAX_NR_TXPACKETS; stats[i].count = q->nr_tx_packets; - spin_unlock_irqrestore(&q->lock, flags); } } @@ -768,9 +754,9 @@ static void b43_pio_rx_work(struct work_struct *work) bool stop; do { - spin_lock_irq(&q->lock); + mutex_lock(&q->dev->wl->mutex); stop = (pio_rx_frame(q) == 0); - spin_unlock_irq(&q->lock); + mutex_unlock(&q->dev->wl->mutex); cond_resched(); if (stop) break; @@ -787,9 +773,6 @@ void b43_pio_rx(struct b43_pio_rxqueue *q) static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q) { - unsigned long flags; - - spin_lock_irqsave(&q->lock, flags); if (q->rev >= 8) { b43_piotx_write32(q, B43_PIO8_TXCTL, b43_piotx_read32(q, B43_PIO8_TXCTL) @@ -799,14 +782,10 @@ static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q) b43_piotx_read16(q, B43_PIO_TXCTL) | B43_PIO_TXCTL_SUSPREQ); } - spin_unlock_irqrestore(&q->lock, flags); } static void b43_pio_tx_resume_queue(struct b43_pio_txqueue *q) { - unsigned long flags; - - spin_lock_irqsave(&q->lock, flags); if (q->rev >= 8) { b43_piotx_write32(q, B43_PIO8_TXCTL, b43_piotx_read32(q, B43_PIO8_TXCTL) @@ -816,7 +795,6 @@ static void b43_pio_tx_resume_queue(struct b43_pio_txqueue *q) b43_piotx_read16(q, B43_PIO_TXCTL) & ~B43_PIO_TXCTL_SUSPREQ); } - spin_unlock_irqrestore(&q->lock, flags); } void b43_pio_tx_suspend(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h index 6c174c91ca2..a976bbdd6f4 100644 --- a/drivers/net/wireless/b43/pio.h +++ b/drivers/net/wireless/b43/pio.h @@ -70,7 +70,6 @@ struct b43_pio_txpacket { struct b43_pio_txqueue { struct b43_wldev *dev; - spinlock_t lock; u16 mmio_base; /* The device queue buffer size in bytes. */ @@ -103,7 +102,6 @@ struct b43_pio_txqueue { struct b43_pio_rxqueue { struct b43_wldev *dev; - spinlock_t lock; u16 mmio_base; /* Work to reduce latency issues on RX. */ -- cgit v1.2.3-18-g5258 From 77ca07ffe1797a0f2f41aa4997c9a5ae433a0be8 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 4 Sep 2009 22:56:19 +0200 Subject: b43: Remove PIO RX workqueue This removes the PIO RX work. It's not needed anymore, because we can sleep in the threaded interrupt handler. Signed-off-by: Michael Buesch Tested-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 1 - drivers/net/wireless/b43/pio.c | 36 +++++++----------------------------- drivers/net/wireless/b43/pio.h | 4 ---- 3 files changed, 7 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index fca2fe947d7..23de3db4f6d 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3883,7 +3883,6 @@ redo: while (skb_queue_len(&wl->tx_queue)) dev_kfree_skb(skb_dequeue(&wl->tx_queue)); - b43_pio_stop(dev); b43_mac_suspend(dev); free_irq(dev->dev->irq, dev); b43dbg(wl, "Wireless interface stopped\n"); diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 4635baa9b99..3498b68385e 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -32,9 +32,6 @@ #include -static void b43_pio_rx_work(struct work_struct *work); - - static u16 generate_cookie(struct b43_pio_txqueue *q, struct b43_pio_txpacket *pack) { @@ -182,7 +179,6 @@ static struct b43_pio_rxqueue *b43_setup_pioqueue_rx(struct b43_wldev *dev, q->rev = dev->dev->id.revision; q->mmio_base = index_to_pioqueue_base(dev, index) + pio_rxqueue_offset(dev); - INIT_WORK(&q->rx_work, b43_pio_rx_work); /* Enable Direct FIFO RX (PIO) on the engine. */ b43_dma_direct_fifo_rx(dev, index, 1); @@ -247,13 +243,6 @@ void b43_pio_free(struct b43_wldev *dev) destroy_queue_tx(pio, tx_queue_AC_BK); } -void b43_pio_stop(struct b43_wldev *dev) -{ - if (!b43_using_pio_transfers(dev)) - return; - cancel_work_sync(&dev->pio.rx_queue->rx_work); -} - int b43_pio_init(struct b43_wldev *dev) { struct b43_pio *pio = &dev->pio; @@ -745,30 +734,19 @@ rx_error: return 1; } -/* RX workqueue. We can sleep, yay! */ -static void b43_pio_rx_work(struct work_struct *work) +void b43_pio_rx(struct b43_pio_rxqueue *q) { - struct b43_pio_rxqueue *q = container_of(work, struct b43_pio_rxqueue, - rx_work); - unsigned int budget = 50; + unsigned int count = 0; bool stop; - do { - mutex_lock(&q->dev->wl->mutex); + while (1) { stop = (pio_rx_frame(q) == 0); - mutex_unlock(&q->dev->wl->mutex); - cond_resched(); if (stop) break; - } while (--budget); -} - -/* Called with IRQs disabled. */ -void b43_pio_rx(struct b43_pio_rxqueue *q) -{ - /* Due to latency issues we must run the RX path in - * a workqueue to be able to schedule between packets. */ - ieee80211_queue_work(q->dev->wl->hw, &q->rx_work); + cond_resched(); + if (WARN_ON_ONCE(++count > 10000)) + break; + } } static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q) diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h index a976bbdd6f4..7dd649c9dda 100644 --- a/drivers/net/wireless/b43/pio.h +++ b/drivers/net/wireless/b43/pio.h @@ -104,9 +104,6 @@ struct b43_pio_rxqueue { struct b43_wldev *dev; u16 mmio_base; - /* Work to reduce latency issues on RX. */ - struct work_struct rx_work; - /* Shortcut to the 802.11 core revision. This is to * avoid horrible pointer dereferencing in the fastpaths. */ u8 rev; @@ -160,7 +157,6 @@ static inline void b43_piorx_write32(struct b43_pio_rxqueue *q, int b43_pio_init(struct b43_wldev *dev); -void b43_pio_stop(struct b43_wldev *dev); void b43_pio_free(struct b43_wldev *dev); int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb); -- cgit v1.2.3-18-g5258 From 69eddc8a37a33479205ac3a3d8575fad1466da90 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 4 Sep 2009 22:57:26 +0200 Subject: b43: remove SHM spinlock This removes the SHM spinlock. SHM is protected by wl->mutex. Signed-off-by: Michael Buesch Tested-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 2 -- drivers/net/wireless/b43/debugfs.c | 14 +++------- drivers/net/wireless/b43/main.c | 55 +++----------------------------------- drivers/net/wireless/b43/main.h | 4 --- 4 files changed, 8 insertions(+), 67 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 1cd470d6e2d..09cfe68537b 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -635,8 +635,6 @@ struct b43_wl { rwlock_t tx_lock; /* Lock for LEDs access. */ spinlock_t leds_lock; - /* Lock for SHM access. */ - spinlock_t shm_lock; /* We can only have one operating interface (802.11 core) * at a time. General information about this interface follows. diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index bf23a3a863f..8f64943e3f6 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -125,7 +125,6 @@ static int shm16write__write_file(struct b43_wldev *dev, unsigned int routing, addr, mask, set; u16 val; int res; - unsigned long flags; res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X", &routing, &addr, &mask, &set); @@ -142,15 +141,13 @@ static int shm16write__write_file(struct b43_wldev *dev, if ((mask > 0xFFFF) || (set > 0xFFFF)) return -E2BIG; - spin_lock_irqsave(&dev->wl->shm_lock, flags); if (mask == 0) val = 0; else - val = __b43_shm_read16(dev, routing, addr); + val = b43_shm_read16(dev, routing, addr); val &= mask; val |= set; - __b43_shm_write16(dev, routing, addr, val); - spin_unlock_irqrestore(&dev->wl->shm_lock, flags); + b43_shm_write16(dev, routing, addr, val); return 0; } @@ -204,7 +201,6 @@ static int shm32write__write_file(struct b43_wldev *dev, unsigned int routing, addr, mask, set; u32 val; int res; - unsigned long flags; res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X", &routing, &addr, &mask, &set); @@ -221,15 +217,13 @@ static int shm32write__write_file(struct b43_wldev *dev, if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF)) return -E2BIG; - spin_lock_irqsave(&dev->wl->shm_lock, flags); if (mask == 0) val = 0; else - val = __b43_shm_read32(dev, routing, addr); + val = b43_shm_read32(dev, routing, addr); val &= mask; val |= set; - __b43_shm_write32(dev, routing, addr, val); - spin_unlock_irqrestore(&dev->wl->shm_lock, flags); + b43_shm_write32(dev, routing, addr, val); return 0; } diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 23de3db4f6d..0a4d0b3eceb 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -390,7 +390,7 @@ static inline void b43_shm_control_word(struct b43_wldev *dev, b43_write32(dev, B43_MMIO_SHM_CONTROL, control); } -u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) +u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) { u32 ret; @@ -413,20 +413,7 @@ out: return ret; } -u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) -{ - struct b43_wl *wl = dev->wl; - unsigned long flags; - u32 ret; - - spin_lock_irqsave(&wl->shm_lock, flags); - ret = __b43_shm_read32(dev, routing, offset); - spin_unlock_irqrestore(&wl->shm_lock, flags); - - return ret; -} - -u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset) +u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset) { u16 ret; @@ -447,20 +434,7 @@ out: return ret; } -u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset) -{ - struct b43_wl *wl = dev->wl; - unsigned long flags; - u16 ret; - - spin_lock_irqsave(&wl->shm_lock, flags); - ret = __b43_shm_read16(dev, routing, offset); - spin_unlock_irqrestore(&wl->shm_lock, flags); - - return ret; -} - -void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) +void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) { if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); @@ -480,17 +454,7 @@ void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value b43_write32(dev, B43_MMIO_SHM_DATA, value); } -void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) -{ - struct b43_wl *wl = dev->wl; - unsigned long flags; - - spin_lock_irqsave(&wl->shm_lock, flags); - __b43_shm_write32(dev, routing, offset, value); - spin_unlock_irqrestore(&wl->shm_lock, flags); -} - -void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) +void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) { if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); @@ -506,16 +470,6 @@ void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value b43_write16(dev, B43_MMIO_SHM_DATA, value); } -void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) -{ - struct b43_wl *wl = dev->wl; - unsigned long flags; - - spin_lock_irqsave(&wl->shm_lock, flags); - __b43_shm_write16(dev, routing, offset, value); - spin_unlock_irqrestore(&wl->shm_lock, flags); -} - /* Read HostFlags */ u64 b43_hf_read(struct b43_wldev *dev) { @@ -4866,7 +4820,6 @@ static int b43_wireless_init(struct ssb_device *dev) /* Initialize struct b43_wl */ wl->hw = hw; spin_lock_init(&wl->leds_lock); - spin_lock_init(&wl->shm_lock); mutex_init(&wl->mutex); spin_lock_init(&wl->hardirq_lock); INIT_LIST_HEAD(&wl->devlist); diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 0406e06781d..40db03678d9 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -112,13 +112,9 @@ void b43_tsf_read(struct b43_wldev *dev, u64 * tsf); void b43_tsf_write(struct b43_wldev *dev, u64 tsf); u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset); -u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset); u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset); -u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset); void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value); -void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value); void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value); -void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value); u64 b43_hf_read(struct b43_wldev *dev); void b43_hf_write(struct b43_wldev *dev, u64 value); -- cgit v1.2.3-18-g5258 From e6c463e3a3d067f5da2c79d5acdb2f626754cdb3 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 5 Sep 2009 11:18:47 +0200 Subject: ssb: Fail ssb modinit, if attach of the buses failed. SSB modinit should not succeed, if busattach failed. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 65a1ed951a1..8d16cb258cc 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -1358,8 +1358,10 @@ static int __init ssb_modinit(void) ssb_buses_lock(); err = ssb_attach_queued_buses(); ssb_buses_unlock(); - if (err) + if (err) { bus_unregister(&ssb_bustype); + goto out; + } err = b43_pci_ssb_bridge_init(); if (err) { @@ -1375,7 +1377,7 @@ static int __init ssb_modinit(void) /* don't fail SSB init because of this */ err = 0; } - +out: return err; } /* ssb must be initialized after PCI but before the ssb drivers. -- cgit v1.2.3-18-g5258 From 7f42c37aa676825fea329a7bec2fefe51033b3e9 Mon Sep 17 00:00:00 2001 From: Joerg Albert Date: Sat, 5 Sep 2009 16:07:43 +0200 Subject: ath,ar9170: move CTL_ defines into regd.h The ar9170 driver needs the defines for conformance test limit groups and cannot include regd_common.h Signed-off-by: Joerg Albert Acked-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/regd.h | 6 ++++++ drivers/net/wireless/ath/regd_common.h | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 4d3c53674e5..c1dd857697a 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -22,6 +22,12 @@ #include "ath.h" +enum ctl_group { + CTL_FCC = 0x10, + CTL_MKK = 0x40, + CTL_ETSI = 0x30, +}; + #define NO_CTL 0xff #define SD_NO_CTL 0xE0 #define NO_CTL 0xff diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index ad6d938d3cf..9847af72208 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -154,12 +154,6 @@ enum EnumRd { DEBUG_REG_DMN = 0x01ff, }; -enum ctl_group { - CTL_FCC = 0x10, - CTL_MKK = 0x40, - CTL_ETSI = 0x30, -}; - /* Regpair to CTL band mapping */ static struct reg_dmn_pair_mapping regDomainPairs[] = { /* regpair, 5 GHz CTL, 2 GHz CTL */ -- cgit v1.2.3-18-g5258 From fea6734a0e444c31c99a1271154bb0281d7908d8 Mon Sep 17 00:00:00 2001 From: Joerg Albert Date: Sat, 5 Sep 2009 16:07:47 +0200 Subject: ath,ar9170: implemented conformance test limit calc. for tx power apply the conformance test limits (CTL) stored in the eeprom upon the values calculated for the tx power (ar->power_*). This is based on the implementation in the vendor driver (hal/hpmain.c, line 3700 ff.) with one difference: If any ctl mode isn't found in the eeprom, we fall back to the "lower", legacy modes (5GHT20,11A or 2GHT20,11G,11B). Otus only did 5GHT20->11A. Currently CTL are applied for the FCC group only. Signed-off-by: Joerg Albert Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/phy.c | 165 +++++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c index 108ebfe21fc..b3e5cf3735b 100644 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ b/drivers/net/wireless/ath/ar9170/phy.c @@ -556,7 +556,6 @@ int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) if (err) return err; - /* TODO: (heavy clip) regulatory domain power level fine-tuning. */ err = ar9170_init_phy_from_eeprom(ar, is_2ghz, is_40mhz); if (err) return err; @@ -1238,6 +1237,164 @@ static int ar9170_set_freq_cal_data(struct ar9170 *ar, return ar9170_regwrite_result(); } +static u8 ar9170_get_max_edge_power(struct ar9170 *ar, + struct ar9170_calctl_edges edges[], + u32 freq) +{ +/* TODO: move somewhere else */ +#define AR5416_MAX_RATE_POWER 63 + + int i; + u8 rc = AR5416_MAX_RATE_POWER; + u8 f; + if (freq < 3000) + f = freq - 2300; + else + f = (freq - 4800) / 5; + + for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) { + if (edges[i].channel == 0xff) + break; + if (f == edges[i].channel) { + /* exact freq match */ + rc = edges[i].power_flags & ~AR9170_CALCTL_EDGE_FLAGS; + break; + } + if (i > 0 && f < edges[i].channel) { + if (f > edges[i-1].channel && + edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) { + /* lower channel has the inband flag set */ + rc = edges[i-1].power_flags & + ~AR9170_CALCTL_EDGE_FLAGS; + } + break; + } + } + + if (i == AR5416_NUM_BAND_EDGES) { + if (f > edges[i-1].channel && + edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) { + /* lower channel has the inband flag set */ + rc = edges[i-1].power_flags & + ~AR9170_CALCTL_EDGE_FLAGS; + } + } + return rc; +} + +/* calculate the conformance test limits and apply them to ar->power* + * (derived from otus hal/hpmain.c, line 3706 ff.) + */ +static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) +{ + u8 ctl_grp; /* CTL group */ + u8 ctl_idx; /* CTL index */ + int i, j; + struct ctl_modes { + u8 ctl_mode; + u8 max_power; + u8 *pwr_cal_data; + int pwr_cal_len; + } *modes; + + /* order is relevant in the mode_list_*: we fall back to the + * lower indices if any mode is missed in the EEPROM. + */ + struct ctl_modes mode_list_2ghz[] = { + { CTL_11B, 0, ar->power_2G_cck, 4 }, + { CTL_11G, 0, ar->power_2G_ofdm, 4 }, + { CTL_2GHT20, 0, ar->power_2G_ht20, 8 }, + { CTL_2GHT40, 0, ar->power_2G_ht40, 8 }, + }; + struct ctl_modes mode_list_5ghz[] = { + { CTL_11A, 0, ar->power_5G_leg, 4 }, + { CTL_5GHT20, 0, ar->power_5G_ht20, 8 }, + { CTL_5GHT40, 0, ar->power_5G_ht40, 8 }, + }; + int nr_modes; + +#define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n]) + + /* TODO: investigate the differences between OTUS' + * hpreg.c::zfHpGetRegulatoryDomain() and + * ath/regd.c::ath_regd_get_band_ctl() - + * e.g. for FCC3_WORLD the OTUS procedure + * always returns CTL_FCC, while the one in ath/ delivers + * CTL_ETSI for 2GHz and CTL_FCC for 5GHz. + */ + ctl_grp = ath_regd_get_band_ctl(&ar->common.regulatory, + ar->hw->conf.channel->band); + + /* ctl group not found - either invalid band (NO_CTL) or ww roaming */ + if (ctl_grp == NO_CTL || ctl_grp == SD_NO_CTL) + ctl_grp = CTL_FCC; + + if (ctl_grp != CTL_FCC) + /* skip CTL and heavy clip for CTL_MKK and CTL_ETSI */ + return; + + if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) { + modes = mode_list_2ghz; + nr_modes = ARRAY_SIZE(mode_list_2ghz); + } else { + modes = mode_list_5ghz; + nr_modes = ARRAY_SIZE(mode_list_5ghz); + } + + for (i = 0; i < nr_modes; i++) { + u8 c = ctl_grp | modes[i].ctl_mode; + for (ctl_idx = 0; ctl_idx < AR5416_NUM_CTLS; ctl_idx++) + if (c == ar->eeprom.ctl_index[ctl_idx]) + break; + if (ctl_idx < AR5416_NUM_CTLS) { + int f_off = 0; + + /* adjust freq for 40MHz */ + if (modes[i].ctl_mode == CTL_2GHT40 || + modes[i].ctl_mode == CTL_5GHT40) { + if (bw == AR9170_BW_40_BELOW) + f_off = -10; + else + f_off = 10; + } + + modes[i].max_power = + ar9170_get_max_edge_power(ar, EDGES(ctl_idx, 1), + freq+f_off); + + /* TODO: check if the regulatory max. power is + * controlled by cfg80211 for DFS + * (hpmain applies it to max_power itself for DFS freq) + */ + + } else { + /* Workaround in otus driver, hpmain.c, line 3906: + * if no data for 5GHT20 are found, take the + * legacy 5G value. + * We extend this here to fallback from any other *HT or + * 11G, too. + */ + int k = i; + + modes[i].max_power = AR5416_MAX_RATE_POWER; + while (k-- > 0) { + if (modes[k].max_power != + AR5416_MAX_RATE_POWER) { + modes[i].max_power = modes[k].max_power; + break; + } + } + } + + /* apply max power to pwr_cal_data (ar->power_*) */ + for (j = 0; j < modes[i].pwr_cal_len; j++) { + modes[i].pwr_cal_data[j] = min(modes[i].pwr_cal_data[j], + modes[i].max_power); + } + } +#undef EDGES +} + static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) { struct ar9170_calibration_target_power_legacy *ctpl; @@ -1340,6 +1497,12 @@ static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) ctph[idx + 1].power[n]); } + + /* calc. conformance test limits and apply to ar->power*[] */ + ar9170_calc_ctl(ar, freq, bw); + + /* TODO: (heavy clip) regulatory domain power level fine-tuning. */ + /* set ACK/CTS TX power */ ar9170_regwrite_begin(ar); -- cgit v1.2.3-18-g5258 From fd413da852991e96c555ad7253cc481bc133e221 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 6 Sep 2009 14:49:43 +0200 Subject: b43: PCMCIA is not experimental anymore PCMCIA support works well and is not experimental anymore. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 2af3b352232..83e38134acc 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -42,8 +42,8 @@ config B43_PCICORE_AUTOSELECT default y config B43_PCMCIA - bool "Broadcom 43xx PCMCIA device support (EXPERIMENTAL)" - depends on B43 && SSB_PCMCIAHOST_POSSIBLE && EXPERIMENTAL + bool "Broadcom 43xx PCMCIA device support" + depends on B43 && SSB_PCMCIAHOST_POSSIBLE select SSB_PCMCIAHOST ---help--- Broadcom 43xx PCMCIA device support. -- cgit v1.2.3-18-g5258 From e6890f6f3dc2d9024a08b1a149d9bd5208eea350 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 8 Sep 2009 17:09:24 -0700 Subject: i915: disable interrupts before tearing down GEM state Reinette Chatre reports a frozen system (with blinking keyboard LEDs) when switching from graphics mode to the text console, or when suspending (which does the same thing). With netconsole, the oops turned out to be BUG: unable to handle kernel NULL pointer dereference at 0000000000000084 IP: [] i915_driver_irq_handler+0x26b/0xd20 [i915] and it's due to the i915_gem.c code doing drm_irq_uninstall() after having done i915_gem_idle(). And the i915_gem_idle() path will do i915_gem_idle() -> i915_gem_cleanup_ringbuffer() -> i915_gem_cleanup_hws() -> dev_priv->hw_status_page = NULL; but if an i915 interrupt comes in after this stage, it may want to access that hw_status_page, and gets the above NULL pointer dereference. And since the NULL pointer dereference happens from within an interrupt, and with the screen still in graphics mode, the common end result is simply a silently hung machine. Fix it by simply uninstalling the irq handler before idling rather than after. Fixes http://bugzilla.kernel.org/show_bug.cgi?id=13819 Reported-and-tested-by: Reinette Chatre Acked-by: Jesse Barnes Signed-off-by: Linus Torvalds --- drivers/gpu/drm/i915/i915_gem.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 7edb5b9d579..80e5ba490dc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4232,15 +4232,11 @@ int i915_gem_leavevt_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - int ret; - if (drm_core_check_feature(dev, DRIVER_MODESET)) return 0; - ret = i915_gem_idle(dev); drm_irq_uninstall(dev); - - return ret; + return i915_gem_idle(dev); } void -- cgit v1.2.3-18-g5258 From 72fee3823d2938fa98f2f3113301f46803f4c711 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 1 Sep 2009 23:19:10 +0900 Subject: sata_sis: convert to slave_link During introduction of slave_link, sata_sis slipped through the crack and left with ad-hoc merged SCR access. As SCR status was shared for both the master and slave devices, when only one of the device is online, libata EH would think both are online but would only get valid device signature for the actually present one, which in turn trigger the probing safety net mechanism and make EH retry causing large delay during boot. This patch converts sata_sis to slave_link mechanism. This bug was reported by TAXI in bko#14075. http://bugzilla.kernel.org/show_bug.cgi?id=14075 Signed-off-by: Tejun Heo Reported-by: TAXI Cc: Uwe Koziolek Signed-off-by: Jeff Garzik --- drivers/ata/sata_sis.c | 75 +++++++++++++++++--------------------------------- 1 file changed, 25 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 8f983322861..f8a91bfd66a 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -109,8 +109,9 @@ MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, sis_pci_tbl); MODULE_VERSION(DRV_VERSION); -static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg) +static unsigned int get_scr_cfg_addr(struct ata_link *link, unsigned int sc_reg) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); unsigned int addr = SIS_SCR_BASE + (4 * sc_reg); u8 pmr; @@ -131,6 +132,9 @@ static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg) break; } } + if (link->pmp) + addr += 0x10; + return addr; } @@ -138,24 +142,12 @@ static u32 sis_scr_cfg_read(struct ata_link *link, unsigned int sc_reg, u32 *val) { struct pci_dev *pdev = to_pci_dev(link->ap->host->dev); - unsigned int cfg_addr = get_scr_cfg_addr(link->ap, sc_reg); - u32 val2 = 0; - u8 pmr; + unsigned int cfg_addr = get_scr_cfg_addr(link, sc_reg); if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */ return -EINVAL; - pci_read_config_byte(pdev, SIS_PMR, &pmr); - pci_read_config_dword(pdev, cfg_addr, val); - - if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || - (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED)) - pci_read_config_dword(pdev, cfg_addr+0x10, &val2); - - *val |= val2; - *val &= 0xfffffffb; /* avoid problems with powerdowned ports */ - return 0; } @@ -163,28 +155,16 @@ static int sis_scr_cfg_write(struct ata_link *link, unsigned int sc_reg, u32 val) { struct pci_dev *pdev = to_pci_dev(link->ap->host->dev); - unsigned int cfg_addr = get_scr_cfg_addr(link->ap, sc_reg); - u8 pmr; - - if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */ - return -EINVAL; - - pci_read_config_byte(pdev, SIS_PMR, &pmr); + unsigned int cfg_addr = get_scr_cfg_addr(link, sc_reg); pci_write_config_dword(pdev, cfg_addr, val); - - if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || - (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED)) - pci_write_config_dword(pdev, cfg_addr+0x10, val); - return 0; } static int sis_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val) { struct ata_port *ap = link->ap; - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u8 pmr; + void __iomem *base = ap->ioaddr.scr_addr + link->pmp * 0x10; if (sc_reg > SCR_CONTROL) return -EINVAL; @@ -192,39 +172,23 @@ static int sis_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val) if (ap->flags & SIS_FLAG_CFGSCR) return sis_scr_cfg_read(link, sc_reg, val); - pci_read_config_byte(pdev, SIS_PMR, &pmr); - - *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4)); - - if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || - (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED)) - *val |= ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10); - - *val &= 0xfffffffb; - + *val = ioread32(base + sc_reg * 4); return 0; } static int sis_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) { struct ata_port *ap = link->ap; - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u8 pmr; + void __iomem *base = ap->ioaddr.scr_addr + link->pmp * 0x10; if (sc_reg > SCR_CONTROL) return -EINVAL; - pci_read_config_byte(pdev, SIS_PMR, &pmr); - if (ap->flags & SIS_FLAG_CFGSCR) return sis_scr_cfg_write(link, sc_reg, val); - else { - iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)); - if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || - (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED)) - iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10); - return 0; - } + + iowrite32(val, base + (sc_reg * 4)); + return 0; } static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -236,7 +200,7 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) u32 genctl, val; u8 pmr; u8 port2_start = 0x20; - int rc; + int i, rc; if (!printed_version++) dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); @@ -319,6 +283,17 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; + for (i = 0; i < 2; i++) { + struct ata_port *ap = host->ports[i]; + + if (ap->flags & ATA_FLAG_SATA && + ap->flags & ATA_FLAG_SLAVE_POSS) { + rc = ata_slave_link_init(ap); + if (rc) + return rc; + } + } + if (!(pi.flags & SIS_FLAG_CFGSCR)) { void __iomem *mmio; -- cgit v1.2.3-18-g5258 From bd30add88cea831dfb854d564478f09ee66206b5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 3 Sep 2009 16:08:11 +0900 Subject: libata: unbreak TPM filtering by reorganizing ata_scsi_pass_thru() ata_scsi_pass_thru() was checking for input sanity and disallowed commands while initializaing qc from scmd. TPM filtering was added right after protocol check at which point tf wasn't initialized properly. This means that TPM filtering has never really worked. This patch fixes the bug by reorganizing ata_scsi_pass_thru() such that qc is fully initialized before checking for invalid conditions which is way less error prone. Discovered while Thilo-Alexander Ginkel was trying debug patches for bko#13416. Signed-off-by: Tejun Heo Cc: Thilo-Alexander Ginkel Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 104 +++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 5d7a1bd37e9..b4ee28dec52 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2759,28 +2759,6 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) if ((tf->protocol = ata_scsi_map_proto(cdb[1])) == ATA_PROT_UNKNOWN) goto invalid_fld; - /* - * Filter TPM commands by default. These provide an - * essentially uncontrolled encrypted "back door" between - * applications and the disk. Set libata.allow_tpm=1 if you - * have a real reason for wanting to use them. This ensures - * that installed software cannot easily mess stuff up without - * user intent. DVR type users will probably ship with this enabled - * for movie content management. - * - * Note that for ATA8 we can issue a DCS change and DCS freeze lock - * for this and should do in future but that it is not sufficient as - * DCS is an optional feature set. Thus we also do the software filter - * so that we comply with the TC consortium stated goal that the user - * can turn off TC features of their system. - */ - if (tf->command >= 0x5C && tf->command <= 0x5F && !libata_allow_tpm) - goto invalid_fld; - - /* We may not issue DMA commands if no DMA mode is set */ - if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0) - goto invalid_fld; - /* * 12 and 16 byte CDBs use different offsets to * provide the various register values. @@ -2830,6 +2808,41 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) tf->device = dev->devno ? tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1; + /* READ/WRITE LONG use a non-standard sect_size */ + qc->sect_size = ATA_SECT_SIZE; + switch (tf->command) { + case ATA_CMD_READ_LONG: + case ATA_CMD_READ_LONG_ONCE: + case ATA_CMD_WRITE_LONG: + case ATA_CMD_WRITE_LONG_ONCE: + if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1) + goto invalid_fld; + qc->sect_size = scsi_bufflen(scmd); + } + + /* + * Set flags so that all registers will be written, pass on + * write indication (used for PIO/DMA setup), result TF is + * copied back and we don't whine too much about its failure. + */ + tf->flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + if (scmd->sc_data_direction == DMA_TO_DEVICE) + tf->flags |= ATA_TFLAG_WRITE; + + qc->flags |= ATA_QCFLAG_RESULT_TF | ATA_QCFLAG_QUIET; + + /* + * Set transfer length. + * + * TODO: find out if we need to do more here to + * cover scatter/gather case. + */ + ata_qc_set_pc_nbytes(qc); + + /* We may not issue DMA commands if no DMA mode is set */ + if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0) + goto invalid_fld; + /* sanity check for pio multi commands */ if ((cdb[1] & 0xe0) && !is_multi_taskfile(tf)) goto invalid_fld; @@ -2846,18 +2859,6 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) multi_count); } - /* READ/WRITE LONG use a non-standard sect_size */ - qc->sect_size = ATA_SECT_SIZE; - switch (tf->command) { - case ATA_CMD_READ_LONG: - case ATA_CMD_READ_LONG_ONCE: - case ATA_CMD_WRITE_LONG: - case ATA_CMD_WRITE_LONG_ONCE: - if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1) - goto invalid_fld; - qc->sect_size = scsi_bufflen(scmd); - } - /* * Filter SET_FEATURES - XFER MODE command -- otherwise, * SET_FEATURES - XFER MODE must be preceded/succeeded @@ -2865,30 +2866,27 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) * controller (i.e. the reason for ->set_piomode(), * ->set_dmamode(), and ->post_set_mode() hooks). */ - if ((tf->command == ATA_CMD_SET_FEATURES) - && (tf->feature == SETFEATURES_XFER)) + if (tf->command == ATA_CMD_SET_FEATURES && + tf->feature == SETFEATURES_XFER) goto invalid_fld; /* - * Set flags so that all registers will be written, - * and pass on write indication (used for PIO/DMA - * setup.) - */ - tf->flags |= (ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE); - - if (scmd->sc_data_direction == DMA_TO_DEVICE) - tf->flags |= ATA_TFLAG_WRITE; - - /* - * Set transfer length. + * Filter TPM commands by default. These provide an + * essentially uncontrolled encrypted "back door" between + * applications and the disk. Set libata.allow_tpm=1 if you + * have a real reason for wanting to use them. This ensures + * that installed software cannot easily mess stuff up without + * user intent. DVR type users will probably ship with this enabled + * for movie content management. * - * TODO: find out if we need to do more here to - * cover scatter/gather case. + * Note that for ATA8 we can issue a DCS change and DCS freeze lock + * for this and should do in future but that it is not sufficient as + * DCS is an optional feature set. Thus we also do the software filter + * so that we comply with the TC consortium stated goal that the user + * can turn off TC features of their system. */ - ata_qc_set_pc_nbytes(qc); - - /* request result TF and be quiet about device error */ - qc->flags |= ATA_QCFLAG_RESULT_TF | ATA_QCFLAG_QUIET; + if (tf->command >= 0x5C && tf->command <= 0x5F && !libata_allow_tpm) + goto invalid_fld; return 0; -- cgit v1.2.3-18-g5258 From 02c24fa87724bb3af969463cd74dc3b3feb24740 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 16 Aug 2009 21:01:22 +0900 Subject: dmi: fix date handling in dmi_get_year() Year parsing in dmi_get_year() had the following two bugs. * "00" is treated as invalid instead of 2000 because zero return from simple_strtoul() is treated as error. * "0N" where N >= 8 is treated as invalid of 200N because the leading 0 is considered to specify octal. Fix the above two bugs by using endptr to detect invalid number and forcing decimal. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/firmware/dmi_scan.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 24c84ae8152..531e621677c 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -577,6 +577,7 @@ int dmi_get_year(int field) { int year; const char *s = dmi_get_system_info(field); + char *e; if (!s) return -1; @@ -587,8 +588,8 @@ int dmi_get_year(int field) return 0; s += 1; - year = simple_strtoul(s, NULL, 0); - if (year && year < 100) { /* 2-digit year */ + year = simple_strtoul(s, &e, 10); + if (s != e && year < 100) { /* 2-digit year */ year += 1900; if (year < 1996) /* no dates < spec 1.0 */ year += 100; -- cgit v1.2.3-18-g5258 From 3e5cd1f2576c720f1d0705fdd7ba64f27e8836b7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 16 Aug 2009 21:02:36 +0900 Subject: dmi: extend dmi_get_year() to dmi_get_date() There are cases where full date information is required instead of just the year. Add month and day parsing to dmi_get_year() and rename it to dmi_get_date(). As the original function only required '/' followed by any number of parseable characters at the end of the string, keep that behavior to avoid upsetting existing users. The new function takes dates of format [mm[/dd]]/yy[yy]. Year, month and date are checked to be in the ranges of [1-9999], [1-12] and [1-31] respectively and any invalid or out-of-range component is returned as zero. The dummy implementation is updated accordingly but the return value is updated to indicate field not found which is consistent with how other dummy functions behave. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/acpi/blacklist.c | 5 +-- drivers/ata/ahci.c | 2 +- drivers/firmware/dmi_scan.c | 76 ++++++++++++++++++++++++++++++++++----------- 3 files changed, 62 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index f6baa77deef..0c4ca4d318b 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -78,9 +78,10 @@ static struct acpi_blacklist_item acpi_blacklist[] __initdata = { static int __init blacklist_by_year(void) { - int year = dmi_get_year(DMI_BIOS_DATE); + int year; + /* Doesn't exist? Likely an old system */ - if (year == -1) { + if (!dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL)) { printk(KERN_ERR PREFIX "no DMI BIOS year, " "acpi=force is required to enable ACPI\n" ); return 1; diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index be4c39f8ab8..147b9be3b4d 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -2679,7 +2679,7 @@ static bool ahci_asus_m2a_vm_32bit_only(struct pci_dev *pdev) * different versions. */ date = dmi_get_system_info(DMI_BIOS_DATE); - year = dmi_get_year(DMI_BIOS_DATE); + dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL); if (date && strlen(date) >= 10 && date[2] == '/' && date[5] == '/' && (year > 2007 || (year == 2007 && strncmp(date, cutoff_mmdd, 5) >= 0))) diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 531e621677c..938100f14b1 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -568,36 +568,76 @@ const struct dmi_device * dmi_find_device(int type, const char *name, EXPORT_SYMBOL(dmi_find_device); /** - * dmi_get_year - Return year of a DMI date - * @field: data index (like dmi_get_system_info) + * dmi_get_date - parse a DMI date + * @field: data index (see enum dmi_field) + * @yearp: optional out parameter for the year + * @monthp: optional out parameter for the month + * @dayp: optional out parameter for the day * - * Returns -1 when the field doesn't exist. 0 when it is broken. + * The date field is assumed to be in the form resembling + * [mm[/dd]]/yy[yy] and the result is stored in the out + * parameters any or all of which can be omitted. + * + * If the field doesn't exist, all out parameters are set to zero + * and false is returned. Otherwise, true is returned with any + * invalid part of date set to zero. + * + * On return, year, month and day are guaranteed to be in the + * range of [0,9999], [0,12] and [0,31] respectively. */ -int dmi_get_year(int field) +bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp) { - int year; - const char *s = dmi_get_system_info(field); + int year = 0, month = 0, day = 0; + bool exists; + const char *s, *y; char *e; - if (!s) - return -1; - if (*s == '\0') - return 0; - s = strrchr(s, '/'); - if (!s) - return 0; + s = dmi_get_system_info(field); + exists = s; + if (!exists) + goto out; - s += 1; - year = simple_strtoul(s, &e, 10); - if (s != e && year < 100) { /* 2-digit year */ + /* + * Determine year first. We assume the date string resembles + * mm/dd/yy[yy] but the original code extracted only the year + * from the end. Keep the behavior in the spirit of no + * surprises. + */ + y = strrchr(s, '/'); + if (!y) + goto out; + + y++; + year = simple_strtoul(y, &e, 10); + if (y != e && year < 100) { /* 2-digit year */ year += 1900; if (year < 1996) /* no dates < spec 1.0 */ year += 100; } + if (year > 9999) /* year should fit in %04d */ + year = 0; + + /* parse the mm and dd */ + month = simple_strtoul(s, &e, 10); + if (s == e || *e != '/' || !month || month > 12) { + month = 0; + goto out; + } - return year; + s = e + 1; + day = simple_strtoul(s, &e, 10); + if (s == y || s == e || *e != '/' || day > 31) + day = 0; +out: + if (yearp) + *yearp = year; + if (monthp) + *monthp = month; + if (dayp) + *dayp = day; + return exists; } -EXPORT_SYMBOL(dmi_get_year); +EXPORT_SYMBOL(dmi_get_date); /** * dmi_walk - Walk the DMI table and get called back for every record -- cgit v1.2.3-18-g5258 From 03d783bf5573ff316a8c703eed811a9a97901a8b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 16 Aug 2009 21:04:02 +0900 Subject: ahci: make ahci_asus_m2a_vm_32bit_only() quirk more generic It turns out ASUS M2A-VM isn't the only one with the 32bit DMA problem. Make ahci_asus_m2a_vm_32bit_only() more generic using the new dmi_get_date() and rename it to ahci_sb600_32bit_only(). Cut off date is now pointed to by dmi_system_id->driver_data in "yyyymmdd" format and it's now also allowed to be omitted. Signed-off-by: Tejun Heo Cc: Sandor Bodo-Merle Cc: Shane Huang Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 53 +++++++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 147b9be3b4d..aa03b49a9af 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -2647,14 +2647,18 @@ static void ahci_p5wdh_workaround(struct ata_host *host) } /* - * SB600 ahci controller on ASUS M2A-VM can't do 64bit DMA with older - * BIOS. The oldest version known to be broken is 0901 and working is - * 1501 which was released on 2007-10-26. Force 32bit DMA on anything - * older than 1501. Please read bko#9412 for more info. + * SB600 ahci controller on certain boards can't do 64bit DMA with + * older BIOS. */ -static bool ahci_asus_m2a_vm_32bit_only(struct pci_dev *pdev) +static bool ahci_sb600_32bit_only(struct pci_dev *pdev) { static const struct dmi_system_id sysids[] = { + /* + * The oldest version known to be broken is 0901 and + * working is 1501 which was released on 2007-10-26. + * Force 32bit DMA on anything older than 1501. + * Please read bko#9412 for more info. + */ { .ident = "ASUS M2A-VM", .matches = { @@ -2662,31 +2666,32 @@ static bool ahci_asus_m2a_vm_32bit_only(struct pci_dev *pdev) "ASUSTeK Computer INC."), DMI_MATCH(DMI_BOARD_NAME, "M2A-VM"), }, + .driver_data = "20071026", /* yyyymmdd */ }, { } }; - const char *cutoff_mmdd = "10/26"; - const char *date; - int year; + const struct dmi_system_id *match; + match = dmi_first_match(sysids); if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) || - !dmi_check_system(sysids)) + !match) return false; - /* - * Argh.... both version and date are free form strings. - * Let's hope they're using the same date format across - * different versions. - */ - date = dmi_get_system_info(DMI_BIOS_DATE); - dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL); - if (date && strlen(date) >= 10 && date[2] == '/' && date[5] == '/' && - (year > 2007 || - (year == 2007 && strncmp(date, cutoff_mmdd, 5) >= 0))) - return false; + if (match->driver_data) { + int year, month, date; + char buf[9]; + + dmi_get_date(DMI_BIOS_DATE, &year, &month, &date); + snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date); - dev_printk(KERN_WARNING, &pdev->dev, "ASUS M2A-VM: BIOS too old, " - "forcing 32bit DMA, update BIOS\n"); + if (strcmp(buf, match->driver_data) >= 0) + return false; + + dev_printk(KERN_WARNING, &pdev->dev, "%s: BIOS too old, " + "forcing 32bit DMA, update BIOS\n", match->ident); + } else + dev_printk(KERN_WARNING, &pdev->dev, "%s: this board can't " + "do 64bit DMA, forcing 32bit\n", match->ident); return true; } @@ -2901,8 +2906,8 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (board_id == board_ahci_sb700 && pdev->revision >= 0x40) hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL; - /* apply ASUS M2A_VM quirk */ - if (ahci_asus_m2a_vm_32bit_only(pdev)) + /* apply sb600 32bit only quirk */ + if (ahci_sb600_32bit_only(pdev)) hpriv->flags |= AHCI_HFLAG_32BIT_ONLY; if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) -- cgit v1.2.3-18-g5258 From 1b549dcbf607e88f3016bc149109472a46fe7bbb Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 16 Aug 2009 21:06:57 +0900 Subject: ahci: Gigabyte GA-MA69VM-S2 can't do 64bit DMA Gigabyte GA-MA69VM-S2 can't do 64bit DMA either. It's yet unknown whether recent BIOS fixes the problem. Blacklist regardless of BIOS revisions for now. Sandor Bodo-Merle reported and provided the initial patch for this issue. Signed-off-by: Tejun Heo Reported-by: Sandor Bodo-Merle Cc: Shane Huang Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index aa03b49a9af..a4e4cf141c0 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -2668,6 +2668,22 @@ static bool ahci_sb600_32bit_only(struct pci_dev *pdev) }, .driver_data = "20071026", /* yyyymmdd */ }, + /* + * It's yet unknown whether more recent BIOS fixes the + * problem. Blacklist the whole board for the time + * being. Please read the following thread for more + * info. + * + * http://thread.gmane.org/gmane.linux.ide/42326 + */ + { + .ident = "Gigabyte GA-MA69VM-S2", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, + "Gigabyte Technology Co., Ltd."), + DMI_MATCH(DMI_BOARD_NAME, "GA-MA69VM-S2"), + }, + }, { } }; const struct dmi_system_id *match; -- cgit v1.2.3-18-g5258 From ac8672ea922bde59acf50eaa1eaa1640a6395fd2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 16 Aug 2009 21:21:21 +0900 Subject: libata: fix off-by-one error in ata_tf_read_block() ata_tf_read_block() has off-by-one error when converting CHS address to LBA. The bug isn't very visible because ata_tf_read_block() is used only when generating sense data for a failed RW command and CHS addressing isn't used too often these days. This problem was spotted by Atsushi Nemoto. Signed-off-by: Tejun Heo Reported-by: Atsushi Nemoto Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 98af50f16e0..df31deac5c8 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -709,7 +709,13 @@ u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev) head = tf->device & 0xf; sect = tf->lbal; - block = (cyl * dev->heads + head) * dev->sectors + sect; + if (!sect) { + ata_dev_printk(dev, KERN_WARNING, "device reported " + "invalid CHS sector 0\n"); + sect = 1; /* oh well */ + } + + block = (cyl * dev->heads + head) * dev->sectors + sect - 1; } return block; -- cgit v1.2.3-18-g5258 From deeb003e5e01c0db02bb68fd9c93faf75ab9002d Mon Sep 17 00:00:00 2001 From: Shane Huang Date: Tue, 8 Sep 2009 17:37:01 +0800 Subject: libata: add SATA PMP revision information for spec 1.2 This small patch is just adding the information for PMP spec 1.2 Signed-off-by: Shane Huang Signed-off-by: Jeff Garzik --- drivers/ata/libata-pmp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 619f2c33950..51f0ffb78cb 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -221,6 +221,8 @@ static const char *sata_pmp_spec_rev_str(const u32 *gscr) { u32 rev = gscr[SATA_PMP_GSCR_REV]; + if (rev & (1 << 3)) + return "1.2"; if (rev & (1 << 2)) return "1.1"; if (rev & (1 << 1)) -- cgit v1.2.3-18-g5258 From f90f613c3ed7381209de8aa36458442b5130170b Mon Sep 17 00:00:00 2001 From: Ashish Kalra Date: Wed, 29 Jul 2009 21:15:49 +0530 Subject: sata_fsl: Defer non-ncq commands when ncq commands active Fix for non-ncq & ncq commands causing timeouts when both are issued simultaneously to the same device. Signed-off-by: Ashish Kalra [fixed to be actual compileable C code -jg] Signed-off-by: Jeff Garzik --- drivers/ata/sata_fsl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 94eaa432c40..d344db42a00 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -1257,6 +1257,7 @@ static struct scsi_host_template sata_fsl_sht = { static struct ata_port_operations sata_fsl_ops = { .inherits = &sata_pmp_port_ops, + .qc_defer = ata_std_qc_defer, .qc_prep = sata_fsl_qc_prep, .qc_issue = sata_fsl_qc_issue, .qc_fill_rtf = sata_fsl_qc_fill_rtf, -- cgit v1.2.3-18-g5258 From 6f0e013548fd15fddb952f657a3cc81282641191 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 9 Sep 2009 01:41:30 -0700 Subject: niu: Use resource_size instead of private function The function res_size in drivers/net/niu.c is a copy of resource_size in linux/ioport.h. Remove the function and use resource_size instead. Signed-off-by: Tobias Klauser Signed-off-by: David S. Miller --- drivers/net/niu.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 119fd4e0414..76cc2614f48 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -10145,11 +10145,6 @@ static const struct niu_ops niu_phys_ops = { .unmap_single = niu_phys_unmap_single, }; -static unsigned long res_size(struct resource *r) -{ - return r->end - r->start + 1UL; -} - static int __devinit niu_of_probe(struct of_device *op, const struct of_device_id *match) { @@ -10189,7 +10184,7 @@ static int __devinit niu_of_probe(struct of_device *op, dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM); np->regs = of_ioremap(&op->resource[1], 0, - res_size(&op->resource[1]), + resource_size(&op->resource[1]), "niu regs"); if (!np->regs) { dev_err(&op->dev, PFX "Cannot map device registers, " @@ -10199,7 +10194,7 @@ static int __devinit niu_of_probe(struct of_device *op, } np->vir_regs_1 = of_ioremap(&op->resource[2], 0, - res_size(&op->resource[2]), + resource_size(&op->resource[2]), "niu vregs-1"); if (!np->vir_regs_1) { dev_err(&op->dev, PFX "Cannot map device vir registers 1, " @@ -10209,7 +10204,7 @@ static int __devinit niu_of_probe(struct of_device *op, } np->vir_regs_2 = of_ioremap(&op->resource[3], 0, - res_size(&op->resource[3]), + resource_size(&op->resource[3]), "niu vregs-2"); if (!np->vir_regs_2) { dev_err(&op->dev, PFX "Cannot map device vir registers 2, " @@ -10244,19 +10239,19 @@ static int __devinit niu_of_probe(struct of_device *op, err_out_iounmap: if (np->vir_regs_1) { of_iounmap(&op->resource[2], np->vir_regs_1, - res_size(&op->resource[2])); + resource_size(&op->resource[2])); np->vir_regs_1 = NULL; } if (np->vir_regs_2) { of_iounmap(&op->resource[3], np->vir_regs_2, - res_size(&op->resource[3])); + resource_size(&op->resource[3])); np->vir_regs_2 = NULL; } if (np->regs) { of_iounmap(&op->resource[1], np->regs, - res_size(&op->resource[1])); + resource_size(&op->resource[1])); np->regs = NULL; } @@ -10281,19 +10276,19 @@ static int __devexit niu_of_remove(struct of_device *op) if (np->vir_regs_1) { of_iounmap(&op->resource[2], np->vir_regs_1, - res_size(&op->resource[2])); + resource_size(&op->resource[2])); np->vir_regs_1 = NULL; } if (np->vir_regs_2) { of_iounmap(&op->resource[3], np->vir_regs_2, - res_size(&op->resource[3])); + resource_size(&op->resource[3])); np->vir_regs_2 = NULL; } if (np->regs) { of_iounmap(&op->resource[1], np->regs, - res_size(&op->resource[1])); + resource_size(&op->resource[1])); np->regs = NULL; } -- cgit v1.2.3-18-g5258 From 7135a71b19be1faf48b7148d77844d03bc0717d6 Mon Sep 17 00:00:00 2001 From: Ed Cashin Date: Wed, 9 Sep 2009 14:10:18 +0200 Subject: aoe: allocate unused request_queue for sysfs Andy Whitcroft reported an oops in aoe triggered by use of an incorrectly initialised request_queue object: [ 2645.959090] kobject '' (ffff880059ca22c0): tried to add an uninitialized object, something is seriously wrong. [ 2645.959104] Pid: 6, comm: events/0 Not tainted 2.6.31-5-generic #24-Ubuntu [ 2645.959107] Call Trace: [ 2645.959139] [] kobject_add+0x5f/0x70 [ 2645.959151] [] blk_register_queue+0x8b/0xf0 [ 2645.959155] [] add_disk+0x8f/0x160 [ 2645.959161] [] aoeblk_gdalloc+0x164/0x1c0 [aoe] The request queue of an aoe device is not used but can be allocated in code that does not sleep. Bruno bisected this regression down to cd43e26f071524647e660706b784ebcbefbd2e44 block: Expose stacked device queues in sysfs "This seems to generate /sys/block/$device/queue and its contents for everyone who is using queues, not just for those queues that have a non-NULL queue->request_fn." Addresses http://bugs.launchpad.net/bugs/410198 Addresses http://bugzilla.kernel.org/show_bug.cgi?id=13942 Note that embedding a queue inside another object has always been an illegal construct, since the queues are reference counted and must persist until the last reference is dropped. So aoe was always buggy in this respect (Jens). Signed-off-by: Ed Cashin Cc: Andy Whitcroft Cc: "Rafael J. Wysocki" Cc: Bruno Premont Cc: Martin K. Petersen Cc: Andrew Morton Signed-off-by: Jens Axboe --- drivers/block/aoe/aoe.h | 2 +- drivers/block/aoe/aoeblk.c | 12 +++++++++--- drivers/block/aoe/aoedev.c | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 5e41e6dd657..db195abad69 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -155,7 +155,7 @@ struct aoedev { u16 fw_ver; /* version of blade's firmware */ struct work_struct work;/* disk create work struct */ struct gendisk *gd; - struct request_queue blkq; + struct request_queue *blkq; struct hd_geometry geo; sector_t ssize; struct timer_list timer; diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 2307a271bdc..1e15889c4b9 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -264,9 +264,12 @@ aoeblk_gdalloc(void *vp) goto err_disk; } - blk_queue_make_request(&d->blkq, aoeblk_make_request); - if (bdi_init(&d->blkq.backing_dev_info)) + d->blkq = blk_alloc_queue(GFP_KERNEL); + if (!d->blkq) goto err_mempool; + blk_queue_make_request(d->blkq, aoeblk_make_request); + if (bdi_init(&d->blkq->backing_dev_info)) + goto err_blkq; spin_lock_irqsave(&d->lock, flags); gd->major = AOE_MAJOR; gd->first_minor = d->sysminor * AOE_PARTITIONS; @@ -276,7 +279,7 @@ aoeblk_gdalloc(void *vp) snprintf(gd->disk_name, sizeof gd->disk_name, "etherd/e%ld.%d", d->aoemajor, d->aoeminor); - gd->queue = &d->blkq; + gd->queue = d->blkq; d->gd = gd; d->flags &= ~DEVFL_GDALLOC; d->flags |= DEVFL_UP; @@ -287,6 +290,9 @@ aoeblk_gdalloc(void *vp) aoedisk_add_sysfs(d); return; +err_blkq: + blk_cleanup_queue(d->blkq); + d->blkq = NULL; err_mempool: mempool_destroy(d->bufpool); err_disk: diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index eeea477d960..fa67027789a 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -113,6 +113,7 @@ aoedev_freedev(struct aoedev *d) if (d->bufpool) mempool_destroy(d->bufpool); skbpoolfree(d); + blk_cleanup_queue(d->blkq); kfree(d); } -- cgit v1.2.3-18-g5258 From 4789666e13fb0b2d45feb1b4a5119a1b997ec84c Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 6 Sep 2009 15:14:23 +0200 Subject: rt2x00: Hardcode TX ack timeout and consume time The calculated values for the ACK timeout and ACK consume time are different then the values as used by the Legacy drivers. After testing from James Ledwith it appeared that the calculated values caused a high amount of TX failures, and the values from the Legacy drivers were the most optimal to prevent TX failure due to excessive retries. The symptoms of this problem: - Rate control module always falls back to 1Mbs - Low throughput when bitrate was fixed Possible side-effects (not confirmed but highly likely) - Problems with DHCP - Broken connections due to lack of probe response This should fix at least: Kernel bugzilla reports: [13362], [13009], [9273] Fedora bugzilla reports: [443203] but possible some additional bugs as well. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 5 ++--- drivers/net/wireless/rt2x00/rt2500pci.c | 5 ++--- drivers/net/wireless/rt2x00/rt2500usb.c | 4 ---- drivers/net/wireless/rt2x00/rt2800usb.c | 3 +-- drivers/net/wireless/rt2x00/rt2x00.h | 3 --- drivers/net/wireless/rt2x00/rt2x00config.c | 11 ----------- drivers/net/wireless/rt2x00/rt61pci.c | 2 +- drivers/net/wireless/rt2x00/rt73usb.c | 2 +- 8 files changed, 7 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 164df9347a2..798f625e38f 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -331,9 +331,8 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev, preamble_mask = erp->short_preamble << 3; rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); - rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, erp->ack_timeout); - rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, - erp->ack_consume_time); + rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, 0x1ff); + rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, 0x13a); rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 4186582f277..2e872ac6982 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -337,9 +337,8 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev, preamble_mask = erp->short_preamble << 3; rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); - rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, erp->ack_timeout); - rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, - erp->ack_consume_time); + rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, 0x162); + rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, 0xa2); rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index b04f59bab3b..22dd6d9e298 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -488,10 +488,6 @@ static void rt2500usb_config_erp(struct rt2x00_dev *rt2x00dev, { u16 reg; - rt2500usb_register_read(rt2x00dev, TXRX_CSR1, ®); - rt2x00_set_field16(®, TXRX_CSR1_ACK_TIMEOUT, erp->ack_timeout); - rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg); - rt2500usb_register_read(rt2x00dev, TXRX_CSR10, ®); rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, !!erp->short_preamble); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 639dc6cc04b..a084077a1c6 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -580,8 +580,7 @@ static void rt2800usb_config_erp(struct rt2x00_dev *rt2x00dev, u32 reg; rt2x00usb_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); - rt2x00_set_field32(®, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, - DIV_ROUND_UP(erp->ack_timeout, erp->slot_time)); + rt2x00_set_field32(®, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 0x20); rt2x00usb_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); rt2x00usb_register_read(rt2x00dev, AUTO_RSP_CFG, ®); diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 555a777db6d..27bc6b7fbfd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -417,9 +417,6 @@ struct rt2x00lib_erp { int short_preamble; int cts_protection; - int ack_timeout; - int ack_consume_time; - u32 basic_rates; int slot_time; diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 3501788ab49..40a201e2e15 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -94,17 +94,6 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, erp.difs = bss_conf->use_short_slot ? SHORT_DIFS : DIFS; erp.eifs = bss_conf->use_short_slot ? SHORT_EIFS : EIFS; - erp.ack_timeout = PLCP + erp.difs + GET_DURATION(ACK_SIZE, 10); - erp.ack_consume_time = SIFS + PLCP + GET_DURATION(ACK_SIZE, 10); - - if (bss_conf->use_short_preamble) { - erp.ack_timeout += SHORT_PREAMBLE; - erp.ack_consume_time += SHORT_PREAMBLE; - } else { - erp.ack_timeout += PREAMBLE; - erp.ack_consume_time += PREAMBLE; - } - erp.basic_rates = bss_conf->basic_rates; erp.beacon_int = bss_conf->beacon_int; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index f4b4b86da4d..b20e3eac9d6 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -598,7 +598,7 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev, u32 reg; rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); + rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, 0x32); rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 90e11726305..1cbd9b4a3ef 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -561,7 +561,7 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev, u32 reg; rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); + rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, 0x32); rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); -- cgit v1.2.3-18-g5258 From b0544eb6019a33e836141156a8fbe74a9f8367b4 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 6 Sep 2009 15:42:45 +0200 Subject: b43: Really disable QoS, if requested Currently, when QoS-disable is requested, we would leave QoS enabled in firmware, but only queue frames on one queue. Change that and also tell firmware about disabled QoS, so it completely ignores all the QoS parameters. Also don't upload the parameters, if QoS is disabled. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 0a4d0b3eceb..d29323d5083 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3093,7 +3093,6 @@ static int b43_op_tx(struct ieee80211_hw *hw, return NETDEV_TX_OK; } -/* Locking: wl->irq_lock */ static void b43_qos_params_upload(struct b43_wldev *dev, const struct ieee80211_tx_queue_params *p, u16 shm_offset) @@ -3102,6 +3101,9 @@ static void b43_qos_params_upload(struct b43_wldev *dev, int bslots, tmp; unsigned int i; + if (!dev->qos_enabled) + return; + bslots = b43_read16(dev, B43_MMIO_RNG) & p->cw_min; memset(¶ms, 0, sizeof(params)); @@ -3147,6 +3149,9 @@ static void b43_qos_upload_all(struct b43_wldev *dev) struct b43_qos_params *params; unsigned int i; + if (!dev->qos_enabled) + return; + BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) != ARRAY_SIZE(wl->qos_params)); @@ -3206,6 +3211,16 @@ static void b43_qos_clear(struct b43_wl *wl) /* Initialize the core's QOS capabilities */ static void b43_qos_init(struct b43_wldev *dev) { + if (!dev->qos_enabled) { + /* Disable QOS support. */ + b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_EDCF); + b43_write16(dev, B43_MMIO_IFSCTL, + b43_read16(dev, B43_MMIO_IFSCTL) + & ~B43_MMIO_IFSCTL_USE_EDCF); + b43dbg(dev->wl, "QoS disabled\n"); + return; + } + /* Upload the current QOS parameters. */ b43_qos_upload_all(dev); @@ -3214,6 +3229,7 @@ static void b43_qos_init(struct b43_wldev *dev) b43_write16(dev, B43_MMIO_IFSCTL, b43_read16(dev, B43_MMIO_IFSCTL) | B43_MMIO_IFSCTL_USE_EDCF); + b43dbg(dev->wl, "QoS enabled\n"); } static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, -- cgit v1.2.3-18-g5258 From cde1b55b43b71cabb1a94278a809bca21b9df791 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 6 Sep 2009 16:18:58 +0200 Subject: b43: Fix sparse warning in hw-tkip code This fixes a sparse warning in the hardware-TKIP code: drivers/net/wireless/b43/xmit.c:272:18: warning: incorrect type in assignment (different base types) drivers/net/wireless/b43/xmit.c:272:18: expected unsigned short [unsigned] [short] drivers/net/wireless/b43/xmit.c:272:18: got restricted unsigned short [usertype] The code should work correctly with and without this patch applied. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/xmit.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index e7075d2c775..14f541248b5 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -267,11 +267,11 @@ int b43_generate_txhdr(struct b43_wldev *dev, */ ieee80211_get_tkip_key(info->control.hw_key, skb_frag, IEEE80211_TKIP_P1_KEY, (u8*)phase1key); - /* phase1key is in host endian */ - for (i = 0; i < 5; i++) - phase1key[i] = cpu_to_le16(phase1key[i]); - - memcpy(txhdr->iv, phase1key, 10); + /* phase1key is in host endian. Copy to little-endian txhdr->iv. */ + for (i = 0; i < 5; i++) { + txhdr->iv[i * 2 + 0] = phase1key[i]; + txhdr->iv[i * 2 + 1] = phase1key[i] >> 8; + } /* iv16 */ memcpy(txhdr->iv + 10, ((u8 *) wlhdr) + wlhdr_len, 3); } else { -- cgit v1.2.3-18-g5258 From 7b6840ab5f836a18c4ea98173f73c8d046930efb Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 7 Sep 2009 17:46:49 +0530 Subject: ath9k: Disable ASPM when btcoex is active Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 14 ++++++++++++++ drivers/net/wireless/ath/ath9k/hw.h | 5 +++++ drivers/net/wireless/ath/ath9k/main.c | 1 + 3 files changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 011b14f35e5..97a09dba76d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -16,6 +16,7 @@ #include #include +#include #include "ath9k.h" #include "initvals.h" @@ -4298,3 +4299,16 @@ void ath_gen_timer_isr(struct ath_hw *ah) timer->trigger(timer->arg); } } + +/* + * Primitive to disable ASPM + */ +void ath_pcie_aspm_disable(struct ath_softc *sc) +{ + struct pci_dev *pdev = to_pci_dev(sc->dev); + u8 aspm; + + pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm); + aspm &= ~(ATH_PCIE_CAP_LINK_L0S | ATH_PCIE_CAP_LINK_L1); + pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm); +} diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 5ca6ffa7091..a592f1a46ec 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -665,4 +665,9 @@ void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer); void ath_gen_timer_isr(struct ath_hw *hw); u32 ath9k_hw_gettsf32(struct ath_hw *ah); +#define ATH_PCIE_CAP_LINK_CTRL 0x70 +#define ATH_PCIE_CAP_LINK_L0S 1 +#define ATH_PCIE_CAP_LINK_L1 2 + +void ath_pcie_aspm_disable(struct ath_softc *sc); #endif diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a69fda8a910..ce011ab5e89 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2010,6 +2010,7 @@ static int ath9k_start(struct ieee80211_hw *hw) AR_STOMP_LOW_WLAN_WGHT); ath9k_hw_btcoex_enable(sc->sc_ah); + ath_pcie_aspm_disable(sc); if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) ath_btcoex_timer_resume(sc, &sc->btcoex_info); } -- cgit v1.2.3-18-g5258 From f020979d5d7c9816c071d0aedf60a889fa4fae40 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 7 Sep 2009 17:46:50 +0530 Subject: ath9k: Remove unnecessary casting to u8 in pci_read_config_byte() call Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/pci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 8bb286df71b..8b288141d4c 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -35,8 +35,7 @@ static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz) { u8 u8tmp; - pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, - (u8 *)&u8tmp); + pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, &u8tmp); *csz = (int)u8tmp; /* -- cgit v1.2.3-18-g5258 From 24ea602e183ca20a7577ebe253323d0e5d0f9847 Mon Sep 17 00:00:00 2001 From: Albert Herranz Date: Tue, 8 Sep 2009 19:30:12 +0200 Subject: ssb: Implement SDIO host bus support Add support for communicating with a Sonics Silicon Backplane through a SDIO interface, as found in the Nintendo Wii WLAN daughter card. The Nintendo Wii WLAN card includes a custom Broadcom 4318 chip with a SDIO host interface. Signed-off-by: Albert Herranz Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/Kconfig | 14 ++ drivers/ssb/Makefile | 1 + drivers/ssb/main.c | 58 ++++- drivers/ssb/scan.c | 11 + drivers/ssb/sdio.c | 610 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/ssb/ssb_private.h | 40 +++ 6 files changed, 733 insertions(+), 1 deletion(-) create mode 100644 drivers/ssb/sdio.c (limited to 'drivers') diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig index 540a2948596..2d8cc455dbc 100644 --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig @@ -66,6 +66,20 @@ config SSB_PCMCIAHOST If unsure, say N +config SSB_SDIOHOST_POSSIBLE + bool + depends on SSB && (MMC = y || MMC = SSB) + default y + +config SSB_SDIOHOST + bool "Support for SSB on SDIO-bus host" + depends on SSB_SDIOHOST_POSSIBLE + help + Support for a Sonics Silicon Backplane on top + of a SDIO device. + + If unsure, say N + config SSB_SILENT bool "No SSB kernel messages" depends on SSB && EMBEDDED diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile index cfbb74f2982..656e58b9261 100644 --- a/drivers/ssb/Makefile +++ b/drivers/ssb/Makefile @@ -6,6 +6,7 @@ ssb-$(CONFIG_SSB_SPROM) += sprom.o # host support ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o +ssb-$(CONFIG_SSB_SDIOHOST) += sdio.o # built-in drivers ssb-y += driver_chipcommon.o diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 8d16cb258cc..579b114be41 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -88,6 +89,25 @@ found: } #endif /* CONFIG_SSB_PCMCIAHOST */ +#ifdef CONFIG_SSB_SDIOHOST +struct ssb_bus *ssb_sdio_func_to_bus(struct sdio_func *func) +{ + struct ssb_bus *bus; + + ssb_buses_lock(); + list_for_each_entry(bus, &buses, list) { + if (bus->bustype == SSB_BUSTYPE_SDIO && + bus->host_sdio == func) + goto found; + } + bus = NULL; +found: + ssb_buses_unlock(); + + return bus; +} +#endif /* CONFIG_SSB_SDIOHOST */ + int ssb_for_each_bus_call(unsigned long data, int (*func)(struct ssb_bus *bus, unsigned long data)) { @@ -467,6 +487,12 @@ static int ssb_devices_register(struct ssb_bus *bus) #ifdef CONFIG_SSB_PCMCIAHOST sdev->irq = bus->host_pcmcia->irq.AssignedIRQ; dev->parent = &bus->host_pcmcia->dev; +#endif + break; + case SSB_BUSTYPE_SDIO: +#ifdef CONFIG_SSB_SDIO + sdev->irq = bus->host_sdio->dev.irq; + dev->parent = &bus->host_sdio->dev; #endif break; case SSB_BUSTYPE_SSB: @@ -724,12 +750,18 @@ static int ssb_bus_register(struct ssb_bus *bus, err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); if (err) goto out; + + /* Init SDIO-host device (if any), before the scan */ + err = ssb_sdio_init(bus); + if (err) + goto err_disable_xtal; + ssb_buses_lock(); bus->busnumber = next_busnumber; /* Scan for devices (cores) */ err = ssb_bus_scan(bus, baseaddr); if (err) - goto err_disable_xtal; + goto err_sdio_exit; /* Init PCI-host device (if any) */ err = ssb_pci_init(bus); @@ -776,6 +808,8 @@ err_pci_exit: ssb_pci_exit(bus); err_unmap: ssb_iounmap(bus); +err_sdio_exit: + ssb_sdio_exit(bus); err_disable_xtal: ssb_buses_unlock(); ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); @@ -825,6 +859,28 @@ int ssb_bus_pcmciabus_register(struct ssb_bus *bus, EXPORT_SYMBOL(ssb_bus_pcmciabus_register); #endif /* CONFIG_SSB_PCMCIAHOST */ +#ifdef CONFIG_SSB_SDIOHOST +int ssb_bus_sdiobus_register(struct ssb_bus *bus, struct sdio_func *func, + unsigned int quirks) +{ + int err; + + bus->bustype = SSB_BUSTYPE_SDIO; + bus->host_sdio = func; + bus->ops = &ssb_sdio_ops; + bus->quirks = quirks; + + err = ssb_bus_register(bus, ssb_sdio_get_invariants, ~0); + if (!err) { + ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " + "SDIO device %s\n", sdio_func_id(func)); + } + + return err; +} +EXPORT_SYMBOL(ssb_bus_sdiobus_register); +#endif /* CONFIG_SSB_PCMCIAHOST */ + int ssb_bus_ssbbus_register(struct ssb_bus *bus, unsigned long baseaddr, ssb_invariants_func_t get_invariants) diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c index 63ee5cfbefb..b74212d698c 100644 --- a/drivers/ssb/scan.c +++ b/drivers/ssb/scan.c @@ -175,6 +175,9 @@ static u32 scan_read32(struct ssb_bus *bus, u8 current_coreidx, } else ssb_pcmcia_switch_segment(bus, 0); break; + case SSB_BUSTYPE_SDIO: + offset += current_coreidx * SSB_CORE_SIZE; + return ssb_sdio_scan_read32(bus, offset); } return readl(bus->mmio + offset); } @@ -188,6 +191,8 @@ static int scan_switchcore(struct ssb_bus *bus, u8 coreidx) return ssb_pci_switch_coreidx(bus, coreidx); case SSB_BUSTYPE_PCMCIA: return ssb_pcmcia_switch_coreidx(bus, coreidx); + case SSB_BUSTYPE_SDIO: + return ssb_sdio_scan_switch_coreidx(bus, coreidx); } return 0; } @@ -206,6 +211,8 @@ void ssb_iounmap(struct ssb_bus *bus) SSB_BUG_ON(1); /* Can't reach this code. */ #endif break; + case SSB_BUSTYPE_SDIO: + break; } bus->mmio = NULL; bus->mapped_device = NULL; @@ -230,6 +237,10 @@ static void __iomem *ssb_ioremap(struct ssb_bus *bus, SSB_BUG_ON(1); /* Can't reach this code. */ #endif break; + case SSB_BUSTYPE_SDIO: + /* Nothing to ioremap in the SDIO case, just fake it */ + mmio = (void __iomem *)baseaddr; + break; } return mmio; diff --git a/drivers/ssb/sdio.c b/drivers/ssb/sdio.c new file mode 100644 index 00000000000..114051056b5 --- /dev/null +++ b/drivers/ssb/sdio.c @@ -0,0 +1,610 @@ +/* + * Sonics Silicon Backplane + * SDIO-Hostbus related functions + * + * Copyright 2009 Albert Herranz + * + * Based on drivers/ssb/pcmcia.c + * Copyright 2006 Johannes Berg + * Copyright 2007-2008 Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + * + */ + +#include +#include +#include +#include +#include + +#include "ssb_private.h" + +/* Define the following to 1 to enable a printk on each coreswitch. */ +#define SSB_VERBOSE_SDIOCORESWITCH_DEBUG 1 + + +/* Hardware invariants CIS tuples */ +#define SSB_SDIO_CIS 0x80 +#define SSB_SDIO_CIS_SROMREV 0x00 +#define SSB_SDIO_CIS_ID 0x01 +#define SSB_SDIO_CIS_BOARDREV 0x02 +#define SSB_SDIO_CIS_PA 0x03 +#define SSB_SDIO_CIS_PA_PA0B0_LO 0 +#define SSB_SDIO_CIS_PA_PA0B0_HI 1 +#define SSB_SDIO_CIS_PA_PA0B1_LO 2 +#define SSB_SDIO_CIS_PA_PA0B1_HI 3 +#define SSB_SDIO_CIS_PA_PA0B2_LO 4 +#define SSB_SDIO_CIS_PA_PA0B2_HI 5 +#define SSB_SDIO_CIS_PA_ITSSI 6 +#define SSB_SDIO_CIS_PA_MAXPOW 7 +#define SSB_SDIO_CIS_OEMNAME 0x04 +#define SSB_SDIO_CIS_CCODE 0x05 +#define SSB_SDIO_CIS_ANTENNA 0x06 +#define SSB_SDIO_CIS_ANTGAIN 0x07 +#define SSB_SDIO_CIS_BFLAGS 0x08 +#define SSB_SDIO_CIS_LEDS 0x09 + +#define CISTPL_FUNCE_LAN_NODE_ID 0x04 /* same as in PCMCIA */ + + +/* + * Function 1 miscellaneous registers. + * + * Definitions match src/include/sbsdio.h from the + * Android Open Source Project + * http://android.git.kernel.org/?p=platform/system/wlan/broadcom.git + * + */ +#define SBSDIO_FUNC1_SBADDRLOW 0x1000a /* SB Address window Low (b15) */ +#define SBSDIO_FUNC1_SBADDRMID 0x1000b /* SB Address window Mid (b23-b16) */ +#define SBSDIO_FUNC1_SBADDRHIGH 0x1000c /* SB Address window High (b24-b31) */ + +/* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */ +#define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid address bits in SBADDRLOW */ +#define SBSDIO_SBADDRMID_MASK 0xff /* Valid address bits in SBADDRMID */ +#define SBSDIO_SBADDRHIGH_MASK 0xff /* Valid address bits in SBADDRHIGH */ + +#define SBSDIO_SB_OFT_ADDR_MASK 0x7FFF /* sb offset addr is <= 15 bits, 32k */ + +/* REVISIT: this flag doesn't seem to matter */ +#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x8000 /* forces 32-bit SB access */ + + +/* + * Address map within the SDIO function address space (128K). + * + * Start End Description + * ------- ------- ------------------------------------------ + * 0x00000 0x0ffff selected backplane address window (64K) + * 0x10000 0x1ffff backplane control registers (max 64K) + * + * The current address window is configured by writing to registers + * SBADDRLOW, SBADDRMID and SBADDRHIGH. + * + * In order to access the contents of a 32-bit Silicon Backplane address + * the backplane address window must be first loaded with the highest + * 16 bits of the target address. Then, an access must be done to the + * SDIO function address space using the lower 15 bits of the address. + * Bit 15 of the address must be set when doing 32 bit accesses. + * + * 10987654321098765432109876543210 + * WWWWWWWWWWWWWWWWW SB Address Window + * OOOOOOOOOOOOOOOO Offset within SB Address Window + * a 32-bit access flag + */ + + +/* + * SSB I/O via SDIO. + * + * NOTE: SDIO address @addr is 17 bits long (SDIO address space is 128K). + */ + +static inline struct device *ssb_sdio_dev(struct ssb_bus *bus) +{ + return &bus->host_sdio->dev; +} + +/* host claimed */ +static int ssb_sdio_writeb(struct ssb_bus *bus, unsigned int addr, u8 val) +{ + int error = 0; + + sdio_writeb(bus->host_sdio, val, addr, &error); + if (unlikely(error)) { + dev_dbg(ssb_sdio_dev(bus), "%08X <- %02x, error %d\n", + addr, val, error); + } + + return error; +} + +#if 0 +static u8 ssb_sdio_readb(struct ssb_bus *bus, unsigned int addr) +{ + u8 val; + int error = 0; + + val = sdio_readb(bus->host_sdio, addr, &error); + if (unlikely(error)) { + dev_dbg(ssb_sdio_dev(bus), "%08X -> %02x, error %d\n", + addr, val, error); + } + + return val; +} +#endif + +/* host claimed */ +static int ssb_sdio_set_sbaddr_window(struct ssb_bus *bus, u32 address) +{ + int error; + + error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRLOW, + (address >> 8) & SBSDIO_SBADDRLOW_MASK); + if (error) + goto out; + error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRMID, + (address >> 16) & SBSDIO_SBADDRMID_MASK); + if (error) + goto out; + error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRHIGH, + (address >> 24) & SBSDIO_SBADDRHIGH_MASK); + if (error) + goto out; + bus->sdio_sbaddr = address; +out: + if (error) { + dev_dbg(ssb_sdio_dev(bus), "failed to set address window" + " to 0x%08x, error %d\n", address, error); + } + + return error; +} + +/* for enumeration use only */ +u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset) +{ + u32 val; + int error; + + sdio_claim_host(bus->host_sdio); + val = sdio_readl(bus->host_sdio, offset, &error); + sdio_release_host(bus->host_sdio); + if (unlikely(error)) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %08x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } + + return val; +} + +/* for enumeration use only */ +int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx) +{ + u32 sbaddr; + int error; + + sbaddr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE; + sdio_claim_host(bus->host_sdio); + error = ssb_sdio_set_sbaddr_window(bus, sbaddr); + sdio_release_host(bus->host_sdio); + if (error) { + dev_err(ssb_sdio_dev(bus), "failed to switch to core %u," + " error %d\n", coreidx, error); + goto out; + } +out: + return error; +} + +/* host must be already claimed */ +int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev) +{ + u8 coreidx = dev->core_index; + u32 sbaddr; + int error = 0; + + sbaddr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE; + if (unlikely(bus->sdio_sbaddr != sbaddr)) { +#if SSB_VERBOSE_SDIOCORESWITCH_DEBUG + dev_info(ssb_sdio_dev(bus), + "switching to %s core, index %d\n", + ssb_core_name(dev->id.coreid), coreidx); +#endif + error = ssb_sdio_set_sbaddr_window(bus, sbaddr); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "failed to switch to" + " core %u, error %d\n", coreidx, error); + goto out; + } + bus->mapped_device = dev; + } + +out: + return error; +} + +static u8 ssb_sdio_read8(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + u8 val = 0xff; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) + goto out; + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + val = sdio_readb(bus->host_sdio, offset, &error); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %02x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } +out: + sdio_release_host(bus->host_sdio); + + return val; +} + +static u16 ssb_sdio_read16(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + u16 val = 0xffff; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) + goto out; + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + val = sdio_readw(bus->host_sdio, offset, &error); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %04x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } +out: + sdio_release_host(bus->host_sdio); + + return val; +} + +static u32 ssb_sdio_read32(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + u32 val = 0xffffffff; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) + goto out; + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ + val = sdio_readl(bus->host_sdio, offset, &error); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %08x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } +out: + sdio_release_host(bus->host_sdio); + + return val; +} + +#ifdef CONFIG_SSB_BLOCKIO +static void ssb_sdio_block_read(struct ssb_device *dev, void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + size_t saved_count = count; + struct ssb_bus *bus = dev->bus; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) { + error = -EIO; + memset(buffer, 0xff, count); + goto err_out; + } + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + + switch (reg_width) { + case sizeof(u8): { + error = sdio_readsb(bus->host_sdio, buffer, offset, count); + break; + } + case sizeof(u16): { + SSB_WARN_ON(count & 1); + error = sdio_readsb(bus->host_sdio, buffer, offset, count); + break; + } + case sizeof(u32): { + SSB_WARN_ON(count & 3); + offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ + error = sdio_readsb(bus->host_sdio, buffer, offset, count); + break; + } + default: + SSB_WARN_ON(1); + } + if (!error) + goto out; + +err_out: + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%u), error %d\n", + bus->sdio_sbaddr >> 16, offset, reg_width, saved_count, error); +out: + sdio_release_host(bus->host_sdio); +} +#endif /* CONFIG_SSB_BLOCKIO */ + +static void ssb_sdio_write8(struct ssb_device *dev, u16 offset, u8 val) +{ + struct ssb_bus *bus = dev->bus; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) + goto out; + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + sdio_writeb(bus->host_sdio, val, offset, &error); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %02x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } +out: + sdio_release_host(bus->host_sdio); +} + +static void ssb_sdio_write16(struct ssb_device *dev, u16 offset, u16 val) +{ + struct ssb_bus *bus = dev->bus; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) + goto out; + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + sdio_writew(bus->host_sdio, val, offset, &error); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %04x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } +out: + sdio_release_host(bus->host_sdio); +} + +static void ssb_sdio_write32(struct ssb_device *dev, u16 offset, u32 val) +{ + struct ssb_bus *bus = dev->bus; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) + goto out; + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ + sdio_writel(bus->host_sdio, val, offset, &error); + if (error) { + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %08x, error %d\n", + bus->sdio_sbaddr >> 16, offset, val, error); + } + if (bus->quirks & SSB_QUIRK_SDIO_READ_AFTER_WRITE32) + sdio_readl(bus->host_sdio, 0, &error); +out: + sdio_release_host(bus->host_sdio); +} + +#ifdef CONFIG_SSB_BLOCKIO +static void ssb_sdio_block_write(struct ssb_device *dev, const void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + size_t saved_count = count; + struct ssb_bus *bus = dev->bus; + int error = 0; + + sdio_claim_host(bus->host_sdio); + if (unlikely(ssb_sdio_switch_core(bus, dev))) { + error = -EIO; + memset((void *)buffer, 0xff, count); + goto err_out; + } + offset |= bus->sdio_sbaddr & 0xffff; + offset &= SBSDIO_SB_OFT_ADDR_MASK; + + switch (reg_width) { + case sizeof(u8): + error = sdio_writesb(bus->host_sdio, offset, + (void *)buffer, count); + break; + case sizeof(u16): + SSB_WARN_ON(count & 1); + error = sdio_writesb(bus->host_sdio, offset, + (void *)buffer, count); + break; + case sizeof(u32): + SSB_WARN_ON(count & 3); + offset |= SBSDIO_SB_ACCESS_2_4B_FLAG; /* 32 bit data access */ + error = sdio_writesb(bus->host_sdio, offset, + (void *)buffer, count); + break; + default: + SSB_WARN_ON(1); + } + if (!error) + goto out; + +err_out: + dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%u), error %d\n", + bus->sdio_sbaddr >> 16, offset, reg_width, saved_count, error); +out: + sdio_release_host(bus->host_sdio); +} + +#endif /* CONFIG_SSB_BLOCKIO */ + +/* Not "static", as it's used in main.c */ +const struct ssb_bus_ops ssb_sdio_ops = { + .read8 = ssb_sdio_read8, + .read16 = ssb_sdio_read16, + .read32 = ssb_sdio_read32, + .write8 = ssb_sdio_write8, + .write16 = ssb_sdio_write16, + .write32 = ssb_sdio_write32, +#ifdef CONFIG_SSB_BLOCKIO + .block_read = ssb_sdio_block_read, + .block_write = ssb_sdio_block_write, +#endif +}; + +#define GOTO_ERROR_ON(condition, description) do { \ + if (unlikely(condition)) { \ + error_description = description; \ + goto error; \ + } \ + } while (0) + +int ssb_sdio_get_invariants(struct ssb_bus *bus, + struct ssb_init_invariants *iv) +{ + struct ssb_sprom *sprom = &iv->sprom; + struct ssb_boardinfo *bi = &iv->boardinfo; + const char *error_description = "none"; + struct sdio_func_tuple *tuple; + void *mac; + + memset(sprom, 0xFF, sizeof(*sprom)); + sprom->boardflags_lo = 0; + sprom->boardflags_hi = 0; + + tuple = bus->host_sdio->tuples; + while (tuple) { + switch (tuple->code) { + case 0x22: /* extended function */ + switch (tuple->data[0]) { + case CISTPL_FUNCE_LAN_NODE_ID: + GOTO_ERROR_ON((tuple->size != 7) && + (tuple->data[1] != 6), + "mac tpl size"); + /* fetch the MAC address. */ + mac = tuple->data + 2; + memcpy(sprom->il0mac, mac, ETH_ALEN); + memcpy(sprom->et1mac, mac, ETH_ALEN); + break; + default: + break; + } + break; + case 0x80: /* vendor specific tuple */ + switch (tuple->data[0]) { + case SSB_SDIO_CIS_SROMREV: + GOTO_ERROR_ON(tuple->size != 2, + "sromrev tpl size"); + sprom->revision = tuple->data[1]; + break; + case SSB_SDIO_CIS_ID: + GOTO_ERROR_ON((tuple->size != 5) && + (tuple->size != 7), + "id tpl size"); + bi->vendor = tuple->data[1] | + (tuple->data[2]<<8); + break; + case SSB_SDIO_CIS_BOARDREV: + GOTO_ERROR_ON(tuple->size != 2, + "boardrev tpl size"); + sprom->board_rev = tuple->data[1]; + break; + case SSB_SDIO_CIS_PA: + GOTO_ERROR_ON((tuple->size != 9) && + (tuple->size != 10), + "pa tpl size"); + sprom->pa0b0 = tuple->data[1] | + ((u16)tuple->data[2] << 8); + sprom->pa0b1 = tuple->data[3] | + ((u16)tuple->data[4] << 8); + sprom->pa0b2 = tuple->data[5] | + ((u16)tuple->data[6] << 8); + sprom->itssi_a = tuple->data[7]; + sprom->itssi_bg = tuple->data[7]; + sprom->maxpwr_a = tuple->data[8]; + sprom->maxpwr_bg = tuple->data[8]; + break; + case SSB_SDIO_CIS_OEMNAME: + /* Not present */ + break; + case SSB_SDIO_CIS_CCODE: + GOTO_ERROR_ON(tuple->size != 2, + "ccode tpl size"); + sprom->country_code = tuple->data[1]; + break; + case SSB_SDIO_CIS_ANTENNA: + GOTO_ERROR_ON(tuple->size != 2, + "ant tpl size"); + sprom->ant_available_a = tuple->data[1]; + sprom->ant_available_bg = tuple->data[1]; + break; + case SSB_SDIO_CIS_ANTGAIN: + GOTO_ERROR_ON(tuple->size != 2, + "antg tpl size"); + sprom->antenna_gain.ghz24.a0 = tuple->data[1]; + sprom->antenna_gain.ghz24.a1 = tuple->data[1]; + sprom->antenna_gain.ghz24.a2 = tuple->data[1]; + sprom->antenna_gain.ghz24.a3 = tuple->data[1]; + sprom->antenna_gain.ghz5.a0 = tuple->data[1]; + sprom->antenna_gain.ghz5.a1 = tuple->data[1]; + sprom->antenna_gain.ghz5.a2 = tuple->data[1]; + sprom->antenna_gain.ghz5.a3 = tuple->data[1]; + break; + case SSB_SDIO_CIS_BFLAGS: + GOTO_ERROR_ON((tuple->size != 3) && + (tuple->size != 5), + "bfl tpl size"); + sprom->boardflags_lo = tuple->data[1] | + ((u16)tuple->data[2] << 8); + break; + case SSB_SDIO_CIS_LEDS: + GOTO_ERROR_ON(tuple->size != 5, + "leds tpl size"); + sprom->gpio0 = tuple->data[1]; + sprom->gpio1 = tuple->data[2]; + sprom->gpio2 = tuple->data[3]; + sprom->gpio3 = tuple->data[4]; + break; + default: + break; + } + break; + default: + break; + } + tuple = tuple->next; + } + + return 0; +error: + dev_err(ssb_sdio_dev(bus), "failed to fetch device invariants: %s\n", + error_description); + return -ENODEV; +} + +void ssb_sdio_exit(struct ssb_bus *bus) +{ + if (bus->bustype != SSB_BUSTYPE_SDIO) + return; + /* Nothing to do here. */ +} + +int ssb_sdio_init(struct ssb_bus *bus) +{ + if (bus->bustype != SSB_BUSTYPE_SDIO) + return 0; + + bus->sdio_sbaddr = ~0; + + return 0; +} diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 57fa482abb9..25433565dfd 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -114,6 +114,46 @@ static inline int ssb_pcmcia_init(struct ssb_bus *bus) } #endif /* CONFIG_SSB_PCMCIAHOST */ +/* sdio.c */ +#ifdef CONFIG_SSB_SDIOHOST +extern int ssb_sdio_get_invariants(struct ssb_bus *bus, + struct ssb_init_invariants *iv); + +extern u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset); +extern int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev); +extern int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx); +extern int ssb_sdio_hardware_setup(struct ssb_bus *bus); +extern void ssb_sdio_exit(struct ssb_bus *bus); +extern int ssb_sdio_init(struct ssb_bus *bus); + +extern const struct ssb_bus_ops ssb_sdio_ops; +#else /* CONFIG_SSB_SDIOHOST */ +static inline u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset) +{ + return 0; +} +static inline int ssb_sdio_switch_core(struct ssb_bus *bus, + struct ssb_device *dev) +{ + return 0; +} +static inline int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx) +{ + return 0; +} +static inline int ssb_sdio_hardware_setup(struct ssb_bus *bus) +{ + return 0; +} +static inline void ssb_sdio_exit(struct ssb_bus *bus) +{ +} +static inline int ssb_sdio_init(struct ssb_bus *bus) +{ + return 0; +} +#endif /* CONFIG_SSB_SDIOHOST */ + /* scan.c */ extern const char *ssb_core_name(u16 coreid); -- cgit v1.2.3-18-g5258 From 98a1e2a9260d30ad691fbd1ed778a05e38fe655b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 8 Sep 2009 19:33:31 +0200 Subject: b44/b43/b43legacy: Fix switch warnings introduced by SSB-SDIO This fixes some gcc warnings for switch statements. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/b44.c | 10 ++++++++-- drivers/net/wireless/b43/main.c | 8 ++++++-- drivers/net/wireless/b43legacy/main.c | 8 ++++++-- 3 files changed, 20 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 951735c9ec0..0189dcd36f3 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1303,10 +1303,13 @@ static void b44_chip_reset(struct b44 *bp, int reset_kind) & MDIO_CTRL_MAXF_MASK))); break; case SSB_BUSTYPE_PCI: - case SSB_BUSTYPE_PCMCIA: bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | (0x0d & MDIO_CTRL_MAXF_MASK))); break; + case SSB_BUSTYPE_PCMCIA: + case SSB_BUSTYPE_SDIO: + WARN_ON(1); /* A device with this bus does not exist. */ + break; } br32(bp, B44_MDIO_CTRL); @@ -1764,10 +1767,13 @@ static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *inf case SSB_BUSTYPE_PCI: strlcpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info)); break; - case SSB_BUSTYPE_PCMCIA: case SSB_BUSTYPE_SSB: strlcpy(info->bus_info, "SSB", sizeof(info->bus_info)); break; + case SSB_BUSTYPE_PCMCIA: + case SSB_BUSTYPE_SDIO: + WARN_ON(1); /* A device with this bus does not exist. */ + break; } } diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index d29323d5083..7a9a3fa5542 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4092,16 +4092,20 @@ static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev) bus->pcicore.dev->id.revision <= 5) { /* IMCFGLO timeouts workaround. */ tmp = ssb_read32(dev->dev, SSB_IMCFGLO); - tmp &= ~SSB_IMCFGLO_REQTO; - tmp &= ~SSB_IMCFGLO_SERTO; switch (bus->bustype) { case SSB_BUSTYPE_PCI: case SSB_BUSTYPE_PCMCIA: + tmp &= ~SSB_IMCFGLO_REQTO; + tmp &= ~SSB_IMCFGLO_SERTO; tmp |= 0x32; break; case SSB_BUSTYPE_SSB: + tmp &= ~SSB_IMCFGLO_REQTO; + tmp &= ~SSB_IMCFGLO_SERTO; tmp |= 0x53; break; + default: + break; } ssb_write32(dev->dev, SSB_IMCFGLO, tmp); } diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index b166a6f9f05..1d9223b3d4c 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3106,16 +3106,20 @@ static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev) bus->pcicore.dev->id.revision <= 5) { /* IMCFGLO timeouts workaround. */ tmp = ssb_read32(dev->dev, SSB_IMCFGLO); - tmp &= ~SSB_IMCFGLO_REQTO; - tmp &= ~SSB_IMCFGLO_SERTO; switch (bus->bustype) { case SSB_BUSTYPE_PCI: case SSB_BUSTYPE_PCMCIA: + tmp &= ~SSB_IMCFGLO_REQTO; + tmp &= ~SSB_IMCFGLO_SERTO; tmp |= 0x32; break; case SSB_BUSTYPE_SSB: + tmp &= ~SSB_IMCFGLO_REQTO; + tmp &= ~SSB_IMCFGLO_SERTO; tmp |= 0x53; break; + default: + break; } ssb_write32(dev->dev, SSB_IMCFGLO, tmp); } -- cgit v1.2.3-18-g5258 From 4d8cd26849737e141ff0aa23fedacef4ea76ea4f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 8 Sep 2009 12:09:47 -0700 Subject: wireless: mark prism54 as deprecated and mark for removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The preferred module is p54pci which also supports FullMAC PCI / Cardbus devices. We schedule removal for 2.6.34. Reason to remove this is no one really is testing prism54 anymore, and while it works p54pci provides support for the same hardware. It should be noted I have been told some FullMAC devices may not have worked with the SoftMAC driver but to date we have yet to recieve a single bug report regarding this. If there are users out there please let us know! Cc: aquilaver@yahoo.com Cc: linux-kernel@vger.kernel.org Cc: Dan Williams Cc: Kai Engert Cc: Jean Tourrilhes Cc: Tim de Waal Cc: Roy Marples Cc: Alan Cox Cc: Christian Lamparter Cc: Björn Steinbrink Cc: Tim Gardner Cc: Larry Finger Cc: Johannes Berg Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 57 +++++++++++++------------------------------- 1 file changed, 16 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index a8871a84d87..ad89d23968d 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -275,51 +275,26 @@ config PCMCIA_WL3501 micro support for ethtool. config PRISM54 - tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus' + tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus (DEPRECATED)' depends on PCI && EXPERIMENTAL && WLAN_80211 select WIRELESS_EXT select FW_LOADER ---help--- - Enable PCI and Cardbus support for the following chipset based cards: - - ISL3880 - Prism GT 802.11 b/g - ISL3877 - Prism Indigo 802.11 a - ISL3890 - Prism Duette 802.11 a/b/g - - For a complete list of supported cards visit . - Here is the latest confirmed list of supported cards: - - 3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72 (version 1) - Allnet ALL0271 PCI Card - Compex WL54G Cardbus Card - Corega CG-WLCB54GT Cardbus Card - D-Link Air Plus Xtreme G A1 Cardbus Card aka DWL-g650 - I-O Data WN-G54/CB Cardbus Card - Kobishi XG-300 aka Z-Com Cardbus Card - Netgear WG511 Cardbus Card - Ovislink WL-5400PCI PCI Card - Peabird WLG-PCI PCI Card - Sitecom WL-100i Cardbus Card - Sitecom WL-110i PCI Card - SMC2802W - EZ Connect g 2.4GHz 54 Mbps Wireless PCI Card - SMC2835W - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card - SMC2835W-V2 - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card - Z-Com XG-900 PCI Card - Zyxel G-100 Cardbus Card - - If you enable this you will need a firmware file as well. - You will need to copy this to /usr/lib/hotplug/firmware/isl3890. - You can get this non-GPL'd firmware file from the Prism54 project page: - - You will also need the /etc/hotplug/firmware.agent script from - a current hotplug package. - - Note: You need a motherboard with DMA support to use any of these cards - - If you want to compile the driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . - The module will be called prism54. + This enables support for FullMAC PCI/Cardbus prism54 devices. This + driver is now deprecated in favor for the SoftMAC driver, p54pci. + p54pci supports FullMAC PCI/Cardbus devices as well. For details on + the scheduled removal of this driver on the kernel see the feature + removal schedule: + + Documentation/feature-removal-schedule.txt + + For more information refer to the p54 wiki: + + http://wireless.kernel.org/en/users/Drivers/p54 + + Note: You need a motherboard with DMA support to use any of these cards + + When built as module you get the module prism54 config USB_ZD1201 tristate "USB ZD1201 based Wireless device support" -- cgit v1.2.3-18-g5258 From aeac355d23fb13a2082a8740ae7cf9408a71ec2c Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 9 Sep 2009 15:25:49 +0530 Subject: ath9k: Store subsystem id in struct hw_version This subsystem id will be used later to turn on the btcoex support. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ahb.c | 2 +- drivers/net/wireless/ath/ath9k/ath9k.h | 2 +- drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/main.c | 7 ++++--- drivers/net/wireless/ath/ath9k/pci.c | 4 +++- 5 files changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 7dc6301ae20..2ad7d0280f7 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -119,7 +119,7 @@ static int ath_ahb_probe(struct platform_device *pdev) sc->bus_ops = &ath_ahb_bus_ops; sc->irq = irq; - ret = ath_init_device(AR5416_AR9100_DEVID, sc); + ret = ath_init_device(AR5416_AR9100_DEVID, sc, 0x0); if (ret) { dev_err(&pdev->dev, "failed to initialize device\n"); goto err_free_hw; diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 1c68a9da22d..1d59f10f68d 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -658,7 +658,7 @@ extern struct ieee80211_ops ath9k_ops; irqreturn_t ath_isr(int irq, void *dev); void ath_cleanup(struct ath_softc *sc); -int ath_init_device(u16 devid, struct ath_softc *sc); +int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid); void ath_detach(struct ath_softc *sc); const char *ath_mac_bb_name(u32 mac_bb_version); const char *ath_rf_name(u16 rf_version); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index a592f1a46ec..64ea547adef 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -390,6 +390,7 @@ struct ath9k_hw_version { u16 phyRev; u16 analog5GhzRev; u16 analog2GhzRev; + u16 subsysid; }; /* Generic TSF timer definitions */ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index ce011ab5e89..3dc7b5a13e6 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1310,7 +1310,7 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, * to allow the separation between hardware specific * variables (now in ath_hw) and driver specific variables. */ -static int ath_init_softc(u16 devid, struct ath_softc *sc) +static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) { struct ath_hw *ah = NULL; int r = 0, i; @@ -1348,6 +1348,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc) ah->ah_sc = sc; ah->hw_version.devid = devid; + ah->hw_version.subsysid = subsysid; sc->sc_ah = ah; r = ath9k_hw_init(ah); @@ -1577,7 +1578,7 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) } /* Device driver core initialization */ -int ath_init_device(u16 devid, struct ath_softc *sc) +int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid) { struct ieee80211_hw *hw = sc->hw; int error = 0, i; @@ -1585,7 +1586,7 @@ int ath_init_device(u16 devid, struct ath_softc *sc) DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); - error = ath_init_softc(devid, sc); + error = ath_init_softc(devid, sc, subsysid); if (error != 0) return error; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 8b288141d4c..903dd8ad9d4 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -88,6 +88,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct ath_softc *sc; struct ieee80211_hw *hw; u8 csz; + u16 subsysid; u32 val; int ret = 0; struct ath_hw *ah; @@ -178,7 +179,8 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) sc->mem = mem; sc->bus_ops = &ath_pci_bus_ops; - ret = ath_init_device(id->device, sc); + pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid); + ret = ath_init_device(id->device, sc, subsysid); if (ret) { dev_err(&pdev->dev, "failed to initialize device\n"); goto bad3; -- cgit v1.2.3-18-g5258 From fe12946e66575677879941a14f75b70ca2d2962a Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 9 Sep 2009 15:25:50 +0530 Subject: ath9k: Enable btcoex based on the subsystem id of the device Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/btcoex.c | 23 +++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/btcoex.h | 1 + drivers/net/wireless/ath/ath9k/hw.c | 3 ++- drivers/net/wireless/ath/ath9k/hw.h | 4 ++++ 4 files changed, 30 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index e8bfb01ee78..55f607b7699 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -19,6 +19,29 @@ static const struct ath_btcoex_config ath_bt_config = { 0, true, true, ATH_BT_COEX_MODE_SLOTTED, true, true, 2, 5, true }; +static const u16 ath_subsysid_tbl[] = { + AR9280_COEX2WIRE_SUBSYSID, + AT9285_COEX3WIRE_SA_SUBSYSID, + AT9285_COEX3WIRE_DA_SUBSYSID +}; + +/* + * Checks the subsystem id of the device to see if it + * supports btcoex + */ +bool ath_btcoex_supported(u16 subsysid) +{ + int i; + + if (!subsysid) + return false; + + for (i = 0; i < ARRAY_SIZE(ath_subsysid_tbl); i++) + if (subsysid == ath_subsysid_tbl[i]) + return true; + + return false; +} /* * Detects if there is any priority bt traffic diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 45568196c59..f1baf66e2ec 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -79,6 +79,7 @@ struct ath_btcoex_info { struct ath_gen_timer *no_stomp_timer; /*Timer for no BT stomping*/ }; +bool ath_btcoex_supported(u16 subsysid); int ath9k_hw_btcoex_init(struct ath_hw *ah); void ath9k_hw_btcoex_enable(struct ath_hw *ah); void ath9k_hw_btcoex_disable(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 97a09dba76d..8d77817f67a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3690,7 +3690,8 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->num_antcfg_2ghz = ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ); - if (AR_SREV_9280_10_OR_LATER(ah) && btcoex_enable) { + if (AR_SREV_9280_10_OR_LATER(ah) && + ath_btcoex_supported(ah->hw_version.subsysid)) { btcoex_info->btactive_gpio = ATH_BTACTIVE_GPIO; btcoex_info->wlanactive_gpio = ATH_WLANACTIVE_GPIO; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 64ea547adef..9106a0b537d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -45,6 +45,10 @@ #define AR5416_DEVID_AR9287_PCI 0x002D #define AR5416_DEVID_AR9287_PCIE 0x002E +#define AR9280_COEX2WIRE_SUBSYSID 0x309b +#define AT9285_COEX3WIRE_SA_SUBSYSID 0x30aa +#define AT9285_COEX3WIRE_DA_SUBSYSID 0x30ab + /* Register read/write primitives */ #define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val)) #define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg)) -- cgit v1.2.3-18-g5258 From f42cc2c2909f24faa1381ae139067edeba8c796d Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 9 Sep 2009 15:25:51 +0530 Subject: ath9k: Get rid of the modparam btcoex_enable Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8d77817f67a..c39693ba06a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -21,10 +21,6 @@ #include "ath9k.h" #include "initvals.h" -static int btcoex_enable; -module_param(btcoex_enable, bool, 0); -MODULE_PARM_DESC(btcoex_enable, "Enable Bluetooth coexistence support"); - #define ATH9K_CLOCK_RATE_CCK 22 #define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 #define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 -- cgit v1.2.3-18-g5258 From 8c8f9ba7051b017e44124666b41c1dc70333a77c Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 9 Sep 2009 15:25:52 +0530 Subject: ath9k: Initialize the priority gpio for BT coex 3-wire Oops, a stupid mistake in the original patch which adds coex 3-wire support. Bluetooth priority gpio needs to be gpio 7. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/btcoex.h | 1 + drivers/net/wireless/ath/ath9k/hw.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index f1baf66e2ec..297b027fd3c 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -19,6 +19,7 @@ #define ATH_WLANACTIVE_GPIO 5 #define ATH_BTACTIVE_GPIO 6 +#define ATH_BTPRIORITY_GPIO 7 #define ATH_BTCOEX_DEF_BT_PERIOD 45 #define ATH_BTCOEX_DEF_DUTY_CYCLE 55 diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index c39693ba06a..b6c6cca0781 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3691,10 +3691,12 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) btcoex_info->btactive_gpio = ATH_BTACTIVE_GPIO; btcoex_info->wlanactive_gpio = ATH_WLANACTIVE_GPIO; - if (AR_SREV_9285(ah)) + if (AR_SREV_9285(ah)) { btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_3WIRE; - else + btcoex_info->btpriority_gpio = ATH_BTPRIORITY_GPIO; + } else { btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_2WIRE; + } } else { btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_NONE; } -- cgit v1.2.3-18-g5258 From 13a239330abdda5afcb1161fce68ec214af2cc90 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 9 Sep 2009 11:25:55 -0700 Subject: RDMA/cxgb3: Don't ignore insert_handle() failures Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb3/iwch_mem.c | 21 ++++++++---- drivers/infiniband/hw/cxgb3/iwch_provider.c | 50 ++++++++++++++++++++--------- 2 files changed, 49 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb3/iwch_mem.c b/drivers/infiniband/hw/cxgb3/iwch_mem.c index ec49a5cbdeb..e1ec65ebb01 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_mem.c +++ b/drivers/infiniband/hw/cxgb3/iwch_mem.c @@ -39,7 +39,7 @@ #include "iwch.h" #include "iwch_provider.h" -static void iwch_finish_mem_reg(struct iwch_mr *mhp, u32 stag) +static int iwch_finish_mem_reg(struct iwch_mr *mhp, u32 stag) { u32 mmid; @@ -47,14 +47,15 @@ static void iwch_finish_mem_reg(struct iwch_mr *mhp, u32 stag) mhp->attr.stag = stag; mmid = stag >> 8; mhp->ibmr.rkey = mhp->ibmr.lkey = stag; - insert_handle(mhp->rhp, &mhp->rhp->mmidr, mhp, mmid); PDBG("%s mmid 0x%x mhp %p\n", __func__, mmid, mhp); + return insert_handle(mhp->rhp, &mhp->rhp->mmidr, mhp, mmid); } int iwch_register_mem(struct iwch_dev *rhp, struct iwch_pd *php, struct iwch_mr *mhp, int shift) { u32 stag; + int ret; if (cxio_register_phys_mem(&rhp->rdev, &stag, mhp->attr.pdid, @@ -66,9 +67,11 @@ int iwch_register_mem(struct iwch_dev *rhp, struct iwch_pd *php, mhp->attr.pbl_size, mhp->attr.pbl_addr)) return -ENOMEM; - iwch_finish_mem_reg(mhp, stag); - - return 0; + ret = iwch_finish_mem_reg(mhp, stag); + if (ret) + cxio_dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size, + mhp->attr.pbl_addr); + return ret; } int iwch_reregister_mem(struct iwch_dev *rhp, struct iwch_pd *php, @@ -77,6 +80,7 @@ int iwch_reregister_mem(struct iwch_dev *rhp, struct iwch_pd *php, int npages) { u32 stag; + int ret; /* We could support this... */ if (npages > mhp->attr.pbl_size) @@ -93,9 +97,12 @@ int iwch_reregister_mem(struct iwch_dev *rhp, struct iwch_pd *php, mhp->attr.pbl_size, mhp->attr.pbl_addr)) return -ENOMEM; - iwch_finish_mem_reg(mhp, stag); + ret = iwch_finish_mem_reg(mhp, stag); + if (ret) + cxio_dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size, + mhp->attr.pbl_addr); - return 0; + return ret; } int iwch_alloc_pbl(struct iwch_mr *mhp, int npages) diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index 72aa57cdf69..6895523779d 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -195,7 +195,11 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int ve spin_lock_init(&chp->lock); atomic_set(&chp->refcnt, 1); init_waitqueue_head(&chp->wait); - insert_handle(rhp, &rhp->cqidr, chp, chp->cq.cqid); + if (insert_handle(rhp, &rhp->cqidr, chp, chp->cq.cqid)) { + cxio_destroy_cq(&chp->rhp->rdev, &chp->cq); + kfree(chp); + return ERR_PTR(-ENOMEM); + } if (ucontext) { struct iwch_mm_entry *mm; @@ -750,7 +754,11 @@ static struct ib_mw *iwch_alloc_mw(struct ib_pd *pd) mhp->attr.stag = stag; mmid = (stag) >> 8; mhp->ibmw.rkey = stag; - insert_handle(rhp, &rhp->mmidr, mhp, mmid); + if (insert_handle(rhp, &rhp->mmidr, mhp, mmid)) { + cxio_deallocate_window(&rhp->rdev, mhp->attr.stag); + kfree(mhp); + return ERR_PTR(-ENOMEM); + } PDBG("%s mmid 0x%x mhp %p stag 0x%x\n", __func__, mmid, mhp, stag); return &(mhp->ibmw); } @@ -778,37 +786,43 @@ static struct ib_mr *iwch_alloc_fast_reg_mr(struct ib_pd *pd, int pbl_depth) struct iwch_mr *mhp; u32 mmid; u32 stag = 0; - int ret; + int ret = 0; php = to_iwch_pd(pd); rhp = php->rhp; mhp = kzalloc(sizeof(*mhp), GFP_KERNEL); if (!mhp) - return ERR_PTR(-ENOMEM); + goto err; mhp->rhp = rhp; ret = iwch_alloc_pbl(mhp, pbl_depth); - if (ret) { - kfree(mhp); - return ERR_PTR(ret); - } + if (ret) + goto err1; mhp->attr.pbl_size = pbl_depth; ret = cxio_allocate_stag(&rhp->rdev, &stag, php->pdid, mhp->attr.pbl_size, mhp->attr.pbl_addr); - if (ret) { - iwch_free_pbl(mhp); - kfree(mhp); - return ERR_PTR(ret); - } + if (ret) + goto err2; mhp->attr.pdid = php->pdid; mhp->attr.type = TPT_NON_SHARED_MR; mhp->attr.stag = stag; mhp->attr.state = 1; mmid = (stag) >> 8; mhp->ibmr.rkey = mhp->ibmr.lkey = stag; - insert_handle(rhp, &rhp->mmidr, mhp, mmid); + if (insert_handle(rhp, &rhp->mmidr, mhp, mmid)) + goto err3; + PDBG("%s mmid 0x%x mhp %p stag 0x%x\n", __func__, mmid, mhp, stag); return &(mhp->ibmr); +err3: + cxio_dereg_mem(&rhp->rdev, stag, mhp->attr.pbl_size, + mhp->attr.pbl_addr); +err2: + iwch_free_pbl(mhp); +err1: + kfree(mhp); +err: + return ERR_PTR(ret); } static struct ib_fast_reg_page_list *iwch_alloc_fastreg_pbl( @@ -961,7 +975,13 @@ static struct ib_qp *iwch_create_qp(struct ib_pd *pd, spin_lock_init(&qhp->lock); init_waitqueue_head(&qhp->wait); atomic_set(&qhp->refcnt, 1); - insert_handle(rhp, &rhp->qpidr, qhp, qhp->wq.qpid); + + if (insert_handle(rhp, &rhp->qpidr, qhp, qhp->wq.qpid)) { + cxio_destroy_qp(&rhp->rdev, &qhp->wq, + ucontext ? &ucontext->uctx : &rhp->rdev.uctx); + kfree(qhp); + return ERR_PTR(-ENOMEM); + } if (udata) { -- cgit v1.2.3-18-g5258 From ffc40c6433e763209d2b1ec5b1a9854eb3bcd61c Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 9 Sep 2009 11:25:56 -0700 Subject: RDMA/cxgb3: Clean up properly on FW mismatch failures FW mismatches can cause a crash in the iw_cxgb3 event handler. - NULL the t3cdev->ulp pointer on failures in cxio_rdev_open() - Silently ignore events when the ulp ptr is NULL in iwch_err_handler() Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb3/cxio_hal.c | 1 + drivers/infiniband/hw/cxgb3/iwch.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index 4dec515c676..72ed3396b72 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -1034,6 +1034,7 @@ err3: err2: cxio_hal_destroy_ctrl_qp(rdev_p); err1: + rdev_p->t3cdev_p->ulp = NULL; list_del(&rdev_p->entry); return err; } diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c index 5796170b0b2..3f0c99daae8 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.c +++ b/drivers/infiniband/hw/cxgb3/iwch.c @@ -165,10 +165,13 @@ static void close_rnic_dev(struct t3cdev *tdev) static void iwch_event_handler(struct t3cdev *tdev, u32 evt, u32 port_id) { struct cxio_rdev *rdev = tdev->ulp; - struct iwch_dev *rnicp = rdev_to_iwch_dev(rdev); + struct iwch_dev *rnicp; struct ib_event event; u32 portnum = port_id + 1; + if (!rdev) + return; + rnicp = rdev_to_iwch_dev(rdev); switch (evt) { case OFFLOAD_STATUS_DOWN: { rdev->flags = CXIO_ERROR_FATAL; -- cgit v1.2.3-18-g5258 From cb58160e72244a23f4e0cf4d6f81ffbd131fcd51 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 9 Sep 2009 11:37:38 -0700 Subject: RDMA/iwcm: Reject the connection when the cm_id is destroyed If the cm_id of a connect request is destroyed prior to the ULP accepting or rejecting the connection, then the provider never cleans up the connection. The iwcm should explicitly reject these connections if the cm_id is destroyed. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/core/iwcm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c index 8f9509e1ebf..55d093a36ae 100644 --- a/drivers/infiniband/core/iwcm.c +++ b/drivers/infiniband/core/iwcm.c @@ -362,6 +362,7 @@ static void destroy_cm_id(struct iw_cm_id *cm_id) * In either case, must tell the provider to reject. */ cm_id_priv->state = IW_CM_STATE_DESTROYING; + cm_id->device->iwcm->reject(cm_id, NULL, 0); break; case IW_CM_STATE_CONN_SENT: case IW_CM_STATE_DESTROYING: -- cgit v1.2.3-18-g5258 From 577eebeae34d340685d8985dfdb7dfe337c511e8 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 27 Aug 2009 12:46:35 -0700 Subject: xen: make -fstack-protector work under Xen -fstack-protector uses a special per-cpu "stack canary" value. gcc generates special code in each function to test the canary to make sure that the function's stack hasn't been overrun. On x86-64, this is simply an offset of %gs, which is the usual per-cpu base segment register, so setting it up simply requires loading %gs's base as normal. On i386, the stack protector segment is %gs (rather than the usual kernel percpu %fs segment register). This requires setting up the full kernel GDT and then loading %gs accordingly. We also need to make sure %gs is initialized when bringing up secondary cpus too. To keep things consistent, we do the full GDT/segment register setup on both architectures. Because we need to avoid -fstack-protected code before setting up the GDT and because there's no way to disable it on a per-function basis, several files need to have stack-protector inhibited. [ Impact: allow Xen booting with stack-protector enabled ] Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/Makefile | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index ec2a39b1e26..7c284342f30 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -1,6 +1,9 @@ obj-y += grant-table.o features.o events.o manage.o obj-y += xenbus/ +nostackp := $(call cc-option, -fno-stack-protector) +CFLAGS_features.o := $(nostackp) + obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o obj-$(CONFIG_XEN_XENCOMM) += xencomm.o obj-$(CONFIG_XEN_BALLOON) += balloon.o -- cgit v1.2.3-18-g5258 From 3db7675506ef7460bf6220545bfc69abb7dbceab Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Wed, 9 Sep 2009 18:12:37 -0700 Subject: netxen: fix check for ip addr hashing support Fix typo in checking dest ip has support before programming destip addresses. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 304618aa09d..81c24a7effc 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -2340,7 +2340,7 @@ netxen_config_indev_addr(struct net_device *dev, unsigned long event) struct in_device *indev; struct netxen_adapter *adapter = netdev_priv(dev); - if (netxen_destip_supported(adapter)) + if (!netxen_destip_supported(adapter)) return; indev = in_dev_get(dev); -- cgit v1.2.3-18-g5258 From 58f25468b5636c390ad2a58356b127c0055884b4 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Wed, 9 Sep 2009 18:12:59 -0700 Subject: netxen: fix tx descriptor structure Fix the offset of vlan_TCI field in cmd_desc_type0. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 2a52479bcdf..23718887d02 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -348,9 +348,9 @@ struct cmd_desc_type0 { __le64 addr_buffer4; - __le16 vlan_TCI; - __le16 reserved; __le32 reserved2; + __le16 reserved; + __le16 vlan_TCI; } __attribute__ ((aligned(64))); -- cgit v1.2.3-18-g5258 From 07fcb044b6ea53b67d00e198f9073e0538df7b75 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 9 Sep 2009 01:07:44 +0000 Subject: dm9000: Remove unnecessary memset of netdev private data The memory for the private data is allocated using kzalloc in alloc_etherdev (or alloc_netdev_mq respectively) so there is no need to set it to 0 again. Signed-off-by: Tobias Klauser Signed-off-by: David S. Miller --- drivers/net/dm9000.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index a2bc4158259..60de17689e6 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -1281,7 +1281,6 @@ dm9000_probe(struct platform_device *pdev) /* setup board info structure */ db = netdev_priv(ndev); - memset(db, 0, sizeof(*db)); db->dev = &pdev->dev; db->ndev = ndev; -- cgit v1.2.3-18-g5258 From ec282e9225be924479d4880b51f13524795bd8d3 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 9 Sep 2009 01:07:43 +0000 Subject: dm9000: Use resource_size instead of private macro The macro res_size in drivers/net/dm9000.c is a copy of resource_size in linux/ioport.h. Remove the function and use resource_size instead. Signed-off-by: Tobias Klauser Signed-off-by: David S. Miller --- drivers/net/dm9000.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 60de17689e6..31b8bef49d2 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -1251,8 +1251,6 @@ static const struct net_device_ops dm9000_netdev_ops = { #endif }; -#define res_size(_r) (((_r)->end - (_r)->start) + 1) - /* * Search DM9000 board, allocate space and register it */ @@ -1301,7 +1299,7 @@ dm9000_probe(struct platform_device *pdev) goto out; } - iosize = res_size(db->addr_res); + iosize = resource_size(db->addr_res); db->addr_req = request_mem_region(db->addr_res->start, iosize, pdev->name); @@ -1319,7 +1317,7 @@ dm9000_probe(struct platform_device *pdev) goto out; } - iosize = res_size(db->data_res); + iosize = resource_size(db->data_res); db->data_req = request_mem_region(db->data_res->start, iosize, pdev->name); -- cgit v1.2.3-18-g5258 From ec57935837a78f9661125b08a5d08b697568e040 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 9 Sep 2009 17:22:18 -0600 Subject: TPM: Fixup boot probe timeout for tpm_tis driver When probing the device in tpm_tis_init the call request_locality uses timeout_a, which wasn't being initalized until after request_locality. This results in request_locality falsely timing out if the chip is still starting. Move the initialization to before request_locality. This probably only matters for embedded cases (ie mine), a BIOS likely gets the TPM into a state where this code path isn't necessary. Signed-off-by: Jason Gunthorpe Acked-by: Rajiv Andrade Signed-off-by: James Morris --- drivers/char/tpm/tpm_tis.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index aec1931608a..0b73e4ec1ad 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -450,6 +450,12 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, goto out_err; } + /* Default timeouts */ + chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); + chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + if (request_locality(chip, 0) != 0) { rc = -ENODEV; goto out_err; @@ -457,12 +463,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0)); - /* Default timeouts */ - chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); - chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); - chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); - chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); - dev_info(dev, "1.2 TPM (device-id 0x%X, rev-id %d)\n", vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); -- cgit v1.2.3-18-g5258 From 05cc7390735c49357b9ae67bf97f1c1579547f5b Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Tue, 25 Aug 2009 13:59:03 -0700 Subject: [SCSI] fcoe: Add sysfs parameter to fcoe for minimum DDP read I/O size This adds fcoe_ddp_min as a module parameter for fcoe module to: /sys/module/fcoe/parameters/ddp_min It is observed that for some hardware, particularly Intel 82599, there is too much overhead in setting up context for direct data placement (DDP) read when the requested read I/O size is small. This is added as a module parameter for performance tuning and is set as 0 by default and user can change this based on their own hardware. Signed-off-by: Yi Zou Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index e32a0ed266a..a39d370bccf 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -49,6 +49,12 @@ MODULE_AUTHOR("Open-FCoE.org"); MODULE_DESCRIPTION("FCoE"); MODULE_LICENSE("GPL v2"); +/* Performance tuning parameters for fcoe */ +static unsigned int fcoe_ddp_min; +module_param_named(ddp_min, fcoe_ddp_min, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(ddp_min, "Minimum I/O size in bytes for " \ + "Direct Data Placement (DDP)."); + /* fcoe host list */ LIST_HEAD(fcoe_hostlist); DEFINE_RWLOCK(fcoe_hostlist_lock); @@ -414,7 +420,8 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost, */ bool fcoe_oem_match(struct fc_frame *fp) { - return fc_fcp_is_read(fr_fsp(fp)); + return fc_fcp_is_read(fr_fsp(fp)) && + (fr_fsp(fp)->data_len > fcoe_ddp_min); } /** -- cgit v1.2.3-18-g5258 From a4b7cfaee487caef913be978dce60896fe741268 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 25 Aug 2009 13:59:08 -0700 Subject: [SCSI] libfcoe: fcoe_ctlr_destroy use cancel_work_sync instead of flush_work Use cancel_work_sync() in place of flush_work(), so that fcoe_ctlr_destroy() can be called from a workqueue. Also, purge the receive queue after the recv_work has been cancled because if recv_work isn't run it's not guaranteed to be empty now. Signed-off-by: Chris Leech Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/libfcoe.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index d0b5208e1a4..62a4c202607 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -148,13 +148,17 @@ static void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip) */ void fcoe_ctlr_destroy(struct fcoe_ctlr *fip) { - flush_work(&fip->recv_work); + cancel_work_sync(&fip->recv_work); + spin_lock_bh(&fip->fip_recv_list.lock); + __skb_queue_purge(&fip->fip_recv_list); + spin_unlock_bh(&fip->fip_recv_list.lock); + spin_lock_bh(&fip->lock); fip->state = FIP_ST_DISABLED; fcoe_ctlr_reset_fcfs(fip); spin_unlock_bh(&fip->lock); del_timer_sync(&fip->timer); - flush_work(&fip->link_work); + cancel_work_sync(&fip->link_work); } EXPORT_SYMBOL(fcoe_ctlr_destroy); -- cgit v1.2.3-18-g5258 From 5892c32f8a2d5a37d4c2ff1df62f6e8a2664abdb Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 25 Aug 2009 13:59:14 -0700 Subject: [SCSI] fcoe: fix missing error check in call to fcoe_if_init fcoe_if_init() can fail, but it's return value wasn't checked Signed-off-by: Chris Leech Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index a39d370bccf..d205ac08d07 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1900,7 +1900,9 @@ static int __init fcoe_init(void) /* Setup link change notification */ fcoe_dev_setup(); - fcoe_if_init(); + rc = fcoe_if_init(); + if (rc) + goto out_free; return 0; -- cgit v1.2.3-18-g5258 From 36eb7fc872bdd7f7443ce24a718784bfa567f6c7 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 13:59:19 -0700 Subject: [SCSI] fcoe: remove unnecessary list and lock initializations. The hostlist and the hostlist_lock were initialized both in the delcaration and in fcoe_init(). Remove the unneeded code. Signed-off-by: Joe Eykholt Signed-off-by: Chris Leech Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index d205ac08d07..e481882a3e8 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1881,9 +1881,6 @@ static int __init fcoe_init(void) int rc = 0; struct fcoe_percpu_s *p; - INIT_LIST_HEAD(&fcoe_hostlist); - rwlock_init(&fcoe_hostlist_lock); - for_each_possible_cpu(cpu) { p = &per_cpu(fcoe_percpu, cpu); skb_queue_head_init(&p->fcoe_rx_list); -- cgit v1.2.3-18-g5258 From af7f85d95a34b04f5cf8c3b8c2d4cdd179dc1e19 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 25 Aug 2009 13:59:24 -0700 Subject: [SCSI] fcoe: interface changes to fcoe_if_create and fcoe_if_destroy By passing in the parent device instead of assuming the netdev is what should be used, fcoe_if_create becomes usable for NPIV vports as well. You still need a netdev, because that's how FCoE works. Also removed some duplicate checks from fcoe_if_create that are already in fcoe_create. fcoe_if_destroy needs to take an lport as it's only argument, not a netdev. That removes the 1:1 netdev:lport assumption from the destroy path. Signed-off-by: Chris Leech Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 113 ++++++++++++++++++++--------------------------- 1 file changed, 48 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index e481882a3e8..74927969813 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1,5 +1,5 @@ /* - * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -506,30 +506,20 @@ skip_oem: /** * fcoe_if_destroy() - FCoE software HBA tear-down function - * @netdev: ptr to the associated net_device - * - * Returns: 0 if link is OK for use by FCoE. + * @lport: fc_lport to destroy */ -static int fcoe_if_destroy(struct net_device *netdev) +static void fcoe_if_destroy(struct fc_lport *lport) { - struct fc_lport *lp = NULL; - struct fcoe_softc *fc; - - BUG_ON(!netdev); + struct fcoe_softc *fc = lport_priv(lport); + struct net_device *netdev = fc->netdev; FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); - lp = fcoe_hostlist_lookup(netdev); - if (!lp) - return -ENODEV; - - fc = lport_priv(lp); - /* Logout of the fabric */ - fc_fabric_logoff(lp); + fc_fabric_logoff(lport); /* Remove the instance from fcoe's list */ - fcoe_hostlist_remove(lp); + fcoe_hostlist_remove(lport); /* clean up netdev configurations */ fcoe_netdev_cleanup(fc); @@ -538,33 +528,31 @@ static int fcoe_if_destroy(struct net_device *netdev) fcoe_ctlr_destroy(&fc->ctlr); /* Free queued packets for the per-CPU receive threads */ - fcoe_percpu_clean(lp); + fcoe_percpu_clean(lport); /* Cleanup the fc_lport */ - fc_lport_destroy(lp); - fc_fcp_destroy(lp); + fc_lport_destroy(lport); + fc_fcp_destroy(lport); /* Detach from the scsi-ml */ - fc_remove_host(lp->host); - scsi_remove_host(lp->host); + fc_remove_host(lport->host); + scsi_remove_host(lport->host); /* There are no more rports or I/O, free the EM */ - fc_exch_mgr_free(lp); + fc_exch_mgr_free(lport); /* Free existing skbs */ - fcoe_clean_pending_queue(lp); + fcoe_clean_pending_queue(lport); /* Stop the timer */ del_timer_sync(&fc->timer); /* Free memory used by statistical counters */ - fc_lport_free_stats(lp); + fc_lport_free_stats(lport); /* Release the net_device and Scsi_Host */ dev_put(netdev); - scsi_host_put(lp->host); - - return 0; + scsi_host_put(lport->host); } /* @@ -612,38 +600,35 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = { /** * fcoe_if_create() - this function creates the fcoe interface * @netdev: pointer the associated netdevice + * @parent: device pointer to be the parent in sysfs for the SCSI host * * Creates fc_lport struct and scsi_host for lport, configures lport * and starts fabric login. * - * Returns : 0 on success + * Returns : The allocated fc_lport or an error pointer */ -static int fcoe_if_create(struct net_device *netdev) +static struct fc_lport *fcoe_if_create(struct net_device *netdev, + struct device *parent) { int rc; - struct fc_lport *lp = NULL; + struct fc_lport *lport = NULL; struct fcoe_softc *fc; struct Scsi_Host *shost; - BUG_ON(!netdev); - FCOE_NETDEV_DBG(netdev, "Create Interface\n"); - lp = fcoe_hostlist_lookup(netdev); - if (lp) - return -EEXIST; - shost = libfc_host_alloc(&fcoe_shost_template, sizeof(struct fcoe_softc)); if (!shost) { FCOE_NETDEV_DBG(netdev, "Could not allocate host structure\n"); - return -ENOMEM; + rc = -ENOMEM; + goto out; } - lp = shost_priv(shost); - fc = lport_priv(lp); + lport = shost_priv(shost); + fc = lport_priv(lport); /* configure fc_lport, e.g., em */ - rc = fcoe_lport_config(lp); + rc = fcoe_lport_config(lport); if (rc) { FCOE_NETDEV_DBG(netdev, "Could not configure lport for the " "interface\n"); @@ -658,7 +643,7 @@ static int fcoe_if_create(struct net_device *netdev) fc->ctlr.update_mac = fcoe_update_src_mac; /* configure lport network properties */ - rc = fcoe_netdev_config(lp, netdev); + rc = fcoe_netdev_config(lport, netdev); if (rc) { FCOE_NETDEV_DBG(netdev, "Could not configure netdev for the " "interface\n"); @@ -666,7 +651,7 @@ static int fcoe_if_create(struct net_device *netdev) } /* configure lport scsi host properties */ - rc = fcoe_shost_config(lp, shost, &netdev->dev); + rc = fcoe_shost_config(lport, shost, parent); if (rc) { FCOE_NETDEV_DBG(netdev, "Could not configure shost for the " "interface\n"); @@ -674,7 +659,7 @@ static int fcoe_if_create(struct net_device *netdev) } /* Initialize the library */ - rc = fcoe_libfc_config(lp, &fcoe_libfc_fcn_templ); + rc = fcoe_libfc_config(lport, &fcoe_libfc_fcn_templ); if (rc) { FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the " "interface\n"); @@ -689,7 +674,7 @@ static int fcoe_if_create(struct net_device *netdev) */ write_lock(&fcoe_hostlist_lock); /* lport exch manager allocation */ - rc = fcoe_em_config(lp); + rc = fcoe_em_config(lport); if (rc) { FCOE_NETDEV_DBG(netdev, "Could not configure the EM for the " "interface\n"); @@ -697,27 +682,28 @@ static int fcoe_if_create(struct net_device *netdev) } /* add to lports list */ - fcoe_hostlist_add(lp); + fcoe_hostlist_add(lport); write_unlock(&fcoe_hostlist_lock); - lp->boot_time = jiffies; + lport->boot_time = jiffies; - fc_fabric_login(lp); + fc_fabric_login(lport); - if (!fcoe_link_ok(lp)) + if (!fcoe_link_ok(lport)) fcoe_ctlr_link_up(&fc->ctlr); dev_hold(netdev); - return rc; + return lport; out_lp_destroy: - fc_exch_mgr_free(lp); + fc_exch_mgr_free(lport); out_netdev_cleanup: fcoe_netdev_cleanup(fc); out_host_put: - scsi_host_put(lp->host); - return rc; + scsi_host_put(lport->host); +out: + return ERR_PTR(rc); } /** @@ -1616,8 +1602,9 @@ static int fcoe_ethdrv_put(const struct net_device *netdev) */ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) { - int rc; struct net_device *netdev; + struct fc_lport *lport; + int rc; netdev = fcoe_if_to_netdev(buffer); if (!netdev) { @@ -1625,17 +1612,12 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) goto out_nodev; } /* look for existing lport */ - if (!fcoe_hostlist_lookup(netdev)) { + lport = fcoe_hostlist_lookup(netdev); + if (!lport) { rc = -ENODEV; goto out_putdev; } - rc = fcoe_if_destroy(netdev); - if (rc) { - printk(KERN_ERR "fcoe: Failed to destroy interface (%s)\n", - netdev->name); - rc = -EIO; - goto out_putdev; - } + fcoe_if_destroy(lport); fcoe_ethdrv_put(netdev); rc = 0; out_putdev: @@ -1654,6 +1636,7 @@ out_nodev: static int fcoe_create(const char *buffer, struct kernel_param *kp) { int rc; + struct fc_lport *lport; struct net_device *netdev; netdev = fcoe_if_to_netdev(buffer); @@ -1668,8 +1651,8 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) } fcoe_ethdrv_get(netdev); - rc = fcoe_if_create(netdev); - if (rc) { + lport = fcoe_if_create(netdev, &netdev->dev); + if (IS_ERR(lport)) { printk(KERN_ERR "fcoe: Failed to create interface (%s)\n", netdev->name); fcoe_ethdrv_put(netdev); @@ -1926,7 +1909,7 @@ static void __exit fcoe_exit(void) /* releases the associated fcoe hosts */ list_for_each_entry_safe(fc, tmp, &fcoe_hostlist, list) - fcoe_if_destroy(fc->netdev); + fcoe_if_destroy(fc->ctlr.lp); unregister_hotcpu_notifier(&fcoe_cpu_notifier); -- cgit v1.2.3-18-g5258 From 014f5c3f560a336cb8ad5b9f828c85de0398e7bb Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 25 Aug 2009 13:59:30 -0700 Subject: [SCSI] fcoe: Introduce and allocate fcoe_interface structure, 1:1 with net_device In preparation for NPIV support, I'm splitting the fcoe instance structure into two to remove the assumptions about it being 1:1 with the net_device. There will now be two structures, one which is 1:1 with the underlying net_device and one which is allocated per virtual SCSI/FC host. fcoe_softc is renamed to fcoe_port for the per Scsi_Host FCoE private data. Later patches with start moving shared stuff from fcoe_port to fcoe_interface Signed-off-by: Chris Leech Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 326 +++++++++++++++++++++++++---------------------- drivers/scsi/fcoe/fcoe.h | 19 ++- 2 files changed, 188 insertions(+), 157 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 74927969813..0ae54b2bce3 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -151,10 +151,10 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev) { - struct fcoe_softc *fc; + struct fcoe_port *port; - fc = container_of(ptype, struct fcoe_softc, fip_packet_type); - fcoe_ctlr_recv(&fc->ctlr, skb); + port = container_of(ptype, struct fcoe_port, fip_packet_type); + fcoe_ctlr_recv(&port->ctlr, skb); return 0; } @@ -180,13 +180,13 @@ static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) */ static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new) { - struct fcoe_softc *fc; + struct fcoe_port *port; - fc = fcoe_from_ctlr(fip); + port = fcoe_from_ctlr(fip); rtnl_lock(); if (!is_zero_ether_addr(old)) - dev_unicast_delete(fc->netdev, old); - dev_unicast_add(fc->netdev, new); + dev_unicast_delete(port->netdev, old); + dev_unicast_add(port->netdev, new); rtnl_unlock(); } @@ -224,25 +224,25 @@ static int fcoe_lport_config(struct fc_lport *lp) /** * fcoe_netdev_cleanup() - clean up netdev configurations - * @fc: ptr to the fcoe_softc + * @port: ptr to the fcoe_port */ -void fcoe_netdev_cleanup(struct fcoe_softc *fc) +void fcoe_netdev_cleanup(struct fcoe_port *port) { u8 flogi_maddr[ETH_ALEN]; /* Don't listen for Ethernet packets anymore */ - dev_remove_pack(&fc->fcoe_packet_type); - dev_remove_pack(&fc->fip_packet_type); + dev_remove_pack(&port->fcoe_packet_type); + dev_remove_pack(&port->fip_packet_type); /* Delete secondary MAC addresses */ rtnl_lock(); memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); - dev_unicast_delete(fc->netdev, flogi_maddr); - if (!is_zero_ether_addr(fc->ctlr.data_src_addr)) - dev_unicast_delete(fc->netdev, fc->ctlr.data_src_addr); - if (fc->ctlr.spma) - dev_unicast_delete(fc->netdev, fc->ctlr.ctl_src_addr); - dev_mc_delete(fc->netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); + dev_unicast_delete(port->netdev, flogi_maddr); + if (!is_zero_ether_addr(port->ctlr.data_src_addr)) + dev_unicast_delete(port->netdev, port->ctlr.data_src_addr); + if (port->ctlr.spma) + dev_unicast_delete(port->netdev, port->ctlr.ctl_src_addr); + dev_mc_delete(port->netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); rtnl_unlock(); } @@ -271,14 +271,14 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) { u32 mfs; u64 wwnn, wwpn; - struct fcoe_softc *fc; + struct fcoe_port *port; u8 flogi_maddr[ETH_ALEN]; struct netdev_hw_addr *ha; /* Setup lport private data to point to fcoe softc */ - fc = lport_priv(lp); - fc->ctlr.lp = lp; - fc->netdev = netdev; + port = lport_priv(lp); + port->ctlr.lp = lp; + port->netdev = netdev; /* Do not support for bonding device */ if ((netdev->priv_flags & IFF_MASTER_ALB) || @@ -317,27 +317,27 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) FCOE_NETDEV_DBG(netdev, "Supports LRO for max xid 0x%x\n", lp->lro_xid); } - skb_queue_head_init(&fc->fcoe_pending_queue); - fc->fcoe_pending_queue_active = 0; - setup_timer(&fc->timer, fcoe_queue_timer, (unsigned long)lp); + skb_queue_head_init(&port->fcoe_pending_queue); + port->fcoe_pending_queue_active = 0; + setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lp); /* look for SAN MAC address, if multiple SAN MACs exist, only * use the first one for SPMA */ rcu_read_lock(); for_each_dev_addr(netdev, ha) { if ((ha->type == NETDEV_HW_ADDR_T_SAN) && - (is_valid_ether_addr(ha->addr))) { - memcpy(fc->ctlr.ctl_src_addr, ha->addr, ETH_ALEN); - fc->ctlr.spma = 1; + (is_valid_ether_addr(port->ctlr.ctl_src_addr))) { + memcpy(port->ctlr.ctl_src_addr, ha->addr, ETH_ALEN); + port->ctlr.spma = 1; break; } } rcu_read_unlock(); /* setup Source Mac Address */ - if (!fc->ctlr.spma) - memcpy(fc->ctlr.ctl_src_addr, netdev->dev_addr, - fc->netdev->addr_len); + if (!port->ctlr.spma) + memcpy(port->ctlr.ctl_src_addr, netdev->dev_addr, + netdev->addr_len); wwnn = fcoe_wwn_from_mac(netdev->dev_addr, 1, 0); fc_set_wwnn(lp, wwnn); @@ -353,8 +353,8 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) rtnl_lock(); memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); dev_unicast_add(netdev, flogi_maddr); - if (fc->ctlr.spma) - dev_unicast_add(netdev, fc->ctlr.ctl_src_addr); + if (port->ctlr.spma) + dev_unicast_add(netdev, port->ctlr.ctl_src_addr); dev_mc_add(netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); rtnl_unlock(); @@ -362,15 +362,15 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) * setup the receive function from ethernet driver * on the ethertype for the given device */ - fc->fcoe_packet_type.func = fcoe_rcv; - fc->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); - fc->fcoe_packet_type.dev = netdev; - dev_add_pack(&fc->fcoe_packet_type); + port->fcoe_packet_type.func = fcoe_rcv; + port->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); + port->fcoe_packet_type.dev = netdev; + dev_add_pack(&port->fcoe_packet_type); - fc->fip_packet_type.func = fcoe_fip_recv; - fc->fip_packet_type.type = htons(ETH_P_FIP); - fc->fip_packet_type.dev = netdev; - dev_add_pack(&fc->fip_packet_type); + port->fip_packet_type.func = fcoe_fip_recv; + port->fip_packet_type.type = htons(ETH_P_FIP); + port->fip_packet_type.dev = netdev; + dev_add_pack(&port->fip_packet_type); return 0; } @@ -426,7 +426,7 @@ bool fcoe_oem_match(struct fc_frame *fp) /** * fcoe_em_config() - allocates em for this lport - * @lp: the port that em is to allocated for + * @lp: the fcoe that em is to allocated for * * Called with write fcoe_hostlist_lock held. * @@ -434,8 +434,9 @@ bool fcoe_oem_match(struct fc_frame *fp) */ static inline int fcoe_em_config(struct fc_lport *lp) { - struct fcoe_softc *fc = lport_priv(lp); - struct fcoe_softc *oldfc = NULL; + struct fcoe_interface *fcoe; + struct fcoe_port *port = lport_priv(lp); + struct fcoe_port *oldfc = NULL; struct net_device *old_real_dev, *cur_real_dev; u16 min_xid = FCOE_MIN_XID; u16 max_xid = FCOE_MAX_XID; @@ -453,38 +454,39 @@ static inline int fcoe_em_config(struct fc_lport *lp) * Reuse existing offload em instance in case * it is already allocated on real eth device */ - if (fc->netdev->priv_flags & IFF_802_1Q_VLAN) - cur_real_dev = vlan_dev_real_dev(fc->netdev); + if (port->netdev->priv_flags & IFF_802_1Q_VLAN) + cur_real_dev = vlan_dev_real_dev(port->netdev); else - cur_real_dev = fc->netdev; + cur_real_dev = port->netdev; - list_for_each_entry(oldfc, &fcoe_hostlist, list) { + list_for_each_entry(fcoe, &fcoe_hostlist, list) { + oldfc = fcoe->priv; if (oldfc->netdev->priv_flags & IFF_802_1Q_VLAN) old_real_dev = vlan_dev_real_dev(oldfc->netdev); else old_real_dev = oldfc->netdev; if (cur_real_dev == old_real_dev) { - fc->oem = oldfc->oem; + port->oem = oldfc->oem; break; } } - if (fc->oem) { - if (!fc_exch_mgr_add(lp, fc->oem, fcoe_oem_match)) { + if (port->oem) { + if (!fc_exch_mgr_add(lp, port->oem, fcoe_oem_match)) { printk(KERN_ERR "fcoe_em_config: failed to add " "offload em:%p on interface:%s\n", - fc->oem, fc->netdev->name); + port->oem, port->netdev->name); return -ENOMEM; } } else { - fc->oem = fc_exch_mgr_alloc(lp, FC_CLASS_3, + port->oem = fc_exch_mgr_alloc(lp, FC_CLASS_3, FCOE_MIN_XID, lp->lro_xid, fcoe_oem_match); - if (!fc->oem) { + if (!port->oem) { printk(KERN_ERR "fcoe_em_config: failed to allocate " "em for offload exches on interface:%s\n", - fc->netdev->name); + port->netdev->name); return -ENOMEM; } } @@ -497,7 +499,7 @@ static inline int fcoe_em_config(struct fc_lport *lp) skip_oem: if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, min_xid, max_xid, NULL)) { printk(KERN_ERR "fcoe_em_config: failed to " - "allocate em on interface %s\n", fc->netdev->name); + "allocate em on interface %s\n", port->netdev->name); return -ENOMEM; } @@ -510,8 +512,9 @@ skip_oem: */ static void fcoe_if_destroy(struct fc_lport *lport) { - struct fcoe_softc *fc = lport_priv(lport); - struct net_device *netdev = fc->netdev; + struct fcoe_port *port = lport_priv(lport); + struct fcoe_interface *fcoe = port->fcoe; + struct net_device *netdev = port->netdev; FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); @@ -522,10 +525,10 @@ static void fcoe_if_destroy(struct fc_lport *lport) fcoe_hostlist_remove(lport); /* clean up netdev configurations */ - fcoe_netdev_cleanup(fc); + fcoe_netdev_cleanup(port); /* tear-down the FCoE controller */ - fcoe_ctlr_destroy(&fc->ctlr); + fcoe_ctlr_destroy(&port->ctlr); /* Free queued packets for the per-CPU receive threads */ fcoe_percpu_clean(lport); @@ -545,7 +548,7 @@ static void fcoe_if_destroy(struct fc_lport *lport) fcoe_clean_pending_queue(lport); /* Stop the timer */ - del_timer_sync(&fc->timer); + del_timer_sync(&port->timer); /* Free memory used by statistical counters */ fc_lport_free_stats(lport); @@ -553,6 +556,7 @@ static void fcoe_if_destroy(struct fc_lport *lport) /* Release the net_device and Scsi_Host */ dev_put(netdev); scsi_host_put(lport->host); + kfree(fcoe); /* TODO, should be refcounted */ } /* @@ -612,20 +616,31 @@ static struct fc_lport *fcoe_if_create(struct net_device *netdev, { int rc; struct fc_lport *lport = NULL; - struct fcoe_softc *fc; + struct fcoe_port *port; + struct fcoe_interface *fcoe; struct Scsi_Host *shost; FCOE_NETDEV_DBG(netdev, "Create Interface\n"); + fcoe = kzalloc(sizeof(*fcoe), GFP_KERNEL); + if (!fcoe) { + FCOE_NETDEV_DBG(netdev, "Could not allocate fcoe structure\n"); + rc = -ENOMEM; + goto out; + } + shost = libfc_host_alloc(&fcoe_shost_template, - sizeof(struct fcoe_softc)); + sizeof(struct fcoe_port)); if (!shost) { FCOE_NETDEV_DBG(netdev, "Could not allocate host structure\n"); rc = -ENOMEM; - goto out; + goto out_kfree_port; } lport = shost_priv(shost); - fc = lport_priv(lport); + port = lport_priv(lport); + + port->fcoe = fcoe; + fcoe->priv = port; /* configure fc_lport, e.g., em */ rc = fcoe_lport_config(lport); @@ -638,9 +653,9 @@ static struct fc_lport *fcoe_if_create(struct net_device *netdev, /* * Initialize FIP. */ - fcoe_ctlr_init(&fc->ctlr); - fc->ctlr.send = fcoe_fip_send; - fc->ctlr.update_mac = fcoe_update_src_mac; + fcoe_ctlr_init(&port->ctlr); + port->ctlr.send = fcoe_fip_send; + port->ctlr.update_mac = fcoe_update_src_mac; /* configure lport network properties */ rc = fcoe_netdev_config(lport, netdev); @@ -690,7 +705,7 @@ static struct fc_lport *fcoe_if_create(struct net_device *netdev, fc_fabric_login(lport); if (!fcoe_link_ok(lport)) - fcoe_ctlr_link_up(&fc->ctlr); + fcoe_ctlr_link_up(&port->ctlr); dev_hold(netdev); @@ -699,9 +714,11 @@ static struct fc_lport *fcoe_if_create(struct net_device *netdev, out_lp_destroy: fc_exch_mgr_free(lport); out_netdev_cleanup: - fcoe_netdev_cleanup(fc); + fcoe_netdev_cleanup(port); out_host_put: scsi_host_put(lport->host); +out_kfree_port: + kfree(fcoe); out: return ERR_PTR(rc); } @@ -902,13 +919,13 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev, { struct fc_lport *lp; struct fcoe_rcv_info *fr; - struct fcoe_softc *fc; + struct fcoe_port *port; struct fc_frame_header *fh; struct fcoe_percpu_s *fps; unsigned int cpu; - fc = container_of(ptype, struct fcoe_softc, fcoe_packet_type); - lp = fc->ctlr.lp; + port = container_of(ptype, struct fcoe_port, fcoe_packet_type); + lp = port->ctlr.lp; if (unlikely(lp == NULL)) { FCOE_NETDEV_DBG(dev, "Cannot find hba structure"); goto err2; @@ -1059,7 +1076,7 @@ static int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen) * fcoe_fc_crc() - calculates FC CRC in this fcoe skb * @fp: the fc_frame containing data to be checksummed * - * This uses crc32() to calculate the crc for fc frame + * This uses crc32() to calculate the crc for port frame * Return : 32 bit crc */ u32 fcoe_fc_crc(struct fc_frame *fp) @@ -1092,7 +1109,7 @@ u32 fcoe_fc_crc(struct fc_frame *fp) /** * fcoe_xmit() - FCoE frame transmit function - * @lp: the associated local port + * @lp: the associated local fcoe * @fp: the fc_frame to be transmitted * * Return : 0 for success @@ -1109,13 +1126,13 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) unsigned int hlen; /* header length implies the version */ unsigned int tlen; /* trailer length */ unsigned int elen; /* eth header, may include vlan */ - struct fcoe_softc *fc; + struct fcoe_port *port; u8 sof, eof; struct fcoe_hdr *hp; WARN_ON((fr_len(fp) % sizeof(u32)) != 0); - fc = lport_priv(lp); + port = lport_priv(lp); fh = fc_frame_header_get(fp); skb = fp_skb(fp); wlen = skb->len / FCOE_WORD_TO_BYTE; @@ -1126,7 +1143,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) } if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ) && - fcoe_ctlr_els_send(&fc->ctlr, skb)) + fcoe_ctlr_els_send(&port->ctlr, skb)) return 0; sof = fr_sof(fp); @@ -1148,7 +1165,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) crc = fcoe_fc_crc(fp); } - /* copy fc crc and eof to the skb buff */ + /* copy port crc and eof to the skb buff */ if (skb_is_nonlinear(skb)) { skb_frag_t *frag; if (fcoe_get_paged_crc_eof(skb, tlen)) { @@ -1171,27 +1188,27 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) cp = NULL; } - /* adjust skb network/transport offsets to match mac/fcoe/fc */ + /* adjust skb network/transport offsets to match mac/fcoe/port */ skb_push(skb, elen + hlen); skb_reset_mac_header(skb); skb_reset_network_header(skb); skb->mac_len = elen; skb->protocol = htons(ETH_P_FCOE); - skb->dev = fc->netdev; + skb->dev = port->netdev; /* fill up mac and fcoe headers */ eh = eth_hdr(skb); eh->h_proto = htons(ETH_P_FCOE); - if (fc->ctlr.map_dest) + if (port->ctlr.map_dest) fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id); else /* insert GW address */ - memcpy(eh->h_dest, fc->ctlr.dest_addr, ETH_ALEN); + memcpy(eh->h_dest, port->ctlr.dest_addr, ETH_ALEN); - if (unlikely(fc->ctlr.flogi_oxid != FC_XID_UNKNOWN)) - memcpy(eh->h_source, fc->ctlr.ctl_src_addr, ETH_ALEN); + if (unlikely(port->ctlr.flogi_oxid != FC_XID_UNKNOWN)) + memcpy(eh->h_source, port->ctlr.ctl_src_addr, ETH_ALEN); else - memcpy(eh->h_source, fc->ctlr.data_src_addr, ETH_ALEN); + memcpy(eh->h_source, port->ctlr.data_src_addr, ETH_ALEN); hp = (struct fcoe_hdr *)(eh + 1); memset(hp, 0, sizeof(*hp)); @@ -1214,7 +1231,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) /* send down to lld */ fr_dev(fp) = lp; - if (fc->fcoe_pending_queue.qlen) + if (port->fcoe_pending_queue.qlen) fcoe_check_wait_queue(lp, skb); else if (fcoe_start_io(skb)) fcoe_check_wait_queue(lp, skb); @@ -1240,7 +1257,7 @@ int fcoe_percpu_receive_thread(void *arg) struct fcoe_crc_eof crc_eof; struct fc_frame *fp; u8 *mac = NULL; - struct fcoe_softc *fc; + struct fcoe_port *port; struct fcoe_hdr *hp; set_user_nice(current, -20); @@ -1276,7 +1293,7 @@ int fcoe_percpu_receive_thread(void *arg) /* * Save source MAC address before discarding header. */ - fc = lport_priv(lp); + port = lport_priv(lp); if (skb_is_nonlinear(skb)) skb_linearize(skb); /* not ideal */ mac = eth_hdr(skb)->h_source; @@ -1354,8 +1371,8 @@ int fcoe_percpu_receive_thread(void *arg) } fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; } - if (unlikely(fc->ctlr.flogi_oxid != FC_XID_UNKNOWN) && - fcoe_ctlr_recv_flogi(&fc->ctlr, fp, mac)) { + if (unlikely(port->ctlr.flogi_oxid != FC_XID_UNKNOWN) && + fcoe_ctlr_recv_flogi(&port->ctlr, fp, mac)) { fc_frame_free(fp); continue; } @@ -1379,46 +1396,46 @@ int fcoe_percpu_receive_thread(void *arg) */ static void fcoe_check_wait_queue(struct fc_lport *lp, struct sk_buff *skb) { - struct fcoe_softc *fc = lport_priv(lp); + struct fcoe_port *port = lport_priv(lp); int rc; - spin_lock_bh(&fc->fcoe_pending_queue.lock); + spin_lock_bh(&port->fcoe_pending_queue.lock); if (skb) - __skb_queue_tail(&fc->fcoe_pending_queue, skb); + __skb_queue_tail(&port->fcoe_pending_queue, skb); - if (fc->fcoe_pending_queue_active) + if (port->fcoe_pending_queue_active) goto out; - fc->fcoe_pending_queue_active = 1; + port->fcoe_pending_queue_active = 1; - while (fc->fcoe_pending_queue.qlen) { + while (port->fcoe_pending_queue.qlen) { /* keep qlen > 0 until fcoe_start_io succeeds */ - fc->fcoe_pending_queue.qlen++; - skb = __skb_dequeue(&fc->fcoe_pending_queue); + port->fcoe_pending_queue.qlen++; + skb = __skb_dequeue(&port->fcoe_pending_queue); - spin_unlock_bh(&fc->fcoe_pending_queue.lock); + spin_unlock_bh(&port->fcoe_pending_queue.lock); rc = fcoe_start_io(skb); - spin_lock_bh(&fc->fcoe_pending_queue.lock); + spin_lock_bh(&port->fcoe_pending_queue.lock); if (rc) { - __skb_queue_head(&fc->fcoe_pending_queue, skb); + __skb_queue_head(&port->fcoe_pending_queue, skb); /* undo temporary increment above */ - fc->fcoe_pending_queue.qlen--; + port->fcoe_pending_queue.qlen--; break; } /* undo temporary increment above */ - fc->fcoe_pending_queue.qlen--; + port->fcoe_pending_queue.qlen--; } - if (fc->fcoe_pending_queue.qlen < FCOE_LOW_QUEUE_DEPTH) + if (port->fcoe_pending_queue.qlen < FCOE_LOW_QUEUE_DEPTH) lp->qfull = 0; - if (fc->fcoe_pending_queue.qlen && !timer_pending(&fc->timer)) - mod_timer(&fc->timer, jiffies + 2); - fc->fcoe_pending_queue_active = 0; + if (port->fcoe_pending_queue.qlen && !timer_pending(&port->timer)) + mod_timer(&port->timer, jiffies + 2); + port->fcoe_pending_queue_active = 0; out: - if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) + if (port->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) lp->qfull = 1; - spin_unlock_bh(&fc->fcoe_pending_queue.lock); + spin_unlock_bh(&port->fcoe_pending_queue.lock); return; } @@ -1453,16 +1470,18 @@ static int fcoe_device_notification(struct notifier_block *notifier, { struct fc_lport *lp = NULL; struct net_device *netdev = ptr; - struct fcoe_softc *fc; + struct fcoe_interface *fcoe; + struct fcoe_port *port = NULL; struct fcoe_dev_stats *stats; u32 link_possible = 1; u32 mfs; int rc = NOTIFY_OK; read_lock(&fcoe_hostlist_lock); - list_for_each_entry(fc, &fcoe_hostlist, list) { - if (fc->netdev == netdev) { - lp = fc->ctlr.lp; + list_for_each_entry(fcoe, &fcoe_hostlist, list) { + port = fcoe->priv; + if (port->netdev == netdev) { + lp = port->ctlr.lp; break; } } @@ -1493,8 +1512,8 @@ static int fcoe_device_notification(struct notifier_block *notifier, "from netdev netlink\n", event); } if (link_possible && !fcoe_link_ok(lp)) - fcoe_ctlr_link_up(&fc->ctlr); - else if (fcoe_ctlr_link_down(&fc->ctlr)) { + fcoe_ctlr_link_up(&port->ctlr); + else if (fcoe_ctlr_link_down(&port->ctlr)) { stats = fc_lport_get_stats(lp); stats->LinkFailureCount++; fcoe_clean_pending_queue(lp); @@ -1668,10 +1687,10 @@ out_nodev: module_param_call(create, fcoe_create, NULL, NULL, S_IWUSR); __MODULE_PARM_TYPE(create, "string"); -MODULE_PARM_DESC(create, "Create fcoe port using net device passed in."); +MODULE_PARM_DESC(create, "Create fcoe fcoe using net device passed in."); module_param_call(destroy, fcoe_destroy, NULL, NULL, S_IWUSR); __MODULE_PARM_TYPE(destroy, "string"); -MODULE_PARM_DESC(destroy, "Destroy fcoe port"); +MODULE_PARM_DESC(destroy, "Destroy fcoe fcoe"); /** * fcoe_link_ok() - Check if link is ok for the fc_lport @@ -1689,8 +1708,8 @@ MODULE_PARM_DESC(destroy, "Destroy fcoe port"); */ int fcoe_link_ok(struct fc_lport *lp) { - struct fcoe_softc *fc = lport_priv(lp); - struct net_device *dev = fc->netdev; + struct fcoe_port *port = lport_priv(lp); + struct net_device *dev = port->netdev; struct ethtool_cmd ecmd = { ETHTOOL_GSET }; if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) && @@ -1752,16 +1771,16 @@ void fcoe_percpu_clean(struct fc_lport *lp) */ void fcoe_clean_pending_queue(struct fc_lport *lp) { - struct fcoe_softc *fc = lport_priv(lp); + struct fcoe_port *port = lport_priv(lp); struct sk_buff *skb; - spin_lock_bh(&fc->fcoe_pending_queue.lock); - while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) { - spin_unlock_bh(&fc->fcoe_pending_queue.lock); + spin_lock_bh(&port->fcoe_pending_queue.lock); + while ((skb = __skb_dequeue(&port->fcoe_pending_queue)) != NULL) { + spin_unlock_bh(&port->fcoe_pending_queue.lock); kfree_skb(skb); - spin_lock_bh(&fc->fcoe_pending_queue.lock); + spin_lock_bh(&port->fcoe_pending_queue.lock); } - spin_unlock_bh(&fc->fcoe_pending_queue.lock); + spin_unlock_bh(&port->fcoe_pending_queue.lock); } /** @@ -1778,21 +1797,21 @@ int fcoe_reset(struct Scsi_Host *shost) } /** - * fcoe_hostlist_lookup_softc() - find the corresponding lport by a given device + * fcoe_hostlist_lookup_port() - find the corresponding lport by a given device * @dev: this is currently ptr to net_device * * Called with fcoe_hostlist_lock held. * - * Returns: NULL or the located fcoe_softc + * Returns: NULL or the located fcoe_port */ -static struct fcoe_softc * -fcoe_hostlist_lookup_softc(const struct net_device *dev) +static struct fcoe_interface * +fcoe_hostlist_lookup_port(const struct net_device *dev) { - struct fcoe_softc *fc; + struct fcoe_interface *fcoe; - list_for_each_entry(fc, &fcoe_hostlist, list) { - if (fc->netdev == dev) - return fc; + list_for_each_entry(fcoe, &fcoe_hostlist, list) { + if (fcoe->priv->netdev == dev) + return fcoe; } return NULL; } @@ -1805,13 +1824,13 @@ fcoe_hostlist_lookup_softc(const struct net_device *dev) */ struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) { - struct fcoe_softc *fc; + struct fcoe_interface *fcoe; read_lock(&fcoe_hostlist_lock); - fc = fcoe_hostlist_lookup_softc(netdev); + fcoe = fcoe_hostlist_lookup_port(netdev); read_unlock(&fcoe_hostlist_lock); - return (fc) ? fc->ctlr.lp : NULL; + return (fcoe) ? fcoe->priv->ctlr.lp : NULL; } /** @@ -1822,14 +1841,16 @@ struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) * * Returns: 0 for success */ -int fcoe_hostlist_add(const struct fc_lport *lp) +int fcoe_hostlist_add(const struct fc_lport *lport) { - struct fcoe_softc *fc; - - fc = fcoe_hostlist_lookup_softc(fcoe_netdev(lp)); - if (!fc) { - fc = lport_priv(lp); - list_add_tail(&fc->list, &fcoe_hostlist); + struct fcoe_interface *fcoe; + struct fcoe_port *port; + + fcoe = fcoe_hostlist_lookup_port(fcoe_netdev(lport)); + if (!fcoe) { + port = lport_priv(lport); + fcoe = port->fcoe; + list_add_tail(&fcoe->list, &fcoe_hostlist); } return 0; } @@ -1840,14 +1861,14 @@ int fcoe_hostlist_add(const struct fc_lport *lp) * * Returns: 0 for success */ -int fcoe_hostlist_remove(const struct fc_lport *lp) +int fcoe_hostlist_remove(const struct fc_lport *lport) { - struct fcoe_softc *fc; + struct fcoe_interface *fcoe; write_lock_bh(&fcoe_hostlist_lock); - fc = fcoe_hostlist_lookup_softc(fcoe_netdev(lp)); - BUG_ON(!fc); - list_del(&fc->list); + fcoe = fcoe_hostlist_lookup_port(fcoe_netdev(lport)); + BUG_ON(!fcoe); + list_del(&fcoe->list); write_unlock_bh(&fcoe_hostlist_lock); return 0; @@ -1903,19 +1924,18 @@ module_init(fcoe_init); static void __exit fcoe_exit(void) { unsigned int cpu; - struct fcoe_softc *fc, *tmp; + struct fcoe_interface *fcoe, *tmp; fcoe_dev_cleanup(); /* releases the associated fcoe hosts */ - list_for_each_entry_safe(fc, tmp, &fcoe_hostlist, list) - fcoe_if_destroy(fc->ctlr.lp); + list_for_each_entry_safe(fcoe, tmp, &fcoe_hostlist, list) + fcoe_if_destroy(fcoe->priv->ctlr.lp); unregister_hotcpu_notifier(&fcoe_cpu_notifier); - for_each_online_cpu(cpu) { + for_each_online_cpu(cpu) fcoe_percpu_thread_destroy(cpu); - } /* detach from scsi transport */ fcoe_if_exit(); diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index 550d1e49d1a..060a6dce658 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h @@ -75,10 +75,21 @@ struct fcoe_percpu_s { }; /* - * the fcoe sw transport private data + * an FCoE interface, 1:1 with netdev */ -struct fcoe_softc { +struct fcoe_interface { struct list_head list; + /* This will be removed once all the shared values are + * moved out of fcoe_port */ + struct fcoe_port *priv; +}; + +/* + * the FCoE private structure that's allocated along with the + * Scsi_Host and libfc fc_lport structures + */ +struct fcoe_port { + struct fcoe_interface *fcoe; struct net_device *netdev; struct fc_exch_mgr *oem; /* offload exchange manger */ struct packet_type fcoe_packet_type; @@ -89,12 +100,12 @@ struct fcoe_softc { struct fcoe_ctlr ctlr; }; -#define fcoe_from_ctlr(fc) container_of(fc, struct fcoe_softc, ctlr) +#define fcoe_from_ctlr(port) container_of(port, struct fcoe_port, ctlr) static inline struct net_device *fcoe_netdev( const struct fc_lport *lp) { - return ((struct fcoe_softc *)lport_priv(lp))->netdev; + return ((struct fcoe_port *)lport_priv(lp))->netdev; } #endif /* _FCOE_H_ */ -- cgit v1.2.3-18-g5258 From 250249898a92a1228050f40fbe3c05deb1392da8 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 25 Aug 2009 13:59:35 -0700 Subject: [SCSI] fcoe: move netdev to fcoe_interface The network interface needs to be shared between all NPIV VN_Ports, therefor it should be tracked in the fcoe_interface and not for each SCSI host in fcoe_port. Signed-off-by: Chris Leech Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 61 +++++++++++++++++++++++++++--------------------- drivers/scsi/fcoe/fcoe.h | 9 ++++--- 2 files changed, 38 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 0ae54b2bce3..44c963c8bc7 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -165,7 +165,7 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev, */ static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) { - skb->dev = fcoe_from_ctlr(fip)->netdev; + skb->dev = fcoe_from_ctlr(fip)->fcoe->netdev; dev_queue_xmit(skb); } @@ -180,13 +180,16 @@ static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) */ static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new) { + struct fcoe_interface *fcoe; struct fcoe_port *port; port = fcoe_from_ctlr(fip); + fcoe = port->fcoe; + rtnl_lock(); if (!is_zero_ether_addr(old)) - dev_unicast_delete(port->netdev, old); - dev_unicast_add(port->netdev, new); + dev_unicast_delete(fcoe->netdev, old); + dev_unicast_add(fcoe->netdev, new); rtnl_unlock(); } @@ -229,6 +232,7 @@ static int fcoe_lport_config(struct fc_lport *lp) void fcoe_netdev_cleanup(struct fcoe_port *port) { u8 flogi_maddr[ETH_ALEN]; + struct fcoe_interface *fcoe = port->fcoe; /* Don't listen for Ethernet packets anymore */ dev_remove_pack(&port->fcoe_packet_type); @@ -237,12 +241,12 @@ void fcoe_netdev_cleanup(struct fcoe_port *port) /* Delete secondary MAC addresses */ rtnl_lock(); memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); - dev_unicast_delete(port->netdev, flogi_maddr); + dev_unicast_delete(fcoe->netdev, flogi_maddr); if (!is_zero_ether_addr(port->ctlr.data_src_addr)) - dev_unicast_delete(port->netdev, port->ctlr.data_src_addr); + dev_unicast_delete(fcoe->netdev, port->ctlr.data_src_addr); if (port->ctlr.spma) - dev_unicast_delete(port->netdev, port->ctlr.ctl_src_addr); - dev_mc_delete(port->netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); + dev_unicast_delete(fcoe->netdev, port->ctlr.ctl_src_addr); + dev_mc_delete(fcoe->netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); rtnl_unlock(); } @@ -271,14 +275,16 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) { u32 mfs; u64 wwnn, wwpn; + struct fcoe_interface *fcoe; struct fcoe_port *port; u8 flogi_maddr[ETH_ALEN]; struct netdev_hw_addr *ha; /* Setup lport private data to point to fcoe softc */ port = lport_priv(lp); + fcoe = port->fcoe; port->ctlr.lp = lp; - port->netdev = netdev; + fcoe->netdev = netdev; /* Do not support for bonding device */ if ((netdev->priv_flags & IFF_MASTER_ALB) || @@ -434,9 +440,10 @@ bool fcoe_oem_match(struct fc_frame *fp) */ static inline int fcoe_em_config(struct fc_lport *lp) { - struct fcoe_interface *fcoe; struct fcoe_port *port = lport_priv(lp); - struct fcoe_port *oldfc = NULL; + struct fcoe_port *oldport = NULL; + struct fcoe_interface *fcoe = port->fcoe; + struct fcoe_interface *oldfcoe = NULL; struct net_device *old_real_dev, *cur_real_dev; u16 min_xid = FCOE_MIN_XID; u16 max_xid = FCOE_MAX_XID; @@ -454,20 +461,20 @@ static inline int fcoe_em_config(struct fc_lport *lp) * Reuse existing offload em instance in case * it is already allocated on real eth device */ - if (port->netdev->priv_flags & IFF_802_1Q_VLAN) - cur_real_dev = vlan_dev_real_dev(port->netdev); + if (fcoe->netdev->priv_flags & IFF_802_1Q_VLAN) + cur_real_dev = vlan_dev_real_dev(fcoe->netdev); else - cur_real_dev = port->netdev; + cur_real_dev = fcoe->netdev; - list_for_each_entry(fcoe, &fcoe_hostlist, list) { - oldfc = fcoe->priv; - if (oldfc->netdev->priv_flags & IFF_802_1Q_VLAN) - old_real_dev = vlan_dev_real_dev(oldfc->netdev); + list_for_each_entry(oldfcoe, &fcoe_hostlist, list) { + oldport = oldfcoe->priv; + if (oldfcoe->netdev->priv_flags & IFF_802_1Q_VLAN) + old_real_dev = vlan_dev_real_dev(oldfcoe->netdev); else - old_real_dev = oldfc->netdev; + old_real_dev = oldfcoe->netdev; if (cur_real_dev == old_real_dev) { - port->oem = oldfc->oem; + port->oem = oldport->oem; break; } } @@ -476,7 +483,7 @@ static inline int fcoe_em_config(struct fc_lport *lp) if (!fc_exch_mgr_add(lp, port->oem, fcoe_oem_match)) { printk(KERN_ERR "fcoe_em_config: failed to add " "offload em:%p on interface:%s\n", - port->oem, port->netdev->name); + port->oem, fcoe->netdev->name); return -ENOMEM; } } else { @@ -486,7 +493,7 @@ static inline int fcoe_em_config(struct fc_lport *lp) if (!port->oem) { printk(KERN_ERR "fcoe_em_config: failed to allocate " "em for offload exches on interface:%s\n", - port->netdev->name); + fcoe->netdev->name); return -ENOMEM; } } @@ -499,7 +506,7 @@ static inline int fcoe_em_config(struct fc_lport *lp) skip_oem: if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, min_xid, max_xid, NULL)) { printk(KERN_ERR "fcoe_em_config: failed to " - "allocate em on interface %s\n", port->netdev->name); + "allocate em on interface %s\n", fcoe->netdev->name); return -ENOMEM; } @@ -514,7 +521,7 @@ static void fcoe_if_destroy(struct fc_lport *lport) { struct fcoe_port *port = lport_priv(lport); struct fcoe_interface *fcoe = port->fcoe; - struct net_device *netdev = port->netdev; + struct net_device *netdev = fcoe->netdev; FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); @@ -1194,7 +1201,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) skb_reset_network_header(skb); skb->mac_len = elen; skb->protocol = htons(ETH_P_FCOE); - skb->dev = port->netdev; + skb->dev = port->fcoe->netdev; /* fill up mac and fcoe headers */ eh = eth_hdr(skb); @@ -1480,7 +1487,7 @@ static int fcoe_device_notification(struct notifier_block *notifier, read_lock(&fcoe_hostlist_lock); list_for_each_entry(fcoe, &fcoe_hostlist, list) { port = fcoe->priv; - if (port->netdev == netdev) { + if (fcoe->netdev == netdev) { lp = port->ctlr.lp; break; } @@ -1709,7 +1716,7 @@ MODULE_PARM_DESC(destroy, "Destroy fcoe fcoe"); int fcoe_link_ok(struct fc_lport *lp) { struct fcoe_port *port = lport_priv(lp); - struct net_device *dev = port->netdev; + struct net_device *dev = port->fcoe->netdev; struct ethtool_cmd ecmd = { ETHTOOL_GSET }; if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) && @@ -1810,7 +1817,7 @@ fcoe_hostlist_lookup_port(const struct net_device *dev) struct fcoe_interface *fcoe; list_for_each_entry(fcoe, &fcoe_hostlist, list) { - if (fcoe->priv->netdev == dev) + if (fcoe->netdev == dev) return fcoe; } return NULL; diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index 060a6dce658..3b3886e99b4 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h @@ -82,6 +82,7 @@ struct fcoe_interface { /* This will be removed once all the shared values are * moved out of fcoe_port */ struct fcoe_port *priv; + struct net_device *netdev; }; /* @@ -90,7 +91,6 @@ struct fcoe_interface { */ struct fcoe_port { struct fcoe_interface *fcoe; - struct net_device *netdev; struct fc_exch_mgr *oem; /* offload exchange manger */ struct packet_type fcoe_packet_type; struct packet_type fip_packet_type; @@ -100,12 +100,11 @@ struct fcoe_port { struct fcoe_ctlr ctlr; }; -#define fcoe_from_ctlr(port) container_of(port, struct fcoe_port, ctlr) +#define fcoe_from_ctlr(fip) container_of(fip, struct fcoe_port, ctlr) -static inline struct net_device *fcoe_netdev( - const struct fc_lport *lp) +static inline struct net_device *fcoe_netdev(const struct fc_lport *lp) { - return ((struct fcoe_port *)lport_priv(lp))->netdev; + return ((struct fcoe_port *)lport_priv(lp))->fcoe->netdev; } #endif /* _FCOE_H_ */ -- cgit v1.2.3-18-g5258 From 259ad85d8dbbcd508e3dad29a36e3e76365853b7 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 25 Aug 2009 13:59:41 -0700 Subject: [SCSI] fcoe: move packet handlers from fcoe_port to fcoe_interface The packet handlers need to be tracked in fcoe_interface so there is only one set per net_device. When NPIV is enabled there will be multiple SCSI hosts and multiple fcoe_port structures on a single net_device. The packet handlers match by ethertype and netdev. If the same handler gets registered on a single netdev multiple times, the receive function will be called multiple times for each frame. Signed-off-by: Chris Leech Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 28 ++++++++++++++++------------ drivers/scsi/fcoe/fcoe.h | 4 ++-- 2 files changed, 18 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 44c963c8bc7..c215235ee39 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -151,9 +151,11 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev) { + struct fcoe_interface *fcoe; struct fcoe_port *port; - port = container_of(ptype, struct fcoe_port, fip_packet_type); + fcoe = container_of(ptype, struct fcoe_interface, fip_packet_type); + port = fcoe->priv; fcoe_ctlr_recv(&port->ctlr, skb); return 0; } @@ -235,8 +237,8 @@ void fcoe_netdev_cleanup(struct fcoe_port *port) struct fcoe_interface *fcoe = port->fcoe; /* Don't listen for Ethernet packets anymore */ - dev_remove_pack(&port->fcoe_packet_type); - dev_remove_pack(&port->fip_packet_type); + dev_remove_pack(&fcoe->fcoe_packet_type); + dev_remove_pack(&fcoe->fip_packet_type); /* Delete secondary MAC addresses */ rtnl_lock(); @@ -368,15 +370,15 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) * setup the receive function from ethernet driver * on the ethertype for the given device */ - port->fcoe_packet_type.func = fcoe_rcv; - port->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); - port->fcoe_packet_type.dev = netdev; - dev_add_pack(&port->fcoe_packet_type); + fcoe->fcoe_packet_type.func = fcoe_rcv; + fcoe->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); + fcoe->fcoe_packet_type.dev = netdev; + dev_add_pack(&fcoe->fcoe_packet_type); - port->fip_packet_type.func = fcoe_fip_recv; - port->fip_packet_type.type = htons(ETH_P_FIP); - port->fip_packet_type.dev = netdev; - dev_add_pack(&port->fip_packet_type); + fcoe->fip_packet_type.func = fcoe_fip_recv; + fcoe->fip_packet_type.type = htons(ETH_P_FIP); + fcoe->fip_packet_type.dev = netdev; + dev_add_pack(&fcoe->fip_packet_type); return 0; } @@ -926,12 +928,14 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev, { struct fc_lport *lp; struct fcoe_rcv_info *fr; + struct fcoe_interface *fcoe; struct fcoe_port *port; struct fc_frame_header *fh; struct fcoe_percpu_s *fps; unsigned int cpu; - port = container_of(ptype, struct fcoe_port, fcoe_packet_type); + fcoe = container_of(ptype, struct fcoe_interface, fcoe_packet_type); + port = fcoe->priv; lp = port->ctlr.lp; if (unlikely(lp == NULL)) { FCOE_NETDEV_DBG(dev, "Cannot find hba structure"); diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index 3b3886e99b4..685aa9d0222 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h @@ -83,6 +83,8 @@ struct fcoe_interface { * moved out of fcoe_port */ struct fcoe_port *priv; struct net_device *netdev; + struct packet_type fcoe_packet_type; + struct packet_type fip_packet_type; }; /* @@ -92,8 +94,6 @@ struct fcoe_interface { struct fcoe_port { struct fcoe_interface *fcoe; struct fc_exch_mgr *oem; /* offload exchange manger */ - struct packet_type fcoe_packet_type; - struct packet_type fip_packet_type; struct sk_buff_head fcoe_pending_queue; u8 fcoe_pending_queue_active; struct timer_list timer; /* queue timer */ -- cgit v1.2.3-18-g5258 From 3fe9a0badae7fa2eb35eff4f07e851fbd25e3d4f Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 25 Aug 2009 13:59:46 -0700 Subject: [SCSI] fcoe: move FIP controller from fcoe_port to fcoe_interface There is only one FIP state per net_device, so the FIP controller needs to be moved from the per-SCSI-host fcoe_port to the per-net_device fcoe_interface structure. Signed-off-by: Chris Leech Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 83 +++++++++++++++++++++--------------------------- drivers/scsi/fcoe/fcoe.h | 4 +-- 2 files changed, 39 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index c215235ee39..01519c722ed 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -152,11 +152,9 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev, struct net_device *orig_dev) { struct fcoe_interface *fcoe; - struct fcoe_port *port; fcoe = container_of(ptype, struct fcoe_interface, fip_packet_type); - port = fcoe->priv; - fcoe_ctlr_recv(&port->ctlr, skb); + fcoe_ctlr_recv(&fcoe->ctlr, skb); return 0; } @@ -167,7 +165,7 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev, */ static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) { - skb->dev = fcoe_from_ctlr(fip)->fcoe->netdev; + skb->dev = fcoe_from_ctlr(fip)->netdev; dev_queue_xmit(skb); } @@ -183,11 +181,8 @@ static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new) { struct fcoe_interface *fcoe; - struct fcoe_port *port; - - port = fcoe_from_ctlr(fip); - fcoe = port->fcoe; + fcoe = fcoe_from_ctlr(fip); rtnl_lock(); if (!is_zero_ether_addr(old)) dev_unicast_delete(fcoe->netdev, old); @@ -244,10 +239,10 @@ void fcoe_netdev_cleanup(struct fcoe_port *port) rtnl_lock(); memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); dev_unicast_delete(fcoe->netdev, flogi_maddr); - if (!is_zero_ether_addr(port->ctlr.data_src_addr)) - dev_unicast_delete(fcoe->netdev, port->ctlr.data_src_addr); - if (port->ctlr.spma) - dev_unicast_delete(fcoe->netdev, port->ctlr.ctl_src_addr); + if (!is_zero_ether_addr(fcoe->ctlr.data_src_addr)) + dev_unicast_delete(fcoe->netdev, fcoe->ctlr.data_src_addr); + if (fcoe->ctlr.spma) + dev_unicast_delete(fcoe->netdev, fcoe->ctlr.ctl_src_addr); dev_mc_delete(fcoe->netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); rtnl_unlock(); } @@ -285,7 +280,7 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) /* Setup lport private data to point to fcoe softc */ port = lport_priv(lp); fcoe = port->fcoe; - port->ctlr.lp = lp; + fcoe->ctlr.lp = lp; fcoe->netdev = netdev; /* Do not support for bonding device */ @@ -334,17 +329,17 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) rcu_read_lock(); for_each_dev_addr(netdev, ha) { if ((ha->type == NETDEV_HW_ADDR_T_SAN) && - (is_valid_ether_addr(port->ctlr.ctl_src_addr))) { - memcpy(port->ctlr.ctl_src_addr, ha->addr, ETH_ALEN); - port->ctlr.spma = 1; + (is_valid_ether_addr(fcoe->ctlr.ctl_src_addr))) { + memcpy(fcoe->ctlr.ctl_src_addr, ha->addr, ETH_ALEN); + fcoe->ctlr.spma = 1; break; } } rcu_read_unlock(); /* setup Source Mac Address */ - if (!port->ctlr.spma) - memcpy(port->ctlr.ctl_src_addr, netdev->dev_addr, + if (!fcoe->ctlr.spma) + memcpy(fcoe->ctlr.ctl_src_addr, netdev->dev_addr, netdev->addr_len); wwnn = fcoe_wwn_from_mac(netdev->dev_addr, 1, 0); @@ -361,8 +356,8 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) rtnl_lock(); memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); dev_unicast_add(netdev, flogi_maddr); - if (port->ctlr.spma) - dev_unicast_add(netdev, port->ctlr.ctl_src_addr); + if (fcoe->ctlr.spma) + dev_unicast_add(netdev, fcoe->ctlr.ctl_src_addr); dev_mc_add(netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); rtnl_unlock(); @@ -537,7 +532,7 @@ static void fcoe_if_destroy(struct fc_lport *lport) fcoe_netdev_cleanup(port); /* tear-down the FCoE controller */ - fcoe_ctlr_destroy(&port->ctlr); + fcoe_ctlr_destroy(&fcoe->ctlr); /* Free queued packets for the per-CPU receive threads */ fcoe_percpu_clean(lport); @@ -662,9 +657,9 @@ static struct fc_lport *fcoe_if_create(struct net_device *netdev, /* * Initialize FIP. */ - fcoe_ctlr_init(&port->ctlr); - port->ctlr.send = fcoe_fip_send; - port->ctlr.update_mac = fcoe_update_src_mac; + fcoe_ctlr_init(&fcoe->ctlr); + fcoe->ctlr.send = fcoe_fip_send; + fcoe->ctlr.update_mac = fcoe_update_src_mac; /* configure lport network properties */ rc = fcoe_netdev_config(lport, netdev); @@ -714,7 +709,7 @@ static struct fc_lport *fcoe_if_create(struct net_device *netdev, fc_fabric_login(lport); if (!fcoe_link_ok(lport)) - fcoe_ctlr_link_up(&port->ctlr); + fcoe_ctlr_link_up(&fcoe->ctlr); dev_hold(netdev); @@ -929,14 +924,12 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev, struct fc_lport *lp; struct fcoe_rcv_info *fr; struct fcoe_interface *fcoe; - struct fcoe_port *port; struct fc_frame_header *fh; struct fcoe_percpu_s *fps; unsigned int cpu; fcoe = container_of(ptype, struct fcoe_interface, fcoe_packet_type); - port = fcoe->priv; - lp = port->ctlr.lp; + lp = fcoe->ctlr.lp; if (unlikely(lp == NULL)) { FCOE_NETDEV_DBG(dev, "Cannot find hba structure"); goto err2; @@ -1137,13 +1130,13 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) unsigned int hlen; /* header length implies the version */ unsigned int tlen; /* trailer length */ unsigned int elen; /* eth header, may include vlan */ - struct fcoe_port *port; + struct fcoe_port *port = lport_priv(lp); + struct fcoe_interface *fcoe = port->fcoe; u8 sof, eof; struct fcoe_hdr *hp; WARN_ON((fr_len(fp) % sizeof(u32)) != 0); - port = lport_priv(lp); fh = fc_frame_header_get(fp); skb = fp_skb(fp); wlen = skb->len / FCOE_WORD_TO_BYTE; @@ -1154,7 +1147,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) } if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ) && - fcoe_ctlr_els_send(&port->ctlr, skb)) + fcoe_ctlr_els_send(&fcoe->ctlr, skb)) return 0; sof = fr_sof(fp); @@ -1205,21 +1198,21 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) skb_reset_network_header(skb); skb->mac_len = elen; skb->protocol = htons(ETH_P_FCOE); - skb->dev = port->fcoe->netdev; + skb->dev = fcoe->netdev; /* fill up mac and fcoe headers */ eh = eth_hdr(skb); eh->h_proto = htons(ETH_P_FCOE); - if (port->ctlr.map_dest) + if (fcoe->ctlr.map_dest) fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id); else /* insert GW address */ - memcpy(eh->h_dest, port->ctlr.dest_addr, ETH_ALEN); + memcpy(eh->h_dest, fcoe->ctlr.dest_addr, ETH_ALEN); - if (unlikely(port->ctlr.flogi_oxid != FC_XID_UNKNOWN)) - memcpy(eh->h_source, port->ctlr.ctl_src_addr, ETH_ALEN); + if (unlikely(fcoe->ctlr.flogi_oxid != FC_XID_UNKNOWN)) + memcpy(eh->h_source, fcoe->ctlr.ctl_src_addr, ETH_ALEN); else - memcpy(eh->h_source, port->ctlr.data_src_addr, ETH_ALEN); + memcpy(eh->h_source, fcoe->ctlr.data_src_addr, ETH_ALEN); hp = (struct fcoe_hdr *)(eh + 1); memset(hp, 0, sizeof(*hp)); @@ -1382,8 +1375,8 @@ int fcoe_percpu_receive_thread(void *arg) } fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; } - if (unlikely(port->ctlr.flogi_oxid != FC_XID_UNKNOWN) && - fcoe_ctlr_recv_flogi(&port->ctlr, fp, mac)) { + if (unlikely(port->fcoe->ctlr.flogi_oxid != FC_XID_UNKNOWN) && + fcoe_ctlr_recv_flogi(&port->fcoe->ctlr, fp, mac)) { fc_frame_free(fp); continue; } @@ -1482,7 +1475,6 @@ static int fcoe_device_notification(struct notifier_block *notifier, struct fc_lport *lp = NULL; struct net_device *netdev = ptr; struct fcoe_interface *fcoe; - struct fcoe_port *port = NULL; struct fcoe_dev_stats *stats; u32 link_possible = 1; u32 mfs; @@ -1490,9 +1482,8 @@ static int fcoe_device_notification(struct notifier_block *notifier, read_lock(&fcoe_hostlist_lock); list_for_each_entry(fcoe, &fcoe_hostlist, list) { - port = fcoe->priv; if (fcoe->netdev == netdev) { - lp = port->ctlr.lp; + lp = fcoe->ctlr.lp; break; } } @@ -1523,8 +1514,8 @@ static int fcoe_device_notification(struct notifier_block *notifier, "from netdev netlink\n", event); } if (link_possible && !fcoe_link_ok(lp)) - fcoe_ctlr_link_up(&port->ctlr); - else if (fcoe_ctlr_link_down(&port->ctlr)) { + fcoe_ctlr_link_up(&fcoe->ctlr); + else if (fcoe_ctlr_link_down(&fcoe->ctlr)) { stats = fc_lport_get_stats(lp); stats->LinkFailureCount++; fcoe_clean_pending_queue(lp); @@ -1841,7 +1832,7 @@ struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) fcoe = fcoe_hostlist_lookup_port(netdev); read_unlock(&fcoe_hostlist_lock); - return (fcoe) ? fcoe->priv->ctlr.lp : NULL; + return (fcoe) ? fcoe->ctlr.lp : NULL; } /** @@ -1941,7 +1932,7 @@ static void __exit fcoe_exit(void) /* releases the associated fcoe hosts */ list_for_each_entry_safe(fcoe, tmp, &fcoe_hostlist, list) - fcoe_if_destroy(fcoe->priv->ctlr.lp); + fcoe_if_destroy(fcoe->ctlr.lp); unregister_hotcpu_notifier(&fcoe_cpu_notifier); diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index 685aa9d0222..5b190b5fea3 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h @@ -85,6 +85,7 @@ struct fcoe_interface { struct net_device *netdev; struct packet_type fcoe_packet_type; struct packet_type fip_packet_type; + struct fcoe_ctlr ctlr; }; /* @@ -97,10 +98,9 @@ struct fcoe_port { struct sk_buff_head fcoe_pending_queue; u8 fcoe_pending_queue_active; struct timer_list timer; /* queue timer */ - struct fcoe_ctlr ctlr; }; -#define fcoe_from_ctlr(fip) container_of(fip, struct fcoe_port, ctlr) +#define fcoe_from_ctlr(fip) container_of(fip, struct fcoe_interface, ctlr) static inline struct net_device *fcoe_netdev(const struct fc_lport *lp) { -- cgit v1.2.3-18-g5258 From 991cbb6082db3025bd82908eb9ee2d2920be2114 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 25 Aug 2009 13:59:51 -0700 Subject: [SCSI] fcoe: move offload exchange manager pointer from fcoe_port to fcoe_interface The offload EM pointer is only used when setting up a new libfc instance, but as it's designed to be shared among NPIV VN_Ports it should be tracked in fcoe_interface. With the host-list changed to track fcoe_interfaces as well, this is needed before we can remove the priv pointer from that structure (which is only there to help in the transition, and stops making sense once NPIV is enabled). Signed-off-by: Chris Leech Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 14 ++++++-------- drivers/scsi/fcoe/fcoe.h | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 01519c722ed..bb59a7a04f2 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -438,7 +438,6 @@ bool fcoe_oem_match(struct fc_frame *fp) static inline int fcoe_em_config(struct fc_lport *lp) { struct fcoe_port *port = lport_priv(lp); - struct fcoe_port *oldport = NULL; struct fcoe_interface *fcoe = port->fcoe; struct fcoe_interface *oldfcoe = NULL; struct net_device *old_real_dev, *cur_real_dev; @@ -464,30 +463,29 @@ static inline int fcoe_em_config(struct fc_lport *lp) cur_real_dev = fcoe->netdev; list_for_each_entry(oldfcoe, &fcoe_hostlist, list) { - oldport = oldfcoe->priv; if (oldfcoe->netdev->priv_flags & IFF_802_1Q_VLAN) old_real_dev = vlan_dev_real_dev(oldfcoe->netdev); else old_real_dev = oldfcoe->netdev; if (cur_real_dev == old_real_dev) { - port->oem = oldport->oem; + fcoe->oem = oldfcoe->oem; break; } } - if (port->oem) { - if (!fc_exch_mgr_add(lp, port->oem, fcoe_oem_match)) { + if (fcoe->oem) { + if (!fc_exch_mgr_add(lp, fcoe->oem, fcoe_oem_match)) { printk(KERN_ERR "fcoe_em_config: failed to add " "offload em:%p on interface:%s\n", - port->oem, fcoe->netdev->name); + fcoe->oem, fcoe->netdev->name); return -ENOMEM; } } else { - port->oem = fc_exch_mgr_alloc(lp, FC_CLASS_3, + fcoe->oem = fc_exch_mgr_alloc(lp, FC_CLASS_3, FCOE_MIN_XID, lp->lro_xid, fcoe_oem_match); - if (!port->oem) { + if (!fcoe->oem) { printk(KERN_ERR "fcoe_em_config: failed to allocate " "em for offload exches on interface:%s\n", fcoe->netdev->name); diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index 5b190b5fea3..26e85957460 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h @@ -86,6 +86,7 @@ struct fcoe_interface { struct packet_type fcoe_packet_type; struct packet_type fip_packet_type; struct fcoe_ctlr ctlr; + struct fc_exch_mgr *oem; /* offload exchange manager */ }; /* @@ -94,7 +95,6 @@ struct fcoe_interface { */ struct fcoe_port { struct fcoe_interface *fcoe; - struct fc_exch_mgr *oem; /* offload exchange manger */ struct sk_buff_head fcoe_pending_queue; u8 fcoe_pending_queue_active; struct timer_list timer; /* queue timer */ -- cgit v1.2.3-18-g5258 From cb0a6ca81439a9f113d3b46de0953da168a06f6a Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 25 Aug 2009 13:59:56 -0700 Subject: [SCSI] fcoe: remove fcoe_interface->priv pointer The priv pointer is no longer needed, and once NPIV is enabled fcoe_interface:fc_lport becomes a one-to-many relationship. Remove the single pointer. Signed-off-by: Chris Leech Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 2 -- drivers/scsi/fcoe/fcoe.h | 3 --- 2 files changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index bb59a7a04f2..7f14c633da6 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -640,9 +640,7 @@ static struct fc_lport *fcoe_if_create(struct net_device *netdev, } lport = shost_priv(shost); port = lport_priv(lport); - port->fcoe = fcoe; - fcoe->priv = port; /* configure fc_lport, e.g., em */ rc = fcoe_lport_config(lport); diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index 26e85957460..673e70e1f8b 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h @@ -79,9 +79,6 @@ struct fcoe_percpu_s { */ struct fcoe_interface { struct list_head list; - /* This will be removed once all the shared values are - * moved out of fcoe_port */ - struct fcoe_port *priv; struct net_device *netdev; struct packet_type fcoe_packet_type; struct packet_type fip_packet_type; -- cgit v1.2.3-18-g5258 From 030f4e001f13e0ee80bac1e756013341b1674d10 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 25 Aug 2009 14:00:02 -0700 Subject: [SCSI] fcoe: fcoe_interface create, destroy and refcounting Up to this point the fcoe_instance structure was simply kzalloc/kfreed. This patch introduces create and destroy functions as well as kref based reference counting. The create function will grow as the initialization code is moved there. Signed-off-by: Chris Leech Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 97 ++++++++++++++++++++++++++++++++++++++---------- drivers/scsi/fcoe/fcoe.h | 1 + 2 files changed, 79 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 7f14c633da6..d1d6b3b8bf5 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -138,6 +138,58 @@ static struct scsi_host_template fcoe_shost_template = { .max_sectors = 0xffff, }; +/** + * fcoe_interface_create() + * @netdev: network interface + * + * Returns: pointer to a struct fcoe_interface or NULL on error + */ +static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev) +{ + struct fcoe_interface *fcoe; + + fcoe = kzalloc(sizeof(*fcoe), GFP_KERNEL); + if (!fcoe) { + FCOE_NETDEV_DBG(netdev, "Could not allocate fcoe structure\n"); + return NULL; + } + + kref_init(&fcoe->kref); + fcoe->netdev = netdev; + + return fcoe; +} + +/** + * fcoe_interface_release() - fcoe_port kref release function + * @kref: embedded reference count in an fcoe_interface struct + */ +static void fcoe_interface_release(struct kref *kref) +{ + struct fcoe_interface *fcoe; + + fcoe = container_of(kref, struct fcoe_interface, kref); + kfree(fcoe); +} + +/** + * fcoe_interface_get() + * @fcoe: + */ +static inline void fcoe_interface_get(struct fcoe_interface *fcoe) +{ + kref_get(&fcoe->kref); +} + +/** + * fcoe_interface_put() + * @fcoe: + */ +static inline void fcoe_interface_put(struct fcoe_interface *fcoe) +{ + kref_put(&fcoe->kref, fcoe_interface_release); +} + /** * fcoe_fip_recv - handle a received FIP frame. * @skb: the receive skb @@ -558,7 +610,7 @@ static void fcoe_if_destroy(struct fc_lport *lport) /* Release the net_device and Scsi_Host */ dev_put(netdev); scsi_host_put(lport->host); - kfree(fcoe); /* TODO, should be refcounted */ + fcoe_interface_put(fcoe); } /* @@ -604,8 +656,8 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = { }; /** - * fcoe_if_create() - this function creates the fcoe interface - * @netdev: pointer the associated netdevice + * fcoe_if_create() - this function creates the fcoe port + * @fcoe: fcoe_interface structure to create an fc_lport instance on * @parent: device pointer to be the parent in sysfs for the SCSI host * * Creates fc_lport struct and scsi_host for lport, configures lport @@ -613,30 +665,23 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = { * * Returns : The allocated fc_lport or an error pointer */ -static struct fc_lport *fcoe_if_create(struct net_device *netdev, +static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, struct device *parent) { int rc; struct fc_lport *lport = NULL; struct fcoe_port *port; - struct fcoe_interface *fcoe; struct Scsi_Host *shost; + struct net_device *netdev = fcoe->netdev; FCOE_NETDEV_DBG(netdev, "Create Interface\n"); - fcoe = kzalloc(sizeof(*fcoe), GFP_KERNEL); - if (!fcoe) { - FCOE_NETDEV_DBG(netdev, "Could not allocate fcoe structure\n"); - rc = -ENOMEM; - goto out; - } - shost = libfc_host_alloc(&fcoe_shost_template, sizeof(struct fcoe_port)); if (!shost) { FCOE_NETDEV_DBG(netdev, "Could not allocate host structure\n"); rc = -ENOMEM; - goto out_kfree_port; + goto out; } lport = shost_priv(shost); port = lport_priv(lport); @@ -708,7 +753,7 @@ static struct fc_lport *fcoe_if_create(struct net_device *netdev, fcoe_ctlr_link_up(&fcoe->ctlr); dev_hold(netdev); - + fcoe_interface_get(fcoe); return lport; out_lp_destroy: @@ -717,8 +762,6 @@ out_netdev_cleanup: fcoe_netdev_cleanup(port); out_host_put: scsi_host_put(lport->host); -out_kfree_port: - kfree(fcoe); out: return ERR_PTR(rc); } @@ -1620,6 +1663,8 @@ static int fcoe_ethdrv_put(const struct net_device *netdev) static int fcoe_destroy(const char *buffer, struct kernel_param *kp) { struct net_device *netdev; + struct fcoe_interface *fcoe; + struct fcoe_port *port; struct fc_lport *lport; int rc; @@ -1634,6 +1679,8 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) rc = -ENODEV; goto out_putdev; } + port = lport_priv(lport); + fcoe = port->fcoe; fcoe_if_destroy(lport); fcoe_ethdrv_put(netdev); rc = 0; @@ -1653,6 +1700,7 @@ out_nodev: static int fcoe_create(const char *buffer, struct kernel_param *kp) { int rc; + struct fcoe_interface *fcoe; struct fc_lport *lport; struct net_device *netdev; @@ -1668,15 +1716,26 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) } fcoe_ethdrv_get(netdev); - lport = fcoe_if_create(netdev, &netdev->dev); + fcoe = fcoe_interface_create(netdev); + if (!fcoe) { + rc = -ENOMEM; + goto out_putdev; + } + + lport = fcoe_if_create(fcoe, &netdev->dev); if (IS_ERR(lport)) { printk(KERN_ERR "fcoe: Failed to create interface (%s)\n", netdev->name); fcoe_ethdrv_put(netdev); rc = -EIO; - goto out_putdev; + goto out_free; } - rc = 0; + + dev_put(netdev); + return 0; + +out_free: + fcoe_interface_put(fcoe); out_putdev: dev_put(netdev); out_nodev: diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index 673e70e1f8b..ff229288b7f 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h @@ -84,6 +84,7 @@ struct fcoe_interface { struct packet_type fip_packet_type; struct fcoe_ctlr ctlr; struct fc_exch_mgr *oem; /* offload exchange manager */ + struct kref kref; }; /* -- cgit v1.2.3-18-g5258 From 54b649f88eb17a29687bece4b8ad7d72d99e2d95 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 25 Aug 2009 14:00:07 -0700 Subject: [SCSI] fcoe: split out per interface setup fcoe_netdev_config() is called during initialization of a libfc instance. Much of what was there only needs to be done once for each net_device. The same goes for the corresponding cleanup. The FIP controller initialization is moved to interface creation time. Otherwise it will keep getting re-initialized for every VN_Port once NPIV is enabled. fcoe_if_destroy() has some reordering to deal with the changes. Receives are not stopped until after fcoe_interface_put() is called, but transmits must be stopped before. So there is some care to stop libfc transmits and the transmit backlog timer, then call fcoe_interface_put which will stop receives and cleanup the FIP controller, then the receive queues can be cleaned and the port freed. Signed-off-by: Chris Leech Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 267 ++++++++++++++++++++++++++--------------------- 1 file changed, 148 insertions(+), 119 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index d1d6b3b8bf5..63aeeca384b 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -138,6 +138,82 @@ static struct scsi_host_template fcoe_shost_template = { .max_sectors = 0xffff, }; +static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *ptype, + struct net_device *orig_dev); +/** + * fcoe_interface_setup() + * @fcoe: new fcoe_interface + * @netdev : ptr to the associated netdevice struct + * + * Returns : 0 for success + */ +static int fcoe_interface_setup(struct fcoe_interface *fcoe, + struct net_device *netdev) +{ + struct fcoe_ctlr *fip = &fcoe->ctlr; + struct netdev_hw_addr *ha; + u8 flogi_maddr[ETH_ALEN]; + + fcoe->netdev = netdev; + + /* Do not support for bonding device */ + if ((netdev->priv_flags & IFF_MASTER_ALB) || + (netdev->priv_flags & IFF_SLAVE_INACTIVE) || + (netdev->priv_flags & IFF_MASTER_8023AD)) { + return -EOPNOTSUPP; + } + + /* look for SAN MAC address, if multiple SAN MACs exist, only + * use the first one for SPMA */ + rcu_read_lock(); + for_each_dev_addr(netdev, ha) { + if ((ha->type == NETDEV_HW_ADDR_T_SAN) && + (is_valid_ether_addr(fip->ctl_src_addr))) { + memcpy(fip->ctl_src_addr, ha->addr, ETH_ALEN); + fip->spma = 1; + break; + } + } + rcu_read_unlock(); + + /* setup Source Mac Address */ + if (!fip->spma) + memcpy(fip->ctl_src_addr, netdev->dev_addr, netdev->addr_len); + + /* + * Add FCoE MAC address as second unicast MAC address + * or enter promiscuous mode if not capable of listening + * for multiple unicast MACs. + */ + rtnl_lock(); + memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); + dev_unicast_add(netdev, flogi_maddr); + if (fip->spma) + dev_unicast_add(netdev, fip->ctl_src_addr); + dev_mc_add(netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); + rtnl_unlock(); + + /* + * setup the receive function from ethernet driver + * on the ethertype for the given device + */ + fcoe->fcoe_packet_type.func = fcoe_rcv; + fcoe->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); + fcoe->fcoe_packet_type.dev = netdev; + dev_add_pack(&fcoe->fcoe_packet_type); + + fcoe->fip_packet_type.func = fcoe_fip_recv; + fcoe->fip_packet_type.type = htons(ETH_P_FIP); + fcoe->fip_packet_type.dev = netdev; + dev_add_pack(&fcoe->fip_packet_type); + + return 0; +} + +static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb); +static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new); + /** * fcoe_interface_create() * @netdev: network interface @@ -155,11 +231,54 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev) } kref_init(&fcoe->kref); - fcoe->netdev = netdev; + + /* + * Initialize FIP. + */ + fcoe_ctlr_init(&fcoe->ctlr); + fcoe->ctlr.send = fcoe_fip_send; + fcoe->ctlr.update_mac = fcoe_update_src_mac; + + fcoe_interface_setup(fcoe, netdev); return fcoe; } +/** + * fcoe_interface_cleanup() - clean up netdev configurations + * @fcoe: + */ +void fcoe_interface_cleanup(struct fcoe_interface *fcoe) +{ + struct net_device *netdev = fcoe->netdev; + struct fcoe_ctlr *fip = &fcoe->ctlr; + u8 flogi_maddr[ETH_ALEN]; + + /* + * Don't listen for Ethernet packets anymore. + * synchronize_net() ensures that the packet handlers are not running + * on another CPU. dev_remove_pack() would do that, this calls the + * unsyncronized version __dev_remove_pack() to avoid multiple delays. + */ + __dev_remove_pack(&fcoe->fcoe_packet_type); + __dev_remove_pack(&fcoe->fip_packet_type); + synchronize_net(); + + /* tear-down the FCoE controller */ + fcoe_ctlr_destroy(&fcoe->ctlr); + + /* Delete secondary MAC addresses */ + rtnl_lock(); + memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); + dev_unicast_delete(netdev, flogi_maddr); + if (!is_zero_ether_addr(fip->data_src_addr)) + dev_unicast_delete(netdev, fip->data_src_addr); + if (fip->spma) + dev_unicast_delete(netdev, fip->ctl_src_addr); + dev_mc_delete(netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); + rtnl_unlock(); +} + /** * fcoe_interface_release() - fcoe_port kref release function * @kref: embedded reference count in an fcoe_interface struct @@ -169,6 +288,7 @@ static void fcoe_interface_release(struct kref *kref) struct fcoe_interface *fcoe; fcoe = container_of(kref, struct fcoe_interface, kref); + fcoe_interface_cleanup(fcoe); kfree(fcoe); } @@ -274,31 +394,6 @@ static int fcoe_lport_config(struct fc_lport *lp) return 0; } -/** - * fcoe_netdev_cleanup() - clean up netdev configurations - * @port: ptr to the fcoe_port - */ -void fcoe_netdev_cleanup(struct fcoe_port *port) -{ - u8 flogi_maddr[ETH_ALEN]; - struct fcoe_interface *fcoe = port->fcoe; - - /* Don't listen for Ethernet packets anymore */ - dev_remove_pack(&fcoe->fcoe_packet_type); - dev_remove_pack(&fcoe->fip_packet_type); - - /* Delete secondary MAC addresses */ - rtnl_lock(); - memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); - dev_unicast_delete(fcoe->netdev, flogi_maddr); - if (!is_zero_ether_addr(fcoe->ctlr.data_src_addr)) - dev_unicast_delete(fcoe->netdev, fcoe->ctlr.data_src_addr); - if (fcoe->ctlr.spma) - dev_unicast_delete(fcoe->netdev, fcoe->ctlr.ctl_src_addr); - dev_mc_delete(fcoe->netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); - rtnl_unlock(); -} - /** * fcoe_queue_timer() - fcoe queue timer * @lp: the fc_lport pointer @@ -326,21 +421,10 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) u64 wwnn, wwpn; struct fcoe_interface *fcoe; struct fcoe_port *port; - u8 flogi_maddr[ETH_ALEN]; - struct netdev_hw_addr *ha; /* Setup lport private data to point to fcoe softc */ port = lport_priv(lp); fcoe = port->fcoe; - fcoe->ctlr.lp = lp; - fcoe->netdev = netdev; - - /* Do not support for bonding device */ - if ((netdev->priv_flags & IFF_MASTER_ALB) || - (netdev->priv_flags & IFF_SLAVE_INACTIVE) || - (netdev->priv_flags & IFF_MASTER_8023AD)) { - return -EOPNOTSUPP; - } /* * Determine max frame size based on underlying device and optional @@ -376,57 +460,12 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) port->fcoe_pending_queue_active = 0; setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lp); - /* look for SAN MAC address, if multiple SAN MACs exist, only - * use the first one for SPMA */ - rcu_read_lock(); - for_each_dev_addr(netdev, ha) { - if ((ha->type == NETDEV_HW_ADDR_T_SAN) && - (is_valid_ether_addr(fcoe->ctlr.ctl_src_addr))) { - memcpy(fcoe->ctlr.ctl_src_addr, ha->addr, ETH_ALEN); - fcoe->ctlr.spma = 1; - break; - } - } - rcu_read_unlock(); - - /* setup Source Mac Address */ - if (!fcoe->ctlr.spma) - memcpy(fcoe->ctlr.ctl_src_addr, netdev->dev_addr, - netdev->addr_len); - wwnn = fcoe_wwn_from_mac(netdev->dev_addr, 1, 0); fc_set_wwnn(lp, wwnn); /* XXX - 3rd arg needs to be vlan id */ wwpn = fcoe_wwn_from_mac(netdev->dev_addr, 2, 0); fc_set_wwpn(lp, wwpn); - /* - * Add FCoE MAC address as second unicast MAC address - * or enter promiscuous mode if not capable of listening - * for multiple unicast MACs. - */ - rtnl_lock(); - memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); - dev_unicast_add(netdev, flogi_maddr); - if (fcoe->ctlr.spma) - dev_unicast_add(netdev, fcoe->ctlr.ctl_src_addr); - dev_mc_add(netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); - rtnl_unlock(); - - /* - * setup the receive function from ethernet driver - * on the ethertype for the given device - */ - fcoe->fcoe_packet_type.func = fcoe_rcv; - fcoe->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); - fcoe->fcoe_packet_type.dev = netdev; - dev_add_pack(&fcoe->fcoe_packet_type); - - fcoe->fip_packet_type.func = fcoe_fip_recv; - fcoe->fip_packet_type.type = htons(ETH_P_FIP); - fcoe->fip_packet_type.dev = netdev; - dev_add_pack(&fcoe->fip_packet_type); - return 0; } @@ -578,19 +617,22 @@ static void fcoe_if_destroy(struct fc_lport *lport) /* Remove the instance from fcoe's list */ fcoe_hostlist_remove(lport); - /* clean up netdev configurations */ - fcoe_netdev_cleanup(port); + /* Cleanup the fc_lport */ + fc_lport_destroy(lport); + fc_fcp_destroy(lport); + + /* Stop the transmit retry timer */ + del_timer_sync(&port->timer); - /* tear-down the FCoE controller */ - fcoe_ctlr_destroy(&fcoe->ctlr); + /* Free existing transmit skbs */ + fcoe_clean_pending_queue(lport); + + /* receives may not be stopped until after this */ + fcoe_interface_put(fcoe); /* Free queued packets for the per-CPU receive threads */ fcoe_percpu_clean(lport); - /* Cleanup the fc_lport */ - fc_lport_destroy(lport); - fc_fcp_destroy(lport); - /* Detach from the scsi-ml */ fc_remove_host(lport->host); scsi_remove_host(lport->host); @@ -598,19 +640,12 @@ static void fcoe_if_destroy(struct fc_lport *lport) /* There are no more rports or I/O, free the EM */ fc_exch_mgr_free(lport); - /* Free existing skbs */ - fcoe_clean_pending_queue(lport); - - /* Stop the timer */ - del_timer_sync(&port->timer); - /* Free memory used by statistical counters */ fc_lport_free_stats(lport); /* Release the net_device and Scsi_Host */ dev_put(netdev); scsi_host_put(lport->host); - fcoe_interface_put(fcoe); } /* @@ -660,8 +695,7 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = { * @fcoe: fcoe_interface structure to create an fc_lport instance on * @parent: device pointer to be the parent in sysfs for the SCSI host * - * Creates fc_lport struct and scsi_host for lport, configures lport - * and starts fabric login. + * Creates fc_lport struct and scsi_host for lport, configures lport. * * Returns : The allocated fc_lport or an error pointer */ @@ -695,19 +729,12 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, goto out_host_put; } - /* - * Initialize FIP. - */ - fcoe_ctlr_init(&fcoe->ctlr); - fcoe->ctlr.send = fcoe_fip_send; - fcoe->ctlr.update_mac = fcoe_update_src_mac; - /* configure lport network properties */ rc = fcoe_netdev_config(lport, netdev); if (rc) { FCOE_NETDEV_DBG(netdev, "Could not configure netdev for the " "interface\n"); - goto out_netdev_cleanup; + goto out_lp_destroy; } /* configure lport scsi host properties */ @@ -715,7 +742,7 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, if (rc) { FCOE_NETDEV_DBG(netdev, "Could not configure shost for the " "interface\n"); - goto out_netdev_cleanup; + goto out_lp_destroy; } /* Initialize the library */ @@ -745,21 +772,12 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, fcoe_hostlist_add(lport); write_unlock(&fcoe_hostlist_lock); - lport->boot_time = jiffies; - - fc_fabric_login(lport); - - if (!fcoe_link_ok(lport)) - fcoe_ctlr_link_up(&fcoe->ctlr); - dev_hold(netdev); fcoe_interface_get(fcoe); return lport; out_lp_destroy: fc_exch_mgr_free(lport); -out_netdev_cleanup: - fcoe_netdev_cleanup(port); out_host_put: scsi_host_put(lport->host); out: @@ -1731,10 +1749,21 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) goto out_free; } - dev_put(netdev); - return 0; + /* Make this the "master" N_Port */ + fcoe->ctlr.lp = lport; + + /* start FIP Discovery and FLOGI */ + lport->boot_time = jiffies; + fc_fabric_login(lport); + if (!fcoe_link_ok(lport)) + fcoe_ctlr_link_up(&fcoe->ctlr); + rc = 0; out_free: + /* + * Release from init in fcoe_interface_create(), on success lport + * should be holding a reference taken in fcoe_if_create(). + */ fcoe_interface_put(fcoe); out_putdev: dev_put(netdev); -- cgit v1.2.3-18-g5258 From dfc1d0fe3a8b2139295600ab519f24059493e6f6 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 25 Aug 2009 14:00:13 -0700 Subject: [SCSI] fcoe: add mutex to protect create and destroy Rather than rely on the hostlist_lock to be held while creating exchange managers, serialize fcoe instance creation and destruction with a mutex. This will allow the hostlist addition to be moved out of fcoe_if_create(), which will simplify NPIV support. Signed-off-by: Chris Leech Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 63aeeca384b..43added0a17 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -55,6 +55,8 @@ module_param_named(ddp_min, fcoe_ddp_min, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ddp_min, "Minimum I/O size in bytes for " \ "Direct Data Placement (DDP)."); +DEFINE_MUTEX(fcoe_config_mutex); + /* fcoe host list */ LIST_HEAD(fcoe_hostlist); DEFINE_RWLOCK(fcoe_hostlist_lock); @@ -811,6 +813,7 @@ static int __init fcoe_if_init(void) int __exit fcoe_if_exit(void) { fc_release_transport(scsi_transport_fcoe_sw); + scsi_transport_fcoe_sw = NULL; return 0; } @@ -1686,6 +1689,19 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) struct fc_lport *lport; int rc; + mutex_lock(&fcoe_config_mutex); +#ifdef CONFIG_FCOE_MODULE + /* + * Make sure the module has been initialized, and is not about to be + * removed. Module paramter sysfs files are writable before the + * module_init function is called and after module_exit. + */ + if (THIS_MODULE->state != MODULE_STATE_LIVE) { + rc = -ENODEV; + goto out_nodev; + } +#endif + netdev = fcoe_if_to_netdev(buffer); if (!netdev) { rc = -ENODEV; @@ -1705,6 +1721,7 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) out_putdev: dev_put(netdev); out_nodev: + mutex_unlock(&fcoe_config_mutex); return rc; } @@ -1722,6 +1739,19 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) struct fc_lport *lport; struct net_device *netdev; + mutex_lock(&fcoe_config_mutex); +#ifdef CONFIG_FCOE_MODULE + /* + * Make sure the module has been initialized, and is not about to be + * removed. Module paramter sysfs files are writable before the + * module_init function is called and after module_exit. + */ + if (THIS_MODULE->state != MODULE_STATE_LIVE) { + rc = -ENODEV; + goto out_nodev; + } +#endif + netdev = fcoe_if_to_netdev(buffer); if (!netdev) { rc = -ENODEV; @@ -1768,6 +1798,7 @@ out_free: out_putdev: dev_put(netdev); out_nodev: + mutex_unlock(&fcoe_config_mutex); return rc; } @@ -1971,6 +2002,8 @@ static int __init fcoe_init(void) int rc = 0; struct fcoe_percpu_s *p; + mutex_lock(&fcoe_config_mutex); + for_each_possible_cpu(cpu) { p = &per_cpu(fcoe_percpu, cpu); skb_queue_head_init(&p->fcoe_rx_list); @@ -1991,13 +2024,14 @@ static int __init fcoe_init(void) if (rc) goto out_free; + mutex_unlock(&fcoe_config_mutex); return 0; out_free: for_each_online_cpu(cpu) { fcoe_percpu_thread_destroy(cpu); } - + mutex_unlock(&fcoe_config_mutex); return rc; } module_init(fcoe_init); @@ -2012,6 +2046,8 @@ static void __exit fcoe_exit(void) unsigned int cpu; struct fcoe_interface *fcoe, *tmp; + mutex_lock(&fcoe_config_mutex); + fcoe_dev_cleanup(); /* releases the associated fcoe hosts */ @@ -2025,5 +2061,7 @@ static void __exit fcoe_exit(void) /* detach from scsi transport */ fcoe_if_exit(); + + mutex_unlock(&fcoe_config_mutex); } module_exit(fcoe_exit); -- cgit v1.2.3-18-g5258 From c863df33bb784eecfb24090d2258fa0d3f653750 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 25 Aug 2009 14:00:18 -0700 Subject: [SCSI] fcoe: move the host-list add/remove to keep out VN_Ports We only want the FCoE create and destroy routines to deal with top level N_Ports, the VN_Ports are tracked on the vport list (see scsi_transport_fc). Signed-off-by: Chris Leech Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 43added0a17..c9a0346e493 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -616,9 +616,6 @@ static void fcoe_if_destroy(struct fc_lport *lport) /* Logout of the fabric */ fc_fabric_logoff(lport); - /* Remove the instance from fcoe's list */ - fcoe_hostlist_remove(lport); - /* Cleanup the fc_lport */ fc_lport_destroy(lport); fc_fcp_destroy(lport); @@ -757,11 +754,13 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, /* * fcoe_em_alloc() and fcoe_hostlist_add() both - * need to be atomic under fcoe_hostlist_lock + * need to be atomic with respect to other changes to the hostlist * since fcoe_em_alloc() looks for an existing EM * instance on host list updated by fcoe_hostlist_add(). + * + * This is currently handled through the fcoe_config_mutex begin held. */ - write_lock(&fcoe_hostlist_lock); + /* lport exch manager allocation */ rc = fcoe_em_config(lport); if (rc) { @@ -770,10 +769,6 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, goto out_lp_destroy; } - /* add to lports list */ - fcoe_hostlist_add(lport); - write_unlock(&fcoe_hostlist_lock); - dev_hold(netdev); fcoe_interface_get(fcoe); return lport; @@ -1713,6 +1708,8 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) rc = -ENODEV; goto out_putdev; } + /* Remove the instance from fcoe's list */ + fcoe_hostlist_remove(lport); port = lport_priv(lport); fcoe = port->fcoe; fcoe_if_destroy(lport); @@ -1782,6 +1779,9 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) /* Make this the "master" N_Port */ fcoe->ctlr.lp = lport; + /* add to lports list */ + fcoe_hostlist_add(lport); + /* start FIP Discovery and FLOGI */ lport->boot_time = jiffies; fc_fabric_login(lport); @@ -1954,8 +1954,6 @@ struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) * fcoe_hostlist_add() - Add a lport to lports list * @lp: ptr to the fc_lport to be added * - * Called with write fcoe_hostlist_lock held. - * * Returns: 0 for success */ int fcoe_hostlist_add(const struct fc_lport *lport) @@ -1963,12 +1961,14 @@ int fcoe_hostlist_add(const struct fc_lport *lport) struct fcoe_interface *fcoe; struct fcoe_port *port; + write_lock_bh(&fcoe_hostlist_lock); fcoe = fcoe_hostlist_lookup_port(fcoe_netdev(lport)); if (!fcoe) { port = lport_priv(lport); fcoe = port->fcoe; list_add_tail(&fcoe->list, &fcoe_hostlist); } + write_unlock_bh(&fcoe_hostlist_lock); return 0; } @@ -2045,14 +2045,21 @@ static void __exit fcoe_exit(void) { unsigned int cpu; struct fcoe_interface *fcoe, *tmp; + LIST_HEAD(local_list); mutex_lock(&fcoe_config_mutex); fcoe_dev_cleanup(); /* releases the associated fcoe hosts */ - list_for_each_entry_safe(fcoe, tmp, &fcoe_hostlist, list) + write_lock_bh(&fcoe_hostlist_lock); + list_splice_init(&fcoe_hostlist, &local_list); + write_unlock_bh(&fcoe_hostlist_lock); + + list_for_each_entry_safe(fcoe, tmp, &local_list, list) { + list_del(&fcoe->list); fcoe_if_destroy(fcoe->ctlr.lp); + } unregister_hotcpu_notifier(&fcoe_cpu_notifier); -- cgit v1.2.3-18-g5258 From 2e70e2415193b84c1b79ec373af15c3f280ad7c4 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 25 Aug 2009 14:00:23 -0700 Subject: [SCSI] fcoe: Fix module ref count bug by adding NETDEV UNREGISTER handling Fixes reference counting on fcoe_instance and net_device, and adds NETDEV_UNREGISTER notifier handling so that you can unload network drivers. FCoE no longer increments the module use count for the network driver. On an NETDEV_UNREGISTER event, destroying the FCoE instance is deferred to a workqueue context to avoid RTNL deadlocks. Based in part by an earlier patch from John Fastabend John's patch description: Currently, the netdev module ref count is not decremented with module_put() when the module is unloaded while fcoe instances are present. To fix this removed reference count on netdev module completely and added functionality to netdev event handling for NETDEV_UNREGISTER events. This allows fcoe to remove devices cleanly when the netdev module is unloaded so we no longer need to hold a reference count for the netdev module. Signed-off-by: Chris Leech Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 186 +++++++++++++++++------------------------------ drivers/scsi/fcoe/fcoe.h | 2 + 2 files changed, 67 insertions(+), 121 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index c9a0346e493..c0264a98439 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -74,12 +74,13 @@ static int fcoe_link_ok(struct fc_lport *lp); static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *); static int fcoe_hostlist_add(const struct fc_lport *); -static int fcoe_hostlist_remove(const struct fc_lport *); static void fcoe_check_wait_queue(struct fc_lport *, struct sk_buff *); static int fcoe_device_notification(struct notifier_block *, ulong, void *); static void fcoe_dev_setup(void); static void fcoe_dev_cleanup(void); +static struct fcoe_interface * + fcoe_hostlist_lookup_port(const struct net_device *dev); /* notification function from net device */ static struct notifier_block fcoe_notifier = { @@ -149,6 +150,7 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev, * @netdev : ptr to the associated netdevice struct * * Returns : 0 for success + * Locking: must be called with the RTNL mutex held */ static int fcoe_interface_setup(struct fcoe_interface *fcoe, struct net_device *netdev) @@ -188,13 +190,11 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe, * or enter promiscuous mode if not capable of listening * for multiple unicast MACs. */ - rtnl_lock(); memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); dev_unicast_add(netdev, flogi_maddr); if (fip->spma) dev_unicast_add(netdev, fip->ctl_src_addr); dev_mc_add(netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); - rtnl_unlock(); /* * setup the receive function from ethernet driver @@ -215,6 +215,7 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe, static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb); static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new); +static void fcoe_destroy_work(struct work_struct *work); /** * fcoe_interface_create() @@ -232,6 +233,7 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev) return NULL; } + dev_hold(netdev); kref_init(&fcoe->kref); /* @@ -249,6 +251,8 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev) /** * fcoe_interface_cleanup() - clean up netdev configurations * @fcoe: + * + * Caller must be holding the RTNL mutex */ void fcoe_interface_cleanup(struct fcoe_interface *fcoe) { @@ -266,11 +270,7 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe) __dev_remove_pack(&fcoe->fip_packet_type); synchronize_net(); - /* tear-down the FCoE controller */ - fcoe_ctlr_destroy(&fcoe->ctlr); - /* Delete secondary MAC addresses */ - rtnl_lock(); memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); dev_unicast_delete(netdev, flogi_maddr); if (!is_zero_ether_addr(fip->data_src_addr)) @@ -278,7 +278,6 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe) if (fip->spma) dev_unicast_delete(netdev, fip->ctl_src_addr); dev_mc_delete(netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); - rtnl_unlock(); } /** @@ -288,10 +287,14 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe) static void fcoe_interface_release(struct kref *kref) { struct fcoe_interface *fcoe; + struct net_device *netdev; fcoe = container_of(kref, struct fcoe_interface, kref); - fcoe_interface_cleanup(fcoe); + netdev = fcoe->netdev; + /* tear-down the FCoE controller */ + fcoe_ctlr_destroy(&fcoe->ctlr); kfree(fcoe); + dev_put(netdev); } /** @@ -642,8 +645,7 @@ static void fcoe_if_destroy(struct fc_lport *lport) /* Free memory used by statistical counters */ fc_lport_free_stats(lport); - /* Release the net_device and Scsi_Host */ - dev_put(netdev); + /* Release the Scsi_Host */ scsi_host_put(lport->host); } @@ -718,7 +720,9 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, } lport = shost_priv(shost); port = lport_priv(lport); + port->lport = lport; port->fcoe = fcoe; + INIT_WORK(&port->destroy_work, fcoe_destroy_work); /* configure fc_lport, e.g., em */ rc = fcoe_lport_config(lport); @@ -769,7 +773,6 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, goto out_lp_destroy; } - dev_hold(netdev); fcoe_interface_get(fcoe); return lport; @@ -1530,19 +1533,19 @@ static int fcoe_device_notification(struct notifier_block *notifier, struct fc_lport *lp = NULL; struct net_device *netdev = ptr; struct fcoe_interface *fcoe; + struct fcoe_port *port; struct fcoe_dev_stats *stats; u32 link_possible = 1; u32 mfs; int rc = NOTIFY_OK; - read_lock(&fcoe_hostlist_lock); + write_lock(&fcoe_hostlist_lock); list_for_each_entry(fcoe, &fcoe_hostlist, list) { if (fcoe->netdev == netdev) { lp = fcoe->ctlr.lp; break; } } - read_unlock(&fcoe_hostlist_lock); if (lp == NULL) { rc = NOTIFY_DONE; goto out; @@ -1564,6 +1567,13 @@ static int fcoe_device_notification(struct notifier_block *notifier, break; case NETDEV_REGISTER: break; + case NETDEV_UNREGISTER: + list_del(&fcoe->list); + port = lport_priv(fcoe->ctlr.lp); + fcoe_interface_cleanup(fcoe); + schedule_work(&port->destroy_work); + goto out; + break; default: FCOE_NETDEV_DBG(netdev, "Unknown event %ld " "from netdev netlink\n", event); @@ -1576,6 +1586,7 @@ static int fcoe_device_notification(struct notifier_block *notifier, fcoe_clean_pending_queue(lp); } out: + write_unlock(&fcoe_hostlist_lock); return rc; } @@ -1600,75 +1611,6 @@ static struct net_device *fcoe_if_to_netdev(const char *buffer) return NULL; } -/** - * fcoe_netdev_to_module_owner() - finds out the driver module of the netdev - * @netdev: the target netdev - * - * Returns: ptr to the struct module, NULL for failure - */ -static struct module * -fcoe_netdev_to_module_owner(const struct net_device *netdev) -{ - struct device *dev; - - if (!netdev) - return NULL; - - dev = netdev->dev.parent; - if (!dev) - return NULL; - - if (!dev->driver) - return NULL; - - return dev->driver->owner; -} - -/** - * fcoe_ethdrv_get() - Hold the Ethernet driver - * @netdev: the target netdev - * - * Holds the Ethernet driver module by try_module_get() for - * the corresponding netdev. - * - * Returns: 0 for success - */ -static int fcoe_ethdrv_get(const struct net_device *netdev) -{ - struct module *owner; - - owner = fcoe_netdev_to_module_owner(netdev); - if (owner) { - FCOE_NETDEV_DBG(netdev, "Hold driver module %s\n", - module_name(owner)); - return try_module_get(owner); - } - return -ENODEV; -} - -/** - * fcoe_ethdrv_put() - Release the Ethernet driver - * @netdev: the target netdev - * - * Releases the Ethernet driver module by module_put for - * the corresponding netdev. - * - * Returns: 0 for success - */ -static int fcoe_ethdrv_put(const struct net_device *netdev) -{ - struct module *owner; - - owner = fcoe_netdev_to_module_owner(netdev); - if (owner) { - FCOE_NETDEV_DBG(netdev, "Release driver module %s\n", - module_name(owner)); - module_put(owner); - return 0; - } - return -ENODEV; -} - /** * fcoe_destroy() - handles the destroy from sysfs * @buffer: expected to be an eth if name @@ -1678,10 +1620,8 @@ static int fcoe_ethdrv_put(const struct net_device *netdev) */ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) { - struct net_device *netdev; struct fcoe_interface *fcoe; - struct fcoe_port *port; - struct fc_lport *lport; + struct net_device *netdev; int rc; mutex_lock(&fcoe_config_mutex); @@ -1702,19 +1642,20 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) rc = -ENODEV; goto out_nodev; } - /* look for existing lport */ - lport = fcoe_hostlist_lookup(netdev); - if (!lport) { + + write_lock(&fcoe_hostlist_lock); + fcoe = fcoe_hostlist_lookup_port(netdev); + if (!fcoe) { + write_unlock(&fcoe_hostlist_lock); rc = -ENODEV; goto out_putdev; } - /* Remove the instance from fcoe's list */ - fcoe_hostlist_remove(lport); - port = lport_priv(lport); - fcoe = port->fcoe; - fcoe_if_destroy(lport); - fcoe_ethdrv_put(netdev); - rc = 0; + list_del(&fcoe->list); + write_unlock(&fcoe_hostlist_lock); + rtnl_lock(); + fcoe_interface_cleanup(fcoe); + rtnl_unlock(); + fcoe_if_destroy(fcoe->ctlr.lp); out_putdev: dev_put(netdev); out_nodev: @@ -1722,6 +1663,16 @@ out_nodev: return rc; } +static void fcoe_destroy_work(struct work_struct *work) +{ + struct fcoe_port *port; + + port = container_of(work, struct fcoe_port, destroy_work); + mutex_lock(&fcoe_config_mutex); + fcoe_if_destroy(port->lport); + mutex_unlock(&fcoe_config_mutex); +} + /** * fcoe_create() - Handles the create call from sysfs * @buffer: expected to be an eth if name @@ -1749,17 +1700,18 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) } #endif + rtnl_lock(); netdev = fcoe_if_to_netdev(buffer); if (!netdev) { rc = -ENODEV; goto out_nodev; } + /* look for existing lport */ if (fcoe_hostlist_lookup(netdev)) { rc = -EEXIST; goto out_putdev; } - fcoe_ethdrv_get(netdev); fcoe = fcoe_interface_create(netdev); if (!fcoe) { @@ -1771,8 +1723,8 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) if (IS_ERR(lport)) { printk(KERN_ERR "fcoe: Failed to create interface (%s)\n", netdev->name); - fcoe_ethdrv_put(netdev); rc = -EIO; + fcoe_interface_cleanup(fcoe); goto out_free; } @@ -1798,6 +1750,7 @@ out_free: out_putdev: dev_put(netdev); out_nodev: + rtnl_unlock(); mutex_unlock(&fcoe_config_mutex); return rc; } @@ -1972,25 +1925,6 @@ int fcoe_hostlist_add(const struct fc_lport *lport) return 0; } -/** - * fcoe_hostlist_remove() - remove a lport from lports list - * @lp: ptr to the fc_lport to be removed - * - * Returns: 0 for success - */ -int fcoe_hostlist_remove(const struct fc_lport *lport) -{ - struct fcoe_interface *fcoe; - - write_lock_bh(&fcoe_hostlist_lock); - fcoe = fcoe_hostlist_lookup_port(fcoe_netdev(lport)); - BUG_ON(!fcoe); - list_del(&fcoe->list); - write_unlock_bh(&fcoe_hostlist_lock); - - return 0; -} - /** * fcoe_init() - fcoe module loading initialization * @@ -2046,6 +1980,7 @@ static void __exit fcoe_exit(void) unsigned int cpu; struct fcoe_interface *fcoe, *tmp; LIST_HEAD(local_list); + struct fcoe_port *port; mutex_lock(&fcoe_config_mutex); @@ -2058,7 +1993,11 @@ static void __exit fcoe_exit(void) list_for_each_entry_safe(fcoe, tmp, &local_list, list) { list_del(&fcoe->list); - fcoe_if_destroy(fcoe->ctlr.lp); + port = lport_priv(fcoe->ctlr.lp); + rtnl_lock(); + fcoe_interface_cleanup(fcoe); + rtnl_unlock(); + schedule_work(&port->destroy_work); } unregister_hotcpu_notifier(&fcoe_cpu_notifier); @@ -2066,9 +2005,14 @@ static void __exit fcoe_exit(void) for_each_online_cpu(cpu) fcoe_percpu_thread_destroy(cpu); - /* detach from scsi transport */ - fcoe_if_exit(); - mutex_unlock(&fcoe_config_mutex); + + /* flush any asyncronous interface destroys, + * this should happen after the netdev notifier is unregistered */ + flush_scheduled_work(); + + /* detach from scsi transport + * must happen after all destroys are done, therefor after the flush */ + fcoe_if_exit(); } module_exit(fcoe_exit); diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index ff229288b7f..ce7f60fb1bc 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h @@ -93,9 +93,11 @@ struct fcoe_interface { */ struct fcoe_port { struct fcoe_interface *fcoe; + struct fc_lport *lport; struct sk_buff_head fcoe_pending_queue; u8 fcoe_pending_queue_active; struct timer_list timer; /* queue timer */ + struct work_struct destroy_work; /* to prevent rtnl deadlocks */ }; #define fcoe_from_ctlr(fip) container_of(fip, struct fcoe_interface, ctlr) -- cgit v1.2.3-18-g5258 From 090eb6c41aa74273d3f0721637cff738cfd80669 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 25 Aug 2009 14:00:28 -0700 Subject: [SCSI] fcoe: use rtnl mutex in place of hostlist lock This just cuts down on the number of locks we're dealing with, and eliminates the need to take another lock in the netdev notifier. Signed-off-by: Chris Leech Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 37 +++++++++++-------------------------- 1 file changed, 11 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index c0264a98439..ac481ad112a 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -58,8 +58,8 @@ MODULE_PARM_DESC(ddp_min, "Minimum I/O size in bytes for " \ DEFINE_MUTEX(fcoe_config_mutex); /* fcoe host list */ +/* must only by accessed under the RTNL mutex */ LIST_HEAD(fcoe_hostlist); -DEFINE_RWLOCK(fcoe_hostlist_lock); DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu); /* Function Prototypes */ @@ -527,8 +527,6 @@ bool fcoe_oem_match(struct fc_frame *fp) * fcoe_em_config() - allocates em for this lport * @lp: the fcoe that em is to allocated for * - * Called with write fcoe_hostlist_lock held. - * * Returns : 0 on success */ static inline int fcoe_em_config(struct fc_lport *lp) @@ -1539,7 +1537,6 @@ static int fcoe_device_notification(struct notifier_block *notifier, u32 mfs; int rc = NOTIFY_OK; - write_lock(&fcoe_hostlist_lock); list_for_each_entry(fcoe, &fcoe_hostlist, list) { if (fcoe->netdev == netdev) { lp = fcoe->ctlr.lp; @@ -1586,7 +1583,6 @@ static int fcoe_device_notification(struct notifier_block *notifier, fcoe_clean_pending_queue(lp); } out: - write_unlock(&fcoe_hostlist_lock); return rc; } @@ -1643,16 +1639,14 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) goto out_nodev; } - write_lock(&fcoe_hostlist_lock); + rtnl_lock(); fcoe = fcoe_hostlist_lookup_port(netdev); if (!fcoe) { - write_unlock(&fcoe_hostlist_lock); + rtnl_unlock(); rc = -ENODEV; goto out_putdev; } list_del(&fcoe->list); - write_unlock(&fcoe_hostlist_lock); - rtnl_lock(); fcoe_interface_cleanup(fcoe); rtnl_unlock(); fcoe_if_destroy(fcoe->ctlr.lp); @@ -1870,9 +1864,8 @@ int fcoe_reset(struct Scsi_Host *shost) * fcoe_hostlist_lookup_port() - find the corresponding lport by a given device * @dev: this is currently ptr to net_device * - * Called with fcoe_hostlist_lock held. - * * Returns: NULL or the located fcoe_port + * Locking: must be called with the RNL mutex held */ static struct fcoe_interface * fcoe_hostlist_lookup_port(const struct net_device *dev) @@ -1891,15 +1884,13 @@ fcoe_hostlist_lookup_port(const struct net_device *dev) * @netdev: ptr to net_device * * Returns: 0 for success + * Locking: must be called with the RTNL mutex held */ -struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) +static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) { struct fcoe_interface *fcoe; - read_lock(&fcoe_hostlist_lock); fcoe = fcoe_hostlist_lookup_port(netdev); - read_unlock(&fcoe_hostlist_lock); - return (fcoe) ? fcoe->ctlr.lp : NULL; } @@ -1908,20 +1899,19 @@ struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) * @lp: ptr to the fc_lport to be added * * Returns: 0 for success + * Locking: must be called with the RTNL mutex held */ -int fcoe_hostlist_add(const struct fc_lport *lport) +static int fcoe_hostlist_add(const struct fc_lport *lport) { struct fcoe_interface *fcoe; struct fcoe_port *port; - write_lock_bh(&fcoe_hostlist_lock); fcoe = fcoe_hostlist_lookup_port(fcoe_netdev(lport)); if (!fcoe) { port = lport_priv(lport); fcoe = port->fcoe; list_add_tail(&fcoe->list, &fcoe_hostlist); } - write_unlock_bh(&fcoe_hostlist_lock); return 0; } @@ -1979,7 +1969,6 @@ static void __exit fcoe_exit(void) { unsigned int cpu; struct fcoe_interface *fcoe, *tmp; - LIST_HEAD(local_list); struct fcoe_port *port; mutex_lock(&fcoe_config_mutex); @@ -1987,18 +1976,14 @@ static void __exit fcoe_exit(void) fcoe_dev_cleanup(); /* releases the associated fcoe hosts */ - write_lock_bh(&fcoe_hostlist_lock); - list_splice_init(&fcoe_hostlist, &local_list); - write_unlock_bh(&fcoe_hostlist_lock); - - list_for_each_entry_safe(fcoe, tmp, &local_list, list) { + rtnl_lock(); + list_for_each_entry_safe(fcoe, tmp, &fcoe_hostlist, list) { list_del(&fcoe->list); port = lport_priv(fcoe->ctlr.lp); - rtnl_lock(); fcoe_interface_cleanup(fcoe); - rtnl_unlock(); schedule_work(&port->destroy_work); } + rtnl_unlock(); unregister_hotcpu_notifier(&fcoe_cpu_notifier); -- cgit v1.2.3-18-g5258 From ab28f1fd3b0d14c1bd693e640decd711d5e6642a Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:00:34 -0700 Subject: [SCSI] libfc: prepare to split off struct fc_rport_priv from fc_rport_libfc_priv While the I/O and LLD interfaces use fc_rport_libfc_priv, the disc and rport interfaces will use fc_rport_priv, which will be separately allocated. Change the disc and rport usage of fc_rport_libfc_priv to fc_rport_priv. Use #define temporarily to make both names equivalent until a subsequent patch splits them. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 18 ++++++------- drivers/scsi/libfc/fc_lport.c | 2 +- drivers/scsi/libfc/fc_rport.c | 60 +++++++++++++++++++++---------------------- 3 files changed, 40 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 6fabf66972b..4c8d893af7b 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -65,7 +65,7 @@ struct fc_rport *fc_disc_lookup_rport(const struct fc_lport *lport, { const struct fc_disc *disc = &lport->disc; struct fc_rport *rport, *found = NULL; - struct fc_rport_libfc_priv *rdata; + struct fc_rport_priv *rdata; int disc_found = 0; list_for_each_entry(rdata, &disc->rports, peers) { @@ -94,7 +94,7 @@ void fc_disc_stop_rports(struct fc_disc *disc) { struct fc_lport *lport; struct fc_rport *rport; - struct fc_rport_libfc_priv *rdata, *next; + struct fc_rport_priv *rdata, *next; lport = disc->lport; @@ -126,7 +126,7 @@ static void fc_disc_rport_callback(struct fc_lport *lport, struct fc_rport *rport, enum fc_rport_event event) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_disc *disc = &lport->disc; FC_DISC_DBG(disc, "Received a %d event for port (%6x)\n", event, @@ -170,7 +170,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, { struct fc_lport *lport; struct fc_rport *rport; - struct fc_rport_libfc_priv *rdata; + struct fc_rport_priv *rdata; struct fc_els_rscn *rp; struct fc_els_rscn_page *pp; struct fc_seq_els_data rjt_data; @@ -309,7 +309,7 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp, static void fc_disc_restart(struct fc_disc *disc) { struct fc_rport *rport; - struct fc_rport_libfc_priv *rdata, *next; + struct fc_rport_priv *rdata, *next; struct fc_lport *lport = disc->lport; FC_DISC_DBG(disc, "Restarting discovery\n"); @@ -400,7 +400,7 @@ static int fc_disc_new_target(struct fc_disc *disc, struct fc_rport_identifiers *ids) { struct fc_lport *lport = disc->lport; - struct fc_rport_libfc_priv *rdata; + struct fc_rport_priv *rdata; int error = 0; if (rport && ids->port_name) { @@ -458,7 +458,7 @@ static int fc_disc_new_target(struct fc_disc *disc, static void fc_disc_del_target(struct fc_disc *disc, struct fc_rport *rport) { struct fc_lport *lport = disc->lport; - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; list_del(&rdata->peers); lport->tt.rport_logoff(rport); } @@ -580,7 +580,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) int error = 0; struct fc_disc_port dp; struct fc_rport *rport; - struct fc_rport_libfc_priv *rdata; + struct fc_rport_priv *rdata; lport = disc->lport; @@ -774,7 +774,7 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) { struct fc_lport *lport; struct fc_rport *new_rport; - struct fc_rport_libfc_priv *rdata; + struct fc_rport_priv *rdata; lport = disc->lport; diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index ca8ea264b68..f7f328f952a 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -1306,7 +1306,7 @@ static struct fc_rport_operations fc_lport_rport_ops = { static void fc_lport_enter_dns(struct fc_lport *lport) { struct fc_rport *rport; - struct fc_rport_libfc_priv *rdata; + struct fc_rport_priv *rdata; struct fc_disc_port dp; dp.ids.port_id = FC_FID_DIR_SERV; diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 90cc90dd3b5..5f8f437e76b 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -96,7 +96,7 @@ static void fc_rport_rogue_destroy(struct device *dev) struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *dp) { struct fc_rport *rport; - struct fc_rport_libfc_priv *rdata; + struct fc_rport_priv *rdata; rport = kzalloc(sizeof(*rport) + sizeof(*rdata), GFP_KERNEL); if (!rport) @@ -144,7 +144,7 @@ struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *dp) static const char *fc_rport_state(struct fc_rport *rport) { const char *cp; - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; cp = fc_rport_state_names[rdata->rp_state]; if (!cp) @@ -199,7 +199,7 @@ static unsigned int fc_plogi_get_maxframe(struct fc_els_flogi *flp, static void fc_rport_state_enter(struct fc_rport *rport, enum fc_rport_state new) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; if (rdata->rp_state != new) rdata->retries = 0; rdata->rp_state = new; @@ -208,8 +208,8 @@ static void fc_rport_state_enter(struct fc_rport *rport, static void fc_rport_work(struct work_struct *work) { u32 port_id; - struct fc_rport_libfc_priv *rdata = - container_of(work, struct fc_rport_libfc_priv, event_work); + struct fc_rport_priv *rdata = + container_of(work, struct fc_rport_priv, event_work); enum fc_rport_event event; enum fc_rport_trans_state trans_state; struct fc_lport *lport = rdata->local_port; @@ -222,7 +222,7 @@ static void fc_rport_work(struct work_struct *work) if (event == RPORT_EV_CREATED) { struct fc_rport *new_rport; - struct fc_rport_libfc_priv *new_rdata; + struct fc_rport_priv *new_rdata; struct fc_rport_identifiers ids; ids.port_id = rport->port_id; @@ -299,7 +299,7 @@ static void fc_rport_work(struct work_struct *work) */ int fc_rport_login(struct fc_rport *rport) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; mutex_lock(&rdata->rp_mutex); @@ -329,7 +329,7 @@ int fc_rport_login(struct fc_rport *rport) static void fc_rport_enter_delete(struct fc_rport *rport, enum fc_rport_event event) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; if (rdata->rp_state == RPORT_ST_DELETE) return; @@ -353,7 +353,7 @@ static void fc_rport_enter_delete(struct fc_rport *rport, */ int fc_rport_logoff(struct fc_rport *rport) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; mutex_lock(&rdata->rp_mutex); @@ -387,7 +387,7 @@ out: */ static void fc_rport_enter_ready(struct fc_rport *rport) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; fc_rport_state_enter(rport, RPORT_ST_READY); @@ -400,7 +400,7 @@ static void fc_rport_enter_ready(struct fc_rport *rport) /** * fc_rport_timeout() - Handler for the retry_work timer. - * @work: The work struct of the fc_rport_libfc_priv + * @work: The work struct of the fc_rport_priv * * Locking Note: Called without the rport lock held. This * function will hold the rport lock, call an _enter_* @@ -408,8 +408,8 @@ static void fc_rport_enter_ready(struct fc_rport *rport) */ static void fc_rport_timeout(struct work_struct *work) { - struct fc_rport_libfc_priv *rdata = - container_of(work, struct fc_rport_libfc_priv, retry_work.work); + struct fc_rport_priv *rdata = + container_of(work, struct fc_rport_priv, retry_work.work); struct fc_rport *rport = PRIV_TO_RPORT(rdata); mutex_lock(&rdata->rp_mutex); @@ -446,7 +446,7 @@ static void fc_rport_timeout(struct work_struct *work) */ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; FC_RPORT_DBG(rport, "Error %ld in state %s, retries %d\n", PTR_ERR(fp), fc_rport_state(rport), rdata->retries); @@ -480,7 +480,7 @@ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) */ static void fc_rport_error_retry(struct fc_rport *rport, struct fc_frame *fp) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; unsigned long delay = FC_DEF_E_D_TOV; /* make sure this isn't an FC_EX_CLOSED error, never retry those */ @@ -515,7 +515,7 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, void *rp_arg) { struct fc_rport *rport = rp_arg; - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; struct fc_els_flogi *plp = NULL; unsigned int tov; @@ -586,7 +586,7 @@ err: */ static void fc_rport_enter_plogi(struct fc_rport *rport) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; struct fc_frame *fp; @@ -624,7 +624,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, void *rp_arg) { struct fc_rport *rport = rp_arg; - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct { struct fc_els_prli prli; struct fc_els_spp spp; @@ -694,7 +694,7 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, void *rp_arg) { struct fc_rport *rport = rp_arg; - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; u8 op; mutex_lock(&rdata->rp_mutex); @@ -738,7 +738,7 @@ err: */ static void fc_rport_enter_prli(struct fc_rport *rport) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; struct { struct fc_els_prli prli; @@ -780,7 +780,7 @@ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, void *rp_arg) { struct fc_rport *rport = rp_arg; - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; u8 op; mutex_lock(&rdata->rp_mutex); @@ -841,7 +841,7 @@ err: static void fc_rport_enter_rtv(struct fc_rport *rport) { struct fc_frame *fp; - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; FC_RPORT_DBG(rport, "Port entered RTV state from %s state\n", @@ -871,7 +871,7 @@ static void fc_rport_enter_rtv(struct fc_rport *rport) */ static void fc_rport_enter_logo(struct fc_rport *rport) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; struct fc_frame *fp; @@ -907,7 +907,7 @@ static void fc_rport_enter_logo(struct fc_rport *rport) void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, struct fc_rport *rport) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; struct fc_frame_header *fh; @@ -967,7 +967,7 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, static void fc_rport_recv_plogi_req(struct fc_rport *rport, struct fc_seq *sp, struct fc_frame *rx_fp) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; struct fc_frame *fp = rx_fp; struct fc_exch *ep; @@ -1090,7 +1090,7 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, static void fc_rport_recv_prli_req(struct fc_rport *rport, struct fc_seq *sp, struct fc_frame *rx_fp) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; struct fc_exch *ep; struct fc_frame *fp; @@ -1242,7 +1242,7 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport, static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp, struct fc_frame *fp) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; struct fc_frame_header *fh; @@ -1278,7 +1278,7 @@ static void fc_rport_recv_logo_req(struct fc_rport *rport, struct fc_seq *sp, struct fc_frame *fp) { struct fc_frame_header *fh; - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; fh = fc_frame_header_get(fp); @@ -1342,8 +1342,8 @@ EXPORT_SYMBOL(fc_destroy_rport); void fc_rport_terminate_io(struct fc_rport *rport) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; - struct fc_lport *lport = rdata->local_port; + struct fc_rport_libfc_priv *rp = rport->dd_data; + struct fc_lport *lport = rp->local_port; lport->tt.exch_mgr_reset(lport, 0, rport->port_id); lport->tt.exch_mgr_reset(lport, rport->port_id, 0); -- cgit v1.2.3-18-g5258 From 795d86f55ec3bf6280dda368f208943f1fb7d366 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:00:39 -0700 Subject: [SCSI] libfc: change interface for rport_create The interface for lport->tt.rport_create() takes a fc_disc_port arg, which is unnatural for most calls. The only reason for this was to avoid passing in the local port as an argument, but otherwise added to complexity. Simplify by just using lport and fc_rport_identifiers. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 31 ++++++++++++------------------- drivers/scsi/libfc/fc_lport.c | 26 ++++++++++++-------------- drivers/scsi/libfc/fc_rport.c | 17 +++++++++-------- 3 files changed, 33 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 4c8d893af7b..ecc625c2052 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -428,13 +428,7 @@ static int fc_disc_new_target(struct fc_disc *disc, if (!rport) { rport = lport->tt.rport_lookup(lport, ids->port_id); if (!rport) { - struct fc_disc_port dp; - dp.lp = lport; - dp.ids.port_id = ids->port_id; - dp.ids.port_name = ids->port_name; - dp.ids.node_name = ids->node_name; - dp.ids.roles = ids->roles; - rport = lport->tt.rport_create(&dp); + rport = lport->tt.rport_create(lport, ids); } if (!rport) error = -ENOMEM; @@ -578,7 +572,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) size_t plen; size_t tlen; int error = 0; - struct fc_disc_port dp; + struct fc_rport_identifiers ids; struct fc_rport *rport; struct fc_rport_priv *rdata; @@ -621,15 +615,14 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) * After the first time through the loop, things return to "normal". */ while (plen >= sizeof(*np)) { - dp.lp = lport; - dp.ids.port_id = ntoh24(np->fp_fid); - dp.ids.port_name = ntohll(np->fp_wwpn); - dp.ids.node_name = -1; - dp.ids.roles = FC_RPORT_ROLE_UNKNOWN; - - if ((dp.ids.port_id != fc_host_port_id(lport->host)) && - (dp.ids.port_name != lport->wwpn)) { - rport = lport->tt.rport_create(&dp); + ids.port_id = ntoh24(np->fp_fid); + ids.port_name = ntohll(np->fp_wwpn); + ids.node_name = -1; + ids.roles = FC_RPORT_ROLE_UNKNOWN; + + if (ids.port_id != fc_host_port_id(lport->host) && + ids.port_name != lport->wwpn) { + rport = lport->tt.rport_create(lport, &ids); if (rport) { rdata = rport->dd_data; rdata->ops = &fc_disc_rport_ops; @@ -640,7 +633,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) } else printk(KERN_WARNING "libfc: Failed to allocate " "memory for the newly discovered port " - "(%6x)\n", dp.ids.port_id); + "(%6x)\n", ids.port_id); } if (np->fp_flags & FC_NS_FID_LAST) { @@ -781,7 +774,7 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) if (dp->ids.port_id == fc_host_port_id(lport->host)) goto out; - new_rport = lport->tt.rport_create(dp); + new_rport = lport->tt.rport_create(lport, &dp->ids); if (new_rport) { rdata = new_rport->dd_data; rdata->ops = &fc_disc_rport_ops; diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index f7f328f952a..a78161cf181 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -211,20 +211,19 @@ static void fc_lport_ptp_setup(struct fc_lport *lport, u32 remote_fid, u64 remote_wwpn, u64 remote_wwnn) { - struct fc_disc_port dp; + struct fc_rport_identifiers ids; - dp.lp = lport; - dp.ids.port_id = remote_fid; - dp.ids.port_name = remote_wwpn; - dp.ids.node_name = remote_wwnn; - dp.ids.roles = FC_RPORT_ROLE_UNKNOWN; + ids.port_id = remote_fid; + ids.port_name = remote_wwpn; + ids.node_name = remote_wwnn; + ids.roles = FC_RPORT_ROLE_UNKNOWN; if (lport->ptp_rp) { lport->tt.rport_logoff(lport->ptp_rp); lport->ptp_rp = NULL; } - lport->ptp_rp = lport->tt.rport_create(&dp); + lport->ptp_rp = lport->tt.rport_create(lport, &ids); lport->tt.rport_login(lport->ptp_rp); @@ -1307,20 +1306,19 @@ static void fc_lport_enter_dns(struct fc_lport *lport) { struct fc_rport *rport; struct fc_rport_priv *rdata; - struct fc_disc_port dp; + struct fc_rport_identifiers ids; - dp.ids.port_id = FC_FID_DIR_SERV; - dp.ids.port_name = -1; - dp.ids.node_name = -1; - dp.ids.roles = FC_RPORT_ROLE_UNKNOWN; - dp.lp = lport; + ids.port_id = FC_FID_DIR_SERV; + ids.port_name = -1; + ids.node_name = -1; + ids.roles = FC_RPORT_ROLE_UNKNOWN; FC_LPORT_DBG(lport, "Entered DNS state from %s state\n", fc_lport_state(lport)); fc_lport_state_enter(lport, LPORT_ST_DNS); - rport = lport->tt.rport_create(&dp); + rport = lport->tt.rport_create(lport, &ids); if (!rport) goto err; diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 5f8f437e76b..2fbc94aaf34 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -93,7 +93,8 @@ static void fc_rport_rogue_destroy(struct device *dev) kfree(rport); } -struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *dp) +struct fc_rport *fc_rport_rogue_create(struct fc_lport *lport, + struct fc_rport_identifiers *ids) { struct fc_rport *rport; struct fc_rport_priv *rdata; @@ -105,10 +106,10 @@ struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *dp) rdata = RPORT_TO_PRIV(rport); rport->dd_data = rdata; - rport->port_id = dp->ids.port_id; - rport->port_name = dp->ids.port_name; - rport->node_name = dp->ids.node_name; - rport->roles = dp->ids.roles; + rport->port_id = ids->port_id; + rport->port_name = ids->port_name; + rport->node_name = ids->node_name; + rport->roles = ids->roles; rport->maxframe_size = FC_MIN_MAX_PAYLOAD; /* * Note: all this libfc rogue rport code will be removed for @@ -118,14 +119,14 @@ struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *dp) rport->dev.release = fc_rport_rogue_destroy; mutex_init(&rdata->rp_mutex); - rdata->local_port = dp->lp; + rdata->local_port = lport; rdata->trans_state = FC_PORTSTATE_ROGUE; rdata->rp_state = RPORT_ST_INIT; rdata->event = RPORT_EV_NONE; rdata->flags = FC_RP_FLAGS_REC_SUPPORTED; rdata->ops = NULL; - rdata->e_d_tov = dp->lp->e_d_tov; - rdata->r_a_tov = dp->lp->r_a_tov; + rdata->e_d_tov = lport->e_d_tov; + rdata->r_a_tov = lport->r_a_tov; INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); INIT_WORK(&rdata->event_work, fc_rport_work); /* -- cgit v1.2.3-18-g5258 From 9fb9d32831fd687e427ec5b147bb690f468b99a0 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:00:50 -0700 Subject: [SCSI] libfc: make fc_rport_priv the primary rport interface. The rport and discovery modules deal with remote ports before fc_remote_port_add() can be done, because the full set of rport identifiers is not known at early stages. In preparation for splitting the fc_rport/fc_rport_priv allocation, make fc_rport_priv the primary interface for the remote port and discovery engines. The FCP / SCSI layers still deal with fc_rport and fc_rport_libfc_priv, however. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 95 ++++------- drivers/scsi/libfc/fc_elsct.c | 4 +- drivers/scsi/libfc/fc_fcp.c | 2 +- drivers/scsi/libfc/fc_lport.c | 26 +-- drivers/scsi/libfc/fc_rport.c | 364 ++++++++++++++++++++---------------------- 5 files changed, 226 insertions(+), 265 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index ecc625c2052..448ffc38865 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -49,7 +49,6 @@ static void fc_disc_gpn_ft_req(struct fc_disc *); static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); static int fc_disc_new_target(struct fc_disc *, struct fc_rport *, struct fc_rport_identifiers *); -static void fc_disc_del_target(struct fc_disc *, struct fc_rport *); static void fc_disc_done(struct fc_disc *); static void fc_disc_timeout(struct work_struct *); static void fc_disc_single(struct fc_disc *, struct fc_disc_port *); @@ -60,27 +59,19 @@ static void fc_disc_restart(struct fc_disc *); * @lport: Fibre Channel host port instance * @port_id: remote port port_id to match */ -struct fc_rport *fc_disc_lookup_rport(const struct fc_lport *lport, - u32 port_id) +struct fc_rport_priv *fc_disc_lookup_rport(const struct fc_lport *lport, + u32 port_id) { const struct fc_disc *disc = &lport->disc; - struct fc_rport *rport, *found = NULL; + struct fc_rport *rport; struct fc_rport_priv *rdata; - int disc_found = 0; list_for_each_entry(rdata, &disc->rports, peers) { rport = PRIV_TO_RPORT(rdata); - if (rport->port_id == port_id) { - disc_found = 1; - found = rport; - break; - } + if (rport->port_id == port_id) + return rdata; } - - if (!disc_found) - found = NULL; - - return found; + return NULL; } /** @@ -93,21 +84,18 @@ struct fc_rport *fc_disc_lookup_rport(const struct fc_lport *lport, void fc_disc_stop_rports(struct fc_disc *disc) { struct fc_lport *lport; - struct fc_rport *rport; struct fc_rport_priv *rdata, *next; lport = disc->lport; mutex_lock(&disc->disc_mutex); list_for_each_entry_safe(rdata, next, &disc->rports, peers) { - rport = PRIV_TO_RPORT(rdata); list_del(&rdata->peers); - lport->tt.rport_logoff(rport); + lport->tt.rport_logoff(rdata); } list_for_each_entry_safe(rdata, next, &disc->rogue_rports, peers) { - rport = PRIV_TO_RPORT(rdata); - lport->tt.rport_logoff(rport); + lport->tt.rport_logoff(rdata); } mutex_unlock(&disc->disc_mutex); @@ -116,18 +104,18 @@ void fc_disc_stop_rports(struct fc_disc *disc) /** * fc_disc_rport_callback() - Event handler for rport events * @lport: The lport which is receiving the event - * @rport: The rport which the event has occured on + * @rdata: private remote port data * @event: The event that occured * * Locking Note: The rport lock should not be held when calling * this function. */ static void fc_disc_rport_callback(struct fc_lport *lport, - struct fc_rport *rport, + struct fc_rport_priv *rdata, enum fc_rport_event event) { - struct fc_rport_priv *rdata = rport->dd_data; struct fc_disc *disc = &lport->disc; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); FC_DISC_DBG(disc, "Received a %d event for port (%6x)\n", event, rport->port_id); @@ -169,7 +157,6 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, struct fc_disc *disc) { struct fc_lport *lport; - struct fc_rport *rport; struct fc_rport_priv *rdata; struct fc_els_rscn *rp; struct fc_els_rscn_page *pp; @@ -249,11 +236,10 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, redisc, lport->state, disc->pending); list_for_each_entry_safe(dp, next, &disc_ports, peers) { list_del(&dp->peers); - rport = lport->tt.rport_lookup(lport, dp->ids.port_id); - if (rport) { - rdata = rport->dd_data; + rdata = lport->tt.rport_lookup(lport, dp->ids.port_id); + if (rdata) { list_del(&rdata->peers); - lport->tt.rport_logoff(rport); + lport->tt.rport_logoff(rdata); } fc_disc_single(disc, dp); } @@ -308,16 +294,14 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp, */ static void fc_disc_restart(struct fc_disc *disc) { - struct fc_rport *rport; struct fc_rport_priv *rdata, *next; struct fc_lport *lport = disc->lport; FC_DISC_DBG(disc, "Restarting discovery\n"); list_for_each_entry_safe(rdata, next, &disc->rports, peers) { - rport = PRIV_TO_RPORT(rdata); list_del(&rdata->peers); - lport->tt.rport_logoff(rport); + lport->tt.rport_logoff(rdata); } disc->requested = 1; @@ -335,6 +319,7 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, enum fc_disc_event), struct fc_lport *lport) { + struct fc_rport_priv *rdata; struct fc_rport *rport; struct fc_rport_identifiers ids; struct fc_disc *disc = &lport->disc; @@ -362,8 +347,9 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, * Handle point-to-point mode as a simple discovery * of the remote port. Yucky, yucky, yuck, yuck! */ - rport = disc->lport->ptp_rp; - if (rport) { + rdata = disc->lport->ptp_rp; + if (rdata) { + rport = PRIV_TO_RPORT(rdata); ids.port_id = rport->port_id; ids.port_name = rport->port_name; ids.node_name = rport->node_name; @@ -418,7 +404,9 @@ static int fc_disc_new_target(struct fc_disc *disc, * assigned the same FCID. This should be rare. * Delete the old one and fall thru to re-create. */ - fc_disc_del_target(disc, rport); + rdata = rport->dd_data; + list_del(&rdata->peers); + lport->tt.rport_logoff(rdata); rport = NULL; } } @@ -426,37 +414,26 @@ static int fc_disc_new_target(struct fc_disc *disc, ids->port_id != fc_host_port_id(lport->host) && ids->port_name != lport->wwpn) { if (!rport) { - rport = lport->tt.rport_lookup(lport, ids->port_id); + rdata = lport->tt.rport_lookup(lport, ids->port_id); if (!rport) { - rport = lport->tt.rport_create(lport, ids); + rdata = lport->tt.rport_create(lport, ids); } - if (!rport) + if (!rdata) error = -ENOMEM; + else + rport = PRIV_TO_RPORT(rdata); } if (rport) { rdata = rport->dd_data; rdata->ops = &fc_disc_rport_ops; rdata->rp_state = RPORT_ST_INIT; list_add_tail(&rdata->peers, &disc->rogue_rports); - lport->tt.rport_login(rport); + lport->tt.rport_login(rdata); } } return error; } -/** - * fc_disc_del_target() - Delete a target - * @disc: FC discovery context - * @rport: The remote port to be removed - */ -static void fc_disc_del_target(struct fc_disc *disc, struct fc_rport *rport) -{ - struct fc_lport *lport = disc->lport; - struct fc_rport_priv *rdata = rport->dd_data; - list_del(&rdata->peers); - lport->tt.rport_logoff(rport); -} - /** * fc_disc_done() - Discovery has been completed * @disc: FC discovery context @@ -573,7 +550,6 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) size_t tlen; int error = 0; struct fc_rport_identifiers ids; - struct fc_rport *rport; struct fc_rport_priv *rdata; lport = disc->lport; @@ -622,14 +598,13 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) if (ids.port_id != fc_host_port_id(lport->host) && ids.port_name != lport->wwpn) { - rport = lport->tt.rport_create(lport, &ids); - if (rport) { - rdata = rport->dd_data; + rdata = lport->tt.rport_create(lport, &ids); + if (rdata) { rdata->ops = &fc_disc_rport_ops; rdata->local_port = lport; list_add_tail(&rdata->peers, &disc->rogue_rports); - lport->tt.rport_login(rport); + lport->tt.rport_login(rdata); } else printk(KERN_WARNING "libfc: Failed to allocate " "memory for the newly discovered port " @@ -766,7 +741,6 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) { struct fc_lport *lport; - struct fc_rport *new_rport; struct fc_rport_priv *rdata; lport = disc->lport; @@ -774,13 +748,12 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) if (dp->ids.port_id == fc_host_port_id(lport->host)) goto out; - new_rport = lport->tt.rport_create(lport, &dp->ids); - if (new_rport) { - rdata = new_rport->dd_data; + rdata = lport->tt.rport_create(lport, &dp->ids); + if (rdata) { rdata->ops = &fc_disc_rport_ops; kfree(dp); list_add_tail(&rdata->peers, &disc->rogue_rports); - lport->tt.rport_login(new_rport); + lport->tt.rport_login(rdata); } return; out: diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c index 5878b34bff1..2b8a3bbc039 100644 --- a/drivers/scsi/libfc/fc_elsct.c +++ b/drivers/scsi/libfc/fc_elsct.c @@ -32,7 +32,7 @@ * fc_elsct_send - sends ELS/CT frame */ static struct fc_seq *fc_elsct_send(struct fc_lport *lport, - struct fc_rport *rport, + struct fc_rport_priv *rdata, struct fc_frame *fp, unsigned int op, void (*resp)(struct fc_seq *, @@ -47,7 +47,7 @@ static struct fc_seq *fc_elsct_send(struct fc_lport *lport, /* ELS requests */ if ((op >= ELS_LS_RJT) && (op <= ELS_AUTH_ELS)) - rc = fc_els_fill(lport, rport, fp, op, &r_ctl, &did, &fh_type); + rc = fc_els_fill(lport, rdata, fp, op, &r_ctl, &did, &fh_type); else /* CT requests */ rc = fc_ct_fill(lport, fp, op, &r_ctl, &did, &fh_type); diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 7d5ffcbbf39..a622096eb31 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -1308,7 +1308,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp) fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rport->port_id, fc_host_port_id(rp->local_port->host), FC_TYPE_ELS, FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); - if (lp->tt.elsct_send(lp, rport, fp, ELS_REC, fc_fcp_rec_resp, + if (lp->tt.elsct_send(lp, rport->dd_data, fp, ELS_REC, fc_fcp_rec_resp, fsp, jiffies_to_msecs(FC_SCSI_REC_TOV))) { fc_fcp_pkt_hold(fsp); /* hold while REC outstanding */ return; diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index a78161cf181..3c15abd35ff 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -133,16 +133,18 @@ static int fc_frame_drop(struct fc_lport *lport, struct fc_frame *fp) /** * fc_lport_rport_callback() - Event handler for rport events * @lport: The lport which is receiving the event - * @rport: The rport which the event has occured on + * @rdata: private remote port data * @event: The event that occured * * Locking Note: The rport lock should not be held when calling * this function. */ static void fc_lport_rport_callback(struct fc_lport *lport, - struct fc_rport *rport, + struct fc_rport_priv *rdata, enum fc_rport_event event) { + struct fc_rport *rport = PRIV_TO_RPORT(rdata); + FC_LPORT_DBG(lport, "Received a %d event for port (%6x)\n", event, rport->port_id); @@ -151,7 +153,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport, if (rport->port_id == FC_FID_DIR_SERV) { mutex_lock(&lport->lp_mutex); if (lport->state == LPORT_ST_DNS) { - lport->dns_rp = rport; + lport->dns_rp = rdata; fc_lport_enter_rpn_id(lport); } else { FC_LPORT_DBG(lport, "Received an CREATED event " @@ -160,7 +162,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport, "in the DNS state, it's in the " "%d state", rport->port_id, lport->state); - lport->tt.rport_logoff(rport); + lport->tt.rport_logoff(rdata); } mutex_unlock(&lport->lp_mutex); } else @@ -832,7 +834,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, { struct fc_frame_header *fh = fc_frame_header_get(fp); void (*recv) (struct fc_seq *, struct fc_frame *, struct fc_lport *); - struct fc_rport *rport; + struct fc_rport_priv *rdata; u32 s_id; u32 d_id; struct fc_seq_els_data rjt_data; @@ -888,9 +890,9 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, s_id = ntoh24(fh->fh_s_id); d_id = ntoh24(fh->fh_d_id); - rport = lport->tt.rport_lookup(lport, s_id); - if (rport) - lport->tt.rport_recv_req(sp, fp, rport); + rdata = lport->tt.rport_lookup(lport, s_id); + if (rdata) + lport->tt.rport_recv_req(sp, fp, rdata); else { rjt_data.fp = NULL; rjt_data.reason = ELS_RJT_UNAB; @@ -1304,7 +1306,6 @@ static struct fc_rport_operations fc_lport_rport_ops = { */ static void fc_lport_enter_dns(struct fc_lport *lport) { - struct fc_rport *rport; struct fc_rport_priv *rdata; struct fc_rport_identifiers ids; @@ -1318,13 +1319,12 @@ static void fc_lport_enter_dns(struct fc_lport *lport) fc_lport_state_enter(lport, LPORT_ST_DNS); - rport = lport->tt.rport_create(lport, &ids); - if (!rport) + rdata = lport->tt.rport_create(lport, &ids); + if (!rdata) goto err; - rdata = rport->dd_data; rdata->ops = &fc_lport_rport_ops; - lport->tt.rport_login(rport); + lport->tt.rport_login(rdata); return; err: diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 2fbc94aaf34..13d3d758fb0 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -57,23 +57,23 @@ struct workqueue_struct *rport_event_queue; -static void fc_rport_enter_plogi(struct fc_rport *); -static void fc_rport_enter_prli(struct fc_rport *); -static void fc_rport_enter_rtv(struct fc_rport *); -static void fc_rport_enter_ready(struct fc_rport *); -static void fc_rport_enter_logo(struct fc_rport *); +static void fc_rport_enter_plogi(struct fc_rport_priv *); +static void fc_rport_enter_prli(struct fc_rport_priv *); +static void fc_rport_enter_rtv(struct fc_rport_priv *); +static void fc_rport_enter_ready(struct fc_rport_priv *); +static void fc_rport_enter_logo(struct fc_rport_priv *); -static void fc_rport_recv_plogi_req(struct fc_rport *, +static void fc_rport_recv_plogi_req(struct fc_rport_priv *, struct fc_seq *, struct fc_frame *); -static void fc_rport_recv_prli_req(struct fc_rport *, +static void fc_rport_recv_prli_req(struct fc_rport_priv *, struct fc_seq *, struct fc_frame *); -static void fc_rport_recv_prlo_req(struct fc_rport *, +static void fc_rport_recv_prlo_req(struct fc_rport_priv *, struct fc_seq *, struct fc_frame *); -static void fc_rport_recv_logo_req(struct fc_rport *, +static void fc_rport_recv_logo_req(struct fc_rport_priv *, struct fc_seq *, struct fc_frame *); static void fc_rport_timeout(struct work_struct *); -static void fc_rport_error(struct fc_rport *, struct fc_frame *); -static void fc_rport_error_retry(struct fc_rport *, struct fc_frame *); +static void fc_rport_error(struct fc_rport_priv *, struct fc_frame *); +static void fc_rport_error_retry(struct fc_rport_priv *, struct fc_frame *); static void fc_rport_work(struct work_struct *); static const char *fc_rport_state_names[] = { @@ -89,12 +89,14 @@ static const char *fc_rport_state_names[] = { static void fc_rport_rogue_destroy(struct device *dev) { struct fc_rport *rport = dev_to_rport(dev); - FC_RPORT_DBG(rport, "Destroying rogue rport\n"); + struct fc_rport_priv *rdata = RPORT_TO_PRIV(rport); + + FC_RPORT_DBG(rdata, "Destroying rogue rport\n"); kfree(rport); } -struct fc_rport *fc_rport_rogue_create(struct fc_lport *lport, - struct fc_rport_identifiers *ids) +struct fc_rport_priv *fc_rport_rogue_create(struct fc_lport *lport, + struct fc_rport_identifiers *ids) { struct fc_rport *rport; struct fc_rport_priv *rdata; @@ -135,17 +137,16 @@ struct fc_rport *fc_rport_rogue_create(struct fc_lport *lport, */ INIT_LIST_HEAD(&rdata->peers); - return rport; + return rdata; } /** * fc_rport_state() - return a string for the state the rport is in - * @rport: The rport whose state we want to get a string for + * @rdata: remote port private data */ -static const char *fc_rport_state(struct fc_rport *rport) +static const char *fc_rport_state(struct fc_rport_priv *rdata) { const char *cp; - struct fc_rport_priv *rdata = rport->dd_data; cp = fc_rport_state_names[rdata->rp_state]; if (!cp) @@ -192,15 +193,14 @@ static unsigned int fc_plogi_get_maxframe(struct fc_els_flogi *flp, /** * fc_rport_state_enter() - Change the rport's state - * @rport: The rport whose state should change + * @rdata: The rport whose state should change * @new: The new state of the rport * * Locking Note: Called with the rport lock held */ -static void fc_rport_state_enter(struct fc_rport *rport, +static void fc_rport_state_enter(struct fc_rport_priv *rdata, enum fc_rport_state new) { - struct fc_rport_priv *rdata = rport->dd_data; if (rdata->rp_state != new) rdata->retries = 0; rdata->rp_state = new; @@ -255,7 +255,7 @@ static void fc_rport_work(struct work_struct *work) INIT_LIST_HEAD(&new_rdata->peers); INIT_WORK(&new_rdata->event_work, fc_rport_work); - fc_rport_state_enter(new_rport, RPORT_ST_READY); + fc_rport_state_enter(new_rdata, RPORT_ST_READY); } else { printk(KERN_WARNING "libfc: Failed to allocate " " memory for rport (%6x)\n", ids.port_id); @@ -263,20 +263,20 @@ static void fc_rport_work(struct work_struct *work) } if (rport->port_id != FC_FID_DIR_SERV) if (rport_ops->event_callback) - rport_ops->event_callback(lport, rport, + rport_ops->event_callback(lport, rdata, RPORT_EV_FAILED); put_device(&rport->dev); rport = new_rport; rdata = new_rport->dd_data; if (rport_ops->event_callback) - rport_ops->event_callback(lport, rport, event); + rport_ops->event_callback(lport, rdata, event); } else if ((event == RPORT_EV_FAILED) || (event == RPORT_EV_LOGO) || (event == RPORT_EV_STOP)) { trans_state = rdata->trans_state; mutex_unlock(&rdata->rp_mutex); if (rport_ops->event_callback) - rport_ops->event_callback(lport, rport, event); + rport_ops->event_callback(lport, rdata, event); cancel_delayed_work_sync(&rdata->retry_work); if (trans_state == FC_PORTSTATE_ROGUE) put_device(&rport->dev); @@ -292,21 +292,19 @@ static void fc_rport_work(struct work_struct *work) /** * fc_rport_login() - Start the remote port login state machine - * @rport: Fibre Channel remote port + * @rdata: private remote port * * Locking Note: Called without the rport lock held. This * function will hold the rport lock, call an _enter_* * function and then unlock the rport. */ -int fc_rport_login(struct fc_rport *rport) +int fc_rport_login(struct fc_rport_priv *rdata) { - struct fc_rport_priv *rdata = rport->dd_data; - mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rport, "Login to port\n"); + FC_RPORT_DBG(rdata, "Login to port\n"); - fc_rport_enter_plogi(rport); + fc_rport_enter_plogi(rdata); mutex_unlock(&rdata->rp_mutex); @@ -315,7 +313,7 @@ int fc_rport_login(struct fc_rport *rport) /** * fc_rport_enter_delete() - schedule a remote port to be deleted. - * @rport: Fibre Channel remote port + * @rdata: private remote port * @event: event to report as the reason for deletion * * Locking Note: Called with the rport lock held. @@ -327,17 +325,15 @@ int fc_rport_login(struct fc_rport *rport) * Since we have the mutex, even if fc_rport_work() is already started, * it'll see the new event. */ -static void fc_rport_enter_delete(struct fc_rport *rport, +static void fc_rport_enter_delete(struct fc_rport_priv *rdata, enum fc_rport_event event) { - struct fc_rport_priv *rdata = rport->dd_data; - if (rdata->rp_state == RPORT_ST_DELETE) return; - FC_RPORT_DBG(rport, "Delete port\n"); + FC_RPORT_DBG(rdata, "Delete port\n"); - fc_rport_state_enter(rport, RPORT_ST_DELETE); + fc_rport_state_enter(rdata, RPORT_ST_DELETE); if (rdata->event == RPORT_EV_NONE) queue_work(rport_event_queue, &rdata->event_work); @@ -346,33 +342,31 @@ static void fc_rport_enter_delete(struct fc_rport *rport, /** * fc_rport_logoff() - Logoff and remove an rport - * @rport: Fibre Channel remote port to be removed + * @rdata: private remote port * * Locking Note: Called without the rport lock held. This * function will hold the rport lock, call an _enter_* * function and then unlock the rport. */ -int fc_rport_logoff(struct fc_rport *rport) +int fc_rport_logoff(struct fc_rport_priv *rdata) { - struct fc_rport_priv *rdata = rport->dd_data; - mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rport, "Remove port\n"); + FC_RPORT_DBG(rdata, "Remove port\n"); if (rdata->rp_state == RPORT_ST_DELETE) { - FC_RPORT_DBG(rport, "Port in Delete state, not removing\n"); + FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n"); mutex_unlock(&rdata->rp_mutex); goto out; } - fc_rport_enter_logo(rport); + fc_rport_enter_logo(rdata); /* * Change the state to Delete so that we discard * the response. */ - fc_rport_enter_delete(rport, RPORT_EV_STOP); + fc_rport_enter_delete(rdata, RPORT_EV_STOP); mutex_unlock(&rdata->rp_mutex); out: @@ -381,18 +375,16 @@ out: /** * fc_rport_enter_ready() - The rport is ready - * @rport: Fibre Channel remote port that is ready + * @rdata: private remote port * * Locking Note: The rport lock is expected to be held before calling * this routine. */ -static void fc_rport_enter_ready(struct fc_rport *rport) +static void fc_rport_enter_ready(struct fc_rport_priv *rdata) { - struct fc_rport_priv *rdata = rport->dd_data; - - fc_rport_state_enter(rport, RPORT_ST_READY); + fc_rport_state_enter(rdata, RPORT_ST_READY); - FC_RPORT_DBG(rport, "Port is Ready\n"); + FC_RPORT_DBG(rdata, "Port is Ready\n"); if (rdata->event == RPORT_EV_NONE) queue_work(rport_event_queue, &rdata->event_work); @@ -411,22 +403,21 @@ static void fc_rport_timeout(struct work_struct *work) { struct fc_rport_priv *rdata = container_of(work, struct fc_rport_priv, retry_work.work); - struct fc_rport *rport = PRIV_TO_RPORT(rdata); mutex_lock(&rdata->rp_mutex); switch (rdata->rp_state) { case RPORT_ST_PLOGI: - fc_rport_enter_plogi(rport); + fc_rport_enter_plogi(rdata); break; case RPORT_ST_PRLI: - fc_rport_enter_prli(rport); + fc_rport_enter_prli(rdata); break; case RPORT_ST_RTV: - fc_rport_enter_rtv(rport); + fc_rport_enter_rtv(rdata); break; case RPORT_ST_LOGO: - fc_rport_enter_logo(rport); + fc_rport_enter_logo(rdata); break; case RPORT_ST_READY: case RPORT_ST_INIT: @@ -439,27 +430,25 @@ static void fc_rport_timeout(struct work_struct *work) /** * fc_rport_error() - Error handler, called once retries have been exhausted - * @rport: The fc_rport object + * @rdata: private remote port * @fp: The frame pointer * * Locking Note: The rport lock is expected to be held before * calling this routine */ -static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) +static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp) { - struct fc_rport_priv *rdata = rport->dd_data; - - FC_RPORT_DBG(rport, "Error %ld in state %s, retries %d\n", - PTR_ERR(fp), fc_rport_state(rport), rdata->retries); + FC_RPORT_DBG(rdata, "Error %ld in state %s, retries %d\n", + PTR_ERR(fp), fc_rport_state(rdata), rdata->retries); switch (rdata->rp_state) { case RPORT_ST_PLOGI: case RPORT_ST_PRLI: case RPORT_ST_LOGO: - fc_rport_enter_delete(rport, RPORT_EV_FAILED); + fc_rport_enter_delete(rdata, RPORT_EV_FAILED); break; case RPORT_ST_RTV: - fc_rport_enter_ready(rport); + fc_rport_enter_ready(rdata); break; case RPORT_ST_DELETE: case RPORT_ST_READY: @@ -470,7 +459,7 @@ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) /** * fc_rport_error_retry() - Error handler when retries are desired - * @rport: The fc_rport object + * @rdata: private remote port data * @fp: The frame pointer * * If the error was an exchange timeout retry immediately, @@ -479,18 +468,18 @@ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) * Locking Note: The rport lock is expected to be held before * calling this routine */ -static void fc_rport_error_retry(struct fc_rport *rport, struct fc_frame *fp) +static void fc_rport_error_retry(struct fc_rport_priv *rdata, + struct fc_frame *fp) { - struct fc_rport_priv *rdata = rport->dd_data; unsigned long delay = FC_DEF_E_D_TOV; /* make sure this isn't an FC_EX_CLOSED error, never retry those */ if (PTR_ERR(fp) == -FC_EX_CLOSED) - return fc_rport_error(rport, fp); + return fc_rport_error(rdata, fp); if (rdata->retries < rdata->local_port->max_rport_retry_count) { - FC_RPORT_DBG(rport, "Error %ld in state %s, retrying\n", - PTR_ERR(fp), fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Error %ld in state %s, retrying\n", + PTR_ERR(fp), fc_rport_state(rdata)); rdata->retries++; /* no additional delay on exchange timeouts */ if (PTR_ERR(fp) == -FC_EX_TIMEOUT) @@ -499,24 +488,24 @@ static void fc_rport_error_retry(struct fc_rport *rport, struct fc_frame *fp) return; } - return fc_rport_error(rport, fp); + return fc_rport_error(rdata, fp); } /** * fc_rport_plogi_recv_resp() - Handle incoming ELS PLOGI response * @sp: current sequence in the PLOGI exchange * @fp: response frame - * @rp_arg: Fibre Channel remote port + * @rdata_arg: private remote port data * * Locking Note: This function will be called without the rport lock * held, but it will lock, call an _enter_* function or fc_rport_error * and then unlock the rport. */ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, - void *rp_arg) + void *rdata_arg) { - struct fc_rport *rport = rp_arg; - struct fc_rport_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rdata_arg; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_lport *lport = rdata->local_port; struct fc_els_flogi *plp = NULL; unsigned int tov; @@ -526,18 +515,18 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rport, "Received a PLOGI response\n"); + FC_RPORT_DBG(rdata, "Received a PLOGI response\n"); if (rdata->rp_state != RPORT_ST_PLOGI) { - FC_RPORT_DBG(rport, "Received a PLOGI response, but in state " - "%s\n", fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Received a PLOGI response, but in state " + "%s\n", fc_rport_state(rdata)); if (IS_ERR(fp)) goto err; goto out; } if (IS_ERR(fp)) { - fc_rport_error_retry(rport, fp); + fc_rport_error_retry(rdata, fp); goto err; } @@ -565,11 +554,11 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, * we skip PRLI and RTV and go straight to READY. */ if (rport->port_id >= FC_FID_DOM_MGR) - fc_rport_enter_ready(rport); + fc_rport_enter_ready(rdata); else - fc_rport_enter_prli(rport); + fc_rport_enter_prli(rdata); } else - fc_rport_error_retry(rport, fp); + fc_rport_error_retry(rdata, fp); out: fc_frame_free(fp); @@ -580,33 +569,33 @@ err: /** * fc_rport_enter_plogi() - Send Port Login (PLOGI) request to peer - * @rport: Fibre Channel remote port to send PLOGI to + * @rdata: private remote port data * * Locking Note: The rport lock is expected to be held before calling * this routine. */ -static void fc_rport_enter_plogi(struct fc_rport *rport) +static void fc_rport_enter_plogi(struct fc_rport_priv *rdata) { - struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_frame *fp; - FC_RPORT_DBG(rport, "Port entered PLOGI state from %s state\n", - fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Port entered PLOGI state from %s state\n", + fc_rport_state(rdata)); - fc_rport_state_enter(rport, RPORT_ST_PLOGI); + fc_rport_state_enter(rdata, RPORT_ST_PLOGI); rport->maxframe_size = FC_MIN_MAX_PAYLOAD; fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); if (!fp) { - fc_rport_error_retry(rport, fp); + fc_rport_error_retry(rdata, fp); return; } rdata->e_d_tov = lport->e_d_tov; - if (!lport->tt.elsct_send(lport, rport, fp, ELS_PLOGI, - fc_rport_plogi_resp, rport, lport->e_d_tov)) - fc_rport_error_retry(rport, fp); + if (!lport->tt.elsct_send(lport, rdata, fp, ELS_PLOGI, + fc_rport_plogi_resp, rdata, lport->e_d_tov)) + fc_rport_error_retry(rdata, fp); else get_device(&rport->dev); } @@ -615,17 +604,17 @@ static void fc_rport_enter_plogi(struct fc_rport *rport) * fc_rport_prli_resp() - Process Login (PRLI) response handler * @sp: current sequence in the PRLI exchange * @fp: response frame - * @rp_arg: Fibre Channel remote port + * @rdata_arg: private remote port data * * Locking Note: This function will be called without the rport lock * held, but it will lock, call an _enter_* function or fc_rport_error * and then unlock the rport. */ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, - void *rp_arg) + void *rdata_arg) { - struct fc_rport *rport = rp_arg; - struct fc_rport_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rdata_arg; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct { struct fc_els_prli prli; struct fc_els_spp spp; @@ -636,18 +625,18 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rport, "Received a PRLI response\n"); + FC_RPORT_DBG(rdata, "Received a PRLI response\n"); if (rdata->rp_state != RPORT_ST_PRLI) { - FC_RPORT_DBG(rport, "Received a PRLI response, but in state " - "%s\n", fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Received a PRLI response, but in state " + "%s\n", fc_rport_state(rdata)); if (IS_ERR(fp)) goto err; goto out; } if (IS_ERR(fp)) { - fc_rport_error_retry(rport, fp); + fc_rport_error_retry(rdata, fp); goto err; } @@ -667,11 +656,11 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, roles |= FC_RPORT_ROLE_FCP_TARGET; rport->roles = roles; - fc_rport_enter_rtv(rport); + fc_rport_enter_rtv(rdata); } else { - FC_RPORT_DBG(rport, "Bad ELS response for PRLI command\n"); - fc_rport_enter_delete(rport, RPORT_EV_FAILED); + FC_RPORT_DBG(rdata, "Bad ELS response for PRLI command\n"); + fc_rport_enter_delete(rdata, RPORT_EV_FAILED); } out: @@ -685,42 +674,42 @@ err: * fc_rport_logo_resp() - Logout (LOGO) response handler * @sp: current sequence in the LOGO exchange * @fp: response frame - * @rp_arg: Fibre Channel remote port + * @rdata_arg: private remote port data * * Locking Note: This function will be called without the rport lock * held, but it will lock, call an _enter_* function or fc_rport_error * and then unlock the rport. */ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, - void *rp_arg) + void *rdata_arg) { - struct fc_rport *rport = rp_arg; - struct fc_rport_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rdata_arg; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); u8 op; mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rport, "Received a LOGO response\n"); + FC_RPORT_DBG(rdata, "Received a LOGO response\n"); if (rdata->rp_state != RPORT_ST_LOGO) { - FC_RPORT_DBG(rport, "Received a LOGO response, but in state " - "%s\n", fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Received a LOGO response, but in state " + "%s\n", fc_rport_state(rdata)); if (IS_ERR(fp)) goto err; goto out; } if (IS_ERR(fp)) { - fc_rport_error_retry(rport, fp); + fc_rport_error_retry(rdata, fp); goto err; } op = fc_frame_payload_op(fp); if (op == ELS_LS_ACC) { - fc_rport_enter_rtv(rport); + fc_rport_enter_rtv(rdata); } else { - FC_RPORT_DBG(rport, "Bad ELS response for LOGO command\n"); - fc_rport_enter_delete(rport, RPORT_EV_LOGO); + FC_RPORT_DBG(rdata, "Bad ELS response for LOGO command\n"); + fc_rport_enter_delete(rdata, RPORT_EV_LOGO); } out: @@ -732,14 +721,14 @@ err: /** * fc_rport_enter_prli() - Send Process Login (PRLI) request to peer - * @rport: Fibre Channel remote port to send PRLI to + * @rdata: private remote port data * * Locking Note: The rport lock is expected to be held before calling * this routine. */ -static void fc_rport_enter_prli(struct fc_rport *rport) +static void fc_rport_enter_prli(struct fc_rport_priv *rdata) { - struct fc_rport_priv *rdata = rport->dd_data; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_lport *lport = rdata->local_port; struct { struct fc_els_prli prli; @@ -747,20 +736,20 @@ static void fc_rport_enter_prli(struct fc_rport *rport) } *pp; struct fc_frame *fp; - FC_RPORT_DBG(rport, "Port entered PRLI state from %s state\n", - fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Port entered PRLI state from %s state\n", + fc_rport_state(rdata)); - fc_rport_state_enter(rport, RPORT_ST_PRLI); + fc_rport_state_enter(rdata, RPORT_ST_PRLI); fp = fc_frame_alloc(lport, sizeof(*pp)); if (!fp) { - fc_rport_error_retry(rport, fp); + fc_rport_error_retry(rdata, fp); return; } - if (!lport->tt.elsct_send(lport, rport, fp, ELS_PRLI, - fc_rport_prli_resp, rport, lport->e_d_tov)) - fc_rport_error_retry(rport, fp); + if (!lport->tt.elsct_send(lport, rdata, fp, ELS_PRLI, + fc_rport_prli_resp, rdata, lport->e_d_tov)) + fc_rport_error_retry(rdata, fp); else get_device(&rport->dev); } @@ -769,7 +758,7 @@ static void fc_rport_enter_prli(struct fc_rport *rport) * fc_rport_els_rtv_resp() - Request Timeout Value response handler * @sp: current sequence in the RTV exchange * @fp: response frame - * @rp_arg: Fibre Channel remote port + * @rdata_arg: private remote port data * * Many targets don't seem to support this. * @@ -778,26 +767,26 @@ static void fc_rport_enter_prli(struct fc_rport *rport) * and then unlock the rport. */ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, - void *rp_arg) + void *rdata_arg) { - struct fc_rport *rport = rp_arg; - struct fc_rport_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rdata_arg; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); u8 op; mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rport, "Received a RTV response\n"); + FC_RPORT_DBG(rdata, "Received a RTV response\n"); if (rdata->rp_state != RPORT_ST_RTV) { - FC_RPORT_DBG(rport, "Received a RTV response, but in state " - "%s\n", fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Received a RTV response, but in state " + "%s\n", fc_rport_state(rdata)); if (IS_ERR(fp)) goto err; goto out; } if (IS_ERR(fp)) { - fc_rport_error(rport, fp); + fc_rport_error(rdata, fp); goto err; } @@ -823,7 +812,7 @@ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, } } - fc_rport_enter_ready(rport); + fc_rport_enter_ready(rdata); out: fc_frame_free(fp); @@ -834,62 +823,62 @@ err: /** * fc_rport_enter_rtv() - Send Request Timeout Value (RTV) request to peer - * @rport: Fibre Channel remote port to send RTV to + * @rdata: private remote port data * * Locking Note: The rport lock is expected to be held before calling * this routine. */ -static void fc_rport_enter_rtv(struct fc_rport *rport) +static void fc_rport_enter_rtv(struct fc_rport_priv *rdata) { struct fc_frame *fp; - struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); - FC_RPORT_DBG(rport, "Port entered RTV state from %s state\n", - fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Port entered RTV state from %s state\n", + fc_rport_state(rdata)); - fc_rport_state_enter(rport, RPORT_ST_RTV); + fc_rport_state_enter(rdata, RPORT_ST_RTV); fp = fc_frame_alloc(lport, sizeof(struct fc_els_rtv)); if (!fp) { - fc_rport_error_retry(rport, fp); + fc_rport_error_retry(rdata, fp); return; } - if (!lport->tt.elsct_send(lport, rport, fp, ELS_RTV, - fc_rport_rtv_resp, rport, lport->e_d_tov)) - fc_rport_error_retry(rport, fp); + if (!lport->tt.elsct_send(lport, rdata, fp, ELS_RTV, + fc_rport_rtv_resp, rdata, lport->e_d_tov)) + fc_rport_error_retry(rdata, fp); else get_device(&rport->dev); } /** * fc_rport_enter_logo() - Send Logout (LOGO) request to peer - * @rport: Fibre Channel remote port to send LOGO to + * @rdata: private remote port data * * Locking Note: The rport lock is expected to be held before calling * this routine. */ -static void fc_rport_enter_logo(struct fc_rport *rport) +static void fc_rport_enter_logo(struct fc_rport_priv *rdata) { - struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_frame *fp; - FC_RPORT_DBG(rport, "Port entered LOGO state from %s state\n", - fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Port entered LOGO state from %s state\n", + fc_rport_state(rdata)); - fc_rport_state_enter(rport, RPORT_ST_LOGO); + fc_rport_state_enter(rdata, RPORT_ST_LOGO); fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo)); if (!fp) { - fc_rport_error_retry(rport, fp); + fc_rport_error_retry(rdata, fp); return; } - if (!lport->tt.elsct_send(lport, rport, fp, ELS_LOGO, - fc_rport_logo_resp, rport, lport->e_d_tov)) - fc_rport_error_retry(rport, fp); + if (!lport->tt.elsct_send(lport, rdata, fp, ELS_LOGO, + fc_rport_logo_resp, rdata, lport->e_d_tov)) + fc_rport_error_retry(rdata, fp); else get_device(&rport->dev); } @@ -899,16 +888,15 @@ static void fc_rport_enter_logo(struct fc_rport *rport) * fc_rport_recv_req() - Receive a request from a rport * @sp: current sequence in the PLOGI exchange * @fp: response frame - * @rp_arg: Fibre Channel remote port + * @rdata_arg: private remote port data * * Locking Note: Called without the rport lock held. This * function will hold the rport lock, call an _enter_* * function and then unlock the rport. */ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, - struct fc_rport *rport) + struct fc_rport_priv *rdata) { - struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; struct fc_frame_header *fh; @@ -927,16 +915,16 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, op = fc_frame_payload_op(fp); switch (op) { case ELS_PLOGI: - fc_rport_recv_plogi_req(rport, sp, fp); + fc_rport_recv_plogi_req(rdata, sp, fp); break; case ELS_PRLI: - fc_rport_recv_prli_req(rport, sp, fp); + fc_rport_recv_prli_req(rdata, sp, fp); break; case ELS_PRLO: - fc_rport_recv_prlo_req(rport, sp, fp); + fc_rport_recv_prlo_req(rdata, sp, fp); break; case ELS_LOGO: - fc_rport_recv_logo_req(rport, sp, fp); + fc_rport_recv_logo_req(rdata, sp, fp); break; case ELS_RRQ: els_data.fp = fp; @@ -958,17 +946,17 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, /** * fc_rport_recv_plogi_req() - Handle incoming Port Login (PLOGI) request - * @rport: Fibre Channel remote port that initiated PLOGI + * @rdata: private remote port data * @sp: current sequence in the PLOGI exchange * @fp: PLOGI request frame * * Locking Note: The rport lock is exected to be held before calling * this function. */ -static void fc_rport_recv_plogi_req(struct fc_rport *rport, +static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata, struct fc_seq *sp, struct fc_frame *rx_fp) { - struct fc_rport_priv *rdata = rport->dd_data; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_lport *lport = rdata->local_port; struct fc_frame *fp = rx_fp; struct fc_exch *ep; @@ -984,13 +972,13 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, fh = fc_frame_header_get(fp); - FC_RPORT_DBG(rport, "Received PLOGI request while in state %s\n", - fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Received PLOGI request while in state %s\n", + fc_rport_state(rdata)); sid = ntoh24(fh->fh_s_id); pl = fc_frame_payload_get(fp, sizeof(*pl)); if (!pl) { - FC_RPORT_DBG(rport, "Received PLOGI too short\n"); + FC_RPORT_DBG(rdata, "Received PLOGI too short\n"); WARN_ON(1); /* XXX TBD: send reject? */ fc_frame_free(fp); @@ -1012,25 +1000,25 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, */ switch (rdata->rp_state) { case RPORT_ST_INIT: - FC_RPORT_DBG(rport, "Received PLOGI, wwpn %llx state INIT " + FC_RPORT_DBG(rdata, "Received PLOGI, wwpn %llx state INIT " "- reject\n", (unsigned long long)wwpn); reject = ELS_RJT_UNSUP; break; case RPORT_ST_PLOGI: - FC_RPORT_DBG(rport, "Received PLOGI in PLOGI state %d\n", + FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state %d\n", rdata->rp_state); if (wwpn < lport->wwpn) reject = ELS_RJT_INPROG; break; case RPORT_ST_PRLI: case RPORT_ST_READY: - FC_RPORT_DBG(rport, "Received PLOGI in logged-in state %d " + FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d " "- ignored for now\n", rdata->rp_state); /* XXX TBD - should reset */ break; case RPORT_ST_DELETE: default: - FC_RPORT_DBG(rport, "Received PLOGI in unexpected " + FC_RPORT_DBG(rdata, "Received PLOGI in unexpected " "state %d\n", rdata->rp_state); fc_frame_free(fp); return; @@ -1074,24 +1062,24 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, FC_TYPE_ELS, f_ctl, 0); lport->tt.seq_send(lport, sp, fp); if (rdata->rp_state == RPORT_ST_PLOGI) - fc_rport_enter_prli(rport); + fc_rport_enter_prli(rdata); } } } /** * fc_rport_recv_prli_req() - Handle incoming Process Login (PRLI) request - * @rport: Fibre Channel remote port that initiated PRLI + * @rdata: private remote port data * @sp: current sequence in the PRLI exchange * @fp: PRLI request frame * * Locking Note: The rport lock is exected to be held before calling * this function. */ -static void fc_rport_recv_prli_req(struct fc_rport *rport, +static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, struct fc_seq *sp, struct fc_frame *rx_fp) { - struct fc_rport_priv *rdata = rport->dd_data; + struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_lport *lport = rdata->local_port; struct fc_exch *ep; struct fc_frame *fp; @@ -1115,8 +1103,8 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport, fh = fc_frame_header_get(rx_fp); - FC_RPORT_DBG(rport, "Received PRLI request while in state %s\n", - fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n", + fc_rport_state(rdata)); switch (rdata->rp_state) { case RPORT_ST_PRLI: @@ -1220,7 +1208,7 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport, */ switch (rdata->rp_state) { case RPORT_ST_PRLI: - fc_rport_enter_ready(rport); + fc_rport_enter_ready(rdata); break; case RPORT_ST_READY: break; @@ -1233,17 +1221,17 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport, /** * fc_rport_recv_prlo_req() - Handle incoming Process Logout (PRLO) request - * @rport: Fibre Channel remote port that initiated PRLO + * @rdata: private remote port data * @sp: current sequence in the PRLO exchange * @fp: PRLO request frame * * Locking Note: The rport lock is exected to be held before calling * this function. */ -static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp, +static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata, + struct fc_seq *sp, struct fc_frame *fp) { - struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; struct fc_frame_header *fh; @@ -1251,8 +1239,8 @@ static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp, fh = fc_frame_header_get(fp); - FC_RPORT_DBG(rport, "Received PRLO request while in state %s\n", - fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n", + fc_rport_state(rdata)); if (rdata->rp_state == RPORT_ST_DELETE) { fc_frame_free(fp); @@ -1268,24 +1256,24 @@ static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp, /** * fc_rport_recv_logo_req() - Handle incoming Logout (LOGO) request - * @rport: Fibre Channel remote port that initiated LOGO + * @rdata: private remote port data * @sp: current sequence in the LOGO exchange * @fp: LOGO request frame * * Locking Note: The rport lock is exected to be held before calling * this function. */ -static void fc_rport_recv_logo_req(struct fc_rport *rport, struct fc_seq *sp, +static void fc_rport_recv_logo_req(struct fc_rport_priv *rdata, + struct fc_seq *sp, struct fc_frame *fp) { struct fc_frame_header *fh; - struct fc_rport_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; fh = fc_frame_header_get(fp); - FC_RPORT_DBG(rport, "Received LOGO request while in state %s\n", - fc_rport_state(rport)); + FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n", + fc_rport_state(rdata)); if (rdata->rp_state == RPORT_ST_DELETE) { fc_frame_free(fp); @@ -1293,7 +1281,7 @@ static void fc_rport_recv_logo_req(struct fc_rport *rport, struct fc_seq *sp, } rdata->event = RPORT_EV_LOGO; - fc_rport_state_enter(rport, RPORT_ST_DELETE); + fc_rport_state_enter(rdata, RPORT_ST_DELETE); queue_work(rport_event_queue, &rdata->event_work); lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); -- cgit v1.2.3-18-g5258 From a46f327aa5caf2cce138e98ddd863b6cca0e71e2 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:00:55 -0700 Subject: [SCSI] libfc: change elsct to use FC_ID instead of rdata tt.elsct_send is used by both FCP and by the rport state machine. After further patches, these two modules will use different structures for the remote port. So, change elsct_send to use the FC_ID instead of the fc_rport_priv as its argument. It currently only uses the FC_ID anyway. For CT requests the destination FC_ID is still implicitly 0xfffffc. After further patches the did arg on CT requests will be used to specify the FC_ID being inquired about for GPN_ID or other queries. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 2 +- drivers/scsi/libfc/fc_elsct.c | 11 ++++++----- drivers/scsi/libfc/fc_fcp.c | 2 +- drivers/scsi/libfc/fc_lport.c | 12 ++++++------ drivers/scsi/libfc/fc_rport.c | 8 ++++---- 5 files changed, 18 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 448ffc38865..4b1f9faf639 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -526,7 +526,7 @@ static void fc_disc_gpn_ft_req(struct fc_disc *disc) if (!fp) goto err; - if (lport->tt.elsct_send(lport, NULL, fp, + if (lport->tt.elsct_send(lport, 0, fp, FC_NS_GPN_FT, fc_disc_gpn_ft_resp, disc, lport->e_d_tov)) diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c index 2b8a3bbc039..5e8b011af50 100644 --- a/drivers/scsi/libfc/fc_elsct.c +++ b/drivers/scsi/libfc/fc_elsct.c @@ -32,7 +32,7 @@ * fc_elsct_send - sends ELS/CT frame */ static struct fc_seq *fc_elsct_send(struct fc_lport *lport, - struct fc_rport_priv *rdata, + u32 did, struct fc_frame *fp, unsigned int op, void (*resp)(struct fc_seq *, @@ -41,16 +41,17 @@ static struct fc_seq *fc_elsct_send(struct fc_lport *lport, void *arg, u32 timer_msec) { enum fc_rctl r_ctl; - u32 did = FC_FID_NONE; enum fc_fh_type fh_type; int rc; /* ELS requests */ if ((op >= ELS_LS_RJT) && (op <= ELS_AUTH_ELS)) - rc = fc_els_fill(lport, rdata, fp, op, &r_ctl, &did, &fh_type); - else + rc = fc_els_fill(lport, did, fp, op, &r_ctl, &fh_type); + else { /* CT requests */ - rc = fc_ct_fill(lport, fp, op, &r_ctl, &did, &fh_type); + rc = fc_ct_fill(lport, fp, op, &r_ctl, &fh_type); + did = FC_FID_DIR_SERV; + } if (rc) return NULL; diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index a622096eb31..59a4408b27b 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -1308,7 +1308,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp) fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rport->port_id, fc_host_port_id(rp->local_port->host), FC_TYPE_ELS, FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); - if (lp->tt.elsct_send(lp, rport->dd_data, fp, ELS_REC, fc_fcp_rec_resp, + if (lp->tt.elsct_send(lp, rport->port_id, fp, ELS_REC, fc_fcp_rec_resp, fsp, jiffies_to_msecs(FC_SCSI_REC_TOV))) { fc_fcp_pkt_hold(fsp); /* hold while REC outstanding */ return; diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 3c15abd35ff..aa605d2012e 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -1217,7 +1217,7 @@ static void fc_lport_enter_scr(struct fc_lport *lport) return; } - if (!lport->tt.elsct_send(lport, NULL, fp, ELS_SCR, + if (!lport->tt.elsct_send(lport, FC_FID_FCTRL, fp, ELS_SCR, fc_lport_scr_resp, lport, lport->e_d_tov)) fc_lport_error(lport, fp); } @@ -1258,7 +1258,7 @@ static void fc_lport_enter_rft_id(struct fc_lport *lport) return; } - if (!lport->tt.elsct_send(lport, NULL, fp, FC_NS_RFT_ID, + if (!lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, FC_NS_RFT_ID, fc_lport_rft_id_resp, lport, lport->e_d_tov)) fc_lport_error(lport, fp); @@ -1287,7 +1287,7 @@ static void fc_lport_enter_rpn_id(struct fc_lport *lport) return; } - if (!lport->tt.elsct_send(lport, NULL, fp, FC_NS_RPN_ID, + if (!lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, FC_NS_RPN_ID, fc_lport_rpn_id_resp, lport, lport->e_d_tov)) fc_lport_error(lport, fp); @@ -1443,8 +1443,8 @@ static void fc_lport_enter_logo(struct fc_lport *lport) return; } - if (!lport->tt.elsct_send(lport, NULL, fp, ELS_LOGO, fc_lport_logo_resp, - lport, lport->e_d_tov)) + if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp, ELS_LOGO, + fc_lport_logo_resp, lport, lport->e_d_tov)) fc_lport_error(lport, fp); } @@ -1567,7 +1567,7 @@ void fc_lport_enter_flogi(struct fc_lport *lport) if (!fp) return fc_lport_error(lport, fp); - if (!lport->tt.elsct_send(lport, NULL, fp, ELS_FLOGI, + if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp, ELS_FLOGI, fc_lport_flogi_resp, lport, lport->e_d_tov)) fc_lport_error(lport, fp); } diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 13d3d758fb0..20371b445bb 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -593,7 +593,7 @@ static void fc_rport_enter_plogi(struct fc_rport_priv *rdata) } rdata->e_d_tov = lport->e_d_tov; - if (!lport->tt.elsct_send(lport, rdata, fp, ELS_PLOGI, + if (!lport->tt.elsct_send(lport, rport->port_id, fp, ELS_PLOGI, fc_rport_plogi_resp, rdata, lport->e_d_tov)) fc_rport_error_retry(rdata, fp); else @@ -747,7 +747,7 @@ static void fc_rport_enter_prli(struct fc_rport_priv *rdata) return; } - if (!lport->tt.elsct_send(lport, rdata, fp, ELS_PRLI, + if (!lport->tt.elsct_send(lport, rport->port_id, fp, ELS_PRLI, fc_rport_prli_resp, rdata, lport->e_d_tov)) fc_rport_error_retry(rdata, fp); else @@ -845,7 +845,7 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *rdata) return; } - if (!lport->tt.elsct_send(lport, rdata, fp, ELS_RTV, + if (!lport->tt.elsct_send(lport, rport->port_id, fp, ELS_RTV, fc_rport_rtv_resp, rdata, lport->e_d_tov)) fc_rport_error_retry(rdata, fp); else @@ -876,7 +876,7 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata) return; } - if (!lport->tt.elsct_send(lport, rdata, fp, ELS_LOGO, + if (!lport->tt.elsct_send(lport, rport->port_id, fp, ELS_LOGO, fc_rport_logo_resp, rdata, lport->e_d_tov)) fc_rport_error_retry(rdata, fp); else -- cgit v1.2.3-18-g5258 From f211fa514a07326c0f9364c0e6ed17e38860172f Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:01:01 -0700 Subject: [SCSI] libfc: make rport structure optional Allow a struct fc_rport_priv to have no fc_rport associated with it. This sets up to remove the need for "rogue" rports. Add a few fields to fc_rport_priv that are needed before the fc_rport is created. These are the ids, maxframe_size, classes, and rport pointer. Remove the macro PRIV_TO_RPORT(). Just use rdata->rport where appropriate. To take the place of the get_device()/put_device ops that were used to hold both the rport and rdata, add a reference count to rdata structures using kref. When kref_get decrements the refcount to zero, a new template function releasing the rdata should be called. This will take care of freeing the rdata and releasing the hold on the rport (for now). After subsequent patches make the rport truly optional, this release function will simply free the rdata. Remove the simple inline function fc_rport_set_name(), which becomes semanticly ambiguous otherwise. The caller will set the port_name and node_name in the rdata->Ids, which will later be copied to the rport when it its created. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 54 ++++++++-------------- drivers/scsi/libfc/fc_lport.c | 14 +++--- drivers/scsi/libfc/fc_rport.c | 102 +++++++++++++++++++++++------------------- 3 files changed, 82 insertions(+), 88 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 4b1f9faf639..5f839b625e5 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -47,7 +47,7 @@ static void fc_disc_gpn_ft_req(struct fc_disc *); static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); -static int fc_disc_new_target(struct fc_disc *, struct fc_rport *, +static int fc_disc_new_target(struct fc_disc *, struct fc_rport_priv *, struct fc_rport_identifiers *); static void fc_disc_done(struct fc_disc *); static void fc_disc_timeout(struct work_struct *); @@ -63,12 +63,10 @@ struct fc_rport_priv *fc_disc_lookup_rport(const struct fc_lport *lport, u32 port_id) { const struct fc_disc *disc = &lport->disc; - struct fc_rport *rport; struct fc_rport_priv *rdata; list_for_each_entry(rdata, &disc->rports, peers) { - rport = PRIV_TO_RPORT(rdata); - if (rport->port_id == port_id) + if (rdata->ids.port_id == port_id) return rdata; } return NULL; @@ -115,10 +113,9 @@ static void fc_disc_rport_callback(struct fc_lport *lport, enum fc_rport_event event) { struct fc_disc *disc = &lport->disc; - struct fc_rport *rport = PRIV_TO_RPORT(rdata); FC_DISC_DBG(disc, "Received a %d event for port (%6x)\n", event, - rport->port_id); + rdata->ids.port_id); switch (event) { case RPORT_EV_CREATED: @@ -320,8 +317,6 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, struct fc_lport *lport) { struct fc_rport_priv *rdata; - struct fc_rport *rport; - struct fc_rport_identifiers ids; struct fc_disc *disc = &lport->disc; /* @@ -349,18 +344,12 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, */ rdata = disc->lport->ptp_rp; if (rdata) { - rport = PRIV_TO_RPORT(rdata); - ids.port_id = rport->port_id; - ids.port_name = rport->port_name; - ids.node_name = rport->node_name; - ids.roles = FC_RPORT_ROLE_UNKNOWN; - get_device(&rport->dev); - - if (!fc_disc_new_target(disc, rport, &ids)) { + kref_get(&rdata->kref); + if (!fc_disc_new_target(disc, rdata, &rdata->ids)) { disc->event = DISC_EV_SUCCESS; fc_disc_done(disc); } - put_device(&rport->dev); + kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); } else { fc_disc_gpn_ft_req(disc); /* get ports by FC-4 type */ } @@ -375,28 +364,27 @@ static struct fc_rport_operations fc_disc_rport_ops = { /** * fc_disc_new_target() - Handle new target found by discovery * @lport: FC local port - * @rport: The previous FC remote port (NULL if new remote port) + * @rdata: The previous FC remote port priv (NULL if new remote port) * @ids: Identifiers for the new FC remote port * * Locking Note: This function expects that the disc_mutex is locked * before it is called. */ static int fc_disc_new_target(struct fc_disc *disc, - struct fc_rport *rport, + struct fc_rport_priv *rdata, struct fc_rport_identifiers *ids) { struct fc_lport *lport = disc->lport; - struct fc_rport_priv *rdata; int error = 0; - if (rport && ids->port_name) { - if (rport->port_name == -1) { + if (rdata && ids->port_name) { + if (rdata->ids.port_name == -1) { /* * Set WWN and fall through to notify of create. */ - fc_rport_set_name(rport, ids->port_name, - rport->node_name); - } else if (rport->port_name != ids->port_name) { + rdata->ids.port_name = ids->port_name; + rdata->ids.node_name = ids->node_name; + } else if (rdata->ids.port_name != ids->port_name) { /* * This is a new port with the same FCID as * a previously-discovered port. Presumably the old @@ -404,27 +392,23 @@ static int fc_disc_new_target(struct fc_disc *disc, * assigned the same FCID. This should be rare. * Delete the old one and fall thru to re-create. */ - rdata = rport->dd_data; list_del(&rdata->peers); lport->tt.rport_logoff(rdata); - rport = NULL; + rdata = NULL; } } if (((ids->port_name != -1) || (ids->port_id != -1)) && ids->port_id != fc_host_port_id(lport->host) && ids->port_name != lport->wwpn) { - if (!rport) { + if (!rdata) { rdata = lport->tt.rport_lookup(lport, ids->port_id); - if (!rport) { + if (!rdata) { rdata = lport->tt.rport_create(lport, ids); + if (!rdata) + error = -ENOMEM; } - if (!rdata) - error = -ENOMEM; - else - rport = PRIV_TO_RPORT(rdata); } - if (rport) { - rdata = rport->dd_data; + if (rdata) { rdata->ops = &fc_disc_rport_ops; rdata->rp_state = RPORT_ST_INIT; list_add_tail(&rdata->peers, &disc->rogue_rports); diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index aa605d2012e..a7fe6b8d38b 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -143,14 +143,12 @@ static void fc_lport_rport_callback(struct fc_lport *lport, struct fc_rport_priv *rdata, enum fc_rport_event event) { - struct fc_rport *rport = PRIV_TO_RPORT(rdata); - FC_LPORT_DBG(lport, "Received a %d event for port (%6x)\n", event, - rport->port_id); + rdata->ids.port_id); switch (event) { case RPORT_EV_CREATED: - if (rport->port_id == FC_FID_DIR_SERV) { + if (rdata->ids.port_id == FC_FID_DIR_SERV) { mutex_lock(&lport->lp_mutex); if (lport->state == LPORT_ST_DNS) { lport->dns_rp = rdata; @@ -160,7 +158,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport, "on port (%6x) for the directory " "server, but the lport is not " "in the DNS state, it's in the " - "%d state", rport->port_id, + "%d state", rdata->ids.port_id, lport->state); lport->tt.rport_logoff(rdata); } @@ -168,12 +166,12 @@ static void fc_lport_rport_callback(struct fc_lport *lport, } else FC_LPORT_DBG(lport, "Received an event for port (%6x) " "which is not the directory server\n", - rport->port_id); + rdata->ids.port_id); break; case RPORT_EV_LOGO: case RPORT_EV_FAILED: case RPORT_EV_STOP: - if (rport->port_id == FC_FID_DIR_SERV) { + if (rdata->ids.port_id == FC_FID_DIR_SERV) { mutex_lock(&lport->lp_mutex); lport->dns_rp = NULL; mutex_unlock(&lport->lp_mutex); @@ -181,7 +179,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport, } else FC_LPORT_DBG(lport, "Received an event for port (%6x) " "which is not the directory server\n", - rport->port_id); + rdata->ids.port_id); break; case RPORT_EV_NONE: break; diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 20371b445bb..69f6e588d37 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -120,7 +120,10 @@ struct fc_rport_priv *fc_rport_rogue_create(struct fc_lport *lport, device_initialize(&rport->dev); rport->dev.release = fc_rport_rogue_destroy; + rdata->ids = *ids; + kref_init(&rdata->kref); mutex_init(&rdata->rp_mutex); + rdata->rport = rport; rdata->local_port = lport; rdata->trans_state = FC_PORTSTATE_ROGUE; rdata->rp_state = RPORT_ST_INIT; @@ -129,6 +132,7 @@ struct fc_rport_priv *fc_rport_rogue_create(struct fc_lport *lport, rdata->ops = NULL; rdata->e_d_tov = lport->e_d_tov; rdata->r_a_tov = lport->r_a_tov; + rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); INIT_WORK(&rdata->event_work, fc_rport_work); /* @@ -140,6 +144,20 @@ struct fc_rport_priv *fc_rport_rogue_create(struct fc_lport *lport, return rdata; } +/** + * fc_rport_destroy() - free a remote port after last reference is released. + * @kref: pointer to kref inside struct fc_rport_priv + */ +static void fc_rport_destroy(struct kref *kref) +{ + struct fc_rport_priv *rdata; + struct fc_rport *rport; + + rdata = container_of(kref, struct fc_rport_priv, kref); + rport = rdata->rport; + put_device(&rport->dev); +} + /** * fc_rport_state() - return a string for the state the rport is in * @rdata: remote port private data @@ -215,22 +233,19 @@ static void fc_rport_work(struct work_struct *work) enum fc_rport_trans_state trans_state; struct fc_lport *lport = rdata->local_port; struct fc_rport_operations *rport_ops; - struct fc_rport *rport = PRIV_TO_RPORT(rdata); + struct fc_rport *rport; mutex_lock(&rdata->rp_mutex); event = rdata->event; rport_ops = rdata->ops; + rport = rdata->rport; if (event == RPORT_EV_CREATED) { struct fc_rport *new_rport; struct fc_rport_priv *new_rdata; struct fc_rport_identifiers ids; - ids.port_id = rport->port_id; - ids.roles = rport->roles; - ids.port_name = rport->port_name; - ids.node_name = rport->node_name; - + ids = rdata->ids; rdata->event = RPORT_EV_NONE; mutex_unlock(&rdata->rp_mutex); @@ -240,15 +255,20 @@ static void fc_rport_work(struct work_struct *work) * Switch from the rogue rport to the rport * returned by the FC class. */ - new_rport->maxframe_size = rport->maxframe_size; + new_rport->maxframe_size = rdata->maxframe_size; new_rdata = new_rport->dd_data; + new_rdata->rport = new_rport; + new_rdata->ids = ids; new_rdata->e_d_tov = rdata->e_d_tov; new_rdata->r_a_tov = rdata->r_a_tov; new_rdata->ops = rdata->ops; new_rdata->local_port = rdata->local_port; new_rdata->flags = FC_RP_FLAGS_REC_SUPPORTED; new_rdata->trans_state = FC_PORTSTATE_REAL; + new_rdata->maxframe_size = rdata->maxframe_size; + new_rdata->supported_classes = rdata->supported_classes; + kref_init(&new_rdata->kref); mutex_init(&new_rdata->rp_mutex); INIT_DELAYED_WORK(&new_rdata->retry_work, fc_rport_timeout); @@ -261,12 +281,11 @@ static void fc_rport_work(struct work_struct *work) " memory for rport (%6x)\n", ids.port_id); event = RPORT_EV_FAILED; } - if (rport->port_id != FC_FID_DIR_SERV) + if (rdata->ids.port_id != FC_FID_DIR_SERV) if (rport_ops->event_callback) rport_ops->event_callback(lport, rdata, RPORT_EV_FAILED); - put_device(&rport->dev); - rport = new_rport; + kref_put(&rdata->kref, lport->tt.rport_destroy); rdata = new_rport->dd_data; if (rport_ops->event_callback) rport_ops->event_callback(lport, rdata, event); @@ -279,7 +298,7 @@ static void fc_rport_work(struct work_struct *work) rport_ops->event_callback(lport, rdata, event); cancel_delayed_work_sync(&rdata->retry_work); if (trans_state == FC_PORTSTATE_ROGUE) - put_device(&rport->dev); + kref_put(&rdata->kref, lport->tt.rport_destroy); else { port_id = rport->port_id; fc_remote_port_delete(rport); @@ -505,7 +524,6 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, void *rdata_arg) { struct fc_rport_priv *rdata = rdata_arg; - struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_lport *lport = rdata->local_port; struct fc_els_flogi *plp = NULL; unsigned int tov; @@ -533,8 +551,8 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, op = fc_frame_payload_op(fp); if (op == ELS_LS_ACC && (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) { - rport->port_name = get_unaligned_be64(&plp->fl_wwpn); - rport->node_name = get_unaligned_be64(&plp->fl_wwnn); + rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn); + rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn); tov = ntohl(plp->fl_csp.sp_e_d_tov); if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR) @@ -546,14 +564,13 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, if (cssp_seq < csp_seq) csp_seq = cssp_seq; rdata->max_seq = csp_seq; - rport->maxframe_size = - fc_plogi_get_maxframe(plp, lport->mfs); + rdata->maxframe_size = fc_plogi_get_maxframe(plp, lport->mfs); /* * If the rport is one of the well known addresses * we skip PRLI and RTV and go straight to READY. */ - if (rport->port_id >= FC_FID_DOM_MGR) + if (rdata->ids.port_id >= FC_FID_DOM_MGR) fc_rport_enter_ready(rdata); else fc_rport_enter_prli(rdata); @@ -564,7 +581,7 @@ out: fc_frame_free(fp); err: mutex_unlock(&rdata->rp_mutex); - put_device(&rport->dev); + kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); } /** @@ -577,7 +594,6 @@ err: static void fc_rport_enter_plogi(struct fc_rport_priv *rdata) { struct fc_lport *lport = rdata->local_port; - struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_frame *fp; FC_RPORT_DBG(rdata, "Port entered PLOGI state from %s state\n", @@ -585,7 +601,7 @@ static void fc_rport_enter_plogi(struct fc_rport_priv *rdata) fc_rport_state_enter(rdata, RPORT_ST_PLOGI); - rport->maxframe_size = FC_MIN_MAX_PAYLOAD; + rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); if (!fp) { fc_rport_error_retry(rdata, fp); @@ -593,11 +609,11 @@ static void fc_rport_enter_plogi(struct fc_rport_priv *rdata) } rdata->e_d_tov = lport->e_d_tov; - if (!lport->tt.elsct_send(lport, rport->port_id, fp, ELS_PLOGI, + if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PLOGI, fc_rport_plogi_resp, rdata, lport->e_d_tov)) fc_rport_error_retry(rdata, fp); else - get_device(&rport->dev); + kref_get(&rdata->kref); } /** @@ -614,7 +630,6 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, void *rdata_arg) { struct fc_rport_priv *rdata = rdata_arg; - struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct { struct fc_els_prli prli; struct fc_els_spp spp; @@ -649,13 +664,13 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, rdata->flags |= FC_RP_FLAGS_RETRY; } - rport->supported_classes = FC_COS_CLASS3; + rdata->supported_classes = FC_COS_CLASS3; if (fcp_parm & FCP_SPPF_INIT_FCN) roles |= FC_RPORT_ROLE_FCP_INITIATOR; if (fcp_parm & FCP_SPPF_TARG_FCN) roles |= FC_RPORT_ROLE_FCP_TARGET; - rport->roles = roles; + rdata->ids.roles = roles; fc_rport_enter_rtv(rdata); } else { @@ -667,7 +682,7 @@ out: fc_frame_free(fp); err: mutex_unlock(&rdata->rp_mutex); - put_device(&rport->dev); + kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); } /** @@ -684,7 +699,6 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, void *rdata_arg) { struct fc_rport_priv *rdata = rdata_arg; - struct fc_rport *rport = PRIV_TO_RPORT(rdata); u8 op; mutex_lock(&rdata->rp_mutex); @@ -716,7 +730,7 @@ out: fc_frame_free(fp); err: mutex_unlock(&rdata->rp_mutex); - put_device(&rport->dev); + kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); } /** @@ -728,7 +742,6 @@ err: */ static void fc_rport_enter_prli(struct fc_rport_priv *rdata) { - struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_lport *lport = rdata->local_port; struct { struct fc_els_prli prli; @@ -747,11 +760,11 @@ static void fc_rport_enter_prli(struct fc_rport_priv *rdata) return; } - if (!lport->tt.elsct_send(lport, rport->port_id, fp, ELS_PRLI, + if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PRLI, fc_rport_prli_resp, rdata, lport->e_d_tov)) fc_rport_error_retry(rdata, fp); else - get_device(&rport->dev); + kref_get(&rdata->kref); } /** @@ -770,7 +783,6 @@ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, void *rdata_arg) { struct fc_rport_priv *rdata = rdata_arg; - struct fc_rport *rport = PRIV_TO_RPORT(rdata); u8 op; mutex_lock(&rdata->rp_mutex); @@ -818,7 +830,7 @@ out: fc_frame_free(fp); err: mutex_unlock(&rdata->rp_mutex); - put_device(&rport->dev); + kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); } /** @@ -832,7 +844,6 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *rdata) { struct fc_frame *fp; struct fc_lport *lport = rdata->local_port; - struct fc_rport *rport = PRIV_TO_RPORT(rdata); FC_RPORT_DBG(rdata, "Port entered RTV state from %s state\n", fc_rport_state(rdata)); @@ -845,11 +856,11 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *rdata) return; } - if (!lport->tt.elsct_send(lport, rport->port_id, fp, ELS_RTV, + if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_RTV, fc_rport_rtv_resp, rdata, lport->e_d_tov)) fc_rport_error_retry(rdata, fp); else - get_device(&rport->dev); + kref_get(&rdata->kref); } /** @@ -862,7 +873,6 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *rdata) static void fc_rport_enter_logo(struct fc_rport_priv *rdata) { struct fc_lport *lport = rdata->local_port; - struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_frame *fp; FC_RPORT_DBG(rdata, "Port entered LOGO state from %s state\n", @@ -876,11 +886,11 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata) return; } - if (!lport->tt.elsct_send(lport, rport->port_id, fp, ELS_LOGO, + if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO, fc_rport_logo_resp, rdata, lport->e_d_tov)) fc_rport_error_retry(rdata, fp); else - get_device(&rport->dev); + kref_get(&rdata->kref); } @@ -956,7 +966,6 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata, struct fc_seq *sp, struct fc_frame *rx_fp) { - struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_lport *lport = rdata->local_port; struct fc_frame *fp = rx_fp; struct fc_exch *ep; @@ -1041,12 +1050,13 @@ static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata, } else { sp = lport->tt.seq_start_next(sp); WARN_ON(!sp); - fc_rport_set_name(rport, wwpn, wwnn); + rdata->ids.port_name = wwpn; + rdata->ids.node_name = wwnn; /* * Get session payload size from incoming PLOGI. */ - rport->maxframe_size = + rdata->maxframe_size = fc_plogi_get_maxframe(pl, lport->mfs); fc_frame_free(rx_fp); fc_plogi_fill(lport, fp, ELS_LS_ACC); @@ -1079,7 +1089,6 @@ static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata, static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, struct fc_seq *sp, struct fc_frame *rx_fp) { - struct fc_rport *rport = PRIV_TO_RPORT(rdata); struct fc_lport *lport = rdata->local_port; struct fc_exch *ep; struct fc_frame *fp; @@ -1173,12 +1182,12 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, fcp_parm = ntohl(rspp->spp_params); if (fcp_parm * FCP_SPPF_RETRY) rdata->flags |= FC_RP_FLAGS_RETRY; - rport->supported_classes = FC_COS_CLASS3; + rdata->supported_classes = FC_COS_CLASS3; if (fcp_parm & FCP_SPPF_INIT_FCN) roles |= FC_RPORT_ROLE_FCP_INITIATOR; if (fcp_parm & FCP_SPPF_TARG_FCN) roles |= FC_RPORT_ROLE_FCP_TARGET; - rport->roles = roles; + rdata->ids.roles = roles; spp->spp_params = htonl(lport->service_params); @@ -1310,6 +1319,9 @@ int fc_rport_init(struct fc_lport *lport) if (!lport->tt.rport_flush_queue) lport->tt.rport_flush_queue = fc_rport_flush_queue; + if (!lport->tt.rport_destroy) + lport->tt.rport_destroy = fc_rport_destroy; + return 0; } EXPORT_SYMBOL(fc_rport_init); -- cgit v1.2.3-18-g5258 From 629f44279d169f29b084d406e9f1c33314f220fa Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:01:06 -0700 Subject: [SCSI] libfc: rearrange code in fc_rport_work This is a cleanup without semantic changes to use a switch statement instead of a series of if-statements in fc_rport_work(), and to move some declarations up to the top. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 69f6e588d37..d0a45425cc3 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -233,6 +233,9 @@ static void fc_rport_work(struct work_struct *work) enum fc_rport_trans_state trans_state; struct fc_lport *lport = rdata->local_port; struct fc_rport_operations *rport_ops; + struct fc_rport *new_rport; + struct fc_rport_priv *new_rdata; + struct fc_rport_identifiers ids; struct fc_rport *rport; mutex_lock(&rdata->rp_mutex); @@ -240,11 +243,8 @@ static void fc_rport_work(struct work_struct *work) rport_ops = rdata->ops; rport = rdata->rport; - if (event == RPORT_EV_CREATED) { - struct fc_rport *new_rport; - struct fc_rport_priv *new_rdata; - struct fc_rport_identifiers ids; - + switch (event) { + case RPORT_EV_CREATED: ids = rdata->ids; rdata->event = RPORT_EV_NONE; mutex_unlock(&rdata->rp_mutex); @@ -289,9 +289,11 @@ static void fc_rport_work(struct work_struct *work) rdata = new_rport->dd_data; if (rport_ops->event_callback) rport_ops->event_callback(lport, rdata, event); - } else if ((event == RPORT_EV_FAILED) || - (event == RPORT_EV_LOGO) || - (event == RPORT_EV_STOP)) { + break; + + case RPORT_EV_FAILED: + case RPORT_EV_LOGO: + case RPORT_EV_STOP: trans_state = rdata->trans_state; mutex_unlock(&rdata->rp_mutex); if (rport_ops->event_callback) @@ -305,8 +307,12 @@ static void fc_rport_work(struct work_struct *work) lport->tt.exch_mgr_reset(lport, 0, port_id); lport->tt.exch_mgr_reset(lport, port_id, 0); } - } else + break; + + default: mutex_unlock(&rdata->rp_mutex); + break; + } } /** -- cgit v1.2.3-18-g5258 From 4c0f62b5679321b2e5572cf541ffb9f7b344d47c Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:01:12 -0700 Subject: [SCSI] libfc: rename rport event CREATED to READY Remote ports will become READY more than once after ADISC is implemented in a later patch. The event callback that has been called "CREATED" will mean "READY". Rename it now in preparation for those changes. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 2 +- drivers/scsi/libfc/fc_lport.c | 4 ++-- drivers/scsi/libfc/fc_rport.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 5f839b625e5..e5e5b260a57 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -118,7 +118,7 @@ static void fc_disc_rport_callback(struct fc_lport *lport, rdata->ids.port_id); switch (event) { - case RPORT_EV_CREATED: + case RPORT_EV_READY: if (disc) { mutex_lock(&disc->disc_mutex); list_add_tail(&rdata->peers, &disc->rports); diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index a7fe6b8d38b..016f771ebe6 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -147,14 +147,14 @@ static void fc_lport_rport_callback(struct fc_lport *lport, rdata->ids.port_id); switch (event) { - case RPORT_EV_CREATED: + case RPORT_EV_READY: if (rdata->ids.port_id == FC_FID_DIR_SERV) { mutex_lock(&lport->lp_mutex); if (lport->state == LPORT_ST_DNS) { lport->dns_rp = rdata; fc_lport_enter_rpn_id(lport); } else { - FC_LPORT_DBG(lport, "Received an CREATED event " + FC_LPORT_DBG(lport, "Received an READY event " "on port (%6x) for the directory " "server, but the lport is not " "in the DNS state, it's in the " diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index d0a45425cc3..50959ba0a9a 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -244,7 +244,7 @@ static void fc_rport_work(struct work_struct *work) rport = rdata->rport; switch (event) { - case RPORT_EV_CREATED: + case RPORT_EV_READY: ids = rdata->ids; rdata->event = RPORT_EV_NONE; mutex_unlock(&rdata->rp_mutex); @@ -413,7 +413,7 @@ static void fc_rport_enter_ready(struct fc_rport_priv *rdata) if (rdata->event == RPORT_EV_NONE) queue_work(rport_event_queue, &rdata->event_work); - rdata->event = RPORT_EV_CREATED; + rdata->event = RPORT_EV_READY; } /** -- cgit v1.2.3-18-g5258 From 9e9d0452fe12115b1c1883c0d4d2ee509079791b Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:01:18 -0700 Subject: [SCSI] libfc: don't create dummy (rogue) remote ports Don't create a "dummy" remote port to go with fc_rport_priv. Make the rport truly optional by allocating fc_rport_priv separately and not requiring a dummy rport to be there if we haven't yet done fc_remote_port_add(). The fc_rport_libfc_priv remains as a structure attached to the rport for I/O purposes. Be sure to hold references on rdata when the lock is dropped in fc_rport_work(). Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 40 +++-------- drivers/scsi/libfc/fc_rport.c | 154 +++++++++++++++++------------------------- 2 files changed, 73 insertions(+), 121 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index e5e5b260a57..bbea41e50a5 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -66,7 +66,8 @@ struct fc_rport_priv *fc_disc_lookup_rport(const struct fc_lport *lport, struct fc_rport_priv *rdata; list_for_each_entry(rdata, &disc->rports, peers) { - if (rdata->ids.port_id == port_id) + if (rdata->ids.port_id == port_id && + rdata->rp_state != RPORT_ST_DELETE) return rdata; } return NULL; @@ -87,15 +88,8 @@ void fc_disc_stop_rports(struct fc_disc *disc) lport = disc->lport; mutex_lock(&disc->disc_mutex); - list_for_each_entry_safe(rdata, next, &disc->rports, peers) { - list_del(&rdata->peers); + list_for_each_entry_safe(rdata, next, &disc->rports, peers) lport->tt.rport_logoff(rdata); - } - - list_for_each_entry_safe(rdata, next, &disc->rogue_rports, peers) { - lport->tt.rport_logoff(rdata); - } - mutex_unlock(&disc->disc_mutex); } @@ -119,20 +113,12 @@ static void fc_disc_rport_callback(struct fc_lport *lport, switch (event) { case RPORT_EV_READY: - if (disc) { - mutex_lock(&disc->disc_mutex); - list_add_tail(&rdata->peers, &disc->rports); - mutex_unlock(&disc->disc_mutex); - } break; case RPORT_EV_LOGO: case RPORT_EV_FAILED: case RPORT_EV_STOP: mutex_lock(&disc->disc_mutex); - mutex_lock(&rdata->rp_mutex); - if (rdata->trans_state == FC_PORTSTATE_ROGUE) - list_del(&rdata->peers); - mutex_unlock(&rdata->rp_mutex); + list_del(&rdata->peers); mutex_unlock(&disc->disc_mutex); break; default: @@ -235,7 +221,6 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, list_del(&dp->peers); rdata = lport->tt.rport_lookup(lport, dp->ids.port_id); if (rdata) { - list_del(&rdata->peers); lport->tt.rport_logoff(rdata); } fc_disc_single(disc, dp); @@ -296,10 +281,8 @@ static void fc_disc_restart(struct fc_disc *disc) FC_DISC_DBG(disc, "Restarting discovery\n"); - list_for_each_entry_safe(rdata, next, &disc->rports, peers) { - list_del(&rdata->peers); + list_for_each_entry_safe(rdata, next, &disc->rports, peers) lport->tt.rport_logoff(rdata); - } disc->requested = 1; if (!disc->pending) @@ -392,7 +375,6 @@ static int fc_disc_new_target(struct fc_disc *disc, * assigned the same FCID. This should be rare. * Delete the old one and fall thru to re-create. */ - list_del(&rdata->peers); lport->tt.rport_logoff(rdata); rdata = NULL; } @@ -406,12 +388,13 @@ static int fc_disc_new_target(struct fc_disc *disc, rdata = lport->tt.rport_create(lport, ids); if (!rdata) error = -ENOMEM; + else + list_add_tail(&rdata->peers, + &disc->rports); } } if (rdata) { rdata->ops = &fc_disc_rport_ops; - rdata->rp_state = RPORT_ST_INIT; - list_add_tail(&rdata->peers, &disc->rogue_rports); lport->tt.rport_login(rdata); } } @@ -585,9 +568,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) rdata = lport->tt.rport_create(lport, &ids); if (rdata) { rdata->ops = &fc_disc_rport_ops; - rdata->local_port = lport; - list_add_tail(&rdata->peers, - &disc->rogue_rports); + list_add_tail(&rdata->peers, &disc->rports); lport->tt.rport_login(rdata); } else printk(KERN_WARNING "libfc: Failed to allocate " @@ -736,7 +717,7 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) if (rdata) { rdata->ops = &fc_disc_rport_ops; kfree(dp); - list_add_tail(&rdata->peers, &disc->rogue_rports); + list_add_tail(&rdata->peers, &disc->rports); lport->tt.rport_login(rdata); } return; @@ -798,7 +779,6 @@ int fc_disc_init(struct fc_lport *lport) INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout); mutex_init(&disc->disc_mutex); INIT_LIST_HEAD(&disc->rports); - INIT_LIST_HEAD(&disc->rogue_rports); disc->lport = lport; disc->delay = FC_DISC_DELAY; diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 50959ba0a9a..a1794a39158 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -86,61 +86,35 @@ static const char *fc_rport_state_names[] = { [RPORT_ST_DELETE] = "Delete", }; -static void fc_rport_rogue_destroy(struct device *dev) -{ - struct fc_rport *rport = dev_to_rport(dev); - struct fc_rport_priv *rdata = RPORT_TO_PRIV(rport); - - FC_RPORT_DBG(rdata, "Destroying rogue rport\n"); - kfree(rport); -} - -struct fc_rport_priv *fc_rport_rogue_create(struct fc_lport *lport, - struct fc_rport_identifiers *ids) +/** + * fc_rport_create() - create remote port in INIT state. + * @lport: local port. + * @ids: remote port identifiers. + * + * Locking note: this may be called without locks held, but + * is usually called from discovery with the disc_mutex held. + */ +static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, + struct fc_rport_identifiers *ids) { - struct fc_rport *rport; struct fc_rport_priv *rdata; - rport = kzalloc(sizeof(*rport) + sizeof(*rdata), GFP_KERNEL); - if (!rport) + rdata = kzalloc(sizeof(*rdata), GFP_KERNEL); + if (!rdata) return NULL; - rdata = RPORT_TO_PRIV(rport); - - rport->dd_data = rdata; - rport->port_id = ids->port_id; - rport->port_name = ids->port_name; - rport->node_name = ids->node_name; - rport->roles = ids->roles; - rport->maxframe_size = FC_MIN_MAX_PAYLOAD; - /* - * Note: all this libfc rogue rport code will be removed for - * upstream so it fine that this is really ugly and hacky right now. - */ - device_initialize(&rport->dev); - rport->dev.release = fc_rport_rogue_destroy; - rdata->ids = *ids; kref_init(&rdata->kref); mutex_init(&rdata->rp_mutex); - rdata->rport = rport; rdata->local_port = lport; - rdata->trans_state = FC_PORTSTATE_ROGUE; rdata->rp_state = RPORT_ST_INIT; rdata->event = RPORT_EV_NONE; rdata->flags = FC_RP_FLAGS_REC_SUPPORTED; - rdata->ops = NULL; rdata->e_d_tov = lport->e_d_tov; rdata->r_a_tov = lport->r_a_tov; rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); INIT_WORK(&rdata->event_work, fc_rport_work); - /* - * For good measure, but not necessary as we should only - * add REAL rport to the lport list. - */ - INIT_LIST_HEAD(&rdata->peers); - return rdata; } @@ -151,11 +125,9 @@ struct fc_rport_priv *fc_rport_rogue_create(struct fc_lport *lport, static void fc_rport_destroy(struct kref *kref) { struct fc_rport_priv *rdata; - struct fc_rport *rport; rdata = container_of(kref, struct fc_rport_priv, kref); - rport = rdata->rport; - put_device(&rport->dev); + kfree(rdata); } /** @@ -229,12 +201,10 @@ static void fc_rport_work(struct work_struct *work) u32 port_id; struct fc_rport_priv *rdata = container_of(work, struct fc_rport_priv, event_work); + struct fc_rport_libfc_priv *rp; enum fc_rport_event event; - enum fc_rport_trans_state trans_state; struct fc_lport *lport = rdata->local_port; struct fc_rport_operations *rport_ops; - struct fc_rport *new_rport; - struct fc_rport_priv *new_rdata; struct fc_rport_identifiers ids; struct fc_rport *rport; @@ -243,70 +213,72 @@ static void fc_rport_work(struct work_struct *work) rport_ops = rdata->ops; rport = rdata->rport; + FC_RPORT_DBG(rdata, "work event %u\n", event); + switch (event) { case RPORT_EV_READY: ids = rdata->ids; rdata->event = RPORT_EV_NONE; + kref_get(&rdata->kref); mutex_unlock(&rdata->rp_mutex); - new_rport = fc_remote_port_add(lport->host, 0, &ids); - if (new_rport) { - /* - * Switch from the rogue rport to the rport - * returned by the FC class. - */ - new_rport->maxframe_size = rdata->maxframe_size; - - new_rdata = new_rport->dd_data; - new_rdata->rport = new_rport; - new_rdata->ids = ids; - new_rdata->e_d_tov = rdata->e_d_tov; - new_rdata->r_a_tov = rdata->r_a_tov; - new_rdata->ops = rdata->ops; - new_rdata->local_port = rdata->local_port; - new_rdata->flags = FC_RP_FLAGS_REC_SUPPORTED; - new_rdata->trans_state = FC_PORTSTATE_REAL; - new_rdata->maxframe_size = rdata->maxframe_size; - new_rdata->supported_classes = rdata->supported_classes; - kref_init(&new_rdata->kref); - mutex_init(&new_rdata->rp_mutex); - INIT_DELAYED_WORK(&new_rdata->retry_work, - fc_rport_timeout); - INIT_LIST_HEAD(&new_rdata->peers); - INIT_WORK(&new_rdata->event_work, fc_rport_work); - - fc_rport_state_enter(new_rdata, RPORT_ST_READY); - } else { - printk(KERN_WARNING "libfc: Failed to allocate " - " memory for rport (%6x)\n", ids.port_id); - event = RPORT_EV_FAILED; + if (!rport) + rport = fc_remote_port_add(lport->host, 0, &ids); + if (!rport) { + FC_RPORT_DBG(rdata, "Failed to add the rport\n"); + lport->tt.rport_logoff(rdata); + kref_put(&rdata->kref, lport->tt.rport_destroy); + return; } - if (rdata->ids.port_id != FC_FID_DIR_SERV) - if (rport_ops->event_callback) - rport_ops->event_callback(lport, rdata, - RPORT_EV_FAILED); - kref_put(&rdata->kref, lport->tt.rport_destroy); - rdata = new_rport->dd_data; - if (rport_ops->event_callback) + mutex_lock(&rdata->rp_mutex); + if (rdata->rport) + FC_RPORT_DBG(rdata, "rport already allocated\n"); + rdata->rport = rport; + rport->maxframe_size = rdata->maxframe_size; + rport->supported_classes = rdata->supported_classes; + + rp = rport->dd_data; + rp->local_port = lport; + rp->rp_state = rdata->rp_state; + rp->flags = rdata->flags; + rp->e_d_tov = rdata->e_d_tov; + rp->r_a_tov = rdata->r_a_tov; + mutex_unlock(&rdata->rp_mutex); + + if (rport_ops->event_callback) { + FC_RPORT_DBG(rdata, "callback ev %d\n", event); rport_ops->event_callback(lport, rdata, event); + } + kref_put(&rdata->kref, lport->tt.rport_destroy); break; case RPORT_EV_FAILED: case RPORT_EV_LOGO: case RPORT_EV_STOP: - trans_state = rdata->trans_state; + port_id = rdata->ids.port_id; mutex_unlock(&rdata->rp_mutex); - if (rport_ops->event_callback) + + if (rport_ops->event_callback) { + FC_RPORT_DBG(rdata, "callback ev %d\n", event); rport_ops->event_callback(lport, rdata, event); + } cancel_delayed_work_sync(&rdata->retry_work); - if (trans_state == FC_PORTSTATE_ROGUE) - kref_put(&rdata->kref, lport->tt.rport_destroy); - else { - port_id = rport->port_id; + + /* + * Reset any outstanding exchanges before freeing rport. + */ + lport->tt.exch_mgr_reset(lport, 0, port_id); + lport->tt.exch_mgr_reset(lport, port_id, 0); + + if (rport) { + rp = rport->dd_data; + rp->rp_state = RPORT_ST_DELETE; + mutex_lock(&rdata->rp_mutex); + rdata->rport = NULL; + mutex_unlock(&rdata->rp_mutex); fc_remote_port_delete(rport); - lport->tt.exch_mgr_reset(lport, 0, port_id); - lport->tt.exch_mgr_reset(lport, port_id, 0); } + kref_put(&rdata->kref, lport->tt.rport_destroy); break; default: @@ -1311,7 +1283,7 @@ static void fc_rport_flush_queue(void) int fc_rport_init(struct fc_lport *lport) { if (!lport->tt.rport_create) - lport->tt.rport_create = fc_rport_rogue_create; + lport->tt.rport_create = fc_rport_create; if (!lport->tt.rport_login) lport->tt.rport_login = fc_rport_login; -- cgit v1.2.3-18-g5258 From 00fea930d404b9a9039291d5a61975e6c2ea974e Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:01:23 -0700 Subject: [SCSI] libfc: fix rport event race between READY and LOGO When a remote port becomes ready and a LOGO is received before the READY event is in rport_work waiting on the mutex, the event is changed to LOGO and the work queued, so both the calls to rport_work see the LOGO event, and both try to do the list_del(), causing a crash. Don't change the event if it is already set. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index a1794a39158..cbf6c9f233c 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -1267,9 +1267,7 @@ static void fc_rport_recv_logo_req(struct fc_rport_priv *rdata, return; } - rdata->event = RPORT_EV_LOGO; - fc_rport_state_enter(rdata, RPORT_ST_DELETE); - queue_work(rport_event_queue, &rdata->event_work); + fc_rport_enter_delete(rdata, RPORT_EV_LOGO); lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); fc_frame_free(fp); -- cgit v1.2.3-18-g5258 From 786681b96fc1a5b94d187160b7bf80bf6b4681ed Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:01:29 -0700 Subject: [SCSI] libfc: eliminate disc->event There was no need to have the discovery status stored in struct fc_disc. Change fc_disc_done() to take the discovery status as an argument and just pass it on to the discovery callback. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index bbea41e50a5..736f9174206 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -49,7 +49,7 @@ static void fc_disc_gpn_ft_req(struct fc_disc *); static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); static int fc_disc_new_target(struct fc_disc *, struct fc_rport_priv *, struct fc_rport_identifiers *); -static void fc_disc_done(struct fc_disc *); +static void fc_disc_done(struct fc_disc *, enum fc_disc_event); static void fc_disc_timeout(struct work_struct *); static void fc_disc_single(struct fc_disc *, struct fc_disc_port *); static void fc_disc_restart(struct fc_disc *); @@ -329,8 +329,7 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, if (rdata) { kref_get(&rdata->kref); if (!fc_disc_new_target(disc, rdata, &rdata->ids)) { - disc->event = DISC_EV_SUCCESS; - fc_disc_done(disc); + fc_disc_done(disc, DISC_EV_SUCCESS); } kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); } else { @@ -404,20 +403,18 @@ static int fc_disc_new_target(struct fc_disc *disc, /** * fc_disc_done() - Discovery has been completed * @disc: FC discovery context + * @event: discovery completion status + * * Locking Note: This function expects that the disc mutex is locked before * it is called. The discovery callback is then made with the lock released, * and the lock is re-taken before returning from this function */ -static void fc_disc_done(struct fc_disc *disc) +static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event) { struct fc_lport *lport = disc->lport; - enum fc_disc_event event; FC_DISC_DBG(disc, "Discovery complete\n"); - event = disc->event; - disc->event = DISC_EV_NONE; - if (disc->requested) fc_disc_gpn_ft_req(disc); else @@ -460,11 +457,8 @@ static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp) } disc->retry_count++; schedule_delayed_work(&disc->disc_work, delay); - } else { - /* exceeded retries */ - disc->event = DISC_EV_FAILED; - fc_disc_done(disc); - } + } else + fc_disc_done(disc, DISC_EV_FAILED); } } @@ -503,10 +497,12 @@ err: } /** - * fc_disc_gpn_ft_parse() - Parse the list of IDs and names resulting from a request + * fc_disc_gpn_ft_parse() - Parse the body of the dNS GPN_FT response. * @lport: Fibre Channel host port instance * @buf: GPN_FT response buffer * @len: size of response buffer + * + * Goes through the list of IDs and names resulting from a request. */ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) { @@ -577,8 +573,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) } if (np->fp_flags & FC_NS_FID_LAST) { - disc->event = DISC_EV_SUCCESS; - fc_disc_done(disc); + fc_disc_done(disc, DISC_EV_SUCCESS); len = 0; break; } @@ -669,8 +664,7 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, FC_DISC_DBG(disc, "GPN_FT rejected reason %x exp %x " "(check zoning)\n", cp->ct_reason, cp->ct_explan); - disc->event = DISC_EV_FAILED; - fc_disc_done(disc); + fc_disc_done(disc, DISC_EV_FAILED); } else { FC_DISC_DBG(disc, "GPN_FT unexpected response code " "%x\n", ntohs(cp->ct_cmd)); @@ -782,7 +776,6 @@ int fc_disc_init(struct fc_lport *lport) disc->lport = lport; disc->delay = FC_DISC_DELAY; - disc->event = DISC_EV_NONE; return 0; } -- cgit v1.2.3-18-g5258 From b84c7962653e4d04065d2603f0e1424ee0f455ae Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:01:34 -0700 Subject: [SCSI] libfc: remove unused disc->delay element Delete unused disc->delay element. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 736f9174206..8427396909e 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -43,8 +43,6 @@ #define FC_DISC_RETRY_LIMIT 3 /* max retries */ #define FC_DISC_RETRY_DELAY 500UL /* (msecs) delay */ -#define FC_DISC_DELAY 3 - static void fc_disc_gpn_ft_req(struct fc_disc *); static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); static int fc_disc_new_target(struct fc_disc *, struct fc_rport_priv *, @@ -775,7 +773,6 @@ int fc_disc_init(struct fc_lport *lport) INIT_LIST_HEAD(&disc->rports); disc->lport = lport; - disc->delay = FC_DISC_DELAY; return 0; } -- cgit v1.2.3-18-g5258 From cdbe6dfece038e75214735d56cd06319b9a6df46 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:01:39 -0700 Subject: [SCSI] libfc: rport debug messages were printing pointer values Don't print large negative decimal numbers for frame pointers in the debug messages from fc_rport_error(). Just print 0 if its a frame pointer, and print the error numbers as positive. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index cbf6c9f233c..6ecf36d4708 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -436,7 +436,8 @@ static void fc_rport_timeout(struct work_struct *work) static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp) { FC_RPORT_DBG(rdata, "Error %ld in state %s, retries %d\n", - PTR_ERR(fp), fc_rport_state(rdata), rdata->retries); + IS_ERR(fp) ? -PTR_ERR(fp) : 0, + fc_rport_state(rdata), rdata->retries); switch (rdata->rp_state) { case RPORT_ST_PLOGI: -- cgit v1.2.3-18-g5258 From b5cbf083736e14911c32fca2a93c540a92e8413d Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:01:44 -0700 Subject: [SCSI] libfc: simplify fc_lport_rport_callback The lport rport callback can only be called for the dNS rport, since its the only rport who's ops point to that function. Remove unnecessary checking and debug messages. Put the locking outside the switch statement as a simplification. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_lport.c | 43 +++++++++++++++---------------------------- 1 file changed, 15 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 016f771ebe6..22c0f7bc004 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -146,44 +146,31 @@ static void fc_lport_rport_callback(struct fc_lport *lport, FC_LPORT_DBG(lport, "Received a %d event for port (%6x)\n", event, rdata->ids.port_id); + mutex_lock(&lport->lp_mutex); switch (event) { case RPORT_EV_READY: - if (rdata->ids.port_id == FC_FID_DIR_SERV) { - mutex_lock(&lport->lp_mutex); - if (lport->state == LPORT_ST_DNS) { - lport->dns_rp = rdata; - fc_lport_enter_rpn_id(lport); - } else { - FC_LPORT_DBG(lport, "Received an READY event " - "on port (%6x) for the directory " - "server, but the lport is not " - "in the DNS state, it's in the " - "%d state", rdata->ids.port_id, - lport->state); - lport->tt.rport_logoff(rdata); - } - mutex_unlock(&lport->lp_mutex); - } else - FC_LPORT_DBG(lport, "Received an event for port (%6x) " - "which is not the directory server\n", - rdata->ids.port_id); + if (lport->state == LPORT_ST_DNS) { + lport->dns_rp = rdata; + fc_lport_enter_rpn_id(lport); + } else { + FC_LPORT_DBG(lport, "Received an READY event " + "on port (%6x) for the directory " + "server, but the lport is not " + "in the DNS state, it's in the " + "%d state", rdata->ids.port_id, + lport->state); + lport->tt.rport_logoff(rdata); + } break; case RPORT_EV_LOGO: case RPORT_EV_FAILED: case RPORT_EV_STOP: - if (rdata->ids.port_id == FC_FID_DIR_SERV) { - mutex_lock(&lport->lp_mutex); - lport->dns_rp = NULL; - mutex_unlock(&lport->lp_mutex); - - } else - FC_LPORT_DBG(lport, "Received an event for port (%6x) " - "which is not the directory server\n", - rdata->ids.port_id); + lport->dns_rp = NULL; break; case RPORT_EV_NONE: break; } + mutex_unlock(&lport->lp_mutex); } /** -- cgit v1.2.3-18-g5258 From 48f00902ba40d3e4467782a42258b952437a89f9 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:01:50 -0700 Subject: [SCSI] libfc: make rport module maintain the rport list The list of remote ports (struct fc_rport_priv) has been maintained by the discovery module. In preparation for having lport->tt.rport_create() do a lookup first, maintain the rports list in the rport module. It will still be protected by the disc_mutex. The DNS rport is an exception for until after further patches. For now, do not add it to the list. The point-to-point rport will be in the discovery list. So at shutdown, it doesn't need to be separately logged out. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 8 -------- drivers/scsi/libfc/fc_lport.c | 14 ++++++-------- drivers/scsi/libfc/fc_rport.c | 11 +++++++++-- 3 files changed, 15 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 8427396909e..e6b13bfecf7 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -115,9 +115,6 @@ static void fc_disc_rport_callback(struct fc_lport *lport, case RPORT_EV_LOGO: case RPORT_EV_FAILED: case RPORT_EV_STOP: - mutex_lock(&disc->disc_mutex); - list_del(&rdata->peers); - mutex_unlock(&disc->disc_mutex); break; default: break; @@ -385,9 +382,6 @@ static int fc_disc_new_target(struct fc_disc *disc, rdata = lport->tt.rport_create(lport, ids); if (!rdata) error = -ENOMEM; - else - list_add_tail(&rdata->peers, - &disc->rports); } } if (rdata) { @@ -562,7 +556,6 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) rdata = lport->tt.rport_create(lport, &ids); if (rdata) { rdata->ops = &fc_disc_rport_ops; - list_add_tail(&rdata->peers, &disc->rports); lport->tt.rport_login(rdata); } else printk(KERN_WARNING "libfc: Failed to allocate " @@ -709,7 +702,6 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) if (rdata) { rdata->ops = &fc_disc_rport_ops; kfree(dp); - list_add_tail(&rdata->peers, &disc->rports); lport->tt.rport_login(rdata); } return; diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 22c0f7bc004..f33e5732e3f 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -205,12 +205,11 @@ static void fc_lport_ptp_setup(struct fc_lport *lport, ids.node_name = remote_wwnn; ids.roles = FC_RPORT_ROLE_UNKNOWN; - if (lport->ptp_rp) { + mutex_lock(&lport->disc.disc_mutex); + if (lport->ptp_rp) lport->tt.rport_logoff(lport->ptp_rp); - lport->ptp_rp = NULL; - } - lport->ptp_rp = lport->tt.rport_create(lport, &ids); + mutex_unlock(&lport->disc.disc_mutex); lport->tt.rport_login(lport->ptp_rp); @@ -931,10 +930,7 @@ static void fc_lport_reset_locked(struct fc_lport *lport) if (lport->dns_rp) lport->tt.rport_logoff(lport->dns_rp); - if (lport->ptp_rp) { - lport->tt.rport_logoff(lport->ptp_rp); - lport->ptp_rp = NULL; - } + lport->ptp_rp = NULL; lport->tt.disc_stop(lport); @@ -1304,7 +1300,9 @@ static void fc_lport_enter_dns(struct fc_lport *lport) fc_lport_state_enter(lport, LPORT_ST_DNS); + mutex_lock(&lport->disc.disc_mutex); rdata = lport->tt.rport_create(lport, &ids); + mutex_unlock(&lport->disc.disc_mutex); if (!rdata) goto err; diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 6ecf36d4708..a9087b31bce 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -91,8 +91,7 @@ static const char *fc_rport_state_names[] = { * @lport: local port. * @ids: remote port identifiers. * - * Locking note: this may be called without locks held, but - * is usually called from discovery with the disc_mutex held. + * Locking note: must be called with the disc_mutex held. */ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, struct fc_rport_identifiers *ids) @@ -115,6 +114,8 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); INIT_WORK(&rdata->event_work, fc_rport_work); + if (ids->port_id != FC_FID_DIR_SERV) + list_add(&rdata->peers, &lport->disc.rports); return rdata; } @@ -258,6 +259,12 @@ static void fc_rport_work(struct work_struct *work) port_id = rdata->ids.port_id; mutex_unlock(&rdata->rp_mutex); + if (port_id != FC_FID_DIR_SERV) { + mutex_lock(&lport->disc.disc_mutex); + list_del(&rdata->peers); + mutex_unlock(&lport->disc.disc_mutex); + } + if (rport_ops->event_callback) { FC_RPORT_DBG(rdata, "callback ev %d\n", event); rport_ops->event_callback(lport, rdata, event); -- cgit v1.2.3-18-g5258 From 19f97e3c0acc5eb03486044f5428395b7690a01a Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:01:55 -0700 Subject: [SCSI] libfc: have rport_create do a lookup for pre-existing rports first For future discovery patches, change rport_create to return a previously created rport_priv that has the FC_ID as long as it isn't in deleted state. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 9 +++------ drivers/scsi/libfc/fc_rport.c | 4 ++++ 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index e6b13bfecf7..266aa1ea01e 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -377,12 +377,9 @@ static int fc_disc_new_target(struct fc_disc *disc, ids->port_id != fc_host_port_id(lport->host) && ids->port_name != lport->wwpn) { if (!rdata) { - rdata = lport->tt.rport_lookup(lport, ids->port_id); - if (!rdata) { - rdata = lport->tt.rport_create(lport, ids); - if (!rdata) - error = -ENOMEM; - } + rdata = lport->tt.rport_create(lport, ids); + if (!rdata) + error = -ENOMEM; } if (rdata) { rdata->ops = &fc_disc_rport_ops; diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index a9087b31bce..29bb6fd1003 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -98,6 +98,10 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, { struct fc_rport_priv *rdata; + rdata = lport->tt.rport_lookup(lport, ids->port_id); + if (rdata) + return rdata; + rdata = kzalloc(sizeof(*rdata), GFP_KERNEL); if (!rdata) return NULL; -- cgit v1.2.3-18-g5258 From 8345592b8388b51e0f52f63e94a5a5d3f07fda9a Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:02:01 -0700 Subject: [SCSI] libfc: change to make remote port callback optional Since the rport list maintenance is now done in the rport module, the callback (and ops) are usually not necessary. Allow rdata->ops to be left NULL if nothing needs to be done in an event callback. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 45 +++---------------------------------------- drivers/scsi/libfc/fc_rport.c | 4 ++-- 2 files changed, 5 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 266aa1ea01e..3fcbba17186 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -91,37 +91,6 @@ void fc_disc_stop_rports(struct fc_disc *disc) mutex_unlock(&disc->disc_mutex); } -/** - * fc_disc_rport_callback() - Event handler for rport events - * @lport: The lport which is receiving the event - * @rdata: private remote port data - * @event: The event that occured - * - * Locking Note: The rport lock should not be held when calling - * this function. - */ -static void fc_disc_rport_callback(struct fc_lport *lport, - struct fc_rport_priv *rdata, - enum fc_rport_event event) -{ - struct fc_disc *disc = &lport->disc; - - FC_DISC_DBG(disc, "Received a %d event for port (%6x)\n", event, - rdata->ids.port_id); - - switch (event) { - case RPORT_EV_READY: - break; - case RPORT_EV_LOGO: - case RPORT_EV_FAILED: - case RPORT_EV_STOP: - break; - default: - break; - } - -} - /** * fc_disc_recv_rscn_req() - Handle Registered State Change Notification (RSCN) * @sp: Current sequence of the RSCN exchange @@ -334,10 +303,6 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, mutex_unlock(&disc->disc_mutex); } -static struct fc_rport_operations fc_disc_rport_ops = { - .event_callback = fc_disc_rport_callback, -}; - /** * fc_disc_new_target() - Handle new target found by discovery * @lport: FC local port @@ -381,10 +346,8 @@ static int fc_disc_new_target(struct fc_disc *disc, if (!rdata) error = -ENOMEM; } - if (rdata) { - rdata->ops = &fc_disc_rport_ops; + if (rdata) lport->tt.rport_login(rdata); - } } return error; } @@ -551,10 +514,9 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) if (ids.port_id != fc_host_port_id(lport->host) && ids.port_name != lport->wwpn) { rdata = lport->tt.rport_create(lport, &ids); - if (rdata) { - rdata->ops = &fc_disc_rport_ops; + if (rdata) lport->tt.rport_login(rdata); - } else + else printk(KERN_WARNING "libfc: Failed to allocate " "memory for the newly discovered port " "(%6x)\n", ids.port_id); @@ -697,7 +659,6 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) rdata = lport->tt.rport_create(lport, &dp->ids); if (rdata) { - rdata->ops = &fc_disc_rport_ops; kfree(dp); lport->tt.rport_login(rdata); } diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 29bb6fd1003..406049c13a0 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -250,7 +250,7 @@ static void fc_rport_work(struct work_struct *work) rp->r_a_tov = rdata->r_a_tov; mutex_unlock(&rdata->rp_mutex); - if (rport_ops->event_callback) { + if (rport_ops && rport_ops->event_callback) { FC_RPORT_DBG(rdata, "callback ev %d\n", event); rport_ops->event_callback(lport, rdata, event); } @@ -269,7 +269,7 @@ static void fc_rport_work(struct work_struct *work) mutex_unlock(&lport->disc.disc_mutex); } - if (rport_ops->event_callback) { + if (rport_ops && rport_ops->event_callback) { FC_RPORT_DBG(rdata, "callback ev %d\n", event); rport_ops->event_callback(lport, rdata, event); } -- cgit v1.2.3-18-g5258 From 8025b5db7e10cd90cadec940cc766be3bbda65e8 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:02:06 -0700 Subject: [SCSI] libfc: move rport_lookup into fc_rport.c Move the libfc remote port lookup function into fc_rport.c. This seems like the best place for it. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 22 ---------------------- drivers/scsi/libfc/fc_rport.c | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 3fcbba17186..f6762a52147 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -52,25 +52,6 @@ static void fc_disc_timeout(struct work_struct *); static void fc_disc_single(struct fc_disc *, struct fc_disc_port *); static void fc_disc_restart(struct fc_disc *); -/** - * fc_disc_lookup_rport() - lookup a remote port by port_id - * @lport: Fibre Channel host port instance - * @port_id: remote port port_id to match - */ -struct fc_rport_priv *fc_disc_lookup_rport(const struct fc_lport *lport, - u32 port_id) -{ - const struct fc_disc *disc = &lport->disc; - struct fc_rport_priv *rdata; - - list_for_each_entry(rdata, &disc->rports, peers) { - if (rdata->ids.port_id == port_id && - rdata->rp_state != RPORT_ST_DELETE) - return rdata; - } - return NULL; -} - /** * fc_disc_stop_rports() - delete all the remote ports associated with the lport * @disc: The discovery job to stop rports on @@ -714,9 +695,6 @@ int fc_disc_init(struct fc_lport *lport) if (!lport->tt.disc_recv_req) lport->tt.disc_recv_req = fc_disc_recv_req; - if (!lport->tt.rport_lookup) - lport->tt.rport_lookup = fc_disc_lookup_rport; - disc = &lport->disc; INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout); mutex_init(&disc->disc_mutex); diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 406049c13a0..99ac056293f 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -86,6 +86,23 @@ static const char *fc_rport_state_names[] = { [RPORT_ST_DELETE] = "Delete", }; +/** + * fc_rport_lookup() - lookup a remote port by port_id + * @lport: Fibre Channel host port instance + * @port_id: remote port port_id to match + */ +static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport, + u32 port_id) +{ + struct fc_rport_priv *rdata; + + list_for_each_entry(rdata, &lport->disc.rports, peers) + if (rdata->ids.port_id == port_id && + rdata->rp_state != RPORT_ST_DELETE) + return rdata; + return NULL; +} + /** * fc_rport_create() - create remote port in INIT state. * @lport: local port. @@ -1292,6 +1309,9 @@ static void fc_rport_flush_queue(void) int fc_rport_init(struct fc_lport *lport) { + if (!lport->tt.rport_lookup) + lport->tt.rport_lookup = fc_rport_lookup; + if (!lport->tt.rport_create) lport->tt.rport_create = fc_rport_create; -- cgit v1.2.3-18-g5258 From 0f6c6149870e03c722af6eae406758b28cb71320 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:02:11 -0700 Subject: [SCSI] libfc: do not log off rports before or after discovery When receiving an RSCN, do not log off all rports. This is extremely disruptive. If, after the GPN_FT response, some rports haven't been listed, delete them. Add field disc_id to structs fc_rport_priv and fc_disc. disc_id is an arbitrary serial number used to identify the rports found by the latest discovery. This eliminates the need to go through the rport list when restarting discovery. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 47 ++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index f6762a52147..ddf494424ff 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -221,17 +221,19 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp, */ static void fc_disc_restart(struct fc_disc *disc) { - struct fc_rport_priv *rdata, *next; - struct fc_lport *lport = disc->lport; - FC_DISC_DBG(disc, "Restarting discovery\n"); - list_for_each_entry_safe(rdata, next, &disc->rports, peers) - lport->tt.rport_logoff(rdata); - disc->requested = 1; - if (!disc->pending) - fc_disc_gpn_ft_req(disc); + if (disc->pending) + return; + + /* + * Advance disc_id. This is an arbitrary non-zero number that will + * match the value in the fc_rport_priv after discovery for all + * freshly-discovered remote ports. Avoid wrapping to zero. + */ + disc->disc_id = (disc->disc_id + 2) | 1; + fc_disc_gpn_ft_req(disc); } /** @@ -278,6 +280,7 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, } kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); } else { + disc->disc_id = (disc->disc_id + 2) | 1; fc_disc_gpn_ft_req(disc); /* get ports by FC-4 type */ } @@ -345,13 +348,30 @@ static int fc_disc_new_target(struct fc_disc *disc, static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event) { struct fc_lport *lport = disc->lport; + struct fc_rport_priv *rdata; FC_DISC_DBG(disc, "Discovery complete\n"); - if (disc->requested) - fc_disc_gpn_ft_req(disc); - else - disc->pending = 0; + disc->pending = 0; + if (disc->requested) { + fc_disc_restart(disc); + return; + } + + /* + * Go through all remote ports. If they were found in the latest + * discovery, reverify or log them in. Otherwise, log them out. + * Skip ports which were never discovered. These are the dNS port + * and ports which were created by PLOGI. + */ + list_for_each_entry(rdata, &disc->rports, peers) { + if (!rdata->disc_id) + continue; + if (rdata->disc_id == disc->disc_id) + lport->tt.rport_login(rdata); + else + lport->tt.rport_logoff(rdata); + } mutex_unlock(&disc->disc_mutex); disc->disc_callback(lport, event); @@ -496,7 +516,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) ids.port_name != lport->wwpn) { rdata = lport->tt.rport_create(lport, &ids); if (rdata) - lport->tt.rport_login(rdata); + rdata->disc_id = disc->disc_id; else printk(KERN_WARNING "libfc: Failed to allocate " "memory for the newly discovered port " @@ -640,6 +660,7 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) rdata = lport->tt.rport_create(lport, &dp->ids); if (rdata) { + rdata->disc_id = disc->disc_id; kfree(dp); lport->tt.rport_login(rdata); } -- cgit v1.2.3-18-g5258 From c356afd48690775097507c37780ee17c0b0ea375 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:02:17 -0700 Subject: [SCSI] libfc: discovery restart sequence error fix When an RSCN is received during fabric discovery, it restarts. After the restart, disc->seq_count was incremented, so when the first frame was received, it was considered "out of sequence". That left the state disc->active, preventing further discoveries. Change to advance the sequence count before parsing, so that it won't be changed after a potential restart. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index ddf494424ff..fd3a6b287e9 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -629,11 +629,10 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, seq_cnt, disc->seq_count, fr_sof(fp), fr_eof(fp)); } if (buf) { + disc->seq_count++; error = fc_disc_gpn_ft_parse(disc, buf, len); if (error) fc_disc_error(disc, fp); - else - disc->seq_count++; } fc_frame_free(fp); -- cgit v1.2.3-18-g5258 From a1c1e4e76c68f564cddc0b43842b895464f7865f Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:02:22 -0700 Subject: [SCSI] libfc: rearrange code in fc_disc_gpn_ft_resp() Code cleanup for fc_disc_gpn_ft_resp(). Some of the fc_disc.c code was poorly formatted. For example, some lines in fc_disc.c were unnecessarily truncated and the buf variable could be eliminated. Also moved the increment of seq_count into fc_disc_gpn_ft_parse(), to avoid doing it separately before each call. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index fd3a6b287e9..819ec6256a5 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -469,6 +469,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) struct fc_rport_priv *rdata; lport = disc->lport; + disc->seq_count++; /* * Handle partial name record left over from previous call. @@ -582,10 +583,10 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, struct fc_disc *disc = disc_arg; struct fc_ct_hdr *cp; struct fc_frame_header *fh; + enum fc_disc_event event = DISC_EV_NONE; unsigned int seq_cnt; - void *buf = NULL; unsigned int len; - int error; + int error = 0; mutex_lock(&disc->disc_mutex); FC_DISC_DBG(disc, "Received a GPN_FT response\n"); @@ -600,8 +601,7 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, fh = fc_frame_header_get(fp); len = fr_len(fp) - sizeof(*fh); seq_cnt = ntohs(fh->fh_seq_cnt); - if (fr_sof(fp) == FC_SOF_I3 && seq_cnt == 0 && - disc->seq_count == 0) { + if (fr_sof(fp) == FC_SOF_I3 && seq_cnt == 0 && disc->seq_count == 0) { cp = fc_frame_payload_get(fp, sizeof(*cp)); if (!cp) { FC_DISC_DBG(disc, "GPN_FT response too short, len %d\n", @@ -609,33 +609,29 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, } else if (ntohs(cp->ct_cmd) == FC_FS_ACC) { /* Accepted, parse the response. */ - buf = cp + 1; len -= sizeof(*cp); + error = fc_disc_gpn_ft_parse(disc, cp + 1, len); } else if (ntohs(cp->ct_cmd) == FC_FS_RJT) { FC_DISC_DBG(disc, "GPN_FT rejected reason %x exp %x " "(check zoning)\n", cp->ct_reason, cp->ct_explan); - fc_disc_done(disc, DISC_EV_FAILED); + event = DISC_EV_FAILED; } else { FC_DISC_DBG(disc, "GPN_FT unexpected response code " "%x\n", ntohs(cp->ct_cmd)); } - } else if (fr_sof(fp) == FC_SOF_N3 && - seq_cnt == disc->seq_count) { - buf = fh + 1; + } else if (fr_sof(fp) == FC_SOF_N3 && seq_cnt == disc->seq_count) { + error = fc_disc_gpn_ft_parse(disc, fh + 1, len); } else { FC_DISC_DBG(disc, "GPN_FT unexpected frame - out of sequence? " "seq_cnt %x expected %x sof %x eof %x\n", seq_cnt, disc->seq_count, fr_sof(fp), fr_eof(fp)); } - if (buf) { - disc->seq_count++; - error = fc_disc_gpn_ft_parse(disc, buf, len); - if (error) - fc_disc_error(disc, fp); - } + if (error) + fc_disc_error(disc, fp); + else if (event != DISC_EV_NONE) + fc_disc_done(disc, event); fc_frame_free(fp); - mutex_unlock(&disc->disc_mutex); } -- cgit v1.2.3-18-g5258 From 883a337cf8969b2906ffd8aeb838d875f7338190 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:02:27 -0700 Subject: [SCSI] libfc: handle discovery failure more correctly. Abhijeet Joglekar wrote: "In gpn_ft_resp, if the payload is short, or unexpected response or out of sequence frame, then we just return and do nothing. We should either enter fc_disc_done() with DISC_EV_FAIL which will then restart any queued discovery requests or call lport module which will reset local port, or we should call fc_disc_error() so that the gpn_ft is retried. The situation as is causes discovery to remain pending and never get restarted, in these rare cases. We saw this due to a coding bug in fc_disc before. The only ways it could happen would be bugs, packet corruption or an FC fabric problem. Change it to fail discovery. The local port will restart discovery, although it probably should just give up until the next link flap. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 819ec6256a5..844376c1d8d 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -606,6 +606,7 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, if (!cp) { FC_DISC_DBG(disc, "GPN_FT response too short, len %d\n", fr_len(fp)); + event = DISC_EV_FAILED; } else if (ntohs(cp->ct_cmd) == FC_FS_ACC) { /* Accepted, parse the response. */ @@ -619,6 +620,7 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, } else { FC_DISC_DBG(disc, "GPN_FT unexpected response code " "%x\n", ntohs(cp->ct_cmd)); + event = DISC_EV_FAILED; } } else if (fr_sof(fp) == FC_SOF_N3 && seq_cnt == disc->seq_count) { error = fc_disc_gpn_ft_parse(disc, fh + 1, len); @@ -626,6 +628,7 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, FC_DISC_DBG(disc, "GPN_FT unexpected frame - out of sequence? " "seq_cnt %x expected %x sof %x eof %x\n", seq_cnt, disc->seq_count, fr_sof(fp), fr_eof(fp)); + event = DISC_EV_FAILED; } if (error) fc_disc_error(disc, fp); -- cgit v1.2.3-18-g5258 From c762608bf75f792dcaf3658338189b9970951704 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:02:33 -0700 Subject: [SCSI] libfc: fix: empty zone causes endless discovery retries. On some switches, an empty zone causes GPN_FT to be rejected with reason 9 (unable) explanation 7 (FC-4 types not registered), which causes discovery to be retried endlessly. Treat this as just an empty response and consider discovery complete. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 844376c1d8d..9b8043bdedd 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -617,6 +617,9 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, "(check zoning)\n", cp->ct_reason, cp->ct_explan); event = DISC_EV_FAILED; + if (cp->ct_reason == FC_FS_RJT_UNABL && + cp->ct_explan == FC_FS_EXP_FTNR) + event = DISC_EV_SUCCESS; } else { FC_DISC_DBG(disc, "GPN_FT unexpected response code " "%x\n", ntohs(cp->ct_cmd)); -- cgit v1.2.3-18-g5258 From 3667d7e7f7bb63a394f73a671fdaf4a187aa858e Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:02:38 -0700 Subject: [SCSI] libfc: discovery retry should clear pending first. Currently fc_disc_timeout() restarts discovery only if it is not pending. When the timer is scheduled, the discovery is left pending, so the timeout never restarts it. Fix by not checking for pending in the timeout handler. If discovery is stopped and restarted in the meantime, the timeout will be canceled. Also, when a new discovery is started, the retry count wasn't cleared. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 9b8043bdedd..3efdbbab9b2 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -233,6 +233,7 @@ static void fc_disc_restart(struct fc_disc *disc) * freshly-discovered remote ports. Avoid wrapping to zero. */ disc->disc_id = (disc->disc_id + 2) | 1; + disc->retry_count = 0; fc_disc_gpn_ft_req(disc); } @@ -563,8 +564,7 @@ static void fc_disc_timeout(struct work_struct *work) struct fc_disc, disc_work.work); mutex_lock(&disc->disc_mutex); - if (disc->requested && !disc->pending) - fc_disc_gpn_ft_req(disc); + fc_disc_gpn_ft_req(disc); mutex_unlock(&disc->disc_mutex); } -- cgit v1.2.3-18-g5258 From 81a67b9717d9e4f81bed7d1f2df6ba86aaab9ad9 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:02:43 -0700 Subject: [SCSI] libfc: discovery gpn_ft parse bug In fc_disc_gpn_ft_parse(), after fc_disc_done() is called, the disc state is changed by setting buf_len = 0. This is wrong since the discovery may have restarted. Instead, return after calling fc_disc_done. Also, return an error on memory allocation failure. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 3efdbbab9b2..a2410dc7444 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -479,6 +479,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) plen = len; np = (struct fc_gpn_ft_resp *)bp; tlen = disc->buf_len; + disc->buf_len = 0; if (tlen) { WARN_ON(tlen >= sizeof(*np)); plen = sizeof(*np) - tlen; @@ -519,10 +520,12 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) rdata = lport->tt.rport_create(lport, &ids); if (rdata) rdata->disc_id = disc->disc_id; - else + else { printk(KERN_WARNING "libfc: Failed to allocate " "memory for the newly discovered port " "(%6x)\n", ids.port_id); + error = -ENOMEM; + } } if (np->fp_flags & FC_NS_FID_LAST) { @@ -546,8 +549,6 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) memcpy(&disc->partial_buf, np, len); } disc->buf_len = (unsigned char) len; - } else { - disc->buf_len = 0; } return error; } -- cgit v1.2.3-18-g5258 From 29d898e909e3d086055e2649f5a24d4c2c1ca884 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:02:49 -0700 Subject: [SCSI] libfc: clean up point-to-point discovery code. The discovery code had a special-case for the point-to-point mode, which used a bunch of code that wasn't really needed. Now that rport_create adds the rport to the discovery list, completely skip discovery for the point-to-point case. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 84 ++----------------------------------------- drivers/scsi/libfc/fc_lport.c | 13 ++----- 2 files changed, 4 insertions(+), 93 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index a2410dc7444..428421842f3 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -45,8 +45,6 @@ static void fc_disc_gpn_ft_req(struct fc_disc *); static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); -static int fc_disc_new_target(struct fc_disc *, struct fc_rport_priv *, - struct fc_rport_identifiers *); static void fc_disc_done(struct fc_disc *, enum fc_disc_event); static void fc_disc_timeout(struct work_struct *); static void fc_disc_single(struct fc_disc *, struct fc_disc_port *); @@ -240,14 +238,12 @@ static void fc_disc_restart(struct fc_disc *disc) /** * fc_disc_start() - Fibre Channel Target discovery * @lport: FC local port - * - * Returns non-zero if discovery cannot be started. + * @disc_callback: function to be called when discovery is complete */ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, enum fc_disc_event), struct fc_lport *lport) { - struct fc_rport_priv *rdata; struct fc_disc *disc = &lport->disc; /* @@ -256,87 +252,11 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, * and send the GPN_FT request. */ mutex_lock(&disc->disc_mutex); - disc->disc_callback = disc_callback; - - /* - * If not ready, or already running discovery, just set request flag. - */ - disc->requested = 1; - - if (disc->pending) { - mutex_unlock(&disc->disc_mutex); - return; - } - - /* - * Handle point-to-point mode as a simple discovery - * of the remote port. Yucky, yucky, yuck, yuck! - */ - rdata = disc->lport->ptp_rp; - if (rdata) { - kref_get(&rdata->kref); - if (!fc_disc_new_target(disc, rdata, &rdata->ids)) { - fc_disc_done(disc, DISC_EV_SUCCESS); - } - kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); - } else { - disc->disc_id = (disc->disc_id + 2) | 1; - fc_disc_gpn_ft_req(disc); /* get ports by FC-4 type */ - } - + fc_disc_restart(disc); mutex_unlock(&disc->disc_mutex); } -/** - * fc_disc_new_target() - Handle new target found by discovery - * @lport: FC local port - * @rdata: The previous FC remote port priv (NULL if new remote port) - * @ids: Identifiers for the new FC remote port - * - * Locking Note: This function expects that the disc_mutex is locked - * before it is called. - */ -static int fc_disc_new_target(struct fc_disc *disc, - struct fc_rport_priv *rdata, - struct fc_rport_identifiers *ids) -{ - struct fc_lport *lport = disc->lport; - int error = 0; - - if (rdata && ids->port_name) { - if (rdata->ids.port_name == -1) { - /* - * Set WWN and fall through to notify of create. - */ - rdata->ids.port_name = ids->port_name; - rdata->ids.node_name = ids->node_name; - } else if (rdata->ids.port_name != ids->port_name) { - /* - * This is a new port with the same FCID as - * a previously-discovered port. Presumably the old - * port logged out and a new port logged in and was - * assigned the same FCID. This should be rare. - * Delete the old one and fall thru to re-create. - */ - lport->tt.rport_logoff(rdata); - rdata = NULL; - } - } - if (((ids->port_name != -1) || (ids->port_id != -1)) && - ids->port_id != fc_host_port_id(lport->host) && - ids->port_name != lport->wwpn) { - if (!rdata) { - rdata = lport->tt.rport_create(lport, ids); - if (!rdata) - error = -ENOMEM; - } - if (rdata) - lport->tt.rport_login(rdata); - } - return error; -} - /** * fc_disc_done() - Discovery has been completed * @disc: FC discovery context diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index f33e5732e3f..7000df57369 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -708,7 +708,8 @@ static void fc_lport_enter_ready(struct fc_lport *lport) fc_lport_state_enter(lport, LPORT_ST_READY); - lport->tt.disc_start(fc_lport_disc_callback, lport); + if (!lport->ptp_rp) + lport->tt.disc_start(fc_lport_disc_callback, lport); } /** @@ -794,8 +795,6 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, fc_lport_ptp_setup(lport, remote_fid, remote_wwpn, get_unaligned_be64(&flp->fl_wwnn)); - lport->tt.disc_start(fc_lport_disc_callback, lport); - out: sp = fr_seq(rx_fp); fc_frame_free(rx_fp); @@ -1512,14 +1511,6 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, fc_lport_enter_dns(lport); } } - - if (flp) { - csp_flags = ntohs(flp->fl_csp.sp_features); - if ((csp_flags & FC_SP_FT_FPORT) == 0) { - lport->tt.disc_start(fc_lport_disc_callback, - lport); - } - } } else { FC_LPORT_DBG(lport, "Bad FLOGI response\n"); } -- cgit v1.2.3-18-g5258 From 935d0fce44b906268b8a29de4e72ebb57a3a06d8 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:02:54 -0700 Subject: [SCSI] libfc: don't do discovery before callback is set It's possible to "restart" discovery before it was started if an RSCN is received early enough. We were jumping to 0 due to the disc_callback function pointer not getting set. Don't restart discovery if disc_callback is NULL. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 428421842f3..1a699f484c8 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -219,6 +219,9 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp, */ static void fc_disc_restart(struct fc_disc *disc) { + if (!disc->disc_callback) + return; + FC_DISC_DBG(disc, "Restarting discovery\n"); disc->requested = 1; -- cgit v1.2.3-18-g5258 From 9737e6a7b5b8af48f983cd565df93493597c565b Mon Sep 17 00:00:00 2001 From: Robert Love Date: Tue, 25 Aug 2009 14:02:59 -0700 Subject: [SCSI] libfc: Initialize fc_rport_identifiers inside fc_rport_create Currently these values are initialized by the callers. This was exposed by a later patch that adds PLOGI request support. The patch failed to initialize the new remote port's roles and it caused problems. This patch has the rport_create routine initialize the identifiers and then the callers can override them with real values. Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 20 ++++++++------------ drivers/scsi/libfc/fc_lport.c | 19 ++++--------------- drivers/scsi/libfc/fc_rport.c | 18 +++++++++++------- 3 files changed, 23 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 1a699f484c8..4242894cce7 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -137,10 +137,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, break; } dp->lp = lport; - dp->ids.port_id = ntoh24(pp->rscn_fid); - dp->ids.port_name = -1; - dp->ids.node_name = -1; - dp->ids.roles = FC_RPORT_ROLE_UNKNOWN; + dp->port_id = ntoh24(pp->rscn_fid); list_add_tail(&dp->peers, &disc_ports); break; case ELS_ADDR_FMT_AREA: @@ -162,7 +159,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, redisc, lport->state, disc->pending); list_for_each_entry_safe(dp, next, &disc_ports, peers) { list_del(&dp->peers); - rdata = lport->tt.rport_lookup(lport, dp->ids.port_id); + rdata = lport->tt.rport_lookup(lport, dp->port_id); if (rdata) { lport->tt.rport_logoff(rdata); } @@ -435,15 +432,14 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) while (plen >= sizeof(*np)) { ids.port_id = ntoh24(np->fp_fid); ids.port_name = ntohll(np->fp_wwpn); - ids.node_name = -1; - ids.roles = FC_RPORT_ROLE_UNKNOWN; if (ids.port_id != fc_host_port_id(lport->host) && ids.port_name != lport->wwpn) { - rdata = lport->tt.rport_create(lport, &ids); - if (rdata) + rdata = lport->tt.rport_create(lport, ids.port_id); + if (rdata) { + rdata->ids.port_name = ids.port_name; rdata->disc_id = disc->disc_id; - else { + } else { printk(KERN_WARNING "libfc: Failed to allocate " "memory for the newly discovered port " "(%6x)\n", ids.port_id); @@ -580,10 +576,10 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) lport = disc->lport; - if (dp->ids.port_id == fc_host_port_id(lport->host)) + if (dp->port_id == fc_host_port_id(lport->host)) goto out; - rdata = lport->tt.rport_create(lport, &dp->ids); + rdata = lport->tt.rport_create(lport, dp->port_id); if (rdata) { rdata->disc_id = disc->disc_id; kfree(dp); diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 7000df57369..caf68240bdd 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -198,17 +198,12 @@ static void fc_lport_ptp_setup(struct fc_lport *lport, u32 remote_fid, u64 remote_wwpn, u64 remote_wwnn) { - struct fc_rport_identifiers ids; - - ids.port_id = remote_fid; - ids.port_name = remote_wwpn; - ids.node_name = remote_wwnn; - ids.roles = FC_RPORT_ROLE_UNKNOWN; - mutex_lock(&lport->disc.disc_mutex); if (lport->ptp_rp) lport->tt.rport_logoff(lport->ptp_rp); - lport->ptp_rp = lport->tt.rport_create(lport, &ids); + lport->ptp_rp = lport->tt.rport_create(lport, remote_fid); + lport->ptp_rp->ids.port_name = remote_wwpn; + lport->ptp_rp->ids.node_name = remote_wwnn; mutex_unlock(&lport->disc.disc_mutex); lport->tt.rport_login(lport->ptp_rp); @@ -1287,12 +1282,6 @@ static struct fc_rport_operations fc_lport_rport_ops = { static void fc_lport_enter_dns(struct fc_lport *lport) { struct fc_rport_priv *rdata; - struct fc_rport_identifiers ids; - - ids.port_id = FC_FID_DIR_SERV; - ids.port_name = -1; - ids.node_name = -1; - ids.roles = FC_RPORT_ROLE_UNKNOWN; FC_LPORT_DBG(lport, "Entered DNS state from %s state\n", fc_lport_state(lport)); @@ -1300,7 +1289,7 @@ static void fc_lport_enter_dns(struct fc_lport *lport) fc_lport_state_enter(lport, LPORT_ST_DNS); mutex_lock(&lport->disc.disc_mutex); - rdata = lport->tt.rport_create(lport, &ids); + rdata = lport->tt.rport_create(lport, FC_FID_DIR_SERV); mutex_unlock(&lport->disc.disc_mutex); if (!rdata) goto err; diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 99ac056293f..c667be879be 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -104,18 +104,18 @@ static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport, } /** - * fc_rport_create() - create remote port in INIT state. - * @lport: local port. - * @ids: remote port identifiers. + * fc_rport_create() - Create a new remote port + * @lport: The local port that the new remote port is for + * @port_id: The port ID for the new remote port * * Locking note: must be called with the disc_mutex held. */ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, - struct fc_rport_identifiers *ids) + u32 port_id) { struct fc_rport_priv *rdata; - rdata = lport->tt.rport_lookup(lport, ids->port_id); + rdata = lport->tt.rport_lookup(lport, port_id); if (rdata) return rdata; @@ -123,7 +123,11 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, if (!rdata) return NULL; - rdata->ids = *ids; + rdata->ids.node_name = -1; + rdata->ids.port_name = -1; + rdata->ids.port_id = port_id; + rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN; + kref_init(&rdata->kref); mutex_init(&rdata->rp_mutex); rdata->local_port = lport; @@ -135,7 +139,7 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); INIT_WORK(&rdata->event_work, fc_rport_work); - if (ids->port_id != FC_FID_DIR_SERV) + if (port_id != FC_FID_DIR_SERV) list_add(&rdata->peers, &lport->disc.rports); return rdata; } -- cgit v1.2.3-18-g5258 From 6bd054cbf3f7da3442f30a7d4eb7da4dd1c44f21 Mon Sep 17 00:00:00 2001 From: Robert Love Date: Tue, 25 Aug 2009 14:03:04 -0700 Subject: [SCSI] libfc: Always reset remote port roles when receiving PRLI Don't trust previous roles, reset them when we receive a PRLI. Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index c667be879be..cb54115c26c 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -666,6 +666,9 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, goto err; } + /* reinitialize remote port roles */ + rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN; + op = fc_frame_payload_op(fp); if (op == ELS_LS_ACC) { pp = fc_frame_payload_get(fp, sizeof(*pp)); @@ -1173,6 +1176,9 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, pp->prli.prli_len = htons(len); len -= sizeof(struct fc_els_prli); + /* reinitialize remote port roles */ + rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN; + /* * Go through all the service parameter pages and build * response. If plen indicates longer SPP than standard, -- cgit v1.2.3-18-g5258 From 131203a1ef53f3a4deb3260031bc53c7e4db4a24 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:03:10 -0700 Subject: [SCSI] libfc: move remote port lookup for ELS requests into fc_rport.c. This moves the remote port lookup for incoming ELS requests into fc_rport.c, in preparation for handing PLOGI and LOGO from unknown rports. This changes the arg to rport_recv_req from an rdata to an lport. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_lport.c | 30 ++--------------- drivers/scsi/libfc/fc_rport.c | 78 +++++++++++++++++++++++-------------------- 2 files changed, 43 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index caf68240bdd..d3f4e0c34f5 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -812,10 +812,6 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, { struct fc_frame_header *fh = fc_frame_header_get(fp); void (*recv) (struct fc_seq *, struct fc_frame *, struct fc_lport *); - struct fc_rport_priv *rdata; - u32 s_id; - u32 d_id; - struct fc_seq_els_data rjt_data; mutex_lock(&lport->lp_mutex); @@ -831,7 +827,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, /* * Check opcode. */ - recv = NULL; + recv = lport->tt.rport_recv_req; switch (fc_frame_payload_op(fp)) { case ELS_FLOGI: recv = fc_lport_recv_flogi_req; @@ -858,29 +854,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, break; } - if (recv) - recv(sp, fp, lport); - else { - /* - * Find session. - * If this is a new incoming PLOGI, we won't find it. - */ - s_id = ntoh24(fh->fh_s_id); - d_id = ntoh24(fh->fh_d_id); - - rdata = lport->tt.rport_lookup(lport, s_id); - if (rdata) - lport->tt.rport_recv_req(sp, fp, rdata); - else { - rjt_data.fp = NULL; - rjt_data.reason = ELS_RJT_UNAB; - rjt_data.explan = ELS_EXPL_NONE; - lport->tt.seq_els_rsp_send(sp, - ELS_LS_RJT, - &rjt_data); - fc_frame_free(fp); - } - } + recv(sp, fp, lport); } else { FC_LPORT_DBG(lport, "dropping invalid frame (eof %x)\n", fr_eof(fp)); diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index cb54115c26c..acdc72d6b87 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -912,57 +912,61 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata) * fc_rport_recv_req() - Receive a request from a rport * @sp: current sequence in the PLOGI exchange * @fp: response frame - * @rdata_arg: private remote port data + * @lport: Fibre Channel local port * - * Locking Note: Called without the rport lock held. This - * function will hold the rport lock, call an _enter_* - * function and then unlock the rport. + * Locking Note: Called with the lport lock held. */ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, - struct fc_rport_priv *rdata) + struct fc_lport *lport) { - struct fc_lport *lport = rdata->local_port; - + struct fc_rport_priv *rdata; struct fc_frame_header *fh; struct fc_seq_els_data els_data; + u32 s_id; u8 op; - mutex_lock(&rdata->rp_mutex); - els_data.fp = NULL; els_data.explan = ELS_EXPL_NONE; els_data.reason = ELS_RJT_NONE; fh = fc_frame_header_get(fp); + s_id = ntoh24(fh->fh_s_id); - if (fh->fh_r_ctl == FC_RCTL_ELS_REQ && fh->fh_type == FC_TYPE_ELS) { - op = fc_frame_payload_op(fp); - switch (op) { - case ELS_PLOGI: - fc_rport_recv_plogi_req(rdata, sp, fp); - break; - case ELS_PRLI: - fc_rport_recv_prli_req(rdata, sp, fp); - break; - case ELS_PRLO: - fc_rport_recv_prlo_req(rdata, sp, fp); - break; - case ELS_LOGO: - fc_rport_recv_logo_req(rdata, sp, fp); - break; - case ELS_RRQ: - els_data.fp = fp; - lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data); - break; - case ELS_REC: - els_data.fp = fp; - lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data); - break; - default: - els_data.reason = ELS_RJT_UNSUP; - lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data); - break; - } + rdata = lport->tt.rport_lookup(lport, s_id); + if (!rdata) { + els_data.reason = ELS_RJT_UNAB; + lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data); + fc_frame_free(fp); + return; + } + mutex_lock(&rdata->rp_mutex); + + op = fc_frame_payload_op(fp); + switch (op) { + case ELS_PLOGI: + fc_rport_recv_plogi_req(rdata, sp, fp); + break; + case ELS_PRLI: + fc_rport_recv_prli_req(rdata, sp, fp); + break; + case ELS_PRLO: + fc_rport_recv_prlo_req(rdata, sp, fp); + break; + case ELS_LOGO: + fc_rport_recv_logo_req(rdata, sp, fp); + break; + case ELS_RRQ: + els_data.fp = fp; + lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data); + break; + case ELS_REC: + els_data.fp = fp; + lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data); + break; + default: + els_data.reason = ELS_RJT_UNSUP; + lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data); + break; } mutex_unlock(&rdata->rp_mutex); -- cgit v1.2.3-18-g5258 From 25b37b981e706c6df72c28c94f7787c3ea0cd343 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:03:15 -0700 Subject: [SCSI] libfc: fix: rport_recv_req needs disc_mutex when calling rport_lookup The rport_lookup function must be called while holding the disc_mutex. Otherwise, the rdata could be deleted just after that by another thread. All callers now check the state after grabbing the rdata rp_mutex. Even though rport_lookup skips ports in DELETE state, it does that without holding the rdata rp_mutex, so that the state may change. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index acdc72d6b87..02200b26d89 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -932,14 +932,17 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, fh = fc_frame_header_get(fp); s_id = ntoh24(fh->fh_s_id); + mutex_lock(&lport->disc.disc_mutex); rdata = lport->tt.rport_lookup(lport, s_id); if (!rdata) { + mutex_unlock(&lport->disc.disc_mutex); els_data.reason = ELS_RJT_UNAB; lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data); fc_frame_free(fp); return; } mutex_lock(&rdata->rp_mutex); + mutex_unlock(&lport->disc.disc_mutex); op = fc_frame_payload_op(fp); switch (op) { -- cgit v1.2.3-18-g5258 From f657d299cf05883e23e12a69e86842da1df378ad Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:03:21 -0700 Subject: [SCSI] libfc: improve debug messages for ELS response handlers Improve lport and rport debug messages to indicate whether the response is LS_ACC, LS_RJT, closed, or timeout. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_elsct.c | 38 ++++++++++++++++++++++++++++++++++++++ drivers/scsi/libfc/fc_lport.c | 20 ++++++++++---------- drivers/scsi/libfc/fc_rport.c | 8 ++++---- 3 files changed, 52 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c index 5e8b011af50..d655924d46b 100644 --- a/drivers/scsi/libfc/fc_elsct.c +++ b/drivers/scsi/libfc/fc_elsct.c @@ -70,3 +70,41 @@ int fc_elsct_init(struct fc_lport *lport) return 0; } EXPORT_SYMBOL(fc_elsct_init); + +/** + * fc_els_resp_type() - return string describing ELS response for debug. + * @fp: frame pointer with possible error code. + */ +const char *fc_els_resp_type(struct fc_frame *fp) +{ + const char *msg; + if (IS_ERR(fp)) { + switch (-PTR_ERR(fp)) { + case FC_NO_ERR: + msg = "response no error"; + break; + case FC_EX_TIMEOUT: + msg = "response timeout"; + break; + case FC_EX_CLOSED: + msg = "response closed"; + break; + default: + msg = "response unknown error"; + break; + } + } else { + switch (fc_frame_payload_op(fp)) { + case ELS_LS_ACC: + msg = "accept"; + break; + case ELS_LS_RJT: + msg = "reject"; + break; + default: + msg = "response unknown ELS"; + break; + } + } + return msg; +} diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index d3f4e0c34f5..3f2f7239014 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -1006,13 +1006,13 @@ static void fc_lport_rft_id_resp(struct fc_seq *sp, struct fc_frame *fp, struct fc_frame_header *fh; struct fc_ct_hdr *ct; + FC_LPORT_DBG(lport, "Received a RFT_ID %s\n", fc_els_resp_type(fp)); + if (fp == ERR_PTR(-FC_EX_CLOSED)) return; mutex_lock(&lport->lp_mutex); - FC_LPORT_DBG(lport, "Received a RFT_ID response\n"); - if (lport->state != LPORT_ST_RFT_ID) { FC_LPORT_DBG(lport, "Received a RFT_ID response, but in state " "%s\n", fc_lport_state(lport)); @@ -1060,13 +1060,13 @@ static void fc_lport_rpn_id_resp(struct fc_seq *sp, struct fc_frame *fp, struct fc_frame_header *fh; struct fc_ct_hdr *ct; + FC_LPORT_DBG(lport, "Received a RPN_ID %s\n", fc_els_resp_type(fp)); + if (fp == ERR_PTR(-FC_EX_CLOSED)) return; mutex_lock(&lport->lp_mutex); - FC_LPORT_DBG(lport, "Received a RPN_ID response\n"); - if (lport->state != LPORT_ST_RPN_ID) { FC_LPORT_DBG(lport, "Received a RPN_ID response, but in state " "%s\n", fc_lport_state(lport)); @@ -1112,13 +1112,13 @@ static void fc_lport_scr_resp(struct fc_seq *sp, struct fc_frame *fp, struct fc_lport *lport = lp_arg; u8 op; + FC_LPORT_DBG(lport, "Received a SCR %s\n", fc_els_resp_type(fp)); + if (fp == ERR_PTR(-FC_EX_CLOSED)) return; mutex_lock(&lport->lp_mutex); - FC_LPORT_DBG(lport, "Received a SCR response\n"); - if (lport->state != LPORT_ST_SCR) { FC_LPORT_DBG(lport, "Received a SCR response, but in state " "%s\n", fc_lport_state(lport)); @@ -1333,13 +1333,13 @@ static void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, struct fc_lport *lport = lp_arg; u8 op; + FC_LPORT_DBG(lport, "Received a LOGO %s\n", fc_els_resp_type(fp)); + if (fp == ERR_PTR(-FC_EX_CLOSED)) return; mutex_lock(&lport->lp_mutex); - FC_LPORT_DBG(lport, "Received a LOGO response\n"); - if (lport->state != LPORT_ST_LOGO) { FC_LPORT_DBG(lport, "Received a LOGO response, but in state " "%s\n", fc_lport_state(lport)); @@ -1415,13 +1415,13 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, unsigned int e_d_tov; u16 mfs; + FC_LPORT_DBG(lport, "Received a FLOGI %s\n", fc_els_resp_type(fp)); + if (fp == ERR_PTR(-FC_EX_CLOSED)) return; mutex_lock(&lport->lp_mutex); - FC_LPORT_DBG(lport, "Received a FLOGI response\n"); - if (lport->state != LPORT_ST_FLOGI) { FC_LPORT_DBG(lport, "Received a FLOGI response, but in state " "%s\n", fc_lport_state(lport)); diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 02200b26d89..d014b285cd1 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -544,7 +544,7 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rdata, "Received a PLOGI response\n"); + FC_RPORT_DBG(rdata, "Received a PLOGI %s\n", fc_els_resp_type(fp)); if (rdata->rp_state != RPORT_ST_PLOGI) { FC_RPORT_DBG(rdata, "Received a PLOGI response, but in state " @@ -651,7 +651,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rdata, "Received a PRLI response\n"); + FC_RPORT_DBG(rdata, "Received a PRLI %s\n", fc_els_resp_type(fp)); if (rdata->rp_state != RPORT_ST_PRLI) { FC_RPORT_DBG(rdata, "Received a PRLI response, but in state " @@ -717,7 +717,7 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rdata, "Received a LOGO response\n"); + FC_RPORT_DBG(rdata, "Received a LOGO %s\n", fc_els_resp_type(fp)); if (rdata->rp_state != RPORT_ST_LOGO) { FC_RPORT_DBG(rdata, "Received a LOGO response, but in state " @@ -801,7 +801,7 @@ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rdata, "Received a RTV response\n"); + FC_RPORT_DBG(rdata, "Received a RTV %s\n", fc_els_resp_type(fp)); if (rdata->rp_state != RPORT_ST_RTV) { FC_RPORT_DBG(rdata, "Received a RTV response, but in state " -- cgit v1.2.3-18-g5258 From 3ac6f98f4113ec1c115cf9d443a9bff816e47c0b Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:03:26 -0700 Subject: [SCSI] libfc: correctly handle incoming PLOGI request. libfc receives PLOGIs from switches which are trying to discover what kind of devices are present, and from other initiators to find out if we're a target. As an initiator, some argue we don't need to handle incoming PLOGI requests, and we currently reject them from unknown remote ports, but accept them is we're in the middle of a PLOGI to the remote port. For eventual target implementations, we want to handle them always. For incoming PLOGI, don't fail if the rport_priv doesn't exist. Just create it and go become READY without going through PRLI. If PRLI occurs, then our roles will be set and we'll become READY again. Also, allow incoming PRLI in RTV state. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 185 +++++++++++++++++++++--------------------- 1 file changed, 93 insertions(+), 92 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index d014b285cd1..e121ff92c8e 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -63,7 +63,7 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *); static void fc_rport_enter_ready(struct fc_rport_priv *); static void fc_rport_enter_logo(struct fc_rport_priv *); -static void fc_rport_recv_plogi_req(struct fc_rport_priv *, +static void fc_rport_recv_plogi_req(struct fc_lport *, struct fc_seq *, struct fc_frame *); static void fc_rport_recv_prli_req(struct fc_rport_priv *, struct fc_seq *, struct fc_frame *); @@ -576,15 +576,7 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, csp_seq = cssp_seq; rdata->max_seq = csp_seq; rdata->maxframe_size = fc_plogi_get_maxframe(plp, lport->mfs); - - /* - * If the rport is one of the well known addresses - * we skip PRLI and RTV and go straight to READY. - */ - if (rdata->ids.port_id >= FC_FID_DOM_MGR) - fc_rport_enter_ready(rdata); - else - fc_rport_enter_prli(rdata); + fc_rport_enter_prli(rdata); } else fc_rport_error_retry(rdata, fp); @@ -763,6 +755,15 @@ static void fc_rport_enter_prli(struct fc_rport_priv *rdata) } *pp; struct fc_frame *fp; + /* + * If the rport is one of the well known addresses + * we skip PRLI and RTV and go straight to READY. + */ + if (rdata->ids.port_id >= FC_FID_DOM_MGR) { + fc_rport_enter_ready(rdata); + return; + } + FC_RPORT_DBG(rdata, "Port entered PRLI state from %s state\n", fc_rport_state(rdata)); @@ -929,6 +930,15 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, els_data.explan = ELS_EXPL_NONE; els_data.reason = ELS_RJT_NONE; + op = fc_frame_payload_op(fp); + switch (op) { + case ELS_PLOGI: + fc_rport_recv_plogi_req(lport, sp, fp); + return; + default: + break; + } + fh = fc_frame_header_get(fp); s_id = ntoh24(fh->fh_s_id); @@ -944,11 +954,7 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&rdata->rp_mutex); mutex_unlock(&lport->disc.disc_mutex); - op = fc_frame_payload_op(fp); switch (op) { - case ELS_PLOGI: - fc_rport_recv_plogi_req(rdata, sp, fp); - break; case ELS_PRLI: fc_rport_recv_prli_req(rdata, sp, fp); break; @@ -977,48 +983,56 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, /** * fc_rport_recv_plogi_req() - Handle incoming Port Login (PLOGI) request - * @rdata: private remote port data + * @lport: local port * @sp: current sequence in the PLOGI exchange * @fp: PLOGI request frame * - * Locking Note: The rport lock is exected to be held before calling - * this function. + * Locking Note: The rport lock is held before calling this function. */ -static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata, +static void fc_rport_recv_plogi_req(struct fc_lport *lport, struct fc_seq *sp, struct fc_frame *rx_fp) { - struct fc_lport *lport = rdata->local_port; + struct fc_disc *disc; + struct fc_rport_priv *rdata; struct fc_frame *fp = rx_fp; struct fc_exch *ep; struct fc_frame_header *fh; struct fc_els_flogi *pl; struct fc_seq_els_data rjt_data; - u32 sid; - u64 wwpn; - u64 wwnn; - enum fc_els_rjt_reason reject = 0; - u32 f_ctl; - rjt_data.fp = NULL; + u32 sid, f_ctl; + rjt_data.fp = NULL; fh = fc_frame_header_get(fp); + sid = ntoh24(fh->fh_s_id); - FC_RPORT_DBG(rdata, "Received PLOGI request while in state %s\n", - fc_rport_state(rdata)); + FC_RPORT_ID_DBG(lport, sid, "Received PLOGI request\n"); - sid = ntoh24(fh->fh_s_id); pl = fc_frame_payload_get(fp, sizeof(*pl)); if (!pl) { - FC_RPORT_DBG(rdata, "Received PLOGI too short\n"); - WARN_ON(1); - /* XXX TBD: send reject? */ - fc_frame_free(fp); - return; + FC_RPORT_ID_DBG(lport, sid, "Received PLOGI too short\n"); + rjt_data.reason = ELS_RJT_PROT; + rjt_data.explan = ELS_EXPL_INV_LEN; + goto reject; + } + + disc = &lport->disc; + mutex_lock(&disc->disc_mutex); + rdata = lport->tt.rport_create(lport, sid); + if (!rdata) { + mutex_unlock(&disc->disc_mutex); + rjt_data.reason = ELS_RJT_UNAB; + rjt_data.explan = ELS_EXPL_INSUF_RES; + goto reject; } - wwpn = get_unaligned_be64(&pl->fl_wwpn); - wwnn = get_unaligned_be64(&pl->fl_wwnn); + + mutex_lock(&rdata->rp_mutex); + mutex_unlock(&disc->disc_mutex); + + rdata->ids.port_name = get_unaligned_be64(&pl->fl_wwpn); + rdata->ids.node_name = get_unaligned_be64(&pl->fl_wwnn); /* - * If the session was just created, possibly due to the incoming PLOGI, + * If the rport was just created, possibly due to the incoming PLOGI, * set the state appropriately and accept the PLOGI. * * If we had also sent a PLOGI, and if the received PLOGI is from a @@ -1030,72 +1044,58 @@ static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata, */ switch (rdata->rp_state) { case RPORT_ST_INIT: - FC_RPORT_DBG(rdata, "Received PLOGI, wwpn %llx state INIT " - "- reject\n", (unsigned long long)wwpn); - reject = ELS_RJT_UNSUP; + FC_RPORT_DBG(rdata, "Received PLOGI in INIT state\n"); break; case RPORT_ST_PLOGI: - FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state %d\n", - rdata->rp_state); - if (wwpn < lport->wwpn) - reject = ELS_RJT_INPROG; + FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state\n"); + if (rdata->ids.port_name < lport->wwpn) { + mutex_unlock(&rdata->rp_mutex); + rjt_data.reason = ELS_RJT_INPROG; + rjt_data.explan = ELS_EXPL_NONE; + goto reject; + } break; case RPORT_ST_PRLI: case RPORT_ST_READY: - FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d " - "- ignored for now\n", rdata->rp_state); - /* XXX TBD - should reset */ break; case RPORT_ST_DELETE: default: - FC_RPORT_DBG(rdata, "Received PLOGI in unexpected " - "state %d\n", rdata->rp_state); - fc_frame_free(fp); - return; - break; + FC_RPORT_DBG(rdata, "Received PLOGI in unexpected state %d\n", + rdata->rp_state); + fc_frame_free(rx_fp); + goto out; } - if (reject) { - rjt_data.reason = reject; - rjt_data.explan = ELS_EXPL_NONE; - lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); - fc_frame_free(fp); - } else { - fp = fc_frame_alloc(lport, sizeof(*pl)); - if (fp == NULL) { - fp = rx_fp; - rjt_data.reason = ELS_RJT_UNAB; - rjt_data.explan = ELS_EXPL_NONE; - lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); - fc_frame_free(fp); - } else { - sp = lport->tt.seq_start_next(sp); - WARN_ON(!sp); - rdata->ids.port_name = wwpn; - rdata->ids.node_name = wwnn; - - /* - * Get session payload size from incoming PLOGI. - */ - rdata->maxframe_size = - fc_plogi_get_maxframe(pl, lport->mfs); - fc_frame_free(rx_fp); - fc_plogi_fill(lport, fp, ELS_LS_ACC); - - /* - * Send LS_ACC. If this fails, - * the originator should retry. - */ - f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ; - f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT; - ep = fc_seq_exch(sp); - fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, - FC_TYPE_ELS, f_ctl, 0); - lport->tt.seq_send(lport, sp, fp); - if (rdata->rp_state == RPORT_ST_PLOGI) - fc_rport_enter_prli(rdata); - } - } + /* + * Get session payload size from incoming PLOGI. + */ + rdata->maxframe_size = fc_plogi_get_maxframe(pl, lport->mfs); + fc_frame_free(rx_fp); + + /* + * Send LS_ACC. If this fails, the originator should retry. + */ + sp = lport->tt.seq_start_next(sp); + if (!sp) + goto out; + fp = fc_frame_alloc(lport, sizeof(*pl)); + if (!fp) + goto out; + + fc_plogi_fill(lport, fp, ELS_LS_ACC); + f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT; + ep = fc_seq_exch(sp); + fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, + FC_TYPE_ELS, f_ctl, 0); + lport->tt.seq_send(lport, sp, fp); + fc_rport_enter_prli(rdata); +out: + mutex_unlock(&rdata->rp_mutex); + return; + +reject: + lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); + fc_frame_free(fp); } /** @@ -1138,6 +1138,7 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, switch (rdata->rp_state) { case RPORT_ST_PRLI: + case RPORT_ST_RTV: case RPORT_ST_READY: reason = ELS_RJT_NONE; break; -- cgit v1.2.3-18-g5258 From 83fe6a93465750d1a20221aaa9a253d9ea7fe45c Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:03:31 -0700 Subject: [SCSI] libfc: fix rport error handling for login-required and invalid ops When receiving an ELS request, if the request isn't recognized, the unsupported operation error should be given even if the port is not found or not logged in. Also, the LOGO request shouldn't give the login-required explanation. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 137 +++++++++++++++++++++++++++--------------- 1 file changed, 88 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index e121ff92c8e..04e9846ad1b 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -69,7 +69,7 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *, struct fc_seq *, struct fc_frame *); static void fc_rport_recv_prlo_req(struct fc_rport_priv *, struct fc_seq *, struct fc_frame *); -static void fc_rport_recv_logo_req(struct fc_rport_priv *, +static void fc_rport_recv_logo_req(struct fc_lport *, struct fc_seq *, struct fc_frame *); static void fc_rport_timeout(struct work_struct *); static void fc_rport_error(struct fc_rport_priv *, struct fc_frame *); @@ -908,62 +908,56 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata) kref_get(&rdata->kref); } - /** - * fc_rport_recv_req() - Receive a request from a rport + * fc_rport_recv_els_req() - handle a validated ELS request. + * @lport: Fibre Channel local port * @sp: current sequence in the PLOGI exchange * @fp: response frame - * @lport: Fibre Channel local port + * + * Handle incoming ELS requests that require port login. + * The ELS opcode has already been validated by the caller. * * Locking Note: Called with the lport lock held. */ -void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, - struct fc_lport *lport) +static void fc_rport_recv_els_req(struct fc_lport *lport, + struct fc_seq *sp, struct fc_frame *fp) { struct fc_rport_priv *rdata; struct fc_frame_header *fh; struct fc_seq_els_data els_data; - u32 s_id; - u8 op; els_data.fp = NULL; - els_data.explan = ELS_EXPL_NONE; - els_data.reason = ELS_RJT_NONE; - - op = fc_frame_payload_op(fp); - switch (op) { - case ELS_PLOGI: - fc_rport_recv_plogi_req(lport, sp, fp); - return; - default: - break; - } + els_data.reason = ELS_RJT_UNAB; + els_data.explan = ELS_EXPL_PLOGI_REQD; fh = fc_frame_header_get(fp); - s_id = ntoh24(fh->fh_s_id); mutex_lock(&lport->disc.disc_mutex); - rdata = lport->tt.rport_lookup(lport, s_id); + rdata = lport->tt.rport_lookup(lport, ntoh24(fh->fh_s_id)); if (!rdata) { mutex_unlock(&lport->disc.disc_mutex); - els_data.reason = ELS_RJT_UNAB; - lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data); - fc_frame_free(fp); - return; + goto reject; } mutex_lock(&rdata->rp_mutex); mutex_unlock(&lport->disc.disc_mutex); - switch (op) { + switch (rdata->rp_state) { + case RPORT_ST_PRLI: + case RPORT_ST_RTV: + case RPORT_ST_READY: + break; + default: + mutex_unlock(&rdata->rp_mutex); + goto reject; + } + + switch (fc_frame_payload_op(fp)) { case ELS_PRLI: fc_rport_recv_prli_req(rdata, sp, fp); break; case ELS_PRLO: fc_rport_recv_prlo_req(rdata, sp, fp); break; - case ELS_LOGO: - fc_rport_recv_logo_req(rdata, sp, fp); - break; case ELS_RRQ: els_data.fp = fp; lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data); @@ -973,12 +967,58 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data); break; default: - els_data.reason = ELS_RJT_UNSUP; - lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data); + fc_frame_free(fp); /* can't happen */ break; } mutex_unlock(&rdata->rp_mutex); + return; + +reject: + lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data); + fc_frame_free(fp); +} + +/** + * fc_rport_recv_req() - Handle a received ELS request from a rport + * @sp: current sequence in the PLOGI exchange + * @fp: response frame + * @lport: Fibre Channel local port + * + * Locking Note: Called with the lport lock held. + */ +void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, + struct fc_lport *lport) +{ + struct fc_seq_els_data els_data; + + /* + * Handle PLOGI and LOGO requests separately, since they + * don't require prior login. + * Check for unsupported opcodes first and reject them. + * For some ops, it would be incorrect to reject with "PLOGI required". + */ + switch (fc_frame_payload_op(fp)) { + case ELS_PLOGI: + fc_rport_recv_plogi_req(lport, sp, fp); + break; + case ELS_LOGO: + fc_rport_recv_logo_req(lport, sp, fp); + break; + case ELS_PRLI: + case ELS_PRLO: + case ELS_RRQ: + case ELS_REC: + fc_rport_recv_els_req(lport, sp, fp); + break; + default: + fc_frame_free(fp); + els_data.fp = NULL; + els_data.reason = ELS_RJT_UNSUP; + els_data.explan = ELS_EXPL_NONE; + lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data); + break; + } } /** @@ -1276,11 +1316,6 @@ static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata, FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n", fc_rport_state(rdata)); - if (rdata->rp_state == RPORT_ST_DELETE) { - fc_frame_free(fp); - return; - } - rjt_data.fp = NULL; rjt_data.reason = ELS_RJT_UNAB; rjt_data.explan = ELS_EXPL_NONE; @@ -1290,32 +1325,36 @@ static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata, /** * fc_rport_recv_logo_req() - Handle incoming Logout (LOGO) request - * @rdata: private remote port data + * @lport: local port. * @sp: current sequence in the LOGO exchange * @fp: LOGO request frame * * Locking Note: The rport lock is exected to be held before calling * this function. */ -static void fc_rport_recv_logo_req(struct fc_rport_priv *rdata, +static void fc_rport_recv_logo_req(struct fc_lport *lport, struct fc_seq *sp, struct fc_frame *fp) { struct fc_frame_header *fh; - struct fc_lport *lport = rdata->local_port; + struct fc_rport_priv *rdata; + u32 sid; fh = fc_frame_header_get(fp); + sid = ntoh24(fh->fh_s_id); - FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n", - fc_rport_state(rdata)); - - if (rdata->rp_state == RPORT_ST_DELETE) { - fc_frame_free(fp); - return; - } - - fc_rport_enter_delete(rdata, RPORT_EV_LOGO); - + mutex_lock(&lport->disc.disc_mutex); + rdata = lport->tt.rport_lookup(lport, sid); + if (rdata) { + mutex_lock(&rdata->rp_mutex); + FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n", + fc_rport_state(rdata)); + fc_rport_enter_delete(rdata, RPORT_EV_LOGO); + mutex_unlock(&rdata->rp_mutex); + } else + FC_RPORT_ID_DBG(lport, sid, + "Received LOGO from non-logged-in port\n"); + mutex_unlock(&lport->disc.disc_mutex); lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); fc_frame_free(fp); } -- cgit v1.2.3-18-g5258 From feab4ae73031699fcf92a88f4b1e4ec1b14157a5 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:03:36 -0700 Subject: [SCSI] libfc: re-login to remote ports that send us LOGO After a quick link flap, a target was seen to send us a LOGO. Apparently, it saw an RSCN reporting that we had dropped out of the fabric after we had logged back into it. This is likely in larger fabrics (more than 2 FC switches) after a quick link flap at the initiator. Each link transition causes an port-specific RSCN to the target. After the link comes back up, the initiator successfully discovers and does a PLOGI to the target before the target sees the first RSCN reporting the initiator is gone, and it sends a LOGO. The target may see a subsequent RSCN saying the port is back, but probably wouldn't send a PLOGI and leaves it up to the initiator to re-login. An RSCN can be delayed by the switches due to software layers but a PLOGI is forwarded in hardware causing the PLOGI to beat the RSCN. If a remote port is in the discovered set and sends a LOGO, re-login to it. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 04e9846ad1b..dc97c603744 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -1340,6 +1340,8 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport, struct fc_rport_priv *rdata; u32 sid; + lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); + fh = fc_frame_header_get(fp); sid = ntoh24(fh->fh_s_id); @@ -1349,13 +1351,20 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport, mutex_lock(&rdata->rp_mutex); FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n", fc_rport_state(rdata)); - fc_rport_enter_delete(rdata, RPORT_EV_LOGO); + + /* + * If the remote port was created due to discovery, + * log back in. It may have seen a stale RSCN about us. + */ + if (rdata->rp_state != RPORT_ST_DELETE && rdata->disc_id) + fc_rport_enter_plogi(rdata); + else + fc_rport_enter_delete(rdata, RPORT_EV_LOGO); mutex_unlock(&rdata->rp_mutex); } else FC_RPORT_ID_DBG(lport, sid, "Received LOGO from non-logged-in port\n"); mutex_unlock(&lport->disc.disc_mutex); - lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); fc_frame_free(fp); } -- cgit v1.2.3-18-g5258 From 68a1750b46ad5177f7703081b5fe85624f1aa62b Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:03:42 -0700 Subject: [SCSI] libfc: LOGO response code had extraeous enter_rtv fc_rport_logo_resp() had a call to fc_rport_enter_rtv() if the LOGO was accepted. This must've been a copy/paste mistake, but it didn't matter since we don't stay in the LOGO state long enough to hit this code. Change fc_rport_logo_resp() to just enter the delete state no matter what. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index dc97c603744..b5bc8724e1a 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -725,12 +725,10 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, } op = fc_frame_payload_op(fp); - if (op == ELS_LS_ACC) { - fc_rport_enter_rtv(rdata); - } else { - FC_RPORT_DBG(rdata, "Bad ELS response for LOGO command\n"); - fc_rport_enter_delete(rdata, RPORT_EV_LOGO); - } + if (op != ELS_LS_ACC) + FC_RPORT_DBG(rdata, "Bad ELS response op %x for LOGO command\n", + op); + fc_rport_enter_delete(rdata, RPORT_EV_LOGO); out: fc_frame_free(fp); -- cgit v1.2.3-18-g5258 From 370c3bd05cf02afabea9cd3f2de66202d6b516dc Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:03:47 -0700 Subject: [SCSI] libfc: use ADISC to verify rport login state When rport_login is called on an rport that is already thought to be logged in, use ADISC. If that fails, redo PLOGI. This is less disruptive after fabric changes that don't affect the state of the target. Implement the sending of ADISC via fc_els_fill. Add ADISC state to the rport state machine. This is entered from READY and returns to READY after successful completion. If it fails, the rport is either logged off and deleted or re-does PLOGI. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 122 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 117 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index b5bc8724e1a..c33e2585108 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -62,6 +62,7 @@ static void fc_rport_enter_prli(struct fc_rport_priv *); static void fc_rport_enter_rtv(struct fc_rport_priv *); static void fc_rport_enter_ready(struct fc_rport_priv *); static void fc_rport_enter_logo(struct fc_rport_priv *); +static void fc_rport_enter_adisc(struct fc_rport_priv *); static void fc_rport_recv_plogi_req(struct fc_lport *, struct fc_seq *, struct fc_frame *); @@ -83,6 +84,7 @@ static const char *fc_rport_state_names[] = { [RPORT_ST_RTV] = "RTV", [RPORT_ST_READY] = "Ready", [RPORT_ST_LOGO] = "LOGO", + [RPORT_ST_ADISC] = "ADISC", [RPORT_ST_DELETE] = "Delete", }; @@ -326,15 +328,25 @@ static void fc_rport_work(struct work_struct *work) * Locking Note: Called without the rport lock held. This * function will hold the rport lock, call an _enter_* * function and then unlock the rport. + * + * This indicates the intent to be logged into the remote port. + * If it appears we are already logged in, ADISC is used to verify + * the setup. */ int fc_rport_login(struct fc_rport_priv *rdata) { mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rdata, "Login to port\n"); - - fc_rport_enter_plogi(rdata); - + switch (rdata->rp_state) { + case RPORT_ST_READY: + FC_RPORT_DBG(rdata, "ADISC port\n"); + fc_rport_enter_adisc(rdata); + break; + default: + FC_RPORT_DBG(rdata, "Login to port\n"); + fc_rport_enter_plogi(rdata); + break; + } mutex_unlock(&rdata->rp_mutex); return 0; @@ -448,6 +460,9 @@ static void fc_rport_timeout(struct work_struct *work) case RPORT_ST_LOGO: fc_rport_enter_logo(rdata); break; + case RPORT_ST_ADISC: + fc_rport_enter_adisc(rdata); + break; case RPORT_ST_READY: case RPORT_ST_INIT: case RPORT_ST_DELETE: @@ -473,13 +488,16 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp) switch (rdata->rp_state) { case RPORT_ST_PLOGI: - case RPORT_ST_PRLI: case RPORT_ST_LOGO: fc_rport_enter_delete(rdata, RPORT_EV_FAILED); break; case RPORT_ST_RTV: fc_rport_enter_ready(rdata); break; + case RPORT_ST_PRLI: + case RPORT_ST_ADISC: + fc_rport_enter_logo(rdata); + break; case RPORT_ST_DELETE: case RPORT_ST_READY: case RPORT_ST_INIT: @@ -906,6 +924,93 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata) kref_get(&rdata->kref); } +/** + * fc_rport_els_adisc_resp() - Address Discovery response handler + * @sp: current sequence in the ADISC exchange + * @fp: response frame + * @rdata_arg: remote port private. + * + * Locking Note: This function will be called without the rport lock + * held, but it will lock, call an _enter_* function or fc_rport_error + * and then unlock the rport. + */ +static void fc_rport_adisc_resp(struct fc_seq *sp, struct fc_frame *fp, + void *rdata_arg) +{ + struct fc_rport_priv *rdata = rdata_arg; + struct fc_els_adisc *adisc; + u8 op; + + mutex_lock(&rdata->rp_mutex); + + FC_RPORT_DBG(rdata, "Received a ADISC response\n"); + + if (rdata->rp_state != RPORT_ST_ADISC) { + FC_RPORT_DBG(rdata, "Received a ADISC resp but in state %s\n", + fc_rport_state(rdata)); + if (IS_ERR(fp)) + goto err; + goto out; + } + + if (IS_ERR(fp)) { + fc_rport_error(rdata, fp); + goto err; + } + + /* + * If address verification failed. Consider us logged out of the rport. + * Since the rport is still in discovery, we want to be + * logged in, so go to PLOGI state. Otherwise, go back to READY. + */ + op = fc_frame_payload_op(fp); + adisc = fc_frame_payload_get(fp, sizeof(*adisc)); + if (op != ELS_LS_ACC || !adisc || + ntoh24(adisc->adisc_port_id) != rdata->ids.port_id || + get_unaligned_be64(&adisc->adisc_wwpn) != rdata->ids.port_name || + get_unaligned_be64(&adisc->adisc_wwnn) != rdata->ids.node_name) { + FC_RPORT_DBG(rdata, "ADISC error or mismatch\n"); + fc_rport_enter_plogi(rdata); + } else { + FC_RPORT_DBG(rdata, "ADISC OK\n"); + fc_rport_enter_ready(rdata); + } +out: + fc_frame_free(fp); +err: + mutex_unlock(&rdata->rp_mutex); + kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); +} + +/** + * fc_rport_enter_adisc() - Send Address Discover (ADISC) request to peer + * @rdata: remote port private data + * + * Locking Note: The rport lock is expected to be held before calling + * this routine. + */ +static void fc_rport_enter_adisc(struct fc_rport_priv *rdata) +{ + struct fc_lport *lport = rdata->local_port; + struct fc_frame *fp; + + FC_RPORT_DBG(rdata, "sending ADISC from %s state\n", + fc_rport_state(rdata)); + + fc_rport_state_enter(rdata, RPORT_ST_ADISC); + + fp = fc_frame_alloc(lport, sizeof(struct fc_els_adisc)); + if (!fp) { + fc_rport_error_retry(rdata, fp); + return; + } + if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_ADISC, + fc_rport_adisc_resp, rdata, lport->e_d_tov)) + fc_rport_error_retry(rdata, fp); + else + kref_get(&rdata->kref); +} + /** * fc_rport_recv_els_req() - handle a validated ELS request. * @lport: Fibre Channel local port @@ -943,6 +1048,7 @@ static void fc_rport_recv_els_req(struct fc_lport *lport, case RPORT_ST_PRLI: case RPORT_ST_RTV: case RPORT_ST_READY: + case RPORT_ST_ADISC: break; default: mutex_unlock(&rdata->rp_mutex); @@ -1095,6 +1201,10 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport, break; case RPORT_ST_PRLI: case RPORT_ST_READY: + case RPORT_ST_ADISC: + FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d " + "- ignored for now\n", rdata->rp_state); + /* XXX TBD - should reset */ break; case RPORT_ST_DELETE: default: @@ -1178,6 +1288,7 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, case RPORT_ST_PRLI: case RPORT_ST_RTV: case RPORT_ST_READY: + case RPORT_ST_ADISC: reason = ELS_RJT_NONE; break; default: @@ -1283,6 +1394,7 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, fc_rport_enter_ready(rdata); break; case RPORT_ST_READY: + case RPORT_ST_ADISC: break; default: break; -- cgit v1.2.3-18-g5258 From 8abbe3a42324264c9d5cc4e7c3d265b5be6d82d6 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:03:52 -0700 Subject: [SCSI] libfc: fix handling of incoming Discover Address (ADISC) requests The local port facility has been replying to ADISC requests without looking to see if the remote port is logged in. This is incorrect. An ADISC request requires PLOGI first. It should be rejected if the sending remote port is not logged in. This is like other incoming requests that require login, all of which should be handled in the remote port module. Move the ADISC request handling from fc_lport.c to fc_rport.c. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_lport.c | 53 ------------------------------------------- drivers/scsi/libfc/fc_rport.c | 48 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 3f2f7239014..bd2f7719744 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -451,56 +451,6 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, fc_frame_free(in_fp); } -/** - * fc_lport_recv_adisc_req() - Handle received Address Discovery Request - * @lport: Fibre Channel local port recieving the ADISC - * @sp: current sequence in the ADISC exchange - * @fp: ADISC request frame - * - * Locking Note: The lport lock is expected to be held before calling - * this function. - */ -static void fc_lport_recv_adisc_req(struct fc_seq *sp, struct fc_frame *in_fp, - struct fc_lport *lport) -{ - struct fc_frame *fp; - struct fc_exch *ep = fc_seq_exch(sp); - struct fc_els_adisc *req, *rp; - struct fc_seq_els_data rjt_data; - size_t len; - u32 f_ctl; - - FC_LPORT_DBG(lport, "Received ADISC request while in state %s\n", - fc_lport_state(lport)); - - req = fc_frame_payload_get(in_fp, sizeof(*req)); - if (!req) { - rjt_data.fp = NULL; - rjt_data.reason = ELS_RJT_LOGIC; - rjt_data.explan = ELS_EXPL_NONE; - lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); - } else { - len = sizeof(*rp); - fp = fc_frame_alloc(lport, len); - if (fp) { - rp = fc_frame_payload_get(fp, len); - memset(rp, 0, len); - rp->adisc_cmd = ELS_LS_ACC; - rp->adisc_wwpn = htonll(lport->wwpn); - rp->adisc_wwnn = htonll(lport->wwnn); - hton24(rp->adisc_port_id, - fc_host_port_id(lport->host)); - sp = lport->tt.seq_start_next(sp); - f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ; - f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT; - fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, - FC_TYPE_ELS, f_ctl, 0); - lport->tt.seq_send(lport, sp, fp); - } - } - fc_frame_free(in_fp); -} - /** * fc_lport_recv_logo_req() - Handle received fabric LOGO request * @lport: Fibre Channel local port recieving the LOGO @@ -849,9 +799,6 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, case ELS_RNID: recv = fc_lport_recv_rnid_req; break; - case ELS_ADISC: - recv = fc_lport_recv_adisc_req; - break; } recv(sp, fp, lport); diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index c33e2585108..03ea6748e7e 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -1011,6 +1011,50 @@ static void fc_rport_enter_adisc(struct fc_rport_priv *rdata) kref_get(&rdata->kref); } +/** + * fc_rport_recv_adisc_req() - Handle incoming Address Discovery (ADISC) Request + * @rdata: remote port private + * @sp: current sequence in the ADISC exchange + * @in_fp: ADISC request frame + * + * Locking Note: Called with the lport and rport locks held. + */ +static void fc_rport_recv_adisc_req(struct fc_rport_priv *rdata, + struct fc_seq *sp, struct fc_frame *in_fp) +{ + struct fc_lport *lport = rdata->local_port; + struct fc_frame *fp; + struct fc_exch *ep = fc_seq_exch(sp); + struct fc_els_adisc *adisc; + struct fc_seq_els_data rjt_data; + u32 f_ctl; + + FC_RPORT_DBG(rdata, "Received ADISC request\n"); + + adisc = fc_frame_payload_get(in_fp, sizeof(*adisc)); + if (!adisc) { + rjt_data.fp = NULL; + rjt_data.reason = ELS_RJT_PROT; + rjt_data.explan = ELS_EXPL_INV_LEN; + lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); + goto drop; + } + + fp = fc_frame_alloc(lport, sizeof(*adisc)); + if (!fp) + goto drop; + fc_adisc_fill(lport, fp); + adisc = fc_frame_payload_get(fp, sizeof(*adisc)); + adisc->adisc_cmd = ELS_LS_ACC; + sp = lport->tt.seq_start_next(sp); + f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT; + fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, + FC_TYPE_ELS, f_ctl, 0); + lport->tt.seq_send(lport, sp, fp); +drop: + fc_frame_free(in_fp); +} + /** * fc_rport_recv_els_req() - handle a validated ELS request. * @lport: Fibre Channel local port @@ -1062,6 +1106,9 @@ static void fc_rport_recv_els_req(struct fc_lport *lport, case ELS_PRLO: fc_rport_recv_prlo_req(rdata, sp, fp); break; + case ELS_ADISC: + fc_rport_recv_adisc_req(rdata, sp, fp); + break; case ELS_RRQ: els_data.fp = fp; lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data); @@ -1111,6 +1158,7 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, break; case ELS_PRLI: case ELS_PRLO: + case ELS_ADISC: case ELS_RRQ: case ELS_REC: fc_rport_recv_els_req(lport, sp, fp); -- cgit v1.2.3-18-g5258 From 2ab7e1ecb81ce35ed8e8df512e3fc6338a4c55bb Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:03:58 -0700 Subject: [SCSI] libfc: send GPN_ID in reaction to single-port RSCNs. When an RSCN indicates changes to individual remote ports, don't blindly log them out and then back in. Instead, determine whether they're still in the directory, by doing GPN_ID. If that is successful, call login, which will send ADISC and reverify, otherwise, call logoff. Perhaps we should just delete the rport, not send LOGO, but it seems safer. Also, fix a possible issue where if a mix of records in the RSCN cause us to queue disc_ports for disc_single and then we decide to do full rediscovery, we leak memory for those disc_ports queued. So, go through the list of disc_ports even if doing full discovery. Free the disc_ports in any case. If any of the disc_single() calls return error, do a full discovery. The ability to fill in GPN_ID requests was added to fc_ct_fill(). For this, it needs the FC_ID to be passed in as an arg. The did parameter for fc_elsct_send() is used for that, since the actual D_DID will always be 0xfffffc for all CT requests so far. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 137 ++++++++++++++++++++++++++++++++++-------- drivers/scsi/libfc/fc_elsct.c | 2 +- 2 files changed, 114 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 4242894cce7..c48799e9dd8 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -47,7 +47,7 @@ static void fc_disc_gpn_ft_req(struct fc_disc *); static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); static void fc_disc_done(struct fc_disc *, enum fc_disc_event); static void fc_disc_timeout(struct work_struct *); -static void fc_disc_single(struct fc_disc *, struct fc_disc_port *); +static int fc_disc_single(struct fc_lport *, struct fc_disc_port *); static void fc_disc_restart(struct fc_disc *); /** @@ -83,7 +83,6 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, struct fc_disc *disc) { struct fc_lport *lport; - struct fc_rport_priv *rdata; struct fc_els_rscn *rp; struct fc_els_rscn_page *pp; struct fc_seq_els_data rjt_data; @@ -150,6 +149,19 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, } } lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); + + /* + * If not doing a complete rediscovery, do GPN_ID on + * the individual ports mentioned in the list. + * If any of these get an error, do a full rediscovery. + * In any case, go through the list and free the entries. + */ + list_for_each_entry_safe(dp, next, &disc_ports, peers) { + list_del(&dp->peers); + if (!redisc) + redisc = fc_disc_single(lport, dp); + kfree(dp); + } if (redisc) { FC_DISC_DBG(disc, "RSCN received: rediscovering\n"); fc_disc_restart(disc); @@ -157,14 +169,6 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, FC_DISC_DBG(disc, "RSCN received: not rediscovering. " "redisc %d state %d in_prog %d\n", redisc, lport->state, disc->pending); - list_for_each_entry_safe(dp, next, &disc_ports, peers) { - list_del(&dp->peers); - rdata = lport->tt.rport_lookup(lport, dp->port_id); - if (rdata) { - lport->tt.rport_logoff(rdata); - } - fc_disc_single(disc, dp); - } } fc_frame_free(fp); return; @@ -562,32 +566,117 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, } /** - * fc_disc_single() - Discover the directory information for a single target - * @lport: FC local port - * @dp: The port to rediscover + * fc_disc_gpn_id_resp() - Handle a response frame from Get Port Names (GPN_ID) + * @sp: exchange sequence + * @fp: response frame + * @rdata_arg: remote port private data * - * Locking Note: This function expects that the disc_mutex is locked - * before it is called. + * Locking Note: This function is called without disc mutex held. */ -static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) +static void fc_disc_gpn_id_resp(struct fc_seq *sp, struct fc_frame *fp, + void *rdata_arg) { + struct fc_rport_priv *rdata = rdata_arg; + struct fc_rport_priv *new_rdata; struct fc_lport *lport; - struct fc_rport_priv *rdata; + struct fc_disc *disc; + struct fc_ct_hdr *cp; + struct fc_ns_gid_pn *pn; + u64 port_name; - lport = disc->lport; + lport = rdata->local_port; + disc = &lport->disc; - if (dp->port_id == fc_host_port_id(lport->host)) + mutex_lock(&disc->disc_mutex); + if (PTR_ERR(fp) == -FC_EX_CLOSED) goto out; + if (IS_ERR(fp)) + goto redisc; + + cp = fc_frame_payload_get(fp, sizeof(*cp)); + if (!cp) + goto redisc; + if (ntohs(cp->ct_cmd) == FC_FS_ACC) { + if (fr_len(fp) < sizeof(struct fc_frame_header) + + sizeof(*cp) + sizeof(*pn)) + goto redisc; + pn = (struct fc_ns_gid_pn *)(cp + 1); + port_name = get_unaligned_be64(&pn->fn_wwpn); + if (rdata->ids.port_name == -1) + rdata->ids.port_name = port_name; + else if (rdata->ids.port_name != port_name) { + FC_DISC_DBG(disc, "GPN_ID accepted. WWPN changed. " + "Port-id %x wwpn %llx\n", + rdata->ids.port_id, port_name); + lport->tt.rport_logoff(rdata); - rdata = lport->tt.rport_create(lport, dp->port_id); - if (rdata) { + new_rdata = lport->tt.rport_create(lport, + rdata->ids.port_id); + if (new_rdata) { + new_rdata->disc_id = disc->disc_id; + lport->tt.rport_login(new_rdata); + } + goto out; + } rdata->disc_id = disc->disc_id; - kfree(dp); lport->tt.rport_login(rdata); + } else if (ntohs(cp->ct_cmd) == FC_FS_RJT) { + FC_DISC_DBG(disc, "GPN_ID rejected reason %x exp %x\n", + cp->ct_reason, cp->ct_explan); + lport->tt.rport_logoff(rdata); + } else { + FC_DISC_DBG(disc, "GPN_ID unexpected response code %x\n", + ntohs(cp->ct_cmd)); +redisc: + fc_disc_restart(disc); } - return; out: - kfree(dp); + mutex_unlock(&disc->disc_mutex); + kref_put(&rdata->kref, lport->tt.rport_destroy); +} + +/** + * fc_disc_gpn_id_req() - Send Get Port Names by ID (GPN_ID) request + * @lport: local port + * @rdata: remote port private data + * + * Locking Note: This function expects that the disc_mutex is locked + * before it is called. + * On failure, an error code is returned. + */ +static int fc_disc_gpn_id_req(struct fc_lport *lport, + struct fc_rport_priv *rdata) +{ + struct fc_frame *fp; + + fp = fc_frame_alloc(lport, sizeof(struct fc_ct_hdr) + + sizeof(struct fc_ns_fid)); + if (!fp) + return -ENOMEM; + if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, FC_NS_GPN_ID, + fc_disc_gpn_id_resp, rdata, lport->e_d_tov)) + return -ENOMEM; + kref_get(&rdata->kref); + return 0; +} + +/** + * fc_disc_single() - Discover the directory information for a single target + * @lport: local port + * @dp: The port to rediscover + * + * Locking Note: This function expects that the disc_mutex is locked + * before it is called. + */ +static int fc_disc_single(struct fc_lport *lport, struct fc_disc_port *dp) +{ + struct fc_rport_priv *rdata; + + rdata = lport->tt.rport_create(lport, dp->port_id); + if (!rdata) + return -ENOMEM; + rdata->disc_id = 0; + return fc_disc_gpn_id_req(lport, rdata); } /** diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c index d655924d46b..5cfa68732e9 100644 --- a/drivers/scsi/libfc/fc_elsct.c +++ b/drivers/scsi/libfc/fc_elsct.c @@ -49,7 +49,7 @@ static struct fc_seq *fc_elsct_send(struct fc_lport *lport, rc = fc_els_fill(lport, did, fp, op, &r_ctl, &fh_type); else { /* CT requests */ - rc = fc_ct_fill(lport, fp, op, &r_ctl, &fh_type); + rc = fc_ct_fill(lport, did, fp, op, &r_ctl, &fh_type); did = FC_FID_DIR_SERV; } -- cgit v1.2.3-18-g5258 From 1d490ce33ee8b93638d09e471a3bc66ae33b6606 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:04:03 -0700 Subject: [SCSI] libfc: don't swap OX_ID and RX_ID when sending BA_RJT I saw an lport debug message from the exchange manager saying: "lport 70500: Received response for out of range oxid:ffff" A trace showed this was a BA_RJT sent due to an incoming ABTS which arrived on an unknown exchange. So, the sender of the BA_RJT was in error, but in this case, both the initiator and responder were the same machine. The OX_ID and RX_ID should not have been reversed in this case. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_exch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index b51db15a387..c1c15748220 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -1017,8 +1017,8 @@ static void fc_exch_send_ba_rjt(struct fc_frame *rx_fp, */ memcpy(fh->fh_s_id, rx_fh->fh_d_id, 3); memcpy(fh->fh_d_id, rx_fh->fh_s_id, 3); - fh->fh_ox_id = rx_fh->fh_rx_id; - fh->fh_rx_id = rx_fh->fh_ox_id; + fh->fh_ox_id = rx_fh->fh_ox_id; + fh->fh_rx_id = rx_fh->fh_rx_id; fh->fh_seq_cnt = rx_fh->fh_seq_cnt; fh->fh_r_ctl = FC_RCTL_BA_RJT; fh->fh_type = FC_TYPE_BLS; -- cgit v1.2.3-18-g5258 From e7a51997dad4e17395be1209970e18d2e9305b24 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:04:08 -0700 Subject: [SCSI] fcoe: flush per-cpu thread work when destroying interface This fixes one cause of an occational problem when unloading libfc where the exchange manager pool doesn't have all items freed. The existing WARN_ON(mp->total_exches <= 0) isn't hit. However, note that total_exches is decremented when the exchange is completed, and it can be held with a refcnt for a while after that. I'm not sure what the offending exchange is, but I suspect it is an incoming request, because outgoing state machines should be all stopped at this point. Note that although receive is stopped before the exchange manager is freed, there could still be active threads handling received frames. This patch flushes the queues by allocating a new skb and sending it through, and have the thread handle this new skb specially. This is similar to the way the work queues are flushed now by putting work items in them and waiting until they make it through the queue. An skb->destructor function is used to inform us of the completion of the flush, and the fr_dev() is left NULL to indicate to fcoe_percpu_receive_thread() that the skb should be just freed. There's already a check for the lp being NULL which prints a message. We skip printing the message if the destructor is for flushing. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index ac481ad112a..704b8e03494 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -57,6 +57,9 @@ MODULE_PARM_DESC(ddp_min, "Minimum I/O size in bytes for " \ DEFINE_MUTEX(fcoe_config_mutex); +/* fcoe_percpu_clean completion. Waiter protected by fcoe_create_mutex */ +static DECLARE_COMPLETION(fcoe_flush_completion); + /* fcoe host list */ /* must only by accessed under the RTNL mutex */ LIST_HEAD(fcoe_hostlist); @@ -827,7 +830,7 @@ static void fcoe_percpu_thread_create(unsigned int cpu) thread = kthread_create(fcoe_percpu_receive_thread, (void *)p, "fcoethread/%d", cpu); - if (likely(!IS_ERR(p->thread))) { + if (likely(!IS_ERR(thread))) { kthread_bind(thread, cpu); wake_up_process(thread); @@ -1299,6 +1302,15 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) return 0; } +/** + * fcoe_percpu_flush_done() - Indicate percpu queue flush completion. + * @skb: the skb being completed. + */ +static void fcoe_percpu_flush_done(struct sk_buff *skb) +{ + complete(&fcoe_flush_completion); +} + /** * fcoe_percpu_receive_thread() - recv thread per cpu * @arg: ptr to the fcoe per cpu struct @@ -1338,7 +1350,8 @@ int fcoe_percpu_receive_thread(void *arg) fr = fcoe_dev_from_skb(skb); lp = fr->fr_dev; if (unlikely(lp == NULL)) { - FCOE_NETDEV_DBG(skb->dev, "Invalid HBA Structure"); + if (skb->destructor != fcoe_percpu_flush_done) + FCOE_NETDEV_DBG(skb->dev, "NULL lport in skb"); kfree_skb(skb); continue; } @@ -1799,6 +1812,13 @@ int fcoe_link_ok(struct fc_lport *lp) /** * fcoe_percpu_clean() - Clear the pending skbs for an lport * @lp: the fc_lport + * + * Must be called with fcoe_create_mutex held to single-thread completion. + * + * This flushes the pending skbs by adding a new skb to each queue and + * waiting until they are all freed. This assures us that not only are + * there no packets that will be handled by the lport, but also that any + * threads already handling packet have returned. */ void fcoe_percpu_clean(struct fc_lport *lp) { @@ -1823,7 +1843,25 @@ void fcoe_percpu_clean(struct fc_lport *lp) kfree_skb(skb); } } + + if (!pp->thread || !cpu_online(cpu)) { + spin_unlock_bh(&pp->fcoe_rx_list.lock); + continue; + } + + skb = dev_alloc_skb(0); + if (!skb) { + spin_unlock_bh(&pp->fcoe_rx_list.lock); + continue; + } + skb->destructor = fcoe_percpu_flush_done; + + __skb_queue_tail(&pp->fcoe_rx_list, skb); + if (pp->fcoe_rx_list.qlen == 1) + wake_up_process(pp->thread); spin_unlock_bh(&pp->fcoe_rx_list.lock); + + wait_for_completion(&fcoe_flush_completion); } } -- cgit v1.2.3-18-g5258 From 0d03d59d9b31cd1e33b7e46a80b6fef66244b1f2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 10 Sep 2009 23:13:28 +0200 Subject: md: Fix "strchr" [drivers/md/dm-log-userspace.ko] undefined! Commit b8313b6da7e2e7c7f47d93d8561969a3ff9ba0ea ("dm log: remove incorrect field from userspace table output") added a call to strstr() with a single-character "needle" string parameter. Unfortunately some versions of gcc replace such calls to strstr() by calls to strchr() behind our back. This causes linking errors if strchr() is defined as an inline function in (e.g. on m68k): | WARNING: "strchr" [drivers/md/dm-log-userspace.ko] undefined! Avoid this by explicitly calling strchr() instead. Signed-off-by: Geert Uytterhoeven Cc: stable@kernel.org Signed-off-by: Linus Torvalds --- drivers/md/dm-log-userspace-base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/dm-log-userspace-base.c b/drivers/md/dm-log-userspace-base.c index 6e186b1a062..652bd33109e 100644 --- a/drivers/md/dm-log-userspace-base.c +++ b/drivers/md/dm-log-userspace-base.c @@ -582,7 +582,7 @@ static int userspace_status(struct dm_dirty_log *log, status_type_t status_type, break; case STATUSTYPE_TABLE: sz = 0; - table_args = strstr(lc->usr_argv_str, " "); + table_args = strchr(lc->usr_argv_str, ' '); BUG_ON(!table_args); /* There will always be a ' ' */ table_args++; -- cgit v1.2.3-18-g5258 From 1c7827ae70e7c8456e08f7bb9ef2238d27814cbe Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 3 Sep 2009 21:45:34 -0700 Subject: Input: i8042 - bypass AUX IRQ delivery test on laptops It seems that many laptops do not fully implement AUX LOOP command in their keyboard controllers, causing issues with touchpad detection. We know however that almost every laptop/portable uses a PS/2 pointing device and, even if user disables it in favor of an external mouse, the system will not use IRQ 12 for anything else. Therefore we may bypass AUX IRQ delivery test when running on a laptop and assume that it is routed properly. Just to be safe we require the box to have good PNP data in order to bypass the test. [Jin Dongming : fix crash caused by missing terminator in the DMI table] Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042-x86ia64io.h | 33 +++++++++++++++++++++++++++++++++ drivers/input/serio/i8042.c | 4 +++- 2 files changed, 36 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index ae04d8a494e..66829a860ee 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -449,6 +449,34 @@ static struct dmi_system_id __initdata i8042_dmi_nopnp_table[] = { }, { } }; + +static struct dmi_system_id __initdata i8042_dmi_laptop_table[] = { + { + .ident = "Portable", + .matches = { + DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ + }, + }, + { + .ident = "Laptop", + .matches = { + DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */ + }, + }, + { + .ident = "Notebook", + .matches = { + DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */ + }, + }, + { + .ident = "Sub-Notebook", + .matches = { + DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */ + }, + }, + { } +}; #endif /* @@ -727,6 +755,11 @@ static int __init i8042_pnp_init(void) i8042_kbd_irq = i8042_pnp_kbd_irq; i8042_aux_irq = i8042_pnp_aux_irq; +#ifdef CONFIG_X86 + i8042_bypass_aux_irq_test = !pnp_data_busted && + dmi_check_system(i8042_dmi_laptop_table); +#endif + return 0; } diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 9f5c0506242..b53a015bf8a 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -83,6 +83,8 @@ module_param_named(debug, i8042_debug, bool, 0600); MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off"); #endif +static bool i8042_bypass_aux_irq_test; + #include "i8042.h" static DEFINE_SPINLOCK(i8042_lock); @@ -641,7 +643,7 @@ static int __devinit i8042_check_aux(void) * used it for a PCI card or somethig else. */ - if (i8042_noloop || aux_loop_broken) { + if (i8042_noloop || i8042_bypass_aux_irq_test || aux_loop_broken) { /* * Without LOOP command we can't test AUX IRQ delivery. Assume the port * is working and hope we are right. -- cgit v1.2.3-18-g5258 From 7cac9cd935533e52e277c0c8799a8ba16c24f250 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 3 Sep 2009 21:57:48 -0700 Subject: Input: sunkbd - fix formatting Adjust the way 'switch' statements were indented; make sure we stay under 80 ciolumns. Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/sunkbd.c | 128 +++++++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index e7aa935a294..472b56639cd 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -73,7 +73,7 @@ static unsigned char sunkbd_keycode[128] = { */ struct sunkbd { - unsigned char keycode[128]; + unsigned char keycode[ARRAY_SIZE(sunkbd_keycode)]; struct input_dev *dev; struct serio *serio; struct work_struct tq; @@ -81,7 +81,7 @@ struct sunkbd { char name[64]; char phys[32]; char type; - unsigned char enabled; + bool enabled; volatile s8 reset; volatile s8 layout; }; @@ -94,10 +94,14 @@ struct sunkbd { static irqreturn_t sunkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags) { - struct sunkbd* sunkbd = serio_get_drvdata(serio); + struct sunkbd *sunkbd = serio_get_drvdata(serio); - if (sunkbd->reset <= -1) { /* If cp[i] is 0xff, sunkbd->reset will stay -1. */ - sunkbd->reset = data; /* The keyboard sends 0xff 0xff 0xID on powerup */ + if (sunkbd->reset <= -1) { + /* + * If cp[i] is 0xff, sunkbd->reset will stay -1. + * The keyboard sends 0xff 0xff 0xID on powerup. + */ + sunkbd->reset = data; wake_up_interruptible(&sunkbd->wait); goto out; } @@ -110,29 +114,33 @@ static irqreturn_t sunkbd_interrupt(struct serio *serio, switch (data) { - case SUNKBD_RET_RESET: - schedule_work(&sunkbd->tq); - sunkbd->reset = -1; - break; + case SUNKBD_RET_RESET: + schedule_work(&sunkbd->tq); + sunkbd->reset = -1; + break; - case SUNKBD_RET_LAYOUT: - sunkbd->layout = -1; - break; + case SUNKBD_RET_LAYOUT: + sunkbd->layout = -1; + break; - case SUNKBD_RET_ALLUP: /* All keys released */ + case SUNKBD_RET_ALLUP: /* All keys released */ + break; + + default: + if (!sunkbd->enabled) break; - default: - if (!sunkbd->enabled) - break; - - if (sunkbd->keycode[data & SUNKBD_KEY]) { - input_report_key(sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE)); - input_sync(sunkbd->dev); - } else { - printk(KERN_WARNING "sunkbd.c: Unknown key (scancode %#x) %s.\n", - data & SUNKBD_KEY, data & SUNKBD_RELEASE ? "released" : "pressed"); - } + if (sunkbd->keycode[data & SUNKBD_KEY]) { + input_report_key(sunkbd->dev, + sunkbd->keycode[data & SUNKBD_KEY], + !(data & SUNKBD_RELEASE)); + input_sync(sunkbd->dev); + } else { + printk(KERN_WARNING + "sunkbd.c: Unknown key (scancode %#x) %s.\n", + data & SUNKBD_KEY, + data & SUNKBD_RELEASE ? "released" : "pressed"); + } } out: return IRQ_HANDLED; @@ -142,34 +150,37 @@ out: * sunkbd_event() handles events from the input module. */ -static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +static int sunkbd_event(struct input_dev *dev, + unsigned int type, unsigned int code, int value) { struct sunkbd *sunkbd = input_get_drvdata(dev); switch (type) { - case EV_LED: + case EV_LED: - serio_write(sunkbd->serio, SUNKBD_CMD_SETLED); - serio_write(sunkbd->serio, - (!!test_bit(LED_CAPSL, dev->led) << 3) | (!!test_bit(LED_SCROLLL, dev->led) << 2) | - (!!test_bit(LED_COMPOSE, dev->led) << 1) | !!test_bit(LED_NUML, dev->led)); - return 0; + serio_write(sunkbd->serio, SUNKBD_CMD_SETLED); + serio_write(sunkbd->serio, + (!!test_bit(LED_CAPSL, dev->led) << 3) | + (!!test_bit(LED_SCROLLL, dev->led) << 2) | + (!!test_bit(LED_COMPOSE, dev->led) << 1) | + !!test_bit(LED_NUML, dev->led)); + return 0; - case EV_SND: + case EV_SND: - switch (code) { + switch (code) { - case SND_CLICK: - serio_write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value); - return 0; + case SND_CLICK: + serio_write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value); + return 0; - case SND_BELL: - serio_write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value); - return 0; - } + case SND_BELL: + serio_write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value); + return 0; + } - break; + break; } return -1; @@ -193,9 +204,12 @@ static int sunkbd_initialize(struct sunkbd *sunkbd) if (sunkbd->type == 4) { /* Type 4 keyboard */ sunkbd->layout = -2; serio_write(sunkbd->serio, SUNKBD_CMD_LAYOUT); - wait_event_interruptible_timeout(sunkbd->wait, sunkbd->layout >= 0, HZ/4); - if (sunkbd->layout < 0) return -1; - if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) sunkbd->type = 5; + wait_event_interruptible_timeout(sunkbd->wait, + sunkbd->layout >= 0, HZ / 4); + if (sunkbd->layout < 0) + return -1; + if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) + sunkbd->type = 5; } return 0; @@ -218,11 +232,13 @@ static void sunkbd_reinit(struct work_struct *work) (!!test_bit(LED_SCROLLL, sunkbd->dev->led) << 2) | (!!test_bit(LED_COMPOSE, sunkbd->dev->led) << 1) | !!test_bit(LED_NUML, sunkbd->dev->led)); - serio_write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev->snd)); - serio_write(sunkbd->serio, SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd)); + serio_write(sunkbd->serio, + SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev->snd)); + serio_write(sunkbd->serio, + SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd)); } -static void sunkbd_enable(struct sunkbd *sunkbd, int enable) +static void sunkbd_enable(struct sunkbd *sunkbd, bool enable) { serio_pause_rx(sunkbd->serio); sunkbd->enabled = enable; @@ -230,7 +246,8 @@ static void sunkbd_enable(struct sunkbd *sunkbd, int enable) } /* - * sunkbd_connect() probes for a Sun keyboard and fills the necessary structures. + * sunkbd_connect() probes for a Sun keyboard and fills the necessary + * structures. */ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv) @@ -262,7 +279,8 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv) goto fail3; } - snprintf(sunkbd->name, sizeof(sunkbd->name), "Sun Type %d keyboard", sunkbd->type); + snprintf(sunkbd->name, sizeof(sunkbd->name), + "Sun Type %d keyboard", sunkbd->type); memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode)); input_dev->name = sunkbd->name; @@ -286,11 +304,11 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv) input_dev->keycode = sunkbd->keycode; input_dev->keycodesize = sizeof(unsigned char); input_dev->keycodemax = ARRAY_SIZE(sunkbd_keycode); - for (i = 0; i < 128; i++) - set_bit(sunkbd->keycode[i], input_dev->keybit); - clear_bit(0, input_dev->keybit); + for (i = 0; i < ARRAY_SIZE(sunkbd_keycode); i++) + __set_bit(sunkbd->keycode[i], input_dev->keybit); + __clear_bit(KEY_RESERVED, input_dev->keybit); - sunkbd_enable(sunkbd, 1); + sunkbd_enable(sunkbd, true); err = input_register_device(sunkbd->dev); if (err) @@ -298,7 +316,7 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv) return 0; - fail4: sunkbd_enable(sunkbd, 0); + fail4: sunkbd_enable(sunkbd, false); fail3: serio_close(serio); fail2: serio_set_drvdata(serio, NULL); fail1: input_free_device(input_dev); @@ -314,7 +332,7 @@ static void sunkbd_disconnect(struct serio *serio) { struct sunkbd *sunkbd = serio_get_drvdata(serio); - sunkbd_enable(sunkbd, 0); + sunkbd_enable(sunkbd, false); input_unregister_device(sunkbd->dev); serio_close(serio); serio_set_drvdata(serio, NULL); -- cgit v1.2.3-18-g5258 From bd96f37895197563bc1d6d6f7c012b3ae7df1c45 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 4 Sep 2009 23:46:18 -0700 Subject: Input: pxa27x_keypad - allow modifying keymap from userspace Tested-by: Mike Rapoport Acked-by: Eric Miao Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/pxa27x_keypad.c | 173 +++++++++++++++++---------------- 1 file changed, 91 insertions(+), 82 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index c987cc75674..76f9668221a 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -32,7 +32,6 @@ #include #include - /* * Keypad Controller registers */ @@ -96,7 +95,8 @@ #define keypad_readl(off) __raw_readl(keypad->mmio_base + (off)) #define keypad_writel(off, v) __raw_writel((v), keypad->mmio_base + (off)) -#define MAX_MATRIX_KEY_NUM (8 * 8) +#define MAX_MATRIX_KEY_NUM (MAX_MATRIX_KEY_ROWS * MAX_MATRIX_KEY_COLS) +#define MAX_KEYPAD_KEYS (MAX_MATRIX_KEY_NUM + MAX_DIRECT_KEY_NUM) struct pxa27x_keypad { struct pxa27x_keypad_platform_data *pdata; @@ -107,73 +107,82 @@ struct pxa27x_keypad { int irq; - /* matrix key code map */ - unsigned short matrix_keycodes[MAX_MATRIX_KEY_NUM]; + unsigned short keycodes[MAX_KEYPAD_KEYS]; + int rotary_rel_code[2]; /* state row bits of each column scan */ uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS]; uint32_t direct_key_state; unsigned int direct_key_mask; - - int rotary_rel_code[2]; - int rotary_up_key[2]; - int rotary_down_key[2]; }; static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad) { struct pxa27x_keypad_platform_data *pdata = keypad->pdata; struct input_dev *input_dev = keypad->input_dev; + unsigned short keycode; int i; for (i = 0; i < pdata->matrix_key_map_size; i++) { unsigned int key = pdata->matrix_key_map[i]; unsigned int row = KEY_ROW(key); unsigned int col = KEY_COL(key); - unsigned short code = KEY_VAL(key); + unsigned int scancode = MATRIX_SCAN_CODE(row, col, + MATRIX_ROW_SHIFT); - keypad->matrix_keycodes[(row << 3) + col] = code; - __set_bit(code, input_dev->keybit); + keycode = KEY_VAL(key); + keypad->keycodes[scancode] = keycode; + __set_bit(keycode, input_dev->keybit); } - __clear_bit(KEY_RESERVED, input_dev->keybit); - - for (i = 0; i < pdata->direct_key_num; i++) - __set_bit(pdata->direct_key_map[i], input_dev->keybit); - keypad->rotary_up_key[0] = pdata->rotary0_up_key; - keypad->rotary_up_key[1] = pdata->rotary1_up_key; - keypad->rotary_down_key[0] = pdata->rotary0_down_key; - keypad->rotary_down_key[1] = pdata->rotary1_down_key; - keypad->rotary_rel_code[0] = pdata->rotary0_rel_code; - keypad->rotary_rel_code[1] = pdata->rotary1_rel_code; + for (i = 0; i < pdata->direct_key_num; i++) { + keycode = pdata->direct_key_map[i]; + keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = keycode; + __set_bit(keycode, input_dev->keybit); + } if (pdata->enable_rotary0) { if (pdata->rotary0_up_key && pdata->rotary0_down_key) { - __set_bit(pdata->rotary0_up_key, input_dev->keybit); - __set_bit(pdata->rotary0_down_key, input_dev->keybit); - } else + keycode = pdata->rotary0_up_key; + keypad->keycodes[MAX_MATRIX_KEY_NUM + 0] = keycode; + __set_bit(keycode, input_dev->keybit); + + keycode = pdata->rotary0_down_key; + keypad->keycodes[MAX_MATRIX_KEY_NUM + 1] = keycode; + __set_bit(keycode, input_dev->keybit); + + keypad->rotary_rel_code[0] = -1; + } else { + keypad->rotary_rel_code[0] = pdata->rotary0_rel_code; __set_bit(pdata->rotary0_rel_code, input_dev->relbit); + } } if (pdata->enable_rotary1) { if (pdata->rotary1_up_key && pdata->rotary1_down_key) { - __set_bit(pdata->rotary1_up_key, input_dev->keybit); - __set_bit(pdata->rotary1_down_key, input_dev->keybit); - } else + keycode = pdata->rotary1_up_key; + keypad->keycodes[MAX_MATRIX_KEY_NUM + 2] = keycode; + __set_bit(keycode, input_dev->keybit); + + keycode = pdata->rotary1_down_key; + keypad->keycodes[MAX_MATRIX_KEY_NUM + 3] = keycode; + __set_bit(keycode, input_dev->keybit); + + keypad->rotary_rel_code[1] = -1; + } else { + keypad->rotary_rel_code[1] = pdata->rotary1_rel_code; __set_bit(pdata->rotary1_rel_code, input_dev->relbit); + } } -} -static inline unsigned int lookup_matrix_keycode( - struct pxa27x_keypad *keypad, int row, int col) -{ - return keypad->matrix_keycodes[(row << 3) + col]; + __clear_bit(KEY_RESERVED, input_dev->keybit); } static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad) { struct pxa27x_keypad_platform_data *pdata = keypad->pdata; + struct input_dev *input_dev = keypad->input_dev; int row, col, num_keys_pressed = 0; uint32_t new_state[MAX_MATRIX_KEY_COLS]; uint32_t kpas = keypad_readl(KPAS); @@ -216,6 +225,7 @@ static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad) scan: for (col = 0; col < pdata->matrix_key_cols; col++) { uint32_t bits_changed; + int code; bits_changed = keypad->matrix_key_state[col] ^ new_state[col]; if (bits_changed == 0) @@ -225,12 +235,13 @@ scan: if ((bits_changed & (1 << row)) == 0) continue; - input_report_key(keypad->input_dev, - lookup_matrix_keycode(keypad, row, col), - new_state[col] & (1 << row)); + code = MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT); + input_event(input_dev, EV_MSC, MSC_SCAN, code); + input_report_key(input_dev, keypad->keycodes[code], + new_state[col] & (1 << row)); } } - input_sync(keypad->input_dev); + input_sync(input_dev); memcpy(keypad->matrix_key_state, new_state, sizeof(new_state)); } @@ -253,13 +264,15 @@ static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta) if (delta == 0) return; - if (keypad->rotary_up_key[r] && keypad->rotary_down_key[r]) { - int keycode = (delta > 0) ? keypad->rotary_up_key[r] : - keypad->rotary_down_key[r]; + if (keypad->rotary_rel_code[r] == -1) { + int code = MAX_MATRIX_KEY_NUM + 2 * r + (delta > 0 ? 0 : 1); + unsigned char keycode = keypad->keycodes[code]; /* simulate a press-n-release */ + input_event(dev, EV_MSC, MSC_SCAN, code); input_report_key(dev, keycode, 1); input_sync(dev); + input_event(dev, EV_MSC, MSC_SCAN, code); input_report_key(dev, keycode, 0); input_sync(dev); } else { @@ -287,6 +300,7 @@ static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad) static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad) { struct pxa27x_keypad_platform_data *pdata = keypad->pdata; + struct input_dev *input_dev = keypad->input_dev; unsigned int new_state; uint32_t kpdk, bits_changed; int i; @@ -296,9 +310,6 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad) if (pdata->enable_rotary0 || pdata->enable_rotary1) pxa27x_keypad_scan_rotary(keypad); - if (pdata->direct_key_map == NULL) - return; - new_state = KPDK_DK(kpdk) & keypad->direct_key_mask; bits_changed = keypad->direct_key_state ^ new_state; @@ -306,12 +317,15 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad) return; for (i = 0; i < pdata->direct_key_num; i++) { - if (bits_changed & (1 << i)) - input_report_key(keypad->input_dev, - pdata->direct_key_map[i], - (new_state & (1 << i))); + if (bits_changed & (1 << i)) { + int code = MAX_MATRIX_KEY_NUM + i; + + input_event(input_dev, EV_MSC, MSC_SCAN, code); + input_report_key(input_dev, keypad->keycodes[code], + new_state & (1 << i)); + } } - input_sync(keypad->input_dev); + input_sync(input_dev); keypad->direct_key_state = new_state; } @@ -432,38 +446,41 @@ static const struct dev_pm_ops pxa27x_keypad_pm_ops = { static int __devinit pxa27x_keypad_probe(struct platform_device *pdev) { + struct pxa27x_keypad_platform_data *pdata = pdev->dev.platform_data; struct pxa27x_keypad *keypad; struct input_dev *input_dev; struct resource *res; int irq, error; - keypad = kzalloc(sizeof(struct pxa27x_keypad), GFP_KERNEL); - if (keypad == NULL) { - dev_err(&pdev->dev, "failed to allocate driver data\n"); - return -ENOMEM; - } - - keypad->pdata = pdev->dev.platform_data; - if (keypad->pdata == NULL) { + if (pdata == NULL) { dev_err(&pdev->dev, "no platform data defined\n"); - error = -EINVAL; - goto failed_free; + return -EINVAL; } irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "failed to get keypad irq\n"); - error = -ENXIO; - goto failed_free; + return -ENXIO; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(&pdev->dev, "failed to get I/O memory\n"); - error = -ENXIO; + return -ENXIO; + } + + keypad = kzalloc(sizeof(struct pxa27x_keypad), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!keypad || !input_dev) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + error = -ENOMEM; goto failed_free; } + keypad->pdata = pdata; + keypad->input_dev = input_dev; + keypad->irq = irq; + res = request_mem_region(res->start, resource_size(res), pdev->name); if (res == NULL) { dev_err(&pdev->dev, "failed to request I/O memory\n"); @@ -485,43 +502,35 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev) goto failed_free_io; } - /* Create and register the input driver. */ - input_dev = input_allocate_device(); - if (!input_dev) { - dev_err(&pdev->dev, "failed to allocate input device\n"); - error = -ENOMEM; - goto failed_put_clk; - } - input_dev->name = pdev->name; input_dev->id.bustype = BUS_HOST; input_dev->open = pxa27x_keypad_open; input_dev->close = pxa27x_keypad_close; input_dev->dev.parent = &pdev->dev; - keypad->input_dev = input_dev; + input_dev->keycode = keypad->keycodes; + input_dev->keycodesize = sizeof(keypad->keycodes[0]); + input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes); + input_set_drvdata(input_dev, keypad); input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); - if ((keypad->pdata->enable_rotary0 && - keypad->pdata->rotary0_rel_code) || - (keypad->pdata->enable_rotary1 && - keypad->pdata->rotary1_rel_code)) { - input_dev->evbit[0] |= BIT_MASK(EV_REL); - } + input_set_capability(input_dev, EV_MSC, MSC_SCAN); pxa27x_keypad_build_keycode(keypad); - platform_set_drvdata(pdev, keypad); + + if ((pdata->enable_rotary0 && keypad->rotary_rel_code[0] != -1) || + (pdata->enable_rotary1 && keypad->rotary_rel_code[1] != -1)) { + input_dev->evbit[0] |= BIT_MASK(EV_REL); + } error = request_irq(irq, pxa27x_keypad_irq_handler, IRQF_DISABLED, pdev->name, keypad); if (error) { dev_err(&pdev->dev, "failed to request IRQ\n"); - goto failed_free_dev; + goto failed_put_clk; } - keypad->irq = irq; - /* Register the input device */ error = input_register_device(input_dev); if (error) { @@ -529,15 +538,13 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev) goto failed_free_irq; } + platform_set_drvdata(pdev, keypad); device_init_wakeup(&pdev->dev, 1); return 0; failed_free_irq: free_irq(irq, pdev); - platform_set_drvdata(pdev, NULL); -failed_free_dev: - input_free_device(input_dev); failed_put_clk: clk_put(keypad->clk); failed_free_io: @@ -545,6 +552,7 @@ failed_free_io: failed_free_mem: release_mem_region(res->start, resource_size(res)); failed_free: + input_free_device(input_dev); kfree(keypad); return error; } @@ -567,6 +575,7 @@ static int __devexit pxa27x_keypad_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); kfree(keypad); + return 0; } -- cgit v1.2.3-18-g5258 From 5ddbc77c3eb54336fcd44b7b66b44784d65677e2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 9 Sep 2009 19:08:15 -0700 Subject: Input: i8042 - try disabling and re-enabling AUX port at close Ever since we switched from having a polling timer to registering IRQ handlers for both keyboard and AUX ports at the driver registration time, on certain boxes probing for a mouse results in keyboard stopping working. The only real difference between old and new way is that before we disabled ports after unsuccessful probe whereas now we leave them as is. Try to emulate the old behavior by disabling and immediately re-enabling AUX and KBD ports when corresponding serio port is being closed. Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042.c | 50 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index b53a015bf8a..8aaf8fcacf6 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -264,6 +264,49 @@ static int i8042_aux_write(struct serio *serio, unsigned char c) I8042_CMD_MUX_SEND + port->mux); } + +/* + * i8042_aux_close attempts to clear AUX or KBD port state by disabling + * and then re-enabling it. + */ + +static void i8042_port_close(struct serio *serio) +{ + int irq_bit; + int disable_bit; + const char *port_name; + + if (serio == i8042_ports[I8042_AUX_PORT_NO].serio) { + irq_bit = I8042_CTR_AUXINT; + disable_bit = I8042_CTR_AUXDIS; + port_name = "AUX"; + } else { + irq_bit = I8042_CTR_KBDINT; + disable_bit = I8042_CTR_KBDDIS; + port_name = "KBD"; + } + + i8042_ctr &= ~irq_bit; + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) + printk(KERN_WARNING + "i8042.c: Can't write CTR while closing %s port.\n", + port_name); + + udelay(50); + + i8042_ctr &= ~disable_bit; + i8042_ctr |= irq_bit; + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) + printk(KERN_ERR "i8042.c: Can't reactivate %s port.\n", + port_name); + + /* + * See if there is any data appeared while we were messing with + * port state. + */ + i8042_interrupt(0, NULL); +} + /* * i8042_start() is called by serio core when port is about to finish * registering. It will mark port as existing so i8042_interrupt can @@ -393,7 +436,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) } /* - * i8042_enable_kbd_port enables keybaord port on chip + * i8042_enable_kbd_port enables keyboard port on chip */ static int i8042_enable_kbd_port(void) @@ -841,6 +884,9 @@ static void i8042_controller_reset(void) i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS; i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT); + if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR)) + printk(KERN_WARNING "i8042.c: Can't write CTR while resetting.\n"); + /* * Disable MUX mode if present. */ @@ -1026,6 +1072,7 @@ static int __devinit i8042_create_kbd_port(void) serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; serio->start = i8042_start; serio->stop = i8042_stop; + serio->close = i8042_port_close; serio->port_data = port; serio->dev.parent = &i8042_platform_device->dev; strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name)); @@ -1056,6 +1103,7 @@ static int __devinit i8042_create_aux_port(int idx) if (idx < 0) { strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name)); strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); + serio->close = i8042_port_close; } else { snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx); snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1); -- cgit v1.2.3-18-g5258 From 386b384900a200d5fcabdd4a9c27eb21db606cd4 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 9 Sep 2009 19:08:16 -0700 Subject: Input: i8042 - use boolean type where it makes sense Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042-x86ia64io.h | 38 ++++++------- drivers/input/serio/i8042.c | 103 +++++++++++++++++----------------- 2 files changed, 71 insertions(+), 70 deletions(-) (limited to 'drivers') diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 66829a860ee..248a6acf669 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -550,9 +550,9 @@ static struct dmi_system_id __initdata i8042_dmi_dritek_table[] = { #ifdef CONFIG_PNP #include -static int i8042_pnp_kbd_registered; +static bool i8042_pnp_kbd_registered; static unsigned int i8042_pnp_kbd_devices; -static int i8042_pnp_aux_registered; +static bool i8042_pnp_aux_registered; static unsigned int i8042_pnp_aux_devices; static int i8042_pnp_command_reg; @@ -640,12 +640,12 @@ static struct pnp_driver i8042_pnp_aux_driver = { static void i8042_pnp_exit(void) { if (i8042_pnp_kbd_registered) { - i8042_pnp_kbd_registered = 0; + i8042_pnp_kbd_registered = false; pnp_unregister_driver(&i8042_pnp_kbd_driver); } if (i8042_pnp_aux_registered) { - i8042_pnp_aux_registered = 0; + i8042_pnp_aux_registered = false; pnp_unregister_driver(&i8042_pnp_aux_driver); } } @@ -653,12 +653,12 @@ static void i8042_pnp_exit(void) static int __init i8042_pnp_init(void) { char kbd_irq_str[4] = { 0 }, aux_irq_str[4] = { 0 }; - int pnp_data_busted = 0; + int pnp_data_busted = false; int err; #ifdef CONFIG_X86 if (dmi_check_system(i8042_dmi_nopnp_table)) - i8042_nopnp = 1; + i8042_nopnp = true; #endif if (i8042_nopnp) { @@ -668,11 +668,11 @@ static int __init i8042_pnp_init(void) err = pnp_register_driver(&i8042_pnp_kbd_driver); if (!err) - i8042_pnp_kbd_registered = 1; + i8042_pnp_kbd_registered = true; err = pnp_register_driver(&i8042_pnp_aux_driver); if (!err) - i8042_pnp_aux_registered = 1; + i8042_pnp_aux_registered = true; if (!i8042_pnp_kbd_devices && !i8042_pnp_aux_devices) { i8042_pnp_exit(); @@ -700,9 +700,9 @@ static int __init i8042_pnp_init(void) #if defined(__ia64__) if (!i8042_pnp_kbd_devices) - i8042_nokbd = 1; + i8042_nokbd = true; if (!i8042_pnp_aux_devices) - i8042_noaux = 1; + i8042_noaux = true; #endif if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) && @@ -713,7 +713,7 @@ static int __init i8042_pnp_init(void) "using default %#x\n", i8042_pnp_data_reg, i8042_data_reg); i8042_pnp_data_reg = i8042_data_reg; - pnp_data_busted = 1; + pnp_data_busted = true; } if (((i8042_pnp_command_reg & ~0xf) == (i8042_command_reg & ~0xf) && @@ -724,7 +724,7 @@ static int __init i8042_pnp_init(void) "using default %#x\n", i8042_pnp_command_reg, i8042_command_reg); i8042_pnp_command_reg = i8042_command_reg; - pnp_data_busted = 1; + pnp_data_busted = true; } if (!i8042_nokbd && !i8042_pnp_kbd_irq) { @@ -732,7 +732,7 @@ static int __init i8042_pnp_init(void) "PNP: PS/2 controller doesn't have KBD irq; " "using default %d\n", i8042_kbd_irq); i8042_pnp_kbd_irq = i8042_kbd_irq; - pnp_data_busted = 1; + pnp_data_busted = true; } if (!i8042_noaux && !i8042_pnp_aux_irq) { @@ -741,7 +741,7 @@ static int __init i8042_pnp_init(void) "PNP: PS/2 appears to have AUX port disabled, " "if this is incorrect please boot with " "i8042.nopnp\n"); - i8042_noaux = 1; + i8042_noaux = true; } else { printk(KERN_WARNING "PNP: PS/2 controller doesn't have AUX irq; " @@ -788,21 +788,21 @@ static int __init i8042_platform_init(void) return retval; #if defined(__ia64__) - i8042_reset = 1; + i8042_reset = true; #endif #ifdef CONFIG_X86 if (dmi_check_system(i8042_dmi_reset_table)) - i8042_reset = 1; + i8042_reset = true; if (dmi_check_system(i8042_dmi_noloop_table)) - i8042_noloop = 1; + i8042_noloop = true; if (dmi_check_system(i8042_dmi_nomux_table)) - i8042_nomux = 1; + i8042_nomux = true; if (dmi_check_system(i8042_dmi_dritek_table)) - i8042_dritek = 1; + i8042_dritek = true; #endif /* CONFIG_X86 */ return retval; diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 8aaf8fcacf6..61ed7a966c6 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -28,35 +28,35 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver"); MODULE_LICENSE("GPL"); -static unsigned int i8042_nokbd; +static bool i8042_nokbd; module_param_named(nokbd, i8042_nokbd, bool, 0); MODULE_PARM_DESC(nokbd, "Do not probe or use KBD port."); -static unsigned int i8042_noaux; +static bool i8042_noaux; module_param_named(noaux, i8042_noaux, bool, 0); MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port."); -static unsigned int i8042_nomux; +static bool i8042_nomux; module_param_named(nomux, i8042_nomux, bool, 0); MODULE_PARM_DESC(nomux, "Do not check whether an active multiplexing conrtoller is present."); -static unsigned int i8042_unlock; +static bool i8042_unlock; module_param_named(unlock, i8042_unlock, bool, 0); MODULE_PARM_DESC(unlock, "Ignore keyboard lock."); -static unsigned int i8042_reset; +static bool i8042_reset; module_param_named(reset, i8042_reset, bool, 0); MODULE_PARM_DESC(reset, "Reset controller during init and cleanup."); -static unsigned int i8042_direct; +static bool i8042_direct; module_param_named(direct, i8042_direct, bool, 0); MODULE_PARM_DESC(direct, "Put keyboard port into non-translated mode."); -static unsigned int i8042_dumbkbd; +static bool i8042_dumbkbd; module_param_named(dumbkbd, i8042_dumbkbd, bool, 0); MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard"); -static unsigned int i8042_noloop; +static bool i8042_noloop; module_param_named(noloop, i8042_noloop, bool, 0); MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port"); @@ -65,20 +65,20 @@ module_param_named(panicblink, i8042_blink_frequency, uint, 0600); MODULE_PARM_DESC(panicblink, "Frequency with which keyboard LEDs should blink when kernel panics"); #ifdef CONFIG_X86 -static unsigned int i8042_dritek; +static bool i8042_dritek; module_param_named(dritek, i8042_dritek, bool, 0); MODULE_PARM_DESC(dritek, "Force enable the Dritek keyboard extension"); #endif #ifdef CONFIG_PNP -static int i8042_nopnp; +static bool i8042_nopnp; module_param_named(nopnp, i8042_nopnp, bool, 0); MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings"); #endif #define DEBUG #ifdef DEBUG -static int i8042_debug; +static bool i8042_debug; module_param_named(debug, i8042_debug, bool, 0600); MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off"); #endif @@ -92,7 +92,7 @@ static DEFINE_SPINLOCK(i8042_lock); struct i8042_port { struct serio *serio; int irq; - unsigned char exists; + bool exists; signed char mux; }; @@ -105,9 +105,9 @@ static struct i8042_port i8042_ports[I8042_NUM_PORTS]; static unsigned char i8042_initial_ctr; static unsigned char i8042_ctr; -static unsigned char i8042_mux_present; -static unsigned char i8042_kbd_irq_registered; -static unsigned char i8042_aux_irq_registered; +static bool i8042_mux_present; +static bool i8042_kbd_irq_registered; +static bool i8042_aux_irq_registered; static unsigned char i8042_suppress_kbd_ack; static struct platform_device *i8042_platform_device; @@ -316,7 +316,7 @@ static int i8042_start(struct serio *serio) { struct i8042_port *port = serio->port_data; - port->exists = 1; + port->exists = true; mb(); return 0; } @@ -330,7 +330,7 @@ static void i8042_stop(struct serio *serio) { struct i8042_port *port = serio->port_data; - port->exists = 0; + port->exists = false; /* * We synchronize with both AUX and KBD IRQs because there is @@ -492,14 +492,15 @@ static int i8042_enable_mux_ports(void) } /* - * i8042_set_mux_mode checks whether the controller has an active - * multiplexor and puts the chip into Multiplexed (1) or Legacy (0) mode. + * i8042_set_mux_mode checks whether the controller has an + * active multiplexor and puts the chip into Multiplexed (true) + * or Legacy (false) mode. */ -static int i8042_set_mux_mode(unsigned int mode, unsigned char *mux_version) +static int i8042_set_mux_mode(bool multiplex, unsigned char *mux_version) { - unsigned char param; + unsigned char param, val; /* * Get rid of bytes in the queue. */ @@ -511,14 +512,21 @@ static int i8042_set_mux_mode(unsigned int mode, unsigned char *mux_version) * mouse interface, the last should be version. */ - param = 0xf0; - if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0xf0) + param = val = 0xf0; + if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != val) + return -1; + param = val = multiplex ? 0x56 : 0xf6; + if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != val) return -1; - param = mode ? 0x56 : 0xf6; - if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != (mode ? 0x56 : 0xf6)) + param = val = multiplex ? 0xa4 : 0xa5; + if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == val) return -1; - param = mode ? 0xa4 : 0xa5; - if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == (mode ? 0xa4 : 0xa5)) + +/* + * Workaround for interference with USB Legacy emulation + * that causes a v10.12 MUX to be found. + */ + if (param == 0xac) return -1; if (mux_version) @@ -537,14 +545,7 @@ static int __devinit i8042_check_mux(void) { unsigned char mux_version; - if (i8042_set_mux_mode(1, &mux_version)) - return -1; - -/* - * Workaround for interference with USB Legacy emulation - * that causes a v10.12 MUX to be found. - */ - if (mux_version == 0xAC) + if (i8042_set_mux_mode(true, &mux_version)) return -1; printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n", @@ -561,7 +562,7 @@ static int __devinit i8042_check_mux(void) return -EIO; } - i8042_mux_present = 1; + i8042_mux_present = true; return 0; } @@ -570,7 +571,7 @@ static int __devinit i8042_check_mux(void) * The following is used to test AUX IRQ delivery. */ static struct completion i8042_aux_irq_delivered __devinitdata; -static int i8042_irq_being_tested __devinitdata; +static bool i8042_irq_being_tested __devinitdata; static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id) { @@ -597,7 +598,7 @@ static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id) * verifies success by readinng CTR. Used when testing for presence of AUX * port. */ -static int __devinit i8042_toggle_aux(int on) +static int __devinit i8042_toggle_aux(bool on) { unsigned char param; int i; @@ -628,8 +629,8 @@ static int __devinit i8042_toggle_aux(int on) static int __devinit i8042_check_aux(void) { int retval = -1; - int irq_registered = 0; - int aux_loop_broken = 0; + bool irq_registered = false; + bool aux_loop_broken = false; unsigned long flags; unsigned char param; @@ -666,19 +667,19 @@ static int __devinit i8042_check_aux(void) * mark it as broken */ if (!retval) - aux_loop_broken = 1; + aux_loop_broken = true; } /* * Bit assignment test - filters out PS/2 i8042's in AT mode */ - if (i8042_toggle_aux(0)) { + if (i8042_toggle_aux(false)) { printk(KERN_WARNING "Failed to disable AUX port, but continuing anyway... Is this a SiS?\n"); printk(KERN_WARNING "If AUX port is really absent please use the 'i8042.noaux' option.\n"); } - if (i8042_toggle_aux(1)) + if (i8042_toggle_aux(true)) return -1; /* @@ -699,7 +700,7 @@ static int __devinit i8042_check_aux(void) "i8042", i8042_platform_device)) goto out; - irq_registered = 1; + irq_registered = true; if (i8042_enable_aux_port()) goto out; @@ -707,7 +708,7 @@ static int __devinit i8042_check_aux(void) spin_lock_irqsave(&i8042_lock, flags); init_completion(&i8042_aux_irq_delivered); - i8042_irq_being_tested = 1; + i8042_irq_being_tested = true; param = 0xa5; retval = __i8042_command(¶m, I8042_CMD_AUX_LOOP & 0xf0ff); @@ -844,7 +845,7 @@ static int i8042_controller_init(void) */ if (~i8042_ctr & I8042_CTR_XLATE) - i8042_direct = 1; + i8042_direct = true; /* * Set nontranslated mode for the kbd interface if requested by an option. @@ -892,7 +893,7 @@ static void i8042_controller_reset(void) */ if (i8042_mux_present) - i8042_set_mux_mode(0, NULL); + i8042_set_mux_mode(false, NULL); /* * Reset the controller if requested. @@ -1025,7 +1026,7 @@ static int i8042_pm_restore(struct device *dev) #endif if (i8042_mux_present) { - if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports()) + if (i8042_set_mux_mode(true, NULL) || i8042_enable_mux_ports()) printk(KERN_WARNING "i8042: failed to resume active multiplexor, " "mouse won't work.\n"); @@ -1167,7 +1168,7 @@ static void i8042_free_irqs(void) if (i8042_kbd_irq_registered) free_irq(I8042_KBD_IRQ, i8042_platform_device); - i8042_aux_irq_registered = i8042_kbd_irq_registered = 0; + i8042_aux_irq_registered = i8042_kbd_irq_registered = false; } static int __devinit i8042_setup_aux(void) @@ -1201,7 +1202,7 @@ static int __devinit i8042_setup_aux(void) if (aux_enable()) goto err_free_irq; - i8042_aux_irq_registered = 1; + i8042_aux_irq_registered = true; return 0; err_free_irq: @@ -1228,7 +1229,7 @@ static int __devinit i8042_setup_kbd(void) if (error) goto err_free_irq; - i8042_kbd_irq_registered = 1; + i8042_kbd_irq_registered = true; return 0; err_free_irq: -- cgit v1.2.3-18-g5258 From f81134163fc785622f58af27363079ba1de7c7aa Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 9 Sep 2009 19:08:17 -0700 Subject: Input: i8042 - use platform_driver_probe i8042 is not hot-pluggable and we create the device when we register the driver, so let's save some memory by using platform_device_probe and using __init instead of __devinit. Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042.c | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 61ed7a966c6..eb3ff94af58 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -541,7 +541,7 @@ static int i8042_set_mux_mode(bool multiplex, unsigned char *mux_version) * LCS/Telegraphics. */ -static int __devinit i8042_check_mux(void) +static int __init i8042_check_mux(void) { unsigned char mux_version; @@ -570,10 +570,10 @@ static int __devinit i8042_check_mux(void) /* * The following is used to test AUX IRQ delivery. */ -static struct completion i8042_aux_irq_delivered __devinitdata; -static bool i8042_irq_being_tested __devinitdata; +static struct completion i8042_aux_irq_delivered __initdata; +static bool i8042_irq_being_tested __initdata; -static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id) +static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id) { unsigned long flags; unsigned char str, data; @@ -598,7 +598,7 @@ static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id) * verifies success by readinng CTR. Used when testing for presence of AUX * port. */ -static int __devinit i8042_toggle_aux(bool on) +static int __init i8042_toggle_aux(bool on) { unsigned char param; int i; @@ -626,7 +626,7 @@ static int __devinit i8042_toggle_aux(bool on) * the presence of an AUX interface. */ -static int __devinit i8042_check_aux(void) +static int __init i8042_check_aux(void) { int retval = -1; bool irq_registered = false; @@ -1060,7 +1060,7 @@ static void i8042_shutdown(struct platform_device *dev) i8042_controller_reset(); } -static int __devinit i8042_create_kbd_port(void) +static int __init i8042_create_kbd_port(void) { struct serio *serio; struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO]; @@ -1085,7 +1085,7 @@ static int __devinit i8042_create_kbd_port(void) return 0; } -static int __devinit i8042_create_aux_port(int idx) +static int __init i8042_create_aux_port(int idx) { struct serio *serio; int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx; @@ -1117,13 +1117,13 @@ static int __devinit i8042_create_aux_port(int idx) return 0; } -static void __devinit i8042_free_kbd_port(void) +static void __init i8042_free_kbd_port(void) { kfree(i8042_ports[I8042_KBD_PORT_NO].serio); i8042_ports[I8042_KBD_PORT_NO].serio = NULL; } -static void __devinit i8042_free_aux_ports(void) +static void __init i8042_free_aux_ports(void) { int i; @@ -1133,7 +1133,7 @@ static void __devinit i8042_free_aux_ports(void) } } -static void __devinit i8042_register_ports(void) +static void __init i8042_register_ports(void) { int i; @@ -1171,7 +1171,7 @@ static void i8042_free_irqs(void) i8042_aux_irq_registered = i8042_kbd_irq_registered = false; } -static int __devinit i8042_setup_aux(void) +static int __init i8042_setup_aux(void) { int (*aux_enable)(void); int error; @@ -1212,7 +1212,7 @@ static int __devinit i8042_setup_aux(void) return error; } -static int __devinit i8042_setup_kbd(void) +static int __init i8042_setup_kbd(void) { int error; @@ -1239,7 +1239,7 @@ static int __devinit i8042_setup_kbd(void) return error; } -static int __devinit i8042_probe(struct platform_device *dev) +static int __init i8042_probe(struct platform_device *dev) { int error; @@ -1299,7 +1299,6 @@ static struct platform_driver i8042_driver = { .pm = &i8042_pm_ops, #endif }, - .probe = i8042_probe, .remove = __devexit_p(i8042_remove), .shutdown = i8042_shutdown, }; @@ -1318,28 +1317,28 @@ static int __init i8042_init(void) if (err) goto err_platform_exit; - err = platform_driver_register(&i8042_driver); - if (err) - goto err_platform_exit; - i8042_platform_device = platform_device_alloc("i8042", -1); if (!i8042_platform_device) { err = -ENOMEM; - goto err_unregister_driver; + goto err_platform_exit; } err = platform_device_add(i8042_platform_device); if (err) goto err_free_device; + err = platform_driver_probe(&i8042_driver, i8042_probe); + if (err) + goto err_del_device; + panic_blink = i8042_panic_blink; return 0; + err_del_device: + platform_device_del(i8042_platform_device); err_free_device: platform_device_put(i8042_platform_device); - err_unregister_driver: - platform_driver_unregister(&i8042_driver); err_platform_exit: i8042_platform_exit(); @@ -1348,8 +1347,8 @@ static int __init i8042_init(void) static void __exit i8042_exit(void) { - platform_device_unregister(i8042_platform_device); platform_driver_unregister(&i8042_driver); + platform_device_unregister(i8042_platform_device); i8042_platform_exit(); panic_blink = NULL; -- cgit v1.2.3-18-g5258 From b7802c5c1ea9563f3746bea09c214ccedc8600f4 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 9 Sep 2009 19:13:20 -0700 Subject: Input: psmouse - use boolean type Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 20 +++++---- drivers/input/mouse/alps.h | 4 +- drivers/input/mouse/elantech.c | 2 +- drivers/input/mouse/elantech.h | 4 +- drivers/input/mouse/hgpk.c | 8 ++-- drivers/input/mouse/hgpk.h | 6 +-- drivers/input/mouse/lifebook.c | 8 ++-- drivers/input/mouse/lifebook.h | 4 +- drivers/input/mouse/logips2pp.c | 41 +++++++++--------- drivers/input/mouse/logips2pp.h | 4 +- drivers/input/mouse/psmouse-base.c | 87 ++++++++++++++++++++------------------ drivers/input/mouse/psmouse.h | 14 +++--- drivers/input/mouse/sentelic.c | 2 +- drivers/input/mouse/sentelic.h | 4 +- drivers/input/mouse/synaptics.c | 34 +++++++-------- drivers/input/mouse/synaptics.h | 2 +- drivers/input/mouse/touchkit_ps2.c | 4 +- drivers/input/mouse/touchkit_ps2.h | 4 +- drivers/input/mouse/trackpoint.c | 2 +- drivers/input/mouse/trackpoint.h | 4 +- 20 files changed, 133 insertions(+), 125 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 5547e2429fb..f36110689aa 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -279,7 +279,7 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int * subsequent commands. It looks like glidepad is behind stickpointer, * I'd thought it would be other way around... */ -static int alps_passthrough_mode(struct psmouse *psmouse, int enable) +static int alps_passthrough_mode(struct psmouse *psmouse, bool enable) { struct ps2dev *ps2dev = &psmouse->ps2dev; int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11; @@ -367,16 +367,16 @@ static int alps_poll(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; unsigned char buf[6]; - int poll_failed; + bool poll_failed; if (priv->i->flags & ALPS_PASS) - alps_passthrough_mode(psmouse, 1); + alps_passthrough_mode(psmouse, true); poll_failed = ps2_command(&psmouse->ps2dev, buf, PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0; if (priv->i->flags & ALPS_PASS) - alps_passthrough_mode(psmouse, 0); + alps_passthrough_mode(psmouse, false); if (poll_failed || (buf[0] & priv->i->mask0) != priv->i->byte0) return -1; @@ -401,10 +401,12 @@ static int alps_hw_init(struct psmouse *psmouse, int *version) if (!priv->i) return -1; - if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1)) + if ((priv->i->flags & ALPS_PASS) && + alps_passthrough_mode(psmouse, true)) { return -1; + } - if (alps_tap_mode(psmouse, 1)) { + if (alps_tap_mode(psmouse, true)) { printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n"); return -1; } @@ -414,8 +416,10 @@ static int alps_hw_init(struct psmouse *psmouse, int *version) return -1; } - if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 0)) + if ((priv->i->flags & ALPS_PASS) && + alps_passthrough_mode(psmouse, false)) { return -1; + } /* ALPS needs stream mode, otherwise it won't report any data */ if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)) { @@ -519,7 +523,7 @@ init_fail: return -1; } -int alps_detect(struct psmouse *psmouse, int set_properties) +int alps_detect(struct psmouse *psmouse, bool set_properties) { int version; const struct alps_model_info *model; diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index 4bbddc99962..bc87936fee1 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -26,10 +26,10 @@ struct alps_data { }; #ifdef CONFIG_MOUSE_PS2_ALPS -int alps_detect(struct psmouse *psmouse, int set_properties); +int alps_detect(struct psmouse *psmouse, bool set_properties); int alps_init(struct psmouse *psmouse); #else -inline int alps_detect(struct psmouse *psmouse, int set_properties) +inline int alps_detect(struct psmouse *psmouse, bool set_properties) { return -ENOSYS; } diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 4bc78892ba9..fda35e615ab 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -553,7 +553,7 @@ static struct attribute_group elantech_attr_group = { /* * Use magic knock to detect Elantech touchpad */ -int elantech_detect(struct psmouse *psmouse, int set_properties) +int elantech_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char param[3]; diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index ed848cc8081..feac5f7af96 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -109,10 +109,10 @@ struct elantech_data { }; #ifdef CONFIG_MOUSE_PS2_ELANTECH -int elantech_detect(struct psmouse *psmouse, int set_properties); +int elantech_detect(struct psmouse *psmouse, bool set_properties); int elantech_init(struct psmouse *psmouse); #else -static inline int elantech_detect(struct psmouse *psmouse, int set_properties) +static inline int elantech_detect(struct psmouse *psmouse, bool set_properties) { return -ENOSYS; } diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c index f5aa035774d..de1e553028b 100644 --- a/drivers/input/mouse/hgpk.c +++ b/drivers/input/mouse/hgpk.c @@ -367,7 +367,7 @@ static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data, } __PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL, - hgpk_show_powered, hgpk_set_powered, 0); + hgpk_show_powered, hgpk_set_powered, false); static ssize_t hgpk_trigger_recal_show(struct psmouse *psmouse, void *data, char *buf) @@ -396,7 +396,7 @@ static ssize_t hgpk_trigger_recal(struct psmouse *psmouse, void *data, } __PSMOUSE_DEFINE_ATTR(recalibrate, S_IWUSR | S_IRUGO, NULL, - hgpk_trigger_recal_show, hgpk_trigger_recal, 0); + hgpk_trigger_recal_show, hgpk_trigger_recal, false); static void hgpk_disconnect(struct psmouse *psmouse) { @@ -489,7 +489,7 @@ int hgpk_init(struct psmouse *psmouse) psmouse->private = priv; priv->psmouse = psmouse; - priv->powered = 1; + priv->powered = true; INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work); err = psmouse_reset(psmouse); @@ -532,7 +532,7 @@ static enum hgpk_model_t hgpk_get_model(struct psmouse *psmouse) return param[2]; } -int hgpk_detect(struct psmouse *psmouse, int set_properties) +int hgpk_detect(struct psmouse *psmouse, bool set_properties) { int version; diff --git a/drivers/input/mouse/hgpk.h b/drivers/input/mouse/hgpk.h index a4b2a96f5f5..d61cfd3ee9c 100644 --- a/drivers/input/mouse/hgpk.h +++ b/drivers/input/mouse/hgpk.h @@ -15,7 +15,7 @@ enum hgpk_model_t { struct hgpk_data { struct psmouse *psmouse; - int powered; + bool powered; int count, x_tally, y_tally; /* hardware workaround stuff */ unsigned long recalib_window; struct delayed_work recalib_wq; @@ -33,10 +33,10 @@ struct hgpk_data { dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg) #ifdef CONFIG_MOUSE_PS2_OLPC -int hgpk_detect(struct psmouse *psmouse, int set_properties); +int hgpk_detect(struct psmouse *psmouse, bool set_properties); int hgpk_init(struct psmouse *psmouse); #else -static inline int hgpk_detect(struct psmouse *psmouse, int set_properties) +static inline int hgpk_detect(struct psmouse *psmouse, bool set_properties) { return -ENODEV; } diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index dcd4236af1e..5e630869440 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c @@ -33,11 +33,11 @@ static int lifebook_set_serio_phys(const struct dmi_system_id *d) return 0; } -static unsigned char lifebook_use_6byte_proto; +static bool lifebook_use_6byte_proto; static int lifebook_set_6byte_proto(const struct dmi_system_id *d) { - lifebook_use_6byte_proto = 1; + lifebook_use_6byte_proto = true; return 0; } @@ -125,7 +125,7 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) struct input_dev *dev1 = psmouse->dev; struct input_dev *dev2 = priv ? priv->dev2 : NULL; unsigned char *packet = psmouse->packet; - int relative_packet = packet[0] & 0x08; + bool relative_packet = packet[0] & 0x08; if (relative_packet || !lifebook_use_6byte_proto) { if (psmouse->pktcnt != 3) @@ -242,7 +242,7 @@ static void lifebook_disconnect(struct psmouse *psmouse) psmouse->private = NULL; } -int lifebook_detect(struct psmouse *psmouse, int set_properties) +int lifebook_detect(struct psmouse *psmouse, bool set_properties) { if (!dmi_check_system(lifebook_dmi_table)) return -1; diff --git a/drivers/input/mouse/lifebook.h b/drivers/input/mouse/lifebook.h index c1647cf036c..407cb226bc0 100644 --- a/drivers/input/mouse/lifebook.h +++ b/drivers/input/mouse/lifebook.h @@ -12,10 +12,10 @@ #define _LIFEBOOK_H #ifdef CONFIG_MOUSE_PS2_LIFEBOOK -int lifebook_detect(struct psmouse *psmouse, int set_properties); +int lifebook_detect(struct psmouse *psmouse, bool set_properties); int lifebook_init(struct psmouse *psmouse); #else -inline int lifebook_detect(struct psmouse *psmouse, int set_properties) +inline int lifebook_detect(struct psmouse *psmouse, bool set_properties) { return -ENOSYS; } diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 390f1dbb98a..de745d75116 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -130,14 +130,11 @@ static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned cha * 0 - disabled */ -static void ps2pp_set_smartscroll(struct psmouse *psmouse, unsigned int smartscroll) +static void ps2pp_set_smartscroll(struct psmouse *psmouse, bool smartscroll) { struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char param[4]; - if (smartscroll > 1) - smartscroll = 1; - ps2pp_cmd(psmouse, param, 0x32); param[0] = 0; @@ -149,12 +146,14 @@ static void ps2pp_set_smartscroll(struct psmouse *psmouse, unsigned int smartscr ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); } -static ssize_t ps2pp_attr_show_smartscroll(struct psmouse *psmouse, void *data, char *buf) +static ssize_t ps2pp_attr_show_smartscroll(struct psmouse *psmouse, + void *data, char *buf) { - return sprintf(buf, "%d\n", psmouse->smartscroll ? 1 : 0); + return sprintf(buf, "%d\n", psmouse->smartscroll); } -static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data, const char *buf, size_t count) +static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data, + const char *buf, size_t count) { unsigned long value; @@ -261,29 +260,29 @@ static const struct ps2pp_info *get_model_info(unsigned char model) static void ps2pp_set_model_properties(struct psmouse *psmouse, const struct ps2pp_info *model_info, - int using_ps2pp) + bool using_ps2pp) { struct input_dev *input_dev = psmouse->dev; if (model_info->features & PS2PP_SIDE_BTN) - set_bit(BTN_SIDE, input_dev->keybit); + __set_bit(BTN_SIDE, input_dev->keybit); if (model_info->features & PS2PP_EXTRA_BTN) - set_bit(BTN_EXTRA, input_dev->keybit); + __set_bit(BTN_EXTRA, input_dev->keybit); if (model_info->features & PS2PP_TASK_BTN) - set_bit(BTN_TASK, input_dev->keybit); + __set_bit(BTN_TASK, input_dev->keybit); if (model_info->features & PS2PP_NAV_BTN) { - set_bit(BTN_FORWARD, input_dev->keybit); - set_bit(BTN_BACK, input_dev->keybit); + __set_bit(BTN_FORWARD, input_dev->keybit); + __set_bit(BTN_BACK, input_dev->keybit); } if (model_info->features & PS2PP_WHEEL) - set_bit(REL_WHEEL, input_dev->relbit); + __set_bit(REL_WHEEL, input_dev->relbit); if (model_info->features & PS2PP_HWHEEL) - set_bit(REL_HWHEEL, input_dev->relbit); + __set_bit(REL_HWHEEL, input_dev->relbit); switch (model_info->kind) { case PS2PP_KIND_WHEEL: @@ -321,13 +320,13 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse, * that support it. */ -int ps2pp_init(struct psmouse *psmouse, int set_properties) +int ps2pp_init(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char param[4]; unsigned char model, buttons; const struct ps2pp_info *model_info; - int use_ps2pp = 0; + bool use_ps2pp = false; int error; param[0] = 0; @@ -364,7 +363,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) param[0] = 0; if (!ps2_command(ps2dev, param, 0x13d1) && param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) { - use_ps2pp = 1; + use_ps2pp = true; } } else { @@ -376,8 +375,8 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 && (param[2] & 0x03) == ((param[1] >> 2) & 3)) { - ps2pp_set_smartscroll(psmouse, psmouse->smartscroll); - use_ps2pp = 1; + ps2pp_set_smartscroll(psmouse, false); + use_ps2pp = true; } } } @@ -406,7 +405,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) } if (buttons < 3) - clear_bit(BTN_MIDDLE, psmouse->dev->keybit); + __clear_bit(BTN_MIDDLE, psmouse->dev->keybit); if (model_info) ps2pp_set_model_properties(psmouse, model_info, use_ps2pp); diff --git a/drivers/input/mouse/logips2pp.h b/drivers/input/mouse/logips2pp.h index 6e5712525fd..0c186f0282d 100644 --- a/drivers/input/mouse/logips2pp.h +++ b/drivers/input/mouse/logips2pp.h @@ -12,9 +12,9 @@ #define _LOGIPS2PP_H #ifdef CONFIG_MOUSE_PS2_LOGIPS2PP -int ps2pp_init(struct psmouse *psmouse, int set_properties); +int ps2pp_init(struct psmouse *psmouse, bool set_properties); #else -inline int ps2pp_init(struct psmouse *psmouse, int set_properties) +inline int ps2pp_init(struct psmouse *psmouse, bool set_properties) { return -ENOSYS; } diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index df318887ca0..690aed90543 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -109,10 +109,10 @@ static struct workqueue_struct *kpsmoused_wq; struct psmouse_protocol { enum psmouse_type type; + bool maxproto; const char *name; const char *alias; - int maxproto; - int (*detect)(struct psmouse *, int); + int (*detect)(struct psmouse *, bool); int (*init)(struct psmouse *); }; @@ -217,7 +217,7 @@ void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work, static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) { psmouse->state = new_state; - psmouse->pktcnt = psmouse->out_of_sync = 0; + psmouse->pktcnt = psmouse->out_of_sync_cnt = 0; psmouse->ps2dev.flags = 0; psmouse->last = jiffies; } @@ -250,7 +250,7 @@ static int psmouse_handle_byte(struct psmouse *psmouse) if (psmouse->state == PSMOUSE_ACTIVATED) { printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n", psmouse->name, psmouse->phys, psmouse->pktcnt); - if (++psmouse->out_of_sync == psmouse->resetafter) { + if (++psmouse->out_of_sync_cnt == psmouse->resetafter) { __psmouse_set_state(psmouse, PSMOUSE_IGNORE); printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n"); serio_reconnect(psmouse->ps2dev.serio); @@ -262,8 +262,8 @@ static int psmouse_handle_byte(struct psmouse *psmouse) case PSMOUSE_FULL_PACKET: psmouse->pktcnt = 0; - if (psmouse->out_of_sync) { - psmouse->out_of_sync = 0; + if (psmouse->out_of_sync_cnt) { + psmouse->out_of_sync_cnt = 0; printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n", psmouse->name, psmouse->phys); } @@ -409,7 +409,7 @@ int psmouse_reset(struct psmouse *psmouse) /* * Genius NetMouse magic init. */ -static int genius_detect(struct psmouse *psmouse, int set_properties) +static int genius_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char param[4]; @@ -425,9 +425,9 @@ static int genius_detect(struct psmouse *psmouse, int set_properties) return -1; if (set_properties) { - set_bit(BTN_EXTRA, psmouse->dev->keybit); - set_bit(BTN_SIDE, psmouse->dev->keybit); - set_bit(REL_WHEEL, psmouse->dev->relbit); + __set_bit(BTN_EXTRA, psmouse->dev->keybit); + __set_bit(BTN_SIDE, psmouse->dev->keybit); + __set_bit(REL_WHEEL, psmouse->dev->relbit); psmouse->vendor = "Genius"; psmouse->name = "Mouse"; @@ -440,7 +440,7 @@ static int genius_detect(struct psmouse *psmouse, int set_properties) /* * IntelliMouse magic init. */ -static int intellimouse_detect(struct psmouse *psmouse, int set_properties) +static int intellimouse_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char param[2]; @@ -457,8 +457,8 @@ static int intellimouse_detect(struct psmouse *psmouse, int set_properties) return -1; if (set_properties) { - set_bit(BTN_MIDDLE, psmouse->dev->keybit); - set_bit(REL_WHEEL, psmouse->dev->relbit); + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); + __set_bit(REL_WHEEL, psmouse->dev->relbit); if (!psmouse->vendor) psmouse->vendor = "Generic"; if (!psmouse->name) psmouse->name = "Wheel Mouse"; @@ -471,7 +471,7 @@ static int intellimouse_detect(struct psmouse *psmouse, int set_properties) /* * Try IntelliMouse/Explorer magic init. */ -static int im_explorer_detect(struct psmouse *psmouse, int set_properties) +static int im_explorer_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char param[2]; @@ -498,11 +498,11 @@ static int im_explorer_detect(struct psmouse *psmouse, int set_properties) ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); if (set_properties) { - set_bit(BTN_MIDDLE, psmouse->dev->keybit); - set_bit(REL_WHEEL, psmouse->dev->relbit); - set_bit(REL_HWHEEL, psmouse->dev->relbit); - set_bit(BTN_SIDE, psmouse->dev->keybit); - set_bit(BTN_EXTRA, psmouse->dev->keybit); + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); + __set_bit(REL_WHEEL, psmouse->dev->relbit); + __set_bit(REL_HWHEEL, psmouse->dev->relbit); + __set_bit(BTN_SIDE, psmouse->dev->keybit); + __set_bit(BTN_EXTRA, psmouse->dev->keybit); if (!psmouse->vendor) psmouse->vendor = "Generic"; if (!psmouse->name) psmouse->name = "Explorer Mouse"; @@ -515,7 +515,7 @@ static int im_explorer_detect(struct psmouse *psmouse, int set_properties) /* * Kensington ThinkingMouse / ExpertMouse magic init. */ -static int thinking_detect(struct psmouse *psmouse, int set_properties) +static int thinking_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char param[2]; @@ -536,7 +536,7 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties) return -1; if (set_properties) { - set_bit(BTN_EXTRA, psmouse->dev->keybit); + __set_bit(BTN_EXTRA, psmouse->dev->keybit); psmouse->vendor = "Kensington"; psmouse->name = "ThinkingMouse"; @@ -548,7 +548,7 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties) /* * Bare PS/2 protocol "detection". Always succeeds. */ -static int ps2bare_detect(struct psmouse *psmouse, int set_properties) +static int ps2bare_detect(struct psmouse *psmouse, bool set_properties) { if (set_properties) { if (!psmouse->vendor) psmouse->vendor = "Generic"; @@ -562,12 +562,12 @@ static int ps2bare_detect(struct psmouse *psmouse, int set_properties) * Cortron PS/2 protocol detection. There's no special way to detect it, so it * must be forced by sysfs protocol writing. */ -static int cortron_detect(struct psmouse *psmouse, int set_properties) +static int cortron_detect(struct psmouse *psmouse, bool set_properties) { if (set_properties) { psmouse->vendor = "Cortron"; psmouse->name = "PS/2 Trackball"; - set_bit(BTN_SIDE, psmouse->dev->keybit); + __set_bit(BTN_SIDE, psmouse->dev->keybit); } return 0; @@ -579,9 +579,9 @@ static int cortron_detect(struct psmouse *psmouse, int set_properties) */ static int psmouse_extensions(struct psmouse *psmouse, - unsigned int max_proto, int set_properties) + unsigned int max_proto, bool set_properties) { - int synaptics_hardware = 0; + bool synaptics_hardware = true; /* * We always check for lifebook because it does not disturb mouse @@ -608,7 +608,7 @@ static int psmouse_extensions(struct psmouse *psmouse, * can reset it properly after probing for intellimouse. */ if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse, set_properties) == 0) { - synaptics_hardware = 1; + synaptics_hardware = true; if (max_proto > PSMOUSE_IMEX) { if (!set_properties || synaptics_init(psmouse) == 0) @@ -733,7 +733,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { .type = PSMOUSE_PS2, .name = "PS/2", .alias = "bare", - .maxproto = 1, + .maxproto = true, .detect = ps2bare_detect, }, #ifdef CONFIG_MOUSE_PS2_LOGIPS2PP @@ -760,14 +760,14 @@ static const struct psmouse_protocol psmouse_protocols[] = { .type = PSMOUSE_IMPS, .name = "ImPS/2", .alias = "imps", - .maxproto = 1, + .maxproto = true, .detect = intellimouse_detect, }, { .type = PSMOUSE_IMEX, .name = "ImExPS/2", .alias = "exps", - .maxproto = 1, + .maxproto = true, .detect = im_explorer_detect, }, #ifdef CONFIG_MOUSE_PS2_SYNAPTICS @@ -848,7 +848,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { .type = PSMOUSE_AUTO, .name = "auto", .alias = "any", - .maxproto = 1, + .maxproto = true, }, }; @@ -1014,7 +1014,7 @@ static void psmouse_resync(struct work_struct *work) container_of(work, struct psmouse, resync_work.work); struct serio *serio = psmouse->ps2dev.serio; psmouse_ret_t rc = PSMOUSE_GOOD_DATA; - int failed = 0, enabled = 0; + bool failed = false, enabled = false; int i; mutex_lock(&psmouse_mutex); @@ -1041,9 +1041,9 @@ static void psmouse_resync(struct work_struct *work) if (ps2_sendbyte(&psmouse->ps2dev, PSMOUSE_CMD_DISABLE, 20)) { if (psmouse->num_resyncs < 3 || psmouse->acks_disable_command) - failed = 1; + failed = true; } else - psmouse->acks_disable_command = 1; + psmouse->acks_disable_command = true; /* * Poll the mouse. If it was reset the packet will be shorter than @@ -1054,7 +1054,7 @@ static void psmouse_resync(struct work_struct *work) */ if (!failed) { if (psmouse->poll(psmouse)) - failed = 1; + failed = true; else { psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); for (i = 0; i < psmouse->pktsize; i++) { @@ -1064,7 +1064,7 @@ static void psmouse_resync(struct work_struct *work) break; } if (rc != PSMOUSE_FULL_PACKET) - failed = 1; + failed = true; psmouse_set_state(psmouse, PSMOUSE_RESYNCING); } } @@ -1075,7 +1075,7 @@ static void psmouse_resync(struct work_struct *work) */ for (i = 0; i < 5; i++) { if (!ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { - enabled = 1; + enabled = true; break; } msleep(200); @@ -1084,7 +1084,7 @@ static void psmouse_resync(struct work_struct *work) if (!enabled) { printk(KERN_WARNING "psmouse.c: failed to re-enable mouse on %s\n", psmouse->ps2dev.serio->phys); - failed = 1; + failed = true; } if (failed) { @@ -1211,7 +1211,8 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse psmouse->type = proto->type; } else - psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1); + psmouse->type = psmouse_extensions(psmouse, + psmouse_max_proto, true); /* * If mouse's packet size is 3 there is no point in polling the @@ -1366,8 +1367,10 @@ static int psmouse_reconnect(struct serio *serio) if (psmouse->reconnect(psmouse)) goto out; } else if (psmouse_probe(psmouse) < 0 || - psmouse->type != psmouse_extensions(psmouse, psmouse_max_proto, 0)) + psmouse->type != psmouse_extensions(psmouse, + psmouse_max_proto, false)) { goto out; + } /* ok, the device type (and capabilities) match the old one, * we can continue using it, complete intialization @@ -1552,7 +1555,9 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co while (serio->child) { if (++retry > 3) { - printk(KERN_WARNING "psmouse: failed to destroy child port, protocol change aborted.\n"); + printk(KERN_WARNING + "psmouse: failed to destroy child port, " + "protocol change aborted.\n"); input_free_device(new_dev); return -EIO; } diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index cca1744c2a0..e053bdd137f 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -47,10 +47,10 @@ struct psmouse { unsigned char pktcnt; unsigned char pktsize; unsigned char type; - unsigned char acks_disable_command; + bool acks_disable_command; unsigned int model; unsigned long last; - unsigned long out_of_sync; + unsigned long out_of_sync_cnt; unsigned long num_resyncs; enum psmouse_state state; char devname[64]; @@ -60,7 +60,7 @@ struct psmouse { unsigned int resolution; unsigned int resetafter; unsigned int resync_time; - unsigned int smartscroll; /* Logitech only */ + bool smartscroll; /* Logitech only */ psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse); void (*set_rate)(struct psmouse *psmouse, unsigned int rate); @@ -108,7 +108,7 @@ struct psmouse_attribute { ssize_t (*show)(struct psmouse *psmouse, void *data, char *buf); ssize_t (*set)(struct psmouse *psmouse, void *data, const char *buf, size_t count); - int protect; + bool protect; }; #define to_psmouse_attr(a) container_of((a), struct psmouse_attribute, dattr) @@ -139,14 +139,14 @@ static struct psmouse_attribute psmouse_attr_##_name = { \ __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, _set, _protect) #define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set) \ - __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, 1) + __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, true) #define PSMOUSE_DEFINE_RO_ATTR(_name, _mode, _data, _show) \ static ssize_t _show(struct psmouse *, void *, char *); \ - __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, NULL, 1) + __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, NULL, true) #define PSMOUSE_DEFINE_WO_ATTR(_name, _mode, _data, _set) \ static ssize_t _set(struct psmouse *, void *, const char *, size_t); \ - __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, NULL, _set, 1) + __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, NULL, _set, true) #endif /* _PSMOUSE_H */ diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c index 97b1e72855a..84e2fc04d11 100644 --- a/drivers/input/mouse/sentelic.c +++ b/drivers/input/mouse/sentelic.c @@ -756,7 +756,7 @@ static int fsp_activate_protocol(struct psmouse *psmouse) return 0; } -int fsp_detect(struct psmouse *psmouse, int set_properties) +int fsp_detect(struct psmouse *psmouse, bool set_properties) { int id; diff --git a/drivers/input/mouse/sentelic.h b/drivers/input/mouse/sentelic.h index 083559c7282..ed1395ac7b8 100644 --- a/drivers/input/mouse/sentelic.h +++ b/drivers/input/mouse/sentelic.h @@ -80,10 +80,10 @@ struct fsp_data { }; #ifdef CONFIG_MOUSE_PS2_SENTELIC -extern int fsp_detect(struct psmouse *psmouse, int set_properties); +extern int fsp_detect(struct psmouse *psmouse, bool set_properties); extern int fsp_init(struct psmouse *psmouse); #else -inline int fsp_detect(struct psmouse *psmouse, int set_properties) +inline int fsp_detect(struct psmouse *psmouse, bool set_properties) { return -ENOSYS; } diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 19984bf06ca..b66ff1ac7de 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -60,7 +60,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode) return 0; } -int synaptics_detect(struct psmouse *psmouse, int set_properties) +int synaptics_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char param[4]; @@ -556,38 +556,38 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) { int i; - set_bit(EV_ABS, dev->evbit); + __set_bit(EV_ABS, dev->evbit); input_set_abs_params(dev, ABS_X, XMIN_NOMINAL, XMAX_NOMINAL, 0, 0); input_set_abs_params(dev, ABS_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0); input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); - set_bit(ABS_TOOL_WIDTH, dev->absbit); + __set_bit(ABS_TOOL_WIDTH, dev->absbit); - set_bit(EV_KEY, dev->evbit); - set_bit(BTN_TOUCH, dev->keybit); - set_bit(BTN_TOOL_FINGER, dev->keybit); - set_bit(BTN_LEFT, dev->keybit); - set_bit(BTN_RIGHT, dev->keybit); + __set_bit(EV_KEY, dev->evbit); + __set_bit(BTN_TOUCH, dev->keybit); + __set_bit(BTN_TOOL_FINGER, dev->keybit); + __set_bit(BTN_LEFT, dev->keybit); + __set_bit(BTN_RIGHT, dev->keybit); if (SYN_CAP_MULTIFINGER(priv->capabilities)) { - set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); - set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); + __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); + __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); } if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) - set_bit(BTN_MIDDLE, dev->keybit); + __set_bit(BTN_MIDDLE, dev->keybit); if (SYN_CAP_FOUR_BUTTON(priv->capabilities) || SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) { - set_bit(BTN_FORWARD, dev->keybit); - set_bit(BTN_BACK, dev->keybit); + __set_bit(BTN_FORWARD, dev->keybit); + __set_bit(BTN_BACK, dev->keybit); } for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++) - set_bit(BTN_0 + i, dev->keybit); + __set_bit(BTN_0 + i, dev->keybit); - clear_bit(EV_REL, dev->evbit); - clear_bit(REL_X, dev->relbit); - clear_bit(REL_Y, dev->relbit); + __clear_bit(EV_REL, dev->evbit); + __clear_bit(REL_X, dev->relbit); + __clear_bit(REL_Y, dev->relbit); dev->absres[ABS_X] = priv->x_res; dev->absres[ABS_Y] = priv->y_res; diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 30238215175..871f6fe377f 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -105,7 +105,7 @@ struct synaptics_data { int scroll; }; -int synaptics_detect(struct psmouse *psmouse, int set_properties); +int synaptics_detect(struct psmouse *psmouse, bool set_properties); int synaptics_init(struct psmouse *psmouse); void synaptics_reset(struct psmouse *psmouse); diff --git a/drivers/input/mouse/touchkit_ps2.c b/drivers/input/mouse/touchkit_ps2.c index 3fadb2accac..0308a0faa94 100644 --- a/drivers/input/mouse/touchkit_ps2.c +++ b/drivers/input/mouse/touchkit_ps2.c @@ -67,7 +67,7 @@ static psmouse_ret_t touchkit_ps2_process_byte(struct psmouse *psmouse) return PSMOUSE_FULL_PACKET; } -int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties) +int touchkit_ps2_detect(struct psmouse *psmouse, bool set_properties) { struct input_dev *dev = psmouse->dev; unsigned char param[3]; @@ -86,7 +86,7 @@ int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties) if (set_properties) { dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - set_bit(BTN_TOUCH, dev->keybit); + __set_bit(BTN_TOUCH, dev->keybit); input_set_abs_params(dev, ABS_X, 0, TOUCHKIT_MAX_XC, 0, 0); input_set_abs_params(dev, ABS_Y, 0, TOUCHKIT_MAX_YC, 0, 0); diff --git a/drivers/input/mouse/touchkit_ps2.h b/drivers/input/mouse/touchkit_ps2.h index 8a0dd3574ae..2efe9ea29d0 100644 --- a/drivers/input/mouse/touchkit_ps2.h +++ b/drivers/input/mouse/touchkit_ps2.h @@ -13,10 +13,10 @@ #define _TOUCHKIT_PS2_H #ifdef CONFIG_MOUSE_PS2_TOUCHKIT -int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties); +int touchkit_ps2_detect(struct psmouse *psmouse, bool set_properties); #else static inline int touchkit_ps2_detect(struct psmouse *psmouse, - int set_properties) + bool set_properties) { return -ENOSYS; } diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c index e68c814c436..e354362f297 100644 --- a/drivers/input/mouse/trackpoint.c +++ b/drivers/input/mouse/trackpoint.c @@ -282,7 +282,7 @@ static int trackpoint_reconnect(struct psmouse *psmouse) return 0; } -int trackpoint_detect(struct psmouse *psmouse, int set_properties) +int trackpoint_detect(struct psmouse *psmouse, bool set_properties) { struct trackpoint_data *priv; struct ps2dev *ps2dev = &psmouse->ps2dev; diff --git a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h index c10a6e7d010..e558a709661 100644 --- a/drivers/input/mouse/trackpoint.h +++ b/drivers/input/mouse/trackpoint.h @@ -143,9 +143,9 @@ struct trackpoint_data }; #ifdef CONFIG_MOUSE_PS2_TRACKPOINT -int trackpoint_detect(struct psmouse *psmouse, int set_properties); +int trackpoint_detect(struct psmouse *psmouse, bool set_properties); #else -inline int trackpoint_detect(struct psmouse *psmouse, int set_properties) +inline int trackpoint_detect(struct psmouse *psmouse, bool set_properties) { return -ENOSYS; } -- cgit v1.2.3-18-g5258 From 041b5eac254107cd3ba60034c38a411531cc64ee Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 6 Aug 2009 16:05:08 -0700 Subject: drivers/ata: use resource_size Use the function resource_size, which reduces the chance of introducing off-by-one errors in calculating the resource size. The semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @@ struct resource *res; @@ - (res->end - res->start) + 1 + resource_size(res) // Signed-off-by: Julia Lawall Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/pata_octeon_cf.c | 2 +- drivers/ata/pata_platform.c | 8 ++++---- drivers/ata/pata_rb532_cf.c | 2 +- drivers/ata/sata_mv.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c index e807cc3b6ab..d6f69561dc8 100644 --- a/drivers/ata/pata_octeon_cf.c +++ b/drivers/ata/pata_octeon_cf.c @@ -841,7 +841,7 @@ static int __devinit octeon_cf_probe(struct platform_device *pdev) ocd = pdev->dev.platform_data; cs0 = devm_ioremap_nocache(&pdev->dev, res_cs0->start, - res_cs0->end - res_cs0->start + 1); + resource_size(res_cs0)); if (!cs0) return -ENOMEM; diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index d8d743af322..3f6ebc6c665 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -151,14 +151,14 @@ int __devinit __pata_platform_probe(struct device *dev, */ if (mmio) { ap->ioaddr.cmd_addr = devm_ioremap(dev, io_res->start, - io_res->end - io_res->start + 1); + resource_size(io_res)); ap->ioaddr.ctl_addr = devm_ioremap(dev, ctl_res->start, - ctl_res->end - ctl_res->start + 1); + resource_size(ctl_res)); } else { ap->ioaddr.cmd_addr = devm_ioport_map(dev, io_res->start, - io_res->end - io_res->start + 1); + resource_size(io_res)); ap->ioaddr.ctl_addr = devm_ioport_map(dev, ctl_res->start, - ctl_res->end - ctl_res->start + 1); + resource_size(ctl_res)); } if (!ap->ioaddr.cmd_addr || !ap->ioaddr.ctl_addr) { dev_err(dev, "failed to map IO/CTL base\n"); diff --git a/drivers/ata/pata_rb532_cf.c b/drivers/ata/pata_rb532_cf.c index 8e3cdef8a25..45f1e10f917 100644 --- a/drivers/ata/pata_rb532_cf.c +++ b/drivers/ata/pata_rb532_cf.c @@ -151,7 +151,7 @@ static __devinit int rb532_pata_driver_probe(struct platform_device *pdev) info->irq = irq; info->iobase = devm_ioremap_nocache(&pdev->dev, res->start, - res->end - res->start + 1); + resource_size(res)); if (!info->iobase) return -ENOMEM; diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index c19417e0220..17f9ff9067a 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -4013,7 +4013,7 @@ static int mv_platform_probe(struct platform_device *pdev) host->iomap = NULL; hpriv->base = devm_ioremap(&pdev->dev, res->start, - res->end - res->start + 1); + resource_size(res)); hpriv->base -= SATAHC0_REG_BASE; /* -- cgit v1.2.3-18-g5258 From e2dd90b1ad4c61ecb52f2424049d91ce6ccc1f17 Mon Sep 17 00:00:00 2001 From: Shane Huang Date: Wed, 29 Jul 2009 11:34:49 +0800 Subject: ahci: Add AMD SB900 SATA/IDE controller device IDs Add AMD SB900 SATA/IDE controller device IDs. Signed-off-by: Shane Huang Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 6 ++++++ drivers/ata/pata_atiixp.c | 1 + drivers/ide/atiixp.c | 1 + drivers/pci/quirks.c | 4 +++- 4 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index a4e4cf141c0..5fb9c3a1f40 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -553,6 +553,12 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */ { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */ + /* AMD */ + { PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD SB900 */ + /* AMD is using RAID class only for ahci controllers */ + { PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci }, + /* VIA */ { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */ { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */ diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 45915566e4e..aa4b3f6ae77 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -246,6 +246,7 @@ static const struct pci_device_id atiixp[] = { { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), }, { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), }, { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP700_IDE), }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_SB900_IDE), }, { }, }; diff --git a/drivers/ide/atiixp.c b/drivers/ide/atiixp.c index 923cbfe259d..6396c3ad325 100644 --- a/drivers/ide/atiixp.c +++ b/drivers/ide/atiixp.c @@ -177,6 +177,7 @@ static const struct pci_device_id atiixp_pci_tbl[] = { { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), 0 }, { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), 1 }, { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP700_IDE), 0 }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_SB900_IDE), 0 }, { 0, }, }; MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 06b96562396..85ce23997be 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -992,7 +992,7 @@ DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, static void __devinit quirk_amd_ide_mode(struct pci_dev *pdev) { - /* set sb600/sb700/sb800 sata to ahci mode */ + /* set SBX00 SATA in IDE mode to AHCI mode */ u8 tmp; pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &tmp); @@ -1011,6 +1011,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk_amd_ide_mode); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk_amd_ide_mode); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk_amd_ide_mode); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_SB900_SATA_IDE, quirk_amd_ide_mode); +DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_SB900_SATA_IDE, quirk_amd_ide_mode); /* * Serverworks CSB5 IDE does not fully support native mode -- cgit v1.2.3-18-g5258 From 02cb009bb942007b76c38da4cc2ca0a0a974c667 Mon Sep 17 00:00:00 2001 From: Otavio Salvador Date: Fri, 3 Jul 2009 11:22:42 -0300 Subject: pata_cs5535: add pci id for AMD based CS5535 controllers Signed-off-by: Otavio Salvador Signed-off-by: Jeff Garzik --- drivers/ata/pata_cs5535.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index d33aa28239a..403f56165ce 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -202,7 +202,8 @@ static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id) } static const struct pci_device_id cs5535[] = { - { PCI_VDEVICE(NS, 0x002D), }, + { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_CS5535_IDE), }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5535_IDE), }, { }, }; -- cgit v1.2.3-18-g5258 From 78d5ae39af19a02a3d16213c0f62930d9a5d25f7 Mon Sep 17 00:00:00 2001 From: Shane Huang Date: Fri, 7 Aug 2009 15:05:52 +0800 Subject: ahci: kill @force_restart and refine CLO for ahci_kick_engine() This patch refines ahci_kick_engine() after discussion with Tejun about FBS(FIS-based switching) support preparation: a. Kill @force_restart and always kick the engine. The only case where @force_restart is zero is when it's called from ahci_p5wdh_hardreset() Actually at that point, BSY is pretty much guaranteed to be set. b. If PMP is attached, ignore busy and always do CLO. (AHCI-1.3 9.2) Signed-off-by: Shane Huang Acked-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 5fb9c3a1f40..d4cd9c20331 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1634,7 +1634,7 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16); } -static int ahci_kick_engine(struct ata_port *ap, int force_restart) +static int ahci_kick_engine(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); struct ahci_host_priv *hpriv = ap->host->private_data; @@ -1642,18 +1642,16 @@ static int ahci_kick_engine(struct ata_port *ap, int force_restart) u32 tmp; int busy, rc; - /* do we need to kick the port? */ - busy = status & (ATA_BUSY | ATA_DRQ); - if (!busy && !force_restart) - return 0; - /* stop engine */ rc = ahci_stop_engine(ap); if (rc) goto out_restart; - /* need to do CLO? */ - if (!busy) { + /* need to do CLO? + * always do CLO if PMP is attached (AHCI-1.3 9.2) + */ + busy = status & (ATA_BUSY | ATA_DRQ); + if (!busy && !sata_pmp_attached(ap)) { rc = 0; goto out_restart; } @@ -1701,7 +1699,7 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, timeout_msec); if (tmp & 0x1) { - ahci_kick_engine(ap, 1); + ahci_kick_engine(ap); return -EBUSY; } } else @@ -1724,7 +1722,7 @@ static int ahci_do_softreset(struct ata_link *link, unsigned int *class, DPRINTK("ENTER\n"); /* prepare for SRST (AHCI-1.1 10.4.1) */ - rc = ahci_kick_engine(ap, 1); + rc = ahci_kick_engine(ap); if (rc && rc != -EOPNOTSUPP) ata_link_printk(link, KERN_WARNING, "failed to reset engine (errno=%d)\n", rc); @@ -1940,7 +1938,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, rc = ata_wait_after_reset(link, jiffies + 2 * HZ, ahci_check_ready); if (rc) - ahci_kick_engine(ap, 0); + ahci_kick_engine(ap); } return rc; } @@ -2321,7 +2319,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) /* make DMA engine forget about the failed command */ if (qc->flags & ATA_QCFLAG_FAILED) - ahci_kick_engine(ap, 1); + ahci_kick_engine(ap); } static void ahci_pmp_attach(struct ata_port *ap) -- cgit v1.2.3-18-g5258 From c984123c7a888731b7e971e1c878b6f2b716b292 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Sun, 23 Aug 2009 20:23:34 +0200 Subject: pata_rz1000: use printk_once Signed-off-by: Marcin Slusarz Signed-off-by: Jeff Garzik --- drivers/ata/pata_rz1000.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 0c574c065c6..a5e4dfe60b4 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -85,7 +85,6 @@ static int rz1000_fifo_disable(struct pci_dev *pdev) static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { - static int printed_version; static const struct ata_port_info info = { .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = ATA_PIO4, @@ -93,8 +92,7 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en }; const struct ata_port_info *ppi[] = { &info, NULL }; - if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + printk_once(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); if (rz1000_fifo_disable(pdev) == 0) return ata_pci_sff_init_one(pdev, ppi, &rz1000_sht, NULL); -- cgit v1.2.3-18-g5258 From d8a8559cd7a9ccac98d5f6f13297a2ff68a43627 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 2 Sep 2009 12:34:32 +0200 Subject: writeback: get rid of generic_sync_sb_inodes() export This adds two new exported functions: - writeback_inodes_sb(), which only attempts to writeback dirty inodes on this super_block, for WB_SYNC_NONE writeout. - sync_inodes_sb(), which writes out all dirty inodes on this super_block and also waits for the IO to complete. Acked-by: Jan Kara Signed-off-by: Jens Axboe --- drivers/staging/pohmelfs/inode.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c index 7b605795b77..e63c9bea6c5 100644 --- a/drivers/staging/pohmelfs/inode.c +++ b/drivers/staging/pohmelfs/inode.c @@ -1950,14 +1950,7 @@ static int pohmelfs_get_sb(struct file_system_type *fs_type, */ static void pohmelfs_kill_super(struct super_block *sb) { - struct writeback_control wbc = { - .sync_mode = WB_SYNC_ALL, - .range_start = 0, - .range_end = LLONG_MAX, - .nr_to_write = LONG_MAX, - }; - generic_sync_sb_inodes(sb, &wbc); - + sync_inodes_sb(sb); kill_anon_super(sb); } -- cgit v1.2.3-18-g5258 From d993831fa7ffeb89e994f046f93eeb09ec91df08 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 12 Jun 2009 14:45:52 +0200 Subject: writeback: add name to backing_dev_info This enables us to track who does what and print info. Its main use is catching dirty inodes on the default_backing_dev_info, so we can fix that up. Signed-off-by: Jens Axboe --- drivers/block/aoe/aoeblk.c | 1 + drivers/char/mem.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 1e15889c4b9..95d344971ed 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -268,6 +268,7 @@ aoeblk_gdalloc(void *vp) if (!d->blkq) goto err_mempool; blk_queue_make_request(d->blkq, aoeblk_make_request); + d->blkq->backing_dev_info.name = "aoe"; if (bdi_init(&d->blkq->backing_dev_info)) goto err_blkq; spin_lock_irqsave(&d->lock, flags); diff --git a/drivers/char/mem.c b/drivers/char/mem.c index afa8813e737..645237bda68 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -822,6 +822,7 @@ static const struct file_operations zero_fops = { * - permits private mappings, "copies" are taken of the source of zeros */ static struct backing_dev_info zero_bdi = { + .name = "char/mem", .capabilities = BDI_CAP_MAP_COPY, }; -- cgit v1.2.3-18-g5258 From 1f1148c88ad37c87f14d2153416a605bf0aeaf74 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Fri, 11 Sep 2009 10:28:14 +0200 Subject: [S390] cio: fix ineffective verify event Path verification events occurring for offline devices are currently ignored. As a result, offline devices are not removed, even though they might no longer be accessible (for example because the last path to the device was varied offline). Fix this by scheduling a status evaluation for the affected subchannel when a path verification event occurs. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device_fsm.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 3db88c52d28..b8bdb0d7542 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -730,6 +730,17 @@ static void ccw_device_generic_notoper(struct ccw_device *cdev, css_schedule_eval(sch->schid); } +/* + * Handle path verification event in offline state. + */ +static void ccw_device_offline_verify(struct ccw_device *cdev, + enum dev_event dev_event) +{ + struct subchannel *sch = to_subchannel(cdev->dev.parent); + + css_schedule_eval(sch->schid); +} + /* * Handle path verification event. */ @@ -1149,7 +1160,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_offline_irq, [DEV_EVENT_TIMEOUT] = ccw_device_nop, - [DEV_EVENT_VERIFY] = ccw_device_nop, + [DEV_EVENT_VERIFY] = ccw_device_offline_verify, }, [DEV_STATE_VERIFY] = { [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, -- cgit v1.2.3-18-g5258 From 62733e5a5a480a893e56fa6133ae90904d857bc4 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 11 Sep 2009 10:28:15 +0200 Subject: [S390] cio: move scsw helper functions to header file All scsw helper functions are very short and usage of them shouldn't result in function calls. Therefore we move them to a separate header file. Also saves a lot of EXPORT_SYMBOLs. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/Makefile | 2 +- drivers/s390/cio/chsc.h | 24 -- drivers/s390/cio/scsw.c | 843 ---------------------------------------------- 3 files changed, 1 insertion(+), 868 deletions(-) delete mode 100644 drivers/s390/cio/scsw.c (limited to 'drivers') diff --git a/drivers/s390/cio/Makefile b/drivers/s390/cio/Makefile index adb3dd30152..fa4c9662f65 100644 --- a/drivers/s390/cio/Makefile +++ b/drivers/s390/cio/Makefile @@ -2,7 +2,7 @@ # Makefile for the S/390 common i/o drivers # -obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o scsw.o \ +obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o \ fcx.o itcw.o crw.o ccw_device-objs += device.o device_fsm.o device_ops.o ccw_device-objs += device_id.o device_pgid.o device_status.o diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 425e8f89a6c..37aa611d4ac 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -37,29 +37,6 @@ struct channel_path_desc { struct channel_path; -struct css_general_char { - u64 : 12; - u32 dynio : 1; /* bit 12 */ - u32 : 28; - u32 aif : 1; /* bit 41 */ - u32 : 3; - u32 mcss : 1; /* bit 45 */ - u32 fcs : 1; /* bit 46 */ - u32 : 1; - u32 ext_mb : 1; /* bit 48 */ - u32 : 7; - u32 aif_tdd : 1; /* bit 56 */ - u32 : 1; - u32 qebsm : 1; /* bit 58 */ - u32 : 8; - u32 aif_osa : 1; /* bit 67 */ - u32 : 14; - u32 cib : 1; /* bit 82 */ - u32 : 5; - u32 fcx : 1; /* bit 88 */ - u32 : 7; -}__attribute__((packed)); - struct css_chsc_char { u64 res; u64 : 20; @@ -72,7 +49,6 @@ struct css_chsc_char { u32 : 19; }__attribute__((packed)); -extern struct css_general_char css_general_characteristics; extern struct css_chsc_char css_chsc_characteristics; struct chsc_ssd_info { diff --git a/drivers/s390/cio/scsw.c b/drivers/s390/cio/scsw.c deleted file mode 100644 index f8da25ab576..00000000000 --- a/drivers/s390/cio/scsw.c +++ /dev/null @@ -1,843 +0,0 @@ -/* - * Helper functions for scsw access. - * - * Copyright IBM Corp. 2008 - * Author(s): Peter Oberparleiter - */ - -#include -#include -#include -#include "css.h" -#include "chsc.h" - -/** - * scsw_is_tm - check for transport mode scsw - * @scsw: pointer to scsw - * - * Return non-zero if the specified scsw is a transport mode scsw, zero - * otherwise. - */ -int scsw_is_tm(union scsw *scsw) -{ - return css_general_characteristics.fcx && (scsw->tm.x == 1); -} -EXPORT_SYMBOL(scsw_is_tm); - -/** - * scsw_key - return scsw key field - * @scsw: pointer to scsw - * - * Return the value of the key field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_key(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.key; - else - return scsw->cmd.key; -} -EXPORT_SYMBOL(scsw_key); - -/** - * scsw_eswf - return scsw eswf field - * @scsw: pointer to scsw - * - * Return the value of the eswf field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_eswf(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.eswf; - else - return scsw->cmd.eswf; -} -EXPORT_SYMBOL(scsw_eswf); - -/** - * scsw_cc - return scsw cc field - * @scsw: pointer to scsw - * - * Return the value of the cc field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_cc(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.cc; - else - return scsw->cmd.cc; -} -EXPORT_SYMBOL(scsw_cc); - -/** - * scsw_ectl - return scsw ectl field - * @scsw: pointer to scsw - * - * Return the value of the ectl field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_ectl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.ectl; - else - return scsw->cmd.ectl; -} -EXPORT_SYMBOL(scsw_ectl); - -/** - * scsw_pno - return scsw pno field - * @scsw: pointer to scsw - * - * Return the value of the pno field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_pno(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.pno; - else - return scsw->cmd.pno; -} -EXPORT_SYMBOL(scsw_pno); - -/** - * scsw_fctl - return scsw fctl field - * @scsw: pointer to scsw - * - * Return the value of the fctl field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_fctl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.fctl; - else - return scsw->cmd.fctl; -} -EXPORT_SYMBOL(scsw_fctl); - -/** - * scsw_actl - return scsw actl field - * @scsw: pointer to scsw - * - * Return the value of the actl field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_actl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.actl; - else - return scsw->cmd.actl; -} -EXPORT_SYMBOL(scsw_actl); - -/** - * scsw_stctl - return scsw stctl field - * @scsw: pointer to scsw - * - * Return the value of the stctl field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_stctl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.stctl; - else - return scsw->cmd.stctl; -} -EXPORT_SYMBOL(scsw_stctl); - -/** - * scsw_dstat - return scsw dstat field - * @scsw: pointer to scsw - * - * Return the value of the dstat field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_dstat(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.dstat; - else - return scsw->cmd.dstat; -} -EXPORT_SYMBOL(scsw_dstat); - -/** - * scsw_cstat - return scsw cstat field - * @scsw: pointer to scsw - * - * Return the value of the cstat field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_cstat(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.cstat; - else - return scsw->cmd.cstat; -} -EXPORT_SYMBOL(scsw_cstat); - -/** - * scsw_cmd_is_valid_key - check key field validity - * @scsw: pointer to scsw - * - * Return non-zero if the key field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_key(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_key); - -/** - * scsw_cmd_is_valid_sctl - check fctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fctl field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_sctl(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_sctl); - -/** - * scsw_cmd_is_valid_eswf - check eswf field validity - * @scsw: pointer to scsw - * - * Return non-zero if the eswf field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_eswf(union scsw *scsw) -{ - return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_eswf); - -/** - * scsw_cmd_is_valid_cc - check cc field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cc field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_cc(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) && - (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_cc); - -/** - * scsw_cmd_is_valid_fmt - check fmt field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fmt field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_fmt(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_fmt); - -/** - * scsw_cmd_is_valid_pfch - check pfch field validity - * @scsw: pointer to scsw - * - * Return non-zero if the pfch field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_pfch(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_pfch); - -/** - * scsw_cmd_is_valid_isic - check isic field validity - * @scsw: pointer to scsw - * - * Return non-zero if the isic field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_isic(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_isic); - -/** - * scsw_cmd_is_valid_alcc - check alcc field validity - * @scsw: pointer to scsw - * - * Return non-zero if the alcc field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_alcc(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_alcc); - -/** - * scsw_cmd_is_valid_ssi - check ssi field validity - * @scsw: pointer to scsw - * - * Return non-zero if the ssi field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_ssi(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_ssi); - -/** - * scsw_cmd_is_valid_zcc - check zcc field validity - * @scsw: pointer to scsw - * - * Return non-zero if the zcc field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_zcc(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) && - (scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_zcc); - -/** - * scsw_cmd_is_valid_ectl - check ectl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the ectl field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_ectl(union scsw *scsw) -{ - return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) && - !(scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) && - (scsw->cmd.stctl & SCSW_STCTL_ALERT_STATUS); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_ectl); - -/** - * scsw_cmd_is_valid_pno - check pno field validity - * @scsw: pointer to scsw - * - * Return non-zero if the pno field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_pno(union scsw *scsw) -{ - return (scsw->cmd.fctl != 0) && - (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) && - (!(scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) || - ((scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) && - (scsw->cmd.actl & SCSW_ACTL_SUSPENDED))); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_pno); - -/** - * scsw_cmd_is_valid_fctl - check fctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fctl field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_fctl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_cmd_is_valid_fctl); - -/** - * scsw_cmd_is_valid_actl - check actl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the actl field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_actl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_cmd_is_valid_actl); - -/** - * scsw_cmd_is_valid_stctl - check stctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the stctl field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_stctl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_cmd_is_valid_stctl); - -/** - * scsw_cmd_is_valid_dstat - check dstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the dstat field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_dstat(union scsw *scsw) -{ - return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) && - (scsw->cmd.cc != 3); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_dstat); - -/** - * scsw_cmd_is_valid_cstat - check cstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cstat field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_cstat(union scsw *scsw) -{ - return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) && - (scsw->cmd.cc != 3); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_cstat); - -/** - * scsw_tm_is_valid_key - check key field validity - * @scsw: pointer to scsw - * - * Return non-zero if the key field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_key(union scsw *scsw) -{ - return (scsw->tm.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_tm_is_valid_key); - -/** - * scsw_tm_is_valid_eswf - check eswf field validity - * @scsw: pointer to scsw - * - * Return non-zero if the eswf field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_eswf(union scsw *scsw) -{ - return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND); -} -EXPORT_SYMBOL(scsw_tm_is_valid_eswf); - -/** - * scsw_tm_is_valid_cc - check cc field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cc field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_cc(union scsw *scsw) -{ - return (scsw->tm.fctl & SCSW_FCTL_START_FUNC) && - (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND); -} -EXPORT_SYMBOL(scsw_tm_is_valid_cc); - -/** - * scsw_tm_is_valid_fmt - check fmt field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fmt field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_fmt(union scsw *scsw) -{ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_fmt); - -/** - * scsw_tm_is_valid_x - check x field validity - * @scsw: pointer to scsw - * - * Return non-zero if the x field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_x(union scsw *scsw) -{ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_x); - -/** - * scsw_tm_is_valid_q - check q field validity - * @scsw: pointer to scsw - * - * Return non-zero if the q field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_q(union scsw *scsw) -{ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_q); - -/** - * scsw_tm_is_valid_ectl - check ectl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the ectl field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_ectl(union scsw *scsw) -{ - return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) && - !(scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) && - (scsw->tm.stctl & SCSW_STCTL_ALERT_STATUS); -} -EXPORT_SYMBOL(scsw_tm_is_valid_ectl); - -/** - * scsw_tm_is_valid_pno - check pno field validity - * @scsw: pointer to scsw - * - * Return non-zero if the pno field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_pno(union scsw *scsw) -{ - return (scsw->tm.fctl != 0) && - (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) && - (!(scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) || - ((scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) && - (scsw->tm.actl & SCSW_ACTL_SUSPENDED))); -} -EXPORT_SYMBOL(scsw_tm_is_valid_pno); - -/** - * scsw_tm_is_valid_fctl - check fctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fctl field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_fctl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_fctl); - -/** - * scsw_tm_is_valid_actl - check actl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the actl field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_actl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_actl); - -/** - * scsw_tm_is_valid_stctl - check stctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the stctl field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_stctl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_stctl); - -/** - * scsw_tm_is_valid_dstat - check dstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the dstat field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_dstat(union scsw *scsw) -{ - return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) && - (scsw->tm.cc != 3); -} -EXPORT_SYMBOL(scsw_tm_is_valid_dstat); - -/** - * scsw_tm_is_valid_cstat - check cstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cstat field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_cstat(union scsw *scsw) -{ - return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) && - (scsw->tm.cc != 3); -} -EXPORT_SYMBOL(scsw_tm_is_valid_cstat); - -/** - * scsw_tm_is_valid_fcxs - check fcxs field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fcxs field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_fcxs(union scsw *scsw) -{ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_fcxs); - -/** - * scsw_tm_is_valid_schxs - check schxs field validity - * @scsw: pointer to scsw - * - * Return non-zero if the schxs field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_schxs(union scsw *scsw) -{ - return (scsw->tm.cstat & (SCHN_STAT_PROG_CHECK | - SCHN_STAT_INTF_CTRL_CHK | - SCHN_STAT_PROT_CHECK | - SCHN_STAT_CHN_DATA_CHK)); -} -EXPORT_SYMBOL(scsw_tm_is_valid_schxs); - -/** - * scsw_is_valid_actl - check actl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the actl field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_actl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_actl(scsw); - else - return scsw_cmd_is_valid_actl(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_actl); - -/** - * scsw_is_valid_cc - check cc field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cc field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_cc(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_cc(scsw); - else - return scsw_cmd_is_valid_cc(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_cc); - -/** - * scsw_is_valid_cstat - check cstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cstat field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_cstat(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_cstat(scsw); - else - return scsw_cmd_is_valid_cstat(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_cstat); - -/** - * scsw_is_valid_dstat - check dstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the dstat field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_dstat(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_dstat(scsw); - else - return scsw_cmd_is_valid_dstat(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_dstat); - -/** - * scsw_is_valid_ectl - check ectl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the ectl field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_ectl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_ectl(scsw); - else - return scsw_cmd_is_valid_ectl(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_ectl); - -/** - * scsw_is_valid_eswf - check eswf field validity - * @scsw: pointer to scsw - * - * Return non-zero if the eswf field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_eswf(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_eswf(scsw); - else - return scsw_cmd_is_valid_eswf(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_eswf); - -/** - * scsw_is_valid_fctl - check fctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fctl field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_fctl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_fctl(scsw); - else - return scsw_cmd_is_valid_fctl(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_fctl); - -/** - * scsw_is_valid_key - check key field validity - * @scsw: pointer to scsw - * - * Return non-zero if the key field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_key(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_key(scsw); - else - return scsw_cmd_is_valid_key(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_key); - -/** - * scsw_is_valid_pno - check pno field validity - * @scsw: pointer to scsw - * - * Return non-zero if the pno field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_pno(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_pno(scsw); - else - return scsw_cmd_is_valid_pno(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_pno); - -/** - * scsw_is_valid_stctl - check stctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the stctl field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_stctl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_stctl(scsw); - else - return scsw_cmd_is_valid_stctl(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_stctl); - -/** - * scsw_cmd_is_solicited - check for solicited scsw - * @scsw: pointer to scsw - * - * Return non-zero if the command mode scsw indicates that the associated - * status condition is solicited, zero if it is unsolicited. - */ -int scsw_cmd_is_solicited(union scsw *scsw) -{ - return (scsw->cmd.cc != 0) || (scsw->cmd.stctl != - (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)); -} -EXPORT_SYMBOL(scsw_cmd_is_solicited); - -/** - * scsw_tm_is_solicited - check for solicited scsw - * @scsw: pointer to scsw - * - * Return non-zero if the transport mode scsw indicates that the associated - * status condition is solicited, zero if it is unsolicited. - */ -int scsw_tm_is_solicited(union scsw *scsw) -{ - return (scsw->tm.cc != 0) || (scsw->tm.stctl != - (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)); -} -EXPORT_SYMBOL(scsw_tm_is_solicited); - -/** - * scsw_is_solicited - check for solicited scsw - * @scsw: pointer to scsw - * - * Return non-zero if the transport or command mode scsw indicates that the - * associated status condition is solicited, zero if it is unsolicited. - */ -int scsw_is_solicited(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_solicited(scsw); - else - return scsw_cmd_is_solicited(scsw); -} -EXPORT_SYMBOL(scsw_is_solicited); -- cgit v1.2.3-18-g5258 From 1da73bc80bdfc9588192a6e6f5a72f8138f7378d Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Fri, 11 Sep 2009 10:28:16 +0200 Subject: [S390] cio: consolidate subchannel intparm reset Ensure that the hardware interruption parameter for a subchannel is reset when the associated subchannel data structure is freed. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/css.c | 3 +++ drivers/s390/cio/device.c | 10 ---------- 2 files changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 85d43c6bcb6..40d4b3093b7 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -170,6 +170,9 @@ css_subchannel_release(struct device *dev) sch = to_subchannel(dev); if (!cio_is_console(sch->schid)) { + /* Reset intparm to zeroes. */ + sch->config.intparm = 0; + cio_commit_config(sch); kfree(sch->lock); kfree(sch); } diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index d593bc76afe..b6240227ecb 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1024,9 +1024,6 @@ static void ccw_device_call_sch_unregister(struct work_struct *work) return; sch = to_subchannel(cdev->dev.parent); css_sch_device_unregister(sch); - /* Reset intparm to zeroes. */ - sch->config.intparm = 0; - cio_commit_config(sch); /* Release cdev reference for workqueue processing.*/ put_device(&cdev->dev); /* Release subchannel reference for local processing. */ @@ -1210,9 +1207,6 @@ static void io_subchannel_do_unreg(struct work_struct *work) sch = container_of(work, struct subchannel, work); css_sch_device_unregister(sch); - /* Reset intparm to zeroes. */ - sch->config.intparm = 0; - cio_commit_config(sch); put_device(&sch->dev); } @@ -1688,10 +1682,6 @@ static int io_subchannel_sch_event(struct subchannel *sch, int slow) spin_unlock_irqrestore(sch->lock, flags); css_sch_device_unregister(sch); spin_lock_irqsave(sch->lock, flags); - - /* Reset intparm to zeroes. */ - sch->config.intparm = 0; - cio_commit_config(sch); break; case REPROBE: ccw_device_trigger_reprobe(cdev); -- cgit v1.2.3-18-g5258 From 626e476ae011cafddc0ccb39ab838b90cc5d2272 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 11 Sep 2009 10:28:17 +0200 Subject: [S390] cio: fix not oper handling after failed [on|off]line processing If online/offline processing of a ccw device fails, resulting in not operational state, notify the driver and unregister the device in case the driver dosn't want to keep it. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device_fsm.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index b8bdb0d7542..9c1452a6b9a 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -394,6 +394,13 @@ ccw_device_done(struct ccw_device *cdev, int state) ccw_device_schedule_sch_unregister(cdev); cdev->private->flags.donotify = 0; } + if (state == DEV_STATE_NOT_OPER) { + CIO_MSG_EVENT(0, "Device %04x gone on subchannel %04x\n", + cdev->private->dev_id.devno, sch->schid.sch_no); + if (!ccw_device_notify(cdev, CIO_GONE)) + ccw_device_schedule_sch_unregister(cdev); + cdev->private->flags.donotify = 0; + } if (cdev->private->flags.donotify) { cdev->private->flags.donotify = 0; -- cgit v1.2.3-18-g5258 From efd986db2d720e8f6660ec2c292509ee7d28cc6a Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 11 Sep 2009 10:28:18 +0200 Subject: [S390] cio: increase trace level Move debug traces for start I/O and interrupt events to exclusive trace levels. Also change tracing in hot-path from sprintf (costly) to hex. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/cio.c | 44 +++++++++++++++----------------------------- drivers/s390/cio/device.c | 4 ++-- 2 files changed, 17 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 5ec7789bd9d..390b4e96fd0 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -139,12 +139,11 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ __u8 lpm, /* logical path mask */ __u8 key) /* storage key */ { - char dbf_txt[15]; int ccode; union orb *orb; - CIO_TRACE_EVENT(4, "stIO"); - CIO_TRACE_EVENT(4, dev_name(&sch->dev)); + CIO_TRACE_EVENT(5, "stIO"); + CIO_TRACE_EVENT(5, dev_name(&sch->dev)); orb = &to_io_private(sch)->orb; memset(orb, 0, sizeof(union orb)); @@ -169,8 +168,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ ccode = ssch(sch->schid, orb); /* process condition code */ - sprintf(dbf_txt, "ccode:%d", ccode); - CIO_TRACE_EVENT(4, dbf_txt); + CIO_HEX_EVENT(5, &ccode, sizeof(ccode)); switch (ccode) { case 0: @@ -201,16 +199,14 @@ cio_start (struct subchannel *sch, struct ccw1 *cpa, __u8 lpm) int cio_resume (struct subchannel *sch) { - char dbf_txt[15]; int ccode; - CIO_TRACE_EVENT (4, "resIO"); + CIO_TRACE_EVENT(4, "resIO"); CIO_TRACE_EVENT(4, dev_name(&sch->dev)); ccode = rsch (sch->schid); - sprintf (dbf_txt, "ccode:%d", ccode); - CIO_TRACE_EVENT (4, dbf_txt); + CIO_HEX_EVENT(4, &ccode, sizeof(ccode)); switch (ccode) { case 0: @@ -235,13 +231,12 @@ cio_resume (struct subchannel *sch) int cio_halt(struct subchannel *sch) { - char dbf_txt[15]; int ccode; if (!sch) return -ENODEV; - CIO_TRACE_EVENT (2, "haltIO"); + CIO_TRACE_EVENT(2, "haltIO"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); /* @@ -249,8 +244,7 @@ cio_halt(struct subchannel *sch) */ ccode = hsch (sch->schid); - sprintf (dbf_txt, "ccode:%d", ccode); - CIO_TRACE_EVENT (2, dbf_txt); + CIO_HEX_EVENT(2, &ccode, sizeof(ccode)); switch (ccode) { case 0: @@ -270,13 +264,12 @@ cio_halt(struct subchannel *sch) int cio_clear(struct subchannel *sch) { - char dbf_txt[15]; int ccode; if (!sch) return -ENODEV; - CIO_TRACE_EVENT (2, "clearIO"); + CIO_TRACE_EVENT(2, "clearIO"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); /* @@ -284,8 +277,7 @@ cio_clear(struct subchannel *sch) */ ccode = csch (sch->schid); - sprintf (dbf_txt, "ccode:%d", ccode); - CIO_TRACE_EVENT (2, dbf_txt); + CIO_HEX_EVENT(2, &ccode, sizeof(ccode)); switch (ccode) { case 0: @@ -306,19 +298,17 @@ cio_clear(struct subchannel *sch) int cio_cancel (struct subchannel *sch) { - char dbf_txt[15]; int ccode; if (!sch) return -ENODEV; - CIO_TRACE_EVENT (2, "cancelIO"); + CIO_TRACE_EVENT(2, "cancelIO"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); ccode = xsch (sch->schid); - sprintf (dbf_txt, "ccode:%d", ccode); - CIO_TRACE_EVENT (2, dbf_txt); + CIO_HEX_EVENT(2, &ccode, sizeof(ccode)); switch (ccode) { case 0: /* success */ @@ -429,11 +419,10 @@ EXPORT_SYMBOL_GPL(cio_update_schib); */ int cio_enable_subchannel(struct subchannel *sch, u32 intparm) { - char dbf_txt[15]; int retry; int ret; - CIO_TRACE_EVENT (2, "ensch"); + CIO_TRACE_EVENT(2, "ensch"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); if (sch_is_pseudo_sch(sch)) @@ -460,8 +449,7 @@ int cio_enable_subchannel(struct subchannel *sch, u32 intparm) } else break; } - sprintf (dbf_txt, "ret:%d", ret); - CIO_TRACE_EVENT (2, dbf_txt); + CIO_HEX_EVENT(2, &ret, sizeof(ret)); return ret; } EXPORT_SYMBOL_GPL(cio_enable_subchannel); @@ -472,11 +460,10 @@ EXPORT_SYMBOL_GPL(cio_enable_subchannel); */ int cio_disable_subchannel(struct subchannel *sch) { - char dbf_txt[15]; int retry; int ret; - CIO_TRACE_EVENT (2, "dissch"); + CIO_TRACE_EVENT(2, "dissch"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); if (sch_is_pseudo_sch(sch)) @@ -495,8 +482,7 @@ int cio_disable_subchannel(struct subchannel *sch) } else break; } - sprintf (dbf_txt, "ret:%d", ret); - CIO_TRACE_EVENT (2, dbf_txt); + CIO_HEX_EVENT(2, &ret, sizeof(ret)); return ret; } EXPORT_SYMBOL_GPL(cio_disable_subchannel); diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index b6240227ecb..19b4469a3ca 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1168,8 +1168,8 @@ static void io_subchannel_irq(struct subchannel *sch) cdev = sch_get_cdev(sch); - CIO_TRACE_EVENT(3, "IRQ"); - CIO_TRACE_EVENT(3, dev_name(&sch->dev)); + CIO_TRACE_EVENT(6, "IRQ"); + CIO_TRACE_EVENT(6, dev_name(&sch->dev)); if (cdev) dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); } -- cgit v1.2.3-18-g5258 From e2910bcf8ca762b306767a0894ab1987be014c9e Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Fri, 11 Sep 2009 10:28:19 +0200 Subject: [S390] qdio: continue polling if the queue is not finished With commit c38f96080955854e54df9cb392bc674e1ae330e1 polling was stopped for the queue even if new data is available. Return immediately after scheduling the queue tasklet if the queue is not done. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 0038750ad94..9aef402a5f1 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -798,8 +798,10 @@ static void __tiqdio_inbound_processing(struct qdio_q *q) if (!qdio_inbound_q_done(q)) { qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop); - if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) + if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) { tasklet_schedule(&q->tasklet); + return; + } } qdio_stop_polling(q); -- cgit v1.2.3-18-g5258 From be7a2ddce66991c05a1c6ad19790289591e53547 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 11 Sep 2009 10:28:20 +0200 Subject: [S390] cio: ensure to hold a reference for deferred deregistration Ensure to always hold an extra device reference for scheduling a subchannel deregistration, by moving the get_device to ccw_device_schedule_sch_unregister. This fixes an use after free error in ccw_device_call_sch_unregister where put_device was called on an already freed device structure. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 19b4469a3ca..a7a340b1d71 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -333,15 +333,15 @@ ccw_device_remove_disconnected(struct ccw_device *cdev) * Forced offline in disconnected state means * 'throw away device'. */ - /* Get cdev reference for workqueue processing. */ - if (!get_device(&cdev->dev)) - return; if (ccw_device_is_orphan(cdev)) { /* * Deregister ccw device. * Unfortunately, we cannot do this directly from the * attribute method. */ + /* Get cdev reference for workqueue processing. */ + if (!get_device(&cdev->dev)) + return; spin_lock_irqsave(cdev->ccwlock, flags); cdev->private->state = DEV_STATE_NOT_OPER; spin_unlock_irqrestore(cdev->ccwlock, flags); @@ -1032,6 +1032,9 @@ static void ccw_device_call_sch_unregister(struct work_struct *work) void ccw_device_schedule_sch_unregister(struct ccw_device *cdev) { + /* Get cdev reference for workqueue processing. */ + if (!get_device(&cdev->dev)) + return; PREPARE_WORK(&cdev->private->kick_work, ccw_device_call_sch_unregister); queue_work(slow_path_wq, &cdev->private->kick_work); @@ -1052,9 +1055,6 @@ io_subchannel_recog_done(struct ccw_device *cdev) /* Device did not respond in time. */ case DEV_STATE_NOT_OPER: cdev->private->flags.recog_done = 1; - /* Remove device found not operational. */ - if (!get_device(&cdev->dev)) - break; ccw_device_schedule_sch_unregister(cdev); if (atomic_dec_and_test(&ccw_device_init_count)) wake_up(&ccw_device_init_wq); @@ -1565,8 +1565,6 @@ static int purge_fn(struct device *dev, void *data) spin_unlock_irq(cdev->ccwlock); if (!unreg) goto out; - if (!get_device(&cdev->dev)) - goto out; CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", priv->dev_id.ssid, priv->dev_id.devno); ccw_device_schedule_sch_unregister(cdev); -- cgit v1.2.3-18-g5258 From 217ee6c64a9589bc5ad4d1c88136fc359d17930b Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Fri, 11 Sep 2009 10:28:21 +0200 Subject: [S390] cio: failing set online/offline processing. When unit checks trigger sensing the device state is set to W4SENSE until sense completion; then the device state is set back to ONLINE. If a unit check occurs while set online or set offline requests are processed then it might happen that the device's temporary W4SENSE state causes these functions to terminate, leaving the device in an inconsistent state when the state is set back to ONLINE later on so that the device cannot be set online or offline any longer. To solve this, set online/offline and related rollback or error routines are processed only if the device is in a final or DISCONNECTED state. Signed-off-by: Michael Ernst Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 100 +++++++++++++++++++++++++++--------------- drivers/s390/cio/device_fsm.c | 2 + 2 files changed, 67 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index a7a340b1d71..a50cfa51aa3 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -380,30 +380,34 @@ int ccw_device_set_offline(struct ccw_device *cdev) } cdev->online = 0; spin_lock_irq(cdev->ccwlock); - ret = ccw_device_offline(cdev); - if (ret == -ENODEV) { - if (cdev->private->state != DEV_STATE_NOT_OPER) { - cdev->private->state = DEV_STATE_OFFLINE; - dev_fsm_event(cdev, DEV_EVENT_NOTOPER); - } + /* Wait until a final state or DISCONNECTED is reached */ + while (!dev_fsm_final_state(cdev) && + cdev->private->state != DEV_STATE_DISCONNECTED) { spin_unlock_irq(cdev->ccwlock); - /* Give up reference from ccw_device_set_online(). */ - put_device(&cdev->dev); - return ret; + wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) || + cdev->private->state == DEV_STATE_DISCONNECTED)); + spin_lock_irq(cdev->ccwlock); } + ret = ccw_device_offline(cdev); + if (ret) + goto error; spin_unlock_irq(cdev->ccwlock); - if (ret == 0) { - wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); - /* Give up reference from ccw_device_set_online(). */ - put_device(&cdev->dev); - } else { - CIO_MSG_EVENT(0, "ccw_device_offline returned %d, " - "device 0.%x.%04x\n", - ret, cdev->private->dev_id.ssid, - cdev->private->dev_id.devno); - cdev->online = 1; - } - return ret; + wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) || + cdev->private->state == DEV_STATE_DISCONNECTED)); + /* Give up reference from ccw_device_set_online(). */ + put_device(&cdev->dev); + return 0; + +error: + CIO_MSG_EVENT(0, "ccw_device_offline returned %d, device 0.%x.%04x\n", + ret, cdev->private->dev_id.ssid, + cdev->private->dev_id.devno); + cdev->private->state = DEV_STATE_OFFLINE; + dev_fsm_event(cdev, DEV_EVENT_NOTOPER); + spin_unlock_irq(cdev->ccwlock); + /* Give up reference from ccw_device_set_online(). */ + put_device(&cdev->dev); + return -ENODEV; } /** @@ -421,6 +425,7 @@ int ccw_device_set_offline(struct ccw_device *cdev) int ccw_device_set_online(struct ccw_device *cdev) { int ret; + int ret2; if (!cdev) return -ENODEV; @@ -444,28 +449,53 @@ int ccw_device_set_online(struct ccw_device *cdev) put_device(&cdev->dev); return ret; } - if (cdev->private->state != DEV_STATE_ONLINE) { + spin_lock_irq(cdev->ccwlock); + /* Check if online processing was successful */ + if ((cdev->private->state != DEV_STATE_ONLINE) && + (cdev->private->state != DEV_STATE_W4SENSE)) { + spin_unlock_irq(cdev->ccwlock); /* Give up online reference since onlining failed. */ put_device(&cdev->dev); return -ENODEV; } - if (!cdev->drv->set_online || cdev->drv->set_online(cdev) == 0) { - cdev->online = 1; - return 0; - } + spin_unlock_irq(cdev->ccwlock); + if (cdev->drv->set_online) + ret = cdev->drv->set_online(cdev); + if (ret) + goto rollback; + cdev->online = 1; + return 0; + +rollback: spin_lock_irq(cdev->ccwlock); - ret = ccw_device_offline(cdev); + /* Wait until a final state or DISCONNECTED is reached */ + while (!dev_fsm_final_state(cdev) && + cdev->private->state != DEV_STATE_DISCONNECTED) { + spin_unlock_irq(cdev->ccwlock); + wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) || + cdev->private->state == DEV_STATE_DISCONNECTED)); + spin_lock_irq(cdev->ccwlock); + } + ret2 = ccw_device_offline(cdev); + if (ret2) + goto error; spin_unlock_irq(cdev->ccwlock); - if (ret == 0) - wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); - else - CIO_MSG_EVENT(0, "ccw_device_offline returned %d, " - "device 0.%x.%04x\n", - ret, cdev->private->dev_id.ssid, - cdev->private->dev_id.devno); + wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) || + cdev->private->state == DEV_STATE_DISCONNECTED)); /* Give up online reference since onlining failed. */ put_device(&cdev->dev); - return (ret == 0) ? -ENODEV : ret; + return ret; + +error: + CIO_MSG_EVENT(0, "rollback ccw_device_offline returned %d, " + "device 0.%x.%04x\n", + ret2, cdev->private->dev_id.ssid, + cdev->private->dev_id.devno); + cdev->private->state = DEV_STATE_OFFLINE; + spin_unlock_irq(cdev->ccwlock); + /* Give up online reference since onlining failed. */ + put_device(&cdev->dev); + return ret; } static int online_store_handle_offline(struct ccw_device *cdev) diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 9c1452a6b9a..e728ce447f6 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -905,6 +905,8 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) } call_handler: cdev->private->state = DEV_STATE_ONLINE; + /* In case sensing interfered with setting the device online */ + wake_up(&cdev->private->wait_q); /* Call the handler. */ if (ccw_device_call_handler(cdev) && cdev->private->flags.doverify) /* Start delayed path verification. */ -- cgit v1.2.3-18-g5258 From 3f09bb8965cefe36f42a9ec09ebb821523eba530 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Fri, 11 Sep 2009 10:28:22 +0200 Subject: [S390] qdio: remove limited number of debugfs entries The number of qdio debugfs entries was limited. Remove this limit and group the queue files in a per device directory. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio.h | 4 +++- drivers/s390/cio/qdio_debug.c | 55 ++++++++++++------------------------------- 2 files changed, 18 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index b1241f8fae8..ff7748a9199 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -1,7 +1,7 @@ /* * linux/drivers/s390/cio/qdio.h * - * Copyright 2000,2008 IBM Corp. + * Copyright 2000,2009 IBM Corp. * Author(s): Utz Bacher * Jan Glauber */ @@ -246,6 +246,7 @@ struct qdio_q { atomic_t nr_buf_used; struct qdio_irq *irq_ptr; + struct dentry *debugfs_q; struct tasklet_struct tasklet; /* error condition during a data transfer */ @@ -267,6 +268,7 @@ struct qdio_irq { struct qib qib; u32 *dsci; /* address of device state change indicator */ struct ccw_device *cdev; + struct dentry *debugfs_dev; unsigned long int_parm; struct subchannel_id schid; diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index b8626d4df11..1b78f639ead 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -1,14 +1,12 @@ /* * drivers/s390/cio/qdio_debug.c * - * Copyright IBM Corp. 2008 + * Copyright IBM Corp. 2008,2009 * * Author: Jan Glauber (jang@linux.vnet.ibm.com) */ -#include #include #include -#include #include #include "qdio_debug.h" #include "qdio.h" @@ -17,10 +15,7 @@ debug_info_t *qdio_dbf_setup; debug_info_t *qdio_dbf_error; static struct dentry *debugfs_root; -#define MAX_DEBUGFS_QUEUES 32 -static struct dentry *debugfs_queues[MAX_DEBUGFS_QUEUES] = { NULL }; -static DEFINE_MUTEX(debugfs_mutex); -#define QDIO_DEBUGFS_NAME_LEN 40 +#define QDIO_DEBUGFS_NAME_LEN 10 void qdio_allocate_dbf(struct qdio_initialize *init_data, struct qdio_irq *irq_ptr) @@ -130,20 +125,6 @@ static int qstat_seq_open(struct inode *inode, struct file *filp) filp->f_path.dentry->d_inode->i_private); } -static void remove_debugfs_entry(struct qdio_q *q) -{ - int i; - - for (i = 0; i < MAX_DEBUGFS_QUEUES; i++) { - if (!debugfs_queues[i]) - continue; - if (debugfs_queues[i]->d_inode->i_private == q) { - debugfs_remove(debugfs_queues[i]); - debugfs_queues[i] = NULL; - } - } -} - static struct file_operations debugfs_fops = { .owner = THIS_MODULE, .open = qstat_seq_open, @@ -155,22 +136,15 @@ static struct file_operations debugfs_fops = { static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev) { - int i = 0; char name[QDIO_DEBUGFS_NAME_LEN]; - while (debugfs_queues[i] != NULL) { - i++; - if (i >= MAX_DEBUGFS_QUEUES) - return; - } - snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%s_%d", - dev_name(&cdev->dev), + snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d", q->is_input_q ? "input" : "output", q->nr); - debugfs_queues[i] = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR, - debugfs_root, q, &debugfs_fops); - if (IS_ERR(debugfs_queues[i])) - debugfs_queues[i] = NULL; + q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR, + q->irq_ptr->debugfs_dev, q, &debugfs_fops); + if (IS_ERR(q->debugfs_q)) + q->debugfs_q = NULL; } void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) @@ -178,12 +152,14 @@ void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) struct qdio_q *q; int i; - mutex_lock(&debugfs_mutex); + irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev), + debugfs_root); + if (IS_ERR(irq_ptr->debugfs_dev)) + irq_ptr->debugfs_dev = NULL; for_each_input_queue(irq_ptr, q, i) setup_debugfs_entry(q, cdev); for_each_output_queue(irq_ptr, q, i) setup_debugfs_entry(q, cdev); - mutex_unlock(&debugfs_mutex); } void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) @@ -191,17 +167,16 @@ void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cd struct qdio_q *q; int i; - mutex_lock(&debugfs_mutex); for_each_input_queue(irq_ptr, q, i) - remove_debugfs_entry(q); + debugfs_remove(q->debugfs_q); for_each_output_queue(irq_ptr, q, i) - remove_debugfs_entry(q); - mutex_unlock(&debugfs_mutex); + debugfs_remove(q->debugfs_q); + debugfs_remove(irq_ptr->debugfs_dev); } int __init qdio_debug_init(void) { - debugfs_root = debugfs_create_dir("qdio_queues", NULL); + debugfs_root = debugfs_create_dir("qdio", NULL); qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16); debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view); -- cgit v1.2.3-18-g5258 From f014824ee72e66292c3b1172dc142f959b42e61b Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 11 Sep 2009 10:28:23 +0200 Subject: [S390] cio: fix use after free in s390 debug feature When using s390dbf with "%s" in sprintf format strings the string itself is not copied to the dbf buffer. Since in this case only pointers are stored in the s390dbf, we should not use dev_name - which is bound to the lifetime of the device. Reading this entry from s390dbf after the device was released will cause an use after free error. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index a50cfa51aa3..6b770f8c0a8 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -2038,7 +2038,9 @@ static void __ccw_device_pm_restore(struct ccw_device *cdev) spin_unlock_irq(sch->lock); if (ret) { CIO_MSG_EVENT(0, "Couldn't start recognition for device " - "%s (ret=%d)\n", dev_name(&cdev->dev), ret); + "0.%x.%04x (ret=%d)\n", + cdev->private->dev_id.ssid, + cdev->private->dev_id.devno, ret); spin_lock_irq(sch->lock); cdev->private->state = DEV_STATE_DISCONNECTED; spin_unlock_irq(sch->lock); @@ -2101,8 +2103,9 @@ static int ccw_device_pm_restore(struct device *dev) } /* check if the device id has changed */ if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) { - CIO_MSG_EVENT(0, "resume: sch %s: failed (devno changed from " - "%04x to %04x)\n", dev_name(&sch->dev), + CIO_MSG_EVENT(0, "resume: sch 0.%x.%04x: failed (devno " + "changed from %04x to %04x)\n", + sch->schid.ssid, sch->schid.sch_no, cdev->private->dev_id.devno, sch->schib.pmcw.dev); goto out_unreg_unlock; @@ -2135,8 +2138,9 @@ static int ccw_device_pm_restore(struct device *dev) if (cm_enabled) { ret = ccw_set_cmf(cdev, 1); if (ret) { - CIO_MSG_EVENT(2, "resume: cdev %s: cmf failed " - "(rc=%d)\n", dev_name(&cdev->dev), ret); + CIO_MSG_EVENT(2, "resume: cdev 0.%x.%04x: cmf failed " + "(rc=%d)\n", cdev->private->dev_id.ssid, + cdev->private->dev_id.devno, ret); ret = 0; } } -- cgit v1.2.3-18-g5258 From ab6aae09024be1b039df441fa1b64dbe092d0acb Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 11 Sep 2009 10:28:24 +0200 Subject: [S390] cio: fix memleak in subchannel validation When scanning for new subchannels we have a code path where we allocate memory for a struct subchannel, set the device name (which is dynamically allocated now) and do a check if the underlying device is blacklisted - if so we free the subchannel structure. Since we have not set up refcounting at this stage, the device name's memory is lost. Fix this by moving the dev_set_name after the blacklist test. Note: With this patch the init_name for the console subchannel becomes virtually obsolete. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/cio.c | 5 ----- drivers/s390/cio/css.c | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 390b4e96fd0..fe18ef691bb 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -564,11 +564,6 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid) goto out; } mutex_init(&sch->reg_mutex); - /* Set a name for the subchannel */ - if (cio_is_console(schid)) - sch->dev.init_name = cio_get_console_sch_name(schid); - else - dev_set_name(&sch->dev, "0.%x.%04x", schid.ssid, schid.sch_no); /* * The first subchannel that is not-operational (ccode==3) diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 40d4b3093b7..0dc6f6d2628 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -183,6 +183,11 @@ static int css_sch_device_register(struct subchannel *sch) int ret; mutex_lock(&sch->reg_mutex); + if (cio_is_console(sch->schid)) + sch->dev.init_name = cio_get_console_sch_name(sch->schid); + else + dev_set_name(&sch->dev, "0.%x.%04x", sch->schid.ssid, + sch->schid.sch_no); ret = device_register(&sch->dev); mutex_unlock(&sch->reg_mutex); return ret; -- cgit v1.2.3-18-g5258 From 6ee4fec6be06f7d138860b37cba58982cc3ccb16 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 11 Sep 2009 10:28:25 +0200 Subject: [S390] cio: remove subchannel init_name We used the init_name to set the console subchannels name early at the boot stage. With the patch cio: fix memleak in subchannel validation we moved the name setting to the point where we actually register the console subchannel. At this time we can do dynamic allocations and therefore use dev_set_name. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/cio.c | 7 ------- drivers/s390/cio/cio.h | 2 -- drivers/s390/cio/css.c | 7 ++----- 3 files changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index fe18ef691bb..138124fcfca 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -667,7 +667,6 @@ void __irq_entry do_IRQ(struct pt_regs *regs) #ifdef CONFIG_CCW_CONSOLE static struct subchannel console_subchannel; -static char console_sch_name[10] = "0.x.xxxx"; static struct io_subchannel_private console_priv; static int console_subchannel_in_use; @@ -854,12 +853,6 @@ cio_get_console_subchannel(void) return &console_subchannel; } -const char *cio_get_console_sch_name(struct subchannel_id schid) -{ - snprintf(console_sch_name, 10, "0.%x.%04x", schid.ssid, schid.sch_no); - return (const char *)console_sch_name; -} - #endif static int __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index 5150fba742a..883e19d83e4 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h @@ -133,14 +133,12 @@ extern int cio_is_console(struct subchannel_id); extern struct subchannel *cio_get_console_subchannel(void); extern spinlock_t * cio_get_console_lock(void); extern void *cio_get_console_priv(void); -extern const char *cio_get_console_sch_name(struct subchannel_id schid); extern const char *cio_get_console_cdev_name(struct subchannel *sch); #else #define cio_is_console(schid) 0 #define cio_get_console_subchannel() NULL #define cio_get_console_lock() NULL #define cio_get_console_priv() NULL -#define cio_get_console_sch_name(schid) NULL #define cio_get_console_cdev_name(sch) NULL #endif diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 0dc6f6d2628..0a3ce6522f0 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -183,11 +183,8 @@ static int css_sch_device_register(struct subchannel *sch) int ret; mutex_lock(&sch->reg_mutex); - if (cio_is_console(sch->schid)) - sch->dev.init_name = cio_get_console_sch_name(sch->schid); - else - dev_set_name(&sch->dev, "0.%x.%04x", sch->schid.ssid, - sch->schid.sch_no); + dev_set_name(&sch->dev, "0.%x.%04x", sch->schid.ssid, + sch->schid.sch_no); ret = device_register(&sch->dev); mutex_unlock(&sch->reg_mutex); return ret; -- cgit v1.2.3-18-g5258 From 3b554a14f4bdf754ba9d2f64c2b6edf8dafe93b9 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 11 Sep 2009 10:28:26 +0200 Subject: [S390] cio: move final put_device to ccw_device_unregister We use a test_and_clear_bit to prevent a device from being unregistered twice. Unfortunately in this cases the "final" put_device (from device_initialize) was issued more than once, resulting in an use after free error. Fix this by moving this put_device to ccw_device_unregister. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 6b770f8c0a8..345a61f45a5 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -307,8 +307,11 @@ int ccw_device_is_orphan(struct ccw_device *cdev) static void ccw_device_unregister(struct ccw_device *cdev) { - if (test_and_clear_bit(1, &cdev->private->registered)) + if (test_and_clear_bit(1, &cdev->private->registered)) { device_del(&cdev->dev); + /* Release reference from device_initialize(). */ + put_device(&cdev->dev); + } } static void ccw_device_remove_orphan_cb(struct work_struct *work) @@ -319,7 +322,6 @@ static void ccw_device_remove_orphan_cb(struct work_struct *work) priv = container_of(work, struct ccw_device_private, kick_work); cdev = priv->cdev; ccw_device_unregister(cdev); - put_device(&cdev->dev); /* Release cdev reference for workqueue processing. */ put_device(&cdev->dev); } @@ -1358,7 +1360,6 @@ io_subchannel_remove (struct subchannel *sch) cdev->private->state = DEV_STATE_NOT_OPER; spin_unlock_irqrestore(cdev->ccwlock, flags); ccw_device_unregister(cdev); - put_device(&cdev->dev); kfree(sch->private); sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); return 0; -- cgit v1.2.3-18-g5258 From 3ac276f8cb020adbbc3399c47edc1100748c2c16 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 11 Sep 2009 10:28:27 +0200 Subject: [S390] cio: remove ccw_device init_name We used the init_name to set the console ccw_device's name early at the boot stage. This patch moves the name setting (for all ccw devices) to the point where we actually register the device. At this time we can do dynamic allocations and therefore use dev_set_name. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/cio.h | 2 -- drivers/s390/cio/device.c | 23 ++++++----------------- 2 files changed, 6 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index 883e19d83e4..2e43558c704 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h @@ -133,13 +133,11 @@ extern int cio_is_console(struct subchannel_id); extern struct subchannel *cio_get_console_subchannel(void); extern spinlock_t * cio_get_console_lock(void); extern void *cio_get_console_priv(void); -extern const char *cio_get_console_cdev_name(struct subchannel *sch); #else #define cio_is_console(schid) 0 #define cio_get_console_subchannel() NULL #define cio_get_console_lock() NULL #define cio_get_console_priv() NULL -#define cio_get_console_cdev_name(sch) NULL #endif #endif diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 345a61f45a5..0f95405c2c5 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -669,8 +669,12 @@ static int ccw_device_register(struct ccw_device *cdev) int ret; dev->bus = &ccw_bus_type; - - if ((ret = device_add(dev))) + ret = dev_set_name(&cdev->dev, "0.%x.%04x", cdev->private->dev_id.ssid, + cdev->private->dev_id.devno); + if (ret) + return ret; + ret = device_add(dev); + if (ret) return ret; set_bit(1, &cdev->private->registered); @@ -1124,13 +1128,6 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) init_waitqueue_head(&priv->wait_q); init_timer(&priv->timer); - /* Set an initial name for the device. */ - if (cio_is_console(sch->schid)) - cdev->dev.init_name = cio_get_console_cdev_name(sch); - else - dev_set_name(&cdev->dev, "0.%x.%04x", - sch->schid.ssid, sch->schib.pmcw.dev); - /* Increase counter of devices currently in recognition. */ atomic_inc(&ccw_device_init_count); @@ -1731,7 +1728,6 @@ static int io_subchannel_sch_event(struct subchannel *sch, int slow) #ifdef CONFIG_CCW_CONSOLE static struct ccw_device console_cdev; -static char console_cdev_name[10] = "0.x.xxxx"; static struct ccw_device_private console_private; static int console_cdev_in_use; @@ -1815,13 +1811,6 @@ int ccw_device_force_console(void) return ccw_device_pm_restore(&console_cdev.dev); } EXPORT_SYMBOL_GPL(ccw_device_force_console); - -const char *cio_get_console_cdev_name(struct subchannel *sch) -{ - snprintf(console_cdev_name, 10, "0.%x.%04x", - sch->schid.ssid, sch->schib.pmcw.dev); - return (const char *)console_cdev_name; -} #endif /* -- cgit v1.2.3-18-g5258 From 97f604b07473669f4da52b1f859ee45e8d48d42a Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Fri, 11 Sep 2009 10:28:28 +0200 Subject: [S390] dasd: fail requests when device state is less then ready A DASD device that is not ready or online has no defined disk layout, so all requests that arrive in such a state need to be returned as failed. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 3f62dd50bbb..f8445b8ff17 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1699,8 +1699,11 @@ static void __dasd_process_request_queue(struct dasd_block *block) * for that. State DASD_STATE_ONLINE is normal block device * operation. */ - if (basedev->state < DASD_STATE_READY) + if (basedev->state < DASD_STATE_READY) { + while ((req = blk_fetch_request(block->request_queue))) + __blk_end_request_all(req, -EIO); return; + } /* Now we try to fetch requests from the request queue */ while (!blk_queue_plugged(queue) && (req = blk_peek_request(queue))) { if (basedev->features & DASD_FEATURE_READONLY && -- cgit v1.2.3-18-g5258 From 68b781fe1bed89011ab7c58ede8476abe64432d2 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Fri, 11 Sep 2009 10:28:29 +0200 Subject: [S390] dasd: optimize cpu usage in goodcase remove unnecessary dbf call, remove string operations for magic Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 21 ++++++++----------- drivers/s390/block/dasd_alias.c | 3 +-- drivers/s390/block/dasd_diag.c | 3 +-- drivers/s390/block/dasd_eckd.c | 45 +++++++++++++++++------------------------ drivers/s390/block/dasd_eer.c | 2 +- drivers/s390/block/dasd_fba.c | 7 +++---- drivers/s390/block/dasd_int.h | 11 +++++++--- 7 files changed, 41 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index f8445b8ff17..e109da4583a 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -669,14 +669,14 @@ static void dasd_profile_end(struct dasd_block *block, * memory and 2) dasd_smalloc_request uses the static ccw memory * that gets allocated for each device. */ -struct dasd_ccw_req *dasd_kmalloc_request(char *magic, int cplength, +struct dasd_ccw_req *dasd_kmalloc_request(int magic, int cplength, int datasize, struct dasd_device *device) { struct dasd_ccw_req *cqr; /* Sanity checks */ - BUG_ON( magic == NULL || datasize > PAGE_SIZE || + BUG_ON(datasize > PAGE_SIZE || (cplength*sizeof(struct ccw1)) > PAGE_SIZE); cqr = kzalloc(sizeof(struct dasd_ccw_req), GFP_ATOMIC); @@ -700,14 +700,13 @@ struct dasd_ccw_req *dasd_kmalloc_request(char *magic, int cplength, return ERR_PTR(-ENOMEM); } } - strncpy((char *) &cqr->magic, magic, 4); - ASCEBC((char *) &cqr->magic, 4); + cqr->magic = magic; set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); dasd_get_device(device); return cqr; } -struct dasd_ccw_req *dasd_smalloc_request(char *magic, int cplength, +struct dasd_ccw_req *dasd_smalloc_request(int magic, int cplength, int datasize, struct dasd_device *device) { @@ -717,7 +716,7 @@ struct dasd_ccw_req *dasd_smalloc_request(char *magic, int cplength, int size; /* Sanity checks */ - BUG_ON( magic == NULL || datasize > PAGE_SIZE || + BUG_ON(datasize > PAGE_SIZE || (cplength*sizeof(struct ccw1)) > PAGE_SIZE); size = (sizeof(struct dasd_ccw_req) + 7L) & -8L; @@ -744,8 +743,7 @@ struct dasd_ccw_req *dasd_smalloc_request(char *magic, int cplength, cqr->data = data; memset(cqr->data, 0, datasize); } - strncpy((char *) &cqr->magic, magic, 4); - ASCEBC((char *) &cqr->magic, 4); + cqr->magic = magic; set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); dasd_get_device(device); return cqr; @@ -899,9 +897,6 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) switch (rc) { case 0: cqr->status = DASD_CQR_IN_IO; - DBF_DEV_EVENT(DBF_DEBUG, device, - "start_IO: request %p started successful", - cqr); break; case -EBUSY: DBF_DEV_EVENT(DBF_DEBUG, device, "%s", @@ -2533,7 +2528,7 @@ EXPORT_SYMBOL_GPL(dasd_generic_restore_device); static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, void *rdc_buffer, int rdc_buffer_size, - char *magic) + int magic) { struct dasd_ccw_req *cqr; struct ccw1 *ccw; @@ -2564,7 +2559,7 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, } -int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic, +int dasd_generic_read_dev_chars(struct dasd_device *device, int magic, void *rdc_buffer, int rdc_buffer_size) { int ret; diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 5b7bbc87593..b9efd09cefe 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c @@ -379,8 +379,7 @@ static int read_unit_address_configuration(struct dasd_device *device, int rc; unsigned long flags; - cqr = dasd_kmalloc_request("ECKD", - 1 /* PSF */ + 1 /* RSSD */ , + cqr = dasd_kmalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */, (sizeof(struct dasd_psf_prssd_data)), device); if (IS_ERR(cqr)) diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 644086ba2ed..0b89796080b 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -523,8 +523,7 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev, /* Build the request */ datasize = sizeof(struct dasd_diag_req) + count*sizeof(struct dasd_diag_bio); - cqr = dasd_smalloc_request(dasd_diag_discipline.name, 0, - datasize, memdev); + cqr = dasd_smalloc_request(DASD_DIAG_MAGIC, 0, datasize, memdev); if (IS_ERR(cqr)) return cqr; diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index c11770f5b36..f15addf728d 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -730,7 +730,8 @@ static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device, struct dasd_ccw_req *cqr; struct ccw1 *ccw; - cqr = dasd_smalloc_request("ECKD", 1 /* RCD */, ciw->count, device); + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* RCD */, ciw->count, + device); if (IS_ERR(cqr)) { DBF_DEV_EVENT(DBF_WARNING, device, "%s", @@ -934,8 +935,7 @@ static int dasd_eckd_read_features(struct dasd_device *device) struct dasd_eckd_private *private; private = (struct dasd_eckd_private *) device->private; - cqr = dasd_smalloc_request(dasd_eckd_discipline.name, - 1 /* PSF */ + 1 /* RSSD */ , + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */, (sizeof(struct dasd_psf_prssd_data) + sizeof(struct dasd_rssd_features)), device); @@ -998,7 +998,7 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device, struct dasd_psf_ssc_data *psf_ssc_data; struct ccw1 *ccw; - cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ , + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ , sizeof(struct dasd_psf_ssc_data), device); @@ -1149,8 +1149,8 @@ dasd_eckd_check_characteristics(struct dasd_device *device) goto out_err3; /* Read Device Characteristics */ - rc = dasd_generic_read_dev_chars(device, "ECKD", &private->rdc_data, - 64); + rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC, + &private->rdc_data, 64); if (rc) { DBF_EVENT(DBF_WARNING, "Read device characteristics failed, rc=%d for " @@ -1217,8 +1217,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device) cplength = 8; datasize = sizeof(struct DE_eckd_data) + 2*sizeof(struct LO_eckd_data); - cqr = dasd_smalloc_request(dasd_eckd_discipline.name, - cplength, datasize, device); + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, device); if (IS_ERR(cqr)) return cqr; ccw = cqr->cpaddr; @@ -1499,8 +1498,7 @@ dasd_eckd_format_device(struct dasd_device * device, return ERR_PTR(-EINVAL); } /* Allocate the format ccw request. */ - fcp = dasd_smalloc_request(dasd_eckd_discipline.name, - cplength, datasize, device); + fcp = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, device); if (IS_ERR(fcp)) return fcp; @@ -1783,8 +1781,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( datasize += count*sizeof(struct LO_eckd_data); } /* Allocate the ccw request. */ - cqr = dasd_smalloc_request(dasd_eckd_discipline.name, - cplength, datasize, startdev); + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, + startdev); if (IS_ERR(cqr)) return cqr; ccw = cqr->cpaddr; @@ -1948,8 +1946,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( cidaw * sizeof(unsigned long long); /* Allocate the ccw request. */ - cqr = dasd_smalloc_request(dasd_eckd_discipline.name, - cplength, datasize, startdev); + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, + startdev); if (IS_ERR(cqr)) return cqr; ccw = cqr->cpaddr; @@ -2249,8 +2247,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( /* Allocate the ccw request. */ itcw_size = itcw_calc_size(0, ctidaw, 0); - cqr = dasd_smalloc_request(dasd_eckd_discipline.name, - 0, itcw_size, startdev); + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 0, itcw_size, startdev); if (IS_ERR(cqr)) return cqr; @@ -2557,8 +2554,7 @@ dasd_eckd_release(struct dasd_device *device) if (!capable(CAP_SYS_ADMIN)) return -EACCES; - cqr = dasd_smalloc_request(dasd_eckd_discipline.name, - 1, 32, device); + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); if (IS_ERR(cqr)) { DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Could not allocate initialization request"); @@ -2600,8 +2596,7 @@ dasd_eckd_reserve(struct dasd_device *device) if (!capable(CAP_SYS_ADMIN)) return -EACCES; - cqr = dasd_smalloc_request(dasd_eckd_discipline.name, - 1, 32, device); + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); if (IS_ERR(cqr)) { DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Could not allocate initialization request"); @@ -2642,8 +2637,7 @@ dasd_eckd_steal_lock(struct dasd_device *device) if (!capable(CAP_SYS_ADMIN)) return -EACCES; - cqr = dasd_smalloc_request(dasd_eckd_discipline.name, - 1, 32, device); + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); if (IS_ERR(cqr)) { DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Could not allocate initialization request"); @@ -2681,8 +2675,7 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp) struct ccw1 *ccw; int rc; - cqr = dasd_smalloc_request(dasd_eckd_discipline.name, - 1 /* PSF */ + 1 /* RSSD */ , + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */, (sizeof(struct dasd_psf_prssd_data) + sizeof(struct dasd_rssd_perf_stats_t)), device); @@ -2828,7 +2821,7 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp) } /* setup CCWs for PSF + RSSD */ - cqr = dasd_smalloc_request("ECKD", 2 , 0, device); + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 2 , 0, device); if (IS_ERR(cqr)) { DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Could not allocate initialization request"); @@ -3254,7 +3247,7 @@ int dasd_eckd_restore_device(struct dasd_device *device) /* Read Device Characteristics */ memset(&private->rdc_data, 0, sizeof(private->rdc_data)); - rc = dasd_generic_read_dev_chars(device, "ECKD", + rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC, &private->rdc_data, 64); if (rc) { DBF_EVENT(DBF_WARNING, diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index c24c8c30380..6bd2bd54f22 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -464,7 +464,7 @@ int dasd_eer_enable(struct dasd_device *device) if (!device->discipline || strcmp(device->discipline->name, "ECKD")) return -EPERM; /* FIXME: -EMEDIUMTYPE ? */ - cqr = dasd_kmalloc_request("ECKD", 1 /* SNSS */, + cqr = dasd_kmalloc_request(DASD_ECKD_MAGIC, 1 /* SNSS */, SNSS_DATA_SIZE, device); if (IS_ERR(cqr)) return -ENOMEM; diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 31849ad5e59..403730cfaf8 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -152,8 +152,8 @@ dasd_fba_check_characteristics(struct dasd_device *device) block->base = device; /* Read Device Characteristics */ - rc = dasd_generic_read_dev_chars(device, "FBA ", &private->rdc_data, - 32); + rc = dasd_generic_read_dev_chars(device, DASD_FBA_MAGIC, + &private->rdc_data, 32); if (rc) { DBF_EVENT(DBF_WARNING, "Read device characteristics returned " "error %d for device: %s", @@ -305,8 +305,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, datasize += (count - 1)*sizeof(struct LO_fba_data); } /* Allocate the ccw request. */ - cqr = dasd_smalloc_request(dasd_fba_discipline.name, - cplength, datasize, memdev); + cqr = dasd_smalloc_request(DASD_FBA_MAGIC, cplength, datasize, memdev); if (IS_ERR(cqr)) return cqr; ccw = cqr->cpaddr; diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index b699ca356ac..5e47a1ee52b 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -59,6 +59,11 @@ #include #include +/* DASD discipline magic */ +#define DASD_ECKD_MAGIC 0xC5C3D2C4 +#define DASD_DIAG_MAGIC 0xC4C9C1C7 +#define DASD_FBA_MAGIC 0xC6C2C140 + /* * SECTION: Type definitions */ @@ -540,9 +545,9 @@ extern struct block_device_operations dasd_device_operations; extern struct kmem_cache *dasd_page_cache; struct dasd_ccw_req * -dasd_kmalloc_request(char *, int, int, struct dasd_device *); +dasd_kmalloc_request(int , int, int, struct dasd_device *); struct dasd_ccw_req * -dasd_smalloc_request(char *, int, int, struct dasd_device *); +dasd_smalloc_request(int , int, int, struct dasd_device *); void dasd_kfree_request(struct dasd_ccw_req *, struct dasd_device *); void dasd_sfree_request(struct dasd_ccw_req *, struct dasd_device *); @@ -587,7 +592,7 @@ void dasd_generic_handle_state_change(struct dasd_device *); int dasd_generic_pm_freeze(struct ccw_device *); int dasd_generic_restore_device(struct ccw_device *); -int dasd_generic_read_dev_chars(struct dasd_device *, char *, void *, int); +int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int); char *dasd_get_sense(struct irb *); /* externals in dasd_devmap.c */ -- cgit v1.2.3-18-g5258 From ca99dab01dd63dcc413395bd3e75b0be152dfefc Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Fri, 11 Sep 2009 10:28:30 +0200 Subject: [S390] dasd: fix message naming This patch fixes message naming so that generic dasd messages do not contain the device discipline. For this purpose the dev_ makros are replaced by pr_ makros for generic dasd messages. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_3990_erp.c | 2 +- drivers/s390/block/dasd_alias.c | 2 +- drivers/s390/block/dasd_diag.c | 2 +- drivers/s390/block/dasd_eckd.c | 2 +- drivers/s390/block/dasd_eer.c | 2 +- drivers/s390/block/dasd_erp.c | 4 ++-- drivers/s390/block/dasd_fba.c | 2 +- drivers/s390/block/dasd_ioctl.c | 24 ++++++++++++------------ 8 files changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 27991b69205..e8ff7b0c961 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -7,7 +7,7 @@ * */ -#define KMSG_COMPONENT "dasd" +#define KMSG_COMPONENT "dasd-eckd" #include #include diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index b9efd09cefe..70a008c0052 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c @@ -5,7 +5,7 @@ * Author(s): Stefan Weinhuber */ -#define KMSG_COMPONENT "dasd" +#define KMSG_COMPONENT "dasd-eckd" #include #include diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 0b89796080b..4e49b4a6c88 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -8,7 +8,7 @@ * */ -#define KMSG_COMPONENT "dasd" +#define KMSG_COMPONENT "dasd-diag" #include #include diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index f15addf728d..a1ce573648a 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -10,7 +10,7 @@ * Author.........: Nigel Hislop */ -#define KMSG_COMPONENT "dasd" +#define KMSG_COMPONENT "dasd-eckd" #include #include diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index 6bd2bd54f22..d96039eae59 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -6,7 +6,7 @@ * Author(s): Stefan Weinhuber */ -#define KMSG_COMPONENT "dasd" +#define KMSG_COMPONENT "dasd-eckd" #include #include diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c index cb8f9cef742..7656384a811 100644 --- a/drivers/s390/block/dasd_erp.c +++ b/drivers/s390/block/dasd_erp.c @@ -99,8 +99,8 @@ dasd_default_erp_action(struct dasd_ccw_req *cqr) cqr->lpm = LPM_ANYPATH; cqr->status = DASD_CQR_FILLED; } else { - dev_err(&device->cdev->dev, - "default ERP has run out of retries and failed\n"); + pr_err("%s: default ERP has run out of retries and failed\n", + dev_name(&device->cdev->dev)); cqr->status = DASD_CQR_FAILED; cqr->stopclk = get_clock(); } diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 403730cfaf8..f245377e8e2 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -5,7 +5,7 @@ * Copyright IBM Corp. 1999, 2009 */ -#define KMSG_COMPONENT "dasd" +#define KMSG_COMPONENT "dasd-fba" #include #include diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index df918ef2796..f756a1b0c57 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -98,8 +98,8 @@ static int dasd_ioctl_quiesce(struct dasd_block *block) if (!capable (CAP_SYS_ADMIN)) return -EACCES; - dev_info(&base->cdev->dev, "The DASD has been put in the quiesce " - "state\n"); + pr_info("%s: The DASD has been put in the quiesce " + "state\n", dev_name(&base->cdev->dev)); spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); base->stopped |= DASD_STOPPED_QUIESCE; spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); @@ -119,8 +119,8 @@ static int dasd_ioctl_resume(struct dasd_block *block) if (!capable (CAP_SYS_ADMIN)) return -EACCES; - dev_info(&base->cdev->dev, "I/O operations have been resumed " - "on the DASD\n"); + pr_info("%s: I/O operations have been resumed " + "on the DASD\n", dev_name(&base->cdev->dev)); spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); base->stopped &= ~DASD_STOPPED_QUIESCE; spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); @@ -146,8 +146,8 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata) return -EPERM; if (base->state != DASD_STATE_BASIC) { - dev_warn(&base->cdev->dev, - "The DASD cannot be formatted while it is enabled\n"); + pr_warning("%s: The DASD cannot be formatted while it is " + "enabled\n", dev_name(&base->cdev->dev)); return -EBUSY; } @@ -175,9 +175,9 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata) dasd_sfree_request(cqr, cqr->memdev); if (rc) { if (rc != -ERESTARTSYS) - dev_err(&base->cdev->dev, - "Formatting unit %d failed with " - "rc=%d\n", fdata->start_unit, rc); + pr_err("%s: Formatting unit %d failed with " + "rc=%d\n", dev_name(&base->cdev->dev), + fdata->start_unit, rc); return rc; } fdata->start_unit++; @@ -204,9 +204,9 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp) if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) return -EFAULT; if (bdev != bdev->bd_contains) { - dev_warn(&block->base->cdev->dev, - "The specified DASD is a partition and cannot be " - "formatted\n"); + pr_warning("%s: The specified DASD is a partition and cannot " + "be formatted\n", + dev_name(&block->base->cdev->dev)); return -EINVAL; } return dasd_format(block, &fdata); -- cgit v1.2.3-18-g5258 From c6304933274f8e3cc6983d496456757ac8ab2e0b Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 11 Sep 2009 10:28:38 +0200 Subject: [S390] proper use of device register Don't use kfree directly after device registration started. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/char/hvc_iucv.c | 2 +- drivers/s390/char/monreader.c | 2 +- drivers/s390/char/vmlogrdr.c | 4 +++- drivers/s390/cio/chp.c | 3 ++- drivers/s390/cio/css.c | 23 ++++++++--------------- drivers/s390/crypto/ap_bus.c | 2 +- drivers/s390/net/netiucv.c | 9 ++++++--- drivers/s390/net/smsgiucv.c | 6 +++--- 8 files changed, 25 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c index 86105efb4eb..0ecac7e532f 100644 --- a/drivers/char/hvc_iucv.c +++ b/drivers/char/hvc_iucv.c @@ -1006,7 +1006,7 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console) priv->dev->release = (void (*)(struct device *)) kfree; rc = device_register(priv->dev); if (rc) { - kfree(priv->dev); + put_device(priv->dev); goto out_error_dev; } diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index 3234e90bd7f..89ece1c235a 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -581,7 +581,7 @@ static int __init mon_init(void) monreader_device->release = (void (*)(struct device *))kfree; rc = device_register(monreader_device); if (rc) { - kfree(monreader_device); + put_device(monreader_device); goto out_driver; } diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index c20a4fe6da5..d1a142fa3eb 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -765,8 +765,10 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) } else return -ENOMEM; ret = device_register(dev); - if (ret) + if (ret) { + put_device(dev); return ret; + } ret = sysfs_create_group(&dev->kobj, &vmlogrdr_attr_group); if (ret) { diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 3e5f304ad88..40002830d48 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -417,7 +417,8 @@ int chp_new(struct chp_id chpid) if (ret) { CIO_MSG_EVENT(0, "Could not register chp%x.%02x: %d\n", chpid.cssid, chpid.id, ret); - goto out_free; + put_device(&chp->dev); + goto out; } ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group); if (ret) { diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 0a3ce6522f0..45858f3b731 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -151,18 +151,6 @@ css_alloc_subchannel(struct subchannel_id schid) return sch; } -static void -css_free_subchannel(struct subchannel *sch) -{ - if (sch) { - /* Reset intparm to zeroes. */ - sch->config.intparm = 0; - cio_commit_config(sch); - kfree(sch->lock); - kfree(sch); - } -} - static void css_subchannel_release(struct device *dev) { @@ -332,7 +320,7 @@ int css_probe_device(struct subchannel_id schid) return PTR_ERR(sch); ret = css_register_subchannel(sch); if (ret) - css_free_subchannel(sch); + put_device(&sch->dev); return ret; } @@ -649,7 +637,10 @@ __init_channel_subsystem(struct subchannel_id schid, void *data) * not working) so we do it now. This is true e.g. for the * console subchannel. */ - css_register_subchannel(sch); + if (css_register_subchannel(sch)) { + if (!cio_is_console(schid)) + put_device(&sch->dev); + } return 0; } @@ -925,8 +916,10 @@ init_channel_subsystem (void) goto out_device; } ret = device_register(&css->pseudo_subchannel->dev); - if (ret) + if (ret) { + put_device(&css->pseudo_subchannel->dev); goto out_file; + } } ret = register_reboot_notifier(&css_reboot_notifier); if (ret) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index ed3dcdea7fe..ae9ab240c7f 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -1114,7 +1114,7 @@ static void ap_scan_bus(struct work_struct *unused) ap_dev->device.release = ap_device_release; rc = device_register(&ap_dev->device); if (rc) { - kfree(ap_dev); + put_device(&ap_dev->device); continue; } /* Add device attributes. */ diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 8c36eafcfbf..87dff11061b 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1839,9 +1839,10 @@ static int netiucv_register_device(struct net_device *ndev) return -ENOMEM; ret = device_register(dev); - - if (ret) + if (ret) { + put_device(dev); return ret; + } ret = netiucv_add_files(dev); if (ret) goto out_unreg; @@ -2226,8 +2227,10 @@ static int __init netiucv_init(void) netiucv_dev->release = (void (*)(struct device *))kfree; netiucv_dev->driver = &netiucv_driver; rc = device_register(netiucv_dev); - if (rc) + if (rc) { + put_device(netiucv_dev); goto out_driver; + } netiucv_banner(); return rc; diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index e76a320d373..102000d1af6 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c @@ -219,13 +219,13 @@ static int __init smsg_init(void) smsg_dev->driver = &smsg_driver; rc = device_register(smsg_dev); if (rc) - goto out_free_dev; + goto out_put; cpcmd("SET SMSG IUCV", NULL, 0, NULL); return 0; -out_free_dev: - kfree(smsg_dev); +out_put: + put_device(smsg_dev); out_free_path: iucv_path_free(smsg_path); smsg_path = NULL; -- cgit v1.2.3-18-g5258 From 6292b9ef5a4e85d6b782412a85725dd38df24b85 Mon Sep 17 00:00:00 2001 From: Frank Munzert Date: Fri, 11 Sep 2009 10:28:39 +0200 Subject: [S390] tape: use init_timer_on_stack() rather than init_timer() With CONFIG_DEBUG_OBJECTS_TIMERS=y "chccwdev --online" for a tape device will fail with message "ODEBUG: object is on stack, but not annotated". We now use init_timer_on_stack. Signed-off-by: Frank Munzert Signed-off-by: Martin Schwidefsky --- drivers/s390/char/tape_std.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c index 1a9420ba518..750354ad16e 100644 --- a/drivers/s390/char/tape_std.c +++ b/drivers/s390/char/tape_std.c @@ -68,7 +68,7 @@ tape_std_assign(struct tape_device *device) * to another host (actually this shouldn't happen but it does). * So we set up a timeout for this call. */ - init_timer(&timeout); + init_timer_on_stack(&timeout); timeout.function = tape_std_assign_timeout; timeout.data = (unsigned long) request; timeout.expires = jiffies + 2 * HZ; -- cgit v1.2.3-18-g5258 From c114728af2acdca0bd8b1d2f5792e393c775f5fc Mon Sep 17 00:00:00 2001 From: Hans-Joachim Picht Date: Fri, 11 Sep 2009 10:28:47 +0200 Subject: [S390] add call home support Signed-off-by: Hans-Joachim Picht Signed-off-by: Martin Schwidefsky --- drivers/s390/char/Kconfig | 10 ++ drivers/s390/char/Makefile | 1 + drivers/s390/char/sclp.h | 4 +- drivers/s390/char/sclp_async.c | 224 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 238 insertions(+), 1 deletion(-) create mode 100644 drivers/s390/char/sclp_async.c (limited to 'drivers') diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig index 0769ced52db..4e34d3686c2 100644 --- a/drivers/s390/char/Kconfig +++ b/drivers/s390/char/Kconfig @@ -82,6 +82,16 @@ config SCLP_CPI You should only select this option if you know what you are doing, need this feature and intend to run your kernel in LPAR. +config SCLP_ASYNC + tristate "Support for Call Home via Asynchronous SCLP Records" + depends on S390 + help + This option enables the call home function, which is able to inform + the service element and connected organisations about a kernel panic. + You should only select this option if you know what you are doing, + want for inform other people about your kernel panics, + need this feature and intend to run your kernel in LPAR. + config S390_TAPE tristate "S/390 tape device support" depends on CCW diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index 7e73e39a174..efb500ab66c 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_SCLP_TTY) += sclp_tty.o obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o obj-$(CONFIG_SCLP_CPI) += sclp_cpi.o +obj-$(CONFIG_SCLP_ASYNC) += sclp_async.o obj-$(CONFIG_ZVM_WATCHDOG) += vmwatchdog.o obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 60e7cb07095..6bb5a6bdfab 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -27,6 +27,7 @@ #define EVTYP_VT220MSG 0x1A #define EVTYP_CONFMGMDATA 0x04 #define EVTYP_SDIAS 0x1C +#define EVTYP_ASYNC 0x0A #define EVTYP_OPCMD_MASK 0x80000000 #define EVTYP_MSG_MASK 0x40000000 @@ -38,6 +39,7 @@ #define EVTYP_VT220MSG_MASK 0x00000040 #define EVTYP_CONFMGMDATA_MASK 0x10000000 #define EVTYP_SDIAS_MASK 0x00000010 +#define EVTYP_ASYNC_MASK 0x00400000 #define GNRLMSGFLGS_DOM 0x8000 #define GNRLMSGFLGS_SNDALRM 0x4000 @@ -85,12 +87,12 @@ struct sccb_header { } __attribute__((packed)); extern u64 sclp_facilities; - #define SCLP_HAS_CHP_INFO (sclp_facilities & 0x8000000000000000ULL) #define SCLP_HAS_CHP_RECONFIG (sclp_facilities & 0x2000000000000000ULL) #define SCLP_HAS_CPU_INFO (sclp_facilities & 0x0800000000000000ULL) #define SCLP_HAS_CPU_RECONFIG (sclp_facilities & 0x0400000000000000ULL) + struct gds_subvector { u8 length; u8 key; diff --git a/drivers/s390/char/sclp_async.c b/drivers/s390/char/sclp_async.c new file mode 100644 index 00000000000..daaec185ed3 --- /dev/null +++ b/drivers/s390/char/sclp_async.c @@ -0,0 +1,224 @@ +/* + * Enable Asynchronous Notification via SCLP. + * + * Copyright IBM Corp. 2009 + * Author(s): Hans-Joachim Picht + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sclp.h" + +static int callhome_enabled; +static struct sclp_req *request; +static struct sclp_async_sccb *sccb; +static int sclp_async_send_wait(char *message); +static struct ctl_table_header *callhome_sysctl_header; +static DEFINE_SPINLOCK(sclp_async_lock); +static char nodename[64]; +#define SCLP_NORMAL_WRITE 0x00 + +struct async_evbuf { + struct evbuf_header header; + u64 reserved; + u8 rflags; + u8 empty; + u8 rtype; + u8 otype; + char comp_id[12]; + char data[3000]; /* there is still some space left */ +} __attribute__((packed)); + +struct sclp_async_sccb { + struct sccb_header header; + struct async_evbuf evbuf; +} __attribute__((packed)); + +static struct sclp_register sclp_async_register = { + .send_mask = EVTYP_ASYNC_MASK, +}; + +static int call_home_on_panic(struct notifier_block *self, + unsigned long event, void *data) +{ + strncat(data, nodename, strlen(nodename)); + sclp_async_send_wait(data); + return NOTIFY_DONE; +} + +static struct notifier_block call_home_panic_nb = { + .notifier_call = call_home_on_panic, + .priority = INT_MAX, +}; + +static int proc_handler_callhome(ctl_table *ctl, int write, struct file *filp, + void __user *buffer, size_t *count, + loff_t *ppos) +{ + unsigned long val; + int len, rc; + char buf[2]; + + if (!*count | (*ppos && !write)) { + *count = 0; + return 0; + } + if (!write) { + len = sprintf(buf, "%d\n", callhome_enabled); + buf[len] = '\0'; + rc = copy_to_user(buffer, buf, sizeof(buf)); + if (rc != 0) + return -EFAULT; + } else { + len = *count; + rc = copy_from_user(buf, buffer, sizeof(buf)); + if (rc != 0) + return -EFAULT; + if (strict_strtoul(buf, 0, &val) != 0) + return -EINVAL; + if (val != 0 && val != 1) + return -EINVAL; + callhome_enabled = val; + } + *count = len; + *ppos += len; + return 0; +} + +static struct ctl_table callhome_table[] = { + { + .procname = "callhome", + .mode = 0644, + .proc_handler = &proc_handler_callhome, + }, + { .ctl_name = 0 } +}; + +static struct ctl_table kern_dir_table[] = { + { + .ctl_name = CTL_KERN, + .procname = "kernel", + .maxlen = 0, + .mode = 0555, + .child = callhome_table, + }, + { .ctl_name = 0 } +}; + +/* + * Function used to transfer asynchronous notification + * records which waits for send completion + */ +static int sclp_async_send_wait(char *message) +{ + struct async_evbuf *evb; + int rc; + unsigned long flags; + + if (!callhome_enabled) + return 0; + sccb->evbuf.header.type = EVTYP_ASYNC; + sccb->evbuf.rtype = 0xA5; + sccb->evbuf.otype = 0x00; + evb = &sccb->evbuf; + request->command = SCLP_CMDW_WRITE_EVENT_DATA; + request->sccb = sccb; + request->status = SCLP_REQ_FILLED; + strncpy(sccb->evbuf.data, message, sizeof(sccb->evbuf.data)); + /* + * Retain Queue + * e.g. 5639CC140 500 Red Hat RHEL5 Linux for zSeries (RHEL AS) + */ + strncpy(sccb->evbuf.comp_id, "000000000", sizeof(sccb->evbuf.comp_id)); + sccb->evbuf.header.length = sizeof(sccb->evbuf); + sccb->header.length = sizeof(sccb->evbuf) + sizeof(sccb->header); + sccb->header.function_code = SCLP_NORMAL_WRITE; + rc = sclp_add_request(request); + if (rc) + return rc; + spin_lock_irqsave(&sclp_async_lock, flags); + while (request->status != SCLP_REQ_DONE && + request->status != SCLP_REQ_FAILED) { + sclp_sync_wait(); + } + spin_unlock_irqrestore(&sclp_async_lock, flags); + if (request->status != SCLP_REQ_DONE) + return -EIO; + rc = ((struct sclp_async_sccb *) + request->sccb)->header.response_code; + if (rc != 0x0020) + return -EIO; + if (evb->header.flags != 0x80) + return -EIO; + return rc; +} + +static int __init sclp_async_init(void) +{ + int rc; + + rc = sclp_register(&sclp_async_register); + if (rc) + return rc; + callhome_sysctl_header = register_sysctl_table(kern_dir_table); + if (!callhome_sysctl_header) { + rc = -ENOMEM; + goto out_sclp; + } + if (!(sclp_async_register.sclp_receive_mask & EVTYP_ASYNC_MASK)) { + rc = -EOPNOTSUPP; + goto out_sclp; + } + rc = -ENOMEM; + request = kzalloc(sizeof(struct sclp_req), GFP_KERNEL); + if (!request) + goto out_sys; + sccb = (struct sclp_async_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!sccb) + goto out_mem; + rc = atomic_notifier_chain_register(&panic_notifier_list, + &call_home_panic_nb); + if (rc) + goto out_mem; + + strncpy(nodename, init_utsname()->nodename, 64); + return 0; + +out_mem: + kfree(request); + free_page((unsigned long) sccb); +out_sys: + unregister_sysctl_table(callhome_sysctl_header); +out_sclp: + sclp_unregister(&sclp_async_register); + return rc; + +} +module_init(sclp_async_init); + +static void __exit sclp_async_exit(void) +{ + atomic_notifier_chain_unregister(&panic_notifier_list, + &call_home_panic_nb); + unregister_sysctl_table(callhome_sysctl_header); + sclp_unregister(&sclp_async_register); + free_page((unsigned long) sccb); + kfree(request); +} +module_exit(sclp_async_exit); + +MODULE_AUTHOR("Copyright IBM Corp. 2009"); +MODULE_AUTHOR("Hans-Joachim Picht "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SCLP Asynchronous Notification Records"); -- cgit v1.2.3-18-g5258 From 3f7cb51fac60618aa543058a90e668956d5fb518 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 11 Sep 2009 10:28:49 +0200 Subject: [S390] vmur: Invalid allocation sequence for vmur class The vmur class is allocated after the CCW driver is registered and it is destroyed before the CCW driver is unregistered. This is not the correct sequence, because the vmur class can be used via driver core callbacks that are triggered during the CCW driver deregistration. For Example: 1. vmur device is online 2. vmur module is unloaded This leads to the following function call stack: <4> [<0000000000387286>] device_destroy+0x36/0x5c <4> [<000003e000209714>] ur_set_offline_force+0x9c/0x10c [vmur] <4> [<000003e00020a928>] ur_remove+0x64/0xbc [vmur] <4> [<00000000003e4d2e>] ccw_device_remove+0x42/0x1ac <4> [<000000000038a1aa>] __device_release_driver+0x9a/0xe4 <4> [<000000000038a2da>] driver_detach+0xe6/0xec <4> [<0000000000388ee4>] bus_remove_driver+0xc0/0x108 <4> [<000003e00020ad5a>] ur_exit+0x52/0x84 [vmur] In device_destroy() the vmur class is used. Since it is already freed, this can lead to a kernel panic. To fix the problem, the vmur class has to be allocated before the CCW driver is registered and destroyed after the CCW driver has ben unregistered. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- drivers/s390/char/vmur.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index 31b902e94f7..77571b68539 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -1026,9 +1026,15 @@ static int __init ur_init(void) debug_set_level(vmur_dbf, 6); + vmur_class = class_create(THIS_MODULE, "vmur"); + if (IS_ERR(vmur_class)) { + rc = PTR_ERR(vmur_class); + goto fail_free_dbf; + } + rc = ccw_driver_register(&ur_driver); if (rc) - goto fail_free_dbf; + goto fail_class_destroy; rc = alloc_chrdev_region(&dev, 0, NUM_MINORS, "vmur"); if (rc) { @@ -1038,18 +1044,13 @@ static int __init ur_init(void) } ur_first_dev_maj_min = MKDEV(MAJOR(dev), 0); - vmur_class = class_create(THIS_MODULE, "vmur"); - if (IS_ERR(vmur_class)) { - rc = PTR_ERR(vmur_class); - goto fail_unregister_region; - } pr_info("%s loaded.\n", ur_banner); return 0; -fail_unregister_region: - unregister_chrdev_region(ur_first_dev_maj_min, NUM_MINORS); fail_unregister_driver: ccw_driver_unregister(&ur_driver); +fail_class_destroy: + class_destroy(vmur_class); fail_free_dbf: debug_unregister(vmur_dbf); return rc; @@ -1057,9 +1058,9 @@ fail_free_dbf: static void __exit ur_exit(void) { - class_destroy(vmur_class); unregister_chrdev_region(ur_first_dev_maj_min, NUM_MINORS); ccw_driver_unregister(&ur_driver); + class_destroy(vmur_class); debug_unregister(vmur_dbf); pr_info("%s unloaded.\n", ur_banner); } -- cgit v1.2.3-18-g5258 From 99b5e2d3d7ae8f5a2dba7a41a02ba7eb25523b3f Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 11 Sep 2009 10:28:50 +0200 Subject: [S390] xpram: Remove checksum validation for suspend/resume Currently in the suspend process checksums for the XPRAM partitions are created and stored. During the resume process it is checked, if the checksums are still the same. If this is not the case, a kernel panic is triggered. Unfortunately this prevents XPRAM from beeing used as suspend device, because in this case after the checksum has been created, the memory image is written to XPRAM and therefore the contents of the suspend partition is changed. In order to allow XPRAM to be used as suspend device, this patch removes the checksum validation. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- drivers/s390/block/xpram.c | 65 ---------------------------------------------- 1 file changed, 65 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index db442cd6621..ee604e92a5f 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -42,7 +42,6 @@ #include #include #include -#include #define XPRAM_NAME "xpram" #define XPRAM_DEVS 1 /* one partition */ @@ -51,7 +50,6 @@ typedef struct { unsigned int size; /* size of xpram segment in pages */ unsigned int offset; /* start page of xpram segment */ - unsigned int csum; /* partition checksum for suspend */ } xpram_device_t; static xpram_device_t xpram_devices[XPRAM_MAX_DEVS]; @@ -386,58 +384,6 @@ out: return rc; } -/* - * Save checksums for all partitions. - */ -static int xpram_save_checksums(void) -{ - unsigned long mem_page; - int rc, i; - - rc = 0; - mem_page = (unsigned long) __get_free_page(GFP_KERNEL); - if (!mem_page) - return -ENOMEM; - for (i = 0; i < xpram_devs; i++) { - rc = xpram_page_in(mem_page, xpram_devices[i].offset); - if (rc) - goto fail; - xpram_devices[i].csum = csum_partial((const void *) mem_page, - PAGE_SIZE, 0); - } -fail: - free_page(mem_page); - return rc ? -ENXIO : 0; -} - -/* - * Verify checksums for all partitions. - */ -static int xpram_validate_checksums(void) -{ - unsigned long mem_page; - unsigned int csum; - int rc, i; - - rc = 0; - mem_page = (unsigned long) __get_free_page(GFP_KERNEL); - if (!mem_page) - return -ENOMEM; - for (i = 0; i < xpram_devs; i++) { - rc = xpram_page_in(mem_page, xpram_devices[i].offset); - if (rc) - goto fail; - csum = csum_partial((const void *) mem_page, PAGE_SIZE, 0); - if (xpram_devices[i].csum != csum) { - rc = -EINVAL; - goto fail; - } - } -fail: - free_page(mem_page); - return rc ? -ENXIO : 0; -} - /* * Resume failed: Print error message and call panic. */ @@ -458,21 +404,10 @@ static int xpram_restore(struct device *dev) xpram_resume_error("xpram disappeared"); if (xpram_pages != xpram_highest_page_index() + 1) xpram_resume_error("Size of xpram changed"); - if (xpram_validate_checksums()) - xpram_resume_error("Data of xpram changed"); return 0; } -/* - * Save necessary state in suspend. - */ -static int xpram_freeze(struct device *dev) -{ - return xpram_save_checksums(); -} - static struct dev_pm_ops xpram_pm_ops = { - .freeze = xpram_freeze, .restore = xpram_restore, }; -- cgit v1.2.3-18-g5258 From 95f1556c35529a162cef50296f3dc7f978852048 Mon Sep 17 00:00:00 2001 From: Felix Beck Date: Fri, 11 Sep 2009 10:28:51 +0200 Subject: [S390] zcrypt: Use spin_lock_bh in suspend callback Fix lock dependency warning. inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage. bash/1442 [HC0[0]:SC0[0]:HE1:SE1] takes: (&ap_dev->lock){+.?...}, at: [<000003e001280404>] __ap_poll_device+0x40/0x3e8 [ap] {IN-SOFTIRQ-W} state was registered at: [<000000000017f094>] __lock_acquire+0xb78/0x182c [<000000000017fe8e>] lock_acquire+0x146/0x178 [<0000000000549cf2>] _spin_lock+0x5a/0x98 [<000003e001280404>] __ap_poll_device+0x40/0x3e8 [ap] [<000003e001280afe>] ap_poll_all+0xaa/0x1a4 [ap] [<000000000014fa82>] tasklet_action+0xfe/0x1f4 [<0000000000150a56>] __do_softirq+0x116/0x284 [<0000000000111058>] do_softirq+0xe4/0xe8 [<00000000001504ba>] irq_exit+0xba/0xd8 [<00000000003dd04a>] do_IRQ+0x176/0x1fc [<000000000011823c>] io_return+0x0/0x8 [<0000004bfbfd2c0e>] 0x4bfbfd2c0e Signed-off-by: Felix Beck Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index ae9ab240c7f..85785807acb 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -648,7 +648,9 @@ static int ap_bus_suspend(struct device *dev, pm_message_t state) /* Poll on the device until all requests are finished. */ do { flags = 0; + spin_lock_bh(&ap_dev->lock); __ap_poll_device(ap_dev, &flags); + spin_unlock_bh(&ap_dev->lock); } while ((flags & 1) || (flags & 2)); ap_device_remove(dev); @@ -1407,14 +1409,12 @@ static void ap_reset(struct ap_device *ap_dev) static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags) { - spin_lock(&ap_dev->lock); if (!ap_dev->unregistered) { if (ap_poll_queue(ap_dev, flags)) ap_dev->unregistered = 1; if (ap_dev->reset == AP_RESET_DO) ap_reset(ap_dev); } - spin_unlock(&ap_dev->lock); return 0; } @@ -1441,7 +1441,9 @@ static void ap_poll_all(unsigned long dummy) flags = 0; spin_lock(&ap_device_list_lock); list_for_each_entry(ap_dev, &ap_device_list, list) { + spin_lock(&ap_dev->lock); __ap_poll_device(ap_dev, &flags); + spin_unlock(&ap_dev->lock); } spin_unlock(&ap_device_list_lock); } while (flags & 1); @@ -1487,7 +1489,9 @@ static int ap_poll_thread(void *data) flags = 0; spin_lock_bh(&ap_device_list_lock); list_for_each_entry(ap_dev, &ap_device_list, list) { + spin_lock(&ap_dev->lock); __ap_poll_device(ap_dev, &flags); + spin_unlock(&ap_dev->lock); } spin_unlock_bh(&ap_device_list_lock); } -- cgit v1.2.3-18-g5258 From edc44fa03ed7bc9847787e080190cf1d7ed68ceb Mon Sep 17 00:00:00 2001 From: Felix Beck Date: Fri, 11 Sep 2009 10:28:52 +0200 Subject: [S390] zcrypt: Free ap_device if dev_set_name fails. If dev_set_name fails during scanning the AP bus, the reserved memory has to be freed. Signed-off-by: Felix Beck Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 85785807acb..090b32a339c 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -1111,8 +1111,11 @@ static void ap_scan_bus(struct work_struct *unused) ap_dev->device.bus = &ap_bus_type; ap_dev->device.parent = ap_root_device; - dev_set_name(&ap_dev->device, "card%02x", - AP_QID_DEVICE(ap_dev->qid)); + if (dev_set_name(&ap_dev->device, "card%02x", + AP_QID_DEVICE(ap_dev->qid))) { + kfree(ap_dev); + continue; + } ap_dev->device.release = ap_device_release; rc = device_register(&ap_dev->device); if (rc) { -- cgit v1.2.3-18-g5258 From 68d36bdbf6377d36129b2c6bcbe9d24c5fb1739a Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Fri, 11 Sep 2009 10:28:55 +0200 Subject: [S390] tape: reversed order of labels Fix the order of goto labels in tape_generic_online. Signed-off-by: Roel Kluin --- drivers/s390/char/tape_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 1d420d94759..7424d648e81 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -358,11 +358,11 @@ tape_generic_online(struct tape_device *device, out_char: tapechar_cleanup_device(device); +out_minor: + tape_remove_minor(device); out_discipline: device->discipline->cleanup_device(device); device->discipline = NULL; -out_minor: - tape_remove_minor(device); out: module_put(discipline->owner); return rc; -- cgit v1.2.3-18-g5258 From c4de0c1a18237c2727dde8ad392e333539b0af3c Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Fri, 11 Sep 2009 10:28:56 +0200 Subject: [S390] kvm: use console_initcall() to initialize s390 virtio console Use a console_initcall() to initialize the s390 virtio console and clean up s390 console initialization in setup.c. Signed-off-by: Hendrik Brueckner Tested-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky --- drivers/s390/kvm/kvm_virtio.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index e38e5d306fa..2930fc763ac 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c @@ -403,10 +403,14 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count) return len; } -void __init s390_virtio_console_init(void) +static int __init s390_virtio_console_init(void) { - virtio_cons_early_init(early_put_chars); + if (!MACHINE_IS_KVM) + return -ENODEV; + return virtio_cons_early_init(early_put_chars); } +console_initcall(s390_virtio_console_init); + /* * We do this after core stuff, but before the drivers. -- cgit v1.2.3-18-g5258 From 53f8c573ea3b54b7e1b81d2cd403373b08103736 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 11 Sep 2009 10:29:02 +0200 Subject: [S390] tape: Fix device online messages Currently, when a tape device is set online and no cartridge is loaded, we get the messages "The tape cartridge has been successfully unloaded" and "Determining the size of the recorded area". These messages are not correct. To fix this, we now print the "cartridge loaded/unloaded" messages only, when the load/unload event really occurs. In addition to that, the message "Determining the size of the recorded area" is only printed, if a cartridge is loaded. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- drivers/s390/char/tape_block.c | 4 ++-- drivers/s390/char/tape_core.c | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index 47ff695255e..1c2a582e626 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -302,8 +302,6 @@ tapeblock_revalidate_disk(struct gendisk *disk) if (!device->blk_data.medium_changed) return 0; - dev_info(&device->cdev->dev, "Determining the size of the recorded " - "area...\n"); rc = tape_mtop(device, MTFSFM, 1); if (rc) return rc; @@ -312,6 +310,8 @@ tapeblock_revalidate_disk(struct gendisk *disk) if (rc < 0) return rc; + dev_info(&device->cdev->dev, "Determining the size of the recorded " + "area...\n"); DBF_LH(3, "Image file ends at %d\n", rc); nr_of_blks = rc; diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 7424d648e81..934a42ebe11 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -214,13 +214,15 @@ tape_med_state_set(struct tape_device *device, enum tape_medium_state newstate) switch(newstate){ case MS_UNLOADED: device->tape_generic_status |= GMT_DR_OPEN(~0); - dev_info(&device->cdev->dev, "The tape cartridge has been " - "successfully unloaded\n"); + if (device->medium_state == MS_LOADED) + dev_info(&device->cdev->dev, "The tape cartridge has " + "been successfully unloaded\n"); break; case MS_LOADED: device->tape_generic_status &= ~GMT_DR_OPEN(~0); - dev_info(&device->cdev->dev, "A tape cartridge has been " - "mounted\n"); + if (device->medium_state == MS_UNLOADED) + dev_info(&device->cdev->dev, "A tape cartridge has " + "been mounted\n"); break; default: // print nothing -- cgit v1.2.3-18-g5258 From e86a6ed63f46fe8fb555fda531084bca3ef62fd7 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 11 Sep 2009 10:29:04 +0200 Subject: [S390] Get rid of cpuid.h header file. Merge cpuid.h header file into cpu.h. While at it convert from typedef to struct declaration and also convert cio code to use proper lowcore structure instead of casts. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/zcore.c | 2 +- drivers/s390/cio/css.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 1bbae433fbd..c431198bdbc 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -275,7 +275,7 @@ struct zcore_header { u32 num_pages; u32 pad1; u64 tod; - cpuid_t cpu_id; + struct cpuid cpu_id; u32 arch_id; u32 volnr; u32 build_arch; diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 45858f3b731..e995123fd80 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -657,8 +657,8 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high) css->global_pgid.pgid_high.cpu_addr = 0; #endif } - css->global_pgid.cpu_id = ((cpuid_t *) __LC_CPUID)->ident; - css->global_pgid.cpu_model = ((cpuid_t *) __LC_CPUID)->machine; + css->global_pgid.cpu_id = S390_lowcore.cpu_id.ident; + css->global_pgid.cpu_model = S390_lowcore.cpu_id.machine; css->global_pgid.tod_high = tod_high; } -- cgit v1.2.3-18-g5258 From 59e36927ee08f3bf06d8d14597e57389bf1b41dc Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 11 Sep 2009 10:29:07 +0200 Subject: [S390] tape: Use pr_xxx instead of dev_xxx in shared driver code For messages from the tape core that is shared between the 3590 and 34xx tape disciplines, we want to have the "tape" prefix instead of "tape_3590" or "tape_34xx". In order to fix this, we now use the pr_xxx printk macros. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- drivers/s390/char/tape_34xx.c | 2 +- drivers/s390/char/tape_3590.c | 4 +--- drivers/s390/char/tape_block.c | 12 ++++++------ drivers/s390/char/tape_core.c | 12 ++++++------ 4 files changed, 14 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index 5a519fac37b..2fe45ff77b7 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c @@ -8,7 +8,7 @@ * Martin Schwidefsky */ -#define KMSG_COMPONENT "tape" +#define KMSG_COMPONENT "tape_34xx" #include #include diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 418f72dd39b..e4cc3aae916 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -8,7 +8,7 @@ * Martin Schwidefsky */ -#define KMSG_COMPONENT "tape" +#define KMSG_COMPONENT "tape_3590" #include #include @@ -39,8 +39,6 @@ EXPORT_SYMBOL(TAPE_DBF_AREA); * - Read Alternate: implemented *******************************************************************/ -#define KMSG_COMPONENT "tape" - static const char *tape_3590_msg[TAPE_3590_MAX_MSG] = { [0x00] = "", [0x10] = "Lost Sense", diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index 1c2a582e626..4cb9e70507a 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -310,8 +310,8 @@ tapeblock_revalidate_disk(struct gendisk *disk) if (rc < 0) return rc; - dev_info(&device->cdev->dev, "Determining the size of the recorded " - "area...\n"); + pr_info("%s: Determining the size of the recorded area...\n", + dev_name(&device->cdev->dev)); DBF_LH(3, "Image file ends at %d\n", rc); nr_of_blks = rc; @@ -330,8 +330,8 @@ tapeblock_revalidate_disk(struct gendisk *disk) device->bof = rc; nr_of_blks -= rc; - dev_info(&device->cdev->dev, "The size of the recorded area is %i " - "blocks\n", nr_of_blks); + pr_info("%s: The size of the recorded area is %i blocks\n", + dev_name(&device->cdev->dev), nr_of_blks); set_capacity(device->blk_data.disk, nr_of_blks*(TAPEBLOCK_HSEC_SIZE/512)); @@ -366,8 +366,8 @@ tapeblock_open(struct block_device *bdev, fmode_t mode) if (device->required_tapemarks) { DBF_EVENT(2, "TBLOCK: missing tapemarks\n"); - dev_warn(&device->cdev->dev, "Opening the tape failed because" - " of missing end-of-file marks\n"); + pr_warning("%s: Opening the tape failed because of missing " + "end-of-file marks\n", dev_name(&device->cdev->dev)); rc = -EPERM; goto put_device; } diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 934a42ebe11..5cd31e07164 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -215,14 +215,14 @@ tape_med_state_set(struct tape_device *device, enum tape_medium_state newstate) case MS_UNLOADED: device->tape_generic_status |= GMT_DR_OPEN(~0); if (device->medium_state == MS_LOADED) - dev_info(&device->cdev->dev, "The tape cartridge has " - "been successfully unloaded\n"); + pr_info("%s: The tape cartridge has been successfully " + "unloaded\n", dev_name(&device->cdev->dev)); break; case MS_LOADED: device->tape_generic_status &= ~GMT_DR_OPEN(~0); if (device->medium_state == MS_UNLOADED) - dev_info(&device->cdev->dev, "A tape cartridge has " - "been mounted\n"); + pr_info("%s: A tape cartridge has been mounted\n", + dev_name(&device->cdev->dev)); break; default: // print nothing @@ -656,8 +656,8 @@ tape_generic_remove(struct ccw_device *cdev) */ DBF_EVENT(3, "(%08x): Drive in use vanished!\n", device->cdev_id); - dev_warn(&device->cdev->dev, "A tape unit was detached" - " while in use\n"); + pr_warning("%s: A tape unit was detached while in " + "use\n", dev_name(&device->cdev->dev)); tape_state_set(device, TS_NOT_OPER); __tape_discard_requests(device); spin_unlock_irq(get_ccwdev_lock(device->cdev)); -- cgit v1.2.3-18-g5258 From da6c5c720c52cc717124f8f0830b710ea6a092fd Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 11 Sep 2009 14:26:40 +0200 Subject: scsi,block: update SCSI to handle mixed merge failures Update scsi_io_completion() such that it only fails requests till the next error boundary and retry the leftover. This enables block layer to merge requests with different failfast settings and still behave correctly on errors. Allow merge of requests of different failfast settings. As SCSI is currently the only subsystem which follows failfast status, there's no need to worry about other block drivers for now. Signed-off-by: Tejun Heo Cc: Niel Lambrechts Cc: James Bottomley Signed-off-by: Jens Axboe --- drivers/scsi/scsi_lib.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index f3c40898fc7..90c94da8baa 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -897,8 +897,10 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) if (driver_byte(result) & DRIVER_SENSE) scsi_print_sense("", cmd); } - blk_end_request_all(req, -EIO); - scsi_next_command(cmd); + if (blk_end_request_err(req, -EIO)) + scsi_requeue_command(q, cmd); + else + scsi_next_command(cmd); break; case ACTION_REPREP: /* Unprep the request and put it back at the head of the queue. -- cgit v1.2.3-18-g5258 From 1f98a13f623e0ef666690a18c1250335fc6d7ef1 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 11 Sep 2009 14:32:04 +0200 Subject: bio: first step in sanitizing the bio->bi_rw flag testing Get rid of any functions that test for these bits and make callers use bio_rw_flagged() directly. Then it is at least directly apparent what variable and flag they check. Signed-off-by: Jens Axboe --- drivers/block/loop.c | 2 +- drivers/md/dm-raid1.c | 2 +- drivers/md/dm-stripe.c | 2 +- drivers/md/dm.c | 12 ++++++------ drivers/md/linear.c | 2 +- drivers/md/multipath.c | 4 ++-- drivers/md/raid0.c | 2 +- drivers/md/raid1.c | 14 ++++++++------ drivers/md/raid10.c | 6 +++--- drivers/md/raid5.c | 2 +- drivers/staging/dst/dcore.c | 5 +++-- 11 files changed, 28 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 5757188cd1f..bbb79441d89 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -475,7 +475,7 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio) pos = ((loff_t) bio->bi_sector << 9) + lo->lo_offset; if (bio_rw(bio) == WRITE) { - int barrier = bio_barrier(bio); + bool barrier = bio_rw_flagged(bio, BIO_RW_BARRIER); struct file *file = lo->lo_backing_file; if (barrier) { diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 33f179e66bf..cc9dc79b078 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -1129,7 +1129,7 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, if (error == -EOPNOTSUPP) goto out; - if ((error == -EWOULDBLOCK) && bio_rw_ahead(bio)) + if ((error == -EWOULDBLOCK) && bio_rw_flagged(bio, BIO_RW_AHEAD)) goto out; if (unlikely(error)) { diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index 3e563d25173..fde658ccbce 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c @@ -285,7 +285,7 @@ static int stripe_end_io(struct dm_target *ti, struct bio *bio, if (!error) return 0; /* I/O complete */ - if ((error == -EWOULDBLOCK) && bio_rw_ahead(bio)) + if ((error == -EWOULDBLOCK) && bio_rw_flagged(bio, BIO_RW_AHEAD)) return error; if (error == -EOPNOTSUPP) diff --git a/drivers/md/dm.c b/drivers/md/dm.c index b4845b14740..ec012f03024 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -586,7 +586,7 @@ static void dec_pending(struct dm_io *io, int error) */ spin_lock_irqsave(&md->deferred_lock, flags); if (__noflush_suspending(md)) { - if (!bio_barrier(io->bio)) + if (!bio_rw_flagged(io->bio, BIO_RW_BARRIER)) bio_list_add_head(&md->deferred, io->bio); } else @@ -598,7 +598,7 @@ static void dec_pending(struct dm_io *io, int error) io_error = io->error; bio = io->bio; - if (bio_barrier(bio)) { + if (bio_rw_flagged(bio, BIO_RW_BARRIER)) { /* * There can be just one barrier request so we use * a per-device variable for error reporting. @@ -1209,7 +1209,7 @@ static void __split_and_process_bio(struct mapped_device *md, struct bio *bio) ci.map = dm_get_table(md); if (unlikely(!ci.map)) { - if (!bio_barrier(bio)) + if (!bio_rw_flagged(bio, BIO_RW_BARRIER)) bio_io_error(bio); else if (!md->barrier_error) @@ -1321,7 +1321,7 @@ static int _dm_request(struct request_queue *q, struct bio *bio) * we have to queue this io for later. */ if (unlikely(test_bit(DMF_QUEUE_IO_TO_THREAD, &md->flags)) || - unlikely(bio_barrier(bio))) { + unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER))) { up_read(&md->io_lock); if (unlikely(test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) && @@ -1344,7 +1344,7 @@ static int dm_make_request(struct request_queue *q, struct bio *bio) { struct mapped_device *md = q->queuedata; - if (unlikely(bio_barrier(bio))) { + if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER))) { bio_endio(bio, -EOPNOTSUPP); return 0; } @@ -2164,7 +2164,7 @@ static void dm_wq_work(struct work_struct *work) if (dm_request_based(md)) generic_make_request(c); else { - if (bio_barrier(c)) + if (bio_rw_flagged(c, BIO_RW_BARRIER)) process_barrier(md, c); else __split_and_process_bio(md, c); diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 5fe39c2a3d2..ea484290544 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -288,7 +288,7 @@ static int linear_make_request (struct request_queue *q, struct bio *bio) sector_t start_sector; int cpu; - if (unlikely(bio_barrier(bio))) { + if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER))) { bio_endio(bio, -EOPNOTSUPP); return 0; } diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 7140909f666..89e76819f61 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -90,7 +90,7 @@ static void multipath_end_request(struct bio *bio, int error) if (uptodate) multipath_end_bh_io(mp_bh, 0); - else if (!bio_rw_ahead(bio)) { + else if (!bio_rw_flagged(bio, BIO_RW_AHEAD)) { /* * oops, IO error: */ @@ -144,7 +144,7 @@ static int multipath_make_request (struct request_queue *q, struct bio * bio) const int rw = bio_data_dir(bio); int cpu; - if (unlikely(bio_barrier(bio))) { + if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER))) { bio_endio(bio, -EOPNOTSUPP); return 0; } diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 898e2bdfee4..f845ed98fec 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -448,7 +448,7 @@ static int raid0_make_request(struct request_queue *q, struct bio *bio) const int rw = bio_data_dir(bio); int cpu; - if (unlikely(bio_barrier(bio))) { + if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER))) { bio_endio(bio, -EOPNOTSUPP); return 0; } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 8726fd7ebce..ff7ed333599 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -782,8 +782,9 @@ static int make_request(struct request_queue *q, struct bio * bio) struct bio_list bl; struct page **behind_pages = NULL; const int rw = bio_data_dir(bio); - const int do_sync = bio_sync(bio); - int cpu, do_barriers; + const bool do_sync = bio_rw_flagged(bio, BIO_RW_SYNCIO); + int cpu; + bool do_barriers; mdk_rdev_t *blocked_rdev; /* @@ -797,7 +798,8 @@ static int make_request(struct request_queue *q, struct bio * bio) md_write_start(mddev, bio); /* wait on superblock update early */ - if (unlikely(!mddev->barriers_work && bio_barrier(bio))) { + if (unlikely(!mddev->barriers_work && + bio_rw_flagged(bio, BIO_RW_BARRIER))) { if (rw == WRITE) md_write_end(mddev); bio_endio(bio, -EOPNOTSUPP); @@ -925,7 +927,7 @@ static int make_request(struct request_queue *q, struct bio * bio) atomic_set(&r1_bio->remaining, 0); atomic_set(&r1_bio->behind_remaining, 0); - do_barriers = bio_barrier(bio); + do_barriers = bio_rw_flagged(bio, BIO_RW_BARRIER); if (do_barriers) set_bit(R1BIO_Barrier, &r1_bio->state); @@ -1600,7 +1602,7 @@ static void raid1d(mddev_t *mddev) * We already have a nr_pending reference on these rdevs. */ int i; - const int do_sync = bio_sync(r1_bio->master_bio); + const bool do_sync = bio_rw_flagged(r1_bio->master_bio, BIO_RW_SYNCIO); clear_bit(R1BIO_BarrierRetry, &r1_bio->state); clear_bit(R1BIO_Barrier, &r1_bio->state); for (i=0; i < conf->raid_disks; i++) @@ -1654,7 +1656,7 @@ static void raid1d(mddev_t *mddev) (unsigned long long)r1_bio->sector); raid_end_bio_io(r1_bio); } else { - const int do_sync = bio_sync(r1_bio->master_bio); + const bool do_sync = bio_rw_flagged(r1_bio->master_bio, BIO_RW_SYNCIO); r1_bio->bios[r1_bio->read_disk] = mddev->ro ? IO_BLOCKED : NULL; r1_bio->read_disk = disk; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 3d9020cf6f6..d0a2152e064 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -796,12 +796,12 @@ static int make_request(struct request_queue *q, struct bio * bio) int i; int chunk_sects = conf->chunk_mask + 1; const int rw = bio_data_dir(bio); - const int do_sync = bio_sync(bio); + const bool do_sync = bio_rw_flagged(bio, BIO_RW_SYNCIO); struct bio_list bl; unsigned long flags; mdk_rdev_t *blocked_rdev; - if (unlikely(bio_barrier(bio))) { + if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER))) { bio_endio(bio, -EOPNOTSUPP); return 0; } @@ -1610,7 +1610,7 @@ static void raid10d(mddev_t *mddev) raid_end_bio_io(r10_bio); bio_put(bio); } else { - const int do_sync = bio_sync(r10_bio->master_bio); + const bool do_sync = bio_rw_flagged(r10_bio->master_bio, BIO_RW_SYNCIO); bio_put(bio); rdev = conf->mirrors[mirror].rdev; if (printk_ratelimit()) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index b8a2c5dc67b..826eb346735 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3606,7 +3606,7 @@ static int make_request(struct request_queue *q, struct bio * bi) const int rw = bio_data_dir(bi); int cpu, remaining; - if (unlikely(bio_barrier(bi))) { + if (unlikely(bio_rw_flagged(bi, BIO_RW_BARRIER))) { bio_endio(bi, -EOPNOTSUPP); return 0; } diff --git a/drivers/staging/dst/dcore.c b/drivers/staging/dst/dcore.c index fad25b75304..b1c258ca210 100644 --- a/drivers/staging/dst/dcore.c +++ b/drivers/staging/dst/dcore.c @@ -112,8 +112,9 @@ static int dst_request(struct request_queue *q, struct bio *bio) * I worked with. * * Empty barriers are not allowed anyway, see 51fd77bd9f512 - * for example, although later it was changed to bio_discard() - * only, which does not work in this case. + * for example, although later it was changed to + * bio_rw_flagged(bio, BIO_RW_DISCARD) only, which does not + * work in this case. */ //err = -EOPNOTSUPP; err = 0; -- cgit v1.2.3-18-g5258 From 212a502676c308ead964a024e081529ad3f8d94c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 24 Aug 2009 10:01:53 +0200 Subject: cciss: memory leak in cciss_init_one() commit 22bece00dc1f28dd3374c55e464c9f02eb642876 (cciss: fix regression firmware not displayed in procfs) added a small memory leak in cciss_init_one() Signed-off-by: Eric Dumazet Signed-off-by: Jens Axboe --- drivers/block/cciss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index a52cc7fe45e..0589dfbbd7d 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -3889,7 +3889,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, int j = 0; int rc; int dac, return_code; - InquiryData_struct *inq_buff = NULL; + InquiryData_struct *inq_buff; if (reset_devices) { /* Reset the controller with a PCI power-cycle */ @@ -4029,6 +4029,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, printk(KERN_WARNING "cciss: unable to determine firmware" " version of controller\n"); } + kfree(inq_buff); cciss_procinit(i); @@ -4045,7 +4046,6 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, return 1; clean4: - kfree(inq_buff); kfree(hba[i]->cmd_pool_bits); if (hba[i]->cmd_pool) pci_free_consistent(hba[i]->pdev, -- cgit v1.2.3-18-g5258 From 49b3a3cbc0311f8f809183696b1f2ab824b18a51 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Mon, 24 Aug 2009 10:56:38 +0200 Subject: block: use printk_once Signed-off-by: Marcin Slusarz Cc: Jens Axboe Cc: Tim Waugh Signed-off-by: Jens Axboe --- drivers/block/paride/pcd.c | 12 ++++-------- drivers/block/sx8.c | 4 +--- drivers/block/viodasd.c | 12 +++--------- 3 files changed, 8 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 911dfd98d81..9f3518c515a 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -219,8 +219,6 @@ static int pcd_sector; /* address of next requested sector */ static int pcd_count; /* number of blocks still to do */ static char *pcd_buf; /* buffer for request in progress */ -static int pcd_warned; /* Have we logged a phase warning ? */ - /* kernel glue structures */ static int pcd_block_open(struct block_device *bdev, fmode_t mode) @@ -417,12 +415,10 @@ static int pcd_completion(struct pcd_unit *cd, char *buf, char *fun) printk ("%s: %s: Unexpected phase %d, d=%d, k=%d\n", cd->name, fun, p, d, k); - if ((verbose < 2) && !pcd_warned) { - pcd_warned = 1; - printk - ("%s: WARNING: ATAPI phase errors\n", - cd->name); - } + if (verbose < 2) + printk_once( + "%s: WARNING: ATAPI phase errors\n", + cd->name); mdelay(1); } if (k++ > PCD_TMO) { diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index da403b6a7f4..f5cd2e83ebc 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -1564,15 +1564,13 @@ static int carm_init_shm(struct carm_host *host) static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { - static unsigned int printed_version; struct carm_host *host; unsigned int pci_dac; int rc; struct request_queue *q; unsigned int i; - if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + printk_once(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); rc = pci_enable_device(pdev); if (rc) diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index 390d69bb7c4..b441ce3832e 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -416,15 +416,9 @@ retry: goto retry; } if (we.max_disk > (MAX_DISKNO - 1)) { - static int warned; - - if (warned == 0) { - warned++; - printk(VIOD_KERN_INFO - "Only examining the first %d " - "of %d disks connected\n", - MAX_DISKNO, we.max_disk + 1); - } + printk_once(VIOD_KERN_INFO + "Only examining the first %d of %d disks connected\n", + MAX_DISKNO, we.max_disk + 1); } /* Send the close event to OS/400. We DON'T expect a response */ -- cgit v1.2.3-18-g5258 From ffcfb8db540ff879c2a85bf7e404954281443414 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 Sep 2009 11:35:22 -0700 Subject: Subject: [PATCH] appletalk: Fix skb leak when ipddp interface is not loaded And also do a better job of returning proper NET_{RX,XMIT}_ values. Based on a patch and suggestions by Mark Smith. This fixes CVE-2009-2903 Reported-by: Mark Smith Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- drivers/net/appletalk/ipddp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index bea87da97e3..aaf14d306a4 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -177,8 +177,7 @@ static netdev_tx_t ipddp_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; - if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0) - dev_kfree_skb(skb); + aarp_send_ddp(rt->dev, skb, &rt->at, NULL); spin_unlock(&ipddp_route_lock); -- cgit v1.2.3-18-g5258 From 966a5d1b85c45f1b55abbc1b595e0b5ca14b87db Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 11 Sep 2009 06:21:51 +0000 Subject: drivers/net/wan: introduce missing kfree Error handling code following a kmalloc should free the allocated data. The semantic match that finds the problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; statement S; expression E; identifier f,f1,l; position p1,p2; expression *ptr != NULL; @@ x@p1 = \(kmalloc\|kzalloc\|kcalloc\)(...); ... if (x == NULL) S <... when != x when != if (...) { <+...x...+> } ( x->f1 = E | (x->f1 == NULL || ...) | f(...,x->f1,...) ) ...> ( return \(0\|<+...x...+>\|ptr\); | return@p2 ...; ) @script:python@ p1 << r.p1; p2 << r.p2; @@ print "* file: %s kmalloc %s return %s" % (p1[0].file,p1[0].line,p2[0].line) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/wan/hdlc_ppp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index 72a7cdab424..b9b9d6b01c0 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -389,6 +389,7 @@ static void ppp_cp_parse_cr(struct net_device *dev, u16 pid, u8 id, for (opt = data; len; len -= opt[1], opt += opt[1]) { if (len < 2 || len < opt[1]) { dev->stats.rx_errors++; + kfree(out); return; /* bad packet, drop silently */ } -- cgit v1.2.3-18-g5258 From a4b11649618ef5366ee553f4083449d6bee5d8ec Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 11 Sep 2009 06:22:09 +0000 Subject: drivers/net/phy: introduce missing kfree Error handling code following a kzalloc should free the allocated data. The semantic match that finds the problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; statement S; expression E; identifier f,f1,l; position p1,p2; expression *ptr != NULL; @@ x@p1 = \(kmalloc\|kzalloc\|kcalloc\)(...); ... if (x == NULL) S <... when != x when != if (...) { <+...x...+> } ( x->f1 = E | (x->f1 == NULL || ...) | f(...,x->f1,...) ) ...> ( return \(0\|<+...x...+>\|ptr\); | return@p2 ...; ) @script:python@ p1 << r.p1; p2 << r.p2; @@ print "* file: %s kmalloc %s return %s" % (p1[0].file,p1[0].line,p2[0].line) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/phy/mdio-gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index 22cdd451fb8..250e10f2c35 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -211,7 +211,7 @@ static int __devinit mdio_ofgpio_probe(struct of_device *ofdev, new_bus = mdio_gpio_bus_init(&ofdev->dev, pdata, pdata->mdc); if (!new_bus) - return -ENODEV; + goto out_free; ret = of_mdiobus_register(new_bus, ofdev->node); if (ret) -- cgit v1.2.3-18-g5258 From 8ff44985c761ad6697a3c97e7b14cf5362ff3801 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Wed, 9 Sep 2009 16:01:30 +0000 Subject: phy/marvell: Make non-aneg speed/duplex forcing work for 88E1111 PHYs According to specs, when auto-negotiation is disabled, Marvell PHYs need a software reset after changing speed/duplex forcing bits. Otherwise, the modified bits have no effect. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index dd6f54d1b49..6f69b9ba0df 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -155,8 +155,27 @@ static int marvell_config_aneg(struct phy_device *phydev) return err; err = genphy_config_aneg(phydev); + if (err < 0) + return err; - return err; + if (phydev->autoneg != AUTONEG_ENABLE) { + int bmcr; + + /* + * A write to speed/duplex bits (that is performed by + * genphy_config_aneg() call above) must be followed by + * a software reset. Otherwise, the write has no effect. + */ + bmcr = phy_read(phydev, MII_BMCR); + if (bmcr < 0) + return bmcr; + + err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET); + if (err < 0) + return err; + } + + return 0; } static int m88e1121_config_aneg(struct phy_device *phydev) -- cgit v1.2.3-18-g5258 From 7de8ee787e8e10adaf5635bffab4ee19a7558afb Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Wed, 9 Sep 2009 16:01:40 +0000 Subject: ucc_geth: Rearrange some code to avoid forward declarations We'll need ugeth_disable() and ugeth_enable() calls earlier in the file, so rearrange some code to avoid forward declarations. The patch doesn't contain any functional changes. Signed-off-by: Anton Vorontsov Acked-by: Timur Tabi Signed-off-by: David S. Miller --- drivers/net/ucc_geth.c | 300 ++++++++++++++++++++++++------------------------- 1 file changed, 149 insertions(+), 151 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 3b647d07e41..a39368a4635 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -1412,6 +1412,155 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) return 0; } +static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) +{ + struct ucc_fast_private *uccf; + u32 cecr_subblock; + u32 temp; + int i = 10; + + uccf = ugeth->uccf; + + /* Mask GRACEFUL STOP TX interrupt bit and clear it */ + clrbits32(uccf->p_uccm, UCC_GETH_UCCE_GRA); + out_be32(uccf->p_ucce, UCC_GETH_UCCE_GRA); /* clear by writing 1 */ + + /* Issue host command */ + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); + qe_issue_cmd(QE_GRACEFUL_STOP_TX, cecr_subblock, + QE_CR_PROTOCOL_ETHERNET, 0); + + /* Wait for command to complete */ + do { + msleep(10); + temp = in_be32(uccf->p_ucce); + } while (!(temp & UCC_GETH_UCCE_GRA) && --i); + + uccf->stopped_tx = 1; + + return 0; +} + +static int ugeth_graceful_stop_rx(struct ucc_geth_private *ugeth) +{ + struct ucc_fast_private *uccf; + u32 cecr_subblock; + u8 temp; + int i = 10; + + uccf = ugeth->uccf; + + /* Clear acknowledge bit */ + temp = in_8(&ugeth->p_rx_glbl_pram->rxgstpack); + temp &= ~GRACEFUL_STOP_ACKNOWLEDGE_RX; + out_8(&ugeth->p_rx_glbl_pram->rxgstpack, temp); + + /* Keep issuing command and checking acknowledge bit until + it is asserted, according to spec */ + do { + /* Issue host command */ + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info. + ucc_num); + qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock, + QE_CR_PROTOCOL_ETHERNET, 0); + msleep(10); + temp = in_8(&ugeth->p_rx_glbl_pram->rxgstpack); + } while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX) && --i); + + uccf->stopped_rx = 1; + + return 0; +} + +static int ugeth_restart_tx(struct ucc_geth_private *ugeth) +{ + struct ucc_fast_private *uccf; + u32 cecr_subblock; + + uccf = ugeth->uccf; + + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); + qe_issue_cmd(QE_RESTART_TX, cecr_subblock, QE_CR_PROTOCOL_ETHERNET, 0); + uccf->stopped_tx = 0; + + return 0; +} + +static int ugeth_restart_rx(struct ucc_geth_private *ugeth) +{ + struct ucc_fast_private *uccf; + u32 cecr_subblock; + + uccf = ugeth->uccf; + + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); + qe_issue_cmd(QE_RESTART_RX, cecr_subblock, QE_CR_PROTOCOL_ETHERNET, + 0); + uccf->stopped_rx = 0; + + return 0; +} + +static int ugeth_enable(struct ucc_geth_private *ugeth, enum comm_dir mode) +{ + struct ucc_fast_private *uccf; + int enabled_tx, enabled_rx; + + uccf = ugeth->uccf; + + /* check if the UCC number is in range. */ + if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) { + if (netif_msg_probe(ugeth)) + ugeth_err("%s: ucc_num out of range.", __func__); + return -EINVAL; + } + + enabled_tx = uccf->enabled_tx; + enabled_rx = uccf->enabled_rx; + + /* Get Tx and Rx going again, in case this channel was actively + disabled. */ + if ((mode & COMM_DIR_TX) && (!enabled_tx) && uccf->stopped_tx) + ugeth_restart_tx(ugeth); + if ((mode & COMM_DIR_RX) && (!enabled_rx) && uccf->stopped_rx) + ugeth_restart_rx(ugeth); + + ucc_fast_enable(uccf, mode); /* OK to do even if not disabled */ + + return 0; + +} + +static int ugeth_disable(struct ucc_geth_private *ugeth, enum comm_dir mode) +{ + struct ucc_fast_private *uccf; + + uccf = ugeth->uccf; + + /* check if the UCC number is in range. */ + if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) { + if (netif_msg_probe(ugeth)) + ugeth_err("%s: ucc_num out of range.", __func__); + return -EINVAL; + } + + /* Stop any transmissions */ + if ((mode & COMM_DIR_TX) && uccf->enabled_tx && !uccf->stopped_tx) + ugeth_graceful_stop_tx(ugeth); + + /* Stop any receptions */ + if ((mode & COMM_DIR_RX) && uccf->enabled_rx && !uccf->stopped_rx) + ugeth_graceful_stop_rx(ugeth); + + ucc_fast_disable(ugeth->uccf, mode); /* OK to do even if not enabled */ + + return 0; +} + /* Called every time the controller might need to be made * aware of new link state. The PHY code conveys this * information through variables in the ugeth structure, and this @@ -1587,157 +1736,6 @@ static int init_phy(struct net_device *dev) return 0; } - - -static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) -{ - struct ucc_fast_private *uccf; - u32 cecr_subblock; - u32 temp; - int i = 10; - - uccf = ugeth->uccf; - - /* Mask GRACEFUL STOP TX interrupt bit and clear it */ - clrbits32(uccf->p_uccm, UCC_GETH_UCCE_GRA); - out_be32(uccf->p_ucce, UCC_GETH_UCCE_GRA); /* clear by writing 1 */ - - /* Issue host command */ - cecr_subblock = - ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); - qe_issue_cmd(QE_GRACEFUL_STOP_TX, cecr_subblock, - QE_CR_PROTOCOL_ETHERNET, 0); - - /* Wait for command to complete */ - do { - msleep(10); - temp = in_be32(uccf->p_ucce); - } while (!(temp & UCC_GETH_UCCE_GRA) && --i); - - uccf->stopped_tx = 1; - - return 0; -} - -static int ugeth_graceful_stop_rx(struct ucc_geth_private * ugeth) -{ - struct ucc_fast_private *uccf; - u32 cecr_subblock; - u8 temp; - int i = 10; - - uccf = ugeth->uccf; - - /* Clear acknowledge bit */ - temp = in_8(&ugeth->p_rx_glbl_pram->rxgstpack); - temp &= ~GRACEFUL_STOP_ACKNOWLEDGE_RX; - out_8(&ugeth->p_rx_glbl_pram->rxgstpack, temp); - - /* Keep issuing command and checking acknowledge bit until - it is asserted, according to spec */ - do { - /* Issue host command */ - cecr_subblock = - ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info. - ucc_num); - qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock, - QE_CR_PROTOCOL_ETHERNET, 0); - msleep(10); - temp = in_8(&ugeth->p_rx_glbl_pram->rxgstpack); - } while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX) && --i); - - uccf->stopped_rx = 1; - - return 0; -} - -static int ugeth_restart_tx(struct ucc_geth_private *ugeth) -{ - struct ucc_fast_private *uccf; - u32 cecr_subblock; - - uccf = ugeth->uccf; - - cecr_subblock = - ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); - qe_issue_cmd(QE_RESTART_TX, cecr_subblock, QE_CR_PROTOCOL_ETHERNET, 0); - uccf->stopped_tx = 0; - - return 0; -} - -static int ugeth_restart_rx(struct ucc_geth_private *ugeth) -{ - struct ucc_fast_private *uccf; - u32 cecr_subblock; - - uccf = ugeth->uccf; - - cecr_subblock = - ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); - qe_issue_cmd(QE_RESTART_RX, cecr_subblock, QE_CR_PROTOCOL_ETHERNET, - 0); - uccf->stopped_rx = 0; - - return 0; -} - -static int ugeth_enable(struct ucc_geth_private *ugeth, enum comm_dir mode) -{ - struct ucc_fast_private *uccf; - int enabled_tx, enabled_rx; - - uccf = ugeth->uccf; - - /* check if the UCC number is in range. */ - if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) { - if (netif_msg_probe(ugeth)) - ugeth_err("%s: ucc_num out of range.", __func__); - return -EINVAL; - } - - enabled_tx = uccf->enabled_tx; - enabled_rx = uccf->enabled_rx; - - /* Get Tx and Rx going again, in case this channel was actively - disabled. */ - if ((mode & COMM_DIR_TX) && (!enabled_tx) && uccf->stopped_tx) - ugeth_restart_tx(ugeth); - if ((mode & COMM_DIR_RX) && (!enabled_rx) && uccf->stopped_rx) - ugeth_restart_rx(ugeth); - - ucc_fast_enable(uccf, mode); /* OK to do even if not disabled */ - - return 0; - -} - -static int ugeth_disable(struct ucc_geth_private * ugeth, enum comm_dir mode) -{ - struct ucc_fast_private *uccf; - - uccf = ugeth->uccf; - - /* check if the UCC number is in range. */ - if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) { - if (netif_msg_probe(ugeth)) - ugeth_err("%s: ucc_num out of range.", __func__); - return -EINVAL; - } - - /* Stop any transmissions */ - if ((mode & COMM_DIR_TX) && uccf->enabled_tx && !uccf->stopped_tx) - ugeth_graceful_stop_tx(ugeth); - - /* Stop any receptions */ - if ((mode & COMM_DIR_RX) && uccf->enabled_rx && !uccf->stopped_rx) - ugeth_graceful_stop_rx(ugeth); - - ucc_fast_disable(ugeth->uccf, mode); /* OK to do even if not enabled */ - - return 0; -} - static void ugeth_dump_regs(struct ucc_geth_private *ugeth) { #ifdef DEBUG -- cgit v1.2.3-18-g5258 From 864fdf884e82bacbe8ca5e93bd43393a61d2e2b4 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 10 Sep 2009 11:48:12 +0000 Subject: ucc_geth: Fix hangs after switching from full to half duplex MPC8360 QE UCC ethernet controllers hang when changing link duplex under a load (a bit of NFS activity is enough). PHY: mdio@e0102120:00 - Link is Up - 1000/Full sh-3.00# ethtool -s eth0 speed 100 duplex half autoneg off PHY: mdio@e0102120:00 - Link is Down PHY: mdio@e0102120:00 - Link is Up - 100/Half NETDEV WATCHDOG: eth0 (ucc_geth): transmit queue 0 timed out ------------[ cut here ]------------ Badness at c01fcbd0 [verbose debug info unavailable] NIP: c01fcbd0 LR: c01fcbd0 CTR: c0194e44 ... The cure is to disable the controller before changing speed/duplex and enable it afterwards. Though, disabling the controller might take quite a while, so we better not grab any spinlocks in adjust_link(). Instead, we quiesce the driver's activity, and only then disable the controller. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/ucc_geth.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index a39368a4635..4469f2451a6 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -1561,6 +1561,25 @@ static int ugeth_disable(struct ucc_geth_private *ugeth, enum comm_dir mode) return 0; } +static void ugeth_quiesce(struct ucc_geth_private *ugeth) +{ + /* Wait for and prevent any further xmits. */ + netif_tx_disable(ugeth->ndev); + + /* Disable the interrupt to avoid NAPI rescheduling. */ + disable_irq(ugeth->ug_info->uf_info.irq); + + /* Stop NAPI, and possibly wait for its completion. */ + napi_disable(&ugeth->napi); +} + +static void ugeth_activate(struct ucc_geth_private *ugeth) +{ + napi_enable(&ugeth->napi); + enable_irq(ugeth->ug_info->uf_info.irq); + netif_tx_wake_all_queues(ugeth->ndev); +} + /* Called every time the controller might need to be made * aware of new link state. The PHY code conveys this * information through variables in the ugeth structure, and this @@ -1574,14 +1593,11 @@ static void adjust_link(struct net_device *dev) struct ucc_geth __iomem *ug_regs; struct ucc_fast __iomem *uf_regs; struct phy_device *phydev = ugeth->phydev; - unsigned long flags; int new_state = 0; ug_regs = ugeth->ug_regs; uf_regs = ugeth->uccf->uf_regs; - spin_lock_irqsave(&ugeth->lock, flags); - if (phydev->link) { u32 tempval = in_be32(&ug_regs->maccfg2); u32 upsmr = in_be32(&uf_regs->upsmr); @@ -1632,9 +1648,21 @@ static void adjust_link(struct net_device *dev) ugeth->oldspeed = phydev->speed; } + /* + * To change the MAC configuration we need to disable the + * controller. To do so, we have to either grab ugeth->lock, + * which is a bad idea since 'graceful stop' commands might + * take quite a while, or we can quiesce driver's activity. + */ + ugeth_quiesce(ugeth); + ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); + out_be32(&ug_regs->maccfg2, tempval); out_be32(&uf_regs->upsmr, upsmr); + ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); + ugeth_activate(ugeth); + if (!ugeth->oldlink) { new_state = 1; ugeth->oldlink = 1; @@ -1648,8 +1676,6 @@ static void adjust_link(struct net_device *dev) if (new_state && netif_msg_link(ugeth)) phy_print_status(phydev); - - spin_unlock_irqrestore(&ugeth->lock, flags); } /* Initialize TBI PHY interface for communicating with the -- cgit v1.2.3-18-g5258 From f510c35de0e63e1066db83d2fdce99e6dbde0c80 Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Sun, 6 Sep 2009 23:59:16 +0000 Subject: mv643xx_eth.c: remove unused txq_set_wrr() The txq_set_wrr() function in drivers/net/mv643xx_eth.c is unused, not even referenced under #if 0 or something like that, which results in a compile-time warning: drivers/net/mv643xx_eth.c:1070: warning: 'txq_set_wrr' defined but not used Fix: remove it. Signed-off-by: Mikael Pettersson Signed-off-by: David S. Miller --- drivers/net/mv643xx_eth.c | 34 ---------------------------------- 1 file changed, 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 0f32db3e92a..b62e61d4ca3 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1066,40 +1066,6 @@ static void txq_set_fixed_prio_mode(struct tx_queue *txq) } } -static void txq_set_wrr(struct tx_queue *txq, int weight) -{ - struct mv643xx_eth_private *mp = txq_to_mp(txq); - int off; - u32 val; - - /* - * Turn off fixed priority mode. - */ - off = 0; - switch (mp->shared->tx_bw_control) { - case TX_BW_CONTROL_OLD_LAYOUT: - off = TXQ_FIX_PRIO_CONF; - break; - case TX_BW_CONTROL_NEW_LAYOUT: - off = TXQ_FIX_PRIO_CONF_MOVED; - break; - } - - if (off) { - val = rdlp(mp, off); - val &= ~(1 << txq->index); - wrlp(mp, off, val); - - /* - * Configure WRR weight for this queue. - */ - - val = rdlp(mp, off); - val = (val & ~0xff) | (weight & 0xff); - wrlp(mp, TXQ_BW_WRR_CONF(txq->index), val); - } -} - /* mii management interface *************************************************/ static irqreturn_t mv643xx_eth_err_irq(int irq, void *dev_id) -- cgit v1.2.3-18-g5258 From 384912ed194e43c03ad1cdaa09b0b1e488c34d46 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 31 Aug 2009 21:08:19 +0000 Subject: net: Add DEVTYPE support for Ethernet based devices The Ethernet framing is used for a lot of devices these days. Most prominent are WiFi and WiMAX based devices. However for userspace application it is important to classify these devices correctly and not only see them as Ethernet devices. The daemons like HAL, DeviceKit or even NetworkManager with udev support tries to do the classification in userspace with a lot trickery and extra system calls. This is not good and actually reaches its limitations. Especially since the kernel does know the type of the Ethernet device it is pretty stupid. To solve this problem the underlying device type needs to be set and then the value will be exported as DEVTYPE via uevents and available within udev. # cat /sys/class/net/wlan0/uevent DEVTYPE=wlan INTERFACE=wlan0 IFINDEX=5 This is similar to subsystems like USB and SCSI that distinguish between hosts, devices, disks, partitions etc. The new SET_NETDEV_DEVTYPE() is a convenience helper to set the actual device type. All device types are free form, but for convenience the same strings as used with RFKILL are choosen. Signed-off-by: Marcel Holtmann Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 5 +++++ drivers/net/wimax/i2400m/sdio.c | 5 +++++ drivers/net/wimax/i2400m/usb.c | 5 +++++ 3 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 3f9c92a2afc..fa4e58196c2 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -2535,6 +2535,10 @@ static void hso_create_rfkill(struct hso_device *hso_dev, } } +static struct device_type hso_type = { + .name = "wwan", +}; + /* Creates our network device */ static struct hso_device *hso_create_net_device(struct usb_interface *interface, int port_spec) @@ -2575,6 +2579,7 @@ static struct hso_device *hso_create_net_device(struct usb_interface *interface, goto exit; } SET_NETDEV_DEV(net, &interface->dev); + SET_NETDEV_DEVTYPE(net, &hso_type); /* registering our net device */ result = register_netdev(net); diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index ea7b29034aa..2981e211e04 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c @@ -371,6 +371,10 @@ error: } +static struct device_type i2400ms_type = { + .name = "wimax", +}; + /* * Probe a i2400m interface and register it * @@ -412,6 +416,7 @@ int i2400ms_probe(struct sdio_func *func, goto error_alloc_netdev; } SET_NETDEV_DEV(net_dev, dev); + SET_NETDEV_DEVTYPE(net_dev, &i2400ms_type); i2400m = net_dev_to_i2400m(net_dev); i2400ms = container_of(i2400m, struct i2400ms, i2400m); i2400m->wimax_dev.net_dev = net_dev; diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index cfdaf69da9d..7eadd11c815 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c @@ -351,6 +351,10 @@ error: } +static struct device_type i2400mu_type = { + .name = "wimax", +}; + /* * Probe a i2400m interface and register it * @@ -388,6 +392,7 @@ int i2400mu_probe(struct usb_interface *iface, goto error_alloc_netdev; } SET_NETDEV_DEV(net_dev, dev); + SET_NETDEV_DEVTYPE(net_dev, &i2400mu_type); i2400m = net_dev_to_i2400m(net_dev); i2400mu = container_of(i2400m, struct i2400mu, i2400m); i2400m->wimax_dev.net_dev = net_dev; -- cgit v1.2.3-18-g5258 From 02571f89871e009b66fb5f8d5ae222e90e9f357c Mon Sep 17 00:00:00 2001 From: Rémi Denis-Courmont Date: Wed, 9 Sep 2009 00:00:06 +0000 Subject: cdc-phonet: autoconfigure Phonet address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- drivers/net/usb/cdc-phonet.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c index 0ca5916ca8d..97e54d9d03c 100644 --- a/drivers/net/usb/cdc-phonet.c +++ b/drivers/net/usb/cdc-phonet.c @@ -27,6 +27,7 @@ #include #include #include +#include #define PN_MEDIA_USB 0x1B @@ -256,6 +257,19 @@ static int usbpn_close(struct net_device *dev) return usb_set_interface(pnd->usb, num, !pnd->active_setting); } +static int usbpn_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct if_phonet_req *req = (struct if_phonet_req *)ifr; + + switch (cmd) { + case SIOCPNGAUTOCONF: + req->ifr_phonet_autoconf.device = PN_DEV_PC; + printk(KERN_CRIT"device is PN_DEV_PC\n"); + return 0; + } + return -ENOIOCTLCMD; +} + static int usbpn_set_mtu(struct net_device *dev, int new_mtu) { if ((new_mtu < PHONET_MIN_MTU) || (new_mtu > PHONET_MAX_MTU)) @@ -269,6 +283,7 @@ static const struct net_device_ops usbpn_ops = { .ndo_open = usbpn_open, .ndo_stop = usbpn_close, .ndo_start_xmit = usbpn_xmit, + .ndo_do_ioctl = usbpn_ioctl, .ndo_change_mtu = usbpn_set_mtu, }; -- cgit v1.2.3-18-g5258 From 9feae56c0de65fdd8b1f64f376bb6578417d2b79 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 11 Sep 2009 12:41:04 +0000 Subject: netxen: build fix for INET=n When CONFIG_INET is disabled, netxen has a build failure: netxen_nic_main.c:(.text+0x118fd1): undefined reference to `netxen_config_indev_addr' so make that function just an empty stub when CONFIG_INET=n. (not "inline" since that conflicts with other declarations of it) Signed-off-by: Randy Dunlap Acked-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_main.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 81c24a7effc..1399102fa4b 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -2450,6 +2450,10 @@ static struct notifier_block netxen_netdev_cb = { static struct notifier_block netxen_inetaddr_cb = { .notifier_call = netxen_inetaddr_event, }; +#else +static void +netxen_config_indev_addr(struct net_device *dev, unsigned long event) +{ } #endif static struct pci_driver netxen_driver = { -- cgit v1.2.3-18-g5258 From 5ea1c50662d447de344812054175d7151783ea25 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Fri, 11 Sep 2009 16:50:16 -0700 Subject: tg3: Fix return ring size breakage Commit f6eb9b1fc1411d22c073f5264e5630a541d0f7df, "tg3: Add 5717 asic rev" changed how the rx return ring size operations are done. It effectively inverts the sense of the previous test, but it failed to also invert the resulting sizes. This patch corrects that error. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7cf80006eaf..f09bc5dfe8b 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -112,7 +112,7 @@ */ #define TG3_RX_RCB_RING_SIZE(tp) \ (((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) && \ - !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) ? 512 : 1024) + !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) ? 1024 : 512) #define TG3_TX_RING_SIZE 512 #define TG3_DEF_TX_RING_PENDING (TG3_TX_RING_SIZE - 1) -- cgit v1.2.3-18-g5258 From f78c0850d2ebe7a44a4b0263480a2f1a36a92218 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Fri, 11 Sep 2009 11:28:11 +0000 Subject: netxen: change firmware write size Use 8 byte strides for firmware download into card memory since oncard memory controller needs 8 byte (64 bit) accesses. This avoids unnecessary rmw cycles. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_init.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 485b947932a..8926b0e0c8b 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -727,21 +727,28 @@ netxen_load_firmware(struct netxen_adapter *adapter) flashaddr += 8; } } else { - u32 data; + u64 data; + u32 hi, lo; - size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 4; + size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 8; flashaddr = NETXEN_BOOTLD_START; for (i = 0; i < size; i++) { if (netxen_rom_fast_read(adapter, - flashaddr, (int *)&data) != 0) + flashaddr, &lo) != 0) + return -EIO; + if (netxen_rom_fast_read(adapter, + flashaddr + 4, &hi) != 0) return -EIO; + /* hi, lo are already in host endian byteorder */ + data = (((u64)hi << 32) | lo); + if (adapter->pci_mem_write(adapter, - flashaddr, &data, 4)) + flashaddr, &data, 8)) return -EIO; - flashaddr += 4; + flashaddr += 8; } } msleep(1); -- cgit v1.2.3-18-g5258 From ea6828b8aa3a8ebae8d7740f32f212ba1d2f0742 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Fri, 11 Sep 2009 11:28:12 +0000 Subject: netxen: improve pci memory access o Access on card memory through memory controller (agent) rather than moving small pci window around. Clean up the code for moving windows around. o Restrict memory accesss to 64 bit, currently only firmware download uses this. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 4 +- drivers/net/netxen/netxen_nic_hw.c | 348 +++++++++-------------------------- drivers/net/netxen/netxen_nic_main.c | 7 +- 3 files changed, 93 insertions(+), 266 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 23718887d02..7e3d2b93279 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -552,8 +552,8 @@ struct netxen_hardware_context { int qdr_sn_window; int ddr_mn_window; - unsigned long mn_win_crb; - unsigned long ms_win_crb; + u32 mn_win_crb; + u32 ms_win_crb; u8 cut_through; u8 revision_id; diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 555bc4a7e88..018cf429c30 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -1279,25 +1279,6 @@ netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter, ulong off) return data; } -/* - * check memory access boundary. - * used by test agent. support ddr access only for now - */ -static unsigned long -netxen_nic_pci_mem_bound_check(struct netxen_adapter *adapter, - unsigned long long addr, int size) -{ - if (!ADDR_IN_RANGE(addr, - NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX) || - !ADDR_IN_RANGE(addr+size-1, - NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX) || - ((size != 1) && (size != 2) && (size != 4) && (size != 8))) { - return 0; - } - - return 1; -} - static int netxen_pci_set_window_warning_count; static unsigned long @@ -1424,10 +1405,8 @@ netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, /* DDR network side */ window = MN_WIN(addr); adapter->ahw.ddr_mn_window = window; - NXWR32(adapter, adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE, - window); - win_read = NXRD32(adapter, - adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE); + NXWR32(adapter, adapter->ahw.mn_win_crb, window); + win_read = NXRD32(adapter, adapter->ahw.mn_win_crb); if ((win_read << 17) != window) { printk(KERN_INFO "Written MNwin (0x%x) != " "Read MNwin (0x%x)\n", window, win_read); @@ -1442,10 +1421,8 @@ netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, window = OCM_WIN(addr); adapter->ahw.ddr_mn_window = window; - NXWR32(adapter, adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE, - window); - win_read = NXRD32(adapter, - adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE); + NXWR32(adapter, adapter->ahw.mn_win_crb, window); + win_read = NXRD32(adapter, adapter->ahw.mn_win_crb); if ((win_read >> 7) != window) { printk(KERN_INFO "%s: Written OCMwin (0x%x) != " "Read OCMwin (0x%x)\n", @@ -1458,10 +1435,8 @@ netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, /* QDR network side */ window = MS_WIN(addr); adapter->ahw.qdr_sn_window = window; - NXWR32(adapter, adapter->ahw.ms_win_crb | NETXEN_PCI_CRBSPACE, - window); - win_read = NXRD32(adapter, - adapter->ahw.ms_win_crb | NETXEN_PCI_CRBSPACE); + NXWR32(adapter, adapter->ahw.ms_win_crb, window); + win_read = NXRD32(adapter, adapter->ahw.ms_win_crb); if (win_read != window) { printk(KERN_INFO "%s: Written MSwin (0x%x) != " "Read MSwin (0x%x)\n", @@ -1484,177 +1459,6 @@ netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, return addr; } -static int netxen_nic_pci_is_same_window(struct netxen_adapter *adapter, - unsigned long long addr) -{ - int window; - unsigned long long qdr_max; - - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) - qdr_max = NETXEN_ADDR_QDR_NET_MAX_P2; - else - qdr_max = NETXEN_ADDR_QDR_NET_MAX_P3; - - if (ADDR_IN_RANGE(addr, - NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) { - /* DDR network side */ - BUG(); /* MN access can not come here */ - } else if (ADDR_IN_RANGE(addr, - NETXEN_ADDR_OCM0, NETXEN_ADDR_OCM0_MAX)) { - return 1; - } else if (ADDR_IN_RANGE(addr, - NETXEN_ADDR_OCM1, NETXEN_ADDR_OCM1_MAX)) { - return 1; - } else if (ADDR_IN_RANGE(addr, NETXEN_ADDR_QDR_NET, qdr_max)) { - /* QDR network side */ - window = ((addr - NETXEN_ADDR_QDR_NET) >> 22) & 0x3f; - if (adapter->ahw.qdr_sn_window == window) - return 1; - } - - return 0; -} - -static int netxen_nic_pci_mem_read_direct(struct netxen_adapter *adapter, - u64 off, void *data, int size) -{ - unsigned long flags; - void __iomem *addr, *mem_ptr = NULL; - int ret = 0; - u64 start; - unsigned long mem_base; - unsigned long mem_page; - - write_lock_irqsave(&adapter->adapter_lock, flags); - - /* - * If attempting to access unknown address or straddle hw windows, - * do not access. - */ - start = adapter->pci_set_window(adapter, off); - if ((start == -1UL) || - (netxen_nic_pci_is_same_window(adapter, off+size-1) == 0)) { - write_unlock_irqrestore(&adapter->adapter_lock, flags); - printk(KERN_ERR "%s out of bound pci memory access. " - "offset is 0x%llx\n", netxen_nic_driver_name, - (unsigned long long)off); - return -1; - } - - addr = pci_base_offset(adapter, start); - if (!addr) { - write_unlock_irqrestore(&adapter->adapter_lock, flags); - mem_base = pci_resource_start(adapter->pdev, 0); - mem_page = start & PAGE_MASK; - /* Map two pages whenever user tries to access addresses in two - consecutive pages. - */ - if (mem_page != ((start + size - 1) & PAGE_MASK)) - mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2); - else - mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); - if (mem_ptr == NULL) { - *(uint8_t *)data = 0; - return -1; - } - addr = mem_ptr; - addr += start & (PAGE_SIZE - 1); - write_lock_irqsave(&adapter->adapter_lock, flags); - } - - switch (size) { - case 1: - *(uint8_t *)data = readb(addr); - break; - case 2: - *(uint16_t *)data = readw(addr); - break; - case 4: - *(uint32_t *)data = readl(addr); - break; - case 8: - *(uint64_t *)data = readq(addr); - break; - default: - ret = -1; - break; - } - write_unlock_irqrestore(&adapter->adapter_lock, flags); - - if (mem_ptr) - iounmap(mem_ptr); - return ret; -} - -static int -netxen_nic_pci_mem_write_direct(struct netxen_adapter *adapter, u64 off, - void *data, int size) -{ - unsigned long flags; - void __iomem *addr, *mem_ptr = NULL; - int ret = 0; - u64 start; - unsigned long mem_base; - unsigned long mem_page; - - write_lock_irqsave(&adapter->adapter_lock, flags); - - /* - * If attempting to access unknown address or straddle hw windows, - * do not access. - */ - start = adapter->pci_set_window(adapter, off); - if ((start == -1UL) || - (netxen_nic_pci_is_same_window(adapter, off+size-1) == 0)) { - write_unlock_irqrestore(&adapter->adapter_lock, flags); - printk(KERN_ERR "%s out of bound pci memory access. " - "offset is 0x%llx\n", netxen_nic_driver_name, - (unsigned long long)off); - return -1; - } - - addr = pci_base_offset(adapter, start); - if (!addr) { - write_unlock_irqrestore(&adapter->adapter_lock, flags); - mem_base = pci_resource_start(adapter->pdev, 0); - mem_page = start & PAGE_MASK; - /* Map two pages whenever user tries to access addresses in two - * consecutive pages. - */ - if (mem_page != ((start + size - 1) & PAGE_MASK)) - mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE*2); - else - mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); - if (mem_ptr == NULL) - return -1; - addr = mem_ptr; - addr += start & (PAGE_SIZE - 1); - write_lock_irqsave(&adapter->adapter_lock, flags); - } - - switch (size) { - case 1: - writeb(*(uint8_t *)data, addr); - break; - case 2: - writew(*(uint16_t *)data, addr); - break; - case 4: - writel(*(uint32_t *)data, addr); - break; - case 8: - writeq(*(uint64_t *)data, addr); - break; - default: - ret = -1; - break; - } - write_unlock_irqrestore(&adapter->adapter_lock, flags); - if (mem_ptr) - iounmap(mem_ptr); - return ret; -} - #define MAX_CTL_CHECK 1000 static int @@ -1667,19 +1471,28 @@ netxen_nic_pci_mem_write_128M(struct netxen_adapter *adapter, uint64_t off8, tmpw, word[2] = {0, 0}; void __iomem *mem_crb; - /* - * If not MN, go check for MS or invalid. - */ - if (netxen_nic_pci_mem_bound_check(adapter, off, size) == 0) - return netxen_nic_pci_mem_write_direct(adapter, - off, data, size); + if (size != 8) + return -EIO; + + if (ADDR_IN_RANGE(off, NETXEN_ADDR_QDR_NET, + NETXEN_ADDR_QDR_NET_MAX_P2)) { + mem_crb = pci_base_offset(adapter, NETXEN_CRB_QDR_NET); + goto correct; + } + + if (ADDR_IN_RANGE(off, NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) { + mem_crb = pci_base_offset(adapter, NETXEN_CRB_DDR_NET); + goto correct; + } + + return -EIO; +correct: off8 = off & 0xfffffff8; off0 = off & 0x7; sz[0] = (size < (8 - off0)) ? size : (8 - off0); sz[1] = size - sz[0]; loop = ((off0 + size - 1) >> 3) + 1; - mem_crb = pci_base_offset(adapter, NETXEN_CRB_DDR_NET); if ((size != 8) || (off0 != 0)) { for (i = 0; i < loop; i++) { @@ -1760,20 +1573,29 @@ netxen_nic_pci_mem_read_128M(struct netxen_adapter *adapter, uint64_t off8, val, word[2] = {0, 0}; void __iomem *mem_crb; + if (size != 8) + return -EIO; - /* - * If not MN, go check for MS or invalid. - */ - if (netxen_nic_pci_mem_bound_check(adapter, off, size) == 0) - return netxen_nic_pci_mem_read_direct(adapter, off, data, size); + if (ADDR_IN_RANGE(off, NETXEN_ADDR_QDR_NET, + NETXEN_ADDR_QDR_NET_MAX_P2)) { + mem_crb = pci_base_offset(adapter, NETXEN_CRB_QDR_NET); + goto correct; + } + if (ADDR_IN_RANGE(off, NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) { + mem_crb = pci_base_offset(adapter, NETXEN_CRB_DDR_NET); + goto correct; + } + + return -EIO; + +correct: off8 = off & 0xfffffff8; off0[0] = off & 0x7; off0[1] = 0; sz[0] = (size < (8 - off0[0])) ? size : (8 - off0[0]); sz[1] = size - sz[0]; loop = ((off0[0] + size - 1) >> 3) + 1; - mem_crb = pci_base_offset(adapter, NETXEN_CRB_DDR_NET); write_lock_irqsave(&adapter->adapter_lock, flags); netxen_nic_pci_change_crbwindow_128M(adapter, 0); @@ -1847,20 +1669,26 @@ netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter, { int i, j, ret = 0, loop, sz[2], off0; uint32_t temp; - uint64_t off8, mem_crb, tmpw, word[2] = {0, 0}; + uint64_t off8, tmpw, word[2] = {0, 0}; + void __iomem *mem_crb; - /* - * If not MN, go check for MS or invalid. - */ - if (off >= NETXEN_ADDR_QDR_NET && off <= NETXEN_ADDR_QDR_NET_MAX_P3) - mem_crb = NETXEN_CRB_QDR_NET; - else { - mem_crb = NETXEN_CRB_DDR_NET; - if (netxen_nic_pci_mem_bound_check(adapter, off, size) == 0) - return netxen_nic_pci_mem_write_direct(adapter, - off, data, size); + if (size != 8) + return -EIO; + + if (ADDR_IN_RANGE(off, NETXEN_ADDR_QDR_NET, + NETXEN_ADDR_QDR_NET_MAX_P3)) { + mem_crb = netxen_get_ioaddr(adapter, NETXEN_CRB_QDR_NET); + goto correct; } + if (ADDR_IN_RANGE(off, NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) { + mem_crb = netxen_get_ioaddr(adapter, NETXEN_CRB_DDR_NET); + goto correct; + } + + return -EIO; + +correct: off8 = off & 0xfffffff8; off0 = off & 0x7; sz[0] = (size < (8 - off0)) ? size : (8 - off0); @@ -1906,21 +1734,18 @@ netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter, */ for (i = 0; i < loop; i++) { - temp = off8 + (i << 3); - NXWR32(adapter, mem_crb+MIU_TEST_AGT_ADDR_LO, temp); - temp = 0; - NXWR32(adapter, mem_crb+MIU_TEST_AGT_ADDR_HI, temp); - temp = word[i] & 0xffffffff; - NXWR32(adapter, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp); - temp = (word[i] >> 32) & 0xffffffff; - NXWR32(adapter, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp); - temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; - NXWR32(adapter, mem_crb+MIU_TEST_AGT_CTRL, temp); - temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; - NXWR32(adapter, mem_crb+MIU_TEST_AGT_CTRL, temp); + writel(off8 + (i << 3), mem_crb+MIU_TEST_AGT_ADDR_LO); + writel(0, mem_crb+MIU_TEST_AGT_ADDR_HI); + writel(word[i] & 0xffffffff, mem_crb+MIU_TEST_AGT_WRDATA_LO); + writel((word[i] >> 32) & 0xffffffff, + mem_crb+MIU_TEST_AGT_WRDATA_HI); + writel((MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE), + mem_crb+MIU_TEST_AGT_CTRL); + writel(MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE, + mem_crb+MIU_TEST_AGT_CTRL); for (j = 0; j < MAX_CTL_CHECK; j++) { - temp = NXRD32(adapter, mem_crb + MIU_TEST_AGT_CTRL); + temp = readl(mem_crb + MIU_TEST_AGT_CTRL); if ((temp & MIU_TA_CTL_BUSY) == 0) break; } @@ -1947,21 +1772,26 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, { int i, j = 0, k, start, end, loop, sz[2], off0[2]; uint32_t temp; - uint64_t off8, val, mem_crb, word[2] = {0, 0}; + uint64_t off8, val, word[2] = {0, 0}; + void __iomem *mem_crb; - /* - * If not MN, go check for MS or invalid. - */ + if (size != 8) + return -EIO; + + if (ADDR_IN_RANGE(off, NETXEN_ADDR_QDR_NET, + NETXEN_ADDR_QDR_NET_MAX_P3)) { + mem_crb = netxen_get_ioaddr(adapter, NETXEN_CRB_QDR_NET); + goto correct; + } - if (off >= NETXEN_ADDR_QDR_NET && off <= NETXEN_ADDR_QDR_NET_MAX_P3) - mem_crb = NETXEN_CRB_QDR_NET; - else { - mem_crb = NETXEN_CRB_DDR_NET; - if (netxen_nic_pci_mem_bound_check(adapter, off, size) == 0) - return netxen_nic_pci_mem_read_direct(adapter, - off, data, size); + if (ADDR_IN_RANGE(off, NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) { + mem_crb = netxen_get_ioaddr(adapter, NETXEN_CRB_DDR_NET); + goto correct; } + return -EIO; + +correct: off8 = off & 0xfffffff8; off0[0] = off & 0x7; off0[1] = 0; @@ -1976,17 +1806,14 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, */ for (i = 0; i < loop; i++) { - temp = off8 + (i << 3); - NXWR32(adapter, mem_crb + MIU_TEST_AGT_ADDR_LO, temp); - temp = 0; - NXWR32(adapter, mem_crb + MIU_TEST_AGT_ADDR_HI, temp); - temp = MIU_TA_CTL_ENABLE; - NXWR32(adapter, mem_crb + MIU_TEST_AGT_CTRL, temp); - temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE; - NXWR32(adapter, mem_crb + MIU_TEST_AGT_CTRL, temp); + writel(off8 + (i << 3), mem_crb + MIU_TEST_AGT_ADDR_LO); + writel(0, mem_crb + MIU_TEST_AGT_ADDR_HI); + writel(MIU_TA_CTL_ENABLE, mem_crb + MIU_TEST_AGT_CTRL); + writel(MIU_TA_CTL_START | MIU_TA_CTL_ENABLE, + mem_crb + MIU_TEST_AGT_CTRL); for (j = 0; j < MAX_CTL_CHECK; j++) { - temp = NXRD32(adapter, mem_crb + MIU_TEST_AGT_CTRL); + temp = readl(mem_crb + MIU_TEST_AGT_CTRL); if ((temp & MIU_TA_CTL_BUSY) == 0) break; } @@ -2001,8 +1828,7 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, start = off0[i] >> 2; end = (off0[i] + sz[i] - 1) >> 2; for (k = start; k <= end; k++) { - temp = NXRD32(adapter, - mem_crb + MIU_TEST_AGT_RDDATA(k)); + temp = readl(mem_crb + MIU_TEST_AGT_RDDATA(k)); word[i] |= ((uint64_t)temp << (32 * k)); } } diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 1399102fa4b..557e76c4c58 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -643,9 +643,10 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) adapter->ahw.ddr_mn_window = 0; adapter->ahw.qdr_sn_window = 0; - adapter->ahw.mn_win_crb = 0x100000 + PCIX_MN_WINDOW + - (pci_func * 0x20); - adapter->ahw.ms_win_crb = 0x100000 + PCIX_SN_WINDOW; + adapter->ahw.mn_win_crb = NETXEN_PCI_CRBSPACE + + 0x100000 + PCIX_MN_WINDOW + (pci_func * 0x20); + adapter->ahw.ms_win_crb = NETXEN_PCI_CRBSPACE + + 0x100000 + PCIX_SN_WINDOW; if (pci_func < 4) adapter->ahw.ms_win_crb += (pci_func * 0x20); else -- cgit v1.2.3-18-g5258 From ec5c50cb93c446a4686863df74e4b7a547628115 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Fri, 11 Sep 2009 11:28:13 +0000 Subject: netxen: fix file firmware leak Release file firmware when no firmware reset is required. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 557e76c4c58..e8574eeae58 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -817,7 +817,7 @@ netxen_start_firmware(struct netxen_adapter *adapter) if (err < 0) goto err_out; if (err == 0) - goto wait_init; + goto ready; if (first_boot != 0x55555555) { NXWR32(adapter, CRB_CMDPEG_STATE, 0); @@ -860,6 +860,7 @@ netxen_start_firmware(struct netxen_adapter *adapter) | (_NETXEN_NIC_LINUX_SUBVERSION); NXWR32(adapter, CRB_DRIVER_VERSION, val); +ready: NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_READY); wait_init: @@ -874,7 +875,7 @@ wait_init: netxen_check_options(adapter); - return 0; + /* fall through and release firmware */ err_out: netxen_release_firmware(adapter); -- cgit v1.2.3-18-g5258 From 74c520da5414d15b0ab2839d67efab2e7227be75 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Fri, 11 Sep 2009 11:28:14 +0000 Subject: netxen: fix tx timeout recovery Redesign tx timeout handling in line with new firmware reset design that co-ordinates with other PCI function drivers. o For NX3031, first try to reset PCI function's own context before requesting firmware reset. o For NX2031, since firmware heartbit is not supported directly request firmware reset. Signed-off-by: Amit Kumar Salecha Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 4 ++- drivers/net/netxen/netxen_nic_init.c | 4 ++- drivers/net/netxen/netxen_nic_main.c | 69 ++++++++++++++++++++++++++++++------ 3 files changed, 64 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 7e3d2b93279..1ae46e8c2dc 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -178,6 +178,7 @@ #define MAX_BUFFERS_PER_CMD 32 #define TX_STOP_THRESH ((MAX_SKB_FRAGS >> 2) + 4) +#define NX_MAX_TX_TIMEOUTS 2 /* * Following are the states of the Phantom. Phantom will set them and @@ -1145,7 +1146,8 @@ struct netxen_adapter { u8 link_changed; u8 fw_wait_cnt; u8 fw_fail_cnt; - u16 resv4; + u8 tx_timeo_cnt; + u8 need_fw_reset; u8 has_link_events; u8 fw_type; diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 8926b0e0c8b..128d1b65402 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1434,8 +1434,10 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter) if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) { __netif_tx_lock(tx_ring->txq, smp_processor_id()); - if (netxen_tx_avail(tx_ring) > TX_STOP_THRESH) + if (netxen_tx_avail(tx_ring) > TX_STOP_THRESH) { netif_wake_queue(netdev); + adapter->tx_timeo_cnt = 0; + } __netif_tx_unlock(tx_ring->txq); } } diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index e8574eeae58..53bd44e808e 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -66,7 +66,7 @@ static int netxen_nic_close(struct net_device *netdev); static netdev_tx_t netxen_nic_xmit_frame(struct sk_buff *, struct net_device *); static void netxen_tx_timeout(struct net_device *netdev); -static void netxen_reset_task(struct work_struct *work); +static void netxen_tx_timeout_task(struct work_struct *work); static void netxen_fw_poll_work(struct work_struct *work); static void netxen_schedule_work(struct netxen_adapter *adapter, work_func_t func, int delay); @@ -875,6 +875,8 @@ wait_init: netxen_check_options(adapter); + adapter->need_fw_reset = 0; + /* fall through and release firmware */ err_out: @@ -1183,7 +1185,7 @@ netxen_setup_netdev(struct netxen_adapter *adapter, netdev->irq = adapter->msix_entries[0].vector; - INIT_WORK(&adapter->tx_timeout_task, netxen_reset_task); + INIT_WORK(&adapter->tx_timeout_task, netxen_tx_timeout_task); if (netxen_read_mac_addr(adapter)) dev_warn(&pdev->dev, "failed to read mac addr\n"); @@ -1882,7 +1884,7 @@ static void netxen_tx_timeout(struct net_device *netdev) schedule_work(&adapter->tx_timeout_task); } -static void netxen_reset_task(struct work_struct *work) +static void netxen_tx_timeout_task(struct work_struct *work) { struct netxen_adapter *adapter = container_of(work, struct netxen_adapter, tx_timeout_task); @@ -1890,15 +1892,37 @@ static void netxen_reset_task(struct work_struct *work) if (!netif_running(adapter->netdev)) return; - if (test_bit(__NX_RESETTING, &adapter->state)) + if (test_and_set_bit(__NX_RESETTING, &adapter->state)) return; - netxen_napi_disable(adapter); + if (++adapter->tx_timeo_cnt >= NX_MAX_TX_TIMEOUTS) + goto request_reset; + + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + /* try to scrub interrupt */ + netxen_napi_disable(adapter); - adapter->netdev->trans_start = jiffies; + adapter->netdev->trans_start = jiffies; - netxen_napi_enable(adapter); - netif_wake_queue(adapter->netdev); + netxen_napi_enable(adapter); + + netif_wake_queue(adapter->netdev); + + goto done; + + } else { + if (!netxen_nic_reset_context(adapter)) { + adapter->netdev->trans_start = jiffies; + goto done; + } + + /* context reset failed, fall through for fw reset */ + } + +request_reset: + adapter->need_fw_reset = 1; +done: + clear_bit(__NX_RESETTING, &adapter->state); } struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev) @@ -2048,6 +2072,22 @@ nx_decr_dev_ref_cnt(struct netxen_adapter *adapter) return count; } +static void +nx_dev_request_reset(struct netxen_adapter *adapter) +{ + u32 state; + + if (netxen_api_lock(adapter)) + return; + + state = NXRD32(adapter, NX_CRB_DEV_STATE); + + if (state != NX_DEV_INITALIZING) + NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_NEED_RESET); + + netxen_api_unlock(adapter); +} + static int netxen_can_start_firmware(struct netxen_adapter *adapter) { @@ -2133,9 +2173,11 @@ netxen_fwinit_work(struct work_struct *work) switch (dev_state) { case NX_DEV_COLD: case NX_DEV_READY: - netxen_start_firmware(adapter); - netxen_schedule_work(adapter, netxen_attach_work, 0); - return; + if (!netxen_start_firmware(adapter)) { + netxen_schedule_work(adapter, netxen_attach_work, 0); + return; + } + break; case NX_DEV_INITALIZING: if (++adapter->fw_wait_cnt < FW_POLL_THRESH) { @@ -2195,6 +2237,11 @@ netxen_check_health(struct netxen_adapter *adapter) if (netxen_nic_check_temp(adapter)) goto detach; + if (adapter->need_fw_reset) { + nx_dev_request_reset(adapter); + goto detach; + } + state = NXRD32(adapter, NX_CRB_DEV_STATE); if (state == NX_DEV_NEED_RESET) goto detach; -- cgit v1.2.3-18-g5258 From 13af7a6ea502fcdd4c0e3d7de6e332b102309491 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Fri, 11 Sep 2009 11:28:15 +0000 Subject: netxen: update copyright o Add QLogic copyright, add linux-driver@qlogic.com to MAINTAINERS. o Delete old contact information. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/Makefile | 7 +------ drivers/net/netxen/netxen_nic.h | 7 +------ drivers/net/netxen/netxen_nic_ctx.c | 7 +------ drivers/net/netxen/netxen_nic_ethtool.c | 7 +------ drivers/net/netxen/netxen_nic_hdr.h | 7 +------ drivers/net/netxen/netxen_nic_hw.c | 7 +------ drivers/net/netxen/netxen_nic_hw.h | 7 +------ drivers/net/netxen/netxen_nic_init.c | 7 +------ drivers/net/netxen/netxen_nic_main.c | 7 +------ 9 files changed, 9 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/Makefile b/drivers/net/netxen/Makefile index a70b682f616..11d94e2434e 100644 --- a/drivers/net/netxen/Makefile +++ b/drivers/net/netxen/Makefile @@ -1,4 +1,5 @@ # Copyright (C) 2003 - 2009 NetXen, Inc. +# Copyright (C) 2009 - QLogic Corporation. # All rights reserved. # # This program is free software; you can redistribute it and/or @@ -19,12 +20,6 @@ # The full GNU General Public License is included in this distribution # in the file called LICENSE. # -# Contact Information: -# info@netxen.com -# NetXen Inc, -# 18922 Forge Drive -# Cupertino, CA 95014-0701 -# # diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 1ae46e8c2dc..7384f59df61 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 - 2009 NetXen, Inc. + * Copyright (C) 2009 - QLogic Corporation. * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -20,12 +21,6 @@ * The full GNU General Public License is included in this distribution * in the file called LICENSE. * - * Contact Information: - * info@netxen.com - * NetXen Inc, - * 18922 Forge Drive - * Cupertino, CA 95014-0701 - * */ #ifndef _NETXEN_NIC_H_ diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 33f82db0129..9cb8f687804 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 - 2009 NetXen, Inc. + * Copyright (C) 2009 - QLogic Corporation. * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -20,12 +21,6 @@ * The full GNU General Public License is included in this distribution * in the file called LICENSE. * - * Contact Information: - * info@netxen.com - * NetXen Inc, - * 18922 Forge Drive - * Cupertino, CA 95014-0701 - * */ #include "netxen_nic_hw.h" diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index d18832ce4b5..714f38791a9 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 - 2009 NetXen, Inc. + * Copyright (C) 2009 - QLogic Corporation. * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -20,12 +21,6 @@ * The full GNU General Public License is included in this distribution * in the file called LICENSE. * - * Contact Information: - * info@netxen.com - * NetXen Inc, - * 18922 Forge Drive - * Cupertino, CA 95014-0701 - * */ #include diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index 26188b43abe..7a7177421d7 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 - 2009 NetXen, Inc. + * Copyright (C) 2009 - QLogic Corporation. * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -20,12 +21,6 @@ * The full GNU General Public License is included in this distribution * in the file called LICENSE. * - * Contact Information: - * info@netxen.com - * NetXen Inc, - * 18922 Forge Drive - * Cupertino, CA 95014-0701 - * */ #ifndef __NETXEN_NIC_HDR_H_ diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 018cf429c30..32314000dfc 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 - 2009 NetXen, Inc. + * Copyright (C) 2009 - QLogic Corporation. * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -20,12 +21,6 @@ * The full GNU General Public License is included in this distribution * in the file called LICENSE. * - * Contact Information: - * info@netxen.com - * NetXen Inc, - * 18922 Forge Drive - * Cupertino, CA 95014-0701 - * */ #include "netxen_nic.h" diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h index 98e4b95788b..3fd1dcb3583 100644 --- a/drivers/net/netxen/netxen_nic_hw.h +++ b/drivers/net/netxen/netxen_nic_hw.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 - 2009 NetXen, Inc. + * Copyright (C) 2009 - QLogic Corporation. * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -20,12 +21,6 @@ * The full GNU General Public License is included in this distribution * in the file called LICENSE. * - * Contact Information: - * info@netxen.com - * NetXen Inc, - * 18922 Forge Drive - * Cupertino, CA 95014-0701 - * */ #ifndef __NETXEN_NIC_HW_H_ diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 128d1b65402..91c2bc61c8e 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 - 2009 NetXen, Inc. + * Copyright (C) 2009 - QLogic Corporation. * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -20,12 +21,6 @@ * The full GNU General Public License is included in this distribution * in the file called LICENSE. * - * Contact Information: - * info@netxen.com - * NetXen Inc, - * 18922 Forge Drive - * Cupertino, CA 95014-0701 - * */ #include diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 53bd44e808e..f7bdde111df 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 - 2009 NetXen, Inc. + * Copyright (C) 2009 - QLogic Corporation. * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -20,12 +21,6 @@ * The full GNU General Public License is included in this distribution * in the file called LICENSE. * - * Contact Information: - * info@netxen.com - * NetXen Inc, - * 18922 Forge Drive - * Cupertino, CA 95014-0701 - * */ #include -- cgit v1.2.3-18-g5258 From f17a1f06d2fa93f4825be572622eb02c4894db4e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 4 Aug 2009 01:01:02 +0100 Subject: ARM: 5636/1: Move vendor enum to AMBA include This moves the primecell vendor enum definition inside vic.c out to linux/amba/bus.h where it belongs and replace any occurances of specific vendor ID:s with the respective enums instead. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index e1aa8471ab1..d78b1e460d7 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -430,7 +430,7 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) clk = 255; host->cclk = host->mclk / (2 * (clk + 1)); } - if (host->hw_designer == 0x80) + if (host->hw_designer == AMBA_VENDOR_ST) clk |= MCI_FCEN; /* Bug fix in ST IP block */ clk |= MCI_CLK_ENABLE; } @@ -443,7 +443,7 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) break; case MMC_POWER_UP: /* The ST version does not have this, fall through to POWER_ON */ - if (host->hw_designer != 0x80) { + if (host->hw_designer != AMBA_VENDOR_ST) { pwr |= MCI_PWR_UP; break; } @@ -453,7 +453,7 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) { - if (host->hw_designer != 0x80) + if (host->hw_designer != AMBA_VENDOR_ST) pwr |= MCI_ROD; else { /* -- cgit v1.2.3-18-g5258 From 8474f3a02a18e18459663ad88951822c62a45068 Mon Sep 17 00:00:00 2001 From: Santosh Vernekar Date: Tue, 25 Aug 2009 11:36:16 -0700 Subject: [SCSI] qla2xxx: Correctly set FCF_TAPE_PRESENT flag based on scsi-device. In fabric-login based on iop BIT_8 firmware notifies presence of a FCP2 device and not necessarily a TAPE device. So instead of setting FCF_TAPE_PRESENT flag there we set it using scsi_device->type after mid-layer scan recognises "type" of the device. It also adds a new flag FCF_FCP2_DEVICE for any future use. Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_init.c | 2 +- drivers/scsi/qla2xxx/qla_isr.c | 4 ++-- drivers/scsi/qla2xxx/qla_os.c | 3 +++ 4 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index efdfb1eb26b..21506186179 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1590,6 +1590,7 @@ typedef struct fc_port { #define FCF_FABRIC_DEVICE BIT_0 #define FCF_LOGIN_NEEDED BIT_1 #define FCF_TAPE_PRESENT BIT_2 +#define FCF_FCP2_DEVICE BIT_3 /* No loop ID flag. */ #define FC_NO_LOOP_ID 0x1000 diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 37c99a27874..51f81b27277 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -3341,7 +3341,7 @@ qla2x00_fabric_login(scsi_qla_host_t *vha, fc_port_t *fcport, } else { fcport->port_type = FCT_TARGET; if (mb[1] & BIT_1) { - fcport->flags |= FCF_TAPE_PRESENT; + fcport->flags |= FCF_FCP2_DEVICE; } } diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index c0fec6914b9..27db6246ca3 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1013,7 +1013,7 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, data[0] = MBS_COMMAND_COMPLETE; if (lio->ctx.type == SRB_LOGIN_CMD && le16_to_cpu(mbx->mb1) & BIT_1) - fcport->flags |= FCF_TAPE_PRESENT; + fcport->flags |= FCF_FCP2_DEVICE; goto done_post_logio_done_work; } @@ -1112,7 +1112,7 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, if (iop[0] & BIT_4) { fcport->port_type = FCT_TARGET; if (iop[0] & BIT_8) - fcport->flags |= FCF_TAPE_PRESENT; + fcport->flags |= FCF_FCP2_DEVICE; } if (iop[0] & BIT_5) fcport->port_type = FCT_INITIATOR; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 5fd7adbff30..649fd75d37b 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1216,6 +1216,7 @@ qla2xxx_slave_configure(struct scsi_device *sdev) scsi_qla_host_t *vha = shost_priv(sdev->host); struct qla_hw_data *ha = vha->hw; struct fc_rport *rport = starget_to_rport(sdev->sdev_target); + fc_port_t *fcport = *(fc_port_t **)rport->dd_data; struct req_que *req = vha->req; if (sdev->tagged_supported) @@ -1224,6 +1225,8 @@ qla2xxx_slave_configure(struct scsi_device *sdev) scsi_deactivate_tcq(sdev, req->max_q_depth); rport->dev_loss_tmo = ha->port_down_retry_count; + if (sdev->type == TYPE_TAPE) + fcport->flags |= FCF_TAPE_PRESENT; return 0; } -- cgit v1.2.3-18-g5258 From ab67114935d611caffe18063d1777f8c4f8b4272 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Tue, 25 Aug 2009 11:36:17 -0700 Subject: [SCSI] qla2xxx: Further limit device-table (qla_devtbl) lookup to non-24xx. Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 51f81b27277..825700ae504 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1794,7 +1794,8 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len, char *st, *en; uint16_t index; struct qla_hw_data *ha = vha->hw; - int use_tbl = !IS_QLA25XX(ha) && !IS_QLA81XX(ha); + int use_tbl = !IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && + !IS_QLA81XX(ha); if (memcmp(model, BINZERO, len) != 0) { strncpy(ha->model_number, model, len); -- cgit v1.2.3-18-g5258 From d970432c48ab8dd28216e80942723aeb505b623e Mon Sep 17 00:00:00 2001 From: Lalit Chandivade Date: Tue, 25 Aug 2009 11:36:18 -0700 Subject: [SCSI] qla2xxx: Correct qla2x00_eh_wait_on_command() to wait correctly. Original code would break-out of loop after only one iteration. Signed-off-by: Lalit Chandivade Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 649fd75d37b..ea9f91756c1 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -568,11 +568,8 @@ qla2x00_eh_wait_on_command(struct scsi_cmnd *cmd) unsigned long wait_iter = ABORT_WAIT_ITER; int ret = QLA_SUCCESS; - while (CMD_SP(cmd)) { + while (CMD_SP(cmd) && wait_iter--) { msleep(ABORT_POLLING_PERIOD); - - if (--wait_iter) - break; } if (CMD_SP(cmd)) ret = QLA_FUNCTION_FAILED; -- cgit v1.2.3-18-g5258 From 0d6e61bc6a4f3f54444b088ae6d447f1703a21dd Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Tue, 25 Aug 2009 11:36:19 -0700 Subject: [SCSI] qla2xxx: Correct various NPIV issues. * Consolidate vport-count processing. * Correct vp_idx restrictions during RSCN processing. * Push topology verification check to qla2x00_do_dpc_all_vps(). * Don't skip vport full-login-lip/lip-reset mailbox handling. Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 5 +++++ drivers/scsi/qla2xxx/qla_init.c | 2 -- drivers/scsi/qla2xxx/qla_isr.c | 3 ++- drivers/scsi/qla2xxx/qla_mid.c | 30 ++++++++++++++---------------- drivers/scsi/qla2xxx/qla_os.c | 21 +++++++++++---------- 5 files changed, 32 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 5b0a222241b..fbcb82a2f7f 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1736,6 +1736,11 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) qla24xx_deallocate_vp_id(vha); + mutex_lock(&ha->vport_lock); + ha->cur_vport_count--; + clear_bit(vha->vp_idx, ha->vp_idx_map); + mutex_unlock(&ha->vport_lock); + if (vha->timer_active) { qla2x00_vp_stop_timer(vha); DEBUG15(printk ("scsi(%ld): timer for the vport[%d] = %p " diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 825700ae504..f74d07a9e94 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -3540,8 +3540,6 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) if (atomic_read(&vha->loop_state) != LOOP_DOWN) { atomic_set(&vha->loop_state, LOOP_DOWN); qla2x00_mark_all_devices_lost(vha, 0); - list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) - qla2x00_mark_all_devices_lost(vp, 0); } else { if (!atomic_read(&vha->loop_down_timer)) atomic_set(&vha->loop_down_timer, diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 27db6246ca3..b20a7169aac 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -685,8 +685,9 @@ skip_rio: if (vha->vp_idx && test_bit(VP_SCR_NEEDED, &vha->vp_flags)) break; /* Only handle SCNs for our Vport index. */ - if (vha->vp_idx != (mb[3] & 0xff)) + if (ha->flags.npiv_supported && vha->vp_idx != (mb[3] & 0xff)) break; + DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n", vha->host_no)); DEBUG(printk(KERN_INFO diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index a748a95efb1..42b799abba5 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -42,7 +42,6 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha) set_bit(vp_id, ha->vp_idx_map); ha->num_vhosts++; - ha->cur_vport_count++; vha->vp_idx = vp_id; list_add_tail(&vha->list, &ha->vp_list); mutex_unlock(&ha->vport_lock); @@ -58,7 +57,6 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha) mutex_lock(&ha->vport_lock); vp_id = vha->vp_idx; ha->num_vhosts--; - ha->cur_vport_count--; clear_bit(vp_id, ha->vp_idx_map); list_del(&vha->list); mutex_unlock(&ha->vport_lock); @@ -235,7 +233,11 @@ qla2x00_vp_abort_isp(scsi_qla_host_t *vha) atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); } - /* To exclusively reset vport, we need to log it out first.*/ + /* + * To exclusively reset vport, we need to log it out first. Note: this + * control_vp can fail if ISP reset is already issued, this is + * expected, as the vp would be already logged out due to ISP reset. + */ if (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) qla24xx_control_vp(vha, VCE_COMMAND_DISABLE_VPS_LOGO_ALL); @@ -247,23 +249,11 @@ qla2x00_vp_abort_isp(scsi_qla_host_t *vha) static int qla2x00_do_dpc_vp(scsi_qla_host_t *vha) { - struct qla_hw_data *ha = vha->hw; - scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); - - if (!(ha->current_topology & ISP_CFG_F)) - return 0; - qla2x00_do_work(vha); if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) { /* VP acquired. complete port configuration */ - if (atomic_read(&base_vha->loop_state) == LOOP_READY) { - qla24xx_configure_vp(vha); - } else { - set_bit(VP_IDX_ACQUIRED, &vha->vp_flags); - set_bit(VP_DPC_NEEDED, &base_vha->dpc_flags); - } - + qla24xx_configure_vp(vha); return 0; } @@ -314,6 +304,9 @@ qla2x00_do_dpc_all_vps(scsi_qla_host_t *vha) clear_bit(VP_DPC_NEEDED, &vha->dpc_flags); + if (!(ha->current_topology & ISP_CFG_F)) + return; + list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { if (vp->vp_idx) ret = qla2x00_do_dpc_vp(vp); @@ -418,6 +411,11 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) vha->flags.init_done = 1; + mutex_lock(&ha->vport_lock); + set_bit(vha->vp_idx, ha->vp_idx_map); + ha->cur_vport_count++; + mutex_unlock(&ha->vport_lock); + return vha; create_vhost_failed: diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index ea9f91756c1..21022901958 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1119,8 +1119,7 @@ qla2x00_loop_reset(scsi_qla_host_t *vha) struct fc_port *fcport; struct qla_hw_data *ha = vha->hw; - if (ha->flags.enable_lip_full_login && !vha->vp_idx && - !IS_QLA81XX(ha)) { + if (ha->flags.enable_lip_full_login && !IS_QLA81XX(ha)) { ret = qla2x00_full_login_lip(vha); if (ret != QLA_SUCCESS) { DEBUG2_3(printk("%s(%ld): failed: " @@ -1133,7 +1132,7 @@ qla2x00_loop_reset(scsi_qla_host_t *vha) qla2x00_wait_for_loop_ready(vha); } - if (ha->flags.enable_lip_reset && !vha->vp_idx) { + if (ha->flags.enable_lip_reset) { ret = qla2x00_lip_reset(vha); if (ret != QLA_SUCCESS) { DEBUG2_3(printk("%s(%ld): failed: " @@ -2264,8 +2263,9 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer) fc_port_t *fcport; list_for_each_entry(fcport, &vha->vp_fcports, list) { - if (vha->vp_idx != fcport->vp_idx) + if (vha->vp_idx != 0 && vha->vp_idx != fcport->vp_idx) continue; + /* * No point in marking the device as lost, if the device is * already DEAD. @@ -2273,10 +2273,12 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer) if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD) continue; if (atomic_read(&fcport->state) == FCS_ONLINE) { - atomic_set(&fcport->state, FCS_DEVICE_LOST); - qla2x00_schedule_rport_del(vha, fcport, defer); - } else - atomic_set(&fcport->state, FCS_DEVICE_LOST); + if (defer) + qla2x00_schedule_rport_del(vha, fcport, defer); + else if (vha->vp_idx == fcport->vp_idx) + qla2x00_schedule_rport_del(vha, fcport, defer); + } + atomic_set(&fcport->state, FCS_DEVICE_LOST); } } @@ -3069,8 +3071,7 @@ qla2x00_timer(scsi_qla_host_t *vha) /* if the loop has been down for 4 minutes, reinit adapter */ if (atomic_dec_and_test(&vha->loop_down_timer) != 0) { - if (!(vha->device_flags & DFLG_NO_CABLE) && - !vha->vp_idx) { + if (!(vha->device_flags & DFLG_NO_CABLE)) { DEBUG(printk("scsi(%ld): Loop down - " "aborting ISP.\n", vha->host_no)); -- cgit v1.2.3-18-g5258 From 67becc0041615651b75e4496204a0835a8c345a8 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Tue, 25 Aug 2009 11:36:20 -0700 Subject: [SCSI] qla2xxx: Properly delete rports attached to a vport. Original code would inadvertently skip the deferred fc_remote_port_delete() call for rports hanging off any vport. Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_init.c | 12 +++++++----- drivers/scsi/qla2xxx/qla_os.c | 6 ++++-- 2 files changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index f74d07a9e94..9e3eaac2559 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -3495,15 +3495,17 @@ qla2x00_loop_resync(scsi_qla_host_t *vha) } void -qla2x00_update_fcports(scsi_qla_host_t *vha) +qla2x00_update_fcports(scsi_qla_host_t *base_vha) { fc_port_t *fcport; + struct scsi_qla_host *tvp, *vha; /* Go with deferred removal of rport references. */ - list_for_each_entry(fcport, &vha->vp_fcports, list) - if (fcport && fcport->drport && - atomic_read(&fcport->state) != FCS_UNCONFIGURED) - qla2x00_rport_del(fcport); + list_for_each_entry_safe(vha, tvp, &base_vha->hw->vp_list, list) + list_for_each_entry(fcport, &vha->vp_fcports, list) + if (fcport && fcport->drport && + atomic_read(&fcport->state) != FCS_UNCONFIGURED) + qla2x00_rport_del(fcport); } /* diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 21022901958..b79fca7d461 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2181,17 +2181,19 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport, int defer) { struct fc_rport *rport; + scsi_qla_host_t *base_vha; if (!fcport->rport) return; rport = fcport->rport; if (defer) { + base_vha = pci_get_drvdata(vha->hw->pdev); spin_lock_irq(vha->host->host_lock); fcport->drport = rport; spin_unlock_irq(vha->host->host_lock); - set_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); + set_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags); + qla2xxx_wake_dpc(base_vha); } else fc_remote_port_delete(rport); } -- cgit v1.2.3-18-g5258 From 073ed91e245d56d71a85e2a49bf0b3962fe74dc4 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Tue, 25 Aug 2009 11:36:21 -0700 Subject: [SCSI] qla2xxx: Update version number to 8.03.01-k6. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 87a884e341a..ac107a2c34a 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.03.01-k5" +#define QLA2XXX_VERSION "8.03.01-k6" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 3 -- cgit v1.2.3-18-g5258 From 89a3681041507773dfee1b88c1c90c8a811a79d3 Mon Sep 17 00:00:00 2001 From: Anil Ravindranath Date: Tue, 25 Aug 2009 17:35:18 -0700 Subject: [SCSI] pmcraid: PMC-Sierra MaxRAID driver to support 6Gb/s SAS RAID controller Signed-off-by: Anil Ravindranath Signed-off-by: James Bottomley --- drivers/scsi/Kconfig | 6 + drivers/scsi/Makefile | 1 + drivers/scsi/pmcraid.c | 5604 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/pmcraid.h | 1029 +++++++++ 4 files changed, 6640 insertions(+) create mode 100644 drivers/scsi/pmcraid.c create mode 100644 drivers/scsi/pmcraid.h (limited to 'drivers') diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 9c23122f755..82bb3b2d207 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1811,6 +1811,12 @@ config ZFCP called zfcp. If you want to compile it as a module, say M here and read . +config SCSI_PMCRAID + tristate "PMC SIERRA Linux MaxRAID adapter support" + depends on PCI && SCSI + ---help--- + This driver supports the PMC SIERRA MaxRAID adapters. + config SCSI_SRP tristate "SCSI RDMA Protocol helper library" depends on SCSI && PCI diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 25429ea63d0..61a94af3cee 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -130,6 +130,7 @@ obj-$(CONFIG_SCSI_MVSAS) += mvsas/ obj-$(CONFIG_PS3_ROM) += ps3rom.o obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libiscsi.o libiscsi_tcp.o cxgb3i/ obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/ +obj-$(CONFIG_SCSI_PMCRAID) += pmcraid.o obj-$(CONFIG_ARM) += arm/ diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c new file mode 100644 index 00000000000..4302f06e4ec --- /dev/null +++ b/drivers/scsi/pmcraid.c @@ -0,0 +1,5604 @@ +/* + * pmcraid.c -- driver for PMC Sierra MaxRAID controller adapters + * + * Written By: PMC Sierra Corporation + * + * Copyright (C) 2008, 2009 PMC Sierra Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, + * USA + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pmcraid.h" + +/* + * Module configuration parameters + */ +static unsigned int pmcraid_debug_log; +static unsigned int pmcraid_disable_aen; +static unsigned int pmcraid_log_level = IOASC_LOG_LEVEL_MUST; + +/* + * Data structures to support multiple adapters by the LLD. + * pmcraid_adapter_count - count of configured adapters + */ +static atomic_t pmcraid_adapter_count = ATOMIC_INIT(0); + +/* + * Supporting user-level control interface through IOCTL commands. + * pmcraid_major - major number to use + * pmcraid_minor - minor number(s) to use + */ +static unsigned int pmcraid_major; +static struct class *pmcraid_class; +DECLARE_BITMAP(pmcraid_minor, PMCRAID_MAX_ADAPTERS); + +/* + * Module parameters + */ +MODULE_AUTHOR("PMC Sierra Corporation, anil_ravindranath@pmc-sierra.com"); +MODULE_DESCRIPTION("PMC Sierra MaxRAID Controller Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(PMCRAID_DRIVER_VERSION); + +module_param_named(log_level, pmcraid_log_level, uint, (S_IRUGO | S_IWUSR)); +MODULE_PARM_DESC(log_level, + "Enables firmware error code logging, default :1 high-severity" + " errors, 2: all errors including high-severity errors," + " 0: disables logging"); + +module_param_named(debug, pmcraid_debug_log, uint, (S_IRUGO | S_IWUSR)); +MODULE_PARM_DESC(debug, + "Enable driver verbose message logging. Set 1 to enable." + "(default: 0)"); + +module_param_named(disable_aen, pmcraid_disable_aen, uint, (S_IRUGO | S_IWUSR)); +MODULE_PARM_DESC(disable_aen, + "Disable driver aen notifications to apps. Set 1 to disable." + "(default: 0)"); + +/* chip specific constants for PMC MaxRAID controllers (same for + * 0x5220 and 0x8010 + */ +static struct pmcraid_chip_details pmcraid_chip_cfg[] = { + { + .ioastatus = 0x0, + .ioarrin = 0x00040, + .mailbox = 0x7FC30, + .global_intr_mask = 0x00034, + .ioa_host_intr = 0x0009C, + .ioa_host_intr_clr = 0x000A0, + .ioa_host_mask = 0x7FC28, + .ioa_host_mask_clr = 0x7FC28, + .host_ioa_intr = 0x00020, + .host_ioa_intr_clr = 0x00020, + .transop_timeout = 300 + } +}; + +/* + * PCI device ids supported by pmcraid driver + */ +static struct pci_device_id pmcraid_pci_table[] __devinitdata = { + { PCI_DEVICE(PCI_VENDOR_ID_PMC, PCI_DEVICE_ID_PMC_MAXRAID), + 0, 0, (kernel_ulong_t)&pmcraid_chip_cfg[0] + }, + {} +}; + +MODULE_DEVICE_TABLE(pci, pmcraid_pci_table); + + + +/** + * pmcraid_slave_alloc - Prepare for commands to a device + * @scsi_dev: scsi device struct + * + * This function is called by mid-layer prior to sending any command to the new + * device. Stores resource entry details of the device in scsi_device struct. + * Queuecommand uses the resource handle and other details to fill up IOARCB + * while sending commands to the device. + * + * Return value: + * 0 on success / -ENXIO if device does not exist + */ +static int pmcraid_slave_alloc(struct scsi_device *scsi_dev) +{ + struct pmcraid_resource_entry *temp, *res = NULL; + struct pmcraid_instance *pinstance; + u8 target, bus, lun; + unsigned long lock_flags; + int rc = -ENXIO; + pinstance = shost_priv(scsi_dev->host); + + /* Driver exposes VSET and GSCSI resources only; all other device types + * are not exposed. Resource list is synchronized using resource lock + * so any traversal or modifications to the list should be done inside + * this lock + */ + spin_lock_irqsave(&pinstance->resource_lock, lock_flags); + list_for_each_entry(temp, &pinstance->used_res_q, queue) { + + /* do not expose VSETs with order-ids >= 240 */ + if (RES_IS_VSET(temp->cfg_entry)) { + target = temp->cfg_entry.unique_flags1; + if (target >= PMCRAID_MAX_VSET_TARGETS) + continue; + bus = PMCRAID_VSET_BUS_ID; + lun = 0; + } else if (RES_IS_GSCSI(temp->cfg_entry)) { + target = RES_TARGET(temp->cfg_entry.resource_address); + bus = PMCRAID_PHYS_BUS_ID; + lun = RES_LUN(temp->cfg_entry.resource_address); + } else { + continue; + } + + if (bus == scsi_dev->channel && + target == scsi_dev->id && + lun == scsi_dev->lun) { + res = temp; + break; + } + } + + if (res) { + res->scsi_dev = scsi_dev; + scsi_dev->hostdata = res; + res->change_detected = 0; + atomic_set(&res->read_failures, 0); + atomic_set(&res->write_failures, 0); + rc = 0; + } + spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); + return rc; +} + +/** + * pmcraid_slave_configure - Configures a SCSI device + * @scsi_dev: scsi device struct + * + * This fucntion is executed by SCSI mid layer just after a device is first + * scanned (i.e. it has responded to an INQUIRY). For VSET resources, the + * timeout value (default 30s) will be over-written to a higher value (60s) + * and max_sectors value will be over-written to 512. It also sets queue depth + * to host->cmd_per_lun value + * + * Return value: + * 0 on success + */ +static int pmcraid_slave_configure(struct scsi_device *scsi_dev) +{ + struct pmcraid_resource_entry *res = scsi_dev->hostdata; + + if (!res) + return 0; + + /* LLD exposes VSETs and Enclosure devices only */ + if (RES_IS_GSCSI(res->cfg_entry) && + scsi_dev->type != TYPE_ENCLOSURE) + return -ENXIO; + + pmcraid_info("configuring %x:%x:%x:%x\n", + scsi_dev->host->unique_id, + scsi_dev->channel, + scsi_dev->id, + scsi_dev->lun); + + if (RES_IS_GSCSI(res->cfg_entry)) { + scsi_dev->allow_restart = 1; + } else if (RES_IS_VSET(res->cfg_entry)) { + scsi_dev->allow_restart = 1; + blk_queue_rq_timeout(scsi_dev->request_queue, + PMCRAID_VSET_IO_TIMEOUT); + blk_queue_max_sectors(scsi_dev->request_queue, + PMCRAID_VSET_MAX_SECTORS); + } + + if (scsi_dev->tagged_supported && + (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry))) { + scsi_activate_tcq(scsi_dev, scsi_dev->queue_depth); + scsi_adjust_queue_depth(scsi_dev, MSG_SIMPLE_TAG, + scsi_dev->host->cmd_per_lun); + } else { + scsi_adjust_queue_depth(scsi_dev, 0, + scsi_dev->host->cmd_per_lun); + } + + return 0; +} + +/** + * pmcraid_slave_destroy - Unconfigure a SCSI device before removing it + * + * @scsi_dev: scsi device struct + * + * This is called by mid-layer before removing a device. Pointer assignments + * done in pmcraid_slave_alloc will be reset to NULL here. + * + * Return value + * none + */ +static void pmcraid_slave_destroy(struct scsi_device *scsi_dev) +{ + struct pmcraid_resource_entry *res; + + res = (struct pmcraid_resource_entry *)scsi_dev->hostdata; + + if (res) + res->scsi_dev = NULL; + + scsi_dev->hostdata = NULL; +} + +/** + * pmcraid_change_queue_depth - Change the device's queue depth + * @scsi_dev: scsi device struct + * @depth: depth to set + * + * Return value + * actual depth set + */ +static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth) +{ + if (depth > PMCRAID_MAX_CMD_PER_LUN) + depth = PMCRAID_MAX_CMD_PER_LUN; + + scsi_adjust_queue_depth(scsi_dev, scsi_get_tag_type(scsi_dev), depth); + + return scsi_dev->queue_depth; +} + +/** + * pmcraid_change_queue_type - Change the device's queue type + * @scsi_dev: scsi device struct + * @tag: type of tags to use + * + * Return value: + * actual queue type set + */ +static int pmcraid_change_queue_type(struct scsi_device *scsi_dev, int tag) +{ + struct pmcraid_resource_entry *res; + + res = (struct pmcraid_resource_entry *)scsi_dev->hostdata; + + if ((res) && scsi_dev->tagged_supported && + (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry))) { + scsi_set_tag_type(scsi_dev, tag); + + if (tag) + scsi_activate_tcq(scsi_dev, scsi_dev->queue_depth); + else + scsi_deactivate_tcq(scsi_dev, scsi_dev->queue_depth); + } else + tag = 0; + + return tag; +} + + +/** + * pmcraid_init_cmdblk - initializes a command block + * + * @cmd: pointer to struct pmcraid_cmd to be initialized + * @index: if >=0 first time initialization; otherwise reinitialization + * + * Return Value + * None + */ +void pmcraid_init_cmdblk(struct pmcraid_cmd *cmd, int index) +{ + struct pmcraid_ioarcb *ioarcb = &(cmd->ioa_cb->ioarcb); + dma_addr_t dma_addr = cmd->ioa_cb_bus_addr; + + if (index >= 0) { + /* first time initialization (called from probe) */ + u32 ioasa_offset = + offsetof(struct pmcraid_control_block, ioasa); + + cmd->index = index; + ioarcb->response_handle = cpu_to_le32(index << 2); + ioarcb->ioarcb_bus_addr = cpu_to_le64(dma_addr); + ioarcb->ioasa_bus_addr = cpu_to_le64(dma_addr + ioasa_offset); + ioarcb->ioasa_len = cpu_to_le16(sizeof(struct pmcraid_ioasa)); + } else { + /* re-initialization of various lengths, called once command is + * processed by IOA + */ + memset(&cmd->ioa_cb->ioarcb.cdb, 0, PMCRAID_MAX_CDB_LEN); + ioarcb->request_flags0 = 0; + ioarcb->request_flags1 = 0; + ioarcb->cmd_timeout = 0; + ioarcb->ioarcb_bus_addr &= (~0x1FULL); + ioarcb->ioadl_bus_addr = 0; + ioarcb->ioadl_length = 0; + ioarcb->data_transfer_length = 0; + ioarcb->add_cmd_param_length = 0; + ioarcb->add_cmd_param_offset = 0; + cmd->ioa_cb->ioasa.ioasc = 0; + cmd->ioa_cb->ioasa.residual_data_length = 0; + cmd->u.time_left = 0; + } + + cmd->cmd_done = NULL; + cmd->scsi_cmd = NULL; + cmd->release = 0; + cmd->completion_req = 0; + cmd->dma_handle = 0; + init_timer(&cmd->timer); +} + +/** + * pmcraid_reinit_cmdblk - reinitialize a command block + * + * @cmd: pointer to struct pmcraid_cmd to be reinitialized + * + * Return Value + * None + */ +static void pmcraid_reinit_cmdblk(struct pmcraid_cmd *cmd) +{ + pmcraid_init_cmdblk(cmd, -1); +} + +/** + * pmcraid_get_free_cmd - get a free cmd block from command block pool + * @pinstance: adapter instance structure + * + * Return Value: + * returns pointer to cmd block or NULL if no blocks are available + */ +static struct pmcraid_cmd *pmcraid_get_free_cmd( + struct pmcraid_instance *pinstance +) +{ + struct pmcraid_cmd *cmd = NULL; + unsigned long lock_flags; + + /* free cmd block list is protected by free_pool_lock */ + spin_lock_irqsave(&pinstance->free_pool_lock, lock_flags); + + if (!list_empty(&pinstance->free_cmd_pool)) { + cmd = list_entry(pinstance->free_cmd_pool.next, + struct pmcraid_cmd, free_list); + list_del(&cmd->free_list); + } + spin_unlock_irqrestore(&pinstance->free_pool_lock, lock_flags); + + /* Initialize the command block before giving it the caller */ + if (cmd != NULL) + pmcraid_reinit_cmdblk(cmd); + return cmd; +} + +/** + * pmcraid_return_cmd - return a completed command block back into free pool + * @cmd: pointer to the command block + * + * Return Value: + * nothing + */ +void pmcraid_return_cmd(struct pmcraid_cmd *cmd) +{ + struct pmcraid_instance *pinstance = cmd->drv_inst; + unsigned long lock_flags; + + spin_lock_irqsave(&pinstance->free_pool_lock, lock_flags); + list_add_tail(&cmd->free_list, &pinstance->free_cmd_pool); + spin_unlock_irqrestore(&pinstance->free_pool_lock, lock_flags); +} + +/** + * pmcraid_read_interrupts - reads IOA interrupts + * + * @pinstance: pointer to adapter instance structure + * + * Return value + * interrupts read from IOA + */ +static u32 pmcraid_read_interrupts(struct pmcraid_instance *pinstance) +{ + return ioread32(pinstance->int_regs.ioa_host_interrupt_reg); +} + +/** + * pmcraid_disable_interrupts - Masks and clears all specified interrupts + * + * @pinstance: pointer to per adapter instance structure + * @intrs: interrupts to disable + * + * Return Value + * None + */ +static void pmcraid_disable_interrupts( + struct pmcraid_instance *pinstance, + u32 intrs +) +{ + u32 gmask = ioread32(pinstance->int_regs.global_interrupt_mask_reg); + u32 nmask = gmask | GLOBAL_INTERRUPT_MASK; + + iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg); + iowrite32(intrs, pinstance->int_regs.ioa_host_interrupt_clr_reg); + iowrite32(intrs, pinstance->int_regs.ioa_host_interrupt_mask_reg); + ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); +} + +/** + * pmcraid_enable_interrupts - Enables specified interrupts + * + * @pinstance: pointer to per adapter instance structure + * @intr: interrupts to enable + * + * Return Value + * None + */ +static void pmcraid_enable_interrupts( + struct pmcraid_instance *pinstance, + u32 intrs +) +{ + u32 gmask = ioread32(pinstance->int_regs.global_interrupt_mask_reg); + u32 nmask = gmask & (~GLOBAL_INTERRUPT_MASK); + + iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg); + iowrite32(~intrs, pinstance->int_regs.ioa_host_interrupt_mask_reg); + ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); + + pmcraid_info("enabled interrupts global mask = %x intr_mask = %x\n", + ioread32(pinstance->int_regs.global_interrupt_mask_reg), + ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg)); +} + +/** + * pmcraid_reset_type - Determine the required reset type + * @pinstance: pointer to adapter instance structure + * + * IOA requires hard reset if any of the following conditions is true. + * 1. If HRRQ valid interrupt is not masked + * 2. IOA reset alert doorbell is set + * 3. If there are any error interrupts + */ +static void pmcraid_reset_type(struct pmcraid_instance *pinstance) +{ + u32 mask; + u32 intrs; + u32 alerts; + + mask = ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); + intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); + alerts = ioread32(pinstance->int_regs.host_ioa_interrupt_reg); + + if ((mask & INTRS_HRRQ_VALID) == 0 || + (alerts & DOORBELL_IOA_RESET_ALERT) || + (intrs & PMCRAID_ERROR_INTERRUPTS)) { + pmcraid_info("IOA requires hard reset\n"); + pinstance->ioa_hard_reset = 1; + } + + /* If unit check is active, trigger the dump */ + if (intrs & INTRS_IOA_UNIT_CHECK) + pinstance->ioa_unit_check = 1; +} + +/** + * pmcraid_bist_done - completion function for PCI BIST + * @cmd: pointer to reset command + * Return Value + * none + */ + +static void pmcraid_ioa_reset(struct pmcraid_cmd *); + +static void pmcraid_bist_done(struct pmcraid_cmd *cmd) +{ + struct pmcraid_instance *pinstance = cmd->drv_inst; + unsigned long lock_flags; + int rc; + u16 pci_reg; + + rc = pci_read_config_word(pinstance->pdev, PCI_COMMAND, &pci_reg); + + /* If PCI config space can't be accessed wait for another two secs */ + if ((rc != PCIBIOS_SUCCESSFUL || (!(pci_reg & PCI_COMMAND_MEMORY))) && + cmd->u.time_left > 0) { + pmcraid_info("BIST not complete, waiting another 2 secs\n"); + cmd->timer.expires = jiffies + cmd->u.time_left; + cmd->u.time_left = 0; + cmd->timer.data = (unsigned long)cmd; + cmd->timer.function = + (void (*)(unsigned long))pmcraid_bist_done; + add_timer(&cmd->timer); + } else { + cmd->u.time_left = 0; + pmcraid_info("BIST is complete, proceeding with reset\n"); + spin_lock_irqsave(pinstance->host->host_lock, lock_flags); + pmcraid_ioa_reset(cmd); + spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); + } +} + +/** + * pmcraid_start_bist - starts BIST + * @cmd: pointer to reset cmd + * Return Value + * none + */ +static void pmcraid_start_bist(struct pmcraid_cmd *cmd) +{ + struct pmcraid_instance *pinstance = cmd->drv_inst; + u32 doorbells, intrs; + + /* proceed with bist and wait for 2 seconds */ + iowrite32(DOORBELL_IOA_START_BIST, + pinstance->int_regs.host_ioa_interrupt_reg); + doorbells = ioread32(pinstance->int_regs.host_ioa_interrupt_reg); + intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); + pmcraid_info("doorbells after start bist: %x intrs: %x \n", + doorbells, intrs); + + cmd->u.time_left = msecs_to_jiffies(PMCRAID_BIST_TIMEOUT); + cmd->timer.data = (unsigned long)cmd; + cmd->timer.expires = jiffies + msecs_to_jiffies(PMCRAID_BIST_TIMEOUT); + cmd->timer.function = (void (*)(unsigned long))pmcraid_bist_done; + add_timer(&cmd->timer); +} + +/** + * pmcraid_reset_alert_done - completion routine for reset_alert + * @cmd: pointer to command block used in reset sequence + * Return value + * None + */ +static void pmcraid_reset_alert_done(struct pmcraid_cmd *cmd) +{ + struct pmcraid_instance *pinstance = cmd->drv_inst; + u32 status = ioread32(pinstance->ioa_status); + unsigned long lock_flags; + + /* if the critical operation in progress bit is set or the wait times + * out, invoke reset engine to proceed with hard reset. If there is + * some more time to wait, restart the timer + */ + if (((status & INTRS_CRITICAL_OP_IN_PROGRESS) == 0) || + cmd->u.time_left <= 0) { + pmcraid_info("critical op is reset proceeding with reset\n"); + spin_lock_irqsave(pinstance->host->host_lock, lock_flags); + pmcraid_ioa_reset(cmd); + spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); + } else { + pmcraid_info("critical op is not yet reset waiting again\n"); + /* restart timer if some more time is available to wait */ + cmd->u.time_left -= PMCRAID_CHECK_FOR_RESET_TIMEOUT; + cmd->timer.data = (unsigned long)cmd; + cmd->timer.expires = jiffies + PMCRAID_CHECK_FOR_RESET_TIMEOUT; + cmd->timer.function = + (void (*)(unsigned long))pmcraid_reset_alert_done; + add_timer(&cmd->timer); + } +} + +/** + * pmcraid_reset_alert - alerts IOA for a possible reset + * @cmd : command block to be used for reset sequence. + * + * Return Value + * returns 0 if pci config-space is accessible and RESET_DOORBELL is + * successfully written to IOA. Returns non-zero in case pci_config_space + * is not accessible + */ +static void pmcraid_reset_alert(struct pmcraid_cmd *cmd) +{ + struct pmcraid_instance *pinstance = cmd->drv_inst; + u32 doorbells; + int rc; + u16 pci_reg; + + /* If we are able to access IOA PCI config space, alert IOA that we are + * going to reset it soon. This enables IOA to preserv persistent error + * data if any. In case memory space is not accessible, proceed with + * BIST or slot_reset + */ + rc = pci_read_config_word(pinstance->pdev, PCI_COMMAND, &pci_reg); + if ((rc == PCIBIOS_SUCCESSFUL) && (pci_reg & PCI_COMMAND_MEMORY)) { + + /* wait for IOA permission i.e until CRITICAL_OPERATION bit is + * reset IOA doesn't generate any interrupts when CRITICAL + * OPERATION bit is reset. A timer is started to wait for this + * bit to be reset. + */ + cmd->u.time_left = PMCRAID_RESET_TIMEOUT; + cmd->timer.data = (unsigned long)cmd; + cmd->timer.expires = jiffies + PMCRAID_CHECK_FOR_RESET_TIMEOUT; + cmd->timer.function = + (void (*)(unsigned long))pmcraid_reset_alert_done; + add_timer(&cmd->timer); + + iowrite32(DOORBELL_IOA_RESET_ALERT, + pinstance->int_regs.host_ioa_interrupt_reg); + doorbells = + ioread32(pinstance->int_regs.host_ioa_interrupt_reg); + pmcraid_info("doorbells after reset alert: %x\n", doorbells); + } else { + pmcraid_info("PCI config is not accessible starting BIST\n"); + pinstance->ioa_state = IOA_STATE_IN_HARD_RESET; + pmcraid_start_bist(cmd); + } +} + +/** + * pmcraid_timeout_handler - Timeout handler for internally generated ops + * + * @cmd : pointer to command structure, that got timedout + * + * This function blocks host requests and initiates an adapter reset. + * + * Return value: + * None + */ +static void pmcraid_timeout_handler(struct pmcraid_cmd *cmd) +{ + struct pmcraid_instance *pinstance = cmd->drv_inst; + unsigned long lock_flags; + + dev_err(&pinstance->pdev->dev, + "Adapter being reset due to command timeout.\n"); + + /* Command timeouts result in hard reset sequence. The command that got + * timed out may be the one used as part of reset sequence. In this + * case restart reset sequence using the same command block even if + * reset is in progress. Otherwise fail this command and get a free + * command block to restart the reset sequence. + */ + spin_lock_irqsave(pinstance->host->host_lock, lock_flags); + if (!pinstance->ioa_reset_in_progress) { + pinstance->ioa_reset_attempts = 0; + cmd = pmcraid_get_free_cmd(pinstance); + + /* If we are out of command blocks, just return here itself. + * Some other command's timeout handler can do the reset job + */ + if (cmd == NULL) { + spin_unlock_irqrestore(pinstance->host->host_lock, + lock_flags); + pmcraid_err("no free cmnd block for timeout handler\n"); + return; + } + + pinstance->reset_cmd = cmd; + pinstance->ioa_reset_in_progress = 1; + } else { + pmcraid_info("reset is already in progress\n"); + + if (pinstance->reset_cmd != cmd) { + /* This command should have been given to IOA, this + * command will be completed by fail_outstanding_cmds + * anyway + */ + pmcraid_err("cmd is pending but reset in progress\n"); + } + + /* If this command was being used as part of the reset + * sequence, set cmd_done pointer to pmcraid_ioa_reset. This + * causes fail_outstanding_commands not to return the command + * block back to free pool + */ + if (cmd == pinstance->reset_cmd) + cmd->cmd_done = pmcraid_ioa_reset; + + } + + pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; + scsi_block_requests(pinstance->host); + pmcraid_reset_alert(cmd); + spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); +} + +/** + * pmcraid_internal_done - completion routine for internally generated cmds + * + * @cmd: command that got response from IOA + * + * Return Value: + * none + */ +static void pmcraid_internal_done(struct pmcraid_cmd *cmd) +{ + pmcraid_info("response internal cmd CDB[0] = %x ioasc = %x\n", + cmd->ioa_cb->ioarcb.cdb[0], + le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); + + /* Some of the internal commands are sent with callers blocking for the + * response. Same will be indicated as part of cmd->completion_req + * field. Response path needs to wake up any waiters waiting for cmd + * completion if this flag is set. + */ + if (cmd->completion_req) { + cmd->completion_req = 0; + complete(&cmd->wait_for_completion); + } + + /* most of the internal commands are completed by caller itself, so + * no need to return the command block back to free pool until we are + * required to do so (e.g once done with initialization). + */ + if (cmd->release) { + cmd->release = 0; + pmcraid_return_cmd(cmd); + } +} + +/** + * pmcraid_reinit_cfgtable_done - done function for cfg table reinitialization + * + * @cmd: command that got response from IOA + * + * This routine is called after driver re-reads configuration table due to a + * lost CCN. It returns the command block back to free pool and schedules + * worker thread to add/delete devices into the system. + * + * Return Value: + * none + */ +static void pmcraid_reinit_cfgtable_done(struct pmcraid_cmd *cmd) +{ + pmcraid_info("response internal cmd CDB[0] = %x ioasc = %x\n", + cmd->ioa_cb->ioarcb.cdb[0], + le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); + + if (cmd->release) { + cmd->release = 0; + pmcraid_return_cmd(cmd); + } + pmcraid_info("scheduling worker for config table reinitialization\n"); + schedule_work(&cmd->drv_inst->worker_q); +} + +/** + * pmcraid_erp_done - Process completion of SCSI error response from device + * @cmd: pmcraid_command + * + * This function copies the sense buffer into the scsi_cmd struct and completes + * scsi_cmd by calling scsi_done function. + * + * Return value: + * none + */ +static void pmcraid_erp_done(struct pmcraid_cmd *cmd) +{ + struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; + struct pmcraid_instance *pinstance = cmd->drv_inst; + u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); + + if (PMCRAID_IOASC_SENSE_KEY(ioasc) > 0) { + scsi_cmd->result |= (DID_ERROR << 16); + pmcraid_err("command CDB[0] = %x failed with IOASC: 0x%08X\n", + cmd->ioa_cb->ioarcb.cdb[0], ioasc); + } + + /* if we had allocated sense buffers for request sense, copy the sense + * release the buffers + */ + if (cmd->sense_buffer != NULL) { + memcpy(scsi_cmd->sense_buffer, + cmd->sense_buffer, + SCSI_SENSE_BUFFERSIZE); + pci_free_consistent(pinstance->pdev, + SCSI_SENSE_BUFFERSIZE, + cmd->sense_buffer, cmd->sense_buffer_dma); + cmd->sense_buffer = NULL; + cmd->sense_buffer_dma = 0; + } + + scsi_dma_unmap(scsi_cmd); + pmcraid_return_cmd(cmd); + scsi_cmd->scsi_done(scsi_cmd); +} + +/** + * pmcraid_fire_command - sends an IOA command to adapter + * + * This function adds the given block into pending command list + * and returns without waiting + * + * @cmd : command to be sent to the device + * + * Return Value + * None + */ +static void _pmcraid_fire_command(struct pmcraid_cmd *cmd) +{ + struct pmcraid_instance *pinstance = cmd->drv_inst; + unsigned long lock_flags; + + /* Add this command block to pending cmd pool. We do this prior to + * writting IOARCB to ioarrin because IOA might complete the command + * by the time we are about to add it to the list. Response handler + * (isr/tasklet) looks for cmb block in the pending pending list. + */ + spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags); + list_add_tail(&cmd->free_list, &pinstance->pending_cmd_pool); + spin_unlock_irqrestore(&pinstance->pending_pool_lock, lock_flags); + atomic_inc(&pinstance->outstanding_cmds); + + /* driver writes lower 32-bit value of IOARCB address only */ + mb(); + iowrite32(le32_to_cpu(cmd->ioa_cb->ioarcb.ioarcb_bus_addr), + pinstance->ioarrin); +} + +/** + * pmcraid_send_cmd - fires a command to IOA + * + * This function also sets up timeout function, and command completion + * function + * + * @cmd: pointer to the command block to be fired to IOA + * @cmd_done: command completion function, called once IOA responds + * @timeout: timeout to wait for this command completion + * @timeout_func: timeout handler + * + * Return value + * none + */ +static void pmcraid_send_cmd( + struct pmcraid_cmd *cmd, + void (*cmd_done) (struct pmcraid_cmd *), + unsigned long timeout, + void (*timeout_func) (struct pmcraid_cmd *) +) +{ + /* initialize done function */ + cmd->cmd_done = cmd_done; + + if (timeout_func) { + /* setup timeout handler */ + cmd->timer.data = (unsigned long)cmd; + cmd->timer.expires = jiffies + timeout; + cmd->timer.function = (void (*)(unsigned long))timeout_func; + add_timer(&cmd->timer); + } + + /* fire the command to IOA */ + _pmcraid_fire_command(cmd); +} + +/** + * pmcraid_ioa_shutdown - sends SHUTDOWN command to ioa + * + * @cmd: pointer to the command block used as part of reset sequence + * + * Return Value + * None + */ +static void pmcraid_ioa_shutdown(struct pmcraid_cmd *cmd) +{ + pmcraid_info("response for Cancel CCN CDB[0] = %x ioasc = %x\n", + cmd->ioa_cb->ioarcb.cdb[0], + le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); + + /* Note that commands sent during reset require next command to be sent + * to IOA. Hence reinit the done function as well as timeout function + */ + pmcraid_reinit_cmdblk(cmd); + cmd->ioa_cb->ioarcb.request_type = REQ_TYPE_IOACMD; + cmd->ioa_cb->ioarcb.resource_handle = + cpu_to_le32(PMCRAID_IOA_RES_HANDLE); + cmd->ioa_cb->ioarcb.cdb[0] = PMCRAID_IOA_SHUTDOWN; + cmd->ioa_cb->ioarcb.cdb[1] = PMCRAID_SHUTDOWN_NORMAL; + + /* fire shutdown command to hardware. */ + pmcraid_info("firing normal shutdown command (%d) to IOA\n", + le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle)); + + pmcraid_send_cmd(cmd, pmcraid_ioa_reset, + PMCRAID_SHUTDOWN_TIMEOUT, + pmcraid_timeout_handler); +} + +/** + * pmcraid_identify_hrrq - registers host rrq buffers with IOA + * @cmd: pointer to command block to be used for identify hrrq + * + * Return Value + * 0 in case of success, otherwise non-zero failure code + */ + +static void pmcraid_querycfg(struct pmcraid_cmd *); + +static void pmcraid_identify_hrrq(struct pmcraid_cmd *cmd) +{ + struct pmcraid_instance *pinstance = cmd->drv_inst; + struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; + int index = 0; + __be64 hrrq_addr = cpu_to_be64(pinstance->hrrq_start_bus_addr[index]); + u32 hrrq_size = cpu_to_be32(sizeof(u32) * PMCRAID_MAX_CMD); + + pmcraid_reinit_cmdblk(cmd); + + /* Initialize ioarcb */ + ioarcb->request_type = REQ_TYPE_IOACMD; + ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); + + /* initialize the hrrq number where IOA will respond to this command */ + ioarcb->hrrq_id = index; + ioarcb->cdb[0] = PMCRAID_IDENTIFY_HRRQ; + ioarcb->cdb[1] = index; + + /* IOA expects 64-bit pci address to be written in B.E format + * (i.e cdb[2]=MSByte..cdb[9]=LSB. + */ + pmcraid_info("HRRQ_IDENTIFY with hrrq:ioarcb => %llx:%llx\n", + hrrq_addr, ioarcb->ioarcb_bus_addr); + + memcpy(&(ioarcb->cdb[2]), &hrrq_addr, sizeof(hrrq_addr)); + memcpy(&(ioarcb->cdb[10]), &hrrq_size, sizeof(hrrq_size)); + + /* Subsequent commands require HRRQ identification to be successful. + * Note that this gets called even during reset from SCSI mid-layer + * or tasklet + */ + pmcraid_send_cmd(cmd, pmcraid_querycfg, + PMCRAID_INTERNAL_TIMEOUT, + pmcraid_timeout_handler); +} + +static void pmcraid_process_ccn(struct pmcraid_cmd *cmd); +static void pmcraid_process_ldn(struct pmcraid_cmd *cmd); + +/** + * pmcraid_send_hcam_cmd - send an initialized command block(HCAM) to IOA + * + * @cmd: initialized command block pointer + * + * Return Value + * none + */ +static void pmcraid_send_hcam_cmd(struct pmcraid_cmd *cmd) +{ + if (cmd->ioa_cb->ioarcb.cdb[1] == PMCRAID_HCAM_CODE_CONFIG_CHANGE) + atomic_set(&(cmd->drv_inst->ccn.ignore), 0); + else + atomic_set(&(cmd->drv_inst->ldn.ignore), 0); + + pmcraid_send_cmd(cmd, cmd->cmd_done, 0, NULL); +} + +/** + * pmcraid_init_hcam - send an initialized command block(HCAM) to IOA + * + * @pinstance: pointer to adapter instance structure + * @type: HCAM type + * + * Return Value + * pointer to initialized pmcraid_cmd structure or NULL + */ +static struct pmcraid_cmd *pmcraid_init_hcam +( + struct pmcraid_instance *pinstance, + u8 type +) +{ + struct pmcraid_cmd *cmd; + struct pmcraid_ioarcb *ioarcb; + struct pmcraid_ioadl_desc *ioadl; + struct pmcraid_hostrcb *hcam; + void (*cmd_done) (struct pmcraid_cmd *); + dma_addr_t dma; + int rcb_size; + + cmd = pmcraid_get_free_cmd(pinstance); + + if (!cmd) { + pmcraid_err("no free command blocks for hcam\n"); + return cmd; + } + + if (type == PMCRAID_HCAM_CODE_CONFIG_CHANGE) { + rcb_size = sizeof(struct pmcraid_hcam_ccn); + cmd_done = pmcraid_process_ccn; + dma = pinstance->ccn.baddr + PMCRAID_AEN_HDR_SIZE; + hcam = &pinstance->ccn; + } else { + rcb_size = sizeof(struct pmcraid_hcam_ldn); + cmd_done = pmcraid_process_ldn; + dma = pinstance->ldn.baddr + PMCRAID_AEN_HDR_SIZE; + hcam = &pinstance->ldn; + } + + /* initialize command pointer used for HCAM registration */ + hcam->cmd = cmd; + + ioarcb = &cmd->ioa_cb->ioarcb; + ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + + offsetof(struct pmcraid_ioarcb, + add_data.u.ioadl[0])); + ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); + ioadl = ioarcb->add_data.u.ioadl; + + /* Initialize ioarcb */ + ioarcb->request_type = REQ_TYPE_HCAM; + ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); + ioarcb->cdb[0] = PMCRAID_HOST_CONTROLLED_ASYNC; + ioarcb->cdb[1] = type; + ioarcb->cdb[7] = (rcb_size >> 8) & 0xFF; + ioarcb->cdb[8] = (rcb_size) & 0xFF; + + ioarcb->data_transfer_length = cpu_to_le32(rcb_size); + + ioadl[0].flags |= cpu_to_le32(IOADL_FLAGS_READ_LAST); + ioadl[0].data_len = cpu_to_le32(rcb_size); + ioadl[0].address = cpu_to_le32(dma); + + cmd->cmd_done = cmd_done; + return cmd; +} + +/** + * pmcraid_send_hcam - Send an HCAM to IOA + * @pinstance: ioa config struct + * @type: HCAM type + * + * This function will send a Host Controlled Async command to IOA. + * + * Return value: + * none + */ +static void pmcraid_send_hcam(struct pmcraid_instance *pinstance, u8 type) +{ + struct pmcraid_cmd *cmd = pmcraid_init_hcam(pinstance, type); + pmcraid_send_hcam_cmd(cmd); +} + + +/** + * pmcraid_prepare_cancel_cmd - prepares a command block to abort another + * + * @cmd: pointer to cmd that is used as cancelling command + * @cmd_to_cancel: pointer to the command that needs to be cancelled + */ +static void pmcraid_prepare_cancel_cmd( + struct pmcraid_cmd *cmd, + struct pmcraid_cmd *cmd_to_cancel +) +{ + struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; + __be64 ioarcb_addr = cmd_to_cancel->ioa_cb->ioarcb.ioarcb_bus_addr; + + /* Get the resource handle to where the command to be aborted has been + * sent. + */ + ioarcb->resource_handle = cmd_to_cancel->ioa_cb->ioarcb.resource_handle; + ioarcb->request_type = REQ_TYPE_IOACMD; + memset(ioarcb->cdb, 0, PMCRAID_MAX_CDB_LEN); + ioarcb->cdb[0] = PMCRAID_ABORT_CMD; + + /* IOARCB address of the command to be cancelled is given in + * cdb[2]..cdb[9] is Big-Endian format. Note that length bits in + * IOARCB address are not masked. + */ + ioarcb_addr = cpu_to_be64(ioarcb_addr); + memcpy(&(ioarcb->cdb[2]), &ioarcb_addr, sizeof(ioarcb_addr)); +} + +/** + * pmcraid_cancel_hcam - sends ABORT task to abort a given HCAM + * + * @cmd: command to be used as cancelling command + * @type: HCAM type + * @cmd_done: op done function for the cancelling command + */ +static void pmcraid_cancel_hcam( + struct pmcraid_cmd *cmd, + u8 type, + void (*cmd_done) (struct pmcraid_cmd *) +) +{ + struct pmcraid_instance *pinstance; + struct pmcraid_hostrcb *hcam; + + pinstance = cmd->drv_inst; + hcam = (type == PMCRAID_HCAM_CODE_LOG_DATA) ? + &pinstance->ldn : &pinstance->ccn; + + /* prepare for cancelling previous hcam command. If the HCAM is + * currently not pending with IOA, we would have hcam->cmd as non-null + */ + if (hcam->cmd == NULL) + return; + + pmcraid_prepare_cancel_cmd(cmd, hcam->cmd); + + /* writing to IOARRIN must be protected by host_lock, as mid-layer + * schedule queuecommand while we are doing this + */ + pmcraid_send_cmd(cmd, cmd_done, + PMCRAID_INTERNAL_TIMEOUT, + pmcraid_timeout_handler); +} + +/** + * pmcraid_cancel_ccn - cancel CCN HCAM already registered with IOA + * + * @cmd: command block to be used for cancelling the HCAM + */ +static void pmcraid_cancel_ccn(struct pmcraid_cmd *cmd) +{ + pmcraid_info("response for Cancel LDN CDB[0] = %x ioasc = %x\n", + cmd->ioa_cb->ioarcb.cdb[0], + le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); + + pmcraid_reinit_cmdblk(cmd); + + pmcraid_cancel_hcam(cmd, + PMCRAID_HCAM_CODE_CONFIG_CHANGE, + pmcraid_ioa_shutdown); +} + +/** + * pmcraid_cancel_ldn - cancel LDN HCAM already registered with IOA + * + * @cmd: command block to be used for cancelling the HCAM + */ +static void pmcraid_cancel_ldn(struct pmcraid_cmd *cmd) +{ + pmcraid_cancel_hcam(cmd, + PMCRAID_HCAM_CODE_LOG_DATA, + pmcraid_cancel_ccn); +} + +/** + * pmcraid_expose_resource - check if the resource can be exposed to OS + * + * @cfgte: pointer to configuration table entry of the resource + * + * Return value: + * true if resource can be added to midlayer, false(0) otherwise + */ +static int pmcraid_expose_resource(struct pmcraid_config_table_entry *cfgte) +{ + int retval = 0; + + if (cfgte->resource_type == RES_TYPE_VSET) + retval = ((cfgte->unique_flags1 & 0xFF) < 0xFE); + else if (cfgte->resource_type == RES_TYPE_GSCSI) + retval = (RES_BUS(cfgte->resource_address) != + PMCRAID_VIRTUAL_ENCL_BUS_ID); + return retval; +} + +/* attributes supported by pmcraid_event_family */ +enum { + PMCRAID_AEN_ATTR_UNSPEC, + PMCRAID_AEN_ATTR_EVENT, + __PMCRAID_AEN_ATTR_MAX, +}; +#define PMCRAID_AEN_ATTR_MAX (__PMCRAID_AEN_ATTR_MAX - 1) + +/* commands supported by pmcraid_event_family */ +enum { + PMCRAID_AEN_CMD_UNSPEC, + PMCRAID_AEN_CMD_EVENT, + __PMCRAID_AEN_CMD_MAX, +}; +#define PMCRAID_AEN_CMD_MAX (__PMCRAID_AEN_CMD_MAX - 1) + +static struct genl_family pmcraid_event_family = { + .id = GENL_ID_GENERATE, + .name = "pmcraid", + .version = 1, + .maxattr = PMCRAID_AEN_ATTR_MAX +}; + +/** + * pmcraid_netlink_init - registers pmcraid_event_family + * + * Return value: + * 0 if the pmcraid_event_family is successfully registered + * with netlink generic, non-zero otherwise + */ +static int pmcraid_netlink_init(void) +{ + int result; + + result = genl_register_family(&pmcraid_event_family); + + if (result) + return result; + + pmcraid_info("registered NETLINK GENERIC group: %d\n", + pmcraid_event_family.id); + + return result; +} + +/** + * pmcraid_netlink_release - unregisters pmcraid_event_family + * + * Return value: + * none + */ +static void pmcraid_netlink_release(void) +{ + genl_unregister_family(&pmcraid_event_family); +} + +/** + * pmcraid_notify_aen - sends event msg to user space application + * @pinstance: pointer to adapter instance structure + * @type: HCAM type + * + * Return value: + * 0 if success, error value in case of any failure. + */ +static int pmcraid_notify_aen(struct pmcraid_instance *pinstance, u8 type) +{ + struct sk_buff *skb; + struct pmcraid_aen_msg *aen_msg; + void *msg_header; + int data_size, total_size; + int result; + + + if (type == PMCRAID_HCAM_CODE_LOG_DATA) { + aen_msg = pinstance->ldn.msg; + data_size = pinstance->ldn.hcam->data_len; + } else { + aen_msg = pinstance->ccn.msg; + data_size = pinstance->ccn.hcam->data_len; + } + + data_size += sizeof(struct pmcraid_hcam_hdr); + aen_msg->hostno = (pinstance->host->unique_id << 16 | + MINOR(pinstance->cdev.dev)); + aen_msg->length = data_size; + data_size += sizeof(*aen_msg); + + total_size = nla_total_size(data_size); + skb = genlmsg_new(total_size, GFP_ATOMIC); + + + if (!skb) { + pmcraid_err("Failed to allocate aen data SKB of size: %x\n", + total_size); + return -ENOMEM; + } + + /* add the genetlink message header */ + msg_header = genlmsg_put(skb, 0, 0, + &pmcraid_event_family, 0, + PMCRAID_AEN_CMD_EVENT); + if (!msg_header) { + pmcraid_err("failed to copy command details\n"); + nlmsg_free(skb); + return -ENOMEM; + } + + result = nla_put(skb, PMCRAID_AEN_ATTR_EVENT, data_size, aen_msg); + + if (result) { + pmcraid_err("failed to copy AEN attribute data \n"); + nlmsg_free(skb); + return -EINVAL; + } + + /* send genetlink multicast message to notify appplications */ + result = genlmsg_end(skb, msg_header); + + if (result < 0) { + pmcraid_err("genlmsg_end failed\n"); + nlmsg_free(skb); + return result; + } + + result = + genlmsg_multicast(skb, 0, pmcraid_event_family.id, GFP_ATOMIC); + + /* If there are no listeners, genlmsg_multicast may return non-zero + * value. + */ + if (result) + pmcraid_info("failed to send %s event message %x!\n", + type == PMCRAID_HCAM_CODE_LOG_DATA ? "LDN" : "CCN", + result); + return result; +} + +/** + * pmcraid_handle_config_change - Handle a config change from the adapter + * @pinstance: pointer to per adapter instance structure + * + * Return value: + * none + */ +static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance) +{ + struct pmcraid_config_table_entry *cfg_entry; + struct pmcraid_hcam_ccn *ccn_hcam; + struct pmcraid_cmd *cmd; + struct pmcraid_cmd *cfgcmd; + struct pmcraid_resource_entry *res = NULL; + u32 new_entry = 1; + unsigned long lock_flags; + unsigned long host_lock_flags; + int rc; + + ccn_hcam = (struct pmcraid_hcam_ccn *)pinstance->ccn.hcam; + cfg_entry = &ccn_hcam->cfg_entry; + + pmcraid_info + ("CCN(%x): %x type: %x lost: %x flags: %x res: %x:%x:%x:%x\n", + pinstance->ccn.hcam->ilid, + pinstance->ccn.hcam->op_code, + pinstance->ccn.hcam->notification_type, + pinstance->ccn.hcam->notification_lost, + pinstance->ccn.hcam->flags, + pinstance->host->unique_id, + RES_IS_VSET(*cfg_entry) ? PMCRAID_VSET_BUS_ID : + (RES_IS_GSCSI(*cfg_entry) ? PMCRAID_PHYS_BUS_ID : + RES_BUS(cfg_entry->resource_address)), + RES_IS_VSET(*cfg_entry) ? cfg_entry->unique_flags1 : + RES_TARGET(cfg_entry->resource_address), + RES_LUN(cfg_entry->resource_address)); + + + /* If this HCAM indicates a lost notification, read the config table */ + if (pinstance->ccn.hcam->notification_lost) { + cfgcmd = pmcraid_get_free_cmd(pinstance); + if (cfgcmd) { + pmcraid_info("lost CCN, reading config table\b"); + pinstance->reinit_cfg_table = 1; + pmcraid_querycfg(cfgcmd); + } else { + pmcraid_err("lost CCN, no free cmd for querycfg\n"); + } + goto out_notify_apps; + } + + /* If this resource is not going to be added to mid-layer, just notify + * applications and return + */ + if (!pmcraid_expose_resource(cfg_entry)) + goto out_notify_apps; + + spin_lock_irqsave(&pinstance->resource_lock, lock_flags); + list_for_each_entry(res, &pinstance->used_res_q, queue) { + rc = memcmp(&res->cfg_entry.resource_address, + &cfg_entry->resource_address, + sizeof(cfg_entry->resource_address)); + if (!rc) { + new_entry = 0; + break; + } + } + + if (new_entry) { + + /* If there are more number of resources than what driver can + * manage, do not notify the applications about the CCN. Just + * ignore this notifications and re-register the same HCAM + */ + if (list_empty(&pinstance->free_res_q)) { + spin_unlock_irqrestore(&pinstance->resource_lock, + lock_flags); + pmcraid_err("too many resources attached\n"); + spin_lock_irqsave(pinstance->host->host_lock, + host_lock_flags); + pmcraid_send_hcam(pinstance, + PMCRAID_HCAM_CODE_CONFIG_CHANGE); + spin_unlock_irqrestore(pinstance->host->host_lock, + host_lock_flags); + return; + } + + res = list_entry(pinstance->free_res_q.next, + struct pmcraid_resource_entry, queue); + + list_del(&res->queue); + res->scsi_dev = NULL; + res->reset_progress = 0; + list_add_tail(&res->queue, &pinstance->used_res_q); + } + + memcpy(&res->cfg_entry, cfg_entry, + sizeof(struct pmcraid_config_table_entry)); + + if (pinstance->ccn.hcam->notification_type == + NOTIFICATION_TYPE_ENTRY_DELETED) { + if (res->scsi_dev) { + res->change_detected = RES_CHANGE_DEL; + res->cfg_entry.resource_handle = + PMCRAID_INVALID_RES_HANDLE; + schedule_work(&pinstance->worker_q); + } else { + /* This may be one of the non-exposed resources */ + list_move_tail(&res->queue, &pinstance->free_res_q); + } + } else if (!res->scsi_dev) { + res->change_detected = RES_CHANGE_ADD; + schedule_work(&pinstance->worker_q); + } + spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); + +out_notify_apps: + + /* Notify configuration changes to registered applications.*/ + if (!pmcraid_disable_aen) + pmcraid_notify_aen(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); + + cmd = pmcraid_init_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); + if (cmd) + pmcraid_send_hcam_cmd(cmd); +} + +/** + * pmcraid_get_error_info - return error string for an ioasc + * @ioasc: ioasc code + * Return Value + * none + */ +static struct pmcraid_ioasc_error *pmcraid_get_error_info(u32 ioasc) +{ + int i; + for (i = 0; i < ARRAY_SIZE(pmcraid_ioasc_error_table); i++) { + if (pmcraid_ioasc_error_table[i].ioasc_code == ioasc) + return &pmcraid_ioasc_error_table[i]; + } + return NULL; +} + +/** + * pmcraid_ioasc_logger - log IOASC information based user-settings + * @ioasc: ioasc code + * @cmd: pointer to command that resulted in 'ioasc' + */ +void pmcraid_ioasc_logger(u32 ioasc, struct pmcraid_cmd *cmd) +{ + struct pmcraid_ioasc_error *error_info = pmcraid_get_error_info(ioasc); + + if (error_info == NULL || + cmd->drv_inst->current_log_level < error_info->log_level) + return; + + /* log the error string */ + pmcraid_err("cmd [%d] for resource %x failed with %x(%s)\n", + cmd->ioa_cb->ioarcb.cdb[0], + cmd->ioa_cb->ioarcb.resource_handle, + le32_to_cpu(ioasc), error_info->error_string); +} + +/** + * pmcraid_handle_error_log - Handle a config change (error log) from the IOA + * + * @pinstance: pointer to per adapter instance structure + * + * Return value: + * none + */ +static void pmcraid_handle_error_log(struct pmcraid_instance *pinstance) +{ + struct pmcraid_hcam_ldn *hcam_ldn; + u32 ioasc; + + hcam_ldn = (struct pmcraid_hcam_ldn *)pinstance->ldn.hcam; + + pmcraid_info + ("LDN(%x): %x type: %x lost: %x flags: %x overlay id: %x\n", + pinstance->ldn.hcam->ilid, + pinstance->ldn.hcam->op_code, + pinstance->ldn.hcam->notification_type, + pinstance->ldn.hcam->notification_lost, + pinstance->ldn.hcam->flags, + pinstance->ldn.hcam->overlay_id); + + /* log only the errors, no need to log informational log entries */ + if (pinstance->ldn.hcam->notification_type != + NOTIFICATION_TYPE_ERROR_LOG) + return; + + if (pinstance->ldn.hcam->notification_lost == + HOSTRCB_NOTIFICATIONS_LOST) + dev_err(&pinstance->pdev->dev, "Error notifications lost\n"); + + ioasc = le32_to_cpu(hcam_ldn->error_log.fd_ioasc); + + if (ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET || + ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER) { + dev_err(&pinstance->pdev->dev, + "UnitAttention due to IOA Bus Reset\n"); + scsi_report_bus_reset( + pinstance->host, + RES_BUS(hcam_ldn->error_log.fd_ra)); + } + + return; +} + +/** + * pmcraid_process_ccn - Op done function for a CCN. + * @cmd: pointer to command struct + * + * This function is the op done function for a configuration + * change notification + * + * Return value: + * none + */ +static void pmcraid_process_ccn(struct pmcraid_cmd *cmd) +{ + struct pmcraid_instance *pinstance = cmd->drv_inst; + u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); + unsigned long lock_flags; + + pinstance->ccn.cmd = NULL; + pmcraid_return_cmd(cmd); + + /* If driver initiated IOA reset happened while this hcam was pending + * with IOA, or IOA bringdown sequence is in progress, no need to + * re-register the hcam + */ + if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET || + atomic_read(&pinstance->ccn.ignore) == 1) { + return; + } else if (ioasc) { + dev_err(&pinstance->pdev->dev, + "Host RCB (CCN) failed with IOASC: 0x%08X\n", ioasc); + spin_lock_irqsave(pinstance->host->host_lock, lock_flags); + pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); + spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); + } else { + pmcraid_handle_config_change(pinstance); + } +} + +/** + * pmcraid_process_ldn - op done function for an LDN + * @cmd: pointer to command block + * + * Return value + * none + */ +static void pmcraid_initiate_reset(struct pmcraid_instance *); + +static void pmcraid_process_ldn(struct pmcraid_cmd *cmd) +{ + struct pmcraid_instance *pinstance = cmd->drv_inst; + struct pmcraid_hcam_ldn *ldn_hcam = + (struct pmcraid_hcam_ldn *)pinstance->ldn.hcam; + u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); + u32 fd_ioasc = le32_to_cpu(ldn_hcam->error_log.fd_ioasc); + unsigned long lock_flags; + + /* return the command block back to freepool */ + pinstance->ldn.cmd = NULL; + pmcraid_return_cmd(cmd); + + /* If driver initiated IOA reset happened while this hcam was pending + * with IOA, no need to re-register the hcam as reset engine will do it + * once reset sequence is complete + */ + if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET || + atomic_read(&pinstance->ccn.ignore) == 1) { + return; + } else if (!ioasc) { + pmcraid_handle_error_log(pinstance); + if (fd_ioasc == PMCRAID_IOASC_NR_IOA_RESET_REQUIRED) { + spin_lock_irqsave(pinstance->host->host_lock, + lock_flags); + pmcraid_initiate_reset(pinstance); + spin_unlock_irqrestore(pinstance->host->host_lock, + lock_flags); + return; + } + } else { + dev_err(&pinstance->pdev->dev, + "Host RCB(LDN) failed with IOASC: 0x%08X\n", ioasc); + } + /* send netlink message for HCAM notification if enabled */ + if (!pmcraid_disable_aen) + pmcraid_notify_aen(pinstance, PMCRAID_HCAM_CODE_LOG_DATA); + + cmd = pmcraid_init_hcam(pinstance, PMCRAID_HCAM_CODE_LOG_DATA); + if (cmd) + pmcraid_send_hcam_cmd(cmd); +} + +/** + * pmcraid_register_hcams - register HCAMs for CCN and LDN + * + * @pinstance: pointer per adapter instance structure + * + * Return Value + * none + */ +static void pmcraid_register_hcams(struct pmcraid_instance *pinstance) +{ + pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); + pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_LOG_DATA); +} + +/** + * pmcraid_unregister_hcams - cancel HCAMs registered already + * @cmd: pointer to command used as part of reset sequence + */ +static void pmcraid_unregister_hcams(struct pmcraid_cmd *cmd) +{ + struct pmcraid_instance *pinstance = cmd->drv_inst; + + /* During IOA bringdown, HCAM gets fired and tasklet proceeds with + * handling hcam response though it is not necessary. In order to + * prevent this, set 'ignore', so that bring-down sequence doesn't + * re-send any more hcams + */ + atomic_set(&pinstance->ccn.ignore, 1); + atomic_set(&pinstance->ldn.ignore, 1); + + /* If adapter reset was forced as part of runtime reset sequence, + * start the reset sequence. + */ + if (pinstance->force_ioa_reset && !pinstance->ioa_bringdown) { + pinstance->force_ioa_reset = 0; + pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; + pmcraid_reset_alert(cmd); + return; + } + + /* Driver tries to cancel HCAMs by sending ABORT TASK for each HCAM + * one after the other. So CCN cancellation will be triggered by + * pmcraid_cancel_ldn itself. + */ + pmcraid_cancel_ldn(cmd); +} + +/** + * pmcraid_reset_enable_ioa - re-enable IOA after a hard reset + * @pinstance: pointer to adapter instance structure + * Return Value + * 1 if TRANSITION_TO_OPERATIONAL is active, otherwise 0 + */ +static void pmcraid_reinit_buffers(struct pmcraid_instance *); + +static int pmcraid_reset_enable_ioa(struct pmcraid_instance *pinstance) +{ + u32 intrs; + + pmcraid_reinit_buffers(pinstance); + intrs = pmcraid_read_interrupts(pinstance); + + pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS); + + if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) { + iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, + pinstance->int_regs.ioa_host_interrupt_mask_reg); + iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, + pinstance->int_regs.ioa_host_interrupt_clr_reg); + return 1; + } else { + return 0; + } +} + +/** + * pmcraid_soft_reset - performs a soft reset and makes IOA become ready + * @cmd : pointer to reset command block + * + * Return Value + * none + */ +static void pmcraid_soft_reset(struct pmcraid_cmd *cmd) +{ + struct pmcraid_instance *pinstance = cmd->drv_inst; + u32 int_reg; + u32 doorbell; + + /* There will be an interrupt when Transition to Operational bit is + * set so tasklet would execute next reset task. The timeout handler + * would re-initiate a reset + */ + cmd->cmd_done = pmcraid_ioa_reset; + cmd->timer.data = (unsigned long)cmd; + cmd->timer.expires = jiffies + + msecs_to_jiffies(PMCRAID_TRANSOP_TIMEOUT); + cmd->timer.function = (void (*)(unsigned long))pmcraid_timeout_handler; + + if (!timer_pending(&cmd->timer)) + add_timer(&cmd->timer); + + /* Enable destructive diagnostics on IOA if it is not yet in + * operational state + */ + doorbell = DOORBELL_RUNTIME_RESET | + DOORBELL_ENABLE_DESTRUCTIVE_DIAGS; + + iowrite32(doorbell, pinstance->int_regs.host_ioa_interrupt_reg); + int_reg = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); + pmcraid_info("Waiting for IOA to become operational %x:%x\n", + ioread32(pinstance->int_regs.host_ioa_interrupt_reg), + int_reg); +} + +/** + * pmcraid_get_dump - retrieves IOA dump in case of Unit Check interrupt + * + * @pinstance: pointer to adapter instance structure + * + * Return Value + * none + */ +static void pmcraid_get_dump(struct pmcraid_instance *pinstance) +{ + pmcraid_info("%s is not yet implemented\n", __func__); +} + +/** + * pmcraid_fail_outstanding_cmds - Fails all outstanding ops. + * @pinstance: pointer to adapter instance structure + * + * This function fails all outstanding ops. If they are submitted to IOA + * already, it sends cancel all messages if IOA is still accepting IOARCBs, + * otherwise just completes the commands and returns the cmd blocks to free + * pool. + * + * Return value: + * none + */ +static void pmcraid_fail_outstanding_cmds(struct pmcraid_instance *pinstance) +{ + struct pmcraid_cmd *cmd, *temp; + unsigned long lock_flags; + + /* pending command list is protected by pending_pool_lock. Its + * traversal must be done as within this lock + */ + spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags); + list_for_each_entry_safe(cmd, temp, &pinstance->pending_cmd_pool, + free_list) { + list_del(&cmd->free_list); + spin_unlock_irqrestore(&pinstance->pending_pool_lock, + lock_flags); + cmd->ioa_cb->ioasa.ioasc = + cpu_to_le32(PMCRAID_IOASC_IOA_WAS_RESET); + cmd->ioa_cb->ioasa.ilid = + cpu_to_be32(PMCRAID_DRIVER_ILID); + + /* In case the command timer is still running */ + del_timer(&cmd->timer); + + /* If this is an IO command, complete it by invoking scsi_done + * function. If this is one of the internal commands other + * than pmcraid_ioa_reset and HCAM commands invoke cmd_done to + * complete it + */ + if (cmd->scsi_cmd) { + + struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; + __le32 resp = cmd->ioa_cb->ioarcb.response_handle; + + scsi_cmd->result |= DID_ERROR << 16; + + scsi_dma_unmap(scsi_cmd); + pmcraid_return_cmd(cmd); + + + pmcraid_info("failing(%d) CDB[0] = %x result: %x\n", + le32_to_cpu(resp) >> 2, + cmd->ioa_cb->ioarcb.cdb[0], + scsi_cmd->result); + scsi_cmd->scsi_done(scsi_cmd); + } else if (cmd->cmd_done == pmcraid_internal_done || + cmd->cmd_done == pmcraid_erp_done) { + cmd->cmd_done(cmd); + } else if (cmd->cmd_done != pmcraid_ioa_reset) { + pmcraid_return_cmd(cmd); + } + + atomic_dec(&pinstance->outstanding_cmds); + spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags); + } + + spin_unlock_irqrestore(&pinstance->pending_pool_lock, lock_flags); +} + +/** + * pmcraid_ioa_reset - Implementation of IOA reset logic + * + * @cmd: pointer to the cmd block to be used for entire reset process + * + * This function executes most of the steps required for IOA reset. This gets + * called by user threads (modprobe/insmod/rmmod) timer, tasklet and midlayer's + * 'eh_' thread. Access to variables used for controling the reset sequence is + * synchronized using host lock. Various functions called during reset process + * would make use of a single command block, pointer to which is also stored in + * adapter instance structure. + * + * Return Value + * None + */ +static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd) +{ + struct pmcraid_instance *pinstance = cmd->drv_inst; + u8 reset_complete = 0; + + pinstance->ioa_reset_in_progress = 1; + + if (pinstance->reset_cmd != cmd) { + pmcraid_err("reset is called with different command block\n"); + pinstance->reset_cmd = cmd; + } + + pmcraid_info("reset_engine: state = %d, command = %p\n", + pinstance->ioa_state, cmd); + + switch (pinstance->ioa_state) { + + case IOA_STATE_DEAD: + /* If IOA is offline, whatever may be the reset reason, just + * return. callers might be waiting on the reset wait_q, wake + * up them + */ + pmcraid_err("IOA is offline no reset is possible\n"); + reset_complete = 1; + break; + + case IOA_STATE_IN_BRINGDOWN: + /* we enter here, once ioa shutdown command is processed by IOA + * Alert IOA for a possible reset. If reset alert fails, IOA + * goes through hard-reset + */ + pmcraid_disable_interrupts(pinstance, ~0); + pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; + pmcraid_reset_alert(cmd); + break; + + case IOA_STATE_UNKNOWN: + /* We may be called during probe or resume. Some pre-processing + * is required for prior to reset + */ + scsi_block_requests(pinstance->host); + + /* If asked to reset while IOA was processing responses or + * there are any error responses then IOA may require + * hard-reset. + */ + if (pinstance->ioa_hard_reset == 0) { + if (ioread32(pinstance->ioa_status) & + INTRS_TRANSITION_TO_OPERATIONAL) { + pmcraid_info("sticky bit set, bring-up\n"); + pinstance->ioa_state = IOA_STATE_IN_BRINGUP; + pmcraid_reinit_cmdblk(cmd); + pmcraid_identify_hrrq(cmd); + } else { + pinstance->ioa_state = IOA_STATE_IN_SOFT_RESET; + pmcraid_soft_reset(cmd); + } + } else { + /* Alert IOA of a possible reset and wait for critical + * operation in progress bit to reset + */ + pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; + pmcraid_reset_alert(cmd); + } + break; + + case IOA_STATE_IN_RESET_ALERT: + /* If critical operation in progress bit is reset or wait gets + * timed out, reset proceeds with starting BIST on the IOA. + * pmcraid_ioa_hard_reset keeps a count of reset attempts. If + * they are 3 or more, reset engine marks IOA dead and returns + */ + pinstance->ioa_state = IOA_STATE_IN_HARD_RESET; + pmcraid_start_bist(cmd); + break; + + case IOA_STATE_IN_HARD_RESET: + pinstance->ioa_reset_attempts++; + + /* retry reset if we haven't reached maximum allowed limit */ + if (pinstance->ioa_reset_attempts > PMCRAID_RESET_ATTEMPTS) { + pinstance->ioa_reset_attempts = 0; + pmcraid_err("IOA didn't respond marking it as dead\n"); + pinstance->ioa_state = IOA_STATE_DEAD; + reset_complete = 1; + break; + } + + /* Once either bist or pci reset is done, restore PCI config + * space. If this fails, proceed with hard reset again + */ + + if (pci_restore_state(pinstance->pdev)) { + pmcraid_info("config-space error resetting again\n"); + pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; + pmcraid_reset_alert(cmd); + break; + } + + /* fail all pending commands */ + pmcraid_fail_outstanding_cmds(pinstance); + + /* check if unit check is active, if so extract dump */ + if (pinstance->ioa_unit_check) { + pmcraid_info("unit check is active\n"); + pinstance->ioa_unit_check = 0; + pmcraid_get_dump(pinstance); + pinstance->ioa_reset_attempts--; + pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; + pmcraid_reset_alert(cmd); + break; + } + + /* if the reset reason is to bring-down the ioa, we might be + * done with the reset restore pci_config_space and complete + * the reset + */ + if (pinstance->ioa_bringdown) { + pmcraid_info("bringing down the adapter\n"); + pinstance->ioa_shutdown_type = SHUTDOWN_NONE; + pinstance->ioa_bringdown = 0; + pinstance->ioa_state = IOA_STATE_UNKNOWN; + reset_complete = 1; + } else { + /* bring-up IOA, so proceed with soft reset + * Reinitialize hrrq_buffers and their indices also + * enable interrupts after a pci_restore_state + */ + if (pmcraid_reset_enable_ioa(pinstance)) { + pinstance->ioa_state = IOA_STATE_IN_BRINGUP; + pmcraid_info("bringing up the adapter\n"); + pmcraid_reinit_cmdblk(cmd); + pmcraid_identify_hrrq(cmd); + } else { + pinstance->ioa_state = IOA_STATE_IN_SOFT_RESET; + pmcraid_soft_reset(cmd); + } + } + break; + + case IOA_STATE_IN_SOFT_RESET: + /* TRANSITION TO OPERATIONAL is on so start initialization + * sequence + */ + pmcraid_info("In softreset proceeding with bring-up\n"); + pinstance->ioa_state = IOA_STATE_IN_BRINGUP; + + /* Initialization commands start with HRRQ identification. From + * now on tasklet completes most of the commands as IOA is up + * and intrs are enabled + */ + pmcraid_identify_hrrq(cmd); + break; + + case IOA_STATE_IN_BRINGUP: + /* we are done with bringing up of IOA, change the ioa_state to + * operational and wake up any waiters + */ + pinstance->ioa_state = IOA_STATE_OPERATIONAL; + reset_complete = 1; + break; + + case IOA_STATE_OPERATIONAL: + default: + /* When IOA is operational and a reset is requested, check for + * the reset reason. If reset is to bring down IOA, unregister + * HCAMs and initiate shutdown; if adapter reset is forced then + * restart reset sequence again + */ + if (pinstance->ioa_shutdown_type == SHUTDOWN_NONE && + pinstance->force_ioa_reset == 0) { + reset_complete = 1; + } else { + if (pinstance->ioa_shutdown_type != SHUTDOWN_NONE) + pinstance->ioa_state = IOA_STATE_IN_BRINGDOWN; + pmcraid_reinit_cmdblk(cmd); + pmcraid_unregister_hcams(cmd); + } + break; + } + + /* reset will be completed if ioa_state is either DEAD or UNKNOWN or + * OPERATIONAL. Reset all control variables used during reset, wake up + * any waiting threads and let the SCSI mid-layer send commands. Note + * that host_lock must be held before invoking scsi_report_bus_reset. + */ + if (reset_complete) { + pinstance->ioa_reset_in_progress = 0; + pinstance->ioa_reset_attempts = 0; + pinstance->reset_cmd = NULL; + pinstance->ioa_shutdown_type = SHUTDOWN_NONE; + pinstance->ioa_bringdown = 0; + pmcraid_return_cmd(cmd); + + /* If target state is to bring up the adapter, proceed with + * hcam registration and resource exposure to mid-layer. + */ + if (pinstance->ioa_state == IOA_STATE_OPERATIONAL) + pmcraid_register_hcams(pinstance); + + wake_up_all(&pinstance->reset_wait_q); + } + + return; +} + +/** + * pmcraid_initiate_reset - initiates reset sequence. This is called from + * ISR/tasklet during error interrupts including IOA unit check. If reset + * is already in progress, it just returns, otherwise initiates IOA reset + * to bring IOA up to operational state. + * + * @pinstance: pointer to adapter instance structure + * + * Return value + * none + */ +static void pmcraid_initiate_reset(struct pmcraid_instance *pinstance) +{ + struct pmcraid_cmd *cmd; + + /* If the reset is already in progress, just return, otherwise start + * reset sequence and return + */ + if (!pinstance->ioa_reset_in_progress) { + scsi_block_requests(pinstance->host); + cmd = pmcraid_get_free_cmd(pinstance); + + if (cmd == NULL) { + pmcraid_err("no cmnd blocks for initiate_reset\n"); + return; + } + + pinstance->ioa_shutdown_type = SHUTDOWN_NONE; + pinstance->reset_cmd = cmd; + pinstance->force_ioa_reset = 1; + pmcraid_ioa_reset(cmd); + } +} + +/** + * pmcraid_reset_reload - utility routine for doing IOA reset either to bringup + * or bringdown IOA + * @pinstance: pointer adapter instance structure + * @shutdown_type: shutdown type to be used NONE, NORMAL or ABRREV + * @target_state: expected target state after reset + * + * Note: This command initiates reset and waits for its completion. Hence this + * should not be called from isr/timer/tasklet functions (timeout handlers, + * error response handlers and interrupt handlers). + * + * Return Value + * 1 in case ioa_state is not target_state, 0 otherwise. + */ +static int pmcraid_reset_reload( + struct pmcraid_instance *pinstance, + u8 shutdown_type, + u8 target_state +) +{ + struct pmcraid_cmd *reset_cmd = NULL; + unsigned long lock_flags; + int reset = 1; + + spin_lock_irqsave(pinstance->host->host_lock, lock_flags); + + if (pinstance->ioa_reset_in_progress) { + pmcraid_info("reset_reload: reset is already in progress\n"); + + spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); + + wait_event(pinstance->reset_wait_q, + !pinstance->ioa_reset_in_progress); + + spin_lock_irqsave(pinstance->host->host_lock, lock_flags); + + if (pinstance->ioa_state == IOA_STATE_DEAD) { + spin_unlock_irqrestore(pinstance->host->host_lock, + lock_flags); + pmcraid_info("reset_reload: IOA is dead\n"); + return reset; + } else if (pinstance->ioa_state == target_state) { + reset = 0; + } + } + + if (reset) { + pmcraid_info("reset_reload: proceeding with reset\n"); + scsi_block_requests(pinstance->host); + reset_cmd = pmcraid_get_free_cmd(pinstance); + + if (reset_cmd == NULL) { + pmcraid_err("no free cmnd for reset_reload\n"); + spin_unlock_irqrestore(pinstance->host->host_lock, + lock_flags); + return reset; + } + + if (shutdown_type == SHUTDOWN_NORMAL) + pinstance->ioa_bringdown = 1; + + pinstance->ioa_shutdown_type = shutdown_type; + pinstance->reset_cmd = reset_cmd; + pinstance->force_ioa_reset = reset; + pmcraid_info("reset_reload: initiating reset\n"); + pmcraid_ioa_reset(reset_cmd); + spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); + pmcraid_info("reset_reload: waiting for reset to complete\n"); + wait_event(pinstance->reset_wait_q, + !pinstance->ioa_reset_in_progress); + + pmcraid_info("reset_reload: reset is complete !! \n"); + scsi_unblock_requests(pinstance->host); + if (pinstance->ioa_state == target_state) + reset = 0; + } + + return reset; +} + +/** + * pmcraid_reset_bringdown - wrapper over pmcraid_reset_reload to bringdown IOA + * + * @pinstance: pointer to adapter instance structure + * + * Return Value + * whatever is returned from pmcraid_reset_reload + */ +static int pmcraid_reset_bringdown(struct pmcraid_instance *pinstance) +{ + return pmcraid_reset_reload(pinstance, + SHUTDOWN_NORMAL, + IOA_STATE_UNKNOWN); +} + +/** + * pmcraid_reset_bringup - wrapper over pmcraid_reset_reload to bring up IOA + * + * @pinstance: pointer to adapter instance structure + * + * Return Value + * whatever is returned from pmcraid_reset_reload + */ +static int pmcraid_reset_bringup(struct pmcraid_instance *pinstance) +{ + return pmcraid_reset_reload(pinstance, + SHUTDOWN_NONE, + IOA_STATE_OPERATIONAL); +} + +/** + * pmcraid_request_sense - Send request sense to a device + * @cmd: pmcraid command struct + * + * This function sends a request sense to a device as a result of a check + * condition. This method re-uses the same command block that failed earlier. + */ +static void pmcraid_request_sense(struct pmcraid_cmd *cmd) +{ + struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; + struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; + + /* allocate DMAable memory for sense buffers */ + cmd->sense_buffer = pci_alloc_consistent(cmd->drv_inst->pdev, + SCSI_SENSE_BUFFERSIZE, + &cmd->sense_buffer_dma); + + if (cmd->sense_buffer == NULL) { + pmcraid_err + ("couldn't allocate sense buffer for request sense\n"); + pmcraid_erp_done(cmd); + return; + } + + /* re-use the command block */ + memset(&cmd->ioa_cb->ioasa, 0, sizeof(struct pmcraid_ioasa)); + memset(ioarcb->cdb, 0, PMCRAID_MAX_CDB_LEN); + ioarcb->request_flags0 = (SYNC_COMPLETE | + NO_LINK_DESCS | + INHIBIT_UL_CHECK); + ioarcb->request_type = REQ_TYPE_SCSI; + ioarcb->cdb[0] = REQUEST_SENSE; + ioarcb->cdb[4] = SCSI_SENSE_BUFFERSIZE; + + ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + + offsetof(struct pmcraid_ioarcb, + add_data.u.ioadl[0])); + ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); + + ioarcb->data_transfer_length = cpu_to_le32(SCSI_SENSE_BUFFERSIZE); + + ioadl->address = cpu_to_le64(cmd->sense_buffer_dma); + ioadl->data_len = cpu_to_le32(SCSI_SENSE_BUFFERSIZE); + ioadl->flags = cpu_to_le32(IOADL_FLAGS_LAST_DESC); + + /* request sense might be called as part of error response processing + * which runs in tasklets context. It is possible that mid-layer might + * schedule queuecommand during this time, hence, writting to IOARRIN + * must be protect by host_lock + */ + pmcraid_send_cmd(cmd, pmcraid_erp_done, + PMCRAID_REQUEST_SENSE_TIMEOUT, + pmcraid_timeout_handler); +} + +/** + * pmcraid_cancel_all - cancel all outstanding IOARCBs as part of error recovery + * @cmd: command that failed + * @sense: true if request_sense is required after cancel all + * + * This function sends a cancel all to a device to clear the queue. + */ +static void pmcraid_cancel_all(struct pmcraid_cmd *cmd, u32 sense) +{ + struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; + struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; + struct pmcraid_resource_entry *res = scsi_cmd->device->hostdata; + void (*cmd_done) (struct pmcraid_cmd *) = sense ? pmcraid_erp_done + : pmcraid_request_sense; + + memset(ioarcb->cdb, 0, PMCRAID_MAX_CDB_LEN); + ioarcb->request_flags0 = SYNC_OVERRIDE; + ioarcb->request_type = REQ_TYPE_IOACMD; + ioarcb->cdb[0] = PMCRAID_CANCEL_ALL_REQUESTS; + + if (RES_IS_GSCSI(res->cfg_entry)) + ioarcb->cdb[1] = PMCRAID_SYNC_COMPLETE_AFTER_CANCEL; + + ioarcb->ioadl_bus_addr = 0; + ioarcb->ioadl_length = 0; + ioarcb->data_transfer_length = 0; + ioarcb->ioarcb_bus_addr &= (~0x1FULL); + + /* writing to IOARRIN must be protected by host_lock, as mid-layer + * schedule queuecommand while we are doing this + */ + pmcraid_send_cmd(cmd, cmd_done, + PMCRAID_REQUEST_SENSE_TIMEOUT, + pmcraid_timeout_handler); +} + +/** + * pmcraid_frame_auto_sense: frame fixed format sense information + * + * @cmd: pointer to failing command block + * + * Return value + * none + */ +static void pmcraid_frame_auto_sense(struct pmcraid_cmd *cmd) +{ + u8 *sense_buf = cmd->scsi_cmd->sense_buffer; + struct pmcraid_resource_entry *res = cmd->scsi_cmd->device->hostdata; + struct pmcraid_ioasa *ioasa = &cmd->ioa_cb->ioasa; + u32 ioasc = le32_to_cpu(ioasa->ioasc); + u32 failing_lba = 0; + + memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE); + cmd->scsi_cmd->result = SAM_STAT_CHECK_CONDITION; + + if (RES_IS_VSET(res->cfg_entry) && + ioasc == PMCRAID_IOASC_ME_READ_ERROR_NO_REALLOC && + ioasa->u.vset.failing_lba_hi != 0) { + + sense_buf[0] = 0x72; + sense_buf[1] = PMCRAID_IOASC_SENSE_KEY(ioasc); + sense_buf[2] = PMCRAID_IOASC_SENSE_CODE(ioasc); + sense_buf[3] = PMCRAID_IOASC_SENSE_QUAL(ioasc); + + sense_buf[7] = 12; + sense_buf[8] = 0; + sense_buf[9] = 0x0A; + sense_buf[10] = 0x80; + + failing_lba = le32_to_cpu(ioasa->u.vset.failing_lba_hi); + + sense_buf[12] = (failing_lba & 0xff000000) >> 24; + sense_buf[13] = (failing_lba & 0x00ff0000) >> 16; + sense_buf[14] = (failing_lba & 0x0000ff00) >> 8; + sense_buf[15] = failing_lba & 0x000000ff; + + failing_lba = le32_to_cpu(ioasa->u.vset.failing_lba_lo); + + sense_buf[16] = (failing_lba & 0xff000000) >> 24; + sense_buf[17] = (failing_lba & 0x00ff0000) >> 16; + sense_buf[18] = (failing_lba & 0x0000ff00) >> 8; + sense_buf[19] = failing_lba & 0x000000ff; + } else { + sense_buf[0] = 0x70; + sense_buf[2] = PMCRAID_IOASC_SENSE_KEY(ioasc); + sense_buf[12] = PMCRAID_IOASC_SENSE_CODE(ioasc); + sense_buf[13] = PMCRAID_IOASC_SENSE_QUAL(ioasc); + + if (ioasc == PMCRAID_IOASC_ME_READ_ERROR_NO_REALLOC) { + if (RES_IS_VSET(res->cfg_entry)) + failing_lba = + le32_to_cpu(ioasa->u. + vset.failing_lba_lo); + sense_buf[0] |= 0x80; + sense_buf[3] = (failing_lba >> 24) & 0xff; + sense_buf[4] = (failing_lba >> 16) & 0xff; + sense_buf[5] = (failing_lba >> 8) & 0xff; + sense_buf[6] = failing_lba & 0xff; + } + + sense_buf[7] = 6; /* additional length */ + } +} + +/** + * pmcraid_error_handler - Error response handlers for a SCSI op + * @cmd: pointer to pmcraid_cmd that has failed + * + * This function determines whether or not to initiate ERP on the affected + * device. This is called from a tasklet, which doesn't hold any locks. + * + * Return value: + * 0 it caller can complete the request, otherwise 1 where in error + * handler itself completes the request and returns the command block + * back to free-pool + */ +static int pmcraid_error_handler(struct pmcraid_cmd *cmd) +{ + struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; + struct pmcraid_resource_entry *res = scsi_cmd->device->hostdata; + struct pmcraid_instance *pinstance = cmd->drv_inst; + struct pmcraid_ioasa *ioasa = &cmd->ioa_cb->ioasa; + u32 ioasc = le32_to_cpu(ioasa->ioasc); + u32 masked_ioasc = ioasc & PMCRAID_IOASC_SENSE_MASK; + u32 sense_copied = 0; + + if (!res) { + pmcraid_info("resource pointer is NULL\n"); + return 0; + } + + /* If this was a SCSI read/write command keep count of errors */ + if (SCSI_CMD_TYPE(scsi_cmd->cmnd[0]) == SCSI_READ_CMD) + atomic_inc(&res->read_failures); + else if (SCSI_CMD_TYPE(scsi_cmd->cmnd[0]) == SCSI_WRITE_CMD) + atomic_inc(&res->write_failures); + + if (!RES_IS_GSCSI(res->cfg_entry) && + masked_ioasc != PMCRAID_IOASC_HW_DEVICE_BUS_STATUS_ERROR) { + pmcraid_frame_auto_sense(cmd); + } + + /* Log IOASC/IOASA information based on user settings */ + pmcraid_ioasc_logger(ioasc, cmd); + + switch (masked_ioasc) { + + case PMCRAID_IOASC_AC_TERMINATED_BY_HOST: + scsi_cmd->result |= (DID_ABORT << 16); + break; + + case PMCRAID_IOASC_IR_INVALID_RESOURCE_HANDLE: + case PMCRAID_IOASC_HW_CANNOT_COMMUNICATE: + scsi_cmd->result |= (DID_NO_CONNECT << 16); + break; + + case PMCRAID_IOASC_NR_SYNC_REQUIRED: + res->sync_reqd = 1; + scsi_cmd->result |= (DID_IMM_RETRY << 16); + break; + + case PMCRAID_IOASC_ME_READ_ERROR_NO_REALLOC: + scsi_cmd->result |= (DID_PASSTHROUGH << 16); + break; + + case PMCRAID_IOASC_UA_BUS_WAS_RESET: + case PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER: + if (!res->reset_progress) + scsi_report_bus_reset(pinstance->host, + scsi_cmd->device->channel); + scsi_cmd->result |= (DID_ERROR << 16); + break; + + case PMCRAID_IOASC_HW_DEVICE_BUS_STATUS_ERROR: + scsi_cmd->result |= PMCRAID_IOASC_SENSE_STATUS(ioasc); + res->sync_reqd = 1; + + /* if check_condition is not active return with error otherwise + * get/frame the sense buffer + */ + if (PMCRAID_IOASC_SENSE_STATUS(ioasc) != + SAM_STAT_CHECK_CONDITION && + PMCRAID_IOASC_SENSE_STATUS(ioasc) != SAM_STAT_ACA_ACTIVE) + return 0; + + /* If we have auto sense data as part of IOASA pass it to + * mid-layer + */ + if (ioasa->auto_sense_length != 0) { + short sense_len = ioasa->auto_sense_length; + int data_size = min_t(u16, le16_to_cpu(sense_len), + SCSI_SENSE_BUFFERSIZE); + + memcpy(scsi_cmd->sense_buffer, + ioasa->sense_data, + data_size); + sense_copied = 1; + } + + if (RES_IS_GSCSI(res->cfg_entry)) { + pmcraid_cancel_all(cmd, sense_copied); + } else if (sense_copied) { + pmcraid_erp_done(cmd); + return 0; + } else { + pmcraid_request_sense(cmd); + } + + return 1; + + case PMCRAID_IOASC_NR_INIT_CMD_REQUIRED: + break; + + default: + if (PMCRAID_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR) + scsi_cmd->result |= (DID_ERROR << 16); + break; + } + return 0; +} + +/** + * pmcraid_reset_device - device reset handler functions + * + * @scsi_cmd: scsi command struct + * @modifier: reset modifier indicating the reset sequence to be performed + * + * This function issues a device reset to the affected device. + * A LUN reset will be sent to the device first. If that does + * not work, a target reset will be sent. + * + * Return value: + * SUCCESS / FAILED + */ +static int pmcraid_reset_device( + struct scsi_cmnd *scsi_cmd, + unsigned long timeout, + u8 modifier +) +{ + struct pmcraid_cmd *cmd; + struct pmcraid_instance *pinstance; + struct pmcraid_resource_entry *res; + struct pmcraid_ioarcb *ioarcb; + unsigned long lock_flags; + u32 ioasc; + + pinstance = + (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; + res = scsi_cmd->device->hostdata; + + if (!res) { + pmcraid_err("reset_device: NULL resource pointer\n"); + return FAILED; + } + + /* If adapter is currently going through reset/reload, return failed. + * This will force the mid-layer to call _eh_bus/host reset, which + * will then go to sleep and wait for the reset to complete + */ + spin_lock_irqsave(pinstance->host->host_lock, lock_flags); + if (pinstance->ioa_reset_in_progress || + pinstance->ioa_state == IOA_STATE_DEAD) { + spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); + return FAILED; + } + + res->reset_progress = 1; + pmcraid_info("Resetting %s resource with addr %x\n", + ((modifier & RESET_DEVICE_LUN) ? "LUN" : + ((modifier & RESET_DEVICE_TARGET) ? "TARGET" : "BUS")), + le32_to_cpu(res->cfg_entry.resource_address)); + + /* get a free cmd block */ + cmd = pmcraid_get_free_cmd(pinstance); + + if (cmd == NULL) { + spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); + pmcraid_err("%s: no cmd blocks are available\n", __func__); + return FAILED; + } + + ioarcb = &cmd->ioa_cb->ioarcb; + ioarcb->resource_handle = res->cfg_entry.resource_handle; + ioarcb->request_type = REQ_TYPE_IOACMD; + ioarcb->cdb[0] = PMCRAID_RESET_DEVICE; + + /* Initialize reset modifier bits */ + if (modifier) + modifier = ENABLE_RESET_MODIFIER | modifier; + + ioarcb->cdb[1] = modifier; + + init_completion(&cmd->wait_for_completion); + cmd->completion_req = 1; + + pmcraid_info("cmd(CDB[0] = %x) for %x with index = %d\n", + cmd->ioa_cb->ioarcb.cdb[0], + le32_to_cpu(cmd->ioa_cb->ioarcb.resource_handle), + le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2); + + pmcraid_send_cmd(cmd, + pmcraid_internal_done, + timeout, + pmcraid_timeout_handler); + + spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); + + /* RESET_DEVICE command completes after all pending IOARCBs are + * completed. Once this command is completed, pmcraind_internal_done + * will wake up the 'completion' queue. + */ + wait_for_completion(&cmd->wait_for_completion); + + /* complete the command here itself and return the command block + * to free list + */ + pmcraid_return_cmd(cmd); + res->reset_progress = 0; + ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); + + /* set the return value based on the returned ioasc */ + return PMCRAID_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS; +} + +/** + * _pmcraid_io_done - helper for pmcraid_io_done function + * + * @cmd: pointer to pmcraid command struct + * @reslen: residual data length to be set in the ioasa + * @ioasc: ioasc either returned by IOA or set by driver itself. + * + * This function is invoked by pmcraid_io_done to complete mid-layer + * scsi ops. + * + * Return value: + * 0 if caller is required to return it to free_pool. Returns 1 if + * caller need not worry about freeing command block as error handler + * will take care of that. + */ + +static int _pmcraid_io_done(struct pmcraid_cmd *cmd, int reslen, int ioasc) +{ + struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; + int rc = 0; + + scsi_set_resid(scsi_cmd, reslen); + + pmcraid_info("response(%d) CDB[0] = %x ioasc:result: %x:%x\n", + le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2, + cmd->ioa_cb->ioarcb.cdb[0], + ioasc, scsi_cmd->result); + + if (PMCRAID_IOASC_SENSE_KEY(ioasc) != 0) + rc = pmcraid_error_handler(cmd); + + if (rc == 0) { + scsi_dma_unmap(scsi_cmd); + scsi_cmd->scsi_done(scsi_cmd); + } + + return rc; +} + +/** + * pmcraid_io_done - SCSI completion function + * + * @cmd: pointer to pmcraid command struct + * + * This function is invoked by tasklet/mid-layer error handler to completing + * the SCSI ops sent from mid-layer. + * + * Return value + * none + */ + +static void pmcraid_io_done(struct pmcraid_cmd *cmd) +{ + u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); + u32 reslen = le32_to_cpu(cmd->ioa_cb->ioasa.residual_data_length); + + if (_pmcraid_io_done(cmd, reslen, ioasc) == 0) + pmcraid_return_cmd(cmd); +} + +/** + * pmcraid_abort_cmd - Aborts a single IOARCB already submitted to IOA + * + * @cmd: command block of the command to be aborted + * + * Return Value: + * returns pointer to command structure used as cancelling cmd + */ +static struct pmcraid_cmd *pmcraid_abort_cmd(struct pmcraid_cmd *cmd) +{ + struct pmcraid_cmd *cancel_cmd; + struct pmcraid_instance *pinstance; + struct pmcraid_resource_entry *res; + + pinstance = (struct pmcraid_instance *)cmd->drv_inst; + res = cmd->scsi_cmd->device->hostdata; + + cancel_cmd = pmcraid_get_free_cmd(pinstance); + + if (cancel_cmd == NULL) { + pmcraid_err("%s: no cmd blocks are available\n", __func__); + return NULL; + } + + pmcraid_prepare_cancel_cmd(cancel_cmd, cmd); + + pmcraid_info("aborting command CDB[0]= %x with index = %d\n", + cmd->ioa_cb->ioarcb.cdb[0], + cmd->ioa_cb->ioarcb.response_handle >> 2); + + init_completion(&cancel_cmd->wait_for_completion); + cancel_cmd->completion_req = 1; + + pmcraid_info("command (%d) CDB[0] = %x for %x\n", + le32_to_cpu(cancel_cmd->ioa_cb->ioarcb.response_handle) >> 2, + cmd->ioa_cb->ioarcb.cdb[0], + le32_to_cpu(cancel_cmd->ioa_cb->ioarcb.resource_handle)); + + pmcraid_send_cmd(cancel_cmd, + pmcraid_internal_done, + PMCRAID_INTERNAL_TIMEOUT, + pmcraid_timeout_handler); + return cancel_cmd; +} + +/** + * pmcraid_abort_complete - Waits for ABORT TASK completion + * + * @cancel_cmd: command block use as cancelling command + * + * Return Value: + * returns SUCCESS if ABORT TASK has good completion + * otherwise FAILED + */ +static int pmcraid_abort_complete(struct pmcraid_cmd *cancel_cmd) +{ + struct pmcraid_resource_entry *res; + u32 ioasc; + + wait_for_completion(&cancel_cmd->wait_for_completion); + res = cancel_cmd->u.res; + cancel_cmd->u.res = NULL; + ioasc = le32_to_cpu(cancel_cmd->ioa_cb->ioasa.ioasc); + + /* If the abort task is not timed out we will get a Good completion + * as sense_key, otherwise we may get one the following responses + * due to subsquent bus reset or device reset. In case IOASC is + * NR_SYNC_REQUIRED, set sync_reqd flag for the corresponding resource + */ + if (ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET || + ioasc == PMCRAID_IOASC_NR_SYNC_REQUIRED) { + if (ioasc == PMCRAID_IOASC_NR_SYNC_REQUIRED) + res->sync_reqd = 1; + ioasc = 0; + } + + /* complete the command here itself */ + pmcraid_return_cmd(cancel_cmd); + return PMCRAID_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS; +} + +/** + * pmcraid_eh_abort_handler - entry point for aborting a single task on errors + * + * @scsi_cmd: scsi command struct given by mid-layer. When this is called + * mid-layer ensures that no other commands are queued. This + * never gets called under interrupt, but a separate eh thread. + * + * Return value: + * SUCCESS / FAILED + */ +static int pmcraid_eh_abort_handler(struct scsi_cmnd *scsi_cmd) +{ + struct pmcraid_instance *pinstance; + struct pmcraid_cmd *cmd; + struct pmcraid_resource_entry *res; + unsigned long host_lock_flags; + unsigned long pending_lock_flags; + struct pmcraid_cmd *cancel_cmd = NULL; + int cmd_found = 0; + int rc = FAILED; + + pinstance = + (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; + + dev_err(&pinstance->pdev->dev, + "I/O command timed out, aborting it.\n"); + + res = scsi_cmd->device->hostdata; + + if (res == NULL) + return rc; + + /* If we are currently going through reset/reload, return failed. + * This will force the mid-layer to eventually call + * pmcraid_eh_host_reset which will then go to sleep and wait for the + * reset to complete + */ + spin_lock_irqsave(pinstance->host->host_lock, host_lock_flags); + + if (pinstance->ioa_reset_in_progress || + pinstance->ioa_state == IOA_STATE_DEAD) { + spin_unlock_irqrestore(pinstance->host->host_lock, + host_lock_flags); + return rc; + } + + /* loop over pending cmd list to find cmd corresponding to this + * scsi_cmd. Note that this command might not have been completed + * already. locking: all pending commands are protected with + * pending_pool_lock. + */ + spin_lock_irqsave(&pinstance->pending_pool_lock, pending_lock_flags); + list_for_each_entry(cmd, &pinstance->pending_cmd_pool, free_list) { + + if (cmd->scsi_cmd == scsi_cmd) { + cmd_found = 1; + break; + } + } + + spin_unlock_irqrestore(&pinstance->pending_pool_lock, + pending_lock_flags); + + /* If the command to be aborted was given to IOA and still pending with + * it, send ABORT_TASK to abort this and wait for its completion + */ + if (cmd_found) + cancel_cmd = pmcraid_abort_cmd(cmd); + + spin_unlock_irqrestore(pinstance->host->host_lock, + host_lock_flags); + + if (cancel_cmd) { + cancel_cmd->u.res = cmd->scsi_cmd->device->hostdata; + rc = pmcraid_abort_complete(cancel_cmd); + } + + return cmd_found ? rc : SUCCESS; +} + +/** + * pmcraid_eh_xxxx_reset_handler - bus/target/device reset handler callbacks + * + * @scmd: pointer to scsi_cmd that was sent to the resource to be reset. + * + * All these routines invokve pmcraid_reset_device with appropriate parameters. + * Since these are called from mid-layer EH thread, no other IO will be queued + * to the resource being reset. However, control path (IOCTL) may be active so + * it is necessary to synchronize IOARRIN writes which pmcraid_reset_device + * takes care by locking/unlocking host_lock. + * + * Return value + * SUCCESS or FAILED + */ +static int pmcraid_eh_device_reset_handler(struct scsi_cmnd *scmd) +{ + pmcraid_err("Doing device reset due to an I/O command timeout.\n"); + return pmcraid_reset_device(scmd, + PMCRAID_INTERNAL_TIMEOUT, + RESET_DEVICE_LUN); +} + +static int pmcraid_eh_bus_reset_handler(struct scsi_cmnd *scmd) +{ + pmcraid_err("Doing bus reset due to an I/O command timeout.\n"); + return pmcraid_reset_device(scmd, + PMCRAID_RESET_BUS_TIMEOUT, + RESET_DEVICE_BUS); +} + +static int pmcraid_eh_target_reset_handler(struct scsi_cmnd *scmd) +{ + pmcraid_err("Doing target reset due to an I/O command timeout.\n"); + return pmcraid_reset_device(scmd, + PMCRAID_INTERNAL_TIMEOUT, + RESET_DEVICE_TARGET); +} + +/** + * pmcraid_eh_host_reset_handler - adapter reset handler callback + * + * @scmd: pointer to scsi_cmd that was sent to a resource of adapter + * + * Initiates adapter reset to bring it up to operational state + * + * Return value + * SUCCESS or FAILED + */ +static int pmcraid_eh_host_reset_handler(struct scsi_cmnd *scmd) +{ + unsigned long interval = 10000; /* 10 seconds interval */ + int waits = jiffies_to_msecs(PMCRAID_RESET_HOST_TIMEOUT) / interval; + struct pmcraid_instance *pinstance = + (struct pmcraid_instance *)(scmd->device->host->hostdata); + + + /* wait for an additional 150 seconds just in case firmware could come + * up and if it could complete all the pending commands excluding the + * two HCAM (CCN and LDN). + */ + while (waits--) { + if (atomic_read(&pinstance->outstanding_cmds) <= + PMCRAID_MAX_HCAM_CMD) + return SUCCESS; + msleep(interval); + } + + dev_err(&pinstance->pdev->dev, + "Adapter being reset due to an I/O command timeout.\n"); + return pmcraid_reset_bringup(pinstance) == 0 ? SUCCESS : FAILED; +} + +/** + * pmcraid_task_attributes - Translate SPI Q-Tags to task attributes + * @scsi_cmd: scsi command struct + * + * Return value + * number of tags or 0 if the task is not tagged + */ +static u8 pmcraid_task_attributes(struct scsi_cmnd *scsi_cmd) +{ + char tag[2]; + u8 rc = 0; + + if (scsi_populate_tag_msg(scsi_cmd, tag)) { + switch (tag[0]) { + case MSG_SIMPLE_TAG: + rc = TASK_TAG_SIMPLE; + break; + case MSG_HEAD_TAG: + rc = TASK_TAG_QUEUE_HEAD; + break; + case MSG_ORDERED_TAG: + rc = TASK_TAG_ORDERED; + break; + }; + } + + return rc; +} + + +/** + * pmcraid_init_ioadls - initializes IOADL related fields in IOARCB + * @cmd: pmcraid command struct + * @sgcount: count of scatter-gather elements + * + * Return value + * returns pointer pmcraid_ioadl_desc, initialized to point to internal + * or external IOADLs + */ +struct pmcraid_ioadl_desc * +pmcraid_init_ioadls(struct pmcraid_cmd *cmd, int sgcount) +{ + struct pmcraid_ioadl_desc *ioadl; + struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; + int ioadl_count = 0; + + if (ioarcb->add_cmd_param_length) + ioadl_count = DIV_ROUND_UP(ioarcb->add_cmd_param_length, 16); + ioarcb->ioadl_length = + sizeof(struct pmcraid_ioadl_desc) * sgcount; + + if ((sgcount + ioadl_count) > (ARRAY_SIZE(ioarcb->add_data.u.ioadl))) { + /* external ioadls start at offset 0x80 from control_block + * structure, re-using 24 out of 27 ioadls part of IOARCB. + * It is necessary to indicate to firmware that driver is + * using ioadls to be treated as external to IOARCB. + */ + ioarcb->ioarcb_bus_addr &= ~(0x1FULL); + ioarcb->ioadl_bus_addr = + cpu_to_le64((cmd->ioa_cb_bus_addr) + + offsetof(struct pmcraid_ioarcb, + add_data.u.ioadl[3])); + ioadl = &ioarcb->add_data.u.ioadl[3]; + } else { + ioarcb->ioadl_bus_addr = + cpu_to_le64((cmd->ioa_cb_bus_addr) + + offsetof(struct pmcraid_ioarcb, + add_data.u.ioadl[ioadl_count])); + + ioadl = &ioarcb->add_data.u.ioadl[ioadl_count]; + ioarcb->ioarcb_bus_addr |= + DIV_ROUND_CLOSEST(sgcount + ioadl_count, 8); + } + + return ioadl; +} + +/** + * pmcraid_build_ioadl - Build a scatter/gather list and map the buffer + * @pinstance: pointer to adapter instance structure + * @cmd: pmcraid command struct + * + * This function is invoked by queuecommand entry point while sending a command + * to firmware. This builds ioadl descriptors and sets up ioarcb fields. + * + * Return value: + * 0 on success or -1 on failure + */ +static int pmcraid_build_ioadl( + struct pmcraid_instance *pinstance, + struct pmcraid_cmd *cmd +) +{ + int i, nseg; + struct scatterlist *sglist; + + struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; + struct pmcraid_ioarcb *ioarcb = &(cmd->ioa_cb->ioarcb); + struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; + + u32 length = scsi_bufflen(scsi_cmd); + + if (!length) + return 0; + + nseg = scsi_dma_map(scsi_cmd); + + if (nseg < 0) { + dev_err(&pinstance->pdev->dev, "scsi_map_dma failed!\n"); + return -1; + } else if (nseg > PMCRAID_MAX_IOADLS) { + scsi_dma_unmap(scsi_cmd); + dev_err(&pinstance->pdev->dev, + "sg count is (%d) more than allowed!\n", nseg); + return -1; + } + + /* Initialize IOARCB data transfer length fields */ + if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) + ioarcb->request_flags0 |= TRANSFER_DIR_WRITE; + + ioarcb->request_flags0 |= NO_LINK_DESCS; + ioarcb->data_transfer_length = cpu_to_le32(length); + ioadl = pmcraid_init_ioadls(cmd, nseg); + + /* Initialize IOADL descriptor addresses */ + scsi_for_each_sg(scsi_cmd, sglist, nseg, i) { + ioadl[i].data_len = cpu_to_le32(sg_dma_len(sglist)); + ioadl[i].address = cpu_to_le64(sg_dma_address(sglist)); + ioadl[i].flags = 0; + } + /* setup last descriptor */ + ioadl[i - 1].flags = cpu_to_le32(IOADL_FLAGS_LAST_DESC); + + return 0; +} + +/** + * pmcraid_free_sglist - Frees an allocated SG buffer list + * @sglist: scatter/gather list pointer + * + * Free a DMA'able memory previously allocated with pmcraid_alloc_sglist + * + * Return value: + * none + */ +static void pmcraid_free_sglist(struct pmcraid_sglist *sglist) +{ + int i; + + for (i = 0; i < sglist->num_sg; i++) + __free_pages(sg_page(&(sglist->scatterlist[i])), + sglist->order); + + kfree(sglist); +} + +/** + * pmcraid_alloc_sglist - Allocates memory for a SG list + * @buflen: buffer length + * + * Allocates a DMA'able buffer in chunks and assembles a scatter/gather + * list. + * + * Return value + * pointer to sglist / NULL on failure + */ +static struct pmcraid_sglist *pmcraid_alloc_sglist(int buflen) +{ + struct pmcraid_sglist *sglist; + struct scatterlist *scatterlist; + struct page *page; + int num_elem, i, j; + int sg_size; + int order; + int bsize_elem; + + sg_size = buflen / (PMCRAID_MAX_IOADLS - 1); + order = (sg_size > 0) ? get_order(sg_size) : 0; + bsize_elem = PAGE_SIZE * (1 << order); + + /* Determine the actual number of sg entries needed */ + if (buflen % bsize_elem) + num_elem = (buflen / bsize_elem) + 1; + else + num_elem = buflen / bsize_elem; + + /* Allocate a scatter/gather list for the DMA */ + sglist = kzalloc(sizeof(struct pmcraid_sglist) + + (sizeof(struct scatterlist) * (num_elem - 1)), + GFP_KERNEL); + + if (sglist == NULL) + return NULL; + + scatterlist = sglist->scatterlist; + sg_init_table(scatterlist, num_elem); + sglist->order = order; + sglist->num_sg = num_elem; + sg_size = buflen; + + for (i = 0; i < num_elem; i++) { + page = alloc_pages(GFP_KERNEL|GFP_DMA, order); + if (!page) { + for (j = i - 1; j >= 0; j--) + __free_pages(sg_page(&scatterlist[j]), order); + kfree(sglist); + return NULL; + } + + sg_set_page(&scatterlist[i], page, + sg_size < bsize_elem ? sg_size : bsize_elem, 0); + sg_size -= bsize_elem; + } + + return sglist; +} + +/** + * pmcraid_copy_sglist - Copy user buffer to kernel buffer's SG list + * @sglist: scatter/gather list pointer + * @buffer: buffer pointer + * @len: buffer length + * @direction: data transfer direction + * + * Copy a user buffer into a buffer allocated by pmcraid_alloc_sglist + * + * Return value: + * 0 on success / other on failure + */ +static int pmcraid_copy_sglist( + struct pmcraid_sglist *sglist, + unsigned long buffer, + u32 len, + int direction +) +{ + struct scatterlist *scatterlist; + void *kaddr; + int bsize_elem; + int i; + int rc = 0; + + /* Determine the actual number of bytes per element */ + bsize_elem = PAGE_SIZE * (1 << sglist->order); + + scatterlist = sglist->scatterlist; + + for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) { + struct page *page = sg_page(&scatterlist[i]); + + kaddr = kmap(page); + if (direction == DMA_TO_DEVICE) + rc = __copy_from_user(kaddr, + (void *)buffer, + bsize_elem); + else + rc = __copy_to_user((void *)buffer, kaddr, bsize_elem); + + kunmap(page); + + if (rc) { + pmcraid_err("failed to copy user data into sg list\n"); + return -EFAULT; + } + + scatterlist[i].length = bsize_elem; + } + + if (len % bsize_elem) { + struct page *page = sg_page(&scatterlist[i]); + + kaddr = kmap(page); + + if (direction == DMA_TO_DEVICE) + rc = __copy_from_user(kaddr, + (void *)buffer, + len % bsize_elem); + else + rc = __copy_to_user((void *)buffer, + kaddr, + len % bsize_elem); + + kunmap(page); + + scatterlist[i].length = len % bsize_elem; + } + + if (rc) { + pmcraid_err("failed to copy user data into sg list\n"); + rc = -EFAULT; + } + + return rc; +} + +/** + * pmcraid_queuecommand - Queue a mid-layer request + * @scsi_cmd: scsi command struct + * @done: done function + * + * This function queues a request generated by the mid-layer. Midlayer calls + * this routine within host->lock. Some of the functions called by queuecommand + * would use cmd block queue locks (free_pool_lock and pending_pool_lock) + * + * Return value: + * 0 on success + * SCSI_MLQUEUE_DEVICE_BUSY if device is busy + * SCSI_MLQUEUE_HOST_BUSY if host is busy + */ +static int pmcraid_queuecommand( + struct scsi_cmnd *scsi_cmd, + void (*done) (struct scsi_cmnd *) +) +{ + struct pmcraid_instance *pinstance; + struct pmcraid_resource_entry *res; + struct pmcraid_ioarcb *ioarcb; + struct pmcraid_cmd *cmd; + int rc = 0; + + pinstance = + (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; + + scsi_cmd->scsi_done = done; + res = scsi_cmd->device->hostdata; + scsi_cmd->result = (DID_OK << 16); + + /* if adapter is marked as dead, set result to DID_NO_CONNECT complete + * the command + */ + if (pinstance->ioa_state == IOA_STATE_DEAD) { + pmcraid_info("IOA is dead, but queuecommand is scheduled\n"); + scsi_cmd->result = (DID_NO_CONNECT << 16); + scsi_cmd->scsi_done(scsi_cmd); + return 0; + } + + /* If IOA reset is in progress, can't queue the commands */ + if (pinstance->ioa_reset_in_progress) + return SCSI_MLQUEUE_HOST_BUSY; + + /* initialize the command and IOARCB to be sent to IOA */ + cmd = pmcraid_get_free_cmd(pinstance); + + if (cmd == NULL) { + pmcraid_err("free command block is not available\n"); + return SCSI_MLQUEUE_HOST_BUSY; + } + + cmd->scsi_cmd = scsi_cmd; + ioarcb = &(cmd->ioa_cb->ioarcb); + memcpy(ioarcb->cdb, scsi_cmd->cmnd, scsi_cmd->cmd_len); + ioarcb->resource_handle = res->cfg_entry.resource_handle; + ioarcb->request_type = REQ_TYPE_SCSI; + + cmd->cmd_done = pmcraid_io_done; + + if (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry)) { + if (scsi_cmd->underflow == 0) + ioarcb->request_flags0 |= INHIBIT_UL_CHECK; + + if (res->sync_reqd) { + ioarcb->request_flags0 |= SYNC_COMPLETE; + res->sync_reqd = 0; + } + + ioarcb->request_flags0 |= NO_LINK_DESCS; + ioarcb->request_flags1 |= pmcraid_task_attributes(scsi_cmd); + + if (RES_IS_GSCSI(res->cfg_entry)) + ioarcb->request_flags1 |= DELAY_AFTER_RESET; + } + + rc = pmcraid_build_ioadl(pinstance, cmd); + + pmcraid_info("command (%d) CDB[0] = %x for %x:%x:%x:%x\n", + le32_to_cpu(ioarcb->response_handle) >> 2, + scsi_cmd->cmnd[0], pinstance->host->unique_id, + RES_IS_VSET(res->cfg_entry) ? PMCRAID_VSET_BUS_ID : + PMCRAID_PHYS_BUS_ID, + RES_IS_VSET(res->cfg_entry) ? + res->cfg_entry.unique_flags1 : + RES_TARGET(res->cfg_entry.resource_address), + RES_LUN(res->cfg_entry.resource_address)); + + if (likely(rc == 0)) { + _pmcraid_fire_command(cmd); + } else { + pmcraid_err("queuecommand could not build ioadl\n"); + pmcraid_return_cmd(cmd); + rc = SCSI_MLQUEUE_HOST_BUSY; + } + + return rc; +} + +/** + * pmcraid_open -char node "open" entry, allowed only users with admin access + */ +static int pmcraid_chr_open(struct inode *inode, struct file *filep) +{ + struct pmcraid_instance *pinstance; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + /* Populate adapter instance * pointer for use by ioctl */ + pinstance = container_of(inode->i_cdev, struct pmcraid_instance, cdev); + filep->private_data = pinstance; + + return 0; +} + +/** + * pmcraid_release - char node "release" entry point + */ +static int pmcraid_chr_release(struct inode *inode, struct file *filep) +{ + struct pmcraid_instance *pinstance = + ((struct pmcraid_instance *)filep->private_data); + + filep->private_data = NULL; + fasync_helper(-1, filep, 0, &pinstance->aen_queue); + + return 0; +} + +/** + * pmcraid_fasync - Async notifier registration from applications + * + * This function adds the calling process to a driver global queue. When an + * event occurs, SIGIO will be sent to all processes in this queue. + */ +static int pmcraid_chr_fasync(int fd, struct file *filep, int mode) +{ + struct pmcraid_instance *pinstance; + int rc; + + pinstance = (struct pmcraid_instance *)filep->private_data; + mutex_lock(&pinstance->aen_queue_lock); + rc = fasync_helper(fd, filep, mode, &pinstance->aen_queue); + mutex_unlock(&pinstance->aen_queue_lock); + + return rc; +} + + +/** + * pmcraid_build_passthrough_ioadls - builds SG elements for passthrough + * commands sent over IOCTL interface + * + * @cmd : pointer to struct pmcraid_cmd + * @buflen : length of the request buffer + * @direction : data transfer direction + * + * Return value + * 0 on sucess, non-zero error code on failure + */ +static int pmcraid_build_passthrough_ioadls( + struct pmcraid_cmd *cmd, + int buflen, + int direction +) +{ + struct pmcraid_sglist *sglist = NULL; + struct scatterlist *sg = NULL; + struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; + struct pmcraid_ioadl_desc *ioadl; + int i; + + sglist = pmcraid_alloc_sglist(buflen); + + if (!sglist) { + pmcraid_err("can't allocate memory for passthrough SGls\n"); + return -ENOMEM; + } + + sglist->num_dma_sg = pci_map_sg(cmd->drv_inst->pdev, + sglist->scatterlist, + sglist->num_sg, direction); + + if (!sglist->num_dma_sg || sglist->num_dma_sg > PMCRAID_MAX_IOADLS) { + dev_err(&cmd->drv_inst->pdev->dev, + "Failed to map passthrough buffer!\n"); + pmcraid_free_sglist(sglist); + return -EIO; + } + + cmd->sglist = sglist; + ioarcb->request_flags0 |= NO_LINK_DESCS; + + ioadl = pmcraid_init_ioadls(cmd, sglist->num_dma_sg); + + /* Initialize IOADL descriptor addresses */ + for_each_sg(sglist->scatterlist, sg, sglist->num_dma_sg, i) { + ioadl[i].data_len = cpu_to_le32(sg_dma_len(sg)); + ioadl[i].address = cpu_to_le64(sg_dma_address(sg)); + ioadl[i].flags = 0; + } + + /* setup the last descriptor */ + ioadl[i - 1].flags = cpu_to_le32(IOADL_FLAGS_LAST_DESC); + + return 0; +} + + +/** + * pmcraid_release_passthrough_ioadls - release passthrough ioadls + * + * @cmd: pointer to struct pmcraid_cmd for which ioadls were allocated + * @buflen: size of the request buffer + * @direction: data transfer direction + * + * Return value + * 0 on sucess, non-zero error code on failure + */ +static void pmcraid_release_passthrough_ioadls( + struct pmcraid_cmd *cmd, + int buflen, + int direction +) +{ + struct pmcraid_sglist *sglist = cmd->sglist; + + if (buflen > 0) { + pci_unmap_sg(cmd->drv_inst->pdev, + sglist->scatterlist, + sglist->num_sg, + direction); + pmcraid_free_sglist(sglist); + cmd->sglist = NULL; + } +} + +/** + * pmcraid_ioctl_passthrough - handling passthrough IOCTL commands + * + * @pinstance: pointer to adapter instance structure + * @cmd: ioctl code + * @arg: pointer to pmcraid_passthrough_buffer user buffer + * + * Return value + * 0 on sucess, non-zero error code on failure + */ +static long pmcraid_ioctl_passthrough( + struct pmcraid_instance *pinstance, + unsigned int ioctl_cmd, + unsigned int buflen, + unsigned long arg +) +{ + struct pmcraid_passthrough_ioctl_buffer *buffer; + struct pmcraid_ioarcb *ioarcb; + struct pmcraid_cmd *cmd; + struct pmcraid_cmd *cancel_cmd; + unsigned long request_buffer; + unsigned long request_offset; + unsigned long lock_flags; + int request_size; + int buffer_size; + u8 access, direction; + int rc = 0; + + /* If IOA reset is in progress, wait 10 secs for reset to complete */ + if (pinstance->ioa_reset_in_progress) { + rc = wait_event_interruptible_timeout( + pinstance->reset_wait_q, + !pinstance->ioa_reset_in_progress, + msecs_to_jiffies(10000)); + + if (!rc) + return -ETIMEDOUT; + else if (rc < 0) + return -ERESTARTSYS; + } + + /* If adapter is not in operational state, return error */ + if (pinstance->ioa_state != IOA_STATE_OPERATIONAL) { + pmcraid_err("IOA is not operational\n"); + return -ENOTTY; + } + + buffer_size = sizeof(struct pmcraid_passthrough_ioctl_buffer); + buffer = kmalloc(buffer_size, GFP_KERNEL); + + if (!buffer) { + pmcraid_err("no memory for passthrough buffer\n"); + return -ENOMEM; + } + + request_offset = + offsetof(struct pmcraid_passthrough_ioctl_buffer, request_buffer); + + request_buffer = arg + request_offset; + + rc = __copy_from_user(buffer, + (struct pmcraid_passthrough_ioctl_buffer *) arg, + sizeof(struct pmcraid_passthrough_ioctl_buffer)); + if (rc) { + pmcraid_err("ioctl: can't copy passthrough buffer\n"); + rc = -EFAULT; + goto out_free_buffer; + } + + request_size = buffer->ioarcb.data_transfer_length; + + if (buffer->ioarcb.request_flags0 & TRANSFER_DIR_WRITE) { + access = VERIFY_READ; + direction = DMA_TO_DEVICE; + } else { + access = VERIFY_WRITE; + direction = DMA_FROM_DEVICE; + } + + if (request_size > 0) { + rc = access_ok(access, arg, request_offset + request_size); + + if (!rc) { + rc = -EFAULT; + goto out_free_buffer; + } + } + + /* check if we have any additional command parameters */ + if (buffer->ioarcb.add_cmd_param_length > PMCRAID_ADD_CMD_PARAM_LEN) { + rc = -EINVAL; + goto out_free_buffer; + } + + cmd = pmcraid_get_free_cmd(pinstance); + + if (!cmd) { + pmcraid_err("free command block is not available\n"); + rc = -ENOMEM; + goto out_free_buffer; + } + + cmd->scsi_cmd = NULL; + ioarcb = &(cmd->ioa_cb->ioarcb); + + /* Copy the user-provided IOARCB stuff field by field */ + ioarcb->resource_handle = buffer->ioarcb.resource_handle; + ioarcb->data_transfer_length = buffer->ioarcb.data_transfer_length; + ioarcb->cmd_timeout = buffer->ioarcb.cmd_timeout; + ioarcb->request_type = buffer->ioarcb.request_type; + ioarcb->request_flags0 = buffer->ioarcb.request_flags0; + ioarcb->request_flags1 = buffer->ioarcb.request_flags1; + memcpy(ioarcb->cdb, buffer->ioarcb.cdb, PMCRAID_MAX_CDB_LEN); + + if (buffer->ioarcb.add_cmd_param_length) { + ioarcb->add_cmd_param_length = + buffer->ioarcb.add_cmd_param_length; + ioarcb->add_cmd_param_offset = + buffer->ioarcb.add_cmd_param_offset; + memcpy(ioarcb->add_data.u.add_cmd_params, + buffer->ioarcb.add_data.u.add_cmd_params, + buffer->ioarcb.add_cmd_param_length); + } + + if (request_size) { + rc = pmcraid_build_passthrough_ioadls(cmd, + request_size, + direction); + if (rc) { + pmcraid_err("couldn't build passthrough ioadls\n"); + goto out_free_buffer; + } + } + + /* If data is being written into the device, copy the data from user + * buffers + */ + if (direction == DMA_TO_DEVICE && request_size > 0) { + rc = pmcraid_copy_sglist(cmd->sglist, + request_buffer, + request_size, + direction); + if (rc) { + pmcraid_err("failed to copy user buffer\n"); + goto out_free_sglist; + } + } + + /* passthrough ioctl is a blocking command so, put the user to sleep + * until timeout. Note that a timeout value of 0 means, do timeout. + */ + cmd->cmd_done = pmcraid_internal_done; + init_completion(&cmd->wait_for_completion); + cmd->completion_req = 1; + + pmcraid_info("command(%d) (CDB[0] = %x) for %x\n", + le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2, + cmd->ioa_cb->ioarcb.cdb[0], + le32_to_cpu(cmd->ioa_cb->ioarcb.resource_handle)); + + spin_lock_irqsave(pinstance->host->host_lock, lock_flags); + _pmcraid_fire_command(cmd); + spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); + + /* If command timeout is specified put caller to wait till that time, + * otherwise it would be blocking wait. If command gets timed out, it + * will be aborted. + */ + if (buffer->ioarcb.cmd_timeout == 0) { + wait_for_completion(&cmd->wait_for_completion); + } else if (!wait_for_completion_timeout( + &cmd->wait_for_completion, + msecs_to_jiffies(buffer->ioarcb.cmd_timeout * 1000))) { + + pmcraid_info("aborting cmd %d (CDB[0] = %x) due to timeout\n", + le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle >> 2), + cmd->ioa_cb->ioarcb.cdb[0]); + + rc = -ETIMEDOUT; + spin_lock_irqsave(pinstance->host->host_lock, lock_flags); + cancel_cmd = pmcraid_abort_cmd(cmd); + spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); + + if (cancel_cmd) { + wait_for_completion(&cancel_cmd->wait_for_completion); + pmcraid_return_cmd(cancel_cmd); + } + + goto out_free_sglist; + } + + /* If the command failed for any reason, copy entire IOASA buffer and + * return IOCTL success. If copying IOASA to user-buffer fails, return + * EFAULT + */ + if (le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)) { + + void *ioasa = + (void *)(arg + + offsetof(struct pmcraid_passthrough_ioctl_buffer, ioasa)); + + pmcraid_info("command failed with %x\n", + le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); + if (copy_to_user(ioasa, &cmd->ioa_cb->ioasa, + sizeof(struct pmcraid_ioasa))) { + pmcraid_err("failed to copy ioasa buffer to user\n"); + rc = -EFAULT; + } + } + /* If the data transfer was from device, copy the data onto user + * buffers + */ + else if (direction == DMA_FROM_DEVICE && request_size > 0) { + rc = pmcraid_copy_sglist(cmd->sglist, + request_buffer, + request_size, + direction); + if (rc) { + pmcraid_err("failed to copy user buffer\n"); + rc = -EFAULT; + } + } + +out_free_sglist: + pmcraid_release_passthrough_ioadls(cmd, request_size, direction); + pmcraid_return_cmd(cmd); + +out_free_buffer: + kfree(buffer); + + return rc; +} + + + + +/** + * pmcraid_ioctl_driver - ioctl handler for commands handled by driver itself + * + * @pinstance: pointer to adapter instance structure + * @cmd: ioctl command passed in + * @buflen: length of user_buffer + * @user_buffer: user buffer pointer + * + * Return Value + * 0 in case of success, otherwise appropriate error code + */ +static long pmcraid_ioctl_driver( + struct pmcraid_instance *pinstance, + unsigned int cmd, + unsigned int buflen, + void __user *user_buffer +) +{ + int rc = -ENOSYS; + + if (!access_ok(VERIFY_READ, user_buffer, _IOC_SIZE(cmd))) { + pmcraid_err("ioctl_driver: access fault in request buffer \n"); + return -EFAULT; + } + + switch (cmd) { + case PMCRAID_IOCTL_RESET_ADAPTER: + pmcraid_reset_bringup(pinstance); + rc = 0; + break; + + default: + break; + } + + return rc; +} + +/** + * pmcraid_check_ioctl_buffer - check for proper access to user buffer + * + * @cmd: ioctl command + * @arg: user buffer + * @hdr: pointer to kernel memory for pmcraid_ioctl_header + * + * Return Value + * negetive error code if there are access issues, otherwise zero. + * Upon success, returns ioctl header copied out of user buffer. + */ + +static int pmcraid_check_ioctl_buffer( + int cmd, + void __user *arg, + struct pmcraid_ioctl_header *hdr +) +{ + int rc = 0; + int access = VERIFY_READ; + + if (copy_from_user(hdr, arg, sizeof(struct pmcraid_ioctl_header))) { + pmcraid_err("couldn't copy ioctl header from user buffer\n"); + return -EFAULT; + } + + /* check for valid driver signature */ + rc = memcmp(hdr->signature, + PMCRAID_IOCTL_SIGNATURE, + sizeof(hdr->signature)); + if (rc) { + pmcraid_err("signature verification failed\n"); + return -EINVAL; + } + + /* buffer length can't be negetive */ + if (hdr->buffer_length < 0) { + pmcraid_err("ioctl: invalid buffer length specified\n"); + return -EINVAL; + } + + /* check for appropriate buffer access */ + if ((_IOC_DIR(cmd) & _IOC_READ) == _IOC_READ) + access = VERIFY_WRITE; + + rc = access_ok(access, + (arg + sizeof(struct pmcraid_ioctl_header)), + hdr->buffer_length); + if (!rc) { + pmcraid_err("access failed for user buffer of size %d\n", + hdr->buffer_length); + return -EFAULT; + } + + return 0; +} + +/** + * pmcraid_ioctl - char node ioctl entry point + */ +static long pmcraid_chr_ioctl( + struct file *filep, + unsigned int cmd, + unsigned long arg +) +{ + struct pmcraid_instance *pinstance = NULL; + struct pmcraid_ioctl_header *hdr = NULL; + int retval = -ENOTTY; + + hdr = kmalloc(GFP_KERNEL, sizeof(struct pmcraid_ioctl_header)); + + if (!hdr) { + pmcraid_err("faile to allocate memory for ioctl header\n"); + return -ENOMEM; + } + + retval = pmcraid_check_ioctl_buffer(cmd, (void *)arg, hdr); + + if (retval) { + pmcraid_info("chr_ioctl: header check failed\n"); + kfree(hdr); + return retval; + } + + pinstance = (struct pmcraid_instance *)filep->private_data; + + if (!pinstance) { + pmcraid_info("adapter instance is not found\n"); + kfree(hdr); + return -ENOTTY; + } + + switch (_IOC_TYPE(cmd)) { + + case PMCRAID_PASSTHROUGH_IOCTL: + /* If ioctl code is to download microcode, we need to block + * mid-layer requests. + */ + if (cmd == PMCRAID_IOCTL_DOWNLOAD_MICROCODE) + scsi_block_requests(pinstance->host); + + retval = pmcraid_ioctl_passthrough(pinstance, + cmd, + hdr->buffer_length, + arg); + + if (cmd == PMCRAID_IOCTL_DOWNLOAD_MICROCODE) + scsi_unblock_requests(pinstance->host); + break; + + case PMCRAID_DRIVER_IOCTL: + arg += sizeof(struct pmcraid_ioctl_header); + retval = pmcraid_ioctl_driver(pinstance, + cmd, + hdr->buffer_length, + (void __user *)arg); + break; + + default: + retval = -ENOTTY; + break; + } + + kfree(hdr); + + return retval; +} + +/** + * File operations structure for management interface + */ +static const struct file_operations pmcraid_fops = { + .owner = THIS_MODULE, + .open = pmcraid_chr_open, + .release = pmcraid_chr_release, + .fasync = pmcraid_chr_fasync, + .unlocked_ioctl = pmcraid_chr_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = pmcraid_chr_ioctl, +#endif +}; + + + + +/** + * pmcraid_show_log_level - Display adapter's error logging level + * @dev: class device struct + * @buf: buffer + * + * Return value: + * number of bytes printed to buffer + */ +static ssize_t pmcraid_show_log_level( + struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct pmcraid_instance *pinstance = + (struct pmcraid_instance *)shost->hostdata; + return snprintf(buf, PAGE_SIZE, "%d\n", pinstance->current_log_level); +} + +/** + * pmcraid_store_log_level - Change the adapter's error logging level + * @dev: class device struct + * @buf: buffer + * @count: not used + * + * Return value: + * number of bytes printed to buffer + */ +static ssize_t pmcraid_store_log_level( + struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count +) +{ + struct Scsi_Host *shost; + struct pmcraid_instance *pinstance; + unsigned long val; + + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + /* log-level should be from 0 to 2 */ + if (val > 2) + return -EINVAL; + + shost = class_to_shost(dev); + pinstance = (struct pmcraid_instance *)shost->hostdata; + pinstance->current_log_level = val; + + return strlen(buf); +} + +static struct device_attribute pmcraid_log_level_attr = { + .attr = { + .name = "log_level", + .mode = S_IRUGO | S_IWUSR, + }, + .show = pmcraid_show_log_level, + .store = pmcraid_store_log_level, +}; + +/** + * pmcraid_show_drv_version - Display driver version + * @dev: class device struct + * @buf: buffer + * + * Return value: + * number of bytes printed to buffer + */ +static ssize_t pmcraid_show_drv_version( + struct device *dev, + struct device_attribute *attr, + char *buf +) +{ + return snprintf(buf, PAGE_SIZE, "version: %s, build date: %s\n", + PMCRAID_DRIVER_VERSION, PMCRAID_DRIVER_DATE); +} + +static struct device_attribute pmcraid_driver_version_attr = { + .attr = { + .name = "drv_version", + .mode = S_IRUGO, + }, + .show = pmcraid_show_drv_version, +}; + +/** + * pmcraid_show_io_adapter_id - Display driver assigned adapter id + * @dev: class device struct + * @buf: buffer + * + * Return value: + * number of bytes printed to buffer + */ +static ssize_t pmcraid_show_adapter_id( + struct device *dev, + struct device_attribute *attr, + char *buf +) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct pmcraid_instance *pinstance = + (struct pmcraid_instance *)shost->hostdata; + u32 adapter_id = (pinstance->pdev->bus->number << 8) | + pinstance->pdev->devfn; + u32 aen_group = pmcraid_event_family.id; + + return snprintf(buf, PAGE_SIZE, + "adapter id: %d\nminor: %d\naen group: %d\n", + adapter_id, MINOR(pinstance->cdev.dev), aen_group); +} + +static struct device_attribute pmcraid_adapter_id_attr = { + .attr = { + .name = "adapter_id", + .mode = S_IRUGO | S_IWUSR, + }, + .show = pmcraid_show_adapter_id, +}; + +static struct device_attribute *pmcraid_host_attrs[] = { + &pmcraid_log_level_attr, + &pmcraid_driver_version_attr, + &pmcraid_adapter_id_attr, + NULL, +}; + + +/* host template structure for pmcraid driver */ +static struct scsi_host_template pmcraid_host_template = { + .module = THIS_MODULE, + .name = PMCRAID_DRIVER_NAME, + .queuecommand = pmcraid_queuecommand, + .eh_abort_handler = pmcraid_eh_abort_handler, + .eh_bus_reset_handler = pmcraid_eh_bus_reset_handler, + .eh_target_reset_handler = pmcraid_eh_target_reset_handler, + .eh_device_reset_handler = pmcraid_eh_device_reset_handler, + .eh_host_reset_handler = pmcraid_eh_host_reset_handler, + + .slave_alloc = pmcraid_slave_alloc, + .slave_configure = pmcraid_slave_configure, + .slave_destroy = pmcraid_slave_destroy, + .change_queue_depth = pmcraid_change_queue_depth, + .change_queue_type = pmcraid_change_queue_type, + .can_queue = PMCRAID_MAX_IO_CMD, + .this_id = -1, + .sg_tablesize = PMCRAID_MAX_IOADLS, + .max_sectors = PMCRAID_IOA_MAX_SECTORS, + .cmd_per_lun = PMCRAID_MAX_CMD_PER_LUN, + .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = pmcraid_host_attrs, + .proc_name = PMCRAID_DRIVER_NAME +}; + +/** + * pmcraid_isr_common - Common interrupt handler routine + * + * @pinstance: pointer to adapter instance + * @intrs: active interrupts (contents of ioa_host_interrupt register) + * @hrrq_id: Host RRQ index + * + * Return Value + * none + */ +static void pmcraid_isr_common( + struct pmcraid_instance *pinstance, + u32 intrs, + int hrrq_id +) +{ + u32 intrs_clear = + (intrs & INTRS_CRITICAL_OP_IN_PROGRESS) ? intrs + : INTRS_HRRQ_VALID; + iowrite32(intrs_clear, + pinstance->int_regs.ioa_host_interrupt_clr_reg); + intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); + + /* hrrq valid bit was set, schedule tasklet to handle the response */ + if (intrs_clear == INTRS_HRRQ_VALID) + tasklet_schedule(&(pinstance->isr_tasklet[hrrq_id])); +} + +/** + * pmcraid_isr - implements interrupt handling routine + * + * @irq: interrupt vector number + * @dev_id: pointer hrrq_vector + * + * Return Value + * IRQ_HANDLED if interrupt is handled or IRQ_NONE if ignored + */ +static irqreturn_t pmcraid_isr(int irq, void *dev_id) +{ + struct pmcraid_isr_param *hrrq_vector; + struct pmcraid_instance *pinstance; + unsigned long lock_flags; + u32 intrs; + + /* In case of legacy interrupt mode where interrupts are shared across + * isrs, it may be possible that the current interrupt is not from IOA + */ + if (!dev_id) { + printk(KERN_INFO "%s(): NULL host pointer\n", __func__); + return IRQ_NONE; + } + + hrrq_vector = (struct pmcraid_isr_param *)dev_id; + pinstance = hrrq_vector->drv_inst; + + /* Acquire the lock (currently host_lock) while processing interrupts. + * This interval is small as most of the response processing is done by + * tasklet without the lock. + */ + spin_lock_irqsave(pinstance->host->host_lock, lock_flags); + intrs = pmcraid_read_interrupts(pinstance); + + if (unlikely((intrs & PMCRAID_PCI_INTERRUPTS) == 0)) { + spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); + return IRQ_NONE; + } + + /* Any error interrupts including unit_check, initiate IOA reset. + * In case of unit check indicate to reset_sequence that IOA unit + * checked and prepare for a dump during reset sequence + */ + if (intrs & PMCRAID_ERROR_INTERRUPTS) { + + if (intrs & INTRS_IOA_UNIT_CHECK) + pinstance->ioa_unit_check = 1; + + iowrite32(intrs, + pinstance->int_regs.ioa_host_interrupt_clr_reg); + pmcraid_err("ISR: error interrupts: %x initiating reset\n", + intrs); + intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); + pmcraid_initiate_reset(pinstance); + } else { + pmcraid_isr_common(pinstance, intrs, hrrq_vector->hrrq_id); + } + + spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); + + return IRQ_HANDLED; +} + + +/** + * pmcraid_worker_function - worker thread function + * + * @workp: pointer to struct work queue + * + * Return Value + * None + */ + +static void pmcraid_worker_function(struct work_struct *workp) +{ + struct pmcraid_instance *pinstance; + struct pmcraid_resource_entry *res; + struct pmcraid_resource_entry *temp; + struct scsi_device *sdev; + unsigned long lock_flags; + unsigned long host_lock_flags; + u8 bus, target, lun; + + pinstance = container_of(workp, struct pmcraid_instance, worker_q); + /* add resources only after host is added into system */ + if (!atomic_read(&pinstance->expose_resources)) + return; + + spin_lock_irqsave(&pinstance->resource_lock, lock_flags); + list_for_each_entry_safe(res, temp, &pinstance->used_res_q, queue) { + + if (res->change_detected == RES_CHANGE_DEL && res->scsi_dev) { + sdev = res->scsi_dev; + + /* host_lock must be held before calling + * scsi_device_get + */ + spin_lock_irqsave(pinstance->host->host_lock, + host_lock_flags); + if (!scsi_device_get(sdev)) { + spin_unlock_irqrestore( + pinstance->host->host_lock, + host_lock_flags); + pmcraid_info("deleting %x from midlayer\n", + res->cfg_entry.resource_address); + list_move_tail(&res->queue, + &pinstance->free_res_q); + spin_unlock_irqrestore( + &pinstance->resource_lock, + lock_flags); + scsi_remove_device(sdev); + scsi_device_put(sdev); + spin_lock_irqsave(&pinstance->resource_lock, + lock_flags); + res->change_detected = 0; + } else { + spin_unlock_irqrestore( + pinstance->host->host_lock, + host_lock_flags); + } + } + } + + list_for_each_entry(res, &pinstance->used_res_q, queue) { + + if (res->change_detected == RES_CHANGE_ADD) { + + if (!pmcraid_expose_resource(&res->cfg_entry)) + continue; + + if (RES_IS_VSET(res->cfg_entry)) { + bus = PMCRAID_VSET_BUS_ID; + target = res->cfg_entry.unique_flags1; + lun = PMCRAID_VSET_LUN_ID; + } else { + bus = PMCRAID_PHYS_BUS_ID; + target = + RES_TARGET( + res->cfg_entry.resource_address); + lun = RES_LUN(res->cfg_entry.resource_address); + } + + res->change_detected = 0; + spin_unlock_irqrestore(&pinstance->resource_lock, + lock_flags); + scsi_add_device(pinstance->host, bus, target, lun); + spin_lock_irqsave(&pinstance->resource_lock, + lock_flags); + } + } + + spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); +} + +/** + * pmcraid_tasklet_function - Tasklet function + * + * @instance: pointer to msix param structure + * + * Return Value + * None + */ +void pmcraid_tasklet_function(unsigned long instance) +{ + struct pmcraid_isr_param *hrrq_vector; + struct pmcraid_instance *pinstance; + unsigned long hrrq_lock_flags; + unsigned long pending_lock_flags; + unsigned long host_lock_flags; + spinlock_t *lockp; /* hrrq buffer lock */ + int id; + u32 intrs; + __le32 resp; + + hrrq_vector = (struct pmcraid_isr_param *)instance; + pinstance = hrrq_vector->drv_inst; + id = hrrq_vector->hrrq_id; + lockp = &(pinstance->hrrq_lock[id]); + intrs = pmcraid_read_interrupts(pinstance); + + /* If interrupts was as part of the ioa initialization, clear and mask + * it. Delete the timer and wakeup the reset engine to proceed with + * reset sequence + */ + if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) { + iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, + pinstance->int_regs.ioa_host_interrupt_mask_reg); + iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, + pinstance->int_regs.ioa_host_interrupt_clr_reg); + + if (pinstance->reset_cmd != NULL) { + del_timer(&pinstance->reset_cmd->timer); + spin_lock_irqsave(pinstance->host->host_lock, + host_lock_flags); + pinstance->reset_cmd->cmd_done(pinstance->reset_cmd); + spin_unlock_irqrestore(pinstance->host->host_lock, + host_lock_flags); + } + return; + } + + /* loop through each of the commands responded by IOA. Each HRRQ buf is + * protected by its own lock. Traversals must be done within this lock + * as there may be multiple tasklets running on multiple CPUs. Note + * that the lock is held just for picking up the response handle and + * manipulating hrrq_curr/toggle_bit values. + */ + spin_lock_irqsave(lockp, hrrq_lock_flags); + + resp = le32_to_cpu(*(pinstance->hrrq_curr[id])); + + while ((resp & HRRQ_TOGGLE_BIT) == + pinstance->host_toggle_bit[id]) { + + int cmd_index = resp >> 2; + struct pmcraid_cmd *cmd = NULL; + + if (cmd_index < PMCRAID_MAX_CMD) { + cmd = pinstance->cmd_list[cmd_index]; + } else { + /* In case of invalid response handle, initiate IOA + * reset sequence. + */ + spin_unlock_irqrestore(lockp, hrrq_lock_flags); + + pmcraid_err("Invalid response %d initiating reset\n", + cmd_index); + + spin_lock_irqsave(pinstance->host->host_lock, + host_lock_flags); + pmcraid_initiate_reset(pinstance); + spin_unlock_irqrestore(pinstance->host->host_lock, + host_lock_flags); + + spin_lock_irqsave(lockp, hrrq_lock_flags); + break; + } + + if (pinstance->hrrq_curr[id] < pinstance->hrrq_end[id]) { + pinstance->hrrq_curr[id]++; + } else { + pinstance->hrrq_curr[id] = pinstance->hrrq_start[id]; + pinstance->host_toggle_bit[id] ^= 1u; + } + + spin_unlock_irqrestore(lockp, hrrq_lock_flags); + + spin_lock_irqsave(&pinstance->pending_pool_lock, + pending_lock_flags); + list_del(&cmd->free_list); + spin_unlock_irqrestore(&pinstance->pending_pool_lock, + pending_lock_flags); + del_timer(&cmd->timer); + atomic_dec(&pinstance->outstanding_cmds); + + if (cmd->cmd_done == pmcraid_ioa_reset) { + spin_lock_irqsave(pinstance->host->host_lock, + host_lock_flags); + cmd->cmd_done(cmd); + spin_unlock_irqrestore(pinstance->host->host_lock, + host_lock_flags); + } else if (cmd->cmd_done != NULL) { + cmd->cmd_done(cmd); + } + /* loop over until we are done with all responses */ + spin_lock_irqsave(lockp, hrrq_lock_flags); + resp = le32_to_cpu(*(pinstance->hrrq_curr[id])); + } + + spin_unlock_irqrestore(lockp, hrrq_lock_flags); +} + +/** + * pmcraid_unregister_interrupt_handler - de-register interrupts handlers + * @pinstance: pointer to adapter instance structure + * + * This routine un-registers registered interrupt handler and + * also frees irqs/vectors. + * + * Retun Value + * None + */ +static +void pmcraid_unregister_interrupt_handler(struct pmcraid_instance *pinstance) +{ + free_irq(pinstance->pdev->irq, &(pinstance->hrrq_vector[0])); +} + +/** + * pmcraid_register_interrupt_handler - registers interrupt handler + * @pinstance: pointer to per-adapter instance structure + * + * Return Value + * 0 on success, non-zero error code otherwise. + */ +static int +pmcraid_register_interrupt_handler(struct pmcraid_instance *pinstance) +{ + struct pci_dev *pdev = pinstance->pdev; + + pinstance->hrrq_vector[0].hrrq_id = 0; + pinstance->hrrq_vector[0].drv_inst = pinstance; + pinstance->hrrq_vector[0].vector = 0; + pinstance->num_hrrq = 1; + return request_irq(pdev->irq, pmcraid_isr, IRQF_SHARED, + PMCRAID_DRIVER_NAME, &pinstance->hrrq_vector[0]); +} + +/** + * pmcraid_release_cmd_blocks - release buufers allocated for command blocks + * @pinstance: per adapter instance structure pointer + * @max_index: number of buffer blocks to release + * + * Return Value + * None + */ +static void +pmcraid_release_cmd_blocks(struct pmcraid_instance *pinstance, int max_index) +{ + int i; + for (i = 0; i < max_index; i++) { + kmem_cache_free(pinstance->cmd_cachep, pinstance->cmd_list[i]); + pinstance->cmd_list[i] = NULL; + } + kmem_cache_destroy(pinstance->cmd_cachep); + pinstance->cmd_cachep = NULL; +} + +/** + * pmcraid_release_control_blocks - releases buffers alloced for control blocks + * @pinstance: pointer to per adapter instance structure + * @max_index: number of buffers (from 0 onwards) to release + * + * This function assumes that the command blocks for which control blocks are + * linked are not released. + * + * Return Value + * None + */ +static void +pmcraid_release_control_blocks( + struct pmcraid_instance *pinstance, + int max_index +) +{ + int i; + + if (pinstance->control_pool == NULL) + return; + + for (i = 0; i < max_index; i++) { + pci_pool_free(pinstance->control_pool, + pinstance->cmd_list[i]->ioa_cb, + pinstance->cmd_list[i]->ioa_cb_bus_addr); + pinstance->cmd_list[i]->ioa_cb = NULL; + pinstance->cmd_list[i]->ioa_cb_bus_addr = 0; + } + pci_pool_destroy(pinstance->control_pool); + pinstance->control_pool = NULL; +} + +/** + * pmcraid_allocate_cmd_blocks - allocate memory for cmd block structures + * @pinstance - pointer to per adapter instance structure + * + * Allocates memory for command blocks using kernel slab allocator. + * + * Return Value + * 0 in case of success; -ENOMEM in case of failure + */ +static int __devinit +pmcraid_allocate_cmd_blocks(struct pmcraid_instance *pinstance) +{ + int i; + + sprintf(pinstance->cmd_pool_name, "pmcraid_cmd_pool_%d", + pinstance->host->unique_id); + + + pinstance->cmd_cachep = kmem_cache_create( + pinstance->cmd_pool_name, + sizeof(struct pmcraid_cmd), 0, + SLAB_HWCACHE_ALIGN, NULL); + if (!pinstance->cmd_cachep) + return -ENOMEM; + + for (i = 0; i < PMCRAID_MAX_CMD; i++) { + pinstance->cmd_list[i] = + kmem_cache_alloc(pinstance->cmd_cachep, GFP_KERNEL); + if (!pinstance->cmd_list[i]) { + pmcraid_release_cmd_blocks(pinstance, i); + return -ENOMEM; + } + } + return 0; +} + +/** + * pmcraid_allocate_control_blocks - allocates memory control blocks + * @pinstance : pointer to per adapter instance structure + * + * This function allocates PCI memory for DMAable buffers like IOARCB, IOADLs + * and IOASAs. This is called after command blocks are already allocated. + * + * Return Value + * 0 in case it can allocate all control blocks, otherwise -ENOMEM + */ +static int __devinit +pmcraid_allocate_control_blocks(struct pmcraid_instance *pinstance) +{ + int i; + + sprintf(pinstance->ctl_pool_name, "pmcraid_control_pool_%d", + pinstance->host->unique_id); + + pinstance->control_pool = + pci_pool_create(pinstance->ctl_pool_name, + pinstance->pdev, + sizeof(struct pmcraid_control_block), + PMCRAID_IOARCB_ALIGNMENT, 0); + + if (!pinstance->control_pool) + return -ENOMEM; + + for (i = 0; i < PMCRAID_MAX_CMD; i++) { + pinstance->cmd_list[i]->ioa_cb = + pci_pool_alloc( + pinstance->control_pool, + GFP_KERNEL, + &(pinstance->cmd_list[i]->ioa_cb_bus_addr)); + + if (!pinstance->cmd_list[i]->ioa_cb) { + pmcraid_release_control_blocks(pinstance, i); + return -ENOMEM; + } + memset(pinstance->cmd_list[i]->ioa_cb, 0, + sizeof(struct pmcraid_control_block)); + } + return 0; +} + +/** + * pmcraid_release_host_rrqs - release memory allocated for hrrq buffer(s) + * @pinstance: pointer to per adapter instance structure + * @maxindex: size of hrrq buffer pointer array + * + * Return Value + * None + */ +static void +pmcraid_release_host_rrqs(struct pmcraid_instance *pinstance, int maxindex) +{ + int i; + for (i = 0; i < maxindex; i++) { + + pci_free_consistent(pinstance->pdev, + HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD, + pinstance->hrrq_start[i], + pinstance->hrrq_start_bus_addr[i]); + + /* reset pointers and toggle bit to zeros */ + pinstance->hrrq_start[i] = NULL; + pinstance->hrrq_start_bus_addr[i] = 0; + pinstance->host_toggle_bit[i] = 0; + } +} + +/** + * pmcraid_allocate_host_rrqs - Allocate and initialize host RRQ buffers + * @pinstance: pointer to per adapter instance structure + * + * Return value + * 0 hrrq buffers are allocated, -ENOMEM otherwise. + */ +static int __devinit +pmcraid_allocate_host_rrqs(struct pmcraid_instance *pinstance) +{ + int i; + int buf_count = PMCRAID_MAX_CMD / pinstance->num_hrrq; + + for (i = 0; i < pinstance->num_hrrq; i++) { + int buffer_size = HRRQ_ENTRY_SIZE * buf_count; + + pinstance->hrrq_start[i] = + pci_alloc_consistent( + pinstance->pdev, + buffer_size, + &(pinstance->hrrq_start_bus_addr[i])); + + if (pinstance->hrrq_start[i] == 0) { + pmcraid_err("could not allocate host rrq: %d\n", i); + pmcraid_release_host_rrqs(pinstance, i); + return -ENOMEM; + } + + memset(pinstance->hrrq_start[i], 0, buffer_size); + pinstance->hrrq_curr[i] = pinstance->hrrq_start[i]; + pinstance->hrrq_end[i] = + pinstance->hrrq_start[i] + buf_count - 1; + pinstance->host_toggle_bit[i] = 1; + spin_lock_init(&pinstance->hrrq_lock[i]); + } + return 0; +} + +/** + * pmcraid_release_hcams - release HCAM buffers + * + * @pinstance: pointer to per adapter instance structure + * + * Return value + * none + */ +static void pmcraid_release_hcams(struct pmcraid_instance *pinstance) +{ + if (pinstance->ccn.msg != NULL) { + pci_free_consistent(pinstance->pdev, + PMCRAID_AEN_HDR_SIZE + + sizeof(struct pmcraid_hcam_ccn), + pinstance->ccn.msg, + pinstance->ccn.baddr); + + pinstance->ccn.msg = NULL; + pinstance->ccn.hcam = NULL; + pinstance->ccn.baddr = 0; + } + + if (pinstance->ldn.msg != NULL) { + pci_free_consistent(pinstance->pdev, + PMCRAID_AEN_HDR_SIZE + + sizeof(struct pmcraid_hcam_ldn), + pinstance->ldn.msg, + pinstance->ldn.baddr); + + pinstance->ldn.msg = NULL; + pinstance->ldn.hcam = NULL; + pinstance->ldn.baddr = 0; + } +} + +/** + * pmcraid_allocate_hcams - allocates HCAM buffers + * @pinstance : pointer to per adapter instance structure + * + * Return Value: + * 0 in case of successful allocation, non-zero otherwise + */ +static int pmcraid_allocate_hcams(struct pmcraid_instance *pinstance) +{ + pinstance->ccn.msg = pci_alloc_consistent( + pinstance->pdev, + PMCRAID_AEN_HDR_SIZE + + sizeof(struct pmcraid_hcam_ccn), + &(pinstance->ccn.baddr)); + + pinstance->ldn.msg = pci_alloc_consistent( + pinstance->pdev, + PMCRAID_AEN_HDR_SIZE + + sizeof(struct pmcraid_hcam_ldn), + &(pinstance->ldn.baddr)); + + if (pinstance->ldn.msg == NULL || pinstance->ccn.msg == NULL) { + pmcraid_release_hcams(pinstance); + } else { + pinstance->ccn.hcam = + (void *)pinstance->ccn.msg + PMCRAID_AEN_HDR_SIZE; + pinstance->ldn.hcam = + (void *)pinstance->ldn.msg + PMCRAID_AEN_HDR_SIZE; + + atomic_set(&pinstance->ccn.ignore, 0); + atomic_set(&pinstance->ldn.ignore, 0); + } + + return (pinstance->ldn.msg == NULL) ? -ENOMEM : 0; +} + +/** + * pmcraid_release_config_buffers - release config.table buffers + * @pinstance: pointer to per adapter instance structure + * + * Return Value + * none + */ +static void pmcraid_release_config_buffers(struct pmcraid_instance *pinstance) +{ + if (pinstance->cfg_table != NULL && + pinstance->cfg_table_bus_addr != 0) { + pci_free_consistent(pinstance->pdev, + sizeof(struct pmcraid_config_table), + pinstance->cfg_table, + pinstance->cfg_table_bus_addr); + pinstance->cfg_table = NULL; + pinstance->cfg_table_bus_addr = 0; + } + + if (pinstance->res_entries != NULL) { + int i; + + for (i = 0; i < PMCRAID_MAX_RESOURCES; i++) + list_del(&pinstance->res_entries[i].queue); + kfree(pinstance->res_entries); + pinstance->res_entries = NULL; + } + + pmcraid_release_hcams(pinstance); +} + +/** + * pmcraid_allocate_config_buffers - allocates DMAable memory for config table + * @pinstance : pointer to per adapter instance structure + * + * Return Value + * 0 for successful allocation, -ENOMEM for any failure + */ +static int __devinit +pmcraid_allocate_config_buffers(struct pmcraid_instance *pinstance) +{ + int i; + + pinstance->res_entries = + kzalloc(sizeof(struct pmcraid_resource_entry) * + PMCRAID_MAX_RESOURCES, GFP_KERNEL); + + if (NULL == pinstance->res_entries) { + pmcraid_err("failed to allocate memory for resource table\n"); + return -ENOMEM; + } + + for (i = 0; i < PMCRAID_MAX_RESOURCES; i++) + list_add_tail(&pinstance->res_entries[i].queue, + &pinstance->free_res_q); + + pinstance->cfg_table = + pci_alloc_consistent(pinstance->pdev, + sizeof(struct pmcraid_config_table), + &pinstance->cfg_table_bus_addr); + + if (NULL == pinstance->cfg_table) { + pmcraid_err("couldn't alloc DMA memory for config table\n"); + pmcraid_release_config_buffers(pinstance); + return -ENOMEM; + } + + if (pmcraid_allocate_hcams(pinstance)) { + pmcraid_err("could not alloc DMA memory for HCAMS\n"); + pmcraid_release_config_buffers(pinstance); + return -ENOMEM; + } + + return 0; +} + +/** + * pmcraid_init_tasklets - registers tasklets for response handling + * + * @pinstance: pointer adapter instance structure + * + * Return value + * none + */ +static void pmcraid_init_tasklets(struct pmcraid_instance *pinstance) +{ + int i; + for (i = 0; i < pinstance->num_hrrq; i++) + tasklet_init(&pinstance->isr_tasklet[i], + pmcraid_tasklet_function, + (unsigned long)&pinstance->hrrq_vector[i]); +} + +/** + * pmcraid_kill_tasklets - destroys tasklets registered for response handling + * + * @pinstance: pointer to adapter instance structure + * + * Return value + * none + */ +static void pmcraid_kill_tasklets(struct pmcraid_instance *pinstance) +{ + int i; + for (i = 0; i < pinstance->num_hrrq; i++) + tasklet_kill(&pinstance->isr_tasklet[i]); +} + +/** + * pmcraid_init_buffers - allocates memory and initializes various structures + * @pinstance: pointer to per adapter instance structure + * + * This routine pre-allocates memory based on the type of block as below: + * cmdblocks(PMCRAID_MAX_CMD): kernel memory using kernel's slab_allocator, + * IOARCBs(PMCRAID_MAX_CMD) : DMAable memory, using pci pool allocator + * config-table entries : DMAable memory using pci_alloc_consistent + * HostRRQs : DMAable memory, using pci_alloc_consistent + * + * Return Value + * 0 in case all of the blocks are allocated, -ENOMEM otherwise. + */ +static int __devinit pmcraid_init_buffers(struct pmcraid_instance *pinstance) +{ + int i; + + if (pmcraid_allocate_host_rrqs(pinstance)) { + pmcraid_err("couldn't allocate memory for %d host rrqs\n", + pinstance->num_hrrq); + return -ENOMEM; + } + + if (pmcraid_allocate_config_buffers(pinstance)) { + pmcraid_err("couldn't allocate memory for config buffers\n"); + pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); + return -ENOMEM; + } + + if (pmcraid_allocate_cmd_blocks(pinstance)) { + pmcraid_err("couldn't allocate memory for cmd blocks \n"); + pmcraid_release_config_buffers(pinstance); + pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); + return -ENOMEM; + } + + if (pmcraid_allocate_control_blocks(pinstance)) { + pmcraid_err("couldn't allocate memory control blocks \n"); + pmcraid_release_config_buffers(pinstance); + pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD); + pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); + return -ENOMEM; + } + + /* Initialize all the command blocks and add them to free pool. No + * need to lock (free_pool_lock) as this is done in initialization + * itself + */ + for (i = 0; i < PMCRAID_MAX_CMD; i++) { + struct pmcraid_cmd *cmdp = pinstance->cmd_list[i]; + pmcraid_init_cmdblk(cmdp, i); + cmdp->drv_inst = pinstance; + list_add_tail(&cmdp->free_list, &pinstance->free_cmd_pool); + } + + return 0; +} + +/** + * pmcraid_reinit_buffers - resets various buffer pointers + * @pinstance: pointer to adapter instance + * Return value + * none + */ +static void pmcraid_reinit_buffers(struct pmcraid_instance *pinstance) +{ + int i; + int buffer_size = HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD; + + for (i = 0; i < pinstance->num_hrrq; i++) { + memset(pinstance->hrrq_start[i], 0, buffer_size); + pinstance->hrrq_curr[i] = pinstance->hrrq_start[i]; + pinstance->hrrq_end[i] = + pinstance->hrrq_start[i] + PMCRAID_MAX_CMD - 1; + pinstance->host_toggle_bit[i] = 1; + } +} + +/** + * pmcraid_init_instance - initialize per instance data structure + * @pdev: pointer to pci device structure + * @host: pointer to Scsi_Host structure + * @mapped_pci_addr: memory mapped IOA configuration registers + * + * Return Value + * 0 on success, non-zero in case of any failure + */ +static int __devinit pmcraid_init_instance( + struct pci_dev *pdev, + struct Scsi_Host *host, + void __iomem *mapped_pci_addr +) +{ + struct pmcraid_instance *pinstance = + (struct pmcraid_instance *)host->hostdata; + + pinstance->host = host; + pinstance->pdev = pdev; + + /* Initialize register addresses */ + pinstance->mapped_dma_addr = mapped_pci_addr; + + /* Initialize chip-specific details */ + { + struct pmcraid_chip_details *chip_cfg = pinstance->chip_cfg; + struct pmcraid_interrupts *pint_regs = &pinstance->int_regs; + + pinstance->ioarrin = mapped_pci_addr + chip_cfg->ioarrin; + + pint_regs->ioa_host_interrupt_reg = + mapped_pci_addr + chip_cfg->ioa_host_intr; + pint_regs->ioa_host_interrupt_clr_reg = + mapped_pci_addr + chip_cfg->ioa_host_intr_clr; + pint_regs->host_ioa_interrupt_reg = + mapped_pci_addr + chip_cfg->host_ioa_intr; + pint_regs->host_ioa_interrupt_clr_reg = + mapped_pci_addr + chip_cfg->host_ioa_intr_clr; + + /* Current version of firmware exposes interrupt mask set + * and mask clr registers through memory mapped bar0. + */ + pinstance->mailbox = mapped_pci_addr + chip_cfg->mailbox; + pinstance->ioa_status = mapped_pci_addr + chip_cfg->ioastatus; + pint_regs->ioa_host_interrupt_mask_reg = + mapped_pci_addr + chip_cfg->ioa_host_mask; + pint_regs->ioa_host_interrupt_mask_clr_reg = + mapped_pci_addr + chip_cfg->ioa_host_mask_clr; + pint_regs->global_interrupt_mask_reg = + mapped_pci_addr + chip_cfg->global_intr_mask; + }; + + pinstance->ioa_reset_attempts = 0; + init_waitqueue_head(&pinstance->reset_wait_q); + + atomic_set(&pinstance->outstanding_cmds, 0); + atomic_set(&pinstance->expose_resources, 0); + + INIT_LIST_HEAD(&pinstance->free_res_q); + INIT_LIST_HEAD(&pinstance->used_res_q); + INIT_LIST_HEAD(&pinstance->free_cmd_pool); + INIT_LIST_HEAD(&pinstance->pending_cmd_pool); + + spin_lock_init(&pinstance->free_pool_lock); + spin_lock_init(&pinstance->pending_pool_lock); + spin_lock_init(&pinstance->resource_lock); + mutex_init(&pinstance->aen_queue_lock); + + /* Work-queue (Shared) for deferred processing error handling */ + INIT_WORK(&pinstance->worker_q, pmcraid_worker_function); + + /* Initialize the default log_level */ + pinstance->current_log_level = pmcraid_log_level; + + /* Setup variables required for reset engine */ + pinstance->ioa_state = IOA_STATE_UNKNOWN; + pinstance->reset_cmd = NULL; + return 0; +} + +/** + * pmcraid_release_buffers - release per-adapter buffers allocated + * + * @pinstance: pointer to adapter soft state + * + * Return Value + * none + */ +static void pmcraid_release_buffers(struct pmcraid_instance *pinstance) +{ + pmcraid_release_config_buffers(pinstance); + pmcraid_release_control_blocks(pinstance, PMCRAID_MAX_CMD); + pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD); + pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); + +} + +/** + * pmcraid_shutdown - shutdown adapter controller. + * @pdev: pci device struct + * + * Issues an adapter shutdown to the card waits for its completion + * + * Return value + * none + */ +static void pmcraid_shutdown(struct pci_dev *pdev) +{ + struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); + pmcraid_reset_bringdown(pinstance); +} + + +/** + * pmcraid_get_minor - returns unused minor number from minor number bitmap + */ +static unsigned short pmcraid_get_minor(void) +{ + int minor; + + minor = find_first_zero_bit(pmcraid_minor, sizeof(pmcraid_minor)); + __set_bit(minor, pmcraid_minor); + return minor; +} + +/** + * pmcraid_release_minor - releases given minor back to minor number bitmap + */ +static void pmcraid_release_minor(unsigned short minor) +{ + __clear_bit(minor, pmcraid_minor); +} + +/** + * pmcraid_setup_chrdev - allocates a minor number and registers a char device + * + * @pinstance: pointer to adapter instance for which to register device + * + * Return value + * 0 in case of success, otherwise non-zero + */ +static int pmcraid_setup_chrdev(struct pmcraid_instance *pinstance) +{ + int minor; + int error; + + minor = pmcraid_get_minor(); + cdev_init(&pinstance->cdev, &pmcraid_fops); + pinstance->cdev.owner = THIS_MODULE; + + error = cdev_add(&pinstance->cdev, MKDEV(pmcraid_major, minor), 1); + + if (error) + pmcraid_release_minor(minor); + else + device_create(pmcraid_class, NULL, MKDEV(pmcraid_major, minor), + NULL, "pmcsas%u", minor); + return error; +} + +/** + * pmcraid_release_chrdev - unregisters per-adapter management interface + * + * @pinstance: pointer to adapter instance structure + * + * Return value + * none + */ +static void pmcraid_release_chrdev(struct pmcraid_instance *pinstance) +{ + pmcraid_release_minor(MINOR(pinstance->cdev.dev)); + device_destroy(pmcraid_class, + MKDEV(pmcraid_major, MINOR(pinstance->cdev.dev))); + cdev_del(&pinstance->cdev); +} + +/** + * pmcraid_remove - IOA hot plug remove entry point + * @pdev: pci device struct + * + * Return value + * none + */ +static void __devexit pmcraid_remove(struct pci_dev *pdev) +{ + struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); + + /* remove the management interface (/dev file) for this device */ + pmcraid_release_chrdev(pinstance); + + /* remove host template from scsi midlayer */ + scsi_remove_host(pinstance->host); + + /* block requests from mid-layer */ + scsi_block_requests(pinstance->host); + + /* initiate shutdown adapter */ + pmcraid_shutdown(pdev); + + pmcraid_disable_interrupts(pinstance, ~0); + flush_scheduled_work(); + + pmcraid_kill_tasklets(pinstance); + pmcraid_unregister_interrupt_handler(pinstance); + pmcraid_release_buffers(pinstance); + iounmap(pinstance->mapped_dma_addr); + pci_release_regions(pdev); + scsi_host_put(pinstance->host); + pci_disable_device(pdev); + + return; +} + +#ifdef CONFIG_PM +/** + * pmcraid_suspend - driver suspend entry point for power management + * @pdev: PCI device structure + * @state: PCI power state to suspend routine + * + * Return Value - 0 always + */ +static int pmcraid_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); + + pmcraid_shutdown(pdev); + pmcraid_disable_interrupts(pinstance, ~0); + pmcraid_kill_tasklets(pinstance); + pci_set_drvdata(pinstance->pdev, pinstance); + pmcraid_unregister_interrupt_handler(pinstance); + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +/** + * pmcraid_resume - driver resume entry point PCI power management + * @pdev: PCI device structure + * + * Return Value - 0 in case of success. Error code in case of any failure + */ +static int pmcraid_resume(struct pci_dev *pdev) +{ + struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); + struct Scsi_Host *host = pinstance->host; + int rc; + int hrrqs; + + pci_set_power_state(pdev, PCI_D0); + pci_enable_wake(pdev, PCI_D0, 0); + pci_restore_state(pdev); + + rc = pci_enable_device(pdev); + + if (rc) { + pmcraid_err("pmcraid: Enable device failed\n"); + return rc; + } + + pci_set_master(pdev); + + if ((sizeof(dma_addr_t) == 4) || + pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + + if (rc == 0) + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + + if (rc != 0) { + dev_err(&pdev->dev, "Failed to set PCI DMA mask\n"); + goto disable_device; + } + + atomic_set(&pinstance->outstanding_cmds, 0); + hrrqs = pinstance->num_hrrq; + rc = pmcraid_register_interrupt_handler(pinstance); + + if (rc) { + pmcraid_err("resume: couldn't register interrupt handlers\n"); + rc = -ENODEV; + goto release_host; + } + + pmcraid_init_tasklets(pinstance); + pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS); + + /* Start with hard reset sequence which brings up IOA to operational + * state as well as completes the reset sequence. + */ + pinstance->ioa_hard_reset = 1; + + /* Start IOA firmware initialization and bring card to Operational + * state. + */ + if (pmcraid_reset_bringup(pinstance)) { + pmcraid_err("couldn't initialize IOA \n"); + rc = -ENODEV; + goto release_tasklets; + } + + return 0; + +release_tasklets: + pmcraid_kill_tasklets(pinstance); + pmcraid_unregister_interrupt_handler(pinstance); + +release_host: + scsi_host_put(host); + +disable_device: + pci_disable_device(pdev); + + return rc; +} + +#else + +#define pmcraid_suspend NULL +#define pmcraid_resume NULL + +#endif /* CONFIG_PM */ + +/** + * pmcraid_complete_ioa_reset - Called by either timer or tasklet during + * completion of the ioa reset + * @cmd: pointer to reset command block + */ +static void pmcraid_complete_ioa_reset(struct pmcraid_cmd *cmd) +{ + struct pmcraid_instance *pinstance = cmd->drv_inst; + unsigned long flags; + + spin_lock_irqsave(pinstance->host->host_lock, flags); + pmcraid_ioa_reset(cmd); + spin_unlock_irqrestore(pinstance->host->host_lock, flags); + scsi_unblock_requests(pinstance->host); + schedule_work(&pinstance->worker_q); +} + +/** + * pmcraid_set_supported_devs - sends SET SUPPORTED DEVICES to IOAFP + * + * @cmd: pointer to pmcraid_cmd structure + * + * Return Value + * 0 for success or non-zero for failure cases + */ +static void pmcraid_set_supported_devs(struct pmcraid_cmd *cmd) +{ + struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; + void (*cmd_done) (struct pmcraid_cmd *) = pmcraid_complete_ioa_reset; + + pmcraid_reinit_cmdblk(cmd); + + ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); + ioarcb->request_type = REQ_TYPE_IOACMD; + ioarcb->cdb[0] = PMCRAID_SET_SUPPORTED_DEVICES; + ioarcb->cdb[1] = ALL_DEVICES_SUPPORTED; + + /* If this was called as part of resource table reinitialization due to + * lost CCN, it is enough to return the command block back to free pool + * as part of set_supported_devs completion function. + */ + if (cmd->drv_inst->reinit_cfg_table) { + cmd->drv_inst->reinit_cfg_table = 0; + cmd->release = 1; + cmd_done = pmcraid_reinit_cfgtable_done; + } + + /* we will be done with the reset sequence after set supported devices, + * setup the done function to return the command block back to free + * pool + */ + pmcraid_send_cmd(cmd, + cmd_done, + PMCRAID_SET_SUP_DEV_TIMEOUT, + pmcraid_timeout_handler); + return; +} + +/** + * pmcraid_init_res_table - Initialize the resource table + * @cmd: pointer to pmcraid command struct + * + * This function looks through the existing resource table, comparing + * it with the config table. This function will take care of old/new + * devices and schedule adding/removing them from the mid-layer + * as appropriate. + * + * Return value + * None + */ +static void pmcraid_init_res_table(struct pmcraid_cmd *cmd) +{ + struct pmcraid_instance *pinstance = cmd->drv_inst; + struct pmcraid_resource_entry *res, *temp; + struct pmcraid_config_table_entry *cfgte; + unsigned long lock_flags; + int found, rc, i; + LIST_HEAD(old_res); + + if (pinstance->cfg_table->flags & MICROCODE_UPDATE_REQUIRED) + dev_err(&pinstance->pdev->dev, "Require microcode download\n"); + + /* resource list is protected by pinstance->resource_lock. + * init_res_table can be called from probe (user-thread) or runtime + * reset (timer/tasklet) + */ + spin_lock_irqsave(&pinstance->resource_lock, lock_flags); + + list_for_each_entry_safe(res, temp, &pinstance->used_res_q, queue) + list_move_tail(&res->queue, &old_res); + + for (i = 0; i < pinstance->cfg_table->num_entries; i++) { + cfgte = &pinstance->cfg_table->entries[i]; + + if (!pmcraid_expose_resource(cfgte)) + continue; + + found = 0; + + /* If this entry was already detected and initialized */ + list_for_each_entry_safe(res, temp, &old_res, queue) { + + rc = memcmp(&res->cfg_entry.resource_address, + &cfgte->resource_address, + sizeof(cfgte->resource_address)); + if (!rc) { + list_move_tail(&res->queue, + &pinstance->used_res_q); + found = 1; + break; + } + } + + /* If this is new entry, initialize it and add it the queue */ + if (!found) { + + if (list_empty(&pinstance->free_res_q)) { + dev_err(&pinstance->pdev->dev, + "Too many devices attached\n"); + break; + } + + found = 1; + res = list_entry(pinstance->free_res_q.next, + struct pmcraid_resource_entry, queue); + + res->scsi_dev = NULL; + res->change_detected = RES_CHANGE_ADD; + res->reset_progress = 0; + list_move_tail(&res->queue, &pinstance->used_res_q); + } + + /* copy new configuration table entry details into driver + * maintained resource entry + */ + if (found) { + memcpy(&res->cfg_entry, cfgte, + sizeof(struct pmcraid_config_table_entry)); + pmcraid_info("New res type:%x, vset:%x, addr:%x:\n", + res->cfg_entry.resource_type, + res->cfg_entry.unique_flags1, + le32_to_cpu(res->cfg_entry.resource_address)); + } + } + + /* Detect any deleted entries, mark them for deletion from mid-layer */ + list_for_each_entry_safe(res, temp, &old_res, queue) { + + if (res->scsi_dev) { + res->change_detected = RES_CHANGE_DEL; + res->cfg_entry.resource_handle = + PMCRAID_INVALID_RES_HANDLE; + list_move_tail(&res->queue, &pinstance->used_res_q); + } else { + list_move_tail(&res->queue, &pinstance->free_res_q); + } + } + + /* release the resource list lock */ + spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); + pmcraid_set_supported_devs(cmd); +} + +/** + * pmcraid_querycfg - Send a Query IOA Config to the adapter. + * @cmd: pointer pmcraid_cmd struct + * + * This function sends a Query IOA Configuration command to the adapter to + * retrieve the IOA configuration table. + * + * Return value: + * none + */ +static void pmcraid_querycfg(struct pmcraid_cmd *cmd) +{ + struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; + struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; + struct pmcraid_instance *pinstance = cmd->drv_inst; + int cfg_table_size = cpu_to_be32(sizeof(struct pmcraid_config_table)); + + ioarcb->request_type = REQ_TYPE_IOACMD; + ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); + + ioarcb->cdb[0] = PMCRAID_QUERY_IOA_CONFIG; + + /* firmware requires 4-byte length field, specified in B.E format */ + memcpy(&(ioarcb->cdb[10]), &cfg_table_size, sizeof(cfg_table_size)); + + /* Since entire config table can be described by single IOADL, it can + * be part of IOARCB itself + */ + ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + + offsetof(struct pmcraid_ioarcb, + add_data.u.ioadl[0])); + ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); + ioarcb->ioarcb_bus_addr &= ~(0x1FULL); + + ioarcb->request_flags0 |= NO_LINK_DESCS; + ioarcb->data_transfer_length = + cpu_to_le32(sizeof(struct pmcraid_config_table)); + + ioadl = &(ioarcb->add_data.u.ioadl[0]); + ioadl->flags = cpu_to_le32(IOADL_FLAGS_LAST_DESC); + ioadl->address = cpu_to_le64(pinstance->cfg_table_bus_addr); + ioadl->data_len = cpu_to_le32(sizeof(struct pmcraid_config_table)); + + pmcraid_send_cmd(cmd, pmcraid_init_res_table, + PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); +} + + +/** + * pmcraid_probe - PCI probe entry pointer for PMC MaxRaid controller driver + * @pdev: pointer to pci device structure + * @dev_id: pointer to device ids structure + * + * Return Value + * returns 0 if the device is claimed and successfully configured. + * returns non-zero error code in case of any failure + */ +static int __devinit pmcraid_probe( + struct pci_dev *pdev, + const struct pci_device_id *dev_id +) +{ + struct pmcraid_instance *pinstance; + struct Scsi_Host *host; + void __iomem *mapped_pci_addr; + int rc = PCIBIOS_SUCCESSFUL; + + if (atomic_read(&pmcraid_adapter_count) >= PMCRAID_MAX_ADAPTERS) { + pmcraid_err + ("maximum number(%d) of supported adapters reached\n", + atomic_read(&pmcraid_adapter_count)); + return -ENOMEM; + } + + atomic_inc(&pmcraid_adapter_count); + rc = pci_enable_device(pdev); + + if (rc) { + dev_err(&pdev->dev, "Cannot enable adapter\n"); + atomic_dec(&pmcraid_adapter_count); + return rc; + } + + dev_info(&pdev->dev, + "Found new IOA(%x:%x), Total IOA count: %d\n", + pdev->vendor, pdev->device, + atomic_read(&pmcraid_adapter_count)); + + rc = pci_request_regions(pdev, PMCRAID_DRIVER_NAME); + + if (rc < 0) { + dev_err(&pdev->dev, + "Couldn't register memory range of registers\n"); + goto out_disable_device; + } + + mapped_pci_addr = pci_iomap(pdev, 0, 0); + + if (!mapped_pci_addr) { + dev_err(&pdev->dev, "Couldn't map PCI registers memory\n"); + rc = -ENOMEM; + goto out_release_regions; + } + + pci_set_master(pdev); + + /* Firmware requires the system bus address of IOARCB to be within + * 32-bit addressable range though it has 64-bit IOARRIN register. + * However, firmware supports 64-bit streaming DMA buffers, whereas + * coherent buffers are to be 32-bit. Since pci_alloc_consistent always + * returns memory within 4GB (if not, change this logic), coherent + * buffers are within firmware acceptible address ranges. + */ + if ((sizeof(dma_addr_t) == 4) || + pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + + /* firmware expects 32-bit DMA addresses for IOARRIN register; set 32 + * bit mask for pci_alloc_consistent to return addresses within 4GB + */ + if (rc == 0) + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + + if (rc != 0) { + dev_err(&pdev->dev, "Failed to set PCI DMA mask\n"); + goto cleanup_nomem; + } + + host = scsi_host_alloc(&pmcraid_host_template, + sizeof(struct pmcraid_instance)); + + if (!host) { + dev_err(&pdev->dev, "scsi_host_alloc failed!\n"); + rc = -ENOMEM; + goto cleanup_nomem; + } + + host->max_id = PMCRAID_MAX_NUM_TARGETS_PER_BUS; + host->max_lun = PMCRAID_MAX_NUM_LUNS_PER_TARGET; + host->unique_id = host->host_no; + host->max_channel = PMCRAID_MAX_BUS_TO_SCAN; + host->max_cmd_len = PMCRAID_MAX_CDB_LEN; + + /* zero out entire instance structure */ + pinstance = (struct pmcraid_instance *)host->hostdata; + memset(pinstance, 0, sizeof(*pinstance)); + + pinstance->chip_cfg = + (struct pmcraid_chip_details *)(dev_id->driver_data); + + rc = pmcraid_init_instance(pdev, host, mapped_pci_addr); + + if (rc < 0) { + dev_err(&pdev->dev, "failed to initialize adapter instance\n"); + goto out_scsi_host_put; + } + + pci_set_drvdata(pdev, pinstance); + + /* Save PCI config-space for use following the reset */ + rc = pci_save_state(pinstance->pdev); + + if (rc != 0) { + dev_err(&pdev->dev, "Failed to save PCI config space\n"); + goto out_scsi_host_put; + } + + pmcraid_disable_interrupts(pinstance, ~0); + + rc = pmcraid_register_interrupt_handler(pinstance); + + if (rc) { + pmcraid_err("couldn't register interrupt handler\n"); + goto out_scsi_host_put; + } + + pmcraid_init_tasklets(pinstance); + + /* allocate verious buffers used by LLD.*/ + rc = pmcraid_init_buffers(pinstance); + + if (rc) { + pmcraid_err("couldn't allocate memory blocks\n"); + goto out_unregister_isr; + } + + /* check the reset type required */ + pmcraid_reset_type(pinstance); + + pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS); + + /* Start IOA firmware initialization and bring card to Operational + * state. + */ + pmcraid_info("starting IOA initialization sequence\n"); + if (pmcraid_reset_bringup(pinstance)) { + pmcraid_err("couldn't initialize IOA \n"); + rc = 1; + goto out_release_bufs; + } + + /* Add adapter instance into mid-layer list */ + rc = scsi_add_host(pinstance->host, &pdev->dev); + if (rc != 0) { + pmcraid_err("couldn't add host into mid-layer: %d\n", rc); + goto out_release_bufs; + } + + scsi_scan_host(pinstance->host); + + rc = pmcraid_setup_chrdev(pinstance); + + if (rc != 0) { + pmcraid_err("couldn't create mgmt interface, error: %x\n", + rc); + goto out_remove_host; + } + + /* Schedule worker thread to handle CCN and take care of adding and + * removing devices to OS + */ + atomic_set(&pinstance->expose_resources, 1); + schedule_work(&pinstance->worker_q); + return rc; + +out_remove_host: + scsi_remove_host(host); + +out_release_bufs: + pmcraid_release_buffers(pinstance); + +out_unregister_isr: + pmcraid_kill_tasklets(pinstance); + pmcraid_unregister_interrupt_handler(pinstance); + +out_scsi_host_put: + scsi_host_put(host); + +cleanup_nomem: + iounmap(mapped_pci_addr); + +out_release_regions: + pci_release_regions(pdev); + +out_disable_device: + atomic_dec(&pmcraid_adapter_count); + pci_set_drvdata(pdev, NULL); + pci_disable_device(pdev); + return -ENODEV; +} + +/* + * PCI driver structure of pcmraid driver + */ +static struct pci_driver pmcraid_driver = { + .name = PMCRAID_DRIVER_NAME, + .id_table = pmcraid_pci_table, + .probe = pmcraid_probe, + .remove = pmcraid_remove, + .suspend = pmcraid_suspend, + .resume = pmcraid_resume, + .shutdown = pmcraid_shutdown +}; + + +/** + * pmcraid_init - module load entry point + */ +static int __init pmcraid_init(void) +{ + dev_t dev; + int error; + + pmcraid_info("%s Device Driver version: %s %s\n", + PMCRAID_DRIVER_NAME, + PMCRAID_DRIVER_VERSION, PMCRAID_DRIVER_DATE); + + error = alloc_chrdev_region(&dev, 0, + PMCRAID_MAX_ADAPTERS, + PMCRAID_DEVFILE); + + if (error) { + pmcraid_err("failed to get a major number for adapters\n"); + goto out_init; + } + + pmcraid_major = MAJOR(dev); + pmcraid_class = class_create(THIS_MODULE, PMCRAID_DEVFILE); + + if (IS_ERR(pmcraid_class)) { + error = PTR_ERR(pmcraid_class); + pmcraid_err("failed to register with with sysfs, error = %x\n", + error); + goto out_unreg_chrdev; + } + + + error = pmcraid_netlink_init(); + + if (error) + goto out_unreg_chrdev; + + error = pci_register_driver(&pmcraid_driver); + + if (error == 0) + goto out_init; + + pmcraid_err("failed to register pmcraid driver, error = %x\n", + error); + class_destroy(pmcraid_class); + pmcraid_netlink_release(); + +out_unreg_chrdev: + unregister_chrdev_region(MKDEV(pmcraid_major, 0), PMCRAID_MAX_ADAPTERS); +out_init: + return error; +} + +/** + * pmcraid_exit - module unload entry point + */ +static void __exit pmcraid_exit(void) +{ + pmcraid_netlink_release(); + class_destroy(pmcraid_class); + unregister_chrdev_region(MKDEV(pmcraid_major, 0), + PMCRAID_MAX_ADAPTERS); + pci_unregister_driver(&pmcraid_driver); +} + +module_init(pmcraid_init); +module_exit(pmcraid_exit); diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h new file mode 100644 index 00000000000..614b3a764fe --- /dev/null +++ b/drivers/scsi/pmcraid.h @@ -0,0 +1,1029 @@ +/* + * pmcraid.h -- PMC Sierra MaxRAID controller driver header file + * + * Copyright (C) 2008, 2009 PMC Sierra Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _PMCRAID_H +#define _PMCRAID_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* + * Driver name : string representing the driver name + * Device file : /dev file to be used for management interfaces + * Driver version: version string in major_version.minor_version.patch format + * Driver date : date information in "Mon dd yyyy" format + */ +#define PMCRAID_DRIVER_NAME "PMC MaxRAID" +#define PMCRAID_DEVFILE "pmcsas" +#define PMCRAID_DRIVER_VERSION "1.0.2" +#define PMCRAID_DRIVER_DATE __DATE__ + +/* Maximum number of adapters supported by current version of the driver */ +#define PMCRAID_MAX_ADAPTERS 1024 + +/* Bit definitions as per firmware, bit position [0][1][2].....[31] */ +#define PMC_BIT8(n) (1 << (7-n)) +#define PMC_BIT16(n) (1 << (15-n)) +#define PMC_BIT32(n) (1 << (31-n)) + +/* PMC PCI vendor ID and device ID values */ +#define PCI_VENDOR_ID_PMC 0x11F8 +#define PCI_DEVICE_ID_PMC_MAXRAID 0x5220 + +/* + * MAX_CMD : maximum commands that can be outstanding with IOA + * MAX_IO_CMD : command blocks available for IO commands + * MAX_HCAM_CMD : command blocks avaibale for HCAMS + * MAX_INTERNAL_CMD : command blocks avaible for internal commands like reset + */ +#define PMCRAID_MAX_CMD 1024 +#define PMCRAID_MAX_IO_CMD 1020 +#define PMCRAID_MAX_HCAM_CMD 2 +#define PMCRAID_MAX_INTERNAL_CMD 2 + +/* MAX_IOADLS : max number of scatter-gather lists supported by IOA + * IOADLS_INTERNAL : number of ioadls included as part of IOARCB. + * IOADLS_EXTERNAL : number of ioadls allocated external to IOARCB + */ +#define PMCRAID_IOADLS_INTERNAL 27 +#define PMCRAID_IOADLS_EXTERNAL 37 +#define PMCRAID_MAX_IOADLS PMCRAID_IOADLS_INTERNAL + +/* HRRQ_ENTRY_SIZE : size of hrrq buffer + * IOARCB_ALIGNMENT : alignment required for IOARCB + * IOADL_ALIGNMENT : alignment requirement for IOADLs + * MSIX_VECTORS : number of MSIX vectors supported + */ +#define HRRQ_ENTRY_SIZE sizeof(__le32) +#define PMCRAID_IOARCB_ALIGNMENT 32 +#define PMCRAID_IOADL_ALIGNMENT 16 +#define PMCRAID_IOASA_ALIGNMENT 4 +#define PMCRAID_NUM_MSIX_VECTORS 1 + +/* various other limits */ +#define PMCRAID_VENDOR_ID_LEN 8 +#define PMCRAID_PRODUCT_ID_LEN 16 +#define PMCRAID_SERIAL_NUM_LEN 8 +#define PMCRAID_LUN_LEN 8 +#define PMCRAID_MAX_CDB_LEN 16 +#define PMCRAID_DEVICE_ID_LEN 8 +#define PMCRAID_SENSE_DATA_LEN 256 +#define PMCRAID_ADD_CMD_PARAM_LEN 48 + +#define PMCRAID_MAX_BUS_TO_SCAN 1 +#define PMCRAID_MAX_NUM_TARGETS_PER_BUS 256 +#define PMCRAID_MAX_NUM_LUNS_PER_TARGET 8 + +/* IOA bus/target/lun number of IOA resources */ +#define PMCRAID_IOA_BUS_ID 0xfe +#define PMCRAID_IOA_TARGET_ID 0xff +#define PMCRAID_IOA_LUN_ID 0xff +#define PMCRAID_VSET_BUS_ID 0x1 +#define PMCRAID_VSET_LUN_ID 0x0 +#define PMCRAID_PHYS_BUS_ID 0x0 +#define PMCRAID_VIRTUAL_ENCL_BUS_ID 0x8 +#define PMCRAID_MAX_VSET_TARGETS 240 +#define PMCRAID_MAX_VSET_LUNS_PER_TARGET 8 + +#define PMCRAID_IOA_MAX_SECTORS 32767 +#define PMCRAID_VSET_MAX_SECTORS 512 +#define PMCRAID_MAX_CMD_PER_LUN 254 + +/* Number of configuration table entries (resources) */ +#define PMCRAID_MAX_NUM_OF_VSETS 240 + +/* Todo : Check max limit for Phase 1 */ +#define PMCRAID_MAX_NUM_OF_PHY_DEVS 256 + +/* MAX_NUM_OF_DEVS includes 1 FP, 1 Dummy Enclosure device */ +#define PMCRAID_MAX_NUM_OF_DEVS \ + (PMCRAID_MAX_NUM_OF_VSETS + PMCRAID_MAX_NUM_OF_PHY_DEVS + 2) + +#define PMCRAID_MAX_RESOURCES PMCRAID_MAX_NUM_OF_DEVS + +/* Adapter Commands used by driver */ +#define PMCRAID_QUERY_RESOURCE_STATE 0xC2 +#define PMCRAID_RESET_DEVICE 0xC3 +/* options to select reset target */ +#define ENABLE_RESET_MODIFIER 0x80 +#define RESET_DEVICE_LUN 0x40 +#define RESET_DEVICE_TARGET 0x20 +#define RESET_DEVICE_BUS 0x10 + +#define PMCRAID_IDENTIFY_HRRQ 0xC4 +#define PMCRAID_QUERY_IOA_CONFIG 0xC5 +#define PMCRAID_QUERY_CMD_STATUS 0xCB +#define PMCRAID_ABORT_CMD 0xC7 + +/* CANCEL ALL command, provides option for setting SYNC_COMPLETE + * on the target resources for which commands got cancelled + */ +#define PMCRAID_CANCEL_ALL_REQUESTS 0xCE +#define PMCRAID_SYNC_COMPLETE_AFTER_CANCEL PMC_BIT8(0) + +/* HCAM command and types of HCAM supported by IOA */ +#define PMCRAID_HOST_CONTROLLED_ASYNC 0xCF +#define PMCRAID_HCAM_CODE_CONFIG_CHANGE 0x01 +#define PMCRAID_HCAM_CODE_LOG_DATA 0x02 + +/* IOA shutdown command and various shutdown types */ +#define PMCRAID_IOA_SHUTDOWN 0xF7 +#define PMCRAID_SHUTDOWN_NORMAL 0x00 +#define PMCRAID_SHUTDOWN_PREPARE_FOR_NORMAL 0x40 +#define PMCRAID_SHUTDOWN_NONE 0x100 +#define PMCRAID_SHUTDOWN_ABBREV 0x80 + +/* SET SUPPORTED DEVICES command and the option to select all the + * devices to be supported + */ +#define PMCRAID_SET_SUPPORTED_DEVICES 0xFB +#define ALL_DEVICES_SUPPORTED PMC_BIT8(0) + +/* This option is used with SCSI WRITE_BUFFER command */ +#define PMCRAID_WR_BUF_DOWNLOAD_AND_SAVE 0x05 + +/* IOASC Codes used by driver */ +#define PMCRAID_IOASC_SENSE_MASK 0xFFFFFF00 +#define PMCRAID_IOASC_SENSE_KEY(ioasc) ((ioasc) >> 24) +#define PMCRAID_IOASC_SENSE_CODE(ioasc) (((ioasc) & 0x00ff0000) >> 16) +#define PMCRAID_IOASC_SENSE_QUAL(ioasc) (((ioasc) & 0x0000ff00) >> 8) +#define PMCRAID_IOASC_SENSE_STATUS(ioasc) ((ioasc) & 0x000000ff) + +#define PMCRAID_IOASC_GOOD_COMPLETION 0x00000000 +#define PMCRAID_IOASC_NR_INIT_CMD_REQUIRED 0x02040200 +#define PMCRAID_IOASC_NR_IOA_RESET_REQUIRED 0x02048000 +#define PMCRAID_IOASC_NR_SYNC_REQUIRED 0x023F0000 +#define PMCRAID_IOASC_ME_READ_ERROR_NO_REALLOC 0x03110C00 +#define PMCRAID_IOASC_HW_CANNOT_COMMUNICATE 0x04050000 +#define PMCRAID_IOASC_HW_DEVICE_TIMEOUT 0x04080100 +#define PMCRAID_IOASC_HW_DEVICE_BUS_STATUS_ERROR 0x04448500 +#define PMCRAID_IOASC_HW_IOA_RESET_REQUIRED 0x04448600 +#define PMCRAID_IOASC_IR_INVALID_RESOURCE_HANDLE 0x05250000 +#define PMCRAID_IOASC_AC_TERMINATED_BY_HOST 0x0B5A0000 +#define PMCRAID_IOASC_UA_BUS_WAS_RESET 0x06290000 +#define PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER 0x06298000 + +/* Driver defined IOASCs */ +#define PMCRAID_IOASC_IOA_WAS_RESET 0x10000001 +#define PMCRAID_IOASC_PCI_ACCESS_ERROR 0x10000002 + +/* Various timeout values (in milliseconds) used. If any of these are chip + * specific, move them to pmcraid_chip_details structure. + */ +#define PMCRAID_PCI_DEASSERT_TIMEOUT 2000 +#define PMCRAID_BIST_TIMEOUT 2000 +#define PMCRAID_AENWAIT_TIMEOUT 5000 +#define PMCRAID_TRANSOP_TIMEOUT 60000 + +#define PMCRAID_RESET_TIMEOUT (2 * HZ) +#define PMCRAID_CHECK_FOR_RESET_TIMEOUT ((HZ / 10)) +#define PMCRAID_VSET_IO_TIMEOUT (60 * HZ) +#define PMCRAID_INTERNAL_TIMEOUT (60 * HZ) +#define PMCRAID_SHUTDOWN_TIMEOUT (150 * HZ) +#define PMCRAID_RESET_BUS_TIMEOUT (60 * HZ) +#define PMCRAID_RESET_HOST_TIMEOUT (150 * HZ) +#define PMCRAID_REQUEST_SENSE_TIMEOUT (30 * HZ) +#define PMCRAID_SET_SUP_DEV_TIMEOUT (2 * 60 * HZ) + +/* structure to represent a scatter-gather element (IOADL descriptor) */ +struct pmcraid_ioadl_desc { + __le64 address; + __le32 data_len; + __u8 reserved[3]; + __u8 flags; +} __attribute__((packed, aligned(PMCRAID_IOADL_ALIGNMENT))); + +/* pmcraid_ioadl_desc.flags values */ +#define IOADL_FLAGS_CHAINED PMC_BIT8(0) +#define IOADL_FLAGS_LAST_DESC PMC_BIT8(1) +#define IOADL_FLAGS_READ_LAST PMC_BIT8(1) +#define IOADL_FLAGS_WRITE_LAST PMC_BIT8(1) + + +/* additional IOARCB data which can be CDB or additional request parameters + * or list of IOADLs. Firmware supports max of 512 bytes for IOARCB, hence then + * number of IOADLs are limted to 27. In case they are more than 27, they will + * be used in chained form + */ +struct pmcraid_ioarcb_add_data { + union { + struct pmcraid_ioadl_desc ioadl[PMCRAID_IOADLS_INTERNAL]; + __u8 add_cmd_params[PMCRAID_ADD_CMD_PARAM_LEN]; + } u; +}; + +/* + * IOA Request Control Block + */ +struct pmcraid_ioarcb { + __le64 ioarcb_bus_addr; + __le32 resource_handle; + __le32 response_handle; + __le64 ioadl_bus_addr; + __le32 ioadl_length; + __le32 data_transfer_length; + __le64 ioasa_bus_addr; + __le16 ioasa_len; + __le16 cmd_timeout; + __le16 add_cmd_param_offset; + __le16 add_cmd_param_length; + __le32 reserved1[2]; + __le32 reserved2; + __u8 request_type; + __u8 request_flags0; + __u8 request_flags1; + __u8 hrrq_id; + __u8 cdb[PMCRAID_MAX_CDB_LEN]; + struct pmcraid_ioarcb_add_data add_data; +} __attribute__((packed, aligned(PMCRAID_IOARCB_ALIGNMENT))); + +/* well known resource handle values */ +#define PMCRAID_IOA_RES_HANDLE 0xffffffff +#define PMCRAID_INVALID_RES_HANDLE 0 + +/* pmcraid_ioarcb.request_type values */ +#define REQ_TYPE_SCSI 0x00 +#define REQ_TYPE_IOACMD 0x01 +#define REQ_TYPE_HCAM 0x02 + +/* pmcraid_ioarcb.flags0 values */ +#define TRANSFER_DIR_WRITE PMC_BIT8(0) +#define INHIBIT_UL_CHECK PMC_BIT8(2) +#define SYNC_OVERRIDE PMC_BIT8(3) +#define SYNC_COMPLETE PMC_BIT8(4) +#define NO_LINK_DESCS PMC_BIT8(5) + +/* pmcraid_ioarcb.flags1 values */ +#define DELAY_AFTER_RESET PMC_BIT8(0) +#define TASK_TAG_SIMPLE 0x10 +#define TASK_TAG_ORDERED 0x20 +#define TASK_TAG_QUEUE_HEAD 0x30 + +/* toggle bit offset in response handle */ +#define HRRQ_TOGGLE_BIT 0x01 +#define HRRQ_RESPONSE_BIT 0x02 + +/* IOA Status Area */ +struct pmcraid_ioasa_vset { + __le32 failing_lba_hi; + __le32 failing_lba_lo; + __le32 reserved; +} __attribute__((packed, aligned(4))); + +struct pmcraid_ioasa { + __le32 ioasc; + __le16 returned_status_length; + __le16 available_status_length; + __le32 residual_data_length; + __le32 ilid; + __le32 fd_ioasc; + __le32 fd_res_address; + __le32 fd_res_handle; + __le32 reserved; + + /* resource specific sense information */ + union { + struct pmcraid_ioasa_vset vset; + } u; + + /* IOA autosense data */ + __le16 auto_sense_length; + __le16 error_data_length; + __u8 sense_data[PMCRAID_SENSE_DATA_LEN]; +} __attribute__((packed, aligned(4))); + +#define PMCRAID_DRIVER_ILID 0xffffffff + +/* Config Table Entry per Resource */ +struct pmcraid_config_table_entry { + __u8 resource_type; + __u8 bus_protocol; + __le16 array_id; + __u8 common_flags0; + __u8 common_flags1; + __u8 unique_flags0; + __u8 unique_flags1; /*also used as vset target_id */ + __le32 resource_handle; + __le32 resource_address; + __u8 device_id[PMCRAID_DEVICE_ID_LEN]; + __u8 lun[PMCRAID_LUN_LEN]; +} __attribute__((packed, aligned(4))); + +/* resource types (config_table_entry.resource_type values) */ +#define RES_TYPE_AF_DASD 0x00 +#define RES_TYPE_GSCSI 0x01 +#define RES_TYPE_VSET 0x02 +#define RES_TYPE_IOA_FP 0xFF + +#define RES_IS_IOA(res) ((res).resource_type == RES_TYPE_IOA_FP) +#define RES_IS_GSCSI(res) ((res).resource_type == RES_TYPE_GSCSI) +#define RES_IS_VSET(res) ((res).resource_type == RES_TYPE_VSET) +#define RES_IS_AFDASD(res) ((res).resource_type == RES_TYPE_AF_DASD) + +/* bus_protocol values used by driver */ +#define RES_TYPE_VENCLOSURE 0x8 + +/* config_table_entry.common_flags0 */ +#define MULTIPATH_RESOURCE PMC_BIT32(0) + +/* unique_flags1 */ +#define IMPORT_MODE_MANUAL PMC_BIT8(0) + +/* well known resource handle values */ +#define RES_HANDLE_IOA 0xFFFFFFFF +#define RES_HANDLE_NONE 0x00000000 + +/* well known resource address values */ +#define RES_ADDRESS_IOAFP 0xFEFFFFFF +#define RES_ADDRESS_INVALID 0xFFFFFFFF + +/* BUS/TARGET/LUN values from resource_addrr */ +#define RES_BUS(res_addr) (le32_to_cpu(res_addr) & 0xFF) +#define RES_TARGET(res_addr) ((le32_to_cpu(res_addr) >> 16) & 0xFF) +#define RES_LUN(res_addr) 0x0 + +/* configuration table structure */ +struct pmcraid_config_table { + __le16 num_entries; + __u8 table_format; + __u8 reserved1; + __u8 flags; + __u8 reserved2[11]; + struct pmcraid_config_table_entry entries[PMCRAID_MAX_RESOURCES]; +} __attribute__((packed, aligned(4))); + +/* config_table.flags value */ +#define MICROCODE_UPDATE_REQUIRED PMC_BIT32(0) + +/* + * HCAM format + */ +#define PMCRAID_HOSTRCB_LDNSIZE 4056 + +/* Error log notification format */ +struct pmcraid_hostrcb_error { + __le32 fd_ioasc; + __le32 fd_ra; + __le32 fd_rh; + __le32 prc; + union { + __u8 data[PMCRAID_HOSTRCB_LDNSIZE]; + } u; +} __attribute__ ((packed, aligned(4))); + +struct pmcraid_hcam_hdr { + __u8 op_code; + __u8 notification_type; + __u8 notification_lost; + __u8 flags; + __u8 overlay_id; + __u8 reserved1[3]; + __le32 ilid; + __le32 timestamp1; + __le32 timestamp2; + __le32 data_len; +} __attribute__((packed, aligned(4))); + +#define PMCRAID_AEN_GROUP 0x3 + +struct pmcraid_hcam_ccn { + struct pmcraid_hcam_hdr header; + struct pmcraid_config_table_entry cfg_entry; +} __attribute__((packed, aligned(4))); + +struct pmcraid_hcam_ldn { + struct pmcraid_hcam_hdr header; + struct pmcraid_hostrcb_error error_log; +} __attribute__((packed, aligned(4))); + +/* pmcraid_hcam.op_code values */ +#define HOSTRCB_TYPE_CCN 0xE1 +#define HOSTRCB_TYPE_LDN 0xE2 + +/* pmcraid_hcam.notification_type values */ +#define NOTIFICATION_TYPE_ENTRY_CHANGED 0x0 +#define NOTIFICATION_TYPE_ENTRY_NEW 0x1 +#define NOTIFICATION_TYPE_ENTRY_DELETED 0x2 +#define NOTIFICATION_TYPE_ERROR_LOG 0x10 +#define NOTIFICATION_TYPE_INFORMATION_LOG 0x11 + +#define HOSTRCB_NOTIFICATIONS_LOST PMC_BIT8(0) + +/* pmcraid_hcam.flags values */ +#define HOSTRCB_INTERNAL_OP_ERROR PMC_BIT8(0) +#define HOSTRCB_ERROR_RESPONSE_SENT PMC_BIT8(1) + +/* pmcraid_hcam.overlay_id values */ +#define HOSTRCB_OVERLAY_ID_08 0x08 +#define HOSTRCB_OVERLAY_ID_09 0x09 +#define HOSTRCB_OVERLAY_ID_11 0x11 +#define HOSTRCB_OVERLAY_ID_12 0x12 +#define HOSTRCB_OVERLAY_ID_13 0x13 +#define HOSTRCB_OVERLAY_ID_14 0x14 +#define HOSTRCB_OVERLAY_ID_16 0x16 +#define HOSTRCB_OVERLAY_ID_17 0x17 +#define HOSTRCB_OVERLAY_ID_20 0x20 +#define HOSTRCB_OVERLAY_ID_FF 0xFF + +/* Implementation specific card details */ +struct pmcraid_chip_details { + /* hardware register offsets */ + unsigned long ioastatus; + unsigned long ioarrin; + unsigned long mailbox; + unsigned long global_intr_mask; + unsigned long ioa_host_intr; + unsigned long ioa_host_intr_clr; + unsigned long ioa_host_mask; + unsigned long ioa_host_mask_clr; + unsigned long host_ioa_intr; + unsigned long host_ioa_intr_clr; + + /* timeout used during transitional to operational state */ + unsigned long transop_timeout; +}; + +/* IOA to HOST doorbells (interrupts) */ +#define INTRS_TRANSITION_TO_OPERATIONAL PMC_BIT32(0) +#define INTRS_IOARCB_TRANSFER_FAILED PMC_BIT32(3) +#define INTRS_IOA_UNIT_CHECK PMC_BIT32(4) +#define INTRS_NO_HRRQ_FOR_CMD_RESPONSE PMC_BIT32(5) +#define INTRS_CRITICAL_OP_IN_PROGRESS PMC_BIT32(6) +#define INTRS_IO_DEBUG_ACK PMC_BIT32(7) +#define INTRS_IOARRIN_LOST PMC_BIT32(27) +#define INTRS_SYSTEM_BUS_MMIO_ERROR PMC_BIT32(28) +#define INTRS_IOA_PROCESSOR_ERROR PMC_BIT32(29) +#define INTRS_HRRQ_VALID PMC_BIT32(30) +#define INTRS_OPERATIONAL_STATUS PMC_BIT32(0) + +/* Host to IOA Doorbells */ +#define DOORBELL_RUNTIME_RESET PMC_BIT32(1) +#define DOORBELL_IOA_RESET_ALERT PMC_BIT32(7) +#define DOORBELL_IOA_DEBUG_ALERT PMC_BIT32(9) +#define DOORBELL_ENABLE_DESTRUCTIVE_DIAGS PMC_BIT32(8) +#define DOORBELL_IOA_START_BIST PMC_BIT32(23) +#define DOORBELL_RESET_IOA PMC_BIT32(31) + +/* Global interrupt mask register value */ +#define GLOBAL_INTERRUPT_MASK 0x4ULL + +#define PMCRAID_ERROR_INTERRUPTS (INTRS_IOARCB_TRANSFER_FAILED | \ + INTRS_IOA_UNIT_CHECK | \ + INTRS_NO_HRRQ_FOR_CMD_RESPONSE | \ + INTRS_IOARRIN_LOST | \ + INTRS_SYSTEM_BUS_MMIO_ERROR | \ + INTRS_IOA_PROCESSOR_ERROR) + +#define PMCRAID_PCI_INTERRUPTS (PMCRAID_ERROR_INTERRUPTS | \ + INTRS_HRRQ_VALID | \ + INTRS_CRITICAL_OP_IN_PROGRESS |\ + INTRS_TRANSITION_TO_OPERATIONAL) + +/* control_block, associated with each of the commands contains IOARCB, IOADLs + * memory for IOASA. Additional 3 * 16 bytes are allocated in order to support + * additional request parameters (of max size 48) any command. + */ +struct pmcraid_control_block { + struct pmcraid_ioarcb ioarcb; + struct pmcraid_ioadl_desc ioadl[PMCRAID_IOADLS_EXTERNAL + 3]; + struct pmcraid_ioasa ioasa; +} __attribute__ ((packed, aligned(PMCRAID_IOARCB_ALIGNMENT))); + +/* pmcraid_sglist - Scatter-gather list allocated for passthrough ioctls + */ +struct pmcraid_sglist { + u32 order; + u32 num_sg; + u32 num_dma_sg; + u32 buffer_len; + struct scatterlist scatterlist[1]; +}; + +/* pmcraid_cmd - LLD representation of SCSI command */ +struct pmcraid_cmd { + + /* Ptr and bus address of DMA.able control block for this command */ + struct pmcraid_control_block *ioa_cb; + dma_addr_t ioa_cb_bus_addr; + + /* sense buffer for REQUEST SENSE command if firmware is not sending + * auto sense data + */ + dma_addr_t sense_buffer_dma; + dma_addr_t dma_handle; + u8 *sense_buffer; + + /* pointer to mid layer structure of SCSI commands */ + struct scsi_cmnd *scsi_cmd; + + struct list_head free_list; + struct completion wait_for_completion; + struct timer_list timer; /* needed for internal commands */ + u32 timeout; /* current timeout value */ + u32 index; /* index into the command list */ + u8 completion_req; /* for handling internal commands */ + u8 release; /* for handling completions */ + + void (*cmd_done) (struct pmcraid_cmd *); + struct pmcraid_instance *drv_inst; + + struct pmcraid_sglist *sglist; /* used for passthrough IOCTLs */ + + /* scratch used during reset sequence */ + union { + unsigned long time_left; + struct pmcraid_resource_entry *res; + } u; +}; + +/* + * Interrupt registers of IOA + */ +struct pmcraid_interrupts { + void __iomem *ioa_host_interrupt_reg; + void __iomem *ioa_host_interrupt_clr_reg; + void __iomem *ioa_host_interrupt_mask_reg; + void __iomem *ioa_host_interrupt_mask_clr_reg; + void __iomem *global_interrupt_mask_reg; + void __iomem *host_ioa_interrupt_reg; + void __iomem *host_ioa_interrupt_clr_reg; +}; + +/* ISR parameters LLD allocates (one for each MSI-X if enabled) vectors */ +struct pmcraid_isr_param { + u8 hrrq_id; /* hrrq entry index */ + u16 vector; /* allocated msi-x vector */ + struct pmcraid_instance *drv_inst; +}; + +/* AEN message header sent as part of event data to applications */ +struct pmcraid_aen_msg { + u32 hostno; + u32 length; + u8 reserved[8]; + u8 data[0]; +}; + +struct pmcraid_hostrcb { + struct pmcraid_instance *drv_inst; + struct pmcraid_aen_msg *msg; + struct pmcraid_hcam_hdr *hcam; /* pointer to hcam buffer */ + struct pmcraid_cmd *cmd; /* pointer to command block used */ + dma_addr_t baddr; /* system address of hcam buffer */ + atomic_t ignore; /* process HCAM response ? */ +}; + +#define PMCRAID_AEN_HDR_SIZE sizeof(struct pmcraid_aen_msg) + + + +/* + * Per adapter structure maintained by LLD + */ +struct pmcraid_instance { + /* Array of allowed-to-be-exposed resources, initialized from + * Configutation Table, later updated with CCNs + */ + struct pmcraid_resource_entry *res_entries; + + struct list_head free_res_q; /* res_entries lists for easy lookup */ + struct list_head used_res_q; /* List of to be exposed resources */ + spinlock_t resource_lock; /* spinlock to protect resource list */ + + void __iomem *mapped_dma_addr; + void __iomem *ioa_status; /* Iomapped IOA status register */ + void __iomem *mailbox; /* Iomapped mailbox register */ + void __iomem *ioarrin; /* IOmapped IOARR IN register */ + + struct pmcraid_interrupts int_regs; + struct pmcraid_chip_details *chip_cfg; + + /* HostRCBs needed for HCAM */ + struct pmcraid_hostrcb ldn; + struct pmcraid_hostrcb ccn; + + + /* Bus address of start of HRRQ */ + dma_addr_t hrrq_start_bus_addr[PMCRAID_NUM_MSIX_VECTORS]; + + /* Pointer to 1st entry of HRRQ */ + __be32 *hrrq_start[PMCRAID_NUM_MSIX_VECTORS]; + + /* Pointer to last entry of HRRQ */ + __be32 *hrrq_end[PMCRAID_NUM_MSIX_VECTORS]; + + /* Pointer to current pointer of hrrq */ + __be32 *hrrq_curr[PMCRAID_NUM_MSIX_VECTORS]; + + /* Lock for HRRQ access */ + spinlock_t hrrq_lock[PMCRAID_NUM_MSIX_VECTORS]; + + /* Expected toggle bit at host */ + u8 host_toggle_bit[PMCRAID_NUM_MSIX_VECTORS]; + + /* No of Reset IOA retries . IOA marked dead if threshold exceeds */ + u8 ioa_reset_attempts; +#define PMCRAID_RESET_ATTEMPTS 3 + + /* Wait Q for threads to wait for Reset IOA completion */ + wait_queue_head_t reset_wait_q; + struct pmcraid_cmd *reset_cmd; + + /* structures for supporting SIGIO based AEN. */ + struct fasync_struct *aen_queue; + struct mutex aen_queue_lock; /* lock for aen subscribers list */ + struct cdev cdev; + + struct Scsi_Host *host; /* mid layer interface structure handle */ + struct pci_dev *pdev; /* PCI device structure handle */ + + u8 current_log_level; /* default level for logging IOASC errors */ + + u8 num_hrrq; /* Number of interrupt vectors allocated */ + dev_t dev; /* Major-Minor numbers for Char device */ + + /* Used as ISR handler argument */ + struct pmcraid_isr_param hrrq_vector[PMCRAID_NUM_MSIX_VECTORS]; + + /* configuration table */ + struct pmcraid_config_table *cfg_table; + dma_addr_t cfg_table_bus_addr; + + /* structures related to command blocks */ + struct kmem_cache *cmd_cachep; /* cache for cmd blocks */ + struct pci_pool *control_pool; /* pool for control blocks */ + char cmd_pool_name[64]; /* name of cmd cache */ + char ctl_pool_name[64]; /* name of control cache */ + + struct pmcraid_cmd *cmd_list[PMCRAID_MAX_CMD]; + + struct list_head free_cmd_pool; + struct list_head pending_cmd_pool; + spinlock_t free_pool_lock; /* free pool lock */ + spinlock_t pending_pool_lock; /* pending pool lock */ + + /* No of IO commands pending with FW */ + atomic_t outstanding_cmds; + + /* should add/delete resources to mid-layer now ?*/ + atomic_t expose_resources; + + /* Tasklet to handle deferred processing */ + struct tasklet_struct isr_tasklet[PMCRAID_NUM_MSIX_VECTORS]; + + /* Work-queue (Shared) for deferred reset processing */ + struct work_struct worker_q; + + + u32 ioa_state:4; /* For IOA Reset sequence FSM */ +#define IOA_STATE_OPERATIONAL 0x0 +#define IOA_STATE_UNKNOWN 0x1 +#define IOA_STATE_DEAD 0x2 +#define IOA_STATE_IN_SOFT_RESET 0x3 +#define IOA_STATE_IN_HARD_RESET 0x4 +#define IOA_STATE_IN_RESET_ALERT 0x5 +#define IOA_STATE_IN_BRINGDOWN 0x6 +#define IOA_STATE_IN_BRINGUP 0x7 + + u32 ioa_reset_in_progress:1; /* true if IOA reset is in progress */ + u32 ioa_hard_reset:1; /* TRUE if Hard Reset is needed */ + u32 ioa_unit_check:1; /* Indicates Unit Check condition */ + u32 ioa_bringdown:1; /* whether IOA needs to be brought down */ + u32 force_ioa_reset:1; /* force adapter reset ? */ + u32 reinit_cfg_table:1; /* reinit config table due to lost CCN */ + u32 ioa_shutdown_type:2;/* shutdown type used during reset */ +#define SHUTDOWN_NONE 0x0 +#define SHUTDOWN_NORMAL 0x1 +#define SHUTDOWN_ABBREV 0x2 + +}; + +/* LLD maintained resource entry structure */ +struct pmcraid_resource_entry { + struct list_head queue; /* link to "to be exposed" resources */ + struct pmcraid_config_table_entry cfg_entry; + struct scsi_device *scsi_dev; /* Link scsi_device structure */ + atomic_t read_failures; /* count of failed READ commands */ + atomic_t write_failures; /* count of failed WRITE commands */ + + /* To indicate add/delete/modify during CCN */ + u8 change_detected; +#define RES_CHANGE_ADD 0x1 /* add this to mid-layer */ +#define RES_CHANGE_DEL 0x2 /* remove this from mid-layer */ + + u8 reset_progress; /* Device is resetting */ + + /* + * When IOA asks for sync (i.e. IOASC = Not Ready, Sync Required), this + * flag will be set, mid layer will be asked to retry. In the next + * attempt, this flag will be checked in queuecommand() to set + * SYNC_COMPLETE flag in IOARCB (flag_0). + */ + u8 sync_reqd; + + /* target indicates the mapped target_id assigned to this resource if + * this is VSET resource. For non-VSET resources this will be un-used + * or zero + */ + u8 target; +}; + +/* Data structures used in IOASC error code logging */ +struct pmcraid_ioasc_error { + u32 ioasc_code; /* IOASC code */ + u8 log_level; /* default log level assignment. */ + char *error_string; +}; + +/* Initial log_level assignments for various IOASCs */ +#define IOASC_LOG_LEVEL_NONE 0x0 /* no logging */ +#define IOASC_LOG_LEVEL_MUST 0x1 /* must log: all high-severity errors */ +#define IOASC_LOG_LEVEL_HARD 0x2 /* optional – low severity errors */ + +/* Error information maintained by LLD. LLD initializes the pmcraid_error_table + * statically. + */ +static struct pmcraid_ioasc_error pmcraid_ioasc_error_table[] = { + {0x01180600, IOASC_LOG_LEVEL_MUST, + "Recovered Error, soft media error, sector reassignment suggested"}, + {0x015D0000, IOASC_LOG_LEVEL_MUST, + "Recovered Error, failure prediction thresold exceeded"}, + {0x015D9200, IOASC_LOG_LEVEL_MUST, + "Recovered Error, soft Cache Card Battery error thresold"}, + {0x015D9200, IOASC_LOG_LEVEL_MUST, + "Recovered Error, soft Cache Card Battery error thresold"}, + {0x02048000, IOASC_LOG_LEVEL_MUST, + "Not Ready, IOA Reset Required"}, + {0x02408500, IOASC_LOG_LEVEL_MUST, + "Not Ready, IOA microcode download required"}, + {0x03110B00, IOASC_LOG_LEVEL_MUST, + "Medium Error, data unreadable, reassignment suggested"}, + {0x03110C00, IOASC_LOG_LEVEL_MUST, + "Medium Error, data unreadable do not reassign"}, + {0x03310000, IOASC_LOG_LEVEL_MUST, + "Medium Error, media corrupted"}, + {0x04050000, IOASC_LOG_LEVEL_MUST, + "Hardware Error, IOA can't communicate with device"}, + {0x04080000, IOASC_LOG_LEVEL_MUST, + "Hardware Error, device bus error"}, + {0x04080000, IOASC_LOG_LEVEL_MUST, + "Hardware Error, device bus is not functioning"}, + {0x04118000, IOASC_LOG_LEVEL_MUST, + "Hardware Error, IOA reserved area data check"}, + {0x04118100, IOASC_LOG_LEVEL_MUST, + "Hardware Error, IOA reserved area invalid data pattern"}, + {0x04118200, IOASC_LOG_LEVEL_MUST, + "Hardware Error, IOA reserved area LRC error"}, + {0x04320000, IOASC_LOG_LEVEL_MUST, + "Hardware Error, reassignment space exhausted"}, + {0x04330000, IOASC_LOG_LEVEL_MUST, + "Hardware Error, data transfer underlength error"}, + {0x04330000, IOASC_LOG_LEVEL_MUST, + "Hardware Error, data transfer overlength error"}, + {0x04418000, IOASC_LOG_LEVEL_MUST, + "Hardware Error, PCI bus error"}, + {0x04440000, IOASC_LOG_LEVEL_MUST, + "Hardware Error, device error"}, + {0x04448300, IOASC_LOG_LEVEL_MUST, + "Hardware Error, undefined device response"}, + {0x04448400, IOASC_LOG_LEVEL_MUST, + "Hardware Error, IOA microcode error"}, + {0x04448600, IOASC_LOG_LEVEL_MUST, + "Hardware Error, IOA reset required"}, + {0x04449200, IOASC_LOG_LEVEL_MUST, + "Hardware Error, hard Cache Fearuee Card Battery error"}, + {0x0444A000, IOASC_LOG_LEVEL_MUST, + "Hardware Error, failed device altered"}, + {0x0444A200, IOASC_LOG_LEVEL_MUST, + "Hardware Error, data check after reassignment"}, + {0x0444A300, IOASC_LOG_LEVEL_MUST, + "Hardware Error, LRC error after reassignment"}, + {0x044A0000, IOASC_LOG_LEVEL_MUST, + "Hardware Error, device bus error (msg/cmd phase)"}, + {0x04670400, IOASC_LOG_LEVEL_MUST, + "Hardware Error, new device can't be used"}, + {0x04678000, IOASC_LOG_LEVEL_MUST, + "Hardware Error, invalid multiadapter configuration"}, + {0x04678100, IOASC_LOG_LEVEL_MUST, + "Hardware Error, incorrect connection between enclosures"}, + {0x04678200, IOASC_LOG_LEVEL_MUST, + "Hardware Error, connections exceed IOA design limits"}, + {0x04678300, IOASC_LOG_LEVEL_MUST, + "Hardware Error, incorrect multipath connection"}, + {0x04679000, IOASC_LOG_LEVEL_MUST, + "Hardware Error, command to LUN failed"}, + {0x064C8000, IOASC_LOG_LEVEL_HARD, + "Unit Attention, cache exists for missing/failed device"}, + {0x06670100, IOASC_LOG_LEVEL_HARD, + "Unit Attention, incompatible exposed mode device"}, + {0x06670600, IOASC_LOG_LEVEL_HARD, + "Unit Attention, attachment of logical unit failed"}, + {0x06678000, IOASC_LOG_LEVEL_MUST, + "Unit Attention, cables exceed connective design limit"}, + {0x06678300, IOASC_LOG_LEVEL_MUST, + "Unit Attention, incomplete multipath connection between" \ + "IOA and enclosure"}, + {0x06678400, IOASC_LOG_LEVEL_MUST, + "Unit Attention, incomplete multipath connection between" \ + "device and enclosure"}, + {0x06678500, IOASC_LOG_LEVEL_MUST, + "Unit Attention, incomplete multipath connection between" \ + "IOA and remote IOA"}, + {0x06678600, IOASC_LOG_LEVEL_HARD, + "Unit Attention, missing remote IOA"}, + {0x06679100, IOASC_LOG_LEVEL_HARD, + "Unit Attention, enclosure doesn't support required multipath" \ + "function"}, + {0x06698200, IOASC_LOG_LEVEL_HARD, + "Unit Attention, corrupt array parity detected on device"}, + {0x066B0200, IOASC_LOG_LEVEL_MUST, + "Unit Attention, array exposed"}, + {0x066B8200, IOASC_LOG_LEVEL_HARD, + "Unit Attention, exposed array is still protected"}, + {0x066B9200, IOASC_LOG_LEVEL_MUST, + "Unit Attention, Multipath redundancy level got worse"}, + {0x07270000, IOASC_LOG_LEVEL_HARD, + "Data Protect, device is read/write protected by IOA"}, + {0x07278000, IOASC_LOG_LEVEL_HARD, + "Data Protect, IOA doesn't support device attribute"}, + {0x07278100, IOASC_LOG_LEVEL_HARD, + "Data Protect, NVRAM mirroring prohibited"}, + {0x07278400, IOASC_LOG_LEVEL_MUST, + "Data Protect, array is short 2 or more devices"}, + {0x07278600, IOASC_LOG_LEVEL_MUST, + "Data Protect, exposed array is short a required device"}, + {0x07278700, IOASC_LOG_LEVEL_MUST, + "Data Protect, array members not at required addresses"}, + {0x07278800, IOASC_LOG_LEVEL_MUST, + "Data Protect, exposed mode device resource address conflict"}, + {0x07278900, IOASC_LOG_LEVEL_MUST, + "Data Protect, incorrect resource address of exposed mode device"}, + {0x07278A00, IOASC_LOG_LEVEL_MUST, + "Data Protect, Array is missing a device and parity is out of sync"}, + {0x07278B00, IOASC_LOG_LEVEL_MUST, + "Data Protect, maximum number of arrays already exist"}, + {0x07278C00, IOASC_LOG_LEVEL_HARD, + "Data Protect, cannot locate cache data for device"}, + {0x07278D00, IOASC_LOG_LEVEL_HARD, + "Data Protect, cache data exits for a changed device"}, + {0x07279100, IOASC_LOG_LEVEL_MUST, + "Data Protect, detection of a device requiring format"}, + {0x07279200, IOASC_LOG_LEVEL_MUST, + "Data Protect, IOA exceeds maximum number of devices"}, + {0x07279600, IOASC_LOG_LEVEL_MUST, + "Data Protect, missing array, volume set is not functional"}, + {0x07279700, IOASC_LOG_LEVEL_MUST, + "Data Protect, single device for a volume set"}, + {0x07279800, IOASC_LOG_LEVEL_MUST, + "Data Protect, missing multiple devices for a volume set"}, + {0x07279900, IOASC_LOG_LEVEL_HARD, + "Data Protect, maximum number of volument sets already exists"}, + {0x07279A00, IOASC_LOG_LEVEL_MUST, + "Data Protect, other volume set problem"}, +}; + +/* macros to help in debugging */ +#define pmcraid_err(...) \ + printk(KERN_ERR "MaxRAID: "__VA_ARGS__) + +#define pmcraid_info(...) \ + if (pmcraid_debug_log) \ + printk(KERN_INFO "MaxRAID: "__VA_ARGS__) + +/* check if given command is a SCSI READ or SCSI WRITE command */ +#define SCSI_READ_CMD 0x1 /* any of SCSI READ commands */ +#define SCSI_WRITE_CMD 0x2 /* any of SCSI WRITE commands */ +#define SCSI_CMD_TYPE(opcode) \ +({ u8 op = opcode; u8 __type = 0;\ + if (op == READ_6 || op == READ_10 || op == READ_12 || op == READ_16)\ + __type = SCSI_READ_CMD;\ + else if (op == WRITE_6 || op == WRITE_10 || op == WRITE_12 || \ + op == WRITE_16)\ + __type = SCSI_WRITE_CMD;\ + __type;\ +}) + +#define IS_SCSI_READ_WRITE(opcode) \ +({ u8 __type = SCSI_CMD_TYPE(opcode); \ + (__type == SCSI_READ_CMD || __type == SCSI_WRITE_CMD) ? 1 : 0;\ +}) + + +/* + * pmcraid_ioctl_header - definition of header structure that preceeds all the + * buffers given as ioctl arguements. + * + * .signature : always ASCII string, "PMCRAID" + * .reserved : not used + * .buffer_length : length of the buffer following the header + */ +struct pmcraid_ioctl_header { + u8 signature[8]; + u32 reserved; + u32 buffer_length; +}; + +#define PMCRAID_IOCTL_SIGNATURE "PMCRAID" + + +/* + * pmcraid_event_details - defines AEN details that apps can retrieve from LLD + * + * .rcb_ccn - complete RCB of CCN + * .rcb_ldn - complete RCB of CCN + */ +struct pmcraid_event_details { + struct pmcraid_hcam_ccn rcb_ccn; + struct pmcraid_hcam_ldn rcb_ldn; +}; + +/* + * pmcraid_driver_ioctl_buffer - structure passed as argument to most of the + * PMC driver handled ioctls. + */ +struct pmcraid_driver_ioctl_buffer { + struct pmcraid_ioctl_header ioctl_header; + struct pmcraid_event_details event_details; +}; + +/* + * pmcraid_passthrough_ioctl_buffer - structure given as argument to + * passthrough(or firmware handled) IOCTL commands. Note that ioarcb requires + * 32-byte alignment so, it is necessary to pack this structure to avoid any + * holes between ioctl_header and passthrough buffer + * + * .ioactl_header : ioctl header + * .ioarcb : filled-up ioarcb buffer, driver always reads this buffer + * .ioasa : buffer for ioasa, driver fills this with IOASA from firmware + * .request_buffer: The I/O buffer (flat), driver reads/writes to this based on + * the transfer directions passed in ioarcb.flags0. Contents + * of this buffer are valid only when ioarcb.data_transfer_len + * is not zero. + */ +struct pmcraid_passthrough_ioctl_buffer { + struct pmcraid_ioctl_header ioctl_header; + struct pmcraid_ioarcb ioarcb; + struct pmcraid_ioasa ioasa; + u8 request_buffer[1]; +} __attribute__ ((packed)); + +/* + * keys to differentiate between driver handled IOCTLs and passthrough + * IOCTLs passed to IOA. driver determines the ioctl type using macro + * _IOC_TYPE + */ +#define PMCRAID_DRIVER_IOCTL 'D' +#define PMCRAID_PASSTHROUGH_IOCTL 'F' + +#define DRV_IOCTL(n, size) \ + _IOC(_IOC_READ|_IOC_WRITE, PMCRAID_DRIVER_IOCTL, (n), (size)) + +#define FMW_IOCTL(n, size) \ + _IOC(_IOC_READ|_IOC_WRITE, PMCRAID_PASSTHROUGH_IOCTL, (n), (size)) + +/* + * _ARGSIZE: macro that gives size of the argument type passed to an IOCTL cmd. + * This is to facilitate applications avoiding un-necessary memory allocations. + * For example, most of driver handled ioctls do not require ioarcb, ioasa. + */ +#define _ARGSIZE(arg) (sizeof(struct pmcraid_ioctl_header) + sizeof(arg)) + +/* Driver handled IOCTL command definitions */ + +#define PMCRAID_IOCTL_RESET_ADAPTER \ + DRV_IOCTL(5, sizeof(struct pmcraid_ioctl_header)) + +/* passthrough/firmware handled commands */ +#define PMCRAID_IOCTL_PASSTHROUGH_COMMAND \ + FMW_IOCTL(1, sizeof(struct pmcraid_passthrough_ioctl_buffer)) + +#define PMCRAID_IOCTL_DOWNLOAD_MICROCODE \ + FMW_IOCTL(2, sizeof(struct pmcraid_passthrough_ioctl_buffer)) + + +#endif /* _PMCRAID_H */ -- cgit v1.2.3-18-g5258 From 5bab08858cecaacba803e8c90638db14bde470c0 Mon Sep 17 00:00:00 2001 From: Charlie Brady Date: Wed, 26 Aug 2009 14:16:57 -0400 Subject: [SCSI] scsi_dh_rdac: Add support for Sun StorageTek ST2500, ST2510 and ST2530 These storage arrays can use RDAC when configured with 'linux' as the initiator. http://www.sun.com/storage/disk_systems/workgroup/2500/ http://www.sun.com/storage/disk_systems/workgroup/2510/ http://www.sun.com/storage/disk_systems/workgroup/2530/ Signed-off-by: Charlie Brady Reviewed-by: Chandra Seetharaman Signed-off-by: James Bottomley --- drivers/scsi/device_handler/scsi_dh_rdac.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 872292f659c..8b9e14318d1 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -628,6 +628,9 @@ static const struct scsi_dh_devlist rdac_dev_list[] = { {"SGI", "IS"}, {"STK", "OPENstorage D280"}, {"SUN", "CSM200_R"}, + {"SUN", "LCSM100_I"}, + {"SUN", "LCSM100_S"}, + {"SUN", "LCSM100_E"}, {"SUN", "LCSM100_F"}, {"DELL", "MD3000"}, {"DELL", "MD3000i"}, -- cgit v1.2.3-18-g5258 From 9e39089b958818c8f3d772414cd27f84fb2622f2 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 2 Sep 2009 11:43:36 +0530 Subject: [SCSI] mptsas : Sanity check for phyinfo is added Check for phyinfo->phy before calling sas_port_delete_phy. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptsas.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 21bd78e4f30..f744f0fc949 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -852,7 +852,13 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) port_details->num_phys--; port_details->phy_bitmask &= ~ (1 << phy_info->phy_id); memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); - sas_port_delete_phy(port_details->port, phy_info->phy); + if (phy_info->phy) { + devtprintk(ioc, dev_printk(KERN_DEBUG, + &phy_info->phy->dev, MYIOC_s_FMT + "delete phy %d, phy-obj (0x%p)\n", ioc->name, + phy_info->phy_id, phy_info->phy)); + sas_port_delete_phy(port_details->port, phy_info->phy); + } phy_info->port_details = NULL; } -- cgit v1.2.3-18-g5258 From f44fd18198eb26b62ba86b17016e9441ce95fc71 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 2 Sep 2009 11:44:19 +0530 Subject: [SCSI] mptsas : NULL pointer on big endian systems causing Expander not to tear off On Big endian system kernel will crash due to address translation is not handle properly. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptsas.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index f744f0fc949..02a18dfcd52 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -3314,6 +3314,7 @@ mptsas_send_expander_event(struct fw_event_work *fw_event) expander_data = (MpiEventDataSasExpanderStatusChange_t *) fw_event->event_data; memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); + sas_address = le64_to_cpu(sas_address); port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) { -- cgit v1.2.3-18-g5258 From c55b89fba9872ebcd5ac15cdfdad29ffb89329f0 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 2 Sep 2009 11:44:57 +0530 Subject: [SCSI] mptsas : PAE Kernel more than 4 GB kernel panic This patch is solving problem for PAE kernel DMA operation. On PAE system dma_addr and unsigned long will have different values. Now dma_addr is not type casted using unsigned long. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 8ab7b37ed70..76fa2ee0b57 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -1015,9 +1015,9 @@ mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr) { SGESimple64_t *pSge = (SGESimple64_t *) pAddr; pSge->Address.Low = cpu_to_le32 - (lower_32_bits((unsigned long)(dma_addr))); + (lower_32_bits(dma_addr)); pSge->Address.High = cpu_to_le32 - (upper_32_bits((unsigned long)dma_addr)); + (upper_32_bits(dma_addr)); pSge->FlagsLength = cpu_to_le32 ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING)); } @@ -1038,8 +1038,8 @@ mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr) u32 tmp; pSge->Address.Low = cpu_to_le32 - (lower_32_bits((unsigned long)(dma_addr))); - tmp = (u32)(upper_32_bits((unsigned long)dma_addr)); + (lower_32_bits(dma_addr)); + tmp = (u32)(upper_32_bits(dma_addr)); /* * 1078 errata workaround for the 36GB limitation @@ -1101,7 +1101,7 @@ mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr) pChain->NextChainOffset = next; pChain->Address.Low = cpu_to_le32(tmp); - tmp = (u32)(upper_32_bits((unsigned long)dma_addr)); + tmp = (u32)(upper_32_bits(dma_addr)); pChain->Address.High = cpu_to_le32(tmp); } -- cgit v1.2.3-18-g5258 From fea984034b1ccdb26e8163ed5350ce7f0563b136 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 2 Sep 2009 11:45:53 +0530 Subject: [SCSI] mptsas : Send DID_NO_CONNECT for pending IOs of removed device Driver is modified to return DID_NO_CONNECT for all pending I/O requests for bus type SAS, if it founds the target is removed at the firmware level. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptscsih.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 0e402eb9571..c2957861450 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -628,6 +628,16 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) return 1; } + if (ioc->bus_type == SAS) { + VirtDevice *vdevice = sc->device->hostdata; + + if (!vdevice || !vdevice->vtarget || + vdevice->vtarget->deleted) { + sc->result = DID_NO_CONNECT << 16; + goto out; + } + } + sc->host_scribble = NULL; sc->result = DID_OK << 16; /* Set default reply as OK */ pScsiReq = (SCSIIORequest_t *) mf; @@ -892,7 +902,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) #endif } /* end of address reply case */ - +out: /* Unmap the DMA buffers, if any. */ scsi_dma_unmap(sc); -- cgit v1.2.3-18-g5258 From 9766096d331c82e71d3c9df61f1c88eff6ad916b Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 2 Sep 2009 11:46:33 +0530 Subject: [SCSI] mptsas : FW event thread and scsi mid layer deadlock in SYNCHRONIZE CACHE command Normally In HBA reset path MPT driver will flush existing work in current work queue (mpt/0) . This is just a dummy activity for MPT driver point of view, since HBA reset will turn off Work queue events. It means we will simply returns from work queue without doing anything. But for the case where Work is already done (half the way), we have to have that work to be done. Considering above condition we stuck forever since Deadlock in scsi midlayer and MPT driver. sd_sync_cache() will wait forever since HBA is not in Running state, and it will never come into Running state since sd_sync_cache() is called from HBA reset context. Now new code will not wait for half cooked work to be finished before returning from HBA reset. Once we are out of HBA reset, EH thread will change host state to running from recovery and work waiting for running state of HBA will be finished. New code is turning ON firmware event from another special work called Rescan toplogy. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptsas.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 02a18dfcd52..83873e3d0ce 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -325,7 +325,6 @@ mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc) { struct fw_event_work *fw_event, *next; struct mptsas_target_reset_event *target_reset_list, *n; - u8 flush_q; MPT_SCSI_HOST *hd = shost_priv(ioc->sh); /* flush the target_reset_list */ @@ -345,15 +344,10 @@ mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc) !ioc->fw_event_q || in_interrupt()) return; - flush_q = 0; list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) { if (cancel_delayed_work(&fw_event->work)) mptsas_free_fw_event(ioc, fw_event); - else - flush_q = 1; } - if (flush_q) - flush_workqueue(ioc->fw_event_q); } @@ -1279,7 +1273,6 @@ mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) } mptsas_cleanup_fw_event_q(ioc); mptsas_queue_rescan(ioc); - mptsas_fw_event_on(ioc); break; default: break; @@ -1599,6 +1592,7 @@ mptsas_firmware_event_work(struct work_struct *work) mptsas_scan_sas_topology(ioc); ioc->in_rescan = 0; mptsas_free_fw_event(ioc, fw_event); + mptsas_fw_event_on(ioc); return; } -- cgit v1.2.3-18-g5258 From b437b95620dbf4bf7bd13af0f9d32fdac82c5d37 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Wed, 2 Sep 2009 12:44:10 +0530 Subject: [SCSI] mptsas : Bump version to 3.04.12 Bump version to 3.04.12 Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 79b17ceb714..8dd4d219e43 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -76,8 +76,8 @@ #define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.04.11" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.11" +#define MPT_LINUX_VERSION_COMMON "3.04.12" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.12" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ -- cgit v1.2.3-18-g5258 From e71044ee2efa4792e21d243b03d49006db66aec9 Mon Sep 17 00:00:00 2001 From: Michal Schmidt Date: Thu, 3 Sep 2009 14:27:08 +0200 Subject: [SCSI] sg: fix oops in the error path in sg_build_indirect() When the allocation fails in sg_build_indirect(), an oops happens in the error path. It's caused by an obvious typo. Signed-off-by: Michal Schmidt Reported-by: Bob Tracy Acked-by: Douglas Gilbert Cc: Stable Tree Signed-off-by: James Bottomley --- drivers/scsi/sg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 9230402c45a..4968c4ced38 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1811,7 +1811,7 @@ retry: return 0; out: for (i = 0; i < k; i++) - __free_pages(schp->pages[k], order); + __free_pages(schp->pages[i], order); if (--order >= 0) goto retry; -- cgit v1.2.3-18-g5258 From 87b79a53277c21a2de07106d0affa857bd79e1bb Mon Sep 17 00:00:00 2001 From: "Moger, Babu" Date: Thu, 3 Sep 2009 21:42:15 -0600 Subject: [SCSI] scsi_dh_rdac: move the init code from rdac_activate to rdac_bus_attach Moving the initialization code from rdac_activate to rdac_bus_attach which is more efficient. We don't have to collect all the information during every activate. Signed-off-by: Babu Moger Reviewed-by: Vijay Chauhan Reviewed-by: Bob Stankey Signed-off-by: James Bottomley --- drivers/scsi/device_handler/scsi_dh_rdac.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 8b9e14318d1..c5e4476e912 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -525,17 +525,6 @@ static int rdac_activate(struct scsi_device *sdev) if (err != SCSI_DH_OK) goto done; - if (!h->ctlr) { - err = initialize_controller(sdev, h); - if (err != SCSI_DH_OK) - goto done; - } - - if (h->ctlr->use_ms10 == -1) { - err = set_mode_select(sdev, h); - if (err != SCSI_DH_OK) - goto done; - } if (h->lun_state == RDAC_LUN_UNOWNED) err = send_mode_select(sdev, h); done: @@ -681,12 +670,20 @@ static int rdac_bus_attach(struct scsi_device *sdev) if (err != SCSI_DH_OK) goto failed; - err = check_ownership(sdev, h); + err = initialize_controller(sdev, h); if (err != SCSI_DH_OK) goto failed; + err = check_ownership(sdev, h); + if (err != SCSI_DH_OK) + goto clean_ctlr; + + err = set_mode_select(sdev, h); + if (err != SCSI_DH_OK) + goto clean_ctlr; + if (!try_module_get(THIS_MODULE)) - goto failed; + goto clean_ctlr; spin_lock_irqsave(sdev->request_queue->queue_lock, flags); sdev->scsi_dh_data = scsi_dh_data; @@ -698,6 +695,9 @@ static int rdac_bus_attach(struct scsi_device *sdev) return 0; +clean_ctlr: + kref_put(&h->ctlr->kref, release_controller); + failed: kfree(scsi_dh_data); sdev_printk(KERN_ERR, sdev, "%s: not attached\n", -- cgit v1.2.3-18-g5258 From 1527666e6af977cc287e0f7088356c8be29b3f75 Mon Sep 17 00:00:00 2001 From: "Moger, Babu" Date: Thu, 3 Sep 2009 21:42:21 -0600 Subject: [SCSI] scsi_dh_rdac: changes to collect the rdac debug information during the initialization Adding the code to read the debug information during initialization. This patch collects the information about storage and controllers during rdac_activate. Signed-off-by: Babu Moger Reviewed-by: Vijay Chauhan Reviewed-by: Bob Stankey Signed-off-by: James Bottomley --- drivers/scsi/device_handler/scsi_dh_rdac.c | 34 ++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index c5e4476e912..9f1c4c2df92 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -112,6 +112,7 @@ struct c9_inquiry { #define SUBSYS_ID_LEN 16 #define SLOT_ID_LEN 2 +#define ARRAY_LABEL_LEN 31 struct c4_inquiry { u8 peripheral_info; @@ -135,6 +136,8 @@ struct rdac_controller { struct rdac_pg_legacy legacy; struct rdac_pg_expanded expanded; } mode_select; + u8 index; + u8 array_name[ARRAY_LABEL_LEN]; }; struct c8_inquiry { u8 peripheral_info; @@ -303,7 +306,8 @@ static void release_controller(struct kref *kref) kfree(ctlr); } -static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id) +static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id, + char *array_name) { struct rdac_controller *ctlr, *tmp; @@ -324,6 +328,14 @@ static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id) /* initialize fields of controller */ memcpy(ctlr->subsys_id, subsys_id, SUBSYS_ID_LEN); memcpy(ctlr->slot_id, slot_id, SLOT_ID_LEN); + memcpy(ctlr->array_name, array_name, ARRAY_LABEL_LEN); + + /* update the controller index */ + if (slot_id[1] == 0x31) + ctlr->index = 0; + else + ctlr->index = 1; + kref_init(&ctlr->kref); ctlr->use_ms10 = -1; list_add(&ctlr->node, &ctlr_list); @@ -363,9 +375,10 @@ done: return err; } -static int get_lun(struct scsi_device *sdev, struct rdac_dh_data *h) +static int get_lun_info(struct scsi_device *sdev, struct rdac_dh_data *h, + char *array_name) { - int err; + int err, i; struct c8_inquiry *inqp; err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry), h); @@ -377,6 +390,11 @@ static int get_lun(struct scsi_device *sdev, struct rdac_dh_data *h) inqp->page_id[2] != 'i' || inqp->page_id[3] != 'd') return SCSI_DH_NOSYS; h->lun = inqp->lun[7]; /* Uses only the last byte */ + + for(i=0; iarray_user_label[(2*i)+1]; + + *(array_name+ARRAY_LABEL_LEN-1) = '\0'; } return err; } @@ -410,7 +428,7 @@ static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h) } static int initialize_controller(struct scsi_device *sdev, - struct rdac_dh_data *h) + struct rdac_dh_data *h, char *array_name) { int err; struct c4_inquiry *inqp; @@ -418,7 +436,8 @@ static int initialize_controller(struct scsi_device *sdev, err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry), h); if (err == SCSI_DH_OK) { inqp = &h->inq.c4; - h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id); + h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id, + array_name); if (!h->ctlr) err = SCSI_DH_RES_TEMP_UNAVAIL; } @@ -652,6 +671,7 @@ static int rdac_bus_attach(struct scsi_device *sdev) struct rdac_dh_data *h; unsigned long flags; int err; + char array_name[ARRAY_LABEL_LEN]; scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) + sizeof(*h) , GFP_KERNEL); @@ -666,11 +686,11 @@ static int rdac_bus_attach(struct scsi_device *sdev) h->lun = UNINITIALIZED_LUN; h->state = RDAC_STATE_ACTIVE; - err = get_lun(sdev, h); + err = get_lun_info(sdev, h, array_name); if (err != SCSI_DH_OK) goto failed; - err = initialize_controller(sdev, h); + err = initialize_controller(sdev, h, array_name); if (err != SCSI_DH_OK) goto failed; -- cgit v1.2.3-18-g5258 From dd784edcfc080fb4c83f1f3d10d905c5ab61616f Mon Sep 17 00:00:00 2001 From: "Moger, Babu" Date: Thu, 3 Sep 2009 21:42:28 -0600 Subject: [SCSI] scsi_dh_rdac: changes for rdac debug logging Patch to add debugging stuff for rdac device handler. - Added a bit mask "module parameter" rdac_logging with 2 bits for each type of logging. - currently defined only two types of logging(failover and sense logging). Can be enhanced later if required. - By default only failover logging is enabled which is equivalent of current logging. Signed-off-by: Babu Moger Reviewed-by: Vijay Chauhan Reviewed-by: Bob Stankey Signed-off-by: James Bottomley --- drivers/scsi/device_handler/scsi_dh_rdac.c | 51 +++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 9f1c4c2df92..11c89311427 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -201,6 +201,31 @@ static const char *lun_state[] = static LIST_HEAD(ctlr_list); static DEFINE_SPINLOCK(list_lock); +/* + * module parameter to enable rdac debug logging. + * 2 bits for each type of logging, only two types defined for now + * Can be enhanced if required at later point + */ +static int rdac_logging = 1; +module_param(rdac_logging, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(rdac_logging, "A bit mask of rdac logging levels, " + "Default is 1 - failover logging enabled, " + "set it to 0xF to enable all the logs"); + +#define RDAC_LOG_FAILOVER 0 +#define RDAC_LOG_SENSE 2 + +#define RDAC_LOG_BITS 2 + +#define RDAC_LOG_LEVEL(SHIFT) \ + ((rdac_logging >> (SHIFT)) & ((1 << (RDAC_LOG_BITS)) - 1)) + +#define RDAC_LOG(SHIFT, sdev, f, arg...) \ +do { \ + if (unlikely(RDAC_LOG_LEVEL(SHIFT))) \ + sdev_printk(KERN_INFO, sdev, RDAC_NAME ": " f "\n", ## arg); \ +} while (0); + static inline struct rdac_dh_data *get_rdac_data(struct scsi_device *sdev) { struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; @@ -469,6 +494,7 @@ static int mode_select_handle_sense(struct scsi_device *sdev, { struct scsi_sense_hdr sense_hdr; int err = SCSI_DH_IO, ret; + struct rdac_dh_data *h = get_rdac_data(sdev); ret = scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE, &sense_hdr); if (!ret) @@ -497,11 +523,14 @@ static int mode_select_handle_sense(struct scsi_device *sdev, err = SCSI_DH_RETRY; break; default: - sdev_printk(KERN_INFO, sdev, - "MODE_SELECT failed with sense %02x/%02x/%02x.\n", - sense_hdr.sense_key, sense_hdr.asc, sense_hdr.ascq); + break; } + RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, " + "MODE_SELECT returned with sense %02x/%02x/%02x", + (char *) h->ctlr->array_name, h->ctlr->index, + sense_hdr.sense_key, sense_hdr.asc, sense_hdr.ascq); + done: return err; } @@ -518,7 +547,9 @@ retry: if (!rq) goto done; - sdev_printk(KERN_INFO, sdev, "%s MODE_SELECT command.\n", + RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, " + "%s MODE_SELECT command", + (char *) h->ctlr->array_name, h->ctlr->index, (retry_cnt == RDAC_RETRY_COUNT) ? "queueing" : "retrying"); err = blk_execute_rq(q, NULL, rq, 1); @@ -528,8 +559,12 @@ retry: if (err == SCSI_DH_RETRY && retry_cnt--) goto retry; } - if (err == SCSI_DH_OK) + if (err == SCSI_DH_OK) { h->state = RDAC_STATE_ACTIVE; + RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, " + "MODE_SELECT completed", + (char *) h->ctlr->array_name, h->ctlr->index); + } done: return err; @@ -567,6 +602,12 @@ static int rdac_check_sense(struct scsi_device *sdev, struct scsi_sense_hdr *sense_hdr) { struct rdac_dh_data *h = get_rdac_data(sdev); + + RDAC_LOG(RDAC_LOG_SENSE, sdev, "array %s, ctlr %d, " + "I/O returned with sense %02x/%02x/%02x", + (char *) h->ctlr->array_name, h->ctlr->index, + sense_hdr->sense_key, sense_hdr->asc, sense_hdr->ascq); + switch (sense_hdr->sense_key) { case NOT_READY: if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x01) -- cgit v1.2.3-18-g5258 From 4c0ba5d2593b5156327263f3ef6d7399dc0717b8 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sat, 5 Sep 2009 07:34:23 +0530 Subject: [SCSI] libiscsi: add completion function for drivers that do not need pdu processing beiscsi does not need the iscsi scsi cmd processing. It does not even get this info on the completion path. This adds a function to just update the sequencing numbers and complete a task. Signed-off-by: Mike Christie Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/libiscsi.c | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index a7ee4bb4070..67b2a2b0028 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -109,12 +109,9 @@ inline void iscsi_conn_queue_work(struct iscsi_conn *conn) } EXPORT_SYMBOL_GPL(iscsi_conn_queue_work); -void -iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) +static void __iscsi_update_cmdsn(struct iscsi_session *session, + uint32_t exp_cmdsn, uint32_t max_cmdsn) { - uint32_t max_cmdsn = be32_to_cpu(hdr->max_cmdsn); - uint32_t exp_cmdsn = be32_to_cpu(hdr->exp_cmdsn); - /* * standard specifies this check for when to update expected and * max sequence numbers @@ -138,6 +135,12 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) iscsi_conn_queue_work(session->leadconn); } } + +void iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) +{ + __iscsi_update_cmdsn(session, be32_to_cpu(hdr->exp_cmdsn), + be32_to_cpu(hdr->max_cmdsn)); +} EXPORT_SYMBOL_GPL(iscsi_update_cmdsn); /** @@ -499,6 +502,31 @@ static void iscsi_complete_task(struct iscsi_task *task, int state) __iscsi_put_task(task); } +/** + * iscsi_complete_scsi_task - finish scsi task normally + * @task: iscsi task for scsi cmd + * @exp_cmdsn: expected cmd sn in cpu format + * @max_cmdsn: max cmd sn in cpu format + * + * This is used when drivers do not need or cannot perform + * lower level pdu processing. + * + * Called with session lock + */ +void iscsi_complete_scsi_task(struct iscsi_task *task, + uint32_t exp_cmdsn, uint32_t max_cmdsn) +{ + struct iscsi_conn *conn = task->conn; + + ISCSI_DBG_SESSION(conn->session, "[itt 0x%x]\n", task->itt); + + conn->last_recv = jiffies; + __iscsi_update_cmdsn(conn->session, exp_cmdsn, max_cmdsn); + iscsi_complete_task(task, ISCSI_TASK_COMPLETED); +} +EXPORT_SYMBOL_GPL(iscsi_complete_scsi_task); + + /* * session lock must be held and if not called for a task that is * still pending or from the xmit thread, then xmit thread must -- cgit v1.2.3-18-g5258 From 661134ad3765348ecd6150a92e736bf28ba40f80 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sat, 5 Sep 2009 07:35:33 +0530 Subject: [SCSI] libiscsi, bnx2i: make bound ep check common bnx2i currently has a check for if a ep is properly bound, so if iscsi_queuecommand/xmit_task is called while there is no ep we will not queue IO. be2iscsi sends IO from queuecommand/xmit_task like how bnx2i does and needs a similar test. This patch has us just use the suspend_bit test for this. When ep_poll has succeeed iscsid will call conn_bind, the LLD will then call iscsi_conn_bind which will clear the suspend bit. When ep_disconnect is called (or if there is a conn error) we set the suspend bit. For the ep_disconnect case I am adding a helper in this patch that will take the session lock to make sure iscsi_queuecommand/xmit_task is not running and it will set the suspend bit. Signed-off-by: Mike Christie Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/libiscsi.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 67b2a2b0028..8dc73c489a1 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1571,6 +1571,12 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) goto fault; } + if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) { + reason = FAILURE_SESSION_IN_RECOVERY; + sc->result = DID_REQUEUE; + goto fault; + } + if (iscsi_check_cmdsn_window_closed(conn)) { reason = FAILURE_WINDOW_CLOSED; goto reject; @@ -1810,6 +1816,33 @@ static void fail_scsi_tasks(struct iscsi_conn *conn, unsigned lun, } } +/** + * iscsi_suspend_queue - suspend iscsi_queuecommand + * @conn: iscsi conn to stop queueing IO on + * + * This grabs the session lock to make sure no one is in + * xmit_task/queuecommand, and then sets suspend to prevent + * new commands from being queued. This only needs to be called + * by offload drivers that need to sync a path like ep disconnect + * with the iscsi_queuecommand/xmit_task. To start IO again libiscsi + * will call iscsi_start_tx and iscsi_unblock_session when in FFP. + */ +void iscsi_suspend_queue(struct iscsi_conn *conn) +{ + spin_lock_bh(&conn->session->lock); + set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); + spin_unlock_bh(&conn->session->lock); +} +EXPORT_SYMBOL_GPL(iscsi_suspend_queue); + +/** + * iscsi_suspend_tx - suspend iscsi_data_xmit + * @conn: iscsi conn tp stop processing IO on. + * + * This function sets the suspend bit to prevent iscsi_data_xmit + * from sending new IO, and if work is queued on the xmit thread + * it will wait for it to be completed. + */ void iscsi_suspend_tx(struct iscsi_conn *conn) { struct Scsi_Host *shost = conn->session->host; -- cgit v1.2.3-18-g5258 From afffd3dabe5209882c8cc59a373a4d33b5db304a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 30 Aug 2009 12:36:48 +0200 Subject: [SCSI] libsrp: fix memory leak in srp_ring_free() This patch fixes a memory leak in the libsrp function srp_ring_free(). It is not documented whether or not this function should free the ring pointer itself. But the source code of the callers of this function (srp_target_alloc() and srp_target_free()) makes it clear that srp_ring_free() should deallocate the ring pointer itself. Furthermore, the patch below makes srp_ring_free() deallocate all memory allocated by srp_ring_alloc(). This patch affects the ibmvstgt driver, which is the only in-tree driver that calls the srp_ring_free() function (indirectly). Signed-off-by: Bart Van Assche Acked-by: FUJITA Tomonori Cc: Stable Tree Signed-off-by: James Bottomley --- drivers/scsi/libsrp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c index 2742ae8a3d0..9ad38e81e34 100644 --- a/drivers/scsi/libsrp.c +++ b/drivers/scsi/libsrp.c @@ -124,6 +124,7 @@ static void srp_ring_free(struct device *dev, struct srp_buf **ring, size_t max, dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma); kfree(ring[i]); } + kfree(ring); } int srp_target_alloc(struct srp_target *target, struct device *dev, -- cgit v1.2.3-18-g5258 From ea038f63ac52439e7816295fa6064fe95e6c1f51 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 21 Aug 2009 09:47:54 -0600 Subject: [SCSI] fix oops during scsi scanning Chris Webb reported: p0# uname -a Linux f7ea8425-d45b-490f-a738-d181d0df6963.host.elastichosts.com 2.6.30.4-elastic-lon-p #2 SMP PREEMPT Thu Aug 20 14:30:50 BST 2009 x86_64 Intel(R) Xeon(R) CPU E5420 @ 2.50GHz GenuineIntel GNU/Linux p0# zgrep SCAN_ASYNC /proc/config.gz # CONFIG_SCSI_SCAN_ASYNC is not set p0# cat /var/log/kern/2009-08-20 [...] 15:27:10.485 kernel: scsi9 : iSCSI Initiator over TCP/IP 15:27:11.493 kernel: scsi 9:0:0:0: RAID IET Controller 0001 PQ: 0 ANSI: 5 15:27:11.493 kernel: scsi 9:0:0:0: Attached scsi generic sg6 type 12 15:27:11.495 kernel: scsi 9:0:0:1: Direct-Access IET VIRTUAL-DISK 0001 PQ: 0 ANSI: 5 15:27:11.495 kernel: sd 9:0:0:1: Attached scsi generic sg7 type 0 15:27:11.495 kernel: sd 9:0:0:1: [sdg] 4194304 512-byte hardware sectors: (2.14 GB/2.00 GiB) 15:27:11.495 kernel: sd 9:0:0:1: [sdg] Write Protect is off 15:27:11.495 kernel: sd 9:0:0:1: [sdg] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA 15:27:13.012 kernel: sdg:<6>scsi 9:0:0:1: [sdg] Unhandled error code 15:27:13.012 kernel: scsi 9:0:0:1: [sdg] Result: hostbyte=0x07 driverbyte=0x00 15:27:13.012 kernel: end_request: I/O error, dev sdg, sector 0 15:27:13.012 kernel: Buffer I/O error on device sdg, logical block 0 15:27:13.012 kernel: ldm_validate_partition_table(): Disk read failed. 15:27:13.012 kernel: unable to read partition table 15:27:13.014 kernel: BUG: unable to handle kernel NULL pointer dereference at 0000000000000010 15:27:13.014 kernel: IP: [] disk_part_iter_next+0x74/0xfd 15:27:13.014 kernel: PGD 82ad0b067 PUD 82cd7e067 PMD 0 15:27:13.014 kernel: Oops: 0000 [#1] PREEMPT SMP 15:27:13.014 kernel: last sysfs file: /sys/devices/platform/host9/session4/iscsi_session/session4/ifacename 15:27:13.014 kernel: CPU 5 15:27:13.014 kernel: Modules linked in: 15:27:13.014 kernel: Pid: 13999, comm: async/0 Not tainted 2.6.30.4-elastic-lon-p #2 X7DBN 15:27:13.014 kernel: RIP: 0010:[] [] disk_part_iter_next+0x74/0xfd 15:27:13.014 kernel: RSP: 0018:ffff88066afa3dd0 EFLAGS: 00010246 15:27:13.014 kernel: RAX: ffff88082b58a000 RBX: ffff88066afa3e00 RCX: 0000000000000000 15:27:13.014 kernel: RDX: 0000000000000000 RSI: ffff88082b58a000 RDI: 0000000000000000 15:27:13.014 kernel: RBP: ffff88066afa3df0 R08: ffff88066afa2000 R09: ffff8806a204f000 15:27:13.014 kernel: R10: 000000fb12c7d274 R11: ffff8806c2bf0628 R12: ffff88066afa3e00 15:27:13.014 kernel: R13: ffff88082c829a00 R14: 0000000000000000 R15: ffff8806bc50c920 15:27:13.014 kernel: FS: 0000000000000000(0000) GS:ffff88002818a000(0000) knlGS:0000000000000000 15:27:13.014 kernel: CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b 15:27:13.014 kernel: CR2: 0000000000000010 CR3: 000000082ade3000 CR4: 00000000000426e0 15:27:13.014 kernel: DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 15:27:13.014 kernel: DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 15:27:13.014 kernel: Process async/0 (pid: 13999, threadinfo ffff88066afa2000, task ffff8806c2bf05e0) 15:27:13.014 kernel: Stack: 15:27:13.014 kernel: 0000000000000000 ffff88066afa3e00 ffff88066afa3e00 ffff88082c829a00 15:27:13.014 kernel: ffff88066afa3e40 ffffffff80306feb ffff88082b58a000 0000000000000000 15:27:13.014 kernel: 0000000000000001 ffff8806bc50c920 ffff88066afa3e40 ffff88082b58a000 15:27:13.014 kernel: Call Trace: 15:27:13.014 kernel: [] register_disk+0x122/0x13a 15:27:13.014 kernel: [] add_disk+0xaa/0x106 15:27:13.014 kernel: [] sd_probe_async+0x198/0x25b 15:27:13.014 kernel: [] async_thread+0x10c/0x20d 15:27:13.014 kernel: [] ? default_wake_function+0x0/0xf 15:27:13.014 kernel: [] ? async_thread+0x0/0x20d 15:27:13.014 kernel: [] kthread+0x55/0x80 15:27:13.014 kernel: [] child_rip+0xa/0x20 15:27:13.014 kernel: [] ? kthread+0x0/0x80 15:27:13.014 kernel: [] ? child_rip+0x0/0x20 15:27:13.014 kernel: Code: c8 ff 80 e1 0c b9 00 00 00 00 0f 44 c1 41 83 cd ff 48 8d 7a 20 48 be ff ff ff ff 08 00 00 00 48 b9 00 00 00 00 08 00 00 00 eb 50 <8b> 42 10 41 bd 01 00 00 00 eb db 4c 63 c2 4e 8d 04 c7 4d 8b 20 15:27:13.015 kernel: RIP [] disk_part_iter_next+0x74/0xfd 15:27:13.015 kernel: RSP 15:27:13.015 kernel: CR2: 0000000000000010 15:27:13.015 kernel: ---[ end trace 6104b56ef5590e25 ]--- The problem is caused because the async scanning split in sd.c doesn't hold any reference to the device when it kicks off the async piece. What's happening is that an iSCSI disconnect is destorying the device again *before* the async sd scanning thread even starts. Fix this by taking a reference before starting the thread and dropping it again when the thread completes. Reported-by: Chris Webb Cc: Stable Tree Signed-off-by: James Bottomley --- drivers/scsi/sd.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index b7b9fec67a9..a89c421dab5 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2021,6 +2021,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie) sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", sdp->removable ? "removable " : ""); + put_device(&sdkp->dev); } /** @@ -2106,6 +2107,7 @@ static int sd_probe(struct device *dev) get_device(&sdp->sdev_gendev); + get_device(&sdkp->dev); /* prevent release before async_schedule */ async_schedule(sd_probe_async, sdkp); return 0; -- cgit v1.2.3-18-g5258 From 85927b0d5240dd2f48f1debf2797bd28ed4d112b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 9 Sep 2009 19:17:24 -0700 Subject: Input: wistron_btns - add keymap for AOpen 1557 This one does not have anything useful in DMI either so again we need to use: force=1 keymap=aopen1557 Signed-off-by: Dmitry Torokhov --- drivers/input/misc/wistron_btns.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index ebb08cfe273..11fd038a078 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -611,10 +611,24 @@ static struct key_entry keymap_wistron_generic[] __initdata = { { KE_END, 0 } }; +static struct key_entry keymap_aopen_1557[] __initdata = { + { KE_KEY, 0x01, {KEY_HELP} }, + { KE_KEY, 0x11, {KEY_PROG1} }, + { KE_KEY, 0x12, {KEY_PROG2} }, + { KE_WIFI, 0x30 }, + { KE_KEY, 0x22, {KEY_REWIND} }, + { KE_KEY, 0x23, {KEY_FORWARD} }, + { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, + { KE_KEY, 0x25, {KEY_STOPCD} }, + { KE_KEY, 0x31, {KEY_MAIL} }, + { KE_KEY, 0x36, {KEY_WWW} }, + { KE_END, 0 } +}; + static struct key_entry keymap_prestigio[] __initdata = { { KE_KEY, 0x11, {KEY_PROG1} }, { KE_KEY, 0x12, {KEY_PROG2} }, - { KE_WIFI, 0x30 }, + { KE_WIFI, 0x30 }, { KE_KEY, 0x22, {KEY_REWIND} }, { KE_KEY, 0x23, {KEY_FORWARD} }, { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, @@ -985,6 +999,8 @@ static int __init select_keymap(void) if (keymap_name != NULL) { if (strcmp (keymap_name, "1557/MS2141") == 0) keymap = keymap_wistron_ms2141; + else if (strcmp (keymap_name, "aopen1557") == 0) + keymap = keymap_aopen_1557; else if (strcmp (keymap_name, "prestigio") == 0) keymap = keymap_prestigio; else if (strcmp (keymap_name, "generic") == 0) -- cgit v1.2.3-18-g5258 From 9de48cc300fb10f7d9faa978670becf5e352462a Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Sun, 13 Sep 2009 09:10:11 -0700 Subject: Input: bcm5974 - silence uninitialized variables warnings Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/bcm5974.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index 2d8fc0bf692..0d1d33468b4 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -317,7 +317,7 @@ static int report_tp_state(struct bcm5974 *dev, int size) const struct tp_finger *f; struct input_dev *input = dev->input; int raw_p, raw_w, raw_x, raw_y, raw_n; - int ptest = 0, origin = 0, ibt = 0, nmin = 0, nmax = 0; + int ptest, origin, ibt = 0, nmin = 0, nmax = 0; int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0; if (size < c->tp_offset || (size - c->tp_offset) % SIZEOF_FINGER != 0) @@ -345,21 +345,22 @@ static int report_tp_state(struct bcm5974 *dev, int size) /* set the integrated button if applicable */ if (c->tp_type == TYPE2) ibt = raw2int(dev->tp_data[BUTTON_TYPE2]); - } - /* while tracking finger still valid, count all fingers */ - if (ptest > PRESSURE_LOW && origin) { - abs_p = ptest; - abs_w = int2bound(&c->w, raw_w); - abs_x = int2bound(&c->x, raw_x - c->x.devmin); - abs_y = int2bound(&c->y, c->y.devmax - raw_y); - while (raw_n--) { - ptest = int2bound(&c->p, raw2int(f->force_major)); - if (ptest > PRESSURE_LOW) - nmax++; - if (ptest > PRESSURE_HIGH) - nmin++; - f++; + /* while tracking finger still valid, count all fingers */ + if (ptest > PRESSURE_LOW && origin) { + abs_p = ptest; + abs_w = int2bound(&c->w, raw_w); + abs_x = int2bound(&c->x, raw_x - c->x.devmin); + abs_y = int2bound(&c->y, c->y.devmax - raw_y); + while (raw_n--) { + ptest = int2bound(&c->p, + raw2int(f->force_major)); + if (ptest > PRESSURE_LOW) + nmax++; + if (ptest > PRESSURE_HIGH) + nmin++; + f++; + } } } -- cgit v1.2.3-18-g5258 From 18d8217bc441630c3c5ec7416c5a65c69e8a0979 Mon Sep 17 00:00:00 2001 From: Ed Cashin Date: Thu, 10 Sep 2009 22:30:47 +0200 Subject: aoe: end barrier bios with EOPNOTSUPP BugLink: http://bugzilla.kernel.org/show_bug.cgi?id=13942 Bruno Premont noticed that aoe throws a BUG during umount of an XFS in 2.6.31: [ 5259.349897] aoe: bi_io_vec is NULL [ 5259.349940] ------------[ cut here ]------------ [ 5259.349958] kernel BUG at /usr/src/linux-2.6/drivers/block/aoe/aoeblk.c:177! [ 5259.349990] invalid opcode: 0000 [#1] The bio in question is a barrier. Jens Axboe suggested that such bios need to be recognized and ended with -EOPNOTSUPP by any driver that provides its own ->make_request_fn handler and does not handle barriers. In testing the changes below eliminate the BUG. (Better would be real barrier support, something that Ed says he'll add for later in the .32 cycle. For now, this at least gets rid of a bug with crashing on an empty barrier. Jens) Signed-off-by: Ed L. Cashin Signed-off-by: Jens Axboe --- drivers/block/aoe/aoeblk.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 1e15889c4b9..bf7ceba1878 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -172,6 +172,9 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio) BUG(); bio_endio(bio, -ENXIO); return 0; + } else if (bio_rw_flagged(bio, BIO_RW_BARRIER)) { + bio_endio(bio, -EOPNOTSUPP); + return 0; } else if (bio->bi_io_vec == NULL) { printk(KERN_ERR "aoe: bi_io_vec is NULL\n"); BUG(); -- cgit v1.2.3-18-g5258 From a9327cac440be4d8333bba975cbbf76045096275 Mon Sep 17 00:00:00 2001 From: Nikanth Karthikesan Date: Fri, 11 Sep 2009 09:18:54 +0200 Subject: Seperate read and write statistics of in_flight requests Currently, there is a single in_flight counter measuring the number of requests in the request_queue. But some monitoring tools would like to know how many read requests and write requests are in progress. Split the current in_flight counter into two seperate counters for read and write. This information is exported as a sysfs attribute, as changing the currently available stat files would break the existing tools. Signed-off-by: Nikanth Karthikesan Signed-off-by: Jens Axboe --- drivers/md/dm.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm.c b/drivers/md/dm.c index ec012f03024..eee28fac210 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -130,7 +130,7 @@ struct mapped_device { /* * A list of ios that arrived while we were suspended. */ - atomic_t pending; + atomic_t pending[2]; wait_queue_head_t wait; struct work_struct work; struct bio_list deferred; @@ -453,13 +453,14 @@ static void start_io_acct(struct dm_io *io) { struct mapped_device *md = io->md; int cpu; + int rw = bio_data_dir(io->bio); io->start_time = jiffies; cpu = part_stat_lock(); part_round_stats(cpu, &dm_disk(md)->part0); part_stat_unlock(); - dm_disk(md)->part0.in_flight = atomic_inc_return(&md->pending); + dm_disk(md)->part0.in_flight[rw] = atomic_inc_return(&md->pending[rw]); } static void end_io_acct(struct dm_io *io) @@ -479,8 +480,9 @@ static void end_io_acct(struct dm_io *io) * After this is decremented the bio must not be touched if it is * a barrier. */ - dm_disk(md)->part0.in_flight = pending = - atomic_dec_return(&md->pending); + dm_disk(md)->part0.in_flight[rw] = pending = + atomic_dec_return(&md->pending[rw]); + pending += atomic_read(&md->pending[rw^0x1]); /* nudge anyone waiting on suspend queue */ if (!pending) @@ -1785,7 +1787,8 @@ static struct mapped_device *alloc_dev(int minor) if (!md->disk) goto bad_disk; - atomic_set(&md->pending, 0); + atomic_set(&md->pending[0], 0); + atomic_set(&md->pending[1], 0); init_waitqueue_head(&md->wait); INIT_WORK(&md->work, dm_wq_work); init_waitqueue_head(&md->eventq); @@ -2088,7 +2091,8 @@ static int dm_wait_for_completion(struct mapped_device *md, int interruptible) break; } spin_unlock_irqrestore(q->queue_lock, flags); - } else if (!atomic_read(&md->pending)) + } else if (!atomic_read(&md->pending[0]) && + !atomic_read(&md->pending[1])) break; if (interruptible == TASK_INTERRUPTIBLE && -- cgit v1.2.3-18-g5258 From 3c5820c743479285ce2678fd3c12b1fd39fe998f Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Fri, 11 Sep 2009 21:54:52 +0200 Subject: block: Optimal I/O limit wrapper Implement blk_limits_io_opt() and make blk_queue_io_opt() a wrapper around it. DM needs this to avoid poking at the queue_limits directly. Signed-off-by: Martin K. Petersen Signed-off-by: Mike Snitzer Signed-off-by: Jens Axboe --- drivers/md/dm-stripe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index fde658ccbce..e0efc1adcaf 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c @@ -336,7 +336,7 @@ static void stripe_io_hints(struct dm_target *ti, unsigned chunk_size = (sc->chunk_mask + 1) << 9; blk_limits_io_min(limits, chunk_size); - limits->io_opt = chunk_size * sc->stripes; + blk_limits_io_opt(limits, chunk_size * sc->stripes); } static struct target_type stripe_target = { -- cgit v1.2.3-18-g5258 From b04f932171e8a99bb8ca2f863b2b9eadb85741e8 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 17 Aug 2009 18:14:33 +0200 Subject: pohmelfs: Use __generic_file_aio_write instead of generic_file_aio_write_nolock Use new helper __generic_file_aio_write(). Since the fs takes care of syncing by itself afterwards, there are no more changes needed. CC: Evgeniy Polyakov Signed-off-by: Jan Kara --- drivers/staging/pohmelfs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c index e63c9bea6c5..e9d41e439aa 100644 --- a/drivers/staging/pohmelfs/inode.c +++ b/drivers/staging/pohmelfs/inode.c @@ -921,7 +921,7 @@ ssize_t pohmelfs_write(struct file *file, const char __user *buf, if (ret) goto err_out_unlock; - ret = generic_file_aio_write_nolock(&kiocb, &iov, 1, pos); + ret = __generic_file_aio_write(&kiocb, &iov, 1, &kiocb.ki_pos); *ppos = kiocb.ki_pos; mutex_unlock(&inode->i_mutex); -- cgit v1.2.3-18-g5258 From eef99380679e20e7edc096aa4d8a98b875404d79 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 20 Aug 2009 17:43:41 +0200 Subject: vfs: Rename generic_file_aio_write_nolock generic_file_aio_write_nolock() is now used only by block devices and raw character device. Filesystems should use __generic_file_aio_write() in case generic_file_aio_write() doesn't suit them. So rename the function to blkdev_aio_write() and move it to fs/blockdev.c. Signed-off-by: Christoph Hellwig Signed-off-by: Jan Kara --- drivers/char/raw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 05f9d18b936..40268db02e2 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -246,7 +246,7 @@ static const struct file_operations raw_fops = { .read = do_sync_read, .aio_read = generic_file_aio_read, .write = do_sync_write, - .aio_write = generic_file_aio_write_nolock, + .aio_write = blkdev_aio_write, .open = raw_open, .release= raw_release, .ioctl = raw_ioctl, -- cgit v1.2.3-18-g5258 From aa3caafe53cab7ef60605e481cd5d7943e1c3022 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 18 Aug 2009 18:38:45 +0200 Subject: pohmelfs: Use new syncing helper Use new generic_write_sync() helper instead of sync_page_range(). Acked-by: Evgeniy Polyakov Signed-off-by: Jan Kara --- drivers/staging/pohmelfs/inode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c index e9d41e439aa..d004a9ddddb 100644 --- a/drivers/staging/pohmelfs/inode.c +++ b/drivers/staging/pohmelfs/inode.c @@ -927,10 +927,10 @@ ssize_t pohmelfs_write(struct file *file, const char __user *buf, mutex_unlock(&inode->i_mutex); WARN_ON(ret < 0); - if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { + if (ret > 0) { ssize_t err; - err = sync_page_range(inode, mapping, pos, ret); + err = generic_write_sync(file, pos, ret); if (err < 0) ret = err; WARN_ON(ret < 0); -- cgit v1.2.3-18-g5258 From b70ef01016850de87b9a28a6af19fed8801df076 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 25 Jun 2009 19:32:38 +0200 Subject: EDAC: move MCE error descriptions to EDAC core This is in preparation of adding AMD-specific MCE decoding functionality to the EDAC core. The error decoding macros originate from the AMD64 EDAC driver albeit in a simplified and cleaned up version here. While at it, add macros to generate the error description strings and use them in the error type decoders directly which removes a bunch of code and makes the decoding functions much more readable. Also, fix strings and shorten macro names. Remove superfluous htlink_msgs. Signed-off-by: Borislav Petkov --- drivers/edac/Makefile | 6 +- drivers/edac/amd64_edac.c | 140 +++++++++++++++++-------------- drivers/edac/amd64_edac.h | 17 +--- drivers/edac/amd64_edac_err_types.c | 161 ------------------------------------ drivers/edac/edac_mce_amd.c | 101 ++++++++++++++++++++++ drivers/edac/edac_mce_amd.h | 29 +++++++ 6 files changed, 214 insertions(+), 240 deletions(-) delete mode 100644 drivers/edac/amd64_edac_err_types.c create mode 100644 drivers/edac/edac_mce_amd.c create mode 100644 drivers/edac/edac_mce_amd.h (limited to 'drivers') diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index 98aa4a7db41..cfa033ce53a 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -17,6 +17,10 @@ ifdef CONFIG_PCI edac_core-objs += edac_pci.o edac_pci_sysfs.o endif +ifdef CONFIG_CPU_SUP_AMD +edac_core-objs += edac_mce_amd.o +endif + obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o obj-$(CONFIG_EDAC_CPC925) += cpc925_edac.o obj-$(CONFIG_EDAC_I5000) += i5000_edac.o @@ -32,7 +36,7 @@ obj-$(CONFIG_EDAC_X38) += x38_edac.o obj-$(CONFIG_EDAC_I82860) += i82860_edac.o obj-$(CONFIG_EDAC_R82600) += r82600_edac.o -amd64_edac_mod-y := amd64_edac_err_types.o amd64_edac.o +amd64_edac_mod-y := amd64_edac.o amd64_edac_mod-$(CONFIG_EDAC_DEBUG) += amd64_edac_dbg.o amd64_edac_mod-$(CONFIG_EDAC_AMD64_ERROR_INJECTION) += amd64_edac_inj.o diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index e2a10bcba7a..b9e84bc9176 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -18,6 +18,63 @@ struct amd64_pvt; static struct mem_ctl_info *mci_lookup[MAX_NUMNODES]; static struct amd64_pvt *pvt_lookup[MAX_NUMNODES]; +/* + * See F2x80 for K8 and F2x[1,0]80 for Fam10 and later. The table below is only + * for DDR2 DRAM mapping. + */ +u32 revf_quad_ddr2_shift[] = { + 0, /* 0000b NULL DIMM (128mb) */ + 28, /* 0001b 256mb */ + 29, /* 0010b 512mb */ + 29, /* 0011b 512mb */ + 29, /* 0100b 512mb */ + 30, /* 0101b 1gb */ + 30, /* 0110b 1gb */ + 31, /* 0111b 2gb */ + 31, /* 1000b 2gb */ + 32, /* 1001b 4gb */ + 32, /* 1010b 4gb */ + 33, /* 1011b 8gb */ + 0, /* 1100b future */ + 0, /* 1101b future */ + 0, /* 1110b future */ + 0 /* 1111b future */ +}; + +/* + * Valid scrub rates for the K8 hardware memory scrubber. We map the scrubbing + * bandwidth to a valid bit pattern. The 'set' operation finds the 'matching- + * or higher value'. + * + *FIXME: Produce a better mapping/linearisation. + */ + +struct scrubrate scrubrates[] = { + { 0x01, 1600000000UL}, + { 0x02, 800000000UL}, + { 0x03, 400000000UL}, + { 0x04, 200000000UL}, + { 0x05, 100000000UL}, + { 0x06, 50000000UL}, + { 0x07, 25000000UL}, + { 0x08, 12284069UL}, + { 0x09, 6274509UL}, + { 0x0A, 3121951UL}, + { 0x0B, 1560975UL}, + { 0x0C, 781440UL}, + { 0x0D, 390720UL}, + { 0x0E, 195300UL}, + { 0x0F, 97650UL}, + { 0x10, 48854UL}, + { 0x11, 24427UL}, + { 0x12, 12213UL}, + { 0x13, 6101UL}, + { 0x14, 3051UL}, + { 0x15, 1523UL}, + { 0x16, 761UL}, + { 0x00, 0UL}, /* scrubbing off */ +}; + /* * Memory scrubber control interface. For K8, memory scrubbing is handled by * hardware and can involve L2 cache, dcache as well as the main memory. With @@ -1101,8 +1158,8 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u32 page, offset; /* Extract the syndrome parts and form a 16-bit syndrome */ - syndrome = EXTRACT_HIGH_SYNDROME(info->nbsl) << 8; - syndrome |= EXTRACT_LOW_SYNDROME(info->nbsh); + syndrome = HIGH_SYNDROME(info->nbsl) << 8; + syndrome |= LOW_SYNDROME(info->nbsh); /* CHIPKILL enabled */ if (info->nbcfg & K8_NBCFG_CHIPKILL) { @@ -1701,8 +1758,8 @@ static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci, if (csrow >= 0) { error_address_to_page_and_offset(sys_addr, &page, &offset); - syndrome = EXTRACT_HIGH_SYNDROME(info->nbsl) << 8; - syndrome |= EXTRACT_LOW_SYNDROME(info->nbsh); + syndrome = HIGH_SYNDROME(info->nbsl) << 8; + syndrome |= LOW_SYNDROME(info->nbsh); /* * Is CHIPKILL on? If so, then we can attempt to use the @@ -2155,36 +2212,22 @@ static int amd64_get_error_info(struct mem_ctl_info *mci, static inline void amd64_decode_gart_tlb_error(struct mem_ctl_info *mci, struct amd64_error_info_regs *info) { - u32 err_code; - u32 ec_tt; /* error code transaction type (2b) */ - u32 ec_ll; /* error code cache level (2b) */ - - err_code = EXTRACT_ERROR_CODE(info->nbsl); - ec_ll = EXTRACT_LL_CODE(err_code); - ec_tt = EXTRACT_TT_CODE(err_code); + u32 ec = ERROR_CODE(info->nbsl); amd64_mc_printk(mci, KERN_ERR, "GART TLB event: transaction type(%s), " - "cache level(%s)\n", tt_msgs[ec_tt], ll_msgs[ec_ll]); + "cache level(%s)\n", TT_MSG(ec), LL_MSG(ec)); } static inline void amd64_decode_mem_cache_error(struct mem_ctl_info *mci, struct amd64_error_info_regs *info) { - u32 err_code; - u32 ec_rrrr; /* error code memory transaction (4b) */ - u32 ec_tt; /* error code transaction type (2b) */ - u32 ec_ll; /* error code cache level (2b) */ - - err_code = EXTRACT_ERROR_CODE(info->nbsl); - ec_ll = EXTRACT_LL_CODE(err_code); - ec_tt = EXTRACT_TT_CODE(err_code); - ec_rrrr = EXTRACT_RRRR_CODE(err_code); + u32 ec = ERROR_CODE(info->nbsl); amd64_mc_printk(mci, KERN_ERR, "cache hierarchy error: memory transaction type(%s), " "transaction type(%s), cache level(%s)\n", - rrrr_msgs[ec_rrrr], tt_msgs[ec_tt], ll_msgs[ec_ll]); + RRRR_MSG(ec), TT_MSG(ec), LL_MSG(ec)); } @@ -2264,21 +2307,8 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, static void amd64_decode_bus_error(struct mem_ctl_info *mci, struct amd64_error_info_regs *info) { - u32 err_code, ext_ec; - u32 ec_pp; /* error code participating processor (2p) */ - u32 ec_to; /* error code timed out (1b) */ - u32 ec_rrrr; /* error code memory transaction (4b) */ - u32 ec_ii; /* error code memory or I/O (2b) */ - u32 ec_ll; /* error code cache level (2b) */ - - ext_ec = EXTRACT_EXT_ERROR_CODE(info->nbsl); - err_code = EXTRACT_ERROR_CODE(info->nbsl); - - ec_ll = EXTRACT_LL_CODE(err_code); - ec_ii = EXTRACT_II_CODE(err_code); - ec_rrrr = EXTRACT_RRRR_CODE(err_code); - ec_to = EXTRACT_TO_CODE(err_code); - ec_pp = EXTRACT_PP_CODE(err_code); + u32 ec = ERROR_CODE(info->nbsl); + u32 xec = EXT_ERROR_CODE(info->nbsl); amd64_mc_printk(mci, KERN_ERR, "BUS ERROR:\n" @@ -2286,20 +2316,17 @@ static void amd64_decode_bus_error(struct mem_ctl_info *mci, " participating processor(%s)\n" " memory transaction type(%s)\n" " cache level(%s) Error Found by: %s\n", - to_msgs[ec_to], - ii_msgs[ec_ii], - pp_msgs[ec_pp], - rrrr_msgs[ec_rrrr], - ll_msgs[ec_ll], + TO_MSG(ec), II_MSG(ec), PP_MSG(ec), RRRR_MSG(ec), LL_MSG(ec), (info->nbsh & K8_NBSH_ERR_SCRUBER) ? "Scrubber" : "Normal Operation"); - /* If this was an 'observed' error, early out */ - if (ec_pp == K8_NBSL_PP_OBS) - return; /* We aren't the node involved */ + + /* Bail early out if this was an 'observed' error */ + if (PP(ec) == K8_NBSL_PP_OBS) + return; /* Parse out the extended error code for ECC events */ - switch (ext_ec) { + switch (xec) { /* F10 changed to one Extended ECC error code */ case F10_NBSL_EXT_ERR_RES: /* Reserved field */ case F10_NBSL_EXT_ERR_ECC: /* F10 ECC ext err code */ @@ -2379,7 +2406,7 @@ int amd64_process_error_info(struct mem_ctl_info *mci, (regs->nbsh & K8_NBSH_CORE3) ? "True" : "False"); - err_code = EXTRACT_ERROR_CODE(regs->nbsl); + err_code = ERROR_CODE(regs->nbsl); /* Determine which error type: * 1) GART errors - non-fatal, developmental events @@ -2387,7 +2414,7 @@ int amd64_process_error_info(struct mem_ctl_info *mci, * 3) BUS errors * 4) Unknown error */ - if (TEST_TLB_ERROR(err_code)) { + if (TLB_ERROR(err_code)) { /* * GART errors are intended to help graphics driver developers * to detect bad GART PTEs. It is recommended by AMD to disable @@ -2411,10 +2438,10 @@ int amd64_process_error_info(struct mem_ctl_info *mci, debugf1("GART TLB error\n"); amd64_decode_gart_tlb_error(mci, info); - } else if (TEST_MEM_ERROR(err_code)) { + } else if (MEM_ERROR(err_code)) { debugf1("Memory/Cache error\n"); amd64_decode_mem_cache_error(mci, info); - } else if (TEST_BUS_ERROR(err_code)) { + } else if (BUS_ERROR(err_code)) { debugf1("Bus (Link/DRAM) error\n"); amd64_decode_bus_error(mci, info); } else { @@ -2424,21 +2451,10 @@ int amd64_process_error_info(struct mem_ctl_info *mci, err_code); } - ext_ec = EXTRACT_EXT_ERROR_CODE(regs->nbsl); + ext_ec = EXT_ERROR_CODE(regs->nbsl); amd64_mc_printk(mci, KERN_ERR, "ExtErr=(0x%x) %s\n", ext_ec, ext_msgs[ext_ec]); - if (((ext_ec >= F10_NBSL_EXT_ERR_CRC && - ext_ec <= F10_NBSL_EXT_ERR_TGT) || - (ext_ec == F10_NBSL_EXT_ERR_RMW)) && - EXTRACT_LDT_LINK(info->nbsh)) { - - amd64_mc_printk(mci, KERN_ERR, - "Error on hypertransport link: %s\n", - htlink_msgs[ - EXTRACT_LDT_LINK(info->nbsh)]); - } - /* * Check the UE bit of the NB status high register, if set generate some * logs. If NOT a GART error, then process the event as a NO-INFO event. diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index ba73015af8e..1ddef8d15d5 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -72,6 +72,7 @@ #include #include #include "edac_core.h" +#include "edac_mce_amd.h" #define amd64_printk(level, fmt, arg...) \ edac_printk(level, "amd64", fmt, ##arg) @@ -303,9 +304,6 @@ enum { #define K8_NBSL 0x48 -#define EXTRACT_HIGH_SYNDROME(x) (((x) >> 24) & 0xff) -#define EXTRACT_EXT_ERROR_CODE(x) (((x) >> 16) & 0x1f) - /* Family F10h: Normalized Extended Error Codes */ #define F10_NBSL_EXT_ERR_RES 0x0 #define F10_NBSL_EXT_ERR_CRC 0x1 @@ -348,17 +346,6 @@ enum { #define K8_NBSL_EXT_ERR_CHIPKILL_ECC 0x8 #define K8_NBSL_EXT_ERR_DRAM_PARITY 0xD -#define EXTRACT_ERROR_CODE(x) ((x) & 0xffff) -#define TEST_TLB_ERROR(x) (((x) & 0xFFF0) == 0x0010) -#define TEST_MEM_ERROR(x) (((x) & 0xFF00) == 0x0100) -#define TEST_BUS_ERROR(x) (((x) & 0xF800) == 0x0800) -#define EXTRACT_TT_CODE(x) (((x) >> 2) & 0x3) -#define EXTRACT_II_CODE(x) (((x) >> 2) & 0x3) -#define EXTRACT_LL_CODE(x) (((x) >> 0) & 0x3) -#define EXTRACT_RRRR_CODE(x) (((x) >> 4) & 0xf) -#define EXTRACT_TO_CODE(x) (((x) >> 8) & 0x1) -#define EXTRACT_PP_CODE(x) (((x) >> 9) & 0x3) - /* * The following are for BUS type errors AFTER values have been normalized by * shifting right @@ -386,9 +373,7 @@ enum { #define K8_NBSH_CORE1 BIT(1) #define K8_NBSH_CORE0 BIT(0) -#define EXTRACT_LDT_LINK(x) (((x) >> 4) & 0x7) #define EXTRACT_ERR_CPU_MAP(x) ((x) & 0xF) -#define EXTRACT_LOW_SYNDROME(x) (((x) >> 15) & 0xff) #define K8_NBEAL 0x50 diff --git a/drivers/edac/amd64_edac_err_types.c b/drivers/edac/amd64_edac_err_types.c deleted file mode 100644 index f212ff12a9d..00000000000 --- a/drivers/edac/amd64_edac_err_types.c +++ /dev/null @@ -1,161 +0,0 @@ -#include "amd64_edac.h" - -/* - * See F2x80 for K8 and F2x[1,0]80 for Fam10 and later. The table below is only - * for DDR2 DRAM mapping. - */ -u32 revf_quad_ddr2_shift[] = { - 0, /* 0000b NULL DIMM (128mb) */ - 28, /* 0001b 256mb */ - 29, /* 0010b 512mb */ - 29, /* 0011b 512mb */ - 29, /* 0100b 512mb */ - 30, /* 0101b 1gb */ - 30, /* 0110b 1gb */ - 31, /* 0111b 2gb */ - 31, /* 1000b 2gb */ - 32, /* 1001b 4gb */ - 32, /* 1010b 4gb */ - 33, /* 1011b 8gb */ - 0, /* 1100b future */ - 0, /* 1101b future */ - 0, /* 1110b future */ - 0 /* 1111b future */ -}; - -/* - * Valid scrub rates for the K8 hardware memory scrubber. We map the scrubbing - * bandwidth to a valid bit pattern. The 'set' operation finds the 'matching- - * or higher value'. - * - *FIXME: Produce a better mapping/linearisation. - */ - -struct scrubrate scrubrates[] = { - { 0x01, 1600000000UL}, - { 0x02, 800000000UL}, - { 0x03, 400000000UL}, - { 0x04, 200000000UL}, - { 0x05, 100000000UL}, - { 0x06, 50000000UL}, - { 0x07, 25000000UL}, - { 0x08, 12284069UL}, - { 0x09, 6274509UL}, - { 0x0A, 3121951UL}, - { 0x0B, 1560975UL}, - { 0x0C, 781440UL}, - { 0x0D, 390720UL}, - { 0x0E, 195300UL}, - { 0x0F, 97650UL}, - { 0x10, 48854UL}, - { 0x11, 24427UL}, - { 0x12, 12213UL}, - { 0x13, 6101UL}, - { 0x14, 3051UL}, - { 0x15, 1523UL}, - { 0x16, 761UL}, - { 0x00, 0UL}, /* scrubbing off */ -}; - -/* - * string representation for the different MCA reported error types, see F3x48 - * or MSR0000_0411. - */ -const char *tt_msgs[] = { /* transaction type */ - "instruction", - "data", - "generic", - "reserved" -}; - -const char *ll_msgs[] = { /* cache level */ - "L0", - "L1", - "L2", - "L3/generic" -}; - -const char *rrrr_msgs[] = { - "generic", - "generic read", - "generic write", - "data read", - "data write", - "inst fetch", - "prefetch", - "evict", - "snoop", - "reserved RRRR= 9", - "reserved RRRR= 10", - "reserved RRRR= 11", - "reserved RRRR= 12", - "reserved RRRR= 13", - "reserved RRRR= 14", - "reserved RRRR= 15" -}; - -const char *pp_msgs[] = { /* participating processor */ - "local node originated (SRC)", - "local node responded to request (RES)", - "local node observed as 3rd party (OBS)", - "generic" -}; - -const char *to_msgs[] = { - "no timeout", - "timed out" -}; - -const char *ii_msgs[] = { /* memory or i/o */ - "mem access", - "reserved", - "i/o access", - "generic" -}; - -/* Map the 5 bits of Extended Error code to the string table. */ -const char *ext_msgs[] = { /* extended error */ - "K8 ECC error/F10 reserved", /* 0_0000b */ - "CRC error", /* 0_0001b */ - "sync error", /* 0_0010b */ - "mst abort", /* 0_0011b */ - "tgt abort", /* 0_0100b */ - "GART error", /* 0_0101b */ - "RMW error", /* 0_0110b */ - "Wdog timer error", /* 0_0111b */ - "F10-ECC/K8-Chipkill error", /* 0_1000b */ - "DEV Error", /* 0_1001b */ - "Link Data error", /* 0_1010b */ - "Link or L3 Protocol error", /* 0_1011b */ - "NB Array error", /* 0_1100b */ - "DRAM Parity error", /* 0_1101b */ - "Link Retry/GART Table Walk/DEV Table Walk error", /* 0_1110b */ - "Res 0x0ff error", /* 0_1111b */ - "Res 0x100 error", /* 1_0000b */ - "Res 0x101 error", /* 1_0001b */ - "Res 0x102 error", /* 1_0010b */ - "Res 0x103 error", /* 1_0011b */ - "Res 0x104 error", /* 1_0100b */ - "Res 0x105 error", /* 1_0101b */ - "Res 0x106 error", /* 1_0110b */ - "Res 0x107 error", /* 1_0111b */ - "Res 0x108 error", /* 1_1000b */ - "Res 0x109 error", /* 1_1001b */ - "Res 0x10A error", /* 1_1010b */ - "Res 0x10B error", /* 1_1011b */ - "L3 Cache Data error", /* 1_1100b */ - "L3 CacheTag error", /* 1_1101b */ - "L3 Cache LRU error", /* 1_1110b */ - "Res 0x1FF error" /* 1_1111b */ -}; - -const char *htlink_msgs[] = { - "none", - "1", - "2", - "1 2", - "3", - "1 3", - "2 3", - "1 2 3" -}; diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c new file mode 100644 index 00000000000..cf8465450b3 --- /dev/null +++ b/drivers/edac/edac_mce_amd.c @@ -0,0 +1,101 @@ +#include +#include "edac_mce_amd.h" + +/* + * string representation for the different MCA reported error types, see F3x48 + * or MSR0000_0411. + */ +const char *tt_msgs[] = { /* transaction type */ + "instruction", + "data", + "generic", + "reserved" +}; +EXPORT_SYMBOL_GPL(tt_msgs); + +const char *ll_msgs[] = { /* cache level */ + "L0", + "L1", + "L2", + "L3/generic" +}; +EXPORT_SYMBOL_GPL(ll_msgs); + +const char *rrrr_msgs[] = { + "generic", + "generic read", + "generic write", + "data read", + "data write", + "inst fetch", + "prefetch", + "evict", + "snoop", + "reserved RRRR= 9", + "reserved RRRR= 10", + "reserved RRRR= 11", + "reserved RRRR= 12", + "reserved RRRR= 13", + "reserved RRRR= 14", + "reserved RRRR= 15" +}; +EXPORT_SYMBOL_GPL(rrrr_msgs); + +const char *pp_msgs[] = { /* participating processor */ + "local node originated (SRC)", + "local node responded to request (RES)", + "local node observed as 3rd party (OBS)", + "generic" +}; +EXPORT_SYMBOL_GPL(pp_msgs); + +const char *to_msgs[] = { + "no timeout", + "timed out" +}; +EXPORT_SYMBOL_GPL(to_msgs); + +const char *ii_msgs[] = { /* memory or i/o */ + "mem access", + "reserved", + "i/o access", + "generic" +}; +EXPORT_SYMBOL_GPL(ii_msgs); + +/* Map the 5 bits of Extended Error code to the string table. */ +const char *ext_msgs[] = { /* extended error */ + "K8 ECC error/F10 reserved", /* 0_0000b */ + "CRC error", /* 0_0001b */ + "sync error", /* 0_0010b */ + "mst abort", /* 0_0011b */ + "tgt abort", /* 0_0100b */ + "GART error", /* 0_0101b */ + "RMW error", /* 0_0110b */ + "Wdog timer error", /* 0_0111b */ + "F10-ECC/K8-Chipkill error", /* 0_1000b */ + "DEV Error", /* 0_1001b */ + "Link Data error", /* 0_1010b */ + "Link or L3 Protocol error", /* 0_1011b */ + "NB Array error", /* 0_1100b */ + "DRAM Parity error", /* 0_1101b */ + "Link Retry/GART Table Walk/DEV Table Walk error", /* 0_1110b */ + "Res 0x0ff error", /* 0_1111b */ + "Res 0x100 error", /* 1_0000b */ + "Res 0x101 error", /* 1_0001b */ + "Res 0x102 error", /* 1_0010b */ + "Res 0x103 error", /* 1_0011b */ + "Res 0x104 error", /* 1_0100b */ + "Res 0x105 error", /* 1_0101b */ + "Res 0x106 error", /* 1_0110b */ + "Res 0x107 error", /* 1_0111b */ + "Res 0x108 error", /* 1_1000b */ + "Res 0x109 error", /* 1_1001b */ + "Res 0x10A error", /* 1_1010b */ + "Res 0x10B error", /* 1_1011b */ + "L3 Cache Data error", /* 1_1100b */ + "L3 CacheTag error", /* 1_1101b */ + "L3 Cache LRU error", /* 1_1110b */ + "Res 0x1FF error" /* 1_1111b */ +}; +EXPORT_SYMBOL_GPL(ext_msgs); diff --git a/drivers/edac/edac_mce_amd.h b/drivers/edac/edac_mce_amd.h new file mode 100644 index 00000000000..81f9dcf9990 --- /dev/null +++ b/drivers/edac/edac_mce_amd.h @@ -0,0 +1,29 @@ +#define ERROR_CODE(x) ((x) & 0xffff) +#define EXT_ERROR_CODE(x) (((x) >> 16) & 0x1f) +#define LOW_SYNDROME(x) (((x) >> 15) & 0xff) +#define HIGH_SYNDROME(x) (((x) >> 24) & 0xff) + +#define TLB_ERROR(x) (((x) & 0xFFF0) == 0x0010) +#define MEM_ERROR(x) (((x) & 0xFF00) == 0x0100) +#define BUS_ERROR(x) (((x) & 0xF800) == 0x0800) + +#define TT(x) (((x) >> 2) & 0x3) +#define TT_MSG(x) tt_msgs[TT(x)] +#define II(x) (((x) >> 2) & 0x3) +#define II_MSG(x) ii_msgs[II(x)] +#define LL(x) (((x) >> 0) & 0x3) +#define LL_MSG(x) ll_msgs[LL(x)] +#define RRRR(x) (((x) >> 4) & 0xf) +#define RRRR_MSG(x) rrrr_msgs[RRRR(x)] +#define TO(x) (((x) >> 8) & 0x1) +#define TO_MSG(x) to_msgs[TO(x)] +#define PP(x) (((x) >> 9) & 0x3) +#define PP_MSG(x) pp_msgs[PP(x)] + +extern const char *tt_msgs[]; +extern const char *ll_msgs[]; +extern const char *rrrr_msgs[]; +extern const char *pp_msgs[]; +extern const char *to_msgs[]; +extern const char *ii_msgs[]; +extern const char *ext_msgs[]; -- cgit v1.2.3-18-g5258 From 1c43f2e24d059913bce58887f1d6e4267aaed284 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 23 Jul 2009 15:47:51 +0200 Subject: EDAC: beef up ErrorCodeExt error signatures Signed-off-by: Borislav Petkov --- drivers/edac/edac_mce_amd.c | 71 +++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c index cf8465450b3..918567e8cfd 100644 --- a/drivers/edac/edac_mce_amd.c +++ b/drivers/edac/edac_mce_amd.c @@ -63,39 +63,42 @@ const char *ii_msgs[] = { /* memory or i/o */ }; EXPORT_SYMBOL_GPL(ii_msgs); -/* Map the 5 bits of Extended Error code to the string table. */ -const char *ext_msgs[] = { /* extended error */ - "K8 ECC error/F10 reserved", /* 0_0000b */ - "CRC error", /* 0_0001b */ - "sync error", /* 0_0010b */ - "mst abort", /* 0_0011b */ - "tgt abort", /* 0_0100b */ - "GART error", /* 0_0101b */ - "RMW error", /* 0_0110b */ - "Wdog timer error", /* 0_0111b */ - "F10-ECC/K8-Chipkill error", /* 0_1000b */ - "DEV Error", /* 0_1001b */ - "Link Data error", /* 0_1010b */ - "Link or L3 Protocol error", /* 0_1011b */ - "NB Array error", /* 0_1100b */ - "DRAM Parity error", /* 0_1101b */ - "Link Retry/GART Table Walk/DEV Table Walk error", /* 0_1110b */ - "Res 0x0ff error", /* 0_1111b */ - "Res 0x100 error", /* 1_0000b */ - "Res 0x101 error", /* 1_0001b */ - "Res 0x102 error", /* 1_0010b */ - "Res 0x103 error", /* 1_0011b */ - "Res 0x104 error", /* 1_0100b */ - "Res 0x105 error", /* 1_0101b */ - "Res 0x106 error", /* 1_0110b */ - "Res 0x107 error", /* 1_0111b */ - "Res 0x108 error", /* 1_1000b */ - "Res 0x109 error", /* 1_1001b */ - "Res 0x10A error", /* 1_1010b */ - "Res 0x10B error", /* 1_1011b */ - "L3 Cache Data error", /* 1_1100b */ - "L3 CacheTag error", /* 1_1101b */ - "L3 Cache LRU error", /* 1_1110b */ - "Res 0x1FF error" /* 1_1111b */ +/* + * Map the 4 or 5 (family-specific) bits of Extended Error code to the + * string table. + */ +const char *ext_msgs[] = { + "K8 ECC error", /* 0_0000b */ + "CRC error on link", /* 0_0001b */ + "Sync error packets on link", /* 0_0010b */ + "Master Abort during link operation", /* 0_0011b */ + "Target Abort during link operation", /* 0_0100b */ + "Invalid GART PTE entry during table walk", /* 0_0101b */ + "Unsupported atomic RMW command received", /* 0_0110b */ + "WDT error: NB transaction timeout", /* 0_0111b */ + "ECC/ChipKill ECC error", /* 0_1000b */ + "SVM DEV Error", /* 0_1001b */ + "Link Data error", /* 0_1010b */ + "Link/L3/Probe Filter Protocol error", /* 0_1011b */ + "NB Internal Arrays Parity error", /* 0_1100b */ + "DRAM Address/Control Parity error", /* 0_1101b */ + "Link Transmission error", /* 0_1110b */ + "GART/DEV Table Walk Data error" /* 0_1111b */ + "Res 0x100 error", /* 1_0000b */ + "Res 0x101 error", /* 1_0001b */ + "Res 0x102 error", /* 1_0010b */ + "Res 0x103 error", /* 1_0011b */ + "Res 0x104 error", /* 1_0100b */ + "Res 0x105 error", /* 1_0101b */ + "Res 0x106 error", /* 1_0110b */ + "Res 0x107 error", /* 1_0111b */ + "Res 0x108 error", /* 1_1000b */ + "Res 0x109 error", /* 1_1001b */ + "Res 0x10A error", /* 1_1010b */ + "Res 0x10B error", /* 1_1011b */ + "ECC error in L3 Cache Data", /* 1_1100b */ + "L3 Cache Tag error", /* 1_1101b */ + "L3 Cache LRU Parity error", /* 1_1110b */ + "Probe Filter error" /* 1_1111b */ }; EXPORT_SYMBOL_GPL(ext_msgs); -- cgit v1.2.3-18-g5258 From ef44cc4c2245d3c43f3c11c7bff6239852eef498 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 23 Jul 2009 14:45:48 +0200 Subject: amd64_edac: cleanup amd64_process_error_info * mv amd64_error_info_regs -> err_regs * remove redundant info ptr Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 44 ++++++++++++++++++++------------------------ drivers/edac/amd64_edac.h | 10 +++++----- 2 files changed, 25 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index b9e84bc9176..c9b88d82970 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -750,7 +750,7 @@ static void find_csrow_limits(struct mem_ctl_info *mci, int csrow, * specific. */ static u64 extract_error_address(struct mem_ctl_info *mci, - struct amd64_error_info_regs *info) + struct err_regs *info) { struct amd64_pvt *pvt = mci->pvt_info; @@ -1106,7 +1106,7 @@ static int k8_early_channel_count(struct amd64_pvt *pvt) /* extract the ERROR ADDRESS for the K8 CPUs */ static u64 k8_get_error_address(struct mem_ctl_info *mci, - struct amd64_error_info_regs *info) + struct err_regs *info) { return (((u64) (info->nbeah & 0xff)) << 32) + (info->nbeal & ~0x03); @@ -1149,7 +1149,7 @@ static void k8_read_dram_base_limit(struct amd64_pvt *pvt, int dram) } static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, - struct amd64_error_info_regs *info, + struct err_regs *info, u64 SystemAddress) { struct mem_ctl_info *src_mci; @@ -1368,7 +1368,7 @@ static void amd64_teardown(struct amd64_pvt *pvt) } static u64 f10_get_error_address(struct mem_ctl_info *mci, - struct amd64_error_info_regs *info) + struct err_regs *info) { return (((u64) (info->nbeah & 0xffff)) << 32) + (info->nbeal & ~0x01); @@ -1745,7 +1745,7 @@ static int f10_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr, * The @sys_addr is usually an error address received from the hardware. */ static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci, - struct amd64_error_info_regs *info, + struct err_regs *info, u64 sys_addr) { struct amd64_pvt *pvt = mci->pvt_info; @@ -2102,7 +2102,7 @@ static int get_channel_from_ecc_syndrome(unsigned short syndrome) * - 0: if no valid error is indicated */ static int amd64_get_error_info_regs(struct mem_ctl_info *mci, - struct amd64_error_info_regs *regs) + struct err_regs *regs) { struct amd64_pvt *pvt; struct pci_dev *misc_f3_ctl; @@ -2151,10 +2151,10 @@ err_reg: * - 0: if no error is found */ static int amd64_get_error_info(struct mem_ctl_info *mci, - struct amd64_error_info_regs *info) + struct err_regs *info) { struct amd64_pvt *pvt; - struct amd64_error_info_regs regs; + struct err_regs regs; pvt = mci->pvt_info; @@ -2210,7 +2210,7 @@ static int amd64_get_error_info(struct mem_ctl_info *mci, } static inline void amd64_decode_gart_tlb_error(struct mem_ctl_info *mci, - struct amd64_error_info_regs *info) + struct err_regs *info) { u32 ec = ERROR_CODE(info->nbsl); @@ -2220,7 +2220,7 @@ static inline void amd64_decode_gart_tlb_error(struct mem_ctl_info *mci, } static inline void amd64_decode_mem_cache_error(struct mem_ctl_info *mci, - struct amd64_error_info_regs *info) + struct err_regs *info) { u32 ec = ERROR_CODE(info->nbsl); @@ -2236,7 +2236,7 @@ static inline void amd64_decode_mem_cache_error(struct mem_ctl_info *mci, * ADDRESS and process. */ static void amd64_handle_ce(struct mem_ctl_info *mci, - struct amd64_error_info_regs *info) + struct err_regs *info) { struct amd64_pvt *pvt = mci->pvt_info; u64 SystemAddress; @@ -2259,7 +2259,7 @@ static void amd64_handle_ce(struct mem_ctl_info *mci, /* Handle any Un-correctable Errors (UEs) */ static void amd64_handle_ue(struct mem_ctl_info *mci, - struct amd64_error_info_regs *info) + struct err_regs *info) { int csrow; u64 SystemAddress; @@ -2305,7 +2305,7 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, } static void amd64_decode_bus_error(struct mem_ctl_info *mci, - struct amd64_error_info_regs *info) + struct err_regs *info) { u32 ec = ERROR_CODE(info->nbsl); u32 xec = EXT_ERROR_CODE(info->nbsl); @@ -2356,22 +2356,18 @@ static void amd64_decode_bus_error(struct mem_ctl_info *mci, } int amd64_process_error_info(struct mem_ctl_info *mci, - struct amd64_error_info_regs *info, + struct err_regs *regs, int handle_errors) { struct amd64_pvt *pvt; - struct amd64_error_info_regs *regs; u32 err_code, ext_ec; int gart_tlb_error = 0; pvt = mci->pvt_info; - /* If caller doesn't want us to process the error, return */ if (!handle_errors) return 1; - regs = info; - debugf1("NorthBridge ERROR: mci(0x%p)\n", mci); debugf1(" MC node(%d) Error-Address(0x%.8x-%.8x)\n", pvt->mc_node_id, regs->nbeah, regs->nbeal); @@ -2437,13 +2433,13 @@ int amd64_process_error_info(struct mem_ctl_info *mci, gart_tlb_error = 1; debugf1("GART TLB error\n"); - amd64_decode_gart_tlb_error(mci, info); + amd64_decode_gart_tlb_error(mci, regs); } else if (MEM_ERROR(err_code)) { debugf1("Memory/Cache error\n"); - amd64_decode_mem_cache_error(mci, info); + amd64_decode_mem_cache_error(mci, regs); } else if (BUS_ERROR(err_code)) { debugf1("Bus (Link/DRAM) error\n"); - amd64_decode_bus_error(mci, info); + amd64_decode_bus_error(mci, regs); } else { /* shouldn't reach here! */ amd64_mc_printk(mci, KERN_WARNING, @@ -2480,10 +2476,10 @@ EXPORT_SYMBOL_GPL(amd64_process_error_info); */ static void amd64_check(struct mem_ctl_info *mci) { - struct amd64_error_info_regs info; + struct err_regs regs; - if (amd64_get_error_info(mci, &info)) - amd64_process_error_info(mci, &info, 1); + if (amd64_get_error_info(mci, ®s)) + amd64_process_error_info(mci, ®s, 1); } /* diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 1ddef8d15d5..bde8f78551f 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -449,7 +449,7 @@ enum amd64_chipset_families { * * Depends on entry into the modules */ -struct amd64_error_info_regs { +struct err_regs { u32 nbcfg; u32 nbsh; u32 nbsl; @@ -527,7 +527,7 @@ struct amd64_pvt { u32 online_spare; /* On-Line spare Reg */ /* temp storage for when input is received from sysfs */ - struct amd64_error_info_regs ctl_error_info; + struct err_regs ctl_error_info; /* place to store error injection parameters prior to issue */ struct error_injection injection; @@ -586,11 +586,11 @@ struct low_ops { int (*early_channel_count)(struct amd64_pvt *pvt); u64 (*get_error_address)(struct mem_ctl_info *mci, - struct amd64_error_info_regs *info); + struct err_regs *info); void (*read_dram_base_limit)(struct amd64_pvt *pvt, int dram); void (*read_dram_ctl_register)(struct amd64_pvt *pvt); void (*map_sysaddr_to_csrow)(struct mem_ctl_info *mci, - struct amd64_error_info_regs *info, + struct err_regs *info, u64 SystemAddr); int (*dbam_map_to_pages)(struct amd64_pvt *pvt, int dram_map); }; @@ -623,7 +623,7 @@ static inline struct low_ops *family_ops(int index) #define F11_MIN_SCRUB_RATE_BITS 0x6 int amd64_process_error_info(struct mem_ctl_info *mci, - struct amd64_error_info_regs *info, + struct err_regs *info, int handle_errors); int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base, u64 *hole_offset, u64 *hole_size); -- cgit v1.2.3-18-g5258 From 5110dbdeab546268dda2e4c6a83448639b2fc5ae Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 25 Jun 2009 19:51:04 +0200 Subject: amd64_edac: cleanup/complete NB MCE decoding * don't dump info which mcheck already does * update to newest BKDG * mv amd64_process_error_info -> amd64_decode_nb_mce * shorten error struct names * remove redundant info ptr in amd64_process_error_info * remove unused ErrorCodeExt[19:16] (MCx_STATUS) defines Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 125 ++++++++++++++++-------------------------- drivers/edac/amd64_edac.h | 26 +++------ drivers/edac/amd64_edac_dbg.c | 2 +- drivers/edac/edac_mce_amd.h | 2 + 4 files changed, 56 insertions(+), 99 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index c9b88d82970..5af87d44c80 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -2355,62 +2355,47 @@ static void amd64_decode_bus_error(struct mem_ctl_info *mci, "Error Overflow set"); } -int amd64_process_error_info(struct mem_ctl_info *mci, - struct err_regs *regs, - int handle_errors) +void amd64_decode_nb_mce(struct mem_ctl_info *mci, struct err_regs *regs, + int handle_errors) { - struct amd64_pvt *pvt; - u32 err_code, ext_ec; - int gart_tlb_error = 0; - - pvt = mci->pvt_info; + struct amd64_pvt *pvt = mci->pvt_info; + int ecc; + u32 ec = ERROR_CODE(regs->nbsl); + u32 xec = EXT_ERROR_CODE(regs->nbsl); if (!handle_errors) - return 1; + return; - debugf1("NorthBridge ERROR: mci(0x%p)\n", mci); - debugf1(" MC node(%d) Error-Address(0x%.8x-%.8x)\n", - pvt->mc_node_id, regs->nbeah, regs->nbeal); - debugf1(" nbsh(0x%.8x) nbsl(0x%.8x)\n", - regs->nbsh, regs->nbsl); - debugf1(" Valid Error=%s Overflow=%s\n", - (regs->nbsh & K8_NBSH_VALID_BIT) ? "True" : "False", - (regs->nbsh & K8_NBSH_OVERFLOW) ? "True" : "False"); - debugf1(" Err Uncorrected=%s MCA Error Reporting=%s\n", - (regs->nbsh & K8_NBSH_UNCORRECTED_ERR) ? - "True" : "False", - (regs->nbsh & K8_NBSH_ERR_ENABLE) ? - "True" : "False"); - debugf1(" MiscErr Valid=%s ErrAddr Valid=%s PCC=%s\n", - (regs->nbsh & K8_NBSH_MISC_ERR_VALID) ? - "True" : "False", - (regs->nbsh & K8_NBSH_VALID_ERROR_ADDR) ? - "True" : "False", - (regs->nbsh & K8_NBSH_PCC) ? - "True" : "False"); - debugf1(" CECC=%s UECC=%s Found by Scruber=%s\n", - (regs->nbsh & K8_NBSH_CECC) ? - "True" : "False", - (regs->nbsh & K8_NBSH_UECC) ? - "True" : "False", - (regs->nbsh & K8_NBSH_ERR_SCRUBER) ? - "True" : "False"); - debugf1(" CORE0=%s CORE1=%s CORE2=%s CORE3=%s\n", - (regs->nbsh & K8_NBSH_CORE0) ? "True" : "False", - (regs->nbsh & K8_NBSH_CORE1) ? "True" : "False", - (regs->nbsh & K8_NBSH_CORE2) ? "True" : "False", - (regs->nbsh & K8_NBSH_CORE3) ? "True" : "False"); + pr_emerg(" Northbridge ERROR, mc node %d", pvt->mc_node_id); + /* + * F10h, revD can disable ErrCpu[3:0] so check that first and also the + * value encoding has changed so interpret those differently + */ + if ((boot_cpu_data.x86 == 0x10) && + (boot_cpu_data.x86_model > 8)) { + if (regs->nbsh & K8_NBSH_ERR_CPU_VAL) + pr_cont(", core: %u\n", (u8)(regs->nbsh & 0xf)); + } else { + pr_cont(", core: %d\n", ilog2((regs->nbsh & 0xf))); + } - err_code = ERROR_CODE(regs->nbsl); + pr_emerg(" Error: %sorrected", + ((regs->nbsh & K8_NBSH_UC_ERR) ? "Unc" : "C")); + pr_cont(", Report Error: %s", + ((regs->nbsh & K8_NBSH_ERR_EN) ? "yes" : "no")); + pr_cont(", MiscV: %svalid, CPU context corrupt: %s", + ((regs->nbsh & K8_NBSH_MISCV) ? "" : "In"), + ((regs->nbsh & K8_NBSH_PCC) ? "yes" : "no")); - /* Determine which error type: - * 1) GART errors - non-fatal, developmental events - * 2) MEMORY errors - * 3) BUS errors - * 4) Unknown error - */ - if (TLB_ERROR(err_code)) { + /* do the two bits[14:13] together */ + ecc = regs->nbsh & (0x3 << 13); + if (ecc) + pr_cont(", %sECC Error", ((ecc == 2) ? "C" : "U")); + + pr_cont("\n"); + + if (TLB_ERROR(ec)) { /* * GART errors are intended to help graphics driver developers * to detect bad GART PTEs. It is recommended by AMD to disable @@ -2423,52 +2408,34 @@ int amd64_process_error_info(struct mem_ctl_info *mci, * [1] section 13.10.1 on BIOS and Kernel Developers Guide for * AMD NPT family 0Fh processors */ - if (report_gart_errors == 0) - return 1; - - /* - * Only if GART error reporting is requested should we generate - * any logs. - */ - gart_tlb_error = 1; + if (!report_gart_errors) + return; - debugf1("GART TLB error\n"); + pr_emerg("GART TLB error\n"); amd64_decode_gart_tlb_error(mci, regs); - } else if (MEM_ERROR(err_code)) { - debugf1("Memory/Cache error\n"); + } else if (MEM_ERROR(ec)) { + pr_emerg("Memory/Cache error\n"); amd64_decode_mem_cache_error(mci, regs); - } else if (BUS_ERROR(err_code)) { - debugf1("Bus (Link/DRAM) error\n"); + } else if (BUS_ERROR(ec)) { + pr_emerg("Bus (Link/DRAM) error\n"); amd64_decode_bus_error(mci, regs); } else { /* shouldn't reach here! */ amd64_mc_printk(mci, KERN_WARNING, "%s(): unknown MCE error 0x%x\n", __func__, - err_code); + ec); } - ext_ec = EXT_ERROR_CODE(regs->nbsl); - amd64_mc_printk(mci, KERN_ERR, - "ExtErr=(0x%x) %s\n", ext_ec, ext_msgs[ext_ec]); + pr_emerg("%s.\n", EXT_ERR_MSG(xec)); /* * Check the UE bit of the NB status high register, if set generate some * logs. If NOT a GART error, then process the event as a NO-INFO event. * If it was a GART error, skip that process. */ - if (regs->nbsh & K8_NBSH_UNCORRECTED_ERR) { - amd64_mc_printk(mci, KERN_CRIT, "uncorrected error\n"); - if (!gart_tlb_error) - edac_mc_handle_ue_no_info(mci, "UE bit is set\n"); - } - - if (regs->nbsh & K8_NBSH_PCC) - amd64_mc_printk(mci, KERN_CRIT, - "PCC (processor context corrupt) set\n"); - - return 1; + if (regs->nbsh & K8_NBSH_UC_ERR && !report_gart_errors) + edac_mc_handle_ue_no_info(mci, "UE bit is set"); } -EXPORT_SYMBOL_GPL(amd64_process_error_info); /* * The main polling 'check' function, called FROM the edac core to perform the @@ -2479,7 +2446,7 @@ static void amd64_check(struct mem_ctl_info *mci) struct err_regs regs; if (amd64_get_error_info(mci, ®s)) - amd64_process_error_info(mci, ®s, 1); + amd64_decode_nb_mce(mci, ®s, 1); } /* diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index bde8f78551f..ecab0c9fd14 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -306,16 +306,7 @@ enum { /* Family F10h: Normalized Extended Error Codes */ #define F10_NBSL_EXT_ERR_RES 0x0 -#define F10_NBSL_EXT_ERR_CRC 0x1 -#define F10_NBSL_EXT_ERR_SYNC 0x2 -#define F10_NBSL_EXT_ERR_MST 0x3 -#define F10_NBSL_EXT_ERR_TGT 0x4 -#define F10_NBSL_EXT_ERR_GART 0x5 -#define F10_NBSL_EXT_ERR_RMW 0x6 -#define F10_NBSL_EXT_ERR_WDT 0x7 #define F10_NBSL_EXT_ERR_ECC 0x8 -#define F10_NBSL_EXT_ERR_DEV 0x9 -#define F10_NBSL_EXT_ERR_LINK_DATA 0xA /* Next two are overloaded values */ #define F10_NBSL_EXT_ERR_LINK_PROTO 0xB @@ -360,18 +351,15 @@ enum { #define K8_NBSH_VALID_BIT BIT(31) #define K8_NBSH_OVERFLOW BIT(30) -#define K8_NBSH_UNCORRECTED_ERR BIT(29) -#define K8_NBSH_ERR_ENABLE BIT(28) -#define K8_NBSH_MISC_ERR_VALID BIT(27) +#define K8_NBSH_UC_ERR BIT(29) +#define K8_NBSH_ERR_EN BIT(28) +#define K8_NBSH_MISCV BIT(27) #define K8_NBSH_VALID_ERROR_ADDR BIT(26) #define K8_NBSH_PCC BIT(25) +#define K8_NBSH_ERR_CPU_VAL BIT(24) #define K8_NBSH_CECC BIT(14) #define K8_NBSH_UECC BIT(13) #define K8_NBSH_ERR_SCRUBER BIT(8) -#define K8_NBSH_CORE3 BIT(3) -#define K8_NBSH_CORE2 BIT(2) -#define K8_NBSH_CORE1 BIT(1) -#define K8_NBSH_CORE0 BIT(0) #define EXTRACT_ERR_CPU_MAP(x) ((x) & 0xF) @@ -622,8 +610,8 @@ static inline struct low_ops *family_ops(int index) #define F10_MIN_SCRUB_RATE_BITS 0x5 #define F11_MIN_SCRUB_RATE_BITS 0x6 -int amd64_process_error_info(struct mem_ctl_info *mci, - struct err_regs *info, - int handle_errors); +void amd64_decode_nb_mce(struct mem_ctl_info *mci, struct err_regs *info, + int handle_errors); + int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base, u64 *hole_offset, u64 *hole_size); diff --git a/drivers/edac/amd64_edac_dbg.c b/drivers/edac/amd64_edac_dbg.c index 0a41b248a4a..bcb4e2eba3d 100644 --- a/drivers/edac/amd64_edac_dbg.c +++ b/drivers/edac/amd64_edac_dbg.c @@ -24,7 +24,7 @@ static ssize_t amd64_nbea_store(struct mem_ctl_info *mci, const char *data, /* Process the Mapping request */ /* TODO: Add race prevention */ - amd64_process_error_info(mci, &pvt->ctl_error_info, 1); + amd64_decode_nb_mce(mci, &pvt->ctl_error_info, 1); return count; } diff --git a/drivers/edac/edac_mce_amd.h b/drivers/edac/edac_mce_amd.h index 81f9dcf9990..39971cdabb5 100644 --- a/drivers/edac/edac_mce_amd.h +++ b/drivers/edac/edac_mce_amd.h @@ -1,5 +1,7 @@ #define ERROR_CODE(x) ((x) & 0xffff) #define EXT_ERROR_CODE(x) (((x) >> 16) & 0x1f) +#define EXT_ERR_MSG(x) ext_msgs[EXT_ERROR_CODE(x)] + #define LOW_SYNDROME(x) (((x) >> 15) & 0xff) #define HIGH_SYNDROME(x) (((x) >> 24) & 0xff) -- cgit v1.2.3-18-g5258 From b7225e4fc19ce27a594cb2b868ef151bf82f8f93 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 23 Jul 2009 16:05:53 +0200 Subject: amd64_edac: remove memory and GART TLB error decoders Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 36 +++++++----------------------------- 1 file changed, 7 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 5af87d44c80..75842f08db8 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -2209,28 +2209,6 @@ static int amd64_get_error_info(struct mem_ctl_info *mci, return 1; } -static inline void amd64_decode_gart_tlb_error(struct mem_ctl_info *mci, - struct err_regs *info) -{ - u32 ec = ERROR_CODE(info->nbsl); - - amd64_mc_printk(mci, KERN_ERR, - "GART TLB event: transaction type(%s), " - "cache level(%s)\n", TT_MSG(ec), LL_MSG(ec)); -} - -static inline void amd64_decode_mem_cache_error(struct mem_ctl_info *mci, - struct err_regs *info) -{ - u32 ec = ERROR_CODE(info->nbsl); - - amd64_mc_printk(mci, KERN_ERR, - "cache hierarchy error: memory transaction type(%s), " - "transaction type(%s), cache level(%s)\n", - RRRR_MSG(ec), TT_MSG(ec), LL_MSG(ec)); -} - - /* * Handle any Correctable Errors (CEs) that have occurred. Check for valid ERROR * ADDRESS and process. @@ -2411,19 +2389,19 @@ void amd64_decode_nb_mce(struct mem_ctl_info *mci, struct err_regs *regs, if (!report_gart_errors) return; - pr_emerg("GART TLB error\n"); - amd64_decode_gart_tlb_error(mci, regs); + pr_emerg(" GART TLB error, Transaction: %s, Cache Level %s\n", + TT_MSG(ec), LL_MSG(ec)); } else if (MEM_ERROR(ec)) { - pr_emerg("Memory/Cache error\n"); - amd64_decode_mem_cache_error(mci, regs); + pr_emerg(" Memory/Cache error, Transaction: %s, Type: %s," + " Cache Level: %s", + RRRR_MSG(ec), TT_MSG(ec), LL_MSG(ec)); } else if (BUS_ERROR(ec)) { - pr_emerg("Bus (Link/DRAM) error\n"); + pr_emerg(" Bus (Link/DRAM) error\n"); amd64_decode_bus_error(mci, regs); } else { /* shouldn't reach here! */ amd64_mc_printk(mci, KERN_WARNING, - "%s(): unknown MCE error 0x%x\n", __func__, - ec); + "%s(): unknown MCE error 0x%x\n", __func__, ec); } pr_emerg("%s.\n", EXT_ERR_MSG(xec)); -- cgit v1.2.3-18-g5258 From ecaf5606de65cdd04de5f526185fe28fb0df654e Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 23 Jul 2009 16:32:01 +0200 Subject: amd64_edac: cleanup amd64_decode_bus_error Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 75842f08db8..82f48ee90f1 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -2283,42 +2283,26 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, } static void amd64_decode_bus_error(struct mem_ctl_info *mci, - struct err_regs *info) + struct err_regs *info, int ecc_type) { u32 ec = ERROR_CODE(info->nbsl); u32 xec = EXT_ERROR_CODE(info->nbsl); - amd64_mc_printk(mci, KERN_ERR, - "BUS ERROR:\n" - " time-out(%s) mem or i/o(%s)\n" - " participating processor(%s)\n" - " memory transaction type(%s)\n" - " cache level(%s) Error Found by: %s\n", - TO_MSG(ec), II_MSG(ec), PP_MSG(ec), RRRR_MSG(ec), LL_MSG(ec), - (info->nbsh & K8_NBSH_ERR_SCRUBER) ? - "Scrubber" : "Normal Operation"); + pr_emerg(" Transaction type: %s(%s), %s, Cache Level: %s, %s\n", + RRRR_MSG(ec), II_MSG(ec), TO_MSG(ec), LL_MSG(ec), PP_MSG(ec)); /* Bail early out if this was an 'observed' error */ if (PP(ec) == K8_NBSL_PP_OBS) return; - /* Parse out the extended error code for ECC events */ - switch (xec) { - /* F10 changed to one Extended ECC error code */ - case F10_NBSL_EXT_ERR_RES: /* Reserved field */ - case F10_NBSL_EXT_ERR_ECC: /* F10 ECC ext err code */ - break; - - default: - amd64_mc_printk(mci, KERN_ERR, "NOT ECC: no special error " - "handling for this error\n"); + /* Do only ECC errors */ + if (xec && xec != F10_NBSL_EXT_ERR_ECC) return; - } - if (info->nbsh & K8_NBSH_CECC) + if (ecc_type == 2) amd64_handle_ce(mci, info); - else if (info->nbsh & K8_NBSH_UECC) + else if (ecc_type == 1) amd64_handle_ue(mci, info); /* @@ -2329,8 +2313,7 @@ static void amd64_decode_bus_error(struct mem_ctl_info *mci, * catastrophic. */ if (info->nbsh & K8_NBSH_OVERFLOW) - edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR - "Error Overflow set"); + edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR "Error Overflow"); } void amd64_decode_nb_mce(struct mem_ctl_info *mci, struct err_regs *regs, @@ -2397,7 +2380,7 @@ void amd64_decode_nb_mce(struct mem_ctl_info *mci, struct err_regs *regs, RRRR_MSG(ec), TT_MSG(ec), LL_MSG(ec)); } else if (BUS_ERROR(ec)) { pr_emerg(" Bus (Link/DRAM) error\n"); - amd64_decode_bus_error(mci, regs); + amd64_decode_bus_error(mci, regs, ecc); } else { /* shouldn't reach here! */ amd64_mc_printk(mci, KERN_WARNING, -- cgit v1.2.3-18-g5258 From 549d042df240dfb4203bab40ad44f9336751b7d6 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 24 Jul 2009 13:51:42 +0200 Subject: x86, mce: pass mce info to EDAC for decoding Move NB decoder along with required defines to EDAC MCE core. Add registration routines for further decoding of the MCE info in the AMD64 EDAC module. CC: Andi Kleen Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 98 +++++++++-------------------------- drivers/edac/amd64_edac.h | 36 ------------- drivers/edac/amd64_edac_dbg.c | 2 +- drivers/edac/edac_mce_amd.c | 115 ++++++++++++++++++++++++++++++++++++++++++ drivers/edac/edac_mce_amd.h | 38 ++++++++++++++ 5 files changed, 178 insertions(+), 111 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 82f48ee90f1..2080b1e2e8a 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -2282,8 +2282,8 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, } } -static void amd64_decode_bus_error(struct mem_ctl_info *mci, - struct err_regs *info, int ecc_type) +static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci, + struct err_regs *info, int ecc_type) { u32 ec = ERROR_CODE(info->nbsl); u32 xec = EXT_ERROR_CODE(info->nbsl); @@ -2316,86 +2316,23 @@ static void amd64_decode_bus_error(struct mem_ctl_info *mci, edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR "Error Overflow"); } -void amd64_decode_nb_mce(struct mem_ctl_info *mci, struct err_regs *regs, - int handle_errors) +void amd64_decode_bus_error(int node_id, struct err_regs *regs, + int ecc_type) { - struct amd64_pvt *pvt = mci->pvt_info; - int ecc; - u32 ec = ERROR_CODE(regs->nbsl); - u32 xec = EXT_ERROR_CODE(regs->nbsl); - - if (!handle_errors) - return; - - pr_emerg(" Northbridge ERROR, mc node %d", pvt->mc_node_id); - - /* - * F10h, revD can disable ErrCpu[3:0] so check that first and also the - * value encoding has changed so interpret those differently - */ - if ((boot_cpu_data.x86 == 0x10) && - (boot_cpu_data.x86_model > 8)) { - if (regs->nbsh & K8_NBSH_ERR_CPU_VAL) - pr_cont(", core: %u\n", (u8)(regs->nbsh & 0xf)); - } else { - pr_cont(", core: %d\n", ilog2((regs->nbsh & 0xf))); - } - - pr_emerg(" Error: %sorrected", - ((regs->nbsh & K8_NBSH_UC_ERR) ? "Unc" : "C")); - pr_cont(", Report Error: %s", - ((regs->nbsh & K8_NBSH_ERR_EN) ? "yes" : "no")); - pr_cont(", MiscV: %svalid, CPU context corrupt: %s", - ((regs->nbsh & K8_NBSH_MISCV) ? "" : "In"), - ((regs->nbsh & K8_NBSH_PCC) ? "yes" : "no")); - - /* do the two bits[14:13] together */ - ecc = regs->nbsh & (0x3 << 13); - if (ecc) - pr_cont(", %sECC Error", ((ecc == 2) ? "C" : "U")); - - pr_cont("\n"); - - if (TLB_ERROR(ec)) { - /* - * GART errors are intended to help graphics driver developers - * to detect bad GART PTEs. It is recommended by AMD to disable - * GART table walk error reporting by default[1] (currently - * being disabled in mce_cpu_quirks()) and according to the - * comment in mce_cpu_quirks(), such GART errors can be - * incorrectly triggered. We may see these errors anyway and - * unless requested by the user, they won't be reported. - * - * [1] section 13.10.1 on BIOS and Kernel Developers Guide for - * AMD NPT family 0Fh processors - */ - if (!report_gart_errors) - return; - - pr_emerg(" GART TLB error, Transaction: %s, Cache Level %s\n", - TT_MSG(ec), LL_MSG(ec)); - } else if (MEM_ERROR(ec)) { - pr_emerg(" Memory/Cache error, Transaction: %s, Type: %s," - " Cache Level: %s", - RRRR_MSG(ec), TT_MSG(ec), LL_MSG(ec)); - } else if (BUS_ERROR(ec)) { - pr_emerg(" Bus (Link/DRAM) error\n"); - amd64_decode_bus_error(mci, regs, ecc); - } else { - /* shouldn't reach here! */ - amd64_mc_printk(mci, KERN_WARNING, - "%s(): unknown MCE error 0x%x\n", __func__, ec); - } + struct mem_ctl_info *mci = mci_lookup[node_id]; - pr_emerg("%s.\n", EXT_ERR_MSG(xec)); + __amd64_decode_bus_error(mci, regs, ecc_type); /* * Check the UE bit of the NB status high register, if set generate some * logs. If NOT a GART error, then process the event as a NO-INFO event. * If it was a GART error, skip that process. + * + * FIXME: this should go somewhere else, if at all. */ if (regs->nbsh & K8_NBSH_UC_ERR && !report_gart_errors) edac_mc_handle_ue_no_info(mci, "UE bit is set"); + } /* @@ -2406,8 +2343,10 @@ static void amd64_check(struct mem_ctl_info *mci) { struct err_regs regs; - if (amd64_get_error_info(mci, ®s)) - amd64_decode_nb_mce(mci, ®s, 1); + if (amd64_get_error_info(mci, ®s)) { + struct amd64_pvt *pvt = mci->pvt_info; + amd_decode_nb_mce(pvt->mc_node_id, ®s, 1); + } } /* @@ -3103,6 +3042,13 @@ static int amd64_init_2nd_stage(struct amd64_pvt *pvt) mci_lookup[node_id] = mci; pvt_lookup[node_id] = NULL; + + /* register stuff with EDAC MCE */ + if (report_gart_errors) + amd_report_gart_errors(true); + + amd_register_ecc_decoder(amd64_decode_bus_error); + return 0; err_add_mc: @@ -3169,6 +3115,10 @@ static void __devexit amd64_remove_one_instance(struct pci_dev *pdev) mci_lookup[pvt->mc_node_id] = NULL; + /* unregister from EDAC MCE */ + amd_report_gart_errors(false); + amd_unregister_ecc_decoder(amd64_decode_bus_error); + /* Free the EDAC CORE resources */ edac_mc_free(mci); } diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index ecab0c9fd14..8ea07e2715d 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -346,24 +346,8 @@ enum { #define K8_NBSL_PP_OBS 0x2 #define K8_NBSL_PP_GENERIC 0x3 - -#define K8_NBSH 0x4C - -#define K8_NBSH_VALID_BIT BIT(31) -#define K8_NBSH_OVERFLOW BIT(30) -#define K8_NBSH_UC_ERR BIT(29) -#define K8_NBSH_ERR_EN BIT(28) -#define K8_NBSH_MISCV BIT(27) -#define K8_NBSH_VALID_ERROR_ADDR BIT(26) -#define K8_NBSH_PCC BIT(25) -#define K8_NBSH_ERR_CPU_VAL BIT(24) -#define K8_NBSH_CECC BIT(14) -#define K8_NBSH_UECC BIT(13) -#define K8_NBSH_ERR_SCRUBER BIT(8) - #define EXTRACT_ERR_CPU_MAP(x) ((x) & 0xF) - #define K8_NBEAL 0x50 #define K8_NBEAH 0x54 #define K8_SCRCTRL 0x58 @@ -428,23 +412,6 @@ enum amd64_chipset_families { F11_CPUS, }; -/* - * Structure to hold: - * - * 1) dynamically read status and error address HW registers - * 2) sysfs entered values - * 3) MCE values - * - * Depends on entry into the modules - */ -struct err_regs { - u32 nbcfg; - u32 nbsh; - u32 nbsl; - u32 nbeah; - u32 nbeal; -}; - /* Error injection control structure */ struct error_injection { u32 section; @@ -610,8 +577,5 @@ static inline struct low_ops *family_ops(int index) #define F10_MIN_SCRUB_RATE_BITS 0x5 #define F11_MIN_SCRUB_RATE_BITS 0x6 -void amd64_decode_nb_mce(struct mem_ctl_info *mci, struct err_regs *info, - int handle_errors); - int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base, u64 *hole_offset, u64 *hole_size); diff --git a/drivers/edac/amd64_edac_dbg.c b/drivers/edac/amd64_edac_dbg.c index bcb4e2eba3d..59cf2cf6e11 100644 --- a/drivers/edac/amd64_edac_dbg.c +++ b/drivers/edac/amd64_edac_dbg.c @@ -24,7 +24,7 @@ static ssize_t amd64_nbea_store(struct mem_ctl_info *mci, const char *data, /* Process the Mapping request */ /* TODO: Add race prevention */ - amd64_decode_nb_mce(mci, &pvt->ctl_error_info, 1); + amd_decode_nb_mce(pvt->mc_node_id, &pvt->ctl_error_info, 1); return count; } diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c index 918567e8cfd..444c2cc4472 100644 --- a/drivers/edac/edac_mce_amd.c +++ b/drivers/edac/edac_mce_amd.c @@ -1,6 +1,31 @@ #include #include "edac_mce_amd.h" +static bool report_gart_errors; +static void (*nb_bus_decoder)(int node_id, struct err_regs *regs, int ecc_type); + +void amd_report_gart_errors(bool v) +{ + report_gart_errors = v; +} +EXPORT_SYMBOL_GPL(amd_report_gart_errors); + +void amd_register_ecc_decoder(void (*f)(int, struct err_regs *, int)) +{ + nb_bus_decoder = f; +} +EXPORT_SYMBOL_GPL(amd_register_ecc_decoder); + +void amd_unregister_ecc_decoder(void (*f)(int, struct err_regs *, int)) +{ + if (nb_bus_decoder) { + WARN_ON(nb_bus_decoder != f); + + nb_bus_decoder = NULL; + } +} +EXPORT_SYMBOL_GPL(amd_unregister_ecc_decoder); + /* * string representation for the different MCA reported error types, see F3x48 * or MSR0000_0411. @@ -102,3 +127,93 @@ const char *ext_msgs[] = { "Probe Filter error" /* 1_1111b */ }; EXPORT_SYMBOL_GPL(ext_msgs); + +void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors) +{ + int ecc; + u32 ec = ERROR_CODE(regs->nbsl); + u32 xec = EXT_ERROR_CODE(regs->nbsl); + + if (!handle_errors) + return; + + pr_emerg(" Northbridge Error, node %d", node_id); + + /* + * F10h, revD can disable ErrCpu[3:0] so check that first and also the + * value encoding has changed so interpret those differently + */ + if ((boot_cpu_data.x86 == 0x10) && + (boot_cpu_data.x86_model > 8)) { + if (regs->nbsh & K8_NBSH_ERR_CPU_VAL) + pr_cont(", core: %u\n", (u8)(regs->nbsh & 0xf)); + } else { + pr_cont(", core: %d\n", ilog2((regs->nbsh & 0xf))); + } + + pr_emerg(" Error: %sorrected", + ((regs->nbsh & K8_NBSH_UC_ERR) ? "Unc" : "C")); + pr_cont(", Report Error: %s", + ((regs->nbsh & K8_NBSH_ERR_EN) ? "yes" : "no")); + pr_cont(", MiscV: %svalid, CPU context corrupt: %s", + ((regs->nbsh & K8_NBSH_MISCV) ? "" : "In"), + ((regs->nbsh & K8_NBSH_PCC) ? "yes" : "no")); + + /* do the two bits[14:13] together */ + ecc = regs->nbsh & (0x3 << 13); + if (ecc) + pr_cont(", %sECC Error", ((ecc == 2) ? "C" : "U")); + + pr_cont("\n"); + + if (TLB_ERROR(ec)) { + /* + * GART errors are intended to help graphics driver developers + * to detect bad GART PTEs. It is recommended by AMD to disable + * GART table walk error reporting by default[1] (currently + * being disabled in mce_cpu_quirks()) and according to the + * comment in mce_cpu_quirks(), such GART errors can be + * incorrectly triggered. We may see these errors anyway and + * unless requested by the user, they won't be reported. + * + * [1] section 13.10.1 on BIOS and Kernel Developers Guide for + * AMD NPT family 0Fh processors + */ + if (!report_gart_errors) + return; + + pr_emerg(" GART TLB error, Transaction: %s, Cache Level %s\n", + TT_MSG(ec), LL_MSG(ec)); + } else if (MEM_ERROR(ec)) { + pr_emerg(" Memory/Cache error, Transaction: %s, Type: %s," + " Cache Level: %s", + RRRR_MSG(ec), TT_MSG(ec), LL_MSG(ec)); + } else if (BUS_ERROR(ec)) { + pr_emerg(" Bus (Link/DRAM) error\n"); + if (nb_bus_decoder) + nb_bus_decoder(node_id, regs, ecc); + } else { + /* shouldn't reach here! */ + pr_warning("%s: unknown MCE error 0x%x\n", __func__, ec); + } + + pr_emerg("%s.\n", EXT_ERR_MSG(xec)); +} +EXPORT_SYMBOL_GPL(amd_decode_nb_mce); + +void decode_mce(struct mce *m) +{ + struct err_regs regs; + int node; + + if (m->bank != 4) + return; + + regs.nbsl = (u32) m->status; + regs.nbsh = (u32)(m->status >> 32); + regs.nbeal = (u32) m->addr; + regs.nbeah = (u32)(m->addr >> 32); + node = topology_cpu_node_id(m->extcpu); + + amd_decode_nb_mce(node, ®s, 1); +} diff --git a/drivers/edac/edac_mce_amd.h b/drivers/edac/edac_mce_amd.h index 39971cdabb5..9114dc62782 100644 --- a/drivers/edac/edac_mce_amd.h +++ b/drivers/edac/edac_mce_amd.h @@ -1,3 +1,8 @@ +#ifndef _EDAC_MCE_AMD_H +#define _EDAC_MCE_AMD_H + +#include + #define ERROR_CODE(x) ((x) & 0xffff) #define EXT_ERROR_CODE(x) (((x) >> 16) & 0x1f) #define EXT_ERR_MSG(x) ext_msgs[EXT_ERROR_CODE(x)] @@ -22,6 +27,20 @@ #define PP(x) (((x) >> 9) & 0x3) #define PP_MSG(x) pp_msgs[PP(x)] +#define K8_NBSH 0x4C + +#define K8_NBSH_VALID_BIT BIT(31) +#define K8_NBSH_OVERFLOW BIT(30) +#define K8_NBSH_UC_ERR BIT(29) +#define K8_NBSH_ERR_EN BIT(28) +#define K8_NBSH_MISCV BIT(27) +#define K8_NBSH_VALID_ERROR_ADDR BIT(26) +#define K8_NBSH_PCC BIT(25) +#define K8_NBSH_ERR_CPU_VAL BIT(24) +#define K8_NBSH_CECC BIT(14) +#define K8_NBSH_UECC BIT(13) +#define K8_NBSH_ERR_SCRUBER BIT(8) + extern const char *tt_msgs[]; extern const char *ll_msgs[]; extern const char *rrrr_msgs[]; @@ -29,3 +48,22 @@ extern const char *pp_msgs[]; extern const char *to_msgs[]; extern const char *ii_msgs[]; extern const char *ext_msgs[]; + +/* + * relevant NB regs + */ +struct err_regs { + u32 nbcfg; + u32 nbsh; + u32 nbsl; + u32 nbeah; + u32 nbeal; +}; + + +void amd_report_gart_errors(bool); +void amd_register_ecc_decoder(void (*f)(int, struct err_regs *, int)); +void amd_unregister_ecc_decoder(void (*f)(int, struct err_regs *, int)); +void amd_decode_nb_mce(int, struct err_regs *, int); + +#endif /* _EDAC_MCE_AMD_H */ -- cgit v1.2.3-18-g5258 From b69b29de65fe4078b125acc9dea34be82f7c362c Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 27 Jul 2009 16:21:14 +0200 Subject: EDAC, AMD: carve out MCi_STATUS decoding The MCi_STATUS registers have most field definitions in common so decode them in the general path. Do not pass ecc_type along and compute it in __amd64_decode_bus_error instead. Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 8 +++---- drivers/edac/edac_mce_amd.c | 57 ++++++++++++++++++++++----------------------- drivers/edac/edac_mce_amd.h | 4 ++-- 3 files changed, 34 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 2080b1e2e8a..c81ca2cf8dc 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -2283,10 +2283,11 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, } static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci, - struct err_regs *info, int ecc_type) + struct err_regs *info) { u32 ec = ERROR_CODE(info->nbsl); u32 xec = EXT_ERROR_CODE(info->nbsl); + int ecc_type = info->nbsh & (0x3 << 13); pr_emerg(" Transaction type: %s(%s), %s, Cache Level: %s, %s\n", RRRR_MSG(ec), II_MSG(ec), TO_MSG(ec), LL_MSG(ec), PP_MSG(ec)); @@ -2316,12 +2317,11 @@ static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci, edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR "Error Overflow"); } -void amd64_decode_bus_error(int node_id, struct err_regs *regs, - int ecc_type) +void amd64_decode_bus_error(int node_id, struct err_regs *regs) { struct mem_ctl_info *mci = mci_lookup[node_id]; - __amd64_decode_bus_error(mci, regs, ecc_type); + __amd64_decode_bus_error(mci, regs); /* * Check the UE bit of the NB status high register, if set generate some diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c index 444c2cc4472..0ba92d65db4 100644 --- a/drivers/edac/edac_mce_amd.c +++ b/drivers/edac/edac_mce_amd.c @@ -2,7 +2,7 @@ #include "edac_mce_amd.h" static bool report_gart_errors; -static void (*nb_bus_decoder)(int node_id, struct err_regs *regs, int ecc_type); +static void (*nb_bus_decoder)(int node_id, struct err_regs *regs); void amd_report_gart_errors(bool v) { @@ -10,13 +10,13 @@ void amd_report_gart_errors(bool v) } EXPORT_SYMBOL_GPL(amd_report_gart_errors); -void amd_register_ecc_decoder(void (*f)(int, struct err_regs *, int)) +void amd_register_ecc_decoder(void (*f)(int, struct err_regs *)) { nb_bus_decoder = f; } EXPORT_SYMBOL_GPL(amd_register_ecc_decoder); -void amd_unregister_ecc_decoder(void (*f)(int, struct err_regs *, int)) +void amd_unregister_ecc_decoder(void (*f)(int, struct err_regs *)) { if (nb_bus_decoder) { WARN_ON(nb_bus_decoder != f); @@ -130,7 +130,6 @@ EXPORT_SYMBOL_GPL(ext_msgs); void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors) { - int ecc; u32 ec = ERROR_CODE(regs->nbsl); u32 xec = EXT_ERROR_CODE(regs->nbsl); @@ -151,21 +150,6 @@ void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors) pr_cont(", core: %d\n", ilog2((regs->nbsh & 0xf))); } - pr_emerg(" Error: %sorrected", - ((regs->nbsh & K8_NBSH_UC_ERR) ? "Unc" : "C")); - pr_cont(", Report Error: %s", - ((regs->nbsh & K8_NBSH_ERR_EN) ? "yes" : "no")); - pr_cont(", MiscV: %svalid, CPU context corrupt: %s", - ((regs->nbsh & K8_NBSH_MISCV) ? "" : "In"), - ((regs->nbsh & K8_NBSH_PCC) ? "yes" : "no")); - - /* do the two bits[14:13] together */ - ecc = regs->nbsh & (0x3 << 13); - if (ecc) - pr_cont(", %sECC Error", ((ecc == 2) ? "C" : "U")); - - pr_cont("\n"); - if (TLB_ERROR(ec)) { /* * GART errors are intended to help graphics driver developers @@ -191,7 +175,7 @@ void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors) } else if (BUS_ERROR(ec)) { pr_emerg(" Bus (Link/DRAM) error\n"); if (nb_bus_decoder) - nb_bus_decoder(node_id, regs, ecc); + nb_bus_decoder(node_id, regs); } else { /* shouldn't reach here! */ pr_warning("%s: unknown MCE error 0x%x\n", __func__, ec); @@ -204,16 +188,31 @@ EXPORT_SYMBOL_GPL(amd_decode_nb_mce); void decode_mce(struct mce *m) { struct err_regs regs; - int node; + int node, ecc; - if (m->bank != 4) - return; + pr_emerg("MC%d_STATUS:\n", m->bank); - regs.nbsl = (u32) m->status; - regs.nbsh = (u32)(m->status >> 32); - regs.nbeal = (u32) m->addr; - regs.nbeah = (u32)(m->addr >> 32); - node = topology_cpu_node_id(m->extcpu); + pr_emerg(" Error: %sorrected, Report: %s, MiscV: %svalid, " + "CPU context corrupt: %s", + ((m->status & MCI_STATUS_UC) ? "Unc" : "C"), + ((m->status & MCI_STATUS_EN) ? "yes" : "no"), + ((m->status & MCI_STATUS_MISCV) ? "" : "in"), + ((m->status & MCI_STATUS_PCC) ? "yes" : "no")); - amd_decode_nb_mce(node, ®s, 1); + /* do the two bits[14:13] together */ + ecc = m->status & (3ULL << 45); + if (ecc) + pr_cont(", %sECC Error", ((ecc == 2) ? "C" : "U")); + + pr_cont("\n"); + + if (m->bank == 4) { + regs.nbsl = (u32) m->status; + regs.nbsh = (u32)(m->status >> 32); + regs.nbeal = (u32) m->addr; + regs.nbeah = (u32)(m->addr >> 32); + node = per_cpu(cpu_llc_id, m->extcpu); + + amd_decode_nb_mce(node, ®s, 1); + } } diff --git a/drivers/edac/edac_mce_amd.h b/drivers/edac/edac_mce_amd.h index 9114dc62782..df23ee065f7 100644 --- a/drivers/edac/edac_mce_amd.h +++ b/drivers/edac/edac_mce_amd.h @@ -62,8 +62,8 @@ struct err_regs { void amd_report_gart_errors(bool); -void amd_register_ecc_decoder(void (*f)(int, struct err_regs *, int)); -void amd_unregister_ecc_decoder(void (*f)(int, struct err_regs *, int)); +void amd_register_ecc_decoder(void (*f)(int, struct err_regs *)); +void amd_unregister_ecc_decoder(void (*f)(int, struct err_regs *)); void amd_decode_nb_mce(int, struct err_regs *, int); #endif /* _EDAC_MCE_AMD_H */ -- cgit v1.2.3-18-g5258 From d93cc222adf3532ddb442648f8db00c15d1dc4c1 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 28 Jul 2009 10:56:15 +0200 Subject: EDAC, AMD: carve out decoding of MCi_STATUS ErrorCode This is the MCE error code from the MCi_STATUS banks, bits [15:0] which describe what type of error was encountered: GART TLB, Memory or Bus error. The semantics of those bits are identical across all MCE banks so decode those separately, irrespectively of MCE type. Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 4 ---- drivers/edac/edac_mce_amd.c | 37 ++++++++++++++++++++++--------------- 2 files changed, 22 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index c81ca2cf8dc..173dc4a8416 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -2289,10 +2289,6 @@ static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci, u32 xec = EXT_ERROR_CODE(info->nbsl); int ecc_type = info->nbsh & (0x3 << 13); - pr_emerg(" Transaction type: %s(%s), %s, Cache Level: %s, %s\n", - RRRR_MSG(ec), II_MSG(ec), TO_MSG(ec), LL_MSG(ec), PP_MSG(ec)); - - /* Bail early out if this was an 'observed' error */ if (PP(ec) == K8_NBSL_PP_OBS) return; diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c index 0ba92d65db4..81f812eb3ae 100644 --- a/drivers/edac/edac_mce_amd.c +++ b/drivers/edac/edac_mce_amd.c @@ -150,6 +150,16 @@ void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors) pr_cont(", core: %d\n", ilog2((regs->nbsh & 0xf))); } + + pr_emerg("%s.\n", EXT_ERR_MSG(xec)); + + if (BUS_ERROR(ec) && nb_bus_decoder) + nb_bus_decoder(node_id, regs); +} +EXPORT_SYMBOL_GPL(amd_decode_nb_mce); + +static inline void amd_decode_err_code(unsigned int ec) +{ if (TLB_ERROR(ec)) { /* * GART errors are intended to help graphics driver developers @@ -166,33 +176,28 @@ void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors) if (!report_gart_errors) return; - pr_emerg(" GART TLB error, Transaction: %s, Cache Level %s\n", + pr_emerg(" Transaction: %s, Cache Level %s\n", TT_MSG(ec), LL_MSG(ec)); } else if (MEM_ERROR(ec)) { - pr_emerg(" Memory/Cache error, Transaction: %s, Type: %s," - " Cache Level: %s", + pr_emerg(" Transaction: %s, Type: %s, Cache Level: %s", RRRR_MSG(ec), TT_MSG(ec), LL_MSG(ec)); } else if (BUS_ERROR(ec)) { - pr_emerg(" Bus (Link/DRAM) error\n"); - if (nb_bus_decoder) - nb_bus_decoder(node_id, regs); - } else { - /* shouldn't reach here! */ - pr_warning("%s: unknown MCE error 0x%x\n", __func__, ec); - } - - pr_emerg("%s.\n", EXT_ERR_MSG(xec)); + pr_emerg(" Transaction type: %s(%s), %s, Cache Level: %s, " + "Participating Processor: %s\n", + RRRR_MSG(ec), II_MSG(ec), TO_MSG(ec), LL_MSG(ec), + PP_MSG(ec)); + } else + pr_warning("Huh? Unknown MCE error 0x%x\n", ec); } -EXPORT_SYMBOL_GPL(amd_decode_nb_mce); void decode_mce(struct mce *m) { struct err_regs regs; int node, ecc; - pr_emerg("MC%d_STATUS:\n", m->bank); + pr_emerg("MC%d_STATUS: ", m->bank); - pr_emerg(" Error: %sorrected, Report: %s, MiscV: %svalid, " + pr_cont("%sorrected error, report: %s, MiscV: %svalid, " "CPU context corrupt: %s", ((m->status & MCI_STATUS_UC) ? "Unc" : "C"), ((m->status & MCI_STATUS_EN) ? "yes" : "no"), @@ -206,6 +211,8 @@ void decode_mce(struct mce *m) pr_cont("\n"); + amd_decode_err_code(m->status & 0xffff); + if (m->bank == 4) { regs.nbsl = (u32) m->status; regs.nbsh = (u32)(m->status >> 32); -- cgit v1.2.3-18-g5258 From 51966241360874e85d1e4d93c9fcdd2ef917b0fb Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 28 Jul 2009 13:50:43 +0200 Subject: EDAC, AMD: decode data cache MCEs Those get reported in MC0_STATUS, see Table 92, F10h BKDG (31116, rev. 3.28) for more details. Signed-off-by: Borislav Petkov --- drivers/edac/edac_mce_amd.c | 56 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c index 81f812eb3ae..fe8ccebd967 100644 --- a/drivers/edac/edac_mce_amd.c +++ b/drivers/edac/edac_mce_amd.c @@ -128,6 +128,49 @@ const char *ext_msgs[] = { }; EXPORT_SYMBOL_GPL(ext_msgs); +static void amd_decode_dc_mce(u64 mc0_status) +{ + u32 ec = mc0_status & 0xffff; + u32 xec = (mc0_status >> 16) & 0xf; + + pr_emerg(" Data Cache Error"); + + if (xec == 1 && TLB_ERROR(ec)) + pr_cont(": %s TLB multimatch.\n", LL_MSG(ec)); + else if (xec == 0) { + if (mc0_status & (1ULL << 40)) + pr_cont(" during Data Scrub.\n"); + else if (TLB_ERROR(ec)) + pr_cont(": %s TLB parity error.\n", LL_MSG(ec)); + else if (MEM_ERROR(ec)) { + u8 ll = ec & 0x3; + u8 tt = (ec >> 2) & 0x3; + u8 rrrr = (ec >> 4) & 0xf; + + /* see F10h BKDG (31116), Table 92. */ + if (ll == 0x1) { + if (tt != 0x1) + goto wrong_dc_mce; + + pr_cont(": Data/Tag %s error.\n", RRRR_MSG(ec)); + + } else if (ll == 0x2 && rrrr == 0x3) + pr_cont(" during L1 linefill from L2.\n"); + else + goto wrong_dc_mce; + } else if (BUS_ERROR(ec) && boot_cpu_data.x86 == 0xf) + pr_cont(" during system linefill.\n"); + else + goto wrong_dc_mce; + } else + goto wrong_dc_mce; + + return; + +wrong_dc_mce: + pr_warning("Corrupted DC MCE info?\n"); +} + void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors) { u32 ec = ERROR_CODE(regs->nbsl); @@ -211,9 +254,12 @@ void decode_mce(struct mce *m) pr_cont("\n"); - amd_decode_err_code(m->status & 0xffff); + switch (m->bank) { + case 0: + amd_decode_dc_mce(m->status); + break; - if (m->bank == 4) { + case 4: regs.nbsl = (u32) m->status; regs.nbsh = (u32)(m->status >> 32); regs.nbeal = (u32) m->addr; @@ -221,5 +267,11 @@ void decode_mce(struct mce *m) node = per_cpu(cpu_llc_id, m->extcpu); amd_decode_nb_mce(node, ®s, 1); + break; + + default: + break; } + + amd_decode_err_code(m->status & 0xffff); } -- cgit v1.2.3-18-g5258 From ab5535e70fb35b8046b6ace50259fe212e074a4f Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 28 Jul 2009 14:06:26 +0200 Subject: EDAC, AMD: decode instruction cache MCEs See Fam10h BKDG (31116, rev. 3.28), Table 95 Signed-off-by: Borislav Petkov --- drivers/edac/edac_mce_amd.c | 61 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'drivers') diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c index fe8ccebd967..b30a8306b14 100644 --- a/drivers/edac/edac_mce_amd.c +++ b/drivers/edac/edac_mce_amd.c @@ -171,6 +171,63 @@ wrong_dc_mce: pr_warning("Corrupted DC MCE info?\n"); } +static void amd_decode_ic_mce(u64 mc1_status) +{ + u32 ec = mc1_status & 0xffff; + u32 xec = (mc1_status >> 16) & 0xf; + + pr_emerg(" Instruction Cache Error"); + + if (xec == 1 && TLB_ERROR(ec)) + pr_cont(": %s TLB multimatch.\n", LL_MSG(ec)); + else if (xec == 0) { + if (TLB_ERROR(ec)) + pr_cont(": %s TLB Parity error.\n", LL_MSG(ec)); + else if (BUS_ERROR(ec)) { + if (boot_cpu_data.x86 == 0xf && + (mc1_status & (1ULL << 58))) + pr_cont(" during system linefill.\n"); + else + pr_cont(" during attempted NB data read.\n"); + } else if (MEM_ERROR(ec)) { + u8 ll = ec & 0x3; + u8 rrrr = (ec >> 4) & 0xf; + + if (ll == 0x2) + pr_cont(" during a linefill from L2.\n"); + else if (ll == 0x1) { + + switch (rrrr) { + case 0x5: + pr_cont(": Parity error during " + "data load.\n"); + break; + + case 0x7: + pr_cont(": Copyback Parity/Victim" + " error.\n"); + break; + + case 0x8: + pr_cont(": Tag Snoop error.\n"); + break; + + default: + goto wrong_ic_mce; + break; + } + } + } else + goto wrong_ic_mce; + } else + goto wrong_ic_mce; + + return; + +wrong_ic_mce: + pr_warning("Corrupted IC MCE info?\n"); +} + void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors) { u32 ec = ERROR_CODE(regs->nbsl); @@ -259,6 +316,10 @@ void decode_mce(struct mce *m) amd_decode_dc_mce(m->status); break; + case 1: + amd_decode_ic_mce(m->status); + break; + case 4: regs.nbsl = (u32) m->status; regs.nbsh = (u32)(m->status >> 32); -- cgit v1.2.3-18-g5258 From 56cad2d6fb832a876ab8bda4b01e5d0722dc754b Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 28 Jul 2009 14:14:24 +0200 Subject: EDAC, AMD: decode bus unit MCEs ... according to Table 69, Fam10h BKDG (31116, rev. 3.28). Signed-off-by: Borislav Petkov --- drivers/edac/edac_mce_amd.c | 46 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'drivers') diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c index b30a8306b14..e1f32c36248 100644 --- a/drivers/edac/edac_mce_amd.c +++ b/drivers/edac/edac_mce_amd.c @@ -228,6 +228,48 @@ wrong_ic_mce: pr_warning("Corrupted IC MCE info?\n"); } +static void amd_decode_bu_mce(u64 mc2_status) +{ + u32 ec = mc2_status & 0xffff; + u32 xec = (mc2_status >> 16) & 0xf; + + pr_emerg(" Bus Unit Error"); + + if (xec == 0x1) + pr_cont(" in the write data buffers.\n"); + else if (xec == 0x3) + pr_cont(" in the victim data buffers.\n"); + else if (xec == 0x2 && MEM_ERROR(ec)) + pr_cont(": %s error in the L2 cache tags.\n", RRRR_MSG(ec)); + else if (xec == 0x0) { + if (TLB_ERROR(ec)) + pr_cont(": %s error in a Page Descriptor Cache or " + "Guest TLB.\n", TT_MSG(ec)); + else if (BUS_ERROR(ec)) + pr_cont(": %s/ECC error in data read from NB: %s.\n", + RRRR_MSG(ec), PP_MSG(ec)); + else if (MEM_ERROR(ec)) { + u8 rrrr = (ec >> 4) & 0xf; + + if (rrrr >= 0x7) + pr_cont(": %s error during data copyback.\n", + RRRR_MSG(ec)); + else if (rrrr <= 0x1) + pr_cont(": %s parity/ECC error during data " + "access from L2.\n", RRRR_MSG(ec)); + else + goto wrong_bu_mce; + } else + goto wrong_bu_mce; + } else + goto wrong_bu_mce; + + return; + +wrong_bu_mce: + pr_warning("Corrupted BU MCE info?\n"); +} + void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors) { u32 ec = ERROR_CODE(regs->nbsl); @@ -320,6 +362,10 @@ void decode_mce(struct mce *m) amd_decode_ic_mce(m->status); break; + case 2: + amd_decode_bu_mce(m->status); + break; + case 4: regs.nbsl = (u32) m->status; regs.nbsh = (u32)(m->status >> 32); -- cgit v1.2.3-18-g5258 From f9350efd6f37ef60d2334739edb76ef1f8ee0183 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 28 Jul 2009 14:17:30 +0200 Subject: EDAC, AMD: decode load store MCEs See Fam10h BKDG (31116, rev. 3.28), Table 100. Signed-off-by: Borislav Petkov --- drivers/edac/edac_mce_amd.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c index e1f32c36248..22848285536 100644 --- a/drivers/edac/edac_mce_amd.c +++ b/drivers/edac/edac_mce_amd.c @@ -270,6 +270,27 @@ wrong_bu_mce: pr_warning("Corrupted BU MCE info?\n"); } +static void amd_decode_ls_mce(u64 mc3_status) +{ + u32 ec = mc3_status & 0xffff; + u32 xec = (mc3_status >> 16) & 0xf; + + pr_emerg(" Load Store Error"); + + if (xec == 0x0) { + u8 rrrr = (ec >> 4) & 0xf; + + if (!BUS_ERROR(ec) || (rrrr != 0x3 && rrrr != 0x4)) + goto wrong_ls_mce; + + pr_cont(" during %s.\n", RRRR_MSG(ec)); + } + return; + +wrong_ls_mce: + pr_warning("Corrupted LS MCE info?\n"); +} + void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors) { u32 ec = ERROR_CODE(regs->nbsl); @@ -366,6 +387,10 @@ void decode_mce(struct mce *m) amd_decode_bu_mce(m->status); break; + case 3: + amd_decode_ls_mce(m->status); + break; + case 4: regs.nbsl = (u32) m->status; regs.nbsh = (u32)(m->status >> 32); -- cgit v1.2.3-18-g5258 From 53bd5fedca7d0c28b35b02cab5f4e27bf8d7fabe Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 28 Jul 2009 14:20:46 +0200 Subject: EDAC, AMD: decode FR MCEs See Fam10h BKDG (31116, rev. 3.28), Table 101. Signed-off-by: Borislav Petkov --- drivers/edac/edac_mce_amd.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c index 22848285536..c8ca7136dac 100644 --- a/drivers/edac/edac_mce_amd.c +++ b/drivers/edac/edac_mce_amd.c @@ -321,6 +321,15 @@ void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors) } EXPORT_SYMBOL_GPL(amd_decode_nb_mce); +static void amd_decode_fr_mce(u64 mc5_status) +{ + /* we have only one error signature so match all fields at once. */ + if ((mc5_status & 0xffff) == 0x0f0f) + pr_emerg(" FR Error: CPU Watchdog timer expire.\n"); + else + pr_warning("Corrupted FR MCE info?\n"); +} + static inline void amd_decode_err_code(unsigned int ec) { if (TLB_ERROR(ec)) { @@ -401,6 +410,10 @@ void decode_mce(struct mce *m) amd_decode_nb_mce(node, ®s, 1); break; + case 5: + amd_decode_fr_mce(m->status); + break; + default: break; } -- cgit v1.2.3-18-g5258 From c90cd332d3dbf9fc78934b8bda271c1f909216ea Mon Sep 17 00:00:00 2001 From: Frans Pop Date: Sat, 25 Jul 2009 22:24:54 +0200 Subject: floppy: Switch driver to dev_pm_ops Gets rid of the following warning: Platform driver 'floppy' needs updating - please use dev_pm_ops [rjw: Fixed up the definition of floppy_pm_ops.] Signed-off-by: Frans Pop Signed-off-by: Andrew Morton Signed-off-by: Rafael J. Wysocki --- drivers/block/floppy.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 91b75301378..2b387c2260d 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4151,7 +4151,7 @@ static void floppy_device_release(struct device *dev) { } -static int floppy_resume(struct platform_device *dev) +static int floppy_resume(struct device *dev) { int fdc; @@ -4162,10 +4162,15 @@ static int floppy_resume(struct platform_device *dev) return 0; } -static struct platform_driver floppy_driver = { +static struct dev_pm_ops floppy_pm_ops = { .resume = floppy_resume, + .restore = floppy_resume, +}; + +static struct platform_driver floppy_driver = { .driver = { .name = "floppy", + .pm = &floppy_pm_ops, }, }; -- cgit v1.2.3-18-g5258 From 8dd2b42665f9d4ca4fded99f048631b60f669dc5 Mon Sep 17 00:00:00 2001 From: Frans Pop Date: Thu, 20 Aug 2009 20:38:13 +0200 Subject: hp-wmi: Switch driver to dev_pm_ops Gets rid of the following warning: Platform driver 'hp-wmi' needs updating - please use dev_pm_ops I tested that the resume handler still works on my HP 2510p notebook. [rjw: Fixed up the definition of hp_wmi_pm_ops.] Signed-off-by: Frans Pop Signed-off-by: Andrew Morton Signed-off-by: Rafael J. Wysocki --- drivers/platform/x86/hp-wmi.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index a2ad53e1587..af04f5b049d 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -53,7 +53,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); static int __init hp_wmi_bios_setup(struct platform_device *device); static int __exit hp_wmi_bios_remove(struct platform_device *device); -static int hp_wmi_resume_handler(struct platform_device *device); +static int hp_wmi_resume_handler(struct device *device); struct bios_args { u32 signature; @@ -94,14 +94,19 @@ static struct rfkill *wifi_rfkill; static struct rfkill *bluetooth_rfkill; static struct rfkill *wwan_rfkill; +static struct dev_pm_ops hp_wmi_pm_ops = { + .resume = hp_wmi_resume_handler, + .restore = hp_wmi_resume_handler, +}; + static struct platform_driver hp_wmi_driver = { .driver = { - .name = "hp-wmi", - .owner = THIS_MODULE, + .name = "hp-wmi", + .owner = THIS_MODULE, + .pm = &hp_wmi_pm_ops, }, .probe = hp_wmi_bios_setup, .remove = hp_wmi_bios_remove, - .resume = hp_wmi_resume_handler, }; static int hp_wmi_perform_query(int query, int write, int value) @@ -512,7 +517,7 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device) return 0; } -static int hp_wmi_resume_handler(struct platform_device *device) +static int hp_wmi_resume_handler(struct device *device) { /* * Hardware state may have changed while suspended, so trigger -- cgit v1.2.3-18-g5258 From 20d652d7d1c2f202215ecf0306ccecc3569df9ba Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 20 Aug 2009 20:25:52 +0200 Subject: PM: Update kerneldoc comments in drivers/base/power/main.c The kerneldoc comments in drivers/base/power/main.c are generally outdated and some of them don't describe the functions very accurately. Update them and standardize the format to use spaces instead of tabs. Signed-off-by: Rafael J. Wysocki Acked-by: Randy Dunlap Acked-by: Greg Kroah-Hartman Acked-by: Alan Stern --- drivers/base/power/main.c | 169 +++++++++++++++++++++++----------------------- 1 file changed, 84 insertions(+), 85 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 86990011277..b0899118569 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -50,7 +50,7 @@ static DEFINE_MUTEX(dpm_list_mtx); static bool transition_started; /** - * device_pm_init - Initialize the PM-related part of a device object + * device_pm_init - Initialize the PM-related part of a device object. * @dev: Device object being initialized. */ void device_pm_init(struct device *dev) @@ -60,7 +60,7 @@ void device_pm_init(struct device *dev) } /** - * device_pm_lock - lock the list of active devices used by the PM core + * device_pm_lock - Lock the list of active devices used by the PM core. */ void device_pm_lock(void) { @@ -68,7 +68,7 @@ void device_pm_lock(void) } /** - * device_pm_unlock - unlock the list of active devices used by the PM core + * device_pm_unlock - Unlock the list of active devices used by the PM core. */ void device_pm_unlock(void) { @@ -76,8 +76,8 @@ void device_pm_unlock(void) } /** - * device_pm_add - add a device to the list of active devices - * @dev: Device to be added to the list + * device_pm_add - Add a device to the PM core's list of active devices. + * @dev: Device to add to the list. */ void device_pm_add(struct device *dev) { @@ -103,10 +103,8 @@ void device_pm_add(struct device *dev) } /** - * device_pm_remove - remove a device from the list of active devices - * @dev: Device to be removed from the list - * - * This function also removes the device's PM-related sysfs attributes. + * device_pm_remove - Remove a device from the PM core's list of active devices. + * @dev: Device to be removed from the list. */ void device_pm_remove(struct device *dev) { @@ -120,9 +118,9 @@ void device_pm_remove(struct device *dev) } /** - * device_pm_move_before - move device in dpm_list - * @deva: Device to move in dpm_list - * @devb: Device @deva should come before + * device_pm_move_before - Move device in the PM core's list of active devices. + * @deva: Device to move in dpm_list. + * @devb: Device @deva should come before. */ void device_pm_move_before(struct device *deva, struct device *devb) { @@ -136,9 +134,9 @@ void device_pm_move_before(struct device *deva, struct device *devb) } /** - * device_pm_move_after - move device in dpm_list - * @deva: Device to move in dpm_list - * @devb: Device @deva should come after + * device_pm_move_after - Move device in the PM core's list of active devices. + * @deva: Device to move in dpm_list. + * @devb: Device @deva should come after. */ void device_pm_move_after(struct device *deva, struct device *devb) { @@ -152,8 +150,8 @@ void device_pm_move_after(struct device *deva, struct device *devb) } /** - * device_pm_move_last - move device to end of dpm_list - * @dev: Device to move in dpm_list + * device_pm_move_last - Move device to end of the PM core's list of devices. + * @dev: Device to move in dpm_list. */ void device_pm_move_last(struct device *dev) { @@ -164,10 +162,10 @@ void device_pm_move_last(struct device *dev) } /** - * pm_op - execute the PM operation appropiate for given PM event - * @dev: Device. - * @ops: PM operations to choose from. - * @state: PM transition of the system being carried out. + * pm_op - Execute the PM operation appropriate for given PM event. + * @dev: Device to handle. + * @ops: PM operations to choose from. + * @state: PM transition of the system being carried out. */ static int pm_op(struct device *dev, const struct dev_pm_ops *ops, @@ -225,13 +223,13 @@ static int pm_op(struct device *dev, } /** - * pm_noirq_op - execute the PM operation appropiate for given PM event - * @dev: Device. - * @ops: PM operations to choose from. - * @state: PM transition of the system being carried out. + * pm_noirq_op - Execute the PM operation appropriate for given PM event. + * @dev: Device to handle. + * @ops: PM operations to choose from. + * @state: PM transition of the system being carried out. * - * The operation is executed with interrupts disabled by the only remaining - * functional CPU in the system. + * The driver of @dev will not receive interrupts while this function is being + * executed. */ static int pm_noirq_op(struct device *dev, const struct dev_pm_ops *ops, @@ -329,11 +327,12 @@ static void pm_dev_err(struct device *dev, pm_message_t state, char *info, /*------------------------- Resume routines -------------------------*/ /** - * device_resume_noirq - Power on one device (early resume). - * @dev: Device. - * @state: PM transition of the system being carried out. + * device_resume_noirq - Execute an "early resume" callback for given device. + * @dev: Device to handle. + * @state: PM transition of the system being carried out. * - * Must be called with interrupts disabled. + * The driver of @dev will not receive interrupts while this function is being + * executed. */ static int device_resume_noirq(struct device *dev, pm_message_t state) { @@ -355,14 +354,11 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) } /** - * dpm_resume_noirq - Power on all regular (non-sysdev) devices. - * @state: PM transition of the system being carried out. - * - * Call the "noirq" resume handlers for all devices marked as - * DPM_OFF_IRQ and enable device drivers to receive interrupts. + * dpm_resume_noirq - Execute "early resume" callbacks for non-sysdev devices. + * @state: PM transition of the system being carried out. * - * Must be called under dpm_list_mtx. Device drivers should not receive - * interrupts while it's being executed. + * Call the "noirq" resume handlers for all devices marked as DPM_OFF_IRQ and + * enable device drivers to receive interrupts. */ void dpm_resume_noirq(pm_message_t state) { @@ -384,9 +380,9 @@ void dpm_resume_noirq(pm_message_t state) EXPORT_SYMBOL_GPL(dpm_resume_noirq); /** - * device_resume - Restore state for one device. - * @dev: Device. - * @state: PM transition of the system being carried out. + * device_resume - Execute "resume" callbacks for given device. + * @dev: Device to handle. + * @state: PM transition of the system being carried out. */ static int device_resume(struct device *dev, pm_message_t state) { @@ -435,11 +431,11 @@ static int device_resume(struct device *dev, pm_message_t state) } /** - * dpm_resume - Resume every device. - * @state: PM transition of the system being carried out. + * dpm_resume - Execute "resume" callbacks for non-sysdev devices. + * @state: PM transition of the system being carried out. * - * Execute the appropriate "resume" callback for all devices the status of - * which indicates that they are inactive. + * Execute the appropriate "resume" callback for all devices whose status + * indicates that they are suspended. */ static void dpm_resume(pm_message_t state) { @@ -476,9 +472,9 @@ static void dpm_resume(pm_message_t state) } /** - * device_complete - Complete a PM transition for given device - * @dev: Device. - * @state: PM transition of the system being carried out. + * device_complete - Complete a PM transition for given device. + * @dev: Device to handle. + * @state: PM transition of the system being carried out. */ static void device_complete(struct device *dev, pm_message_t state) { @@ -503,11 +499,11 @@ static void device_complete(struct device *dev, pm_message_t state) } /** - * dpm_complete - Complete a PM transition for all devices. - * @state: PM transition of the system being carried out. + * dpm_complete - Complete a PM transition for all non-sysdev devices. + * @state: PM transition of the system being carried out. * - * Execute the ->complete() callbacks for all devices that are not marked - * as DPM_ON. + * Execute the ->complete() callbacks for all devices whose PM status is not + * DPM_ON (this allows new devices to be registered). */ static void dpm_complete(pm_message_t state) { @@ -537,11 +533,11 @@ static void dpm_complete(pm_message_t state) } /** - * dpm_resume_end - Restore state of each device in system. - * @state: PM transition of the system being carried out. + * dpm_resume_end - Execute "resume" callbacks and complete system transition. + * @state: PM transition of the system being carried out. * - * Resume all the devices, unlock them all, and allow new - * devices to be registered once again. + * Execute "resume" callbacks for all devices and complete the PM transition of + * the system. */ void dpm_resume_end(pm_message_t state) { @@ -555,9 +551,11 @@ EXPORT_SYMBOL_GPL(dpm_resume_end); /*------------------------- Suspend routines -------------------------*/ /** - * resume_event - return a PM message representing the resume event - * corresponding to given sleep state. - * @sleep_state: PM message representing a sleep state. + * resume_event - Return a "resume" message for given "suspend" sleep state. + * @sleep_state: PM message representing a sleep state. + * + * Return a PM message representing the resume event corresponding to given + * sleep state. */ static pm_message_t resume_event(pm_message_t sleep_state) { @@ -574,11 +572,12 @@ static pm_message_t resume_event(pm_message_t sleep_state) } /** - * device_suspend_noirq - Shut down one device (late suspend). - * @dev: Device. - * @state: PM transition of the system being carried out. + * device_suspend_noirq - Execute a "late suspend" callback for given device. + * @dev: Device to handle. + * @state: PM transition of the system being carried out. * - * This is called with interrupts off and only a single CPU running. + * The driver of @dev will not receive interrupts while this function is being + * executed. */ static int device_suspend_noirq(struct device *dev, pm_message_t state) { @@ -595,13 +594,11 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) } /** - * dpm_suspend_noirq - Power down all regular (non-sysdev) devices. - * @state: PM transition of the system being carried out. + * dpm_suspend_noirq - Execute "late suspend" callbacks for non-sysdev devices. + * @state: PM transition of the system being carried out. * - * Prevent device drivers from receiving interrupts and call the "noirq" - * suspend handlers. - * - * Must be called under dpm_list_mtx. + * Prevent device drivers from receiving interrupts and call the "noirq" suspend + * handlers for all non-sysdev devices. */ int dpm_suspend_noirq(pm_message_t state) { @@ -626,9 +623,9 @@ int dpm_suspend_noirq(pm_message_t state) EXPORT_SYMBOL_GPL(dpm_suspend_noirq); /** - * device_suspend - Save state of one device. - * @dev: Device. - * @state: PM transition of the system being carried out. + * device_suspend - Execute "suspend" callbacks for given device. + * @dev: Device to handle. + * @state: PM transition of the system being carried out. */ static int device_suspend(struct device *dev, pm_message_t state) { @@ -675,10 +672,8 @@ static int device_suspend(struct device *dev, pm_message_t state) } /** - * dpm_suspend - Suspend every device. - * @state: PM transition of the system being carried out. - * - * Execute the appropriate "suspend" callbacks for all devices. + * dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices. + * @state: PM transition of the system being carried out. */ static int dpm_suspend(pm_message_t state) { @@ -712,9 +707,12 @@ static int dpm_suspend(pm_message_t state) } /** - * device_prepare - Execute the ->prepare() callback(s) for given device. - * @dev: Device. - * @state: PM transition of the system being carried out. + * device_prepare - Prepare a device for system power transition. + * @dev: Device to handle. + * @state: PM transition of the system being carried out. + * + * Execute the ->prepare() callback(s) for given device. No new children of the + * device may be registered after this function has returned. */ static int device_prepare(struct device *dev, pm_message_t state) { @@ -750,10 +748,10 @@ static int device_prepare(struct device *dev, pm_message_t state) } /** - * dpm_prepare - Prepare all devices for a PM transition. - * @state: PM transition of the system being carried out. + * dpm_prepare - Prepare all non-sysdev devices for a system PM transition. + * @state: PM transition of the system being carried out. * - * Execute the ->prepare() callback for all devices. + * Execute the ->prepare() callback(s) for all devices. */ static int dpm_prepare(pm_message_t state) { @@ -804,10 +802,11 @@ static int dpm_prepare(pm_message_t state) } /** - * dpm_suspend_start - Save state and stop all devices in system. - * @state: PM transition of the system being carried out. + * dpm_suspend_start - Prepare devices for PM transition and suspend them. + * @state: PM transition of the system being carried out. * - * Prepare and suspend all devices. + * Prepare all non-sysdev devices for system PM transition and execute "suspend" + * callbacks for them. */ int dpm_suspend_start(pm_message_t state) { -- cgit v1.2.3-18-g5258 From 3eb132c986f04f64b9c360abd67a1e0d18d6d5b4 Mon Sep 17 00:00:00 2001 From: Xiaotian Feng Date: Thu, 20 Aug 2009 20:28:33 +0200 Subject: PM: Reset transition_started at dpm_resume_noirq transition_started should be set once the preparation of devices for a PM has started, reset before starting to resume devices. When resuming devices, kernel calls dpm_resume_noirq then dpm_resume_end(dpm_resume). Thus we should reset transition_started at dpm_resume_noirq. This patch fixes ACPI warning when resuming from suspend/hibernate: ACPI: \_SB_.PCI0.IDE1.PRI1.MAS1 - docking ------------[ cut here ]------------ WARNING: at drivers/base/power/main.c:87 device_pm_add+0x8b/0xcc() Hardware name: OptiPlex 760 Device: acpi Parentless device registered during a PM transaction [rjw: Fixed up the changelog.] Signed-off-by: Xiaotian Feng Signed-off-by: Rafael J. Wysocki --- drivers/base/power/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index b0899118569..e0dc4071e08 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -365,6 +365,7 @@ void dpm_resume_noirq(pm_message_t state) struct device *dev; mutex_lock(&dpm_list_mtx); + transition_started = false; list_for_each_entry(dev, &dpm_list, power.entry) if (dev->power.status > DPM_OFF) { int error; @@ -443,7 +444,6 @@ static void dpm_resume(pm_message_t state) INIT_LIST_HEAD(&list); mutex_lock(&dpm_list_mtx); - transition_started = false; while (!list_empty(&dpm_list)) { struct device *dev = to_device(dpm_list.next); -- cgit v1.2.3-18-g5258 From 33f82d141c897f39cd8bce592d88cb3c5af58342 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 10 Sep 2009 00:06:44 +0200 Subject: at_hdmac: Rework suspend_late()/resume_early() This patch reworks platform driver power management code for at_hdmac from legacy late/early callbacks to dev_pm_ops. The callbacks are converted for CONFIG_SUSPEND like this: suspend_late() -> suspend_noirq() resume_early() -> resume_noirq() Signed-off-by: Dan Williams Signed-off-by: Rafael J. Wysocki --- drivers/dma/at_hdmac.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 9a1e5fb412e..c8522e6f1ad 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -1166,32 +1166,37 @@ static void at_dma_shutdown(struct platform_device *pdev) clk_disable(atdma->clk); } -static int at_dma_suspend_late(struct platform_device *pdev, pm_message_t mesg) +static int at_dma_suspend_noirq(struct device *dev) { - struct at_dma *atdma = platform_get_drvdata(pdev); + struct platform_device *pdev = to_platform_device(dev); + struct at_dma *atdma = platform_get_drvdata(pdev); at_dma_off(platform_get_drvdata(pdev)); clk_disable(atdma->clk); return 0; } -static int at_dma_resume_early(struct platform_device *pdev) +static int at_dma_resume_noirq(struct device *dev) { - struct at_dma *atdma = platform_get_drvdata(pdev); + struct platform_device *pdev = to_platform_device(dev); + struct at_dma *atdma = platform_get_drvdata(pdev); clk_enable(atdma->clk); dma_writel(atdma, EN, AT_DMA_ENABLE); return 0; - } +static struct dev_pm_ops at_dma_dev_pm_ops = { + .suspend_noirq = at_dma_suspend_noirq, + .resume_noirq = at_dma_resume_noirq, +}; + static struct platform_driver at_dma_driver = { .remove = __exit_p(at_dma_remove), .shutdown = at_dma_shutdown, - .suspend_late = at_dma_suspend_late, - .resume_early = at_dma_resume_early, .driver = { .name = "at_hdmac", + .pm = &at_dma_dev_pm_ops, }, }; -- cgit v1.2.3-18-g5258 From 353f6dd2dec992ddd34620a94b051b0f76227379 Mon Sep 17 00:00:00 2001 From: Anirban Sinha Date: Mon, 14 Sep 2009 11:13:37 -0700 Subject: cleanup console_print() console_print() is an old legacy interface mostly unused in the entire kernel tree. It's best to clean up its existing use and let developers use their own implementation of it as they feel fit. Signed-off-by: Anirban Sinha Signed-off-by: Linus Torvalds --- drivers/char/serial167.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index 51e7a46787b..5942a9d674c 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -171,7 +171,6 @@ static int startup(struct cyclades_port *); static void cy_throttle(struct tty_struct *); static void cy_unthrottle(struct tty_struct *); static void config_setup(struct cyclades_port *); -extern void console_print(const char *); #ifdef CYCLOM_SHOW_STATUS static void show_status(int); #endif @@ -245,7 +244,7 @@ void SP(char *data) { unsigned long flags; local_irq_save(flags); - console_print(data); + printk(KERN_EMERG "%s", data); local_irq_restore(flags); } @@ -255,7 +254,7 @@ void CP(char data) unsigned long flags; local_irq_save(flags); scrn[0] = data; - console_print(scrn); + printk(KERN_EMERG "%c", scrn); local_irq_restore(flags); } /* CP */ -- cgit v1.2.3-18-g5258